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