diff options
Diffstat (limited to 'source3/smbd/server.c')
-rw-r--r-- | source3/smbd/server.c | 573 |
1 files changed, 16 insertions, 557 deletions
diff --git a/source3/smbd/server.c b/source3/smbd/server.c index ccb830637d..d81d80047b 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -114,188 +114,10 @@ void killkids(void) if(am_parent) kill(0,SIGTERM); } -/**************************************************************************** - change a dos mode to a unix mode - base permission for files: - everybody gets read bit set - dos readonly is represented in unix by removing everyone's write bit - dos archive is represented in unix by the user's execute bit - dos system is represented in unix by the group's execute bit - dos hidden is represented in unix by the other's execute bit - Then apply create mask, - then add force bits. - base permission for directories: - dos directory is represented in unix by unix's dir bit and the exec bit - Then apply create mask, - then add force bits. -****************************************************************************/ -mode_t unix_mode(connection_struct *conn,int dosmode) -{ - mode_t result = (S_IRUSR | S_IRGRP | S_IROTH); - - if ( !IS_DOS_READONLY(dosmode) ) - result |= (S_IWUSR | S_IWGRP | S_IWOTH); - - if (IS_DOS_DIR(dosmode)) { - /* We never make directories read only for the owner as under DOS a user - can always create a file in a read-only directory. */ - result |= (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH | S_IWUSR); - /* Apply directory mask */ - result &= lp_dir_mode(SNUM(conn)); - /* Add in force bits */ - result |= lp_force_dir_mode(SNUM(conn)); - } else { - if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode)) - result |= S_IXUSR; - - if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode)) - result |= S_IXGRP; - - if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode)) - result |= S_IXOTH; - - /* Apply mode mask */ - result &= lp_create_mode(SNUM(conn)); - /* Add in force bits */ - result |= lp_force_create_mode(SNUM(conn)); - } - return(result); -} - - -/**************************************************************************** - change a unix mode to a dos mode -****************************************************************************/ -int dos_mode(connection_struct *conn,char *path,struct stat *sbuf) -{ - int result = 0; - extern struct current_user current_user; - - DEBUG(8,("dos_mode: %s\n", path)); - - if (CAN_WRITE(conn) && !lp_alternate_permissions(SNUM(conn))) { - if (!((sbuf->st_mode & S_IWOTH) || - conn->admin_user || - ((sbuf->st_mode & S_IWUSR) && current_user.uid==sbuf->st_uid) || - ((sbuf->st_mode & S_IWGRP) && - in_group(sbuf->st_gid,current_user.gid, - current_user.ngroups,current_user.groups)))) - result |= aRONLY; - } else { - if ((sbuf->st_mode & S_IWUSR) == 0) - result |= aRONLY; - } - - if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0)) - result |= aARCH; - - if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0)) - result |= aSYSTEM; - - if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0)) - result |= aHIDDEN; - - if (S_ISDIR(sbuf->st_mode)) - result = aDIR | (result & aRONLY); - -#ifdef S_ISLNK -#if LINKS_READ_ONLY - if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode)) - result |= aRONLY; -#endif -#endif - - /* hide files with a name starting with a . */ - if (lp_hide_dot_files(SNUM(conn))) - { - char *p = strrchr(path,'/'); - if (p) - p++; - else - p = path; - - if (p[0] == '.' && p[1] != '.' && p[1] != 0) - result |= aHIDDEN; - } - - /* Optimization : Only call is_hidden_path if it's not already - hidden. */ - if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) - { - result |= aHIDDEN; - } - - DEBUG(8,("dos_mode returning ")); - - if (result & aHIDDEN) DEBUG(8, ("h")); - if (result & aRONLY ) DEBUG(8, ("r")); - if (result & aSYSTEM) DEBUG(8, ("s")); - if (result & aDIR ) DEBUG(8, ("d")); - if (result & aARCH ) DEBUG(8, ("a")); - - DEBUG(8,("\n")); - - return(result); -} - -/******************************************************************* -chmod a file - but preserve some bits -********************************************************************/ -int dos_chmod(connection_struct *conn,char *fname,int dosmode,struct stat *st) -{ - struct stat st1; - int mask=0; - int tmp; - int unixmode; - - if (!st) { - st = &st1; - if (sys_stat(fname,st)) return(-1); - } - - if (S_ISDIR(st->st_mode)) dosmode |= aDIR; - - if (dos_mode(conn,fname,st) == dosmode) return(0); - - unixmode = unix_mode(conn,dosmode); - - /* preserve the s bits */ - mask |= (S_ISUID | S_ISGID); - - /* preserve the t bit */ -#ifdef S_ISVTX - mask |= S_ISVTX; -#endif - - /* possibly preserve the x bits */ - if (!MAP_ARCHIVE(conn)) mask |= S_IXUSR; - if (!MAP_SYSTEM(conn)) mask |= S_IXGRP; - if (!MAP_HIDDEN(conn)) mask |= S_IXOTH; - - unixmode |= (st->st_mode & mask); - - /* if we previously had any r bits set then leave them alone */ - if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) { - unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH); - unixmode |= tmp; - } - - /* if we previously had any w bits set then leave them alone - if the new mode is not rdonly */ - if (!IS_DOS_READONLY(dosmode) && - (tmp = st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))) { - unixmode &= ~(S_IWUSR|S_IWGRP|S_IWOTH); - unixmode |= tmp; - } - - return(sys_chmod(fname,unixmode)); -} - /******************************************************************* Wrapper around sys_utime that possibly allows DOS semantics rather than POSIX. *******************************************************************/ - int file_utime(connection_struct *conn, char *fname, struct utimbuf *times) { extern struct current_user current_user; @@ -343,7 +165,6 @@ int file_utime(connection_struct *conn, char *fname, struct utimbuf *times) /******************************************************************* Change a filetime - possibly allowing DOS semantics. *******************************************************************/ - BOOL set_filetime(connection_struct *conn, char *fname, time_t mtime) { struct utimbuf times; @@ -359,373 +180,6 @@ BOOL set_filetime(connection_struct *conn, char *fname, time_t mtime) return(True); } -/**************************************************************************** -check if two filenames are equal - -this needs to be careful about whether we are case sensitive -****************************************************************************/ -static BOOL fname_equal(char *name1, char *name2) -{ - int l1 = strlen(name1); - int l2 = strlen(name2); - - /* handle filenames ending in a single dot */ - if (l1-l2 == 1 && name1[l1-1] == '.' && lp_strip_dot()) - { - BOOL ret; - name1[l1-1] = 0; - ret = fname_equal(name1,name2); - name1[l1-1] = '.'; - return(ret); - } - - if (l2-l1 == 1 && name2[l2-1] == '.' && lp_strip_dot()) - { - BOOL ret; - name2[l2-1] = 0; - ret = fname_equal(name1,name2); - name2[l2-1] = '.'; - return(ret); - } - - /* now normal filename handling */ - if (case_sensitive) - return(strcmp(name1,name2) == 0); - - return(strequal(name1,name2)); -} - - -/**************************************************************************** -mangle the 2nd name and check if it is then equal to the first name -****************************************************************************/ -static BOOL mangled_equal(char *name1, char *name2) -{ - pstring tmpname; - - if (is_8_3(name2, True)) - return(False); - - pstrcpy(tmpname,name2); - mangle_name_83(tmpname,sizeof(tmpname)); - - return(strequal(name1,tmpname)); -} - - -/**************************************************************************** -scan a directory to find a filename, matching without case sensitivity - -If the name looks like a mangled name then try via the mangling functions -****************************************************************************/ -static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL docache) -{ - void *cur_dir; - char *dname; - BOOL mangled; - pstring name2; - - mangled = is_mangled(name); - - /* handle null paths */ - if (*path == 0) - path = "."; - - if (docache && (dname = DirCacheCheck(path,name,SNUM(conn)))) { - pstrcpy(name, dname); - return(True); - } - - /* - * The incoming name can be mangled, and if we de-mangle it - * here it will not compare correctly against the filename (name2) - * read from the directory and then mangled by the name_map_mangle() - * call. We need to mangle both names or neither. - * (JRA). - */ - if (mangled) - mangled = !check_mangled_cache( name ); - - /* open the directory */ - if (!(cur_dir = OpenDir(conn, path, True))) - { - DEBUG(3,("scan dir didn't open dir [%s]\n",path)); - return(False); - } - - /* now scan for matching names */ - while ((dname = ReadDirName(cur_dir))) - { - if (*dname == '.' && - (strequal(dname,".") || strequal(dname,".."))) - continue; - - pstrcpy(name2,dname); - if (!name_map_mangle(name2,False,SNUM(conn))) continue; - - if ((mangled && mangled_equal(name,name2)) - || fname_equal(name, name2)) - { - /* we've found the file, change it's name and return */ - if (docache) DirCacheAdd(path,name,dname,SNUM(conn)); - pstrcpy(name, dname); - CloseDir(cur_dir); - return(True); - } - } - - CloseDir(cur_dir); - return(False); -} - -/**************************************************************************** -This routine is called to convert names from the dos namespace to unix -namespace. It needs to handle any case conversions, mangling, format -changes etc. - -We assume that we have already done a chdir() to the right "root" directory -for this service. - -The function will return False if some part of the name except for the last -part cannot be resolved - -If the saved_last_component != 0, then the unmodified last component -of the pathname is returned there. This is used in an exceptional -case in reply_mv (so far). If saved_last_component == 0 then nothing -is returned there. - -The bad_path arg is set to True if the filename walk failed. This is -used to pick the correct error code to return between ENOENT and ENOTDIR -as Windows applications depend on ERRbadpath being returned if a component -of a pathname does not exist. -****************************************************************************/ -BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component, BOOL *bad_path) -{ - struct stat st; - char *start, *end; - pstring dirpath; - int saved_errno; - - *dirpath = 0; - *bad_path = False; - - if(saved_last_component) - *saved_last_component = 0; - - /* convert to basic unix format - removing \ chars and cleaning it up */ - unix_format(name); - unix_clean_name(name); - - /* names must be relative to the root of the service - trim any leading /. - also trim trailing /'s */ - trim_string(name,"/","/"); - - /* - * Ensure saved_last_component is valid even if file exists. - */ - if(saved_last_component) { - end = strrchr(name, '/'); - if(end) - pstrcpy(saved_last_component, end + 1); - else - pstrcpy(saved_last_component, name); - } - - if (!case_sensitive && - (!case_preserve || (is_8_3(name, False) && !short_case_preserve))) - strnorm(name); - - /* check if it's a printer file */ - if (conn->printer) - { - if ((! *name) || strchr(name,'/') || !is_8_3(name, True)) - { - char *s; - fstring name2; - slprintf(name2,sizeof(name2)-1,"%.6s.XXXXXX",remote_machine); - /* sanitise the name */ - for (s=name2 ; *s ; s++) - if (!issafe(*s)) *s = '_'; - pstrcpy(name,(char *)mktemp(name2)); - } - return(True); - } - - /* stat the name - if it exists then we are all done! */ - if (sys_stat(name,&st) == 0) - return(True); - - saved_errno = errno; - - DEBUG(5,("unix_convert(%s)\n",name)); - - /* a special case - if we don't have any mangling chars and are case - sensitive then searching won't help */ - if (case_sensitive && !is_mangled(name) && - !lp_strip_dot() && !use_mangled_map && (saved_errno != ENOENT)) - return(False); - - /* now we need to recursively match the name against the real - directory structure */ - - start = name; - while (strncmp(start,"./",2) == 0) - start += 2; - - /* now match each part of the path name separately, trying the names - as is first, then trying to scan the directory for matching names */ - for (;start;start = (end?end+1:(char *)NULL)) - { - /* pinpoint the end of this section of the filename */ - end = strchr(start, '/'); - - /* chop the name at this point */ - if (end) *end = 0; - - if(saved_last_component != 0) - pstrcpy(saved_last_component, end ? end + 1 : start); - - /* check if the name exists up to this point */ - if (sys_stat(name, &st) == 0) - { - /* it exists. it must either be a directory or this must be - the last part of the path for it to be OK */ - if (end && !(st.st_mode & S_IFDIR)) - { - /* an intermediate part of the name isn't a directory */ - DEBUG(5,("Not a dir %s\n",start)); - *end = '/'; - return(False); - } - } - else - { - pstring rest; - - *rest = 0; - - /* remember the rest of the pathname so it can be restored - later */ - if (end) pstrcpy(rest,end+1); - - /* try to find this part of the path in the directory */ - if (strchr(start,'?') || strchr(start,'*') || - !scan_directory(dirpath, start, conn, end?True:False)) - { - if (end) - { - /* an intermediate part of the name can't be found */ - DEBUG(5,("Intermediate not found %s\n",start)); - *end = '/'; - /* We need to return the fact that the intermediate - name resolution failed. This is used to return an - error of ERRbadpath rather than ERRbadfile. Some - Windows applications depend on the difference between - these two errors. - */ - *bad_path = True; - return(False); - } - - /* just the last part of the name doesn't exist */ - /* we may need to strupper() or strlower() it in case - this conversion is being used for file creation - purposes */ - /* if the filename is of mixed case then don't normalise it */ - if (!case_preserve && - (!strhasupper(start) || !strhaslower(start))) - strnorm(start); - - /* check on the mangled stack to see if we can recover the - base of the filename */ - if (is_mangled(start)) - check_mangled_cache( start ); - - DEBUG(5,("New file %s\n",start)); - return(True); - } - - /* restore the rest of the string */ - if (end) - { - pstrcpy(start+strlen(start)+1,rest); - end = start + strlen(start); - } - } - - /* add to the dirpath that we have resolved so far */ - if (*dirpath) pstrcat(dirpath,"/"); - pstrcat(dirpath,start); - - /* restore the / that we wiped out earlier */ - if (end) *end = '/'; - } - - /* the name has been resolved */ - DEBUG(5,("conversion finished %s\n",name)); - return(True); -} - - -/**************************************************************************** -check a filename - possibly caling reducename - -This is called by every routine before it allows an operation on a filename. -It does any final confirmation necessary to ensure that the filename is -a valid one for the user to access. -****************************************************************************/ -BOOL check_name(char *name,connection_struct *conn) -{ - BOOL ret; - - errno = 0; - - if (IS_VETO_PATH(conn, name)) { - DEBUG(5,("file path name %s vetoed\n",name)); - return(0); - } - - ret = reduce_name(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> - University of Geneva */ - -#ifdef S_ISLNK - if (!lp_symlinks(SNUM(conn))) - { - struct stat statbuf; - if ( (sys_lstat(name,&statbuf) != -1) && - (S_ISLNK(statbuf.st_mode)) ) - { - DEBUG(3,("check_name: denied: file path name %s is a symlink\n",name)); - ret=0; - } - } -#endif - - if (!ret) - DEBUG(5,("check_name on %s failed\n",name)); - - return(ret); -} - -/**************************************************************************** -check a filename - possibly caling reducename -****************************************************************************/ -static void check_for_pipe(char *fname) -{ - /* special case of pipe opens */ - char s[10]; - StrnCpy(s,fname,9); - strlower(s); - if (strstr(s,"pipe/")) - { - DEBUG(3,("Rejecting named pipe open for %s\n",fname)); - unix_ERR_class = ERRSRV; - unix_ERR_code = ERRaccess; - } -} /**************************************************************************** fd support routines - attempt to do a sys_open @@ -946,6 +400,22 @@ static BOOL check_access_allowed_for_current_user( char *fname, int accmode ) } /**************************************************************************** +check a filename for the pipe string +****************************************************************************/ +static void check_for_pipe(char *fname) +{ + /* special case of pipe opens */ + char s[10]; + StrnCpy(s,fname,9); + strlower(s); + if (strstr(s,"pipe/")) { + DEBUG(3,("Rejecting named pipe open for %s\n",fname)); + unix_ERR_class = ERRSRV; + unix_ERR_code = ERRaccess; + } +} + +/**************************************************************************** open a file ****************************************************************************/ static void open_file(files_struct *fsp,connection_struct *conn, @@ -1235,17 +705,6 @@ static void open_file(files_struct *fsp,connection_struct *conn, #endif } -/******************************************************************* -sync a file -********************************************************************/ -void sync_file(connection_struct *conn, files_struct *fsp) -{ -#ifdef HAVE_FSYNC - if(lp_strict_sync(SNUM(conn))) - fsync(fsp->fd_ptr->fd); -#endif -} - /**************************************************************************** run a file if it is a magic script ****************************************************************************/ |