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