--- /dev/null
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * For copying and distribution information, please see the file
+ * <krb5/copyright.h>.
+ *
+ * convenience sendauth/recvauth functions
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_sendauth_c [] =
+"$Id$";
+#endif /* !lint & !SABER */
+
+#include <krb5/krb5.h>
+#include <krb5/osconf.h>
+#include <krb5/kdb.h>
+#include <krb5/kdb_dbm.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <com_err.h>
+#include <errno.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#define WORKING_RCACHE
+
+extern krb5_flags krb5_kdc_default_options;
+
+static char *sendauth_version = "KRB5_SENDAUTH_V1.0";
+
+krb5_error_code
+krb5_recvauth(/* IN */
+ fd, appl_version, server, sender_addr, fetch_from,
+ keyproc, keyprocarg, rc_type,
+ /* OUT */
+ seq_number, client, ticket, authent)
+ krb5_pointer fd;
+ char *appl_version;
+ krb5_principal server;
+ krb5_address *sender_addr;
+ krb5_pointer fetch_from;
+ krb5_int32 *seq_number;
+ char *rc_type;
+ krb5_rdreq_key_proc keyproc;
+ krb5_pointer keyprocarg;
+ krb5_principal *client;
+ krb5_ticket **ticket;
+ krb5_authenticator **authent;
+{
+ krb5_error_code retval, problem;
+ krb5_data inbuf;
+ krb5_tkt_authent *authdat;
+ krb5_data outbuf;
+ krb5_rcache rcache;
+ krb5_octet response;
+ char *cachename;
+ extern krb5_deltat krb5_clockskew;
+ static char *rc_base = "rc_";
+
+ /*
+ * Zero out problem variable. If problem is set at the end of
+ * the intial version negotiation section, it means that we
+ * need to send an error code back to the client application
+ * and exit.
+ */
+ problem = 0;
+ /*
+ * First read the sendauth version string and check it.
+ */
+ if (retval = krb5_read_message(fd, &inbuf))
+ return(retval);
+ if (strcmp(inbuf.data, sendauth_version)) {
+ xfree(inbuf.data);
+ problem = KRB5_SENDAUTH_BADAUTHVERS;
+ }
+ xfree(inbuf.data);
+ /*
+ * Do the same thing for the application version string.
+ */
+ if (retval = krb5_read_message(fd, &inbuf))
+ return(retval);
+ if (strcmp(inbuf.data, appl_version)) {
+ xfree(inbuf.data);
+ if (!problem)
+ problem = KRB5_SENDAUTH_BADAPPLVERS;
+ }
+ xfree(inbuf.data);
+ /*
+ * OK, now check the problem variable. If it's zero, we're
+ * fine and we can continue. Otherwise, we have to signal an
+ * error to the client side and bail out.
+ */
+ switch (problem) {
+ case 0:
+ response = 0;
+ break;
+ case KRB5_SENDAUTH_BADAUTHVERS:
+ response = 1;
+ break;
+ case KRB5_SENDAUTH_BADAPPLVERS:
+ response = 2;
+ break;
+ default:
+ /*
+ * Should never happen!
+ */
+ response = 255;
+#ifdef SENDAUTH_DEBUG
+ fprintf(stderr, "Programming botch in recvauth! problem = %d",
+ problem);
+ abort();
+#endif
+ break;
+ }
+ /*
+ * Now we actually write the response. If the response is non-zero,
+ * exit with a return value of problem
+ */
+ if ((krb5_net_write(*((int *) fd), (char *)&response, 1)) < 0) {
+ return(problem); /* We'll return the top-level problem */
+ }
+ if (problem)
+ return(problem);
+ rcache = NULL;
+#ifdef WORKING_RCACHE
+ /*
+ * Setup the replay cache.
+ */
+ if (!(rcache = (krb5_rcache) malloc(sizeof(*rcache))))
+ problem = ENOMEM;
+ if (!problem)
+ problem = krb5_rc_resolve_type(&rcache,
+ rc_type ? rc_type : "dfl");
+ cachename = NULL;
+ if (!problem && !(cachename = malloc(server[1]->length+1+
+ strlen(rc_base))))
+ problem = ENOMEM;
+ if (!problem) {
+ strcpy(cachename, rc_base ? rc_base : "rc_");
+ strncat(cachename, server[1]->data, server[1]->length);
+ cachename[server[1]->length+strlen(rc_base)] = '\0';
+ problem = krb5_rc_resolve(rcache, cachename);
+ }
+ if (!problem) {
+ if (krb5_rc_recover(rcache))
+ /*
+ * If the rc_recover didn't work, then try
+ * initializing the replay cache.
+ */
+ problem = krb5_rc_initialize(rcache, krb5_clockskew);
+ if (problem) {
+ krb5_rc_close(rcache);
+ rcache = NULL;
+ }
+ }
+#endif
+ /*
+ * Now, let's read the AP_REQ message and decode it
+ */
+ if (retval = krb5_read_message(fd, &inbuf)) {
+#ifdef WORKING_RCACHE
+ (void) krb5_rc_close(rcache);
+ if (cachename)
+ free(cachename);
+#endif
+ return(retval);
+ }
+ authdat = 0; /* so we can tell if we need to
+ free it later... */
+ if (!problem)
+ problem = krb5_rd_req(&inbuf, server, sender_addr, fetch_from,
+ keyproc, keyprocarg, rcache, &authdat);
+ xfree(inbuf.data);
+#ifdef WORKING_RCACHE
+ if (rcache)
+ retval = krb5_rc_close(rcache);
+#endif
+ if (!problem && retval)
+ problem = retval;
+#ifdef WORKING_RCACHE
+ if (cachename)
+ free(cachename);
+#endif
+
+ /*
+ * If there was a problem, send back a krb5_error message,
+ * preceeded by the length of the krb5_error message. If
+ * everything's ok, send back 0 for the length.
+ */
+ if (problem) {
+ krb5_error error;
+ const char *message;
+
+ memset((char *)&error, 0, sizeof(error));
+ krb5_us_timeofday(&error.stime, &error.susec);
+ error.server = server;
+ error.error = problem - ERROR_TABLE_BASE_krb5;
+ if (error.error < 0 || error.error > 127)
+ error.error = KRB_ERR_GENERIC;
+ message = error_message(problem);
+ error.text.length = strlen(message) + 1;
+ if (!(error.text.data = malloc(error.text.length)))
+ return(ENOMEM);
+ strcpy(error.text.data, message);
+ if (retval = krb5_mk_error(&error, &outbuf)) {
+ free(error.text.data);
+ return(retval);
+ }
+ free(error.text.data);
+ } else {
+ outbuf.length = 0;
+ outbuf.data = 0;
+ }
+ if (retval = krb5_write_message(fd, &outbuf)) {
+ if (outbuf.data)
+ xfree(outbuf.data);
+ if (!problem)
+ krb5_free_tkt_authent(authdat);
+ return(retval);
+ }
+ if (problem) {
+ /*
+ * We sent back an error, we need to return
+ */
+ if (authdat) krb5_free_tkt_authent(authdat);
+ return(problem);
+ }
+ /*
+ * Here lies the mutual authentication stuff...
+ *
+ * We're going to compose and send a AP_REP message.
+ */
+ if ((authdat->ap_options & AP_OPTS_MUTUAL_REQUIRED)) {
+ krb5_ap_rep_enc_part repl;
+
+ /*
+ * Generate a random sequence number
+ */
+ if (seq_number &&
+ (retval = krb5_generate_seq_number(authdat->ticket->enc_part2->session,
+ seq_number))) {
+ krb5_free_tkt_authent(authdat);
+ return(retval);
+ }
+
+ repl.ctime = authdat->authenticator->ctime;
+ repl.cusec = authdat->authenticator->cusec;
+ repl.subkey = authdat->authenticator->subkey;
+ if (seq_number)
+ repl.seq_number = *seq_number;
+ else
+ repl.seq_number = 0;
+
+ if (retval = krb5_mk_rep(&repl,
+ authdat->ticket->enc_part2->session,
+ &outbuf)) {
+ krb5_free_tkt_authent(authdat);
+ return(retval);
+ }
+ if (retval = krb5_write_message(fd, &outbuf)) {
+ xfree(outbuf.data);
+ krb5_free_tkt_authent(authdat);
+ return(retval);
+ }
+ xfree(outbuf.data);
+ }
+ /*
+ * At this point, we've won. We just need to copy whatever
+ * parts of the authdat structure which the user wants, clean
+ * up, and exit.
+ */
+ if (client)
+ if (retval =
+ krb5_copy_principal(authdat->ticket->enc_part2->client,
+ client))
+ return(retval);
+ /*
+ * The following efficiency hack assumes knowledge about the
+ * structure of krb5_tkt_authent. If we later add additional
+ * allocated substructures to krb5_tkt_authent, they will have
+ * to be reflected here; otherwise, we will probably have a
+ * memory leak.
+ *
+ * If the user wants that part of the authdat structure,
+ * return it; otherwise free it.
+ */
+ if (ticket)
+ *ticket = authdat->ticket;
+ else
+ krb5_free_ticket(authdat->ticket);
+ if (authent)
+ *authent = authdat->authenticator;
+ else
+ krb5_free_authenticator(authdat->authenticator);
+ xfree(authdat);
+ return 0;
+}
+
+
--- /dev/null
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * For copying and distribution information, please see the file
+ * <krb5/copyright.h>.
+ *
+ * convenience sendauth/recvauth functions
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_sendauth_c [] =
+"$Id$";
+#endif /* !lint & !SABER */
+
+#include <krb5/krb5.h>
+#include <krb5/osconf.h>
+#include <krb5/kdb.h>
+#include <krb5/kdb_dbm.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <com_err.h>
+#include <errno.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#define WORKING_RCACHE
+
+extern krb5_flags krb5_kdc_default_options;
+
+static char *sendauth_version = "KRB5_SENDAUTH_V1.0";
+
+krb5_error_code
+krb5_sendauth(/* IN */
+ fd, appl_version, client, server, ap_req_options,
+ checksump,
+ /* IN/OUT */
+ credsp, ccache,
+ /* OUT */
+ sequence, newkey,
+ error, rep_result)
+ krb5_pointer fd;
+ char *appl_version;
+ krb5_principal client;
+ krb5_principal server;
+ krb5_flags ap_req_options;
+ krb5_int32 *sequence;
+ krb5_keyblock **newkey;
+ krb5_checksum *checksump;
+ krb5_creds *credsp;
+ krb5_ccache ccache;
+ krb5_error **error;
+ krb5_ap_rep_enc_part **rep_result;
+{
+ krb5_flags kdc_options = krb5_kdc_default_options;
+ krb5_octet result;
+ krb5_creds creds;
+ krb5_checksum checksum;
+ krb5_error_code retval = 0;
+ krb5_authenticator authent;
+ krb5_data inbuf, outbuf;
+ int len;
+
+ /*
+ * First, send over the length of the sendauth version string;
+ * then, we send over the sendauth version. Next, we send
+ * over the length of the application version strings followed
+ * by the string itself.
+ */
+ outbuf.length = strlen(sendauth_version) + 1;
+ outbuf.data = sendauth_version;
+ if (retval = krb5_write_message(fd, &outbuf))
+ return(retval);
+ outbuf.length = strlen(appl_version) + 1;
+ outbuf.data = appl_version;
+ if (retval = krb5_write_message(fd, &outbuf))
+ return(retval);
+ /*
+ * Now, read back a byte: 0 means no error, 1 means bad sendauth
+ * version, 2 means bad application version
+ */
+ if ((len = krb5_net_read(*((int *) fd), (char *)&result, 1)) != 1)
+ return((len < 0) ? errno : ECONNABORTED);
+ if (result == 1)
+ return(KRB5_SENDAUTH_BADAUTHVERS);
+ else if (result == 2)
+ return(KRB5_SENDAUTH_BADAPPLVERS);
+ else if (result != 0)
+ return(KRB5_SENDAUTH_BADRESPONSE);
+ /*
+ * We're finished with the initial negotiations; let's get and
+ * send over the authentication header. (The AP_REQ message)
+ */
+
+ /*
+ * If no credentials were provided, try getting it from the
+ * credentials cache.
+ */
+ memset((char *)&creds, 0, sizeof(creds));
+ if (!credsp) {
+ if (!ccache)
+ return(KRB5_NOCREDS_SUPPLIED);
+ creds.server = (krb5_principal) server;
+ if (retval = krb5_copy_principal(client, &creds.client))
+ return(retval);
+ /* creds.times.endtime = 0; -- memset 0 takes care of this
+ zero means "as long as possible" */
+ /* creds.keyblock.keytype = 0; -- as well as this.
+ zero means no session keytype
+ preference */
+ credsp = &creds;
+ }
+ if (!credsp->ticket.length) {
+ if (retval = krb5_get_credentials(kdc_options,
+ ccache,
+ &creds)) {
+ krb5_free_cred_contents(&creds);
+ return(retval);
+ }
+ }
+
+ /*
+ * If no checksum was provided, supply a zero checksum structure
+ */
+
+ if (!checksump) {
+ memset((char *)&checksum, 0, sizeof(checksum));
+ checksump = &checksum;
+ }
+
+ /*
+ * Generate a random sequence number
+ */
+ if (sequence &&
+ (retval = krb5_generate_seq_number(&credsp->keyblock, sequence))) {
+
+ memset((char *)&authent, 0, sizeof(authent));
+ krb5_free_cred_contents(&creds);
+ return(retval);
+ }
+ /*
+ * OK, get the authentication header!
+ */
+ if (retval = krb5_mk_req_extended(ap_req_options, checksump,
+ &credsp->times, kdc_options,
+ sequence ? *sequence : 0, newkey,
+ ccache, credsp, &authent, &outbuf)) {
+ memset((char *)&authent, 0, sizeof(authent));
+ krb5_free_cred_contents(&creds);
+ return(retval);
+ }
+
+ /*
+ * First write the length of the AP_REQ message, then write
+ * the message itself.
+ */
+ if (retval = krb5_write_message(fd, &outbuf)) {
+ krb5_free_cred_contents(&creds);
+ memset((char *)&authent, 0, sizeof(authent));
+ return(retval);
+ }
+ free(outbuf.data);
+
+ /*
+ * Now, read back a message. If it was a null message (the
+ * length was zero) then there was no error. If not, we the
+ * authentication was rejected, and we need to return the
+ * error structure.
+ */
+ if (retval = krb5_read_message(fd, &inbuf)) {
+ krb5_free_cred_contents(&creds);
+ memset((char *)&authent, 0, sizeof(authent));
+ return(retval);
+ }
+ if (inbuf.length) {
+ if (error) {
+ if (retval = krb5_rd_error(&inbuf, error)) {
+ xfree(inbuf.data);
+ return(retval);
+ }
+ }
+ xfree(inbuf.data);
+ krb5_free_cred_contents(&creds);
+ memset((char *)&authent, 0, sizeof(authent));
+ return(KRB5_SENDAUTH_REJECTED);
+ }
+ /*
+ * If we asked for mutual authentication, we should now get a
+ * length field, followed by a AP_REP message
+ */
+ if ((ap_req_options & AP_OPTS_MUTUAL_REQUIRED)) {
+ krb5_ap_rep_enc_part *repl;
+ krb5_error_code problem = 0;
+
+ if (retval = krb5_read_message(fd, &inbuf)) {
+ krb5_free_cred_contents(&creds);
+ memset((char *)&authent, 0, sizeof(authent));
+ return(retval);
+ }
+ problem = krb5_rd_rep(&inbuf,
+ &credsp->keyblock,
+ &repl);
+ if (problem || ((repl->ctime != authent.ctime) ||
+ (repl->cusec != authent.cusec)))
+ problem = KRB5_SENDAUTH_MUTUAL_FAILED;
+ memset((char *)&authent, 0, sizeof(authent));
+ krb5_free_cred_contents(&creds);
+ xfree(inbuf.data);
+ if (problem) {
+ krb5_free_ap_rep_enc_part(repl);
+ return(problem);
+ }
+ /*
+ * If the user wants to look at the AP_REP message,
+ * copy it for him
+ */
+ if (rep_result)
+ *rep_result = repl;
+ else
+ krb5_free_ap_rep_enc_part(repl);
+ } else
+ krb5_free_cred_contents(&creds);
+ return(0);
+}
+
+
--- /dev/null
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * For copying and distribution information, please see the file
+ * <krb5/copyright.h>.
+ *
+ * Write a message to the network
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_sendauth_c [] =
+"$Id$";
+#endif /* !lint & !SABER */
+
+#include <krb5/krb5.h>
+#include <krb5/los-proto.h>
+#include <com_err.h>
+#include <errno.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+
+krb5_error_code
+krb5_read_message(fdp, inbuf)
+ krb5_pointer fdp;
+ krb5_data *inbuf;
+{
+ krb5_int32 len, len2;
+ char *buf = NULL;
+ int fd = *( (int *) fdp);
+
+ if ((len2 = krb5_net_read(fd, (char *)&len, 4)) != 4)
+ return((len2 < 0) ? errno : ECONNABORTED);
+ inbuf->length = len = ntohl(len);
+ if (len) {
+ /*
+ * We may want to include a sanity check here someday....
+ */
+ if (!(buf = malloc(len))) {
+ return(ENOMEM);
+ }
+ if ((len2 = krb5_net_read(fd, buf, len)) != len) {
+ xfree(buf);
+ return((len2 < 0) ? errno : ECONNABORTED);
+ }
+ }
+ inbuf->data = buf;
+ return(0);
+}
+
--- /dev/null
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * For copying and distribution information, please see the file
+ * <krb5/copyright.h>.
+ *
+ * convenience sendauth/recvauth functions
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_sendauth_c [] =
+"$Id$";
+#endif /* !lint & !SABER */
+
+#include <krb5/krb5.h>
+#include <krb5/los-proto.h>
+#include <com_err.h>
+#include <errno.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+
+krb5_error_code
+krb5_write_message(fdp, outbuf)
+ krb5_pointer fdp;
+ krb5_data *outbuf;
+{
+ krb5_int32 len;
+ int fd = *( (int *) fdp);
+
+ len = htonl(outbuf->length);
+ if (krb5_net_write(fd, (char *)&len, 4) < 0) {
+ return(errno);
+ }
+ if (len && (krb5_net_write(fd, outbuf->data, outbuf->length) < 0)) {
+ return(errno);
+ }
+ return(0);
+}
+
+
+
+