]> andersk Git - moira.git/blob - reg_svr/reg_svr.c
c531f31b8ce2f0a1ff9f40eff09644ed2f5128e9
[moira.git] / reg_svr / reg_svr.c
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1987, 1988 by the Massachusetts Institute of Technology
7  *      For copying and distribution information, please see the file
8  *      <mit-copyright.h>.
9  *
10  *      Server for user registration with Moira and Kerberos.
11  *
12  *      This program is a client of the Kerberos admin_server and a
13  *      server for the userreg program.  It is not a client of the
14  *      Moira server as it is linked with libmoiraglue which bypasses
15  *      the network protocol.
16  */
17
18 #ifndef lint
19 static char *rcsid_reg_svr_c = "$Header$";
20 #endif lint
21
22 #include <mit-copyright.h>
23 #include <stdio.h>
24 #include <strings.h>
25 #include <ctype.h>
26 #include <sys/time.h>
27 #include <sys/types.h>
28 #include <sys/file.h>
29 #include <krb.h>
30 #include <des.h>
31 #include <kadm.h>
32 #include <kadm_err.h>
33 #include <krb_err.h>
34 #include <errno.h>
35 #include "moira.h"
36 #include "moira_site.h"
37 #include "reg_svr.h"
38
39 extern char admin_errmsg[];
40
41 void reg_com_err_hook();
42
43 main(argc,argv)
44   int argc;
45   char *argv[];
46 {
47     struct msg message;         /* Storage for parsed packet */
48     int status = SUCCESS;       /* Error status */
49     char retval[BUFSIZ];        /* Buffer to hold return message for client */
50     
51     void req_initialize();      /* Initialize request layer */
52     void get_request();         /* Get a request */
53     void report();              /* Respond to a request */
54
55     /* Initialize */
56     whoami = argv[0];
57     
58     /* Error messages sent one line at a time */
59     setlinebuf(stderr);
60     setlinebuf(stdout);
61     set_com_err_hook(reg_com_err_hook);
62     
63     /* Initialize com_err error tables */
64     init_ureg_err_tbl();
65     init_krb_err_tbl();
66     init_kadm_err_tbl();
67     
68     /* Use com_err or output to stderr for all log messages. */    
69 #ifdef DEBUG
70     com_err(whoami, 0, "*** Debugging messages enabled. ***");
71 #endif DEBUG
72     
73     /* Set the name of our kerberos ticket file */
74     krb_set_tkt_string("/tmp/tkt_ureg");
75
76     /* Connect to the Moira server */
77     if ((status = mr_connect(MOIRA_SERVER)) != MR_SUCCESS) 
78     {
79         com_err(whoami, status, " on mr_connect");
80         exit(1);
81     }
82     
83     /* Authorize, telling the server who you are */
84     if ((status = mr_auth(whoami)) != MR_SUCCESS) 
85     {
86         com_err(whoami, status, " on mr_auth");
87         exit(1);
88     }
89     
90     journal = fopen(REGJOURNAL, "a");
91     if (journal == NULL) {
92         com_err(whoami, errno, " while opening journal file");
93         exit(1);
94     }
95     
96     /* Allow request layer to initialize */
97     req_initialize();
98     
99     /* Sit around waiting for requests from the client. */
100     for (;;) 
101     {
102         get_request(&message);
103         
104         switch((int)message.request) 
105         {
106           case UREG_VERIFY_USER:
107             status = verify_user(&message,retval);
108             break;
109           case UREG_RESERVE_LOGIN:
110             status = reserve_user(&message,retval);
111             break;
112           case UREG_SET_PASSWORD:
113           case UREG_GET_KRB:
114             status = set_password(&message,retval);
115             break;
116           case UREG_SET_IDENT:
117             status = set_identity(&message,retval);
118             break;
119           case UREG_GET_SECURE:
120             status = get_secure(&message,retval);
121             break;
122           case UREG_SET_SECURE:
123             status = set_secure(&message,retval);
124             break;
125           default:
126             status = UREG_UNKNOWN_REQUEST;
127             critical_alert(FAIL_INST,"Unknown request %d from userreg.",
128                            message.request);
129             break;
130         }
131         
132         /* Report what happened to client */
133         report(status, retval);
134     }
135 }
136
137 int parse_encrypted(message,data)
138   struct msg *message;          /* Formatted packet */
139   struct db_data *data;         /* Data from the Moira database */
140 /* This routine makes sure that the ID from the database matches
141    the ID sent accross in the packet.  The information in the packet
142    was created in the following way:
143
144    The database used to contain encrypted IDs.  Now we don't encrypt
145    them in the database, although there are still some encrypted IDs
146    there.
147
148    The plain text ID number was encrypted via EncryptID() resulting
149    in the form that would appear in the Moira database.  This is
150    concatinated to the plain text ID so that the ID string contains plain
151    text ID followed by a null followed by the encrypted ID.  Other
152    information such as the username or password is appended.  The whole
153    thing is then DES encrypted using the encrypted ID as the source of
154    the key.
155
156    This routine tries each ID in the database that belongs
157    to someone with this user's first and last name and tries to 
158    decrypt the packet with this information.  If it succeeds, it returns 
159    zero and initializes all the fields of the formatted packet structure
160    that depend on the encrypted information. */
161 {
162     des_cblock key;             /* The key for DES en/decryption */
163     des_key_schedule sched;     /* En/decryption schedule */
164     static char decrypt[BUFSIZ];   /* Buffer to hold decrypted information */
165     long decrypt_len;           /* Length of decypted ID information */
166     char recrypt[14];           /* Buffer to hold re-encrypted information */
167     static char hashid[14];     /* Buffer to hold one-way encrypted ID */
168     char idnumber[BUFSIZ];      /* Buffer to hold plain-text ID */
169     char *temp;                 /* A temporary string pointer */
170     int len;                    /* Keeps track of length left in packet */
171     int status = SUCCESS;       /* Error status */
172     
173 #ifdef DEBUG
174     com_err(whoami, 0, "Entering parse_encrypted");
175 #endif
176
177     /* Make the decrypted information length the same as the encrypted
178        information length.  Both are integral multples of eight bytes 
179        because of the DES encryption routines. */
180     decrypt_len = (long)message->encrypted_len;
181     
182     /* Get key from the possibly one-way encrypted ID in the Moira database */
183     if (data->mit_id[0] >= '0' && data->mit_id[0] <= '9') {
184         char buf[32];
185
186         EncryptID(buf, data->mit_id, message->first, message->last);
187         des_string_to_key(buf, key);
188     } else
189       des_string_to_key(data->mit_id, key);
190
191     /* Get schedule from key */
192     des_key_sched(key, sched);
193     /* Decrypt information from packet using this key.  Since decrypt_len
194        is an integral multiple of eight bytes, it will probably be null-
195        padded. */
196     des_pcbc_encrypt(message->encrypted, decrypt, decrypt_len,
197                      sched, key, DES_DECRYPT);
198     
199     /* Extract the plain text and encrypted ID fields from the decrypted
200        packet information. */
201     /* Since the decrypted information starts with the plain-text ID
202        followed by a null, if the decryption worked, this will only 
203        copy the plain text part of the decrypted information.  It is
204        important that strncpy be used because if we are not using the
205        correct key, there is no guarantee that a null will occur
206        anywhere in the string. */
207     (void) strncpy(idnumber,decrypt,(int)decrypt_len);
208     /* Check that the idnumber of a mismatched decryption doesn't overflow
209      * the buffer.
210      */
211     if (strlen(idnumber) != 9) {
212 #ifdef DEBUG
213         com_err(whoami, 0, "idnumber wrong size, probable user mismatch\n");
214 #endif
215         return(FAILURE);
216     }
217     /* Point temp to the end of the plain text ID number. */
218     temp = decrypt + strlen(idnumber) + 1;
219     /* Find out how much more packet there is. */
220     len = message->encrypted_len - (temp - decrypt);
221     /* Copy the next CRYPT_LEN bytes of the decrypted information into 
222        hashid if there are CRYPT_LEN more bytes to copy.  There will be
223        if we have the right key. */
224     (void) strncpy(hashid, temp, min(len, CRYPT_LEN));
225     /* Point temp to the end of the encrypted ID field */
226     temp += strlen(hashid) + 1;
227     /* Find out how much more room there is. */
228     len = message->encrypted_len - (temp - decrypt);
229     
230     /* Now compare encrypted ID and clear text ID for a match. */
231     if (strcmp(hashid, data->mit_id) &&
232         strcmp(idnumber, data->mit_id))
233       status = FAILURE;
234     
235     if (status == SUCCESS)
236     {
237         /* We made it.  Now we can finish initializing message. */
238         /* Point leftover to whatever is left over! */
239         message->leftover = temp;
240         message->leftover_len = len;
241         /* Since we know we have the right user, fill in the information 
242            from the Moira database. */
243         message->db.reg_status = data->reg_status;
244         (void) strncpy(message->db.uid,data->uid, sizeof(message->db.uid));
245         (void) strncpy(message->db.mit_id,data->mit_id, 
246                        sizeof(message->db.mit_id));
247         (void) strncpy(message->db.login,data->login, sizeof(message->db.login));
248     }
249     
250 #ifdef DEBUG
251     if (status)
252         com_err(whoami, status, " in parse_encrypted");
253     else
254         com_err(whoami, status, "parse_encrypted succeeded");
255 #endif
256
257     return status;
258 }
259
260 int db_callproc(argc,argv,queue)
261   int argc;                     /* Number of arguments returned by Moira */
262   char *argv[];                 /* Arguments returned by Moira */
263   struct save_queue *queue;     /* Queue to save information in */
264 /* This function is called by mr_query after each tuple found.  It is
265    used by find_user to cache information about each user found.  */
266 {
267     struct db_data *data;       /* Structure to store the information in */
268     int status = SUCCESS;       /* Error status */
269     
270 #ifdef DEBUG
271     com_err(whoami, 0, "Entering db_callproc.");
272 #endif
273
274     if (argc != U_END)
275     {
276         critical_alert
277             (FAIL_INST,
278              "Wrong number of arguments returned from get_user_account_by_name.");
279         status = MR_ABORT;
280     }
281     else
282     {
283         /* extract the needed information from the results of the Moira query */
284         data = (struct db_data *)malloc(sizeof(struct db_data));
285         data->reg_status = atoi(argv[U_STATE]);
286         (void) strncpy(data->login,argv[U_NAME],sizeof(data->login));
287         (void) strncpy(data->mit_id,argv[U_MITID],sizeof(data->mit_id));
288         (void) strncpy(data->uid,argv[U_UID],sizeof(data->uid));
289 #ifdef DEBUG
290         fprintf(stderr,"Found in database:\n");
291         fprintf(stderr,"   Registration status: %d\n",data->reg_status);
292         fprintf(stderr,"   login: %s\n",data->login);
293         fprintf(stderr,"   MIT ID: %s\n",data->mit_id);
294         fprintf(stderr,"   uid: %s\n",data->uid);
295 #endif
296         sq_save_data(queue,data);
297     }
298
299     return status;
300 }
301     
302 int find_user(message)
303   struct msg *message;          /* Formatted packet structure */
304 /* This routine verifies that a user is allowed to register by finding
305    him/her in the Moira database.  It returns the status of the Moira
306    query that it calls. */
307 {
308 #define GUBN_ARGS 2             /* Arguements needed by get_user_by_name */
309     char *q_name;               /* Name of query */
310     int q_argc;                 /* Number of arguments for query */
311     char *q_argv[GUBN_ARGS];    /* Arguments to query */
312     int status = SUCCESS;       /* Query return status */
313
314     struct save_queue *queue;   /* Queue to hold Moira data */
315     struct db_data *data;       /* Structure for data for one tuple */
316     short verified = FALSE;     /* Have we verified the user? */
317
318     /* Zero the mit_id field in the formatted packet structure.  This
319        being zeroed means that no user was found. */
320     bzero(message->db.mit_id,sizeof(message->db.mit_id));
321     
322     if (status == SUCCESS)
323     {
324         /* Get ready to make an Moira query */
325         q_name = "get_user_account_by_name";
326         q_argc = GUBN_ARGS;     /* #defined in this routine */
327         q_argv[0] = message->first;
328         q_argv[1] = message->last;
329         
330         /* Create queue to hold information */
331         queue = sq_create();
332         
333         /* Do it */
334         status = mr_query(q_name,q_argc,q_argv,db_callproc,(char *)queue);
335         
336 #ifdef DEBUG
337         fprintf(stderr," %d returned by get_user_by_name\n",status);
338 #endif
339         
340         if (status == MR_SUCCESS) 
341         {
342             /* Traverse the list, freeing data as we go.  If sq_get_data()
343                returns zero if there is no more data on the queue. */
344             while (sq_get_data(queue,&data))
345             {
346                 if (!verified)
347                     /* parse_encrypted returns zero on success */
348                     verified = (parse_encrypted(message,data) == SUCCESS);
349                 free((char *)data);
350             }
351         }
352
353         /* Destroy the queue */
354         sq_destroy(queue);
355     }
356     
357 #ifdef DEBUG
358     fprintf(stderr,"Returned from find_user\n");
359     fprintf(stderr,"   MIT ID: %s\n", message->db.mit_id);
360     fprintf(stderr,"   Registration status: %d\n",message->db.reg_status);
361     fprintf(stderr,"   uid: %s\n",message->db.uid);
362     fprintf(stderr,"   login: %s\n",message->db.login);
363     fprintf(stderr,"   Status from query: %d\n",status);
364 #endif DEBGUG
365
366     return status;
367 }
368
369 int verify_user(message,retval)
370   struct msg *message;
371   char *retval;
372   /* This routine determines whether a user is in the databse and returns
373      his state so that other routines can figure out whether he is the 
374      correct state for various transactions. */
375      
376 {
377     int status = SUCCESS;       /* Return status */
378
379     /* Log that we are about to veryify user */
380     com_err(whoami, 0, "verifying user %s %s",message->first,message->last);
381
382     /* Figure out what user (if any) can be found based on the
383        encrypted information in the packet.  (See the comment on 
384        parse_encrypted().) */
385
386     status = find_user(message);
387
388     /* If Moira coudn't find the user */
389     if (status == MR_NO_MATCH) 
390         status = UREG_USER_NOT_FOUND;
391     else if (status == MR_SUCCESS)
392     {
393         /* If the information sent over in the packet did not point to a
394            valid user, the mit_id field in the formatted packet structure
395            will be empty. */
396         if (message->db.mit_id[0] == NULL)
397             status = UREG_USER_NOT_FOUND;
398         /* If the user was found but the registration has already started,
399            use this as the status */
400         else
401         {
402             switch (message->db.reg_status)
403             {
404               case US_NO_LOGIN_YET:
405                 status = SUCCESS;
406                 break;
407               case US_REGISTERED:
408                 status = UREG_ALREADY_REGISTERED;
409                 break;
410               case US_NO_PASSWD:
411                 status = UREG_NO_PASSWD_YET;
412                 break;
413               case US_DELETED:
414                 status = UREG_DELETED;
415                 break;
416               case US_NOT_ALLOWED:
417                 status = UREG_NOT_ALLOWED;
418                 break;
419               case US_ENROLLED:
420                 status = UREG_ENROLLED;
421                 break;
422               case US_ENROLL_NOT_ALLOWED:
423                 status = UREG_ENROLL_NOT_ALLOWED;
424                 break;
425             case US_HALF_ENROLLED:
426                 status = UREG_HALF_ENROLLED;
427                 break;
428               default:
429                 status = UREG_MISC_ERROR;
430                 critical_alert(FAIL_INST,"Bad user state %d for login %s.",
431                                message->db.reg_status, message->db.login);
432                 break;
433             }
434             /* Set retval to the login name so that the client can use
435                it in the error message it will give the user. */
436             (void) strcpy(retval,message->db.login);
437         }
438     }
439     
440     if (status)
441         com_err(whoami, status, " returned from verify_user");
442     else
443         com_err(whoami, 0, "User verified");
444
445     return status;
446 }
447         
448 int ureg_kadm_init()
449 {
450     unsigned int status = SUCCESS;       /* Return status */
451     static char krbrealm[REALM_SZ];      /* kerberos realm name */
452     static char hostbuf[BUFSIZ], *host;  /* local hostname in principal fmt */
453     static int inited = 0;
454     char *p;
455
456 #ifdef DEBUG
457     com_err(whoami, 0, "Entering ureg_kadm_init");
458 #endif DEBUG
459
460     if (!inited) {
461         inited++;
462         bzero(krbrealm, sizeof(krbrealm));
463         if (status = krb_get_lrealm(krbrealm, 1)) {
464             status += krb_err_base;
465             com_err(whoami, status, " fetching kerberos realm");
466             exit(1);
467         }
468         if (gethostname(hostbuf, sizeof(hostbuf)) < 0)
469           com_err(whoami, errno, "getting local hostname");
470         host = canonicalize_hostname(strsave(hostbuf));
471         for (p = host; *p && *p != '.'; p++)
472           if (isupper(*p))
473             *p = tolower(*p);
474         *p = 0;
475     }
476
477     /* Get keys for interacting with Kerberos admin server. */
478     /* principal, instance, realm, service, service instance, life, file */
479     if (status = krb_get_svc_in_tkt(MOIRA_SNAME, host, krbrealm, PWSERV_NAME,
480                                     KADM_SINST, 1, KEYFILE))
481         status += krb_err_base;
482     
483     if (status != SUCCESS)
484         com_err(whoami, status, " while get admin tickets");
485 #ifdef DEBUG
486     else {
487         com_err(whoami, status, "Succeeded in getting admin tickets");
488     }
489 #endif
490
491     if (status == SUCCESS) {
492         if ((status = kadm_init_link(PWSERV_NAME, KADM_SINST, krbrealm)) !=
493             KADM_SUCCESS) {
494             com_err(whoami, status, " while initializing kadmin connection");
495         }
496     }
497
498     return status;
499 }
500
501 int null_callproc(argc,argv,message)
502   int argc;
503   char *argv[];
504   char *message;
505   /* This routine is a null callback that should be used for queries that
506      do not return tuples.  If it ever gets called, something is wrong. */
507 {
508     critical_alert(FAIL_INST,"Something returned from an update query.");
509     return FAILURE;
510 }
511
512 /*
513  * This routine reserves a principal in kerberos by setting up a 
514  * principal with a random initial key.
515  */
516 int reserve_krb(login)
517   char *login;
518 {
519     int status = SUCCESS;
520     Kadm_vals new;
521     des_cblock key;
522     u_long *lkey = (u_long *)key;
523
524 #ifdef DEBUG
525     com_err(whoami, 0, "Entering reserve_krb");
526 #endif DEBUG
527
528     if ((status = ureg_kadm_init()) == SUCCESS) {
529         bzero((char *)&new, sizeof(new));
530         SET_FIELD(KADM_DESKEY, new.fields);
531         SET_FIELD(KADM_NAME, new.fields);
532         
533         (void) des_random_key(key);
534         new.key_low = htonl(lkey[0]);
535         new.key_high = htonl(lkey[1]);
536         strcpy(new.name, login);
537         
538         com_err(whoami, 0, "Creating kerberos principal for %s", login);
539         status = kadm_add(&new);
540         if (status != KADM_SUCCESS) 
541             com_err(whoami, status, " while reserving principal");
542         
543         bzero((char *)&new, sizeof(new));
544     }
545
546     dest_tkt();
547
548     return(status);
549 }
550
551 /*
552  * This routine reserves a principal in kerberos by setting up a 
553  * principal with a random initial key.
554  */
555 int setpass_krb(login, password)
556   char *login;
557   char *password;
558 {
559     int status = SUCCESS;
560     Kadm_vals new;
561     des_cblock key;
562     u_long *lkey = (u_long *)key;
563
564     if ((status = ureg_kadm_init()) == SUCCESS) {
565         bzero((char *)&new, sizeof(new));
566         SET_FIELD(KADM_DESKEY, new.fields);
567         SET_FIELD(KADM_NAME, new.fields);
568         
569         (void) des_string_to_key(password, key);
570         new.key_low = htonl(lkey[0]);
571         new.key_high = htonl(lkey[1]);
572         strcpy(new.name, login);
573         
574         com_err(whoami, 0, "Setting password for %s", login);
575         /* First arguement is not used if user has modify privileges */
576         if ((status = kadm_mod(&new, &new)) != KADM_SUCCESS) {
577             if (status == KADM_NOENTRY) {
578                 com_err(whoami, 0, 
579                         "kerberos principal doesn't exist; creating");
580                 if ((status = kadm_add(&new)) != KADM_SUCCESS)
581                     com_err(whoami, status, 
582                             " while creating kerberos principal");
583             }
584             else
585                 com_err(whoami, status, " while setting password");
586         }
587     }
588     
589     dest_tkt();
590     return(status);
591 }
592
593 int reserve_user(message,retval)
594   struct msg *message;
595   char *retval;
596 {
597     int q_argc;                 /* Number of arguments to query */
598     char *q_argv[3];            /* Arguments to Moira query */
599     char *q_name;               /* Name of Moira query */
600     int status = SUCCESS;       /* General purpose error status */
601     char fstype_buf[7];         /* Buffer to hold fs_type, a 16 bit number */
602     char *login;                /* The login name the user wants */
603     register int i;             /* A counter */
604
605     /* Log that we are about to reserve a user. */
606     com_err(whoami, 0, "reserving user %s %s", 
607             message->first, message->last);
608     
609     /* Check to make sure that we can verify this user. */
610     if ((status = verify_user(message,retval)) == SUCCESS)
611     {
612         /* Get the requested login name from leftover packet information. */
613         login = message->leftover;
614
615         /* Check the login name for validity.  The login name is currently
616            is allowed to contain lowercase letters in any position and 
617            and numbers and underscore characters in any position but the 
618            first. */
619         if ((strlen(login) < MIN_UNAME) || (strlen(login) > MAX_UNAME))
620             status = UREG_INVALID_UNAME;
621     }
622     if (status == SUCCESS)
623         if ((login[0] == '_') || isdigit(login[0]))
624             status = UREG_INVALID_UNAME;
625     
626     if (status == SUCCESS)
627     {
628         for (i = 0; i < strlen(login); i++)
629             if (!islower(login[i]) && !isdigit(login[i]) && 
630                 (login[i] != '_'))
631             {
632                 status = UREG_INVALID_UNAME;
633                 break;
634             }
635     }
636     if (status == SUCCESS)
637     {
638         /* Now that we have a valid user with a valid login... */
639
640         /* First, try to reserve the user in Moira. */
641         (void) sprintf(fstype_buf,"%d",MR_FS_STUDENT);
642         q_name = "register_user";
643         q_argv[0] = message->db.uid;
644         q_argv[1] = login;
645         q_argv[2] = fstype_buf;
646         q_argc = 3;
647         status = mr_query(q_name,q_argc,q_argv,null_callproc,(char *)0);
648         switch (status)
649         {
650           case MR_SUCCESS:
651             status = SUCCESS;
652             break;
653           case MR_IN_USE:
654             status = UREG_LOGIN_USED;
655             break;
656           case MR_DEADLOCK:
657             status = UREG_MISC_ERROR;
658             break;
659           default:
660             critical_alert(FAIL_INST,"%s returned from register_user.",
661                            error_message(status));
662             status = UREG_MISC_ERROR;
663             break;
664         }
665     }
666
667     if (status == SUCCESS)
668     {
669         /* 
670          * Moira login was successfully created; try to reserve kerberos
671          * principal. 
672          *
673          * If this routine fails, store the login in the retval so
674          * that it can be used in the client-side error message.
675          */
676         if ((status = reserve_krb(login)) != SUCCESS)
677             (void) strcpy(retval, login);
678     }
679
680     if (status)
681         com_err(whoami, status, " returned from reserve_user");
682     else {
683         com_err(whoami, 0, "User reserved");
684     }
685     
686     return status;
687 }
688
689 int set_final_status(message)
690 struct msg *message;
691     /* This routine updates a user's registration status to fully 
692        registered. */
693 {
694     char *login;
695     char *q_name;               /* Name of Moira query */
696     int q_argc;                 /* Number of arguments for Moira query */
697     char *q_argv[2];            /* Arguments to get user by uid */
698     char state[7];              /* Can hold a 16 bit integer */
699     int status;                 /* Error status */
700
701     if (message->request == UREG_SET_PASSWORD)
702       (void) sprintf(state,"%d",US_REGISTERED);
703     else if (message->db.reg_status == US_NO_LOGIN_YET)
704       (void) sprintf(state,"%d",US_ENROLLED);
705     else
706       (void) sprintf(state,"%d",US_ENROLL_NOT_ALLOWED);
707
708     login = message->db.login;
709     com_err(whoami, 0, "Setting final status for %s to %s", login, state);
710
711     q_name = "update_user_status";
712     q_argc = 2;
713     q_argv[0] = login;
714     q_argv[1] = state;
715     if ((status = mr_query(q_name, q_argc, q_argv, null_callproc,
716                             (char *)0)) != MR_SUCCESS) {
717         if (status == MR_DEADLOCK)
718           status = UREG_MISC_ERROR;
719         else
720           critical_alert(FAIL_INST,"%s returned from update_user_status.",
721                          error_message(status));
722     }
723     if (status)
724         com_err(whoami, status, " returned from set_final_status");
725     else
726         com_err(whoami, 0, "Final status set");
727     return status;
728 }
729
730
731 int set_password(message,retval)
732   struct msg *message;
733   char *retval;
734   /* This routine is used to set the initial password for the new user. */
735 {
736     int status = SUCCESS;       /* Return status */
737     char *passwd;               /* User's password */
738
739     com_err(whoami, 0, "setting password %s %s",
740             message->first, message->last);
741
742     status = verify_user(message,retval);
743
744     /* Don't set the password unless the registration status of the user
745        is that he exists and has no password. */
746     if (status == SUCCESS)
747         status = UREG_NO_LOGIN_YET;
748     if (((int)message->request == UREG_SET_PASSWORD &&
749          status == UREG_NO_PASSWD_YET) ||
750         ((int)message->request == UREG_GET_KRB &&
751          status == UREG_HALF_ENROLLED))
752     {
753         /* User is in proper state for this transaction. */
754         
755         passwd = message->leftover;
756         
757         /* Set password. */
758         if ((status = setpass_krb(message->db.login, passwd)) != SUCCESS)
759             /* If failure, allow login name to be used in client 
760                error message */
761             (void) strcpy(retval,message->db.login);
762         else
763             /* Otherwise, mark user as finished. */
764             status = set_final_status(message);
765     }
766
767     if (status)
768         com_err(whoami, status, " returned from set_passwd");
769     else
770         com_err(whoami, 0, "Password set");
771
772     return status;
773 }
774
775
776 int getuserinfo(argc, argv, qargv)
777 int argc;
778 char **argv;
779 char **qargv;
780 {
781     int status = SUCCESS;
782     int  i;
783
784     if (argc != U_END) {
785         critical_alert(FAIL_INST,
786                        "Wrong number of args returned from get_user_by_uid");
787         status = MR_ABORT;
788     } else {
789         qargv[U_NAME] = strsave(argv[U_NAME]);
790         for (i = 1; i < U_MODTIME; i++)
791           qargv[i+1] = strsave(argv[i]);
792         qargv[U_MODTIME+1] = NULL;
793     }
794     return(status);
795 }
796
797
798 int set_identity(message,retval)
799 struct msg *message;
800 char *retval;
801 {
802     int q_argc;                 /* Number of arguments to query */
803     char *q_argv[U_END];        /* Arguments to Moira query */
804     char *q_name;               /* Name of Moira query */
805     int status = SUCCESS;       /* General purpose error status */
806     char fstype_buf[7];         /* Buffer to hold fs_type, a 16 bit number */
807     char *login;                /* The login name the user wants */
808     register int i;             /* A counter */
809
810     /* Log that we are about to reserve a user. */
811     com_err(whoami, 0, "setting identity %s %s", 
812             message->first, message->last);
813     
814     /* Check to make sure that we can verify this user. */
815     status = verify_user(message,retval);
816     if (status == SUCCESS || status == UREG_NOT_ALLOWED)
817     {
818         status = SUCCESS;
819         /* Get the requested login name from leftover packet information. */
820         login = message->leftover;
821
822         /* Check the login name for validity.  The login name is currently
823            is allowed to contain lowercase letters in any position and 
824            and numbers and underscore characters in any position but the 
825            first. */
826         if ((strlen(login) < MIN_UNAME) || (strlen(login) > MAX_UNAME))
827             status = UREG_INVALID_UNAME;
828     }
829     if (status == SUCCESS)
830         if ((login[0] == '_') || isdigit(login[0]))
831             status = UREG_INVALID_UNAME;
832     if (status == SUCCESS)
833     {
834         for (i = 0; i < strlen(login); i++)
835             if (!islower(login[i]) && !isdigit(login[i]) && 
836                 (login[i] != '_'))
837             {
838                 status = UREG_INVALID_UNAME;
839                 break;
840             }
841     }
842     if (status == SUCCESS)
843     {
844         /* Now that we have a valid user with a valid login... */
845
846         q_argv[0] = message->db.uid;
847         status = mr_query("get_user_account_by_uid", 1, q_argv,
848                           getuserinfo, q_argv);
849         if (status != SUCCESS) {
850             com_err(whoami, status, " while getting user info");
851             return(status);
852         }
853         q_argv[U_NAME+1] = login;
854         q_argv[U_STATE+1] = "7";
855         status = mr_query("update_user_account", U_MODTIME+1, q_argv,
856                            null_callproc, NULL);
857         switch (status)
858         {
859           case MR_SUCCESS:
860             status = SUCCESS;
861             break;
862           case MR_IN_USE:
863             status = UREG_LOGIN_USED;
864             break;
865           case MR_DEADLOCK:
866             status = UREG_MISC_ERROR;
867             break;
868           default:
869             critical_alert(FAIL_INST,"%s returned from update_user_account.",
870                            error_message(status));
871             status = UREG_MISC_ERROR;
872             break;
873         }
874     }
875     if (status == SUCCESS)
876     {
877         /* Moira login was successfully created; try to reserve kerberos
878            principal. */
879         /* If this routine fails, store the login in the retval so
880            that it can be used in the client-side error message. */
881         if ((status = reserve_krb(login)) != SUCCESS)
882             (void) strcpy(retval, login);
883     }
884
885     if (status)
886         com_err(whoami, status, " returned from set_identity");
887     else
888         com_err(whoami, 0, "Identity set");
889     
890     return status;
891 }
892
893
894 void reg_com_err_hook(whoami, code, fmt, pvar)
895         char *whoami;
896         int code;
897         char *fmt;
898         caddr_t pvar;
899 {
900         if (whoami) {
901                 fputs(whoami, stderr);
902                 fputs(": ", stderr);
903         }
904         if (code) {
905                 fputs(error_message(code), stderr);
906         }
907         if (fmt) {
908                 _doprnt(fmt, pvar, stderr);
909         }
910         putc('\n', stderr);
911         fflush(stderr);
912 }
913
914
915 /* Find out of someone's secure instance password is set.
916  * Returns UREG_ALREADY_REGISTERED if set, SUCCESS (0) if not.
917  */
918
919 int get_secure(message, retval)
920 struct msg *message;
921 char *retval;
922 {
923     int status;
924     char *argv[U_END];
925
926     com_err(whoami, 0, "checking status of secure password for %s",
927             message->first);
928     argv[0] = message->first;
929     status = mr_query("get_user_account_by_login", 1, argv, getuserinfo, argv);
930     if (status != SUCCESS) {
931         com_err(whoami, status, " while getting user info");
932         return(status);
933     }
934     if (atoi(argv[U_SECURE + 1]))
935       return UREG_ALREADY_REGISTERED;
936     return SUCCESS;
937 }
938
939
940 /* Set someone's secure instance password. */
941
942 int set_secure(message, retval)
943 struct msg *message;
944 char *retval;
945 {
946     int status, i;
947     char *argv[U_END], hostbuf[256], *bp, *p, buf[512], *passwd, *id;
948     KTEXT_ST creds;
949     AUTH_DAT auth;
950     C_Block key;
951     Key_schedule keys;
952     Kadm_vals kv;
953     u_long *lkey = (u_long *)key;
954     struct timeval now;
955     static int inited = 0;
956     static char *host;
957
958     if (!inited) {
959         inited++;
960         if (gethostname(hostbuf, sizeof(hostbuf)) < 0)
961           com_err(whoami, errno, "getting local hostname");
962         host = strsave(krb_get_phost(hostbuf));
963     }
964
965     com_err(whoami, 0, "setting secure passwd for %s", message->first);
966     argv[0] = message->first;
967     status = mr_query("get_user_account_by_login", 1, argv, getuserinfo, argv);
968     if (status != SUCCESS) {
969         com_err(whoami, status, " while getting user info");
970         return(status);
971     }
972     if (atoi(argv[U_SECURE + 1])) {
973         com_err(whoami, UREG_ALREADY_REGISTERED, "in set_secure()");
974         return UREG_ALREADY_REGISTERED;
975     }
976
977     bp = message->encrypted;
978     /* round up to word boundary */
979     bp = (char *)((((u_long)bp + 3) >> 2) << 2);
980     
981     creds.length = ntohl(*((int *)bp));
982     bp += sizeof(int);
983     bcopy(bp, creds.dat, creds.length);
984     creds.mbz = 0;
985     bp += creds.length;
986
987 #ifdef DEBUG
988     com_err(whoami, 0, "Cred: length %d", creds.length);
989     for (i = 0; i < creds.length; i += 16)
990       com_err(whoami, 0, " %02x %02x %02x %02x %02x %02x %02x %02x  %02x %02x %02x %02x %02x %02x %02x %02x",
991               creds.dat[i+0], creds.dat[i+1], creds.dat[i+2], creds.dat[i+3],
992               creds.dat[i+4], creds.dat[i+5], creds.dat[i+6], creds.dat[i+7],
993               creds.dat[i+8], creds.dat[i+9], creds.dat[i+10], creds.dat[i+11],
994               creds.dat[i+12], creds.dat[i+13], creds.dat[i+14], creds.dat[i+15]);
995 #endif /* DEBUG */
996     
997     status = krb_rd_req(&creds, "changepw", host, cur_req_sender(),
998                         &auth, "");
999     if (status) {
1000         status += krb_err_base;
1001         com_err(whoami, status, " verifying credentials in set_secure()");
1002         return(status);
1003     }
1004
1005     message->leftover_len = ntohl(*((int*)(bp)));
1006     bp += sizeof(int);
1007     message->leftover = bp;
1008
1009     des_key_sched(auth.session, keys);
1010     des_pcbc_encrypt(message->leftover, buf, message->leftover_len,
1011                      keys, auth.session, 0);
1012
1013     id = buf;
1014     passwd = index(buf, ',');
1015     *passwd++ = 0;
1016 #ifdef DEBUG
1017     com_err(whoami, 0, "Got id: %s, passwd %d chars", id, strlen(passwd));
1018 #endif
1019
1020     if (strcmp(id, argv[U_MITID + 1])) {
1021         status = UREG_USER_NOT_FOUND;
1022         com_err(whoami, status, "IDs mismatch: %s, %s", id, argv[U_MITID + 1]);
1023         return status;
1024     }
1025
1026     /* now do actual password setting stuff */
1027
1028     if ((status = ureg_kadm_init()) != SUCCESS) {
1029         com_err(whoami, status, "initing kadm stuff");
1030         return(status);
1031     }
1032
1033     bzero((char *)&kv, sizeof(kv));
1034     SET_FIELD(KADM_DESKEY, kv.fields);
1035     SET_FIELD(KADM_NAME, kv.fields);
1036     SET_FIELD(KADM_INST, kv.fields);
1037     (void) des_string_to_key(passwd, key);
1038     kv.key_low = htonl(lkey[0]);
1039     kv.key_high = htonl(lkey[1]);
1040     strcpy(kv.name, message->first);
1041     strcpy(kv.instance, "extra");
1042
1043     if ((status = kadm_add(&kv)) != KADM_SUCCESS) {
1044         com_err(whoami, status, " while creating kerberos principal");
1045         return(status);
1046     }
1047
1048     argv[0] = message->first;
1049     argv[1] = buf;
1050     gettimeofday(&now, NULL);
1051     sprintf(buf, "%d", now.tv_sec);
1052     status = mr_query("update_user_security_status", 2, argv, getuserinfo, argv);
1053     if (status != SUCCESS) {
1054         com_err(whoami, status, " while updating user status");
1055         return(status);
1056     }
1057     return SUCCESS;
1058 }
This page took 0.121827 seconds and 3 git commands to generate.