mirror of
https://github.com/samba-team/samba.git
synced 2024-12-27 03:21:53 +03:00
added a ASN.1 parser, so now I can properly parse the negTokenInit
packet which means I can extract the service and realm, so we should
now work with realms other than the local realm.
it also means we now check the list of OIDs given by the server just
in case it says that it doesn't support kerberos. In that case we
should fall back to NTLMSSP but that isn't written yet.
(This used to be commit 395cfeea94
)
This commit is contained in:
parent
49307c2678
commit
7cd9c611e2
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
struct nesting {
|
struct nesting {
|
||||||
off_t start;
|
off_t start;
|
||||||
|
size_t taglen; /* for parsing */
|
||||||
struct nesting *next;
|
struct nesting *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -30,6 +31,7 @@ typedef struct {
|
|||||||
size_t length;
|
size_t length;
|
||||||
off_t ofs;
|
off_t ofs;
|
||||||
struct nesting *nesting;
|
struct nesting *nesting;
|
||||||
|
BOOL has_error;
|
||||||
} ASN1_DATA;
|
} ASN1_DATA;
|
||||||
|
|
||||||
|
|
||||||
@ -40,3 +42,5 @@ typedef struct {
|
|||||||
#define ASN1_OCTET_STRING 0x4
|
#define ASN1_OCTET_STRING 0x4
|
||||||
#define ASN1_OID 0x6
|
#define ASN1_OID 0x6
|
||||||
#define ASN1_BOOLEAN 0x1
|
#define ASN1_BOOLEAN 0x1
|
||||||
|
|
||||||
|
#define ASN1_MAX_OIDS 20
|
||||||
|
@ -30,9 +30,13 @@ void asn1_free(ASN1_DATA *data)
|
|||||||
/* write to the ASN1 buffer, advancing the buffer pointer */
|
/* write to the ASN1 buffer, advancing the buffer pointer */
|
||||||
BOOL asn1_write(ASN1_DATA *data, const void *p, int len)
|
BOOL asn1_write(ASN1_DATA *data, const void *p, int len)
|
||||||
{
|
{
|
||||||
|
if (data->has_error) return False;
|
||||||
if (data->length < data->ofs+len) {
|
if (data->length < data->ofs+len) {
|
||||||
data->data = Realloc(data->data, data->ofs+len);
|
data->data = Realloc(data->data, data->ofs+len);
|
||||||
if (!data->data) return False;
|
if (!data->data) {
|
||||||
|
data->has_error = True;
|
||||||
|
return False;
|
||||||
|
}
|
||||||
data->length = data->ofs+len;
|
data->length = data->ofs+len;
|
||||||
}
|
}
|
||||||
memcpy(data->data + data->ofs, p, len);
|
memcpy(data->data + data->ofs, p, len);
|
||||||
@ -53,13 +57,15 @@ BOOL asn1_push_tag(ASN1_DATA *data, uint8 tag)
|
|||||||
|
|
||||||
asn1_write_uint8(data, tag);
|
asn1_write_uint8(data, tag);
|
||||||
nesting = (struct nesting *)malloc(sizeof(struct nesting));
|
nesting = (struct nesting *)malloc(sizeof(struct nesting));
|
||||||
if (!nesting) return False;
|
if (!nesting) {
|
||||||
|
data->has_error = True;
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
nesting->start = data->ofs;
|
nesting->start = data->ofs;
|
||||||
nesting->next = data->nesting;
|
nesting->next = data->nesting;
|
||||||
data->nesting = nesting;
|
data->nesting = nesting;
|
||||||
asn1_write_uint8(data, 0xff);
|
return asn1_write_uint8(data, 0xff);
|
||||||
return True;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pop a tag */
|
/* pop a tag */
|
||||||
@ -71,6 +77,7 @@ BOOL asn1_pop_tag(ASN1_DATA *data)
|
|||||||
nesting = data->nesting;
|
nesting = data->nesting;
|
||||||
|
|
||||||
if (!nesting) {
|
if (!nesting) {
|
||||||
|
data->has_error = True;
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
len = data->ofs - (nesting->start+1);
|
len = data->ofs - (nesting->start+1);
|
||||||
@ -79,8 +86,8 @@ BOOL asn1_pop_tag(ASN1_DATA *data)
|
|||||||
need to correct our mistake */
|
need to correct our mistake */
|
||||||
if (len > 127) {
|
if (len > 127) {
|
||||||
data->data[nesting->start] = 0x82;
|
data->data[nesting->start] = 0x82;
|
||||||
asn1_write_uint8(data, 0);
|
if (!asn1_write_uint8(data, 0)) return False;
|
||||||
asn1_write_uint8(data, 0);
|
if (!asn1_write_uint8(data, 0)) return False;
|
||||||
memmove(data->data+nesting->start+3, data->data+nesting->start+1, len);
|
memmove(data->data+nesting->start+3, data->data+nesting->start+1, len);
|
||||||
data->data[nesting->start+1] = len>>8;
|
data->data[nesting->start+1] = len>>8;
|
||||||
data->data[nesting->start+2] = len&0xff;
|
data->data[nesting->start+2] = len&0xff;
|
||||||
@ -99,10 +106,10 @@ BOOL asn1_write_OID(ASN1_DATA *data, const char *OID)
|
|||||||
unsigned v, v2;
|
unsigned v, v2;
|
||||||
char *p = (char *)OID;
|
char *p = (char *)OID;
|
||||||
|
|
||||||
asn1_push_tag(data, ASN1_OID);
|
if (!asn1_push_tag(data, ASN1_OID)) return False;
|
||||||
v = strtol(p, &p, 10);
|
v = strtol(p, &p, 10);
|
||||||
v2 = strtol(p, &p, 10);
|
v2 = strtol(p, &p, 10);
|
||||||
asn1_write_uint8(data, 40*v + v2);
|
if (!asn1_write_uint8(data, 40*v + v2)) return False;
|
||||||
|
|
||||||
while (*p) {
|
while (*p) {
|
||||||
v = strtol(p, &p, 10);
|
v = strtol(p, &p, 10);
|
||||||
@ -110,10 +117,9 @@ BOOL asn1_write_OID(ASN1_DATA *data, const char *OID)
|
|||||||
if (v >= (1<<21)) asn1_write_uint8(data, 0x80 | ((v>>21)&0xff));
|
if (v >= (1<<21)) asn1_write_uint8(data, 0x80 | ((v>>21)&0xff));
|
||||||
if (v >= (1<<14)) asn1_write_uint8(data, 0x80 | ((v>>14)&0xff));
|
if (v >= (1<<14)) asn1_write_uint8(data, 0x80 | ((v>>14)&0xff));
|
||||||
if (v >= (1<<7)) asn1_write_uint8(data, 0x80 | ((v>>7)&0xff));
|
if (v >= (1<<7)) asn1_write_uint8(data, 0x80 | ((v>>7)&0xff));
|
||||||
asn1_write_uint8(data, v&0x7f);
|
if (!asn1_write_uint8(data, v&0x7f)) return False;
|
||||||
}
|
}
|
||||||
asn1_pop_tag(data);
|
return asn1_pop_tag(data);
|
||||||
return True;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write an octet string */
|
/* write an octet string */
|
||||||
@ -122,7 +128,7 @@ BOOL asn1_write_OctetString(ASN1_DATA *data, const void *p, size_t length)
|
|||||||
asn1_push_tag(data, ASN1_OCTET_STRING);
|
asn1_push_tag(data, ASN1_OCTET_STRING);
|
||||||
asn1_write(data, p, length);
|
asn1_write(data, p, length);
|
||||||
asn1_pop_tag(data);
|
asn1_pop_tag(data);
|
||||||
return True;
|
return !data->has_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write a general string */
|
/* write a general string */
|
||||||
@ -131,7 +137,7 @@ BOOL asn1_write_GeneralString(ASN1_DATA *data, const char *s)
|
|||||||
asn1_push_tag(data, ASN1_GENERAL_STRING);
|
asn1_push_tag(data, ASN1_GENERAL_STRING);
|
||||||
asn1_write(data, s, strlen(s));
|
asn1_write(data, s, strlen(s));
|
||||||
asn1_pop_tag(data);
|
asn1_pop_tag(data);
|
||||||
return True;
|
return !data->has_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write a BOOLEAN */
|
/* write a BOOLEAN */
|
||||||
@ -139,17 +145,20 @@ BOOL asn1_write_BOOLEAN(ASN1_DATA *data, BOOL v)
|
|||||||
{
|
{
|
||||||
asn1_write_uint8(data, ASN1_BOOLEAN);
|
asn1_write_uint8(data, ASN1_BOOLEAN);
|
||||||
asn1_write_uint8(data, v);
|
asn1_write_uint8(data, v);
|
||||||
return True;
|
return !data->has_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* load a ASN1_DATA structure with a lump of data, ready to be parsed */
|
/* load a ASN1_DATA structure with a lump of data, ready to be parsed */
|
||||||
BOOL asn1_load(ASN1_DATA *data, void *p, size_t length)
|
BOOL asn1_load(ASN1_DATA *data, DATA_BLOB blob)
|
||||||
{
|
{
|
||||||
ZERO_STRUCTP(data);
|
ZERO_STRUCTP(data);
|
||||||
data->data = memdup(p, length);
|
data->data = memdup(blob.data, blob.length);
|
||||||
if (!data->data) return False;
|
if (!data->data) {
|
||||||
data->length = length;
|
data->has_error = True;
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
data->length = blob.length;
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,6 +166,7 @@ BOOL asn1_load(ASN1_DATA *data, void *p, size_t length)
|
|||||||
BOOL asn1_read(ASN1_DATA *data, void *p, int len)
|
BOOL asn1_read(ASN1_DATA *data, void *p, int len)
|
||||||
{
|
{
|
||||||
if (data->ofs + len > data->length) {
|
if (data->ofs + len > data->length) {
|
||||||
|
data->has_error = True;
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
memcpy(p, data->data + data->ofs, len);
|
memcpy(p, data->data + data->ofs, len);
|
||||||
@ -164,4 +174,144 @@ BOOL asn1_read(ASN1_DATA *data, void *p, int len)
|
|||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* read a uint8 from a ASN1 buffer */
|
||||||
|
BOOL asn1_read_uint8(ASN1_DATA *data, uint8 *v)
|
||||||
|
{
|
||||||
|
return asn1_read(data, v, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* start reading a nested asn1 structure */
|
||||||
|
BOOL asn1_start_tag(ASN1_DATA *data, uint8 tag)
|
||||||
|
{
|
||||||
|
uint8 b;
|
||||||
|
struct nesting *nesting;
|
||||||
|
|
||||||
|
asn1_read_uint8(data, &b);
|
||||||
|
if (b != tag) {
|
||||||
|
data->has_error = True;
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
nesting = (struct nesting *)malloc(sizeof(struct nesting));
|
||||||
|
if (!nesting) {
|
||||||
|
data->has_error = True;
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
|
asn1_read_uint8(data, &b);
|
||||||
|
if (b & 0x80) {
|
||||||
|
int n = b & 0x7f;
|
||||||
|
if (n != 2) {
|
||||||
|
data->has_error = True;
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
asn1_read_uint8(data, &b);
|
||||||
|
nesting->taglen = b<<8;
|
||||||
|
asn1_read_uint8(data, &b);
|
||||||
|
nesting->taglen |= b;
|
||||||
|
} else {
|
||||||
|
nesting->taglen = b;
|
||||||
|
}
|
||||||
|
nesting->start = data->ofs;
|
||||||
|
nesting->next = data->nesting;
|
||||||
|
data->nesting = nesting;
|
||||||
|
return !data->has_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* stop reading a tag */
|
||||||
|
BOOL asn1_end_tag(ASN1_DATA *data)
|
||||||
|
{
|
||||||
|
struct nesting *nesting;
|
||||||
|
|
||||||
|
/* make sure we read it all */
|
||||||
|
if (asn1_tag_remaining(data) != 0) {
|
||||||
|
data->has_error = True;
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
|
nesting = data->nesting;
|
||||||
|
|
||||||
|
if (!nesting) {
|
||||||
|
data->has_error = True;
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->nesting = nesting->next;
|
||||||
|
free(nesting);
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* work out how many bytes are left in this nested tag */
|
||||||
|
int asn1_tag_remaining(ASN1_DATA *data)
|
||||||
|
{
|
||||||
|
if (!data->nesting) {
|
||||||
|
data->has_error = True;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return data->nesting->taglen - (data->ofs - data->nesting->start);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read an object ID from a ASN1 buffer */
|
||||||
|
BOOL asn1_read_OID(ASN1_DATA *data, char **OID)
|
||||||
|
{
|
||||||
|
uint8 b;
|
||||||
|
pstring oid;
|
||||||
|
fstring el;
|
||||||
|
|
||||||
|
if (!asn1_start_tag(data, ASN1_OID)) return False;
|
||||||
|
asn1_read_uint8(data, &b);
|
||||||
|
|
||||||
|
oid[0] = 0;
|
||||||
|
snprintf(el, sizeof(el), "%u", b/40);
|
||||||
|
pstrcat(oid, el);
|
||||||
|
snprintf(el, sizeof(el), " %u", b%40);
|
||||||
|
pstrcat(oid, el);
|
||||||
|
|
||||||
|
while (asn1_tag_remaining(data) > 0) {
|
||||||
|
unsigned v = 0;
|
||||||
|
do {
|
||||||
|
asn1_read_uint8(data, &b);
|
||||||
|
v = (v<<7) | (b&0x7f);
|
||||||
|
} while (!data->has_error && b & 0x80);
|
||||||
|
snprintf(el, sizeof(el), " %u", v);
|
||||||
|
pstrcat(oid, el);
|
||||||
|
}
|
||||||
|
|
||||||
|
asn1_end_tag(data);
|
||||||
|
|
||||||
|
*OID = strdup(oid);
|
||||||
|
|
||||||
|
return !data->has_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check that the next object ID is correct */
|
||||||
|
BOOL asn1_check_OID(ASN1_DATA *data, char *OID)
|
||||||
|
{
|
||||||
|
char *id;
|
||||||
|
|
||||||
|
if (!asn1_read_OID(data, &id)) return False;
|
||||||
|
|
||||||
|
if (strcmp(id, OID) != 0) {
|
||||||
|
data->has_error = True;
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
free(id);
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read a GeneralString from a ASN1 buffer */
|
||||||
|
BOOL asn1_read_GeneralString(ASN1_DATA *data, char **s)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
if (!asn1_start_tag(data, ASN1_GENERAL_STRING)) return False;
|
||||||
|
len = asn1_tag_remaining(data);
|
||||||
|
*s = malloc(len+1);
|
||||||
|
if (! *s) {
|
||||||
|
data->has_error = True;
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
asn1_read(data, *s, len);
|
||||||
|
(*s)[len] = 0;
|
||||||
|
asn1_end_tag(data);
|
||||||
|
return !data->has_error;
|
||||||
|
}
|
||||||
|
@ -325,8 +325,39 @@ static BOOL cli_session_setup_spnego(struct cli_state *cli, char *user,
|
|||||||
uint32 capabilities = cli_session_setup_capabilities(cli);
|
uint32 capabilities = cli_session_setup_capabilities(cli);
|
||||||
char *p;
|
char *p;
|
||||||
DATA_BLOB blob2, negTokenTarg;
|
DATA_BLOB blob2, negTokenTarg;
|
||||||
|
char *principle;
|
||||||
|
char *OIDs[ASN1_MAX_OIDS];
|
||||||
|
uint8 guid[16];
|
||||||
|
int i;
|
||||||
|
BOOL got_kerberos_mechanism = False;
|
||||||
|
|
||||||
negTokenTarg = spnego_gen_negTokenTarg(cli);
|
/* the server sent us the first part of the SPNEGO exchange in the negprot
|
||||||
|
reply */
|
||||||
|
if (!spnego_parse_negTokenInit(cli->secblob, guid, OIDs, &principle)) {
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure the server understands kerberos */
|
||||||
|
for (i=0;OIDs[i];i++) {
|
||||||
|
DEBUG(3,("got OID=%s\n", OIDs[i]));
|
||||||
|
if (strcmp(OIDs[i], "1 2 840 48018 1 2 2") == 0) {
|
||||||
|
got_kerberos_mechanism = True;
|
||||||
|
}
|
||||||
|
free(OIDs[i]);
|
||||||
|
}
|
||||||
|
DEBUG(3,("got principle=%s\n", principle));
|
||||||
|
|
||||||
|
if (!got_kerberos_mechanism) {
|
||||||
|
DEBUG(1,("Server didn't offer kerberos5 mechanism!?\n"));
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* generate the encapsulated kerberos5 ticket */
|
||||||
|
negTokenTarg = spnego_gen_negTokenTarg(cli, principle);
|
||||||
|
|
||||||
|
free(principle);
|
||||||
|
|
||||||
|
if (!negTokenTarg.data) return False;
|
||||||
|
|
||||||
capabilities |= CAP_EXTENDED_SECURITY;
|
capabilities |= CAP_EXTENDED_SECURITY;
|
||||||
|
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
#define OID_SPNEGO "1 3 6 1 5 5 2"
|
#define OID_SPNEGO "1 3 6 1 5 5 2"
|
||||||
#define OID_KERBEROS5 "1 2 840 113554 1 2 2"
|
#define OID_KERBEROS5 "1 2 840 113554 1 2 2"
|
||||||
|
|
||||||
|
#define CHECK_CALL(x) if (! x) goto failed
|
||||||
|
|
||||||
/*
|
/*
|
||||||
we can't use krb5_mk_req because w2k wants the service to be in a particular format
|
we can't use krb5_mk_req because w2k wants the service to be in a particular format
|
||||||
*/
|
*/
|
||||||
@ -34,60 +36,62 @@ static krb5_error_code krb5_mk_req2(krb5_context context,
|
|||||||
krb5_auth_context *auth_context,
|
krb5_auth_context *auth_context,
|
||||||
const krb5_flags ap_req_options,
|
const krb5_flags ap_req_options,
|
||||||
const char *service,
|
const char *service,
|
||||||
krb5_data *in_data,
|
const char *realm,
|
||||||
krb5_ccache ccache,
|
krb5_ccache ccache,
|
||||||
krb5_data *outbuf)
|
krb5_data *outbuf)
|
||||||
{
|
{
|
||||||
krb5_error_code retval;
|
krb5_error_code retval;
|
||||||
krb5_principal server;
|
krb5_principal server;
|
||||||
krb5_creds * credsp;
|
krb5_creds * credsp;
|
||||||
krb5_creds creds;
|
krb5_creds creds;
|
||||||
char *realm;
|
krb5_data in_data;
|
||||||
|
|
||||||
|
retval = krb5_build_principal(context, &server, strlen(realm),
|
||||||
|
realm, service, NULL);
|
||||||
|
if (retval) {
|
||||||
|
DEBUG(1,("Failed to build principle for %s@%s\n", service, realm));
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* obtain ticket & session key */
|
||||||
|
memset((char *)&creds, 0, sizeof(creds));
|
||||||
|
if ((retval = krb5_copy_principal(context, server, &creds.server)))
|
||||||
|
goto cleanup_princ;
|
||||||
|
|
||||||
|
if ((retval = krb5_cc_get_principal(context, ccache, &creds.client)))
|
||||||
|
goto cleanup_creds;
|
||||||
|
|
||||||
/* we should really get the realm from the negTargInit packet,
|
if ((retval = krb5_get_credentials(context, 0,
|
||||||
but this will do until I've done the asn1 decoder for that */
|
ccache, &creds, &credsp))) {
|
||||||
if ((retval = krb5_get_default_realm(context, &realm))) {
|
DEBUG(1,("krb5_get_credentials failed (%d)\n", retval));
|
||||||
return retval;
|
goto cleanup_creds;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = krb5_build_principal(context, &server, strlen(realm),
|
in_data.length = 0;
|
||||||
realm, service, NULL);
|
retval = krb5_mk_req_extended(context, auth_context, ap_req_options,
|
||||||
if (retval)
|
&in_data, credsp, outbuf);
|
||||||
return retval;
|
if (retval) {
|
||||||
|
DEBUG(1,("krb5_mk_req_extended failed (%d)\n", retval));
|
||||||
/* obtain ticket & session key */
|
}
|
||||||
memset((char *)&creds, 0, sizeof(creds));
|
|
||||||
if ((retval = krb5_copy_principal(context, server, &creds.server)))
|
krb5_free_creds(context, credsp);
|
||||||
goto cleanup_princ;
|
|
||||||
|
|
||||||
if ((retval = krb5_cc_get_principal(context, ccache, &creds.client)))
|
|
||||||
goto cleanup_creds;
|
|
||||||
|
|
||||||
if ((retval = krb5_get_credentials(context, 0,
|
|
||||||
ccache, &creds, &credsp)))
|
|
||||||
goto cleanup_creds;
|
|
||||||
|
|
||||||
retval = krb5_mk_req_extended(context, auth_context, ap_req_options,
|
|
||||||
in_data, credsp, outbuf);
|
|
||||||
|
|
||||||
krb5_free_creds(context, credsp);
|
|
||||||
|
|
||||||
cleanup_creds:
|
cleanup_creds:
|
||||||
krb5_free_cred_contents(context, &creds);
|
krb5_free_cred_contents(context, &creds);
|
||||||
|
|
||||||
cleanup_princ:
|
cleanup_princ:
|
||||||
krb5_free_principal(context, server);
|
krb5_free_principal(context, server);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
get a kerberos5 ticket for the given service
|
get a kerberos5 ticket for the given service
|
||||||
*/
|
*/
|
||||||
static DATA_BLOB krb5_get_ticket(char *service)
|
static DATA_BLOB krb5_get_ticket(char *service, char *realm)
|
||||||
{
|
{
|
||||||
krb5_error_code retval;
|
krb5_error_code retval;
|
||||||
krb5_data packet, inbuf;
|
krb5_data packet;
|
||||||
krb5_ccache ccdef;
|
krb5_ccache ccdef;
|
||||||
krb5_context context;
|
krb5_context context;
|
||||||
krb5_auth_context auth_context = NULL;
|
krb5_auth_context auth_context = NULL;
|
||||||
@ -99,8 +103,6 @@ static DATA_BLOB krb5_get_ticket(char *service)
|
|||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
inbuf.length = 0;
|
|
||||||
|
|
||||||
if ((retval = krb5_cc_default(context, &ccdef))) {
|
if ((retval = krb5_cc_default(context, &ccdef))) {
|
||||||
DEBUG(1,("krb5_cc_default failed\n"));
|
DEBUG(1,("krb5_cc_default failed\n"));
|
||||||
goto failed;
|
goto failed;
|
||||||
@ -109,8 +111,8 @@ static DATA_BLOB krb5_get_ticket(char *service)
|
|||||||
if ((retval = krb5_mk_req2(context,
|
if ((retval = krb5_mk_req2(context,
|
||||||
&auth_context,
|
&auth_context,
|
||||||
AP_OPTS_MUTUAL_REQUIRED,
|
AP_OPTS_MUTUAL_REQUIRED,
|
||||||
service,
|
service, realm,
|
||||||
&inbuf, ccdef, &packet))) {
|
ccdef, &packet))) {
|
||||||
DEBUG(1,("krb5_mk_req2 failed\n"));
|
DEBUG(1,("krb5_mk_req2 failed\n"));
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
@ -139,16 +141,16 @@ ASN1_DATA spnego_gen_negTokenInit(uint8 guid[16],
|
|||||||
|
|
||||||
memset(&data, 0, sizeof(data));
|
memset(&data, 0, sizeof(data));
|
||||||
|
|
||||||
asn1_write(&data, guid, 16);
|
CHECK_CALL(asn1_write(&data, guid, 16));
|
||||||
asn1_push_tag(&data,ASN1_APPLICATION(0));
|
CHECK_CALL(asn1_push_tag(&data,ASN1_APPLICATION(0)));
|
||||||
asn1_write_OID(&data,OID_SPNEGO);
|
CHECK_CALL(asn1_write_OID(&data,OID_SPNEGO));
|
||||||
asn1_push_tag(&data,ASN1_CONTEXT(0));
|
CHECK_CALL(asn1_push_tag(&data,ASN1_CONTEXT(0)));
|
||||||
asn1_push_tag(&data,ASN1_SEQUENCE(0));
|
CHECK_CALL(asn1_push_tag(&data,ASN1_SEQUENCE(0)));
|
||||||
|
|
||||||
asn1_push_tag(&data,ASN1_CONTEXT(0));
|
CHECK_CALL(asn1_push_tag(&data,ASN1_CONTEXT(0)));
|
||||||
asn1_push_tag(&data,ASN1_SEQUENCE(0));
|
CHECK_CALL(asn1_push_tag(&data,ASN1_SEQUENCE(0)));
|
||||||
for (i=0; OIDs[i]; i++) {
|
for (i=0; OIDs[i]; i++) {
|
||||||
asn1_write_OID(&data,OIDs[i]);
|
CHECK_CALL(asn1_write_OID(&data,OIDs[i]));
|
||||||
}
|
}
|
||||||
asn1_pop_tag(&data);
|
asn1_pop_tag(&data);
|
||||||
asn1_pop_tag(&data);
|
asn1_pop_tag(&data);
|
||||||
@ -167,6 +169,62 @@ ASN1_DATA spnego_gen_negTokenInit(uint8 guid[16],
|
|||||||
asn1_pop_tag(&data);
|
asn1_pop_tag(&data);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
|
||||||
|
failed:
|
||||||
|
DEBUG(1,("Failed to build negTokenInit at offset %d\n", (int)data.ofs));
|
||||||
|
asn1_free(&data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
parse a negTokenInit packet giving a GUID, a list of supported
|
||||||
|
OIDs (the mechanisms) and a principle name string
|
||||||
|
*/
|
||||||
|
BOOL spnego_parse_negTokenInit(DATA_BLOB blob,
|
||||||
|
uint8 guid[16],
|
||||||
|
char *OIDs[ASN1_MAX_OIDS],
|
||||||
|
char **principle)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
BOOL ret;
|
||||||
|
ASN1_DATA data;
|
||||||
|
|
||||||
|
asn1_load(&data, blob);
|
||||||
|
|
||||||
|
asn1_read(&data, guid, 16);
|
||||||
|
asn1_start_tag(&data,ASN1_APPLICATION(0));
|
||||||
|
asn1_check_OID(&data,OID_SPNEGO);
|
||||||
|
asn1_start_tag(&data,ASN1_CONTEXT(0));
|
||||||
|
asn1_start_tag(&data,ASN1_SEQUENCE(0));
|
||||||
|
|
||||||
|
asn1_start_tag(&data,ASN1_CONTEXT(0));
|
||||||
|
asn1_start_tag(&data,ASN1_SEQUENCE(0));
|
||||||
|
for (i=0; asn1_tag_remaining(&data) > 0 && i < ASN1_MAX_OIDS; i++) {
|
||||||
|
char *oid = NULL;
|
||||||
|
asn1_read_OID(&data,&oid);
|
||||||
|
OIDs[i] = oid;
|
||||||
|
}
|
||||||
|
OIDs[i] = NULL;
|
||||||
|
asn1_end_tag(&data);
|
||||||
|
asn1_end_tag(&data);
|
||||||
|
|
||||||
|
asn1_start_tag(&data, ASN1_CONTEXT(3));
|
||||||
|
asn1_start_tag(&data, ASN1_SEQUENCE(0));
|
||||||
|
asn1_start_tag(&data, ASN1_CONTEXT(0));
|
||||||
|
asn1_read_GeneralString(&data,principle);
|
||||||
|
asn1_end_tag(&data);
|
||||||
|
asn1_end_tag(&data);
|
||||||
|
asn1_end_tag(&data);
|
||||||
|
|
||||||
|
asn1_end_tag(&data);
|
||||||
|
asn1_end_tag(&data);
|
||||||
|
|
||||||
|
asn1_end_tag(&data);
|
||||||
|
|
||||||
|
ret = !data.has_error;
|
||||||
|
asn1_free(&data);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -229,25 +287,28 @@ static ASN1_DATA spnego_gen_krb5_wrap(DATA_BLOB ticket)
|
|||||||
generate a SPNEGO negTokenTarg packet, ready for a EXTENDED_SECURITY
|
generate a SPNEGO negTokenTarg packet, ready for a EXTENDED_SECURITY
|
||||||
kerberos session setup
|
kerberos session setup
|
||||||
*/
|
*/
|
||||||
DATA_BLOB spnego_gen_negTokenTarg(struct cli_state *cli)
|
DATA_BLOB spnego_gen_negTokenTarg(struct cli_state *cli, char *principle)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
fstring service;
|
fstring service;
|
||||||
|
char *realm;
|
||||||
DATA_BLOB tkt, ret;
|
DATA_BLOB tkt, ret;
|
||||||
ASN1_DATA tkt_wrapped, targ;
|
ASN1_DATA tkt_wrapped, targ;
|
||||||
const char *krb_mechs[] =
|
const char *krb_mechs[] =
|
||||||
{"1 2 840 48018 1 2 2", "1 3 6 1 4 1 311 2 2 10", NULL};
|
{"1 2 840 48018 1 2 2", "1 3 6 1 4 1 311 2 2 10", NULL};
|
||||||
|
|
||||||
/* the service name is the WINS name of the server in lowercase with
|
fstrcpy(service, principle);
|
||||||
a $ on the end */
|
p = strchr_m(service, '@');
|
||||||
fstrcpy(service, cli->desthost);
|
if (!p) {
|
||||||
p = strchr_m(service, '.');
|
DEBUG(1,("Malformed principle [%s] in spnego_gen_negTokenTarg\n",
|
||||||
if (p) *p = 0;
|
principle));
|
||||||
fstrcat(service, "$");
|
return data_blob(NULL, 0);
|
||||||
strlower(service);
|
}
|
||||||
|
*p = 0;
|
||||||
|
realm = p+1;
|
||||||
|
|
||||||
/* get a kerberos ticket for the service */
|
/* get a kerberos ticket for the service */
|
||||||
tkt = krb5_get_ticket(service);
|
tkt = krb5_get_ticket(service, realm);
|
||||||
|
|
||||||
/* wrap that up in a nice GSS-API wrapping */
|
/* wrap that up in a nice GSS-API wrapping */
|
||||||
tkt_wrapped = spnego_gen_krb5_wrap(tkt);
|
tkt_wrapped = spnego_gen_krb5_wrap(tkt);
|
||||||
|
Loading…
Reference in New Issue
Block a user