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