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