]> andersk Git - moira.git/blobdiff - reg_svr/reg_svr.c
dereference NULL bug
[moira.git] / reg_svr / reg_svr.c
index 1b2b75fff067d4ac0dd8856fcd6b1c6ac059f319..72e410c3c28fc1ad56f74d0caabb93ffbd0bc42a 100644 (file)
@@ -11,7 +11,7 @@
  *
  *      This program is a client of the Kerberos admin_server and a
  *      server for the userreg program.  It is not a client of the
- *      Moira server as it is linked with libsmsglue which bypasses
+ *      Moira server as it is linked with libmoiraglue which bypasses
  *      the network protocol.
  */
 
@@ -23,6 +23,7 @@ static char *rcsid_reg_svr_c = "$Header$";
 #include <stdio.h>
 #include <strings.h>
 #include <ctype.h>
+#include <sys/time.h>
 #include <sys/types.h>
 #include <sys/file.h>
 #include <krb.h>
@@ -31,8 +32,8 @@ static char *rcsid_reg_svr_c = "$Header$";
 #include <kadm_err.h>
 #include <krb_err.h>
 #include <errno.h>
-#include "sms.h"
-#include "sms_app.h"
+#include "moira.h"
+#include "moira_site.h"
 #include "reg_svr.h"
 
 extern char admin_errmsg[];
@@ -63,6 +64,7 @@ main(argc,argv)
     init_ureg_err_tbl();
     init_krb_err_tbl();
     init_kadm_err_tbl();
+    initialize_gdss_error_table();
     
     /* Use com_err or output to stderr for all log messages. */    
 #ifdef DEBUG
@@ -73,16 +75,16 @@ main(argc,argv)
     krb_set_tkt_string("/tmp/tkt_ureg");
 
     /* Connect to the Moira server */
-    if ((status = sms_connect(SMS_SERVER)) != SMS_SUCCESS) 
+    if ((status = mr_connect(MOIRA_SERVER)) != MR_SUCCESS) 
     {
-       com_err(whoami, status, " on sms_connect");
+       com_err(whoami, status, " on mr_connect");
        exit(1);
     }
     
     /* Authorize, telling the server who you are */
-    if ((status = sms_auth(whoami)) != SMS_SUCCESS) 
+    if ((status = mr_auth(whoami)) != MR_SUCCESS) 
     {
-       com_err(whoami, status, " on sms_auth");
+       com_err(whoami, status, " on mr_auth");
        exit(1);
     }
     
@@ -115,6 +117,12 @@ main(argc,argv)
          case UREG_SET_IDENT:
            status = set_identity(&message,retval);
            break;
+         case UREG_GET_SECURE:
+           status = get_secure(&message,retval);
+           break;
+         case UREG_SET_SECURE:
+           status = set_secure(&message,retval);
+           break;
          default:
            status = UREG_UNKNOWN_REQUEST;
            critical_alert(FAIL_INST,"Unknown request %d from userreg.",
@@ -134,6 +142,10 @@ int parse_encrypted(message,data)
    the ID sent accross in the packet.  The information in the packet
    was created in the following way:
 
+   The database used to contain encrypted IDs.  Now we don't encrypt
+   them in the database, although there are still some encrypted IDs
+   there.
+
    The plain text ID number was encrypted via EncryptID() resulting
    in the form that would appear in the Moira database.  This is
    concatinated to the plain text ID so that the ID string contains plain
@@ -142,14 +154,14 @@ int parse_encrypted(message,data)
    thing is then DES encrypted using the encrypted ID as the source of
    the key.
 
-   This routine tries each encrypted ID in the database that belongs
+   This routine tries each ID in the database that belongs
    to someone with this user's first and last name and tries to 
    decrypt the packet with this information.  If it succeeds, it returns 
    zero and initializes all the fields of the formatted packet structure
    that depend on the encrypted information. */
 {
-    C_Block key;               /* The key for DES en/decryption */
-    Key_schedule sched;                /* En/decryption schedule */
+    des_cblock key;            /* The key for DES en/decryption */
+    des_key_schedule sched;    /* En/decryption schedule */
     static char decrypt[BUFSIZ];   /* Buffer to hold decrypted information */
     long decrypt_len;          /* Length of decypted ID information */
     char recrypt[14];          /* Buffer to hold re-encrypted information */
@@ -168,14 +180,22 @@ int parse_encrypted(message,data)
        because of the DES encryption routines. */
     decrypt_len = (long)message->encrypted_len;
     
-    /* Get key from the one-way encrypted ID in the Moira database */
-    string_to_key(data->mit_id, key);
+    /* Get key from the possibly one-way encrypted ID in the Moira database */
+    if (data->mit_id[0] >= '0' && data->mit_id[0] <= '9') {
+       char buf[32];
+
+       EncryptID(buf, data->mit_id, message->first, message->last);
+       des_string_to_key(buf, key);
+    } else
+      des_string_to_key(data->mit_id, key);
+
     /* Get schedule from key */
-    key_sched(key, sched);
+    des_key_sched(key, sched);
     /* Decrypt information from packet using this key.  Since decrypt_len
        is an integral multiple of eight bytes, it will probably be null-
        padded. */
-    pcbc_encrypt(message->encrypted,decrypt, decrypt_len, sched, key, DECRYPT);
+    des_pcbc_encrypt(message->encrypted, decrypt, decrypt_len,
+                    sched, key, DES_DECRYPT);
     
     /* Extract the plain text and encrypted ID fields from the decrypted
        packet information. */
@@ -186,6 +206,15 @@ int parse_encrypted(message,data)
        correct key, there is no guarantee that a null will occur
        anywhere in the string. */
     (void) strncpy(idnumber,decrypt,(int)decrypt_len);
+    /* Check that the idnumber of a mismatched decryption doesn't overflow
+     * the buffer.
+     */
+    if (strlen(idnumber) != 9) {
+#ifdef DEBUG
+       com_err(whoami, 0, "idnumber wrong size, probable user mismatch\n");
+#endif
+       return(FAILURE);
+    }
     /* Point temp to the end of the plain text ID number. */
     temp = decrypt + strlen(idnumber) + 1;
     /* Find out how much more packet there is. */
@@ -199,14 +228,10 @@ int parse_encrypted(message,data)
     /* Find out how much more room there is. */
     len = message->encrypted_len - (temp - decrypt);
     
-    /* Now compare encrypted ID's don't match. */
-    if (strcmp(hashid, data->mit_id)) status = FAILURE;
-    if (status == SUCCESS)
-    {
-       EncryptID(recrypt, idnumber, message->first, message->last);
-       /* Now compare encrypted plain text to ID from database. */
-       if (strcmp(recrypt, data->mit_id)) status = FAILURE;
-    }
+    /* Now compare encrypted ID and clear text ID for a match. */
+    if (strcmp(hashid, data->mit_id) &&
+       strcmp(idnumber, data->mit_id))
+      status = FAILURE;
     
     if (status == SUCCESS)
     {
@@ -237,7 +262,7 @@ int db_callproc(argc,argv,queue)
   int argc;                    /* Number of arguments returned by Moira */
   char *argv[];                        /* Arguments returned by Moira */
   struct save_queue *queue;    /* Queue to save information in */
-/* This function is called by sms_query after each tuple found.  It is
+/* This function is called by mr_query after each tuple found.  It is
    used by find_user to cache information about each user found.  */
 {
     struct db_data *data;      /* Structure to store the information in */
@@ -251,8 +276,8 @@ int db_callproc(argc,argv,queue)
     {
        critical_alert
            (FAIL_INST,
-            "Wrong number of arguments returned from get_user_by_name.");
-       status = SMS_ABORT;
+            "Wrong number of arguments returned from get_user_account_by_name.");
+       status = MR_ABORT;
     }
     else
     {
@@ -298,7 +323,7 @@ int find_user(message)
     if (status == SUCCESS)
     {
        /* Get ready to make an Moira query */
-       q_name = "get_user_by_name";
+       q_name = "get_user_account_by_name";
        q_argc = GUBN_ARGS;     /* #defined in this routine */
        q_argv[0] = message->first;
        q_argv[1] = message->last;
@@ -307,13 +332,13 @@ int find_user(message)
        queue = sq_create();
        
        /* Do it */
-       status = sms_query(q_name,q_argc,q_argv,db_callproc,(char *)queue);
+       status = mr_query(q_name,q_argc,q_argv,db_callproc,(char *)queue);
        
 #ifdef DEBUG
        fprintf(stderr," %d returned by get_user_by_name\n",status);
 #endif
        
-       if (status == SMS_SUCCESS) 
+       if (status == MR_SUCCESS) 
        {
            /* Traverse the list, freeing data as we go.  If sq_get_data()
               returns zero if there is no more data on the queue. */
@@ -362,9 +387,9 @@ int verify_user(message,retval)
     status = find_user(message);
 
     /* If Moira coudn't find the user */
-    if (status == SMS_NO_MATCH) 
+    if (status == MR_NO_MATCH) 
        status = UREG_USER_NOT_FOUND;
-    else if (status == SMS_SUCCESS)
+    else if (status == MR_SUCCESS)
     {
        /* If the information sent over in the packet did not point to a
           valid user, the mit_id field in the formatted packet structure
@@ -398,6 +423,9 @@ int verify_user(message,retval)
              case US_ENROLL_NOT_ALLOWED:
                status = UREG_ENROLL_NOT_ALLOWED;
                break;
+           case US_HALF_ENROLLED:
+               status = UREG_HALF_ENROLLED;
+               break;
              default:
                status = UREG_MISC_ERROR;
                critical_alert(FAIL_INST,"Bad user state %d for login %s.",
@@ -611,22 +639,22 @@ int reserve_user(message,retval)
        /* Now that we have a valid user with a valid login... */
 
        /* First, try to reserve the user in Moira. */
-       (void) sprintf(fstype_buf,"%d",SMS_FS_STUDENT);
+       (void) sprintf(fstype_buf,"%d",MR_FS_STUDENT);
        q_name = "register_user";
        q_argv[0] = message->db.uid;
        q_argv[1] = login;
        q_argv[2] = fstype_buf;
        q_argc = 3;
-       status = sms_query(q_name,q_argc,q_argv,null_callproc,(char *)0);
+       status = mr_query(q_name,q_argc,q_argv,null_callproc,(char *)0);
        switch (status)
        {
-         case SMS_SUCCESS:
+         case MR_SUCCESS:
            status = SUCCESS;
            break;
-         case SMS_IN_USE:
+         case MR_IN_USE:
            status = UREG_LOGIN_USED;
            break;
-         case SMS_DEADLOCK:
+         case MR_DEADLOCK:
            status = UREG_MISC_ERROR;
            break;
          default:
@@ -685,9 +713,9 @@ struct msg *message;
     q_argc = 2;
     q_argv[0] = login;
     q_argv[1] = state;
-    if ((status = sms_query(q_name, q_argc, q_argv, null_callproc,
-                           (char *)0)) != SMS_SUCCESS) {
-       if (status == SMS_DEADLOCK)
+    if ((status = mr_query(q_name, q_argc, q_argv, null_callproc,
+                           (char *)0)) != MR_SUCCESS) {
+       if (status == MR_DEADLOCK)
          status = UREG_MISC_ERROR;
        else
          critical_alert(FAIL_INST,"%s returned from update_user_status.",
@@ -718,7 +746,10 @@ int set_password(message,retval)
        is that he exists and has no password. */
     if (status == SUCCESS)
        status = UREG_NO_LOGIN_YET;
-    if (status == UREG_NO_PASSWD_YET)
+    if (((int)message->request == UREG_SET_PASSWORD &&
+        status == UREG_NO_PASSWD_YET) ||
+       ((int)message->request == UREG_GET_KRB &&
+        status == UREG_HALF_ENROLLED))
     {
        /* User is in proper state for this transaction. */
        
@@ -749,21 +780,16 @@ char **argv;
 char **qargv;
 {
     int status = SUCCESS;
+    int  i;
 
     if (argc != U_END) {
        critical_alert(FAIL_INST,
                       "Wrong number of args returned from get_user_by_uid");
-       status = SMS_ABORT;
+       status = MR_ABORT;
     } else {
        qargv[U_NAME] = strsave(argv[U_NAME]);
-       qargv[U_UID+1] = strsave(argv[U_UID]);
-       qargv[U_SHELL+1] = strsave(argv[U_SHELL]);
-       qargv[U_LAST+1] = strsave(argv[U_LAST]);
-       qargv[U_FIRST+1] = strsave(argv[U_FIRST]);
-       qargv[U_MIDDLE+1] = strsave(argv[U_MIDDLE]);
-       qargv[U_STATE+1] = strsave(argv[U_STATE]);
-       qargv[U_MITID+1] = strsave(argv[U_MITID]);
-       qargv[U_CLASS+1] = strsave(argv[U_CLASS]);
+       for (i = 1; i < U_MODTIME; i++)
+         qargv[i+1] = strsave(argv[i]);
        qargv[U_MODTIME+1] = NULL;
     }
     return(status);
@@ -819,27 +845,30 @@ char *retval;
        /* Now that we have a valid user with a valid login... */
 
        q_argv[0] = message->db.uid;
-       status = sms_query("get_user_by_uid", 1, q_argv, getuserinfo, q_argv);
+       status = mr_query("get_user_account_by_uid", 1, q_argv,
+                         getuserinfo, q_argv);
        if (status != SUCCESS) {
            com_err(whoami, status, " while getting user info");
            return(status);
        }
        q_argv[U_NAME+1] = login;
-       status = sms_query("update_user", U_MODTIME+1, q_argv,
+       q_argv[U_STATE+1] = "7";
+       q_argv[U_SIGNATURE+1] = "";
+       status = mr_query("update_user_account", U_MODTIME+1, q_argv,
                           null_callproc, NULL);
        switch (status)
        {
-         case SMS_SUCCESS:
+         case MR_SUCCESS:
            status = SUCCESS;
            break;
-         case SMS_IN_USE:
+         case MR_IN_USE:
            status = UREG_LOGIN_USED;
            break;
-         case SMS_DEADLOCK:
+         case MR_DEADLOCK:
            status = UREG_MISC_ERROR;
            break;
          default:
-           critical_alert(FAIL_INST,"%s returned from update_user.",
+           critical_alert(FAIL_INST,"%s returned from update_user_account.",
                           error_message(status));
            status = UREG_MISC_ERROR;
            break;
@@ -883,3 +912,155 @@ void reg_com_err_hook(whoami, code, fmt, pvar)
        putc('\n', stderr);
        fflush(stderr);
 }
+
+
+/* Find out of someone's secure instance password is set.
+ * Returns UREG_ALREADY_REGISTERED if set, SUCCESS (0) if not.
+ */
+
+int get_secure(message, retval)
+struct msg *message;
+char *retval;
+{
+    int status;
+    char *argv[U_END];
+
+    com_err(whoami, 0, "checking status of secure password for %s",
+           message->first);
+    argv[0] = message->first;
+    status = mr_query("get_user_account_by_login", 1, argv, getuserinfo, argv);
+    if (status != SUCCESS) {
+       com_err(whoami, status, " while getting user info");
+       return(status);
+    }
+    if (atoi(argv[U_SECURE + 1]))
+      return UREG_ALREADY_REGISTERED;
+    return SUCCESS;
+}
+
+
+/* Set someone's secure instance password. */
+
+int set_secure(message, retval)
+struct msg *message;
+char *retval;
+{
+    int status, i;
+    char *argv[U_END], hostbuf[256], *bp, *p, buf[512], *passwd, *id;
+    KTEXT_ST creds;
+    AUTH_DAT auth;
+    C_Block key;
+    Key_schedule keys;
+    Kadm_vals kv;
+    u_long *lkey = (u_long *)key;
+    struct timeval now;
+    static int inited = 0;
+    static char *host;
+
+    if (!inited) {
+       inited++;
+       if (gethostname(hostbuf, sizeof(hostbuf)) < 0)
+         com_err(whoami, errno, "getting local hostname");
+       host = strsave(krb_get_phost(hostbuf));
+    }
+
+    com_err(whoami, 0, "setting secure passwd for %s", message->first);
+    argv[0] = message->first;
+    status = mr_query("get_user_account_by_login", 1, argv, getuserinfo, argv);
+    if (status != SUCCESS) {
+       com_err(whoami, status, " while getting user info");
+       return(status);
+    }
+    if (atoi(argv[U_SECURE + 1])) {
+       com_err(whoami, UREG_ALREADY_REGISTERED, "in set_secure()");
+       return UREG_ALREADY_REGISTERED;
+    }
+
+    bp = message->encrypted;
+    /* round up to word boundary */
+    bp = (char *)((((u_long)bp + 3) >> 2) << 2);
+    
+    creds.length = ntohl(*((int *)bp));
+    bp += sizeof(int);
+    bcopy(bp, creds.dat, creds.length);
+    creds.mbz = 0;
+    bp += creds.length;
+
+#ifdef DEBUG
+    com_err(whoami, 0, "Cred: length %d", creds.length);
+    for (i = 0; i < creds.length; i += 16)
+      com_err(whoami, 0, " %02x %02x %02x %02x %02x %02x %02x %02x  %02x %02x %02x %02x %02x %02x %02x %02x",
+             creds.dat[i+0], creds.dat[i+1], creds.dat[i+2], creds.dat[i+3],
+             creds.dat[i+4], creds.dat[i+5], creds.dat[i+6], creds.dat[i+7],
+             creds.dat[i+8], creds.dat[i+9], creds.dat[i+10], creds.dat[i+11],
+             creds.dat[i+12], creds.dat[i+13], creds.dat[i+14], creds.dat[i+15]);
+#endif /* DEBUG */
+    
+    status = krb_rd_req(&creds, "changepw", host, cur_req_sender(),
+                       &auth, "");
+    if (status) {
+       status += krb_err_base;
+       com_err(whoami, status, " verifying credentials in set_secure()");
+       return(status);
+    }
+
+    message->leftover_len = ntohl(*((int*)(bp)));
+    bp += sizeof(int);
+    message->leftover = bp;
+
+    des_key_sched(auth.session, keys);
+    des_pcbc_encrypt(message->leftover, buf, message->leftover_len,
+                    keys, auth.session, 0);
+
+    id = buf;
+    passwd = index(buf, ',');
+    *passwd++ = 0;
+#ifdef DEBUG
+    com_err(whoami, 0, "Got id: %s, passwd %d chars", id, strlen(passwd));
+#endif
+
+    if (strcmp(id, argv[U_MITID + 1])) {
+       char buf[32];
+
+       EncryptID(buf, id, argv[U_FIRST+1], argv[U_LAST+1]);
+       if (strcmp(buf, argv[U_MITID + 1])) {
+           status = UREG_USER_NOT_FOUND;
+           com_err(whoami, status, "IDs mismatch: %s (%s), %s", id, buf,
+                   argv[U_MITID + 1]);
+           return status;
+       }
+    }
+
+    /* now do actual password setting stuff */
+
+    if ((status = ureg_kadm_init()) != SUCCESS) {
+       com_err(whoami, status, "initing kadm stuff");
+       return(status);
+    }
+
+    bzero((char *)&kv, sizeof(kv));
+    SET_FIELD(KADM_DESKEY, kv.fields);
+    SET_FIELD(KADM_NAME, kv.fields);
+    SET_FIELD(KADM_INST, kv.fields);
+    (void) des_string_to_key(passwd, key);
+    kv.key_low = htonl(lkey[0]);
+    kv.key_high = htonl(lkey[1]);
+    strcpy(kv.name, message->first);
+    strcpy(kv.instance, "extra");
+
+    if ((status = kadm_add(&kv)) != KADM_SUCCESS) {
+       com_err(whoami, status, " while creating kerberos principal");
+       return(status);
+    }
+
+    argv[0] = message->first;
+    argv[1] = buf;
+    gettimeofday(&now, NULL);
+    sprintf(buf, "%d", now.tv_sec);
+    status = mr_query("update_user_security_status", 2, argv, getuserinfo, argv);
+    if (status != SUCCESS) {
+       com_err(whoami, status, " while updating user status");
+       return(status);
+    }
+    return SUCCESS;
+}
This page took 0.051996 seconds and 4 git commands to generate.