I've just upgraded from RHEL 5 to 6.5 and setup fail2ban anew. I can't seem to get my custom action to work now, supposedly because of a permission issue. I wan't to know what am I doing wrong, and how can I make fail2ban run the script successfully.

I have a fail2ban action set up to run a generic shell script. I prefer things this way.

actionstart = <script> <jail> start

Where <script> is specified in the jail.local file:

action   = run-script[jail=drupal-reg-lim,script=/path/to/script.sh]

But I get a 126 exit code when I try to run the script, which, according to tldp.org, means that there is a "Permission problem or command is not an executable".

This happens regardless of the contents of script.sh - whether it is completely empty, or only has a shebang (#!/bin/sh). Trying to run sudo /path/to/script.sh works.

I tried changing the actionstart so that it would log, and placed the script as /etc/fail2ban/action.d/script.sh:

actionstart = <script> <jail> start || logger -dit fail2ban-run-script <script> <jail> start failed: exitcode = $?

Actually outputs the following into /var/log/messages:

Apr 23 05:49:25 xx1 fail2ban-run-script[8236]: /etc/fail2ban/action.d/script.sh drupal-reg-lim start failed: exitcode = 126

Also trying to run sh works. Only running a script fails. I also tried chmod 777 script.sh:

-rwxrwxrwx. 1 root root      10 Apr 23 05:12 script.sh

Another thought was that this might have to do with the SELinux security context (logging id output gave me uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:system_r:fail2ban_t:s0), but I haven't been successful at testing this (sudo -t fail2ban_t -r system_r /bin/sh fails with Permission denied even though fail2ban can run sh; I might be doing something wrong in my sudo).

Something that might be useful to know is that fail2ban uses Python's os.system() to execute the command. But my attempt at recreating it this way has failed too:

>>> import os
>>> print os.system('/etc/fail2ban/action.d/script.sh || echo "No"')

All of this leaves me with nothing. I'd be glad to get any kind of help.

(Side note: actually, fail2ban didn't get the 126 exit code for some reason, and simply spit out an error with a code of 0x7e00, which means the process has stopped but the exit code is zero. Took me some time to figure out, so thought I'd share.)

  • At least the github version of fail2ban uses subprocess.Popen to run shell commands. shell=True implies that it tries to run it as /bin/sh -c .... Enable debugging log level to see the actual command – jfs Apr 25 '14 at 20:40
  • Thanks for the comment. I found the solution, which had nothing to do with Python. Mind you, that I have the RHEL version of fail2ban, which uses os.system(). Adding a log message to print out the exact command used made me eventually get to the answer (see below). I would like to understand, though, how would you suggest that I enable debugging log level without changing code? I guess that's another question... – Yuval May 11 '14 at 23:56

As always, it had nothing to do with anything except for an error in the script I was trying to run!

Specifically, the script I was calling, was trying to run another script which is located in the same directory. To get the name of the common directory, rather than using BASE_DIR=$(dirname $(readlink -f "$0")) I accidently wrote BASE_DIR=$(readlink -f "$0"), and needless to say, "${BASE_DIR}/another_script.sh arg1 arg2..." failed (it was trying to run the non-existing non-sense path /path/to/script.sh/another_script.sh) with status code 126.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.