6 * Copyright (C) 1987 by the Massachusetts Institute of Technology
8 * Server for user registration with SMS and Kerberos.
10 * This program is a client of the SMS server and the Kerberos
11 * admin_server, and is a server for the userreg program.
14 * Revision 1.3 1987-09-03 03:05:18 wesommer
15 * Version used for userreg tests.
17 * Revision 1.2 87/08/22 18:39:45 wesommer
18 * User registration server.
20 * Revision 1.1 87/07/31 15:48:13 wesommer
26 static char *rcsid_reg_svr_c = "$Header$";
30 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
39 #include "ureg_proto.h"
40 #include "../../include/sms.h"
41 #include "admin_server.h"
42 #include "admin_err.h"
46 extern char *strdup();
47 extern char *malloc();
48 extern int krb_err_base;
49 extern char admin_errmsg[];
52 #define STAMP { time (&now); printf(ctime(&now)); }
63 static char retval[BUFSIZ];
67 struct sockaddr_in sin;
84 sp = getservbyname("sms_ureg", "udp");
86 fprintf(stderr, "Unknown service sms_ureg/udp\n");
89 s = socket(AF_INET, SOCK_DGRAM, 0);
94 bzero((char *)&sin, sizeof(sin));
96 sin.sin_family = AF_INET;
97 sin.sin_port = sp->s_port;
98 sin.sin_addr.s_addr = INADDR_ANY;
100 if (bind(s, &sin, sizeof(sin)) < 0) {
105 status = sms_connect();
107 com_err("reg_svr", status, " on connect");
112 com_err("reg_svr", status, " on auth");
119 addrlen = sizeof(sin);
120 bzero(retval, BUFSIZ);
121 len = recvfrom(s, buf, BUFSIZ, 0, &sin, &addrlen);
124 if (errno == EINTR) continue;
128 /* Parse a request packet */
129 status = parse_pkt(buf, len, &seqno, &message);
132 format_pkt(buf, &len, seqno, status, (char *)NULL);
133 (void) sendto(s, buf, len, 0, &sin, addrlen);
137 switch((int)message.request) {
138 case UREG_VERIFY_USER:
139 status = verify_user(&message);
141 case UREG_RESERVE_LOGIN:
142 status = reserve_user(&message);
144 case UREG_SET_PASSWORD:
145 status = set_password(&message);
149 status = UREG_UNKNOWN_REQUEST;
153 format_pkt(buf, &len, seqno, status, retval);
155 sendto(s, buf, len, 0, &sin, addrlen);
166 #define min(a,b) ((a)>(b)?(b):(a))
168 int validate_idno(message, db_mit_id, first, last)
175 static char decrypt[BUFSIZ];
177 static char hashid[14];
178 char idnumber[BUFSIZ];
184 for (i = 0; i < message->sealed_len; i++) {
185 printf("%02x ", (unsigned char)message->sealed[i]);
191 string_to_key(db_mit_id, key);
192 key_sched(key, sched);
193 pcbc_encrypt(message->sealed, decrypt, message->sealed_len, sched, key, 0);
196 for (i = 0; i < message->sealed_len; i++) {
197 printf("%02x ", (unsigned char)decrypt[i]);
200 for (i = 0; i < message->sealed_len; i++) {
201 if (isprint(decrypt[i]))
202 printf("%c ", (unsigned char)decrypt[i]);
207 (void) strncpy(idnumber, decrypt, message->sealed_len);
208 temp = decrypt + strlen(idnumber) + 1;
209 len = message->sealed_len - (temp - decrypt);
211 (void) strncpy(hashid, temp, min(len, 14));
212 temp += strlen(hashid) + 1;
213 len = message->sealed_len - (temp - decrypt);
215 if (strcmp(hashid, db_mit_id)) return 1;
216 encrypt_mitid(recrypt, idnumber, first, last);
217 if (strcmp(recrypt, db_mit_id)) return 1;
225 static int status_in_db;
227 vfy_callbk(argc, argv, p_message)
228 int argc; /* Should sanity check this.. */
232 struct msg *message = (struct msg *)p_message;
234 char *firstname, *lastname;
238 printf("Callback: %s %s %s\n", argv[8], argv[5], argv[4]);
240 if (got_one) return 0;
247 status = validate_idno(message, db_mit_id, firstname, lastname);
248 if (status) return 0; /* Nope; decryption failed */
250 status_in_db = atoi(argv[7]);
251 reg_status = status_in_db;
253 if (status_in_db != 0) {
254 (void) strcpy(retval, argv[0]);
256 user_id = atoi(argv[1]);
261 encrypt_mitid(buf, idnumber, first, last)
262 char *buf, *idnumber, *first, *last;
265 extern char *crypt();
267 #define _tolower(c) ((c)|0x60)
269 salt[0] = _tolower(last[0]);
270 salt[1] = _tolower(first[0]);
273 (void) strcpy(buf, crypt(&idnumber[2], salt));
276 int verify_user(message)
283 printf("verify_user\n");
284 argv[0] = "get_user_by_first_and_last";
285 argv[1] = message->first;
286 argv[2] = message->last;
289 status = sms_query_internal(3, argv, vfy_callbk, (char *)message);
291 if (status == SMS_NO_MATCH) status = UREG_USER_NOT_FOUND;
292 if (!got_one && !status)
293 status = UREG_USER_NOT_FOUND;
295 if (status != 0) goto punt;
297 if (reg_status == 1) status = UREG_ALREADY_REGISTERED;
298 if (reg_status == 2) status = UREG_NO_PASSWD_YET;
304 reserve_user(message)
314 printf("reserve_user\n");
316 argv[0] = "gufl"; /* get_user_by_first_and_last */
317 argv[1] = message->first;
318 argv[2] = message->last;
321 status = sms_query_internal(3, argv, vfy_callbk, (char *)message);
325 if (status == SMS_NO_MATCH) status = UREG_USER_NOT_FOUND;
326 if (!got_one && !status)
327 status = UREG_USER_NOT_FOUND;
329 if (status != 0) goto punt;
330 if (reg_status != 0) {
331 status = UREG_ALREADY_REGISTERED;
335 * He's made it past this phase already.
337 if (status_in_db == 2) {
341 /* Sanity check requested login name. */
342 printf("reg_misc_len = %d\n", reg_misc_len);
344 for (i = 0; i < reg_misc_len && reg_misc[i]; i++) {
345 if (!islower(reg_misc[i])) {
346 status = UREG_INVALID_UNAME;
350 if (i < 3 || i > 8) {
351 status = UREG_INVALID_UNAME;
356 /* Send request to kerberos admin_server for login name */
358 printf("get_svc_in_tkt\n");
359 status = get_svc_in_tkt("register", "kerberos", "ATHENA.MIT.EDU",
360 "changepw", "kerberos",
363 status += krb_err_base;
368 printf("admin_call\n");
369 /* send set password request to kerberos admin_server */
370 (void) sprintf(uid_buf, "%013d", user_id); /* 13 chars of placebo */
371 /* for backwards-compat. */
373 status = admin_call(ADMIN_ADD_NEW_KEY_ATTR, login, "",
377 if (status == ADMIN_SERVER_ERROR) {
378 printf("Server error: %s\n", admin_errmsg);
380 if (strcmp(admin_errmsg,
381 "Principal already in kerberos database.") ==0)
382 status = UREG_LOGIN_USED;
392 status = set_login(login, mit_id);
396 com_err("set_login", status, 0);
399 /* choose post office */
402 status = choose_pobox(login);
404 com_err("choose_pobox", status, 0);
410 status = create_group(login);
411 if (status == SMS_LIST) status = UREG_LOGIN_USED;
414 com_err("create_group", status, 0);
417 /* set quota entry, create filsys */
420 status = alloc_filsys(login, SMS_FS_STUDENT, 0, 0);
421 if (status == SMS_FILESYS_EXISTS) status = UREG_LOGIN_USED;
423 com_err("alloc_filsys", status, 0);
426 /* set filsys and status in SMS database */
429 status = set_status_filsys(reg_misc, mit_id);
431 com_err("set_filsys", status, 0);
437 printf("reserve_user returning %s\n", error_message(status));
441 set_password(message)
447 printf("set_password\n");
449 /* validate that user is who he claims to be */
451 argv[0] = "get_user_by_first_and_last";
452 argv[1] = message->first;
453 argv[2] = message->last;
456 status = sms_query_internal(3, argv, vfy_callbk, (char *)message);
458 if (status == SMS_NO_MATCH) status = UREG_USER_NOT_FOUND;
459 if (!got_one && !status)
460 status = UREG_USER_NOT_FOUND;
462 if (status != 0) goto punt;
464 /* validate that state is equal to '2' (login, but no password) */
466 if (reg_status != 2) {
467 status = UREG_NO_LOGIN_YET;
471 printf("password for %s would be set to %s\n", retval ,reg_misc);
474 status = get_svc_in_tkt("register", "kerberos", "ATHENA.MIT.EDU",
475 "changepw", "kerberos",
478 status += krb_err_base;
481 /* send set password request to kerberos admin_server */
482 status = admin_call(ADMIN_SET_KDC_PASSWORD, retval, "",
483 reg_misc, "BBBBBBBBBBBBB");
485 if (status) goto punt;
488 status = set_final_status(retval, mit_id);
490 /* reflect reply to client */
496 parse_pkt(buf, len, seqnop, messagep)
500 struct msg *messagep;
502 if (len < 4) return UREG_BROKEN_PACKET;
503 bcopy(buf, (char *)&messagep->version, sizeof(long));
504 messagep->version = ntohl(messagep->version);
505 if (messagep->version != 1) return UREG_WRONG_VERSION;
510 if (len < 4) return UREG_BROKEN_PACKET;
511 bcopy(buf, (char *)seqnop, sizeof(long));
516 if (len < 4) return UREG_BROKEN_PACKET;
517 bcopy(buf, (char *)(&messagep->request), sizeof(long));
518 messagep->request = ntohl(messagep->request);
522 messagep->first = buf;
524 for (; *buf && len > 0; --len, ++buf) continue;
525 if (len <= 0) return UREG_BROKEN_PACKET;
529 messagep->last = buf;
531 for (; *buf && len > 0; --len, ++buf) continue;
532 if (len <= 0) return UREG_BROKEN_PACKET;
536 if (len <= 0) return UREG_BROKEN_PACKET;
538 messagep->sealed = buf;
539 messagep->sealed_len = len;
544 format_pkt(buf, lenp, seqno, status, message)
551 u_long vers = htonl((u_long)1);
552 status = htonl((u_long)status);
554 bcopy((char *)&vers, buf, sizeof(long));
555 bcopy((char *)&seqno, buf+sizeof(long), sizeof(long));
556 bcopy((char *)&status, buf+ 2*sizeof(long), sizeof(long));
557 *lenp = sizeof(long) * 3;
558 (void) strcpy(buf+3*sizeof(long), message);
559 (*lenp) += strlen(message);
562 store_user(argc, argv, argp)
567 char **retv = (char **) argp;
570 for (i = 0; i < argc; i++) {
575 retv[i] = strdup(argv[i]);
582 * Set login name of user with "idnumber" to be "username"
585 set_login(username, idnumber)
593 argv[0] = "get_user_by_mitid";
596 for (i=0; i<13; i++) {
600 status = sms_query_internal(2, argv, store_user, (char *)(retv+1));
601 if (status) return status;
605 if (retv[4]) free(retv[4]);
606 retv[4] = "null"; /* No such filesystem */
608 printf("Update_user(%s, %s)\n", retv[0], retv[1]);
610 status = sms_query("update_user", 12, retv, abort, 0);
614 for (i=1; i<12; i++) {
615 if (retv[i]) free(retv[i]);
623 * Set the status and filsys of user with username "uname" and filesys filsys.
626 set_status_filsys(username, idnumber)
634 argv[0] = "get_user_by_mitid";
637 for (i=0; i<13; i++) {
641 status = sms_query_internal(2, argv, store_user, (char *)(retv+1));
642 if (status) return status;
652 printf("Update_user(%s, %s)\n", retv[0], retv[1]);
654 status = sms_query("update_user", 12, retv, abort, 0);
657 for (i=1; i<12; i++) {
658 if (retv[i]) free(retv[i]);
664 * Set the status and filsys of user with username "uname" and filesys filsys.
667 set_final_status(username, idnumber)
675 argv[0] = "get_user_by_mitid";
678 for (i=0; i<13; i++) {
682 status = sms_query_internal(2, argv, store_user, (char *)(retv+1));
683 if (status) return status;
690 printf("Update_user(%s, %s)\n", retv[0], retv[1]);
692 status = sms_query("update_user", 12, retv, abort, 0);
694 for (i=1; i<12; i++) {
695 if (retv[i]) free(retv[i]);
705 static char *cr[] = {
712 return sms_query_internal(2, cr, abort, 0);
718 * c-continued-statement-offset: 4
720 * c-argdecl-indent: 4
724 char *get_krbhst(a1, a2)
728 strcpy(a1, "ICARUS.MIT.EDU");
735 strcpy(a1, "ATHENA.MIT.EDU");