X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fgssd%2Fsvcgssd_proc.c;fp=utils%2Fgssd%2Fsvcgssd_proc.c;h=f1bfbef7b57a3b63428c3ab278e97c31966252ff;hp=6f2ba61e31edfc62c5b60bf379c80b0631690299;hb=b695dbb65bb199e3a9ed5a9f780ed2e575061b46;hpb=2905358524c0835311501bad04c521479b0525ff diff --git a/utils/gssd/svcgssd_proc.c b/utils/gssd/svcgssd_proc.c index 6f2ba61..f1bfbef 100644 --- a/utils/gssd/svcgssd_proc.c +++ b/utils/gssd/svcgssd_proc.c @@ -56,6 +56,7 @@ #include "gss_util.h" #include "err_util.h" #include "context.h" +#include "gss_oids.h" extern char * mech2file(gss_OID mech); #define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.rpcsec.context/channel" @@ -73,7 +74,7 @@ struct svc_cred { static int do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred, gss_OID mech, gss_buffer_desc *context_token, - int32_t endtime) + int32_t endtime, char *client_name) { FILE *f; int i; @@ -98,9 +99,10 @@ do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred, qword_printint(f, cred->cr_gid); qword_printint(f, cred->cr_ngroups); printerr(2, "mech: %s, hndl len: %d, ctx len %d, timeout: %d (%d from now), " - "uid: %d, gid: %d, num aux grps: %d:\n", + "clnt: %s, uid: %d, gid: %d, num aux grps: %d:\n", fname, out_handle->length, context_token->length, endtime, endtime - time(0), + client_name ? client_name : "", cred->cr_uid, cred->cr_gid, cred->cr_ngroups); for (i=0; i < cred->cr_ngroups; i++) { qword_printint(f, cred->cr_groups[i]); @@ -108,6 +110,8 @@ do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred, } qword_print(f, fname); qword_printhex(f, context_token->value, context_token->length); + if (client_name) + qword_print(f, client_name); err = qword_eol(f); if (err) { printerr(1, "WARNING: error writing to downcall channel " @@ -307,6 +311,75 @@ print_hexl(const char *description, unsigned char *cp, int length) } #endif +static int +get_krb5_hostbased_name (gss_buffer_desc *name, char **hostbased_name) +{ + char *p, *sname = NULL; + if (strchr(name->value, '@') && strchr(name->value, '/')) { + if ((sname = calloc(name->length, 1)) == NULL) { + printerr(0, "ERROR: get_krb5_hostbased_name failed " + "to allocate %d bytes\n", name->length); + return -1; + } + /* read in name and instance and replace '/' with '@' */ + sscanf(name->value, "%[^@]", sname); + p = strrchr(sname, '/'); + if (p == NULL) { /* The '@' preceeded the '/' */ + free(sname); + return -1; + } + *p = '@'; + } + *hostbased_name = sname; + return 0; +} + +static int +get_hostbased_client_name(gss_name_t client_name, gss_OID mech, + char **hostbased_name) +{ + u_int32_t maj_stat, min_stat; + gss_buffer_desc name; + gss_OID name_type = GSS_C_NO_OID; + char *cname; + int res = -1; + + *hostbased_name = NULL; /* preset in case we fail */ + + /* Get the client's gss authenticated name */ + maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type); + if (maj_stat != GSS_S_COMPLETE) { + pgsserr("get_hostbased_client_name: gss_display_name", + maj_stat, min_stat, mech); + goto out_err; + } + if (name.length >= 0xffff) { /* don't overflow */ + printerr(0, "ERROR: get_hostbased_client_name: " + "received gss_name is too long (%d bytes)\n", + name.length); + goto out_rel_buf; + } + + /* For Kerberos, transform the NT_KRB5_PRINCIPAL name to + * an NT_HOSTBASED_SERVICE name */ + if (g_OID_equal(&krb5oid, mech)) { + if (get_krb5_hostbased_name(&name, &cname) == 0) + *hostbased_name = cname; + } + + /* No support for SPKM3, just print a warning (for now) */ + if (g_OID_equal(&spkm3oid, mech)) { + printerr(1, "WARNING: get_hostbased_client_name: " + "no hostbased_name support for SPKM3\n"); + } + + res = 0; +out_rel_buf: + gss_release_buffer(&min_stat, &name); +out_err: + return res; +} + void handle_nullreq(FILE *f) { /* XXX initialize to a random integer to reduce chances of unnecessary @@ -325,7 +398,7 @@ handle_nullreq(FILE *f) { null_token = {.value = NULL}; u_int32_t ret_flags; gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; - gss_name_t client_name; + gss_name_t client_name = NULL; gss_OID mech = GSS_C_NO_OID; u_int32_t maj_stat = GSS_S_FAILURE, min_stat = 0; u_int32_t ignore_min_stat; @@ -334,6 +407,7 @@ handle_nullreq(FILE *f) { static int lbuflen = 0; static char *cp; int32_t ctx_endtime; + char *hostbased_name = NULL; printerr(1, "handling null request\n"); @@ -396,11 +470,13 @@ handle_nullreq(FILE *f) { if (get_ids(client_name, mech, &cred)) { /* get_ids() prints error msg */ maj_stat = GSS_S_BAD_NAME; /* XXX ? */ - gss_release_name(&ignore_min_stat, &client_name); goto out_err; } - gss_release_name(&ignore_min_stat, &client_name); - + if (get_hostbased_client_name(client_name, mech, &hostbased_name)) { + /* get_hostbased_client_name() prints error msg */ + maj_stat = GSS_S_BAD_NAME; /* XXX ? */ + goto out_err; + } /* Context complete. Pass handle_seq in out_handle to use * for context lookup in the kernel. */ @@ -419,7 +495,8 @@ handle_nullreq(FILE *f) { /* We no longer need the gss context */ gss_delete_sec_context(&ignore_min_stat, &ctx, &ignore_out_tok); - do_svc_downcall(&out_handle, &cred, mech, &ctx_token, ctx_endtime); + do_svc_downcall(&out_handle, &cred, mech, &ctx_token, ctx_endtime, + hostbased_name); continue_needed: send_response(f, &in_handle, &in_tok, maj_stat, min_stat, &out_handle, &out_tok); @@ -428,6 +505,9 @@ out: free(ctx_token.value); if (out_tok.value != NULL) gss_release_buffer(&ignore_min_stat, &out_tok); + if (client_name) + gss_release_name(&ignore_min_stat, &client_name); + free(hostbased_name); printerr(1, "finished handling null request\n"); return;