[quote user="David Harris"]
When Mercury checks AREPLY.KFS, it does the 48-hour check as part of the process... So, before examining the contents of AREPLY.KFS, it first checks the age of the file and removes it if it's too old. I'm fairly sure that this is what is leading to the sequence of log entries in Rolf's last post. Here's the actual code from Mercury that does this test:
sprintf (fname, "%s\\AREPLY.KFL", newmaildir);
if (check_existence (fname) != 0)
if (stat (fname, &statblk) == 0)
if ((time (NULL) - statblk.st_ctime) > killfile_lifetime)
remove (fname);
It checks to see whether or not the file exists: if it does, it calls "stat" (a posix runtime library function) to get the file time information and checks to see whether the file's creation time is more than 48 hours ago: if it is, it deletes the file.
Now, the only way this can happen, is if the Operating System is returning an invalid value for the "ctime" member of "statblk". Note also that for the file to be deleted, the call to "stat" has to be successful, so the value of "ctime" *should* be correct.
[/quote]
Did you mean AREPLY.KFL, or .KFS in your comment?
At present, one of my users has this precise issue. The Created date returned by Windows (right-click, get Properties) for the AREPLY.KFS and AREPLY.KFL files for said user is December 2005!
I suspect the "implementation-defined" behavior of remove() vs. unlink() might be an issue on Win32's "sort of POSIX" behavior. The Mercury code logic looks fine. I suspect remove() is not really removing and recreating the file, but rather keeping its old file creation date due to a lingering handle.
https://www.securecoding.cert.org/confluence/display/seccode/FIO08-A.+Take+care+when+calling+remove()+on+an+open+file states:
Invoking <tt>remove()</tt> on an open file is implementation-defined. Removing an open file is sometimes recommended to hide the names of temporary files that may prone to attack (see [TMP30-C. Temporary files must be created with unique and unpredictable file names]).
In cases when an open file needs to be removed, a more strongly defined function, such as the POSIX <tt>unlink()</tt> function, should be considered. To be strictly conforming and portable, <tt>remove()</tt> should not be called on an open file.
Non-Compliant Code Example
The following non-compliant code example illustrates a case where a file is removed while it is still open.
FILE *file;
/* ... */
file = fopen("myfile", "w+");
if (fopen == NULL) {
/* Handle error condition */
}
/* ... */
remove("myfile");
/* ... */
Some implementations will not remove <tt>"myfile"</tt> because the stream is still open.
Implementation Details
Code compiled using Microsoft Visual Studio C++ 2005 and run on Microsoft Windows XP, prevents the <tt>remove()</tt> call from succeeding when the file is open, meaning that the file link will remain after execution completes.
Compliant Solution (POSIX)
This compliant solution uses the POSIX <tt>unlink()</tt> function to remove the file. The <tt>unlink()</tt>
function is guaranteed to unlink the file from the file system
hierarchy but keep the file on disk until all open instances of the
file are closed) is used [Open Group 04].
#include <unistd.h>
FILE *file;
/* ... */
file = fopen("myfile", "w+");
if (fopen == NULL) {
/* Handle error condition */
}
unlink("myfile");
fclose("myfile");
Risk Assessment
Calling <tt>remove()</tt> on an open file has different implications
for different implementations and may cause abnormal termination if the
closed file is written to or read from, or may result in unintended
information disclosure from not actually deleting a file as intended.
[quote user="David Harris"]
<p>When Mercury checks AREPLY.KFS, it does the 48-hour check as part of the process... So, before examining the contents of AREPLY.KFS, it first checks the age of the file and removes it if it's too old. I'm fairly sure that this is what is leading to the sequence of log entries in Rolf's last post. Here's the actual code from Mercury that does this test:
<font face="courier new,courier">&nbsp;&nbsp; sprintf (fname, "%s\\AREPLY.KFL", newmaildir);
&nbsp;&nbsp; if (check_existence (fname) != 0)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (stat (fname, &amp;statblk) == 0)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((time (NULL) - statblk.st_ctime) &gt; killfile_lifetime)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; remove (fname);
</font>
It checks to see whether or not the file exists: if it does, it calls "stat" (a posix runtime library function) to get the file time information and checks to see whether the file's creation time is more than 48 hours ago: if it is, it deletes the file.
Now, the only way this can happen, is if the Operating System is returning an invalid value for the "ctime" member of "statblk". Note also that for the file to be deleted, the call to "stat" has to be successful, so the value of "ctime" *should* be correct.
</p><p>[/quote]</p><p>Did you mean AREPLY.KFL, or .KFS in your comment?</p><p>At present, one of my users has this precise issue. The Created date returned by Windows (right-click, get Properties) for the AREPLY.KFS and AREPLY.KFL files for said user is <b>December 2005!</b></p><p>I suspect the "implementation-defined" behavior of remove() vs. unlink() might be an issue on Win32's "sort of POSIX" behavior. The Mercury code logic looks fine. I suspect remove() is not really removing and recreating the file, but rather keeping its old file creation date due to a lingering handle.
</p><p>https://www.securecoding.cert.org/confluence/display/seccode/FIO08-A.+Take+care+when+calling+remove()+on+an+open+file states:</p><p>Invoking <tt>remove()</tt> on an open file is <a href="https://www.securecoding.cert.org/confluence/display/seccode/BB.+Definitions#BB.Definitions-implementationdefinedbehavior">implementation-defined</a>. Removing an open file is sometimes recommended to hide the names of temporary files that may prone to attack (see [<a href="https://www.securecoding.cert.org/confluence/display/seccode/TMP30-C.+Temporary+files+must+be+created+with+unique+and+unpredictable+file+names" title="TMP30-C. Temporary files must be created with unique and unpredictable file names">TMP30-C. Temporary files must be created with unique and unpredictable file names</a>]).</p>
<p>In cases when an open file needs to be removed, a more strongly defined function, such as the POSIX <tt>unlink()</tt> function, should be considered. To be strictly conforming and portable, <tt>remove()</tt> should <em>not</em> be called on an open file.</p>
<h2><a class="" name="FIO08-A.Takecarewhencallingremove()onanopenfile-NonCompliantCodeExample"></a>Non-Compliant Code Example</h2>
<p>The following non-compliant code example illustrates a case where a file is removed while it is still open.</p>
<div class="code panel" style="border-width: 1px; background-color: rgb(255, 204, 204);"><div class="codeContent panelContent" style="background-color: rgb(255, 204, 204);">
<pre class="code-java">FILE *file;
/* ... */
file = fopen(<span class="code-quote">"myfile"</span>, <span class="code-quote">"w+"</span>);
<span class="code-keyword">if</span> (fopen == NULL) {
/* Handle error condition */
}
/* ... */
remove(<span class="code-quote">"myfile"</span>);
/* ... */</pre>
</div></div>
<p>Some <a href="https://www.securecoding.cert.org/confluence/display/seccode/BB.+Definitions#BB.Definitions-implementation">implementations</a> will not remove <tt>"myfile"</tt> because the stream is still open.</p>
<h3><a class="" name="FIO08-A.Takecarewhencallingremove()onanopenfile-ImplementationDetails"></a>Implementation Details</h3>
<p>Code compiled using Microsoft Visual Studio C++ 2005 and run on Microsoft Windows XP, prevents the <tt>remove()</tt> call from succeeding when the file is open, meaning that the file link will remain after execution completes.</p>
<h2><a class="" name="FIO08-A.Takecarewhencallingremove()onanopenfile-CompliantSolution(POSIX)"></a>Compliant Solution (POSIX)</h2>
<p>This compliant solution uses the POSIX <tt>unlink()</tt> function to remove the file. The <tt>unlink()</tt>
function is guaranteed to unlink the file from the file system
hierarchy but keep the file on disk until all open instances of the
file are closed) is used [<a href="https://www.securecoding.cert.org/confluence/display/seccode/AA.+C+References#AA.CReferences-OpenGroup04">Open Group 04</a>].</p>
<div class="code panel" style="border-width: 1px; background-color: rgb(204, 204, 255);"><div class="codeContent panelContent" style="background-color: rgb(204, 204, 255);">
<pre class="code-java">#include &lt;unistd.h&gt;
FILE *file;
/* ... */
file = fopen(<span class="code-quote">"myfile"</span>, <span class="code-quote">"w+"</span>);
<span class="code-keyword">if</span> (fopen == NULL) {
/* Handle error condition */
}
unlink(<span class="code-quote">"myfile"</span>);
fclose(<span class="code-quote">"myfile"</span>);</pre>
</div></div>
<h2><a class="" name="FIO08-A.Takecarewhencallingremove()onanopenfile-RiskAssessment"></a>Risk Assessment</h2>
<p>Calling <tt>remove()</tt> on an open file has different implications
for different implementations and may cause abnormal termination if the
closed file is written to or read from, or may result in unintended
information disclosure from not actually deleting a file as intended.</p>