EXISTS=`ssh xyz 'egrep "$username" /etc/passwd | cut -d':' -f1'` command is not working properly - linux

I am writing a script to add users on multiple linux servers. But first i want to check that mentioned username already exists on that particular server or not.
EXISTS=`ssh xyz 'egrep "$username" /etc/passwd | cut -d':' -f1'`
This is the command i am trying. But its not giving me the output that i want..rather its giving me the all username in passwd file.
The variable EXISTS should have the only that username or it should be empty.

On any modern Linux systems, you have getent. So instead of checking like this, check the return code (via $?) of:
getent passwd $username &>/dev/null
(exits with 0 if the user exists, 2 if it doesn't exist; other error codes described in the manpage)
(note: this is not really a Java question, is it?)
EDIT OK, full code...
ssh thehost getent passwd $username;
RC=$?;
# check for $RC here; if 0, the user exists; if not 0 it doesn't.
# Man getent for more details
Note that another solution would be to try and add the user directly; the command will fail if the user already exists, or some other reason; here again, man useradd, and check for possible return codes.

Related

Bash script to add and remove users

I am a beginner in bash scripting and I have created a bash script to add users and remove users on Linux.
But since I am facing some issues with the script not really major issues but would be helpful if anyone could point me how to improve the script and the worst practice I am doing the script would be helpful
however the problem I have noticed is that the script takes -a to add a user -d to remove user and -h to get help the -a flag as 2 optional arguments -p for password and -s for shell so the command would be
./useradd.sh -a user -p password -s shell
this works as expected and the user is added to the system but the problem I am facing is that if I do not enter -a flag and specify the -s and -p flag the script is just exited I want to show a clear idea to the user why it exited and there is so many such errors I am assuming but I have not tested it out so much any help would be appreciated, so here is my script
https://github.com/abhijith7025/bash_scripts/blob/master/useradd.sh
... I have created a bash script to add users and remove users on Linux.
You might want to reconsider this, given that Linux has separate commands for these two operations.
There's a lot more to creating a user than there is is getting rid of one, so you may be asking for trouble trying to conjoin the two.
Anyway:
Your case statement has no "other" branch ("* )").
This may be why you're getting no errors when "misusing" your script.
case $opt in
a )
;;
d )
;;
h )
;;
* )
usage
exit 1
;;
esac
Other things to look out for:
useradd is, perhaps, a poor name for a script that can delete users.
You allow a shell to be specified as an argument, but you don't check to see if that exists.
It's conventional for Linux commands to operate on a "thing" or list of "things" and for that operation to be qualified by options that [usually] precede the thing(s). Thus, your script might be better invoked like this:
./manage_user -a -p password -s shell_exe user1
| | | |
| | | User name
| | Shell for User
| Password for User
Add a User
./manage_user -d user2
| |
| User name
Delete a User

How to get XDG variables with sudo?

I need to retrieve $XDG_CONFIG_HOME, $XDG_RUNTIME_DIR and $XDG_DATA_HOME of all users.
I try with:
sudo -Eiu user printenv | grep XDG_CONFIG_HOME
But I get nothing.
If I log on with the user account, the simple command:
printenv | grep XDG_CONFIG_HOME
Works fine.
How do I?
TLDR, these variables are not available in the sudo case, and some can even not be set at all in the standard login case.
On my linux system (debian 8) some of the XDG variables are defined when the user's session is initialized with the pam module pam_systemd. The variables defined to be initialised at that point are documented in the man page, but include XDG_RUNTIME_DIR.
This module is only loaded in the login cases - i.e. I need to ssh to the system, or login via the console/gui to get the user session to initialize via the pam_systemd module.
This module is not loaded in the su or the sudo cases.
As a result, when you do a sudo to emulate a user this variable is not set.
Other XDG variables are only applicable when the user is actually logged in at the GUI. I don't get these variable set on the GUI that I use, but the docs for XDG variables specify what they are supposed to default to if they're not set. The default value for XDG_CONFIG_HOME is $HOME/.config, and the default value for XDG_DATA_HOME is $HOME/.local/share.
So you should only expect these variables to be set in the interactive login case, and not via the non-interactive case - sudo would be effectively designated as a non-interactive case, even though you can do interactive things with it.
These values are very much templated - e.g. the XDG_RUNTIME_DIR on my system is /var/run/UID, and, per the man page, does not survive after my last logout; so it's not a place to put permanent files.
Unless you, as a user change these values, I would expect the defaults that are specified in the XDG documentation, the KDE compliance pages to be the ones that are used. There are probably others, but I just picked the KDE compliance one as it calls it out in the systems admin guide.
There are several parts to isolating all general users (non-system accounts) on a Linux box. For your purpose, the easiest is probably reading all users into an array, and then looking at the XDG config for each. A quick bash script for this purpose is:
#!/bin/bash
uarray=( $(awk -F':' -v "limit=$(grep "^UID_MIN" /etc/login.defs | sed -e 's/UID_MIN\s*//')" '{ if ( $3 >= limit ) print $1}' /etc/passwd) )
for i in "${uarray[#]}"; do
printf "\nXDG Config for user: %s\n\n" "$i"
sudo -Eiu $i printenv | grep XDG
done
That will print all XDG environment variables for each user with a brief header to identify whose it is. If you would prefer it all in one line:
for i in $(awk -F':' -v "limit=$(grep "^UID_MIN" /etc/login.defs | sed -e 's/UID_MIN\s*//')" '{ if ( $3 >= limit ) print $1}' /etc/passwd); do printf "\nXDG Config for user: %s\n\n" "$i"; sudo -Eiu $i printenv | grep XDG; done
You can limit or change which XDG environment variables are selected by narrowing the argument for grep.

Perform action when user logs in via SSH from a particular host

I have a quesiton that puzzles me and I wonder if anyone has attempted to achieve the following:
Let's assume that this is the result of my 'last' command in a Linux environment:
root pts/1 192.168.1.10 Wed Feb 10 07:04 - 07:57 (00:52)
root pts/2 Tue Feb 9 22:00 - 00:13 (02:13)
How can I setup a particular action (say for example a modified MOTD or sending an email) if the the 'root' user has logged in from 192.168.1.10. Is there a way of capturing this information?
The second part of this question is that how can I make the above check a bit more robust - i.e. if I have the following:
mary pts/1 192.168.1.10 Wed Feb 10 07:04 - 07:57 (00:52)
bob pts/2 Tue Feb 9 22:00 - 00:13 (02:13)
Now I'd like to perform an action if the username is equal to 'mary' and the host is 192.168.1.10.
Any suggestions are welcomed.
Thank you in advance.
There's a special file /etc/ssh/sshrc where you can put some commands that will runs each time someone connect by ssh. I wrote that for you :
#!/bin/bash
mail=user#domain.tld
monitored_user=root
monitored_ip=x.x.x.x
hostname=$(hostname)
# add a welcome message:
printf >&2 "\nWelcome on $hostname $USER\n"
read -d " " ip <<< $SSH_CONNECTION
[[ $ip == $monitored_ip && $USER == $monitored_user ]] || exit 0
date=$(date "+%d.%m.%Y %Hh%M")
reverse=$(dig -x $ip +short)
mail -s "Connexion of $USER on $hostname" $mail <<EOF
IP: $ip
Reverse: $reverse
Date: $date
EOF
Put this script in a file, then put the full path of the script in /etc/ssh/sshrc
In man ssh :
/etc/ssh/sshrc :
Commands in this file are executed by ssh when the user
logs in, just before the user's shell (or command) is started. See the
sshd(8) manual page for more information.
Thanks for all your replies. Eventually I managed to find a solution which does work for the time being but it does have one flaw which I'll point out in a minute.
I have added the following to my /etc/bashrc file (or /etc/bash.bashrc whatever environment you're using):
HOST="192.168.0.1"
RHOST=`who am i | sed -n 's/.*(\([^) ]*\).*/\1/p; 1q'`
if [ "$RHOST" == "$HOST" ]; then
echo "SAY WHAT!"
#add further actions here if needed
fi
The flaw that I was talking about before may actually not be a flaw. If you're already SSH-ed into the system, and you want to SSH to a host which lives on the same IP, say ssh root#your-host who am i would then print 'your-host' but I think that's the way it should be.
Needless to say that the above sed statement can be modified so you can capture the username as well, and you can extend the if/else statement to suite your needs.
Thank you again for all your replies.
You can add something to /etc/profile or equivalent that does something depending on the value of $SSH_CLIENT.
It looks like you are using last because it reads /var/log/wtmp by default which is a record of logins. The who command also allows you to read the same file but with an interface more to your needs.
For example:
$ who --ips /var/log/wtmp | grep '^msw.*127.0.0.1'
msw pts/2 2012-10-07 15:52 127.0.0.1
msw pts/3 2012-10-07 15:55 127.0.0.1
where neither of those sessions were active, but rather historic and logged.
In ubuntu i put a script in
/etc/profile.d
and when someone(user ssh) log in, it send an email to my mail
#/etc/profile.d/run_on_loggin.sh
echo $(who i am) | mail -s 'SSH Login Notification' mymail#hotmail.com
I want to create a php file with smtp, to send email with my mail to me...
some times hotmail saved in spam...
if i have the php file i will run like this...
if i want to pass var to file php run like this...
excuse my english :3
note: i think this command run from user, be carefully if the user doen't has permission to use some command or send email.
One way would be to run a simple script periodically:
#!/bin/bash
users=$(last | sed -ne '/192\.168\.1\.10/ s/\([^ ]*\).*/\1/p')
for user in $users; do
sendmail "$user" < email.txt
done
This would pipe the last command into sed to extract a user list and save it into the variable $users. The sed command uses the -n flag so it only prints what we tell it to. First, we select lines that contain the specified IP, with the /192\.168\.1\.10/ "address". On those lines, we attempt to extract the characters before a space, and if we succeed we print the result.
Then, we can loop through the $users variable and act accordingly.
One way to call this repeatedly would be through cron, and a simpler way would be to do while true; do ./my_script.bash; sleep 60; done.

Most reliable way to identify the current user through a sudo

I have an application that may or may not be run while users are sudo'ed to a shared user account. I would like to reliably identify who the real user is for a sort of "honor-system" ACL. I think there's some way by tracing parent/group/session process ids the way that the pstree command does, but I'm not sure how to do that best or if there are better alternatives.
I tried getlogin() originally. That works if ./myapp is used, but it fails with 'cat input | ./myapp` (because the "controlling terminal" is a pipe owned by the shared account).
I'd rather not trust environment variables, as I don't want my "honor system" to be completely thwarted by a simply unset, when the information is still available elsewhere.
I'd also like to avoid forcing a lookup in the password database, as that is a remote RPC (NIS or LDAP) and I'm pretty sure wtmp already contains the information I need.
For a shell script, you might use this to get the sudo'ing user:
WHO=$(who am i | sed -e 's/ .*//'`)
and extract the id from the login using:
ID_WHO=$(id -u $WHO)
I'll ferret out the C library equivalent later.
sudo sets the environment variables SUDO_USER, SUDO_UID, and SUDO_GID.
You can test this with:
$ sudo env
[sudo] password for shteef:
TERM=xterm
# [...snip...]
SHELL=/bin/bash
LOGNAME=root
USER=root
USERNAME=root
SUDO_COMMAND=/usr/bin/env
SUDO_USER=shteef
SUDO_UID=1000
SUDO_GID=1000
But if your users have shell access on the shared account, then I suppose you cannot blindly trust this either.
How about:
#!/usr/bin/ksh
username=`id | cut -d"=" -f2 | cut -d" " -f1`
if [ $username == "0(root)" ]
then
print "Yes, the user is root"
else
print "Sorry! the user $username, is not a root"
fi

Using the passwd command from within a shell script

I'm writing a shell script to automatically add a new user and update their password. I don't know how to get passwd to read from the shell script instead of interactively prompting me for the new password. My code is below.
adduser $1
passwd $1
$2
$2
from "man 1 passwd":
--stdin
This option is used to indicate that passwd should read the new
password from standard input, which can be a pipe.
So in your case
adduser "$1"
echo "$2" | passwd "$1" --stdin
[Update] a few issues were brought up in the comments:
Your passwd command may not have a --stdin option: use the chpasswd
utility instead, as suggested by ashawley.
If you use a shell other than bash, "echo" might not be a builtin command,
and the shell will call /bin/echo. This is insecure because the password
will show up in the process table and can be seen with tools like ps.
In this case, you should use another scripting language. Here is an example in Perl:
#!/usr/bin/perl -w
open my $pipe, '|chpasswd' or die "can't open pipe: $!";
print {$pipe} "$username:$password";
close $pipe
The only solution works on Ubuntu 12.04:
echo -e "new_password\nnew_password" | (passwd user)
But the second option only works when I change from:
echo "password:name" | chpasswd
To:
echo "user:password" | chpasswd
See explanations in original post: Changing password via a script
Nowadays, you can use this command:
echo "user:pass" | chpasswd
Read the wise words from:
http://mywiki.wooledge.org/BashFAQ/078
I quote:
Nothing you can do in bash can possibly work. passwd(1) does not read from standard input. This is intentional. It is for your protection. Passwords were never intended to be put into programs, or generated by programs. They were intended to be entered only by the fingers of an actual human being, with a functional brain, and never, ever written down anywhere.
Nonetheless, we get hordes of users asking how they can circumvent 35 years of Unix security.
It goes on to explain how you can set your shadow(5) password properly, and shows you the GNU-I-only-care-about-security-if-it-doesn't-make-me-think-too-much-way of abusing passwd(1).
Lastly, if you ARE going to use the silly GNU passwd(1) extension --stdin, do not pass the password putting it on the command line.
echo $mypassword | passwd --stdin # Eternal Sin.
echo "$mypassword" | passwd --stdin # Eternal Sin, but at least you remembered to quote your PE.
passwd --stdin <<< "$mypassword" # A little less insecure, still pretty insecure, though.
passwd --stdin < "passwordfile" # With a password file that was created with a secure `umask(1)`, a little bit secure.
The last is the best you can do with GNU passwd. Though I still wouldn't recommend it.
Putting the password on the command line means anyone with even the remotest hint of access to the box can be monitoring ps or such and steal the password. Even if you think your box is safe; it's something you should really get in the habit of avoiding at all cost (yes, even the cost of doing a bit more trouble getting the job done).
Here-document works if your passwd doesn't support --stdin and you don't want to (or can't) use chpasswd for some reason.
Example:
#!/usr/bin/env bash
username="user"
password="pass"
passwd ${username} << EOD
${password}
${password}
EOD
Tested under Arch Linux. This passwd is an element of shadow-utils and installed from the core/filesystem package, which you usually have by default since the package is required by core/base.
You could use chpasswd
echo $1:$2 | chpasswd
For those who need to 'run as root' remotely through a script logging into a user account in the sudoers file, I found an evil horrible hack, that is no doubt very insecure:
sshpass -p 'userpass' ssh -T -p port user#server << EOSSH
sudo -S su - << RROOT
userpass
echo ""
echo "*** Got Root ***"
echo ""
#[root commands go here]
useradd -m newuser
echo "newuser:newpass" | chpasswd
RROOT
EOSSH
I stumbled upon the same problem and for some reason the --stdin option was not available on the version of passwd I was using (shipped in Ubuntu 14.04).
If any of you happen to experience the same issue, you can work it around as I did, by using the chpasswd command like this:
echo "<user>:<password>" | chpasswd
Tested this on a CentOS VMWare image that I keep around for this sort of thing. Note that you probably want to avoid putting passwords as command-line arguments, because anybody on the entire machine can read them out of 'ps -ef'.
That said, this will work:
user="$1"
password="$2"
adduser $user
echo $password | passwd --stdin $user
This is the definitive answer for a teradata node admin.
Go to your /etc/hosts file and create a list of IP's or node names in a text file.
SMP007-1
SMP007-2
SMP007-3
Put the following script in a file.
#set a password across all nodes
printf "User ID: "
read MYUSERID
printf "New Password: "
read MYPASS
while read -r i; do
echo changing password on "$i"
ssh root#"$i" sudo echo "$MYUSERID":"$MYPASS" | chpasswd
echo password changed on "$i"
done< /usr/bin/setpwd.srvrs
Okay I know I've broken a cardinal security rule with ssh and root
but I'll let you security folks deal with it.
Now put this in your /usr/bin subdir along with your setpwd.srvrs config file.
When you run the command it prompts you one time for the User ID
then one time for the password. Then the script traverses all nodes
in the setpwd.srvrs file and does a passwordless ssh to each node,
then sets the password without any user interaction or secondary
password validation.
For me on Raspbian it works only this way (old password added):
#!/usr/bin/env bash
username="pi"
password="Szevasz123"
new_ps="Szevasz1234"
passwd ${username} << EOD
${password}
${new_ps}
${new_ps}
EOD
Have you looked at the -p option of adduser (which AFAIK is just another name for useradd)? You may also want to look at the -P option of luseradd which takes a plaintext password, but I don't know if luseradd is a standard command (it may be part of SE Linux or perhaps just an oddity of Fedora).
Sometimes it is useful to set a password which nobody knows. This seems to work:
tr -dc A-Za-z0-9 < /dev/urandom | head -c44 | passwd --stdin $user
echo 'yourPassword' | sudo -S yourCommand
if -S doesnt work try with -kS
You can use the expect utility to drive all programs that read from a tty (as opposed to stdin, which is what passwd does). Expect comes with ready to run examples for all sorts of interactive problems, like passwd entry.

Resources