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>
37 #include "moira_site.h"
40 extern char admin_errmsg[];
42 void reg_com_err_hook();
48 struct msg message; /* Storage for parsed packet */
49 int status = SUCCESS; /* Error status */
50 char retval[BUFSIZ]; /* Buffer to hold return message for client */
52 void req_initialize(); /* Initialize request layer */
53 void get_request(); /* Get a request */
54 void report(); /* Respond to a request */
59 /* Error messages sent one line at a time */
60 setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
61 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
62 set_com_err_hook(reg_com_err_hook);
64 /* Initialize com_err error tables */
68 initialize_gdss_error_table();
70 /* Use com_err or output to stderr for all log messages. */
72 com_err(whoami, 0, "*** Debugging messages enabled. ***");
75 /* Set the name of our kerberos ticket file */
76 krb_set_tkt_string("/tmp/tkt_ureg");
78 /* Connect to the Moira server */
79 if ((status = mr_connect(MOIRA_SERVER)) != MR_SUCCESS)
81 com_err(whoami, status, " on mr_connect");
85 /* Authorize, telling the server who you are */
86 if ((status = mr_auth(whoami)) != MR_SUCCESS)
88 com_err(whoami, status, " on mr_auth");
92 journal = fopen(REGJOURNAL, "a");
93 if (journal == NULL) {
94 com_err(whoami, errno, " while opening journal file");
98 /* Allow request layer to initialize */
101 /* Sit around waiting for requests from the client. */
104 get_request(&message);
106 switch((int)message.request)
108 case UREG_VERIFY_USER:
109 status = verify_user(&message,retval);
111 case UREG_RESERVE_LOGIN:
112 status = reserve_user(&message,retval);
114 case UREG_SET_PASSWORD:
116 status = set_password(&message,retval);
119 status = set_identity(&message,retval);
121 case UREG_GET_SECURE:
122 status = get_secure(&message,retval);
124 case UREG_SET_SECURE:
125 status = set_secure(&message,retval);
128 status = UREG_UNKNOWN_REQUEST;
129 critical_alert(FAIL_INST,"Unknown request %d from userreg.",
134 /* Report what happened to client */
135 report(status, retval);
139 int parse_encrypted(message,data)
140 struct msg *message; /* Formatted packet */
141 struct db_data *data; /* Data from the Moira database */
142 /* This routine makes sure that the ID from the database matches
143 the ID sent accross in the packet. The information in the packet
144 was created in the following way:
146 The database used to contain encrypted IDs. Now we don't encrypt
147 them in the database, although there are still some encrypted IDs
150 The plain text ID number was encrypted via EncryptID() resulting
151 in the form that would appear in the Moira database. This is
152 concatinated to the plain text ID so that the ID string contains plain
153 text ID followed by a null followed by the encrypted ID. Other
154 information such as the username or password is appended. The whole
155 thing is then DES encrypted using the encrypted ID as the source of
158 This routine tries each ID in the database that belongs
159 to someone with this user's first and last name and tries to
160 decrypt the packet with this information. If it succeeds, it returns
161 zero and initializes all the fields of the formatted packet structure
162 that depend on the encrypted information. */
164 des_cblock key; /* The key for DES en/decryption */
165 des_key_schedule sched; /* En/decryption schedule */
166 static char decrypt[BUFSIZ]; /* Buffer to hold decrypted information */
167 long decrypt_len; /* Length of decypted ID information */
168 char recrypt[14]; /* Buffer to hold re-encrypted 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 */
176 com_err(whoami, 0, "Entering parse_encrypted");
179 /* Make the decrypted information length the same as the encrypted
180 information length. Both are integral multples of eight bytes
181 because of the DES encryption routines. */
182 decrypt_len = (long)message->encrypted_len;
184 /* Get key from the possibly one-way encrypted ID in the Moira database */
185 if (data->mit_id[0] >= '0' && data->mit_id[0] <= '9') {
188 EncryptID(buf, data->mit_id, message->first, message->last);
189 des_string_to_key(buf, key);
191 des_string_to_key(data->mit_id, key);
193 /* Get schedule from key */
194 des_key_sched(key, sched);
195 /* Decrypt information from packet using this key. Since decrypt_len
196 is an integral multiple of eight bytes, it will probably be null-
198 des_pcbc_encrypt(message->encrypted, decrypt, decrypt_len,
199 sched, key, DES_DECRYPT);
201 /* Extract the plain text and encrypted ID fields from the decrypted
202 packet information. */
203 /* Since the decrypted information starts with the plain-text ID
204 followed by a null, if the decryption worked, this will only
205 copy the plain text part of the decrypted information. It is
206 important that strncpy be used because if we are not using the
207 correct key, there is no guarantee that a null will occur
208 anywhere in the string. */
209 (void) strncpy(idnumber,decrypt,(int)decrypt_len);
210 /* Check that the idnumber of a mismatched decryption doesn't overflow
213 if (strlen(idnumber) != 9) {
215 com_err(whoami, 0, "idnumber wrong size, probable user mismatch\n");
219 /* Point temp to the end of the plain text ID number. */
220 temp = decrypt + strlen(idnumber) + 1;
221 /* Find out how much more packet there is. */
222 len = message->encrypted_len - (temp - decrypt);
223 /* Copy the next CRYPT_LEN bytes of the decrypted information into
224 hashid if there are CRYPT_LEN more bytes to copy. There will be
225 if we have the right key. */
226 (void) strncpy(hashid, temp, min(len, CRYPT_LEN));
227 /* Point temp to the end of the encrypted ID field */
228 temp += strlen(hashid) + 1;
229 /* Find out how much more room there is. */
230 len = message->encrypted_len - (temp - decrypt);
232 /* Now compare encrypted ID and clear text ID for a match. */
233 if (strcmp(hashid, data->mit_id) &&
234 strcmp(idnumber, data->mit_id))
237 if (status == SUCCESS)
239 /* We made it. Now we can finish initializing message. */
240 /* Point leftover to whatever is left over! */
241 message->leftover = temp;
242 message->leftover_len = len;
243 /* Since we know we have the right user, fill in the information
244 from the Moira database. */
245 message->db.reg_status = data->reg_status;
246 (void) strncpy(message->db.uid,data->uid, sizeof(message->db.uid));
247 (void) strncpy(message->db.mit_id,data->mit_id,
248 sizeof(message->db.mit_id));
249 (void) strncpy(message->db.login,data->login, sizeof(message->db.login));
254 com_err(whoami, status, " in parse_encrypted");
256 com_err(whoami, status, "parse_encrypted succeeded");
262 int db_callproc(argc,argv,queue)
263 int argc; /* Number of arguments returned by Moira */
264 char *argv[]; /* Arguments returned by Moira */
265 struct save_queue *queue; /* Queue to save information in */
266 /* This function is called by mr_query after each tuple found. It is
267 used by find_user to cache information about each user found. */
269 struct db_data *data; /* Structure to store the information in */
270 int status = SUCCESS; /* Error status */
273 com_err(whoami, 0, "Entering db_callproc.");
280 "Wrong number of arguments returned from get_user_account_by_name.");
285 /* extract the needed information from the results of the Moira query */
286 data = (struct db_data *)malloc(sizeof(struct db_data));
287 data->reg_status = atoi(argv[U_STATE]);
288 (void) strncpy(data->login,argv[U_NAME],sizeof(data->login));
289 (void) strncpy(data->mit_id,argv[U_MITID],sizeof(data->mit_id));
290 (void) strncpy(data->uid,argv[U_UID],sizeof(data->uid));
292 fprintf(stderr,"Found in database:\n");
293 fprintf(stderr," Registration status: %d\n",data->reg_status);
294 fprintf(stderr," login: %s\n",data->login);
295 fprintf(stderr," MIT ID: %s\n",data->mit_id);
296 fprintf(stderr," uid: %s\n",data->uid);
298 sq_save_data(queue,data);
304 int find_user(message)
305 struct msg *message; /* Formatted packet structure */
306 /* This routine verifies that a user is allowed to register by finding
307 him/her in the Moira database. It returns the status of the Moira
308 query that it calls. */
310 #define GUBN_ARGS 2 /* Arguements needed by get_user_by_name */
311 char *q_name; /* Name of query */
312 int q_argc; /* Number of arguments for query */
313 char *q_argv[GUBN_ARGS]; /* Arguments to query */
314 int status = SUCCESS; /* Query return status */
316 struct save_queue *queue; /* Queue to hold Moira data */
317 struct db_data *data; /* Structure for data for one tuple */
318 short verified = FALSE; /* Have we verified the user? */
320 /* Zero the mit_id field in the formatted packet structure. This
321 being zeroed means that no user was found. */
322 memset(message->db.mit_id,0,sizeof(message->db.mit_id));
324 if (status == SUCCESS)
326 /* Get ready to make an Moira query */
327 q_name = "get_user_account_by_name";
328 q_argc = GUBN_ARGS; /* #defined in this routine */
329 q_argv[0] = message->first;
330 q_argv[1] = message->last;
332 /* Create queue to hold information */
336 status = mr_query(q_name,q_argc,q_argv,db_callproc,(char *)queue);
339 fprintf(stderr," %d returned by get_user_by_name\n",status);
342 if (status == MR_SUCCESS)
344 /* Traverse the list, freeing data as we go. If sq_get_data()
345 returns zero if there is no more data on the queue. */
346 while (sq_get_data(queue,&data))
349 /* parse_encrypted returns zero on success */
350 verified = (parse_encrypted(message,data) == SUCCESS);
355 /* Destroy the queue */
360 fprintf(stderr,"Returned from find_user\n");
361 fprintf(stderr," MIT ID: %s\n", message->db.mit_id);
362 fprintf(stderr," Registration status: %d\n",message->db.reg_status);
363 fprintf(stderr," uid: %s\n",message->db.uid);
364 fprintf(stderr," login: %s\n",message->db.login);
365 fprintf(stderr," Status from query: %d\n",status);
371 int verify_user(message,retval)
374 /* This routine determines whether a user is in the databse and returns
375 his state so that other routines can figure out whether he is the
376 correct state for various transactions. */
379 int status = SUCCESS; /* Return status */
381 /* Log that we are about to veryify user */
382 com_err(whoami, 0, "verifying user %s %s",message->first,message->last);
384 /* Figure out what user (if any) can be found based on the
385 encrypted information in the packet. (See the comment on
386 parse_encrypted().) */
388 status = find_user(message);
390 /* If Moira coudn't find the user */
391 if (status == MR_NO_MATCH)
392 status = UREG_USER_NOT_FOUND;
393 else if (status == MR_SUCCESS)
395 /* If the information sent over in the packet did not point to a
396 valid user, the mit_id field in the formatted packet structure
398 if (message->db.mit_id[0] == '\0')
399 status = UREG_USER_NOT_FOUND;
400 /* If the user was found but the registration has already started,
401 use this as the status */
404 switch (message->db.reg_status)
406 case US_NO_LOGIN_YET:
410 status = UREG_ALREADY_REGISTERED;
413 status = UREG_NO_PASSWD_YET;
416 status = UREG_DELETED;
419 status = UREG_NOT_ALLOWED;
422 status = UREG_ENROLLED;
424 case US_ENROLL_NOT_ALLOWED:
425 status = UREG_ENROLL_NOT_ALLOWED;
427 case US_HALF_ENROLLED:
428 status = UREG_HALF_ENROLLED;
431 status = UREG_MISC_ERROR;
432 critical_alert(FAIL_INST,"Bad user state %d for login %s.",
433 message->db.reg_status, message->db.login);
436 /* Set retval to the login name so that the client can use
437 it in the error message it will give the user. */
438 (void) strcpy(retval,message->db.login);
443 com_err(whoami, status, " returned from verify_user");
445 com_err(whoami, 0, "User verified");
452 unsigned int status = SUCCESS; /* Return status */
453 static char krbrealm[REALM_SZ]; /* kerberos realm name */
454 static char hostbuf[BUFSIZ], *host; /* local hostname in principal fmt */
455 static int inited = 0;
459 com_err(whoami, 0, "Entering ureg_kadm_init");
464 memset(krbrealm, 0, sizeof(krbrealm));
465 if (status = krb_get_lrealm(krbrealm, 1)) {
466 status += krb_err_base;
467 com_err(whoami, status, " fetching kerberos realm");
470 if (gethostname(hostbuf, sizeof(hostbuf)) < 0)
471 com_err(whoami, errno, "getting local hostname");
472 host = canonicalize_hostname(strsave(hostbuf));
473 for (p = host; *p && *p != '.'; p++)
479 /* Get keys for interacting with Kerberos admin server. */
480 /* principal, instance, realm, service, service instance, life, file */
481 if (status = krb_get_svc_in_tkt(MOIRA_SNAME, host, krbrealm, PWSERV_NAME,
482 KADM_SINST, 1, KEYFILE))
483 status += krb_err_base;
485 if (status != SUCCESS)
486 com_err(whoami, status, " while get admin tickets");
489 com_err(whoami, status, "Succeeded in getting admin tickets");
493 if (status == SUCCESS) {
494 if ((status = kadm_init_link(PWSERV_NAME, KADM_SINST, krbrealm)) !=
496 com_err(whoami, status, " while initializing kadmin connection");
503 int null_callproc(argc,argv,message)
507 /* This routine is a null callback that should be used for queries that
508 do not return tuples. If it ever gets called, something is wrong. */
510 critical_alert(FAIL_INST,"Something returned from an update query.");
515 * This routine reserves a principal in kerberos by setting up a
516 * principal with a random initial key.
518 int reserve_krb(login)
521 int status = SUCCESS;
524 u_long *lkey = (u_long *)key;
527 com_err(whoami, 0, "Entering reserve_krb");
530 if ((status = ureg_kadm_init()) == SUCCESS) {
531 memset(&new, 0, sizeof(new));
532 SET_FIELD(KADM_DESKEY, new.fields);
533 SET_FIELD(KADM_NAME, new.fields);
535 (void) des_random_key(key);
536 new.key_low = htonl(lkey[0]);
537 new.key_high = htonl(lkey[1]);
538 strcpy(new.name, login);
540 com_err(whoami, 0, "Creating kerberos principal for %s", login);
541 status = kadm_add(&new);
542 if (status != KADM_SUCCESS)
543 com_err(whoami, status, " while reserving principal");
545 memset(&new, 0, sizeof(new));
554 * This routine reserves a principal in kerberos by setting up a
555 * principal with a random initial key.
557 int setpass_krb(login, password)
561 int status = SUCCESS;
564 u_long *lkey = (u_long *)key;
566 if ((status = ureg_kadm_init()) == SUCCESS) {
567 memset(&new, 0, sizeof(new));
568 SET_FIELD(KADM_DESKEY, new.fields);
569 SET_FIELD(KADM_NAME, new.fields);
571 (void) des_string_to_key(password, key);
572 new.key_low = htonl(lkey[0]);
573 new.key_high = htonl(lkey[1]);
574 strcpy(new.name, login);
576 com_err(whoami, 0, "Setting password for %s", login);
577 /* First arguement is not used if user has modify privileges */
578 if ((status = kadm_mod(&new, &new)) != KADM_SUCCESS) {
579 if (status == KADM_NOENTRY) {
581 "kerberos principal doesn't exist; creating");
582 if ((status = kadm_add(&new)) != KADM_SUCCESS)
583 com_err(whoami, status,
584 " while creating kerberos principal");
587 com_err(whoami, status, " while setting password");
595 int reserve_user(message,retval)
599 int q_argc; /* Number of arguments to query */
600 char *q_argv[3]; /* Arguments to Moira query */
601 char *q_name; /* Name of Moira query */
602 int status = SUCCESS; /* General purpose error status */
603 char fstype_buf[7]; /* Buffer to hold fs_type, a 16 bit number */
604 char *login; /* The login name the user wants */
605 register int i; /* A counter */
607 /* Log that we are about to reserve a user. */
608 com_err(whoami, 0, "reserving user %s %s",
609 message->first, message->last);
611 /* Check to make sure that we can verify this user. */
612 if ((status = verify_user(message,retval)) == SUCCESS)
614 /* Get the requested login name from leftover packet information. */
615 login = message->leftover;
617 /* Check the login name for validity. The login name is currently
618 is allowed to contain lowercase letters in any position and
619 and numbers and underscore characters in any position but the
621 if ((strlen(login) < MIN_UNAME) || (strlen(login) > MAX_UNAME))
622 status = UREG_INVALID_UNAME;
624 if (status == SUCCESS)
625 if ((login[0] == '_') || isdigit(login[0]))
626 status = UREG_INVALID_UNAME;
628 if (status == SUCCESS)
630 for (i = 0; i < strlen(login); i++)
631 if (!islower(login[i]) && !isdigit(login[i]) &&
634 status = UREG_INVALID_UNAME;
638 if (status == SUCCESS)
640 /* Now that we have a valid user with a valid login... */
642 /* First, try to reserve the user in Moira. */
643 (void) sprintf(fstype_buf,"%d",MR_FS_STUDENT);
644 q_name = "register_user";
645 q_argv[0] = message->db.uid;
647 q_argv[2] = fstype_buf;
649 status = mr_query(q_name,q_argc,q_argv,null_callproc,(char *)0);
656 status = UREG_LOGIN_USED;
659 status = UREG_MISC_ERROR;
662 critical_alert(FAIL_INST,"%s returned from register_user.",
663 error_message(status));
664 status = UREG_MISC_ERROR;
669 if (status == SUCCESS)
672 * Moira login was successfully created; try to reserve kerberos
675 * If this routine fails, store the login in the retval so
676 * that it can be used in the client-side error message.
678 if ((status = reserve_krb(login)) != SUCCESS)
679 (void) strcpy(retval, login);
683 com_err(whoami, status, " returned from reserve_user");
685 com_err(whoami, 0, "User reserved");
691 int set_final_status(message)
693 /* This routine updates a user's registration status to fully
697 char *q_name; /* Name of Moira query */
698 int q_argc; /* Number of arguments for Moira query */
699 char *q_argv[2]; /* Arguments to get user by uid */
700 char state[7]; /* Can hold a 16 bit integer */
701 int status; /* Error status */
703 if (message->request == UREG_SET_PASSWORD)
704 (void) sprintf(state,"%d",US_REGISTERED);
705 else if (message->db.reg_status == US_NO_LOGIN_YET)
706 (void) sprintf(state,"%d",US_ENROLLED);
708 (void) sprintf(state,"%d",US_ENROLL_NOT_ALLOWED);
710 login = message->db.login;
711 com_err(whoami, 0, "Setting final status for %s to %s", login, state);
713 q_name = "update_user_status";
717 if ((status = mr_query(q_name, q_argc, q_argv, null_callproc,
718 (char *)0)) != MR_SUCCESS) {
719 if (status == MR_DEADLOCK)
720 status = UREG_MISC_ERROR;
722 critical_alert(FAIL_INST,"%s returned from update_user_status.",
723 error_message(status));
726 com_err(whoami, status, " returned from set_final_status");
728 com_err(whoami, 0, "Final status set");
733 int set_password(message,retval)
736 /* This routine is used to set the initial password for the new user. */
738 int status = SUCCESS; /* Return status */
739 char *passwd; /* User's password */
741 com_err(whoami, 0, "setting password %s %s",
742 message->first, message->last);
744 status = verify_user(message,retval);
746 /* Don't set the password unless the registration status of the user
747 is that he exists and has no password. */
748 if (status == SUCCESS)
749 status = UREG_NO_LOGIN_YET;
750 if (((int)message->request == UREG_SET_PASSWORD &&
751 status == UREG_NO_PASSWD_YET) ||
752 ((int)message->request == UREG_GET_KRB &&
753 status == UREG_HALF_ENROLLED))
755 /* User is in proper state for this transaction. */
757 passwd = message->leftover;
760 if ((status = setpass_krb(message->db.login, passwd)) != SUCCESS)
761 /* If failure, allow login name to be used in client
763 (void) strcpy(retval,message->db.login);
765 /* Otherwise, mark user as finished. */
766 status = set_final_status(message);
770 com_err(whoami, status, " returned from set_passwd");
772 com_err(whoami, 0, "Password set");
778 int getuserinfo(argc, argv, qargv)
783 int status = SUCCESS;
787 critical_alert(FAIL_INST,
788 "Wrong number of args returned from get_user_by_uid");
791 qargv[U_NAME] = strsave(argv[U_NAME]);
792 for (i = 1; i < U_MODTIME; i++)
793 qargv[i+1] = strsave(argv[i]);
794 qargv[U_MODTIME+1] = NULL;
800 int set_identity(message,retval)
804 int q_argc; /* Number of arguments to query */
805 char *q_argv[U_END]; /* Arguments to Moira query */
806 char *q_name; /* Name of Moira query */
807 int status = SUCCESS; /* General purpose error status */
808 char fstype_buf[7]; /* Buffer to hold fs_type, a 16 bit number */
809 char *login; /* The login name the user wants */
810 register int i; /* A counter */
812 /* Log that we are about to reserve a user. */
813 com_err(whoami, 0, "setting identity %s %s",
814 message->first, message->last);
816 /* Check to make sure that we can verify this user. */
817 status = verify_user(message,retval);
818 if (status == SUCCESS || status == UREG_NOT_ALLOWED)
821 /* Get the requested login name from leftover packet information. */
822 login = message->leftover;
824 /* Check the login name for validity. The login name is currently
825 is allowed to contain lowercase letters in any position and
826 and numbers and underscore characters in any position but the
828 if ((strlen(login) < MIN_UNAME) || (strlen(login) > MAX_UNAME))
829 status = UREG_INVALID_UNAME;
831 if (status == SUCCESS)
832 if ((login[0] == '_') || isdigit(login[0]))
833 status = UREG_INVALID_UNAME;
834 if (status == SUCCESS)
836 for (i = 0; i < strlen(login); i++)
837 if (!islower(login[i]) && !isdigit(login[i]) &&
840 status = UREG_INVALID_UNAME;
844 if (status == SUCCESS)
846 /* Now that we have a valid user with a valid login... */
848 q_argv[0] = message->db.uid;
849 status = mr_query("get_user_account_by_uid", 1, q_argv,
850 getuserinfo, (char *)q_argv);
851 if (status != SUCCESS) {
852 com_err(whoami, status, " while getting user info");
855 q_argv[U_NAME+1] = login;
856 q_argv[U_STATE+1] = "7";
857 q_argv[U_SIGNATURE+1] = "";
858 status = mr_query("update_user_account", U_MODTIME+1, q_argv,
859 null_callproc, NULL);
867 status = UREG_LOGIN_USED;
870 status = UREG_MISC_ERROR;
873 critical_alert(FAIL_INST,"%s returned from update_user_account.",
874 error_message(status));
875 status = UREG_MISC_ERROR;
879 if (status == SUCCESS)
881 /* Moira login was successfully created; try to reserve kerberos
883 /* If this routine fails, store the login in the retval so
884 that it can be used in the client-side error message. */
885 if ((status = reserve_krb(login)) != SUCCESS)
886 (void) strcpy(retval, login);
890 com_err(whoami, status, " returned from set_identity");
892 com_err(whoami, 0, "Identity set");
898 void reg_com_err_hook(whoami, code, fmt, pvar)
905 fputs(whoami, stderr);
909 fputs(error_message(code), stderr);
912 _doprnt(fmt, pvar, stderr);
919 /* Find out of someone's secure instance password is set.
920 * Returns UREG_ALREADY_REGISTERED if set, SUCCESS (0) if not.
923 int get_secure(message, retval)
930 com_err(whoami, 0, "checking status of secure password for %s",
932 argv[0] = message->first;
933 status = mr_query("get_user_account_by_login", 1, argv, getuserinfo,
935 if (status != SUCCESS) {
936 com_err(whoami, status, " while getting user info");
939 if (atoi(argv[U_SECURE + 1]))
940 return UREG_ALREADY_REGISTERED;
945 /* Set someone's secure instance password. */
947 int set_secure(message, retval)
952 char *argv[U_END], hostbuf[256], *bp, *p, buf[512], *passwd, *id;
958 u_long *lkey = (u_long *)key;
960 static int inited = 0;
962 extern char *krb_get_phost(char *);
966 if (gethostname(hostbuf, sizeof(hostbuf)) < 0)
967 com_err(whoami, errno, "getting local hostname");
968 host = strsave(krb_get_phost(hostbuf));
971 com_err(whoami, 0, "setting secure passwd for %s", message->first);
972 argv[0] = message->first;
973 status = mr_query("get_user_account_by_login", 1, argv, getuserinfo,
975 if (status != SUCCESS) {
976 com_err(whoami, status, " while getting user info");
979 if (atoi(argv[U_SECURE + 1])) {
980 com_err(whoami, UREG_ALREADY_REGISTERED, "in set_secure()");
981 return UREG_ALREADY_REGISTERED;
984 bp = message->encrypted;
985 /* round up to word boundary */
986 bp = (char *)((((u_long)bp + 3) >> 2) << 2);
988 creds.length = ntohl(*((int *)bp));
990 memcpy(creds.dat, bp, creds.length);
995 com_err(whoami, 0, "Cred: length %d", creds.length);
996 for (i = 0; i < creds.length; i += 16)
997 com_err(whoami, 0, " %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
998 creds.dat[i+0], creds.dat[i+1], creds.dat[i+2], creds.dat[i+3],
999 creds.dat[i+4], creds.dat[i+5], creds.dat[i+6], creds.dat[i+7],
1000 creds.dat[i+8], creds.dat[i+9], creds.dat[i+10], creds.dat[i+11],
1001 creds.dat[i+12], creds.dat[i+13], creds.dat[i+14], creds.dat[i+15]);
1004 status = krb_rd_req(&creds, "changepw", host, cur_req_sender(),
1007 status += krb_err_base;
1008 com_err(whoami, status, " verifying credentials in set_secure()");
1012 message->leftover_len = ntohl(*((int*)(bp)));
1014 message->leftover = bp;
1016 des_key_sched(auth.session, keys);
1017 des_pcbc_encrypt(message->leftover, buf, message->leftover_len,
1018 keys, auth.session, 0);
1021 passwd = strchr(buf, ',');
1024 com_err(whoami, 0, "Got id: %s, passwd %d chars", id, strlen(passwd));
1027 if (strcmp(id, argv[U_MITID + 1])) {
1030 EncryptID(buf, id, argv[U_FIRST+1], argv[U_LAST+1]);
1031 if (strcmp(buf, argv[U_MITID + 1])) {
1032 status = UREG_USER_NOT_FOUND;
1033 com_err(whoami, status, "IDs mismatch: %s (%s), %s", id, buf,
1039 /* now do actual password setting stuff */
1041 if ((status = ureg_kadm_init()) != SUCCESS) {
1042 com_err(whoami, status, "initing kadm stuff");
1046 memset(&kv, 0, sizeof(kv));
1047 SET_FIELD(KADM_DESKEY, kv.fields);
1048 SET_FIELD(KADM_NAME, kv.fields);
1049 SET_FIELD(KADM_INST, kv.fields);
1050 (void) des_string_to_key(passwd, key);
1051 kv.key_low = htonl(lkey[0]);
1052 kv.key_high = htonl(lkey[1]);
1053 strcpy(kv.name, message->first);
1054 strcpy(kv.instance, "extra");
1056 if ((status = kadm_add(&kv)) != KADM_SUCCESS) {
1057 com_err(whoami, status, " while creating kerberos principal");
1061 argv[0] = message->first;
1063 gettimeofday(&now, NULL);
1064 sprintf(buf, "%d", now.tv_sec);
1065 status = mr_query("update_user_security_status", 2, argv, getuserinfo,
1067 if (status != SUCCESS) {
1068 com_err(whoami, status, " while updating user status");