+++ /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
-
-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);
-
-void gsscon_connect (const char *inHost,
- int inPort,
- int *outFD);
-
-void 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"
-
-/* --------------------------------------------------------------------------- */
-
-static 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 {
- printError (err, "OpenConnection failed");
- }
-
- if (fd >= 0) { close (fd); }
-
- return err;
-}
-
-/* --------------------------------------------------------------------------- */
-
-static 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) {
- printGSSErrors ("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) {
- printGSSErrors ("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) {
- printGSSErrors ("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 = WriteToken (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 = ReadToken (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) {
- printGSSErrors ("gss_init_sec_context", majorStatus, minorStatus);
- err = minorStatus ? minorStatus : majorStatus;
- }
- }
- }
-
- if (!err) {
- *outGSSContext = gssContext;
- gssContext = NULL;
- } else {
- printError (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) { printError (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) { printError (err, "WriteBuffer 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 {
- printError (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 {
- printError (err, "WriteToken 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 = ReadToken (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) {
- printGSSErrors ("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 {
- printError (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) {
- printGSSErrors ("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 = WriteToken (inSocket, outputBuffer.value, outputBuffer.length);
- }
-
- if (!err) {
- } else {
- printError (err, "WriteToken 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);
-}
-
-/* --------------------------------------------------------------------------- */
-/* Print GSSAPI 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 = ReadToken (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 = WriteToken (inSocket, outputToken.value, outputToken.length);
-
- /* free the output token */
- gss_release_buffer (&minorStatus, &outputToken);
- }
- }
-
- if ((majorStatus != GSS_S_COMPLETE) && (majorStatus != GSS_S_CONTINUE_NEEDED)) {
- printGSSErrors ("gss_accept_sec_context", majorStatus, minorStatus);
- err = minorStatus ? minorStatus : majorStatus;
- }
- }
-
- if (!err) {
- *outGSSContext = gssContext;
- gssContext = NULL;
- } else {
- printError (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;
-}
-
-