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