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