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