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 "@(#)smbd_share_doorsvc.c 1.6 08/08/05 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/smb_share.h> 46 #include <smbsrv/smbinfo.h> 47 48 #define SMB_SHARE_DSRV_VERSION 1 49 #define SMB_SHARE_DSRV_COOKIE ((void*)(0xdeadbeef^SMB_SHARE_DSRV_VERSION)) 50 51 static int smb_share_dsrv_fd = -1; 52 static pthread_mutex_t smb_share_dsrv_mtx = PTHREAD_MUTEX_INITIALIZER; 53 54 static void smb_share_dsrv_dispatch(void *, char *, size_t, door_desc_t *, 55 uint_t); 56 static int smb_share_dsrv_enum(smb_enumshare_info_t *esi); 57 58 /* 59 * smb_share_dsrv_start 60 * 61 * Start the LanMan share door service. 62 * Returns 0 on success. Otherwise, -1. 63 */ 64 int 65 smb_share_dsrv_start(void) 66 { 67 int newfd; 68 69 (void) pthread_mutex_lock(&smb_share_dsrv_mtx); 70 71 if (smb_share_dsrv_fd != -1) { 72 syslog(LOG_ERR, "smb_share_dsrv_start: duplicate"); 73 (void) pthread_mutex_unlock(&smb_share_dsrv_mtx); 74 return (smb_share_dsrv_fd); 75 } 76 77 if ((smb_share_dsrv_fd = door_create(smb_share_dsrv_dispatch, 78 SMB_SHARE_DSRV_COOKIE, (DOOR_UNREF | DOOR_REFUSE_DESC))) < 0) { 79 syslog(LOG_ERR, "smb_share_dsrv_start: door_create: %s", 80 strerror(errno)); 81 (void) pthread_mutex_unlock(&smb_share_dsrv_mtx); 82 return (-1); 83 } 84 85 (void) unlink(SMB_SHARE_DNAME); 86 87 if ((newfd = creat(SMB_SHARE_DNAME, 0644)) < 0) { 88 syslog(LOG_ERR, "smb_share_dsrv_start: open: %s", 89 strerror(errno)); 90 (void) door_revoke(smb_share_dsrv_fd); 91 smb_share_dsrv_fd = -1; 92 (void) pthread_mutex_unlock(&smb_share_dsrv_mtx); 93 return (-1); 94 } 95 96 (void) close(newfd); 97 (void) fdetach(SMB_SHARE_DNAME); 98 99 if (fattach(smb_share_dsrv_fd, SMB_SHARE_DNAME) < 0) { 100 syslog(LOG_ERR, "smb_share_dsrv_start: fattach: %s", 101 strerror(errno)); 102 (void) door_revoke(smb_share_dsrv_fd); 103 smb_share_dsrv_fd = -1; 104 (void) pthread_mutex_unlock(&smb_share_dsrv_mtx); 105 return (-1); 106 } 107 108 (void) pthread_mutex_unlock(&smb_share_dsrv_mtx); 109 return (smb_share_dsrv_fd); 110 } 111 112 /* 113 * smb_share_dsrv_stop 114 * 115 * Stop the LanMan share door service. 116 */ 117 void 118 smb_share_dsrv_stop(void) 119 { 120 (void) pthread_mutex_lock(&smb_share_dsrv_mtx); 121 122 if (smb_share_dsrv_fd != -1) { 123 (void) fdetach(SMB_SHARE_DNAME); 124 (void) door_revoke(smb_share_dsrv_fd); 125 smb_share_dsrv_fd = -1; 126 } 127 128 (void) pthread_mutex_unlock(&smb_share_dsrv_mtx); 129 } 130 131 /* 132 * smb_share_dsrv_dispatch 133 * 134 * This function with which the LMSHARE door is associated 135 * will invoke the appropriate CIFS share management function 136 * based on the request type of the door call. 137 */ 138 /*ARGSUSED*/ 139 static void 140 smb_share_dsrv_dispatch(void *cookie, char *ptr, size_t size, door_desc_t *dp, 141 uint_t n_desc) 142 { 143 uint32_t rc; 144 int req_type; 145 char buf[SMB_SHARE_DSIZE]; 146 unsigned int used; 147 smb_dr_ctx_t *dec_ctx; 148 smb_dr_ctx_t *enc_ctx; 149 unsigned int dec_status; 150 unsigned int enc_status; 151 char *sharename, *sharename2; 152 char *cmnt, *ad_container; 153 smb_share_t lmshr_info; 154 smb_shrlist_t lmshr_list; 155 smb_enumshare_info_t esi; 156 int offset; 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_delete(sharename, B_FALSE); 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 if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) { 211 smb_dr_free_string(sharename); 212 goto decode_error; 213 } 214 215 rc = smb_shr_get(sharename, &lmshr_info); 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_create(&lmshr_info, B_FALSE); 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 sharename = smb_dr_get_string(dec_ctx); 235 cmnt = smb_dr_get_string(dec_ctx); 236 ad_container = smb_dr_get_string(dec_ctx); 237 if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) { 238 smb_dr_free_string(sharename); 239 smb_dr_free_string(cmnt); 240 smb_dr_free_string(ad_container); 241 goto decode_error; 242 } 243 244 rc = smb_shr_modify(sharename, cmnt, ad_container, B_FALSE); 245 smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS); 246 smb_dr_put_uint32(enc_ctx, rc); 247 248 smb_dr_free_string(sharename); 249 smb_dr_free_string(cmnt); 250 smb_dr_free_string(ad_container); 251 break; 252 253 case SMB_SHROP_LIST: 254 offset = smb_dr_get_int32(dec_ctx); 255 if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) 256 goto decode_error; 257 258 smb_shr_list(offset, &lmshr_list); 259 smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS); 260 smb_dr_put_buf(enc_ctx, (unsigned char *)&lmshr_list, 261 sizeof (smb_shrlist_t)); 262 break; 263 264 case SMB_SHROP_ENUM: 265 esi.es_bufsize = smb_dr_get_ushort(dec_ctx); 266 esi.es_username = smb_dr_get_string(dec_ctx); 267 if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) { 268 smb_dr_free_string(esi.es_username); 269 goto decode_error; 270 } 271 272 rc = smb_share_dsrv_enum(&esi); 273 274 smb_dr_free_string(esi.es_username); 275 276 smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS); 277 smb_dr_put_uint32(enc_ctx, rc); 278 if (rc == NERR_Success) { 279 smb_dr_put_ushort(enc_ctx, esi.es_ntotal); 280 smb_dr_put_ushort(enc_ctx, esi.es_nsent); 281 smb_dr_put_ushort(enc_ctx, esi.es_datasize); 282 smb_dr_put_buf(enc_ctx, 283 (unsigned char *)esi.es_buf, esi.es_bufsize); 284 free(esi.es_buf); 285 } 286 break; 287 288 default: 289 dec_status = smb_dr_decode_finish(dec_ctx); 290 goto decode_error; 291 } 292 293 if ((enc_status = smb_dr_encode_finish(enc_ctx, &used)) != 0) { 294 enc_ctx = smb_dr_encode_start(buf, sizeof (buf)); 295 smb_dr_put_int32(enc_ctx, SMB_SHARE_DERROR); 296 smb_dr_put_uint32(enc_ctx, enc_status); 297 (void) smb_dr_encode_finish(enc_ctx, &used); 298 } 299 300 (void) door_return(buf, used, NULL, 0); 301 return; 302 303 decode_error: 304 smb_dr_put_int32(enc_ctx, SMB_SHARE_DERROR); 305 smb_dr_put_uint32(enc_ctx, dec_status); 306 (void) smb_dr_encode_finish(enc_ctx, &used); 307 (void) door_return(buf, used, NULL, 0); 308 } 309 310 /* 311 * smb_share_dsrv_enum 312 * 313 * This function builds a response for a NetShareEnum RAP request which 314 * originates from smbsrv kernel module. A response buffer is allocated 315 * with the specified size in esi->es_bufsize. List of shares is scanned 316 * twice. In the first round the total number of shares which their OEM 317 * name is shorter than 13 chars (esi->es_ntotal) and also the number of 318 * shares that fit in the given buffer are calculated. In the second 319 * round the shares data are encoded in the buffer. 320 * 321 * The data associated with each share has two parts, a fixed size part and 322 * a variable size part which is share's comment. The outline of the response 323 * buffer is so that fixed part for all the shares will appear first and follows 324 * with the comments for all those shares and that's why the data cannot be 325 * encoded in one round without unnecessarily complicating the code. 326 */ 327 static int 328 smb_share_dsrv_enum(smb_enumshare_info_t *esi) 329 { 330 smb_shriter_t shi; 331 smb_share_t *si; 332 int remained; 333 uint16_t infolen = 0; 334 uint16_t cmntlen = 0; 335 uint16_t sharelen; 336 uint16_t clen; 337 uint32_t cmnt_offs; 338 smb_msgbuf_t info_mb; 339 smb_msgbuf_t cmnt_mb; 340 boolean_t autohome_added = B_FALSE; 341 342 esi->es_ntotal = esi->es_nsent = 0; 343 344 if ((esi->es_buf = malloc(esi->es_bufsize)) == NULL) 345 return (NERR_InternalError); 346 347 bzero(esi->es_buf, esi->es_bufsize); 348 remained = esi->es_bufsize; 349 350 /* Do the necessary calculations in the first round */ 351 smb_shr_iterinit(&shi); 352 353 while ((si = smb_shr_iterate(&shi)) != NULL) { 354 if (si->shr_flags & SMB_SHRF_LONGNAME) 355 continue; 356 357 if ((si->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) { 358 if (strcasecmp(esi->es_username, si->shr_name) == 0) 359 autohome_added = B_TRUE; 360 else 361 continue; 362 } 363 364 esi->es_ntotal++; 365 366 if (remained <= 0) 367 continue; 368 369 clen = strlen(si->shr_cmnt) + 1; 370 sharelen = SHARE_INFO_1_SIZE + clen; 371 372 if (sharelen <= remained) { 373 infolen += SHARE_INFO_1_SIZE; 374 cmntlen += clen; 375 } 376 377 remained -= sharelen; 378 } 379 380 esi->es_datasize = infolen + cmntlen; 381 382 smb_msgbuf_init(&info_mb, (uint8_t *)esi->es_buf, infolen, 0); 383 smb_msgbuf_init(&cmnt_mb, (uint8_t *)esi->es_buf + infolen, cmntlen, 0); 384 cmnt_offs = infolen; 385 386 /* Encode the data in the second round */ 387 smb_shr_iterinit(&shi); 388 autohome_added = B_FALSE; 389 390 while ((si = smb_shr_iterate(&shi)) != NULL) { 391 if (si->shr_flags & SMB_SHRF_LONGNAME) 392 continue; 393 394 if ((si->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) { 395 if (strcasecmp(esi->es_username, si->shr_name) == 0) 396 autohome_added = B_TRUE; 397 else 398 continue; 399 } 400 401 if (smb_msgbuf_encode(&info_mb, "13c.wl", 402 si->shr_oemname, si->shr_type, cmnt_offs) < 0) 403 break; 404 405 if (smb_msgbuf_encode(&cmnt_mb, "s", si->shr_cmnt) < 0) 406 break; 407 408 cmnt_offs += strlen(si->shr_cmnt) + 1; 409 esi->es_nsent++; 410 } 411 412 smb_msgbuf_term(&info_mb); 413 smb_msgbuf_term(&cmnt_mb); 414 415 return (NERR_Success); 416 } 417