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