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