Home | History | Annotate | Download | only in smb
      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