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 "@(#)smb_kshare.c 1.7 08/08/07 SMI" 27 28 /* 29 * Kernel door client for LanMan share management. 30 */ 31 32 #include <sys/ddi.h> 33 #include <sys/sunddi.h> 34 #include <sys/cmn_err.h> 35 #include <sys/door.h> 36 #include <smbsrv/lmerr.h> 37 #include <smbsrv/smb_share.h> 38 #include <smbsrv/smb_common_door.h> 39 #include <smbsrv/smbinfo.h> 40 41 static int smb_kshare_chk_dsrv_status(int, smb_dr_ctx_t *); 42 43 /* 44 * smb_kshare_init 45 * 46 * This function is not MultiThread safe. The caller has to make sure only one 47 * thread calls this function. 48 */ 49 door_handle_t 50 smb_kshare_init(int door_id) 51 { 52 return (door_ki_lookup(door_id)); 53 } 54 55 /* 56 * smb_kshare_fini 57 * 58 * This function is not MultiThread safe. The caller has to make sure only one 59 * thread calls this function. 60 */ 61 void 62 smb_kshare_fini(door_handle_t dhdl) 63 { 64 if (dhdl) 65 door_ki_rele(dhdl); 66 } 67 68 uint32_t 69 smb_kshare_getinfo(door_handle_t dhdl, const char *share_name, smb_share_t *si) 70 { 71 door_arg_t arg; 72 char *buf; 73 unsigned int used; 74 smb_dr_ctx_t *dec_ctx; 75 smb_dr_ctx_t *enc_ctx; 76 int status; 77 uint32_t rc; 78 int opcode = SMB_SHROP_GETINFO; 79 80 buf = kmem_alloc(SMB_SHARE_DSIZE, KM_SLEEP); 81 82 enc_ctx = smb_dr_encode_start(buf, SMB_SHARE_DSIZE); 83 smb_dr_put_uint32(enc_ctx, opcode); 84 smb_dr_put_string(enc_ctx, share_name); 85 86 if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) { 87 cmn_err(CE_WARN, "smb_kshare_getinfo: Encode error %d", 88 status); 89 kmem_free(buf, SMB_SHARE_DSIZE); 90 return (NERR_InternalError); 91 } 92 93 arg.data_ptr = buf; 94 arg.data_size = used; 95 arg.desc_ptr = NULL; 96 arg.desc_num = 0; 97 arg.rbuf = buf; 98 arg.rsize = SMB_SHARE_DSIZE; 99 100 if (door_ki_upcall_limited(dhdl, &arg, NULL, SIZE_MAX, 0) != 0) { 101 cmn_err(CE_WARN, "smb_kshare_getinfo: Door call failed"); 102 kmem_free(buf, SMB_SHARE_DSIZE); 103 return (NERR_InternalError); 104 } 105 106 dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size); 107 if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) { 108 kmem_free(buf, SMB_SHARE_DSIZE); 109 return (NERR_InternalError); 110 } 111 112 rc = smb_dr_get_uint32(dec_ctx); 113 smb_dr_get_share(dec_ctx, si); 114 if ((status = smb_dr_decode_finish(dec_ctx)) != 0) { 115 cmn_err(CE_WARN, "smb_kshare_getinfo: Decode error %d", 116 status); 117 rc = NERR_InternalError; 118 } 119 120 kmem_free(buf, SMB_SHARE_DSIZE); 121 return (rc); 122 } 123 124 uint32_t 125 smb_kshare_enum(door_handle_t dhdl, smb_enumshare_info_t *enuminfo) 126 { 127 door_arg_t arg; 128 char *door_buf; 129 int door_bufsz; 130 unsigned int used; 131 smb_dr_ctx_t *dec_ctx; 132 smb_dr_ctx_t *enc_ctx; 133 int status; 134 uint32_t rc; 135 int opcode = SMB_SHROP_ENUM; 136 137 enuminfo->es_ntotal = enuminfo->es_nsent = 0; 138 139 door_bufsz = enuminfo->es_bufsize + strlen(enuminfo->es_username) 140 + sizeof (smb_enumshare_info_t); 141 door_buf = kmem_alloc(door_bufsz, KM_SLEEP); 142 143 enc_ctx = smb_dr_encode_start(door_buf, door_bufsz); 144 smb_dr_put_uint32(enc_ctx, opcode); 145 smb_dr_put_ushort(enc_ctx, enuminfo->es_bufsize); 146 smb_dr_put_string(enc_ctx, enuminfo->es_username); 147 148 if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) { 149 cmn_err(CE_WARN, "smb_kshare_enum: Encode error %d", status); 150 kmem_free(door_buf, door_bufsz); 151 return (NERR_InternalError); 152 } 153 154 arg.data_ptr = door_buf; 155 arg.data_size = used; 156 arg.desc_ptr = NULL; 157 arg.desc_num = 0; 158 arg.rbuf = door_buf; 159 arg.rsize = door_bufsz; 160 161 if (door_ki_upcall_limited(dhdl, &arg, NULL, SIZE_MAX, 0) != 0) { 162 cmn_err(CE_WARN, "smb_kshare_enum: Door call failed"); 163 kmem_free(door_buf, door_bufsz); 164 return (NERR_InternalError); 165 } 166 167 dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size); 168 if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) { 169 kmem_free(door_buf, door_bufsz); 170 return (NERR_InternalError); 171 } 172 173 rc = smb_dr_get_uint32(dec_ctx); 174 if (rc == NERR_Success) { 175 enuminfo->es_ntotal = smb_dr_get_ushort(dec_ctx); 176 enuminfo->es_nsent = smb_dr_get_ushort(dec_ctx); 177 enuminfo->es_datasize = smb_dr_get_ushort(dec_ctx); 178 (void) smb_dr_get_buf(dec_ctx, 179 (unsigned char *)enuminfo->es_buf, 180 enuminfo->es_bufsize); 181 } 182 183 if ((status = smb_dr_decode_finish(dec_ctx)) != 0) { 184 cmn_err(CE_WARN, "smb_kshare_enum: Decode error %d", status); 185 rc = NERR_InternalError; 186 } 187 188 kmem_free(door_buf, door_bufsz); 189 return (rc); 190 } 191 192 /* 193 * This is a special interface that will be utilized by ZFS to cause 194 * a share to be added/removed 195 * 196 * arg is either a smb_share_t or share_name from userspace. 197 * It will need to be copied into the kernel. It is smb_share_t 198 * for add operations and share_name for delete operations. 199 */ 200 int 201 smb_kshare_upcall(door_handle_t dhdl, void *arg, boolean_t add_share) 202 { 203 door_arg_t doorarg = { 0 }; 204 char *buf = NULL; 205 char *str = NULL; 206 int error; 207 int rc; 208 unsigned int used; 209 smb_dr_ctx_t *dec_ctx; 210 smb_dr_ctx_t *enc_ctx; 211 smb_share_t *lmshare = NULL; 212 int opcode; 213 214 opcode = (add_share) ? SMB_SHROP_ADD : SMB_SHROP_DELETE; 215 216 buf = kmem_alloc(SMB_SHARE_DSIZE, KM_SLEEP); 217 enc_ctx = smb_dr_encode_start(buf, SMB_SHARE_DSIZE); 218 smb_dr_put_uint32(enc_ctx, opcode); 219 220 switch (opcode) { 221 case SMB_SHROP_ADD: 222 lmshare = kmem_alloc(sizeof (smb_share_t), KM_SLEEP); 223 if (error = xcopyin(arg, lmshare, sizeof (smb_share_t))) { 224 kmem_free(lmshare, sizeof (smb_share_t)); 225 kmem_free(buf, SMB_SHARE_DSIZE); 226 return (error); 227 } 228 smb_dr_put_share(enc_ctx, lmshare); 229 break; 230 231 case SMB_SHROP_DELETE: 232 str = kmem_alloc(MAXPATHLEN, KM_SLEEP); 233 if (error = copyinstr(arg, str, MAXPATHLEN, NULL)) { 234 kmem_free(str, MAXPATHLEN); 235 kmem_free(buf, SMB_SHARE_DSIZE); 236 return (error); 237 } 238 smb_dr_put_string(enc_ctx, str); 239 kmem_free(str, MAXPATHLEN); 240 break; 241 } 242 243 if ((error = smb_dr_encode_finish(enc_ctx, &used)) != 0) { 244 kmem_free(buf, SMB_SHARE_DSIZE); 245 if (lmshare) 246 kmem_free(lmshare, sizeof (smb_share_t)); 247 return (NERR_InternalError); 248 } 249 250 doorarg.data_ptr = buf; 251 doorarg.data_size = used; 252 doorarg.rbuf = buf; 253 doorarg.rsize = SMB_SHARE_DSIZE; 254 255 error = door_ki_upcall_limited(dhdl, &doorarg, NULL, SIZE_MAX, 0); 256 257 if (error) { 258 kmem_free(buf, SMB_SHARE_DSIZE); 259 if (lmshare) 260 kmem_free(lmshare, sizeof (smb_share_t)); 261 return (error); 262 } 263 264 dec_ctx = smb_dr_decode_start(doorarg.data_ptr, doorarg.data_size); 265 if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) { 266 kmem_free(buf, SMB_SHARE_DSIZE); 267 if (lmshare) 268 kmem_free(lmshare, sizeof (smb_share_t)); 269 return (NERR_InternalError); 270 } 271 272 rc = smb_dr_get_uint32(dec_ctx); 273 if (opcode == SMB_SHROP_ADD) 274 smb_dr_get_share(dec_ctx, lmshare); 275 276 if (smb_dr_decode_finish(dec_ctx)) 277 rc = NERR_InternalError; 278 279 kmem_free(buf, SMB_SHARE_DSIZE); 280 if (lmshare) 281 kmem_free(lmshare, sizeof (smb_share_t)); 282 283 return ((rc == NERR_DuplicateShare && add_share) ? 0 : rc); 284 } 285 286 /* 287 * Return 0 upon success. Otherwise > 0 288 */ 289 static int 290 smb_kshare_chk_dsrv_status(int opcode, smb_dr_ctx_t *dec_ctx) 291 { 292 int status = smb_dr_get_int32(dec_ctx); 293 int err; 294 295 switch (status) { 296 case SMB_SHARE_DSUCCESS: 297 return (0); 298 299 case SMB_SHARE_DERROR: 300 err = smb_dr_get_uint32(dec_ctx); 301 cmn_err(CE_WARN, "%d: Encountered door server error %d", 302 opcode, err); 303 (void) smb_dr_decode_finish(dec_ctx); 304 return (err); 305 } 306 307 ASSERT(0); 308 return (EINVAL); 309 } 310