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 /* 228670SJose.Borrego@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 236771Sjb150015 * Use is subject to license terms. 246771Sjb150015 */ 256771Sjb150015 266771Sjb150015 /* 276771Sjb150015 * Kernel door client for LanMan share management. 286771Sjb150015 */ 296771Sjb150015 306771Sjb150015 #include <sys/ddi.h> 316771Sjb150015 #include <sys/sunddi.h> 326771Sjb150015 #include <sys/cmn_err.h> 336771Sjb150015 #include <sys/door.h> 346771Sjb150015 #include <smbsrv/lmerr.h> 357052Samw #include <smbsrv/smb_share.h> 366771Sjb150015 #include <smbsrv/smb_common_door.h> 376771Sjb150015 #include <smbsrv/smbinfo.h> 386771Sjb150015 396771Sjb150015 static int smb_kshare_chk_dsrv_status(int, smb_dr_ctx_t *); 406771Sjb150015 416771Sjb150015 /* 426771Sjb150015 * smb_kshare_init 436771Sjb150015 * 446771Sjb150015 * This function is not MultiThread safe. The caller has to make sure only one 456771Sjb150015 * thread calls this function. 466771Sjb150015 */ 476771Sjb150015 door_handle_t 486771Sjb150015 smb_kshare_init(int door_id) 496771Sjb150015 { 506771Sjb150015 return (door_ki_lookup(door_id)); 516771Sjb150015 } 526771Sjb150015 536771Sjb150015 /* 546771Sjb150015 * smb_kshare_fini 556771Sjb150015 * 566771Sjb150015 * This function is not MultiThread safe. The caller has to make sure only one 576771Sjb150015 * thread calls this function. 586771Sjb150015 */ 596771Sjb150015 void 606771Sjb150015 smb_kshare_fini(door_handle_t dhdl) 616771Sjb150015 { 626771Sjb150015 if (dhdl) 636771Sjb150015 door_ki_rele(dhdl); 646771Sjb150015 } 656771Sjb150015 666771Sjb150015 uint32_t 677961SNatalie.Li@Sun.COM smb_kshare_getinfo(door_handle_t dhdl, char *share_name, smb_share_t *si, 688670SJose.Borrego@Sun.COM smb_inaddr_t *ipaddr) 696771Sjb150015 { 706771Sjb150015 door_arg_t arg; 716771Sjb150015 char *buf; 726771Sjb150015 unsigned int used; 736771Sjb150015 smb_dr_ctx_t *dec_ctx; 746771Sjb150015 smb_dr_ctx_t *enc_ctx; 756771Sjb150015 uint32_t rc; 767052Samw int opcode = SMB_SHROP_GETINFO; 776771Sjb150015 787052Samw buf = kmem_alloc(SMB_SHARE_DSIZE, KM_SLEEP); 796771Sjb150015 807052Samw enc_ctx = smb_dr_encode_start(buf, SMB_SHARE_DSIZE); 816771Sjb150015 smb_dr_put_uint32(enc_ctx, opcode); 826771Sjb150015 smb_dr_put_string(enc_ctx, share_name); 838670SJose.Borrego@Sun.COM smb_dr_put_buf(enc_ctx, (uchar_t *)ipaddr, sizeof (smb_inaddr_t)); 846771Sjb150015 857961SNatalie.Li@Sun.COM if (smb_dr_encode_finish(enc_ctx, &used) != 0) { 867052Samw kmem_free(buf, SMB_SHARE_DSIZE); 876771Sjb150015 return (NERR_InternalError); 886771Sjb150015 } 896771Sjb150015 906771Sjb150015 arg.data_ptr = buf; 916771Sjb150015 arg.data_size = used; 926771Sjb150015 arg.desc_ptr = NULL; 936771Sjb150015 arg.desc_num = 0; 946771Sjb150015 arg.rbuf = buf; 957052Samw arg.rsize = SMB_SHARE_DSIZE; 966771Sjb150015 976997Sjwadams if (door_ki_upcall_limited(dhdl, &arg, NULL, SIZE_MAX, 0) != 0) { 987052Samw kmem_free(buf, SMB_SHARE_DSIZE); 996771Sjb150015 return (NERR_InternalError); 1006771Sjb150015 } 1016771Sjb150015 1026771Sjb150015 dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size); 1036771Sjb150015 if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) { 1047052Samw kmem_free(buf, SMB_SHARE_DSIZE); 1056771Sjb150015 return (NERR_InternalError); 1066771Sjb150015 } 1076771Sjb150015 1086771Sjb150015 rc = smb_dr_get_uint32(dec_ctx); 1097052Samw smb_dr_get_share(dec_ctx, si); 1107961SNatalie.Li@Sun.COM if (smb_dr_decode_finish(dec_ctx) != 0) 1116771Sjb150015 rc = NERR_InternalError; 1126771Sjb150015 1137052Samw kmem_free(buf, SMB_SHARE_DSIZE); 1146771Sjb150015 return (rc); 1156771Sjb150015 } 1166771Sjb150015 1176771Sjb150015 uint32_t 1186771Sjb150015 smb_kshare_enum(door_handle_t dhdl, smb_enumshare_info_t *enuminfo) 1196771Sjb150015 { 1206771Sjb150015 door_arg_t arg; 1216771Sjb150015 char *door_buf; 1226771Sjb150015 int door_bufsz; 1236771Sjb150015 unsigned int used; 1246771Sjb150015 smb_dr_ctx_t *dec_ctx; 1256771Sjb150015 smb_dr_ctx_t *enc_ctx; 1266771Sjb150015 uint32_t rc; 1277052Samw int opcode = SMB_SHROP_ENUM; 1286771Sjb150015 1296771Sjb150015 enuminfo->es_ntotal = enuminfo->es_nsent = 0; 1306771Sjb150015 1316771Sjb150015 door_bufsz = enuminfo->es_bufsize + strlen(enuminfo->es_username) 1326771Sjb150015 + sizeof (smb_enumshare_info_t); 1336771Sjb150015 door_buf = kmem_alloc(door_bufsz, KM_SLEEP); 1346771Sjb150015 1356771Sjb150015 enc_ctx = smb_dr_encode_start(door_buf, door_bufsz); 1366771Sjb150015 smb_dr_put_uint32(enc_ctx, opcode); 1376771Sjb150015 smb_dr_put_ushort(enc_ctx, enuminfo->es_bufsize); 1386771Sjb150015 smb_dr_put_string(enc_ctx, enuminfo->es_username); 1396771Sjb150015 1407961SNatalie.Li@Sun.COM if (smb_dr_encode_finish(enc_ctx, &used) != 0) { 1416771Sjb150015 kmem_free(door_buf, door_bufsz); 1426771Sjb150015 return (NERR_InternalError); 1436771Sjb150015 } 1446771Sjb150015 1456771Sjb150015 arg.data_ptr = door_buf; 1466771Sjb150015 arg.data_size = used; 1476771Sjb150015 arg.desc_ptr = NULL; 1486771Sjb150015 arg.desc_num = 0; 1496771Sjb150015 arg.rbuf = door_buf; 1506771Sjb150015 arg.rsize = door_bufsz; 1516771Sjb150015 1526997Sjwadams if (door_ki_upcall_limited(dhdl, &arg, NULL, SIZE_MAX, 0) != 0) { 1536771Sjb150015 kmem_free(door_buf, door_bufsz); 1546771Sjb150015 return (NERR_InternalError); 1556771Sjb150015 } 1566771Sjb150015 1576771Sjb150015 dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size); 1586771Sjb150015 if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) { 1596771Sjb150015 kmem_free(door_buf, door_bufsz); 1606771Sjb150015 return (NERR_InternalError); 1616771Sjb150015 } 1626771Sjb150015 1636771Sjb150015 rc = smb_dr_get_uint32(dec_ctx); 1646771Sjb150015 if (rc == NERR_Success) { 1656771Sjb150015 enuminfo->es_ntotal = smb_dr_get_ushort(dec_ctx); 1666771Sjb150015 enuminfo->es_nsent = smb_dr_get_ushort(dec_ctx); 1676771Sjb150015 enuminfo->es_datasize = smb_dr_get_ushort(dec_ctx); 1686771Sjb150015 (void) smb_dr_get_buf(dec_ctx, 1696771Sjb150015 (unsigned char *)enuminfo->es_buf, 1706771Sjb150015 enuminfo->es_bufsize); 1716771Sjb150015 } 1726771Sjb150015 1737961SNatalie.Li@Sun.COM if (smb_dr_decode_finish(dec_ctx) != 0) 1746771Sjb150015 rc = NERR_InternalError; 1756771Sjb150015 1766771Sjb150015 kmem_free(door_buf, door_bufsz); 1776771Sjb150015 return (rc); 1786771Sjb150015 } 1796771Sjb150015 1806771Sjb150015 /* 181*9832Samw@Sun.COM * Executes map and unmap command for shares. 182*9832Samw@Sun.COM */ 183*9832Samw@Sun.COM uint32_t 184*9832Samw@Sun.COM smb_kshare_exec(door_handle_t dhdl, char *sharename, smb_execsub_info_t *subs, 185*9832Samw@Sun.COM int exec_type) 186*9832Samw@Sun.COM { 187*9832Samw@Sun.COM door_arg_t arg; 188*9832Samw@Sun.COM char *buf; 189*9832Samw@Sun.COM int bufsz; 190*9832Samw@Sun.COM unsigned int used; 191*9832Samw@Sun.COM smb_dr_ctx_t *dec_ctx; 192*9832Samw@Sun.COM smb_dr_ctx_t *enc_ctx; 193*9832Samw@Sun.COM uint32_t rc; 194*9832Samw@Sun.COM int opcode = SMB_SHROP_EXEC; 195*9832Samw@Sun.COM 196*9832Samw@Sun.COM bufsz = (2 * sizeof (int)) + strlen(sharename) + strlen(subs->e_winname) 197*9832Samw@Sun.COM + strlen(subs->e_userdom) + strlen(subs->e_cli_netbiosname) + 198*9832Samw@Sun.COM (2 * sizeof (smb_inaddr_t)) + sizeof (uid_t) + 199*9832Samw@Sun.COM sizeof (smb_execsub_info_t); 200*9832Samw@Sun.COM 201*9832Samw@Sun.COM buf = kmem_alloc(bufsz, KM_SLEEP); 202*9832Samw@Sun.COM 203*9832Samw@Sun.COM enc_ctx = smb_dr_encode_start(buf, bufsz); 204*9832Samw@Sun.COM smb_dr_put_uint32(enc_ctx, opcode); 205*9832Samw@Sun.COM smb_dr_put_string(enc_ctx, sharename); 206*9832Samw@Sun.COM smb_dr_put_string(enc_ctx, subs->e_winname); 207*9832Samw@Sun.COM smb_dr_put_string(enc_ctx, subs->e_userdom); 208*9832Samw@Sun.COM smb_dr_put_buf(enc_ctx, (uchar_t *)&subs->e_srv_ipaddr, 209*9832Samw@Sun.COM sizeof (smb_inaddr_t)); 210*9832Samw@Sun.COM smb_dr_put_buf(enc_ctx, (uchar_t *)&subs->e_cli_ipaddr, 211*9832Samw@Sun.COM sizeof (smb_inaddr_t)); 212*9832Samw@Sun.COM smb_dr_put_string(enc_ctx, subs->e_cli_netbiosname); 213*9832Samw@Sun.COM smb_dr_put_int32(enc_ctx, subs->e_uid); 214*9832Samw@Sun.COM smb_dr_put_int32(enc_ctx, exec_type); 215*9832Samw@Sun.COM 216*9832Samw@Sun.COM if (smb_dr_encode_finish(enc_ctx, &used) != 0) { 217*9832Samw@Sun.COM kmem_free(buf, bufsz); 218*9832Samw@Sun.COM return (NERR_InternalError); 219*9832Samw@Sun.COM } 220*9832Samw@Sun.COM 221*9832Samw@Sun.COM arg.data_ptr = buf; 222*9832Samw@Sun.COM arg.data_size = used; 223*9832Samw@Sun.COM arg.desc_ptr = NULL; 224*9832Samw@Sun.COM arg.desc_num = 0; 225*9832Samw@Sun.COM arg.rbuf = buf; 226*9832Samw@Sun.COM arg.rsize = bufsz; 227*9832Samw@Sun.COM 228*9832Samw@Sun.COM if (door_ki_upcall_limited(dhdl, &arg, NULL, SIZE_MAX, 0) != 0) { 229*9832Samw@Sun.COM kmem_free(buf, bufsz); 230*9832Samw@Sun.COM return (NERR_InternalError); 231*9832Samw@Sun.COM } 232*9832Samw@Sun.COM 233*9832Samw@Sun.COM dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size); 234*9832Samw@Sun.COM if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) { 235*9832Samw@Sun.COM kmem_free(buf, bufsz); 236*9832Samw@Sun.COM return (NERR_InternalError); 237*9832Samw@Sun.COM } 238*9832Samw@Sun.COM 239*9832Samw@Sun.COM rc = smb_dr_get_uint32(dec_ctx); 240*9832Samw@Sun.COM if (smb_dr_decode_finish(dec_ctx) != 0) 241*9832Samw@Sun.COM rc = NERR_InternalError; 242*9832Samw@Sun.COM 243*9832Samw@Sun.COM kmem_free(buf, bufsz); 244*9832Samw@Sun.COM return (rc); 245*9832Samw@Sun.COM } 246*9832Samw@Sun.COM 247*9832Samw@Sun.COM /* 2486771Sjb150015 * This is a special interface that will be utilized by ZFS to cause 2496771Sjb150015 * a share to be added/removed 2506771Sjb150015 * 2517052Samw * arg is either a smb_share_t or share_name from userspace. 2527052Samw * It will need to be copied into the kernel. It is smb_share_t 2536771Sjb150015 * for add operations and share_name for delete operations. 2546771Sjb150015 */ 2556771Sjb150015 int 2566771Sjb150015 smb_kshare_upcall(door_handle_t dhdl, void *arg, boolean_t add_share) 2576771Sjb150015 { 2586771Sjb150015 door_arg_t doorarg = { 0 }; 2596771Sjb150015 char *buf = NULL; 2606771Sjb150015 char *str = NULL; 2616771Sjb150015 int error; 2626771Sjb150015 int rc; 2636771Sjb150015 unsigned int used; 2646771Sjb150015 smb_dr_ctx_t *dec_ctx; 2656771Sjb150015 smb_dr_ctx_t *enc_ctx; 2667052Samw smb_share_t *lmshare = NULL; 2676771Sjb150015 int opcode; 2686771Sjb150015 2697052Samw opcode = (add_share) ? SMB_SHROP_ADD : SMB_SHROP_DELETE; 2706771Sjb150015 2717052Samw buf = kmem_alloc(SMB_SHARE_DSIZE, KM_SLEEP); 2727052Samw enc_ctx = smb_dr_encode_start(buf, SMB_SHARE_DSIZE); 2736771Sjb150015 smb_dr_put_uint32(enc_ctx, opcode); 2746771Sjb150015 2756771Sjb150015 switch (opcode) { 2767052Samw case SMB_SHROP_ADD: 2777052Samw lmshare = kmem_alloc(sizeof (smb_share_t), KM_SLEEP); 2787052Samw if (error = xcopyin(arg, lmshare, sizeof (smb_share_t))) { 2797052Samw kmem_free(lmshare, sizeof (smb_share_t)); 2807052Samw kmem_free(buf, SMB_SHARE_DSIZE); 2816771Sjb150015 return (error); 2826771Sjb150015 } 2837052Samw smb_dr_put_share(enc_ctx, lmshare); 2846771Sjb150015 break; 2856771Sjb150015 2867052Samw case SMB_SHROP_DELETE: 2876771Sjb150015 str = kmem_alloc(MAXPATHLEN, KM_SLEEP); 2886771Sjb150015 if (error = copyinstr(arg, str, MAXPATHLEN, NULL)) { 2896771Sjb150015 kmem_free(str, MAXPATHLEN); 2907052Samw kmem_free(buf, SMB_SHARE_DSIZE); 2916771Sjb150015 return (error); 2926771Sjb150015 } 2936771Sjb150015 smb_dr_put_string(enc_ctx, str); 2946771Sjb150015 kmem_free(str, MAXPATHLEN); 2956771Sjb150015 break; 2966771Sjb150015 } 2976771Sjb150015 2986771Sjb150015 if ((error = smb_dr_encode_finish(enc_ctx, &used)) != 0) { 2997052Samw kmem_free(buf, SMB_SHARE_DSIZE); 3006771Sjb150015 if (lmshare) 3017052Samw kmem_free(lmshare, sizeof (smb_share_t)); 3026771Sjb150015 return (NERR_InternalError); 3036771Sjb150015 } 3046771Sjb150015 3056771Sjb150015 doorarg.data_ptr = buf; 3066771Sjb150015 doorarg.data_size = used; 3076771Sjb150015 doorarg.rbuf = buf; 3087052Samw doorarg.rsize = SMB_SHARE_DSIZE; 3096771Sjb150015 3106997Sjwadams error = door_ki_upcall_limited(dhdl, &doorarg, NULL, SIZE_MAX, 0); 3116771Sjb150015 3126771Sjb150015 if (error) { 3137052Samw kmem_free(buf, SMB_SHARE_DSIZE); 3146771Sjb150015 if (lmshare) 3157052Samw kmem_free(lmshare, sizeof (smb_share_t)); 3166771Sjb150015 return (error); 3176771Sjb150015 } 3186771Sjb150015 3196771Sjb150015 dec_ctx = smb_dr_decode_start(doorarg.data_ptr, doorarg.data_size); 3206771Sjb150015 if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) { 3217052Samw kmem_free(buf, SMB_SHARE_DSIZE); 3226771Sjb150015 if (lmshare) 3237052Samw kmem_free(lmshare, sizeof (smb_share_t)); 3246771Sjb150015 return (NERR_InternalError); 3256771Sjb150015 } 3266771Sjb150015 3276771Sjb150015 rc = smb_dr_get_uint32(dec_ctx); 3287052Samw if (opcode == SMB_SHROP_ADD) 3297052Samw smb_dr_get_share(dec_ctx, lmshare); 3306771Sjb150015 3316771Sjb150015 if (smb_dr_decode_finish(dec_ctx)) 3326771Sjb150015 rc = NERR_InternalError; 3336771Sjb150015 3347052Samw kmem_free(buf, SMB_SHARE_DSIZE); 3356771Sjb150015 if (lmshare) 3367052Samw kmem_free(lmshare, sizeof (smb_share_t)); 3376771Sjb150015 3386771Sjb150015 return ((rc == NERR_DuplicateShare && add_share) ? 0 : rc); 3396771Sjb150015 } 3406771Sjb150015 3416771Sjb150015 /* 3426771Sjb150015 * Return 0 upon success. Otherwise > 0 3436771Sjb150015 */ 3446771Sjb150015 static int 3456771Sjb150015 smb_kshare_chk_dsrv_status(int opcode, smb_dr_ctx_t *dec_ctx) 3466771Sjb150015 { 3476771Sjb150015 int status = smb_dr_get_int32(dec_ctx); 3486771Sjb150015 int err; 3496771Sjb150015 3506771Sjb150015 switch (status) { 3517052Samw case SMB_SHARE_DSUCCESS: 3526771Sjb150015 return (0); 3536771Sjb150015 3547052Samw case SMB_SHARE_DERROR: 3556771Sjb150015 err = smb_dr_get_uint32(dec_ctx); 3566771Sjb150015 cmn_err(CE_WARN, "%d: Encountered door server error %d", 3576771Sjb150015 opcode, err); 3586771Sjb150015 (void) smb_dr_decode_finish(dec_ctx); 3596771Sjb150015 return (err); 3606771Sjb150015 } 3616771Sjb150015 3626771Sjb150015 ASSERT(0); 3636771Sjb150015 return (EINVAL); 3646771Sjb150015 } 365