]> andersk Git - moira.git/blame_incremental - reg_svr/reg_svr.c
sync'ing files for RCS->CVS migration
[moira.git] / reg_svr / reg_svr.c
... / ...
CommitLineData
1/*
2 * $Source$
3 * $Author$
4 * $Header$
5 *
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>.
9 *
10 * Server for user registration with Moira and Kerberos.
11 *
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
14 * Moira server as it is linked with libmoiraglue which bypasses
15 * the network protocol.
16 */
17
18#ifndef lint
19static char *rcsid_reg_svr_c = "$Header$";
20#endif lint
21
22#include <mit-copyright.h>
23#include <stdio.h>
24#include <strings.h>
25#include <ctype.h>
26#include <sys/time.h>
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>
35#include "moira.h"
36#include "moira_site.h"
37#include "reg_svr.h"
38
39extern char admin_errmsg[];
40
41void reg_com_err_hook();
42
43main(argc,argv)
44 int argc;
45 char *argv[];
46{
47 struct msg message; /* Storage for parsed packet */
48 int status = SUCCESS; /* Error status */
49 char retval[BUFSIZ]; /* Buffer to hold return message for client */
50
51 void req_initialize(); /* Initialize request layer */
52 void get_request(); /* Get a request */
53 void report(); /* Respond to a request */
54
55 /* Initialize */
56 whoami = argv[0];
57
58 /* Error messages sent one line at a time */
59 setlinebuf(stderr);
60 setlinebuf(stdout);
61 set_com_err_hook(reg_com_err_hook);
62
63 /* Initialize com_err error tables */
64 init_ureg_err_tbl();
65 init_krb_err_tbl();
66 init_kadm_err_tbl();
67 initialize_gdss_error_table();
68
69 /* 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 */
78 if ((status = mr_connect(MOIRA_SERVER)) != MR_SUCCESS)
79 {
80 com_err(whoami, status, " on mr_connect");
81 exit(1);
82 }
83
84 /* Authorize, telling the server who you are */
85 if ((status = mr_auth(whoami)) != MR_SUCCESS)
86 {
87 com_err(whoami, status, " on mr_auth");
88 exit(1);
89 }
90
91 journal = fopen(REGJOURNAL, "a");
92 if (journal == NULL) {
93 com_err(whoami, errno, " while opening journal file");
94 exit(1);
95 }
96
97 /* Allow request layer to initialize */
98 req_initialize();
99
100 /* Sit around waiting for requests from the client. */
101 for (;;)
102 {
103 get_request(&message);
104
105 switch((int)message.request)
106 {
107 case UREG_VERIFY_USER:
108 status = verify_user(&message,retval);
109 break;
110 case UREG_RESERVE_LOGIN:
111 status = reserve_user(&message,retval);
112 break;
113 case UREG_SET_PASSWORD:
114 case UREG_GET_KRB:
115 status = set_password(&message,retval);
116 break;
117 case UREG_SET_IDENT:
118 status = set_identity(&message,retval);
119 break;
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;
126 default:
127 status = UREG_UNKNOWN_REQUEST;
128 critical_alert(FAIL_INST,"Unknown request %d from userreg.",
129 message.request);
130 break;
131 }
132
133 /* Report what happened to client */
134 report(status, retval);
135 }
136}
137
138int parse_encrypted(message,data)
139 struct msg *message; /* Formatted packet */
140 struct db_data *data; /* Data from the Moira database */
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
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
149 The plain text ID number was encrypted via EncryptID() resulting
150 in the form that would appear in the Moira database. This is
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.
156
157 This routine tries each ID in the database that belongs
158 to someone with this user's first and last name and tries to
159 decrypt the packet with this information. If it succeeds, it returns
160 zero and initializes all the fields of the formatted packet structure
161 that depend on the encrypted information. */
162{
163 des_cblock key; /* The key for DES en/decryption */
164 des_key_schedule sched; /* En/decryption schedule */
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 */
170 char *temp; /* A temporary string pointer */
171 int len; /* Keeps track of length left in packet */
172 int status = SUCCESS; /* Error status */
173
174#ifdef DEBUG
175 com_err(whoami, 0, "Entering parse_encrypted");
176#endif
177
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. */
181 decrypt_len = (long)message->encrypted_len;
182
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
192 /* Get schedule from key */
193 des_key_sched(key, sched);
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. */
197 des_pcbc_encrypt(message->encrypted, decrypt, decrypt_len,
198 sched, key, DES_DECRYPT);
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. */
208 (void) strncpy(idnumber,decrypt,(int)decrypt_len);
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 }
218 /* Point temp to the end of the plain text ID number. */
219 temp = decrypt + strlen(idnumber) + 1;
220 /* Find out how much more packet there is. */
221 len = message->encrypted_len - (temp - decrypt);
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
224 if we have the right key. */
225 (void) strncpy(hashid, temp, min(len, CRYPT_LEN));
226 /* Point temp to the end of the encrypted ID field */
227 temp += strlen(hashid) + 1;
228 /* Find out how much more room there is. */
229 len = message->encrypted_len - (temp - decrypt);
230
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;
235
236 if (status == SUCCESS)
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
243 from the Moira database. */
244 message->db.reg_status = data->reg_status;
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));
249 }
250
251#ifdef DEBUG
252 if (status)
253 com_err(whoami, status, " in parse_encrypted");
254 else
255 com_err(whoami, status, "parse_encrypted succeeded");
256#endif
257
258 return status;
259}
260
261int db_callproc(argc,argv,queue)
262 int argc; /* Number of arguments returned by Moira */
263 char *argv[]; /* Arguments returned by Moira */
264 struct save_queue *queue; /* Queue to save information in */
265/* This function is called by mr_query after each tuple found. It is
266 used by find_user to cache information about each user found. */
267{
268 struct db_data *data; /* Structure to store the information in */
269 int status = SUCCESS; /* Error status */
270
271#ifdef DEBUG
272 com_err(whoami, 0, "Entering db_callproc.");
273#endif
274
275 if (argc != U_END)
276 {
277 critical_alert
278 (FAIL_INST,
279 "Wrong number of arguments returned from get_user_account_by_name.");
280 status = MR_ABORT;
281 }
282 else
283 {
284 /* extract the needed information from the results of the Moira query */
285 data = (struct db_data *)malloc(sizeof(struct db_data));
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));
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);
298 }
299
300 return status;
301}
302
303int find_user(message)
304 struct msg *message; /* Formatted packet structure */
305/* This routine verifies that a user is allowed to register by finding
306 him/her in the Moira database. It returns the status of the Moira
307 query that it calls. */
308{
309#define GUBN_ARGS 2 /* Arguements needed by get_user_by_name */
310 char *q_name; /* Name of query */
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 */
314
315 struct save_queue *queue; /* Queue to hold Moira data */
316 struct db_data *data; /* Structure for data for one tuple */
317 short verified = FALSE; /* Have we verified the user? */
318
319 /* Zero the mit_id field in the formatted packet structure. This
320 being zeroed means that no user was found. */
321 bzero(message->db.mit_id,sizeof(message->db.mit_id));
322
323 if (status == SUCCESS)
324 {
325 /* Get ready to make an Moira query */
326 q_name = "get_user_account_by_name";
327 q_argc = GUBN_ARGS; /* #defined in this routine */
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 */
335 status = mr_query(q_name,q_argc,q_argv,db_callproc,(char *)queue);
336
337#ifdef DEBUG
338 fprintf(stderr," %d returned by get_user_by_name\n",status);
339#endif
340
341 if (status == MR_SUCCESS)
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 */
349 verified = (parse_encrypted(message,data) == SUCCESS);
350 free((char *)data);
351 }
352 }
353
354 /* Destroy the queue */
355 sq_destroy(queue);
356 }
357
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
370int verify_user(message,retval)
371 struct msg *message;
372 char *retval;
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
377{
378 int status = SUCCESS; /* Return status */
379
380 /* Log that we are about to veryify user */
381 com_err(whoami, 0, "verifying user %s %s",message->first,message->last);
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().) */
386
387 status = find_user(message);
388
389 /* If Moira coudn't find the user */
390 if (status == MR_NO_MATCH)
391 status = UREG_USER_NOT_FOUND;
392 else if (status == MR_SUCCESS)
393 {
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. */
397 if (message->db.mit_id[0] == NULL)
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 {
405 case US_NO_LOGIN_YET:
406 status = SUCCESS;
407 break;
408 case US_REGISTERED:
409 status = UREG_ALREADY_REGISTERED;
410 break;
411 case US_NO_PASSWD:
412 status = UREG_NO_PASSWD_YET;
413 break;
414 case US_DELETED:
415 status = UREG_DELETED;
416 break;
417 case US_NOT_ALLOWED:
418 status = UREG_NOT_ALLOWED;
419 break;
420 case US_ENROLLED:
421 status = UREG_ENROLLED;
422 break;
423 case US_ENROLL_NOT_ALLOWED:
424 status = UREG_ENROLL_NOT_ALLOWED;
425 break;
426 case US_HALF_ENROLLED:
427 status = UREG_HALF_ENROLLED;
428 break;
429 default:
430 status = UREG_MISC_ERROR;
431 critical_alert(FAIL_INST,"Bad user state %d for login %s.",
432 message->db.reg_status, message->db.login);
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. */
437 (void) strcpy(retval,message->db.login);
438 }
439 }
440
441 if (status)
442 com_err(whoami, status, " returned from verify_user");
443 else
444 com_err(whoami, 0, "User verified");
445
446 return status;
447}
448
449int ureg_kadm_init()
450{
451 unsigned int status = SUCCESS; /* Return status */
452 static char krbrealm[REALM_SZ]; /* kerberos realm name */
453 static char hostbuf[BUFSIZ], *host; /* local hostname in principal fmt */
454 static int inited = 0;
455 char *p;
456
457#ifdef DEBUG
458 com_err(whoami, 0, "Entering ureg_kadm_init");
459#endif DEBUG
460
461 if (!inited) {
462 inited++;
463 bzero(krbrealm, sizeof(krbrealm));
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 }
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;
476 }
477
478 /* Get keys for interacting with Kerberos admin server. */
479 /* principal, instance, realm, service, service instance, life, file */
480 if (status = krb_get_svc_in_tkt(MOIRA_SNAME, host, krbrealm, PWSERV_NAME,
481 KADM_SINST, 1, KEYFILE))
482 status += krb_err_base;
483
484 if (status != SUCCESS)
485 com_err(whoami, status, " while get admin tickets");
486#ifdef DEBUG
487 else {
488 com_err(whoami, status, "Succeeded in getting admin tickets");
489 }
490#endif
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
499 return status;
500}
501
502int null_callproc(argc,argv,message)
503 int argc;
504 char *argv[];
505 char *message;
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. */
508{
509 critical_alert(FAIL_INST,"Something returned from an update query.");
510 return FAILURE;
511}
512
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;
519{
520 int status = SUCCESS;
521 Kadm_vals new;
522 des_cblock key;
523 u_long *lkey = (u_long *)key;
524
525#ifdef DEBUG
526 com_err(whoami, 0, "Entering reserve_krb");
527#endif DEBUG
528
529 if ((status = ureg_kadm_init()) == SUCCESS) {
530 bzero((char *)&new, sizeof(new));
531 SET_FIELD(KADM_DESKEY, new.fields);
532 SET_FIELD(KADM_NAME, new.fields);
533
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
544 bzero((char *)&new, sizeof(new));
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) {
566 bzero((char *)&new, sizeof(new));
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");
587 }
588 }
589
590 dest_tkt();
591 return(status);
592}
593
594int reserve_user(message,retval)
595 struct msg *message;
596 char *retval;
597{
598 int q_argc; /* Number of arguments to query */
599 char *q_argv[3]; /* Arguments to Moira query */
600 char *q_name; /* Name of Moira query */
601 int status = SUCCESS; /* General purpose error status */
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 */
605
606 /* Log that we are about to reserve a user. */
607 com_err(whoami, 0, "reserving user %s %s",
608 message->first, message->last);
609
610 /* Check to make sure that we can verify this user. */
611 if ((status = verify_user(message,retval)) == SUCCESS)
612 {
613 /* Get the requested login name from leftover packet information. */
614 login = message->leftover;
615
616 /* Check the login name for validity. The login name is currently
617 is allowed to contain lowercase letters in any position and
618 and numbers and underscore characters in any position but the
619 first. */
620 if ((strlen(login) < MIN_UNAME) || (strlen(login) > MAX_UNAME))
621 status = UREG_INVALID_UNAME;
622 }
623 if (status == SUCCESS)
624 if ((login[0] == '_') || isdigit(login[0]))
625 status = UREG_INVALID_UNAME;
626
627 if (status == SUCCESS)
628 {
629 for (i = 0; i < strlen(login); i++)
630 if (!islower(login[i]) && !isdigit(login[i]) &&
631 (login[i] != '_'))
632 {
633 status = UREG_INVALID_UNAME;
634 break;
635 }
636 }
637 if (status == SUCCESS)
638 {
639 /* Now that we have a valid user with a valid login... */
640
641 /* First, try to reserve the user in Moira. */
642 (void) sprintf(fstype_buf,"%d",MR_FS_STUDENT);
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;
648 status = mr_query(q_name,q_argc,q_argv,null_callproc,(char *)0);
649 switch (status)
650 {
651 case MR_SUCCESS:
652 status = SUCCESS;
653 break;
654 case MR_IN_USE:
655 status = UREG_LOGIN_USED;
656 break;
657 case MR_DEADLOCK:
658 status = UREG_MISC_ERROR;
659 break;
660 default:
661 critical_alert(FAIL_INST,"%s returned from register_user.",
662 error_message(status));
663 status = UREG_MISC_ERROR;
664 break;
665 }
666 }
667
668 if (status == SUCCESS)
669 {
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)
678 (void) strcpy(retval, login);
679 }
680
681 if (status)
682 com_err(whoami, status, " returned from reserve_user");
683 else {
684 com_err(whoami, 0, "User reserved");
685 }
686
687 return status;
688}
689
690int set_final_status(message)
691struct msg *message;
692 /* This routine updates a user's registration status to fully
693 registered. */
694{
695 char *login;
696 char *q_name; /* Name of Moira query */
697 int q_argc; /* Number of arguments for Moira query */
698 char *q_argv[2]; /* Arguments to get user by uid */
699 char state[7]; /* Can hold a 16 bit integer */
700 int status; /* Error status */
701
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);
711
712 q_name = "update_user_status";
713 q_argc = 2;
714 q_argv[0] = login;
715 q_argv[1] = state;
716 if ((status = mr_query(q_name, q_argc, q_argv, null_callproc,
717 (char *)0)) != MR_SUCCESS) {
718 if (status == MR_DEADLOCK)
719 status = UREG_MISC_ERROR;
720 else
721 critical_alert(FAIL_INST,"%s returned from update_user_status.",
722 error_message(status));
723 }
724 if (status)
725 com_err(whoami, status, " returned from set_final_status");
726 else
727 com_err(whoami, 0, "Final status set");
728 return status;
729}
730
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. */
736{
737 int status = SUCCESS; /* Return status */
738 char *passwd; /* User's password */
739
740 com_err(whoami, 0, "setting password %s %s",
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;
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))
753 {
754 /* User is in proper state for this transaction. */
755
756 passwd = message->leftover;
757
758 /* Set password. */
759 if ((status = setpass_krb(message->db.login, passwd)) != SUCCESS)
760 /* If failure, allow login name to be used in client
761 error message */
762 (void) strcpy(retval,message->db.login);
763 else
764 /* Otherwise, mark user as finished. */
765 status = set_final_status(message);
766 }
767
768 if (status)
769 com_err(whoami, status, " returned from set_passwd");
770 else
771 com_err(whoami, 0, "Password set");
772
773 return status;
774}
775
776
777int getuserinfo(argc, argv, qargv)
778int argc;
779char **argv;
780char **qargv;
781{
782 int status = SUCCESS;
783 int i;
784
785 if (argc != U_END) {
786 critical_alert(FAIL_INST,
787 "Wrong number of args returned from get_user_by_uid");
788 status = MR_ABORT;
789 } else {
790 qargv[U_NAME] = strsave(argv[U_NAME]);
791 for (i = 1; i < U_MODTIME; i++)
792 qargv[i+1] = strsave(argv[i]);
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 */
804 char *q_argv[U_END]; /* Arguments to Moira query */
805 char *q_name; /* Name of Moira query */
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. */
812 com_err(whoami, 0, "setting identity %s %s",
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
824 is allowed to contain lowercase letters in any position and
825 and numbers and underscore characters in any position but the
826 first. */
827 if ((strlen(login) < MIN_UNAME) || (strlen(login) > MAX_UNAME))
828 status = UREG_INVALID_UNAME;
829 }
830 if (status == SUCCESS)
831 if ((login[0] == '_') || isdigit(login[0]))
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;
848 status = mr_query("get_user_account_by_uid", 1, q_argv,
849 getuserinfo, q_argv);
850 if (status != SUCCESS) {
851 com_err(whoami, status, " while getting user info");
852 return(status);
853 }
854 q_argv[U_NAME+1] = login;
855 q_argv[U_STATE+1] = "7";
856 q_argv[U_SIGNATURE+1] = "";
857 status = mr_query("update_user_account", U_MODTIME+1, q_argv,
858 null_callproc, NULL);
859 switch (status)
860 {
861 case MR_SUCCESS:
862 status = SUCCESS;
863 break;
864 case MR_IN_USE:
865 case MR_NOT_UNIQUE:
866 status = UREG_LOGIN_USED;
867 break;
868 case MR_DEADLOCK:
869 status = UREG_MISC_ERROR;
870 break;
871 default:
872 critical_alert(FAIL_INST,"%s returned from update_user_account.",
873 error_message(status));
874 status = UREG_MISC_ERROR;
875 break;
876 }
877 }
878 if (status == SUCCESS)
879 {
880 /* Moira login was successfully created; try to reserve kerberos
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. */
884 if ((status = reserve_krb(login)) != SUCCESS)
885 (void) strcpy(retval, login);
886 }
887
888 if (status)
889 com_err(whoami, status, " returned from set_identity");
890 else
891 com_err(whoami, 0, "Identity set");
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}
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 }
937 if (atoi(argv[U_SECURE + 1]))
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);
986 bcopy(bp, creds.dat, creds.length);
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;
1017 passwd = index(buf, ',');
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])) {
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 }
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
1042 bzero((char *)&kv, sizeof(kv));
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);
1050 strcpy(kv.instance, "extra");
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.051338 seconds and 5 git commands to generate.