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 * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 25 */ 26 27 /* 28 * User-space door client for LanMan share management. 29 */ 30 31 #include <syslog.h> 32 #include <door.h> 33 #include <fcntl.h> 34 #include <stdarg.h> 35 #include <errno.h> 36 #include <string.h> 37 #include <strings.h> 38 #include <unistd.h> 39 #include <thread.h> 40 #include <synch.h> 41 42 #include <smbsrv/libsmb.h> 43 #include <smbsrv/smb_share.h> 44 #include <smbsrv/smb.h> 45 46 #define SMB_SHARE_DOOR_CALL_RETRIES 3 47 48 static int smb_share_dfd = -1; 49 static uint64_t smb_share_dncall = 0; 50 static mutex_t smb_share_dmtx; 51 static cond_t smb_share_dcv; 52 53 static int smb_share_door_clnt_open(void); 54 static void smb_share_door_clnt_close(void); 55 56 void 57 smb_share_door_clnt_init(void) 58 { 59 (void) mutex_lock(&smb_share_dmtx); 60 (void) smb_share_door_clnt_open(); 61 (void) mutex_unlock(&smb_share_dmtx); 62 } 63 64 void 65 smb_share_door_clnt_fini(void) 66 { 67 (void) mutex_lock(&smb_share_dmtx); 68 smb_share_door_clnt_close(); 69 (void) mutex_unlock(&smb_share_dmtx); 70 } 71 72 /* 73 * Open smb_share_door. This is a private call for use by 74 * smb_share_door_clnt_enter() and must be called with smb_share_dmtx held. 75 * 76 * Returns the door fd on success. Otherwise, -1. 77 */ 78 static int 79 smb_share_door_clnt_open(void) 80 { 81 const char *door_name; 82 83 if (smb_share_dfd == -1) { 84 door_name = getenv("SMB_SHARE_DNAME"); 85 if (door_name == NULL) 86 door_name = SMB_SHARE_DNAME; 87 88 if ((smb_share_dfd = open(door_name, O_RDONLY)) < 0) 89 smb_share_dfd = -1; 90 else 91 smb_share_dncall = 0; 92 } 93 94 return (smb_share_dfd); 95 } 96 97 /* 98 * Close smb_share_door. 99 * Private call that must be called with smb_share_dmtx held. 100 */ 101 static void 102 smb_share_door_clnt_close(void) 103 { 104 if (smb_share_dfd != -1) { 105 while (smb_share_dncall > 0) 106 (void) cond_wait(&smb_share_dcv, &smb_share_dmtx); 107 108 if (smb_share_dfd != -1) { 109 (void) close(smb_share_dfd); 110 smb_share_dfd = -1; 111 } 112 } 113 } 114 115 /* 116 * Entry handler for smb_share_door calls. 117 */ 118 static door_arg_t * 119 smb_share_door_clnt_enter(void) 120 { 121 door_arg_t *arg; 122 char *buf; 123 124 (void) mutex_lock(&smb_share_dmtx); 125 126 if (smb_share_door_clnt_open() == -1) { 127 (void) mutex_unlock(&smb_share_dmtx); 128 return (NULL); 129 } 130 131 if ((arg = malloc(sizeof (door_arg_t) + SMB_SHARE_DSIZE)) != NULL) { 132 buf = ((char *)arg) + sizeof (door_arg_t); 133 bzero(arg, sizeof (door_arg_t)); 134 arg->data_ptr = buf; 135 arg->rbuf = buf; 136 arg->rsize = SMB_SHARE_DSIZE; 137 138 ++smb_share_dncall; 139 } 140 141 (void) mutex_unlock(&smb_share_dmtx); 142 return (arg); 143 } 144 145 /* 146 * Exit handler for smb_share_door calls. 147 */ 148 static void 149 smb_share_door_clnt_exit(door_arg_t *arg, boolean_t must_close, char *errmsg) 150 { 151 if (errmsg) 152 syslog(LOG_DEBUG, "smb_share_door: %s failed", errmsg); 153 154 (void) mutex_lock(&smb_share_dmtx); 155 free(arg); 156 --smb_share_dncall; 157 (void) cond_signal(&smb_share_dcv); 158 159 if (must_close) 160 smb_share_door_clnt_close(); 161 162 (void) mutex_unlock(&smb_share_dmtx); 163 } 164 165 static int 166 smb_share_door_call(int fd, door_arg_t *arg) 167 { 168 int rc; 169 int i; 170 171 for (i = 0; i < SMB_SHARE_DOOR_CALL_RETRIES; ++i) { 172 errno = 0; 173 174 if ((rc = door_call(fd, arg)) == 0) 175 break; 176 177 if (errno != EAGAIN && errno != EINTR) 178 break; 179 } 180 181 return (rc); 182 } 183 184 static int 185 smb_share_dchk(smb_dr_ctx_t *dec_ctx) 186 { 187 int status = smb_dr_get_int32(dec_ctx); 188 189 if (status != SMB_SHARE_DSUCCESS) { 190 if (status == SMB_SHARE_DERROR) 191 (void) smb_dr_get_uint32(dec_ctx); 192 return (-1); 193 } 194 195 return (0); 196 } 197 198 uint32_t 199 smb_share_list(int offset, smb_shrlist_t *list) 200 { 201 door_arg_t *arg; 202 smb_dr_ctx_t *dec_ctx; 203 smb_dr_ctx_t *enc_ctx; 204 uint32_t rc; 205 206 bzero(list, sizeof (smb_shrlist_t)); 207 208 if ((arg = smb_share_door_clnt_enter()) == NULL) 209 return (NERR_InternalError); 210 211 enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE); 212 smb_dr_put_uint32(enc_ctx, SMB_SHROP_LIST); 213 smb_dr_put_int32(enc_ctx, offset); 214 215 rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size); 216 if (rc != 0) { 217 smb_share_door_clnt_exit(arg, B_FALSE, "encode"); 218 return (NERR_InternalError); 219 } 220 221 if (smb_share_door_call(smb_share_dfd, arg) < 0) { 222 smb_share_door_clnt_exit(arg, B_TRUE, "door call"); 223 return (NERR_InternalError); 224 } 225 226 dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size); 227 if (smb_share_dchk(dec_ctx) != 0) { 228 (void) smb_dr_decode_finish(dec_ctx); 229 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 230 return (NERR_InternalError); 231 } 232 233 (void) smb_dr_get_buf(dec_ctx, (unsigned char *)list, 234 sizeof (smb_shrlist_t)); 235 if (smb_dr_decode_finish(dec_ctx) != 0) { 236 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 237 return (NERR_InternalError); 238 } 239 240 smb_share_door_clnt_exit(arg, B_FALSE, NULL); 241 return (NERR_Success); 242 } 243 244 int 245 smb_share_count(void) 246 { 247 door_arg_t *arg; 248 smb_dr_ctx_t *dec_ctx; 249 smb_dr_ctx_t *enc_ctx; 250 uint32_t num_shares; 251 int rc; 252 253 if ((arg = smb_share_door_clnt_enter()) == NULL) 254 return (-1); 255 256 enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE); 257 smb_dr_put_uint32(enc_ctx, SMB_SHROP_NUM_SHARES); 258 259 rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size); 260 if (rc != 0) { 261 smb_share_door_clnt_exit(arg, B_FALSE, "encode"); 262 return (-1); 263 } 264 265 if (smb_share_door_call(smb_share_dfd, arg) < 0) { 266 smb_share_door_clnt_exit(arg, B_TRUE, "door call"); 267 return (-1); 268 } 269 270 dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size); 271 if (smb_share_dchk(dec_ctx) != 0) { 272 (void) smb_dr_decode_finish(dec_ctx); 273 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 274 return (-1); 275 } 276 277 num_shares = smb_dr_get_uint32(dec_ctx); 278 if (smb_dr_decode_finish(dec_ctx) != 0) { 279 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 280 return (-1); 281 } 282 283 smb_share_door_clnt_exit(arg, B_FALSE, NULL); 284 return (num_shares); 285 } 286 287 uint32_t 288 smb_share_delete(char *share_name) 289 { 290 door_arg_t *arg; 291 smb_dr_ctx_t *dec_ctx; 292 smb_dr_ctx_t *enc_ctx; 293 uint32_t rc; 294 295 if ((arg = smb_share_door_clnt_enter()) == NULL) 296 return (NERR_InternalError); 297 298 enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE); 299 smb_dr_put_uint32(enc_ctx, SMB_SHROP_DELETE); 300 smb_dr_put_string(enc_ctx, share_name); 301 302 rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size); 303 if (rc != 0) { 304 smb_share_door_clnt_exit(arg, B_FALSE, "encode"); 305 return (NERR_InternalError); 306 } 307 308 if (smb_share_door_call(smb_share_dfd, arg) < 0) { 309 smb_share_door_clnt_exit(arg, B_TRUE, "door call"); 310 return (NERR_InternalError); 311 } 312 313 dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size); 314 if (smb_share_dchk(dec_ctx) != 0) { 315 (void) smb_dr_decode_finish(dec_ctx); 316 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 317 return (NERR_InternalError); 318 } 319 320 rc = smb_dr_get_uint32(dec_ctx); 321 if (smb_dr_decode_finish(dec_ctx) != 0) { 322 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 323 return (NERR_InternalError); 324 } 325 326 smb_share_door_clnt_exit(arg, B_FALSE, NULL); 327 return (rc); 328 329 } 330 331 uint32_t 332 smb_share_rename(char *from, char *to) 333 { 334 door_arg_t *arg; 335 smb_dr_ctx_t *dec_ctx; 336 smb_dr_ctx_t *enc_ctx; 337 uint32_t rc; 338 339 if ((arg = smb_share_door_clnt_enter()) == NULL) 340 return (NERR_InternalError); 341 342 enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE); 343 smb_dr_put_uint32(enc_ctx, SMB_SHROP_RENAME); 344 smb_dr_put_string(enc_ctx, from); 345 smb_dr_put_string(enc_ctx, to); 346 347 rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size); 348 if (rc != 0) { 349 smb_share_door_clnt_exit(arg, B_FALSE, "encode"); 350 return (NERR_InternalError); 351 } 352 353 if (smb_share_door_call(smb_share_dfd, arg) < 0) { 354 smb_share_door_clnt_exit(arg, B_TRUE, "door call"); 355 return (NERR_InternalError); 356 } 357 358 dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size); 359 if (smb_share_dchk(dec_ctx) != 0) { 360 (void) smb_dr_decode_finish(dec_ctx); 361 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 362 return (NERR_InternalError); 363 } 364 365 rc = smb_dr_get_uint32(dec_ctx); 366 if (smb_dr_decode_finish(dec_ctx) != 0) { 367 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 368 return (NERR_InternalError); 369 } 370 371 smb_share_door_clnt_exit(arg, B_FALSE, NULL); 372 return (rc); 373 } 374 375 uint32_t 376 smb_share_create(smb_share_t *si) 377 { 378 door_arg_t *arg; 379 smb_dr_ctx_t *dec_ctx; 380 smb_dr_ctx_t *enc_ctx; 381 uint32_t rc; 382 383 if ((arg = smb_share_door_clnt_enter()) == NULL) 384 return (NERR_InternalError); 385 386 enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE); 387 smb_dr_put_uint32(enc_ctx, SMB_SHROP_ADD); 388 smb_dr_put_share(enc_ctx, si); 389 390 rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size); 391 if (rc != 0) { 392 smb_share_door_clnt_exit(arg, B_FALSE, "encode"); 393 return (NERR_InternalError); 394 } 395 396 if (smb_share_door_call(smb_share_dfd, arg) < 0) { 397 smb_share_door_clnt_exit(arg, B_TRUE, "door call"); 398 return (NERR_InternalError); 399 } 400 401 dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size); 402 if (smb_share_dchk(dec_ctx) != 0) { 403 (void) smb_dr_decode_finish(dec_ctx); 404 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 405 return (NERR_InternalError); 406 } 407 408 rc = smb_dr_get_uint32(dec_ctx); 409 smb_dr_get_share(dec_ctx, si); 410 if (smb_dr_decode_finish(dec_ctx) != 0) { 411 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 412 return (NERR_InternalError); 413 } 414 415 smb_share_door_clnt_exit(arg, B_FALSE, NULL); 416 return (rc); 417 } 418 419 uint32_t 420 smb_share_modify(smb_share_t *si) 421 { 422 door_arg_t *arg; 423 smb_dr_ctx_t *dec_ctx; 424 smb_dr_ctx_t *enc_ctx; 425 uint32_t rc; 426 427 if ((arg = smb_share_door_clnt_enter()) == NULL) 428 return (NERR_InternalError); 429 430 enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE); 431 smb_dr_put_uint32(enc_ctx, SMB_SHROP_MODIFY); 432 smb_dr_put_share(enc_ctx, si); 433 434 rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size); 435 if (rc != 0) { 436 smb_share_door_clnt_exit(arg, B_FALSE, "encode"); 437 return (NERR_InternalError); 438 } 439 440 if (smb_share_door_call(smb_share_dfd, arg) < 0) { 441 smb_share_door_clnt_exit(arg, B_TRUE, "door call"); 442 return (NERR_InternalError); 443 } 444 445 dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size); 446 if (smb_share_dchk(dec_ctx) != 0) { 447 (void) smb_dr_decode_finish(dec_ctx); 448 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 449 return (NERR_InternalError); 450 } 451 452 rc = smb_dr_get_uint32(dec_ctx); 453 if (smb_dr_decode_finish(dec_ctx) != 0) { 454 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 455 return (NERR_InternalError); 456 } 457 458 smb_share_door_clnt_exit(arg, B_FALSE, NULL); 459 return (rc); 460 } 461