Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash: Only allow script to run by being called from another script

We have two bash scripts to start up an application. The first (Start-App.sh) one sets up the environment and the second (startup.sh) is from a 3rd party that we are trying not to heavily edit. If someone runs the second script before the first the application does not come up correctly.

Is there a way to ensure that the startup.sh can only be called from the Start-App.sh script?

They are both in the same directory and run via bash on Red Hat Linux.

like image 726
HF Clibron Avatar asked Dec 19 '22 18:12

HF Clibron


2 Answers

Is there a way to ensure that the startup.sh can only be called from the Start-App.sh script?

Ensure? No. And even less so without editing startup.sh at all. But you can get fairly close.

Below are three suggestions − you can either use one of them, or any combination of them.


The simplest, and probably the best, way is to add a single line at the top of startup.sh:

[ -z $CALLED_FROM_START_APP ] && { echo "Not called from Start-App.sh"; exit 42; }

And then call it from Start-App.sh like so:

export CALLED_FROM_START_APP=yes
sh startup.sh

of course, you can set this environment variable from the shell yourself, so it won't actually ensure anything, but I hope your engineering staff is mature enough not to do this.


You can also remove the execute permissions from startup.sh:

$ chmod a-x startup.sh

This will not prevent people from using sh startup.sh, so there is a very small guarantee here; but it might prevent auto-completion oopsies, and it will mark the file as "not intended to be executed" − if I see a directory with only one executable .sh file, I'll try and run that one, and not one of the others.


Lastly, you could perhaps rename the startup.sh script; for example, you could rename it to do_not_run, or "hide" it by renaming it to .startup. This probably won't interfere with the operation of this script (although I can't check this).

like image 188
Martin Tournoij Avatar answered Dec 21 '22 06:12

Martin Tournoij


TL;DR:

[ $(basename "$0") = "Start-App.sh" ] || exit


Explanation

As with all other solutions presented it's not 100% bulletproof but this covers most common instances I've come across for preventing accidentally running a script directly as opposed to calling it from another script.

Unlike other approaches presented, this approach:

  • doesn't rely on manually set file names for each included/sourced script (i.e. is resilient to file name changes)
  • behaves consistently across all major *nix distros that ship with bash
  • introduces no unnecessary environment variables
  • isn't tied to a single parent script
  • prevents running the script through calling bash explicitly (e.g. bash myscript.sh)

The basic idea is having something like this at the top of your script:

[ $(basename "$0") = $(basename "$BASH_SOURCE") ] && exit

$0 returns the name of the script at the beginning of the execution chain

$BASH_SOURCE will always point to the file the currently executing code resides in (or empty if no file e.g. piping text directly to bash)

basename returns only the main file name without any directory information (e.g. basename "/user/foo/example.sh" will return example.sh). This is important so you don't get false negatives from comparing example.sh and ./example.sh for example.

To adapt this to only allow running when sourced from one specific file as in your question and provide a helpful error message to the end user, you could use:

[ $(basename "$0") = "Start-App.sh"  ] || echo "[ERROR] To start MyApplication please run ./Start-App.sh" && exit

As mentioned from the start of the answer, this is not intended as a serious security measure of any kind, but I'm guessing that's not what you're looking for anyway.

like image 42
nathanchere Avatar answered Dec 21 '22 08:12

nathanchere