diff --git a/daemon/daemon_debug.c b/daemon/daemon_debug.c index e8edcc3..1e6fae5 100644 --- a/daemon/daemon_debug.c +++ b/daemon/daemon_debug.c @@ -506,3 +506,15 @@ void print_sr_status_flags(int level, int flags) fprintf(dlog_file, "SEQ4_STATUS_DEVID_DELETED "); fprintf(dlog_file, "\n"); } + +const char* secflavorop2name(DWORD sec_flavor) +{ + switch(sec_flavor) { + case RPCSEC_AUTH_SYS: return "AUTH_SYS"; + case RPCSEC_AUTHGSS_KRB5: return "AUTHGSS_KRB5"; + case RPCSEC_AUTHGSS_KRB5I: return "AUTHGSS_KRB5I"; + case RPCSEC_AUTHGSS_KRB5P: return "AUTHGSS_KRB5P"; + } + + return "UNKNOWN FLAVOR"; +} \ No newline at end of file diff --git a/daemon/daemon_debug.h b/daemon/daemon_debug.h index e8e3aa2..6c5a13b 100644 --- a/daemon/daemon_debug.h +++ b/daemon/daemon_debug.h @@ -55,7 +55,7 @@ void print_condwait_status(int level, int status); void print_sr_status_flags(int level, int flags); void open_log_files(); void close_log_files(); - +const char* secflavorop2name(DWORD sec_flavor); /* pnfs_debug.c */ enum pnfs_status; diff --git a/daemon/mount.c b/daemon/mount.c index 89b9855..85e9504 100644 --- a/daemon/mount.c +++ b/daemon/mount.c @@ -41,9 +41,11 @@ static int parse_mount(unsigned char *buffer, uint32_t length, nfs41_upcall *upc if(status) goto out; status = get_name(&buffer, &length, &args->path); if(status) goto out; + status = safe_read(&buffer, &length, &args->sec_flavor, sizeof(DWORD)); + if (status) goto out; - dprintf(1, "parsing NFS14_MOUNT: srv_name=%s root=%s\n", - args->hostname, args->path); + dprintf(1, "parsing NFS14_MOUNT: srv_name=%s root=%s sec_flavor=%s\n", + args->hostname, args->path, secflavorop2name(args->sec_flavor)); out: return status; } @@ -74,6 +76,7 @@ static int handle_mount(nfs41_upcall *upcall) // add a mount root->uid = upcall->uid; root->gid = upcall->gid; + root->sec_flavor = args->sec_flavor; status = nfs41_root_mount_addrs(root, &addrs, 0, 0, &client); if (status) { eprintf("nfs41_root_mount() failed with %d\n", status); diff --git a/daemon/namespace.c b/daemon/namespace.c index d7b7f15..e0f71c8 100644 --- a/daemon/namespace.c +++ b/daemon/namespace.c @@ -354,7 +354,7 @@ int nfs41_root_mount_addrs( /* create an rpc client */ status = nfs41_rpc_clnt_create(addrs, root->wsize, root->rsize, !is_data, - root->uid, root->gid, &rpc); + root->uid, root->gid, root->sec_flavor, &rpc); if (status) { eprintf("nfs41_rpc_clnt_create() failed %d\n", status); goto out; diff --git a/daemon/nfs41.h b/daemon/nfs41.h index c62d731..7f3f087 100644 --- a/daemon/nfs41.h +++ b/daemon/nfs41.h @@ -184,6 +184,7 @@ typedef struct __nfs41_root { LONG ref_count; uint32_t uid; uint32_t gid; + DWORD sec_flavor; } nfs41_root; @@ -352,6 +353,7 @@ int nfs41_rpc_clnt_create( IN bool_t needcb, IN uint32_t uid, IN uint32_t gid, + IN uint32_t sec_flavor, OUT nfs41_rpc_clnt **rpc_out); void nfs41_rpc_clnt_free( diff --git a/daemon/nfs41_rpc.c b/daemon/nfs41_rpc.c index 5951bfe..0c243d9 100644 --- a/daemon/nfs41_rpc.c +++ b/daemon/nfs41_rpc.c @@ -25,6 +25,7 @@ #include "daemon_debug.h" #include "nfs41_xdr.h" #include "nfs41_callback.h" +#include "nfs41_driver.h" /* for AUTH_SYS, AUTHGSS_KRB5s defines */ #include "rpc/rpc.h" #define SECURITY_WIN32 @@ -115,6 +116,7 @@ int nfs41_rpc_clnt_create( bool_t needcb, IN uint32_t uid, IN uint32_t gid, + IN uint32_t sec_flavor, OUT nfs41_rpc_clnt **rpc_out) { CLIENT *client; @@ -148,31 +150,44 @@ int nfs41_rpc_clnt_create( status = ERROR_NETWORK_UNREACHABLE; goto out_err_auth; } -#if 0 - // XXX Pick credentials in better manner - if (gethostname(machname, sizeof(machname)) == -1) { - eprintf("nfs41_rpc_clnt_create: gethostname failed\n"); - goto out_free_rpc_clnt; + + switch (sec_flavor) { + case RPCSEC_AUTH_SYS: + if (gethostname(machname, sizeof(machname)) == -1) { + eprintf("nfs41_rpc_clnt_create: gethostname failed\n"); + goto out_free_rpc_clnt; + } + machname[sizeof(machname) - 1] = '\0'; + client->cl_auth = authsys_create(machname, uid, gid, 0, gids); + break; + case RPCSEC_AUTHGSS_KRB5: + client->cl_auth = authsspi_create_default(client, server_name, + RPCSEC_SSPI_SVC_NONE); + break; + case RPCSEC_AUTHGSS_KRB5I: + client->cl_auth = authsspi_create_default(client, server_name, + RPCSEC_SSPI_SVC_INTEGRITY); + break; + case RPCSEC_AUTHGSS_KRB5P: + client->cl_auth = authsspi_create_default(client, server_name, + RPCSEC_SSPI_SVC_PRIVACY); + break; + default: + eprintf("nfs41_rpc_clnt_create: unknown rpcsec flavor %d\n", + sec_flavor); + client->cl_auth = NULL; } - machname[sizeof(machname) - 1] = '\0'; - client->cl_auth = authsys_create(machname, uid, gid, 0, gids); + if (client->cl_auth == NULL) { // XXX log failure in auth creation somewhere // XXX Better error return - eprintf("nfs41_rpc_clnt_create: failed to create AUTHSYS\n"); + eprintf("nfs41_rpc_clnt_create: failed to create %s\n", + secflavorop2name(sec_flavor)); status = ERROR_NETWORK_UNREACHABLE; goto out_err_client; - } else dprintf(1, "nfs41_rpc_clnt_create: successfully created AUTHSYS\n"); -#else - client->cl_auth = authsspi_create_default(client, server_name, RPCSEC_SSPI_SVC_NONE); -#endif - if (client->cl_auth == NULL) { - // XXX log failure in auth creation somewhere - // XXX Better error return - eprintf("nfs41_rpc_clnt_create: failed to create AUTHGSS\n"); - status = ERROR_NETWORK_UNREACHABLE; - goto out_err_client; - } else dprintf(1, "nfs41_rpc_clnt_create: successfully created AUTHGSS\n"); + } else + dprintf(1, "nfs41_rpc_clnt_create: successfully created %s\n", + secflavorop2name(sec_flavor)); free(server_name); rpc->rpc = client; diff --git a/daemon/upcall.h b/daemon/upcall.h index 076347e..21d9829 100644 --- a/daemon/upcall.h +++ b/daemon/upcall.h @@ -32,6 +32,7 @@ typedef struct __mount_upcall_args { const char *hostname; const char *path; nfs41_root *root; + DWORD sec_flavor; } mount_upcall_args; typedef struct __unmount_upcall_args { diff --git a/sys/nfs41_driver.c b/sys/nfs41_driver.c index 627a01f..99d8880 100644 --- a/sys/nfs41_driver.c +++ b/sys/nfs41_driver.c @@ -122,6 +122,7 @@ typedef struct _updowncall_entry { struct { PUNICODE_STRING srv_name; PUNICODE_STRING root; + DWORD sec_flavor; HANDLE session; } Mount; struct { @@ -264,12 +265,17 @@ nfs41_updowncall_list *upcall = NULL, *downcall = NULL; /* In order to cooperate with other network providers, * we only claim paths of the format '\\server\nfs4\path' */ DECLARE_CONST_UNICODE_STRING(NfsPrefix, L"\\nfs4"); +DECLARE_CONST_UNICODE_STRING(AUTH_SYS_NAME, L"sys"); +DECLARE_CONST_UNICODE_STRING(AUTHGSS_KRB5_NAME, L"krb5"); +DECLARE_CONST_UNICODE_STRING(AUTHGSS_KRB5I_NAME, L"krb5i"); +DECLARE_CONST_UNICODE_STRING(AUTHGSS_KRB5P_NAME, L"krb5p"); #define SERVER_NAME_BUFFER_SIZE 1024 #define MOUNT_CONFIG_RW_SIZE_MIN 1024 #define MOUNT_CONFIG_RW_SIZE_DEFAULT 32768 #define MOUNT_CONFIG_RW_SIZE_MAX 65536 +#define MAX_SEC_FLAVOR_LEN 12 typedef struct _NFS41_MOUNT_CONFIG { DWORD ReadSize; @@ -279,6 +285,8 @@ typedef struct _NFS41_MOUNT_CONFIG { UNICODE_STRING SrvName; WCHAR mntpt_buffer[MAX_PATH]; UNICODE_STRING MntPt; + WCHAR sec_flavor[MAX_SEC_FLAVOR_LEN]; + UNICODE_STRING SecFlavor; } NFS41_MOUNT_CONFIG, *PNFS41_MOUNT_CONFIG; typedef struct _NFS41_NETROOT_EXTENSION { @@ -301,6 +309,7 @@ typedef struct _NFS41_V_NET_ROOT_EXTENSION { HANDLE session; BYTE FsAttrs[FS_ATTR_LEN]; LONG FsAttrsLen; + DWORD sec_flavor; } NFS41_V_NET_ROOT_EXTENSION, *PNFS41_V_NET_ROOT_EXTENSION; #define NFS41GetVNetRootExtension(pVNetRoot) \ (((pVNetRoot) == NULL) ? NULL : \ @@ -474,6 +483,17 @@ out: return status; } +const char* secflavorop2name(DWORD sec_flavor) +{ + switch(sec_flavor) { + case RPCSEC_AUTH_SYS: return "AUTH_SYS"; + case RPCSEC_AUTHGSS_KRB5: return "AUTHGSS_KRB5"; + case RPCSEC_AUTHGSS_KRB5I: return "AUTHGSS_KRB5I"; + case RPCSEC_AUTHGSS_KRB5P: return "AUTHGSS_KRB5P"; + } + + return "UNKNOWN FLAVOR"; +} NTSTATUS marshal_nfs41_mount(nfs41_updowncall_entry *entry, unsigned char *buf, ULONG buf_len, @@ -491,7 +511,7 @@ NTSTATUS marshal_nfs41_mount(nfs41_updowncall_entry *entry, else tmp += *len; header_len = *len + length_as_ansi(entry->u.Mount.srv_name) + - length_as_ansi(entry->u.Mount.root); + length_as_ansi(entry->u.Mount.root) + sizeof(entry->u.Mount.sec_flavor); if (header_len > buf_len) { status = STATUS_INSUFFICIENT_RESOURCES; goto out; @@ -500,11 +520,13 @@ NTSTATUS marshal_nfs41_mount(nfs41_updowncall_entry *entry, if (status) goto out; status = marshall_unicode_as_ansi(&tmp, entry->u.Mount.root); if (status) goto out; + RtlCopyMemory(tmp, &entry->u.Mount.sec_flavor, sizeof(entry->u.Mount.sec_flavor)); *len = header_len; - DbgP("server name=%wZ mount point=%wZ\n", - entry->u.Mount.srv_name, entry->u.Mount.root); + DbgP("server name=%wZ mount point=%wZ sec_flavor=%s\n", + entry->u.Mount.srv_name, entry->u.Mount.root, + secflavorop2name(entry->u.Mount.sec_flavor)); out: DbgEx(); return status; @@ -2079,7 +2101,7 @@ static NTSTATUS map_mount_errors(DWORD status) } NTSTATUS nfs41_mount(PUNICODE_STRING srv_name, PUNICODE_STRING root, - PHANDLE session, DWORD *version) + DWORD sec_flavor, PHANDLE session, DWORD *version) { NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; nfs41_updowncall_entry *entry; @@ -2090,6 +2112,7 @@ NTSTATUS nfs41_mount(PUNICODE_STRING srv_name, PUNICODE_STRING root, goto out; entry->u.Mount.srv_name = srv_name; entry->u.Mount.root = root; + entry->u.Mount.sec_flavor = sec_flavor; entry->version = *version; if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) { @@ -2124,6 +2147,10 @@ void nfs41_MountConfig_InitDefaults( Config->MntPt.Length = 0; Config->MntPt.MaximumLength = MAX_PATH; Config->MntPt.Buffer = Config->mntpt_buffer; + Config->SecFlavor.Length = 0; + Config->SecFlavor.MaximumLength = MAX_SEC_FLAVOR_LEN; + Config->SecFlavor.Buffer = Config->sec_flavor; + RtlCopyUnicodeString(&Config->SecFlavor, &AUTH_SYS_NAME); } static NTSTATUS nfs41_MountConfig_ParseBoolean( @@ -2229,6 +2256,13 @@ NTSTATUS nfs41_MountConfig_ParseOptions( else RtlCopyUnicodeString(&Config->MntPt, &usValue); } + else if (wcsncmp(L"sec", Name, NameLen) == 0) + { + if (usValue.Length > Config->SecFlavor.MaximumLength) + status = STATUS_NAME_TOO_LONG; + else + RtlCopyUnicodeString(&Config->SecFlavor, &usValue); + } else { status = STATUS_INVALID_PARAMETER; @@ -2265,6 +2299,22 @@ static NTSTATUS has_nfs_prefix( return status; } +static NTSTATUS map_sec_flavor( + IN PUNICODE_STRING sec_flavor_name, + OUT PDWORD sec_flavor) +{ + if (RtlCompareUnicodeString(sec_flavor_name, &AUTH_SYS_NAME, FALSE) == 0) + *sec_flavor = RPCSEC_AUTH_SYS; + else if (RtlCompareUnicodeString(sec_flavor_name, &AUTHGSS_KRB5_NAME, FALSE) == 0) + *sec_flavor = RPCSEC_AUTHGSS_KRB5; + else if (RtlCompareUnicodeString(sec_flavor_name, &AUTHGSS_KRB5I_NAME, FALSE) == 0) + *sec_flavor = RPCSEC_AUTHGSS_KRB5I; + else if (RtlCompareUnicodeString(sec_flavor_name, &AUTHGSS_KRB5P_NAME, FALSE) == 0) + *sec_flavor = RPCSEC_AUTHGSS_KRB5P; + else return STATUS_INVALID_PARAMETER; + return STATUS_SUCCESS; +} + NTSTATUS nfs41_CreateVNetRoot( IN OUT PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext) { @@ -2338,10 +2388,16 @@ NTSTATUS nfs41_CreateVNetRoot( pSrvCall->pSrvCallName->MaximumLength - sizeof(WCHAR); } + status = map_sec_flavor(&Config.SecFlavor, &pVNetRootContext->sec_flavor); + if (status != STATUS_SUCCESS) { + DbgP("Invalid rpcsec security flavor %wZ\n", &Config.SecFlavor); + goto out; + } + /* send the mount upcall */ DbgP("Server Name %wZ Mount Point %wZ\n", &Config.SrvName, &Config.MntPt); - status = nfs41_mount(&Config.SrvName, &Config.MntPt, + status = nfs41_mount(&Config.SrvName, &Config.MntPt, pVNetRootContext->sec_flavor, &pVNetRootContext->session, &nfs41d_version); if (status != STATUS_SUCCESS) goto out; diff --git a/sys/nfs41_driver.h b/sys/nfs41_driver.h index 56e03b1..4f8d363 100644 --- a/sys/nfs41_driver.h +++ b/sys/nfs41_driver.h @@ -70,6 +70,13 @@ typedef enum _nfs41_opcodes { INVALID_OPCODE } nfs41_opcodes; +enum rpcsec_flavors { + RPCSEC_AUTH_SYS, + RPCSEC_AUTHGSS_KRB5, + RPCSEC_AUTHGSS_KRB5I, + RPCSEC_AUTHGSS_KRB5P +}; + typedef enum _nfs41_init_driver_state { NFS41_INIT_DRIVER_STARTABLE, NFS41_INIT_DRIVER_START_IN_PROGRESS,