3 * Server for user registration with Moira and Kerberos.
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.
10 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
11 * For copying and distribution information, please see the file
15 #include <mit-copyright.h>
17 #include <moira_site.h>
19 #include <sys/utsname.h>
36 extern char admin_errmsg[];
38 int parse_encrypted(struct msg *message, struct db_data *data);
39 int parse_encrypted(struct msg *message, struct db_data *data);
40 int db_callproc(int argc, char **argv, void *queue);
41 int find_user(struct msg *message);
42 int verify_user(struct msg *message, char *retval);
43 int ureg_kadm_init(void);
44 int reserve_krb(char *login);
45 int setpass_krb(char *login, char *password);
46 int reserve_user(struct msg *message, char *retval);
47 int set_final_status(struct msg *message);
48 int set_password(struct msg *message, char *retval);
49 int getuserinfo(int argc, char **argv, void *qa);
50 int set_identity(struct msg *message, char *retval);
51 int get_secure(struct msg *message, char *retval);
52 int set_secure(struct msg *message, char *retval);
54 int main(int argc, char *argv[])
56 struct msg message; /* Storage for parsed packet */
57 int status = SUCCESS; /* Error status */
58 char retval[BUFSIZ]; /* Buffer to hold return message for client */
63 /* Error messages sent one line at a time */
64 setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
65 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
67 /* Initialize com_err error tables */
71 initialize_gdss_error_table();
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");
93 com_err(whoami, errno, " while opening journal file");
97 /* Allow request layer to initialize */
100 /* Sit around waiting for requests from the client. */
103 get_request(&message);
105 switch (message.request)
107 case UREG_VERIFY_USER:
108 status = verify_user(&message, retval);
110 case UREG_RESERVE_LOGIN:
111 status = reserve_user(&message, retval);
113 case UREG_SET_PASSWORD:
115 status = set_password(&message, retval);
118 status = set_identity(&message, retval);
120 case UREG_GET_SECURE:
121 status = get_secure(&message, retval);
123 case UREG_SET_SECURE:
124 status = set_secure(&message, retval);
127 status = UREG_UNKNOWN_REQUEST;
128 critical_alert(FAIL_INST, "Unknown request %d from userreg.",
133 /* Report what happened to client */
134 report(status, retval);
138 /* This routine makes sure that the ID from the database matches
139 the ID sent accross in the packet. The information in the packet
140 was created in the following way:
142 The database used to contain encrypted IDs. Now we don't encrypt
143 them in the database, although there are still some encrypted IDs
146 The plain text ID number was encrypted via EncryptID() resulting
147 in the form that would appear in the Moira database. This is
148 concatenated to the plain text ID so that the ID string contains plain
149 text ID followed by a null followed by the encrypted ID. Other
150 information such as the username or password is appended. The whole
151 thing is then DES encrypted using the encrypted ID as the source of
154 This routine tries each ID in the database that belongs
155 to someone with this user's first and last name and tries to
156 decrypt the packet with this information. If it succeeds, it returns
157 zero and initializes all the fields of the formatted packet structure
158 that depend on the encrypted information. */
160 int parse_encrypted(struct msg *message, struct db_data *data)
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 static char hashid[14]; /* Buffer to hold one-way encrypted ID */
167 char idnumber[BUFSIZ]; /* Buffer to hold plain-text ID */
168 char *temp; /* A temporary string pointer */
169 int len; /* Keeps track of length left in packet */
170 int status = SUCCESS; /* Error status */
172 /* Make the decrypted information length the same as the encrypted
173 information length. Both are integral multples of eight bytes
174 because of the DES encryption routines. */
175 decrypt_len = message->encrypted_len;
177 /* Get key from the possibly one-way encrypted ID in the Moira database */
178 if (data->mit_id[0] >= '0' && data->mit_id[0] <= '9')
182 EncryptID(buf, data->mit_id, message->first, message->last);
183 des_string_to_key(buf, key);
186 des_string_to_key(data->mit_id, key);
188 /* Get schedule from key */
189 des_key_sched(key, sched);
190 /* Decrypt information from packet using this key. Since decrypt_len
191 is an integral multiple of eight bytes, it will probably be null-
193 des_pcbc_encrypt(message->encrypted, decrypt, decrypt_len,
194 sched, key, DES_DECRYPT);
196 /* Extract the plain text and encrypted ID fields from the decrypted
197 packet information. */
198 /* Since the decrypted information starts with the plain-text ID
199 followed by a null, if the decryption worked, this will only
200 copy the plain text part of the decrypted information. It is
201 important that strncpy be used because if we are not using the
202 correct key, there is no guarantee that a null will occur
203 anywhere in the string. */
204 strncpy(idnumber, decrypt, decrypt_len);
205 /* Check that the idnumber of a mismatched decryption doesn't overflow
207 if (strlen(idnumber) != 9)
210 /* Point temp to the end of the plain text ID number. */
211 temp = decrypt + strlen(idnumber) + 1;
212 /* Find out how much more packet there is. */
213 len = message->encrypted_len - (temp - decrypt);
214 /* Copy the next CRYPT_LEN bytes of the decrypted information into
215 hashid if there are CRYPT_LEN more bytes to copy. There will be
216 if we have the right key. */
217 strncpy(hashid, temp, min(len, CRYPT_LEN));
218 /* Point temp to the end of the encrypted ID field */
219 temp += strlen(hashid) + 1;
220 /* Find out how much more room there is. */
221 len = message->encrypted_len - (temp - decrypt);
223 /* Now compare encrypted ID and clear text ID for a match. */
224 if (strcmp(hashid, data->mit_id) &&
225 strcmp(idnumber, data->mit_id))
228 if (status == SUCCESS)
230 /* We made it. Now we can finish initializing message. */
231 /* Point leftover to whatever is left over! */
232 message->leftover = temp;
233 message->leftover_len = len;
234 /* Since we know we have the right user, fill in the information
235 from the Moira database. */
236 message->db.reg_status = data->reg_status;
237 strncpy(message->db.uid, data->uid, sizeof(message->db.uid));
238 strncpy(message->db.mit_id, data->mit_id, sizeof(message->db.mit_id));
239 strncpy(message->db.login, data->login, sizeof(message->db.login));
245 /* This function is called by mr_query after each tuple found. It is
246 used by find_user to cache information about each user found. */
247 int db_callproc(int argc, char **argv, void*queue)
249 struct db_data *data; /* Structure to store the information in */
250 int status = SUCCESS; /* Error status */
254 critical_alert(FAIL_INST, "Wrong number of arguments returned "
255 "from get_user_account_by_name.");
260 /* extract the needed information from the results of the Moira query */
261 data = malloc(sizeof(struct db_data));
262 data->reg_status = atoi(argv[U_STATE]);
263 strncpy(data->login, argv[U_NAME], sizeof(data->login));
264 strncpy(data->mit_id, argv[U_MITID], sizeof(data->mit_id));
265 strncpy(data->uid, argv[U_UID], sizeof(data->uid));
266 sq_save_data(queue, data);
272 /* This routine verifies that a user is allowed to register by finding
273 him/her in the Moira database. It returns the status of the Moira
274 query that it calls. */
275 int find_user(struct msg *message)
277 #define GUBN_ARGS 2 /* Arguements needed by get_user_by_name */
278 char *q_name; /* Name of Moira query */
279 int q_argc; /* Number of arguments for query */
280 char *q_argv[GUBN_ARGS]; /* Arguments to query */
281 int status = SUCCESS; /* Query return status */
283 struct save_queue *queue; /* Queue to hold Moira data */
284 struct db_data *data; /* Structure for data for one tuple */
285 short verified = FALSE; /* Have we verified the user? */
287 /* Zero the mit_id field in the formatted packet structure. This
288 being zeroed means that no user was found. */
289 memset(message->db.mit_id, 0, sizeof(message->db.mit_id));
291 if (status == SUCCESS)
293 /* Get ready to make a Moira query */
294 q_name = "get_user_account_by_name";
295 q_argc = GUBN_ARGS; /* #defined in this routine */
296 q_argv[0] = message->first;
297 q_argv[1] = message->last;
299 /* Create queue to hold information */
303 status = mr_query(q_name, q_argc, q_argv, db_callproc, queue);
305 if (status == MR_SUCCESS)
307 /* Traverse the list, freeing data as we go. If sq_get_data()
308 returns zero if there is no more data on the queue. */
309 while (sq_get_data(queue, &data))
312 /* parse_encrypted returns zero on success */
313 verified = (parse_encrypted(message, data) == SUCCESS);
318 /* Destroy the queue */
325 /* This routine determines whether a user is in the databse and returns
326 his state so that other routines can figure out whether he is the
327 correct state for various transactions. */
328 int verify_user(struct msg *message, char *retval)
330 int status = SUCCESS; /* Return status */
332 /* Log that we are about to veryify user */
333 com_err(whoami, 0, "verifying user %s %s", message->first, message->last);
335 /* Figure out what user (if any) can be found based on the
336 encrypted information in the packet. (See the comment on
337 parse_encrypted().) */
339 status = find_user(message);
341 /* If Moira coudn't find the user */
342 if (status == MR_NO_MATCH)
343 status = UREG_USER_NOT_FOUND;
344 else if (status == MR_SUCCESS)
346 /* If the information sent over in the packet did not point to a
347 valid user, the mit_id field in the formatted packet structure
349 if (message->db.mit_id[0] == '\0')
350 status = UREG_USER_NOT_FOUND;
351 /* If the user was found but the registration has already started,
352 use this as the status */
355 switch (message->db.reg_status)
357 case US_NO_LOGIN_YET:
361 status = UREG_ALREADY_REGISTERED;
364 status = UREG_NO_PASSWD_YET;
367 status = UREG_DELETED;
370 status = UREG_NOT_ALLOWED;
373 status = UREG_ENROLLED;
375 case US_ENROLL_NOT_ALLOWED:
376 status = UREG_ENROLL_NOT_ALLOWED;
378 case US_HALF_ENROLLED:
379 status = UREG_HALF_ENROLLED;
382 status = UREG_MISC_ERROR;
383 critical_alert(FAIL_INST, "Bad user state %d for login %s.",
384 message->db.reg_status, message->db.login);
387 /* Set retval to the login name so that the client can use
388 it in the error message it will give the user. */
389 strcpy(retval, message->db.login);
394 com_err(whoami, status, " returned from verify_user");
396 com_err(whoami, 0, "User verified");
401 int ureg_kadm_init(void)
403 unsigned int status = SUCCESS; /* Return status */
404 static char krbrealm[REALM_SZ]; /* kerberos realm name */
405 static char *host; /* local hostname in principal fmt */
406 static int inited = 0;
413 memset(krbrealm, 0, sizeof(krbrealm));
414 if ((status = krb_get_lrealm(krbrealm, 1)))
416 status += krb_err_base;
417 com_err(whoami, status, " fetching kerberos realm");
421 com_err(whoami, errno, "getting local hostname");
422 host = canonicalize_hostname(strdup(uts.nodename));
423 for (p = host; *p && *p != '.'; p++)
431 /* Get keys for interacting with Kerberos admin server. */
432 /* principal, instance, realm, service, service instance, life, file */
433 if ((status = krb_get_svc_in_tkt(MOIRA_SNAME, host, krbrealm, PWSERV_NAME,
434 KADM_SINST, 1, KEYFILE)))
435 status += krb_err_base;
437 if (status != SUCCESS)
438 com_err(whoami, status, " while get admin tickets");
441 if ((status = kadm_init_link(PWSERV_NAME, KADM_SINST, krbrealm)) !=
443 com_err(whoami, status, " while initializing kadmin connection");
450 * This routine reserves a principal in kerberos by setting up a
451 * principal with a random initial key.
453 int reserve_krb(char *login)
455 int status = SUCCESS;
458 u_long *lkey = (u_long *)key;
460 if ((status = ureg_kadm_init()) == SUCCESS)
462 memset(&new, 0, sizeof(new));
463 SET_FIELD(KADM_DESKEY, new.fields);
464 SET_FIELD(KADM_NAME, new.fields);
467 new.key_low = htonl(lkey[0]);
468 new.key_high = htonl(lkey[1]);
469 strcpy(new.name, login);
471 com_err(whoami, 0, "Creating kerberos principal for %s", login);
472 status = kadm_add(&new);
473 if (status != KADM_SUCCESS)
474 com_err(whoami, status, " while reserving principal");
476 memset(&new, 0, sizeof(new));
485 * This routine reserves a principal in kerberos by setting up a
486 * principal with a random initial key.
488 int setpass_krb(char *login, char *password)
490 int status = SUCCESS;
493 u_long *lkey = (u_long *)key;
495 if ((status = ureg_kadm_init()) == SUCCESS)
497 memset(&new, 0, sizeof(new));
498 SET_FIELD(KADM_DESKEY, new.fields);
499 SET_FIELD(KADM_NAME, new.fields);
501 des_string_to_key(password, key);
502 new.key_low = htonl(lkey[0]);
503 new.key_high = htonl(lkey[1]);
504 strcpy(new.name, login);
506 com_err(whoami, 0, "Setting password for %s", login);
507 /* First arguement is not used if user has modify privileges */
508 if ((status = kadm_mod(&new, &new)) != KADM_SUCCESS)
510 if (status == KADM_NOENTRY)
512 com_err(whoami, 0, "kerberos principal doesn't exist; creating");
513 if ((status = kadm_add(&new)) != KADM_SUCCESS)
514 com_err(whoami, status, " while creating kerberos principal");
517 com_err(whoami, status, " while setting password");
525 int reserve_user(struct msg *message, char *retval)
527 int q_argc; /* Number of arguments to query */
528 char *q_argv[3]; /* Arguments to Moira query */
529 char *q_name; /* Name of Moira query */
530 int status = SUCCESS; /* General purpose error status */
531 char fstype_buf[7]; /* Buffer to hold fs_type, a 16 bit number */
532 char *login; /* The login name the user wants */
533 int i; /* A counter */
535 /* Log that we are about to reserve a user. */
536 com_err(whoami, 0, "reserving user %s %s", message->first, message->last);
538 /* Check to make sure that we can verify this user. */
539 if ((status = verify_user(message, retval)) == SUCCESS)
541 /* Get the requested login name from leftover packet information. */
542 login = message->leftover;
544 /* Check the login name for validity. The login name is currently
545 is allowed to contain lowercase letters in any position and
546 and numbers and underscore characters in any position but the
548 if ((strlen(login) < MIN_UNAME) || (strlen(login) > MAX_UNAME))
549 status = UREG_INVALID_UNAME;
551 if (status == SUCCESS)
552 if ((login[0] == '_') || isdigit(login[0]))
553 status = UREG_INVALID_UNAME;
555 if (status == SUCCESS)
557 for (i = 0; i < strlen(login); i++)
559 if (!islower(login[i]) && !isdigit(login[i]) &&
562 status = UREG_INVALID_UNAME;
567 if (status == SUCCESS)
569 /* Now that we have a valid user with a valid login... */
571 /* First, try to reserve the user in Moira. */
572 sprintf(fstype_buf, "%d", MR_FS_STUDENT);
573 q_name = "register_user";
574 q_argv[0] = message->db.uid;
576 q_argv[2] = fstype_buf;
578 status = mr_query(q_name, q_argc, q_argv, NULL, NULL);
585 status = UREG_LOGIN_USED;
588 status = UREG_MISC_ERROR;
591 critical_alert(FAIL_INST, "%s returned from register_user.",
592 error_message(status));
593 status = UREG_MISC_ERROR;
598 if (status == SUCCESS)
601 * Moira login was successfully created; try to reserve kerberos
604 * If this routine fails, store the login in the retval so
605 * that it can be used in the client-side error message.
607 if ((status = reserve_krb(login)) != SUCCESS)
608 strcpy(retval, login);
612 com_err(whoami, status, " returned from reserve_user");
614 com_err(whoami, 0, "User reserved");
619 /* This routine updates a user's registration status to fully
621 int set_final_status(struct msg *message)
624 char *q_name; /* Name of Moira query */
625 int q_argc; /* Number of arguments for Moira query */
626 char *q_argv[2]; /* Arguments to get user by uid */
627 char state[7]; /* Can hold a 16 bit integer */
628 int status; /* Error status */
630 if (message->request == UREG_SET_PASSWORD)
631 sprintf(state, "%d", US_REGISTERED);
632 else if (message->db.reg_status == US_NO_LOGIN_YET)
633 sprintf(state, "%d", US_ENROLLED);
635 sprintf(state, "%d", US_ENROLL_NOT_ALLOWED);
637 login = message->db.login;
638 com_err(whoami, 0, "Setting final status for %s to %s", login, state);
640 q_name = "update_user_status";
644 if ((status = mr_query(q_name, q_argc, q_argv, NULL, NULL))
647 if (status == MR_DEADLOCK)
648 status = UREG_MISC_ERROR;
650 critical_alert(FAIL_INST, "%s returned from update_user_status.",
651 error_message(status));
654 com_err(whoami, status, " returned from set_final_status");
656 com_err(whoami, 0, "Final status set");
661 /* This routine is used to set the initial password for the new user. */
662 int set_password(struct msg *message, char *retval)
664 int status = SUCCESS; /* Return status */
665 char *passwd; /* User's password */
667 com_err(whoami, 0, "setting password %s %s", message->first, message->last);
669 status = verify_user(message, retval);
671 /* Don't set the password unless the registration status of the user
672 is that he exists and has no password. */
673 if (status == SUCCESS)
674 status = UREG_NO_LOGIN_YET;
675 if ((message->request == UREG_SET_PASSWORD &&
676 status == UREG_NO_PASSWD_YET) ||
677 (message->request == UREG_GET_KRB &&
678 status == UREG_HALF_ENROLLED))
680 /* User is in proper state for this transaction. */
682 passwd = message->leftover;
685 if ((status = setpass_krb(message->db.login, passwd)) != SUCCESS)
686 /* If failure, allow login name to be used in client error message */
687 strcpy(retval, message->db.login);
689 /* Otherwise, mark user as finished. */
690 status = set_final_status(message);
694 com_err(whoami, status, " returned from set_passwd");
696 com_err(whoami, 0, "Password set");
702 int getuserinfo(int argc, char **argv, void *qa)
705 int status = SUCCESS;
710 critical_alert(FAIL_INST,
711 "Wrong number of args returned from get_user_by_uid");
716 qargv[U_NAME] = strdup(argv[U_NAME]);
717 for (i = 1; i < U_MODTIME; i++)
718 qargv[i + 1] = strdup(argv[i]);
719 qargv[U_MODTIME + 1] = NULL;
725 int set_identity(struct msg *message, char *retval)
727 char *q_argv[U_END]; /* Arguments to Moira query */
728 int status = SUCCESS; /* General purpose error status */
729 char *login; /* The login name the user wants */
730 int i; /* A counter */
732 /* Log that we are about to reserve a user. */
733 com_err(whoami, 0, "setting identity %s %s",
734 message->first, message->last);
736 /* Check to make sure that we can verify this user. */
737 status = verify_user(message, retval);
738 if (status == SUCCESS || status == UREG_NOT_ALLOWED)
741 /* Get the requested login name from leftover packet information. */
742 login = message->leftover;
744 /* Check the login name for validity. The login name is currently
745 is allowed to contain lowercase letters in any position and
746 and numbers and underscore characters in any position but the
748 if ((strlen(login) < MIN_UNAME) || (strlen(login) > MAX_UNAME))
749 status = UREG_INVALID_UNAME;
751 if (status == SUCCESS)
753 if ((login[0] == '_') || isdigit(login[0]))
754 status = UREG_INVALID_UNAME;
756 if (status == SUCCESS)
758 for (i = 0; i < strlen(login); i++)
760 if (!islower(login[i]) && !isdigit(login[i]) &&
763 status = UREG_INVALID_UNAME;
768 if (status == SUCCESS)
770 /* Now that we have a valid user with a valid login... */
772 q_argv[0] = message->db.uid;
773 status = mr_query("get_user_account_by_uid", 1, q_argv,
774 getuserinfo, q_argv);
775 if (status != SUCCESS)
777 com_err(whoami, status, " while getting user info");
780 q_argv[U_NAME + 1] = login;
781 q_argv[U_STATE + 1] = "7";
782 q_argv[U_SIGNATURE + 1] = "";
783 status = mr_query("update_user_account", U_MODTIME + 1, q_argv,
792 status = UREG_LOGIN_USED;
795 status = UREG_MISC_ERROR;
798 critical_alert(FAIL_INST, "%s returned from update_user_account.",
799 error_message(status));
800 status = UREG_MISC_ERROR;
804 if (status == SUCCESS)
806 /* Moira login was successfully created; try to reserve kerberos
808 /* If this routine fails, store the login in the retval so
809 that it can be used in the client-side error message. */
810 if ((status = reserve_krb(login)) != SUCCESS)
811 strcpy(retval, login);
815 com_err(whoami, status, " returned from set_identity");
817 com_err(whoami, 0, "Identity set");
823 /* Find out if someone's secure instance password is set.
824 * Returns UREG_ALREADY_REGISTERED if set, SUCCESS (0) if not.
827 int get_secure(struct msg *message, char *retval)
832 com_err(whoami, 0, "checking status of secure password for %s",
834 argv[0] = message->first;
835 status = mr_query("get_user_account_by_login", 1, argv, getuserinfo, argv);
836 if (status != SUCCESS)
838 com_err(whoami, status, " while getting user info");
841 if (atoi(argv[U_SECURE + 1]))
842 return UREG_ALREADY_REGISTERED;
847 /* Set someone's secure instance password. */
849 int set_secure(struct msg *message, char *retval)
852 char *argv[U_END], *bp, buf[512], *passwd, *id;
858 u_long *lkey = (u_long *)key;
860 static int inited = 0;
868 com_err(whoami, errno, "getting local hostname");
869 host = strdup(krb_get_phost(uts.nodename));
872 com_err(whoami, 0, "setting secure passwd for %s", message->first);
873 argv[0] = message->first;
874 status = mr_query("get_user_account_by_login", 1, argv, getuserinfo, argv);
875 if (status != SUCCESS)
877 com_err(whoami, status, " while getting user info");
880 if (atoi(argv[U_SECURE + 1]))
882 com_err(whoami, UREG_ALREADY_REGISTERED, "in set_secure()");
883 return UREG_ALREADY_REGISTERED;
886 bp = message->encrypted;
887 /* round up to word boundary */
888 bp = (char *)((((u_long)bp + 3) >> 2) << 2);
890 creds.length = ntohl(*((int *)bp));
892 memcpy(creds.dat, bp, creds.length);
896 status = krb_rd_req(&creds, "changepw", host, cur_req_sender(), &auth, "");
899 status += krb_err_base;
900 com_err(whoami, status, " verifying credentials in set_secure()");
904 message->leftover_len = ntohl(*((int *)(bp)));
906 message->leftover = bp;
908 des_key_sched(auth.session, keys);
909 des_pcbc_encrypt(message->leftover, buf, message->leftover_len,
910 keys, auth.session, 0);
913 passwd = strchr(buf, ',');
916 if (strcmp(id, argv[U_MITID + 1]))
920 EncryptID(buf, id, argv[U_FIRST + 1], argv[U_LAST + 1]);
921 if (strcmp(buf, argv[U_MITID + 1]))
923 status = UREG_USER_NOT_FOUND;
924 com_err(whoami, status, "IDs mismatch: %s (%s), %s", id, buf,
930 /* now do actual password setting stuff */
932 if ((status = ureg_kadm_init()) != SUCCESS)
934 com_err(whoami, status, "initing kadm stuff");
938 memset(&kv, 0, sizeof(kv));
939 SET_FIELD(KADM_DESKEY, kv.fields);
940 SET_FIELD(KADM_NAME, kv.fields);
941 SET_FIELD(KADM_INST, kv.fields);
942 des_string_to_key(passwd, key);
943 kv.key_low = htonl(lkey[0]);
944 kv.key_high = htonl(lkey[1]);
945 strcpy(kv.name, message->first);
946 strcpy(kv.instance, "extra");
948 if ((status = kadm_add(&kv)) != KADM_SUCCESS)
950 com_err(whoami, status, " while creating kerberos principal");
954 argv[0] = message->first;
956 gettimeofday(&now, NULL);
957 sprintf(buf, "%ld", now.tv_sec);
958 status = mr_query("update_user_security_status", 2, argv, getuserinfo, argv);
959 if (status != SUCCESS)
961 com_err(whoami, status, " while updating user status");