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