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