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