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