Added mhmail.in. start of a replacement for compiled mhmail.
[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 (0);
96                 case VERSIONSW:
97                     print_version(invo_name);
98                     done (0);
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     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], akerror (err));
150         }
151         else
152             if (out && !mail)
153                 fprintf (out, "alias file %s is ok\n", akv[i]);
154 }
155
156
157 void
158 pwd_names (void)
159 {
160     int hit = 0;
161     register struct home *hm, *lm;
162
163     for (hm = homehead; hm; hm = hm->h_next)
164         for (lm = hm->h_next; lm; lm = lm->h_next)
165             if (strcmp (hm->h_name, lm->h_name) == 0) {
166                 setup ();
167                 fprintf (out, "duplicate user %s(uid=%d)\n",
168                         lm->h_name, (int) lm->h_uid);
169                 hit++;
170             }
171
172     if (!hit && out && !mail)
173         fprintf (out, "no duplicate users\n");
174 }
175
176
177 void
178 grp_names (void)
179 {
180     int numgroups, maxgroups;
181     int i, hit = 0;
182     char **grps;
183     struct group *gr;
184
185     /* allocate space NGRPS at a time */
186     numgroups = 0;
187     maxgroups = NGRPS;
188     grps = (char **) mh_xmalloc((size_t) (maxgroups * sizeof(*grps)));
189
190     setgrent ();
191     while ((gr = getgrent ())) {
192         for (i = 0; i < numgroups; i++)
193             if (!strcmp (grps[i], gr->gr_name)) {
194                 setup ();
195                 fprintf (out, "duplicate group %s(gid=%d)\n",
196                         gr->gr_name, (int) gr->gr_gid);
197                 hit++;
198                 break;
199             }
200         if (i >= numgroups) {
201             if (numgroups >= maxgroups) {
202                 maxgroups += NGRPS;
203                 grps = (char **) mh_xrealloc(grps,
204                     (size_t) (maxgroups * sizeof(*grps)));
205             }
206             grps[numgroups++] = getcpy (gr->gr_name);
207         }
208     }
209     endgrent ();
210
211     for (i = 0; i < numgroups; i++)
212         free (grps[i]);
213     free (grps);
214
215     if (!hit && out && !mail)
216         fprintf (out, "no duplicate groups\n");
217 }
218
219
220 void
221 grp_members (void)
222 {
223     register int hit = 0;
224     register char **cp, **dp;
225     register struct group *gr;
226     register struct home  *hm;
227
228     setgrent ();
229     while ((gr = getgrent ())) {
230         for (cp = gr->gr_mem; *cp; cp++) {
231             for (hm = homehead; hm; hm = hm->h_next)
232                 if (!strcmp (*cp, hm->h_name))
233                     break;
234             if (hm == NULL) {
235                 setup ();
236                 fprintf (out, "group %s(gid=%d) has unknown member %s\n",
237                         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",
247                             gr->gr_name, (int) gr->gr_gid, *cp);
248                     hit++;
249                 }
250         }
251     }
252     endgrent ();
253
254     for (hm = homehead; hm; hm = hm->h_next)
255         if (hm->h_ngrps > NGROUPS_MAX) {
256             setup ();
257             fprintf (out, "user %s is a member of %d groups (max %d)\n",
258                     hm->h_name, hm->h_ngrps, NGROUPS_MAX);
259             hit++;
260         }
261
262     if (!hit && out && !mail)
263         fprintf (out, "all group members accounted for\n");
264 }
265
266
267 void
268 grp_ids (void)
269 {               /* -DRAND not implemented at most places */
270     register int hit = 0;
271     register struct home *hm;
272
273     for (hm = homehead; hm; hm = hm->h_next)
274         if (getgrgid (hm->h_gid) == NULL) {
275             setup ();
276             fprintf (out, "user %s(uid=%d) has unknown group-id %d\n",
277                     hm->h_name, (int) hm->h_uid, (int) hm->h_gid);
278             hit++;
279         }
280
281     if (!hit && out && !mail)
282         fprintf (out, "all group-id users accounted for\n");
283 }
284
285
286 void
287 maildrops (void) 
288 {
289     register int i;
290
291     if (mmdfldir && *mmdfldir)
292         mdrop (mmdfldir);
293     if (uucpldir && *uucpldir)
294         mdrop (uucpldir);
295     for (i = 0; dirs[i]; i++)
296         mdrop (dirs[i]);
297 }
298
299
300 void
301 mdrop(char *drop)
302 {
303     register int hit = 0;
304     register struct dirent *dp;
305     register DIR *dd = opendir (drop);
306
307     if (!dd) {
308         setup ();
309         fprintf (out, "unable to open maildrop area %s\n", drop);
310         return;
311     }
312
313     while ((dp = readdir (dd)))
314         if (dp->d_name[0] != '.' && !check (dp->d_name)) {
315             setup ();
316             fprintf (out,
317                     "there is a maildrop for the unknown user %s in %s\n",
318                     dp->d_name, drop);
319             hit++;
320         }
321
322     closedir (dd);
323     if (!hit && out && !mail)
324         fprintf (out, "all maildrops accounted for in %s\n", drop);
325 }
326
327
328 int
329 check (char *s)
330 {
331     register struct home *hm;
332
333     for (hm = homehead; hm; hm = hm->h_next)
334         if (!strcmp (s, hm->h_name))
335             return 1;
336     return 0;
337 }
338
339 void
340 setup (void)
341 {
342     int fd, pd[2];
343
344     if (out)
345         return;
346
347     if (mail) {
348         if (pipe (pd) == NOTOK)
349             adios ("pipe", "unable to");
350
351         switch (fork ()) {
352             case NOTOK: 
353                 adios ("fork", "unable to");
354
355             case OK: 
356                 close (pd[1]);
357                 if (pd[0] != 0) {
358                     dup2 (pd[0], 0);
359                     close (pd[0]);
360                 }
361                 if ((fd = open ("/dev/null", O_WRONLY)) != NOTOK)
362                     if (fd != 1) {
363                         dup2 (fd, 1);
364                         close (fd);
365                     }
366                 execlp (mailproc, r1bindex (mailproc, '/'),
367                         mail, "-subject", invo_name, NULL);
368                 adios (mailproc, "unable to exec ");
369
370             default: 
371                 close (pd[0]);
372                 out = fdopen (pd[1], "w");
373                 fprintf (out, "%s: the following is suspicious\n\n",
374                         invo_name);
375         }
376     }
377 }