Skip to content

Commit e4bf01c

Browse files
committed
gp_export: Add facility to export creds as gssx options
Add Initial test implementation of the Linux Kernel NFS creds structure.
1 parent 3639ccb commit e4bf01c

File tree

3 files changed

+268
-0
lines changed

3 files changed

+268
-0
lines changed

proxy/src/gp_export.c

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#include "gp_export.h"
3232
#include "gp_debug.h"
3333
#include <gssapi/gssapi_krb5.h>
34+
#include <pwd.h>
35+
#include <grp.h>
3436

3537
/* FIXME: F I X M E
3638
*
@@ -426,3 +428,248 @@ uint32_t gp_import_gssx_to_ctx_id(uint32_t *min, int type,
426428
return gss_import_sec_context(min, &export_buffer, out);
427429
}
428430

431+
/* Exported Creds */
432+
433+
#define EXP_CREDS_TYPE_OPTION "exported_creds_type"
434+
#define LINUX_CREDS_V1 "linux_creds_v1"
435+
436+
enum exp_creds_types {
437+
EXP_CREDS_NO_CREDS = 0,
438+
EXP_CREDS_LINUX_V1 = 1,
439+
};
440+
441+
int gp_get_export_creds_type(struct gssx_call_ctx *ctx)
442+
{
443+
444+
struct gssx_option *val;
445+
int i;
446+
447+
for (i = 0; i < ctx->options.options_len; i++) {
448+
val = &ctx->options.options_val[i];
449+
if (val->option.octet_string_len == sizeof(EXP_CREDS_TYPE_OPTION) &&
450+
strncmp(EXP_CREDS_TYPE_OPTION,
451+
val->option.octet_string_val,
452+
val->option.octet_string_len) == 0) {
453+
if (strncmp(LINUX_CREDS_V1,
454+
val->value.octet_string_val,
455+
val->value.octet_string_len) == 0) {
456+
return EXP_CREDS_LINUX_V1;
457+
}
458+
return -1;
459+
}
460+
}
461+
462+
return EXP_CREDS_NO_CREDS;
463+
}
464+
465+
#define CREDS_BUF_MAX (NGROUPS_MAX * sizeof(int32_t))
466+
#define CREDS_HDR (3 * sizeof(int32_t)) /* uid, gid, count */
467+
468+
static uint32_t gp_export_creds_enoent(uint32_t *min, gss_buffer_t buf)
469+
{
470+
int32_t *p;
471+
472+
p = malloc(CREDS_HDR);
473+
if (!p) {
474+
*min = ENOMEM;
475+
return GSS_S_FAILURE;
476+
}
477+
p[0] = -1; /* uid */
478+
p[1] = -1; /* gid */
479+
p[2] = 0; /* num groups */
480+
481+
buf->value = p;
482+
buf->length = CREDS_HDR;
483+
*min = 0;
484+
return GSS_S_COMPLETE;
485+
}
486+
487+
static uint32_t gp_export_creds_linux(uint32_t *min, gss_name_t name,
488+
gss_const_OID mech, gss_buffer_t buf)
489+
{
490+
gss_buffer_desc localname;
491+
uint32_t ret_maj;
492+
uint32_t ret_min;
493+
struct passwd pwd, *res;
494+
char *pwbuf = NULL;
495+
char *grbuf = NULL;
496+
int32_t *p;
497+
size_t len;
498+
int count, num;
499+
int ret;
500+
501+
/* We use gss_localname() to map the name. Then just use nsswitch to
502+
* look up the user.
503+
*
504+
* (TODO: If gss_localname() fails we may wanto agree with SSSD on a name
505+
* format to match principal names, es: gss:[email protected], or just
506+
* [email protected]) until sssd can provide a libkrb5 interface to augment
507+
* gss_localname() resolution for trusted realms */
508+
509+
ret_maj = gss_localname(&ret_min, name, mech, &localname);
510+
if (ret_maj) {
511+
if (ret_min == ENOENT) {
512+
return gp_export_creds_enoent(min, buf);
513+
}
514+
*min = ret_min;
515+
return ret_maj;
516+
}
517+
518+
len = 1024;
519+
pwbuf = malloc(len);
520+
if (!pwbuf) {
521+
ret_min = ENOMEM;
522+
ret_maj = GSS_S_FAILURE;
523+
goto done;
524+
}
525+
ret = 0;
526+
do {
527+
if (ret == ERANGE) {
528+
if (len == CREDS_BUF_MAX) {
529+
ret_min = ENOSPC;
530+
ret_maj = GSS_S_FAILURE;
531+
goto done;
532+
}
533+
len *= 2;
534+
if (len > CREDS_BUF_MAX) {
535+
len = CREDS_BUF_MAX;
536+
}
537+
p = realloc(pwbuf, len);
538+
if (!p) {
539+
ret_min = ENOMEM;
540+
ret_maj = GSS_S_FAILURE;
541+
goto done;
542+
}
543+
pwbuf = (char *)p;
544+
}
545+
ret = getpwnam_r((char *)localname.value, &pwd, pwbuf, len, &res);
546+
} while (ret == EINTR || ret == ERANGE);
547+
548+
switch (ret) {
549+
case 0:
550+
if (res != NULL) {
551+
break;
552+
}
553+
/* fall through as ret == NULL is equivalent to ENOENT */
554+
case ENOENT:
555+
case ESRCH:
556+
free(pwbuf);
557+
return gp_export_creds_enoent(min, buf);
558+
default:
559+
ret_min = ret;
560+
ret_maj = GSS_S_FAILURE;
561+
goto done;
562+
}
563+
564+
/* start with a reasonably sized buffer */
565+
count = 256;
566+
num = 0;
567+
do {
568+
if (count >= NGROUPS_MAX) {
569+
ret_min = ENOSPC;
570+
ret_maj = GSS_S_FAILURE;
571+
goto done;
572+
}
573+
count *= 2;
574+
if (count < num) {
575+
count = num;
576+
}
577+
if (count > NGROUPS_MAX) {
578+
count = NGROUPS_MAX;
579+
}
580+
len = count * sizeof(int32_t);
581+
p = realloc(grbuf, len + CREDS_HDR);
582+
if (!p) {
583+
ret_min = ENOMEM;
584+
ret_maj = GSS_S_FAILURE;
585+
goto done;
586+
}
587+
grbuf = (char *)p;
588+
num = count;
589+
ret = getgrouplist(pwd.pw_name, pwd.pw_gid, (gid_t *)&p[3], &num);
590+
} while (ret == -1);
591+
592+
/* we got the buffer, now fill in [uid, gid, num] and we are done */
593+
p[0] = pwd.pw_uid;
594+
p[1] = pwd.pw_gid;
595+
p[2] = num;
596+
buf->value = p;
597+
buf->length = (num + 3) * sizeof(int32_t);
598+
ret_min = 0;
599+
ret_maj = GSS_S_COMPLETE;
600+
601+
done:
602+
if (ret_maj) {
603+
free(grbuf);
604+
}
605+
free(pwbuf);
606+
*min = ret_min;
607+
return ret_maj;
608+
}
609+
610+
uint32_t gp_export_creds_to_gssx_options(uint32_t *min, int type,
611+
gss_name_t src_name,
612+
gss_const_OID mech_type,
613+
unsigned int *opt_num,
614+
gssx_option **opt_array)
615+
{
616+
gss_buffer_desc export_buffer = GSS_C_EMPTY_BUFFER;
617+
unsigned int num;
618+
gssx_option *opta;
619+
uint32_t ret_min;
620+
uint32_t ret_maj;
621+
622+
switch (type) {
623+
case EXP_CREDS_NO_CREDS:
624+
*min = 0;
625+
return GSS_S_COMPLETE;
626+
627+
case EXP_CREDS_LINUX_V1:
628+
ret_maj = gp_export_creds_linux(&ret_min, src_name,
629+
mech_type, &export_buffer);
630+
if (ret_maj) {
631+
if (ret_min == ENOENT) {
632+
/* if not user, return w/o adding anything to the array */
633+
ret_min = 0;
634+
ret_maj = GSS_S_COMPLETE;
635+
}
636+
*min = ret_min;
637+
return ret_maj;
638+
}
639+
break;
640+
641+
default:
642+
*min = EINVAL;
643+
return GSS_S_FAILURE;
644+
}
645+
646+
num = *opt_num;
647+
opta = realloc(*opt_array, sizeof(gssx_option) * (num + 1));
648+
if (!opta) {
649+
ret_min = ENOMEM;
650+
ret_maj = GSS_S_FAILURE;
651+
goto done;
652+
}
653+
opta[num].option.octet_string_val = strdup(LINUX_CREDS_V1);
654+
if (!opta[num].option.octet_string_val) {
655+
ret_min = ENOMEM;
656+
ret_maj = GSS_S_FAILURE;
657+
goto done;
658+
}
659+
opta[num].option.octet_string_len = sizeof(LINUX_CREDS_V1);
660+
opta[num].value.octet_string_val = export_buffer.value;
661+
opta[num].value.octet_string_len = export_buffer.length;
662+
663+
num++;
664+
*opt_num = num;
665+
*opt_array = opta;
666+
ret_min = 0;
667+
ret_maj = GSS_S_COMPLETE;
668+
669+
done:
670+
*min = ret_min;
671+
if (ret_maj) {
672+
gss_release_buffer(&ret_min, &export_buffer);
673+
}
674+
return ret_maj;
675+
}

proxy/src/gp_export.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,11 @@ uint32_t gp_export_ctx_id_to_gssx(uint32_t *min, int type,
4040
uint32_t gp_import_gssx_to_ctx_id(uint32_t *min, int type,
4141
gssx_ctx *in, gss_ctx_id_t *out);
4242

43+
int gp_get_export_creds_type(struct gssx_call_ctx *ctx);
44+
uint32_t gp_export_creds_to_gssx_options(uint32_t *min, int type,
45+
gss_name_t src_name,
46+
gss_const_OID mech_type,
47+
unsigned int *opt_num,
48+
gssx_option **opt_array);
49+
4350
#endif /* _GSS_EXPORT_H_ */

proxy/src/gp_rpc_accept_sec_context.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ int gp_accept_sec_context(struct gssproxy_ctx *gpctx,
4646
gss_cred_id_t dch = GSS_C_NO_CREDENTIAL;
4747
gss_cred_id_t *pdch = NULL;
4848
int exp_ctx_type;
49+
int exp_creds_type;
4950
int ret;
5051

5152
asca = &arg->accept_sec_context;
@@ -58,6 +59,13 @@ int gp_accept_sec_context(struct gssproxy_ctx *gpctx,
5859
goto done;
5960
}
6061

62+
exp_creds_type = gp_get_export_creds_type(&asca->call_ctx);
63+
if (exp_creds_type == -1) {
64+
ret_maj = GSS_S_FAILURE;
65+
ret_min = EINVAL;
66+
goto done;
67+
}
68+
6169
if (asca->cred_handle) {
6270
ret = gp_find_cred(asca->cred_handle, &ach);
6371
if (ret) {
@@ -146,6 +154,12 @@ int gp_accept_sec_context(struct gssproxy_ctx *gpctx,
146154
}
147155
}
148156

157+
ret_maj = gp_export_creds_to_gssx_options(&ret_min,
158+
exp_creds_type,
159+
src_name, oid,
160+
&ascr->options.options_len,
161+
&ascr->options.options_val);
162+
149163
done:
150164
ret = gp_conv_status_to_gssx(&asca->call_ctx,
151165
ret_maj, ret_min, oid,

0 commit comments

Comments
 (0)