]> andersk Git - moira.git/blobdiff - reg_svr/reg_svr.c
Switch from Imake-based build system to autoconf-based.
[moira.git] / reg_svr / reg_svr.c
index d365f7ecd86bd5523828df0d659d7435039c269e..daef5ab7646d6301471ce42a43b2388e648a0d1d 100644 (file)
-/*
- *      $Source$
- *      $Author$
- *      $Header$
- *
- *      Copyright (C) 1987 by the Massachusetts Institute of Technology
+/* $Id$
  *
- *      Server for user registration with SMS and Kerberos.
+ * Server for user registration with Moira and Kerberos.
  *
- *      This program is a client of the SMS server and the Kerberos
- *      admin_server, and is a server for the userreg program.
- * 
- *      $Log$
- *      Revision 1.9  1988-07-26 14:50:40  qjb
- *      Added comments and did some cleaning up in preparation for rewrite.
- *      This version will not run; the last version that will is 1.8.
+ * 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 libmoiraglue which bypasses
+ * the network protocol.
  *
- * Revision 1.8  88/07/20  15:39:25  mar
- * find realm at runtime; don't use hard-coded one
- * 
- * Revision 1.7  88/02/08  15:08:15  mar
- * Moved header file locations
- * 
- * Revision 1.6  87/09/21  15:19:11  wesommer
- * Allow numbers, _, and . as legal characters in the username.
- * 
- * Revision 1.5  87/09/10  22:18:32  wesommer
- * Clean up output format.
- * 
- * Revision 1.4  87/09/04  23:33:19  wesommer
- * Deleted test scaffolding (second oops.)
- * 
- * Revision 1.3  87/09/03  03:05:18  wesommer
- * Version used for userreg tests.
- * 
- * Revision 1.2  87/08/22  18:39:45  wesommer
- * User registration server.
- * 
- * Revision 1.1  87/07/31  15:48:13  wesommer
- * Initial revision
- * 
+ * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
  */
 
-#ifndef lint
-static char *rcsid_reg_svr_c = "$Header$";
-#endif lint
+#include <mit-copyright.h>
+#include <moira.h>
+#include <moira_site.h>
 
+#include <sys/utsname.h>
+
+#include <errno.h>
 #include <stdio.h>
-#include <sys/types.h>
-#include <sys/file.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <krb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
 #include <des.h>
-#include <errno.h>
-#include <ctype.h>
-#include "ureg_err.h"
-#include "ureg_proto.h"
-#include "sms.h"
-#include "admin_server.h"
-#include "admin_err.h"
-#include <strings.h>
-
-#define WHOAMI "reg_svr"       /* Name of program for SMS logging */
-#define CUR_SMS_VERSION SMS_VERSION_2    /* SMS version for this program */
-
-
-extern int abort();
-extern char *strdup();
-extern char *malloc();
-extern int krb_err_base;
+#include <kadm.h>
+#include <kadm_err.h>
+#include <krb.h>
+
+#include "reg_svr.h"
+
+RCSID("$Header$");
+
 extern char admin_errmsg[];
 
-extern int errno;              /* Unix error number */
-
-/* This is the structure used to store the packet information */
-/* Get this.  The register client gets the MIT id of the registering user
-   in plain text, encrypts it with one-way password encryption,
-   concatenates that to the plain text id, and then des encrypts the
-   whole thing using the password encrypted id as the key!  The result
-   goes in enc_mitid. */
-struct msg 
-{    
-    u_long version;            /* SMS version */
-    u_long request;            /* Request */
-    char *first;               /* First name */
-    char *last;                        /* Last name */
-    char *enc_mitid;           /* See comment above */
-    int enc_mitid_len;         /* Length of enc_mitid */
-};
-
-static char errmsg[BUFSIZ];
-
-main()
+FILE *journal;
+char *whoami;
+
+int parse_encrypted(struct msg *message, struct db_data *data);
+int parse_encrypted(struct msg *message, struct db_data *data);
+int db_callproc(int argc, char **argv, void *queue);
+int find_user(struct msg *message);
+int verify_user(struct msg *message, char *retval);
+int ureg_kadm_init(void);
+int reserve_krb(char *login);
+int setpass_krb(char *login, char *password);
+int reserve_user(struct msg *message, char *retval);
+int set_final_status(struct msg *message);
+int set_password(struct msg *message, char *retval);
+int getuserinfo(int argc, char **argv, void *qa);
+int set_identity(struct msg *message, char *retval);
+int get_secure(struct msg *message, char *retval);
+int set_secure(struct msg *message, char *retval);
+
+int main(int argc, char *argv[])
 {
-    struct servent *sp;                /* Service info from /etc/services */
-    int s;                     /* Socket descriptor */
-    struct sockaddr_in sin;    /* Internet style socket address */
-    int addrlen;               /* Size of socket address (sin) */
-    char packet[BUFSIZ];       /* Buffer for packet transmission */
-    int pktlen;                        /* Size of packet */
-    u_long seqno;              /* Sequence number for packet transmission */
-    struct msg message;                /* Storage for parsed packet */
-    int status;                        /* General purpose error status */
-    
-    /* Error messages sent one line at a time */
-    setlinebuf(stderr);
-    
-    /* Initialize user registration error table */
-    init_ureg_err_tbl();
-    
-    /* Get service information from /etc/services */
-    if ((sp = getservbyname("sms_ureg", "udp")) == NULL) 
-    {
-       fprintf(stderr, "Unknown service sms_ureg/udp\n");
-       exit(1);
-    }
-    
-    /* Get an internet style datagram socket */
-    if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) 
-    {
-       perror("socket");
-       exit(1);
-    }
-    bzero((char *)&sin, sizeof(sin));
-    
-    sin.sin_family = AF_INET;
-    sin.sin_port = sp->s_port;
-    sin.sin_addr.s_addr = INADDR_ANY;
-    
-    /* Bind a name to the socket */
-    if (bind(s, &sin, sizeof(sin)) < 0) 
-    {
-       perror("bind");
-       exit(1);
-    }
-    
-    /* Connect to the SMS server */
-    if ((status = sms_connect()) != SMS_SUCCESS) 
-    {
-       com_err(WHOAMI, status, " on connect");
-       exit(1);
-    }
-    
-    /* Authorize, telling the server who you are */
-    if ((status = sms_auth(WHOAMI)) != SMS_SUCCESS) 
-    {
-       com_err(WHOAMI, status, " on auth");
-       exit(1);
-    }
-    
-    /* Sit around waiting for requests from the client. */
-    for (;;) 
-    {
-       com_err(WHOAMI, 0, "Ready for next request");
-       addrlen = sizeof(sin);
-       bzero(errmsg, BUFSIZ);
-       /* Receive a packet into buf. */
-       if ((pktlen = recvfrom(s,packet,sizeof(packet),0,&sin,&addrlen)) < 0) 
-       {
-           perror("recvfrom");
-           if (errno == EINTR) continue;
-           exit(1);
-       }
-       
-       /* Parse a request packet */
-       if ((status = parse_pkt(packet, pktlen, &seqno, &message)) != 0) 
-       {
-           pktlen = sizeof(packet);
-           /* Format packet to send back to the client */
-           format_pkt(packet, &pktlen, seqno, status, (char *)NULL);
-           /* Report the error the the client */
-           (void) sendto(s, packet, pktlen, 0, &sin, addrlen);
-           continue;
-       }
-       
-       /* do action */
-       switch((int)message.request) 
+  struct msg message;          /* Storage for parsed packet */
+  int status = SUCCESS;                /* Error status */
+  char retval[BUFSIZ];         /* Buffer to hold return message for client */
+
+  /* Initialize */
+  whoami = argv[0];
+
+  /* Error messages sent one line at a time */
+  setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
+  setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
+
+  /* Initialize com_err error tables */
+  init_ureg_err_tbl();
+  init_krb_err_tbl();
+  init_kadm_err_tbl();
+  initialize_gdss_error_table();
+
+  /* Set the name of our kerberos ticket file */
+  krb_set_tkt_string("/tmp/tkt_ureg");
+
+  /* Connect to the Moira server */
+  if ((status = mr_connect(MOIRA_SERVER)) != MR_SUCCESS)
+    {
+      com_err(whoami, status, " on mr_connect");
+      exit(1);
+    }
+
+  /* Authorize, telling the server who you are */
+  if ((status = mr_auth(whoami)) != MR_SUCCESS)
+    {
+      com_err(whoami, status, " on mr_auth");
+      exit(1);
+    }
+
+  journal = fopen(REGJOURNAL, "a");
+  if (!journal)
+    {
+      com_err(whoami, errno, " while opening journal file");
+      exit(1);
+    }
+
+  /* Allow request layer to initialize */
+  req_initialize();
+
+  /* Sit around waiting for requests from the client. */
+  for (;;)
+    {
+      get_request(&message);
+
+      switch (message.request)
        {
-         case UREG_VERIFY_USER:
-           status = verify_user(&message);
-           break;
-         case UREG_RESERVE_LOGIN:
-           status = reserve_user(&message);
-           break;
-         case UREG_SET_PASSWORD:
-           status = set_password(&message);
-           break;
-           
-         default:
-           status = UREG_UNKNOWN_REQUEST;
-           break;
+       case UREG_VERIFY_USER:
+         status = verify_user(&message, retval);
+         break;
+       case UREG_RESERVE_LOGIN:
+         status = reserve_user(&message, retval);
+         break;
+       case UREG_SET_PASSWORD:
+       case UREG_GET_KRB:
+         status = set_password(&message, retval);
+         break;
+       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.",
+                        message.request);
+         break;
        }
-       
-       /* Report what happened to client */
-       pktlen = sizeof(packet);
-       format_pkt(packet, &pktlen, seqno, status, errmsg);
-       sendto(s, packet, pktlen, 0, &sin, addrlen);
+
+      /* Report what happened to client */
+      report(status, retval);
     }
 }
 
-int got_one;
-int reg_status;
-char *mit_id;
-char *reg_misc;
-int reg_misc_len;
-int user_id;
-
-#define min(a,b) ((a)>(b)?(b):(a))
-
-int validate_idno(message, db_mit_id, first, last)
-  struct msg *message;         /* Formatted packet */
-  char *db_mit_id;             /* Encrypted MIT ID from SMS database */
-  char *first, *last;          /* First and last name for MIT ID encryption */
 /* This routine makes sure that the ID from the database matches
    the ID sent accross in the packet.  The information in the packet
    was created in the following way:
 
-   The plain text ID number was encrypted via crypt() resulting in
-   the form that would appear in the SMS database.  This is 
-   concatinated to the plain text ID so that the ID string contains
-   plain text ID followed by a null followed by the encrypted ID.
-   The whole thing is then DES encrypted using the encrypted ID as 
-   the source of the key.
+   The database used to contain encrypted IDs.  Now we don't encrypt
+   them in the database, although there are still some encrypted IDs
+   there.
 
-   This routine tries each encrypted 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. */
+   The plain text ID number was encrypted via EncryptID() resulting
+   in the form that would appear in the Moira database.  This is
+   concatenated to the plain text ID so that the ID string contains plain
+   text ID followed by a null followed by the encrypted ID.  Other
+   information such as the username or password is appended.  The whole
+   thing is then DES encrypted using the encrypted ID as the source of
+   the key.
+
+   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. */
+
+int parse_encrypted(struct msg *message, struct db_data *data)
 {
-    C_Block key;               /* The key for DES en/decryption */
-    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 */
-    static char hashid[14];    /* Buffer to hold one-way encrypted ID */
-    char idnumber[BUFSIZ];     /* Buffer to hold plain-text ID */
-    char *temp;                        /* A temporary storage buffer */
-    int len;                   /*  */
-    
-    mit_id = 0;
-    /* Make the decrypted information length the same as the encrypted
-       information length.  Both are integral multples of eight bytes 
-       because of the DES encryption routines. */
-    decrypt_len = (long)message->enc_mitid_len;
-    
-    /* Get key from the one-way encrypted ID in the SMS database */
-    string_to_key(db_mit_id, key);
-    /* Get schedule from key */
-    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->enc_mitid, decrypt, \
-                decrypt_len, sched, key, DECRYPT);
-    
-    /* Extract the plain text and encrypted ID fields from the decrypted
-       packet information. */
-    /* Since the decrypted information starts with the plain-text ID
-       followed by a null, if the decryption worked, this will only 
-       copy the plain text part of the decrypted information.  It is
-       important that strncpy be used because if we are not using the
-       correct key, there is no guarantee that a null will occur
-       anywhere in the string. */
-    (void) strncpy(idnumber, decrypt, decrypt_len);
-    /* Point temp to the end of the plain text ID number. */
-    temp = decrypt + strlen(idnumber) + 1;
-    /* Find out how much more room there is. */
-    len = message->enc_mitid_len - (temp - decrypt);
-    /* Copy the next 14 bytes of the decrypted information into 
-       hashid if there are 14 more bytes to copy.  There will be
-       if we have the right key. */
-    (void) strncpy(hashid, temp, min(len, 14));
-    /* Point temp to the end of the encrypted ID field */
-    temp += strlen(hashid) + 1;
-    /* Find out how much more room there is. */
-    len = message->enc_mitid_len - (temp - decrypt);
-    
-    /* Now compare encrypted ID's returning with an error if they
-       don't match. */
-    if (strcmp(hashid, db_mit_id)) return 1;
-    encrypt_mitid(recrypt, idnumber, first, last);
-    /* Now compare encrypted plain text to ID from database. */
-    if (strcmp(recrypt, db_mit_id)) return 1;
-    
-    /* We made it. */
-    reg_misc = temp;
-    reg_misc_len = len;
-    mit_id = hashid;
-    return 0;
-}
+  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 */
+  static char hashid[14];      /* Buffer to hold one-way encrypted ID */
+  char idnumber[BUFSIZ];       /* Buffer to hold plain-text ID */
+  char *temp;                  /* A temporary string pointer */
+  int len;                     /* Keeps track of length left in packet */
+  int status = SUCCESS;                /* Error status */
+
+  /* Make the decrypted information length the same as the encrypted
+     information length.  Both are integral multples of eight bytes
+     because of the DES encryption routines. */
+  decrypt_len = message->encrypted_len;
 
-static int status_in_db;
+  /* 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);
 
-vfy_callbk(argc, argv, p_message)
-  int argc;                    /* Should sanity check this.. */
-  char **argv;
-  char *p_message;
+  /* Get schedule from key */
+  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. */
+  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. */
+  /* Since the decrypted information starts with the plain-text ID
+     followed by a null, if the decryption worked, this will only
+     copy the plain text part of the decrypted information.  It is
+     important that strncpy be used because if we are not using the
+     correct key, there is no guarantee that a null will occur
+     anywhere in the string. */
+  strncpy(idnumber, decrypt, decrypt_len);
+  /* Check that the idnumber of a mismatched decryption doesn't overflow
+   * the buffer. */
+  if (strlen(idnumber) != 9)
+    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. */
+  len = message->encrypted_len - (temp - decrypt);
+  /* Copy the next CRYPT_LEN bytes of the decrypted information into
+     hashid if there are CRYPT_LEN more bytes to copy.  There will be
+     if we have the right key. */
+  strncpy(hashid, temp, min(len, CRYPT_LEN));
+  /* Point temp to the end of the encrypted ID field */
+  temp += strlen(hashid) + 1;
+  /* Find out how much more room there is. */
+  len = message->encrypted_len - (temp - decrypt);
+
+  /* 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)
+    {
+      /* We made it.  Now we can finish initializing message. */
+      /* Point leftover to whatever is left over! */
+      message->leftover = temp;
+      message->leftover_len = len;
+      /* Since we know we have the right user, fill in the information
+        from the Moira database. */
+      message->db.reg_status = data->reg_status;
+      strncpy(message->db.uid, data->uid, sizeof(message->db.uid));
+      strncpy(message->db.mit_id, data->mit_id, sizeof(message->db.mit_id));
+      strncpy(message->db.login, data->login, sizeof(message->db.login));
+    }
+
+    return status;
+}
+
+/* This function is called by mr_query after each tuple found.  It is
+   used by find_user to cache information about each user found.  */
+int db_callproc(int argc, char **argv, void*queue)
 {
-    struct msg *message = (struct msg *)p_message;
-    char *db_mit_id;
-    char *firstname, *lastname;
-    int status;
-    
-    if (got_one) return 0;
-    reg_status = 0;
-    
-    db_mit_id = argv[8];
-    firstname = argv[5];
-    lastname = argv[4];
-    
-    status = validate_idno(message, db_mit_id, firstname, lastname);
-    if (status) return 0; /* Nope; decryption failed */
-    
-    status_in_db = atoi(argv[7]);
-    reg_status = status_in_db;    
-    
-    if (status_in_db != 0) 
-    {
-       (void) strcpy(errmsg, argv[0]);
-    }
-    user_id = atoi(argv[1]);
-    got_one = 1;
-    return 0;
-}    
-
-encrypt_mitid(buf, idnumber, first, last)
-    char *buf, *idnumber, *first, *last;
+  struct db_data *data;        /* Structure to store the information in */
+  int status = SUCCESS;        /* Error status */
+
+  if (argc != U_END)
+    {
+      critical_alert(FAIL_INST, "Wrong number of arguments returned "
+                    "from get_user_account_by_name.");
+      status = MR_ABORT;
+    }
+  else
+    {
+      /* extract the needed information from the results of the Moira query */
+      data = malloc(sizeof(struct db_data));
+      data->reg_status = atoi(argv[U_STATE]);
+      strncpy(data->login, argv[U_NAME], sizeof(data->login));
+      strncpy(data->mit_id, argv[U_MITID], sizeof(data->mit_id));
+      strncpy(data->uid, argv[U_UID], sizeof(data->uid));
+      sq_save_data(queue, data);
+    }
+
+  return status;
+}
+
+/* This routine verifies that a user is allowed to register by finding
+   him/her in the Moira database.  It returns the status of the Moira
+   query that it calls. */
+int find_user(struct msg *message)
 {
-    char salt[3];
-    extern char *crypt();
-    
-#define _tolower(c) ((c)|0x60)
-    
-    salt[0] = _tolower(last[0]);
-    salt[1] = _tolower(first[0]);
-    salt[2] = 0;
-    
-    (void) strcpy(buf, crypt(&idnumber[2], salt));
+#define GUBN_ARGS 2            /* Arguements needed by get_user_by_name */
+  char *q_name;                        /* Name of Moira query */
+  int q_argc;                  /* Number of arguments for query */
+  char *q_argv[GUBN_ARGS];     /* Arguments to query */
+  int status = SUCCESS;                /* Query return status */
+
+  struct save_queue *queue;    /* Queue to hold Moira data */
+  struct db_data *data;                /* Structure for data for one tuple */
+  short verified = FALSE;      /* Have we verified the user? */
+
+  /* Zero the mit_id field in the formatted packet structure.  This
+     being zeroed means that no user was found. */
+  memset(message->db.mit_id, 0, sizeof(message->db.mit_id));
+
+  if (status == SUCCESS)
+    {
+      /* Get ready to make a Moira query */
+      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;
+
+      /* Create queue to hold information */
+      queue = sq_create();
+
+      /* Do it */
+      status = mr_query(q_name, q_argc, q_argv, db_callproc, queue);
+
+      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. */
+         while (sq_get_data(queue, &data))
+           {
+             if (!verified)
+               /* parse_encrypted returns zero on success */
+               verified = (parse_encrypted(message, data) == SUCCESS);
+             free(data);
+           }
+       }
+
+      /* Destroy the queue */
+      sq_destroy(queue);
+    }
+
+  return status;
 }
 
-int verify_user(message)
-  struct msg *message;
+/* This routine determines whether a user is in the databse and returns
+   his state so that other routines can figure out whether he is the
+   correct state for various transactions. */
+int verify_user(struct msg *message, char *retval)
 {
-    char *argv[3];
-    int status;
-    
-    com_err(WHOAMI, 0, " verify_user %s %s\n",
-           message->first, message->last);
-    argv[0] = "get_user_by_first_and_last";
-    argv[1] = message->first;
-    argv[2] = message->last;
-    got_one = 0;
-    
-    status = sms_query_internal(3, argv, vfy_callbk, (char *)message);
-    
-    if (status == SMS_NO_MATCH) status = UREG_USER_NOT_FOUND;
-    if (!got_one && !status)
+  int status = SUCCESS;        /* Return status */
+
+  /* Log that we are about to veryify user */
+  com_err(whoami, 0, "verifying user %s %s", message->first, message->last);
+
+  /* Figure out what user (if any) can be found based on the
+     encrypted information in the packet.  (See the comment on
+     parse_encrypted().) */
+
+  status = find_user(message);
+
+  /* If Moira coudn't find the user */
+  if (status == MR_NO_MATCH)
+    status = UREG_USER_NOT_FOUND;
+  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
+        will be empty. */
+      if (message->db.mit_id[0] == '\0')
        status = UREG_USER_NOT_FOUND;
-    
-    if (status != SMS_SUCCESS) goto punt;
-    
-    if (reg_status == 1) status = UREG_ALREADY_REGISTERED;
-    if (reg_status == 2) status = UREG_NO_PASSWD_YET;
-    
-  punt:
-    return status;
+      /* If the user was found but the registration has already started,
+        use this as the status */
+      else
+       {
+         switch (message->db.reg_status)
+           {
+           case US_NO_LOGIN_YET:
+             status = SUCCESS;
+             break;
+           case US_REGISTERED:
+             status = UREG_ALREADY_REGISTERED;
+             break;
+           case US_NO_PASSWD:
+             status = UREG_NO_PASSWD_YET;
+             break;
+           case US_DELETED:
+             status = UREG_DELETED;
+             break;
+           case US_NOT_ALLOWED:
+             status = UREG_NOT_ALLOWED;
+             break;
+           case US_ENROLLED:
+             status = UREG_ENROLLED;
+             break;
+           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.",
+                            message->db.reg_status, message->db.login);
+             break;
+           }
+         /* Set retval to the login name so that the client can use
+            it in the error message it will give the user. */
+         strcpy(retval, message->db.login);
+       }
+    }
+
+  if (status)
+    com_err(whoami, status, " returned from verify_user");
+  else
+    com_err(whoami, 0, "User verified");
+
+  return status;
 }
 
-reserve_user(message)
-  struct msg *message;
+int ureg_kadm_init(void)
 {
-    char *argv[3];
-    int status;
-    int i;
-    char *login;
-    char uid_buf[20];
-    char realm[REALM_SZ];
-    
-    com_err(WHOAMI, 0, " reserve_user %s %s\n",
-           message->first, message->last);
-    
-    argv[0] = "gufl";          /* get_user_by_first_and_last */
-    argv[1] = message->first;
-    argv[2] = message->last;
-    got_one = 0;
-    
-    status = sms_query_internal(3, argv, vfy_callbk, (char *)message);
-    
-    if (status == SMS_NO_MATCH) status = UREG_USER_NOT_FOUND;
-    if (!got_one && !status)
-       status = UREG_USER_NOT_FOUND;
-    
-    if (status != SMS_SUCCESS) goto punt;
-    if (reg_status != 0) 
+  unsigned int status = SUCCESS;        /* Return status */
+  static char krbrealm[REALM_SZ];       /* kerberos realm name */
+  static char *host;                    /* local hostname in principal fmt */
+  static int inited = 0;
+  char *p;
+  struct utsname uts;
+
+  if (!inited)
     {
-       status = UREG_ALREADY_REGISTERED;
-       goto punt;
+      inited++;
+      memset(krbrealm, 0, sizeof(krbrealm));
+      if ((status = krb_get_lrealm(krbrealm, 1)))
+       {
+         status += krb_err_base;
+         com_err(whoami, status, " fetching kerberos realm");
+         exit(1);
+       }
+      if (uname(&uts) < 0)
+       com_err(whoami, errno, "getting local hostname");
+      host = canonicalize_hostname(strdup(uts.nodename));
+      for (p = host; *p && *p != '.'; p++)
+       {
+         if (isupper(*p))
+           *p = tolower(*p);
+       }
+      *p = 0;
     }
-    /*
-     * He's made it past this phase already.
-     */
-    if (status_in_db == 2) 
+
+  /* Get keys for interacting with Kerberos admin server. */
+  /* principal, instance, realm, service, service instance, life, file */
+  if ((status = krb_get_svc_in_tkt(MOIRA_SNAME, host, krbrealm, PWSERV_NAME,
+                                  KADM_SINST, 1, KEYFILE)))
+    status += krb_err_base;
+
+  if (status != SUCCESS)
+    com_err(whoami, status, " while get admin tickets");
+  else
     {
-       status = 0;
-       goto punt;
+      if ((status = kadm_init_link(PWSERV_NAME, KADM_SINST, krbrealm)) !=
+         KADM_SUCCESS)
+       com_err(whoami, status, " while initializing kadmin connection");
     }
-    
-    for (i = 0; i < reg_misc_len && reg_misc[i]; i++) 
+
+  return status;
+}
+
+/*
+ * This routine reserves a principal in kerberos by setting up a
+ * principal with a random initial key.
+ */
+int reserve_krb(char *login)
+{
+  int status = SUCCESS;
+  Kadm_vals new;
+  des_cblock key;
+  u_long *lkey = (u_long *)key;
+
+  if ((status = ureg_kadm_init()) == SUCCESS)
     {
-       if (!islower(reg_misc[i]) && !isdigit(reg_misc[i]) &&
-           reg_misc[i] != '_' && reg_misc[i] != '.') 
+      memset(&new, 0, sizeof(new));
+      SET_FIELD(KADM_DESKEY, new.fields);
+      SET_FIELD(KADM_NAME, new.fields);
+
+      des_random_key(key);
+      new.key_low = htonl(lkey[0]);
+      new.key_high = htonl(lkey[1]);
+      strcpy(new.name, login);
+
+      com_err(whoami, 0, "Creating kerberos principal for %s", login);
+      status = kadm_add(&new);
+      if (status != KADM_SUCCESS)
+       com_err(whoami, status, " while reserving principal");
+
+      memset(&new, 0, sizeof(new));
+    }
+
+  dest_tkt();
+
+  return status;
+}
+
+/*
+ * This routine reserves a principal in kerberos by setting up a
+ * principal with a random initial key.
+ */
+int setpass_krb(char *login, char *password)
+{
+  int status = SUCCESS;
+  Kadm_vals new;
+  des_cblock key;
+  u_long *lkey = (u_long *)key;
+
+  if ((status = ureg_kadm_init()) == SUCCESS)
+    {
+      memset(&new, 0, sizeof(new));
+      SET_FIELD(KADM_DESKEY, new.fields);
+      SET_FIELD(KADM_NAME, new.fields);
+
+      des_string_to_key(password, key);
+      new.key_low = htonl(lkey[0]);
+      new.key_high = htonl(lkey[1]);
+      strcpy(new.name, login);
+
+      com_err(whoami, 0, "Setting password for %s", login);
+      /* First arguement is not used if user has modify privileges */
+      if ((status = kadm_mod(&new, &new)) != KADM_SUCCESS)
        {
-           status = UREG_INVALID_UNAME;
-           goto punt;
+         if (status == KADM_NOENTRY)
+           {
+             com_err(whoami, 0, "kerberos principal doesn't exist; creating");
+             if ((status = kadm_add(&new)) != KADM_SUCCESS)
+               com_err(whoami, status, " while creating kerberos principal");
+           }
+         else
+           com_err(whoami, status, " while setting password");
        }
     }
-    if (i < 3 || i > 8) 
+
+  dest_tkt();
+  return status;
+}
+
+int reserve_user(struct msg *message, char *retval)
+{
+  int q_argc;                  /* Number of arguments to query */
+  char *q_argv[3];             /* Arguments to Moira query */
+  char *q_name;                        /* Name of Moira query */
+  int status = SUCCESS;                /* General purpose error status */
+  char fstype_buf[7];          /* Buffer to hold fs_type, a 16 bit number */
+  char *login;                 /* The login name the user wants */
+  int i;                       /* A counter */
+
+  /* Log that we are about to reserve a user. */
+  com_err(whoami, 0, "reserving user %s %s", message->first, message->last);
+
+  /* Check to make sure that we can verify this user. */
+  if ((status = verify_user(message, retval)) == SUCCESS)
     {
+      /* Get the requested login name from leftover packet information. */
+      login = message->leftover;
+
+      /* Check the login name for validity.  The login name is currently
+        is allowed to contain lowercase letters in any position and
+        and numbers and underscore characters in any position but the
+        first. */
+      if ((strlen(login) < MIN_UNAME) || (strlen(login) > MAX_UNAME))
        status = UREG_INVALID_UNAME;
-       goto punt;
-    }
-    login = reg_misc;
-    
-    /* Send request to kerberos admin_server for login name */
-    /* get keys */
-    if ((status = get_krbrlm(realm, 1)) != KSUCCESS) 
-    {
-       status += krb_err_base;
-       goto punt;
-    }
-    status = get_svc_in_tkt("register", "sms", realm,
-                           "changepw", "kerberos",
-                           1, "/etc/srvtab");
-    if (status) 
-    {
-       status += krb_err_base;
-       goto punt;
-    }
-    
-    /* send set password request to kerberos admin_server */
-    (void) sprintf(uid_buf, "%013d", user_id); /* 13 chars of placebo */
-    /* for backwards-compat. */
-    
-    status = admin_call(ADMIN_ADD_NEW_KEY_ATTR, login, "", 
-                       "", uid_buf);
-    
-    if (status) 
-    {
-       if (status == ADMIN_SERVER_ERROR) 
+    }
+  if (status == SUCCESS)
+    if ((login[0] == '_') || isdigit(login[0]))
+      status = UREG_INVALID_UNAME;
+
+  if (status == SUCCESS)
+    {
+      for (i = 0; i < strlen(login); i++)
        {
-           printf("Server error: %s\n", admin_errmsg);
-           
-           if (strcmp(admin_errmsg,
-                      "Principal already in kerberos database.") ==0)
-               status = UREG_LOGIN_USED;
+         if (!islower(login[i]) && !isdigit(login[i]) &&
+             (login[i] != '_'))
+           {
+             status = UREG_INVALID_UNAME;
+             break;
+           }
        }
-       goto punt;
-    }
-    
-    dest_tkt();
-    /* If valid: */
-    
-    /* Set login name */
-    status = set_login(login, mit_id);
-    
-    
-    if (status) 
-    {
-       com_err("set_login", status, (char *)0);
-       goto punt;
-    }
-    /* choose post office */
-    
-    status = choose_pobox(login);
-    if (status) 
-    {
-       com_err("choose_pobox", status, (char *)0);
-       goto punt;
-    }
-    /* create group */
-    
-    status = create_group(login);
-    if (status == SMS_LIST) status = UREG_LOGIN_USED;
-    
-    if (status) 
-    {
-       com_err("create_group", status, (char *)0);
-       goto punt;
-    }
-    /* set quota entry, create filsys */
-    
-    status = alloc_filsys(login, SMS_FS_STUDENT, 0, 0);
-    if (status == SMS_FILESYS_EXISTS) status = UREG_LOGIN_USED;
-    if (status) 
-    {
-       com_err("alloc_filsys", status, (char *)0);
-       goto punt;
-    }
-    /* set filsys and status in SMS database */
-    
-    status = set_status_filsys(reg_misc, mit_id);
-    if (status) 
-    {
-       com_err("set_filsys", status, (char *)0);
-       goto punt;
-    }
-  punt:
-    dest_tkt();
-    
-    com_err(WHOAMI, status, " returned from reserve_user");
-    return status;
+    }
+  if (status == SUCCESS)
+    {
+      /* Now that we have a valid user with a valid login... */
+
+      /* First, try to reserve the user in Moira. */
+      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 = mr_query(q_name, q_argc, q_argv, NULL, NULL);
+      switch (status)
+       {
+       case MR_SUCCESS:
+         status = SUCCESS;
+         break;
+       case MR_IN_USE:
+         status = UREG_LOGIN_USED;
+         break;
+       case MR_DEADLOCK:
+         status = UREG_MISC_ERROR;
+         break;
+       default:
+         critical_alert(FAIL_INST, "%s returned from register_user.",
+                        error_message(status));
+         status = UREG_MISC_ERROR;
+         break;
+       }
+    }
+
+  if (status == SUCCESS)
+    {
+      /*
+       * Moira login was successfully created; try to reserve kerberos
+       * principal.
+       *
+       * If this routine fails, store the login in the retval so
+       * that it can be used in the client-side error message.
+       */
+      if ((status = reserve_krb(login)) != SUCCESS)
+       strcpy(retval, login);
+    }
+
+  if (status)
+    com_err(whoami, status, " returned from reserve_user");
+  else
+    com_err(whoami, 0, "User reserved");
+
+  return status;
 }
 
-set_password(message)
-  struct msg *message;
+/* This routine updates a user's registration status to fully
+   registered. */
+int set_final_status(struct msg *message)
 {
-    char *argv[3];
-    int status;
-    char uid_buf[10];
-    char realm[REALM_SZ];
-    
-    com_err(WHOAMI, 0, " set_password %s %s\n",
-           message->first, message->last);
-    
-    /* validate that user is who he claims to be */
-    
-    argv[0] = "get_user_by_first_and_last";
-    argv[1] = message->first;
-    argv[2] = message->last;
-    got_one = 0;
-    
-    status = sms_query_internal(3, argv, vfy_callbk, (char *)message);
-    
-    if (status == SMS_NO_MATCH) status = UREG_USER_NOT_FOUND;
-    if (!got_one && !status)
-       status = UREG_USER_NOT_FOUND;
-    
-    if (status != SMS_SUCCESS) goto punt;
-    
-    /* validate that state is equal to '2' (login, but no password) */
-    
-    if (reg_status != 2) 
-    {
-       status = UREG_NO_LOGIN_YET;
-       goto punt;
-    }
-    
-    /* get keys */
-    if ((status = get_krbrlm(realm, 1)) != KSUCCESS) 
-    {
-       goto punt;
-    }
-    status = get_svc_in_tkt("register", "sms", realm,
-                           "changepw", "kerberos",
-                           1, "/etc/srvtab");
-    if (status) 
-    {
-       status += krb_err_base;
-       goto punt;
-    }
-    
-    (void) sprintf(uid_buf, "%013d", user_id); /* 13 chars of placebo */
-    /* for backwards-compat. */
-    /* send set password request to kerberos admin_server */
-    /**####**/
-    status = admin_call(ADMIN_ADD_NEW_KEY_ATTR, errmsg, "", 
-                       reg_misc, uid_buf);
-    
-    if (status) goto punt;
-    dest_tkt();
-    /**#####**/    
-    status = set_final_status(errmsg, mit_id);
-    
-    /* reflect reply to client */
-  punt:
-    dest_tkt();
-    return status;
+  char *login;
+  char *q_name;                        /* Name of Moira query */
+  int q_argc;                  /* Number of arguments for Moira query */
+  char *q_argv[2];             /* Arguments to get user by uid */
+  char state[7];               /* Can hold a 16 bit integer */
+  int status;                  /* Error status */
+
+  if (message->request == UREG_SET_PASSWORD)
+    sprintf(state, "%d", US_REGISTERED);
+  else if (message->db.reg_status == US_NO_LOGIN_YET)
+    sprintf(state, "%d", US_ENROLLED);
+  else
+    sprintf(state, "%d", US_ENROLL_NOT_ALLOWED);
+
+  login = message->db.login;
+  com_err(whoami, 0, "Setting final status for %s to %s", login, state);
+
+  q_name = "update_user_status";
+  q_argc = 2;
+  q_argv[0] = login;
+  q_argv[1] = state;
+  if ((status = mr_query(q_name, q_argc, q_argv, NULL, NULL))
+      != MR_SUCCESS)
+    {
+      if (status == MR_DEADLOCK)
+       status = UREG_MISC_ERROR;
+      else
+       critical_alert(FAIL_INST, "%s returned from update_user_status.",
+                      error_message(status));
+    }
+  if (status)
+    com_err(whoami, status, " returned from set_final_status");
+  else
+    com_err(whoami, 0, "Final status set");
+  return status;
 }
 
-parse_pkt(packet, pktlen, seqnop, messagep)
-  char *packet;
-  int pktlen;
-  u_long *seqnop;
-  struct msg *messagep;
-  /* This routine checks a packet and puts the information in it in
-       a structure if it is valid. */
+
+/* This routine is used to set the initial password for the new user. */
+int set_password(struct msg *message, char *retval)
 {
-    if (pktlen < 4) return UREG_BROKEN_PACKET;
-    /* Extract the SMS version from the packet */
-    bcopy(packet, (char *)&messagep->version, sizeof(long));
-    /* Convert byte order from network to host */
-    messagep->version = ntohl(messagep->version);
-    /* Verify version */
-    if (messagep->version != CUR_SMS_VERSION) return UREG_WRONG_VERSION;
-    
-    packet += 4;
-    pktlen -= 4;
-    
-    if (pktlen < 4) return UREG_BROKEN_PACKET;
-    /* Extract the sequence number from the packet */
-    bcopy(packet, (char *)seqnop, sizeof(long));
-    
-    packet += 4;
-    pktlen -= 4;
-    
-    if (pktlen < 4) return UREG_BROKEN_PACKET;
-    /* Extract the request from the packet */
-    bcopy(packet, (char *)(&messagep->request), sizeof(long));
-    messagep->request = ntohl(messagep->request);
-    packet += 4;
-    pktlen -= 4;
-    
-    /* Extract first name from the packet */
-    messagep->first = packet;
-    
-    /* Scan forward until null appears in the packet or there
-       is no more packet! */
-    for (; *packet && pktlen > 0; --pktlen, ++packet) continue;
-    if (pktlen <= 0) return UREG_BROKEN_PACKET;
-    
-    /* Skip over the null */
-    packet++, pktlen--;
-    
-    /* Extract last name from the packet */
-    messagep->last = packet;
-    
-    for (; *packet && pktlen > 0; --pktlen, ++packet) continue;
-    if (pktlen <= 0) return UREG_BROKEN_PACKET;
-    
-    packet++, pktlen--;
-    
-    if (pktlen <= 0) return UREG_BROKEN_PACKET;
-    
-    /* Extract MIT id information from packet; see comment on
-       struct msg. */
-    messagep->enc_mitid = packet;
-    messagep->enc_mitid_len = pktlen;
-    
-    return 0;
+  int status = SUCCESS;        /* Return status */
+  char *passwd;                /* User's password */
+
+  com_err(whoami, 0, "setting password %s %s", message->first, message->last);
+
+  status = verify_user(message, retval);
+
+  /* Don't set the password unless the registration status of the user
+     is that he exists and has no password. */
+  if (status == SUCCESS)
+    status = UREG_NO_LOGIN_YET;
+  if ((message->request == UREG_SET_PASSWORD &&
+       status == UREG_NO_PASSWD_YET) ||
+      (message->request == UREG_GET_KRB &&
+       status == UREG_HALF_ENROLLED))
+    {
+      /* User is in proper state for this transaction. */
+
+      passwd = message->leftover;
+
+      /* Set password. */
+      if ((status = setpass_krb(message->db.login, passwd)) != SUCCESS)
+       /* If failure, allow login name to be used in client error message */
+       strcpy(retval, message->db.login);
+      else
+       /* Otherwise, mark user as finished. */
+       status = set_final_status(message);
+    }
+
+  if (status)
+    com_err(whoami, status, " returned from set_passwd");
+  else
+    com_err(whoami, 0, "Password set");
+
+  return status;
 }
 
-format_pkt(packet, pktlenp, seqno, status, message)
-  char *packet;
-  int *pktlenp;
-  u_long seqno;
-  int status;
-  char *message;
-  /* This routine prepares a packet to send back to the client. */
+
+int getuserinfo(int argc, char **argv, void *qa)
 {
-    u_long vers = htonl((u_long)CUR_SMS_VERSION);
-    status = htonl((u_long)status);
-    
-    /* Put current SMS version into the packet */
-    bcopy((char *)&vers, packet, sizeof(long));
-    /* Put sequence number into the packet */
-    bcopy((char *)&seqno, packet+sizeof(long), sizeof(long));
-    /* Put error status into the packet */
-    bcopy((char *)&status, packet+ 2*sizeof(long), sizeof(long));
-    *pktlenp = sizeof(long) * 3;
-    /* Copy the message into the packet */
-    (void) strcpy(packet+3*sizeof(long), message);
-    (*pktlenp) += strlen(message);
+  char **qargv = qa;
+  int status = SUCCESS;
+  int  i;
+
+  if (argc != U_END)
+    {
+      critical_alert(FAIL_INST,
+                    "Wrong number of args returned from get_user_by_uid");
+      status = MR_ABORT;
+    }
+  else
+    {
+      qargv[U_NAME] = strdup(argv[U_NAME]);
+      for (i = 1; i < U_MODTIME; i++)
+       qargv[i + 1] = strdup(argv[i]);
+      qargv[U_MODTIME + 1] = NULL;
+    }
+  return status;
 }
 
-store_user(argc, argv, argp)
-  int argc;
-  char **argv;
-    char *argp;
+
+int set_identity(struct msg *message, char *retval)
 {
-    char **retv = (char **) argp;
-    int i;
-    
-    for (i = 0; i < argc; i++) 
+  char *q_argv[U_END];         /* Arguments to Moira query */
+  int status = SUCCESS;                /* General purpose error status */
+  char *login;                 /* The login name the user wants */
+  int i;                       /* A counter */
+
+  /* Log that we are about to reserve a user. */
+  com_err(whoami, 0, "setting identity %s %s",
+         message->first, message->last);
+
+  /* Check to make sure that we can verify this user. */
+  status = verify_user(message, retval);
+  if (status == SUCCESS || status == UREG_NOT_ALLOWED)
+    {
+      status = SUCCESS;
+      /* Get the requested login name from leftover packet information. */
+      login = message->leftover;
+
+      /* Check the login name for validity.  The login name is currently
+        is allowed to contain lowercase letters in any position and
+        and numbers and underscore characters in any position but the
+        first. */
+      if ((strlen(login) < MIN_UNAME) || (strlen(login) > MAX_UNAME))
+       status = UREG_INVALID_UNAME;
+    }
+  if (status == SUCCESS)
+    {
+      if ((login[0] == '_') || isdigit(login[0]))
+       status = UREG_INVALID_UNAME;
+    }
+  if (status == SUCCESS)
+    {
+      for (i = 0; i < strlen(login); i++)
+       {
+         if (!islower(login[i]) && !isdigit(login[i]) &&
+             (login[i] != '_'))
+           {
+             status = UREG_INVALID_UNAME;
+             break;
+           }
+       }
+    }
+  if (status == SUCCESS)
     {
-       if (retv[i]) 
+      /* Now that we have a valid user with a valid login... */
+
+      q_argv[0] = message->db.uid;
+      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;
+      q_argv[U_STATE + 1] = "7";
+      q_argv[U_SIGNATURE + 1] = "";
+      status = mr_query("update_user_account", U_MODTIME + 1, q_argv,
+                       NULL, NULL);
+      switch (status)
        {
-           free(retv[i]);
-           retv[i]=0;
+       case MR_SUCCESS:
+         status = SUCCESS;
+         break;
+       case MR_IN_USE:
+       case MR_NOT_UNIQUE:
+         status = UREG_LOGIN_USED;
+         break;
+       case MR_DEADLOCK:
+         status = UREG_MISC_ERROR;
+         break;
+       default:
+         critical_alert(FAIL_INST, "%s returned from update_user_account.",
+                        error_message(status));
+         status = UREG_MISC_ERROR;
+         break;
        }
-       retv[i] = strdup(argv[i]);
     }
-    return 0;
+  if (status == SUCCESS)
+    {
+      /* Moira login was successfully created; try to reserve kerberos
+        principal. */
+      /* If this routine fails, store the login in the retval so
+        that it can be used in the client-side error message. */
+      if ((status = reserve_krb(login)) != SUCCESS)
+       strcpy(retval, login);
+    }
+
+  if (status)
+    com_err(whoami, status, " returned from set_identity");
+  else
+    com_err(whoami, 0, "Identity set");
+
+  return status;
 }
 
 
-/*
- * Set login name of user with "idnumber" to be "username"
+/* Find out if someone's secure instance password is set.
+ * Returns UREG_ALREADY_REGISTERED if set, SUCCESS (0) if not.
  */
 
-set_login(username, idnumber)
-  char *username;
-  char *idnumber;
+int get_secure(struct msg *message, char *retval)
 {
-    char *argv[2];
-    int status, i;
-    char *retv[13];
-    
-    argv[0] = "get_user_by_mitid";
-    argv[1] = idnumber;
-    
-    for (i=0; i<13; i++) 
-    {
-       retv[i] = 0;
-    }
-    
-    status = sms_query_internal(2, argv, store_user, (char *)(retv+1));
-    if (status) return status;
-    
-    retv[0] = retv[1];
-    retv[1] = username;
-    if (retv[4]) free(retv[4]);
-    retv[4] = "null";          /* No such filesystem */
-    
-    printf("Update_user(%s, %s)\n", retv[0], retv[1]);
-    
-    status = sms_query("update_user", 12, retv, abort, 0);
-    retv[1] = 0;
-    retv[4] = 0;
-    
-    for (i=1; i<12; i++) 
-    {
-       if (retv[i]) free(retv[i]);
-       retv[i] = 0;
-    }
-    
-    return status;
-}    
+  int status;
+  char *argv[U_END];
 
-/*
- * Set the status and filsys of user with username "uname" and filesys filsys.
- */
+  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. */
 
-set_status_filsys(username, idnumber)
-  char *username;
-  char *idnumber;
+int set_secure(struct msg *message, char *retval)
 {
-    char *argv[2];
-    int status, i;
-    char *retv[13];
-    
-    argv[0] = "get_user_by_mitid";
-    argv[1] = idnumber;
-    
-    for (i=0; i<13; i++) 
-    {
-       retv[i] = 0;
-    }
-    
-    status = sms_query_internal(2, argv, store_user, (char *)(retv+1));
-    if (status) return status;
-    
-    retv[0] = retv[1];
-    
-    free(retv[4]);
-    retv[4] = username;
-    
-    free(retv[8]);
-    retv[8] = "2";
-    
-    printf("Update_user(%s, %s)\n", retv[0], retv[1]);
-    
-    status = sms_query("update_user", 12, retv, abort, 0);
-    retv[4] = 0;
-    retv[8] = 0;
-    for (i=1; i<12; i++) 
-    {
-       if (retv[i]) free(retv[i]);
-       retv[i] = 0;
+  int status;
+  char *argv[U_END], *bp, 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;
+  struct utsname uts;
+
+  if (!inited)
+    {
+      inited++;
+      if (uname(&uts) < 0)
+       com_err(whoami, errno, "getting local hostname");
+      host = strdup(krb_get_phost(uts.nodename));
     }
-    return status;
-}    
-/*
- * Set the status and filsys of user with username "uname" and filesys filsys.
- */
 
-set_final_status(username, idnumber)
-  char *username;
-  char *idnumber;
-{
-    char *argv[2];
-    int status, i;
-    char *retv[13];
-    
-    argv[0] = "get_user_by_mitid";
-    argv[1] = idnumber;
-    
-    for (i=0; i<13; i++) 
-    {
-       retv[i] = 0;
-    }
-    
-    status = sms_query_internal(2, argv, store_user, (char *)(retv+1));
-    if (status) return status;
-    
-    retv[0] = retv[1];
-    
-    free(retv[8]);
-    retv[8] = "1";
-    
-    printf("Update_user(%s, %s)\n", retv[0], retv[1]);
-    
-    status = sms_query("update_user", 12, retv, abort, 0);
-    retv[8] = 0;
-    for (i=1; i<12; i++) 
-    {
-       if (retv[i]) free(retv[i]);
-       retv[i] = 0;
+  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;
     }
-    return status;
-}    
 
-create_group(login)
-  char *login;
-{
-    int status;
-    static char *cr[] = 
-    {
-       "add_user_group",
-       0,
-    };
-    
-    cr[1] = login;
-    
-    return sms_query_internal(2, cr, abort, 0);
-}    
+  bp = message->encrypted;
+  /* round up to word boundary */
+  bp = (char *)((((u_long)bp + 3) >> 2) << 2);
 
-/*
- * Local Variables:
- * mode: c
- * c-argdecl-indent: 2
- * c-brace-offset: -4
- * c-continued-statement-offset: 2
- * c-indent-level: 4
- * c-label-offset: -2
- * End:
- */
+  creds.length = ntohl(*((int *)bp));
+  bp += sizeof(int);
+  memcpy(creds.dat, bp, creds.length);
+  creds.mbz = 0;
+  bp += creds.length;
+
+  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 = strchr(buf, ',');
+  *passwd++ = 0;
+
+  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;
+    }
+
+  memset(&kv, 0, sizeof(kv));
+  SET_FIELD(KADM_DESKEY, kv.fields);
+  SET_FIELD(KADM_NAME, kv.fields);
+  SET_FIELD(KADM_INST, kv.fields);
+  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, "%ld", 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.090217 seconds and 4 git commands to generate.