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