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