]> andersk Git - moira.git/blame - clients/passwd/chpobox.c
updated list of subdirs
[moira.git] / clients / passwd / chpobox.c
CommitLineData
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 12static 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
50char *getlogin();
51char *malloc();
52char *strcpy();
53char *strcat();
54char *whoami;
55
56int getopt();
57int status;
58
ccd5efe6 59#define MAXBOX 16
60
48fbc492 61extern int h_errno;
62static int match;
ccd5efe6 63static struct pobox_values boxes[MAXBOX];
64static int nboxes = 0;
48fbc492 65
66uid_t getuid();
67
68#define DOMAIN ".MIT.EDU"
69#define NET_ADDRESS_SIZE 500 /* You would not believe the length of some
70 * addresses.. */
71main(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 \
155run \"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 \
173email 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 205failed.\nI cannot change your mailbox at this time. Please try again \
206later.\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 \
237database.");
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 \
258database.");
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
282punt:
ccd5efe6 283 if (status)
284 com_err(whoami, status, buf);
48fbc492 285 sms_disconnect();
286 exit(1);
287}
288
289scream()
290{
291 com_err(whoami, status, "Unexpected return value from SMS -- \
292programmer 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 */
302int
303get_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
316char *
317ds(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
328char **
329crunch_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 */
345char *
346trim(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 */
369char *
370in(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 \
382database.");
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 \
393database.");
394 goto punt;
395 }
396 if (match)
397 return ("local");
398 else
399 return ("foreign");
400punt:
401 com_err(whoami, status, buf);
402 sms_disconnect();
403 exit(1);
404}
405
406/* ARGSUSED */
407int
408check_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 */
425char *
426canon(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
442usage()
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.10782 seconds and 5 git commands to generate.