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) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <sys/types.h> 26 #include <sys/stat.h> 27 #include <sys/ioccom.h> 28 #include <sys/param.h> 29 #include <stddef.h> 30 #include <stdio.h> 31 #include <string.h> 32 #include <strings.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <fcntl.h> 36 #include <errno.h> 37 38 #include <smbsrv/smb_xdr.h> 39 #include <smbsrv/smbinfo.h> 40 #include <smbsrv/smb_ioctl.h> 41 #include <smbsrv/smb_ioctl.h> 42 #include <smbsrv/libsmb.h> 43 44 #define SMBDRV_DEVICE_PATH "/devices/pseudo/smbsrv@0:smbsrv" 45 #define SMB_IOC_DATA_SIZE (256 * 1024) 46 47 static int smb_kmod_ioctl(int, smb_ioc_header_t *, uint32_t); 48 49 50 int smbdrv_fd = -1; 51 52 int 53 smb_kmod_bind(void) 54 { 55 if (smbdrv_fd != -1) 56 (void) close(smbdrv_fd); 57 58 if ((smbdrv_fd = open(SMBDRV_DEVICE_PATH, 0)) < 0) { 59 smbdrv_fd = -1; 60 return (errno); 61 } 62 63 return (0); 64 } 65 66 int 67 smb_kmod_setcfg(smb_kmod_cfg_t *cfg) 68 { 69 smb_ioc_cfg_t ioc; 70 71 ioc.maxworkers = cfg->skc_maxworkers; 72 ioc.maxconnections = cfg->skc_maxconnections; 73 ioc.keepalive = cfg->skc_keepalive; 74 ioc.restrict_anon = cfg->skc_restrict_anon; 75 ioc.signing_enable = cfg->skc_signing_enable; 76 ioc.signing_required = cfg->skc_signing_required; 77 ioc.oplock_enable = cfg->skc_oplock_enable; 78 ioc.sync_enable = cfg->skc_sync_enable; 79 ioc.secmode = cfg->skc_secmode; 80 ioc.ipv6_enable = cfg->skc_ipv6_enable; 81 ioc.exec_flags = cfg->skc_execflags; 82 ioc.version = cfg->skc_version; 83 84 (void) strlcpy(ioc.nbdomain, cfg->skc_nbdomain, sizeof (ioc.nbdomain)); 85 (void) strlcpy(ioc.fqdn, cfg->skc_fqdn, sizeof (ioc.fqdn)); 86 (void) strlcpy(ioc.hostname, cfg->skc_hostname, sizeof (ioc.hostname)); 87 (void) strlcpy(ioc.system_comment, cfg->skc_system_comment, 88 sizeof (ioc.system_comment)); 89 90 return (smb_kmod_ioctl(SMB_IOC_CONFIG, &ioc.hdr, sizeof (ioc))); 91 } 92 93 int 94 smb_kmod_setgmtoff(int32_t gmtoff) 95 { 96 smb_ioc_gmt_t ioc; 97 98 ioc.offset = gmtoff; 99 return (smb_kmod_ioctl(SMB_IOC_GMTOFF, &ioc.hdr, 100 sizeof (ioc))); 101 } 102 103 int 104 smb_kmod_start(int opipe, int lmshr, int udoor) 105 { 106 smb_ioc_start_t ioc; 107 108 ioc.opipe = opipe; 109 ioc.lmshrd = lmshr; 110 ioc.udoor = udoor; 111 return (smb_kmod_ioctl(SMB_IOC_START, &ioc.hdr, sizeof (ioc))); 112 } 113 114 void 115 smb_kmod_stop(void) 116 { 117 smb_ioc_header_t ioc; 118 119 (void) smb_kmod_ioctl(SMB_IOC_STOP, &ioc, sizeof (ioc)); 120 } 121 122 int 123 smb_kmod_event_notify(uint32_t txid) 124 { 125 smb_ioc_event_t ioc; 126 127 ioc.txid = txid; 128 return (smb_kmod_ioctl(SMB_IOC_EVENT, &ioc.hdr, sizeof (ioc))); 129 } 130 131 int 132 smb_kmod_tcplisten(int error) 133 { 134 smb_ioc_listen_t ioc; 135 136 ioc.error = error; 137 return (smb_kmod_ioctl(SMB_IOC_TCP_LISTEN, &ioc.hdr, sizeof (ioc))); 138 } 139 140 int 141 smb_kmod_nbtlisten(int error) 142 { 143 smb_ioc_listen_t ioc; 144 145 ioc.error = error; 146 return (smb_kmod_ioctl(SMB_IOC_NBT_LISTEN, &ioc.hdr, sizeof (ioc))); 147 } 148 149 int 150 smb_kmod_tcpreceive(void) 151 { 152 smb_ioc_header_t ioc; 153 154 return (smb_kmod_ioctl(SMB_IOC_TCP_RECEIVE, &ioc, sizeof (ioc))); 155 } 156 157 int 158 smb_kmod_nbtreceive(void) 159 { 160 smb_ioc_header_t ioc; 161 162 return (smb_kmod_ioctl(SMB_IOC_NBT_RECEIVE, &ioc, sizeof (ioc))); 163 } 164 165 int 166 smb_kmod_share(nvlist_t *shrlist) 167 { 168 smb_ioc_share_t *ioc; 169 uint32_t ioclen; 170 char *shrbuf = NULL; 171 size_t bufsz; 172 int rc = ENOMEM; 173 174 if ((rc = nvlist_pack(shrlist, &shrbuf, &bufsz, NV_ENCODE_XDR, 0)) != 0) 175 return (rc); 176 177 ioclen = sizeof (smb_ioc_share_t) + bufsz; 178 179 if ((ioc = malloc(ioclen)) != NULL) { 180 ioc->shrlen = bufsz; 181 bcopy(shrbuf, ioc->shr, bufsz); 182 rc = smb_kmod_ioctl(SMB_IOC_SHARE, &ioc->hdr, ioclen); 183 free(ioc); 184 } 185 186 free(shrbuf); 187 return (rc); 188 } 189 190 int 191 smb_kmod_unshare(nvlist_t *shrlist) 192 { 193 smb_ioc_share_t *ioc; 194 uint32_t ioclen; 195 char *shrbuf = NULL; 196 size_t bufsz; 197 int rc = ENOMEM; 198 199 if ((rc = nvlist_pack(shrlist, &shrbuf, &bufsz, NV_ENCODE_XDR, 0)) != 0) 200 return (rc); 201 202 ioclen = sizeof (smb_ioc_share_t) + bufsz; 203 204 if ((ioc = malloc(ioclen)) != NULL) { 205 ioc->shrlen = bufsz; 206 bcopy(shrbuf, ioc->shr, bufsz); 207 rc = smb_kmod_ioctl(SMB_IOC_UNSHARE, &ioc->hdr, ioclen); 208 free(ioc); 209 } 210 211 free(shrbuf); 212 return (rc); 213 } 214 215 int 216 smb_kmod_get_open_num(smb_opennum_t *opennum) 217 { 218 smb_ioc_opennum_t ioc; 219 int rc; 220 221 bzero(&ioc, sizeof (ioc)); 222 ioc.qualtype = opennum->qualtype; 223 (void) strlcpy(ioc.qualifier, opennum->qualifier, MAXNAMELEN); 224 225 rc = smb_kmod_ioctl(SMB_IOC_NUMOPEN, &ioc.hdr, sizeof (ioc)); 226 if (rc == 0) { 227 opennum->open_users = ioc.open_users; 228 opennum->open_trees = ioc.open_trees; 229 opennum->open_files = ioc.open_files; 230 } 231 232 return (rc); 233 } 234 235 /* 236 * Initialization for an smb_kmod_enum request. If this call succeeds, 237 * smb_kmod_enum_fini() must be called later to deallocate resources. 238 */ 239 smb_netsvc_t * 240 smb_kmod_enum_init(smb_svcenum_t *request) 241 { 242 smb_netsvc_t *ns; 243 smb_svcenum_t *svcenum; 244 smb_ioc_svcenum_t *ioc; 245 uint32_t ioclen; 246 247 if ((ns = calloc(1, sizeof (smb_netsvc_t))) == NULL) 248 return (NULL); 249 250 ioclen = sizeof (smb_ioc_svcenum_t) + SMB_IOC_DATA_SIZE; 251 if ((ioc = malloc(ioclen)) == NULL) { 252 free(ns); 253 return (NULL); 254 } 255 256 bzero(ioc, ioclen); 257 svcenum = &ioc->svcenum; 258 svcenum->se_type = request->se_type; 259 svcenum->se_level = request->se_level; 260 svcenum->se_bavail = SMB_IOC_DATA_SIZE; 261 svcenum->se_nlimit = request->se_nlimit; 262 svcenum->se_nskip = request->se_nskip; 263 svcenum->se_buflen = SMB_IOC_DATA_SIZE; 264 265 list_create(&ns->ns_list, sizeof (smb_netsvcitem_t), 266 offsetof(smb_netsvcitem_t, nsi_lnd)); 267 268 ns->ns_ioc = ioc; 269 ns->ns_ioclen = ioclen; 270 return (ns); 271 } 272 273 /* 274 * Cleanup resources allocated via smb_kmod_enum_init and smb_kmod_enum. 275 */ 276 void 277 smb_kmod_enum_fini(smb_netsvc_t *ns) 278 { 279 list_t *lst; 280 smb_netsvcitem_t *item; 281 smb_netuserinfo_t *user; 282 smb_netconnectinfo_t *tree; 283 smb_netfileinfo_t *ofile; 284 uint32_t se_type; 285 286 if (ns == NULL) 287 return; 288 289 lst = &ns->ns_list; 290 se_type = ns->ns_ioc->svcenum.se_type; 291 292 while ((item = list_head(lst)) != NULL) { 293 list_remove(lst, item); 294 295 switch (se_type) { 296 case SMB_SVCENUM_TYPE_USER: 297 user = &item->nsi_un.nsi_user; 298 free(user->ui_domain); 299 free(user->ui_account); 300 free(user->ui_workstation); 301 break; 302 case SMB_SVCENUM_TYPE_TREE: 303 tree = &item->nsi_un.nsi_tree; 304 free(tree->ci_username); 305 free(tree->ci_share); 306 break; 307 case SMB_SVCENUM_TYPE_FILE: 308 ofile = &item->nsi_un.nsi_ofile; 309 free(ofile->fi_path); 310 free(ofile->fi_username); 311 break; 312 default: 313 break; 314 } 315 } 316 317 list_destroy(&ns->ns_list); 318 free(ns->ns_items); 319 free(ns->ns_ioc); 320 free(ns); 321 } 322 323 /* 324 * Enumerate users, connections or files. 325 */ 326 int 327 smb_kmod_enum(smb_netsvc_t *ns) 328 { 329 smb_ioc_svcenum_t *ioc; 330 uint32_t ioclen; 331 smb_svcenum_t *svcenum; 332 smb_netsvcitem_t *items; 333 smb_netuserinfo_t *user; 334 smb_netconnectinfo_t *tree; 335 smb_netfileinfo_t *ofile; 336 uint8_t *data; 337 uint32_t len; 338 uint32_t se_type; 339 uint_t nbytes; 340 int i; 341 int rc; 342 343 ioc = ns->ns_ioc; 344 ioclen = ns->ns_ioclen; 345 rc = smb_kmod_ioctl(SMB_IOC_SVCENUM, &ioc->hdr, ioclen); 346 if (rc != 0) 347 return (rc); 348 349 svcenum = &ioc->svcenum; 350 items = calloc(svcenum->se_nitems, sizeof (smb_netsvcitem_t)); 351 if (items == NULL) 352 return (ENOMEM); 353 354 ns->ns_items = items; 355 se_type = ns->ns_ioc->svcenum.se_type; 356 data = svcenum->se_buf; 357 len = svcenum->se_bused; 358 359 for (i = 0; i < svcenum->se_nitems; ++i) { 360 switch (se_type) { 361 case SMB_SVCENUM_TYPE_USER: 362 user = &items->nsi_un.nsi_user; 363 rc = smb_netuserinfo_decode(user, data, len, &nbytes); 364 break; 365 case SMB_SVCENUM_TYPE_TREE: 366 tree = &items->nsi_un.nsi_tree; 367 rc = smb_netconnectinfo_decode(tree, data, len, 368 &nbytes); 369 break; 370 case SMB_SVCENUM_TYPE_FILE: 371 ofile = &items->nsi_un.nsi_ofile; 372 rc = smb_netfileinfo_decode(ofile, data, len, &nbytes); 373 break; 374 default: 375 rc = -1; 376 break; 377 } 378 379 if (rc != 0) 380 return (EINVAL); 381 382 list_insert_tail(&ns->ns_list, items); 383 384 ++items; 385 data += nbytes; 386 len -= nbytes; 387 } 388 389 return (0); 390 } 391 392 /* 393 * A NULL pointer is a wildcard indicator, which we pass on 394 * as an empty string (by virtue of the bzero). 395 */ 396 int 397 smb_kmod_session_close(const char *client, const char *username) 398 { 399 smb_ioc_session_t ioc; 400 int rc; 401 402 bzero(&ioc, sizeof (ioc)); 403 404 if (client != NULL) 405 (void) strlcpy(ioc.client, client, MAXNAMELEN); 406 if (username != NULL) 407 (void) strlcpy(ioc.username, username, MAXNAMELEN); 408 409 rc = smb_kmod_ioctl(SMB_IOC_SESSION_CLOSE, &ioc.hdr, sizeof (ioc)); 410 return (rc); 411 } 412 413 int 414 smb_kmod_file_close(uint32_t uniqid) 415 { 416 smb_ioc_fileid_t ioc; 417 int rc; 418 419 bzero(&ioc, sizeof (ioc)); 420 ioc.uniqid = uniqid; 421 422 rc = smb_kmod_ioctl(SMB_IOC_FILE_CLOSE, &ioc.hdr, sizeof (ioc)); 423 return (rc); 424 } 425 426 void 427 smb_kmod_unbind(void) 428 { 429 if (smbdrv_fd != -1) { 430 (void) close(smbdrv_fd); 431 smbdrv_fd = -1; 432 } 433 } 434 435 static int 436 smb_kmod_ioctl(int cmd, smb_ioc_header_t *ioc, uint32_t len) 437 { 438 int rc = EINVAL; 439 440 ioc->version = SMB_IOC_VERSION; 441 ioc->cmd = cmd; 442 ioc->len = len; 443 ioc->crc = 0; 444 ioc->crc = smb_crc_gen((uint8_t *)ioc, sizeof (smb_ioc_header_t)); 445 446 if (smbdrv_fd != -1) { 447 if (ioctl(smbdrv_fd, cmd, ioc) < 0) 448 rc = errno; 449 else 450 rc = 0; 451 } 452 return (rc); 453 } 454