Removed mts.conf; the maildelivery option went into slocal directly.
[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         arguments = getarguments(invo_name, argc, argv, 0);
78         argp = arguments;
79
80         while ((cp = *argp++)) {
81                 if (*cp == '-') {
82                         switch (smatch(++cp, switches)) {
83                         case AMBIGSW:
84                                 ambigsw(cp, switches);
85                                 done(1);
86                         case UNKWNSW:
87                                 adios(NULL, "-%s unknown", cp);
88
89                         case HELPSW:
90                                 snprintf(buf, sizeof(buf), "%s [switches] [aliasfiles ...]", invo_name);
91                                 print_help(buf, switches, 0);
92                                 done(1);
93                         case VERSIONSW:
94                                 print_version(invo_name);
95                                 done(1);
96
97                         case MAILSW:
98                                 if (!(cp = *argp++) || *cp == '-')
99                                         adios(NULL, "missing argument to %s",
100                                                         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",
110                                                         argp[-2]);
111                                 if (dp >= NDIRS)
112                                         adios(NULL, "more than %d directories",
113                                                         NDIRS);
114                                 dirs[dp++] = cp;
115                                 continue;
116                         }
117                 }
118                 akv[akp++] = cp;
119         }
120
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         maildrops();
133
134         done(0);
135         return 1;
136 }
137
138
139 void
140 alias_files(int akp, char **akv)
141 {
142         register int i, err;
143
144         for (i = 0; i < akp; i++)
145                 if ((err = alias(akv[i])) != AK_OK) {
146                         setup();
147                         fprintf(out, "aliasing error in %s - %s\n", akv[i],
148                                         akerror(err));
149                 } else if (out && !mail)
150                         fprintf(out, "alias file %s is ok\n", akv[i]);
151 }
152
153
154 void
155 pwd_names(void)
156 {
157         int hit = 0;
158         register struct home *hm, *lm;
159
160         for (hm = homehead; hm; hm = hm->h_next)
161                 for (lm = hm->h_next; lm; lm = lm->h_next)
162                         if (strcmp(hm->h_name, lm->h_name) == 0) {
163                                 setup();
164                                 fprintf(out, "duplicate user %s(uid=%d)\n",
165                                                 lm->h_name, (int) lm->h_uid);
166                                 hit++;
167                         }
168
169         if (!hit && out && !mail)
170                 fprintf(out, "no duplicate users\n");
171 }
172
173
174 void
175 grp_names(void)
176 {
177         int numgroups, maxgroups;
178         int i, hit = 0;
179         char **grps;
180         struct group *gr;
181
182         /* allocate space NGRPS at a time */
183         numgroups = 0;
184         maxgroups = NGRPS;
185         grps = (char **) mh_xmalloc((size_t) (maxgroups * sizeof(*grps)));
186
187         setgrent();
188         while ((gr = getgrent())) {
189                 for (i = 0; i < numgroups; i++)
190                         if (strcmp(grps[i], gr->gr_name)==0) {
191                                 setup();
192                                 fprintf(out, "duplicate group %s(gid=%d)\n",
193                                                 gr->gr_name, (int) gr->gr_gid);
194                                 hit++;
195                                 break;
196                         }
197                 if (i >= numgroups) {
198                         if (numgroups >= maxgroups) {
199                                 maxgroups += NGRPS;
200                                 grps = (char **) mh_xrealloc(grps,
201                                         (size_t) (maxgroups * sizeof(*grps)));
202                         }
203                         grps[numgroups++] = getcpy(gr->gr_name);
204                 }
205         }
206         endgrent();
207
208         for (i = 0; i < numgroups; i++)
209                 free(grps[i]);
210         free(grps);
211
212         if (!hit && out && !mail)
213                 fprintf(out, "no duplicate groups\n");
214 }
215
216
217 void
218 grp_members(void)
219 {
220         register int hit = 0;
221         register char **cp, **dp;
222         register struct group *gr;
223         register struct home  *hm;
224
225         setgrent();
226         while ((gr = getgrent())) {
227                 for (cp = gr->gr_mem; *cp; cp++) {
228                         for (hm = homehead; hm; hm = hm->h_next)
229                                 if (strcmp(*cp, hm->h_name)==0)
230                                         break;
231                         if (hm == NULL) {
232                                 setup();
233                                 fprintf(out, "group %s(gid=%d) has unknown member %s\n", gr->gr_name, (int) gr->gr_gid, *cp);
234                                 hit++;
235                         } else {
236                                 hm->h_ngrps++;
237                         }
238
239                         for (dp = cp + 1; *dp; dp++)
240                                 if (strcmp(*cp, *dp) == 0) {
241                                         setup();
242                                         fprintf(out, "group %s(gid=%d) has duplicate member %s\n", gr->gr_name, (int) gr->gr_gid, *cp);
243                                         hit++;
244                                 }
245                 }
246         }
247         endgrent();
248
249         for (hm = homehead; hm; hm = hm->h_next)
250                 if (hm->h_ngrps > NGROUPS_MAX) {
251                         setup();
252                         fprintf(out, "user %s is a member of %d groups (max %d)\n",
253                                         hm->h_name, hm->h_ngrps, NGROUPS_MAX);
254                         hit++;
255                 }
256
257         if (!hit && out && !mail)
258                 fprintf(out, "all group members accounted for\n");
259 }
260
261
262 void
263 grp_ids(void)
264 {  /* -DRAND not implemented at most places */
265         register int hit = 0;
266         register struct home *hm;
267
268         for (hm = homehead; hm; hm = hm->h_next)
269                 if (getgrgid(hm->h_gid) == NULL) {
270                         setup();
271                         fprintf(out, "user %s(uid=%d) has unknown group-id %d\n", hm->h_name, (int) hm->h_uid, (int) hm->h_gid);
272                         hit++;
273                 }
274
275         if (!hit && out && !mail)
276                 fprintf(out, "all group-id users accounted for\n");
277 }
278
279
280 void
281 maildrops(void)
282 {
283         register int i;
284
285         mdrop(mailspool);
286         for (i = 0; dirs[i]; i++)
287                 mdrop(dirs[i]);
288 }
289
290
291 void
292 mdrop(char *drop)
293 {
294         register int hit = 0;
295         register struct dirent *dp;
296         register DIR *dd = opendir(drop);
297
298         if (!dd) {
299                 setup();
300                 fprintf(out, "unable to open maildrop area %s\n", drop);
301                 return;
302         }
303
304         while ((dp = readdir(dd)))
305                 if (dp->d_name[0] != '.' && !check(dp->d_name)) {
306                         setup();
307                         fprintf(out, "there is a maildrop for the unknown user %s in %s\n", dp->d_name, drop);
308                         hit++;
309                 }
310
311         closedir(dd);
312         if (!hit && out && !mail)
313                 fprintf(out, "all maildrops accounted for in %s\n", drop);
314 }
315
316
317 int
318 check(char *s)
319 {
320         register struct home *hm;
321
322         for (hm = homehead; hm; hm = hm->h_next)
323                 if (strcmp(s, hm->h_name)==0)
324                         return 1;
325         return 0;
326 }
327
328 void
329 setup(void)
330 {
331         int fd, pd[2];
332
333         if (out)
334                 return;
335
336         if (mail) {
337                 if (pipe(pd) == NOTOK)
338                         adios("pipe", "unable to");
339
340                 switch (fork()) {
341                 case NOTOK:
342                         adios("fork", "unable to");
343
344                 case OK:
345                         close(pd[1]);
346                         if (pd[0] != 0) {
347                                 dup2(pd[0], 0);
348                                 close(pd[0]);
349                         }
350                         if ((fd = open("/dev/null", O_WRONLY))
351                                         != NOTOK)
352                                 if (fd != 1) {
353                                         dup2(fd, 1);
354                                         close(fd);
355                                 }
356                         execlp(mailproc, mhbasename(mailproc),
357                                         mail, "-subject", invo_name,
358                                         NULL);
359                         adios(mailproc, "unable to exec ");
360
361                 default:
362                         close(pd[0]);
363                         out = fdopen(pd[1], "w");
364                         fprintf(out, "%s: the following is suspicious\n\n", invo_name);
365                 }
366         }
367 }