]> granicus.if.org Git - shadow/blob - lib/gshadow.c
* lib/gshadow.c: Use a bool when possible instead of int integers.
[shadow] / lib / gshadow.c
1 /*
2  * Copyright (c) 1990 - 1994, Julianne Frances Haugh
3  * Copyright (c) 1996 - 1998, Marek Michałkiewicz
4  * Copyright (c) 2005       , Tomasz Kłoczko
5  * Copyright (c) 2008       , Nicolas François
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the copyright holders or contributors may not be used to
17  *    endorse or promote products derived from this software without
18  *    specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <config.h>
34
35 /* Newer versions of Linux libc already have shadow support.  */
36 #if defined(SHADOWGRP) && !defined(HAVE_SHADOWGRP)      /*{ */
37
38 #ident "$Id$"
39
40 #include <stdio.h>
41 #include "prototypes.h"
42 #include "defines.h"
43 static FILE *shadow;
44 static char sgrbuf[BUFSIZ * 4];
45 static char **members = NULL;
46 static size_t nmembers = 0;
47 static char **admins = NULL;
48 static size_t nadmins = 0;
49 static struct sgrp sgroup;
50
51 #define FIELDS  4
52
53 #ifdef  USE_NIS
54 static bool nis_used;
55 static bool nis_ignore;
56 static enum { native, start, middle, native2 } nis_state;
57 static bool nis_bound;
58 static char *nis_domain;
59 static char *nis_key;
60 static int nis_keylen;
61 static char *nis_val;
62 static int nis_vallen;
63
64 #define IS_NISCHAR(c) ((c)=='+')
65 #endif
66
67 #ifdef  USE_NIS
68 /*
69  * bind_nis - bind to NIS server
70  */
71
72 static int bind_nis (void)
73 {
74         if (yp_get_default_domain (&nis_domain))
75                 return -1;
76
77         nis_bound = true;
78         return 0;
79 }
80 #endif
81
82 static char **build_list (char *s, char **list[], size_t * nlist)
83 {
84         char **ptr = *list;
85         size_t nelem = *nlist, size;
86
87         while (s != NULL && *s != '\0') {
88                 size = (nelem + 1) * sizeof (ptr);
89                 if ((ptr = realloc (*list, size)) != NULL) {
90                         ptr[nelem] = s;
91                         nelem++;
92                         *list = ptr;
93                         *nlist = nelem;
94                         s = strchr (s, ',');
95                         if (NULL != s) {
96                                 *s = '\0';
97                                 s++;
98                         }
99                 }
100         }
101         size = (nelem + 1) * sizeof (ptr);
102         ptr = realloc (*list, size);
103         if (NULL != ptr) {
104                 ptr[nelem] = NULL;
105                 *list = ptr;
106         }
107         return ptr;
108 }
109
110 void setsgent (void)
111 {
112 #ifdef  USE_NIS
113         nis_state = native;
114 #endif
115         if (NULL != shadow) {
116                 rewind (shadow);
117         } else {
118                 shadow = fopen (SGROUP_FILE, "r");
119         }
120 }
121
122 void endsgent (void)
123 {
124         if (NULL != shadow) {
125                 (void) fclose (shadow);
126         }
127
128         shadow = (FILE *) 0;
129 }
130
131 struct sgrp *sgetsgent (const char *string)
132 {
133         char *fields[FIELDS];
134         char *cp;
135         int i;
136
137         strncpy (sgrbuf, string, sizeof sgrbuf - 1);
138         sgrbuf[sizeof sgrbuf - 1] = '\0';
139
140         cp = strrchr (sgrbuf, '\n');
141         if (NULL != cp) {
142                 *cp = '\0';
143         }
144
145         /*
146          * There should be exactly 4 colon separated fields.  Find
147          * all 4 of them and save the starting addresses in fields[].
148          */
149
150         for (cp = sgrbuf, i = 0; (i < FIELDS) && (NULL != cp); i++) {
151                 fields[i] = cp;
152                 cp = strchr (cp, ':');
153                 if (NULL != cp) {
154                         *cp++ = '\0';
155                 }
156         }
157
158         /*
159          * If there was an extra field somehow, or perhaps not enough,
160          * the line is invalid.
161          */
162
163         if ((NULL != cp) || (i != FIELDS))
164 #ifdef  USE_NIS
165                 if (!IS_NISCHAR (fields[0][0])) {
166                         return 0;
167                 } else {
168                         nis_used = true;
169                 }
170 #else
171                 return 0;
172 #endif
173
174         sgroup.sg_name = fields[0];
175         sgroup.sg_passwd = fields[1];
176         if (0 != nadmins) {
177                 nadmins = 0;
178                 free (admins);
179                 admins = NULL;
180         }
181         if (0 != nmembers) {
182                 nmembers = 0;
183                 free (members);
184                 members = NULL;
185         }
186         sgroup.sg_adm = build_list (fields[2], &admins, &nadmins);
187         sgroup.sg_mem = build_list (fields[3], &members, &nmembers);
188
189         return &sgroup;
190 }
191
192 /*
193  * fgetsgent - convert next line in stream to (struct sgrp)
194  *
195  * fgetsgent() reads the next line from the provided stream and
196  * converts it to a (struct sgrp).  NULL is returned on EOF.
197  */
198
199 struct sgrp *fgetsgent (FILE * fp)
200 {
201         char buf[sizeof sgrbuf];
202         char *cp;
203
204         if (NULL == fp) {
205                 return (0);
206         }
207
208 #ifdef  USE_NIS
209         while (fgetsx (buf, (int) sizeof buf, fp) != (char *) 0)
210 #else
211         if (fgetsx (buf, (int) sizeof buf, fp) != (char *) 0)
212 #endif
213         {
214                 cp = strchr (buf, '\n');
215                 if (NULL != cp) {
216                         *cp = '\0';
217                 }
218 #ifdef  USE_NIS
219                 if (nis_ignore && IS_NISCHAR (buf[0])) {
220                         continue;
221                 }
222 #endif
223                 return (sgetsgent (buf));
224         }
225         return 0;
226 }
227
228 /*
229  * getsgent - get a single shadow group entry
230  */
231
232 struct sgrp *getsgent (void)
233 {
234 #ifdef  USE_NIS
235         bool nis_1_group = false;
236         struct sgrp *val;
237         char buf[BUFSIZ];
238 #endif
239         if (NULL == shadow) {
240                 setsgent ();
241         }
242
243 #ifdef  USE_NIS
244       again:
245         /*
246          * See if we are reading from the local file.
247          */
248
249         if (nis_state == native || nis_state == native2) {
250
251                 /*
252                  * Get the next entry from the shadow group file.  Return
253                  * NULL right away if there is none.
254                  */
255
256                 val = fgetsgent (shadow);
257                 if (NULL == val) {
258                         return 0;
259                 }
260
261                 /*
262                  * If this entry began with a NIS escape character, we have
263                  * to see if this is just a single group, or if the entire
264                  * map is being asked for.
265                  */
266
267                 if (IS_NISCHAR (val->sg_name[0])) {
268                         if ('\0' != val->sg_name[1]) {
269                                 nis_1_group = true;
270                         } else {
271                                 nis_state = start;
272                         }
273                 }
274
275                 /*
276                  * If this isn't a NIS group and this isn't an escape to go
277                  * use a NIS map, it must be a regular local group.
278                  */
279
280                 if (!nis_1_group && (nis_state != start)) {
281                         return val;
282                 }
283
284                 /*
285                  * If this is an escape to use an NIS map, switch over to
286                  * that bunch of code.
287                  */
288
289                 if (nis_state == start) {
290                         goto again;
291                 }
292
293                 /*
294                  * NEEDSWORK.  Here we substitute pieces-parts of this entry.
295                  */
296
297                 return 0;
298         } else {
299                 if (!nis_bound) {
300                         if (bind_nis ()) {
301                                 nis_state = native2;
302                                 goto again;
303                         }
304                 }
305                 if (nis_state == start) {
306                         if (yp_first (nis_domain, "gshadow.byname", &nis_key,
307                                       &nis_keylen, &nis_val, &nis_vallen)) {
308                                 nis_state = native2;
309                                 goto again;
310                         }
311                         nis_state = middle;
312                 } else if (nis_state == middle) {
313                         if (yp_next (nis_domain, "gshadow.byname", nis_key,
314                                      nis_keylen, &nis_key, &nis_keylen,
315                                      &nis_val, &nis_vallen)) {
316                                 nis_state = native2;
317                                 goto again;
318                         }
319                 }
320                 return sgetsgent (nis_val);
321         }
322 #else
323         return (fgetsgent (shadow));
324 #endif
325 }
326
327 /*
328  * getsgnam - get a shadow group entry by name
329  */
330
331 struct sgrp *getsgnam (const char *name)
332 {
333         struct sgrp *sgrp;
334
335 #ifdef  USE_NIS
336         char buf[BUFSIZ];
337         static char save_name[16];
338         int nis_disabled = 0;
339 #endif
340
341         setsgent ();
342
343 #ifdef  USE_NIS
344         if (nis_used) {
345               again:
346
347                 /*
348                  * Search the gshadow.byname map for this group.
349                  */
350
351                 if (!nis_bound) {
352                         bind_nis ();
353                 }
354
355                 if (nis_bound) {
356                         char *cp;
357
358                         if (yp_match (nis_domain, "gshadow.byname", name,
359                                       strlen (name), &nis_val,
360                                       &nis_vallen) == 0) {
361                                 cp = strchr (nis_val, '\n');
362                                 if (NULL != cp) {
363                                         *cp = '\0';
364                                 }
365
366                                 nis_state = middle;
367                                 sgrp = sgetsgent (nis_val);
368                                 if (NULL != sgrp) {
369                                         strcpy (save_name, sgrp->sg_name);
370                                         nis_key = save_name;
371                                         nis_keylen = strlen (save_name);
372                                 }
373                                 return sgrp;
374                         }
375                 }
376                 nis_state = native2;
377         }
378 #endif
379 #ifdef  USE_NIS
380         if (nis_used) {
381                 nis_ignore = true;
382                 nis_disabled = true;
383         }
384 #endif
385         while ((sgrp = getsgent ()) != (struct sgrp *) 0) {
386                 if (strcmp (name, sgrp->sg_name) == 0) {
387                         break;
388                 }
389         }
390 #ifdef  USE_NIS
391         nis_ignore = false;
392 #endif
393         return sgrp;
394 }
395
396 /*
397  * putsgent - output shadow group entry in text form
398  *
399  * putsgent() converts the contents of a (struct sgrp) to text and
400  * writes the result to the given stream.  This is the logical
401  * opposite of fgetsgent.
402  */
403
404 int putsgent (const struct sgrp *sgrp, FILE * fp)
405 {
406         char *buf, *cp;
407         int i;
408         size_t size;
409
410         if ((NULL == fp) || (NULL == sgrp)) {
411                 return -1;
412         }
413
414         /* calculate the required buffer size */
415         size = strlen (sgrp->sg_name) + strlen (sgrp->sg_passwd) + 10;
416         for (i = 0; (NULL != sgrp->sg_adm) && (NULL != sgrp->sg_adm[i]); i++) {
417                 size += strlen (sgrp->sg_adm[i]) + 1;
418         }
419         for (i = 0; (NULL != sgrp->sg_mem) && (NULL != sgrp->sg_mem[i]); i++) {
420                 size += strlen (sgrp->sg_mem[i]) + 1;
421         }
422
423         buf = malloc (size);
424         if (NULL == buf) {
425                 return -1;
426         }
427         cp = buf;
428
429         /*
430          * Copy the group name and passwd.
431          */
432
433         strcpy (cp, sgrp->sg_name);
434         cp += strlen (cp);
435         *cp++ = ':';
436
437         strcpy (cp, sgrp->sg_passwd);
438         cp += strlen (cp);
439         *cp++ = ':';
440
441         /*
442          * Copy the administrators, separating each from the other
443          * with a ",".
444          */
445
446         for (i = 0; NULL != sgrp->sg_adm[i]; i++) {
447                 if (i > 0) {
448                         *cp++ = ',';
449                 }
450
451                 strcpy (cp, sgrp->sg_adm[i]);
452                 cp += strlen (cp);
453         }
454         *cp++ = ':';
455
456         /*
457          * Now do likewise with the group members.
458          */
459
460         for (i = 0; NULL != sgrp->sg_mem[i]; i++) {
461                 if (i > 0) {
462                         *cp = ',';
463                         cp++;
464                 }
465
466                 strcpy (cp, sgrp->sg_mem[i]);
467                 cp += strlen (cp);
468         }
469         *cp = '\n';
470         cp++;
471         *cp = '\0';
472
473         /*
474          * Output using the function which understands the line
475          * continuation conventions.
476          */
477
478         if (fputsx (buf, fp) == EOF) {
479                 free (buf);
480                 return -1;
481         }
482
483         free (buf);
484         return 0;
485 }
486 #else
487 extern int errno;               /* warning: ANSI C forbids an empty source file */
488 #endif                          /*} SHADOWGRP */