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