Skip to content
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

Add support for changing the home directory in PAM modules #323

Merged
merged 3 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/seat.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ seat_get_allow_guest (Seat *seat)
}

static gboolean
run_script (Seat *seat, DisplayServer *display_server, const gchar *script_name, User *user)
run_script (Seat *seat, DisplayServer *display_server, const gchar *script_name, User *user, const gchar *home_directory)
{
g_autoptr(Process) script = process_new (NULL, NULL);

Expand All @@ -392,7 +392,7 @@ run_script (Seat *seat, DisplayServer *display_server, const gchar *script_name,
{
process_set_env (script, "USER", user_get_name (user));
process_set_env (script, "LOGNAME", user_get_name (user));
process_set_env (script, "HOME", user_get_home_directory (user));
process_set_env (script, "HOME", home_directory ? home_directory : user_get_home_directory (user));
}
else
process_set_env (script, "HOME", "/");
Expand Down Expand Up @@ -457,7 +457,7 @@ display_server_stopped_cb (DisplayServer *display_server, Seat *seat)
/* Run a script right after stopping the display server */
const gchar *script = seat_get_string_property (seat, "display-stopped-script");
if (script)
run_script (seat, NULL, script, NULL);
run_script (seat, NULL, script, NULL, NULL);

g_signal_handlers_disconnect_matched (display_server, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, seat);
priv->display_servers = g_list_remove (priv->display_servers, display_server);
Expand Down Expand Up @@ -654,7 +654,7 @@ run_session (Seat *seat, Session *session)
script = seat_get_string_property (seat, "greeter-setup-script");
else
script = seat_get_string_property (seat, "session-setup-script");
if (script && !run_script (seat, session_get_display_server (session), script, session_get_user (session)))
if (script && !run_script (seat, session_get_display_server (session), script, session_get_user (session), session_get_home_directory (session)))
{
l_debug (seat, "Switching to greeter due to failed setup script");
switch_to_greeter_from_failed_session (seat, session);
Expand Down Expand Up @@ -778,7 +778,7 @@ session_stopped_cb (Session *session, Seat *seat)
{
const gchar *script = seat_get_string_property (seat, "session-cleanup-script");
if (script)
run_script (seat, display_server, script, session_get_user (session));
run_script (seat, display_server, script, session_get_user (session), session_get_home_directory (session));
}

if (priv->stopping)
Expand Down Expand Up @@ -1324,7 +1324,7 @@ display_server_ready_cb (DisplayServer *display_server, Seat *seat)
{
/* Run setup script */
const gchar *script = seat_get_string_property (seat, "display-setup-script");
if (script && !run_script (seat, display_server, script, NULL))
if (script && !run_script (seat, display_server, script, NULL, NULL))
{
l_debug (seat, "Stopping display server due to failed setup script");
display_server_stop (display_server);
Expand Down
18 changes: 16 additions & 2 deletions src/session-child.c
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,14 @@ session_child_run (int argc, char **argv)
return EXIT_FAILURE;
}

/* try to get HOME from PAM since it might have been changed */
const gchar *home_directory = pam_getenv (pam_handle, "HOME");
if (!home_directory) {
home_directory = user_get_home_directory (user);
}
if (version >= 4)
write_string (home_directory);

/* Open a connection to the system bus for ConsoleKit - we must keep it open or CK will close the session */
g_autoptr(GError) error = NULL;
g_autoptr(GDBusConnection) bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
Expand Down Expand Up @@ -602,6 +610,11 @@ session_child_run (int argc, char **argv)
/* Write X authority */
if (x_authority)
{
if (!g_path_is_absolute (x_authority_filename)) {
gchar *x_authority_filename_new = g_build_filename (home_directory, x_authority_filename, NULL);
g_free (x_authority_filename);
x_authority_filename = x_authority_filename_new;
}
gboolean drop_privileges = geteuid () == 0;
if (drop_privileges)
privileges_drop (user_get_uid (user), user_get_gid (user));
Expand Down Expand Up @@ -629,7 +642,6 @@ session_child_run (int argc, char **argv)
/* Run the command as the authenticated user */
uid_t uid = user_get_uid (user);
gid_t gid = user_get_gid (user);
const gchar *home_directory = user_get_home_directory (user);
child_pid = fork ();
if (child_pid == 0)
{
Expand All @@ -651,8 +663,10 @@ session_child_run (int argc, char **argv)
/* NOTE: This must be done after the permissions are changed because NFS filesystems can
* be setup so the local root user accesses the NFS files as 'nobody'. If the home directories
* are not system readable then the chdir can fail */
if (chdir (home_directory) != 0)
if (chdir (home_directory) != 0) {
g_printerr ("chdir: %s\n", strerror (errno));
robert-ancell marked this conversation as resolved.
Show resolved Hide resolved
_exit (errno);
}

if (log_filename)
{
Expand Down
24 changes: 22 additions & 2 deletions src/session.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ typedef struct
/* User to authenticate as */
gchar *username;

/* Home directory of the authenticating user */
gchar *home_directory;

/* TRUE if is a guest account */
gboolean is_guest;

Expand Down Expand Up @@ -644,7 +647,7 @@ session_real_start (Session *session)
close (from_child_input);

/* Indicate what version of the protocol we are using */
int version = 3;
int version = 4;
write_data (session, &version, sizeof (version));

/* Send configuration */
Expand All @@ -671,6 +674,14 @@ session_get_username (Session *session)
return priv->username;
}

const gchar *
session_get_home_directory (Session *session)
{
SessionPrivate *priv = session_get_instance_private (session);
g_return_val_if_fail (session != NULL, NULL);
return priv->home_directory;
}

const gchar *
session_get_login1_session_id (Session *session)
{
Expand Down Expand Up @@ -812,7 +823,7 @@ session_real_run (Session *session)
x_authority_filename = g_build_filename (dir, "xauthority", NULL);
}
else
x_authority_filename = g_build_filename (user_get_home_directory (session_get_user (session)), ".Xauthority", NULL);
x_authority_filename = g_strdup (".Xauthority");

/* Make sure shared user directory for this user exists */
if (!priv->remote_host_name)
Expand Down Expand Up @@ -863,6 +874,14 @@ session_real_run (Session *session)
for (gsize i = 0; i < argc; i++)
write_string (session, priv->argv[i]);

/* Get the home directory of the user currently being authenticated (may change after opening PAM session) */
g_autofree gchar *home_directory = read_string_from_child (session);
if (g_strcmp0 (home_directory, priv->home_directory) != 0)
{
g_free (priv->home_directory);
priv->home_directory = g_steal_pointer (&home_directory);
}

priv->login1_session_id = read_string_from_child (session);
priv->console_kit_cookie = read_string_from_child (session);
}
Expand Down Expand Up @@ -1005,6 +1024,7 @@ session_finalize (GObject *object)
if (priv->child_watch)
g_source_remove (priv->child_watch);
g_clear_pointer (&priv->username, g_free);
g_clear_pointer (&priv->home_directory, g_free);
g_clear_object (&priv->user);
g_clear_pointer (&priv->pam_service, g_free);
for (size_t i = 0; i < priv->messages_length; i++)
Expand Down
2 changes: 2 additions & 0 deletions src/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ gboolean session_get_is_started (Session *session);

const gchar *session_get_username (Session *session);

const gchar *session_get_home_directory (Session *session);

const gchar *session_get_login1_session_id (Session *session);

const gchar *session_get_console_kit_cookie (Session *session);
Expand Down
4 changes: 3 additions & 1 deletion tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,8 @@ TESTS = \
test-wayland-greeter \
test-wayland-session \
test-invalid-seat \
test-seatdefaults-still-supported
test-seatdefaults-still-supported \
test-change-home-dir-on-session

# test-switch-to-greeter-return-session-repeat
# test-session-exit-error
Expand Down Expand Up @@ -389,6 +390,7 @@ EXTRA_DIST = \
scripts/autologin-timeout-logout.conf \
scripts/autologin-xserver-crash.conf \
scripts/change-authentication.conf \
scripts/change-home-dir-on-session.conf \
scripts/cancel-authentication.conf \
scripts/console-kit.conf \
scripts/console-kit-no-xdg-runtime.conf \
Expand Down
34 changes: 34 additions & 0 deletions tests/scripts/change-home-dir-on-session.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#
# Check home directory is set correctly in session after having been changed by PAM
#

[Seat:*]
autologin-user=change-home-dir
user-session=default

#?*START-DAEMON
#?RUNNER DAEMON-START

# X server starts
#?XSERVER-0 START VT=7 SEAT=seat0

# Daemon connects when X server is ready
#?*XSERVER-0 INDICATE-READY
#?XSERVER-0 INDICATE-READY
#?XSERVER-0 ACCEPT-CONNECT

# Session starts
#?SESSION-X-0 START XDG_SEAT=seat0 XDG_VTNR=7 XDG_GREETER_DATA_DIR=.*/change-home-dir XDG_SESSION_TYPE=x11 XDG_SESSION_DESKTOP=default USER=change-home-dir
#?LOGIN1 ACTIVATE-SESSION SESSION=c0
#?XSERVER-0 ACCEPT-CONNECT
#?SESSION-X-0 CONNECT-XSERVER

# Check environment variables
#?*SESSION-X-0 READ-ENV NAME=HOME
#?SESSION-X-0 READ-ENV NAME=HOME VALUE=.*/users/change-home-dir

# Cleanup
#?*STOP-DAEMON
#?SESSION-X-0 TERMINATE SIGNAL=15
#?XSERVER-0 TERMINATE SIGNAL=15
#?RUNNER DAEMON-EXIT STATUS=0
21 changes: 21 additions & 0 deletions tests/src/libsystem.c
Original file line number Diff line number Diff line change
Expand Up @@ -1285,6 +1285,27 @@ pam_open_session (pam_handle_t *pamh, int flags)
g_mkdir_with_parents (entry->pw_dir, 0755);
}

if (strcmp (pamh->user, "change-home-dir") == 0)
{
struct passwd *entry = getpwnam (pamh->user);

/* Actual home dir is changed by PAM, differing from passwd, strip off
trailing /home/<user> and replace with /users/<user> */
const char *endp = pamh->user;
int slashes = 0;
while (*endp++ != '\0');
while (slashes < 2 && endp > pamh->user) {
if (*endp-- == '/')
slashes++;
}
g_autofree gchar *changed_home = g_strdup_printf("%.*s/users/%s\n", (int)(endp - entry->pw_dir), entry->pw_dir, pamh->user);

g_mkdir_with_parents (changed_home, 0755);

g_autofree gchar *e = g_strdup_printf ("HOME=%s", changed_home);
pam_putenv (pamh, e);
}

/* Open logind session */
g_autoptr(GError) error = NULL;
g_autoptr(GVariant) result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
Expand Down
4 changes: 3 additions & 1 deletion tests/src/test-runner.c
Original file line number Diff line number Diff line change
Expand Up @@ -2772,13 +2772,15 @@ main (int argc, char **argv)
{"corrupt-xauth", "password", "Corrupt Xauthority", 1032},
/* User to test properties */
{"prop-user", "", "TEST", 1033},
/* This account has the home directory changed by PAM during authentication */
{"change-home-dir", "", "Change Home Dir User", 1034},
{NULL, NULL, NULL, 0}
};
g_autoptr(GString) passwd_data = g_string_new ("");
g_autoptr(GString) group_data = g_string_new ("");
for (int i = 0; users[i].user_name; i++)
{
if (strcmp (users[i].user_name, "mount-home-dir") != 0 && strcmp (users[i].user_name, "make-home-dir") != 0)
if (strcmp (users[i].user_name, "mount-home-dir") != 0 && strcmp (users[i].user_name, "make-home-dir") != 0 && strcmp (users[i].user_name, "change-home-dir") != 0)
{
g_autofree gchar *path = g_build_filename (home_dir, users[i].user_name, NULL);
g_mkdir_with_parents (path, 0755);
Expand Down
2 changes: 2 additions & 0 deletions tests/test-change-home-dir-on-session
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
./src/dbus-env ./src/test-runner change-home-dir-on-session test-gobject-greeter