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