]>
Commit | Line | Data |
---|---|---|
48fbc492 | 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$ | |
48fbc492 | 8 | * |
9 | */ | |
10 | ||
11 | #ifndef lint | |
67655a21 | 12 | static char *rcsid_chpobox_c = "$Header$"; |
48fbc492 | 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 | * | |
67655a21 | 19 | * chpobox with no modifiers reports all current mailboxes. |
48fbc492 | 20 | * |
67655a21 | 21 | * chpobox -a [address] means add (not replace) a mailbox to the ones |
48fbc492 | 22 | * the user already has. Complains if the user tries to give herself |
23 | * more than one mailbox of type pop. | |
24 | * | |
67655a21 | 25 | * chpobox -d [address] means delete the specified mailbox from the list. |
48fbc492 | 26 | * Complains if this would mean leaving the user with no mailbox at all. |
27 | * | |
67655a21 | 28 | * chpobox -u [user] is needed if you are logged in as one user, but |
48fbc492 | 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> | |
67655a21 | 48 | #include "mit-copyright.h" |
48fbc492 | 49 | |
50 | char *getlogin(); | |
51 | char *malloc(); | |
52 | char *strcpy(); | |
53 | char *strcat(); | |
54 | char *whoami; | |
55 | ||
56 | int getopt(); | |
57 | int status; | |
58 | ||
ccd5efe6 | 59 | #define MAXBOX 16 |
60 | ||
48fbc492 | 61 | extern int h_errno; |
62 | static int match; | |
ccd5efe6 | 63 | static struct pobox_values boxes[MAXBOX]; |
64 | static int nboxes = 0; | |
48fbc492 | 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; | |
f663f685 | 163 | pobox.type = "FOREIGN"; |
48fbc492 | 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 | } | |
ccd5efe6 | 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 | ||
48fbc492 | 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 */ | |
f663f685 | 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 \ | |
48fbc492 | 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) { | |
48fbc492 | 215 | if (strcmp(pobox.type, "pop") == 0) { |
ccd5efe6 | 216 | int i; |
48fbc492 | 217 | /* |
218 | * check to be sure that they're not getting more than one. If | |
219 | * they are, punt. | |
220 | */ | |
ccd5efe6 | 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 | } | |
48fbc492 | 228 | } |
ccd5efe6 | 229 | printf("Adding email address %s@%s for %s.", |
230 | pobox.box, pobox.machine, uname); | |
231 | ||
48fbc492 | 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 | } | |
ccd5efe6 | 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 | } | |
48fbc492 | 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 | } | |
ccd5efe6 | 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); | |
48fbc492 | 277 | } |
ccd5efe6 | 278 | |
48fbc492 | 279 | sms_disconnect(); |
280 | exit(0); | |
281 | ||
282 | punt: | |
ccd5efe6 | 283 | if (status) |
284 | com_err(whoami, status, buf); | |
48fbc492 | 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 | { | |
ccd5efe6 | 307 | struct pobox_values *pobox = &boxes[nboxes++]; |
48fbc492 | 308 | |
309 | pobox->type = ds(argv[1]); | |
310 | pobox->machine = ds(argv[2]); | |
311 | pobox->box = ds(argv[3]); | |
312 | ||
48fbc492 | 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) | |
f663f685 | 433 | machine = ds(hostinfo->h_name); |
48fbc492 | 434 | else /* gethostbyname failed; this should be very |
435 | * rare, since we're dealing with local | |
67655a21 | 436 | * hosts, so no fancy error recovery. |
437 | */ | |
48fbc492 | 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 | */ |