|
@@ -46,6 +46,7 @@
|
|
#include <linux/kdev_t.h>
|
|
#include <linux/kdev_t.h>
|
|
#include <linux/sunrpc/clnt.h>
|
|
#include <linux/sunrpc/clnt.h>
|
|
#include <linux/sunrpc/msg_prot.h>
|
|
#include <linux/sunrpc/msg_prot.h>
|
|
|
|
+#include <linux/sunrpc/gss_api.h>
|
|
#include <linux/nfs.h>
|
|
#include <linux/nfs.h>
|
|
#include <linux/nfs4.h>
|
|
#include <linux/nfs4.h>
|
|
#include <linux/nfs_fs.h>
|
|
#include <linux/nfs_fs.h>
|
|
@@ -253,6 +254,8 @@ static int nfs4_stat_to_errno(int);
|
|
(encode_getattr_maxsz)
|
|
(encode_getattr_maxsz)
|
|
#define decode_fs_locations_maxsz \
|
|
#define decode_fs_locations_maxsz \
|
|
(0)
|
|
(0)
|
|
|
|
+#define encode_secinfo_maxsz (op_encode_hdr_maxsz + nfs4_name_maxsz)
|
|
|
|
+#define decode_secinfo_maxsz (op_decode_hdr_maxsz + 4 + (NFS_MAX_SECFLAVORS * (16 + GSS_OID_MAX_LEN)))
|
|
|
|
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
#define NFS4_MAX_MACHINE_NAME_LEN (64)
|
|
#define NFS4_MAX_MACHINE_NAME_LEN (64)
|
|
@@ -676,6 +679,14 @@ static int nfs4_stat_to_errno(int);
|
|
decode_putfh_maxsz + \
|
|
decode_putfh_maxsz + \
|
|
decode_lookup_maxsz + \
|
|
decode_lookup_maxsz + \
|
|
decode_fs_locations_maxsz)
|
|
decode_fs_locations_maxsz)
|
|
|
|
+#define NFS4_enc_secinfo_sz (compound_encode_hdr_maxsz + \
|
|
|
|
+ encode_sequence_maxsz + \
|
|
|
|
+ encode_putfh_maxsz + \
|
|
|
|
+ encode_secinfo_maxsz)
|
|
|
|
+#define NFS4_dec_secinfo_sz (compound_decode_hdr_maxsz + \
|
|
|
|
+ decode_sequence_maxsz + \
|
|
|
|
+ decode_putfh_maxsz + \
|
|
|
|
+ decode_secinfo_maxsz)
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
#define NFS4_enc_exchange_id_sz \
|
|
#define NFS4_enc_exchange_id_sz \
|
|
(compound_encode_hdr_maxsz + \
|
|
(compound_encode_hdr_maxsz + \
|
|
@@ -1620,6 +1631,18 @@ static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *state
|
|
hdr->replen += decode_delegreturn_maxsz;
|
|
hdr->replen += decode_delegreturn_maxsz;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void encode_secinfo(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
|
|
|
|
+{
|
|
|
|
+ int len = name->len;
|
|
|
|
+ __be32 *p;
|
|
|
|
+
|
|
|
|
+ p = reserve_space(xdr, 8 + len);
|
|
|
|
+ *p++ = cpu_to_be32(OP_SECINFO);
|
|
|
|
+ xdr_encode_opaque(p, name->name, len);
|
|
|
|
+ hdr->nops++;
|
|
|
|
+ hdr->replen += decode_secinfo_maxsz;
|
|
|
|
+}
|
|
|
|
+
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
/* NFSv4.1 operations */
|
|
/* NFSv4.1 operations */
|
|
static void encode_exchange_id(struct xdr_stream *xdr,
|
|
static void encode_exchange_id(struct xdr_stream *xdr,
|
|
@@ -2465,6 +2488,24 @@ static void nfs4_xdr_enc_fs_locations(struct rpc_rqst *req,
|
|
encode_nops(&hdr);
|
|
encode_nops(&hdr);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Encode SECINFO request
|
|
|
|
+ */
|
|
|
|
+static void nfs4_xdr_enc_secinfo(struct rpc_rqst *req,
|
|
|
|
+ struct xdr_stream *xdr,
|
|
|
|
+ struct nfs4_secinfo_arg *args)
|
|
|
|
+{
|
|
|
|
+ struct compound_hdr hdr = {
|
|
|
|
+ .minorversion = nfs4_xdr_minorversion(&args->seq_args),
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ encode_compound_hdr(xdr, req, &hdr);
|
|
|
|
+ encode_sequence(xdr, &args->seq_args, &hdr);
|
|
|
|
+ encode_putfh(xdr, args->dir_fh, &hdr);
|
|
|
|
+ encode_secinfo(xdr, args->name, &hdr);
|
|
|
|
+ encode_nops(&hdr);
|
|
|
|
+}
|
|
|
|
+
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
/*
|
|
/*
|
|
* EXCHANGE_ID request
|
|
* EXCHANGE_ID request
|
|
@@ -4680,6 +4721,73 @@ static int decode_delegreturn(struct xdr_stream *xdr)
|
|
return decode_op_hdr(xdr, OP_DELEGRETURN);
|
|
return decode_op_hdr(xdr, OP_DELEGRETURN);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int decode_secinfo_gss(struct xdr_stream *xdr, struct nfs4_secinfo_flavor *flavor)
|
|
|
|
+{
|
|
|
|
+ __be32 *p;
|
|
|
|
+
|
|
|
|
+ p = xdr_inline_decode(xdr, 4);
|
|
|
|
+ if (unlikely(!p))
|
|
|
|
+ goto out_overflow;
|
|
|
|
+ flavor->gss.sec_oid4.len = be32_to_cpup(p);
|
|
|
|
+ if (flavor->gss.sec_oid4.len > GSS_OID_MAX_LEN)
|
|
|
|
+ goto out_err;
|
|
|
|
+
|
|
|
|
+ p = xdr_inline_decode(xdr, flavor->gss.sec_oid4.len);
|
|
|
|
+ if (unlikely(!p))
|
|
|
|
+ goto out_overflow;
|
|
|
|
+ memcpy(flavor->gss.sec_oid4.data, p, flavor->gss.sec_oid4.len);
|
|
|
|
+
|
|
|
|
+ p = xdr_inline_decode(xdr, 8);
|
|
|
|
+ if (unlikely(!p))
|
|
|
|
+ goto out_overflow;
|
|
|
|
+ flavor->gss.qop4 = be32_to_cpup(p++);
|
|
|
|
+ flavor->gss.service = be32_to_cpup(p);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+out_overflow:
|
|
|
|
+ print_overflow_msg(__func__, xdr);
|
|
|
|
+ return -EIO;
|
|
|
|
+out_err:
|
|
|
|
+ return -EINVAL;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)
|
|
|
|
+{
|
|
|
|
+ struct nfs4_secinfo_flavor *sec_flavor;
|
|
|
|
+ int status;
|
|
|
|
+ __be32 *p;
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ status = decode_op_hdr(xdr, OP_SECINFO);
|
|
|
|
+ p = xdr_inline_decode(xdr, 4);
|
|
|
|
+ if (unlikely(!p))
|
|
|
|
+ goto out_overflow;
|
|
|
|
+ res->flavors->num_flavors = be32_to_cpup(p);
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < res->flavors->num_flavors; i++) {
|
|
|
|
+ sec_flavor = &res->flavors->flavors[i];
|
|
|
|
+ if ((char *)&sec_flavor[1] - (char *)res > PAGE_SIZE)
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ p = xdr_inline_decode(xdr, 4);
|
|
|
|
+ if (unlikely(!p))
|
|
|
|
+ goto out_overflow;
|
|
|
|
+ sec_flavor->flavor = be32_to_cpup(p);
|
|
|
|
+
|
|
|
|
+ if (sec_flavor->flavor == RPC_AUTH_GSS) {
|
|
|
|
+ if (decode_secinfo_gss(xdr, sec_flavor))
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+out_overflow:
|
|
|
|
+ print_overflow_msg(__func__, xdr);
|
|
|
|
+ return -EIO;
|
|
|
|
+}
|
|
|
|
+
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
static int decode_exchange_id(struct xdr_stream *xdr,
|
|
static int decode_exchange_id(struct xdr_stream *xdr,
|
|
struct nfs41_exchange_id_res *res)
|
|
struct nfs41_exchange_id_res *res)
|
|
@@ -5919,6 +6027,32 @@ out:
|
|
return status;
|
|
return status;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Decode SECINFO response
|
|
|
|
+ */
|
|
|
|
+static int nfs4_xdr_dec_secinfo(struct rpc_rqst *rqstp,
|
|
|
|
+ struct xdr_stream *xdr,
|
|
|
|
+ struct nfs4_secinfo_res *res)
|
|
|
|
+{
|
|
|
|
+ struct compound_hdr hdr;
|
|
|
|
+ int status;
|
|
|
|
+
|
|
|
|
+ status = decode_compound_hdr(xdr, &hdr);
|
|
|
|
+ if (status)
|
|
|
|
+ goto out;
|
|
|
|
+ status = decode_sequence(xdr, &res->seq_res, rqstp);
|
|
|
|
+ if (status)
|
|
|
|
+ goto out;
|
|
|
|
+ status = decode_putfh(xdr);
|
|
|
|
+ if (status)
|
|
|
|
+ goto out;
|
|
|
|
+ status = decode_secinfo(xdr, res);
|
|
|
|
+ if (status)
|
|
|
|
+ goto out;
|
|
|
|
+out:
|
|
|
|
+ return status;
|
|
|
|
+}
|
|
|
|
+
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
/*
|
|
/*
|
|
* Decode EXCHANGE_ID response
|
|
* Decode EXCHANGE_ID response
|
|
@@ -6258,6 +6392,7 @@ struct rpc_procinfo nfs4_procedures[] = {
|
|
PROC(SETACL, enc_setacl, dec_setacl),
|
|
PROC(SETACL, enc_setacl, dec_setacl),
|
|
PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations),
|
|
PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations),
|
|
PROC(RELEASE_LOCKOWNER, enc_release_lockowner, dec_release_lockowner),
|
|
PROC(RELEASE_LOCKOWNER, enc_release_lockowner, dec_release_lockowner),
|
|
|
|
+ PROC(SECINFO, enc_secinfo, dec_secinfo),
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id),
|
|
PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id),
|
|
PROC(CREATE_SESSION, enc_create_session, dec_create_session),
|
|
PROC(CREATE_SESSION, enc_create_session, dec_create_session),
|