0d9c78c4a1ca1c7497cdb7b183adaff7f0dde5dd
[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/utils.h>
13 #include <grp.h>
14 #include <pwd.h>
15
16 /*
17 ** maximum number of directories that can
18 ** be specified using -search switch.
19 */
20 #define NDIRS  100
21
22 /*
23 ** Add space for group names, 100 at a time
24 */
25 #define NGRPS  100
26
27 static struct swit switches[] = {
28 #define MAILSW  0
29         { "mail name", 0 },
30 #define SERCHSW  1
31         { "search directory", 0 },
32 #define VERSIONSW  2
33         { "version", 0 },
34 #define HELPSW  3
35         { "help", 0 },
36         { NULL, 0 }
37 };
38
39 static char *mail = NULL;
40 static char *dirs[NDIRS];
41 static FILE *out = NULL;
42
43 extern struct aka  *akahead;
44 extern struct home *homehead;
45
46 /*
47 ** prototypes
48 */
49 void alias_files(int, char **);
50 void pwd_names(void);
51 void grp_names(void);
52 void grp_members(void);
53 void grp_ids(void);
54 void maildrops(void);
55 void mdrop(char *);
56 int check(char *);
57 void setup(void);
58
59
60 int
61 main(int argc, char **argv)
62 {
63         int akp = 0, dp = 0;
64         char *cp, **argp, **arguments;
65         char buf[BUFSIZ], *akv[50];
66
67 #ifdef LOCALE
68         setlocale(LC_ALL, "");
69 #endif
70         invo_name = mhbasename(argv[0]);
71
72         /* foil search of user profile/context */
73         if (context_foil(NULL) == -1)
74                 done(1);
75
76         arguments = getarguments(invo_name, argc, argv, 0);
77         argp = arguments;
78
79         while ((cp = *argp++)) {
80                 if (*cp == '-') {
81                         switch (smatch(++cp, switches)) {
82                         case AMBIGSW:
83                                 ambigsw(cp, switches);
84                                 done(1);
85                         case UNKWNSW:
86                                 adios(NULL, "-%s unknown", cp);
87
88                         case HELPSW:
89                                 snprintf(buf, sizeof(buf), "%s [switches] [aliasfiles ...]", invo_name);
90                                 print_help(buf, switches, 0);
91                                 done(1);
92                         case VERSIONSW:
93                                 print_version(invo_name);
94                                 done(1);
95
96                         case MAILSW:
97                                 if (!(cp = *argp++) || *cp == '-')
98                                         adios(NULL, "missing argument to %s",
99                                                         argp[-2]);
100                                 if (mail)
101                                         adios(NULL, "mail to one address only");
102                                 else
103                                         mail = cp;
104                                 continue;
105
106                         case SERCHSW:
107                                 if (!(cp = *argp++) || *cp == '-')
108                                         adios(NULL, "missing argument to %s",
109                                                         argp[-2]);
110                                 if (dp >= NDIRS)
111                                         adios(NULL, "more than %d directories",
112                                                         NDIRS);
113                                 dirs[dp++] = cp;
114                                 continue;
115                         }
116                 }
117                 akv[akp++] = cp;
118         }
119
120         if (!homehead)
121                 init_pw();
122         if (!mail)
123                 out = stdout;
124         dirs[dp] = NULL;
125
126         alias_files(akp, akv);
127         pwd_names();
128         grp_names();
129         grp_members();
130         grp_ids();
131         maildrops();
132
133         done(0);
134         return 1;
135 }
136
137
138 void
139 alias_files(int akp, char **akv)
140 {
141         register int i, err;
142
143         for (i = 0; i < akp; i++)
144                 if ((err = alias(akv[i])) != AK_OK) {
145                         setup();
146                         fprintf(out, "aliasing error in %s - %s\n", akv[i],
147                                         akerror(err));
148                 } else if (out && !mail)
149                         fprintf(out, "alias file %s is ok\n", akv[i]);
150 }
151
152
153 void
154 pwd_names(void)
155 {
156         int hit = 0;
157         register struct home *hm, *lm;
158
159         for (hm = homehead; hm; hm = hm->h_next)
160                 for (lm = hm->h_next; lm; lm = lm->h_next)
161                         if (strcmp(hm->h_name, lm->h_name) == 0) {
162                                 setup();
163                                 fprintf(out, "duplicate user %s(uid=%d)\n",
164                                                 lm->h_name, (int) lm->h_uid);
165                                 hit++;
166                         }
167
168         if (!hit && out && !mail)
169                 fprintf(out, "no duplicate users\n");
170 }
171
172
173 void
174 grp_names(void)
175 {
176         int numgroups, maxgroups;
177         int i, hit = 0;
178         char **grps;
179         struct group *gr;
180
181         /* allocate space NGRPS at a time */
182         numgroups = 0;
183         maxgroups = NGRPS;
184         grps = (char **) mh_xmalloc((size_t) (maxgroups * sizeof(*grps)));
185
186         setgrent();
187         while ((gr = getgrent())) {
188                 for (i = 0; i < numgroups; i++)
189                         if (strcmp(grps[i], gr->gr_name)==0) {
190                                 setup();
191                                 fprintf(out, "duplicate group %s(gid=%d)\n",
192                                                 gr->gr_name, (int) gr->gr_gid);
193                                 hit++;
194                                 break;
195                         }
196                 if (i >= numgroups) {
197                         if (numgroups >= maxgroups) {
198                                 maxgroups += NGRPS;
199                                 grps = (char **) mh_xrealloc(grps,
200                                         (size_t) (maxgroups * sizeof(*grps)));
201                         }
202                         grps[numgroups++] = getcpy(gr->gr_name);
203                 }
204         }
205         endgrent();
206
207         for (i = 0; i < numgroups; i++)
208                 free(grps[i]);
209         free(grps);
210
211         if (!hit && out && !mail)
212                 fprintf(out, "no duplicate groups\n");
213 }
214
215
216 void
217 grp_members(void)
218 {
219         register int hit = 0;
220         register char **cp, **dp;
221         register struct group *gr;
222         register struct home  *hm;
223
224         setgrent();
225         while ((gr = getgrent())) {
226                 for (cp = gr->gr_mem; *cp; cp++) {
227                         for (hm = homehead; hm; hm = hm->h_next)
228                                 if (strcmp(*cp, hm->h_name)==0)
229                                         break;
230                         if (hm == NULL) {
231                                 setup();
232                                 fprintf(out, "group %s(gid=%d) has unknown member %s\n", gr->gr_name, (int) gr->gr_gid, *cp);
233                                 hit++;
234                         } else {
235                                 hm->h_ngrps++;
236                         }
237
238                         for (dp = cp + 1; *dp; dp++)
239                                 if (strcmp(*cp, *dp) == 0) {
240                                         setup();
241                                         fprintf(out, "group %s(gid=%d) has duplicate member %s\n", gr->gr_name, (int) gr->gr_gid, *cp);
242                                         hit++;
243                                 }
244                 }
245         }
246         endgrent();
247
248         for (hm = homehead; hm; hm = hm->h_next)
249                 if (hm->h_ngrps > NGROUPS_MAX) {
250                         setup();
251                         fprintf(out, "user %s is a member of %d groups (max %d)\n",
252                                         hm->h_name, hm->h_ngrps, NGROUPS_MAX);
253                         hit++;
254                 }
255
256         if (!hit && out && !mail)
257                 fprintf(out, "all group members accounted for\n");
258 }
259
260
261 void
262 grp_ids(void)
263 {  /* -DRAND not implemented at most places */
264         register int hit = 0;
265         register struct home *hm;
266
267         for (hm = homehead; hm; hm = hm->h_next)
268                 if (getgrgid(hm->h_gid) == NULL) {
269                         setup();
270                         fprintf(out, "user %s(uid=%d) has unknown group-id %d\n", hm->h_name, (int) hm->h_uid, (int) hm->h_gid);
271                         hit++;
272                 }
273
274         if (!hit && out && !mail)
275                 fprintf(out, "all group-id users accounted for\n");
276 }
277
278
279 void
280 maildrops(void)
281 {
282         register int i;
283
284         mdrop(mailspool);
285         for (i = 0; dirs[i]; i++)
286                 mdrop(dirs[i]);
287 }
288
289
290 void
291 mdrop(char *drop)
292 {
293         register int hit = 0;
294         register struct dirent *dp;
295         register DIR *dd = opendir(drop);
296
297         if (!dd) {
298                 setup();
299                 fprintf(out, "unable to open maildrop area %s\n", drop);
300                 return;
301         }
302
303         while ((dp = readdir(dd)))
304                 if (dp->d_name[0] != '.' && !check(dp->d_name)) {
305                         setup();
306                         fprintf(out, "there is a maildrop for the unknown user %s in %s\n", dp->d_name, drop);
307                         hit++;
308                 }
309
310         closedir(dd);
311         if (!hit && out && !mail)
312                 fprintf(out, "all maildrops accounted for in %s\n", drop);
313 }
314
315
316 int
317 check(char *s)
318 {
319         register struct home *hm;
320
321         for (hm = homehead; hm; hm = hm->h_next)
322                 if (strcmp(s, hm->h_name)==0)
323                         return 1;
324         return 0;
325 }
326
327 void
328 setup(void)
329 {
330         int fd, pd[2];
331
332         if (out)
333                 return;
334
335         if (mail) {
336                 if (pipe(pd) == NOTOK)
337                         adios("pipe", "unable to");
338
339                 switch (fork()) {
340                 case NOTOK:
341                         adios("fork", "unable to");
342
343                 case OK:
344                         close(pd[1]);
345                         if (pd[0] != 0) {
346                                 dup2(pd[0], 0);
347                                 close(pd[0]);
348                         }
349                         if ((fd = open("/dev/null", O_WRONLY))
350                                         != NOTOK)
351                                 if (fd != 1) {
352                                         dup2(fd, 1);
353                                         close(fd);
354                                 }
355                         execlp(mailproc, mhbasename(mailproc),
356                                         mail, "-subject", invo_name,
357                                         NULL);
358                         adios(mailproc, "unable to exec ");
359
360                 default:
361                         close(pd[0]);
362                         out = fdopen(pd[1], "w");
363                         fprintf(out, "%s: the following is suspicious\n\n", invo_name);
364                 }
365         }
366 }