]> andersk Git - moira.git/blobdiff - reg_svr/reg_svr.c
added copyright message
[moira.git] / reg_svr / reg_svr.c
index d1a2871d47df7705eb426a30865ccb62b24636de..137f9c179af7d749afb0b43dab8b7eec50c94d43 100644 (file)
 /*
- *     $Source$
- *     $Author$
- *     $Header$
+ *      $Source$
+ *      $Author$
+ *      $Header$
  *
- *     Copyright (C) 1987 by the Massachusetts Institute of Technology
+ *      Copyright (C) 1987, 1988 by the Massachusetts Institute of Technology
+ *     For copying and distribution information, please see the file
+ *     <mit-copyright.h>.
  *
- *     Server for user registration with SMS and Kerberos.
+ *      Server for user registration with SMS 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.2  1987-08-22 18:39:45  wesommer
- *     User registration server.
- *
- * Revision 1.1  87/07/31  15:48:13  wesommer
- * Initial revision
- * 
+ *      This program is a client of the Kerberos admin_server and a
+ *      server for the userreg program.  It is not a client of the
+ *      SMS server as it is linked with libsmsglue which bypasses
+ *      the network protocol.
  */
 
 #ifndef lint
 static char *rcsid_reg_svr_c = "$Header$";
 #endif lint
 
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/file.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <des.h>
-#include <errno.h>
-#include <ctype.h>
-#include "ureg_err.h"
-#include "ureg_proto.h"
-#include "../../include/sms.h"
+#include <mit-copyright.h>
+#include "reg_svr.h"
 #include "admin_server.h"
-#include "admin_err.h" 
-#include <strings.h>
+#include "admin_err.h"
 
-extern void abort();
-extern char *strdup();
-extern char *malloc();
 extern int krb_err_base;
 extern char admin_errmsg[];
 
-long now;
-#define STAMP { time (&now); printf(ctime(&now)); }
-                      
-struct msg {
-    u_long version;
-    u_long request;
-    char *first;
-    char *last;
-    char *sealed;
-    int sealed_len;
-};
-
-static char retval[BUFSIZ];
-
-main()
+static char krbhst[BUFSIZ];    /* kerberos server name */
+static char krbrealm[REALM_SZ];        /* kerberos realm name */
+
+main(argc,argv)
+  int argc;
+  char *argv[];
 {
-    struct sockaddr_in sin;
-    struct servent *sp;
-    int s;
-    int status;
-    int addrlen, len;
-    char buf[BUFSIZ];
-    extern int errno;
-    u_long seqno;
-    struct msg message;
-    extern char *whoami;
+    struct msg message;                /* Storage for parsed packet */
+    int status = SUCCESS;      /* Error status */
+    char retval[BUFSIZ];       /* Buffer to hold return message for client */
+    
+    void req_initialize();     /* Initialize request layer */
+    void get_request();                /* Get a request */
+    void report();             /* Respond to a request */
 
+    /* Initialize */
+    whoami = argv[0];
+    
+    /* Use com_err or output to stderr for all log messages. */    
+#ifdef DEBUG
+    fprintf(stderr,"*** Debugging messages enabled. ***\n");
+#endif DEBUG
+    
+    /* Error messages sent one line at a time */
     setlinebuf(stderr);
-    whoami = "reg_svr";
     
+    /* Initialize user registration error table for com_err */
     init_ureg_err_tbl();
     
-    status = sms_connect();
-    if (status != 0) {
-       com_err("reg_svr", status, " on connect");
+    /* Connect to the SMS server */
+    if ((status = sms_connect()) != SMS_SUCCESS) 
+    {
+       com_err(whoami, status, " on connect");
        exit(1);
     }
-    status = sms_auth();
-    if (status != 0) {
-       com_err("reg_svr", status, " on auth");
+    
+    /* Authorize, telling the server who you are */
+    if ((status = sms_auth(whoami)) != SMS_SUCCESS) 
+    {
+       com_err(whoami, status, " on auth");
        exit(1);
     }
     
-    sp = getservbyname("sms_ureg", "udp");
-    if (sp == NULL) {
-       fprintf(stderr, "Unknown service sms_ureg/udp\n");
+    if (status = get_krbrlm(krbrealm, 1)) {
+       status += krb_err_base;
+       com_err(whoami, status, " fetching kerberos realm");
        exit(1);
     }
-    s = socket(AF_INET, SOCK_DGRAM, 0);
-    if (s < 0) {
-       perror("socket");
+    
+    if (status = get_krbhst(krbhst, krbrealm, 1)) {
+       status += krb_err_base;
+       com_err(whoami, status, " fetching kerberos hostname");
        exit(1);
+    } else {
+       char *s;
+       for (s = krbhst; *s && *s != '.'; s++)
+           if (isupper(*s))
+               *s = tolower(*s);
+       *s = 0;
     }
-    bzero((char *)&sin, sizeof(sin));
-
-    sin.sin_family = AF_INET;
-    sin.sin_port = sp->s_port;
-    sin.sin_addr.s_addr = INADDR_ANY;
 
-    if (bind(s, &sin, sizeof(sin)) < 0) {
-       perror("bind");
+    journal = fopen(JOURNAL, "a");
+    if (journal == NULL) {
+       com_err(whoami, errno, " while opening journal file");
        exit(1);
     }
     
-    for (;;) {
-       addrlen = sizeof(sin);
-       bzero(retval, BUFSIZ);
-       len = recvfrom(s, buf, BUFSIZ, 0, &sin, &addrlen);
-       if (len < 0) {
-           perror("recvfrom");
-           if (errno == EINTR) continue;
-           
-           exit(1);
-       }
-       /* Parse a request packet */
-       status = parse_pkt(buf, len, &seqno, &message);
-       if (status != 0) {
-           len = BUFSIZ;
-           format_pkt(buf, &len, seqno, status, (char *)NULL);
-           (void) sendto(s, buf, len, 0, &sin, addrlen);
-           continue;
-       }
-       /* do action */
-       switch((int)message.request) {
-       case UREG_VERIFY_USER:
-           status = verify_user(&message);
+    /* Allow request layer to initialize */
+    req_initialize();
+    
+    /* Sit around waiting for requests from the client. */
+    for (;;) 
+    {
+       get_request(&message);
+       
+       switch((int)message.request) 
+       {
+         case UREG_VERIFY_USER:
+           status = verify_user(&message,retval);
            break;
-       case UREG_RESERVE_LOGIN:
-           status = reserve_user(&message);
+         case UREG_RESERVE_LOGIN:
+           status = reserve_user(&message,retval);
            break;
-       case UREG_SET_PASSWORD:
-           status = set_password(&message);
+         case UREG_SET_PASSWORD:
+           status = set_password(&message,retval);
            break;
            
-       default:
+         default:
            status = UREG_UNKNOWN_REQUEST;
+           critical_alert(FAIL_INST,"Unknown request %d from userreg.",
+                          message.request);
            break;
        }
-       len = BUFSIZ;
-       format_pkt(buf, &len, seqno, status, retval);
        
-       sendto(s, buf, len, 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;
+/* This is necessary so that this server can know where to put its
+   tickets. */
+char *tkt_string()
+{
+    return("/tmp/tkt_ureg");
+}
 
-#define min(a,b) ((a)>(b)?(b):(a))
-    
-int validate_idno(message, db_mit_id, first, last)
-    struct msg *message;
-    char *db_mit_id;
-    char *first, *last;
+int parse_encrypted(message,data)
+  struct msg *message;         /* Formatted packet */
+  struct db_data *data;                /* Data from the SMS database */
+/* 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 EncryptID() 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.  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 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.  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;
-    Key_schedule sched;
-    static char decrypt[BUFSIZ];
-    char recrypt[14];
-    static char hashid[14];
-    char idnumber[BUFSIZ];
-    char *temp;
-    int len;
-
-    int i;
-#ifdef notdef
-    for (i = 0; i < message->sealed_len; i++) {
-       printf("%02x ", (unsigned char)message->sealed[i]);
-    }
-    printf("\n");
-#endif notdef
-    mit_id = 0;
-    
-    string_to_key(db_mit_id, key);
+    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 string pointer */
+    int len;                   /* Keeps track of length left in packet */
+    int status = SUCCESS;      /* Error status */
+    
+#ifdef DEBUG
+    com_err(whoami,0,"Entering parse_encrypted");
+#endif
+
+    /* 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->encrypted_len;
+    
+    /* Get key from the one-way encrypted ID in the SMS database */
+    string_to_key(data->mit_id, key);
+    /* Get schedule from key */
     key_sched(key, sched);
-    pcbc_encrypt(message->sealed, decrypt, message->sealed_len, sched, key, 0);
-
-#ifdef notdef
-    for (i = 0; i < message->sealed_len; i++) {
-       printf("%02x ", (unsigned char)decrypt[i]);
-    }
-    printf("\n");
-    for (i = 0; i < message->sealed_len; i++) {
-       if (isprint(decrypt[i])) 
-           printf("%c  ", (unsigned char)decrypt[i]);
-       else printf(".  ");
-    }
-    printf("\n");
-#endif notdef
-    (void) strncpy(idnumber, decrypt, message->sealed_len);
+    /* 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);
+    
+    /* 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,(int)decrypt_len);
+    /* Point temp to the end of the plain text ID number. */
     temp = decrypt + strlen(idnumber) + 1;
-    len = message->sealed_len - (temp - decrypt);
-    
-    (void) strncpy(hashid, temp, min(len, 14));
+    /* 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. */
+    (void) strncpy(hashid, temp, min(len, CRYPT_LEN));
+    /* Point temp to the end of the encrypted ID field */
     temp += strlen(hashid) + 1;
-    len = message->sealed_len - (temp - decrypt);
-
-    if (strcmp(hashid, db_mit_id)) return 1;
-    encrypt_mitid(recrypt, idnumber, first, last);
-    if (strcmp(recrypt, db_mit_id)) return 1;
-
-    reg_misc = temp;
-    reg_misc_len = len;
-    mit_id = hashid;
-    return 0;
-}
-
-static int status_in_db;
-
-vfy_callbk(argc, argv, p_message)
-    int argc;                  /* Should sanity check this.. */
-    char **argv;
-    char *p_message;
-{
-    struct msg *message = (struct msg *)p_message;
-    char *db_mit_id;
-    char *firstname, *lastname;
-    int status;
-    
-#ifdef debug
-    printf("Callback: %s %s %s\n", argv[8], argv[5], argv[4]);
-#endif debug
-    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(retval, argv[0]);
+    /* 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;
     }
-    user_id = atoi(argv[1]);
-    got_one = 1;
-    return 0;
-}    
-
-encrypt_mitid(buf, idnumber, first, last)
-    char *buf, *idnumber, *first, *last;
-{
-    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));
-}
-
-int verify_user(message)
-    struct msg *message;
-
-{
-    char *argv[3];
-    int status;
-    
-    printf("verify_user\n");
-    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 == 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 SMS database. */
+       message->db.reg_status = data->reg_status;
+       (void) strncpy(message->db.uid,data->uid, sizeof(message->db.uid));
+       (void) strncpy(message->db.mit_id,data->mit_id, 
+                      sizeof(message->db.mit_id));
+       (void) strncpy(message->db.login,data->login, sizeof(message->db.login));
+    }
     
-    if (status != 0) goto punt;
+#ifdef DEBUG
+    if (status)
+       com_err(whoami,status," parse_encrypted failed.");
+    else
+       com_err(whoami,status,"parse_encrypted succeeded.");
+#endif
 
-    if (reg_status == 1) status = UREG_ALREADY_REGISTERED;
-    if (reg_status == 2) status = UREG_NO_PASSWD_YET;
-    
-punt:
     return status;
 }
 
-reserve_user(message)
-    struct msg *message;
+int db_callproc(argc,argv,queue)
+  int argc;                    /* Number of arguments returned by SMS */
+  char *argv[];                        /* Arguments returned by SMS */
+  struct save_queue *queue;    /* Queue to save information in */
+/* This function is called by sms_query after each tuple found.  It is
+   used by find_user to cache information about each user found.  */
 {
-    char *argv[3];
-    int status;
-    int i;
-    char *login;
-    char uid_buf[20];
-    
-    STAMP;
-    printf("reserve_user\n");
-
-    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);
-
-    STAMP;
-    
-    if (status == SMS_NO_MATCH) status = UREG_USER_NOT_FOUND;
-    if (!got_one && !status)
-       status = UREG_USER_NOT_FOUND;
-
-    if (status != 0) goto punt;
-    if (reg_status != 0) {
-       status = UREG_ALREADY_REGISTERED;
-       goto punt;
+    struct db_data *data;      /* Structure to store the information in */
+    int status = SUCCESS;      /* Error status */
+    
+#ifdef DEBUG
+    com_err(whoami,0,"Entering db_callproc.");
+#endif
+
+    if (argc != U_END)
+    {
+       critical_alert
+           (FAIL_INST,
+            "Wrong number of arguments returned from get_user_by_name.");
+       status = SMS_ABORT;
     }
-    /*
-     * He's made it past this phase already.
-     */
-    if (status_in_db == 2) {
-       status = 0;
-       goto punt;
+    else
+    {
+       /* extract the needed information from the results of the SMS query */
+       data = (struct db_data *)malloc(sizeof(struct db_data));
+       data->reg_status = atoi(argv[U_STATE]);
+       (void) strncpy(data->login,argv[U_NAME],sizeof(data->login));
+       (void) strncpy(data->mit_id,argv[U_MITID],sizeof(data->mit_id));
+       (void) strncpy(data->uid,argv[U_UID],sizeof(data->uid));
+#ifdef DEBUG
+       fprintf(stderr,"Found in database:\n");
+       fprintf(stderr,"   Registration status: %d\n",data->reg_status);
+       fprintf(stderr,"   login: %s\n",data->login);
+       fprintf(stderr,"   MIT ID: %s\n",data->mit_id);
+       fprintf(stderr,"   uid: %s\n",data->uid);
+#endif
+       sq_save_data(queue,data);
     }
-    /* Sanity check requested login name. */
-    printf("reg_misc_len = %d\n", reg_misc_len);
 
-    for (i = 0; i < reg_misc_len && reg_misc[i]; i++) {
-       if (!islower(reg_misc[i])) {
-           status = UREG_INVALID_UNAME;
-           goto punt;
-       }
-    }
-    if (i < 3 || i > 8) {
-       status = UREG_INVALID_UNAME;
-       goto punt;
-    }
-    login = reg_misc;
-    
-    /* Send request to kerberos admin_server for login name */
-    /* get keys */
-    printf("get_svc_in_tkt\n");
-    status = get_svc_in_tkt("register", "kerberos", "ATHENA.MIT.EDU",
-                           "changepw", "kerberos",
-                           1, "/etc/srvtab");
-    if (status) {
-           status += krb_err_base;
-           goto punt;
-    }
-    STAMP;
-    
-    printf("admin_call\n");
-    /* send set password request to kerberos admin_server */
-    (void) sprintf(uid_buf, "%013d", user_id); /* 13 chars of placebo */
-                                              /* for backwards-compat. */
+    return status;
+}
     
-    status = admin_call(ADMIN_ADD_NEW_KEY_ATTR, login, "", 
-                       "", uid_buf);
-
-    if (status) {
-           if (status == ADMIN_SERVER_ERROR) {
-                   printf("Server error: %s\n", admin_errmsg);
-                   
-                   if (strcmp(admin_errmsg,
-                               "Principal already in kerberos database.") ==0)
-                           status = UREG_LOGIN_USED;
+int find_user(message)
+  struct msg *message;         /* Formatted packet structure */
+/* This routine verifies that a user is allowed to register by finding
+   him/her in the SMS database.  It returns the status of the SMS
+   query that it calls. */
+{
+#define GUBN_ARGS 2            /* Arguements needed by get_user_by_name */
+    char *q_name;              /* Name of 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 SMS 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. */
+    bzero(message->db.mit_id,sizeof(message->db.mit_id));
+    
+    if (status == SUCCESS)
+    {
+       /* Get ready to make an SMS query */
+       q_name = "get_user_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 = sms_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) 
+       {
+           /* 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((char *)data);
            }
-           goto punt;
-    }
+       }
 
-    dest_tkt();
-    /* If valid: */
-    STAMP;
-    
-    /* Set login name */
-    status = set_login(login, mit_id);
-    if (status) {
-       com_err("set_login", status, 0);
-       goto punt;
+       /* Destroy the queue */
+       sq_destroy(queue);
     }
-    /* choose post office */
-    STAMP;
     
-    status = choose_pobox(login);
-    if (status) {
-       com_err("choose_pobox", status, 0);
-       goto punt;
-    }
-    /* set quota entry, create filsys */
-    STAMP;
-    
-    status = alloc_filsys(login, SMS_FS_STUDENT, 0, 0);
-    if (status) {
-       com_err("alloc_filsys", status, 0);
-       goto punt;
-    }
-    /* create group */
-    STAMP;
-    
-    status = create_group(login);
-    if (status) {
-       com_err("create_group", status, 0);
-       goto punt;
-    }
-    /* set filsys and status in SMS database */
-    STAMP;
-    
-    status = set_status_filsys(reg_misc, mit_id);
-    if (status) {
-       com_err("set_filsys", status, 0);
-       goto punt;
-    }
-punt:
-    dest_tkt();
-    STAMP;
-    printf("reserve_user returning %s\n", error_message(status));
+#ifdef DEBUG
+    fprintf(stderr,"Returned from find_user\n");
+    fprintf(stderr,"   MIT ID: %s\n", message->db.mit_id);
+    fprintf(stderr,"   Registration status: %d\n",message->db.reg_status);
+    fprintf(stderr,"   uid: %s\n",message->db.uid);
+    fprintf(stderr,"   login: %s\n",message->db.login);
+    fprintf(stderr,"   Status from query: %d\n",status);
+#endif DEBGUG
+
     return status;
 }
 
-set_password(message)
-    struct msg *message;
+int verify_user(message,retval)
+  struct msg *message;
+  char *retval;
+  /* 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. */
+     
 {
-    char *argv[3];
-    int status;
-    
-    printf("set_password\n");
+    int status = SUCCESS;      /* Return status */
 
-    /* validate that user is who he claims to be */
+    /* Log that we are about to veryify user */
+    com_err(whoami,0,"verify_user %s %s",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)
-       status = UREG_USER_NOT_FOUND;
-    
-    if (status != 0) goto punt;
+    /* Figure out what user (if any) can be found based on the
+       encrypted information in the packet.  (See the comment on 
+       parse_encrypted().) */
 
-    /* validate that state is equal to '2' (login, but no password) */
+    status = find_user(message);
 
-    if (reg_status != 2) {
-       status = UREG_NO_LOGIN_YET;
-       goto punt;
-    }
-
-    printf("password for %s would be set to %s\n", retval ,reg_misc);
-
-    /* get keys */
-    status = get_svc_in_tkt("register", "kerberos", "ATHENA.MIT.EDU",
-                           "changepw", "kerberos",
-                           1, "/etc/srvtab");
-    if (status) {
-           status += krb_err_base;
-           goto punt;
+    /* If SMS coudn't find the user */
+    if (status == SMS_NO_MATCH) 
+       status = UREG_USER_NOT_FOUND;
+    else if (status == SMS_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] == NULL)
+           status = UREG_USER_NOT_FOUND;
+       /* 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;
+
+             default:
+               status = UREG_MISC_ERROR;
+               critical_alert(FAIL_INST,"Bad user state for login %s.",
+                              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. */
+           (void) strcpy(retval,message->db.login);
+       }
     }
-    /* send set password request to kerberos admin_server */
-    status = admin_call(ADMIN_SET_KDC_PASSWORD, retval, "", 
-                       reg_misc, "BBBBBBBBBBBBB");
-
-    if (status) goto punt;
-    dest_tkt();
     
-    status = set_final_status(retval, mit_id);
+    com_err(whoami,status," returned from verify_user");
 
-    /* reflect reply to client */
-punt:
-    dest_tkt();
     return status;
 }
-
-parse_pkt(buf, len, seqnop, messagep)
-    char *buf;
-    int len;
-    u_long *seqnop;
-    struct msg *messagep;
+       
+int ureg_get_tkt()
 {
-    if (len < 4) return UREG_BROKEN_PACKET;
-    bcopy(buf, (char *)&messagep->version, sizeof(long));
-    messagep->version = ntohl(messagep->version);
-    if (messagep->version != 1) return UREG_WRONG_VERSION;
-    
-    buf += 4;
-    len -= 4;
-
-    if (len < 4) return UREG_BROKEN_PACKET;
-    bcopy(buf, (char *)seqnop, sizeof(long));
-
-    buf += 4;
-    len -= 4;
-    
-    if (len < 4) return UREG_BROKEN_PACKET;
-    bcopy(buf, (char *)(&messagep->request), sizeof(long));
-    messagep->request = ntohl(messagep->request);
-    buf += 4;
-    len -= 4;
-    
-    messagep->first = buf;
-
-    for (; *buf && len > 0; --len, ++buf) continue;
-    if (len <= 0) return UREG_BROKEN_PACKET;
-
-    buf++, len--;
-
-    messagep->last = buf;
-
-    for (; *buf && len > 0; --len, ++buf) continue;
-    if (len <= 0) return UREG_BROKEN_PACKET;
-    
-    buf++, len--;
-
-    if (len <= 0) return UREG_BROKEN_PACKET;
-    
-    messagep->sealed = buf;
-    messagep->sealed_len = len;
-    
-    return 0;
+    int status = SUCCESS;      /* Return status */
+
+    /* Get keys for interacting with Kerberos admin server. */
+    /* principal, instance, realm, service, service instance, life, file */
+    if (status = get_svc_in_tkt("register", "sms", krbrealm, "changepw", 
+                               krbhst, 1, KEYFILE))
+       status += krb_err_base;
+
+#ifdef DEBUG
+    if (status == SUCCESS)
+       com_err(whoami,status,"Succeeded in getting tickets.");
+    else
+       com_err(whoami,status,"Failed to get tickets.");
+#endif
+    return status;
 }
 
-format_pkt(buf, lenp, seqno, status, message)
-    char *buf;
-    int *lenp;
-    u_long seqno;
-    int status;
-    char *message;
+int null_callproc(argc,argv,message)
+  int argc;
+  char *argv[];
+  char *message;
+  /* This routine is a null callback that should be used for queries that
+     do not return tuples.  If it ever gets called, something is wrong. */
 {
-    u_long vers = htonl((u_long)1);
-    status = htonl((u_long)status);
-    
-    bcopy((char *)&vers, buf, sizeof(long));
-    bcopy((char *)&seqno, buf+sizeof(long), sizeof(long));
-    bcopy((char *)&status, buf+ 2*sizeof(long), sizeof(long));
-    *lenp = sizeof(long) * 3;
-    (void) strcpy(buf+3*sizeof(long), message);
-    (*lenp) += strlen(message);
+    critical_alert(FAIL_INST,"Something returned from an update query.");
+    return FAILURE;
 }
 
-store_user(argc, argv, argp)
-    int argc;
-    char **argv;
-    char *argp;
+int do_admin_call(login, passwd, uid)
+  char *login;                 /* Requested kerberos principal */
+  char *passwd;                        /* Requested password */
+  char *uid;                   /* Uid of user who owns this principal */
+  /* This routine gets tickets, makes the appropriate call to admin_call,
+     and destroys tickets. */
 {
-    char **retv = (char **) argp;
-    int i;
-    
-    for (i = 0; i < argc; i++) {
-       if (retv[i]) {
-           free(retv[i]);
-           retv[i]=0;
+    int status;                        /* Error status */
+    char uid_buf[20];          /* Holds uid for kerberos */
+
+    com_err(whoami,0,"Entering do_admin_call");
+
+    if ((status = ureg_get_tkt()) == SUCCESS)
+    {
+       /* Try to reserve kerberos principal.  To do this, send a 
+          password request and a null password.  It will only succeed
+          if there is no principal or the principal exists and has no 
+          password. */
+       /* 13 chars of placebo for backwards-compatability - the admin
+          server protocol reqires this. */
+       bzero(uid_buf,sizeof(uid_buf));
+       (void) sprintf(uid_buf, "%13s", uid);
+       
+       if ((status = admin_call(ADMIN_ADD_NEW_KEY_ATTR, login, 
+                                "", passwd, uid_buf)) != KSUCCESS)
+       {
+           com_err(whoami,status," server error: %s",admin_errmsg);
+           
+           if (strcmp(admin_errmsg,
+                      "Principal already in kerberos database.") == 0)
+               status = UREG_KRB_TAKEN;
+           critical_alert(FAIL_INST,"%s is known to Kerberos but not SMS.", 
+                          login);
        }
-       retv[i] = strdup(argv[i]);
     }
-    return 0;
-}
     
+    dest_tkt();
+    com_err(whoami,status," returned from do_adin_call");
+    return status;
+}
 
-/*
- * Set login name of user with "idnumber" to be "username"
- */
-
-set_login(username, idnumber)
-    char *username;
-    char *idnumber;
+int reserve_user(message,retval)
+  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;
+    int q_argc;                        /* Number of arguments to query */
+    char *q_argv[3];           /* Arguments to SMS query */
+    char *q_name;              /* Name of SMS 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 */
+    register int i;            /* A counter */
+
+    /* Log that we are about to reserve a user. */
+    com_err(whoami, 0, "reserve_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 and numbers in any
+          position and underscore characters and periods in any position
+          but the first. */
+       if ((strlen(login) < MIN_UNAME) || (strlen(login) > MAX_UNAME))
+           status = UREG_INVALID_UNAME;
     }
-
-    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;
+    if (status == SUCCESS)
+       if (login[1] == '_')
+           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;
+           }
     }
-    
-    return status;
-}    
-
-/*
- * Set the status and filsys of user with username "uname" and filesys filsys.
- */
-
-set_status_filsys(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;
+    if (status == SUCCESS)
+    {
+       /* Now that we have a valid user with a valid login... */
+
+       /* First, try to reserve the user in SMS. */
+       (void) sprintf(fstype_buf,"%d",SMS_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);
+       switch (status)
+       {
+         case SMS_SUCCESS:
+           status = SUCCESS;
+           break;
+         case SMS_IN_USE:
+           status = UREG_LOGIN_USED;
+           break;
+         default:
+           status = UREG_MISC_ERROR;
+           critical_alert(FAIL_INST,"%s returned from register_user.",
+                          error_message(status));
+           break;
+       }
+    }
+    if (status == SUCCESS)
+    {
+       /* SMS 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 = do_admin_call(login, "", message->db.uid)) != SUCCESS)
+           (void) strcpy(retval, login);
     }
 
-    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]);
+    com_err(whoami, status, " returned from reserve_user");
     
-    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;
-    }
     return status;
-}    
-/*
- * Set the status and filsys of user with username "uname" and filesys filsys.
- */
+}
 
-set_final_status(username, idnumber)
-    char *username;
-    char *idnumber;
+int set_final_status(login)
+  char *login;
+    /* This routine updates a user's registration status to fully 
+       registered. */
 {
-    char *argv[2];
-    int status, i;
-    char *retv[13];
-    
-    argv[0] = "get_user_by_mitid";
-    argv[1] = idnumber;
+    char *q_name;              /* Name of SMS query */
+    int q_argc;                        /* Number of arguments for SMS query */
+    char *q_argv[2];           /* Arguments to get user by uid */
+    char state[7];             /* Can hold a 16 bit integer */
+    int status;                        /* Error status */
+
+    com_err(whoami, 0, "Setting final status for %s", login);
+
+    (void) sprintf(state,"%d",US_REGISTERED);
+    q_name = "update_user_status";
+    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)
+       critical_alert(FAIL_INST,"%s returned from update_user_status.",
+                      error_message(status));
+    
+    com_err(whoami,status," returned from set_final_status");
+    return status;
+}
 
-    for (i=0; i<13; i++) {
-       retv[i] = 0;
-    }
 
-    status = sms_query_internal(2, argv, store_user, (char *)(retv+1));
-    if (status) return status;
+int set_password(message,retval)
+  struct msg *message;
+  char *retval;
+  /* This routine is used to set the initial password for the new user. */
+{
+    int status = SUCCESS;      /* Return status */
+    char *passwd;              /* User's password */
 
-    retv[0] = retv[1];
+    com_err(whoami, 0, " set_password %s %s",
+           message->first, message->last);
 
-    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;
-    }
-    return status;
-}    
+    status = verify_user(message,retval);
 
-create_group(login)
-    char *login;
-{
-    int status;
-    static char *cr[] = {
-       "add_user_group",
-       0,
-    };
+    /* 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 (status == UREG_NO_PASSWD_YET)
+    {
+       /* User is in proper state for this transaction. */
+       
+       passwd = message->leftover;
+       
+       /* Set password. */
+       if ((status = do_admin_call(message->db.login, 
+                                   passwd, message->db.uid)) != SUCCESS)
+           /* If failure, allow login name to be used in client 
+              error message */
+           (void) strcpy(retval,message->db.login);
+       else
+           /* Otherwise, mark user as finished. */
+           status = set_final_status(message->db.login);
+    }
+    com_err(whoami, status, " returned from set_passwd");
     
-    cr[1] = login;
+    return status;
+}
     
-    return sms_query_internal(2, cr, abort, 0);
-}    
 /*
  * Local Variables:
  * mode: c
- * c-indent-level: 4
- * c-continued-statement-offset: 4
+ * c-argdecl-indent: 2
  * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-indent-level: 4
+ * c-label-offset: -2
  * End:
  */
-char *get_krbhst(a1, a2)
-       char *a1;
-       char *a2;
-{
-       strcpy(a1, "ICARUS.MIT.EDU");
-       return 0;
-}
-
-char *get_krbrlm(a1)
-       char *a1;
-{
-       strcpy(a1, "ATHENA.MIT.EDU");
-       return 0;
-}
-
This page took 0.135721 seconds and 4 git commands to generate.