#include <netsmb/smbio.h>
#include <netsmb/upi_mbuf.h>
#include <sys/mchain.h>
#include <netsmb/rq.h>
#include <netsmb/smb_converter.h>
#include <sys/smb_byte_order.h>
int
smbio_ntcreatex(void *smbctx, const char *path, const char *streamName,
struct open_inparms *inparms, struct open_outparm *outparms,
int *fid)
{
uint16_t *namelenp;
struct smb_usr_rq *rqp;
mbchain_t mbp;
mdchain_t mdp;
uint8_t wc;
size_t nmlen;
int error;
u_int16_t fid16;
error = smb_usr_rq_init(smbctx, SMB_COM_NT_CREATE_ANDX, 0, &rqp);
if (error != 0) {
return error;
}
mbp = smb_usr_rq_getrequest(rqp);
smb_usr_rq_wstart(rqp);
mb_put_uint8(mbp, 0xff);
mb_put_uint8(mbp, 0);
mb_put_uint16le(mbp, 0);
mb_put_uint8(mbp, 0);
namelenp = (uint16_t *)mb_reserve(mbp, sizeof(uint16_t));
mb_put_uint32le(mbp, NTCREATEX_FLAGS_EXTENDED);
mb_put_uint32le(mbp, 0);
mb_put_uint32le(mbp, inparms->rights);
mb_put_uint64le(mbp, inparms->allocSize);
mb_put_uint32le(mbp, inparms->attrs);
mb_put_uint32le(mbp, inparms->shareMode);
mb_put_uint32le(mbp, inparms->disp);
mb_put_uint32le(mbp, inparms->createOptions);
mb_put_uint32le(mbp, NTCREATEX_IMPERSONATION_IMPERSONATION);
mb_put_uint8(mbp, 0);
smb_usr_rq_wend(rqp);
smb_usr_rq_bstart(rqp);
nmlen = 0;
if (streamName) {
size_t snmlen = 0;
error = smb_usr_put_dmem(smbctx, mbp, path, strlen(path),
SMB_UTF_SFM_CONVERSIONS | SMB_FULLPATH_CONVERSIONS,
&nmlen);
if (!error) {
if (*streamName != ':') {
mb_put_uint16le(mbp, ':');
nmlen += 2;
}
error = smb_usr_rq_put_dstring(smbctx, mbp, streamName, strlen(streamName),
NO_SFM_CONVERSIONS, &snmlen);
}
nmlen += snmlen;
} else {
error = smb_usr_rq_put_dstring(smbctx, mbp, path, strlen(path),
SMB_UTF_SFM_CONVERSIONS |
SMB_FULLPATH_CONVERSIONS,
&nmlen);
}
if (error) {
smb_log_info("%s: smb_usr_rq_put_dstring failed syserr = %s",
ASL_LEVEL_DEBUG, __FUNCTION__, strerror(error));
goto done;
}
*namelenp = htoles((uint16_t)nmlen);
smb_usr_rq_bend(rqp);
error = smb_usr_rq_simple(rqp);
if (error != 0) {
smb_log_info("%s: smb_usr_rq_simple failed, syserr = %s",
ASL_LEVEL_DEBUG, __FUNCTION__, strerror(error));
goto done;
}
mdp = smb_usr_rq_getreply(rqp);
if (md_get_uint8(mdp, &wc) != 0 ||
((wc != NTCREATEX_NORMAL_WDCNT) && (wc != NTCREATEX_EXTENDED_WDCNT))) {
error = EIO;
smb_log_info("%s: bad word count, syserr = %s",
ASL_LEVEL_DEBUG, __FUNCTION__, strerror(error));
goto done;
}
md_get_uint8(mdp, NULL);
md_get_uint8(mdp, NULL);
md_get_uint16le(mdp, NULL);
md_get_uint8(mdp, NULL);
md_get_uint16le(mdp, &fid16);
*fid = fid16;
error = md_get_uint32le(mdp, NULL);
if (outparms) {
md_get_uint64le(mdp, &outparms->createTime);
md_get_uint64le(mdp, &outparms->accessTime);
md_get_uint64le(mdp, &outparms->writeTime);
md_get_uint64le(mdp, &outparms->changeTime);
md_get_uint32le(mdp, &outparms->attributes);
md_get_uint64le(mdp, &outparms->allocationSize);
md_get_uint64le(mdp, &outparms->fileSize);
md_get_uint16le(mdp, NULL);
md_get_uint16le(mdp, NULL);
error = md_get_uint8(mdp, NULL);
if (wc == NTCREATEX_EXTENDED_WDCNT) {
md_get_mem(mdp, (caddr_t)outparms->volumeGID, sizeof(outparms->volumeGID), MB_MSYSTEM);
md_get_uint64le(mdp, &outparms->fileInode);
md_get_uint32le(mdp, &outparms->maxAccessRights);
error = md_get_uint32le(mdp, &outparms->maxGuessAccessRights);
}
}
done:
smb_usr_rq_done(rqp);
return error;
}
ssize_t smbio_read(void *smbctx, int fid, uint8_t *buf, size_t buflen)
{
int bytes;
bytes = smb_read(smbctx, (uint16_t)fid, 0 ,
(uint32_t)buflen, (char *)buf);
if (bytes == -1) {
return -errno;
}
return (ssize_t)bytes;
}
#define SMB1_TRANS2_MAXSIZE 0x0000ffff
int smbio_transact(void *smbctx, uint16_t *setup, int setupCnt, const char *name,
const uint8_t *sndPData, size_t sndPDataLen,
const uint8_t *sndData, size_t sndDataLen,
uint8_t *rcvPData, size_t *rcvPDataLen,
uint8_t *rcvdData, size_t *rcvDataLen)
{
uint16_t rPDataLen = 0;
uint16_t rDataLen = 0;
uint32_t buffer_oflow = 0;
int error;
if ((sndPDataLen > SMB1_TRANS2_MAXSIZE) || (sndDataLen > SMB1_TRANS2_MAXSIZE)) {
return -EINVAL;
}
if (rcvPDataLen) {
if (*rcvPDataLen > SMB1_TRANS2_MAXSIZE) {
rPDataLen = (uint16_t)SMB1_TRANS2_MAXSIZE;
} else {
rPDataLen = (uint16_t)*rcvPDataLen;
}
}
if (rcvDataLen) {
if (*rcvDataLen > SMB1_TRANS2_MAXSIZE) {
rDataLen = (uint16_t)SMB1_TRANS2_MAXSIZE;
} else {
rDataLen = (uint16_t)*rcvDataLen;
}
}
error = smb_usr_t2_request(smbctx, setupCnt, setup, name,
(uint16_t)sndPDataLen, sndPData,
(uint16_t)sndDataLen, sndData,
&rPDataLen, rcvPData,
&rDataLen, rcvdData,
&buffer_oflow);
if (error) {
return error;
}
if (rcvPDataLen) {
*rcvPDataLen = rPDataLen;
}
if (rcvDataLen) {
*rcvDataLen = rDataLen;
}
if (buffer_oflow) {
return EOVERFLOW;
}
return 0;
}
int smbio_open_pipe(void *smbctx, const char *pipe_path, int *fid)
{
struct open_inparms inparms;
int error;
memset(&inparms, 0,sizeof(inparms));
inparms.rights = SMB2_READ_CONTROL | SMB2_FILE_WRITE_ATTRIBUTES |
SMB2_FILE_READ_ATTRIBUTES | SMB2_FILE_WRITE_EA |
SMB2_FILE_READ_EA | SMB2_FILE_APPEND_DATA |
SMB2_FILE_WRITE_DATA | SMB2_FILE_READ_DATA;
inparms.attrs = SMB_EFA_NORMAL;
inparms.shareMode = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
inparms.disp = FILE_OPEN;
inparms.createOptions = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
error = smbio_ntcreatex(smbctx, pipe_path, NULL, &inparms, NULL, fid);
if (error == EINVAL) {
error = ECONNREFUSED;
}
if (error)
smb_log_info("%s, syserr = %s", ASL_LEVEL_DEBUG, __FUNCTION__, strerror(error));
return -error;
}
int smbio_close_file(void *ctx, int fid)
{
struct smb_usr_rq *rqp;
mbchain_t mbp;
int error;
u_int16_t fid16 = fid;
error = smb_usr_rq_init(ctx, SMB_COM_CLOSE, 0, &rqp);
if (error)
return error;
mbp = smb_usr_rq_getrequest(rqp);
smb_usr_rq_wstart(rqp);
mb_put_uint16le(mbp, fid16);
mb_put_uint32le(mbp, -1);
smb_usr_rq_wend(rqp);
smb_usr_rq_bstart(rqp);
smb_usr_rq_bend(rqp);
error = smb_usr_rq_simple(rqp);
smb_usr_rq_done(rqp);
return error;
}
int smbio_check_directory(struct smb_ctx *ctx, const void *path,
uint32_t flags2, uint32_t *nt_error)
{
struct smb_usr_rq *rqp;
mbchain_t mbp;
int error;
error = smb_usr_rq_init(ctx, SMB_COM_CHECK_DIRECTORY, flags2, &rqp);
if (error)
return error;
mbp = smb_usr_rq_getrequest(rqp);
smb_usr_rq_wstart(rqp);
smb_usr_rq_wend(rqp);
smb_usr_rq_bstart(rqp);
mb_put_uint8(mbp, SMB_DT_ASCII);
error = smb_usr_rq_put_dstring(ctx, mbp, path, strlen(path),
SMB_UTF_SFM_CONVERSIONS, NULL);
if (error == 0) {
smb_usr_rq_bend(rqp);
error = smb_usr_rq_simple(rqp);
}
if (error && (error != ENOENT) && (error != ENOTDIR)) {
smb_log_info("%s failed, syserr = %s", ASL_LEVEL_DEBUG, __FUNCTION__, strerror(error));
}
if (nt_error) {
*nt_error = smb_usr_rq_nt_error(rqp);
}
smb_usr_rq_done(rqp);
return error;
}