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
smb_share_door_clnt_init(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
smb_share_door_clnt_fini(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
smb_share_door_clnt_open(void)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
smb_share_door_clnt_close(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 *
smb_share_door_clnt_enter(void)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
smb_share_door_clnt_exit(door_arg_t * arg,boolean_t must_close,char * errmsg)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
smb_share_door_call(int fd,door_arg_t * arg)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
smb_share_dchk(smb_dr_ctx_t * dec_ctx)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
smb_share_list(int offset,smb_shrlist_t * list)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
smb_share_count(void)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
smb_share_delete(char * share_name)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
smb_share_rename(char * from,char * to)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
smb_share_create(smb_share_t * si)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
smb_share_modify(smb_share_t * si)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