Home | History | Annotate | Download | only in smbd
      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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * LanMan share door server
     28  */
     29 
     30 #include <door.h>
     31 #include <unistd.h>
     32 #include <sys/types.h>
     33 #include <sys/stat.h>
     34 #include <fcntl.h>
     35 #include <errno.h>
     36 #include <syslog.h>
     37 #include <string.h>
     38 #include <strings.h>
     39 #include <pthread.h>
     40 
     41 #include <smbsrv/libsmb.h>
     42 
     43 #include <smbsrv/smb_share.h>
     44 #include <smbsrv/smbinfo.h>
     45 
     46 #define	SMB_SHARE_DSRV_VERSION	1
     47 #define	SMB_SHARE_DSRV_COOKIE	((void*)(0xdeadbeef^SMB_SHARE_DSRV_VERSION))
     48 
     49 static int smb_share_dsrv_fd = -1;
     50 static pthread_mutex_t smb_share_dsrv_mtx = PTHREAD_MUTEX_INITIALIZER;
     51 
     52 static void smb_share_dsrv_dispatch(void *, char *, size_t, door_desc_t *,
     53     uint_t);
     54 static int smb_share_dsrv_enum(smb_enumshare_info_t *esi);
     55 
     56 /*
     57  * smb_share_dsrv_start
     58  *
     59  * Start the LanMan share door service.
     60  * Returns 0 on success. Otherwise, -1.
     61  */
     62 int
     63 smb_share_dsrv_start(void)
     64 {
     65 	int	newfd;
     66 
     67 	(void) pthread_mutex_lock(&smb_share_dsrv_mtx);
     68 
     69 	if (smb_share_dsrv_fd != -1) {
     70 		syslog(LOG_ERR, "smb_share_dsrv_start: duplicate");
     71 		(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
     72 		return (smb_share_dsrv_fd);
     73 	}
     74 
     75 	if ((smb_share_dsrv_fd = door_create(smb_share_dsrv_dispatch,
     76 	    SMB_SHARE_DSRV_COOKIE, (DOOR_UNREF | DOOR_REFUSE_DESC))) < 0) {
     77 		syslog(LOG_ERR, "smb_share_dsrv_start: door_create: %s",
     78 		    strerror(errno));
     79 		(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
     80 		return (-1);
     81 	}
     82 
     83 	(void) unlink(SMB_SHARE_DNAME);
     84 
     85 	if ((newfd = creat(SMB_SHARE_DNAME, 0644)) < 0) {
     86 		syslog(LOG_ERR, "smb_share_dsrv_start: open: %s",
     87 		    strerror(errno));
     88 		(void) door_revoke(smb_share_dsrv_fd);
     89 		smb_share_dsrv_fd = -1;
     90 		(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
     91 		return (-1);
     92 	}
     93 
     94 	(void) close(newfd);
     95 	(void) fdetach(SMB_SHARE_DNAME);
     96 
     97 	if (fattach(smb_share_dsrv_fd, SMB_SHARE_DNAME) < 0) {
     98 		syslog(LOG_ERR, "smb_share_dsrv_start: fattach: %s",
     99 		    strerror(errno));
    100 		(void) door_revoke(smb_share_dsrv_fd);
    101 		smb_share_dsrv_fd = -1;
    102 		(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
    103 		return (-1);
    104 	}
    105 
    106 	(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
    107 	return (smb_share_dsrv_fd);
    108 }
    109 
    110 /*
    111  * smb_share_dsrv_stop
    112  *
    113  * Stop the LanMan share door service.
    114  */
    115 void
    116 smb_share_dsrv_stop(void)
    117 {
    118 	(void) pthread_mutex_lock(&smb_share_dsrv_mtx);
    119 
    120 	if (smb_share_dsrv_fd != -1) {
    121 		(void) fdetach(SMB_SHARE_DNAME);
    122 		(void) door_revoke(smb_share_dsrv_fd);
    123 		smb_share_dsrv_fd = -1;
    124 	}
    125 
    126 	(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
    127 }
    128 
    129 /*
    130  * smb_share_dsrv_dispatch
    131  *
    132  * This function with which the LMSHARE door is associated
    133  * will invoke the appropriate CIFS share management function
    134  * based on the request type of the door call.
    135  */
    136 /*ARGSUSED*/
    137 static void
    138 smb_share_dsrv_dispatch(void *cookie, char *ptr, size_t size, door_desc_t *dp,
    139     uint_t n_desc)
    140 {
    141 	uint32_t rc;
    142 	int req_type;
    143 	char buf[SMB_SHARE_DSIZE];
    144 	unsigned int used;
    145 	smb_dr_ctx_t *dec_ctx;
    146 	smb_dr_ctx_t *enc_ctx;
    147 	unsigned int dec_status;
    148 	unsigned int enc_status;
    149 	char *sharename, *sharename2;
    150 	smb_share_t lmshr_info;
    151 	smb_shrlist_t lmshr_list;
    152 	smb_enumshare_info_t esi;
    153 	int offset;
    154 	smb_inaddr_t ipaddr;
    155 	int exec_type;
    156 	smb_execsub_info_t subs;
    157 
    158 	if ((cookie != SMB_SHARE_DSRV_COOKIE) || (ptr == NULL) ||
    159 	    (size < sizeof (uint32_t))) {
    160 		(void) door_return(NULL, 0, NULL, 0);
    161 	}
    162 
    163 	dec_ctx = smb_dr_decode_start(ptr, size);
    164 	enc_ctx = smb_dr_encode_start(buf, sizeof (buf));
    165 	req_type = smb_dr_get_uint32(dec_ctx);
    166 
    167 	switch (req_type) {
    168 	case SMB_SHROP_NUM_SHARES:
    169 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
    170 			goto decode_error;
    171 
    172 		rc = smb_shr_count();
    173 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
    174 		smb_dr_put_uint32(enc_ctx, rc);
    175 		break;
    176 
    177 	case SMB_SHROP_DELETE:
    178 		sharename = smb_dr_get_string(dec_ctx);
    179 
    180 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
    181 			smb_dr_free_string(sharename);
    182 			goto decode_error;
    183 		}
    184 
    185 		rc = smb_shr_remove(sharename);
    186 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
    187 		smb_dr_put_uint32(enc_ctx, rc);
    188 		smb_dr_free_string(sharename);
    189 		break;
    190 
    191 	case SMB_SHROP_RENAME:
    192 		sharename = smb_dr_get_string(dec_ctx);
    193 		sharename2 = smb_dr_get_string(dec_ctx);
    194 
    195 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
    196 			smb_dr_free_string(sharename);
    197 			smb_dr_free_string(sharename2);
    198 			goto decode_error;
    199 		}
    200 
    201 		rc = smb_shr_rename(sharename, sharename2);
    202 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
    203 		smb_dr_put_uint32(enc_ctx, rc);
    204 		smb_dr_free_string(sharename);
    205 		smb_dr_free_string(sharename2);
    206 		break;
    207 
    208 	case SMB_SHROP_GETINFO:
    209 		sharename = smb_dr_get_string(dec_ctx);
    210 		(void) smb_dr_get_buf(dec_ctx, (unsigned char *)&ipaddr,
    211 		    sizeof (smb_inaddr_t));
    212 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
    213 			smb_dr_free_string(sharename);
    214 			goto decode_error;
    215 		}
    216 		rc = smb_shr_get(sharename, &lmshr_info);
    217 		smb_shr_hostaccess(&lmshr_info, &ipaddr);
    218 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
    219 		smb_dr_put_uint32(enc_ctx, rc);
    220 		smb_dr_put_share(enc_ctx, &lmshr_info);
    221 		smb_dr_free_string(sharename);
    222 		break;
    223 
    224 	case SMB_SHROP_ADD:
    225 		smb_dr_get_share(dec_ctx, &lmshr_info);
    226 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
    227 			goto decode_error;
    228 
    229 		rc = smb_shr_add(&lmshr_info);
    230 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
    231 		smb_dr_put_uint32(enc_ctx, rc);
    232 		smb_dr_put_share(enc_ctx, &lmshr_info);
    233 		break;
    234 
    235 	case SMB_SHROP_MODIFY:
    236 		smb_dr_get_share(dec_ctx, &lmshr_info);
    237 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
    238 			goto decode_error;
    239 		}
    240 
    241 		rc = smb_shr_modify(&lmshr_info);
    242 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
    243 		smb_dr_put_uint32(enc_ctx, rc);
    244 
    245 		break;
    246 
    247 	case SMB_SHROP_LIST:
    248 		offset = smb_dr_get_int32(dec_ctx);
    249 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
    250 			goto decode_error;
    251 
    252 		smb_shr_list(offset, &lmshr_list);
    253 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
    254 		smb_dr_put_buf(enc_ctx, (unsigned char *)&lmshr_list,
    255 		    sizeof (smb_shrlist_t));
    256 		break;
    257 
    258 	case SMB_SHROP_ENUM:
    259 		esi.es_bufsize = smb_dr_get_ushort(dec_ctx);
    260 		esi.es_username = smb_dr_get_string(dec_ctx);
    261 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
    262 			smb_dr_free_string(esi.es_username);
    263 			goto decode_error;
    264 		}
    265 
    266 		rc = smb_share_dsrv_enum(&esi);
    267 
    268 		smb_dr_free_string(esi.es_username);
    269 
    270 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
    271 		smb_dr_put_uint32(enc_ctx, rc);
    272 		if (rc == NERR_Success) {
    273 			smb_dr_put_ushort(enc_ctx, esi.es_ntotal);
    274 			smb_dr_put_ushort(enc_ctx, esi.es_nsent);
    275 			smb_dr_put_ushort(enc_ctx, esi.es_datasize);
    276 			smb_dr_put_buf(enc_ctx,
    277 			    (unsigned char *)esi.es_buf, esi.es_bufsize);
    278 			free(esi.es_buf);
    279 		}
    280 		break;
    281 
    282 	case SMB_SHROP_EXEC:
    283 		sharename = smb_dr_get_string(dec_ctx);
    284 		subs.e_winname = smb_dr_get_string(dec_ctx);
    285 		subs.e_userdom = smb_dr_get_string(dec_ctx);
    286 		(void) smb_dr_get_buf(dec_ctx,
    287 		    (unsigned char *)&subs.e_srv_ipaddr, sizeof (smb_inaddr_t));
    288 		(void) smb_dr_get_buf(dec_ctx,
    289 		    (unsigned char *)&subs.e_cli_ipaddr, sizeof (smb_inaddr_t));
    290 		subs.e_cli_netbiosname = smb_dr_get_string(dec_ctx);
    291 		subs.e_uid = smb_dr_get_int32(dec_ctx);
    292 		exec_type = smb_dr_get_int32(dec_ctx);
    293 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
    294 			smb_dr_free_string(sharename);
    295 			smb_dr_free_string(subs.e_winname);
    296 			smb_dr_free_string(subs.e_userdom);
    297 			smb_dr_free_string(subs.e_cli_netbiosname);
    298 			goto decode_error;
    299 		}
    300 
    301 		rc = smb_shr_exec(sharename, &subs, exec_type);
    302 
    303 		if (rc != 0)
    304 			syslog(LOG_NOTICE, "Failed to execute %s" \
    305 			    " command.\n",
    306 			    (exec_type == SMB_SHR_UNMAP) ? "unmap" : "map");
    307 
    308 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
    309 		smb_dr_put_uint32(enc_ctx, rc);
    310 		smb_dr_free_string(sharename);
    311 		smb_dr_free_string(subs.e_winname);
    312 		smb_dr_free_string(subs.e_userdom);
    313 		smb_dr_free_string(subs.e_cli_netbiosname);
    314 		break;
    315 
    316 	default:
    317 		dec_status = smb_dr_decode_finish(dec_ctx);
    318 		goto decode_error;
    319 	}
    320 
    321 	if ((enc_status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
    322 		enc_ctx = smb_dr_encode_start(buf, sizeof (buf));
    323 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DERROR);
    324 		smb_dr_put_uint32(enc_ctx, enc_status);
    325 		(void) smb_dr_encode_finish(enc_ctx, &used);
    326 	}
    327 
    328 	(void) door_return(buf, used, NULL, 0);
    329 	return;
    330 
    331 decode_error:
    332 	smb_dr_put_int32(enc_ctx, SMB_SHARE_DERROR);
    333 	smb_dr_put_uint32(enc_ctx, dec_status);
    334 	(void) smb_dr_encode_finish(enc_ctx, &used);
    335 	(void) door_return(buf, used, NULL, 0);
    336 }
    337 
    338 /*
    339  * smb_share_dsrv_enum
    340  *
    341  * This function builds a response for a NetShareEnum RAP request which
    342  * originates from smbsrv kernel module. A response buffer is allocated
    343  * with the specified size in esi->es_bufsize. List of shares is scanned
    344  * twice. In the first round the total number of shares which their OEM
    345  * name is shorter than 13 chars (esi->es_ntotal) and also the number of
    346  * shares that fit in the given buffer are calculated. In the second
    347  * round the shares data are encoded in the buffer.
    348  *
    349  * The data associated with each share has two parts, a fixed size part and
    350  * a variable size part which is share's comment. The outline of the response
    351  * buffer is so that fixed part for all the shares will appear first and follows
    352  * with the comments for all those shares and that's why the data cannot be
    353  * encoded in one round without unnecessarily complicating the code.
    354  */
    355 static int
    356 smb_share_dsrv_enum(smb_enumshare_info_t *esi)
    357 {
    358 	smb_shriter_t shi;
    359 	smb_share_t *si;
    360 	int remained;
    361 	uint16_t infolen = 0;
    362 	uint16_t cmntlen = 0;
    363 	uint16_t sharelen;
    364 	uint16_t clen;
    365 	uint32_t cmnt_offs;
    366 	smb_msgbuf_t info_mb;
    367 	smb_msgbuf_t cmnt_mb;
    368 	boolean_t autohome_added = B_FALSE;
    369 
    370 	esi->es_ntotal = esi->es_nsent = 0;
    371 
    372 	if ((esi->es_buf = malloc(esi->es_bufsize)) == NULL)
    373 		return (NERR_InternalError);
    374 
    375 	bzero(esi->es_buf, esi->es_bufsize);
    376 	remained = esi->es_bufsize;
    377 
    378 	/* Do the necessary calculations in the first round */
    379 	smb_shr_iterinit(&shi);
    380 
    381 	while ((si = smb_shr_iterate(&shi)) != NULL) {
    382 		if (si->shr_flags & SMB_SHRF_LONGNAME)
    383 			continue;
    384 
    385 		if ((si->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) {
    386 			if (strcasecmp(esi->es_username, si->shr_name) == 0)
    387 				autohome_added = B_TRUE;
    388 			else
    389 				continue;
    390 		}
    391 
    392 		esi->es_ntotal++;
    393 
    394 		if (remained <= 0)
    395 			continue;
    396 
    397 		clen = strlen(si->shr_cmnt) + 1;
    398 		sharelen = SHARE_INFO_1_SIZE + clen;
    399 
    400 		if (sharelen <= remained) {
    401 			infolen += SHARE_INFO_1_SIZE;
    402 			cmntlen += clen;
    403 		}
    404 
    405 		remained -= sharelen;
    406 	}
    407 
    408 	esi->es_datasize = infolen + cmntlen;
    409 
    410 	smb_msgbuf_init(&info_mb, (uint8_t *)esi->es_buf, infolen, 0);
    411 	smb_msgbuf_init(&cmnt_mb, (uint8_t *)esi->es_buf + infolen, cmntlen, 0);
    412 	cmnt_offs = infolen;
    413 
    414 	/* Encode the data in the second round */
    415 	smb_shr_iterinit(&shi);
    416 	autohome_added = B_FALSE;
    417 
    418 	while ((si = smb_shr_iterate(&shi)) != NULL) {
    419 		if (si->shr_flags & SMB_SHRF_LONGNAME)
    420 			continue;
    421 
    422 		if ((si->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) {
    423 			if (strcasecmp(esi->es_username, si->shr_name) == 0)
    424 				autohome_added = B_TRUE;
    425 			else
    426 				continue;
    427 		}
    428 
    429 		if (smb_msgbuf_encode(&info_mb, "13c.wl",
    430 		    si->shr_oemname, si->shr_type, cmnt_offs) < 0)
    431 			break;
    432 
    433 		if (smb_msgbuf_encode(&cmnt_mb, "s", si->shr_cmnt) < 0)
    434 			break;
    435 
    436 		cmnt_offs += strlen(si->shr_cmnt) + 1;
    437 		esi->es_nsent++;
    438 	}
    439 
    440 	smb_msgbuf_term(&info_mb);
    441 	smb_msgbuf_term(&cmnt_mb);
    442 
    443 	return (NERR_Success);
    444 }
    445