]> andersk Git - moira.git/blame - reg_svr/reg_svr.c
handle secure password stuff
[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,
278 "Wrong number of arguments returned from get_user_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 */
bac67528 325 q_name = "get_user_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;
782
783 if (argc != U_END) {
784 critical_alert(FAIL_INST,
785 "Wrong number of args returned from get_user_by_uid");
2ce085d2 786 status = MR_ABORT;
3f5f9b08 787 } else {
788 qargv[U_NAME] = strsave(argv[U_NAME]);
789 qargv[U_UID+1] = strsave(argv[U_UID]);
790 qargv[U_SHELL+1] = strsave(argv[U_SHELL]);
791 qargv[U_LAST+1] = strsave(argv[U_LAST]);
792 qargv[U_FIRST+1] = strsave(argv[U_FIRST]);
793 qargv[U_MIDDLE+1] = strsave(argv[U_MIDDLE]);
794 qargv[U_STATE+1] = strsave(argv[U_STATE]);
795 qargv[U_MITID+1] = strsave(argv[U_MITID]);
796 qargv[U_CLASS+1] = strsave(argv[U_CLASS]);
797 qargv[U_MODTIME+1] = NULL;
798 }
799 return(status);
800}
801
802
803int set_identity(message,retval)
804struct msg *message;
805char *retval;
806{
807 int q_argc; /* Number of arguments to query */
40174425 808 char *q_argv[U_END]; /* Arguments to Moira query */
809 char *q_name; /* Name of Moira query */
3f5f9b08 810 int status = SUCCESS; /* General purpose error status */
811 char fstype_buf[7]; /* Buffer to hold fs_type, a 16 bit number */
812 char *login; /* The login name the user wants */
813 register int i; /* A counter */
814
815 /* Log that we are about to reserve a user. */
40174425 816 com_err(whoami, 0, "setting identity %s %s",
3f5f9b08 817 message->first, message->last);
818
819 /* Check to make sure that we can verify this user. */
820 status = verify_user(message,retval);
821 if (status == SUCCESS || status == UREG_NOT_ALLOWED)
822 {
823 status = SUCCESS;
824 /* Get the requested login name from leftover packet information. */
825 login = message->leftover;
826
827 /* Check the login name for validity. The login name is currently
40174425 828 is allowed to contain lowercase letters in any position and
829 and numbers and underscore characters in any position but the
3f5f9b08 830 first. */
831 if ((strlen(login) < MIN_UNAME) || (strlen(login) > MAX_UNAME))
832 status = UREG_INVALID_UNAME;
833 }
834 if (status == SUCCESS)
40174425 835 if ((login[0] == '_') || isdigit(login[0]))
3f5f9b08 836 status = UREG_INVALID_UNAME;
837 if (status == SUCCESS)
838 {
839 for (i = 0; i < strlen(login); i++)
840 if (!islower(login[i]) && !isdigit(login[i]) &&
841 (login[i] != '_'))
842 {
843 status = UREG_INVALID_UNAME;
844 break;
845 }
846 }
847 if (status == SUCCESS)
848 {
849 /* Now that we have a valid user with a valid login... */
850
851 q_argv[0] = message->db.uid;
2ce085d2 852 status = mr_query("get_user_by_uid", 1, q_argv, getuserinfo, q_argv);
3f5f9b08 853 if (status != SUCCESS) {
854 com_err(whoami, status, " while getting user info");
855 return(status);
856 }
857 q_argv[U_NAME+1] = login;
d8ffd27c 858 q_argv[U_STATE+1] = "7";
2ce085d2 859 status = mr_query("update_user", U_MODTIME+1, q_argv,
3f5f9b08 860 null_callproc, NULL);
861 switch (status)
862 {
2ce085d2 863 case MR_SUCCESS:
3f5f9b08 864 status = SUCCESS;
865 break;
2ce085d2 866 case MR_IN_USE:
3f5f9b08 867 status = UREG_LOGIN_USED;
868 break;
2ce085d2 869 case MR_DEADLOCK:
62ba0b73 870 status = UREG_MISC_ERROR;
871 break;
3f5f9b08 872 default:
873 critical_alert(FAIL_INST,"%s returned from update_user.",
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;
933 status = mr_query("get_user_account_by_login", 1, argv, getuserinfo, argv);
934 if (status != SUCCESS) {
935 com_err(whoami, status, " while getting user info");
936 return(status);
937 }
938 if (atoi(argv[U_SECURE]))
939 return UREG_ALREADY_REGISTERED;
940 return SUCCESS;
941}
942
943
944/* Set someone's secure instance password. */
945
946int set_secure(message, retval)
947struct msg *message;
948char *retval;
949{
950 int status, i;
951 char *argv[U_END], hostbuf[256], *bp, *p, buf[512], *passwd, *id;
952 KTEXT_ST creds;
953 AUTH_DAT auth;
954 C_Block key;
955 Key_schedule keys;
956 Kadm_vals kv;
957 u_long *lkey = (u_long *)key;
958 struct timeval now;
959 static int inited = 0;
960 static char *host;
961
962 if (!inited) {
963 inited++;
964 if (gethostname(hostbuf, sizeof(hostbuf)) < 0)
965 com_err(whoami, errno, "getting local hostname");
966 host = strsave(krb_get_phost(hostbuf));
967 }
968
969 com_err(whoami, 0, "setting secure passwd for %s", message->first);
970 argv[0] = message->first;
971 status = mr_query("get_user_account_by_login", 1, argv, getuserinfo, argv);
972 if (status != SUCCESS) {
973 com_err(whoami, status, " while getting user info");
974 return(status);
975 }
976 if (atoi(argv[U_SECURE + 1])) {
977 com_err(whoami, UREG_ALREADY_REGISTERED, "in set_secure()");
978 return UREG_ALREADY_REGISTERED;
979 }
980
981 bp = message->encrypted;
982 /* round up to word boundary */
983 bp = (char *)((((u_long)bp + 3) >> 2) << 2);
984
985 creds.length = ntohl(*((int *)bp));
986 bp += sizeof(int);
987 bcopy(bp, creds.dat, creds.length);
988 creds.mbz = 0;
989 bp += creds.length;
990
991#ifdef DEBUG
992 com_err(whoami, 0, "Cred: length %d", creds.length);
993 for (i = 0; i < creds.length; i += 16)
994 com_err(whoami, 0, " %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
995 creds.dat[i+0], creds.dat[i+1], creds.dat[i+2], creds.dat[i+3],
996 creds.dat[i+4], creds.dat[i+5], creds.dat[i+6], creds.dat[i+7],
997 creds.dat[i+8], creds.dat[i+9], creds.dat[i+10], creds.dat[i+11],
998 creds.dat[i+12], creds.dat[i+13], creds.dat[i+14], creds.dat[i+15]);
999#endif /* DEBUG */
1000
1001 status = krb_rd_req(&creds, "changepw", host, cur_req_sender(),
1002 &auth, "");
1003 if (status) {
1004 status += krb_err_base;
1005 com_err(whoami, status, " verifying credentials in set_secure()");
1006 return(status);
1007 }
1008
1009 message->leftover_len = ntohl(*((int*)(bp)));
1010 bp += sizeof(int);
1011 message->leftover = bp;
1012
1013 des_key_sched(auth.session, keys);
1014 des_pcbc_encrypt(message->leftover, buf, message->leftover_len,
1015 keys, auth.session, 0);
1016
1017 id = buf;
1018 passwd = index(buf, ',');
1019 *passwd++ = 0;
1020#ifdef DEBUG
1021 com_err(whoami, 0, "Got id: %s, passwd %d chars", id, strlen(passwd));
1022#endif
1023
1024 if (strcmp(id, argv[U_MITID + 1])) {
1025 status = UREG_USER_NOT_FOUND;
1026 com_err(whoami, status, "IDs mismatch: %s, %s", id, argv[U_MITID + 1]);
1027 return status;
1028 }
1029
1030 /* now do actual password setting stuff */
1031
1032 if ((status = ureg_kadm_init()) != SUCCESS) {
1033 com_err(whoami, status, "initing kadm stuff");
1034 return(status);
1035 }
1036
1037 bzero((char *)&kv, sizeof(kv));
1038 SET_FIELD(KADM_DESKEY, kv.fields);
1039 SET_FIELD(KADM_NAME, kv.fields);
1040 SET_FIELD(KADM_INST, kv.fields);
1041 (void) des_string_to_key(passwd, key);
1042 kv.key_low = htonl(lkey[0]);
1043 kv.key_high = htonl(lkey[1]);
1044 strcpy(kv.name, message->first);
1045 strcpy(kv.instance, "secure");
1046
1047 if ((status = kadm_add(&kv)) != KADM_SUCCESS) {
1048 com_err(whoami, status, " while creating kerberos principal");
1049 return(status);
1050 }
1051
1052 argv[0] = message->first;
1053 argv[1] = buf;
1054 gettimeofday(&now, NULL);
1055 sprintf(buf, "%d", now.tv_sec);
1056 status = mr_query("update_user_security_status", 2, argv, getuserinfo, argv);
1057 if (status != SUCCESS) {
1058 com_err(whoami, status, " while updating user status");
1059 return(status);
1060 }
1061 return SUCCESS;
1062}
This page took 0.26045 seconds and 5 git commands to generate.