]> diplodocus.org Git - nmh/blob - uip/aliasbr.c
Removed temporary probes added in commit
[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/addrsbr.h>
13 #include <h/utils.h>
14 #include <grp.h>
15 #include <pwd.h>
16
17 static int akvis;
18 static char *akerrst;
19
20 struct aka *akahead = NULL;
21 struct aka *akatail = NULL;
22
23 struct home *homehead = NULL;
24 struct home *hometail = NULL;
25
26 /*
27 * prototypes
28 */
29 int alias (char *);
30 int akvisible (void);
31 void init_pw (void);
32 char *akresult (struct aka *);
33 char *akvalue (char *);
34 char *akerror (int);
35
36 static char *akval (struct aka *, char *);
37 static int aleq (char *, char *);
38 static char *scanp (char *);
39 static char *getp (char *);
40 static char *seekp (char *, char *, char **);
41 static int addfile (struct aka *, char *);
42 static int addgroup (struct aka *, char *);
43 static int addmember (struct aka *, char *);
44 static int addall (struct aka *);
45 static char *getalias (char *);
46 static void add_aka (struct aka *, char *);
47 static struct aka *akalloc (char *);
48 static struct home *hmalloc (struct passwd *);
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 /* It'd be tempting to check for a trailing semicolon and remove
108 it. But that would break the EXMH alias parser on what would
109 then be valid expressions:
110 http://lists.gnu.org/archive/html/nmh-workers/2012-10/msg00039.html
111 */
112
113 for (; ak; ak = ak->ak_next) {
114 if (aleq (s, ak->ak_name)) {
115 return akresult (ak);
116 } else if (strchr (s, ':')) {
117 /* The first address in a blind list will contain the
118 alias name, so try to match, but just with just the
119 address (not including the list name). If there's a
120 match, then replace the alias part with its
121 expansion. */
122
123 char *name = getname (s);
124 char *cp = NULL;
125
126 if (name) {
127 /* s is of the form "Blind list: address". If address
128 is an alias, expand it. */
129 struct mailname *mp = getm (name, NULL, 0, NULL, 0);
130
131 if (mp && mp->m_ingrp) {
132 char *gname = add (mp->m_gname, NULL);
133
134 if (gname && aleq (name, ak->ak_name)) {
135 /* Will leak cp. */
136 cp = concat (gname, akresult (ak), NULL);
137 free (gname);
138 }
139 }
140
141 mnfree (mp);
142 }
143
144 /* Need to flush getname after use. */
145 while (getname ("")) continue;
146
147 if (cp) {
148 return cp;
149 }
150 }
151 }
152
153 return getcpy (s);
154 }
155
156
157 static int
158 aleq (char *string, char *aliasent)
159 {
160 register char c;
161
162 while ((c = *string++))
163 if (*aliasent == '*')
164 return 1;
165 else
166 if ((c | 040) != (*aliasent | 040))
167 return 0;
168 else
169 aliasent++;
170
171 return (*aliasent == 0 || *aliasent == '*');
172 }
173
174
175 int
176 alias (char *file)
177 {
178 int i;
179 register char *bp, *cp, *pp;
180 char lc, *ap;
181 register struct aka *ak = NULL;
182 register FILE *fp;
183
184 if (*file != '/'
185 && (strncmp (file, "./", 2) && strncmp (file, "../", 3)))
186 file = etcpath (file);
187 if ((fp = fopen (file, "r")) == NULL) {
188 akerrst = file;
189 return AK_NOFILE;
190 }
191
192 while (vfgets (fp, &ap) == OK) {
193 bp = ap;
194 switch (*(pp = scanp (bp))) {
195 case '<': /* recurse a level */
196 if (!*(cp = getp (pp + 1))) {
197 akerrst = "'<' without alias-file";
198 fclose (fp);
199 return AK_ERROR;
200 }
201 if ((i = alias (cp)) != AK_OK) {
202 fclose (fp);
203 return i;
204 }
205
206 case ':': /* comment */
207 case ';':
208 case '#':
209 case 0:
210 continue;
211 }
212
213 akerrst = bp;
214 if (!*(cp = seekp (pp, &lc, &ap))) {
215 fclose (fp);
216 return AK_ERROR;
217 }
218 if (!(ak = akalloc (cp))) {
219 fclose (fp);
220 return AK_LIMIT;
221 }
222 switch (lc) {
223 case ':':
224 ak->ak_visible = 0;
225 break;
226
227 case ';':
228 ak->ak_visible = 1;
229 break;
230
231 default:
232 fclose (fp);
233 return AK_ERROR;
234 }
235
236 switch (*(pp = scanp (ap))) {
237 case 0: /* EOL */
238 fclose (fp);
239 return AK_ERROR;
240
241 case '<': /* read values from file */
242 if (!*(cp = getp (pp + 1))) {
243 fclose (fp);
244 return AK_ERROR;
245 }
246 if (!addfile (ak, cp)) {
247 fclose (fp);
248 return AK_NOFILE;
249 }
250 break;
251
252 case '=': /* UNIX group */
253 if (!*(cp = getp (pp + 1))) {
254 fclose (fp);
255 return AK_ERROR;
256 }
257 if (!addgroup (ak, cp)) {
258 fclose (fp);
259 return AK_NOGROUP;
260 }
261 break;
262
263 case '+': /* UNIX group members */
264 if (!*(cp = getp (pp + 1))) {
265 fclose (fp);
266 return AK_ERROR;
267 }
268 if (!addmember (ak, cp)) {
269 fclose (fp);
270 return AK_NOGROUP;
271 }
272 break;
273
274 case '*': /* Everyone */
275 addall (ak);
276 break;
277
278 default: /* list */
279 while ((cp = getalias (pp)))
280 add_aka (ak, cp);
281 break;
282 }
283 }
284
285 fclose (fp);
286 return AK_OK;
287 }
288
289
290 char *
291 akerror (int i)
292 {
293 static char buffer[BUFSIZ];
294
295 switch (i) {
296 case AK_NOFILE:
297 snprintf (buffer, sizeof(buffer), "unable to read '%s'", akerrst);
298 break;
299
300 case AK_ERROR:
301 snprintf (buffer, sizeof(buffer), "error in line '%s'", akerrst);
302 break;
303
304 case AK_LIMIT:
305 snprintf (buffer, sizeof(buffer), "out of memory while on '%s'", akerrst);
306 break;
307
308 case AK_NOGROUP:
309 snprintf (buffer, sizeof(buffer), "no such group as '%s'", akerrst);
310 break;
311
312 default:
313 snprintf (buffer, sizeof(buffer), "unknown error (%d)", i);
314 break;
315 }
316
317 return buffer;
318 }
319
320
321 static char *
322 scanp (char *p)
323 {
324 while (isspace ((unsigned char) *p))
325 p++;
326 return p;
327 }
328
329
330 static char *
331 getp (char *p)
332 {
333 char *cp = scanp (p);
334
335 p = cp;
336 while (!isspace ((unsigned char) *cp) && *cp)
337 cp++;
338 *cp = 0;
339
340 return p;
341 }
342
343
344 static char *
345 seekp (char *p, char *c, char **a)
346 {
347 char *cp;
348
349 p = cp = scanp (p);
350 while (!isspace ((unsigned char) *cp) && *cp && *cp != ':' && *cp != ';')
351 cp++;
352 *c = *cp;
353 *cp++ = 0;
354 *a = cp;
355
356 return p;
357 }
358
359
360 static int
361 addfile (struct aka *ak, char *file)
362 {
363 register char *cp;
364 char buffer[BUFSIZ];
365 register FILE *fp;
366
367 if (!(fp = fopen (etcpath (file), "r"))) {
368 akerrst = file;
369 return 0;
370 }
371
372 while (fgets (buffer, sizeof buffer, fp))
373 while ((cp = getalias (buffer)))
374 add_aka (ak, cp);
375
376 fclose (fp);
377 return 1;
378 }
379
380
381 static int
382 addgroup (struct aka *ak, char *grp)
383 {
384 register char *gp;
385 register struct group *gr = getgrnam (grp);
386 register struct home *hm = NULL;
387
388 if (!gr)
389 gr = getgrgid (atoi (grp));
390 if (!gr) {
391 akerrst = grp;
392 return 0;
393 }
394
395 while ((gp = *gr->gr_mem++))
396 {
397 struct passwd *pw;
398 for (hm = homehead; hm; hm = hm->h_next)
399 if (!strcmp (hm->h_name, gp)) {
400 add_aka (ak, hm->h_name);
401 break;
402 }
403 if ((pw = getpwnam(gp)))
404 {
405 hmalloc(pw);
406 add_aka (ak, gp);
407 }
408 }
409
410 return 1;
411 }
412
413
414 static int
415 addmember (struct aka *ak, char *grp)
416 {
417 gid_t gid;
418 register struct group *gr = getgrnam (grp);
419 register struct home *hm = NULL;
420
421 if (gr)
422 gid = gr->gr_gid;
423 else {
424 gid = atoi (grp);
425 gr = getgrgid (gid);
426 }
427 if (!gr) {
428 akerrst = grp;
429 return 0;
430 }
431
432 init_pw ();
433
434 for (hm = homehead; hm; hm = hm->h_next)
435 if (hm->h_gid == gid)
436 add_aka (ak, hm->h_name);
437
438 return 1;
439 }
440
441
442 static int
443 addall (struct aka *ak)
444 {
445 int noshell = NoShell == NULL || *NoShell == 0;
446 register struct home *hm;
447
448 init_pw ();
449
450 if (Everyone < 0)
451 Everyone = EVERYONE;
452
453 for (hm = homehead; hm; hm = hm->h_next)
454 if ((int) hm->h_uid > Everyone
455 && (noshell || strcmp (hm->h_shell, NoShell)))
456 add_aka (ak, hm->h_name);
457
458 return homehead != NULL;
459 }
460
461
462 static char *
463 getalias (char *addrs)
464 {
465 char *pp, *qp;
466 static char *cp = NULL;
467
468 if (cp == NULL)
469 cp = addrs;
470 else
471 if (*cp == 0)
472 return (cp = NULL);
473
474 /* Remove leading any space from the address. */
475 for (pp = cp; isspace ((unsigned char) *pp); pp++)
476 continue;
477 if (*pp == 0)
478 return (cp = NULL);
479 /* Find the end of the address. */
480 for (qp = pp; *qp != 0 && *qp != ','; qp++)
481 continue;
482 /* Set cp to point to the remainder of the addresses. */
483 if (*qp == ',')
484 *qp++ = 0;
485 for (cp = qp, qp--; qp > pp; qp--)
486 if (*qp != 0) {
487 if (isspace ((unsigned char) *qp))
488 *qp = 0;
489 else
490 break;
491 }
492
493 return pp;
494 }
495
496
497 static void
498 add_aka (struct aka *ak, char *pp)
499 {
500 register struct adr *ad, *ld;
501
502 for (ad = ak->ak_addr, ld = NULL; ad; ld = ad, ad = ad->ad_next)
503 if (!strcmp (pp, ad->ad_text))
504 return;
505
506 ad = (struct adr *) mh_xmalloc (sizeof(*ad));
507 ad->ad_text = getcpy (pp);
508 ad->ad_local = strchr(pp, '@') == NULL && strchr(pp, '!') == NULL;
509 ad->ad_next = NULL;
510 if (ak->ak_addr)
511 ld->ad_next = ad;
512 else
513 ak->ak_addr = ad;
514 }
515
516
517 void
518 init_pw (void)
519 {
520 register struct passwd *pw;
521 static int init;
522
523 if (!init)
524 {
525 /* if the list has yet to be initialized */
526 /* zap the list, and rebuild from scratch */
527 homehead=NULL;
528 hometail=NULL;
529 init++;
530
531 setpwent ();
532
533 while ((pw = getpwent ()))
534 if (!hmalloc (pw))
535 break;
536
537 endpwent ();
538 }
539 }
540
541
542 static struct aka *
543 akalloc (char *id)
544 {
545 register struct aka *p;
546
547 p = (struct aka *) mh_xmalloc (sizeof(*p));
548
549 p->ak_name = getcpy (id);
550 p->ak_visible = 0;
551 p->ak_addr = NULL;
552 p->ak_next = NULL;
553 if (akatail != NULL)
554 akatail->ak_next = p;
555 if (akahead == NULL)
556 akahead = p;
557 akatail = p;
558
559 return p;
560 }
561
562
563 static struct home *
564 hmalloc (struct passwd *pw)
565 {
566 register struct home *p;
567
568 p = (struct home *) mh_xmalloc (sizeof(*p));
569
570 p->h_name = getcpy (pw->pw_name);
571 p->h_uid = pw->pw_uid;
572 p->h_gid = pw->pw_gid;
573 p->h_home = getcpy (pw->pw_dir);
574 p->h_shell = getcpy (pw->pw_shell);
575 p->h_ngrps = 0;
576 p->h_next = NULL;
577 if (hometail != NULL)
578 hometail->h_next = p;
579 if (homehead == NULL)
580 homehead = p;
581 hometail = p;
582
583 return p;
584 }