diff -uBb -r samba-2.2.7a/source/include/version.h samba-2.2.7b/source/include/version.h --- samba-2.2.7a/source/include/version.h Wed Dec 11 09:34:33 2002 +++ samba-2.2.7b/source/include/version.h Sun Apr 6 20:49:28 2003 @@ -1 +1 @@ -#define VERSION "2.2.7a" +#define VERSION "2.2.7b" diff -uBb -r samba-2.2.7a/source/smbd/ipc.c samba-2.2.7b/source/smbd/ipc.c --- samba-2.2.7a/source/smbd/ipc.c Fri Feb 1 16:14:43 2002 +++ samba-2.2.7b/source/smbd/ipc.c Sun Apr 6 20:47:58 2003 @@ -368,52 +368,69 @@ uint16 *setup=NULL; int outsize = 0; uint16 vuid = SVAL(inbuf,smb_uid); - int tpscnt = SVAL(inbuf,smb_vwv0); - int tdscnt = SVAL(inbuf,smb_vwv1); - int mprcnt = SVAL(inbuf,smb_vwv2); - int mdrcnt = SVAL(inbuf,smb_vwv3); - int msrcnt = CVAL(inbuf,smb_vwv4); + unsigned int tpscnt = SVAL(inbuf,smb_vwv0); + unsigned int tdscnt = SVAL(inbuf,smb_vwv1); + unsigned int mprcnt = SVAL(inbuf,smb_vwv2); + unsigned int mdrcnt = SVAL(inbuf,smb_vwv3); + unsigned int msrcnt = CVAL(inbuf,smb_vwv4); BOOL close_on_completion = BITSETW(inbuf+smb_vwv5,0); BOOL one_way = BITSETW(inbuf+smb_vwv5,1); - int pscnt = SVAL(inbuf,smb_vwv9); - int psoff = SVAL(inbuf,smb_vwv10); - int dscnt = SVAL(inbuf,smb_vwv11); - int dsoff = SVAL(inbuf,smb_vwv12); - int suwcnt = CVAL(inbuf,smb_vwv13); + unsigned int pscnt = SVAL(inbuf,smb_vwv9); + unsigned int psoff = SVAL(inbuf,smb_vwv10); + unsigned int dscnt = SVAL(inbuf,smb_vwv11); + unsigned int dsoff = SVAL(inbuf,smb_vwv12); + unsigned int suwcnt = CVAL(inbuf,smb_vwv13); START_PROFILE(SMBtrans); memset(name, '\0',sizeof(name)); fstrcpy(name,smb_buf(inbuf)); - if (dscnt > tdscnt || pscnt > tpscnt) { - exit_server("invalid trans parameters\n"); - } + if (dscnt > tdscnt || pscnt > tpscnt) + goto bad_param; if (tdscnt) { if((data = (char *)malloc(tdscnt)) == NULL) { - DEBUG(0,("reply_trans: data malloc fail for %d bytes !\n", tdscnt)); + DEBUG(0,("reply_trans: data malloc fail for %u bytes !\n", tdscnt)); END_PROFILE(SMBtrans); return(ERROR_DOS(ERRDOS,ERRnomem)); } + if ((dsoff+dscnt < dsoff) || (dsoff+dscnt < dscnt)) + goto bad_param; + if (smb_base(inbuf)+dsoff+dscnt > inbuf + size) + goto bad_param; + memcpy(data,smb_base(inbuf)+dsoff,dscnt); } if (tpscnt) { if((params = (char *)malloc(tpscnt)) == NULL) { - DEBUG(0,("reply_trans: param malloc fail for %d bytes !\n", tpscnt)); + DEBUG(0,("reply_trans: param malloc fail for %u bytes !\n", tpscnt)); + SAFE_FREE(data); END_PROFILE(SMBtrans); return(ERROR_DOS(ERRDOS,ERRnomem)); } + if ((psoff+pscnt < psoff) || (psoff+pscnt < pscnt)) + goto bad_param; + if (smb_base(inbuf)+psoff+pscnt > inbuf + size) + goto bad_param; + memcpy(params,smb_base(inbuf)+psoff,pscnt); } if (suwcnt) { int i; if((setup = (uint16 *)malloc(suwcnt*sizeof(uint16))) == NULL) { - DEBUG(0,("reply_trans: setup malloc fail for %d bytes !\n", (int)(suwcnt * sizeof(uint16)))); + DEBUG(0,("reply_trans: setup malloc fail for %u bytes !\n", (unsigned int)(suwcnt * sizeof(uint16)))); + SAFE_FREE(data); + SAFE_FREE(params); END_PROFILE(SMBtrans); return(ERROR_DOS(ERRDOS,ERRnomem)); } + if (inbuf+smb_vwv14+(suwcnt*SIZEOFWORD) > inbuf + size) + goto bad_param; + if ((smb_vwv14+(suwcnt*SIZEOFWORD) < smb_vwv14) || (smb_vwv14+(suwcnt*SIZEOFWORD) < (suwcnt*SIZEOFWORD))) + goto bad_param; + for (i=0;i tdscnt || pscnt > tpscnt) { - exit_server("invalid trans parameters\n"); - } + if (dscnt > tdscnt || pscnt > tpscnt) + goto bad_param; + + if (pcnt) { + if (pdisp+pcnt >= tpscnt) + goto bad_param; + if ((pdisp+pcnt < pdisp) || (pdisp+pcnt < pcnt)) + goto bad_param; + if (smb_base(inbuf) + poff + pcnt >= inbuf + bufsize) + goto bad_param; + if (params + pdisp < params) + goto bad_param; - if (pcnt) memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt); - if (dcnt) + } + + if (dcnt) { + if (ddisp+dcnt >= tdscnt) + goto bad_param; + if ((ddisp+dcnt < ddisp) || (ddisp+dcnt < dcnt)) + goto bad_param; + if (smb_base(inbuf) + doff + dcnt >= inbuf + bufsize) + goto bad_param; + if (data + ddisp < data) + goto bad_param; + memcpy(data+ddisp,smb_base(inbuf)+doff,dcnt); } + } - DEBUG(3,("trans <%s> data=%d params=%d setup=%d\n", + DEBUG(3,("trans <%s> data=%u params=%u setup=%u\n", name,tdscnt,tpscnt,suwcnt)); /* @@ -525,4 +565,14 @@ END_PROFILE(SMBtrans); return(outsize); + + + bad_param: + + DEBUG(0,("reply_trans: invalid trans parameters\n")); + SAFE_FREE(data); + SAFE_FREE(params); + SAFE_FREE(setup); + END_PROFILE(SMBtrans); + return ERROR_NT(NT_STATUS_INVALID_PARAMETER); } diff -uBb -r samba-2.2.7a/source/smbd/nttrans.c samba-2.2.7b/source/smbd/nttrans.c --- samba-2.2.7a/source/smbd/nttrans.c Wed Dec 4 11:16:36 2002 +++ samba-2.2.7b/source/smbd/nttrans.c Sun Apr 6 20:47:58 2003 @@ -1889,8 +1890,7 @@ if(CVAL(inbuf, smb_wct) != 19 + (setup_count/2)) { DEBUG(2,("Invalid smb_wct %d in nttrans call (should be %d)\n", CVAL(inbuf, smb_wct), 19 + (setup_count/2))); - END_PROFILE(SMBnttrans); - return ERROR_DOS(ERRSRV,ERRerror); + goto bad_param; } /* Allocate the space for the setup, the maximum needed parameters and data */ @@ -1904,35 +1904,51 @@ if ((total_parameter_count && !params) || (total_data_count && !data) || (setup_count && !setup)) { - safe_free(setup); - safe_free(params); - safe_free(data); + SAFE_FREE(setup); + SAFE_FREE(params); + SAFE_FREE(data); DEBUG(0,("reply_nttrans : Out of memory\n")); END_PROFILE(SMBnttrans); return ERROR_DOS(ERRDOS,ERRnomem); } - /* Copy the param and data bytes sent with this request into - the params buffer */ + /* Copy the param and data bytes sent with this request into the params buffer */ num_params_sofar = parameter_count; num_data_sofar = data_count; if (parameter_count > total_parameter_count || data_count > total_data_count) - exit_server("reply_nttrans: invalid sizes in packet."); + goto bad_param; if(setup) { - memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count); DEBUG(10,("reply_nttrans: setup_count = %d\n", setup_count)); + if ((smb_nt_SetupStart + setup_count < smb_nt_SetupStart) || + (smb_nt_SetupStart + setup_count < setup_count)) + goto bad_param; + if (smb_nt_SetupStart + setup_count > length) + goto bad_param; + + memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count); dump_data(10, setup, setup_count); } if(params) { - memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count); DEBUG(10,("reply_nttrans: parameter_count = %d\n", parameter_count)); + if ((parameter_offset + parameter_count < parameter_offset) || + (parameter_offset + parameter_count < parameter_count)) + goto bad_param; + if (smb_base(inbuf) + parameter_offset + parameter_count > inbuf + length) + goto bad_param; + + memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count); dump_data(10, params, parameter_count); } if(data) { - memcpy( data, smb_base(inbuf) + data_offset, data_count); DEBUG(10,("reply_nttrans: data_count = %d\n",data_count)); + if ((data_offset + data_count < data_offset) || (data_offset + data_count < data_count)) + goto bad_param; + if (smb_base(inbuf) + data_offset + data_count > inbuf + length) + goto bad_param; + + memcpy( data, smb_base(inbuf) + data_offset, data_count); dump_data(10, data, data_count); } @@ -1945,6 +1961,8 @@ while( num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) { BOOL ret; + uint32 parameter_displacement; + uint32 data_displacement; ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT); @@ -1956,25 +1974,57 @@ DEBUG(0,("reply_nttrans: %s in getting secondary nttrans response.\n", (smb_read_error == READ_ERROR) ? "error" : "timeout" )); } - SAFE_FREE(params); - SAFE_FREE(data); - SAFE_FREE(setup); - END_PROFILE(SMBnttrans); - return ERROR_DOS(ERRSRV,ERRerror); + goto bad_param; } /* Revise total_params and total_data in case they have changed downwards */ + if (IVAL(inbuf, smb_nts_TotalParameterCount) < total_parameter_count) total_parameter_count = IVAL(inbuf, smb_nts_TotalParameterCount); + if (IVAL(inbuf, smb_nts_TotalDataCount) < total_data_count) total_data_count = IVAL(inbuf, smb_nts_TotalDataCount); - num_params_sofar += (parameter_count = IVAL(inbuf,smb_nts_ParameterCount)); - num_data_sofar += ( data_count = IVAL(inbuf, smb_nts_DataCount)); - if (num_params_sofar > total_parameter_count || num_data_sofar > total_data_count) - exit_server("reply_nttrans2: data overflow in secondary nttrans packet"); - - memcpy( ¶ms[ IVAL(inbuf, smb_nts_ParameterDisplacement)], - smb_base(inbuf) + IVAL(inbuf, smb_nts_ParameterOffset), parameter_count); - memcpy( &data[IVAL(inbuf, smb_nts_DataDisplacement)], - smb_base(inbuf)+ IVAL(inbuf, smb_nts_DataOffset), data_count); + + parameter_count = IVAL(inbuf,smb_nts_ParameterCount); + parameter_offset = IVAL(inbuf, smb_nts_ParameterOffset); + parameter_displacement = IVAL(inbuf, smb_nts_ParameterDisplacement); + num_params_sofar += parameter_count; + + data_count = IVAL(inbuf, smb_nts_DataCount); + data_displacement = IVAL(inbuf, smb_nts_DataDisplacement); + data_offset = IVAL(inbuf, smb_nts_DataOffset); + num_data_sofar += data_count; + + if (num_params_sofar > total_parameter_count || num_data_sofar > total_data_count) { + DEBUG(0,("reply_nttrans2: data overflow in secondary nttrans packet")); + goto bad_param; + } + + if (parameter_count) { + if (parameter_displacement + parameter_count >= total_parameter_count) + goto bad_param; + if ((parameter_displacement + parameter_count < parameter_displacement) || + (parameter_displacement + parameter_count < parameter_count)) + goto bad_param; + if (smb_base(inbuf) + parameter_offset + parameter_count >= inbuf + bufsize) + goto bad_param; + if (params + parameter_displacement < params) + goto bad_param; + + memcpy( ¶ms[parameter_displacement], smb_base(inbuf) + parameter_offset, parameter_count); + } + + if (data_count) { + if (data_displacement + data_count >= total_data_count) + goto bad_param; + if ((data_displacement + data_count < data_displacement) || + (data_displacement + data_count < data_count)) + goto bad_param; + if (smb_base(inbuf) + data_offset + data_count >= inbuf + bufsize) + goto bad_param; + if (data + data_displacement < data) + goto bad_param; + + memcpy( &data[data_displacement], smb_base(inbuf)+ data_offset, data_count); + } } } @@ -2051,4 +2101,12 @@ return outsize; /* If a correct response was needed the call_nt_transact_xxxx calls have already sent it. If outsize != -1 then it is returning an error packet. */ + + bad_param: + + SAFE_FREE(params); + SAFE_FREE(data); + SAFE_FREE(setup); + END_PROFILE(SMBnttrans); + return ERROR_NT(NT_STATUS_INVALID_PARAMETER); } diff -uBb -r samba-2.2.7a/source/smbd/password.c samba-2.2.7b/source/smbd/password.c --- samba-2.2.7a/source/smbd/password.c Tue Dec 10 08:58:17 2002 +++ samba-2.2.7b/source/smbd/password.c Sun Apr 6 20:47:58 2003 @@ -816,7 +816,7 @@ if (!ok && lp_username(snum)) { char *auser; pstring user_list; - StrnCpy(user_list,lp_username(snum),sizeof(pstring)); + StrnCpy(user_list,lp_username(snum),sizeof(pstring)-1); pstring_sub(user_list,"%S",lp_servicename(snum)); diff -uBb -r samba-2.2.7a/source/smbd/reply.c samba-2.2.7b/source/smbd/reply.c --- samba-2.2.7a/source/smbd/reply.c Mon Dec 9 19:01:02 2002 +++ samba-2.2.7b/source/smbd/reply.c Sun Apr 6 20:47:58 2003 @@ -1478,6 +1478,9 @@ for (i=numentries;(i BUFFER_SIZE ) + break; finished = !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend); if (!finished) @@ -3505,6 +3508,9 @@ for (i=first;i BUFFER_SIZE ) + break; put_dos_date2(p,0,queue[i].time); SCVAL(p,4,(queue[i].status==LPQ_PRINTING?2:3)); SSVAL(p,5, queue[i].job); diff -uBb -r samba-2.2.7a/source/smbd/statcache.c samba-2.2.7b/source/smbd/statcache.c --- samba-2.2.7a/source/smbd/statcache.c Thu Oct 11 04:34:37 2001 +++ samba-2.2.7b/source/smbd/statcache.c Sun Apr 6 20:47:58 2003 @@ -88,7 +88,7 @@ * StrnCpy always null terminates. */ - StrnCpy(orig_name, full_orig_name, namelen); + StrnCpy(orig_name, full_orig_name, MIN(namelen, sizeof(orig_name)-1)); if(!case_sensitive) strupper( orig_name ); diff -uBb -r samba-2.2.7a/source/smbd/trans2.c samba-2.2.7b/source/smbd/trans2.c --- samba-2.2.7a/source/smbd/trans2.c Wed Dec 4 15:08:35 2002 +++ samba-2.2.7b/source/smbd/trans2.c Sun Apr 6 20:47:58 2003 @@ -217,7 +217,6 @@ int16 open_ofun; int32 open_size; char *pname; - int16 namelen; pstring fname; mode_t unixmode; @@ -247,9 +246,8 @@ open_ofun = SVAL(params,12); open_size = IVAL(params,14); pname = ¶ms[28]; - namelen = strlen(pname)+1; - StrnCpy(fname,pname,namelen); + pstrcpy(fname, pname); DEBUG(3,("trans2open %s mode=%d attr=%d ofun=%d size=%d\n", fname,open_mode, open_attr, open_ofun, open_size)); @@ -3202,7 +3200,7 @@ unsigned int suwcnt = SVAL(inbuf, smb_suwcnt); unsigned int tran_call = SVAL(inbuf, smb_setup0); char *params = NULL, *data = NULL; - int num_params, num_params_sofar, num_data, num_data_sofar; + unsigned int num_params, num_params_sofar, num_data, num_data_sofar; START_PROFILE(SMBtrans2); if(global_oplock_break && (tran_call == TRANSACT2_OPEN)) { @@ -3241,10 +3239,10 @@ (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) { DEBUG(2,("Got Trans2 DevIOctl jobid\n")); } else { - DEBUG(2,("Invalid smb_sucnt in trans2 call(%d)\n",suwcnt)); + DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",suwcnt)); DEBUG(2,("Transaction is %d\n",tran_call)); END_PROFILE(SMBtrans2); - return ERROR_DOS(ERRSRV,ERRerror); + ERROR_DOS(ERRDOS,ERRinvalidparam); } } @@ -3270,10 +3268,22 @@ if (num_params > total_params || num_data > total_data) exit_server("invalid params in reply_trans2"); - if(params) - memcpy( params, smb_base(inbuf) + SVAL(inbuf, smb_psoff), num_params); - if(data) - memcpy( data, smb_base(inbuf) + SVAL(inbuf, smb_dsoff), num_data); + if(params) { + unsigned int psoff = SVAL(inbuf, smb_psoff); + if ((psoff + num_params < psoff) || (psoff + num_params < num_params)) + goto bad_param; + if (smb_base(inbuf) + psoff + num_params > inbuf + length) + goto bad_param; + memcpy( params, smb_base(inbuf) + psoff, num_params); + } + if(data) { + unsigned int dsoff = SVAL(inbuf, smb_dsoff); + if ((dsoff + num_data < dsoff) || (dsoff + num_data < num_data)) + goto bad_param; + if (smb_base(inbuf) + dsoff + num_data > inbuf + length) + goto bad_param; + memcpy( data, smb_base(inbuf) + dsoff, num_data); + } if(num_data_sofar < total_data || num_params_sofar < total_params) { /* We need to send an interim response then receive the rest @@ -3285,6 +3295,10 @@ while (num_data_sofar < total_data || num_params_sofar < total_params) { BOOL ret; + unsigned int param_disp; + unsigned int param_off; + unsigned int data_disp; + unsigned int data_off; ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT); @@ -3296,25 +3310,55 @@ else DEBUG(0,("reply_trans2: %s in getting secondary trans2 response.\n", (smb_read_error == READ_ERROR) ? "error" : "timeout" )); - SAFE_FREE(params); - SAFE_FREE(data); - END_PROFILE(SMBtrans2); - return ERROR_DOS(ERRSRV,ERRerror); + goto bad_param; } /* Revise total_params and total_data in case they have changed downwards */ + if (SVAL(inbuf, smb_tpscnt) < total_params) total_params = SVAL(inbuf, smb_tpscnt); + if (SVAL(inbuf, smb_tdscnt) < total_data) total_data = SVAL(inbuf, smb_tdscnt); - num_params_sofar += (num_params = SVAL(inbuf,smb_spscnt)); - num_data_sofar += ( num_data = SVAL(inbuf, smb_sdscnt)); + + num_params = SVAL(inbuf,smb_spscnt); + param_off = SVAL(inbuf, smb_spsoff); + param_disp = SVAL(inbuf, smb_spsdisp); + num_params_sofar += num_params; + + num_data = SVAL(inbuf, smb_sdscnt); + data_off = SVAL(inbuf, smb_sdsoff); + data_disp = SVAL(inbuf, smb_sdsdisp); + num_data_sofar += num_data; + if (num_params_sofar > total_params || num_data_sofar > total_data) - exit_server("data overflow in trans2"); + goto bad_param; - memcpy( ¶ms[ SVAL(inbuf, smb_spsdisp)], - smb_base(inbuf) + SVAL(inbuf, smb_spsoff), num_params); - memcpy( &data[SVAL(inbuf, smb_sdsdisp)], - smb_base(inbuf)+ SVAL(inbuf, smb_sdsoff), num_data); + if (num_params) { + if (param_disp + num_params >= total_params) + goto bad_param; + if ((param_disp + num_params < param_disp) || + (param_disp + num_params < num_params)) + goto bad_param; + if (smb_base(inbuf) + param_off + num_params >= inbuf + bufsize) + goto bad_param; + if (params + param_disp < params) + goto bad_param; + + memcpy( ¶ms[param_disp], smb_base(inbuf) + param_off, num_params); + } + if (num_data) { + if (data_disp + num_data >= total_data) + goto bad_param; + if ((data_disp + num_data < data_disp) || + (data_disp + num_data < num_data)) + goto bad_param; + if (smb_base(inbuf) + data_off + num_data >= inbuf + bufsize) + goto bad_param; + if (data + data_disp < data) + goto bad_param; + + memcpy( &data[data_disp], smb_base(inbuf) + data_off, num_data); + } } } @@ -3427,4 +3471,11 @@ return outsize; /* If a correct response was needed the call_trans2xxx calls have already sent it. If outsize != -1 then it is returning */ + + bad_param: + + SAFE_FREE(params); + SAFE_FREE(data); + END_PROFILE(SMBtrans2); + return ERROR_NT(NT_STATUS_INVALID_PARAMETER); } diff -uBb -r samba-2.2.7a/source/smbd/vfs-wrap.c samba-2.2.7b/source/smbd/vfs-wrap.c --- samba-2.2.7a/source/smbd/vfs-wrap.c Tue Dec 10 08:58:17 2002 +++ samba-2.2.7b/source/smbd/vfs-wrap.c Sun Apr 6 20:47:58 2003 @@ -213,8 +213,9 @@ static int copy_reg(const char *source, const char *dest) { SMB_STRUCT_STAT source_stats; - int ifd; - int ofd; + int saved_errno; + int ifd = -1; + int ofd = -1; if (sys_lstat (source, &source_stats) == -1) return -1; @@ -222,42 +223,44 @@ if (!S_ISREG (source_stats.st_mode)) return -1; - if (unlink (dest) && errno != ENOENT) - return -1; - if((ifd = sys_open (source, O_RDONLY, 0)) < 0) return -1; - if((ofd = sys_open (dest, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0 ) { - int saved_errno = errno; - close (ifd); - errno = saved_errno; + if (unlink (dest) && errno != ENOENT) return -1; - } - if (transfer_file(ifd, ofd, (size_t)-1) == -1) { - int saved_errno = errno; - close (ifd); - close (ofd); - unlink (dest); - errno = saved_errno; - return -1; - } +#ifdef O_NOFOLLOW + if((ofd = sys_open (dest, O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0600)) < 0 ) +#else + if((ofd = sys_open (dest, O_WRONLY | O_CREAT | O_TRUNC , 0600)) < 0 ) +#endif + goto err; - if (close (ifd) == -1) { - int saved_errno = errno; - close (ofd); - errno = saved_errno; - return -1; - } - if (close (ofd) == -1) - return -1; + if (transfer_file(ifd, ofd, (size_t)-1) == -1) + goto err; /* - * chown turns off set[ug]id bits for non-root, + * Try to preserve ownership. For non-root it might fail, but that's ok. + * But root probably wants to know, e.g. if NFS disallows it. + */ + + if ((fchown(ofd, source_stats.st_uid, source_stats.st_gid) == -1) && (errno != EPERM)) + goto err; + + /* + * fchown turns off set[ug]id bits for non-root, * so do the chmod last. */ + if (fchmod (ofd, source_stats.st_mode & 07777)) + goto err; + + if (close (ifd) == -1) + goto err; + + if (close (ofd) == -1) + return -1; + /* Try to copy the old file's modtime and access time. */ { struct utimbuf tv; @@ -267,21 +270,19 @@ utime (dest, &tv); } - /* - * Try to preserve ownership. For non-root it might fail, but that's ok. - * But root probably wants to know, e.g. if NFS disallows it. - */ - - if ((chown(dest, source_stats.st_uid, source_stats.st_gid) == -1) && (errno != EPERM)) - return -1; - - if (chmod (dest, source_stats.st_mode & 07777)) - return -1; - if (unlink (source) == -1) return -1; return 0; + + err: + saved_errno = errno; + if (ifd != -1) + close(ifd); + if (ofd != -1) + close(ofd); + errno = saved_errno; + return -1; } int vfswrap_rename(connection_struct *conn, const char *oldname, const char *newname)