]>
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]; | |
dbe34e72 | 78 | char *strsave(), *trim(), *in(), *canon(); |
48fbc492 | 79 | char *address, *uname, *machine; |
80 | char **return_args, **crunch_pobox_args(); | |
81 | uid_t u; | |
dbe34e72 | 82 | int get_pobox(), scream(); |
48fbc492 | 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++; | |
dbe34e72 | 111 | address = strsave(optarg); |
48fbc492 | 112 | } |
113 | break; | |
114 | case 'a': | |
115 | if (delflag) | |
116 | usageflag++; | |
117 | else { | |
118 | add++; | |
dbe34e72 | 119 | address = strsave(optarg); |
48fbc492 | 120 | } |
121 | break; | |
122 | case 'u': | |
dbe34e72 | 123 | uname = strsave(optarg); |
48fbc492 | 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 | ||
dbe34e72 | 152 | status = sms_auth("chpobox"); |
48fbc492 | 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; | |
dbe34e72 | 163 | pobox.type = "SMTP"; |
48fbc492 | 164 | pobox.box = "foo"; |
48fbc492 | 165 | return_args = crunch_pobox_args(pobox); |
166 | /* | |
167 | * do an access check. | |
168 | */ | |
dbe34e72 | 169 | status = sms_access("set_pobox", 3, return_args); |
48fbc492 | 170 | if (status) { |
171 | (void) sprintf(buf, "\nUnauthorized attempt to modify %s's \ | |
172 | email address.", uname); | |
173 | goto punt; | |
174 | } | |
ccd5efe6 | 175 | |
176 | /* | |
177 | * get a list of current boxes | |
178 | */ | |
dbe34e72 | 179 | status = sms_query("get_pobox", 1, smsarg, get_pobox, NULL); |
ccd5efe6 | 180 | if (status && status != SMS_NO_MATCH) { |
181 | com_err(whoami, status, "while retrieving current mailboxes\n"); | |
182 | goto punt; | |
183 | } | |
184 | ||
48fbc492 | 185 | /* |
186 | * address, if it exists, is of form user@host. It needs to be split up. | |
187 | */ | |
188 | if (address) { | |
189 | machine = index(address, '@'); | |
190 | if (machine) { | |
191 | *machine++ = '\0'; /* get rid of the @ sign */ | |
192 | machine = trim(machine); /* get rid of whitespace */ | |
193 | } | |
194 | else { | |
195 | fprintf(stderr, "%s: no at sign (@) in address\n", | |
196 | whoami); | |
197 | sms_disconnect(); | |
198 | exit(1); | |
199 | } /* now machine points to the machine name, | |
200 | * and address points to the "box" name */ | |
f663f685 | 201 | pobox.machine = canon(machine); /* canonicalize the machine name */ |
202 | if (pobox.machine == (char *) NULL) {/* nameserver failed in canon */ | |
203 | (void) sprintf(buf, "\nNameserver lookup \ | |
48fbc492 | 204 | failed.\nI cannot change your mailbox at this time. Please try again \ |
205 | later.\n"); | |
206 | goto punt; | |
207 | } | |
208 | pobox.type = in(pobox.machine); /* find out the type */ | |
209 | pobox.login = uname; /* whose is changing? */ | |
210 | pobox.box = address; /* to what mailbox? */ | |
211 | } | |
212 | ||
213 | if (add) { | |
48fbc492 | 214 | if (strcmp(pobox.type, "pop") == 0) { |
ccd5efe6 | 215 | int i; |
48fbc492 | 216 | /* |
217 | * check to be sure that they're not getting more than one. If | |
218 | * they are, punt. | |
219 | */ | |
ccd5efe6 | 220 | for (i = 0; i < nboxes; i++) { |
221 | if (!strcmp(boxes[i].type, "POP")) { | |
222 | printf("%s already has a pobox on %s\n", | |
223 | uname, boxes[i].machine); | |
224 | goto punt; | |
225 | } | |
226 | } | |
48fbc492 | 227 | } |
ccd5efe6 | 228 | printf("Adding email address %s@%s for %s.", |
229 | pobox.box, pobox.machine, uname); | |
230 | ||
48fbc492 | 231 | return_args = crunch_pobox_args(pobox); |
232 | status = sms_query("add_pobox", 4, return_args, scream, | |
233 | (char *) NULL); | |
234 | if (status) { | |
235 | (void) sprintf(buf, "\nWrite failed to SMS \ | |
236 | database."); | |
237 | goto punt; | |
238 | } | |
239 | printf("..done.\n"); | |
240 | sms_disconnect(); | |
241 | exit(0); | |
242 | } | |
ccd5efe6 | 243 | else if (delflag) { |
244 | /* check to make sure that the | |
245 | * user isn't being left without a mailbox. */ | |
246 | if (nboxes < 2) { | |
247 | printf("That would leave %s without a mailbox\n", uname); | |
248 | goto punt; | |
249 | } | |
48fbc492 | 250 | printf("Deleting email address %s@%s for %s.", pobox.box, |
251 | pobox.machine, uname); | |
252 | return_args = crunch_pobox_args(pobox); | |
253 | status = sms_query("delete_pobox", 4, return_args, scream, | |
254 | (char *) NULL); | |
255 | if (status) { | |
256 | (void) sprintf(buf, "\nWrite failed to SMS \ | |
257 | database."); | |
258 | goto punt; | |
259 | } | |
260 | printf("..done.\n"); | |
261 | sms_disconnect(); | |
262 | exit(0); | |
263 | } | |
ccd5efe6 | 264 | |
dbe34e72 | 265 | printf("Current mail address for %s is: ", uname); |
ccd5efe6 | 266 | if (nboxes == 0) |
267 | printf(" None\n"); | |
268 | else { | |
dbe34e72 | 269 | printf("%s\n last modified on %s by user %s using %s\n", |
270 | boxes[0].box, boxes[0].modtime, boxes[0].modby, boxes[0].modwith); | |
48fbc492 | 271 | } |
ccd5efe6 | 272 | |
48fbc492 | 273 | sms_disconnect(); |
274 | exit(0); | |
275 | ||
276 | punt: | |
ccd5efe6 | 277 | if (status) |
278 | com_err(whoami, status, buf); | |
48fbc492 | 279 | sms_disconnect(); |
280 | exit(1); | |
281 | } | |
282 | ||
283 | scream() | |
284 | { | |
285 | com_err(whoami, status, "Unexpected return value from SMS -- \ | |
286 | programmer botch\n"); | |
287 | sms_disconnect(); | |
288 | exit(1); | |
289 | } | |
290 | ||
291 | /* | |
dbe34e72 | 292 | * get_pobox gets all your poboxes and displays them. |
48fbc492 | 293 | */ |
294 | ||
295 | /* ARGSUSED */ | |
296 | int | |
dbe34e72 | 297 | get_pobox(argc, argv, callarg) |
48fbc492 | 298 | int argc; |
299 | char **argv, *callarg; | |
300 | { | |
ccd5efe6 | 301 | struct pobox_values *pobox = &boxes[nboxes++]; |
48fbc492 | 302 | |
dbe34e72 | 303 | pobox->type = strsave(argv[1]); |
304 | pobox->box = strsave(argv[2]); | |
305 | pobox->modtime = strsave(argv[3]); | |
306 | pobox->modby = strsave(argv[4]); | |
307 | pobox->modwith = strsave(argv[5]); | |
48fbc492 | 308 | |
48fbc492 | 309 | return (0); |
310 | } | |
311 | ||
48fbc492 | 312 | char ** |
313 | crunch_pobox_args(in) | |
314 | struct pobox_values in; | |
315 | { | |
316 | char **out; | |
317 | ||
dbe34e72 | 318 | out = (char **) malloc((unsigned) sizeof(char *) * 6); |
48fbc492 | 319 | out[0] = in.login; |
320 | out[1] = in.type; | |
dbe34e72 | 321 | out[2] = in.box; |
322 | out[3] = in.modtime; | |
323 | out[4] = in.modby; | |
324 | out[5] = in.modwith; | |
48fbc492 | 325 | return (out); |
326 | } | |
327 | ||
328 | /* | |
329 | * Trim whitespace off of cp. Side-effects cp. | |
330 | */ | |
331 | char * | |
332 | trim(cp) | |
333 | register char *cp; | |
334 | { | |
335 | register char *ep; | |
336 | ||
337 | while (isspace(*cp)) | |
338 | cp++; | |
339 | ep = cp; | |
340 | while (*ep) | |
341 | ep++; | |
342 | if (ep > cp) { | |
343 | for (--ep; isspace(*ep); --ep) | |
344 | continue; | |
345 | ep++; | |
346 | *ep = '\0'; | |
347 | } | |
348 | return cp; | |
349 | } | |
350 | ||
351 | /* | |
352 | * given a canonicalized machine name, ask the SMS server if it is of type | |
353 | * pop, or of type local -- if neither, we assume that it's of type foreign. | |
354 | */ | |
355 | char * | |
356 | in(machine) | |
357 | char *machine; | |
358 | { | |
359 | char *service[1], buf[BUFSIZ]; | |
360 | int check_match(); | |
361 | ||
362 | match = 0; | |
dbe34e72 | 363 | service[0] = strsave("pop"); |
48fbc492 | 364 | status = sms_query("get_server_locations", 1, service, |
365 | check_match, machine); | |
366 | if (status && (status != SMS_NO_MATCH)) { | |
367 | (void) sprintf(buf, "\nRead failed from SMS \ | |
368 | database."); | |
369 | goto punt; | |
370 | } | |
371 | if (match) | |
372 | return ("pop"); | |
373 | ||
dbe34e72 | 374 | service[0] = strsave("local"); |
48fbc492 | 375 | status = sms_query("get_server_locations", 1, service, |
376 | check_match, machine); | |
377 | if (status && (status != SMS_NO_MATCH)) { | |
378 | (void) sprintf(buf, "\nRead failed from SMS \ | |
379 | database."); | |
380 | goto punt; | |
381 | } | |
382 | if (match) | |
383 | return ("local"); | |
384 | else | |
385 | return ("foreign"); | |
386 | punt: | |
387 | com_err(whoami, status, buf); | |
388 | sms_disconnect(); | |
389 | exit(1); | |
390 | } | |
391 | ||
392 | /* ARGSUSED */ | |
393 | int | |
394 | check_match(argc, argv, callback) | |
395 | int argc; | |
396 | char **argv, *callback; | |
397 | { | |
398 | if (match) | |
399 | return (0); | |
400 | ||
401 | if (strcmp(argv[1], callback) == 0) | |
402 | match = 1; | |
403 | ||
404 | return (0); | |
405 | } | |
406 | ||
407 | /* | |
408 | * given a machine name, canonicalize it and return it. Returns (char *) | |
409 | * NULL if the nameserver returns any error. | |
410 | */ | |
411 | char * | |
412 | canon(machine) | |
413 | char *machine; | |
414 | { | |
415 | struct hostent *hostinfo; | |
416 | ||
417 | hostinfo = gethostbyname(machine); | |
418 | if (hostinfo != (struct hostent *) NULL) | |
dbe34e72 | 419 | machine = strsave(hostinfo->h_name); |
48fbc492 | 420 | else /* gethostbyname failed; this should be very |
421 | * rare, since we're dealing with local | |
67655a21 | 422 | * hosts, so no fancy error recovery. |
423 | */ | |
48fbc492 | 424 | machine = (char *) NULL; |
425 | return (machine); | |
426 | } | |
427 | ||
428 | usage() | |
429 | { | |
430 | fprintf(stderr, "Usage: %s [-d|a address] [-u user]\n", whoami); | |
431 | exit(1); | |
432 | } | |
433 | ||
434 | /* | |
435 | * Local Variables: | |
436 | * mode: c | |
437 | * c-indent-level: 4 | |
438 | * c-continued-statement-offset: 4 | |
439 | * c-brace-offset: -4 | |
440 | * c-argdecl-indent: 4 | |
441 | * c-label-offset: -4 | |
442 | * End: | |
443 | */ |