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 /*
23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
25  */
26 
27 /*
28  * User-space door client for LanMan share management.
29  */
30 
31 #include <syslog.h>
32 #include <door.h>
33 #include <fcntl.h>
34 #include <stdarg.h>
35 #include <errno.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <unistd.h>
39 #include <thread.h>
40 #include <synch.h>
41 
42 #include <smbsrv/libsmb.h>
43 #include <smbsrv/smb_share.h>
44 #include <smbsrv/smb.h>
45 
46 #define	SMB_SHARE_DOOR_CALL_RETRIES		3
47 
48 static int smb_share_dfd = -1;
49 static uint64_t smb_share_dncall = 0;
50 static mutex_t smb_share_dmtx;
51 static cond_t smb_share_dcv;
52 
53 static int smb_share_door_clnt_open(void);
54 static void smb_share_door_clnt_close(void);
55 
56 void
smb_share_door_clnt_init(void)57 smb_share_door_clnt_init(void)
58 {
59 	(void) mutex_lock(&smb_share_dmtx);
60 	(void) smb_share_door_clnt_open();
61 	(void) mutex_unlock(&smb_share_dmtx);
62 }
63 
64 void
smb_share_door_clnt_fini(void)65 smb_share_door_clnt_fini(void)
66 {
67 	(void) mutex_lock(&smb_share_dmtx);
68 	smb_share_door_clnt_close();
69 	(void) mutex_unlock(&smb_share_dmtx);
70 }
71 
72 /*
73  * Open smb_share_door.  This is a private call for use by
74  * smb_share_door_clnt_enter() and must be called with smb_share_dmtx held.
75  *
76  * Returns the door fd on success.  Otherwise, -1.
77  */
78 static int
smb_share_door_clnt_open(void)79 smb_share_door_clnt_open(void)
80 {
81 	const char	*door_name;
82 
83 	if (smb_share_dfd == -1) {
84 		door_name = getenv("SMB_SHARE_DNAME");
85 		if (door_name == NULL)
86 			door_name = SMB_SHARE_DNAME;
87 
88 		if ((smb_share_dfd = open(door_name, O_RDONLY)) < 0)
89 			smb_share_dfd = -1;
90 		else
91 			smb_share_dncall = 0;
92 	}
93 
94 	return (smb_share_dfd);
95 }
96 
97 /*
98  * Close smb_share_door.
99  * Private call that must be called with smb_share_dmtx held.
100  */
101 static void
smb_share_door_clnt_close(void)102 smb_share_door_clnt_close(void)
103 {
104 	if (smb_share_dfd != -1) {
105 		while (smb_share_dncall > 0)
106 			(void) cond_wait(&smb_share_dcv, &smb_share_dmtx);
107 
108 		if (smb_share_dfd != -1) {
109 			(void) close(smb_share_dfd);
110 			smb_share_dfd = -1;
111 		}
112 	}
113 }
114 
115 /*
116  * Entry handler for smb_share_door calls.
117  */
118 static door_arg_t *
smb_share_door_clnt_enter(void)119 smb_share_door_clnt_enter(void)
120 {
121 	door_arg_t *arg;
122 	char *buf;
123 
124 	(void) mutex_lock(&smb_share_dmtx);
125 
126 	if (smb_share_door_clnt_open() == -1) {
127 		(void) mutex_unlock(&smb_share_dmtx);
128 		return (NULL);
129 	}
130 
131 	if ((arg = malloc(sizeof (door_arg_t) + SMB_SHARE_DSIZE)) != NULL) {
132 		buf = ((char *)arg) + sizeof (door_arg_t);
133 		bzero(arg, sizeof (door_arg_t));
134 		arg->data_ptr = buf;
135 		arg->rbuf = buf;
136 		arg->rsize = SMB_SHARE_DSIZE;
137 
138 		++smb_share_dncall;
139 	}
140 
141 	(void) mutex_unlock(&smb_share_dmtx);
142 	return (arg);
143 }
144 
145 /*
146  * Exit handler for smb_share_door calls.
147  */
148 static void
smb_share_door_clnt_exit(door_arg_t * arg,boolean_t must_close,char * errmsg)149 smb_share_door_clnt_exit(door_arg_t *arg, boolean_t must_close, char *errmsg)
150 {
151 	if (errmsg)
152 		syslog(LOG_DEBUG, "smb_share_door: %s failed", errmsg);
153 
154 	(void) mutex_lock(&smb_share_dmtx);
155 	free(arg);
156 	--smb_share_dncall;
157 	(void) cond_signal(&smb_share_dcv);
158 
159 	if (must_close)
160 		smb_share_door_clnt_close();
161 
162 	(void) mutex_unlock(&smb_share_dmtx);
163 }
164 
165 static int
smb_share_door_call(int fd,door_arg_t * arg)166 smb_share_door_call(int fd, door_arg_t *arg)
167 {
168 	int rc;
169 	int i;
170 
171 	for (i = 0; i < SMB_SHARE_DOOR_CALL_RETRIES; ++i) {
172 		errno = 0;
173 
174 		if ((rc = door_call(fd, arg)) == 0)
175 			break;
176 
177 		if (errno != EAGAIN && errno != EINTR)
178 			break;
179 	}
180 
181 	return (rc);
182 }
183 
184 static int
smb_share_dchk(smb_dr_ctx_t * dec_ctx)185 smb_share_dchk(smb_dr_ctx_t *dec_ctx)
186 {
187 	int status = smb_dr_get_int32(dec_ctx);
188 
189 	if (status != SMB_SHARE_DSUCCESS) {
190 		if (status == SMB_SHARE_DERROR)
191 			(void) smb_dr_get_uint32(dec_ctx);
192 		return (-1);
193 	}
194 
195 	return (0);
196 }
197 
198 uint32_t
smb_share_list(int offset,smb_shrlist_t * list)199 smb_share_list(int offset, smb_shrlist_t *list)
200 {
201 	door_arg_t *arg;
202 	smb_dr_ctx_t *dec_ctx;
203 	smb_dr_ctx_t *enc_ctx;
204 	uint32_t rc;
205 
206 	bzero(list, sizeof (smb_shrlist_t));
207 
208 	if ((arg = smb_share_door_clnt_enter()) == NULL)
209 		return (NERR_InternalError);
210 
211 	enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE);
212 	smb_dr_put_uint32(enc_ctx, SMB_SHROP_LIST);
213 	smb_dr_put_int32(enc_ctx, offset);
214 
215 	rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size);
216 	if (rc != 0) {
217 		smb_share_door_clnt_exit(arg, B_FALSE, "encode");
218 		return (NERR_InternalError);
219 	}
220 
221 	if (smb_share_door_call(smb_share_dfd, arg) < 0) {
222 		smb_share_door_clnt_exit(arg, B_TRUE, "door call");
223 		return (NERR_InternalError);
224 	}
225 
226 	dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size);
227 	if (dec_ctx == NULL || smb_share_dchk(dec_ctx) != 0) {
228 		if (dec_ctx != NULL)
229 			(void) smb_dr_decode_finish(dec_ctx);
230 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
231 		return (NERR_InternalError);
232 	}
233 
234 	(void) smb_dr_get_buf(dec_ctx, (unsigned char *)list,
235 	    sizeof (smb_shrlist_t));
236 	if (smb_dr_decode_finish(dec_ctx) != 0) {
237 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
238 		return (NERR_InternalError);
239 	}
240 
241 	smb_share_door_clnt_exit(arg, B_FALSE, NULL);
242 	return (NERR_Success);
243 }
244 
245 int
smb_share_count(void)246 smb_share_count(void)
247 {
248 	door_arg_t *arg;
249 	smb_dr_ctx_t *dec_ctx;
250 	smb_dr_ctx_t *enc_ctx;
251 	uint32_t num_shares;
252 	int rc;
253 
254 	if ((arg = smb_share_door_clnt_enter()) == NULL)
255 		return (-1);
256 
257 	enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE);
258 	smb_dr_put_uint32(enc_ctx, SMB_SHROP_NUM_SHARES);
259 
260 	rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size);
261 	if (rc != 0) {
262 		smb_share_door_clnt_exit(arg, B_FALSE, "encode");
263 		return (-1);
264 	}
265 
266 	if (smb_share_door_call(smb_share_dfd, arg) < 0) {
267 		smb_share_door_clnt_exit(arg, B_TRUE, "door call");
268 		return (-1);
269 	}
270 
271 	dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size);
272 	if (dec_ctx == NULL || smb_share_dchk(dec_ctx) != 0) {
273 		if (dec_ctx != NULL)
274 			(void) smb_dr_decode_finish(dec_ctx);
275 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
276 		return (-1);
277 	}
278 
279 	num_shares = smb_dr_get_uint32(dec_ctx);
280 	if (smb_dr_decode_finish(dec_ctx) != 0) {
281 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
282 		return (-1);
283 	}
284 
285 	smb_share_door_clnt_exit(arg, B_FALSE, NULL);
286 	return (num_shares);
287 }
288 
289 uint32_t
smb_share_delete(char * share_name)290 smb_share_delete(char *share_name)
291 {
292 	door_arg_t *arg;
293 	smb_dr_ctx_t *dec_ctx;
294 	smb_dr_ctx_t *enc_ctx;
295 	uint32_t rc;
296 
297 	if ((arg = smb_share_door_clnt_enter()) == NULL)
298 		return (NERR_InternalError);
299 
300 	enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE);
301 	smb_dr_put_uint32(enc_ctx, SMB_SHROP_DELETE);
302 	smb_dr_put_string(enc_ctx, share_name);
303 
304 	rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size);
305 	if (rc != 0) {
306 		smb_share_door_clnt_exit(arg, B_FALSE, "encode");
307 		return (NERR_InternalError);
308 	}
309 
310 	if (smb_share_door_call(smb_share_dfd, arg) < 0) {
311 		smb_share_door_clnt_exit(arg, B_TRUE, "door call");
312 		return (NERR_InternalError);
313 	}
314 
315 	dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size);
316 	if (dec_ctx == NULL || smb_share_dchk(dec_ctx) != 0) {
317 		if (dec_ctx != NULL)
318 			(void) smb_dr_decode_finish(dec_ctx);
319 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
320 		return (NERR_InternalError);
321 	}
322 
323 	rc = smb_dr_get_uint32(dec_ctx);
324 	if (smb_dr_decode_finish(dec_ctx) != 0) {
325 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
326 		return (NERR_InternalError);
327 	}
328 
329 	smb_share_door_clnt_exit(arg, B_FALSE, NULL);
330 	return (rc);
331 
332 }
333 
334 uint32_t
smb_share_rename(char * from,char * to)335 smb_share_rename(char *from, char *to)
336 {
337 	door_arg_t *arg;
338 	smb_dr_ctx_t *dec_ctx;
339 	smb_dr_ctx_t *enc_ctx;
340 	uint32_t rc;
341 
342 	if ((arg = smb_share_door_clnt_enter()) == NULL)
343 		return (NERR_InternalError);
344 
345 	enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE);
346 	smb_dr_put_uint32(enc_ctx, SMB_SHROP_RENAME);
347 	smb_dr_put_string(enc_ctx, from);
348 	smb_dr_put_string(enc_ctx, to);
349 
350 	rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size);
351 	if (rc != 0) {
352 		smb_share_door_clnt_exit(arg, B_FALSE, "encode");
353 		return (NERR_InternalError);
354 	}
355 
356 	if (smb_share_door_call(smb_share_dfd, arg) < 0) {
357 		smb_share_door_clnt_exit(arg, B_TRUE, "door call");
358 		return (NERR_InternalError);
359 	}
360 
361 	dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size);
362 	if (dec_ctx == NULL || smb_share_dchk(dec_ctx) != 0) {
363 		if (dec_ctx != NULL)
364 			(void) smb_dr_decode_finish(dec_ctx);
365 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
366 		return (NERR_InternalError);
367 	}
368 
369 	rc = smb_dr_get_uint32(dec_ctx);
370 	if (smb_dr_decode_finish(dec_ctx) != 0) {
371 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
372 		return (NERR_InternalError);
373 	}
374 
375 	smb_share_door_clnt_exit(arg, B_FALSE, NULL);
376 	return (rc);
377 }
378 
379 uint32_t
smb_share_create(smb_share_t * si)380 smb_share_create(smb_share_t *si)
381 {
382 	door_arg_t *arg;
383 	smb_dr_ctx_t *dec_ctx;
384 	smb_dr_ctx_t *enc_ctx;
385 	uint32_t rc;
386 
387 	if ((arg = smb_share_door_clnt_enter()) == NULL)
388 		return (NERR_InternalError);
389 
390 	enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE);
391 	smb_dr_put_uint32(enc_ctx, SMB_SHROP_ADD);
392 	smb_dr_put_share(enc_ctx, si);
393 
394 	rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size);
395 	if (rc != 0) {
396 		smb_share_door_clnt_exit(arg, B_FALSE, "encode");
397 		return (NERR_InternalError);
398 	}
399 
400 	if (smb_share_door_call(smb_share_dfd, arg) < 0) {
401 		smb_share_door_clnt_exit(arg, B_TRUE, "door call");
402 		return (NERR_InternalError);
403 	}
404 
405 	dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size);
406 	if (dec_ctx == NULL || smb_share_dchk(dec_ctx) != 0) {
407 		if (dec_ctx != NULL)
408 			(void) smb_dr_decode_finish(dec_ctx);
409 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
410 		return (NERR_InternalError);
411 	}
412 
413 	rc = smb_dr_get_uint32(dec_ctx);
414 	smb_dr_get_share(dec_ctx, si);
415 	if (smb_dr_decode_finish(dec_ctx) != 0) {
416 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
417 		return (NERR_InternalError);
418 	}
419 
420 	smb_share_door_clnt_exit(arg, B_FALSE, NULL);
421 	return (rc);
422 }
423 
424 uint32_t
smb_share_modify(smb_share_t * si)425 smb_share_modify(smb_share_t *si)
426 {
427 	door_arg_t *arg;
428 	smb_dr_ctx_t *dec_ctx;
429 	smb_dr_ctx_t *enc_ctx;
430 	uint32_t rc;
431 
432 	if ((arg = smb_share_door_clnt_enter()) == NULL)
433 		return (NERR_InternalError);
434 
435 	enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE);
436 	smb_dr_put_uint32(enc_ctx, SMB_SHROP_MODIFY);
437 	smb_dr_put_share(enc_ctx, si);
438 
439 	rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size);
440 	if (rc != 0) {
441 		smb_share_door_clnt_exit(arg, B_FALSE, "encode");
442 		return (NERR_InternalError);
443 	}
444 
445 	if (smb_share_door_call(smb_share_dfd, arg) < 0) {
446 		smb_share_door_clnt_exit(arg, B_TRUE, "door call");
447 		return (NERR_InternalError);
448 	}
449 
450 	dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size);
451 	if (dec_ctx == NULL || smb_share_dchk(dec_ctx) != 0) {
452 		if (dec_ctx != NULL)
453 			(void) smb_dr_decode_finish(dec_ctx);
454 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
455 		return (NERR_InternalError);
456 	}
457 
458 	rc = smb_dr_get_uint32(dec_ctx);
459 	if (smb_dr_decode_finish(dec_ctx) != 0) {
460 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
461 		return (NERR_InternalError);
462 	}
463 
464 	smb_share_door_clnt_exit(arg, B_FALSE, NULL);
465 	return (rc);
466 }
467