]> andersk Git - moira.git/blob - reg_svr/reg_svr.c
Solaris/POSIX changes
[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     setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
60     setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
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     memset(message->db.mit_id,0,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         memset(krbrealm, 0, 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         memset(&new, 0, 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         memset(&new, 0, 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         memset(&new, 0, 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           case MR_NOT_UNIQUE:
866             status = UREG_LOGIN_USED;
867             break;
868           case MR_DEADLOCK:
869             status = UREG_MISC_ERROR;
870             break;
871           default:
872             critical_alert(FAIL_INST,"%s returned from update_user_account.",
873                            error_message(status));
874             status = UREG_MISC_ERROR;
875             break;
876         }
877     }
878     if (status == SUCCESS)
879     {
880         /* Moira login was successfully created; try to reserve kerberos
881            principal. */
882         /* If this routine fails, store the login in the retval so
883            that it can be used in the client-side error message. */
884         if ((status = reserve_krb(login)) != SUCCESS)
885             (void) strcpy(retval, login);
886     }
887
888     if (status)
889         com_err(whoami, status, " returned from set_identity");
890     else
891         com_err(whoami, 0, "Identity set");
892     
893     return status;
894 }
895
896
897 void reg_com_err_hook(whoami, code, fmt, pvar)
898         char *whoami;
899         int code;
900         char *fmt;
901         caddr_t pvar;
902 {
903         if (whoami) {
904                 fputs(whoami, stderr);
905                 fputs(": ", stderr);
906         }
907         if (code) {
908                 fputs(error_message(code), stderr);
909         }
910         if (fmt) {
911                 _doprnt(fmt, pvar, stderr);
912         }
913         putc('\n', stderr);
914         fflush(stderr);
915 }
916
917
918 /* Find out of someone's secure instance password is set.
919  * Returns UREG_ALREADY_REGISTERED if set, SUCCESS (0) if not.
920  */
921
922 int get_secure(message, retval)
923 struct msg *message;
924 char *retval;
925 {
926     int status;
927     char *argv[U_END];
928
929     com_err(whoami, 0, "checking status of secure password for %s",
930             message->first);
931     argv[0] = message->first;
932     status = mr_query("get_user_account_by_login", 1, argv, getuserinfo, argv);
933     if (status != SUCCESS) {
934         com_err(whoami, status, " while getting user info");
935         return(status);
936     }
937     if (atoi(argv[U_SECURE + 1]))
938       return UREG_ALREADY_REGISTERED;
939     return SUCCESS;
940 }
941
942
943 /* Set someone's secure instance password. */
944
945 int set_secure(message, retval)
946 struct msg *message;
947 char *retval;
948 {
949     int status, i;
950     char *argv[U_END], hostbuf[256], *bp, *p, buf[512], *passwd, *id;
951     KTEXT_ST creds;
952     AUTH_DAT auth;
953     C_Block key;
954     Key_schedule keys;
955     Kadm_vals kv;
956     u_long *lkey = (u_long *)key;
957     struct timeval now;
958     static int inited = 0;
959     static char *host;
960
961     if (!inited) {
962         inited++;
963         if (gethostname(hostbuf, sizeof(hostbuf)) < 0)
964           com_err(whoami, errno, "getting local hostname");
965         host = strsave(krb_get_phost(hostbuf));
966     }
967
968     com_err(whoami, 0, "setting secure passwd for %s", message->first);
969     argv[0] = message->first;
970     status = mr_query("get_user_account_by_login", 1, argv, getuserinfo, argv);
971     if (status != SUCCESS) {
972         com_err(whoami, status, " while getting user info");
973         return(status);
974     }
975     if (atoi(argv[U_SECURE + 1])) {
976         com_err(whoami, UREG_ALREADY_REGISTERED, "in set_secure()");
977         return UREG_ALREADY_REGISTERED;
978     }
979
980     bp = message->encrypted;
981     /* round up to word boundary */
982     bp = (char *)((((u_long)bp + 3) >> 2) << 2);
983     
984     creds.length = ntohl(*((int *)bp));
985     bp += sizeof(int);
986     memcpy(creds.dat, bp, creds.length);
987     creds.mbz = 0;
988     bp += creds.length;
989
990 #ifdef DEBUG
991     com_err(whoami, 0, "Cred: length %d", creds.length);
992     for (i = 0; i < creds.length; i += 16)
993       com_err(whoami, 0, " %02x %02x %02x %02x %02x %02x %02x %02x  %02x %02x %02x %02x %02x %02x %02x %02x",
994               creds.dat[i+0], creds.dat[i+1], creds.dat[i+2], creds.dat[i+3],
995               creds.dat[i+4], creds.dat[i+5], creds.dat[i+6], creds.dat[i+7],
996               creds.dat[i+8], creds.dat[i+9], creds.dat[i+10], creds.dat[i+11],
997               creds.dat[i+12], creds.dat[i+13], creds.dat[i+14], creds.dat[i+15]);
998 #endif /* DEBUG */
999     
1000     status = krb_rd_req(&creds, "changepw", host, cur_req_sender(),
1001                         &auth, "");
1002     if (status) {
1003         status += krb_err_base;
1004         com_err(whoami, status, " verifying credentials in set_secure()");
1005         return(status);
1006     }
1007
1008     message->leftover_len = ntohl(*((int*)(bp)));
1009     bp += sizeof(int);
1010     message->leftover = bp;
1011
1012     des_key_sched(auth.session, keys);
1013     des_pcbc_encrypt(message->leftover, buf, message->leftover_len,
1014                      keys, auth.session, 0);
1015
1016     id = buf;
1017     passwd = strchr(buf, ',');
1018     *passwd++ = 0;
1019 #ifdef DEBUG
1020     com_err(whoami, 0, "Got id: %s, passwd %d chars", id, strlen(passwd));
1021 #endif
1022
1023     if (strcmp(id, argv[U_MITID + 1])) {
1024         char buf[32];
1025
1026         EncryptID(buf, id, argv[U_FIRST+1], argv[U_LAST+1]);
1027         if (strcmp(buf, argv[U_MITID + 1])) {
1028             status = UREG_USER_NOT_FOUND;
1029             com_err(whoami, status, "IDs mismatch: %s (%s), %s", id, buf,
1030                     argv[U_MITID + 1]);
1031             return status;
1032         }
1033     }
1034
1035     /* now do actual password setting stuff */
1036
1037     if ((status = ureg_kadm_init()) != SUCCESS) {
1038         com_err(whoami, status, "initing kadm stuff");
1039         return(status);
1040     }
1041
1042     memset(&kv, 0, sizeof(kv));
1043     SET_FIELD(KADM_DESKEY, kv.fields);
1044     SET_FIELD(KADM_NAME, kv.fields);
1045     SET_FIELD(KADM_INST, kv.fields);
1046     (void) des_string_to_key(passwd, key);
1047     kv.key_low = htonl(lkey[0]);
1048     kv.key_high = htonl(lkey[1]);
1049     strcpy(kv.name, message->first);
1050     strcpy(kv.instance, "extra");
1051
1052     if ((status = kadm_add(&kv)) != KADM_SUCCESS) {
1053         com_err(whoami, status, " while creating kerberos principal");
1054         return(status);
1055     }
1056
1057     argv[0] = message->first;
1058     argv[1] = buf;
1059     gettimeofday(&now, NULL);
1060     sprintf(buf, "%d", now.tv_sec);
1061     status = mr_query("update_user_security_status", 2, argv, getuserinfo, argv);
1062     if (status != SUCCESS) {
1063         com_err(whoami, status, " while updating user status");
1064         return(status);
1065     }
1066     return SUCCESS;
1067 }
This page took 0.122819 seconds and 5 git commands to generate.