]> andersk Git - moira.git/blob - reg_svr/reg_svr.c
7e4015268136504c087f6411ad2100f3373d186c
[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     /* Point temp to the end of the plain text ID number. */
191     temp = decrypt + strlen(idnumber) + 1;
192     /* Find out how much more packet there is. */
193     len = message->encrypted_len - (temp - decrypt);
194     /* Copy the next CRYPT_LEN bytes of the decrypted information into 
195        hashid if there are CRYPT_LEN more bytes to copy.  There will be
196        if we have the right key. */
197     (void) strncpy(hashid, temp, min(len, CRYPT_LEN));
198     /* Point temp to the end of the encrypted ID field */
199     temp += strlen(hashid) + 1;
200     /* Find out how much more room there is. */
201     len = message->encrypted_len - (temp - decrypt);
202     
203     /* Now compare encrypted ID's don't match. */
204     if (strcmp(hashid, data->mit_id)) status = FAILURE;
205     if (status == SUCCESS)
206     {
207         EncryptID(recrypt, idnumber, message->first, message->last);
208         /* Now compare encrypted plain text to ID from database. */
209         if (strcmp(recrypt, data->mit_id)) status = FAILURE;
210     }
211     
212     if (status == SUCCESS)
213     {
214         /* We made it.  Now we can finish initializing message. */
215         /* Point leftover to whatever is left over! */
216         message->leftover = temp;
217         message->leftover_len = len;
218         /* Since we know we have the right user, fill in the information 
219            from the Moira database. */
220         message->db.reg_status = data->reg_status;
221         (void) strncpy(message->db.uid,data->uid, sizeof(message->db.uid));
222         (void) strncpy(message->db.mit_id,data->mit_id, 
223                        sizeof(message->db.mit_id));
224         (void) strncpy(message->db.login,data->login, sizeof(message->db.login));
225     }
226     
227 #ifdef DEBUG
228     if (status)
229         com_err(whoami, status, " in parse_encrypted");
230     else
231         com_err(whoami, status, "parse_encrypted succeeded");
232 #endif
233
234     return status;
235 }
236
237 int db_callproc(argc,argv,queue)
238   int argc;                     /* Number of arguments returned by Moira */
239   char *argv[];                 /* Arguments returned by Moira */
240   struct save_queue *queue;     /* Queue to save information in */
241 /* This function is called by mr_query after each tuple found.  It is
242    used by find_user to cache information about each user found.  */
243 {
244     struct db_data *data;       /* Structure to store the information in */
245     int status = SUCCESS;       /* Error status */
246     
247 #ifdef DEBUG
248     com_err(whoami, 0, "Entering db_callproc.");
249 #endif
250
251     if (argc != U_END)
252     {
253         critical_alert
254             (FAIL_INST,
255              "Wrong number of arguments returned from get_user_by_name.");
256         status = MR_ABORT;
257     }
258     else
259     {
260         /* extract the needed information from the results of the Moira query */
261         data = (struct db_data *)malloc(sizeof(struct db_data));
262         data->reg_status = atoi(argv[U_STATE]);
263         (void) strncpy(data->login,argv[U_NAME],sizeof(data->login));
264         (void) strncpy(data->mit_id,argv[U_MITID],sizeof(data->mit_id));
265         (void) strncpy(data->uid,argv[U_UID],sizeof(data->uid));
266 #ifdef DEBUG
267         fprintf(stderr,"Found in database:\n");
268         fprintf(stderr,"   Registration status: %d\n",data->reg_status);
269         fprintf(stderr,"   login: %s\n",data->login);
270         fprintf(stderr,"   MIT ID: %s\n",data->mit_id);
271         fprintf(stderr,"   uid: %s\n",data->uid);
272 #endif
273         sq_save_data(queue,data);
274     }
275
276     return status;
277 }
278     
279 int find_user(message)
280   struct msg *message;          /* Formatted packet structure */
281 /* This routine verifies that a user is allowed to register by finding
282    him/her in the Moira database.  It returns the status of the Moira
283    query that it calls. */
284 {
285 #define GUBN_ARGS 2             /* Arguements needed by get_user_by_name */
286     char *q_name;               /* Name of query */
287     int q_argc;                 /* Number of arguments for query */
288     char *q_argv[GUBN_ARGS];    /* Arguments to query */
289     int status = SUCCESS;       /* Query return status */
290
291     struct save_queue *queue;   /* Queue to hold Moira data */
292     struct db_data *data;       /* Structure for data for one tuple */
293     short verified = FALSE;     /* Have we verified the user? */
294
295     /* Zero the mit_id field in the formatted packet structure.  This
296        being zeroed means that no user was found. */
297     bzero(message->db.mit_id,sizeof(message->db.mit_id));
298     
299     if (status == SUCCESS)
300     {
301         /* Get ready to make an Moira query */
302         q_name = "get_user_by_name";
303         q_argc = GUBN_ARGS;     /* #defined in this routine */
304         q_argv[0] = message->first;
305         q_argv[1] = message->last;
306         
307         /* Create queue to hold information */
308         queue = sq_create();
309         
310         /* Do it */
311         status = mr_query(q_name,q_argc,q_argv,db_callproc,(char *)queue);
312         
313 #ifdef DEBUG
314         fprintf(stderr," %d returned by get_user_by_name\n",status);
315 #endif
316         
317         if (status == MR_SUCCESS) 
318         {
319             /* Traverse the list, freeing data as we go.  If sq_get_data()
320                returns zero if there is no more data on the queue. */
321             while (sq_get_data(queue,&data))
322             {
323                 if (!verified)
324                     /* parse_encrypted returns zero on success */
325                     verified = (parse_encrypted(message,data) == SUCCESS);
326                 free((char *)data);
327             }
328         }
329
330         /* Destroy the queue */
331         sq_destroy(queue);
332     }
333     
334 #ifdef DEBUG
335     fprintf(stderr,"Returned from find_user\n");
336     fprintf(stderr,"   MIT ID: %s\n", message->db.mit_id);
337     fprintf(stderr,"   Registration status: %d\n",message->db.reg_status);
338     fprintf(stderr,"   uid: %s\n",message->db.uid);
339     fprintf(stderr,"   login: %s\n",message->db.login);
340     fprintf(stderr,"   Status from query: %d\n",status);
341 #endif DEBGUG
342
343     return status;
344 }
345
346 int verify_user(message,retval)
347   struct msg *message;
348   char *retval;
349   /* This routine determines whether a user is in the databse and returns
350      his state so that other routines can figure out whether he is the 
351      correct state for various transactions. */
352      
353 {
354     int status = SUCCESS;       /* Return status */
355
356     /* Log that we are about to veryify user */
357     com_err(whoami, 0, "verifying user %s %s",message->first,message->last);
358
359     /* Figure out what user (if any) can be found based on the
360        encrypted information in the packet.  (See the comment on 
361        parse_encrypted().) */
362
363     status = find_user(message);
364
365     /* If Moira coudn't find the user */
366     if (status == MR_NO_MATCH) 
367         status = UREG_USER_NOT_FOUND;
368     else if (status == MR_SUCCESS)
369     {
370         /* If the information sent over in the packet did not point to a
371            valid user, the mit_id field in the formatted packet structure
372            will be empty. */
373         if (message->db.mit_id[0] == NULL)
374             status = UREG_USER_NOT_FOUND;
375         /* If the user was found but the registration has already started,
376            use this as the status */
377         else
378         {
379             switch (message->db.reg_status)
380             {
381               case US_NO_LOGIN_YET:
382                 status = SUCCESS;
383                 break;
384               case US_REGISTERED:
385                 status = UREG_ALREADY_REGISTERED;
386                 break;
387               case US_NO_PASSWD:
388                 status = UREG_NO_PASSWD_YET;
389                 break;
390               case US_DELETED:
391                 status = UREG_DELETED;
392                 break;
393               case US_NOT_ALLOWED:
394                 status = UREG_NOT_ALLOWED;
395                 break;
396               case US_ENROLLED:
397                 status = UREG_ENROLLED;
398                 break;
399               case US_ENROLL_NOT_ALLOWED:
400                 status = UREG_ENROLL_NOT_ALLOWED;
401                 break;
402             case US_HALF_ENROLLED:
403                 status = UREG_HALF_ENROLLED;
404                 break;
405               default:
406                 status = UREG_MISC_ERROR;
407                 critical_alert(FAIL_INST,"Bad user state %d for login %s.",
408                                message->db.reg_status, message->db.login);
409                 break;
410             }
411             /* Set retval to the login name so that the client can use
412                it in the error message it will give the user. */
413             (void) strcpy(retval,message->db.login);
414         }
415     }
416     
417     if (status)
418         com_err(whoami, status, " returned from verify_user");
419     else
420         com_err(whoami, 0, "User verified");
421
422     return status;
423 }
424         
425 int ureg_kadm_init()
426 {
427     unsigned int status = SUCCESS;       /* Return status */
428     static char krbrealm[REALM_SZ];      /* kerberos realm name */
429     static char hostbuf[BUFSIZ], *host;  /* local hostname in principal fmt */
430     static int inited = 0;
431     char *p;
432
433 #ifdef DEBUG
434     com_err(whoami, 0, "Entering ureg_kadm_init");
435 #endif DEBUG
436
437     if (!inited) {
438         inited++;
439         bzero(krbrealm, sizeof(krbrealm));
440         if (status = krb_get_lrealm(krbrealm, 1)) {
441             status += krb_err_base;
442             com_err(whoami, status, " fetching kerberos realm");
443             exit(1);
444         }
445         if (gethostname(hostbuf, sizeof(hostbuf)) < 0)
446           com_err(whoami, errno, "getting local hostname");
447         host = canonicalize_hostname(strsave(hostbuf));
448         for (p = host; *p && *p != '.'; p++)
449           if (isupper(*p))
450             *p = tolower(*p);
451         *p = 0;
452     }
453
454     /* Get keys for interacting with Kerberos admin server. */
455     /* principal, instance, realm, service, service instance, life, file */
456     if (status = krb_get_svc_in_tkt(MOIRA_SNAME, host, krbrealm, PWSERV_NAME,
457                                     KADM_SINST, 1, KEYFILE))
458         status += krb_err_base;
459     
460     if (status != SUCCESS)
461         com_err(whoami, status, " while get admin tickets");
462 #ifdef DEBUG
463     else {
464         com_err(whoami, status, "Succeeded in getting admin tickets");
465     }
466 #endif
467
468     if (status == SUCCESS) {
469         if ((status = kadm_init_link(PWSERV_NAME, KADM_SINST, krbrealm)) !=
470             KADM_SUCCESS) {
471             com_err(whoami, status, " while initializing kadmin connection");
472         }
473     }
474
475     return status;
476 }
477
478 int null_callproc(argc,argv,message)
479   int argc;
480   char *argv[];
481   char *message;
482   /* This routine is a null callback that should be used for queries that
483      do not return tuples.  If it ever gets called, something is wrong. */
484 {
485     critical_alert(FAIL_INST,"Something returned from an update query.");
486     return FAILURE;
487 }
488
489 /*
490  * This routine reserves a principal in kerberos by setting up a 
491  * principal with a random initial key.
492  */
493 int reserve_krb(login)
494   char *login;
495 {
496     int status = SUCCESS;
497     Kadm_vals new;
498     des_cblock key;
499     u_long *lkey = (u_long *)key;
500
501 #ifdef DEBUG
502     com_err(whoami, 0, "Entering reserve_krb");
503 #endif DEBUG
504
505     if ((status = ureg_kadm_init()) == SUCCESS) {
506         bzero((char *)&new, sizeof(new));
507         SET_FIELD(KADM_DESKEY, new.fields);
508         SET_FIELD(KADM_NAME, new.fields);
509         
510         (void) des_random_key(key);
511         new.key_low = htonl(lkey[0]);
512         new.key_high = htonl(lkey[1]);
513         strcpy(new.name, login);
514         
515         com_err(whoami, 0, "Creating kerberos principal for %s", login);
516         status = kadm_add(&new);
517         if (status != KADM_SUCCESS) 
518             com_err(whoami, status, " while reserving principal");
519         
520         bzero((char *)&new, sizeof(new));
521     }
522
523     dest_tkt();
524
525     return(status);
526 }
527
528 /*
529  * This routine reserves a principal in kerberos by setting up a 
530  * principal with a random initial key.
531  */
532 int setpass_krb(login, password)
533   char *login;
534   char *password;
535 {
536     int status = SUCCESS;
537     Kadm_vals new;
538     des_cblock key;
539     u_long *lkey = (u_long *)key;
540
541     if ((status = ureg_kadm_init()) == SUCCESS) {
542         bzero((char *)&new, sizeof(new));
543         SET_FIELD(KADM_DESKEY, new.fields);
544         SET_FIELD(KADM_NAME, new.fields);
545         
546         (void) des_string_to_key(password, key);
547         new.key_low = htonl(lkey[0]);
548         new.key_high = htonl(lkey[1]);
549         strcpy(new.name, login);
550         
551         com_err(whoami, 0, "Setting password for %s", login);
552         /* First arguement is not used if user has modify privileges */
553         if ((status = kadm_mod(&new, &new)) != KADM_SUCCESS) {
554             if (status == KADM_NOENTRY) {
555                 com_err(whoami, 0, 
556                         "kerberos principal doesn't exist; creating");
557                 if ((status = kadm_add(&new)) != KADM_SUCCESS)
558                     com_err(whoami, status, 
559                             " while creating kerberos principal");
560             }
561             else
562                 com_err(whoami, status, " while setting password");
563         }
564     }
565     
566     dest_tkt();
567     return(status);
568 }
569
570 int reserve_user(message,retval)
571   struct msg *message;
572   char *retval;
573 {
574     int q_argc;                 /* Number of arguments to query */
575     char *q_argv[3];            /* Arguments to Moira query */
576     char *q_name;               /* Name of Moira query */
577     int status = SUCCESS;       /* General purpose error status */
578     char fstype_buf[7];         /* Buffer to hold fs_type, a 16 bit number */
579     char *login;                /* The login name the user wants */
580     register int i;             /* A counter */
581
582     /* Log that we are about to reserve a user. */
583     com_err(whoami, 0, "reserving user %s %s", 
584             message->first, message->last);
585     
586     /* Check to make sure that we can verify this user. */
587     if ((status = verify_user(message,retval)) == SUCCESS)
588     {
589         /* Get the requested login name from leftover packet information. */
590         login = message->leftover;
591
592         /* Check the login name for validity.  The login name is currently
593            is allowed to contain lowercase letters in any position and 
594            and numbers and underscore characters in any position but the 
595            first. */
596         if ((strlen(login) < MIN_UNAME) || (strlen(login) > MAX_UNAME))
597             status = UREG_INVALID_UNAME;
598     }
599     if (status == SUCCESS)
600         if ((login[0] == '_') || isdigit(login[0]))
601             status = UREG_INVALID_UNAME;
602     
603     if (status == SUCCESS)
604     {
605         for (i = 0; i < strlen(login); i++)
606             if (!islower(login[i]) && !isdigit(login[i]) && 
607                 (login[i] != '_'))
608             {
609                 status = UREG_INVALID_UNAME;
610                 break;
611             }
612     }
613     if (status == SUCCESS)
614     {
615         /* Now that we have a valid user with a valid login... */
616
617         /* First, try to reserve the user in Moira. */
618         (void) sprintf(fstype_buf,"%d",MR_FS_STUDENT);
619         q_name = "register_user";
620         q_argv[0] = message->db.uid;
621         q_argv[1] = login;
622         q_argv[2] = fstype_buf;
623         q_argc = 3;
624         status = mr_query(q_name,q_argc,q_argv,null_callproc,(char *)0);
625         switch (status)
626         {
627           case MR_SUCCESS:
628             status = SUCCESS;
629             break;
630           case MR_IN_USE:
631             status = UREG_LOGIN_USED;
632             break;
633           case MR_DEADLOCK:
634             status = UREG_MISC_ERROR;
635             break;
636           default:
637             critical_alert(FAIL_INST,"%s returned from register_user.",
638                            error_message(status));
639             status = UREG_MISC_ERROR;
640             break;
641         }
642     }
643
644     if (status == SUCCESS)
645     {
646         /* 
647          * Moira login was successfully created; try to reserve kerberos
648          * principal. 
649          *
650          * If this routine fails, store the login in the retval so
651          * that it can be used in the client-side error message.
652          */
653         if ((status = reserve_krb(login)) != SUCCESS)
654             (void) strcpy(retval, login);
655     }
656
657     if (status)
658         com_err(whoami, status, " returned from reserve_user");
659     else {
660         com_err(whoami, 0, "User reserved");
661     }
662     
663     return status;
664 }
665
666 int set_final_status(message)
667 struct msg *message;
668     /* This routine updates a user's registration status to fully 
669        registered. */
670 {
671     char *login;
672     char *q_name;               /* Name of Moira query */
673     int q_argc;                 /* Number of arguments for Moira query */
674     char *q_argv[2];            /* Arguments to get user by uid */
675     char state[7];              /* Can hold a 16 bit integer */
676     int status;                 /* Error status */
677
678     if (message->request == UREG_SET_PASSWORD)
679       (void) sprintf(state,"%d",US_REGISTERED);
680     else if (message->db.reg_status == US_NO_LOGIN_YET)
681       (void) sprintf(state,"%d",US_ENROLLED);
682     else
683       (void) sprintf(state,"%d",US_ENROLL_NOT_ALLOWED);
684
685     login = message->db.login;
686     com_err(whoami, 0, "Setting final status for %s to %s", login, state);
687
688     q_name = "update_user_status";
689     q_argc = 2;
690     q_argv[0] = login;
691     q_argv[1] = state;
692     if ((status = mr_query(q_name, q_argc, q_argv, null_callproc,
693                             (char *)0)) != MR_SUCCESS) {
694         if (status == MR_DEADLOCK)
695           status = UREG_MISC_ERROR;
696         else
697           critical_alert(FAIL_INST,"%s returned from update_user_status.",
698                          error_message(status));
699     }
700     if (status)
701         com_err(whoami, status, " returned from set_final_status");
702     else
703         com_err(whoami, 0, "Final status set");
704     return status;
705 }
706
707
708 int set_password(message,retval)
709   struct msg *message;
710   char *retval;
711   /* This routine is used to set the initial password for the new user. */
712 {
713     int status = SUCCESS;       /* Return status */
714     char *passwd;               /* User's password */
715
716     com_err(whoami, 0, "setting password %s %s",
717             message->first, message->last);
718
719     status = verify_user(message,retval);
720
721     /* Don't set the password unless the registration status of the user
722        is that he exists and has no password. */
723     if (status == SUCCESS)
724         status = UREG_NO_LOGIN_YET;
725     if (((int)message->request == UREG_SET_PASSWORD &&
726          status == UREG_NO_PASSWD_YET) ||
727         ((int)message->request == UREG_GET_KRB &&
728          status == UREG_HALF_ENROLLED))
729     {
730         /* User is in proper state for this transaction. */
731         
732         passwd = message->leftover;
733         
734         /* Set password. */
735         if ((status = setpass_krb(message->db.login, passwd)) != SUCCESS)
736             /* If failure, allow login name to be used in client 
737                error message */
738             (void) strcpy(retval,message->db.login);
739         else
740             /* Otherwise, mark user as finished. */
741             status = set_final_status(message);
742     }
743
744     if (status)
745         com_err(whoami, status, " returned from set_passwd");
746     else
747         com_err(whoami, 0, "Password set");
748
749     return status;
750 }
751
752
753 int getuserinfo(argc, argv, qargv)
754 int argc;
755 char **argv;
756 char **qargv;
757 {
758     int status = SUCCESS;
759
760     if (argc != U_END) {
761         critical_alert(FAIL_INST,
762                        "Wrong number of args returned from get_user_by_uid");
763         status = MR_ABORT;
764     } else {
765         qargv[U_NAME] = strsave(argv[U_NAME]);
766         qargv[U_UID+1] = strsave(argv[U_UID]);
767         qargv[U_SHELL+1] = strsave(argv[U_SHELL]);
768         qargv[U_LAST+1] = strsave(argv[U_LAST]);
769         qargv[U_FIRST+1] = strsave(argv[U_FIRST]);
770         qargv[U_MIDDLE+1] = strsave(argv[U_MIDDLE]);
771         qargv[U_STATE+1] = strsave(argv[U_STATE]);
772         qargv[U_MITID+1] = strsave(argv[U_MITID]);
773         qargv[U_CLASS+1] = strsave(argv[U_CLASS]);
774         qargv[U_MODTIME+1] = NULL;
775     }
776     return(status);
777 }
778
779
780 int set_identity(message,retval)
781 struct msg *message;
782 char *retval;
783 {
784     int q_argc;                 /* Number of arguments to query */
785     char *q_argv[U_END];        /* Arguments to Moira query */
786     char *q_name;               /* Name of Moira query */
787     int status = SUCCESS;       /* General purpose error status */
788     char fstype_buf[7];         /* Buffer to hold fs_type, a 16 bit number */
789     char *login;                /* The login name the user wants */
790     register int i;             /* A counter */
791
792     /* Log that we are about to reserve a user. */
793     com_err(whoami, 0, "setting identity %s %s", 
794             message->first, message->last);
795     
796     /* Check to make sure that we can verify this user. */
797     status = verify_user(message,retval);
798     if (status == SUCCESS || status == UREG_NOT_ALLOWED)
799     {
800         status = SUCCESS;
801         /* Get the requested login name from leftover packet information. */
802         login = message->leftover;
803
804         /* Check the login name for validity.  The login name is currently
805            is allowed to contain lowercase letters in any position and 
806            and numbers and underscore characters in any position but the 
807            first. */
808         if ((strlen(login) < MIN_UNAME) || (strlen(login) > MAX_UNAME))
809             status = UREG_INVALID_UNAME;
810     }
811     if (status == SUCCESS)
812         if ((login[0] == '_') || isdigit(login[0]))
813             status = UREG_INVALID_UNAME;
814     if (status == SUCCESS)
815     {
816         for (i = 0; i < strlen(login); i++)
817             if (!islower(login[i]) && !isdigit(login[i]) && 
818                 (login[i] != '_'))
819             {
820                 status = UREG_INVALID_UNAME;
821                 break;
822             }
823     }
824     if (status == SUCCESS)
825     {
826         /* Now that we have a valid user with a valid login... */
827
828         q_argv[0] = message->db.uid;
829         status = mr_query("get_user_by_uid", 1, q_argv, getuserinfo, q_argv);
830         if (status != SUCCESS) {
831             com_err(whoami, status, " while getting user info");
832             return(status);
833         }
834         q_argv[U_NAME+1] = login;
835         q_argv[U_STATE+1] = "7";
836         status = mr_query("update_user", U_MODTIME+1, q_argv,
837                            null_callproc, NULL);
838         switch (status)
839         {
840           case MR_SUCCESS:
841             status = SUCCESS;
842             break;
843           case MR_IN_USE:
844             status = UREG_LOGIN_USED;
845             break;
846           case MR_DEADLOCK:
847             status = UREG_MISC_ERROR;
848             break;
849           default:
850             critical_alert(FAIL_INST,"%s returned from update_user.",
851                            error_message(status));
852             status = UREG_MISC_ERROR;
853             break;
854         }
855     }
856     if (status == SUCCESS)
857     {
858         /* Moira login was successfully created; try to reserve kerberos
859            principal. */
860         /* If this routine fails, store the login in the retval so
861            that it can be used in the client-side error message. */
862         if ((status = reserve_krb(login)) != SUCCESS)
863             (void) strcpy(retval, login);
864     }
865
866     if (status)
867         com_err(whoami, status, " returned from set_identity");
868     else
869         com_err(whoami, 0, "Identity set");
870     
871     return status;
872 }
873
874
875 void reg_com_err_hook(whoami, code, fmt, pvar)
876         char *whoami;
877         int code;
878         char *fmt;
879         caddr_t pvar;
880 {
881         if (whoami) {
882                 fputs(whoami, stderr);
883                 fputs(": ", stderr);
884         }
885         if (code) {
886                 fputs(error_message(code), stderr);
887         }
888         if (fmt) {
889                 _doprnt(fmt, pvar, stderr);
890         }
891         putc('\n', stderr);
892         fflush(stderr);
893 }
This page took 0.093201 seconds and 3 git commands to generate.