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 2010 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 #include <smbsrv/libsmb.h> 41 #include <smbsrv/smb_share.h> 42 #include <smbsrv/smbinfo.h> 43 #include "smbd.h" 44 45 #define SMB_SHARE_DSRV_VERSION 1 46 #define SMB_SHARE_DSRV_COOKIE ((void*)(0xdeadbeef^SMB_SHARE_DSRV_VERSION)) 47 48 static int smb_share_dsrv_fd = -1; 49 static pthread_mutex_t smb_share_dsrv_mtx = PTHREAD_MUTEX_INITIALIZER; 50 static smbd_door_t smb_share_sdh; 51 52 static void smbd_share_dispatch(void *, char *, size_t, door_desc_t *, uint_t); 53 static int smbd_share_enum(smb_enumshare_info_t *esi); 54 55 /* 56 * Start the LanMan share door service. 57 * Returns 0 on success. Otherwise, -1. 58 */ 59 int 60 smbd_share_start(void) 61 { 62 int newfd; 63 64 (void) pthread_mutex_lock(&smb_share_dsrv_mtx); 65 66 if (smb_share_dsrv_fd != -1) { 67 syslog(LOG_ERR, "smbd_share_start: duplicate"); 68 (void) pthread_mutex_unlock(&smb_share_dsrv_mtx); 69 return (smb_share_dsrv_fd); 70 } 71 72 smbd_door_init(&smb_share_sdh, "share"); 73 74 if ((smb_share_dsrv_fd = door_create(smbd_share_dispatch, 75 SMB_SHARE_DSRV_COOKIE, (DOOR_UNREF | DOOR_REFUSE_DESC))) < 0) { 76 syslog(LOG_ERR, "smbd_share_start: door_create: %s", 77 strerror(errno)); 78 (void) pthread_mutex_unlock(&smb_share_dsrv_mtx); 79 return (-1); 80 } 81 82 (void) unlink(SMB_SHARE_DNAME); 83 84 if ((newfd = creat(SMB_SHARE_DNAME, 0644)) < 0) { 85 syslog(LOG_ERR, "smbd_share_start: open: %s", 86 strerror(errno)); 87 (void) door_revoke(smb_share_dsrv_fd); 88 smb_share_dsrv_fd = -1; 89 (void) pthread_mutex_unlock(&smb_share_dsrv_mtx); 90 return (-1); 91 } 92 93 (void) close(newfd); 94 (void) fdetach(SMB_SHARE_DNAME); 95 96 if (fattach(smb_share_dsrv_fd, SMB_SHARE_DNAME) < 0) { 97 syslog(LOG_ERR, "smbd_share_start: fattach: %s", 98 strerror(errno)); 99 (void) door_revoke(smb_share_dsrv_fd); 100 smb_share_dsrv_fd = -1; 101 (void) pthread_mutex_unlock(&smb_share_dsrv_mtx); 102 return (-1); 103 } 104 105 (void) pthread_mutex_unlock(&smb_share_dsrv_mtx); 106 return (smb_share_dsrv_fd); 107 } 108 109 /* 110 * Stop the LanMan share door service. 111 */ 112 void 113 smbd_share_stop(void) 114 { 115 (void) pthread_mutex_lock(&smb_share_dsrv_mtx); 116 117 smbd_door_fini(&smb_share_sdh); 118 119 if (smb_share_dsrv_fd != -1) { 120 (void) fdetach(SMB_SHARE_DNAME); 121 (void) door_revoke(smb_share_dsrv_fd); 122 smb_share_dsrv_fd = -1; 123 } 124 125 (void) pthread_mutex_unlock(&smb_share_dsrv_mtx); 126 } 127 128 /* 129 * This function with which the LMSHARE door is associated 130 * will invoke the appropriate CIFS share management function 131 * based on the request type of the door call. 132 */ 133 /*ARGSUSED*/ 134 static void 135 smbd_share_dispatch(void *cookie, char *ptr, size_t size, door_desc_t *dp, 136 uint_t n_desc) 137 { 138 uint32_t rc; 139 int req_type; 140 char buf[SMB_SHARE_DSIZE]; 141 unsigned int used; 142 smb_dr_ctx_t *dec_ctx; 143 smb_dr_ctx_t *enc_ctx; 144 unsigned int dec_status; 145 unsigned int enc_status; 146 char *sharename, *sharename2; 147 smb_share_t lmshr_info; 148 smb_shrlist_t lmshr_list; 149 smb_enumshare_info_t esi; 150 int offset; 151 smb_inaddr_t ipaddr; 152 int exec_type; 153 smb_execsub_info_t subs; 154 155 smbd_door_enter(&smb_share_sdh); 156 157 if ((cookie != SMB_SHARE_DSRV_COOKIE) || (ptr == NULL) || 158 (size < sizeof (uint32_t))) { 159 smbd_door_return(&smb_share_sdh, NULL, 0, NULL, 0); 160 } 161 162 dec_ctx = smb_dr_decode_start(ptr, size); 163 enc_ctx = smb_dr_encode_start(buf, sizeof (buf)); 164 req_type = smb_dr_get_uint32(dec_ctx); 165 166 switch (req_type) { 167 case SMB_SHROP_NUM_SHARES: 168 if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) 169 goto decode_error; 170 171 rc = smb_shr_count(); 172 smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS); 173 smb_dr_put_uint32(enc_ctx, rc); 174 break; 175 176 case SMB_SHROP_DELETE: 177 sharename = smb_dr_get_string(dec_ctx); 178 179 if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) { 180 smb_dr_free_string(sharename); 181 goto decode_error; 182 } 183 184 rc = smb_shr_remove(sharename); 185 smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS); 186 smb_dr_put_uint32(enc_ctx, rc); 187 smb_dr_free_string(sharename); 188 break; 189 190 case SMB_SHROP_RENAME: 191 sharename = smb_dr_get_string(dec_ctx); 192 sharename2 = smb_dr_get_string(dec_ctx); 193 194 if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) { 195 smb_dr_free_string(sharename); 196 smb_dr_free_string(sharename2); 197 goto decode_error; 198 } 199 200 rc = smb_shr_rename(sharename, sharename2); 201 smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS); 202 smb_dr_put_uint32(enc_ctx, rc); 203 smb_dr_free_string(sharename); 204 smb_dr_free_string(sharename2); 205 break; 206 207 case SMB_SHROP_GETINFO: 208 sharename = smb_dr_get_string(dec_ctx); 209 (void) smb_dr_get_buf(dec_ctx, (unsigned char *)&ipaddr, 210 sizeof (smb_inaddr_t)); 211 if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) { 212 smb_dr_free_string(sharename); 213 goto decode_error; 214 } 215 rc = smb_shr_get(sharename, &lmshr_info); 216 if (rc == NERR_Success) 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 = smbd_share_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 command", 305 (exec_type == SMB_SHR_UNMAP) ? "unmap" : "map"); 306 307 smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS); 308 smb_dr_put_uint32(enc_ctx, rc); 309 smb_dr_free_string(sharename); 310 smb_dr_free_string(subs.e_winname); 311 smb_dr_free_string(subs.e_userdom); 312 smb_dr_free_string(subs.e_cli_netbiosname); 313 break; 314 315 default: 316 dec_status = smb_dr_decode_finish(dec_ctx); 317 goto decode_error; 318 } 319 320 if ((enc_status = smb_dr_encode_finish(enc_ctx, &used)) != 0) { 321 enc_ctx = smb_dr_encode_start(buf, sizeof (buf)); 322 smb_dr_put_int32(enc_ctx, SMB_SHARE_DERROR); 323 smb_dr_put_uint32(enc_ctx, enc_status); 324 (void) smb_dr_encode_finish(enc_ctx, &used); 325 } 326 327 smbd_door_return(&smb_share_sdh, buf, used, NULL, 0); 328 return; 329 330 decode_error: 331 smb_dr_put_int32(enc_ctx, SMB_SHARE_DERROR); 332 smb_dr_put_uint32(enc_ctx, dec_status); 333 (void) smb_dr_encode_finish(enc_ctx, &used); 334 smbd_door_return(&smb_share_sdh, buf, used, NULL, 0); 335 } 336 337 /* 338 * This function builds a response for a NetShareEnum RAP request which 339 * originates from smbsrv kernel module. A response buffer is allocated 340 * with the specified size in esi->es_bufsize. List of shares is scanned 341 * twice. In the first round the total number of shares which their OEM 342 * name is shorter than 13 chars (esi->es_ntotal) and also the number of 343 * shares that fit in the given buffer are calculated. In the second 344 * round the shares data are encoded in the buffer. 345 * 346 * The data associated with each share has two parts, a fixed size part and 347 * a variable size part which is share's comment. The outline of the response 348 * buffer is so that fixed part for all the shares will appear first and follows 349 * with the comments for all those shares and that's why the data cannot be 350 * encoded in one round without unnecessarily complicating the code. 351 */ 352 static int 353 smbd_share_enum(smb_enumshare_info_t *esi) 354 { 355 smb_shriter_t shi; 356 smb_share_t *si; 357 int remained; 358 uint16_t infolen = 0; 359 uint16_t cmntlen = 0; 360 uint16_t sharelen; 361 uint16_t clen; 362 uint32_t cmnt_offs; 363 smb_msgbuf_t info_mb; 364 smb_msgbuf_t cmnt_mb; 365 boolean_t autohome_added = B_FALSE; 366 367 esi->es_ntotal = esi->es_nsent = 0; 368 369 if ((esi->es_buf = malloc(esi->es_bufsize)) == NULL) 370 return (NERR_InternalError); 371 372 bzero(esi->es_buf, esi->es_bufsize); 373 remained = esi->es_bufsize; 374 375 /* Do the necessary calculations in the first round */ 376 smb_shr_iterinit(&shi); 377 378 while ((si = smb_shr_iterate(&shi)) != NULL) { 379 if (si->shr_flags & SMB_SHRF_LONGNAME) 380 continue; 381 382 if ((si->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) { 383 if (strcasecmp(esi->es_username, si->shr_name) == 0) 384 autohome_added = B_TRUE; 385 else 386 continue; 387 } 388 389 esi->es_ntotal++; 390 391 if (remained <= 0) 392 continue; 393 394 clen = strlen(si->shr_cmnt) + 1; 395 sharelen = SHARE_INFO_1_SIZE + clen; 396 397 if (sharelen <= remained) { 398 infolen += SHARE_INFO_1_SIZE; 399 cmntlen += clen; 400 } 401 402 remained -= sharelen; 403 } 404 405 esi->es_datasize = infolen + cmntlen; 406 407 smb_msgbuf_init(&info_mb, (uint8_t *)esi->es_buf, infolen, 0); 408 smb_msgbuf_init(&cmnt_mb, (uint8_t *)esi->es_buf + infolen, cmntlen, 0); 409 cmnt_offs = infolen; 410 411 /* Encode the data in the second round */ 412 smb_shr_iterinit(&shi); 413 autohome_added = B_FALSE; 414 415 while ((si = smb_shr_iterate(&shi)) != NULL) { 416 if (si->shr_flags & SMB_SHRF_LONGNAME) 417 continue; 418 419 if ((si->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) { 420 if (strcasecmp(esi->es_username, si->shr_name) == 0) 421 autohome_added = B_TRUE; 422 else 423 continue; 424 } 425 426 if (smb_msgbuf_encode(&info_mb, "13c.wl", 427 si->shr_oemname, si->shr_type, cmnt_offs) < 0) 428 break; 429 430 if (smb_msgbuf_encode(&cmnt_mb, "s", si->shr_cmnt) < 0) 431 break; 432 433 cmnt_offs += strlen(si->shr_cmnt) + 1; 434 esi->es_nsent++; 435 } 436 437 smb_msgbuf_term(&info_mb); 438 smb_msgbuf_term(&cmnt_mb); 439 440 return (NERR_Success); 441 } 442