diff options
Diffstat (limited to 'fs/nfsd/nfs4proc.c')
-rw-r--r-- | fs/nfsd/nfs4proc.c | 143 |
1 files changed, 119 insertions, 24 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 59ec449b0c7f..3a6dbd70b34b 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -196,9 +196,9 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o | |||
196 | 196 | ||
197 | /* | 197 | /* |
198 | * Note: create modes (UNCHECKED,GUARDED...) are the same | 198 | * Note: create modes (UNCHECKED,GUARDED...) are the same |
199 | * in NFSv4 as in v3. | 199 | * in NFSv4 as in v3 except EXCLUSIVE4_1. |
200 | */ | 200 | */ |
201 | status = nfsd_create_v3(rqstp, current_fh, open->op_fname.data, | 201 | status = do_nfsd_create(rqstp, current_fh, open->op_fname.data, |
202 | open->op_fname.len, &open->op_iattr, | 202 | open->op_fname.len, &open->op_iattr, |
203 | &resfh, open->op_createmode, | 203 | &resfh, open->op_createmode, |
204 | (u32 *)open->op_verf.data, | 204 | (u32 *)open->op_verf.data, |
@@ -403,7 +403,7 @@ nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
403 | cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen; | 403 | cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen; |
404 | memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval, | 404 | memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval, |
405 | putfh->pf_fhlen); | 405 | putfh->pf_fhlen); |
406 | return fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP); | 406 | return fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_BYPASS_GSS); |
407 | } | 407 | } |
408 | 408 | ||
409 | static __be32 | 409 | static __be32 |
@@ -604,9 +604,7 @@ nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
604 | return status; | 604 | return status; |
605 | } | 605 | } |
606 | 606 | ||
607 | static __be32 | 607 | static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh) |
608 | nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | ||
609 | void *arg) | ||
610 | { | 608 | { |
611 | struct svc_fh tmp_fh; | 609 | struct svc_fh tmp_fh; |
612 | __be32 ret; | 610 | __be32 ret; |
@@ -615,13 +613,19 @@ nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
615 | ret = exp_pseudoroot(rqstp, &tmp_fh); | 613 | ret = exp_pseudoroot(rqstp, &tmp_fh); |
616 | if (ret) | 614 | if (ret) |
617 | return ret; | 615 | return ret; |
618 | if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) { | 616 | if (tmp_fh.fh_dentry == fh->fh_dentry) { |
619 | fh_put(&tmp_fh); | 617 | fh_put(&tmp_fh); |
620 | return nfserr_noent; | 618 | return nfserr_noent; |
621 | } | 619 | } |
622 | fh_put(&tmp_fh); | 620 | fh_put(&tmp_fh); |
623 | return nfsd_lookup(rqstp, &cstate->current_fh, | 621 | return nfsd_lookup(rqstp, fh, "..", 2, fh); |
624 | "..", 2, &cstate->current_fh); | 622 | } |
623 | |||
624 | static __be32 | ||
625 | nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | ||
626 | void *arg) | ||
627 | { | ||
628 | return nfsd4_do_lookupp(rqstp, &cstate->current_fh); | ||
625 | } | 629 | } |
626 | 630 | ||
627 | static __be32 | 631 | static __be32 |
@@ -758,6 +762,9 @@ nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
758 | __be32 err; | 762 | __be32 err; |
759 | 763 | ||
760 | fh_init(&resfh, NFS4_FHSIZE); | 764 | fh_init(&resfh, NFS4_FHSIZE); |
765 | err = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, NFSD_MAY_EXEC); | ||
766 | if (err) | ||
767 | return err; | ||
761 | err = nfsd_lookup_dentry(rqstp, &cstate->current_fh, | 768 | err = nfsd_lookup_dentry(rqstp, &cstate->current_fh, |
762 | secinfo->si_name, secinfo->si_namelen, | 769 | secinfo->si_name, secinfo->si_namelen, |
763 | &exp, &dentry); | 770 | &exp, &dentry); |
@@ -769,10 +776,36 @@ nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
769 | } else | 776 | } else |
770 | secinfo->si_exp = exp; | 777 | secinfo->si_exp = exp; |
771 | dput(dentry); | 778 | dput(dentry); |
779 | if (cstate->minorversion) | ||
780 | /* See rfc 5661 section 2.6.3.1.1.8 */ | ||
781 | fh_put(&cstate->current_fh); | ||
772 | return err; | 782 | return err; |
773 | } | 783 | } |
774 | 784 | ||
775 | static __be32 | 785 | static __be32 |
786 | nfsd4_secinfo_no_name(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | ||
787 | struct nfsd4_secinfo_no_name *sin) | ||
788 | { | ||
789 | __be32 err; | ||
790 | |||
791 | switch (sin->sin_style) { | ||
792 | case NFS4_SECINFO_STYLE4_CURRENT_FH: | ||
793 | break; | ||
794 | case NFS4_SECINFO_STYLE4_PARENT: | ||
795 | err = nfsd4_do_lookupp(rqstp, &cstate->current_fh); | ||
796 | if (err) | ||
797 | return err; | ||
798 | break; | ||
799 | default: | ||
800 | return nfserr_inval; | ||
801 | } | ||
802 | exp_get(cstate->current_fh.fh_export); | ||
803 | sin->sin_exp = cstate->current_fh.fh_export; | ||
804 | fh_put(&cstate->current_fh); | ||
805 | return nfs_ok; | ||
806 | } | ||
807 | |||
808 | static __be32 | ||
776 | nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 809 | nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
777 | struct nfsd4_setattr *setattr) | 810 | struct nfsd4_setattr *setattr) |
778 | { | 811 | { |
@@ -954,8 +987,11 @@ typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *, | |||
954 | void *); | 987 | void *); |
955 | enum nfsd4_op_flags { | 988 | enum nfsd4_op_flags { |
956 | ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */ | 989 | ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */ |
957 | ALLOWED_ON_ABSENT_FS = 2 << 0, /* ops processed on absent fs */ | 990 | ALLOWED_ON_ABSENT_FS = 1 << 1, /* ops processed on absent fs */ |
958 | ALLOWED_AS_FIRST_OP = 3 << 0, /* ops reqired first in compound */ | 991 | ALLOWED_AS_FIRST_OP = 1 << 2, /* ops reqired first in compound */ |
992 | /* For rfc 5661 section 2.6.3.1.1: */ | ||
993 | OP_HANDLES_WRONGSEC = 1 << 3, | ||
994 | OP_IS_PUTFH_LIKE = 1 << 4, | ||
959 | }; | 995 | }; |
960 | 996 | ||
961 | struct nfsd4_operation { | 997 | struct nfsd4_operation { |
@@ -974,8 +1010,8 @@ static const char *nfsd4_op_name(unsigned opnum); | |||
974 | * Also note, enforced elsewhere: | 1010 | * Also note, enforced elsewhere: |
975 | * - SEQUENCE other than as first op results in | 1011 | * - SEQUENCE other than as first op results in |
976 | * NFS4ERR_SEQUENCE_POS. (Enforced in nfsd4_sequence().) | 1012 | * NFS4ERR_SEQUENCE_POS. (Enforced in nfsd4_sequence().) |
977 | * - BIND_CONN_TO_SESSION must be the only op in its compound | 1013 | * - BIND_CONN_TO_SESSION must be the only op in its compound. |
978 | * (Will be enforced in nfsd4_bind_conn_to_session().) | 1014 | * (Enforced in nfsd4_bind_conn_to_session().) |
979 | * - DESTROY_SESSION must be the final operation in a compound, if | 1015 | * - DESTROY_SESSION must be the final operation in a compound, if |
980 | * sessionid's in SEQUENCE and DESTROY_SESSION are the same. | 1016 | * sessionid's in SEQUENCE and DESTROY_SESSION are the same. |
981 | * (Enforced in nfsd4_destroy_session().) | 1017 | * (Enforced in nfsd4_destroy_session().) |
@@ -1001,6 +1037,44 @@ static __be32 nfs41_check_op_ordering(struct nfsd4_compoundargs *args) | |||
1001 | return nfs_ok; | 1037 | return nfs_ok; |
1002 | } | 1038 | } |
1003 | 1039 | ||
1040 | static inline struct nfsd4_operation *OPDESC(struct nfsd4_op *op) | ||
1041 | { | ||
1042 | return &nfsd4_ops[op->opnum]; | ||
1043 | } | ||
1044 | |||
1045 | static bool need_wrongsec_check(struct svc_rqst *rqstp) | ||
1046 | { | ||
1047 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | ||
1048 | struct nfsd4_compoundargs *argp = rqstp->rq_argp; | ||
1049 | struct nfsd4_op *this = &argp->ops[resp->opcnt - 1]; | ||
1050 | struct nfsd4_op *next = &argp->ops[resp->opcnt]; | ||
1051 | struct nfsd4_operation *thisd; | ||
1052 | struct nfsd4_operation *nextd; | ||
1053 | |||
1054 | thisd = OPDESC(this); | ||
1055 | /* | ||
1056 | * Most ops check wronsec on our own; only the putfh-like ops | ||
1057 | * have special rules. | ||
1058 | */ | ||
1059 | if (!(thisd->op_flags & OP_IS_PUTFH_LIKE)) | ||
1060 | return false; | ||
1061 | /* | ||
1062 | * rfc 5661 2.6.3.1.1.6: don't bother erroring out a | ||
1063 | * put-filehandle operation if we're not going to use the | ||
1064 | * result: | ||
1065 | */ | ||
1066 | if (argp->opcnt == resp->opcnt) | ||
1067 | return false; | ||
1068 | |||
1069 | nextd = OPDESC(next); | ||
1070 | /* | ||
1071 | * Rest of 2.6.3.1.1: certain operations will return WRONGSEC | ||
1072 | * errors themselves as necessary; others should check for them | ||
1073 | * now: | ||
1074 | */ | ||
1075 | return !(nextd->op_flags & OP_HANDLES_WRONGSEC); | ||
1076 | } | ||
1077 | |||
1004 | /* | 1078 | /* |
1005 | * COMPOUND call. | 1079 | * COMPOUND call. |
1006 | */ | 1080 | */ |
@@ -1031,8 +1105,11 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1031 | resp->cstate.session = NULL; | 1105 | resp->cstate.session = NULL; |
1032 | fh_init(&resp->cstate.current_fh, NFS4_FHSIZE); | 1106 | fh_init(&resp->cstate.current_fh, NFS4_FHSIZE); |
1033 | fh_init(&resp->cstate.save_fh, NFS4_FHSIZE); | 1107 | fh_init(&resp->cstate.save_fh, NFS4_FHSIZE); |
1034 | /* Use the deferral mechanism only for NFSv4.0 compounds */ | 1108 | /* |
1035 | rqstp->rq_usedeferral = (args->minorversion == 0); | 1109 | * Don't use the deferral mechanism for NFSv4; compounds make it |
1110 | * too hard to avoid non-idempotency problems. | ||
1111 | */ | ||
1112 | rqstp->rq_usedeferral = 0; | ||
1036 | 1113 | ||
1037 | /* | 1114 | /* |
1038 | * According to RFC3010, this takes precedence over all other errors. | 1115 | * According to RFC3010, this takes precedence over all other errors. |
@@ -1075,7 +1152,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1075 | goto encode_op; | 1152 | goto encode_op; |
1076 | } | 1153 | } |
1077 | 1154 | ||
1078 | opdesc = &nfsd4_ops[op->opnum]; | 1155 | opdesc = OPDESC(op); |
1079 | 1156 | ||
1080 | if (!cstate->current_fh.fh_dentry) { | 1157 | if (!cstate->current_fh.fh_dentry) { |
1081 | if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) { | 1158 | if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) { |
@@ -1093,6 +1170,9 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1093 | else | 1170 | else |
1094 | BUG_ON(op->status == nfs_ok); | 1171 | BUG_ON(op->status == nfs_ok); |
1095 | 1172 | ||
1173 | if (!op->status && need_wrongsec_check(rqstp)) | ||
1174 | op->status = check_nfsd_access(cstate->current_fh.fh_export, rqstp); | ||
1175 | |||
1096 | encode_op: | 1176 | encode_op: |
1097 | /* Only from SEQUENCE */ | 1177 | /* Only from SEQUENCE */ |
1098 | if (resp->cstate.status == nfserr_replay_cache) { | 1178 | if (resp->cstate.status == nfserr_replay_cache) { |
@@ -1123,10 +1203,6 @@ encode_op: | |||
1123 | 1203 | ||
1124 | nfsd4_increment_op_stats(op->opnum); | 1204 | nfsd4_increment_op_stats(op->opnum); |
1125 | } | 1205 | } |
1126 | if (!rqstp->rq_usedeferral && status == nfserr_dropit) { | ||
1127 | dprintk("%s Dropit - send NFS4ERR_DELAY\n", __func__); | ||
1128 | status = nfserr_jukebox; | ||
1129 | } | ||
1130 | 1206 | ||
1131 | resp->cstate.status = status; | 1207 | resp->cstate.status = status; |
1132 | fh_put(&resp->cstate.current_fh); | 1208 | fh_put(&resp->cstate.current_fh); |
@@ -1188,10 +1264,12 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1188 | }, | 1264 | }, |
1189 | [OP_LOOKUP] = { | 1265 | [OP_LOOKUP] = { |
1190 | .op_func = (nfsd4op_func)nfsd4_lookup, | 1266 | .op_func = (nfsd4op_func)nfsd4_lookup, |
1267 | .op_flags = OP_HANDLES_WRONGSEC, | ||
1191 | .op_name = "OP_LOOKUP", | 1268 | .op_name = "OP_LOOKUP", |
1192 | }, | 1269 | }, |
1193 | [OP_LOOKUPP] = { | 1270 | [OP_LOOKUPP] = { |
1194 | .op_func = (nfsd4op_func)nfsd4_lookupp, | 1271 | .op_func = (nfsd4op_func)nfsd4_lookupp, |
1272 | .op_flags = OP_HANDLES_WRONGSEC, | ||
1195 | .op_name = "OP_LOOKUPP", | 1273 | .op_name = "OP_LOOKUPP", |
1196 | }, | 1274 | }, |
1197 | [OP_NVERIFY] = { | 1275 | [OP_NVERIFY] = { |
@@ -1200,6 +1278,7 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1200 | }, | 1278 | }, |
1201 | [OP_OPEN] = { | 1279 | [OP_OPEN] = { |
1202 | .op_func = (nfsd4op_func)nfsd4_open, | 1280 | .op_func = (nfsd4op_func)nfsd4_open, |
1281 | .op_flags = OP_HANDLES_WRONGSEC, | ||
1203 | .op_name = "OP_OPEN", | 1282 | .op_name = "OP_OPEN", |
1204 | }, | 1283 | }, |
1205 | [OP_OPEN_CONFIRM] = { | 1284 | [OP_OPEN_CONFIRM] = { |
@@ -1212,17 +1291,20 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1212 | }, | 1291 | }, |
1213 | [OP_PUTFH] = { | 1292 | [OP_PUTFH] = { |
1214 | .op_func = (nfsd4op_func)nfsd4_putfh, | 1293 | .op_func = (nfsd4op_func)nfsd4_putfh, |
1215 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | 1294 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1295 | | OP_IS_PUTFH_LIKE, | ||
1216 | .op_name = "OP_PUTFH", | 1296 | .op_name = "OP_PUTFH", |
1217 | }, | 1297 | }, |
1218 | [OP_PUTPUBFH] = { | 1298 | [OP_PUTPUBFH] = { |
1219 | .op_func = (nfsd4op_func)nfsd4_putrootfh, | 1299 | .op_func = (nfsd4op_func)nfsd4_putrootfh, |
1220 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | 1300 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1301 | | OP_IS_PUTFH_LIKE, | ||
1221 | .op_name = "OP_PUTPUBFH", | 1302 | .op_name = "OP_PUTPUBFH", |
1222 | }, | 1303 | }, |
1223 | [OP_PUTROOTFH] = { | 1304 | [OP_PUTROOTFH] = { |
1224 | .op_func = (nfsd4op_func)nfsd4_putrootfh, | 1305 | .op_func = (nfsd4op_func)nfsd4_putrootfh, |
1225 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | 1306 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1307 | | OP_IS_PUTFH_LIKE, | ||
1226 | .op_name = "OP_PUTROOTFH", | 1308 | .op_name = "OP_PUTROOTFH", |
1227 | }, | 1309 | }, |
1228 | [OP_READ] = { | 1310 | [OP_READ] = { |
@@ -1252,15 +1334,18 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1252 | }, | 1334 | }, |
1253 | [OP_RESTOREFH] = { | 1335 | [OP_RESTOREFH] = { |
1254 | .op_func = (nfsd4op_func)nfsd4_restorefh, | 1336 | .op_func = (nfsd4op_func)nfsd4_restorefh, |
1255 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | 1337 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1338 | | OP_IS_PUTFH_LIKE, | ||
1256 | .op_name = "OP_RESTOREFH", | 1339 | .op_name = "OP_RESTOREFH", |
1257 | }, | 1340 | }, |
1258 | [OP_SAVEFH] = { | 1341 | [OP_SAVEFH] = { |
1259 | .op_func = (nfsd4op_func)nfsd4_savefh, | 1342 | .op_func = (nfsd4op_func)nfsd4_savefh, |
1343 | .op_flags = OP_HANDLES_WRONGSEC, | ||
1260 | .op_name = "OP_SAVEFH", | 1344 | .op_name = "OP_SAVEFH", |
1261 | }, | 1345 | }, |
1262 | [OP_SECINFO] = { | 1346 | [OP_SECINFO] = { |
1263 | .op_func = (nfsd4op_func)nfsd4_secinfo, | 1347 | .op_func = (nfsd4op_func)nfsd4_secinfo, |
1348 | .op_flags = OP_HANDLES_WRONGSEC, | ||
1264 | .op_name = "OP_SECINFO", | 1349 | .op_name = "OP_SECINFO", |
1265 | }, | 1350 | }, |
1266 | [OP_SETATTR] = { | 1351 | [OP_SETATTR] = { |
@@ -1297,6 +1382,11 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1297 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1382 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, |
1298 | .op_name = "OP_EXCHANGE_ID", | 1383 | .op_name = "OP_EXCHANGE_ID", |
1299 | }, | 1384 | }, |
1385 | [OP_BIND_CONN_TO_SESSION] = { | ||
1386 | .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session, | ||
1387 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | ||
1388 | .op_name = "OP_BIND_CONN_TO_SESSION", | ||
1389 | }, | ||
1300 | [OP_CREATE_SESSION] = { | 1390 | [OP_CREATE_SESSION] = { |
1301 | .op_func = (nfsd4op_func)nfsd4_create_session, | 1391 | .op_func = (nfsd4op_func)nfsd4_create_session, |
1302 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1392 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, |
@@ -1317,6 +1407,11 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1317 | .op_flags = ALLOWED_WITHOUT_FH, | 1407 | .op_flags = ALLOWED_WITHOUT_FH, |
1318 | .op_name = "OP_RECLAIM_COMPLETE", | 1408 | .op_name = "OP_RECLAIM_COMPLETE", |
1319 | }, | 1409 | }, |
1410 | [OP_SECINFO_NO_NAME] = { | ||
1411 | .op_func = (nfsd4op_func)nfsd4_secinfo_no_name, | ||
1412 | .op_flags = OP_HANDLES_WRONGSEC, | ||
1413 | .op_name = "OP_SECINFO_NO_NAME", | ||
1414 | }, | ||
1320 | }; | 1415 | }; |
1321 | 1416 | ||
1322 | static const char *nfsd4_op_name(unsigned opnum) | 1417 | static const char *nfsd4_op_name(unsigned opnum) |