--- /dev/null
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This code was adapted from the MIT Kerberos Consortium's
+ * GSS example code, which was distributed under the following
+ * license:
+ *
+ * Copyright 2004-2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef GSSCON_H
+#define GSSCON_H
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h>
+#include <krb5.h>
+#include <errno.h>
+
+#define kDefaultPort 2000
+extern const char *gServiceName;
+
+int gsscon_read_token (int inSocket,
+ char **outTokenValue,
+ size_t *outTokenLength);
+
+int gsscon_write_token (int inSocket,
+ const char *inTokenValue,
+ size_t inTokenLength);
+
+int gsscon_read_encrypted_token (int inSocket,
+ const gss_ctx_id_t inContext,
+ char **outTokenValue,
+ size_t *outTokenLength);
+
+int gsscon_write_encrypted_token (int inSocket,
+ const gss_ctx_id_t inContext,
+ const char *inToken,
+ size_t inTokenLength);
+
+void gsscon_print_error (int inError,
+ const char *inString);
+
+void gsscon_print_gss_errors (const char *inRoutineName,
+ OM_uint32 inMajorStatus,
+ OM_uint32 inMinorStatus);
+
+int gsscon_connect (const char *inHost,
+ int inPort,
+ int *outFD);
+
+int gsscon_active_authenticate (int inSocket,
+ const char *inClientName,
+ const char *inServiceName,
+ gss_ctx_id_t *outGSSContext);
+
+int gsscon_passive_authenticate (int inSocket,
+ gss_ctx_id_t *outGSSContext);
+
+int gsscon_authorize (gss_ctx_id_t inContext,
+ int *outAuthorized,
+ int *outAuthorizationError);
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This code was adapted from the MIT Kerberos Consortium's
+ * GSS example code, which was distributed under the following
+ * license:
+ *
+ * Copyright 2004-2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "gsscon.h"
+
+/* --------------------------------------------------------------------------- */
+
+int gsscon_connect (const char *inHost, int inPort, int *outFD)
+{
+ int err = 0;
+ int fd = -1;
+ struct hostent *hp = NULL;
+ struct sockaddr_in saddr;
+
+ if (!err) {
+ hp = gethostbyname (inHost);
+ if (hp == NULL) { err = errno; }
+ }
+
+ if (!err) {
+ saddr.sin_family = hp->h_addrtype;
+ memcpy ((char *) &saddr.sin_addr, hp->h_addr, sizeof (saddr.sin_addr));
+ saddr.sin_port = htons(inPort);
+
+ fd = socket (AF_INET, SOCK_STREAM, 0);
+ if (fd < 0) { err = errno; }
+ }
+
+ if (!err) {
+ err = connect (fd, (struct sockaddr *) &saddr, sizeof (saddr));
+ if (err < 0) { err = errno; }
+ }
+
+ if (!err) {
+ printf ("connecting to host '%s' on port %d\n", inHost, inPort);
+ *outFD = fd;
+ fd = -1; /* takes ownership */
+ } else {
+ gsscon_print_error (err, "OpenConnection failed");
+ }
+
+ if (fd >= 0) { close (fd); }
+
+ return err;
+}
+
+/* --------------------------------------------------------------------------- */
+
+int gsscon_active_authenticate (int inSocket,
+ const char *inClientName,
+ const char *inServiceName,
+ gss_ctx_id_t *outGSSContext)
+{
+ int err = 0;
+ OM_uint32 majorStatus;
+ OM_uint32 minorStatus = 0;
+ gss_name_t serviceName = NULL;
+ gss_name_t clientName = NULL;
+ gss_cred_id_t clientCredentials = GSS_C_NO_CREDENTIAL;
+ gss_ctx_id_t gssContext = GSS_C_NO_CONTEXT;
+ OM_uint32 actualFlags = 0;
+
+ char *inputTokenBuffer = NULL;
+ size_t inputTokenBufferLength = 0;
+ gss_buffer_desc inputToken; /* buffer received from the server */
+ gss_buffer_t inputTokenPtr = GSS_C_NO_BUFFER;
+
+ if (inSocket < 0 ) { err = EINVAL; }
+ if (!inServiceName) { err = EINVAL; }
+ if (!outGSSContext) { err = EINVAL; }
+
+ /*
+ * Here is where the client picks the client principal it wants to use.
+ * If your application knows what the user's client principal should be,
+ * it should set that here. Otherwise leave clientCredentials set to NULL
+ * and Kerberos will attempt to use the client principal in the default
+ * ccache.
+ */
+
+ if (!err) {
+ if (inClientName != NULL) {
+ gss_buffer_desc nameBuffer = { strlen (inClientName), (char *) inClientName };
+
+ majorStatus = gss_import_name (&minorStatus, &nameBuffer, GSS_C_NT_USER_NAME, &clientName);
+ if (majorStatus != GSS_S_COMPLETE) {
+ gsscon_print_gss_errors ("gss_import_name(inClientName)", majorStatus, minorStatus);
+ err = minorStatus ? minorStatus : majorStatus;
+ }
+
+ if (!err) {
+ majorStatus = gss_acquire_cred (&minorStatus, clientName, GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
+ GSS_C_INITIATE, &clientCredentials, NULL, NULL);
+ if (majorStatus != GSS_S_COMPLETE) {
+ gsscon_print_gss_errors ("gss_acquire_cred", majorStatus, minorStatus);
+ err = minorStatus ? minorStatus : majorStatus;
+ }
+ }
+ }
+ }
+
+ /*
+ * Here is where the client picks the service principal it will try to use to
+ * connect to the server. In the case of the gssClientSample, the service
+ * principal is passed in on the command line, however, in a real world example,
+ * this would be unacceptable from a user interface standpoint since the user
+ * shouldn't need to know the server's service principal.
+ *
+ * In traditional Kerberos setups, the service principal would be constructed from
+ * the type of the service (eg: "imap"), the DNS hostname of the server
+ * (eg: "mailserver.domain.com") and the client's local realm (eg: "DOMAIN.COM")
+ * to form a full principal string (eg: "imap/mailserver.domain.com@DOMAIN.COM").
+ *
+ * Now that many sites do not have DNS, this setup is becoming less common.
+ * However you decide to generate the service principal, you need to adhere
+ * to the following constraint: The service principal must be constructed
+ * by the client, typed in by the user or administrator, or transmitted to
+ * the client in a secure manner from a trusted third party -- such as
+ * through an encrypted connection to a directory server. You should not
+ * have the server send the client the service principal name as part of
+ * the authentication negotiation.
+ *
+ * The reason you can't let the server tell the client which principal to
+ * use is that many machines at a site will have their own service principal
+ * and keytab which identifies the machine -- in a Windows Active Directory
+ * environment all machines have a service principal and keytab. Some of these
+ * machines (such as a financial services server) will be more trustworthy than
+ * others (such as a random machine on a coworker's desk). If the owner of
+ * one of these untrustworthy machines can trick the client into using the
+ * untrustworthy machine's principal instead of the financial services
+ * server's principal, then he can trick the client into authenticating
+ * and connecting to the untrustworthy machine. The untrustworthy machine can
+ * then harvest any confidential information the client sends to it, such as
+ * credit card information or social security numbers.
+ *
+ * If your protocol already involves sending the service principal as part of
+ * your authentication negotiation, your client should cache the name it gets
+ * after the first successful authentication so that the problem above can
+ * only happen on the first connection attempt -- similar to what ssh does with
+ * host keys.
+ */
+
+ if (!err) {
+ gss_buffer_desc nameBuffer = { strlen (inServiceName), (char *) inServiceName };
+
+ majorStatus = gss_import_name (&minorStatus, &nameBuffer, (gss_OID) GSS_KRB5_NT_PRINCIPAL_NAME, &serviceName);
+ if (majorStatus != GSS_S_COMPLETE) {
+ gsscon_print_gss_errors ("gss_import_name(inServiceName)", majorStatus, minorStatus);
+ err = minorStatus ? minorStatus : majorStatus;
+ }
+ }
+
+ /*
+ * The main authentication loop:
+ *
+ * GSS is a multimechanism API. Because the number of packet exchanges required to
+ * authenticate can vary between mechanisms, we need to loop calling
+ * gss_init_sec_context, passing the "input tokens" received from the server and
+ * send the resulting "output tokens" back until we get GSS_S_COMPLETE or an error.
+ */
+
+ majorStatus = GSS_S_CONTINUE_NEEDED;
+
+ gss_OID_desc EAP_OID = { 10, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x01\x11" };
+
+ while (!err && (majorStatus != GSS_S_COMPLETE)) {
+ gss_buffer_desc outputToken = { 0, NULL }; /* buffer to send to the server */
+ OM_uint32 requestedFlags = (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG |
+ GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG);
+
+ printf ("Calling gss_init_sec_context...\n");
+ majorStatus = gss_init_sec_context (&minorStatus,
+ clientCredentials,
+ &gssContext,
+ serviceName,
+ &EAP_OID /* mech_type */,
+ requestedFlags,
+ GSS_C_INDEFINITE,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ inputTokenPtr,
+ NULL /* actual_mech_type */,
+ &outputToken,
+ &actualFlags,
+ NULL /* time_rec */);
+
+ /* Send the output token to the server (even on error) */
+ if ((outputToken.length > 0) && (outputToken.value != NULL)) {
+ err = gsscon_write_token (inSocket, outputToken.value, outputToken.length);
+
+ /* free the output token */
+ gss_release_buffer (&minorStatus, &outputToken);
+ }
+
+ if (!err) {
+ if (majorStatus == GSS_S_CONTINUE_NEEDED) {
+ /* Protocol requires another packet exchange */
+
+ /* Clean up old input buffer */
+ if (inputTokenBuffer) {
+ free (inputTokenBuffer);
+ inputTokenBuffer = NULL; /* don't double-free */
+ }
+
+ /* Read another input token from the server */
+ err = gsscon_read_token (inSocket, &inputTokenBuffer, &inputTokenBufferLength);
+
+ if (!err) {
+ /* Set up input buffers for the next run through the loop */
+ inputToken.value = inputTokenBuffer;
+ inputToken.length = inputTokenBufferLength;
+ inputTokenPtr = &inputToken;
+ }
+ } else if (majorStatus != GSS_S_COMPLETE) {
+ gsscon_print_gss_errors ("gss_init_sec_context", majorStatus, minorStatus);
+ err = minorStatus ? minorStatus : majorStatus;
+ }
+ }
+ }
+
+ if (!err) {
+ *outGSSContext = gssContext;
+ gssContext = NULL;
+ } else {
+ gsscon_print_gss_error (err, "AuthenticateToServer failed");
+ }
+
+ if (inputTokenBuffer) { free (inputTokenBuffer); }
+ if (serviceName ) { gss_release_name (&minorStatus, &serviceName); }
+ if (clientName ) { gss_release_name (&minorStatus, &clientName); }
+
+ if (clientCredentials != GSS_C_NO_CREDENTIAL) {
+ gss_release_cred (&minorStatus, &clientCredentials); }
+ if (gssContext != GSS_C_NO_CONTEXT) {
+ gss_delete_sec_context (&minorStatus, &gssContext, GSS_C_NO_BUFFER); }
+
+ return err;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This code was adapted from the MIT Kerberos Consortium's
+ * GSS example code, which was distributed under the following
+ * license:
+ *
+ * Copyright 2004-2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "gsscon.h"
+
+/* --------------------------------------------------------------------------- */
+/* Display the contents of the buffer in hex and ascii */
+
+static void PrintBuffer (const char *inBuffer,
+ size_t inLength)
+{
+ int i;
+
+ for (i = 0; i < inLength; i += 16) {
+ int l;
+ for (l = i; l < (i + 16); l++) {
+ if (l >= inLength) {
+ printf (" ");
+ } else {
+ u_int8_t *byte = (u_int8_t *) inBuffer + l;
+ printf ("%2.2x", *byte);
+ }
+ if ((l % 4) == 3) { printf (" "); }
+ }
+ printf (" ");
+ for (l = i; l < (i + 16) && l < inLength; l++) {
+ printf ("%c", ((inBuffer[l] > 0x1f) &&
+ (inBuffer[l] < 0x7f)) ? inBuffer[l] : '.');
+ }
+ printf ("\n");
+ }
+ printf ("\n");
+}
+
+/* --------------------------------------------------------------------------- */
+/* Standard network read loop, accounting for EINTR, EOF and incomplete reads */
+
+static int ReadBuffer (int inSocket,
+ size_t inBufferLength,
+ char *ioBuffer)
+{
+ int err = 0;
+ ssize_t bytesRead = 0;
+
+ if (!ioBuffer) { err = EINVAL; }
+
+ if (!err) {
+ char *ptr = ioBuffer;
+ do {
+ ssize_t count = read (inSocket, ptr, inBufferLength - bytesRead);
+ if (count < 0) {
+ /* Try again on EINTR */
+ if (errno != EINTR) { err = errno; }
+ } else if (count == 0) {
+ err = ECONNRESET; /* EOF and we expected data */
+ } else {
+ ptr += count;
+ bytesRead += count;
+ }
+ } while (!err && (bytesRead < inBufferLength));
+ }
+
+ if (err) { gsscon_print_error (err, "ReadBuffer failed"); }
+
+ return err;
+}
+
+/* --------------------------------------------------------------------------- */
+/* Standard network write loop, accounting for EINTR and incomplete writes */
+
+static int WriteBuffer (int inSocket,
+ const char *inBuffer,
+ size_t inBufferLength)
+{
+ int err = 0;
+ ssize_t bytesWritten = 0;
+
+ if (!inBuffer) { err = EINVAL; }
+
+ if (!err) {
+ const char *ptr = inBuffer;
+ do {
+ ssize_t count = write (inSocket, ptr, inBufferLength - bytesWritten);
+ if (count < 0) {
+ /* Try again on EINTR */
+ if (errno != EINTR) { err = errno; }
+ } else {
+ ptr += count;
+ bytesWritten += count;
+ }
+ } while (!err && (bytesWritten < inBufferLength));
+ }
+
+ if (err) { gsscon_print_error (err, "WritBuffer failed"); }
+
+ return err;
+}
+
+/* --------------------------------------------------------------------------- */
+/* Read a GSS token (length + data) off the network */
+
+int gsscon_read_token (int inSocket,
+ char **outTokenValue,
+ size_t *outTokenLength)
+{
+ int err = 0;
+ char *token = NULL;
+ u_int32_t tokenLength = 0;
+
+ if (!outTokenValue ) { err = EINVAL; }
+ if (!outTokenLength) { err = EINVAL; }
+
+ if (!err) {
+ err = ReadBuffer (inSocket, 4, (char *) &tokenLength);
+ }
+
+ if (!err) {
+ tokenLength = ntohl (tokenLength);
+ token = malloc (tokenLength);
+ memset (token, 0, tokenLength);
+
+ err = ReadBuffer (inSocket, tokenLength, token);
+ }
+
+ if (!err) {
+ printf ("Read token:\n");
+ PrintBuffer (token, tokenLength);
+
+ *outTokenLength = tokenLength;
+ *outTokenValue = token;
+ token = NULL; /* only free on error */
+ } else {
+ gsscon_print_error (err, "ReadToken failed");
+ }
+
+ if (token) { free (token); }
+
+ return err;
+}
+
+/* --------------------------------------------------------------------------- */
+/* Write a GSS token (length + data) onto the network */
+
+int gsscon_write_token (int inSocket,
+ const char *inTokenValue,
+ size_t inTokenLength)
+{
+ int err = 0;
+ u_int32_t tokenLength = htonl (inTokenLength);
+
+ if (!inTokenValue) { err = EINVAL; }
+
+ if (!err) {
+ err = WriteBuffer (inSocket, (char *) &tokenLength, 4);
+ }
+
+ if (!err) {
+ err = WriteBuffer (inSocket, inTokenValue, inTokenLength);
+ }
+
+ if (!err) {
+ printf ("Wrote token:\n");
+ PrintBuffer (inTokenValue, inTokenLength);
+ } else {
+ gsscon_print_error (err, "gsscon_write_token() failed");
+ }
+
+ return err;
+}
+
+/* --------------------------------------------------------------------------- */
+/* Read an encrypted GSS token (length + encrypted data) off the network */
+
+
+int gsscon_read_encrypted_token (int inSocket,
+ const gss_ctx_id_t inContext,
+ char **outTokenValue,
+ size_t *outTokenLength)
+{
+ int err = 0;
+ char *token = NULL;
+ size_t tokenLength = 0;
+ OM_uint32 majorStatus;
+ OM_uint32 minorStatus = 0;
+ gss_buffer_desc outputBuffer = { 0 , NULL};
+ char *unencryptedToken = NULL;
+
+ if (!inContext ) { err = EINVAL; }
+ if (!outTokenValue ) { err = EINVAL; }
+ if (!outTokenLength) { err = EINVAL; }
+
+ if (!err) {
+ err = gsscon_read_token (inSocket, &token, &tokenLength);
+ }
+
+ if (!err) {
+ gss_buffer_desc inputBuffer = { tokenLength, token};
+ int encrypted = 0; /* did mechanism encrypt/integrity protect? */
+
+ majorStatus = gss_unwrap (&minorStatus,
+ inContext,
+ &inputBuffer,
+ &outputBuffer,
+ &encrypted,
+ NULL /* qop_state */);
+ if (majorStatus != GSS_S_COMPLETE) {
+ gsscon_print_gss_errors("gss_unwrap", majorStatus, minorStatus);
+ err = minorStatus ? minorStatus : majorStatus;
+ } else if (!encrypted) {
+ fprintf (stderr, "WARNING! Mechanism not using encryption!");
+ err = EINVAL; /* You may not want to fail here. */
+ }
+ }
+
+ if (!err) {
+ unencryptedToken = malloc (outputBuffer.length);
+ if (unencryptedToken == NULL) { err = ENOMEM; }
+ }
+
+ if (!err) {
+ memcpy (unencryptedToken, outputBuffer.value, outputBuffer.length);
+
+ printf ("Unencrypted token:\n");
+ PrintBuffer (unencryptedToken, outputBuffer.length);
+
+ *outTokenLength = outputBuffer.length;
+ *outTokenValue = unencryptedToken;
+ unencryptedToken = NULL; /* only free on error */
+
+ } else {
+ gsscon_print_error (err, "ReadToken failed");
+ }
+
+ if (token ) { free (token); }
+ if (outputBuffer.value) { gss_release_buffer (&minorStatus, &outputBuffer); }
+ if (unencryptedToken ) { free (unencryptedToken); }
+
+ return err;
+}
+
+/* --------------------------------------------------------------------------- */
+/* Write an encrypted GSS token (length + encrypted data) onto the network */
+
+int gsscon_write_encrypted_token (int inSocket,
+ const gss_ctx_id_t inContext,
+ const char *inToken,
+ size_t inTokenLength)
+{
+ int err = 0;
+ OM_uint32 majorStatus;
+ OM_uint32 minorStatus = 0;
+ gss_buffer_desc outputBuffer = { 0, NULL };
+
+ if (!inContext) { err = EINVAL; }
+ if (!inToken ) { err = EINVAL; }
+
+ if (!err) {
+ gss_buffer_desc inputBuffer = { inTokenLength, (char *) inToken };
+ int encrypt = 1; /* do encryption and integrity protection */
+ int encrypted = 0; /* did mechanism encrypt/integrity protect? */
+
+ majorStatus = gss_wrap (&minorStatus,
+ inContext,
+ encrypt,
+ GSS_C_QOP_DEFAULT,
+ &inputBuffer,
+ &encrypted,
+ &outputBuffer);
+ if (majorStatus != GSS_S_COMPLETE) {
+ gsscon_print_gss_errors ("gss_wrap", majorStatus, minorStatus);
+ err = minorStatus ? minorStatus : majorStatus;
+ } else if (!encrypted) {
+ fprintf (stderr, "WARNING! Mechanism does not support encryption!");
+ err = EINVAL; /* You may not want to fail here. */
+ }
+ }
+
+ if (!err) {
+ printf ("Unencrypted token:\n");
+ PrintBuffer (inToken, inTokenLength);
+ err = gsscon_write_token (inSocket, outputBuffer.value, outputBuffer.length);
+ }
+
+ if (!err) {
+ } else {
+ gsscon_print_error (err, "gsscon_write_token failed");
+ }
+
+ if (outputBuffer.value) { gss_release_buffer (&minorStatus, &outputBuffer); }
+
+ return err;
+}
+
+/* --------------------------------------------------------------------------- */
+/* Print BSD error */
+
+void gsscon_print_error (int inError,
+ const char *inString)
+{
+ fprintf (stderr, "%s: %s (err = %d)\n",
+ inString, error_message (inError), inError);
+}
+
+/* --------------------------------------------------------------------------- */
+/* PrintGSSAPI errors */
+
+void gsscon_print_gss_errors (const char *inRoutineName,
+ OM_uint32 inMajorStatus,
+ OM_uint32 inMinorStatus)
+{
+ OM_uint32 minorStatus;
+ OM_uint32 majorStatus;
+ gss_buffer_desc errorBuffer;
+
+ OM_uint32 messageContext = 0; /* first message */
+ int count = 1;
+
+ fprintf (stderr, "Error returned by %s:\n", inRoutineName);
+
+ do {
+ majorStatus = gss_display_status (&minorStatus,
+ inMajorStatus,
+ GSS_C_GSS_CODE,
+ GSS_C_NULL_OID,
+ &messageContext,
+ &errorBuffer);
+ if (majorStatus == GSS_S_COMPLETE) {
+ fprintf (stderr," major error <%d> %s\n",
+ count, (char *) errorBuffer.value);
+ gss_release_buffer (&minorStatus, &errorBuffer);
+ }
+ ++count;
+ } while (messageContext != 0);
+
+ count = 1;
+ messageContext = 0;
+ do {
+ majorStatus = gss_display_status (&minorStatus,
+ inMinorStatus,
+ GSS_C_MECH_CODE,
+ GSS_C_NULL_OID,
+ &messageContext,
+ &errorBuffer);
+ fprintf (stderr," minor error <%d> %s\n",
+ count, (char *) errorBuffer.value);
+ ++count;
+ } while (messageContext != 0);
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This code was adapted from the MIT Kerberos Consortium's
+ * GSS example code, which was distributed under the following
+ * license:
+ *
+ * Copyright 2004-2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "gsscon.h"
+
+const char *gServiceName = NULL;
+
+int gsscon_passive_authenticate (int inSocket,
+ gss_ctx_id_t *outGSSContext)
+{
+ int err = 0;
+ OM_uint32 majorStatus;
+ OM_uint32 minorStatus = 0;
+ gss_ctx_id_t gssContext = GSS_C_NO_CONTEXT;
+
+ char *inputTokenBuffer = NULL;
+ size_t inputTokenBufferLength = 0;
+ gss_buffer_desc inputToken; /* buffer received from the server */
+
+ if (inSocket < 0 ) { err = EINVAL; }
+ if (!outGSSContext) { err = EINVAL; }
+
+ /*
+ * The main authentication loop:
+ *
+ * GSS is a multimechanism API. The number of packet exchanges required to
+ * authenticatevaries between mechanisms. As a result, we need to loop reading
+ * input tokens from the client, calling gss_accept_sec_context on the input
+ * tokens and send the resulting output tokens back to the client until we
+ * get GSS_S_COMPLETE or an error.
+ *
+ * When we are done, save the client principal so we can make authorization
+ * checks.
+ */
+
+ majorStatus = GSS_S_CONTINUE_NEEDED;
+ while (!err && (majorStatus != GSS_S_COMPLETE)) {
+ /* Clean up old input buffer */
+ if (inputTokenBuffer != NULL) {
+ free (inputTokenBuffer);
+ inputTokenBuffer = NULL; /* don't double-free */
+ }
+
+ err = gsscon_read_token (inSocket, &inputTokenBuffer, &inputTokenBufferLength);
+
+ if (!err) {
+ /* Set up input buffers for the next run through the loop */
+ inputToken.value = inputTokenBuffer;
+ inputToken.length = inputTokenBufferLength;
+ }
+
+ if (!err) {
+ /* buffer to send to the server */
+ gss_buffer_desc outputToken = { 0, NULL };
+
+ /*
+ * accept_sec_context does the actual work of taking the client's
+ * request and generating an appropriate reply. Note that we pass
+ * GSS_C_NO_CREDENTIAL for the service principal. This causes the
+ * server to accept any service principal in the server's keytab,
+ * which enables you to support multihomed hosts by having one key
+ * in the keytab for each host identity the server responds on.
+ *
+ * However, since we may have more keys in the keytab than we want
+ * the server to actually use, we will need to check which service
+ * principal the client used after authentication succeeds. See
+ * ServicePrincipalIsValidForService() for where you would put these
+ * checks. We don't check here since if we stopped responding in the
+ * middle of the authentication negotiation, the client would get an
+ * EOF, and the user wouldn't know what went wrong.
+ */
+
+ printf ("Calling gss_accept_sec_context...\n");
+ majorStatus = gss_accept_sec_context (&minorStatus,
+ &gssContext,
+ GSS_C_NO_CREDENTIAL,
+ &inputToken,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ NULL /* client_name */,
+ NULL /* actual_mech_type */,
+ &outputToken,
+ NULL /* req_flags */,
+ NULL /* time_rec */,
+ NULL /* delegated_cred_handle */);
+
+ if ((outputToken.length > 0) && (outputToken.value != NULL)) {
+ /* Send the output token to the client (even on error) */
+ err = gsscon_write_token (inSocket, outputToken.value, outputToken.length);
+
+ /* free the output token */
+ gss_release_buffer (&minorStatus, &outputToken);
+ }
+ }
+
+ if ((majorStatus != GSS_S_COMPLETE) && (majorStatus != GSS_S_CONTINUE_NEEDED)) {
+ gsscon_print_gss_errors ("gss_accept_sec_context", majorStatus, minorStatus);
+ err = minorStatus ? minorStatus : majorStatus;
+ }
+ }
+
+ if (!err) {
+ *outGSSContext = gssContext;
+ gssContext = NULL;
+ } else {
+ gsscon_print_error (err, "Authenticate failed");
+ }
+
+ if (inputTokenBuffer) { free (inputTokenBuffer); }
+ if (gssContext != GSS_C_NO_CONTEXT) {
+ gss_delete_sec_context (&minorStatus, &gssContext, GSS_C_NO_BUFFER); }
+
+ return err;
+}
+
+/* --------------------------------------------------------------------------- */
+
+static int ServicePrincipalIsValidForService (const char *inServicePrincipal)
+{
+ int err = 0;
+ krb5_context context = NULL;
+ krb5_principal principal = NULL;
+
+ if (!inServicePrincipal) { err = EINVAL; }
+
+ if (!err) {
+ err = krb5_init_context (&context);
+ }
+
+ if (!err) {
+ err = krb5_parse_name (context, inServicePrincipal, &principal);
+ }
+
+ if (!err) {
+ /*
+ * Here is where we check to see if the service principal the client
+ * used is valid. Typically we would just check that the first component
+ * is the name of the service provided by the server. This check exists
+ * to make sure the server is using the correct key in its keytab since
+ * we passed GSS_C_NO_CREDENTIAL into gss_accept_sec_context().
+ */
+ if (gServiceName && strcmp (gServiceName,
+ krb5_princ_name (context, principal)->data) != 0) {
+ err = KRB5KRB_AP_WRONG_PRINC;
+ }
+ }
+
+ if (principal) { krb5_free_principal (context, principal); }
+ if (context ) { krb5_free_context (context); }
+
+ return err;
+}
+
+
+/* --------------------------------------------------------------------------- */
+
+static int ClientPrincipalIsAuthorizedForService (const char *inClientPrincipal)
+{
+ int err = 0;
+ krb5_context context = NULL;
+ krb5_principal principal = NULL;
+
+ if (!inClientPrincipal) { err = EINVAL; }
+
+ if (!err) {
+ err = krb5_init_context (&context);
+ }
+
+ if (!err) {
+ err = krb5_parse_name (context, inClientPrincipal, &principal);
+ }
+
+ if (!err) {
+ /*
+ * Here is where the server checks to see if the client principal should
+ * be allowed to use your service. Typically it should check both the name
+ * and the realm, since with cross-realm shared keys, a user at another
+ * realm may be trying to contact your service.
+ */
+ err = 0;
+ }
+
+ if (principal) { krb5_free_principal (context, principal); }
+ if (context ) { krb5_free_context (context); }
+
+ return err;
+}
+
+/* --------------------------------------------------------------------------- */
+
+int gsscon_authorize (gss_ctx_id_t inContext,
+ int *outAuthorized,
+ int *outAuthorizationError)
+{
+ int err = 0;
+ OM_uint32 majorStatus;
+ OM_uint32 minorStatus = 0;
+ gss_name_t clientName = NULL;
+ gss_name_t serviceName = NULL;
+ char *clientPrincipal = NULL;
+ char *servicePrincipal = NULL;
+
+ if (!inContext ) { err = EINVAL; }
+ if (!outAuthorized ) { err = EINVAL; }
+ if (!outAuthorizationError) { err = EINVAL; }
+
+ if (!err) {
+ /* Get the client and service principals used to authenticate */
+ majorStatus = gss_inquire_context (&minorStatus,
+ inContext,
+ &clientName,
+ &serviceName,
+ NULL, NULL, NULL, NULL, NULL);
+ if (majorStatus != GSS_S_COMPLETE) {
+ err = minorStatus ? minorStatus : majorStatus;
+ }
+ }
+
+ if (!err) {
+ /* Pull the client principal string out of the gss name */
+ gss_buffer_desc nameToken;
+
+ majorStatus = gss_display_name (&minorStatus,
+ clientName,
+ &nameToken,
+ NULL);
+ if (majorStatus != GSS_S_COMPLETE) {
+ err = minorStatus ? minorStatus : majorStatus;
+ }
+
+ if (!err) {
+ clientPrincipal = malloc (nameToken.length + 1);
+ if (clientPrincipal == NULL) { err = ENOMEM; }
+ }
+
+ if (!err) {
+ memcpy (clientPrincipal, nameToken.value, nameToken.length);
+ clientPrincipal[nameToken.length] = '\0';
+ }
+
+ if (nameToken.value) { gss_release_buffer (&minorStatus, &nameToken); }
+ }
+
+ if (!err) {
+ /* Pull the service principal string out of the gss name */
+ gss_buffer_desc nameToken;
+
+ majorStatus = gss_display_name (&minorStatus,
+ serviceName,
+ &nameToken,
+ NULL);
+ if (majorStatus != GSS_S_COMPLETE) {
+ err = minorStatus ? minorStatus : majorStatus;
+ }
+
+ if (!err) {
+ servicePrincipal = malloc (nameToken.length + 1);
+ if (servicePrincipal == NULL) { err = ENOMEM; }
+ }
+
+ if (!err) {
+ memcpy (servicePrincipal, nameToken.value, nameToken.length);
+ servicePrincipal[nameToken.length] = '\0';
+ }
+
+ if (nameToken.value) { gss_release_buffer (&minorStatus, &nameToken); }
+ }
+
+ if (!err) {
+ int authorizationErr = ServicePrincipalIsValidForService (servicePrincipal);
+
+ if (!authorizationErr) {
+ authorizationErr = ClientPrincipalIsAuthorizedForService (clientPrincipal);
+ }
+
+ printf ("'%s' is%s authorized for service '%s'\n",
+ clientPrincipal, authorizationErr ? " NOT" : "", servicePrincipal);
+
+ *outAuthorized = !authorizationErr;
+ *outAuthorizationError = authorizationErr;
+ }
+
+ if (serviceName ) { gss_release_name (&minorStatus, &serviceName); }
+ if (clientName ) { gss_release_name (&minorStatus, &clientName); }
+ if (clientPrincipal ) { free (clientPrincipal); }
+ if (servicePrincipal) { free (servicePrincipal); }
+
+ return err;
+}
+
+
--- /dev/null
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This code was adapted from the MIT Kerberos Consortium's
+ * GSS example code, which was distributed under the following
+ * license:
+ *
+ * Copyright 2004-2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "../gsscon.h"
+
+static void Usage (const char *argv[])
+{
+ fprintf (stderr, "Usage: %s [--port portNumber] [--server serverHostName]\n"
+ "\t[--sprinc servicePrincipal] [--cprinc clientPrincipal]\n", argv[0]);
+ exit (1);
+}
+
+/* --------------------------------------------------------------------------- */
+
+int main (int argc, const char *argv[])
+{
+ int err = 0;
+ int fd = -1;
+ int port = kDefaultPort;
+ const char *server = "127.0.0.1";
+ const char *clientName = NULL;
+ const char *serviceName = "host";
+ gss_ctx_id_t gssContext = GSS_C_NO_CONTEXT;
+ OM_uint32 minorStatus = 0;
+ int i = 0;
+
+ for (i = 1; (i < argc) && !err; i++) {
+ if ((strcmp (argv[i], "--port") == 0) && (i < (argc - 1))) {
+ port = strtol (argv[++i], NULL, 0);
+ if (port == 0) { err = errno; }
+ } else if ((strcmp (argv[i], "--server") == 0) && (i < (argc - 1))) {
+ server = argv[++i];
+ } else if ((strcmp(argv[i], "--cprinc") == 0) && (i < (argc - 1))) {
+ clientName = argv[++i];
+ } else if ((strcmp(argv[i], "--sprinc") == 0) && (i < (argc - 1))) {
+ serviceName = argv[++i];
+ } else {
+ err = EINVAL;
+ }
+ }
+
+ if (!err) {
+ printf ("%s: Starting up...\n", argv[0]);
+
+ err = gsscon_connect (server, port, &fd);
+ }
+
+ if (!err) {
+ err = gsscon_active_authenticate (fd, clientName, serviceName, &gssContext);
+ }
+
+ if (!err) {
+ char *buffer = NULL;
+ size_t bufferLength = 0;
+
+ /*
+ * Here is where your protocol would go. This sample client just
+ * reads a nul terminated string from the server.
+ */
+ err = gsscon_read_encrypted_token (fd, gssContext, &buffer, &bufferLength);
+
+ if (!err) {
+ printf ("Server message: '%s'\n", buffer);
+ }
+
+ if (buffer != NULL) { free (buffer); }
+ }
+
+
+ if (err) {
+ if (err == EINVAL) {
+ Usage (argv);
+ } else {
+ gsscon_print_error (err, "Client failed");
+ }
+ }
+
+ if (fd >= 0) { printf ("Closing socket.\n"); close (fd); }
+ if (gssContext != GSS_C_NO_CONTEXT) {
+ gss_delete_sec_context (&minorStatus, &gssContext, GSS_C_NO_BUFFER); }
+
+ return err ? 1 : 0;
+}
+
+
+
--- /dev/null
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This code was adapted from the MIT Kerberos Consortium's
+ * GSS example code, which was distributed under the following
+ * license:
+ *
+ * Copyright 2004-2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "../gsscon.h"
+
+static void Usage (const char *argv[])
+{
+ fprintf (stderr, "Usage: %s [--port portNumber] [--server serverHostName]\n"
+ "\t[--sprinc servicePrincipal] [--cprinc clientPrincipal]\n", argv[0]);
+ exit (1);
+}
+
+/* --------------------------------------------------------------------------- */
+
+int main (int argc, const char *argv[])
+{
+ int err = 0;
+ int fd = -1;
+ int port = kDefaultPort;
+ const char *server = "127.0.0.1";
+ const char *clientName = NULL;
+ const char *serviceName = "host";
+ gss_ctx_id_t gssContext = GSS_C_NO_CONTEXT;
+ OM_uint32 minorStatus = 0;
+ int i = 0;
+
+ for (i = 1; (i < argc) && !err; i++) {
+ if ((strcmp (argv[i], "--port") == 0) && (i < (argc - 1))) {
+ port = strtol (argv[++i], NULL, 0);
+ if (port == 0) { err = errno; }
+ } else if ((strcmp (argv[i], "--server") == 0) && (i < (argc - 1))) {
+ server = argv[++i];
+ } else if ((strcmp(argv[i], "--cprinc") == 0) && (i < (argc - 1))) {
+ clientName = argv[++i];
+ } else if ((strcmp(argv[i], "--sprinc") == 0) && (i < (argc - 1))) {
+ serviceName = argv[++i];
+ } else {
+ err = EINVAL;
+ }
+ }
+
+ if (!err) {
+ printf ("%s: Starting up...\n", argv[0]);
+
+ err = gsscon_connect (server, port, &fd);
+ }
+
+ if (!err) {
+ err = gsscon_active_authenticate (fd, clientName, serviceName, &gssContext);
+ }
+
+ if (!err) {
+ char *buffer = NULL;
+ size_t bufferLength = 0;
+
+ /*
+ * Here is where your protocol would go. This sample client just
+ * reads a nul terminated string from the server.
+ */
+ err = gsscon_read_encrypted_token (fd, gssContext, &buffer, &bufferLength);
+
+ if (!err) {
+ printf ("Server message: '%s'\n", buffer);
+ }
+
+ if (buffer != NULL) { free (buffer); }
+ }
+
+
+ if (err) {
+ if (err == EINVAL) {
+ Usage (argv);
+ } else {
+ printError (err, "Client failed");
+ }
+ }
+
+ if (fd >= 0) { printf ("Closing socket.\n"); close (fd); }
+ if (gssContext != GSS_C_NO_CONTEXT) {
+ gss_delete_sec_context (&minorStatus, &gssContext, GSS_C_NO_BUFFER); }
+
+ return err ? 1 : 0;
+}
+
+
+
--- /dev/null
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This code was adapted from the MIT Kerberos Consortium's
+ * GSS example code, which was distributed under the following
+ * license:
+ *
+ * Copyright 2004-2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "../gsscon.h"
+
+/* --------------------------------------------------------------------------- */
+
+static int SetupListeningSocket (int inPort,
+ int *outFD)
+{
+ int err = 0;
+ int fd = -1;
+
+ if (!outFD) { err = EINVAL; }
+
+ if (!err) {
+ fd = socket (AF_INET, SOCK_STREAM, 0);
+ if (fd < 0) { err = errno; }
+ }
+
+ if (!err) {
+ struct sockaddr_storage addressStorage;
+ struct sockaddr_in *saddr = (struct sockaddr_in *) &addressStorage;
+
+ saddr->sin_port = htons (inPort);
+ // saddr->sin_len = sizeof (struct sockaddr_in);
+ saddr->sin_family = AF_INET;
+ saddr->sin_addr.s_addr = INADDR_ANY;
+
+ err = bind (fd, (struct sockaddr *) saddr, sizeof(struct sockaddr_in));
+ if (err < 0) { err = errno; }
+ }
+
+ if (!err) {
+ err = listen (fd, 5);
+ if (err < 0) { err = errno; }
+ }
+
+ if (!err) {
+ printf ("listening on port %d\n", inPort);
+ *outFD = fd;
+ fd = -1; /* only close on error */
+ } else {
+ gsscon_print_error (err, "SetupListeningSocket failed");
+ }
+
+ if (fd >= 0) { close (fd); }
+
+ return err;
+}
+
+/* --------------------------------------------------------------------------- */
+
+static void Usage (const char *argv[])
+{
+ fprintf (stderr, "Usage: %s [--port portNumber] [--service serviceName]\n",
+ argv[0]);
+ exit (1);
+}
+
+/* --------------------------------------------------------------------------- */
+
+int main (int argc, const char *argv[])
+{
+ int err = 0;
+ OM_uint32 minorStatus;
+ int port = kDefaultPort;
+ int listenFD = -1;
+ gss_ctx_id_t gssContext = GSS_C_NO_CONTEXT;
+ int i = 0;
+
+ for (i = 1; (i < argc) && !err; i++) {
+ if ((strcmp (argv[i], "--port") == 0) && (i < (argc - 1))) {
+ port = strtol (argv[++i], NULL, 0);
+ if (port == 0) { err = errno; }
+ } else if ((strcmp(argv[i], "--service") == 0) && (i < (argc - 1))) {
+ gServiceName = argv[++i];
+ } else {
+ err = EINVAL;
+ }
+ }
+
+ if (!err) {
+ printf ("%s: Starting up...\n", argv[0]);
+
+ err = SetupListeningSocket (port, &listenFD);
+ }
+
+ while (!err) {
+ int connectionErr = 0;
+ int connectionFD = -1;
+ int authorized = 0;
+ int authorizationError = 0;
+
+ connectionFD = accept (listenFD, NULL, NULL);
+ if (connectionFD < 0) {
+ if (errno != EINTR) {
+ err = errno;
+ }
+ continue; /* Try again */
+ }
+
+ printf ("Accepting new connection...\n");
+ connectionErr = gsscon_passive_authenticate (connectionFD, &gssContext);
+
+ if (!connectionErr) {
+ connectionErr = gsscon_authorize (gssContext,
+ &authorized,
+ &authorizationError);
+ }
+
+ if (!connectionErr) {
+ char buffer[1024];
+ memset (buffer, 0, sizeof (buffer));
+
+ /*
+ * Here is where your protocol would go. This sample server just
+ * writes a nul terminated string to the client telling whether
+ * it was authorized.
+ */
+ if (authorized) {
+ snprintf (buffer, sizeof (buffer), "SUCCESS!");
+ } else {
+ snprintf (buffer, sizeof(buffer), "FAILURE! %s (err = %d)",
+ error_message (authorizationError),
+ authorizationError);
+ }
+ connectionErr = gsscon_write_encrypted_token (connectionFD, gssContext,
+ buffer, strlen (buffer) + 1);
+ }
+
+ if (connectionErr) {
+ gsscon_print_error (connectionErr, "Connection failed");
+ }
+
+ if (connectionFD >= 0) {
+ printf ("Closing connection.\n");
+ close (connectionFD);
+ }
+ }
+
+ if (err) {
+ if (err == EINVAL) {
+ Usage (argv);
+ } else {
+ gsscon_print_error (err, "Server failed");
+ }
+ }
+
+ if (listenFD >= 0) { close (listenFD); }
+ if (gssContext != GSS_C_NO_CONTEXT) {
+ gss_delete_sec_context (&minorStatus, &gssContext, GSS_C_NO_BUFFER); }
+
+ return err ? -1 : 0;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This code was adapted from the MIT Kerberos Consortium's
+ * GSS example code, which was distributed under the following
+ * license:
+ *
+ * Copyright 2004-2006 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "../gsscon.h"
+
+/* --------------------------------------------------------------------------- */
+
+static int SetupListeningSocket (int inPort,
+ int *outFD)
+{
+ int err = 0;
+ int fd = -1;
+
+ if (!outFD) { err = EINVAL; }
+
+ if (!err) {
+ fd = socket (AF_INET, SOCK_STREAM, 0);
+ if (fd < 0) { err = errno; }
+ }
+
+ if (!err) {
+ struct sockaddr_storage addressStorage;
+ struct sockaddr_in *saddr = (struct sockaddr_in *) &addressStorage;
+
+ saddr->sin_port = htons (inPort);
+ // saddr->sin_len = sizeof (struct sockaddr_in);
+ saddr->sin_family = AF_INET;
+ saddr->sin_addr.s_addr = INADDR_ANY;
+
+ err = bind (fd, (struct sockaddr *) saddr, sizeof(struct sockaddr_in));
+ if (err < 0) { err = errno; }
+ }
+
+ if (!err) {
+ err = listen (fd, 5);
+ if (err < 0) { err = errno; }
+ }
+
+ if (!err) {
+ printf ("listening on port %d\n", inPort);
+ *outFD = fd;
+ fd = -1; /* only close on error */
+ } else {
+ printError (err, "SetupListeningSocket failed");
+ }
+
+ if (fd >= 0) { close (fd); }
+
+ return err;
+}
+
+/* --------------------------------------------------------------------------- */
+
+static void Usage (const char *argv[])
+{
+ fprintf (stderr, "Usage: %s [--port portNumber] [--service serviceName]\n",
+ argv[0]);
+ exit (1);
+}
+
+/* --------------------------------------------------------------------------- */
+
+int main (int argc, const char *argv[])
+{
+ int err = 0;
+ OM_uint32 minorStatus;
+ int port = kDefaultPort;
+ int listenFD = -1;
+ gss_ctx_id_t gssContext = GSS_C_NO_CONTEXT;
+ int i = 0;
+
+ for (i = 1; (i < argc) && !err; i++) {
+ if ((strcmp (argv[i], "--port") == 0) && (i < (argc - 1))) {
+ port = strtol (argv[++i], NULL, 0);
+ if (port == 0) { err = errno; }
+ } else if ((strcmp(argv[i], "--service") == 0) && (i < (argc - 1))) {
+ gServiceName = argv[++i];
+ } else {
+ err = EINVAL;
+ }
+ }
+
+ if (!err) {
+ printf ("%s: Starting up...\n", argv[0]);
+
+ err = SetupListeningSocket (port, &listenFD);
+ }
+
+ while (!err) {
+ int connectionErr = 0;
+ int connectionFD = -1;
+ int authorized = 0;
+ int authorizationError = 0;
+
+ connectionFD = accept (listenFD, NULL, NULL);
+ if (connectionFD < 0) {
+ if (errno != EINTR) {
+ err = errno;
+ }
+ continue; /* Try again */
+ }
+
+ printf ("Accepting new connection...\n");
+ connectionErr = gsscon_passive_authenticate (connectionFD, &gssContext);
+
+ if (!connectionErr) {
+ connectionErr = gsscon_authorize (gssContext,
+ &authorized,
+ &authorizationError);
+ }
+
+ if (!connectionErr) {
+ char buffer[1024];
+ memset (buffer, 0, sizeof (buffer));
+
+ /*
+ * Here is where your protocol would go. This sample server just
+ * writes a nul terminated string to the client telling whether
+ * it was authorized.
+ */
+ if (authorized) {
+ snprintf (buffer, sizeof (buffer), "SUCCESS!");
+ } else {
+ snprintf (buffer, sizeof(buffer), "FAILURE! %s (err = %d)",
+ error_message (authorizationError),
+ authorizationError);
+ }
+ connectionErr = gsscon_write_encrypted_token (connectionFD, gssContext,
+ buffer, strlen (buffer) + 1);
+ }
+
+ if (connectionErr) {
+ printError (connectionErr, "Connection failed");
+ }
+
+ if (connectionFD >= 0) {
+ printf ("Closing connection.\n");
+ close (connectionFD);
+ }
+ }
+
+ if (err) {
+ if (err == EINVAL) {
+ Usage (argv);
+ } else {
+ printError (err, "Server failed");
+ }
+ }
+
+ if (listenFD >= 0) { close (listenFD); }
+ if (gssContext != GSS_C_NO_CONTEXT) {
+ gss_delete_sec_context (&minorStatus, &gssContext, GSS_C_NO_BUFFER); }
+
+ return err ? -1 : 0;
+}
+