OSDN Git Service

6cf195e4a09f10eff53c9a4f28bad79052af0e21
[android-x86/external-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 "busybox.h"
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42
43 #include "shadow.h"
44
45 static FILE *shadow;
46 static char spwbuf[BUFSIZ];
47 static struct spwd spwd;
48
49 #define FIELDS  9
50 #define OFIELDS 5
51
52 /* setspent - initialize access to shadow text and DBM files */
53 void setspent(void)
54 {
55         if (shadow) {
56                 rewind(shadow);
57         } else {
58                 if ((shadow = fopen("/etc/shadow", "r")) == NULL)
59                         perror_msg_and_die("/etc/shadow");
60         }
61 }
62
63 /* endspent - terminate access to shadow text and DBM files */
64 void endspent(void)
65 {
66         if (shadow)
67                 (void) fclose(shadow);
68         shadow = (FILE *) 0;
69 }
70
71 /* getspent - get a (struct spwd *) from the current shadow file */
72 struct spwd *getspent(void)
73 {
74         if (!shadow)
75                 setspent();
76         return (fgetspent(shadow));
77 }
78
79 /* getspnam - get a shadow entry by name */
80 struct spwd *getspnam(const char *name)
81 {
82         struct spwd *sp;
83
84         if (!name || !strlen(name))
85                 return NULL;
86
87         setspent();
88         while ((sp = getspent()) != NULL) {
89                 if (strcmp(name, sp->sp_namp) == 0)
90                         break;
91         }
92         endspent();
93         return (sp);
94 }
95
96
97 /* sgetspent - convert string in shadow file format to (struct spwd *) */
98 /* returns NULL on error */
99 struct spwd *sgetspent(const char *string)
100 {
101         char *fields[FIELDS];
102         char *cp;
103         char *cpp;
104         int i;
105
106         /*
107          * Copy string to local buffer.  It has to be tokenized and we
108          * have to do that to our private copy.
109          */
110
111         if (strlen(string) >= sizeof spwbuf)
112                 /* return 0; */
113                 return NULL;
114         strcpy(spwbuf, string);
115
116         if ((cp = strrchr(spwbuf, '\n')))
117                 *cp = '\0';
118
119         /*
120          * Tokenize the string into colon separated fields.  Allow up to
121          * FIELDS different fields.
122          */
123
124         for (cp = spwbuf, i = 0; *cp && i < FIELDS; i++) {
125                 fields[i] = cp;
126                 while (*cp && *cp != ':')
127                         cp++;
128
129                 if (*cp)
130                         *cp++ = '\0';
131         }
132
133         /*
134          * It is acceptable for the last SVR4 field to be blank.  This
135          * results in the loop being terminated early.  In which case,
136          * we just make the last field be blank and be done with it.
137          */
138
139         if (i == (FIELDS - 1))
140                 fields[i++] = cp;
141
142         if ((cp && *cp) || (i != FIELDS && i != OFIELDS))
143                 /* return 0; */
144                 return NULL;
145
146         /*
147          * Start populating the structure.  The fields are all in
148          * static storage, as is the structure we pass back.  If we
149          * ever see a name with '+' as the first character, we try
150          * to turn on NIS processing.
151          */
152
153         spwd.sp_namp = fields[0];
154         spwd.sp_pwdp = fields[1];
155
156         /*
157          * Get the last changed date.  For all of the integer fields,
158          * we check for proper format.  It is an error to have an
159          * incorrectly formatted number, unless we are using NIS.
160          */
161
162         if ((spwd.sp_lstchg = strtol(fields[2], &cpp, 10)) == 0 && *cpp) {
163                 /* return 0; */
164                 return NULL;
165         } else if (fields[2][0] == '\0')
166                 spwd.sp_lstchg = -1;
167
168         /*
169          * Get the minimum period between password changes.
170          */
171
172         if ((spwd.sp_min = strtol(fields[3], &cpp, 10)) == 0 && *cpp) {
173                 /* return 0; */
174                 return NULL;
175         } else if (fields[3][0] == '\0')
176                 spwd.sp_min = -1;
177
178         /*
179          * Get the maximum number of days a password is valid.
180          */
181
182         if ((spwd.sp_max = strtol(fields[4], &cpp, 10)) == 0 && *cpp) {
183                 /* return 0; */
184                 return NULL;
185         } else if (fields[4][0] == '\0')
186                 spwd.sp_max = -1;
187
188         /*
189          * If there are only OFIELDS fields (this is a SVR3.2 /etc/shadow
190          * formatted file), initialize the other field members to -1.
191          */
192
193         if (i == OFIELDS) {
194                 spwd.sp_warn = spwd.sp_inact = spwd.sp_expire = spwd.sp_flag = -1;
195
196                 return &spwd;
197         }
198
199         /*
200          * The rest of the fields are mandatory for SVR4, but optional
201          * for anything else.  However, if one is present the others
202          * must be as well.
203          */
204
205         /*
206          * Get the number of days of password expiry warning.
207          */
208
209         if ((spwd.sp_warn = strtol(fields[5], &cpp, 10)) == 0 && *cpp) {
210                 /* return 0; */
211                 return NULL;
212         } else if (fields[5][0] == '\0')
213                 spwd.sp_warn = -1;
214
215         /*
216          * Get the number of days of inactivity before an account is
217          * disabled.
218          */
219
220         if ((spwd.sp_inact = strtol(fields[6], &cpp, 10)) == 0 && *cpp) {
221                 /* return 0; */
222                 return NULL;
223         } else if (fields[6][0] == '\0')
224                 spwd.sp_inact = -1;
225
226         /*
227          * Get the number of days after the epoch before the account is
228          * set to expire.
229          */
230
231         if ((spwd.sp_expire = strtol(fields[7], &cpp, 10)) == 0 && *cpp) {
232                 /* return 0; */
233                 return NULL;
234         } else if (fields[7][0] == '\0')
235                 spwd.sp_expire = -1;
236
237         /*
238          * This field is reserved for future use.  But it isn't supposed
239          * to have anything other than a valid integer in it.
240          */
241
242         if ((spwd.sp_flag = strtol(fields[8], &cpp, 10)) == 0 && *cpp) {
243                 /* return 0; */
244                 return NULL;
245         } else if (fields[8][0] == '\0')
246                 spwd.sp_flag = -1;
247
248         return (&spwd);
249 }
250
251 /* fgetspent - get an entry from an /etc/shadow formatted stream */
252 struct spwd *fgetspent(FILE *fp)
253 {
254         char buf[BUFSIZ];
255         char *cp;
256
257         if (!fp)
258                 /* return (0); */
259                 return NULL;
260
261         if (fgets(buf, sizeof buf, fp) != (char *) 0) {
262                 if ((cp = strchr(buf, '\n')))
263                         *cp = '\0';
264                 return (sgetspent(buf));
265         }
266         /* return 0; */
267         return NULL;
268 }
269
270 /*
271  * putspent - put a (struct spwd *) into the (FILE *) you provide.
272  * 
273  *      this was described in shadow_.h but not implemented, so here
274  *      I go.  -beppu
275  *
276  */
277 int putspent(const struct spwd *sp, FILE *fp)
278 {
279         int ret;
280
281         /* seek to end */
282         ret = fseek(fp, 0, SEEK_END);
283         if (ret == -1) {
284                 /* return -1; */
285                 return 1;
286         }
287
288         /* powered by fprintf */
289         fprintf(fp, "%s:%s:%ld:%ld:%ld:%ld:%ld:%ld:%s\n", sp->sp_namp,  /* login name */
290                         sp->sp_pwdp,            /* encrypted password */
291                         sp->sp_lstchg,          /* date of last change */
292                         sp->sp_min,                     /* minimum number of days between changes */
293                         sp->sp_max,                     /* maximum number of days between changes */
294                         sp->sp_warn,            /* number of days of warning before password expires */
295                         sp->sp_inact,           /* number of days after password expires until 
296                                                                    the account becomes unusable */
297                         sp->sp_expire,          /* days since 1/1/70 until account expires */
298                         "");
299         return 0;
300 }
301
302