Logo Search packages:      
Sourcecode: hexec version File versions  Download package

expr-eval-exec.c

/***************************************************************************
 *   Copyright (C) 2008 by Alexander Block                                 *
 *   ablock@blocksoftware.net                                              *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "config.h"

#include "common/expr.h"
#include "common/args.h"
#include "common/buf.h"
#include "common/error.h"
#include "common/locate.h"
#include "common/utils.h"
#include "hexec/hexec.h"
#include "libhexec-hook.h"

#include <stdlib.h>
#include <ctype.h>
#include <stdbool.h>
#include <string.h>
#include <fnmatch.h>
#include <assert.h>
#include <unistd.h>
#include <sys/wait.h>

static void remove_ld_preload(struct args_t* env)
{
    for(int i = 0; i < env->argc; i++)
    {
        char* a = strstr(env->argv[i], "LD_PRELOAD=");
        if(a == env->argv[i])
        {
            char* b = strstr(env->argv[i], HEXEC_LIBHOOK);
            if(b)
            {
                int pos = b - env->argv[i];
                int len = strlen(HEXEC_LIBHOOK);
                //hexec_log("env1 = %s\n", env->argv[i]);
                if(b[-1] == '=' || (isspace(b[-1])) && (b[len] == 0 || isspace(b[len])))
                {
                    memmove(env->argv[i] + pos, env->argv[i] + pos + len, strlen(env->argv[i]) - pos - len + 1); 
                }
                //hexec_log("env2 = %s\n", env->argv[i]);
            }
            hexec_args_remove(env, i--);
        }
    }
}

#define PLACEHOLDER_QUOTE           0x0001
#define PLACEHOLDER_ESCAPE          0x0002
#define PLACEHOLDER_AS_SINGLE_ARGS  0x0004

static bool needs_escaping(char ch)
{
    return !isalnum(ch);
    //if(ch == '\'' || ch == '\"' || ch == '(' || ch == ')' || ch == ' ' || ch == '$' || ch == '<')
    //    return true;
    //return false;
}

static int insert_exec_args(struct args_t* exec_args, struct args_t* orig_args, const char* arg)
{
    int ins_arg_len = 0;
    int ins_arg_max = 32;
    char* ins_arg = malloc(ins_arg_max);

    int arg_len = strlen(arg);
    assert(arg_len);
    int pos = 0;
    while(pos < arg_len)
    {
        if(arg[pos] == '{' && (pos == 0 || arg[pos - 1] != '\\'))
        {
            int flags = 0;
            
            int start = pos;
            int end = start;
            while(end < arg_len && arg[end] != '}')
                end++;
            if(end == arg_len)
                goto format_error;

            bool is_insert_cnt = false;
            int first_arg = -1;
            int arg_cnt = 0;
            //hexec_log("start=%s\n", arg + start);
            for(int i = start + 1; i <= end && first_arg == -1; i++)
            {
                switch(arg[i])
                {
                case 'q':
                    flags |= PLACEHOLDER_QUOTE;
                    break;
                case 's':
                    flags |= PLACEHOLDER_AS_SINGLE_ARGS;
                    break;
                case 'e':
                    flags |= PLACEHOLDER_ESCAPE;
                    break;
                case '}':
                    first_arg = 0;
                    arg_cnt = orig_args->argc;
                    break;
                default:
                    if(arg[i] == 'n')
                    {
                        is_insert_cnt = true;
                        if(i + 1 != end)
                            goto format_error;
                    }
                    else
                    {
                        for(int j = i; j < end; j++)
                        {
                            if(!isdigit(arg[j]))
                                goto format_error;
                        }
                        first_arg = atoi(arg + i);
                        arg_cnt = 1;
                    }
                    break;
                }
            }
            if(!is_insert_cnt && (first_arg < 0 || first_arg >= orig_args->argc || first_arg + arg_cnt > orig_args->argc))
                goto out_of_range_error;

            if(flags & PLACEHOLDER_AS_SINGLE_ARGS)
            {
                /* commit the current argument */
                if(ins_arg_len > 0)
                {
                    hexec_args_add(exec_args, ins_arg);
                    *ins_arg = 0;
                    ins_arg_len = 0;
                }
            }

            if(is_insert_cnt)
            {
                char tmp[32];
                sprintf(tmp, "%d", orig_args->argc);
                if(flags & PLACEHOLDER_QUOTE)
                    ins_arg = hexec_xstrcatch(ins_arg, '\"', &ins_arg_len, &ins_arg_max);
                ins_arg = hexec_xstrcat(ins_arg, tmp, &ins_arg_len, &ins_arg_max);
                if(flags & PLACEHOLDER_QUOTE)
                    ins_arg = hexec_xstrcatch(ins_arg, '\"', &ins_arg_len, &ins_arg_max);
                if(flags & PLACEHOLDER_AS_SINGLE_ARGS)
                {
                    /* commit the current argument */
                    if(ins_arg_len > 0)
                    {
                        hexec_args_add(exec_args, ins_arg);
                        *ins_arg = 0;
                        ins_arg_len = 0;
                    }
                }
            }
            else
            {
                for(int i = 0; i < arg_cnt; i++)
                {
                    if(i != 0 && !(flags & PLACEHOLDER_AS_SINGLE_ARGS))
                        ins_arg = hexec_xstrcatch(ins_arg, ' ', &ins_arg_len, &ins_arg_max);
                    if(flags & PLACEHOLDER_QUOTE)
                        ins_arg = hexec_xstrcatch(ins_arg, '\"', &ins_arg_len, &ins_arg_max);
                    if(flags & PLACEHOLDER_ESCAPE)
                    {
                        const char* a = orig_args->argv[i + first_arg];
                        for(int j = 0; a[j]; j++)
                        {
                            if(needs_escaping(a[j]))
                                ins_arg = hexec_xstrcatch(ins_arg, '\\', &ins_arg_len, &ins_arg_max);
                            ins_arg = hexec_xstrcatch(ins_arg, a[j], &ins_arg_len, &ins_arg_max);
                        }
                    }
                    else
                    {
                        ins_arg = hexec_xstrcat(ins_arg, orig_args->argv[i + first_arg], &ins_arg_len, &ins_arg_max);
                    }
                    if(flags & PLACEHOLDER_QUOTE)
                        ins_arg = hexec_xstrcatch(ins_arg, '\"', &ins_arg_len, &ins_arg_max);

                    if(flags & PLACEHOLDER_AS_SINGLE_ARGS)
                    {
                        hexec_args_add(exec_args, ins_arg);
                        *ins_arg = 0;
                        ins_arg_len = 0;
                    }
                }
            }

            pos = end + 1;
        }
        else
        {
            ins_arg = hexec_xstrcatch(ins_arg, arg[pos], &ins_arg_len, &ins_arg_max);
            pos++;
        }
    }

    /* commit the remaining argument */
    if(ins_arg_len > 0)
    {
        hexec_args_add(exec_args, ins_arg);
    }

success:
    free(ins_arg);
    return 0;

unknown_error:
    hexec_fatal("error while processing replacement argument\n");
    free(ins_arg);

format_error:
    hexec_error("invalid format of replacement argument '%s'\n", arg);
    free(ins_arg);
    return -1;

out_of_range_error:
    hexec_error("replacement argument '%s' out of range\n", arg);
    free(ins_arg);
    return -1;
}

int eval_exec(const char* path, struct args_t* args, struct args_t* env, struct hexec_buf* buf, struct hexec_expr* e, int* last_exec_status)
{
    char* exec_path;
    struct args_t exec_args;
    struct args_t exec_env;

//hexec_log("eval_exec\n");

    hexec_args_init(&exec_args);
    hexec_args_init(&exec_env);
    for(int i = 0; i < env->argc; i++)
        hexec_args_add(&exec_env, env->argv[i]);
    for(int i = 0; i < e->argc; i++)
    {
        int* argv = (int*)(buf->buf + e->argv);
        char* arg = buf->buf + argv[i];
        if(insert_exec_args(&exec_args, args, arg))
            return HEXEC_EXPR_RESULT_ERROR;
    }
    remove_ld_preload(&exec_env);

    if(hexec_locate(exec_args.argv[0], &exec_path))
    {
        hexec_error("could not locate %s\n", exec_args.argv[0]);
        hexec_args_free(&exec_args);
        hexec_args_free(&exec_env);
        return HEXEC_EXPR_RESULT_ERROR;
    }

    //hexec_args_print(&exec_args);
    //hexec_log("\n");
    //hexec_args_print(&exec_env);

    int pid = fork();
    if(pid == -1)
        hexec_fatal("failed to fork\n");
    if(pid == 0)
    {
        int err = orig_execve(exec_path, exec_args.argv, exec_env.argv);
        hexec_log("execve err = %d\n", err);
        exit(err);
    }

    int status;
    if (waitpid(pid, &status, 0) != pid) 
    {
        hexec_fatal("waitpid failed\n");
    }

    if (WEXITSTATUS(status) == 0 && WIFSIGNALED(status)) 
    {
        *last_exec_status = -1;
    }
    else
    {
        *last_exec_status = WEXITSTATUS(status);
    }

    free(exec_path);
    hexec_args_free(&exec_args);
    hexec_args_free(&exec_env);

    return HEXEC_EXPR_RESULT_MATCH;
}


Generated by  Doxygen 1.6.0   Back to index