From 9c1ede8c2372f51c3e0ed520a2dd4cd8f66503e4 Mon Sep 17 00:00:00 2001 From: Giovanni Campagna Date: Thu, 21 Jun 2012 22:34:10 +0200 Subject: [PATCH] Use PAM to change passwords Modifying /etc/shadow directly can be wrong in many configurations, and will fail to update other tokens (such as keyring passwords). Instead, use a small helper to interact with PAM (as PAM functions are not safe to use in process) https://bugs.freedesktop.org/show_bug.cgi?id=51833 --- src/Makefile.am | 8 ++++- src/pam-password-helper.c | 87 +++++++++++++++++++++++++++++++++++++++++++++ src/user.c | 8 ++--- 3 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 src/pam-password-helper.c diff --git a/src/Makefile.am b/src/Makefile.am index c368c02..c66fa2b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,6 +4,7 @@ INCLUDES = \ -DDATADIR=\""$(datadir)"\" \ -DICONDIR=\"$(localstatedir)/lib/AccountsService/icons\" \ -DUSERDIR=\"$(localstatedir)/lib/AccountsService/users\" \ + -DLIBEXECDIR=\"$(libexecdir)\" \ $(DBUS_GLIB_CFLAGS) \ $(GIO_CFLAGS) \ $(GLIB_CFLAGS) \ @@ -22,7 +23,7 @@ accounts-generated.c accounts-generated.h: $(top_srcdir)/data/org.freedesktop.Ac accounts-user-generated.c accounts-user-generated.h: $(top_srcdir)/data/org.freedesktop.Accounts.User.xml Makefile gdbus-codegen --generate-c-code accounts-user-generated --c-namespace Accounts --interface-prefix=org.freedesktop.Accounts. $(top_srcdir)/data/org.freedesktop.Accounts.User.xml -libexec_PROGRAMS = accounts-daemon +libexec_PROGRAMS = accounts-daemon accounts-daemon-pam-password-helper accounts_daemon_SOURCES = \ $(enums_h_sources) \ @@ -42,6 +43,11 @@ accounts_daemon_LDADD = \ $(GLIB_LIBS) \ $(POLKIT_LIBS) +accounts_daemon_pam_password_helper_SOURCES = \ + pam-password-helper.c +accounts_daemon_pam_password_helper_LDADD = \ + -lpam + CLEANFILES = $(BUILT_SOURCES) install-data-hook: diff --git a/src/pam-password-helper.c b/src/pam-password-helper.c new file mode 100644 index 0000000..afcffc5 --- /dev/null +++ b/src/pam-password-helper.c @@ -0,0 +1,87 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2012 Giovanni Campagna + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +char *password; + +static int +answer_pam_message (int num_msg, + const struct pam_message **msg, + struct pam_response **resp, + void *appdata_ptr) +{ + int i; + struct pam_response *resps; + + resps = malloc((sizeof (struct pam_response)) * num_msg); + /* We run non-interactively, so just copy the password + into each question, and hope that configuration is + correct. */ + for (i = 0; i < num_msg; i++) { + resps[i].resp = strdup(password); + resps[i].resp_retcode = 0; + } + + *resp = resps; + + return PAM_SUCCESS; +} + +int +main (int argc, + char **argv) +{ + const char *username; + pam_handle_t *pamh; + struct pam_conv conv = { answer_pam_message, NULL }; + int res; + + if (argc != 2) { + fprintf (stderr, "Wrong number of arguments passed, 1 expected\n"); + return 1; + } + + username = argv[1]; + password = argv[2]; + + res = pam_start ("accountsservice", username, + &conv, &pamh); + if (res != PAM_SUCCESS) { + /* pam_strerror can't be used without a pam handle */ + fprintf (stderr, "Pam handle creation failed (not enough memory?)\n"); + return 2; + } + + res = pam_chauthtok (pamh, PAM_SILENT); + if (res != PAM_SUCCESS) { + fprintf (stderr, "Password change failed: %s\n", pam_strerror (pamh, res)); + } + pam_end (pamh, res); + + return res == PAM_SUCCESS ? 0 : 2; +} diff --git a/src/user.c b/src/user.c index 55c238d..4625092 100644 --- a/src/user.c +++ b/src/user.c @@ -1478,12 +1478,10 @@ user_change_password_authorized_cb (Daemon *daemon, g_object_freeze_notify (G_OBJECT (user)); - argv[0] = "/usr/sbin/usermod"; - argv[1] = "-p"; + argv[0] = LIBEXECDIR "/accounts-daemon-pam-password-helper"; + argv[1] = user->user_name; argv[2] = strings[0]; - argv[3] = "--"; - argv[4] = user->user_name; - argv[5] = NULL; + argv[3] = NULL; error = NULL; if (!spawn_with_login_uid (context, argv, &error)) { -- 1.7.10.4