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