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