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