55

I've got SSH passwordless set up, however it prints the MoTD when it logs in. Is there anyway to stop that happening from the client side?

I've tried ssh -q but that doesn't work. I don't want to use ~/.hushlogin nor do I want to change the server set up. The only thing that can work is to quiet all output, with >/dev/null 2>&1. However, I don't want to ignore errors in case there actually is a problem. Even doing >/dev/null doesn't work, since ssh seems to print the motd to the stderr.

Update & reasoning I'm running backup in a cron. I don't want to get a cron email unless an error has occured. However if the motd is printed I'll get an email all the time.

I want to keep the motd being printed because that has legal implications. The motd says "unathorized access prohibited". You need to have this sort of statement in there to legally prevent people from access it (like a no trespassing sign). Hence I don't want to blanket disable it all the time.

4
  • 1
    Can you add some details about the cron job ... Aug 6, 2009 at 12:20
  • 1
    The motd is only printed for interactive sessions. I just tested it, and it is so: > $ ssh host → MOTD printed > $ ssh host ls → prints only the content of the home directory In other words, you're doing something very wrong; have you even tried?
    – niXar
    Aug 9, 2009 at 2:36
  • It is also worth noting to check in /etc/profile.d for any scripts that may run there and print some output to the console on login.
    – Dave
    Mar 13, 2014 at 1:28
  • 5
    Is there really a law that requires you to say "unauthorized access prohibited"? I thought the DMCA makes it illegal to break any sort of electronic system (no matter how poorly protected), so as long as you have some sort of password/SSH key requirement, this seems like pure window dressing.
    – Nick T
    Jun 1, 2015 at 22:24

16 Answers 16

68
+50

I'm not sure why you have an aversion to doing this correctly - either on the server a la

PrintMotd no
PrintLastLog no

and

#/etc/pam.d/ssh
# Print the message of the day upon successful login.
# session    optional     pam_motd.so

Or adding ~/.hushlogin for each user.

Hint, for ~/.hushlogin, add it to /etc/skel so new user home directories are created with the file.

Update:

Without more information about your backup cron job, my only other suggestion is to redirect the output of the command to a file (or let cron capture it in email) and the output of the ssh session to /dev/null. Something like:

0 0 * * * ssh backuphost "backup_script_that_writes_to_a_log" >/dev/null

Or

0 0 * * * ssh backuphost "backup_command 2>&1" >/dev/null

I'd have to play around with the commands a bit, but that should get you started.

8
  • 4
    I like the "doing correctly".
    – Benoit
    Aug 5, 2009 at 13:44
  • 18
    I don't want to remove it from the server since I need to keep an 'authorized access prohibited' notice there for legal reasons. Aug 6, 2009 at 8:22
  • 3
    Fwiw, the notice doesn't prevent unauthorized access, it merely notifies people that you can (and will) take appropriate legal action, and may be monitoring their use, just like notification about recording a phone conversation.
    – jtimberman
    Aug 7, 2009 at 5:35
  • 4
    .hushlogin is nice Mar 27, 2016 at 23:24
  • 1
    @geedoubleya: Because I provided an actual solution? Just because someone doesn't want a specific answer to their problem doesn't mean it isn't a good answer. Trying to work around something because one "doesn't want to" isn't good professional practice. Sometimes we have to type things into our computers to get them to do what we want, and sometimes we have to type more than we want to. This is a thing solvable in a repeatable manner with automation/base images, etc.
    – jtimberman
    Dec 28, 2016 at 19:11
22

@note All examples assume you've set a variable connectionString with something like connectionString=user@server.

How I got to the solution

Using ssh -T should work for simple commands. For example this doesn't print any extra information:

ssh -T $connectionString "echo 'blah'"

The problem is when you try to use here-doc to run many commands. For example - bellow will NOT work - it will echo message of the day (MoTD) and also might show you "stdin: is not a tty".

somethingLocal='something local'
ssh -T $connectionString <<EOC
    echo 'blah'
    echo "blah $somethingLocal"
EOC

To workaround the issue you need first save commands to local variable and the send them to remote server.

somethingLocal='something local'
read -r -d '' commands <<EOC
    echo 'blah'
    echo "blah $somethingLocal"
EOC
ssh -T $connectionString "$commands"

But that's messy...

Final solution

Make a universal function (note that it can take a string or HEREDOC as commands).

function silentSsh {
    local connectionString="$1"
    local commands="$2"
    if [ -z "$commands" ]; then
        commands=`cat`
    fi
    ssh -T $connectionString "$commands"
}

Examples

Use this like so:

somethingLocal='something local'
silentSsh $connectionString <<EOC
    echo 'blah'
    echo "blah $somethingLocal"
EOC

Or like so:

silentSsh $connectionString "echo 'blah'"

Or like so:

silentSsh $connectionString <<'EOC'
    echo 'blah'
    somethingRemote=`echo 'whatever'`
    echo "blah $somethingRemote"
EOC

Or even like so:

silentSsh $connectionString < getlines.sh
2
  • 2
    I wish I had more upvotes for this. Very helpful in figuring out some over-ssh-scripting we needed to do.
    – csexton
    Jul 10, 2018 at 17:17
  • 1
    Fantastic Answer!! Thank you very much!!
    – Scottie H
    Jul 23, 2019 at 19:41
19

If you want this on a per-user basis, just do a touch ~/.hushlogin and you're all set with OpenSSH.

Update: As pointed out elsewhere, pam_motd may be configured to not use a per-user .hushlogin; check /etc/login.defs for HUSHLOGIN_FILE. It may be configured to have all users listed in /etc/hushlogins or similar.

1
  • 2
    I tried that, but it didn't work. As others have pointed out, the motd might be printed from pam Aug 6, 2009 at 8:22
11

How about this hack? ;-P

ssh -t user@machineName '/bin/bash'

The following is not valid:

Passing -T to ssh to disable tty allocation:

ssh -T machineName 'echo foo'
5
  • 4
    ssh user@machine 'your command here' does not show the motd anyway (it is not an interactive shell). Jul 6, 2009 at 17:30
  • 1
    Oh good, point.... Jul 6, 2009 at 17:39
  • but what it means "it is not an interactive shell" since I tried and i can run commands what would I be missing using -t Sep 8, 2016 at 18:47
  • please note that adding "-t" changes the behavior (it displays according to your TERM settings, adds control characters when needed, etc). It can change the result of some commands (it could for exemple introduce errors in : ssh -t somehost "tar cf - some files" > local.tar # DO NOT use -t here... especially if you ssh a unix host from a windows one. but many other problem may arise in other cases ). See the wonderful @StephaneChazelas answer: unix.stackexchange.com/questions/151916/… Jun 21, 2018 at 9:19
  • Please, note that this solution works quite well without -t or -T argument. MOTD is for interactive shell and the moment were are not interactive it is not displayed. Great solution, because it works without maintaining any other files and messing with terminal allocation.
    – Sergei G
    Sep 25, 2020 at 2:26
3

What operating system is this? On some systems (like ubuntu) the motd isn't printed by the ssh server (PrintMotd in /etc/ssh/sshd_config), but by pam with pam_motd. If this is the case then you probably can't control it from the client.

2
  • you can't control it in the ssh client, but you can for sure on the client side :) .. see my answer for details
    – drAlberT
    Aug 7, 2009 at 14:29
  • No, you've proposed a pretty interesting/clever hack around the motd being printed, not a solution to stop it being printed by the client, which was the question. Aug 8, 2009 at 2:06
2

You have to do it on the server:

PrintMotd no
PrintLastLog no

On debian/ubtuntu also hash the line with pam_motd.so:

#/etc/pam.d/ssh
# Print the message of the day upon successful login.
# session    optional     pam_motd.so
2
  • No you don't. See Kyle Brandt's answer below.
    – Stobor
    Aug 6, 2009 at 6:15
  • -1 - Answer does not reflect edited question. No longer relevant.
    – romandas
    Aug 6, 2009 at 19:52
2

Don't execute ssh command directly by cron.

Make an helper bash script instead, executing the ssh job and fetching the output, the errors and the error code if needed; eventually parse them in order to remove unwanted strings from error messages (the MoTD in your case) and then re print on the bash script output and error streams what you have obtained in such a way.

Than put this bash script in cron and live happy :)

Note: This is a general solution, and has to work whatever is the job you have to perform via ssh. It is only client side too, which should fulfill your needs ... the only dependence of the client on the server config is the knowledge of the exact message you want to cut out from the std err or out of ssh client

2
  • 2
    That's not a solution that's a workaround.
    – niXar
    Aug 9, 2009 at 2:43
  • I can't agree with you sorry. IMHO that's the way things should be done cleanly ... I'd agreed with you if there were been a way to explicitly configure ssh client to ignore the motd, but it can't exists, simply because it is not under the sshd control!
    – drAlberT
    Aug 10, 2009 at 8:06
2

Just a sidenote (would have been a comment, if I could post that): Contents of motd are shown after successfull login to the system. If I'd like to legally prevent people from accessing a box I'd rather do that by a "Banner" in sshd_config. The contents are displayed after entering Username but before authenticating.

3
  • 4
    yes, but you can disable the banner using -q on the ssh client, so I can't agree with your note
    – drAlberT
    Aug 7, 2009 at 14:31
  • 1
    Oh boy, I can totally see it, "-q" defeating the whole defense of the crack legal team working for Dynacorp Inc. Gosh darn it! They hadn't seen it coming. Get real. If someone who's supposed to see the banner purposefully evades it ... the banner is still binding, since you had to know it to evade it.
    – niXar
    Aug 9, 2009 at 2:47
  • @niXar No banner is "binding" anyway. Nov 19, 2020 at 14:45
2

Either you haven't tried what you're describing, or your servers are configured wrong!

Here's what I just tried on RHEL5:

workstation ~ $ ssh root@server
server ~ # echo "MOTD" > /etc/motd
server ~ # ^D
workstation ~ $ ssh root@server
MOTD
server ~ # ^D
workstation ~ $ ssh root@server echo notice the lack of motd
notice the lack of motd
workstation ~ $ 

I don't suppose you need the disclaimer to be sent to non-interactive shells, do you? (If anyone claims you do, do me a favor, kick them in the nuts.) Because that's exactly why there's a distinction between interactive shells and non-interactive ones.

But in any case, here's what I do because I don't like mail from cron: I pipe the output to logger. Just pipe it through tail to remove the first few (let's say 3) lines of your pointless disclaimer as such (untested code, I don't have access to my scripts):

( tail -n +3 | logger -i -t mycronjob -s -p cron.crit ) <&6 &
exec 2>&6
cron_fsckin_job
2
  • If you look in man sshd, you'll see that it says: LOGIN PROCESS When a user successfully logs in, sshd does the following: 1. If the login is on a tty, and no command has been specified, prints last login time and /etc/motd (unless prevented in the configuration file or by ~/.hushlogin; see the FILES section). 2. ... Notice that if a command is entered directory in the ssh login, no MOTD is displayed
    – katriel
    Aug 9, 2009 at 21:53
  • I know, that's what I was demonstrating. What's your point?
    – niXar
    Aug 10, 2009 at 0:31
1

If I understand you, you need motd for other reasons but don't need motd for backup. In the config of sshd cannot set it up by user basis only globally. Therefore you need solve motd supression in client side. But there is not difference between motd's text and the backup software's error messages. Both are text in the terminal. The only solution I see to make difference between this two message then filter the motd's one. Because software's messages are hard to modify I suggest to modify motd's text. For example put a frame around:

*** BEGIN message from the machine room ***

motd message

*** END message from the machine room ***

Then you should filter out the text between the frame and drop it.

1

SOLUTION HERE:

In case you are not in charge of the server and you cannot change motd or sshd config, use command like the following:

Redirect STDERR to STDOUT for remote command(s) so that you will see it. And then redirect STDERR of ssh to /dev/null. MOTD goes to STERR and ends up in /dev/null. Any standard AND error message from remote command will be shown (as it goes to STDOUT)

Variant 1 - if you care about the exit status of the remotely-executed command:

ssh remotehost "(remote_command1 && remote_command2; remote_command3) 2>&1" 2>/dev/null || echo SSH connection or remote command failed - either of them returned non-zero exit code $?

Variant 2 - if you want to ignore the exit code of remote command - just execute true as the last remote command

ssh remotehost "(remote_command; true) 2>&1" 2>/dev/null || echo SSH connection failed

Examples of error messages:

Example 1:

ssh remotehost "failed_remote_command 2>&1" 2>/dev/null || echo SSH connection failed or remote command returned non-zero exit code
bash: failed_remote_command: command not found
SSH connection or remote command failed - either of them returned non-zero exit code 127

Example 2:

ssh remotehost "failed_remote_command 2>&1; true" 2>/dev/null || echo SSH connection failed
bash: failed_remote_command: command not found

Example 3a:

ssh remotehost "failed_remote_command 2>&1; true" 2>/dev/null || echo SSH connection failed
# no message is shown

Example 3b:

ssh nonexistinghost "failed_remote_command 2>&1; true" 2>/dev/null || echo SSH connection failed
SSH connection failed
1

I hade the same problem on FreeNAS which is based on freeBSD I think.

The only thing that worked was to do

ssh user@device "show run" | tee "file_$(date +"%y%m%d".cfg" 2>/dev/null. 

Throwing away the errors are not a problem for me since I wrote a script that looks for each new device config. If it fails then my monitor script will alarm me.

I'd be happy to share the monitor script. It also rotates the files for devices that push their configs through TFTP. Those devices can't by themselves make custom names with dates and such, so it needs to rotate name.cfg to name_[todays date].cfg each day.

0

Have you tried removing the text in the motd file? Just a thought.

Hint: /etc/motd
1
  • 4
    He said from the client side, from the server side setting PrintMotd to no in sshd_config would probably be better Jul 6, 2009 at 15:26
0

What are you trying to do and why does the MoTD bother you? I'm guessing executing a remote command and parsing the output? If so, this could be done in a variety of ways without invoking an interactive shell (which causes the motd to be shown).

1
  • Oh, such as? I'd really rather use ssh thought.. Aug 6, 2009 at 8:20
0

Have you tried using an ssh subsystem configuration? You can find an example at http://www.hell.org.ua/Docs/oreilly/tcpip2/ssh/ch05_07.htm that even includes backing up files.

0

I came across this thread searching for a solution to suppress the MOTD when using sftp in non-interactive mode but I didn't have access to the server. So the solution that worked for me when passing the -q flag to sftp, which is to make it quiet.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .