summaryrefslogtreecommitdiff
path: root/libpam
diff options
context:
space:
mode:
authorSteve Langasek <steve.langasek@ubuntu.com>2019-01-03 21:06:32 -0800
committerSteve Langasek <steve.langasek@ubuntu.com>2019-01-03 21:06:32 -0800
commitf3c0273b7bd2d7fdcac3fe3604cedd82afc57f49 (patch)
treeead579aab3f7345280205fa43570f2c033b1f6ce /libpam
parentb70316c593cbc8e5c9155e5c6597497090c6eb88 (diff)
parent46cdce51ed99e5b86c613fb19dafa973c219d255 (diff)
New upstream version 1.1.3
Diffstat (limited to 'libpam')
-rw-r--r--libpam/Makefile.am5
-rw-r--r--libpam/Makefile.in27
-rw-r--r--libpam/include/security/pam_modutil.h24
-rw-r--r--libpam/libpam.map6
-rw-r--r--libpam/pam_modutil_priv.c170
5 files changed, 220 insertions, 12 deletions
diff --git a/libpam/Makefile.am b/libpam/Makefile.am
index 57bd8109..3c7ae1d6 100644
--- a/libpam/Makefile.am
+++ b/libpam/Makefile.am
@@ -20,7 +20,7 @@ include_HEADERS = include/security/_pam_compat.h \
noinst_HEADERS = pam_prelude.h pam_private.h pam_tokens.h \
pam_modutil_private.h pam_static_modules.h
-libpam_la_LDFLAGS = -no-undefined -version-info 82:3:82
+libpam_la_LDFLAGS = -no-undefined -version-info 83:0:83
libpam_la_LIBADD = @LIBAUDIT@ $(LIBPRELUDE_LIBS) @LIBDL@
if STATIC_MODULES
@@ -41,4 +41,5 @@ libpam_la_SOURCES = pam_account.c pam_auth.c pam_data.c pam_delay.c \
pam_vprompt.c pam_syslog.c pam_dynamic.c pam_audit.c \
pam_modutil_cleanup.c pam_modutil_getpwnam.c pam_modutil_ioloop.c \
pam_modutil_getgrgid.c pam_modutil_getpwuid.c pam_modutil_getgrnam.c \
- pam_modutil_getspnam.c pam_modutil_getlogin.c pam_modutil_ingroup.c
+ pam_modutil_getspnam.c pam_modutil_getlogin.c pam_modutil_ingroup.c \
+ pam_modutil_priv.c
diff --git a/libpam/Makefile.in b/libpam/Makefile.in
index 641078b8..55a348f5 100644
--- a/libpam/Makefile.in
+++ b/libpam/Makefile.in
@@ -51,13 +51,13 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \
$(top_srcdir)/m4/japhar_grep_cflags.m4 \
$(top_srcdir)/m4/jh_path_xml_catalog.m4 \
$(top_srcdir)/m4/ld-O1.m4 $(top_srcdir)/m4/ld-as-needed.m4 \
- $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
- $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libprelude.m4 \
- $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
- $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
- $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
- $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
- $(top_srcdir)/configure.in
+ $(top_srcdir)/m4/ld-no-undefined.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libprelude.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.in
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
@@ -85,7 +85,8 @@ am_libpam_la_OBJECTS = pam_account.lo pam_auth.lo pam_data.lo \
pam_modutil_getpwnam.lo pam_modutil_ioloop.lo \
pam_modutil_getgrgid.lo pam_modutil_getpwuid.lo \
pam_modutil_getgrnam.lo pam_modutil_getspnam.lo \
- pam_modutil_getlogin.lo pam_modutil_ingroup.lo
+ pam_modutil_getlogin.lo pam_modutil_ingroup.lo \
+ pam_modutil_priv.lo
libpam_la_OBJECTS = $(am_libpam_la_OBJECTS)
libpam_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
@@ -117,6 +118,8 @@ AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BROWSER = @BROWSER@
+BUILD_CFLAGS = @BUILD_CFLAGS@
+BUILD_LDFLAGS = @BUILD_LDFLAGS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CC_FOR_BUILD = @CC_FOR_BUILD@
@@ -256,7 +259,9 @@ lt_ECHO = @lt_ECHO@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
+pam_cv_ld_O1 = @pam_cv_ld_O1@
pam_cv_ld_as_needed = @pam_cv_ld_as_needed@
+pam_cv_ld_no_undefined = @pam_cv_ld_no_undefined@
pam_xauth_path = @pam_xauth_path@
pdfdir = @pdfdir@
prefix = @prefix@
@@ -283,7 +288,7 @@ include_HEADERS = include/security/_pam_compat.h \
noinst_HEADERS = pam_prelude.h pam_private.h pam_tokens.h \
pam_modutil_private.h pam_static_modules.h
-libpam_la_LDFLAGS = -no-undefined -version-info 82:3:82 \
+libpam_la_LDFLAGS = -no-undefined -version-info 83:0:83 \
$(am__append_3)
libpam_la_LIBADD = @LIBAUDIT@ $(LIBPRELUDE_LIBS) @LIBDL@ \
$(am__append_2)
@@ -296,7 +301,8 @@ libpam_la_SOURCES = pam_account.c pam_auth.c pam_data.c pam_delay.c \
pam_vprompt.c pam_syslog.c pam_dynamic.c pam_audit.c \
pam_modutil_cleanup.c pam_modutil_getpwnam.c pam_modutil_ioloop.c \
pam_modutil_getgrgid.c pam_modutil_getpwuid.c pam_modutil_getgrnam.c \
- pam_modutil_getspnam.c pam_modutil_getlogin.c pam_modutil_ingroup.c
+ pam_modutil_getspnam.c pam_modutil_getlogin.c pam_modutil_ingroup.c \
+ pam_modutil_priv.c
all: all-am
@@ -389,6 +395,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pam_modutil_getspnam.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pam_modutil_ingroup.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pam_modutil_ioloop.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pam_modutil_priv.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pam_password.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pam_prelude.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pam_session.Plo@am__quote@
diff --git a/libpam/include/security/pam_modutil.h b/libpam/include/security/pam_modutil.h
index ffdf5ad0..317202de 100644
--- a/libpam/include/security/pam_modutil.h
+++ b/libpam/include/security/pam_modutil.h
@@ -100,6 +100,30 @@ pam_modutil_write(int fd, const char *buffer, int count);
extern int PAM_NONNULL((1,3))
pam_modutil_audit_write(pam_handle_t *pamh, int type,
const char *message, int retval);
+
+struct pam_modutil_privs {
+ gid_t *grplist;
+ int number_of_groups;
+ int allocated;
+ gid_t old_gid;
+ uid_t old_uid;
+ int is_dropped;
+};
+
+#define PAM_MODUTIL_NGROUPS 64
+#define PAM_MODUTIL_DEF_PRIVS(n) \
+ gid_t n##_grplist[PAM_MODUTIL_NGROUPS]; \
+ struct pam_modutil_privs n = { n##_grplist, PAM_MODUTIL_NGROUPS, 0, -1, -1, 0 }
+
+extern int PAM_NONNULL((1,2,3))
+pam_modutil_drop_priv(pam_handle_t *pamh,
+ struct pam_modutil_privs *p,
+ const struct passwd *pw);
+
+extern int PAM_NONNULL((1,2))
+pam_modutil_regain_priv(pam_handle_t *pamh,
+ struct pam_modutil_privs *p);
+
#ifdef __cplusplus
}
#endif
diff --git a/libpam/libpam.map b/libpam/libpam.map
index 9d55e84f..b0885d65 100644
--- a/libpam/libpam.map
+++ b/libpam/libpam.map
@@ -61,3 +61,9 @@ LIBPAM_MODUTIL_1.1 {
global:
pam_modutil_audit_write;
} LIBPAM_MODUTIL_1.0;
+
+LIBPAM_MODUTIL_1.1.3 {
+ global:
+ pam_modutil_drop_priv;
+ pam_modutil_regain_priv;
+} LIBPAM_MODUTIL_1.1;
diff --git a/libpam/pam_modutil_priv.c b/libpam/pam_modutil_priv.c
new file mode 100644
index 00000000..0f82eabc
--- /dev/null
+++ b/libpam/pam_modutil_priv.c
@@ -0,0 +1,170 @@
+/*
+ * $Id: pam_modutil_priv.c,v 1.1 2010/10/03 21:02:07 ldv Exp $
+ *
+ * This file provides two functions:
+ * pam_modutil_drop_priv:
+ * temporarily lower process fs privileges by switching to another uid/gid,
+ * pam_modutil_regain_priv:
+ * regain process fs privileges lowered by pam_modutil_drop_priv().
+ */
+
+#include "pam_modutil_private.h"
+#include <security/pam_ext.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/fsuid.h>
+
+/*
+ * Two setfsuid() calls in a row are necessary to check
+ * whether setfsuid() succeeded or not.
+ */
+static int change_uid(uid_t uid, uid_t *save)
+{
+ uid_t tmp = setfsuid(uid);
+ if (save)
+ *save = tmp;
+ return (uid_t) setfsuid(uid) == uid ? 0 : -1;
+}
+static int change_gid(gid_t gid, gid_t *save)
+{
+ gid_t tmp = setfsgid(gid);
+ if (save)
+ *save = tmp;
+ return (gid_t) setfsgid(gid) == gid ? 0 : -1;
+}
+
+static int cleanup(struct pam_modutil_privs *p)
+{
+ if (p->allocated) {
+ p->allocated = 0;
+ free(p->grplist);
+ }
+ p->grplist = NULL;
+ p->number_of_groups = 0;
+ return -1;
+}
+
+#define PRIV_MAGIC 0x1004000a
+#define PRIV_MAGIC_DONOTHING 0xdead000a
+
+int pam_modutil_drop_priv(pam_handle_t *pamh,
+ struct pam_modutil_privs *p,
+ const struct passwd *pw)
+{
+ int res;
+
+ if (p->is_dropped) {
+ pam_syslog(pamh, LOG_CRIT,
+ "pam_modutil_drop_priv: called with dropped privileges");
+ return -1;
+ }
+
+ /*
+ * If not root, we can do nothing.
+ * If switching to root, we have nothing to do.
+ * That is, in both cases, we do not care.
+ */
+ if (geteuid() != 0 || pw->pw_uid == 0) {
+ p->is_dropped = PRIV_MAGIC_DONOTHING;
+ return 0;
+ }
+
+ if (!p->grplist || p->number_of_groups <= 0) {
+ pam_syslog(pamh, LOG_CRIT,
+ "pam_modutil_drop_priv: called without room for supplementary groups");
+ return -1;
+ }
+ res = getgroups(0, NULL);
+ if (res < 0) {
+ pam_syslog(pamh, LOG_ERR,
+ "pam_modutil_drop_priv: getgroups failed: %m");
+ return -1;
+ }
+
+ p->allocated = 0;
+ if (res > p->number_of_groups) {
+ p->grplist = calloc(res, sizeof(gid_t));
+ if (!p->grplist) {
+ pam_syslog(pamh, LOG_ERR, "out of memory");
+ return cleanup(p);
+ }
+ p->allocated = 1;
+ p->number_of_groups = res;
+ }
+
+ res = getgroups(p->number_of_groups, p->grplist);
+ if (res < 0) {
+ pam_syslog(pamh, LOG_ERR,
+ "pam_modutil_drop_priv: getgroups failed: %m");
+ return cleanup(p);
+ }
+
+ p->number_of_groups = res;
+
+ /*
+ * We should care to leave process credentials in consistent state.
+ * That is, e.g. if change_gid() succeeded but change_uid() failed,
+ * we should try to restore old gid.
+ */
+ if (setgroups(0, NULL)) {
+ pam_syslog(pamh, LOG_ERR,
+ "pam_modutil_drop_priv: setgroups failed: %m");
+ return cleanup(p);
+ }
+ if (change_gid(pw->pw_gid, &p->old_gid)) {
+ pam_syslog(pamh, LOG_ERR,
+ "pam_modutil_drop_priv: change_gid failed: %m");
+ (void) setgroups(p->number_of_groups, p->grplist);
+ return cleanup(p);
+ }
+ if (change_uid(pw->pw_uid, &p->old_uid)) {
+ pam_syslog(pamh, LOG_ERR,
+ "pam_modutil_drop_priv: change_uid failed: %m");
+ (void) change_gid(p->old_gid, NULL);
+ (void) setgroups(p->number_of_groups, p->grplist);
+ return cleanup(p);
+ }
+
+ p->is_dropped = PRIV_MAGIC;
+ return 0;
+}
+
+int pam_modutil_regain_priv(pam_handle_t *pamh,
+ struct pam_modutil_privs *p)
+{
+ switch (p->is_dropped) {
+ case PRIV_MAGIC_DONOTHING:
+ p->is_dropped = 0;
+ return 0;
+
+ case PRIV_MAGIC:
+ break;
+
+ default:
+ pam_syslog(pamh, LOG_CRIT,
+ "pam_modutil_regain_priv: called with invalid state");
+ return -1;
+ }
+
+ if (change_uid(p->old_uid, NULL)) {
+ pam_syslog(pamh, LOG_ERR,
+ "pam_modutil_regain_priv: change_uid failed: %m");
+ return cleanup(p);
+ }
+ if (change_gid(p->old_gid, NULL)) {
+ pam_syslog(pamh, LOG_ERR,
+ "pam_modutil_regain_priv: change_gid failed: %m");
+ return cleanup(p);
+ }
+ if (setgroups(p->number_of_groups, p->grplist)) {
+ pam_syslog(pamh, LOG_ERR,
+ "pam_modutil_regain_priv: setgroups failed: %m");
+ return cleanup(p);
+ }
+
+ p->is_dropped = 0;
+ cleanup(p);
+ return 0;
+}