xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_kshare.c (revision c0dd49bdd68c0d758a67d56f07826f3b45cfc664)
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  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 /*
26  * Kernel door client for LanMan share management.
27  */
28 
29 #include <sys/ddi.h>
30 #include <sys/sunddi.h>
31 #include <sys/cmn_err.h>
32 #include <sys/door.h>
33 #include <smbsrv/lmerr.h>
34 #include <smbsrv/smb_share.h>
35 #include <smbsrv/smb_door.h>
36 #include <smbsrv/smbinfo.h>
37 
38 static int smb_kshare_chk_dsrv_status(int, smb_dr_ctx_t *);
39 
40 /*
41  * smb_kshare_init
42  *
43  * This function is not MultiThread safe. The caller has to make sure only one
44  * thread calls this function.
45  */
46 door_handle_t
47 smb_kshare_init(int door_id)
48 {
49 	return (door_ki_lookup(door_id));
50 }
51 
52 /*
53  * smb_kshare_fini
54  *
55  * This function is not MultiThread safe. The caller has to make sure only one
56  * thread calls this function.
57  */
58 void
59 smb_kshare_fini(door_handle_t dhdl)
60 {
61 	if (dhdl)
62 		door_ki_rele(dhdl);
63 }
64 
65 uint32_t
66 smb_kshare_getinfo(door_handle_t dhdl, char *share_name, smb_share_t *si,
67     smb_inaddr_t *ipaddr)
68 {
69 	door_arg_t arg;
70 	char *buf;
71 	unsigned int used;
72 	smb_dr_ctx_t *dec_ctx;
73 	smb_dr_ctx_t *enc_ctx;
74 	uint32_t rc;
75 	int opcode = SMB_SHROP_GETINFO;
76 
77 	buf = kmem_alloc(SMB_SHARE_DSIZE, KM_SLEEP);
78 
79 	enc_ctx = smb_dr_encode_start(buf, SMB_SHARE_DSIZE);
80 	smb_dr_put_uint32(enc_ctx, opcode);
81 	smb_dr_put_string(enc_ctx, share_name);
82 	smb_dr_put_buf(enc_ctx, (uchar_t *)ipaddr, sizeof (smb_inaddr_t));
83 
84 	if (smb_dr_encode_finish(enc_ctx, &used) != 0) {
85 		kmem_free(buf, SMB_SHARE_DSIZE);
86 		return (NERR_InternalError);
87 	}
88 
89 	arg.data_ptr = buf;
90 	arg.data_size = used;
91 	arg.desc_ptr = NULL;
92 	arg.desc_num = 0;
93 	arg.rbuf = buf;
94 	arg.rsize = SMB_SHARE_DSIZE;
95 
96 	if (door_ki_upcall_limited(dhdl, &arg, NULL, SIZE_MAX, 0) != 0) {
97 		kmem_free(buf, SMB_SHARE_DSIZE);
98 		return (NERR_InternalError);
99 	}
100 
101 	dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
102 	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
103 		kmem_free(buf, SMB_SHARE_DSIZE);
104 		return (NERR_InternalError);
105 	}
106 
107 	rc = smb_dr_get_uint32(dec_ctx);
108 	smb_dr_get_share(dec_ctx, si);
109 	if (smb_dr_decode_finish(dec_ctx) != 0)
110 		rc = NERR_InternalError;
111 
112 	kmem_free(buf, SMB_SHARE_DSIZE);
113 	return (rc);
114 }
115 
116 uint32_t
117 smb_kshare_enum(door_handle_t dhdl, smb_enumshare_info_t *enuminfo)
118 {
119 	door_arg_t arg;
120 	char *door_buf;
121 	int door_bufsz;
122 	unsigned int used;
123 	smb_dr_ctx_t *dec_ctx;
124 	smb_dr_ctx_t *enc_ctx;
125 	uint32_t rc;
126 	int opcode = SMB_SHROP_ENUM;
127 
128 	enuminfo->es_ntotal = enuminfo->es_nsent = 0;
129 
130 	door_bufsz = enuminfo->es_bufsize + sizeof (smb_enumshare_info_t);
131 	door_buf = kmem_alloc(door_bufsz, KM_SLEEP);
132 
133 	enc_ctx = smb_dr_encode_start(door_buf, door_bufsz);
134 	smb_dr_put_uint32(enc_ctx, opcode);
135 	smb_dr_put_ushort(enc_ctx, enuminfo->es_bufsize);
136 	smb_dr_put_uint32(enc_ctx, enuminfo->es_posix_uid);
137 
138 	if (smb_dr_encode_finish(enc_ctx, &used) != 0) {
139 		kmem_free(door_buf, door_bufsz);
140 		return (NERR_InternalError);
141 	}
142 
143 	arg.data_ptr = door_buf;
144 	arg.data_size = used;
145 	arg.desc_ptr = NULL;
146 	arg.desc_num = 0;
147 	arg.rbuf = door_buf;
148 	arg.rsize = door_bufsz;
149 
150 	if (door_ki_upcall_limited(dhdl, &arg, NULL, SIZE_MAX, 0) != 0) {
151 		kmem_free(door_buf, door_bufsz);
152 		return (NERR_InternalError);
153 	}
154 
155 	dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
156 	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
157 		kmem_free(door_buf, door_bufsz);
158 		return (NERR_InternalError);
159 	}
160 
161 	rc = smb_dr_get_uint32(dec_ctx);
162 	if (rc == NERR_Success) {
163 		enuminfo->es_ntotal = smb_dr_get_ushort(dec_ctx);
164 		enuminfo->es_nsent = smb_dr_get_ushort(dec_ctx);
165 		enuminfo->es_datasize = smb_dr_get_ushort(dec_ctx);
166 		(void) smb_dr_get_buf(dec_ctx,
167 		    (unsigned char *)enuminfo->es_buf,
168 		    enuminfo->es_bufsize);
169 	}
170 
171 	if (smb_dr_decode_finish(dec_ctx) != 0)
172 		rc = NERR_InternalError;
173 
174 	kmem_free(door_buf, door_bufsz);
175 	return (rc);
176 }
177 
178 /*
179  * Executes map and unmap command for shares.
180  */
181 uint32_t
182 smb_kshare_exec(door_handle_t dhdl, char *sharename, smb_execsub_info_t *subs,
183     int exec_type)
184 {
185 	door_arg_t arg;
186 	char *buf;
187 	int bufsz;
188 	unsigned int used;
189 	smb_dr_ctx_t *dec_ctx;
190 	smb_dr_ctx_t *enc_ctx;
191 	uint32_t rc;
192 	int opcode = SMB_SHROP_EXEC;
193 
194 	bufsz = (2 * sizeof (int)) + strlen(sharename) + strlen(subs->e_winname)
195 	    + strlen(subs->e_userdom) + strlen(subs->e_cli_netbiosname) +
196 	    (2 * sizeof (smb_inaddr_t)) + sizeof (uid_t) +
197 	    sizeof (smb_execsub_info_t);
198 
199 	buf = kmem_alloc(bufsz, KM_SLEEP);
200 
201 	enc_ctx = smb_dr_encode_start(buf, bufsz);
202 	smb_dr_put_uint32(enc_ctx, opcode);
203 	smb_dr_put_string(enc_ctx, sharename);
204 	smb_dr_put_string(enc_ctx, subs->e_winname);
205 	smb_dr_put_string(enc_ctx, subs->e_userdom);
206 	smb_dr_put_buf(enc_ctx, (uchar_t *)&subs->e_srv_ipaddr,
207 	    sizeof (smb_inaddr_t));
208 	smb_dr_put_buf(enc_ctx, (uchar_t *)&subs->e_cli_ipaddr,
209 	    sizeof (smb_inaddr_t));
210 	smb_dr_put_string(enc_ctx, subs->e_cli_netbiosname);
211 	smb_dr_put_int32(enc_ctx, subs->e_uid);
212 	smb_dr_put_int32(enc_ctx, exec_type);
213 
214 	if (smb_dr_encode_finish(enc_ctx, &used) != 0) {
215 		kmem_free(buf, bufsz);
216 		return (NERR_InternalError);
217 	}
218 
219 	arg.data_ptr = buf;
220 	arg.data_size = used;
221 	arg.desc_ptr = NULL;
222 	arg.desc_num = 0;
223 	arg.rbuf = buf;
224 	arg.rsize = bufsz;
225 
226 	if (door_ki_upcall_limited(dhdl, &arg, NULL, SIZE_MAX, 0) != 0) {
227 		kmem_free(buf, bufsz);
228 		return (NERR_InternalError);
229 	}
230 
231 	dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
232 	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
233 		kmem_free(buf, bufsz);
234 		return (NERR_InternalError);
235 	}
236 
237 	rc = smb_dr_get_uint32(dec_ctx);
238 	if (smb_dr_decode_finish(dec_ctx) != 0)
239 		rc = NERR_InternalError;
240 
241 	kmem_free(buf, bufsz);
242 	return (rc);
243 }
244 
245 /*
246  * This is a special interface that will be utilized by ZFS to cause
247  * a share to be added/removed
248  *
249  * arg is either a smb_share_t or share_name from userspace.
250  * It will need to be copied into the kernel.   It is smb_share_t
251  * for add operations and share_name for delete operations.
252  */
253 int
254 smb_kshare_upcall(door_handle_t dhdl, void *arg, boolean_t add_share)
255 {
256 	door_arg_t	doorarg = { 0 };
257 	char		*buf = NULL;
258 	char		*str = NULL;
259 	int		error;
260 	int		rc;
261 	unsigned int	used;
262 	smb_dr_ctx_t	*dec_ctx;
263 	smb_dr_ctx_t	*enc_ctx;
264 	smb_share_t	*lmshare = NULL;
265 	int		opcode;
266 
267 	opcode = (add_share) ? SMB_SHROP_ADD : SMB_SHROP_DELETE;
268 
269 	buf = kmem_alloc(SMB_SHARE_DSIZE, KM_SLEEP);
270 	enc_ctx = smb_dr_encode_start(buf, SMB_SHARE_DSIZE);
271 	smb_dr_put_uint32(enc_ctx, opcode);
272 
273 	switch (opcode) {
274 	case SMB_SHROP_ADD:
275 		lmshare = kmem_alloc(sizeof (smb_share_t), KM_SLEEP);
276 		if (error = xcopyin(arg, lmshare, sizeof (smb_share_t))) {
277 			kmem_free(lmshare, sizeof (smb_share_t));
278 			kmem_free(buf, SMB_SHARE_DSIZE);
279 			return (error);
280 		}
281 		smb_dr_put_share(enc_ctx, lmshare);
282 		break;
283 
284 	case SMB_SHROP_DELETE:
285 		str = kmem_alloc(MAXPATHLEN, KM_SLEEP);
286 		if (error = copyinstr(arg, str, MAXPATHLEN, NULL)) {
287 			kmem_free(str, MAXPATHLEN);
288 			kmem_free(buf, SMB_SHARE_DSIZE);
289 			return (error);
290 		}
291 		smb_dr_put_string(enc_ctx, str);
292 		kmem_free(str, MAXPATHLEN);
293 		break;
294 	}
295 
296 	if ((error = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
297 		kmem_free(buf, SMB_SHARE_DSIZE);
298 		if (lmshare)
299 			kmem_free(lmshare, sizeof (smb_share_t));
300 		return (NERR_InternalError);
301 	}
302 
303 	doorarg.data_ptr = buf;
304 	doorarg.data_size = used;
305 	doorarg.rbuf = buf;
306 	doorarg.rsize = SMB_SHARE_DSIZE;
307 
308 	error = door_ki_upcall_limited(dhdl, &doorarg, NULL, SIZE_MAX, 0);
309 
310 	if (error) {
311 		kmem_free(buf, SMB_SHARE_DSIZE);
312 		if (lmshare)
313 			kmem_free(lmshare, sizeof (smb_share_t));
314 		return (error);
315 	}
316 
317 	dec_ctx = smb_dr_decode_start(doorarg.data_ptr, doorarg.data_size);
318 	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
319 		kmem_free(buf, SMB_SHARE_DSIZE);
320 		if (lmshare)
321 			kmem_free(lmshare, sizeof (smb_share_t));
322 		return (NERR_InternalError);
323 	}
324 
325 	rc = smb_dr_get_uint32(dec_ctx);
326 	if (opcode == SMB_SHROP_ADD)
327 		smb_dr_get_share(dec_ctx, lmshare);
328 
329 	if (smb_dr_decode_finish(dec_ctx))
330 		rc = NERR_InternalError;
331 
332 	kmem_free(buf, SMB_SHARE_DSIZE);
333 	if (lmshare)
334 		kmem_free(lmshare, sizeof (smb_share_t));
335 
336 	return ((rc == NERR_DuplicateShare && add_share) ? 0 : rc);
337 }
338 
339 /*
340  * Return 0 upon success. Otherwise > 0
341  */
342 static int
343 smb_kshare_chk_dsrv_status(int opcode, smb_dr_ctx_t *dec_ctx)
344 {
345 	int status = smb_dr_get_int32(dec_ctx);
346 	int err;
347 
348 	switch (status) {
349 	case SMB_SHARE_DSUCCESS:
350 		return (0);
351 
352 	case SMB_SHARE_DERROR:
353 		err = smb_dr_get_uint32(dec_ctx);
354 		cmn_err(CE_WARN, "%d: Encountered door server error %d",
355 		    opcode, err);
356 		(void) smb_dr_decode_finish(dec_ctx);
357 		return (err);
358 	}
359 
360 	ASSERT(0);
361 	return (EINVAL);
362 }
363