oops. make this actually work as intended....
[platform/upstream/busybox.git] / libpwdgrp / shadow.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Copyright 1989 - 1994, Julianne Frances Haugh 
4  *                      <jockgrrl@austin.rr.com>, <jfh@austin.ibm.com>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 /* TODO:  fgetspent_r.c  getspent_r.c  getspnam_r.c sgetspent_r.c 
33  *                lckpwdf  ulckpwdf 
34  */
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40
41 #include "busybox.h"
42 #include "shadow_.h"
43
44 static FILE *shadow;
45 static char spwbuf[BUFSIZ];
46 static struct spwd spwd;
47
48 #define FIELDS  9
49 #define OFIELDS 5
50
51 /* setspent - initialize access to shadow text and DBM files */
52 void setspent(void)
53 {
54         if (shadow) {
55                 rewind(shadow);
56         } else {
57                 shadow = bb_xfopen(bb_path_shadow_file, "r");
58         }
59 }
60
61 /* endspent - terminate access to shadow text and DBM files */
62 void endspent(void)
63 {
64         if (shadow)
65                 (void) fclose(shadow);
66         shadow = (FILE *) 0;
67 }
68
69 /* getspent - get a (struct spwd *) from the current shadow file */
70 struct spwd *getspent(void)
71 {
72         if (!shadow)
73                 setspent();
74         return (fgetspent(shadow));
75 }
76
77 /* getspnam - get a shadow entry by name */
78 struct spwd *getspnam(const char *name)
79 {
80         struct spwd *sp;
81
82         if (!name || !strlen(name))
83                 return NULL;
84
85         setspent();
86         while ((sp = getspent()) != NULL) {
87                 if (strcmp(name, sp->sp_namp) == 0)
88                         break;
89         }
90         endspent();
91         return (sp);
92 }
93
94
95 /* sgetspent - convert string in shadow file format to (struct spwd *) */
96 /* returns NULL on error */
97 struct spwd *sgetspent(const char *string)
98 {
99         char *fields[FIELDS];
100         char *cp;
101         char *cpp;
102         int i;
103
104         /*
105          * Copy string to local buffer.  It has to be tokenized and we
106          * have to do that to our private copy.
107          */
108
109         if (strlen(string) >= sizeof spwbuf)
110                 /* return 0; */
111                 return NULL;
112         strcpy(spwbuf, string);
113
114         if ((cp = strrchr(spwbuf, '\n')))
115                 *cp = '\0';
116
117         /*
118          * Tokenize the string into colon separated fields.  Allow up to
119          * FIELDS different fields.
120          */
121
122         for (cp = spwbuf, i = 0; *cp && i < FIELDS; i++) {
123                 fields[i] = cp;
124                 while (*cp && *cp != ':')
125                         cp++;
126
127                 if (*cp)
128                         *cp++ = '\0';
129         }
130
131         /*
132          * It is acceptable for the last SVR4 field to be blank.  This
133          * results in the loop being terminated early.  In which case,
134          * we just make the last field be blank and be done with it.
135          */
136
137         if (i == (FIELDS - 1))
138                 fields[i++] = cp;
139
140         if ((cp && *cp) || (i != FIELDS && i != OFIELDS))
141                 /* return 0; */
142                 return NULL;
143
144         /*
145          * Start populating the structure.  The fields are all in
146          * static storage, as is the structure we pass back.  If we
147          * ever see a name with '+' as the first character, we try
148          * to turn on NIS processing.
149          */
150
151         spwd.sp_namp = fields[0];
152         spwd.sp_pwdp = fields[1];
153
154         /*
155          * Get the last changed date.  For all of the integer fields,
156          * we check for proper format.  It is an error to have an
157          * incorrectly formatted number, unless we are using NIS.
158          */
159
160         if ((spwd.sp_lstchg = strtol(fields[2], &cpp, 10)) == 0 && *cpp) {
161                 /* return 0; */
162                 return NULL;
163         } else if (fields[2][0] == '\0')
164                 spwd.sp_lstchg = -1;
165
166         /*
167          * Get the minimum period between password changes.
168          */
169
170         if ((spwd.sp_min = strtol(fields[3], &cpp, 10)) == 0 && *cpp) {
171                 /* return 0; */
172                 return NULL;
173         } else if (fields[3][0] == '\0')
174                 spwd.sp_min = -1;
175
176         /*
177          * Get the maximum number of days a password is valid.
178          */
179
180         if ((spwd.sp_max = strtol(fields[4], &cpp, 10)) == 0 && *cpp) {
181                 /* return 0; */
182                 return NULL;
183         } else if (fields[4][0] == '\0')
184                 spwd.sp_max = -1;
185
186         /*
187          * If there are only OFIELDS fields (this is a SVR3.2 /etc/shadow
188          * formatted file), initialize the other field members to -1.
189          */
190
191         if (i == OFIELDS) {
192                 spwd.sp_warn = spwd.sp_inact = spwd.sp_expire = spwd.sp_flag = -1;
193
194                 return &spwd;
195         }
196
197         /*
198          * The rest of the fields are mandatory for SVR4, but optional
199          * for anything else.  However, if one is present the others
200          * must be as well.
201          */
202
203         /*
204          * Get the number of days of password expiry warning.
205          */
206
207         if ((spwd.sp_warn = strtol(fields[5], &cpp, 10)) == 0 && *cpp) {
208                 /* return 0; */
209                 return NULL;
210         } else if (fields[5][0] == '\0')
211                 spwd.sp_warn = -1;
212
213         /*
214          * Get the number of days of inactivity before an account is
215          * disabled.
216          */
217
218         if ((spwd.sp_inact = strtol(fields[6], &cpp, 10)) == 0 && *cpp) {
219                 /* return 0; */
220                 return NULL;
221         } else if (fields[6][0] == '\0')
222                 spwd.sp_inact = -1;
223
224         /*
225          * Get the number of days after the epoch before the account is
226          * set to expire.
227          */
228
229         if ((spwd.sp_expire = strtol(fields[7], &cpp, 10)) == 0 && *cpp) {
230                 /* return 0; */
231                 return NULL;
232         } else if (fields[7][0] == '\0')
233                 spwd.sp_expire = -1;
234
235         /*
236          * This field is reserved for future use.  But it isn't supposed
237          * to have anything other than a valid integer in it.
238          */
239
240         if ((spwd.sp_flag = strtol(fields[8], &cpp, 10)) == 0 && *cpp) {
241                 /* return 0; */
242                 return NULL;
243         } else if (fields[8][0] == '\0')
244                 spwd.sp_flag = -1;
245
246         return (&spwd);
247 }
248
249 /* fgetspent - get an entry from an /etc/shadow formatted stream */
250 struct spwd *fgetspent(FILE *fp)
251 {
252         char buf[BUFSIZ];
253         char *cp;
254
255         if (!fp)
256                 /* return (0); */
257                 return NULL;
258
259         if (fgets(buf, sizeof buf, fp) != (char *) 0) {
260                 if ((cp = strchr(buf, '\n')))
261                         *cp = '\0';
262                 return (sgetspent(buf));
263         }
264         /* return 0; */
265         return NULL;
266 }
267
268 /*
269  * putspent - put a (struct spwd *) into the (FILE *) you provide.
270  * 
271  *      this was described in shadow_.h but not implemented, so here
272  *      I go.  -beppu
273  *
274  */
275 int putspent(const struct spwd *sp, FILE *fp)
276 {
277         int ret;
278
279         /* seek to end */
280         ret = fseek(fp, 0, SEEK_END);
281         if (ret == -1) {
282                 /* return -1; */
283                 return 1;
284         }
285
286         /* powered by fprintf */
287         fprintf(fp, "%s:%s:%ld:%ld:%ld:%ld:%ld:%ld:%s\n", sp->sp_namp,  /* login name */
288                         sp->sp_pwdp,            /* encrypted password */
289                         sp->sp_lstchg,          /* date of last change */
290                         sp->sp_min,                     /* minimum number of days between changes */
291                         sp->sp_max,                     /* maximum number of days between changes */
292                         sp->sp_warn,            /* number of days of warning before password expires */
293                         sp->sp_inact,           /* number of days after password expires until 
294                                                                    the account becomes unusable */
295                         sp->sp_expire,          /* days since 1/1/70 until account expires */
296                         "");
297         return 0;
298 }
299
300