Relayouted all switch statements: case aligns with switch.
[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         akvis = -1;
57         v = akval(akahead, s);
58         if (akvis == -1)
59                 akvis = 0;
60         return v;
61 }
62
63
64 int
65 akvisible(void)
66 {
67         return akvis;
68 }
69
70
71 char *
72 akresult(struct aka *ak)
73 {
74         register char *cp = NULL, *dp, *pp;
75         register struct adr *ad;
76
77         for (ad = ak->ak_addr; ad; ad = ad->ad_next) {
78                 pp = ad->ad_local ? akval(ak->ak_next, ad->ad_text)
79                         : getcpy(ad->ad_text);
80
81                 if (cp) {
82                         dp = cp;
83                         cp = concat(cp, ",", pp, NULL);
84                         free(dp);
85                         free(pp);
86                 } else
87                         cp = pp;
88         }
89
90         if (akvis == -1)
91                 akvis = ak->ak_visible;
92         return cp;
93 }
94
95
96 static char *
97 akval(struct aka *ak, char *s)
98 {
99         if (!s)
100                 return s;  /* XXX */
101
102         for (; ak; ak = ak->ak_next)
103                 if (aleq(s, ak->ak_name))
104                         return akresult(ak);
105
106         return getcpy(s);
107 }
108
109
110 static int
111 aleq(char *string, char *aliasent)
112 {
113         register char c;
114
115         while ((c = *string++))
116                 if (*aliasent == '*')
117                         return 1;
118                 else
119                         if ((c | 040) != (*aliasent | 040))
120                                 return 0;
121                         else
122                                 aliasent++;
123
124         return (*aliasent == 0 || *aliasent == '*');
125 }
126
127
128 int
129 alias(char *file)
130 {
131         int i;
132         register char *bp, *cp, *pp;
133         char lc, *ap;
134         register struct aka *ak = NULL;
135         register FILE *fp;
136
137         if (*file!='/' && (strncmp(file, "./", 2) && strncmp(file, "../", 3)))
138                 file = etcpath(file);
139         if ((fp = fopen(file, "r")) == NULL) {
140                 akerrst = file;
141                 return AK_NOFILE;
142         }
143
144         while (vfgets(fp, &ap) == OK) {
145                 bp = ap;
146                 switch (*(pp = scanp(bp))) {
147                 case '<':  /* recurse a level */
148                         if (!*(cp = getp(pp + 1))) {
149                                 akerrst = "'<' without alias-file";
150                                 fclose(fp);
151                                 return AK_ERROR;
152                         }
153                         if ((i = alias(cp)) != AK_OK) {
154                                 fclose(fp);
155                                 return i;
156                         }
157
158                 case ':':  /* comment */
159                 case ';':
160                 case '#':
161                 case 0:
162                         continue;
163                 }
164
165                 akerrst = bp;
166                 if (!*(cp = seekp(pp, &lc, &ap))) {
167                         fclose(fp);
168                         return AK_ERROR;
169                 }
170                 if (!(ak = akalloc(cp))) {
171                         fclose(fp);
172                         return AK_LIMIT;
173                 }
174                 switch (lc) {
175                 case ':':
176                         ak->ak_visible = 0;
177                         break;
178
179                 case ';':
180                         ak->ak_visible = 1;
181                         break;
182
183                 default:
184                         fclose(fp);
185                         return AK_ERROR;
186                 }
187
188                 switch (*(pp = scanp(ap))) {
189                 case 0:  /* EOL */
190                         fclose(fp);
191                         return AK_ERROR;
192
193                 case '<':  /* read values from file */
194                         if (!*(cp = getp(pp + 1))) {
195                                 fclose(fp);
196                                 return AK_ERROR;
197                         }
198                         if (!addfile(ak, cp)) {
199                                 fclose(fp);
200                                 return AK_NOFILE;
201                         }
202                         break;
203
204                 case '=':  /* UNIX group */
205                         if (!*(cp = getp(pp + 1))) {
206                                 fclose(fp);
207                                 return AK_ERROR;
208                         }
209                         if (!addgroup(ak, cp)) {
210                                 fclose(fp);
211                                 return AK_NOGROUP;
212                         }
213                         break;
214
215                 case '+':  /* UNIX group members */
216                         if (!*(cp = getp(pp + 1))) {
217                                 fclose(fp);
218                                 return AK_ERROR;
219                         }
220                         if (!addmember(ak, cp)) {
221                                 fclose(fp);
222                                 return AK_NOGROUP;
223                         }
224                         break;
225
226                 case '*':  /* Everyone */
227                         addall(ak);
228                         break;
229
230                 default:  /* list */
231                         while ((cp = getalias(pp)))
232                                 add_aka(ak, cp);
233                         break;
234                 }
235         }
236
237         fclose(fp);
238         return AK_OK;
239 }
240
241
242 char *
243 akerror(int i)
244 {
245         static char buffer[BUFSIZ];
246
247         switch (i) {
248         case AK_NOFILE:
249                 snprintf(buffer, sizeof(buffer), "unable to read '%s'",
250                                 akerrst);
251                 break;
252
253         case AK_ERROR:
254                 snprintf(buffer, sizeof(buffer), "error in line '%s'",
255                                 akerrst);
256                 break;
257
258         case AK_LIMIT:
259                 snprintf(buffer, sizeof(buffer), "out of memory while on '%s'",
260                                 akerrst);
261                 break;
262
263         case AK_NOGROUP:
264                 snprintf(buffer, sizeof(buffer), "no such group as '%s'",
265                                 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                                 hmalloc(pw);
369                                 add_aka(ak, gp);
370                 }
371         }
372 #endif /* DBMPWD */
373
374         return 1;
375 }
376
377
378 static int
379 addmember(struct aka *ak, char *grp)
380 {
381         gid_t gid;
382         register struct group *gr = getgrnam(grp);
383         register struct home *hm = NULL;
384
385         if (gr)
386                 gid = gr->gr_gid;
387         else {
388                 gid = atoi(grp);
389                 gr = getgrgid(gid);
390         }
391         if (!gr) {
392                 akerrst = grp;
393                 return 0;
394         }
395
396 #ifndef DBMPWD
397         if (homehead == NULL)
398 #endif /* DBMPWD */
399                 init_pw();
400
401         for (hm = homehead; hm; hm = hm->h_next)
402                 if (hm->h_gid == gid)
403                         add_aka(ak, hm->h_name);
404
405         return 1;
406 }
407
408
409 static int
410 addall(struct aka *ak)
411 {
412         int noshell = NoShell == NULL || *NoShell == 0;
413         register struct home *hm;
414
415 #ifndef DBMPWD
416         if (homehead == NULL)
417 #endif /* DBMPWD */
418                 init_pw();
419         if (Everyone < 0)
420                 Everyone = EVERYONE;
421
422         for (hm = homehead; hm; hm = hm->h_next)
423                 if (hm->h_uid > Everyone
424                                 && (noshell || strcmp(hm->h_shell, NoShell)))
425                         add_aka(ak, hm->h_name);
426
427         return homehead != NULL;
428 }
429
430
431 static char *
432 getalias(char *addrs)
433 {
434         register unsigned char *pp, *qp;
435         static char *cp = NULL;
436
437         if (cp == NULL)
438                 cp = addrs;
439         else
440                 if (*cp == 0)
441                         return (cp = NULL);
442
443         for (pp = cp; isspace(*pp); pp++)
444                 continue;
445         if (*pp == 0)
446                 return (cp = NULL);
447         for (qp = pp; *qp != 0 && *qp != ','; qp++)
448                 continue;
449         if (*qp == ',')
450                 *qp++ = 0;
451         for (cp = qp, qp--; qp > pp; qp--)
452                 if (*qp != 0) {
453                         if (isspace(*qp))
454                                 *qp = 0;
455                         else
456                                 break;
457                 }
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 *) mh_xmalloc(sizeof(*ad));
473         ad->ad_text = getcpy(pp);
474         ad->ad_local = strchr(pp, '@') == NULL && strchr(pp, '!') == NULL;
475         ad->ad_next = NULL;
476         if (ak->ak_addr)
477                 ld->ad_next = ad;
478         else
479                 ak->ak_addr = ad;
480 }
481
482
483 void
484 init_pw(void)
485 {
486         register struct passwd  *pw;
487 #ifdef DBMPWD
488         static int init;
489
490         if (!init) {
491                 /* if the list has yet to be initialized */
492                 /* zap the list, and rebuild from scratch */
493                 homehead=NULL;
494                 hometail=NULL;
495                 init++;
496 #endif /* DBMPWD */
497
498                 setpwent();
499
500                 while ((pw = getpwent()))
501                         if (!hmalloc(pw))
502                                 break;
503
504                 endpwent();
505 #ifdef DBMPWD
506         }
507 #endif /* DBMPWD */
508 }
509
510
511 static struct aka *
512 akalloc(char *id)
513 {
514         register struct aka *p;
515
516         p = (struct aka *) mh_xmalloc(sizeof(*p));
517
518         p->ak_name = getcpy(id);
519         p->ak_visible = 0;
520         p->ak_addr = NULL;
521         p->ak_next = NULL;
522         if (akatail != NULL)
523                 akatail->ak_next = p;
524         if (akahead == NULL)
525                 akahead = p;
526         akatail = p;
527
528         return p;
529 }
530
531
532 static struct home *
533 hmalloc(struct passwd *pw)
534 {
535         register struct home *p;
536
537         p = (struct home *) mh_xmalloc(sizeof(*p));
538
539         p->h_name = getcpy(pw->pw_name);
540         p->h_uid = pw->pw_uid;
541         p->h_gid = pw->pw_gid;
542         p->h_home = getcpy(pw->pw_dir);
543         p->h_shell = getcpy(pw->pw_shell);
544         p->h_ngrps = 0;
545         p->h_next = NULL;
546         if (hometail != NULL)
547                 hometail->h_next = p;
548         if (homehead == NULL)
549                 homehead = p;
550         hometail = p;
551
552         return p;
553 }
554
555
556 struct home *
557 seek_home(char *name)
558 {
559         register struct home *hp;
560 #ifdef DBMPWD
561         struct passwd *pw;
562         char lname[32];
563         unsigned char *c;
564         char *c1;
565 #else  /* DBMPWD */
566
567         if (homehead == NULL)
568                 init_pw();
569 #endif /* DBMPWD */
570
571         for (hp = homehead; hp; hp = hp->h_next)
572                 if (!mh_strcasecmp(name, hp->h_name))
573                         return hp;
574
575 #ifdef DBMPWD
576         /*
577         ** The only place where there might be problems.
578         ** This assumes that ALL usernames are kept in lowercase.
579         */
580         for (c = name, c1 = lname; *c && (c1 - lname < sizeof(lname) - 1);
581                         c++, c1++) {
582                 if (isalpha(*c) && isupper(*c))
583                         *c1 = tolower(*c);
584                 else
585                         *c1 = *c;
586         }
587         *c1 = '\0';
588         if ((pw = getpwnam(lname)))
589                 return(hmalloc(pw));
590 #endif /* DBMPWD */
591
592         return NULL;
593 }