diff options
Diffstat (limited to 'modules/pam_limits')
-rw-r--r-- | modules/pam_limits/Makefile.am | 8 | ||||
-rw-r--r-- | modules/pam_limits/Makefile.in | 51 | ||||
-rw-r--r-- | modules/pam_limits/README | 14 | ||||
-rw-r--r-- | modules/pam_limits/README.xml | 32 | ||||
-rw-r--r-- | modules/pam_limits/limits.conf | 17 | ||||
-rw-r--r-- | modules/pam_limits/limits.conf.5 | 82 | ||||
-rw-r--r-- | modules/pam_limits/limits.conf.5.xml | 130 | ||||
-rw-r--r-- | modules/pam_limits/pam_limits.8 | 20 | ||||
-rw-r--r-- | modules/pam_limits/pam_limits.8.xml | 81 | ||||
-rw-r--r-- | modules/pam_limits/pam_limits.c | 433 |
10 files changed, 624 insertions, 244 deletions
diff --git a/modules/pam_limits/Makefile.am b/modules/pam_limits/Makefile.am index 911b07b3..3a3b5e01 100644 --- a/modules/pam_limits/Makefile.am +++ b/modules/pam_limits/Makefile.am @@ -15,12 +15,16 @@ dist_check_SCRIPTS = tst-pam_limits TESTS = $(dist_check_SCRIPTS) securelibdir = $(SECUREDIR) +if HAVE_VENDORDIR +secureconfdir = $(VENDOR_SCONFIGDIR) +else secureconfdir = $(SCONFIGDIR) +endif limits_conf_dir = $(SCONFIGDIR)/limits.d AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \ - -DLIMITS_FILE_DIR=\"$(limits_conf_dir)/*.conf\" \ - -DLIMITS_FILE=\"$(SCONFIGDIR)/limits.conf\" $(WARN_CFLAGS) + -DLIMITS_FILE_DIR=\"$(limits_conf_dir)\" \ + $(WARN_CFLAGS) AM_LDFLAGS = -no-undefined -avoid-version -module if HAVE_VERSIONING AM_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map diff --git a/modules/pam_limits/Makefile.in b/modules/pam_limits/Makefile.in index ac06d6c0..7b515b83 100644 --- a/modules/pam_limits/Makefile.in +++ b/modules/pam_limits/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.16.1 from Makefile.am. +# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2018 Free Software Foundation, Inc. +# Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -96,18 +96,21 @@ host_triplet = @host@ @HAVE_VERSIONING_TRUE@am__append_1 = -Wl,--version-script=$(srcdir)/../modules.map subdir = modules/pam_limits ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \ - $(top_srcdir)/m4/japhar_grep_cflags.m4 \ +am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/intlmacosx.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/ld-no-undefined.m4 $(top_srcdir)/m4/lib-ld.m4 \ + $(top_srcdir)/m4/ld-no-undefined.m4 \ + $(top_srcdir)/m4/ld-z-now.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.ac + $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/m4/warn_lang_flags.m4 \ + $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(dist_check_SCRIPTS) \ @@ -376,6 +379,7 @@ am__set_TESTS_bases = \ bases='$(TEST_LOGS)'; \ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ bases=`echo $$bases` +AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)' RECHECK_LOGS = $(TEST_LOGS) AM_RECURSIVE_TARGETS = check recheck TEST_SUITE_LOG = test-suite.log @@ -420,10 +424,14 @@ CC_FOR_BUILD = @CC_FOR_BUILD@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ +CRYPTO_LIBS = @CRYPTO_LIBS@ +CRYPT_CFLAGS = @CRYPT_CFLAGS@ +CRYPT_LIBS = @CRYPT_LIBS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ +DOCBOOK_RNG = @DOCBOOK_RNG@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -433,12 +441,16 @@ ECONF_CFLAGS = @ECONF_CFLAGS@ ECONF_LIBS = @ECONF_LIBS@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +EXE_CFLAGS = @EXE_CFLAGS@ +EXE_LDFLAGS = @EXE_LDFLAGS@ FGREP = @FGREP@ +FILECMD = @FILECMD@ FO2PDF = @FO2PDF@ GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GREP = @GREP@ +HTML_STYLESHEET = @HTML_STYLESHEET@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ @@ -452,7 +464,6 @@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBAUDIT = @LIBAUDIT@ -LIBCRACK = @LIBCRACK@ LIBCRYPT = @LIBCRYPT@ LIBDB = @LIBDB@ LIBDL = @LIBDL@ @@ -471,12 +482,14 @@ LIBSELINUX = @LIBSELINUX@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ +LOGIND_CFLAGS = @LOGIND_CFLAGS@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ +MAN_STYLESHEET = @MAN_STYLESHEET@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ @@ -499,8 +512,7 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ -PIE_CFLAGS = @PIE_CFLAGS@ -PIE_LDFLAGS = @PIE_LDFLAGS@ +PDF_STYLESHEET = @PDF_STYLESHEET@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ @@ -511,11 +523,16 @@ SECUREDIR = @SECUREDIR@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ +STRINGPARAM_PROFILECONDITIONS = @STRINGPARAM_PROFILECONDITIONS@ STRINGPARAM_VENDORDIR = @STRINGPARAM_VENDORDIR@ STRIP = @STRIP@ +SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@ +SYSTEMD_LIBS = @SYSTEMD_LIBS@ TIRPC_CFLAGS = @TIRPC_CFLAGS@ TIRPC_LIBS = @TIRPC_LIBS@ +TXT_STYLESHEET = @TXT_STYLESHEET@ USE_NLS = @USE_NLS@ +VENDOR_SCONFIGDIR = @VENDOR_SCONFIGDIR@ VERSION = @VERSION@ WARN_CFLAGS = @WARN_CFLAGS@ XGETTEXT = @XGETTEXT@ @@ -560,7 +577,6 @@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ -libc_cv_fpie = @libc_cv_fpie@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ @@ -568,9 +584,6 @@ localstatedir = @localstatedir@ 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@ @@ -580,6 +593,7 @@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ +systemdunitdir = @systemdunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ @@ -592,11 +606,12 @@ XMLS = README.xml limits.conf.5.xml pam_limits.8.xml dist_check_SCRIPTS = tst-pam_limits TESTS = $(dist_check_SCRIPTS) securelibdir = $(SECUREDIR) -secureconfdir = $(SCONFIGDIR) +@HAVE_VENDORDIR_FALSE@secureconfdir = $(SCONFIGDIR) +@HAVE_VENDORDIR_TRUE@secureconfdir = $(VENDOR_SCONFIGDIR) limits_conf_dir = $(SCONFIGDIR)/limits.d AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \ - -DLIMITS_FILE_DIR=\"$(limits_conf_dir)/*.conf\" \ - -DLIMITS_FILE=\"$(SCONFIGDIR)/limits.conf\" $(WARN_CFLAGS) + -DLIMITS_FILE_DIR=\"$(limits_conf_dir)\" \ + $(WARN_CFLAGS) AM_LDFLAGS = -no-undefined -avoid-version -module $(am__append_1) securelib_LTLIBRARIES = pam_limits.la @@ -982,7 +997,7 @@ $(TEST_SUITE_LOG): $(TEST_LOGS) test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ fi; \ echo "$${col}$$br$${std}"; \ - echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ + echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \ echo "$${col}$$br$${std}"; \ create_testsuite_report --maybe-color; \ echo "$$col$$br$$std"; \ diff --git a/modules/pam_limits/README b/modules/pam_limits/README index 6aabd54f..dc560eff 100644 --- a/modules/pam_limits/README +++ b/modules/pam_limits/README @@ -15,6 +15,18 @@ concatenated together in the order of parsing. If a config file is explicitly specified with a module option then the files in the above directory are not parsed. +By default limits are taken from the /etc/security/limits.conf config file or, +if that one is not present, the file %vendordir%/security/limits.conf. Then +individual *.conf files from the /etc/security/limits.d/ and %vendordir%/ +security/limits.d directories are read. If /etc/security/limits.d/ +@filename@.conf exists, then %vendordir%/security/limits.d/@filename@.conf will +not be used. All limits.d/*.conf files are sorted by their @filename@.conf in +lexicographic order regardless of which of the directories they reside in. The +effect of the individual files is the same as if all the files were +concatenated together in the order of parsing. If a config file is explicitly +specified with the config option the files in the above directories are not +parsed. + The module must not be called by a multithreaded application. If Linux PAM is compiled with audit support the module will report when it @@ -56,12 +68,14 @@ These are some example lines which might be specified in /etc/security/ limits.conf. * soft core 0 +root hard core 100000 * hard nofile 512 @student hard nproc 20 @faculty soft nproc 20 @faculty hard nproc 50 ftp hard nproc 0 @student - maxlogins 4 +@student - nonewprivs 1 :123 hard cpu 5000 @500: soft cpu 10000 600:700 hard locks 10 diff --git a/modules/pam_limits/README.xml b/modules/pam_limits/README.xml index 964a5a21..25a463cc 100644 --- a/modules/pam_limits/README.xml +++ b/modules/pam_limits/README.xml @@ -1,39 +1,23 @@ -<?xml version="1.0" encoding='UTF-8'?> -<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" -"http://www.docbook.org/xml/4.3/docbookx.dtd" -[ -<!-- -<!ENTITY pamlimits SYSTEM "pam_limits.8.xml"> ---> -<!-- -<!ENTITY limitsconf SYSTEM "limits.conf.5.xml"> ---> -]> +<article xmlns="http://docbook.org/ns/docbook" version="5.0"> -<article> - - <articleinfo> + <info> <title> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" - href="pam_limits.8.xml" xpointer='xpointer(//refnamediv[@id = "pam_limits-name"]/*)'/> + <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="pam_limits.8.xml" xpointer='xpointer(id("pam_limits-name")/*)'/> </title> - </articleinfo> + </info> <section> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" - href="pam_limits.8.xml" xpointer='xpointer(//refsect1[@id = "pam_limits-description"]/*)'/> + <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="pam_limits.8.xml" xpointer='xpointer(id("pam_limits-description")/*)'/> </section> <section> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" - href="pam_limits.8.xml" xpointer='xpointer(//refsect1[@id = "pam_limits-options"]/*)'/> + <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="pam_limits.8.xml" xpointer='xpointer(id("pam_limits-options")/*)'/> </section> <section> - <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" - href="limits.conf.5.xml" xpointer='xpointer(//refsect1[@id = "limits.conf-examples"]/*)'/> + <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="limits.conf.5.xml" xpointer='xpointer(id("limits.conf-examples")/*)'/> </section> -</article> +</article>
\ No newline at end of file diff --git a/modules/pam_limits/limits.conf b/modules/pam_limits/limits.conf index be621a7c..6b3865cb 100644 --- a/modules/pam_limits/limits.conf +++ b/modules/pam_limits/limits.conf @@ -1,5 +1,16 @@ # /etc/security/limits.conf # +#This file sets the resource limits for the users logged in via PAM. +#It does not affect resource limits of the system services. +# +#Also note that configuration files in /etc/security/limits.d directory, +#which are read in alphabetical order, override the settings in this +#file in case the domain is the same or more specific. +#That means, for example, that setting a limit for wildcard domain here +#can be overridden with a wildcard setting in a config file in the +#subdirectory, but a user specific setting here can be overridden only +#with a user specific setting in the subdirectory. +# #Each line describes a limit for a user in the form: # #<domain> <type> <item> <value> @@ -11,6 +22,9 @@ # - the wildcard *, for default entry # - the wildcard %, can be also used with %group syntax, # for maxlogin limit +# - NOTE: group and wildcard limits are not applied to root. +# To apply a limit to the root user, <domain> must be +# the literal username root. # #<type> can have the two values: # - "soft" for enforcing the soft limits @@ -35,16 +49,19 @@ # - msgqueue - max memory used by POSIX message queues (bytes) # - nice - max nice priority allowed to raise to values: [-20, 19] # - rtprio - max realtime priority +# - chroot - change root to directory (Debian-specific) # #<domain> <type> <item> <value> # #* soft core 0 +#root hard core 100000 #* hard rss 10000 #@student hard nproc 20 #@faculty soft nproc 20 #@faculty hard nproc 50 #ftp hard nproc 0 +#ftp - chroot /ftp #@student - maxlogins 4 # End of file diff --git a/modules/pam_limits/limits.conf.5 b/modules/pam_limits/limits.conf.5 index f527fec8..c9c41876 100644 --- a/modules/pam_limits/limits.conf.5 +++ b/modules/pam_limits/limits.conf.5 @@ -1,13 +1,13 @@ '\" t .\" Title: limits.conf .\" Author: [see the "AUTHOR" section] -.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/> -.\" Date: 06/08/2020 +.\" Generator: DocBook XSL Stylesheets v1.79.2 <http://docbook.sf.net/> +.\" Date: 05/07/2023 .\" Manual: Linux-PAM Manual -.\" Source: Linux-PAM Manual +.\" Source: Linux-PAM .\" Language: English .\" -.TH "LIMITS\&.CONF" "5" "06/08/2020" "Linux-PAM Manual" "Linux\-PAM Manual" +.TH "LIMITS\&.CONF" "5" "05/07/2023" "Linux\-PAM" "Linux\-PAM Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -50,7 +50,7 @@ The syntax of the lines is as follows: .PP The fields listed above should be filled as follows: .PP -\fB<domain>\fR +<domain> .RS 4 .sp .RS 4 @@ -145,19 +145,23 @@ a gid specified as \fB%:\fR\fI<gid>\fR applicable to maxlogins limit only\&. It limits the total number of logins of all users that are member of the group with the specified gid\&. .RE +.sp +\fBNOTE:\fR +group and wildcard limits are not applied to the root user\&. To set a limit for the root user, this field must contain the literal username +\fBroot\fR\&. .RE .PP -\fB<type>\fR +<type> .RS 4 .PP -\fBhard\fR +hard .RS 4 for enforcing \fBhard\fR resource limits\&. These limits are set by the superuser and enforced by the Kernel\&. The user cannot raise his requirement of system resources above such values\&. .RE .PP -\fBsoft\fR +soft .RS 4 for enforcing \fBsoft\fR @@ -168,7 +172,7 @@ limits\&. The values specified with this token can be thought of as values, for normal system usage\&. .RE .PP -\fB\-\fR +\- .RS 4 for enforcing both \fBsoft\fR @@ -180,100 +184,110 @@ Note, if you specify a type of \*(Aq\-\*(Aq but neglect to supply the item and v .RE .RE .PP -\fB<item>\fR +<item> .RS 4 .PP -\fBcore\fR +core .RS 4 limits the core file size (KB) .RE .PP -\fBdata\fR +data .RS 4 maximum data size (KB) .RE .PP -\fBfsize\fR +fsize .RS 4 maximum filesize (KB) .RE .PP -\fBmemlock\fR +memlock .RS 4 maximum locked\-in\-memory address space (KB) .RE .PP -\fBnofile\fR +nofile .RS 4 maximum number of open file descriptors .RE .PP -\fBrss\fR +rss .RS 4 maximum resident set size (KB) (Ignored in Linux 2\&.4\&.30 and higher) .RE .PP -\fBstack\fR +stack .RS 4 maximum stack size (KB) .RE .PP -\fBcpu\fR +cpu .RS 4 maximum CPU time (minutes) .RE .PP -\fBnproc\fR +nproc .RS 4 maximum number of processes .RE .PP -\fBas\fR +as .RS 4 address space limit (KB) .RE .PP -\fBmaxlogins\fR +maxlogins .RS 4 maximum number of logins for this user (this limit does not apply to user with \fIuid=0\fR) .RE .PP -\fBmaxsyslogins\fR +maxsyslogins .RS 4 maximum number of all logins on system; user is not allowed to log\-in if total number of all user logins is greater than specified number (this limit does not apply to user with \fIuid=0\fR) .RE .PP -\fBpriority\fR +nonewprivs +.RS 4 +value of 0 or 1; if set to 1 disables acquiring new privileges by invoking prctl(PR_SET_NO_NEW_PRIVS) +.RE +.PP +priority .RS 4 the priority to run user process with (negative values boost process priority) .RE .PP -\fBlocks\fR +locks .RS 4 maximum locked files (Linux 2\&.4 and higher) .RE .PP -\fBsigpending\fR +sigpending .RS 4 maximum number of pending signals (Linux 2\&.6 and higher) .RE .PP -\fBmsgqueue\fR +msgqueue .RS 4 maximum memory used by POSIX message queues (bytes) (Linux 2\&.6 and higher) .RE .PP -\fBnice\fR +nice .RS 4 maximum nice priority allowed to raise to (Linux 2\&.6\&.12 and higher) values: [\-20,19] .RE .PP -\fBrtprio\fR +rtprio .RS 4 maximum realtime priority allowed for non\-privileged processes (Linux 2\&.6\&.12 and higher) .RE +.PP +\fBchroot\fR +.RS 4 +the directory to chroot the user to +.RE .RE .PP All items support the values @@ -282,9 +296,11 @@ All items support the values or \fIinfinity\fR indicating no limit, except for -\fBpriority\fR -and -\fBnice\fR\&. +\fBpriority\fR, +\fBnice\fR, and +\fBnonewprivs\fR\&. If +\fBnofile\fR +is to be set to one of these values, it will be set to the contents of /proc/sys/fs/nr_open instead (see setrlimit(3))\&. .PP If a hard limit or soft limit of a resource is set to a valid value, but outside of the supported range of the local system, the system may reject the new limit or unexpected behavior may occur\&. If the control value \fIrequired\fR @@ -315,12 +331,14 @@ These are some example lines which might be specified in .\} .nf * soft core 0 +root hard core 100000 * hard nofile 512 @student hard nproc 20 @faculty soft nproc 20 @faculty hard nproc 50 ftp hard nproc 0 @student \- maxlogins 4 +@student \- nonewprivs 1 :123 hard cpu 5000 @500: soft cpu 10000 600:700 hard locks 10 @@ -333,7 +351,7 @@ ftp hard nproc 0 .PP \fBpam_limits\fR(8), \fBpam.d\fR(5), -\fBpam\fR(8), +\fBpam\fR(7), \fBgetrlimit\fR(2), \fBgetrlimit\fR(3p) .SH "AUTHOR" diff --git a/modules/pam_limits/limits.conf.5.xml b/modules/pam_limits/limits.conf.5.xml index 380a1399..d3893350 100644 --- a/modules/pam_limits/limits.conf.5.xml +++ b/modules/pam_limits/limits.conf.5.xml @@ -1,13 +1,10 @@ -<?xml version="1.0" encoding='UTF-8'?> -<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" - "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"> - -<refentry id="limits.conf"> +<refentry xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="limits.conf"> <refmeta> <refentrytitle>limits.conf</refentrytitle> <manvolnum>5</manvolnum> - <refmiscinfo class="sectdesc">Linux-PAM Manual</refmiscinfo> + <refmiscinfo class="source">Linux-PAM</refmiscinfo> + <refmiscinfo class="manual">Linux-PAM Manual</refmiscinfo> </refmeta> <refnamediv> @@ -15,7 +12,7 @@ <refpurpose>configuration file for the pam_limits module</refpurpose> </refnamediv> - <refsect1 id='limits.conf-description'> + <refsect1 xml:id="limits.conf-description"> <title>DESCRIPTION</title> <para> The <emphasis>pam_limits.so</emphasis> module applies ulimit limits, @@ -38,7 +35,7 @@ <variablelist> <varlistentry> <term> - <option><domain></option> + <domain> </term> <listitem> <itemizedlist> @@ -49,38 +46,35 @@ </listitem> <listitem> <para> - a groupname, with <emphasis remap='B'>@group</emphasis> syntax. + a groupname, with <emphasis remap="B">@group</emphasis> syntax. This should not be confused with netgroups. </para> </listitem> <listitem> <para> - the wildcard <emphasis remap='B'>*</emphasis>, for default entry. + the wildcard <emphasis remap="B">*</emphasis>, for default entry. </para> </listitem> <listitem> <para> - the wildcard <emphasis remap='B'>%</emphasis>, for maxlogins limit only, - can also be used with <emphasis remap='B'>%group</emphasis> syntax. If the - <emphasis remap='B'>%</emphasis> wildcard is used alone it is identical - to using <emphasis remap='B'>*</emphasis> with maxsyslogins limit. With - a group specified after <emphasis remap='B'>%</emphasis> it limits the total + the wildcard <emphasis remap="B">%</emphasis>, for maxlogins limit only, + can also be used with <emphasis remap="B">%group</emphasis> syntax. If the + <emphasis remap="B">%</emphasis> wildcard is used alone it is identical + to using <emphasis remap="B">*</emphasis> with maxsyslogins limit. With + a group specified after <emphasis remap="B">%</emphasis> it limits the total number of logins of all users that are member of the group. </para> </listitem> <listitem> <para> - an uid range specified as <replaceable><min_uid></replaceable><emphasis - remap='B'>:</emphasis><replaceable><max_uid></replaceable>. If min_uid + an uid range specified as <replaceable><min_uid></replaceable><emphasis remap="B">:</emphasis><replaceable><max_uid></replaceable>. If min_uid is omitted, the match is exact for the max_uid. If max_uid is omitted, all uids greater than or equal min_uid match. </para> </listitem> <listitem> <para> - a gid range specified as <emphasis - remap='B'>@</emphasis><replaceable><min_gid></replaceable><emphasis - remap='B'>:</emphasis><replaceable><max_gid></replaceable>. If min_gid + a gid range specified as <emphasis remap="B">@</emphasis><replaceable><min_gid></replaceable><emphasis remap="B">:</emphasis><replaceable><max_gid></replaceable>. If min_gid is omitted, the match is exact for the max_gid. If max_gid is omitted, all gids greater than or equal min_gid match. For the exact match all groups including the user's supplementary groups are examined. For the range matches only @@ -89,50 +83,54 @@ </listitem> <listitem> <para> - a gid specified as <emphasis - remap='B'>%:</emphasis><replaceable><gid></replaceable> applicable + a gid specified as <emphasis remap="B">%:</emphasis><replaceable><gid></replaceable> applicable to maxlogins limit only. It limits the total number of logins of all users that are member of the group with the specified gid. </para> </listitem> </itemizedlist> + <para> + <emphasis remap='B'>NOTE:</emphasis> group and wildcard limits are not + applied to the root user. To set a limit for the root user, this field + must contain the literal username <emphasis remap='B'>root</emphasis>. + </para> </listitem> </varlistentry> <varlistentry> <term> - <option><type></option> + <type> </term> <listitem> <variablelist> <varlistentry> - <term><option>hard</option></term> + <term>hard</term> <listitem> <para> - for enforcing <emphasis remap='B'>hard</emphasis> resource limits. + for enforcing <emphasis remap="B">hard</emphasis> resource limits. These limits are set by the superuser and enforced by the Kernel. The user cannot raise his requirement of system resources above such values. </para> </listitem> </varlistentry> <varlistentry> - <term><option>soft</option></term> + <term>soft</term> <listitem> <para> - for enforcing <emphasis remap='B'>soft</emphasis> resource limits. + for enforcing <emphasis remap="B">soft</emphasis> resource limits. These limits are ones that the user can move up or down within the - permitted range by any pre-existing <emphasis remap='B'>hard</emphasis> + permitted range by any pre-existing <emphasis remap="B">hard</emphasis> limits. The values specified with this token can be thought of as <emphasis>default</emphasis> values, for normal system usage. </para> </listitem> </varlistentry> <varlistentry> - <term><option>-</option></term> + <term>-</term> <listitem> <para> - for enforcing both <emphasis remap='B'>soft</emphasis> and - <emphasis remap='B'>hard</emphasis> resource limits together. + for enforcing both <emphasis remap="B">soft</emphasis> and + <emphasis remap="B">hard</emphasis> resource limits together. </para> <para> Note, if you specify a type of '-' but neglect to supply the @@ -147,79 +145,79 @@ <varlistentry> <term> - <option><item></option> + <item> </term> <listitem> <variablelist> <varlistentry> - <term><option>core</option></term> + <term>core</term> <listitem> <para>limits the core file size (KB)</para> </listitem> </varlistentry> <varlistentry> - <term><option>data</option></term> + <term>data</term> <listitem> <para>maximum data size (KB)</para> </listitem> </varlistentry> <varlistentry> - <term><option>fsize</option></term> + <term>fsize</term> <listitem> <para>maximum filesize (KB)</para> </listitem> </varlistentry> <varlistentry> - <term><option>memlock</option></term> + <term>memlock</term> <listitem> <para>maximum locked-in-memory address space (KB)</para> </listitem> </varlistentry> <varlistentry> - <term><option>nofile</option></term> + <term>nofile</term> <listitem> <para>maximum number of open file descriptors</para> </listitem> </varlistentry> <varlistentry> - <term><option>rss</option></term> + <term>rss</term> <listitem> <para>maximum resident set size (KB) (Ignored in Linux 2.4.30 and higher)</para> </listitem> </varlistentry> <varlistentry> - <term><option>stack</option></term> + <term>stack</term> <listitem> <para>maximum stack size (KB)</para> </listitem> </varlistentry> <varlistentry> - <term><option>cpu</option></term> + <term>cpu</term> <listitem> <para>maximum CPU time (minutes)</para> </listitem> </varlistentry> <varlistentry> - <term><option>nproc</option></term> + <term>nproc</term> <listitem> <para>maximum number of processes</para> </listitem> </varlistentry> <varlistentry> - <term><option>as</option></term> + <term>as</term> <listitem> <para>address space limit (KB)</para> </listitem> </varlistentry> <varlistentry> - <term><option>maxlogins</option></term> + <term>maxlogins</term> <listitem> <para>maximum number of logins for this user (this limit does not apply to user with <emphasis>uid=0</emphasis>)</para> </listitem> </varlistentry> <varlistentry> - <term><option>maxsyslogins</option></term> + <term>maxsyslogins</term> <listitem> <para>maximum number of all logins on system; user is not allowed to log-in if total number of all user logins is @@ -228,44 +226,57 @@ </listitem> </varlistentry> <varlistentry> - <term><option>priority</option></term> + <term>nonewprivs</term> + <listitem> + <para>value of 0 or 1; if set to 1 disables acquiring new + privileges by invoking prctl(PR_SET_NO_NEW_PRIVS)</para> + </listitem> + </varlistentry> + <varlistentry> + <term>priority</term> <listitem> <para>the priority to run user process with (negative values boost process priority)</para> </listitem> </varlistentry> <varlistentry> - <term><option>locks</option></term> + <term>locks</term> <listitem> <para>maximum locked files (Linux 2.4 and higher)</para> </listitem> </varlistentry> <varlistentry> - <term><option>sigpending</option></term> + <term>sigpending</term> <listitem> <para>maximum number of pending signals (Linux 2.6 and higher)</para> </listitem> </varlistentry> <varlistentry> - <term><option>msgqueue</option></term> + <term>msgqueue</term> <listitem> <para>maximum memory used by POSIX message queues (bytes) (Linux 2.6 and higher)</para> </listitem> </varlistentry> <varlistentry> - <term><option>nice</option></term> + <term>nice</term> <listitem> <para>maximum nice priority allowed to raise to (Linux 2.6.12 and higher) values: [-20,19]</para> </listitem> </varlistentry> <varlistentry> - <term><option>rtprio</option></term> + <term>rtprio</term> <listitem> <para>maximum realtime priority allowed for non-privileged processes (Linux 2.6.12 and higher)</para> </listitem> </varlistentry> + <varlistentry> + <term><option>chroot</option></term> + <listitem> + <para>the directory to chroot the user to</para> + </listitem> + </varlistentry> </variablelist> </listitem> </varlistentry> @@ -274,7 +285,10 @@ <para> All items support the values <emphasis>-1</emphasis>, <emphasis>unlimited</emphasis> or <emphasis>infinity</emphasis> indicating no limit, - except for <emphasis remap='B'>priority</emphasis> and <emphasis remap='B'>nice</emphasis>. + except for <emphasis remap="B">priority</emphasis>, <emphasis remap="B">nice</emphasis>, + and <emphasis remap="B">nonewprivs</emphasis>. + If <emphasis remap="B">nofile</emphasis> is to be set to one of these values, + it will be set to the contents of /proc/sys/fs/nr_open instead (see setrlimit(3)). </para> <para> If a hard limit or soft limit of a resource is set to a valid value, @@ -299,7 +313,7 @@ </para> <para> In the <emphasis>limits</emphasis> configuration file, the - '<emphasis remap='B'>#</emphasis>' character introduces a comment + '<emphasis remap="B">#</emphasis>' character introduces a comment - after which the rest of the line is ignored. </para> <para> @@ -309,7 +323,7 @@ </para> </refsect1> - <refsect1 id="limits.conf-examples"> + <refsect1 xml:id="limits.conf-examples"> <title>EXAMPLES</title> <para> These are some example lines which might be specified in @@ -317,33 +331,35 @@ </para> <programlisting> * soft core 0 +root hard core 100000 * hard nofile 512 @student hard nproc 20 @faculty soft nproc 20 @faculty hard nproc 50 ftp hard nproc 0 @student - maxlogins 4 +@student - nonewprivs 1 :123 hard cpu 5000 @500: soft cpu 10000 600:700 hard locks 10 </programlisting> </refsect1> - <refsect1 id="limits.conf-see_also"> + <refsect1 xml:id="limits.conf-see_also"> <title>SEE ALSO</title> <para> <citerefentry><refentrytitle>pam_limits</refentrytitle><manvolnum>8</manvolnum></citerefentry>, <citerefentry><refentrytitle>pam.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>, - <citerefentry><refentrytitle>pam</refentrytitle><manvolnum>8</manvolnum></citerefentry>, + <citerefentry><refentrytitle>pam</refentrytitle><manvolnum>7</manvolnum></citerefentry>, <citerefentry><refentrytitle>getrlimit</refentrytitle><manvolnum>2</manvolnum></citerefentry>, <citerefentry><refentrytitle>getrlimit</refentrytitle><manvolnum>3p</manvolnum></citerefentry> </para> </refsect1> - <refsect1 id="limits.conf-author"> + <refsect1 xml:id="limits.conf-author"> <title>AUTHOR</title> <para> pam_limits was initially written by Cristian Gafton <gafton@redhat.com> </para> </refsect1> -</refentry> +</refentry>
\ No newline at end of file diff --git a/modules/pam_limits/pam_limits.8 b/modules/pam_limits/pam_limits.8 index fbbacc66..f971b64c 100644 --- a/modules/pam_limits/pam_limits.8 +++ b/modules/pam_limits/pam_limits.8 @@ -1,13 +1,13 @@ '\" t .\" Title: pam_limits .\" Author: [see the "AUTHORS" section] -.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/> -.\" Date: 06/08/2020 +.\" Generator: DocBook XSL Stylesheets v1.79.2 <http://docbook.sf.net/> +.\" Date: 05/07/2023 .\" Manual: Linux-PAM Manual -.\" Source: Linux-PAM Manual +.\" Source: Linux-PAM .\" Language: English .\" -.TH "PAM_LIMITS" "8" "06/08/2020" "Linux-PAM Manual" "Linux-PAM Manual" +.TH "PAM_LIMITS" "8" "05/07/2023" "Linux\-PAM" "Linux\-PAM Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -49,27 +49,27 @@ The module must not be called by a multithreaded application\&. If Linux PAM is compiled with audit support the module will report when it denies access based on limit of maximum number of concurrent login sessions\&. .SH "OPTIONS" .PP -\fBconf=\fR\fB\fI/path/to/limits\&.conf\fR\fR +conf=/path/to/limits\&.conf .RS 4 Indicate an alternative limits\&.conf style configuration file to override the default\&. .RE .PP -\fBdebug\fR +debug .RS 4 Print debug information\&. .RE .PP -\fBset_all\fR +set_all .RS 4 Set the limits for which no value is specified in the configuration file to the one from the process with the PID 1\&. Please note that if the init process is systemd these limits will not be the kernel default limits and this option should not be used\&. .RE .PP -\fButmp_early\fR +utmp_early .RS 4 Some broken applications actually allocate a utmp entry for the user before the user is admitted to the system\&. If some of the services you are configuring PAM for do this, you can selectively use this module argument to compensate for this behavior and at the same time maintain system\-wide consistency with a single limits\&.conf file\&. .RE .PP -\fBnoaudit\fR +noaudit .RS 4 Do not report exceeded maximum logins count to the audit subsystem\&. .RE @@ -146,7 +146,7 @@ Replace "login" for each service you are using this module\&. .PP \fBlimits.conf\fR(5), \fBpam.d\fR(5), -\fBpam\fR(8)\&. +\fBpam\fR(7)\&. .SH "AUTHORS" .PP pam_limits was initially written by Cristian Gafton <gafton@redhat\&.com> diff --git a/modules/pam_limits/pam_limits.8.xml b/modules/pam_limits/pam_limits.8.xml index bc46cbf4..8f026f0a 100644 --- a/modules/pam_limits/pam_limits.8.xml +++ b/modules/pam_limits/pam_limits.8.xml @@ -1,16 +1,13 @@ -<?xml version="1.0" encoding="ISO-8859-1"?> -<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" - "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"> - -<refentry id='pam_limits'> +<refentry xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="pam_limits"> <refmeta> <refentrytitle>pam_limits</refentrytitle> <manvolnum>8</manvolnum> - <refmiscinfo class='setdesc'>Linux-PAM Manual</refmiscinfo> + <refmiscinfo class="source">Linux-PAM</refmiscinfo> + <refmiscinfo class="manual">Linux-PAM Manual</refmiscinfo> </refmeta> - <refnamediv id='pam_limits-name'> + <refnamediv xml:id="pam_limits-name"> <refname>pam_limits</refname> <refpurpose> PAM module to limit resources @@ -20,35 +17,35 @@ <!-- body begins here --> <refsynopsisdiv> - <cmdsynopsis id="pam_limits-cmdsynopsis"> + <cmdsynopsis xml:id="pam_limits-cmdsynopsis" sepchar=" "> <command>pam_limits.so</command> - <arg choice="opt"> + <arg choice="opt" rep="norepeat"> conf=<replaceable>/path/to/limits.conf</replaceable> </arg> - <arg choice="opt"> + <arg choice="opt" rep="norepeat"> debug </arg> - <arg choice="opt"> + <arg choice="opt" rep="norepeat"> set_all </arg> - <arg choice="opt"> + <arg choice="opt" rep="norepeat"> utmp_early </arg> - <arg choice="opt"> + <arg choice="opt" rep="norepeat"> noaudit </arg> </cmdsynopsis> </refsynopsisdiv> - <refsect1 id="pam_limits-description"> + <refsect1 xml:id="pam_limits-description"> <title>DESCRIPTION</title> <para> The pam_limits PAM module sets limits on the system resources that can be obtained in a user-session. Users of <emphasis>uid=0</emphasis> are affected by this limits, too. </para> - <para> + <para condition="without_vendordir"> By default limits are taken from the <filename>/etc/security/limits.conf</filename> config file. Then individual *.conf files from the <filename>/etc/security/limits.d/</filename> directory are read. The files are parsed one after another in the order of "C" locale. @@ -57,6 +54,23 @@ If a config file is explicitly specified with a module option then the files in the above directory are not parsed. </para> + <para condition="with_vendordir"> + By default limits are taken from the <filename>/etc/security/limits.conf</filename> + config file or, if that one is not present, the file + <filename>%vendordir%/security/limits.conf</filename>. + Then individual <filename>*.conf</filename> files from the + <filename>/etc/security/limits.d/</filename> and + <filename>%vendordir%/security/limits.d</filename> directories are read. + If <filename>/etc/security/limits.d/@filename@.conf</filename> exists, then + <filename>%vendordir%/security/limits.d/@filename@.conf</filename> will not be used. + All <filename>limits.d/*.conf</filename> files are sorted by their + <filename>@filename@.conf</filename> in lexicographic order regardless of which + of the directories they reside in. + The effect of the individual files is the same as if all the files were + concatenated together in the order of parsing. + If a config file is explicitly specified with the <option>config</option> + option the files in the above directories are not parsed. + </para> <para> The module must not be called by a multithreaded application. </para> @@ -67,12 +81,12 @@ </para> </refsect1> - <refsect1 id="pam_limits-options"> + <refsect1 xml:id="pam_limits-options"> <title>OPTIONS</title> <variablelist> <varlistentry> <term> - <option>conf=<replaceable>/path/to/limits.conf</replaceable></option> + conf=/path/to/limits.conf </term> <listitem> <para> @@ -83,7 +97,7 @@ </varlistentry> <varlistentry> <term> - <option>debug</option> + debug </term> <listitem> <para> @@ -93,7 +107,7 @@ </varlistentry> <varlistentry> <term> - <option>set_all</option> + set_all </term> <listitem> <para> @@ -107,7 +121,7 @@ </varlistentry> <varlistentry> <term> - <option>utmp_early</option> + utmp_early </term> <listitem> <para> @@ -122,7 +136,7 @@ </varlistentry> <varlistentry> <term> - <option>noaudit</option> + noaudit </term> <listitem> <para> @@ -133,14 +147,14 @@ </variablelist> </refsect1> - <refsect1 id="pam_limits-types"> + <refsect1 xml:id="pam_limits-types"> <title>MODULE TYPES PROVIDED</title> <para> Only the <option>session</option> module type is provided. </para> </refsect1> - <refsect1 id="pam_limits-return_values"> + <refsect1 xml:id="pam_limits-return_values"> <title>RETURN VALUES</title> <variablelist> <varlistentry> @@ -202,19 +216,26 @@ </variablelist> </refsect1> - <refsect1 id="pam_limits-files"> + <refsect1 xml:id="pam_limits-files"> <title>FILES</title> <variablelist> <varlistentry> - <term><filename>/etc/security/limits.conf</filename></term> + <term>/etc/security/limits.conf</term> <listitem> <para>Default configuration file</para> </listitem> </varlistentry> + <varlistentry condition="with_vendordir"> + <term>%vendordir%/security/limits.conf</term> + <listitem> + <para>Default configuration file if + <filename>/etc/security/limits.conf</filename> does not exist.</para> + </listitem> + </varlistentry> </variablelist> </refsect1> - <refsect1 id='pam_limits-examples'> + <refsect1 xml:id="pam_limits-examples"> <title>EXAMPLES</title> <para> For the services you need resources limits (login for example) put a @@ -233,7 +254,7 @@ session required pam_limits.so </para> </refsect1> - <refsect1 id="pam_limits-see_also"> + <refsect1 xml:id="pam_limits-see_also"> <title>SEE ALSO</title> <para> <citerefentry> @@ -243,15 +264,15 @@ session required pam_limits.so <refentrytitle>pam.d</refentrytitle><manvolnum>5</manvolnum> </citerefentry>, <citerefentry> - <refentrytitle>pam</refentrytitle><manvolnum>8</manvolnum> + <refentrytitle>pam</refentrytitle><manvolnum>7</manvolnum> </citerefentry>. </para> </refsect1> - <refsect1 id="pam_limits-authors"> + <refsect1 xml:id="pam_limits-authors"> <title>AUTHORS</title> <para> pam_limits was initially written by Cristian Gafton <gafton@redhat.com> </para> </refsect1> -</refentry> +</refentry>
\ No newline at end of file diff --git a/modules/pam_limits/pam_limits.c b/modules/pam_limits/pam_limits.c index b791cdce..da83b705 100644 --- a/modules/pam_limits/pam_limits.c +++ b/modules/pam_limits/pam_limits.c @@ -13,7 +13,7 @@ * See end for Copyright information */ -#if !defined(linux) && !defined(__linux) +#ifndef __linux__ #warning THIS CODE IS KNOWN TO WORK ONLY ON LINUX !!! #endif @@ -28,6 +28,7 @@ #include <syslog.h> #include <stdarg.h> #include <signal.h> +#include <sys/prctl.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/resource.h> @@ -46,10 +47,23 @@ #include <libaudit.h> #endif + +#ifndef PR_SET_NO_NEW_PRIVS +# define PR_SET_NO_NEW_PRIVS 38 /* from <linux/prctl.h> */ +#endif + +#ifndef MLOCK_LIMIT +#ifdef __FreeBSD_kernel__ +#define MLOCK_LIMIT RLIM_INFINITY +#else +#define MLOCK_LIMIT (64*1024) +#endif +#endif + /* Module defines */ #define LINE_LENGTH 1024 -#define LIMITS_DEF_USER 0 /* limit was set by an user entry */ +#define LIMITS_DEF_USER 0 /* limit was set by a user entry */ #define LIMITS_DEF_GROUP 1 /* limit was set by a group entry */ #define LIMITS_DEF_ALLGROUP 2 /* limit was set by a group entry */ #define LIMITS_DEF_ALL 3 /* limit was set by an all entry */ @@ -83,11 +97,14 @@ struct user_limits_struct { /* internal data */ struct pam_limit_s { + int root; /* running as root? */ int login_limit; /* the max logins limit */ int login_limit_def; /* which entry set the login limit */ int flag_numsyslogins; /* whether to limit logins only for a specific user or to count all logins */ int priority; /* the priority to run user process with */ + int nonewprivs; /* whether to prctl(PR_SET_NO_NEW_PRIVS) */ + char chroot_dir[8092]; /* directory to chroot into */ struct user_limits_struct limits[RLIM_NLIMITS]; const char *conf_file; int utmp_after_pam_call; @@ -98,6 +115,8 @@ struct pam_limit_s { #define LIMIT_NUMSYSLOGINS RLIM_NLIMITS+2 #define LIMIT_PRI RLIM_NLIMITS+3 +#define LIMIT_NONEWPRIVS RLIM_NLIMITS+4 +#define LIMIT_CHROOT RLIM_NLIMITS+5 #define LIMIT_SOFT 1 #define LIMIT_HARD 2 @@ -116,9 +135,14 @@ struct pam_limit_s { #define PAM_SET_ALL 0x0010 /* Limits from globbed files. */ -#define LIMITS_CONF_GLOB LIMITS_FILE_DIR +#define LIMITS_CONF_GLOB (LIMITS_FILE_DIR "/*.conf") -#define CONF_FILE (pl->conf_file != NULL)?pl->conf_file:LIMITS_FILE +#define LIMITS_FILE (SCONFIGDIR "/limits.conf") + +#ifdef VENDOR_SCONFIGDIR +#define VENDOR_LIMITS_FILE (VENDOR_SCONFIGDIR "/limits.conf") +#define VENDOR_LIMITS_CONF_GLOB (VENDOR_SCONFIGDIR "/limits.d/*.conf") +#endif static int _pam_parse (const pam_handle_t *pamh, int argc, const char **argv, @@ -271,8 +295,8 @@ check_logins (pam_handle_t *pamh, const char *name, int limit, int ctrl, } if (!pl->flag_numsyslogins) { char user[sizeof(ut->UT_USER) + 1]; - user[0] = '\0'; - strncat(user, ut->UT_USER, sizeof(ut->UT_USER)); + memcpy(user, ut->UT_USER, sizeof(ut->UT_USER)); + user[sizeof(ut->UT_USER)] = '\0'; if (((pl->login_limit_def == LIMITS_DEF_USER) || (pl->login_limit_def == LIMITS_DEF_GROUP) @@ -437,15 +461,32 @@ static void parse_kernel_limits(pam_handle_t *pamh, struct pam_limit_s *pl, int pl->limits[i].src_hard = LIMITS_DEF_KERNEL; } fclose(limitsfile); + + /* Cap the default soft nofile limit read from pid 1 to FD_SETSIZE + * since larger values can cause problems with fd_set overflow and + * systemd sets itself higher. */ + if (pl->limits[RLIMIT_NOFILE].src_soft == LIMITS_DEF_KERNEL && + pl->limits[RLIMIT_NOFILE].limit.rlim_cur > FD_SETSIZE) { + pl->limits[RLIMIT_NOFILE].limit.rlim_cur = FD_SETSIZE; + } } static int init_limits(pam_handle_t *pamh, struct pam_limit_s *pl, int ctrl) { int i; int retval = PAM_SUCCESS; + static int mlock_limit = 0; D(("called.")); + pl->root = 0; + + if (mlock_limit == 0) { + mlock_limit = sysconf(_SC_PAGESIZE); + if (mlock_limit < MLOCK_LIMIT) + mlock_limit = MLOCK_LIMIT; + } + for(i = 0; i < RLIM_NLIMITS; i++) { int r = getrlimit(i, &pl->limits[i].limit); if (r == -1) { @@ -461,18 +502,68 @@ static int init_limits(pam_handle_t *pamh, struct pam_limit_s *pl, int ctrl) } #ifdef __linux__ - if (ctrl & PAM_SET_ALL) { - parse_kernel_limits(pamh, pl, ctrl); + parse_kernel_limits(pamh, pl, ctrl); +#endif - for(i = 0; i < RLIM_NLIMITS; i++) { + for(i = 0; i < RLIM_NLIMITS; i++) { if (pl->limits[i].supported && (pl->limits[i].src_soft == LIMITS_DEF_NONE || pl->limits[i].src_hard == LIMITS_DEF_NONE)) { - pam_syslog(pamh, LOG_WARNING, "Did not find kernel RLIMIT for %s, using PAM default", rlimit2str(i)); +#ifdef __linux__ + pam_syslog(pamh, LOG_WARNING, "Did not find kernel RLIMIT for %s, using PAM default", rlimit2str(i)); +#endif + pl->limits[i].src_soft = LIMITS_DEF_DEFAULT; + pl->limits[i].src_hard = LIMITS_DEF_DEFAULT; + switch(i) { + case RLIMIT_CPU: + case RLIMIT_FSIZE: + case RLIMIT_DATA: + case RLIMIT_RSS: + case RLIMIT_NPROC: +#ifdef RLIMIT_AS + case RLIMIT_AS: +#endif +#ifdef RLIMIT_LOCKS + case RLIMIT_LOCKS: +#endif + pl->limits[i].limit.rlim_cur = RLIM_INFINITY; + pl->limits[i].limit.rlim_max = RLIM_INFINITY; + break; + case RLIMIT_MEMLOCK: + pl->limits[i].limit.rlim_cur = mlock_limit; + pl->limits[i].limit.rlim_max = mlock_limit; + break; +#ifdef RLIMIT_SIGPENDING + case RLIMIT_SIGPENDING: + pl->limits[i].limit.rlim_cur = 16382; + pl->limits[i].limit.rlim_max = 16382; + break; +#endif +#ifdef RLIMIT_MSGQUEUE + case RLIMIT_MSGQUEUE: + pl->limits[i].limit.rlim_cur = 819200; + pl->limits[i].limit.rlim_max = 819200; + break; +#endif + case RLIMIT_CORE: + pl->limits[i].limit.rlim_cur = 0; + pl->limits[i].limit.rlim_max = RLIM_INFINITY; + break; + case RLIMIT_STACK: + pl->limits[i].limit.rlim_cur = 8192*1024; + pl->limits[i].limit.rlim_max = RLIM_INFINITY; + break; + case RLIMIT_NOFILE: + pl->limits[i].limit.rlim_cur = 1024; + pl->limits[i].limit.rlim_max = 1024; + break; + default: + pl->limits[i].src_soft = LIMITS_DEF_NONE; + pl->limits[i].src_hard = LIMITS_DEF_NONE; + break; + } } - } } -#endif errno = 0; pl->priority = getpriority (PRIO_PROCESS, 0); @@ -481,6 +572,43 @@ static int init_limits(pam_handle_t *pamh, struct pam_limit_s *pl, int ctrl) pl->login_limit = -2; pl->login_limit_def = LIMITS_DEF_NONE; + pl->chroot_dir[0] = '\0'; + + return retval; +} + +/* + * Read the contents of <pathname> and return it in *valuep + * return 1 if conversion succeeds, result is in *valuep + * return 0 if conversion fails, *valuep is untouched. + */ +static int +value_from_file(const char *pathname, rlim_t *valuep) +{ + char buf[128]; + FILE *fp; + int retval; + + retval = 0; + + if ((fp = fopen(pathname, "r")) != NULL) { + if (fgets(buf, sizeof(buf), fp) != NULL) { + char *endptr; + unsigned long long value; + + errno = 0; + value = strtoull(buf, &endptr, 10); + if (endptr != buf && + (value != ULLONG_MAX || errno == 0) && + (unsigned long long) (rlim_t) value == value) { + *valuep = (rlim_t) value; + retval = 1; + } + } + + fclose(fp); + } + return retval; } @@ -551,6 +679,10 @@ process_limit (const pam_handle_t *pamh, int source, const char *lim_type, pl->flag_numsyslogins = 1; } else if (strcmp(lim_item, "priority") == 0) { limit_item = LIMIT_PRI; + } else if (strcmp(lim_item, "nonewprivs") == 0) { + limit_item = LIMIT_NONEWPRIVS; + } else if (strcmp(lim_item, "chroot") == 0) { + limit_item = LIMIT_CHROOT; } else { pam_syslog(pamh, LOG_DEBUG, "unknown limit item '%s'", lim_item); return; @@ -562,11 +694,23 @@ process_limit (const pam_handle_t *pamh, int source, const char *lim_type, limit_type=LIMIT_HARD; else if (strcmp(lim_type,"-")==0) limit_type=LIMIT_SOFT | LIMIT_HARD; - else if (limit_item != LIMIT_LOGIN && limit_item != LIMIT_NUMSYSLOGINS) { + else if (limit_item != LIMIT_LOGIN && limit_item != LIMIT_NUMSYSLOGINS + && limit_item != LIMIT_NONEWPRIVS) { pam_syslog(pamh, LOG_DEBUG, "unknown limit type '%s'", lim_type); return; } - if (limit_item != LIMIT_PRI + if (limit_item == LIMIT_NONEWPRIVS) { + /* just require a bool-style 0 or 1 */ + if (strcmp(lim_value, "0") == 0) { + int_value = 0; + } else if (strcmp(lim_value, "1") == 0) { + int_value = 1; + } else { + pam_syslog(pamh, LOG_DEBUG, + "wrong limit value '%s' for limit type '%s'", + lim_value, lim_type); + } + } else if (limit_item != LIMIT_PRI #ifdef RLIMIT_NICE && limit_item != RLIMIT_NICE #endif @@ -588,9 +732,9 @@ process_limit (const pam_handle_t *pamh, int source, const char *lim_type, pam_syslog(pamh, LOG_DEBUG, "wrong limit value '%s' for limit type '%s'", lim_value, lim_type); - return; + return; } - } else { + } else if (limit_item != LIMIT_CHROOT) { #ifdef __USE_FILE_OFFSET64 rlimit_value = strtoull (lim_value, &endptr, 10); #else @@ -649,11 +793,30 @@ process_limit (const pam_handle_t *pamh, int source, const char *lim_type, rlimit_value = 20 - int_value; break; #endif + case RLIMIT_NOFILE: + /* + * If nofile is to be set to "unlimited", try to set it to + * the value in /proc/sys/fs/nr_open instead. + */ + if (rlimit_value == RLIM_INFINITY) { + if (!value_from_file("/proc/sys/fs/nr_open", &rlimit_value)) + pam_syslog(pamh, LOG_WARNING, + "Cannot set \"nofile\" to a sensible value"); + else if (ctrl & PAM_DEBUG_ARG) + pam_syslog(pamh, LOG_DEBUG, "Setting \"nofile\" limit to %llu", + (unsigned long long) rlimit_value); + } + break; } - if ( (limit_item != LIMIT_LOGIN) + if (limit_item == LIMIT_CHROOT) { + strncpy(pl->chroot_dir, value_orig, sizeof(pl->chroot_dir)-1); + pl->chroot_dir[sizeof(pl->chroot_dir)-1]='\0'; + } + else if ( (limit_item != LIMIT_LOGIN) && (limit_item != LIMIT_NUMSYSLOGINS) - && (limit_item != LIMIT_PRI) ) { + && (limit_item != LIMIT_PRI) + && (limit_item != LIMIT_NONEWPRIVS) ) { if (limit_type & LIMIT_SOFT) { if (pl->limits[limit_item].src_soft < source) { return; @@ -674,14 +837,16 @@ process_limit (const pam_handle_t *pamh, int source, const char *lim_type, /* recent kernels support negative priority limits (=raise priority) */ if (limit_item == LIMIT_PRI) { - pl->priority = int_value; + pl->priority = int_value; + } else if (limit_item == LIMIT_NONEWPRIVS) { + pl->nonewprivs = int_value; } else { - if (pl->login_limit_def < source) { - return; - } else { - pl->login_limit = int_value; - pl->login_limit_def = source; - } + if (pl->login_limit_def < source) { + return; + } else { + pl->login_limit = int_value; + pl->login_limit_def = source; + } } } return; @@ -737,18 +902,22 @@ parse_uid_range(pam_handle_t *pamh, const char *domain, static int parse_config_file(pam_handle_t *pamh, const char *uname, uid_t uid, gid_t gid, - int ctrl, struct pam_limit_s *pl) + int ctrl, struct pam_limit_s *pl, const int conf_file_set_by_user) { FILE *fil; char buf[LINE_LENGTH]; - /* check for the LIMITS_FILE */ + /* check for the conf_file */ if (ctrl & PAM_DEBUG_ARG) - pam_syslog(pamh, LOG_DEBUG, "reading settings from '%s'", CONF_FILE); - fil = fopen(CONF_FILE, "r"); + pam_syslog(pamh, LOG_DEBUG, "reading settings from '%s'", pl->conf_file); + fil = fopen(pl->conf_file, "r"); if (fil == NULL) { - pam_syslog (pamh, LOG_WARNING, - "cannot read settings from %s: %m", CONF_FILE); + if (errno == ENOENT && !conf_file_set_by_user) + return PAM_SUCCESS; /* file is not there and it has not been set by the conf= argument */ + + pam_syslog(pamh, LOG_WARNING, + "cannot read settings from %s: %s", pl->conf_file, + strerror(errno)); return PAM_SERVICE_ERR; } @@ -803,7 +972,7 @@ parse_config_file(pam_handle_t *pamh, const char *uname, uid_t uid, gid_t gid, if (strcmp(uname, domain) == 0) /* this user have a limit */ process_limit(pamh, LIMITS_DEF_USER, ltype, item, value, ctrl, pl); - else if (domain[0]=='@') { + else if (domain[0]=='@' && !pl->root) { if (ctrl & PAM_DEBUG_ARG) { pam_syslog(pamh, LOG_DEBUG, "checking if %s is in group %s", @@ -829,7 +998,7 @@ parse_config_file(pam_handle_t *pamh, const char *uname, uid_t uid, gid_t gid, process_limit(pamh, LIMITS_DEF_GROUP, ltype, item, value, ctrl, pl); } - } else if (domain[0]=='%') { + } else if (domain[0]=='%' && !pl->root) { if (ctrl & PAM_DEBUG_ARG) { pam_syslog(pamh, LOG_DEBUG, "checking if %s is in group %s", @@ -863,7 +1032,7 @@ parse_config_file(pam_handle_t *pamh, const char *uname, uid_t uid, gid_t gid, } else { switch(rngtype) { case LIMIT_RANGE_NONE: - if (strcmp(domain, "*") == 0) + if (strcmp(domain, "*") == 0 && !pl->root) process_limit(pamh, LIMITS_DEF_DEFAULT, ltype, item, value, ctrl, pl); break; @@ -962,9 +1131,21 @@ static int setup_limits(pam_handle_t *pamh, if (pl->limits[i].limit.rlim_cur > pl->limits[i].limit.rlim_max) pl->limits[i].limit.rlim_cur = pl->limits[i].limit.rlim_max; res = setrlimit(i, &pl->limits[i].limit); - if (res != 0) - pam_syslog(pamh, LOG_ERR, "Could not set limit for '%s': %m", - rlimit2str(i)); + if (res != 0 && (i != RLIMIT_NOFILE + || pl->limits[i].limit.rlim_cur != RLIM_INFINITY)) + { + int save_errno = errno; + pam_syslog(pamh, LOG_DEBUG, + "Could not set limit for '%s' to soft=%d, hard=%d:" + " %m; uid=%lu,euid=%lu", rlimit2str(i), + pl->limits[i].limit.rlim_cur, + pl->limits[i].limit.rlim_max, + (unsigned long) getuid(), + (unsigned long) geteuid()); + errno = save_errno; + } + if (res == -1 && errno == EPERM) + continue; status |= res; } @@ -995,36 +1176,151 @@ static int setup_limits(pam_handle_t *pamh, retval |= LOGIN_ERR; } + if (pl->nonewprivs) { + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { + pam_syslog(pamh, LOG_ERR, "Could not set prctl(PR_SET_NO_NEW_PRIVS): %m"); + retval |= LIMIT_ERR; + } + } + + if (!retval && pl->chroot_dir[0]) { + i = chdir(pl->chroot_dir); + if (i == 0) + i = chroot(pl->chroot_dir); + if (i == 0) + i = chdir("/"); + if (i != 0) + retval = LIMIT_ERR; + } return retval; } +/* --- evaluting all files in VENDORDIR/security/limits.d and /etc/security/limits.d --- */ +static const char * +base_name(const char *path) +{ + const char *base = strrchr(path, '/'); + return base ? base+1 : path; +} + +static int +compare_filename(const void *a, const void *b) +{ + return strcmp(base_name(* (const char * const *) a), + base_name(* (const char * const *) b)); +} + +/* Evaluating a list of files which have to be parsed in the right order: + * + * - If etc/security/limits.d/@filename@.conf exists, then + * %vendordir%/security/limits.d/@filename@.conf should not be used. + * - All files in both limits.d directories are sorted by their @filename@.conf in + * lexicographic order regardless of which of the directories they reside in. */ +static char ** +read_limits_dir(pam_handle_t *pamh) +{ + glob_t globbuf; + size_t i=0; + int glob_rv = glob(LIMITS_CONF_GLOB, GLOB_ERR | GLOB_NOSORT, NULL, &globbuf); + char **file_list; + size_t file_list_size = glob_rv == 0 ? globbuf.gl_pathc : 0; + +#ifdef VENDOR_LIMITS_CONF_GLOB + glob_t globbuf_vendor; + int glob_rv_vendor = glob(VENDOR_LIMITS_CONF_GLOB, GLOB_ERR | GLOB_NOSORT, NULL, &globbuf_vendor); + if (glob_rv_vendor == 0) + file_list_size += globbuf_vendor.gl_pathc; +#endif + file_list = malloc((file_list_size + 1) * sizeof(char*)); + if (file_list == NULL) { + pam_syslog(pamh, LOG_ERR, "Cannot allocate memory for file list: %m"); +#ifdef VENDOR_ACCESS_CONF_GLOB + if (glob_rv_vendor == 0) + globfree(&globbuf_vendor); +#endif + if (glob_rv == 0) + globfree(&globbuf); + return NULL; + } + + if (glob_rv == 0) { + for (i = 0; i < globbuf.gl_pathc; i++) { + file_list[i] = strdup(globbuf.gl_pathv[i]); + if (file_list[i] == NULL) { + pam_syslog(pamh, LOG_ERR, "strdup failed: %m"); + break; + } + } + } +#ifdef VENDOR_LIMITS_CONF_GLOB + if (glob_rv_vendor == 0) { + for (size_t j = 0; j < globbuf_vendor.gl_pathc; j++) { + if (glob_rv == 0 && globbuf.gl_pathc > 0) { + int double_found = 0; + for (size_t k = 0; k < globbuf.gl_pathc; k++) { + if (strcmp(base_name(globbuf.gl_pathv[k]), + base_name(globbuf_vendor.gl_pathv[j])) == 0) { + double_found = 1; + break; + } + } + if (double_found) + continue; + } + file_list[i] = strdup(globbuf_vendor.gl_pathv[j]); + if (file_list[i] == NULL) { + pam_syslog(pamh, LOG_ERR, "strdup failed: %m"); + break; + } + i++; + } + globfree(&globbuf_vendor); + } +#endif + file_list[i] = NULL; + qsort(file_list, i, sizeof(char *), compare_filename); + if (glob_rv == 0) + globfree(&globbuf); + + return file_list; +} + /* now the session stuff */ int pam_sm_open_session (pam_handle_t *pamh, int flags UNUSED, int argc, const char **argv) { - int retval; - int i; - int glob_rc; + int retval, i; char *user_name; struct passwd *pwd; int ctrl; struct pam_limit_s plstruct; struct pam_limit_s *pl = &plstruct; - glob_t globbuf; - const char *oldlocale; D(("called.")); memset(pl, 0, sizeof(*pl)); - memset(&globbuf, 0, sizeof(globbuf)); ctrl = _pam_parse(pamh, argc, argv, pl); retval = pam_get_item( pamh, PAM_USER, (void*) &user_name ); if ( user_name == NULL || retval != PAM_SUCCESS ) { pam_syslog(pamh, LOG_ERR, "open_session - error recovering username"); return PAM_SESSION_ERR; - } + } + + int conf_file_set_by_user = (pl->conf_file != NULL); + if (pl->conf_file == NULL) { + pl->conf_file = LIMITS_FILE; +#ifdef VENDOR_LIMITS_FILE + /* + * Check whether LIMITS_FILE file is available. + * If it does not exist, fall back to VENDOR_LIMITS_FILE file. + */ + struct stat buffer; + if (stat(pl->conf_file, &buffer) != 0 && errno == ENOENT) + pl->conf_file = VENDOR_LIMITS_FILE; +#endif + } pwd = pam_modutil_getpwnam(pamh, user_name); if (!pwd) { @@ -1040,46 +1336,41 @@ pam_sm_open_session (pam_handle_t *pamh, int flags UNUSED, return PAM_ABORT; } - retval = parse_config_file(pamh, pwd->pw_name, pwd->pw_uid, pwd->pw_gid, ctrl, pl); + if (pwd->pw_uid == 0) + pl->root = 1; + retval = parse_config_file(pamh, pwd->pw_name, pwd->pw_uid, pwd->pw_gid, + ctrl, pl, conf_file_set_by_user); if (retval == PAM_IGNORE) { - D(("the configuration file ('%s') has an applicable '<domain> -' entry", CONF_FILE)); + D(("the configuration file ('%s') has an applicable '<domain> -' entry", pl->conf_file)); return PAM_SUCCESS; } - if (retval != PAM_SUCCESS || pl->conf_file != NULL) + if (retval != PAM_SUCCESS || conf_file_set_by_user) /* skip reading limits.d if config file explicitly specified */ goto out; /* Read subsequent *.conf files, if they exist. */ - - /* set the LC_COLLATE so the sorting order doesn't depend - on system locale */ - - oldlocale = setlocale(LC_COLLATE, "C"); - glob_rc = glob(LIMITS_CONF_GLOB, GLOB_ERR, NULL, &globbuf); - - if (oldlocale != NULL) - setlocale (LC_COLLATE, oldlocale); - - if (!glob_rc) { - /* Parse the *.conf files. */ - for (i = 0; globbuf.gl_pathv[i] != NULL; i++) { - pl->conf_file = globbuf.gl_pathv[i]; - retval = parse_config_file(pamh, pwd->pw_name, pwd->pw_uid, pwd->pw_gid, ctrl, pl); - if (retval == PAM_IGNORE) { - D(("the configuration file ('%s') has an applicable '<domain> -' entry", pl->conf_file)); - globfree(&globbuf); - return PAM_SUCCESS; - } - if (retval != PAM_SUCCESS) - goto out; + char **filename_list = read_limits_dir(pamh); + if (filename_list != NULL) { + for (i = 0; filename_list[i] != NULL; i++) { + pl->conf_file = filename_list[i]; + retval = parse_config_file(pamh, pwd->pw_name, pwd->pw_uid, pwd->pw_gid, ctrl, pl, 0); + if (retval != PAM_SUCCESS) + break; } + for (i = 0; filename_list[i] != NULL; i++) + free(filename_list[i]); + free(filename_list); + } + + if (retval == PAM_IGNORE) { + D(("the configuration file ('%s') has an applicable '<domain> -' entry", pl->conf_file)); + return PAM_SUCCESS; } out: - globfree(&globbuf); if (retval != PAM_SUCCESS) { - pam_syslog(pamh, LOG_ERR, "error parsing the configuration file: '%s' ",CONF_FILE); + pam_syslog(pamh, LOG_ERR, "error parsing the configuration file: '%s' ", pl->conf_file); return retval; } |