diff --git a/daemon/daemon_debug.c b/daemon/daemon_debug.c index bba6af9..5ef1047 100644 --- a/daemon/daemon_debug.c +++ b/daemon/daemon_debug.c @@ -29,6 +29,7 @@ #include "nfs41_driver.h" #include "nfs41_ops.h" #include "service.h" +#include "rpc/rpc.h" static int g_debug_level = DEFAULT_DEBUG_LEVEL; @@ -478,6 +479,27 @@ const char* nfs_error_string(int status) } } +const char* rpc_error_string(int status) +{ + switch (status) + { + case RPC_CANTENCODEARGS: return "RPC_CANTENCODEARGS"; + case RPC_CANTDECODERES: return "RPC_CANTDECODERES"; + case RPC_CANTSEND: return "RPC_CANTSEND"; + case RPC_CANTRECV: return "RPC_CANTRECV"; + case RPC_TIMEDOUT: return "RPC_TIMEDOUT"; + case RPC_INTR: return "RPC_INTR"; + case RPC_UDERROR: return "RPC_UDERROR"; + case RPC_VERSMISMATCH: return "RPC_VERSMISMATCH"; + case RPC_AUTHERROR: return "RPC_AUTHERROR"; + case RPC_PROGUNAVAIL: return "RPC_PROGUNAVAIL"; + case RPC_PROGVERSMISMATCH: return "RPC_PROGVERSMISMATCH"; + case RPC_PROCUNAVAIL: return "RPC_PROCUNAVAIL"; + case RPC_CANTDECODEARGS: return "RPC_CANTDECODEARGS"; + case RPC_SYSTEMERROR: return "RPC_SYSTEMERROR"; + default: return "invalid rpc error code"; + } +} void print_condwait_status(int level, int status) { if (level > g_debug_level) return; diff --git a/daemon/daemon_debug.h b/daemon/daemon_debug.h index 3cf9c02..78660bd 100644 --- a/daemon/daemon_debug.h +++ b/daemon/daemon_debug.h @@ -54,6 +54,7 @@ void print_opcode(int level, DWORD opcode); const char* opcode2string(DWORD opcode); const char* nfs_opnum_to_string(int opnum); const char* nfs_error_string(int status); +const char* rpc_error_string(int status); void print_condwait_status(int level, int status); void print_sr_status_flags(int level, int flags); void open_log_files(); diff --git a/daemon/nfs41.h b/daemon/nfs41.h index f8dd555..c876f7f 100644 --- a/daemon/nfs41.h +++ b/daemon/nfs41.h @@ -114,6 +114,8 @@ typedef struct __nfs41_rpc_clnt { uint32_t wsize; uint32_t rsize; uint32_t version; + uint32_t sec_flavor; + char server_name[NI_MAXHOST]; bool_t is_valid_session; bool_t in_recovery; bool_t needcb; diff --git a/daemon/nfs41_rpc.c b/daemon/nfs41_rpc.c index a6fe228..17ed4c3 100644 --- a/daemon/nfs41_rpc.c +++ b/daemon/nfs41_rpc.c @@ -105,6 +105,45 @@ static int get_client_for_multi_addr( return status; } +int create_rpcsec_auth_client( + IN uint32_t sec_flavor, + IN char *server_name, + CLIENT *client + ) +{ + int status = ERROR_NETWORK_UNREACHABLE; + + switch (sec_flavor) { + 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("create_rpc_auth_client: unknown rpcsec flavor %d\n", + sec_flavor); + client->cl_auth = NULL; + } + + if (client->cl_auth == NULL) { + eprintf("nfs41_rpc_clnt_create: failed to create %s\n", + secflavorop2name(sec_flavor)); + goto out; + } else + dprintf(1, "nfs41_rpc_clnt_create: successfully created %s\n", + secflavorop2name(sec_flavor)); + status = 0; +out: + return status; +} + /* Returns a client structure and an associated lock */ int nfs41_rpc_clnt_create( IN const multi_addr4 *addrs, @@ -121,7 +160,6 @@ int nfs41_rpc_clnt_create( uint32_t addr_index; int status; char machname[MAXHOSTNAMELEN + 1]; - char server_name[NI_MAXHOST]; gid_t gids[1]; rpc = calloc(1, sizeof(nfs41_rpc_clnt)); @@ -141,7 +179,7 @@ int nfs41_rpc_clnt_create( goto out_free_rpc_clnt; } status = get_client_for_multi_addr(addrs, wsize, rsize, needcb?rpc:NULL, - server_name, &client, &addr_index); + rpc->server_name, &client, &addr_index); if (status) { clnt_pcreateerror("connecting failed"); goto out_free_rpc_cond; @@ -153,44 +191,25 @@ int nfs41_rpc_clnt_create( goto out_err_client; } - switch (sec_flavor) { - case RPCSEC_AUTH_SYS: + rpc->sec_flavor = sec_flavor; + if (sec_flavor == RPCSEC_AUTH_SYS) { if (gethostname(machname, sizeof(machname)) == -1) { eprintf("nfs41_rpc_clnt_create: gethostname failed\n"); goto out_err_client; } 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; - } - - if (client->cl_auth == NULL) { - // XXX log failure in auth creation somewhere - // XXX Better error return - eprintf("nfs41_rpc_clnt_create: failed to create %s\n", + } else { + status = create_rpcsec_auth_client(sec_flavor, rpc->server_name, client); + if (status) { + eprintf("nfs41_rpc_clnt_create: failed to establish security " + "context with %s\n", rpc->server_name); + status = ERROR_NETWORK_UNREACHABLE; + goto out_err_client; + } else + dprintf(1, "nfs41_rpc_clnt_create: successfully created %s\n", secflavorop2name(sec_flavor)); - status = ERROR_NETWORK_UNREACHABLE; - goto out_err_client; - } else - dprintf(1, "nfs41_rpc_clnt_create: successfully created %s\n", - secflavorop2name(sec_flavor)); - + } rpc->rpc = client; /* keep a copy of the address and buffer sizes for reconnect */ @@ -267,7 +286,17 @@ static int rpc_reconnect( if (status) goto out_unlock; - client->cl_auth = rpc->rpc->cl_auth; + if(rpc->sec_flavor == RPCSEC_AUTH_SYS) + client->cl_auth = rpc->rpc->cl_auth; + else { + auth_destroy(rpc->rpc->cl_auth); + status = create_rpcsec_auth_client(rpc->sec_flavor, rpc->server_name, client); + if (status) { + eprintf("Failed to reestablish security context\n"); + status = ERROR_NETWORK_UNREACHABLE; + goto out_err_client; + } + } if (send_null(client) != RPC_SUCCESS) { eprintf("rpc_reconnect: send_null failed\n"); status = ERROR_NETWORK_UNREACHABLE; @@ -321,11 +350,13 @@ int nfs41_send_compound( ReleaseSRWLockShared(&rpc->lock); if (rpc_status != RPC_SUCCESS) { - eprintf("clnt_call returned rpc_status=%i\n", rpc_status); + eprintf("clnt_call returned rpc_status = %s\n", + rpc_error_string(rpc_status)); switch(rpc_status) { case RPC_CANTRECV: case RPC_CANTSEND: case RPC_TIMEDOUT: + case RPC_AUTHERROR: if (!rpc->is_valid_session && ++count > 3) { status = ERROR_NETWORK_UNREACHABLE; break; @@ -335,7 +366,7 @@ int nfs41_send_compound( while (rpc_renew_in_progress(rpc, NULL)) { status = WaitForSingleObject(rpc->cond, INFINITE); if (status != WAIT_OBJECT_0) { - dprintf(1, "nfs41_rpc_renew_in_progress: WaitForSingleObject failed\n"); + dprintf(1, "rpc_renew_in_progress: WaitForSingleObject failed\n"); print_condwait_status(1, status); status = ERROR_LOCK_VIOLATION; goto out; @@ -345,13 +376,13 @@ int nfs41_send_compound( } rpc_renew_in_progress(rpc, &one); if (rpc_reconnect(rpc)) - eprintf("Failed to reconnect!\n"); + eprintf("rpc_reconnect: Failed to reconnect!\n"); rpc_renew_in_progress(rpc, &zero); goto try_again; default: eprintf("UNHANDLED RPC_ERROR: %d\n", rpc_status); status = ERROR_NETWORK_UNREACHABLE; - break; + goto out; } goto out; }