From: Brian Candler Date: Fri, 8 Feb 2013 17:41:58 +0000 (+0000) Subject: Factor out argv splitting into rad_expand_xlat X-Git-Tag: debian/3.0.0git+dfsg+moonshot3-2~90^2~3 X-Git-Url: http://www.project-moonshot.org/gitweb/?a=commitdiff_plain;h=00965e119b97d6d01b249d990d0a626b2a2b77db;hp=09c602e1716fcfed563b6966cd4e9d31ffe3ded8;p=freeradius.git Factor out argv splitting into rad_expand_xlat --- diff --git a/src/include/radiusd.h b/src/include/radiusd.h index 70a1348..bbfb491 100644 --- a/src/include/radiusd.h +++ b/src/include/radiusd.h @@ -626,6 +626,9 @@ int rad_copy_string(char *dst, const char *src); int rad_copy_variable(char *dst, const char *from); int rad_pps(int *past, int *present, time_t *then, struct timeval *now); +int rad_expand_xlat(REQUEST *request, const char *cmd, + int max_argc, const char *argv[], int can_fail, + size_t argv_buflen, char *argv_buf); /* client.c */ RADCLIENT_LIST *clients_init(CONF_SECTION *cs); diff --git a/src/main/exec.c b/src/main/exec.c index 9b1279b..f068de8 100644 --- a/src/main/exec.c +++ b/src/main/exec.c @@ -90,8 +90,6 @@ pid_t radius_start_program(const char *cmd, REQUEST *request, VALUE_PAIR *input_pairs, int shell_escape) { - const char *from; - char *to; #ifndef __MINGW32__ char *p; VALUE_PAIR *vp; @@ -100,147 +98,20 @@ pid_t radius_start_program(const char *cmd, REQUEST *request, int from_child[2] = {-1, -1}; pid_t pid; #endif - int argc = -1; + int argc; int i; - int left; char *argv[MAX_ARGV]; char argv_buf[4096]; #define MAX_ENVP 1024 char *envp[MAX_ENVP]; - char mycmd[1024]; - if (strlen(cmd) > (sizeof(mycmd) - 1)) { - radlog(L_ERR, "Command line is too long"); - return -1; - } - - /* - * Check for bad escapes. - */ - if (cmd[strlen(cmd) - 1] == '\\') { - radlog(L_ERR, "Command line has final backslash, without a following character"); - return -1; - } - - strlcpy(mycmd, cmd, sizeof(mycmd)); - - /* - * Split the string into argv's BEFORE doing radius_xlat... - */ - from = cmd; - to = mycmd; - argc = 0; - while (*from) { - int length; - - /* - * Skip spaces. - */ - if ((*from == ' ') || (*from == '\t')) { - from++; - continue; - } - - argv[argc] = to; - argc++; - - if (argc >= (MAX_ARGV - 1)) break; - - /* - * Copy the argv over to our buffer. - */ - while (*from && (*from != ' ') && (*from != '\t')) { - if (to >= mycmd + sizeof(mycmd) - 1) { - return -1; /* ran out of space */ - } - - switch (*from) { - case '"': - case '\'': - length = rad_copy_string(to, from); - if (length < 0) { - radlog(L_ERR, "Invalid string passed as argument for external program"); - return -1; - } - from += length; - to += length; - break; - - case '%': - if (from[1] == '{') { - *(to++) = *(from++); - - length = rad_copy_variable(to, from); - if (length < 0) { - radlog(L_ERR, "Invalid variable expansion passed as argument for external program"); - return -1; - } - from += length; - to += length; - } else { /* FIXME: catch %%{ ? */ - *(to++) = *(from++); - } - break; - - case '\\': - if (from[1] == ' ') from++; - /* FALL-THROUGH */ - - default: - *(to++) = *(from++); - } - } /* end of string, or found a space */ - - *(to++) = '\0'; /* terminate the string */ - } - - /* - * We have to have SOMETHING, at least. - */ + argc = rad_expand_xlat(request, cmd, MAX_ARGV, argv, 1, + sizeof(argv_buf), argv_buf); if (argc <= 0) { - radlog(L_ERR, "Exec-Program: empty command line."); + radlog(L_ERR, "Exec-Program: invalid command line."); return -1; } - /* - * Expand each string, as appropriate. - */ - to = argv_buf; - left = sizeof(argv_buf); - for (i = 0; i < argc; i++) { - int sublen; - - /* - * Don't touch argv's which won't be translated. - */ - if (strchr(argv[i], '%') == NULL) continue; - - if (!request) continue; - - sublen = radius_xlat(to, left - 1, argv[i], request, NULL, NULL); - if (sublen <= 0) { - /* - * Fail to be backwards compatible. - * - * It's yucky, but it won't break anything, - * and it won't cause security problems. - */ - sublen = 0; - } - - argv[i] = to; - to += sublen; - *(to++) = '\0'; - left -= sublen; - left--; - - if (left <= 0) { - radlog(L_ERR, "Exec-Program: Ran out of space while expanding arguments."); - return -1; - } - } - argv[argc] = NULL; - #ifndef __MINGW32__ /* * Open a pipe for child/parent communication, if necessary. diff --git a/src/main/util.c b/src/main/util.c index a5777d3..42cd53f 100644 --- a/src/main/util.c +++ b/src/main/util.c @@ -686,3 +686,159 @@ int rad_pps(int *past, int *present, time_t *then, struct timeval *now) return pps; } + +/* + * Split a string into words, xlat each one and write into argv array. + * Return argc or -1 on failure. + */ + +int rad_expand_xlat(REQUEST *request, const char *cmd, + int max_argc, const char *argv[], int can_fail, + size_t argv_buflen, char *argv_buf) +{ + const char *from; + char *to; + int argc = -1; + int i; + int left; + + if (strlen(cmd) > (argv_buflen - 1)) { + radlog(L_ERR, "rad_expand_xlat: Command line is too long"); + return -1; + } + + /* + * Check for bad escapes. + */ + if (cmd[strlen(cmd) - 1] == '\\') { + radlog(L_ERR, "rad_expand_xlat: Command line has final backslash, without a following character"); + return -1; + } + + strlcpy(argv_buf, cmd, argv_buflen); + + /* + * Split the string into argv's BEFORE doing radius_xlat... + */ + from = cmd; + to = argv_buf; + argc = 0; + while (*from) { + int length; + + /* + * Skip spaces. + */ + if ((*from == ' ') || (*from == '\t')) { + from++; + continue; + } + + argv[argc] = to; + argc++; + + if (argc >= (max_argc - 1)) break; + + /* + * Copy the argv over to our buffer. + */ + while (*from && (*from != ' ') && (*from != '\t')) { + if (to >= argv_buf + argv_buflen - 1) { + radlog(L_ERR, "rad_expand_xlat: Ran out of space in command line"); + return -1; + } + + switch (*from) { + case '"': + case '\'': + length = rad_copy_string(to, from); + if (length < 0) { + radlog(L_ERR, "rad_expand_xlat: Invalid string passed as argument"); + return -1; + } + from += length; + to += length; + break; + + case '%': + if (from[1] == '{') { + *(to++) = *(from++); + + length = rad_copy_variable(to, from); + if (length < 0) { + radlog(L_ERR, "rad_expand_xlat: Invalid variable expansion passed as argument"); + return -1; + } + from += length; + to += length; + } else { /* FIXME: catch %%{ ? */ + *(to++) = *(from++); + } + break; + + case '\\': + if (from[1] == ' ') from++; + /* FALL-THROUGH */ + + default: + *(to++) = *(from++); + } + } /* end of string, or found a space */ + + *(to++) = '\0'; /* terminate the string */ + } + + /* + * We have to have SOMETHING, at least. + */ + if (argc <= 0) { + radlog(L_ERR, "rad_expand_xlat: Empty command line."); + return -1; + } + + /* + * Expand each string, as appropriate. + */ + left = argv_buf + argv_buflen - to; + for (i = 0; i < argc; i++) { + int sublen; + + /* + * Don't touch argv's which won't be translated. + */ + if (strchr(argv[i], '%') == NULL) continue; + + if (!request) continue; + + sublen = radius_xlat(to, left - 1, argv[i], request, NULL, NULL); + if (sublen <= 0) { + if (can_fail) { + /* + * Fail to be backwards compatible. + * + * It's yucky, but it won't break anything, + * and it won't cause security problems. + */ + sublen = 0; + } else { + radlog(L_ERR, "rad_expand_xlat: xlat failed"); + return -1; + } + } + + argv[i] = to; + to += sublen; + *(to++) = '\0'; + left -= sublen; + left--; + + if (left <= 0) { + radlog(L_ERR, "rad_expand_xlat: Ran out of space while expanding arguments."); + return -1; + } + } + argv[argc] = NULL; + + return argc; +} +