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.7 1988-02-08 15:08:15 mar
15 * Moved header file locations
17 * Revision 1.6 87/09/21 15:19:11 wesommer
18 * Allow numbers, _, and . as legal characters in the username.
20 * Revision 1.5 87/09/10 22:18:32 wesommer
21 * Clean up output format.
23 * Revision 1.4 87/09/04 23:33:19 wesommer
24 * Deleted test scaffolding (second oops.)
26 * Revision 1.3 87/09/03 03:05:18 wesommer
27 * Version used for userreg tests.
29 * Revision 1.2 87/08/22 18:39:45 wesommer
30 * User registration server.
32 * Revision 1.1 87/07/31 15:48:13 wesommer
38 static char *rcsid_reg_svr_c = "$Header$";
42 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <netinet/in.h>
51 #include "ureg_proto.h"
53 #include "admin_server.h"
54 #include "admin_err.h"
58 extern char *strdup();
59 extern char *malloc();
60 extern int krb_err_base;
61 extern char admin_errmsg[];
74 static char retval[BUFSIZ];
78 struct sockaddr_in sin;
95 sp = getservbyname("sms_ureg", "udp");
97 fprintf(stderr, "Unknown service sms_ureg/udp\n");
100 s = socket(AF_INET, SOCK_DGRAM, 0);
105 bzero((char *)&sin, sizeof(sin));
107 sin.sin_family = AF_INET;
108 sin.sin_port = sp->s_port;
109 sin.sin_addr.s_addr = INADDR_ANY;
111 if (bind(s, &sin, sizeof(sin)) < 0) {
116 status = sms_connect();
118 com_err("reg_svr", status, " on connect");
123 com_err("reg_svr", status, " on auth");
128 com_err("reg_svr", 0, "Ready for next request");
129 addrlen = sizeof(sin);
130 bzero(retval, BUFSIZ);
131 len = recvfrom(s, buf, BUFSIZ, 0, &sin, &addrlen);
134 if (errno == EINTR) continue;
138 /* Parse a request packet */
139 status = parse_pkt(buf, len, &seqno, &message);
142 format_pkt(buf, &len, seqno, status, (char *)NULL);
143 (void) sendto(s, buf, len, 0, &sin, addrlen);
147 switch((int)message.request) {
148 case UREG_VERIFY_USER:
149 status = verify_user(&message);
151 case UREG_RESERVE_LOGIN:
152 status = reserve_user(&message);
154 case UREG_SET_PASSWORD:
155 status = set_password(&message);
159 status = UREG_UNKNOWN_REQUEST;
163 format_pkt(buf, &len, seqno, status, retval);
165 sendto(s, buf, len, 0, &sin, addrlen);
176 #define min(a,b) ((a)>(b)?(b):(a))
178 int validate_idno(message, db_mit_id, first, last)
185 static char decrypt[BUFSIZ];
187 static char hashid[14];
188 char idnumber[BUFSIZ];
195 string_to_key(db_mit_id, key);
196 key_sched(key, sched);
197 pcbc_encrypt(message->sealed, decrypt, message->sealed_len, sched, key, 0);
199 (void) strncpy(idnumber, decrypt, message->sealed_len);
200 temp = decrypt + strlen(idnumber) + 1;
201 len = message->sealed_len - (temp - decrypt);
203 (void) strncpy(hashid, temp, min(len, 14));
204 temp += strlen(hashid) + 1;
205 len = message->sealed_len - (temp - decrypt);
207 if (strcmp(hashid, db_mit_id)) return 1;
208 encrypt_mitid(recrypt, idnumber, first, last);
209 if (strcmp(recrypt, db_mit_id)) return 1;
217 static int status_in_db;
219 vfy_callbk(argc, argv, p_message)
220 int argc; /* Should sanity check this.. */
224 struct msg *message = (struct msg *)p_message;
226 char *firstname, *lastname;
229 if (got_one) return 0;
236 status = validate_idno(message, db_mit_id, firstname, lastname);
237 if (status) return 0; /* Nope; decryption failed */
239 status_in_db = atoi(argv[7]);
240 reg_status = status_in_db;
242 if (status_in_db != 0) {
243 (void) strcpy(retval, argv[0]);
245 user_id = atoi(argv[1]);
250 encrypt_mitid(buf, idnumber, first, last)
251 char *buf, *idnumber, *first, *last;
254 extern char *crypt();
256 #define _tolower(c) ((c)|0x60)
258 salt[0] = _tolower(last[0]);
259 salt[1] = _tolower(first[0]);
262 (void) strcpy(buf, crypt(&idnumber[2], salt));
265 int verify_user(message)
272 com_err("reg_svr", 0, " verify_user %s %s\n",
273 message->first, message->last);
274 argv[0] = "get_user_by_first_and_last";
275 argv[1] = message->first;
276 argv[2] = message->last;
279 status = sms_query_internal(3, argv, vfy_callbk, (char *)message);
281 if (status == SMS_NO_MATCH) status = UREG_USER_NOT_FOUND;
282 if (!got_one && !status)
283 status = UREG_USER_NOT_FOUND;
285 if (status != 0) goto punt;
287 if (reg_status == 1) status = UREG_ALREADY_REGISTERED;
288 if (reg_status == 2) status = UREG_NO_PASSWD_YET;
294 reserve_user(message)
303 com_err("reg_svr", 0, " reserve_user %s %s\n",
304 message->first, message->last);
306 argv[0] = "gufl"; /* get_user_by_first_and_last */
307 argv[1] = message->first;
308 argv[2] = message->last;
311 status = sms_query_internal(3, argv, vfy_callbk, (char *)message);
313 if (status == SMS_NO_MATCH) status = UREG_USER_NOT_FOUND;
314 if (!got_one && !status)
315 status = UREG_USER_NOT_FOUND;
317 if (status != 0) goto punt;
318 if (reg_status != 0) {
319 status = UREG_ALREADY_REGISTERED;
323 * He's made it past this phase already.
325 if (status_in_db == 2) {
330 for (i = 0; i < reg_misc_len && reg_misc[i]; i++) {
331 if (!islower(reg_misc[i]) && !isdigit(reg_misc[i]) &&
332 reg_misc[i] != '_' && reg_misc[i] != '.') {
333 status = UREG_INVALID_UNAME;
337 if (i < 3 || i > 8) {
338 status = UREG_INVALID_UNAME;
343 /* Send request to kerberos admin_server for login name */
345 status = get_svc_in_tkt("register", "sms", "ATHENA.MIT.EDU",
346 "changepw", "kerberos",
349 status += krb_err_base;
353 /* send set password request to kerberos admin_server */
354 (void) sprintf(uid_buf, "%013d", user_id); /* 13 chars of placebo */
355 /* for backwards-compat. */
357 status = admin_call(ADMIN_ADD_NEW_KEY_ATTR, login, "",
361 if (status == ADMIN_SERVER_ERROR) {
362 printf("Server error: %s\n", admin_errmsg);
364 if (strcmp(admin_errmsg,
365 "Principal already in kerberos database.") ==0)
366 status = UREG_LOGIN_USED;
375 status = set_login(login, mit_id);
379 com_err("set_login", status, 0);
382 /* choose post office */
384 status = choose_pobox(login);
386 com_err("choose_pobox", status, 0);
391 status = create_group(login);
392 if (status == SMS_LIST) status = UREG_LOGIN_USED;
395 com_err("create_group", status, 0);
398 /* set quota entry, create filsys */
400 status = alloc_filsys(login, SMS_FS_STUDENT, 0, 0);
401 if (status == SMS_FILESYS_EXISTS) status = UREG_LOGIN_USED;
403 com_err("alloc_filsys", status, 0);
406 /* set filsys and status in SMS database */
408 status = set_status_filsys(reg_misc, mit_id);
410 com_err("set_filsys", status, 0);
416 com_err("reg_svr", status, " returned from reserve_user");
420 set_password(message)
427 com_err("reg_svr", 0, " set_password %s %s\n",
428 message->first, message->last);
430 /* validate that user is who he claims to be */
432 argv[0] = "get_user_by_first_and_last";
433 argv[1] = message->first;
434 argv[2] = message->last;
437 status = sms_query_internal(3, argv, vfy_callbk, (char *)message);
439 if (status == SMS_NO_MATCH) status = UREG_USER_NOT_FOUND;
440 if (!got_one && !status)
441 status = UREG_USER_NOT_FOUND;
443 if (status != 0) goto punt;
445 /* validate that state is equal to '2' (login, but no password) */
447 if (reg_status != 2) {
448 status = UREG_NO_LOGIN_YET;
453 status = get_svc_in_tkt("register", "sms", "ATHENA.MIT.EDU",
454 "changepw", "kerberos",
457 status += krb_err_base;
461 (void) sprintf(uid_buf, "%013d", user_id); /* 13 chars of placebo */
462 /* for backwards-compat. */
463 /* send set password request to kerberos admin_server */
464 status = admin_call(ADMIN_ADD_NEW_KEY_ATTR, retval, "",
467 if (status) goto punt;
470 status = set_final_status(retval, mit_id);
472 /* reflect reply to client */
478 parse_pkt(buf, len, seqnop, messagep)
482 struct msg *messagep;
484 if (len < 4) return UREG_BROKEN_PACKET;
485 bcopy(buf, (char *)&messagep->version, sizeof(long));
486 messagep->version = ntohl(messagep->version);
487 if (messagep->version != 1) return UREG_WRONG_VERSION;
492 if (len < 4) return UREG_BROKEN_PACKET;
493 bcopy(buf, (char *)seqnop, sizeof(long));
498 if (len < 4) return UREG_BROKEN_PACKET;
499 bcopy(buf, (char *)(&messagep->request), sizeof(long));
500 messagep->request = ntohl(messagep->request);
504 messagep->first = buf;
506 for (; *buf && len > 0; --len, ++buf) continue;
507 if (len <= 0) return UREG_BROKEN_PACKET;
511 messagep->last = buf;
513 for (; *buf && len > 0; --len, ++buf) continue;
514 if (len <= 0) return UREG_BROKEN_PACKET;
518 if (len <= 0) return UREG_BROKEN_PACKET;
520 messagep->sealed = buf;
521 messagep->sealed_len = len;
526 format_pkt(buf, lenp, seqno, status, message)
533 u_long vers = htonl((u_long)1);
534 status = htonl((u_long)status);
536 bcopy((char *)&vers, buf, sizeof(long));
537 bcopy((char *)&seqno, buf+sizeof(long), sizeof(long));
538 bcopy((char *)&status, buf+ 2*sizeof(long), sizeof(long));
539 *lenp = sizeof(long) * 3;
540 (void) strcpy(buf+3*sizeof(long), message);
541 (*lenp) += strlen(message);
544 store_user(argc, argv, argp)
549 char **retv = (char **) argp;
552 for (i = 0; i < argc; i++) {
557 retv[i] = strdup(argv[i]);
564 * Set login name of user with "idnumber" to be "username"
567 set_login(username, idnumber)
575 argv[0] = "get_user_by_mitid";
578 for (i=0; i<13; i++) {
582 status = sms_query_internal(2, argv, store_user, (char *)(retv+1));
583 if (status) return status;
587 if (retv[4]) free(retv[4]);
588 retv[4] = "null"; /* No such filesystem */
590 printf("Update_user(%s, %s)\n", retv[0], retv[1]);
592 status = sms_query("update_user", 12, retv, abort, 0);
596 for (i=1; i<12; i++) {
597 if (retv[i]) free(retv[i]);
605 * Set the status and filsys of user with username "uname" and filesys filsys.
608 set_status_filsys(username, idnumber)
616 argv[0] = "get_user_by_mitid";
619 for (i=0; i<13; i++) {
623 status = sms_query_internal(2, argv, store_user, (char *)(retv+1));
624 if (status) return status;
634 printf("Update_user(%s, %s)\n", retv[0], retv[1]);
636 status = sms_query("update_user", 12, retv, abort, 0);
639 for (i=1; i<12; i++) {
640 if (retv[i]) free(retv[i]);
646 * Set the status and filsys of user with username "uname" and filesys filsys.
649 set_final_status(username, idnumber)
657 argv[0] = "get_user_by_mitid";
660 for (i=0; i<13; i++) {
664 status = sms_query_internal(2, argv, store_user, (char *)(retv+1));
665 if (status) return status;
672 printf("Update_user(%s, %s)\n", retv[0], retv[1]);
674 status = sms_query("update_user", 12, retv, abort, 0);
676 for (i=1; i<12; i++) {
677 if (retv[i]) free(retv[i]);
687 static char *cr[] = {
694 return sms_query_internal(2, cr, abort, 0);
700 * c-continued-statement-offset: 4
702 * c-argdecl-indent: 4