Moved gsscon.h include file to a newly created trust_router/include directory.
authorMargaret Wasserman <mrw@painless-security.com>
Wed, 21 Nov 2012 11:59:23 +0000 (06:59 -0500)
committerMargaret Wasserman <mrw@painless-security.com>
Wed, 21 Nov 2012 11:59:23 +0000 (06:59 -0500)
12 files changed:
gsscon/.#gsscon_test.c [new symlink]
gsscon/gsscon.h~ [moved from gsscon/test/gsscon_client.c~ with 53% similarity, mode: 0755]
gsscon/gsscon_active.c
gsscon/gsscon_active.c~ [new file with mode: 0755]
gsscon/gsscon_common.c
gsscon/gsscon_common.c~ [new file with mode: 0755]
gsscon/gsscon_passive.c
gsscon/gsscon_passive.c~ [new file with mode: 0755]
gsscon/test/gsscon_client.c
gsscon/test/gsscon_server.c
gsscon/test/gsscon_server.c~ [deleted file]
include/gsscon.h [moved from gsscon/gsscon.h with 100% similarity]

diff --git a/gsscon/.#gsscon_test.c b/gsscon/.#gsscon_test.c
new file mode 120000 (symlink)
index 0000000..f036edb
--- /dev/null
@@ -0,0 +1 @@
+mrw@lilac-moonshot.suchdamage.org.13738:1346036289
\ No newline at end of file
old mode 100644 (file)
new mode 100755 (executable)
similarity index 53%
rename from gsscon/test/gsscon_client.c~
rename to gsscon/gsscon.h~
index f309a98..3fc0bde
  * or implied warranty.
  */
 
-#include "../gsscon.h"
+#ifndef GSSCON_H
+#define 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);
-}
+#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>
 
-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;
+#define kDefaultPort 2000
 
-        /* 
-         * 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);
+int gsscon_read_token (int      inSocket, 
+               char   **outTokenValue, 
+               size_t  *outTokenLength);
 
-        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;
-}
+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
index d933944..a71f1f4 100755 (executable)
@@ -52,7 +52,7 @@
  * or implied warranty.
  */
 
-#include "gsscon.h"
+#include <gsscon.h>
 
 /* --------------------------------------------------------------------------- */
 
diff --git a/gsscon/gsscon_active.c~ b/gsscon/gsscon_active.c~
new file mode 100755 (executable)
index 0000000..bd8e315
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * 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;
+}
+
index 325b98b..d067979 100755 (executable)
@@ -52,7 +52,7 @@
  * or implied warranty.
  */
 
-#include "gsscon.h"
+#include <gsscon.h>
 
 /* --------------------------------------------------------------------------- */
 /* Display the contents of the buffer in hex and ascii                         */
diff --git a/gsscon/gsscon_common.c~ b/gsscon/gsscon_common.c~
new file mode 100755 (executable)
index 0000000..5f65826
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ * 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);
+}
+
index 68f188a..5fc7030 100755 (executable)
@@ -52,7 +52,7 @@
  * or implied warranty.
  */
 
-#include "gsscon.h"
+#include <gsscon.h>
 
 const char *gServiceName = NULL;
 
diff --git a/gsscon/gsscon_passive.c~ b/gsscon/gsscon_passive.c~
new file mode 100755 (executable)
index 0000000..7b3f661
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * 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; 
+}
+
+
index 73c7858..9e3cca2 100644 (file)
@@ -52,7 +52,7 @@
  * or implied warranty.
  */
 
-#include "../gsscon.h"
+#include <gsscon.h>
 
 static void Usage (const char *argv[])
 {
index 999d0cd..c4170c0 100644 (file)
@@ -52,7 +52,7 @@
  * or implied warranty.
  */
 
-#include "../gsscon.h"
+#include <gsscon.h>
 
 /* --------------------------------------------------------------------------- */
 
diff --git a/gsscon/test/gsscon_server.c~ b/gsscon/test/gsscon_server.c~
deleted file mode 100644 (file)
index a7d25a9..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * 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;
-}
-
similarity index 100%
rename from gsscon/gsscon.h
rename to include/gsscon.h