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