Skip to content

Commit 588d6a1

Browse files
Volodymyr Khomenkosimo5
Volodymyr Khomenko
authored andcommitted
Support get_sids request via name attributes
To allow server to get details about authenticated user new get_sid request by "urn:gssntlmssp:sids" name attribute is implemented (see RFC6680) to report the list of user SIDs. The list of SIDs is stored in gssntlm source_name (part of gss context, can be get by gss_inquire_context) in textual representation - comma-separated list of SIDs. gss_get_name_attribute() and gssntlm_inquire_name() should be used to inquire name attributes. Unit-test for get_sids name attributes: Test is checking memory management for name attributes with gss_duplicate_name, gss_release_name and gss_get_name_attribute / gss_inquire_name API for accessing name attributes in both textual and binary representation. Signed-off-by: Volodymyr Khomenko <[email protected]>
1 parent f93ca02 commit 588d6a1

File tree

7 files changed

+668
-5
lines changed

7 files changed

+668
-5
lines changed

Diff for: src/external.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ uint32_t external_srv_auth(struct gssntlm_ctx *ctx,
7373
return winbind_srv_auth(cred->cred.external.user.data.user.name,
7474
cred->cred.external.user.data.user.domain,
7575
ctx->workstation, chal_ptr,
76-
nt_chal_resp, lm_chal_resp, session_base_key);
76+
nt_chal_resp, lm_chal_resp, session_base_key,
77+
&ctx->source_name.attrs);
7778
#else
7879
return ERR_NOTAVAIL;
7980
#endif

Diff for: src/gss_names.c

+227-1
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,128 @@ uint32_t gssntlm_import_name(uint32_t *minor_status,
281281
output_name);
282282
}
283283

284+
size_t gssntlm_get_attrs_count(const struct gssntlm_name_attribute *attrs)
285+
{
286+
size_t c;
287+
for (c = 0; attrs && attrs[c].attr_name != NULL; c++) ;
288+
return c;
289+
}
290+
291+
int gssntlm_copy_attrs(const struct gssntlm_name_attribute *src,
292+
struct gssntlm_name_attribute **dst)
293+
{
294+
struct gssntlm_name_attribute *copied_attrs;
295+
size_t attrs_count = gssntlm_get_attrs_count(src);
296+
297+
*dst = NULL;
298+
if (attrs_count == 0) {
299+
return 0;
300+
}
301+
302+
copied_attrs = calloc(attrs_count + 1, /* +1 for terminator entry */
303+
sizeof(struct gssntlm_name_attribute));
304+
if (copied_attrs == NULL) {
305+
return ENOMEM;
306+
}
307+
308+
for (size_t i = 0; i < attrs_count; i++) {
309+
/* read-only persistent data ptr can be just copied */
310+
copied_attrs[i].attr_name = src[i].attr_name;
311+
copied_attrs[i].attr_value.length = src[i].attr_value.length;
312+
copied_attrs[i].attr_value.value = malloc(src[i].attr_value.length);
313+
if (copied_attrs[i].attr_value.value == NULL) {
314+
gssntlm_release_attrs(&copied_attrs);
315+
return ENOMEM;
316+
}
317+
memcpy(copied_attrs[i].attr_value.value, src[i].attr_value.value,
318+
src[i].attr_value.length);
319+
}
320+
/* terminator entry is filled with zeroes by calloc */
321+
322+
*dst = copied_attrs;
323+
return 0;
324+
}
325+
326+
/* Low-level func with buffer ownership transfer
327+
* attr_name - read-only static string, should not be released
328+
* attr_value - ownership of that buffer is MOVED to dst
329+
* (MUST NOT BE RELEASED from caller side) */
330+
int gssntlm_append_attr(const char *attr_name, gss_buffer_t attr_value,
331+
struct gssntlm_name *dst)
332+
{
333+
size_t prev_attrs_count = gssntlm_get_attrs_count(dst->attrs);
334+
/* 1 for new attribute +1 for terminator entry */
335+
size_t new_attrs_count = prev_attrs_count + 2;
336+
struct gssntlm_name_attribute *attrs;
337+
338+
if (!attr_name || !attr_value || !dst) {
339+
return ERR_NOARG;
340+
}
341+
342+
/* Increase buffer - if there was no any attributes before,
343+
* realloc is identical to malloc */
344+
attrs = realloc(dst->attrs,
345+
new_attrs_count * sizeof(struct gssntlm_name_attribute));
346+
if (attrs == NULL) {
347+
return ENOMEM;
348+
}
349+
dst->attrs = attrs;
350+
351+
attrs[prev_attrs_count].attr_name = attr_name;
352+
attrs[prev_attrs_count].attr_value.value = attr_value->value;
353+
attrs[prev_attrs_count].attr_value.length = attr_value->length;
354+
355+
/* Fill the last terminator entry with zeroes
356+
beacuse realloc does not init added memory */
357+
memset(&attrs[prev_attrs_count + 1], 0, sizeof(struct gssntlm_name_attribute));
358+
359+
return 0;
360+
}
361+
362+
int gssntlm_append_attr_str(const char *attr_name, const char *attr_value,
363+
struct gssntlm_name *dst)
364+
{
365+
int ret;
366+
gss_buffer_desc buf;
367+
if (!attr_value) {
368+
return ERR_NOARG;
369+
}
370+
buf.value = strdup(attr_value);
371+
if (!buf.value) {
372+
return ENOMEM;
373+
}
374+
buf.length = strlen(attr_value) + 1; /* +1 for EOL */
375+
ret = gssntlm_append_attr(attr_name, &buf, dst);
376+
if (ret) {
377+
free(buf.value);
378+
}
379+
return ret;
380+
}
381+
382+
struct gssntlm_name_attribute *gssntlm_find_attr(
383+
struct gssntlm_name_attribute *attrs,
384+
const char *attr_name,
385+
size_t attr_name_len)
386+
{
387+
for (size_t i = 0; attrs && (attrs[i].attr_name != NULL); i++) {
388+
/* We store attr_name as const static zero-terminated string, so
389+
* it is always zero-terminated */
390+
if (attr_name_len == strlen(attrs[i].attr_name) &&
391+
strncasecmp(attrs[i].attr_name, attr_name, attr_name_len) == 0) {
392+
return &attrs[i];
393+
}
394+
}
395+
return NULL;
396+
}
397+
398+
void gssntlm_release_attrs(struct gssntlm_name_attribute **attrs)
399+
{
400+
for (size_t i = 0; *attrs && (*attrs)[i].attr_name != NULL; i++) {
401+
free((*attrs)[i].attr_value.value);
402+
}
403+
safefree(*attrs);
404+
}
405+
284406
int gssntlm_copy_name(struct gssntlm_name *src, struct gssntlm_name *dst)
285407
{
286408
char *dom = NULL, *usr = NULL, *srv = NULL;
@@ -320,6 +442,9 @@ int gssntlm_copy_name(struct gssntlm_name *src, struct gssntlm_name *dst)
320442
break;
321443
}
322444

445+
ret = gssntlm_copy_attrs(src->attrs, &dst->attrs);
446+
if (ret) goto done;
447+
323448
ret = 0;
324449
done:
325450
if (ret) {
@@ -389,6 +514,7 @@ void gssntlm_int_release_name(struct gssntlm_name *name)
389514
safefree(name->data.server.name);
390515
break;
391516
}
517+
gssntlm_release_attrs(&name->attrs);
392518
name->type = GSSNTLM_NAME_NULL;
393519
}
394520

@@ -626,7 +752,107 @@ uint32_t gssntlm_inquire_name(uint32_t *minor_status,
626752
gss_OID *MN_mech,
627753
gss_buffer_set_t *attrs)
628754
{
629-
return GSS_S_UNAVAILABLE;
755+
uint32_t retmin = 0;
756+
uint32_t retmaj = 0;
757+
uint32_t tmpmin;
758+
const struct gssntlm_name *in = (const struct gssntlm_name *)name;
759+
760+
if (!attrs) {
761+
return GSSERRS(ERR_NOARG, GSS_S_CALL_INACCESSIBLE_WRITE);
762+
}
763+
*attrs = GSS_C_NO_BUFFER_SET;
764+
765+
if (name == GSS_C_NO_NAME) {
766+
return GSSERRS(GSS_S_BAD_NAME, GSS_S_CALL_INACCESSIBLE_READ);
767+
}
768+
769+
for (size_t i = 0; in->attrs && in->attrs[i].attr_name != NULL; i++) {
770+
struct gssntlm_name_attribute *attr = &in->attrs[i];
771+
size_t attr_name_len = strlen(attr->attr_name);
772+
gss_buffer_desc buf;
773+
gss_buffer_t attr_value = &attr->attr_value;
774+
/* +1 for '=' separator and +1 for EOL */
775+
size_t full_string_len = attr_value->length + attr_name_len + 2;
776+
size_t offset = 0;
777+
char *attr_string = malloc(full_string_len);
778+
if (attr_string == NULL) {
779+
set_GSSERR(ENOMEM);
780+
goto done;
781+
}
782+
783+
/* Construct 'attr_name=<attr_value>\0' string */
784+
memcpy(attr_string, attr->attr_name, attr_name_len);
785+
offset += attr_name_len;
786+
787+
attr_string[offset++] = '=';
788+
789+
memcpy(attr_string + offset, attr_value->value, attr_value->length);
790+
offset += attr_value->length;
791+
792+
attr_string[offset] = 0;
793+
794+
/* now add a buffer to output set */
795+
buf.length = full_string_len;
796+
buf.value = attr_string;
797+
retmaj = gss_add_buffer_set_member(&retmin, &buf, attrs);
798+
free(attr_string);
799+
if (retmaj != GSS_S_COMPLETE) goto done;
800+
}
801+
802+
done:
803+
if (retmaj) {
804+
(void)gss_release_buffer_set(&tmpmin, attrs);
805+
}
806+
return GSSERRS(retmin, retmaj);
807+
}
808+
809+
/* RFC6680 - GSSAPI Naming Extensions */
810+
uint32_t gssntlm_get_name_attribute(uint32_t *minor_status,
811+
gss_name_t name,
812+
gss_buffer_t attr,
813+
int *authenticated,
814+
int *complete,
815+
gss_buffer_t value,
816+
gss_buffer_t display_value,
817+
int *more)
818+
{
819+
uint32_t retmin;
820+
uint32_t retmaj;
821+
const struct gssntlm_name *in = (const struct gssntlm_name *)name;
822+
struct gssntlm_name_attribute *found_attr;
823+
824+
if (name == GSS_C_NO_NAME) {
825+
return GSSERRS(GSS_S_BAD_NAME, GSS_S_CALL_INACCESSIBLE_READ);
826+
}
827+
if (attr == NULL) {
828+
return GSSERRS(ERR_NOARG, GSS_S_CALL_INACCESSIBLE_READ);
829+
}
830+
831+
if (display_value) {
832+
display_value->value = NULL;
833+
display_value->length = 0;
834+
}
835+
if (more) { *more = 0; }
836+
if (authenticated) { *authenticated = 0; }
837+
if (complete) { *complete = 0; }
838+
839+
found_attr = gssntlm_find_attr(in->attrs, attr->value, attr->length);
840+
if (!found_attr) {
841+
return GSSERRS(ENOENT, GSS_S_UNAVAILABLE);
842+
}
843+
844+
if (authenticated) { *authenticated = 1; }
845+
if (complete) { *complete = 1; }
846+
if (value) {
847+
gss_buffer_t attr_value = &found_attr->attr_value;
848+
value->value = malloc(attr_value->length);
849+
if (!value->value) {
850+
return GSSERRS(ENOMEM, GSS_S_FAILURE);
851+
}
852+
memcpy(value->value, attr_value->value, attr_value->length);
853+
value->length = attr_value->length;
854+
}
855+
return GSSERRS(0, GSS_S_COMPLETE);
630856
}
631857

632858
/* RFC5801 Extensions */

Diff for: src/gss_ntlmssp.h

+30
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@
4040
#define NTLMSSP_CTX_FLAG_SPNEGO_CAN_MIC 0x02 /* SPNEGO asks for MIC */
4141
#define NTLMSSP_CTX_FLAG_AUTH_WITH_MIC 0x04 /* Auth MIC was created */
4242

43+
struct gssntlm_name_attribute {
44+
const char *attr_name; /* Read-only static string, should not be released */
45+
/* NULL is used to indicate */
46+
/* the terminating element of array */
47+
gss_buffer_desc attr_value;
48+
};
49+
4350
struct gssntlm_name {
4451
enum ntlm_name_type {
4552
GSSNTLM_NAME_NULL,
@@ -57,6 +64,8 @@ struct gssntlm_name {
5764
char *name;
5865
} server;
5966
} data;
67+
68+
struct gssntlm_name_attribute *attrs; /* Array of name attributes */
6069
};
6170

6271
struct gssntlm_cred {
@@ -146,6 +155,9 @@ static inline uint32_t gssntlmssp_ret_err(uint32_t *s, uint32_t n, uint32_t j)
146155
DEBUG_GSS_ERRORS((retmaj = (maj)), (retmin = (min))) ? 0 : \
147156
gssntlmssp_ret_err(minor_status, retmin, retmaj)
148157

158+
/* Static const name attribute for sids list */
159+
extern const char gssntlmssp_sids_urn[];
160+
149161
bool gssntlm_required_security(int security_level, struct gssntlm_ctx *ctx);
150162

151163
void gssntlm_set_role(struct gssntlm_ctx *ctx,
@@ -167,6 +179,15 @@ int gssntlm_get_lm_compatibility_level(void);
167179
void gssntlm_int_release_name(struct gssntlm_name *name);
168180
void gssntlm_int_release_cred(struct gssntlm_cred *cred);
169181

182+
size_t gssntlm_get_attrs_count(const struct gssntlm_name_attribute *attrs);
183+
int gssntlm_copy_attrs(const struct gssntlm_name_attribute *src,
184+
struct gssntlm_name_attribute **dst);
185+
struct gssntlm_name_attribute *gssntlm_find_attr(
186+
struct gssntlm_name_attribute *attrs,
187+
const char *attr_name,
188+
size_t attr_name_len);
189+
void gssntlm_release_attrs(struct gssntlm_name_attribute **attrs);
190+
170191
int gssntlm_copy_name(struct gssntlm_name *src, struct gssntlm_name *dst);
171192
int gssntlm_copy_creds(struct gssntlm_cred *in, struct gssntlm_cred *out);
172193

@@ -391,6 +412,15 @@ uint32_t gssntlm_display_status(uint32_t *minor_status,
391412
uint32_t *message_context,
392413
gss_buffer_t status_string);
393414

415+
uint32_t gssntlm_get_name_attribute(uint32_t *minor_status,
416+
gss_name_t name,
417+
gss_buffer_t attr,
418+
int *authenticated,
419+
int *complete,
420+
gss_buffer_t value,
421+
gss_buffer_t display_value,
422+
int *more);
423+
394424
uint32_t gssntlm_inquire_name(uint32_t *minor_status,
395425
gss_name_t name,
396426
int *name_is_MN,

Diff for: src/gss_ntlmssp_winbind.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ uint32_t winbind_srv_auth(char *user, char *domain,
1717
char *workstation, uint8_t *challenge,
1818
struct ntlm_buffer *nt_chal_resp,
1919
struct ntlm_buffer *lm_chal_resp,
20-
struct ntlm_key *ntlmv2_key);
20+
struct ntlm_key *ntlmv2_key,
21+
struct gssntlm_name_attribute **auth_attrs);

Diff for: src/gss_spi.c

+12
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,18 @@ OM_uint32 gss_release_name(OM_uint32 *minor_status,
147147
return gssntlm_release_name(minor_status,
148148
input_name);
149149
}
150+
OM_uint32 gss_get_name_attribute(OM_uint32 *minor_status,
151+
gss_name_t name,
152+
gss_buffer_t attr,
153+
int *authenticated,
154+
int *complete,
155+
gss_buffer_t value,
156+
gss_buffer_t display_value,
157+
int *more)
158+
{
159+
return gssntlm_get_name_attribute(minor_status, name, attr, authenticated,
160+
complete, value, display_value, more);
161+
}
150162

151163
OM_uint32 gss_context_time(OM_uint32 *minor_status,
152164
gss_ctx_id_t context_handle,

0 commit comments

Comments
 (0)