diff options
author | Steve Langasek <steve.langasek@ubuntu.com> | 2019-01-03 21:06:32 -0800 |
---|---|---|
committer | Steve Langasek <steve.langasek@ubuntu.com> | 2019-01-03 21:06:32 -0800 |
commit | f3c0273b7bd2d7fdcac3fe3604cedd82afc57f49 (patch) | |
tree | ead579aab3f7345280205fa43570f2c033b1f6ce /libpam | |
parent | b70316c593cbc8e5c9155e5c6597497090c6eb88 (diff) | |
parent | 46cdce51ed99e5b86c613fb19dafa973c219d255 (diff) |
New upstream version 1.1.3
Diffstat (limited to 'libpam')
-rw-r--r-- | libpam/Makefile.am | 5 | ||||
-rw-r--r-- | libpam/Makefile.in | 27 | ||||
-rw-r--r-- | libpam/include/security/pam_modutil.h | 24 | ||||
-rw-r--r-- | libpam/libpam.map | 6 | ||||
-rw-r--r-- | libpam/pam_modutil_priv.c | 170 |
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; +} |