*** empty log message ***
authorTheodore Tso <tytso@mit.edu>
Thu, 28 Mar 1991 17:50:46 +0000 (17:50 +0000)
committerTheodore Tso <tytso@mit.edu>
Thu, 28 Mar 1991 17:50:46 +0000 (17:50 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@1954 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/krb/recvauth.c [new file with mode: 0644]
src/lib/krb5/krb/sendauth.c [new file with mode: 0644]
src/lib/krb5/os/read_msg.c [new file with mode: 0644]
src/lib/krb5/os/write_msg.c [new file with mode: 0644]

diff --git a/src/lib/krb5/krb/recvauth.c b/src/lib/krb5/krb/recvauth.c
new file mode 100644 (file)
index 0000000..09f120a
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * $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;
+}
+
+
diff --git a/src/lib/krb5/krb/sendauth.c b/src/lib/krb5/krb/sendauth.c
new file mode 100644 (file)
index 0000000..03a279c
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * $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);
+}
+
+
diff --git a/src/lib/krb5/os/read_msg.c b/src/lib/krb5/os/read_msg.c
new file mode 100644 (file)
index 0000000..681fe8a
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * $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);
+}
+
diff --git a/src/lib/krb5/os/write_msg.c b/src/lib/krb5/os/write_msg.c
new file mode 100644 (file)
index 0000000..61ac2d8
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * $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);
+}
+
+
+
+