linux: setguid() in new user namespace - linux-namespaces

My initial task: start a bunch of processes in separate network namespace (with lo 127.0.0.1 interface only and no one listening any ports). So I use:
unshare -n -r bash -c -x myscript.sh
I need -r because of -n: you can't manage your "new network" without effective root.
Also my processes want to call setuid(1234) (where 1234 is product of searching for some username william by getpwnam()) and there is no 1234 in newly created --user namespace and there is no mapping from 1234 to anyone in parent user namespace. Also, i cannot modify /proc/$$/uid_map more than once in newly created user namespace and that modification is already made by unshare and /proc/$$/uid_map contains only this:
0 1000 1
Is it possible to create new users inside new userspace?
Is it possible to create new anonymous network namespace without -r and without root (in parent namespace)? I dislike -r here because of this (from man unshare): "As a mere convenience feature, it does not support more sophisticated use cases, such as mapping multiple ranges of UIDs and GIDs." and i want multiple mappings, because I need more than single user (root) in my new user namespace.

Related

SSH config file limited to 100 identity files

I have to connect to more than 100 machines through SSH. I made an script to make all the connections and perform the changes that i need. The problem is that i cant type the password every time i execute the script for each of the remote machines. Then, I found out that I could create a file in the /root/.ssh/ directory named config where I can store lines like this:
IdentityFile /root/.ssh/id_rsa_XXXX
The key pair is saved also in /root/.ssh/ but the problem is that there is a limit of 100 identity files that I can write in the config file.
Do u know if there's a workaround to make this possible?
Thanks to all, first question here! :)
First of all, if you have 100 servers to connect and 100 keys, you are doing it wrong. You can reuse the public key for other servers if you make sure the private key is safe.
If you are trying to load all the keys to ssh at once, you are doing it also wrong. The ssh config has a Host keyword, which can be made to filter which key is supposed to be used on which server. And I advise you to use it. Otherwise ssh will not know what key to use to which server and it also overcomes the limit.
Do you have separate ssh keys for each and every server? You could bundle them (one key for each type/function of server). Then you wouldn't need to specify each inside a config file.
Another way around this, would be to call the key from the command line, instead of a config file like so:
ssh -i /root/.ssh/id_rsa_XXX -l user.name server.example.com
If you do it carefully, you could create /root/.ssh/hostname where hostname is the actual hostname of the server you want to connect to. For example:
/root/.ssh/server.example.com
You could then script (BASH) like so (assuming you call the script dossh.sh):
key_and_hostname=$1
ssh -i /root/.ssh/${key_and_hostname} -l user.name ${key_and_hostname}
call the script like:
dossh.sh server.example.com

Concatenating a local file with a remote one

These three lines of code require authentication twice. I don't yet have password-less authentication set up on this server. In fact, these lines of code are to copy my public key to the server and concatenate it with the existing file.
How can I re-write this process with a single ssh command that requires authentication only once?
scp ~/local.txt user#server.com:~/remote.txt
ssh -l user user#server.com
cat ~/remote.txt >> ~/otherRemote.txt
I've looked into the following possibilities:
command sed
operator ||
operator &&
shared session: Can I use an existing SSH connection and execute SCP over that tunnel without re-authenticating?
I also considered placing local.txt at an openly accessible location, for example, with a public dropbox link. Then if cat could accept this as an input, the scp line wouldn't be necessary. But this would also require an additional step and wouldn't work in cases where local.txt cannot be made public.
Other references:
Using a variable's value as password for scp, ssh etc. instead of prompting for user input every time
https://superuser.com/questions/400714/how-to-remotely-write-to-a-file-using-ssh
You can redirect the content to the remote, and then use commands on the remote to do something with it. Like this:
ssh user#server.com 'cat >> otherRemote.txt' < ~/local.txt
The remote cat command will receive as its input the content of ~/local.txt, passed to the ssh command by input redirection.
Btw, as #Barmar pointed out, specifying the username with both -l user and user# was also redundant in your example.

How do I configure the aws instance ip during the user data configuration?

I have question about passing a shell script to an instance with user data. So what I need to configure here is, since my server is going to run on the instance, before the instance got created, the shell script should configure the server.xml information, (like the instance ip address, database ip addresss...) before starting the instance/server.
But, since the instance/server hasn't be generated yet, is there any variable I can use to pass the localhost information in the shell script? is there any way for user to specify some custom variable while running the user data before the instance got created? (before using the aws user data, I used to run it manually, through the configure.sh file and the config.properties file after the instance got created)
#!/bin/bash
# source the properties:
. ./config.properties
echo "Installation"
echo "Updating server.xml"
cd "Server/server/configuration/"
sed -i -s "s/SERVER_IP/"$LOCALHOST_IP"/g" server.xml
sed -i -s "s/DB_IP/"$DATABASE_IP"/g" server.xml
cd "../tomcat/bin"
sh startup.sh

Forcing usermod with running program

I've been looking for a way to force usermod to modify the password/group/... files despite the user being in use.
What I do get now is this:
!! Failed to execute 'usermod --home '...' --password '...' --shell '/bin/false' 'zabbix' 2>&1':
usermod: user zabbix is currently used by process 518
I know that for being secure I need to restart the service. But this is done within a setup script. I am restarting all services at the end.
Is there any way to say --force? (well, except for modifying all necessary files.)
Thanks
If you can get root rights via sudo and are confident enough to change system files using vi then I would change the files manually.
Only a few things need to be changed in
- /etc/passwd
here you could change UID, GID, Homedirectory, Shell ...
- /etc/group
here you might need to change UID/GID as well for the username if there was a change
The File /etc/shadow will be changed automatically when using passwd to set a new password. This you can directly perform if you are root: "passwd username"
You can run usermod in a separate user namespace (with a recent enough linux), but you need to map the root user to root (otherwise you won't have permissions to modify /etc/passwd).
I.e. something like this:
unshare --user --map-root-user usermod ...
Now usermod won't find the processes running with the uid of user you are modifying.
You probably won't be able to modify the root user itself with this.

In a bash script executed on boot, how do I get the username of the user just logged-in?

I need to execute a bash script on boot.
To do so I created a file
/etc/init.d/blah
I edited it and added the following lines
#! /bin/sh
# /etc/init.d/blah
touch '/var/lock/blah'
username1=$(id -n -u)
username2=$(whoami)
touch '/var/lock/1'${username1}
touch '/var/lock/2'${username2}
exit 0
The script is execute with root privileges (which is what I need because I have to use mount inside this script) .. but the problem is that I also need to know the username of the user who has just logged-in beacuse my goal is to mount a certain folder to a certain mount-point depending on the username, like
mount -o bind /home/USERNAME/mount-point /media/data/home/USERNAME/to-be-mounted
Going back to the boot script, if I do
sudo update-rc.d blah defaults
and then reboot and log-in with my username (let's say john) both ways to get username in my script produce root in fact I've got 3 files
/var/lock/blah
/var/lock/1root
/var/lock/2root
So, how can I get the username of the user who just logged-in? (john in my example)
EDITED:
I solved in this way:
1. I created a .desktop file for each user I need to perform automount on boot to autostart a script on boot (I'm on LXDE) and put it on /home/{username}/.config/autostart
[Desktop Entry]
Type=Application
Exec=bash "/path/to/mount-bind.sh"
2. I stored in that path a bash script called mount-bind.sh and made it executable:
#!/bin/bash
_username=$1
if [[ -z "${_username}" ]]; then
_username="$(id -u -n)"
fi
mkdir -p "/home/${_username}/mount-folder"
sudo mount -o bind "/media/data/home/${_username}/mount-folder" "/home/${_username}/mount-folder"
exit 0
3. I added the following line to /etc/sudoers
%nopwd ALL=(ALL) NOPASSWD: /bin/mount
4. I created the nopwd group and added to it all the users I need
In his way after login I can mount the path under the user home.
Problem with this method is that I have to create the desktop file for each new user and add him/her to nopwd, but it works.
Any further improvement is welcome! :)
I think you should move from a boot time init script to a script executed at login time under the logged-in user. To allow this, you should look into ways to allow your users to execute the mount command you need. Depending on what you are trying to achieve, one of the following methods may help you:
Assuming you are on Linux or some other UNIX with a similar feature, add the mountpoint to /etc/fstab with the user option, allowing normal users to mount the entry.
Execute mount through sudo with a suitably narrow sudoers configuration as to not allow users to execute any mount commands.
Write a suid-root program in c which executes the required mount commands when called. This however is very tricky to get right without creating gaping security holes.
Login does not happen at boot time. You cannot foretell which user is going to log in when booting.
Try Exporting the logindetails and use it.
export username2=$(whoami)

Resources