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