summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2000-09-27 19:09:59 +0000
committerJeremy Allison <jra@samba.org>2000-09-27 19:09:59 +0000
commitb43b2e4f8a4be30e3f7aca6f570f5376fd508e3d (patch)
tree3c604a52b53f0a846fe62b5995becda7facda187 /source3
parent8c93ddf3e0ea80d482cbee7bf233c32fc69955bb (diff)
downloadsamba-b43b2e4f8a4be30e3f7aca6f570f5376fd508e3d.tar.gz
samba-b43b2e4f8a4be30e3f7aca6f570f5376fd508e3d.tar.bz2
samba-b43b2e4f8a4be30e3f7aca6f570f5376fd508e3d.zip
Restructuring of the code to remove dos_ChDir/dos_GetWd and re-vector them
through the VFS. All file access/directory access code in smbd should now go via the vfs. Added vfs_chown/vfs_chmod calls. Still looking at vfs_get_nt_acl() vfs_set_nt_acl() call API design. Jeremy. (This used to be commit f96625ec124adb6e110dc54632e006b3620a962b)
Diffstat (limited to 'source3')
-rw-r--r--source3/include/proto.h19
-rw-r--r--source3/include/vfs.h7
-rw-r--r--source3/lib/doscalls.c169
-rw-r--r--source3/lib/util.c131
-rw-r--r--source3/param/loadparm.c2
-rw-r--r--source3/smbd/dosmode.c8
-rw-r--r--source3/smbd/filename.c2
-rw-r--r--source3/smbd/notify_hash.c4
-rw-r--r--source3/smbd/oplock.c4
-rw-r--r--source3/smbd/reply.c2
-rw-r--r--source3/smbd/service.c10
-rw-r--r--source3/smbd/unix_acls.c14
-rw-r--r--source3/smbd/vfs-wrap.c46
-rw-r--r--source3/smbd/vfs.c413
14 files changed, 485 insertions, 346 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h
index be773f0bc3..cdc8e70d59 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -90,8 +90,6 @@ BOOL dos_file_exist(char *fname,SMB_STRUCT_STAT *sbuf);
BOOL dos_directory_exist(char *dname,SMB_STRUCT_STAT *st);
time_t dos_file_modtime(char *fname);
SMB_OFF_T dos_file_size(char *file_name);
-int dos_ChDir(char *path);
-char *dos_GetWd(char *path);
/*The following definitions come from lib/error.c */
@@ -339,7 +337,6 @@ void smb_setlen(char *buf,int len);
int set_message(char *buf,int num_words,int num_bytes,BOOL zero);
void dos_clean_name(char *s);
void unix_clean_name(char *s);
-BOOL reduce_name(char *s,char *dir,BOOL widelinks);
void make_dir_struct(char *buf,char *mask,char *fname,SMB_OFF_T size,int mode,time_t date);
void close_low_fds(void);
int set_blocking(int fd, BOOL set);
@@ -3854,23 +3851,35 @@ int vfswrap_lstat(char *path,
SMB_STRUCT_STAT *sbuf);
int vfswrap_unlink(char *path);
int vfswrap_chmod(char *path, mode_t mode);
+int vfswrap_chown(char *path, uid_t uid, gid_t gid);
+int vfswrap_chdir(char *path);
+char *vfswrap_getwd(char *path);
int vfswrap_utime(char *path, struct utimbuf *times);
int vfswrap_ftruncate(int fd, SMB_OFF_T offset);
BOOL vfswrap_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type);
+size_t vfswrap_get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc);
+BOOL vfswrap_set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd);
/*The following definitions come from smbd/vfs.c */
int vfs_init_default(connection_struct *conn);
BOOL vfs_init_custom(connection_struct *conn);
-BOOL vfs_directory_exist(connection_struct *conn, char *dname,
- SMB_STRUCT_STAT *st);
+int vfs_stat(connection_struct *conn, char *fname, SMB_STRUCT_STAT *st);
+BOOL vfs_directory_exist(connection_struct *conn, char *dname, SMB_STRUCT_STAT *st);
int vfs_unlink(connection_struct *conn, char *fname);
+int vfs_chmod(connection_struct *conn, char *fname,mode_t mode);
+int vfs_chown(connection_struct *conn, char *fname, uid_t uid, gid_t gid);
+int vfs_chdir(connection_struct *conn, char *fname);
+char *vfs_getwd(connection_struct *conn, char *unix_path);
BOOL vfs_file_exist(connection_struct *conn,char *fname,SMB_STRUCT_STAT *sbuf);
ssize_t vfs_write_data(files_struct *fsp,char *buffer,size_t N);
SMB_OFF_T vfs_transfer_file(int in_fd, files_struct *in_fsp,
int out_fd, files_struct *out_fsp,
SMB_OFF_T n, char *header, int headlen, int align);
char *vfs_readdirname(connection_struct *conn, void *p);
+int vfs_ChDir(connection_struct *conn, char *path);
+char *vfs_GetWd(connection_struct *conn, char *path);
+BOOL reduce_name(connection_struct *conn, char *s,char *dir,BOOL widelinks);
/*The following definitions come from smbwrapper/realcalls.c */
diff --git a/source3/include/vfs.h b/source3/include/vfs.h
index 1312935e7f..e657354d94 100644
--- a/source3/include/vfs.h
+++ b/source3/include/vfs.h
@@ -184,9 +184,16 @@ struct vfs_ops {
int (*lstat)(char *path, SMB_STRUCT_STAT *sbuf);
int (*unlink)(char *path);
int (*chmod)(char *path, mode_t mode);
+ int (*chown)(char *path, uid_t uid, gid_t gid);
+ int (*chdir)(char *path);
+ char *(*getwd)(char *buf);
int (*utime)(char *path, struct utimbuf *times);
int (*ftruncate)(int fd, SMB_OFF_T offset);
BOOL (*lock)(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type);
+#if 0
+ size_t (*get_nt_acl)(files_struct *fsp, SEC_DESC **ppdesc);
+ BOOL (*set_nt_acl)(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd);
+#endif
};
struct vfs_options {
diff --git a/source3/lib/doscalls.c b/source3/lib/doscalls.c
index 2bd68d3097..50c446faeb 100644
--- a/source3/lib/doscalls.c
+++ b/source3/lib/doscalls.c
@@ -33,6 +33,7 @@
extern int DEBUGLEVEL;
+#if 0 /* Use vfs_unlink. */
/*******************************************************************
Unlink wrapper that calls dos_to_unix.
********************************************************************/
@@ -41,6 +42,7 @@ int dos_unlink(char *fname)
{
return(unlink(dos_to_unix(fname,False)));
}
+#endif
/*******************************************************************
Open() wrapper that calls dos_to_unix.
@@ -85,10 +87,12 @@ char *dos_readdirname(DIR *p)
A chown() wrapper that calls dos_to_unix.
********************************************************************/
+#if 0 /* Use vfs_chown. */
int dos_chown(char *fname, uid_t uid, gid_t gid)
{
return(sys_chown(dos_to_unix(fname,False),uid,gid));
}
+#endif
/*******************************************************************
A stat() wrapper that calls dos_to_unix.
@@ -134,6 +138,7 @@ int dos_rmdir(char *dname)
return(rmdir(dos_to_unix(dname,False)));
}
+#if 0 /* VFS */
/*******************************************************************
chdir() - call dos_to_unix.
********************************************************************/
@@ -142,6 +147,7 @@ int dos_chdir(char *dname)
{
return(chdir(dos_to_unix(dname,False)));
}
+#endif
/*******************************************************************
Utime() - call dos_to_unix.
@@ -282,6 +288,7 @@ int dos_chmod(char *fname,mode_t mode)
return(chmod(dos_to_unix(fname,False),mode));
}
+#if 0 /* VFS */
/*******************************************************************
Getwd - takes a UNIX directory name and returns the name
in dos format.
@@ -295,6 +302,7 @@ char *dos_getwd(char *unix_path)
unix_to_dos(wd, True);
return wd;
}
+#endif /* VFS */
/*******************************************************************
Check if a DOS file exists. Use vfs_file_exist function instead.
@@ -333,164 +341,3 @@ SMB_OFF_T dos_file_size(char *file_name)
{
return get_file_size(dos_to_unix(file_name, False));
}
-
-/*******************************************************************
- A wrapper for dos_chdir().
-********************************************************************/
-
-int dos_ChDir(char *path)
-{
- int res;
- static pstring LastDir="";
-
- if (strcsequal(path,"."))
- return(0);
-
- if (*path == '/' && strcsequal(LastDir,path))
- return(0);
-
- DEBUG(3,("dos_ChDir to %s\n",path));
-
- res = dos_chdir(path);
- if (!res)
- pstrcpy(LastDir,path);
- return(res);
-}
-
-/* number of list structures for a caching GetWd function. */
-#define MAX_GETWDCACHE (50)
-
-struct
-{
- SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
- SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
- char *dos_path; /* The pathname in DOS format. */
- BOOL valid;
-} ino_list[MAX_GETWDCACHE];
-
-BOOL use_getwd_cache=True;
-
-/****************************************************************************
- Prompte a ptr (to make it recently used)
-****************************************************************************/
-
-static void array_promote(char *array,int elsize,int element)
-{
- char *p;
- if (element == 0)
- return;
-
- p = (char *)malloc(elsize);
-
- if (!p)
- {
- DEBUG(5,("Ahh! Can't malloc\n"));
- return;
- }
- memcpy(p,array + element * elsize, elsize);
- memmove(array + elsize,array,elsize*element);
- memcpy(array,p,elsize);
- free(p);
-}
-
-/*******************************************************************
- Return the absolute current directory path - given a UNIX pathname.
- Note that this path is returned in DOS format, not UNIX
- format.
-********************************************************************/
-
-char *dos_GetWd(char *path)
-{
- pstring s;
- static BOOL getwd_cache_init = False;
- SMB_STRUCT_STAT st, st2;
- int i;
-
- *s = 0;
-
- if (!use_getwd_cache)
- return(dos_getwd(path));
-
- /* init the cache */
- if (!getwd_cache_init)
- {
- getwd_cache_init = True;
- for (i=0;i<MAX_GETWDCACHE;i++)
- {
- string_set(&ino_list[i].dos_path,"");
- ino_list[i].valid = False;
- }
- }
-
- /* Get the inode of the current directory, if this doesn't work we're
- in trouble :-) */
-
- if (sys_stat(".",&st) == -1)
- {
- DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path));
- return(dos_getwd(path));
- }
-
-
- for (i=0; i<MAX_GETWDCACHE; i++)
- if (ino_list[i].valid)
- {
-
- /* If we have found an entry with a matching inode and dev number
- then find the inode number for the directory in the cached string.
- If this agrees with that returned by the stat for the current
- directory then all is o.k. (but make sure it is a directory all
- the same...) */
-
- if (st.st_ino == ino_list[i].inode &&
- st.st_dev == ino_list[i].dev)
- {
- if (dos_stat(ino_list[i].dos_path,&st2) == 0)
- {
- if (st.st_ino == st2.st_ino &&
- st.st_dev == st2.st_dev &&
- (st2.st_mode & S_IFMT) == S_IFDIR)
- {
- pstrcpy (path, ino_list[i].dos_path);
-
- /* promote it for future use */
- array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
- return (path);
- }
- else
- {
- /* If the inode is different then something's changed,
- scrub the entry and start from scratch. */
- ino_list[i].valid = False;
- }
- }
- }
- }
-
-
- /* We don't have the information to hand so rely on traditional methods.
- The very slow getcwd, which spawns a process on some systems, or the
- not quite so bad getwd. */
-
- if (!dos_getwd(s))
- {
- DEBUG(0,("dos_GetWd: dos_getwd call failed, errno %s\n",strerror(errno)));
- return (NULL);
- }
-
- pstrcpy(path,s);
-
- DEBUG(5,("dos_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
-
- /* add it to the cache */
- i = MAX_GETWDCACHE - 1;
- string_set(&ino_list[i].dos_path,s);
- ino_list[i].dev = st.st_dev;
- ino_list[i].inode = st.st_ino;
- ino_list[i].valid = True;
-
- /* put it at the top of the list */
- array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
-
- return (path);
-}
diff --git a/source3/lib/util.c b/source3/lib/util.c
index f2d89eebb7..aced56bc2f 100644
--- a/source3/lib/util.c
+++ b/source3/lib/util.c
@@ -410,137 +410,6 @@ void unix_clean_name(char *s)
trim_string(s,NULL,"/..");
}
-/*******************************************************************
-reduce a file name, removing .. elements and checking that
-it is below dir in the heirachy. This uses dos_GetWd() and so must be run
-on the system that has the referenced file system.
-
-widelinks are allowed if widelinks is true
-********************************************************************/
-
-BOOL reduce_name(char *s,char *dir,BOOL widelinks)
-{
-#ifndef REDUCE_PATHS
- return True;
-#else
- pstring dir2;
- pstring wd;
- pstring base_name;
- pstring newname;
- char *p=NULL;
- BOOL relative = (*s != '/');
-
- *dir2 = *wd = *base_name = *newname = 0;
-
- if (widelinks)
- {
- unix_clean_name(s);
- /* can't have a leading .. */
- if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/'))
- {
- DEBUG(3,("Illegal file name? (%s)\n",s));
- return(False);
- }
-
- if (strlen(s) == 0)
- pstrcpy(s,"./");
-
- return(True);
- }
-
- DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
-
- /* remove any double slashes */
- all_string_sub(s,"//","/",0);
-
- pstrcpy(base_name,s);
- p = strrchr(base_name,'/');
-
- if (!p)
- return(True);
-
- if (!dos_GetWd(wd))
- {
- DEBUG(0,("couldn't getwd for %s %s\n",s,dir));
- return(False);
- }
-
- if (dos_ChDir(dir) != 0)
- {
- DEBUG(0,("couldn't chdir to %s\n",dir));
- return(False);
- }
-
- if (!dos_GetWd(dir2))
- {
- DEBUG(0,("couldn't getwd for %s\n",dir));
- dos_ChDir(wd);
- return(False);
- }
-
- if (p && (p != base_name))
- {
- *p = 0;
- if (strcmp(p+1,".")==0)
- p[1]=0;
- if (strcmp(p+1,"..")==0)
- *p = '/';
- }
-
- if (dos_ChDir(base_name) != 0)
- {
- dos_ChDir(wd);
- DEBUG(3,("couldn't chdir for %s %s basename=%s\n",s,dir,base_name));
- return(False);
- }
-
- if (!dos_GetWd(newname))
- {
- dos_ChDir(wd);
- DEBUG(2,("couldn't get wd for %s %s\n",s,dir2));
- return(False);
- }
-
- if (p && (p != base_name))
- {
- pstrcat(newname,"/");
- pstrcat(newname,p+1);
- }
-
- {
- size_t l = strlen(dir2);
- if (dir2[l-1] == '/')
- l--;
-
- if (strncmp(newname,dir2,l) != 0)
- {
- dos_ChDir(wd);
- DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,(int)l));
- return(False);
- }
-
- if (relative)
- {
- if (newname[l] == '/')
- pstrcpy(s,newname + l + 1);
- else
- pstrcpy(s,newname+l);
- }
- else
- pstrcpy(s,newname);
- }
-
- dos_ChDir(wd);
-
- if (strlen(s) == 0)
- pstrcpy(s,"./");
-
- DEBUG(3,("reduced to %s\n",s));
- return(True);
-#endif
-}
-
-
/****************************************************************************
make a dir struct
****************************************************************************/
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index c03e1025b1..64e5908b19 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -92,7 +92,7 @@ pstring global_scope = "";
#define VALID(i) iSERVICE(i).valid
int keepalive = DEFAULT_KEEPALIVE;
-extern BOOL use_getwd_cache;
+BOOL use_getwd_cache;
extern int extra_time_offset;
diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c
index 8e2382ee9f..269d286517 100644
--- a/source3/smbd/dosmode.c
+++ b/source3/smbd/dosmode.c
@@ -61,7 +61,7 @@ mode_t unix_mode(connection_struct *conn,int dosmode,const char *fname)
dname = parent_dirname(fname);
DEBUG(2,("unix_mode(%s) inheriting from %s\n",fname,dname));
- if (dos_stat(dname,&sbuf) != 0) {
+ if (vfs_stat(conn,dname,&sbuf) != 0) {
DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",fname,dname,strerror(errno)));
return(0); /* *** shouldn't happen! *** */
}
@@ -191,7 +191,7 @@ int file_chmod(connection_struct *conn,char *fname,int dosmode,SMB_STRUCT_STAT *
if (!st) {
st = &st1;
- if (conn->vfs_ops.stat(dos_to_unix(fname,False),st)) return(-1);
+ if (vfs_stat(conn,fname,st)) return(-1);
}
if (S_ISDIR(st->st_mode)) dosmode |= aDIR;
@@ -227,7 +227,7 @@ int file_chmod(connection_struct *conn,char *fname,int dosmode,SMB_STRUCT_STAT *
unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
}
- return(conn->vfs_ops.chmod(dos_to_unix(fname,False),unixmode));
+ return(vfs_chmod(conn,fname,unixmode));
}
@@ -258,7 +258,7 @@ int file_utime(connection_struct *conn, char *fname, struct utimbuf *times)
(as DOS does).
*/
- if(conn->vfs_ops.stat(dos_to_unix(fname,False),&sb) != 0)
+ if(vfs_stat(conn,fname,&sb) != 0)
return -1;
/* Check if we have write access. */
diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 294e80250a..67fa85d9cb 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -419,7 +419,7 @@ BOOL check_name(char *name,connection_struct *conn)
return(0);
}
- ret = reduce_name(name,conn->connectpath,lp_widelinks(SNUM(conn)));
+ ret = reduce_name(conn,name,conn->connectpath,lp_widelinks(SNUM(conn)));
/* Check if we are allowing users to follow symlinks */
/* Patch from David Clerc <David.Clerc@cui.unige.ch>
diff --git a/source3/smbd/notify_hash.c b/source3/smbd/notify_hash.c
index a8cdcea17d..5a2f865310 100644
--- a/source3/smbd/notify_hash.c
+++ b/source3/smbd/notify_hash.c
@@ -51,7 +51,7 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
ZERO_STRUCTP(data);
- if(dos_stat(path, &st) == -1) return False;
+ if(vfs_stat(conn,path, &st) == -1) return False;
data->modify_time = st.st_mtime;
data->status_time = st.st_ctime;
@@ -102,7 +102,7 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
/*
* Do the stat - but ignore errors.
*/
- dos_stat(full_name, &st);
+ vfs_stat(conn,full_name, &st);
data->total_time += (st.st_mtime + st.st_ctime);
}
diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index 59c3c83f6f..4a8260421c 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -732,7 +732,7 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, B
*/
saved_conn = fsp->conn;
saved_vuid = current_user.vuid;
- dos_GetWd(saved_dir);
+ vfs_GetWd(saved_conn,saved_dir);
unbecome_user();
/* Save the chain fnum. */
file_chain_save();
@@ -814,7 +814,7 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, B
exit_server("unable to re-become user");
}
/* Including the directory. */
- dos_ChDir(saved_dir);
+ vfs_ChDir(saved_conn,saved_dir);
/* Restore the chain fnum. */
file_chain_restore();
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 9dd5a9ef68..8624bdb9b4 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -1100,7 +1100,7 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
unix_convert(fname,conn,0,&bad_path,&sbuf);
if (check_name(fname,conn))
{
- if (VALID_STAT(sbuf) || dos_stat(fname,&sbuf) == 0)
+ if (VALID_STAT(sbuf) || vfs_stat(conn,fname,&sbuf) == 0)
{
mode = dos_mode(conn,fname,&sbuf);
size = sbuf.st_size;
diff --git a/source3/smbd/service.c b/source3/smbd/service.c
index 272d54e3ba..e82bbefa5a 100644
--- a/source3/smbd/service.c
+++ b/source3/smbd/service.c
@@ -56,8 +56,8 @@ BOOL become_service(connection_struct *conn,BOOL do_chdir)
snum = SNUM(conn);
if (do_chdir &&
- dos_ChDir(conn->connectpath) != 0 &&
- dos_ChDir(conn->origpath) != 0) {
+ vfs_ChDir(conn,conn->connectpath) != 0 &&
+ vfs_ChDir(conn,conn->origpath) != 0) {
DEBUG(0,("chdir (%s) failed\n",
conn->connectpath));
return(False);
@@ -575,7 +575,7 @@ connection_struct *make_connection(char *service,char *user,char *password, int
return NULL;
}
- if (dos_ChDir(conn->connectpath) != 0) {
+ if (vfs_ChDir(conn,conn->connectpath) != 0) {
DEBUG(0,("Can't change directory to %s (%s)\n",
conn->connectpath,strerror(errno)));
unbecome_user();
@@ -598,9 +598,9 @@ connection_struct *make_connection(char *service,char *user,char *password, int
{
pstring s;
pstrcpy(s,conn->connectpath);
- dos_GetWd(s);
+ vfs_GetWd(conn,s);
string_set(&conn->connectpath,s);
- dos_ChDir(conn->connectpath);
+ vfs_ChDir(conn,conn->connectpath);
}
#endif
diff --git a/source3/smbd/unix_acls.c b/source3/smbd/unix_acls.c
index 7ab448e6a3..48f6163596 100644
--- a/source3/smbd/unix_acls.c
+++ b/source3/smbd/unix_acls.c
@@ -146,8 +146,6 @@ static BOOL unpack_nt_permissions(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *p
DOM_SID grp_sid;
DOM_SID file_owner_sid;
DOM_SID file_grp_sid;
- uint32 owner_rid;
- uint32 grp_rid;
SEC_ACL *dacl = psd->dacl;
BOOL all_aces_are_inherit_only = (is_directory ? True : False);
int i;
@@ -353,7 +351,7 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
} else {
if(fsp->is_directory || fsp->fd == -1) {
- if(dos_stat(fsp->fsp_name, &sbuf) != 0) {
+ if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
return 0;
}
} else {
@@ -458,14 +456,14 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
*/
if(fsp->is_directory) {
- if(dos_stat(fsp->fsp_name, &sbuf) != 0)
+ if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0)
return False;
} else {
int ret;
if(fsp->fd == -1)
- ret = conn->vfs_ops.stat(dos_to_unix(fsp->fsp_name,False), &sbuf);
+ ret = vfs_stat(fsp->conn,fsp->fsp_name,&sbuf);
else
ret = conn->vfs_ops.fstat(fsp->fd,&sbuf);
@@ -492,7 +490,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
DEBUG(3,("call_nt_transact_set_security_desc: chown %s. uid = %u, gid = %u.\n",
fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
- if(dos_chown( fsp->fsp_name, user, grp) == -1) {
+ if(vfs_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
DEBUG(3,("call_nt_transact_set_security_desc: chown %s, %u, %u failed. Error = %s.\n",
fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
return False;
@@ -504,7 +502,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
*/
if(fsp->is_directory) {
- if(dos_stat(fsp->fsp_name, &sbuf) != 0) {
+ if(vfs_stat(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
return False;
}
} else {
@@ -512,7 +510,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
int ret;
if(fsp->fd == -1)
- ret = conn->vfs_ops.stat(dos_to_unix(fsp->fsp_name,False), &sbuf);
+ ret = vfs_stat(fsp->conn, fsp->fsp_name, &sbuf);
else
ret = conn->vfs_ops.fstat(fsp->fd,&sbuf);
diff --git a/source3/smbd/vfs-wrap.c b/source3/smbd/vfs-wrap.c
index 5db1689450..12ba9bda84 100644
--- a/source3/smbd/vfs-wrap.c
+++ b/source3/smbd/vfs-wrap.c
@@ -284,6 +284,42 @@ int vfswrap_chmod(char *path, mode_t mode)
return result;
}
+int vfswrap_chown(char *path, uid_t uid, gid_t gid)
+{
+ int result;
+
+#ifdef VFS_CHECK_NULL
+ if (path == NULL) {
+ smb_panic("NULL pointer passed to vfswrap_chown()\n");
+ }
+#endif
+
+ result = sys_chown(path, uid, gid);
+ return result;
+}
+
+int vfswrap_chdir(char *path)
+{
+#ifdef VFS_CHECK_NULL
+ if (path == NULL) {
+ smb_panic("NULL pointer passed to vfswrap_chdir()\n");
+ }
+#endif
+
+ return chdir(path);
+}
+
+char *vfswrap_getwd(char *path)
+{
+#ifdef VFS_CHECK_NULL
+ if (path == NULL) {
+ smb_panic("NULL pointer passed to vfswrap_getwd()\n");
+ }
+#endif
+
+ return sys_getwd(path);
+}
+
int vfswrap_utime(char *path, struct utimbuf *times)
{
int result;
@@ -310,3 +346,13 @@ BOOL vfswrap_lock(int fd, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
{
return fcntl_lock(fd, op, offset, count,type);
}
+
+#if 0
+size_t vfswrap_get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
+{
+}
+
+BOOL vfswrap_set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
+{
+}
+#endif
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 496d3e0432..631d4bedbe 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -64,9 +64,16 @@ struct vfs_ops default_vfs_ops = {
vfswrap_lstat,
vfswrap_unlink,
vfswrap_chmod,
+ vfswrap_chown,
+ vfswrap_chdir,
+ vfswrap_getwd,
vfswrap_utime,
vfswrap_ftruncate,
- vfswrap_lock
+ vfswrap_lock,
+#if 0
+ vfswrap_get_nt_acl,
+ vfswrap_set_nt_acl
+#endif
};
/****************************************************************************
@@ -208,6 +215,10 @@ BOOL vfs_init_custom(connection_struct *conn)
conn->vfs_ops.chmod = default_vfs_ops.chmod;
}
+ if (conn->vfs_ops.chown == NULL) {
+ conn->vfs_ops.chown = default_vfs_ops.chown;
+ }
+
if (conn->vfs_ops.utime == NULL) {
conn->vfs_ops.utime = default_vfs_ops.utime;
}
@@ -224,20 +235,33 @@ BOOL vfs_init_custom(connection_struct *conn)
}
#endif
-BOOL vfs_directory_exist(connection_struct *conn, char *dname,
- SMB_STRUCT_STAT *st)
+/*******************************************************************
+ vfs stat wrapper that calls dos_to_unix.
+********************************************************************/
+
+int vfs_stat(connection_struct *conn, char *fname, SMB_STRUCT_STAT *st)
{
- SMB_STRUCT_STAT st2;
- BOOL ret;
+ return(conn->vfs_ops.stat(dos_to_unix(fname,False),st));
+}
- if (!st) st = &st2;
+/*******************************************************************
+ Check if directory exists.
+********************************************************************/
- if (conn->vfs_ops.stat(dos_to_unix(dname,False),st) != 0)
- return(False);
+BOOL vfs_directory_exist(connection_struct *conn, char *dname, SMB_STRUCT_STAT *st)
+{
+ SMB_STRUCT_STAT st2;
+ BOOL ret;
+
+ if (!st)
+ st = &st2;
- ret = S_ISDIR(st->st_mode);
- if(!ret)
- errno = ENOTDIR;
+ if (vfs_stat(conn,dname,st) != 0)
+ return(False);
+
+ ret = S_ISDIR(st->st_mode);
+ if(!ret)
+ errno = ENOTDIR;
return ret;
}
@@ -248,26 +272,70 @@ BOOL vfs_directory_exist(connection_struct *conn, char *dname,
int vfs_unlink(connection_struct *conn, char *fname)
{
- return(conn->vfs_ops.unlink(dos_to_unix(fname,False)));
+ return(conn->vfs_ops.unlink(dos_to_unix(fname,False)));
+}
+
+/*******************************************************************
+ vfs chmod wrapper that calls dos_to_unix.
+********************************************************************/
+
+int vfs_chmod(connection_struct *conn, char *fname,mode_t mode)
+{
+ return(conn->vfs_ops.chmod(dos_to_unix(fname,False), mode));
+}
+
+/*******************************************************************
+ vfs chown wrapper that calls dos_to_unix.
+********************************************************************/
+
+int vfs_chown(connection_struct *conn, char *fname, uid_t uid, gid_t gid)
+{
+ return(conn->vfs_ops.chown(dos_to_unix(fname,False), uid, gid));
}
/*******************************************************************
- check if a vfs file exists
+ A wrapper for vfs_chdir().
+********************************************************************/
+
+int vfs_chdir(connection_struct *conn, char *fname)
+{
+ return(conn->vfs_ops.chdir(dos_to_unix(fname,False)));
+}
+
+/*******************************************************************
+ vfs getwd wrapper that calls dos_to_unix.
+********************************************************************/
+
+char *vfs_getwd(connection_struct *conn, char *unix_path)
+{
+ char *wd;
+ wd = conn->vfs_ops.getwd(unix_path);
+ if (wd)
+ unix_to_dos(wd, True);
+ return wd;
+}
+
+/*******************************************************************
+ Check if a vfs file exists.
********************************************************************/
+
BOOL vfs_file_exist(connection_struct *conn,char *fname,SMB_STRUCT_STAT *sbuf)
{
- SMB_STRUCT_STAT st;
- if (!sbuf) sbuf = &st;
-
- if (conn->vfs_ops.stat(dos_to_unix(fname,False),sbuf) != 0)
- return(False);
+ SMB_STRUCT_STAT st;
- return(S_ISREG(sbuf->st_mode));
+ if (!sbuf)
+ sbuf = &st;
+
+ if (vfs_stat(conn,fname,sbuf) != 0)
+ return(False);
+
+ return(S_ISREG(sbuf->st_mode));
}
/****************************************************************************
- write data to a fd on the vfs
+ Write data to a fd on the vfs.
****************************************************************************/
+
ssize_t vfs_write_data(files_struct *fsp,char *buffer,size_t N)
{
size_t total=0;
@@ -286,8 +354,9 @@ ssize_t vfs_write_data(files_struct *fsp,char *buffer,size_t N)
}
/****************************************************************************
-transfer some data between two file_struct's
+ Transfer some data between two file_struct's.
****************************************************************************/
+
SMB_OFF_T vfs_transfer_file(int in_fd, files_struct *in_fsp,
int out_fd, files_struct *out_fsp,
SMB_OFF_T n, char *header, int headlen, int align)
@@ -376,22 +445,26 @@ SMB_OFF_T vfs_transfer_file(int in_fd, files_struct *in_fsp,
}
/*******************************************************************
-a vfs_readdir wrapper which just returns the file name
+ A vfs_readdir wrapper which just returns the file name.
********************************************************************/
+
char *vfs_readdirname(connection_struct *conn, void *p)
{
struct dirent *ptr;
char *dname;
- if (!p) return(NULL);
+ if (!p)
+ return(NULL);
ptr = (struct dirent *)conn->vfs_ops.readdir(p);
- if (!ptr) return(NULL);
+ if (!ptr)
+ return(NULL);
dname = ptr->d_name;
#ifdef NEXT2
- if (telldir(p) < 0) return(NULL);
+ if (telldir(p) < 0)
+ return(NULL);
#endif
#ifdef HAVE_BROKEN_READDIR
@@ -474,3 +547,293 @@ static BOOL handle_vfs_option(char *pszParmValue, char **ptr)
#endif
+
+/*******************************************************************
+ A wrapper for vfs_chdir().
+********************************************************************/
+
+int vfs_ChDir(connection_struct *conn, char *path)
+{
+ int res;
+ static pstring LastDir="";
+
+ if (strcsequal(path,"."))
+ return(0);
+
+ if (*path == '/' && strcsequal(LastDir,path))
+ return(0);
+
+ DEBUG(3,("vfs_ChDir to %s\n",path));
+
+ res = vfs_chdir(conn,path);
+ if (!res)
+ pstrcpy(LastDir,path);
+ return(res);
+}
+
+/* number of list structures for a caching GetWd function. */
+#define MAX_GETWDCACHE (50)
+
+struct
+{
+ SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
+ SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
+ char *dos_path; /* The pathname in DOS format. */
+ BOOL valid;
+} ino_list[MAX_GETWDCACHE];
+
+extern BOOL use_getwd_cache;
+
+/****************************************************************************
+ Prompte a ptr (to make it recently used)
+****************************************************************************/
+
+static void array_promote(char *array,int elsize,int element)
+{
+ char *p;
+ if (element == 0)
+ return;
+
+ p = (char *)malloc(elsize);
+
+ if (!p) {
+ DEBUG(5,("array_promote: malloc fail\n"));
+ return;
+ }
+
+ memcpy(p,array + element * elsize, elsize);
+ memmove(array + elsize,array,elsize*element);
+ memcpy(array,p,elsize);
+ free(p);
+}
+
+/*******************************************************************
+ Return the absolute current directory path - given a UNIX pathname.
+ Note that this path is returned in DOS format, not UNIX
+ format. Note this can be called with conn == NULL.
+********************************************************************/
+
+char *vfs_GetWd(connection_struct *conn, char *path)
+{
+ pstring s;
+ static BOOL getwd_cache_init = False;
+ SMB_STRUCT_STAT st, st2;
+ int i;
+
+ *s = 0;
+
+ if (!use_getwd_cache)
+ return(vfs_getwd(conn,path));
+
+ /* init the cache */
+ if (!getwd_cache_init)
+ {
+ getwd_cache_init = True;
+ for (i=0;i<MAX_GETWDCACHE;i++)
+ {
+ string_set(&ino_list[i].dos_path,"");
+ ino_list[i].valid = False;
+ }
+ }
+
+ /* Get the inode of the current directory, if this doesn't work we're
+ in trouble :-) */
+
+ if (vfs_stat(conn, ".",&st) == -1)
+ {
+ DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path));
+ return(vfs_getwd(conn,path));
+ }
+
+
+ for (i=0; i<MAX_GETWDCACHE; i++)
+ if (ino_list[i].valid)
+ {
+
+ /* If we have found an entry with a matching inode and dev number
+ then find the inode number for the directory in the cached string.
+ If this agrees with that returned by the stat for the current
+ directory then all is o.k. (but make sure it is a directory all
+ the same...) */
+
+ if (st.st_ino == ino_list[i].inode &&
+ st.st_dev == ino_list[i].dev)
+ {
+ if (vfs_stat(conn,ino_list[i].dos_path,&st2) == 0)
+ {
+ if (st.st_ino == st2.st_ino &&
+ st.st_dev == st2.st_dev &&
+ (st2.st_mode & S_IFMT) == S_IFDIR)
+ {
+ pstrcpy (path, ino_list[i].dos_path);
+
+ /* promote it for future use */
+ array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
+ return (path);
+ }
+ else
+ {
+ /* If the inode is different then something's changed,
+ scrub the entry and start from scratch. */
+ ino_list[i].valid = False;
+ }
+ }
+ }
+ }
+
+
+ /* We don't have the information to hand so rely on traditional methods.
+ The very slow getcwd, which spawns a process on some systems, or the
+ not quite so bad getwd. */
+
+ if (!vfs_getwd(conn,s))
+ {
+ DEBUG(0,("vfs_GetWd: vfs_getwd call failed, errno %s\n",strerror(errno)));
+ return (NULL);
+ }
+
+ pstrcpy(path,s);
+
+ DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
+
+ /* add it to the cache */
+ i = MAX_GETWDCACHE - 1;
+ string_set(&ino_list[i].dos_path,s);
+ ino_list[i].dev = st.st_dev;
+ ino_list[i].inode = st.st_ino;
+ ino_list[i].valid = True;
+
+ /* put it at the top of the list */
+ array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
+
+ return (path);
+}
+
+/*******************************************************************
+ Reduce a file name, removing .. elements and checking that
+ it is below dir in the heirachy. This uses vfs_GetWd() and so must be run
+ on the system that has the referenced file system.
+ Widelinks are allowed if widelinks is true.
+********************************************************************/
+
+BOOL reduce_name(connection_struct *conn, char *s,char *dir,BOOL widelinks)
+{
+#ifndef REDUCE_PATHS
+ return True;
+#else
+ pstring dir2;
+ pstring wd;
+ pstring base_name;
+ pstring newname;
+ char *p=NULL;
+ BOOL relative = (*s != '/');
+
+ *dir2 = *wd = *base_name = *newname = 0;
+
+ if (widelinks)
+ {
+ unix_clean_name(s);
+ /* can't have a leading .. */
+ if (strncmp(s,"..",2) == 0 && (s[2]==0 || s[2]=='/'))
+ {
+ DEBUG(3,("Illegal file name? (%s)\n",s));
+ return(False);
+ }
+
+ if (strlen(s) == 0)
+ pstrcpy(s,"./");
+
+ return(True);
+ }
+
+ DEBUG(3,("reduce_name [%s] [%s]\n",s,dir));
+
+ /* remove any double slashes */
+ all_string_sub(s,"//","/",0);
+
+ pstrcpy(base_name,s);
+ p = strrchr(base_name,'/');
+
+ if (!p)
+ return(True);
+
+ if (!vfs_GetWd(conn,wd))
+ {
+ DEBUG(0,("couldn't vfs_GetWd for %s %s\n",s,dir));
+ return(False);
+ }
+
+ if (vfs_ChDir(conn,dir) != 0)
+ {
+ DEBUG(0,("couldn't vfs_ChDir to %s\n",dir));
+ return(False);
+ }
+
+ if (!vfs_GetWd(conn,dir2))
+ {
+ DEBUG(0,("couldn't vfs_GetWd for %s\n",dir));
+ vfs_ChDir(conn,wd);
+ return(False);
+ }
+
+ if (p && (p != base_name))
+ {
+ *p = 0;
+ if (strcmp(p+1,".")==0)
+ p[1]=0;
+ if (strcmp(p+1,"..")==0)
+ *p = '/';
+ }
+
+ if (vfs_ChDir(conn,base_name) != 0)
+ {
+ vfs_ChDir(conn,wd);
+ DEBUG(3,("couldn't vfs_ChDir for %s %s basename=%s\n",s,dir,base_name));
+ return(False);
+ }
+
+ if (!vfs_GetWd(conn,newname))
+ {
+ vfs_ChDir(conn,wd);
+ DEBUG(2,("couldn't get vfs_GetWd for %s %s\n",s,dir2));
+ return(False);
+ }
+
+ if (p && (p != base_name))
+ {
+ pstrcat(newname,"/");
+ pstrcat(newname,p+1);
+ }
+
+ {
+ size_t l = strlen(dir2);
+ if (dir2[l-1] == '/')
+ l--;
+
+ if (strncmp(newname,dir2,l) != 0)
+ {
+ vfs_ChDir(conn,wd);
+ DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n",s,dir2,newname,(int)l));
+ return(False);
+ }
+
+ if (relative)
+ {
+ if (newname[l] == '/')
+ pstrcpy(s,newname + l + 1);
+ else
+ pstrcpy(s,newname+l);
+ }
+ else
+ pstrcpy(s,newname);
+ }
+
+ vfs_ChDir(conn,wd);
+
+ if (strlen(s) == 0)
+ pstrcpy(s,"./");
+
+ DEBUG(3,("reduced to %s\n",s));
+ return(True);
+#endif
+}