]> andersk Git - moira.git/blob - clients/passwd/chpobox.c
don't allow the user to: delete his last maildrop, or add more
[moira.git] / clients / passwd / chpobox.c
1 /*
2  * Copyright 1987 by the Massachusetts Institute of Technology. For copying
3  * and distribution information, see the file "mit-copyright.h". 
4  *
5  * $Source$
6  * $Header$
7  * $Author$
8  *
9  */
10
11 #ifndef lint
12 static char *rcsid_chpobox_c = "$Header$";
13 #endif not lint
14
15 /*
16  * Talk to the SMS database to change a person's home mail machine. This may
17  * be an Athena machine, or a completely arbitrary address.
18  * 
19  * chpobox with no modifiers reports all current mailboxes.
20  * 
21  * chpobox -a [address] means add (not replace) a mailbox to the ones
22  * the user already has.  Complains if the user tries to give herself
23  * more than one mailbox of type pop.
24  *
25  * chpobox -d [address] means delete the specified mailbox from the list.
26  * Complains if this would mean leaving the user with no mailbox at all. 
27  *
28  * chpobox -u [user] is needed if you are logged in as one user, but
29  * are trying to change the email address of another.  You must have
30  * Kerberos tickets as the person whose address you are trying to
31  * change, or the attempt will fail.
32  *
33  * [address] must always have an @ sign in it. 
34  *
35  */
36
37 #include <sys/types.h>
38 #include <stdio.h>
39 #include <pwd.h>
40 #include <strings.h>
41 #include <ctype.h>
42 #include <netdb.h>
43 #include <errno.h>
44
45 /* SMS includes */
46 #include <sms.h>
47 #include <sms_app.h>
48 #include "mit-copyright.h"
49
50 char *getlogin();
51 char *malloc();
52 char *strcpy();
53 char *strcat();
54 char *whoami;
55
56 int getopt();
57 int status;
58
59 #define MAXBOX 16
60
61 extern int h_errno;
62 static int match;
63 static struct pobox_values boxes[MAXBOX];
64 static int nboxes = 0;
65
66 uid_t getuid();
67
68 #define DOMAIN ".MIT.EDU"
69 #define NET_ADDRESS_SIZE 500    /* You would not believe the length of some
70                                  * addresses.. */
71 main(argc, argv)
72     char *argv[];
73
74 {
75     struct passwd *pwd;
76     struct pobox_values getnewmach(), pobox;
77     char *smsarg[1], buf[BUFSIZ];
78     char *ds(), *trim(), *in(), *canon();
79     char *address, *uname, *machine;
80     char **return_args, **crunch_pobox_args();
81     uid_t u;
82     int get_machine(), scream();
83     int c, delflag, add, usageflag;
84
85     extern int optind;
86     extern char *optarg;
87
88     init_sms_err_tbl();
89     init_krb_err_tbl();
90     c = delflag = add = usageflag = 0;
91     address = uname = (char *) NULL;
92     u = getuid();
93
94     if ((whoami = rindex(argv[0], '/')) == NULL)
95         whoami = argv[0];
96     else
97         whoami++;
98
99     if (argc > 5) {
100         usage();
101     }
102
103     while ((c = getopt(argc, argv, "d:a:u:")) != EOF)
104         switch (c) {
105
106         case 'd':
107             if (add)
108                 usageflag++;
109             else {
110                 delflag++;
111                 address = ds(optarg);
112             }
113             break;
114         case 'a':
115             if (delflag)
116                 usageflag++;
117             else {
118                 add++;
119                 address = ds(optarg);
120             }
121             break;
122         case 'u':
123             uname = ds(optarg);
124             break;
125         default:
126             usageflag++;
127             break;
128         }
129     if (argc == 2 && optind == 1 && !uname) {
130         uname = argv[optind++];
131     }
132     if (usageflag || optind != argc) {
133         usage();
134     }
135     if (!uname) {
136         if ((uname = getlogin()) == NULL) {
137             usage();
138         }
139         if (uname[0] == '\0') {
140             pwd = getpwuid((int) u);
141             (void) strcpy(uname, pwd->pw_name);
142         }
143     }
144     smsarg[0] = uname;
145
146     status = sms_connect();
147     if (status) {
148         (void) sprintf(buf, "\nConnection to SMS server failed.");
149         goto punt;
150     }
151
152     status = sms_auth();
153     if (status) {
154         (void) sprintf(buf, "\nAuthorization failed -- please \
155 run \"kinit\" and try again.");
156         goto punt;
157     }
158
159     /*
160      * set up some bogus arguments to feed to sms_access 
161      */
162     pobox.login = uname;
163     pobox.type = "FOREIGN";
164     pobox.box = "foo";
165     pobox.machine = "baz.bat.quux";
166     return_args = crunch_pobox_args(pobox);
167     /*
168      * do an access check. 
169      */
170     status = sms_access("add_pobox", 4, return_args);
171     if (status) {
172         (void) sprintf(buf, "\nUnauthorized attempt to modify %s's \
173 email address.", uname);
174         goto punt;
175     }
176
177     /*
178      * get a list of current boxes
179      */
180     status = sms_query("get_pobox", 1, smsarg, get_machine, NULL);
181     if (status && status != SMS_NO_MATCH) {
182         com_err(whoami, status, "while retrieving current mailboxes\n");
183         goto punt;
184     }
185
186     /*
187      * address, if it exists, is of form user@host.  It needs to be split up. 
188      */
189     if (address) {
190         machine = index(address, '@');
191         if (machine) {
192             *machine++ = '\0';  /* get rid of the @ sign */
193             machine = trim(machine);    /* get rid of whitespace */
194         }
195         else {
196             fprintf(stderr, "%s: no at sign (@) in address\n",
197                     whoami);
198             sms_disconnect();
199             exit(1);
200         }                       /* now machine points to the machine name,
201                                  * and address points to the "box" name */
202         pobox.machine = canon(machine); /* canonicalize the machine name */
203         if (pobox.machine == (char *) NULL) {/* nameserver failed in canon */
204             (void) sprintf(buf, "\nNameserver lookup \
205 failed.\nI cannot change your mailbox at this time.  Please try again \
206 later.\n");
207             goto punt;
208         }
209         pobox.type = in(pobox.machine); /* find out the type     */
210         pobox.login = uname;    /* whose is changing?            */
211         pobox.box = address;    /* to what mailbox?              */
212     }
213
214     if (add) {
215         if (strcmp(pobox.type, "pop") == 0) {
216             int i;
217             /*
218              * check to be sure that they're not getting more than one. If
219              * they are, punt. 
220              */
221             for (i = 0; i < nboxes; i++) {
222                 if (!strcmp(boxes[i].type, "POP")) {
223                     printf("%s already has a pobox on %s\n",
224                            uname, boxes[i].machine);
225                     goto punt;
226                 }
227             }
228         }
229         printf("Adding email address %s@%s for %s.",
230                pobox.box, pobox.machine, uname);
231
232         return_args = crunch_pobox_args(pobox);
233         status = sms_query("add_pobox", 4, return_args, scream,
234                            (char *) NULL);
235         if (status) {
236             (void) sprintf(buf, "\nWrite failed to SMS \
237 database.");
238             goto punt;
239         }
240         printf("..done.\n");
241         sms_disconnect();
242         exit(0);
243     }
244     else if (delflag) {
245         /* check to make sure that the
246          * user isn't being left without a mailbox. */
247         if (nboxes < 2) {
248             printf("That would leave %s without a mailbox\n", uname);
249             goto punt;
250         }
251         printf("Deleting email address %s@%s for %s.", pobox.box,
252                pobox.machine, uname);
253         return_args = crunch_pobox_args(pobox);
254         status = sms_query("delete_pobox", 4, return_args, scream,
255                            (char *) NULL);
256         if (status) {
257             (void) sprintf(buf, "\nWrite failed to SMS \
258 database.");
259             goto punt;
260         }
261         printf("..done.\n");
262         sms_disconnect();
263         exit(0);
264     }
265
266     printf("Current mail address%s for %s %s:\n",
267            nboxes < 2 ? "" : "es",
268            uname,
269            nboxes < 2 ? "is" : "are");
270     if (nboxes == 0)
271         printf("  None\n");
272     else {
273         int i;
274         for (i = 0; i < nboxes; i++)
275             printf("  type: %s, address: %s@%s\n", boxes[i].type,
276                    boxes[i].box, boxes[i].machine);
277     }
278
279     sms_disconnect();
280     exit(0);
281
282 punt:
283     if (status)
284         com_err(whoami, status, buf);
285     sms_disconnect();
286     exit(1);
287 }
288
289 scream()
290 {
291     com_err(whoami, status, "Unexpected return value from SMS -- \
292 programmer botch\n");
293     sms_disconnect();
294     exit(1);
295 }
296
297 /*
298  * get_machine gets all your poboxes and displays them.
299  */
300
301 /* ARGSUSED */
302 int
303 get_machine(argc, argv, callarg)
304     int argc;
305     char **argv, *callarg;
306 {
307     struct pobox_values *pobox = &boxes[nboxes++];
308
309     pobox->type = ds(argv[1]);
310     pobox->machine = ds(argv[2]);
311     pobox->box = ds(argv[3]);
312
313     return (0);
314 }
315
316 char *
317 ds(str)
318     char *str;
319 {
320     register char *newstr = malloc((unsigned) strlen(str) + 1);
321
322     if (newstr == (char *) NULL)
323         return ((char *) NULL);
324     else
325         return (strcpy(newstr, str));
326 }
327
328 char **
329 crunch_pobox_args(in)
330     struct pobox_values in;
331 {
332     char **out;
333
334     out = (char **) malloc((unsigned) sizeof(char *) * 4);
335     out[0] = in.login;
336     out[1] = in.type;
337     out[2] = in.machine;
338     out[3] = in.box;
339     return (out);
340 }
341
342 /*
343  * Trim whitespace off of cp.  Side-effects cp. 
344  */
345 char *
346 trim(cp)
347     register char *cp;
348 {
349     register char *ep;
350
351     while (isspace(*cp))
352         cp++;
353     ep = cp;
354     while (*ep)
355         ep++;
356     if (ep > cp) {
357         for (--ep; isspace(*ep); --ep)
358             continue;
359         ep++;
360         *ep = '\0';
361     }
362     return cp;
363 }
364
365 /*
366  * given a canonicalized machine name, ask the SMS server if it is of type
367  * pop, or of type local -- if neither, we assume that it's of type foreign. 
368  */
369 char *
370 in(machine)
371     char *machine;
372 {
373     char *service[1], buf[BUFSIZ];
374     int check_match();
375
376     match = 0;
377     service[0] = ds("pop");
378     status = sms_query("get_server_locations", 1, service,
379                        check_match, machine);
380     if (status && (status != SMS_NO_MATCH)) {
381         (void) sprintf(buf, "\nRead failed from SMS \
382 database.");
383         goto punt;
384     }
385     if (match)
386         return ("pop");
387
388     service[0] = ds("local");
389     status = sms_query("get_server_locations", 1, service,
390                        check_match, machine);
391     if (status && (status != SMS_NO_MATCH)) {
392         (void) sprintf(buf, "\nRead failed from SMS \
393 database.");
394         goto punt;
395     }
396     if (match)
397         return ("local");
398     else
399         return ("foreign");
400 punt:
401     com_err(whoami, status, buf);
402     sms_disconnect();
403     exit(1);
404 }
405
406 /* ARGSUSED */
407 int
408 check_match(argc, argv, callback)
409     int argc;
410     char **argv, *callback;
411 {
412     if (match)
413         return (0);
414
415     if (strcmp(argv[1], callback) == 0)
416         match = 1;
417
418     return (0);
419 }
420
421 /*
422  * given a machine name, canonicalize it and return it.  Returns (char *)
423  * NULL if the nameserver returns any error. 
424  */
425 char *
426 canon(machine)
427     char *machine;
428 {
429     struct hostent *hostinfo;
430
431     hostinfo = gethostbyname(machine);
432     if (hostinfo != (struct hostent *) NULL)
433         machine = ds(hostinfo->h_name);
434     else                        /* gethostbyname failed; this should be very
435                                  * rare, since we're dealing with local
436                                  * hosts, so no fancy error recovery.
437                                  */
438         machine = (char *) NULL;
439     return (machine);
440 }
441
442 usage()
443 {
444     fprintf(stderr, "Usage: %s [-d|a address] [-u user]\n", whoami);
445     exit(1);
446 }
447
448 /*
449  * Local Variables:
450  * mode: c
451  * c-indent-level: 4
452  * c-continued-statement-offset: 4
453  * c-brace-offset: -4
454  * c-argdecl-indent: 4
455  * c-label-offset: -4
456  * End:
457  */
This page took 0.292503 seconds and 5 git commands to generate.