diff options
author | Jeremy Allison <jra@samba.org> | 2000-09-27 19:09:59 +0000 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2000-09-27 19:09:59 +0000 |
commit | b43b2e4f8a4be30e3f7aca6f570f5376fd508e3d (patch) | |
tree | 3c604a52b53f0a846fe62b5995becda7facda187 /source3 | |
parent | 8c93ddf3e0ea80d482cbee7bf233c32fc69955bb (diff) | |
download | samba-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.h | 19 | ||||
-rw-r--r-- | source3/include/vfs.h | 7 | ||||
-rw-r--r-- | source3/lib/doscalls.c | 169 | ||||
-rw-r--r-- | source3/lib/util.c | 131 | ||||
-rw-r--r-- | source3/param/loadparm.c | 2 | ||||
-rw-r--r-- | source3/smbd/dosmode.c | 8 | ||||
-rw-r--r-- | source3/smbd/filename.c | 2 | ||||
-rw-r--r-- | source3/smbd/notify_hash.c | 4 | ||||
-rw-r--r-- | source3/smbd/oplock.c | 4 | ||||
-rw-r--r-- | source3/smbd/reply.c | 2 | ||||
-rw-r--r-- | source3/smbd/service.c | 10 | ||||
-rw-r--r-- | source3/smbd/unix_acls.c | 14 | ||||
-rw-r--r-- | source3/smbd/vfs-wrap.c | 46 | ||||
-rw-r--r-- | source3/smbd/vfs.c | 413 |
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 +} |