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