6 * Copyright (C) 1987, 1988 by the Massachusetts Institute of Technology
7 * For copying and distribution information, please see the file
10 * Server for user registration with Moira and Kerberos.
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.
19 static char *rcsid_reg_svr_c = "$Header$";
22 #include <mit-copyright.h>
27 #include <sys/types.h>
36 #include "moira_site.h"
39 extern char admin_errmsg[];
41 void reg_com_err_hook();
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 */
51 void req_initialize(); /* Initialize request layer */
52 void get_request(); /* Get a request */
53 void report(); /* Respond to a request */
58 /* Error messages sent one line at a time */
61 set_com_err_hook(reg_com_err_hook);
63 /* Initialize com_err error tables */
68 /* Use com_err or output to stderr for all log messages. */
70 com_err(whoami, 0, "*** Debugging messages enabled. ***");
73 /* Set the name of our kerberos ticket file */
74 krb_set_tkt_string("/tmp/tkt_ureg");
76 /* Connect to the Moira server */
77 if ((status = mr_connect(MOIRA_SERVER)) != MR_SUCCESS)
79 com_err(whoami, status, " on mr_connect");
83 /* Authorize, telling the server who you are */
84 if ((status = mr_auth(whoami)) != MR_SUCCESS)
86 com_err(whoami, status, " on mr_auth");
90 journal = fopen(REGJOURNAL, "a");
91 if (journal == NULL) {
92 com_err(whoami, errno, " while opening journal file");
96 /* Allow request layer to initialize */
99 /* Sit around waiting for requests from the client. */
102 get_request(&message);
104 switch((int)message.request)
106 case UREG_VERIFY_USER:
107 status = verify_user(&message,retval);
109 case UREG_RESERVE_LOGIN:
110 status = reserve_user(&message,retval);
112 case UREG_SET_PASSWORD:
114 status = set_password(&message,retval);
117 status = set_identity(&message,retval);
119 case UREG_GET_SECURE:
120 status = get_secure(&message,retval);
122 case UREG_SET_SECURE:
123 status = set_secure(&message,retval);
126 status = UREG_UNKNOWN_REQUEST;
127 critical_alert(FAIL_INST,"Unknown request %d from userreg.",
132 /* Report what happened to client */
133 report(status, retval);
137 int parse_encrypted(message,data)
138 struct msg *message; /* Formatted packet */
139 struct db_data *data; /* Data from the Moira database */
140 /* This routine makes sure that the ID from the database matches
141 the ID sent accross in the packet. The information in the packet
142 was created in the following way:
144 The database used to contain encrypted IDs. Now we don't encrypt
145 them in the database, although there are still some encrypted IDs
148 The plain text ID number was encrypted via EncryptID() resulting
149 in the form that would appear in the Moira database. This is
150 concatinated to the plain text ID so that the ID string contains plain
151 text ID followed by a null followed by the encrypted ID. Other
152 information such as the username or password is appended. The whole
153 thing is then DES encrypted using the encrypted ID as the source of
156 This routine tries each ID in the database that belongs
157 to someone with this user's first and last name and tries to
158 decrypt the packet with this information. If it succeeds, it returns
159 zero and initializes all the fields of the formatted packet structure
160 that depend on the encrypted information. */
162 des_cblock key; /* The key for DES en/decryption */
163 des_key_schedule sched; /* En/decryption schedule */
164 static char decrypt[BUFSIZ]; /* Buffer to hold decrypted information */
165 long decrypt_len; /* Length of decypted ID information */
166 char recrypt[14]; /* Buffer to hold re-encrypted information */
167 static char hashid[14]; /* Buffer to hold one-way encrypted ID */
168 char idnumber[BUFSIZ]; /* Buffer to hold plain-text ID */
169 char *temp; /* A temporary string pointer */
170 int len; /* Keeps track of length left in packet */
171 int status = SUCCESS; /* Error status */
174 com_err(whoami, 0, "Entering parse_encrypted");
177 /* Make the decrypted information length the same as the encrypted
178 information length. Both are integral multples of eight bytes
179 because of the DES encryption routines. */
180 decrypt_len = (long)message->encrypted_len;
182 /* Get key from the possibly one-way encrypted ID in the Moira database */
183 if (data->mit_id[0] >= '0' && data->mit_id[0] <= '9') {
186 EncryptID(buf, data->mit_id, message->first, message->last);
187 des_string_to_key(buf, key);
189 des_string_to_key(data->mit_id, key);
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-
196 des_pcbc_encrypt(message->encrypted, decrypt, decrypt_len,
197 sched, key, DES_DECRYPT);
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 (void) strncpy(idnumber,decrypt,(int)decrypt_len);
208 /* Check that the idnumber of a mismatched decryption doesn't overflow
211 if (strlen(idnumber) != 9) {
213 com_err(whoami, 0, "idnumber wrong size, probable user mismatch\n");
217 /* Point temp to the end of the plain text ID number. */
218 temp = decrypt + strlen(idnumber) + 1;
219 /* Find out how much more packet there is. */
220 len = message->encrypted_len - (temp - decrypt);
221 /* Copy the next CRYPT_LEN bytes of the decrypted information into
222 hashid if there are CRYPT_LEN more bytes to copy. There will be
223 if we have the right key. */
224 (void) strncpy(hashid, temp, min(len, CRYPT_LEN));
225 /* Point temp to the end of the encrypted ID field */
226 temp += strlen(hashid) + 1;
227 /* Find out how much more room there is. */
228 len = message->encrypted_len - (temp - decrypt);
230 /* Now compare encrypted ID and clear text ID for a match. */
231 if (strcmp(hashid, data->mit_id) &&
232 strcmp(idnumber, data->mit_id))
235 if (status == SUCCESS)
237 /* We made it. Now we can finish initializing message. */
238 /* Point leftover to whatever is left over! */
239 message->leftover = temp;
240 message->leftover_len = len;
241 /* Since we know we have the right user, fill in the information
242 from the Moira database. */
243 message->db.reg_status = data->reg_status;
244 (void) strncpy(message->db.uid,data->uid, sizeof(message->db.uid));
245 (void) strncpy(message->db.mit_id,data->mit_id,
246 sizeof(message->db.mit_id));
247 (void) strncpy(message->db.login,data->login, sizeof(message->db.login));
252 com_err(whoami, status, " in parse_encrypted");
254 com_err(whoami, status, "parse_encrypted succeeded");
260 int db_callproc(argc,argv,queue)
261 int argc; /* Number of arguments returned by Moira */
262 char *argv[]; /* Arguments returned by Moira */
263 struct save_queue *queue; /* Queue to save information in */
264 /* This function is called by mr_query after each tuple found. It is
265 used by find_user to cache information about each user found. */
267 struct db_data *data; /* Structure to store the information in */
268 int status = SUCCESS; /* Error status */
271 com_err(whoami, 0, "Entering db_callproc.");
278 "Wrong number of arguments returned from get_user_account_by_name.");
283 /* extract the needed information from the results of the Moira query */
284 data = (struct db_data *)malloc(sizeof(struct db_data));
285 data->reg_status = atoi(argv[U_STATE]);
286 (void) strncpy(data->login,argv[U_NAME],sizeof(data->login));
287 (void) strncpy(data->mit_id,argv[U_MITID],sizeof(data->mit_id));
288 (void) strncpy(data->uid,argv[U_UID],sizeof(data->uid));
290 fprintf(stderr,"Found in database:\n");
291 fprintf(stderr," Registration status: %d\n",data->reg_status);
292 fprintf(stderr," login: %s\n",data->login);
293 fprintf(stderr," MIT ID: %s\n",data->mit_id);
294 fprintf(stderr," uid: %s\n",data->uid);
296 sq_save_data(queue,data);
302 int find_user(message)
303 struct msg *message; /* Formatted packet structure */
304 /* This routine verifies that a user is allowed to register by finding
305 him/her in the Moira database. It returns the status of the Moira
306 query that it calls. */
308 #define GUBN_ARGS 2 /* Arguements needed by get_user_by_name */
309 char *q_name; /* Name of query */
310 int q_argc; /* Number of arguments for query */
311 char *q_argv[GUBN_ARGS]; /* Arguments to query */
312 int status = SUCCESS; /* Query return status */
314 struct save_queue *queue; /* Queue to hold Moira data */
315 struct db_data *data; /* Structure for data for one tuple */
316 short verified = FALSE; /* Have we verified the user? */
318 /* Zero the mit_id field in the formatted packet structure. This
319 being zeroed means that no user was found. */
320 bzero(message->db.mit_id,sizeof(message->db.mit_id));
322 if (status == SUCCESS)
324 /* Get ready to make an Moira query */
325 q_name = "get_user_account_by_name";
326 q_argc = GUBN_ARGS; /* #defined in this routine */
327 q_argv[0] = message->first;
328 q_argv[1] = message->last;
330 /* Create queue to hold information */
334 status = mr_query(q_name,q_argc,q_argv,db_callproc,(char *)queue);
337 fprintf(stderr," %d returned by get_user_by_name\n",status);
340 if (status == MR_SUCCESS)
342 /* Traverse the list, freeing data as we go. If sq_get_data()
343 returns zero if there is no more data on the queue. */
344 while (sq_get_data(queue,&data))
347 /* parse_encrypted returns zero on success */
348 verified = (parse_encrypted(message,data) == SUCCESS);
353 /* Destroy the queue */
358 fprintf(stderr,"Returned from find_user\n");
359 fprintf(stderr," MIT ID: %s\n", message->db.mit_id);
360 fprintf(stderr," Registration status: %d\n",message->db.reg_status);
361 fprintf(stderr," uid: %s\n",message->db.uid);
362 fprintf(stderr," login: %s\n",message->db.login);
363 fprintf(stderr," Status from query: %d\n",status);
369 int verify_user(message,retval)
372 /* This routine determines whether a user is in the databse and returns
373 his state so that other routines can figure out whether he is the
374 correct state for various transactions. */
377 int status = SUCCESS; /* Return status */
379 /* Log that we are about to veryify user */
380 com_err(whoami, 0, "verifying user %s %s",message->first,message->last);
382 /* Figure out what user (if any) can be found based on the
383 encrypted information in the packet. (See the comment on
384 parse_encrypted().) */
386 status = find_user(message);
388 /* If Moira coudn't find the user */
389 if (status == MR_NO_MATCH)
390 status = UREG_USER_NOT_FOUND;
391 else if (status == MR_SUCCESS)
393 /* If the information sent over in the packet did not point to a
394 valid user, the mit_id field in the formatted packet structure
396 if (message->db.mit_id[0] == NULL)
397 status = UREG_USER_NOT_FOUND;
398 /* If the user was found but the registration has already started,
399 use this as the status */
402 switch (message->db.reg_status)
404 case US_NO_LOGIN_YET:
408 status = UREG_ALREADY_REGISTERED;
411 status = UREG_NO_PASSWD_YET;
414 status = UREG_DELETED;
417 status = UREG_NOT_ALLOWED;
420 status = UREG_ENROLLED;
422 case US_ENROLL_NOT_ALLOWED:
423 status = UREG_ENROLL_NOT_ALLOWED;
425 case US_HALF_ENROLLED:
426 status = UREG_HALF_ENROLLED;
429 status = UREG_MISC_ERROR;
430 critical_alert(FAIL_INST,"Bad user state %d for login %s.",
431 message->db.reg_status, message->db.login);
434 /* Set retval to the login name so that the client can use
435 it in the error message it will give the user. */
436 (void) strcpy(retval,message->db.login);
441 com_err(whoami, status, " returned from verify_user");
443 com_err(whoami, 0, "User verified");
450 unsigned int status = SUCCESS; /* Return status */
451 static char krbrealm[REALM_SZ]; /* kerberos realm name */
452 static char hostbuf[BUFSIZ], *host; /* local hostname in principal fmt */
453 static int inited = 0;
457 com_err(whoami, 0, "Entering ureg_kadm_init");
462 bzero(krbrealm, sizeof(krbrealm));
463 if (status = krb_get_lrealm(krbrealm, 1)) {
464 status += krb_err_base;
465 com_err(whoami, status, " fetching kerberos realm");
468 if (gethostname(hostbuf, sizeof(hostbuf)) < 0)
469 com_err(whoami, errno, "getting local hostname");
470 host = canonicalize_hostname(strsave(hostbuf));
471 for (p = host; *p && *p != '.'; p++)
477 /* Get keys for interacting with Kerberos admin server. */
478 /* principal, instance, realm, service, service instance, life, file */
479 if (status = krb_get_svc_in_tkt(MOIRA_SNAME, host, krbrealm, PWSERV_NAME,
480 KADM_SINST, 1, KEYFILE))
481 status += krb_err_base;
483 if (status != SUCCESS)
484 com_err(whoami, status, " while get admin tickets");
487 com_err(whoami, status, "Succeeded in getting admin tickets");
491 if (status == SUCCESS) {
492 if ((status = kadm_init_link(PWSERV_NAME, KADM_SINST, krbrealm)) !=
494 com_err(whoami, status, " while initializing kadmin connection");
501 int null_callproc(argc,argv,message)
505 /* This routine is a null callback that should be used for queries that
506 do not return tuples. If it ever gets called, something is wrong. */
508 critical_alert(FAIL_INST,"Something returned from an update query.");
513 * This routine reserves a principal in kerberos by setting up a
514 * principal with a random initial key.
516 int reserve_krb(login)
519 int status = SUCCESS;
522 u_long *lkey = (u_long *)key;
525 com_err(whoami, 0, "Entering reserve_krb");
528 if ((status = ureg_kadm_init()) == SUCCESS) {
529 bzero((char *)&new, sizeof(new));
530 SET_FIELD(KADM_DESKEY, new.fields);
531 SET_FIELD(KADM_NAME, new.fields);
533 (void) des_random_key(key);
534 new.key_low = htonl(lkey[0]);
535 new.key_high = htonl(lkey[1]);
536 strcpy(new.name, login);
538 com_err(whoami, 0, "Creating kerberos principal for %s", login);
539 status = kadm_add(&new);
540 if (status != KADM_SUCCESS)
541 com_err(whoami, status, " while reserving principal");
543 bzero((char *)&new, sizeof(new));
552 * This routine reserves a principal in kerberos by setting up a
553 * principal with a random initial key.
555 int setpass_krb(login, password)
559 int status = SUCCESS;
562 u_long *lkey = (u_long *)key;
564 if ((status = ureg_kadm_init()) == SUCCESS) {
565 bzero((char *)&new, sizeof(new));
566 SET_FIELD(KADM_DESKEY, new.fields);
567 SET_FIELD(KADM_NAME, new.fields);
569 (void) des_string_to_key(password, key);
570 new.key_low = htonl(lkey[0]);
571 new.key_high = htonl(lkey[1]);
572 strcpy(new.name, login);
574 com_err(whoami, 0, "Setting password for %s", login);
575 /* First arguement is not used if user has modify privileges */
576 if ((status = kadm_mod(&new, &new)) != KADM_SUCCESS) {
577 if (status == KADM_NOENTRY) {
579 "kerberos principal doesn't exist; creating");
580 if ((status = kadm_add(&new)) != KADM_SUCCESS)
581 com_err(whoami, status,
582 " while creating kerberos principal");
585 com_err(whoami, status, " while setting password");
593 int reserve_user(message,retval)
597 int q_argc; /* Number of arguments to query */
598 char *q_argv[3]; /* Arguments to Moira query */
599 char *q_name; /* Name of Moira query */
600 int status = SUCCESS; /* General purpose error status */
601 char fstype_buf[7]; /* Buffer to hold fs_type, a 16 bit number */
602 char *login; /* The login name the user wants */
603 register int i; /* A counter */
605 /* Log that we are about to reserve a user. */
606 com_err(whoami, 0, "reserving user %s %s",
607 message->first, message->last);
609 /* Check to make sure that we can verify this user. */
610 if ((status = verify_user(message,retval)) == SUCCESS)
612 /* Get the requested login name from leftover packet information. */
613 login = message->leftover;
615 /* Check the login name for validity. The login name is currently
616 is allowed to contain lowercase letters in any position and
617 and numbers and underscore characters in any position but the
619 if ((strlen(login) < MIN_UNAME) || (strlen(login) > MAX_UNAME))
620 status = UREG_INVALID_UNAME;
622 if (status == SUCCESS)
623 if ((login[0] == '_') || isdigit(login[0]))
624 status = UREG_INVALID_UNAME;
626 if (status == SUCCESS)
628 for (i = 0; i < strlen(login); i++)
629 if (!islower(login[i]) && !isdigit(login[i]) &&
632 status = UREG_INVALID_UNAME;
636 if (status == SUCCESS)
638 /* Now that we have a valid user with a valid login... */
640 /* First, try to reserve the user in Moira. */
641 (void) sprintf(fstype_buf,"%d",MR_FS_STUDENT);
642 q_name = "register_user";
643 q_argv[0] = message->db.uid;
645 q_argv[2] = fstype_buf;
647 status = mr_query(q_name,q_argc,q_argv,null_callproc,(char *)0);
654 status = UREG_LOGIN_USED;
657 status = UREG_MISC_ERROR;
660 critical_alert(FAIL_INST,"%s returned from register_user.",
661 error_message(status));
662 status = UREG_MISC_ERROR;
667 if (status == SUCCESS)
670 * Moira login was successfully created; try to reserve kerberos
673 * If this routine fails, store the login in the retval so
674 * that it can be used in the client-side error message.
676 if ((status = reserve_krb(login)) != SUCCESS)
677 (void) strcpy(retval, login);
681 com_err(whoami, status, " returned from reserve_user");
683 com_err(whoami, 0, "User reserved");
689 int set_final_status(message)
691 /* This routine updates a user's registration status to fully
695 char *q_name; /* Name of Moira query */
696 int q_argc; /* Number of arguments for Moira query */
697 char *q_argv[2]; /* Arguments to get user by uid */
698 char state[7]; /* Can hold a 16 bit integer */
699 int status; /* Error status */
701 if (message->request == UREG_SET_PASSWORD)
702 (void) sprintf(state,"%d",US_REGISTERED);
703 else if (message->db.reg_status == US_NO_LOGIN_YET)
704 (void) sprintf(state,"%d",US_ENROLLED);
706 (void) sprintf(state,"%d",US_ENROLL_NOT_ALLOWED);
708 login = message->db.login;
709 com_err(whoami, 0, "Setting final status for %s to %s", login, state);
711 q_name = "update_user_status";
715 if ((status = mr_query(q_name, q_argc, q_argv, null_callproc,
716 (char *)0)) != MR_SUCCESS) {
717 if (status == MR_DEADLOCK)
718 status = UREG_MISC_ERROR;
720 critical_alert(FAIL_INST,"%s returned from update_user_status.",
721 error_message(status));
724 com_err(whoami, status, " returned from set_final_status");
726 com_err(whoami, 0, "Final status set");
731 int set_password(message,retval)
734 /* This routine is used to set the initial password for the new user. */
736 int status = SUCCESS; /* Return status */
737 char *passwd; /* User's password */
739 com_err(whoami, 0, "setting password %s %s",
740 message->first, message->last);
742 status = verify_user(message,retval);
744 /* Don't set the password unless the registration status of the user
745 is that he exists and has no password. */
746 if (status == SUCCESS)
747 status = UREG_NO_LOGIN_YET;
748 if (((int)message->request == UREG_SET_PASSWORD &&
749 status == UREG_NO_PASSWD_YET) ||
750 ((int)message->request == UREG_GET_KRB &&
751 status == UREG_HALF_ENROLLED))
753 /* User is in proper state for this transaction. */
755 passwd = message->leftover;
758 if ((status = setpass_krb(message->db.login, passwd)) != SUCCESS)
759 /* If failure, allow login name to be used in client
761 (void) strcpy(retval,message->db.login);
763 /* Otherwise, mark user as finished. */
764 status = set_final_status(message);
768 com_err(whoami, status, " returned from set_passwd");
770 com_err(whoami, 0, "Password set");
776 int getuserinfo(argc, argv, qargv)
781 int status = SUCCESS;
785 critical_alert(FAIL_INST,
786 "Wrong number of args returned from get_user_by_uid");
789 qargv[U_NAME] = strsave(argv[U_NAME]);
790 for (i = 1; i < U_MODTIME; i++)
791 qargv[i+1] = strsave(argv[i]);
792 qargv[U_MODTIME+1] = NULL;
798 int set_identity(message,retval)
802 int q_argc; /* Number of arguments to query */
803 char *q_argv[U_END]; /* Arguments to Moira query */
804 char *q_name; /* Name of Moira query */
805 int status = SUCCESS; /* General purpose error status */
806 char fstype_buf[7]; /* Buffer to hold fs_type, a 16 bit number */
807 char *login; /* The login name the user wants */
808 register int i; /* A counter */
810 /* Log that we are about to reserve a user. */
811 com_err(whoami, 0, "setting identity %s %s",
812 message->first, message->last);
814 /* Check to make sure that we can verify this user. */
815 status = verify_user(message,retval);
816 if (status == SUCCESS || status == UREG_NOT_ALLOWED)
819 /* Get the requested login name from leftover packet information. */
820 login = message->leftover;
822 /* Check the login name for validity. The login name is currently
823 is allowed to contain lowercase letters in any position and
824 and numbers and underscore characters in any position but the
826 if ((strlen(login) < MIN_UNAME) || (strlen(login) > MAX_UNAME))
827 status = UREG_INVALID_UNAME;
829 if (status == SUCCESS)
830 if ((login[0] == '_') || isdigit(login[0]))
831 status = UREG_INVALID_UNAME;
832 if (status == SUCCESS)
834 for (i = 0; i < strlen(login); i++)
835 if (!islower(login[i]) && !isdigit(login[i]) &&
838 status = UREG_INVALID_UNAME;
842 if (status == SUCCESS)
844 /* Now that we have a valid user with a valid login... */
846 q_argv[0] = message->db.uid;
847 status = mr_query("get_user_account_by_uid", 1, q_argv,
848 getuserinfo, q_argv);
849 if (status != SUCCESS) {
850 com_err(whoami, status, " while getting user info");
853 q_argv[U_NAME+1] = login;
854 q_argv[U_STATE+1] = "7";
855 status = mr_query("update_user_account", U_MODTIME+1, q_argv,
856 null_callproc, NULL);
863 status = UREG_LOGIN_USED;
866 status = UREG_MISC_ERROR;
869 critical_alert(FAIL_INST,"%s returned from update_user_account.",
870 error_message(status));
871 status = UREG_MISC_ERROR;
875 if (status == SUCCESS)
877 /* Moira login was successfully created; try to reserve kerberos
879 /* If this routine fails, store the login in the retval so
880 that it can be used in the client-side error message. */
881 if ((status = reserve_krb(login)) != SUCCESS)
882 (void) strcpy(retval, login);
886 com_err(whoami, status, " returned from set_identity");
888 com_err(whoami, 0, "Identity set");
894 void reg_com_err_hook(whoami, code, fmt, pvar)
901 fputs(whoami, stderr);
905 fputs(error_message(code), stderr);
908 _doprnt(fmt, pvar, stderr);
915 /* Find out of someone's secure instance password is set.
916 * Returns UREG_ALREADY_REGISTERED if set, SUCCESS (0) if not.
919 int get_secure(message, retval)
926 com_err(whoami, 0, "checking status of secure password for %s",
928 argv[0] = message->first;
929 status = mr_query("get_user_account_by_login", 1, argv, getuserinfo, argv);
930 if (status != SUCCESS) {
931 com_err(whoami, status, " while getting user info");
934 if (atoi(argv[U_SECURE + 1]))
935 return UREG_ALREADY_REGISTERED;
940 /* Set someone's secure instance password. */
942 int set_secure(message, retval)
947 char *argv[U_END], hostbuf[256], *bp, *p, buf[512], *passwd, *id;
953 u_long *lkey = (u_long *)key;
955 static int inited = 0;
960 if (gethostname(hostbuf, sizeof(hostbuf)) < 0)
961 com_err(whoami, errno, "getting local hostname");
962 host = strsave(krb_get_phost(hostbuf));
965 com_err(whoami, 0, "setting secure passwd for %s", message->first);
966 argv[0] = message->first;
967 status = mr_query("get_user_account_by_login", 1, argv, getuserinfo, argv);
968 if (status != SUCCESS) {
969 com_err(whoami, status, " while getting user info");
972 if (atoi(argv[U_SECURE + 1])) {
973 com_err(whoami, UREG_ALREADY_REGISTERED, "in set_secure()");
974 return UREG_ALREADY_REGISTERED;
977 bp = message->encrypted;
978 /* round up to word boundary */
979 bp = (char *)((((u_long)bp + 3) >> 2) << 2);
981 creds.length = ntohl(*((int *)bp));
983 bcopy(bp, creds.dat, creds.length);
988 com_err(whoami, 0, "Cred: length %d", creds.length);
989 for (i = 0; i < creds.length; i += 16)
990 com_err(whoami, 0, " %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
991 creds.dat[i+0], creds.dat[i+1], creds.dat[i+2], creds.dat[i+3],
992 creds.dat[i+4], creds.dat[i+5], creds.dat[i+6], creds.dat[i+7],
993 creds.dat[i+8], creds.dat[i+9], creds.dat[i+10], creds.dat[i+11],
994 creds.dat[i+12], creds.dat[i+13], creds.dat[i+14], creds.dat[i+15]);
997 status = krb_rd_req(&creds, "changepw", host, cur_req_sender(),
1000 status += krb_err_base;
1001 com_err(whoami, status, " verifying credentials in set_secure()");
1005 message->leftover_len = ntohl(*((int*)(bp)));
1007 message->leftover = bp;
1009 des_key_sched(auth.session, keys);
1010 des_pcbc_encrypt(message->leftover, buf, message->leftover_len,
1011 keys, auth.session, 0);
1014 passwd = index(buf, ',');
1017 com_err(whoami, 0, "Got id: %s, passwd %d chars", id, strlen(passwd));
1020 if (strcmp(id, argv[U_MITID + 1])) {
1021 status = UREG_USER_NOT_FOUND;
1022 com_err(whoami, status, "IDs mismatch: %s, %s", id, argv[U_MITID + 1]);
1026 /* now do actual password setting stuff */
1028 if ((status = ureg_kadm_init()) != SUCCESS) {
1029 com_err(whoami, status, "initing kadm stuff");
1033 bzero((char *)&kv, sizeof(kv));
1034 SET_FIELD(KADM_DESKEY, kv.fields);
1035 SET_FIELD(KADM_NAME, kv.fields);
1036 SET_FIELD(KADM_INST, kv.fields);
1037 (void) des_string_to_key(passwd, key);
1038 kv.key_low = htonl(lkey[0]);
1039 kv.key_high = htonl(lkey[1]);
1040 strcpy(kv.name, message->first);
1041 strcpy(kv.instance, "extra");
1043 if ((status = kadm_add(&kv)) != KADM_SUCCESS) {
1044 com_err(whoami, status, " while creating kerberos principal");
1048 argv[0] = message->first;
1050 gettimeofday(&now, NULL);
1051 sprintf(buf, "%d", now.tv_sec);
1052 status = mr_query("update_user_security_status", 2, argv, getuserinfo, argv);
1053 if (status != SUCCESS) {
1054 com_err(whoami, status, " while updating user status");