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