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