#include #include "stralloc.h" #include "qsutil.h" #include "mysql_queries.h" extern int connect_mysql(); extern int disconnect_mysql(); extern MYSQL dbh, *mysql; extern MYSQL_RES *result; /* simulate reading a .qmail file from ye olde database */ int dotqmail_mysql(char *username, char *ext, stralloc *sa, int bufsize) { int i, len, num; MYSQL_ROW row; stralloc query = { 0 }; stralloc user = { 0 }; stralloc real_ext = { 0 }; #ifdef FUNKY_ALIAS_QUERIES #ifdef OIL_AND_WATER stralloc last1 = { 0 }; stralloc last2 = { 0 }; #endif #endif /* initialise database handle or signal trouble */ if (! connect_mysql()) return -1; i = str_len(username); if (! stralloc_ready(&user, 2 * i + 1)) return zoiks(-1); mysql_escape_string(user.s, username, i); i = str_len(ext); if (! stralloc_ready(&real_ext, 2 * i + 1)) return zoiks(-1); mysql_escape_string(real_ext.s, ext, i); /* make the query or signal an out of memory exception */ len = str_len(ALIAS) + real_ext.len + user.len - 3; if (! stralloc_ready(&query, len)) return zoiks(-1); if (! stralloc_cats(&query, ALIAS1)) return zoiks(-1); if (! stralloc_cats(&query, user.s)) return zoiks(-1); if (! stralloc_cats(&query, ALIAS2)) return zoiks(-1); if (! stralloc_cats(&query, real_ext.s)) return zoiks(-1); if (! stralloc_cats(&query, ALIAS3)) return zoiks(-1); if (! stralloc_0(&query)) return zoiks(-1); #ifndef O_NOT_LOG tcplog("query: ", query.s, ";\n"); #endif /* do the query or signal to use .qmail */ if (mysql_real_query(mysql, query.s, query.len) < 0) { /* bad => log it anyway */ tcplog("error: ", mysql_error(&dbh), "\n"); disconnect_mysql(); return 0; } result = mysql_store_result(mysql); if (!result) return zoiks(-1); num = mysql_num_rows(result); /* no rows: let's try the default alias - but not if extension was blank */ if (num == 0 && *ext) { mysql_free_result(result); query.len = 0; len = str_len(ALIAS) + user.len - 2; if (! stralloc_ready(&query, len)) return zoiks(-1); if (! stralloc_cats(&query, ALIAS1)) return zoiks(-1); if (! stralloc_cats(&query, user.s)) return zoiks(-1); if (! stralloc_cats(&query, ALIAS2)) return zoiks(-1); if (! stralloc_append(&query, "@")) return zoiks(-1); if (! stralloc_cats(&query, ALIAS3)) return zoiks(-1); if (! stralloc_0(&query)) return zoiks(-1); #ifndef O_NOT_LOG tcplog("query: ", query.s, ";\n"); #endif /* hmm, a function would have been nice here */ if (mysql_real_query(mysql, query.s, query.len) < 0) { /* bad => log it anyway */ tcplog("error: ", mysql_error(&dbh), "\n"); disconnect_mysql(); return 0; } result = mysql_store_result(mysql); if (!result) return zoiks(0); num = mysql_num_rows(result); } /* well it looks like there's really no match */ if (num == 0) return zoiks(0); #ifdef FUNKY_ALIAS_QUERIES #ifdef OIL_AND_WATER if (! stralloc_ready(&last1, 2)) return zoiks(-1); if (! stralloc_append(&last1, "0")) return zoiks(-1); if (! stralloc_0(&last1)) return zoiks(-1); if (! stralloc_ready(&last2, 2)) return zoiks(-1); if (! stralloc_append(&last2, "0")) return zoiks(-1); if (! stralloc_0(&last2)) return zoiks(-1); #endif #endif for (i = 0; i < num; i++) { row = mysql_fetch_row(result); if (! *(row[0])) { tcplog("MySQL misconfiguration: alias_username is blank for username '", user.s, "' in alias table!\n"); continue; } #ifdef FUNKY_ALIAS_QUERIES #ifdef OIL_AND_WATER /* discard wildcard matches if we already had explicit matches */ if (i && (str_diff(row[2], last1.s) || str_diff(row[3], last2.s))) break; if (! stralloc_ready(&last1, str_len(row[2]) + 1)) return zoiks(-1); if (! stralloc_cats(&last1, row[2])) return zoiks(-1); if (! stralloc_0(&last1)) return zoiks(-1); if (! stralloc_ready(&last2, str_len(row[3]) + 1)) return zoiks(-1); if (! stralloc_cats(&last2, row[3])) return zoiks(-1); if (! stralloc_0(&last2)) return zoiks(-1); #endif #endif /* we need space for &blabla@crap\n\0 */ len = str_len(row[0]) + str_len(row[1]) + 4; if (! stralloc_readyplus(sa, len)) return zoiks(-1); /* if the result is too big for the buffer we skip it */ if (len > bufsize) continue; /* if the alias username is a | we use the alias host value as the target */ if (*row[0] == '|') { /* skip if the pipe would break */ if (str_len(row[1]) == 0) continue; if (! stralloc_cats(sa, "| ")) return zoiks(-1); } /* . or / means delivery to a mailbox or maildir */ else if (*row[0] == '/' || *row[0] == '.') { *(row[0] + 1) = '\0'; if (str_len(row[1]) == 0) continue; if (! stralloc_cats(sa, row[0])) return zoiks(-1); } else { if (! stralloc_cats(sa, "&")) return zoiks(-1); if (! stralloc_cats(sa, row[0])) return zoiks(-1); if (strcmp(row[1], "") && ! stralloc_cats(sa, "@")) return zoiks(-1); } if (! stralloc_cats(sa, row[1])) return zoiks(-1); if (! stralloc_cats(sa, "\n")) return zoiks(-1); } return zoiks(num); } /* free memory used by query, disconnect from database and return */ int zoiks(int ret) { mysql_free_result(result); disconnect_mysql(); return ret; }