putc('-', f);
if (is_tainted(value))
{
- int q = quoter_for_address(value);
+ const uschar * quoter_name;
putc('-', f);
- if (is_real_quoter(q))
- {
- const lookup_info * li = lookup_with_acq_num(q);
- fprintf(f, "(%s)", li ? li->name : US"???");
- }
+ (void) quoter_for_address(value, "er_name);
+ if (quoter_name)
+ fprintf(f, "(%s)", quoter_name);
}
fprintf(f, "acl%c %s %d\n%s\n", name[0], name+1, Ustrlen(value), value);
}
+/* Hunt for the lookup with the given acquisition number */
+
static unsigned hunt_acq;
static void
if (li->acq_num == hunt_acq) *(lookup_info **)ctx = li;
}
-/*XXX many of the calls here could instead use a name on the quoted-pool */
const lookup_info *
lookup_with_acq_num(unsigned k)
{
while ((c = *t++))
if (c == '\'') count++;
-t = quoted = store_get_quoted(Ustrlen(s) + count + 1, s, idx);
+t = quoted = store_get_quoted(Ustrlen(s) + count + 1, s, idx, US(ibase));
while ((c = *s++))
if (c == '\'') { *t++ = '\''; *t++ = '\''; }
/* Get sufficient store to hold the quoted string */
-t = quoted = store_get_quoted(len + count + 1, s, idx);
+t = quoted = store_get_quoted(len + count + 1, s, idx, US"ldap");
/* Handle plain quote_ldap */
/* Old code: if (count == 0) return s;
Now always allocate and copy, to track the quoted status. */
-t = quoted = store_get_quoted(Ustrlen(s) + count + 1, s, idx);
+t = quoted = store_get_quoted(Ustrlen(s) + count + 1, s, idx, US"mysql");
while ((c = *s++))
{
while (*t) if (*t++ == '\"') count++;
-t = quoted = store_get_quoted(Ustrlen(s) + count + 1, s, idx);
+t = quoted = store_get_quoted(Ustrlen(s) + count + 1, s, idx, US"nisplus");
while (*s)
{
while ((c = *t++))
if (strchr("\n\t\r\b\'\"\\", c) != NULL) count++;
-t = quoted = store_get_quoted((int)Ustrlen(s) + count + 1, s, idx);
+t = quoted = store_get_quoted((int)Ustrlen(s) + count + 1, s, idx, US"oracle");
while ((c = *s++))
{
while ((c = *t++))
if (Ustrchr("\n\t\r\b\'\"\\", c) != NULL) count++;
-t = quoted = store_get_quoted(Ustrlen(s) + count + 1, s, idx);
+t = quoted = store_get_quoted(Ustrlen(s) + count + 1, s, idx, US"pgsql");
while ((c = *s++))
{
while ((c = *t++))
if (isspace(c) || c == '\\') count++;
-t = quoted = store_get_quoted(Ustrlen(s) + count + 1, s, idx);
+t = quoted = store_get_quoted(Ustrlen(s) + count + 1, s, idx, US"redis");
while ((c = *s++))
{
while ((c = *t++)) if (c == '\'') count++;
count += t - s;
-t = quoted = store_get_quoted(count + 1, s, idx);
+t = quoted = store_get_quoted(count + 1, s, idx, US"sqlite");
while ((c = *s++))
{
const lookup_info * li = c->li;
expiring_data * e = NULL; /* compiler quietening */
uschar * data = NULL;
-int quoter_id = li->acq_num;
+int required_quoter_id = li->acq_num;
int old_pool = store_pool;
/* Lookups that return DEFER may not always set an error message. So that
XXX Should we this move into lf_sqlperform() ? The server-taint check is there.
Also it already knows about looking for a "servers" spec in the query string.
- Passing quoter_id down that far is an issue.
+ Passing required_quoter_id down that far is an issue.
*/
if ( !filename && li->quote
- && is_tainted(keystring) && !is_quoted_like(keystring, quoter_id))
+ && is_tainted(keystring) && !is_quoted_like(keystring, required_quoter_id))
{
const uschar * ks = keystring;
uschar * loc = acl_current_verb();
DEBUG(D_lookup)
{
- int q = quoter_for_address(ks);
- const lookup_info * qli = lookup_with_acq_num(q);
+ const uschar * quoter_name;
+ int q = quoter_for_address(ks, "er_name);
- debug_printf_indent("quoter_id %d (%s) quoting %d (%s)\n",
- quoter_id, li->name,
- q,
- is_real_quoter(q) ? qli ? qli->name : US"???" : US"none");
+ debug_printf_indent("required_quoter_id %d (%s) quoting %d (%s)\n",
+ required_quoter_id, li->name,
+ q, quoter_name);
}
#endif
}
where = NULL;
goto SPOOL_FORMAT_ERROR;
}
- proto_mem = store_get_quoted(1, GET_TAINTED, li->acq_num);
+ proto_mem = store_get_quoted(1, GET_TAINTED, li->acq_num, li->name);
}
#endif /* COMPILE_UTILITY */
var = s + 1;
putc('-', fp);
if (is_tainted(val))
{
- int q = quoter_for_address(val);
+ const uschar * quoter_name;
putc('-', fp);
- if (is_real_quoter(q))
- {
- const lookup_info * li = lookup_with_acq_num(q);
- fprintf(fp, "(%s)", li ? li->name : US"unknown!");
- }
+ (void) quoter_for_address(val, "er_name);
+ if (quoter_name)
+ fprintf(fp, "(%s)", quoter_name);
}
fprintf(fp, "%s %s\n", name, val);
}
typedef struct quoted_pooldesc {
pooldesc pool;
unsigned quoter;
+ const unsigned char * quoter_name;
struct quoted_pooldesc * next;
} quoted_pooldesc;
/* Return the pool for the given quoter, or null */
static pooldesc *
-pool_for_quoter(unsigned quoter)
+pool_for_quoter(unsigned quoter, const uschar ** namep)
{
for (quoted_pooldesc * qp = quoted_pools; qp; qp = qp->next)
if (qp->quoter == quoter)
+ {
+ if (namep) *namep = qp->quoter_name;
return &qp->pool;
+ }
return NULL;
}
/* Allocate/init a new quoted-pool and return the pool */
static pooldesc *
-quoted_pool_new(unsigned quoter)
+quoted_pool_new(unsigned quoter, const uschar * quoter_name)
{
-// debug_printf("allocating quoted-pool\n");
quoted_pooldesc * qp = store_get_perm(sizeof(quoted_pooldesc), GET_UNTAINTED);
pool_init(&qp->pool);
qp->quoter = quoter;
+qp->quoter_name = quoter_name;
qp->next = quoted_pools;
quoted_pools = qp;
return &qp->pool;
store_get_3(int size, const void * proto_mem, const char * func, int linenumber)
{
#ifndef COMPILE_UTILITY
-int quoter = quoter_for_address(proto_mem);
+const uschar * quoter_name;
+int quoter = quoter_for_address(proto_mem, "er_name);
#endif
pooldesc * pp;
void * yield;
#ifndef COMPILE_UTILITY
-if (!is_real_quoter(quoter))
+if (!quoter_name)
#endif
{
BOOL tainted = is_tainted(proto_mem);
DEBUG(D_memory)
debug_printf("allocating quoted-block for quoter %u (from %s %d)\n",
quoter, func, linenumber);
- if (!(pp = pool_for_quoter(quoter))) pp = quoted_pool_new(quoter);
+ if (!(pp = pool_for_quoter(quoter, NULL)))
+ pp = quoted_pool_new(quoter, quoter_name);
yield = pool_get(pp, size, FALSE, func, linenumber);
DEBUG(D_memory)
debug_printf("---QQ Get %6p %5d %-14s %4d\n",
*/
static void *
-store_force_get_quoted(int size, unsigned quoter,
+store_force_get_quoted(int size, unsigned quoter, const uschar * quoter_name,
const char * func, int linenumber)
{
-pooldesc * pp = pool_for_quoter(quoter);
+pooldesc * pp = pool_for_quoter(quoter, NULL);
void * yield;
DEBUG(D_memory)
debug_printf("allocating quoted-block for quoter %u (from %s %d)\n", quoter, func, linenumber);
-if (!pp) pp = quoted_pool_new(quoter);
+if (!pp) pp = quoted_pool_new(quoter, quoter_name);
yield = pool_get(pp, size, FALSE, func, linenumber);
DEBUG(D_memory)
*/
void *
store_get_quoted_3(int size, const void * proto_mem, unsigned quoter,
- const char * func, int linenumber)
+ const uschar * quoter_name, const char * func, int linenumber)
{
-// debug_printf("store_get_quoted_3: quoter %u\n", quoter);
return is_tainted(proto_mem)
- ? store_force_get_quoted(size, quoter, func, linenumber)
+ ? store_force_get_quoted(size, quoter, quoter_name, func, linenumber)
: store_get_3(size, proto_mem, func, linenumber);
}
/* Return quoter for given address, or -1 if not in a quoted-pool. */
int
-quoter_for_address(const void * p)
+quoter_for_address(const void * p, const uschar ** namep)
{
-for (quoted_pooldesc * qp = quoted_pools; qp; qp = qp->next)
+const quoted_pooldesc * qp;
+for (qp = quoted_pools; qp; qp = qp->next)
{
- pooldesc * pp = &qp->pool;
+ const pooldesc * pp = &qp->pool;
storeblock * b;
if (b = pp->current_block)
if (is_pointer_in_block(b, p))
- return qp->quoter;
+ goto found;
for (b = pp->chainbase; b; b = b->next)
if (is_pointer_in_block(b, p))
- return qp->quoter;
+ goto found;
}
+if (namep) *namep = NULL;
return -1;
+
+found:
+ if (namep) *namep = qp->quoter_name;
+ return qp->quoter;
}
/* Return TRUE iff the given address is quoted for the given type.
BOOL
is_quoted_like(const void * p, unsigned quoter)
{
-int pq = quoter_for_address(p);
-const lookup_info * p_li = lookup_with_acq_num(pq);
-void * p_qfn = p_li ? p_li->quote : NULL;
-const lookup_info * q_li = lookup_with_acq_num(quoter);
-void * q_qfn = q_li ? q_li->quote : NULL;
-BOOL y = is_real_quoter(pq) && p_qfn == q_qfn;
+const uschar * p_name, * q_name;
+const lookup_info * p_li, * q_li;
+void * p_qfn, * q_qfn;
+
+(void) quoter_for_address(p, &p_name);
+(void) pool_for_quoter(quoter, &q_name);
+
+if (!p_name || !q_name) return FALSE;
+
+p_li = search_findtype(p_name, Ustrlen(p_name));
+p_qfn = p_li ? p_li->quote : NULL;
+q_li = search_findtype(q_name, Ustrlen(q_name));
+q_qfn = q_li ? q_li->quote : NULL;
+
+BOOL y = p_qfn == q_qfn;
+
/* debug_printf("is_quoted(%p, %u): %c\n", p, quoter, y?'T':'F'); */
return y;
}
return quoter >= 0;
}
+
/* Return TRUE if the "new" data requires that the "old" data
be recopied to new-class memory. We order the classes as
int oq, nq;
unsigned oi, ni;
-ni = is_real_quoter(nq = quoter_for_address(new)) ? 1 : is_tainted(new) ? 2 : 0;
-oi = is_real_quoter(oq = quoter_for_address(old)) ? 1 : is_tainted(old) ? 2 : 0;
+ni = is_real_quoter(nq = quoter_for_address(new, NULL)) ? 1 : is_tainted(new) ? 2 : 0;
+oi = is_real_quoter(oq = quoter_for_address(old, NULL)) ? 1 : is_tainted(old) ? 2 : 0;
return ni > oi || ni == oi && nq != oq;
}
for (quoted_pooldesc * qp = quoted_pools; qp; i++, qp = qp->next)
{
pooldesc * pp = &qp->pool;
- const lookup_info* li = lookup_with_acq_num(qp->quoter);
debug_printf("----Exit pool Q%d max: %3d kB in %d blocks at order %u\ttainted quoted:%s\n",
i, (pp->maxbytes+1023)/1024, pp->maxblocks, pp->maxorder,
- li ? li->name : US"???");
+ qp->quoter_name);
}
}
#endif
void
debug_print_taint(const void * p)
{
-int q = quoter_for_address(p);
+const uschar * quoter_name;
if (!is_tainted(p)) return;
debug_printf("(tainted");
-if (is_real_quoter(q))
- {
- const lookup_info * li = lookup_with_acq_num(q);
- debug_printf(", quoted:%s", li ? li->name : US"???");
- }
+(void) quoter_for_address(p, "er_name);
+if (quoter_name)
+ debug_printf(", quoted:%s", quoter_name);
debug_printf(")\n");
}
#endif
#define store_free(addr) \
store_free_3(addr, __FUNCTION__, __LINE__)
/* store_get & store_get_perm are in local_scan.h */
-#define store_get_quoted(size, proto_mem, quoter) \
- store_get_quoted_3((size), (proto_mem), (quoter), __FUNCTION__, __LINE__)
+#define store_get_quoted(size, proto_mem, quoter, quoter_name) \
+ store_get_quoted_3((size), (proto_mem), (quoter), (quoter_name), \
+ __FUNCTION__, __LINE__)
#define store_malloc(size) \
store_malloc_3(size, __FUNCTION__, __LINE__)
#define store_mark(void) \
extern BOOL store_extend_3(void *, int, int, const char *, int);
extern void store_free_3(void *, const char *, int);
/* store_get_3 & store_get_perm_3 are in local_scan.h */
-extern void * store_get_quoted_3(int, const void *, unsigned, const char *, int);
+extern void * store_get_quoted_3(int, const void *, unsigned, const uschar *,
+ const char *, int);
extern void * store_malloc_3(size_t, const char *, int) ALLOC ALLOC_SIZE(1) WARN_UNUSED_RESULT;
extern rmark store_mark_3(const char *, int);
extern void * store_newblock_3(void *, int, int, const char *, int);
#define GET_UNTAINTED (const void *)0
#define GET_TAINTED (const void *)1
-extern int quoter_for_address(const void *);
+extern int quoter_for_address(const void *, const uschar **);
extern BOOL is_quoted_like(const void *, unsigned);
extern BOOL is_real_quoter(int);
extern void debug_print_taint(const void * p);
}
# Different builds will have different lookup types included
- s/quoter_id \K\d+ \((\w+)\) quoting -1 \(none\)$/NN ($1) quoting -1 (none)/;
+ s/required_quoter_id \K\d+ \((\w+)\) quoting -1 \(NULL\)$/NN ($1) quoting -1 (NULL)/;
# and different numbers of lookup types result in different type-code letters,
# so convert them all to "0"
s%(?<!lsearch)[^ ](?=TESTSUITE/aux-fixed/(?:0414.list[12]|0464.domains)$)%0%;
01:01:01 p1235 (tainted)
01:01:01 p1235 LOG: MAIN PANIC
01:01:01 p1235 tainted search query is not properly quoted (ACL warn, TESTSUITE/test-config 26): select name from them where id = 'c'
-01:01:01 p1235 quoter_id NN (mysql) quoting -1 (none)
+01:01:01 p1235 required_quoter_id NN (mysql) quoting -1 (NULL)
01:01:01 p1235 MySQL query: "select name from them where id = 'c'" opts 'no_rd'
01:01:01 p1235 MYSQL using cached connection for 127.0.0.1:PORT_N/test/root
01:01:01 p1235 MYSQL: no data found
01:01:01 p1235 (tainted)
01:01:01 p1235 LOG: MAIN PANIC
01:01:01 p1235 tainted search query is not properly quoted (ACL warn, TESTSUITE/test-config 39): select name from them where id = 'c'
-01:01:01 p1235 quoter_id NN (mysql) quoting -1 (none)
+01:01:01 p1235 required_quoter_id NN (mysql) quoting -1 (NULL)
01:01:01 p1235 MySQL query: "servers=127.0.0.1::PORT_N; select name from them where id = 'c'" opts 'NULL'
01:01:01 p1235 LOG: MAIN
01:01:01 p1235 Exim configuration error in line 89 of TESTSUITE/test-config:
(tainted)
LOG: MAIN PANIC
tainted search query is not properly quoted (router r1, TESTSUITE/test-config 68): select name from them where id='ph10' limit 1
- quoter_id NN (mysql) quoting -1 (none)
+ required_quoter_id NN (mysql) quoting -1 (NULL)
MySQL query: "select name from them where id='ph10' limit 1" opts 'NULL'
MYSQL using cached connection for 127.0.0.1:PORT_N/test/root
creating new cache entry
(tainted)
LOG: MAIN
tainted search query is not properly quoted (transport t1, TESTSUITE/test-config 82): select id from them where id='ph10'
- quoter_id NN (mysql) quoting -1 (none)
+ required_quoter_id NN (mysql) quoting -1 (NULL)
MySQL query: "select id from them where id='ph10'" opts 'NULL'
MYSQL new connection: host=127.0.0.1 port=PORT_N socket=NULL database=test user=root
creating new cache entry
(tainted)
LOG: MAIN PANIC
tainted search query is not properly quoted (ACL warn, TESTSUITE/test-config 27): select name from them where id = 'c'
- quoter_id NN (pgsql) quoting -1 (none)
+ required_quoter_id NN (pgsql) quoting -1 (NULL)
PostgreSQL query: "select name from them where id = 'c'" opts 'NULL'
PGSQL using cached connection for localhost:PORT_N/test/CALLER
PGSQL: no data found
(tainted)
LOG: MAIN PANIC
tainted search query is not properly quoted (ACL warn, TESTSUITE/test-config 27): select name from them where id = 'c'
- quoter_id NN (pgsql) quoting -1 (none)
+ required_quoter_id NN (pgsql) quoting -1 (NULL)
PostgreSQL query: "select name from them where id = 'c'" opts 'NULL'
PGSQL using cached connection for localhost:PORT_N/test/CALLER
PGSQL: no data found