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