xref: /illumos-gate/usr/src/lib/libsmbfs/smb/file.c (revision d656abb5804319b33c85955a73ee450ef7ff9739)
1 /*
2  * Copyright (c) 2000, Boris Popov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *    This product includes software developed by Boris Popov.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $Id: file.c,v 1.4 2004/12/13 00:25:21 lindak Exp $
33  */
34 
35 /*
36  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37  * Use is subject to license terms.
38  */
39 
40 #include <sys/param.h>
41 #include <sys/ioctl.h>
42 #include <sys/time.h>
43 #include <sys/mount.h>
44 #include <fcntl.h>
45 #include <ctype.h>
46 #include <errno.h>
47 #include <stdio.h>
48 #include <string.h>
49 #include <strings.h>
50 #include <stdlib.h>
51 #include <pwd.h>
52 #include <grp.h>
53 #include <unistd.h>
54 #include <libintl.h>
55 
56 #include <sys/types.h>
57 #include <sys/file.h>
58 
59 #include <netsmb/smb_lib.h>
60 #include <cflib.h>
61 
62 #include "charsets.h"
63 #include "private.h"
64 
65 int
66 smb_fh_close(struct smb_ctx *ctx, smbfh fh)
67 {
68 	struct smb_rq	*rqp;
69 	struct mbdata	*mbp;
70 	int serr;
71 
72 	serr = smb_rq_init(ctx, SMB_COM_CLOSE, 0, &rqp);
73 	if (serr != 0)
74 		return (serr);
75 	mbp = smb_rq_getrequest(rqp);
76 	mb_put_uint16le(mbp, fh);
77 	mb_put_uint32le(mbp, 0);	/* time stamp */
78 	smb_rq_wend(rqp);
79 	serr = smb_rq_simple(rqp);
80 	if (serr != 0) {
81 		smb_rq_done(rqp);
82 		return (serr);
83 	}
84 	mbp = smb_rq_getreply(rqp);
85 	smb_rq_done(rqp);
86 
87 	return (serr);
88 }
89 
90 int
91 smb_fh_ntcreate(
92 	struct smb_ctx *ctx, char *path,
93 	int flags, int req_acc, int efattr,
94 	int share_acc, int open_disp,
95 	int create_opts, int impersonation,
96 	smbfh *fhp, uint32_t *action_taken)
97 {
98 	struct smb_rq	*rqp;
99 	struct mbdata	*mbp;
100 	uint8_t		wc;
101 	size_t		pathlen, pathsize;
102 	int		error, flags2;
103 	uint16_t	*upath = NULL;
104 
105 	flags2 = smb_ctx_flags2(ctx);
106 	if (flags2 == -1)
107 		return (EIO);
108 
109 	error = smb_rq_init(ctx, SMB_COM_NT_CREATE_ANDX, 42, &rqp);
110 	if (error != 0)
111 		return (error);
112 
113 	if (flags2 & SMB_FLAGS2_UNICODE) {
114 		upath = convert_utf8_to_leunicode(path);
115 		if (upath == NULL) {
116 			smb_error(dgettext(TEXT_DOMAIN,
117 			    "%s: failed converting to UCS-2"), 0, path);
118 			error = EINVAL;
119 			goto out;
120 		}
121 		pathlen = unicode_strlen(upath);
122 		pathsize = (pathlen + 1) * 2;
123 	} else {
124 		pathlen = strlen(path);
125 		pathsize = pathlen + 1;
126 	}
127 
128 	mbp = smb_rq_getrequest(rqp);
129 	mb_put_uint8(mbp, 0xff);	/* secondary command */
130 	mb_put_uint8(mbp, 0);		/* MBZ */
131 	mb_put_uint16le(mbp, 0);	/* offset to next command (none) */
132 	mb_put_uint8(mbp, 0);		/* MBZ */
133 	mb_put_uint16le(mbp, pathsize);	/* path size (bytes) */
134 	mb_put_uint32le(mbp, 0);	/* create flags (oplock) */
135 	mb_put_uint32le(mbp, 0);	/* FID - basis for path if not root */
136 	mb_put_uint32le(mbp, req_acc);
137 	mb_put_uint64le(mbp, 0);		/* initial alloc. size */
138 	mb_put_uint32le(mbp, efattr);		/* ext. file attributes */
139 	mb_put_uint32le(mbp, share_acc);	/* share access mode */
140 	mb_put_uint32le(mbp, open_disp);	/* open disposition */
141 	mb_put_uint32le(mbp, create_opts);  /* create_options */
142 	mb_put_uint32le(mbp, NTCREATEX_IMPERSONATION_IMPERSONATION); /* (?) */
143 	mb_put_uint8(mbp, 0);	/* security flags (?) */
144 	smb_rq_wend(rqp);
145 
146 	/* XXX: Need a "put string" function. */
147 	if (flags2 & SMB_FLAGS2_UNICODE) {
148 		mb_put_uint8(mbp, 0);	/* pad byte - align(2) for Unicode */
149 		mb_put_mem(mbp, (char *)upath, pathsize);
150 	} else
151 		mb_put_mem(mbp, path, pathsize);
152 
153 	error = smb_rq_simple(rqp);
154 	if (error)
155 		goto out;
156 
157 	mbp = smb_rq_getreply(rqp);
158 	/*
159 	 * spec says 26 for word count, but 34 words are defined
160 	 * and observed from win2000
161 	 */
162 	wc = rqp->rq_wcount;
163 	if (wc < 26) {
164 		smb_error(dgettext(TEXT_DOMAIN,
165 		    "%s: open failed, bad word count"), 0, path);
166 		error = EBADRPC;
167 		goto out;
168 	}
169 	mb_get_uint8(mbp, NULL);	/* secondary cmd */
170 	mb_get_uint8(mbp, NULL);	/* mbz */
171 	mb_get_uint16le(mbp, NULL);	/* andxoffset */
172 	mb_get_uint8(mbp, NULL);	/* oplock lvl granted */
173 	mb_get_uint16le(mbp, fhp);	/* FID */
174 	mb_get_uint32le(mbp, action_taken);
175 #if 0	/* skip decoding the rest */
176 	mb_get_uint64le(mbp, NULL);	/* creation time */
177 	mb_get_uint64le(mbp, NULL);	/* access time */
178 	mb_get_uint64le(mbp, NULL);	/* write time */
179 	mb_get_uint64le(mbp, NULL);	/* change time */
180 	mb_get_uint32le(mbp, NULL);	/* attributes */
181 	mb_get_uint64le(mbp, NULL);	/* allocation size */
182 	mb_get_uint64le(mbp, NULL);	/* EOF */
183 	mb_get_uint16le(mbp, NULL);	/* file type */
184 	mb_get_uint16le(mbp, NULL);	/* device state */
185 	mb_get_uint8(mbp, NULL);	/* directory (boolean) */
186 #endif	/* skip decoding */
187 
188 out:
189 	if (upath)
190 		free(upath);
191 	smb_rq_done(rqp);
192 
193 	return (0);
194 }
195 
196 /*
197  * Conveinence wrapper for smb_fh_ntcreate
198  * Converts Unix-style open call to NTCreate.
199  */
200 int
201 smb_fh_open(struct smb_ctx *ctx, const char *path, int oflag, smbfh *fhp)
202 {
203 	int error, mode, open_disp, req_acc, share_acc;
204 	char *p, *ntpath = NULL;
205 
206 	/*
207 	 * Map O_RDONLY, O_WRONLY, O_RDWR
208 	 * to FREAD, FWRITE
209 	 */
210 	mode = (oflag & 3) + 1;
211 
212 	/*
213 	 * Compute requested access, share access.
214 	 */
215 	req_acc = (
216 	    STD_RIGHT_READ_CONTROL_ACCESS |
217 	    STD_RIGHT_SYNCHRONIZE_ACCESS);
218 	share_acc = NTCREATEX_SHARE_ACCESS_NONE;
219 	if (mode & FREAD) {
220 		req_acc |= (
221 		    SA_RIGHT_FILE_READ_DATA |
222 		    SA_RIGHT_FILE_READ_EA |
223 		    SA_RIGHT_FILE_READ_ATTRIBUTES);
224 		share_acc |= NTCREATEX_SHARE_ACCESS_READ;
225 	}
226 	if (mode & FWRITE) {
227 		req_acc |= (
228 		    SA_RIGHT_FILE_WRITE_DATA |
229 		    SA_RIGHT_FILE_APPEND_DATA |
230 		    SA_RIGHT_FILE_WRITE_EA |
231 		    SA_RIGHT_FILE_WRITE_ATTRIBUTES);
232 		share_acc |= NTCREATEX_SHARE_ACCESS_WRITE;
233 	}
234 
235 	/*
236 	 * Compute open disposition
237 	 */
238 	if (oflag & FCREAT) {
239 		/* Creat if necessary. */
240 		if (oflag & FEXCL) {
241 			/* exclusive */
242 			open_disp = NTCREATEX_DISP_CREATE;
243 		} else if (oflag & FTRUNC)
244 			open_disp = NTCREATEX_DISP_OVERWRITE_IF;
245 		else
246 			open_disp = NTCREATEX_DISP_OPEN_IF;
247 	} else {
248 		/* Not creating. */
249 		if (oflag & FTRUNC)
250 			open_disp = NTCREATEX_DISP_OVERWRITE;
251 		else
252 			open_disp = NTCREATEX_DISP_OPEN;
253 	}
254 
255 	/*
256 	 * Convert Unix path to NT (backslashes)
257 	 */
258 	ntpath = strdup(path);
259 	if (ntpath == NULL)
260 		return (ENOMEM);
261 	for (p = ntpath; *p; p++)
262 		if (*p == '/')
263 			*p = '\\';
264 
265 	error = smb_fh_ntcreate(ctx, ntpath, 0, /* flags */
266 	    req_acc, SMB_EFA_NORMAL, share_acc, open_disp,
267 	    NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
268 	    NTCREATEX_IMPERSONATION_IMPERSONATION,
269 	    fhp, NULL);
270 	free(ntpath);
271 
272 	return (error);
273 }
274 
275 int
276 smb_fh_read(struct smb_ctx *ctx, smbfh fh, off_t offset, size_t count,
277 	char *dst)
278 {
279 	struct smbioc_rw rwrq;
280 
281 	bzero(&rwrq, sizeof (rwrq));
282 	rwrq.ioc_fh = fh;
283 	rwrq.ioc_base = dst;
284 	rwrq.ioc_cnt = count;
285 	rwrq.ioc_offset = offset;
286 	if (ioctl(ctx->ct_fd, SMBIOC_READ, &rwrq) == -1) {
287 		return (-1);
288 	}
289 	return (rwrq.ioc_cnt);
290 }
291 
292 int
293 smb_fh_write(struct smb_ctx *ctx, smbfh fh, off_t offset, size_t count,
294 	const char *src)
295 {
296 	struct smbioc_rw rwrq;
297 
298 	bzero(&rwrq, sizeof (rwrq));
299 	rwrq.ioc_fh = fh;
300 	rwrq.ioc_base = (char *)src;
301 	rwrq.ioc_cnt = count;
302 	rwrq.ioc_offset = offset;
303 	if (ioctl(ctx->ct_fd, SMBIOC_WRITE, &rwrq) == -1) {
304 		return (-1);
305 	}
306 	return (rwrq.ioc_cnt);
307 }
308 
309 /*
310  * Do a TRANSACT_NAMED_PIPE, which is basically just a
311  * pipe write and pipe read, all in one round trip.
312  *
313  * tdlen, tdata describe the data to send.
314  * rdlen, rdata on input describe the receive buffer,
315  * and on output *rdlen is the received length.
316  */
317 int
318 smb_fh_xactnp(struct smb_ctx *ctx, smbfh fh,
319 	int tdlen, const char *tdata,	/* transmit */
320 	int *rdlen, char *rdata,	/* receive */
321 	int *more)
322 {
323 	int		err, rparamcnt;
324 	uint16_t	setup[2];
325 
326 	setup[0] = TRANS_TRANSACT_NAMED_PIPE;
327 	setup[1] = fh;
328 	rparamcnt = 0;
329 
330 	err = smb_t2_request(ctx, 2, setup, "\\PIPE\\",
331 	    0, NULL,	/* TX paramcnt, params */
332 	    tdlen, (void *)tdata,
333 	    &rparamcnt, NULL,	/* no RX params */
334 	    rdlen, rdata, more);
335 
336 	if (err)
337 		*rdlen = 0;
338 
339 	return (err);
340 }
341