openssh2.3.0p1 and /etc/limits
Sagi Bashari
sagi at aresworld.net
Fri Feb 9 06:25:45 EST 2001
Hi!
I wrote a small patch to enable /etc/limits support in openssh. nice
thing when you don't have PAM installed..
It is based on Ultor's openssh 1.x patch
(http://marc.theaimsgroup.com/?l=secure-shell&m=96427677022741&w=2)
Works fine on slackware7.1. define USE_ETC_LIMITS in config.h , and
compile as usual.
Sagi
-------------- next part --------------
diff -N -u openssh-2.3.0p1.orig/Makefile.in openssh-2.3.0p1/Makefile.in
--- openssh-2.3.0p1.orig/Makefile.in Wed Feb 7 22:24:35 2001
+++ openssh-2.3.0p1/Makefile.in Wed Feb 7 22:43:55 2001
@@ -41,7 +41,7 @@
SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o log-client.o readconf.o clientloop.o
-SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth-skey.o auth2-skey.o auth-rhosts.o auth-options.o auth-krb4.o auth-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o dh.o pty.o log-server.o login.o loginrec.o servconf.o serverloop.o md5crypt.o session.o
+SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth-skey.o auth2-skey.o auth-rhosts.o auth-options.o auth-krb4.o auth-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o dh.o pty.o log-server.o login.o loginrec.o servconf.o serverloop.o md5crypt.o session.o limits.o
TROFFMAN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8 sftp-server.8
CATMAN = scp.0 ssh-add.0 ssh-agent.0 ssh-keygen.0 ssh.0 sshd.0 sftp-server.0
diff -N -u openssh-2.3.0p1.orig/config.h.in openssh-2.3.0p1/config.h.in
--- openssh-2.3.0p1.orig/config.h.in Wed Feb 7 22:24:36 2001
+++ openssh-2.3.0p1/config.h.in Wed Feb 7 22:43:55 2001
@@ -5,6 +5,8 @@
/* Generated automatically from acconfig.h by autoheader. */
/* Please make your changes there */
+/* use /etc/limits*/
+#undef USE_ETC_LIMITS
/* Define if the `getpgrp' function takes no argument. */
#undef GETPGRP_VOID
Common subdirectories: openssh-2.3.0p1.orig/contrib and openssh-2.3.0p1/contrib
diff -N -u openssh-2.3.0p1.orig/limits.c openssh-2.3.0p1/limits.c
--- openssh-2.3.0p1.orig/limits.c Thu Jan 1 02:00:00 1970
+++ openssh-2.3.0p1/limits.c Wed Feb 7 22:43:55 2001
@@ -0,0 +1,340 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Separated from setup.c. --marekm
+ * Resource limits thanks to Cristian Gafton.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <syslog.h>
+
+#include <stdio.h>
+#include <utmp.h>
+#include <pwd.h>
+
+#include <sys/resource.h>
+#define LIMITS
+
+#ifdef LIMITS
+
+#ifndef LIMITS_FILE
+#define LIMITS_FILE "/etc/limits"
+#endif
+
+#define memzero(ptr, size) memset((void *)(ptr), 0, (size))
+
+#define LOGIN_ERROR_RLIMIT 1
+#define LOGIN_ERROR_LOGIN 2
+
+/* Set a limit on a resource */
+/*
+ * rlimit - RLIMIT_XXXX
+ * value - string value to be read
+ * multiplier - value*multiplier is the actual limit
+ */
+static int
+setrlimit_value(unsigned int rlimit, const char *value, unsigned int multiplier)
+{
+ struct rlimit rlim;
+ long limit;
+ char **endptr = (char **) &value;
+ const char *value_orig = value;
+
+ limit = strtol(value, endptr, 10);
+ if (limit == 0 && value_orig == *endptr) /* no chars read */
+ return 0;
+ limit *= multiplier;
+ rlim.rlim_cur = limit;
+ rlim.rlim_max = limit;
+ if (setrlimit(rlimit, &rlim))
+ return LOGIN_ERROR_RLIMIT;
+ return 0;
+}
+
+
+static int
+set_prio(const char *value)
+{
+ int prio;
+ char **endptr = (char **) &value;
+
+ prio = strtol(value, endptr, 10);
+ if ((prio == 0) && (value == *endptr))
+ return 0;
+ if (setpriority(PRIO_PROCESS, 0, prio))
+ return LOGIN_ERROR_RLIMIT;
+ return 0;
+}
+
+
+/* Counts the number of user logins and check against the limit */
+static int
+check_logins(const char *name, const char *maxlogins)
+{
+ struct utmp *ut;
+ unsigned int limit, count;
+ char **endptr = (char **) &maxlogins;
+ const char *ml_orig = maxlogins;
+
+ limit = strtol(maxlogins, endptr, 10);
+ if (limit == 0 && ml_orig == *endptr) /* no chars read */
+ return 0;
+
+ if (limit == 0) /* maximum 0 logins ? */ {
+ syslog(LOG_WARNING, "No logins allowed for `%s'\n", name);
+ return LOGIN_ERROR_LOGIN;
+ }
+
+ setutent();
+ count = 0;
+ while ((ut = getutent())) {
+// if (ut->ut_type != USER_PROCESS)
+// continue;
+ if (ut->ut_user[0] == '\0')
+ continue;
+ if (strncmp(name, ut->ut_user, sizeof(ut->ut_user)) != 0)
+ continue;
+ if (++count > limit)
+ break;
+ }
+ endutent();
+ /*
+ * This is called after setutmp(), so the number of logins counted
+ * includes the user who is currently trying to log in.
+ */
+
+ if (count > limit) {
+ printf("Too many logins (max %d).\n",count);
+ syslog(LOG_WARNING, "Too many logins (max %d) for %s\n",limit, name);
+ return LOGIN_ERROR_LOGIN;
+ }
+
+ return 0;
+}
+
+/* Function setup_user_limits - checks/set limits for the curent login
+ * Original idea from Joel Katz's lshell. Ported to shadow-login
+ * by Cristian Gafton - gafton at sorosis.ro
+ *
+ * We are passed a string of the form ('BASH' constants for ulimit)
+ * [Aa][Cc][Dd][Ff][Mm][Nn][Rr][Ss][Tt][Uu][Ll][Pp]
+ * (eg. 'C2F256D2048N5' or 'C2 F256 D2048 N5')
+ * where:
+ * [Aa]: a = RLIMIT_AS max address space (KB)
+ * [Cc]: c = RLIMIT_CORE max core file size (KB)
+ * [Dd]: d = RLIMIT_DATA max data size (KB)
+ * [Ff]: f = RLIMIT_FSIZE Maximum filesize (KB)
+ * [Mm]: m = RLIMIT_MEMLOCK max locked-in-memory address space (KB)
+ * [Nn]: n = RLIMIT_NOFILE max number of open files
+ * [Rr]: r = RLIMIT_RSS max resident set size (KB)
+ * [Ss]: s = RLIMIT_STACK max stack size (KB)
+ * [Tt]: t = RLIMIT_CPU max CPU time (MIN)
+ * [Uu]: u = RLIMIT_NPROC max number of processes
+ * [Ll]: l = max number of logins for this user
+ * [Pp]: p = process priority -20..20 (negative = high priority)
+ *
+ * Return value:
+ * 0 = okay, of course
+ * LOGIN_ERROR_RLIMIT = error setting some RLIMIT
+ * LOGIN_ERROR_LOGIN = error - too many logins for this user
+ *
+ * buf - the limits string
+ * name - the username
+ */
+static int
+do_user_limits(const char *buf, const char *name)
+{
+ const char *pp;
+ int retval = 0;
+
+ pp = buf;
+
+ while (*pp != '\0') switch(*pp++) {
+#ifdef RLIMIT_AS
+ case 'a':
+ case 'A':
+ /* RLIMIT_AS - max address space (KB) */
+ retval |= setrlimit_value(RLIMIT_AS, pp, 1024);
+#endif
+#ifdef RLIMIT_CPU
+ case 't':
+ case 'T':
+ /* RLIMIT_CPU - max CPU time (MIN) */
+ retval |= setrlimit_value(RLIMIT_CPU, pp, 60);
+ break;
+#endif
+#ifdef RLIMIT_DATA
+ case 'd':
+ case 'D':
+ /* RLIMIT_DATA - max data size (KB) */
+ retval |= setrlimit_value(RLIMIT_DATA, pp, 1024);
+ break;
+#endif
+#ifdef RLIMIT_FSIZE
+ case 'f':
+ case 'F':
+ /* RLIMIT_FSIZE - Maximum filesize (KB) */
+ retval |= setrlimit_value(RLIMIT_FSIZE, pp, 1024);
+ break;
+#endif
+#ifdef RLIMIT_NPROC
+ case 'u':
+ case 'U':
+ /* RLIMIT_NPROC - max number of processes */
+ retval |= setrlimit_value(RLIMIT_NPROC, pp, 1);
+ break;
+#endif
+#ifdef RLIMIT_CORE
+ case 'c':
+ case 'C':
+ /* RLIMIT_CORE - max core file size (KB) */
+ retval |= setrlimit_value(RLIMIT_CORE, pp, 1024);
+ break;
+#endif
+#ifdef RLIMIT_MEMLOCK
+ case 'm':
+ case 'M':
+ /* RLIMIT_MEMLOCK - max locked-in-memory address space (KB) */
+ retval |= setrlimit_value(RLIMIT_MEMLOCK, pp, 1024);
+ break;
+#endif
+#ifdef RLIMIT_NOFILE
+ case 'n':
+ case 'N':
+ /* RLIMIT_NOFILE - max number of open files */
+ retval |= setrlimit_value(RLIMIT_NOFILE, pp, 1);
+ break;
+#endif
+#ifdef RLIMIT_RSS
+ case 'r':
+ case 'R':
+ /* RLIMIT_RSS - max resident set size (KB) */
+ retval |= setrlimit_value(RLIMIT_RSS, pp, 1024);
+ break;
+#endif
+#ifdef RLIMIT_STACK
+ case 's':
+ case 'S':
+ /* RLIMIT_STACK - max stack size (KB) */
+ retval |= setrlimit_value(RLIMIT_STACK, pp, 1024);
+ break;
+#endif
+ case 'l':
+ case 'L':
+ /* LIMIT the number of concurent logins */
+ retval |= check_logins(name, pp);
+ break;
+ case 'p':
+ case 'P':
+ retval |= set_prio(pp);
+ break;
+ }
+ return retval;
+}
+
+static int
+setup_user_limits(const char *uname)
+{
+ /* TODO: allow and use @group syntax --cristiang */
+ FILE *fil;
+ char buf[1024];
+ char name[1024];
+ char limits[1024];
+ char deflimits[1024];
+ char tempbuf[1024];
+
+ /* init things */
+ memzero(buf, sizeof(buf));
+ memzero(name, sizeof(name));
+ memzero(limits, sizeof(limits));
+ memzero(deflimits, sizeof(deflimits));
+ memzero(tempbuf, sizeof(tempbuf));
+
+ /* start the checks */
+ fil = fopen(LIMITS_FILE, "r");
+ if (fil == NULL) {
+#if 0 /* no limits file is ok, not everyone is a BOFH :-). --marekm */
+ syslog(LOG_WARNING, NO_LIMITS, uname, LIMITS_FILE);
+#endif
+ return 0;
+ }
+ /* The limits file have the following format:
+ * - '#' (comment) chars only as first chars on a line;
+ * - username must start on first column
+ * A better (smarter) checking should be done --cristiang */
+ while (fgets(buf, 1024, fil) != NULL) {
+ if (buf[0]=='#' || buf[0]=='\n')
+ continue;
+ memzero(tempbuf, sizeof(tempbuf));
+ /* a valid line should have a username, then spaces,
+ * then limits
+ * we allow the format:
+ * username L2 D2048 R4096
+ * where spaces={' ',\t}. Also, we reject invalid limits.
+ * Imposing a limit should be done with care, so a wrong
+ * entry means no care anyway :-). A '-' as a limits
+ * strings means no limits --cristiang */
+ if (sscanf(buf, "%s%[ACDFMNRSTULPacdfmnrstulp0-9 \t-]",
+ name, tempbuf) == 2) {
+ if (strcmp(name, uname) == 0) {
+ strcpy(limits, tempbuf);
+ break;
+ } else if (strcmp(name, "*") == 0) {
+ strcpy(deflimits, tempbuf);
+ }
+ }
+ }
+ fclose(fil);
+ if (limits[0] == '\0') {
+ /* no user specific limits */
+ if (deflimits[0] == '\0') /* no default limits */
+ return 0;
+ strcpy(limits, deflimits); /* use the default limits */
+ }
+ return do_user_limits(limits, uname);
+}
+
+#endif /* LIMITS */
+
+/*
+ * set the process nice, ulimit, and umask from the password file entry
+ */
+
+void setup_limits(const struct passwd *info) {
+ char *cp;
+ int i;
+ long l;
+
+ if (info->pw_uid) if (setup_user_limits(info->pw_name) & LOGIN_ERROR_LOGIN) {
+ sleep(2);
+ exit(1);
+ }
+}
diff -N -u openssh-2.3.0p1.orig/session.c openssh-2.3.0p1/session.c
--- openssh-2.3.0p1.orig/session.c Wed Feb 7 22:24:35 2001
+++ openssh-2.3.0p1/session.c Wed Feb 7 22:43:55 2001
@@ -599,6 +599,10 @@
do_pam_session(pw->pw_name, s->tty);
do_pam_setcred();
#endif /* USE_PAM */
+
+#ifdef USE_ETC_LIMITS
+ setup_limits(pw);
+#endif /* USE_ETC_LIMITS */
/* Fork the child. */
if ((pid = fork()) == 0) {
More information about the openssh-unix-dev
mailing list