2N/A/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2N/A/*
2N/A * lib/krb5/krb/recvauth.c
2N/A *
2N/A * Copyright 1991 by the Massachusetts Institute of Technology.
2N/A * All Rights Reserved.
2N/A *
2N/A * Export of this software from the United States of America may
2N/A * require a specific license from the United States Government.
2N/A * It is the responsibility of any person or organization contemplating
2N/A * export to obtain such a license before exporting.
2N/A *
2N/A * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
2N/A * distribute this software and its documentation for any purpose and
2N/A * without fee is hereby granted, provided that the above copyright
2N/A * notice appear in all copies and that both that copyright notice and
2N/A * this permission notice appear in supporting documentation, and that
2N/A * the name of M.I.T. not be used in advertising or publicity pertaining
2N/A * to distribution of the software without specific, written prior
2N/A * permission. Furthermore if you modify this software you must label
2N/A * your software as modified software and not distribute it in such a
2N/A * fashion that it might be confused with the original M.I.T. software.
2N/A * M.I.T. makes no representations about the suitability of
2N/A * this software for any purpose. It is provided "as is" without express
2N/A * or implied warranty.
2N/A */
2N/A/*
2N/A * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A/*
2N/A * convenience sendauth/recvauth functions
2N/A */
2N/A
2N/A#include "k5-int.h"
2N/A#include "auth_con.h"
2N/A#include "com_err.h"
2N/A#include <errno.h>
2N/A#include <stdio.h>
2N/A#include <string.h>
2N/A
2N/Astatic const char sendauth_version[] = "KRB5_SENDAUTH_V1.0";
2N/A
2N/Astatic krb5_error_code
2N/Arecvauth_common(krb5_context context,
2N/A krb5_auth_context * auth_context,
2N/A /* IN */
2N/A krb5_pointer fd,
2N/A char *appl_version,
2N/A krb5_principal server,
2N/A krb5_int32 flags,
2N/A krb5_keytab keytab,
2N/A /* OUT */
2N/A krb5_ticket ** ticket,
2N/A krb5_data *version)
2N/A{
2N/A krb5_auth_context new_auth_context;
2N/A krb5_flags ap_option = 0;
2N/A krb5_error_code retval, problem;
2N/A krb5_data inbuf;
2N/A krb5_data outbuf;
2N/A krb5_rcache rcache = 0;
2N/A krb5_octet response;
2N/A krb5_data null_server;
2N/A int need_error_free = 0;
2N/A int local_rcache = 0, local_authcon = 0;
2N/A
2N/A /*
2N/A * Zero out problem variable. If problem is set at the end of
2N/A * the intial version negotiation section, it means that we
2N/A * need to send an error code back to the client application
2N/A * and exit.
2N/A */
2N/A problem = 0;
2N/A response = 0;
2N/A
2N/A if (!(flags & KRB5_RECVAUTH_SKIP_VERSION)) {
2N/A /*
2N/A * First read the sendauth version string and check it.
2N/A */
2N/A if ((retval = krb5_read_message(context, fd, &inbuf)))
2N/A return(retval);
2N/A if (strcmp(inbuf.data, sendauth_version)) {
2N/A problem = KRB5_SENDAUTH_BADAUTHVERS;
2N/A response = 1;
2N/A }
2N/A free(inbuf.data);
2N/A }
2N/A if (flags & KRB5_RECVAUTH_BADAUTHVERS) {
2N/A problem = KRB5_SENDAUTH_BADAUTHVERS;
2N/A response = 1;
2N/A }
2N/A
2N/A /*
2N/A * Do the same thing for the application version string.
2N/A */
2N/A if ((retval = krb5_read_message(context, fd, &inbuf)))
2N/A return(retval);
2N/A if (appl_version && strcmp(inbuf.data, appl_version)) {
2N/A if (!problem) {
2N/A problem = KRB5_SENDAUTH_BADAPPLVERS;
2N/A response = 2;
2N/A }
2N/A }
2N/A if (version && !problem)
2N/A *version = inbuf;
2N/A else
2N/A free(inbuf.data);
2N/A
2N/A /*
2N/A * Now we actually write the response. If the response is non-zero,
2N/A * exit with a return value of problem
2N/A */
2N/A if ((krb5_net_write(context, *((int *)fd), (char *)&response, 1)) < 0) {
2N/A return(problem); /* We'll return the top-level problem */
2N/A }
2N/A if (problem)
2N/A return(problem);
2N/A
2N/A /* We are clear of errors here */
2N/A
2N/A /*
2N/A * Now, let's read the AP_REQ message and decode it
2N/A */
2N/A if ((retval = krb5_read_message(context, fd, &inbuf)))
2N/A return retval;
2N/A
2N/A if (*auth_context == NULL) {
2N/A problem = krb5_auth_con_init(context, &new_auth_context);
2N/A *auth_context = new_auth_context;
2N/A local_authcon = 1;
2N/A }
2N/A krb5_auth_con_getrcache(context, *auth_context, &rcache);
2N/A if ((!problem) && rcache == NULL) {
2N/A /*
2N/A * Setup the replay cache.
2N/A */
2N/A if (server) {
2N/A problem = krb5_get_server_rcache(context,
2N/A krb5_princ_component(context, server, 0), &rcache);
2N/A } else {
2N/A null_server.length = 7;
2N/A null_server.data = "default";
2N/A problem = krb5_get_server_rcache(context, &null_server, &rcache);
2N/A }
2N/A if (!problem)
2N/A problem = krb5_auth_con_setrcache(context, *auth_context, rcache);
2N/A local_rcache = 1;
2N/A }
2N/A if (!problem) {
2N/A problem = krb5_rd_req(context, auth_context, &inbuf, server,
2N/A keytab, &ap_option, ticket);
2N/A free(inbuf.data);
2N/A }
2N/A
2N/A /*
2N/A * If there was a problem, send back a krb5_error message,
2N/A * preceeded by the length of the krb5_error message. If
2N/A * everything's ok, send back 0 for the length.
2N/A */
2N/A if (problem) {
2N/A krb5_error error;
2N/A const char *message;
2N/A
2N/A memset(&error, 0, sizeof(error));
2N/A krb5_us_timeofday(context, &error.stime, &error.susec);
2N/A if(server)
2N/A error.server = server;
2N/A else {
2N/A /* If this fails - ie. ENOMEM we are hosed
2N/A we cannot even send the error if we wanted to... */
2N/A (void) krb5_parse_name(context, "????", &error.server);
2N/A need_error_free = 1;
2N/A }
2N/A
2N/A error.error = problem - ERROR_TABLE_BASE_krb5;
2N/A if (error.error > 127)
2N/A error.error = KRB_ERR_GENERIC;
2N/A message = error_message(problem);
2N/A error.text.length = strlen(message) + 1;
2N/A error.text.data = strdup(message);
2N/A if (!error.text.data) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A if ((retval = krb5_mk_error(context, &error, &outbuf))) {
2N/A free(error.text.data);
2N/A goto cleanup;
2N/A }
2N/A free(error.text.data);
2N/A if(need_error_free)
2N/A krb5_free_principal(context, error.server);
2N/A
2N/A } else {
2N/A outbuf.length = 0;
2N/A outbuf.data = 0;
2N/A }
2N/A
2N/A retval = krb5_write_message(context, fd, &outbuf);
2N/A if (outbuf.data) {
2N/A free(outbuf.data);
2N/A /* We sent back an error, we need cleanup then return */
2N/A retval = problem;
2N/A goto cleanup;
2N/A }
2N/A if (retval)
2N/A goto cleanup;
2N/A
2N/A /* Here lies the mutual authentication stuff... */
2N/A if ((ap_option & AP_OPTS_MUTUAL_REQUIRED)) {
2N/A if ((retval = krb5_mk_rep(context, *auth_context, &outbuf))) {
2N/A return(retval);
2N/A }
2N/A retval = krb5_write_message(context, fd, &outbuf);
2N/A free(outbuf.data);
2N/A }
2N/A
2N/Acleanup:;
2N/A if (retval) {
2N/A if (local_authcon) {
2N/A krb5_auth_con_free(context, *auth_context);
2N/A /* Solaris Kerberos */
2N/A *auth_context = NULL;
2N/A } else if (local_rcache && rcache != NULL) {
2N/A krb5_rc_close(context, rcache);
2N/A krb5_auth_con_setrcache(context, *auth_context, NULL);
2N/A }
2N/A }
2N/A return retval;
2N/A}
2N/A
2N/Akrb5_error_code KRB5_CALLCONV
2N/Akrb5_recvauth(krb5_context context, krb5_auth_context *auth_context, krb5_pointer fd, char *appl_version, krb5_principal server, krb5_int32 flags, krb5_keytab keytab, krb5_ticket **ticket)
2N/A{
2N/A return recvauth_common (context, auth_context, fd, appl_version,
2N/A server, flags, keytab, ticket, 0);
2N/A}
2N/A
2N/Akrb5_error_code KRB5_CALLCONV
2N/Akrb5_recvauth_version(krb5_context context,
2N/A krb5_auth_context *auth_context,
2N/A /* IN */
2N/A krb5_pointer fd,
2N/A krb5_principal server,
2N/A krb5_int32 flags,
2N/A krb5_keytab keytab,
2N/A /* OUT */
2N/A krb5_ticket **ticket,
2N/A krb5_data *version)
2N/A{
2N/A return recvauth_common (context, auth_context, fd, 0,
2N/A server, flags, keytab, ticket, version);
2N/A}