]> andersk Git - moira.git/blame - clients/userreg/userreg.c
User registration protocol def.
[moira.git] / clients / userreg / userreg.c
CommitLineData
989a2c2c 1/*
569ee3f8 2 * $Source$
3 * $Author$
4 * $Locker$
5 * $Header$
989a2c2c 6 */
7
8#ifndef lint
569ee3f8 9static char *rcsid_userreg_c = "$Header$";
989a2c2c 10#endif lint
11
12#include <curses.h>
13#include "userreg.h"
14#include <signal.h>
15#include <sys/time.h>
16#include <setjmp.h>
6f742fd0 17#include <ctype.h>
18#include "ureg_err.h"
19#include <krb.h>
20#include <errno.h>
989a2c2c 21#define EXIT -1
22
23
569ee3f8 24struct user user, db_user;
25struct alias alias;
26char typed_mit_id[100];
989a2c2c 27
569ee3f8 28jmp_buf redo;
29int restart();
989a2c2c 30
569ee3f8 31extern int errno;
32int user_is_valid = 0;
6f742fd0 33int user_has_login = 0;
569ee3f8 34int already_registered = 0;
989a2c2c 35
569ee3f8 36fix_display(sig)
989a2c2c 37{
569ee3f8 38 signal(sig, SIG_IGN); /* let us clean up, please */
989a2c2c 39 noraw();
40 echo();
41 endwin();
569ee3f8 42 exit(1);
989a2c2c 43}
44
569ee3f8 45main(argc, argv)
46 int argc;
47 char **argv;
989a2c2c 48{
569ee3f8 49 register int ntimes;
50 register int reencrypt;
51 char line[100];
6f742fd0 52 int status;
53
54 status = ureg_init();
55 if (status) {
56 com_err(argv[0], status, "while trying to initialize");
57 exit(1);
58 }
569ee3f8 59
60 setup_display();
61
62 signal(SIGINT, fix_display);
63 signal(SIGQUIT, fix_display);
64 signal(SIGHUP, fix_display);
65
66 do {
67 setjmp(redo);
68 reset();
69 ntimes = 0;
70
71 display_text(WELCOME);
72
73 gfirst();
74 gmi();
75 glast();
76 gmitid();
77
78 while (dolook()) {
79 ntimes++;
80 if (ntimes > 3) {
81 display_text_line("Sorry, you still cannot be found in the database.");
82 display_text_line(" ");
83 display_text_line("Please call the account administrator at x1325 for help.");
84 sleep(8);
85 break;
86 }
87 display_text_line(0); /* clear the window */
88 display_text_line("I'm afraid I was unable to find you in the database.");
89 display_text_line("Do you want to change some input (for example, the spelling");
90 display_text_line("of part of your name) and try again?");
91 if (askyn("Do you want to try again ? ") == YES) {
92 reencrypt = 0;
93 display_text_line(0);
94 sprintf(line,
95 "You entered your first name as \"%s\"", user.u_first);
96 display_text_line(line);
97 if (askyn("Do you want to change it? ") == YES) {
98 gfirst();
99 reencrypt = 1;
100 }
101 display_text_line(0);
102 sprintf(line,
103 "You entered your middle initial as \"%s\"", user.u_mid_init);
104 display_text_line(line);
105 if (askyn("Do you want to change it? ") == YES)
106 gmi();
107 display_text_line(0);
108 sprintf(line,
109 "You entered your last name as \"%s\"", user.u_last);
110 display_text_line(line);
111 if (askyn("Do you want to change it? ") == YES) {
112 glast();
113 reencrypt = 1;
114 }
115 display_text_line(0);
116 sprintf(line,
117 "You entered your MIT id number as \"%s\"", typed_mit_id);
118 display_text_line(line);
119 if (askyn("Do you want to change it? ") == YES) {
120 gmitid();
121 reencrypt = 0;
122 }
123 if (reencrypt) {
124 encrypt_mitid();
125 }
126 } else
127 break;
128 }
129 if (!user_is_valid || already_registered) {
130 qexit();
131 continue;
132 }
133 redisp();
6f742fd0 134 if (!user_has_login) {
135 if (negotiate_login() == -1) {
136 qexit();
137 continue;
138 }
139 }
140 if (negotiate_passwd() == -1) {
569ee3f8 141 qexit();
142 continue;
143 }
144 sleep(1);
145 display_text_line(0);
146 display_text_line("You are now registered to get an Athena account.");
147 sprintf(line, "Please remember your username of \"%s\" and the password",
148 user.u_login);
149 display_text_line(line);
150 display_text_line("you typed in earlier.");
151 display_text_line("");
152 display_text_line("You are now finished. Thank you!");
153 sleep(5);
154 qexit();
155 } while (getuid() == 0);/* Loop forever if we're root */
156 restore_display();
157 exit(0);
989a2c2c 158}
159
569ee3f8 160reset()
161{
162 reset_display();
163 bzero(&user, sizeof(user));
164 user_is_valid = 0;
165 already_registered = 0;
166 redisp();
989a2c2c 167}
168
569ee3f8 169dolook()
170{
171 /* do the database lookup */
989a2c2c 172
569ee3f8 173 char line[100];
174 register int result;
175 if (user_is_valid) {
176 /* !! */
177 return (0);
178 }
179 display_text_line(0);
180 display_text_line(
181 "Looking you up in the database.... This may take a few minutes.");
6f742fd0 182
183 result = verify_user(user.u_first, user.u_last,
184 typed_mit_id, user.u_mit_id, db_user.u_login);
185 switch(result) {
186 case 0:
187 display_text_line("You have been located in the user registration database.");
188 user_is_valid = 1;
189 user_has_login = 0;
190 sleep(1);
191 return 0;
192 case UREG_NO_PASSWD_YET:
193 user_is_valid = 1;
194 user_has_login = 1;
195 display_text_line ("You have chosen a login name, but you have not yet chosen a password.");
196 sprintf(line, "Remember: the username you chose was '%s'",
197 db_user.u_login);
198 strcpy(user.u_login, db_user.u_login);
199 display_text_line(line);
200 redisp();
201 sleep(5);
202 return (0);
203
204 case UREG_ALREADY_REGISTERED:
205 already_registered = 1;
206 /*
207 * we have to reset this so we dont ask for a
208 * new username
209 */
210 user_is_valid = 0;
211 display_text_line("You are already registered. An account for you probably already exists");
212 display_text_line("(if not, it will appear within 12 hours).");
213 display_text_line("");
214 display_text_line("Refer to the documents 'Essential Athena' and 'Essential Unix'");
215 strcpy(user.u_login, db_user.u_login);
216 sprintf(line, "for help logging in. Remember, the username you chose was '%s'",
217 db_user.u_login);
218 display_text_line(line);
219 redisp();
220 sleep(5);
221 return (0);
222 case UREG_USER_NOT_FOUND:
223 return (1);
224 case ECONNREFUSED:
569ee3f8 225 display_text(NETWORK_DOWN);
6f742fd0 226 return (0);
227
228 default:
229 display_text_line("An unexpected error occurred while trying to access the database");
230 display_text_line(error_message(result));
231 redisp();
569ee3f8 232 sleep(5);
6f742fd0 233 return(1);
989a2c2c 234 }
989a2c2c 235}
236
6f742fd0 237negotiate_login()
569ee3f8 238{
239 register int result, result2;
240 int same;
241 char line[100];
242 char old_login[LOGIN_SIZE];
243 char old_password[PASSWORD_SIZE];
6f742fd0 244 int i;
245
569ee3f8 246 display_text(USERNAME_BLURB);
6f742fd0 247 user.u_login[0] = user.u_first[0];
248 user.u_login[1] = user.u_mid_init[0];
249 strncpy(user.u_login+2, user.u_last, 6);
250 for (i=0; user.u_login[i]; i++)
251 if (isupper(user.u_login[i]))
252 user.u_login[i]=tolower(user.u_login[i]);
253
569ee3f8 254 strcpy(old_login, user.u_login);
255 sprintf(line, "We suggest the username '%s'.", user.u_login);
256 display_text_line(line);
257 display_text_line(
258 "If you are sure you would prefer another username, feel free to enter");
259 display_text_line(
6f742fd0 260 "a different one, but remember that it will remain with you for all the ");
261 display_text_line("time you are at MIT.");
569ee3f8 262
569ee3f8 263 while (1) {
264 glogin();
6f742fd0 265
569ee3f8 266 display_text_line(0);
267 display_text_line("Looking up that username in the database... This may take a few minutes.");
6f742fd0 268 /*
269 * Rather than bother SMS with a bunch of different
270 * usernames, all in use, we first try and see if this
271 * guy is known to Kerberos.
272 */
273 result = get_in_tkt(user.u_login, "", "ATHENA.MIT.EDU", "krbtgt", "ATHENA.MIT.EDU", "");
274 if (result != KDC_PR_UNKNOWN) {
275 in_use:
569ee3f8 276 strcpy(user.u_login, old_login);
277 redisp();
6f742fd0 278 display_text_line("I'm sorry, but that username is already taken. Please try again with a different username");
569ee3f8 279 continue;
569ee3f8 280 }
6f742fd0 281 /*
282 * If he isn't, let's try through SMS.
283 */
284 result = grab_login(user.u_first, user.u_last,
285 typed_mit_id, user.u_mit_id,
286 user.u_login);
287 if (result != 0) {
288 if (result == UREG_LOGIN_USED) goto in_use;
289 display_text(NETWORK_DOWN);
290 return (qexit());
291 } else break;
569ee3f8 292 }
569ee3f8 293 /* at this point we have successfully negotiated a username */
294
6f742fd0 295 sprintf(line, "O.K. your username will be \"%s\".", user.u_login);
569ee3f8 296 display_text_line(0);
297 display_text_line(line);
298 redisp();
299 sleep(3);
6f742fd0 300 return 0;
301}
302negotiate_passwd()
303{
569ee3f8 304 display_text_line(0);
305 display_text(PASSWORD_BLURB);
6f742fd0 306
569ee3f8 307 gpass();
6f742fd0 308 display_text_line("Storing password in the database... This may take a few minutes.");
569ee3f8 309 if (do_replace()) {
310 return (-1);
311 }
312 display_text_line("done.");
6f742fd0 313
989a2c2c 314}
315
569ee3f8 316gfirst()
317{
318 /* input the first name */
319 char buf[100];
320
321 signal(SIGALRM, restart);
322 input("Enter first Name:", buf, 100, FIRSTNAME_TIMEOUT);
323 strncpy(user.u_first, buf, FIRST_NAME_SIZE);
324 user.u_first[FIRST_NAME_SIZE - 1] = '\0';
6f742fd0 325 canon_name(user.u_first);
569ee3f8 326 redisp();
327}
989a2c2c 328
569ee3f8 329glast()
330{
331 /* input the last name */
332 char buf[100];
333
334 signal(SIGALRM, restart);
335 input("Enter last Name:", buf, 100, LASTNAME_TIMEOUT);
336 strncpy(user.u_last, buf, LAST_NAME_SIZE);
337 user.u_last[LAST_NAME_SIZE - 1] = '\0';
6f742fd0 338 canon_name(user.u_last);
569ee3f8 339 redisp();
989a2c2c 340}
341
569ee3f8 342gpass()
343{
344 /* input password */
345 char old_password[PASSWORD_SIZE];
346 char new_password[PASSWORD_SIZE];
347 char new_password_again[PASSWORD_SIZE];
348
349 if (already_registered) { /* we have to ask for his old
350 * password */
351 signal(SIGALRM, restart);
352 input_no_echo("Enter old Password:", old_password,
353 PASSWORD_SIZE, OLD_PASSWORD_TIMEOUT);
354 if (strcmp(user.u_password, crypt(old_password,
355 user.u_password))) {
356 display_text_line("Sorry, that does not match your old password.");
357 display_text_line("In order to get a new one, you have to know the old one.");
358 return (1);
359 }
360 }
361do_input:
362 signal(SIGALRM, restart);
363 input_no_echo("Enter password:", new_password,
364 PASSWORD_SIZE, NEW_PASSWORD_TIMEOUT);
365 if (strlen(new_password) < 4) {
366 display_text_line("Please use a password of at least 4 characters.");
367 goto do_input;
368 }
369 signal(SIGALRM, restart);
370 input_no_echo("Enter password again:", new_password_again,
371 PASSWORD_SIZE, REENTER_PASSWORD_TIMEOUT);
372 if (strcmp(new_password, new_password_again)) {
373 display_text_line("Sorry, the two passwords you just typed in don't match.");
374 display_text_line("Please try again.");
375 goto do_input;
376 }
377 /*
378 * give him a new password. It looks funny because we are trying to
379 * get a semi_random key without a lot of hair by using the login
380 * name as a seed
381 */
382
6f742fd0 383 strcpy(user.u_password, new_password);
569ee3f8 384 redisp();
989a2c2c 385}
386
569ee3f8 387glogin()
388{
389 /* get login name */
390 register int i;
391 char buf[100];
392 register char *nbuf = buf;
393
394input_login:
395 i = 0;
396 user.u_login[0] = '\0';
397 nbuf = &buf[0];
398 signal(SIGALRM, restart);
399 input("Enter username:", buf, 100, USERNAME_TIMEOUT);
400 while (*nbuf != '\0') {
401 if (!islower(*nbuf)) {
402 display_text_line("Your username must be all lowercase alphabetic characters.");
403 goto input_login;
404 }
405 user.u_login[i] = *nbuf++;
406 i++;
407 if (i > LOGIN_SIZE - 1) {
408 display_text_line("Your username must be no more than 8 characters long.");
409 goto input_login;
410 }
411 }
412 if (i != 0) {
413 user.u_login[i] = '\0';
414 }
415 if (strlen(user.u_login) < 2) {
416 goto input_login;
417 }
6f742fd0 418#ifdef notdef
569ee3f8 419 /* This part added to fix home directories -- asp */
420 strcpy(user.u_home_dir, "/mit/");
421 user.u_home_dir[5] = user.u_login[0];
422 user.u_home_dir[6] = '/';
423 user.u_home_dir[7] = user.u_login[1];
424 user.u_home_dir[8] = '/';
425 strcpy(user.u_home_dir + 9, user.u_login);
6f742fd0 426#endif notdef
569ee3f8 427 redisp();
989a2c2c 428}
429
569ee3f8 430gmitid()
431{
432 /* get mid id */
433 register int i;
434 char buf[100];
435 register char *nbuf = buf;
436
437input_mit_id:
438 signal(SIGALRM, restart);
439 input("Enter MIT Id:", buf, 100, MITID_TIMEOUT);
440 i = 0;
441 nbuf = &buf[0];
442 while (*nbuf != '\0') {
443 if (*nbuf == ' ' || *nbuf == '-') {
444 nbuf++;
445 continue;
446 }
447 if (!isdigit(*nbuf)) {
448 i = 0;
449 break;
450 }
451 typed_mit_id[i] = *nbuf;
452 nbuf++;
453 i++;
454 }
455 if (i != 9) {
456 display_text_line(
457 "Your MIT id must be a nine-digit number. Please try again.");
458 goto input_mit_id;
459 }
460 typed_mit_id[9] = '\0';
461 redisp();
462 encrypt_mitid();
989a2c2c 463}
464
569ee3f8 465encrypt_mitid()
466{
467 char salt[3];
989a2c2c 468
569ee3f8 469 make_salt(salt, user.u_first, user.u_last);
470 strcpy(user.u_mit_id, crypt(&typed_mit_id[2], salt));
989a2c2c 471}
472
473
474#define _tolower(c) ((c)|0x60)
475
569ee3f8 476make_salt(salt, first, last)
477 char *salt, *first, *last;
989a2c2c 478{
569ee3f8 479 salt[0] = _tolower(last[0]);
480 salt[1] = _tolower(first[0]);
989a2c2c 481}
482
483
569ee3f8 484gmi()
485{
486 /* get middle initial */
487 char buf[100];
488
489 signal(SIGALRM, restart);
490 input("Enter Middle Initial:", buf, 100, MI_TIMEOUT);
491 strncpy(user.u_mid_init, buf, MID_INIT_SIZE);
492 user.u_mid_init[MID_INIT_SIZE - 1] = '\0';
6f742fd0 493 canon_name(user.u_mid_init);
569ee3f8 494 redisp();
989a2c2c 495}
496
569ee3f8 497qexit()
498{
499 /* exit quickly, not saving anything in the database */
500 bzero(&user, sizeof(user));
501 typed_mit_id[0] = '\0';
502 user_is_valid = 0;
503 already_registered = 0;
504 sleep(6); /* give the user a chance to see the screen */
505 display_text_line(0);
506 return (EXIT);
989a2c2c 507}
508
509
569ee3f8 510do_replace()
511{
6f742fd0 512 int status;
513
569ee3f8 514 /*
515 * replaces a user in the database. If there is an error, it informs
516 * the user and calls qexit(); It returns only if is is successful
517 */
6f742fd0 518 status = set_password(user.u_first, user.u_last, typed_mit_id,
519 user.u_mit_id, user.u_password);
520 if (status) {
521 display_text (NETWORK_DOWN);
569ee3f8 522 return (-1);
6f742fd0 523 } else return 0;
989a2c2c 524}
525
526#define _toupper(c) ((c) & ~0x20)
527
569ee3f8 528lenient_strcmp(string1, string2)
529 register char *string1, *string2;
989a2c2c 530{
569ee3f8 531 /*
532 * a primitive case insensitive string comparison. It returns only 0
533 * if the strings are equal (ignoring case) and 1 if they are
534 * different. Also ignores spaces.
535 */
536
537 while (1) {
538 if (*string1 == '\0' && *string2 == '\0') {
539 return (0);
540 }
541 if (*string1 == ' ' || *string1 == '.' || *string1 == '-' || *string1 == '\'') {
542 string1++;
543 continue;
544 }
545 if (*string2 == ' ' || *string2 == '.' || *string2 == '-' || *string2 == '\'') {
546 string2++;
547 continue;
548 }
549 if (_toupper(*string1) != _toupper(*string2)) {
550 return (1);
551 }
552 string1++;
553 string2++;
554 }
989a2c2c 555}
556
569ee3f8 557/*
558 * Input timeout handler. Loop back to asking for the first name.
989a2c2c 559 */
560
561restart()
562/* Go to asking for first name. */
563{
569ee3f8 564 qexit();
565 longjmp(redo);
989a2c2c 566}
6f742fd0 567
568canon_name(cp)
569 register char *cp;
570{
571 register char *p2 = cp;
572
573 /* Trim whitespace off both ends. */
574 for (; *p2 && isspace(*p2); p2++) ;
575 if (*p2) {
576 strcpy(cp, p2);
577 p2 = cp + strlen(cp);
578 --p2;
579 while (p2 >= cp && isspace(*p2)) *(--p2) = '\0';
580 }
581 /* Make it capitalized */
582 for (p2=cp; *p2; p2++) {
583 if (isupper(*p2)) *p2 = tolower(*p2);
584 }
585 if (islower(*cp)) *cp=toupper(*cp);
586}
This page took 0.342162 seconds and 5 git commands to generate.