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[];
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);
57 int main(int argc, char *argv[])
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 */
66 /* Error messages sent one line at a time */
67 setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
68 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
70 /* Initialize com_err error tables */
74 initialize_gdss_error_table();
76 /* Set the name of our kerberos ticket file */
77 krb_set_tkt_string("/tmp/tkt_ureg");
79 /* Connect to the Moira server */
80 if ((status = mr_connect(MOIRA_SERVER)) != MR_SUCCESS)
82 com_err(whoami, status, " on mr_connect");
86 /* Authorize, telling the server who you are */
87 if ((status = mr_auth(whoami)) != MR_SUCCESS)
89 com_err(whoami, status, " on mr_auth");
93 journal = fopen(REGJOURNAL, "a");
96 com_err(whoami, errno, " while opening journal file");
100 /* Allow request layer to initialize */
103 /* Sit around waiting for requests from the client. */
106 get_request(&message);
108 switch (message.request)
110 case UREG_VERIFY_USER:
111 status = verify_user(&message, retval);
113 case UREG_RESERVE_LOGIN:
114 status = reserve_user(&message, retval);
116 case UREG_SET_PASSWORD:
118 status = set_password(&message, retval);
121 status = set_identity(&message, retval);
123 case UREG_GET_SECURE:
124 status = get_secure(&message, retval);
126 case UREG_SET_SECURE:
127 status = set_secure(&message, retval);
130 status = UREG_UNKNOWN_REQUEST;
131 critical_alert(FAIL_INST, "Unknown request %d from userreg.",
136 /* Report what happened to client */
137 report(status, retval);
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:
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
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
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. */
163 int parse_encrypted(struct msg *message, struct db_data *data)
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 */
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;
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')
185 EncryptID(buf, data->mit_id, message->first, message->last);
186 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 strncpy(idnumber, decrypt, decrypt_len);
208 /* Check that the idnumber of a mismatched decryption doesn't overflow
210 if (strlen(idnumber) != 9)
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);
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))
231 if (status == SUCCESS)
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));
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)
252 struct db_data *data; /* Structure to store the information in */
253 int status = SUCCESS; /* Error status */
257 critical_alert(FAIL_INST, "Wrong number of arguments returned "
258 "from get_user_account_by_name.");
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);
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)
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 */
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? */
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));
294 if (status == SUCCESS)
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;
302 /* Create queue to hold information */
306 status = mr_query(q_name, q_argc, q_argv, db_callproc, queue);
308 if (status == MR_SUCCESS)
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))
315 /* parse_encrypted returns zero on success */
316 verified = (parse_encrypted(message, data) == SUCCESS);
321 /* Destroy the queue */
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)
333 int status = SUCCESS; /* Return status */
335 /* Log that we are about to veryify user */
336 com_err(whoami, 0, "verifying user %s %s", message->first, message->last);
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().) */
342 status = find_user(message);
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)
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
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 */
358 switch (message->db.reg_status)
360 case US_NO_LOGIN_YET:
364 status = UREG_ALREADY_REGISTERED;
367 status = UREG_NO_PASSWD_YET;
370 status = UREG_DELETED;
373 status = UREG_NOT_ALLOWED;
376 status = UREG_ENROLLED;
378 case US_ENROLL_NOT_ALLOWED:
379 status = UREG_ENROLL_NOT_ALLOWED;
381 case US_HALF_ENROLLED:
382 status = UREG_HALF_ENROLLED;
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);
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);
397 com_err(whoami, status, " returned from verify_user");
399 com_err(whoami, 0, "User verified");
404 int ureg_kadm_init(void)
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;
416 memset(krbrealm, 0, sizeof(krbrealm));
417 if ((status = krb_get_lrealm(krbrealm, 1)))
419 status += krb_err_base;
420 com_err(whoami, status, " fetching kerberos realm");
424 com_err(whoami, errno, "getting local hostname");
425 host = canonicalize_hostname(strdup(uts.nodename));
426 for (p = host; *p && *p != '.'; p++)
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;
440 if (status != SUCCESS)
441 com_err(whoami, status, " while get admin tickets");
444 if ((status = kadm_init_link(PWSERV_NAME, KADM_SINST, krbrealm)) !=
446 com_err(whoami, status, " while initializing kadmin connection");
453 * This routine reserves a principal in kerberos by setting up a
454 * principal with a random initial key.
456 int reserve_krb(char *login)
458 int status = SUCCESS;
461 u_long *lkey = (u_long *)key;
463 if ((status = ureg_kadm_init()) == SUCCESS)
465 memset(&new, 0, sizeof(new));
466 SET_FIELD(KADM_DESKEY, new.fields);
467 SET_FIELD(KADM_NAME, new.fields);
470 new.key_low = htonl(lkey[0]);
471 new.key_high = htonl(lkey[1]);
472 strcpy(new.name, login);
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");
479 memset(&new, 0, sizeof(new));
488 * This routine reserves a principal in kerberos by setting up a
489 * principal with a random initial key.
491 int setpass_krb(char *login, char *password)
493 int status = SUCCESS;
496 u_long *lkey = (u_long *)key;
498 if ((status = ureg_kadm_init()) == SUCCESS)
500 memset(&new, 0, sizeof(new));
501 SET_FIELD(KADM_DESKEY, new.fields);
502 SET_FIELD(KADM_NAME, new.fields);
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);
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)
513 if (status == KADM_NOENTRY)
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");
520 com_err(whoami, status, " while setting password");
528 int reserve_user(struct msg *message, char *retval)
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 */
538 /* Log that we are about to reserve a user. */
539 com_err(whoami, 0, "reserving user %s %s", message->first, message->last);
541 /* Check to make sure that we can verify this user. */
542 if ((status = verify_user(message, retval)) == SUCCESS)
544 /* Get the requested login name from leftover packet information. */
545 login = message->leftover;
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
551 if ((strlen(login) < MIN_UNAME) || (strlen(login) > MAX_UNAME))
552 status = UREG_INVALID_UNAME;
554 if (status == SUCCESS)
555 if ((login[0] == '_') || isdigit(login[0]))
556 status = UREG_INVALID_UNAME;
558 if (status == SUCCESS)
560 for (i = 0; i < strlen(login); i++)
562 if (!islower(login[i]) && !isdigit(login[i]) &&
565 status = UREG_INVALID_UNAME;
570 if (status == SUCCESS)
572 /* Now that we have a valid user with a valid login... */
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;
579 q_argv[2] = fstype_buf;
581 status = mr_query(q_name, q_argc, q_argv, NULL, NULL);
588 status = UREG_LOGIN_USED;
591 status = UREG_MISC_ERROR;
594 critical_alert(FAIL_INST, "%s returned from register_user.",
595 error_message(status));
596 status = UREG_MISC_ERROR;
601 if (status == SUCCESS)
604 * Moira login was successfully created; try to reserve kerberos
607 * If this routine fails, store the login in the retval so
608 * that it can be used in the client-side error message.
610 if ((status = reserve_krb(login)) != SUCCESS)
611 strcpy(retval, login);
615 com_err(whoami, status, " returned from reserve_user");
617 com_err(whoami, 0, "User reserved");
622 /* This routine updates a user's registration status to fully
624 int set_final_status(struct msg *message)
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 */
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);
638 sprintf(state, "%d", US_ENROLL_NOT_ALLOWED);
640 login = message->db.login;
641 com_err(whoami, 0, "Setting final status for %s to %s", login, state);
643 q_name = "update_user_status";
647 if ((status = mr_query(q_name, q_argc, q_argv, NULL, NULL))
650 if (status == MR_DEADLOCK)
651 status = UREG_MISC_ERROR;
653 critical_alert(FAIL_INST, "%s returned from update_user_status.",
654 error_message(status));
657 com_err(whoami, status, " returned from set_final_status");
659 com_err(whoami, 0, "Final status set");
664 /* This routine is used to set the initial password for the new user. */
665 int set_password(struct msg *message, char *retval)
667 int status = SUCCESS; /* Return status */
668 char *passwd; /* User's password */
670 com_err(whoami, 0, "setting password %s %s", message->first, message->last);
672 status = verify_user(message, retval);
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))
683 /* User is in proper state for this transaction. */
685 passwd = message->leftover;
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);
692 /* Otherwise, mark user as finished. */
693 status = set_final_status(message);
697 com_err(whoami, status, " returned from set_passwd");
699 com_err(whoami, 0, "Password set");
705 int getuserinfo(int argc, char **argv, void *qa)
708 int status = SUCCESS;
713 critical_alert(FAIL_INST,
714 "Wrong number of args returned from get_user_by_uid");
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;
728 int set_identity(struct msg *message, char *retval)
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 */
735 /* Log that we are about to reserve a user. */
736 com_err(whoami, 0, "setting identity %s %s",
737 message->first, message->last);
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)
744 /* Get the requested login name from leftover packet information. */
745 login = message->leftover;
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
751 if ((strlen(login) < MIN_UNAME) || (strlen(login) > MAX_UNAME))
752 status = UREG_INVALID_UNAME;
754 if (status == SUCCESS)
756 if ((login[0] == '_') || isdigit(login[0]))
757 status = UREG_INVALID_UNAME;
759 if (status == SUCCESS)
761 for (i = 0; i < strlen(login); i++)
763 if (!islower(login[i]) && !isdigit(login[i]) &&
766 status = UREG_INVALID_UNAME;
771 if (status == SUCCESS)
773 /* Now that we have a valid user with a valid login... */
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)
780 com_err(whoami, status, " while getting user info");
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,
795 status = UREG_LOGIN_USED;
798 status = UREG_MISC_ERROR;
801 critical_alert(FAIL_INST, "%s returned from update_user_account.",
802 error_message(status));
803 status = UREG_MISC_ERROR;
807 if (status == SUCCESS)
809 /* Moira login was successfully created; try to reserve kerberos
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);
818 com_err(whoami, status, " returned from set_identity");
820 com_err(whoami, 0, "Identity set");
826 /* Find out if someone's secure instance password is set.
827 * Returns UREG_ALREADY_REGISTERED if set, SUCCESS (0) if not.
830 int get_secure(struct msg *message, char *retval)
835 com_err(whoami, 0, "checking status of secure password for %s",
837 argv[0] = message->first;
838 status = mr_query("get_user_account_by_login", 1, argv, getuserinfo, argv);
839 if (status != SUCCESS)
841 com_err(whoami, status, " while getting user info");
844 if (atoi(argv[U_SECURE + 1]))
845 return UREG_ALREADY_REGISTERED;
850 /* Set someone's secure instance password. */
852 int set_secure(struct msg *message, char *retval)
855 char *argv[U_END], *bp, buf[512], *passwd, *id;
861 u_long *lkey = (u_long *)key;
863 static int inited = 0;
871 com_err(whoami, errno, "getting local hostname");
872 host = strdup(krb_get_phost(uts.nodename));
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)
880 com_err(whoami, status, " while getting user info");
883 if (atoi(argv[U_SECURE + 1]))
885 com_err(whoami, UREG_ALREADY_REGISTERED, "in set_secure()");
886 return UREG_ALREADY_REGISTERED;
889 bp = message->encrypted;
890 /* round up to word boundary */
891 bp = (char *)((((u_long)bp + 3) >> 2) << 2);
893 creds.length = ntohl(*((int *)bp));
895 memcpy(creds.dat, bp, creds.length);
899 status = krb_rd_req(&creds, "changepw", host, cur_req_sender(), &auth, "");
902 status += krb_err_base;
903 com_err(whoami, status, " verifying credentials in set_secure()");
907 message->leftover_len = ntohl(*((int *)(bp)));
909 message->leftover = bp;
911 des_key_sched(auth.session, keys);
912 des_pcbc_encrypt(message->leftover, buf, message->leftover_len,
913 keys, auth.session, 0);
916 passwd = strchr(buf, ',');
919 if (strcmp(id, argv[U_MITID + 1]))
923 EncryptID(buf, id, argv[U_FIRST + 1], argv[U_LAST + 1]);
924 if (strcmp(buf, argv[U_MITID + 1]))
926 status = UREG_USER_NOT_FOUND;
927 com_err(whoami, status, "IDs mismatch: %s (%s), %s", id, buf,
933 /* now do actual password setting stuff */
935 if ((status = ureg_kadm_init()) != SUCCESS)
937 com_err(whoami, status, "initing kadm stuff");
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");
951 if ((status = kadm_add(&kv)) != KADM_SUCCESS)
953 com_err(whoami, status, " while creating kerberos principal");
957 argv[0] = message->first;
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)
964 com_err(whoami, status, " while updating user status");