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