add timeout option to rlm_exec
authorMatthew Newton <mcn4@leicester.ac.uk>
Tue, 15 Oct 2013 21:40:29 +0000 (22:40 +0100)
committerAlan T. DeKok <aland@freeradius.org>
Wed, 16 Oct 2013 15:16:04 +0000 (11:16 -0400)
raddb/mods-available/echo
src/modules/rlm_exec/rlm_exec.c

index a99d443..ad3e159 100644 (file)
@@ -108,4 +108,16 @@ exec echo {
        #  That is to say: User-Name=BobUser => USER_NAME="BobUser"
        shell_escape = yes
 
+       #
+       #  How long should we wait for the program to finish?
+       #
+       #  Default is 10 seconds, which should be plenty for nearly
+       #  anything. Range is 1 to 30 seconds. You are strongly
+       #  encouraged to NOT increase this value. Decreasing can
+       #  be used to cause authentication to fail sooner when you
+       #  know it's going to fail anyway due to the time taken,
+       #  thereby saving resources.
+       #
+       #timeout = 10
+
 }
index a787d72..05dd975 100644 (file)
@@ -42,6 +42,7 @@ typedef struct rlm_exec_t {
        char            *packet_type;
        unsigned int    packet_code;
        int             shell_escape;
+       int             timeout;
 } rlm_exec_t;
 
 /*
@@ -60,6 +61,7 @@ static const CONF_PARSER module_config[] = {
        { "output_pairs",  PW_TYPE_STRING_PTR, offsetof(rlm_exec_t,output), NULL, NULL },
        { "packet_type", PW_TYPE_STRING_PTR, offsetof(rlm_exec_t,packet_type), NULL, NULL },
        { "shell_escape", PW_TYPE_BOOLEAN,  offsetof(rlm_exec_t,shell_escape), NULL, "yes" },
+       { "timeout", PW_TYPE_INTEGER,  offsetof(rlm_exec_t,timeout), NULL, NULL },
 
        { NULL, -1, 0, NULL, NULL }             /* end the list */
 };
@@ -179,7 +181,7 @@ static ssize_t exec_xlat(void *instance, REQUEST *request, char const *fmt, char
         *      FIXME: Do xlat of program name?
         */
        result = radius_exec_program(request, fmt, inst->wait, inst->shell_escape,
-                                    out, outlen, EXEC_TIMEOUT,
+                                    out, outlen, inst->timeout,
                                     input_pairs ? *input_pairs : NULL, NULL);
        if (result != 0) {
                out[0] = '\0';
@@ -265,6 +267,24 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                inst->packet_code = dval->value;
        }
 
+       /*
+        *      Get the time to wait before killing the child
+        */
+       if (!inst->timeout) {
+               inst->timeout = EXEC_TIMEOUT;
+       }
+       if (inst->timeout < 1) {
+               cf_log_err_cs(conf, "Timeout '%d' is too small (minimum: 1)", inst->timeout);
+               return -1;
+       }
+       /*
+        *      Blocking a request longer than 30 seconds isn't going to help anyone.
+        */
+       if (inst->timeout > 30) {
+               cf_log_err_cs(conf, "Timeout '%d' is too large (maximum: 30)", inst->timeout);
+               return -1;
+       }
+
        return 0;
 }
 
@@ -334,7 +354,7 @@ static rlm_rcode_t exec_dispatch(void *instance, REQUEST *request)
         *      into something else.
         */
        status = radius_exec_program(request, inst->program, inst->wait, inst->shell_escape,
-                                    out, sizeof(out), EXEC_TIMEOUT,
+                                    out, sizeof(out), inst->timeout,
                                     input_pairs ? *input_pairs : NULL, &answer);
        rcode = rlm_exec_status2rcode(request, out, strlen(out), status);
 
@@ -384,7 +404,7 @@ static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request)
 
        tmp = NULL;
        status = radius_exec_program(request, vp->vp_strvalue, we_wait, inst->shell_escape,
-                                    out, sizeof(out), EXEC_TIMEOUT,
+                                    out, sizeof(out), inst->timeout,
                                     request->packet->vps, &tmp);
        rcode = rlm_exec_status2rcode(request, out, strlen(out), status);
 
@@ -441,7 +461,7 @@ static  rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
        }
 
        status = radius_exec_program(request, vp->vp_strvalue, we_wait, inst->shell_escape,
-                                    out, sizeof(out), EXEC_TIMEOUT,
+                                    out, sizeof(out), inst->timeout,
                                     request->packet->vps, NULL);
        return rlm_exec_status2rcode(request, out, strlen(out), status);
 }