Skip to content

Commit d9fca57

Browse files
committed
qrexec-client: Better validation of arguments
No change in behavior on valid inputs.
1 parent 2be9adc commit d9fca57

File tree

1 file changed

+46
-33
lines changed

1 file changed

+46
-33
lines changed

daemon/qrexec-client.c

+46-33
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
*
2020
*/
2121

22+
#include <limits.h>
2223
#include <sys/socket.h>
2324
#include <sys/un.h>
2425
#include <stdio.h>
@@ -415,44 +416,47 @@ _Noreturn static void usage(const char *const name)
415416
" -w timeout - override default connection timeout of 5s (set 0 for no timeout)\n"
416417
" -k - kill the domain right before exiting\n"
417418
" --socket-dir=PATH - directory for qrexec socket, default: %s\n",
418-
name, QREXEC_DAEMON_SOCKET_DIR);
419+
name ? name : "qrexec-client", QREXEC_DAEMON_SOCKET_DIR);
419420
exit(1);
420421
}
421422

423+
static int parse_int(const char *str, const char *msg) {
424+
long value;
425+
char *end = (char *)str;
426+
427+
if (str[0] < '0' || str[0] > '9')
428+
errx(1, "%s '%s' does not start with an ASCII digit", msg, str);
429+
errno = 0;
430+
value = strtol(str, &end, 0);
431+
if (*end != '\0')
432+
errx(1, "trailing junk '%s' after %s", end, msg);
433+
if (errno == 0 && (value < 0 || value > INT_MAX))
434+
errno = ERANGE;
435+
if (errno)
436+
err(1, "invalid %s '%s': strtol", msg, str);
437+
return (int)value;
438+
}
439+
422440
static void parse_connect(char *str, char **request_id,
423441
char **src_domain_name, int *src_domain_id)
424442
{
425-
int i=0;
426-
char *token = NULL;
427-
char *separators = ",";
428-
429-
token = strtok(str, separators);
430-
while (token)
431-
{
432-
switch (i)
433-
{
434-
case 0:
435-
*request_id = token;
436-
if (strlen(*request_id) >= sizeof(struct service_params)) {
437-
fprintf(stderr, "Invalid -c parameter (request_id too long, max %lu)\n",
438-
sizeof(struct service_params)-1);
439-
exit(1);
440-
}
441-
break;
442-
case 1:
443-
*src_domain_name = token;
444-
break;
445-
case 2:
446-
*src_domain_id = atoi(token);
447-
break;
448-
default:
449-
goto bad_c_param;
450-
}
451-
token = strtok(NULL, separators);
452-
i++;
453-
}
454-
if (i == 3)
455-
return;
443+
char *token;
444+
445+
token = strchr(str, ',');
446+
if (token == NULL)
447+
goto bad_c_param;
448+
if ((size_t)(token - str) >= sizeof(struct service_params))
449+
errx(1, "Invalid -c parameter (request_id too long, max %zu)\n",
450+
sizeof(struct service_params)-1);
451+
*token = 0;
452+
*request_id = str;
453+
*src_domain_name = token + 1;
454+
token = strchr(*src_domain_name, ',');
455+
if (token == NULL)
456+
goto bad_c_param;
457+
*token = 0;
458+
*src_domain_id = parse_int(token + 1, "source domain ID");
459+
return;
456460
bad_c_param:
457461
fprintf(stderr, "Invalid -c parameter (should be: \"-c request_id,src_domain_name,src_domain_id\")\n");
458462
exit(1);
@@ -547,6 +551,11 @@ int main(int argc, char **argv)
547551
int prepare_ret;
548552
bool kill = false;
549553

554+
if (argc < 3) {
555+
// certainly too few arguments
556+
usage(argv[0]);
557+
}
558+
550559
setup_logging("qrexec-client");
551560

552561
while ((opt = getopt_long(argc, argv, "hd:l:eEc:tTw:Wk", longopts, NULL)) != -1) {
@@ -564,6 +573,10 @@ int main(int argc, char **argv)
564573
exit_with_code = 0;
565574
break;
566575
case 'c':
576+
if (request_id != NULL) {
577+
warnx("ERROR: -c passed more than once");
578+
usage(argv[0]);
579+
}
567580
parse_connect(optarg, &request_id, &src_domain_name, &src_domain_id);
568581
is_service = 1;
569582
break;
@@ -574,7 +587,7 @@ int main(int argc, char **argv)
574587
replace_chars_stderr = 1;
575588
break;
576589
case 'w':
577-
connection_timeout = atoi(optarg);
590+
connection_timeout = parse_int(optarg, "connection timeout");
578591
break;
579592
case 'W':
580593
wait_connection_end = 1;

0 commit comments

Comments
 (0)