diff options
author | Jeremy Allison <jra@samba.org> | 2002-04-30 13:28:41 +0000 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2002-04-30 13:28:41 +0000 |
commit | d04b55f2186fb8af998cf61c576771a5f72f4892 (patch) | |
tree | 9ff8c3a7cf34cefc0ee9a550a3bb1236a9e77595 /source/smbd/reply.c | |
parent | 73267ca42d9eddabb71b31b4c5068ebbe7bc9f7c (diff) | |
download | samba-d04b55f2186fb8af998cf61c576771a5f72f4892.tar.gz samba-d04b55f2186fb8af998cf61c576771a5f72f4892.tar.xz samba-d04b55f2186fb8af998cf61c576771a5f72f4892.zip |
Start of merge to 2_2_RELEASE branch for release.
Jeremy.
Diffstat (limited to 'source/smbd/reply.c')
-rw-r--r-- | source/smbd/reply.c | 821 |
1 files changed, 460 insertions, 361 deletions
diff --git a/source/smbd/reply.c b/source/smbd/reply.c index ae8d4b0ad47..562b0492ca0 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -236,9 +236,9 @@ int reply_tcon(connection_struct *conn, * Ensure the user and password names are in UNIX codepage format. */ - pstrcpy(user,dos_to_unix(user,False)); + pstrcpy(user,dos_to_unix_static(user)); if (!doencrypt) - pstrcpy(password,dos_to_unix(password,False)); + pstrcpy(password,dos_to_unix_static(password)); /* * Pass the user through the NT -> unix user mapping @@ -346,9 +346,9 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt * Ensure the user and password names are in UNIX codepage format. */ - pstrcpy(user,dos_to_unix(user,False)); + pstrcpy(user,dos_to_unix_static(user)); if (!doencrypt) - pstrcpy(password,dos_to_unix(password,False)); + pstrcpy(password,dos_to_unix_static(password)); /* * Pass the user through the NT -> unix user mapping @@ -385,7 +385,8 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt /* what does setting this bit do? It is set by NT4 and may affect the ability to autorun mounted cdroms */ - SSVAL(outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS); + SSVAL(outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS| + (lp_csc_policy(SNUM(conn)) << 2)); init_dfsroot(conn, inbuf, outbuf); } @@ -726,7 +727,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int * Incoming user is in DOS codepage format. Convert * to UNIX. */ - pstrcpy(user,dos_to_unix(user,False)); + pstrcpy(user,dos_to_unix_static(user)); if (!doencrypt && (lp_security() != SEC_SERVER)) { smb_apasslen = strlen(smb_apasswd); @@ -812,8 +813,8 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int * Ensure the plaintext passwords are in UNIX format. */ if(!doencrypt) { - pstrcpy(smb_apasswd,dos_to_unix(smb_apasswd,False)); - pstrcpy(smb_ntpasswd,dos_to_unix(smb_ntpasswd,False)); + pstrcpy(smb_apasswd,dos_to_unix_static(smb_apasswd)); + pstrcpy(smb_ntpasswd,dos_to_unix_static(smb_ntpasswd)); } } else { @@ -823,7 +824,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int /* * Ensure the plaintext password is in UNIX format. */ - pstrcpy(smb_apasswd,dos_to_unix(smb_apasswd,False)); + pstrcpy(smb_apasswd,dos_to_unix_static(smb_apasswd)); /* trim the password */ smb_apasslen = strlen(smb_apasswd); @@ -842,8 +843,8 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int * Incoming user and domain are in DOS codepage format. Convert * to UNIX. */ - pstrcpy(user,dos_to_unix(user,False)); - fstrcpy(domain, dos_to_unix(p, False)); + pstrcpy(user,dos_to_unix_static(user)); + fstrcpy(domain, dos_to_unix_static(p)); DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s]\n", domain,skip_string(p,1),skip_string(p,2))); } @@ -912,7 +913,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int /* Work out who's who */ slprintf(dom_user, sizeof(dom_user) - 1,"%s%s%s", - dos_to_unix(domain, False), lp_winbind_separator(), user); + dos_to_unix_static(domain), lp_winbind_separator(), user); if (sys_getpwnam(dom_user) != NULL) { pstrcpy(user, dom_user); @@ -992,13 +993,30 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) { - if (smb_getpwnam(user,True)) + SAM_ACCOUNT *sampass = NULL; + + pdb_init_sam(&sampass); + + /* + * This is really bad form. We know that password_ok() failed, + * but the return value can't distinguish between a non-existent user + * and a bad password. So we try to look the user up again here + * to see if he or she exists. We must look up the user in the + * "smb passwd file" and not /etc/passwd so that we don't + * get confused when the two don't have a one-to-one correspondence. + * e.g. a standard UNIX account such as "operator" --jerry + */ + + if (pdb_getsampwnam(sampass, user)) { delete_nt_token(&ptok); DEBUG(1,("Rejecting user '%s': bad password\n", user)); - END_PROFILE(SMBsesssetupX); + END_PROFILE(SMBsesssetupX); + pdb_free_sam(sampass); return ERROR_BOTH(NT_STATUS_LOGON_FAILURE,ERRSRV,ERRbadpw); } + + pdb_free_sam(sampass); } /* @@ -1036,7 +1054,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int p = smb_buf(outbuf); pstrcpy(p,"Unix"); p = skip_string(p,1); pstrcpy(p,"Samba "); pstrcat(p,VERSION); p = skip_string(p,1); - pstrcpy(p,global_myworkgroup); unix_to_dos(p, True); p = skip_string(p,1); + pstrcpy(p,global_myworkgroup); unix_to_dos(p); p = skip_string(p,1); set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False); /* perhaps grab OS version here?? */ } @@ -1068,6 +1086,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int delete_nt_token(&ptok); if (sess_vuid == -1) { + END_PROFILE(SMBsesssetupX); return(ERROR_DOS(ERRDOS,ERRnoaccess)); } @@ -1198,9 +1217,8 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size put_dos_date3(outbuf,smb_vwv1,mtime); SIVAL(outbuf,smb_vwv3,(uint32)size); - if (Protocol >= PROTOCOL_NT1) { - SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | 0x40); /* IS_LONG_NAME */ - } + if (Protocol >= PROTOCOL_NT1) + SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME); DEBUG( 3, ( "getatr name=%s mode=%d size=%d\n", fname, mode, (uint32)size ) ); @@ -1231,6 +1249,9 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size if (VALID_STAT_OF_DIR(sbuf)) mode |= aDIR; + else + mode &= ~aDIR; + if (check_name(fname,conn)) ok = (file_chmod(conn,fname,mode,NULL) == 0); if (ok) @@ -1257,23 +1278,46 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size ****************************************************************************/ int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { - int outsize = 0; - SMB_BIG_UINT dfree,dsize,bsize; - START_PROFILE(SMBdskattr); - - conn->vfs_ops.disk_free(conn,".",True,&bsize,&dfree,&dsize); - - outsize = set_message(outbuf,5,0,True); + int outsize = 0; + SMB_BIG_UINT dfree,dsize,bsize; + START_PROFILE(SMBdskattr); + + conn->vfs_ops.disk_free(conn,".",True,&bsize,&dfree,&dsize); - SSVAL(outbuf,smb_vwv0,dsize); - SSVAL(outbuf,smb_vwv1,bsize/512); - SSVAL(outbuf,smb_vwv2,512); - SSVAL(outbuf,smb_vwv3,dfree); + outsize = set_message(outbuf,5,0,True); + + if (Protocol <= PROTOCOL_LANMAN2) { + double total_space, free_space; + /* we need to scale this to a number that DOS6 can handle. We + use floating point so we can handle large drives on systems + that don't have 64 bit integers + + we end up displaying a maximum of 2G to DOS systems + */ + total_space = dsize * (double)bsize; + free_space = dfree * (double)bsize; + + dsize = (total_space+63*512) / (64*512); + dfree = (free_space+63*512) / (64*512); + + if (dsize > 0xFFFF) dsize = 0xFFFF; + if (dfree > 0xFFFF) dfree = 0xFFFF; + + SSVAL(outbuf,smb_vwv0,dsize); + SSVAL(outbuf,smb_vwv1,64); /* this must be 64 for dos systems */ + SSVAL(outbuf,smb_vwv2,512); /* and this must be 512 */ + SSVAL(outbuf,smb_vwv3,dfree); + } else { + SSVAL(outbuf,smb_vwv0,dsize); + SSVAL(outbuf,smb_vwv1,bsize/512); + SSVAL(outbuf,smb_vwv2,512); + SSVAL(outbuf,smb_vwv3,dfree); + } - DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree)); + DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree)); - END_PROFILE(SMBdskattr); - return(outsize); + END_PROFILE(SMBdskattr); + return(outsize); } @@ -1462,9 +1506,8 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size SCVAL(smb_buf(outbuf),0,5); SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE); - if (Protocol >= PROTOCOL_NT1) { - SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | 0x40); /* IS_LONG_NAME */ - } + if (Protocol >= PROTOCOL_NT1) + SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME); outsize += DIR_STRUCT_SIZE*numentries; smb_setlen(outbuf,outsize - 4); @@ -1887,6 +1930,41 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, } /******************************************************************* + Check if a user is allowed to rename a file. +********************************************************************/ + +static NTSTATUS can_rename(char *fname,connection_struct *conn, SMB_STRUCT_STAT *pst) +{ + int smb_action; + int access_mode; + files_struct *fsp; + + if (!CAN_WRITE(conn)) + return NT_STATUS_MEDIA_WRITE_PROTECTED; + + if (S_ISDIR(pst->st_mode)) + return NT_STATUS_OK; + + /* We need a better way to return NT status codes from open... */ + unix_ERR_class = 0; + unix_ERR_code = 0; + + fsp = open_file_shared1(conn, fname, pst, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL), + (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action); + + if (!fsp) { + NTSTATUS ret = NT_STATUS_ACCESS_DENIED; + if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare) + ret = NT_STATUS_SHARING_VIOLATION; + unix_ERR_class = 0; + unix_ERR_code = 0; + return ret; + } + close_file(fsp,False); + return NT_STATUS_OK; +} + +/******************************************************************* Check if a user is allowed to delete a file. ********************************************************************/ @@ -1894,11 +1972,14 @@ static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype) { SMB_STRUCT_STAT sbuf; int fmode; + int smb_action; + int access_mode; + files_struct *fsp; if (!CAN_WRITE(conn)) return NT_STATUS_MEDIA_WRITE_PROTECTED; - if (conn->vfs_ops.lstat(conn,dos_to_unix(fname,False),&sbuf) != 0) + if (conn->vfs_ops.lstat(conn,dos_to_unix_static(fname),&sbuf) != 0) return NT_STATUS_OBJECT_NAME_NOT_FOUND; fmode = dos_mode(conn,fname,&sbuf); @@ -1912,9 +1993,22 @@ static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype) if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) return NT_STATUS_CANNOT_DELETE; - if (!check_file_sharing(conn,fname,False)) - return NT_STATUS_SHARING_VIOLATION; + /* We need a better way to return NT status codes from open... */ + unix_ERR_class = 0; + unix_ERR_code = 0; + fsp = open_file_shared1(conn, fname, &sbuf, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL), + (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action); + + if (!fsp) { + NTSTATUS ret = NT_STATUS_ACCESS_DENIED; + if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare) + ret = NT_STATUS_SHARING_VIOLATION; + unix_ERR_class = 0; + unix_ERR_code = 0; + return ret; + } + close_file(fsp,False); return NT_STATUS_OK; } @@ -1925,93 +2019,91 @@ static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype) NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name) { - pstring directory; - pstring mask; - char *p; - int count=0; + pstring directory; + pstring mask; + char *p; + int count=0; NTSTATUS error = NT_STATUS_OK; - BOOL has_wild; - BOOL exists=False; - BOOL bad_path = False; - BOOL rc = True; - SMB_STRUCT_STAT sbuf; + BOOL has_wild; + BOOL bad_path = False; + BOOL rc = True; + SMB_STRUCT_STAT sbuf; - *directory = *mask = 0; + *directory = *mask = 0; - rc = unix_convert(name,conn,0,&bad_path,&sbuf); + rc = unix_convert(name,conn,0,&bad_path,&sbuf); - p = strrchr(name,'/'); - if (!p) { - pstrcpy(directory,"./"); - pstrcpy(mask,name); - } else { - *p = 0; - pstrcpy(directory,name); - pstrcpy(mask,p+1); - } + p = strrchr(name,'/'); + if (!p) { + pstrcpy(directory,"."); + pstrcpy(mask,name); + } else { + *p = 0; + pstrcpy(directory,name); + pstrcpy(mask,p+1); + } - /* - * We should only check the mangled cache - * here if unix_convert failed. This means - * that the path in 'mask' doesn't exist - * on the file system and so we need to look - * for a possible mangle. This patch from - * Tine Smukavec <valentin.smukavec@hermes.si>. - */ + /* + * We should only check the mangled cache + * here if unix_convert failed. This means + * that the path in 'mask' doesn't exist + * on the file system and so we need to look + * for a possible mangle. This patch from + * Tine Smukavec <valentin.smukavec@hermes.si>. + */ - if (!rc && is_mangled(mask)) - check_mangled_cache( mask ); + if (!rc && is_mangled(mask)) + check_mangled_cache( mask ); - has_wild = ms_has_wild(mask); + has_wild = ms_has_wild(mask); - if (!has_wild) { - pstrcat(directory,"/"); - pstrcat(directory,mask); + if (!has_wild) { + pstrcat(directory,"/"); + pstrcat(directory,mask); error = can_delete(directory,conn,dirtype); - if (!NT_STATUS_IS_OK(error)) return error; - - if (vfs_unlink(conn,directory) == 0) { - count++; - } - if (!count) - exists = vfs_file_exist(conn,directory,&sbuf); - } else { - void *dirptr = NULL; - char *dname; + if (!NT_STATUS_IS_OK(error)) + return error; - if (check_name(directory,conn)) - dirptr = OpenDir(conn, directory, True); + if (vfs_unlink(conn,directory) == 0) + count++; + } else { + void *dirptr = NULL; + char *dname; + if (check_name(directory,conn)) + dirptr = OpenDir(conn, directory, True); - /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then - the pattern matches against the long name, otherwise the short name - We don't implement this yet XXXX - */ + /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then + the pattern matches against the long name, otherwise the short name + We don't implement this yet XXXX + */ if (dirptr) { error = NT_STATUS_OBJECT_NAME_NOT_FOUND; - if (strequal(mask,"????????.???")) - pstrcpy(mask,"*"); + if (strequal(mask,"????????.???")) + pstrcpy(mask,"*"); while ((dname = ReadDirName(dirptr))) { - pstring fname; - pstrcpy(fname,dname); + pstring fname; + pstrcpy(fname,dname); - if(!mask_match(fname, mask, case_sensitive)) continue; + if(!mask_match(fname, mask, case_sensitive)) + continue; - slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname); + slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname); error = can_delete(fname,conn,dirtype); - if (!NT_STATUS_IS_OK(error)) continue; - if (vfs_unlink(conn,fname) == 0) count++; - DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname)); - } - CloseDir(dirptr); - } - } + if (!NT_STATUS_IS_OK(error)) + continue; + if (vfs_unlink(conn,fname) == 0) + count++; + DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname)); + } + CloseDir(dirptr); + } + } - if (count == 0 && NT_STATUS_IS_OK(error)) { + if (count == 0 && NT_STATUS_IS_OK(error)) error = map_nt_error_from_unix(errno); - } return error; } @@ -2022,33 +2114,35 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name) int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { - int outsize = 0; - pstring name; - int dirtype; + int outsize = 0; + pstring name; + int dirtype; NTSTATUS status; - START_PROFILE(SMBunlink); - dirtype = SVAL(inbuf,smb_vwv0); + START_PROFILE(SMBunlink); - pstrcpy(name,smb_buf(inbuf) + 1); + dirtype = SVAL(inbuf,smb_vwv0); - RESOLVE_DFSPATH(name, conn, inbuf, outbuf); + pstrcpy(name,smb_buf(inbuf) + 1); + + RESOLVE_DFSPATH(name, conn, inbuf, outbuf); - DEBUG(3,("reply_unlink : %s\n",name)); + DEBUG(3,("reply_unlink : %s\n",name)); status = unlink_internals(conn, dirtype, name); - if (!NT_STATUS_IS_OK(status)) return ERROR_NT(status); + if (!NT_STATUS_IS_OK(status)) + return ERROR_NT(status); - /* - * Win2k needs a changenotify request response before it will - * update after a rename.. - */ + /* + * Win2k needs a changenotify request response before it will + * update after a rename.. + */ - process_pending_change_notify_queue((time_t)0); + process_pending_change_notify_queue((time_t)0); - outsize = set_message(outbuf,0,0,True); + outsize = set_message(outbuf,0,0,True); - END_PROFILE(SMBunlink); + END_PROFILE(SMBunlink); return outsize; } @@ -2225,7 +2319,7 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length * for a write lock. JRA. */ - status = do_lock(fsp, conn, SVAL(inbuf,smb_pid), + status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK); if (NT_STATUS_V(status)) { @@ -2906,10 +3000,9 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size, return ERROR_DOS(ERRDOS,ERRbadfid); } - if(fsp->is_directory || fsp->stat_open) { + if(fsp->is_directory) { /* - * Special case - close NT SMB directory or stat file - * handle. + * Special case - close NT SMB directory handle. */ DEBUG(3,("close %s fnum=%d\n", fsp->is_directory ? "directory" : "stat file open", fsp->fnum)); close_file(fsp,True); @@ -3036,7 +3129,7 @@ int reply_lock(connection_struct *conn, DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n", fsp->fd, fsp->fnum, (double)offset, (double)count)); - status = do_lock(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK); + status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK); if (NT_STATUS_V(status)) { if (lp_blocking_locks(SNUM(conn))) { /* @@ -3274,7 +3367,7 @@ int reply_printqueue(connection_struct *conn, SSVAL(p,5, queue[i].job); SIVAL(p,7,queue[i].size); SCVAL(p,11,0); - StrnCpy(p+12,queue[i].user,16); + StrnCpy(p+12,queue[i].fs_user,16); p += 28; } @@ -3336,18 +3429,21 @@ int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_ ****************************************************************************/ NTSTATUS mkdir_internal(connection_struct *conn, pstring directory) { - BOOL bad_path = False; - SMB_STRUCT_STAT sbuf; - int ret= -1; + BOOL bad_path = False; + SMB_STRUCT_STAT sbuf; + int ret= -1; - unix_convert(directory,conn,0,&bad_path,&sbuf); + unix_convert(directory,conn,0,&bad_path,&sbuf); - if (check_name(directory, conn)) - ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory)); + if (check_name(directory, conn)) + ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory)); if (ret == -1) { + NTSTATUS nterr = set_bad_path_error(errno, bad_path); + if (!NT_STATUS_IS_OK(nterr)) + return nterr; return map_nt_error_from_unix(errno); - } + } return NT_STATUS_OK; } @@ -3409,7 +3505,7 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory) pstrcat(fullname, "/"); pstrcat(fullname, dname); - if(conn->vfs_ops.lstat(conn,dos_to_unix(fullname,False), &st) != 0) { + if(conn->vfs_ops.lstat(conn,dos_to_unix_static(fullname), &st) != 0) { ret = True; break; } @@ -3481,7 +3577,7 @@ BOOL rmdir_internals(connection_struct *conn, char *directory) pstrcat(fullname, "/"); pstrcat(fullname, dname); - if(conn->vfs_ops.lstat(conn,dos_to_unix(fullname, False), &st) != 0) + if(conn->vfs_ops.lstat(conn,dos_to_unix_static(fullname), &st) != 0) break; if(st.st_mode & S_IFDIR) { if(lp_recursive_veto_delete(SNUM(conn))) { @@ -3615,21 +3711,6 @@ static BOOL resolve_wildcards(char *name1,char *name2) return(True); } -/******************************************************************* - Check if a user is allowed to rename a file. -********************************************************************/ - -static NTSTATUS can_rename(char *fname,connection_struct *conn) -{ - if (!CAN_WRITE(conn)) - return NT_STATUS_ACCESS_DENIED; - - if (!check_file_sharing(conn,fname,True)) - return NT_STATUS_SHARING_VIOLATION; - - return NT_STATUS_OK; -} - /**************************************************************************** The guts of the rename command, split out so it may be called by the NT SMB code. @@ -3756,7 +3837,7 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", * The source object must exist. */ - if (!vfs_object_exist(conn, directory, NULL)) { + if (!vfs_object_exist(conn, directory, &sbuf1)) { DEBUG(3,("rename_internals: source doesn't exist doing rename %s -> %s\n", directory,newname)); @@ -3781,7 +3862,7 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", return error; } - error = can_rename(directory,conn); + error = can_rename(directory,conn,&sbuf1); if (!NT_STATUS_IS_OK(error)) { DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", @@ -3789,8 +3870,8 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", return error; } - pstrcpy(zdirectory, dos_to_unix(directory, False)); - pstrcpy(znewname, dos_to_unix(newname,False)); + pstrcpy(zdirectory, dos_to_unix_static(directory)); + pstrcpy(znewname, dos_to_unix_static(newname)); /* * If the src and dest names are identical - including case, @@ -3851,7 +3932,12 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", error = NT_STATUS_ACCESS_DENIED; slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname); - error = can_rename(fname,conn); + if (!vfs_object_exist(conn, fname, &sbuf1)) { + error = NT_STATUS_OBJECT_NAME_NOT_FOUND; + DEBUG(6,("rename %s failed. Error %s\n", fname, get_nt_error_msg(error))); + continue; + } + error = can_rename(fname,conn,&sbuf1); if (!NT_STATUS_IS_OK(error)) { DEBUG(6,("rename %s failed. Error %s\n", fname, get_nt_error_msg(error))); continue; @@ -3871,8 +3957,8 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", continue; } - if (!conn->vfs_ops.rename(conn,dos_to_unix(fname,False), - dos_to_unix(destname,False))) + if (!conn->vfs_ops.rename(conn,dos_to_unix_static(fname), + dos_to_unix_static(destname))) count++; DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname)); } @@ -4349,180 +4435,190 @@ SMB_BIG_UINT get_lock_offset( char *data, int data_offset, BOOL large_file_forma int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) { - files_struct *fsp = file_fsp(inbuf,smb_vwv2); - unsigned char locktype = CVAL(inbuf,smb_vwv3); - unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1); - uint16 num_ulocks = SVAL(inbuf,smb_vwv6); - uint16 num_locks = SVAL(inbuf,smb_vwv7); - SMB_BIG_UINT count = 0, offset = 0; - uint16 lock_pid; - int32 lock_timeout = IVAL(inbuf,smb_vwv4); - int i; - char *data; - BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False; - BOOL err; + files_struct *fsp = file_fsp(inbuf,smb_vwv2); + unsigned char locktype = CVAL(inbuf,smb_vwv3); + unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1); + uint16 num_ulocks = SVAL(inbuf,smb_vwv6); + uint16 num_locks = SVAL(inbuf,smb_vwv7); + SMB_BIG_UINT count = 0, offset = 0; + uint16 lock_pid; + int32 lock_timeout = IVAL(inbuf,smb_vwv4); + int i; + char *data; + BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False; + BOOL err; NTSTATUS status; - START_PROFILE(SMBlockingX); + START_PROFILE(SMBlockingX); - CHECK_FSP(fsp,conn); + CHECK_FSP(fsp,conn); - data = smb_buf(inbuf); + data = smb_buf(inbuf); - /* Check if this is an oplock break on a file - we have granted an oplock on. - */ + if (locktype & (LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_CHANGE_LOCKTYPE)) { + /* we don't support these - and CANCEL_LOCK makes w2k + and XP reboot so I don't really want to be + compatible! (tridge) */ + return ERROR_NT(NT_STATUS_NOT_SUPPORTED); + } + + /* Check if this is an oplock break on a file + we have granted an oplock on. + */ if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) { - /* Client can insist on breaking to none. */ - BOOL break_to_none = (oplocklevel == 0); + /* Client can insist on breaking to none. */ + BOOL break_to_none = (oplocklevel == 0); - DEBUG(5,("reply_lockingX: oplock break reply (%u) from client for fnum = %d\n", - (unsigned int)oplocklevel, fsp->fnum )); + DEBUG(5,("reply_lockingX: oplock break reply (%u) from client for fnum = %d\n", + (unsigned int)oplocklevel, fsp->fnum )); - /* - * Make sure we have granted an exclusive or batch oplock on this file. - */ + /* + * Make sure we have granted an exclusive or batch oplock on this file. + */ if(!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { - DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \ + DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name)); - /* if this is a pure oplock break request then don't send a reply */ - if (num_locks == 0 && num_ulocks == 0) { - END_PROFILE(SMBlockingX); - return -1; - } else { - END_PROFILE(SMBlockingX); - return ERROR_DOS(ERRDOS,ERRlock); - } - } + /* if this is a pure oplock break request then don't send a reply */ + if (num_locks == 0 && num_ulocks == 0) { + END_PROFILE(SMBlockingX); + return -1; + } else { + END_PROFILE(SMBlockingX); + return ERROR_DOS(ERRDOS,ERRlock); + } + } - if (remove_oplock(fsp, break_to_none) == False) { - DEBUG(0,("reply_lockingX: error in removing oplock on file %s\n", - fsp->fsp_name )); - } + if (remove_oplock(fsp, break_to_none) == False) { + DEBUG(0,("reply_lockingX: error in removing oplock on file %s\n", + fsp->fsp_name )); + } - /* if this is a pure oplock break request then don't send a reply */ + /* if this is a pure oplock break request then don't send a reply */ if (num_locks == 0 && num_ulocks == 0) { - /* Sanity check - ensure a pure oplock break is not a - chained request. */ - if(CVAL(inbuf,smb_vwv0) != 0xff) - DEBUG(0,("reply_lockingX: Error : pure oplock break is a chained %d request !\n", - (unsigned int)CVAL(inbuf,smb_vwv0) )); - END_PROFILE(SMBlockingX); - return -1; - } - } + /* Sanity check - ensure a pure oplock break is not a + chained request. */ + if(CVAL(inbuf,smb_vwv0) != 0xff) + DEBUG(0,("reply_lockingX: Error : pure oplock break is a chained %d request !\n", + (unsigned int)CVAL(inbuf,smb_vwv0) )); + END_PROFILE(SMBlockingX); + return -1; + } + } - /* - * We do this check *after* we have checked this is not a oplock break - * response message. JRA. - */ + /* + * We do this check *after* we have checked this is not a oplock break + * response message. JRA. + */ - release_level_2_oplocks_on_change(fsp); + release_level_2_oplocks_on_change(fsp); - /* Data now points at the beginning of the list - of smb_unlkrng structs */ - for(i = 0; i < (int)num_ulocks; i++) { - lock_pid = get_lock_pid( data, i, large_file_format); - count = get_lock_count( data, i, large_file_format); - offset = get_lock_offset( data, i, large_file_format, &err); + /* Data now points at the beginning of the list + of smb_unlkrng structs */ + for(i = 0; i < (int)num_ulocks; i++) { + lock_pid = get_lock_pid( data, i, large_file_format); + count = get_lock_count( data, i, large_file_format); + offset = get_lock_offset( data, i, large_file_format, &err); - /* - * There is no error code marked "stupid client bug".... :-). - */ - if(err) { - END_PROFILE(SMBlockingX); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } + /* + * There is no error code marked "stupid client bug".... :-). + */ + if(err) { + END_PROFILE(SMBlockingX); + return ERROR_DOS(ERRDOS,ERRnoaccess); + } - DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for pid %u, file %s\n", - (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name )); + DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for pid %u, file %s\n", + (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name )); status = do_unlock(fsp,conn,lock_pid,count,offset); if (NT_STATUS_V(status)) { - END_PROFILE(SMBlockingX); + END_PROFILE(SMBlockingX); return ERROR_NT(status); - } - } + } + } - /* Setup the timeout in seconds. */ - lock_timeout = ((lock_timeout == -1) ? -1 : lock_timeout/1000); + /* Setup the timeout in seconds. */ - /* Now do any requested locks */ - data += ((large_file_format ? 20 : 10)*num_ulocks); + lock_timeout = ((lock_timeout == -1) ? -1 : lock_timeout/1000); - /* Data now points at the beginning of the list - of smb_lkrng structs */ + /* Now do any requested locks */ + data += ((large_file_format ? 20 : 10)*num_ulocks); - for(i = 0; i < (int)num_locks; i++) { - lock_pid = get_lock_pid( data, i, large_file_format); - count = get_lock_count( data, i, large_file_format); - offset = get_lock_offset( data, i, large_file_format, &err); + /* Data now points at the beginning of the list + of smb_lkrng structs */ - /* - * There is no error code marked "stupid client bug".... :-). - */ - if(err) { - END_PROFILE(SMBlockingX); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } + for(i = 0; i < (int)num_locks; i++) { + lock_pid = get_lock_pid( data, i, large_file_format); + count = get_lock_count( data, i, large_file_format); + offset = get_lock_offset( data, i, large_file_format, &err); + + /* + * There is no error code marked "stupid client bug".... :-). + */ + if(err) { + END_PROFILE(SMBlockingX); + return ERROR_DOS(ERRDOS,ERRnoaccess); + } - DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid %u, file %s\n", - (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name )); + DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid %u, file %s timeout = %d\n", + (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name, + (int)lock_timeout )); + + status = do_lock_spin(fsp,conn,lock_pid, count,offset, + ((locktype & 1) ? READ_LOCK : WRITE_LOCK)); - status = do_lock(fsp,conn,lock_pid, count,offset, - ((locktype & 1) ? READ_LOCK : WRITE_LOCK)); if (NT_STATUS_V(status)) { if ((lock_timeout != 0) && lp_blocking_locks(SNUM(conn))) { - /* - * A blocking lock was requested. Package up - * this smb into a queued request and push it - * onto the blocking lock queue. - */ - if(push_blocking_lock_request(inbuf, length, lock_timeout, i)) { - END_PROFILE(SMBlockingX); - return -1; + /* + * A blocking lock was requested. Package up + * this smb into a queued request and push it + * onto the blocking lock queue. + */ + if(push_blocking_lock_request(inbuf, length, lock_timeout, i)) { + END_PROFILE(SMBlockingX); + return -1; + } + } + break; + } } - } - break; - } - } - /* If any of the above locks failed, then we must unlock - all of the previous locks (X/Open spec). */ - if(i != num_locks && num_locks != 0) { - /* - * Ensure we don't do a remove on the lock that just failed, - * as under POSIX rules, if we have a lock already there, we - * will delete it (and we shouldn't) ..... - */ - for(i--; i >= 0; i--) { - lock_pid = get_lock_pid( data, i, large_file_format); - count = get_lock_count( data, i, large_file_format); - offset = get_lock_offset( data, i, large_file_format, &err); + /* If any of the above locks failed, then we must unlock + all of the previous locks (X/Open spec). */ + if(i != num_locks && num_locks != 0) { + /* + * Ensure we don't do a remove on the lock that just failed, + * as under POSIX rules, if we have a lock already there, we + * will delete it (and we shouldn't) ..... + */ + for(i--; i >= 0; i--) { + lock_pid = get_lock_pid( data, i, large_file_format); + count = get_lock_count( data, i, large_file_format); + offset = get_lock_offset( data, i, large_file_format, &err); - /* - * There is no error code marked "stupid client bug".... :-). - */ - if(err) { - END_PROFILE(SMBlockingX); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } + /* + * There is no error code marked "stupid client bug".... :-). + */ + if(err) { + END_PROFILE(SMBlockingX); + return ERROR_DOS(ERRDOS,ERRnoaccess); + } do_unlock(fsp,conn,lock_pid,count,offset); - } - END_PROFILE(SMBlockingX); + } + END_PROFILE(SMBlockingX); return ERROR_NT(status); - } + } - set_message(outbuf,2,0,True); + set_message(outbuf,2,0,True); - DEBUG( 3, ( "lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n", - fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks ) ); + DEBUG( 3, ( "lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n", + fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks ) ); - END_PROFILE(SMBlockingX); - return chain_reply(inbuf,outbuf,length,bufsize); + END_PROFILE(SMBlockingX); + return chain_reply(inbuf,outbuf,length,bufsize); } /* Back from the dead for OS/2..... JRA. */ @@ -4609,54 +4705,54 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length, int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) { - struct utimbuf unix_times; - int outsize = 0; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - START_PROFILE(SMBsetattrE); + struct utimbuf unix_times; + int outsize = 0; + files_struct *fsp = file_fsp(inbuf,smb_vwv0); + START_PROFILE(SMBsetattrE); - outsize = set_message(outbuf,0,0,True); + outsize = set_message(outbuf,0,0,True); - CHECK_FSP(fsp,conn); + if(!fsp || (fsp->conn != conn)) { + END_PROFILE(SMBgetattrE); + return ERROR_DOS(ERRDOS,ERRbadfid); + } - /* Convert the DOS times into unix times. Ignore create - time as UNIX can't set this. - */ - unix_times.actime = make_unix_date2(inbuf+smb_vwv3); - unix_times.modtime = make_unix_date2(inbuf+smb_vwv5); + /* + * Convert the DOS times into unix times. Ignore create + * time as UNIX can't set this. + */ + unix_times.actime = make_unix_date2(inbuf+smb_vwv3); + unix_times.modtime = make_unix_date2(inbuf+smb_vwv5); - /* - * Patch from Ray Frush <frush@engr.colostate.edu> - * Sometimes times are sent as zero - ignore them. - */ + /* + * Patch from Ray Frush <frush@engr.colostate.edu> + * Sometimes times are sent as zero - ignore them. + */ - if ((unix_times.actime == 0) && (unix_times.modtime == 0)) - { - /* Ignore request */ - if( DEBUGLVL( 3 ) ) - { - dbgtext( "reply_setattrE fnum=%d ", fsp->fnum); - dbgtext( "ignoring zero request - not setting timestamps of 0\n" ); - } - END_PROFILE(SMBsetattrE); - return(outsize); - } - else if ((unix_times.actime != 0) && (unix_times.modtime == 0)) - { - /* set modify time = to access time if modify time was 0 */ - unix_times.modtime = unix_times.actime; - } + if ((unix_times.actime == 0) && (unix_times.modtime == 0)) { + /* Ignore request */ + if( DEBUGLVL( 3 ) ) { + dbgtext( "reply_setattrE fnum=%d ", fsp->fnum); + dbgtext( "ignoring zero request - not setting timestamps of 0\n" ); + } + END_PROFILE(SMBsetattrE); + return(outsize); + } else if ((unix_times.actime != 0) && (unix_times.modtime == 0)) { + /* set modify time = to access time if modify time was 0 */ + unix_times.modtime = unix_times.actime; + } - /* Set the date on this file */ - if(file_utime(conn, fsp->fsp_name, &unix_times)) { - END_PROFILE(SMBsetattrE); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } + /* Set the date on this file */ + if(file_utime(conn, fsp->fsp_name, &unix_times)) { + END_PROFILE(SMBsetattrE); + return ERROR_DOS(ERRDOS,ERRnoaccess); + } - DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n", - fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) ); + DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n", + fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) ); - END_PROFILE(SMBsetattrE); - return(outsize); + END_PROFILE(SMBsetattrE); + return(outsize); } @@ -4857,44 +4953,47 @@ int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) { - SMB_STRUCT_STAT sbuf; - int outsize = 0; - int mode; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - START_PROFILE(SMBgetattrE); + SMB_STRUCT_STAT sbuf; + int outsize = 0; + int mode; + files_struct *fsp = file_fsp(inbuf,smb_vwv0); + START_PROFILE(SMBgetattrE); - outsize = set_message(outbuf,11,0,True); + outsize = set_message(outbuf,11,0,True); - CHECK_FSP(fsp,conn); + if(!fsp || (fsp->conn != conn)) { + END_PROFILE(SMBgetattrE); + return ERROR_DOS(ERRDOS,ERRbadfid); + } - /* Do an fstat on this file */ - if(vfs_fstat(fsp,fsp->fd, &sbuf)) { - END_PROFILE(SMBgetattrE); - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } + /* Do an stat on this file */ + + if(fsp_stat(fsp, &sbuf)) { + END_PROFILE(SMBgetattrE); + return(UNIXERROR(ERRDOS,ERRnoaccess)); + } - mode = dos_mode(conn,fsp->fsp_name,&sbuf); + mode = dos_mode(conn,fsp->fsp_name,&sbuf); - /* Convert the times into dos times. Set create - date to be last modify date as UNIX doesn't save - this */ - put_dos_date2(outbuf,smb_vwv0,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)))); - put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime); - put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime); - if (mode & aDIR) - { - SIVAL(outbuf,smb_vwv6,0); - SIVAL(outbuf,smb_vwv8,0); - } - else - { - SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size); - SIVAL(outbuf,smb_vwv8,SMB_ROUNDUP(sbuf.st_size,1024)); - } - SSVAL(outbuf,smb_vwv10, mode); + /* Convert the times into dos times. Set create + * date to be last modify date as UNIX doesn't save + * this. + */ + + put_dos_date2(outbuf,smb_vwv0,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)))); + put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime); + put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime); + if (mode & aDIR) { + SIVAL(outbuf,smb_vwv6,0); + SIVAL(outbuf,smb_vwv8,0); + } else { + SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size); + SIVAL(outbuf,smb_vwv8,SMB_ROUNDUP(sbuf.st_size,1024)); + } + SSVAL(outbuf,smb_vwv10, mode); - DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum)); + DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum)); - END_PROFILE(SMBgetattrE); - return(outsize); + END_PROFILE(SMBgetattrE); + return(outsize); } |