com_cs: Return a syntax error if argc > 2.
[paraslash.git] / mysql_selector.c
index 98db17dc758762b1b16feb2a2cae3da4f38b8571..f41afcdff61b0f14c518b919028e6ee9d879547d 100644 (file)
@@ -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;
+       ret = -E_MYSQL_SYNTAX;
+       if (!strcmp(ebn1, ebn2))
                goto out;
-       remove_entry(ebn2);
+       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,26 +2036,32 @@ 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");
 
+       ret = -E_MYSQL_SYNTAX;
+       if (argc > 2)
+               goto out;
        if (argc == 1) {
-               ret = -E_MYSQL_SYNTAX;
                if (csp)
                        goto out;
                ret = send_va_buffer(fd, "%s\n", old_stream);
                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 +2076,7 @@ static int com_cs(int fd, int argc, char *argv[])
        ret = 1;
 out:
        free(old_stream);
+       free(stream);
        return ret;
 }
 
@@ -2039,7 +2096,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 +2169,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 +2185,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 +2508,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);