Rearranged whitespace (and comments) in all the code!
[mmh] / uip / aliasbr.c
1 /*
2  * aliasbr.c -- new aliasing mechanism
3  *
4  * This code is Copyright (c) 2002, by the authors of nmh.  See the
5  * COPYRIGHT file in the root directory of the nmh distribution for
6  * complete copyright information.
7  */
8
9 #include <h/mh.h>
10 #include <h/aliasbr.h>
11 #include <h/utils.h>
12 #include <grp.h>
13 #include <pwd.h>
14
15 static int akvis;
16 static char *akerrst;
17
18 struct aka *akahead = NULL;
19 struct aka *akatail = NULL;
20
21 struct home *homehead = NULL;
22 struct home *hometail = NULL;
23
24 /*
25  * prototypes
26  */
27 int alias (char *);
28 int akvisible (void);
29 void init_pw (void);
30 char *akresult (struct aka *);
31 char *akvalue (char *);
32 char *akerror (int);
33
34 static  char *akval (struct aka *, char *);
35 static int aleq (char *, char *);
36 static char *scanp (unsigned char *);
37 static char *getp (char *);
38 static char *seekp (char *, char *, char **);
39 static int addfile (struct aka *, char *);
40 static int addgroup (struct aka *, char *);
41 static int addmember (struct aka *, char *);
42 static int addall (struct aka *);
43 static char *getalias (char *);
44 static void add_aka (struct aka *, char *);
45 static struct aka *akalloc (char *);
46 static struct home *hmalloc (struct passwd *);
47 struct home *seek_home (char *);
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                 } 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 (unsigned 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 unsigned 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 unsigned 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 unsigned 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
460         return pp;
461 }
462
463
464 static void
465 add_aka (struct aka *ak, char *pp)
466 {
467         register struct adr *ad, *ld;
468
469         for (ad = ak->ak_addr, ld = NULL; ad; ld = ad, ad = ad->ad_next)
470                 if (!strcmp (pp, ad->ad_text))
471                         return;
472
473         ad = (struct adr *) mh_xmalloc (sizeof(*ad));
474         ad->ad_text = getcpy (pp);
475         ad->ad_local = strchr(pp, '@') == NULL && strchr(pp, '!') == NULL;
476         ad->ad_next = NULL;
477         if (ak->ak_addr)
478                 ld->ad_next = ad;
479         else
480                 ak->ak_addr = ad;
481 }
482
483
484 void
485 init_pw (void)
486 {
487         register struct passwd  *pw;
488 #ifdef DBMPWD
489         static int init;
490
491         if (!init)
492         {
493                   /* if the list has yet to be initialized */
494                         /* zap the list, and rebuild from scratch */
495                         homehead=NULL;
496                         hometail=NULL;
497                         init++;
498 #endif /* DBMPWD */
499
500         setpwent ();
501
502         while ((pw = getpwent ()))
503                 if (!hmalloc (pw))
504                         break;
505
506         endpwent ();
507 #ifdef DBMPWD
508         }
509 #endif /* DBMPWD */
510 }
511
512
513 static struct aka *
514 akalloc (char *id)
515 {
516         register struct aka *p;
517
518         p = (struct aka *) mh_xmalloc (sizeof(*p));
519
520         p->ak_name = getcpy (id);
521         p->ak_visible = 0;
522         p->ak_addr = NULL;
523         p->ak_next = NULL;
524         if (akatail != NULL)
525                 akatail->ak_next = p;
526         if (akahead == NULL)
527                 akahead = p;
528         akatail = p;
529
530         return p;
531 }
532
533
534 static struct home *
535 hmalloc (struct passwd *pw)
536 {
537         register struct home *p;
538
539         p = (struct home *) mh_xmalloc (sizeof(*p));
540
541         p->h_name = getcpy (pw->pw_name);
542         p->h_uid = pw->pw_uid;
543         p->h_gid = pw->pw_gid;
544         p->h_home = getcpy (pw->pw_dir);
545         p->h_shell = getcpy (pw->pw_shell);
546         p->h_ngrps = 0;
547         p->h_next = NULL;
548         if (hometail != NULL)
549                 hometail->h_next = p;
550         if (homehead == NULL)
551                 homehead = p;
552         hometail = p;
553
554         return p;
555 }
556
557
558 struct home *
559 seek_home (char *name)
560 {
561         register struct home *hp;
562 #ifdef DBMPWD
563         struct passwd *pw;
564         char lname[32];
565         unsigned char *c;
566         char *c1;
567 #else  /* DBMPWD */
568
569         if (homehead == NULL)
570                 init_pw ();
571 #endif /* DBMPWD */
572
573         for (hp = homehead; hp; hp = hp->h_next)
574                 if (!mh_strcasecmp (name, hp->h_name))
575                         return hp;
576
577 #ifdef DBMPWD
578         /*
579          * The only place where there might be problems.
580          * This assumes that ALL usernames are kept in lowercase.
581          */
582         for (c = name, c1 = lname; *c && (c1 - lname < sizeof(lname) - 1); c++, c1++) {
583                 if (isalpha(*c) && isupper(*c))
584                         *c1 = tolower (*c);
585                 else
586                         *c1 = *c;
587         }
588         *c1 = '\0';
589         if ((pw = getpwnam(lname)))
590                 return(hmalloc(pw));
591 #endif /* DBMPWD */
592
593         return NULL;
594 }