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