Eric Blake <ebl...@redhat.com> wrote on 09/27/2010 04:52:31 PM: > > On 09/27/2010 12:40 PM, Stefan Berger wrote: > > V2 changes: > > following Eric's comments: > > - commands in the script are assigned using cmd='...' rather > than cmd="..." > > - invoke commands using eval res=... rather than res=eval ... > > - rewrote function escaping ` and single quotes (which became > more tricky) > > > > In this patch I am extending the rule instantiator to create the comment > > node where supported, which is the case for iptables and ip6tables. > > > > Since commands are written in the format > > > > cmd='iptables ...-m comment --comment \"\" ' > > > > certain characters ('`) in the comment need to be escaped to > > prevent comments from becoming commands themselves or cause other > > forms of (bash) substitutions. I have tested this with various input and in > > my tests the input made it straight into the comment. A test case for TCK > > will be provided separately that tests this. > > At first, I failed to see how ` needs escaping inside '', unless you > aren't uniformly using '' like you think you are. Then it hit me - yuck
> - we aren't uniformly using '' - we really do have to escape ` inside > ``, or come up with an alternate solution. That is: > > ret=`iptables -m comment --comment '`'` > > is indeed ill-formed. But if you are going to escape `, then you also > have to escape \ and $ for the same duration. Yuck again. I had tested these also and it doesn't seem to be the case. I looked like really only ` and ' needed special treatment. > > But fear not - I have a slicker solution: > > comment='comment with lone '\'', ", `, \, $x, and two spaces' > cmd='iptables ...-m comment --comment "$comment"' > eval ret=\`"$cmd"\` I changed this now for v3. > > which at expansion time results in: > > eval ret=\`"$cmd"\` > ret=`iptables ...-m comment --comment "$comment"` > iptables ...-m comment --comment \ > 'comment with lone '\'', `, ", `, \, $x, and two spaces' > > That is, rather than trying to pass the comment literally through $cmd > (and thus having to carefully escape $cmd for its eventual use inside > ``), it might be nicer to stick the comment in an intermediate variable > (where you only need to escape ') and make $cmd reference the > intermediate variable (where you won't have any problematic uses of ", > `, or ' to contend with, and where your only $ is one where you > intentionally want variable expansion). It's nicer, true, just a little more changes need for building the final command where a 'prefix', here the comment='' is stuck in front of the line with the iptables command. > > > @@ -52,10 +53,10 @@ > > > > > > #define CMD_SEPARATOR "\n" > > -#define CMD_DEF_PRE "cmd=\"" > > -#define CMD_DEF_POST "\"" > > +#define CMD_DEF_PRE "cmd='" > > +#define CMD_DEF_POST "'" > > #define CMD_DEF(X) CMD_DEF_PRE X CMD_DEF_POST > > -#define CMD_EXEC "res=`${cmd}`" CMD_SEPARATOR > > +#define CMD_EXEC "eval res=\\`\"${cmd}\"\\`" CMD_SEPARATOR > > This part seems okay - the ` is quoted to protect it from evaluation > until after eval has had a chance to collect its arguments. > > > +static char * > > +escapeComment(const char *buf) > > +{ > > + char *res; > > + size_t i, j, add = 0, len = strlen(buf); > > + > > + static const char SINGLEQUOTE_REPLACEMENT[12] = "'\\'\\\"\\'\\\"\\''"; > > That seems rather long to me. Broken into chunks with C-string escaping > eliminated: > > ' \'\"\'\"\' ' > end the current single quoting > the 5 literal shell chars '"'"' > resume single quoting > > I'm not following why we need 5 literal shell characters, instead of 1. > That's because I needed to place the ' in between "". Without it would not work. The first ' was to close the string in front and the final ' was to start another string. > > + > > + if (len > IPTABLES_MAX_COMMENT_SIZE) > > + len = IPTABLES_MAX_COMMENT_SIZE; > > + > > + for (i = 0; i < len; i++) { > > + if (buf[i] == '`') > > + add++; > > + else if (buf[i] == '\'') > > + add += sizeof(SINGLEQUOTE_REPLACEMENT); > > + } > > Back to my observation that this doesn't help for \ or $, the other two > characters that need escaping inside ``. It would be so much easier if > we could rely on $() instead of ``. Wait a minute - this is only done > for Linux hosts, where we are guaranteed a sane shell (it's pretty much > just Solaris where /bin/sh is too puny to do $()) - using $() instead of > `` would solve a lot of escaping issues. > > > @@ -993,6 +1034,16 @@ iptablesHandleIpHdr(virBufferPtr buf, > > } > > } > > > > + if (HAS_ENTRY_ITEM(&ipHdr->dataComment)) { > > + char *cmt = escapeComment(ipHdr->dataComment.u.string); > > + if (!cmt) > > + goto err_exit; > > + virBufferVSprintf(buf, > > + " -m comment --comment '\\''%s'\\''", > > + cmt); > > + VIR_FREE(cmt); > > OK, maybe I see why your comment had such a long replacement for ', > because you aren't adding any escaping to cmt here. But I still think > we can come up with a more elegant solution, by using the intermediate > variable. Thanks for forcing me to explain myself - it's an interesting > process thinking about this. > > > [Do I even dare mention that at an even higher layer, it might be nicer > to avoid /bin/sh in the first place, and instead put effort into my > pending virCommand API patches to make it easier to directly invoke all > the iptables commands from C?] I do also generate some scripts with 'if .. then' statements that won't be able to executed via your virCommand API... Stefan
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list