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