From 6adb1ef279537875495d10f7c74f35101dd335fd Mon Sep 17 00:00:00 2001 From: Cody Maloney Date: Wed, 6 Feb 2013 23:22:20 -0700 Subject: [PATCH] chsh: Add libuser support This is based directly on lchsh which is a part of libuser. libuser.{c,h} exist because exactly the same code is needed for both chsh and chfn. [kzak@redhat.com: cleanup err() usage] Signed-off-by: Cody Maloney Signed-off-by: Karel Zak --- login-utils/Makemodule.am | 3 ++ login-utils/chsh.c | 22 +++++++++++- login-utils/libuser.c | 71 +++++++++++++++++++++++++++++++++++++++ login-utils/libuser.h | 14 ++++++++ 4 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 login-utils/libuser.c create mode 100644 login-utils/libuser.h diff --git a/login-utils/Makemodule.am b/login-utils/Makemodule.am index ee853295c..0c5711841 100644 --- a/login-utils/Makemodule.am +++ b/login-utils/Makemodule.am @@ -73,6 +73,9 @@ chfn_chsh_ldadd = libcommon.la -lpam -lpam_misc if HAVE_USER chfn_chsh_ldflags += $(LIBUSER_LIBS) chfn_chsh_cflags += $(LIBUSER_CFLAGS) +chfn_chsh_sources+= \ + login-utils/libuser.c \ + login-utils/libuser.h endif if HAVE_SELINUX diff --git a/login-utils/chsh.c b/login-utils/chsh.c index 7d3963fc0..66800ca94 100644 --- a/login-utils/chsh.c +++ b/login-utils/chsh.c @@ -1,6 +1,7 @@ /* * chsh.c -- change your login shell * (c) 1994 by salvatore valente + * (c) 2012 by Cody Maloney * * this program is free software. you can redistribute it and * modify it under the terms of the gnu general public license. @@ -32,7 +33,6 @@ #include #include -#include "auth.h" #include "c.h" #include "env.h" #include "closestream.h" @@ -48,6 +48,14 @@ # include "selinux_utils.h" #endif + +#ifdef HAVE_LIBUSER +# include +# include "libuser.h" +#else +# include "auth.h" +#endif + struct sinfo { char *username; char *shell; @@ -131,7 +139,12 @@ int main(int argc, char **argv) oldshell = _PATH_BSHELL; /* default */ /* reality check */ +#ifdef HAVE_LIBUSER + /* If we're setuid and not really root, disallow the password change. */ + if (geteuid() != getuid() && uid != pw->pw_uid) { +#else if (uid != 0 && uid != pw->pw_uid) { +#endif errno = EACCES; err(EXIT_FAILURE, _("running UID doesn't match UID of user we're " @@ -147,9 +160,11 @@ int main(int argc, char **argv) printf(_("Changing shell for %s.\n"), pw->pw_name); +#ifndef HAVE_LIBUSER if(!auth_pam("chsh", uid, pw->pw_name)) { return EXIT_FAILURE; } +#endif if (!shell) { shell = prompt(_("New shell"), oldshell); @@ -162,10 +177,15 @@ int main(int argc, char **argv) if (strcmp(oldshell, shell) == 0) errx(EXIT_SUCCESS, _("Shell not changed.")); + +#ifdef HAVE_LIBUSER + set_value_libuser("chsh", pw->pw_name, uid, LU_LOGINSHELL, shell); +#else pw->pw_shell = shell; if (setpwnam(pw) < 0) err(EXIT_FAILURE, _("setpwnam failed\n" "Shell *NOT* changed. Try again later.")); +#endif printf(_("Shell changed.\n")); return EXIT_SUCCESS; diff --git a/login-utils/libuser.c b/login-utils/libuser.c new file mode 100644 index 000000000..53c7ac9e2 --- /dev/null +++ b/login-utils/libuser.c @@ -0,0 +1,71 @@ +/* + * libuser.c -- Utilize libuser to set a user attribute + * (c) 2012 by Cody Maloney + * + * this program is free software. you can redistribute it and + * modify it under the terms of the gnu general public license. + * there is no warranty. + * + */ + +#include "libuser.h" + +#include +#include +#include + +#include "auth.h" +#include "c.h" +#include "nls.h" + +static int auth_lu(const char *service_name, struct lu_context *ctx, uid_t uid, + const char *username); + +static int auth_lu(const char *service_name, struct lu_context *ctx, uid_t uid, + const char *username) { + if(!lu_uses_elevated_privileges(ctx)) { + /* Drop privileges */ + if (setegid(getgid()) == -1) + err(EXIT_FAILURE, _("Couldn't drop group privileges")); + if (seteuid(getuid()) == -1) + err(EXIT_FAILURE, _("Couldn't drop group privileges")); + return TRUE; + } + + return auth_pam(service_name, uid, username); +} + +int set_value_libuser(const char *service_name, const char *username, uid_t uid, + const char *attr, const char *val) { + struct lu_context *ctx; + struct lu_error *error = NULL; + struct lu_ent *ent; + + ctx = lu_start(username, lu_user, NULL, NULL, lu_prompt_console_quiet, + NULL, &error); + if (ctx == NULL) + errx(EXIT_FAILURE, _("libuser initialization failed: %s."), + lu_strerror(error)); + + if(!auth_lu(service_name, ctx, uid, username)) { + errno = EACCES; + err(EXIT_FAILURE, _("changing user attribute failed")); + } + + /* Look up the user's record. */ + ent = lu_ent_new(); + if (lu_user_lookup_name(ctx, username, ent, &error) == FALSE) { + lu_end(ctx); + errx(EXIT_FAILURE, _("user \"%s\" does not exist."), username); + } + + lu_ent_set_string(ent, attr, val); + if (!lu_user_modify(ctx, ent, &error)) { + lu_ent_free(ent); + lu_end(ctx); + errx(EXIT_FAILURE, _("user attribute not changed: %s"), lu_strerror(error)); + } + lu_ent_free(ent); + lu_end(ctx); + return TRUE; +} diff --git a/login-utils/libuser.h b/login-utils/libuser.h new file mode 100644 index 000000000..7454b997e --- /dev/null +++ b/login-utils/libuser.h @@ -0,0 +1,14 @@ +/* + * libuser.h -- Utilize libuser to set a user attribute + * (c) 2012 by Cody Maloney + * + * this program is free software. you can redistribute it and + * modify it under the terms of the gnu general public license. + * there is no warranty. + * + */ + +#include + +extern int set_value_libuser(const char *service_name, const char *username, + uid_t uid, const char *attr, const char *val);