KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_read_message (krb5_context context, krb5_pointer p_fd, krb5_data *data) { krb5_error_code ret; uint32_t len; uint8_t buf[4]; krb5_data_zero(data); ret = krb5_net_read (context, p_fd, buf, 4); if(ret == -1) { ret = errno; krb5_clear_error_message (context); return ret; } if(ret < 4) { krb5_clear_error_message(context); return HEIM_ERR_EOF; } len = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; ret = krb5_data_alloc (data, len); if (ret) { krb5_clear_error_message(context); return ret; } if (krb5_net_read (context, p_fd, data->data, len) != len) { ret = errno; krb5_data_free (data); krb5_clear_error_message (context); return ret; } return 0; }
ssize_t do_read (int fd, void *buf, size_t sz, void *ivec) { if (do_encrypt) { #ifdef KRB5 if(auth_method == AUTH_KRB5) { krb5_error_code ret; uint32_t len, outer_len; int status; krb5_data data; void *edata; ret = krb5_net_read (context, &fd, &len, 4); if (ret <= 0) return ret; len = ntohl(len); if (len > sz) abort (); /* ivec will be non null for protocol version 2 */ if(ivec != NULL) outer_len = krb5_get_wrapped_length (context, crypto, len + 4); else outer_len = krb5_get_wrapped_length (context, crypto, len); edata = malloc (outer_len); if (edata == NULL) errx (1, "malloc: cannot allocate %u bytes", outer_len); ret = krb5_net_read (context, &fd, edata, outer_len); if (ret <= 0) { free(edata); return ret; } status = krb5_decrypt_ivec(context, crypto, key_usage, edata, outer_len, &data, ivec); free (edata); if (status) krb5_err (context, 1, status, "decrypting data"); if(ivec != NULL) { unsigned long l; if(data.length < len + 4) errx (1, "data received is too short"); _krb5_get_int(data.data, &l, 4); if(l != len) errx (1, "inconsistency in received data"); memcpy (buf, (unsigned char *)data.data+4, len); } else memcpy (buf, data.data, len); krb5_data_free (&data); return len; } else #endif /* KRB5 */ abort (); } else return read (fd, buf, sz); }
static krb5_error_code krb5_compat_recvauth(krb5_context context, krb5_auth_context *auth_context, krb5_pointer fdp, /* IN */ krb5_principal server, /* IN */ krb5_int32 flags, /* IN */ krb5_keytab keytab, /* IN */ krb5_ticket **ticket, /* OUT */ krb5_int32 *auth_sys, /* OUT */ krb5_data *version) /* OUT */ { krb5_int32 vlen; char *buf; int len, length; krb5_int32 retval; int fd = *((int *)fdp); if ((retval = krb5_net_read(context, fd, (char *)&vlen, 4)) != 4) return ((retval < 0) ? errno : ECONNABORTED); /* * Assume that we're talking to a V5 recvauth; read in the * the version string, and make sure it matches. */ len = (int)ntohl(vlen); if (len < 0 || len > 255) return (KRB5_SENDAUTH_BADAUTHVERS); buf = malloc(len); if (buf == NULL) return (ENOMEM); length = krb5_net_read(context, fd, buf, len); if (len != length) { krb5_xfree(buf); return ((len < 0) ? errno : ECONNABORTED); } if (strcmp(buf, KRB_V5_SENDAUTH_VERS) != 0) { krb5_xfree(buf); return (KRB5_SENDAUTH_BADAUTHVERS); } krb5_xfree(buf); *auth_sys = KRB5_RECVAUTH_V5; retval = krb5_recvauth_version(context, auth_context, fdp, server, flags | KRB5_RECVAUTH_SKIP_VERSION, keytab, ticket, version); return (retval); }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_read_message (krb5_context context, krb5_pointer p_fd, krb5_data *data) { krb5_error_code ret; krb5_ssize_t sret; uint32_t len; uint8_t buf[4]; krb5_data_zero(data); sret = krb5_net_read (context, p_fd, buf, 4); if(sret == -1) { ret = errno; krb5_clear_error_message (context); return ret; } if(sret < 4) { krb5_clear_error_message(context); return HEIM_ERR_EOF; } len = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; if (len > UINT_MAX / 16) { krb5_set_error_message(context, ERANGE, N_("packet to large", "")); return ERANGE; } ret = krb5_data_alloc (data, len); if (ret) { krb5_clear_error_message(context); return ret; } if (krb5_net_read (context, p_fd, data->data, len) != (ssize_t)len) { ret = errno; krb5_data_free (data); krb5_clear_error_message (context); return ret; } return 0; }
krb5_error_code kadmind_loop(krb5_context context, krb5_keytab keytab, krb5_socket_t sock) { u_char buf[sizeof(KRB5_SENDAUTH_VERSION) + 4]; ssize_t n; unsigned long len; n = krb5_net_read(context, &sock, buf, 4); if(n == 0) exit(0); if(n < 0) krb5_err(context, 1, errno, "read"); _krb5_get_int(buf, &len, 4); if (len == sizeof(KRB5_SENDAUTH_VERSION)) { n = krb5_net_read(context, &sock, buf + 4, len); if (n < 0) krb5_err (context, 1, errno, "reading sendauth version"); if (n == 0) krb5_errx (context, 1, "EOF reading sendauth version"); if(memcmp(buf + 4, KRB5_SENDAUTH_VERSION, len) == 0) { handle_v5(context, keytab, sock); return 0; } len += 4; } else len = 4; handle_mit(context, buf, len, sock); return 0; }
krb5_error_code KRB5_CALLCONV krb5_sendauth(krb5_context context, krb5_auth_context *auth_context, krb5_pointer fd, char *appl_version, krb5_principal client, krb5_principal server, krb5_flags ap_req_options, krb5_data *in_data, krb5_creds *in_creds, krb5_ccache ccache, krb5_error **error, krb5_ap_rep_enc_part **rep_result, krb5_creds **out_creds) { krb5_octet result; krb5_creds creds; krb5_creds * credsp = NULL; krb5_creds * credspout = NULL; krb5_error_code retval = 0; krb5_data inbuf, outbuf; int len; krb5_ccache use_ccache = 0; if (error) *error = 0; /* * 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 = (char *) sendauth_version; if ((retval = krb5_write_message(context, fd, &outbuf))) return(retval); outbuf.length = strlen(appl_version) + 1; outbuf.data = appl_version; if ((retval = krb5_write_message(context, fd, &outbuf))) return(retval); /* * Now, read back a byte: 0 means no error, 1 means bad sendauth * version, 2 means bad application version */ len = krb5_net_read(context, *((int *) fd), (char *)&result, 1); if (len != 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)); /* * See if we need to access the credentials cache */ if (!in_creds || !in_creds->ticket.length) { if (ccache) use_ccache = ccache; /* Solaris Kerberos */ else if ((retval = krb5int_cc_default(context, &use_ccache)) != 0) goto error_return; } if (!in_creds) { if ((retval = krb5_copy_principal(context, server, &creds.server))) goto error_return; if (client) retval = krb5_copy_principal(context, client, &creds.client); else retval = krb5_cc_get_principal(context, use_ccache, &creds.client); if (retval) { krb5_free_principal(context, creds.server); goto error_return; } /* creds.times.endtime = 0; -- memset 0 takes care of this zero means "as long as possible" */ /* creds.keyblock.enctype = 0; -- as well as this. zero means no session enctype preference */ in_creds = &creds; } if (!in_creds->ticket.length) { /* Solaris Kerberos */ if ((retval = krb5_get_credentials(context, 0, use_ccache, in_creds, &credsp)) != 0) goto error_return; credspout = credsp; } else { credsp = in_creds; } if (ap_req_options & AP_OPTS_USE_SUBKEY) { /* Provide some more fodder for random number code. This isn't strong cryptographically; the point here is not to guarantee randomness, but to make it less likely that multiple sessions could pick the same subkey. */ char rnd_data[1024]; GETPEERNAME_ARG3_TYPE len2; krb5_data d; d.length = sizeof (rnd_data); d.data = rnd_data; len2 = sizeof (rnd_data); if (getpeername (*(int*)fd, (GETPEERNAME_ARG2_TYPE *) rnd_data, &len2) == 0) { d.length = len2; /* Solaris Kerberos */ (void) krb5_c_random_seed (context, &d); } len2 = sizeof (rnd_data); if (getsockname (*(int*)fd, (GETSOCKNAME_ARG2_TYPE *) rnd_data, &len2) == 0) { d.length = len2; /* Solaris Kerberos */ (void) krb5_c_random_seed (context, &d); } } /* Solaris Kerberos */ if ((retval = krb5_mk_req_extended(context, auth_context, ap_req_options, in_data, credsp, &outbuf)) != 0) goto error_return; /* * First write the length of the AP_REQ message, then write * the message itself. */ retval = krb5_write_message(context, fd, &outbuf); free(outbuf.data); if (retval) goto error_return; /* * 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. */ /* Solaris Kerberos */ if ((retval = krb5_read_message(context, fd, &inbuf)) != 0) goto error_return; if (inbuf.length) { if (error) { /* Solaris Kerberos */ if ((retval = krb5_rd_error(context, &inbuf, error)) != 0) { krb5_xfree(inbuf.data); goto error_return; } } retval = KRB5_SENDAUTH_REJECTED; krb5_xfree(inbuf.data); goto error_return; } /* * 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 = 0; /* Solaris Kerberos */ if ((retval = krb5_read_message(context, fd, &inbuf)) != 0) goto error_return; /* Solaris Kerberos */ if ((retval = krb5_rd_rep(context, *auth_context, &inbuf, &repl)) != 0) { if (repl) krb5_free_ap_rep_enc_part(context, repl); krb5_xfree(inbuf.data); goto error_return; } krb5_xfree(inbuf.data); /* * If the user wants to look at the AP_REP message, * copy it for them. */ if (rep_result) *rep_result = repl; else krb5_free_ap_rep_enc_part(context, repl); } retval = 0; /* Normal return */ if (out_creds) { *out_creds = credsp; credspout = NULL; } error_return: krb5_free_cred_contents(context, &creds); if (credspout != NULL) krb5_free_creds(context, credspout); /* Solaris Kerberos */ if (!ccache && use_ccache) (void) krb5_cc_close(context, use_ccache); return(retval); }
static int proto (int sock, const char *service) { krb5_auth_context auth_context; krb5_error_code status; krb5_principal server; krb5_ticket *ticket; char *name; char hostname[MAXHOSTNAMELEN]; krb5_data packet; krb5_data data; u_int32_t len, net_len; ssize_t n; status = krb5_auth_con_init (context, &auth_context); if (status) krb5_err (context, 1, status, "krb5_auth_con_init"); status = krb5_auth_con_setaddrs_from_fd (context, auth_context, &sock); if (status) krb5_err (context, 1, status, "krb5_auth_con_setaddrs_from_fd"); if(gethostname (hostname, sizeof(hostname)) < 0) krb5_err (context, 1, errno, "gethostname"); status = krb5_sname_to_principal (context, hostname, service, KRB5_NT_SRV_HST, &server); if (status) krb5_err (context, 1, status, "krb5_sname_to_principal"); status = krb5_recvauth (context, &auth_context, &sock, VERSION, server, 0, NULL, &ticket); if (status) krb5_err (context, 1, status, "krb5_recvauth"); status = krb5_unparse_name (context, ticket->client, &name); if (status) krb5_err (context, 1, status, "krb5_unparse_name"); fprintf (stderr, "User is `%s'\n", name); free (name); krb5_data_zero (&data); krb5_data_zero (&packet); n = krb5_net_read (context, &sock, &net_len, 4); if (n == 0) krb5_errx (context, 1, "EOF in krb5_net_read"); if (n < 0) krb5_err (context, 1, errno, "krb5_net_read"); len = ntohl(net_len); krb5_data_alloc (&packet, len); n = krb5_net_read (context, &sock, packet.data, len); if (n == 0) krb5_errx (context, 1, "EOF in krb5_net_read"); if (n < 0) krb5_err (context, 1, errno, "krb5_net_read"); status = krb5_rd_safe (context, auth_context, &packet, &data, NULL); if (status) krb5_err (context, 1, status, "krb5_rd_safe"); fprintf (stderr, "safe packet: %.*s\n", (int)data.length, (char *)data.data); n = krb5_net_read (context, &sock, &net_len, 4); if (n == 0) krb5_errx (context, 1, "EOF in krb5_net_read"); if (n < 0) krb5_err (context, 1, errno, "krb5_net_read"); len = ntohl(net_len); krb5_data_alloc (&packet, len); n = krb5_net_read (context, &sock, packet.data, len); if (n == 0) krb5_errx (context, 1, "EOF in krb5_net_read"); if (n < 0) krb5_err (context, 1, errno, "krb5_net_read"); status = krb5_rd_priv (context, auth_context, &packet, &data, NULL); if (status) krb5_err (context, 1, status, "krb5_rd_priv"); fprintf (stderr, "priv packet: %.*s\n", (int)data.length, (char *)data.data); return 0; }
krb5_error_code KRB5_LIB_FUNCTION krb5_sendauth(krb5_context context, krb5_auth_context *auth_context, krb5_pointer p_fd, const char *appl_version, krb5_principal client, krb5_principal server, krb5_flags ap_req_options, krb5_data *in_data, krb5_creds *in_creds, krb5_ccache ccache, krb5_error **ret_error, krb5_ap_rep_enc_part **rep_result, krb5_creds **out_creds) { krb5_error_code ret; uint32_t len, net_len; const char *version = KRB5_SENDAUTH_VERSION; u_char repl; krb5_data ap_req, error_data; krb5_creds this_cred; krb5_principal this_client = NULL; krb5_creds *creds; ssize_t sret; krb5_boolean my_ccache = FALSE; len = strlen(version) + 1; net_len = htonl(len); if (krb5_net_write (context, p_fd, &net_len, 4) != 4 || krb5_net_write (context, p_fd, version, len) != len) { ret = errno; krb5_set_error_string (context, "write: %s", strerror(ret)); return ret; } len = strlen(appl_version) + 1; net_len = htonl(len); if (krb5_net_write (context, p_fd, &net_len, 4) != 4 || krb5_net_write (context, p_fd, appl_version, len) != len) { ret = errno; krb5_set_error_string (context, "write: %s", strerror(ret)); return ret; } sret = krb5_net_read (context, p_fd, &repl, sizeof(repl)); if (sret < 0) { ret = errno; krb5_set_error_string (context, "read: %s", strerror(ret)); return ret; } else if (sret != sizeof(repl)) { krb5_clear_error_string (context); return KRB5_SENDAUTH_BADRESPONSE; } if (repl != 0) { krb5_clear_error_string (context); return KRB5_SENDAUTH_REJECTED; } if (in_creds == NULL) { if (ccache == NULL) { ret = krb5_cc_default (context, &ccache); if (ret) return ret; my_ccache = TRUE; } if (client == NULL) { ret = krb5_cc_get_principal (context, ccache, &this_client); if (ret) { if(my_ccache) krb5_cc_close(context, ccache); return ret; } client = this_client; } memset(&this_cred, 0, sizeof(this_cred)); this_cred.client = client; this_cred.server = server; this_cred.times.endtime = 0; this_cred.ticket.length = 0; in_creds = &this_cred; } if (in_creds->ticket.length == 0) { ret = krb5_get_credentials (context, 0, ccache, in_creds, &creds); if (ret) { if(my_ccache) krb5_cc_close(context, ccache); return ret; } } else { creds = in_creds; } if(my_ccache) krb5_cc_close(context, ccache); ret = krb5_mk_req_extended (context, auth_context, ap_req_options, in_data, creds, &ap_req); if (out_creds) *out_creds = creds; else krb5_free_creds(context, creds); if(this_client) krb5_free_principal(context, this_client); if (ret) return ret; ret = krb5_write_message (context, p_fd, &ap_req); if (ret) return ret; krb5_data_free (&ap_req); ret = krb5_read_message (context, p_fd, &error_data); if (ret) return ret; if (error_data.length != 0) { KRB_ERROR error; ret = krb5_rd_error (context, &error_data, &error); krb5_data_free (&error_data); if (ret == 0) { ret = krb5_error_from_rd_error(context, &error, NULL); if (ret_error != NULL) { *ret_error = malloc (sizeof(krb5_error)); if (*ret_error == NULL) { krb5_free_error_contents (context, &error); } else { **ret_error = error; } } else { krb5_free_error_contents (context, &error); } return ret; } else { krb5_clear_error_string(context); return ret; } } if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED) { krb5_data ap_rep; krb5_ap_rep_enc_part *ignore; krb5_data_zero (&ap_rep); ret = krb5_read_message (context, p_fd, &ap_rep); if (ret) return ret; ret = krb5_rd_rep (context, *auth_context, &ap_rep, rep_result ? rep_result : &ignore); krb5_data_free (&ap_rep); if (ret) return ret; if (rep_result == NULL) krb5_free_ap_rep_enc_part (context, ignore); } return 0; }
/** * Perform the server side of the sendauth protocol like krb5_recvauth(), but support * a user-specified callback, \a match_appl_version, to perform the match of the application * version \a match_data. */ KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_recvauth_match_version(krb5_context context, krb5_auth_context *auth_context, krb5_pointer p_fd, krb5_boolean (*match_appl_version)(const void *, const char*), const void *match_data, krb5_principal server, int32_t flags, krb5_keytab keytab, krb5_ticket **ticket) { krb5_error_code ret; const char *version = KRB5_SENDAUTH_VERSION; char her_version[sizeof(KRB5_SENDAUTH_VERSION)]; char *her_appl_version; uint32_t len; u_char repl; krb5_data data; krb5_flags ap_options; ssize_t n; /* * If there are no addresses in auth_context, get them from `fd'. */ if (*auth_context == NULL) { ret = krb5_auth_con_init (context, auth_context); if (ret) return ret; } ret = krb5_auth_con_setaddrs_from_fd (context, *auth_context, p_fd); if (ret) return ret; /* * Expect SENDAUTH protocol version. */ if(!(flags & KRB5_RECVAUTH_IGNORE_VERSION)) { n = krb5_net_read (context, p_fd, &len, 4); if (n < 0) { ret = errno; krb5_set_error_message(context, ret, "read: %s", strerror(ret)); return ret; } if (n == 0) { krb5_set_error_message(context, KRB5_SENDAUTH_BADAUTHVERS, N_("Failed to receive sendauth data", "")); return KRB5_SENDAUTH_BADAUTHVERS; } len = ntohl(len); if (len != sizeof(her_version) || krb5_net_read (context, p_fd, her_version, len) != len || strncmp (version, her_version, len)) { repl = 1; krb5_net_write (context, p_fd, &repl, 1); krb5_clear_error_message (context); return KRB5_SENDAUTH_BADAUTHVERS; } } /* * Expect application protocol version. */ n = krb5_net_read (context, p_fd, &len, 4); if (n < 0) { ret = errno; krb5_set_error_message(context, ret, "read: %s", strerror(ret)); return ret; } if (n == 0) { krb5_clear_error_message (context); return KRB5_SENDAUTH_BADAPPLVERS; } len = ntohl(len); her_appl_version = malloc (len); if (her_appl_version == NULL) { repl = 2; krb5_net_write (context, p_fd, &repl, 1); krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); return ENOMEM; } if (krb5_net_read (context, p_fd, her_appl_version, len) != len || !(*match_appl_version)(match_data, her_appl_version)) { repl = 2; krb5_net_write (context, p_fd, &repl, 1); krb5_set_error_message(context, KRB5_SENDAUTH_BADAPPLVERS, N_("wrong sendauth application version (%s)", ""), her_appl_version); free (her_appl_version); return KRB5_SENDAUTH_BADAPPLVERS; } free (her_appl_version); /* * Send OK. */ repl = 0; if (krb5_net_write (context, p_fd, &repl, 1) != 1) { ret = errno; krb5_set_error_message(context, ret, "write: %s", strerror(ret)); return ret; } /* * Until here, the fields in the message were in cleartext and unauthenticated. * From now on, Kerberos kicks in. */ /* * Expect AP_REQ. */ krb5_data_zero (&data); ret = krb5_read_message (context, p_fd, &data); if (ret) return ret; ret = krb5_rd_req (context, auth_context, &data, server, keytab, &ap_options, ticket); krb5_data_free (&data); if (ret) { krb5_data error_data; krb5_error_code ret2; ret2 = krb5_mk_error (context, ret, NULL, NULL, NULL, server, NULL, NULL, &error_data); if (ret2 == 0) { krb5_write_message (context, p_fd, &error_data); krb5_data_free (&error_data); } return ret; } /* * Send OK. */ len = 0; if (krb5_net_write (context, p_fd, &len, 4) != 4) { ret = errno; krb5_set_error_message(context, ret, "write: %s", strerror(ret)); krb5_free_ticket(context, *ticket); *ticket = NULL; return ret; } /* * If client requires mutual authentication, send AP_REP. */ if (ap_options & AP_OPTS_MUTUAL_REQUIRED) { ret = krb5_mk_rep (context, *auth_context, &data); if (ret) { krb5_free_ticket(context, *ticket); *ticket = NULL; return ret; } ret = krb5_write_message (context, p_fd, &data); if (ret) { krb5_free_ticket(context, *ticket); *ticket = NULL; return ret; } krb5_data_free (&data); } return 0; }
krb5_error_code KRB5_LIB_FUNCTION krb5_recvauth_match_version(krb5_context context, krb5_auth_context *auth_context, krb5_pointer p_fd, krb5_boolean (*match_appl_version)(const void *, const char*), const void *match_data, krb5_principal server, int32_t flags, krb5_keytab keytab, krb5_ticket **ticket) { krb5_error_code ret; const char *version = KRB5_SENDAUTH_VERSION; char her_version[sizeof(KRB5_SENDAUTH_VERSION)]; char *her_appl_version; u_int32_t len; u_char repl; krb5_data data; krb5_flags ap_options; ssize_t n; /* * If there are no addresses in auth_context, get them from `fd'. */ if (*auth_context == NULL) { ret = krb5_auth_con_init (context, auth_context); if (ret) return ret; } ret = krb5_auth_con_setaddrs_from_fd (context, *auth_context, p_fd); if (ret) return ret; if(!(flags & KRB5_RECVAUTH_IGNORE_VERSION)) { n = krb5_net_read (context, p_fd, &len, 4); if (n < 0) { ret = errno; krb5_set_error_string (context, "read: %s", strerror(errno)); return ret; } if (n == 0) { krb5_clear_error_string (context); return KRB5_SENDAUTH_BADAUTHVERS; } len = ntohl(len); if (len != sizeof(her_version) || krb5_net_read (context, p_fd, her_version, len) != len || strncmp (version, her_version, len)) { repl = 1; krb5_net_write (context, p_fd, &repl, 1); krb5_clear_error_string (context); return KRB5_SENDAUTH_BADAUTHVERS; } } n = krb5_net_read (context, p_fd, &len, 4); if (n < 0) { ret = errno; krb5_set_error_string (context, "read: %s", strerror(errno)); return ret; } if (n == 0) { krb5_clear_error_string (context); return KRB5_SENDAUTH_BADAPPLVERS; } len = ntohl(len); her_appl_version = malloc (len); if (her_appl_version == NULL) { repl = 2; krb5_net_write (context, p_fd, &repl, 1); krb5_set_error_string (context, "malloc: out of memory"); return ENOMEM; } if (krb5_net_read (context, p_fd, her_appl_version, len) != len || !(*match_appl_version)(match_data, her_appl_version)) { repl = 2; krb5_net_write (context, p_fd, &repl, 1); krb5_set_error_string (context, "wrong sendauth version (%s)", her_appl_version); free (her_appl_version); return KRB5_SENDAUTH_BADAPPLVERS; } free (her_appl_version); repl = 0; if (krb5_net_write (context, p_fd, &repl, 1) != 1) { ret = errno; krb5_set_error_string (context, "write: %s", strerror(errno)); return ret; } krb5_data_zero (&data); ret = krb5_read_message (context, p_fd, &data); if (ret) return ret; ret = krb5_rd_req (context, auth_context, &data, server, keytab, &ap_options, ticket); krb5_data_free (&data); if (ret) { krb5_data error_data; krb5_error_code ret2; ret2 = krb5_mk_error (context, ret, NULL, NULL, NULL, server, NULL, NULL, &error_data); if (ret2 == 0) { krb5_write_message (context, p_fd, &error_data); krb5_data_free (&error_data); } return ret; } len = 0; if (krb5_net_write (context, p_fd, &len, 4) != 4) { ret = errno; krb5_set_error_string (context, "write: %s", strerror(errno)); return ret; } if (ap_options & AP_OPTS_MUTUAL_REQUIRED) { ret = krb5_mk_rep (context, *auth_context, &data); if (ret) return ret; ret = krb5_write_message (context, p_fd, &data); if (ret) return ret; krb5_data_free (&data); } return 0; }