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