Enable building #WITHOUT_PROXY
[freeradius.git] / src / modules / rlm_exec / rlm_exec.c
index b417335..bf62521 100644 (file)
 #include <freeradius-devel/ident.h>
 RCSID("$Id$")
 
-#include <freeradius-devel/autoconf.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
 #include <freeradius-devel/radiusd.h>
 #include <freeradius-devel/modules.h>
 
@@ -38,6 +32,7 @@ RCSID("$Id$")
  */
 typedef struct rlm_exec_t {
        char    *xlat_name;
+       int     bare;
        int     wait;
        char    *program;
        char    *input;
@@ -93,6 +88,7 @@ static VALUE_PAIR **decode_string(REQUEST *request, const char *string)
                return &request->reply->vps;
        }
 
+#ifdef WITH_PROXY
        if (strcmp(string, "proxy-request") == 0) {
                if (!request->proxy) return NULL;
 
@@ -104,6 +100,7 @@ static VALUE_PAIR **decode_string(REQUEST *request, const char *string)
 
                return &request->proxy_reply->vps;
        }
+#endif
 
        if (strcmp(string, "config") == 0) {
                return &request->config_items;
@@ -120,13 +117,14 @@ static VALUE_PAIR **decode_string(REQUEST *request, const char *string)
 /*
  *     Do xlat of strings.
  */
-static int exec_xlat(void *instance, REQUEST *request,
-                    char *fmt, char *out, int outlen,
+static size_t exec_xlat(void *instance, REQUEST *request,
+                    char *fmt, char *out, size_t outlen,
                     UNUSED RADIUS_ESCAPE_STRING func)
 {
        int             result;
        rlm_exec_t      *inst = instance;
        VALUE_PAIR      **input_pairs;
+       char *p;
 
        input_pairs = decode_string(request, inst->input);
        if (!input_pairs) {
@@ -139,15 +137,19 @@ static int exec_xlat(void *instance, REQUEST *request,
        /*
         *      FIXME: Do xlat of program name?
         */
-       DEBUG2("rlm_exec (%s): Executing %s", inst->xlat_name, fmt);
+       RDEBUG2("Executing %s", fmt);
        result = radius_exec_program(fmt, request, inst->wait,
                                     out, outlen, *input_pairs, NULL, inst->shell_escape);
-       DEBUG2("rlm_exec (%s): result %d", inst->xlat_name, result);
+       RDEBUG2("result %d", result);
        if (result != 0) {
                out[0] = '\0';
                return 0;
        }
 
+       for (p = out; *p != '\0'; p++) {
+               if (*p < ' ') *p = ' ';
+       }
+
        return strlen(out);
 }
 
@@ -164,14 +166,6 @@ static int exec_detach(void *instance)
                free(inst->xlat_name);
        }
 
-       /*
-        *  Free the strings.
-        */
-       if (inst->program) free(inst->program);
-       if (inst->input) free(inst->input);
-       if (inst->output) free(inst->output);
-       if (inst->packet_type) free(inst->packet_type);
-
        free(inst);
        return 0;
 }
@@ -232,15 +226,6 @@ static int exec_instantiate(CONF_SECTION *conf, void **instance)
        }
 
        /*
-        *      Sanity check the config.  If we're told to wait,
-        *      then the output pairs should be defined.
-        */
-       if (inst->wait &&
-           (inst->output == NULL)) {
-               radlog(L_INFO, "rlm_exec: wait=yes but no output defined. Did you mean output=none?");
-       }
-
-       /*
         *      Get the packet type on which to execute
         */
        if (!inst->packet_type) {
@@ -248,7 +233,7 @@ static int exec_instantiate(CONF_SECTION *conf, void **instance)
        } else {
                DICT_VALUE      *dval;
 
-               dval = dict_valbyname(PW_PACKET_TYPE, inst->packet_type);
+               dval = dict_valbyname(PW_PACKET_TYPE, 0, inst->packet_type);
                if (!dval) {
                        radlog(L_ERR, "rlm_exec: Unknown packet type %s: See list of VALUEs for Packet-Type in share/dictionary", inst->packet_type);
                        exec_detach(inst);
@@ -258,8 +243,10 @@ static int exec_instantiate(CONF_SECTION *conf, void **instance)
        }
 
        xlat_name = cf_section_name2(conf);
-       if (xlat_name == NULL)
+       if (xlat_name == NULL) {
                xlat_name = cf_section_name1(conf);
+               inst->bare = 1;
+       }
        if (xlat_name){
                inst->xlat_name = strdup(xlat_name);
                xlat_register(xlat_name, exec_xlat, inst);
@@ -295,13 +282,16 @@ static int exec_dispatch(void *instance, REQUEST *request)
         */
        if (!((inst->packet_code == 0) ||
              (request->packet->code == inst->packet_code) ||
-             (request->reply->code == inst->packet_code) ||
-             (request->proxy &&
+             (request->reply->code == inst->packet_code)
+#ifdef WITH_PROXY
+             || (request->proxy &&
               (request->proxy->code == inst->packet_code)) ||
              (request->proxy_reply &&
-              (request->proxy_reply->code == inst->packet_code)))) {
-               DEBUG2("  rlm_exec (%s): Packet type is not %s.  Not executing.",
-                      inst->xlat_name, inst->packet_type);
+              (request->proxy_reply->code == inst->packet_code))
+#endif
+                   )) {
+               RDEBUG2("Packet type is not %s.  Not executing.",
+                      inst->packet_type);
                return RLM_MODULE_NOOP;
        }
 
@@ -311,12 +301,18 @@ static int exec_dispatch(void *instance, REQUEST *request)
        input_pairs = decode_string(request, inst->input);
        output_pairs = decode_string(request, inst->output);
 
+       if (!input_pairs) {
+               RDEBUG2("WARNING: Possible parse error in %s",
+                       inst->input);
+               return RLM_MODULE_NOOP;
+       }
+
        /*
         *      It points to the attribute list, but the attribute
         *      list is empty.
         */
-       if (input_pairs && !*input_pairs) {
-               DEBUG2("rlm_exec (%s): WARNING! Input pairs are empty.  No attributes will be passed to the script", inst->xlat_name);
+       if (!*input_pairs) {
+               RDEBUG2("WARNING! Input pairs are empty.  No attributes will be passed to the script");
        }
 
        /*
@@ -370,14 +366,18 @@ static int exec_postauth(void *instance, REQUEST *request)
        VALUE_PAIR *vp, *tmp;
        rlm_exec_t *inst = (rlm_exec_t *) instance;
 
-       vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM);
+       vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM, 0);
        if (vp) {
                exec_wait = 0;
 
-       } else if ((vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM_WAIT)) != NULL) {
+       } else if ((vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM_WAIT, 0)) != NULL) {
                exec_wait = 1;
        }
-       if (!vp) goto dispatch;
+       if (!vp) {
+               if (!inst->program) return RLM_MODULE_NOOP;
+               
+               return exec_dispatch(instance, request);
+       }
 
        tmp = NULL;
        result = radius_exec_program(vp->vp_strvalue, request, exec_wait,
@@ -397,8 +397,8 @@ static int exec_postauth(void *instance, REQUEST *request)
                 */
                tmp = pairmake("Reply-Message", "Access denied (external check failed)", T_OP_SET);
                pairadd(&request->reply->vps, tmp);
-               
-               DEBUG2("Login incorrect (external check failed)");
+
+               RDEBUG2("Login incorrect (external check failed)");
 
                request->reply->code = PW_AUTHENTICATION_REJECT;
                return RLM_MODULE_REJECT;
@@ -410,14 +410,48 @@ static int exec_postauth(void *instance, REQUEST *request)
                 *      exit status.
                 */
                request->reply->code = PW_AUTHENTICATION_REJECT;
-               DEBUG2("Login incorrect (external check said so)");
+               RDEBUG2("Login incorrect (external check said so)");
                return RLM_MODULE_REJECT;
        }
 
- dispatch:
-       if (!inst->program) return RLM_MODULE_NOOP;
+       return RLM_MODULE_OK;
+}
+
+/*
+ *     First, look for Exec-Program && Exec-Program-Wait.
+ *
+ *     Then, call exec_dispatch.
+ */
+static int exec_accounting(void *instance, REQUEST *request)
+{
+       int result;
+       int exec_wait = 0;
+       VALUE_PAIR *vp;
+       rlm_exec_t *inst = (rlm_exec_t *) instance;
+
+       /*
+        *      The "bare" exec module takes care of handling
+        *      Exec-Program and Exec-Program-Wait.
+        */
+       if (!inst->bare) return exec_dispatch(instance, request);
+
+       vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM, 0);
+       if (vp) {
+               exec_wait = 0;
+
+       } else if ((vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM_WAIT, 0)) != NULL) {
+               exec_wait = 1;
+       }
+       if (!vp) return RLM_MODULE_NOOP;
+
+       result = radius_exec_program(vp->vp_strvalue, request, exec_wait,
+                                    NULL, 0, request->packet->vps, NULL,
+                                    inst->shell_escape);
+       if (result != 0) {
+               return RLM_MODULE_REJECT;
+       }
 
-       return exec_dispatch(instance, request);
+       return RLM_MODULE_OK;
 }
 
 /*
@@ -432,17 +466,21 @@ static int exec_postauth(void *instance, REQUEST *request)
 module_t rlm_exec = {
        RLM_MODULE_INIT,
        "exec",                         /* Name */
-       RLM_TYPE_THREAD_SAFE,           /* type */
+       RLM_TYPE_CHECK_CONFIG_SAFE,     /* type */
        exec_instantiate,               /* instantiation */
        exec_detach,                    /* detach */
        {
                exec_dispatch,          /* authentication */
                exec_dispatch,          /* authorization */
                exec_dispatch,          /* pre-accounting */
-               exec_dispatch,          /* accounting */
+               exec_accounting,        /* accounting */
                NULL,                   /* check simul */
                exec_dispatch,          /* pre-proxy */
                exec_dispatch,          /* post-proxy */
                exec_postauth           /* post-auth */
+#ifdef WITH_COA
+               , exec_dispatch,
+               exec_dispatch
+#endif
        },
 };