/*
* Copyright (c) 2000-2001 Boris Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Boris Popov.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: smb_smb.c,v 1.35.100.2 2005/06/02 00:55:39 lindak Exp $
*/
/*
* Copyright 2012 Nexenta Systems, Inc. All rights reserved.
*/
/*
* various SMB requests. Most of the routines merely packs data into mbufs.
*/
#include <netsmb/smb_osdep.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_tran.h>
/*
* Largest size to use with LARGE_READ/LARGE_WRITE.
* Specs say up to 64k data bytes, but Windows traffic
* uses 60k... no doubt for some good reason.
* (Probably to keep 4k block alignment.)
* XXX: Move to smb.h maybe?
*/
/*
* Default timeout values, all in seconds.
* Make these tunable (only via mdb for now).
*/
/*
* Get the string representation of a share "use" type,
* as needed for the "service" in tree connect.
*/
static const char *
{
const char *p;
switch (stype) {
case STYPE_DISKTREE:
p = "A:";
break;
case STYPE_PRINTQ:
p = "LPT1:";
break;
case STYPE_DEVICE:
p = "COMM";
break;
case STYPE_IPC:
p = "IPC";
break;
case STYPE_UNKNOWN:
default:
p = "?????";
break;
}
return (p);
}
/*
* Parse a share type name (inverse of above)
*/
static uint32_t
{
int stype;
switch (*name) {
case 'A': /* A: */
break;
case 'C': /* COMM */
break;
case 'I': /* IPC */
break;
case 'L': /* LPT: */
break;
default:
break;
}
return (stype);
}
int
{
const char *tname;
/*
* Make this a "VC-level" request, so it will have
* rqp->sr_share == NULL, and smb_iod_sendrq()
* will send it with TID = SMB_TID_UNKNOWN
*
* This also serves to bypass the wait for
* share state changes, which this call is
* trying to carry out.
*/
if (error)
return (error);
/*
* but with backslashes of course.
* size math: three slashes, one null.
*/
/*
* Share-level password (pre-computed in user-space)
* MS-SMB 2.2.6 says this should be null terminated,
* and the pw length includes the null.
*/
/*
* Build the request.
*/
mb_put_uint8(mbp, 0);
mb_put_uint16le(mbp, 0);
/* Tree connect password, if any */
if (error)
goto out;
/* UNC resource name */
if (error)
goto out;
/*
* Put the type string (always ASCII),
* including the null.
*/
if (error)
goto out;
/*
* Run the request.
*
* Using NOINTR_RECV because we don't want to risk
* missing a successful tree connect response,
* which would "leak" Tree IDs.
*/
if (error) {
/*
* If we get the server name wrong, i.e. due to
* mis-configured name services, this will be
* NT_STATUS_DUPLICATE_NAME. Log this error.
*/
SMBERROR("(%s) failed, status=0x%x",
goto out;
}
/*
* Parse the TCON response
*/
goto out;
}
if (wc == 7) {
}
if (error)
goto out;
/*
* Get the returned share type string, i.e. "IPC" or whatever.
* (See smb_share_typename, smb_share_parsetype). If we get
* an error reading the type, just say STYPE_UNKNOWN.
*/
/* Success! */
out:
if (unc_name)
return (error);
}
int
{
int error;
return (0);
/*
* Build this as a "VC-level" request, so it will
* avoid testing the _GONE flag on the share,
* which has already been set at this point.
* Add the share pointer "by hand" below, so
* smb_iod_sendrq will plug in the TID.
*/
if (error)
return (error);
/*
* Run this with a relatively short timeout. (5 sec.)
* We don't really care about the result here, but we
* do need to make sure we send this out, or we could
* "leak" active tree IDs on interrupt or timeout.
* The NOINTR_SEND flag makes this request immune to
* interrupt or timeout until the send is done.
* Also, don't reconnect for this, of course!
*/
return (error);
}
/*
*/
int
{
int error;
if (error)
return (error);
/* Word parameters */
/*
* Byte parameters: Just the path name, aligned.
* Note: mb_put_mbuf consumes mb_top, so clear it.
*/
if (SMB_UNICODE_STRINGS(vcp))
/*
* Don't want to risk missing a successful
* open response, or we could "leak" FIDs.
*/
if (error)
goto done;
/*
* spec says 26 for word count, but 34 words are defined
* and observed from win2000
*/
if (error)
goto done;
goto done;
}
/* other stuff we don't care about */
done:
if (error)
return (error);
if (cr_act_p)
if (fap)
return (0);
}
int
{
long time;
int error;
if (error)
return (error);
if (mtime) {
} else {
time = 0;
}
/* Make sure we send, but only if already connected */
return (error);
}
int
char *title,
{
int error;
if (error)
return (error);
/* Word parameters */
/*
* Byte parameters: Just the title
*/
if (error)
goto done;
/*
* Don't want to risk missing a successful
* open response, or we could "leak" FIDs.
*/
if (error)
goto done;
goto done;
}
done:
if (error)
return (error);
return (0);
}
/*
* Like smb_smb_close, but for print shares.
*/
int
{
int error;
if (error)
return (error);
/* Make sure we send but only if already connected */
return (error);
}
/*
* Called by netsmb smb_usr_rw,
* smbfs_readvnode, smbfs_writevnode
*/
int
{
int error = 0;
uio_t *, smb_cred_t *, int);
/*
* Determine which function to use,
* and the transfer size per call.
*/
/*
* Using NT LM 0.12, so readx, writex.
* Make sure we can represent the offset.
*/
return (EFBIG);
else
} else { /* UIO_WRITE */
else
}
} else {
/*
* Using the old SMB_READ and SMB_WRITE so
* we're limited to 32-bit offsets, etc.
* XXX: Someday, punt the old dialects.
*/
return (EFBIG);
} else { /* UIO_WRITE */
}
}
/* Lint: uio_resid may be 64-bits */
/*
* Note: the iofun called uio_update, so
* not doing that here as one might expect.
*
* Quit the loop either on error, or if we
* transferred less then requested.
*/
break;
timo = 0; /* only first I/O should wait */
}
/*
* Stopped on an error after having
* successfully transferred data.
* Suppress this error.
*/
error = 0;
}
return (error);
}
static int
{
int error;
if (error)
return (error);
/* (only indicates blocking) */
if (timo == 0)
if (error)
goto out;
if (error)
goto out;
if (wc != 12) {
goto out;
}
if (error)
goto out;
/*
* Does the data offset indicate padding?
* The current offset is a constant, found
* by counting the md_get_ calls above.
*/
if (rlen == 0) {
goto out;
}
/* paranoid */
SMBSDEBUG("bad server! rlen %d, len %d\n",
}
if (error)
goto out;
/* Success */
out:
return (error);
}
static int
{
int error;
if (error)
return (error);
mb_put_uint16le(mbp, 0);
if (error)
goto out;
if (timo == 0)
if (error)
goto out;
if (error)
goto out;
if (wc != 6) {
goto out;
}
if (error)
goto out;
/* Success */
out:
return (error);
}
static int
{
int error;
/* This next is an "estimate" of planned reads. */
if (error)
return (error);
if (timo == 0)
if (error)
goto out;
if (error)
goto out;
if (wc != 5) {
goto out;
}
if (error)
goto out;
SMBSDEBUG("oops: dlen=%d rcnt=%d\n",
}
if (rcnt == 0) {
*lenp = 0;
goto out;
}
/* paranoid */
SMBSDEBUG("bad server! rcnt %d, cnt %d\n",
}
if (error)
goto out;
/* success */
out:
return (error);
}
static int
{
int error;
/* This next is an "estimate" of planned writes. */
if (error)
return (error);
if (error)
goto out;
if (timo == 0)
if (error)
goto out;
if (error)
goto out;
if (wc != 1) {
goto out;
}
if (error)
goto out;
out:
return (error);
}
int
{
int error;
if (error)
return (error);
/*
* Note: the IOD calls this, so
* this request must not wait for
* connection state changes, etc.
*/
return (error);
}