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