* $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 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.
- *
- * 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
- *
+ * 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.
*/
#ifndef lint
static char *rcsid_reg_svr_c = "$Header$";
#endif lint
+#include <mit-copyright.h>
#include <stdio.h>
+#include <strings.h>
+#include <ctype.h>
+#include <sys/time.h>
#include <sys/types.h>
#include <sys/file.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
#include <krb.h>
#include <des.h>
+#include <kadm.h>
+#include <kadm_err.h>
+#include <krb_err.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 */
+#include "moira.h"
+#include "moira_site.h"
+#include "reg_svr.h"
-
-extern int abort();
-extern char *strdup();
-extern char *malloc();
-extern int krb_err_base;
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()
+void reg_com_err_hook();
+
+main(argc,argv)
+ 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 */
+ 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];
/* Error messages sent one line at a time */
setlinebuf(stderr);
+ setlinebuf(stdout);
+ set_com_err_hook(reg_com_err_hook);
- /* Initialize user registration error table */
+ /* Initialize com_err error tables */
init_ureg_err_tbl();
+ init_krb_err_tbl();
+ init_kadm_err_tbl();
+ initialize_gdss_error_table();
- /* Get service information from /etc/services */
- if ((sp = getservbyname("sms_ureg", "udp")) == NULL)
- {
- fprintf(stderr, "Unknown service sms_ureg/udp\n");
- exit(1);
- }
+ /* Use com_err or output to stderr for all log messages. */
+#ifdef DEBUG
+ com_err(whoami, 0, "*** Debugging messages enabled. ***");
+#endif DEBUG
- /* Get an internet style datagram socket */
- if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0)
+ /* 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)
{
- perror("socket");
+ com_err(whoami, status, " on mr_connect");
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)
+ /* Authorize, telling the server who you are */
+ if ((status = mr_auth(whoami)) != MR_SUCCESS)
{
- perror("bind");
+ com_err(whoami, status, " on mr_auth");
exit(1);
}
- /* Connect to the SMS server */
- if ((status = sms_connect()) != SMS_SUCCESS)
- {
- com_err(WHOAMI, status, " on connect");
+ journal = fopen(REGJOURNAL, "a");
+ if (journal == NULL) {
+ com_err(whoami, errno, " while opening journal file");
exit(1);
}
- /* Authorize, telling the server who you are */
- if ((status = sms_auth(WHOAMI)) != SMS_SUCCESS)
- {
- com_err(WHOAMI, status, " on auth");
- exit(1);
- }
+ /* Allow request layer to initialize */
+ req_initialize();
/* 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;
- }
+ get_request(&message);
- /* do action */
switch((int)message.request)
{
case UREG_VERIFY_USER:
- status = verify_user(&message);
+ status = verify_user(&message,retval);
break;
case UREG_RESERVE_LOGIN:
- status = reserve_user(&message);
+ status = reserve_user(&message,retval);
break;
case UREG_SET_PASSWORD:
- status = set_password(&message);
+ 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(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)
+int parse_encrypted(message,data)
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 */
+ struct db_data *data; /* Data from the Moira 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 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
+ The plain text ID number was encrypted via EncryptID() resulting
+ in the form that would appear in the Moira database. This is
+ concatinated to the plain text ID so that the ID string contains plain
+ 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. */
+ decrypt the packet with this information. If it succeeds, it returns
+ zero and initializes all the fields of the formatted packet structure
+ that depend on the encrypted information. */
{
- C_Block key; /* The key for DES en/decryption */
- Key_schedule sched; /* En/decryption schedule */
+ des_cblock key; /* The key for DES en/decryption */
+ des_key_schedule sched; /* En/decryption schedule */
static char decrypt[BUFSIZ]; /* Buffer to hold decrypted information */
long decrypt_len; /* Length of decypted ID information */
char recrypt[14]; /* Buffer to hold re-encrypted information */
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; /* */
+ char *temp; /* A temporary string pointer */
+ int len; /* Keeps track of length left in packet */
+ int status = SUCCESS; /* Error status */
- mit_id = 0;
+#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->enc_mitid_len;
+ decrypt_len = (long)message->encrypted_len;
- /* Get key from the one-way encrypted ID in the SMS database */
- string_to_key(db_mit_id, key);
+ /* Get key from the possibly one-way encrypted ID in the Moira database */
+ if (data->mit_id[0] >= '0' && data->mit_id[0] <= '9') {
+ char buf[32];
+
+ EncryptID(buf, data->mit_id, message->first, message->last);
+ des_string_to_key(buf, key);
+ } else
+ des_string_to_key(data->mit_id, key);
+
/* Get schedule from key */
- key_sched(key, sched);
+ des_key_sched(key, sched);
/* Decrypt information from packet using this key. Since decrypt_len
is an integral multiple of eight bytes, it will probably be null-
padded. */
- pcbc_encrypt(message->enc_mitid, decrypt, \
- decrypt_len, sched, key, DECRYPT);
+ des_pcbc_encrypt(message->encrypted, decrypt, decrypt_len,
+ sched, key, DES_DECRYPT);
/* Extract the plain text and encrypted ID fields from the decrypted
packet information. */
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);
+ (void) strncpy(idnumber,decrypt,(int)decrypt_len);
+ /* Check that the idnumber of a mismatched decryption doesn't overflow
+ * the buffer.
+ */
+ if (strlen(idnumber) != 9) {
+#ifdef DEBUG
+ com_err(whoami, 0, "idnumber wrong size, probable user mismatch\n");
+#endif
+ return(FAILURE);
+ }
/* Point temp to the end of the plain text ID number. */
temp = decrypt + strlen(idnumber) + 1;
- /* Find out how much more 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
+ /* 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, 14));
+ (void) 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->enc_mitid_len - (temp - decrypt);
+ len = message->encrypted_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;
+ /* Now compare encrypted ID and clear text ID for a match. */
+ if (strcmp(hashid, data->mit_id) &&
+ strcmp(idnumber, data->mit_id))
+ status = FAILURE;
- /* We made it. */
- reg_misc = temp;
- reg_misc_len = len;
- mit_id = hashid;
- return 0;
-}
+ 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;
+ (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));
+ }
+
+#ifdef DEBUG
+ if (status)
+ com_err(whoami, status, " in parse_encrypted");
+ else
+ com_err(whoami, status, "parse_encrypted succeeded");
+#endif
-static int status_in_db;
+ return status;
+}
-vfy_callbk(argc, argv, p_message)
- int argc; /* Should sanity check this.. */
- char **argv;
- char *p_message;
+int db_callproc(argc,argv,queue)
+ int argc; /* Number of arguments returned by Moira */
+ char *argv[]; /* Arguments returned by Moira */
+ struct save_queue *queue; /* Queue to save information in */
+/* This function is called by mr_query after each tuple found. It is
+ used by find_user to cache information about each user found. */
{
- 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];
+ struct db_data *data; /* Structure to store the information in */
+ int status = SUCCESS; /* Error status */
- 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)
+#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_account_by_name.");
+ status = MR_ABORT;
+ }
+ else
{
- (void) strcpy(errmsg, argv[0]);
+ /* extract the needed information from the results of the Moira 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);
}
- 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));
+ return status;
}
-
-int verify_user(message)
- struct msg *message;
-{
- 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)
- status = UREG_USER_NOT_FOUND;
- if (status != SMS_SUCCESS) goto punt;
+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 Moira database. It returns the status of the Moira
+ 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 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. */
+ bzero(message->db.mit_id,sizeof(message->db.mit_id));
- if (reg_status == 1) status = UREG_ALREADY_REGISTERED;
- if (reg_status == 2) status = UREG_NO_PASSWD_YET;
+ if (status == SUCCESS)
+ {
+ /* Get ready to make an 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,(char *)queue);
+
+#ifdef DEBUG
+ fprintf(stderr," %d returned by get_user_by_name\n",status);
+#endif
+
+ 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((char *)data);
+ }
+ }
+
+ /* Destroy the queue */
+ sq_destroy(queue);
+ }
- punt:
+#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;
}
-reserve_user(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;
- 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)
+ 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;
-
- if (status != SMS_SUCCESS) goto punt;
- if (reg_status != 0)
- {
- status = UREG_ALREADY_REGISTERED;
- goto punt;
- }
- /*
- * He's made it past this phase already.
- */
- if (status_in_db == 2)
+ else if (status == MR_SUCCESS)
{
- status = 0;
- goto punt;
- }
-
- for (i = 0; i < reg_misc_len && reg_misc[i]; i++)
- {
- if (!islower(reg_misc[i]) && !isdigit(reg_misc[i]) &&
- reg_misc[i] != '_' && reg_misc[i] != '.')
+ /* 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
{
- status = UREG_INVALID_UNAME;
- goto punt;
+ 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. */
+ (void) strcpy(retval,message->db.login);
}
}
- 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 */
- if ((status = get_krbrlm(realm, 1)) != KSUCCESS)
- {
- status += krb_err_base;
- goto punt;
+ if (status)
+ com_err(whoami, status, " returned from verify_user");
+ else
+ com_err(whoami, 0, "User verified");
+
+ return status;
+}
+
+int ureg_kadm_init()
+{
+ unsigned int status = SUCCESS; /* Return status */
+ static char krbrealm[REALM_SZ]; /* kerberos realm name */
+ static char hostbuf[BUFSIZ], *host; /* local hostname in principal fmt */
+ static int inited = 0;
+ char *p;
+
+#ifdef DEBUG
+ com_err(whoami, 0, "Entering ureg_kadm_init");
+#endif DEBUG
+
+ if (!inited) {
+ inited++;
+ bzero(krbrealm, sizeof(krbrealm));
+ if (status = krb_get_lrealm(krbrealm, 1)) {
+ status += krb_err_base;
+ com_err(whoami, status, " fetching kerberos realm");
+ exit(1);
+ }
+ if (gethostname(hostbuf, sizeof(hostbuf)) < 0)
+ com_err(whoami, errno, "getting local hostname");
+ host = canonicalize_hostname(strsave(hostbuf));
+ for (p = host; *p && *p != '.'; p++)
+ if (isupper(*p))
+ *p = tolower(*p);
+ *p = 0;
}
- status = get_svc_in_tkt("register", "sms", realm,
- "changepw", "kerberos",
- 1, "/etc/srvtab");
- if (status)
- {
+
+ /* 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;
- 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)
- {
- printf("Server error: %s\n", admin_errmsg);
-
- if (strcmp(admin_errmsg,
- "Principal already in kerberos database.") ==0)
- status = UREG_LOGIN_USED;
+ if (status != SUCCESS)
+ com_err(whoami, status, " while get admin tickets");
+#ifdef DEBUG
+ else {
+ com_err(whoami, status, "Succeeded in getting admin tickets");
+ }
+#endif
+
+ if (status == SUCCESS) {
+ if ((status = kadm_init_link(PWSERV_NAME, KADM_SINST, krbrealm)) !=
+ KADM_SUCCESS) {
+ com_err(whoami, status, " while initializing kadmin connection");
}
- goto punt;
}
-
+
+ return status;
+}
+
+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. */
+{
+ critical_alert(FAIL_INST,"Something returned from an update query.");
+ return FAILURE;
+}
+
+/*
+ * This routine reserves a principal in kerberos by setting up a
+ * principal with a random initial key.
+ */
+int reserve_krb(login)
+ char *login;
+{
+ int status = SUCCESS;
+ Kadm_vals new;
+ des_cblock key;
+ u_long *lkey = (u_long *)key;
+
+#ifdef DEBUG
+ com_err(whoami, 0, "Entering reserve_krb");
+#endif DEBUG
+
+ if ((status = ureg_kadm_init()) == SUCCESS) {
+ bzero((char *)&new, sizeof(new));
+ SET_FIELD(KADM_DESKEY, new.fields);
+ SET_FIELD(KADM_NAME, new.fields);
+
+ (void) 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");
+
+ bzero((char *)&new, sizeof(new));
+ }
+
dest_tkt();
- /* If valid: */
-
- /* Set login name */
- status = set_login(login, mit_id);
+
+ return(status);
+}
+
+/*
+ * This routine reserves a principal in kerberos by setting up a
+ * principal with a random initial key.
+ */
+int setpass_krb(login, password)
+ 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) {
+ bzero((char *)&new, sizeof(new));
+ SET_FIELD(KADM_DESKEY, new.fields);
+ SET_FIELD(KADM_NAME, new.fields);
+
+ (void) 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) {
+ 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");
+ }
+ }
+ dest_tkt();
+ return(status);
+}
+
+int reserve_user(message,retval)
+ 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 */
+ register 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);
- if (status)
+ /* Check to make sure that we can verify this user. */
+ if ((status = verify_user(message,retval)) == SUCCESS)
{
- com_err("set_login", status, (char *)0);
- goto punt;
+ /* 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;
}
- /* choose post office */
+ if (status == SUCCESS)
+ if ((login[0] == '_') || isdigit(login[0]))
+ status = UREG_INVALID_UNAME;
- status = choose_pobox(login);
- if (status)
+ if (status == SUCCESS)
{
- com_err("choose_pobox", status, (char *)0);
- goto punt;
+ for (i = 0; i < strlen(login); i++)
+ if (!islower(login[i]) && !isdigit(login[i]) &&
+ (login[i] != '_'))
+ {
+ status = UREG_INVALID_UNAME;
+ break;
+ }
}
- /* create group */
-
- status = create_group(login);
- if (status == SMS_LIST) status = UREG_LOGIN_USED;
-
- if (status)
+ if (status == SUCCESS)
{
- com_err("create_group", status, (char *)0);
- goto punt;
+ /* Now that we have a valid user with a valid login... */
+
+ /* First, try to reserve the user in Moira. */
+ (void) sprintf(fstype_buf,"%d",MR_FS_STUDENT);
+ q_name = "register_user";
+ q_argv[0] = message->db.uid;
+ q_argv[1] = login;
+ q_argv[2] = fstype_buf;
+ q_argc = 3;
+ status = mr_query(q_name,q_argc,q_argv,null_callproc,(char *)0);
+ 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;
+ }
}
- /* 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)
+
+ if (status == SUCCESS)
{
- com_err("alloc_filsys", status, (char *)0);
- goto punt;
+ /*
+ * 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)
+ (void) strcpy(retval, login);
}
- /* 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;
+
+ if (status)
+ com_err(whoami, status, " returned from reserve_user");
+ else {
+ com_err(whoami, 0, "User reserved");
}
- punt:
- dest_tkt();
- com_err(WHOAMI, status, " returned from reserve_user");
return status;
}
-set_password(message)
+int set_final_status(message)
+struct msg *message;
+ /* This routine updates a user's registration status to fully
+ registered. */
+{
+ 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)
+ (void) sprintf(state,"%d",US_REGISTERED);
+ else if (message->db.reg_status == US_NO_LOGIN_YET)
+ (void) sprintf(state,"%d",US_ENROLLED);
+ else
+ (void) 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_callproc,
+ (char *)0)) != 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;
+}
+
+
+int set_password(message,retval)
struct msg *message;
+ char *retval;
+ /* This routine is used to set the initial password for the new user. */
{
- char *argv[3];
- int status;
- char uid_buf[10];
- char realm[REALM_SZ];
-
- com_err(WHOAMI, 0, " set_password %s %s\n",
+ int status = SUCCESS; /* Return status */
+ char *passwd; /* User's password */
+
+ com_err(whoami, 0, "setting password %s %s",
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 = 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;
- goto punt;
- }
-
- /* get keys */
- if ((status = get_krbrlm(realm, 1)) != KSUCCESS)
+ if (((int)message->request == UREG_SET_PASSWORD &&
+ status == UREG_NO_PASSWD_YET) ||
+ ((int)message->request == UREG_GET_KRB &&
+ status == UREG_HALF_ENROLLED))
{
- goto punt;
- }
- status = get_svc_in_tkt("register", "sms", realm,
- "changepw", "kerberos",
- 1, "/etc/srvtab");
- if (status)
- {
- status += krb_err_base;
- goto punt;
+ /* 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 */
+ (void) strcpy(retval,message->db.login);
+ else
+ /* Otherwise, mark user as finished. */
+ status = set_final_status(message);
}
-
- (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();
+
+ if (status)
+ com_err(whoami, status, " returned from set_passwd");
+ else
+ com_err(whoami, 0, "Password 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. */
-{
- 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;
-}
-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(argc, argv, qargv)
+int argc;
+char **argv;
+char **qargv;
{
- 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);
+ 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] = strsave(argv[U_NAME]);
+ for (i = 1; i < U_MODTIME; i++)
+ qargv[i+1] = strsave(argv[i]);
+ qargv[U_MODTIME+1] = NULL;
+ }
+ return(status);
}
-store_user(argc, argv, argp)
- int argc;
- char **argv;
- char *argp;
+
+int set_identity(message,retval)
+struct msg *message;
+char *retval;
{
- char **retv = (char **) argp;
- int i;
+ int q_argc; /* Number of arguments to query */
+ char *q_argv[U_END]; /* 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 */
+ register 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);
- for (i = 0; i < argc; i++)
+ /* Check to make sure that we can verify this user. */
+ status = verify_user(message,retval);
+ if (status == SUCCESS || status == UREG_NOT_ALLOWED)
{
- if (retv[i])
+ 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)
+ {
+ /* 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_callproc, 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)
+ (void) 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"
+void reg_com_err_hook(whoami, code, fmt, pvar)
+ char *whoami;
+ int code;
+ char *fmt;
+ caddr_t pvar;
+{
+ if (whoami) {
+ fputs(whoami, stderr);
+ fputs(": ", stderr);
+ }
+ if (code) {
+ fputs(error_message(code), stderr);
+ }
+ if (fmt) {
+ _doprnt(fmt, pvar, stderr);
+ }
+ putc('\n', stderr);
+ fflush(stderr);
+}
+
+
+/* Find out of someone's secure instance password is set.
+ * Returns UREG_ALREADY_REGISTERED if set, SUCCESS (0) if not.
*/
-set_login(username, idnumber)
- char *username;
- char *idnumber;
+int get_secure(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;
- }
-
- 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;
+ int status;
+ char *argv[U_END];
+
+ com_err(whoami, 0, "checking status of secure password for %s",
+ message->first);
+ argv[0] = message->first;
+ status = mr_query("get_user_account_by_login", 1, argv, getuserinfo, argv);
+ if (status != SUCCESS) {
+ com_err(whoami, status, " while getting user info");
+ return(status);
}
-
- return status;
-}
+ if (atoi(argv[U_SECURE + 1]))
+ return UREG_ALREADY_REGISTERED;
+ return SUCCESS;
+}
-/*
- * Set the status and filsys of user with username "uname" and filesys filsys.
- */
-set_status_filsys(username, idnumber)
- char *username;
- char *idnumber;
+/* Set someone's secure instance password. */
+
+int set_secure(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;
+ char *argv[U_END], hostbuf[256], *bp, *p, buf[512], *passwd, *id;
+ KTEXT_ST creds;
+ AUTH_DAT auth;
+ C_Block key;
+ Key_schedule keys;
+ Kadm_vals kv;
+ u_long *lkey = (u_long *)key;
+ struct timeval now;
+ static int inited = 0;
+ static char *host;
+
+ if (!inited) {
+ inited++;
+ if (gethostname(hostbuf, sizeof(hostbuf)) < 0)
+ com_err(whoami, errno, "getting local hostname");
+ host = strsave(krb_get_phost(hostbuf));
}
-
- 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;
+
+ 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;
-}
-/*
- * 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;
+ bp = message->encrypted;
+ /* round up to word boundary */
+ bp = (char *)((((u_long)bp + 3) >> 2) << 2);
+
+ creds.length = ntohl(*((int *)bp));
+ bp += sizeof(int);
+ bcopy(bp, creds.dat, creds.length);
+ creds.mbz = 0;
+ bp += creds.length;
+
+#ifdef DEBUG
+ com_err(whoami, 0, "Cred: length %d", creds.length);
+ for (i = 0; i < creds.length; i += 16)
+ com_err(whoami, 0, " %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
+ creds.dat[i+0], creds.dat[i+1], creds.dat[i+2], creds.dat[i+3],
+ creds.dat[i+4], creds.dat[i+5], creds.dat[i+6], creds.dat[i+7],
+ creds.dat[i+8], creds.dat[i+9], creds.dat[i+10], creds.dat[i+11],
+ creds.dat[i+12], creds.dat[i+13], creds.dat[i+14], creds.dat[i+15]);
+#endif /* DEBUG */
+
+ status = krb_rd_req(&creds, "changepw", host, cur_req_sender(),
+ &auth, "");
+ if (status) {
+ status += krb_err_base;
+ com_err(whoami, status, " verifying credentials in set_secure()");
+ return(status);
}
-
- 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;
+
+ message->leftover_len = ntohl(*((int*)(bp)));
+ bp += sizeof(int);
+ message->leftover = bp;
+
+ des_key_sched(auth.session, keys);
+ des_pcbc_encrypt(message->leftover, buf, message->leftover_len,
+ keys, auth.session, 0);
+
+ id = buf;
+ passwd = index(buf, ',');
+ *passwd++ = 0;
+#ifdef DEBUG
+ com_err(whoami, 0, "Got id: %s, passwd %d chars", id, strlen(passwd));
+#endif
+
+ if (strcmp(id, argv[U_MITID + 1])) {
+ char buf[32];
+
+ EncryptID(buf, id, argv[U_FIRST+1], argv[U_LAST+1]);
+ if (strcmp(buf, argv[U_MITID + 1])) {
+ status = UREG_USER_NOT_FOUND;
+ com_err(whoami, status, "IDs mismatch: %s (%s), %s", id, buf,
+ argv[U_MITID + 1]);
+ return status;
+ }
}
- 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);
-}
+ /* now do actual password setting stuff */
-/*
- * 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:
- */
+ if ((status = ureg_kadm_init()) != SUCCESS) {
+ com_err(whoami, status, "initing kadm stuff");
+ return(status);
+ }
+
+ bzero((char *)&kv, sizeof(kv));
+ SET_FIELD(KADM_DESKEY, kv.fields);
+ SET_FIELD(KADM_NAME, kv.fields);
+ SET_FIELD(KADM_INST, kv.fields);
+ (void) des_string_to_key(passwd, key);
+ kv.key_low = htonl(lkey[0]);
+ kv.key_high = htonl(lkey[1]);
+ strcpy(kv.name, message->first);
+ strcpy(kv.instance, "extra");
+
+ if ((status = kadm_add(&kv)) != KADM_SUCCESS) {
+ com_err(whoami, status, " while creating kerberos principal");
+ return(status);
+ }
+
+ argv[0] = message->first;
+ argv[1] = buf;
+ gettimeofday(&now, NULL);
+ sprintf(buf, "%d", now.tv_sec);
+ status = mr_query("update_user_security_status", 2, argv, getuserinfo, argv);
+ if (status != SUCCESS) {
+ com_err(whoami, status, " while updating user status");
+ return(status);
+ }
+ return SUCCESS;
+}