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