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 (dec_ctx == NULL || smb_share_dchk(dec_ctx) != 0) { 228 if (dec_ctx != NULL) 229 (void) smb_dr_decode_finish(dec_ctx); 230 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 231 return (NERR_InternalError); 232 } 233 234 (void) smb_dr_get_buf(dec_ctx, (unsigned char *)list, 235 sizeof (smb_shrlist_t)); 236 if (smb_dr_decode_finish(dec_ctx) != 0) { 237 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 238 return (NERR_InternalError); 239 } 240 241 smb_share_door_clnt_exit(arg, B_FALSE, NULL); 242 return (NERR_Success); 243 } 244 245 int 246 smb_share_count(void) 247 { 248 door_arg_t *arg; 249 smb_dr_ctx_t *dec_ctx; 250 smb_dr_ctx_t *enc_ctx; 251 uint32_t num_shares; 252 int rc; 253 254 if ((arg = smb_share_door_clnt_enter()) == NULL) 255 return (-1); 256 257 enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE); 258 smb_dr_put_uint32(enc_ctx, SMB_SHROP_NUM_SHARES); 259 260 rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size); 261 if (rc != 0) { 262 smb_share_door_clnt_exit(arg, B_FALSE, "encode"); 263 return (-1); 264 } 265 266 if (smb_share_door_call(smb_share_dfd, arg) < 0) { 267 smb_share_door_clnt_exit(arg, B_TRUE, "door call"); 268 return (-1); 269 } 270 271 dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size); 272 if (dec_ctx == NULL || smb_share_dchk(dec_ctx) != 0) { 273 if (dec_ctx != NULL) 274 (void) smb_dr_decode_finish(dec_ctx); 275 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 276 return (-1); 277 } 278 279 num_shares = smb_dr_get_uint32(dec_ctx); 280 if (smb_dr_decode_finish(dec_ctx) != 0) { 281 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 282 return (-1); 283 } 284 285 smb_share_door_clnt_exit(arg, B_FALSE, NULL); 286 return (num_shares); 287 } 288 289 uint32_t 290 smb_share_delete(char *share_name) 291 { 292 door_arg_t *arg; 293 smb_dr_ctx_t *dec_ctx; 294 smb_dr_ctx_t *enc_ctx; 295 uint32_t rc; 296 297 if ((arg = smb_share_door_clnt_enter()) == NULL) 298 return (NERR_InternalError); 299 300 enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE); 301 smb_dr_put_uint32(enc_ctx, SMB_SHROP_DELETE); 302 smb_dr_put_string(enc_ctx, share_name); 303 304 rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size); 305 if (rc != 0) { 306 smb_share_door_clnt_exit(arg, B_FALSE, "encode"); 307 return (NERR_InternalError); 308 } 309 310 if (smb_share_door_call(smb_share_dfd, arg) < 0) { 311 smb_share_door_clnt_exit(arg, B_TRUE, "door call"); 312 return (NERR_InternalError); 313 } 314 315 dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size); 316 if (dec_ctx == NULL || smb_share_dchk(dec_ctx) != 0) { 317 if (dec_ctx != NULL) 318 (void) smb_dr_decode_finish(dec_ctx); 319 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 320 return (NERR_InternalError); 321 } 322 323 rc = smb_dr_get_uint32(dec_ctx); 324 if (smb_dr_decode_finish(dec_ctx) != 0) { 325 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 326 return (NERR_InternalError); 327 } 328 329 smb_share_door_clnt_exit(arg, B_FALSE, NULL); 330 return (rc); 331 332 } 333 334 uint32_t 335 smb_share_rename(char *from, char *to) 336 { 337 door_arg_t *arg; 338 smb_dr_ctx_t *dec_ctx; 339 smb_dr_ctx_t *enc_ctx; 340 uint32_t rc; 341 342 if ((arg = smb_share_door_clnt_enter()) == NULL) 343 return (NERR_InternalError); 344 345 enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE); 346 smb_dr_put_uint32(enc_ctx, SMB_SHROP_RENAME); 347 smb_dr_put_string(enc_ctx, from); 348 smb_dr_put_string(enc_ctx, to); 349 350 rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size); 351 if (rc != 0) { 352 smb_share_door_clnt_exit(arg, B_FALSE, "encode"); 353 return (NERR_InternalError); 354 } 355 356 if (smb_share_door_call(smb_share_dfd, arg) < 0) { 357 smb_share_door_clnt_exit(arg, B_TRUE, "door call"); 358 return (NERR_InternalError); 359 } 360 361 dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size); 362 if (dec_ctx == NULL || smb_share_dchk(dec_ctx) != 0) { 363 if (dec_ctx != NULL) 364 (void) smb_dr_decode_finish(dec_ctx); 365 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 366 return (NERR_InternalError); 367 } 368 369 rc = smb_dr_get_uint32(dec_ctx); 370 if (smb_dr_decode_finish(dec_ctx) != 0) { 371 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 372 return (NERR_InternalError); 373 } 374 375 smb_share_door_clnt_exit(arg, B_FALSE, NULL); 376 return (rc); 377 } 378 379 uint32_t 380 smb_share_create(smb_share_t *si) 381 { 382 door_arg_t *arg; 383 smb_dr_ctx_t *dec_ctx; 384 smb_dr_ctx_t *enc_ctx; 385 uint32_t rc; 386 387 if ((arg = smb_share_door_clnt_enter()) == NULL) 388 return (NERR_InternalError); 389 390 enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE); 391 smb_dr_put_uint32(enc_ctx, SMB_SHROP_ADD); 392 smb_dr_put_share(enc_ctx, si); 393 394 rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size); 395 if (rc != 0) { 396 smb_share_door_clnt_exit(arg, B_FALSE, "encode"); 397 return (NERR_InternalError); 398 } 399 400 if (smb_share_door_call(smb_share_dfd, arg) < 0) { 401 smb_share_door_clnt_exit(arg, B_TRUE, "door call"); 402 return (NERR_InternalError); 403 } 404 405 dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size); 406 if (dec_ctx == NULL || smb_share_dchk(dec_ctx) != 0) { 407 if (dec_ctx != NULL) 408 (void) smb_dr_decode_finish(dec_ctx); 409 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 410 return (NERR_InternalError); 411 } 412 413 rc = smb_dr_get_uint32(dec_ctx); 414 smb_dr_get_share(dec_ctx, si); 415 if (smb_dr_decode_finish(dec_ctx) != 0) { 416 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 417 return (NERR_InternalError); 418 } 419 420 smb_share_door_clnt_exit(arg, B_FALSE, NULL); 421 return (rc); 422 } 423 424 uint32_t 425 smb_share_modify(smb_share_t *si) 426 { 427 door_arg_t *arg; 428 smb_dr_ctx_t *dec_ctx; 429 smb_dr_ctx_t *enc_ctx; 430 uint32_t rc; 431 432 if ((arg = smb_share_door_clnt_enter()) == NULL) 433 return (NERR_InternalError); 434 435 enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE); 436 smb_dr_put_uint32(enc_ctx, SMB_SHROP_MODIFY); 437 smb_dr_put_share(enc_ctx, si); 438 439 rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size); 440 if (rc != 0) { 441 smb_share_door_clnt_exit(arg, B_FALSE, "encode"); 442 return (NERR_InternalError); 443 } 444 445 if (smb_share_door_call(smb_share_dfd, arg) < 0) { 446 smb_share_door_clnt_exit(arg, B_TRUE, "door call"); 447 return (NERR_InternalError); 448 } 449 450 dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size); 451 if (dec_ctx == NULL || smb_share_dchk(dec_ctx) != 0) { 452 if (dec_ctx != NULL) 453 (void) smb_dr_decode_finish(dec_ctx); 454 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 455 return (NERR_InternalError); 456 } 457 458 rc = smb_dr_get_uint32(dec_ctx); 459 if (smb_dr_decode_finish(dec_ctx) != 0) { 460 smb_share_door_clnt_exit(arg, B_FALSE, "decode"); 461 return (NERR_InternalError); 462 } 463 464 smb_share_door_clnt_exit(arg, B_FALSE, NULL); 465 return (rc); 466 } 467