]> andersk Git - moira.git/blob - reg_svr/reg_svr.c
Allow numbers, _, and . as legal characters in the username.
[moira.git] / reg_svr / reg_svr.c
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1987 by the Massachusetts Institute of Technology
7  *
8  *      Server for user registration with SMS and Kerberos.
9  *
10  *      This program is a client of the SMS server and the Kerberos
11  *      admin_server, and is a server for the userreg program.
12  * 
13  *      $Log$
14  *      Revision 1.6  1987-09-21 15:19:11  wesommer
15  *      Allow numbers, _, and . as legal characters in the username.
16  *
17  * Revision 1.5  87/09/10  22:18:32  wesommer
18  * Clean up output format.
19  * 
20  * Revision 1.4  87/09/04  23:33:19  wesommer
21  * Deleted test scaffolding (second oops.)
22  * 
23  * Revision 1.3  87/09/03  03:05:18  wesommer
24  * Version used for userreg tests.
25  * 
26  * Revision 1.2  87/08/22  18:39:45  wesommer
27  * User registration server.
28  * 
29  * Revision 1.1  87/07/31  15:48:13  wesommer
30  * Initial revision
31  * 
32  */
33
34 #ifndef lint
35 static char *rcsid_reg_svr_c = "$Header$";
36 #endif lint
37
38 #include <stdio.h>
39 #include <sys/types.h>
40 #include <sys/file.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <netdb.h>
44 #include <des.h>
45 #include <errno.h>
46 #include <ctype.h>
47 #include "ureg_err.h"
48 #include "ureg_proto.h"
49 #include "../../include/sms.h"
50 #include "admin_server.h"
51 #include "admin_err.h" 
52 #include <strings.h>
53
54 extern void abort();
55 extern char *strdup();
56 extern char *malloc();
57 extern int krb_err_base;
58 extern char admin_errmsg[];
59
60 long now;
61                        
62 struct msg {
63     u_long version;
64     u_long request;
65     char *first;
66     char *last;
67     char *sealed;
68     int sealed_len;
69 };
70
71 static char retval[BUFSIZ];
72
73 main()
74 {
75     struct sockaddr_in sin;
76     struct servent *sp;
77     int s;
78     int status;
79     int addrlen, len;
80     char buf[BUFSIZ];
81     extern int errno;
82     u_long seqno;
83     struct msg message;
84     extern char *whoami;
85     int i;
86     
87     setlinebuf(stderr);
88     whoami = "reg_svr";
89     
90     init_ureg_err_tbl();
91
92     sp = getservbyname("sms_ureg", "udp");
93     if (sp == NULL) {
94         fprintf(stderr, "Unknown service sms_ureg/udp\n");
95         exit(1);
96     }
97     s = socket(AF_INET, SOCK_DGRAM, 0);
98     if (s < 0) {
99         perror("socket");
100         exit(1);
101     }
102     bzero((char *)&sin, sizeof(sin));
103
104     sin.sin_family = AF_INET;
105     sin.sin_port = sp->s_port;
106     sin.sin_addr.s_addr = INADDR_ANY;
107
108     if (bind(s, &sin, sizeof(sin)) < 0) {
109         perror("bind");
110         exit(1);
111     }
112
113     status = sms_connect();
114     if (status != 0) {
115         com_err("reg_svr", status, " on connect");
116         exit(1);
117     }
118     status = sms_auth();
119     if (status != 0) {
120         com_err("reg_svr", status, " on auth");
121         exit(1);
122     }
123     
124     for (;;) {
125         com_err("reg_svr", 0, "Ready for next request");
126         addrlen = sizeof(sin);
127         bzero(retval, BUFSIZ);
128         len = recvfrom(s, buf, BUFSIZ, 0, &sin, &addrlen);
129         if (len < 0) {
130             perror("recvfrom");
131             if (errno == EINTR) continue;
132             
133             exit(1);
134         }
135         /* Parse a request packet */
136         status = parse_pkt(buf, len, &seqno, &message);
137         if (status != 0) {
138             len = BUFSIZ;
139             format_pkt(buf, &len, seqno, status, (char *)NULL);
140             (void) sendto(s, buf, len, 0, &sin, addrlen);
141             continue;
142         }
143         /* do action */
144         switch((int)message.request) {
145         case UREG_VERIFY_USER:
146             status = verify_user(&message);
147             break;
148         case UREG_RESERVE_LOGIN:
149             status = reserve_user(&message);
150             break;
151         case UREG_SET_PASSWORD:
152             status = set_password(&message);
153             break;
154             
155         default:
156             status = UREG_UNKNOWN_REQUEST;
157             break;
158         }
159         len = BUFSIZ;
160         format_pkt(buf, &len, seqno, status, retval);
161         
162         sendto(s, buf, len, 0, &sin, addrlen);
163     }
164 }
165
166 int got_one;
167 int reg_status;
168 char *mit_id;
169 char *reg_misc;
170 int reg_misc_len;
171 int user_id;
172
173 #define min(a,b) ((a)>(b)?(b):(a))
174     
175 int validate_idno(message, db_mit_id, first, last)
176     struct msg *message;
177     char *db_mit_id;
178     char *first, *last;
179 {
180     C_Block key;
181     Key_schedule sched;
182     static char decrypt[BUFSIZ];
183     char recrypt[14];
184     static char hashid[14];
185     char idnumber[BUFSIZ];
186     char *temp;
187     int len;
188
189     int i;
190     mit_id = 0;
191     
192     string_to_key(db_mit_id, key);
193     key_sched(key, sched);
194     pcbc_encrypt(message->sealed, decrypt, message->sealed_len, sched, key, 0);
195
196     (void) strncpy(idnumber, decrypt, message->sealed_len);
197     temp = decrypt + strlen(idnumber) + 1;
198     len = message->sealed_len - (temp - decrypt);
199     
200     (void) strncpy(hashid, temp, min(len, 14));
201     temp += strlen(hashid) + 1;
202     len = message->sealed_len - (temp - decrypt);
203
204     if (strcmp(hashid, db_mit_id)) return 1;
205     encrypt_mitid(recrypt, idnumber, first, last);
206     if (strcmp(recrypt, db_mit_id)) return 1;
207
208     reg_misc = temp;
209     reg_misc_len = len;
210     mit_id = hashid;
211     return 0;
212 }
213
214 static int status_in_db;
215
216 vfy_callbk(argc, argv, p_message)
217     int argc;                   /* Should sanity check this.. */
218     char **argv;
219     char *p_message;
220 {
221     struct msg *message = (struct msg *)p_message;
222     char *db_mit_id;
223     char *firstname, *lastname;
224     int status;
225     
226     if (got_one) return 0;
227     reg_status = 0;
228     
229     db_mit_id = argv[8];
230     firstname = argv[5];
231     lastname = argv[4];
232
233     status = validate_idno(message, db_mit_id, firstname, lastname);
234     if (status) return 0; /* Nope; decryption failed */
235
236     status_in_db = atoi(argv[7]);
237     reg_status = status_in_db;    
238
239     if (status_in_db != 0) {
240         (void) strcpy(retval, argv[0]);
241     }
242     user_id = atoi(argv[1]);
243     got_one = 1;
244     return 0;
245 }    
246
247 encrypt_mitid(buf, idnumber, first, last)
248     char *buf, *idnumber, *first, *last;
249 {
250     char salt[3];
251     extern char *crypt();
252     
253 #define _tolower(c) ((c)|0x60)
254
255     salt[0] = _tolower(last[0]);
256     salt[1] = _tolower(first[0]);
257     salt[2] = 0;
258     
259     (void) strcpy(buf, crypt(&idnumber[2], salt));
260 }
261
262 int verify_user(message)
263     struct msg *message;
264
265 {
266     char *argv[3];
267     int status;
268     
269     com_err("reg_svr", 0, " verify_user %s %s\n",
270             message->first, message->last);
271     argv[0] = "get_user_by_first_and_last";
272     argv[1] = message->first;
273     argv[2] = message->last;
274     got_one = 0;
275     
276     status = sms_query_internal(3, argv, vfy_callbk, (char *)message);
277     
278     if (status == SMS_NO_MATCH) status = UREG_USER_NOT_FOUND;
279     if (!got_one && !status)
280         status = UREG_USER_NOT_FOUND;
281     
282     if (status != 0) goto punt;
283
284     if (reg_status == 1) status = UREG_ALREADY_REGISTERED;
285     if (reg_status == 2) status = UREG_NO_PASSWD_YET;
286     
287 punt:
288     return status;
289 }
290
291 reserve_user(message)
292     struct msg *message;
293 {
294     char *argv[3];
295     int status;
296     int i;
297     char *login;
298     char uid_buf[20];
299     
300     com_err("reg_svr", 0, " reserve_user %s %s\n",
301             message->first, message->last);
302
303     argv[0] = "gufl";           /* get_user_by_first_and_last */
304     argv[1] = message->first;
305     argv[2] = message->last;
306     got_one = 0;
307     
308     status = sms_query_internal(3, argv, vfy_callbk, (char *)message);
309
310     if (status == SMS_NO_MATCH) status = UREG_USER_NOT_FOUND;
311     if (!got_one && !status)
312         status = UREG_USER_NOT_FOUND;
313
314     if (status != 0) goto punt;
315     if (reg_status != 0) {
316         status = UREG_ALREADY_REGISTERED;
317         goto punt;
318     }
319     /*
320      * He's made it past this phase already.
321      */
322     if (status_in_db == 2) {
323         status = 0;
324         goto punt;
325     }
326
327     for (i = 0; i < reg_misc_len && reg_misc[i]; i++) {
328         if (!islower(reg_misc[i]) && !isdigit(reg_misc[i]) &&
329             reg_misc[i] != '_' && reg_misc[i] != '.') {
330             status = UREG_INVALID_UNAME;
331             goto punt;
332         }
333     }
334     if (i < 3 || i > 8) {
335         status = UREG_INVALID_UNAME;
336         goto punt;
337     }
338     login = reg_misc;
339     
340     /* Send request to kerberos admin_server for login name */
341     /* get keys */
342     status = get_svc_in_tkt("register", "sms", "ATHENA.MIT.EDU",
343                             "changepw", "kerberos",
344                             1, "/etc/srvtab");
345     if (status) {
346             status += krb_err_base;
347             goto punt;
348     }
349     
350     /* send set password request to kerberos admin_server */
351     (void) sprintf(uid_buf, "%013d", user_id); /* 13 chars of placebo */
352                                                /* for backwards-compat. */
353     
354     status = admin_call(ADMIN_ADD_NEW_KEY_ATTR, login, "", 
355                         "", uid_buf);
356
357     if (status) {
358             if (status == ADMIN_SERVER_ERROR) {
359                     printf("Server error: %s\n", admin_errmsg);
360                     
361                     if (strcmp(admin_errmsg,
362                                 "Principal already in kerberos database.") ==0)
363                             status = UREG_LOGIN_USED;
364             }
365             goto punt;
366     }
367
368     dest_tkt();
369     /* If valid: */
370     
371     /* Set login name */
372     status = set_login(login, mit_id);
373
374     
375     if (status) {
376         com_err("set_login", status, 0);
377         goto punt;
378     }
379     /* choose post office */
380     
381     status = choose_pobox(login);
382     if (status) {
383         com_err("choose_pobox", status, 0);
384         goto punt;
385     }
386     /* create group */
387     
388     status = create_group(login);
389     if (status == SMS_LIST) status = UREG_LOGIN_USED;
390     
391     if (status) {
392         com_err("create_group", status, 0);
393         goto punt;
394     }
395     /* set quota entry, create filsys */
396     
397     status = alloc_filsys(login, SMS_FS_STUDENT, 0, 0);
398     if (status == SMS_FILESYS_EXISTS) status = UREG_LOGIN_USED;
399     if (status) {
400         com_err("alloc_filsys", status, 0);
401         goto punt;
402     }
403     /* set filsys and status in SMS database */
404     
405     status = set_status_filsys(reg_misc, mit_id);
406     if (status) {
407         com_err("set_filsys", status, 0);
408         goto punt;
409     }
410 punt:
411     dest_tkt();
412
413     com_err("reg_svr", status, " returned from reserve_user");
414     return status;
415 }
416
417 set_password(message)
418     struct msg *message;
419 {
420     char *argv[3];
421     int status;
422     char uid_buf[10];
423     
424     com_err("reg_svr", 0, " set_password %s %s\n",
425             message->first, message->last);
426
427     /* validate that user is who he claims to be */
428
429     argv[0] = "get_user_by_first_and_last";
430     argv[1] = message->first;
431     argv[2] = message->last;
432     got_one = 0;
433     
434     status = sms_query_internal(3, argv, vfy_callbk, (char *)message);
435     
436     if (status == SMS_NO_MATCH) status = UREG_USER_NOT_FOUND;
437     if (!got_one && !status)
438         status = UREG_USER_NOT_FOUND;
439     
440     if (status != 0) goto punt;
441
442     /* validate that state is equal to '2' (login, but no password) */
443
444     if (reg_status != 2) {
445         status = UREG_NO_LOGIN_YET;
446         goto punt;
447     }
448
449     /* get keys */
450     status = get_svc_in_tkt("register", "sms", "ATHENA.MIT.EDU",
451                             "changepw", "kerberos",
452                             1, "/etc/srvtab");
453     if (status) {
454             status += krb_err_base;
455             goto punt;
456     }
457
458     (void) sprintf(uid_buf, "%013d", user_id); /* 13 chars of placebo */
459                                                /* for backwards-compat. */
460     /* send set password request to kerberos admin_server */
461     status = admin_call(ADMIN_ADD_NEW_KEY_ATTR, retval, "", 
462                         reg_misc, uid_buf);
463
464     if (status) goto punt;
465     dest_tkt();
466     
467     status = set_final_status(retval, mit_id);
468
469     /* reflect reply to client */
470 punt:
471     dest_tkt();
472     return status;
473 }
474
475 parse_pkt(buf, len, seqnop, messagep)
476     char *buf;
477     int len;
478     u_long *seqnop;
479     struct msg *messagep;
480 {
481     if (len < 4) return UREG_BROKEN_PACKET;
482     bcopy(buf, (char *)&messagep->version, sizeof(long));
483     messagep->version = ntohl(messagep->version);
484     if (messagep->version != 1) return UREG_WRONG_VERSION;
485     
486     buf += 4;
487     len -= 4;
488
489     if (len < 4) return UREG_BROKEN_PACKET;
490     bcopy(buf, (char *)seqnop, sizeof(long));
491
492     buf += 4;
493     len -= 4;
494     
495     if (len < 4) return UREG_BROKEN_PACKET;
496     bcopy(buf, (char *)(&messagep->request), sizeof(long));
497     messagep->request = ntohl(messagep->request);
498     buf += 4;
499     len -= 4;
500     
501     messagep->first = buf;
502
503     for (; *buf && len > 0; --len, ++buf) continue;
504     if (len <= 0) return UREG_BROKEN_PACKET;
505
506     buf++, len--;
507
508     messagep->last = buf;
509
510     for (; *buf && len > 0; --len, ++buf) continue;
511     if (len <= 0) return UREG_BROKEN_PACKET;
512     
513     buf++, len--;
514
515     if (len <= 0) return UREG_BROKEN_PACKET;
516     
517     messagep->sealed = buf;
518     messagep->sealed_len = len;
519     
520     return 0;
521 }
522
523 format_pkt(buf, lenp, seqno, status, message)
524     char *buf;
525     int *lenp;
526     u_long seqno;
527     int status;
528     char *message;
529 {
530     u_long vers = htonl((u_long)1);
531     status = htonl((u_long)status);
532     
533     bcopy((char *)&vers, buf, sizeof(long));
534     bcopy((char *)&seqno, buf+sizeof(long), sizeof(long));
535     bcopy((char *)&status, buf+ 2*sizeof(long), sizeof(long));
536     *lenp = sizeof(long) * 3;
537     (void) strcpy(buf+3*sizeof(long), message);
538     (*lenp) += strlen(message);
539 }
540
541 store_user(argc, argv, argp)
542     int argc;
543     char **argv;
544     char *argp;
545 {
546     char **retv = (char **) argp;
547     int i;
548     
549     for (i = 0; i < argc; i++) {
550         if (retv[i]) {
551             free(retv[i]);
552             retv[i]=0;
553         }
554         retv[i] = strdup(argv[i]);
555     }
556     return 0;
557 }
558     
559
560 /*
561  * Set login name of user with "idnumber" to be "username"
562  */
563
564 set_login(username, idnumber)
565     char *username;
566     char *idnumber;
567 {
568     char *argv[2];
569     int status, i;
570     char *retv[13];
571     
572     argv[0] = "get_user_by_mitid";
573     argv[1] = idnumber;
574
575     for (i=0; i<13; i++) {
576         retv[i] = 0;
577     }
578
579     status = sms_query_internal(2, argv, store_user, (char *)(retv+1));
580     if (status) return status;
581
582     retv[0] = retv[1];
583     retv[1] = username;
584     if (retv[4]) free(retv[4]);
585     retv[4] = "null";           /* No such filesystem */
586     
587     printf("Update_user(%s, %s)\n", retv[0], retv[1]);
588     
589     status = sms_query("update_user", 12, retv, abort, 0);
590     retv[1] = 0;
591     retv[4] = 0;
592     
593     for (i=1; i<12; i++) {
594         if (retv[i]) free(retv[i]);
595         retv[i] = 0;
596     }
597     
598     return status;
599 }    
600
601 /*
602  * Set the status and filsys of user with username "uname" and filesys filsys.
603  */
604
605 set_status_filsys(username, idnumber)
606     char *username;
607     char *idnumber;
608 {
609     char *argv[2];
610     int status, i;
611     char *retv[13];
612     
613     argv[0] = "get_user_by_mitid";
614     argv[1] = idnumber;
615
616     for (i=0; i<13; i++) {
617         retv[i] = 0;
618     }
619
620     status = sms_query_internal(2, argv, store_user, (char *)(retv+1));
621     if (status) return status;
622
623     retv[0] = retv[1];
624
625     free(retv[4]);
626     retv[4] = username;
627
628     free(retv[8]);
629     retv[8] = "2";
630     
631     printf("Update_user(%s, %s)\n", retv[0], retv[1]);
632     
633     status = sms_query("update_user", 12, retv, abort, 0);
634     retv[4] = 0;
635     retv[8] = 0;
636     for (i=1; i<12; i++) {
637         if (retv[i]) free(retv[i]);
638         retv[i] = 0;
639     }
640     return status;
641 }    
642 /*
643  * Set the status and filsys of user with username "uname" and filesys filsys.
644  */
645
646 set_final_status(username, idnumber)
647     char *username;
648     char *idnumber;
649 {
650     char *argv[2];
651     int status, i;
652     char *retv[13];
653     
654     argv[0] = "get_user_by_mitid";
655     argv[1] = idnumber;
656
657     for (i=0; i<13; i++) {
658         retv[i] = 0;
659     }
660
661     status = sms_query_internal(2, argv, store_user, (char *)(retv+1));
662     if (status) return status;
663
664     retv[0] = retv[1];
665
666     free(retv[8]);
667     retv[8] = "1";
668     
669     printf("Update_user(%s, %s)\n", retv[0], retv[1]);
670     
671     status = sms_query("update_user", 12, retv, abort, 0);
672     retv[8] = 0;
673     for (i=1; i<12; i++) {
674         if (retv[i]) free(retv[i]);
675         retv[i] = 0;
676     }
677     return status;
678 }    
679
680 create_group(login)
681     char *login;
682 {
683     int status;
684     static char *cr[] = {
685         "add_user_group",
686         0,
687     };
688     
689     cr[1] = login;
690     
691     return sms_query_internal(2, cr, abort, 0);
692 }    
693 /*
694  * Local Variables:
695  * mode: c
696  * c-indent-level: 4
697  * c-continued-statement-offset: 4
698  * c-brace-offset: -4
699  * c-argdecl-indent: 4
700  * c-label-offset: -4
701  * End:
702  */
703
This page took 0.134044 seconds and 5 git commands to generate.