]> diplodocus.org Git - nmh/blob - uip/aliasbr.c
Formatting cleanup.
[nmh] / uip / aliasbr.c
1
2 /*
3 * aliasbr.c -- new aliasing mechanism
4 *
5 * This code is Copyright (c) 2002, by the authors of nmh. See the
6 * COPYRIGHT file in the root directory of the nmh distribution for
7 * complete copyright information.
8 */
9
10 #include <h/mh.h>
11 #include <h/aliasbr.h>
12 #include <h/utils.h>
13 #include <grp.h>
14 #include <pwd.h>
15
16 static int akvis;
17 static char *akerrst;
18
19 struct aka *akahead = NULL;
20 struct aka *akatail = NULL;
21
22 struct home *homehead = NULL;
23 struct home *hometail = NULL;
24
25 /*
26 * prototypes
27 */
28 int alias (char *);
29 int akvisible (void);
30 void init_pw (void);
31 char *akresult (struct aka *);
32 char *akvalue (char *);
33 char *akerror (int);
34
35 static char *akval (struct aka *, char *);
36 static int aleq (char *, char *);
37 static char *scanp (unsigned char *);
38 static char *getp (char *);
39 static char *seekp (char *, char *, char **);
40 static int addfile (struct aka *, char *);
41 static int addgroup (struct aka *, char *);
42 static int addmember (struct aka *, char *);
43 static int addall (struct aka *);
44 static char *getalias (char *);
45 static void add_aka (struct aka *, char *);
46 static struct aka *akalloc (char *);
47 static struct home *hmalloc (struct passwd *);
48 struct home *seek_home (char *);
49
50
51 /* Do mh alias substitution on 's' and return the results. */
52 char *
53 akvalue (char *s)
54 {
55 register char *v;
56
57 if (akahead == NULL)
58 alias (AliasFile);
59
60 akvis = -1;
61 v = akval (akahead, s);
62 if (akvis == -1)
63 akvis = 0;
64 return v;
65 }
66
67
68 int
69 akvisible (void)
70 {
71 return akvis;
72 }
73
74
75 char *
76 akresult (struct aka *ak)
77 {
78 register char *cp = NULL, *dp, *pp;
79 register struct adr *ad;
80
81 for (ad = ak->ak_addr; ad; ad = ad->ad_next) {
82 pp = ad->ad_local ? akval (ak->ak_next, ad->ad_text)
83 : getcpy (ad->ad_text);
84
85 if (cp) {
86 dp = cp;
87 cp = concat (cp, ",", pp, NULL);
88 free (dp);
89 free (pp);
90 }
91 else
92 cp = pp;
93 }
94
95 if (akvis == -1)
96 akvis = ak->ak_visible;
97 return cp;
98 }
99
100
101 static char *
102 akval (struct aka *ak, char *s)
103 {
104 if (!s)
105 return s; /* XXX */
106
107 for (; ak; ak = ak->ak_next)
108 if (aleq (s, ak->ak_name))
109 return akresult (ak);
110
111 return getcpy (s);
112 }
113
114
115 static int
116 aleq (char *string, char *aliasent)
117 {
118 register char c;
119
120 while ((c = *string++))
121 if (*aliasent == '*')
122 return 1;
123 else
124 if ((c | 040) != (*aliasent | 040))
125 return 0;
126 else
127 aliasent++;
128
129 return (*aliasent == 0 || *aliasent == '*');
130 }
131
132
133 int
134 alias (char *file)
135 {
136 int i;
137 register char *bp, *cp, *pp;
138 char lc, *ap;
139 register struct aka *ak = NULL;
140 register FILE *fp;
141
142 if (*file != '/'
143 && (strncmp (file, "./", 2) && strncmp (file, "../", 3)))
144 file = etcpath (file);
145 if ((fp = fopen (file, "r")) == NULL) {
146 akerrst = file;
147 return AK_NOFILE;
148 }
149
150 while (vfgets (fp, &ap) == OK) {
151 bp = ap;
152 switch (*(pp = scanp (bp))) {
153 case '<': /* recurse a level */
154 if (!*(cp = getp (pp + 1))) {
155 akerrst = "'<' without alias-file";
156 fclose (fp);
157 return AK_ERROR;
158 }
159 if ((i = alias (cp)) != AK_OK) {
160 fclose (fp);
161 return i;
162 }
163
164 case ':': /* comment */
165 case ';':
166 case '#':
167 case 0:
168 continue;
169 }
170
171 akerrst = bp;
172 if (!*(cp = seekp (pp, &lc, &ap))) {
173 fclose (fp);
174 return AK_ERROR;
175 }
176 if (!(ak = akalloc (cp))) {
177 fclose (fp);
178 return AK_LIMIT;
179 }
180 switch (lc) {
181 case ':':
182 ak->ak_visible = 0;
183 break;
184
185 case ';':
186 ak->ak_visible = 1;
187 break;
188
189 default:
190 fclose (fp);
191 return AK_ERROR;
192 }
193
194 switch (*(pp = scanp (ap))) {
195 case 0: /* EOL */
196 fclose (fp);
197 return AK_ERROR;
198
199 case '<': /* read values from file */
200 if (!*(cp = getp (pp + 1))) {
201 fclose (fp);
202 return AK_ERROR;
203 }
204 if (!addfile (ak, cp)) {
205 fclose (fp);
206 return AK_NOFILE;
207 }
208 break;
209
210 case '=': /* UNIX group */
211 if (!*(cp = getp (pp + 1))) {
212 fclose (fp);
213 return AK_ERROR;
214 }
215 if (!addgroup (ak, cp)) {
216 fclose (fp);
217 return AK_NOGROUP;
218 }
219 break;
220
221 case '+': /* UNIX group members */
222 if (!*(cp = getp (pp + 1))) {
223 fclose (fp);
224 return AK_ERROR;
225 }
226 if (!addmember (ak, cp)) {
227 fclose (fp);
228 return AK_NOGROUP;
229 }
230 break;
231
232 case '*': /* Everyone */
233 addall (ak);
234 break;
235
236 default: /* list */
237 while ((cp = getalias (pp)))
238 add_aka (ak, cp);
239 break;
240 }
241 }
242
243 fclose (fp);
244 return AK_OK;
245 }
246
247
248 char *
249 akerror (int i)
250 {
251 static char buffer[BUFSIZ];
252
253 switch (i) {
254 case AK_NOFILE:
255 snprintf (buffer, sizeof(buffer), "unable to read '%s'", akerrst);
256 break;
257
258 case AK_ERROR:
259 snprintf (buffer, sizeof(buffer), "error in line '%s'", akerrst);
260 break;
261
262 case AK_LIMIT:
263 snprintf (buffer, sizeof(buffer), "out of memory while on '%s'", akerrst);
264 break;
265
266 case AK_NOGROUP:
267 snprintf (buffer, sizeof(buffer), "no such group as '%s'", akerrst);
268 break;
269
270 default:
271 snprintf (buffer, sizeof(buffer), "unknown error (%d)", i);
272 break;
273 }
274
275 return buffer;
276 }
277
278
279 static char *
280 scanp (unsigned char *p)
281 {
282 while (isspace (*p))
283 p++;
284 return p;
285 }
286
287
288 static char *
289 getp (char *p)
290 {
291 register unsigned char *cp = scanp (p);
292
293 p = cp;
294 while (!isspace (*cp) && *cp)
295 cp++;
296 *cp = 0;
297
298 return p;
299 }
300
301
302 static char *
303 seekp (char *p, char *c, char **a)
304 {
305 register unsigned char *cp;
306
307 p = cp = scanp (p);
308 while (!isspace (*cp) && *cp && *cp != ':' && *cp != ';')
309 cp++;
310 *c = *cp;
311 *cp++ = 0;
312 *a = cp;
313
314 return p;
315 }
316
317
318 static int
319 addfile (struct aka *ak, char *file)
320 {
321 register char *cp;
322 char buffer[BUFSIZ];
323 register FILE *fp;
324
325 if (!(fp = fopen (etcpath (file), "r"))) {
326 akerrst = file;
327 return 0;
328 }
329
330 while (fgets (buffer, sizeof buffer, fp))
331 while ((cp = getalias (buffer)))
332 add_aka (ak, cp);
333
334 fclose (fp);
335 return 1;
336 }
337
338
339 static int
340 addgroup (struct aka *ak, char *grp)
341 {
342 register char *gp;
343 register struct group *gr = getgrnam (grp);
344 register struct home *hm = NULL;
345
346 if (!gr)
347 gr = getgrgid (atoi (grp));
348 if (!gr) {
349 akerrst = grp;
350 return 0;
351 }
352
353 while ((gp = *gr->gr_mem++))
354 {
355 struct passwd *pw;
356 for (hm = homehead; hm; hm = hm->h_next)
357 if (!strcmp (hm->h_name, gp)) {
358 add_aka (ak, hm->h_name);
359 break;
360 }
361 if ((pw = getpwnam(gp)))
362 {
363 hmalloc(pw);
364 add_aka (ak, gp);
365 }
366 }
367
368 return 1;
369 }
370
371
372 static int
373 addmember (struct aka *ak, char *grp)
374 {
375 gid_t gid;
376 register struct group *gr = getgrnam (grp);
377 register struct home *hm = NULL;
378
379 if (gr)
380 gid = gr->gr_gid;
381 else {
382 gid = atoi (grp);
383 gr = getgrgid (gid);
384 }
385 if (!gr) {
386 akerrst = grp;
387 return 0;
388 }
389
390 init_pw ();
391
392 for (hm = homehead; hm; hm = hm->h_next)
393 if (hm->h_gid == gid)
394 add_aka (ak, hm->h_name);
395
396 return 1;
397 }
398
399
400 static int
401 addall (struct aka *ak)
402 {
403 int noshell = NoShell == NULL || *NoShell == 0;
404 register struct home *hm;
405
406 init_pw ();
407
408 if (Everyone < 0)
409 Everyone = EVERYONE;
410
411 for (hm = homehead; hm; hm = hm->h_next)
412 if ((int) hm->h_uid > Everyone
413 && (noshell || strcmp (hm->h_shell, NoShell)))
414 add_aka (ak, hm->h_name);
415
416 return homehead != NULL;
417 }
418
419
420 static char *
421 getalias (char *addrs)
422 {
423 register unsigned char *pp, *qp;
424 static char *cp = NULL;
425
426 if (cp == NULL)
427 cp = addrs;
428 else
429 if (*cp == 0)
430 return (cp = NULL);
431
432 for (pp = cp; isspace (*pp); pp++)
433 continue;
434 if (*pp == 0)
435 return (cp = NULL);
436 for (qp = pp; *qp != 0 && *qp != ','; qp++)
437 continue;
438 if (*qp == ',')
439 *qp++ = 0;
440 for (cp = qp, qp--; qp > pp; qp--)
441 if (*qp != 0) {
442 if (isspace (*qp))
443 *qp = 0;
444 else
445 break;
446 }
447
448 return pp;
449 }
450
451
452 static void
453 add_aka (struct aka *ak, char *pp)
454 {
455 register struct adr *ad, *ld;
456
457 for (ad = ak->ak_addr, ld = NULL; ad; ld = ad, ad = ad->ad_next)
458 if (!strcmp (pp, ad->ad_text))
459 return;
460
461 ad = (struct adr *) mh_xmalloc (sizeof(*ad));
462 ad->ad_text = getcpy (pp);
463 ad->ad_local = strchr(pp, '@') == NULL && strchr(pp, '!') == NULL;
464 ad->ad_next = NULL;
465 if (ak->ak_addr)
466 ld->ad_next = ad;
467 else
468 ak->ak_addr = ad;
469 }
470
471
472 void
473 init_pw (void)
474 {
475 register struct passwd *pw;
476 static int init;
477
478 if (!init)
479 {
480 /* if the list has yet to be initialized */
481 /* zap the list, and rebuild from scratch */
482 homehead=NULL;
483 hometail=NULL;
484 init++;
485
486 setpwent ();
487
488 while ((pw = getpwent ()))
489 if (!hmalloc (pw))
490 break;
491
492 endpwent ();
493 }
494 }
495
496
497 static struct aka *
498 akalloc (char *id)
499 {
500 register struct aka *p;
501
502 p = (struct aka *) mh_xmalloc (sizeof(*p));
503
504 p->ak_name = getcpy (id);
505 p->ak_visible = 0;
506 p->ak_addr = NULL;
507 p->ak_next = NULL;
508 if (akatail != NULL)
509 akatail->ak_next = p;
510 if (akahead == NULL)
511 akahead = p;
512 akatail = p;
513
514 return p;
515 }
516
517
518 static struct home *
519 hmalloc (struct passwd *pw)
520 {
521 register struct home *p;
522
523 p = (struct home *) mh_xmalloc (sizeof(*p));
524
525 p->h_name = getcpy (pw->pw_name);
526 p->h_uid = pw->pw_uid;
527 p->h_gid = pw->pw_gid;
528 p->h_home = getcpy (pw->pw_dir);
529 p->h_shell = getcpy (pw->pw_shell);
530 p->h_ngrps = 0;
531 p->h_next = NULL;
532 if (hometail != NULL)
533 hometail->h_next = p;
534 if (homehead == NULL)
535 homehead = p;
536 hometail = p;
537
538 return p;
539 }
540
541
542 struct home *
543 seek_home (char *name)
544 {
545 register struct home *hp;
546 struct passwd *pw;
547 char lname[32];
548 unsigned char *c;
549 char *c1;
550
551 for (hp = homehead; hp; hp = hp->h_next)
552 if (!mh_strcasecmp (name, hp->h_name))
553 return hp;
554
555 /*
556 * The only place where there might be problems.
557 * This assumes that ALL usernames are kept in lowercase.
558 */
559 for (c = name, c1 = lname;
560 *c && (c1 - lname < (int) sizeof(lname) - 1);
561 c++, c1++) {
562 if (isalpha(*c) && isupper(*c))
563 *c1 = tolower (*c);
564 else
565 *c1 = *c;
566 }
567 *c1 = '\0';
568 if ((pw = getpwnam(lname)))
569 return(hmalloc(pw));
570
571 return NULL;
572 }