xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_kshare.c (revision 3ad684d66b78e06edd37e2c4fd3b3949f095194b)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Kernel door client for LanMan share management.
30  */
31 
32 #include <sys/ddi.h>
33 #include <sys/sunddi.h>
34 #include <sys/cmn_err.h>
35 #include <sys/door.h>
36 #include <smbsrv/lmshare.h>
37 #include <smbsrv/lmerr.h>
38 #include <smbsrv/smb_common_door.h>
39 #include <smbsrv/lmshare_door.h>
40 #include <smbsrv/smbinfo.h>
41 
42 static int smb_kshare_chk_dsrv_status(int, smb_dr_ctx_t *);
43 
44 /*
45  * smb_kshare_init
46  *
47  * This function is not MultiThread safe. The caller has to make sure only one
48  * thread calls this function.
49  */
50 door_handle_t
51 smb_kshare_init(int door_id)
52 {
53 	return (door_ki_lookup(door_id));
54 }
55 
56 /*
57  * smb_kshare_fini
58  *
59  * This function is not MultiThread safe. The caller has to make sure only one
60  * thread calls this function.
61  */
62 void
63 smb_kshare_fini(door_handle_t dhdl)
64 {
65 	ASSERT(dhdl != NULL);
66 	if (dhdl)
67 		door_ki_rele(dhdl);
68 }
69 
70 uint32_t
71 smb_kshare_getinfo(door_handle_t dhdl, char *share_name, lmshare_info_t *si)
72 {
73 	door_arg_t arg;
74 	char *buf;
75 	unsigned int used;
76 	smb_dr_ctx_t *dec_ctx;
77 	smb_dr_ctx_t *enc_ctx;
78 	int status;
79 	uint32_t rc;
80 	int opcode = LMSHR_DOOR_GETINFO;
81 
82 	buf = kmem_alloc(LMSHR_DOOR_SIZE, KM_SLEEP);
83 
84 	enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
85 	smb_dr_put_uint32(enc_ctx, opcode);
86 	smb_dr_put_string(enc_ctx, share_name);
87 
88 	if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
89 		cmn_err(CE_WARN, "smb_kshare_getinfo: Encode error %d",
90 		    status);
91 		kmem_free(buf, LMSHR_DOOR_SIZE);
92 		return (NERR_InternalError);
93 	}
94 
95 	arg.data_ptr = buf;
96 	arg.data_size = used;
97 	arg.desc_ptr = NULL;
98 	arg.desc_num = 0;
99 	arg.rbuf = buf;
100 	arg.rsize = LMSHR_DOOR_SIZE;
101 
102 	if (door_ki_upcall(dhdl, &arg) != 0) {
103 		cmn_err(CE_WARN, "smb_kshare_getinfo: Door call failed");
104 		kmem_free(buf, LMSHR_DOOR_SIZE);
105 		return (NERR_InternalError);
106 	}
107 
108 	dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
109 	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
110 		kmem_free(buf, LMSHR_DOOR_SIZE);
111 		return (NERR_InternalError);
112 	}
113 
114 	rc = smb_dr_get_uint32(dec_ctx);
115 	smb_dr_get_lmshare(dec_ctx, si);
116 	if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
117 		cmn_err(CE_WARN, "smb_kshare_getinfo: Decode error %d",
118 		    status);
119 		rc = NERR_InternalError;
120 	}
121 
122 	kmem_free(buf, LMSHR_DOOR_SIZE);
123 	return (rc);
124 }
125 
126 uint32_t
127 smb_kshare_enum(door_handle_t dhdl, smb_enumshare_info_t *enuminfo)
128 {
129 	door_arg_t arg;
130 	char *door_buf;
131 	int door_bufsz;
132 	unsigned int used;
133 	smb_dr_ctx_t *dec_ctx;
134 	smb_dr_ctx_t *enc_ctx;
135 	int status;
136 	uint32_t rc;
137 	int opcode = LMSHR_DOOR_ENUM;
138 
139 	enuminfo->es_ntotal = enuminfo->es_nsent = 0;
140 
141 	door_bufsz = enuminfo->es_bufsize + strlen(enuminfo->es_username)
142 	    + sizeof (smb_enumshare_info_t);
143 	door_buf = kmem_alloc(door_bufsz, KM_SLEEP);
144 
145 	enc_ctx = smb_dr_encode_start(door_buf, door_bufsz);
146 	smb_dr_put_uint32(enc_ctx, opcode);
147 	smb_dr_put_ushort(enc_ctx, enuminfo->es_bufsize);
148 	smb_dr_put_string(enc_ctx, enuminfo->es_username);
149 
150 	if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
151 		cmn_err(CE_WARN, "smb_kshare_enum: Encode error %d", status);
152 		kmem_free(door_buf, door_bufsz);
153 		return (NERR_InternalError);
154 	}
155 
156 	arg.data_ptr = door_buf;
157 	arg.data_size = used;
158 	arg.desc_ptr = NULL;
159 	arg.desc_num = 0;
160 	arg.rbuf = door_buf;
161 	arg.rsize = door_bufsz;
162 
163 	if (door_ki_upcall(dhdl, &arg) != 0) {
164 		cmn_err(CE_WARN, "smb_kshare_enum: Door call failed");
165 		kmem_free(door_buf, door_bufsz);
166 		return (NERR_InternalError);
167 	}
168 
169 	dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
170 	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
171 		kmem_free(door_buf, door_bufsz);
172 		return (NERR_InternalError);
173 	}
174 
175 	rc = smb_dr_get_uint32(dec_ctx);
176 	if (rc == NERR_Success) {
177 		enuminfo->es_ntotal = smb_dr_get_ushort(dec_ctx);
178 		enuminfo->es_nsent = smb_dr_get_ushort(dec_ctx);
179 		enuminfo->es_datasize = smb_dr_get_ushort(dec_ctx);
180 		(void) smb_dr_get_buf(dec_ctx,
181 		    (unsigned char *)enuminfo->es_buf,
182 		    enuminfo->es_bufsize);
183 	}
184 
185 	if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
186 		cmn_err(CE_WARN, "smb_kshare_enum: Decode error %d", status);
187 		rc = NERR_InternalError;
188 	}
189 
190 	kmem_free(door_buf, door_bufsz);
191 	return (rc);
192 }
193 
194 /*
195  * This is a special interface that will be utilized by ZFS to cause
196  * a share to be added/removed
197  *
198  * arg is either a lmshare_info_t or share_name from userspace.
199  * It will need to be copied into the kernel.   It is lmshare_info_t
200  * for add operations and share_name for delete operations.
201  */
202 int
203 smb_kshare_upcall(door_handle_t dhdl, void *arg, boolean_t add_share)
204 {
205 	door_arg_t	doorarg = { 0 };
206 	char		*buf = NULL;
207 	char		*str = NULL;
208 	int		error;
209 	int		rc;
210 	unsigned int	used;
211 	smb_dr_ctx_t	*dec_ctx;
212 	smb_dr_ctx_t	*enc_ctx;
213 	lmshare_info_t	*lmshare = NULL;
214 	int		opcode;
215 
216 	opcode = add_share == B_TRUE ? LMSHR_DOOR_ADD : LMSHR_DOOR_DELETE;
217 
218 	buf = kmem_alloc(LMSHR_DOOR_SIZE, KM_SLEEP);
219 	enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
220 	smb_dr_put_uint32(enc_ctx, opcode);
221 
222 	switch (opcode) {
223 	case LMSHR_DOOR_ADD:
224 		lmshare = kmem_alloc(sizeof (lmshare_info_t), KM_SLEEP);
225 		if (error = xcopyin(arg, lmshare, sizeof (lmshare_info_t))) {
226 			kmem_free(lmshare, sizeof (lmshare_info_t));
227 			kmem_free(buf, LMSHR_DOOR_SIZE);
228 			return (error);
229 		}
230 		smb_dr_put_lmshare(enc_ctx, lmshare);
231 		break;
232 
233 	case LMSHR_DOOR_DELETE:
234 		str = kmem_alloc(MAXPATHLEN, KM_SLEEP);
235 		if (error = copyinstr(arg, str, MAXPATHLEN, NULL)) {
236 			kmem_free(str, MAXPATHLEN);
237 			kmem_free(buf, LMSHR_DOOR_SIZE);
238 			return (error);
239 		}
240 		smb_dr_put_string(enc_ctx, str);
241 		kmem_free(str, MAXPATHLEN);
242 		break;
243 	}
244 
245 	if ((error = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
246 		kmem_free(buf, LMSHR_DOOR_SIZE);
247 		if (lmshare)
248 			kmem_free(lmshare, sizeof (lmshare_info_t));
249 		return (NERR_InternalError);
250 	}
251 
252 	doorarg.data_ptr = buf;
253 	doorarg.data_size = used;
254 	doorarg.rbuf = buf;
255 	doorarg.rsize = LMSHR_DOOR_SIZE;
256 
257 	error = door_ki_upcall(dhdl, &doorarg);
258 
259 	if (error) {
260 		kmem_free(buf, LMSHR_DOOR_SIZE);
261 		if (lmshare)
262 			kmem_free(lmshare, sizeof (lmshare_info_t));
263 		return (error);
264 	}
265 
266 	dec_ctx = smb_dr_decode_start(doorarg.data_ptr, doorarg.data_size);
267 	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
268 		kmem_free(buf, LMSHR_DOOR_SIZE);
269 		if (lmshare)
270 			kmem_free(lmshare, sizeof (lmshare_info_t));
271 		return (NERR_InternalError);
272 	}
273 
274 	rc = smb_dr_get_uint32(dec_ctx);
275 	if (opcode == LMSHR_DOOR_ADD)
276 		smb_dr_get_lmshare(dec_ctx, lmshare);
277 
278 	if (smb_dr_decode_finish(dec_ctx))
279 		rc = NERR_InternalError;
280 
281 	kmem_free(buf, LMSHR_DOOR_SIZE);
282 	if (lmshare)
283 		kmem_free(lmshare, sizeof (lmshare_info_t));
284 
285 	return ((rc == NERR_DuplicateShare && add_share) ? 0 : rc);
286 }
287 
288 /*
289  * Return 0 upon success. Otherwise > 0
290  */
291 static int
292 smb_kshare_chk_dsrv_status(int opcode, smb_dr_ctx_t *dec_ctx)
293 {
294 	int status = smb_dr_get_int32(dec_ctx);
295 	int err;
296 
297 	switch (status) {
298 	case LMSHR_DOOR_SRV_SUCCESS:
299 		return (0);
300 
301 	case LMSHR_DOOR_SRV_ERROR:
302 		err = smb_dr_get_uint32(dec_ctx);
303 		cmn_err(CE_WARN, "%d: Encountered door server error %d",
304 		    opcode, err);
305 		(void) smb_dr_decode_finish(dec_ctx);
306 		return (err);
307 	}
308 
309 	ASSERT(0);
310 	return (EINVAL);
311 }
312