1 /*
2  * ProFTPD: mod_load -- a module for refusing connections based on system load
3  * Copyright (c) 2001-2017 TJ Saunders
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18  *
19  * As a special exemption, TJ Saunders and other respective copyright holders
20  * give permission to link this program with OpenSSL, and distribute the
21  * resulting executable, without including the source code for OpenSSL in the
22  * source distribution.
23  *
24  * This is mod_load, contrib software for proftpd 1.2.x and above.
25  * For more information contact TJ Saunders <tj@castaglia.org>.
26  *
27  * Based on the getloadavg.c file included in GNU make-3.79, which carries
28  * the following copyright:
29  *
30  *   Copyright (C) 1985, 86, 87, 88, 89, 91, 92, 93, 1994, 1995, 1997
31  *     Free Software Foundation, Inc.
32  */
33 
34 #include "conf.h"
35 #include "privs.h"
36 #include "mod_load.h"
37 
38 #define MOD_LOAD_VERSION		"mod_load/1.0.1"
39 
40 /* Make sure the version of proftpd is as necessary. */
41 #if PROFTPD_VERSION_NUMBER < 0x0001030402
42 # error "ProFTPD 1.3.4rc2 or later required"
43 #endif
44 
45 /* Support code.  Most of this is from getloadavg.c
46  */
47 
48 #if defined (unix) || defined (__unix)
49 # include <sys/param.h>
50 #endif
51 
52 #ifndef HAVE_GETLOADAVG
53 # if !defined(LDAV_CVT) && defined(LOAD_AVE_CVT)
54 #  define LDAV_CVT(n) (LOAD_AVE_CVT (n) / 100.0)
55 # endif
56 
57 # if !defined (BSD) && defined (ultrix)
58 #  define BSD
59 # endif
60 
61 # ifdef NeXT
62 #  undef BSD
63 #  undef FSCALE
64 # endif
65 
66 # ifdef __GNU__
67 #  undef BSD
68 #  undef FSCALE
69 # endif /* __GNU__ */
70 
71 # if defined (HPUX) && !defined (hpux)
72 #  define hpux
73 # endif
74 
75 # if defined (__hpux) && !defined (hpux)
76 #  define hpux
77 # endif
78 
79 # if defined (__sun) && !defined (sun)
80 #  define sun
81 # endif
82 
83 # if defined(hp300) && !defined(hpux)
84 #  define MORE_BSD
85 # endif
86 
87 # if defined(ultrix) && defined(mips)
88 #  define decstation
89 # endif
90 
91 # if defined (__SVR4) && !defined (SVR4)
92 #  define SVR4
93 # endif
94 
95 # if (defined(sun) && defined(SVR4)) || defined (SOLARIS2)
96 #  define SUNOS_5
97 # endif
98 
99 # if defined (__osf__) && (defined (__alpha) || defined (__alpha__))
100 #  define OSF_ALPHA
101 #  include <sys/mbuf.h>
102 #  include <sys/socket.h>
103 #  include <net/route.h>
104 #  include <sys/table.h>
105 # endif
106 
107 # if defined (__osf__) && (defined (mips) || defined (__mips__))
108 #  define OSF_MIPS
109 #  include <sys/table.h>
110 # endif
111 
112 # if !defined (tek4300) && defined (unix) && defined (m68k) && defined (mc68000) && defined (mc68020) && defined (_MACH_IND_SYS_TYPES)
113 #  define tek4300
114 # endif
115 
116 # ifndef LOAD_AVE_TYPE
117 
118 #  ifdef MORE_BSD
119 #   define LOAD_AVE_TYPE long
120 #  endif
121 
122 #  ifdef sun
123 #   define LOAD_AVE_TYPE long
124 #  endif
125 
126 #  ifdef decstation
127 #   define LOAD_AVE_TYPE long
128 #  endif
129 
130 #  ifdef _SEQUENT_
131 #   define LOAD_AVE_TYPE long
132 #  endif
133 
134 #  ifdef sgi
135 #   define LOAD_AVE_TYPE long
136 #  endif
137 
138 #  ifdef SVR4
139 #   define LOAD_AVE_TYPE long
140 #  endif
141 
142 #  ifdef sony_news
143 #   define LOAD_AVE_TYPE long
144 #  endif
145 
146 #  ifdef sequent
147 #   define LOAD_AVE_TYPE long
148 #  endif
149 
150 #  ifdef OSF_ALPHA
151 #   define LOAD_AVE_TYPE long
152 #  endif
153 
154 #  if defined (ardent) && defined (titan)
155 #   define LOAD_AVE_TYPE long
156 #  endif
157 
158 #  ifdef tek4300
159 #   define LOAD_AVE_TYPE long
160 #  endif
161 
162 #  if defined(alliant) && defined(i860) /* Alliant FX/2800 */
163 #   define LOAD_AVE_TYPE long
164 #  endif
165 
166 #  ifdef _AIX
167 #   define LOAD_AVE_TYPE long
168 #  endif
169 
170 #  ifdef convex
171 #   define LOAD_AVE_TYPE double
172 #   ifndef LDAV_CVT
173 #    define LDAV_CVT(n) (n)
174 #   endif
175 #  endif
176 
177 # endif /* No LOAD_AVE_TYPE.  */
178 
179 # ifdef OSF_ALPHA
180 #  undef FSCALE
181 #  define FSCALE 1024.0
182 # endif
183 
184 # if defined(alliant) && defined(i860) /* Alliant FX/2800 */
185 #  undef FSCALE
186 #  define FSCALE 100.0
187 # endif
188 
189 # ifndef        FSCALE
190 
191 #  ifdef MORE_BSD
192 #   define FSCALE 2048.0
193 #  endif
194 
195 #  if defined(MIPS) || defined(SVR4) || defined(decstation)
196 #   define FSCALE 256
197 #  endif
198 
199 #  if defined (sgi) || defined (sequent)
200 #   undef FSCALE
201 #   define      FSCALE 1000.0
202 #  endif
203 
204 #  if defined (ardent) && defined (titan)
205 #   define FSCALE 65536.0
206 #  endif
207 
208 #  ifdef tek4300
209 #   define FSCALE 100.0
210 #  endif
211 
212 #  ifdef _AIX
213 #   define FSCALE 65536.0
214 #  endif
215 
216 # endif /* Not FSCALE.  */
217 
218 # if !defined (LDAV_CVT) && defined (FSCALE)
219 #  define       LDAV_CVT(n) (((double) (n)) / FSCALE)
220 # endif
221 
222 # ifndef NLIST_STRUCT
223 
224 #  ifdef MORE_BSD
225 #   define NLIST_STRUCT
226 #  endif
227 
228 #  ifdef sun
229 #   define NLIST_STRUCT
230 #  endif
231 
232 #  ifdef decstation
233 #   define NLIST_STRUCT
234 #  endif
235 
236 #  ifdef hpux
237 #   define NLIST_STRUCT
238 #  endif
239 
240 #  if defined (_SEQUENT_) || defined (sequent)
241 #   define NLIST_STRUCT
242 #  endif
243 
244 #  ifdef sgi
245 #   define NLIST_STRUCT
246 #  endif
247 
248 #  ifdef SVR4
249 #   define NLIST_STRUCT
250 #  endif
251 
252 #  ifdef sony_news
253 #   define NLIST_STRUCT
254 #  endif
255 
256 #  ifdef OSF_ALPHA
257 #   define NLIST_STRUCT
258 #  endif
259 
260 #  if defined (ardent) && defined (titan)
261 #   define NLIST_STRUCT
262 #  endif
263 
264 #  ifdef tek4300
265 #   define NLIST_STRUCT
266 #  endif
267 
268 #  ifdef butterfly
269 #   define NLIST_STRUCT
270 #  endif
271 
272 #  if defined(alliant) && defined(i860) /* Alliant FX/2800 */
273 #   define NLIST_STRUCT
274 #  endif
275 
276 #  ifdef _AIX
277 #   define NLIST_STRUCT
278 #  endif
279 
280 # endif /* defined (NLIST_STRUCT) */
281 
282 # if defined(sgi) || (defined(mips) && !defined(BSD))
283 #  define FIXUP_KERNEL_SYMBOL_ADDR(nl) ((nl)[0].n_value &= ~(1 << 31))
284 # endif
285 
286 # if !defined (KERNEL_FILE) && defined (sequent)
287 #  define KERNEL_FILE "/dynix"
288 # endif
289 
290 # if !defined (KERNEL_FILE) && defined (hpux)
291 #  define KERNEL_FILE "/hp-ux"
292 # endif
293 
294 # if !defined(KERNEL_FILE) && (defined(_SEQUENT_) || defined(MIPS) || defined(SVR4) || defined(ISC) || defined (sgi) || (defined (ardent) && defined (titan)))
295 #  define KERNEL_FILE "/unix"
296 # endif
297 
298 # if !defined (LDAV_SYMBOL) && defined (alliant)
299 #  define LDAV_SYMBOL "_Loadavg"
300 # endif
301 
302 # if !defined(LDAV_SYMBOL) && ((defined(hpux) && !defined(hp9000s300)) || defined(_SEQUENT_) || defined(SVR4) || defined(ISC) || defined(sgi) || (defined (ardent) && defined (titan)) || defined (_AIX))
303 #  define LDAV_SYMBOL "avenrun"
304 # endif
305 
306 # ifdef HAVE_UNISTD_H
307 #  include <unistd.h>
308 # endif
309 
310 # include <stdio.h>
311 
312 # if !defined(LOAD_AVE_TYPE) && (defined(BSD) || defined(LDAV_CVT) || defined(KERNEL_FILE) || defined(LDAV_SYMBOL))
313 #  define LOAD_AVE_TYPE double
314 # endif
315 
316 # ifdef LOAD_AVE_TYPE
317 
318 #  ifndef VMS
319 #   ifndef __linux__
320 #    ifndef NLIST_STRUCT
321 #     include <a.out.h>
322 #    else /* NLIST_STRUCT */
323 #     include <nlist.h>
324 #    endif /* NLIST_STRUCT */
325 
326 #    ifdef SUNOS_5
327 #     include <fcntl.h>
328 #     include <kvm.h>
329 #     include <kstat.h>
330 #    endif
331 
332 #    if defined (hpux) && defined (HAVE_PSTAT_GETDYNAMIC)
333 #     include <sys/pstat.h>
334 #    endif
335 
336 #    ifndef KERNEL_FILE
337 #     define KERNEL_FILE "/vmunix"
338 #    endif /* KERNEL_FILE */
339 
340 #    ifndef LDAV_SYMBOL
341 #     define LDAV_SYMBOL "_avenrun"
342 #    endif /* LDAV_SYMBOL */
343 #   endif /* __linux__ */
344 
345 #  else /* VMS */
346 
347 #   ifndef eunice
348 #    include <iodef.h>
349 #    include <descrip.h>
350 #   else /* eunice */
351 #    include <vms/iodef.h>
352 #   endif /* eunice */
353 #  endif /* VMS */
354 
355 #  ifndef LDAV_CVT
356 #   define LDAV_CVT(n) ((double) (n))
357 #  endif /* !LDAV_CVT */
358 
359 # endif /* LOAD_AVE_TYPE */
360 
361 # if defined(__GNU__) && !defined (NeXT)
362 #  define NeXT
363 #  define host_self mach_host_self
364 # endif
365 
366 # ifdef NeXT
367 #  ifdef HAVE_MACH_MACH_H
368 #   include <mach/mach.h>
369 #  else
370 #   include <mach.h>
371 #  endif
372 # endif /* NeXT */
373 
374 # ifdef sgi
375 #  include <sys/sysmp.h>
376 # endif /* sgi */
377 
378 # ifdef UMAX
379 #  include <stdio.h>
380 #  include <signal.h>
381 #  include <sys/time.h>
382 #  include <sys/wait.h>
383 #  include <sys/syscall.h>
384 
385 #  ifdef UMAX_43
386 #   include <machine/cpu.h>
387 #   include <inq_stats/statistics.h>
388 #   include <inq_stats/sysstats.h>
389 #   include <inq_stats/cpustats.h>
390 #   include <inq_stats/procstats.h>
391 #  else /* Not UMAX_43.  */
392 #   include <sys/sysdefs.h>
393 #   include <sys/statistics.h>
394 #   include <sys/sysstats.h>
395 #   include <sys/cpudefs.h>
396 #   include <sys/cpustats.h>
397 #   include <sys/procstats.h>
398 #  endif /* Not UMAX_43.  */
399 # endif /* UMAX */
400 
401 # ifdef DGUX
402 #  include <sys/dg_sys_info.h>
403 # endif
404 
405 # if defined(HAVE_FCNTL_H) || defined(_POSIX_VERSION)
406 #  include <fcntl.h>
407 # else
408 #  include <sys/file.h>
409 # endif
410 
411 # ifdef NeXT
412 static processor_set_t default_set;
413 static int getloadavg_initialized;
414 # endif /* NeXT */
415 
416 # ifdef UMAX
417 static unsigned int cpus = 0;
418 static unsigned int samples;
419 # endif /* UMAX */
420 
421 # ifdef DGUX
422 static struct dg_sys_info_load_info load_info;  /* what-a-mouthful! */
423 # endif /* DGUX */
424 
425 # if !defined(HAVE_LIBKSTAT) && defined(LOAD_AVE_TYPE) && !defined(__linux__)
426 /* File descriptor open to /dev/kmem or VMS load ave driver.  */
427 static int channel;
428 /* Nonzero iff channel is valid.  */
429 static int getloadavg_initialized;
430 /* Offset in kmem to seek to read load average, or 0 means invalid.  */
431 static long offset;
432 
433 #  if !defined(VMS) && !defined(sgi) && !defined(__linux__)
434 static struct nlist nl[2];
435 #  endif /* Not VMS or sgi */
436 
437 #  ifdef SUNOS_5
438 static kvm_t *kd;
439 #  endif /* SUNOS_5 */
440 
441 # endif /* LOAD_AVE_TYPE && !HAVE_LIBKSTAT */
442 
443 /* Put the 1 minute, 5 minute and 15 minute load averages into the first
444  * NELEM elements of LOADAVG.  Return the number written (never more than 3,
445  * but may be less than NELEM), or -1 if an error occurred.
446  */
447 
getloadavg(double * loadavg,int nelem)448 static int getloadavg(double *loadavg, int nelem) {
449   int elem = 0;                 /* Return value.  */
450 
451 # ifdef NO_GET_LOAD_AVG
452 #  define LDAV_DONE
453   /* Set errno to zero to indicate that there was no particular error;
454      this function just can't work at all on this system.  */
455   errno = 0;
456   elem = -1;
457 # endif
458 
459 # if !defined (LDAV_DONE) && defined (HAVE_LIBKSTAT)
460 /* Use libkstat because we don't have to be root.  */
461 #  define LDAV_DONE
462   kstat_ctl_t *kc;
463   kstat_t *ksp;
464   kstat_named_t *kn;
465 
466   kc = kstat_open ();
467   if (kc == 0)
468     return -1;
469   ksp = kstat_lookup (kc, "unix", 0, "system_misc");
470   if (ksp == 0 )
471     return -1;
472   if (kstat_read (kc, ksp, 0) == -1)
473     return -1;
474 
475 
476   kn = kstat_data_lookup (ksp, "avenrun_1min");
477   if (kn == 0)
478     {
479       /* Return -1 if no load average information is available.  */
480       nelem = 0;
481       elem = -1;
482     }
483 
484   if (nelem >= 1)
485     loadavg[elem++] = (double) kn->value.ul/FSCALE;
486 
487   if (nelem >= 2)
488     {
489       kn = kstat_data_lookup (ksp, "avenrun_5min");
490       if (kn != 0)
491         {
492           loadavg[elem++] = (double) kn->value.ul/FSCALE;
493 
494           if (nelem >= 3)
495             {
496               kn = kstat_data_lookup (ksp, "avenrun_15min");
497               if (kn != 0)
498                 loadavg[elem++] = (double) kn->value.ul/FSCALE;
499             }
500         }
501     }
502 
503   kstat_close (kc);
504 # endif /* HAVE_LIBKSTAT */
505 
506 # if !defined (LDAV_DONE) && defined (hpux) && defined (HAVE_PSTAT_GETDYNAMIC)
507 /* Use pstat_getdynamic() because we don't have to be root.  */
508 #  define LDAV_DONE
509 #  undef LOAD_AVE_TYPE
510 
511   struct pst_dynamic dyn_info;
512   if (pstat_getdynamic (&dyn_info, sizeof (dyn_info), 0, 0) < 0)
513     return -1;
514   if (nelem > 0)
515     loadavg[elem++] = dyn_info.psd_avg_1_min;
516   if (nelem > 1)
517     loadavg[elem++] = dyn_info.psd_avg_5_min;
518   if (nelem > 2)
519     loadavg[elem++] = dyn_info.psd_avg_15_min;
520 
521 # endif /* hpux && HAVE_PSTAT_GETDYNAMIC */
522 
523 # if !defined (LDAV_DONE) && defined (__linux__)
524 #  define LDAV_DONE
525 #  undef LOAD_AVE_TYPE
526 
527 #  ifndef LINUX_LDAV_FILE
528 #   define LINUX_LDAV_FILE "/proc/loadavg"
529 #  endif
530 
531   char ldavgbuf[40];
532   double load_ave[3];
533   int fd, count;
534 
535   fd = open (LINUX_LDAV_FILE, O_RDONLY);
536   if (fd == -1)
537     return -1;
538   count = read (fd, ldavgbuf, 40);
539   (void) close (fd);
540   if (count <= 0)
541     return -1;
542 
543   count = sscanf (ldavgbuf, "%lf %lf %lf",
544                   &load_ave[0], &load_ave[1], &load_ave[2]);
545   if (count < 1)
546     return -1;
547 
548   for (elem = 0; elem < nelem && elem < count; elem++)
549     loadavg[elem] = load_ave[elem];
550 
551   return elem;
552 
553 # endif /* __linux__ */
554 
555 # if !defined (LDAV_DONE) && defined (__NetBSD__)
556 #  define LDAV_DONE
557 #  undef LOAD_AVE_TYPE
558 
559 #  ifndef NETBSD_LDAV_FILE
560 #   define NETBSD_LDAV_FILE "/kern/loadavg"
561 #  endif
562 
563   unsigned long int load_ave[3], scale;
564   int count;
565   FILE *fp;
566 
567   fp = fopen (NETBSD_LDAV_FILE, "r");
568   if (fp == NULL)
569     return -1;
570   count = fscanf (fp, "%lu %lu %lu %lu\n",
571                   &load_ave[0], &load_ave[1], &load_ave[2],
572                   &scale);
573   (void) fclose (fp);
574   if (count != 4)
575     return -1;
576 
577   for (elem = 0; elem < nelem; elem++)
578     loadavg[elem] = (double) load_ave[elem] / (double) scale;
579 
580   return elem;
581 
582 # endif /* __NetBSD__ */
583 
584 # if !defined (LDAV_DONE) && defined (NeXT)
585 #  define LDAV_DONE
586   /* The NeXT code was adapted from iscreen 3.2.  */
587 
588   host_t host;
589   struct processor_set_basic_info info;
590   unsigned info_count;
591 
592   /* We only know how to get the 1-minute average for this system,
593      so even if the caller asks for more than 1, we only return 1.  */
594 
595   if (!getloadavg_initialized)
596     {
597       if (processor_set_default (host_self (), &default_set) == KERN_SUCCESS)
598         getloadavg_initialized = 1;
599     }
600 
601   if (getloadavg_initialized)
602     {
603       info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
604       if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host,
605                               (processor_set_info_t) &info, &info_count)
606           != KERN_SUCCESS)
607         getloadavg_initialized = 0;
608       else
609         {
610           if (nelem > 0)
611             loadavg[elem++] = (double) info.load_average / LOAD_SCALE;
612         }
613     }
614 
615   if (!getloadavg_initialized)
616     return -1;
617 # endif /* NeXT */
618 
619 # if !defined (LDAV_DONE) && defined (UMAX)
620 #  define LDAV_DONE
621 /* UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not
622    have a /dev/kmem.  Information about the workings of the running kernel
623    can be gathered with inq_stats system calls.
624    We only know how to get the 1-minute average for this system.  */
625 
626   struct proc_summary proc_sum_data;
627   struct stat_descr proc_info;
628   double load;
629   register unsigned int i, j;
630 
631   if (cpus == 0)
632     {
633       register unsigned int c, i;
634       struct cpu_config conf;
635       struct stat_descr desc;
636 
637       desc.sd_next = 0;
638       desc.sd_subsys = SUBSYS_CPU;
639       desc.sd_type = CPUTYPE_CONFIG;
640       desc.sd_addr = (char *) &conf;
641       desc.sd_size = sizeof conf;
642 
643       if (inq_stats (1, &desc))
644         return -1;
645 
646       c = 0;
647       for (i = 0; i < conf.config_maxclass; ++i)
648         {
649           struct class_stats stats;
650           bzero ((char *) &stats, sizeof stats);
651 
652           desc.sd_type = CPUTYPE_CLASS;
653           desc.sd_objid = i;
654           desc.sd_addr = (char *) &stats;
655           desc.sd_size = sizeof stats;
656 
657           if (inq_stats (1, &desc))
658             return -1;
659 
660           c += stats.class_numcpus;
661         }
662       cpus = c;
663       samples = cpus < 2 ? 3 : (2 * cpus / 3);
664     }
665 
666   proc_info.sd_next = 0;
667   proc_info.sd_subsys = SUBSYS_PROC;
668   proc_info.sd_type = PROCTYPE_SUMMARY;
669   proc_info.sd_addr = (char *) &proc_sum_data;
670   proc_info.sd_size = sizeof (struct proc_summary);
671   proc_info.sd_sizeused = 0;
672 
673   if (inq_stats (1, &proc_info) != 0)
674     return -1;
675 
676   load = proc_sum_data.ps_nrunnable;
677   j = 0;
678   for (i = samples - 1; i > 0; --i)
679     {
680       load += proc_sum_data.ps_nrun[j];
681       if (j++ == PS_NRUNSIZE)
682         j = 0;
683     }
684 
685   if (nelem > 0)
686     loadavg[elem++] = load / samples / cpus;
687 # endif /* UMAX */
688 
689 # if !defined (LDAV_DONE) && defined (DGUX)
690 #  define LDAV_DONE
691   /* This call can return -1 for an error, but with good args
692      it's not supposed to fail.  The first argument is for no
693      apparent reason of type `long int *'.  */
694   dg_sys_info ((long int *) &load_info,
695                DG_SYS_INFO_LOAD_INFO_TYPE,
696                DG_SYS_INFO_LOAD_VERSION_0);
697 
698   if (nelem > 0)
699     loadavg[elem++] = load_info.one_minute;
700   if (nelem > 1)
701     loadavg[elem++] = load_info.five_minute;
702   if (nelem > 2)
703     loadavg[elem++] = load_info.fifteen_minute;
704 # endif /* DGUX */
705 
706 # if !defined (LDAV_DONE) && defined (apollo)
707 #  define LDAV_DONE
708 /* Apollo code from lisch@mentorg.com (Ray Lischner).
709 
710    This system call is not documented.  The load average is obtained as
711    three long integers, for the load average over the past minute,
712    five minutes, and fifteen minutes.  Each value is a scaled integer,
713    with 16 bits of integer part and 16 bits of fraction part.
714 
715    I'm not sure which operating system first supported this system call,
716    but I know that SR10.2 supports it.  */
717 
718   extern void proc1_$get_loadav ();
719   unsigned long load_ave[3];
720 
721   proc1_$get_loadav (load_ave);
722 
723   if (nelem > 0)
724     loadavg[elem++] = load_ave[0] / 65536.0;
725   if (nelem > 1)
726     loadavg[elem++] = load_ave[1] / 65536.0;
727   if (nelem > 2)
728     loadavg[elem++] = load_ave[2] / 65536.0;
729 # endif /* apollo */
730 
731 # if !defined (LDAV_DONE) && defined (OSF_MIPS)
732 #  define LDAV_DONE
733 
734   struct tbl_loadavg load_ave;
735   table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
736   loadavg[elem++]
737     = (load_ave.tl_lscale == 0
738        ? load_ave.tl_avenrun.d[0]
739        : (load_ave.tl_avenrun.l[0] / (double) load_ave.tl_lscale));
740 # endif /* OSF_MIPS */
741 
742 # if !defined (LDAV_DONE) && (defined (__MSDOS__) || defined (WINDOWS32))
743 #  define LDAV_DONE
744 
745   /* A faithful emulation is going to have to be saved for a rainy day.  */
746   for ( ; elem < nelem; elem++)
747     {
748       loadavg[elem] = 0.0;
749     }
750 # endif  /* __MSDOS__ || WINDOWS32 */
751 
752 # if !defined (LDAV_DONE) && defined (OSF_ALPHA)
753 #  define LDAV_DONE
754 
755   struct tbl_loadavg load_ave;
756   table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
757   for (elem = 0; elem < nelem; elem++)
758     loadavg[elem]
759       = (load_ave.tl_lscale == 0
760        ? load_ave.tl_avenrun.d[elem]
761        : (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale));
762 # endif /* OSF_ALPHA */
763 
764 # if !defined (LDAV_DONE) && defined (VMS)
765   /* VMS specific code -- read from the Load Ave driver.  */
766 
767   LOAD_AVE_TYPE load_ave[3];
768   static int getloadavg_initialized = 0;
769 #  ifdef eunice
770   struct
771   {
772     int dsc$w_length;
773     char *dsc$a_pointer;
774   } descriptor;
775 #  endif
776 
777   /* Ensure that there is a channel open to the load ave device.  */
778   if (!getloadavg_initialized)
779     {
780       /* Attempt to open the channel.  */
781 #  ifdef eunice
782       descriptor.dsc$w_length = 18;
783       descriptor.dsc$a_pointer = "$$VMS_LOAD_AVERAGE";
784 #  else
785       $DESCRIPTOR (descriptor, "LAV0:");
786 #  endif
787       if (sys$assign (&descriptor, &channel, 0, 0) & 1)
788         getloadavg_initialized = 1;
789     }
790 
791   /* Read the load average vector.  */
792   if (getloadavg_initialized
793       && !(sys$qiow (0, channel, IO$_READVBLK, 0, 0, 0,
794                      load_ave, 12, 0, 0, 0, 0) & 1))
795     {
796       sys$dassgn (channel);
797       getloadavg_initialized = 0;
798     }
799 
800   if (!getloadavg_initialized)
801     return -1;
802 # endif /* VMS */
803 
804 # if !defined (LDAV_DONE) && defined(LOAD_AVE_TYPE) && !defined(VMS)
805 
806   /* UNIX-specific code -- read the average from /dev/kmem.  */
807 
808 #  define LDAV_PRIVILEGED               /* This code requires special installation.  */
809 
810   LOAD_AVE_TYPE load_ave[3];
811 
812   /* Get the address of LDAV_SYMBOL.  */
813   if (offset == 0)
814     {
815 #  ifndef sgi
816 #   ifndef NLIST_STRUCT
817       strcpy (nl[0].n_name, LDAV_SYMBOL);
818       strcpy (nl[1].n_name, "");
819 #   else /* NLIST_STRUCT */
820 #    ifdef NLIST_NAME_UNION
821       nl[0].n_un.n_name = LDAV_SYMBOL;
822       nl[1].n_un.n_name = 0;
823 #    else /* not NLIST_NAME_UNION */
824       nl[0].n_name = LDAV_SYMBOL;
825       nl[1].n_name = 0;
826 #    endif /* not NLIST_NAME_UNION */
827 #   endif /* NLIST_STRUCT */
828 
829 #   ifndef SUNOS_5
830       if (
831 #    if !(defined (_AIX) && !defined (ps2))
832           nlist (KERNEL_FILE, nl)
833 #    else  /* _AIX */
834           knlist (nl, 1, sizeof (nl[0]))
835 #    endif
836           >= 0)
837           /* Omit "&& nl[0].n_type != 0 " -- it breaks on Sun386i.  */
838           {
839 #    ifdef FIXUP_KERNEL_SYMBOL_ADDR
840             FIXUP_KERNEL_SYMBOL_ADDR (nl);
841 #    endif
842             offset = nl[0].n_value;
843           }
844 #   endif /* !SUNOS_5 */
845 #  else  /* sgi */
846       int ldav_off;
847 
848       ldav_off = sysmp (MP_KERNADDR, MPKA_AVENRUN);
849       if (ldav_off != -1)
850         offset = (long) ldav_off & 0x7fffffff;
851 #  endif /* sgi */
852     }
853 
854   /* Make sure we have /dev/kmem open.  */
855   if (!getloadavg_initialized)
856     {
857 #  ifndef SUNOS_5
858       channel = open ("/dev/kmem", 0);
859       if (channel >= 0)
860         {
861           /* Set the channel to close on exec, so it does not
862              litter any child's descriptor table.  */
863 #   ifdef F_SETFD
864 #    ifndef FD_CLOEXEC
865 #     define FD_CLOEXEC 1
866 #    endif
867           (void) fcntl (channel, F_SETFD, FD_CLOEXEC);
868 #   endif
869           getloadavg_initialized = 1;
870         }
871 #  else /* SUNOS_5 */
872       /* We pass 0 for the kernel, corefile, and swapfile names
873          to use the currently running kernel.  */
874       kd = kvm_open (0, 0, 0, O_RDONLY, 0);
875       if (kd != 0)
876         {
877           /* nlist the currently running kernel.  */
878           kvm_nlist (kd, nl);
879           offset = nl[0].n_value;
880           getloadavg_initialized = 1;
881         }
882 #  endif /* SUNOS_5 */
883     }
884 
885   /* If we can, get the load average values.  */
886   if (offset && getloadavg_initialized)
887     {
888       /* Try to read the load.  */
889 #  ifndef SUNOS_5
890       if (lseek (channel, offset, 0) == -1L
891           || read (channel, (char *) load_ave, sizeof (load_ave))
892           != sizeof (load_ave))
893         {
894           close (channel);
895           getloadavg_initialized = 0;
896         }
897 #  else  /* SUNOS_5 */
898       if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave))
899           != sizeof (load_ave))
900         {
901           kvm_close (kd);
902           getloadavg_initialized = 0;
903         }
904 #  endif /* SUNOS_5 */
905     }
906 
907   if (offset == 0 || !getloadavg_initialized)
908     return -1;
909 # endif /* LOAD_AVE_TYPE and not VMS */
910 
911 # if !defined (LDAV_DONE) && defined (LOAD_AVE_TYPE) /* Including VMS.  */
912   if (nelem > 0)
913     loadavg[elem++] = LDAV_CVT (load_ave[0]);
914   if (nelem > 1)
915     loadavg[elem++] = LDAV_CVT (load_ave[1]);
916   if (nelem > 2)
917     loadavg[elem++] = LDAV_CVT (load_ave[2]);
918 
919 #  define LDAV_DONE
920 # endif /* !LDAV_DONE && LOAD_AVE_TYPE */
921 
922 # ifdef LDAV_DONE
923   return elem;
924 # else
925   /* Set errno to zero to indicate that there was no particular error;
926      this function just can't work at all on this system.  */
927   errno = 0;
928   return -1;
929 # endif
930 }
931 
932 #endif /* !HAVE_GETLOADAVG */
933 
934 module load_module;
935 
load_get_system_load(void)936 static double load_get_system_load(void) {
937   int res;
938   double loadavg = -1.0;
939 
940   /* It is necessary on some platforms (such as Solaris) to have root
941    * privs when doing this, as the information is determined by reading
942    * the image of the running kernel (yikes!)
943    */
944   PRIVS_ROOT
945   res = getloadavg(&loadavg, 1);
946   PRIVS_RELINQUISH
947 
948   /* Return the default value if we did not receive the expected number
949    * of elements from getloadavg().
950    */
951   if (res != 1)
952     return -1.0;
953 
954   return loadavg;
955 }
956 
957 /* Configuration handlers
958  */
959 
960 /* usage: MaxLoad max [mesg] */
set_maxload(cmd_rec * cmd)961 MODRET set_maxload(cmd_rec *cmd) {
962   double loadval = 0.0;
963   config_rec *c = NULL;
964 
965   if (cmd->argc-1 < 1 || cmd->argc-1 > 2)
966     CONF_ERROR(cmd, "incorrect number of parameters");
967 
968   CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
969 
970   if (strcasecmp(cmd->argv[1], "none") == 0)
971     loadval = -1.0;
972   else {
973     loadval = atof(cmd->argv[1]);
974     if (loadval < 0.0)
975       CONF_ERROR(cmd, "positive load limit required");
976   }
977 
978   c = add_config_param(cmd->argv[0], cmd->argc-1, NULL);
979   c->argv[0] = pcalloc(c->pool, sizeof(double));
980 
981   if (loadval < 0.0)
982     c->argv[0] = NULL;
983 
984   else
985     *((double *) c->argv[0]) = loadval;
986 
987   if (cmd->argc-1 == 2) {
988     c->argv[1] = pcalloc(c->pool, sizeof(char *));
989     c->argv[1] = pstrdup(c->pool, cmd->argv[2]);
990   }
991 
992   return PR_HANDLED(cmd);
993 }
994 
995 /* Initialization functions
996  */
997 
load_sess_init(void)998 static int load_sess_init(void) {
999   config_rec *c = NULL;
1000   double max_load = 0.0, curr_load = 0.0;
1001   char curr_load_str[16], max_load_str[16];
1002 
1003   /* Lookup any configured load limit. */
1004   c = find_config(main_server->conf, CONF_PARAM, "MaxLoad", FALSE);
1005   if (!c)
1006     return 0;
1007 
1008   /* If the config_rec is present, but argv[0] is NULL, do nothing */
1009   if (!c->argv[0])
1010     return 0;
1011   max_load = *((double *) c->argv[0]);
1012 
1013   curr_load = load_get_system_load();
1014   if (curr_load < 0) {
1015     pr_log_pri(PR_LOG_NOTICE,
1016       "notice: unable to determine system load average: %s", strerror(errno));
1017     return 0;
1018   }
1019 
1020   pr_log_debug(DEBUG5, MOD_LOAD_VERSION ": current system load: %.2f",
1021     curr_load);
1022 
1023   if (curr_load >= max_load) {
1024     pr_log_pri(PR_LOG_NOTICE, MOD_LOAD_VERSION
1025       ": MaxLoad (%.2f) reached: connection denied", max_load);
1026 
1027     if (c->argc == 2) {
1028       pr_response_send(R_421, "%s", (const char *) c->argv[1]);
1029 
1030     } else {
1031       pr_response_send(R_421, _("System busy, try again later"));
1032     }
1033 
1034     pr_session_disconnect(&load_module, PR_SESS_DISCONNECT_MODULE_ACL,
1035       "MaxLoad");
1036   }
1037 
1038   /* Register some Variable entries for showing the system load. */
1039   memset(curr_load_str, '\0', sizeof(curr_load_str));
1040   pr_snprintf(curr_load_str, sizeof(curr_load_str)-1, "%.2f", curr_load);
1041   if (pr_var_set(session.pool, "%{mod_load.curr_load}",
1042       "Current system load average", PR_VAR_TYPE_STR, curr_load_str, NULL,
1043       0) < 0) {
1044     pr_log_debug(DEBUG1, MOD_LOAD_VERSION
1045       ": error setting %%{mod_load.curr_load} variable: %s", strerror(errno));
1046   }
1047 
1048   memset(max_load_str, '\0', sizeof(max_load_str));
1049   pr_snprintf(max_load_str, sizeof(max_load_str)-1, "%.2f", max_load);
1050   if (pr_var_set(session.pool, "%{mod_load.max_load}",
1051       "Maximum system load average", PR_VAR_TYPE_STR, max_load_str, NULL,
1052       0) < 0) {
1053     pr_log_debug(DEBUG1, MOD_LOAD_VERSION
1054       ": error setting %%{mod_load.max_load} variable: %s", strerror(errno));
1055   }
1056 
1057   return 0;
1058 }
1059 
1060 /* Module API tables
1061  */
1062 
1063 static conftable load_conftab[] = {
1064   { "MaxLoad",		set_maxload,		NULL },
1065   { NULL }
1066 };
1067 
1068 module load_module = {
1069   NULL, NULL,
1070 
1071   /* Module API version 2.0 */
1072   0x20,
1073 
1074   /* Module name */
1075   "load",
1076 
1077   /* Module configuration handler table */
1078   load_conftab,
1079 
1080   /* Module command table */
1081   NULL,
1082 
1083   /* Module authentication handler table */
1084   NULL,
1085 
1086   /* Module initialization function */
1087   NULL,
1088 
1089   /* Session initialization function */
1090   load_sess_init,
1091 
1092   /* Module version */
1093   MOD_LOAD_VERSION
1094 };
1095