#include <sys/types.h>
#include <sys/uio.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <Kerberos/Kerberos.h>
#include "test-gss-common.h"
static int 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;
} else {
printError (err, "OpenConnection failed");
}
if (fd >= 0) { close (fd); }
return err;
}
static int Authenticate (int inSocket, const char *inClientName, const char *inServiceName, gss_ctx_id_t *outContext)
{
int err = 0;
OM_uint32 majorStatus;
OM_uint32 minorStatus = 0;
gss_name_t serverName;
gss_name_t clientName;
gss_cred_id_t clientCredentials = GSS_C_NO_CREDENTIAL;
gss_ctx_id_t context = GSS_C_NO_CONTEXT;
OM_uint32 actualFlags = 0;
char *inputTokenBuffer = NULL;
size_t inputTokenBufferLength = 0;
gss_buffer_desc inputToken;
gss_buffer_t inputTokenPtr = GSS_C_NO_BUFFER;
if (inSocket < 0) { err = EINVAL; }
gss_OID_set *mech_set = malloc(sizeof(gss_OID_set));
*mech_set = GSS_C_NO_OID_SET;
majorStatus = gss_indicate_mechs(&minorStatus, mech_set);
if (majorStatus != GSS_S_COMPLETE) {
printGSSErrors ("gss_indicate_mechs(mec_set)", majorStatus, minorStatus);
err = minorStatus ? minorStatus : majorStatus;
}
majorStatus = gss_release_oid_set(&minorStatus, mech_set);
if (majorStatus != GSS_S_COMPLETE) {
printGSSErrors ("gss_release_oid_set(mec_set)", majorStatus, minorStatus);
err = minorStatus ? minorStatus : majorStatus;
}
majorStatus = gss_krb5_ccache_name(&minorStatus, inClientName, NULL);
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;
}
}
}
}
{
OM_uint32 lt;
int cu;
gss_name_t name;
gss_OID_set *mech_set = malloc(sizeof(gss_OID_set));
*mech_set = GSS_C_NO_OID_SET;
majorStatus = gss_inquire_cred(&minorStatus, clientCredentials, &name, <, &cu, mech_set);
if (majorStatus != GSS_S_COMPLETE) {
printGSSErrors ("gss_release_oid_set(mec_set)", majorStatus, minorStatus);
err = minorStatus ? minorStatus : majorStatus;
}
majorStatus = gss_release_oid_set(&minorStatus, mech_set);
if (majorStatus != GSS_S_COMPLETE) {
printGSSErrors ("gss_release_oid_set(mec_set)", majorStatus, minorStatus);
err = minorStatus ? minorStatus : majorStatus;
}
}
if (!err) {
gss_buffer_desc nameBuffer = { strlen (inServiceName), (char *) inServiceName };
majorStatus = gss_import_name (&minorStatus, &nameBuffer, (gss_OID) GSS_KRB5_NT_PRINCIPAL_NAME, &serverName);
if (majorStatus != GSS_S_COMPLETE) {
printGSSErrors ("gss_import_name(inServiceName)", majorStatus, minorStatus);
err = minorStatus ? minorStatus : majorStatus;
}
}
majorStatus = GSS_S_CONTINUE_NEEDED;
while (!err && (majorStatus != GSS_S_COMPLETE)) {
gss_buffer_desc outputToken = { 0, NULL };
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, &context, serverName,
GSS_C_NULL_OID , requestedFlags, GSS_C_INDEFINITE,
GSS_C_NO_CHANNEL_BINDINGS, inputTokenPtr,
NULL , &outputToken,
&actualFlags, NULL );
if ((outputToken.length > 0) && (outputToken.value != NULL)) {
err = WriteToken (inSocket, outputToken.value, outputToken.length);
gss_release_buffer (&minorStatus, &outputToken);
}
if (!err) {
if (majorStatus == GSS_S_CONTINUE_NEEDED) {
if (inputTokenBuffer != NULL) {
free (inputTokenBuffer);
inputTokenBuffer = NULL;
}
err = ReadToken (inSocket, &inputTokenBuffer, &inputTokenBufferLength);
if (!err) {
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;
exit(err);
}
}
}
int ret;
majorStatus = gss_compare_name(&minorStatus, clientName, serverName, &ret);
if (!err) {
*outContext = context;
} else {
printError (err, "AuthenticateToServer failed");
}
if (serverName != NULL) { gss_release_name (&minorStatus, &serverName); }
if (inputTokenBuffer != NULL) { free (inputTokenBuffer); }
return err;
}
static void Usage (const char *argv[])
{
fprintf (stderr, "Usage: %s [--port portNumber] [--server serverHostName]\n"
"\t[--sprinc servicePrincipal] [--cprinc clientPrincipal]\n", argv[0]);
exit (1);
}
int main (int argc, const char *argv[])
{
int err = 0;
int fd = -1;
int port = kDefaultPort;
const char *server = "127.0.0.1";
const char *clientName = NULL;
const char *serviceName = "host";
gss_ctx_id_t context = GSS_C_NO_CONTEXT;
unsigned int i = 0;
gss_buffer_desc buffer;
gss_oid_to_str(&i, GSS_C_NT_EXPORT_NAME, &buffer);
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 = Connect (server, port, &fd);
}
if (!err) {
err = Authenticate (fd, clientName, serviceName, &context);
}
if (!err) {
char *buffer = NULL;
size_t bufferLength = 0;
err = ReadEncryptedToken (fd, context, &buffer, &bufferLength);
if (!err) {
printf ("Server message: '%s'\n", buffer);
}
if (buffer != NULL) { free (buffer); }
}
if (err) {
if (err == EINVAL) {
Usage (argv);
} else {
printError (err, "Client failed");
}
}
{
OM_uint32 majorStatus, minorStatus;
gss_ctx_id_t back;
gss_cred_id_t *cid;
majorStatus = gss_export_sec_context(&minorStatus, &context, &buffer);
majorStatus = gss_import_sec_context(&minorStatus, &buffer, &back);
cid = malloc(sizeof(gss_cred_id_t));
*cid = GSS_C_NO_CREDENTIAL;
majorStatus = gss_release_cred(&minorStatus, cid);
}
if (fd >= 0) { printf ("Closing socket.\n"); close (fd); }
return err ? 1 : 0;
}