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