110023SGordon.Ross@Sun.COM /*
210023SGordon.Ross@Sun.COM * CDDL HEADER START
310023SGordon.Ross@Sun.COM *
410023SGordon.Ross@Sun.COM * The contents of this file are subject to the terms of the
510023SGordon.Ross@Sun.COM * Common Development and Distribution License (the "License").
610023SGordon.Ross@Sun.COM * You may not use this file except in compliance with the License.
710023SGordon.Ross@Sun.COM *
810023SGordon.Ross@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910023SGordon.Ross@Sun.COM * or http://www.opensolaris.org/os/licensing.
1010023SGordon.Ross@Sun.COM * See the License for the specific language governing permissions
1110023SGordon.Ross@Sun.COM * and limitations under the License.
1210023SGordon.Ross@Sun.COM *
1310023SGordon.Ross@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1410023SGordon.Ross@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510023SGordon.Ross@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1610023SGordon.Ross@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1710023SGordon.Ross@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1810023SGordon.Ross@Sun.COM *
1910023SGordon.Ross@Sun.COM * CDDL HEADER END
2010023SGordon.Ross@Sun.COM */
2110023SGordon.Ross@Sun.COM
2210023SGordon.Ross@Sun.COM /*
2312140SGordon.Ross@Sun.COM * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2410023SGordon.Ross@Sun.COM */
2510023SGordon.Ross@Sun.COM
2610023SGordon.Ross@Sun.COM /*
27*12556SGordon.Ross@Sun.COM * SMBFS I/O Daemon (Per-user IOD)
2810023SGordon.Ross@Sun.COM */
2910023SGordon.Ross@Sun.COM
3010023SGordon.Ross@Sun.COM #include <sys/types.h>
3110023SGordon.Ross@Sun.COM #include <sys/stat.h>
3210023SGordon.Ross@Sun.COM #include <sys/note.h>
3310023SGordon.Ross@Sun.COM
3410023SGordon.Ross@Sun.COM #include <errno.h>
3510023SGordon.Ross@Sun.COM #include <fcntl.h>
3610023SGordon.Ross@Sun.COM #include <signal.h>
3710023SGordon.Ross@Sun.COM #include <stdarg.h>
3810023SGordon.Ross@Sun.COM #include <stdio.h>
3910023SGordon.Ross@Sun.COM #include <string.h>
4010023SGordon.Ross@Sun.COM #include <strings.h>
4110023SGordon.Ross@Sun.COM #include <stdlib.h>
4210023SGordon.Ross@Sun.COM #include <synch.h>
4310023SGordon.Ross@Sun.COM #include <time.h>
4410023SGordon.Ross@Sun.COM #include <unistd.h>
4510023SGordon.Ross@Sun.COM #include <ucred.h>
4610023SGordon.Ross@Sun.COM #include <err.h>
4710023SGordon.Ross@Sun.COM #include <door.h>
48*12556SGordon.Ross@Sun.COM #include <libscf.h>
49*12556SGordon.Ross@Sun.COM #include <locale.h>
5010023SGordon.Ross@Sun.COM #include <thread.h>
5110023SGordon.Ross@Sun.COM
5210023SGordon.Ross@Sun.COM #include <netsmb/smb_lib.h>
5310023SGordon.Ross@Sun.COM
5410023SGordon.Ross@Sun.COM #define DPRINT(...) do \
5510023SGordon.Ross@Sun.COM { \
5610023SGordon.Ross@Sun.COM if (smb_debug) \
5710023SGordon.Ross@Sun.COM fprintf(stderr, __VA_ARGS__); \
5810023SGordon.Ross@Sun.COM _NOTE(CONSTCOND) \
5910023SGordon.Ross@Sun.COM } while (0)
6010023SGordon.Ross@Sun.COM
6110023SGordon.Ross@Sun.COM mutex_t iod_mutex = DEFAULTMUTEX;
6210023SGordon.Ross@Sun.COM int iod_thr_count; /* threads, excluding main */
6310023SGordon.Ross@Sun.COM int iod_terminating;
6412140SGordon.Ross@Sun.COM int iod_alarm_time = 30; /* sec. */
6510023SGordon.Ross@Sun.COM
6610023SGordon.Ross@Sun.COM void iod_dispatch(void *cookie, char *argp, size_t argsz,
6710023SGordon.Ross@Sun.COM door_desc_t *dp, uint_t n_desc);
6810023SGordon.Ross@Sun.COM int iod_newvc(smb_iod_ssn_t *clnt_ssn);
6910023SGordon.Ross@Sun.COM void * iod_work(void *arg);
7010023SGordon.Ross@Sun.COM
7110023SGordon.Ross@Sun.COM int
main(int argc,char ** argv)7210023SGordon.Ross@Sun.COM main(int argc, char **argv)
7310023SGordon.Ross@Sun.COM {
7410023SGordon.Ross@Sun.COM sigset_t oldmask, tmpmask;
7510023SGordon.Ross@Sun.COM char *env, *door_path = NULL;
76*12556SGordon.Ross@Sun.COM int door_fd = -1;
77*12556SGordon.Ross@Sun.COM int err, sig;
78*12556SGordon.Ross@Sun.COM int rc = SMF_EXIT_ERR_FATAL;
79*12556SGordon.Ross@Sun.COM boolean_t attached = B_FALSE;
80*12556SGordon.Ross@Sun.COM
81*12556SGordon.Ross@Sun.COM /* set locale and text domain for i18n */
82*12556SGordon.Ross@Sun.COM (void) setlocale(LC_ALL, "");
83*12556SGordon.Ross@Sun.COM (void) textdomain(TEXT_DOMAIN);
8410023SGordon.Ross@Sun.COM
8510023SGordon.Ross@Sun.COM /* Debugging support. */
8610023SGordon.Ross@Sun.COM if ((env = getenv("SMBFS_DEBUG")) != NULL) {
8710023SGordon.Ross@Sun.COM smb_debug = atoi(env);
8810023SGordon.Ross@Sun.COM if (smb_debug < 1)
8910023SGordon.Ross@Sun.COM smb_debug = 1;
9012140SGordon.Ross@Sun.COM iod_alarm_time = 300;
9110023SGordon.Ross@Sun.COM }
9210023SGordon.Ross@Sun.COM
9310023SGordon.Ross@Sun.COM /*
94*12556SGordon.Ross@Sun.COM * If a user runs this command (i.e. by accident)
95*12556SGordon.Ross@Sun.COM * don't interfere with any already running IOD.
9610023SGordon.Ross@Sun.COM */
9710023SGordon.Ross@Sun.COM err = smb_iod_open_door(&door_fd);
9810023SGordon.Ross@Sun.COM if (err == 0) {
9910023SGordon.Ross@Sun.COM close(door_fd);
10010023SGordon.Ross@Sun.COM door_fd = -1;
101*12556SGordon.Ross@Sun.COM DPRINT("%s: already running\n", argv[0]);
102*12556SGordon.Ross@Sun.COM exit(SMF_EXIT_OK);
10310023SGordon.Ross@Sun.COM }
10410023SGordon.Ross@Sun.COM
10510023SGordon.Ross@Sun.COM /*
106*12556SGordon.Ross@Sun.COM * Want all signals blocked, as we're doing
107*12556SGordon.Ross@Sun.COM * synchronous delivery via sigwait below.
10810023SGordon.Ross@Sun.COM */
10910023SGordon.Ross@Sun.COM sigfillset(&tmpmask);
11010023SGordon.Ross@Sun.COM sigprocmask(SIG_BLOCK, &tmpmask, &oldmask);
11110023SGordon.Ross@Sun.COM
11210023SGordon.Ross@Sun.COM /* Setup the door service. */
113*12556SGordon.Ross@Sun.COM door_path = smb_iod_door_path();
114*12556SGordon.Ross@Sun.COM door_fd = door_create(iod_dispatch, NULL,
115*12556SGordon.Ross@Sun.COM DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
116*12556SGordon.Ross@Sun.COM if (door_fd == -1) {
117*12556SGordon.Ross@Sun.COM perror("iod door_create");
118*12556SGordon.Ross@Sun.COM goto out;
11910023SGordon.Ross@Sun.COM }
12010023SGordon.Ross@Sun.COM fdetach(door_path);
12110023SGordon.Ross@Sun.COM if (fattach(door_fd, door_path) < 0) {
122*12556SGordon.Ross@Sun.COM fprintf(stderr, "%s: fattach failed, %s\n",
123*12556SGordon.Ross@Sun.COM door_path, strerror(errno));
124*12556SGordon.Ross@Sun.COM goto out;
12510023SGordon.Ross@Sun.COM }
126*12556SGordon.Ross@Sun.COM attached = B_TRUE;
127*12556SGordon.Ross@Sun.COM
128*12556SGordon.Ross@Sun.COM /* Initializations done. */
129*12556SGordon.Ross@Sun.COM rc = SMF_EXIT_OK;
13010023SGordon.Ross@Sun.COM
13110023SGordon.Ross@Sun.COM /*
13210023SGordon.Ross@Sun.COM * Post the initial alarm, and then just
13310023SGordon.Ross@Sun.COM * wait for signals.
13410023SGordon.Ross@Sun.COM */
13512140SGordon.Ross@Sun.COM alarm(iod_alarm_time);
13610023SGordon.Ross@Sun.COM again:
13710023SGordon.Ross@Sun.COM sig = sigwait(&tmpmask);
13810023SGordon.Ross@Sun.COM DPRINT("main: sig=%d\n", sig);
139*12556SGordon.Ross@Sun.COM switch (sig) {
140*12556SGordon.Ross@Sun.COM case SIGCONT:
141*12556SGordon.Ross@Sun.COM goto again;
142*12556SGordon.Ross@Sun.COM
143*12556SGordon.Ross@Sun.COM case SIGALRM:
144*12556SGordon.Ross@Sun.COM /* No threads active for a while. */
145*12556SGordon.Ross@Sun.COM mutex_lock(&iod_mutex);
146*12556SGordon.Ross@Sun.COM if (iod_thr_count > 0) {
147*12556SGordon.Ross@Sun.COM /*
148*12556SGordon.Ross@Sun.COM * Door call thread creation raced with
149*12556SGordon.Ross@Sun.COM * the alarm. Ignore this alaram.
150*12556SGordon.Ross@Sun.COM */
151*12556SGordon.Ross@Sun.COM mutex_unlock(&iod_mutex);
152*12556SGordon.Ross@Sun.COM goto again;
153*12556SGordon.Ross@Sun.COM }
154*12556SGordon.Ross@Sun.COM /* Prevent a race with iod_thr_count */
155*12556SGordon.Ross@Sun.COM iod_terminating = 1;
156*12556SGordon.Ross@Sun.COM mutex_unlock(&iod_mutex);
157*12556SGordon.Ross@Sun.COM break;
158*12556SGordon.Ross@Sun.COM
159*12556SGordon.Ross@Sun.COM case SIGINT:
160*12556SGordon.Ross@Sun.COM case SIGTERM:
161*12556SGordon.Ross@Sun.COM break; /* normal termination */
162*12556SGordon.Ross@Sun.COM
163*12556SGordon.Ross@Sun.COM default:
164*12556SGordon.Ross@Sun.COM /* Unexpected signal. */
165*12556SGordon.Ross@Sun.COM fprintf(stderr, "iod_main: unexpected sig=%d\n", sig);
166*12556SGordon.Ross@Sun.COM break;
167*12556SGordon.Ross@Sun.COM }
168*12556SGordon.Ross@Sun.COM
169*12556SGordon.Ross@Sun.COM out:
170*12556SGordon.Ross@Sun.COM iod_terminating = 1;
171*12556SGordon.Ross@Sun.COM if (attached)
172*12556SGordon.Ross@Sun.COM fdetach(door_path);
173*12556SGordon.Ross@Sun.COM if (door_fd != -1)
174*12556SGordon.Ross@Sun.COM door_revoke(door_fd);
17510023SGordon.Ross@Sun.COM
17610023SGordon.Ross@Sun.COM /*
177*12556SGordon.Ross@Sun.COM * We need a reference in -lumem to satisfy check_rtime,
178*12556SGordon.Ross@Sun.COM * else we get build hoise. This is sufficient.
17910023SGordon.Ross@Sun.COM */
180*12556SGordon.Ross@Sun.COM free(NULL);
18110023SGordon.Ross@Sun.COM
18210023SGordon.Ross@Sun.COM return (rc);
18310023SGordon.Ross@Sun.COM }
18410023SGordon.Ross@Sun.COM
18510023SGordon.Ross@Sun.COM /*ARGSUSED*/
18610023SGordon.Ross@Sun.COM void
iod_dispatch(void * cookie,char * argp,size_t argsz,door_desc_t * dp,uint_t n_desc)18710023SGordon.Ross@Sun.COM iod_dispatch(void *cookie, char *argp, size_t argsz,
18810023SGordon.Ross@Sun.COM door_desc_t *dp, uint_t n_desc)
18910023SGordon.Ross@Sun.COM {
19010023SGordon.Ross@Sun.COM smb_iod_ssn_t *ssn;
19110023SGordon.Ross@Sun.COM ucred_t *ucred;
19210023SGordon.Ross@Sun.COM uid_t cl_uid;
19310023SGordon.Ross@Sun.COM int rc;
19410023SGordon.Ross@Sun.COM
19510023SGordon.Ross@Sun.COM /*
19610023SGordon.Ross@Sun.COM * Verify that the calling process has the same UID.
19710023SGordon.Ross@Sun.COM * Paranoia: The door we created has mode 0600, so
19810023SGordon.Ross@Sun.COM * this check is probably redundant.
19910023SGordon.Ross@Sun.COM */
20010023SGordon.Ross@Sun.COM ucred = NULL;
20110023SGordon.Ross@Sun.COM if (door_ucred(&ucred) != 0) {
20210023SGordon.Ross@Sun.COM rc = EACCES;
20310023SGordon.Ross@Sun.COM goto out;
20410023SGordon.Ross@Sun.COM }
20510023SGordon.Ross@Sun.COM cl_uid = ucred_getruid(ucred);
20610023SGordon.Ross@Sun.COM ucred_free(ucred);
20710023SGordon.Ross@Sun.COM ucred = NULL;
20810023SGordon.Ross@Sun.COM if (cl_uid != getuid()) {
20910023SGordon.Ross@Sun.COM DPRINT("iod_dispatch: wrong UID\n");
21010023SGordon.Ross@Sun.COM rc = EACCES;
21110023SGordon.Ross@Sun.COM goto out;
21210023SGordon.Ross@Sun.COM }
21310023SGordon.Ross@Sun.COM
21410023SGordon.Ross@Sun.COM /*
21510023SGordon.Ross@Sun.COM * The library uses a NULL arg call to check if
216*12556SGordon.Ross@Sun.COM * the daemon is running. Just return zero.
21710023SGordon.Ross@Sun.COM */
21810023SGordon.Ross@Sun.COM if (argp == NULL) {
21910023SGordon.Ross@Sun.COM rc = 0;
22010023SGordon.Ross@Sun.COM goto out;
22110023SGordon.Ross@Sun.COM }
22210023SGordon.Ross@Sun.COM
22310023SGordon.Ross@Sun.COM /*
22410023SGordon.Ross@Sun.COM * Otherwise, the arg must be the (fixed size)
22510023SGordon.Ross@Sun.COM * smb_iod_ssn_t
22610023SGordon.Ross@Sun.COM */
22710023SGordon.Ross@Sun.COM if (argsz != sizeof (*ssn)) {
22810023SGordon.Ross@Sun.COM rc = EINVAL;
22910023SGordon.Ross@Sun.COM goto out;
23010023SGordon.Ross@Sun.COM }
23110023SGordon.Ross@Sun.COM
23210023SGordon.Ross@Sun.COM mutex_lock(&iod_mutex);
23310023SGordon.Ross@Sun.COM if (iod_terminating) {
23410023SGordon.Ross@Sun.COM mutex_unlock(&iod_mutex);
23510023SGordon.Ross@Sun.COM DPRINT("iod_dispatch: terminating\n");
23610023SGordon.Ross@Sun.COM rc = EINTR;
23710023SGordon.Ross@Sun.COM goto out;
23810023SGordon.Ross@Sun.COM }
23910023SGordon.Ross@Sun.COM if (iod_thr_count++ == 0) {
24010023SGordon.Ross@Sun.COM alarm(0);
24110023SGordon.Ross@Sun.COM DPRINT("iod_dispatch: cancelled alarm\n");
24210023SGordon.Ross@Sun.COM }
24310023SGordon.Ross@Sun.COM mutex_unlock(&iod_mutex);
24410023SGordon.Ross@Sun.COM
24510023SGordon.Ross@Sun.COM ssn = (void *) argp;
24610023SGordon.Ross@Sun.COM rc = iod_newvc(ssn);
24710023SGordon.Ross@Sun.COM
24810023SGordon.Ross@Sun.COM mutex_lock(&iod_mutex);
24910023SGordon.Ross@Sun.COM if (--iod_thr_count == 0) {
25010023SGordon.Ross@Sun.COM DPRINT("iod_dispatch: schedule alarm\n");
25112140SGordon.Ross@Sun.COM alarm(iod_alarm_time);
25210023SGordon.Ross@Sun.COM }
25310023SGordon.Ross@Sun.COM mutex_unlock(&iod_mutex);
25410023SGordon.Ross@Sun.COM
25510023SGordon.Ross@Sun.COM out:
25610023SGordon.Ross@Sun.COM door_return((void *)&rc, sizeof (rc), NULL, 0);
25710023SGordon.Ross@Sun.COM }
25810023SGordon.Ross@Sun.COM
25910023SGordon.Ross@Sun.COM /*
26010023SGordon.Ross@Sun.COM * Try making a connection with the server described by
26110023SGordon.Ross@Sun.COM * the info in the smb_iod_ssn_t arg. If successful,
26210023SGordon.Ross@Sun.COM * start an IOD thread to service it, then return to
26310023SGordon.Ross@Sun.COM * the client side of the door.
26410023SGordon.Ross@Sun.COM */
26510023SGordon.Ross@Sun.COM int
iod_newvc(smb_iod_ssn_t * clnt_ssn)26610023SGordon.Ross@Sun.COM iod_newvc(smb_iod_ssn_t *clnt_ssn)
26710023SGordon.Ross@Sun.COM {
26810023SGordon.Ross@Sun.COM smb_ctx_t *ctx;
26910023SGordon.Ross@Sun.COM thread_t tid;
27010023SGordon.Ross@Sun.COM int err;
27110023SGordon.Ross@Sun.COM
27210023SGordon.Ross@Sun.COM
27310023SGordon.Ross@Sun.COM /*
27410023SGordon.Ross@Sun.COM * This needs to essentially "clone" the smb_ctx_t
27510023SGordon.Ross@Sun.COM * from the client side of the door, or at least
27610023SGordon.Ross@Sun.COM * as much of it as we need while creating a VC.
27710023SGordon.Ross@Sun.COM */
27810023SGordon.Ross@Sun.COM err = smb_ctx_alloc(&ctx);
27910023SGordon.Ross@Sun.COM if (err)
28010023SGordon.Ross@Sun.COM return (err);
28110023SGordon.Ross@Sun.COM bcopy(clnt_ssn, &ctx->ct_iod_ssn, sizeof (ctx->ct_iod_ssn));
28210023SGordon.Ross@Sun.COM
28310023SGordon.Ross@Sun.COM /*
28410023SGordon.Ross@Sun.COM * Do the initial connection setup here, so we can
28510023SGordon.Ross@Sun.COM * report the outcome to the door client.
28610023SGordon.Ross@Sun.COM */
28710023SGordon.Ross@Sun.COM err = smb_iod_connect(ctx);
28810023SGordon.Ross@Sun.COM if (err != 0)
28910023SGordon.Ross@Sun.COM goto out;
29010023SGordon.Ross@Sun.COM
29110023SGordon.Ross@Sun.COM /*
29210023SGordon.Ross@Sun.COM * Create the driver session now, so we don't
29310023SGordon.Ross@Sun.COM * race with the door client findvc call.
29410023SGordon.Ross@Sun.COM */
29510023SGordon.Ross@Sun.COM if ((err = smb_ctx_gethandle(ctx)) != 0)
29610023SGordon.Ross@Sun.COM goto out;
29710023SGordon.Ross@Sun.COM if (ioctl(ctx->ct_dev_fd, SMBIOC_SSN_CREATE, &ctx->ct_ssn) < 0) {
29810023SGordon.Ross@Sun.COM err = errno;
29910023SGordon.Ross@Sun.COM goto out;
30010023SGordon.Ross@Sun.COM }
30110023SGordon.Ross@Sun.COM
30210023SGordon.Ross@Sun.COM /* The rest happens in the iod_work thread. */
30310023SGordon.Ross@Sun.COM err = thr_create(NULL, 0, iod_work, ctx, THR_DETACHED, &tid);
30410023SGordon.Ross@Sun.COM if (err == 0) {
30510023SGordon.Ross@Sun.COM /*
30610023SGordon.Ross@Sun.COM * Given to the new thread.
30710023SGordon.Ross@Sun.COM * free at end of iod_work
30810023SGordon.Ross@Sun.COM */
30910023SGordon.Ross@Sun.COM ctx = NULL;
31010023SGordon.Ross@Sun.COM }
31110023SGordon.Ross@Sun.COM
31210023SGordon.Ross@Sun.COM out:
31310023SGordon.Ross@Sun.COM if (ctx)
31410023SGordon.Ross@Sun.COM smb_ctx_free(ctx);
31510023SGordon.Ross@Sun.COM
31610023SGordon.Ross@Sun.COM return (err);
31710023SGordon.Ross@Sun.COM }
31810023SGordon.Ross@Sun.COM
31910023SGordon.Ross@Sun.COM /*
32010023SGordon.Ross@Sun.COM * Be the reader thread for some VC.
32110023SGordon.Ross@Sun.COM *
32210023SGordon.Ross@Sun.COM * This is started by a door call thread, which means
32310023SGordon.Ross@Sun.COM * this is always at least the 2nd thread, therefore
32410023SGordon.Ross@Sun.COM * it should never see thr_count==0 or terminating.
32510023SGordon.Ross@Sun.COM */
32610023SGordon.Ross@Sun.COM void *
iod_work(void * arg)32710023SGordon.Ross@Sun.COM iod_work(void *arg)
32810023SGordon.Ross@Sun.COM {
32910023SGordon.Ross@Sun.COM smb_ctx_t *ctx = arg;
33010023SGordon.Ross@Sun.COM
33110023SGordon.Ross@Sun.COM mutex_lock(&iod_mutex);
33210023SGordon.Ross@Sun.COM if (iod_thr_count++ == 0) {
33310023SGordon.Ross@Sun.COM alarm(0);
33410023SGordon.Ross@Sun.COM DPRINT("iod_work: cancelled alarm\n");
33510023SGordon.Ross@Sun.COM }
33610023SGordon.Ross@Sun.COM mutex_unlock(&iod_mutex);
33710023SGordon.Ross@Sun.COM
33810023SGordon.Ross@Sun.COM (void) smb_iod_work(ctx);
33910023SGordon.Ross@Sun.COM
34010023SGordon.Ross@Sun.COM mutex_lock(&iod_mutex);
34110023SGordon.Ross@Sun.COM if (--iod_thr_count == 0) {
34210023SGordon.Ross@Sun.COM DPRINT("iod_work: schedule alarm\n");
34312140SGordon.Ross@Sun.COM alarm(iod_alarm_time);
34410023SGordon.Ross@Sun.COM }
34510023SGordon.Ross@Sun.COM mutex_unlock(&iod_mutex);
34610023SGordon.Ross@Sun.COM
34710023SGordon.Ross@Sun.COM smb_ctx_free(ctx);
34810023SGordon.Ross@Sun.COM return (NULL);
34910023SGordon.Ross@Sun.COM }
350