c4f2d992 |
1 | /* -*-c-*- |
2 | * |
8bdddfb7 |
3 | * $Id: userdb.c,v 1.10 2003/10/12 00:39:16 mdw Exp $ |
c4f2d992 |
4 | * |
5 | * User database management |
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: userdb.c,v $ |
8bdddfb7 |
32 | * Revision 1.10 2003/10/12 00:39:16 mdw |
33 | * Light fixes for strange building. |
34 | * |
f60a3434 |
35 | * Revision 1.9 2003/10/12 00:14:55 mdw |
36 | * Major overhaul. Now uses DSA signatures rather than the bogus symmetric |
37 | * encrypt-and-hope thing. Integrated with mLib and Catacomb. |
38 | * |
e171c3bf |
39 | * Revision 1.8 1998/06/08 11:21:22 mdw |
40 | * Fixed bug in password and group file reading: strtok doesn't handle |
41 | * double colons nicely. |
42 | * |
a340752b |
43 | * Revision 1.7 1998/04/23 13:27:46 mdw |
44 | * Switch to using the ypstuff interface to YP server. |
45 | * |
c758e654 |
46 | * Revision 1.6 1998/01/12 16:46:33 mdw |
47 | * Fix copyright date. |
48 | * |
49 | * Revision 1.5 1997/09/17 10:24:08 mdw |
d8cd61fe |
50 | * Use `uid_t' instead of `int' for uids and gids. Not quite sure why I |
51 | * didn't do this before. |
52 | * |
53 | * Revision 1.4 1997/08/20 16:24:58 mdw |
46cc26eb |
54 | * Patch memory leak. Rename `userdb_reinit' to `userdb_end' for more |
55 | * sensible restart. |
56 | * |
e893b83f |
57 | * Revision 1.3 1997/08/07 09:44:29 mdw |
58 | * Read NIS-based passwords from the YP server directly, rather than using |
59 | * `popen(ypcat)', which is probably both slower and less secure. |
60 | * |
03f996bd |
61 | * Revision 1.2 1997/08/04 10:24:26 mdw |
62 | * Sources placed under CVS control. |
63 | * |
64 | * Revision 1.1 1997/07/21 13:47:43 mdw |
c4f2d992 |
65 | * Initial revision |
66 | * |
67 | */ |
68 | |
69 | /*----- Header files ------------------------------------------------------*/ |
70 | |
71 | /* --- ANSI headers --- */ |
72 | |
73 | #include <ctype.h> |
74 | #include <errno.h> |
75 | #include <stdio.h> |
76 | #include <stdlib.h> |
77 | #include <string.h> |
78 | |
79 | /* --- Unix headers --- */ |
80 | |
03f996bd |
81 | #include "config.h" |
82 | |
c4f2d992 |
83 | #include <sys/types.h> |
84 | |
85 | #include <grp.h> |
86 | #include <pwd.h> |
87 | #include <unistd.h> |
88 | |
f60a3434 |
89 | /* --- mLib headers --- */ |
90 | |
91 | #include <mLib/alloc.h> |
92 | #include <mLib/sym.h> |
93 | #include <mLib/trace.h> |
94 | |
c4f2d992 |
95 | /* --- Local headers --- */ |
96 | |
e893b83f |
97 | #include "become.h" |
c4f2d992 |
98 | #include "userdb.h" |
a340752b |
99 | #include "ypstuff.h" |
c4f2d992 |
100 | |
101 | /*----- Type definitions --------------------------------------------------*/ |
102 | |
103 | /* --- A map link --- */ |
104 | |
105 | typedef struct userdb__node { |
106 | struct userdb__node *next; |
107 | void *rec; |
108 | } userdb__node; |
109 | |
110 | /* --- A reference to a real record --- */ |
111 | |
112 | typedef struct userdb__sym { |
113 | sym_base _base; |
114 | void *rec; |
115 | } userdb__sym; |
116 | |
117 | /* --- A name- and number-mapping --- */ |
118 | |
119 | typedef struct userdb__map { |
120 | sym_table nmap; |
121 | sym_table idmap; |
122 | userdb__node *list; |
123 | } userdb__map; |
124 | |
125 | /*----- Static variables --------------------------------------------------*/ |
126 | |
127 | static userdb__map userdb__users; /* Map of user info blocks */ |
128 | static sym_iter userdb__useri; /* Iterator for users */ |
129 | static userdb__map userdb__groups; /* Map of group info blocks */ |
130 | static sym_iter userdb__groupi; /* Iterator for groups */ |
131 | |
132 | /*----- Map management functions ------------------------------------------*/ |
133 | |
134 | /* --- @userdb__createMap@ --- * |
135 | * |
136 | * Arguments: @userdb__map *m@ = pointer to a map block |
137 | * |
138 | * Returns: --- |
139 | * |
140 | * Use: Initialises a map table. |
141 | */ |
142 | |
143 | static void userdb__createMap(userdb__map *m) |
144 | { |
f60a3434 |
145 | sym_create(&m->nmap); |
146 | sym_create(&m->idmap); |
c4f2d992 |
147 | m->list = 0; |
148 | } |
149 | |
150 | /* --- @userdb__addToMap@ --- * |
151 | * |
152 | * Arguments: @userdb__map *m@ = pointer to the map block |
153 | * @const char *name@ = pointer to the item's name |
d8cd61fe |
154 | * @uid_t id@ = the item's id number |
c4f2d992 |
155 | * @void *rec@ = pointer to the actual record |
156 | * |
157 | * Returns: --- |
158 | * |
159 | * Use: Adds an item to the given map. |
160 | */ |
161 | |
162 | static void userdb__addToMap(userdb__map *m, |
163 | const char *name, |
d8cd61fe |
164 | uid_t id, void *rec) |
c4f2d992 |
165 | { |
166 | unsigned f; |
167 | userdb__sym *s; |
168 | userdb__node *n; |
169 | |
170 | s = sym_find(&m->nmap, name, -1, sizeof(*s), &f); |
171 | if (!f) |
172 | s->rec = rec; |
173 | |
174 | s = sym_find(&m->idmap, (char *)&id, sizeof(id), sizeof(*s), &f); |
175 | if (!f) |
176 | s->rec = rec; |
177 | |
178 | n = xmalloc(sizeof(*n)); |
179 | n->rec = rec; |
180 | n->next = m->list; |
181 | m->list = n; |
182 | } |
183 | |
184 | /* --- @userdb__byName@ --- * |
185 | * |
186 | * Arguments: @userdb__map *m@ = pointer to a map block |
187 | * @const char *name@ = name to look up |
188 | * |
189 | * Returns: A pointer to the appropriate block, or zero if not found. |
190 | * |
191 | * Use: Looks up a name in a mapping and returns the result. |
192 | */ |
193 | |
194 | static void *userdb__byName(userdb__map *m, const char *name) |
195 | { |
196 | userdb__sym *s = sym_find(&m->nmap, name, -1, 0, 0); |
197 | return (s ? s->rec : 0); |
198 | } |
199 | |
200 | /* --- @userdb__byId@ --- * |
201 | * |
202 | * Arguments: @userdb__map *m@ = pointer to a map block |
d8cd61fe |
203 | * @uid_t id@ = id number to find |
c4f2d992 |
204 | * |
205 | * Returns: A pointer to the appropriate block, or zero if not found. |
206 | * |
207 | * Use: Looks up an ID in a mapping, and returns the result. |
208 | */ |
209 | |
d8cd61fe |
210 | static void *userdb__byId(userdb__map *m, uid_t id) |
c4f2d992 |
211 | { |
212 | userdb__sym *s = sym_find(&m->idmap, (char *)&id, sizeof(id), 0, 0); |
213 | return (s ? s->rec : 0); |
214 | } |
215 | |
216 | /* --- @userdb__clearMap@ --- * |
217 | * |
218 | * Arguments: @userdb__map *m@ = pointer to a map block |
219 | * @void (*freerec)(void *rec)@ = pointer to a free-record proc |
220 | * |
221 | * Returns: --- |
222 | * |
223 | * Use: Clears a map, emptying it and releasing the memory it |
224 | * occupied. |
225 | */ |
226 | |
227 | static void userdb__clearMap(userdb__map *m, void (*freerec)(void *rec)) |
228 | { |
229 | userdb__node *n, *t; |
230 | |
f60a3434 |
231 | sym_destroy(&m->nmap); |
232 | sym_destroy(&m->idmap); |
c4f2d992 |
233 | |
234 | for (n = m->list; n; n = t) { |
235 | t = n->next; |
236 | freerec(n->rec); |
237 | free(n); |
238 | } |
239 | } |
240 | |
241 | /*----- User and group block management -----------------------------------*/ |
242 | |
243 | /* --- @userdb__dumpUser@ --- * |
244 | * |
245 | * Arguments: @const struct passwd *pw@ = pointer to a user block |
c4f2d992 |
246 | * |
247 | * Returns: --- |
248 | * |
249 | * Use: Writes a user's informationt to a stream. |
250 | */ |
251 | |
f60a3434 |
252 | #ifndef NTRACE |
c4f2d992 |
253 | |
e893b83f |
254 | static void userdb__dumpUser(const struct passwd *pw) |
c4f2d992 |
255 | { |
e893b83f |
256 | trace(TRACE_DEBUG, |
257 | "debug: name `%s' passwd `%s' uid %i gid %i", |
258 | pw->pw_name, pw->pw_passwd, (int)pw->pw_uid, (int)pw->pw_gid); |
259 | trace(TRACE_DEBUG, |
260 | "debug: ... gecos `%s' home `%s' shell `%s'", |
261 | pw->pw_gecos, pw->pw_dir, pw->pw_shell); |
c4f2d992 |
262 | } |
263 | |
c4f2d992 |
264 | #endif |
265 | |
e171c3bf |
266 | /* --- @userdb__split@ --- * |
267 | * |
268 | * Arguments: @char *p@ = pointer to string |
269 | * @char **v@ = pointer to vector to fill in |
270 | * @int sz@ = maximum number of fields to split |
271 | * |
272 | * Returns: Number of fields extracted. |
273 | * |
274 | * Use: Splits a string into fields at colon characters. |
275 | */ |
276 | |
277 | static int userdb__split(char *p, char **v, int sz) |
278 | { |
279 | int count = 0; |
280 | |
281 | *v++ = p; sz--; count++; |
282 | if (!sz) |
283 | goto done; |
284 | while (*p) { |
285 | if (*p++ == ':') { |
286 | p[-1] = 0; |
287 | *v++ = p; sz--; count++; |
288 | if (!sz) |
289 | goto done; |
290 | } |
291 | } |
292 | while (sz--) |
293 | *v++ = 0; |
294 | |
295 | done: |
296 | return (count); |
297 | } |
298 | |
c4f2d992 |
299 | /* --- @userdb_copyUser@ --- * |
300 | * |
301 | * Arguments: @struct passwd *pw@ = pointer to block to copy |
302 | * |
303 | * Returns: Pointer to the copy. |
304 | * |
305 | * Use: Copies a user block. The copy is `deep' so all the strings |
306 | * are copied too. Free the copy with @userdb_freeUser@ when |
307 | * you don't want it any more. |
308 | */ |
309 | |
310 | struct passwd *userdb_copyUser(struct passwd *pw) |
311 | { |
312 | struct passwd *npw; |
313 | |
314 | if (!pw) |
315 | return (0); |
316 | |
317 | npw = xmalloc(sizeof(*npw)); |
318 | |
319 | npw->pw_name = xstrdup(pw->pw_name); |
320 | npw->pw_passwd = xstrdup(pw->pw_passwd); |
321 | npw->pw_uid = pw->pw_uid; |
322 | npw->pw_gid = pw->pw_gid; |
323 | npw->pw_gecos = xstrdup(pw->pw_gecos); |
324 | npw->pw_dir = xstrdup(pw->pw_dir); |
325 | npw->pw_shell = xstrdup(pw->pw_shell); |
326 | |
327 | return (npw); |
328 | } |
329 | |
330 | /* --- @userdb__buildUser@ --- * |
331 | * |
332 | * Arguments: @char *s@ = pointer to user string |
333 | * |
334 | * Returns: Pointer to a user block. |
335 | * |
336 | * Use: Converts a line from a user file into a password entry. |
337 | * Note that the string is corrupted by @strtok@ while it gets |
338 | * parsed. |
339 | */ |
340 | |
341 | static struct passwd *userdb__buildUser(char *s) |
342 | { |
343 | struct passwd *pw = xmalloc(sizeof(*pw)); |
e171c3bf |
344 | char *v[7]; |
c4f2d992 |
345 | |
e171c3bf |
346 | if (userdb__split(s, v, 7) < 7) { |
347 | free(pw); |
348 | return (0); |
349 | } |
c4f2d992 |
350 | |
e171c3bf |
351 | pw->pw_name = xstrdup(v[0]); |
352 | pw->pw_passwd = xstrdup(v[1]); |
353 | pw->pw_uid = (uid_t)atol(v[2]); |
354 | pw->pw_gid = (gid_t)atol(v[3]); |
355 | pw->pw_gecos = xstrdup(v[4]); |
356 | pw->pw_dir = xstrdup(v[5]); |
357 | pw->pw_shell = xstrdup(v[6]); |
358 | return (pw); |
c4f2d992 |
359 | } |
360 | |
361 | /* --- @userdb_freeUser@ --- * |
362 | * |
363 | * Arguments: @void *rec@ = pointer to a user record |
364 | * |
365 | * Returns: --- |
366 | * |
367 | * Use: Frees a user record. |
368 | */ |
369 | |
370 | void userdb_freeUser(void *rec) |
371 | { |
372 | struct passwd *pw; |
373 | |
374 | if (!rec) |
375 | return; |
376 | |
377 | pw = rec; |
378 | free(pw->pw_name); |
379 | free(pw->pw_passwd); |
380 | free(pw->pw_gecos); |
381 | free(pw->pw_dir); |
382 | free(pw->pw_shell); |
383 | free(pw); |
384 | } |
385 | |
386 | /* --- @userdb__dumpGroup@ --- * |
387 | * |
388 | * Arguments: @const struct group *gr@ = pointer to a group block |
389 | * @FILE *fp@ = pointer to stream to write on |
390 | * |
391 | * Returns: --- |
392 | * |
393 | * Use: Writes a group's information to a stream. |
394 | */ |
395 | |
f60a3434 |
396 | #ifndef NTRACE |
c4f2d992 |
397 | |
e893b83f |
398 | static void userdb__dumpGroup(const struct group *gr) |
c4f2d992 |
399 | { |
400 | char *const *p; |
401 | |
e893b83f |
402 | trace(TRACE_DEBUG, |
403 | "debug: name `%s' passwd `%s' gid %i", |
c4f2d992 |
404 | gr->gr_name, gr->gr_passwd, (int)gr->gr_gid); |
405 | for (p = gr->gr_mem; *p; p++) |
e893b83f |
406 | trace(TRACE_DEBUG,"debug: ... `%s'", *p); |
c4f2d992 |
407 | } |
408 | |
c4f2d992 |
409 | #endif |
410 | |
411 | /* --- @userdb_copyGroup@ --- * |
412 | * |
413 | * Arguments: @struct group *gr@ = pointer to group block |
414 | * |
415 | * Returns: Pointer to copied block |
416 | * |
417 | * Use: Copies a group block. The copy is `deep' so all the strings |
418 | * are copied too. Free the copy with @userdb_freeGroup@ when |
419 | * you don't want it any more. |
420 | */ |
421 | |
422 | struct group *userdb_copyGroup(struct group *gr) |
423 | { |
424 | struct group *ngr; |
425 | int i, max; |
426 | |
427 | if (!gr) |
428 | return (0); |
429 | |
430 | ngr = xmalloc(sizeof(*ngr)); |
431 | |
432 | ngr->gr_name = xstrdup(gr->gr_name); |
433 | ngr->gr_passwd = xstrdup(gr->gr_passwd); |
434 | ngr->gr_gid = gr->gr_gid; |
435 | |
436 | for (max = 0; gr->gr_mem[max]; max++) |
437 | ; |
438 | ngr->gr_mem = xmalloc((max + 1) * sizeof(char *)); |
439 | for (i = 0; i < max; i++) |
440 | ngr->gr_mem[i] = xstrdup(gr->gr_mem[i]); |
441 | ngr->gr_mem[max] = 0; |
442 | |
443 | return (ngr); |
444 | } |
445 | |
446 | /* --- @userdb__buildGroup@ --- * |
447 | * |
448 | * Arguments: @char *s@ = pointer to group line string |
449 | * |
450 | * Returns: Pointer to a group block |
451 | * |
452 | * Use: Parses an entry in the groups file. The string is garbled |
453 | * by @strtok@ as we go. |
454 | */ |
455 | |
456 | static struct group *userdb__buildGroup(char *s) |
457 | { |
458 | struct group *gr = xmalloc(sizeof(*gr)); |
e171c3bf |
459 | char *v[4]; |
c4f2d992 |
460 | int i; |
461 | |
462 | /* --- Do the easy bits --- */ |
463 | |
e171c3bf |
464 | if (userdb__split(s, v, 4) < 3) { |
465 | free(gr); |
466 | return (0); |
467 | } |
468 | gr->gr_name = xstrdup(v[0]); |
469 | gr->gr_passwd = xstrdup(v[1]); |
470 | gr->gr_gid = (gid_t)atol(v[2]); |
c4f2d992 |
471 | |
472 | /* --- Count the number of members --- */ |
473 | |
e171c3bf |
474 | s = v[3]; |
c4f2d992 |
475 | i = 0; |
e171c3bf |
476 | if (s && s[0]) { |
477 | for (;;) { |
478 | i++; |
479 | if ((s = strpbrk(s, ",")) == 0) |
480 | break; |
481 | s++; |
482 | } |
c4f2d992 |
483 | } |
484 | |
485 | /* --- Allocate the block and fill it --- */ |
486 | |
487 | gr->gr_mem = xmalloc((i + 1) * sizeof(char *)); |
488 | i = 0; |
e171c3bf |
489 | if (v[3]) { |
490 | s = strtok(v[3], ","); |
491 | while (s) { |
492 | gr->gr_mem[i++] = xstrdup(s); |
493 | s = strtok(0, ","); |
494 | } |
495 | } |
c4f2d992 |
496 | gr->gr_mem[i] = 0; |
497 | |
498 | return (gr); |
c4f2d992 |
499 | } |
500 | |
501 | /* --- @userdb_freeGroup@ --- * |
502 | * |
503 | * Arguments: @void *rec@ = pointer to a group record |
504 | * |
505 | * Returns: --- |
506 | * |
507 | * Use: Frees a group record. |
508 | */ |
509 | |
510 | void userdb_freeGroup(void *rec) |
511 | { |
512 | struct group *gr; |
513 | char **p; |
514 | |
515 | if (!rec) |
516 | return; |
517 | |
518 | gr = rec; |
519 | free(gr->gr_name); |
520 | free(gr->gr_passwd); |
521 | for (p = gr->gr_mem; *p; p++) |
522 | free(*p); |
523 | free(gr->gr_mem); |
524 | free(gr); |
525 | } |
526 | |
03f996bd |
527 | /*----- Answering queries -------------------------------------------------*/ |
c4f2d992 |
528 | |
529 | /* --- @userdb_userByName@, @userdb_userById@ --- * |
530 | * |
531 | * Arguments: @const char *name@ = pointer to user's name |
532 | * @uid_t id@ = user id to find |
533 | * |
534 | * Returns: Pointer to user block, or zero if not found. |
535 | * |
536 | * Use: Looks up a user by name or id. |
537 | */ |
538 | |
539 | struct passwd *userdb_userByName(const char *name) |
540 | { return (userdb__byName(&userdb__users, name)); } |
541 | |
542 | struct passwd *userdb_userById(uid_t id) |
543 | { return (userdb__byId(&userdb__users, id)); } |
544 | |
545 | /* --- @userdb_iterateUsers@, @userdb_iterateUsers_r@ --- * |
546 | * |
547 | * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator object |
548 | * |
549 | * Returns: --- |
550 | * |
551 | * Use: Initialises an iteration for the user database. |
552 | */ |
553 | |
554 | void userdb_iterateUsers(void) |
555 | { userdb_iterateUsers_r(&userdb__useri); } |
556 | |
557 | void userdb_iterateUsers_r(userdb_iter *i) |
f60a3434 |
558 | { sym_mkiter(i, &userdb__users.nmap); } |
c4f2d992 |
559 | |
560 | /* --- @userdb_nextUser@, @userdb_nextUser_r@ --- * |
561 | * |
562 | * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator oject |
563 | * |
564 | * Returns: Pointer to the next user block, or null. |
565 | * |
566 | * Use: Returns another user block. |
567 | */ |
568 | |
569 | struct passwd *userdb_nextUser(void) |
570 | { return (userdb_nextUser_r(&userdb__useri)); } |
571 | |
572 | struct passwd *userdb_nextUser_r(userdb_iter *i) |
573 | { |
574 | userdb__sym *s = sym_next(i); |
575 | return (s ? s->rec : 0); |
576 | } |
577 | |
578 | /* --- @userdb_groupByName@, @userdb_groupById@ --- * |
579 | * |
580 | * Arguments: @const char *name@ = pointer to group's name |
581 | * @gid_t id@ = group id to find |
582 | * |
583 | * Returns: Pointer to group block, or zero if not found. |
584 | * |
585 | * Use: Looks up a group by name or id. |
586 | */ |
587 | |
588 | struct group *userdb_groupByName(const char *name) |
589 | { return (userdb__byName(&userdb__groups, name)); } |
590 | |
591 | struct group *userdb_groupById(gid_t id) |
592 | { return (userdb__byId(&userdb__groups, id)); } |
593 | |
594 | /* --- @userdb_iterateGroups@, @userdb_iterateGroups_r@ --- * |
595 | * |
596 | * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator object |
597 | * |
598 | * Returns: --- |
599 | * |
600 | * Use: Initialises an iteration for the group database. |
601 | */ |
602 | |
603 | void userdb_iterateGroups(void) |
604 | { userdb_iterateGroups_r(&userdb__groupi); } |
605 | |
606 | void userdb_iterateGroups_r(userdb_iter *i) |
f60a3434 |
607 | { sym_mkiter(i, &userdb__groups.nmap); } |
c4f2d992 |
608 | |
609 | /* --- @userdb_nextGroup@, @userdb_nextGroup_r@ --- * |
610 | * |
611 | * Arguments: @userdb_iter *i@ = pointer to a symbol table iterator oject |
612 | * |
613 | * Returns: Pointer to the next group block, or null. |
614 | * |
615 | * Use: Returns another group block. |
616 | */ |
617 | |
618 | struct group *userdb_nextGroup(void) |
619 | { return (userdb_nextGroup_r(&userdb__groupi)); } |
620 | |
621 | struct group *userdb_nextGroup_r(userdb_iter *i) |
622 | { |
623 | userdb__sym *s = sym_next(i); |
624 | return (s ? s->rec : 0); |
625 | } |
626 | |
03f996bd |
627 | /*----- Yellow pages support ----------------------------------------------*/ |
628 | |
629 | #ifdef HAVE_YP |
630 | |
631 | /* --- @userdb__foreachUser@ --- * |
632 | * |
633 | * Arguments: @int st@ = YP protocol-level status code |
634 | * @char *k@ = address of the key for this record |
635 | * @int ksz@ = size of the key |
636 | * @char *v@ = address of the value for this record |
637 | * @int vsz@ = size of the value |
638 | * @char *data@ = pointer to some data passed to me |
639 | * |
640 | * Returns: Zero to be called again, nonzero to end the enumeration. |
641 | * |
642 | * Use: Handles an incoming user record. |
643 | */ |
644 | |
645 | static int userdb__foreachUser(int st, char *k, int ksz, |
646 | char *v, int vsz, char *data) |
647 | { |
648 | char *cv; |
649 | struct passwd *pw; |
650 | |
651 | if (st != YP_TRUE) |
652 | return (-1); |
653 | cv = xmalloc(vsz + 1); |
654 | memcpy(cv, v, vsz); |
655 | cv[vsz] = 0; |
e893b83f |
656 | T( trace(TRACE_DEBUG, "debug: nis string: `%s'", cv); ) |
03f996bd |
657 | pw = userdb__buildUser(cv); |
e893b83f |
658 | if (pw && !userdb__byName(&userdb__users, pw->pw_name)) { |
659 | IF_TRACING(TRACE_DEBUG, userdb__dumpUser(pw); ) |
03f996bd |
660 | userdb__addToMap(&userdb__users, pw->pw_name, pw->pw_uid, pw); |
46cc26eb |
661 | } else |
662 | userdb_freeUser(pw); |
03f996bd |
663 | free(cv); |
664 | return (0); |
665 | } |
666 | |
667 | /* --- @userdb__foreachGroup@ --- * |
668 | * |
669 | * Arguments: @int st@ = YP protocol-level status code |
670 | * @char *k@ = address of the key for this record |
671 | * @int ksz@ = size of the key |
672 | * @char *v@ = address of the value for this record |
673 | * @int vsz@ = size of the value |
674 | * @char *data@ = pointer to some data passed to me |
675 | * |
676 | * Returns: Zero to be called again, nonzero to end the enumeration. |
677 | * |
678 | * Use: Handles an incoming user record. |
679 | */ |
680 | |
681 | static int userdb__foreachGroup(int st, char *k, int ksz, |
682 | char *v, int vsz, char *data) |
683 | { |
684 | char *cv; |
685 | struct group *gr; |
686 | |
687 | if (st != YP_TRUE) |
688 | return (-1); |
689 | cv = xmalloc(vsz + 1); |
690 | memcpy(cv, v, vsz); |
691 | cv[vsz] = 0; |
e893b83f |
692 | T( trace(TRACE_DEBUG, "debug: nis string: `%s'", cv); ) |
03f996bd |
693 | gr = userdb__buildGroup(cv); |
e893b83f |
694 | if (gr && !userdb__byName(&userdb__groups, gr->gr_name)) { |
695 | IF_TRACING(TRACE_DEBUG, userdb__dumpGroup(gr); ) |
03f996bd |
696 | userdb__addToMap(&userdb__groups, gr->gr_name, gr->gr_gid, gr); |
46cc26eb |
697 | } else |
698 | userdb_freeGroup(gr); |
03f996bd |
699 | free(cv); |
700 | return (0); |
701 | } |
702 | |
703 | /* --- @userdb_yp@ --- * |
704 | * |
705 | * Arguments: --- |
706 | * |
707 | * Returns: --- |
708 | * |
709 | * Use: Fetches the YP database of users. |
710 | */ |
711 | |
712 | void userdb_yp(void) |
713 | { |
03f996bd |
714 | /* --- Bind to a server --- */ |
715 | |
a340752b |
716 | ypstuff_bind(); |
717 | if (!yp_domain) |
03f996bd |
718 | return; |
719 | |
e893b83f |
720 | T( trace(TRACE_DEBUG, "debug: adding NIS users"); ) |
721 | |
03f996bd |
722 | /* --- Fetch the users map --- */ |
723 | |
724 | { |
725 | static struct ypall_callback ucb = { userdb__foreachUser, 0 }; |
a340752b |
726 | yp_all(yp_domain, "passwd.byuid", &ucb); |
03f996bd |
727 | } |
728 | |
729 | /* --- Fetch the groups map --- */ |
730 | |
731 | { |
732 | static struct ypall_callback gcb = { userdb__foreachGroup, 0 }; |
a340752b |
733 | yp_all(yp_domain, "group.bygid", &gcb); |
03f996bd |
734 | } |
03f996bd |
735 | } |
736 | |
737 | #else |
738 | |
739 | void userdb_yp(void) { ; } |
740 | |
741 | #endif |
742 | |
743 | /*----- Building the databases --------------------------------------------*/ |
744 | |
745 | /* --- @userdb_local@ --- * |
746 | * |
747 | * Arguments: --- |
748 | * |
749 | * Returns: --- |
750 | * |
751 | * Use: Reads the local list of users into the maps. |
752 | */ |
753 | |
754 | void userdb_local(void) |
755 | { |
e893b83f |
756 | T( trace(TRACE_DEBUG, "debug: adding local users"); ) |
03f996bd |
757 | |
758 | /* --- Fetch users first --- */ |
759 | |
760 | { |
761 | struct passwd *pw; |
762 | |
763 | setpwent(); |
764 | while ((pw = getpwent()) != 0) { |
e893b83f |
765 | IF_TRACING(TRACE_DEBUG, userdb__dumpUser(pw); ) |
03f996bd |
766 | if (!userdb__byName(&userdb__users, pw->pw_name)) |
767 | userdb__addToMap(&userdb__users, pw->pw_name, pw->pw_uid, |
768 | userdb_copyUser(pw)); |
769 | } |
770 | endpwent(); |
771 | } |
772 | |
773 | /* --- Then fetch groups --- */ |
774 | |
775 | { |
776 | struct group *gr; |
777 | |
778 | setgrent(); |
779 | while ((gr = getgrent()) != 0) { |
e893b83f |
780 | IF_TRACING(TRACE_DEBUG, userdb__dumpGroup(gr); ) |
03f996bd |
781 | if (!userdb__byName(&userdb__groups, gr->gr_name)) |
782 | userdb__addToMap(&userdb__groups, gr->gr_name, gr->gr_gid, |
783 | userdb_copyGroup(gr)); |
784 | } |
785 | endgrent(); |
786 | } |
787 | } |
788 | |
c4f2d992 |
789 | /* --- @userdb_init@ --- * |
790 | * |
791 | * Arguments: --- |
792 | * |
793 | * Returns: --- |
794 | * |
795 | * Use: Initialises the user database. |
796 | */ |
797 | |
798 | void userdb_init(void) |
799 | { |
800 | userdb__createMap(&userdb__users); |
801 | userdb__createMap(&userdb__groups); |
802 | } |
803 | |
46cc26eb |
804 | /* --- @userdb_end@ --- * |
c4f2d992 |
805 | * |
806 | * Arguments: --- |
807 | * |
808 | * Returns: --- |
809 | * |
46cc26eb |
810 | * Use: Closes down the user database. |
c4f2d992 |
811 | */ |
812 | |
46cc26eb |
813 | void userdb_end(void) |
c4f2d992 |
814 | { |
815 | userdb__clearMap(&userdb__users, userdb_freeUser); |
816 | userdb__clearMap(&userdb__groups, userdb_freeGroup); |
c4f2d992 |
817 | } |
818 | |
819 | /*----- Test rig ----------------------------------------------------------*/ |
820 | |
821 | #ifdef TEST_RIG |
822 | |
823 | void dumpit(const char *msg) |
824 | { |
e893b83f |
825 | trace(TRACE_DEBUG, "debug: %s", msg); |
c4f2d992 |
826 | |
827 | { |
828 | struct passwd *pw; |
829 | for (userdb_iterateUsers(); (pw = userdb_nextUser()) != 0; ) |
e893b83f |
830 | userdb__dumpUser(pw); |
c4f2d992 |
831 | } |
832 | |
833 | { |
834 | struct group *gr; |
835 | for (userdb_iterateGroups(); (gr = userdb_nextGroup()) != 0; ) |
e893b83f |
836 | userdb__dumpGroup(gr); |
c4f2d992 |
837 | } |
838 | } |
839 | |
840 | int main(void) |
841 | { |
e893b83f |
842 | ego("userdb-test"); |
8bdddfb7 |
843 | trace_on(stdout, TRACE_ALL); |
c4f2d992 |
844 | userdb_init(); |
e893b83f |
845 | userdb_local(); |
46cc26eb |
846 | userdb_yp(); |
a340752b |
847 | dumpit("spong"); |
848 | /* printf("loaded (%lu)\n", track_memused()); */ |
46cc26eb |
849 | getchar(); |
850 | for (;;) { |
851 | userdb_end(); |
a340752b |
852 | /* printf("cleared (%lu)\n", track_memused()); */ |
46cc26eb |
853 | /* track_memlist(); */ |
854 | userdb_init(); |
855 | userdb_local(); |
856 | userdb_yp(); |
a340752b |
857 | /* printf("reloaded (%lu)\n", track_memused()); */ |
46cc26eb |
858 | getchar(); |
859 | } |
c4f2d992 |
860 | return (0); |
861 | } |
862 | |
863 | #endif |
864 | |
865 | /*----- That's all, folks -------------------------------------------------*/ |