diff options
author | Bryan Schumaker <bjschuma@netapp.com> | 2011-03-24 13:12:29 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-03-24 13:52:41 -0400 |
commit | 5a5ea0d485c9715c86bf858bbdc5f6d373b3db88 (patch) | |
tree | 0aef824c36b7eb6eac6ea706c4c9a33930128ee3 | |
parent | 7c5130588d691a3b34d02312f1bd1b6d56fe0100 (diff) |
NFS: Add secinfo procedure
This patch adds the nfs4 operation secinfo as a
valid nfs rpc operation.
Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/nfs4proc.c | 35 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 135 | ||||
-rw-r--r-- | include/linux/nfs4.h | 1 | ||||
-rw-r--r-- | include/linux/nfs_xdr.h | 37 |
4 files changed, 208 insertions, 0 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 448657456b68..0b8bae119976 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -4639,6 +4639,40 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
4639 | return status; | 4639 | return status; |
4640 | } | 4640 | } |
4641 | 4641 | ||
4642 | static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors) | ||
4643 | { | ||
4644 | int status; | ||
4645 | struct nfs4_secinfo_arg args = { | ||
4646 | .dir_fh = NFS_FH(dir), | ||
4647 | .name = name, | ||
4648 | }; | ||
4649 | struct nfs4_secinfo_res res = { | ||
4650 | .flavors = flavors, | ||
4651 | }; | ||
4652 | struct rpc_message msg = { | ||
4653 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SECINFO], | ||
4654 | .rpc_argp = &args, | ||
4655 | .rpc_resp = &res, | ||
4656 | }; | ||
4657 | |||
4658 | dprintk("NFS call secinfo %s\n", name->name); | ||
4659 | status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0); | ||
4660 | dprintk("NFS reply secinfo: %d\n", status); | ||
4661 | return status; | ||
4662 | } | ||
4663 | |||
4664 | int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors) | ||
4665 | { | ||
4666 | struct nfs4_exception exception = { }; | ||
4667 | int err; | ||
4668 | do { | ||
4669 | err = nfs4_handle_exception(NFS_SERVER(dir), | ||
4670 | _nfs4_proc_secinfo(dir, name, flavors), | ||
4671 | &exception); | ||
4672 | } while (exception.retry); | ||
4673 | return err; | ||
4674 | } | ||
4675 | |||
4642 | #ifdef CONFIG_NFS_V4_1 | 4676 | #ifdef CONFIG_NFS_V4_1 |
4643 | /* | 4677 | /* |
4644 | * Check the exchange flags returned by the server for invalid flags, having | 4678 | * Check the exchange flags returned by the server for invalid flags, having |
@@ -5756,6 +5790,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = { | |||
5756 | .close_context = nfs4_close_context, | 5790 | .close_context = nfs4_close_context, |
5757 | .open_context = nfs4_atomic_open, | 5791 | .open_context = nfs4_atomic_open, |
5758 | .init_client = nfs4_init_client, | 5792 | .init_client = nfs4_init_client, |
5793 | .secinfo = nfs4_proc_secinfo, | ||
5759 | }; | 5794 | }; |
5760 | 5795 | ||
5761 | static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = { | 5796 | static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = { |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 0cf560f77884..98afcf947aa4 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <linux/kdev_t.h> | 46 | #include <linux/kdev_t.h> |
47 | #include <linux/sunrpc/clnt.h> | 47 | #include <linux/sunrpc/clnt.h> |
48 | #include <linux/sunrpc/msg_prot.h> | 48 | #include <linux/sunrpc/msg_prot.h> |
49 | #include <linux/sunrpc/gss_api.h> | ||
49 | #include <linux/nfs.h> | 50 | #include <linux/nfs.h> |
50 | #include <linux/nfs4.h> | 51 | #include <linux/nfs4.h> |
51 | #include <linux/nfs_fs.h> | 52 | #include <linux/nfs_fs.h> |
@@ -253,6 +254,8 @@ static int nfs4_stat_to_errno(int); | |||
253 | (encode_getattr_maxsz) | 254 | (encode_getattr_maxsz) |
254 | #define decode_fs_locations_maxsz \ | 255 | #define decode_fs_locations_maxsz \ |
255 | (0) | 256 | (0) |
257 | #define encode_secinfo_maxsz (op_encode_hdr_maxsz + nfs4_name_maxsz) | ||
258 | #define decode_secinfo_maxsz (op_decode_hdr_maxsz + 4 + (NFS_MAX_SECFLAVORS * (16 + GSS_OID_MAX_LEN))) | ||
256 | 259 | ||
257 | #if defined(CONFIG_NFS_V4_1) | 260 | #if defined(CONFIG_NFS_V4_1) |
258 | #define NFS4_MAX_MACHINE_NAME_LEN (64) | 261 | #define NFS4_MAX_MACHINE_NAME_LEN (64) |
@@ -676,6 +679,14 @@ static int nfs4_stat_to_errno(int); | |||
676 | decode_putfh_maxsz + \ | 679 | decode_putfh_maxsz + \ |
677 | decode_lookup_maxsz + \ | 680 | decode_lookup_maxsz + \ |
678 | decode_fs_locations_maxsz) | 681 | decode_fs_locations_maxsz) |
682 | #define NFS4_enc_secinfo_sz (compound_encode_hdr_maxsz + \ | ||
683 | encode_sequence_maxsz + \ | ||
684 | encode_putfh_maxsz + \ | ||
685 | encode_secinfo_maxsz) | ||
686 | #define NFS4_dec_secinfo_sz (compound_decode_hdr_maxsz + \ | ||
687 | decode_sequence_maxsz + \ | ||
688 | decode_putfh_maxsz + \ | ||
689 | decode_secinfo_maxsz) | ||
679 | #if defined(CONFIG_NFS_V4_1) | 690 | #if defined(CONFIG_NFS_V4_1) |
680 | #define NFS4_enc_exchange_id_sz \ | 691 | #define NFS4_enc_exchange_id_sz \ |
681 | (compound_encode_hdr_maxsz + \ | 692 | (compound_encode_hdr_maxsz + \ |
@@ -1620,6 +1631,18 @@ static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *state | |||
1620 | hdr->replen += decode_delegreturn_maxsz; | 1631 | hdr->replen += decode_delegreturn_maxsz; |
1621 | } | 1632 | } |
1622 | 1633 | ||
1634 | static void encode_secinfo(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | ||
1635 | { | ||
1636 | int len = name->len; | ||
1637 | __be32 *p; | ||
1638 | |||
1639 | p = reserve_space(xdr, 8 + len); | ||
1640 | *p++ = cpu_to_be32(OP_SECINFO); | ||
1641 | xdr_encode_opaque(p, name->name, len); | ||
1642 | hdr->nops++; | ||
1643 | hdr->replen += decode_secinfo_maxsz; | ||
1644 | } | ||
1645 | |||
1623 | #if defined(CONFIG_NFS_V4_1) | 1646 | #if defined(CONFIG_NFS_V4_1) |
1624 | /* NFSv4.1 operations */ | 1647 | /* NFSv4.1 operations */ |
1625 | static void encode_exchange_id(struct xdr_stream *xdr, | 1648 | static void encode_exchange_id(struct xdr_stream *xdr, |
@@ -2465,6 +2488,24 @@ static void nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, | |||
2465 | encode_nops(&hdr); | 2488 | encode_nops(&hdr); |
2466 | } | 2489 | } |
2467 | 2490 | ||
2491 | /* | ||
2492 | * Encode SECINFO request | ||
2493 | */ | ||
2494 | static void nfs4_xdr_enc_secinfo(struct rpc_rqst *req, | ||
2495 | struct xdr_stream *xdr, | ||
2496 | struct nfs4_secinfo_arg *args) | ||
2497 | { | ||
2498 | struct compound_hdr hdr = { | ||
2499 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), | ||
2500 | }; | ||
2501 | |||
2502 | encode_compound_hdr(xdr, req, &hdr); | ||
2503 | encode_sequence(xdr, &args->seq_args, &hdr); | ||
2504 | encode_putfh(xdr, args->dir_fh, &hdr); | ||
2505 | encode_secinfo(xdr, args->name, &hdr); | ||
2506 | encode_nops(&hdr); | ||
2507 | } | ||
2508 | |||
2468 | #if defined(CONFIG_NFS_V4_1) | 2509 | #if defined(CONFIG_NFS_V4_1) |
2469 | /* | 2510 | /* |
2470 | * EXCHANGE_ID request | 2511 | * EXCHANGE_ID request |
@@ -4680,6 +4721,73 @@ static int decode_delegreturn(struct xdr_stream *xdr) | |||
4680 | return decode_op_hdr(xdr, OP_DELEGRETURN); | 4721 | return decode_op_hdr(xdr, OP_DELEGRETURN); |
4681 | } | 4722 | } |
4682 | 4723 | ||
4724 | static int decode_secinfo_gss(struct xdr_stream *xdr, struct nfs4_secinfo_flavor *flavor) | ||
4725 | { | ||
4726 | __be32 *p; | ||
4727 | |||
4728 | p = xdr_inline_decode(xdr, 4); | ||
4729 | if (unlikely(!p)) | ||
4730 | goto out_overflow; | ||
4731 | flavor->gss.sec_oid4.len = be32_to_cpup(p); | ||
4732 | if (flavor->gss.sec_oid4.len > GSS_OID_MAX_LEN) | ||
4733 | goto out_err; | ||
4734 | |||
4735 | p = xdr_inline_decode(xdr, flavor->gss.sec_oid4.len); | ||
4736 | if (unlikely(!p)) | ||
4737 | goto out_overflow; | ||
4738 | memcpy(flavor->gss.sec_oid4.data, p, flavor->gss.sec_oid4.len); | ||
4739 | |||
4740 | p = xdr_inline_decode(xdr, 8); | ||
4741 | if (unlikely(!p)) | ||
4742 | goto out_overflow; | ||
4743 | flavor->gss.qop4 = be32_to_cpup(p++); | ||
4744 | flavor->gss.service = be32_to_cpup(p); | ||
4745 | |||
4746 | return 0; | ||
4747 | |||
4748 | out_overflow: | ||
4749 | print_overflow_msg(__func__, xdr); | ||
4750 | return -EIO; | ||
4751 | out_err: | ||
4752 | return -EINVAL; | ||
4753 | } | ||
4754 | |||
4755 | static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) | ||
4756 | { | ||
4757 | struct nfs4_secinfo_flavor *sec_flavor; | ||
4758 | int status; | ||
4759 | __be32 *p; | ||
4760 | int i; | ||
4761 | |||
4762 | status = decode_op_hdr(xdr, OP_SECINFO); | ||
4763 | p = xdr_inline_decode(xdr, 4); | ||
4764 | if (unlikely(!p)) | ||
4765 | goto out_overflow; | ||
4766 | res->flavors->num_flavors = be32_to_cpup(p); | ||
4767 | |||
4768 | for (i = 0; i < res->flavors->num_flavors; i++) { | ||
4769 | sec_flavor = &res->flavors->flavors[i]; | ||
4770 | if ((char *)&sec_flavor[1] - (char *)res > PAGE_SIZE) | ||
4771 | break; | ||
4772 | |||
4773 | p = xdr_inline_decode(xdr, 4); | ||
4774 | if (unlikely(!p)) | ||
4775 | goto out_overflow; | ||
4776 | sec_flavor->flavor = be32_to_cpup(p); | ||
4777 | |||
4778 | if (sec_flavor->flavor == RPC_AUTH_GSS) { | ||
4779 | if (decode_secinfo_gss(xdr, sec_flavor)) | ||
4780 | break; | ||
4781 | } | ||
4782 | } | ||
4783 | |||
4784 | return 0; | ||
4785 | |||
4786 | out_overflow: | ||
4787 | print_overflow_msg(__func__, xdr); | ||
4788 | return -EIO; | ||
4789 | } | ||
4790 | |||
4683 | #if defined(CONFIG_NFS_V4_1) | 4791 | #if defined(CONFIG_NFS_V4_1) |
4684 | static int decode_exchange_id(struct xdr_stream *xdr, | 4792 | static int decode_exchange_id(struct xdr_stream *xdr, |
4685 | struct nfs41_exchange_id_res *res) | 4793 | struct nfs41_exchange_id_res *res) |
@@ -5919,6 +6027,32 @@ out: | |||
5919 | return status; | 6027 | return status; |
5920 | } | 6028 | } |
5921 | 6029 | ||
6030 | /* | ||
6031 | * Decode SECINFO response | ||
6032 | */ | ||
6033 | static int nfs4_xdr_dec_secinfo(struct rpc_rqst *rqstp, | ||
6034 | struct xdr_stream *xdr, | ||
6035 | struct nfs4_secinfo_res *res) | ||
6036 | { | ||
6037 | struct compound_hdr hdr; | ||
6038 | int status; | ||
6039 | |||
6040 | status = decode_compound_hdr(xdr, &hdr); | ||
6041 | if (status) | ||
6042 | goto out; | ||
6043 | status = decode_sequence(xdr, &res->seq_res, rqstp); | ||
6044 | if (status) | ||
6045 | goto out; | ||
6046 | status = decode_putfh(xdr); | ||
6047 | if (status) | ||
6048 | goto out; | ||
6049 | status = decode_secinfo(xdr, res); | ||
6050 | if (status) | ||
6051 | goto out; | ||
6052 | out: | ||
6053 | return status; | ||
6054 | } | ||
6055 | |||
5922 | #if defined(CONFIG_NFS_V4_1) | 6056 | #if defined(CONFIG_NFS_V4_1) |
5923 | /* | 6057 | /* |
5924 | * Decode EXCHANGE_ID response | 6058 | * Decode EXCHANGE_ID response |
@@ -6258,6 +6392,7 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
6258 | PROC(SETACL, enc_setacl, dec_setacl), | 6392 | PROC(SETACL, enc_setacl, dec_setacl), |
6259 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), | 6393 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), |
6260 | PROC(RELEASE_LOCKOWNER, enc_release_lockowner, dec_release_lockowner), | 6394 | PROC(RELEASE_LOCKOWNER, enc_release_lockowner, dec_release_lockowner), |
6395 | PROC(SECINFO, enc_secinfo, dec_secinfo), | ||
6261 | #if defined(CONFIG_NFS_V4_1) | 6396 | #if defined(CONFIG_NFS_V4_1) |
6262 | PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), | 6397 | PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), |
6263 | PROC(CREATE_SESSION, enc_create_session, dec_create_session), | 6398 | PROC(CREATE_SESSION, enc_create_session, dec_create_session), |
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 134716e5e350..7e7f6b7e46b1 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h | |||
@@ -550,6 +550,7 @@ enum { | |||
550 | NFSPROC4_CLNT_SETACL, | 550 | NFSPROC4_CLNT_SETACL, |
551 | NFSPROC4_CLNT_FS_LOCATIONS, | 551 | NFSPROC4_CLNT_FS_LOCATIONS, |
552 | NFSPROC4_CLNT_RELEASE_LOCKOWNER, | 552 | NFSPROC4_CLNT_RELEASE_LOCKOWNER, |
553 | NFSPROC4_CLNT_SECINFO, | ||
553 | 554 | ||
554 | /* nfs41 */ | 555 | /* nfs41 */ |
555 | NFSPROC4_CLNT_EXCHANGE_ID, | 556 | NFSPROC4_CLNT_EXCHANGE_ID, |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 71ee6799db9b..3f32bf175840 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | #include <linux/nfsacl.h> | 4 | #include <linux/nfsacl.h> |
5 | #include <linux/nfs3.h> | 5 | #include <linux/nfs3.h> |
6 | #include <linux/sunrpc/gss_api.h> | ||
6 | 7 | ||
7 | /* | 8 | /* |
8 | * To change the maximum rsize and wsize supported by the NFS client, adjust | 9 | * To change the maximum rsize and wsize supported by the NFS client, adjust |
@@ -14,6 +15,9 @@ | |||
14 | #define NFS_DEF_FILE_IO_SIZE (4096U) | 15 | #define NFS_DEF_FILE_IO_SIZE (4096U) |
15 | #define NFS_MIN_FILE_IO_SIZE (1024U) | 16 | #define NFS_MIN_FILE_IO_SIZE (1024U) |
16 | 17 | ||
18 | /* Forward declaration for NFS v3 */ | ||
19 | struct nfs4_secinfo_flavors; | ||
20 | |||
17 | struct nfs_fsid { | 21 | struct nfs_fsid { |
18 | uint64_t major; | 22 | uint64_t major; |
19 | uint64_t minor; | 23 | uint64_t minor; |
@@ -936,6 +940,38 @@ struct nfs4_fs_locations_res { | |||
936 | struct nfs4_sequence_res seq_res; | 940 | struct nfs4_sequence_res seq_res; |
937 | }; | 941 | }; |
938 | 942 | ||
943 | struct nfs4_secinfo_oid { | ||
944 | unsigned int len; | ||
945 | char data[GSS_OID_MAX_LEN]; | ||
946 | }; | ||
947 | |||
948 | struct nfs4_secinfo_gss { | ||
949 | struct nfs4_secinfo_oid sec_oid4; | ||
950 | unsigned int qop4; | ||
951 | unsigned int service; | ||
952 | }; | ||
953 | |||
954 | struct nfs4_secinfo_flavor { | ||
955 | unsigned int flavor; | ||
956 | struct nfs4_secinfo_gss gss; | ||
957 | }; | ||
958 | |||
959 | struct nfs4_secinfo_flavors { | ||
960 | unsigned int num_flavors; | ||
961 | struct nfs4_secinfo_flavor flavors[0]; | ||
962 | }; | ||
963 | |||
964 | struct nfs4_secinfo_arg { | ||
965 | const struct nfs_fh *dir_fh; | ||
966 | const struct qstr *name; | ||
967 | struct nfs4_sequence_args seq_args; | ||
968 | }; | ||
969 | |||
970 | struct nfs4_secinfo_res { | ||
971 | struct nfs4_secinfo_flavors *flavors; | ||
972 | struct nfs4_sequence_res seq_res; | ||
973 | }; | ||
974 | |||
939 | #endif /* CONFIG_NFS_V4 */ | 975 | #endif /* CONFIG_NFS_V4 */ |
940 | 976 | ||
941 | struct nfstime4 { | 977 | struct nfstime4 { |
@@ -1118,6 +1154,7 @@ struct nfs_rpc_ops { | |||
1118 | struct iattr *iattr); | 1154 | struct iattr *iattr); |
1119 | int (*init_client) (struct nfs_client *, const struct rpc_timeout *, | 1155 | int (*init_client) (struct nfs_client *, const struct rpc_timeout *, |
1120 | const char *, rpc_authflavor_t, int); | 1156 | const char *, rpc_authflavor_t, int); |
1157 | int (*secinfo)(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); | ||
1121 | }; | 1158 | }; |
1122 | 1159 | ||
1123 | /* | 1160 | /* |