smbfs_smb.c revision 7568150a58e78021968b6c22bc28e9787b33496a
/*
* 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: smbfs_smb.c,v 1.73.38.1 2005/05/27 02:35:28 lindak Exp $
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef APPLE
#include <sys/smb_apple.h>
#else
#include <netsmb/smb_osdep.h>
#endif
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <smbfs/smbfs_node.h>
#include <smbfs/smbfs_subr.h>
/*
* Local functions.
* Not static, to aid debugging.
*/
/*
* Todo: locking over-the-wire
*/
#ifdef APPLE
static int
{
int error;
/* Shared lock for n_fid use below. */
if (op == SMB_LOCK_SHARED)
if (largelock)
if (error)
return (error);
mb_put_uint16le(mbp, 0);
if (!largelock) {
} else {
}
/*
* Don't want to risk missing a successful
* unlock send or lock response, or we could
* lose track of an outstanding lock.
*/
if (op == SMB_LOCK_RELEASE)
else
return (error);
}
int
{
/*
* TODO: use LOCK_BYTE_RANGE here.
*/
return (EINVAL);
else
}
#endif /* APPLE */
/*
* Helper for smbfs_getattr
* Something like nfs_getattr_otw
*/
int
{
int error;
/*
* This lock is really only necessary for qfileinfo,
* but hopefully we use that most of the time.
* Lock may be writer (via open) or reader.
*/
else
/* fallback */
}
#if 0 /* Moved this part to caller. */
#endif
return (error);
}
/*
* Nearly identical to smbfs_smb_qfileinfo (below).
* Please keep them in sync.
*/
int
{
top:
if (error)
return (error);
if (!infolevel) {
else
}
mb_put_uint32le(mbp, 0);
/* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
if (error) {
return (error);
}
if (error) {
/* Invalid info level? Try fallback. */
goto top;
}
return (error);
}
switch (infolevel) {
case SMB_QFILEINFO_STANDARD:
timesok = 0;
timesok++;
}
timesok++;
}
break;
case SMB_QFILEINFO_ALL_INFO:
timesok = 0;
/* creation time (discard) */
/* last access time */
if (llongint) {
timesok++;
}
/* last write time */
if (llongint) {
timesok++;
}
/* last change time */
if (llongint) {
timesok++;
}
/* attributes */
/*
* 4-Byte alignment - discard
* Specs doesn't talk about this.
*/
/* allocation size (discard) */
/* File size */
break;
default:
}
/*
* if all times are zero (observed with FAT on NT4SP6)
* then fall back to older info level
*/
if (!timesok) {
if (infolevel == SMB_QFILEINFO_ALL_INFO) {
goto top;
}
}
return (error);
}
/*
* Nearly identical to smbfs_smb_qpathinfo (above).
* Please keep them in sync.
*/
int
{
/*
* Shared lock for n_fid use below.
* See smbfs_smb_getfattr()
*/
return (EBADF);
top:
if (error)
return (error);
if (!infolevel) {
else
}
if (error) {
/* Invalid info level? Try fallback. */
goto top;
}
return (error);
}
switch (infolevel) {
case SMB_QFILEINFO_STANDARD:
timesok = 0;
timesok++;
}
timesok++;
}
break;
case SMB_QFILEINFO_ALL_INFO:
timesok = 0;
/* creation time (discard) */
/* last access time */
if (llongint) {
timesok++;
}
/* last write time */
if (llongint) {
timesok++;
}
/* last change time */
if (llongint) {
timesok++;
}
/* attributes */
/*
* 4-Byte alignment - discard
* Specs doesn't talk about this.
*/
/* allocation size (discard) */
/* File size */
break;
default:
}
/*
* if all times are zero (observed with FAT on NT4SP6)
* then fall back to older info level
*/
if (!timesok) {
if (infolevel == SMB_QFILEINFO_ALL_INFO) {
goto top;
}
}
return (error);
}
/*
* Support functions for _qstreaminfo
* Todo: show NT file streams as
* Solaris named attributes.
*/
#ifdef APPLE
static char *
{
sizeof (SFM_RESOURCEFORK_NAME)))
return (XATTR_RESOURCEFORK_NAME);
sizeof (SFM_FINDERINFO_NAME)))
return (XATTR_FINDERINFO_NAME);
return (NULL);
}
static int
{
char *cp;
goto bad;
goto bad;
goto bad;
goto bad;
return (0); /* skip it */
/*
* XXX here we should be calling KPI to validate the stream name
*/
return (0); /* skip protected system attrs */
goto bad; /* mustnt return more than 128 bytes */
/*
* Un-count a colon and the $DATA, then the
* 2nd colon is replaced by a terminating null.
*/
*cp = '\0';
return (1);
bad:
SMBSDEBUG("file \"%.*s\" has bad stream \"%.*s\"\n",
return (0); /* skip it */
}
PRIVSYM int
{
int error;
struct smbfs_fctx ctx;
*sizep = 0;
if (error)
return (error);
/*
* SMB_QFILEINFO_STREAM_INFORMATION is an option to consider
* here. Samba declined to support the older info level with
* a comment claiming doing so caused a BSOD.
*/
mb_put_uint32le(mbp, 0);
/* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
if (error)
goto out;
if (error) {
goto out;
}
/*
* On a directory Windows is likely to return a zero data count.
* Check for that now to avoid EBADRPC from md_get_uint32le
*/
goto out;
do {
goto out;
goto out;
goto out;
goto out;
/*
* Sanity check to limit DoS or buffer overrun attempts.
* The arbitrary 16384 is sufficient for all legit packets.
*/
if (nlen > 16384) {
SMBVDEBUG("huge name length in packet!\n");
goto out;
}
goto out;
/*
*/
SMBVDEBUG("huge offset in packet!\n");
goto out;
}
}
/* ignore a trailing null, not that we expect them */
if (SMB_UNICODE_STRINGS(vcp)) {
nlen -= 2;
} else {
nlen -= 1;
}
/*
* We should now have a name in the form
* : <foo> :$DATA
* Where <foo> is UTF-8 w/o null termination
* If it isn't in that form we want to LOG it and skip it.
* Note we want to skip w/o logging the "data fork" entry,
* which is simply ::$DATA
* Otherwise we want to uiomove out <foo> with a null added.
*/
char *s;
/* the "+ 1" skips over the leading colon */
#ifndef DUAL_EAS /* XXX */
/*
* In Tiger Carbon still accesses dot-underscore files directly, so...
* than mapping them to com.apple.*. This means our copy engines
*/
s = NULL;
#endif
if (s)
else
if (uio)
else
}
out:
return (error);
}
#endif /* APPLE */
int
{
int error;
char *fs_name; /* will malloc whatever the size is */
struct smbfs_fctx ctx;
if (error)
return (error);
if (error) {
return (error);
}
/*
* If fs_name isn't NTFS they probably require resume keys.
* This is another example of the client trying to fix a server
* bug. This code uses the logic created by PR-3983209. See
* long block comment in smbfs_smb_findnextLM2.
*/
}
SMBVDEBUG("(fyi) share '%s', attr 0x%x, maxfilename %d\n",
}
return (0);
}
int
{
int error;
else
return (error);
}
int
{
uint64_t s, t, f;
int error;
if (error)
return (error);
if (error) {
return (error);
}
s = bsize;
s *= bpu;
t = units;
f = funits;
/*
* Don't allow over-large blocksizes as they determine
* Finder List-view size granularities. On the other
* hand, we mustn't let the block count overflow the
* 31 bits available.
*/
while (s > 16 * 1024) {
if (t > LONG_MAX)
break;
s /= 2;
t *= 2;
f *= 2;
}
while (t > LONG_MAX) {
t /= 2;
f /= 2;
s *= 2;
}
return (0);
}
int
{
uint64_t s, t, f;
int error;
scrp);
if (error)
return (error);
if (error) {
return (error);
}
s = bsize;
s *= bpu;
t = units;
f = funits;
/*
* Don't allow over-large blocksizes as they determine
* Finder List-view size granularities. On the other
* hand, we mustn't let the block count overflow the
* 31 bits available.
*/
while (s > 16 * 1024) {
if (t > LONG_MAX)
break;
s /= 2;
t *= 2;
f *= 2;
}
while (t > LONG_MAX) {
t /= 2;
f /= 2;
s *= 2;
}
return (0);
}
int
{
int error;
if (error)
return (error);
else
mb_put_uint16le(mbp, 0);
t2p->t2_maxdcount = 0;
return (error);
}
/*ARGSUSED*/
int
{
/* Shared lock for n_fid use below. */
return (ENOTSUP);
if (error)
return (error);
if (tdnp) {
&fid);
if (error)
goto exit;
}
if (error)
goto exit;
t2p->t2_maxdcount = 0;
exit:
if (fid) {
if (cerror)
}
return (error);
}
int
{
int error;
/* Shared lock for n_fid use below. */
return (0);
return (0); /* not open */
return (0); /* not a file */
if (error)
return (error);
if (!error) {
}
return (error);
}
int
{
int error;
/*
* This call knows about 64-bit offsets.
*/
if (!error) {
return (0);
}
/*
* If we have SMB_CAP_LARGE_FILES, the above
* should have worked. XXX: Don't fallback?
* XXX: Or fallback on specific errors?
*/
}
/*
* OK, so fallback to SMB_COM_WRITE, but note:
* it only supports 32-bit file offsets.
*/
if (newsize > UINT32_MAX)
return (EFBIG);
if (error)
return (error);
mb_put_uint16le(mbp, 0);
mb_put_uint16le(mbp, 0);
mb_put_uint16le(mbp, 0);
return (error);
}
int
{
int error;
if (error)
return (error);
do {
if (error)
break;
if (error)
break;
break;
}
/*
* Be careful using the time returned here, as
* with FAT on NT4SP6, at least, the time returned is low
* 32 bits of 100s of nanoseconds (since 1601) so it rolls
* over about every seven minutes!
*/
if (longint) /* avoid bogus zero returns */
/*LINTED*/
} while (0);
return (error);
}
int
{
int error;
/*
* This is the logic that was in smbfs_vnops.c
*/
/*
* NT4 doesn't understand "NT" style SMBs;
* for NT4 we use the old SET_PATH_INFO
* XXX Actually, I think the issue is that
* NT requires an open handle for this.
*/
return (error);
/* NT4 response, remember */
}
} else {
}
return (error);
}
/*
* Set DOS file attributes. mtime should be NULL for dialects above lm10
*/
int
{
long time;
if (error)
return (error);
if (mtime) {
} else
time = 0;
do {
if (error)
break;
}
mb_put_uint8(mbp, 0);
if (error)
break;
/*LINTED*/
} while (0);
return (error);
}
int
{
int error;
attr |= SMB_FA_HIDDEN;
}
return (error);
}
int
{
int error;
attr &= ~SMB_FA_HIDDEN;
}
return (error);
}
/*
* Note, win95 doesn't support this call.
*/
int
{
if (error)
return (error);
/* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
if (error) {
return (error);
}
if (atime)
else
if (mtime)
else
return (error);
}
/*
* *BASIC_INFO works with Samba, but Win2K servers say it is an
* invalid information level on a SET_PATH_INFO. Note Win2K does
* support *BASIC_INFO on a SET_FILE_INFO, and they support the
* equivalent *BASIC_INFORMATION on SET_PATH_INFO. Go figure.
*/
int
{
/* 64 bit value for Jan 1 1980 */
if (error)
return (error);
else
/* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
if (error) {
return (error);
}
/* do we know it won't support dates < 1980? */
if (atime) {
} else
tm = 0;
if (mtime) {
} else
tm = 0;
}
/*
* "invalid argument" error probably means it's a
* FAT drive that doesn't accept dates earlier
* than 1980, so adjust dates and retry. If the
* 1980 flag is on we fell thru the if {} above
*/
if (atime) {
if (tm < DIFF1980TO1601)
tm = DIFF1980TO1601;
} else
tm = 0;
if (mtime) {
if (tm < DIFF1980TO1601)
tm = DIFF1980TO1601;
} else
tm = 0;
/* if this worked set flag to do the right thing next time */
if (!(error)) {
}
}
return (error);
}
int
{
int error;
/*
* This is the logic that was in smbfs_vnops.c
* Might not be quite right for older dialects.
* (XXX: What about the DOS attributes?)
*/
else
return (error);
}
/*
* Set file atime and mtime. Isn't supported by core dialect.
*/
int
{
if (error)
return (error);
if (atime)
else
if (mtime)
else
return (error);
}
/*
* Set DOS file attributes.
* Looks like this call can be used only if CAP_NT_SMBS bit is on.
*/
int
{
if (error)
return (error);
else
if (atime) {
} else
tm = 0;
if (mtime) {
} else
tm = 0;
t2p->t2_maxdcount = 0;
return (error);
}
/*
*
* If disp is ..._DISP_OPEN, or ...DISP_OPEN_IF, or...
* then this is an open attempt, and:
* If xattr then name is the stream to be opened at np,
* Else np should be opened.
* ...we won't touch *fidp,
* ...we will set or clear *attrcacheupdated.
* Else this is a creation attempt, and:
* If xattr then name is the stream to create at np,
* Else name is the thing to create under directory np.
* ...we will return *fidp,
* ...we won't touch *attrcacheupdated.
*
* Note, We use: disp = ...OPEN_IF, ...OVERWRITE_IF, etc.
* now too, which may or may not create a new object.
*/
int
{
int error;
/*
* Set the File attributes and Create options.
* WinXP uses EFA_NORMAL in all of these cases.
*/
}
if (error)
return (error);
/*
* XP to a W2K Server does not use NTCREATEX_FLAGS_OPEN_DIRECTORY
* for creating nor for opening a directory. Samba ignores the bit.
*/
#if 0 /* causes sharing violation when making dir on W2K! */
#else
#endif
do {
nmlen = 0;
if (error)
break;
/*
* Don't want to risk missing a successful
* open response, or we could "leak" FIDs.
*/
if (error)
break;
/*
* spec says 26 for word count, but 34 words are defined
* and observed from win2000
*/
break;
}
if (llongint) /* avoid bogus 0 time (on FAT roots) */
if (llongint) /* avoid bogus 0 time (on FAT roots) */
if (llongint) /* avoid bogus 0 time (on FAT roots) */
if (sizep)
/*LINTED*/
} while (0);
if (error)
return (error);
if (fidp)
if (rightsp)
/*
* Is it possible that we have cached attributes?
* Assume "not cached" if we created the object.
*/
goto uncached;
if (attrcacheupdated)
*attrcacheupdated = 0;
/*
* Update the cached attributes if they are still valid
* in the cache and if nothing has changed.
*/
goto uncached;
goto uncached; /* the cached attributes are not valid */
goto uncached; /* the size is different */
goto uncached; /* the attrs are different */
/*
* fap.fa_mtime is in two second increments while np->n_mtime
* may be in one second increments, so comparing the times is
* somewhat sloppy.
*
* XXX: true fap.fa_mtime resolution must depend upon server's
* local filesystem and is thus indeterminate... XXX ...TBD how that
* affects this code... note wire resolution here is 100ns versus
* 1sec down in smbfs_smb_oldopen(SMB_COM_OPEN)
*/
goto uncached; /* the mod time is different */
if (attrcacheupdated)
*attrcacheupdated = 1;
return (0);
}
static uint32_t
smb_mode2rights(int mode)
{
switch (mode) {
case SMB_AM_OPENREAD:
return (GENERIC_RIGHT_READ_ACCESS);
case SMB_AM_OPENWRITE:
return (GENERIC_RIGHT_WRITE_ACCESS);
case SMB_AM_OPENRW:
return (GENERIC_RIGHT_ALL_ACCESS);
case SMB_AM_OPENEXEC:
return (GENERIC_RIGHT_EXECUTE_ACCESS);
}
return (0);
}
static int
{
return (accmode);
}
static int
{
int error;
/*
* Use DENYNONE to give unixy semantics of permitting
* everything not forbidden by permissions. Ie denial
* advisory locks for further control.
*/
if (error)
return (error);
do {
if (error)
break;
/*
* Don't want to risk missing a successful
* open response, or we could "leak" FIDs.
*/
if (error)
break;
/*
* 8/2002 a DAVE server returned wc of 15 so we ignore that.
* (the actual packet length and data was correct)
*/
break;
}
/*
* Be careful using the time returned here, as
* with FAT on NT4SP6, at least, the time returned is low
* 32 bits of 100s of nanoseconds (since 1601) so it rolls
* over about every seven minutes!
*/
if (longint) /* avoid bogus zero returns */
if (sizep)
/*LINTED*/
} while (0);
if (error)
return (error);
if (fidp)
if (xattr)
goto uncached;
if (rightsp)
if (attrcacheupdated)
*attrcacheupdated = 0;
/*
* Update the cached attributes if they are still valid
* in the cache and if nothing has changed.
* Note that this won't ever update if the file size is
* greater than the 32-bits returned by SMB_COM_OPEN.
* For 64-bit file sizes, SMB_COM_NT_CREATE_ANDX must
* be used instead of SMB_COM_OPEN.
*/
goto uncached;
goto uncached; /* the cached attributes are not valid */
goto uncached; /* the size is different */
goto uncached; /* the attrs are different */
/*
* fap.fa_mtime is in two second increments while np->n_mtime
* may be in one second increments, so comparing the times is
* somewhat sloppy.
*/
goto uncached; /* the mod time is different */
if (attrcacheupdated)
*attrcacheupdated = 1;
return (0);
}
int
{
int error;
/* Shared lock for n_fid use below. */
return (0);
}
} else {
}
/*
* Oh no, the server gave us the same FID again?
* This will cause us to close np->n_fid early!
*/
}
return (error);
}
int
{
int error = 0;
/* Shared lock for n_fid use below. */
/*
* Don't expect to find the last reference
* here in tmpclose. Hard to deal with as
* we don't have r_lkserlock exclusive.
* Will close oldfid below.
*/
}
} else {
/* Will close the passed fid. */
}
if (oldfid != SMB_FID_UNUSED)
return (error);
}
int
{
int error;
} else {
}
#if 0 /* let caller do this */
#endif
return (error);
}
int
{
long time;
int error;
if (error)
return (error);
if (mtime) {
} else
time = 0;
/*
* We don't really care about the result here, but we
* do need to make sure we send this out, or we could
* "leak" open file handles on interrupt or timeout.
* The NOINTR_SEND flag makes this request immune to
* interrupt or timeout until the send is done.
*/
/*
* ENOTCONN isn't interesting - if the connection is closed,
* so are all our FIDs - and EIO is also not interesting,
* as it means a forced unmount was done. (was ENXIO)
* Also ETIME, which means we sent the request but gave up
* waiting before the response came back.
*
* Don't clog up the system log with warnings about these
* uninteresting failures on closes.
*/
switch (error) {
case ENOTCONN:
case ENXIO:
case EIO:
case ETIME:
error = 0;
}
return (error);
}
static int
{
long tm;
int error;
if (error)
return (error);
attr |= SMB_FA_HIDDEN;
gethrestime(&ctime);
if (!error) {
/*
* Don't want to risk missing a successful
* open response, or we could "leak" FIDs.
*/
if (!error) {
if (wc == 1)
else
}
}
return (error);
}
int
{
/*
* At present the only access we might need is to WRITE data,
* access needed gets more complex it should made a parameter
* and be set upstream.
*/
} else
xattr));
}
int
{
int error;
if (error)
return (error);
if (!error) {
}
return (error);
}
int
{
int error;
if (error)
return (error);
/* freebsd bug: Let directories be renamed - Win98 requires DIR bit */
do {
if (error)
break;
'\\');
if (error)
break;
/*LINTED*/
} while (0);
return (error);
}
int
{
int error;
if (error)
return (error);
do {
if (error)
break;
'\\');
if (error)
break;
/*LINTED*/
} while (0);
return (error);
}
static int
{
int error;
if (error)
return (error);
if (!error) {
}
return (error);
}
int
{
int error;
/*
* We ask for SA_RIGHT_FILE_READ_DATA not because we need it, but
* just to be asking for something. The rights==0 case could
* easily be broken on some old or unusual servers.
*/
if (error)
return (error);
if (error)
return (0);
} else
}
int
{
int error;
if (error)
return (error);
if (!error) {
}
return (error);
}
static int
{
}
if (error)
return (error);
&len, '\\');
if (error)
return (error);
} else {
if (SMB_UNICODE_STRINGS(vcp)) {
mb_put_uint8(mbp, 0);
}
mb_put_uint8(mbp, 0);
}
error = 0;
iseof = 1;
} else if (error)
return (error);
if (wc != 1)
if (ec == 0)
return (ENOENT);
if (bc < 3)
return (EBADRPC);
bc -= 3;
if (bt != SMB_DT_VARIABLE)
return (EBADRPC);
return (EBADRPC);
return (0);
}
/*ARGSUSED*/
static int
{
/* #pragma unused(dnp, scrp) */
if (wildcard) {
} else {
}
} else {
}
return (0);
}
static int
{
char *cp;
int error;
return (ENOENT);
gethrestime(&ts);
if (error)
return (error);
}
*cp-- = 0;
return (0);
}
static int
{
return (0);
}
/*
* TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
*/
static int
{
}
}
if (error)
return (error);
mb_put_uint32le(mbp, 0);
/* mb_put_uint8(mbp, SMB_DT_ASCII); specs? hah! */
&len, '\\');
if (error)
return (error);
} else {
if (error)
return (error);
} else
mb_put_uint32le(mbp, 0);
/* resume file name */
}
/* Add trailing null - 1 byte if ASCII, 2 if Unicode */
mb_put_uint8(mbp, 0);
#if 0
/*
* some implementations suggests to sleep here
* for 200ms, due to the bug in the Win95.
* I've didn't notice any problem, but put code
* for it.
*/
}
#endif
}
if (error)
return (error);
return (error);
}
return (error);
return (error);
/*
* tw now is the "end of search" flag. against an XP server tw
* comes back zero when the prior find_next returned exactly
* the number of entries requested. in which case we'd try again
* but the search has in fact been closed so an EBADF results. our
* circumvention is to check here for a zero search count.
*/
return (error);
return (error);
return (ENOENT);
return (ENOENT);
}
#ifdef APPLE
printf("bug: ecnt = %d, but m_len = 0 and m_next = %p "
return (ENOENT);
}
#endif
return (0);
}
static int
{
int error;
if (error)
return (error);
/* Ditto comments at _smb_close */
return (error);
}
/*ARGSUSED*/
static int
{
return (0);
}
static int
{
char *cp;
otw = 0; /* nothing sent Over The Wire (yet) */
return (ENOENT);
gethrestime(&ts);
if (error)
return (error);
otw = 1;
}
switch (ctx->f_infolevel) {
case SMB_FIND_STANDARD:
next = 0;
fxsz = 0;
fxsz = 23;
break;
case SMB_FIND_DIRECTORY_INFO:
/* freebsd bug: fa_attr endian bug */
/*
* Skip EaSize(4 bytes), a byte of ShortNameLength,
* a reserved byte, and ShortName(8.3 means 24 bytes,
* as Leach defined it to always be Unicode)
*/
fxsz += 30;
}
break;
default:
return (EINVAL);
}
else
if (error)
return (error);
if (next) {
if (cnt > 0)
else if (cnt < 0) {
SMBVDEBUG("out of sync\n");
return (EBADRPC);
}
}
/* Don't count any trailing null in the name. */
nmlen -= 2;
} else {
nmlen--;
}
if (nmlen == 0)
return (EBADRPC);
/*
* Ref radar 3983209. On a find-next we expect a server will
* 1) if the continue bit is set, use the server's idea of current loc,
* 2) else if the resume key is non-zero, use that location,
* 3) else if the resume name is set, use that location,
* 4) else use the server's idea of current location.
*
* Current NetApps don't do that. If we send no continue bit, a zero
* resume key, and a resume name, the NetApp ignores the resume name
* and acts on the (zero) resume key, sending back the start of the
* directory again. Panther doesn't expose the netapp bug; Panther used
* the continue bit, but that was changed for 2866172. Win2000 as a
* client also relies upon the resume name, but they request a very
* large number of files, so the bug would be seen only with very
* large directories.
*
* Our fix is to notice if the second OTW op (the first find-next)
* returns, in the first filename, the same filename we got back
* at the start of the first OTW (the find-first). In that case
* we've detected the server bug and set SMBS_RESUMEKEYS, causing us
* to send non-zero resume keys henceforth.
*
* Caveat: if there's a netapp so old it doesn't negotiate NTLM 0.12
* then we get no resume keys so f_rkey stays zero and this "fix"
* changes nothing.
*
* Note due to a similar problem (4051871) we also set SMBS_RESUMEKEYS
* for FAT volumes, at mount time.
*/
"server resume_name bug seen; using resume keys\n");
goto again; /* must redo last otw op! */
}
}
if (ctx->f_rnameofs &&
/*
* Server needs a resume filename.
*/
}
}
return (0);
}
static int
{
int error = 0;
return (error);
}
int
struct smbfs_fctx **ctxpp)
{
struct smbfs_fctx *ctx;
int error;
return (ENOMEM);
}
} else
if (error)
else
return (error);
}
int
{
int error;
/*
* Note: "limit" (maxcount) needs to fit in a short!
*
* smb_lookup always uses 1, which is OK (no wildcards).
* Otherwise, this is smbfs_readdir, and we want to force
* limit to be in the range 3 to 1000. The low limit (3)
* is so we can always give the caller one "real" entry
* (something other than "." or "..") The high limit is
* just tuning. WinNT used 512, Win2k 1366. We use 1000.
*
* XXX: Move the [skip . ..] gunk to our caller (readdir).
*/
if (limit < 3)
limit = 3;
if (limit > 1000)
limit = 1000;
}
for (;;) {
} else
if (error)
return (error);
/*LINTED*/
/* Do comparisons on UCS-2LE characters */
continue;
} else {
continue;
}
break;
}
return (0);
}
int
{
int error;
} else
return (error);
}
int
{
struct smbfs_fctx *ctx;
/* This is no longer called with a null dnp */
/*
* Should not get here with "" anymore.
*/
DEBUG_ENTER("smbfs_smb_lookup: name is NULL");
return (EINVAL);
}
/*
* Should not get here with "." or ".." anymore.
*/
DEBUG_ENTER("smbfs_smb_lookup: name is '.' or '..'");
return (EINVAL);
}
/*
* Shared lock for n_fid use (smb_flush).
*/
return (EINTR);
/*
* This hides a server bug observable in Win98:
* size changes may not show until a CLOSE or a FLUSH op
* XXX: Make this conditional on !NTSMBs
*/
if (error)
goto out;
if (error)
goto out;
if (error == 0) {
if (namep)
*namep = (const char *)smbfs_name_alloc(
if (nmlenp)
}
out:
return (error);
}
/*
* OTW function to Get a security descriptor (SD).
*
* Note: On success, this fills in mdp->md_top,
* which the caller should free.
*/
int
{
if (error)
return (error);
/* Parameters part */
/* Data part (none) */
/* Max. returned parameters and data. */
goto done;
/*
* if there's more data than we said we could receive, here
* is where we pick up the length of it
*/
if (error)
goto done;
/*
* get the data part.
*/
goto done;
}
/*
* The returned parameter SD_length should match
* the length of the returned data. Unfortunately,
* we have to work around server bugs here.
*/
SMBVDEBUG("len %d *reslen %d fid 0x%x\n",
}
/*
* Actual data provided is < returned SD_length.
*
* The following "if (len < *reslen)" handles a Windows bug
* observed when the underlying filesystem is FAT32. In that
* case a 32 byte security descriptor comes back (S-1-1-0, ie
* "Everyone") but the Parameter Block claims 44 is the length
* of the security descriptor. (The Data Block length
* claimed is 32. This server bug was reported against NT
* first and I've personally observed it with W2K.
*/
/*
* Actual data provided is > returned SD_length.
* (Seen on StorageTek NAS 5320, s/w ver. 4.21 M0)
* Narrow work-around for returned SD_length==0.
*/
/*
* Increase *reslen, but carefully.
*/
}
done:
}
return (error);
}
#ifdef APPLE
/*
* Wrapper for _getsd() compatible with darwin code.
*/
int
{
int error;
struct mbuf *m;
/*
* Server may give us an error indicating that we
* need a larger data buffer to receive the SD,
* and the size we'll need. Use the given size,
* but only after a sanity check.
*
* XXX: Check for specific error values here?
* XXX: also ... && len <= MAX_RAW_SD_SIZE
*/
goto again;
if (error)
return (error);
return (error);
}
#endif /* APPLE */
/*
* OTW function to Set a security descriptor (SD).
* Caller data are carried in an mbchain_t.
*
* Note: This normally consumes mbp->mb_top, and clears
* that pointer when it does.
*/
{
int error;
if (error)
return (error);
/* Parameters part */
/* Data part */
/* No returned parameters or data. */
ntp->nt_maxpcount = 0;
ntp->nt_maxdcount = 0;
return (error);
}
#ifdef APPLE
/*
* This function builds the SD given the various parts.
*/
int
{
/*
* Build the SD as its own mbuf chain and pass it to
* smbfs_smb_setsec_m()
*/
/*
* A note about flags ("SECURITY_DESCRIPTOR_CONTROL" in MSDN)
* We set here only those bits we can be sure must be set. The rest
* are up to the caller. In particular, the caller may intentionally
* set an acl PRESENT bit while giving us a null pointer for the
* acl - that sets a null acl, giving access to everyone. Note also
* that the AUTO_INHERITED bits should probably always be set unless
* the server is NT.
*/
if (owner) {
}
if (group) {
}
if (sacl) {
flags |= SD_SACL_PRESENT;
}
if (dacl) {
flags |= SD_DACL_PRESENT;
}
if (owner)
if (group)
if (sacl)
if (dacl)
/*
* Just pass the mbuf to _setsec_m
* It will clear mb_top if consumed.
*/
return (error);
}
#endif /* APPLE */