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