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) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 /*
28 * SMBFS I/O Daemon (Per-user IOD)
29 */
30
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/note.h>
34
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <signal.h>
38 #include <stdarg.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <strings.h>
42 #include <stdlib.h>
43 #include <synch.h>
44 #include <time.h>
45 #include <unistd.h>
46 #include <ucred.h>
47 #include <err.h>
48 #include <door.h>
49 #include <libscf.h>
50 #include <locale.h>
51 #include <thread.h>
52
53 #include <netsmb/smb_lib.h>
54
55 #define DPRINT(...) do \
56 { \
57 if (smb_debug) \
58 fprintf(stderr, __VA_ARGS__); \
59 _NOTE(CONSTCOND) \
60 } while (0)
61
62 mutex_t iod_mutex = DEFAULTMUTEX;
63 int iod_thr_count; /* threads, excluding main */
64 int iod_terminating;
65 int iod_alarm_time = 30; /* sec. */
66
67 void iod_dispatch(void *cookie, char *argp, size_t argsz,
68 door_desc_t *dp, uint_t n_desc);
69 int iod_newvc(smb_iod_ssn_t *clnt_ssn);
70 void * iod_work(void *arg);
71
72 int
main(int argc,char ** argv)73 main(int argc, char **argv)
74 {
75 sigset_t oldmask, tmpmask;
76 char *env, *door_path = NULL;
77 int door_fd = -1;
78 int err, sig;
79 int rc = SMF_EXIT_ERR_FATAL;
80 boolean_t attached = B_FALSE;
81
82 /* set locale and text domain for i18n */
83 (void) setlocale(LC_ALL, "");
84 (void) textdomain(TEXT_DOMAIN);
85
86 /* Debugging support. */
87 if ((env = getenv("SMBFS_DEBUG")) != NULL) {
88 smb_debug = atoi(env);
89 if (smb_debug < 1)
90 smb_debug = 1;
91 iod_alarm_time = 300;
92 }
93
94 /*
95 * If a user runs this command (i.e. by accident)
96 * don't interfere with any already running IOD.
97 */
98 err = smb_iod_open_door(&door_fd);
99 if (err == 0) {
100 close(door_fd);
101 door_fd = -1;
102 DPRINT("%s: already running\n", argv[0]);
103 exit(SMF_EXIT_OK);
104 }
105
106 /*
107 * Want all signals blocked, as we're doing
108 * synchronous delivery via sigwait below.
109 */
110 sigfillset(&tmpmask);
111 sigprocmask(SIG_BLOCK, &tmpmask, &oldmask);
112
113 /* Setup the door service. */
114 door_path = smb_iod_door_path();
115 door_fd = door_create(iod_dispatch, NULL,
116 DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
117 if (door_fd == -1) {
118 perror("iod door_create");
119 goto out;
120 }
121 fdetach(door_path);
122 if (fattach(door_fd, door_path) < 0) {
123 fprintf(stderr, "%s: fattach failed, %s\n",
124 door_path, strerror(errno));
125 goto out;
126 }
127 attached = B_TRUE;
128
129 /* Initializations done. */
130 rc = SMF_EXIT_OK;
131
132 /*
133 * Post the initial alarm, and then just
134 * wait for signals.
135 */
136 alarm(iod_alarm_time);
137 again:
138 sig = sigwait(&tmpmask);
139 DPRINT("main: sig=%d\n", sig);
140 switch (sig) {
141 case SIGCONT:
142 goto again;
143
144 case SIGALRM:
145 /* No threads active for a while. */
146 mutex_lock(&iod_mutex);
147 if (iod_thr_count > 0) {
148 /*
149 * Door call thread creation raced with
150 * the alarm. Ignore this alaram.
151 */
152 mutex_unlock(&iod_mutex);
153 goto again;
154 }
155 /* Prevent a race with iod_thr_count */
156 iod_terminating = 1;
157 mutex_unlock(&iod_mutex);
158 break;
159
160 case SIGINT:
161 case SIGTERM:
162 break; /* normal termination */
163
164 default:
165 /* Unexpected signal. */
166 fprintf(stderr, "iod_main: unexpected sig=%d\n", sig);
167 break;
168 }
169
170 out:
171 iod_terminating = 1;
172 if (attached)
173 fdetach(door_path);
174 if (door_fd != -1)
175 door_revoke(door_fd);
176
177 /*
178 * We need a reference in -lumem to satisfy check_rtime,
179 * else we get build hoise. This is sufficient.
180 */
181 free(NULL);
182
183 return (rc);
184 }
185
186 /*ARGSUSED*/
187 void
iod_dispatch(void * cookie,char * argp,size_t argsz,door_desc_t * dp,uint_t n_desc)188 iod_dispatch(void *cookie, char *argp, size_t argsz,
189 door_desc_t *dp, uint_t n_desc)
190 {
191 smb_iod_ssn_t *ssn;
192 ucred_t *ucred;
193 uid_t cl_uid;
194 int rc;
195
196 /*
197 * Verify that the calling process has the same UID.
198 * Paranoia: The door we created has mode 0600, so
199 * this check is probably redundant.
200 */
201 ucred = NULL;
202 if (door_ucred(&ucred) != 0) {
203 rc = EACCES;
204 goto out;
205 }
206 cl_uid = ucred_getruid(ucred);
207 ucred_free(ucred);
208 ucred = NULL;
209 if (cl_uid != getuid()) {
210 DPRINT("iod_dispatch: wrong UID\n");
211 rc = EACCES;
212 goto out;
213 }
214
215 /*
216 * The library uses a NULL arg call to check if
217 * the daemon is running. Just return zero.
218 */
219 if (argp == NULL) {
220 rc = 0;
221 goto out;
222 }
223
224 /*
225 * Otherwise, the arg must be the (fixed size)
226 * smb_iod_ssn_t
227 */
228 if (argsz != sizeof (*ssn)) {
229 rc = EINVAL;
230 goto out;
231 }
232
233 mutex_lock(&iod_mutex);
234 if (iod_terminating) {
235 mutex_unlock(&iod_mutex);
236 DPRINT("iod_dispatch: terminating\n");
237 rc = EINTR;
238 goto out;
239 }
240 if (iod_thr_count++ == 0) {
241 alarm(0);
242 DPRINT("iod_dispatch: cancelled alarm\n");
243 }
244 mutex_unlock(&iod_mutex);
245
246 ssn = (void *) argp;
247 rc = iod_newvc(ssn);
248
249 mutex_lock(&iod_mutex);
250 if (--iod_thr_count == 0) {
251 DPRINT("iod_dispatch: schedule alarm\n");
252 alarm(iod_alarm_time);
253 }
254 mutex_unlock(&iod_mutex);
255
256 out:
257 door_return((void *)&rc, sizeof (rc), NULL, 0);
258 }
259
260 /*
261 * Try making a connection with the server described by
262 * the info in the smb_iod_ssn_t arg. If successful,
263 * start an IOD thread to service it, then return to
264 * the client side of the door.
265 */
266 int
iod_newvc(smb_iod_ssn_t * clnt_ssn)267 iod_newvc(smb_iod_ssn_t *clnt_ssn)
268 {
269 smb_ctx_t *ctx;
270 thread_t tid;
271 int err;
272
273
274 /*
275 * This needs to essentially "clone" the smb_ctx_t
276 * from the client side of the door, or at least
277 * as much of it as we need while creating a VC.
278 */
279 err = smb_ctx_alloc(&ctx);
280 if (err)
281 return (err);
282 bcopy(clnt_ssn, &ctx->ct_iod_ssn, sizeof (ctx->ct_iod_ssn));
283
284 /*
285 * Create the driver session first, so that any subsequent
286 * requests for the same session will find this one and
287 * wait, the same as when a reconnect is triggered.
288 *
289 * There is still an inherent race here, where two callers
290 * both find no VC in the driver, and both come here trying
291 * to create the VC. In this case, we want the first one
292 * to actually do the VC setup, and the second to proceed
293 * as if the VC had been found in the driver. The second
294 * caller gets an EEXIST error from the ioctl in this case,
295 * which we therefore ignore here so that the caller will
296 * go ahead and look again in the driver for the new VC.
297 */
298 if ((err = smb_ctx_gethandle(ctx)) != 0)
299 goto out;
300 if (ioctl(ctx->ct_dev_fd, SMBIOC_SSN_CREATE, &ctx->ct_ssn) < 0) {
301 err = errno;
302 if (err == EEXIST)
303 err = 0; /* see above */
304 goto out;
305 }
306
307 /*
308 * Do the initial connection setup here, so we can
309 * report the outcome to the door client.
310 */
311 err = smb_iod_connect(ctx);
312 if (err != 0)
313 goto out;
314
315 /* The rest happens in the iod_work thread. */
316 err = thr_create(NULL, 0, iod_work, ctx, THR_DETACHED, &tid);
317 if (err == 0) {
318 /*
319 * Given to the new thread.
320 * free at end of iod_work
321 */
322 ctx = NULL;
323 }
324
325 out:
326 if (ctx)
327 smb_ctx_free(ctx);
328
329 return (err);
330 }
331
332 /*
333 * Be the reader thread for some VC.
334 *
335 * This is started by a door call thread, which means
336 * this is always at least the 2nd thread, therefore
337 * it should never see thr_count==0 or terminating.
338 */
339 void *
iod_work(void * arg)340 iod_work(void *arg)
341 {
342 smb_ctx_t *ctx = arg;
343
344 mutex_lock(&iod_mutex);
345 if (iod_thr_count++ == 0) {
346 alarm(0);
347 DPRINT("iod_work: cancelled alarm\n");
348 }
349 mutex_unlock(&iod_mutex);
350
351 (void) smb_iod_work(ctx);
352
353 mutex_lock(&iod_mutex);
354 if (--iod_thr_count == 0) {
355 DPRINT("iod_work: schedule alarm\n");
356 alarm(iod_alarm_time);
357 }
358 mutex_unlock(&iod_mutex);
359
360 smb_ctx_free(ctx);
361 return (NULL);
362 }
363