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