]> andersk Git - moira.git/blame - reg_svr/reg_svr.c
second code style cleanup: void/void * usage, proper #includes. try to
[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
7ac48069 38int parse_encrypted(struct msg *message, struct db_data *data);
39int parse_encrypted(struct msg *message, struct db_data *data);
40int db_callproc(int argc, char **argv, void *queue);
41int find_user(struct msg *message);
42int verify_user(struct msg *message, char *retval);
43int ureg_kadm_init(void);
44int reserve_krb(char *login);
45int setpass_krb(char *login, char *password);
46int reserve_user(struct msg *message, char *retval);
47int set_final_status(struct msg *message);
48int set_password(struct msg *message, char *retval);
49int getuserinfo(int argc, char **argv, void *qa);
50int set_identity(struct msg *message, char *retval);
51int get_secure(struct msg *message, char *retval);
52int set_secure(struct msg *message, char *retval);
3f5f9b08 53
5eaef520 54int main(int argc, char *argv[])
47baf534 55{
5eaef520 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 */
59
5eaef520 60 /* Initialize */
61 whoami = argv[0];
62
63 /* Error messages sent one line at a time */
64 setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
65 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
5eaef520 66
67 /* Initialize com_err error tables */
68 init_ureg_err_tbl();
69 init_krb_err_tbl();
70 init_kadm_err_tbl();
71 initialize_gdss_error_table();
72
73 /* Set the name of our kerberos ticket file */
74 krb_set_tkt_string("/tmp/tkt_ureg");
75
76 /* Connect to the Moira server */
77 if ((status = mr_connect(MOIRA_SERVER)) != MR_SUCCESS)
3e9b5b7b 78 {
5eaef520 79 com_err(whoami, status, " on mr_connect");
80 exit(1);
78eff417 81 }
5eaef520 82
83 /* Authorize, telling the server who you are */
84 if ((status = mr_auth(whoami)) != MR_SUCCESS)
3e9b5b7b 85 {
5eaef520 86 com_err(whoami, status, " on mr_auth");
87 exit(1);
78eff417 88 }
5eaef520 89
90 journal = fopen(REGJOURNAL, "a");
91 if (!journal)
92 {
93 com_err(whoami, errno, " while opening journal file");
94 exit(1);
0349fd4d 95 }
5eaef520 96
97 /* Allow request layer to initialize */
98 req_initialize();
99
100 /* Sit around waiting for requests from the client. */
101 for (;;)
3e9b5b7b 102 {
5eaef520 103 get_request(&message);
104
105 switch (message.request)
3e9b5b7b 106 {
5eaef520 107 case UREG_VERIFY_USER:
108 status = verify_user(&message, retval);
109 break;
110 case UREG_RESERVE_LOGIN:
111 status = reserve_user(&message, retval);
112 break;
113 case UREG_SET_PASSWORD:
114 case UREG_GET_KRB:
115 status = set_password(&message, retval);
116 break;
117 case UREG_SET_IDENT:
118 status = set_identity(&message, retval);
119 break;
120 case UREG_GET_SECURE:
121 status = get_secure(&message, retval);
122 break;
123 case UREG_SET_SECURE:
124 status = set_secure(&message, retval);
125 break;
126 default:
127 status = UREG_UNKNOWN_REQUEST;
128 critical_alert(FAIL_INST, "Unknown request %d from userreg.",
129 message.request);
130 break;
47baf534 131 }
5eaef520 132
133 /* Report what happened to client */
134 report(status, retval);
47baf534 135 }
136}
137
3e9b5b7b 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:
141
877a2ce9 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
144 there.
145
803d15cb 146 The plain text ID number was encrypted via EncryptID() resulting
40174425 147 in the form that would appear in the Moira database. This is
5eaef520 148 concatenated to the plain text ID so that the ID string contains plain
29bc4461 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
152 the key.
3e9b5b7b 153
877a2ce9 154 This routine tries each ID in the database that belongs
5eaef520 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
29bc4461 157 zero and initializes all the fields of the formatted packet structure
158 that depend on the encrypted information. */
5eaef520 159
160int parse_encrypted(struct msg *message, struct db_data *data)
47baf534 161{
5eaef520 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 */
5eaef520 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 */
171
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;
176
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')
bac67528 179 {
5eaef520 180 char buf[32];
181
182 EncryptID(buf, data->mit_id, message->first, message->last);
183 des_string_to_key(buf, key);
184 }
185 else
186 des_string_to_key(data->mit_id, key);
187
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-
192 padded. */
193 des_pcbc_encrypt(message->encrypted, decrypt, decrypt_len,
194 sched, key, DES_DECRYPT);
195
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
206 * the buffer. */
207 if (strlen(idnumber) != 9)
208 return FAILURE;
209
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);
222
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))
226 status = FAILURE;
227
228 if (status == SUCCESS)
229 {
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));
bac67528 240 }
47baf534 241
47baf534 242 return status;
243}
244
2ce085d2 245/* This function is called by mr_query after each tuple found. It is
29bc4461 246 used by find_user to cache information about each user found. */
7ac48069 247int db_callproc(int argc, char **argv, void*queue)
47baf534 248{
5eaef520 249 struct db_data *data; /* Structure to store the information in */
250 int status = SUCCESS; /* Error status */
251
252 if (argc != U_END)
3e9b5b7b 253 {
5eaef520 254 critical_alert(FAIL_INST, "Wrong number of arguments returned "
255 "from get_user_account_by_name.");
256 status = MR_ABORT;
f46fccfa 257 }
5eaef520 258 else
3e9b5b7b 259 {
5eaef520 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);
47baf534 267 }
bac67528 268
5eaef520 269 return status;
bac67528 270}
5eaef520 271
bac67528 272/* This routine verifies that a user is allowed to register by finding
40174425 273 him/her in the Moira database. It returns the status of the Moira
bac67528 274 query that it calls. */
5eaef520 275int find_user(struct msg *message)
bac67528 276{
803d15cb 277#define GUBN_ARGS 2 /* Arguements needed by get_user_by_name */
7ac48069 278 char *q_name; /* Name of Moira query */
5eaef520 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 */
282
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? */
286
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));
290
291 if (status == SUCCESS)
3e9b5b7b 292 {
59ec8dae 293 /* Get ready to make a Moira query */
5eaef520 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;
298
299 /* Create queue to hold information */
300 queue = sq_create();
301
302 /* Do it */
7ac48069 303 status = mr_query(q_name, q_argc, q_argv, db_callproc, queue);
5eaef520 304
305 if (status == MR_SUCCESS)
bac67528 306 {
5eaef520 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))
bac67528 310 {
5eaef520 311 if (!verified)
312 /* parse_encrypted returns zero on success */
313 verified = (parse_encrypted(message, data) == SUCCESS);
314 free(data);
bac67528 315 }
316 }
29bc4461 317
5eaef520 318 /* Destroy the queue */
319 sq_destroy(queue);
47baf534 320 }
bac67528 321
5eaef520 322 return status;
bac67528 323}
324
5eaef520 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. */
328int verify_user(struct msg *message, char *retval)
47baf534 329{
5eaef520 330 int status = SUCCESS; /* Return status */
bac67528 331
5eaef520 332 /* Log that we are about to veryify user */
333 com_err(whoami, 0, "verifying user %s %s", message->first, message->last);
bac67528 334
5eaef520 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().) */
bac67528 338
5eaef520 339 status = find_user(message);
bac67528 340
5eaef520 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)
3e9b5b7b 345 {
5eaef520 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
348 will be empty. */
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 */
353 else
bac67528 354 {
5eaef520 355 switch (message->db.reg_status)
bac67528 356 {
5eaef520 357 case US_NO_LOGIN_YET:
358 status = SUCCESS;
359 break;
360 case US_REGISTERED:
361 status = UREG_ALREADY_REGISTERED;
362 break;
363 case US_NO_PASSWD:
364 status = UREG_NO_PASSWD_YET;
365 break;
366 case US_DELETED:
367 status = UREG_DELETED;
368 break;
369 case US_NOT_ALLOWED:
370 status = UREG_NOT_ALLOWED;
371 break;
372 case US_ENROLLED:
373 status = UREG_ENROLLED;
374 break;
375 case US_ENROLL_NOT_ALLOWED:
376 status = UREG_ENROLL_NOT_ALLOWED;
377 break;
d8ffd27c 378 case US_HALF_ENROLLED:
5eaef520 379 status = UREG_HALF_ENROLLED;
380 break;
381 default:
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);
385 break;
bac67528 386 }
5eaef520 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);
bac67528 390 }
47baf534 391 }
bac67528 392
5eaef520 393 if (status)
394 com_err(whoami, status, " returned from verify_user");
395 else
396 com_err(whoami, 0, "User verified");
397
398 return status;
47baf534 399}
5eaef520 400
401int ureg_kadm_init(void)
47baf534 402{
5eaef520 403 unsigned int status = SUCCESS; /* Return status */
404 static char krbrealm[REALM_SZ]; /* kerberos realm name */
7ac48069 405 static char *host; /* local hostname in principal fmt */
5eaef520 406 static int inited = 0;
407 char *p;
7ac48069 408 struct utsname uts;
5eaef520 409
410 if (!inited)
411 {
412 inited++;
413 memset(krbrealm, 0, sizeof(krbrealm));
7ac48069 414 if ((status = krb_get_lrealm(krbrealm, 1)))
5eaef520 415 {
416 status += krb_err_base;
417 com_err(whoami, status, " fetching kerberos realm");
418 exit(1);
40174425 419 }
7ac48069 420 if (uname(&uts) < 0)
5eaef520 421 com_err(whoami, errno, "getting local hostname");
7ac48069 422 host = canonicalize_hostname(strdup(uts.nodename));
5eaef520 423 for (p = host; *p && *p != '.'; p++)
424 {
6b407d0f 425 if (isupper(*p))
426 *p = tolower(*p);
5eaef520 427 }
428 *p = 0;
40174425 429 }
bac67528 430
5eaef520 431 /* Get keys for interacting with Kerberos admin server. */
432 /* principal, instance, realm, service, service instance, life, file */
7ac48069 433 if ((status = krb_get_svc_in_tkt(MOIRA_SNAME, host, krbrealm, PWSERV_NAME,
434 KADM_SINST, 1, KEYFILE)))
5eaef520 435 status += krb_err_base;
436
437 if (status != SUCCESS)
438 com_err(whoami, status, " while get admin tickets");
439 else
440 {
441 if ((status = kadm_init_link(PWSERV_NAME, KADM_SINST, krbrealm)) !=
442 KADM_SUCCESS)
443 com_err(whoami, status, " while initializing kadmin connection");
40174425 444 }
445
5eaef520 446 return status;
47baf534 447}
448
40174425 449/*
5eaef520 450 * This routine reserves a principal in kerberos by setting up a
40174425 451 * principal with a random initial key.
452 */
5eaef520 453int reserve_krb(char *login)
47baf534 454{
5eaef520 455 int status = SUCCESS;
456 Kadm_vals new;
457 des_cblock key;
458 u_long *lkey = (u_long *)key;
459
460 if ((status = ureg_kadm_init()) == SUCCESS)
461 {
462 memset(&new, 0, sizeof(new));
463 SET_FIELD(KADM_DESKEY, new.fields);
464 SET_FIELD(KADM_NAME, new.fields);
465
466 des_random_key(key);
467 new.key_low = htonl(lkey[0]);
468 new.key_high = htonl(lkey[1]);
469 strcpy(new.name, login);
470
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");
475
476 memset(&new, 0, sizeof(new));
40174425 477 }
478
5eaef520 479 dest_tkt();
40174425 480
5eaef520 481 return status;
40174425 482}
483
484/*
5eaef520 485 * This routine reserves a principal in kerberos by setting up a
40174425 486 * principal with a random initial key.
487 */
5eaef520 488int setpass_krb(char *login, char *password)
40174425 489{
5eaef520 490 int status = SUCCESS;
491 Kadm_vals new;
492 des_cblock key;
493 u_long *lkey = (u_long *)key;
494
495 if ((status = ureg_kadm_init()) == SUCCESS)
496 {
497 memset(&new, 0, sizeof(new));
498 SET_FIELD(KADM_DESKEY, new.fields);
499 SET_FIELD(KADM_NAME, new.fields);
500
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);
505
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)
509 {
510 if (status == KADM_NOENTRY)
511 {
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");
40174425 515 }
5eaef520 516 else
517 com_err(whoami, status, " while setting password");
47baf534 518 }
47baf534 519 }
5eaef520 520
521 dest_tkt();
522 return status;
47baf534 523}
3e9b5b7b 524
5eaef520 525int reserve_user(struct msg *message, char *retval)
47baf534 526{
5eaef520 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 */
44d12d58 533 int i; /* A counter */
5eaef520 534
535 /* Log that we are about to reserve a user. */
536 com_err(whoami, 0, "reserving user %s %s", message->first, message->last);
537
538 /* Check to make sure that we can verify this user. */
539 if ((status = verify_user(message, retval)) == SUCCESS)
3e9b5b7b 540 {
5eaef520 541 /* Get the requested login name from leftover packet information. */
542 login = message->leftover;
543
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
547 first. */
548 if ((strlen(login) < MIN_UNAME) || (strlen(login) > MAX_UNAME))
549 status = UREG_INVALID_UNAME;
47baf534 550 }
5eaef520 551 if (status == SUCCESS)
552 if ((login[0] == '_') || isdigit(login[0]))
553 status = UREG_INVALID_UNAME;
554
555 if (status == SUCCESS)
3e9b5b7b 556 {
5eaef520 557 for (i = 0; i < strlen(login); i++)
558 {
559 if (!islower(login[i]) && !isdigit(login[i]) &&
560 (login[i] != '_'))
803d15cb 561 {
5eaef520 562 status = UREG_INVALID_UNAME;
563 break;
803d15cb 564 }
5eaef520 565 }
47baf534 566 }
5eaef520 567 if (status == SUCCESS)
3e9b5b7b 568 {
5eaef520 569 /* Now that we have a valid user with a valid login... */
570
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;
575 q_argv[1] = login;
576 q_argv[2] = fstype_buf;
577 q_argc = 3;
7ac48069 578 status = mr_query(q_name, q_argc, q_argv, NULL, NULL);
5eaef520 579 switch (status)
bac67528 580 {
5eaef520 581 case MR_SUCCESS:
582 status = SUCCESS;
583 break;
584 case MR_IN_USE:
585 status = UREG_LOGIN_USED;
586 break;
587 case MR_DEADLOCK:
588 status = UREG_MISC_ERROR;
589 break;
590 default:
591 critical_alert(FAIL_INST, "%s returned from register_user.",
592 error_message(status));
593 status = UREG_MISC_ERROR;
594 break;
bac67528 595 }
47baf534 596 }
40174425 597
5eaef520 598 if (status == SUCCESS)
3e9b5b7b 599 {
5eaef520 600 /*
601 * Moira login was successfully created; try to reserve kerberos
602 * principal.
603 *
604 * If this routine fails, store the login in the retval so
605 * that it can be used in the client-side error message.
606 */
607 if ((status = reserve_krb(login)) != SUCCESS)
608 strcpy(retval, login);
609 }
610
611 if (status)
612 com_err(whoami, status, " returned from reserve_user");
613 else
614 com_err(whoami, 0, "User reserved");
615
616 return status;
bac67528 617}
47baf534 618
5eaef520 619/* This routine updates a user's registration status to fully
620 registered. */
621int set_final_status(struct msg *message)
47baf534 622{
5eaef520 623 char *login;
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 */
629
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);
634 else
635 sprintf(state, "%d", US_ENROLL_NOT_ALLOWED);
636
637 login = message->db.login;
638 com_err(whoami, 0, "Setting final status for %s to %s", login, state);
639
640 q_name = "update_user_status";
641 q_argc = 2;
642 q_argv[0] = login;
643 q_argv[1] = state;
7ac48069 644 if ((status = mr_query(q_name, q_argc, q_argv, NULL, NULL))
5eaef520 645 != MR_SUCCESS)
646 {
647 if (status == MR_DEADLOCK)
648 status = UREG_MISC_ERROR;
649 else
650 critical_alert(FAIL_INST, "%s returned from update_user_status.",
651 error_message(status));
652 }
653 if (status)
654 com_err(whoami, status, " returned from set_final_status");
655 else
656 com_err(whoami, 0, "Final status set");
657 return status;
bac67528 658}
f46fccfa 659
bac67528 660
5eaef520 661/* This routine is used to set the initial password for the new user. */
662int set_password(struct msg *message, char *retval)
47baf534 663{
5eaef520 664 int status = SUCCESS; /* Return status */
665 char *passwd; /* User's password */
666
667 com_err(whoami, 0, "setting password %s %s", message->first, message->last);
668
669 status = verify_user(message, retval);
670
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))
3e9b5b7b 679 {
5eaef520 680 /* User is in proper state for this transaction. */
681
682 passwd = message->leftover;
683
684 /* Set password. */
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);
688 else
689 /* Otherwise, mark user as finished. */
690 status = set_final_status(message);
bac67528 691 }
40174425 692
5eaef520 693 if (status)
694 com_err(whoami, status, " returned from set_passwd");
695 else
696 com_err(whoami, 0, "Password set");
40174425 697
5eaef520 698 return status;
bac67528 699}
3f5f9b08 700
701
7ac48069 702int getuserinfo(int argc, char **argv, void *qa)
3f5f9b08 703{
7ac48069 704 char **qargv = qa;
5eaef520 705 int status = SUCCESS;
706 int i;
707
708 if (argc != U_END)
709 {
710 critical_alert(FAIL_INST,
711 "Wrong number of args returned from get_user_by_uid");
712 status = MR_ABORT;
3f5f9b08 713 }
5eaef520 714 else
715 {
7ac48069 716 qargv[U_NAME] = strdup(argv[U_NAME]);
5eaef520 717 for (i = 1; i < U_MODTIME; i++)
7ac48069 718 qargv[i + 1] = strdup(argv[i]);
5eaef520 719 qargv[U_MODTIME + 1] = NULL;
720 }
721 return status;
3f5f9b08 722}
723
724
5eaef520 725int set_identity(struct msg *message, char *retval)
3f5f9b08 726{
5eaef520 727 char *q_argv[U_END]; /* Arguments to Moira query */
5eaef520 728 int status = SUCCESS; /* General purpose error status */
5eaef520 729 char *login; /* The login name the user wants */
44d12d58 730 int i; /* A counter */
5eaef520 731
732 /* Log that we are about to reserve a user. */
733 com_err(whoami, 0, "setting identity %s %s",
734 message->first, message->last);
735
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)
3f5f9b08 739 {
5eaef520 740 status = SUCCESS;
741 /* Get the requested login name from leftover packet information. */
742 login = message->leftover;
743
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
747 first. */
748 if ((strlen(login) < MIN_UNAME) || (strlen(login) > MAX_UNAME))
749 status = UREG_INVALID_UNAME;
750 }
751 if (status == SUCCESS)
752 {
753 if ((login[0] == '_') || isdigit(login[0]))
754 status = UREG_INVALID_UNAME;
3f5f9b08 755 }
5eaef520 756 if (status == SUCCESS)
3f5f9b08 757 {
5eaef520 758 for (i = 0; i < strlen(login); i++)
759 {
760 if (!islower(login[i]) && !isdigit(login[i]) &&
761 (login[i] != '_'))
3f5f9b08 762 {
5eaef520 763 status = UREG_INVALID_UNAME;
764 break;
3f5f9b08 765 }
5eaef520 766 }
3f5f9b08 767 }
5eaef520 768 if (status == SUCCESS)
3f5f9b08 769 {
5eaef520 770 /* Now that we have a valid user with a valid login... */
771
772 q_argv[0] = message->db.uid;
773 status = mr_query("get_user_account_by_uid", 1, q_argv,
7ac48069 774 getuserinfo, q_argv);
5eaef520 775 if (status != SUCCESS)
776 {
777 com_err(whoami, status, " while getting user info");
778 return status;
3f5f9b08 779 }
5eaef520 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,
7ac48069 784 NULL, NULL);
5eaef520 785 switch (status)
3f5f9b08 786 {
5eaef520 787 case MR_SUCCESS:
788 status = SUCCESS;
789 break;
790 case MR_IN_USE:
791 case MR_NOT_UNIQUE:
792 status = UREG_LOGIN_USED;
793 break;
794 case MR_DEADLOCK:
795 status = UREG_MISC_ERROR;
796 break;
797 default:
798 critical_alert(FAIL_INST, "%s returned from update_user_account.",
799 error_message(status));
800 status = UREG_MISC_ERROR;
801 break;
3f5f9b08 802 }
803 }
5eaef520 804 if (status == SUCCESS)
3f5f9b08 805 {
5eaef520 806 /* Moira login was successfully created; try to reserve kerberos
807 principal. */
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);
3f5f9b08 812 }
813
5eaef520 814 if (status)
815 com_err(whoami, status, " returned from set_identity");
816 else
817 com_err(whoami, 0, "Identity set");
818
819 return status;
3f5f9b08 820}
821
822
5eaef520 823/* Find out if someone's secure instance password is set.
74cb1181 824 * Returns UREG_ALREADY_REGISTERED if set, SUCCESS (0) if not.
825 */
826
5eaef520 827int get_secure(struct msg *message, char *retval)
74cb1181 828{
5eaef520 829 int status;
830 char *argv[U_END];
831
832 com_err(whoami, 0, "checking status of secure password for %s",
833 message->first);
834 argv[0] = message->first;
7ac48069 835 status = mr_query("get_user_account_by_login", 1, argv, getuserinfo, argv);
5eaef520 836 if (status != SUCCESS)
837 {
838 com_err(whoami, status, " while getting user info");
839 return status;
74cb1181 840 }
5eaef520 841 if (atoi(argv[U_SECURE + 1]))
842 return UREG_ALREADY_REGISTERED;
843 return SUCCESS;
74cb1181 844}
845
846
847/* Set someone's secure instance password. */
848
5eaef520 849int set_secure(struct msg *message, char *retval)
74cb1181 850{
7ac48069 851 int status;
852 char *argv[U_END], *bp, buf[512], *passwd, *id;
5eaef520 853 KTEXT_ST creds;
854 AUTH_DAT auth;
855 C_Block key;
856 Key_schedule keys;
857 Kadm_vals kv;
858 u_long *lkey = (u_long *)key;
859 struct timeval now;
860 static int inited = 0;
861 static char *host;
7ac48069 862 struct utsname uts;
5eaef520 863
864 if (!inited)
865 {
866 inited++;
7ac48069 867 if (uname(&uts) < 0)
5eaef520 868 com_err(whoami, errno, "getting local hostname");
7ac48069 869 host = strdup(krb_get_phost(uts.nodename));
74cb1181 870 }
871
5eaef520 872 com_err(whoami, 0, "setting secure passwd for %s", message->first);
873 argv[0] = message->first;
7ac48069 874 status = mr_query("get_user_account_by_login", 1, argv, getuserinfo, argv);
5eaef520 875 if (status != SUCCESS)
876 {
877 com_err(whoami, status, " while getting user info");
878 return status;
74cb1181 879 }
5eaef520 880 if (atoi(argv[U_SECURE + 1]))
881 {
882 com_err(whoami, UREG_ALREADY_REGISTERED, "in set_secure()");
883 return UREG_ALREADY_REGISTERED;
74cb1181 884 }
885
5eaef520 886 bp = message->encrypted;
887 /* round up to word boundary */
888 bp = (char *)((((u_long)bp + 3) >> 2) << 2);
889
890 creds.length = ntohl(*((int *)bp));
891 bp += sizeof(int);
892 memcpy(creds.dat, bp, creds.length);
893 creds.mbz = 0;
894 bp += creds.length;
895
896 status = krb_rd_req(&creds, "changepw", host, cur_req_sender(), &auth, "");
897 if (status)
898 {
899 status += krb_err_base;
900 com_err(whoami, status, " verifying credentials in set_secure()");
901 return status;
74cb1181 902 }
903
5eaef520 904 message->leftover_len = ntohl(*((int *)(bp)));
905 bp += sizeof(int);
906 message->leftover = bp;
907
908 des_key_sched(auth.session, keys);
909 des_pcbc_encrypt(message->leftover, buf, message->leftover_len,
910 keys, auth.session, 0);
911
912 id = buf;
913 passwd = strchr(buf, ',');
914 *passwd++ = 0;
915
916 if (strcmp(id, argv[U_MITID + 1]))
917 {
918 char buf[32];
919
920 EncryptID(buf, id, argv[U_FIRST + 1], argv[U_LAST + 1]);
921 if (strcmp(buf, argv[U_MITID + 1]))
922 {
923 status = UREG_USER_NOT_FOUND;
924 com_err(whoami, status, "IDs mismatch: %s (%s), %s", id, buf,
925 argv[U_MITID + 1]);
926 return status;
9587d5ff 927 }
74cb1181 928 }
929
5eaef520 930 /* now do actual password setting stuff */
74cb1181 931
5eaef520 932 if ((status = ureg_kadm_init()) != SUCCESS)
933 {
934 com_err(whoami, status, "initing kadm stuff");
935 return status;
74cb1181 936 }
937
5eaef520 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");
947
948 if ((status = kadm_add(&kv)) != KADM_SUCCESS)
949 {
950 com_err(whoami, status, " while creating kerberos principal");
951 return status;
74cb1181 952 }
953
5eaef520 954 argv[0] = message->first;
955 argv[1] = buf;
956 gettimeofday(&now, NULL);
7ac48069 957 sprintf(buf, "%ld", now.tv_sec);
958 status = mr_query("update_user_security_status", 2, argv, getuserinfo, argv);
5eaef520 959 if (status != SUCCESS)
960 {
961 com_err(whoami, status, " while updating user status");
962 return status;
74cb1181 963 }
5eaef520 964 return SUCCESS;
74cb1181 965}
This page took 0.237033 seconds and 5 git commands to generate.