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 * Copyright 2017 Nexenta Systems, Inc. All rights reserved. 24 * Copyright 2017 Joyent, Inc. 25 * Copyright 2022 RackTop Systems, Inc. 26 */ 27 28 #include <sys/types.h> 29 #include <sys/stat.h> 30 #include <sys/ioccom.h> 31 #include <sys/param.h> 32 #include <stddef.h> 33 #include <stdio.h> 34 #include <string.h> 35 #include <strings.h> 36 #include <stdlib.h> 37 #include <unistd.h> 38 #include <fcntl.h> 39 #include <errno.h> 40 41 #include <smbsrv/smb_xdr.h> 42 #include <smbsrv/smbinfo.h> 43 #include <smbsrv/smb_ioctl.h> 44 #include <smbsrv/libsmb.h> 45 46 #define SMBDRV_DEVICE_PATH "/dev/smbsrv" 47 48 int smb_kmod_ioctl(int, smb_ioc_header_t *, uint32_t); 49 50 51 int smbdrv_fd = -1; 52 53 /* 54 * Open the smbsrv driver. 55 * The smb daemon (smbd) opens the "control" device (/dev/smbsrv) 56 * and other consumers open the library device (/dev/smbsrv1) 57 */ 58 int 59 smb_kmod_bind(boolean_t smbd) 60 { 61 int fd; 62 63 if (smbdrv_fd != -1) 64 (void) close(smbdrv_fd); 65 66 if (smbd) { 67 fd = open(SMBDRV_DEVICE_PATH, 0); 68 } else { 69 fd = open(SMBDRV_DEVICE_PATH "1", 0); 70 } 71 if (fd < 0) 72 return (errno); 73 74 smbdrv_fd = fd; 75 76 return (0); 77 } 78 79 boolean_t 80 smb_kmod_isbound(void) 81 { 82 return ((smbdrv_fd == -1) ? B_FALSE : B_TRUE); 83 } 84 85 /* See also: smbsrv smb_server_store_cfg */ 86 int 87 smb_kmod_setcfg(smb_kmod_cfg_t *cfg) 88 { 89 smb_ioc_cfg_t ioc = {0}; 90 91 ioc.maxworkers = cfg->skc_maxworkers; 92 ioc.maxconnections = cfg->skc_maxconnections; 93 ioc.keepalive = cfg->skc_keepalive; 94 ioc.restrict_anon = cfg->skc_restrict_anon; 95 ioc.signing_enable = cfg->skc_signing_enable; 96 ioc.signing_required = cfg->skc_signing_required; 97 ioc.oplock_enable = cfg->skc_oplock_enable; 98 ioc.sync_enable = cfg->skc_sync_enable; 99 ioc.secmode = cfg->skc_secmode; 100 ioc.netbios_enable = cfg->skc_netbios_enable; 101 ioc.ipv6_enable = cfg->skc_ipv6_enable; 102 ioc.print_enable = cfg->skc_print_enable; 103 ioc.traverse_mounts = cfg->skc_traverse_mounts; 104 ioc.short_names = cfg->skc_short_names; 105 106 ioc.max_protocol = cfg->skc_max_protocol; 107 ioc.min_protocol = cfg->skc_min_protocol; 108 ioc.exec_flags = cfg->skc_execflags; 109 ioc.negtok_len = cfg->skc_negtok_len; 110 ioc.max_opens = cfg->skc_max_opens; 111 112 ioc.version = cfg->skc_version; 113 ioc.initial_credits = cfg->skc_initial_credits; 114 ioc.maximum_credits = cfg->skc_maximum_credits; 115 ioc.encrypt = cfg->skc_encrypt; 116 ioc.encrypt_ciphers = cfg->skc_encrypt_ciphers; 117 118 (void) memcpy(ioc.machine_uuid, cfg->skc_machine_uuid, sizeof (uuid_t)); 119 (void) memcpy(ioc.negtok, cfg->skc_negtok, sizeof (ioc.negtok)); 120 (void) memcpy(ioc.native_os, cfg->skc_native_os, 121 sizeof (ioc.native_os)); 122 (void) memcpy(ioc.native_lm, cfg->skc_native_lm, 123 sizeof (ioc.native_lm)); 124 125 (void) strlcpy(ioc.nbdomain, cfg->skc_nbdomain, sizeof (ioc.nbdomain)); 126 (void) strlcpy(ioc.fqdn, cfg->skc_fqdn, sizeof (ioc.fqdn)); 127 (void) strlcpy(ioc.hostname, cfg->skc_hostname, sizeof (ioc.hostname)); 128 (void) strlcpy(ioc.system_comment, cfg->skc_system_comment, 129 sizeof (ioc.system_comment)); 130 131 return (smb_kmod_ioctl(SMB_IOC_CONFIG, &ioc.hdr, sizeof (ioc))); 132 } 133 134 int 135 smb_kmod_setgmtoff(int32_t gmtoff) 136 { 137 smb_ioc_gmt_t ioc; 138 139 ioc.offset = gmtoff; 140 return (smb_kmod_ioctl(SMB_IOC_GMTOFF, &ioc.hdr, 141 sizeof (ioc))); 142 } 143 144 int 145 smb_kmod_start(int opipe, int lmshr, int udoor) 146 { 147 smb_ioc_start_t ioc; 148 149 ioc.opipe = opipe; 150 ioc.lmshrd = lmshr; 151 ioc.udoor = udoor; 152 return (smb_kmod_ioctl(SMB_IOC_START, &ioc.hdr, sizeof (ioc))); 153 } 154 155 void 156 smb_kmod_stop(void) 157 { 158 smb_ioc_header_t ioc; 159 160 (void) smb_kmod_ioctl(SMB_IOC_STOP, &ioc, sizeof (ioc)); 161 } 162 163 int 164 smb_kmod_event_notify(uint32_t txid) 165 { 166 smb_ioc_event_t ioc; 167 168 ioc.txid = txid; 169 return (smb_kmod_ioctl(SMB_IOC_EVENT, &ioc.hdr, sizeof (ioc))); 170 } 171 172 int 173 smb_kmod_share(nvlist_t *shrlist) 174 { 175 smb_ioc_share_t *ioc; 176 uint32_t ioclen; 177 char *shrbuf = NULL; 178 size_t bufsz; 179 int rc = ENOMEM; 180 181 if ((rc = nvlist_pack(shrlist, &shrbuf, &bufsz, NV_ENCODE_XDR, 0)) != 0) 182 return (rc); 183 184 ioclen = sizeof (smb_ioc_share_t) + bufsz; 185 186 if ((ioc = malloc(ioclen)) != NULL) { 187 ioc->shrlen = bufsz; 188 bcopy(shrbuf, ioc->shr, bufsz); 189 rc = smb_kmod_ioctl(SMB_IOC_SHARE, &ioc->hdr, ioclen); 190 free(ioc); 191 } 192 193 free(shrbuf); 194 return (rc); 195 } 196 197 int 198 smb_kmod_unshare(nvlist_t *shrlist) 199 { 200 smb_ioc_share_t *ioc; 201 uint32_t ioclen; 202 char *shrbuf = NULL; 203 size_t bufsz; 204 int rc = ENOMEM; 205 206 if ((rc = nvlist_pack(shrlist, &shrbuf, &bufsz, NV_ENCODE_XDR, 0)) != 0) 207 return (rc); 208 209 ioclen = sizeof (smb_ioc_share_t) + bufsz; 210 211 if ((ioc = malloc(ioclen)) != NULL) { 212 ioc->shrlen = bufsz; 213 bcopy(shrbuf, ioc->shr, bufsz); 214 rc = smb_kmod_ioctl(SMB_IOC_UNSHARE, &ioc->hdr, ioclen); 215 free(ioc); 216 } 217 218 free(shrbuf); 219 return (rc); 220 } 221 222 int 223 smb_kmod_shareinfo(char *shrname, boolean_t *shortnames) 224 { 225 smb_ioc_shareinfo_t ioc; 226 int rc; 227 228 bzero(&ioc, sizeof (ioc)); 229 (void) strlcpy(ioc.shrname, shrname, MAXNAMELEN); 230 231 rc = smb_kmod_ioctl(SMB_IOC_SHAREINFO, &ioc.hdr, sizeof (ioc)); 232 if (rc == 0) 233 *shortnames = ioc.shortnames; 234 else 235 *shortnames = B_TRUE; 236 237 return (rc); 238 } 239 240 /* 241 * Does the client have any access in this share? 242 */ 243 int 244 smb_kmod_shareaccess(smb_netuserinfo_t *ui, smb_share_t *si) 245 { 246 smb_ioc_shareaccess_t ioc; 247 int rc; 248 249 bzero(&ioc, sizeof (ioc)); 250 ioc.session_id = ui->ui_session_id; 251 ioc.user_id = ui->ui_user_id; 252 (void) strlcpy(ioc.shrname, si->shr_name, MAXNAMELEN); 253 254 rc = smb_kmod_ioctl(SMB_IOC_SHAREACCESS, &ioc.hdr, sizeof (ioc)); 255 256 return (rc); 257 } 258 259 int 260 smb_kmod_get_open_num(smb_opennum_t *opennum) 261 { 262 smb_ioc_opennum_t ioc; 263 int rc; 264 265 bzero(&ioc, sizeof (ioc)); 266 ioc.qualtype = opennum->qualtype; 267 (void) strlcpy(ioc.qualifier, opennum->qualifier, MAXNAMELEN); 268 269 rc = smb_kmod_ioctl(SMB_IOC_NUMOPEN, &ioc.hdr, sizeof (ioc)); 270 if (rc == 0) { 271 opennum->open_users = ioc.open_users; 272 opennum->open_trees = ioc.open_trees; 273 opennum->open_files = ioc.open_files; 274 } 275 276 return (rc); 277 } 278 279 int 280 smb_kmod_get_spool_doc(uint32_t *spool_num, char *username, 281 char *path, smb_inaddr_t *ipaddr) 282 { 283 smb_ioc_spooldoc_t ioc; 284 int rc; 285 286 bzero(&ioc, sizeof (ioc)); 287 rc = smb_kmod_ioctl(SMB_IOC_SPOOLDOC, &ioc.hdr, sizeof (ioc)); 288 if (rc == 0) { 289 *spool_num = ioc.spool_num; 290 (void) strlcpy(username, ioc.username, MAXNAMELEN); 291 (void) strlcpy(path, ioc.path, MAXPATHLEN); 292 *ipaddr = ioc.ipaddr; 293 } 294 return (rc); 295 } 296 297 /* 298 * Initialization for an smb_kmod_enum request. If this call succeeds, 299 * smb_kmod_enum_fini() must be called later to deallocate resources. 300 */ 301 smb_netsvc_t * 302 smb_kmod_enum_init(smb_svcenum_t *request) 303 { 304 smb_netsvc_t *ns; 305 smb_svcenum_t *svcenum; 306 smb_ioc_svcenum_t *ioc; 307 uint32_t ioclen; 308 309 if ((ns = calloc(1, sizeof (smb_netsvc_t))) == NULL) 310 return (NULL); 311 312 ioclen = sizeof (smb_ioc_svcenum_t) + SMB_IOC_DATA_SIZE; 313 if ((ioc = malloc(ioclen)) == NULL) { 314 free(ns); 315 return (NULL); 316 } 317 318 bzero(ioc, ioclen); 319 svcenum = &ioc->svcenum; 320 svcenum->se_type = request->se_type; 321 svcenum->se_level = request->se_level; 322 svcenum->se_bavail = SMB_IOC_DATA_SIZE; 323 svcenum->se_nlimit = request->se_nlimit; 324 svcenum->se_nskip = request->se_nskip; 325 svcenum->se_buflen = SMB_IOC_DATA_SIZE; 326 327 list_create(&ns->ns_list, sizeof (smb_netsvcitem_t), 328 offsetof(smb_netsvcitem_t, nsi_lnd)); 329 330 ns->ns_ioc = ioc; 331 ns->ns_ioclen = ioclen; 332 return (ns); 333 } 334 335 /* 336 * Cleanup resources allocated via smb_kmod_enum_init and smb_kmod_enum. 337 */ 338 void 339 smb_kmod_enum_fini(smb_netsvc_t *ns) 340 { 341 list_t *lst; 342 smb_netsvcitem_t *item; 343 smb_netuserinfo_t *user; 344 smb_netconnectinfo_t *tree; 345 smb_netfileinfo_t *ofile; 346 uint32_t se_type; 347 348 if (ns == NULL) 349 return; 350 351 lst = &ns->ns_list; 352 se_type = ns->ns_ioc->svcenum.se_type; 353 354 while ((item = list_head(lst)) != NULL) { 355 list_remove(lst, item); 356 357 switch (se_type) { 358 case SMB_SVCENUM_TYPE_USER: 359 user = &item->nsi_un.nsi_user; 360 free(user->ui_domain); 361 free(user->ui_account); 362 free(user->ui_workstation); 363 break; 364 case SMB_SVCENUM_TYPE_TREE: 365 tree = &item->nsi_un.nsi_tree; 366 free(tree->ci_username); 367 free(tree->ci_share); 368 break; 369 case SMB_SVCENUM_TYPE_FILE: 370 ofile = &item->nsi_un.nsi_ofile; 371 free(ofile->fi_path); 372 free(ofile->fi_username); 373 break; 374 default: 375 break; 376 } 377 } 378 379 list_destroy(&ns->ns_list); 380 free(ns->ns_items); 381 free(ns->ns_ioc); 382 free(ns); 383 } 384 385 /* 386 * Enumerate users, connections or files. 387 */ 388 int 389 smb_kmod_enum(smb_netsvc_t *ns) 390 { 391 smb_ioc_svcenum_t *ioc; 392 uint32_t ioclen; 393 smb_svcenum_t *svcenum; 394 smb_netsvcitem_t *items; 395 smb_netuserinfo_t *user; 396 smb_netconnectinfo_t *tree; 397 smb_netfileinfo_t *ofile; 398 uint8_t *data; 399 uint32_t len; 400 uint32_t se_type; 401 uint_t nbytes; 402 int i; 403 int rc; 404 405 ioc = ns->ns_ioc; 406 ioclen = ns->ns_ioclen; 407 rc = smb_kmod_ioctl(SMB_IOC_SVCENUM, &ioc->hdr, ioclen); 408 if (rc != 0) 409 return (rc); 410 411 svcenum = &ioc->svcenum; 412 items = calloc(svcenum->se_nitems, sizeof (smb_netsvcitem_t)); 413 if (items == NULL) 414 return (ENOMEM); 415 416 ns->ns_items = items; 417 se_type = ns->ns_ioc->svcenum.se_type; 418 data = svcenum->se_buf; 419 len = svcenum->se_bused; 420 421 for (i = 0; i < svcenum->se_nitems; ++i) { 422 switch (se_type) { 423 case SMB_SVCENUM_TYPE_USER: 424 user = &items->nsi_un.nsi_user; 425 rc = smb_netuserinfo_decode(user, data, len, &nbytes); 426 break; 427 case SMB_SVCENUM_TYPE_TREE: 428 tree = &items->nsi_un.nsi_tree; 429 rc = smb_netconnectinfo_decode(tree, data, len, 430 &nbytes); 431 break; 432 case SMB_SVCENUM_TYPE_FILE: 433 ofile = &items->nsi_un.nsi_ofile; 434 rc = smb_netfileinfo_decode(ofile, data, len, &nbytes); 435 break; 436 default: 437 rc = -1; 438 break; 439 } 440 441 if (rc != 0) 442 return (EINVAL); 443 444 list_insert_tail(&ns->ns_list, items); 445 446 ++items; 447 data += nbytes; 448 len -= nbytes; 449 } 450 451 return (0); 452 } 453 454 /* 455 * A NULL pointer is a wildcard indicator, which we pass on 456 * as an empty string (by virtue of the bzero). 457 */ 458 int 459 smb_kmod_session_close(const char *client, const char *username) 460 { 461 smb_ioc_session_t ioc; 462 int rc; 463 464 bzero(&ioc, sizeof (ioc)); 465 466 if (client != NULL) 467 (void) strlcpy(ioc.client, client, MAXNAMELEN); 468 if (username != NULL) 469 (void) strlcpy(ioc.username, username, MAXNAMELEN); 470 471 rc = smb_kmod_ioctl(SMB_IOC_SESSION_CLOSE, &ioc.hdr, sizeof (ioc)); 472 return (rc); 473 } 474 475 int 476 smb_kmod_file_close(uint32_t uniqid) 477 { 478 smb_ioc_fileid_t ioc; 479 int rc; 480 481 bzero(&ioc, sizeof (ioc)); 482 ioc.uniqid = uniqid; 483 484 rc = smb_kmod_ioctl(SMB_IOC_FILE_CLOSE, &ioc.hdr, sizeof (ioc)); 485 return (rc); 486 } 487 488 void 489 smb_kmod_unbind(void) 490 { 491 if (smbdrv_fd != -1) { 492 (void) close(smbdrv_fd); 493 smbdrv_fd = -1; 494 } 495 } 496 497 /* 498 * Note: The user-space smbd-d provides it own version of this function 499 * which directly calls the "kernel" module code (in user space). 500 */ 501 int 502 smb_kmod_ioctl(int cmd, smb_ioc_header_t *ioc, uint32_t len) 503 { 504 int rc = EINVAL; 505 506 ioc->version = SMB_IOC_VERSION; 507 ioc->cmd = cmd; 508 ioc->len = len; 509 ioc->crc = 0; 510 ioc->crc = smb_crc_gen((uint8_t *)ioc, sizeof (smb_ioc_header_t)); 511 512 if (smbdrv_fd != -1) { 513 if (ioctl(smbdrv_fd, cmd, ioc) < 0) 514 rc = errno; 515 else 516 rc = 0; 517 } 518 return (rc); 519 } 520