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 (smb_share_dchk(dec_ctx) != 0) {
228 		(void) smb_dr_decode_finish(dec_ctx);
229 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
230 		return (NERR_InternalError);
231 	}
232 
233 	(void) smb_dr_get_buf(dec_ctx, (unsigned char *)list,
234 	    sizeof (smb_shrlist_t));
235 	if (smb_dr_decode_finish(dec_ctx) != 0) {
236 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
237 		return (NERR_InternalError);
238 	}
239 
240 	smb_share_door_clnt_exit(arg, B_FALSE, NULL);
241 	return (NERR_Success);
242 }
243 
244 int
smb_share_count(void)245 smb_share_count(void)
246 {
247 	door_arg_t *arg;
248 	smb_dr_ctx_t *dec_ctx;
249 	smb_dr_ctx_t *enc_ctx;
250 	uint32_t num_shares;
251 	int rc;
252 
253 	if ((arg = smb_share_door_clnt_enter()) == NULL)
254 		return (-1);
255 
256 	enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE);
257 	smb_dr_put_uint32(enc_ctx, SMB_SHROP_NUM_SHARES);
258 
259 	rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size);
260 	if (rc != 0) {
261 		smb_share_door_clnt_exit(arg, B_FALSE, "encode");
262 		return (-1);
263 	}
264 
265 	if (smb_share_door_call(smb_share_dfd, arg) < 0) {
266 		smb_share_door_clnt_exit(arg, B_TRUE, "door call");
267 		return (-1);
268 	}
269 
270 	dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size);
271 	if (smb_share_dchk(dec_ctx) != 0) {
272 		(void) smb_dr_decode_finish(dec_ctx);
273 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
274 		return (-1);
275 	}
276 
277 	num_shares = smb_dr_get_uint32(dec_ctx);
278 	if (smb_dr_decode_finish(dec_ctx) != 0) {
279 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
280 		return (-1);
281 	}
282 
283 	smb_share_door_clnt_exit(arg, B_FALSE, NULL);
284 	return (num_shares);
285 }
286 
287 uint32_t
smb_share_delete(char * share_name)288 smb_share_delete(char *share_name)
289 {
290 	door_arg_t *arg;
291 	smb_dr_ctx_t *dec_ctx;
292 	smb_dr_ctx_t *enc_ctx;
293 	uint32_t rc;
294 
295 	if ((arg = smb_share_door_clnt_enter()) == NULL)
296 		return (NERR_InternalError);
297 
298 	enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE);
299 	smb_dr_put_uint32(enc_ctx, SMB_SHROP_DELETE);
300 	smb_dr_put_string(enc_ctx, share_name);
301 
302 	rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size);
303 	if (rc != 0) {
304 		smb_share_door_clnt_exit(arg, B_FALSE, "encode");
305 		return (NERR_InternalError);
306 	}
307 
308 	if (smb_share_door_call(smb_share_dfd, arg) < 0) {
309 		smb_share_door_clnt_exit(arg, B_TRUE, "door call");
310 		return (NERR_InternalError);
311 	}
312 
313 	dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size);
314 	if (smb_share_dchk(dec_ctx) != 0) {
315 		(void) smb_dr_decode_finish(dec_ctx);
316 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
317 		return (NERR_InternalError);
318 	}
319 
320 	rc = smb_dr_get_uint32(dec_ctx);
321 	if (smb_dr_decode_finish(dec_ctx) != 0) {
322 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
323 		return (NERR_InternalError);
324 	}
325 
326 	smb_share_door_clnt_exit(arg, B_FALSE, NULL);
327 	return (rc);
328 
329 }
330 
331 uint32_t
smb_share_rename(char * from,char * to)332 smb_share_rename(char *from, char *to)
333 {
334 	door_arg_t *arg;
335 	smb_dr_ctx_t *dec_ctx;
336 	smb_dr_ctx_t *enc_ctx;
337 	uint32_t rc;
338 
339 	if ((arg = smb_share_door_clnt_enter()) == NULL)
340 		return (NERR_InternalError);
341 
342 	enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE);
343 	smb_dr_put_uint32(enc_ctx, SMB_SHROP_RENAME);
344 	smb_dr_put_string(enc_ctx, from);
345 	smb_dr_put_string(enc_ctx, to);
346 
347 	rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size);
348 	if (rc != 0) {
349 		smb_share_door_clnt_exit(arg, B_FALSE, "encode");
350 		return (NERR_InternalError);
351 	}
352 
353 	if (smb_share_door_call(smb_share_dfd, arg) < 0) {
354 		smb_share_door_clnt_exit(arg, B_TRUE, "door call");
355 		return (NERR_InternalError);
356 	}
357 
358 	dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size);
359 	if (smb_share_dchk(dec_ctx) != 0) {
360 		(void) smb_dr_decode_finish(dec_ctx);
361 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
362 		return (NERR_InternalError);
363 	}
364 
365 	rc = smb_dr_get_uint32(dec_ctx);
366 	if (smb_dr_decode_finish(dec_ctx) != 0) {
367 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
368 		return (NERR_InternalError);
369 	}
370 
371 	smb_share_door_clnt_exit(arg, B_FALSE, NULL);
372 	return (rc);
373 }
374 
375 uint32_t
smb_share_create(smb_share_t * si)376 smb_share_create(smb_share_t *si)
377 {
378 	door_arg_t *arg;
379 	smb_dr_ctx_t *dec_ctx;
380 	smb_dr_ctx_t *enc_ctx;
381 	uint32_t rc;
382 
383 	if ((arg = smb_share_door_clnt_enter()) == NULL)
384 		return (NERR_InternalError);
385 
386 	enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE);
387 	smb_dr_put_uint32(enc_ctx, SMB_SHROP_ADD);
388 	smb_dr_put_share(enc_ctx, si);
389 
390 	rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size);
391 	if (rc != 0) {
392 		smb_share_door_clnt_exit(arg, B_FALSE, "encode");
393 		return (NERR_InternalError);
394 	}
395 
396 	if (smb_share_door_call(smb_share_dfd, arg) < 0) {
397 		smb_share_door_clnt_exit(arg, B_TRUE, "door call");
398 		return (NERR_InternalError);
399 	}
400 
401 	dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size);
402 	if (smb_share_dchk(dec_ctx) != 0) {
403 		(void) smb_dr_decode_finish(dec_ctx);
404 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
405 		return (NERR_InternalError);
406 	}
407 
408 	rc = smb_dr_get_uint32(dec_ctx);
409 	smb_dr_get_share(dec_ctx, si);
410 	if (smb_dr_decode_finish(dec_ctx) != 0) {
411 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
412 		return (NERR_InternalError);
413 	}
414 
415 	smb_share_door_clnt_exit(arg, B_FALSE, NULL);
416 	return (rc);
417 }
418 
419 uint32_t
smb_share_modify(smb_share_t * si)420 smb_share_modify(smb_share_t *si)
421 {
422 	door_arg_t *arg;
423 	smb_dr_ctx_t *dec_ctx;
424 	smb_dr_ctx_t *enc_ctx;
425 	uint32_t rc;
426 
427 	if ((arg = smb_share_door_clnt_enter()) == NULL)
428 		return (NERR_InternalError);
429 
430 	enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE);
431 	smb_dr_put_uint32(enc_ctx, SMB_SHROP_MODIFY);
432 	smb_dr_put_share(enc_ctx, si);
433 
434 	rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size);
435 	if (rc != 0) {
436 		smb_share_door_clnt_exit(arg, B_FALSE, "encode");
437 		return (NERR_InternalError);
438 	}
439 
440 	if (smb_share_door_call(smb_share_dfd, arg) < 0) {
441 		smb_share_door_clnt_exit(arg, B_TRUE, "door call");
442 		return (NERR_InternalError);
443 	}
444 
445 	dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size);
446 	if (smb_share_dchk(dec_ctx) != 0) {
447 		(void) smb_dr_decode_finish(dec_ctx);
448 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
449 		return (NERR_InternalError);
450 	}
451 
452 	rc = smb_dr_get_uint32(dec_ctx);
453 	if (smb_dr_decode_finish(dec_ctx) != 0) {
454 		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
455 		return (NERR_InternalError);
456 	}
457 
458 	smb_share_door_clnt_exit(arg, B_FALSE, NULL);
459 	return (rc);
460 }
461