Skip to content

How to actually add users to system databases #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
amravyan opened this issue Jan 29, 2025 · 11 comments
Open

How to actually add users to system databases #6

amravyan opened this issue Jan 29, 2025 · 11 comments

Comments

@amravyan
Copy link

amravyan commented Jan 29, 2025

Hi!

We've recently discovered your project and related comment. It looks very promising, but we've encountered some problems: we can not correctly create users and groups in systemdb. All created users and groups are actually missing in /etc/passwd and /etc/group and even deleting of previous created users doesn't work fine.

Could you please provide any examples that will add the user to the system db with a command like adduser

All our configs are below

/etc/libnss_shim/config.json
{
    "databases": {
        "group": {
            "functions": {
                "get_entry_by_gid": {
                    "command": "/usr/local/bin/group_get_all_entries.sh -g <$gid>"
                },
                "get_entry_by_name": {
                    "command": "/usr/local/bin/group_get_all_entries.sh -n <$name>"
                }
            }
        },
        "passwd": {
            "functions": {
                "get_entry_by_name": {
                    "command": "/usr/local/bin/passwd_get_all_entries.sh -n <$name>"
                },
                "get_entry_by_uid": {
                    "command": "/usr/local/bin/passwd_get_all_entries.sh -u <$uid>"
                }
            }
        },
        "shadow": {
            "functions": {
                "get_entry_by_name": {
                    "command": "/bin/bash -c \"echo $name:*:19156:0:99999:7:::\""
                }
            }
        }
    },
    "debug": true
}
/usr/local/bin/passwd_get_all_entries.sh
#!/bin/bash

# https://serverfault.com/questions/1122226/user-account-auto-creation-using-ssh-certificate-authentication

if [ $# -eq 0 ]; then
  exit 0
fi

while getopts "u:n:" opt; do
  case $opt in
    u)
      uid=$OPTARG
      name=$(find /home -maxdepth 1 -type d -uid $uid | head -1 | cut -d "/" -f 3)
      echo "$name:x:$uid:1::/home/$name:/bin/bash"
      ;;
    n)
      name=$OPTARG
      uid=$(stat -c %u /home/$name 2>/dev/null)
      if [[ -z $uid ]]; then
          uid=$(stat -c %u /home/* | sort | tail -1 | awk '{print $1+1;}')
      fi
      sudo_gid=27
      echo "$name:x:$uid:$uid::/home/$name:/bin/bash"
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      exit 1
      ;;
  esac
done
/usr/local/bin/group_get_all_entries.sh
#!/bin/bash

# https://serverfault.com/questions/1122226/user-account-auto-creation-using-ssh-certificate-authentication

if [ $# -eq 0 ]; then
  exit 0
fi

while getopts "g:n:" opt; do
  case $opt in
    g)
      uid=$OPTARG
      name=$(find /home -maxdepth 1 -type d -uid $uid | head -1 | cut -d "/" -f 3)
      echo "$name:x:$uid:"
      ;;
    n)
      name=$OPTARG
      uid=$(stat -c %u /home/$name 2>/dev/null)
      if [[ -z $uid ]]; then
          uid=$(stat -c %u /home/* | sort | tail -1 | awk '{print $1+1;}')
      fi
      echo "$name:x:$uid:"
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      exit 1
      ;;
  esac
done
/etc/nsswitch.conf
# /etc/nsswitch.conf
#
# Example configuration of GNU Name Service Switch functionality.
# If you have the `glibc-doc-reference' and `info' packages installed, try:
# `info libc "Name Service Switch"' for information about this file.

passwd:         files systemd shim
group:          files systemd shim
shadow:         files shim
gshadow:        files

hosts:          files dns
networks:       files

protocols:      db files
services:       db files
ethers:         db files
rpc:            db files

netgroup:       nis
root@testhost:~# useradd test1
useradd: user 'test1' already exists
root@testhost:~# groupadd mygrp
groupadd: group 'mygrp' already exists
root@testhost:~# grep mygrp /etc/group
root@testhost:~# grep test /etc/passwd
root@testhost:~#
@amravyan amravyan changed the title How to actually add users to databases How to actually add users to system databases Jan 29, 2025
@xenago
Copy link
Owner

xenago commented Jan 29, 2025

Although I am not entirely sure I understand, I see that in the config.json file provided, there appears to be a syntax problem. The following section contains $name instead of <$name>, meaning that libnss_shim won't rewrite that with the name parameter:

"shadow": {"functions": {"get_entry_by_name": {"command": "/bin/bash -c \"echo $name:*:19156:0:99999:7:::\""

A quick test in a Debian container with your scripts seems to work as expected, with that change applied (using <$name> for the shadow function command get_entry_by_name):

Image

Notes:

  • I am using the command useradd -s /bin/bash -m test1 2> /dev/null based on info in the docs for useradd

    • The -s /bin/bash parameter sets the shell to bash (this appears to be what you want, based on passwd_get_all_entries.sh including it)
    • The -m parameter creates the home directory
    • The additional bash 2> /dev/null ignores error output
  • To purge the home directory as well (destructive), add -r to the userdel command, e.g. userdel -r test1:

    Image

Hopefully this helps!

@openmsk
Copy link

openmsk commented Jan 30, 2025

This works for a container, but on a clean Ubuntu 22.04 the situation changes:

root@clearvm:~# getent -s systemd passwd testuser1
root@clearvm:~# getent -s files passwd testuser1
root@clearvm:~# getent -s shim passwd testuser1
testuser1:x:1001:1001::/home/testuser1:/bin/bash
root@clearvm:~# useradd testuser1
useradd: user 'testuser1' already exists

group:

root@clearvm:~# groupadd test_grp
groupadd: group 'test_grp' already exists
root@clearvm:~# grep test_grp /etc/group
root@clearvm:~# getent -s files group test_grp
root@clearvm:~#

@amravyan
Copy link
Author

amravyan commented Jan 30, 2025

@xenago could you please try to reproduce issue with our setup? We've prepared dedicated repo with our setup, please checki it libnss_shim_debug
All you have to do is to clone it and then run

docker build . --platform=linux/amd64 -t shim
docker run --platform=linux/amd64 --rm -it shim

Image

@xenago
Copy link
Owner

xenago commented Jan 30, 2025

I think I am misunderstanding the issue, can you clarify in what way libnss_shim is not working correctly? In that docker example both it and useradd appear to be operating as expected: NSS is queried by useradd before creating the additional user, and your script replies with the user via shim, so the procedure stops as the user already exists.

Your scripts are providing responses to passwd/group/shadow queries, so any users managed that way don't need to be duplicated anywhere else; if you just need users to have home directories, your scripts could create them on-demand.

Alternatively, if you do need to store users in the file databases but cannot do that directly in your scripts, you may want to try an approach of temporarily removing the shim plugin from nsswitch.conf (or otherwise configuring your scripts to stop responding with the user info), when creating the required local users with useradd.

@xenago
Copy link
Owner

xenago commented Jan 30, 2025

Also, it looks like that container repo does not contain the fix for the <$name> syntax issue I previously mentioned:

Image

With the fix applied:

Image

@openmsk
Copy link

openmsk commented Jan 30, 2025

we need shim not to imitate users, but to create them in file databases.
current settings do not even allow deleting groups and users in file databases

@openmsk
Copy link

openmsk commented Jan 30, 2025

if in the file replace echo "$name:x:$uid:$uid::/home/$name:/bin/bash" with useradd $name the user will not be created in file databases

/usr/local/bin/passwd_get_all_entries.sh
#!/bin/bash

# https://serverfault.com/questions/1122226/user-account-auto-creation-using-ssh-certificate-authentication

if [ $# -eq 0 ]; then
  exit 0
fi

while getopts "u:n:" opt; do
  case $opt in
    u)
      uid=$OPTARG
      name=$(find /home -maxdepth 1 -type d -uid $uid | head -1 | cut -d "/" -f 3)
      echo "$name:x:$uid:1::/home/$name:/bin/bash"
      ;;
    n)
      name=$OPTARG
      uid=$(stat -c %u /home/$name 2>/dev/null)
      if [[ -z $uid ]]; then
          uid=$(stat -c %u /home/* | sort | tail -1 | awk '{print $1+1;}')
      fi
      sudo_gid=27
      useradd $name 
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      exit 1
      ;;
  esac
done

We need libnss to create users that are not in file.
And if it is deleted when the user exits, that would be great.

@xenago
Copy link
Owner

xenago commented Jan 30, 2025

With these tweaks, your code seems to work as originally described:

https://github.com/xenago/amravyan_libnssh_shim_debug

Image

We need libnss to create users that are not in file.

libnss_shim provides an additional lookup source to nss; if you want to use it modify the content of other nss databases in the middle of an nss call then you will need to make edits to them with tooling that does not itself call that nss source (otherwise that is just recursive since it will end up calling every time). That, or something like adding a method to store state and enable your code to dynamically respond differently based on if user creation is in progress.

See the useradd docs where it explains that useradd checks the other databases:

https://linux.die.net/man/8/useradd

Similarly, if the username already exists in an external user database such as NIS or LDAP, useradd will deny the user account creation request.

@xenago
Copy link
Owner

xenago commented Jan 31, 2025

adding a method to store state and enable your code to dynamically respond differently based on if user creation is in progress

I updated the code to show that concept:

amravyan/libnssh_shim_debug@main...xenago:amravyan_libnssh_shim_debug:main

Image

@openmsk
Copy link

openmsk commented Feb 3, 2025

how to debug problems?
where to look for log if debug-true is specified in config

groupadd aaas
Response is not json: , decoded: EOF while parsing a value at line 1 column 0
Response is not json: , decoded: EOF while parsing a value at line 1 column 0
Response is not json: , decoded: EOF while parsing a value at line 1 column 0

@xenago
Copy link
Owner

xenago commented Feb 3, 2025

where to look for log if debug-true is specified in config

As per the docs, debug output is printed to the terminal:

To enable debug printing to the user terminal, "debug": true can be set at the global level. This is false by default.

In your comment, the lines Response is not json: , decoded: EOF while parsing a value at line 1 column 0 are examples of debug output in the terminal - see line 165 in src/lib.rs for the source of that debug statement:

debug_print!(format!("Response is not json: {}, decoded: {}", &$json, e), $debug);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants