]> diplodocus.org Git - nmh/blob - uip/aliasbr.c
Remove unused NCWD and NPWD #defines.
[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 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
49
50 /* Do mh alias substitution on 's' and return the results. */
51 char *
52 akvalue (char *s)
53 {
54 char *v;
55
56 if (akahead == NULL)
57 alias (AliasFile);
58
59 akvis = -1;
60 v = akval (akahead, s);
61 if (akvis == -1)
62 akvis = 0;
63 return v;
64 }
65
66
67 int
68 akvisible (void)
69 {
70 return akvis;
71 }
72
73
74 char *
75 akresult (struct aka *ak)
76 {
77 char *cp = NULL, *dp, *pp;
78 struct adr *ad;
79
80 for (ad = ak->ak_addr; ad; ad = ad->ad_next) {
81 pp = ad->ad_local ? akval (ak->ak_next, ad->ad_text)
82 : getcpy (ad->ad_text);
83
84 if (cp) {
85 dp = cp;
86 cp = concat (cp, ",", pp, NULL);
87 free (dp);
88 free (pp);
89 }
90 else
91 cp = pp;
92 }
93
94 if (akvis == -1)
95 akvis = ak->ak_visible;
96 return cp;
97 }
98
99
100 static char *
101 akval (struct aka *ak, char *s)
102 {
103 if (!s)
104 return s; /* XXX */
105
106 /* It'd be tempting to check for a trailing semicolon and remove
107 it. But that would break the EXMH alias parser on what would
108 then be valid expressions:
109 http://lists.gnu.org/archive/html/nmh-workers/2012-10/msg00039.html
110 */
111
112 for (; ak; ak = ak->ak_next) {
113 if (aleq (s, ak->ak_name)) {
114 return akresult (ak);
115 }
116
117 if (strchr (s, ':')) {
118 /* The first address in a blind list will contain the
119 alias name, so try to match, but just with just the
120 address (not including the list name). If there's a
121 match, then replace the alias part with its
122 expansion. */
123
124 char *name = getname (s);
125 char *cp = NULL;
126
127 if (name) {
128 /* s is of the form "Blind list: address". If address
129 is an alias, expand it. */
130 struct mailname *mp = getm (name, NULL, 0, NULL, 0);
131
132 if (mp && mp->m_ingrp) {
133 char *gname = add (mp->m_gname, NULL);
134
135 if (gname && aleq (name, ak->ak_name)) {
136 /* Will leak cp. */
137 cp = concat (gname, akresult (ak), NULL);
138 free (gname);
139 }
140 }
141
142 mnfree (mp);
143 }
144
145 /* Need to flush getname after use. */
146 while (getname ("")) continue;
147
148 if (cp) {
149 return cp;
150 }
151 }
152 }
153
154 return mh_xstrdup(s);
155 }
156
157
158 static int
159 aleq (char *string, char *aliasent)
160 {
161 char c;
162
163 while ((c = *string++)) {
164 if (*aliasent == '*')
165 return 1;
166 if ((c | 040) != (*aliasent | 040))
167 return 0;
168 aliasent++;
169 }
170
171 return (*aliasent == 0 || *aliasent == '*');
172 }
173
174
175 int
176 alias (char *file)
177 {
178 int i;
179 char *bp, *cp, *pp;
180 char lc, *ap;
181 struct aka *ak = NULL;
182 FILE *fp;
183
184 if (*file != '/'
185 && !HasPrefix(file, "./") && !HasPrefix(file, "../"))
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 default: /* list */
275 while ((cp = getalias (pp)))
276 add_aka (ak, cp);
277 break;
278 }
279 }
280
281 fclose (fp);
282 return AK_OK;
283 }
284
285
286 char *
287 akerror (int i)
288 {
289 static char buffer[BUFSIZ];
290
291 switch (i) {
292 case AK_NOFILE:
293 snprintf (buffer, sizeof(buffer), "unable to read '%s'", akerrst);
294 break;
295
296 case AK_ERROR:
297 snprintf (buffer, sizeof(buffer), "error in line '%s'", akerrst);
298 break;
299
300 case AK_LIMIT:
301 snprintf (buffer, sizeof(buffer), "out of memory while on '%s'", akerrst);
302 break;
303
304 case AK_NOGROUP:
305 snprintf (buffer, sizeof(buffer), "no such group as '%s'", akerrst);
306 break;
307
308 default:
309 snprintf (buffer, sizeof(buffer), "unknown error (%d)", i);
310 break;
311 }
312
313 return buffer;
314 }
315
316
317 static char *
318 scanp (char *p)
319 {
320 while (isspace ((unsigned char) *p))
321 p++;
322 return p;
323 }
324
325
326 static char *
327 getp (char *p)
328 {
329 char *cp = scanp (p);
330
331 p = cp;
332 while (!isspace ((unsigned char) *cp) && *cp)
333 cp++;
334 *cp = 0;
335
336 return p;
337 }
338
339
340 static char *
341 seekp (char *p, char *c, char **a)
342 {
343 char *cp;
344
345 p = cp = scanp (p);
346 while (!isspace ((unsigned char) *cp) && *cp && *cp != ':' && *cp != ';')
347 cp++;
348 *c = *cp;
349 *cp++ = 0;
350 *a = cp;
351
352 return p;
353 }
354
355
356 static int
357 addfile (struct aka *ak, char *file)
358 {
359 char *cp;
360 char buffer[BUFSIZ];
361 FILE *fp;
362
363 if (!(fp = fopen (etcpath (file), "r"))) {
364 akerrst = file;
365 return 0;
366 }
367
368 while (fgets (buffer, sizeof buffer, fp))
369 while ((cp = getalias (buffer)))
370 add_aka (ak, cp);
371
372 fclose (fp);
373 return 1;
374 }
375
376
377 static int
378 addgroup (struct aka *ak, char *grp)
379 {
380 char *gp;
381 struct group *gr = getgrnam (grp);
382 struct home *hm = NULL;
383
384 if (!gr)
385 gr = getgrgid (atoi (grp));
386 if (!gr) {
387 akerrst = grp;
388 return 0;
389 }
390
391 while ((gp = *gr->gr_mem++))
392 {
393 struct passwd *pw;
394 for (hm = homehead; hm; hm = hm->h_next)
395 if (!strcmp (hm->h_name, gp)) {
396 add_aka (ak, hm->h_name);
397 break;
398 }
399 if ((pw = getpwnam(gp)))
400 {
401 hmalloc(pw);
402 add_aka (ak, gp);
403 }
404 }
405
406 return 1;
407 }
408
409
410 static int
411 addmember (struct aka *ak, char *grp)
412 {
413 gid_t gid;
414 struct group *gr = getgrnam (grp);
415 struct home *hm = NULL;
416
417 if (gr)
418 gid = gr->gr_gid;
419 else {
420 gid = atoi (grp);
421 gr = getgrgid (gid);
422 }
423 if (!gr) {
424 akerrst = grp;
425 return 0;
426 }
427
428 init_pw ();
429
430 for (hm = homehead; hm; hm = hm->h_next)
431 if (hm->h_gid == gid)
432 add_aka (ak, hm->h_name);
433
434 return 1;
435 }
436
437
438 static char *
439 getalias (char *addrs)
440 {
441 char *pp, *qp;
442 static char *cp = NULL;
443
444 if (cp == NULL)
445 cp = addrs;
446 else
447 if (*cp == 0)
448 return (cp = NULL);
449
450 /* Remove leading any space from the address. */
451 for (pp = cp; isspace ((unsigned char) *pp); pp++)
452 continue;
453 if (*pp == 0)
454 return (cp = NULL);
455 /* Find the end of the address. */
456 for (qp = pp; *qp != 0 && *qp != ','; qp++)
457 continue;
458 /* Set cp to point to the remainder of the addresses. */
459 if (*qp == ',')
460 *qp++ = 0;
461 for (cp = qp, qp--; qp > pp; qp--)
462 if (*qp != 0) {
463 if (isspace ((unsigned char) *qp))
464 *qp = 0;
465 else
466 break;
467 }
468
469 return pp;
470 }
471
472
473 static void
474 add_aka (struct aka *ak, char *pp)
475 {
476 struct adr *ad, *ld;
477
478 for (ad = ak->ak_addr, ld = NULL; ad; ld = ad, ad = ad->ad_next)
479 if (!strcmp (pp, ad->ad_text))
480 return;
481
482 NEW(ad);
483 ad->ad_text = mh_xstrdup(pp);
484 ad->ad_local = strchr(pp, '@') == NULL && strchr(pp, '!') == NULL;
485 ad->ad_next = NULL;
486 if (ak->ak_addr)
487 ld->ad_next = ad;
488 else
489 ak->ak_addr = ad;
490 }
491
492
493 void
494 init_pw (void)
495 {
496 struct passwd *pw;
497 static int init;
498
499 if (!init)
500 {
501 /* if the list has yet to be initialized */
502 /* zap the list, and rebuild from scratch */
503 homehead=NULL;
504 hometail=NULL;
505 init++;
506
507 setpwent ();
508
509 while ((pw = getpwent ()))
510 if (!hmalloc (pw))
511 break;
512
513 endpwent ();
514 }
515 }
516
517
518 static struct aka *
519 akalloc (char *id)
520 {
521 struct aka *p;
522
523 NEW(p);
524 p->ak_name = getcpy (id);
525 p->ak_visible = 0;
526 p->ak_addr = NULL;
527 p->ak_next = NULL;
528 if (akatail != NULL)
529 akatail->ak_next = p;
530 if (akahead == NULL)
531 akahead = p;
532 akatail = p;
533
534 return p;
535 }
536
537
538 static struct home *
539 hmalloc (struct passwd *pw)
540 {
541 struct home *p;
542
543 NEW(p);
544 p->h_name = getcpy (pw->pw_name);
545 p->h_uid = pw->pw_uid;
546 p->h_gid = pw->pw_gid;
547 p->h_home = getcpy (pw->pw_dir);
548 p->h_shell = getcpy (pw->pw_shell);
549 p->h_ngrps = 0;
550 p->h_next = NULL;
551 if (hometail != NULL)
552 hometail->h_next = p;
553 if (homehead == NULL)
554 homehead = p;
555 hometail = p;
556
557 return p;
558 }