summaryrefslogtreecommitdiffstats
path: root/source/smbd
diff options
context:
space:
mode:
Diffstat (limited to 'source/smbd')
-rw-r--r--source/smbd/close.c4
-rw-r--r--source/smbd/dir.c6
-rw-r--r--source/smbd/dosmode.c36
-rw-r--r--source/smbd/fileio.c4
-rw-r--r--source/smbd/files.c6
-rw-r--r--source/smbd/msdfs.c841
-rw-r--r--source/smbd/negprot.c4
-rw-r--r--source/smbd/notify_inotify.c4
-rw-r--r--source/smbd/nttrans.c138
-rw-r--r--source/smbd/open.c3
-rw-r--r--source/smbd/pipes.c2
-rw-r--r--source/smbd/process.c23
-rw-r--r--source/smbd/reply.c678
-rw-r--r--source/smbd/sesssetup.c236
-rw-r--r--source/smbd/trans2.c711
15 files changed, 1844 insertions, 852 deletions
diff --git a/source/smbd/close.c b/source/smbd/close.c
index b826cd622af..a123a542fd2 100644
--- a/source/smbd/close.c
+++ b/source/smbd/close.c
@@ -373,9 +373,9 @@ static NTSTATUS close_normal_file(files_struct *fsp, enum file_close_type close_
* Ensure pending modtime is set after close.
*/
- if(fsp->pending_modtime && fsp->pending_modtime_owner) {
+ if (fsp->pending_modtime_owner && !null_timespec(fsp->pending_modtime)) {
set_filetime(conn, fsp->fsp_name, fsp->pending_modtime);
- } else if (fsp->last_write_time) {
+ } else if (!null_timespec(fsp->last_write_time)) {
set_filetime(conn, fsp->fsp_name, fsp->last_write_time);
}
diff --git a/source/smbd/dir.c b/source/smbd/dir.c
index 2795b2a24b2..db3e155ae47 100644
--- a/source/smbd/dir.c
+++ b/source/smbd/dir.c
@@ -1017,6 +1017,7 @@ BOOL is_visible_file(connection_struct *conn, const char *dir_path, const char *
}
if (hide_unreadable || hide_unwriteable || hide_special) {
+ pstring link_target;
char *entry = NULL;
if (asprintf(&entry, "%s/%s", dir_path, name) == -1) {
@@ -1026,10 +1027,7 @@ BOOL is_visible_file(connection_struct *conn, const char *dir_path, const char *
/* If it's a dfs symlink, ignore _hide xxxx_ options */
if (lp_host_msdfs() &&
lp_msdfs_root(SNUM(conn)) &&
- /* We get away with NULL talloc ctx here as
- we're not interested in the link contents
- so we have nothing to free. */
- is_msdfs_link(NULL, conn, entry, NULL, NULL, NULL)) {
+ is_msdfs_link(conn, entry, link_target, NULL)) {
SAFE_FREE(entry);
return True;
}
diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c
index ad79bbacddf..71d4fa179d4 100644
--- a/source/smbd/dosmode.c
+++ b/source/smbd/dosmode.c
@@ -282,7 +282,7 @@ static BOOL set_ea_dos_attribute(connection_struct *conn, const char *path, SMB_
}
/* We want DOS semantics, ie allow non owner with write permission to change the
- bits on a file. Just like file_utime below.
+ bits on a file. Just like file_ntimes below.
*/
/* Check if we have write access. */
@@ -504,7 +504,7 @@ int file_set_dosmode(connection_struct *conn, const char *fname,
return -1;
/* We want DOS semantics, ie allow non owner with write permission to change the
- bits on a file. Just like file_utime below.
+ bits on a file. Just like file_ntimes below.
*/
/* Check if we have write access. */
@@ -532,11 +532,11 @@ int file_set_dosmode(connection_struct *conn, const char *fname,
}
/*******************************************************************
- Wrapper around dos_utime that possibly allows DOS semantics rather
+ Wrapper around the VFS ntimes that possibly allows DOS semantics rather
than POSIX.
*******************************************************************/
-int file_utime(connection_struct *conn, const char *fname, struct utimbuf *times)
+int file_ntimes(connection_struct *conn, const char *fname, const struct timespec ts[2])
{
SMB_STRUCT_STAT sbuf;
int ret = -1;
@@ -555,14 +555,17 @@ int file_utime(connection_struct *conn, const char *fname, struct utimbuf *times
return 0;
}
- if(SMB_VFS_UTIME(conn,fname, times) == 0)
+ if(SMB_VFS_NTIMES(conn, fname, ts) == 0) {
return 0;
+ }
- if((errno != EPERM) && (errno != EACCES))
+ if((errno != EPERM) && (errno != EACCES)) {
return -1;
+ }
- if(!lp_dos_filetimes(SNUM(conn)))
+ if(!lp_dos_filetimes(SNUM(conn))) {
return -1;
+ }
/* We have permission (given by the Samba admin) to
break POSIX semantics and allow a user to change
@@ -574,7 +577,7 @@ int file_utime(connection_struct *conn, const char *fname, struct utimbuf *times
if (can_write_to_file(conn, fname, &sbuf)) {
/* We are allowed to become root and change the filetime. */
become_root();
- ret = SMB_VFS_UTIME(conn,fname, times);
+ ret = SMB_VFS_NTIMES(conn, fname, ts);
unbecome_root();
}
@@ -585,16 +588,19 @@ int file_utime(connection_struct *conn, const char *fname, struct utimbuf *times
Change a filetime - possibly allowing DOS semantics.
*******************************************************************/
-BOOL set_filetime(connection_struct *conn, const char *fname, time_t mtime)
+BOOL set_filetime(connection_struct *conn, const char *fname,
+ const struct timespec mtime)
{
- struct utimbuf times;
+ struct timespec ts[2];
- if (null_mtime(mtime))
+ if (null_timespec(mtime)) {
return(True);
+ }
- times.modtime = times.actime = mtime;
+ ts[1] = mtime; /* mtime. */
+ ts[0] = ts[1]; /* atime. */
- if (file_utime(conn, fname, &times)) {
+ if (file_ntimes(conn, fname, ts)) {
DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno)));
return False;
}
@@ -602,5 +608,5 @@ BOOL set_filetime(connection_struct *conn, const char *fname, time_t mtime)
notify_fname(conn, NOTIFY_ACTION_MODIFIED,
FILE_NOTIFY_CHANGE_LAST_WRITE, fname);
- return(True);
-}
+ return True;
+}
diff --git a/source/smbd/fileio.c b/source/smbd/fileio.c
index e0945be8893..65238c0e9ee 100644
--- a/source/smbd/fileio.c
+++ b/source/smbd/fileio.c
@@ -149,13 +149,13 @@ static ssize_t real_write_file(files_struct *fsp,const char *data, SMB_OFF_T pos
* The 99% solution will hopefully be good enough in this case. JRA.
*/
- if (fsp->pending_modtime) {
+ if (!null_timespec(fsp->pending_modtime)) {
set_filetime(fsp->conn, fsp->fsp_name, fsp->pending_modtime);
/* If we didn't get the "set modtime" call ourselves, we must
store the last write time to restore on close. JRA. */
if (!fsp->pending_modtime_owner) {
- fsp->last_write_time = time(NULL);
+ fsp->last_write_time = timespec_current();
}
}
diff --git a/source/smbd/files.c b/source/smbd/files.c
index 66ef37bb0fa..23fd47671b8 100644
--- a/source/smbd/files.c
+++ b/source/smbd/files.c
@@ -383,11 +383,11 @@ files_struct *file_find_print(void)
Record the owner of that modtime.
****************************************************************************/
-void fsp_set_pending_modtime(files_struct *tfsp, time_t pmod)
+void fsp_set_pending_modtime(files_struct *tfsp, const struct timespec mod)
{
files_struct *fsp;
- if (null_mtime(pmod)) {
+ if (null_timespec(mod)) {
return;
}
@@ -395,7 +395,7 @@ void fsp_set_pending_modtime(files_struct *tfsp, time_t pmod)
if ( fsp->fh->fd != -1 &&
fsp->dev == tfsp->dev &&
fsp->inode == tfsp->inode ) {
- fsp->pending_modtime = pmod;
+ fsp->pending_modtime = mod;
fsp->pending_modtime_owner = False;
}
}
diff --git a/source/smbd/msdfs.c b/source/smbd/msdfs.c
index 2a19d6fb418..284061331bf 100644
--- a/source/smbd/msdfs.c
+++ b/source/smbd/msdfs.c
@@ -1,8 +1,9 @@
/*
Unix SMB/Netbios implementation.
Version 3.0
- MSDfs services for Samba
+ MSDFS services for Samba
Copyright (C) Shirish Kalele 2000
+ Copyright (C) Jeremy Allison 2007
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -26,108 +27,142 @@
extern uint32 global_client_caps;
/**********************************************************************
- Parse the pathname of the form \hostname\service\reqpath
- into the dfs_path structure
- **********************************************************************/
+ Parse a DFS pathname of the form \hostname\service\reqpath
+ into the dfs_path structure.
+ If POSIX pathnames is true, the pathname may also be of the
+ form /hostname/service/reqpath.
+ We cope with either here.
+
+ Unfortunately, due to broken clients who might set the
+ SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
+ send a local path, we have to cope with that too....
-static BOOL parse_dfs_path(const char *pathname, struct dfs_path *pdp)
+ JRA.
+**********************************************************************/
+
+static NTSTATUS parse_dfs_path(const char *pathname,
+ BOOL allow_wcards,
+ struct dfs_path *pdp,
+ BOOL *ppath_contains_wcard)
{
pstring pathname_local;
- char *p, *temp;
+ char *p,*temp;
+ NTSTATUS status = NT_STATUS_OK;
+ char sepchar;
+
+ ZERO_STRUCTP(pdp);
pstrcpy(pathname_local,pathname);
p = temp = pathname_local;
- ZERO_STRUCTP(pdp);
+ pdp->posix_path = (lp_posix_pathnames() && *pathname == '/');
- trim_char(temp,'\\','\\');
- DEBUG(10,("temp in parse_dfs_path: .%s. after trimming \\'s\n",temp));
+ sepchar = pdp->posix_path ? '/' : '\\';
- /* now tokenize */
- /* parse out hostname */
- p = strchr_m(temp,'\\');
- if(p == NULL) {
- return False;
- }
- *p = '\0';
- pstrcpy(pdp->hostname,temp);
- DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
+ if (*pathname != sepchar) {
+ DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
+ pathname, sepchar ));
+ /*
+ * Possibly client sent a local path by mistake.
+ * Try and convert to a local path.
+ */
- /* parse out servicename */
- temp = p+1;
- p = strchr_m(temp,'\\');
- if(p == NULL) {
- pstrcpy(pdp->servicename,temp);
- pdp->reqpath[0] = '\0';
- return True;
+ pdp->hostname[0] = '\0';
+ pdp->servicename[0] = '\0';
+
+ /* We've got no info about separators. */
+ pdp->posix_path = lp_posix_pathnames();
+ p = temp;
+ DEBUG(10,("parse_dfs_path: trying to convert %s to a local path\n",
+ temp));
+ goto local_path;
}
- *p = '\0';
- pstrcpy(pdp->servicename,temp);
- DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
- /* rest is reqpath */
- check_path_syntax(pdp->reqpath, p+1);
+ trim_char(temp,sepchar,sepchar);
- DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
- return True;
-}
+ DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
+ temp, sepchar));
-/**********************************************************************
- Parse the pathname of the form /hostname/service/reqpath
- into the dfs_path structure
- This code is dependent on the fact that check_path_syntax() will
- convert '\\' characters to '/'.
- When POSIX pathnames have been selected this doesn't happen, so we
- must look for the unaltered separator of '\\' instead of the modified '/'.
- JRA.
- **********************************************************************/
+ /* Now tokenize. */
+ /* Parse out hostname. */
+ p = strchr_m(temp,sepchar);
+ if(p == NULL) {
+ DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
+ temp));
+ /*
+ * Possibly client sent a local path by mistake.
+ * Try and convert to a local path.
+ */
-static BOOL parse_processed_dfs_path(char* pathname, struct dfs_path *pdp, BOOL allow_wcards)
-{
- pstring pathname_local;
- char *p,*temp;
- const char sepchar = lp_posix_pathnames() ? '\\' : '/';
+ pdp->hostname[0] = '\0';
+ pdp->servicename[0] = '\0';
- pstrcpy(pathname_local,pathname);
- p = temp = pathname_local;
+ p = temp;
+ DEBUG(10,("parse_dfs_path: trying to convert %s to a local path\n",
+ temp));
+ goto local_path;
+ }
+ *p = '\0';
+ fstrcpy(pdp->hostname,temp);
+ DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
- ZERO_STRUCTP(pdp);
+ /* If we got a hostname, is it ours (or an IP address) ? */
+ if (!is_myname_or_ipaddr(pdp->hostname)) {
+ /* Repair path. */
+ *p = sepchar;
+ DEBUG(10,("parse_dfs_path: hostname %s isn't ours. Try local path from path %s\n",
+ pdp->hostname, temp));
+ /*
+ * Possibly client sent a local path by mistake.
+ * Try and convert to a local path.
+ */
- trim_char(temp,sepchar,sepchar);
- DEBUG(10,("temp in parse_processed_dfs_path: .%s. after trimming \\'s\n",temp));
+ pdp->hostname[0] = '\0';
+ pdp->servicename[0] = '\0';
- /* now tokenize */
- /* parse out hostname */
- p = strchr_m(temp,sepchar);
- if(p == NULL) {
- return False;
+ p = temp;
+ DEBUG(10,("parse_dfs_path: trying to convert %s to a local path\n",
+ temp));
+ goto local_path;
}
- *p = '\0';
- pstrcpy(pdp->hostname,temp);
- DEBUG(10,("parse_processed_dfs_path: hostname: %s\n",pdp->hostname));
- /* parse out servicename */
+ /* Parse out servicename. */
temp = p+1;
p = strchr_m(temp,sepchar);
if(p == NULL) {
- pstrcpy(pdp->servicename,temp);
+ fstrcpy(pdp->servicename,temp);
pdp->reqpath[0] = '\0';
- return True;
+ return NT_STATUS_OK;
}
*p = '\0';
- pstrcpy(pdp->servicename,temp);
- DEBUG(10,("parse_processed_dfs_path: servicename: %s\n",pdp->servicename));
+ fstrcpy(pdp->servicename,temp);
+ DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
+
+ p++;
+
+ local_path:
+
+ *ppath_contains_wcard = False;
- /* rest is reqpath */
- if (allow_wcards) {
- BOOL path_contains_wcard;
- check_path_syntax_wcard(pdp->reqpath, p+1, &path_contains_wcard);
+ /* Rest is reqpath. */
+ if (pdp->posix_path) {
+ status = check_path_syntax_posix(pdp->reqpath, p);
} else {
- check_path_syntax(pdp->reqpath, p+1);
+ if (allow_wcards) {
+ status = check_path_syntax_wcard(pdp->reqpath, p, ppath_contains_wcard);
+ } else {
+ status = check_path_syntax(pdp->reqpath, p);
+ }
}
- DEBUG(10,("parse_processed_dfs_path: rest of the path: %s\n",pdp->reqpath));
- return True;
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
+ p, nt_errstr(status) ));
+ return status;
+ }
+
+ DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
+ return NT_STATUS_OK;
}
/********************************************************
@@ -135,7 +170,7 @@ static BOOL parse_processed_dfs_path(char* pathname, struct dfs_path *pdp, BOOL
Note this CHANGES CWD !!!! JRA.
*********************************************************/
-static BOOL create_conn_struct(connection_struct *conn, int snum, char *path)
+static BOOL create_conn_struct(connection_struct *conn, int snum, const char *path)
{
pstring connpath;
@@ -145,19 +180,19 @@ static BOOL create_conn_struct(connection_struct *conn, int snum, char *path)
pstring_sub(connpath , "%S", lp_servicename(snum));
/* needed for smbd_vfs_init() */
-
- if ( (conn->mem_ctx=talloc_init("connection_struct")) == NULL ) {
- DEBUG(0,("talloc_init(connection_struct) failed!\n"));
- return False;
- }
- if (!(conn->params = TALLOC_P(conn->mem_ctx, struct share_params))) {
+ if ((conn->mem_ctx=talloc_init("connection_struct")) == NULL) {
+ DEBUG(0,("talloc_init(connection_struct) failed!\n"));
+ return False;
+ }
+
+ if (!(conn->params = TALLOC_ZERO_P(conn->mem_ctx, struct share_params))) {
DEBUG(0, ("TALLOC failed\n"));
return False;
}
-
+
conn->params->service = snum;
-
+
set_conn_connectpath(conn, connpath);
if (!smbd_vfs_init(conn)) {
@@ -184,11 +219,27 @@ static BOOL create_conn_struct(connection_struct *conn, int snum, char *path)
/**********************************************************************
Parse the contents of a symlink to verify if it is an msdfs referral
- A valid referral is of the form: msdfs:server1\share1,server2\share2
- talloc CTX can be NULL here if preflist and refcount pointers are null.
+ A valid referral is of the form:
+
+ msdfs:server1\share1,server2\share2
+ msdfs:server1\share1\pathname,server2\share2\pathname
+ msdfs:server1/share1,server2/share2
+ msdfs:server1/share1/pathname,server2/share2/pathname.
+
+ Note that the alternate paths returned here must be of the canonicalized
+ form:
+
+ \server\share or
+ \server\share\path\to\file,
+
+ even in posix path mode. This is because we have no knowledge if the
+ server we're referring to understands posix paths.
**********************************************************************/
-static BOOL parse_symlink(TALLOC_CTX *ctx, char *buf, struct referral **preflist, int *refcount)
+static BOOL parse_msdfs_symlink(TALLOC_CTX *ctx,
+ char *target,
+ struct referral **preflist,
+ int *refcount)
{
pstring temp;
char *prot;
@@ -196,45 +247,28 @@ static BOOL parse_symlink(TALLOC_CTX *ctx, char *buf, struct referral **preflist
int count = 0, i;
struct referral *reflist;
- pstrcpy(temp,buf);
-
+ pstrcpy(temp,target);
prot = strtok(temp,":");
- if (!strequal(prot, "msdfs")) {
- return False;
- }
-
- /* No referral list requested. Just yes/no. */
- if (!preflist) {
- return True;
- }
-
- if (!ctx) {
- DEBUG(0,("parse_symlink: logic error. TALLOC_CTX should not be null.\n"));
- return True;
- }
-
/* parse out the alternate paths */
while((count<MAX_REFERRAL_COUNT) &&
((alt_path[count] = strtok(NULL,",")) != NULL)) {
count++;
}
- DEBUG(10,("parse_symlink: count=%d\n", count));
+ DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
- reflist = *preflist = TALLOC_ARRAY(ctx, struct referral, count);
+ reflist = *preflist = TALLOC_ZERO_ARRAY(ctx, struct referral, count);
if(reflist == NULL) {
- DEBUG(0,("parse_symlink: talloc failed!\n"));
+ DEBUG(0,("parse_msdfs_symlink: talloc failed!\n"));
return False;
}
for(i=0;i<count;i++) {
char *p;
- /* replace all /'s in the alternate path by a \ */
- for(p = alt_path[i]; *p && ((p = strchr_m(p,'/'))!=NULL); p++) {
- *p = '\\';
- }
+ /* Canonicalize link target. Replace all /'s in the path by a \ */
+ string_replace(alt_path[i], '/', '\\');
/* Remove leading '\\'s */
p = alt_path[i];
@@ -244,35 +278,29 @@ static BOOL parse_symlink(TALLOC_CTX *ctx, char *buf, struct referral **preflist
pstrcpy(reflist[i].alternate_path, "\\");
pstrcat(reflist[i].alternate_path, p);
+
reflist[i].proximity = 0;
reflist[i].ttl = REFERRAL_TTL;
- DEBUG(10, ("parse_symlink: Created alt path: %s\n", reflist[i].alternate_path));
- }
-
- if(refcount) {
- *refcount = count;
+ DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n", reflist[i].alternate_path));
+ *refcount += 1;
}
return True;
}
/**********************************************************************
- Returns true if the unix path is a valid msdfs symlink
- talloc CTX can be NULL here if reflistp and refcnt pointers are null.
- **********************************************************************/
+ Returns true if the unix path is a valid msdfs symlink and also
+ returns the target string from inside the link.
+**********************************************************************/
-BOOL is_msdfs_link(TALLOC_CTX *ctx, connection_struct *conn, const char *path,
- struct referral **reflistp, int *refcnt,
- SMB_STRUCT_STAT *sbufp)
+BOOL is_msdfs_link(connection_struct *conn,
+ const char *path,
+ pstring link_target,
+ SMB_STRUCT_STAT *sbufp)
{
SMB_STRUCT_STAT st;
- pstring referral;
int referral_len = 0;
- if (!path || !conn) {
- return False;
- }
-
if (sbufp == NULL) {
sbufp = &st;
}
@@ -282,76 +310,59 @@ BOOL is_msdfs_link(TALLOC_CTX *ctx, connection_struct *conn, const char *path,
return False;
}
- if (S_ISLNK(sbufp->st_mode)) {
- /* open the link and read it */
- referral_len = SMB_VFS_READLINK(conn, path, referral, sizeof(pstring)-1);
- if (referral_len == -1) {
- DEBUG(0,("is_msdfs_link: Error reading msdfs link %s: %s\n", path, strerror(errno)));
- return False;
- }
+ if (!S_ISLNK(sbufp->st_mode)) {
+ DEBUG(5,("is_msdfs_link: %s is not a link.\n",path));
+ return False;
+ }
- referral[referral_len] = '\0';
- DEBUG(5,("is_msdfs_link: %s -> %s\n",path,referral));
- if (parse_symlink(ctx, referral, reflistp, refcnt)) {
- return True;
- }
+ /* open the link and read it */
+ referral_len = SMB_VFS_READLINK(conn, path, link_target, sizeof(pstring)-1);
+ if (referral_len == -1) {
+ DEBUG(0,("is_msdfs_link: Error reading msdfs link %s: %s\n",
+ path, strerror(errno)));
+ return False;
+ }
+ link_target[referral_len] = '\0';
+
+ DEBUG(5,("is_msdfs_link: %s -> %s\n",path, link_target));
+
+ if (!strnequal(link_target, "msdfs:", 6)) {
+ return False;
}
- return False;
+ return True;
}
/*****************************************************************
Used by other functions to decide if a dfs path is remote,
-and to get the list of referred locations for that remote path.
+ and to get the list of referred locations for that remote path.
-findfirst_flag: For findfirsts, dfs links themselves are not
-redirected, but paths beyond the links are. For normal smb calls,
-even dfs links need to be redirected.
+ search_flag: For findfirsts, dfs links themselves are not
+ redirected, but paths beyond the links are. For normal smb calls,
+ even dfs links need to be redirected.
-self_referralp: clients expect a dfs referral for the same share when
-they request referrals for dfs roots on a server.
+ consumedcntp: how much of the dfs path is being redirected. the client
+ should try the remaining path on the redirected server.
-consumedcntp: how much of the dfs path is being redirected. the client
-should try the remaining path on the redirected server.
-
-TALLOC_CTX can be NULL here if struct referral **reflistpp, int *refcntp
-are also NULL.
+ If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
+ link redirect are in targetpath.
*****************************************************************/
-static BOOL resolve_dfs_path(TALLOC_CTX *ctx,
- const char *dfspath,
- struct dfs_path *dp,
- connection_struct *conn,
- BOOL search_flag,
- struct referral **reflistpp,
- int *refcntp,
- BOOL *self_referralp,
- int *consumedcntp)
+static NTSTATUS dfs_path_lookup(connection_struct *conn,
+ const char *dfspath, /* Incoming complete dfs path */
+ const struct dfs_path *pdp, /* Parsed out server+share+extrapath. */
+ BOOL search_flag, /* Called from a findfirst ? */
+ int *consumedcntp,
+ pstring targetpath)
{
- pstring localpath;
- int consumed_level = 1;
- char *p;
+ char *p = NULL;
+ char *q = NULL;
SMB_STRUCT_STAT sbuf;
NTSTATUS status;
- pstring reqpath;
-
- if (!dp || !conn) {
- DEBUG(1,("resolve_dfs_path: NULL dfs_path* or NULL connection_struct*!\n"));
- return False;
- }
-
- if (!ctx && (reflistpp || refcntp)) {
- DEBUG(0,("resolve_dfs_path: logic error. TALLOC_CTX must not be NULL.\n"));
- }
-
- if (dp->reqpath[0] == '\0') {
- if (self_referralp) {
- DEBUG(6,("resolve_dfs_path: self-referral. returning False\n"));
- *self_referralp = True;
- }
- return False;
- }
+ pstring localpath;
+ pstring canon_dfspath; /* Canonicalized dfs path. (only '/' components). */
- DEBUG(10,("resolve_dfs_path: Conn path = %s req_path = %s\n", conn->connectpath, dp->reqpath));
+ DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
+ conn->connectpath, pdp->reqpath));
/*
* Note the unix path conversion here we're doing we can
@@ -365,144 +376,189 @@ static BOOL resolve_dfs_path(TALLOC_CTX *ctx,
* think this is needed. JRA.
*/
- pstrcpy(localpath, dp->reqpath);
-
- status = unix_convert(conn, localpath, False, NULL, &sbuf);
+ pstrcpy(localpath, pdp->reqpath);
+ status = unix_convert(conn, localpath, search_flag, NULL, &sbuf);
if (!NT_STATUS_IS_OK(status)) {
- return False;
+ return status;
}
- /* check if need to redirect */
- if (is_msdfs_link(ctx, conn, localpath, reflistpp, refcntp, NULL)) {
- if ( search_flag ) {
- DEBUG(6,("resolve_dfs_path (FindFirst) No redirection "
+ /* Optimization - check if we can redirect the whole path. */
+
+ if (is_msdfs_link(conn, localpath, targetpath, NULL)) {
+ if (search_flag) {
+ DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
"for dfs link %s.\n", dfspath));
- return False;
+ return NT_STATUS_OK;
}
- DEBUG(6,("resolve_dfs_path: %s resolves to a valid Dfs link.\n", dfspath));
+ DEBUG(6,("dfs_path_lookup: %s resolves to a "
+ "valid dfs link %s.\n", dfspath, targetpath));
+
if (consumedcntp) {
*consumedcntp = strlen(dfspath);
}
- return True;
+ return NT_STATUS_PATH_NOT_COVERED;
+ }
+
+ /* Prepare to test only for '/' components in the given path,
+ * so if a Windows path replace all '\\' characters with '/'.
+ * For a POSIX DFS path we know all separators are already '/'. */
+
+ pstrcpy(canon_dfspath, dfspath);
+ if (!pdp->posix_path) {
+ string_replace(canon_dfspath, '\\', '/');
+ }
+
+ /*
+ * Redirect if any component in the path is a link.
+ * We do this by walking backwards through the
+ * local path, chopping off the last component
+ * in both the local path and the canonicalized
+ * DFS path. If we hit a DFS link then we're done.
+ */
+
+ p = strrchr_m(localpath, '/');
+ if (consumedcntp) {
+ q = strrchr_m(canon_dfspath, '/');
}
- /* redirect if any component in the path is a link */
- pstrcpy(reqpath, localpath);
- p = strrchr_m(reqpath, '/');
while (p) {
*p = '\0';
- pstrcpy(localpath, reqpath);
- if (is_msdfs_link(ctx, conn, localpath, reflistpp, refcntp, NULL)) {
- DEBUG(4, ("resolve_dfs_path: Redirecting %s because parent %s is dfs link\n", dfspath, localpath));
-
- /* To find the path consumed, we truncate the original
- DFS pathname passed to use to remove the last
- component. The length of the resulting string is
- the path consumed
- */
-
+ if (q) {
+ *q = '\0';
+ }
+
+ if (is_msdfs_link(conn, localpath, targetpath, NULL)) {
+ DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
+ "parent %s is dfs link\n", dfspath, localpath));
+
if (consumedcntp) {
- char *q;
- pstring buf;
- pstrcpy(buf, dfspath);
- trim_char(buf, '\0', '\\');
- for (; consumed_level; consumed_level--) {
- q = strrchr_m(buf, '\\');
- if (q) {
- *q = 0;
- }
- }
- *consumedcntp = strlen(buf);
- DEBUG(10, ("resolve_dfs_path: Path consumed: %s (%d)\n", buf, *consumedcntp));
+ *consumedcntp = strlen(canon_dfspath);
+ DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
+ "(%d)\n", canon_dfspath, *consumedcntp));
}
-
- return True;
+
+ return NT_STATUS_PATH_NOT_COVERED;
+ }
+
+ /* Step back on the filesystem. */
+ p = strrchr_m(localpath, '/');
+
+ if (consumedcntp) {
+ /* And in the canonicalized dfs path. */
+ q = strrchr_m(canon_dfspath, '/');
}
- p = strrchr_m(reqpath, '/');
- consumed_level++;
}
- return False;
+ return NT_STATUS_OK;
}
/*****************************************************************
- Decides if a dfs pathname should be redirected or not.
- If not, the pathname is converted to a tcon-relative local unix path
-
- search_wcard_flag: this flag performs 2 functions bother related
- to searches. See resolve_dfs_path() and parse_processed_dfs_path()
- for details.
+ Decides if a dfs pathname should be redirected or not.
+ If not, the pathname is converted to a tcon-relative local unix path
+
+ search_wcard_flag: this flag performs 2 functions bother related
+ to searches. See resolve_dfs_path() and parse_dfs_path_XX()
+ for details.
+
+ This function can return NT_STATUS_OK, meaning use the returned path as-is
+ (mapped into a local path).
+ or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
+ any other NT_STATUS error which is a genuine error to be
+ returned to the client.
*****************************************************************/
-BOOL dfs_redirect( pstring pathname, connection_struct *conn, BOOL search_wcard_flag )
+static NTSTATUS dfs_redirect( connection_struct *conn,
+ pstring dfs_path,
+ BOOL search_wcard_flag,
+ BOOL *ppath_contains_wcard)
{
+ NTSTATUS status;
struct dfs_path dp;
+ pstring targetpath;
- if (!conn || !pathname) {
- return False;
+ status = parse_dfs_path(dfs_path, search_wcard_flag, &dp, ppath_contains_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (dp.reqpath[0] == '\0') {
+ pstrcpy(dfs_path, dp.reqpath);
+ DEBUG(5,("dfs_redirect: self-referral.\n"));
+ return NT_STATUS_OK;
}
- parse_processed_dfs_path(pathname, &dp, search_wcard_flag);
+ /* If dfs pathname for a non-dfs share, convert to tcon-relative
+ path and return OK */
- /* if dfs pathname for a non-dfs share, convert to tcon-relative
- path and return false */
if (!lp_msdfs_root(SNUM(conn))) {
- pstrcpy(pathname, dp.reqpath);
- return False;
+ pstrcpy(dfs_path, dp.reqpath);
+ return NT_STATUS_OK;
}
-
- if ( !( strequal(dp.servicename, lp_servicename(SNUM(conn)))
- || ( strequal(dp.servicename, HOMES_NAME)
- && strequal(lp_servicename(SNUM(conn)), get_current_username()) )) )
- {
- return False;
+
+ /* If it looked like a local path (zero hostname/servicename)
+ * just treat as a tcon-relative path. */
+
+ if (dp.hostname[0] == '\0' && dp.servicename[0] == '\0') {
+ pstrcpy(dfs_path, dp.reqpath);
+ return NT_STATUS_OK;
}
- if (resolve_dfs_path(NULL, pathname, &dp, conn, search_wcard_flag,
- NULL, NULL, NULL, NULL)) {
- DEBUG(3,("dfs_redirect: Redirecting %s\n", pathname));
- return True;
- } else {
- DEBUG(3,("dfs_redirect: Not redirecting %s.\n", pathname));
+ if (!( strequal(dp.servicename, lp_servicename(SNUM(conn)))
+ || (strequal(dp.servicename, HOMES_NAME)
+ && strequal(lp_servicename(SNUM(conn)), get_current_username()) )) ) {
- /* Form non-dfs tcon-relative path */
- pstrcpy(pathname, dp.reqpath);
+ /* The given sharename doesn't match this connection. */
- DEBUG(3,("dfs_redirect: Path converted to non-dfs path %s\n", pathname));
- return False;
+ return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+
+ status = dfs_path_lookup(conn, dfs_path, &dp,
+ search_wcard_flag, NULL, targetpath);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
+ DEBUG(3,("dfs_redirect: Redirecting %s\n", dfs_path));
+ } else {
+ DEBUG(10,("dfs_redirect: dfs_path_lookup failed for %s with %s\n",
+ dfs_path, nt_errstr(status) ));
+ }
+ return status;
}
- /* never reached */
+ DEBUG(3,("dfs_redirect: Not redirecting %s.\n", dfs_path));
+
+ /* Form non-dfs tcon-relative path */
+ pstrcpy(dfs_path, dp.reqpath);
+
+ DEBUG(3,("dfs_redirect: Path converted to non-dfs path %s\n", dfs_path));
+ return NT_STATUS_OK;
}
/**********************************************************************
Return a self referral.
**********************************************************************/
-static BOOL self_ref(TALLOC_CTX *ctx, const char *pathname, struct junction_map *jucn,
- int *consumedcntp, BOOL *self_referralp)
+static BOOL self_ref(TALLOC_CTX *ctx,
+ const char *dfs_path,
+ struct junction_map *jucn,
+ int *consumedcntp,
+ BOOL *self_referralp)
{
struct referral *ref;
- if (self_referralp != NULL) {
- *self_referralp = True;
- }
+ *self_referralp = True;
jucn->referral_count = 1;
- if((ref = TALLOC_P(ctx, struct referral)) == NULL) {
- DEBUG(0,("self_ref: malloc failed for referral\n"));
+ if((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
+ DEBUG(0,("self_ref: talloc failed for referral\n"));
return False;
}
- pstrcpy(ref->alternate_path,pathname);
+ pstrcpy(ref->alternate_path,dfs_path);
ref->proximity = 0;
ref->ttl = REFERRAL_TTL;
jucn->referral_list = ref;
- if (consumedcntp) {
- *consumedcntp = strlen(pathname);
- }
-
+ *consumedcntp = strlen(dfs_path);
return True;
}
@@ -511,40 +567,39 @@ static BOOL self_ref(TALLOC_CTX *ctx, const char *pathname, struct junction_map
junction_map structure.
**********************************************************************/
-BOOL get_referred_path(TALLOC_CTX *ctx, const char *pathname, struct junction_map *jucn,
- int *consumedcntp, BOOL *self_referralp)
+BOOL get_referred_path(TALLOC_CTX *ctx,
+ const char *dfs_path,
+ struct junction_map *jucn,
+ int *consumedcntp,
+ BOOL *self_referralp)
{
- struct dfs_path dp;
-
struct connection_struct conns;
struct connection_struct *conn = &conns;
+ struct dfs_path dp;
pstring conn_path;
+ pstring targetpath;
int snum;
+ NTSTATUS status;
BOOL ret = False;
- BOOL self_referral = False;
-
- if (!pathname || !jucn) {
- return False;
- }
+ BOOL dummy;
ZERO_STRUCT(conns);
- if (self_referralp) {
- *self_referralp = False;
- } else {
- self_referralp = &self_referral;
- }
+ *self_referralp = False;
- parse_dfs_path(pathname, &dp);
+ status = parse_dfs_path(dfs_path, False, &dp, &dummy);
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
/* Verify hostname in path */
if (!is_myname_or_ipaddr(dp.hostname)) {
DEBUG(3, ("get_referred_path: Invalid hostname %s in path %s\n",
- dp.hostname, pathname));
+ dp.hostname, dfs_path));
return False;
}
- pstrcpy(jucn->service_name, dp.servicename);
+ fstrcpy(jucn->service_name, dp.servicename);
pstrcpy(jucn->volume_name, dp.reqpath);
/* Verify the share is a dfs root */
@@ -556,8 +611,8 @@ BOOL get_referred_path(TALLOC_CTX *ctx, const char *pathname, struct junction_ma
}
if (!lp_msdfs_root(snum)) {
- DEBUG(3,("get_referred_path: .%s. in dfs path %s is not a dfs root.\n",
- dp.servicename, pathname));
+ DEBUG(3,("get_referred_path: |%s| in dfs path %s is not a dfs root.\n",
+ dp.servicename, dfs_path));
goto out;
}
@@ -569,15 +624,23 @@ BOOL get_referred_path(TALLOC_CTX *ctx, const char *pathname, struct junction_ma
*/
if (dp.reqpath[0] == '\0') {
-
- struct referral* ref;
+ struct referral *ref;
if (*lp_msdfs_proxy(snum) == '\0') {
- return self_ref(ctx, pathname, jucn, consumedcntp, self_referralp);
+ return self_ref(ctx,
+ dfs_path,
+ jucn,
+ consumedcntp,
+ self_referralp);
}
+ /*
+ * It's an msdfs proxy share. Redirect to
+ * the configured target share.
+ */
+
jucn->referral_count = 1;
- if ((ref = TALLOC_P(ctx, struct referral)) == NULL) {
+ if ((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
DEBUG(0, ("malloc failed for referral\n"));
goto out;
}
@@ -589,9 +652,7 @@ BOOL get_referred_path(TALLOC_CTX *ctx, const char *pathname, struct junction_ma
ref->proximity = 0;
ref->ttl = REFERRAL_TTL;
jucn->referral_list = ref;
- if (consumedcntp) {
- *consumedcntp = strlen(pathname);
- }
+ *consumedcntp = strlen(dfs_path);
ret = True;
goto out;
}
@@ -601,23 +662,27 @@ BOOL get_referred_path(TALLOC_CTX *ctx, const char *pathname, struct junction_ma
return False;
}
- /* If not remote & not a self referral, return False */
- if (!resolve_dfs_path(ctx, pathname, &dp, conn, False,
- &jucn->referral_list, &jucn->referral_count,
- self_referralp, consumedcntp)) {
- if (!*self_referralp) {
- DEBUG(3,("get_referred_path: No valid referrals for path %s\n", pathname));
- goto out;
- }
+ /* If this is a DFS path dfs_lookup should return
+ * NT_STATUS_PATH_NOT_COVERED. */
+
+ status = dfs_path_lookup(conn, dfs_path, &dp,
+ False, consumedcntp, targetpath);
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
+ DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
+ dfs_path));
+ goto out;
}
-
- /* if self_referral, fill up the junction map */
- if (*self_referralp) {
- if (self_ref(ctx, pathname, jucn, consumedcntp, self_referralp) == False) {
- goto out;
- }
+
+ /* We know this is a valid dfs link. Parse the targetpath. */
+ if (!parse_msdfs_symlink(ctx, targetpath,
+ &jucn->referral_list,
+ &jucn->referral_count)) {
+ DEBUG(3,("get_referred_path: failed to parse symlink "
+ "target %s\n", targetpath ));
+ goto out;
}
-
+
ret = True;
out:
@@ -626,10 +691,11 @@ out:
return ret;
}
-static int setup_ver2_dfs_referral(char *pathname, char **ppdata,
- struct junction_map *junction,
- int consumedcnt,
- BOOL self_referral)
+static int setup_ver2_dfs_referral(const char *pathname,
+ char **ppdata,
+ struct junction_map *junction,
+ int consumedcnt,
+ BOOL self_referral)
{
char* pdata = *ppdata;
@@ -641,7 +707,7 @@ static int setup_ver2_dfs_referral(char *pathname, char **ppdata,
int reply_size = 0;
int i=0;
- DEBUG(10,("setting up version2 referral\nRequested path:\n"));
+ DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
requestedpathlen = rpcstr_push(uni_requestedpath, pathname, sizeof(pstring),
STR_TERMINATE);
@@ -675,7 +741,7 @@ static int setup_ver2_dfs_referral(char *pathname, char **ppdata,
pdata = (char *)SMB_REALLOC(pdata,reply_size);
if(pdata == NULL) {
- DEBUG(0,("malloc failed for Realloc!\n"));
+ DEBUG(0,("Realloc failed!\n"));
return -1;
}
*ppdata = pdata;
@@ -726,10 +792,11 @@ static int setup_ver2_dfs_referral(char *pathname, char **ppdata,
return reply_size;
}
-static int setup_ver3_dfs_referral(char *pathname, char **ppdata,
- struct junction_map *junction,
- int consumedcnt,
- BOOL self_referral)
+static int setup_ver3_dfs_referral(const char *pathname,
+ char **ppdata,
+ struct junction_map *junction,
+ int consumedcnt,
+ BOOL self_referral)
{
char* pdata = *ppdata;
@@ -810,17 +877,23 @@ static int setup_ver3_dfs_referral(char *pathname, char **ppdata,
}
/******************************************************************
- Set up the Dfs referral for the dfs pathname
+ Set up the DFS referral for the dfs pathname. This call returns
+ the amount of the path covered by this server, and where the
+ client should be redirected to. This is the meat of the
+ TRANS2_GET_DFS_REFERRAL call.
******************************************************************/
-int setup_dfs_referral(connection_struct *orig_conn, char *pathname, int max_referral_level, char **ppdata)
+int setup_dfs_referral(connection_struct *orig_conn,
+ const char *dfs_path,
+ int max_referral_level,
+ char **ppdata)
{
struct junction_map junction;
- int consumedcnt;
+ int consumedcnt = 0;
BOOL self_referral = False;
- pstring buf;
int reply_size = 0;
- char *pathnamep = pathname;
+ char *pathnamep = NULL;
+ pstring local_dfs_path;
TALLOC_CTX *ctx;
if (!(ctx=talloc_init("setup_dfs_referral"))) {
@@ -830,21 +903,24 @@ int setup_dfs_referral(connection_struct *orig_conn, char *pathname, int max_ref
ZERO_STRUCT(junction);
/* get the junction entry */
- if (!pathnamep) {
+ if (!dfs_path) {
talloc_destroy(ctx);
return -1;
}
- /* Trim pathname sent by client so it begins with only one backslash.
- Two backslashes confuse some dfs clients
+ /*
+ * Trim pathname sent by client so it begins with only one backslash.
+ * Two backslashes confuse some dfs clients
*/
- while (pathnamep[0] == '\\' && pathnamep[1] == '\\') {
+
+ pstrcpy(local_dfs_path, dfs_path);
+ pathnamep = local_dfs_path;
+ while (IS_DIRECTORY_SEP(pathnamep[0]) && IS_DIRECTORY_SEP(pathnamep[1])) {
pathnamep++;
}
- pstrcpy(buf, pathnamep);
/* The following call can change cwd. */
- if (!get_referred_path(ctx, buf, &junction, &consumedcnt, &self_referral)) {
+ if (!get_referred_path(ctx, pathnamep, &junction, &consumedcnt, &self_referral)) {
vfs_ChDir(orig_conn,orig_conn->connectpath);
talloc_destroy(ctx);
return -1;
@@ -902,31 +978,40 @@ int setup_dfs_referral(connection_struct *orig_conn, char *pathname, int max_ref
**********************************************************************/
/*********************************************************************
- Creates a junction structure from a Dfs pathname
+ Creates a junction structure from a DFS pathname
**********************************************************************/
-BOOL create_junction(const char *pathname, struct junction_map *jucn)
+BOOL create_junction(const char *dfs_path, struct junction_map *jucn)
{
- struct dfs_path dp;
+ int snum;
+ BOOL dummy;
+ struct dfs_path dp;
- parse_dfs_path(pathname,&dp);
+ NTSTATUS status = parse_dfs_path(dfs_path, False, &dp, &dummy);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
- /* check if path is dfs : validate first token */
+ /* check if path is dfs : validate first token */
if (!is_myname_or_ipaddr(dp.hostname)) {
DEBUG(4,("create_junction: Invalid hostname %s in dfs path %s\n",
- dp.hostname, pathname));
+ dp.hostname, dfs_path));
return False;
}
/* Check for a non-DFS share */
- if(!lp_msdfs_root(lp_servicenumber(dp.servicename))) {
- DEBUG(4,("create_junction: %s is not an msdfs root.\n", dp.servicename));
+ snum = lp_servicenumber(dp.servicename);
+
+ if(snum < 0 || !lp_msdfs_root(snum)) {
+ DEBUG(4,("create_junction: %s is not an msdfs root.\n",
+ dp.servicename));
return False;
}
- pstrcpy(jucn->service_name,dp.servicename);
+ fstrcpy(jucn->service_name,dp.servicename);
pstrcpy(jucn->volume_name,dp.reqpath);
- pstrcpy(jucn->comment, lp_comment(lp_servicenumber(dp.servicename)));
+ pstrcpy(jucn->comment, lp_comment(snum));
return True;
}
@@ -934,16 +1019,14 @@ BOOL create_junction(const char *pathname, struct junction_map *jucn)
Forms a valid Unix pathname from the junction
**********************************************************************/
-static BOOL junction_to_local_path(struct junction_map *jucn, char *path,
- int max_pathlen, connection_struct *conn)
+static BOOL junction_to_local_path(struct junction_map *jucn,
+ char *path,
+ int max_pathlen,
+ connection_struct *conn_out)
{
int snum;
pstring conn_path;
- if(!path || !jucn) {
- return False;
- }
-
snum = lp_servicenumber(jucn->service_name);
if(snum < 0) {
return False;
@@ -954,7 +1037,7 @@ static BOOL junction_to_local_path(struct junction_map *jucn, char *path,
safe_strcat(path, jucn->volume_name, max_pathlen-1);
pstrcpy(conn_path, lp_pathname(snum));
- if (!create_conn_struct(conn, snum, conn_path)) {
+ if (!create_conn_struct(conn_out, snum, conn_path)) {
return False;
}
@@ -977,11 +1060,12 @@ BOOL create_msdfs_link(struct junction_map *jucn, BOOL exists)
return False;
}
- /* form the msdfs_link contents */
+ /* Form the msdfs_link contents */
pstrcpy(msdfs_link, "msdfs:");
for(i=0; i<jucn->referral_count; i++) {
char* refpath = jucn->referral_list[i].alternate_path;
+ /* Alternate paths always use Windows separators. */
trim_char(refpath, '\\', '\\');
if(*refpath == '\0') {
if (i == 0) {
@@ -999,7 +1083,8 @@ BOOL create_msdfs_link(struct junction_map *jucn, BOOL exists)
}
}
- DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n", path, msdfs_link));
+ DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
+ path, msdfs_link));
if(exists) {
if(SMB_VFS_UNLINK(conn,path)!=0) {
@@ -1015,7 +1100,7 @@ BOOL create_msdfs_link(struct junction_map *jucn, BOOL exists)
ret = True;
-
+
out:
conn_free_internal(conn);
@@ -1042,13 +1127,16 @@ BOOL remove_msdfs_link(struct junction_map *jucn)
return ret;
}
-static int form_junctions(TALLOC_CTX *ctx, int snum, struct junction_map *jucn, int jn_remain)
+static int form_junctions(TALLOC_CTX *ctx,
+ int snum,
+ struct junction_map *jucn,
+ int jn_remain)
{
int cnt = 0;
SMB_STRUCT_DIR *dirp;
- char* dname;
+ char *dname;
pstring connect_path;
- char* service_name = lp_servicename(snum);
+ char *service_name = lp_servicename(snum);
connection_struct conn;
struct referral *ref = NULL;
@@ -1076,13 +1164,13 @@ static int form_junctions(TALLOC_CTX *ctx, int snum, struct junction_map *jucn,
DO NOT REMOVE THIS: NT clients will not work with us
if this is not present
*/
- pstrcpy(jucn[cnt].service_name, service_name);
+ fstrcpy(jucn[cnt].service_name, service_name);
jucn[cnt].volume_name[0] = '\0';
jucn[cnt].referral_count = 1;
- ref = jucn[cnt].referral_list = TALLOC_P(ctx, struct referral);
+ ref = jucn[cnt].referral_list = TALLOC_ZERO_P(ctx, struct referral);
if (jucn[cnt].referral_list == NULL) {
- DEBUG(0, ("Malloc failed!\n"));
+ DEBUG(0, ("talloc failed!\n"));
goto out;
}
@@ -1093,9 +1181,10 @@ static int form_junctions(TALLOC_CTX *ctx, int snum, struct junction_map *jucn,
cnt++;
goto out;
}
-
- slprintf(ref->alternate_path, sizeof(pstring)-1,
- "\\\\%s\\%s", get_local_machine_name(), service_name);
+
+ pstr_sprintf(ref->alternate_path, "\\\\%s\\%s",
+ get_local_machine_name(),
+ service_name);
cnt++;
/* Now enumerate all dfs links */
@@ -1105,16 +1194,22 @@ static int form_junctions(TALLOC_CTX *ctx, int snum, struct junction_map *jucn,
}
while ((dname = vfs_readdirname(&conn, dirp)) != NULL) {
+ pstring link_target;
if (cnt >= jn_remain) {
SMB_VFS_CLOSEDIR(&conn,dirp);
DEBUG(2, ("ran out of MSDFS junction slots"));
goto out;
}
- if (is_msdfs_link(ctx, &conn, dname, &jucn[cnt].referral_list,
- &jucn[cnt].referral_count, NULL)) {
- pstrcpy(jucn[cnt].service_name, service_name);
- pstrcpy(jucn[cnt].volume_name, dname);
- cnt++;
+ if (is_msdfs_link(&conn, dname, link_target, NULL)) {
+ if (parse_msdfs_symlink(ctx,
+ link_target,
+ &jucn[cnt].referral_list,
+ &jucn[cnt].referral_count)) {
+
+ fstrcpy(jucn[cnt].service_name, service_name);
+ pstrcpy(jucn[cnt].volume_name, dname);
+ cnt++;
+ }
}
}
@@ -1148,3 +1243,33 @@ int enum_msdfs_links(TALLOC_CTX *ctx, struct junction_map *jucn, int jn_max)
}
return jn_count;
}
+
+/******************************************************************************
+ Core function to resolve a dfs pathname.
+******************************************************************************/
+
+NTSTATUS resolve_dfspath(connection_struct *conn, BOOL dfs_pathnames, pstring name)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ BOOL dummy;
+ if (dfs_pathnames && lp_host_msdfs() && lp_msdfs_root(SNUM(conn))) {
+ status = dfs_redirect(conn, name, False, &dummy);
+ }
+ return status;
+}
+
+/******************************************************************************
+ Core function to resolve a dfs pathname possibly containing a wildcard.
+ This function is identical to the above except for the BOOL param to
+ dfs_redirect but I need this to be separate so it's really clear when
+ we're allowing wildcards and when we're not. JRA.
+******************************************************************************/
+
+NTSTATUS resolve_dfspath_wcard(connection_struct *conn, BOOL dfs_pathnames, pstring name, BOOL *ppath_contains_wcard)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ if (dfs_pathnames && lp_host_msdfs() && lp_msdfs_root(SNUM(conn))) {
+ status = dfs_redirect(conn, name, True, ppath_contains_wcard);
+ }
+ return status;
+}
diff --git a/source/smbd/negprot.c b/source/smbd/negprot.c
index fb5610b20bb..bc7c75aab4c 100644
--- a/source/smbd/negprot.c
+++ b/source/smbd/negprot.c
@@ -259,7 +259,9 @@ static int reply_nt1(char *inbuf, char *outbuf)
if ( (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY) &&
((SVAL(inbuf, smb_flg2) & FLAGS2_UNKNOWN_BIT4) == 0) )
{
- set_remote_arch( RA_VISTA );
+ if (get_remote_arch() != RA_SAMBA) {
+ set_remote_arch( RA_VISTA );
+ }
}
/* do spnego in user level security if the client
diff --git a/source/smbd/notify_inotify.c b/source/smbd/notify_inotify.c
index 5fb414de4cc..ff17d455f39 100644
--- a/source/smbd/notify_inotify.c
+++ b/source/smbd/notify_inotify.c
@@ -26,6 +26,10 @@
#ifdef HAVE_INOTIFY
+#ifdef HAVE_ASM_TYPES_H
+#include <asm/types.h>
+#endif
+
#include <linux/inotify.h>
#include <asm/unistd.h>
diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c
index 19710d1dcdd..2a49e1f4a64 100644
--- a/source/smbd/nttrans.c
+++ b/source/smbd/nttrans.c
@@ -353,7 +353,7 @@ static int nt_open_pipe(char *fname, connection_struct *conn,
return(ERROR_DOS(ERRSRV,ERRnofids));
}
- /* TODO: Add pipe to db */
+ /* Add pipe to db */
if ( !store_pipe_opendb( p ) ) {
DEBUG(3,("nt_open_pipe: failed to store %s pipe open.\n", fname));
@@ -469,7 +469,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
SMB_OFF_T file_len = 0;
SMB_STRUCT_STAT sbuf;
int info = 0;
- files_struct *fsp=NULL;
+ files_struct *fsp = NULL;
char *p = NULL;
struct timespec c_timespec;
struct timespec a_timespec;
@@ -491,7 +491,9 @@ int reply_ntcreate_and_X(connection_struct *conn,
(unsigned int)create_options,
(unsigned int)root_dir_fid ));
- /* If it's an IPC, use the pipe handler. */
+ /*
+ * If it's an IPC, use the pipe handler.
+ */
if (IS_IPC(conn)) {
if (lp_nt_pipe_support()) {
@@ -502,7 +504,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
return(ERROR_DOS(ERRDOS,ERRnoaccess));
}
}
-
+
if (create_options & FILE_OPEN_BY_FILE_ID) {
END_PROFILE(SMBntcreateX);
return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
@@ -522,7 +524,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
if(!dir_fsp) {
END_PROFILE(SMBntcreateX);
- return(ERROR_DOS(ERRDOS,ERRbadfid));
+ return ERROR_DOS(ERRDOS,ERRbadfid);
}
if(!dir_fsp->is_directory) {
@@ -533,7 +535,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
return ERROR_NT(status);
}
- /*
+ /*
* Check to see if this is a mac fork of some kind.
*/
@@ -564,7 +566,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
* Ensure it ends in a '\'.
*/
- if(fname[dir_name_len-1] != '\\' && fname[dir_name_len-1] != '/') {
+ if((fname[dir_name_len-1] != '\\') && (fname[dir_name_len-1] != '/')) {
pstrcat(fname, "/");
dir_name_len++;
}
@@ -582,7 +584,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
return ERROR_NT(status);
}
- /*
+ /*
* Check to see if this is a mac fork of some kind.
*/
@@ -613,7 +615,14 @@ int reply_ntcreate_and_X(connection_struct *conn,
* Now contruct the smb_open_mode value from the filename,
* desired access and the share access.
*/
- RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBntcreateX);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
+ }
oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
if (oplock_request) {
@@ -664,19 +673,19 @@ int reply_ntcreate_and_X(connection_struct *conn,
}
}
- /*
+ /*
* If it's a request for a directory open, deal with it separately.
*/
if(create_options & FILE_DIRECTORY_FILE) {
- oplock_request = 0;
-
+
/* Can't open a temp directory. IFS kit test. */
if (file_attributes & FILE_ATTRIBUTE_TEMPORARY) {
END_PROFILE(SMBntcreateX);
return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
+ oplock_request = 0;
status = open_directory(conn, fname, &sbuf,
access_mask,
share_access,
@@ -695,7 +704,9 @@ int reply_ntcreate_and_X(connection_struct *conn,
END_PROFILE(SMBntcreateX);
return ERROR_NT(status);
}
+
} else {
+
/*
* Ordinary file case.
*/
@@ -721,6 +732,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
new_file_attributes,
oplock_request,
&info, &fsp);
+
if (!NT_STATUS_IS_OK(status)) {
/* We cheat here. There are two cases we
* care about. One is a directory rename,
@@ -773,7 +785,6 @@ int reply_ntcreate_and_X(connection_struct *conn,
return ERROR_NT(status);
}
} else {
-
restore_case_semantics(conn, file_attributes);
END_PROFILE(SMBntcreateX);
if (open_was_deferred(SVAL(inbuf,smb_mid))) {
@@ -786,7 +797,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
}
restore_case_semantics(conn, file_attributes);
-
+
file_len = sbuf.st_size;
fattr = dos_mode(conn,fname,&sbuf);
if(fattr == 0) {
@@ -827,11 +838,11 @@ int reply_ntcreate_and_X(connection_struct *conn,
* and we granted one (by whatever means) - set the
* correct bit for extended oplock reply.
*/
-
+
if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
extended_oplock_granted = True;
}
-
+
if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
extended_oplock_granted = True;
}
@@ -871,8 +882,8 @@ int reply_ntcreate_and_X(connection_struct *conn,
SIVAL(p,0,info);
}
p += 4;
-
- /* Create time. */
+
+ /* Create time. */
c_timespec = get_create_timespec(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
a_timespec = get_atimespec(&sbuf);
m_timespec = get_mtimespec(&sbuf);
@@ -883,7 +894,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
dos_filetime_timespec(&m_timespec);
}
- put_long_date_timespec(p, c_timespec);
+ put_long_date_timespec(p, c_timespec); /* create time. */
p += 8;
put_long_date_timespec(p, a_timespec); /* access time */
p += 8;
@@ -1252,15 +1263,27 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
}
oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
- oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
+ if (oplock_request) {
+ oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
+ }
/*
+ * Ordinary file or directory.
+ */
+
+ /*
* Check if POSIX semantics are wanted.
*/
-
+
new_file_attributes = set_posix_case_semantics(conn, file_attributes);
- RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
+ }
status = unix_convert(conn, fname, False, NULL, &sbuf);
if (!NT_STATUS_IS_OK(status)) {
@@ -1273,7 +1296,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
restore_case_semantics(conn, file_attributes);
return ERROR_NT(status);
}
-
+
/* This is the correct thing to do (check every time) but can_delete is
expensive (it may have to read the parent directory permissions). So
for now we're not doing it unless we have a strong hint the client
@@ -1317,14 +1340,13 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
- oplock_request = 0;
-
/*
* We will get a create directory here if the Win32
* app specified a security descriptor in the
* CreateDirectory() call.
*/
+ oplock_request = 0;
status = open_directory(conn, fname, &sbuf,
access_mask,
share_access,
@@ -1464,11 +1486,11 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
* and we granted one (by whatever means) - set the
* correct bit for extended oplock reply.
*/
-
+
if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
extended_oplock_granted = True;
}
-
+
if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
extended_oplock_granted = True;
}
@@ -1592,15 +1614,15 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new
return status;
}
- /* Source must already exist. */
- if (!VALID_STAT(sbuf1)) {
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
- }
status = check_name(conn, oldname);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
+ /* Source must already exist. */
+ if (!VALID_STAT(sbuf1)) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
/* Ensure attributes match. */
fattr = dos_mode(conn,oldname,&sbuf1);
if ((fattr & ~attrs) & (aHIDDEN | aSYSTEM)) {
@@ -1612,16 +1634,16 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new
return status;
}
- /* Disallow if newname already exists. */
- if (VALID_STAT(sbuf2)) {
- return NT_STATUS_OBJECT_NAME_COLLISION;
- }
-
status = check_name(conn, newname);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
+ /* Disallow if newname already exists. */
+ if (VALID_STAT(sbuf2)) {
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
/* No links from a directory. */
if (S_ISDIR(sbuf1.st_mode)) {
return NT_STATUS_FILE_IS_A_DIRECTORY;
@@ -1675,7 +1697,7 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new
close_file(fsp1,NORMAL_CLOSE);
/* Ensure the modtime is set correctly on the destination file. */
- fsp_set_pending_modtime(fsp2, sbuf1.st_mtime);
+ fsp_set_pending_modtime(fsp2, get_mtimespec(&sbuf1));
status = close_file(fsp2,NORMAL_CLOSE);
@@ -1708,15 +1730,15 @@ int reply_ntrename(connection_struct *conn,
pstring newname;
char *p;
NTSTATUS status;
- BOOL path1_contains_wcard = False;
- BOOL path2_contains_wcard = False;
+ BOOL src_has_wcard = False;
+ BOOL dest_has_wcard = False;
uint32 attrs = SVAL(inbuf,smb_vwv0);
uint16 rename_type = SVAL(inbuf,smb_vwv1);
START_PROFILE(SMBntrename);
p = smb_buf(inbuf) + 1;
- p += srvstr_get_path_wcard(inbuf, oldname, p, sizeof(oldname), 0, STR_TERMINATE, &status, &path1_contains_wcard);
+ p += srvstr_get_path_wcard(inbuf, oldname, p, sizeof(oldname), 0, STR_TERMINATE, &status, &src_has_wcard);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBntrename);
return ERROR_NT(status);
@@ -1734,23 +1756,38 @@ int reply_ntrename(connection_struct *conn,
}
p++;
- p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &path2_contains_wcard);
+ p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &dest_has_wcard);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBntrename);
return ERROR_NT(status);
}
- RESOLVE_DFSPATH(oldname, conn, inbuf, outbuf);
- RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
-
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, oldname);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBntrename);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
+ }
+
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBntrename);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
+ }
+
DEBUG(3,("reply_ntrename : %s -> %s\n",oldname,newname));
switch(rename_type) {
case RENAME_FLAG_RENAME:
- status = rename_internals(conn, oldname, newname, attrs, False, path1_contains_wcard);
+ status = rename_internals(conn, oldname, newname, attrs, False, src_has_wcard, dest_has_wcard);
break;
case RENAME_FLAG_HARD_LINK:
- if (path1_contains_wcard || path2_contains_wcard) {
+ if (src_has_wcard || dest_has_wcard) {
/* No wildcards. */
status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
} else {
@@ -1758,7 +1795,7 @@ int reply_ntrename(connection_struct *conn,
}
break;
case RENAME_FLAG_COPY:
- if (path1_contains_wcard || path2_contains_wcard) {
+ if (src_has_wcard || dest_has_wcard) {
/* No wildcards. */
status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
} else {
@@ -1899,7 +1936,7 @@ static int call_nt_transact_rename(connection_struct *conn, char *inbuf, char *o
pstring new_name;
files_struct *fsp = NULL;
BOOL replace_if_exists = False;
- BOOL path_contains_wcard = False;
+ BOOL dest_has_wcard = False;
NTSTATUS status;
if(parameter_count < 5) {
@@ -1909,13 +1946,14 @@ static int call_nt_transact_rename(connection_struct *conn, char *inbuf, char *o
fsp = file_fsp(params, 0);
replace_if_exists = (SVAL(params,2) & RENAME_REPLACE_IF_EXISTS) ? True : False;
CHECK_FSP(fsp, conn);
- srvstr_get_path_wcard(inbuf, new_name, params+4, sizeof(new_name), parameter_count - 4, STR_TERMINATE, &status, &path_contains_wcard);
+ srvstr_get_path_wcard(inbuf, new_name, params+4, sizeof(new_name), parameter_count - 4,
+ STR_TERMINATE, &status, &dest_has_wcard);
if (!NT_STATUS_IS_OK(status)) {
return ERROR_NT(status);
}
status = rename_internals(conn, fsp->fsp_name,
- new_name, 0, replace_if_exists, path_contains_wcard);
+ new_name, 0, replace_if_exists, False, dest_has_wcard);
if (!NT_STATUS_IS_OK(status)) {
if (open_was_deferred(SVAL(inbuf,smb_mid))) {
diff --git a/source/smbd/open.c b/source/smbd/open.c
index 13ec9f952fe..c7a7086894e 100644
--- a/source/smbd/open.c
+++ b/source/smbd/open.c
@@ -1903,7 +1903,6 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
uint32 file_attributes,
SMB_STRUCT_STAT *psbuf)
{
- int ret= -1;
mode_t mode;
char *parent_dir;
const char *dirname;
@@ -1931,7 +1930,7 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
mode = unix_mode(conn, aDIR, name, parent_dir);
}
- if ((ret=SMB_VFS_MKDIR(conn, name, mode)) != 0) {
+ if (SMB_VFS_MKDIR(conn, name, mode) != 0) {
return map_nt_error_from_unix(errno);
}
diff --git a/source/smbd/pipes.c b/source/smbd/pipes.c
index 52660da2ffe..58756a0b5a6 100644
--- a/source/smbd/pipes.c
+++ b/source/smbd/pipes.c
@@ -300,7 +300,5 @@ int reply_pipe_close(connection_struct *conn, char *inbuf,char *outbuf)
return ERROR_DOS(ERRDOS,ERRbadfid);
}
- /* TODO: REMOVE PIPE FROM DB */
-
return(outsize);
}
diff --git a/source/smbd/process.c b/source/smbd/process.c
index 14941e64990..836801ba82c 100644
--- a/source/smbd/process.c
+++ b/source/smbd/process.c
@@ -1148,6 +1148,7 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
unsigned smb_off2 = SVAL(inbuf,smb_vwv1);
char *inbuf2, *outbuf2;
int outsize2;
+ int new_size;
char inbuf_saved[smb_wct];
char outbuf_saved[smb_wct];
int outsize = smb_len(outbuf) + 4;
@@ -1198,6 +1199,20 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
/* create the in buffer */
SCVAL(inbuf2,smb_com,smb_com2);
+ /* work out the new size for the in buffer. */
+ new_size = size - (inbuf2 - inbuf);
+ if (new_size < 0) {
+ DEBUG(0,("chain_reply: chain packet size incorrect (orig size = %d, "
+ "offset = %d)\n",
+ size,
+ (inbuf2 - inbuf) ));
+ exit_server_cleanly("Bad chained packet");
+ return(-1);
+ }
+
+ /* And set it in the header. */
+ smb_setlen(inbuf2, new_size);
+
/* create the out buffer */
construct_reply_common(inbuf2, outbuf2);
@@ -1205,7 +1220,7 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
show_msg(inbuf2);
/* process the request */
- outsize2 = switch_message(smb_com2,inbuf2,outbuf2,size-chain_size,
+ outsize2 = switch_message(smb_com2,inbuf2,outbuf2,new_size,
bufsize-chain_size);
/* copy the new reply and request headers over the old ones, but
@@ -1219,8 +1234,10 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
{
int ofs = smb_wct - PTR_DIFF(outbuf2,orig_outbuf);
- if (ofs < 0) ofs = 0;
- memmove(outbuf2+ofs,outbuf_saved+ofs,smb_wct-ofs);
+ if (ofs < 0) {
+ ofs = 0;
+ }
+ memmove(outbuf2+ofs,outbuf_saved+ofs,smb_wct-ofs);
}
return outsize2;
diff --git a/source/smbd/reply.c b/source/smbd/reply.c
index c48bebb0c6c..14b16e1ae23 100644
--- a/source/smbd/reply.c
+++ b/source/smbd/reply.c
@@ -44,9 +44,12 @@ extern BOOL global_encrypted_passwords_negotiated;
set.
****************************************************************************/
+/* Custom version for processing POSIX paths. */
+#define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
+
NTSTATUS check_path_syntax_internal(pstring destname,
const pstring srcname,
- BOOL windows_path,
+ BOOL posix_path,
BOOL *p_last_component_contains_wcard)
{
char *d = destname;
@@ -57,12 +60,12 @@ NTSTATUS check_path_syntax_internal(pstring destname,
*p_last_component_contains_wcard = False;
while (*s) {
- if (IS_DIRECTORY_SEP(*s)) {
+ if (IS_PATH_SEP(*s,posix_path)) {
/*
* Safe to assume is not the second part of a mb char as this is handled below.
*/
/* Eat multiple '/' or '\\' */
- while (IS_DIRECTORY_SEP(*s)) {
+ while (IS_PATH_SEP(*s,posix_path)) {
s++;
}
if ((d != destname) && (*s != '\0')) {
@@ -77,7 +80,7 @@ NTSTATUS check_path_syntax_internal(pstring destname,
}
if (start_of_name_component) {
- if ((s[0] == '.') && (s[1] == '.') && (IS_DIRECTORY_SEP(s[2]) || s[2] == '\0')) {
+ if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
/* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
/*
@@ -107,8 +110,8 @@ NTSTATUS check_path_syntax_internal(pstring destname,
/* We're still at the start of a name component, just the previous one. */
continue;
- } else if ((s[0] == '.') && ((s[1] == '\0') || IS_DIRECTORY_SEP(s[1]))) {
- if (!windows_path) {
+ } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
+ if (posix_path) {
/* Eat the '.' */
s++;
continue;
@@ -118,7 +121,7 @@ NTSTATUS check_path_syntax_internal(pstring destname,
}
if (!(*s & 0x80)) {
- if (windows_path) {
+ if (!posix_path) {
if (*s <= 0x1f) {
return NT_STATUS_OBJECT_NAME_INVALID;
}
@@ -176,7 +179,7 @@ NTSTATUS check_path_syntax_internal(pstring destname,
NTSTATUS check_path_syntax(pstring destname, const pstring srcname)
{
BOOL ignore;
- return check_path_syntax_internal(destname, srcname, True, &ignore);
+ return check_path_syntax_internal(destname, srcname, False, &ignore);
}
/****************************************************************************
@@ -187,7 +190,7 @@ NTSTATUS check_path_syntax(pstring destname, const pstring srcname)
NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL *p_contains_wcard)
{
- return check_path_syntax_internal(destname, srcname, True, p_contains_wcard);
+ return check_path_syntax_internal(destname, srcname, False, p_contains_wcard);
}
/****************************************************************************
@@ -196,10 +199,10 @@ NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL *
set (a safe assumption).
****************************************************************************/
-static NTSTATUS check_path_syntax_posix(pstring destname, const pstring srcname)
+NTSTATUS check_path_syntax_posix(pstring destname, const pstring srcname)
{
BOOL ignore;
- return check_path_syntax_internal(destname, srcname, False, &ignore);
+ return check_path_syntax_internal(destname, srcname, True, &ignore);
}
/****************************************************************************
@@ -224,6 +227,16 @@ size_t srvstr_get_path_wcard(char *inbuf, char *dest, const char *src, size_t de
*contains_wcard = False;
+ if (SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) {
+ /*
+ * For a DFS path the function parse_dfs_path()
+ * will do the path processing, just make a copy.
+ */
+ pstrcpy(dest, tmppath);
+ *err = NT_STATUS_OK;
+ return ret;
+ }
+
if (lp_posix_pathnames()) {
*err = check_path_syntax_posix(dest, tmppath);
} else {
@@ -251,6 +264,17 @@ size_t srvstr_get_path(char *inbuf, char *dest, const char *src, size_t dest_len
} else {
ret = srvstr_pull( inbuf, tmppath_ptr, src, dest_len, src_len, flags);
}
+
+ if (SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) {
+ /*
+ * For a DFS path the function parse_dfs_path()
+ * will do the path processing, just make a copy.
+ */
+ pstrcpy(dest, tmppath);
+ *err = NT_STATUS_OK;
+ return ret;
+ }
+
if (lp_posix_pathnames()) {
*err = check_path_syntax_posix(dest, tmppath);
} else {
@@ -631,7 +655,14 @@ int reply_checkpath(connection_struct *conn, char *inbuf,char *outbuf, int dum_s
return ERROR_NT(status);
}
- RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ END_PROFILE(SMBcheckpath);
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ goto path_err;
+ }
DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(inbuf,smb_vwv0)));
@@ -710,7 +741,14 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
return ERROR_NT(status);
}
- RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBgetatr);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
+ }
/* dos smetimes asks for a stat of "" - it returns a "hidden directory"
under WfWg - weird! */
@@ -789,7 +827,14 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
return ERROR_NT(status);
}
- RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBsetatr);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
+ }
status = unix_convert(conn, fname, False, NULL, &sbuf);
if (!NT_STATUS_IS_OK(status)) {
@@ -797,6 +842,12 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
return ERROR_NT(status);
}
+ status = check_name(conn, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBsetatr);
+ return ERROR_NT(status);
+ }
+
if (fname[0] == '.' && fname[1] == '\0') {
/*
* Not sure here is the right place to catch this
@@ -806,12 +857,6 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
return ERROR_NT(NT_STATUS_ACCESS_DENIED);
}
- status = check_name(conn, fname);
- if (!NT_STATUS_IS_OK(status)) {
- END_PROFILE(SMBsetatr);
- return ERROR_NT(status);
- }
-
mode = SVAL(inbuf,smb_vwv0);
mtime = srv_make_unix_date3(inbuf+smb_vwv1);
@@ -827,7 +872,7 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
}
}
- if (!set_filetime(conn,fname,mtime)) {
+ if (!set_filetime(conn,fname,convert_time_t_to_timespec(mtime))) {
END_PROFILE(SMBsetatr);
return UNIXERROR(ERRDOS, ERRnoaccess);
}
@@ -944,7 +989,14 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
return ERROR_NT(nt_status);
}
- RESOLVE_DFSPATH_WCARD(path, conn, inbuf, outbuf);
+ nt_status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, path, &mask_contains_wcard);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ END_PROFILE(SMBsearch);
+ if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(nt_status);
+ }
p++;
status_len = SVAL(p, 0);
@@ -954,16 +1006,13 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
if (status_len == 0) {
SMB_STRUCT_STAT sbuf;
- pstring dir2;
pstrcpy(directory,path);
- pstrcpy(dir2,path);
nt_status = unix_convert(conn, directory, True, NULL, &sbuf);
if (!NT_STATUS_IS_OK(nt_status)) {
END_PROFILE(SMBsearch);
return ERROR_NT(nt_status);
}
- unix_format(dir2);
nt_status = check_name(conn, directory);
if (!NT_STATUS_IS_OK(nt_status)) {
@@ -971,23 +1020,16 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
return ERROR_NT(nt_status);
}
- p = strrchr_m(dir2,'/');
- if (p == NULL) {
- pstrcpy(mask,dir2);
- *dir2 = 0;
- } else {
- *p = 0;
- pstrcpy(mask,p+1);
- }
-
p = strrchr_m(directory,'/');
if (!p) {
- *directory = 0;
+ pstrcpy(mask,directory);
+ pstrcpy(directory,".");
} else {
*p = 0;
+ pstrcpy(mask,p+1);
}
- if (strlen(directory) == 0) {
+ if (*directory == '\0') {
pstrcpy(directory,".");
}
memset((char *)status,'\0',21);
@@ -1007,6 +1049,11 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
}
string_set(&conn->dirpath,dptr_path(dptr_num));
pstrcpy(mask, dptr_wcard(dptr_num));
+ /*
+ * For a 'continue' search we have no string. So
+ * check from the initial saved string.
+ */
+ mask_contains_wcard = ms_has_wild(mask);
}
p = smb_buf(outbuf) + 3;
@@ -1202,7 +1249,14 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
return ERROR_NT(status);
}
- RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBopen);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
+ }
status = unix_convert(conn, fname, False, NULL, &sbuf);
if (!NT_STATUS_IS_OK(status)) {
@@ -1210,6 +1264,12 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
return ERROR_NT(status);
}
+ status = check_name(conn, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBopen);
+ return ERROR_NT(status);
+ }
+
if (!map_open_params_to_ntcreate(fname, deny_mode, OPENX_FILE_EXISTS_OPEN,
&access_mask, &share_mode, &create_disposition, &create_options)) {
END_PROFILE(SMBopen);
@@ -1320,7 +1380,14 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
return ERROR_NT(status);
}
- RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBopenX);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
+ }
status = unix_convert(conn, fname, False, NULL, &sbuf);
if (!NT_STATUS_IS_OK(status)) {
@@ -1328,6 +1395,12 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
return ERROR_NT(status);
}
+ status = check_name(conn, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBopenX);
+ return ERROR_NT(status);
+ }
+
if (!map_open_params_to_ntcreate(fname, deny_mode, smb_ofun,
&access_mask,
&share_mode,
@@ -1470,7 +1543,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
int com;
int outsize = 0;
uint32 fattr = SVAL(inbuf,smb_vwv0);
- struct utimbuf times;
+ struct timespec ts[2];
files_struct *fsp;
int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
SMB_STRUCT_STAT sbuf;
@@ -1484,7 +1557,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
com = SVAL(inbuf,smb_com);
- times.modtime = srv_make_unix_date3(inbuf + smb_vwv1);
+ ts[1] = convert_time_t_to_timespec(srv_make_unix_date3(inbuf + smb_vwv1)); /* mtime. */
srvstr_get_path(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), 0, STR_TERMINATE, &status);
if (!NT_STATUS_IS_OK(status)) {
@@ -1492,7 +1565,14 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
return ERROR_NT(status);
}
- RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBcreate);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
+ }
status = unix_convert(conn, fname, False, NULL, &sbuf);
if (!NT_STATUS_IS_OK(status)) {
@@ -1500,6 +1580,12 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
return ERROR_NT(status);
}
+ status = check_name(conn, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBcreate);
+ return ERROR_NT(status);
+ }
+
if (fattr & aVOLID) {
DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
}
@@ -1531,8 +1617,8 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
return ERROR_NT(status);
}
- times.actime = sbuf.st_atime;
- file_utime(conn, fname, &times);
+ ts[0] = get_atimespec(&sbuf); /* atime. */
+ file_ntimes(conn, fname, ts);
outsize = set_message(outbuf,1,0,True);
SSVAL(outbuf,smb_vwv0,fsp->fnum);
@@ -1582,13 +1668,26 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
pstrcat(fname,"TMXXXXXX");
}
- RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBctemp);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
+ }
status = unix_convert(conn, fname, False, NULL, &sbuf);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBctemp);
return ERROR_NT(status);
}
+
+ status = check_name(conn, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBctemp);
+ return ERROR_NT(status);
+ }
tmpfd = smb_mkstemp(fname);
if (tmpfd == -1) {
@@ -1858,6 +1957,12 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype,
if (dirtype == 0) {
dirtype = FILE_ATTRIBUTE_NORMAL;
}
+
+ status = check_name(conn, directory);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
status = can_delete(conn,directory,dirtype,can_defer);
if (!NT_STATUS_IS_OK(status)) {
return status;
@@ -1920,6 +2025,13 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype,
}
slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
+
+ status = check_name(conn, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ CloseDir(dir_hnd);
+ return status;
+ }
+
status = can_delete(conn, fname, dirtype, can_defer);
if (!NT_STATUS_IS_OK(status)) {
continue;
@@ -1966,8 +2078,15 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
END_PROFILE(SMBunlink);
return ERROR_NT(status);
}
-
- RESOLVE_DFSPATH_WCARD(name, conn, inbuf, outbuf);
+
+ status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name, &path_contains_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBunlink);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
+ }
DEBUG(3,("reply_unlink : %s\n",name));
@@ -3109,7 +3228,6 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
{
NTSTATUS status = NT_STATUS_OK;
int outsize = 0;
- time_t mtime;
files_struct *fsp = NULL;
START_PROFILE(SMBclose);
@@ -3151,8 +3269,8 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
* Take care of any time sent in the close.
*/
- mtime = srv_make_unix_date3(inbuf+smb_vwv1);
- fsp_set_pending_modtime(fsp, mtime);
+ fsp_set_pending_modtime(fsp,
+ convert_time_t_to_timespec(srv_make_unix_date3(inbuf+smb_vwv1)));
/*
* close_file() returns the unix errno if an error
@@ -3185,7 +3303,7 @@ int reply_writeclose(connection_struct *conn,
NTSTATUS close_status = NT_STATUS_OK;
SMB_OFF_T startpos;
char *data;
- time_t mtime;
+ struct timespec mtime;
files_struct *fsp = file_fsp(inbuf,smb_vwv0);
START_PROFILE(SMBwriteclose);
@@ -3196,7 +3314,7 @@ int reply_writeclose(connection_struct *conn,
numtowrite = SVAL(inbuf,smb_vwv1);
startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
- mtime = srv_make_unix_date3(inbuf+smb_vwv4);
+ mtime = convert_time_t_to_timespec(srv_make_unix_date3(inbuf+smb_vwv4));
data = smb_buf(inbuf) + 1;
if (numtowrite && is_locked(fsp,(uint32)SVAL(inbuf,smb_pid),(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
@@ -3206,7 +3324,7 @@ int reply_writeclose(connection_struct *conn,
nwritten = write_file(fsp,data,startpos,numtowrite);
- set_filetime(conn, fsp->fsp_name,mtime);
+ set_filetime(conn, fsp->fsp_name, mtime);
/*
* More insanity. W2K only closes the file if writelen > 0.
@@ -3598,7 +3716,14 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
return ERROR_NT(status);
}
- RESOLVE_DFSPATH(directory, conn, inbuf, outbuf);
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, directory);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBmkdir);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
+ }
status = unix_convert(conn, directory, False, NULL, &sbuf);
if (!NT_STATUS_IS_OK(status)) {
@@ -3606,6 +3731,12 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
return ERROR_NT(status);
}
+ status = check_name(conn, directory);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBmkdir);
+ return ERROR_NT(status);
+ }
+
status = create_directory(conn, directory);
DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
@@ -3810,7 +3941,14 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
return ERROR_NT(status);
}
- RESOLVE_DFSPATH(directory, conn, inbuf, outbuf)
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, directory);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBrmdir);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
+ }
status = unix_convert(conn, directory, False, NULL, &sbuf);
if (!NT_STATUS_IS_OK(status)) {
@@ -3854,7 +3992,6 @@ static BOOL resolve_wildcards(const char *name1, char *name2)
char *p,*p2, *pname1, *pname2;
int available_space, actual_space;
-
pname1 = strrchr_m(name1,'/');
pname2 = strrchr_m(name2,'/');
@@ -4008,6 +4145,11 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, pstrin
return status;
}
+ status = check_name(conn, newname);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
/* Ensure newname contains a '/' */
if(strrchr_m(newname,'/') == 0) {
pstring tmpstr;
@@ -4152,9 +4294,13 @@ static void notify_rename(connection_struct *conn, BOOL is_dir,
code.
****************************************************************************/
-NTSTATUS rename_internals(connection_struct *conn, pstring name,
- pstring newname, uint32 attrs,
- BOOL replace_if_exists, BOOL has_wild)
+NTSTATUS rename_internals(connection_struct *conn,
+ pstring name,
+ pstring newname,
+ uint32 attrs,
+ BOOL replace_if_exists,
+ BOOL src_has_wild,
+ BOOL dest_has_wild)
{
pstring directory;
pstring mask;
@@ -4165,20 +4311,22 @@ NTSTATUS rename_internals(connection_struct *conn, pstring name,
NTSTATUS status = NT_STATUS_OK;
SMB_STRUCT_STAT sbuf1, sbuf2;
struct share_mode_lock *lck = NULL;
+ struct smb_Dir *dir_hnd = NULL;
+ const char *dname;
+ long offset = 0;
+ pstring destname;
*directory = *mask = 0;
ZERO_STRUCT(sbuf1);
ZERO_STRUCT(sbuf2);
- status = unix_convert(conn, name, has_wild, last_component_src,
- &sbuf1);
+ status = unix_convert(conn, name, src_has_wild, last_component_src, &sbuf1);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- status = unix_convert(conn, newname, True, last_component_dest,
- &sbuf2);
+ status = unix_convert(conn, newname, dest_has_wild, last_component_dest, &sbuf2);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@@ -4212,10 +4360,11 @@ NTSTATUS rename_internals(connection_struct *conn, pstring name,
* Tine Smukavec <valentin.smukavec@hermes.si>.
*/
- if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params))
+ if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) {
mangle_check_cache( mask, sizeof(pstring)-1, conn->params );
+ }
- if (!has_wild) {
+ if (!src_has_wild) {
/*
* No wildcards - just process the one file.
*/
@@ -4242,6 +4391,21 @@ NTSTATUS rename_internals(connection_struct *conn, pstring name,
conn->short_case_preserve, directory,
newname, last_component_dest, is_short_name));
+ /* Ensure the source name is valid for us to access. */
+ status = check_name(conn, directory);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* The dest name still may have wildcards. */
+ if (dest_has_wild) {
+ if (!resolve_wildcards(directory,newname)) {
+ DEBUG(6, ("rename_internals: resolve_wildcards %s %s failed\n",
+ directory,newname));
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
/*
* Check for special case with case preserving and not
* case sensitive, if directory and newname are identical,
@@ -4276,8 +4440,12 @@ NTSTATUS rename_internals(connection_struct *conn, pstring name,
}
}
- resolve_wildcards(directory,newname);
-
+ /* Ensure the dest name is valid for us to access. */
+ status = check_name(conn, newname);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
/*
* The source object must exist.
*/
@@ -4369,136 +4537,130 @@ NTSTATUS rename_internals(connection_struct *conn, pstring name,
nt_errstr(status), directory,newname));
return status;
- } else {
- /*
- * Wildcards - process each file that matches.
- */
- struct smb_Dir *dir_hnd = NULL;
- const char *dname;
- long offset = 0;
- pstring destname;
-
- if (strequal(mask,"????????.???"))
- pstrcpy(mask,"*");
+ }
+
+ /*
+ * Wildcards - process each file that matches.
+ */
+ if (strequal(mask,"????????.???")) {
+ pstrcpy(mask,"*");
+ }
- status = check_name(conn, directory);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
+ status = check_name(conn, directory);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
- dir_hnd = OpenDir(conn, directory, mask, attrs);
- if (dir_hnd == NULL) {
- return map_nt_error_from_unix(errno);
- }
+ dir_hnd = OpenDir(conn, directory, mask, attrs);
+ if (dir_hnd == NULL) {
+ return map_nt_error_from_unix(errno);
+ }
- status = NT_STATUS_NO_SUCH_FILE;
- /*
- * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
- * - gentest fix. JRA
- */
+ status = NT_STATUS_NO_SUCH_FILE;
+ /*
+ * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ * - gentest fix. JRA
+ */
- while ((dname = ReadDirName(dir_hnd, &offset))) {
- pstring fname;
- BOOL sysdir_entry = False;
+ while ((dname = ReadDirName(dir_hnd, &offset))) {
+ pstring fname;
+ BOOL sysdir_entry = False;
- pstrcpy(fname,dname);
+ pstrcpy(fname,dname);
- /* Quick check for "." and ".." */
- if (fname[0] == '.') {
- if (!fname[1]
- || (fname[1] == '.' && !fname[2])) {
- if (attrs & aDIR) {
- sysdir_entry = True;
- } else {
- continue;
- }
+ /* Quick check for "." and ".." */
+ if (fname[0] == '.') {
+ if (!fname[1] || (fname[1] == '.' && !fname[2])) {
+ if (attrs & aDIR) {
+ sysdir_entry = True;
+ } else {
+ continue;
}
}
+ }
- if (!is_visible_file(conn, directory, dname, &sbuf1,
- False)) {
- continue;
- }
+ if (!is_visible_file(conn, directory, dname, &sbuf1, False)) {
+ continue;
+ }
- if(!mask_match(fname, mask, conn->case_sensitive)) {
- continue;
- }
+ if(!mask_match(fname, mask, conn->case_sensitive)) {
+ continue;
+ }
- if (sysdir_entry) {
- status = NT_STATUS_OBJECT_NAME_INVALID;
- break;
- }
+ if (sysdir_entry) {
+ status = NT_STATUS_OBJECT_NAME_INVALID;
+ break;
+ }
- status = NT_STATUS_ACCESS_DENIED;
- slprintf(fname, sizeof(fname)-1, "%s/%s", directory,
- dname);
- if (!vfs_object_exist(conn, fname, &sbuf1)) {
- status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
- DEBUG(6, ("rename %s failed. Error %s\n",
- fname, nt_errstr(status)));
- continue;
- }
- status = can_rename(conn,fname,attrs,&sbuf1);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(6, ("rename %s refused\n", fname));
- continue;
- }
- pstrcpy(destname,newname);
+ status = NT_STATUS_ACCESS_DENIED;
+ slprintf(fname, sizeof(fname)-1, "%s/%s", directory, dname);
+
+ /* Ensure the source name is valid for us to access. */
+ status = check_name(conn, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (!vfs_object_exist(conn, fname, &sbuf1)) {
+ status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ DEBUG(6, ("rename %s failed. Error %s\n",
+ fname, nt_errstr(status)));
+ continue;
+ }
+ status = can_rename(conn,fname,attrs,&sbuf1);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(6, ("rename %s refused\n", fname));
+ continue;
+ }
+ pstrcpy(destname,newname);
- if (!resolve_wildcards(fname,destname)) {
- DEBUG(6, ("resolve_wildcards %s %s failed\n",
- fname, destname));
- continue;
- }
+ if (!resolve_wildcards(fname,destname)) {
+ DEBUG(6, ("resolve_wildcards %s %s failed\n",
+ fname, destname));
+ continue;
+ }
- if (strcsequal(fname,destname)) {
- rename_open_files(conn, NULL, sbuf1.st_dev,
- sbuf1.st_ino, newname);
- DEBUG(3,("rename_internals: identical names "
- "in wildcard rename %s - success\n",
- fname));
- count++;
- status = NT_STATUS_OK;
- continue;
- }
+ /* Ensure the dest name is valid for us to access. */
+ status = check_name(conn, destname);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
- if (!replace_if_exists
- && vfs_file_exist(conn,destname, NULL)) {
- DEBUG(6,("file_exist %s\n", destname));
- status = NT_STATUS_OBJECT_NAME_COLLISION;
- continue;
- }
+ if (strcsequal(fname,destname)) {
+ rename_open_files(conn, NULL, sbuf1.st_dev,
+ sbuf1.st_ino, newname);
+ DEBUG(3,("rename_internals: identical names "
+ "in wildcard rename %s - success\n",
+ fname));
+ count++;
+ status = NT_STATUS_OK;
+ continue;
+ }
+
+ if (!replace_if_exists && vfs_file_exist(conn,destname, NULL)) {
+ DEBUG(6,("file_exist %s\n", destname));
+ status = NT_STATUS_OBJECT_NAME_COLLISION;
+ continue;
+ }
- if (rename_path_prefix_equal(fname, destname)) {
- return NT_STATUS_SHARING_VIOLATION;
- }
+ if (rename_path_prefix_equal(fname, destname)) {
+ return NT_STATUS_SHARING_VIOLATION;
+ }
- lck = get_share_mode_lock(NULL, sbuf1.st_dev,
- sbuf1.st_ino, NULL, NULL);
+ lck = get_share_mode_lock(NULL, sbuf1.st_dev,
+ sbuf1.st_ino, NULL, NULL);
- if (!SMB_VFS_RENAME(conn,fname,destname)) {
- rename_open_files(conn, lck, sbuf1.st_dev,
- sbuf1.st_ino, newname);
- count++;
- status = NT_STATUS_OK;
- }
- TALLOC_FREE(lck);
- DEBUG(3,("rename_internals: doing rename on %s -> "
- "%s\n",fname,destname));
+ if (!SMB_VFS_RENAME(conn,fname,destname)) {
+ rename_open_files(conn, lck, sbuf1.st_dev,
+ sbuf1.st_ino, newname);
+ count++;
+ status = NT_STATUS_OK;
}
- CloseDir(dir_hnd);
+ TALLOC_FREE(lck);
+ DEBUG(3,("rename_internals: doing rename on %s -> "
+ "%s\n",fname,destname));
}
-
-#if 0
- /* Don't think needed any more - JRA. */
- if (!NT_STATUS_EQUAL(error,NT_STATUS_NO_SUCH_FILE)) {
- if (!rcdest && bad_path_dest) {
- if (ms_has_wild(last_component_dest))
- return NT_STATUS_OBJECT_NAME_INVALID;
- return NT_STATUS_OBJECT_PATH_NOT_FOUND;
- }
- }
-#endif
+ CloseDir(dir_hnd);
if (count == 0 && NT_STATUS_IS_OK(status)) {
status = map_nt_error_from_unix(errno);
@@ -4520,30 +4682,45 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
char *p;
uint32 attrs = SVAL(inbuf,smb_vwv0);
NTSTATUS status;
- BOOL path1_contains_wcard = False;
- BOOL path2_contains_wcard = False;
+ BOOL src_has_wcard = False;
+ BOOL dest_has_wcard = False;
START_PROFILE(SMBmv);
p = smb_buf(inbuf) + 1;
- p += srvstr_get_path_wcard(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, &path1_contains_wcard);
+ p += srvstr_get_path_wcard(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, &src_has_wcard);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBmv);
return ERROR_NT(status);
}
p++;
- p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &path2_contains_wcard);
+ p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &dest_has_wcard);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBmv);
return ERROR_NT(status);
}
- RESOLVE_DFSPATH_WCARD(name, conn, inbuf, outbuf);
- RESOLVE_DFSPATH_WCARD(newname, conn, inbuf, outbuf);
+ status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name, &src_has_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBmv);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
+ }
+
+ status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname, &dest_has_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBmv);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
+ }
DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
- status = rename_internals(conn, name, newname, attrs, False, path1_contains_wcard);
+ status = rename_internals(conn, name, newname, attrs, False, src_has_wcard, dest_has_wcard);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBmv);
if (open_was_deferred(SVAL(inbuf,smb_mid))) {
@@ -4567,8 +4744,12 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
* TODO: check error codes on all callers
*/
-NTSTATUS copy_file(char *src, char *dest1,connection_struct *conn, int ofun,
- int count, BOOL target_is_directory)
+NTSTATUS copy_file(connection_struct *conn,
+ char *src,
+ char *dest1,
+ int ofun,
+ int count,
+ BOOL target_is_directory)
{
SMB_STRUCT_STAT src_sbuf, sbuf2;
SMB_OFF_T ret=-1;
@@ -4653,7 +4834,7 @@ NTSTATUS copy_file(char *src, char *dest1,connection_struct *conn, int ofun,
close_file(fsp1,NORMAL_CLOSE);
/* Ensure the modtime is set correctly on the destination file. */
- fsp_set_pending_modtime( fsp2, src_sbuf.st_mtime);
+ fsp_set_pending_modtime( fsp2, get_mtimespec(&src_sbuf));
/*
* As we are opening fsp1 read-only we only expect
@@ -4688,14 +4869,12 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
int count=0;
int error = ERRnoaccess;
int err = 0;
- BOOL has_wild;
- BOOL exists=False;
int tid2 = SVAL(inbuf,smb_vwv0);
int ofun = SVAL(inbuf,smb_vwv1);
int flags = SVAL(inbuf,smb_vwv2);
BOOL target_is_directory=False;
- BOOL path_contains_wcard1 = False;
- BOOL path_contains_wcard2 = False;
+ BOOL source_has_wild = False;
+ BOOL dest_has_wild = False;
SMB_STRUCT_STAT sbuf1, sbuf2;
NTSTATUS status;
START_PROFILE(SMBcopy);
@@ -4703,12 +4882,12 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
*directory = *mask = 0;
p = smb_buf(inbuf);
- p += srvstr_get_path_wcard(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, &path_contains_wcard1);
+ p += srvstr_get_path_wcard(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, &source_has_wild);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBcopy);
return ERROR_NT(status);
}
- p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &path_contains_wcard2);
+ p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &dest_has_wild);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBcopy);
return ERROR_NT(status);
@@ -4723,16 +4902,31 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
return ERROR_DOS(ERRSRV,ERRinvdevice);
}
- RESOLVE_DFSPATH_WCARD(name, conn, inbuf, outbuf);
- RESOLVE_DFSPATH_WCARD(newname, conn, inbuf, outbuf);
+ status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name, &source_has_wild);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBcopy);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
+ }
- status = unix_convert(conn, name, path_contains_wcard1, NULL, &sbuf1);
+ status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname, &dest_has_wild);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBcopy);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
return ERROR_NT(status);
}
- status = unix_convert(conn, newname, path_contains_wcard2, NULL, &sbuf2);
+ status = unix_convert(conn, name, source_has_wild, NULL, &sbuf1);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBcopy);
+ return ERROR_NT(status);
+ }
+
+ status = unix_convert(conn, newname, dest_has_wild, NULL, &sbuf2);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBcopy);
return ERROR_NT(status);
@@ -4776,25 +4970,38 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
* Tine Smukavec <valentin.smukavec@hermes.si>.
*/
- if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params))
+ if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) {
mangle_check_cache( mask, sizeof(pstring)-1, conn->params );
+ }
- has_wild = path_contains_wcard1;
-
- if (!has_wild) {
+ if (!source_has_wild) {
pstrcat(directory,"/");
pstrcat(directory,mask);
- if (resolve_wildcards(directory,newname)
- && NT_STATUS_IS_OK(status = copy_file(
- directory,newname,conn,ofun,
- count,target_is_directory)))
- count++;
- if(!count && !NT_STATUS_IS_OK(status)) {
- END_PROFILE(SMBcopy);
+ if (dest_has_wild) {
+ if (!resolve_wildcards(directory,newname)) {
+ END_PROFILE(SMBcopy);
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+ }
+
+ status = check_name(conn, directory);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ERROR_NT(status);
+ }
+
+ status = check_name(conn, newname);
+ if (!NT_STATUS_IS_OK(status)) {
return ERROR_NT(status);
}
- if (!count) {
- exists = vfs_file_exist(conn,directory,NULL);
+
+ status = copy_file(conn,directory,newname,ofun,
+ count,target_is_directory);
+
+ if(!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBcopy);
+ return ERROR_NT(status);
+ } else {
+ count++;
}
} else {
struct smb_Dir *dir_hnd = NULL;
@@ -4833,13 +5040,27 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
error = ERRnoaccess;
slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
pstrcpy(destname,newname);
- if (resolve_wildcards(fname,destname) &&
- NT_STATUS_IS_OK(status = copy_file(
- fname,destname,conn,ofun,
- count,target_is_directory))) {
+ if (!resolve_wildcards(fname,destname)) {
+ continue;
+ }
+
+ status = check_name(conn, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ERROR_NT(status);
+ }
+
+ status = check_name(conn, destname);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ERROR_NT(status);
+ }
+
+ DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname, destname));
+
+ status = copy_file(conn,fname,destname,ofun,
+ count,target_is_directory);
+ if (NT_STATUS_IS_OK(status)) {
count++;
}
- DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname));
}
CloseDir(dir_hnd);
}
@@ -4888,7 +5109,14 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
return ERROR_NT(status);
}
- RESOLVE_DFSPATH(newdir, conn, inbuf, outbuf);
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newdir);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(pathworks_setdir);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
+ }
if (strlen(newdir) != 0) {
if (!vfs_directory_exist(conn,newdir,NULL)) {
@@ -5440,7 +5668,7 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,
int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
{
- struct utimbuf unix_times;
+ struct timespec ts[2];
int outsize = 0;
files_struct *fsp = file_fsp(inbuf,smb_vwv0);
START_PROFILE(SMBsetattrE);
@@ -5457,15 +5685,15 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
* time as UNIX can't set this.
*/
- unix_times.actime = srv_make_unix_date2(inbuf+smb_vwv3);
- unix_times.modtime = srv_make_unix_date2(inbuf+smb_vwv5);
+ ts[0] = convert_time_t_to_timespec(srv_make_unix_date2(inbuf+smb_vwv3)); /* atime. */
+ ts[1] = convert_time_t_to_timespec(srv_make_unix_date2(inbuf+smb_vwv5)); /* mtime. */
/*
* Patch from Ray Frush <frush@engr.colostate.edu>
* Sometimes times are sent as zero - ignore them.
*/
- if (null_mtime(unix_times.actime) && null_mtime(unix_times.modtime)) {
+ if (null_timespec(ts[0]) && null_timespec(ts[1])) {
/* Ignore request */
if( DEBUGLVL( 3 ) ) {
dbgtext( "reply_setattrE fnum=%d ", fsp->fnum);
@@ -5473,20 +5701,22 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
}
END_PROFILE(SMBsetattrE);
return(outsize);
- } else if (!null_mtime(unix_times.actime) && null_mtime(unix_times.modtime)) {
+ } else if (!null_timespec(ts[0]) && null_timespec(ts[1])) {
/* set modify time = to access time if modify time was unset */
- unix_times.modtime = unix_times.actime;
+ ts[1] = ts[0];
}
/* Set the date on this file */
/* Should we set pending modtime here ? JRA */
- if(file_utime(conn, fsp->fsp_name, &unix_times)) {
+ if(file_ntimes(conn, fsp->fsp_name, ts)) {
END_PROFILE(SMBsetattrE);
return ERROR_DOS(ERRDOS,ERRnoaccess);
}
- DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n",
- fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) );
+ DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u\n",
+ fsp->fnum,
+ (unsigned int)ts[0].tv_sec,
+ (unsigned int)ts[1].tv_sec));
END_PROFILE(SMBsetattrE);
return(outsize);
diff --git a/source/smbd/sesssetup.c b/source/smbd/sesssetup.c
index 7a5f8be47ff..ff1b2821cca 100644
--- a/source/smbd/sesssetup.c
+++ b/source/smbd/sesssetup.c
@@ -158,13 +158,76 @@ static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
#ifdef HAVE_KRB5
+
+#if 0
+/* Experiment that failed. See "only happens with a KDC" comment below. */
+/****************************************************************************
+ Cerate a clock skew error blob for a Windows client.
+****************************************************************************/
+
+static BOOL make_krb5_skew_error(DATA_BLOB *pblob_out)
+{
+ krb5_context context = NULL;
+ krb5_error_code kerr = 0;
+ krb5_data reply;
+ krb5_principal host_princ = NULL;
+ char *host_princ_s = NULL;
+ BOOL ret = False;
+
+ *pblob_out = data_blob(NULL,0);
+
+ initialize_krb5_error_table();
+ kerr = krb5_init_context(&context);
+ if (kerr) {
+ return False;
+ }
+ /* Create server principal. */
+ asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
+ if (!host_princ_s) {
+ goto out;
+ }
+ strlower_m(host_princ_s);
+
+ kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
+ if (kerr) {
+ DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed for name %s: Error %s\n",
+ host_princ_s, error_message(kerr) ));
+ goto out;
+ }
+
+ kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW, host_princ, &reply);
+ if (kerr) {
+ DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error failed: Error %s\n",
+ error_message(kerr) ));
+ goto out;
+ }
+
+ *pblob_out = data_blob(reply.data, reply.length);
+ kerberos_free_data_contents(context,&reply);
+ ret = True;
+
+ out:
+
+ if (host_princ_s) {
+ SAFE_FREE(host_princ_s);
+ }
+ if (host_princ) {
+ krb5_free_principal(context, host_princ);
+ }
+ krb5_free_context(context);
+ return ret;
+}
+#endif
+
/****************************************************************************
-reply to a session setup spnego negotiate packet for kerberos
+ Reply to a session setup spnego negotiate packet for kerberos.
****************************************************************************/
+
static int reply_spnego_kerberos(connection_struct *conn,
char *inbuf, char *outbuf,
int length, int bufsize,
- DATA_BLOB *secblob)
+ DATA_BLOB *secblob,
+ BOOL *p_invalidate_vuid)
{
TALLOC_CTX *mem_ctx;
DATA_BLOB ticket;
@@ -191,9 +254,13 @@ static int reply_spnego_kerberos(connection_struct *conn,
ZERO_STRUCT(ap_rep_wrapped);
ZERO_STRUCT(response);
+ /* Normally we will always invalidate the intermediate vuid. */
+ *p_invalidate_vuid = True;
+
mem_ctx = talloc_init("reply_spnego_kerberos");
- if (mem_ctx == NULL)
+ if (mem_ctx == NULL) {
return ERROR_NT(nt_status_squash(NT_STATUS_NO_MEMORY));
+ }
if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
talloc_destroy(mem_ctx);
@@ -205,9 +272,50 @@ static int reply_spnego_kerberos(connection_struct *conn,
data_blob_free(&ticket);
if (!NT_STATUS_IS_OK(ret)) {
- DEBUG(1,("Failed to verify incoming ticket!\n"));
+#if 0
+ /* Experiment that failed. See "only happens with a KDC" comment below. */
+
+ if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
+
+ /*
+ * Windows in this case returns NT_STATUS_MORE_PROCESSING_REQUIRED
+ * with a negTokenTarg blob containing an krb5_error struct ASN1 encoded
+ * containing KRB5KRB_AP_ERR_SKEW. The client then fixes its
+ * clock and continues rather than giving an error. JRA.
+ * -- Looks like this only happens with a KDC. JRA.
+ */
+
+ BOOL ok = make_krb5_skew_error(&ap_rep);
+ if (!ok) {
+ talloc_destroy(mem_ctx);
+ return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
+ }
+ ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_ERROR);
+ response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
+ reply_sesssetup_blob(conn, outbuf, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
+
+ /*
+ * In this one case we don't invalidate the intermediate vuid.
+ * as we're expecting the client to re-use it for the next
+ * sessionsetupX packet. JRA.
+ */
+
+ *p_invalidate_vuid = False;
+
+ data_blob_free(&ap_rep);
+ data_blob_free(&ap_rep_wrapped);
+ data_blob_free(&response);
+ talloc_destroy(mem_ctx);
+ return -1; /* already replied */
+ }
+#else
+ if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
+ ret = NT_STATUS_LOGON_FAILURE;
+ }
+#endif
+ DEBUG(1,("Failed to verify incoming ticket with error %s!\n", nt_errstr(ret)));
talloc_destroy(mem_ctx);
- return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
+ return ERROR_NT(nt_status_squash(ret));
}
DEBUG(3,("Ticket name is [%s]\n", client));
@@ -523,32 +631,19 @@ static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *out
}
/****************************************************************************
- Reply to a session setup spnego negotiate packet.
+ Is this a krb5 mechanism ?
****************************************************************************/
-static int reply_spnego_negotiate(connection_struct *conn,
- char *inbuf,
- char *outbuf,
- uint16 vuid,
- int length, int bufsize,
- DATA_BLOB blob1,
- AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
+static NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out, BOOL *p_is_krb5)
{
char *OIDs[ASN1_MAX_OIDS];
- DATA_BLOB secblob;
int i;
- DATA_BLOB chal;
-#ifdef HAVE_KRB5
- BOOL got_kerberos_mechanism = False;
-#endif
- NTSTATUS nt_status;
- /* parse out the OIDs and the first sec blob */
- if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
- /* Kill the intermediate vuid */
- invalidate_vuid(vuid);
+ *p_is_krb5 = False;
- return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
+ /* parse out the OIDs and the first sec blob */
+ if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
+ return NT_STATUS_LOGON_FAILURE;
}
/* only look at the first OID for determining the mechToken --
@@ -564,24 +659,53 @@ static int reply_spnego_negotiate(connection_struct *conn,
#ifdef HAVE_KRB5
if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
- got_kerberos_mechanism = True;
+ *p_is_krb5 = True;
}
#endif
for (i=0;OIDs[i];i++) {
- DEBUG(3,("Got OID %s\n", OIDs[i]));
+ DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
free(OIDs[i]);
}
- DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length));
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Reply to a session setup spnego negotiate packet.
+****************************************************************************/
+
+static int reply_spnego_negotiate(connection_struct *conn,
+ char *inbuf,
+ char *outbuf,
+ uint16 vuid,
+ int length, int bufsize,
+ DATA_BLOB blob1,
+ AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
+{
+ DATA_BLOB secblob;
+ DATA_BLOB chal;
+ BOOL got_kerberos_mechanism = False;
+ NTSTATUS status;
+
+ status = parse_spnego_mechanisms(blob1, &secblob, &got_kerberos_mechanism);
+ if (!NT_STATUS_IS_OK(status)) {
+ /* Kill the intermediate vuid */
+ invalidate_vuid(vuid);
+ return ERROR_NT(nt_status_squash(status));
+ }
+
+ DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n", (unsigned long)secblob.length));
#ifdef HAVE_KRB5
if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
+ BOOL destroy_vuid = True;
int ret = reply_spnego_kerberos(conn, inbuf, outbuf,
- length, bufsize, &secblob);
+ length, bufsize, &secblob, &destroy_vuid);
data_blob_free(&secblob);
- /* Kill the intermediate vuid */
- invalidate_vuid(vuid);
-
+ if (destroy_vuid) {
+ /* Kill the intermediate vuid */
+ invalidate_vuid(vuid);
+ }
return ret;
}
#endif
@@ -590,28 +714,27 @@ static int reply_spnego_negotiate(connection_struct *conn,
auth_ntlmssp_end(auth_ntlmssp_state);
}
- nt_status = auth_ntlmssp_start(auth_ntlmssp_state);
- if (!NT_STATUS_IS_OK(nt_status)) {
+ status = auth_ntlmssp_start(auth_ntlmssp_state);
+ if (!NT_STATUS_IS_OK(status)) {
/* Kill the intermediate vuid */
invalidate_vuid(vuid);
-
- return ERROR_NT(nt_status_squash(nt_status));
+ return ERROR_NT(nt_status_squash(status));
}
- nt_status = auth_ntlmssp_update(*auth_ntlmssp_state,
+ status = auth_ntlmssp_update(*auth_ntlmssp_state,
secblob, &chal);
data_blob_free(&secblob);
reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state,
- &chal, nt_status, True);
+ &chal, status, True);
data_blob_free(&chal);
/* already replied */
return -1;
}
-
+
/****************************************************************************
Reply to a session setup spnego auth packet.
****************************************************************************/
@@ -622,8 +745,10 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
DATA_BLOB blob1,
AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
{
- DATA_BLOB auth, auth_reply;
- NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
+ DATA_BLOB auth = data_blob(NULL,0);
+ DATA_BLOB auth_reply = data_blob(NULL,0);
+ DATA_BLOB secblob = data_blob(NULL,0);
+ NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
if (!spnego_parse_auth(blob1, &auth)) {
#if 0
@@ -634,6 +759,33 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
}
+
+ if (auth.data[0] == ASN1_APPLICATION(0)) {
+ /* Might be a second negTokenTarg packet */
+
+ BOOL got_krb5_mechanism = False;
+ status = parse_spnego_mechanisms(auth, &secblob, &got_krb5_mechanism);
+ if (NT_STATUS_IS_OK(status)) {
+ DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n", (unsigned long)secblob.length));
+#ifdef HAVE_KRB5
+ if ( got_krb5_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
+ BOOL destroy_vuid = True;
+ int ret = reply_spnego_kerberos(conn, inbuf, outbuf,
+ length, bufsize, &secblob, &destroy_vuid);
+ data_blob_free(&secblob);
+ data_blob_free(&auth);
+ if (destroy_vuid) {
+ /* Kill the intermediate vuid */
+ invalidate_vuid(vuid);
+ }
+ return ret;
+ }
+#endif
+ }
+ }
+
+ /* If we get here it wasn't a negTokenTarg auth packet. */
+ data_blob_free(&secblob);
if (!*auth_ntlmssp_state) {
/* Kill the intermediate vuid */
@@ -643,14 +795,14 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
}
- nt_status = auth_ntlmssp_update(*auth_ntlmssp_state,
+ status = auth_ntlmssp_update(*auth_ntlmssp_state,
auth, &auth_reply);
data_blob_free(&auth);
reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid,
auth_ntlmssp_state,
- &auth_reply, nt_status, True);
+ &auth_reply, status, True);
data_blob_free(&auth_reply);
diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c
index 5bbd618231b..deb5db1bafe 100644
--- a/source/smbd/trans2.c
+++ b/source/smbd/trans2.c
@@ -5,6 +5,7 @@
Copyright (C) Stefan (metze) Metzmacher 2003
Copyright (C) Volker Lendecke 2005
Copyright (C) Steve French 2005
+ Copyright (C) James Peach 2007
Extensively modified by Andrew Tridgell, 1995
@@ -34,6 +35,16 @@ extern struct current_user current_user;
#define get_file_size(sbuf) ((sbuf).st_size)
#define DIR_ENTRY_SAFETY_MARGIN 4096
+static char *store_file_unix_basic(connection_struct *conn,
+ char *pdata,
+ files_struct *fsp,
+ const SMB_STRUCT_STAT *psbuf);
+
+static char *store_file_unix_basic_info2(connection_struct *conn,
+ char *pdata,
+ files_struct *fsp,
+ const SMB_STRUCT_STAT *psbuf);
+
/********************************************************************
Roundup a value to the nearest allocation roundup size boundary.
Only do this for Windows clients.
@@ -56,7 +67,7 @@ SMB_BIG_UINT smb_roundup(connection_struct *conn, SMB_BIG_UINT val)
account sparse files.
********************************************************************/
-SMB_BIG_UINT get_allocation_size(connection_struct *conn, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
+SMB_BIG_UINT get_allocation_size(connection_struct *conn, files_struct *fsp, const SMB_STRUCT_STAT *sbuf)
{
SMB_BIG_UINT ret;
@@ -1191,15 +1202,17 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
continue;
}
} else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,pathreal,&sbuf) != 0) {
+ pstring link_target;
/* Needed to show the msdfs symlinks as
* directories */
if(lp_host_msdfs() &&
lp_msdfs_root(SNUM(conn)) &&
- ((ms_dfs_link = is_msdfs_link(NULL,conn, pathreal, NULL, NULL, &sbuf)) == True)) {
-
- DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s as a directory\n", pathreal));
+ ((ms_dfs_link = is_msdfs_link(conn, pathreal, link_target, &sbuf)) == True)) {
+ DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s "
+ "as a directory\n",
+ pathreal));
sbuf.st_mode = (sbuf.st_mode & 0xFFF) | S_IFDIR;
} else {
@@ -1578,51 +1591,21 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
/* CIFS UNIX Extension. */
case SMB_FIND_FILE_UNIX:
- DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX\n"));
+ case SMB_FIND_FILE_UNIX_INFO2:
p+= 4;
SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */
/* Begin of SMB_QUERY_FILE_UNIX_BASIC */
- SOFF_T(p,0,get_file_size(sbuf)); /* File size 64 Bit */
- p+= 8;
-
- SOFF_T(p,0,get_allocation_size(conn,NULL,&sbuf)); /* Number of bytes used on disk - 64 Bit */
- p+= 8;
-
- put_long_date_timespec(p,get_ctimespec(&sbuf)); /* Inode change Time 64 Bit */
- put_long_date_timespec(p+8,get_atimespec(&sbuf)); /* Last access time 64 Bit */
- put_long_date_timespec(p+16,get_mtimespec(&sbuf)); /* Last modification time 64 Bit */
- p+= 24;
-
- SIVAL(p,0,sbuf.st_uid); /* user id for the owner */
- SIVAL(p,4,0);
- p+= 8;
-
- SIVAL(p,0,sbuf.st_gid); /* group id of owner */
- SIVAL(p,4,0);
- p+= 8;
-
- SIVAL(p,0,unix_filetype(sbuf.st_mode));
- p+= 4;
-
- SIVAL(p,0,unix_dev_major(sbuf.st_rdev)); /* Major device number if type is device */
- SIVAL(p,4,0);
- p+= 8;
-
- SIVAL(p,0,unix_dev_minor(sbuf.st_rdev)); /* Minor device number if type is device */
- SIVAL(p,4,0);
- p+= 8;
-
- SINO_T_VAL(p,0,(SMB_INO_T)sbuf.st_ino); /* inode number */
- p+= 8;
- SIVAL(p,0, unix_perms_to_wire(sbuf.st_mode)); /* Standard UNIX file permissions */
- SIVAL(p,4,0);
- p+= 8;
-
- SIVAL(p,0,sbuf.st_nlink); /* number of hard links */
- SIVAL(p,4,0);
- p+= 8;
+ if (info_level == SMB_FIND_FILE_UNIX) {
+ DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX\n"));
+ p = store_file_unix_basic(conn, p,
+ NULL, &sbuf);
+ } else {
+ DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX_INFO2\n"));
+ p = store_file_unix_basic_info2(conn, p,
+ NULL, &sbuf);
+ }
len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE);
p += len;
@@ -1732,6 +1715,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
break;
case SMB_FIND_FILE_UNIX:
+ case SMB_FIND_FILE_UNIX_INFO2:
if (!lp_unix_extensions()) {
return ERROR_NT(NT_STATUS_INVALID_LEVEL);
}
@@ -1745,7 +1729,13 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
return ERROR_NT(ntstatus);
}
- RESOLVE_DFSPATH_WCARD(directory, conn, inbuf, outbuf);
+ ntstatus = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, directory, &mask_contains_wcard);
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(ntstatus);
+ }
ntstatus = unix_convert(conn, directory, True, NULL, &sbuf);
if (!NT_STATUS_IS_OK(ntstatus)) {
@@ -2037,6 +2027,7 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
break;
case SMB_FIND_FILE_UNIX:
+ case SMB_FIND_FILE_UNIX_INFO2:
if (!lp_unix_extensions()) {
return ERROR_NT(NT_STATUS_INVALID_LEVEL);
}
@@ -2232,7 +2223,7 @@ static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf
char **pparams, int total_params, char **ppdata, int total_data,
unsigned int max_data_bytes)
{
- char *pdata = *ppdata;
+ char *pdata;
char *params = *pparams;
uint16 info_level;
int data_len, len;
@@ -2530,6 +2521,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
CIFS_UNIX_POSIX_ACLS_CAP|
CIFS_UNIX_POSIX_PATHNAMES_CAP|
CIFS_UNIX_FCNTL_LOCKS_CAP|
+ CIFS_UNIX_EXTATTR_CAP|
CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)));
break;
@@ -2566,6 +2558,114 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
break;
}
+ case SMB_QUERY_POSIX_WHOAMI:
+ {
+ uint32_t flags = 0;
+ uint32_t sid_bytes;
+ int i;
+
+ if (!lp_unix_extensions()) {
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+ }
+
+ if (max_data_bytes < 40) {
+ return ERROR_NT(NT_STATUS_BUFFER_TOO_SMALL);
+ }
+
+ /* We ARE guest if global_sid_Builtin_Guests is
+ * in our list of SIDs.
+ */
+ if (nt_token_check_sid(&global_sid_Builtin_Guests,
+ current_user.nt_user_token)) {
+ flags |= SMB_WHOAMI_GUEST;
+ }
+
+ /* We are NOT guest if global_sid_Authenticated_Users
+ * is in our list of SIDs.
+ */
+ if (nt_token_check_sid(&global_sid_Authenticated_Users,
+ current_user.nt_user_token)) {
+ flags &= ~SMB_WHOAMI_GUEST;
+ }
+
+ /* NOTE: 8 bytes for UID/GID, irrespective of native
+ * platform size. This matches
+ * SMB_QUERY_FILE_UNIX_BASIC and friends.
+ */
+ data_len = 4 /* flags */
+ + 4 /* flag mask */
+ + 8 /* uid */
+ + 8 /* gid */
+ + 4 /* ngroups */
+ + 4 /* num_sids */
+ + 4 /* SID bytes */
+ + 4 /* pad/reserved */
+ + (current_user.ut.ngroups * 8)
+ /* groups list */
+ + (current_user.nt_user_token->num_sids *
+ SID_MAX_SIZE)
+ /* SID list */;
+
+ SIVAL(pdata, 0, flags);
+ SIVAL(pdata, 4, SMB_WHOAMI_MASK);
+ SBIG_UINT(pdata, 8, (SMB_BIG_UINT)current_user.ut.uid);
+ SBIG_UINT(pdata, 16, (SMB_BIG_UINT)current_user.ut.gid);
+
+
+ if (data_len >= max_data_bytes) {
+ /* Potential overflow, skip the GIDs and SIDs. */
+
+ SIVAL(pdata, 24, 0); /* num_groups */
+ SIVAL(pdata, 28, 0); /* num_sids */
+ SIVAL(pdata, 32, 0); /* num_sid_bytes */
+ SIVAL(pdata, 36, 0); /* reserved */
+
+ data_len = 40;
+ break;
+ }
+
+ SIVAL(pdata, 24, current_user.ut.ngroups);
+ SIVAL(pdata, 28,
+ current_user.nt_user_token->num_sids);
+
+ /* We walk the SID list twice, but this call is fairly
+ * infrequent, and I don't expect that it's performance
+ * sensitive -- jpeach
+ */
+ for (i = 0, sid_bytes = 0;
+ i < current_user.nt_user_token->num_sids; ++i) {
+ sid_bytes +=
+ sid_size(&current_user.nt_user_token->user_sids[i]);
+ }
+
+ /* SID list byte count */
+ SIVAL(pdata, 32, sid_bytes);
+
+ /* 4 bytes pad/reserved - must be zero */
+ SIVAL(pdata, 36, 0);
+ data_len = 40;
+
+ /* GID list */
+ for (i = 0; i < current_user.ut.ngroups; ++i) {
+ SBIG_UINT(pdata, data_len,
+ (SMB_BIG_UINT)current_user.ut.groups[i]);
+ data_len += 8;
+ }
+
+ /* SID list */
+ for (i = 0;
+ i < current_user.nt_user_token->num_sids; ++i) {
+ int sid_len =
+ sid_size(&current_user.nt_user_token->user_sids[i]);
+
+ sid_linearize(pdata + data_len, sid_len,
+ &current_user.nt_user_token->user_sids[i]);
+ data_len += sid_len;
+ }
+
+ break;
+ }
+
case SMB_MAC_QUERY_FS_INFO:
/*
* Thursby MAC extension... ONLY on NTFS filesystems
@@ -2871,7 +2971,7 @@ static BOOL marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_
static char *store_file_unix_basic(connection_struct *conn,
char *pdata,
files_struct *fsp,
- SMB_STRUCT_STAT *psbuf)
+ const SMB_STRUCT_STAT *psbuf)
{
DEBUG(10,("store_file_unix_basic: SMB_QUERY_FILE_UNIX_BASIC\n"));
DEBUG(4,("store_file_unix_basic: st_mode=%o\n",(int)psbuf->st_mode));
@@ -2920,6 +3020,121 @@ static char *store_file_unix_basic(connection_struct *conn,
return pdata;
}
+/* Forward and reverse mappings from the UNIX_INFO2 file flags field and
+ * the chflags(2) (or equivalent) flags.
+ *
+ * XXX: this really should be behind the VFS interface. To do this, we would
+ * need to alter SMB_STRUCT_STAT so that it included a flags and a mask field.
+ * Each VFS module could then implement it's own mapping as appropriate for the
+ * platform. We would then pass the SMB flags into SMB_VFS_CHFLAGS.
+ */
+static const struct {unsigned stat_fflag; unsigned smb_fflag;}
+ info2_flags_map[] =
+{
+#ifdef UF_NODUMP
+ { UF_NODUMP, EXT_DO_NOT_BACKUP },
+#endif
+
+#ifdef UF_IMMUTABLE
+ { UF_IMMUTABLE, EXT_IMMUTABLE },
+#endif
+
+#ifdef UF_APPEND
+ { UF_APPEND, EXT_OPEN_APPEND_ONLY },
+#endif
+
+#ifdef UF_HIDDEN
+ { UF_HIDDEN, EXT_HIDDEN },
+#endif
+
+ /* Do not remove. We need to guarantee that this array has at least one
+ * entry to build on HP-UX.
+ */
+ { 0, 0 }
+
+};
+
+static void map_info2_flags_from_sbuf(const SMB_STRUCT_STAT *psbuf,
+ uint32 *smb_fflags, uint32 *smb_fmask)
+{
+#ifdef HAVE_STAT_ST_FLAGS
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
+ *smb_fmask |= info2_flags_map[i].smb_fflag;
+ if (psbuf->st_flags & info2_flags_map[i].stat_fflag) {
+ *smb_fflags |= info2_flags_map[i].smb_fflag;
+ }
+ }
+#endif /* HAVE_STAT_ST_FLAGS */
+}
+
+static BOOL map_info2_flags_to_sbuf(const SMB_STRUCT_STAT *psbuf,
+ const uint32 smb_fflags,
+ const uint32 smb_fmask,
+ int *stat_fflags)
+{
+#ifdef HAVE_STAT_ST_FLAGS
+ uint32 max_fmask = 0;
+ int i;
+
+ *stat_fflags = psbuf->st_flags;
+
+ /* For each flags requested in smb_fmask, check the state of the
+ * corresponding flag in smb_fflags and set or clear the matching
+ * stat flag.
+ */
+
+ for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
+ max_fmask |= info2_flags_map[i].smb_fflag;
+ if (smb_fmask & info2_flags_map[i].smb_fflag) {
+ if (smb_fflags & info2_flags_map[i].smb_fflag) {
+ *stat_fflags |= info2_flags_map[i].stat_fflag;
+ } else {
+ *stat_fflags &= ~info2_flags_map[i].stat_fflag;
+ }
+ }
+ }
+
+ /* If smb_fmask is asking to set any bits that are not supported by
+ * our flag mappings, we should fail.
+ */
+ if ((smb_fmask & max_fmask) != smb_fmask) {
+ return False;
+ }
+
+ return True;
+#else
+ return False;
+#endif /* HAVE_STAT_ST_FLAGS */
+}
+
+
+/* Just like SMB_QUERY_FILE_UNIX_BASIC, but with the addition
+ * of file flags and birth (create) time.
+ */
+static char *store_file_unix_basic_info2(connection_struct *conn,
+ char *pdata,
+ files_struct *fsp,
+ const SMB_STRUCT_STAT *psbuf)
+{
+ uint32 file_flags = 0;
+ uint32 flags_mask = 0;
+
+ pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
+
+ /* Create (birth) time 64 bit */
+ put_long_date_timespec(pdata, get_create_timespec(psbuf, False));
+ pdata += 8;
+
+ map_info2_flags_from_sbuf(psbuf, &file_flags, &flags_mask);
+ SIVAL(pdata, 0, file_flags); /* flags */
+ SIVAL(pdata, 4, flags_mask); /* mask */
+ pdata += 8;
+
+ return pdata;
+}
+
/****************************************************************************
Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by
file name or file id).
@@ -2970,6 +3185,10 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *
DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level));
+ if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+ }
+
if(fsp && (fsp->fake_file_handle)) {
/*
* This is actually for the QUOTA_FAKE_FILE --metze
@@ -3026,12 +3245,22 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *
DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level));
+ if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
+ return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+ }
+
srvstr_get_path(inbuf, fname, &params[6], sizeof(fname), total_params - 6, STR_TERMINATE, &status);
if (!NT_STATUS_IS_OK(status)) {
return ERROR_NT(status);
}
- RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
+ }
status = unix_convert(conn, fname, False, NULL, &sbuf);
if (!NT_STATUS_IS_OK(status)) {
@@ -3175,18 +3404,16 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
allocation_size = get_allocation_size(conn,fsp,&sbuf);
if (fsp) {
- if (fsp->pending_modtime) {
+ if (!null_timespec(fsp->pending_modtime)) {
/* the pending modtime overrides the current modtime */
- mtime_ts.tv_sec = fsp->pending_modtime;
- mtime_ts.tv_nsec = 0;
+ mtime_ts = fsp->pending_modtime;
}
} else {
/* Do we have this path open ? */
files_struct *fsp1 = file_find_di_first(sbuf.st_dev, sbuf.st_ino);
- if (fsp1 && fsp1->pending_modtime) {
+ if (fsp1 && !null_timespec(fsp1->pending_modtime)) {
/* the pending modtime overrides the current modtime */
- mtime_ts.tv_sec = fsp1->pending_modtime;
- mtime_ts.tv_nsec = 0;
+ mtime_ts = fsp1->pending_modtime;
}
if (fsp1 && fsp1->initial_allocation_size) {
allocation_size = get_allocation_size(conn, fsp1, &sbuf);
@@ -3539,6 +3766,22 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
break;
+ case SMB_QUERY_FILE_UNIX_INFO2:
+
+ pdata = store_file_unix_basic_info2(conn, pdata, fsp, &sbuf);
+ data_size = PTR_DIFF(pdata,(*ppdata));
+
+ {
+ int i;
+ DEBUG(4,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_INFO2 "));
+
+ for (i=0; i<100; i++)
+ DEBUG(4,("%d=%x, ",i, (*ppdata)[i]));
+ DEBUG(4,("\n"));
+ }
+
+ break;
+
case SMB_QUERY_FILE_UNIX_LINK:
{
pstring buffer;
@@ -3743,17 +3986,22 @@ NTSTATUS hardlink_internals(connection_struct *conn, pstring oldname, pstring ne
return status;
}
+ status = check_name(conn, oldname);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
/* source must already exist. */
if (!VALID_STAT(sbuf1)) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
- status = check_name(conn, oldname);
+ status = unix_convert(conn, newname, False, last_component_newname, &sbuf2);
if (!NT_STATUS_IS_OK(status)) {
- return NT_STATUS_ACCESS_DENIED;
+ return status;
}
- status = unix_convert(conn, newname, False, last_component_newname, &sbuf2);
+ status = check_name(conn, newname);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@@ -3763,11 +4011,6 @@ NTSTATUS hardlink_internals(connection_struct *conn, pstring oldname, pstring ne
return NT_STATUS_OBJECT_NAME_COLLISION;
}
- status = check_name(conn, newname);
- if (!NT_STATUS_IS_OK(status)) {
- return NT_STATUS_ACCESS_DENIED;
- }
-
/* No links from a directory. */
if (S_ISDIR(sbuf1.st_mode)) {
return NT_STATUS_FILE_IS_A_DIRECTORY;
@@ -3798,7 +4041,7 @@ static NTSTATUS smb_set_file_time(connection_struct *conn,
files_struct *fsp,
const char *fname,
const SMB_STRUCT_STAT *psbuf,
- struct utimbuf tvs)
+ struct timespec ts[2])
{
uint32 action =
FILE_NOTIFY_CHANGE_LAST_ACCESS
@@ -3810,26 +4053,30 @@ static NTSTATUS smb_set_file_time(connection_struct *conn,
}
/* get some defaults (no modifications) if any info is zero or -1. */
- if (null_mtime(tvs.actime)) {
- tvs.actime = psbuf->st_atime;
+ if (null_timespec(ts[0])) {
+ ts[0] = get_atimespec(psbuf);
action &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS;
}
- if (null_mtime(tvs.modtime)) {
- tvs.modtime = psbuf->st_mtime;
+ if (null_timespec(ts[1])) {
+ ts[1] = get_mtimespec(psbuf);
action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
}
- DEBUG(6,("smb_set_file_time: actime: %s " , ctime(&tvs.actime)));
- DEBUG(6,("smb_set_file_time: modtime: %s ", ctime(&tvs.modtime)));
+ DEBUG(6,("smb_set_file_time: actime: %s " , time_to_asc(convert_timespec_to_time_t(ts[0])) ));
+ DEBUG(6,("smb_set_file_time: modtime: %s ", time_to_asc(convert_timespec_to_time_t(ts[1])) ));
/*
* Try and set the times of this file if
* they are different from the current values.
*/
- if (psbuf->st_mtime == tvs.modtime && psbuf->st_atime == tvs.actime) {
- return NT_STATUS_OK;
+ {
+ struct timespec mts = get_mtimespec(psbuf);
+ struct timespec ats = get_atimespec(psbuf);
+ if ((timespec_compare(&ts[0], &ats) == 0) && (timespec_compare(&ts[1], &mts) == 0)) {
+ return NT_STATUS_OK;
+ }
}
if(fsp != NULL) {
@@ -3843,15 +4090,16 @@ static NTSTATUS smb_set_file_time(connection_struct *conn,
* away and will set it on file close and after a write. JRA.
*/
- if (tvs.modtime != (time_t)0 && tvs.modtime != (time_t)-1) {
- DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n", ctime(&tvs.modtime) ));
- fsp_set_pending_modtime(fsp, tvs.modtime);
+ if (!null_timespec(ts[1])) {
+ DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n",
+ time_to_asc(convert_timespec_to_time_t(ts[1])) ));
+ fsp_set_pending_modtime(fsp, ts[1]);
}
}
DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n"));
- if(file_utime(conn, fname, &tvs)!=0) {
+ if(file_ntimes(conn, fname, ts)!=0) {
return map_nt_error_from_unix(errno);
}
if (action != 0) {
@@ -4030,6 +4278,12 @@ static NTSTATUS smb_set_file_disposition_info(connection_struct *conn,
delete_on_close = (CVAL(pdata,0) ? True : False);
dosmode = dos_mode(conn, fname, psbuf);
+ DEBUG(10,("smb_set_file_disposition_info: file %s, dosmode = %u, "
+ "delete_on_close = %u\n",
+ fsp->fsp_name,
+ (unsigned int)dosmode,
+ (unsigned int)delete_on_close ));
+
status = can_set_delete_on_close(fsp, delete_on_close, dosmode);
if (!NT_STATUS_IS_OK(status)) {
@@ -4132,7 +4386,6 @@ static NTSTATUS smb_set_file_unix_link(connection_struct *conn,
pstring rel_name;
char *last_dirp = NULL;
- unix_format(link_target);
if (*link_target == '/') {
/* No absolute paths allowed. */
return NT_STATUS_ACCESS_DENIED;
@@ -4186,7 +4439,10 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
return status;
}
- RESOLVE_DFSPATH_STATUS(oldname, conn, inbuf, outbuf);
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, oldname);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
DEBUG(10,("smb_set_file_unix_hlink: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
fname, oldname));
@@ -4211,6 +4467,7 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
uint32 len;
pstring newname;
pstring base_name;
+ BOOL dest_has_wcard = False;
NTSTATUS status = NT_STATUS_OK;
char *p;
@@ -4226,12 +4483,15 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
return NT_STATUS_INVALID_PARAMETER;
}
- srvstr_get_path(inbuf, newname, &pdata[12], sizeof(newname), len, 0, &status);
+ srvstr_get_path_wcard(inbuf, newname, &pdata[12], sizeof(newname), len, 0, &status, &dest_has_wcard);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- RESOLVE_DFSPATH_STATUS(newname, conn, inbuf, outbuf);
+ status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname, &dest_has_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
/* Check the new name has no '/' characters. */
if (strchr_m(newname, '/')) {
@@ -4255,7 +4515,7 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
} else {
DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION %s -> %s\n",
fname, newname ));
- status = rename_internals(conn, fname, base_name, 0, overwrite, False);
+ status = rename_internals(conn, fname, base_name, 0, overwrite, False, dest_has_wcard);
}
return status;
@@ -4305,6 +4565,11 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn,
return NT_STATUS_INVALID_PARAMETER;
}
+ DEBUG(10,("smb_set_posix_acl: file %s num_file_acls = %u, num_def_acls = %u\n",
+ fname ? fname : fsp->fsp_name,
+ (unsigned int)num_file_acls,
+ (unsigned int)num_def_acls));
+
if (valid_file_acls && !set_unix_posix_acl(conn, fsp, fname, num_file_acls,
pdata + SMB_POSIX_ACL_HEADER_SIZE)) {
return map_nt_error_from_unix(errno);
@@ -4386,6 +4651,14 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn,
count = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_LEN_OFFSET);
#endif /* HAVE_LONGLONG */
+ DEBUG(10,("smb_set_posix_lock: file %s, lock_type = %u,"
+ "lock_pid = %u, count = %.0f, offset = %.0f\n",
+ fsp->fsp_name,
+ (unsigned int)lock_type,
+ (unsigned int)lock_pid,
+ (double)count,
+ (double)offset ));
+
if (lock_type == UNLOCK_LOCK) {
status = do_unlock(fsp,
lock_pid,
@@ -4439,22 +4712,25 @@ static NTSTATUS smb_set_info_standard(connection_struct *conn,
const char *fname,
const SMB_STRUCT_STAT *psbuf)
{
- struct utimbuf tvs;
+ struct timespec ts[2];
if (total_data < 12) {
return NT_STATUS_INVALID_PARAMETER;
}
/* access time */
- tvs.actime = srv_make_unix_date2(pdata+l1_fdateLastAccess);
+ ts[0] = convert_time_t_to_timespec(srv_make_unix_date2(pdata+l1_fdateLastAccess));
/* write time */
- tvs.modtime = srv_make_unix_date2(pdata+l1_fdateLastWrite);
+ ts[1] = convert_time_t_to_timespec(srv_make_unix_date2(pdata+l1_fdateLastWrite));
+
+ DEBUG(10,("smb_set_info_standard: file %s\n",
+ fname ? fname : fsp->fsp_name ));
return smb_set_file_time(conn,
fsp,
fname,
psbuf,
- tvs);
+ ts);
}
/****************************************************************************
@@ -4469,10 +4745,10 @@ static NTSTATUS smb_set_file_basic_info(connection_struct *conn,
SMB_STRUCT_STAT *psbuf)
{
/* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */
- time_t write_time;
- time_t changed_time;
+ struct timespec write_time;
+ struct timespec changed_time;
uint32 dosmode = 0;
- struct utimbuf tvs;
+ struct timespec ts[2];
NTSTATUS status = NT_STATUS_OK;
if (total_data < 36) {
@@ -4492,26 +4768,31 @@ static NTSTATUS smb_set_file_basic_info(connection_struct *conn,
/* Ignore create time at offset pdata. */
/* access time */
- tvs.actime = convert_timespec_to_time_t(interpret_long_date(pdata+8));
+ ts[0] = interpret_long_date(pdata+8);
- write_time = convert_timespec_to_time_t(interpret_long_date(pdata+16));
- changed_time = convert_timespec_to_time_t(interpret_long_date(pdata+24));
+ write_time = interpret_long_date(pdata+16);
+ changed_time = interpret_long_date(pdata+24);
- tvs.modtime = MIN(write_time, changed_time);
+ /* mtime */
+ ts[1] = timespec_min(&write_time, &changed_time);
- if (write_time > tvs.modtime && write_time != (time_t)-1) {
- tvs.modtime = write_time;
+ if ((timespec_compare(&write_time, &ts[1]) == 1) && !null_timespec(write_time)) {
+ ts[1] = write_time;
}
+
/* Prefer a defined time to an undefined one. */
- if (null_mtime(tvs.modtime)) {
- tvs.modtime = null_mtime(write_time) ? changed_time : write_time;
+ if (null_timespec(ts[1])) {
+ ts[1] = null_timespec(write_time) ? changed_time : write_time;
}
+ DEBUG(10,("smb_set_file_basic_info: file %s\n",
+ fname ? fname : fsp->fsp_name ));
+
return smb_set_file_time(conn,
fsp,
fname,
psbuf,
- tvs);
+ ts);
}
/****************************************************************************
@@ -4725,7 +5006,7 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
const char *fname,
SMB_STRUCT_STAT *psbuf)
{
- struct utimbuf tvs;
+ struct timespec ts[2];
uint32 raw_unixmode;
mode_t unixmode;
SMB_OFF_T size = 0;
@@ -4752,8 +5033,8 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
#endif /* LARGE_SMB_OFF_T */
}
- tvs.actime = convert_timespec_to_time_t(interpret_long_date(pdata+24)); /* access_time */
- tvs.modtime = convert_timespec_to_time_t(interpret_long_date(pdata+32)); /* modification_time */
+ ts[0] = interpret_long_date(pdata+24); /* access_time */
+ ts[1] = interpret_long_date(pdata+32); /* modification_time */
set_owner = (uid_t)IVAL(pdata,40);
set_grp = (gid_t)IVAL(pdata,48);
raw_unixmode = IVAL(pdata,84);
@@ -4796,8 +5077,8 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
/* Ensure we don't try and change anything else. */
raw_unixmode = SMB_MODE_NO_CHANGE;
size = get_file_size(*psbuf);
- tvs.modtime = psbuf->st_mtime;
- tvs.actime = psbuf->st_atime;
+ ts[0] = get_atimespec(psbuf);
+ ts[1] = get_mtimespec(psbuf);
/*
* We continue here as we might want to change the
* owner uid/gid.
@@ -4876,7 +5157,68 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
fsp,
fname,
psbuf,
- tvs);
+ ts);
+}
+
+/****************************************************************************
+ Deal with SMB_SET_FILE_UNIX_INFO2.
+****************************************************************************/
+
+static NTSTATUS smb_set_file_unix_info2(connection_struct *conn,
+ const char *pdata,
+ int total_data,
+ files_struct *fsp,
+ const char *fname,
+ SMB_STRUCT_STAT *psbuf)
+{
+ NTSTATUS status;
+ uint32 smb_fflags;
+ uint32 smb_fmask;
+
+ if (total_data < 116) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Start by setting all the fields that are common between UNIX_BASIC
+ * and UNIX_INFO2.
+ */
+ status = smb_set_file_unix_basic(conn, pdata, total_data,
+ fsp, fname, psbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ smb_fflags = IVAL(pdata, 108);
+ smb_fmask = IVAL(pdata, 112);
+
+ /* NB: We should only attempt to alter the file flags if the client
+ * sends a non-zero mask.
+ */
+ if (smb_fmask != 0) {
+ int stat_fflags = 0;
+
+ if (!map_info2_flags_to_sbuf(psbuf, smb_fflags, smb_fmask,
+ &stat_fflags)) {
+ /* Client asked to alter a flag we don't understand. */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (fsp && fsp->fh->fd != -1) {
+ /* XXX: we should be using SMB_VFS_FCHFLAGS here. */
+ return NT_STATUS_NOT_SUPPORTED;
+ } else {
+ if (SMB_VFS_CHFLAGS(conn, fname, stat_fflags) != 0) {
+ return map_nt_error_from_unix(errno);
+ }
+ }
+ }
+
+ /* XXX: need to add support for changing the create_time here. You
+ * can do this for paths on Darwin with setattrlist(2). The right way
+ * to hook this up is probably by extending the VFS utimes interface.
+ */
+
+ return NT_STATUS_OK;
}
/****************************************************************************
@@ -4896,13 +5238,16 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn,
mode_t unixmode = (mode_t)0;
files_struct *fsp = NULL;
uint16 info_level_return = 0;
+ int info;
char *pdata = *ppdata;
- if (total_data < 10) {
+ if (total_data < 18) {
return NT_STATUS_INVALID_PARAMETER;
}
raw_unixmode = IVAL(pdata,8);
+ /* Next 4 bytes are not yet defined. */
+
status = unix_perms_from_wire(conn, psbuf, raw_unixmode, PERM_NEW_DIR, &unixmode);
if (!NT_STATUS_IS_OK(status)) {
return status;
@@ -4910,6 +5255,9 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn,
mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS;
+ DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n",
+ fname, (unsigned int)unixmode ));
+
status = open_directory(conn,
fname,
psbuf,
@@ -4918,19 +5266,21 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn,
FILE_CREATE,
0,
mod_unixmode,
- NULL,
+ &info,
&fsp);
if (NT_STATUS_IS_OK(status)) {
close_file(fsp, NORMAL_CLOSE);
}
- info_level_return = SVAL(pdata,12);
+ info_level_return = SVAL(pdata,16);
if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
- *pdata_return_size = 8 + SMB_FILE_UNIX_BASIC_SIZE;
+ *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
+ } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
+ *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
} else {
- *pdata_return_size = 8;
+ *pdata_return_size = 12;
}
/* Realloc the data size */
@@ -4941,15 +5291,21 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn,
}
SSVAL(pdata,0,NO_OPLOCK_RETURN);
- SSVAL(pdata,2,0);
-
- if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
- SSVAL(pdata,4,SMB_QUERY_FILE_UNIX_BASIC);
- SSVAL(pdata,6,0); /* Padding. */
- store_file_unix_basic(conn, pdata + 8, fsp, psbuf);
- } else {
- SSVAL(pdata,4,SMB_NO_INFO_LEVEL_RETURNED);
- SSVAL(pdata,6,0); /* Padding. */
+ SSVAL(pdata,2,0); /* No fnum. */
+ SIVAL(pdata,4,info); /* Was directory created. */
+
+ switch (info_level_return) {
+ case SMB_QUERY_FILE_UNIX_BASIC:
+ SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
+ SSVAL(pdata,10,0); /* Padding. */
+ store_file_unix_basic(conn, pdata + 12, fsp, psbuf);
+ case SMB_QUERY_FILE_UNIX_INFO2:
+ SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
+ SSVAL(pdata,10,0); /* Padding. */
+ store_file_unix_basic_info2(conn, pdata + 12, fsp, psbuf);
+ default:
+ SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
+ SSVAL(pdata,10,0); /* Padding. */
}
return status;
@@ -4982,7 +5338,7 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
int info = 0;
uint16 info_level_return = 0;
- if (total_data < 14) {
+ if (total_data < 18) {
return NT_STATUS_INVALID_PARAMETER;
}
@@ -5034,6 +5390,8 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
}
raw_unixmode = IVAL(pdata,8);
+ /* Next 4 bytes are not yet defined. */
+
status = unix_perms_from_wire(conn,
psbuf,
raw_unixmode,
@@ -5056,6 +5414,11 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
mod_unixmode |= FILE_FLAG_NO_BUFFERING;
}
+ DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n",
+ fname,
+ (unsigned int)wire_open_mode,
+ (unsigned int)unixmode ));
+
status = open_file_ntcreate(conn,
fname,
psbuf,
@@ -5080,12 +5443,16 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
extended_oplock_granted = True;
}
- info_level_return = SVAL(pdata,12);
+ info_level_return = SVAL(pdata,16);
+ /* Allocate the correct return size. */
+
if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
- *pdata_return_size = 8 + SMB_FILE_UNIX_BASIC_SIZE;
+ *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
+ } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
+ *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
} else {
- *pdata_return_size = 8;
+ *pdata_return_size = 12;
}
/* Realloc the data size */
@@ -5109,13 +5476,20 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
}
SSVAL(pdata,2,fsp->fnum);
- if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
- SSVAL(pdata,4,SMB_QUERY_FILE_UNIX_BASIC);
- SSVAL(pdata,6,0); /* padding. */
- store_file_unix_basic(conn, pdata + 8, fsp, psbuf);
- } else {
- SSVAL(pdata,4,SMB_NO_INFO_LEVEL_RETURNED);
- SSVAL(pdata,6,0); /* padding. */
+ SIVAL(pdata,4,info); /* Was file created etc. */
+
+ switch (info_level_return) {
+ case SMB_QUERY_FILE_UNIX_BASIC:
+ SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
+ SSVAL(pdata,10,0); /* padding. */
+ store_file_unix_basic(conn, pdata + 12, fsp, psbuf);
+ case SMB_QUERY_FILE_UNIX_INFO2:
+ SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
+ SSVAL(pdata,10,0); /* padding. */
+ store_file_unix_basic_info2(conn, pdata + 12, fsp, psbuf);
+ default:
+ SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
+ SSVAL(pdata,10,0); /* padding. */
}
return NT_STATUS_OK;
}
@@ -5132,12 +5506,28 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn,
{
NTSTATUS status = NT_STATUS_OK;
files_struct *fsp = NULL;
+ uint16 flags = 0;
int info = 0;
+ if (total_data < 2) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ flags = SVAL(pdata,0);
+
if (!VALID_STAT(*psbuf)) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
+ if ((flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) &&
+ !VALID_STAT_OF_DIR(*psbuf)) {
+ return NT_STATUS_NOT_A_DIRECTORY;
+ }
+
+ DEBUG(10,("smb_posix_unlink: %s %s\n",
+ (flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) ? "directory" : "file",
+ fname));
+
if (VALID_STAT_OF_DIR(*psbuf)) {
status = open_directory(conn,
fname,
@@ -5150,17 +5540,34 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn,
&info,
&fsp);
} else {
+ char del = 1;
+
status = open_file_ntcreate(conn,
fname,
psbuf,
DELETE_ACCESS,
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
FILE_OPEN,
- FILE_DELETE_ON_CLOSE,
+ 0,
FILE_FLAG_POSIX_SEMANTICS|0777,
- INTERNAL_OPEN_ONLY,
+ 0, /* No oplock, but break existing ones. */
&info,
&fsp);
+ /*
+ * For file opens we must set the delete on close
+ * after the open.
+ */
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = smb_set_file_disposition_info(conn,
+ &del,
+ 1,
+ fsp,
+ fname,
+ psbuf);
}
if (!NT_STATUS_IS_OK(status)) {
@@ -5251,13 +5658,24 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
return ERROR_NT(status);
}
- RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
+ }
status = unix_convert(conn, fname, False, NULL, &sbuf);
if (!NT_STATUS_IS_OK(status)) {
return ERROR_NT(status);
}
+ status = check_name(conn, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ERROR_NT(status);
+ }
+
/*
* For CIFS UNIX extensions the target name may not exist.
*/
@@ -5266,12 +5684,6 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
DEBUG(3,("call_trans2setfilepathinfo: stat of %s failed (%s)\n", fname, strerror(errno)));
return UNIXERROR(ERRDOS,ERRbadpath);
}
-
- status = check_name(conn, fname);
- if (!NT_STATUS_IS_OK(status)) {
- return ERROR_NT(status);
- }
-
}
if (!CAN_WRITE(conn)) {
@@ -5294,9 +5706,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
SSVAL(params,0,0);
- if (fsp && fsp->pending_modtime) {
+ if (fsp && !null_timespec(fsp->pending_modtime)) {
/* the pending modtime overrides the current modtime */
- sbuf.st_mtime = fsp->pending_modtime;
+ set_mtimespec(&sbuf, fsp->pending_modtime);
}
switch (info_level) {
@@ -5417,6 +5829,17 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
break;
}
+ case SMB_SET_FILE_UNIX_INFO2:
+ {
+ status = smb_set_file_unix_info2(conn,
+ pdata,
+ total_data,
+ fsp,
+ fname,
+ &sbuf);
+ break;
+ }
+
case SMB_SET_FILE_UNIX_LINK:
{
if (tran_call != TRANSACT2_SETPATHINFO) {
@@ -5576,6 +5999,12 @@ static int call_trans2mkdir(connection_struct *conn, char *inbuf, char *outbuf,
return ERROR_NT(status);
}
+ status = check_name(conn, directory);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5,("call_trans2mkdir error (%s)\n", nt_errstr(status)));
+ return ERROR_NT(status);
+ }
+
/* Any data in this call is an EA list. */
if (total_data && (total_data != 4) && !lp_ea_support(SNUM(conn))) {
return ERROR_NT(NT_STATUS_EAS_NOT_SUPPORTED);
@@ -5607,12 +6036,6 @@ static int call_trans2mkdir(connection_struct *conn, char *inbuf, char *outbuf,
return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
- status = check_name(conn, directory);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(5,("call_trans2mkdir error (%s)\n", nt_errstr(status)));
- return ERROR_NT(status);
- }
-
status = create_directory(conn, directory);
if (!NT_STATUS_IS_OK(status)) {