📄 ch08_18.htm
字号:
<HTML><HEAD><TITLE>Recipe 8.17. Testing a File for Trustworthiness (Perl Cookbook)</TITLE><METANAME="DC.title"CONTENT="Perl Cookbook"><METANAME="DC.creator"CONTENT="Tom Christiansen & Nathan Torkington"><METANAME="DC.publisher"CONTENT="O'Reilly & Associates, Inc."><METANAME="DC.date"CONTENT="1999-07-02T01:38:55Z"><METANAME="DC.type"CONTENT="Text.Monograph"><METANAME="DC.format"CONTENT="text/html"SCHEME="MIME"><METANAME="DC.source"CONTENT="1-56592-243-3"SCHEME="ISBN"><METANAME="DC.language"CONTENT="en-US"><METANAME="generator"CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"><LINKREV="made"HREF="mailto:online-books@oreilly.com"TITLE="Online Books Comments"><LINKREL="up"HREF="ch08_01.htm"TITLE="8. File Contents"><LINKREL="prev"HREF="ch08_17.htm"TITLE="8.16. Reading Configuration Files"><LINKREL="next"HREF="ch08_19.htm"TITLE="8.18. Program: tailwtmp"></HEAD><BODYBGCOLOR="#FFFFFF"><img alt="Book Home" border="0" src="gifs/smbanner.gif" usemap="#banner-map" /><map name="banner-map"><area shape="rect" coords="1,-2,616,66" href="index.htm" alt="Perl Cookbook"><area shape="rect" coords="629,-11,726,25" href="jobjects/fsearch.htm" alt="Search this book" /></map><div class="navbar"><p><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch08_17.htm"TITLE="8.16. Reading Configuration Files"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 8.16. Reading Configuration Files"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><B><FONTFACE="ARIEL,HELVETICA,HELV,SANSERIF"SIZE="-1"><ACLASS="chapter"REL="up"HREF="ch08_01.htm"TITLE="8. File Contents"></A></FONT></B></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch08_19.htm"TITLE="8.18. Program: tailwtmp"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 8.18. Program: tailwtmp"BORDER="0"></A></TD></TR></TABLE></DIV><DIVCLASS="sect1"><H2CLASS="sect1"><ACLASS="title"NAME="ch08-27276">8.17. Testing a File for Trustworthiness</A></H2><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch08-pgfId-1594">Problem<ACLASS="indexterm"NAME="ch08-idx-1000004720-0"></A><ACLASS="indexterm"NAME="ch08-idx-1000004720-1"></A><ACLASS="indexterm"NAME="ch08-idx-1000004720-2"></A></A></H3><PCLASS="para">You want to read from a file, perhaps because it has configuration information. You only want to use the file if it can't be written to (or perhaps not even be read from) by anyone else than its owner.</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch08-pgfId-1600">Solution</A></H3><PCLASS="para">Use the <CODECLASS="literal">stat</CODE><ACLASS="indexterm"NAME="ch08-idx-1000004728-0"></A> call to retrieve ownership and file permissions information. You can use the built-in version, which returns a list:</P><PRECLASS="programlisting">( $dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks ) = stat($filename) or die "no $filename: $!";$mode &= 07777; # discard file type info</PRE><PCLASS="para">Or you can use the by-name interface in:</P><PRECLASS="programlisting">$info = stat($filename) or die "no $filename: $!";if ($info->uid == 0) { print "Superuser owns $filename\n";} if ($info->atime > $info->mtime) { print "$filename has been read since it was written.\n";} </PRE></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch08-pgfId-1636">Discussion</A></H3><PCLASS="para">Usually you trust users to set file permissions as they wish. If they want others to read their files, or even to write to them, that's their business. Applications like editors, mailers, and shells are often more discerning, though, refusing to evaluate code in configuration files if anyone but the owner can write to them. This helps avoid Trojan horses attacks. Security-minded programs like <EMCLASS="emphasis">ftp</EM> and <EMCLASS="emphasis">rlogin</EM> may even reject config files that can be read by anyone but their owner.</P><PCLASS="para">If the file is writable by someone other than the owner or is owned by someone other than the current user or the superuser, it shouldn't be trusted. To figure out file ownership and permissions, the <CODECLASS="literal">stat</CODE> function is used. The following function returns true if the file is deemed safe and false otherwise. If the <CODECLASS="literal">stat</CODE> fails, <CODECLASS="literal">undef</CODE> is returned.</P><PRECLASS="programlisting">use File::stat;sub is_safe { my $path = shift; my $info = stat($path); return unless $info; # owner neither superuser nor me # the real uid is in stored in the $< variable if (($info->uid != 0) && ($info->uid != $<)) { return 0; } # check whether group or other can write file. # use 066 to detect either reading or writing if ($info->mode & 022) { # someone else can write this return 0 unless -d _; # non-directories aren't safe # but directories with the sticky bit (01000) are return 0 unless $info->mode & 01000; } return 1;}</PRE><PCLASS="para">A directory is considered safe even if others can write to it, provided that its mode 01000 (owner delete only) bit is set.</P><PCLASS="para">Careful programmers also ensure that no enclosing directory is writable. This is due to systems with the "<CODECLASS="literal">chown</CODE> giveaway" problem in which any user can give away a file they own and make it owned by someone else. The following function handles that by using the <CODECLASS="literal">is_safe</CODE><ACLASS="indexterm"NAME="ch08-idx-1000004726-0"></A> function to check every enclosing directory up to the root if it detects that you have the <CODECLASS="literal">chown</CODE> problem, for which it queries the <CODECLASS="literal">POSIX::sysconf</CODE>. If you don't have an unrestricted version of <CODECLASS="literal">chown</CODE>, the <CODECLASS="literal">is_verysafe</CODE><ACLASS="indexterm"NAME="ch08-idx-1000004727-0"></A> subroutine just calls <CODECLASS="literal">is_safe</CODE>. If you do have the problem, it walks up the filesystem tree until it reaches the root.</P><PRECLASS="programlisting">use Cwd;use POSIX qw(sysconf _PC_CHOWN_RESTRICTED);sub is_verysafe { my $path = shift; return is_safe($path) if sysconf(_PC_CHOWN_RESTRICTED); $path = getcwd() . '/' . $path if $path !~ m{^/}; do { return unless is_safe($path); $path =~ s#([^/]+|/)$##; # dirname $path =~ s#/$## if length($path) > 1; # last slash } while length $path; return 1;}</PRE><PCLASS="para">To use this in a program, try something like this:</P><PRECLASS="programlisting">$file = "$ENV{HOME}/.myprogrc";readconfig($file) if is_safe($file);</PRE><PCLASS="para">This has potential for a race condition, because it's presumed that the hypothetical <CODECLASS="literal">readconfig</CODE> function will open the file. Between the time when <CODECLASS="literal">is_safe</CODE> checks the file's stats and when <CODECLASS="literal">readconfig</CODE> opens it, something wicked could theoretically occur. To avoid this, pass <CODECLASS="literal">is_safe</CODE> the already open filehandle, which is set up to handle this:</P><PRECLASS="programlisting">$file = "$ENV{HOME}/.myprogrc";if (open(FILE, "< $file")) { readconfig(*FILE) if is_safe(*FILE);}</PRE><PCLASS="para">You would still have to arrange for <CODECLASS="literal">readconfig</CODE> to accept a filehandle instead of a filename, though.<ACLASS="indexterm"NAME="ch08-idx-1000004722-0"></A><ACLASS="indexterm"NAME="ch08-idx-1000004722-1"></A><ACLASS="indexterm"NAME="ch08-idx-1000004722-2"></A></P></DIV></DIV><DIVCLASS="htmlnav"><P></P><HRALIGN="LEFT"WIDTH="684"TITLE="footer"><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch08_17.htm"TITLE="8.16. Reading Configuration Files"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 8.16. Reading Configuration Files"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><ACLASS="book"HREF="index.htm"TITLE="Perl Cookbook"><IMGSRC="../gifs/txthome.gif"ALT="Perl Cookbook"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch08_19.htm"TITLE="8.18. Program: tailwtmp"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 8.18. Program: tailwtmp"BORDER="0"></A></TD></TR><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228">8.16. Reading Configuration Files</TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><ACLASS="index"HREF="index/index.htm"TITLE="Book Index"><IMGSRC="../gifs/index.gif"ALT="Book Index"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228">8.18. Program: tailwtmp</TD></TR></TABLE><HRALIGN="LEFT"WIDTH="684"TITLE="footer"><FONTSIZE="-1"></DIV<!-- LIBRARY NAV BAR --> <img src="../gifs/smnavbar.gif" usemap="#library-map" border="0" alt="Library Navigation Links"><p> <a href="copyrght.htm">Copyright © 2002</a> O'Reilly & Associates. All rights reserved.</font> </p> <map name="library-map"> <area shape="rect" coords="1,0,85,94" href="../index.htm"><area shape="rect" coords="86,1,178,103" href="../lwp/index.htm"><area shape="rect" coords="180,0,265,103" href="../lperl/index.htm"><area shape="rect" coords="267,0,353,105" href="../perlnut/index.htm"><area shape="rect" coords="354,1,446,115" href="../prog/index.htm"><area shape="rect" coords="448,0,526,132" href="../tk/index.htm"><area shape="rect" coords="528,1,615,119" href="../cookbook/index.htm"><area shape="rect" coords="617,0,690,135" href="../pxml/index.htm"></map> </BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -