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 156 if ((cookie != SMB_SHARE_DSRV_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 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 smb_shr_hostaccess(&lmshr_info, &ipaddr); 216 smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS); 217 smb_dr_put_uint32(enc_ctx, rc); 218 smb_dr_put_share(enc_ctx, &lmshr_info); 219 smb_dr_free_string(sharename); 220 break; 221 222 case SMB_SHROP_ADD: 223 smb_dr_get_share(dec_ctx, &lmshr_info); 224 if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) 225 goto decode_error; 226 227 rc = smb_shr_add(&lmshr_info); 228 smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS); 229 smb_dr_put_uint32(enc_ctx, rc); 230 smb_dr_put_share(enc_ctx, &lmshr_info); 231 break; 232 233 case SMB_SHROP_MODIFY: 234 smb_dr_get_share(dec_ctx, &lmshr_info); 235 if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) { 236 goto decode_error; 237 } 238 239 rc = smb_shr_modify(&lmshr_info); 240 smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS); 241 smb_dr_put_uint32(enc_ctx, rc); 242 243 break; 244 245 case SMB_SHROP_LIST: 246 offset = smb_dr_get_int32(dec_ctx); 247 if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) 248 goto decode_error; 249 250 smb_shr_list(offset, &lmshr_list); 251 smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS); 252 smb_dr_put_buf(enc_ctx, (unsigned char *)&lmshr_list, 253 sizeof (smb_shrlist_t)); 254 break; 255 256 case SMB_SHROP_ENUM: 257 esi.es_bufsize = smb_dr_get_ushort(dec_ctx); 258 esi.es_username = smb_dr_get_string(dec_ctx); 259 if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) { 260 smb_dr_free_string(esi.es_username); 261 goto decode_error; 262 } 263 264 rc = smb_share_dsrv_enum(&esi); 265 266 smb_dr_free_string(esi.es_username); 267 268 smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS); 269 smb_dr_put_uint32(enc_ctx, rc); 270 if (rc == NERR_Success) { 271 smb_dr_put_ushort(enc_ctx, esi.es_ntotal); 272 smb_dr_put_ushort(enc_ctx, esi.es_nsent); 273 smb_dr_put_ushort(enc_ctx, esi.es_datasize); 274 smb_dr_put_buf(enc_ctx, 275 (unsigned char *)esi.es_buf, esi.es_bufsize); 276 free(esi.es_buf); 277 } 278 break; 279 280 default: 281 dec_status = smb_dr_decode_finish(dec_ctx); 282 goto decode_error; 283 } 284 285 if ((enc_status = smb_dr_encode_finish(enc_ctx, &used)) != 0) { 286 enc_ctx = smb_dr_encode_start(buf, sizeof (buf)); 287 smb_dr_put_int32(enc_ctx, SMB_SHARE_DERROR); 288 smb_dr_put_uint32(enc_ctx, enc_status); 289 (void) smb_dr_encode_finish(enc_ctx, &used); 290 } 291 292 (void) door_return(buf, used, NULL, 0); 293 return; 294 295 decode_error: 296 smb_dr_put_int32(enc_ctx, SMB_SHARE_DERROR); 297 smb_dr_put_uint32(enc_ctx, dec_status); 298 (void) smb_dr_encode_finish(enc_ctx, &used); 299 (void) door_return(buf, used, NULL, 0); 300 } 301 302 /* 303 * smb_share_dsrv_enum 304 * 305 * This function builds a response for a NetShareEnum RAP request which 306 * originates from smbsrv kernel module. A response buffer is allocated 307 * with the specified size in esi->es_bufsize. List of shares is scanned 308 * twice. In the first round the total number of shares which their OEM 309 * name is shorter than 13 chars (esi->es_ntotal) and also the number of 310 * shares that fit in the given buffer are calculated. In the second 311 * round the shares data are encoded in the buffer. 312 * 313 * The data associated with each share has two parts, a fixed size part and 314 * a variable size part which is share's comment. The outline of the response 315 * buffer is so that fixed part for all the shares will appear first and follows 316 * with the comments for all those shares and that's why the data cannot be 317 * encoded in one round without unnecessarily complicating the code. 318 */ 319 static int 320 smb_share_dsrv_enum(smb_enumshare_info_t *esi) 321 { 322 smb_shriter_t shi; 323 smb_share_t *si; 324 int remained; 325 uint16_t infolen = 0; 326 uint16_t cmntlen = 0; 327 uint16_t sharelen; 328 uint16_t clen; 329 uint32_t cmnt_offs; 330 smb_msgbuf_t info_mb; 331 smb_msgbuf_t cmnt_mb; 332 boolean_t autohome_added = B_FALSE; 333 334 esi->es_ntotal = esi->es_nsent = 0; 335 336 if ((esi->es_buf = malloc(esi->es_bufsize)) == NULL) 337 return (NERR_InternalError); 338 339 bzero(esi->es_buf, esi->es_bufsize); 340 remained = esi->es_bufsize; 341 342 /* Do the necessary calculations in the first round */ 343 smb_shr_iterinit(&shi); 344 345 while ((si = smb_shr_iterate(&shi)) != NULL) { 346 if (si->shr_flags & SMB_SHRF_LONGNAME) 347 continue; 348 349 if ((si->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) { 350 if (strcasecmp(esi->es_username, si->shr_name) == 0) 351 autohome_added = B_TRUE; 352 else 353 continue; 354 } 355 356 esi->es_ntotal++; 357 358 if (remained <= 0) 359 continue; 360 361 clen = strlen(si->shr_cmnt) + 1; 362 sharelen = SHARE_INFO_1_SIZE + clen; 363 364 if (sharelen <= remained) { 365 infolen += SHARE_INFO_1_SIZE; 366 cmntlen += clen; 367 } 368 369 remained -= sharelen; 370 } 371 372 esi->es_datasize = infolen + cmntlen; 373 374 smb_msgbuf_init(&info_mb, (uint8_t *)esi->es_buf, infolen, 0); 375 smb_msgbuf_init(&cmnt_mb, (uint8_t *)esi->es_buf + infolen, cmntlen, 0); 376 cmnt_offs = infolen; 377 378 /* Encode the data in the second round */ 379 smb_shr_iterinit(&shi); 380 autohome_added = B_FALSE; 381 382 while ((si = smb_shr_iterate(&shi)) != NULL) { 383 if (si->shr_flags & SMB_SHRF_LONGNAME) 384 continue; 385 386 if ((si->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) { 387 if (strcasecmp(esi->es_username, si->shr_name) == 0) 388 autohome_added = B_TRUE; 389 else 390 continue; 391 } 392 393 if (smb_msgbuf_encode(&info_mb, "13c.wl", 394 si->shr_oemname, si->shr_type, cmnt_offs) < 0) 395 break; 396 397 if (smb_msgbuf_encode(&cmnt_mb, "s", si->shr_cmnt) < 0) 398 break; 399 400 cmnt_offs += strlen(si->shr_cmnt) + 1; 401 esi->es_nsent++; 402 } 403 404 smb_msgbuf_term(&info_mb); 405 smb_msgbuf_term(&cmnt_mb); 406 407 return (NERR_Success); 408 } 409