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