summaryrefslogtreecommitdiff
path: root/src/auth_common.c
diff options
context:
space:
mode:
authorfergus.henderson <fergus.henderson@01de4be4-8c4a-0410-9132-4925637da917>2009-07-23 02:16:18 +0000
committerfergus.henderson <fergus.henderson@01de4be4-8c4a-0410-9132-4925637da917>2009-07-23 02:16:18 +0000
commit99d9f20c12125c12cc61dd1cefbeb47a0f343c06 (patch)
treef7f781c1b4a4e47775b6b692b7b4e148fa79ea8d /src/auth_common.c
parent3fdf0bee4dbf8276cacd29e71618fee2d4116339 (diff)
downloaddistcc-99d9f20c12125c12cc61dd1cefbeb47a0f343c06.tar.gz
Apply patch from Ian.Baker@cern.ch:
Optional GSS-API Functionality. This patch implements mutual authentication, out of sequence and replay detection using the GSS-API. The changes implemented are optional and are turned off by default. This option is specified to the client through an environment variable as is the name of the server principal to authenticate. Currently the server principal can be left unspecified and a default based on the host keytab will be used. This option is specified to the daemon through a command line option, with the name of the principal whose credentials the daemon should use specified as an environment variable. A simple handshake is exchanged between the client and server in order to prevent unecessary delays and protocol derailments when mixing authenticating and non-authenticating clients and servers. Revised based on review comments. GSS-API authentication is now implemented as a per host option. Revised further by me (Fergus Henderson) to fix a spelling error and to rename the per host option from ",gssapi" to ",auth". git-svn-id: http://distcc.googlecode.com/svn/trunk@690 01de4be4-8c4a-0410-9132-4925637da917
Diffstat (limited to 'src/auth_common.c')
-rw-r--r--src/auth_common.c229
1 files changed, 229 insertions, 0 deletions
diff --git a/src/auth_common.c b/src/auth_common.c
new file mode 100644
index 0000000..9d9d6ef
--- /dev/null
+++ b/src/auth_common.c
@@ -0,0 +1,229 @@
+/* Copyright (C) 2008 CERN
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+/* Author: Ian Baker */
+
+#include <config.h>
+
+#ifdef HAVE_GSSAPI
+#include <arpa/inet.h>
+#endif
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "auth.h"
+#include "distcc.h"
+#include "exitcode.h"
+#include "netutil.h"
+#include "rpc.h"
+#include "trace.h"
+
+/*
+ * Provide a textual representation of a GSS-API or mechanism-specific
+ * status code and write this to the log file.
+ *
+ * @param status_code. Status code to convert.
+ *
+ * @param status_type. The type of the status code, either GSS_C_GSS_CODE
+ * for a GSS-API status code or GSS_C_MECH_CODE
+ * for a mechanism specific status code.
+ */
+void dcc_gssapi_status_to_log(OM_uint32 status_code, int status_type) {
+ gss_buffer_desc status_string = GSS_C_EMPTY_BUFFER;
+ OM_uint32 major_status, minor_status;
+ OM_uint32 message_ctx = 0;
+
+ do {
+ major_status = gss_display_status(&minor_status,
+ status_code,
+ status_type,
+ GSS_C_NULL_OID,
+ &message_ctx,
+ &status_string);
+
+ rs_log_info("%s: %s", (status_type == GSS_C_GSS_CODE) ? "GSSAPI" : "Mech" ,
+ (char *) status_string.value);
+ gss_release_buffer(&minor_status, &status_string);
+
+ } while (message_ctx != 0);
+}
+
+/*
+ * Perform a cleanup on specified GSS-API internal data formats.
+ *
+ * @param input_tok. The input token to release.
+ *
+ * @param output_tok. The output token to release.
+ *
+ * @param name. The name to release.
+ */
+void dcc_gssapi_cleanup(gss_buffer_desc *input_tok,
+ gss_buffer_desc *output_tok,
+ gss_name_t *name) {
+ OM_uint32 major_status, minor_status;
+
+ if (input_tok != NULL) {
+ if ((major_status = gss_release_buffer(&minor_status,
+ input_tok)) != GSS_S_COMPLETE) {
+ rs_log_error("Failed to release buffer.");
+ }
+ }
+
+ if (output_tok != NULL) {
+ if ((major_status = gss_release_buffer(&minor_status,
+ output_tok)) != GSS_S_COMPLETE) {
+ rs_log_error("Failed to release buffer.");
+ }
+ }
+
+ if (name != NULL) {
+ if ((major_status = gss_release_name(&minor_status,
+ name)) != GSS_S_COMPLETE) {
+ rs_log_error("Failed to release name.");
+ }
+ }
+}
+
+/*
+ * Perform a comparison of two sets of flags representing security
+ * services. At the moment we only check for mutual authentication,
+ * replay and out of sequence detection, but this function could be
+ * extended to include others.
+ *
+ * @param req_flags. The first set of flags to be compared and
+ * represents what is required by the client
+ * or server.
+ *
+ * @param ret_flags. The second set of flags to be compared and
+ * what is provided/returned by the peer.
+ *
+ * Returns 0 on success, otherwise error.
+ */
+int dcc_gssapi_compare_flags(OM_uint32 req_flags, OM_uint32 ret_flags) {
+ if (req_flags & GSS_C_MUTUAL_FLAG) {
+ if (ret_flags & GSS_C_MUTUAL_FLAG) {
+ rs_log_info("Mutual authentication requested and granted.");
+ } else {
+ rs_log_crit("Requested security services don't match those returned.");
+ return EXIT_GSSAPI_FAILED;
+ }
+ }
+
+ if (req_flags & GSS_C_REPLAY_FLAG) {
+ if (ret_flags & GSS_C_REPLAY_FLAG) {
+ rs_log_info("Replay detection requested and granted.");
+ } else {
+ rs_log_crit("Requested security services don't match those returned.");
+ return EXIT_GSSAPI_FAILED;
+ }
+ }
+
+ if (req_flags & GSS_C_SEQUENCE_FLAG) {
+ if (ret_flags & GSS_C_SEQUENCE_FLAG) {
+ rs_log_info("Out of sequence detection requested and granted.");
+ } else {
+ rs_log_crit("Requested security services don't match those returned.");
+ return EXIT_GSSAPI_FAILED;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Delete a specified secure context from the current process.
+ * The output buffer token is not used as we do not notify the
+ * peer.
+ *
+ * @param ctx_handle. The secure context to delete.
+ */
+void dcc_gssapi_delete_ctx(gss_ctx_id_t *ctx_handle) {
+ OM_uint32 major_status, minor_status;
+
+ if (ctx_handle != NULL) {
+ if (*ctx_handle != GSS_C_NO_CONTEXT) {
+ if ((major_status = gss_delete_sec_context(&minor_status,
+ ctx_handle,
+ GSS_C_NO_BUFFER)) != GSS_S_COMPLETE) {
+ rs_log_error("Failed to delete context.");
+ }
+ }
+ }
+}
+
+/*
+ * Send the specified token. First we transmit the token length,
+ * then the token itself.
+ *
+ * @param token. The token to be sent.
+ *
+ * Returns 0 on success, otherwise error.
+ */
+int send_token(int sd, gss_buffer_t token) {
+ int ret;
+
+ if ((ret = dcc_x_token_int(sd, "TLEN", token->length)) != 0) {
+ return ret;
+ }
+
+ if ((ret = dcc_writex(sd, token->value, token->length)) != 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * Receive a token. First we receive the token length,
+ * then the token itself.
+ *
+ * @param token. The token to be received.
+ *
+ * Returns 0 on success, otherwise error.
+ */
+int recv_token(int sd, gss_buffer_t token) {
+ int ret;
+ unsigned length;
+
+ if ((ret = dcc_r_token_int(sd, "TLEN", &length)) != 0) {
+ return ret;
+ }
+
+ if (length > INT_MAX || length == 0) {
+ rs_log_error("Malformed token length.");
+ return EXIT_IO_ERROR;
+ }
+
+ token->length = length;
+ token->value = malloc(length);
+
+ if (token->value == NULL && length != 0) {
+ rs_log_error("malloc failed : %lu bytes: out of memory.",
+ (unsigned long) length);
+ return EXIT_OUT_OF_MEMORY;
+ }
+
+ if ((ret = dcc_readx(sd, token->value, token->length)) != 0) {
+ return ret;
+ }
+
+ return 0;
+}