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