]> granicus.if.org Git - shadow/blob - lib/shadow.c
updated to 360t71f. Thanks to Leandro Azevedo <leorock182@gmail.com>.
[shadow] / lib / shadow.c
1 /*
2  * Copyright 1989 - 1994, Julianne Frances Haugh
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <config.h>
31
32 /* Newer versions of Linux libc already have shadow support.  */
33 #ifndef HAVE_GETSPNAM
34
35 #ident "$Id$"
36
37 #include <sys/types.h>
38 #include "prototypes.h"
39 #include "defines.h"
40 #include <stdio.h>
41 #ifdef  USE_NIS
42 static int nis_used;
43 static int nis_ignore;
44 static enum { native, start, middle, native2 } nis_state;
45 static int nis_bound;
46 static char *nis_domain;
47 static char *nis_key;
48 static int nis_keylen;
49 static char *nis_val;
50 static int nis_vallen;
51
52 #define IS_NISCHAR(c) ((c)=='+')
53 #endif
54
55 static FILE *shadow;
56 static char spwbuf[BUFSIZ];
57 static struct spwd spwd;
58
59 #define FIELDS  9
60 #define OFIELDS 5
61
62 #ifdef  USE_NIS
63
64 /*
65  * __setspNIS - turn on or off NIS searches
66  */
67
68 void __setspNIS (int flag)
69 {
70         nis_ignore = !flag;
71
72         if (nis_ignore)
73                 nis_used = 0;
74 }
75
76 /*
77  * bind_nis - bind to NIS server
78  */
79
80 static int bind_nis (void)
81 {
82         if (yp_get_default_domain (&nis_domain))
83                 return -1;
84
85         nis_bound = 1;
86         return 0;
87 }
88 #endif
89
90 /*
91  * setspent - initialize access to shadow text and DBM files
92  */
93
94 void setspent (void)
95 {
96         if (shadow)
97                 rewind (shadow);
98         else
99                 shadow = fopen (SHADOW_FILE, "r");
100
101 #ifdef  USE_NIS
102         nis_state = native;
103 #endif
104 }
105
106 /*
107  * endspent - terminate access to shadow text and DBM files
108  */
109
110 void endspent (void)
111 {
112         if (shadow)
113                 (void) fclose (shadow);
114
115         shadow = (FILE *) 0;
116 }
117
118 /*
119  * my_sgetspent - convert string in shadow file format to (struct spwd *)
120  */
121
122 static struct spwd *my_sgetspent (const char *string)
123 {
124         char *fields[FIELDS];
125         char *cp;
126         char *cpp;
127         int i;
128
129         /*
130          * Copy string to local buffer.  It has to be tokenized and we
131          * have to do that to our private copy.
132          */
133
134         if (strlen (string) >= sizeof spwbuf)
135                 return 0;
136         strcpy (spwbuf, string);
137
138         cp = strrchr (spwbuf, '\n');
139         if (NULL != cp)
140                 *cp = '\0';
141
142         /*
143          * Tokenize the string into colon separated fields.  Allow up to
144          * FIELDS different fields.
145          */
146
147         for (cp = spwbuf, i = 0; *cp && i < FIELDS; i++) {
148                 fields[i] = cp;
149                 while (*cp && *cp != ':')
150                         cp++;
151
152                 if (*cp)
153                         *cp++ = '\0';
154         }
155
156         if (i == (FIELDS - 1))
157                 fields[i++] = cp;
158
159         if ((cp && *cp) || (i != FIELDS && i != OFIELDS))
160                 return 0;
161
162         /*
163          * Start populating the structure.  The fields are all in
164          * static storage, as is the structure we pass back.  If we
165          * ever see a name with '+' as the first character, we try
166          * to turn on NIS processing.
167          */
168
169         spwd.sp_namp = fields[0];
170 #ifdef  USE_NIS
171         if (IS_NISCHAR (fields[0][0]))
172                 nis_used = 1;
173 #endif
174         spwd.sp_pwdp = fields[1];
175
176         /*
177          * Get the last changed date.  For all of the integer fields,
178          * we check for proper format.  It is an error to have an
179          * incorrectly formatted number, unless we are using NIS.
180          */
181
182         spwd.sp_lstchg = strtol (fields[2], &cpp, 10);
183         if ((spwd.sp_lstchg == 0) && *cpp) {
184 #ifdef  USE_NIS
185                 if (!nis_used)
186                         return 0;
187                 else
188                         spwd.sp_lstchg = -1;
189 #else
190                 return 0;
191 #endif
192         } else if (fields[2][0] == '\0')
193                 spwd.sp_lstchg = -1;
194
195         /*
196          * Get the minimum period between password changes.
197          */
198
199         spwd.sp_min = strtol (fields[3], &cpp, 10);
200         if ((spwd.sp_min == 0) && *cpp) {
201 #ifdef  USE_NIS
202                 if (!nis_used)
203                         return 0;
204                 else
205                         spwd.sp_min = -1;
206 #else
207                 return 0;
208 #endif
209         } else if (fields[3][0] == '\0')
210                 spwd.sp_min = -1;
211
212         /*
213          * Get the maximum number of days a password is valid.
214          */
215
216         spwd.sp_max = strtol (fields[4], &cpp, 10);
217         if ((spwd.sp_max == 0) && *cpp) {
218 #ifdef  USE_NIS
219                 if (!nis_used)
220                         return 0;
221                 else
222                         spwd.sp_max = -1;
223 #else
224                 return 0;
225 #endif
226         } else if (fields[4][0] == '\0')
227                 spwd.sp_max = -1;
228
229         /*
230          * If there are only OFIELDS fields (this is a SVR3.2 /etc/shadow
231          * formatted file), initialize the other field members to -1.
232          */
233
234         if (i == OFIELDS) {
235                 spwd.sp_warn = spwd.sp_inact = spwd.sp_expire =
236                     spwd.sp_flag = -1;
237
238                 return &spwd;
239         }
240
241         /*
242          * Get the number of days of password expiry warning.
243          */
244
245         spwd.sp_warn = strtol (fields[5], &cpp, 10);
246         if ((spwd.sp_warn == 0) && *cpp) {
247 #ifdef  USE_NIS
248                 if (!nis_used)
249                         return 0;
250                 else
251                         spwd.sp_warn = -1;
252 #else
253                 return 0;
254 #endif
255         } else if (fields[5][0] == '\0')
256                 spwd.sp_warn = -1;
257
258         /*
259          * Get the number of days of inactivity before an account is
260          * disabled.
261          */
262
263         spwd.sp_inact = strtol (fields[6], &cpp, 10);
264         if ((spwd.sp_inact == 0) && *cpp) {
265 #ifdef  USE_NIS
266                 if (!nis_used)
267                         return 0;
268                 else
269                         spwd.sp_inact = -1;
270 #else
271                 return 0;
272 #endif
273         } else if (fields[6][0] == '\0')
274                 spwd.sp_inact = -1;
275
276         /*
277          * Get the number of days after the epoch before the account is
278          * set to expire.
279          */
280
281         spwd.sp_expire = strtol (fields[7], &cpp, 10);
282         if ((spwd.sp_expire == 0) && *cpp) {
283 #ifdef  USE_NIS
284                 if (!nis_used)
285                         return 0;
286                 else
287                         spwd.sp_expire = -1;
288 #else
289                 return 0;
290 #endif
291         } else if (fields[7][0] == '\0')
292                 spwd.sp_expire = -1;
293
294         /*
295          * This field is reserved for future use.  But it isn't supposed
296          * to have anything other than a valid integer in it.
297          */
298
299         spwd.sp_flag = strtol (fields[8], &cpp, 10);
300         if ((spwd.sp_flag == 0) && *cpp) {
301 #ifdef  USE_NIS
302                 if (!nis_used)
303                         return 0;
304                 else
305                         spwd.sp_flag = -1;
306 #else
307                 return 0;
308 #endif
309         } else if (fields[8][0] == '\0')
310                 spwd.sp_flag = -1;
311
312         return (&spwd);
313 }
314
315 /*
316  * fgetspent - get an entry from a /etc/shadow formatted stream
317  */
318
319 struct spwd *fgetspent (FILE * fp)
320 {
321         char buf[BUFSIZ];
322         char *cp;
323
324         if (!fp)
325                 return (0);
326
327 #ifdef  USE_NIS
328         while (fgets (buf, sizeof buf, fp) != (char *) 0)
329 #else
330         if (fgets (buf, sizeof buf, fp) != (char *) 0)
331 #endif
332         {
333                 cp = strchr (buf, '\n');
334                 if (NULL != cp)
335                         *cp = '\0';
336 #ifdef  USE_NIS
337                 if (nis_ignore && IS_NISCHAR (buf[0]))
338                         continue;
339 #endif
340                 return my_sgetspent (buf);
341         }
342         return 0;
343 }
344
345 /*
346  * getspent - get a (struct spwd *) from the current shadow file
347  */
348
349 struct spwd *getspent (void)
350 {
351 #ifdef  USE_NIS
352         int nis_1_user = 0;
353         struct spwd *val;
354         char buf[BUFSIZ];
355 #endif
356         if (!shadow)
357                 setspent ();
358
359 #ifdef  USE_NIS
360       again:
361         /*
362          * See if we are reading from the local file.
363          */
364
365         if (nis_state == native || nis_state == native2) {
366
367                 /*
368                  * Get the next entry from the shadow file.  Return NULL
369                  * right away if there is none.
370                  */
371
372                 val = fgetspent (shadow);
373                 if (NULL == val)
374                         return 0;
375
376                 /*
377                  * If this entry began with a NIS escape character, we have
378                  * to see if this is just a single user, or if the entire
379                  * map is being asked for.
380                  */
381
382                 if (IS_NISCHAR (val->sp_namp[0])) {
383                         if (val->sp_namp[1])
384                                 nis_1_user = 1;
385                         else
386                                 nis_state = start;
387                 }
388
389                 /*
390                  * If this isn't a NIS user and this isn't an escape to go
391                  * use a NIS map, it must be a regular local user.
392                  */
393
394                 if (nis_1_user == 0 && nis_state != start)
395                         return val;
396
397                 /*
398                  * If this is an escape to use an NIS map, switch over to
399                  * that bunch of code.
400                  */
401
402                 if (nis_state == start)
403                         goto again;
404
405                 /*
406                  * NEEDSWORK.  Here we substitute pieces-parts of this entry.
407                  */
408
409                 return 0;
410         } else {
411                 if (nis_bound == 0) {
412                         if (bind_nis ()) {
413                                 nis_state = native2;
414                                 goto again;
415                         }
416                 }
417                 if (nis_state == start) {
418                         if (yp_first (nis_domain, "shadow.bynam", &nis_key,
419                                       &nis_keylen, &nis_val, &nis_vallen)) {
420                                 nis_state = native2;
421                                 goto again;
422                         }
423                         nis_state = middle;
424                 } else if (nis_state == middle) {
425                         if (yp_next (nis_domain, "shadow.bynam", nis_key,
426                                      nis_keylen, &nis_key, &nis_keylen,
427                                      &nis_val, &nis_vallen)) {
428                                 nis_state = native2;
429                                 goto again;
430                         }
431                 }
432                 return my_sgetspent (nis_val);
433         }
434 #else
435         return (fgetspent (shadow));
436 #endif
437 }
438
439 /*
440  * getspnam - get a shadow entry by name
441  */
442
443 struct spwd *getspnam (const char *name)
444 {
445         struct spwd *sp;
446
447 #ifdef  USE_NIS
448         char buf[BUFSIZ];
449         static char save_name[16];
450         int nis_disabled = 0;
451 #endif
452
453         setspent ();
454
455 #ifdef  USE_NIS
456         /*
457          * Search the shadow.byname map for this user.
458          */
459
460         if (!nis_ignore && !nis_bound)
461                 bind_nis ();
462
463         if (!nis_ignore && nis_bound) {
464                 char *cp;
465
466                 if (yp_match (nis_domain, "shadow.byname", name,
467                               strlen (name), &nis_val, &nis_vallen) == 0) {
468
469                         cp = strchr (nis_val, '\n');
470                         if (NULL != cp)
471                                 *cp = '\0';
472
473                         nis_state = middle;
474                         sp = my_sgetspent (nis_val);
475                         if (NULL != sp) {
476                                 strcpy (save_name, sp->sp_namp);
477                                 nis_key = save_name;
478                                 nis_keylen = strlen (save_name);
479                         }
480                         endspent ();
481                         return sp;
482                 } else
483                         nis_state = native2;
484         }
485 #endif
486 #ifdef  USE_NIS
487         /*
488          * NEEDSWORK -- this is a mess, and it is the same mess in the
489          * other three files.  I can't just blindly turn off NIS because
490          * this might be the first pass through the local files.  In
491          * that case, I never discover that NIS is present.
492          */
493
494         if (nis_used) {
495                 nis_ignore++;
496                 nis_disabled++;
497         }
498 #endif
499         while ((sp = getspent ()) != (struct spwd *) 0) {
500                 if (strcmp (name, sp->sp_namp) == 0)
501                         break;
502         }
503 #ifdef  USE_NIS
504         if (nis_disabled)
505                 nis_ignore--;
506 #endif
507         endspent ();
508         return (sp);
509 }
510 #else
511 extern int errno;               /* warning: ANSI C forbids an empty source file */
512 #endif