Reformated comments and long lines
[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                 } else if (out && !mail)
154                         fprintf (out, "alias file %s is ok\n", akv[i]);
155 }
156
157
158 void
159 pwd_names (void)
160 {
161         int hit = 0;
162         register struct home *hm, *lm;
163
164         for (hm = homehead; hm; hm = hm->h_next)
165                 for (lm = hm->h_next; lm; lm = lm->h_next)
166                         if (strcmp (hm->h_name, lm->h_name) == 0) {
167                                 setup ();
168                                 fprintf (out, "duplicate user %s(uid=%d)\n",
169                                                 lm->h_name, (int) lm->h_uid);
170                                 hit++;
171                         }
172
173         if (!hit && out && !mail)
174                 fprintf (out, "no duplicate users\n");
175 }
176
177
178 void
179 grp_names (void)
180 {
181         int numgroups, maxgroups;
182         int i, hit = 0;
183         char **grps;
184         struct group *gr;
185
186         /* allocate space NGRPS at a time */
187         numgroups = 0;
188         maxgroups = NGRPS;
189         grps = (char **) mh_xmalloc((size_t) (maxgroups * sizeof(*grps)));
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                                 grps = (char **) mh_xrealloc(grps,
205                                         (size_t) (maxgroups * sizeof(*grps)));
206                         }
207                         grps[numgroups++] = getcpy (gr->gr_name);
208                 }
209         }
210         endgrent ();
211
212         for (i = 0; i < numgroups; i++)
213                 free (grps[i]);
214         free (grps);
215
216         if (!hit && out && !mail)
217                 fprintf (out, "no duplicate groups\n");
218 }
219
220
221 void
222 grp_members (void)
223 {
224         register int hit = 0;
225         register char **cp, **dp;
226         register struct group *gr;
227         register struct home  *hm;
228
229         setgrent ();
230         while ((gr = getgrent ())) {
231                 for (cp = gr->gr_mem; *cp; cp++) {
232                         for (hm = homehead; hm; hm = hm->h_next)
233                                 if (!strcmp (*cp, hm->h_name))
234                                         break;
235                         if (hm == NULL) {
236                                 setup ();
237                                 fprintf (out, "group %s(gid=%d) has unknown member %s\n",
238                                                 gr->gr_name, (int) gr->gr_gid, *cp);
239                                 hit++;
240                         } else {
241                                 hm->h_ngrps++;
242                         }
243
244                         for (dp = cp + 1; *dp; dp++)
245                                 if (strcmp (*cp, *dp) == 0) {
246                                         setup ();
247                                         fprintf (out, "group %s(gid=%d) has duplicate member %s\n",
248                                                         gr->gr_name, (int) gr->gr_gid, *cp);
249                                         hit++;
250                                 }
251                 }
252         }
253         endgrent ();
254
255         for (hm = homehead; hm; hm = hm->h_next)
256                 if (hm->h_ngrps > NGROUPS_MAX) {
257                         setup ();
258                         fprintf (out, "user %s is a member of %d groups (max %d)\n",
259                                         hm->h_name, hm->h_ngrps, NGROUPS_MAX);
260                         hit++;
261                 }
262
263         if (!hit && out && !mail)
264                 fprintf (out, "all group members accounted for\n");
265 }
266
267
268 void
269 grp_ids (void)
270 {  /* -DRAND not implemented at most places */
271         register int hit = 0;
272         register struct home *hm;
273
274         for (hm = homehead; hm; hm = hm->h_next)
275                 if (getgrgid (hm->h_gid) == NULL) {
276                         setup ();
277                         fprintf (out, "user %s(uid=%d) has unknown group-id %d\n",
278                                         hm->h_name, (int) hm->h_uid, (int) hm->h_gid);
279                         hit++;
280                 }
281
282         if (!hit && out && !mail)
283                 fprintf (out, "all group-id users accounted for\n");
284 }
285
286
287 void
288 maildrops (void)
289 {
290         register int i;
291
292         if (mmdfldir && *mmdfldir)
293                 mdrop (mmdfldir);
294         if (uucpldir && *uucpldir)
295                 mdrop (uucpldir);
296         for (i = 0; dirs[i]; i++)
297                 mdrop (dirs[i]);
298 }
299
300
301 void
302 mdrop(char *drop)
303 {
304         register int hit = 0;
305         register struct dirent *dp;
306         register DIR *dd = opendir (drop);
307
308         if (!dd) {
309                 setup ();
310                 fprintf (out, "unable to open maildrop area %s\n", drop);
311                 return;
312         }
313
314         while ((dp = readdir (dd)))
315                 if (dp->d_name[0] != '.' && !check (dp->d_name)) {
316                         setup ();
317                         fprintf (out, "there is a maildrop for the unknown user %s in %s\n",
318                                         dp->d_name, drop);
319                         hit++;
320                 }
321
322         closedir (dd);
323         if (!hit && out && !mail)
324                 fprintf (out, "all maildrops accounted for in %s\n", drop);
325 }
326
327
328 int
329 check (char *s)
330 {
331         register struct home *hm;
332
333         for (hm = homehead; hm; hm = hm->h_next)
334                 if (!strcmp (s, hm->h_name))
335                         return 1;
336         return 0;
337 }
338
339 void
340 setup (void)
341 {
342         int fd, pd[2];
343
344         if (out)
345                 return;
346
347         if (mail) {
348                 if (pipe (pd) == NOTOK)
349                         adios ("pipe", "unable to");
350
351                 switch (fork ()) {
352                         case NOTOK:
353                                 adios ("fork", "unable to");
354
355                         case OK:
356                                 close (pd[1]);
357                                 if (pd[0] != 0) {
358                                         dup2 (pd[0], 0);
359                                         close (pd[0]);
360                                 }
361                                 if ((fd = open ("/dev/null", O_WRONLY)) != NOTOK)
362                                         if (fd != 1) {
363                                                 dup2 (fd, 1);
364                                                 close (fd);
365                                         }
366                                 execlp (mailproc, r1bindex (mailproc, '/'),
367                                                 mail, "-subject", invo_name, NULL);
368                                 adios (mailproc, "unable to exec ");
369
370                         default:
371                                 close (pd[0]);
372                                 out = fdopen (pd[1], "w");
373                                 fprintf (out, "%s: the following is suspicious\n\n",
374                                                 invo_name);
375                 }
376         }
377 }
378
379 #ifdef UCI
380 /*
381 ** UCI specific stuff for conflict
382 */
383
384 /* taken from <grpldr.h> */
385
386 #define GLDRS  "/admin/etc/GroupLeaders"
387
388 struct grpldr {
389         char *gl_name;
390         char **gl_ldr;
391 };
392
393 int setglent (), endglent ();
394 struct grpldr *getglent (), *getglnam ();
395
396
397 /* taken from the getglent() routines */
398
399 #define MAXGLS  100
400
401 static FILE *glp = NULL;
402 static char line[BUFSIZ+1];
403 static struct grpldr grpldr;
404 static char *gl_ldr[MAXGLS + 1];
405
406
407 setglent() {
408         if (glp == NULL)
409                 glp = fopen (GLDRS, "r");
410         else
411                 rewind (glp);
412
413         return (glp != NULL);
414 }
415
416
417 endglent() {
418         if (glp != NULL) {
419                 fclose (glp);
420                 glp = NULL;
421         }
422
423         return 1;
424 }
425
426 struct grpldr  *getglent () {
427         register char  *cp, **q;
428
429         if (glp == NULL && !setglent ())
430                 return NULL;
431         if ((cp = fgets (line, BUFSIZ, glp)) == NULL)
432                 return NULL;
433
434         grpldr.gl_name = cp;
435         grpldr.gl_ldr = q = gl_ldr;
436
437         while (*cp) {
438                 while (*cp && !isspace (*cp))
439                         cp++;
440                 while (*cp && isspace (*cp))
441                         *cp++ = '\0';
442                 if (*cp == '\0')
443                         break;
444                 if (q < gl_ldr + MAXGLS)
445                         *q++ = cp;
446                 else
447                         break;
448         }
449         *q = NULL;
450
451         return (&grpldr);
452 }
453
454 struct grpldr  *getglnam (name)
455 char   *name;
456 {
457         register struct grpldr  *gl = NULL;
458
459         setglent ();
460         while (gl = getglent ())
461                 if (strcmp (name, gl->gl_name) == 0)
462                         break;
463         endglent ();
464
465         return gl;
466 }
467
468 ldr_names () {
469         register int gp, hit = 0;
470         char *gldrs[NGRPS];
471         register struct grpldr  *gl;
472
473         gldrs[0] = NULL;
474         setglent ();
475         while (gl = getglent ()) {
476                 if (getgrnam (gl->gl_name) == NULL) {
477                         setup ();
478                         fprintf (out, "unknown group %s in group leaders file\n",
479                                         gl->gl_name);
480                         hit++;
481                 }
482                 for (gp = 0; gldrs[gp]; gp++)
483                         if (strcmp (gldrs[gp], gl->gl_name) == 0) {
484                                 setup ();
485                                 fprintf (out, "duplicate group %s in group leaders file\n",
486                                                 gl->gl_name);
487                                 hit++;
488                                 break;
489                         }
490                 if (gldrs[gp] == NULL)
491                         if (gp < NGRPS) {
492                                 gldrs[gp++] = getcpy (gl->gl_name);
493                                 gldrs[gp] = NULL;
494                         } else {
495                                 setup ();
496                                 fprintf (out, "more than %d groups in group leaders file%s\n",
497                                                 " (time to recompile)", NGRPS - 1);
498                                 hit++;
499                         }
500         }
501         endglent ();
502
503         for (gp = 0; gldrs[gp]; gp++)
504                 free (gldrs[gp]);
505
506         if (!hit && out && !mail)
507                 fprintf (out, "all groups in group leaders file accounted for\n");
508 }
509
510
511 ldr_ship () {
512         register int hit = 0;
513         register char **cp, **dp;
514         register struct grpldr  *gl;
515
516         setglent ();
517         while (gl = getglent ())
518                 for (cp = gl->gl_ldr; *cp; cp++) {
519                         if (!check (*cp)) {
520                                 setup ();
521                                 fprintf (out, "group %s has unknown leader %s\n",
522                                                 gl->gl_name, *cp);
523                                 hit++;
524                         }
525
526                         for (dp = cp + 1; *dp; dp++)
527                                 if (strcmp (*cp, *dp) == 0) {
528                                         setup ();
529                                         fprintf (out, "group %s had duplicate leader %s\n",
530                                                         gl->gl_name, *cp);
531                                         hit++;
532                                 }
533                 }
534         endglent ();
535
536         if (!hit && out && !mail)
537                 fprintf (out, "all group leaders accounted for\n");
538 }
539 #endif /* UCI */