Renamed r1bindex() to mhbasename(), to make its function becomes clear.
[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 (akp == 0)
120                 akv[akp++] = AliasFile;
121         if (!homehead)
122                 init_pw();
123         if (!mail)
124                 out = stdout;
125         dirs[dp] = NULL;
126
127         alias_files(akp, akv);
128         pwd_names();
129         grp_names();
130         grp_members();
131         grp_ids();
132 #ifdef UCI
133         ldr_names();
134         ldr_ship();
135 #endif /* UCI */
136         maildrops();
137
138         done(0);
139         return 1;
140 }
141
142
143 void
144 alias_files(int akp, char **akv)
145 {
146         register int i, err;
147
148         for (i = 0; i < akp; i++)
149                 if ((err = alias(akv[i])) != AK_OK) {
150                         setup();
151                         fprintf(out, "aliasing error in %s - %s\n", akv[i],
152                                         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", gr->gr_name, (int) gr->gr_gid, *cp);
238                                 hit++;
239                         } else {
240                                 hm->h_ngrps++;
241                         }
242
243                         for (dp = cp + 1; *dp; dp++)
244                                 if (strcmp(*cp, *dp) == 0) {
245                                         setup();
246                                         fprintf(out, "group %s(gid=%d) has duplicate member %s\n", gr->gr_name, (int) gr->gr_gid, *cp);
247                                         hit++;
248                                 }
249                 }
250         }
251         endgrent();
252
253         for (hm = homehead; hm; hm = hm->h_next)
254                 if (hm->h_ngrps > NGROUPS_MAX) {
255                         setup();
256                         fprintf(out, "user %s is a member of %d groups (max %d)\n",
257                                         hm->h_name, hm->h_ngrps, NGROUPS_MAX);
258                         hit++;
259                 }
260
261         if (!hit && out && !mail)
262                 fprintf(out, "all group members accounted for\n");
263 }
264
265
266 void
267 grp_ids(void)
268 {  /* -DRAND not implemented at most places */
269         register int hit = 0;
270         register struct home *hm;
271
272         for (hm = homehead; hm; hm = hm->h_next)
273                 if (getgrgid(hm->h_gid) == NULL) {
274                         setup();
275                         fprintf(out, "user %s(uid=%d) has unknown group-id %d\n", hm->h_name, (int) hm->h_uid, (int) hm->h_gid);
276                         hit++;
277                 }
278
279         if (!hit && out && !mail)
280                 fprintf(out, "all group-id users accounted for\n");
281 }
282
283
284 void
285 maildrops(void)
286 {
287         register int i;
288
289         if (mmdfldir && *mmdfldir)
290                 mdrop(mmdfldir);
291         if (uucpldir && *uucpldir)
292                 mdrop(uucpldir);
293         for (i = 0; dirs[i]; i++)
294                 mdrop(dirs[i]);
295 }
296
297
298 void
299 mdrop(char *drop)
300 {
301         register int hit = 0;
302         register struct dirent *dp;
303         register DIR *dd = opendir(drop);
304
305         if (!dd) {
306                 setup();
307                 fprintf(out, "unable to open maildrop area %s\n", drop);
308                 return;
309         }
310
311         while ((dp = readdir(dd)))
312                 if (dp->d_name[0] != '.' && !check(dp->d_name)) {
313                         setup();
314                         fprintf(out, "there is a maildrop for the unknown user %s in %s\n", dp->d_name, drop);
315                         hit++;
316                 }
317
318         closedir(dd);
319         if (!hit && out && !mail)
320                 fprintf(out, "all maildrops accounted for in %s\n", drop);
321 }
322
323
324 int
325 check(char *s)
326 {
327         register struct home *hm;
328
329         for (hm = homehead; hm; hm = hm->h_next)
330                 if (!strcmp(s, hm->h_name))
331                         return 1;
332         return 0;
333 }
334
335 void
336 setup(void)
337 {
338         int fd, pd[2];
339
340         if (out)
341                 return;
342
343         if (mail) {
344                 if (pipe(pd) == NOTOK)
345                         adios("pipe", "unable to");
346
347                 switch (fork()) {
348                         case NOTOK:
349                                 adios("fork", "unable to");
350
351                         case OK:
352                                 close(pd[1]);
353                                 if (pd[0] != 0) {
354                                         dup2(pd[0], 0);
355                                         close(pd[0]);
356                                 }
357                                 if ((fd = open("/dev/null", O_WRONLY))
358                                                 != NOTOK)
359                                         if (fd != 1) {
360                                                 dup2(fd, 1);
361                                                 close(fd);
362                                         }
363                                 execlp(mailproc, mhbasename(mailproc),
364                                                 mail, "-subject", invo_name,
365                                                 NULL);
366                                 adios(mailproc, "unable to exec ");
367
368                         default:
369                                 close(pd[0]);
370                                 out = fdopen(pd[1], "w");
371                                 fprintf(out, "%s: the following is suspicious\n\n", invo_name);
372                 }
373         }
374 }
375
376 #ifdef UCI
377 /*
378 ** UCI specific stuff for conflict
379 */
380
381 /* taken from <grpldr.h> */
382
383 #define GLDRS  "/admin/etc/GroupLeaders"
384
385 struct grpldr {
386         char *gl_name;
387         char **gl_ldr;
388 };
389
390 int setglent(), endglent();
391 struct grpldr *getglent(), *getglnam();
392
393
394 /* taken from the getglent() routines */
395
396 #define MAXGLS  100
397
398 static FILE *glp = NULL;
399 static char line[BUFSIZ+1];
400 static struct grpldr grpldr;
401 static char *gl_ldr[MAXGLS + 1];
402
403
404 setglent() {
405         if (glp == NULL)
406                 glp = fopen(GLDRS, "r");
407         else
408                 rewind(glp);
409
410         return (glp != NULL);
411 }
412
413
414 endglent() {
415         if (glp != NULL) {
416                 fclose(glp);
417                 glp = NULL;
418         }
419
420         return 1;
421 }
422
423 struct grpldr *getglent() {
424         register char  *cp, **q;
425
426         if (glp == NULL && !setglent())
427                 return NULL;
428         if ((cp = fgets(line, BUFSIZ, glp)) == NULL)
429                 return NULL;
430
431         grpldr.gl_name = cp;
432         grpldr.gl_ldr = q = gl_ldr;
433
434         while (*cp) {
435                 while (*cp && !isspace(*cp))
436                         cp++;
437                 while (*cp && isspace(*cp))
438                         *cp++ = '\0';
439                 if (*cp == '\0')
440                         break;
441                 if (q < gl_ldr + MAXGLS)
442                         *q++ = cp;
443                 else
444                         break;
445         }
446         *q = NULL;
447
448         return (&grpldr);
449 }
450
451 struct grpldr *getglnam(name)
452 char   *name;
453 {
454         register struct grpldr  *gl = NULL;
455
456         setglent();
457         while (gl = getglent())
458                 if (strcmp(name, gl->gl_name) == 0)
459                         break;
460         endglent();
461
462         return gl;
463 }
464
465 ldr_names() {
466         register int gp, hit = 0;
467         char *gldrs[NGRPS];
468         register struct grpldr  *gl;
469
470         gldrs[0] = NULL;
471         setglent();
472         while (gl = getglent()) {
473                 if (getgrnam(gl->gl_name) == NULL) {
474                         setup();
475                         fprintf(out, "unknown group %s in group leaders file\n",
476                                         gl->gl_name);
477                         hit++;
478                 }
479                 for (gp = 0; gldrs[gp]; gp++)
480                         if (strcmp(gldrs[gp], gl->gl_name) == 0) {
481                                 setup();
482                                 fprintf(out, "duplicate group %s in group leaders file\n", gl->gl_name);
483                                 hit++;
484                                 break;
485                         }
486                 if (gldrs[gp] == NULL)
487                         if (gp < NGRPS) {
488                                 gldrs[gp++] = getcpy(gl->gl_name);
489                                 gldrs[gp] = NULL;
490                         } else {
491                                 setup();
492                                 fprintf(out, "more than %d groups in group leaders file (time to recompile)\n", NGRPS - 1);
493                                 hit++;
494                         }
495         }
496         endglent();
497
498         for (gp = 0; gldrs[gp]; gp++)
499                 free(gldrs[gp]);
500
501         if (!hit && out && !mail)
502                 fprintf(out, "all groups in group leaders file accounted for\n");
503 }
504
505
506 ldr_ship() {
507         register int hit = 0;
508         register char **cp, **dp;
509         register struct grpldr  *gl;
510
511         setglent();
512         while (gl = getglent())
513                 for (cp = gl->gl_ldr; *cp; cp++) {
514                         if (!check(*cp)) {
515                                 setup();
516                                 fprintf(out, "group %s has unknown leader %s\n", gl->gl_name, *cp);
517                                 hit++;
518                         }
519
520                         for (dp = cp + 1; *dp; dp++)
521                                 if (strcmp(*cp, *dp) == 0) {
522                                         setup();
523                                         fprintf(out, "group %s had duplicate leader %s\n", gl->gl_name, *cp);
524                                         hit++;
525                                 }
526                 }
527         endglent();
528
529         if (!hit && out && !mail)
530                 fprintf(out, "all group leaders accounted for\n");
531 }
532 #endif /* UCI */