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 */ 25 26 /* 27 * Client-side interface to the IO Daemon (IOD) 28 */ 29 30 #include <errno.h> 31 #include <fcntl.h> 32 #include <stdio.h> 33 #include <string.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <netdb.h> 37 #include <libintl.h> 38 #include <door.h> 39 40 #include <sys/byteorder.h> 41 #include <sys/types.h> 42 #include <sys/fcntl.h> 43 #include <sys/ioctl.h> 44 #include <sys/time.h> 45 #include <sys/socket.h> 46 47 #include <netinet/in.h> 48 #include <netinet/tcp.h> 49 #include <arpa/inet.h> 50 51 #include <netsmb/smb_lib.h> 52 #include <netsmb/netbios.h> 53 #include <netsmb/nb_lib.h> 54 #include <netsmb/smb_dev.h> 55 56 #include <assert.h> 57 58 #include "charsets.h" 59 #include "private.h" 60 61 /* 62 * This is constant for the life of a process, 63 * and initialized at startup, so no locks. 64 */ 65 static char door_path[64]; 66 static int iod_start_timeout = 10; /* seconds */ 67 68 char * 69 smb_iod_door_path(void) 70 { 71 uid_t uid; 72 int x; 73 74 if (door_path[0] == '\0') { 75 uid = getuid(); 76 x = snprintf(door_path, sizeof (door_path), 77 SMBIOD_USR_DOOR, uid); 78 assert(x <= sizeof (door_path)); 79 } 80 81 return (door_path); 82 } 83 84 /* 85 * Open the door (client side) and 86 * find out if the service is there. 87 */ 88 int 89 smb_iod_open_door(int *fdp) 90 { 91 door_arg_t da; 92 char *path; 93 int fd, rc; 94 int err = 0; 95 96 path = smb_iod_door_path(); 97 fd = open(path, O_RDONLY, 0); 98 if (fd < 0) 99 return (errno); 100 101 /* 102 * Make sure the IOD is running. 103 * Pass NULL args. 104 */ 105 memset(&da, 0, sizeof (da)); 106 da.rbuf = (void *) &err; 107 da.rsize = sizeof (err); 108 rc = door_call(fd, &da); 109 if (rc < 0) { 110 err = errno; 111 close(fd); 112 return (err); 113 } 114 if (err != 0) { 115 close(fd); 116 return (err); 117 } 118 119 /* This handle controls per-process resources. */ 120 (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 121 122 *fdp = fd; 123 return (0); 124 } 125 126 /* 127 * Request the creation of our per-user smbiod 128 * via door call to the "main" IOD service. 129 */ 130 static int 131 start_iod(void) 132 { 133 const char *svc_door = SMBIOD_SVC_DOOR; 134 door_arg_t da; 135 int32_t cmd, err; 136 int fd, rc; 137 138 fd = open(svc_door, O_RDONLY, 0); 139 if (fd < 0) { 140 err = errno; 141 DPRINT("%s: open failed, err %d", svc_door, err); 142 return (err); 143 } 144 cmd = SMBIOD_START; 145 memset(&da, 0, sizeof (da)); 146 da.data_ptr = (void *) &cmd; 147 da.data_size = sizeof (cmd); 148 da.rbuf = (void *) &err; 149 da.rsize = sizeof (err); 150 rc = door_call(fd, &da); 151 close(fd); 152 if (rc < 0) { 153 err = errno; 154 DPRINT("door_call, err %d", err); 155 return (err); 156 } 157 158 return (err); 159 } 160 161 /* 162 * Get a door handle to the IOD, starting it if necessary. 163 * On success, sets ctx->ct_door_fd 164 */ 165 int 166 smb_iod_start(smb_ctx_t *ctx) 167 { 168 int err, tmo; 169 int fd = -1; 170 171 tmo = iod_start_timeout; 172 while ((err = smb_iod_open_door(&fd)) != 0) { 173 if (--tmo <= 0) 174 goto errout; 175 176 /* 177 * We have no per-user IOD yet. Request one. 178 * Do this request every time through the loop 179 * because the master IOD will only start our 180 * per-user IOD if we don't have one, and our 181 * first requst could have happened while we 182 * had an IOD that was doing shutdown. 183 * (Prevents a shutdown/startup race). 184 */ 185 err = start_iod(); 186 if (err != 0) 187 goto errout; 188 /* 189 * Wait for it to get ready. 190 */ 191 (void) sleep(1); 192 } 193 194 /* Save the door fd. */ 195 if (ctx->ct_door_fd != -1) 196 close(ctx->ct_door_fd); 197 ctx->ct_door_fd = fd; 198 199 return (0); 200 201 errout: 202 smb_error(dgettext(TEXT_DOMAIN, 203 "Could not contact service: %s"), 204 0, "svc:/network/smb/client"); 205 return (ENOTACTIVE); 206 } 207 208 /* 209 * Ask the IOD to connect using the info in ctx. 210 * Called by newvc. 211 */ 212 int 213 smb_iod_cl_newvc(smb_ctx_t *ctx) 214 { 215 door_arg_t da; 216 int err = 0; 217 218 /* Should already have the IOD door. */ 219 if (ctx->ct_door_fd < 0) 220 return (EINVAL); 221 222 da.data_ptr = (void *) &ctx->ct_iod_ssn; 223 da.data_size = sizeof (ctx->ct_iod_ssn); 224 da.desc_ptr = NULL; 225 da.desc_num = 0; 226 da.rbuf = (void *) &err; 227 da.rsize = sizeof (err); 228 if (door_call(ctx->ct_door_fd, &da) < 0) { 229 err = errno; 230 DPRINT("door_call, err=%d", err); 231 } 232 233 return (err); 234 } 235