1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 1676 jpk * Common Development and Distribution License (the "License"). 6 1676 jpk * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 8662 Jordan * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel /* 27 0 stevel * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T. 28 0 stevel * All Rights Reserved 29 0 stevel */ 30 0 stevel 31 0 stevel #include <sys/param.h> 32 0 stevel #include <sys/types.h> 33 0 stevel #include <sys/systm.h> 34 0 stevel #include <sys/cred.h> 35 0 stevel #include <sys/buf.h> 36 0 stevel #include <sys/vfs.h> 37 3898 rsb #include <sys/vfs_opreg.h> 38 0 stevel #include <sys/vnode.h> 39 0 stevel #include <sys/uio.h> 40 0 stevel #include <sys/errno.h> 41 0 stevel #include <sys/sysmacros.h> 42 0 stevel #include <sys/statvfs.h> 43 0 stevel #include <sys/kmem.h> 44 0 stevel #include <sys/dirent.h> 45 0 stevel #include <sys/cmn_err.h> 46 0 stevel #include <sys/debug.h> 47 0 stevel #include <sys/systeminfo.h> 48 0 stevel #include <sys/flock.h> 49 0 stevel #include <sys/pathname.h> 50 0 stevel #include <sys/nbmlock.h> 51 0 stevel #include <sys/share.h> 52 0 stevel #include <sys/atomic.h> 53 0 stevel #include <sys/policy.h> 54 0 stevel #include <sys/fem.h> 55 1676 jpk #include <sys/sdt.h> 56 2035 calum #include <sys/ddi.h> 57 8662 Jordan #include <sys/zone.h> 58 0 stevel 59 0 stevel #include <rpc/types.h> 60 0 stevel #include <rpc/auth.h> 61 0 stevel #include <rpc/rpcsec_gss.h> 62 0 stevel #include <rpc/svc.h> 63 0 stevel 64 0 stevel #include <nfs/nfs.h> 65 0 stevel #include <nfs/export.h> 66 7961 Natalie #include <nfs/nfs_cmd.h> 67 0 stevel #include <nfs/lm.h> 68 0 stevel #include <nfs/nfs4.h> 69 0 stevel 70 0 stevel #include <sys/strsubr.h> 71 0 stevel #include <sys/strsun.h> 72 0 stevel 73 0 stevel #include <inet/common.h> 74 0 stevel #include <inet/ip.h> 75 0 stevel #include <inet/ip6.h> 76 1676 jpk 77 1676 jpk #include <sys/tsol/label.h> 78 1676 jpk #include <sys/tsol/tndb.h> 79 0 stevel 80 0 stevel #define RFS4_MAXLOCK_TRIES 4 /* Try to get the lock this many times */ 81 0 stevel static int rfs4_maxlock_tries = RFS4_MAXLOCK_TRIES; 82 0 stevel #define RFS4_LOCK_DELAY 10 /* Milliseconds */ 83 7387 Robert static clock_t rfs4_lock_delay = RFS4_LOCK_DELAY; 84 7387 Robert extern struct svc_ops rdma_svc_ops; 85 0 stevel /* End of Tunables */ 86 7387 Robert 87 7387 Robert static int rdma_setup_read_data4(READ4args *, READ4res *); 88 0 stevel 89 0 stevel /* 90 0 stevel * Used to bump the stateid4.seqid value and show changes in the stateid 91 0 stevel */ 92 0 stevel #define next_stateid(sp) (++(sp)->bits.chgseq) 93 0 stevel 94 0 stevel /* 95 0 stevel * RFS4_MINLEN_ENTRY4: XDR-encoded size of smallest possible dirent. 96 0 stevel * This is used to return NFS4ERR_TOOSMALL when clients specify 97 0 stevel * maxcount that isn't large enough to hold the smallest possible 98 0 stevel * XDR encoded dirent. 99 0 stevel * 100 0 stevel * sizeof cookie (8 bytes) + 101 0 stevel * sizeof name_len (4 bytes) + 102 0 stevel * sizeof smallest (padded) name (4 bytes) + 103 0 stevel * sizeof bitmap4_len (12 bytes) + NOTE: we always encode len=2 bm4 104 0 stevel * sizeof attrlist4_len (4 bytes) + 105 0 stevel * sizeof next boolean (4 bytes) 106 0 stevel * 107 0 stevel * RFS4_MINLEN_RDDIR4: XDR-encoded size of READDIR op reply containing 108 0 stevel * the smallest possible entry4 (assumes no attrs requested). 109 0 stevel * sizeof nfsstat4 (4 bytes) + 110 0 stevel * sizeof verifier4 (8 bytes) + 111 0 stevel * sizeof entry4list bool (4 bytes) + 112 0 stevel * sizeof entry4 (36 bytes) + 113 0 stevel * sizeof eof bool (4 bytes) 114 0 stevel * 115 0 stevel * RFS4_MINLEN_RDDIR_BUF: minimum length of buffer server will provide to 116 0 stevel * VOP_READDIR. Its value is the size of the maximum possible dirent 117 0 stevel * for solaris. The DIRENT64_RECLEN macro returns the size of dirent 118 0 stevel * required for a given name length. MAXNAMELEN is the maximum 119 0 stevel * filename length allowed in Solaris. The first two DIRENT64_RECLEN() 120 0 stevel * macros are to allow for . and .. entries -- just a minor tweak to try 121 0 stevel * and guarantee that buffer we give to VOP_READDIR will be large enough 122 0 stevel * to hold ., .., and the largest possible solaris dirent64. 123 0 stevel */ 124 0 stevel #define RFS4_MINLEN_ENTRY4 36 125 0 stevel #define RFS4_MINLEN_RDDIR4 (4 + NFS4_VERIFIER_SIZE + 4 + RFS4_MINLEN_ENTRY4 + 4) 126 0 stevel #define RFS4_MINLEN_RDDIR_BUF \ 127 0 stevel (DIRENT64_RECLEN(1) + DIRENT64_RECLEN(2) + DIRENT64_RECLEN(MAXNAMELEN)) 128 0 stevel 129 0 stevel /* 130 0 stevel * It would be better to pad to 4 bytes since that's what XDR would do, 131 0 stevel * but the dirents UFS gives us are already padded to 8, so just take 132 0 stevel * what we're given. Dircount is only a hint anyway. Currently the 133 0 stevel * solaris kernel is ASCII only, so there's no point in calling the 134 0 stevel * UTF8 functions. 135 0 stevel * 136 0 stevel * dirent64: named padded to provide 8 byte struct alignment 137 0 stevel * d_ino(8) + d_off(8) + d_reclen(2) + d_name(namelen + null(1) + pad) 138 0 stevel * 139 0 stevel * cookie: uint64_t + utf8namelen: uint_t + utf8name padded to 8 bytes 140 0 stevel * 141 0 stevel */ 142 0 stevel #define DIRENT64_TO_DIRCOUNT(dp) \ 143 0 stevel (3 * BYTES_PER_XDR_UNIT + DIRENT64_NAMELEN((dp)->d_reclen)) 144 0 stevel 145 0 stevel time_t rfs4_start_time; /* Initialized in rfs4_srvrinit */ 146 0 stevel 147 0 stevel static sysid_t lockt_sysid; /* dummy sysid for all LOCKT calls */ 148 0 stevel 149 7387 Robert u_longlong_t nfs4_srv_caller_id; 150 7387 Robert uint_t nfs4_srv_vkey = 0; 151 0 stevel 152 0 stevel verifier4 Write4verf; 153 0 stevel verifier4 Readdir4verf; 154 0 stevel 155 7387 Robert void rfs4_init_compound_state(struct compound_state *); 156 0 stevel 157 0 stevel static void nullfree(caddr_t); 158 0 stevel static void rfs4_op_inval(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 159 0 stevel struct compound_state *); 160 0 stevel static void rfs4_op_access(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 161 0 stevel struct compound_state *); 162 0 stevel static void rfs4_op_close(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 163 0 stevel struct compound_state *); 164 0 stevel static void rfs4_op_commit(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 165 0 stevel struct compound_state *); 166 0 stevel static void rfs4_op_create(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 167 0 stevel struct compound_state *); 168 0 stevel static void rfs4_op_create_free(nfs_resop4 *resop); 169 0 stevel static void rfs4_op_delegreturn(nfs_argop4 *, nfs_resop4 *, 170 5647 samf struct svc_req *, struct compound_state *); 171 5647 samf static void rfs4_op_delegpurge(nfs_argop4 *, nfs_resop4 *, 172 5647 samf struct svc_req *, struct compound_state *); 173 0 stevel static void rfs4_op_getattr(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 174 0 stevel struct compound_state *); 175 0 stevel static void rfs4_op_getattr_free(nfs_resop4 *); 176 0 stevel static void rfs4_op_getfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 177 0 stevel struct compound_state *); 178 0 stevel static void rfs4_op_getfh_free(nfs_resop4 *); 179 0 stevel static void rfs4_op_illegal(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 180 0 stevel struct compound_state *); 181 0 stevel static void rfs4_op_link(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 182 0 stevel struct compound_state *); 183 0 stevel static void rfs4_op_lock(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 184 0 stevel struct compound_state *); 185 0 stevel static void lock_denied_free(nfs_resop4 *); 186 0 stevel static void rfs4_op_locku(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 187 0 stevel struct compound_state *); 188 0 stevel static void rfs4_op_lockt(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 189 0 stevel struct compound_state *); 190 0 stevel static void rfs4_op_lookup(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 191 0 stevel struct compound_state *); 192 0 stevel static void rfs4_op_lookupp(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 193 0 stevel struct compound_state *); 194 0 stevel static void rfs4_op_openattr(nfs_argop4 *argop, nfs_resop4 *resop, 195 0 stevel struct svc_req *req, struct compound_state *cs); 196 0 stevel static void rfs4_op_nverify(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 197 0 stevel struct compound_state *); 198 0 stevel static void rfs4_op_open(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 199 0 stevel struct compound_state *); 200 0 stevel static void rfs4_op_open_confirm(nfs_argop4 *, nfs_resop4 *, 201 0 stevel struct svc_req *, struct compound_state *); 202 0 stevel static void rfs4_op_open_downgrade(nfs_argop4 *, nfs_resop4 *, 203 0 stevel struct svc_req *, struct compound_state *); 204 0 stevel static void rfs4_op_putfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 205 0 stevel struct compound_state *); 206 0 stevel static void rfs4_op_putpubfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 207 0 stevel struct compound_state *); 208 0 stevel static void rfs4_op_putrootfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 209 0 stevel struct compound_state *); 210 0 stevel static void rfs4_op_read(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 211 0 stevel struct compound_state *); 212 0 stevel static void rfs4_op_read_free(nfs_resop4 *); 213 0 stevel static void rfs4_op_readdir_free(nfs_resop4 *resop); 214 0 stevel static void rfs4_op_readlink(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 215 0 stevel struct compound_state *); 216 0 stevel static void rfs4_op_readlink_free(nfs_resop4 *); 217 0 stevel static void rfs4_op_release_lockowner(nfs_argop4 *, nfs_resop4 *, 218 0 stevel struct svc_req *, struct compound_state *); 219 0 stevel static void rfs4_op_remove(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 220 0 stevel struct compound_state *); 221 0 stevel static void rfs4_op_rename(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 222 0 stevel struct compound_state *); 223 0 stevel static void rfs4_op_renew(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 224 0 stevel struct compound_state *); 225 0 stevel static void rfs4_op_restorefh(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 226 0 stevel struct compound_state *); 227 0 stevel static void rfs4_op_savefh(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 228 0 stevel struct compound_state *); 229 0 stevel static void rfs4_op_setattr(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 230 0 stevel struct compound_state *); 231 0 stevel static void rfs4_op_verify(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 232 0 stevel struct compound_state *); 233 0 stevel static void rfs4_op_write(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 234 0 stevel struct compound_state *); 235 0 stevel static void rfs4_op_setclientid(nfs_argop4 *, nfs_resop4 *, 236 0 stevel struct svc_req *, struct compound_state *); 237 0 stevel static void rfs4_op_setclientid_confirm(nfs_argop4 *, nfs_resop4 *, 238 0 stevel struct svc_req *req, struct compound_state *); 239 0 stevel static void rfs4_op_secinfo(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 240 0 stevel struct compound_state *); 241 0 stevel static void rfs4_op_secinfo_free(nfs_resop4 *); 242 0 stevel 243 0 stevel static nfsstat4 check_open_access(uint32_t, 244 0 stevel struct compound_state *, struct svc_req *); 245 0 stevel nfsstat4 rfs4_client_sysid(rfs4_client_t *, sysid_t *); 246 0 stevel void rfs4_ss_clid(rfs4_client_t *, struct svc_req *); 247 0 stevel 248 0 stevel /* 249 0 stevel * translation table for attrs 250 0 stevel */ 251 0 stevel struct nfs4_ntov_table { 252 0 stevel union nfs4_attr_u *na; 253 0 stevel uint8_t amap[NFS4_MAXNUM_ATTRS]; 254 0 stevel int attrcnt; 255 0 stevel bool_t vfsstat; 256 0 stevel }; 257 0 stevel 258 0 stevel static void nfs4_ntov_table_init(struct nfs4_ntov_table *ntovp); 259 0 stevel static void nfs4_ntov_table_free(struct nfs4_ntov_table *ntovp, 260 0 stevel struct nfs4_svgetit_arg *sargp); 261 0 stevel 262 0 stevel static nfsstat4 do_rfs4_set_attrs(bitmap4 *resp, fattr4 *fattrp, 263 0 stevel struct compound_state *cs, struct nfs4_svgetit_arg *sargp, 264 0 stevel struct nfs4_ntov_table *ntovp, nfs4_attr_cmd_t cmd); 265 0 stevel 266 7387 Robert fem_t *deleg_rdops; 267 7387 Robert fem_t *deleg_wrops; 268 7387 Robert 269 7387 Robert rfs4_servinst_t *rfs4_cur_servinst = NULL; /* current server instance */ 270 7387 Robert kmutex_t rfs4_servinst_lock; /* protects linked list */ 271 0 stevel int rfs4_seen_first_compound; /* set first time we see one */ 272 0 stevel 273 0 stevel /* 274 0 stevel * NFS4 op dispatch table 275 0 stevel */ 276 0 stevel 277 0 stevel struct rfsv4disp { 278 0 stevel void (*dis_proc)(); /* proc to call */ 279 0 stevel void (*dis_resfree)(); /* frees space allocated by proc */ 280 0 stevel int dis_flags; /* RPC_IDEMPOTENT, etc... */ 281 0 stevel }; 282 0 stevel 283 0 stevel static struct rfsv4disp rfsv4disptab[] = { 284 0 stevel /* 285 0 stevel * NFS VERSION 4 286 0 stevel */ 287 0 stevel 288 0 stevel /* RFS_NULL = 0 */ 289 0 stevel {rfs4_op_illegal, nullfree, 0}, 290 0 stevel 291 0 stevel /* UNUSED = 1 */ 292 0 stevel {rfs4_op_illegal, nullfree, 0}, 293 0 stevel 294 0 stevel /* UNUSED = 2 */ 295 0 stevel {rfs4_op_illegal, nullfree, 0}, 296 0 stevel 297 0 stevel /* OP_ACCESS = 3 */ 298 0 stevel {rfs4_op_access, nullfree, RPC_IDEMPOTENT}, 299 0 stevel 300 0 stevel /* OP_CLOSE = 4 */ 301 0 stevel {rfs4_op_close, nullfree, 0}, 302 0 stevel 303 0 stevel /* OP_COMMIT = 5 */ 304 0 stevel {rfs4_op_commit, nullfree, RPC_IDEMPOTENT}, 305 0 stevel 306 0 stevel /* OP_CREATE = 6 */ 307 0 stevel {rfs4_op_create, nullfree, 0}, 308 0 stevel 309 0 stevel /* OP_DELEGPURGE = 7 */ 310 5647 samf {rfs4_op_delegpurge, nullfree, 0}, 311 0 stevel 312 0 stevel /* OP_DELEGRETURN = 8 */ 313 0 stevel {rfs4_op_delegreturn, nullfree, 0}, 314 0 stevel 315 0 stevel /* OP_GETATTR = 9 */ 316 0 stevel {rfs4_op_getattr, rfs4_op_getattr_free, RPC_IDEMPOTENT}, 317 0 stevel 318 0 stevel /* OP_GETFH = 10 */ 319 0 stevel {rfs4_op_getfh, rfs4_op_getfh_free, RPC_ALL}, 320 0 stevel 321 0 stevel /* OP_LINK = 11 */ 322 0 stevel {rfs4_op_link, nullfree, 0}, 323 0 stevel 324 0 stevel /* OP_LOCK = 12 */ 325 0 stevel {rfs4_op_lock, lock_denied_free, 0}, 326 0 stevel 327 0 stevel /* OP_LOCKT = 13 */ 328 0 stevel {rfs4_op_lockt, lock_denied_free, 0}, 329 0 stevel 330 0 stevel /* OP_LOCKU = 14 */ 331 0 stevel {rfs4_op_locku, nullfree, 0}, 332 0 stevel 333 0 stevel /* OP_LOOKUP = 15 */ 334 7387 Robert {rfs4_op_lookup, nullfree, (RPC_IDEMPOTENT | RPC_PUBLICFH_OK)}, 335 0 stevel 336 0 stevel /* OP_LOOKUPP = 16 */ 337 7387 Robert {rfs4_op_lookupp, nullfree, (RPC_IDEMPOTENT | RPC_PUBLICFH_OK)}, 338 0 stevel 339 0 stevel /* OP_NVERIFY = 17 */ 340 0 stevel {rfs4_op_nverify, nullfree, RPC_IDEMPOTENT}, 341 0 stevel 342 0 stevel /* OP_OPEN = 18 */ 343 0 stevel {rfs4_op_open, rfs4_free_reply, 0}, 344 0 stevel 345 0 stevel /* OP_OPENATTR = 19 */ 346 0 stevel {rfs4_op_openattr, nullfree, 0}, 347 0 stevel 348 0 stevel /* OP_OPEN_CONFIRM = 20 */ 349 0 stevel {rfs4_op_open_confirm, nullfree, 0}, 350 0 stevel 351 0 stevel /* OP_OPEN_DOWNGRADE = 21 */ 352 0 stevel {rfs4_op_open_downgrade, nullfree, 0}, 353 0 stevel 354 0 stevel /* OP_OPEN_PUTFH = 22 */ 355 0 stevel {rfs4_op_putfh, nullfree, RPC_ALL}, 356 0 stevel 357 0 stevel /* OP_PUTPUBFH = 23 */ 358 0 stevel {rfs4_op_putpubfh, nullfree, RPC_ALL}, 359 0 stevel 360 0 stevel /* OP_PUTROOTFH = 24 */ 361 0 stevel {rfs4_op_putrootfh, nullfree, RPC_ALL}, 362 0 stevel 363 0 stevel /* OP_READ = 25 */ 364 0 stevel {rfs4_op_read, rfs4_op_read_free, RPC_IDEMPOTENT}, 365 0 stevel 366 0 stevel /* OP_READDIR = 26 */ 367 0 stevel {rfs4_op_readdir, rfs4_op_readdir_free, RPC_IDEMPOTENT}, 368 0 stevel 369 0 stevel /* OP_READLINK = 27 */ 370 0 stevel {rfs4_op_readlink, rfs4_op_readlink_free, RPC_IDEMPOTENT}, 371 0 stevel 372 0 stevel /* OP_REMOVE = 28 */ 373 0 stevel {rfs4_op_remove, nullfree, 0}, 374 0 stevel 375 0 stevel /* OP_RENAME = 29 */ 376 0 stevel {rfs4_op_rename, nullfree, 0}, 377 0 stevel 378 0 stevel /* OP_RENEW = 30 */ 379 0 stevel {rfs4_op_renew, nullfree, 0}, 380 0 stevel 381 0 stevel /* OP_RESTOREFH = 31 */ 382 0 stevel {rfs4_op_restorefh, nullfree, RPC_ALL}, 383 0 stevel 384 0 stevel /* OP_SAVEFH = 32 */ 385 0 stevel {rfs4_op_savefh, nullfree, RPC_ALL}, 386 0 stevel 387 0 stevel /* OP_SECINFO = 33 */ 388 0 stevel {rfs4_op_secinfo, rfs4_op_secinfo_free, 0}, 389 0 stevel 390 0 stevel /* OP_SETATTR = 34 */ 391 0 stevel {rfs4_op_setattr, nullfree, 0}, 392 0 stevel 393 0 stevel /* OP_SETCLIENTID = 35 */ 394 0 stevel {rfs4_op_setclientid, nullfree, 0}, 395 0 stevel 396 0 stevel /* OP_SETCLIENTID_CONFIRM = 36 */ 397 0 stevel {rfs4_op_setclientid_confirm, nullfree, 0}, 398 0 stevel 399 0 stevel /* OP_VERIFY = 37 */ 400 0 stevel {rfs4_op_verify, nullfree, RPC_IDEMPOTENT}, 401 0 stevel 402 0 stevel /* OP_WRITE = 38 */ 403 0 stevel {rfs4_op_write, nullfree, 0}, 404 0 stevel 405 0 stevel /* OP_RELEASE_LOCKOWNER = 39 */ 406 0 stevel {rfs4_op_release_lockowner, nullfree, 0}, 407 0 stevel }; 408 0 stevel 409 0 stevel static uint_t rfsv4disp_cnt = sizeof (rfsv4disptab) / sizeof (rfsv4disptab[0]); 410 0 stevel 411 0 stevel #define OP_ILLEGAL_IDX (rfsv4disp_cnt) 412 0 stevel 413 0 stevel #ifdef DEBUG 414 0 stevel 415 7387 Robert int rfs4_fillone_debug = 0; 416 7387 Robert int rfs4_no_stub_access = 1; 417 7387 Robert int rfs4_rddir_debug = 0; 418 7387 Robert 419 7387 Robert static char *rfs4_op_string[] = { 420 0 stevel "rfs4_op_null", 421 0 stevel "rfs4_op_1 unused", 422 0 stevel "rfs4_op_2 unused", 423 0 stevel "rfs4_op_access", 424 0 stevel "rfs4_op_close", 425 0 stevel "rfs4_op_commit", 426 0 stevel "rfs4_op_create", 427 0 stevel "rfs4_op_delegpurge", 428 0 stevel "rfs4_op_delegreturn", 429 0 stevel "rfs4_op_getattr", 430 0 stevel "rfs4_op_getfh", 431 0 stevel "rfs4_op_link", 432 0 stevel "rfs4_op_lock", 433 0 stevel "rfs4_op_lockt", 434 0 stevel "rfs4_op_locku", 435 0 stevel "rfs4_op_lookup", 436 0 stevel "rfs4_op_lookupp", 437 0 stevel "rfs4_op_nverify", 438 0 stevel "rfs4_op_open", 439 0 stevel "rfs4_op_openattr", 440 0 stevel "rfs4_op_open_confirm", 441 0 stevel "rfs4_op_open_downgrade", 442 0 stevel "rfs4_op_putfh", 443 0 stevel "rfs4_op_putpubfh", 444 0 stevel "rfs4_op_putrootfh", 445 0 stevel "rfs4_op_read", 446 0 stevel "rfs4_op_readdir", 447 0 stevel "rfs4_op_readlink", 448 0 stevel "rfs4_op_remove", 449 0 stevel "rfs4_op_rename", 450 0 stevel "rfs4_op_renew", 451 0 stevel "rfs4_op_restorefh", 452 0 stevel "rfs4_op_savefh", 453 0 stevel "rfs4_op_secinfo", 454 0 stevel "rfs4_op_setattr", 455 0 stevel "rfs4_op_setclientid", 456 0 stevel "rfs4_op_setclient_confirm", 457 0 stevel "rfs4_op_verify", 458 0 stevel "rfs4_op_write", 459 0 stevel "rfs4_op_release_lockowner", 460 0 stevel "rfs4_op_illegal" 461 0 stevel }; 462 0 stevel #endif 463 0 stevel 464 7387 Robert void rfs4_ss_chkclid(rfs4_client_t *); 465 7387 Robert 466 7387 Robert extern size_t strlcpy(char *dst, const char *src, size_t dstsize); 467 2035 calum 468 0 stevel #ifdef nextdp 469 0 stevel #undef nextdp 470 0 stevel #endif 471 0 stevel #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen)) 472 0 stevel 473 0 stevel static const fs_operation_def_t nfs4_rd_deleg_tmpl[] = { 474 5599 jwahlig VOPNAME_OPEN, { .femop_open = deleg_rd_open }, 475 5599 jwahlig VOPNAME_WRITE, { .femop_write = deleg_rd_write }, 476 5599 jwahlig VOPNAME_SETATTR, { .femop_setattr = deleg_rd_setattr }, 477 3898 rsb VOPNAME_RWLOCK, { .femop_rwlock = deleg_rd_rwlock }, 478 5599 jwahlig VOPNAME_SPACE, { .femop_space = deleg_rd_space }, 479 5599 jwahlig VOPNAME_SETSECATTR, { .femop_setsecattr = deleg_rd_setsecattr }, 480 5599 jwahlig VOPNAME_VNEVENT, { .femop_vnevent = deleg_rd_vnevent }, 481 3898 rsb NULL, NULL 482 0 stevel }; 483 0 stevel static const fs_operation_def_t nfs4_wr_deleg_tmpl[] = { 484 5599 jwahlig VOPNAME_OPEN, { .femop_open = deleg_wr_open }, 485 5599 jwahlig VOPNAME_READ, { .femop_read = deleg_wr_read }, 486 5599 jwahlig VOPNAME_WRITE, { .femop_write = deleg_wr_write }, 487 5599 jwahlig VOPNAME_SETATTR, { .femop_setattr = deleg_wr_setattr }, 488 3898 rsb VOPNAME_RWLOCK, { .femop_rwlock = deleg_wr_rwlock }, 489 5599 jwahlig VOPNAME_SPACE, { .femop_space = deleg_wr_space }, 490 5599 jwahlig VOPNAME_SETSECATTR, { .femop_setsecattr = deleg_wr_setsecattr }, 491 5599 jwahlig VOPNAME_VNEVENT, { .femop_vnevent = deleg_wr_vnevent }, 492 3898 rsb NULL, NULL 493 0 stevel }; 494 0 stevel 495 0 stevel int 496 0 stevel rfs4_srvrinit(void) 497 0 stevel { 498 0 stevel timespec32_t verf; 499 0 stevel int error; 500 0 stevel extern void rfs4_attr_init(); 501 0 stevel extern krwlock_t rfs4_deleg_policy_lock; 502 0 stevel 503 0 stevel /* 504 0 stevel * The following algorithm attempts to find a unique verifier 505 0 stevel * to be used as the write verifier returned from the server 506 0 stevel * to the client. It is important that this verifier change 507 0 stevel * whenever the server reboots. Of secondary importance, it 508 0 stevel * is important for the verifier to be unique between two 509 0 stevel * different servers. 510 0 stevel * 511 0 stevel * Thus, an attempt is made to use the system hostid and the 512 0 stevel * current time in seconds when the nfssrv kernel module is 513 0 stevel * loaded. It is assumed that an NFS server will not be able 514 0 stevel * to boot and then to reboot in less than a second. If the 515 0 stevel * hostid has not been set, then the current high resolution 516 0 stevel * time is used. This will ensure different verifiers each 517 0 stevel * time the server reboots and minimize the chances that two 518 0 stevel * different servers will have the same verifier. 519 0 stevel * XXX - this is broken on LP64 kernels. 520 0 stevel */ 521 8662 Jordan verf.tv_sec = (time_t)zone_get_hostid(NULL); 522 0 stevel if (verf.tv_sec != 0) { 523 0 stevel verf.tv_nsec = gethrestime_sec(); 524 0 stevel } else { 525 0 stevel timespec_t tverf; 526 0 stevel 527 0 stevel gethrestime(&tverf); 528 0 stevel verf.tv_sec = (time_t)tverf.tv_sec; 529 0 stevel verf.tv_nsec = tverf.tv_nsec; 530 0 stevel } 531 0 stevel 532 0 stevel Write4verf = *(uint64_t *)&verf; 533 0 stevel 534 0 stevel rfs4_attr_init(); 535 0 stevel mutex_init(&rfs4_deleg_lock, NULL, MUTEX_DEFAULT, NULL); 536 0 stevel 537 0 stevel /* Used to manage create/destroy of server state */ 538 0 stevel mutex_init(&rfs4_state_lock, NULL, MUTEX_DEFAULT, NULL); 539 0 stevel 540 0 stevel /* Used to manage access to server instance linked list */ 541 0 stevel mutex_init(&rfs4_servinst_lock, NULL, MUTEX_DEFAULT, NULL); 542 0 stevel 543 0 stevel /* Used to manage access to rfs4_deleg_policy */ 544 0 stevel rw_init(&rfs4_deleg_policy_lock, NULL, RW_DEFAULT, NULL); 545 0 stevel 546 0 stevel error = fem_create("deleg_rdops", nfs4_rd_deleg_tmpl, &deleg_rdops); 547 0 stevel if (error != 0) { 548 0 stevel rfs4_disable_delegation(); 549 0 stevel } else { 550 0 stevel error = fem_create("deleg_wrops", nfs4_wr_deleg_tmpl, 551 5050 jwahlig &deleg_wrops); 552 0 stevel if (error != 0) { 553 0 stevel rfs4_disable_delegation(); 554 0 stevel fem_free(deleg_rdops); 555 0 stevel } 556 0 stevel } 557 0 stevel 558 0 stevel nfs4_srv_caller_id = fs_new_caller_id(); 559 0 stevel 560 0 stevel lockt_sysid = lm_alloc_sysidt(); 561 5050 jwahlig 562 5050 jwahlig vsd_create(&nfs4_srv_vkey, NULL); 563 0 stevel 564 0 stevel return (0); 565 0 stevel } 566 0 stevel 567 0 stevel void 568 0 stevel rfs4_srvrfini(void) 569 0 stevel { 570 0 stevel extern krwlock_t rfs4_deleg_policy_lock; 571 0 stevel 572 0 stevel if (lockt_sysid != LM_NOSYSID) { 573 0 stevel lm_free_sysidt(lockt_sysid); 574 0 stevel lockt_sysid = LM_NOSYSID; 575 0 stevel } 576 0 stevel 577 0 stevel mutex_destroy(&rfs4_deleg_lock); 578 0 stevel mutex_destroy(&rfs4_state_lock); 579 0 stevel rw_destroy(&rfs4_deleg_policy_lock); 580 0 stevel 581 0 stevel fem_free(deleg_rdops); 582 0 stevel fem_free(deleg_wrops); 583 0 stevel } 584 0 stevel 585 0 stevel void 586 0 stevel rfs4_init_compound_state(struct compound_state *cs) 587 0 stevel { 588 0 stevel bzero(cs, sizeof (*cs)); 589 0 stevel cs->cont = TRUE; 590 0 stevel cs->access = CS_ACCESS_DENIED; 591 0 stevel cs->deleg = FALSE; 592 0 stevel cs->mandlock = FALSE; 593 0 stevel cs->fh.nfs_fh4_val = cs->fhbuf; 594 0 stevel } 595 0 stevel 596 0 stevel void 597 0 stevel rfs4_grace_start(rfs4_servinst_t *sip) 598 0 stevel { 599 0 stevel rw_enter(&sip->rwlock, RW_WRITER); 600 11066 rafael sip->start_time = (time_t)TICK_TO_SEC(ddi_get_lbolt()); 601 0 stevel sip->grace_period = rfs4_grace_period; 602 0 stevel rw_exit(&sip->rwlock); 603 0 stevel } 604 0 stevel 605 0 stevel /* 606 0 stevel * returns true if the instance's grace period has never been started 607 0 stevel */ 608 0 stevel int 609 0 stevel rfs4_servinst_grace_new(rfs4_servinst_t *sip) 610 0 stevel { 611 0 stevel time_t start_time; 612 0 stevel 613 0 stevel rw_enter(&sip->rwlock, RW_READER); 614 0 stevel start_time = sip->start_time; 615 0 stevel rw_exit(&sip->rwlock); 616 0 stevel 617 0 stevel return (start_time == 0); 618 0 stevel } 619 0 stevel 620 0 stevel /* 621 0 stevel * Indicates if server instance is within the 622 0 stevel * grace period. 623 0 stevel */ 624 0 stevel int 625 0 stevel rfs4_servinst_in_grace(rfs4_servinst_t *sip) 626 0 stevel { 627 0 stevel time_t grace_expiry; 628 0 stevel 629 0 stevel rw_enter(&sip->rwlock, RW_READER); 630 0 stevel grace_expiry = sip->start_time + sip->grace_period; 631 0 stevel rw_exit(&sip->rwlock); 632 0 stevel 633 11066 rafael return (((time_t)TICK_TO_SEC(ddi_get_lbolt())) < grace_expiry); 634 0 stevel } 635 0 stevel 636 0 stevel int 637 0 stevel rfs4_clnt_in_grace(rfs4_client_t *cp) 638 0 stevel { 639 9885 Robert ASSERT(rfs4_dbe_refcnt(cp->rc_dbe) > 0); 640 9885 Robert 641 9885 Robert return (rfs4_servinst_in_grace(cp->rc_server_instance)); 642 0 stevel } 643 0 stevel 644 0 stevel /* 645 0 stevel * reset all currently active grace periods 646 0 stevel */ 647 0 stevel void 648 0 stevel rfs4_grace_reset_all(void) 649 0 stevel { 650 0 stevel rfs4_servinst_t *sip; 651 0 stevel 652 0 stevel mutex_enter(&rfs4_servinst_lock); 653 2035 calum for (sip = rfs4_cur_servinst; sip != NULL; sip = sip->prev) 654 2035 calum if (rfs4_servinst_in_grace(sip)) 655 0 stevel rfs4_grace_start(sip); 656 0 stevel mutex_exit(&rfs4_servinst_lock); 657 0 stevel } 658 0 stevel 659 0 stevel /* 660 0 stevel * start any new instances' grace periods 661 0 stevel */ 662 0 stevel void 663 0 stevel rfs4_grace_start_new(void) 664 0 stevel { 665 0 stevel rfs4_servinst_t *sip; 666 0 stevel 667 0 stevel mutex_enter(&rfs4_servinst_lock); 668 2035 calum for (sip = rfs4_cur_servinst; sip != NULL; sip = sip->prev) 669 0 stevel if (rfs4_servinst_grace_new(sip)) 670 0 stevel rfs4_grace_start(sip); 671 0 stevel mutex_exit(&rfs4_servinst_lock); 672 2035 calum } 673 2035 calum 674 2035 calum static rfs4_dss_path_t * 675 2035 calum rfs4_dss_newpath(rfs4_servinst_t *sip, char *path, unsigned index) 676 2035 calum { 677 2035 calum size_t len; 678 2035 calum rfs4_dss_path_t *dss_path; 679 2035 calum 680 2035 calum dss_path = kmem_alloc(sizeof (rfs4_dss_path_t), KM_SLEEP); 681 2035 calum 682 2035 calum /* 683 2035 calum * Take a copy of the string, since the original may be overwritten. 684 2035 calum * Sadly, no strdup() in the kernel. 685 2035 calum */ 686 2035 calum /* allow for NUL */ 687 2035 calum len = strlen(path) + 1; 688 2035 calum dss_path->path = kmem_alloc(len, KM_SLEEP); 689 2035 calum (void) strlcpy(dss_path->path, path, len); 690 2035 calum 691 2035 calum /* associate with servinst */ 692 2035 calum dss_path->sip = sip; 693 2035 calum dss_path->index = index; 694 2035 calum 695 2035 calum /* 696 2035 calum * Add to list of served paths. 697 2035 calum * No locking required, as we're only ever called at startup. 698 2035 calum */ 699 2035 calum if (rfs4_dss_pathlist == NULL) { 700 2035 calum /* this is the first dss_path_t */ 701 2035 calum 702 2035 calum /* needed for insque/remque */ 703 2035 calum dss_path->next = dss_path->prev = dss_path; 704 2035 calum 705 2035 calum rfs4_dss_pathlist = dss_path; 706 2035 calum } else { 707 2035 calum insque(dss_path, rfs4_dss_pathlist); 708 2035 calum } 709 2035 calum 710 2035 calum return (dss_path); 711 0 stevel } 712 0 stevel 713 0 stevel /* 714 0 stevel * Create a new server instance, and make it the currently active instance. 715 0 stevel * Note that starting the grace period too early will reduce the clients' 716 0 stevel * recovery window. 717 0 stevel */ 718 0 stevel void 719 2035 calum rfs4_servinst_create(int start_grace, int dss_npaths, char **dss_paths) 720 2035 calum { 721 2035 calum unsigned i; 722 0 stevel rfs4_servinst_t *sip; 723 2035 calum rfs4_oldstate_t *oldstate; 724 0 stevel 725 0 stevel sip = kmem_alloc(sizeof (rfs4_servinst_t), KM_SLEEP); 726 0 stevel rw_init(&sip->rwlock, NULL, RW_DEFAULT, NULL); 727 0 stevel 728 0 stevel sip->start_time = (time_t)0; 729 0 stevel sip->grace_period = (time_t)0; 730 0 stevel sip->next = NULL; 731 0 stevel sip->prev = NULL; 732 0 stevel 733 2035 calum rw_init(&sip->oldstate_lock, NULL, RW_DEFAULT, NULL); 734 2035 calum /* 735 2035 calum * This initial dummy entry is required to setup for insque/remque. 736 2035 calum * It must be skipped over whenever the list is traversed. 737 2035 calum */ 738 2035 calum oldstate = kmem_alloc(sizeof (rfs4_oldstate_t), KM_SLEEP); 739 2035 calum /* insque/remque require initial list entry to be self-terminated */ 740 2035 calum oldstate->next = oldstate; 741 2035 calum oldstate->prev = oldstate; 742 2035 calum sip->oldstate = oldstate; 743 2035 calum 744 2035 calum 745 2035 calum sip->dss_npaths = dss_npaths; 746 2035 calum sip->dss_paths = kmem_alloc(dss_npaths * 747 2035 calum sizeof (rfs4_dss_path_t *), KM_SLEEP); 748 2035 calum 749 2035 calum for (i = 0; i < dss_npaths; i++) { 750 2035 calum sip->dss_paths[i] = rfs4_dss_newpath(sip, dss_paths[i], i); 751 2035 calum } 752 2035 calum 753 0 stevel mutex_enter(&rfs4_servinst_lock); 754 2035 calum if (rfs4_cur_servinst != NULL) { 755 0 stevel /* add to linked list */ 756 0 stevel sip->prev = rfs4_cur_servinst; 757 0 stevel rfs4_cur_servinst->next = sip; 758 0 stevel } 759 0 stevel if (start_grace) 760 0 stevel rfs4_grace_start(sip); 761 0 stevel /* make the new instance "current" */ 762 0 stevel rfs4_cur_servinst = sip; 763 2035 calum 764 0 stevel mutex_exit(&rfs4_servinst_lock); 765 0 stevel } 766 0 stevel 767 0 stevel /* 768 0 stevel * In future, we might add a rfs4_servinst_destroy(sip) but, for now, destroy 769 0 stevel * all instances directly. 770 0 stevel */ 771 0 stevel void 772 0 stevel rfs4_servinst_destroy_all(void) 773 0 stevel { 774 0 stevel rfs4_servinst_t *sip, *prev, *current; 775 0 stevel #ifdef DEBUG 776 0 stevel int n = 0; 777 0 stevel #endif 778 0 stevel 779 0 stevel mutex_enter(&rfs4_servinst_lock); 780 0 stevel ASSERT(rfs4_cur_servinst != NULL); 781 0 stevel current = rfs4_cur_servinst; 782 0 stevel rfs4_cur_servinst = NULL; 783 0 stevel for (sip = current; sip != NULL; sip = prev) { 784 0 stevel prev = sip->prev; 785 0 stevel rw_destroy(&sip->rwlock); 786 2035 calum if (sip->oldstate) 787 2035 calum kmem_free(sip->oldstate, sizeof (rfs4_oldstate_t)); 788 2035 calum if (sip->dss_paths) 789 2035 calum kmem_free(sip->dss_paths, 790 2035 calum sip->dss_npaths * sizeof (rfs4_dss_path_t *)); 791 0 stevel kmem_free(sip, sizeof (rfs4_servinst_t)); 792 0 stevel #ifdef DEBUG 793 0 stevel n++; 794 0 stevel #endif 795 0 stevel } 796 0 stevel mutex_exit(&rfs4_servinst_lock); 797 0 stevel } 798 0 stevel 799 0 stevel /* 800 0 stevel * Assign the current server instance to a client_t. 801 9885 Robert * Should be called with cp->rc_dbe held. 802 0 stevel */ 803 0 stevel void 804 0 stevel rfs4_servinst_assign(rfs4_client_t *cp, rfs4_servinst_t *sip) 805 0 stevel { 806 9885 Robert ASSERT(rfs4_dbe_refcnt(cp->rc_dbe) > 0); 807 0 stevel 808 0 stevel /* 809 0 stevel * The lock ensures that if the current instance is in the process 810 0 stevel * of changing, we will see the new one. 811 0 stevel */ 812 0 stevel mutex_enter(&rfs4_servinst_lock); 813 9885 Robert cp->rc_server_instance = sip; 814 0 stevel mutex_exit(&rfs4_servinst_lock); 815 0 stevel } 816 0 stevel 817 0 stevel rfs4_servinst_t * 818 0 stevel rfs4_servinst(rfs4_client_t *cp) 819 0 stevel { 820 9885 Robert ASSERT(rfs4_dbe_refcnt(cp->rc_dbe) > 0); 821 9885 Robert 822 9885 Robert return (cp->rc_server_instance); 823 0 stevel } 824 0 stevel 825 0 stevel /* ARGSUSED */ 826 0 stevel static void 827 0 stevel nullfree(caddr_t resop) 828 0 stevel { 829 0 stevel } 830 0 stevel 831 0 stevel /* 832 0 stevel * This is a fall-through for invalid or not implemented (yet) ops 833 0 stevel */ 834 0 stevel /* ARGSUSED */ 835 0 stevel static void 836 0 stevel rfs4_op_inval(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 837 0 stevel struct compound_state *cs) 838 0 stevel { 839 0 stevel *cs->statusp = *((nfsstat4 *)&(resop)->nfs_resop4_u) = NFS4ERR_INVAL; 840 0 stevel } 841 0 stevel 842 0 stevel /* 843 0 stevel * Check if the security flavor, nfsnum, is in the flavor_list. 844 0 stevel */ 845 0 stevel bool_t 846 0 stevel in_flavor_list(int nfsnum, int *flavor_list, int count) 847 0 stevel { 848 0 stevel int i; 849 0 stevel 850 0 stevel for (i = 0; i < count; i++) { 851 0 stevel if (nfsnum == flavor_list[i]) 852 0 stevel return (TRUE); 853 0 stevel } 854 0 stevel return (FALSE); 855 0 stevel } 856 0 stevel 857 0 stevel /* 858 0 stevel * Used by rfs4_op_secinfo to get the security information from the 859 0 stevel * export structure associated with the component. 860 0 stevel */ 861 0 stevel /* ARGSUSED */ 862 0 stevel static nfsstat4 863 0 stevel do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp) 864 0 stevel { 865 0 stevel int error, different_export = 0; 866 0 stevel vnode_t *dvp, *vp, *tvp; 867 0 stevel struct exportinfo *exi = NULL; 868 0 stevel fid_t fid; 869 0 stevel uint_t count, i; 870 0 stevel secinfo4 *resok_val; 871 0 stevel struct secinfo *secp; 872 5050 jwahlig seconfig_t *si; 873 0 stevel bool_t did_traverse; 874 0 stevel int dotdot, walk; 875 0 stevel 876 0 stevel dvp = cs->vp; 877 0 stevel dotdot = (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0'); 878 0 stevel 879 0 stevel /* 880 0 stevel * If dotdotting, then need to check whether it's above the 881 0 stevel * root of a filesystem, or above an export point. 882 0 stevel */ 883 0 stevel if (dotdot) { 884 0 stevel 885 0 stevel /* 886 0 stevel * If dotdotting at the root of a filesystem, then 887 0 stevel * need to traverse back to the mounted-on filesystem 888 0 stevel * and do the dotdot lookup there. 889 0 stevel */ 890 0 stevel if (cs->vp->v_flag & VROOT) { 891 0 stevel 892 0 stevel /* 893 0 stevel * If at the system root, then can 894 0 stevel * go up no further. 895 0 stevel */ 896 0 stevel if (VN_CMP(dvp, rootdir)) 897 0 stevel return (puterrno4(ENOENT)); 898 0 stevel 899 0 stevel /* 900 0 stevel * Traverse back to the mounted-on filesystem 901 0 stevel */ 902 0 stevel dvp = untraverse(cs->vp); 903 0 stevel 904 0 stevel /* 905 0 stevel * Set the different_export flag so we remember 906 0 stevel * to pick up a new exportinfo entry for 907 0 stevel * this new filesystem. 908 0 stevel */ 909 0 stevel different_export = 1; 910 0 stevel } else { 911 0 stevel 912 0 stevel /* 913 0 stevel * If dotdotting above an export point then set 914 0 stevel * the different_export to get new export info. 915 0 stevel */ 916 0 stevel different_export = nfs_exported(cs->exi, cs->vp); 917 0 stevel } 918 0 stevel } 919 0 stevel 920 0 stevel /* 921 0 stevel * Get the vnode for the component "nm". 922 0 stevel */ 923 5331 amw error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cs->cr, 924 5331 amw NULL, NULL, NULL); 925 0 stevel if (error) 926 0 stevel return (puterrno4(error)); 927 0 stevel 928 0 stevel /* 929 0 stevel * If the vnode is in a pseudo filesystem, or if the security flavor 930 0 stevel * used in the request is valid but not an explicitly shared flavor, 931 0 stevel * or the access bit indicates that this is a limited access, 932 0 stevel * check whether this vnode is visible. 933 0 stevel */ 934 0 stevel if (!different_export && 935 0 stevel (PSEUDO(cs->exi) || ! is_exported_sec(cs->nfsflavor, cs->exi) || 936 0 stevel cs->access & CS_ACCESS_LIMITED)) { 937 0 stevel if (! nfs_visible(cs->exi, vp, &different_export)) { 938 0 stevel VN_RELE(vp); 939 0 stevel return (puterrno4(ENOENT)); 940 0 stevel } 941 0 stevel } 942 0 stevel 943 0 stevel /* 944 0 stevel * If it's a mountpoint, then traverse it. 945 0 stevel */ 946 0 stevel if (vn_ismntpt(vp)) { 947 0 stevel tvp = vp; 948 0 stevel if ((error = traverse(&tvp)) != 0) { 949 0 stevel VN_RELE(vp); 950 0 stevel return (puterrno4(error)); 951 0 stevel } 952 0 stevel /* remember that we had to traverse mountpoint */ 953 0 stevel did_traverse = TRUE; 954 0 stevel vp = tvp; 955 0 stevel different_export = 1; 956 0 stevel } else if (vp->v_vfsp != dvp->v_vfsp) { 957 0 stevel /* 958 0 stevel * If vp isn't a mountpoint and the vfs ptrs aren't the same, 959 0 stevel * then vp is probably an LOFS object. We don't need the 960 0 stevel * realvp, we just need to know that we might have crossed 961 0 stevel * a server fs boundary and need to call checkexport4. 962 0 stevel * (LOFS lookup hides server fs mountpoints, and actually calls 963 0 stevel * traverse) 964 0 stevel */ 965 0 stevel different_export = 1; 966 0 stevel did_traverse = FALSE; 967 0 stevel } 968 0 stevel 969 0 stevel /* 970 0 stevel * Get the export information for it. 971 0 stevel */ 972 0 stevel if (different_export) { 973 0 stevel 974 0 stevel bzero(&fid, sizeof (fid)); 975 0 stevel fid.fid_len = MAXFIDSZ; 976 0 stevel error = vop_fid_pseudo(vp, &fid); 977 0 stevel if (error) { 978 0 stevel VN_RELE(vp); 979 0 stevel return (puterrno4(error)); 980 0 stevel } 981 0 stevel 982 0 stevel if (dotdot) 983 0 stevel exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE); 984 0 stevel else 985 0 stevel exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp); 986 0 stevel 987 0 stevel if (exi == NULL) { 988 0 stevel if (did_traverse == TRUE) { 989 0 stevel /* 990 0 stevel * If this vnode is a mounted-on vnode, 991 0 stevel * but the mounted-on file system is not 992 0 stevel * exported, send back the secinfo for 993 0 stevel * the exported node that the mounted-on 994 0 stevel * vnode lives in. 995 0 stevel */ 996 0 stevel exi = cs->exi; 997 0 stevel } else { 998 0 stevel VN_RELE(vp); 999 0 stevel return (puterrno4(EACCES)); 1000 0 stevel } 1001 0 stevel } 1002 0 stevel } else { 1003 0 stevel exi = cs->exi; 1004 0 stevel } 1005 0 stevel ASSERT(exi != NULL); 1006 0 stevel 1007 0 stevel 1008 0 stevel /* 1009 0 stevel * Create the secinfo result based on the security information 1010 0 stevel * from the exportinfo structure (exi). 1011 0 stevel * 1012 0 stevel * Return all flavors for a pseudo node. 1013 0 stevel * For a real export node, return the flavor that the client 1014 0 stevel * has access with. 1015 0 stevel */ 1016 0 stevel ASSERT(RW_LOCK_HELD(&exported_lock)); 1017 0 stevel if (PSEUDO(exi)) { 1018 0 stevel count = exi->exi_export.ex_seccnt; /* total sec count */ 1019 0 stevel resok_val = kmem_alloc(count * sizeof (secinfo4), KM_SLEEP); 1020 0 stevel secp = exi->exi_export.ex_secinfo; 1021 0 stevel 1022 0 stevel for (i = 0; i < count; i++) { 1023 5050 jwahlig si = &secp[i].s_secinfo; 1024 5050 jwahlig resok_val[i].flavor = si->sc_rpcnum; 1025 5050 jwahlig if (resok_val[i].flavor == RPCSEC_GSS) { 1026 5050 jwahlig rpcsec_gss_info *info; 1027 5050 jwahlig 1028 5050 jwahlig info = &resok_val[i].flavor_info; 1029 5050 jwahlig info->qop = si->sc_qop; 1030 5050 jwahlig info->service = (rpc_gss_svc_t)si->sc_service; 1031 5050 jwahlig 1032 5050 jwahlig /* get oid opaque data */ 1033 5050 jwahlig info->oid.sec_oid4_len = 1034 5050 jwahlig si->sc_gss_mech_type->length; 1035 5050 jwahlig info->oid.sec_oid4_val = kmem_alloc( 1036 5050 jwahlig si->sc_gss_mech_type->length, KM_SLEEP); 1037 5050 jwahlig bcopy( 1038 5050 jwahlig si->sc_gss_mech_type->elements, 1039 5050 jwahlig info->oid.sec_oid4_val, 1040 5050 jwahlig info->oid.sec_oid4_len); 1041 5050 jwahlig } 1042 0 stevel } 1043 0 stevel resp->SECINFO4resok_len = count; 1044 0 stevel resp->SECINFO4resok_val = resok_val; 1045 0 stevel } else { 1046 0 stevel int ret_cnt = 0, k = 0; 1047 0 stevel int *flavor_list; 1048 0 stevel 1049 0 stevel count = exi->exi_export.ex_seccnt; /* total sec count */ 1050 0 stevel secp = exi->exi_export.ex_secinfo; 1051 0 stevel 1052 0 stevel flavor_list = kmem_alloc(count * sizeof (int), KM_SLEEP); 1053 0 stevel /* find out which flavors to return */ 1054 0 stevel for (i = 0; i < count; i ++) { 1055 0 stevel int access, flavor, perm; 1056 0 stevel 1057 0 stevel flavor = secp[i].s_secinfo.sc_nfsnum; 1058 0 stevel perm = secp[i].s_flags; 1059 0 stevel 1060 0 stevel access = nfsauth4_secinfo_access(exi, cs->req, 1061 5050 jwahlig flavor, perm); 1062 0 stevel 1063 0 stevel if (! (access & NFSAUTH_DENIED) && 1064 0 stevel ! (access & NFSAUTH_WRONGSEC)) { 1065 0 stevel flavor_list[ret_cnt] = flavor; 1066 0 stevel ret_cnt++; 1067 0 stevel } 1068 0 stevel } 1069 0 stevel 1070 0 stevel /* Create the returning SECINFO value */ 1071 0 stevel resok_val = kmem_alloc(ret_cnt * sizeof (secinfo4), KM_SLEEP); 1072 0 stevel 1073 0 stevel for (i = 0; i < count; i++) { 1074 5647 samf /* 1075 5647 samf * If the flavor is in the flavor list, 1076 5647 samf * fill in resok_val. 1077 5647 samf */ 1078 5050 jwahlig si = &secp[i].s_secinfo; 1079 5050 jwahlig if (in_flavor_list(si->sc_nfsnum, 1080 5050 jwahlig flavor_list, ret_cnt)) { 1081 5050 jwahlig resok_val[k].flavor = si->sc_rpcnum; 1082 5050 jwahlig if (resok_val[k].flavor == RPCSEC_GSS) { 1083 5050 jwahlig rpcsec_gss_info *info; 1084 5050 jwahlig 1085 5050 jwahlig info = &resok_val[k].flavor_info; 1086 5050 jwahlig info->qop = si->sc_qop; 1087 5050 jwahlig info->service = (rpc_gss_svc_t) 1088 5050 jwahlig si->sc_service; 1089 5050 jwahlig 1090 5050 jwahlig /* get oid opaque data */ 1091 5050 jwahlig info->oid.sec_oid4_len = 1092 5050 jwahlig si->sc_gss_mech_type->length; 1093 5050 jwahlig info->oid.sec_oid4_val = kmem_alloc( 1094 5050 jwahlig si->sc_gss_mech_type->length, 1095 5050 jwahlig KM_SLEEP); 1096 5050 jwahlig bcopy(si->sc_gss_mech_type->elements, 1097 5050 jwahlig info->oid.sec_oid4_val, 1098 5050 jwahlig info->oid.sec_oid4_len); 1099 5050 jwahlig } 1100 5050 jwahlig k++; 1101 5050 jwahlig } 1102 5647 samf if (k >= ret_cnt) 1103 5647 samf break; 1104 0 stevel } 1105 0 stevel resp->SECINFO4resok_len = ret_cnt; 1106 0 stevel resp->SECINFO4resok_val = resok_val; 1107 0 stevel kmem_free(flavor_list, count * sizeof (int)); 1108 0 stevel } 1109 0 stevel 1110 0 stevel VN_RELE(vp); 1111 0 stevel return (NFS4_OK); 1112 0 stevel } 1113 0 stevel 1114 0 stevel /* 1115 0 stevel * SECINFO (Operation 33): Obtain required security information on 1116 0 stevel * the component name in the format of (security-mechanism-oid, qop, service) 1117 0 stevel * triplets. 1118 0 stevel */ 1119 0 stevel /* ARGSUSED */ 1120 0 stevel static void 1121 0 stevel rfs4_op_secinfo(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 1122 9885 Robert struct compound_state *cs) 1123 0 stevel { 1124 5647 samf SECINFO4args *args = &argop->nfs_argop4_u.opsecinfo; 1125 0 stevel SECINFO4res *resp = &resop->nfs_resop4_u.opsecinfo; 1126 5647 samf utf8string *utfnm = &args->name; 1127 0 stevel uint_t len; 1128 0 stevel char *nm; 1129 7961 Natalie struct sockaddr *ca; 1130 7961 Natalie char *name = NULL; 1131 0 stevel 1132 5647 samf DTRACE_NFSV4_2(op__secinfo__start, struct compound_state *, cs, 1133 5647 samf SECINFO4args *, args); 1134 5647 samf 1135 0 stevel /* 1136 0 stevel * Current file handle (cfh) should have been set before getting 1137 0 stevel * into this function. If not, return error. 1138 0 stevel */ 1139 0 stevel if (cs->vp == NULL) { 1140 0 stevel *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 1141 5647 samf goto out; 1142 0 stevel } 1143 0 stevel 1144 0 stevel if (cs->vp->v_type != VDIR) { 1145 0 stevel *cs->statusp = resp->status = NFS4ERR_NOTDIR; 1146 5647 samf goto out; 1147 0 stevel } 1148 0 stevel 1149 0 stevel /* 1150 0 stevel * Verify the component name. If failed, error out, but 1151 0 stevel * do not error out if the component name is a "..". 1152 0 stevel * SECINFO will return its parents secinfo data for SECINFO "..". 1153 0 stevel */ 1154 0 stevel if (!utf8_dir_verify(utfnm)) { 1155 0 stevel if (utfnm->utf8string_len != 2 || 1156 5050 jwahlig utfnm->utf8string_val[0] != '.' || 1157 5050 jwahlig utfnm->utf8string_val[1] != '.') { 1158 0 stevel *cs->statusp = resp->status = NFS4ERR_INVAL; 1159 5647 samf goto out; 1160 0 stevel } 1161 0 stevel } 1162 0 stevel 1163 0 stevel nm = utf8_to_str(utfnm, &len, NULL); 1164 0 stevel if (nm == NULL) { 1165 0 stevel *cs->statusp = resp->status = NFS4ERR_INVAL; 1166 5647 samf goto out; 1167 0 stevel } 1168 0 stevel 1169 0 stevel if (len > MAXNAMELEN) { 1170 0 stevel *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG; 1171 0 stevel kmem_free(nm, len); 1172 5647 samf goto out; 1173 0 stevel } 1174 7961 Natalie /* If necessary, convert to UTF-8 for illbehaved clients */ 1175 7961 Natalie 1176 7961 Natalie ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 1177 7961 Natalie name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND, 1178 7961 Natalie MAXPATHLEN + 1); 1179 7961 Natalie 1180 7961 Natalie if (name == NULL) { 1181 7961 Natalie *cs->statusp = resp->status = NFS4ERR_INVAL; 1182 7961 Natalie kmem_free(nm, len); 1183 7961 Natalie goto out; 1184 7961 Natalie } 1185 7961 Natalie 1186 7961 Natalie 1187 7961 Natalie *cs->statusp = resp->status = do_rfs4_op_secinfo(cs, name, resp); 1188 7961 Natalie 1189 7961 Natalie if (name != nm) 1190 7961 Natalie kmem_free(name, MAXPATHLEN + 1); 1191 0 stevel kmem_free(nm, len); 1192 5647 samf 1193 5647 samf out: 1194 5647 samf DTRACE_NFSV4_2(op__secinfo__done, struct compound_state *, cs, 1195 5647 samf SECINFO4res *, resp); 1196 0 stevel } 1197 0 stevel 1198 0 stevel /* 1199 0 stevel * Free SECINFO result. 1200 0 stevel */ 1201 0 stevel /* ARGSUSED */ 1202 0 stevel static void 1203 0 stevel rfs4_op_secinfo_free(nfs_resop4 *resop) 1204 0 stevel { 1205 0 stevel SECINFO4res *resp = &resop->nfs_resop4_u.opsecinfo; 1206 0 stevel int count, i; 1207 0 stevel secinfo4 *resok_val; 1208 0 stevel 1209 0 stevel /* If this is not an Ok result, nothing to free. */ 1210 0 stevel if (resp->status != NFS4_OK) { 1211 0 stevel return; 1212 0 stevel } 1213 0 stevel 1214 0 stevel count = resp->SECINFO4resok_len; 1215 0 stevel resok_val = resp->SECINFO4resok_val; 1216 0 stevel 1217 0 stevel for (i = 0; i < count; i++) { 1218 5050 jwahlig if (resok_val[i].flavor == RPCSEC_GSS) { 1219 5050 jwahlig rpcsec_gss_info *info; 1220 5050 jwahlig 1221 5050 jwahlig info = &resok_val[i].flavor_info; 1222 5050 jwahlig kmem_free(info->oid.sec_oid4_val, 1223 5050 jwahlig info->oid.sec_oid4_len); 1224 5050 jwahlig } 1225 0 stevel } 1226 0 stevel kmem_free(resok_val, count * sizeof (secinfo4)); 1227 0 stevel resp->SECINFO4resok_len = 0; 1228 0 stevel resp->SECINFO4resok_val = NULL; 1229 0 stevel } 1230 0 stevel 1231 0 stevel /* ARGSUSED */ 1232 0 stevel static void 1233 0 stevel rfs4_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 1234 9885 Robert struct compound_state *cs) 1235 0 stevel { 1236 0 stevel ACCESS4args *args = &argop->nfs_argop4_u.opaccess; 1237 0 stevel ACCESS4res *resp = &resop->nfs_resop4_u.opaccess; 1238 0 stevel int error; 1239 0 stevel vnode_t *vp; 1240 0 stevel struct vattr va; 1241 0 stevel int checkwriteperm; 1242 0 stevel cred_t *cr = cs->cr; 1243 1676 jpk bslabel_t *clabel, *slabel; 1244 1676 jpk ts_label_t *tslabel; 1245 1676 jpk boolean_t admin_low_client; 1246 0 stevel 1247 5647 samf DTRACE_NFSV4_2(op__access__start, struct compound_state *, cs, 1248 5647 samf ACCESS4args *, args); 1249 5647 samf 1250 0 stevel #if 0 /* XXX allow access even if !cs->access. Eventually only pseudo fs */ 1251 0 stevel if (cs->access == CS_ACCESS_DENIED) { 1252 0 stevel *cs->statusp = resp->status = NFS4ERR_ACCESS; 1253 5647 samf goto out; 1254 0 stevel } 1255 0 stevel #endif 1256 0 stevel if (cs->vp == NULL) { 1257 0 stevel *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 1258 5647 samf goto out; 1259 0 stevel } 1260 0 stevel 1261 0 stevel ASSERT(cr != NULL); 1262 0 stevel 1263 0 stevel vp = cs->vp; 1264 0 stevel 1265 0 stevel /* 1266 0 stevel * If the file system is exported read only, it is not appropriate 1267 0 stevel * to check write permissions for regular files and directories. 1268 0 stevel * Special files are interpreted by the client, so the underlying 1269 0 stevel * permissions are sent back to the client for interpretation. 1270 0 stevel */ 1271 0 stevel if (rdonly4(cs->exi, cs->vp, req) && 1272 5050 jwahlig (vp->v_type == VREG || vp->v_type == VDIR)) 1273 0 stevel checkwriteperm = 0; 1274 0 stevel else 1275 0 stevel checkwriteperm = 1; 1276 0 stevel 1277 0 stevel /* 1278 0 stevel * XXX 1279 0 stevel * We need the mode so that we can correctly determine access 1280 0 stevel * permissions relative to a mandatory lock file. Access to 1281 0 stevel * mandatory lock files is denied on the server, so it might 1282 0 stevel * as well be reflected to the server during the open. 1283 0 stevel */ 1284 0 stevel va.va_mask = AT_MODE; 1285 5331 amw error = VOP_GETATTR(vp, &va, 0, cr, NULL); 1286 0 stevel if (error) { 1287 0 stevel *cs->statusp = resp->status = puterrno4(error); 1288 5647 samf goto out; 1289 0 stevel } 1290 0 stevel resp->access = 0; 1291 0 stevel resp->supported = 0; 1292 0 stevel 1293 1676 jpk if (is_system_labeled()) { 1294 1676 jpk ASSERT(req->rq_label != NULL); 1295 1676 jpk clabel = req->rq_label; 1296 1676 jpk DTRACE_PROBE2(tx__rfs4__log__info__opaccess__clabel, char *, 1297 1676 jpk "got client label from request(1)", 1298 1676 jpk struct svc_req *, req); 1299 1676 jpk if (!blequal(&l_admin_low->tsl_label, clabel)) { 1300 9871 Jarrett if ((tslabel = nfs_getflabel(vp, cs->exi)) == NULL) { 1301 1676 jpk *cs->statusp = resp->status = puterrno4(EACCES); 1302 5647 samf goto out; 1303 1676 jpk } 1304 1676 jpk slabel = label2bslabel(tslabel); 1305 1676 jpk DTRACE_PROBE3(tx__rfs4__log__info__opaccess__slabel, 1306 1676 jpk char *, "got server label(1) for vp(2)", 1307 1676 jpk bslabel_t *, slabel, vnode_t *, vp); 1308 1676 jpk 1309 1676 jpk admin_low_client = B_FALSE; 1310 1676 jpk } else 1311 1676 jpk admin_low_client = B_TRUE; 1312 1676 jpk } 1313 1676 jpk 1314 0 stevel if (args->access & ACCESS4_READ) { 1315 5331 amw error = VOP_ACCESS(vp, VREAD, 0, cr, NULL); 1316 1676 jpk if (!error && !MANDLOCK(vp, va.va_mode) && 1317 1676 jpk (!is_system_labeled() || admin_low_client || 1318 1676 jpk bldominates(clabel, slabel))) 1319 0 stevel resp->access |= ACCESS4_READ; 1320 0 stevel resp->supported |= ACCESS4_READ; 1321 0 stevel } 1322 0 stevel if ((args->access & ACCESS4_LOOKUP) && vp->v_type == VDIR) { 1323 5331 amw error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL); 1324 1676 jpk if (!error && (!is_system_labeled() || admin_low_client || 1325 1676 jpk bldominates(clabel, slabel))) 1326 0 stevel resp->access |= ACCESS4_LOOKUP; 1327 0 stevel resp->supported |= ACCESS4_LOOKUP; 1328 0 stevel } 1329 0 stevel if (checkwriteperm && 1330 0 stevel (args->access & (ACCESS4_MODIFY|ACCESS4_EXTEND))) { 1331 5331 amw error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL); 1332 1676 jpk if (!error && !MANDLOCK(vp, va.va_mode) && 1333 1676 jpk (!is_system_labeled() || admin_low_client || 1334 1676 jpk blequal(clabel, slabel))) 1335 0 stevel resp->access |= 1336 7387 Robert (args->access & (ACCESS4_MODIFY | ACCESS4_EXTEND)); 1337 7387 Robert resp->supported |= (ACCESS4_MODIFY | ACCESS4_EXTEND); 1338 0 stevel } 1339 0 stevel 1340 0 stevel if (checkwriteperm && 1341 0 stevel (args->access & ACCESS4_DELETE) && vp->v_type == VDIR) { 1342 5331 amw error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL); 1343 1676 jpk if (!error && (!is_system_labeled() || admin_low_client || 1344 1676 jpk blequal(clabel, slabel))) 1345 0 stevel resp->access |= ACCESS4_DELETE; 1346 0 stevel resp->supported |= ACCESS4_DELETE; 1347 0 stevel } 1348 0 stevel if (args->access & ACCESS4_EXECUTE && vp->v_type != VDIR) { 1349 5331 amw error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL); 1350 1676 jpk if (!error && !MANDLOCK(vp, va.va_mode) && 1351 1676 jpk (!is_system_labeled() || admin_low_client || 1352 1676 jpk bldominates(clabel, slabel))) 1353 0 stevel resp->access |= ACCESS4_EXECUTE; 1354 0 stevel resp->supported |= ACCESS4_EXECUTE; 1355 0 stevel } 1356 1676 jpk 1357 1676 jpk if (is_system_labeled() && !admin_low_client) 1358 1676 jpk label_rele(tslabel); 1359 0 stevel 1360 0 stevel *cs->statusp = resp->status = NFS4_OK; 1361 5647 samf out: 1362 5647 samf DTRACE_NFSV4_2(op__access__done, struct compound_state *, cs, 1363 5647 samf ACCESS4res *, resp); 1364 0 stevel } 1365 0 stevel 1366 0 stevel /* ARGSUSED */ 1367 0 stevel static void 1368 0 stevel rfs4_op_commit(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 1369 9885 Robert struct compound_state *cs) 1370 0 stevel { 1371 0 stevel COMMIT4args *args = &argop->nfs_argop4_u.opcommit; 1372 0 stevel COMMIT4res *resp = &resop->nfs_resop4_u.opcommit; 1373 0 stevel int error; 1374 0 stevel vnode_t *vp = cs->vp; 1375 0 stevel cred_t *cr = cs->cr; 1376 0 stevel vattr_t va; 1377 0 stevel 1378 5647 samf DTRACE_NFSV4_2(op__commit__start, struct compound_state *, cs, 1379 5647 samf COMMIT4args *, args); 1380 5647 samf 1381 0 stevel if (vp == NULL) { 1382 0 stevel *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 1383 5647 samf goto out; 1384 5647 samf } 1385 5647 samf if (cs->access == CS_ACCESS_DENIED) { 1386 5647 samf *cs->statusp = resp->status = NFS4ERR_ACCESS; 1387 5647 samf goto out; 1388 0 stevel } 1389 0 stevel 1390 0 stevel if (args->offset + args->count < args->offset) { 1391 0 stevel *cs->statusp = resp->status = NFS4ERR_INVAL; 1392 5647 samf goto out; 1393 0 stevel } 1394 0 stevel 1395 0 stevel va.va_mask = AT_UID; 1396 5331 amw error = VOP_GETATTR(vp, &va, 0, cr, NULL); 1397 0 stevel 1398 0 stevel /* 1399 0 stevel * If we can't get the attributes, then we can't do the 1400 0 stevel * right access checking. So, we'll fail the request. 1401 0 stevel */ 1402 0 stevel if (error) { 1403 0 stevel *cs->statusp = resp->status = puterrno4(error); 1404 5647 samf goto out; 1405 0 stevel } 1406 0 stevel if (rdonly4(cs->exi, cs->vp, req)) { 1407 0 stevel *cs->statusp = resp->status = NFS4ERR_ROFS; 1408 5647 samf goto out; 1409 0 stevel } 1410 0 stevel 1411 0 stevel if (vp->v_type != VREG) { 1412 0 stevel if (vp->v_type == VDIR) 1413 0 stevel resp->status = NFS4ERR_ISDIR; 1414 0 stevel else 1415 0 stevel resp->status = NFS4ERR_INVAL; 1416 0 stevel *cs->statusp = resp->status; 1417 5647 samf goto out; 1418 0 stevel } 1419 0 stevel 1420 0 stevel if (crgetuid(cr) != va.va_uid && 1421 5331 amw (error = VOP_ACCESS(vp, VWRITE, 0, cs->cr, NULL))) { 1422 5331 amw *cs->statusp = resp->status = puterrno4(error); 1423 5647 samf goto out; 1424 5331 amw } 1425 5331 amw 1426 5331 amw error = VOP_PUTPAGE(vp, args->offset, args->count, 0, cr, NULL); 1427 0 stevel if (!error) 1428 5331 amw error = VOP_FSYNC(vp, FNODSYNC, cr, NULL); 1429 0 stevel 1430 0 stevel if (error) { 1431 0 stevel *cs->statusp = resp->status = puterrno4(error); 1432 5647 samf goto out; 1433 0 stevel } 1434 0 stevel 1435 0 stevel *cs->statusp = resp->status = NFS4_OK; 1436 0 stevel resp->writeverf = Write4verf; 1437 5647 samf out: 1438 5647 samf DTRACE_NFSV4_2(op__commit__done, struct compound_state *, cs, 1439 5647 samf COMMIT4res *, resp); 1440 0 stevel } 1441 0 stevel 1442 0 stevel /* 1443 0 stevel * rfs4_op_mknod is called from rfs4_op_create after all initial verification 1444 0 stevel * was completed. It does the nfsv4 create for special files. 1445 0 stevel */ 1446 0 stevel /* ARGSUSED */ 1447 0 stevel static vnode_t * 1448 0 stevel do_rfs4_op_mknod(CREATE4args *args, CREATE4res *resp, struct svc_req *req, 1449 9885 Robert struct compound_state *cs, vattr_t *vap, char *nm) 1450 0 stevel { 1451 0 stevel int error; 1452 0 stevel cred_t *cr = cs->cr; 1453 0 stevel vnode_t *dvp = cs->vp; 1454 0 stevel vnode_t *vp = NULL; 1455 0 stevel int mode; 1456 0 stevel enum vcexcl excl; 1457 0 stevel 1458 0 stevel switch (args->type) { 1459 0 stevel case NF4CHR: 1460 0 stevel case NF4BLK: 1461 0 stevel if (secpolicy_sys_devices(cr) != 0) { 1462 0 stevel *cs->statusp = resp->status = NFS4ERR_PERM; 1463 0 stevel return (NULL); 1464 0 stevel } 1465 0 stevel if (args->type == NF4CHR) 1466 0 stevel vap->va_type = VCHR; 1467 0 stevel else 1468 0 stevel vap->va_type = VBLK; 1469 0 stevel vap->va_rdev = makedevice(args->ftype4_u.devdata.specdata1, 1470 5050 jwahlig args->ftype4_u.devdata.specdata2); 1471 0 stevel vap->va_mask |= AT_RDEV; 1472 0 stevel break; 1473 0 stevel case NF4SOCK: 1474 0 stevel vap->va_type = VSOCK; 1475 0 stevel break; 1476 0 stevel case NF4FIFO: 1477 0 stevel vap->va_type = VFIFO; 1478 0 stevel break; 1479 0 stevel default: 1480 0 stevel *cs->statusp = resp->status = NFS4ERR_BADTYPE; 1481 0 stevel return (NULL); 1482 0 stevel } 1483 0 stevel 1484 0 stevel /* 1485 0 stevel * Must specify the mode. 1486 0 stevel */ 1487 0 stevel if (!(vap->va_mask & AT_MODE)) { 1488 0 stevel *cs->statusp = resp->status = NFS4ERR_INVAL; 1489 0 stevel return (NULL); 1490 0 stevel } 1491 0 stevel 1492 0 stevel excl = EXCL; 1493 0 stevel 1494 0 stevel mode = 0; 1495 0 stevel 1496 5331 amw error = VOP_CREATE(dvp, nm, vap, excl, mode, &vp, cr, 0, NULL, NULL); 1497 0 stevel if (error) { 1498 0 stevel *cs->statusp = resp->status = puterrno4(error); 1499 0 stevel return (NULL); 1500 0 stevel } 1501 0 stevel return (vp); 1502 0 stevel } 1503 0 stevel 1504 0 stevel /* 1505 0 stevel * nfsv4 create is used to create non-regular files. For regular files, 1506 0 stevel * use nfsv4 open. 1507 0 stevel */ 1508 0 stevel /* ARGSUSED */ 1509 0 stevel static void 1510 0 stevel rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 1511 9885 Robert struct compound_state *cs) 1512 0 stevel { 1513 0 stevel CREATE4args *args = &argop->nfs_argop4_u.opcreate; 1514 0 stevel CREATE4res *resp = &resop->nfs_resop4_u.opcreate; 1515 0 stevel int error; 1516 0 stevel struct vattr bva, iva, iva2, ava, *vap; 1517 0 stevel cred_t *cr = cs->cr; 1518 0 stevel vnode_t *dvp = cs->vp; 1519 0 stevel vnode_t *vp = NULL; 1520 6402 gt29601 vnode_t *realvp; 1521 0 stevel char *nm, *lnm; 1522 0 stevel uint_t len, llen; 1523 0 stevel int syncval = 0; 1524 0 stevel struct nfs4_svgetit_arg sarg; 1525 0 stevel struct nfs4_ntov_table ntov; 1526 0 stevel struct statvfs64 sb; 1527 0 stevel nfsstat4 status; 1528 7961 Natalie struct sockaddr *ca; 1529 7961 Natalie char *name = NULL; 1530 7961 Natalie char *lname = NULL; 1531 0 stevel 1532 5647 samf DTRACE_NFSV4_2(op__create__start, struct compound_state *, cs, 1533 5647 samf CREATE4args *, args); 1534 5647 samf 1535 0 stevel resp->attrset = 0; 1536 0 stevel 1537 0 stevel if (dvp == NULL) { 1538 0 stevel *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 1539 5647 samf goto out; 1540 0 stevel } 1541 0 stevel 1542 0 stevel /* 1543 0 stevel * If there is an unshared filesystem mounted on this vnode, 1544 0 stevel * do not allow to create an object in this directory. 1545 0 stevel */ 1546 0 stevel if (vn_ismntpt(dvp)) { 1547 0 stevel *cs->statusp = resp->status = NFS4ERR_ACCESS; 1548 5647 samf goto out; 1549 0 stevel } 1550 0 stevel 1551 0 stevel /* Verify that type is correct */ 1552 0 stevel switch (args->type) { 1553 0 stevel case NF4LNK: 1554 0 stevel case NF4BLK: 1555 0 stevel case NF4CHR: 1556 0 stevel case NF4SOCK: 1557 0 stevel case NF4FIFO: 1558 0 stevel case NF4DIR: 1559 0 stevel break; 1560 0 stevel default: 1561 0 stevel *cs->statusp = resp->status = NFS4ERR_BADTYPE; 1562 5647 samf goto out; 1563 0 stevel }; 1564 0 stevel 1565 0 stevel if (cs->access == CS_ACCESS_DENIED) { 1566 0 stevel *cs->statusp = resp->status = NFS4ERR_ACCESS; 1567 5647 samf goto out; 1568 0 stevel } 1569 0 stevel if (dvp->v_type != VDIR) { 1570 0 stevel *cs->statusp = resp->status = NFS4ERR_NOTDIR; 1571 5647 samf goto out; 1572 0 stevel } 1573 0 stevel if (!utf8_dir_verify(&args->objname)) { 1574 0 stevel *cs->statusp = resp->status = NFS4ERR_INVAL; 1575 5647 samf goto out; 1576 0 stevel } 1577 0 stevel 1578 0 stevel if (rdonly4(cs->exi, cs->vp, req)) { 1579 0 stevel *cs->statusp = resp->status = NFS4ERR_ROFS; 1580 5647 samf goto out; 1581 0 stevel } 1582 0 stevel 1583 0 stevel /* 1584 0 stevel * Name of newly created object 1585 0 stevel */ 1586 0 stevel nm = utf8_to_fn(&args->objname, &len, NULL); 1587 0 stevel if (nm == NULL) { 1588 0 stevel *cs->statusp = resp->status = NFS4ERR_INVAL; 1589 5647 samf goto out; 1590 0 stevel } 1591 0 stevel 1592 0 stevel if (len > MAXNAMELEN) { 1593 0 stevel *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG; 1594 0 stevel kmem_free(nm, len); 1595 5647 samf goto out; 1596 0 stevel } 1597 0 stevel 1598 7961 Natalie /* If necessary, convert to UTF-8 for poorly behaved clients */ 1599 7961 Natalie ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 1600 7961 Natalie name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND, 1601 7961 Natalie MAXPATHLEN + 1); 1602 7961 Natalie 1603 7961 Natalie if (name == NULL) { 1604 7961 Natalie *cs->statusp = resp->status = NFS4ERR_INVAL; 1605 7961 Natalie kmem_free(nm, len); 1606 7961 Natalie goto out; 1607 7961 Natalie } 1608 7961 Natalie 1609 0 stevel resp->attrset = 0; 1610 0 stevel 1611 0 stevel sarg.sbp = &sb; 1612 0 stevel nfs4_ntov_table_init(&ntov); 1613 0 stevel 1614 0 stevel status = do_rfs4_set_attrs(&resp->attrset, 1615 5050 jwahlig &args->createattrs, cs, &sarg, &ntov, NFS4ATTR_SETIT); 1616 0 stevel 1617 0 stevel if (sarg.vap->va_mask == 0 && status == NFS4_OK) 1618 0 stevel status = NFS4ERR_INVAL; 1619 0 stevel 1620 0 stevel if (status != NFS4_OK) { 1621 0 stevel *cs->statusp = resp->status = status; 1622 0 stevel kmem_free(nm, len); 1623 0 stevel nfs4_ntov_table_free(&ntov, &sarg); 1624 0 stevel resp->attrset = 0; 1625 5647 samf goto out; 1626 0 stevel } 1627 0 stevel 1628 0 stevel /* Get "before" change value */ 1629 0 stevel bva.va_mask = AT_CTIME|AT_SEQ; 1630 5331 amw error = VOP_GETATTR(dvp, &bva, 0, cr, NULL); 1631 0 stevel if (error) { 1632 0 stevel *cs->statusp = resp->status = puterrno4(error); 1633 0 stevel kmem_free(nm, len); 1634 0 stevel nfs4_ntov_table_free(&ntov, &sarg); 1635 0 stevel resp->attrset = 0; 1636 5647 samf goto out; 1637 0 stevel } 1638 0 stevel NFS4_SET_FATTR4_CHANGE(resp->cinfo.before, bva.va_ctime) 1639 0 stevel 1640 0 stevel vap = sarg.vap; 1641 0 stevel 1642 0 stevel /* 1643 0 stevel * Set default initial values for attributes when not specified 1644 0 stevel * in createattrs. 1645 0 stevel */ 1646 0 stevel if ((vap->va_mask & AT_UID) == 0) { 1647 0 stevel vap->va_uid = crgetuid(cr); 1648 0 stevel vap->va_mask |= AT_UID; 1649 0 stevel } 1650 0 stevel if ((vap->va_mask & AT_GID) == 0) { 1651 0 stevel vap->va_gid = crgetgid(cr); 1652 0 stevel vap->va_mask |= AT_GID; 1653 0 stevel } 1654 0 stevel 1655 0 stevel vap->va_mask |= AT_TYPE; 1656 0 stevel switch (args->type) { 1657 0 stevel case NF4DIR: 1658 0 stevel vap->va_type = VDIR; 1659 0 stevel if ((vap->va_mask & AT_MODE) == 0) { 1660 0 stevel vap->va_mode = 0700; /* default: owner rwx only */ 1661 0 stevel vap->va_mask |= AT_MODE; 1662 0 stevel } 1663 5331 amw error = VOP_MKDIR(dvp, nm, vap, &vp, cr, NULL, 0, NULL); 1664 0 stevel if (error) 1665 0 stevel break; 1666 0 stevel 1667 0 stevel /* 1668 0 stevel * Get the initial "after" sequence number, if it fails, 1669 0 stevel * set to zero 1670 0 stevel */ 1671 0 stevel iva.va_mask = AT_SEQ; 1672 5331 amw if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL)) 1673 0 stevel iva.va_seq = 0; 1674 0 stevel break; 1675 0 stevel case NF4LNK: 1676 0 stevel vap->va_type = VLNK; 1677 0 stevel if ((vap->va_mask & AT_MODE) == 0) { 1678 0 stevel vap->va_mode = 0700; /* default: owner rwx only */ 1679 0 stevel vap->va_mask |= AT_MODE; 1680 0 stevel } 1681 0 stevel 1682 0 stevel /* 1683 0 stevel * symlink names must be treated as data 1684 0 stevel */ 1685 0 stevel lnm = utf8_to_str(&args->ftype4_u.linkdata, &llen, NULL); 1686 0 stevel 1687 0 stevel if (lnm == NULL) { 1688 0 stevel *cs->statusp = resp->status = NFS4ERR_INVAL; 1689 7961 Natalie if (name != nm) 1690 7961 Natalie kmem_free(name, MAXPATHLEN + 1); 1691 0 stevel kmem_free(nm, len); 1692 0 stevel nfs4_ntov_table_free(&ntov, &sarg); 1693 0 stevel resp->attrset = 0; 1694 5647 samf goto out; 1695 0 stevel } 1696 0 stevel 1697 0 stevel if (llen > MAXPATHLEN) { 1698 0 stevel *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG; 1699 7961 Natalie if (name != nm) 1700 7961 Natalie kmem_free(name, MAXPATHLEN + 1); 1701 0 stevel kmem_free(nm, len); 1702 0 stevel kmem_free(lnm, llen); 1703 0 stevel nfs4_ntov_table_free(&ntov, &sarg); 1704 0 stevel resp->attrset = 0; 1705 5647 samf goto out; 1706 0 stevel } 1707 0 stevel 1708 7961 Natalie lname = nfscmd_convname(ca, cs->exi, lnm, 1709 7961 Natalie NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 1710 7961 Natalie 1711 7961 Natalie if (lname == NULL) { 1712 7961 Natalie *cs->statusp = resp->status = NFS4ERR_SERVERFAULT; 1713 7961 Natalie if (name != nm) 1714 7961 Natalie kmem_free(name, MAXPATHLEN + 1); 1715 7961 Natalie kmem_free(nm, len); 1716 7961 Natalie kmem_free(lnm, llen); 1717 7961 Natalie nfs4_ntov_table_free(&ntov, &sarg); 1718 7961 Natalie resp->attrset = 0; 1719 7961 Natalie goto out; 1720 7961 Natalie } 1721 7961 Natalie 1722 5331 amw error = VOP_SYMLINK(dvp, nm, vap, lnm, cr, NULL, 0); 1723 7961 Natalie if (lname != lnm) 1724 7961 Natalie kmem_free(lname, MAXPATHLEN + 1); 1725 0 stevel if (lnm != NULL) 1726 0 stevel kmem_free(lnm, llen); 1727 0 stevel if (error) 1728 0 stevel break; 1729 0 stevel 1730 0 stevel /* 1731 0 stevel * Get the initial "after" sequence number, if it fails, 1732 0 stevel * set to zero 1733 0 stevel */ 1734 0 stevel iva.va_mask = AT_SEQ; 1735 5331 amw if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL)) 1736 0 stevel iva.va_seq = 0; 1737 0 stevel 1738 5331 amw error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cr, 1739 5331 amw NULL, NULL, NULL); 1740 0 stevel if (error) 1741 0 stevel break; 1742 0 stevel 1743 0 stevel /* 1744 0 stevel * va_seq is not safe over VOP calls, check it again 1745 0 stevel * if it has changed zero out iva to force atomic = FALSE. 1746 0 stevel */ 1747 0 stevel iva2.va_mask = AT_SEQ; 1748 5331 amw if (VOP_GETATTR(dvp, &iva2, 0, cs->cr, NULL) || 1749 5050 jwahlig iva2.va_seq != iva.va_seq) 1750 0 stevel iva.va_seq = 0; 1751 0 stevel break; 1752 0 stevel default: 1753 0 stevel /* 1754 0 stevel * probably a special file. 1755 0 stevel */ 1756 0 stevel if ((vap->va_mask & AT_MODE) == 0) { 1757 0 stevel vap->va_mode = 0600; /* default: owner rw only */ 1758 0 stevel vap->va_mask |= AT_MODE; 1759 0 stevel } 1760 0 stevel syncval = FNODSYNC; 1761 0 stevel /* 1762 0 stevel * We know this will only generate one VOP call 1763 0 stevel */ 1764 0 stevel vp = do_rfs4_op_mknod(args, resp, req, cs, vap, nm); 1765 0 stevel 1766 0 stevel if (vp == NULL) { 1767 7961 Natalie if (name != nm) 1768 7961 Natalie kmem_free(name, MAXPATHLEN + 1); 1769 0 stevel kmem_free(nm, len); 1770 0 stevel nfs4_ntov_table_free(&ntov, &sarg); 1771 0 stevel resp->attrset = 0; 1772 5647 samf goto out; 1773 0 stevel } 1774 0 stevel 1775 0 stevel /* 1776 0 stevel * Get the initial "after" sequence number, if it fails, 1777 0 stevel * set to zero 1778 0 stevel */ 1779 0 stevel iva.va_mask = AT_SEQ; 1780 5331 amw if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL)) 1781 0 stevel iva.va_seq = 0; 1782 0 stevel 1783 0 stevel break; 1784 0 stevel } 1785 7961 Natalie if (name != nm) 1786 7961 Natalie kmem_free(name, MAXPATHLEN + 1); 1787 0 stevel kmem_free(nm, len); 1788 0 stevel 1789 0 stevel if (error) { 1790 0 stevel *cs->statusp = resp->status = puterrno4(error); 1791 0 stevel } 1792 0 stevel 1793 0 stevel /* 1794 0 stevel * Force modified data and metadata out to stable storage. 1795 0 stevel */ 1796 5331 amw (void) VOP_FSYNC(dvp, 0, cr, NULL); 1797 0 stevel 1798 0 stevel if (resp->status != NFS4_OK) { 1799 0 stevel if (vp != NULL) 1800 0 stevel VN_RELE(vp); 1801 0 stevel nfs4_ntov_table_free(&ntov, &sarg); 1802 0 stevel resp->attrset = 0; 1803 5647 samf goto out; 1804 0 stevel } 1805 0 stevel 1806 0 stevel /* 1807 0 stevel * Finish setup of cinfo response, "before" value already set. 1808 0 stevel * Get "after" change value, if it fails, simply return the 1809 0 stevel * before value. 1810 0 stevel */ 1811 0 stevel ava.va_mask = AT_CTIME|AT_SEQ; 1812 5331 amw if (VOP_GETATTR(dvp, &ava, 0, cr, NULL)) { 1813 0 stevel ava.va_ctime = bva.va_ctime; 1814 0 stevel ava.va_seq = 0; 1815 0 stevel } 1816 0 stevel NFS4_SET_FATTR4_CHANGE(resp->cinfo.after, ava.va_ctime); 1817 0 stevel 1818 0 stevel /* 1819 0 stevel * True verification that object was created with correct 1820 0 stevel * attrs is impossible. The attrs could have been changed 1821 0 stevel * immediately after object creation. If attributes did 1822 0 stevel * not verify, the only recourse for the server is to 1823 0 stevel * destroy the object. Maybe if some attrs (like gid) 1824 0 stevel * are set incorrectly, the object should be destroyed; 1825 0 stevel * however, seems bad as a default policy. Do we really 1826 0 stevel * want to destroy an object over one of the times not 1827 0 stevel * verifying correctly? For these reasons, the server 1828 0 stevel * currently sets bits in attrset for createattrs 1829 0 stevel * that were set; however, no verification is done. 1830 0 stevel * 1831 0 stevel * vmask_to_nmask accounts for vattr bits set on create 1832 0 stevel * [do_rfs4_set_attrs() only sets resp bits for 1833 0 stevel * non-vattr/vfs bits.] 1834 0 stevel * Mask off any bits set by default so as not to return 1835 0 stevel * more attrset bits than were requested in createattrs 1836 0 stevel */ 1837 0 stevel nfs4_vmask_to_nmask(sarg.vap->va_mask, &resp->attrset); 1838 0 stevel resp->attrset &= args->createattrs.attrmask; 1839 0 stevel nfs4_ntov_table_free(&ntov, &sarg); 1840 0 stevel 1841 0 stevel error = makefh4(&cs->fh, vp, cs->exi); 1842 0 stevel if (error) { 1843 0 stevel *cs->statusp = resp->status = puterrno4(error); 1844 0 stevel } 1845 0 stevel 1846 0 stevel /* 1847 0 stevel * The cinfo.atomic = TRUE only if we got no errors, we have 1848 0 stevel * non-zero va_seq's, and it has incremented by exactly one 1849 0 stevel * during the creation and it didn't change during the VOP_LOOKUP 1850 0 stevel * or VOP_FSYNC. 1851 0 stevel */ 1852 0 stevel if (!error && bva.va_seq && iva.va_seq && ava.va_seq && 1853 5050 jwahlig iva.va_seq == (bva.va_seq + 1) && iva.va_seq == ava.va_seq) 1854 0 stevel resp->cinfo.atomic = TRUE; 1855 0 stevel else 1856 0 stevel resp->cinfo.atomic = FALSE; 1857 0 stevel 1858 6402 gt29601 /* 1859 6402 gt29601 * Force modified metadata out to stable storage. 1860 6402 gt29601 * 1861 6402 gt29601 * if a underlying vp exists, pass it to VOP_FSYNC 1862 6402 gt29601 */ 1863 6402 gt29601 if (VOP_REALVP(vp, &realvp, NULL) == 0) 1864 6402 gt29601 (void) VOP_FSYNC(realvp, syncval, cr, NULL); 1865 6402 gt29601 else 1866 6402 gt29601 (void) VOP_FSYNC(vp, syncval, cr, NULL); 1867 0 stevel 1868 0 stevel if (resp->status != NFS4_OK) { 1869 0 stevel VN_RELE(vp); 1870 5647 samf goto out; 1871 0 stevel } 1872 0 stevel if (cs->vp) 1873 0 stevel VN_RELE(cs->vp); 1874 0 stevel 1875 0 stevel cs->vp = vp; 1876 0 stevel *cs->statusp = resp->status = NFS4_OK; 1877 5647 samf out: 1878 5647 samf DTRACE_NFSV4_2(op__create__done, struct compound_state *, cs, 1879 5647 samf CREATE4res *, resp); 1880 5647 samf } 1881 5647 samf 1882 5647 samf /*ARGSUSED*/ 1883 5647 samf static void 1884 5647 samf rfs4_op_delegpurge(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 1885 5647 samf struct compound_state *cs) 1886 5647 samf { 1887 5647 samf DTRACE_NFSV4_2(op__delegpurge__start, struct compound_state *, cs, 1888 5647 samf DELEGPURGE4args *, &argop->nfs_argop4_u.opdelegpurge); 1889 5647 samf 1890 5647 samf rfs4_op_inval(argop, resop, req, cs); 1891 5647 samf 1892 5647 samf DTRACE_NFSV4_2(op__delegpurge__done, struct compound_state *, cs, 1893 5647 samf DELEGPURGE4res *, &resop->nfs_resop4_u.opdelegpurge); 1894 5647 samf } 1895 0 stevel 1896 0 stevel /*ARGSUSED*/ 1897 0 stevel static void 1898 0 stevel rfs4_op_delegreturn(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 1899 9885 Robert struct compound_state *cs) 1900 0 stevel { 1901 0 stevel DELEGRETURN4args *args = &argop->nfs_argop4_u.opdelegreturn; 1902 0 stevel DELEGRETURN4res *resp = &resop->nfs_resop4_u.opdelegreturn; 1903 0 stevel rfs4_deleg_state_t *dsp; 1904 0 stevel nfsstat4 status; 1905 0 stevel 1906 5647 samf DTRACE_NFSV4_2(op__delegreturn__start, struct compound_state *, cs, 1907 5647 samf DELEGRETURN4args *, args); 1908 5647 samf 1909 0 stevel status = rfs4_get_deleg_state(&args->deleg_stateid, &dsp); 1910 0 stevel resp->status = *cs->statusp = status; 1911 0 stevel if (status != NFS4_OK) 1912 5647 samf goto out; 1913 0 stevel 1914 0 stevel /* Ensure specified filehandle matches */ 1915 9885 Robert if (cs->vp != dsp->rds_finfo->rf_vp) { 1916 0 stevel resp->status = *cs->statusp = NFS4ERR_BAD_STATEID; 1917 0 stevel } else 1918 0 stevel rfs4_return_deleg(dsp, FALSE); 1919 0 stevel 1920 9885 Robert rfs4_update_lease(dsp->rds_client); 1921 0 stevel 1922 0 stevel rfs4_deleg_state_rele(dsp); 1923 5647 samf out: 1924 5647 samf DTRACE_NFSV4_2(op__delegreturn__done, struct compound_state *, cs, 1925 5647 samf DELEGRETURN4res *, resp); 1926 0 stevel } 1927 0 stevel 1928 0 stevel /* 1929 0 stevel * Check to see if a given "flavor" is an explicitly shared flavor. 1930 0 stevel * The assumption of this routine is the "flavor" is already a valid 1931 0 stevel * flavor in the secinfo list of "exi". 1932 0 stevel * 1933 0 stevel * e.g. 1934 0 stevel * # share -o sec=flavor1 /export 1935 0 stevel * # share -o sec=flavor2 /export/home 1936 0 stevel * 1937 0 stevel * flavor2 is not an explicitly shared flavor for /export, 1938 0 stevel * however it is in the secinfo list for /export thru the 1939 0 stevel * server namespace setup. 1940 0 stevel */ 1941 0 stevel int 1942 0 stevel is_exported_sec(int flavor, struct exportinfo *exi) 1943 0 stevel { 1944 0 stevel int i; 1945 0 stevel struct secinfo *sp; 1946 0 stevel 1947 0 stevel sp = exi->exi_export.ex_secinfo; 1948 0 stevel for (i = 0; i < exi->exi_export.ex_seccnt; i++) { 1949 0 stevel if (flavor == sp[i].s_secinfo.sc_nfsnum || 1950 0 stevel sp[i].s_secinfo.sc_nfsnum == AUTH_NONE) { 1951 0 stevel return (SEC_REF_EXPORTED(&sp[i])); 1952 0 stevel } 1953 0 stevel } 1954 0 stevel 1955 0 stevel /* Should not reach this point based on the assumption */ 1956 0 stevel return (0); 1957 0 stevel } 1958 0 stevel 1959 0 stevel /* 1960 0 stevel * Check if the security flavor used in the request matches what is 1961 0 stevel * required at the export point or at the root pseudo node (exi_root). 1962 0 stevel * 1963 0 stevel * returns 1 if there's a match or if exported with AUTH_NONE; 0 otherwise. 1964 0 stevel * 1965 0 stevel */ 1966 0 stevel static int 1967 0 stevel secinfo_match_or_authnone(struct compound_state *cs) 1968 0 stevel { 1969 0 stevel int i; 1970 0 stevel struct secinfo *sp; 1971 0 stevel 1972 0 stevel /* 1973 0 stevel * Check cs->nfsflavor (from the request) against 1974 0 stevel * the current export data in cs->exi. 1975 0 stevel */ 1976 0 stevel sp = cs->exi->exi_export.ex_secinfo; 1977 0 stevel for (i = 0; i < cs->exi->exi_export.ex_seccnt; i++) { 1978 0 stevel if (cs->nfsflavor == sp[i].s_secinfo.sc_nfsnum || 1979 0 stevel sp[i].s_secinfo.sc_nfsnum == AUTH_NONE) 1980 0 stevel return (1); 1981 0 stevel } 1982 0 stevel 1983 0 stevel return (0); 1984 0 stevel } 1985 0 stevel 1986 0 stevel /* 1987 0 stevel * Check the access authority for the client and return the correct error. 1988 0 stevel */ 1989 0 stevel nfsstat4 1990 0 stevel call_checkauth4(struct compound_state *cs, struct svc_req *req) 1991 0 stevel { 1992 0 stevel int authres; 1993 0 stevel 1994 0 stevel /* 1995 0 stevel * First, check if the security flavor used in the request 1996 0 stevel * are among the flavors set in the server namespace. 1997 0 stevel */ 1998 0 stevel if (!secinfo_match_or_authnone(cs)) { 1999 0 stevel *cs->statusp = NFS4ERR_WRONGSEC; 2000 0 stevel return (*cs->statusp); 2001 0 stevel } 2002 0 stevel 2003 0 stevel authres = checkauth4(cs, req); 2004 0 stevel 2005 0 stevel if (authres > 0) { 2006 0 stevel *cs->statusp = NFS4_OK; 2007 0 stevel if (! (cs->access & CS_ACCESS_LIMITED)) 2008 0 stevel cs->access = CS_ACCESS_OK; 2009 0 stevel } else if (authres == 0) { 2010 0 stevel *cs->statusp = NFS4ERR_ACCESS; 2011 0 stevel } else if (authres == -2) { 2012 0 stevel *cs->statusp = NFS4ERR_WRONGSEC; 2013 0 stevel } else { 2014 0 stevel *cs->statusp = NFS4ERR_DELAY; 2015 0 stevel } 2016 0 stevel return (*cs->statusp); 2017 0 stevel } 2018 0 stevel 2019 0 stevel /* 2020 0 stevel * bitmap4_to_attrmask is called by getattr and readdir. 2021 0 stevel * It sets up the vattr mask and determines whether vfsstat call is needed 2022 0 stevel * based on the input bitmap. 2023 0 stevel * Returns nfsv4 status. 2024 0 stevel */ 2025 0 stevel static nfsstat4 2026 0 stevel bitmap4_to_attrmask(bitmap4 breq, struct nfs4_svgetit_arg *sargp) 2027 0 stevel { 2028 0 stevel int i; 2029 0 stevel uint_t va_mask; 2030 0 stevel struct statvfs64 *sbp = sargp->sbp; 2031 0 stevel 2032 0 stevel sargp->sbp = NULL; 2033 0 stevel sargp->flag = 0; 2034 0 stevel sargp->rdattr_error = NFS4_OK; 2035 0 stevel sargp->mntdfid_set = FALSE; 2036 0 stevel if (sargp->cs->vp) 2037 0 stevel sargp->xattr = get_fh4_flag(&sargp->cs->fh, 2038 5050 jwahlig FH4_ATTRDIR | FH4_NAMEDATTR); 2039 0 stevel else 2040 0 stevel sargp->xattr = 0; 2041 0 stevel 2042 0 stevel /* 2043 0 stevel * Set rdattr_error_req to true if return error per 2044 0 stevel * failed entry rather than fail the readdir. 2045 0 stevel */ 2046 0 stevel if (breq & FATTR4_RDATTR_ERROR_MASK) 2047 0 stevel sargp->rdattr_error_req = 1; 2048 0 stevel else 2049 0 stevel sargp->rdattr_error_req = 0; 2050 0 stevel 2051 0 stevel /* 2052 0 stevel * generate the va_mask 2053 0 stevel * Handle the easy cases first 2054 0 stevel */ 2055 0 stevel switch (breq) { 2056 0 stevel case NFS4_NTOV_ATTR_MASK: 2057 0 stevel sargp->vap->va_mask = NFS4_NTOV_ATTR_AT_MASK; 2058 0 stevel return (NFS4_OK); 2059 0 stevel 2060 0 stevel case NFS4_FS_ATTR_MASK: 2061 0 stevel sargp->vap->va_mask = NFS4_FS_ATTR_AT_MASK; 2062 0 stevel sargp->sbp = sbp; 2063 0 stevel return (NFS4_OK); 2064 0 stevel 2065 0 stevel case NFS4_NTOV_ATTR_CACHE_MASK: 2066 0 stevel sargp->vap->va_mask = NFS4_NTOV_ATTR_CACHE_AT_MASK; 2067 0 stevel return (NFS4_OK); 2068 0 stevel 2069 0 stevel case FATTR4_LEASE_TIME_MASK: 2070 0 stevel sargp->vap->va_mask = 0; 2071 0 stevel return (NFS4_OK); 2072 0 stevel 2073 0 stevel default: 2074 0 stevel va_mask = 0; 2075 0 stevel for (i = 0; i < nfs4_ntov_map_size; i++) { 2076 0 stevel if ((breq & nfs4_ntov_map[i].fbit) && 2077 5050 jwahlig nfs4_ntov_map[i].vbit) 2078 0 stevel va_mask |= nfs4_ntov_map[i].vbit; 2079 0 stevel } 2080 0 stevel 2081 0 stevel /* 2082 0 stevel * Check is vfsstat is needed 2083 0 stevel */ 2084 0 stevel if (breq & NFS4_FS_ATTR_MASK) 2085 0 stevel sargp->sbp = sbp; 2086 0 stevel 2087 0 stevel sargp->vap->va_mask = va_mask; 2088 0 stevel return (NFS4_OK); 2089 0 stevel } 2090 0 stevel /* NOTREACHED */ 2091 0 stevel } 2092 0 stevel 2093 0 stevel /* 2094 0 stevel * bitmap4_get_sysattrs is called by getattr and readdir. 2095 0 stevel * It calls both VOP_GETATTR and VFS_STATVFS calls to get the attrs. 2096 0 stevel * Returns nfsv4 status. 2097 0 stevel */ 2098 0 stevel static nfsstat4 2099 0 stevel bitmap4_get_sysattrs(struct nfs4_svgetit_arg *sargp) 2100 0 stevel { 2101 0 stevel int error; 2102 0 stevel struct compound_state *cs = sargp->cs; 2103 0 stevel vnode_t *vp = cs->vp; 2104 0 stevel 2105 0 stevel if (sargp->sbp != NULL) { 2106 0 stevel if (error = VFS_STATVFS(vp->v_vfsp, sargp->sbp)) { 2107 0 stevel sargp->sbp = NULL; /* to identify error */ 2108 0 stevel return (puterrno4(error)); 2109 0 stevel } 2110 0 stevel } 2111 0 stevel 2112 0 stevel return (rfs4_vop_getattr(vp, sargp->vap, 0, cs->cr)); 2113 0 stevel } 2114 0 stevel 2115 0 stevel static void 2116 0 stevel nfs4_ntov_table_init(struct nfs4_ntov_table *ntovp) 2117 0 stevel { 2118 0 stevel ntovp->na = kmem_zalloc(sizeof (union nfs4_attr_u) * nfs4_ntov_map_size, 2119 5050 jwahlig KM_SLEEP); 2120 0 stevel ntovp->attrcnt = 0; 2121 0 stevel ntovp->vfsstat = FALSE; 2122 0 stevel } 2123 0 stevel 2124 0 stevel static void 2125 0 stevel nfs4_ntov_table_free(struct nfs4_ntov_table *ntovp, 2126 9885 Robert struct nfs4_svgetit_arg *sargp) 2127 0 stevel { 2128 0 stevel int i; 2129 0 stevel union nfs4_attr_u *na; 2130 0 stevel uint8_t *amap; 2131 0 stevel 2132 0 stevel /* 2133 0 stevel * XXX Should do the same checks for whether the bit is set 2134 0 stevel */ 2135 0 stevel for (i = 0, na = ntovp->na, amap = ntovp->amap; 2136 5050 jwahlig i < ntovp->attrcnt; i++, na++, amap++) { 2137 0 stevel (void) (*nfs4_ntov_map[*amap].sv_getit)( 2138 5050 jwahlig NFS4ATTR_FREEIT, sargp, na); 2139 0 stevel } 2140 0 stevel if ((sargp->op == NFS4ATTR_SETIT) || (sargp->op == NFS4ATTR_VERIT)) { 2141 0 stevel /* 2142 0 stevel * xdr_free for getattr will be done later 2143 0 stevel */ 2144 0 stevel for (i = 0, na = ntovp->na, amap = ntovp->amap; 2145 5050 jwahlig i < ntovp->attrcnt; i++, na++, amap++) { 2146 0 stevel xdr_free(nfs4_ntov_map[*amap].xfunc, (caddr_t)na); 2147 0 stevel } 2148 0 stevel } 2149 0 stevel kmem_free(ntovp->na, sizeof (union nfs4_attr_u) * nfs4_ntov_map_size); 2150 0 stevel } 2151 0 stevel 2152 0 stevel /* 2153 0 stevel * do_rfs4_op_getattr gets the system attrs and converts into fattr4. 2154 0 stevel */ 2155 0 stevel static nfsstat4 2156 0 stevel do_rfs4_op_getattr(bitmap4 breq, fattr4 *fattrp, 2157 9885 Robert struct nfs4_svgetit_arg *sargp) 2158 0 stevel { 2159 0 stevel int error = 0; 2160 0 stevel int i, k; 2161 0 stevel struct nfs4_ntov_table ntov; 2162 0 stevel XDR xdr; 2163 0 stevel ulong_t xdr_size; 2164 0 stevel char *xdr_attrs; 2165 0 stevel nfsstat4 status = NFS4_OK; 2166 0 stevel nfsstat4 prev_rdattr_error = sargp->rdattr_error; 2167 0 stevel union nfs4_attr_u *na; 2168 0 stevel uint8_t *amap; 2169 0 stevel 2170 0 stevel sargp->op = NFS4ATTR_GETIT; 2171 0 stevel sargp->flag = 0; 2172 0 stevel 2173 0 stevel fattrp->attrmask = 0; 2174 0 stevel /* if no bits requested, then return empty fattr4 */ 2175 0 stevel if (breq == 0) { 2176 0 stevel fattrp->attrlist4_len = 0; 2177 0 stevel fattrp->attrlist4 = NULL; 2178 0 stevel return (NFS4_OK); 2179 0 stevel } 2180 0 stevel 2181 0 stevel /* 2182 0 stevel * return NFS4ERR_INVAL when client requests write-only attrs 2183 0 stevel */ 2184 0 stevel if (breq & (FATTR4_TIME_ACCESS_SET_MASK | FATTR4_TIME_MODIFY_SET_MASK)) 2185 0 stevel return (NFS4ERR_INVAL); 2186 0 stevel 2187 0 stevel nfs4_ntov_table_init(&ntov); 2188 0 stevel na = ntov.na; 2189 0 stevel amap = ntov.amap; 2190 0 stevel 2191 0 stevel /* 2192 0 stevel * Now loop to get or verify the attrs 2193 0 stevel */ 2194 0 stevel for (i = 0; i < nfs4_ntov_map_size; i++) { 2195 0 stevel if (breq & nfs4_ntov_map[i].fbit) { 2196 0 stevel if ((*nfs4_ntov_map[i].sv_getit)( 2197 5050 jwahlig NFS4ATTR_SUPPORTED, sargp, NULL) == 0) { 2198 0 stevel 2199 0 stevel error = (*nfs4_ntov_map[i].sv_getit)( 2200 5050 jwahlig NFS4ATTR_GETIT, sargp, na); 2201 0 stevel 2202 0 stevel /* 2203 0 stevel * Possible error values: 2204 0 stevel * >0 if sv_getit failed to 2205 0 stevel * get the attr; 0 if succeeded; 2206 0 stevel * <0 if rdattr_error and the 2207 0 stevel * attribute cannot be returned. 2208 0 stevel */ 2209 0 stevel if (error && !(sargp->rdattr_error_req)) 2210 0 stevel goto done; 2211 0 stevel /* 2212 0 stevel * If error then just for entry 2213 0 stevel */ 2214 0 stevel if (error == 0) { 2215 0 stevel fattrp->attrmask |= 2216 5050 jwahlig nfs4_ntov_map[i].fbit; 2217 0 stevel *amap++ = 2218 5050 jwahlig (uint8_t)nfs4_ntov_map[i].nval; 2219 0 stevel na++; 2220 0 stevel (ntov.attrcnt)++; 2221 0 stevel } else if ((error > 0) && 2222 5050 jwahlig (sargp->rdattr_error == NFS4_OK)) { 2223 0 stevel sargp->rdattr_error = puterrno4(error); 2224 0 stevel } 2225 0 stevel error = 0; 2226 0 stevel } 2227 0 stevel } 2228 0 stevel } 2229 0 stevel 2230 0 stevel /* 2231 0 stevel * If rdattr_error was set after the return value for it was assigned, 2232 0 stevel * update it. 2233 0 stevel */ 2234 0 stevel if (prev_rdattr_error != sargp->rdattr_error) { 2235 0 stevel na = ntov.na; 2236 0 stevel amap = ntov.amap; 2237 0 stevel for (i = 0; i < ntov.attrcnt; i++, na++, amap++) { 2238 0 stevel k = *amap; 2239 0 stevel if (k < FATTR4_RDATTR_ERROR) { 2240 0 stevel continue; 2241 0 stevel } 2242 0 stevel if ((k == FATTR4_RDATTR_ERROR) && 2243 0 stevel ((*nfs4_ntov_map[k].sv_getit)( 2244 5050 jwahlig NFS4ATTR_SUPPORTED, sargp, NULL) == 0)) { 2245 0 stevel 2246 0 stevel (void) (*nfs4_ntov_map[k].sv_getit)( 2247 5050 jwahlig NFS4ATTR_GETIT, sargp, na); 2248 0 stevel } 2249 0 stevel break; 2250 0 stevel } 2251 0 stevel } 2252 0 stevel 2253 0 stevel xdr_size = 0; 2254 0 stevel na = ntov.na; 2255 0 stevel amap = ntov.amap; 2256 0 stevel for (i = 0; i < ntov.attrcnt; i++, na++, amap++) { 2257 0 stevel xdr_size += xdr_sizeof(nfs4_ntov_map[*amap].xfunc, na); 2258 0 stevel } 2259 0 stevel 2260 0 stevel fattrp->attrlist4_len = xdr_size; 2261 0 stevel if (xdr_size) { 2262 0 stevel /* freed by rfs4_op_getattr_free() */ 2263 0 stevel fattrp->attrlist4 = xdr_attrs = kmem_zalloc(xdr_size, KM_SLEEP); 2264 0 stevel 2265 0 stevel xdrmem_create(&xdr, xdr_attrs, xdr_size, XDR_ENCODE); 2266 0 stevel 2267 0 stevel na = ntov.na; 2268 0 stevel amap = ntov.amap; 2269 0 stevel for (i = 0; i < ntov.attrcnt; i++, na++, amap++) { 2270 0 stevel if (!(*nfs4_ntov_map[*amap].xfunc)(&xdr, na)) { 2271 7387 Robert DTRACE_PROBE1(nfss__e__getattr4_encfail, 2272 7387 Robert int, *amap); 2273 0 stevel status = NFS4ERR_SERVERFAULT; 2274 0 stevel break; 2275 0 stevel } 2276 0 stevel } 2277 0 stevel /* xdrmem_destroy(&xdrs); */ /* NO-OP */ 2278 0 stevel } else { 2279 0 stevel fattrp->attrlist4 = NULL; 2280 0 stevel } 2281 0 stevel done: 2282 0 stevel 2283 0 stevel nfs4_ntov_table_free(&ntov, sargp); 2284 0 stevel 2285 0 stevel if (error != 0) 2286 0 stevel status = puterrno4(error); 2287 0 stevel 2288 0 stevel return (status); 2289 0 stevel } 2290 0 stevel 2291 0 stevel /* ARGSUSED */ 2292 0 stevel static void 2293 0 stevel rfs4_op_getattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 2294 9885 Robert struct compound_state *cs) 2295 0 stevel { 2296 0 stevel GETATTR4args *args = &argop->nfs_argop4_u.opgetattr; 2297 0 stevel GETATTR4res *resp = &resop->nfs_resop4_u.opgetattr; 2298 0 stevel struct nfs4_svgetit_arg sarg; 2299 0 stevel struct statvfs64 sb; 2300 0 stevel nfsstat4 status; 2301 0 stevel 2302 5647 samf DTRACE_NFSV4_2(op__getattr__start, struct compound_state *, cs, 2303 5647 samf GETATTR4args *, args); 2304 5647 samf 2305 5647 samf if (cs->vp == NULL) { 2306 5647 samf *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 2307 5647 samf goto out; 2308 5647 samf } 2309 5647 samf 2310 5647 samf if (cs->access == CS_ACCESS_DENIED) { 2311 5647 samf *cs->statusp = resp->status = NFS4ERR_ACCESS; 2312 5647 samf goto out; 2313 0 stevel } 2314 0 stevel 2315 0 stevel sarg.sbp = &sb; 2316 0 stevel sarg.cs = cs; 2317 0 stevel 2318 0 stevel status = bitmap4_to_attrmask(args->attr_request, &sarg); 2319 0 stevel if (status == NFS4_OK) { 2320 0 stevel status = bitmap4_get_sysattrs(&sarg); 2321 0 stevel if (status == NFS4_OK) 2322 0 stevel status = do_rfs4_op_getattr(args->attr_request, 2323 5050 jwahlig &resp->obj_attributes, &sarg); 2324 0 stevel } 2325 0 stevel *cs->statusp = resp->status = status; 2326 5647 samf out: 2327 5647 samf DTRACE_NFSV4_2(op__getattr__done, struct compound_state *, cs, 2328 5647 samf GETATTR4res *, resp); 2329 0 stevel } 2330 0 stevel 2331 0 stevel static void 2332 0 stevel rfs4_op_getattr_free(nfs_resop4 *resop) 2333 0 stevel { 2334 0 stevel GETATTR4res *resp = &resop->nfs_resop4_u.opgetattr; 2335 0 stevel 2336 0 stevel nfs4_fattr4_free(&resp->obj_attributes); 2337 0 stevel } 2338 0 stevel 2339 0 stevel /* ARGSUSED */ 2340 0 stevel static void 2341 0 stevel rfs4_op_getfh(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 2342 9885 Robert struct compound_state *cs) 2343 0 stevel { 2344 0 stevel GETFH4res *resp = &resop->nfs_resop4_u.opgetfh; 2345 0 stevel 2346 5647 samf DTRACE_NFSV4_1(op__getfh__start, struct compound_state *, cs); 2347 5647 samf 2348 5647 samf if (cs->vp == NULL) { 2349 5647 samf *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 2350 5647 samf goto out; 2351 5647 samf } 2352 5647 samf if (cs->access == CS_ACCESS_DENIED) { 2353 5647 samf *cs->statusp = resp->status = NFS4ERR_ACCESS; 2354 5647 samf goto out; 2355 0 stevel } 2356 0 stevel 2357 0 stevel resp->object.nfs_fh4_val = 2358 5050 jwahlig kmem_alloc(cs->fh.nfs_fh4_len, KM_SLEEP); 2359 0 stevel nfs_fh4_copy(&cs->fh, &resp->object); 2360 0 stevel *cs->statusp = resp->status = NFS4_OK; 2361 5647 samf out: 2362 5647 samf DTRACE_NFSV4_2(op__getfh__done, struct compound_state *, cs, 2363 5647 samf GETFH4res *, resp); 2364 0 stevel } 2365 0 stevel 2366 0 stevel static void 2367 0 stevel rfs4_op_getfh_free(nfs_resop4 *resop) 2368 0 stevel { 2369 0 stevel GETFH4res *resp = &resop->nfs_resop4_u.opgetfh; 2370 0 stevel 2371 0 stevel if (resp->status == NFS4_OK && 2372 0 stevel resp->object.nfs_fh4_val != NULL) { 2373 0 stevel kmem_free(resp->object.nfs_fh4_val, resp->object.nfs_fh4_len); 2374 0 stevel resp->object.nfs_fh4_val = NULL; 2375 0 stevel resp->object.nfs_fh4_len = 0; 2376 0 stevel } 2377 0 stevel } 2378 0 stevel 2379 0 stevel /* 2380 0 stevel * illegal: args: void 2381 0 stevel * res : status (NFS4ERR_OP_ILLEGAL) 2382 0 stevel */ 2383 0 stevel /* ARGSUSED */ 2384 0 stevel static void 2385 0 stevel rfs4_op_illegal(nfs_argop4 *argop, nfs_resop4 *resop, 2386 9885 Robert struct svc_req *req, struct compound_state *cs) 2387 0 stevel { 2388 0 stevel ILLEGAL4res *resp = &resop->nfs_resop4_u.opillegal; 2389 0 stevel 2390 0 stevel resop->resop = OP_ILLEGAL; 2391 0 stevel *cs->statusp = resp->status = NFS4ERR_OP_ILLEGAL; 2392 0 stevel } 2393 0 stevel 2394 0 stevel /* 2395 0 stevel * link: args: SAVED_FH: file, CURRENT_FH: target directory 2396 0 stevel * res: status. If success - CURRENT_FH unchanged, return change_info 2397 0 stevel */ 2398 0 stevel /* ARGSUSED */ 2399 0 stevel static void 2400 0 stevel rfs4_op_link(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 2401 9885 Robert struct compound_state *cs) 2402 0 stevel { 2403 0 stevel LINK4args *args = &argop->nfs_argop4_u.oplink; 2404 0 stevel LINK4res *resp = &resop->nfs_resop4_u.oplink; 2405 0 stevel int error; 2406 0 stevel vnode_t *vp; 2407 0 stevel vnode_t *dvp; 2408 0 stevel struct vattr bdva, idva, adva; 2409 0 stevel char *nm; 2410 0 stevel uint_t len; 2411 7961 Natalie struct sockaddr *ca; 2412 7961 Natalie char *name = NULL; 2413 0 stevel 2414 5647 samf DTRACE_NFSV4_2(op__link__start, struct compound_state *, cs, 2415 5647 samf LINK4args *, args); 2416 5647 samf 2417 0 stevel /* SAVED_FH: source object */ 2418 0 stevel vp = cs->saved_vp; 2419 0 stevel if (vp == NULL) { 2420 0 stevel *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 2421 5647 samf goto out; 2422 0 stevel } 2423 0 stevel 2424 0 stevel /* CURRENT_FH: target directory */ 2425 0 stevel dvp = cs->vp; 2426 0 stevel if (dvp == NULL) { 2427 0 stevel *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 2428 5647 samf goto out; 2429 0 stevel } 2430 0 stevel 2431 0 stevel /* 2432 0 stevel * If there is a non-shared filesystem mounted on this vnode, 2433 0 stevel * do not allow to link any file in this directory. 2434 0 stevel */ 2435 0 stevel if (vn_ismntpt(dvp)) { 2436 0 stevel *cs->statusp = resp->status = NFS4ERR_ACCESS; 2437 5647 samf goto out; 2438 5647 samf } 2439 5647 samf 2440 5647 samf if (cs->access == CS_ACCESS_DENIED) { 2441 5647 samf *cs->statusp = resp->status = NFS4ERR_ACCESS; 2442 5647 samf goto out; 2443 0 stevel } 2444 0 stevel 2445 0 stevel /* Check source object's type validity */ 2446 0 stevel if (vp->v_type == VDIR) { 2447 0 stevel *cs->statusp = resp->status = NFS4ERR_ISDIR; 2448 5647 samf goto out; 2449 0 stevel } 2450 0 stevel 2451 0 stevel /* Check target directory's type */ 2452 0 stevel if (dvp->v_type != VDIR) { 2453 0 stevel *cs->statusp = resp->status = NFS4ERR_NOTDIR; 2454 5647 samf goto out; 2455 0 stevel } 2456 0 stevel 2457 0 stevel if (cs->saved_exi != cs->exi) { 2458 0 stevel *cs->statusp = resp->status = NFS4ERR_XDEV; 2459 5647 samf goto out; 2460 0 stevel } 2461 0 stevel 2462 0 stevel if (!utf8_dir_verify(&args->newname)) { 2463 0 stevel *cs->statusp = resp->status = NFS4ERR_INVAL; 2464 5647 samf goto out; 2465 0 stevel } 2466 0 stevel 2467 0 stevel nm = utf8_to_fn(&args->newname, &len, NULL); 2468 0 stevel if (nm == NULL) { 2469 0 stevel *cs->statusp = resp->status = NFS4ERR_INVAL; 2470 5647 samf goto out; 2471 0 stevel } 2472 0 stevel 2473 0 stevel if (len > MAXNAMELEN) { 2474 0 stevel *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG; 2475 0 stevel kmem_free(nm, len); 2476 5647 samf goto out; 2477 0 stevel } 2478 0 stevel 2479 0 stevel if (rdonly4(cs->exi, cs->vp, req)) { 2480 0 stevel *cs->statusp = resp->status = NFS4ERR_ROFS; 2481 0 stevel kmem_free(nm, len); 2482 5647 samf goto out; 2483 0 stevel } 2484 0 stevel 2485 0 stevel /* Get "before" change value */ 2486 0 stevel bdva.va_mask = AT_CTIME|AT_SEQ; 2487 5331 amw error = VOP_GETATTR(dvp, &bdva, 0, cs->cr, NULL); 2488 0 stevel if (error) { 2489 0 stevel *cs->statusp = resp->status = puterrno4(error); 2490 0 stevel kmem_free(nm, len); 2491 5647 samf goto out; 2492 0 stevel } 2493 0 stevel 2494 7961 Natalie ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2495 7961 Natalie name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND, 2496 7961 Natalie MAXPATHLEN + 1); 2497 7961 Natalie 2498 7961 Natalie if (name == NULL) { 2499 7961 Natalie *cs->statusp = resp->status = NFS4ERR_INVAL; 2500 7961 Natalie kmem_free(nm, len); 2501 7961 Natalie goto out; 2502 7961 Natalie } 2503 7961 Natalie 2504 0 stevel NFS4_SET_FATTR4_CHANGE(resp->cinfo.before, bdva.va_ctime) 2505 0 stevel 2506 7961 Natalie error = VOP_LINK(dvp, vp, name, cs->cr, NULL, 0); 2507 7961 Natalie 2508 7961 Natalie if (nm != name) 2509 7961 Natalie kmem_free(name, MAXPATHLEN + 1); 2510 0 stevel kmem_free(nm, len); 2511 0 stevel 2512 0 stevel /* 2513 0 stevel * Get the initial "after" sequence number, if it fails, set to zero 2514 0 stevel */ 2515 0 stevel idva.va_mask = AT_SEQ; 2516 5331 amw if (VOP_GETATTR(dvp, &idva, 0, cs->cr, NULL)) 2517 0 stevel idva.va_seq = 0; 2518 0 stevel 2519 0 stevel /* 2520 0 stevel * Force modified data and metadata out to stable storage. 2521 0 stevel */ 2522 5331 amw (void) VOP_FSYNC(vp, FNODSYNC, cs->cr, NULL); 2523 5331 amw (void) VOP_FSYNC(dvp, 0, cs->cr, NULL); 2524 0 stevel 2525 0 stevel if (error) { 2526 0 stevel *cs->statusp = resp->status = puterrno4(error); 2527 5647 samf goto out; 2528 0 stevel } 2529 0 stevel 2530 0 stevel /* 2531 0 stevel * Get "after" change value, if it fails, simply return the 2532 0 stevel * before value. 2533 0 stevel */ 2534 0 stevel adva.va_mask = AT_CTIME|AT_SEQ; 2535 5331 amw if (VOP_GETATTR(dvp, &adva, 0, cs->cr, NULL)) { 2536 0 stevel adva.va_ctime = bdva.va_ctime; 2537 0 stevel adva.va_seq = 0; 2538 0 stevel } 2539 0 stevel 2540 0 stevel NFS4_SET_FATTR4_CHANGE(resp->cinfo.after, adva.va_ctime) 2541 0 stevel 2542 0 stevel /* 2543 0 stevel * The cinfo.atomic = TRUE only if we have 2544 0 stevel * non-zero va_seq's, and it has incremented by exactly one 2545 0 stevel * during the VOP_LINK and it didn't change during the VOP_FSYNC. 2546 0 stevel */ 2547 0 stevel if (bdva.va_seq && idva.va_seq && adva.va_seq && 2548 5050 jwahlig idva.va_seq == (bdva.va_seq + 1) && idva.va_seq == adva.va_seq) 2549 0 stevel resp->cinfo.atomic = TRUE; 2550 0 stevel else 2551 0 stevel resp->cinfo.atomic = FALSE; 2552 0 stevel 2553 0 stevel *cs->statusp = resp->status = NFS4_OK; 2554 5647 samf out: 2555 5647 samf DTRACE_NFSV4_2(op__link__done, struct compound_state *, cs, 2556 5647 samf LINK4res *, resp); 2557 0 stevel } 2558 0 stevel 2559 0 stevel /* 2560 0 stevel * Used by rfs4_op_lookup and rfs4_op_lookupp to do the actual work. 2561 0 stevel */ 2562 0 stevel 2563 0 stevel /* ARGSUSED */ 2564 0 stevel static nfsstat4 2565 0 stevel do_rfs4_op_lookup(char *nm, uint_t buflen, struct svc_req *req, 2566 9885 Robert struct compound_state *cs) 2567 0 stevel { 2568 0 stevel int error; 2569 0 stevel int different_export = 0; 2570 0 stevel vnode_t *vp, *tvp, *pre_tvp = NULL, *oldvp = NULL; 2571 0 stevel struct exportinfo *exi = NULL, *pre_exi = NULL; 2572 0 stevel nfsstat4 stat; 2573 0 stevel fid_t fid; 2574 0 stevel int attrdir, dotdot, walk; 2575 0 stevel bool_t is_newvp = FALSE; 2576 0 stevel 2577 0 stevel if (cs->vp->v_flag & V_XATTRDIR) { 2578 0 stevel attrdir = 1; 2579 0 stevel ASSERT(get_fh4_flag(&cs->fh, FH4_ATTRDIR)); 2580 0 stevel } else { 2581 0 stevel attrdir = 0; 2582 0 stevel ASSERT(! get_fh4_flag(&cs->fh, FH4_ATTRDIR)); 2583 0 stevel } 2584 0 stevel 2585 0 stevel dotdot = (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0'); 2586 0 stevel 2587 0 stevel /* 2588 0 stevel * If dotdotting, then need to check whether it's 2589 0 stevel * above the root of a filesystem, or above an 2590 0 stevel * export point. 2591 0 stevel */ 2592 0 stevel if (dotdot) { 2593 0 stevel 2594 0 stevel /* 2595 0 stevel * If dotdotting at the root of a filesystem, then 2596 0 stevel * need to traverse back to the mounted-on filesystem 2597 0 stevel * and do the dotdot lookup there. 2598 0 stevel */ 2599 0 stevel if (cs->vp->v_flag & VROOT) { 2600 0 stevel 2601 0 stevel /* 2602 0 stevel * If at the system root, then can 2603 0 stevel * go up no further. 2604 0 stevel */ 2605 0 stevel if (VN_CMP(cs->vp, rootdir)) 2606 0 stevel return (puterrno4(ENOENT)); 2607 0 stevel 2608 0 stevel /* 2609 0 stevel * Traverse back to the mounted-on filesystem 2610 0 stevel */ 2611 0 stevel cs->vp = untraverse(cs->vp); 2612 0 stevel 2613 0 stevel /* 2614 0 stevel * Set the different_export flag so we remember 2615 0 stevel * to pick up a new exportinfo entry for 2616 0 stevel * this new filesystem. 2617 0 stevel */ 2618 0 stevel different_export = 1; 2619 0 stevel } else { 2620 0 stevel 2621 0 stevel /* 2622 0 stevel * If dotdotting above an export point then set 2623 0 stevel * the different_export to get new export info. 2624 0 stevel */ 2625 0 stevel different_export = nfs_exported(cs->exi, cs->vp); 2626 0 stevel } 2627 0 stevel } 2628 0 stevel 2629 5331 amw error = VOP_LOOKUP(cs->vp, nm, &vp, NULL, 0, NULL, cs->cr, 2630 5331 amw NULL, NULL, NULL); 2631 0 stevel if (error) 2632 0 stevel return (puterrno4(error)); 2633 0 stevel 2634 0 stevel /* 2635 0 stevel * If the vnode is in a pseudo filesystem, check whether it is visible. 2636 0 stevel * 2637 0 stevel * XXX if the vnode is a symlink and it is not visible in 2638 0 stevel * a pseudo filesystem, return ENOENT (not following symlink). 2639 0 stevel * V4 client can not mount such symlink. This is a regression 2640 0 stevel * from V2/V3. 2641 0 stevel * 2642 0 stevel * In the same exported filesystem, if the security flavor used 2643 0 stevel * is not an explicitly shared flavor, limit the view to the visible 2644 0 stevel * list entries only. This is not a WRONGSEC case because it's already 2645 0 stevel * checked via PUTROOTFH/PUTPUBFH or PUTFH. 2646 0 stevel */ 2647 0 stevel if (!different_export && 2648 0 stevel (PSEUDO(cs->exi) || ! is_exported_sec(cs->nfsflavor, cs->exi) || 2649 0 stevel cs->access & CS_ACCESS_LIMITED)) { 2650 0 stevel if (! nfs_visible(cs->exi, vp, &different_export)) { 2651 0 stevel VN_RELE(vp); 2652 0 stevel return (puterrno4(ENOENT)); 2653 0 stevel } 2654 0 stevel } 2655 0 stevel 2656 0 stevel /* 2657 0 stevel * If it's a mountpoint, then traverse it. 2658 0 stevel */ 2659 0 stevel if (vn_ismntpt(vp)) { 2660 0 stevel pre_exi = cs->exi; /* save pre-traversed exportinfo */ 2661 0 stevel pre_tvp = vp; /* save pre-traversed vnode */ 2662 0 stevel 2663 0 stevel /* 2664 0 stevel * hold pre_tvp to counteract rele by traverse. We will 2665 0 stevel * need pre_tvp below if checkexport4 fails 2666 0 stevel */ 2667 0 stevel VN_HOLD(pre_tvp); 2668 0 stevel tvp = vp; 2669 0 stevel if ((error = traverse(&tvp)) != 0) { 2670 0 stevel VN_RELE(vp); 2671 0 stevel VN_RELE(pre_tvp); 2672 0 stevel return (puterrno4(error)); 2673 0 stevel } 2674 0 stevel vp = tvp; 2675 0 stevel different_export = 1; 2676 0 stevel } else if (vp->v_vfsp != cs->vp->v_vfsp) { 2677 0 stevel /* 2678 0 stevel * The vfsp comparison is to handle the case where 2679 0 stevel * a LOFS mount is shared. lo_lookup traverses mount points, 2680 0 stevel * and NFS is unaware of local fs transistions because 2681 0 stevel * v_vfsmountedhere isn't set. For this special LOFS case, 2682 0 stevel * the dir and the obj returned by lookup will have different 2683 0 stevel * vfs ptrs. 2684 0 stevel */ 2685 0 stevel different_export = 1; 2686 0 stevel } 2687 0 stevel 2688 0 stevel if (different_export) { 2689 0 stevel 2690 0 stevel bzero(&fid, sizeof (fid)); 2691 0 stevel fid.fid_len = MAXFIDSZ; 2692 0 stevel error = vop_fid_pseudo(vp, &fid); 2693 0 stevel if (error) { 2694 0 stevel VN_RELE(vp); 2695 0 stevel if (pre_tvp) 2696 0 stevel VN_RELE(pre_tvp); 2697 0 stevel return (puterrno4(error)); 2698 0 stevel } 2699 0 stevel 2700 0 stevel if (dotdot) 2701 0 stevel exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE); 2702 0 stevel else 2703 0 stevel exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp); 2704 0 stevel 2705 0 stevel if (exi == NULL) { 2706 0 stevel if (pre_tvp) { 2707 0 stevel /* 2708 0 stevel * If this vnode is a mounted-on vnode, 2709 0 stevel * but the mounted-on file system is not 2710 0 stevel * exported, send back the filehandle for 2711 0 stevel * the mounted-on vnode, not the root of 2712 0 stevel * the mounted-on file system. 2713 0 stevel */ 2714 0 stevel VN_RELE(vp); 2715 0 stevel vp = pre_tvp; 2716 0 stevel exi = pre_exi; 2717 0 stevel } else { 2718 0 stevel VN_RELE(vp); 2719 0 stevel return (puterrno4(EACCES)); 2720 0 stevel } 2721 0 stevel } else if (pre_tvp) { 2722 0 stevel /* we're done with pre_tvp now. release extra hold */ 2723 0 stevel VN_RELE(pre_tvp); 2724 0 stevel } 2725 0 stevel 2726 0 stevel cs->exi = exi; 2727 0 stevel 2728 0 stevel /* 2729 0 stevel * Now we do a checkauth4. The reason is that 2730 0 stevel * this client/user may not have access to the new 2731 0 stevel * exported file system, and if he does, 2732 0 stevel * the client/user may be mapped to a different uid. 2733 0 stevel * 2734 0 stevel * We start with a new cr, because the checkauth4 done 2735 0 stevel * in the PUT*FH operation over wrote the cred's uid, 2736 0 stevel * gid, etc, and we want the real thing before calling 2737 0 stevel * checkauth4() 2738 0 stevel */ 2739 0 stevel crfree(cs->cr); 2740 0 stevel cs->cr = crdup(cs->basecr); 2741 0 stevel 2742 0 stevel if (cs->vp) 2743 0 stevel oldvp = cs->vp; 2744 0 stevel cs->vp = vp; 2745 0 stevel is_newvp = TRUE; 2746 0 stevel 2747 0 stevel stat = call_checkauth4(cs, req); 2748 0 stevel if (stat != NFS4_OK) { 2749 0 stevel VN_RELE(cs->vp); 2750 0 stevel cs->vp = oldvp; 2751 0 stevel return (stat); 2752 0 stevel } 2753 0 stevel } 2754 0 stevel 2755 1676 jpk /* 2756 1676 jpk * After various NFS checks, do a label check on the path 2757 1676 jpk * component. The label on this path should either be the 2758 1676 jpk * global zone's label or a zone's label. We are only 2759 1676 jpk * interested in the zone's label because exported files 2760 1676 jpk * in global zone is accessible (though read-only) to 2761 1676 jpk * clients. The exportability/visibility check is already 2762 1676 jpk * done before reaching this code. 2763 1676 jpk */ 2764 1676 jpk if (is_system_labeled()) { 2765 1676 jpk bslabel_t *clabel; 2766 1676 jpk 2767 1676 jpk ASSERT(req->rq_label != NULL); 2768 1676 jpk clabel = req->rq_label; 2769 1676 jpk DTRACE_PROBE2(tx__rfs4__log__info__oplookup__clabel, char *, 2770 1676 jpk "got client label from request(1)", struct svc_req *, req); 2771 1676 jpk 2772 1676 jpk if (!blequal(&l_admin_low->tsl_label, clabel)) { 2773 9871 Jarrett if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK, 2774 9871 Jarrett cs->exi)) { 2775 1676 jpk error = EACCES; 2776 1676 jpk goto err_out; 2777 1676 jpk } 2778 1676 jpk } else { 2779 1676 jpk /* 2780 1676 jpk * We grant access to admin_low label clients 2781 1676 jpk * only if the client is trusted, i.e. also 2782 1676 jpk * running Solaris Trusted Extension. 2783 1676 jpk */ 2784 1676 jpk struct sockaddr *ca; 2785 1676 jpk int addr_type; 2786 1676 jpk void *ipaddr; 2787 1676 jpk tsol_tpc_t *tp; 2788 1676 jpk 2789 1676 jpk ca = (struct sockaddr *)svc_getrpccaller( 2790 1676 jpk req->rq_xprt)->buf; 2791 1676 jpk if (ca->sa_family == AF_INET) { 2792 1676 jpk addr_type = IPV4_VERSION; 2793 1676 jpk ipaddr = &((struct sockaddr_in *)ca)->sin_addr; 2794 1676 jpk } else if (ca->sa_family == AF_INET6) { 2795 1676 jpk addr_type = IPV6_VERSION; 2796 1676 jpk ipaddr = &((struct sockaddr_in6 *) 2797 1676 jpk ca)->sin6_addr; 2798 1676 jpk } 2799 1676 jpk tp = find_tpc(ipaddr, addr_type, B_FALSE); 2800 1676 jpk if (tp == NULL || tp->tpc_tp.tp_doi != 2801 1676 jpk l_admin_low->tsl_doi || tp->tpc_tp.host_type != 2802 1676 jpk SUN_CIPSO) { 2803 4971 jarrett if (tp != NULL) 2804 4971 jarrett TPC_RELE(tp); 2805 1676 jpk error = EACCES; 2806 1676 jpk goto err_out; 2807 1676 jpk } 2808 4971 jarrett TPC_RELE(tp); 2809 1676 jpk } 2810 1676 jpk } 2811 1676 jpk 2812 0 stevel error = makefh4(&cs->fh, vp, cs->exi); 2813 0 stevel 2814 1676 jpk err_out: 2815 0 stevel if (error) { 2816 0 stevel if (is_newvp) { 2817 0 stevel VN_RELE(cs->vp); 2818 0 stevel cs->vp = oldvp; 2819 0 stevel } else 2820 0 stevel VN_RELE(vp); 2821 0 stevel return (puterrno4(error)); 2822 0 stevel } 2823 0 stevel 2824 0 stevel if (!is_newvp) { 2825 0 stevel if (cs->vp) 2826 0 stevel VN_RELE(cs->vp); 2827 0 stevel cs->vp = vp; 2828 0 stevel } else if (oldvp) 2829 0 stevel VN_RELE(oldvp); 2830 0 stevel 2831 0 stevel /* 2832 0 stevel * if did lookup on attrdir and didn't lookup .., set named 2833 0 stevel * attr fh flag 2834 0 stevel */ 2835 0 stevel if (attrdir && ! dotdot) 2836 0 stevel set_fh4_flag(&cs->fh, FH4_NAMEDATTR); 2837 0 stevel 2838 0 stevel /* Assume false for now, open proc will set this */ 2839 0 stevel cs->mandlock = FALSE; 2840 0 stevel 2841 0 stevel return (NFS4_OK); 2842 0 stevel } 2843 0 stevel 2844 0 stevel /* ARGSUSED */ 2845 0 stevel static void 2846 0 stevel rfs4_op_lookup(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 2847 9885 Robert struct compound_state *cs) 2848 0 stevel { 2849 0 stevel LOOKUP4args *args = &argop->nfs_argop4_u.oplookup; 2850 0 stevel LOOKUP4res *resp = &resop->nfs_resop4_u.oplookup; 2851 0 stevel char *nm; 2852 0 stevel uint_t len; 2853 7961 Natalie struct sockaddr *ca; 2854 7961 Natalie char *name = NULL; 2855 0 stevel 2856 5647 samf DTRACE_NFSV4_2(op__lookup__start, struct compound_state *, cs, 2857 5647 samf LOOKUP4args *, args); 2858 5647 samf 2859 5647 samf if (cs->vp == NULL) { 2860 5647 samf *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 2861 5647 samf goto out; 2862 0 stevel } 2863 0 stevel 2864 0 stevel if (cs->vp->v_type == VLNK) { 2865 0 stevel *cs->statusp = resp->status = NFS4ERR_SYMLINK; 2866 5647 samf goto out; 2867 0 stevel } 2868 0 stevel 2869 0 stevel if (cs->vp->v_type != VDIR) { 2870 0 stevel *cs->statusp = resp->status = NFS4ERR_NOTDIR; 2871 5647 samf goto out; 2872 0 stevel } 2873 0 stevel 2874 0 stevel if (!utf8_dir_verify(&args->objname)) { 2875 0 stevel *cs->statusp = resp->status = NFS4ERR_INVAL; 2876 5647 samf goto out; 2877 0 stevel } 2878 0 stevel 2879 0 stevel nm = utf8_to_str(&args->objname, &len, NULL); 2880 0 stevel if (nm == NULL) { 2881 0 stevel *cs->statusp = resp->status = NFS4ERR_INVAL; 2882 5647 samf goto out; 2883 0 stevel } 2884 0 stevel 2885 0 stevel if (len > MAXNAMELEN) { 2886 0 stevel *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG; 2887 0 stevel kmem_free(nm, len); 2888 5647 samf goto out; 2889 0 stevel } 2890 0 stevel 2891 7961 Natalie /* If necessary, convert to UTF-8 for illbehaved clients */ 2892 7961 Natalie 2893 7961 Natalie ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2894 7961 Natalie name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND, 2895 7961 Natalie MAXPATHLEN + 1); 2896 7961 Natalie 2897 7961 Natalie if (name == NULL) { 2898 7961 Natalie *cs->statusp = resp->status = NFS4ERR_INVAL; 2899 7961 Natalie kmem_free(nm, len); 2900 7961 Natalie goto out; 2901 7961 Natalie } 2902 7961 Natalie 2903 7961 Natalie *cs->statusp = resp->status = do_rfs4_op_lookup(name, len, req, cs); 2904 7961 Natalie 2905 7961 Natalie if (name != nm) 2906 7961 Natalie kmem_free(name, MAXPATHLEN + 1); 2907 0 stevel kmem_free(nm, len); 2908 5647 samf 2909 5647 samf out: 2910 5647 samf DTRACE_NFSV4_2(op__lookup__done, struct compound_state *, cs, 2911 5647 samf LOOKUP4res *, resp); 2912 0 stevel } 2913 0 stevel 2914 0 stevel /* ARGSUSED */ 2915 0 stevel static void 2916 0 stevel rfs4_op_lookupp(nfs_argop4 *args, nfs_resop4 *resop, struct svc_req *req, 2917 9885 Robert struct compound_state *cs) 2918 0 stevel { 2919 0 stevel LOOKUPP4res *resp = &resop->nfs_resop4_u.oplookupp; 2920 0 stevel 2921 5647 samf DTRACE_NFSV4_1(op__lookupp__start, struct compound_state *, cs); 2922 5647 samf 2923 5647 samf if (cs->vp == NULL) { 2924 5647 samf *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 2925 5647 samf goto out; 2926 0 stevel } 2927 0 stevel 2928 0 stevel if (cs->vp->v_type != VDIR) { 2929 0 stevel *cs->statusp = resp->status = NFS4ERR_NOTDIR; 2930 5647 samf goto out; 2931 0 stevel } 2932 0 stevel 2933 0 stevel *cs->statusp = resp->status = do_rfs4_op_lookup("..", 3, req, cs); 2934 0 stevel 2935 0 stevel /* 2936 0 stevel * From NFSV4 Specification, LOOKUPP should not check for 2937 0 stevel * NFS4ERR_WRONGSEC. Retrun NFS4_OK instead. 2938 0 stevel */ 2939 0 stevel if (resp->status == NFS4ERR_WRONGSEC) { 2940 0 stevel *cs->statusp = resp->status = NFS4_OK; 2941 0 stevel } 2942 5647 samf 2943 5647 samf out: 2944 5647 samf DTRACE_NFSV4_2(op__lookupp__done, struct compound_state *, cs, 2945 5647 samf LOOKUPP4res *, resp); 2946 0 stevel } 2947 0 stevel 2948 0 stevel 2949 0 stevel /*ARGSUSED2*/ 2950 0 stevel static void 2951 0 stevel rfs4_op_openattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 2952 9885 Robert struct compound_state *cs) 2953 0 stevel { 2954 0 stevel OPENATTR4args *args = &argop->nfs_argop4_u.opopenattr; 2955 0 stevel OPENATTR4res *resp = &resop->nfs_resop4_u.opopenattr; 2956 0 stevel vnode_t *avp = NULL; 2957 0 stevel int lookup_flags = LOOKUP_XATTR, error; 2958 0 stevel int exp_ro = 0; 2959 0 stevel 2960 5647 samf DTRACE_NFSV4_2(op__openattr__start, struct compound_state *, cs, 2961 5647 samf OPENATTR4args *, args); 2962 5647 samf 2963 5647 samf if (cs->vp == NULL) { 2964 5647 samf *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 2965 5647 samf goto out; 2966 0 stevel } 2967 0 stevel 2968 5331 amw if ((cs->vp->v_vfsp->vfs_flag & VFS_XATTR) == 0 && 2969 7757 Janice !vfs_has_feature(cs->vp->v_vfsp, VFSFT_SYSATTR_VIEWS)) { 2970 5647 samf *cs->statusp = resp->status = puterrno4(ENOTSUP); 2971 5647 samf goto out; 2972 0 stevel } 2973 0 stevel 2974 7067 marks /* 2975 7067 marks * If file system supports passing ACE mask to VOP_ACCESS then 2976 7067 marks * check for ACE_READ_NAMED_ATTRS, otherwise do legacy checks 2977 7067 marks */ 2978 7067 marks 2979 7067 marks if (vfs_has_feature(cs->vp->v_vfsp, VFSFT_ACEMASKONACCESS)) 2980 7067 marks error = VOP_ACCESS(cs->vp, ACE_READ_NAMED_ATTRS, 2981 7067 marks V_ACE_MASK, cs->cr, NULL); 2982 7067 marks else 2983 7067 marks error = ((VOP_ACCESS(cs->vp, VREAD, 0, cs->cr, NULL) != 0) && 2984 7067 marks (VOP_ACCESS(cs->