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