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