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 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 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 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 * 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