File netatalk.papd.quote-vars.fixed.patch of Package netatalk
quote chars correctly
---
etc/papd/lp.c | 214 ++++++++++++++++++++++++++++++++++------------------------
1 file changed, 127 insertions(+), 87 deletions(-)
--- a/etc/papd/lp.c
+++ b/etc/papd/lp.c
@@ -211,99 +211,137 @@ static void lp_setup_comments (charset_t
}
#define is_var(a, b) (strncmp((a), (b), 2) == 0)
+enum quote_state {
+ NONE,
+ QUOTEDBL,
+ APOSTROPHE,
+};
-static size_t quote(char *dest, char *src, const size_t bsize, size_t len)
+static size_t quote_var(char *dest, size_t destlen, enum quote_state qs, const char *untrusted)
{
-size_t used = 0;
+ char c = 0;
+ size_t len = 0;
- while (len && used < bsize ) {
- switch (*src) {
- case '$':
- case '\\':
- case '"':
- case '`':
- if (used + 2 > bsize )
- return used;
- *dest = '\\';
- dest++;
- used++;
- break;
- }
- *dest = *src;
- src++;
- dest++;
- len--;
- used++;
- }
- return used;
+ if (qs == NONE) {
+ *dest='\'';
+ dest++;
+ len++;
+ if (destlen > 1)
+ destlen--;
+ }
+ while (untrusted && (destlen - len) > 1 && (c = *untrusted)) {
+ if (c == '\'' && (qs == NONE || qs == APOSTROPHE)) {
+ /* man bash:
+ * A single quote may not occur between single quotes,
+ * even when preceded by a backslash.
+ */
+ c = '_';
+ } else if (qs == QUOTEDBL) {
+ switch (c) {
+ /* subshells are escaped
+ * no need to handle "& * # ' ; { } < >" */
+ case '"':
+ case '`':
+ case '$':
+ case '(':
+ case ')':
+ case '\\':
+ case '!':
+ *dest = '\\';
+ dest++;
+ len++;
+ default:
+ break;
+ }
+ } else if (c == '\\') {
+ *dest = '\\';
+ dest++;
+ len++;
+ }
+ *dest = c;
+ dest++;
+ len++;
+ untrusted++;
+ }
+ if (qs == NONE) {
+ *dest='\'';
+ dest++;
+ len++;
+ }
+ return len;
}
-
-static char* pipexlate(char *src)
+static char *pipexlate(char *src)
{
- char *p, *q, *dest;
- static char destbuf[MAXPATHLEN +1];
- size_t destlen = MAXPATHLEN;
- int len = 0;
-
- dest = destbuf;
-
- if (!src)
- return NULL;
-
- memset(dest, 0, MAXPATHLEN +1);
- if ((p = strchr(src, '%')) == NULL) { /* nothing to do */
- strncpy(dest, src, MAXPATHLEN);
- return destbuf;
- }
- /* first part of the path. copy and forward to the next variable. */
- len = MIN((size_t)(p - src), destlen);
- if (len > 0) {
- strncpy(dest, src, len);
- destlen -= len;
- dest += len;
- }
-
- while (p && destlen > 0) {
- /* now figure out what the variable is */
- q = NULL;
- if (is_var(p, "%U")) {
- q = lp.lp_person;
- } else if (is_var(p, "%C") || is_var(p, "%J") ) {
- q = lp.lp_job;
- } else if (is_var(p, "%F")) {
- q = lp.lp_created_for;
- } else if (is_var(p, "%%")) {
- q = "%";
- }
-
- /* copy the stuff over. if we don't understand something that we
- * should, just skip it over. */
- if (q) {
- len = MIN(strlen(q), destlen);
- len = quote(dest, q, destlen, len);
- }
- else {
- len = MIN(2, destlen);
- strncpy(dest, q, len);
- }
- dest += len;
- destlen -= len;
-
- /* stuff up to next % */
- src = p + 2;
- p = strchr(src, '%');
- len = p ? MIN((size_t)(p - src), destlen) : destlen;
- if (len > 0) {
- strncpy(dest, src, len);
- dest += len;
- destlen -= len;
- }
- }
- return destbuf;
+ char *dest, *p;
+ char c, *untrusted;
+ static char destbuf[MAXPATHLEN];
+ size_t destlen, vlen;
+ enum quote_state qs;
+
+ if (!src)
+ return NULL;
+
+ p = src;
+ dest = destbuf;
+ destlen = sizeof(destbuf) - 1;
+ qs = NONE;
+
+ while (destlen && (c = *src)) {
+ untrusted = NULL;
+ if (c == '%') {
+ switch (src[1]) {
+ /* %U */
+ case 'U':
+ untrusted = lp.lp_person;
+ break;
+ /* %C/%J */
+ case 'C':
+ case 'J':
+ untrusted = lp.lp_job;
+ break;
+ /* %F */
+ case 'F':
+ untrusted = lp.lp_created_for;
+ break;
+ /* %% */
+ case '%':
+ src++; /* forward to the % and continue copying */
+ /* Unhandled variable, just copy */
+ default:
+ break;
+ }
+ }
+ /* expand variables */
+ if (untrusted) {
+ vlen = quote_var(dest, destlen, qs, untrusted);
+ src += 2;
+ dest += vlen;
+ destlen -= vlen;
+ continue;
+ }
+ if (c == '\'') {
+ if (qs == NONE) {
+ qs = APOSTROPHE;
+ } else if (qs == APOSTROPHE) {
+ qs = NONE;
+ }
+ } else if (c == '"') {
+ if (qs == NONE) {
+ qs = QUOTEDBL;
+ } else if (qs == QUOTEDBL) {
+ qs = NONE;
+ }
+ }
+ *dest = c;
+ src++;
+ dest++;
+ destlen--;
+ }
+ *dest = '\0';
+ return destbuf;
}
-
void lp_person( person )
char *person;
{
@@ -570,6 +608,7 @@ int lp_open( out, sat )
}
if ( lp.lp_flags & LP_PIPE ) {
+ char *pipe_cmd;
/* go right to program */
if (lp.lp_person != NULL) {
@@ -583,12 +622,13 @@ int lp_open( out, sat )
}
lp_setup_comments(CH_UNIX);
- if (( lp.lp_stream = popen( pipexlate(printer->p_printer), "w" )) == NULL ) {
+ pipe_cmd = pipexlate(printer->p_printer);
+ if ((lp.lp_stream = popen(pipe_cmd, "w")) == NULL) {
LOG(log_error, logtype_papd, "lp_open popen %s: %m", printer->p_printer );
spoolerror( out, NULL );
return( -1 );
}
- LOG(log_debug, logtype_papd, "lp_open: opened %s", pipexlate(printer->p_printer) );
+ LOG(log_debug, logtype_papd, "lp_open: opened %s", pipe_cmd);
} else {
sprintf( name, "df%c%03d%s", lp.lp_letter++, lp.lp_seq, hostname );