diff options
author | Gerald Carter <jerry@samba.org> | 2004-05-24 15:24:19 +0000 |
---|---|---|
committer | Gerald Carter <jerry@samba.org> | 2004-05-24 15:24:19 +0000 |
commit | be04052043296dd434bd89c8519d32c44a928984 (patch) | |
tree | 1d1660dd1df57e12fb3ffc1ac2f5221e0fcf9010 /source/smbd | |
parent | 47b01c2f1867f5107fa0b80eba69241a837861da (diff) | |
parent | e9be798ec89f1584ff08047563a3d5c4aedd9615 (diff) | |
download | samba-be04052043296dd434bd89c8519d32c44a928984.tar.gz samba-be04052043296dd434bd89c8519d32c44a928984.tar.xz samba-be04052043296dd434bd89c8519d32c44a928984.zip |
r843: first rounds of sync's for 3.0.5pre1
Diffstat (limited to 'source/smbd')
-rw-r--r-- | source/smbd/conn.c | 1 | ||||
-rw-r--r-- | source/smbd/filename.c | 37 | ||||
-rw-r--r-- | source/smbd/mangle.c | 2 | ||||
-rw-r--r-- | source/smbd/mangle_hash.c | 22 | ||||
-rw-r--r-- | source/smbd/mangle_hash2.c | 2 | ||||
-rw-r--r-- | source/smbd/nttrans.c | 53 | ||||
-rw-r--r-- | source/smbd/open.c | 65 | ||||
-rw-r--r-- | source/smbd/posix_acls.c | 4 | ||||
-rw-r--r-- | source/smbd/process.c | 37 | ||||
-rw-r--r-- | source/smbd/reply.c | 27 | ||||
-rw-r--r-- | source/smbd/server.c | 17 | ||||
-rw-r--r-- | source/smbd/service.c | 48 | ||||
-rw-r--r-- | source/smbd/sesssetup.c | 8 | ||||
-rw-r--r-- | source/smbd/statcache.c | 6 | ||||
-rw-r--r-- | source/smbd/trans2.c | 125 | ||||
-rw-r--r-- | source/smbd/uid.c | 10 | ||||
-rw-r--r-- | source/smbd/vfs.c | 239 |
17 files changed, 343 insertions, 360 deletions
diff --git a/source/smbd/conn.c b/source/smbd/conn.c index 9bac0acdb9f..e083e144263 100644 --- a/source/smbd/conn.c +++ b/source/smbd/conn.c @@ -161,6 +161,7 @@ void conn_close_all(void) connection_struct *conn, *next; for (conn=Connections;conn;conn=next) { next=conn->next; + set_current_service(conn, True); close_cnum(conn, conn->vuid); } } diff --git a/source/smbd/filename.c b/source/smbd/filename.c index 805af9c494a..5e5f5726913 100644 --- a/source/smbd/filename.c +++ b/source/smbd/filename.c @@ -26,11 +26,6 @@ #include "includes.h" -extern BOOL case_sensitive; -extern BOOL case_preserve; -extern BOOL short_case_preserve; -extern BOOL use_mangled_map; - static BOOL scan_directory(const char *path, char *name,size_t maxlength, connection_struct *conn,BOOL docache); @@ -39,7 +34,7 @@ static BOOL scan_directory(const char *path, char *name,size_t maxlength, This needs to be careful about whether we are case sensitive. ****************************************************************************/ -static BOOL fname_equal(const char *name1, const char *name2) +static BOOL fname_equal(const char *name1, const char *name2, BOOL case_sensitive) { /* Normal filename handling */ if (case_sensitive) @@ -137,6 +132,10 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen if (!*name) { name[0] = '.'; name[1] = '\0'; + if (SMB_VFS_STAT(conn,name,&st) == 0) { + *pst = st; + } + DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); return(True); } @@ -152,13 +151,17 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen pstrcpy(saved_last_component, name); } - if (!case_sensitive && (!case_preserve || (mangle_is_8_3(name, False) && !short_case_preserve))) - strnorm(name); +#if 1 + if (!conn->case_preserve || (mangle_is_8_3(name, False) && !conn->short_case_preserve)) +#else + if (!conn->case_sensitive && (!conn->case_preserve || (mangle_is_8_3(name, False) && !conn->short_case_preserve))) +#endif + strnorm(name, lp_defaultcase(SNUM(conn))); start = name; pstrcpy(orig_path, name); - if(!case_sensitive && stat_cache_lookup(conn, name, dirpath, &start, &st)) { + if(!conn->case_sensitive && stat_cache_lookup(conn, name, dirpath, &start, &st)) { *pst = st; return True; } @@ -168,7 +171,7 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen */ if (SMB_VFS_STAT(conn,name,&st) == 0) { - stat_cache_add(orig_path, name); + stat_cache_add(orig_path, name, conn->case_sensitive); DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); *pst = st; return(True); @@ -181,7 +184,7 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen * sensitive then searching won't help. */ - if (case_sensitive && !mangle_is_mangled(name) && !use_mangled_map) + if (conn->case_sensitive && !mangle_is_mangled(name) && !*lp_mangled_map(SNUM(conn))) return(False); name_has_wildcard = ms_has_wild(start); @@ -297,8 +300,8 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen * don't normalise it. */ - if (!case_preserve && (!strhasupper(start) || !strhaslower(start))) - strnorm(start); + if (!conn->case_preserve && (!strhasupper(start) || !strhaslower(start))) + strnorm(start, lp_defaultcase(SNUM(conn))); /* * check on the mangled stack to see if we can recover the @@ -353,7 +356,7 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen */ if(!component_was_mangled && !name_has_wildcard) - stat_cache_add(orig_path, dirpath); + stat_cache_add(orig_path, dirpath, conn->case_sensitive); /* * Restore the / that we wiped out earlier. @@ -368,7 +371,7 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen */ if(!component_was_mangled && !name_has_wildcard) - stat_cache_add(orig_path, name); + stat_cache_add(orig_path, name, conn->case_sensitive); /* * The name has been resolved. @@ -400,7 +403,7 @@ BOOL check_name(pstring name,connection_struct *conn) } if (!lp_widelinks(SNUM(conn))) { - ret = reduce_name(conn,name,conn->connectpath); + ret = reduce_name(conn,name); } /* Check if we are allowing users to follow symlinks */ @@ -482,7 +485,7 @@ static BOOL scan_directory(const char *path, char *name, size_t maxlength, * against unmangled name. */ - if ((mangled && mangled_equal(name,dname,SNUM(conn))) || fname_equal(name, dname)) { + if ((mangled && mangled_equal(name,dname,SNUM(conn))) || fname_equal(name, dname, conn->case_sensitive)) { /* we've found the file, change it's name and return */ if (docache) DirCacheAdd(path,name,dname,SNUM(conn)); diff --git a/source/smbd/mangle.c b/source/smbd/mangle.c index c5d7582c033..b77fe601b69 100644 --- a/source/smbd/mangle.c +++ b/source/smbd/mangle.c @@ -120,5 +120,5 @@ void mangle_map(pstring OutName, BOOL need83, BOOL cache83, int snum) /* invoke the inane "mangled map" code */ mangle_map_filename(OutName, snum); - mangle_fns->name_map(OutName, need83, cache83); + mangle_fns->name_map(OutName, need83, cache83, lp_defaultcase(snum)); } diff --git a/source/smbd/mangle_hash.c b/source/smbd/mangle_hash.c index 16722ae6e9d..7b8cbdbddba 100644 --- a/source/smbd/mangle_hash.c +++ b/source/smbd/mangle_hash.c @@ -51,13 +51,6 @@ /* -------------------------------------------------------------------------- ** - * External Variables... - */ - -extern int case_default; /* Are conforming 8.3 names all upper or lower? */ -extern BOOL case_mangle; /* If true, all chars in 8.3 should be same case. */ - -/* -------------------------------------------------------------------------- ** * Other stuff... * * magic_char - This is the magic char used for mangling. It's @@ -130,13 +123,6 @@ static BOOL mc_initialized = False; #define MANGLED_CACHE_MAX_ENTRIES 1024 #define MANGLED_CACHE_MAX_MEMORY 0 -/* -------------------------------------------------------------------------- ** - * External Variables... - */ - -extern int case_default; /* Are conforming 8.3 names all upper or lower? */ -extern BOOL case_mangle; /* If true, all chars in 8.3 should be same case. */ - /* -------------------------------------------------------------------- */ static NTSTATUS has_valid_83_chars(const smb_ucs2_t *s, BOOL allow_wildcards) @@ -639,7 +625,7 @@ static BOOL check_cache( char *s ) * the buffer must be able to hold 13 characters (including the null) ***************************************************************************** */ -static void to_8_3(char *s) +static void to_8_3(char *s, int default_case) { int csum; char *p; @@ -653,7 +639,7 @@ static void to_8_3(char *s) p = strrchr(s,'.'); if( p && (strlen(p+1) < (size_t)4) ) { - BOOL all_normal = ( strisnormal(p+1) ); /* XXXXXXXXX */ + BOOL all_normal = ( strisnormal(p+1, default_case) ); /* XXXXXXXXX */ if( all_normal && p[1] != 0 ) { *p = 0; @@ -728,7 +714,7 @@ static void to_8_3(char *s) * **************************************************************************** */ -static void name_map(char *OutName, BOOL need83, BOOL cache83) +static void name_map(char *OutName, BOOL need83, BOOL cache83, int default_case) { smb_ucs2_t *OutName_ucs2; DEBUG(5,("name_map( %s, need83 = %s, cache83 = %s)\n", OutName, @@ -750,7 +736,7 @@ static void name_map(char *OutName, BOOL need83, BOOL cache83) if (cache83) tmp = strdup(OutName); - to_8_3(OutName); + to_8_3(OutName, default_case); if(tmp != NULL) { cache_mangled_name(OutName, tmp); diff --git a/source/smbd/mangle_hash2.c b/source/smbd/mangle_hash2.c index 62087e7e593..dcfd7663ba3 100644 --- a/source/smbd/mangle_hash2.c +++ b/source/smbd/mangle_hash2.c @@ -501,7 +501,7 @@ static BOOL is_legal_name(const char *name) the name parameter must be able to hold 13 bytes */ -static void name_map(fstring name, BOOL need83, BOOL cache83) +static void name_map(fstring name, BOOL need83, BOOL cache83, int default_case) { char *dot_p; char lead_chars[7]; diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c index e4ddda104e3..26be4434fdb 100644 --- a/source/smbd/nttrans.c +++ b/source/smbd/nttrans.c @@ -24,9 +24,6 @@ extern int Protocol; extern int smb_read_error; extern int global_oplock_break; -extern BOOL case_sensitive; -extern BOOL case_preserve; -extern BOOL short_case_preserve; extern struct current_user current_user; static const char *known_nt_pipes[] = { @@ -274,33 +271,33 @@ static BOOL saved_short_case_preserve; Save case semantics. ****************************************************************************/ -static void set_posix_case_semantics(uint32 file_attributes) +static void set_posix_case_semantics(connection_struct *conn, uint32 file_attributes) { if(!(file_attributes & FILE_FLAG_POSIX_SEMANTICS)) return; - saved_case_sensitive = case_sensitive; - saved_case_preserve = case_preserve; - saved_short_case_preserve = short_case_preserve; + saved_case_sensitive = conn->case_sensitive; + saved_case_preserve = conn->case_preserve; + saved_short_case_preserve = conn->short_case_preserve; /* Set to POSIX. */ - case_sensitive = True; - case_preserve = True; - short_case_preserve = True; + conn->case_sensitive = True; + conn->case_preserve = True; + conn->short_case_preserve = True; } /**************************************************************************** Restore case semantics. ****************************************************************************/ -static void restore_case_semantics(uint32 file_attributes) +static void restore_case_semantics(connection_struct *conn, uint32 file_attributes) { if(!(file_attributes & FILE_FLAG_POSIX_SEMANTICS)) return; - case_sensitive = saved_case_sensitive; - case_preserve = saved_case_preserve; - short_case_preserve = saved_short_case_preserve; + conn->case_sensitive = saved_case_sensitive; + conn->case_preserve = saved_case_preserve; + conn->short_case_preserve = saved_short_case_preserve; } /**************************************************************************** @@ -762,7 +759,7 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib * Check if POSIX semantics are wanted. */ - set_posix_case_semantics(file_attributes); + set_posix_case_semantics(conn, file_attributes); unix_convert(fname,conn,0,&bad_path,&sbuf); @@ -781,7 +778,7 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, &smb_action); - restore_case_semantics(file_attributes); + restore_case_semantics(conn, file_attributes); if(!fsp) { END_PROFILE(SMBntcreateX); @@ -847,7 +844,7 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib */ if (create_options & FILE_NON_DIRECTORY_FILE) { - restore_case_semantics(file_attributes); + restore_case_semantics(conn, file_attributes); SSVAL(outbuf, smb_flg2, SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES); END_PROFILE(SMBntcreateX); @@ -858,20 +855,20 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, &smb_action); if(!fsp) { - restore_case_semantics(file_attributes); + restore_case_semantics(conn, file_attributes); END_PROFILE(SMBntcreateX); return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); } } else { - restore_case_semantics(file_attributes); + restore_case_semantics(conn, file_attributes); END_PROFILE(SMBntcreateX); return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); } } } - restore_case_semantics(file_attributes); + restore_case_semantics(conn, file_attributes); file_len = sbuf.st_size; fmode = dos_mode(conn,fname,&sbuf); @@ -1285,7 +1282,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o * Check if POSIX semantics are wanted. */ - set_posix_case_semantics(file_attributes); + set_posix_case_semantics(conn, file_attributes); RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); @@ -1313,7 +1310,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, &smb_action); if(!fsp) { - restore_case_semantics(file_attributes); + restore_case_semantics(conn, file_attributes); return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); } @@ -1336,7 +1333,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o */ if (create_options & FILE_NON_DIRECTORY_FILE) { - restore_case_semantics(file_attributes); + restore_case_semantics(conn, file_attributes); SSVAL(outbuf, smb_flg2, SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES); return ERROR_NT(NT_STATUS_FILE_IS_A_DIRECTORY); } @@ -1345,11 +1342,11 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, &smb_action); if(!fsp) { - restore_case_semantics(file_attributes); + restore_case_semantics(conn, file_attributes); return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); } } else { - restore_case_semantics(file_attributes); + restore_case_semantics(conn, file_attributes); return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); } } @@ -1361,7 +1358,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o if (fmode & aDIR) { close_file(fsp,False); - restore_case_semantics(file_attributes); + restore_case_semantics(conn, file_attributes); return ERROR_DOS(ERRDOS,ERRnoaccess); } @@ -1384,11 +1381,11 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o if (sd_len && !NT_STATUS_IS_OK(status = set_sd( fsp, data, sd_len, ALL_SECURITY_INFORMATION))) { close_file(fsp,False); - restore_case_semantics(file_attributes); + restore_case_semantics(conn, file_attributes); return ERROR_NT(status); } - restore_case_semantics(file_attributes); + restore_case_semantics(conn, file_attributes); /* Save the requested allocation size. */ allocation_size = (SMB_BIG_UINT)IVAL(params,12); diff --git a/source/smbd/open.c b/source/smbd/open.c index 8ab5dab6ac9..3b4f50b0656 100644 --- a/source/smbd/open.c +++ b/source/smbd/open.c @@ -242,30 +242,10 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn, return True; } -/**************************************************************************** - C. Hoch 11/22/95 - Helper for open_file_shared. - Truncate a file after checking locking; close file if locked. - **************************************************************************/ - -static int truncate_unless_locked(struct connection_struct *conn, files_struct *fsp) -{ - SMB_BIG_UINT mask = (SMB_BIG_UINT)-1; - - if (is_locked(fsp,fsp->conn,mask,0,WRITE_LOCK,True)){ - errno = EACCES; - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRlock; - unix_ERR_ntstatus = dos_to_ntstatus(ERRDOS, ERRlock); - return -1; - } else { - return SMB_VFS_FTRUNCATE(fsp,fsp->fd,0); - } -} - /******************************************************************* return True if the filename is one of the special executable types ********************************************************************/ + static BOOL is_executable(const char *fname) { if ((fname = strrchr_m(fname,'.'))) { @@ -825,6 +805,25 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_ return print_fsp_open(conn, fname); } + if (desired_access && ((desired_access & ~(SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES))==0) && + ((desired_access & (SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES)) != 0)) { + /* Stat open that doesn't trigger oplock breaks or share mode checks... ! JRA. */ + oplock_request = 0; + fsp = open_file_stat(conn, fname, psbuf); + if (!fsp) + return NULL; + + fsp->desired_access = desired_access; + if (Access) + *Access = DOS_OPEN_RDONLY; + if (paction) + *paction = FILE_WAS_OPENED; + + DEBUG(10,("open_file_shared: stat open for fname = %s share_mode = %x\n", + fname, share_mode )); + return fsp; + } + fsp = file_new(conn); if(!fsp) return NULL; @@ -990,6 +989,13 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", if (fsp_open) fd_close(conn, fsp); file_free(fsp); + /* + * We have detected a sharing violation here + * so return the correct error code + */ + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadshare; + unix_ERR_ntstatus = NT_STATUS_SHARING_VIOLATION; return NULL; } @@ -1057,6 +1063,13 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", unlock_share_entry_fsp(fsp); fd_close(conn,fsp); file_free(fsp); + /* + * We have detected a sharing violation here, so + * return the correct code. + */ + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadshare; + unix_ERR_ntstatus = NT_STATUS_SHARING_VIOLATION; return NULL; } @@ -1095,7 +1108,7 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", /* * We are modifing the file after open - update the stat struct.. */ - if ((truncate_unless_locked(conn,fsp) == -1) || (SMB_VFS_FSTAT(fsp,fsp->fd,psbuf)==-1)) { + if ((SMB_VFS_FTRUNCATE(fsp,fsp->fd,0) == -1) || (SMB_VFS_FSTAT(fsp,fsp->fd,psbuf)==-1)) { unlock_share_entry_fsp(fsp); fd_close(conn,fsp); file_free(fsp); @@ -1433,12 +1446,8 @@ files_struct *open_file_stat(connection_struct *conn, char *fname, SMB_STRUCT_ST */ fsp->mode = psbuf->st_mode; - /* - * Don't store dev or inode, we don't want any iterator - * to see this. - */ - fsp->inode = (SMB_INO_T)0; - fsp->dev = (SMB_DEV_T)0; + fsp->inode = psbuf->st_ino; + fsp->dev = psbuf->st_dev; fsp->size = psbuf->st_size; fsp->vuid = current_user.vuid; fsp->file_pid = global_smbpid; diff --git a/source/smbd/posix_acls.c b/source/smbd/posix_acls.c index 158f1a0ede8..584164e9309 100644 --- a/source/smbd/posix_acls.c +++ b/source/smbd/posix_acls.c @@ -2110,8 +2110,10 @@ static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_ * entries out of the blue when setting ACLs, so a get/set * cycle will drop them. */ - if (the_acl_type == SMB_ACL_TYPE_ACCESS && *puid == psbuf->st_uid) + if (the_acl_type == SMB_ACL_TYPE_ACCESS && *puid == psbuf->st_uid) { + SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype); continue; + } uid_to_sid( &sid, *puid); unix_ug.uid = *puid; owner_type = UID_ACE; diff --git a/source/smbd/process.c b/source/smbd/process.c index 966bb63c1ea..12fd809b784 100644 --- a/source/smbd/process.c +++ b/source/smbd/process.c @@ -344,6 +344,7 @@ force write permissions on print services. #define CAN_IPC (1<<3) #define AS_GUEST (1<<5) #define QUEUE_IN_OPLOCK (1<<6) +#define DO_CHDIR (1<<7) /* define a list of possible SMB messages and their corresponding @@ -373,7 +374,7 @@ static const struct smb_message_struct { /* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER | QUEUE_IN_OPLOCK }, /* 0x0f */ { "SMBmknew",reply_mknew,AS_USER}, /* 0x10 */ { "SMBchkpth",reply_chkpth,AS_USER}, -/* 0x11 */ { "SMBexit",reply_exit,0}, +/* 0x11 */ { "SMBexit",reply_exit,DO_CHDIR}, /* 0x12 */ { "SMBlseek",reply_lseek,AS_USER}, /* 0x13 */ { "SMBlockread",reply_lockread,AS_USER}, /* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER}, @@ -469,7 +470,7 @@ static const struct smb_message_struct { /* 0x6e */ { NULL, NULL, 0 }, /* 0x6f */ { NULL, NULL, 0 }, /* 0x70 */ { "SMBtcon",reply_tcon,0}, -/* 0x71 */ { "SMBtdis",reply_tdis,0}, +/* 0x71 */ { "SMBtdis",reply_tdis,DO_CHDIR}, /* 0x72 */ { "SMBnegprot",reply_negprot,0}, /* 0x73 */ { "SMBsesssetupX",reply_sesssetup_and_X,0}, /* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */ @@ -682,7 +683,7 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize uint16 session_tag = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(inbuf,smb_uid); connection_struct *conn = conn_find(SVAL(inbuf,smb_tid)); - DEBUG(3,("switch message %s (pid %d)\n",smb_fn_name(type),(int)pid)); + DEBUG(3,("switch message %s (pid %d) conn 0x%x\n",smb_fn_name(type),(int)pid,(unsigned int)conn)); smb_dump(smb_fn_name(type), 1, inbuf, size); if(global_oplock_break) { @@ -754,7 +755,7 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize return(ERROR_DOS(ERRSRV,ERRaccess)); /* load service specific parameters */ - if (conn && !set_current_service(conn,(flags & AS_USER)?True:False)) + if (conn && !set_current_service(conn,(flags & (AS_USER|DO_CHDIR)?True:False))) return(ERROR_DOS(ERRSRV,ERRaccess)); /* does this protocol need to be run as guest? */ @@ -1077,15 +1078,41 @@ static int setup_select_timeout(void) void check_reload(int t) { static time_t last_smb_conf_reload_time = 0; + static time_t last_load_printers_reload_time = 0; + time_t printcap_cache_time = (time_t)lp_printcap_cache_time(); - if(last_smb_conf_reload_time == 0) + if(last_smb_conf_reload_time == 0) { last_smb_conf_reload_time = t; + /* Our printing subsystem might not be ready at smbd start up. + Then no printer is available till the first printers check + is performed. A lower initial interval circumvents this. */ + if ( printcap_cache_time > 60 ) + last_load_printers_reload_time = t - printcap_cache_time + 60; + else + last_load_printers_reload_time = t; + } if (reload_after_sighup || (t >= last_smb_conf_reload_time+SMBD_RELOAD_CHECK)) { reload_services(True); reload_after_sighup = False; last_smb_conf_reload_time = t; } + + /* 'printcap cache time = 0' disable the feature */ + + if ( printcap_cache_time != 0 ) + { + /* see if it's time to reload or if the clock has been set back */ + + if ( (t >= last_load_printers_reload_time+printcap_cache_time) + || (t-last_load_printers_reload_time < 0) ) + { + DEBUG( 3,( "Printcap cache time expired.\n")); + remove_stale_printers(); + load_printers(); + last_load_printers_reload_time = t; + } + } } /**************************************************************************** diff --git a/source/smbd/reply.c b/source/smbd/reply.c index ac239c7e042..560208ae157 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -31,9 +31,6 @@ extern int Protocol; extern int max_send; extern int max_recv; extern char magic_char; -extern BOOL case_sensitive; -extern BOOL case_preserve; -extern BOOL short_case_preserve; extern int global_oplock_break; unsigned int smb_echo_count = 0; @@ -492,7 +489,9 @@ int reply_ioctl(connection_struct *conn, } SSVAL(p,0,fsp->rap_print_jobid); /* Job number */ srvstr_push(outbuf, p+2, global_myname(), 15, STR_TERMINATE|STR_ASCII); - srvstr_push(outbuf, p+18, lp_servicename(SNUM(conn)), 13, STR_TERMINATE|STR_ASCII); + if (conn) { + srvstr_push(outbuf, p+18, lp_servicename(SNUM(conn)), 13, STR_TERMINATE|STR_ASCII); + } break; } } @@ -881,7 +880,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size if (ok) { if ((dirtype&0x1F) == aVOLID) { memcpy(p,status,21); - make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0); + make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0,conn->case_sensitive); dptr_fill(p+12,dptr_num); if (dptr_zero(p+12) && (status_len==0)) numentries = 1; @@ -901,7 +900,7 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size finished = !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend); if (!finished) { memcpy(p,status,21); - make_dir_struct(p,mask,fname,size,mode,date); + make_dir_struct(p,mask,fname,size,mode,date,conn->case_sensitive); dptr_fill(p+12,dptr_num); numentries++; } @@ -1570,7 +1569,7 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name) } } - if(!mask_match(fname, mask, case_sensitive)) + if(!mask_match(fname, mask, conn->case_sensitive)) continue; if (sys_direntry) { @@ -3515,7 +3514,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char * * filename). */ - if((case_sensitive == False) && (case_preserve == True) && + if((conn->case_sensitive == False) && (conn->case_preserve == True) && strequal(newname, fsp->fsp_name)) { char *p; pstring newname_modified_last_component; @@ -3689,7 +3688,7 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, ui DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, \ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", - case_sensitive, case_preserve, short_case_preserve, directory, + conn->case_sensitive, conn->case_preserve, conn->short_case_preserve, directory, newname, last_component_dest, is_short_name)); /* @@ -3700,10 +3699,10 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", * the rename (user is trying to change the case of the * filename). */ - if((case_sensitive == False) && - (((case_preserve == True) && + if((conn->case_sensitive == False) && + (((conn->case_preserve == True) && (is_short_name == False)) || - ((short_case_preserve == True) && + ((conn->short_case_preserve == True) && (is_short_name == True))) && strcsequal(directory, newname)) { pstring modified_last_component; @@ -3839,7 +3838,7 @@ directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n", } } - if(!mask_match(fname, mask, case_sensitive)) + if(!mask_match(fname, mask, conn->case_sensitive)) continue; if (sysdir_entry) { @@ -4172,7 +4171,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, pstring fname; pstrcpy(fname,dname); - if(!mask_match(fname, mask, case_sensitive)) + if(!mask_match(fname, mask, conn->case_sensitive)) continue; error = ERRnoaccess; diff --git a/source/smbd/server.c b/source/smbd/server.c index 53d07fd905c..343a835be8a 100644 --- a/source/smbd/server.c +++ b/source/smbd/server.c @@ -545,6 +545,10 @@ static BOOL dump_core(void) DEBUG(0,("Dumping core in %s\n", dname)); + /* Ensure we don't have a signal handler for abort. */ +#ifdef SIGABRT + CatchSignal(SIGABRT,SIGNAL_CAST SIG_DFL); +#endif abort(); return(True); } @@ -845,12 +849,13 @@ void build_options(BOOL screen); /* Setup the main smbd so that we can get messages. */ claim_connection(NULL,"",0,True,FLAG_MSG_GENERAL|FLAG_MSG_SMBD); - /* - DO NOT ENABLE THIS TILL YOU COPE WITH KILLING THESE TASKS AND INETD - THIS *killed* LOTS OF BUILD FARM MACHINES. IT CREATED HUNDREDS OF - smbd PROCESSES THAT NEVER DIE - start_background_queue(); - */ + /* only start the background queue daemon if we are + running as a daemon -- bad things will happen if + smbd is launched via inetd and we fork a copy of + ourselves here */ + + if ( is_daemon ) + start_background_queue(); if (!open_sockets_smbd(is_daemon, interactive, ports)) exit(1); diff --git a/source/smbd/service.c b/source/smbd/service.c index 08b66482496..c74537c299e 100644 --- a/source/smbd/service.c +++ b/source/smbd/service.c @@ -21,12 +21,6 @@ #include "includes.h" extern struct timeval smb_last_time; -extern int case_default; -extern BOOL case_preserve; -extern BOOL short_case_preserve; -extern BOOL case_mangle; -extern BOOL case_sensitive; -extern BOOL use_mangled_map; extern userdom_struct current_user_info; @@ -62,13 +56,7 @@ BOOL set_current_service(connection_struct *conn,BOOL do_chdir) last_conn = conn; - case_default = lp_defaultcase(snum); - case_preserve = lp_preservecase(snum); - short_case_preserve = lp_shortpreservecase(snum); - case_mangle = lp_casemangle(snum); - case_sensitive = lp_casesensitive(snum); magic_char = lp_magicchar(snum); - use_mangled_map = (*lp_mangled_map(snum) ? True:False); return(True); } @@ -357,6 +345,12 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, conn->printer = (strncmp(dev,"LPT",3) == 0); conn->ipc = ((strncmp(dev,"IPC",3) == 0) || strequal(dev,"ADMIN$")); conn->dirptr = NULL; + + /* Case options for the share. */ + conn->case_sensitive = lp_casesensitive(snum); + conn->case_preserve = lp_preservecase(snum); + conn->short_case_preserve = lp_shortpreservecase(snum); + conn->veto_list = NULL; conn->hide_list = NULL; conn->veto_oplock_list = NULL; @@ -794,6 +788,9 @@ void close_cnum(connection_struct *conn, uint16 vuid) { DirCacheFlush(SNUM(conn)); + file_close_conn(conn); + dptr_closecnum(conn); + change_to_root_user(); DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n", @@ -805,9 +802,6 @@ void close_cnum(connection_struct *conn, uint16 vuid) yield_connection(conn, lp_servicename(SNUM(conn))); - file_close_conn(conn); - dptr_closecnum(conn); - /* make sure we leave the directory available for unmount */ vfs_ChDir(conn, "/"); @@ -832,3 +826,27 @@ void close_cnum(connection_struct *conn, uint16 vuid) conn_free(conn); } + +/**************************************************************************** + Remove stale printers +****************************************************************************/ + +void remove_stale_printers( void ) +{ + int snum, iNumServices, printersServiceNum; + const char *pname; + + iNumServices = lp_numservices(); + printersServiceNum = lp_servicenumber( PRINTERS_NAME); + for( snum = 0; snum < iNumServices; snum++) { + /* Never remove PRINTERS_NAME */ + if ( snum == printersServiceNum) + continue; + pname = lp_printername( snum); + /* Is snum a print service and still in the printing subsystem? */ + if ( lp_print_ok( snum) && !pcap_printername_ok( pname, NULL)) { + DEBUG( 3, ( "Removing printer: %s\n", pname)); + lp_killservice( snum); + } + } +} diff --git a/source/smbd/sesssetup.c b/source/smbd/sesssetup.c index 902db2d2886..8a56478929f 100644 --- a/source/smbd/sesssetup.c +++ b/source/smbd/sesssetup.c @@ -150,7 +150,7 @@ static int reply_spnego_kerberos(connection_struct *conn, DATA_BLOB auth_data; DATA_BLOB ap_rep, ap_rep_wrapped, response; auth_serversupplied_info *server_info = NULL; - DATA_BLOB session_key; + DATA_BLOB session_key = data_blob(NULL, 0); uint8 tok_id[2]; BOOL foreign = False; DATA_BLOB nullblob = data_blob(NULL, 0); @@ -183,6 +183,7 @@ static int reply_spnego_kerberos(connection_struct *conn, if (!p) { DEBUG(3,("Doesn't look like a valid principal\n")); data_blob_free(&ap_rep); + data_blob_free(&session_key); SAFE_FREE(client); return ERROR_NT(NT_STATUS_LOGON_FAILURE); } @@ -192,6 +193,7 @@ static int reply_spnego_kerberos(connection_struct *conn, DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1)); if (!lp_allow_trusted_domains()) { data_blob_free(&ap_rep); + data_blob_free(&session_key); SAFE_FREE(client); return ERROR_NT(NT_STATUS_LOGON_FAILURE); } @@ -249,6 +251,7 @@ static int reply_spnego_kerberos(connection_struct *conn, SAFE_FREE(user); SAFE_FREE(client); data_blob_free(&ap_rep); + data_blob_free(&session_key); return ERROR_NT(NT_STATUS_LOGON_FAILURE); } @@ -263,6 +266,7 @@ static int reply_spnego_kerberos(connection_struct *conn, SAFE_FREE(user); SAFE_FREE(client); data_blob_free(&ap_rep); + data_blob_free(&session_key); return ERROR_NT(ret); } @@ -274,6 +278,8 @@ static int reply_spnego_kerberos(connection_struct *conn, } /* register_vuid keeps the server info */ + /* register_vuid takes ownership of session_key, no need to free after this. + A better interface would copy it.... */ sess_vuid = register_vuid(server_info, session_key, nullblob, client); SAFE_FREE(user); diff --git a/source/smbd/statcache.c b/source/smbd/statcache.c index d996f5e4938..5e78e9a4999 100644 --- a/source/smbd/statcache.c +++ b/source/smbd/statcache.c @@ -22,8 +22,6 @@ #include "includes.h" -extern BOOL case_sensitive; - /**************************************************************************** Stat cache code used in unix_convert. *****************************************************************************/ @@ -50,7 +48,7 @@ static hash_table stat_cache; * */ -void stat_cache_add( const char *full_orig_name, const char *orig_translated_path) +void stat_cache_add( const char *full_orig_name, const char *orig_translated_path, BOOL case_sensitive) { stat_cache_entry *scp; stat_cache_entry *found_scp; @@ -222,7 +220,7 @@ BOOL stat_cache_lookup(connection_struct *conn, pstring name, pstring dirpath, (name[1] == '.' && name[1] == '\0')))) return False; - if (case_sensitive) { + if (conn->case_sensitive) { chk_name = strdup(name); if (!chk_name) { DEBUG(0, ("stat_cache_lookup: strdup failed!\n")); diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index 0c6026392c4..738d12e020f 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -24,7 +24,6 @@ #include "includes.h" extern int Protocol; -extern BOOL case_sensitive; extern int smb_read_error; extern fstring local_machine; extern int global_oplock_break; @@ -883,8 +882,8 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, pstrcpy(fname,dname); - if(!(got_match = *got_exact_match = exact_match(fname, mask, case_sensitive))) - got_match = mask_match(fname, mask, case_sensitive); + if(!(got_match = *got_exact_match = exact_match(fname, mask, conn->case_sensitive))) + got_match = mask_match(fname, mask, conn->case_sensitive); if(!got_match && !mangle_is_8_3(fname, False)) { @@ -898,8 +897,8 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, pstring newname; pstrcpy( newname, fname); mangle_map( newname, True, False, SNUM(conn)); - if(!(got_match = *got_exact_match = exact_match(newname, mask, case_sensitive))) - got_match = mask_match(newname, mask, case_sensitive); + if(!(got_match = *got_exact_match = exact_match(newname, mask, conn->case_sensitive))) + got_match = mask_match(newname, mask, conn->case_sensitive); } if(got_match) { @@ -1433,7 +1432,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", a different TRANS2 call. */ DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", conn->dirpath,lp_dontdescend(SNUM(conn)))); - if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive)) + if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),conn->case_sensitive)) dont_descend = True; p = pdata; @@ -1633,7 +1632,7 @@ resume_key = %d resume name = %s continue=%d level = %d\n", a different TRANS2 call. */ DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",conn->dirpath,lp_dontdescend(SNUM(conn)))); - if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),case_sensitive)) + if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),conn->case_sensitive)) dont_descend = True; p = pdata; @@ -2303,7 +2302,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); } - delete_pending = fsp->directory_delete_on_close; + delete_pending = fsp->is_directory ? fsp->directory_delete_on_close : 0; } else { /* * Original code - this is an open file. @@ -2401,7 +2400,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, if (lp_dos_filetime_resolution(SNUM(conn))) { c_time &= ~1; sbuf.st_atime &= ~1; - sbuf.st_mtime &= ~1; + sbuf.st_ctime &= ~1; sbuf.st_mtime &= ~1; } @@ -2863,66 +2862,6 @@ NTSTATUS set_delete_on_close_over_all(files_struct *fsp, BOOL delete_on_close) } /**************************************************************************** - Returns true if this pathname is within the share, and thus safe. -****************************************************************************/ - -static int ensure_link_is_safe(connection_struct *conn, const char *link_dest_in, char *link_dest_out) -{ -#ifdef PATH_MAX - char resolved_name[PATH_MAX+1]; -#else - pstring resolved_name; -#endif - fstring last_component; - pstring link_dest; - pstring link_test; - char *p; - BOOL bad_path = False; - SMB_STRUCT_STAT sbuf; - - pstrcpy(link_dest, link_dest_in); - unix_convert(link_dest,conn,0,&bad_path,&sbuf); - - /* Store the UNIX converted path. */ - pstrcpy(link_dest_out, link_dest); - - p = strrchr(link_dest, '/'); - if (p) { - fstrcpy(last_component, p+1); - *p = '\0'; - } else { - fstrcpy(last_component, link_dest); - pstrcpy(link_dest, "./"); - } - - if (SMB_VFS_REALPATH(conn,link_dest,resolved_name) == NULL) - return -1; - - pstrcpy(link_dest, resolved_name); - pstrcat(link_dest, "/"); - pstrcat(link_dest, last_component); - - if (*link_dest != '/') { - /* Relative path. */ - pstrcpy(link_test, conn->connectpath); - pstrcat(link_test, "/"); - pstrcat(link_test, link_dest); - } else { - pstrcpy(link_test, link_dest); - } - - /* - * Check if the link is within the share. - */ - - if (strncmp(conn->connectpath, link_test, strlen(conn->connectpath))) { - errno = EACCES; - return -1; - } - return 0; -} - -/**************************************************************************** Set a hard link (called by UNIX extensions and by NT rename with HARD link code. ****************************************************************************/ @@ -2962,6 +2901,10 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam return NT_STATUS_OBJECT_NAME_NOT_FOUND; } + if (!check_name(oldname,conn)) { + return NT_STATUS_ACCESS_DENIED; + } + rcdest = unix_convert(newname,conn,last_component_newname,&bad_path_newname,&sbuf2); if (!rcdest && bad_path_newname) { return NT_STATUS_OBJECT_PATH_NOT_FOUND; @@ -2979,12 +2922,17 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam return NT_STATUS_OBJECT_NAME_COLLISION; } + if (!check_name(newname,conn)) { + return NT_STATUS_ACCESS_DENIED; + } + /* No links from a directory. */ if (S_ISDIR(sbuf1.st_mode)) { return NT_STATUS_FILE_IS_A_DIRECTORY; } - if (ensure_link_is_safe(conn, oldname, oldname) != 0) + /* Ensure this is within the share. */ + if (!reduce_name(conn, oldname) != 0) return NT_STATUS_ACCESS_DENIED; DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n", newname, oldname )); @@ -3482,7 +3430,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", case SMB_SET_FILE_UNIX_LINK: { - pstring oldname; + pstring link_target; char *newname = fname; /* Set a symbolic link. */ @@ -3491,18 +3439,37 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", if (!lp_symlinks(SNUM(conn))) return(ERROR_DOS(ERRDOS,ERRnoaccess)); - srvstr_get_path(inbuf, oldname, pdata, sizeof(oldname), -1, STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - return ERROR_NT(status); - } + srvstr_pull(inbuf, link_target, pdata, sizeof(link_target), -1, STR_TERMINATE); - if (ensure_link_is_safe(conn, oldname, oldname) != 0) - return(UNIXERROR(ERRDOS,ERRnoaccess)); + /* !widelinks forces the target path to be within the share. */ + /* This means we can interpret the target as a pathname. */ + if (!lp_widelinks(SNUM(conn))) { + pstring rel_name; + char *last_dirp = NULL; + + unix_format(link_target); + if (*link_target == '/') { + /* No absolute paths allowed. */ + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + pstrcpy(rel_name, newname); + last_dirp = strrchr_m(rel_name, '/'); + if (last_dirp) { + last_dirp[1] = '\0'; + } else { + pstrcpy(rel_name, "./"); + } + pstrcat(rel_name, link_target); + + if (!check_name(rel_name, conn)) { + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } + } DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n", - fname, oldname )); + fname, link_target )); - if (SMB_VFS_SYMLINK(conn,oldname,newname) != 0) + if (SMB_VFS_SYMLINK(conn,link_target,newname) != 0) return(UNIXERROR(ERRDOS,ERRnoaccess)); SSVAL(params,0,0); send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); diff --git a/source/smbd/uid.c b/source/smbd/uid.c index 3859298055b..e1864c74caa 100644 --- a/source/smbd/uid.c +++ b/source/smbd/uid.c @@ -189,20 +189,26 @@ BOOL change_to_user(connection_struct *conn, uint16 vuid) snum = SNUM(conn); + if ((vuser) && !check_user_ok(conn, vuser, snum)) { + DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) not permitted access to share %s.\n", + vuser->user.smb_name, vuser->user.unix_name, vuid, lp_servicename(snum))); + return False; + } + if (conn->force_user) /* security = share sets this too */ { uid = conn->uid; gid = conn->gid; current_user.groups = conn->groups; current_user.ngroups = conn->ngroups; token = conn->nt_user_token; - } else if ((vuser) && check_user_ok(conn, vuser, snum)) { + } else if (vuser) { uid = conn->admin_user ? 0 : vuser->uid; gid = vuser->gid; current_user.ngroups = vuser->n_groups; current_user.groups = vuser->groups; token = vuser->nt_user_token; } else { - DEBUG(2,("change_to_user: Invalid vuid used %d or vuid not permitted access to share.\n",vuid)); + DEBUG(2,("change_to_user: Invalid vuid used %d in accessing share %s.\n",vuid, lp_servicename(snum) )); return False; } diff --git a/source/smbd/vfs.c b/source/smbd/vfs.c index 533220e7dfb..a415e0470e2 100644 --- a/source/smbd/vfs.c +++ b/source/smbd/vfs.c @@ -784,168 +784,127 @@ char *vfs_GetWd(connection_struct *conn, char *path) return (path); } - -/* check if the file 'nmae' is a symlink, in that case check that it point to - a file that reside under the 'dir' tree */ - -static BOOL readlink_check(connection_struct *conn, const char *dir, char *name) -{ - BOOL ret = True; - pstring flink; - pstring cleanlink; - pstring savedir; - pstring realdir; - size_t reallen; - - if (!vfs_GetWd(conn, savedir)) { - DEBUG(0,("couldn't vfs_GetWd for %s %s\n", name, 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, realdir)) { - DEBUG(0,("couldn't vfs_GetWd for %s\n", dir)); - vfs_ChDir(conn, savedir); - return(False); - } - - reallen = strlen(realdir); - if (realdir[reallen -1] == '/') { - reallen--; - realdir[reallen] = 0; - } - - if (SMB_VFS_READLINK(conn, name, flink, sizeof(pstring) -1) != -1) { - DEBUG(3,("readlink_check: file path name %s is a symlink\nChecking it's path\n", name)); - if (*flink == '/') { - pstrcpy(cleanlink, flink); - } else { - pstrcpy(cleanlink, realdir); - pstrcat(cleanlink, "/"); - pstrcat(cleanlink, flink); - } - unix_clean_name(cleanlink); - - if (strncmp(cleanlink, realdir, reallen) != 0) { - DEBUG(2,("Bad access attempt? s=%s dir=%s newname=%s l=%d\n", name, realdir, cleanlink, (int)reallen)); - ret = False; - } - } - - vfs_ChDir(conn, savedir); - - return ret; -} - /******************************************************************* 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. + it is below dir in the heirachy. This uses realpath. ********************************************************************/ -BOOL reduce_name(connection_struct *conn, pstring s, const char *dir) +BOOL reduce_name(connection_struct *conn, pstring fname) { -#ifndef REDUCE_PATHS - return True; +#ifdef REALPATH_TAKES_NULL + BOOL free_resolved_name = True; #else - pstring dir2; - pstring wd; - pstring base_name; - pstring newname; - char *p=NULL; - BOOL relative = (*s != '/'); - - *dir2 = *wd = *base_name = *newname = 0; - - DEBUG(3,("reduce_name [%s] [%s]\n",s,dir)); - - /* We know there are no double slashes as this comes from srvstr_get_path(). - and has gone through check_path_syntax(). JRA */ +#ifdef PATH_MAX + char resolved_name_buf[PATH_MAX+1]; +#else + pstring resolved_name_buf; +#endif + BOOL free_resolved_name = False; +#endif + char *resolved_name = NULL; + size_t con_path_len = strlen(conn->connectpath); + char *p = NULL; - pstrcpy(base_name,s); - p = strrchr_m(base_name,'/'); + DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath)); - if (!p) - return readlink_check(conn, dir, s); +#ifdef REALPATH_TAKES_NULL + resolved_name = SMB_VFS_REALPATH(conn,fname,NULL); +#else + resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf); +#endif - if (!vfs_GetWd(conn,wd)) { - DEBUG(0,("couldn't vfs_GetWd for %s %s\n",s,dir)); - return(False); - } + if (!resolved_name) { + switch (errno) { + case ENOTDIR: + DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname)); + return False; + case ENOENT: + { + pstring tmp_fname; + fstring last_component; + /* Last component didn't exist. Remove it and try and canonicalise the directory. */ + + pstrcpy(tmp_fname, fname); + p = strrchr_m(tmp_fname, '/'); + if (p) { + *p++ = '\0'; + fstrcpy(last_component, p); + } else { + fstrcpy(last_component, tmp_fname); + pstrcpy(tmp_fname, "."); + } - if (vfs_ChDir(conn,dir) != 0) { - DEBUG(0,("couldn't vfs_ChDir to %s\n",dir)); - return(False); +#ifdef REALPATH_TAKES_NULL + resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL); +#else + resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf); +#endif + if (!resolved_name) { + DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname)); + return False; + } + pstrcpy(tmp_fname, resolved_name); + pstrcat(tmp_fname, "/"); + pstrcat(tmp_fname, last_component); +#ifdef REALPATH_TAKES_NULL + SAFE_FREE(resolved_name); + resolved_name = strdup(tmp_fname); + if (!resolved_name) { + DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname)); + return False; + } +#else +#ifdef PATH_MAX + safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX); +#else + pstrcpy(pstring resolved_name_buf, tmp_fname); +#endif + resolved_name = resolved_name_buf; +#endif + break; + } + default: + DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname)); + return False; + } } - if (!vfs_GetWd(conn,dir2)) { - DEBUG(0,("couldn't vfs_GetWd for %s\n",dir)); - vfs_ChDir(conn,wd); - return(False); - } + DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name)); - if (p && (p != base_name)) { - *p = 0; - if (strcmp(p+1,".")==0) - p[1]=0; - if (strcmp(p+1,"..")==0) - *p = '/'; + if (*resolved_name != '/') { + DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n")); + if (free_resolved_name) + SAFE_FREE(resolved_name); + return False; } - 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 (strncmp(conn->connectpath, resolved_name, con_path_len) != 0) { + DEBUG(2, ("reduce_name: Bad access attemt: %s is a symlink outside the share path", fname)); + if (free_resolved_name) + SAFE_FREE(resolved_name); + return False; } - if (!vfs_GetWd(conn,newname)) { - vfs_ChDir(conn,wd); - DEBUG(2,("couldn't get vfs_GetWd for %s %s\n",s,base_name)); - return(False); + /* Move path the connect path to the last part of the filename. */ + p = resolved_name + con_path_len; + if (*p == '/') { + p++; } - if (p && (p != base_name)) { - pstrcat(newname,"/"); - pstrcat(newname,p+1); + if (!*p) { + pstrcpy(resolved_name, "."); + p = resolved_name; } - { - size_t l = strlen(dir2); - char *last_slash = strrchr_m(dir2, '/'); - - if (last_slash && (last_slash[1] == '\0')) - 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 (!readlink_check(conn, dir, newname)) { - DEBUG(2, ("Bad access attemt: %s is a symlink outside the share path", s)); - return(False); - } - - if (relative) { - if (newname[l] == '/') - pstrcpy(s,newname + l + 1); - else - pstrcpy(s,newname+l); - } else - pstrcpy(s,newname); + if (!lp_symlinks(SNUM(conn)) && (strcmp(fname, p)!=0)) { + DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",fname)); + if (free_resolved_name) + SAFE_FREE(resolved_name); + return False; } - vfs_ChDir(conn,wd); - - if (strlen(s) == 0) - pstrcpy(s,"./"); - - DEBUG(3,("reduced to %s\n",s)); + DEBUG(3,("reduce_name: %s reduced to %s\n", fname, p)); + if (free_resolved_name) + SAFE_FREE(resolved_name); return(True); -#endif } |