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 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * User-space door client for LanMan share management.
31  */
32 
33 #include <syslog.h>
34 #include <door.h>
35 #include <fcntl.h>
36 #include <stdarg.h>
37 #include <errno.h>
38 #include <string.h>
39 #include <strings.h>
40 #include <unistd.h>
41 #include <thread.h>
42 #include <synch.h>
43 
44 #include <smbsrv/libsmb.h>
45 #include <smbsrv/lmshare.h>
46 #include <smbsrv/lmerr.h>
47 #include <smbsrv/lmshare_door.h>
48 #include <smbsrv/cifs.h>
49 
50 static int lmshrd_fildes = -1;
51 static uint64_t lmshrd_door_ncall = 0;
52 static mutex_t lmshrd_mutex;
53 static cond_t lmshrd_cv;
54 
55 char *lmshrd_desc[] = {
56 	"",
57 	"LmshrdNumShares",
58 	"LmshrdDelete",
59 	"LmshrdRename",
60 	"LmshrdGetinfo",
61 	"LmshrdAdd",
62 	"LmshrdSetinfo",
63 	"LmshrdExists",
64 	"LmshrdIsSpecial",
65 	"LmshrdIsRestricted",
66 	"LmshrdIsAdmin",
67 	"LmshrdIsValid",
68 	"LmshrdIsDir",
69 	"LmshrdList",
70 	"LmshrdNumTrans",
71 	"N/A",
72 	0
73 };
74 
75 /*
76  * Open the lmshrd door.  This is a private call for use by
77  * lmshrd_door_enter() and must be called with lmshrd_mutex held.
78  *
79  * Returns the door fd on success.  Otherwise, -1.
80  */
81 static int
82 lmshrd_door_open(void)
83 {
84 	if (lmshrd_fildes == -1) {
85 		if ((lmshrd_fildes = open(LMSHR_DOOR_NAME, O_RDONLY)) < 0)
86 			lmshrd_fildes = -1;
87 		else
88 			lmshrd_door_ncall = 0;
89 	}
90 
91 	return (lmshrd_fildes);
92 }
93 
94 /*
95  * Close the lmshrd door.
96  */
97 void
98 lmshrd_door_close(void)
99 {
100 	(void) mutex_lock(&lmshrd_mutex);
101 
102 	if (lmshrd_fildes != -1) {
103 		while (lmshrd_door_ncall > 0)
104 			(void) cond_wait(&lmshrd_cv, &lmshrd_mutex);
105 
106 		if (lmshrd_fildes != -1) {
107 			(void) close(lmshrd_fildes);
108 			lmshrd_fildes = -1;
109 		}
110 	}
111 
112 	(void) mutex_unlock(&lmshrd_mutex);
113 }
114 
115 /*
116  * Entry handler for lmshrd door calls.
117  */
118 static door_arg_t *
119 lmshrd_door_enter(void)
120 {
121 	door_arg_t *arg;
122 	char *buf;
123 
124 	(void) mutex_lock(&lmshrd_mutex);
125 
126 	if (lmshrd_door_open() == -1) {
127 		(void) mutex_unlock(&lmshrd_mutex);
128 		return (NULL);
129 	}
130 
131 	if ((arg = malloc(sizeof (door_arg_t) + LMSHR_DOOR_SIZE)) != 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 = LMSHR_DOOR_SIZE;
137 
138 		++lmshrd_door_ncall;
139 	}
140 
141 	(void) mutex_unlock(&lmshrd_mutex);
142 	return (arg);
143 }
144 
145 /*
146  * Exit handler for lmshrd door calls.
147  */
148 static void
149 lmshrd_door_exit(door_arg_t *arg, char *errmsg)
150 {
151 	if (errmsg)
152 		syslog(LOG_DEBUG, "lmshrd_door: %s", errmsg);
153 
154 	(void) mutex_lock(&lmshrd_mutex);
155 	free(arg);
156 	--lmshrd_door_ncall;
157 	(void) cond_signal(&lmshrd_cv);
158 	(void) mutex_unlock(&lmshrd_mutex);
159 }
160 
161 /*
162  * Return 0 upon success. Otherwise, -1.
163  */
164 static int
165 lmshrd_door_check_status(smb_dr_ctx_t *dec_ctx)
166 {
167 	int status = smb_dr_get_int32(dec_ctx);
168 
169 	if (status != LMSHR_DOOR_SRV_SUCCESS) {
170 		if (status == LMSHR_DOOR_SRV_ERROR)
171 			(void) smb_dr_get_uint32(dec_ctx);
172 		return (-1);
173 	}
174 
175 	return (0);
176 }
177 
178 DWORD
179 lmshrd_list(int offset, lmshare_list_t *list)
180 {
181 	door_arg_t *arg;
182 	smb_dr_ctx_t *dec_ctx;
183 	smb_dr_ctx_t *enc_ctx;
184 	DWORD rc;
185 
186 	if ((arg = lmshrd_door_enter()) == NULL)
187 		return (NERR_InternalError);
188 
189 	enc_ctx = smb_dr_encode_start(arg->data_ptr, LMSHR_DOOR_SIZE);
190 	smb_dr_put_uint32(enc_ctx, LMSHR_DOOR_LIST);
191 	smb_dr_put_int32(enc_ctx, offset);
192 
193 	rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size);
194 	if (rc != 0) {
195 		lmshrd_door_exit(arg, "encode error");
196 		return (NERR_InternalError);
197 	}
198 
199 	if (door_call(lmshrd_fildes, arg) < 0) {
200 		lmshrd_door_exit(arg, "door call error");
201 		lmshrd_door_close();
202 		return (NERR_InternalError);
203 	}
204 
205 	dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size);
206 	if (lmshrd_door_check_status(dec_ctx) != 0) {
207 		(void) smb_dr_decode_finish(dec_ctx);
208 		lmshrd_door_exit(arg, "decode error");
209 		return (NERR_InternalError);
210 	}
211 
212 	smb_dr_get_lmshr_list(dec_ctx, list);
213 	if (smb_dr_decode_finish(dec_ctx) != 0) {
214 		lmshrd_door_exit(arg, "decode error");
215 		return (NERR_InternalError);
216 	}
217 
218 	lmshrd_door_exit(arg, NULL);
219 	return (NERR_Success);
220 }
221 
222 int
223 lmshrd_num_shares(void)
224 {
225 	door_arg_t *arg;
226 	smb_dr_ctx_t *dec_ctx;
227 	smb_dr_ctx_t *enc_ctx;
228 	DWORD num_shares;
229 	int rc;
230 
231 	if ((arg = lmshrd_door_enter()) == NULL)
232 		return (-1);
233 
234 	enc_ctx = smb_dr_encode_start(arg->data_ptr, LMSHR_DOOR_SIZE);
235 	smb_dr_put_uint32(enc_ctx, LMSHR_DOOR_NUM_SHARES);
236 
237 	rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size);
238 	if (rc != 0) {
239 		lmshrd_door_exit(arg, "encode error");
240 		return (-1);
241 	}
242 
243 	if (door_call(lmshrd_fildes, arg) < 0) {
244 		lmshrd_door_exit(arg, "door call error");
245 		lmshrd_door_close();
246 		return (-1);
247 	}
248 
249 	dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size);
250 	if (lmshrd_door_check_status(dec_ctx) != 0) {
251 		(void) smb_dr_decode_finish(dec_ctx);
252 		lmshrd_door_exit(arg, "decode error");
253 		return (-1);
254 	}
255 
256 	num_shares = smb_dr_get_uint32(dec_ctx);
257 	if (smb_dr_decode_finish(dec_ctx) != 0) {
258 		lmshrd_door_exit(arg, "decode error");
259 		return (-1);
260 	}
261 
262 	lmshrd_door_exit(arg, NULL);
263 	return (num_shares);
264 }
265 
266 DWORD
267 lmshrd_delete(char *share_name)
268 {
269 	door_arg_t *arg;
270 	smb_dr_ctx_t *dec_ctx;
271 	smb_dr_ctx_t *enc_ctx;
272 	DWORD rc;
273 
274 	if ((arg = lmshrd_door_enter()) == NULL)
275 		return (NERR_InternalError);
276 
277 	enc_ctx = smb_dr_encode_start(arg->data_ptr, LMSHR_DOOR_SIZE);
278 	smb_dr_put_uint32(enc_ctx, LMSHR_DOOR_DELETE);
279 	smb_dr_put_string(enc_ctx, share_name);
280 
281 	rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size);
282 	if (rc != 0) {
283 		lmshrd_door_exit(arg, "encode error");
284 		return (NERR_InternalError);
285 	}
286 
287 	if (door_call(lmshrd_fildes, arg) < 0) {
288 		lmshrd_door_exit(arg, "door call error");
289 		lmshrd_door_close();
290 		return (NERR_InternalError);
291 	}
292 
293 	dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size);
294 	if (lmshrd_door_check_status(dec_ctx) != 0) {
295 		(void) smb_dr_decode_finish(dec_ctx);
296 		lmshrd_door_exit(arg, "decode error");
297 		return (NERR_InternalError);
298 	}
299 
300 	rc = smb_dr_get_uint32(dec_ctx);
301 	if (smb_dr_decode_finish(dec_ctx) != 0) {
302 		lmshrd_door_exit(arg, "decode error");
303 		return (NERR_InternalError);
304 	}
305 
306 	lmshrd_door_exit(arg, NULL);
307 	return (rc);
308 
309 }
310 
311 DWORD
312 lmshrd_rename(char *from, char *to)
313 {
314 	door_arg_t *arg;
315 	smb_dr_ctx_t *dec_ctx;
316 	smb_dr_ctx_t *enc_ctx;
317 	DWORD rc;
318 
319 	if ((arg = lmshrd_door_enter()) == NULL)
320 		return (NERR_InternalError);
321 
322 	enc_ctx = smb_dr_encode_start(arg->data_ptr, LMSHR_DOOR_SIZE);
323 	smb_dr_put_uint32(enc_ctx, LMSHR_DOOR_RENAME);
324 	smb_dr_put_string(enc_ctx, from);
325 	smb_dr_put_string(enc_ctx, to);
326 
327 	rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size);
328 	if (rc != 0) {
329 		lmshrd_door_exit(arg, "encode error");
330 		return (NERR_InternalError);
331 	}
332 
333 	if (door_call(lmshrd_fildes, arg) < 0) {
334 		lmshrd_door_exit(arg, "door call error");
335 		lmshrd_door_close();
336 		return (NERR_InternalError);
337 	}
338 
339 	dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size);
340 	if (lmshrd_door_check_status(dec_ctx) != 0) {
341 		(void) smb_dr_decode_finish(dec_ctx);
342 		lmshrd_door_exit(arg, "decode error");
343 		return (NERR_InternalError);
344 	}
345 
346 	rc = smb_dr_get_uint32(dec_ctx);
347 	if (smb_dr_decode_finish(dec_ctx) != 0) {
348 		lmshrd_door_exit(arg, "decode error");
349 		return (NERR_InternalError);
350 	}
351 
352 	lmshrd_door_exit(arg, NULL);
353 	return (rc);
354 }
355 
356 DWORD
357 lmshrd_getinfo(char *share_name, lmshare_info_t *si)
358 {
359 	door_arg_t *arg;
360 	smb_dr_ctx_t *dec_ctx;
361 	smb_dr_ctx_t *enc_ctx;
362 	DWORD rc;
363 
364 	if ((arg = lmshrd_door_enter()) == NULL)
365 		return (NERR_InternalError);
366 
367 	enc_ctx = smb_dr_encode_start(arg->data_ptr, LMSHR_DOOR_SIZE);
368 	smb_dr_put_uint32(enc_ctx, LMSHR_DOOR_GETINFO);
369 	smb_dr_put_string(enc_ctx, share_name);
370 
371 	rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size);
372 	if (rc != 0) {
373 		lmshrd_door_exit(arg, "encode error");
374 		return (NERR_InternalError);
375 	}
376 
377 	if (door_call(lmshrd_fildes, arg) < 0) {
378 		lmshrd_door_exit(arg, "door call error");
379 		lmshrd_door_close();
380 		return (NERR_InternalError);
381 	}
382 
383 	dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size);
384 	if (lmshrd_door_check_status(dec_ctx) != 0) {
385 		(void) smb_dr_decode_finish(dec_ctx);
386 		lmshrd_door_exit(arg, "decode error");
387 		return (NERR_InternalError);
388 	}
389 
390 	rc = smb_dr_get_uint32(dec_ctx);
391 	smb_dr_get_lmshare(dec_ctx, si);
392 	if (smb_dr_decode_finish(dec_ctx) != 0) {
393 		lmshrd_door_exit(arg, "decode error");
394 		return (NERR_InternalError);
395 	}
396 
397 	lmshrd_door_exit(arg, NULL);
398 	return (rc);
399 }
400 
401 DWORD
402 lmshrd_add(lmshare_info_t *si)
403 {
404 	door_arg_t *arg;
405 	smb_dr_ctx_t *dec_ctx;
406 	smb_dr_ctx_t *enc_ctx;
407 	DWORD rc;
408 
409 	if ((arg = lmshrd_door_enter()) == NULL)
410 		return (NERR_InternalError);
411 
412 	enc_ctx = smb_dr_encode_start(arg->data_ptr, LMSHR_DOOR_SIZE);
413 	smb_dr_put_uint32(enc_ctx, LMSHR_DOOR_ADD);
414 	smb_dr_put_lmshare(enc_ctx, si);
415 
416 	rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size);
417 	if (rc != 0) {
418 		lmshrd_door_exit(arg, "encode error");
419 		return (NERR_InternalError);
420 	}
421 
422 	if (door_call(lmshrd_fildes, arg) < 0) {
423 		lmshrd_door_exit(arg, "door call error");
424 		lmshrd_door_close();
425 		return (NERR_InternalError);
426 	}
427 
428 	dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size);
429 	if (lmshrd_door_check_status(dec_ctx) != 0) {
430 		(void) smb_dr_decode_finish(dec_ctx);
431 		lmshrd_door_exit(arg, "decode error");
432 		return (NERR_InternalError);
433 	}
434 
435 	rc = smb_dr_get_uint32(dec_ctx);
436 	smb_dr_get_lmshare(dec_ctx, si);
437 	if (smb_dr_decode_finish(dec_ctx) != 0) {
438 		lmshrd_door_exit(arg, "decode error");
439 		return (NERR_InternalError);
440 	}
441 
442 	lmshrd_door_exit(arg, NULL);
443 	return (rc);
444 }
445 
446 DWORD
447 lmshrd_setinfo(lmshare_info_t *si)
448 {
449 	door_arg_t *arg;
450 	smb_dr_ctx_t *dec_ctx;
451 	smb_dr_ctx_t *enc_ctx;
452 	DWORD rc;
453 
454 	if ((arg = lmshrd_door_enter()) == NULL)
455 		return (NERR_InternalError);
456 
457 	enc_ctx = smb_dr_encode_start(arg->data_ptr, LMSHR_DOOR_SIZE);
458 	smb_dr_put_uint32(enc_ctx, LMSHR_DOOR_SETINFO);
459 	smb_dr_put_lmshare(enc_ctx, si);
460 
461 	rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size);
462 	if (rc != 0) {
463 		lmshrd_door_exit(arg, "encode error");
464 		return (NERR_InternalError);
465 	}
466 
467 	if (door_call(lmshrd_fildes, arg) < 0) {
468 		lmshrd_door_exit(arg, "door call error");
469 		lmshrd_door_close();
470 		return (NERR_InternalError);
471 	}
472 
473 	dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size);
474 	if (lmshrd_door_check_status(dec_ctx) != 0) {
475 		(void) smb_dr_decode_finish(dec_ctx);
476 		lmshrd_door_exit(arg, "decode error");
477 		return (NERR_InternalError);
478 	}
479 
480 	rc = smb_dr_get_uint32(dec_ctx);
481 	if (smb_dr_decode_finish(dec_ctx) != 0) {
482 		lmshrd_door_exit(arg, "decode error");
483 		return (NERR_InternalError);
484 	}
485 
486 	lmshrd_door_exit(arg, NULL);
487 	return (rc);
488 }
489 
490 static int
491 lmshrd_check(char *share_name, int opcode)
492 {
493 	door_arg_t *arg;
494 	smb_dr_ctx_t *dec_ctx;
495 	smb_dr_ctx_t *enc_ctx;
496 	int rc;
497 
498 	if ((arg = lmshrd_door_enter()) == NULL)
499 		return (NERR_InternalError);
500 
501 	enc_ctx = smb_dr_encode_start(arg->data_ptr, LMSHR_DOOR_SIZE);
502 	smb_dr_put_uint32(enc_ctx, opcode);
503 	smb_dr_put_string(enc_ctx, share_name);
504 
505 	rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size);
506 	if (rc != 0) {
507 		lmshrd_door_exit(arg, "encode error");
508 		return (NERR_InternalError);
509 	}
510 
511 	if (door_call(lmshrd_fildes, arg) < 0) {
512 		lmshrd_door_exit(arg, "door call error");
513 		lmshrd_door_close();
514 		return (NERR_InternalError);
515 	}
516 
517 	dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size);
518 	if (lmshrd_door_check_status(dec_ctx) != 0) {
519 		(void) smb_dr_decode_finish(dec_ctx);
520 		lmshrd_door_exit(arg, "decode error");
521 		return (NERR_InternalError);
522 	}
523 
524 	rc = smb_dr_get_int32(dec_ctx);
525 	if (smb_dr_decode_finish(dec_ctx) != 0) {
526 		lmshrd_door_exit(arg, "decode error");
527 		return (NERR_InternalError);
528 	}
529 
530 	lmshrd_door_exit(arg, NULL);
531 	return (rc);
532 }
533 
534 int
535 lmshrd_exists(char *share_name)
536 {
537 	return (lmshrd_check(share_name, LMSHR_DOOR_EXISTS));
538 }
539 
540 int
541 lmshrd_is_special(char *share_name)
542 {
543 	return (lmshrd_check(share_name, LMSHR_DOOR_IS_SPECIAL));
544 }
545 
546 int
547 lmshrd_is_restricted(char *share_name)
548 {
549 	return (lmshrd_check(share_name, LMSHR_DOOR_IS_RESTRICTED));
550 }
551 
552 int
553 lmshrd_is_admin(char *share_name)
554 {
555 	return (lmshrd_check(share_name, LMSHR_DOOR_IS_ADMIN));
556 }
557 
558 int
559 lmshrd_is_valid(char *share_name)
560 {
561 	return (lmshrd_check(share_name, LMSHR_DOOR_IS_VALID));
562 }
563 
564 int
565 lmshrd_is_dir(char *path)
566 {
567 	return (lmshrd_check(path, LMSHR_DOOR_IS_DIR));
568 }
569