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