1a921cdce7f0e6b1104a6595faf9ecaf8fe191ca
[mmh] / uip / conflict.c
1
2 /*
3  * conflict.c -- check for conflicts in mail system
4  *
5  * $Id$
6  */
7
8 #include <h/mh.h>
9 #include <fcntl.h>
10 #include <h/aliasbr.h>
11 #include <zotnet/mts/mts.h>
12 #include <grp.h>
13 #include <pwd.h>
14
15 /*
16  * maximum number of directories that can
17  * be specified using -search switch.
18  */
19 #define NDIRS   100
20
21 /*
22  * Add space for group names, 100 at a time
23  */
24 #define NGRPS   100
25
26 static struct swit switches[] = {
27 #define MAILSW         0
28     { "mail name", 0 },
29 #define SERCHSW        1
30     { "search directory", 0 },
31 #define VERSIONSW      2
32     { "version", 0 },
33 #define HELPSW         3
34     { "help", 4 },
35     { NULL, 0 }
36 };
37
38 static char *mail = NULL;
39 static char *dirs[NDIRS];
40 static FILE *out = NULL;
41
42 extern struct aka  *akahead;
43 extern struct home *homehead;
44
45 /*
46  * prototypes
47  */
48 void alias_files (int, char **);
49 void pwd_names (void);
50 void grp_names (void);
51 void grp_members (void);
52 void grp_ids (void);
53 void maildrops (void);
54 void mdrop(char *);
55 int check (char *);
56 void setup (void);
57
58
59 int
60 main (int argc, char **argv)
61 {
62     int akp = 0, dp = 0;
63     char *cp, **argp, **arguments;
64     char buf[BUFSIZ], *akv[50];
65
66 #ifdef LOCALE
67     setlocale(LC_ALL, "");
68 #endif
69     invo_name = r1bindex (argv[0], '/');
70
71     /* foil search of user profile/context */
72     if (context_foil (NULL) == -1)
73         done (1);
74
75     mts_init (invo_name);
76     arguments = getarguments (invo_name, argc, argv, 0);
77     argp = arguments;
78
79     while ((cp = *argp++)) {
80         if (*cp == '-') {
81             switch (smatch (++cp, switches)) {
82                 case AMBIGSW: 
83                     ambigsw (cp, switches);
84                     done (1);
85                 case UNKWNSW: 
86                     adios (NULL, "-%s unknown", cp);
87
88                 case HELPSW: 
89                     snprintf (buf, sizeof(buf), "%s [switches] [aliasfiles ...]",
90                         invo_name);
91                     print_help (buf, switches, 0);
92                     done (1);
93                 case VERSIONSW:
94                     print_version(invo_name);
95                     done (1);
96
97                 case MAILSW: 
98                     if (!(cp = *argp++) || *cp == '-')
99                         adios (NULL, "missing argument to %s", argp[-2]);
100                     if (mail)
101                         adios (NULL, "mail to one address only");
102                     else
103                         mail = cp;
104                     continue;
105
106                 case SERCHSW: 
107                     if (!(cp = *argp++) || *cp == '-')
108                         adios (NULL, "missing argument to %s", argp[-2]);
109                     if (dp >= NDIRS)
110                         adios (NULL, "more than %d directories", NDIRS);
111                     dirs[dp++] = cp;
112                     continue;
113             }
114         }
115         akv[akp++] = cp;
116     }
117
118     if (akp == 0)
119         akv[akp++] = AliasFile;
120     if (!homehead)
121         init_pw ();
122     if (!mail)
123         out = stdout;
124     dirs[dp] = NULL;
125
126     alias_files (akp, akv);
127     pwd_names ();
128     grp_names ();
129     grp_members ();
130     grp_ids ();
131 #ifdef  UCI
132     ldr_names ();
133     ldr_ship ();
134 #endif  /* UCI */
135     maildrops ();
136
137     return done (0);
138 }
139
140
141 void
142 alias_files (int akp, char **akv)
143 {
144     register int i, err;
145
146     for (i = 0; i < akp; i++)
147         if ((err = alias (akv[i])) != AK_OK) {
148             setup ();
149             fprintf (out, "aliasing error in %s - %s\n", akv[i], akerror (err));
150         }
151         else
152             if (out && !mail)
153                 fprintf (out, "alias file %s is ok\n", akv[i]);
154 }
155
156
157 void
158 pwd_names (void)
159 {
160     int hit = 0;
161     register struct home *hm, *lm;
162
163     for (hm = homehead; hm; hm = hm->h_next)
164         for (lm = hm->h_next; lm; lm = lm->h_next)
165             if (strcmp (hm->h_name, lm->h_name) == 0) {
166                 setup ();
167                 fprintf (out, "duplicate user %s(uid=%d)\n",
168                         lm->h_name, (int) lm->h_uid);
169                 hit++;
170             }
171
172     if (!hit && out && !mail)
173         fprintf (out, "no duplicate users\n");
174 }
175
176
177 void
178 grp_names (void)
179 {
180     int numgroups, maxgroups;
181     int i, hit = 0;
182     char **grps;
183     struct group *gr;
184
185     /* allocate space NGRPS at a time */
186     numgroups = 0;
187     maxgroups = NGRPS;
188     if (!(grps = (char **) malloc((size_t) (maxgroups * sizeof(*grps)))))
189         adios (NULL, "unable to allocate group name storage");
190
191     setgrent ();
192     while ((gr = getgrent ())) {
193         for (i = 0; i < numgroups; i++)
194             if (!strcmp (grps[i], gr->gr_name)) {
195                 setup ();
196                 fprintf (out, "duplicate group %s(gid=%d)\n",
197                         gr->gr_name, (int) gr->gr_gid);
198                 hit++;
199                 break;
200             }
201         if (i >= numgroups) {
202             if (numgroups >= maxgroups) {
203                 maxgroups += NGRPS;
204                 if (!(grps = (char **) realloc(grps,
205                         (size_t) (maxgroups * sizeof(*grps)))))
206                     adios (NULL, "unable to reallocate group name storage");
207             }
208             grps[numgroups++] = getcpy (gr->gr_name);
209         }
210     }
211     endgrent ();
212
213     for (i = 0; i < numgroups; i++)
214         free (grps[i]);
215     free (grps);
216
217     if (!hit && out && !mail)
218         fprintf (out, "no duplicate groups\n");
219 }
220
221
222 void
223 grp_members (void)
224 {
225     register int hit = 0;
226     register char **cp, **dp;
227     register struct group *gr;
228     register struct home  *hm;
229
230     setgrent ();
231     while ((gr = getgrent ())) {
232         for (cp = gr->gr_mem; *cp; cp++) {
233             for (hm = homehead; hm; hm = hm->h_next)
234                 if (!strcmp (*cp, hm->h_name))
235                     break;
236             if (hm == NULL) {
237                 setup ();
238                 fprintf (out, "group %s(gid=%d) has unknown member %s\n",
239                         gr->gr_name, (int) gr->gr_gid, *cp);
240                 hit++;
241             } else {
242                 hm->h_ngrps++;
243             }
244
245             for (dp = cp + 1; *dp; dp++)
246                 if (strcmp (*cp, *dp) == 0) {
247                     setup ();
248                     fprintf (out, "group %s(gid=%d) has duplicate member %s\n",
249                             gr->gr_name, (int) gr->gr_gid, *cp);
250                     hit++;
251                 }
252         }
253     }
254     endgrent ();
255
256     for (hm = homehead; hm; hm = hm->h_next)
257         if (hm->h_ngrps > NGROUPS_MAX) {
258             setup ();
259             fprintf (out, "user %s is a member of %d groups (max %d)\n",
260                     hm->h_name, hm->h_ngrps, NGROUPS_MAX);
261             hit++;
262         }
263
264     if (!hit && out && !mail)
265         fprintf (out, "all group members accounted for\n");
266 }
267
268
269 void
270 grp_ids (void)
271 {               /* -DRAND not implemented at most places */
272     register int hit = 0;
273     register struct home *hm;
274
275     for (hm = homehead; hm; hm = hm->h_next)
276         if (getgrgid (hm->h_gid) == NULL) {
277             setup ();
278             fprintf (out, "user %s(uid=%d) has unknown group-id %d\n",
279                     hm->h_name, (int) hm->h_uid, (int) hm->h_gid);
280             hit++;
281         }
282
283     if (!hit && out && !mail)
284         fprintf (out, "all group-id users accounted for\n");
285 }
286
287
288 void
289 maildrops (void) 
290 {
291     register int i;
292
293     if (mmdfldir && *mmdfldir)
294         mdrop (mmdfldir);
295     if (uucpldir && *uucpldir)
296         mdrop (uucpldir);
297     for (i = 0; dirs[i]; i++)
298         mdrop (dirs[i]);
299 }
300
301
302 void
303 mdrop(char *drop)
304 {
305     register int hit = 0;
306     register struct dirent *dp;
307     register DIR *dd = opendir (drop);
308
309     if (!dd) {
310         setup ();
311         fprintf (out, "unable to open maildrop area %s\n", drop);
312         return;
313     }
314
315     while ((dp = readdir (dd)))
316         if (dp->d_name[0] != '.' && !check (dp->d_name)) {
317             setup ();
318             fprintf (out,
319                     "there is a maildrop for the unknown user %s in %s\n",
320                     dp->d_name, drop);
321             hit++;
322         }
323
324     closedir (dd);
325     if (!hit && out && !mail)
326         fprintf (out, "all maildrops accounted for in %s\n", drop);
327 }
328
329
330 int
331 check (char *s)
332 {
333     register struct home *hm;
334
335     for (hm = homehead; hm; hm = hm->h_next)
336         if (!strcmp (s, hm->h_name))
337             return 1;
338     return 0;
339 }
340
341 void
342 setup (void)
343 {
344     int fd, pd[2];
345
346     if (out)
347         return;
348
349     if (mail) {
350         if (pipe (pd) == NOTOK)
351             adios ("pipe", "unable to");
352
353         switch (fork ()) {
354             case NOTOK: 
355                 adios ("fork", "unable to");
356
357             case OK: 
358                 close (pd[1]);
359                 if (pd[0] != 0) {
360                     dup2 (pd[0], 0);
361                     close (pd[0]);
362                 }
363                 if ((fd = open ("/dev/null", O_WRONLY)) != NOTOK)
364                     if (fd != 1) {
365                         dup2 (fd, 1);
366                         close (fd);
367                     }
368                 execlp (mailproc, r1bindex (mailproc, '/'),
369                         mail, "-subject", invo_name, NULL);
370                 adios (mailproc, "unable to exec ");
371
372             default: 
373                 close (pd[0]);
374                 out = fdopen (pd[1], "w");
375                 fprintf (out, "%s: the following is suspicious\n\n",
376                         invo_name);
377         }
378     }
379 }
380
381 #ifdef UCI
382 /*
383  * UCI specific stuff for conflict
384  */
385
386 /* taken from <grpldr.h> */
387
388 #define GLDRS   "/admin/etc/GroupLeaders"
389
390 struct grpldr {
391     char *gl_name;
392     char **gl_ldr;
393 };
394
395 int setglent (), endglent ();
396 struct grpldr *getglent (), *getglnam ();
397
398
399 /* taken from the getglent() routines */
400
401 #define MAXGLS  100
402
403 static FILE *glp = NULL;
404 static char line[BUFSIZ+1];
405 static struct grpldr grpldr;
406 static char *gl_ldr[MAXGLS + 1];
407
408
409 setglent() {
410     if (glp == NULL)
411         glp = fopen (GLDRS, "r");
412     else
413         rewind (glp);
414
415     return (glp != NULL);
416 }
417
418
419 endglent() {
420     if (glp != NULL) {
421         fclose (glp);
422         glp = NULL;
423     }
424
425     return 1;
426 }
427
428 struct grpldr  *getglent () {
429     register char  *cp,
430                   **q;
431
432     if (glp == NULL && !setglent ())
433         return NULL;
434     if ((cp = fgets (line, BUFSIZ, glp)) == NULL)
435         return NULL;
436
437     grpldr.gl_name = cp;
438     grpldr.gl_ldr = q = gl_ldr;
439
440     while (*cp) {
441         while (*cp && !isspace (*cp))
442             cp++;
443         while (*cp && isspace (*cp))
444             *cp++ = '\0';
445         if (*cp == '\0')
446             break;
447         if (q < gl_ldr + MAXGLS)
448             *q++ = cp;
449         else
450             break;
451     }
452     *q = NULL;
453
454     return (&grpldr);
455 }
456
457 struct grpldr  *getglnam (name)
458 char   *name;
459 {
460     register struct grpldr  *gl = NULL;
461
462     setglent ();
463     while (gl = getglent ())
464         if (strcmp (name, gl->gl_name) == 0)
465             break;
466     endglent ();
467
468     return gl;
469 }
470
471 ldr_names () {
472     register int     gp,
473                      hit = 0;
474     char   *gldrs[NGRPS];
475     register struct grpldr  *gl;
476
477     gldrs[0] = NULL;
478     setglent ();
479     while (gl = getglent ()) {
480         if (getgrnam (gl->gl_name) == NULL) {
481             setup ();
482             fprintf (out, "unknown group %s in group leaders file\n",
483                     gl->gl_name);
484             hit++;
485         }
486         for (gp = 0; gldrs[gp]; gp++)
487             if (strcmp (gldrs[gp], gl->gl_name) == 0) {
488                 setup ();
489                 fprintf (out, "duplicate group %s in group leaders file\n",
490                         gl->gl_name);
491                 hit++;
492                 break;
493             }
494         if (gldrs[gp] == NULL)
495             if (gp < NGRPS) {
496                 gldrs[gp++] = getcpy (gl->gl_name);
497                 gldrs[gp] = NULL;
498             }
499             else {
500                 setup ();
501                 fprintf (out, "more than %d groups in group leaders file%s\n",
502                         " (time to recompile)", NGRPS - 1);
503                 hit++;
504             }
505     }
506     endglent ();
507
508     for (gp = 0; gldrs[gp]; gp++)
509         free (gldrs[gp]);
510
511     if (!hit && out && !mail)
512         fprintf (out, "all groups in group leaders file accounted for\n");
513 }
514
515
516 ldr_ship () {
517     register int     hit = 0;
518     register char  **cp,
519                    **dp;
520     register struct grpldr  *gl;
521
522     setglent ();
523     while (gl = getglent ())
524         for (cp = gl->gl_ldr; *cp; cp++) {
525             if (!check (*cp)) {
526                 setup ();
527                 fprintf (out, "group %s has unknown leader %s\n",
528                         gl->gl_name, *cp);
529                 hit++;
530             }
531
532             for (dp = cp + 1; *dp; dp++)
533                 if (strcmp (*cp, *dp) == 0) {
534                     setup ();
535                     fprintf (out, "group %s had duplicate leader %s\n",
536                             gl->gl_name, *cp);
537                     hit++;
538                 }
539         }
540     endglent ();
541
542     if (!hit && out && !mail)
543         fprintf (out, "all group leaders accounted for\n");
544 }
545 #endif  /* UCI */