Skip to content

Fix hostbased name #66

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/gss_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ uint32_t gssntlm_cli_auth(uint32_t *minor_status,

retmin = ntlm_process_target_info(
ctx->ntlm, protect, target_info,
ctx->target_name.data.server.name,
ctx->target_name.data.server.spn,
&cb, &client_target_info,
&srv_time, add_mic_ptr);
if (retmin) {
Expand Down
102 changes: 78 additions & 24 deletions src/gss_names.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright 2013 Simo Sorce <[email protected]>, see COPYING for license */
/* Copyright 2013-2022 Simo Sorce <[email protected]>, see COPYING for license */

#define _GNU_SOURCE

Expand Down Expand Up @@ -266,9 +266,6 @@ uint32_t gssntlm_import_name_by_mech(uint32_t *minor_status,
gss_OID input_name_type,
gss_name_t *output_name)
{
char hostname[HOST_NAME_MAX + 1] = { 0 };
char struid[12] = { 0 };
uid_t uid;
struct gssntlm_name *name = NULL;
uint32_t retmaj;
uint32_t retmin;
Expand All @@ -291,30 +288,74 @@ uint32_t gssntlm_import_name_by_mech(uint32_t *minor_status,

if (gss_oid_equal(input_name_type, GSS_C_NT_HOSTBASED_SERVICE) ||
gss_oid_equal(input_name_type, GSS_C_NT_HOSTBASED_SERVICE_X)) {
char *spn = NULL;
char *p = NULL;

name->type = GSSNTLM_NAME_SERVER;

retmaj = string_split(&retmin, '@',
input_name_buffer->value,
input_name_buffer->length,
NULL, &name->data.server.name);
if ((retmaj == GSS_S_COMPLETE) ||
(retmaj != GSS_S_UNAVAILABLE)) {
goto done;
if (input_name_buffer->length > 0) {
spn = strndup(input_name_buffer->value, input_name_buffer->length);
if (!spn) {
set_GSSERR(ENOMEM);
goto done;
}
p = memchr(spn, '@', input_name_buffer->length);
if (p && input_name_buffer->length == 1) {
free(spn);
spn = p = NULL;
}
}

/* no seprator, assume only service is provided and try to source
* the local host name */
retmin = gethostname(hostname, HOST_NAME_MAX);
if (retmin) {
set_GSSERR(retmin);
goto done;
}
hostname[HOST_NAME_MAX] = '\0';
name->data.server.name = strdup(hostname);
if (!name->data.server.name) {
set_GSSERR(ENOMEM);
if (p) {
/* Windows expects a SPN not a GSS Name */
if (p != spn) {
*p = '/';
name->data.server.spn = spn;
spn = NULL;
}
p += 1;
name->data.server.name = strdup(p);
if (!name->data.server.name) {
free(spn);
set_GSSERR(ENOMEM);
goto done;
}
} else {
char hostname[HOST_NAME_MAX + 1] = { 0 };
size_t l, r;
/* no seprator, assume only service is provided and try to
* source the local host name */
retmin = gethostname(hostname, HOST_NAME_MAX);
if (retmin) {
free(spn);
set_GSSERR(retmin);
goto done;
}
hostname[HOST_NAME_MAX] = '\0';
if (spn != NULL) {
/* spn = <service> + </> + <hostname> + <\0> */
l = strlen(spn) + 1 + strlen(hostname) + 1;
name->data.server.spn = malloc(l);
if (!name->data.server.spn) {
free(spn);
set_GSSERR(ENOMEM);
goto done;
}
r = snprintf(name->data.server.spn, l, "%s/%s", spn, hostname);
if (r != l - 1) {
free(spn);
set_GSSERR(ENOMEM);
goto done;
}
}
name->data.server.name = strdup(hostname);
if (!name->data.server.name) {
free(spn);
set_GSSERR(ENOMEM);
goto done;
}
}
free(spn);
set_GSSERRS(0, GSS_S_COMPLETE);

} else if (gss_oid_equal(input_name_type, GSS_C_NT_USER_NAME)) {
Expand All @@ -326,13 +367,16 @@ uint32_t gssntlm_import_name_by_mech(uint32_t *minor_status,
&name->data.user.domain,
&name->data.user.name);
} else if (gss_oid_equal(input_name_type, GSS_C_NT_MACHINE_UID_NAME)) {
uid_t uid;

name->type = GSSNTLM_NAME_USER;
name->data.user.domain = NULL;

uid = *(uid_t *)input_name_buffer->value;
retmaj = uid_to_name(&retmin, uid, &name->data.user.name);
} else if (gss_oid_equal(input_name_type, GSS_C_NT_STRING_UID_NAME)) {
char struid[12] = { 0 };
uid_t uid;

name->type = GSSNTLM_NAME_USER;
name->data.user.domain = NULL;
Expand Down Expand Up @@ -454,7 +498,7 @@ void gssntlm_release_attrs(struct gssntlm_name_attribute **attrs)

int gssntlm_copy_name(struct gssntlm_name *src, struct gssntlm_name *dst)
{
char *dom = NULL, *usr = NULL, *srv = NULL;
char *dom = NULL, *usr = NULL, *spn = NULL, *srv = NULL;
int ret;
dst->type = src->type;
switch (src->type) {
Expand All @@ -480,6 +524,14 @@ int gssntlm_copy_name(struct gssntlm_name *src, struct gssntlm_name *dst)
dst->data.user.name = usr;
break;
case GSSNTLM_NAME_SERVER:
if (src->data.server.spn) {
spn = strdup(src->data.server.spn);
if (!spn) {
ret = ENOMEM;
goto done;
}
}
dst->data.server.spn = spn;
if (src->data.server.name) {
srv = strdup(src->data.server.name);
if (!srv) {
Expand All @@ -499,6 +551,7 @@ int gssntlm_copy_name(struct gssntlm_name *src, struct gssntlm_name *dst)
if (ret) {
safefree(dom);
safefree(usr);
safefree(spn);
safefree(srv);
}
return ret;
Expand Down Expand Up @@ -560,6 +613,7 @@ void gssntlm_int_release_name(struct gssntlm_name *name)
safefree(name->data.user.name);
break;
case GSSNTLM_NAME_SERVER:
safefree(name->data.server.spn);
safefree(name->data.server.name);
break;
}
Expand Down Expand Up @@ -635,7 +689,7 @@ uint32_t gssntlm_display_name(uint32_t *minor_status,
}
break;
case GSSNTLM_NAME_SERVER:
out->value = strdup(in->data.server.name);
out->value = strdup(in->data.server.spn);
if (!out->value) {
set_GSSERR(ENOMEM);
goto done;
Expand Down
1 change: 1 addition & 0 deletions src/gss_ntlmssp.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ struct gssntlm_name {
char *name;
} user;
struct {
char *spn;
char *name;
} server;
} data;
Expand Down
32 changes: 11 additions & 21 deletions src/gss_sec_ctx.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ uint32_t gssntlm_init_sec_context(uint32_t *minor_status,
struct gssntlm_ctx *ctx;
struct gssntlm_name *server = NULL;
struct gssntlm_cred *cred = NULL;
char *computer_name = NULL;
char *nb_computer_name = NULL;
char *nb_domain_name = NULL;
struct gssntlm_name *client_name = NULL;
Expand Down Expand Up @@ -165,13 +164,8 @@ uint32_t gssntlm_init_sec_context(uint32_t *minor_status,
if (retmaj) goto done;
}

computer_name = strdup(client_name->data.server.name);
if (!computer_name) {
set_GSSERR(ENOMEM);
goto done;
}

retmin = netbios_get_names(ctx->external_context, computer_name,
retmin = netbios_get_names(ctx->external_context,
client_name->data.server.name,
&nb_computer_name, &nb_domain_name);
if (retmin) {
set_GSSERR(retmin);
Expand Down Expand Up @@ -433,7 +427,6 @@ uint32_t gssntlm_init_sec_context(uint32_t *minor_status,
gssntlm_release_cred(&tmpmin, (gss_cred_id_t *)&cred);
}
gssntlm_release_name(&tmpmin, (gss_name_t *)&client_name);
safefree(computer_name);
safefree(nb_computer_name);
safefree(nb_domain_name);
safefree(trgt_name);
Expand Down Expand Up @@ -532,7 +525,6 @@ uint32_t gssntlm_accept_sec_context(uint32_t *minor_status,
int lm_compat_lvl = -1;
struct ntlm_buffer challenge = { 0 };
struct gssntlm_name *server_name = NULL;
char *computer_name = NULL;
char *nb_computer_name = NULL;
char *nb_domain_name = NULL;
char *chal_target_name;
Expand Down Expand Up @@ -618,13 +610,8 @@ uint32_t gssntlm_accept_sec_context(uint32_t *minor_status,
goto done;
}

computer_name = strdup(server_name->data.server.name);
if (!computer_name) {
set_GSSERR(ENOMEM);
goto done;
}

retmin = netbios_get_names(ctx->external_context, computer_name,
retmin = netbios_get_names(ctx->external_context,
server_name->data.server.name,
&nb_computer_name, &nb_domain_name);
if (retmin) {
set_GSSERR(retmin);
Expand Down Expand Up @@ -731,15 +718,19 @@ uint32_t gssntlm_accept_sec_context(uint32_t *minor_status,
goto done;
}

av_flags = MSVAVFLAGS_UNVERIFIED_SPN;

timestamp = ntlm_timestamp_now();

retmin = ntlm_encode_target_info(ctx->ntlm,
nb_computer_name,
nb_domain_name,
computer_name,
server_name->data.server.name,
NULL, NULL,
NULL, &timestamp,
NULL, NULL, NULL,
&av_flags, &timestamp,
NULL,
server_name->data.server.spn,
NULL,
&target_info);
if (retmin) {
set_GSSERR(retmin);
Expand Down Expand Up @@ -1028,7 +1019,6 @@ uint32_t gssntlm_accept_sec_context(uint32_t *minor_status,
gssntlm_release_name(&tmpmin, (gss_name_t *)&server_name);
gssntlm_release_name(&tmpmin, (gss_name_t *)&gss_usrname);
gssntlm_release_cred(&tmpmin, (gss_cred_id_t *)&usr_cred);
safefree(computer_name);
safefree(nb_computer_name);
safefree(nb_domain_name);
safefree(usr_name);
Expand Down
34 changes: 26 additions & 8 deletions src/gss_serialize.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ struct export_attrs {

struct export_name {
uint8_t type;
struct relmem domain;
struct relmem dom_or_spn;
struct relmem name;
struct export_attrs attrs;
};
Expand All @@ -38,7 +38,7 @@ struct export_keys {
uint32_t seq_num;
};

#define EXPORT_CTX_VER 0x0004
#define EXPORT_CTX_VER 0x0005
struct export_ctx {
uint16_t version;
uint8_t role;
Expand Down Expand Up @@ -211,7 +211,7 @@ static int export_name(struct export_state *state,
if (name->data.user.domain) {
ret = export_data_buffer(state, name->data.user.domain,
strlen(name->data.user.domain),
&exp_name->domain);
&exp_name->dom_or_spn);
if (ret) {
return ret;
}
Expand All @@ -227,6 +227,14 @@ static int export_name(struct export_state *state,
break;
case GSSNTLM_NAME_SERVER:
exp_name->type = EXP_NAME_SERV;
if (name->data.server.spn) {
ret = export_data_buffer(state, name->data.server.spn,
strlen(name->data.server.spn),
&exp_name->dom_or_spn);
if (ret) {
return ret;
}
}
if (name->data.server.name) {
ret = export_data_buffer(state, name->data.server.name,
strlen(name->data.server.name),
Expand Down Expand Up @@ -599,10 +607,10 @@ static uint32_t import_name(uint32_t *minor_status,
case EXP_NAME_USER:
imp_name->type = GSSNTLM_NAME_USER;
dest = NULL;
if (name->domain.len > 0) {
if (name->dom_or_spn.len > 0) {
retmaj = import_data_buffer(&retmin, state,
&dest, NULL, true,
&name->domain, true);
&name->dom_or_spn, true);
if (retmaj != GSS_S_COMPLETE) goto done;
}
imp_name->data.user.domain = (char *)dest;
Expand All @@ -619,6 +627,14 @@ static uint32_t import_name(uint32_t *minor_status,
case EXP_NAME_SERV:
imp_name->type = GSSNTLM_NAME_SERVER;
dest = NULL;
if (name->dom_or_spn.len > 0) {
retmaj = import_data_buffer(&retmin, state,
&dest, NULL, true,
&name->dom_or_spn, true);
if (retmaj != GSS_S_COMPLETE) goto done;
}
imp_name->data.server.spn = (char *)dest;
dest = NULL;
if (name->name.len > 0) {
retmaj = import_data_buffer(&retmin, state,
&dest, NULL, true,
Expand Down Expand Up @@ -878,9 +894,11 @@ uint32_t gssntlm_import_sec_context(uint32_t *minor_status,
return GSSERR();
}

#define EXPORT_CRED_VER 0x0002

#pragma pack(push, 1)
struct export_cred {
uint16_t version; /* 0x00 0x02 */
uint16_t version;
uint16_t type;

struct export_name name; /* user or server name */
Expand Down Expand Up @@ -933,7 +951,7 @@ uint32_t gssntlm_export_cred(uint32_t *minor_status,
state.exp_data = (uint8_t *)&ecred.data - (uint8_t *)&ecred;
state.exp_len = state.exp_data;

ecred.version = htole16(1);
ecred.version = htole16(EXPORT_CRED_VER);

switch (cred->type) {
case GSSNTLM_CRED_NONE:
Expand Down Expand Up @@ -1052,7 +1070,7 @@ uint32_t gssntlm_import_cred(uint32_t *minor_status,
ecred = (struct export_cred *)state.exp_struct;
state.exp_data = (char *)ecred->data - (char *)ecred;

if (ecred->version != le16toh(1)) {
if (ecred->version != le16toh(EXPORT_CRED_VER)) {
set_GSSERRS(ERR_BADARG, GSS_S_DEFECTIVE_TOKEN);
goto done;
}
Expand Down
Loading