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