smb_kmod.c revision 29bd28862cfb8abbd3a0f0a4b17e08bbc3652836
/*
* 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 <sys/types.h>
#include <sys/stat.h>
#include <sys/ioccom.h>
#include <sys/param.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <smbsrv/smb_xdr.h>
#include <smbsrv/smbinfo.h>
#include <smbsrv/smb_ioctl.h>
#include <smbsrv/smb_ioctl.h>
#include <smbsrv/libsmb.h>
#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 *name)
{
smb_ioc_share_t *ioc;
int rc = ENOMEM;
ioc = malloc(sizeof (smb_ioc_share_t));
if (ioc != NULL) {
(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);
}