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