Author: mvidner Date: Thu Jan 5 18:03:40 2012 New Revision: 67117 URL: http://svn.opensuse.org/viewcvs/yast?rev=67117&view=rev Log: - ini-agent: added Write(.section_private.SECTION, BOOLEAN) (bnc#713661, CVE-2011-3177) - system agent: added Write(.target.string, [filename, mode], content) svn merge -r66758:66764 http://svn.opensuse.org/svn/yast/branches/SuSE-Code-11-SP2-Branch/core Added: trunk/core/agent-ini/testsuite/multi/private.err trunk/core/agent-ini/testsuite/multi/private.in.1 trunk/core/agent-ini/testsuite/multi/private.in.2 trunk/core/agent-ini/testsuite/multi/private.out trunk/core/agent-ini/testsuite/multi/private.scr trunk/core/agent-ini/testsuite/multi/private.ycp (with props) Modified: trunk/core/ (props changed) trunk/core/VERSION trunk/core/agent-ini/doc/ag_ini.html trunk/core/agent-ini/src/IniAgent.cc trunk/core/agent-ini/src/IniFile.cc trunk/core/agent-ini/src/IniFile.h trunk/core/agent-ini/src/IniParser.cc trunk/core/agent-ini/src/IniParser.h trunk/core/agent-system/src/SystemAgent.cc trunk/core/agent-system/testsuite/tests/string.out trunk/core/agent-system/testsuite/tests/string.ycp trunk/core/package/yast2-core.changes Modified: trunk/core/VERSION URL: http://svn.opensuse.org/viewcvs/yast/trunk/core/VERSION?rev=67117&r1=67116&r2=67117&view=diff ============================================================================== --- trunk/core/VERSION (original) +++ trunk/core/VERSION Thu Jan 5 18:03:40 2012 @@ -1 +1 @@ -2.22.0 +2.22.1 Modified: trunk/core/agent-ini/doc/ag_ini.html URL: http://svn.opensuse.org/viewcvs/yast/trunk/core/agent-ini/doc/ag_ini.html?rev=67117&r1=67116&r2=67117&view=diff ============================================================================== --- trunk/core/agent-ini/doc/ag_ini.html (original) +++ trunk/core/agent-ini/doc/ag_ini.html Thu Jan 5 18:03:40 2012 @@ -280,7 +280,7 @@ <p>Then begin regexp is: ([^=]+)="([^"]*) and end regexp is ([^"]"). These are compared at the end so they are the last possibility. But once we get into this "divided line" by accident, -it becomes greedy, so be carefull to forgotten ". If "multiline" is +it becomes greedy, so be carefull to forgotten ". If "multiline" is not present, this mechanism does not take in effect of course.</p> <p>See also the option http://svn.opensuse.org/viewcvs/yast/trunk/core/agent-ini/src/IniAgent.cc?rev=67117&r1=67116&r2=67117&view=diff ============================================================================== --- trunk/core/agent-ini/src/IniAgent.cc (original) +++ trunk/core/agent-ini/src/IniAgent.cc Thu Jan 5 18:03:40 2012 @@ -98,7 +98,7 @@ else { if (( parser.repeatNames () && value->isList ()) || - (!parser.repeatNames () && (value->isString () || value->isInteger())) || + (!parser.repeatNames () && (value->isString () || value->isBoolean() || value->isInteger())) || path->component_str(0) == "all" ) { Modified: trunk/core/agent-ini/src/IniFile.cc URL: http://svn.opensuse.org/viewcvs/yast/trunk/core/agent-ini/src/IniFile.cc?rev=67117&r1=67116&r2=67117&view=diff ============================================================================== --- trunk/core/agent-ini/src/IniFile.cc (original) +++ trunk/core/agent-ini/src/IniFile.cc Thu Jan 5 18:03:40 2012 @@ -75,6 +75,19 @@ return YCPNull (); } +/** + * Return the YCPBoolean or YCPNull if it is not one. Log an error. + */ +static +YCPBoolean as_boolean (const YCPValue& v, const char * context) +{ + if (v->isBoolean ()) + return v->asBoolean (); + ycp2error ("Expected a boolean for %s, got %s %s", + context, v->valuetype_str(), v->toString().c_str()); + return YCPNull (); +} + void IniSection::initValue (const string&key,const string&val,const string&comment,int rb) { string k = ip->changeCase (key); @@ -486,6 +499,9 @@ return setSectionProp (p, v, 0, 1); if (s == "st" || s == "section_type" || s == "sectiontype") return setSectionProp (p, v, rewrite? 1:2, 1); + if (s == "section_private") + return setSectionProp (p, v, 3, 1); + return -1; } @@ -591,12 +607,18 @@ return -1; s.setRewriteBy (i->value()); } - else { + else if (what == 2) { YCPInteger i = as_integer (prop, "section_type"); if (i.isNull()) return -1; s.setReadBy (i->value()); } + else if (what == 3) { + YCPBoolean b = as_boolean (prop, "section_private"); + if (b.isNull()) + return -1; + s.setPrivate (b->value()); + } if (xi != xe) { Modified: trunk/core/agent-ini/src/IniFile.h URL: http://svn.opensuse.org/viewcvs/yast/trunk/core/agent-ini/src/IniFile.h?rev=67117&r1=67116&r2=67117&view=diff ============================================================================== --- trunk/core/agent-ini/src/IniFile.h (original) +++ trunk/core/agent-ini/src/IniFile.h Thu Jan 5 18:03:40 2012 @@ -241,6 +241,13 @@ */ string end_comment; + /** + * It is effective only when the section corresponds to a file. + * The file will not be readable by group and others. + * bnc#713661 + */ + bool is_private; + /** index to IniParser::rewrites for filename - section name mapping * It appears that read_by was used for both purposes, * causing bug (#19066). @@ -435,7 +442,7 @@ IniSection (const IniParser *p) : IniBase (-1), ip (p), - end_comment (), rewrite_by(-1), + end_comment (), is_private(false), rewrite_by(-1), container (), ivalues (), isections () {} @@ -446,7 +453,7 @@ IniSection (const IniSection &s) : IniBase (s), ip (s.ip), - end_comment (s.end_comment), rewrite_by (s.rewrite_by), + end_comment (s.end_comment), is_private(s.is_private), rewrite_by (s.rewrite_by), container (s.container) { reindex (); } @@ -458,7 +465,9 @@ } IniBase::operator = (s); ip = s.ip; - end_comment = s.end_comment; rewrite_by = s.rewrite_by; + end_comment = s.end_comment; + is_private = s.is_private; + rewrite_by = s.rewrite_by; container = s.container; reindex (); @@ -474,7 +483,7 @@ IniSection (const IniParser *p, string n) : IniBase (n), ip (p), - end_comment (), rewrite_by(0), + end_comment (), is_private(false), rewrite_by(0), container(), ivalues (), isections () {} /** @@ -511,6 +520,9 @@ */ int getSubSectionRewriteBy (const char*name); + void setPrivate(bool p) { is_private = p; } + bool isPrivate() const { return is_private; } + /** * If there is no comment at the beginning and no values and no * sections, it is better to set is as comment at the beginning. Modified: trunk/core/agent-ini/src/IniParser.cc URL: http://svn.opensuse.org/viewcvs/yast/trunk/core/agent-ini/src/IniParser.cc?rev=67117&r1=67116&r2=67117&view=diff ============================================================================== --- trunk/core/agent-ini/src/IniParser.cc (original) +++ trunk/core/agent-ini/src/IniParser.cc Thu Jan 5 18:03:40 2012 @@ -965,19 +965,7 @@ continue; } s.initReadBy (); - // ensure that the directories exist - Pathname pn (filename); - PathInfo::assert_dir (pn.dirname ()); - ofstream of(filename.c_str()); - if (!of.good()) - { - bugs++; - y2error ("Can not open file %s for write", filename.c_str()); - continue; - } - write_helper (s, of, 0); - s.clean(); - of.close (); + bugs += write_file(filename, s); } else { @@ -997,24 +985,37 @@ } else { - // ensure that the directories exist - Pathname pn (file); - PathInfo::assert_dir (pn.dirname ()); - ofstream of(file.c_str()); - if (!of.good()) - { - y2error ("Can not open file %s for write", file.c_str()); - return -1; - } - - write_helper (inifile, of, 0); - - of.close(); + bugs += write_file(file, inifile); timestamp = getTimeStamp (); } - inifile.clean (); return bugs ? -1 : 0; } + +// return 0 on success, like write +int IniParser::write_file(const string & filename, IniSection & section) +{ + // ensure that the directories exist + Pathname pn(filename); + PathInfo::assert_dir (pn.dirname ()); + + mode_t file_umask = section.isPrivate()? 0077: 0022; + mode_t orig_umask = umask(file_umask); + // rewriting an existing file wouldnt change its mode + unlink(filename.c_str()); + + ofstream of(filename.c_str()); + if (!of.good()) { + y2error ("Can not open file %s for write", filename.c_str()); + return -1; + } + + write_helper (section, of, 0); + + of.close(); + umask(orig_umask); + return 0; +} + int IniParser::write_helper(IniSection&ini, ofstream&of, int depth) { char * out_buffer; Modified: trunk/core/agent-ini/src/IniParser.h URL: http://svn.opensuse.org/viewcvs/yast/trunk/core/agent-ini/src/IniParser.h?rev=67117&r1=67116&r2=67117&view=diff ============================================================================== --- trunk/core/agent-ini/src/IniParser.h (original) +++ trunk/core/agent-ini/src/IniParser.h Thu Jan 5 18:03:40 2012 @@ -372,6 +372,10 @@ /** * Write one ini file. */ + int write_file(const string & filename, IniSection & section); + /** + * Write one ini file. + */ int write_helper(IniSection&ini, ofstream&of,int depth); public: /** Added: trunk/core/agent-ini/testsuite/multi/private.err URL: http://svn.opensuse.org/viewcvs/yast/trunk/core/agent-ini/testsuite/multi/private.err?rev=67117&view=auto ============================================================================== --- trunk/core/agent-ini/testsuite/multi/private.err (added) +++ trunk/core/agent-ini/testsuite/multi/private.err Thu Jan 5 18:03:40 2012 @@ -0,0 +1,11 @@ +[agent-ini] IniParser.cc(parse):XXX Rewriting multi/private.in.1.test to 1 +[agent-ini] IniParser.cc(parse):XXX Rewriting multi/private.in.2.test to 2 +[agent-ini] IniFile.cc(setMyValue):XXX Adding value .v."1"."Totalise"."Password" = "Secret password" +[agent-ini] IniFile.cc(setMyValue):XXX Adding value .v."2"."arcor"."Password" = "Public password" +[agent-ini] IniParser.cc(parse):XXX Rewriting multi/private.in.1.test to 1 +[agent-ini] IniParser.cc(parse):XXX Rewriting multi/private.in.2.test to 2 +[agent-ini] IniParser.cc(getFileName):XXX Rewriting 1 to multi/private.in.1.test +[agent-ini] IniParser.cc(getFileName):XXX Rewriting 2 to multi/private.in.2.test +[YCP] multi/private.ycp:XXX secret file mode: $["exit":0, "stderr":"", "stdout":"600\n"] +[YCP] multi/private.ycp:XXX public file mode: $["exit":0, "stderr":"", "stdout":"644\n"] +[agent-ini] IniParser.cc(write):XXX File multi/private.in.*.test did not change. Not saving. Added: trunk/core/agent-ini/testsuite/multi/private.in.1 URL: http://svn.opensuse.org/viewcvs/yast/trunk/core/agent-ini/testsuite/multi/private.in.1?rev=67117&view=auto ============================================================================== --- trunk/core/agent-ini/testsuite/multi/private.in.1 (added) +++ trunk/core/agent-ini/testsuite/multi/private.in.1 Thu Jan 5 18:03:40 2012 @@ -0,0 +1,10 @@ +[Dialer Totalise] +Compuserve = 0 +Provider = Totalise +Phone = 08453001470 +[End] + +[Dialer force9] +Provider = Force9 +Phone = 08451424000 +[End] Added: trunk/core/agent-ini/testsuite/multi/private.in.2 URL: http://svn.opensuse.org/viewcvs/yast/trunk/core/agent-ini/testsuite/multi/private.in.2?rev=67117&view=auto ============================================================================== --- trunk/core/agent-ini/testsuite/multi/private.in.2 (added) +++ trunk/core/agent-ini/testsuite/multi/private.in.2 Thu Jan 5 18:03:40 2012 @@ -0,0 +1,11 @@ +[Dialer arcor] +Compuserve = 0 +Provider = Arcor +[End] + +[Dialer mobilcom] +Compuserve = 0 +Provider = Mobilcom +Phone = 0101901929 +[End] + Added: trunk/core/agent-ini/testsuite/multi/private.out URL: http://svn.opensuse.org/viewcvs/yast/trunk/core/agent-ini/testsuite/multi/private.out?rev=67117&view=auto ============================================================================== --- trunk/core/agent-ini/testsuite/multi/private.out (added) +++ trunk/core/agent-ini/testsuite/multi/private.out Thu Jan 5 18:03:40 2012 @@ -0,0 +1,25 @@ +(nil) +multi/private.in.1.test ------------------------------- +[Dialer Totalise] + Compuserve = 0 + Provider = Totalise + Phone = 08453001470 + Password = Secret password +[End] + +[Dialer force9] + Provider = Force9 + Phone = 08451424000 +[End] +multi/private.in.2.test ------------------------------- +[Dialer arcor] + Compuserve = 0 + Provider = Arcor + Password = Public password +[End] + +[Dialer mobilcom] + Compuserve = 0 + Provider = Mobilcom + Phone = 0101901929 +[End] Added: trunk/core/agent-ini/testsuite/multi/private.scr URL: http://svn.opensuse.org/viewcvs/yast/trunk/core/agent-ini/testsuite/multi/private.scr?rev=67117&view=auto ============================================================================== --- trunk/core/agent-ini/testsuite/multi/private.scr (added) +++ trunk/core/agent-ini/testsuite/multi/private.scr Thu Jan 5 18:03:40 2012 @@ -0,0 +1,24 @@ +. + +`ag_ini( + `IniAgent( [ "multi/private.in.*.test" ], + $[ + "rewrite" : [ + [ "multi/private\.in\.(.)\.test$", "multi/private.in.%s.test"], + ], + "subindent" : " ", + "comments": [ "^[ \t]*#.*", "^[ \t]*$" ], + "sections" : [ + $[ + "begin" : [ "[ \t]*\\[Dialer[ \t]+(.*[^ \t])[ \t]*\\][ \t]*", "[Dialer %s]" ], + "end" : [ "^[ \t]*\\[End\\][ \t]*$", "[End]", ], + ], + ], + "params" : [ + $[ + "match" : [ "^[ \t]*([^=]*[^ \t=])[ \t]*=[ \t]*(.*[^ \t]|)[ \t]*$" , "%s = %s"], + ], + ], + ] + ) +) Added: trunk/core/agent-ini/testsuite/multi/private.ycp URL: http://svn.opensuse.org/viewcvs/yast/trunk/core/agent-ini/testsuite/multi/private.ycp?rev=67117&view=auto ============================================================================== --- trunk/core/agent-ini/testsuite/multi/private.ycp (added) +++ trunk/core/agent-ini/testsuite/multi/private.ycp Thu Jan 5 18:03:40 2012 @@ -0,0 +1,26 @@ +// +// Multiple files test +// +// providers.rpm +// + + +{ + SCR::RegisterAgent (.target, `ag_system ()); + any out = nil; + + SCR::Write (.v."1"."Totalise"."Password", "Secret password"); + SCR::Write (.section_private."1", true); + + SCR::Write (.v."2"."arcor"."Password", "Public password"); + + SCR::Write (., nil); //flush + + out = SCR::Execute (.target.bash_output, "stat -c %a multi/private.in.1.test"); + y2milestone("secret file mode: %1", out); + + out = SCR::Execute (.target.bash_output, "stat -c %a multi/private.in.2.test"); + y2milestone("public file mode: %1", out); + + return nil; +} Modified: trunk/core/agent-system/src/SystemAgent.cc URL: http://svn.opensuse.org/viewcvs/yast/trunk/core/agent-system/src/SystemAgent.cc?rev=67117&r1=67116&r2=67117&view=diff ============================================================================== --- trunk/core/agent-system/src/SystemAgent.cc (original) +++ trunk/core/agent-system/src/SystemAgent.cc Thu Jan 5 18:03:40 2012 @@ -709,25 +709,50 @@ { /** * @builtin Write (.target.string, string filename, string value) -> boolean + * @builtin Write (.target.string, [string filename, integer filemode] , string value) -> boolean * Writes the string <tt>value</tt> into a file. If the file already * exists, the existing file is overwritten. The return value is * true, if the file has been written successfully. + * + * @example Write(.target.string, "/etc/papersize", "a4") -> true + * @example Write(.target.string, ["/etc/rsyncd.secrets", 0600], "user:passwd") -> true */ - if (value.isNull() || !value->isString()) + if (value.isNull() || !(value->isString() || value->isList())) { ycp2error ("Bad filename arg for Write (.string ...)"); return YCPBoolean (false); } + string filename; + mode_t filemode = 0644; + + if (value->isString()) + { + filename = value->asString()->value(); + } + else + { // value is list + YCPList flist = value->asList(); + if ((flist->size() != 2) + || (!flist->value(0)->isString()) + || (!flist->value(1)->isInteger())) + { + ycp2error ("Bad [filename, mode] list in call to Write (%s, [ string filename, integer mode ], ...)", + cmd.c_str ()); + return YCPBoolean (false); + } + filename = flist->value(0)->asString()->value(); + filemode = (int)(flist->value(1)->asInteger()->value()); + } + if (arg.isNull() || !arg->isString()) { ycp2error ("Bad string value for Write (.string ...)"); return YCPBoolean (false); } - string filename = value->asString()->value(); - int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644); + int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, filemode); if (fd >= 0) { string cont = arg->asString()->value(); @@ -1039,8 +1064,8 @@ * Creates a symbolic link named newpath which contains the * string oldpath. * - * Symbolic links are interpreted at run-time as if the con - * tents of the link had been substituted into the path being + * Symbolic links are interpreted at run-time as if the contents + * of the link had been substituted into the path being * followed to find a file or directory. * * The return value is true or false, depending of the success. Modified: trunk/core/agent-system/testsuite/tests/string.out URL: http://svn.opensuse.org/viewcvs/yast/trunk/core/agent-system/testsuite/tests/string.out?rev=67117&r1=67116&r2=67117&view=diff ============================================================================== --- trunk/core/agent-system/testsuite/tests/string.out (original) +++ trunk/core/agent-system/testsuite/tests/string.out Thu Jan 5 18:03:40 2012 @@ -3,3 +3,4 @@ (true) (nil) ("never mind") +("secret file mode: 600\n") Modified: trunk/core/agent-system/testsuite/tests/string.ycp URL: http://svn.opensuse.org/viewcvs/yast/trunk/core/agent-system/testsuite/tests/string.ycp?rev=67117&r1=67116&r2=67117&view=diff ============================================================================== --- trunk/core/agent-system/testsuite/tests/string.ycp (original) +++ trunk/core/agent-system/testsuite/tests/string.ycp Thu Jan 5 18:03:40 2012 @@ -24,3 +24,13 @@ // this must not produce a error in the log return SCR::Read (.string, ["not-here.txt", "never mind"]); } + +{ + map out = nil; + string filename = "tmp.secret.string"; + + SCR::Write (.string, [filename, 0600], "This is secret\n"); + + out = (map) SCR::Execute (.bash_output, "stat -c %a " + filename); + return "secret file mode: " + out["stdout"]:""; +} Modified: trunk/core/package/yast2-core.changes URL: http://svn.opensuse.org/viewcvs/yast/trunk/core/package/yast2-core.changes?rev=67117&r1=67116&r2=67117&view=diff ============================================================================== --- trunk/core/package/yast2-core.changes (original) +++ trunk/core/package/yast2-core.changes Thu Jan 5 18:03:40 2012 @@ -1,4 +1,12 @@ ------------------------------------------------------------------- +Mon Nov 7 18:19:27 CET 2011 - mvidner@suse.cz + +- ini-agent: added Write(.section_private.SECTION, BOOLEAN) + (bnc#713661, CVE-2011-3177) +- system agent: added Write(.target.string, [filename, mode], content) +- 2.22.1 + +------------------------------------------------------------------- Fri Dec 2 11:49:56 UTC 2011 - lslezak@suse.cz - process-agent - fixed testuite (removed potential race condition) -- To unsubscribe, e-mail: yast-commit+unsubscribe@opensuse.org For additional commands, e-mail: yast-commit+help@opensuse.org