gssapi.c   gssapi.c 
/* GSSAPI SASL plugin /* GSSAPI SASL plugin
* Leif Johansson * Leif Johansson
* Rob Siemborski (SASL v2 Conversion) * Rob Siemborski (SASL v2 Conversion)
* $Id: gssapi.c,v 1.92 2004/07/21 14:39:06 rjs3 Exp $ * $Id: gssapi.c,v 1.112 2011/04/19 09:19:18 mel Exp $
*/ */
/* /*
* Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved . * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved .
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
* are met: * are met:
* *
* 1. Redistributions of source code must retain the above copyright * 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
skipping to change at line 85 skipping to change at line 85
#include "plugin_common.h" #include "plugin_common.h"
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
#include <unistd.h> #include <unistd.h>
#endif #endif
#include <errno.h> #include <errno.h>
/***************************** Common Section *************************** **/ /***************************** Common Section *************************** **/
static const char plugin_id[] = "$Id: gssapi.c,v 1.92 2004/07/21 14:39:06 r js3 Exp $"; static const char plugin_id[] = "$Id: gssapi.c,v 1.112 2011/04/19 09:19:18 mel Exp $";
static const char * GSSAPI_BLANK_STRING = ""; static const char * GSSAPI_BLANK_STRING = "";
#ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE #if !defined(HAVE_GSS_C_NT_HOSTBASED_SERVICE) && !defined(GSS_C_NT_HOSTBASE D_SERVICE)
extern gss_OID gss_nt_service_name; extern gss_OID gss_nt_service_name;
#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
#endif #endif
#ifdef WANT_KERBEROS5_3DES #ifdef WANT_KERBEROS5_3DES
/* Check if CyberSafe flag is defined */ /* Check if CyberSafe flag is defined */
#ifdef CSF_GSS_C_DES3_FLAG #ifdef CSF_GSS_C_DES3_FLAG
#define K5_MAX_SSF 112 #define K5_MAX_SSF 112
#endif #endif
skipping to change at line 153 skipping to change at line 153
int state; int state;
gss_ctx_id_t gss_ctx; gss_ctx_id_t gss_ctx;
gss_name_t client_name; gss_name_t client_name;
gss_name_t server_name; gss_name_t server_name;
gss_cred_id_t server_creds; gss_cred_id_t server_creds;
gss_cred_id_t client_creds; gss_cred_id_t client_creds;
sasl_ssf_t limitssf, requiressf; /* application defined bounds, for the sasl_ssf_t limitssf, requiressf; /* application defined bounds, for the
server */ server */
unsigned char qop; /* as allowed by GSSAPI */
const sasl_utils_t *utils; const sasl_utils_t *utils;
/* layers buffering */ /* layers buffering */
decode_context_t decode_context; decode_context_t decode_context;
char *encode_buf; /* For encoding/decoding mem managemen t */ char *encode_buf; /* For encoding/decoding mem managemen t */
char *decode_buf; char *decode_buf;
char *decode_once_buf; char *decode_once_buf;
unsigned encode_buf_len; unsigned encode_buf_len;
unsigned decode_buf_len; unsigned decode_buf_len;
skipping to change at line 180 skipping to change at line 182
const char *user; /* hold the userid between steps - client */ const char *user; /* hold the userid between steps - client */
} context_t; } context_t;
enum { enum {
SASL_GSSAPI_STATE_AUTHNEG = 1, SASL_GSSAPI_STATE_AUTHNEG = 1,
SASL_GSSAPI_STATE_SSFCAP = 2, SASL_GSSAPI_STATE_SSFCAP = 2,
SASL_GSSAPI_STATE_SSFREQ = 3, SASL_GSSAPI_STATE_SSFREQ = 3,
SASL_GSSAPI_STATE_AUTHENTICATED = 4 SASL_GSSAPI_STATE_AUTHENTICATED = 4
}; };
#define LAYER_CONFIDENTIALITY 4
#define LAYER_INTEGRITY 2
#define LAYER_NONE 1
/* sasl_gss_log: only logs status string returned from gss_display_status() */ /* sasl_gss_log: only logs status string returned from gss_display_status() */
#define sasl_gss_log(x,y,z) sasl_gss_seterror_(x,y,z,1) #define sasl_gss_log(x,y,z) sasl_gss_seterror_(x,y,z,1)
#define sasl_gss_seterror(x,y,z) sasl_gss_seterror_(x,y,z,0) #define sasl_gss_seterror(x,y,z) sasl_gss_seterror_(x,y,z,0)
static int static int
sasl_gss_seterror_(const sasl_utils_t *utils, OM_uint32 maj, OM_uint32 min, sasl_gss_seterror_(const sasl_utils_t *utils, OM_uint32 maj, OM_uint32 min,
int logonly) int logonly)
{ {
OM_uint32 maj_stat, min_stat; OM_uint32 maj_stat, min_stat;
gss_buffer_desc msg; gss_buffer_desc msg;
OM_uint32 msg_ctx; OM_uint32 msg_ctx;
int ret; int ret;
char *out = NULL; char *out = NULL;
size_t len, curlen = 0; size_t len, curlen = 0;
const char prefix[] = "GSSAPI Error: "; const char prefix[] = "GSSAPI Error: ";
if (!utils) return SASL_OK;
len = sizeof(prefix); len = sizeof(prefix);
ret = _plug_buf_alloc(utils, &out, &curlen, 256); ret = _plug_buf_alloc(utils, &out, &curlen, 256);
if(ret != SASL_OK) return SASL_OK; if (ret != SASL_OK) return SASL_NOMEM;
strcpy(out, prefix); strcpy(out, prefix);
msg_ctx = 0; msg_ctx = 0;
while (1) { while (1) {
GSS_LOCK_MUTEX(utils); GSS_LOCK_MUTEX(utils);
maj_stat = gss_display_status(&min_stat, maj, maj_stat = gss_display_status(&min_stat, maj,
GSS_C_GSS_CODE, GSS_C_NULL_OID, GSS_C_GSS_CODE, GSS_C_NULL_OID,
&msg_ctx, &msg); &msg_ctx, &msg);
GSS_UNLOCK_MUTEX(utils); GSS_UNLOCK_MUTEX(utils);
skipping to change at line 228 skipping to change at line 236
} }
utils->free(out); utils->free(out);
return SASL_OK; return SASL_OK;
} }
len += len + msg.length; len += len + msg.length;
ret = _plug_buf_alloc(utils, &out, &curlen, len); ret = _plug_buf_alloc(utils, &out, &curlen, len);
if(ret != SASL_OK) { if(ret != SASL_OK) {
utils->free(out); utils->free(out);
return SASL_OK; return SASL_NOMEM;
} }
strcat(out, msg.value); strcat(out, msg.value);
GSS_LOCK_MUTEX(utils); GSS_LOCK_MUTEX(utils);
gss_release_buffer(&min_stat, &msg); gss_release_buffer(&min_stat, &msg);
GSS_UNLOCK_MUTEX(utils); GSS_UNLOCK_MUTEX(utils);
if (!msg_ctx) if (!msg_ctx)
break; break;
skipping to change at line 321 skipping to change at line 329
sasl_gss_encode(void *context, const struct iovec *invec, unsigned numiov, sasl_gss_encode(void *context, const struct iovec *invec, unsigned numiov,
const char **output, unsigned *outputlen, int privacy) const char **output, unsigned *outputlen, int privacy)
{ {
context_t *text = (context_t *)context; context_t *text = (context_t *)context;
OM_uint32 maj_stat, min_stat; OM_uint32 maj_stat, min_stat;
gss_buffer_t input_token, output_token; gss_buffer_t input_token, output_token;
gss_buffer_desc real_input_token, real_output_token; gss_buffer_desc real_input_token, real_output_token;
int ret; int ret;
struct buffer_info *inblob, bufinfo; struct buffer_info *inblob, bufinfo;
if(!output) return SASL_BADPARAM; if (!output) return SASL_BADPARAM;
if(numiov > 1) { if (numiov > 1) {
ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_b uf); ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_b uf);
if(ret != SASL_OK) return ret; if (ret != SASL_OK) return ret;
inblob = text->enc_in_buf; inblob = text->enc_in_buf;
} else { } else {
bufinfo.data = invec[0].iov_base; bufinfo.data = invec[0].iov_base;
bufinfo.curlen = invec[0].iov_len; bufinfo.curlen = invec[0].iov_len;
inblob = &bufinfo; inblob = &bufinfo;
} }
if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) return SASL_NOTDONE ; if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) return SASL_NOTDONE ;
input_token = &real_input_token; input_token = &real_input_token;
skipping to change at line 354 skipping to change at line 362
GSS_LOCK_MUTEX(text->utils); GSS_LOCK_MUTEX(text->utils);
maj_stat = gss_wrap (&min_stat, maj_stat = gss_wrap (&min_stat,
text->gss_ctx, text->gss_ctx,
privacy, privacy,
GSS_C_QOP_DEFAULT, GSS_C_QOP_DEFAULT,
input_token, input_token,
NULL, NULL,
output_token); output_token);
GSS_UNLOCK_MUTEX(text->utils); GSS_UNLOCK_MUTEX(text->utils);
if (GSS_ERROR(maj_stat)) if (GSS_ERROR(maj_stat)) {
{ sasl_gss_seterror(text->utils, maj_stat, min_stat);
sasl_gss_seterror(text->utils, maj_stat, min_stat); if (output_token->value) {
if (output_token->value) { GSS_LOCK_MUTEX(text->utils);
GSS_LOCK_MUTEX(text->utils); gss_release_buffer(&min_stat, output_token);
gss_release_buffer(&min_stat, output_token); GSS_UNLOCK_MUTEX(text->utils);
GSS_UNLOCK_MUTEX(text->utils);
}
return SASL_FAIL;
} }
return SASL_FAIL;
}
if (output_token->value && output) { if (output_token->value && output) {
int len; unsigned char * p = (unsigned char *) text->encode_buf;
ret = _plug_buf_alloc(text->utils, &(text->encode_buf), ret = _plug_buf_alloc(text->utils,
&(text->encode_buf_len), output_token->length &(text->encode_buf),
+ 4); &(text->encode_buf_len),
output_token->length + 4);
if (ret != SASL_OK) { if (ret != SASL_OK) {
GSS_LOCK_MUTEX(text->utils); GSS_LOCK_MUTEX(text->utils);
gss_release_buffer(&min_stat, output_token); gss_release_buffer(&min_stat, output_token);
GSS_UNLOCK_MUTEX(text->utils); GSS_UNLOCK_MUTEX(text->utils);
return ret; return ret;
} }
len = htonl(output_token->length); p[0] = (output_token->length>>24) & 0xFF;
memcpy(text->encode_buf, &len, 4); p[1] = (output_token->length>>16) & 0xFF;
p[2] = (output_token->length>>8) & 0xFF;
p[3] = output_token->length & 0xFF;
memcpy(text->encode_buf + 4, output_token->value, output_token->leng th); memcpy(text->encode_buf + 4, output_token->value, output_token->leng th);
} }
if (outputlen) { if (outputlen) {
*outputlen = output_token->length + 4; *outputlen = output_token->length + 4;
} }
*output = text->encode_buf; *output = text->encode_buf;
if (output_token->value) { if (output_token->value) {
GSS_LOCK_MUTEX(text->utils); GSS_LOCK_MUTEX(text->utils);
gss_release_buffer(&min_stat, output_token); gss_release_buffer(&min_stat, output_token);
GSS_UNLOCK_MUTEX(text->utils); GSS_UNLOCK_MUTEX(text->utils);
} }
return SASL_OK; return SASL_OK;
} }
static int gssapi_privacy_encode(void *context, const struct iovec *invec, static int gssapi_privacy_encode(void *context, const struct iovec *invec,
unsigned numiov, const char **output, unsigned numiov, const char **output,
unsigned *outputlen) unsigned *outputlen)
{ {
return sasl_gss_encode(context,invec,numiov,output,outputlen,1); return sasl_gss_encode(context,invec,numiov,output,outputlen,1);
} }
static int gssapi_integrity_encode(void *context, const struct iovec *invec , static int gssapi_integrity_encode(void *context, const struct iovec *invec ,
unsigned numiov, const char **output, unsigned numiov, const char **output,
unsigned *outputlen) unsigned *outputlen)
{ {
return sasl_gss_encode(context,invec,numiov,output,outputlen,0); return sasl_gss_encode(context,invec,numiov,output,outputlen,0);
} }
static int gssapi_decode_packet(void *context, static int
const char *input, unsigned inputlen, gssapi_decode_packet(void *context,
char **output, unsigned *outputlen) const char *input,
unsigned inputlen,
char **output,
unsigned *outputlen)
{ {
context_t *text = (context_t *) context; context_t *text = (context_t *) context;
OM_uint32 maj_stat, min_stat; OM_uint32 maj_stat, min_stat;
gss_buffer_t input_token, output_token; gss_buffer_t input_token, output_token;
gss_buffer_desc real_input_token, real_output_token; gss_buffer_desc real_input_token, real_output_token;
int result; int result;
if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) { if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) {
SETERROR(text->utils, "GSSAPI Failure"); SETERROR(text->utils, "GSSAPI Failure");
return SASL_NOTDONE; return SASL_NOTDONE;
skipping to change at line 443 skipping to change at line 459
GSS_LOCK_MUTEX(text->utils); GSS_LOCK_MUTEX(text->utils);
maj_stat = gss_unwrap (&min_stat, maj_stat = gss_unwrap (&min_stat,
text->gss_ctx, text->gss_ctx,
input_token, input_token,
output_token, output_token,
NULL, NULL,
NULL); NULL);
GSS_UNLOCK_MUTEX(text->utils); GSS_UNLOCK_MUTEX(text->utils);
if (GSS_ERROR(maj_stat)) if (GSS_ERROR(maj_stat)) {
{ sasl_gss_seterror(text->utils,maj_stat,min_stat);
sasl_gss_seterror(text->utils,maj_stat,min_stat); if (output_token->value) {
if (output_token->value) { GSS_LOCK_MUTEX(text->utils);
GSS_LOCK_MUTEX(text->utils); gss_release_buffer(&min_stat, output_token);
gss_release_buffer(&min_stat, output_token); GSS_UNLOCK_MUTEX(text->utils);
GSS_UNLOCK_MUTEX(text->utils);
}
return SASL_FAIL;
} }
return SASL_FAIL;
}
if (outputlen) if (outputlen) {
*outputlen = output_token->length; *outputlen = output_token->length;
}
if (output_token->value) { if (output_token->value) {
if (output) { if (output) {
result = _plug_buf_alloc(text->utils, &text->decode_once_buf, result = _plug_buf_alloc(text->utils, &text->decode_once_buf,
&text->decode_once_buf_len, &text->decode_once_buf_len,
*outputlen); *outputlen);
if(result != SASL_OK) { if (result != SASL_OK) {
GSS_LOCK_MUTEX(text->utils); GSS_LOCK_MUTEX(text->utils);
gss_release_buffer(&min_stat, output_token); gss_release_buffer(&min_stat, output_token);
GSS_UNLOCK_MUTEX(text->utils); GSS_UNLOCK_MUTEX(text->utils);
return result; return result;
} }
*output = text->decode_once_buf; *output = text->decode_once_buf;
memcpy(*output, output_token->value, *outputlen); memcpy(*output, output_token->value, *outputlen);
} }
GSS_LOCK_MUTEX(text->utils); GSS_LOCK_MUTEX(text->utils);
gss_release_buffer(&min_stat, output_token); gss_release_buffer(&min_stat, output_token);
skipping to change at line 644 skipping to change at line 660
unsigned *serveroutlen, unsigned *serveroutlen,
sasl_out_params_t *oparams) sasl_out_params_t *oparams)
{ {
context_t *text = (context_t *)conn_context; context_t *text = (context_t *)conn_context;
gss_buffer_t input_token, output_token; gss_buffer_t input_token, output_token;
gss_buffer_desc real_input_token, real_output_token; gss_buffer_desc real_input_token, real_output_token;
OM_uint32 maj_stat = 0, min_stat = 0; OM_uint32 maj_stat = 0, min_stat = 0;
OM_uint32 max_input; OM_uint32 max_input;
gss_buffer_desc name_token; gss_buffer_desc name_token;
int ret, out_flags = 0 ; int ret, out_flags = 0 ;
gss_cred_id_t server_creds = params->gss_creds;
input_token = &real_input_token; input_token = &real_input_token;
output_token = &real_output_token; output_token = &real_output_token;
output_token->value = NULL; output_token->length = 0; output_token->value = NULL; output_token->length = 0;
input_token->value = NULL; input_token->length = 0; input_token->value = NULL; input_token->length = 0;
if(!serverout) { if(!serverout) {
PARAMERROR(text->utils); PARAMERROR(text->utils);
return SASL_BADPARAM; return SASL_BADPARAM;
} }
*serverout = NULL; *serverout = NULL;
*serveroutlen = 0; *serveroutlen = 0;
if (text == NULL) {
return SASL_BADPROT;
}
switch (text->state) { switch (text->state) {
case SASL_GSSAPI_STATE_AUTHNEG: case SASL_GSSAPI_STATE_AUTHNEG:
if (text->server_name == GSS_C_NO_NAME) { /* only once */ if (text->server_name == GSS_C_NO_NAME) { /* only once */
if (params->serverFQDN == NULL
|| strlen(params->serverFQDN) == 0) {
SETERROR(text->utils, "GSSAPI Failure: no serverFQDN");
sasl_gss_free_context_contents(text);
return SASL_FAIL;
}
name_token.length = strlen(params->service) + 1 + strlen(params- >serverFQDN); name_token.length = strlen(params->service) + 1 + strlen(params- >serverFQDN);
name_token.value = (char *)params->utils->malloc((name_token.len gth + 1) * sizeof(char)); name_token.value = (char *)params->utils->malloc((name_token.len gth + 1) * sizeof(char));
if (name_token.value == NULL) { if (name_token.value == NULL) {
MEMERROR(text->utils); MEMERROR(text->utils);
sasl_gss_free_context_contents(text); sasl_gss_free_context_contents(text);
return SASL_NOMEM; return SASL_NOMEM;
} }
sprintf(name_token.value,"%s@%s", params->service, params->serve rFQDN); sprintf(name_token.value,"%s@%s", params->service, params->serve rFQDN);
GSS_LOCK_MUTEX(params->utils); GSS_LOCK_MUTEX(params->utils);
skipping to change at line 694 skipping to change at line 721
return SASL_FAIL; return SASL_FAIL;
} }
if ( text->server_creds != GSS_C_NO_CREDENTIAL) { if ( text->server_creds != GSS_C_NO_CREDENTIAL) {
GSS_LOCK_MUTEX(params->utils); GSS_LOCK_MUTEX(params->utils);
maj_stat = gss_release_cred(&min_stat, &text->server_creds); maj_stat = gss_release_cred(&min_stat, &text->server_creds);
GSS_UNLOCK_MUTEX(params->utils); GSS_UNLOCK_MUTEX(params->utils);
text->server_creds = GSS_C_NO_CREDENTIAL; text->server_creds = GSS_C_NO_CREDENTIAL;
} }
GSS_LOCK_MUTEX(params->utils); /* If caller didn't provide creds already */
maj_stat = gss_acquire_cred(&min_stat, if ( server_creds == GSS_C_NO_CREDENTIAL) {
text->server_name, GSS_LOCK_MUTEX(params->utils);
GSS_C_INDEFINITE, maj_stat = gss_acquire_cred(&min_stat,
GSS_C_NO_OID_SET, text->server_name,
GSS_C_ACCEPT, GSS_C_INDEFINITE,
&text->server_creds, GSS_C_NO_OID_SET,
NULL, GSS_C_ACCEPT,
NULL); &text->server_creds,
GSS_UNLOCK_MUTEX(params->utils); NULL,
NULL);
GSS_UNLOCK_MUTEX(params->utils);
if (GSS_ERROR(maj_stat)) { if (GSS_ERROR(maj_stat)) {
sasl_gss_seterror(text->utils, maj_stat, min_stat); sasl_gss_seterror(text->utils, maj_stat, min_stat);
sasl_gss_free_context_contents(text); sasl_gss_free_context_contents(text);
return SASL_FAIL; return SASL_FAIL;
}
server_creds = text->server_creds;
} }
} }
if (clientinlen) { if (clientinlen) {
real_input_token.value = (void *)clientin; real_input_token.value = (void *)clientin;
real_input_token.length = clientinlen; real_input_token.length = clientinlen;
} }
GSS_LOCK_MUTEX(params->utils); GSS_LOCK_MUTEX(params->utils);
maj_stat = maj_stat =
gss_accept_sec_context(&min_stat, gss_accept_sec_context(&min_stat,
&(text->gss_ctx), &(text->gss_ctx),
text->server_creds, server_creds,
input_token, input_token,
GSS_C_NO_CHANNEL_BINDINGS, GSS_C_NO_CHANNEL_BINDINGS,
&text->client_name, &text->client_name,
NULL, NULL, /* resulting mech_name */
output_token, output_token,
&out_flags, &out_flags,
NULL, NULL, /* context validity period * /
&(text->client_creds)); &(text->client_creds));
GSS_UNLOCK_MUTEX(params->utils); GSS_UNLOCK_MUTEX(params->utils);
if (GSS_ERROR(maj_stat)) { if (GSS_ERROR(maj_stat)) {
sasl_gss_log(text->utils, maj_stat, min_stat); sasl_gss_log(text->utils, maj_stat, min_stat);
text->utils->seterror(text->utils->conn, SASL_NOLOG, "GSSAPI Fai lure: gss_accept_sec_context"); text->utils->seterror(text->utils->conn, SASL_NOLOG, "GSSAPI Fai lure: gss_accept_sec_context");
if (output_token->value) { if (output_token->value) {
GSS_LOCK_MUTEX(params->utils); GSS_LOCK_MUTEX(params->utils);
gss_release_buffer(&min_stat, output_token); gss_release_buffer(&min_stat, output_token);
GSS_UNLOCK_MUTEX(params->utils); GSS_UNLOCK_MUTEX(params->utils);
} }
sasl_gss_free_context_contents(text); sasl_gss_free_context_contents(text);
return SASL_BADAUTH; return SASL_BADAUTH;
} }
/* When GSS_Accept_sec_context returns GSS_S_COMPLETE, the server
examines the context to ensure that it provides a level of protec
tion
permitted by the server's security policy. In particular, if the
integ_avail flag is not set in the context, then no security laye
r
can be offered or accepted. If the conf_avail flag is not set in
the
context, then no security layer with confidentiality can be offer
ed
or accepted. */
if ((out_flags & GSS_C_INTEG_FLAG) == 0) {
/* if the integ_avail flag is not set in the context,
then no security layer can be offered or accepted. */
text->qop = LAYER_NONE;
} else if ((out_flags & GSS_C_CONF_FLAG) == 0) {
/* If the conf_avail flag is not set in the context,
then no security layer with confidentiality can be offered
or accepted. */
text->qop = LAYER_NONE | LAYER_INTEGRITY;
} else {
text->qop = LAYER_NONE | LAYER_INTEGRITY | LAYER_CONFIDENTIALITY
;
}
if ((params->props.security_flags & SASL_SEC_PASS_CREDENTIALS) && if ((params->props.security_flags & SASL_SEC_PASS_CREDENTIALS) &&
(!(out_flags & GSS_C_DELEG_FLAG) || (!(out_flags & GSS_C_DELEG_FLAG) ||
text->client_creds == GSS_C_NO_CREDENTIAL) ) text->client_creds == GSS_C_NO_CREDENTIAL) )
{ {
text->utils->seterror(text->utils->conn, SASL_LOG_WARN, text->utils->seterror(text->utils->conn, SASL_LOG_WARN,
"GSSAPI warning: no credentials were passe d"); "GSSAPI warning: no credentials were passe d");
/* continue with authentication */ /* continue with authentication */
} }
if (serveroutlen) if (serveroutlen)
skipping to change at line 775 skipping to change at line 826
memcpy(text->out_buf, output_token->value, *serveroutlen); memcpy(text->out_buf, output_token->value, *serveroutlen);
*serverout = text->out_buf; *serverout = text->out_buf;
} }
GSS_LOCK_MUTEX(params->utils); GSS_LOCK_MUTEX(params->utils);
gss_release_buffer(&min_stat, output_token); gss_release_buffer(&min_stat, output_token);
GSS_UNLOCK_MUTEX(params->utils); GSS_UNLOCK_MUTEX(params->utils);
} else { } else {
/* No output token, send an empty string */ /* No output token, send an empty string */
*serverout = GSSAPI_BLANK_STRING; *serverout = GSSAPI_BLANK_STRING;
serveroutlen = 0; *serveroutlen = 0;
} }
if (maj_stat == GSS_S_COMPLETE) { if (maj_stat == GSS_S_COMPLETE) {
/* Switch to ssf negotiation */ /* Switch to ssf negotiation */
text->state = SASL_GSSAPI_STATE_SSFCAP; text->state = SASL_GSSAPI_STATE_SSFCAP;
}
return SASL_CONTINUE; if (*serveroutlen != 0) {
return SASL_CONTINUE;
}
/* Pretend that we just got an empty response from the client */
clientinlen = 0;
/* fall through */
} else {
return SASL_CONTINUE;
}
case SASL_GSSAPI_STATE_SSFCAP: { case SASL_GSSAPI_STATE_SSFCAP: {
unsigned char sasldata[4]; unsigned char sasldata[4];
gss_buffer_desc name_token; gss_buffer_desc name_token;
gss_buffer_desc name_without_realm; gss_buffer_desc name_without_realm;
gss_name_t without = NULL; gss_name_t without = NULL;
int equal; int equal;
name_token.value = NULL; name_token.value = NULL;
name_without_realm.value = NULL; name_without_realm.value = NULL;
/* We ignore whatever the client sent us at this stage */ if (clientinlen != 0) {
SETERROR(text->utils, "GSSAPI server is not expecting data at th
is stage");
sasl_gss_free_context_contents(text);
return SASL_BADAUTH;
}
GSS_LOCK_MUTEX(params->utils); GSS_LOCK_MUTEX(params->utils);
maj_stat = gss_display_name (&min_stat, maj_stat = gss_display_name (&min_stat,
text->client_name, text->client_name,
&name_token, &name_token,
NULL); NULL);
GSS_UNLOCK_MUTEX(params->utils); GSS_UNLOCK_MUTEX(params->utils);
if (GSS_ERROR(maj_stat)) { if (GSS_ERROR(maj_stat)) {
if (without) {
GSS_LOCK_MUTEX(params->utils);
gss_release_name(&min_stat, &without);
GSS_UNLOCK_MUTEX(params->utils);
}
SETERROR(text->utils, "GSSAPI Failure"); SETERROR(text->utils, "GSSAPI Failure");
sasl_gss_free_context_contents(text); sasl_gss_free_context_contents(text);
return SASL_BADAUTH; return SASL_BADAUTH;
} }
/* If the id contains a realm get the identifier for the user /* If the id contains a realm get the identifier for the user
without the realm and see if it's the same id (i.e. without the realm and see if it's the same id (i.e.
tmartin == tmartin@ANDREW.CMU.EDU. If this is the case we just wa nt tmartin == tmartin@ANDREW.CMU.EDU. If this is the case we just wa nt
to return the id (i.e. just "tmartin" */ to return the id (i.e. just "tmartin" */
if (strchr((char *) name_token.value, (int) '@') != NULL) { if (strchr((char *) name_token.value, (int) '@') != NULL) {
skipping to change at line 936 skipping to change at line 995
} else { } else {
text->limitssf = params->props.max_ssf - params->external_ssf; text->limitssf = params->props.max_ssf - params->external_ssf;
} }
if (params->props.min_ssf < params->external_ssf) { if (params->props.min_ssf < params->external_ssf) {
text->requiressf = 0; text->requiressf = 0;
} else { } else {
text->requiressf = params->props.min_ssf - params->external_ssf; text->requiressf = params->props.min_ssf - params->external_ssf;
} }
/* build up our security properties token */ /* build up our security properties token */
if (params->props.maxbufsize > 0xFFFFFF) { if (text->requiressf != 0 &&
/* make sure maxbufsize isn't too large */ (text->qop & (LAYER_INTEGRITY|LAYER_CONFIDENTIALITY))) {
/* maxbufsize = 0xFFFFFF */ if (params->props.maxbufsize > 0xFFFFFF) {
sasldata[1] = sasldata[2] = sasldata[3] = 0xFF; /* make sure maxbufsize isn't too large */
} else { /* maxbufsize = 0xFFFFFF */
sasldata[1] = (params->props.maxbufsize >> 16) & 0xFF; sasldata[1] = sasldata[2] = sasldata[3] = 0xFF;
sasldata[2] = (params->props.maxbufsize >> 8) & 0xFF; } else {
sasldata[3] = (params->props.maxbufsize >> 0) & 0xFF; sasldata[1] = (params->props.maxbufsize >> 16) & 0xFF;
} sasldata[2] = (params->props.maxbufsize >> 8) & 0xFF;
sasldata[3] = (params->props.maxbufsize >> 0) & 0xFF;
}
} else {
/* From RFC 4752: "The client verifies that the server maximum b
uffer is 0
if the server does not advertise support for any security lay
er." */
sasldata[1] = sasldata[2] = sasldata[3] = 0;
}
sasldata[0] = 0; sasldata[0] = 0;
if(text->requiressf != 0 && !params->props.maxbufsize) { if(text->requiressf != 0 && !params->props.maxbufsize) {
params->utils->seterror(params->utils->conn, 0, params->utils->seterror(params->utils->conn, 0,
"GSSAPI needs a security layer but one i s forbidden"); "GSSAPI needs a security layer but one i s forbidden");
return SASL_TOOWEAK; return SASL_TOOWEAK;
} }
if (text->requiressf == 0) { if (text->requiressf == 0) {
sasldata[0] |= 1; /* authentication */ sasldata[0] |= LAYER_NONE; /* authentication */
} }
if (text->requiressf <= 1 && text->limitssf >= 1 if ((text->qop & LAYER_INTEGRITY) &&
&& params->props.maxbufsize) { text->requiressf <= 1 &&
sasldata[0] |= 2; text->limitssf >= 1 &&
} params->props.maxbufsize) {
if (text->requiressf <= K5_MAX_SSF && text->limitssf >= K5_MAX_SSF sasldata[0] |= LAYER_INTEGRITY;
&& params->props.maxbufsize) { }
sasldata[0] |= 4; if ((text->qop & LAYER_CONFIDENTIALITY) &&
text->requiressf <= K5_MAX_SSF &&
text->limitssf >= K5_MAX_SSF &&
params->props.maxbufsize) {
sasldata[0] |= LAYER_CONFIDENTIALITY;
} }
real_input_token.value = (void *)sasldata; real_input_token.value = (void *)sasldata;
real_input_token.length = 4; real_input_token.length = 4;
GSS_LOCK_MUTEX(params->utils); GSS_LOCK_MUTEX(params->utils);
maj_stat = gss_wrap(&min_stat, maj_stat = gss_wrap(&min_stat,
text->gss_ctx, text->gss_ctx,
0, /* Just integrity checking here */ 0, /* Just integrity checking here */
GSS_C_QOP_DEFAULT, GSS_C_QOP_DEFAULT,
skipping to change at line 1009 skipping to change at line 1080
} }
memcpy(text->out_buf, output_token->value, *serveroutlen); memcpy(text->out_buf, output_token->value, *serveroutlen);
*serverout = text->out_buf; *serverout = text->out_buf;
} }
GSS_LOCK_MUTEX(params->utils); GSS_LOCK_MUTEX(params->utils);
gss_release_buffer(&min_stat, output_token); gss_release_buffer(&min_stat, output_token);
GSS_UNLOCK_MUTEX(params->utils); GSS_UNLOCK_MUTEX(params->utils);
} }
/* Remember what we want and can offer */
text->qop = sasldata[0];
/* Wait for ssf request and authid */ /* Wait for ssf request and authid */
text->state = SASL_GSSAPI_STATE_SSFREQ; text->state = SASL_GSSAPI_STATE_SSFREQ;
return SASL_CONTINUE; return SASL_CONTINUE;
} }
case SASL_GSSAPI_STATE_SSFREQ: { case SASL_GSSAPI_STATE_SSFREQ: {
int layerchoice; int layerchoice;
real_input_token.value = (void *)clientin; real_input_token.value = (void *)clientin;
skipping to change at line 1036 skipping to change at line 1110
NULL, NULL,
NULL); NULL);
GSS_UNLOCK_MUTEX(params->utils); GSS_UNLOCK_MUTEX(params->utils);
if (GSS_ERROR(maj_stat)) { if (GSS_ERROR(maj_stat)) {
sasl_gss_seterror(text->utils, maj_stat, min_stat); sasl_gss_seterror(text->utils, maj_stat, min_stat);
sasl_gss_free_context_contents(text); sasl_gss_free_context_contents(text);
return SASL_FAIL; return SASL_FAIL;
} }
if (output_token->length < 4) {
SETERROR(text->utils,
"token too short");
GSS_LOCK_MUTEX(params->utils);
gss_release_buffer(&min_stat, output_token);
GSS_UNLOCK_MUTEX(params->utils);
sasl_gss_free_context_contents(text);
return SASL_FAIL;
}
layerchoice = (int)(((char *)(output_token->value))[0]); layerchoice = (int)(((char *)(output_token->value))[0]);
if (layerchoice == 1 && text->requiressf == 0) { /* no encryption */ if (layerchoice == LAYER_NONE &&
(text->qop & LAYER_NONE)) { /* no encryption */
oparams->encode = NULL; oparams->encode = NULL;
oparams->decode = NULL; oparams->decode = NULL;
oparams->mech_ssf = 0; oparams->mech_ssf = 0;
} else if (layerchoice == 2 && text->requiressf <= 1 && } else if (layerchoice == LAYER_INTEGRITY &&
text->limitssf >= 1) { /* integrity */ (text->qop & LAYER_INTEGRITY)) { /* integrity */
oparams->encode=&gssapi_integrity_encode; oparams->encode = &gssapi_integrity_encode;
oparams->decode=&gssapi_decode; oparams->decode = &gssapi_decode;
oparams->mech_ssf=1; oparams->mech_ssf = 1;
} else if (layerchoice == 4 && text->requiressf <= K5_MAX_SSF && } else if ((layerchoice == LAYER_CONFIDENTIALITY ||
text->limitssf >= K5_MAX_SSF) { /* privacy */ /* For compatibility with broken clients setting both bi
ts */
layerchoice == (LAYER_CONFIDENTIALITY|LAYER_INTEGRITY))
&&
(text->qop & LAYER_CONFIDENTIALITY)) { /* privacy */
oparams->encode = &gssapi_privacy_encode; oparams->encode = &gssapi_privacy_encode;
oparams->decode = &gssapi_decode; oparams->decode = &gssapi_decode;
/* FIX ME: Need to extract the proper value here */ /* FIX ME: Need to extract the proper value here */
oparams->mech_ssf = K5_MAX_SSF; oparams->mech_ssf = K5_MAX_SSF;
} else { } else {
/* not a supported encryption layer */ /* not a supported encryption layer */
SETERROR(text->utils, SETERROR(text->utils,
"protocol violation: client requested invalid layer"); "protocol violation: client requested invalid layer");
/* Mark that we attempted negotiation */ /* Mark that we attempted negotiation */
oparams->mech_ssf = 2; oparams->mech_ssf = 2;
skipping to change at line 1083 skipping to change at line 1170
SASL_CU_AUTHZID, oparams); SASL_CU_AUTHZID, oparams);
if (ret != SASL_OK) { if (ret != SASL_OK) {
sasl_gss_free_context_contents(text); sasl_gss_free_context_contents(text);
return ret; return ret;
} }
ret = params->canon_user(params->utils->conn, ret = params->canon_user(params->utils->conn,
text->authid, text->authid,
0, /* strlen(text->authid) */ 0, /* strlen(text->authid) */
SASL_CU_AUTHID, oparams); SASL_CU_AUTHID | SASL_CU_EXTERNALLY_VER IFIED, oparams);
if (ret != SASL_OK) { if (ret != SASL_OK) {
sasl_gss_free_context_contents(text); sasl_gss_free_context_contents(text);
return ret; return ret;
} }
} else if(output_token->length == 4) { } else /* if (output_token->length == 4) */ {
/* null authzid */ /* null authzid */
int ret; int ret;
ret = params->canon_user(params->utils->conn, ret = params->canon_user(params->utils->conn,
text->authid, text->authid,
0, /* strlen(text->authid) */ 0, /* strlen(text->authid) */
SASL_CU_AUTHZID | SASL_CU_AUTHID, SASL_CU_AUTHZID | SASL_CU_AUTHID | SASL _CU_EXTERNALLY_VERIFIED,
oparams); oparams);
if (ret != SASL_OK) { if (ret != SASL_OK) {
sasl_gss_free_context_contents(text); sasl_gss_free_context_contents(text);
return ret; return ret;
} }
} else {
SETERROR(text->utils,
"token too short");
GSS_LOCK_MUTEX(params->utils);
gss_release_buffer(&min_stat, output_token);
GSS_UNLOCK_MUTEX(params->utils);
sasl_gss_free_context_contents(text);
return SASL_FAIL;
} }
/* No matter what, set the rest of the oparams */ /* No matter what, set the rest of the oparams */
if (text->client_creds != GSS_C_NO_CREDENTIAL) { if (text->client_creds != GSS_C_NO_CREDENTIAL) {
oparams->client_creds = &text->client_creds; oparams->client_creds = &text->client_creds;
} }
else { else {
oparams->client_creds = NULL; oparams->client_creds = NULL;
} }
skipping to change at line 1150 skipping to change at line 1229
} }
} }
GSS_LOCK_MUTEX(params->utils); GSS_LOCK_MUTEX(params->utils);
gss_release_buffer(&min_stat, output_token); gss_release_buffer(&min_stat, output_token);
GSS_UNLOCK_MUTEX(params->utils); GSS_UNLOCK_MUTEX(params->utils);
text->state = SASL_GSSAPI_STATE_AUTHENTICATED; text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
/* used by layers */ /* used by layers */
_plug_decode_init(&text->decode_context, text->utils, _plug_decode_init(&text->decode_context,
text->utils,
(params->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF : (params->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF :
params->props.maxbufsize); params->props.maxbufsize);
oparams->doneflag = 1; oparams->doneflag = 1;
return SASL_OK; return SASL_OK;
} }
default: default:
params->utils->log(NULL, SASL_LOG_ERR, params->utils->log(NULL, SASL_LOG_ERR,
skipping to change at line 1179 skipping to change at line 1259
{ {
{ {
"GSSAPI", /* mech_name */ "GSSAPI", /* mech_name */
K5_MAX_SSF, /* max_ssf */ K5_MAX_SSF, /* max_ssf */
SASL_SEC_NOPLAINTEXT SASL_SEC_NOPLAINTEXT
| SASL_SEC_NOACTIVE | SASL_SEC_NOACTIVE
| SASL_SEC_NOANONYMOUS | SASL_SEC_NOANONYMOUS
| SASL_SEC_MUTUAL_AUTH /* security_flags */ | SASL_SEC_MUTUAL_AUTH /* security_flags */
| SASL_SEC_PASS_CREDENTIALS, | SASL_SEC_PASS_CREDENTIALS,
SASL_FEAT_WANT_CLIENT_FIRST SASL_FEAT_WANT_CLIENT_FIRST
| SASL_FEAT_ALLOWS_PROXY, /* features */ | SASL_FEAT_ALLOWS_PROXY
| SASL_FEAT_DONTUSE_USERPASSWD, /* features */
NULL, /* glob_context */ NULL, /* glob_context */
&gssapi_server_mech_new, /* mech_new */ &gssapi_server_mech_new, /* mech_new */
&gssapi_server_mech_step, /* mech_step */ &gssapi_server_mech_step, /* mech_step */
&gssapi_common_mech_dispose, /* mech_dispose */ &gssapi_common_mech_dispose, /* mech_dispose */
&gssapi_common_mech_free, /* mech_free */ &gssapi_common_mech_free, /* mech_free */
NULL, /* setpass */ NULL, /* setpass */
NULL, /* user_query */ NULL, /* user_query */
NULL, /* idle */ NULL, /* idle */
NULL, /* mech_avail */ NULL, /* mech_avail */
NULL /* spare */ NULL /* spare */
skipping to change at line 1305 skipping to change at line 1386
OM_uint32 maj_stat = 0, min_stat = 0; OM_uint32 maj_stat = 0, min_stat = 0;
OM_uint32 max_input; OM_uint32 max_input;
gss_buffer_desc name_token; gss_buffer_desc name_token;
int ret; int ret;
OM_uint32 req_flags = 0, out_req_flags = 0; OM_uint32 req_flags = 0, out_req_flags = 0;
input_token = &real_input_token; input_token = &real_input_token;
output_token = &real_output_token; output_token = &real_output_token;
output_token->value = NULL; output_token->value = NULL;
input_token->value = NULL; input_token->value = NULL;
input_token->length = 0; input_token->length = 0;
gss_cred_id_t client_creds = (gss_cred_id_t)params->gss_creds;
*clientout = NULL; *clientout = NULL;
*clientoutlen = 0; *clientoutlen = 0;
switch (text->state) { switch (text->state) {
case SASL_GSSAPI_STATE_AUTHNEG: case SASL_GSSAPI_STATE_AUTHNEG:
/* try to get the userid */ /* try to get the userid */
if (text->user == NULL) { if (text->user == NULL) {
int user_result = SASL_OK; int user_result = SASL_OK;
skipping to change at line 1348 skipping to change at line 1430
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL); NULL, NULL, NULL);
if (result != SASL_OK) return result; if (result != SASL_OK) return result;
return SASL_INTERACT; return SASL_INTERACT;
} }
} }
if (text->server_name == GSS_C_NO_NAME) { /* only once */ if (text->server_name == GSS_C_NO_NAME) { /* only once */
if (params->serverFQDN == NULL
|| strlen(params->serverFQDN) == 0) {
SETERROR(text->utils, "GSSAPI Failure: no serverFQDN");
sasl_gss_free_context_contents(text);
return SASL_FAIL;
}
name_token.length = strlen(params->service) + 1 + strlen(params- >serverFQDN); name_token.length = strlen(params->service) + 1 + strlen(params- >serverFQDN);
name_token.value = (char *)params->utils->malloc((name_token.len gth + 1) * sizeof(char)); name_token.value = (char *)params->utils->malloc((name_token.len gth + 1) * sizeof(char));
if (name_token.value == NULL) { if (name_token.value == NULL) {
sasl_gss_free_context_contents(text); sasl_gss_free_context_contents(text);
return SASL_NOMEM; return SASL_NOMEM;
} }
if (params->serverFQDN == NULL
|| strlen(params->serverFQDN) == 0) {
SETERROR(text->utils, "GSSAPI Failure: no serverFQDN");
return SASL_FAIL;
}
sprintf(name_token.value,"%s@%s", params->service, params->serve rFQDN); sprintf(name_token.value,"%s@%s", params->service, params->serve rFQDN);
GSS_LOCK_MUTEX(params->utils); GSS_LOCK_MUTEX(params->utils);
maj_stat = gss_import_name (&min_stat, maj_stat = gss_import_name (&min_stat,
&name_token, &name_token,
GSS_C_NT_HOSTBASED_SERVICE, GSS_C_NT_HOSTBASED_SERVICE,
&text->server_name); &text->server_name);
GSS_UNLOCK_MUTEX(params->utils); GSS_UNLOCK_MUTEX(params->utils);
skipping to change at line 1398 skipping to change at line 1481
* and no input from the server. However, thanks to Imap, * and no input from the server. However, thanks to Imap,
* which discards our first output, this happens all the time. * which discards our first output, this happens all the time.
* Throw away the context and try again. */ * Throw away the context and try again. */
GSS_LOCK_MUTEX(params->utils); GSS_LOCK_MUTEX(params->utils);
maj_stat = gss_delete_sec_context (&min_stat,&text->gss_ctx,GSS_ C_NO_BUFFER); maj_stat = gss_delete_sec_context (&min_stat,&text->gss_ctx,GSS_ C_NO_BUFFER);
GSS_UNLOCK_MUTEX(params->utils); GSS_UNLOCK_MUTEX(params->utils);
text->gss_ctx = GSS_C_NO_CONTEXT; text->gss_ctx = GSS_C_NO_CONTEXT;
} }
/* Setup req_flags properly */ /* Setup req_flags properly */
req_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG; req_flags = GSS_C_INTEG_FLAG;
if(params->props.max_ssf > params->external_ssf) { if (params->props.max_ssf > params->external_ssf) {
/* We are requesting a security layer */ /* We are requesting a security layer */
req_flags |= GSS_C_INTEG_FLAG; req_flags |= GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG;
/* Any SSF bigger than 1 is confidentiality. */ /* Any SSF bigger than 1 is confidentiality. */
/* Let's check if the client of the API requires confidentiality , /* Let's check if the client of the API requires confidentiality ,
and it wasn't already provided by an external layer */ and it wasn't already provided by an external layer */
if(params->props.max_ssf - params->external_ssf > 1) { if (params->props.max_ssf - params->external_ssf > 1) {
/* We want to try for privacy */ /* We want to try for privacy */
req_flags |= GSS_C_CONF_FLAG; req_flags |= GSS_C_CONF_FLAG;
} }
} }
if (params->props.security_flags & SASL_SEC_PASS_CREDENTIALS) if (params->props.security_flags & SASL_SEC_PASS_CREDENTIALS) {
req_flags = req_flags | GSS_C_DELEG_FLAG; req_flags = req_flags | GSS_C_DELEG_FLAG;
}
GSS_LOCK_MUTEX(params->utils); GSS_LOCK_MUTEX(params->utils);
maj_stat = gss_init_sec_context(&min_stat, maj_stat = gss_init_sec_context(&min_stat,
GSS_C_NO_CREDENTIAL, client_creds, /* GSS_C_NO_CREDENTIAL */
&text->gss_ctx, &text->gss_ctx,
text->server_name, text->server_name,
GSS_C_NO_OID, GSS_C_NO_OID,
req_flags, req_flags,
0, 0,
GSS_C_NO_CHANNEL_BINDINGS, GSS_C_NO_CHANNEL_BINDINGS,
input_token, input_token,
NULL, NULL,
output_token, output_token,
&out_req_flags, &out_req_flags,
skipping to change at line 1441 skipping to change at line 1525
sasl_gss_seterror(text->utils, maj_stat, min_stat); sasl_gss_seterror(text->utils, maj_stat, min_stat);
if (output_token->value) { if (output_token->value) {
GSS_LOCK_MUTEX(params->utils); GSS_LOCK_MUTEX(params->utils);
gss_release_buffer(&min_stat, output_token); gss_release_buffer(&min_stat, output_token);
GSS_UNLOCK_MUTEX(params->utils); GSS_UNLOCK_MUTEX(params->utils);
} }
sasl_gss_free_context_contents(text); sasl_gss_free_context_contents(text);
return SASL_FAIL; return SASL_FAIL;
} }
if ((out_req_flags & GSS_C_INTEG_FLAG) == 0) {
/* if the integ_avail flag is not set in the context,
then no security layer can be offered or accepted. */
text->qop = LAYER_NONE;
} else if ((out_req_flags & GSS_C_CONF_FLAG) == 0) {
/* If the conf_avail flag is not set in the context,
then no security layer with confidentiality can be offered
or accepted. */
text->qop = LAYER_NONE | LAYER_INTEGRITY;
} else {
text->qop = LAYER_NONE | LAYER_INTEGRITY | LAYER_CONFIDENTIALITY
;
}
if ((out_req_flags & GSS_C_DELEG_FLAG) != (req_flags & GSS_C_DELEG_F LAG)) { if ((out_req_flags & GSS_C_DELEG_FLAG) != (req_flags & GSS_C_DELEG_F LAG)) {
text->utils->seterror(text->utils->conn, SASL_LOG_WARN, "GSSAPI warning: no credentials were passed"); text->utils->seterror(text->utils->conn, SASL_LOG_WARN, "GSSAPI warning: no credentials were passed");
/* not a fatal error */ /* not a fatal error */
} }
*clientoutlen = output_token->length; *clientoutlen = output_token->length;
if (output_token->value) { if (output_token->value) {
if (clientout) { if (clientout) {
ret = _plug_buf_alloc(text->utils, &(text->out_buf), ret = _plug_buf_alloc(text->utils, &(text->out_buf),
skipping to change at line 1561 skipping to change at line 1658
sasl_gss_seterror(text->utils, maj_stat, min_stat); sasl_gss_seterror(text->utils, maj_stat, min_stat);
sasl_gss_free_context_contents(text); sasl_gss_free_context_contents(text);
if (output_token->value) { if (output_token->value) {
GSS_LOCK_MUTEX(params->utils); GSS_LOCK_MUTEX(params->utils);
gss_release_buffer(&min_stat, output_token); gss_release_buffer(&min_stat, output_token);
GSS_UNLOCK_MUTEX(params->utils); GSS_UNLOCK_MUTEX(params->utils);
} }
return SASL_FAIL; return SASL_FAIL;
} }
if (output_token->length != 4) {
SETERROR(text->utils,
(output_token->length < 4) ? "token too short" : "token
too long");
GSS_LOCK_MUTEX(params->utils);
gss_release_buffer(&min_stat, output_token);
GSS_UNLOCK_MUTEX(params->utils);
sasl_gss_free_context_contents(text);
return SASL_FAIL;
}
/* taken from kerberos.c */ /* taken from kerberos.c */
if (secprops->min_ssf > (K5_MAX_SSF + external)) { if (secprops->min_ssf > (K5_MAX_SSF + external)) {
return SASL_TOOWEAK; return SASL_TOOWEAK;
} else if (secprops->min_ssf > secprops->max_ssf) { } else if (secprops->min_ssf > secprops->max_ssf) {
return SASL_BADPARAM; return SASL_BADPARAM;
} }
/* need bits of layer -- sasl_ssf_t is unsigned so be careful */ /* need bits of layer -- sasl_ssf_t is unsigned so be careful */
if (secprops->max_ssf >= external) { if (secprops->max_ssf >= external) {
allowed = secprops->max_ssf - external; allowed = secprops->max_ssf - external;
skipping to change at line 1584 skipping to change at line 1691
if (secprops->min_ssf >= external) { if (secprops->min_ssf >= external) {
need = secprops->min_ssf - external; need = secprops->min_ssf - external;
} else { } else {
/* good to go */ /* good to go */
need = 0; need = 0;
} }
/* bit mask of server support */ /* bit mask of server support */
serverhas = ((char *)output_token->value)[0]; serverhas = ((char *)output_token->value)[0];
/* if client didn't set use strongest layer available */ /* use the strongest layer available */
if (allowed >= K5_MAX_SSF && need <= K5_MAX_SSF && (serverhas & 4)) if ((text->qop & LAYER_CONFIDENTIALITY) &&
{ allowed >= K5_MAX_SSF &&
need <= K5_MAX_SSF &&
(serverhas & LAYER_CONFIDENTIALITY)) {
const char *ad_compat;
/* encryption */ /* encryption */
oparams->encode = &gssapi_privacy_encode; oparams->encode = &gssapi_privacy_encode;
oparams->decode = &gssapi_decode; oparams->decode = &gssapi_decode;
/* FIX ME: Need to extract the proper value here */ /* FIX ME: Need to extract the proper value here */
oparams->mech_ssf = K5_MAX_SSF; oparams->mech_ssf = K5_MAX_SSF;
mychoice = 4; mychoice = LAYER_CONFIDENTIALITY;
} else if (allowed >= 1 && need <= 1 && (serverhas & 2)) {
if (serverhas & LAYER_INTEGRITY) {
/* should we send an AD compatible choice of security layers
? */
params->utils->getopt(params->utils->getopt_context,
"GSSAPI",
"ad_compat",
&ad_compat,
NULL);
if (ad_compat &&
(ad_compat[0] == '1' || ad_compat[0] == 'y' ||
(ad_compat[0] == 'o' && ad_compat[1] == 'n') ||
ad_compat[0] == 't')) {
mychoice = LAYER_INTEGRITY|LAYER_CONFIDENTIALITY;
}
}
} else if ((text->qop & LAYER_INTEGRITY) &&
allowed >= 1 &&
need <= 1 &&
(serverhas & LAYER_INTEGRITY)) {
/* integrity */ /* integrity */
oparams->encode = &gssapi_integrity_encode; oparams->encode = &gssapi_integrity_encode;
oparams->decode = &gssapi_decode; oparams->decode = &gssapi_decode;
oparams->mech_ssf = 1; oparams->mech_ssf = 1;
mychoice = 2; mychoice = LAYER_INTEGRITY;
} else if (need <= 0 && (serverhas & 1)) { } else if (need <= 0 && (serverhas & LAYER_NONE)) {
/* no layer */ /* no layer */
oparams->encode = NULL; oparams->encode = NULL;
oparams->decode = NULL; oparams->decode = NULL;
oparams->mech_ssf = 0; oparams->mech_ssf = 0;
mychoice = 1; mychoice = LAYER_NONE;
} else { } else {
/* there's no appropriate layering for us! */ /* there's no appropriate layering for us! */
sasl_gss_free_context_contents(text); sasl_gss_free_context_contents(text);
return SASL_TOOWEAK; return SASL_TOOWEAK;
} }
oparams->maxoutbuf = oparams->maxoutbuf =
(((unsigned char *) output_token->value)[1] << 16) | (((unsigned char *) output_token->value)[1] << 16) |
(((unsigned char *) output_token->value)[2] << 8) | (((unsigned char *) output_token->value)[2] << 8) |
(((unsigned char *) output_token->value)[3] << 0); (((unsigned char *) output_token->value)[3] << 0);
if(oparams->mech_ssf) { if (oparams->mech_ssf) {
maj_stat = gss_wrap_size_limit( &min_stat, maj_stat = gss_wrap_size_limit( &min_stat,
text->gss_ctx, text->gss_ctx,
1, 1,
GSS_C_QOP_DEFAULT, GSS_C_QOP_DEFAULT,
(OM_uint32) oparams->maxoutbuf, (OM_uint32) oparams->maxoutbuf,
&max_input); &max_input);
if(max_input > oparams->maxoutbuf) { if (max_input > oparams->maxoutbuf) {
/* Heimdal appears to get this wrong */ /* Heimdal appears to get this wrong */
oparams->maxoutbuf -= (max_input - oparams->maxoutbuf); oparams->maxoutbuf -= (max_input - oparams->maxoutbuf);
} else { } else {
/* This code is actually correct */ /* This code is actually correct */
oparams->maxoutbuf = max_input; oparams->maxoutbuf = max_input;
} }
} }
GSS_LOCK_MUTEX(params->utils); GSS_LOCK_MUTEX(params->utils);
gss_release_buffer(&min_stat, output_token); gss_release_buffer(&min_stat, output_token);
GSS_UNLOCK_MUTEX(params->utils); GSS_UNLOCK_MUTEX(params->utils);
/* oparams->user is always set, due to canon_user requirements. /* oparams->user is always set, due to canon_user requirements.
* Make sure the client actually requested it though, by checking * Make sure the client actually requested it though, by checking
* if our context was set. * if our context was set.
*/ */
if (text->user && text->user[0]) if (text->user && text->user[0]) {
alen = strlen(oparams->user); alen = strlen(oparams->user);
else } else {
alen = 0; alen = 0;
}
input_token->length = 4 + alen; input_token->length = 4 + alen;
input_token->value = input_token->value =
(char *)params->utils->malloc((input_token->length + 1)*sizeof(c har)); (char *)params->utils->malloc((input_token->length + 1)*sizeof(c har));
if (input_token->value == NULL) { if (input_token->value == NULL) {
sasl_gss_free_context_contents(text); sasl_gss_free_context_contents(text);
return SASL_NOMEM; return SASL_NOMEM;
} }
if (alen) if (alen)
memcpy((char *)input_token->value+4,oparams->user,alen); memcpy((char *)input_token->value+4,oparams->user,alen);
/* build up our security properties token */ /* build up our security properties token */
if (params->props.maxbufsize > 0xFFFFFF) { if (mychoice > 1) {
/* make sure maxbufsize isn't too large */ if (params->props.maxbufsize > 0xFFFFFF) {
/* maxbufsize = 0xFFFFFF */ /* make sure maxbufsize isn't too large */
((unsigned char *)input_token->value)[1] = 0xFF; /* maxbufsize = 0xFFFFFF */
((unsigned char *)input_token->value)[2] = 0xFF; ((unsigned char *)input_token->value)[1] = 0xFF;
((unsigned char *)input_token->value)[3] = 0xFF; ((unsigned char *)input_token->value)[2] = 0xFF;
} else { ((unsigned char *)input_token->value)[3] = 0xFF;
((unsigned char *)input_token->value)[1] = } else {
(params->props.maxbufsize >> 16) & 0xFF; ((unsigned char *)input_token->value)[1] =
((unsigned char *)input_token->value)[2] = (params->props.maxbufsize >> 16) & 0xFF;
(params->props.maxbufsize >> 8) & 0xFF; ((unsigned char *)input_token->value)[2] =
((unsigned char *)input_token->value)[3] = (params->props.maxbufsize >> 8) & 0xFF;
(params->props.maxbufsize >> 0) & 0xFF; ((unsigned char *)input_token->value)[3] =
} (params->props.maxbufsize >> 0) & 0xFF;
}
} else {
((unsigned char *)input_token->value)[1] = 0;
((unsigned char *)input_token->value)[2] = 0;
((unsigned char *)input_token->value)[3] = 0;
}
((unsigned char *)input_token->value)[0] = mychoice; ((unsigned char *)input_token->value)[0] = mychoice;
GSS_LOCK_MUTEX(params->utils); GSS_LOCK_MUTEX(params->utils);
maj_stat = gss_wrap (&min_stat, maj_stat = gss_wrap (&min_stat,
text->gss_ctx, text->gss_ctx,
0, /* Just integrity checking here */ 0, /* Just integrity checking here */
GSS_C_QOP_DEFAULT, GSS_C_QOP_DEFAULT,
input_token, input_token,
NULL, NULL,
output_token); output_token);
skipping to change at line 1697 skipping to change at line 1835
sasl_gss_seterror(text->utils, maj_stat, min_stat); sasl_gss_seterror(text->utils, maj_stat, min_stat);
if (output_token->value) { if (output_token->value) {
GSS_LOCK_MUTEX(params->utils); GSS_LOCK_MUTEX(params->utils);
gss_release_buffer(&min_stat, output_token); gss_release_buffer(&min_stat, output_token);
GSS_UNLOCK_MUTEX(params->utils); GSS_UNLOCK_MUTEX(params->utils);
} }
sasl_gss_free_context_contents(text); sasl_gss_free_context_contents(text);
return SASL_FAIL; return SASL_FAIL;
} }
if (clientoutlen) if (clientoutlen) {
*clientoutlen = output_token->length; *clientoutlen = output_token->length;
}
if (output_token->value) { if (output_token->value) {
if (clientout) { if (clientout) {
ret = _plug_buf_alloc(text->utils, &(text->out_buf), ret = _plug_buf_alloc(text->utils,
&(text->out_buf_len), *clientoutlen); &(text->out_buf),
&(text->out_buf_len),
*clientoutlen);
if (ret != SASL_OK) { if (ret != SASL_OK) {
GSS_LOCK_MUTEX(params->utils); GSS_LOCK_MUTEX(params->utils);
gss_release_buffer(&min_stat, output_token); gss_release_buffer(&min_stat, output_token);
GSS_UNLOCK_MUTEX(params->utils); GSS_UNLOCK_MUTEX(params->utils);
return ret; return ret;
} }
memcpy(text->out_buf, output_token->value, *clientoutlen); memcpy(text->out_buf, output_token->value, *clientoutlen);
*clientout = text->out_buf; *clientout = text->out_buf;
} }
 End of changes. 74 change blocks. 
141 lines changed or deleted 293 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/