chiark / gitweb /
Fixed bug in password and group file reading: strtok doesn't handle
[become] / src / name.c
1 /* -*-c-*-
2  *
3  * $Id: name.c,v 1.7 1998/04/23 13:23:56 mdw Exp $
4  *
5  * Looking up of names in symbol tables
6  *
7  * (c) 1998 EBI
8  */
9
10 /*----- Licensing notice --------------------------------------------------*
11  *
12  * This file is part of `become'
13  *
14  * `Become' is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * `Become' is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with `become'; if not, write to the Free Software Foundation,
26  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 /*----- Revision history --------------------------------------------------*
30  *
31  * $Log: name.c,v $
32  * Revision 1.7  1998/04/23 13:23:56  mdw
33  * Fix bugs involving empty classes.
34  *
35  * Revision 1.6  1998/01/12 16:46:14  mdw
36  * Fix copyright date.
37  *
38  * Revision 1.5  1997/09/17  10:26:11  mdw
39  * Use rewritten class handler.  Support `none' class.
40  *
41  * Revision 1.4  1997/08/20  16:17:59  mdw
42  * Replace `name_reinit' by `name_end' for more sensible restart.
43  *
44  * Revision 1.3  1997/08/07 09:49:39  mdw
45  * Extensive modifications to handle netgroups.  Also sanitise user and group
46  * names before adding them to the symbol table.
47  *
48  * Revision 1.2  1997/08/04 10:24:24  mdw
49  * Sources placed under CVS control.
50  *
51  * Revision 1.1  1997/07/21  13:47:46  mdw
52  * Initial revision
53  *
54  */
55
56 /*----- Header files ------------------------------------------------------*/
57
58 /* --- ANSI headers --- */
59
60 #include <ctype.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64
65 /* --- Unix headers --- */
66
67 #include <sys/types.h>
68 #include <sys/socket.h>
69
70 #include <netinet/in.h>
71
72 #include <arpa/inet.h>
73
74 #include <netdb.h>
75 #include <grp.h>
76 #include <pwd.h>
77
78 /* --- Local headers --- */
79
80 #include "config.h"
81
82 #include "become.h"
83 #include "class.h"
84 #include "name.h"
85 #include "netg.h"
86 #include "sym.h"
87 #include "userdb.h"
88 #include "utils.h"
89
90 /*----- Static variables --------------------------------------------------*/
91
92 static sym_table name__table;           /* Symbol table for everything */
93
94 /*----- Main code ---------------------------------------------------------*/
95
96 /* --- @name__get@ --- *
97  *
98  * Arguments:   @const char *p@ = pointer to the name we want
99  *              @unsigned type@ = type of class it should have
100  *
101  * Returns:     A pointer to a name ready to use, or zero if there's a type
102  *              conflict.
103  *
104  * Use:         Creates a name of the appropriate type all ready to use.
105  */
106
107 static name *name__get(const char *p, unsigned type)
108 {
109   unsigned f;
110   name *n = sym_find(&name__table, p, -1, sizeof(*n), &f);
111   if (!f)
112     n->c = 0;
113   return ((n->c && !(n->c->type & type)) ? 0 : n);
114 }
115
116 /* --- @name__sanitise@ --- *
117  *
118  * Arguments:   @const char *n@ = pointer to a name
119  *              @char *buf@ = pointer to a buffer of space
120  *              @size_t sz@ = size of the buffer
121  *
122  * Returns:     A pointer to the transformed name in the buffer, or null
123  *              if there wasn't enough space.
124  *
125  * Use:         Transforms a name so that it only contains nice characters.
126  */
127
128 static char *name__sanitise(const char *n, char *buf, size_t sz)
129 {
130   char *p = buf;
131
132   if (strlen(n) + 1 > sz)
133     return (0);
134
135   while (*n) {
136     if (isalnum((unsigned char)*n))
137       *p++ = *n;
138     else
139       *p++ = '_';
140     n++;
141   }
142   *p++ = 0;
143   return (buf);
144 }
145
146 /* --- @name__users@ --- *
147  *
148  * Arguments:   ---
149  *
150  * Returns:     ---
151  *
152  * Use:         Adds all of the users registered with the user database to
153  *              the name table.  Also adds the users' primary groups.
154  */
155
156 static void name__users(void)
157 {
158   struct passwd *pw;
159   struct group *gr;
160   char buf[32];
161
162   userdb_iterateUsers();
163   while ((pw = userdb_nextUser()) != 0) {
164     name *n;
165     uid_t u = pw->pw_uid;
166
167     /* --- First, add the user to the table --- */
168
169     if (name__sanitise(pw->pw_name, buf, sizeof(buf)) &&
170         (n = name__get(buf, clType_user)) != 0)
171       n->c = class_addUser(n->c, u);
172
173     /* --- Now handle the user's default group --- */
174
175     if ((gr = userdb_groupById(pw->pw_gid)) != 0 &&
176         name__sanitise(gr->gr_name, buf, sizeof(buf)) &&
177         (n = name__get(buf, clType_user)) != 0)
178       n->c = class_addUser(n->c, u);
179   }
180 }
181
182 /* --- @name__groups@ --- *
183  *
184  * Arguments:   ---
185  *
186  * Returns:     ---
187  *
188  * Use:         Adds users into all of their supplementary groups.
189  */
190
191 static void name__groups(void)
192 {
193   struct group *gr;
194   struct passwd *pw;
195   char **p;
196   char buf[32];
197
198   userdb_iterateGroups();
199   while ((gr = userdb_nextGroup()) != 0) {
200     name *n;
201
202     if (name__sanitise(gr->gr_name, buf, sizeof(buf)) &&
203         (n = name__get(buf, clType_user)) != 0) {
204
205       /* --- Now add all of the members --- */
206
207       for (p = gr->gr_mem; *p; p++) {
208         if ((pw = userdb_userByName(*p)) != 0)
209           n->c = class_addUser(n->c, pw->pw_uid);
210       }
211       if (!n->c)
212         n->c = class_none;
213     }
214   }
215 }
216
217 /* --- @name__scan@ --- *
218  *
219  * Arguments:   @netg *n@ = the netgroup handle we're scanning
220  *              @const char *host@ = the host name
221  *              @const char *user@ = the user name
222  *              @const char *domain@ = the (NIS?) domain name
223  *              @void *ctx@ = some context pointer
224  *
225  * Returns:     Zero to continue scanning.
226  *
227  * Use:         Scans a netgroup, adding items to the name table.
228  */
229
230 /* --- A data type --- */
231
232 typedef struct name__scanctx {
233   char *name;                           /* Netgroup name prefixed with `?_'*/
234   unsigned f;                           /* Various interesting flags */
235   name *h;                              /* Name entry for hosts */
236   name *u;                              /* Name entry for users */
237 } name__scanctx;
238
239 enum { f_host = 1, f_user = 2 };
240
241 /* --- And now for the real code --- */
242
243 static int name__scan(netg *n, const char *host, const char *user,
244                       const char *domain, void *ctx)
245 {
246   name__scanctx *sc = ctx;
247
248   /* --- Add the host to the hosts class --- */
249
250   if (sc->f & f_host && host) {
251     struct hostent *h;
252     struct in_addr in;
253     const char *a;
254
255     /* --- First ensure that I have a host class --- */
256
257     if (!sc->h) {
258       sc->name[0] = 'h';
259       sc->h = name__get(sc->name, clType_host);
260       if (!sc->h) {
261         sc->f &= ~f_host;
262         goto done_host;
263       }
264     }
265
266     /* --- Now that I've done that, try to add the host --- *
267      *
268      * I'll turn it into an IP address.  There's less chance of confusion
269      * that way.
270      */
271
272     if ((h = gethostbyname(host)) == 0)
273       goto done_host;
274     memcpy(&in, h->h_addr, sizeof(in));
275     if ((a = inet_ntoa(in)) == 0)
276       goto done_host;
277     sc->h->c = class_addString(sc->h->c, a);
278   done_host:;
279   }
280
281   /* --- Add the user to the users class --- */
282
283   if (sc->f & f_user && user) {
284     struct passwd *pw;
285     
286     /* --- First ensure that I have a user class --- */
287
288     if (!sc->u) {
289       sc->name[0] = 'u';
290       sc->u = name__get(sc->name, clType_user);
291       if (!sc->u) {
292         sc->f &= ~f_user;
293         goto done_user;
294       }
295     }
296
297     /* --- Add the user to the list --- */
298
299     if ((pw = userdb_userByName(user)) == 0)
300       goto done_user;
301     sc->u->c = class_addUser(sc->u->c, pw->pw_uid);
302   done_user:;
303   }
304
305   return (0);
306 }
307
308 /* --- @name__netgroups@ --- *
309  *
310  * Arguments:   ---
311  *
312  * Returns:     ---
313  *
314  * Use:         Populates the name table with netgroup information.
315  */
316
317 void name__netgroups(void)
318 {
319   netg *n;
320   char buf[32];
321   const char *p;
322   name__scanctx sc;
323
324   netg_iterate();
325   buf[1] = '_';
326   while ((n = netg_next()) != 0) {
327     p = netg_name(n);
328     if (name__sanitise(p, buf + 2, sizeof(buf) - 2) == 0)
329       continue;
330     sc.name = buf;
331     sc.u = sc.h = 0;
332     sc.f = f_host | f_user;
333     netg_scan(n, name__scan, &sc);
334   }
335 }
336
337 /* --- @name_init@ --- *
338  *
339  * Arguments:   ---
340  *
341  * Returns:     ---
342  *
343  * Use:         Initialises the name table.  Requires the user database to
344  *              be populated (see @userdb_local@ and @userdb_yp@, and
345  *              @netg_init@).
346  */
347
348 void name_init(void)
349 {
350   /* --- Initialise the name table --- */
351
352   sym_createTable(&name__table);
353
354   /* --- Add everyone into the table --- */
355
356   name__users();
357   name__groups();
358   name__netgroups();
359
360   /* --- Finally add in the `all' and `none' classes --- *
361    *
362    * Do that now, to prevent them being overwritten by the above.
363    */
364
365   {
366     name *n;
367     unsigned f;
368
369     n = sym_find(&name__table, "all", -1, sizeof(name), &f);
370     if (f)
371       class_dec(n->c);
372     n->c = class_all;
373
374     n = sym_find(&name__table, "none", -1, sizeof(name), &f);
375     if (f)
376       class_dec(n->c);
377     n->c = class_none;
378   }
379 }
380
381 /* --- @name_end@ --- *
382  *
383  * Arguments:   ---
384  *
385  * Returns:     ---
386  *
387  * Use:         Closes down the name database, so that it can be
388  *              reinitialised.
389  */
390
391 void name_end(void)
392 {
393   /* --- Empty the symbol table --- */
394
395   {
396     sym_iter i;
397     name *n;
398
399     for (sym_createIter(&i, &name__table); (n = sym_next(&i)) != 0; ) {
400       if (n->c)
401         class_dec(n->c);
402     }
403   }
404
405   /* --- Destroy and recreate the table --- */
406
407   sym_destroyTable(&name__table);
408 }
409
410 /* --- @name_find@ --- *
411  *
412  * Arguments:   @const char *p@ = pointer to name to look up
413  *              @unsigned create@ = whether to create the item
414  *              @unsigned *f@ = whether the item was created
415  *
416  * Returns:     Pointer to a @name@ block containing the symbol, or
417  *              zero if it wasn't found and we didn't want to create a
418  *              new one.
419  *
420  * Use:         Looks up a name in the symbol table and returns the
421  *              item so located.
422  */
423
424 name *name_find(const char *p, unsigned create, unsigned *f)
425 {
426   /* --- This is a trivial veneer onto @sym_find@ --- */
427
428   return (sym_find(&name__table, p, -1, create ? sizeof(name) : 0, f));
429 }
430
431 /* --- @name_dump@ --- *
432  *
433  * Arguments:   ---
434  *
435  * Returns:     ---
436  *
437  * Use:         Dumps a complete listing of the symbol table.
438  */
439
440 void name_dump(void)
441 {
442 #ifdef TRACING
443   sym_iter i;
444   name *n;
445
446   trace(TRACE_DEBUG, "name: dumping names");
447   for (sym_createIter(&i, &name__table); (n = sym_next(&i)) != 0; ) {
448     trace(TRACE_DEBUG, "name: dumping `%s'", n->base.name);
449     if (!n->c)
450       trace(TRACE_DEBUG, "name:   <empty>");
451     else
452       class_dump(n->c, 1);
453   }
454 #endif
455 }  
456
457 /*----- Test driver -------------------------------------------------------*/
458
459 #ifdef TEST_RIG
460
461 int main(void)
462 {
463   ego("name-test");
464   traceon(stdout, TRACE_ALL);
465   userdb_init();
466   userdb_local();
467   userdb_yp();
468   netg_init();
469   name_init();
470   /* printf("loaded (%lu)\n", track_memused()); */
471 #ifdef notdef
472   getchar();
473   for (;;) {
474     name_end();
475     netg_end();
476     userdb_end();
477     /* printf("cleared (%lu)\n", track_memused()); */
478     /* track_memlist(); */
479     userdb_init();
480     userdb_local();
481     userdb_yp();
482     netg_init();
483     name_init();
484     /* printf("reloaded (%lu)\n", track_memused()); */
485     getchar();
486   }
487 #else
488   name_dump();
489 #endif
490   return (0);
491 }
492
493 #endif