Removed the space between function names and the opening parenthesis.
[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                                 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 }