/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SMBDRV_DEVICE_PATH "/devices/pseudo/smbsrv@0:smbsrv" #define SMB_IOC_DATA_SIZE (256 * 1024) static int smb_kmod_ioctl(int, smb_ioc_header_t *, uint32_t); int smbdrv_fd = -1; int smb_kmod_bind(void) { if (smbdrv_fd != -1) (void) close(smbdrv_fd); if ((smbdrv_fd = open(SMBDRV_DEVICE_PATH, 0)) < 0) { smbdrv_fd = -1; return (errno); } return (0); } int smb_kmod_setcfg(smb_kmod_cfg_t *cfg) { smb_ioc_cfg_t ioc; ioc.maxworkers = cfg->skc_maxworkers; ioc.maxconnections = cfg->skc_maxconnections; ioc.keepalive = cfg->skc_keepalive; ioc.restrict_anon = cfg->skc_restrict_anon; ioc.signing_enable = cfg->skc_signing_enable; ioc.signing_required = cfg->skc_signing_required; ioc.oplock_enable = cfg->skc_oplock_enable; ioc.sync_enable = cfg->skc_sync_enable; ioc.secmode = cfg->skc_secmode; ioc.ipv6_enable = cfg->skc_ipv6_enable; (void) strlcpy(ioc.nbdomain, cfg->skc_nbdomain, sizeof (ioc.nbdomain)); (void) strlcpy(ioc.fqdn, cfg->skc_fqdn, sizeof (ioc.fqdn)); (void) strlcpy(ioc.hostname, cfg->skc_hostname, sizeof (ioc.hostname)); (void) strlcpy(ioc.system_comment, cfg->skc_system_comment, sizeof (ioc.system_comment)); return (smb_kmod_ioctl(SMB_IOC_CONFIG, &ioc.hdr, sizeof (ioc))); } int smb_kmod_setgmtoff(int32_t gmtoff) { smb_ioc_gmt_t ioc; ioc.offset = gmtoff; return (smb_kmod_ioctl(SMB_IOC_GMTOFF, &ioc.hdr, sizeof (ioc))); } int smb_kmod_start(int opipe, int lmshr, int udoor) { smb_ioc_start_t ioc; ioc.opipe = opipe; ioc.lmshrd = lmshr; ioc.udoor = udoor; return (smb_kmod_ioctl(SMB_IOC_START, &ioc.hdr, sizeof (ioc))); } int smb_kmod_tcplisten(int error) { smb_ioc_listen_t ioc; ioc.error = error; return (smb_kmod_ioctl(SMB_IOC_TCP_LISTEN, &ioc.hdr, sizeof (ioc))); } int smb_kmod_nbtlisten(int error) { smb_ioc_listen_t ioc; ioc.error = error; return (smb_kmod_ioctl(SMB_IOC_NBT_LISTEN, &ioc.hdr, sizeof (ioc))); } int smb_kmod_tcpreceive(void) { smb_ioc_header_t ioc; return (smb_kmod_ioctl(SMB_IOC_TCP_RECEIVE, &ioc, sizeof (ioc))); } int smb_kmod_nbtreceive(void) { smb_ioc_header_t ioc; return (smb_kmod_ioctl(SMB_IOC_NBT_RECEIVE, &ioc, sizeof (ioc))); } int smb_kmod_share(char *path, char *name) { smb_ioc_share_t *ioc; int rc = ENOMEM; ioc = malloc(sizeof (smb_ioc_share_t)); if (ioc != NULL) { (void) strlcpy(ioc->path, path, sizeof (ioc->path)); (void) strlcpy(ioc->name, name, sizeof (ioc->name)); rc = smb_kmod_ioctl(SMB_IOC_SHARE, &ioc->hdr, sizeof (smb_ioc_share_t)); free(ioc); } return (rc); } int smb_kmod_unshare(char *path, char *name) { smb_ioc_share_t *ioc; int rc = ENOMEM; ioc = malloc(sizeof (smb_ioc_share_t)); if (ioc != NULL) { (void) strlcpy(ioc->path, path, sizeof (ioc->path)); (void) strlcpy(ioc->name, name, sizeof (ioc->name)); rc = smb_kmod_ioctl(SMB_IOC_UNSHARE, &ioc->hdr, sizeof (smb_ioc_share_t)); free(ioc); } return (rc); } int smb_kmod_get_usernum(uint32_t *punum) { smb_ioc_usernum_t ioc; int rc; ioc.num = 0; rc = smb_kmod_ioctl(SMB_IOC_USER_NUMBER, &ioc.hdr, sizeof (ioc)); if (rc == 0) *punum = ioc.num; return (rc); } int smb_kmod_get_userlist(smb_ulist_t *ulist) { smb_opipe_context_t *ctx; smb_ioc_ulist_t *ioc; uint32_t ioc_len; uint8_t *data; uint32_t data_len; uint32_t unum; int rc; smb_ulist_cleanup(ulist); rc = smb_kmod_get_usernum(&unum); if ((rc != 0) || (unum == 0)) return (rc); ioc_len = sizeof (smb_ioc_ulist_t) + SMB_IOC_DATA_SIZE; ioc = malloc(ioc_len); if (ioc == NULL) return (ENOMEM); ctx = malloc(sizeof (smb_opipe_context_t) * unum); if (ctx == NULL) { free(ioc); return (ENOMEM); } ulist->ul_users = ctx; while (ulist->ul_cnt < unum) { ioc->cookie = ulist->ul_cnt; ioc->data_len = SMB_IOC_DATA_SIZE; rc = smb_kmod_ioctl(SMB_IOC_USER_LIST, &ioc->hdr, ioc_len); if (rc != 0) break; if ((ulist->ul_cnt + ioc->num) > unum) ioc->num = unum - ulist->ul_cnt; if (ioc->num == 0) break; data = ioc->data; data_len = ioc->data_len; while (ioc->num > 0) { uint_t bd = 0; rc = smb_opipe_context_decode(ctx, data, data_len, &bd); if (rc != 0) break; ctx++; ioc->num--; ulist->ul_cnt++; data += bd; data_len -= bd; } } if (rc != 0) smb_ulist_cleanup(ulist); free(ioc); return (rc); } void smb_kmod_unbind(void) { if (smbdrv_fd != -1) { (void) close(smbdrv_fd); smbdrv_fd = -1; } } static int smb_kmod_ioctl(int cmd, smb_ioc_header_t *ioc, uint32_t len) { int rc = EINVAL; ioc->version = SMB_IOC_VERSION; ioc->cmd = cmd; ioc->len = len; ioc->crc = 0; ioc->crc = smb_crc_gen((uint8_t *)ioc, sizeof (smb_ioc_header_t)); if (smbdrv_fd != -1) { if (ioctl(smbdrv_fd, cmd, ioc) < 0) rc = errno; else rc = 0; } return (rc); }