#include "gssapi_generic_err.h"
#include <errno.h>
+#include <sys/types.h>
+#include <netinet/in.h>
/** helper macros **/
(((o1)->length == (o2)->length) && \
(memcmp((o1)->elements,(o2)->elements,(o1)->length) == 0))
-#define TWRITE_INT(ptr, tmp, num) \
- (tmp) = htonl(num); \
- memcpy(ptr, (char *) &(tmp), sizeof(tmp)); \
- (ptr) += sizeof(tmp);
-
-#define TREAD_INT(ptr, num) \
- memcpy((char *) &(num), (char *) (ptr), sizeof(num)); \
- (num) = ntohl(num); \
- (ptr) += sizeof(num);
+/* this code knows that an int on the wire is 32 bits. The type of
+ num should be at least this big, or the extra shifts may do weird
+ things */
+
+#define TWRITE_INT(ptr, num, bigend) \
+ (ptr)[0] = (bigend)?((num)>>24):((num)&0xff); \
+ (ptr)[1] = (bigend)?(((num)>>16)&0xff):(((num)>>8)&0xff); \
+ (ptr)[2] = (bigend)?(((num)>>8)&0xff):(((num)>>16)&0xff); \
+ (ptr)[3] = (bigend)?((num)&0xff):((num)>>24); \
+ (ptr) += 4;
+
+#define TREAD_INT(ptr, num, bigend) \
+ (num) = (((ptr)[0]<<((bigend)?24: 0)) | \
+ ((ptr)[1]<<((bigend)?16: 8)) | \
+ ((ptr)[2]<<((bigend)? 8:16)) | \
+ ((ptr)[3]<<((bigend)? 0:24))); \
+ (ptr) += 4;
#define TWRITE_STR(ptr, str, len) \
memcpy((ptr), (char *) (str), (len)); \
(str) = (ptr); \
(ptr) += (len);
-#define TWRITE_BUF(ptr, tmp, buf) \
- TWRITE_INT((ptr), (tmp), (buf).length); \
+#define TWRITE_BUF(ptr, buf, bigend) \
+ TWRITE_INT((ptr), (buf).length, (bigend)); \
TWRITE_STR((ptr), (buf).value, (buf).length);
/** malloc wrappers; these may actually do something later */
#include "gssapiP_generic.h"
+/*
+ * See krb5/gssapi_krb5.c for a description of the algorithm for
+ * encoding an object identifier.
+ */
+
+/*
+ * The OID of user_name is:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(2) gssapi(1)
+ * generic(1) user_name(1) = 1.2.840.113554.2.1.1.1
+ * machine_uid_name:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(2) gssapi(1)
+ * generic(1) machine_uid_name(2) = 1.2.840.113554.2.1.1.2
+ * string_uid_name:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(2) gssapi(1)
+ * generic(1) string_uid_name(3) = 1.2.840.113554.2.1.1.3
+ * service_name:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(2) gssapi(1)
+ * generic(1) service_name(4) = 1.2.840.113554.2.1.1.4
+ */
+
static const gss_OID_desc oids[] = {
- {2, "\001\001"},
- {2, "\001\002"},
- {2, "\001\003"},
- {2, "\001\004"},
+ {10, "\052\206\110\206\367\022\002\001\001\001"},
+ {10, "\052\206\110\206\367\022\002\001\001\002"},
+ {10, "\052\206\110\206\367\022\002\001\001\003"},
+ {10, "\052\206\110\206\367\022\002\001\001\004"},
};
const_gss_OID gss_nt_user_name = oids+0;
error_code G_WRONG_SIZE, "Buffer is the wrong size"
error_code G_BAD_USAGE, "Credential usage type is unknown"
error_code G_UNKNOWN_QOP, "Unknown quality of protection specified"
+error_code G_BAD_HOSTNAME, "Hostname in SERVICE-NAME string could not be canonicalized"
end
char *g_canonicalize_host(char *hostname)
{
struct hostent *hent;
+ char *haddr;
char *canon, *str;
if ((hent = gethostbyname(hostname)) == NULL)
return(NULL);
+ if (! (haddr = xmalloc(hent->h_length))) {
+ return(NULL);
+ }
+
+ memcpy(haddr, hent->h_addr_list[0], hent->h_length);
+
+ if (! (hent = gethostbyaddr(haddr, hent->h_length, hent->h_addrtype))) {
+ return(NULL);
+ }
+
+ xfree(haddr);
+
if ((canon = xmalloc(strlen(hent->h_name)+1)) == NULL)
return(NULL);
#include <sys/types.h>
#include <sys/file.h>
+#include <fcntl.h>
#include <limits.h>
#include <db.h>
*/
#include "gssapiP_krb5.h"
+#include <krb5/rsa-md5.h>
#include <memory.h>
/*
{
unsigned char *ptr, *ptr2;
long tmp;
+ int bigend;
krb5_gss_cred_id_t cred;
krb5_data ap_req;
int i;
/* get the rcache pointer */
- if (krb5_princ_size(cred->princ) > 1) {
- if (code = krb5_get_server_rcache(krb5_princ_component(cred->princ, 1),
- &rcache)) {
- *minor_status = code;
- return(GSS_S_FAILURE);
- }
- } else {
- rcache = NULL;
+ if (code =
+ krb5_get_server_rcache(krb5_princ_component(cred->princ,
+ ((krb5_princ_size(cred->princ)>1)?1:0)),
+ &rcache)) {
+ *minor_status = code;
+ return(GSS_S_FAILURE);
}
/* decode the message */
/* verify that the checksum is correct */
/* 24 == checksum length: see token formats document */
+ /* This checks for < 24 instead of != 24 in order that this implementation
+ can interoperate with an implementation whcih supports negotiation */
if ((authdat->authenticator->checksum->checksum_type != CKSUMTYPE_KG_CB) ||
- (authdat->authenticator->checksum->length != 24)) {
+ (authdat->authenticator->checksum->length < 24)) {
krb5_free_tkt_authent(authdat);
*minor_status = 0;
return(GSS_S_BAD_BINDINGS);
}
+ /*
+ "Be liberal in what you accept, and
+ conservative in what you send"
+ -- rfc1123
+
+ This code will let this acceptor interoperate with an initiator
+ using little-endian or big-endian integer encoding.
+ */
+
ptr = (unsigned char *) authdat->authenticator->checksum->contents;
+ bigend = 0;
- if (code = kg_checksum_channel_bindings(input_chan_bindings, &md5)) {
- krb5_free_tkt_authent(authdat);
- *minor_status = code;
- return(GSS_S_FAILURE);
+ TREAD_INT(ptr, tmp, bigend);
+
+ if (tmp != RSA_MD5_CKSUM_LENGTH) {
+ ptr = (unsigned char *) authdat->authenticator->checksum->contents;
+ bigend = 1;
+
+ TREAD_INT(ptr, tmp, bigend);
+
+ if (tmp != RSA_MD5_CKSUM_LENGTH) {
+ xfree(md5.contents);
+ krb5_free_tkt_authent(authdat);
+ *minor_status = KG_BAD_LENGTH;
+ return(GSS_S_FAILURE);
+ }
}
- TREAD_INT(ptr, tmp);
- if (tmp != md5.length) {
- xfree(md5.contents);
+ /* at this point, bigend is set according to the initiator's byte order */
+
+ if (code = kg_checksum_channel_bindings(input_chan_bindings, &md5,
+ bigend)) {
krb5_free_tkt_authent(authdat);
- *minor_status = KG_BAD_LENGTH;
+ *minor_status = code;
return(GSS_S_FAILURE);
}
xfree(md5.contents);
- TREAD_INT(ptr, gss_flags);
+ TREAD_INT(ptr, gss_flags, bigend);
/* create the ctx struct and start filling it in */
ctx->mutual = gss_flags & GSS_C_MUTUAL_FLAG;
ctx->seed_init = 0;
ctx->cred = cred;
+ ctx->big_endian = bigend;
if (code = krb5_copy_principal(cred->princ, &ctx->here)) {
xfree(ctx);
ctx->established = 1;
-
/* intern the src_name */
if (src_name)
krb5_int32 seq_send;
krb5_int32 seq_recv;
int established;
+ int big_endian;
} krb5_gss_ctx_id_rec, krb5_gss_ctx_id_t;
extern void *kg_vdb;
OM_uint32 kg_release_defcred(OM_uint32 *minor_status);
krb5_error_code kg_checksum_channel_bindings(gss_channel_bindings_t cb,
- krb5_checksum *cksum);
+ krb5_checksum *cksum,
+ int bigend);
krb5_error_code kg_make_seq_num(krb5_gss_enc_desc *ed, int direction,
int seqnum, unsigned char *cksum,
/* these are bogus, but will compile */
+/*
+ * The OID of the krb5 mechanism, assigned by IETF, is:
+ * 1.3.5.1.5.2
+ * The OID of the krb5_name type is:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(2) gssapi(1)
+ * krb5(2) krb5_name(1) = 1.2.840.113554.2.1.2.1
+ * The OID of the krb5_principal type is:
+ * iso(1) member-body(2) US(840) mit(113554) infosys(2) gssapi(1)
+ * krb5(2) krb5_principal(2) = 1.2.840.113554.2.1.2.2
+ */
+
+/*
+ * Encoding rules: The first two values are encoded in one byte as 40
+ * * value1 + value2. Subsequent values are encoded base 128, most
+ * significant digit first, with the high bit set on all octets except
+ * the last in each value's encoding.
+ */
+
static const gss_OID_desc oids[] = {
/* this OID is from Ted. It's not official yet, but it's close. */
{5, "\053\005\001\005\002"},
- {2, "\002\002"},
- {2, "\002\003"},
+ {10, "\052\206\110\206\367\022\002\001\002\001"},
+ {10, "\052\206\110\206\367\022\002\001\002\002"},
};
const_gss_OID gss_mech_krb5 = oids+0;
extern const gss_OID_desc * const gss_nt_krb5_name;
extern const gss_OID_desc * const gss_nt_krb5_principal;
+#define gss_krb5_nt_general_name gss_nt_krb5_name
+#define gss_krb5_nt_principal gss_nt_krb5_principal
+#define gss_krb5_nt_service_name gss_nt_service_name
+#define gss_krb5_nt_user_name gss_nt_user_name
+#define gss_krb5_nt_machine_uid_name gss_nt_machine_uid_name
+#define gss_krb5_nt_string_uid_name gss_nt_string_uid_name
+
OM_uint32 gss_krb5_get_tkt_flags(OM_uint32 *minor_status,
gss_ctx_id_t context_handle,
krb5_flags *ticket_flags);
/* compute the hash of the channel bindings */
- if (code = kg_checksum_channel_bindings(chan_bindings, &md5))
+ if (code = kg_checksum_channel_bindings(chan_bindings, &md5, 0))
return(code);
ptr = ckbuf;
- TWRITE_INT(ptr, tmp, md5.length);
+ TWRITE_INT(ptr, md5.length, 0);
TWRITE_STR(ptr, (unsigned char *) md5.contents, md5.length);
- TWRITE_INT(ptr, tmp, do_mutual?GSS_C_MUTUAL_FLAG:0);
+ TWRITE_INT(ptr, do_mutual?GSS_C_MUTUAL_FLAG:0, 0);
/* done with this, free it */
xfree(md5.contents);
/* fill in the necessary fields in creds */
memset((char *) &creds, 0, sizeof(creds));
-
- code = krb5_copy_principal(cred->princ, &creds.client);
- if (code)
- return code;
-
- code = krb5_copy_principal(server, &creds.server);
- if (code)
- return code;
+ creds.client = cred->princ;
+ creds.server = server;
creds.times.endtime = *endtime;
/* free stuff which was created */
+ /* XXXX There's a bug in krb5 here, but I have no clue what it is.
+ This is a workaround. */
+ if (creds.client == cred->princ)
+ creds.client = NULL;
+
krb5_free_cred_contents(&creds);
/* build up the token */
ctx->mutual = req_flags & GSS_C_MUTUAL_FLAG;
ctx->seed_init = 0;
ctx->cred = cred;
+ ctx->big_endian = 0; /* all initiators do little-endian, as per spec */
if (time_req == 0 || time_req == GSS_C_INDEFINITE) {
ctx->endtime = 0;
gss_buffer_t text,
gss_buffer_t token,
int encrypt,
- int toktype)
+ int toktype,
+ int bigend)
{
krb5_error_code code;
MD5_CTX md5;
/* create the token buffer */
if (toktype == KG_TOK_SEAL_MSG) {
- tmsglen = text->length;
- if (encrypt)
- tmsglen = (kg_confounder_size(enc_ed) +
- kg_encrypt_size(enc_ed, tmsglen+1));
+ if (bigend && !encrypt)
+ tmsglen = text->length;
+ else
+ tmsglen = (kg_confounder_size(enc_ed)+text->length+8)&(~7);
} else {
tmsglen = 0;
}
ptr[4] = 0xff;
ptr[5] = 0xff;
- /* compute the checksum */
+ /* pad the plaintext, encrypt if needed, and stick it in the token */
- MD5Init(&md5);
- MD5Update(&md5, (unsigned char *) ptr-2, 8);
- MD5Update(&md5, text->value, text->length);
- MD5Final(&md5);
+ if (toktype == KG_TOK_SEAL_MSG) {
+ unsigned char *plain;
+ unsigned char pad;
+
+ if ((plain = (unsigned char *) xmalloc(tmsglen)) == NULL) {
+ xfree(t);
+ return(ENOMEM);
+ }
+
+ if (code = kg_make_confounder(enc_ed, plain)) {
+ xfree(plain);
+ xfree(t);
+ return(code);
+ }
+
+ memcpy(plain+8, text->value, text->length);
+
+ pad = 8-(text->length%8);
+
+ memset(plain+8+text->length, pad, pad);
+
+ if (encrypt) {
+ if (code = kg_encrypt(enc_ed, NULL, (krb5_pointer) plain,
+ (krb5_pointer) (ptr+22), tmsglen)) {
+ xfree(plain);
+ xfree(t);
+ return(code);
+ }
+ } else {
+ if (bigend)
+ memcpy(ptr+22, text->value, text->length);
+ else
+ memcpy(ptr+22, plain, tmsglen);
+ }
+
+ /* compute the checksum */
+
+ MD5Init(&md5);
+ MD5Update(&md5, (unsigned char *) ptr-2, 8);
+ if (bigend)
+ MD5Update(&md5, text->value, text->length);
+ else
+ MD5Update(&md5, plain, tmsglen);
+ MD5Final(&md5);
+
+ xfree(plain);
+ } else {
+ /* compute the checksum */
+
+ MD5Init(&md5);
+ MD5Update(&md5, (unsigned char *) ptr-2, 8);
+ MD5Update(&md5, text->value, text->length);
+ MD5Final(&md5);
+ }
/* XXX this depends on the key being a single-des key, but that's
all that kerberos supports right now */
/* create the seq_num */
- if (code = kg_make_seq_num(seq_ed, direction?0xff:0, *seqnum,
+ if (code = kg_make_seq_num(seq_ed, direction?0:0xff, *seqnum,
ptr+14, ptr+6)) {
xfree(t);
return(code);
}
- /* include seal token fields */
-
- if (toktype == KG_TOK_SEAL_MSG) {
- if (encrypt) {
- unsigned char *plain;
- unsigned char pad;
-
- if ((plain = (unsigned char *) xmalloc(tmsglen)) == NULL) {
- xfree(t);
- return(ENOMEM);
- }
-
- if (code = kg_make_confounder(enc_ed, plain)) {
- xfree(plain);
- xfree(t);
- return(code);
- }
-
- memcpy(plain+8, text->value, text->length);
-
- pad = 8-(text->length%8);
-
- memset(plain+8+text->length, pad, pad);
-
- if (code = kg_encrypt(enc_ed, NULL, (krb5_pointer) plain,
- (krb5_pointer) (ptr+22), tmsglen)) {
- xfree(plain);
- xfree(t);
- return(code);
- }
-
- xfree(plain);
- } else {
- memcpy(ptr+22, text->value, text->length);
- }
- }
-
/* that's it. return the token */
(*seqnum)++;
if (code = make_seal_token(&ctx->enc, &ctx->seq, &ctx->seq_send,
ctx->initiate,
input_message_buffer, output_message_buffer,
- conf_req_flag, toktype)) {
+ conf_req_flag, toktype, ctx->big_endian)) {
*minor_status = code;
return(GSS_S_FAILURE);
}
MD5_CTX md5;
unsigned char *cksum;
krb5_timestamp now;
+ unsigned char *plain;
+ int plainlen;
if (toktype == KG_TOK_SEAL_MSG) {
message_buffer->length = 0;
if (toktype == KG_TOK_SEAL_MSG) {
if (sealalg == 0) {
- unsigned char *plain;
-
if ((plain = (unsigned char *) xmalloc(tmsglen)) == NULL) {
*minor_status = ENOMEM;
return(GSS_S_FAILURE);
*minor_status = code;
return(GSS_S_FAILURE);
}
+ } else {
+ plain = ptr+22;
+ }
- token.length = tmsglen - 8 - plain[tmsglen-1];
-
- if ((token.value = xmalloc(token.length)) == NULL) {
- xfree(plain);
- *minor_status = ENOMEM;
- return(GSS_S_FAILURE);
- }
-
- memcpy(token.value, plain+8, token.length);
+ plainlen = tmsglen;
- xfree(plain);
- } else {
+ if (sealalg && ctx->big_endian)
token.length = tmsglen;
+ else
+ token.length = tmsglen - 8 - plain[tmsglen-1];
+ if (token.length) {
if ((token.value = xmalloc(token.length)) == NULL) {
+ if (sealalg == 0)
+ xfree(plain);
*minor_status = ENOMEM;
return(GSS_S_FAILURE);
}
- memcpy(token.value, ptr+22, token.length);
+ if (sealalg && ctx->big_endian)
+ memcpy(token.value, plain, token.length);
+ else
+ memcpy(token.value, plain+8, token.length);
}
} else if (toktype == KG_TOK_SIGN_MSG) {
token = *message_buffer;
+ plain = token.value;
+ plainlen = token.length;
} else {
token.length = 0;
token.value = NULL;
+ plain = token.value;
+ plainlen = token.length;
}
/* compute the checksum of the message */
if (signalg == 0) {
+ /* compute the checksum of the message */
+
MD5Init(&md5);
MD5Update(&md5, (unsigned char *) ptr-2, 8);
- MD5Update(&md5, token.value, token.length);
+ if (ctx->big_endian)
+ MD5Update(&md5, token.value, token.length);
+ else
+ MD5Update(&md5, plain, plainlen);
MD5Final(&md5);
+ if (sealalg == 0)
+ xfree(plain);
+
/* XXX this depends on the key being a single-des key, but that's
all that kerberos supports right now */
} else {
if (! ctx->seed_init) {
if (code = kg_make_seed(ctx->subkey, ctx->seed)) {
+ if (sealalg == 0)
+ xfree(plain);
if (toktype == KG_TOK_SEAL_MSG)
xfree(token.value);
*minor_status = code;
MD5Init(&md5);
MD5Update(&md5, ctx->seed, sizeof(ctx->seed));
MD5Update(&md5, (unsigned char *) ptr-2, 8);
- MD5Update(&md5, token.value, token.length);
+ if (ctx->big_endian)
+ MD5Update(&md5, token.value, token.length);
+ else
+ MD5Update(&md5, plain, plainlen);
MD5Final(&md5);
+ if (sealalg == 0)
+ xfree(plain);
+
cksum = md5.digest;
}
*/
krb5_error_code kg_checksum_channel_bindings(gss_channel_bindings_t cb,
- krb5_checksum *cksum)
+ krb5_checksum *cksum,
+ int bigend)
{
int len;
char *buf, *ptr;
ptr = buf;
- TWRITE_INT(ptr, tmp, cb->initiator_addrtype);
- TWRITE_BUF(ptr, tmp, cb->initiator_address);
- TWRITE_INT(ptr, tmp, cb->acceptor_addrtype);
- TWRITE_BUF(ptr, tmp, cb->acceptor_address);
- TWRITE_BUF(ptr, tmp, cb->application_data);
+ TWRITE_INT(ptr, cb->initiator_addrtype, bigend);
+ TWRITE_BUF(ptr, cb->initiator_address, bigend);
+ TWRITE_INT(ptr, cb->acceptor_addrtype, bigend);
+ TWRITE_BUF(ptr, cb->acceptor_address, bigend);
+ TWRITE_BUF(ptr, cb->application_data, bigend);
/* checksum the data */