ssh from Linux to Windows - why need so many slashes in path? - linux

I am trying to run commands over ssh from Linux machine to Windows machine.
Windows machine have OpenSSHx64 installed
Following command with double quotes fails:
ssh user#win8-pc "ls -l \\\\172.21.15.120\\vol0slash"
ls: cannot access 172.21.15.120vol0slash: No such file or directory
The same command with single quotes still fails, but at least display single slash:
ssh user#win8-pc 'ls -l \\\\172.21.15.120\\vol0slash'
ls: cannot access \172.21.15.120vol0slash: No such file or directory
Surrounding path with single quotes almost works, but still one root slash is missing:
ssh user#win8-pc "ls -l '\\\\172.21.15.120\\vol0slash'"
ls: cannot access \172.21.15.120\vol0slash: No such file or directory
Now finally adding fifth slash to UNC path root, did the trick:
ssh user#win8-pc "ls -l '\\\\\172.21.15.120\\vol0slash'"
total 536
drwxr-xr-x 1 Admin Domain Users 0 Jan 23 08:33 GeneralSystemDiagnostic
drwxr-xr-x 1 Admin Domain Users 0 Jan 22 08:10 cifs
-rw-r--r-- 1 Admin Domain Users 336 Jan 23 12:00 linux.txt
drwxr-xr-x 1 Admin Domain Users 0 Jan 19 14:11 nfs
Can anyone explain the logic behind this behavior?

Backslash is special symbol in bash and quite much in all Linux shells, therefore if you need to use it, it has to be escaped using another \ (backslash). The command is passed through the remote bash such as
bash -c "ls -l '\\\\\172.21.15.120\\vol0slash'"
which transfers evaluates the special characters and makes it look like
ls -l '\\\172.21.15.120\vol0slash'
when it is supposed to run.
The problem with using odd number of backslashes will end up evaluating as a special character, so you should go with even number, if you want to see a backslash in the end.
The other thing is how the arguments are interpreted by ls on Windows (which I have no idea about). See the tests with simple echo:
$ ssh f25 "echo '\1'"
\1
$ ssh f25 "echo '\\1'"
\1
$ ssh f25 "echo '\\\1'"
\\1
$ ssh f25 "echo '\\\\1'"
\\1
Similarly you can explain the original command without ':
ssh user#win8-pc "ls -l \\\\172.21.15.120\\vol0slash"
gets already in local shell (because it is not in ')
ssh user#win8-pc "ls -l \\172.21.15.120\vol0slash"
and remote shell gets already
bash -c "ls -l \\172.21.15.120\vol0slash"
which evaluates to
bash -c "ls -l \172.21.15.120vol0slash"
and to
ls -l 172.21.15.120vol0slash
which is obviously not existing.

Related

Command substitution doesn't work in script text passed over SSH [duplicate]

This question already has answers here:
Bash script runs one command before previous. I want them one after the other
(2 answers)
Closed 3 years ago.
I tried to use the following bash to access the content of a folder;
test_dir="/some_dir/dir_test"
ssh -t -t user#remote-host "
if [ -d '$test_dir' ]; then
sudo chown -R user:admin '$test_dir'
echo '$test_dir'/*
if [ '$(ls -A $test_dir)' ]; then
sudo rm -rf '$test_dir'/*
echo '$test_dir'/*
fi"
the script tried to check if /some_dir/dir_test is empty or not, if not, delete all files in that folder; but I got the following error;
ls: cannot access '/some_dir/dir_test': No such file or directory
/some_dir/dir_test
drwxr-xr-x. 3 sys admin 16 Sep 23 15:03 dir_test
However, I can ssh to remote-host and ls -A /some_dir/dir_test.
I am wondering how to fix it.
$(ls -A $test_dir) is being executed locally on the client, not the server. You need to escape the $. You'll also need to use " around it, otherwise the command substitution won't be executed.
if [ \"\$(ls -A $test_dir)\" ]; then
Often the best way to execute multiline commands is to use scp to copy a script to the remote machine, then use ssh to execute the script. Mixing local and remote expansion of variables and command substitutions gets complicated, especially when you need to quote them.

Handle permissions with groups in linux

I can't understand how exactly this works in Linux.
For example, I want only users in some group have access to execute some file (I hope this is possible without visudo).
I create a system user and system group like:
useradd -K UID_MIN=100 -K UID_MAX=499 -K GID_MIN=100 -K GID_MAX=499 -p \* -s /sbin/nologin -c "testusr daemon,,," -d "/var/testusr" testusr
I add my current user user to the group testusr (may be not cross platform):
adduser user testusr
I create some test shell file and set permissions:
touch test.sh
chmod ug+x test.sh
sudo chown testusr:testusr test.sh
But I still can't start test.sh as user:
./test.sh
-> Error
Now I look for some system groups like cdrom to check how they work. My user is in cdrom group and can use the cd rom on my computer:
$ ls -al /dev/cdrom
lrwxrwxrwx 1 root root 3 апр. 17 12:55 /dev/cdrom -> sr0
$ ls -al /dev/sr0
brw-rw----+ 1 root cdrom 11, 0 апр. 17 12:55 /dev/sr0
Addition:
./test.sh command starts to work as I want after system reboot. Strange...
I'm on Ubuntu Studio 15.10
The group changes are reflected only upon re-login.

ssh sudo pipe command

this command works
ssh -t www.foo.com 'sudo ls -l'
I immediately get asked for my password, once entered I get the directory contents
if I try to pipe this command it fails - I never get asked my password so I never get any contents.
ssh -t www.foo.com 'sudo ls -l' | grep 'foo'
This is a basic example, I know I could pipe/grep the output in my "ls" command. for my application I need to pipe the output through a program on my host.
In order to not be asked for a password to issue sudo commands, you need to have an entry in /etc/sudoers (or better, a file in /etc/sudoers.d) that lets you do it. There is a nice question on using sudoers here.
A sudoers config to allow you to run ls as root could be:
<yourusername> ALL = (root) NOPASSWD: /bin/ls
One thing to look out for is that ls is quite likely to be a shell built-in, so you may have trouble allowing it. You should be able to set your shell to defer to the system binary instead.
Trying to push your real password through it is not a secure solution.
ssh -t www.foo.com 'echo your_pass | sudo -S ls -l' | grep 'foo'
Also possible:
ssh -t www.foo.com 'sudo -S ls -l <~/passwd.txt' | grep 'foo'
The reason you are not getting prompt for password is because you are feeding the output of "ssh -t www.foo.com 'sudo ls -l'" to the pipe where you are grepping for 'foo'. So in this case the password prompt won't be shown, but actually the process is waiting for your input.
Try giving the password on the blank new line you get after running the command.
I tried this and it worked. Just for example,
$ ssh -t user#host 'sudo ls -l /' | grep 'root'
user#host's password: <===== After this, it waits for user input to feed the password for sudo user.
Connection to host closed.
drwxr-xr-x 2 root root 4096 2011-08-31 15:33 bin
dr-xr-xr-x 24 root root 4096 2014-07-14 00:52 bldmnt
dr-xr-xr-x 2 root root 4096 2011-03-23 15:51 blr
drwxr-xr-x 3 root root 4096 2011-08-31 15:36 boot
.
.
.
Try it and see if it works for you.

Problems running BASH script from a different directory (directory is in path)

To start learning BASH scripting, I've created a trivial script that curls down a stock price from YAHOO and prints it to STDOUT. I've set the permissions to rwx for everyone, and moved the file into my path:
Script:
root#raspberrypi:~/code/scripts$ cat quote
#!/bin/bash
while getopts "s:" opt; do
case $opt in
s)STOCK="$OPTARG";;
\?) echo "ERROR"; exit 1;;
esac
done
PRICE=$(curl -s "http://download.finance.yahoo.com/d/quotes.csv?s=${STOCK}&f=l1")
echo "${STOCK}: ${PRICE}"; exit 0
exit 0
I then set the permissions for all users:
root#raspberrypi:~/code/scripts$ chmod 777 quote
Here is my $PATH:
root#raspberrypi:~/code/scripts$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
I now move it into my path in what I read was the appropriate location for custom user scripts:
root#raspberrypi:~/code/scripts$ ls -la /usr/local/bin
total 12K
drwxrwsr-x 2 root staff 4.0K Apr 30 01:28 ./
drwxrwsr-x 10 root staff 4.0K Jan 1 1970 ../
-rwxrwxrwx 1 root root 433 Apr 30 01:22 quote*
The which command will find it (expected):
root#raspberrypi:~/code/scripts$ which quote
/usr/local/bin/quote
PROBLEM: when I run the script, it returns the first option on the next line followed by my prompt:
root#raspberrypi:~/code/scripts$ quote -s aapl
'-s'root#raspberrypi:~/code/scripts$
But, when I run the script with a full path, it works just fine:
root#raspberrypi:~/code/scripts$ /usr/local/bin/quote -s aapl
-s: 592.33
Apologies if this less a programming question and more a Unix question, but I want to make sure I rule out a problem with my code before I do anything else.
I'm sure this is something very easy, so thanks in advance for the extra set of eyes.
You just chose an unfortunate name for your script. quote is also the name of a function from the bash_completion package, and functions override external scripts.
type quote will show that it's a function (whereis doesn't know about these things).
Either rename it or disable bash_completion. Or run command quote every time.

command not found when runng bash script as user apache

I am trying to run a bash script as user apache. and it throws up the following
[apache#denison public]$ ll
total 32
drwxr-xr-x 2 apache apache 4096 Jul 17 08:14 css
-rw-r--r-- 1 apache apache 4820 Jul 17 10:04 h3111142_58_2012-07-17_16-03-58.php
-rwxrwxrwx 1 apache apache 95 Jul 17 10:04 h31111.bash
drwxr-xr-x 2 apache apache 4096 Jul 17 08:14 images
-rw-r--r-- 1 apache apache 754 Jul 17 08:13 index.php
drwxr-xr-x 2 apache apache 4096 Jul 17 08:14 javascript
drwxr-xr-x 5 apache apache 4096 Jul 17 08:14 jquery-ui-1.8.21.custom
[apache#denison public]$ bash h31111.bash
: command not found :
contents of the file are:
#!/bin/bash
/usr/bin/php /opt/eposdatatransfer/public/h3111142_58_2012-07-17_16-03-58.php
php script runs fine below are the results
[apache#denison public]$ /bin/bash h31111.bash
: command not found:
[apache#denison public]$ chmod +x h31111.bash
[apache#denison public]$ ./h31111.bash
./h31111.bash: Command not found.
[apache#denison public]$ php h3111142_58_2012-07-17_16-03-58.php
creation of file:
$batchFile = $this->session->username . "_" . $index . "_" . $date . ".sh";
$handle = fopen($batchFile, 'w');
$data = "#!/bin/bash
/usr/bin/php /opt/eposdatatransfer/public/$file
";
/*
rm -rf /opt/eposdatatransfer/public/$file
rm -rf /opt/eposdatatransfer/public/$batchFile*";*/
fwrite($handle, $data);
fclose($handle);
batchfile is the bash script and file is the php file. These get craeted automatically based on user input in webapp. my webapp runs on linux.
I'm guessing you uploaded the script from a windows machine, and didn't strip the carriage returns from the end of the lines. This causes the #! mechanism (the first line of most scripts) to fail, because it searches for #!/some/interpreter^M, which rarely exists.
You can probably strip the carriage returns, if you have them, using fromdos or:
tr -d '\015' < /path/to/script > /tmp/script; chmod 755 /tmp/script; mv /tmp/script /path/to/script
What happens if you try to run your script with
$ /bin/bash h31111.bash
Try this (assuming your script file is named "h31111.bash"):
$ chmod +x h31111.bash
then to run it
$ ./h31111.bash
Also are you sure you have the right path for your php command? What does which php report?
--
As #jordanm correctly suggests based on the output of the file command I suggested you run, you need to run the dos2unix command on your file. If you don't have that installed this tr -d '\r' will also work. I.e.,
$ tr -d '\r' h31111.bash > tmp.bash
$ mv tmp.bash h31111.bash
and you should be all set.
Under some versions of Ubuntu these utilities (e.g., dos2unix) don't come installed, for information on this see this page.
It looks to me the problem is your $PATH. Some users on the system will have . (the current directory) in their $PATH and others will not. If typing ./h31111.bash works, then that's your problem. You can either specify the file with a relative or absolute path, or you can add . to the $PATH of that user but never do that for root.
Since you're not sure where it's failing, let's try to find out.
First, can you execute the program?
./h31111.bash
That should be equivalent to invoking it with:
/bin/bash h31111.bash
If the above gives you the same error message than it's likely a problem with the script contents. To figure out where something's gone awry in a bash script, you can use set -x and set -v.
set -x will show you expansions
set -v will show you the lines before their read
So, you'd change your script contents to something like the following:
#!/bin/bash
set -x
set -v
/usr/bin/php /opt/eposdatatransfer/public/h3111142_58_2012-07-17_16-03-58.php
Another possibility, which you probably only learn by experience, is that the file is in MSDOS mode (i.e., has CR LF's instead of just LFs). This often happens if you're still using FTP (as opposed to SFTP) and in ASCII mode. You may be able to set your transfer mode to binary and have everything work successfully. If not, you have a few options. Any of the following lines should work:
dos2unix /path/to/your/file
sed -i 's/\r//g' /path/to/your/file
tr -d '\r' < /path/to/your/file > /path/to/temp/file && mv /path/to/temp/file /path/to/your/file
In Vim, you could do :set ff=unix and save the file to change the format as well.
Let's take a look at what you have in PHP:
$handle = fopen($batchFile, 'w');
$data = "#!/bin/bash
/usr/bin/php /opt/eposdatatransfer/public/$file
";
Since you have a multi-line string, the CR LF characters that are embedded will depend on whether your PHP file is in Windows or Unix format. You could switch that file to Windows format and you'd be fine. But that seems easy to break in the future, so I'd go with something a little less volatile:
$handle = fopen($batchFile, 'w');
fwrite($handle, "#!/bin/bash\n");
fwrite($handle, "/usr/bin/php /opt/eposdatatransfer/public/$file\n");
fclose($handle);

Resources