aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfs4proc.c')
-rw-r--r--fs/nfsd/nfs4proc.c143
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
409static __be32 409static __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
607static __be32 607static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
608nfsd4_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
624static __be32
625nfsd4_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
627static __be32 631static __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
775static __be32 785static __be32
786nfsd4_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
808static __be32
776nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 809nfsd4_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 *);
955enum nfsd4_op_flags { 988enum 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
961struct nfsd4_operation { 997struct 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
1040static inline struct nfsd4_operation *OPDESC(struct nfsd4_op *op)
1041{
1042 return &nfsd4_ops[op->opnum];
1043}
1044
1045static 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
1096encode_op: 1176encode_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
1322static const char *nfsd4_op_name(unsigned opnum) 1417static const char *nfsd4_op_name(unsigned opnum)