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