From a4dbed1c3c7fb8b1b334aa62edcd8d673b3d18b2 Mon Sep 17 00:00:00 2001 From: Andre Date: Thu, 13 Apr 2006 02:42:51 +0200 Subject: [PATCH] mysql selector commands: escape argv[] when used in a query. --- error.h | 1 + mysql_selector.c | 221 ++++++++++++++++++++++++++++++----------------- 2 files changed, 142 insertions(+), 80 deletions(-) diff --git a/error.h b/error.h index d62781c4..478aec1f 100644 --- a/error.h +++ b/error.h @@ -240,6 +240,7 @@ extern const char **para_errlist[]; PARA_ERROR(GET_AUDIO_FILE, "can not get current audio file"), \ PARA_ERROR(GET_STREAM, "can not get current stream"), \ PARA_ERROR(NO_STREAM, "no such stream"), \ + PARA_ERROR(AUDIO_FILE, "no such audio file"), \ PARA_ERROR(GET_QUERY, "can not get query for specified stream"), \ PARA_ERROR(TMPFILE, "error while writing temporary file"), \ PARA_ERROR(META, "can not get meta data"), \ diff --git a/mysql_selector.c b/mysql_selector.c index 98db17dc..edd2c085 100644 --- a/mysql_selector.c +++ b/mysql_selector.c @@ -695,13 +695,17 @@ static char *escaped_basename(const char *name) */ static int com_na(__unused int fd, int argc, char *argv[]) { - char *q; + char *q, *tmp; int ret; if (argc < 2) return -E_MYSQL_SYNTAX; + tmp = escape_str(argv[1]); + if (!tmp) + return -E_ESCAPE; q = make_message("alter table data add %s char(1) " - "not null default 0", argv[1]); + "not null default 0", tmp); + free(tmp); ret = real_query(q); free(q); return ret; @@ -712,12 +716,16 @@ static int com_na(__unused int fd, int argc, char *argv[]) */ static int com_da(__unused int fd, int argc, char *argv[]) { - char *q; + char *q, *tmp; int ret; if (argc < 2) return -E_MYSQL_SYNTAX; - q = make_message("alter table data drop %s", argv[1]); + tmp = escape_str(argv[1]); + if (!tmp) + return -E_ESCAPE; + q = make_message("alter table data drop %s", tmp); + free(tmp); ret = real_query(q); free(q); return ret; @@ -726,7 +734,7 @@ static int com_da(__unused int fd, int argc, char *argv[]) /* stradd/pic_add */ static int com_stradd_picadd(int fd, int argc, char *argv[]) { - char *blob = NULL, *esc_blob = NULL, *q; + char *blob = NULL, *esc_blob = NULL, *q = NULL, *tmp = NULL; const char *fmt, *del_fmt; int ret, stradd = strcmp(argv[0], "picadd"); size_t size; @@ -746,7 +754,11 @@ static int com_stradd_picadd(int fd, int argc, char *argv[]) fmt = "insert into pics (name, pic) values ('%s','%s')"; del_fmt="delete from pics where pic='%s'"; } - q = make_message(del_fmt, argv[1]); + tmp = escape_str(argv[1]); + if (!tmp) + return -E_ESCAPE; + q = make_message(del_fmt, tmp); + free(tmp); ret = real_query(q); free(q); if (ret < 0) @@ -755,17 +767,22 @@ static int com_stradd_picadd(int fd, int argc, char *argv[]) return ret; if ((ret = fd2buf(fd, &blob, size)) < 0) return ret; - PARA_DEBUG_LOG("length: %i\n", ret); size = ret; if (stradd) blob[size] = '\0'; - esc_blob = escape_blob(blob, ret); - free(blob); + ret = -E_ESCAPE; + esc_blob = escape_blob(blob, size); if (!esc_blob) - return -E_TOOBIG; - q = make_message(fmt, argv[1], esc_blob); - free(esc_blob); + goto out; + tmp = escape_str(argv[1]); + if (!tmp) + goto out; + q = make_message(fmt, tmp, esc_blob); ret = real_query(q); +out: + free(blob); + free(esc_blob); + free(tmp); free(q); return ret; } @@ -806,10 +823,15 @@ static int com_verb(int fd, int argc, char *argv[]) void *result = NULL; int ret; unsigned int num_rows, num_fields; + char *tmp; if (argc < 2) return -E_MYSQL_SYNTAX; - result = get_result(argv[1]); + tmp = escape_str(argv[1]); + if (!tmp) + return -E_ESCAPE; + result = get_result(tmp); + free(tmp); if (!result) /* return success, because it's ok to have no results */ return 1; @@ -864,14 +886,23 @@ static int com_laa(int fd, int argc, __unused char *argv[]) static int com_hist(int fd, int argc, char *argv[]) { int ret; void *result = NULL; - char *q; + char *q, *atts; unsigned int num_rows; + if (argc > 3) + return -E_MYSQL_SYNTAX; + if (argc > 1) { + char *tmp = escape_str(argv[1]); + if (!tmp) + return -E_ESCAPE; + atts = make_message("where %s = '1'", tmp); + free(tmp); + } else + atts = para_strdup(NULL); + q = make_message("select name, to_days(now()) - to_days(lastplayed) from " - "data%s%s%s order by lastplayed", - (argc < 2)? "" : " where ", - (argc < 2)? "" : argv[1], - (argc < 2)? "" : " = '1'"); + "data %s order by lastplayed", atts); + free(atts); result = get_result(q); free(q); if (!result) @@ -943,8 +974,12 @@ static int com_mbox(int fd, int argc, char *argv[]) "') from data" ); if (argc >= 2) { - char *tmp = make_message("%s where name LIKE '%s'", query, - argv[1]); + char *esc = escape_str(argv[1]), *tmp; + ret = -E_ESCAPE; + if (!esc) + goto out; + tmp = make_message("%s where name LIKE '%s'", query, esc); + free(esc); free(query); query = tmp; } @@ -1105,6 +1140,7 @@ err_out: mysql_free_result(result); return para_strdup("(none)"); } + /* * Read stream definition of stream streamname and construct mysql * query. Return NULL on errors. If streamname is NULL, use current @@ -1124,7 +1160,7 @@ static char *get_query(char *streamname, char *filename, int with_path) if (!streamname) tmp = get_current_stream(); else - tmp = para_strdup(streamname); + tmp = escape_str(streamname); if (!strcmp(tmp, "(none)")) { free(tmp); if (filename) { @@ -1260,7 +1296,7 @@ static char *get_selector_info(char *name) atts = get_atts(name, 0); dir = get_dir(name); /* get score */ - query = get_query(stream, name, 0); + query = get_query(stream, name, 0); /* FIXME: pass stream == NULL instead? */ if (!query) goto write; result = get_result(query); @@ -1327,25 +1363,17 @@ static int com_info(int fd, int argc, char *argv[]) ret = send_va_buffer(fd, "dir: %s\n" "%s\n" "attributes: %s\n", dir? dir : "(not contained in table)", meta, atts); out: - if (meta) - free(meta); - if (atts) - free(atts); - if (dir) - free(dir); - if (name) - free(name); + free(meta); + free(atts); + free(dir); + free(name); return ret; } + static int change_stream(const char *stream) { char *query; int ret; - /* try to insert if it does not exist (compatibility) */ -// query = make_message("insert into streams (name, def) values " -// "('current_stream', '%s')", stream); -// real_query(query); /* ignore return value */ -// free(query); query = make_message("update streams set def='%s' " "where name = 'current_stream'", stream); ret = real_query(query); @@ -1381,7 +1409,7 @@ static int remove_entry(const char *name) char *q, *ebn = escaped_basename(name); int ret = -E_ESCAPE; - if (!ebn || !*ebn) + if (!ebn) goto out; q = make_message("delete from data where name = '%s'", ebn); real_query(q); /* ignore errors */ @@ -1466,45 +1494,51 @@ static int com_mv(__unused int fd, int argc, char *argv[]) if (argc != 3) return -E_MYSQL_SYNTAX; + ret = -E_ESCAPE; ebn1 = escaped_basename(argv[1]); ebn2 = escaped_basename(argv[2]); - dn = para_dirname(argv[2]); - edn = escape_str(dn); - free(dn); - ret = -E_ESCAPE; - if (!ebn1 || !ebn2) + if (!ebn1 || !ebn2 | !*ebn1 || !*ebn2) goto out; - remove_entry(ebn2); + ret = -E_MYSQL_SYNTAX; + if (!strcmp(ebn1, ebn2)) + goto out; + remove_entry(argv[2]); /* no need to escape, ignore error */ q = make_message("update data set name = '%s' where name = '%s'", ebn2, ebn1); ret = real_query(q); free(q); if (ret < 0) goto out; + ret = -E_AUDIO_FILE; + if (!mysql_affected_rows(mysql_ptr)) + goto out; q = make_message("update dir set name = '%s' where name = '%s'", ebn2, ebn1); ret = real_query(q); free(q); if (ret < 0) goto out; - /* do not touch table dir, return success if argv[2] is no full path */ ret = 1; - if (!edn || !*edn) + dn = para_dirname(argv[2]); + if (!dn) + goto out; + ret = -E_ESCAPE; + edn = escape_str(dn); + free(dn); + if (!edn) + goto out; + ret = 1; + if (!*edn) goto out; q = make_message("update dir set dir = '%s' where name = '%s'", edn, ebn2); -// PARA_DEBUG_LOG("q: %s\n", q); ret = real_query(q); free(q); out: - if (ebn1) - free(ebn1); - if (ebn2) - free(ebn2); - if (edn) - free(edn); + free(edn); + free(ebn1); + free(ebn2); return ret; - } /* @@ -1543,14 +1577,17 @@ static int com_picch(__unused int fd, int argc, char *argv[]) { int ret; long unsigned id; - char *q; + char *q, *tmp; if (argc != 3) return -E_MYSQL_SYNTAX; id = atol(argv[1]); - if (strlen(argv[2]) > MAXLINE) - return -E_NAMETOOLONG; - q = make_message("update pics set name = '%s' where id = %lu", argv[2], id); + ret = -E_ESCAPE; + tmp = escape_str(argv[2]); + if (!tmp) + return -E_ESCAPE; + q = make_message("update pics set name = '%s' where id = %lu", tmp, id); + free(tmp); ret = real_query(q); free(q); return ret; @@ -1663,20 +1700,18 @@ out: /* strdel */ static int com_strdel(__unused int fd, int argc, char *argv[]) { - char *tmp; - int ret = -1; + char *q, *tmp; + int ret; if (argc < 2) return -E_MYSQL_SYNTAX; - tmp = make_message("delete from streams where name='%s'", argv[1]); - ret = real_query(tmp); + tmp = escape_str(argv[1]); + if (!tmp) + return -E_ESCAPE; + q = make_message("delete from streams where name='%s'", tmp); free(tmp); - if (ret < 0) - return ret; - tmp = get_current_stream(); - ret = 1; - if (strcmp(tmp, "(none)") && !strcmp(tmp, argv[1])) - ret = change_stream("(none)"); + ret = real_query(q); + free(q); return ret; } @@ -1690,10 +1725,16 @@ static int com_ls(int fd, int argc, char *argv[]) int ret; unsigned int num_rows; - if (argc > 1) - q = make_message("select name from data where name LIKE '%s'", - argv[1]); - else + if (argc > 2) + return -E_MYSQL_SYNTAX; + if (argc > 1) { + char *tmp = escape_str(argv[1]); + if (!tmp) + return -E_ESCAPE; + q = make_message("select name from data where name like '%s'", + tmp); + free(tmp); + } else q = para_strdup("select name from data"); result = get_result(q); free(q); @@ -1706,6 +1747,7 @@ static int com_ls(int fd, int argc, char *argv[]) mysql_free_result(result); return ret; } + /* * summary */ @@ -1821,9 +1863,17 @@ static void update_audio_file_server_handler(char *name) static int com_us(__unused int fd, int argc, char *argv[]) { + char *tmp; + int ret; + if (argc != 2) return -E_MYSQL_SYNTAX; - return update_audio_file(argv[1]); + tmp = escape_str(argv[1]); + if (!tmp) + return -E_ESCAPE; + ret = update_audio_file(argv[1]); + free(tmp); + return ret; } static void refresh_selector_info(void) @@ -1986,7 +2036,7 @@ out: static int com_cs(int fd, int argc, char *argv[]) { int ret, stream_change; - char *query; + char *query, *stream = NULL; char *old_stream = get_current_stream(); int csp = !strcmp(argv[0], "csp"); @@ -1998,14 +2048,18 @@ static int com_cs(int fd, int argc, char *argv[]) goto out; } ret = -E_GET_QUERY; - query = get_query(argv[1], NULL, 0); /* test if stream is valid */ + /* test if stream is valid, no need to escape argv[1] */ + query = get_query(argv[1], NULL, 0); if (!query) goto out; free(query); /* stream is ok */ - stream_change = strcmp(argv[1], old_stream); + stream = escape_str(argv[1]); + if (!stream) + goto out; + stream_change = strcmp(stream, old_stream); if (stream_change) { - ret = change_stream(argv[1]); + ret = change_stream(stream); if (ret < 0) goto out; refresh_selector_info(); @@ -2020,6 +2074,7 @@ static int com_cs(int fd, int argc, char *argv[]) ret = 1; out: free(old_stream); + free(stream); return ret; } @@ -2039,7 +2094,7 @@ static int com_sl(int fd, int argc, char *argv[]) num = atoi(argv[1]); if (!num) return -E_MYSQL_SYNTAX; - stream = (argc == 2)? get_current_stream() : para_strdup(argv[2]); + stream = (argc == 2)? get_current_stream() : escape_str(argv[2]); tmp = get_query(stream, NULL, 0); query = make_message("%s limit %d", tmp, num); free(tmp); @@ -2112,7 +2167,7 @@ static int com_sa(int fd, int argc, char *argv[]) return -E_MYSQL_SYNTAX; for (i = 1; i < argc; i++) { int unset = 0; - char *tmp, *p =argv[i]; + char *esc, *tmp, *p =argv[i]; int len = strlen(p); if (!len) @@ -2128,8 +2183,12 @@ static int com_sa(int fd, int argc, char *argv[]) goto no_more_atts; } p[len - 1] = '\0'; - tmp = make_message("%s%s='%s'", atts? "," : "", p, + esc = escape_str(p); + if (!esc) + return -E_ESCAPE; + tmp = make_message("%s%s='%s'", atts? "," : "", esc, unset? "0" : "1"); + free(esc); atts = para_strcat(atts, tmp); free(tmp); } @@ -2447,8 +2506,10 @@ static int com_cdb(int fd, int argc, char *argv[]) ret = -E_MYSQL_INIT; if (init_mysql_server() < 0 || !mysql_ptr) goto out; - conf.mysql_database_arg = para_strdup((argc < 2)? - "paraslash" : argv[1]); + if (argc < 2) + conf.mysql_database_arg = para_strdup("paraslash"); + else + conf.mysql_database_arg = escape_str(argv[1]); query = make_message("create database %s", conf.mysql_database_arg); ret = real_query(query); free(query); -- 2.39.5