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