16771Sjb150015 /* 26771Sjb150015 * CDDL HEADER START 36771Sjb150015 * 46771Sjb150015 * The contents of this file are subject to the terms of the 56771Sjb150015 * Common Development and Distribution License (the "License"). 66771Sjb150015 * You may not use this file except in compliance with the License. 76771Sjb150015 * 86771Sjb150015 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 96771Sjb150015 * or http://www.opensolaris.org/os/licensing. 106771Sjb150015 * See the License for the specific language governing permissions 116771Sjb150015 * and limitations under the License. 126771Sjb150015 * 136771Sjb150015 * When distributing Covered Code, include this CDDL HEADER in each 146771Sjb150015 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156771Sjb150015 * If applicable, add the following below this CDDL HEADER, with the 166771Sjb150015 * fields enclosed by brackets "[]" replaced with your own identifying 176771Sjb150015 * information: Portions Copyright [yyyy] [name of copyright owner] 186771Sjb150015 * 196771Sjb150015 * CDDL HEADER END 206771Sjb150015 */ 216771Sjb150015 /* 226771Sjb150015 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 236771Sjb150015 * Use is subject to license terms. 246771Sjb150015 */ 256771Sjb150015 266771Sjb150015 #pragma ident "%Z%%M% %I% %E% SMI" 276771Sjb150015 286771Sjb150015 /* 296771Sjb150015 * Kernel door client for LanMan share management. 306771Sjb150015 */ 316771Sjb150015 326771Sjb150015 #include <sys/ddi.h> 336771Sjb150015 #include <sys/sunddi.h> 346771Sjb150015 #include <sys/cmn_err.h> 356771Sjb150015 #include <sys/door.h> 366771Sjb150015 #include <smbsrv/lmshare.h> 376771Sjb150015 #include <smbsrv/lmerr.h> 386771Sjb150015 #include <smbsrv/smb_common_door.h> 396771Sjb150015 #include <smbsrv/lmshare_door.h> 406771Sjb150015 #include <smbsrv/smbinfo.h> 416771Sjb150015 426771Sjb150015 static int smb_kshare_chk_dsrv_status(int, smb_dr_ctx_t *); 436771Sjb150015 446771Sjb150015 /* 456771Sjb150015 * smb_kshare_init 466771Sjb150015 * 476771Sjb150015 * This function is not MultiThread safe. The caller has to make sure only one 486771Sjb150015 * thread calls this function. 496771Sjb150015 */ 506771Sjb150015 door_handle_t 516771Sjb150015 smb_kshare_init(int door_id) 526771Sjb150015 { 536771Sjb150015 return (door_ki_lookup(door_id)); 546771Sjb150015 } 556771Sjb150015 566771Sjb150015 /* 576771Sjb150015 * smb_kshare_fini 586771Sjb150015 * 596771Sjb150015 * This function is not MultiThread safe. The caller has to make sure only one 606771Sjb150015 * thread calls this function. 616771Sjb150015 */ 626771Sjb150015 void 636771Sjb150015 smb_kshare_fini(door_handle_t dhdl) 646771Sjb150015 { 656771Sjb150015 if (dhdl) 666771Sjb150015 door_ki_rele(dhdl); 676771Sjb150015 } 686771Sjb150015 696771Sjb150015 uint32_t 706771Sjb150015 smb_kshare_getinfo(door_handle_t dhdl, char *share_name, lmshare_info_t *si) 716771Sjb150015 { 726771Sjb150015 door_arg_t arg; 736771Sjb150015 char *buf; 746771Sjb150015 unsigned int used; 756771Sjb150015 smb_dr_ctx_t *dec_ctx; 766771Sjb150015 smb_dr_ctx_t *enc_ctx; 776771Sjb150015 int status; 786771Sjb150015 uint32_t rc; 796771Sjb150015 int opcode = LMSHR_DOOR_GETINFO; 806771Sjb150015 816771Sjb150015 buf = kmem_alloc(LMSHR_DOOR_SIZE, KM_SLEEP); 826771Sjb150015 836771Sjb150015 enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE); 846771Sjb150015 smb_dr_put_uint32(enc_ctx, opcode); 856771Sjb150015 smb_dr_put_string(enc_ctx, share_name); 866771Sjb150015 876771Sjb150015 if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) { 886771Sjb150015 cmn_err(CE_WARN, "smb_kshare_getinfo: Encode error %d", 896771Sjb150015 status); 906771Sjb150015 kmem_free(buf, LMSHR_DOOR_SIZE); 916771Sjb150015 return (NERR_InternalError); 926771Sjb150015 } 936771Sjb150015 946771Sjb150015 arg.data_ptr = buf; 956771Sjb150015 arg.data_size = used; 966771Sjb150015 arg.desc_ptr = NULL; 976771Sjb150015 arg.desc_num = 0; 986771Sjb150015 arg.rbuf = buf; 996771Sjb150015 arg.rsize = LMSHR_DOOR_SIZE; 1006771Sjb150015 101*6997Sjwadams if (door_ki_upcall_limited(dhdl, &arg, NULL, SIZE_MAX, 0) != 0) { 1026771Sjb150015 cmn_err(CE_WARN, "smb_kshare_getinfo: Door call failed"); 1036771Sjb150015 kmem_free(buf, LMSHR_DOOR_SIZE); 1046771Sjb150015 return (NERR_InternalError); 1056771Sjb150015 } 1066771Sjb150015 1076771Sjb150015 dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size); 1086771Sjb150015 if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) { 1096771Sjb150015 kmem_free(buf, LMSHR_DOOR_SIZE); 1106771Sjb150015 return (NERR_InternalError); 1116771Sjb150015 } 1126771Sjb150015 1136771Sjb150015 rc = smb_dr_get_uint32(dec_ctx); 1146771Sjb150015 smb_dr_get_lmshare(dec_ctx, si); 1156771Sjb150015 if ((status = smb_dr_decode_finish(dec_ctx)) != 0) { 1166771Sjb150015 cmn_err(CE_WARN, "smb_kshare_getinfo: Decode error %d", 1176771Sjb150015 status); 1186771Sjb150015 rc = NERR_InternalError; 1196771Sjb150015 } 1206771Sjb150015 1216771Sjb150015 kmem_free(buf, LMSHR_DOOR_SIZE); 1226771Sjb150015 return (rc); 1236771Sjb150015 } 1246771Sjb150015 1256771Sjb150015 uint32_t 1266771Sjb150015 smb_kshare_enum(door_handle_t dhdl, smb_enumshare_info_t *enuminfo) 1276771Sjb150015 { 1286771Sjb150015 door_arg_t arg; 1296771Sjb150015 char *door_buf; 1306771Sjb150015 int door_bufsz; 1316771Sjb150015 unsigned int used; 1326771Sjb150015 smb_dr_ctx_t *dec_ctx; 1336771Sjb150015 smb_dr_ctx_t *enc_ctx; 1346771Sjb150015 int status; 1356771Sjb150015 uint32_t rc; 1366771Sjb150015 int opcode = LMSHR_DOOR_ENUM; 1376771Sjb150015 1386771Sjb150015 enuminfo->es_ntotal = enuminfo->es_nsent = 0; 1396771Sjb150015 1406771Sjb150015 door_bufsz = enuminfo->es_bufsize + strlen(enuminfo->es_username) 1416771Sjb150015 + sizeof (smb_enumshare_info_t); 1426771Sjb150015 door_buf = kmem_alloc(door_bufsz, KM_SLEEP); 1436771Sjb150015 1446771Sjb150015 enc_ctx = smb_dr_encode_start(door_buf, door_bufsz); 1456771Sjb150015 smb_dr_put_uint32(enc_ctx, opcode); 1466771Sjb150015 smb_dr_put_ushort(enc_ctx, enuminfo->es_bufsize); 1476771Sjb150015 smb_dr_put_string(enc_ctx, enuminfo->es_username); 1486771Sjb150015 1496771Sjb150015 if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) { 1506771Sjb150015 cmn_err(CE_WARN, "smb_kshare_enum: Encode error %d", status); 1516771Sjb150015 kmem_free(door_buf, door_bufsz); 1526771Sjb150015 return (NERR_InternalError); 1536771Sjb150015 } 1546771Sjb150015 1556771Sjb150015 arg.data_ptr = door_buf; 1566771Sjb150015 arg.data_size = used; 1576771Sjb150015 arg.desc_ptr = NULL; 1586771Sjb150015 arg.desc_num = 0; 1596771Sjb150015 arg.rbuf = door_buf; 1606771Sjb150015 arg.rsize = door_bufsz; 1616771Sjb150015 162*6997Sjwadams if (door_ki_upcall_limited(dhdl, &arg, NULL, SIZE_MAX, 0) != 0) { 1636771Sjb150015 cmn_err(CE_WARN, "smb_kshare_enum: Door call failed"); 1646771Sjb150015 kmem_free(door_buf, door_bufsz); 1656771Sjb150015 return (NERR_InternalError); 1666771Sjb150015 } 1676771Sjb150015 1686771Sjb150015 dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size); 1696771Sjb150015 if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) { 1706771Sjb150015 kmem_free(door_buf, door_bufsz); 1716771Sjb150015 return (NERR_InternalError); 1726771Sjb150015 } 1736771Sjb150015 1746771Sjb150015 rc = smb_dr_get_uint32(dec_ctx); 1756771Sjb150015 if (rc == NERR_Success) { 1766771Sjb150015 enuminfo->es_ntotal = smb_dr_get_ushort(dec_ctx); 1776771Sjb150015 enuminfo->es_nsent = smb_dr_get_ushort(dec_ctx); 1786771Sjb150015 enuminfo->es_datasize = smb_dr_get_ushort(dec_ctx); 1796771Sjb150015 (void) smb_dr_get_buf(dec_ctx, 1806771Sjb150015 (unsigned char *)enuminfo->es_buf, 1816771Sjb150015 enuminfo->es_bufsize); 1826771Sjb150015 } 1836771Sjb150015 1846771Sjb150015 if ((status = smb_dr_decode_finish(dec_ctx)) != 0) { 1856771Sjb150015 cmn_err(CE_WARN, "smb_kshare_enum: Decode error %d", status); 1866771Sjb150015 rc = NERR_InternalError; 1876771Sjb150015 } 1886771Sjb150015 1896771Sjb150015 kmem_free(door_buf, door_bufsz); 1906771Sjb150015 return (rc); 1916771Sjb150015 } 1926771Sjb150015 1936771Sjb150015 /* 1946771Sjb150015 * This is a special interface that will be utilized by ZFS to cause 1956771Sjb150015 * a share to be added/removed 1966771Sjb150015 * 1976771Sjb150015 * arg is either a lmshare_info_t or share_name from userspace. 1986771Sjb150015 * It will need to be copied into the kernel. It is lmshare_info_t 1996771Sjb150015 * for add operations and share_name for delete operations. 2006771Sjb150015 */ 2016771Sjb150015 int 2026771Sjb150015 smb_kshare_upcall(door_handle_t dhdl, void *arg, boolean_t add_share) 2036771Sjb150015 { 2046771Sjb150015 door_arg_t doorarg = { 0 }; 2056771Sjb150015 char *buf = NULL; 2066771Sjb150015 char *str = NULL; 2076771Sjb150015 int error; 2086771Sjb150015 int rc; 2096771Sjb150015 unsigned int used; 2106771Sjb150015 smb_dr_ctx_t *dec_ctx; 2116771Sjb150015 smb_dr_ctx_t *enc_ctx; 2126771Sjb150015 lmshare_info_t *lmshare = NULL; 2136771Sjb150015 int opcode; 2146771Sjb150015 2156771Sjb150015 opcode = add_share == B_TRUE ? LMSHR_DOOR_ADD : LMSHR_DOOR_DELETE; 2166771Sjb150015 2176771Sjb150015 buf = kmem_alloc(LMSHR_DOOR_SIZE, KM_SLEEP); 2186771Sjb150015 enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE); 2196771Sjb150015 smb_dr_put_uint32(enc_ctx, opcode); 2206771Sjb150015 2216771Sjb150015 switch (opcode) { 2226771Sjb150015 case LMSHR_DOOR_ADD: 2236771Sjb150015 lmshare = kmem_alloc(sizeof (lmshare_info_t), KM_SLEEP); 2246771Sjb150015 if (error = xcopyin(arg, lmshare, sizeof (lmshare_info_t))) { 2256771Sjb150015 kmem_free(lmshare, sizeof (lmshare_info_t)); 2266771Sjb150015 kmem_free(buf, LMSHR_DOOR_SIZE); 2276771Sjb150015 return (error); 2286771Sjb150015 } 2296771Sjb150015 smb_dr_put_lmshare(enc_ctx, lmshare); 2306771Sjb150015 break; 2316771Sjb150015 2326771Sjb150015 case LMSHR_DOOR_DELETE: 2336771Sjb150015 str = kmem_alloc(MAXPATHLEN, KM_SLEEP); 2346771Sjb150015 if (error = copyinstr(arg, str, MAXPATHLEN, NULL)) { 2356771Sjb150015 kmem_free(str, MAXPATHLEN); 2366771Sjb150015 kmem_free(buf, LMSHR_DOOR_SIZE); 2376771Sjb150015 return (error); 2386771Sjb150015 } 2396771Sjb150015 smb_dr_put_string(enc_ctx, str); 2406771Sjb150015 kmem_free(str, MAXPATHLEN); 2416771Sjb150015 break; 2426771Sjb150015 } 2436771Sjb150015 2446771Sjb150015 if ((error = smb_dr_encode_finish(enc_ctx, &used)) != 0) { 2456771Sjb150015 kmem_free(buf, LMSHR_DOOR_SIZE); 2466771Sjb150015 if (lmshare) 2476771Sjb150015 kmem_free(lmshare, sizeof (lmshare_info_t)); 2486771Sjb150015 return (NERR_InternalError); 2496771Sjb150015 } 2506771Sjb150015 2516771Sjb150015 doorarg.data_ptr = buf; 2526771Sjb150015 doorarg.data_size = used; 2536771Sjb150015 doorarg.rbuf = buf; 2546771Sjb150015 doorarg.rsize = LMSHR_DOOR_SIZE; 2556771Sjb150015 256*6997Sjwadams error = door_ki_upcall_limited(dhdl, &doorarg, NULL, SIZE_MAX, 0); 2576771Sjb150015 2586771Sjb150015 if (error) { 2596771Sjb150015 kmem_free(buf, LMSHR_DOOR_SIZE); 2606771Sjb150015 if (lmshare) 2616771Sjb150015 kmem_free(lmshare, sizeof (lmshare_info_t)); 2626771Sjb150015 return (error); 2636771Sjb150015 } 2646771Sjb150015 2656771Sjb150015 dec_ctx = smb_dr_decode_start(doorarg.data_ptr, doorarg.data_size); 2666771Sjb150015 if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) { 2676771Sjb150015 kmem_free(buf, LMSHR_DOOR_SIZE); 2686771Sjb150015 if (lmshare) 2696771Sjb150015 kmem_free(lmshare, sizeof (lmshare_info_t)); 2706771Sjb150015 return (NERR_InternalError); 2716771Sjb150015 } 2726771Sjb150015 2736771Sjb150015 rc = smb_dr_get_uint32(dec_ctx); 2746771Sjb150015 if (opcode == LMSHR_DOOR_ADD) 2756771Sjb150015 smb_dr_get_lmshare(dec_ctx, lmshare); 2766771Sjb150015 2776771Sjb150015 if (smb_dr_decode_finish(dec_ctx)) 2786771Sjb150015 rc = NERR_InternalError; 2796771Sjb150015 2806771Sjb150015 kmem_free(buf, LMSHR_DOOR_SIZE); 2816771Sjb150015 if (lmshare) 2826771Sjb150015 kmem_free(lmshare, sizeof (lmshare_info_t)); 2836771Sjb150015 2846771Sjb150015 return ((rc == NERR_DuplicateShare && add_share) ? 0 : rc); 2856771Sjb150015 } 2866771Sjb150015 2876771Sjb150015 /* 2886771Sjb150015 * Return 0 upon success. Otherwise > 0 2896771Sjb150015 */ 2906771Sjb150015 static int 2916771Sjb150015 smb_kshare_chk_dsrv_status(int opcode, smb_dr_ctx_t *dec_ctx) 2926771Sjb150015 { 2936771Sjb150015 int status = smb_dr_get_int32(dec_ctx); 2946771Sjb150015 int err; 2956771Sjb150015 2966771Sjb150015 switch (status) { 2976771Sjb150015 case LMSHR_DOOR_SRV_SUCCESS: 2986771Sjb150015 return (0); 2996771Sjb150015 3006771Sjb150015 case LMSHR_DOOR_SRV_ERROR: 3016771Sjb150015 err = smb_dr_get_uint32(dec_ctx); 3026771Sjb150015 cmn_err(CE_WARN, "%d: Encountered door server error %d", 3036771Sjb150015 opcode, err); 3046771Sjb150015 (void) smb_dr_decode_finish(dec_ctx); 3056771Sjb150015 return (err); 3066771Sjb150015 } 3076771Sjb150015 3086771Sjb150015 ASSERT(0); 3096771Sjb150015 return (EINVAL); 3106771Sjb150015 } 311