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