first stab at SECINFO

handling receiving WRONGSEC error in compound_encode_decode function by
sending either SECINFO or SECINFO_NONAME op to find out available
security flavors from the server. then try to establish new security
context given the ordered list returned by the server.

Not handling if parent directory doesn't permit a security flavor of
its child directory. Example "/" exported with only auth_sys and
"/sec" exported with only "gss".
This commit is contained in:
Olga Kornievskaia 2011-06-30 12:21:07 -04:00
parent 939db9c80b
commit c570ba2383
3 changed files with 189 additions and 7 deletions

View file

@ -30,6 +30,8 @@
#include "nfs41_callback.h"
#include "name_cache.h"
#include "daemon_debug.h"
#include "rpc/rpc.h"
#include "rpc/auth_sspi.h"
#define BUF_SIZE 1024
@ -295,15 +297,63 @@ static bool_t recover_stateid(nfs_argop4 *argop, nfs41_session *session)
return retry;
}
static int create_new_rpc_auth(nfs41_session *session, uint32_t op,
nfs41_secinfo_info *secinfo)
{
AUTH *auth = NULL;
int status = ERROR_NETWORK_UNREACHABLE, i;
uint32_t sec_flavor;
for (i = 0; i < MAX_SECINFOS; i++) {
if (!secinfo[i].sec_flavor && !secinfo[i].type)
goto out;
if (secinfo[i].sec_flavor == RPCSEC_GSS) {
auth = authsspi_create_default(session->client->rpc->rpc,
session->client->rpc->server_name, secinfo[i].type);
if (auth == NULL) {
eprintf("handle_wrongsecinfo_noname: authsspi_create_default for "
"gsstype %s failed\n", gssauth_string(secinfo[i].type));
continue;
}
sec_flavor = secinfo[i].type;
} else {
char machname[MAXHOSTNAMELEN + 1];
gid_t gids[1];
if (gethostname(machname, sizeof(machname)) == -1) {
eprintf("nfs41_rpc_clnt_create: gethostname failed\n");
continue;
}
machname[sizeof(machname) - 1] = '\0';
auth = authsys_create(machname, session->client->rpc->uid,
session->client->rpc->gid, 0, gids);
if (auth == NULL) {
eprintf("handle_wrongsecinfo_noname: authsys_create failed\n");
continue;
}
sec_flavor = AUTH_SYS;
}
AcquireSRWLockExclusive(&session->client->rpc->lock);
session->client->rpc->sec_flavor = sec_flavor;
session->client->rpc->rpc->cl_auth = auth;
ReleaseSRWLockExclusive(&session->client->rpc->lock);
status = 0;
break;
}
out:
return status;
}
int compound_encode_send_decode(
nfs41_session *session,
nfs41_compound *compound,
bool_t try_recovery)
{
int status, retry_count = 0, delayby = 0;
int status, retry_count = 0, delayby = 0, secinfo_status;
nfs41_sequence_args *args =
(nfs41_sequence_args *)compound->args.argarray[0].arg;
bool_t client_state_lost = FALSE;
uint32_t saved_sec_flavor;
AUTH *saved_auth;
retry:
/* send compound */
@ -370,6 +420,7 @@ retry:
if (status) {
eprintf("nfs41_exchange_id() failed with %d\n", status);
status = ERROR_BAD_NET_RESP;
goto out;
}
if (compound->args.argarray[0].op == OP_CREATE_SESSION) {
@ -492,6 +543,124 @@ restart_recovery:
}
}
break;
case NFS4ERR_WRONGSEC:
{
nfs41_secinfo_info secinfo[MAX_SECINFOS];
uint32_t op = compound->args.argarray[compound->res.resarray_count-1].op;
switch(op) {
case OP_PUTFH:
case OP_RESTOREFH:
case OP_LINK:
case OP_RENAME:
case OP_PUTROOTFH:
case OP_LOOKUP:
case OP_OPEN:
case OP_SECINFO_NO_NAME:
case OP_SECINFO:
if (compound->args.argarray[0].op == OP_SEQUENCE) {
nfs41_sequence_args *seq = (nfs41_sequence_args*)
compound->args.argarray[0].arg;
nfs41_session_free_slot(session, seq->sa_slotid);
}
/* from: 2.6.3.1.1.5. Put Filehandle Operation + SECINFO/SECINFO_NO_NAME
* The NFSv4.1 server MUST NOT return NFS4ERR_WRONGSEC to a put
* filehandle operation that is immediately followed by SECINFO or
* SECINFO_NO_NAME. The NFSv4.1 server MUST NOT return NFS4ERR_WRONGSEC
* from SECINFO or SECINFO_NO_NAME.
*/
if (compound->args.argarray[0].op == OP_SEQUENCE &&
(compound->args.argarray[1].op == OP_PUTFH ||
compound->args.argarray[1].op == OP_PUTROOTFH) &&
(compound->args.argarray[2].op == OP_SECINFO_NO_NAME ||
compound->args.argarray[2].op == OP_SECINFO)) {
dprintf(1, "SECINFO: BROKEN SERVER\n");
goto out;
}
if (!try_recovery)
goto out;
if (!recovery_start_or_wait(session->client))
goto do_retry;
ZeroMemory(secinfo, sizeof(nfs41_secinfo_info)*MAX_SECINFOS);
saved_sec_flavor = session->client->rpc->sec_flavor;
saved_auth = session->client->rpc->rpc->cl_auth;
if (op == OP_LOOKUP || op == OP_OPEN) {
const nfs41_component *name;
nfs41_path_fh *file = NULL, tmp;
if (compound->args.argarray[compound->res.resarray_count-2].op == OP_PUTFH) {
nfs41_putfh_args *putfh = (nfs41_putfh_args*)
compound->args.argarray[compound->res.resarray_count-2].arg;
file = putfh->file;
} else if (compound->args.argarray[compound->res.resarray_count-2].op == OP_GETATTR &&
compound->args.argarray[compound->res.resarray_count-3].op == OP_GETFH) {
nfs41_getfh_res *getfh = (nfs41_getfh_res *)
compound->res.resarray[compound->res.resarray_count-3].res;
ZeroMemory(&tmp, sizeof(nfs41_path_fh));
memcpy(&tmp.fh, getfh->fh, sizeof(nfs41_fh));
file = &tmp;
}
else {
recovery_finish(session->client);
goto out;
}
if (op == OP_LOOKUP) {
nfs41_lookup_args *largs = (nfs41_lookup_args *)
compound->args.argarray[compound->res.resarray_count-1].arg;
name = largs->name;
} else if (op == OP_OPEN) {
nfs41_op_open_args *oargs = (nfs41_op_open_args *)
compound->args.argarray[compound->res.resarray_count-1].arg;
name = oargs->claim.u.null.filename;
}
secinfo_status = nfs41_secinfo(session, file, name, secinfo);
if (secinfo_status) {
eprintf("nfs41_secinfo failed with %d\n", secinfo_status);
recovery_finish(session->client);
if (secinfo_status == NFS4ERR_BADSESSION) {
if (compound->args.argarray[0].op == OP_SEQUENCE) {
nfs41_sequence_args *seq =
(nfs41_sequence_args *)compound->args.argarray[0].arg;
nfs41_session_free_slot(session, seq->sa_slotid);
}
goto do_retry;
}
goto out_free_slot;
}
}
else {
nfs41_path_fh *file = NULL;
if (op == OP_PUTFH) {
nfs41_putfh_args *putfh = (nfs41_putfh_args*)
compound->args.argarray[compound->res.resarray_count-1].arg;
file = putfh->file;
}
secinfo_status = nfs41_secinfo_noname(session, file, secinfo);
if (secinfo_status) {
eprintf("nfs41_secinfo_noname failed with %d\n", secinfo_status);
recovery_finish(session->client);
if (compound->args.argarray[0].op == OP_SEQUENCE) {
nfs41_sequence_args *seq =
(nfs41_sequence_args *)compound->args.argarray[0].arg;
nfs41_session_free_slot(session, seq->sa_slotid);
}
goto out_free_slot;
}
}
secinfo_status = create_new_rpc_auth(session, op, secinfo);
if (!secinfo_status) {
auth_destroy(saved_auth);
recovery_finish(session->client);
// Need to retry only
goto do_retry;
} else {
AcquireSRWLockExclusive(&session->client->rpc->lock);
session->client->rpc->rpc->cl_auth = saved_auth;
ReleaseSRWLockExclusive(&session->client->rpc->lock);
recovery_finish(session->client);
}
break;
}
}
}
out_free_slot:
if (compound->args.argarray[0].op == OP_SEQUENCE) {

View file

@ -1682,15 +1682,19 @@ int nfs41_secinfo(
if (status)
goto out;
compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
putfh_args.file = file;
putfh_args.in_recovery = 0;
if (file == NULL)
compound_add_op(&compound, OP_PUTROOTFH, NULL, &putfh_res);
else {
compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
putfh_args.file = file;
putfh_args.in_recovery = 0;
}
compound_add_op(&compound, OP_SECINFO, &secinfo_args, &secinfo_res);
secinfo_args.name = name;
secinfo_res.secinfo = secinfo;
status = compound_encode_send_decode(session, &compound, TRUE);
status = compound_encode_send_decode(session, &compound, FALSE);
if (status)
goto out;
@ -1701,6 +1705,7 @@ out:
int nfs41_secinfo_noname(
IN nfs41_session *session,
IN nfs41_path_fh *file,
OUT nfs41_secinfo_info *secinfo)
{
int status;
@ -1709,6 +1714,7 @@ int nfs41_secinfo_noname(
nfs_resop4 resops[3];
nfs41_sequence_args sequence_args;
nfs41_sequence_res sequence_res;
nfs41_putfh_args putfh_args;
nfs41_putfh_res putfh_res;
nfs41_secinfo_noname_args noname_args;
nfs41_secinfo_noname_res noname_res;
@ -1720,13 +1726,19 @@ int nfs41_secinfo_noname(
if (status)
goto out;
compound_add_op(&compound, OP_PUTROOTFH, NULL, &putfh_res);
if (file == NULL)
compound_add_op(&compound, OP_PUTROOTFH, NULL, &putfh_res);
else {
compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res);
putfh_args.file = file;
putfh_args.in_recovery = 0;
}
compound_add_op(&compound, OP_SECINFO_NO_NAME, &noname_args, &noname_res);
noname_args.type = SECINFO_STYLE4_CURRENT_FH;
noname_res.secinfo = secinfo;
status = compound_encode_send_decode(session, &compound, TRUE);
status = compound_encode_send_decode(session, &compound, FALSE);
if (status)
goto out;

View file

@ -1143,6 +1143,7 @@ int nfs41_secinfo(
int nfs41_secinfo_noname(
IN nfs41_session *session,
IN nfs41_path_fh *file,
OUT nfs41_secinfo_info *secinfo);
enum nfsstat4 pnfs_rpc_layoutget(