xref: /illumos-gate/usr/src/lib/smbclnt/libfksmbfs/common/fake_open.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2017, Joyent, Inc.
25  * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
26  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
27  */
28 
29 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
30 /*	  All Rights Reserved	*/
31 
32 /*
33  * University Copyright- Copyright (c) 1982, 1986, 1988
34  * The Regents of the University of California
35  * All Rights Reserved
36  *
37  * University Acknowledgment- Portions of this document are derived from
38  * software developed by the University of California, Berkeley, and its
39  * contributors.
40  */
41 
42 /*
43  * Portions of code from both of:
44  *	syscall/open.c
45  *	fs/vnode.c
46  * heavily modified for this use.
47  */
48 
49 #include <sys/types.h>
50 #include <sys/param.h>
51 #include <sys/t_lock.h>
52 #include <sys/errno.h>
53 #include <sys/cred.h>
54 #include <sys/user.h>
55 #include <sys/uio.h>
56 #include <sys/file.h>
57 #include <sys/pathname.h>
58 #include <sys/vfs.h>
59 #include <sys/vfs_opreg.h>
60 #include <sys/vnode.h>
61 #include <sys/rwstlock.h>
62 #include <sys/fem.h>
63 #include <sys/stat.h>
64 #include <sys/mode.h>
65 #include <sys/conf.h>
66 #include <sys/sysmacros.h>
67 #include <sys/cmn_err.h>
68 #include <sys/systm.h>
69 #include <sys/kmem.h>
70 #include <sys/debug.h>
71 #include <sys/acl.h>
72 #include <sys/nbmlock.h>
73 #include <sys/fcntl.h>
74 #include <fs/fs_subr.h>
75 #include <sys/taskq.h>
76 #include <fs/fs_reparse.h>
77 #include <sys/time.h>
78 
79 #include <libfksmbfs.h>
80 
81 /* close and release */
82 int
83 vn_close_rele(vnode_t *vp, int flag)
84 {
85 	int error;
86 
87 	error = VOP_CLOSE(vp, flag, 0, 0, CRED(), NULL);
88 	vn_rele(vp);
89 
90 	return (error);
91 }
92 
93 /*
94  * Open/create a vnode.
95  * This may be callable by the kernel, the only known use
96  * of user context being that the current user credentials
97  * are used for permissions.  crwhy is defined iff filemode & FCREAT.
98  */
99 int
100 vn_open(
101 	char *pnamep,
102 	enum uio_seg seg,
103 	int filemode,
104 	int createmode,
105 	struct vnode **vpp,
106 	enum create crwhy,
107 	mode_t umask)
108 {
109 	struct vnode *vp;
110 	int mode;
111 	int accessflags;
112 	int error;
113 	int open_done = 0;
114 	struct vattr vattr;
115 	int estale_retry = 0;
116 
117 	mode = 0;
118 	accessflags = 0;
119 	if (filemode & FREAD)
120 		mode |= VREAD;
121 	if (filemode & (FWRITE|FTRUNC))
122 		mode |= VWRITE;
123 	if (filemode & (FSEARCH|FEXEC|FXATTRDIROPEN))
124 		mode |= VEXEC;
125 
126 	if (filemode & FAPPEND)
127 		accessflags |= V_APPEND;
128 
129 top:
130 	if (filemode & FCREAT) {
131 		enum vcexcl excl;
132 
133 		/*
134 		 * Wish to create a file.
135 		 */
136 		vattr.va_type = VREG;
137 		vattr.va_mode = createmode;
138 		vattr.va_mask = AT_TYPE|AT_MODE;
139 		if (filemode & FTRUNC) {
140 			vattr.va_size = 0;
141 			vattr.va_mask |= AT_SIZE;
142 		}
143 		if (filemode & FEXCL)
144 			excl = EXCL;
145 		else
146 			excl = NONEXCL;
147 
148 		if ((error =
149 		    vn_create(pnamep, seg, &vattr, excl, mode, &vp, crwhy,
150 		    (filemode & ~(FTRUNC|FEXCL)), umask)) != 0)
151 			return (error);
152 	} else {
153 		/*
154 		 * Wish to open a file.  Just look it up.
155 		 * Was lookupnameat()
156 		 */
157 		if ((error = fake_lookup(NULL, pnamep, &vp)) != 0) {
158 			if ((error == ESTALE) &&
159 			    fs_need_estale_retry(estale_retry++))
160 				goto top;
161 			return (error);
162 		}
163 
164 		/*
165 		 * Want the XATTRDIR under it?
166 		 */
167 		if (filemode & FXATTRDIROPEN) {
168 			vnode_t *xvp = NULL;
169 			error = VOP_LOOKUP(vp, NULL, &xvp, NULL,
170 			    LOOKUP_XATTR, rootdir, CRED(), NULL,
171 			    NULL, NULL);
172 			VN_RELE(vp);
173 			vp = xvp;
174 			/* continue with vp */
175 		}
176 
177 		/*
178 		 * Can't write directories, active texts, or
179 		 * read-only filesystems.  Can't truncate files
180 		 * on which mandatory locking is in effect.
181 		 */
182 		if (filemode & (FWRITE|FTRUNC)) {
183 			if (vp->v_type == VDIR) {
184 				error = EISDIR;
185 				goto out;
186 			}
187 		}
188 		/*
189 		 * Check permissions.
190 		 */
191 		if (error = VOP_ACCESS(vp, mode, accessflags, CRED(), NULL))
192 			goto out;
193 		/*
194 		 * Require FSEARCH to return a directory.
195 		 * Require FEXEC to return a regular file.
196 		 */
197 		if ((filemode & FSEARCH) && vp->v_type != VDIR) {
198 			error = ENOTDIR;
199 			goto out;
200 		}
201 		if ((filemode & FEXEC) && vp->v_type != VREG) {
202 			error = ENOEXEC;
203 			goto out;
204 		}
205 	}
206 
207 	/*
208 	 * Do remaining checks for FNOFOLLOW and FNOLINKS.
209 	 */
210 	if ((filemode & FNOFOLLOW) && vp->v_type == VLNK) {
211 		error = ELOOP;
212 		goto out;
213 	}
214 	if (filemode & FNOLINKS) {
215 		vattr.va_mask = AT_NLINK;
216 		if ((error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))) {
217 			goto out;
218 		}
219 		if (vattr.va_nlink != 1) {
220 			error = EMLINK;
221 			goto out;
222 		}
223 	}
224 
225 	/*
226 	 * Opening a socket corresponding to the AF_UNIX pathname
227 	 * in the filesystem name space is not supported...
228 	 */
229 	if (vp->v_type == VSOCK) {
230 		error = EOPNOTSUPP;
231 		goto out;
232 	}
233 
234 	/*
235 	 * Do opening protocol.
236 	 */
237 	error = VOP_OPEN(&vp, filemode, CRED(), NULL);
238 	if (error)
239 		goto out;
240 	open_done = 1;
241 
242 	/*
243 	 * Truncate if required.
244 	 */
245 	if ((filemode & FTRUNC) && !(filemode & FCREAT)) {
246 		vattr.va_size = 0;
247 		vattr.va_mask = AT_SIZE;
248 		if ((error = VOP_SETATTR(vp, &vattr, 0, CRED(), NULL)) != 0)
249 			goto out;
250 	}
251 out:
252 	ASSERT(vp->v_count > 0);
253 
254 	if (error) {
255 		if (open_done) {
256 			(void) VOP_CLOSE(vp, filemode, 1, (offset_t)0, CRED(),
257 			    NULL);
258 			open_done = 0;
259 		}
260 		VN_RELE(vp);
261 	} else
262 		*vpp = vp;
263 	return (error);
264 }
265 
266 
267 /*
268  * Create a vnode (makenode).
269  */
270 int
271 vn_create(
272 	char *pnamep,
273 	enum uio_seg seg,
274 	struct vattr *vap,
275 	enum vcexcl excl,
276 	int mode,
277 	struct vnode **vpp,
278 	enum create why,
279 	int flag,
280 	mode_t umask)
281 {
282 	struct vnode *dvp = NULL;	/* ptr to parent dir vnode */
283 	char *lastcomp = NULL;
284 	int error;
285 
286 	ASSERT((vap->va_mask & (AT_TYPE|AT_MODE)) == (AT_TYPE|AT_MODE));
287 
288 	flag &= ~(FNOFOLLOW|FNOLINKS);
289 
290 	*vpp = NULL;
291 
292 	/*
293 	 * Lookup directory and last component
294 	 */
295 	error = fake_lookup_dir(pnamep, &dvp, &lastcomp);
296 	if (error != 0) {
297 		/* dir not found */
298 		return (error);
299 	}
300 
301 	/*
302 	 * If default ACLs are defined for the directory don't apply the
303 	 * umask if umask is passed.
304 	 */
305 
306 	if (umask) {
307 		/*
308 		 * Apply the umask if no default ACLs...
309 		 */
310 		vap->va_mode &= ~umask;
311 	}
312 
313 	if (dvp->v_vfsp->vfs_flag & VFS_RDONLY) {
314 		error = EROFS;
315 		goto out;
316 	}
317 
318 	/*
319 	 * Call mkdir() if specified, otherwise create().
320 	 */
321 	if (why == CRMKDIR) {
322 		/*
323 		 * N.B., if vn_createat() ever requests
324 		 * case-insensitive behavior then it will need
325 		 * to be passed to VOP_MKDIR().  VOP_CREATE()
326 		 * will already get it via "flag"
327 		 */
328 		error = VOP_MKDIR(dvp, lastcomp, vap, vpp, CRED(),
329 		    NULL, 0, NULL);
330 	} else {
331 		error = VOP_CREATE(dvp, lastcomp, vap,
332 		    excl, mode, vpp, CRED(), flag, NULL, NULL);
333 	}
334 
335 out:
336 	if (dvp != NULL)
337 		VN_RELE(dvp);
338 
339 	return (error);
340 }
341