Replace `name_reinit' by `name_end' for more sensible restart.
[become] / src / name.c
CommitLineData
c4f2d992 1/* -*-c-*-
2 *
e6677daf 3 * $Id: name.c,v 1.4 1997/08/20 16:17:59 mdw Exp $
c4f2d992 4 *
5 * Looking up of names in symbol tables
6 *
7 * (c) 1997 EBI
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 $
e6677daf 32 * Revision 1.4 1997/08/20 16:17:59 mdw
33 * Replace `name_reinit' by `name_end' for more sensible restart.
34 *
607937a4 35 * Revision 1.3 1997/08/07 09:49:39 mdw
36 * Extensive modifications to handle netgroups. Also sanitise user and group
37 * names before adding them to the symbol table.
38 *
03f996bd 39 * Revision 1.2 1997/08/04 10:24:24 mdw
40 * Sources placed under CVS control.
41 *
42 * Revision 1.1 1997/07/21 13:47:46 mdw
c4f2d992 43 * Initial revision
44 *
45 */
46
47/*----- Header files ------------------------------------------------------*/
48
49/* --- ANSI headers --- */
50
607937a4 51#include <ctype.h>
c4f2d992 52#include <stdio.h>
53#include <stdlib.h>
54#include <string.h>
55
56/* --- Unix headers --- */
57
607937a4 58#include <sys/types.h>
59#include <sys/socket.h>
03f996bd 60
607937a4 61#include <netinet/in.h>
03f996bd 62
607937a4 63#include <arpa/inet.h>
64
65#include <netdb.h>
c4f2d992 66#include <grp.h>
67#include <pwd.h>
68
69/* --- Local headers --- */
70
607937a4 71#include "config.h"
72
03f996bd 73#include "become.h"
c4f2d992 74#include "class.h"
75#include "name.h"
607937a4 76#include "netg.h"
c4f2d992 77#include "sym.h"
78#include "userdb.h"
79#include "utils.h"
80
81/*----- Static variables --------------------------------------------------*/
82
83static sym_table name__table; /* Symbol table for everything */
84
85/*----- Main code ---------------------------------------------------------*/
86
607937a4 87/* --- @name__get@ --- *
88 *
89 * Arguments: @const char *p@ = pointer to the name we want
90 * @unsigned type@ = type of class it should have
91 *
92 * Returns: A pointer to a name ready to use, or zero if there's a type
93 * conflict.
94 *
95 * Use: Creates a name of the appropriate type all ready to use.
96 */
97
98static name *name__get(const char *p, unsigned type)
99{
100 unsigned f;
101 name *n = sym_find(&name__table, p, -1, sizeof(*n), &f);
102 if (!f) {
103 sym_table *t = xmalloc(sizeof(*t));
104 sym_createTable(t);
105 n->c = class_create(type, t);
106 }
107 return (n->c->type == type ? n : 0);
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
122static 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
03f996bd 140/* --- @name__users@ --- *
c4f2d992 141 *
142 * Arguments: ---
143 *
144 * Returns: ---
145 *
03f996bd 146 * Use: Adds all of the users registered with the user database to
147 * the name table. Also adds the users' primary groups.
c4f2d992 148 */
149
03f996bd 150static void name__users(void)
c4f2d992 151{
03f996bd 152 struct passwd *pw;
153 struct group *gr;
607937a4 154 char buf[32];
c4f2d992 155
03f996bd 156 userdb_iterateUsers();
157 while ((pw = userdb_nextUser()) != 0) {
03f996bd 158 name *n;
607937a4 159 int u = pw->pw_uid;
160
03f996bd 161 /* --- First, add the user to the table --- */
c4f2d992 162
607937a4 163 if (name__sanitise(pw->pw_name, buf, sizeof(buf)) &&
164 (n = name__get(buf, clType_user)) != 0)
165 sym_find(n->c->t, (char *)&u, sizeof(u), sizeof(sym_base), 0);
c4f2d992 166
03f996bd 167 /* --- Now handle the user's default group --- */
c4f2d992 168
607937a4 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)
c4f2d992 172 sym_find(n->c->t, (char *)&u, sizeof(u), sizeof(sym_base), 0);
03f996bd 173 }
174}
c4f2d992 175
03f996bd 176/* --- @name__groups@ --- *
177 *
178 * Arguments: ---
179 *
180 * Returns: ---
181 *
182 * Use: Adds users into all of their supplementary groups.
183 */
184
185static void name__groups(void)
186{
187 struct group *gr;
188 struct passwd *pw;
189 char **p;
607937a4 190 char buf[32];
03f996bd 191
192 userdb_iterateGroups();
193 while ((gr = userdb_nextGroup()) != 0) {
03f996bd 194 name *n;
195 int u;
c4f2d992 196
607937a4 197 if (name__sanitise(gr->gr_name, buf, sizeof(buf)) &&
198 (n = name__get(buf, clType_user)) != 0) {
03f996bd 199
607937a4 200 /* --- Now add all of the members --- */
201
202 for (p = gr->gr_mem; *p; p++) {
203 if ((pw = userdb_userByName(*p)) != 0) {
204 u = pw->pw_uid;
205 sym_find(n->c->t, (char *)&u, sizeof(u), sizeof(sym_base), 0);
206 }
207 }
03f996bd 208 }
607937a4 209 }
210}
03f996bd 211
607937a4 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
227typedef 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
234enum { f_host = 1, f_user = 2 };
235
236/* --- And now for the real code --- */
237
238static 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 sym_find(sc->h->c->t, a, -1, sizeof(sym_base), 0);
273 done_host:;
274 }
275
276 /* --- Add the user to the users class --- */
03f996bd 277
607937a4 278 if (sc->f & f_user && user) {
279 struct passwd *pw;
280 int u;
281
282 /* --- First ensure that I have a user class --- */
283
284 if (!sc->u) {
285 sc->name[0] = 'u';
286 sc->u = name__get(sc->name, clType_user);
287 if (!sc->u) {
288 sc->f &= ~f_user;
289 goto done_user;
c4f2d992 290 }
291 }
607937a4 292
293 /* --- Add the user to the list --- */
294
295 if ((pw = userdb_userByName(user)) == 0)
296 goto done_user;
297 u = pw->pw_uid;
298 sym_find(sc->u->c->t, (char *)&u, sizeof(u), sizeof(sym_base), 0);
299 done_user:;
300 }
301
302 return (0);
303}
304
305/* --- @name__netgroups@ --- *
306 *
307 * Arguments: ---
308 *
309 * Returns: ---
310 *
311 * Use: Populates the name table with netgroup information.
312 */
313
314void name__netgroups(void)
315{
316 netg *n;
317 char buf[32];
318 const char *p;
319 name__scanctx sc;
320
321 netg_iterate();
322 buf[1] = '_';
323 while ((n = netg_next()) != 0) {
324 p = netg_name(n);
325 if (name__sanitise(p, buf + 2, sizeof(buf) - 2) == 0)
326 continue;
327 sc.name = buf;
328 sc.u = sc.h = 0;
329 sc.f = f_host | f_user;
330 netg_scan(n, name__scan, &sc);
c4f2d992 331 }
03f996bd 332}
c4f2d992 333
03f996bd 334/* --- @name_init@ --- *
335 *
336 * Arguments: ---
337 *
338 * Returns: ---
339 *
340 * Use: Initialises the name table. Requires the user database to
607937a4 341 * be populated (see @userdb_local@ and @userdb_yp@, and
342 * @netg_init@).
03f996bd 343 */
c4f2d992 344
03f996bd 345void name_init(void)
346{
347 /* --- Initialise the name table --- */
c4f2d992 348
03f996bd 349 sym_createTable(&name__table);
c4f2d992 350
03f996bd 351 /* --- Add everyone into the table --- */
c4f2d992 352
03f996bd 353 name__users();
354 name__groups();
607937a4 355 name__netgroups();
c4f2d992 356
357 /* --- Finally add in the `all' class --- *
358 *
359 * Do that now, to prevent it being overwritten by the above.
360 */
361
362 {
363 name *n;
364 unsigned f;
365
366 n = sym_find(&name__table, "all", -1, sizeof(name), &f);
367 if (f)
368 class_dec(n->c);
369 n->c = class_all;
370 }
371}
372
e6677daf 373/* --- @name_end@ --- *
c4f2d992 374 *
375 * Arguments: ---
376 *
377 * Returns: ---
378 *
e6677daf 379 * Use: Closes down the name database, so that it can be
380 * reinitialised.
c4f2d992 381 */
382
e6677daf 383void name_end(void)
c4f2d992 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);
c4f2d992 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
416name *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 *
03f996bd 425 * Arguments: ---
c4f2d992 426 *
427 * Returns: ---
428 *
429 * Use: Dumps a complete listing of the symbol table.
430 */
431
03f996bd 432void name_dump(void)
c4f2d992 433{
e6677daf 434#ifdef TRACING
c4f2d992 435 sym_iter i;
436 name *n;
437
03f996bd 438 trace(TRACE_DEBUG, "name: dumping names");
c4f2d992 439 for (sym_createIter(&i, &name__table); (n = sym_next(&i)) != 0; ) {
03f996bd 440 trace(TRACE_DEBUG, "name: dumping `%s'", n->base.name);
441 class_dump(n->c);
c4f2d992 442 }
e6677daf 443#endif
c4f2d992 444}
445
446/*----- Test driver -------------------------------------------------------*/
447
448#ifdef TEST_RIG
449
450int main(void)
451{
607937a4 452 ego("name-test");
e6677daf 453 /* traceon(stdout, TRACE_ALL); */
c4f2d992 454 userdb_init();
455 userdb_local();
456 userdb_yp();
607937a4 457 netg_init();
c4f2d992 458 name_init();
e6677daf 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 }
c4f2d992 475 return (0);
476}
477
478#endif