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