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