]> diplodocus.org Git - nmh/blob - uip/aliasbr.c
Sigh. I put the documentation about the -tls switch in the long description,
[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 #ifndef DBMPWD
354 if (homehead == NULL)
355 init_pw ();
356 #endif /* DBMPWD */
357
358 while ((gp = *gr->gr_mem++))
359 #ifdef DBMPWD
360 {
361 struct passwd *pw;
362 #endif /* DBMPWD */
363 for (hm = homehead; hm; hm = hm->h_next)
364 if (!strcmp (hm->h_name, gp)) {
365 add_aka (ak, hm->h_name);
366 break;
367 }
368 #ifdef DBMPWD
369 if ((pw = getpwnam(gp)))
370 {
371 hmalloc(pw);
372 add_aka (ak, gp);
373 }
374 }
375 #endif /* DBMPWD */
376
377 return 1;
378 }
379
380
381 static int
382 addmember (struct aka *ak, char *grp)
383 {
384 gid_t gid;
385 register struct group *gr = getgrnam (grp);
386 register struct home *hm = NULL;
387
388 if (gr)
389 gid = gr->gr_gid;
390 else {
391 gid = atoi (grp);
392 gr = getgrgid (gid);
393 }
394 if (!gr) {
395 akerrst = grp;
396 return 0;
397 }
398
399 #ifndef DBMPWD
400 if (homehead == NULL)
401 #endif /* DBMPWD */
402 init_pw ();
403
404 for (hm = homehead; hm; hm = hm->h_next)
405 if (hm->h_gid == gid)
406 add_aka (ak, hm->h_name);
407
408 return 1;
409 }
410
411
412 static int
413 addall (struct aka *ak)
414 {
415 int noshell = NoShell == NULL || *NoShell == 0;
416 register struct home *hm;
417
418 #ifndef DBMPWD
419 if (homehead == NULL)
420 #endif /* DBMPWD */
421 init_pw ();
422 if (Everyone < 0)
423 Everyone = EVERYONE;
424
425 for (hm = homehead; hm; hm = hm->h_next)
426 if (hm->h_uid > Everyone
427 && (noshell || strcmp (hm->h_shell, NoShell)))
428 add_aka (ak, hm->h_name);
429
430 return homehead != NULL;
431 }
432
433
434 static char *
435 getalias (char *addrs)
436 {
437 register unsigned char *pp, *qp;
438 static char *cp = NULL;
439
440 if (cp == NULL)
441 cp = addrs;
442 else
443 if (*cp == 0)
444 return (cp = NULL);
445
446 for (pp = cp; isspace (*pp); pp++)
447 continue;
448 if (*pp == 0)
449 return (cp = NULL);
450 for (qp = pp; *qp != 0 && *qp != ','; qp++)
451 continue;
452 if (*qp == ',')
453 *qp++ = 0;
454 for (cp = qp, qp--; qp > pp; qp--)
455 if (*qp != 0) {
456 if (isspace (*qp))
457 *qp = 0;
458 else
459 break;
460 }
461
462 return pp;
463 }
464
465
466 static void
467 add_aka (struct aka *ak, char *pp)
468 {
469 register struct adr *ad, *ld;
470
471 for (ad = ak->ak_addr, ld = NULL; ad; ld = ad, ad = ad->ad_next)
472 if (!strcmp (pp, ad->ad_text))
473 return;
474
475 ad = (struct adr *) mh_xmalloc (sizeof(*ad));
476 ad->ad_text = getcpy (pp);
477 ad->ad_local = strchr(pp, '@') == NULL && strchr(pp, '!') == NULL;
478 ad->ad_next = NULL;
479 if (ak->ak_addr)
480 ld->ad_next = ad;
481 else
482 ak->ak_addr = ad;
483 }
484
485
486 void
487 init_pw (void)
488 {
489 register struct passwd *pw;
490 #ifdef DBMPWD
491 static int init;
492
493 if (!init)
494 {
495 /* if the list has yet to be initialized */
496 /* zap the list, and rebuild from scratch */
497 homehead=NULL;
498 hometail=NULL;
499 init++;
500 #endif /* DBMPWD */
501
502 setpwent ();
503
504 while ((pw = getpwent ()))
505 if (!hmalloc (pw))
506 break;
507
508 endpwent ();
509 #ifdef DBMPWD
510 }
511 #endif /* DBMPWD */
512 }
513
514
515 static struct aka *
516 akalloc (char *id)
517 {
518 register struct aka *p;
519
520 p = (struct aka *) mh_xmalloc (sizeof(*p));
521
522 p->ak_name = getcpy (id);
523 p->ak_visible = 0;
524 p->ak_addr = NULL;
525 p->ak_next = NULL;
526 if (akatail != NULL)
527 akatail->ak_next = p;
528 if (akahead == NULL)
529 akahead = p;
530 akatail = p;
531
532 return p;
533 }
534
535
536 static struct home *
537 hmalloc (struct passwd *pw)
538 {
539 register struct home *p;
540
541 p = (struct home *) mh_xmalloc (sizeof(*p));
542
543 p->h_name = getcpy (pw->pw_name);
544 p->h_uid = pw->pw_uid;
545 p->h_gid = pw->pw_gid;
546 p->h_home = getcpy (pw->pw_dir);
547 p->h_shell = getcpy (pw->pw_shell);
548 p->h_ngrps = 0;
549 p->h_next = NULL;
550 if (hometail != NULL)
551 hometail->h_next = p;
552 if (homehead == NULL)
553 homehead = p;
554 hometail = p;
555
556 return p;
557 }
558
559
560 struct home *
561 seek_home (char *name)
562 {
563 register struct home *hp;
564 #ifdef DBMPWD
565 struct passwd *pw;
566 char lname[32];
567 unsigned char *c;
568 char *c1;
569 #else /* DBMPWD */
570
571 if (homehead == NULL)
572 init_pw ();
573 #endif /* DBMPWD */
574
575 for (hp = homehead; hp; hp = hp->h_next)
576 if (!mh_strcasecmp (name, hp->h_name))
577 return hp;
578
579 #ifdef DBMPWD
580 /*
581 * The only place where there might be problems.
582 * This assumes that ALL usernames are kept in lowercase.
583 */
584 for (c = name, c1 = lname; *c && (c1 - lname < sizeof(lname) - 1); c++, c1++) {
585 if (isalpha(*c) && isupper(*c))
586 *c1 = tolower (*c);
587 else
588 *c1 = *c;
589 }
590 *c1 = '\0';
591 if ((pw = getpwnam(lname)))
592 return(hmalloc(pw));
593 #endif /* DBMPWD */
594
595 return NULL;
596 }