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