pam_limits.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215
  1. /*
  2. * pam_limits - impose resource limits when opening a user session
  3. *
  4. * 1.6 - modified for PLD (added process priority settings)
  5. * by Marcin Korzonek <mkorz@shadow.eu.org>
  6. * 1.5 - Elliot Lee's "max system logins patch"
  7. * 1.4 - addressed bug in configuration file parser
  8. * 1.3 - modified the configuration file format
  9. * 1.2 - added 'debug' and 'conf=' arguments
  10. * 1.1 - added @group support
  11. * 1.0 - initial release - Linux ONLY
  12. *
  13. * See end for Copyright information
  14. */
  15. #if !defined(linux) && !defined(__linux)
  16. #warning THIS CODE IS KNOWN TO WORK ONLY ON LINUX !!!
  17. #endif
  18. #include "config.h"
  19. #include <stdio.h>
  20. #include <unistd.h>
  21. #include <string.h>
  22. #include <ctype.h>
  23. #include <stdlib.h>
  24. #include <errno.h>
  25. #include <syslog.h>
  26. #include <stdarg.h>
  27. #include <signal.h>
  28. #include <sys/prctl.h>
  29. #include <sys/types.h>
  30. #include <sys/stat.h>
  31. #include <sys/resource.h>
  32. #include <limits.h>
  33. #include <glob.h>
  34. #include <utmp.h>
  35. #ifndef UT_USER /* some systems have ut_name instead of ut_user */
  36. #define UT_USER ut_user
  37. #endif
  38. #include <grp.h>
  39. #include <pwd.h>
  40. #include <locale.h>
  41. #ifdef HAVE_LIBAUDIT
  42. #include <libaudit.h>
  43. #endif
  44. /* Module defines */
  45. #define LINE_LENGTH 1024
  46. #define LIMITS_DEF_USER 0 /* limit was set by a user entry */
  47. #define LIMITS_DEF_GROUP 1 /* limit was set by a group entry */
  48. #define LIMITS_DEF_ALLGROUP 2 /* limit was set by a group entry */
  49. #define LIMITS_DEF_ALL 3 /* limit was set by an all entry */
  50. #define LIMITS_DEF_DEFAULT 4 /* limit was set by a default entry */
  51. #define LIMITS_DEF_KERNEL 5 /* limit was set from /proc/1/limits */
  52. #define LIMITS_DEF_NONE 6 /* this limit was not set yet */
  53. #define LIMIT_RANGE_ERR -1 /* error in specified uid/gid range */
  54. #define LIMIT_RANGE_NONE 0 /* no range specified */
  55. #define LIMIT_RANGE_ONE 1 /* exact uid/gid specified (:max_uid)*/
  56. #define LIMIT_RANGE_MIN 2 /* only minimum uid/gid specified (min_uid:) */
  57. #define LIMIT_RANGE_MM 3 /* both min and max uid/gid specified (min_uid:max_uid) */
  58. static const char *limits_def_names[] = {
  59. "USER",
  60. "GROUP",
  61. "ALLGROUP",
  62. "ALL",
  63. "DEFAULT",
  64. "KERNEL",
  65. "NONE",
  66. NULL
  67. };
  68. struct user_limits_struct {
  69. int supported;
  70. int src_soft;
  71. int src_hard;
  72. struct rlimit limit;
  73. };
  74. /* internal data */
  75. struct pam_limit_s {
  76. int login_limit; /* the max logins limit */
  77. int login_limit_def; /* which entry set the login limit */
  78. int flag_numsyslogins; /* whether to limit logins only for a
  79. specific user or to count all logins */
  80. int priority; /* the priority to run user process with */
  81. int nonewprivs; /* whether to prctl(PR_SET_NO_NEW_PRIVS) */
  82. struct user_limits_struct limits[RLIM_NLIMITS];
  83. const char *conf_file;
  84. int utmp_after_pam_call;
  85. char login_group[LINE_LENGTH];
  86. };
  87. #define LIMIT_LOGIN RLIM_NLIMITS+1
  88. #define LIMIT_NUMSYSLOGINS RLIM_NLIMITS+2
  89. #define LIMIT_PRI RLIM_NLIMITS+3
  90. #define LIMIT_NONEWPRIVS RLIM_NLIMITS+4
  91. #define LIMIT_SOFT 1
  92. #define LIMIT_HARD 2
  93. #include <security/pam_modules.h>
  94. #include <security/_pam_macros.h>
  95. #include <security/pam_modutil.h>
  96. #include <security/pam_ext.h>
  97. #include "pam_inline.h"
  98. /* argument parsing */
  99. #define PAM_DEBUG_ARG 0x0001
  100. #define PAM_UTMP_EARLY 0x0004
  101. #define PAM_NO_AUDIT 0x0008
  102. #define PAM_SET_ALL 0x0010
  103. /* Limits from globbed files. */
  104. #define LIMITS_CONF_GLOB LIMITS_FILE_DIR
  105. #define CONF_FILE (pl->conf_file != NULL)?pl->conf_file:LIMITS_FILE
  106. static int
  107. _pam_parse (const pam_handle_t *pamh, int argc, const char **argv,
  108. struct pam_limit_s *pl)
  109. {
  110. int ctrl=0;
  111. /* step through arguments */
  112. for (ctrl=0; argc-- > 0; ++argv) {
  113. const char *str;
  114. /* generic options */
  115. if (!strcmp(*argv,"debug")) {
  116. ctrl |= PAM_DEBUG_ARG;
  117. } else if ((str = pam_str_skip_prefix(*argv, "conf=")) != NULL) {
  118. pl->conf_file = str;
  119. } else if (!strcmp(*argv,"utmp_early")) {
  120. ctrl |= PAM_UTMP_EARLY;
  121. } else if (!strcmp(*argv,"noaudit")) {
  122. ctrl |= PAM_NO_AUDIT;
  123. } else if (!strcmp(*argv,"set_all")) {
  124. ctrl |= PAM_SET_ALL;
  125. } else {
  126. pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
  127. }
  128. }
  129. return ctrl;
  130. }
  131. static const char *
  132. rlimit2str (int i)
  133. {
  134. switch (i) {
  135. case RLIMIT_CPU:
  136. return "cpu";
  137. break;
  138. case RLIMIT_FSIZE:
  139. return "fsize";
  140. break;
  141. case RLIMIT_DATA:
  142. return "data";
  143. break;
  144. case RLIMIT_STACK:
  145. return "stack";
  146. break;
  147. case RLIMIT_CORE:
  148. return "core";
  149. break;
  150. case RLIMIT_RSS:
  151. return "rss";
  152. break;
  153. case RLIMIT_NPROC:
  154. return "nproc";
  155. break;
  156. case RLIMIT_NOFILE:
  157. return "nofile";
  158. break;
  159. case RLIMIT_MEMLOCK:
  160. return "memlock";
  161. break;
  162. #ifdef RLIMIT_AS
  163. case RLIMIT_AS:
  164. return "as";
  165. break;
  166. #endif
  167. #ifdef RLIMIT_LOCKS
  168. case RLIMIT_LOCKS:
  169. return "locks";
  170. break;
  171. #endif
  172. #ifdef RLIMIT_SIGPENDING
  173. case RLIMIT_SIGPENDING:
  174. return "sigpending";
  175. break;
  176. #endif
  177. #ifdef RLIMIT_MSGQUEUE
  178. case RLIMIT_MSGQUEUE:
  179. return "msgqueue";
  180. break;
  181. #endif
  182. #ifdef RLIMIT_NICE
  183. case RLIMIT_NICE:
  184. return "nice";
  185. break;
  186. #endif
  187. #ifdef RLIMIT_RTPRIO
  188. case RLIMIT_RTPRIO:
  189. return "rtprio";
  190. break;
  191. #endif
  192. default:
  193. return "UNKNOWN";
  194. break;
  195. }
  196. }
  197. #define LIMITED_OK 0 /* limit setting appeared to work */
  198. #define LIMIT_ERR 1 /* error setting a limit */
  199. #define LOGIN_ERR 2 /* too many logins err */
  200. /* Counts the number of user logins and check against the limit*/
  201. static int
  202. check_logins (pam_handle_t *pamh, const char *name, int limit, int ctrl,
  203. struct pam_limit_s *pl)
  204. {
  205. struct utmp *ut;
  206. int count;
  207. if (ctrl & PAM_DEBUG_ARG) {
  208. pam_syslog(pamh, LOG_DEBUG,
  209. "checking logins for '%s' (maximum of %d)", name, limit);
  210. }
  211. if (limit < 0)
  212. return 0; /* no limits imposed */
  213. if (limit == 0) /* maximum 0 logins ? */ {
  214. pam_syslog(pamh, LOG_WARNING, "No logins allowed for '%s'", name);
  215. return LOGIN_ERR;
  216. }
  217. setutent();
  218. /* Because there is no definition about when an application
  219. actually adds a utmp entry, some applications bizarrely do the
  220. utmp call before the have PAM authenticate them to the system:
  221. you're logged it, sort of...? Anyway, you can use the
  222. "utmp_early" module argument in your PAM config file to make
  223. allowances for this sort of problem. (There should be a PAM
  224. standard for this, since if a module wants to actually map a
  225. username then any early utmp entry will be for the unmapped
  226. name = broken.) */
  227. if (ctrl & PAM_UTMP_EARLY) {
  228. count = 0;
  229. } else {
  230. count = 1;
  231. }
  232. while((ut = getutent())) {
  233. #ifdef USER_PROCESS
  234. if (ut->ut_type != USER_PROCESS) {
  235. continue;
  236. }
  237. #endif
  238. if (ut->UT_USER[0] == '\0') {
  239. continue;
  240. }
  241. if (!pl->flag_numsyslogins) {
  242. char user[sizeof(ut->UT_USER) + 1];
  243. user[0] = '\0';
  244. strncat(user, ut->UT_USER, sizeof(ut->UT_USER));
  245. if (((pl->login_limit_def == LIMITS_DEF_USER)
  246. || (pl->login_limit_def == LIMITS_DEF_GROUP)
  247. || (pl->login_limit_def == LIMITS_DEF_DEFAULT))
  248. && strcmp(name, user) != 0) {
  249. continue;
  250. }
  251. if ((pl->login_limit_def == LIMITS_DEF_ALLGROUP)
  252. && !pam_modutil_user_in_group_nam_nam(pamh, user, pl->login_group)) {
  253. continue;
  254. }
  255. if (kill(ut->ut_pid, 0) == -1 && errno == ESRCH) {
  256. /* process does not exist anymore */
  257. pam_syslog(pamh, LOG_INFO,
  258. "Stale utmp entry (pid %d) for '%s' ignored",
  259. ut->ut_pid, user);
  260. continue;
  261. }
  262. }
  263. if (++count > limit) {
  264. break;
  265. }
  266. }
  267. endutent();
  268. if (count > limit) {
  269. if (name) {
  270. pam_syslog(pamh, LOG_NOTICE,
  271. "Too many logins (max %d) for %s", limit, name);
  272. } else {
  273. pam_syslog(pamh, LOG_NOTICE, "Too many system logins (max %d)", limit);
  274. }
  275. return LOGIN_ERR;
  276. }
  277. return 0;
  278. }
  279. static const char *lnames[RLIM_NLIMITS] = {
  280. [RLIMIT_CPU] = "Max cpu time",
  281. [RLIMIT_FSIZE] = "Max file size",
  282. [RLIMIT_DATA] = "Max data size",
  283. [RLIMIT_STACK] = "Max stack size",
  284. [RLIMIT_CORE] = "Max core file size",
  285. [RLIMIT_RSS] = "Max resident set",
  286. [RLIMIT_NPROC] = "Max processes",
  287. [RLIMIT_NOFILE] = "Max open files",
  288. [RLIMIT_MEMLOCK] = "Max locked memory",
  289. #ifdef RLIMIT_AS
  290. [RLIMIT_AS] = "Max address space",
  291. #endif
  292. #ifdef RLIMIT_LOCKS
  293. [RLIMIT_LOCKS] = "Max file locks",
  294. #endif
  295. #ifdef RLIMIT_SIGPENDING
  296. [RLIMIT_SIGPENDING] = "Max pending signals",
  297. #endif
  298. #ifdef RLIMIT_MSGQUEUE
  299. [RLIMIT_MSGQUEUE] = "Max msgqueue size",
  300. #endif
  301. #ifdef RLIMIT_NICE
  302. [RLIMIT_NICE] = "Max nice priority",
  303. #endif
  304. #ifdef RLIMIT_RTPRIO
  305. [RLIMIT_RTPRIO] = "Max realtime priority",
  306. #endif
  307. #ifdef RLIMIT_RTTIME
  308. [RLIMIT_RTTIME] = "Max realtime timeout",
  309. #endif
  310. };
  311. static int str2rlimit(char *name) {
  312. int i;
  313. if (!name || *name == '\0')
  314. return -1;
  315. for(i = 0; i < RLIM_NLIMITS; i++) {
  316. if (strcmp(name, lnames[i]) == 0) return i;
  317. }
  318. return -1;
  319. }
  320. static rlim_t str2rlim_t(char *value) {
  321. unsigned long long rlimit = 0;
  322. if (!value) return (rlim_t)rlimit;
  323. if (strcmp(value, "unlimited") == 0) {
  324. return RLIM_INFINITY;
  325. }
  326. rlimit = strtoull(value, NULL, 10);
  327. return (rlim_t)rlimit;
  328. }
  329. #define LIMITS_SKIP_WHITESPACE { \
  330. /* step backwards over spaces */ \
  331. pos--; \
  332. while (pos && line[pos] == ' ') pos--; \
  333. if (!pos) continue; \
  334. line[pos+1] = '\0'; \
  335. }
  336. #define LIMITS_MARK_ITEM(item) { \
  337. /* step backwards over non-spaces */ \
  338. pos--; \
  339. while (pos && line[pos] != ' ') pos--; \
  340. if (!pos) continue; \
  341. item = line + pos + 1; \
  342. }
  343. static void parse_kernel_limits(pam_handle_t *pamh, struct pam_limit_s *pl, int ctrl)
  344. {
  345. int i, maxlen = 0;
  346. FILE *limitsfile;
  347. const char *proclimits = "/proc/1/limits";
  348. char line[256];
  349. char *hard, *soft, *name;
  350. if (!(limitsfile = fopen(proclimits, "r"))) {
  351. pam_syslog(pamh, LOG_WARNING, "Could not read %s (%s), using PAM defaults", proclimits, strerror(errno));
  352. return;
  353. }
  354. while (fgets(line, 256, limitsfile)) {
  355. int pos = strlen(line);
  356. if (pos < 2) continue;
  357. /* drop trailing newline */
  358. if (line[pos-1] == '\n') {
  359. pos--;
  360. line[pos] = '\0';
  361. }
  362. /* determine formatting boundary of limits report */
  363. if (!maxlen && pam_str_skip_prefix(line, "Limit") != NULL) {
  364. maxlen = pos;
  365. continue;
  366. }
  367. if (pos == maxlen) {
  368. /* step backwards over "Units" name */
  369. LIMITS_SKIP_WHITESPACE;
  370. LIMITS_MARK_ITEM(hard); /* not a typo, units unused */
  371. }
  372. /* step backwards over "Hard Limit" value */
  373. LIMITS_SKIP_WHITESPACE;
  374. LIMITS_MARK_ITEM(hard);
  375. /* step backwards over "Soft Limit" value */
  376. LIMITS_SKIP_WHITESPACE;
  377. LIMITS_MARK_ITEM(soft);
  378. /* step backwards over name of limit */
  379. LIMITS_SKIP_WHITESPACE;
  380. name = line;
  381. i = str2rlimit(name);
  382. if (i < 0 || i >= RLIM_NLIMITS) {
  383. if (ctrl & PAM_DEBUG_ARG)
  384. pam_syslog(pamh, LOG_DEBUG, "Unknown kernel rlimit '%s' ignored", name);
  385. continue;
  386. }
  387. pl->limits[i].limit.rlim_cur = str2rlim_t(soft);
  388. pl->limits[i].limit.rlim_max = str2rlim_t(hard);
  389. pl->limits[i].src_soft = LIMITS_DEF_KERNEL;
  390. pl->limits[i].src_hard = LIMITS_DEF_KERNEL;
  391. }
  392. fclose(limitsfile);
  393. }
  394. static int init_limits(pam_handle_t *pamh, struct pam_limit_s *pl, int ctrl)
  395. {
  396. int i;
  397. int retval = PAM_SUCCESS;
  398. D(("called."));
  399. for(i = 0; i < RLIM_NLIMITS; i++) {
  400. int r = getrlimit(i, &pl->limits[i].limit);
  401. if (r == -1) {
  402. pl->limits[i].supported = 0;
  403. if (errno != EINVAL) {
  404. retval = !PAM_SUCCESS;
  405. }
  406. } else {
  407. pl->limits[i].supported = 1;
  408. pl->limits[i].src_soft = LIMITS_DEF_NONE;
  409. pl->limits[i].src_hard = LIMITS_DEF_NONE;
  410. }
  411. }
  412. #ifdef __linux__
  413. if (ctrl & PAM_SET_ALL) {
  414. parse_kernel_limits(pamh, pl, ctrl);
  415. for(i = 0; i < RLIM_NLIMITS; i++) {
  416. if (pl->limits[i].supported &&
  417. (pl->limits[i].src_soft == LIMITS_DEF_NONE ||
  418. pl->limits[i].src_hard == LIMITS_DEF_NONE)) {
  419. pam_syslog(pamh, LOG_WARNING, "Did not find kernel RLIMIT for %s, using PAM default", rlimit2str(i));
  420. }
  421. }
  422. }
  423. #endif
  424. errno = 0;
  425. pl->priority = getpriority (PRIO_PROCESS, 0);
  426. if (pl->priority == -1 && errno != 0)
  427. retval = !PAM_SUCCESS;
  428. pl->login_limit = -2;
  429. pl->login_limit_def = LIMITS_DEF_NONE;
  430. return retval;
  431. }
  432. /*
  433. * Read the contents of <pathname> and return it in *valuep
  434. * return 1 if conversion succeeds, result is in *valuep
  435. * return 0 if conversion fails, *valuep is untouched.
  436. */
  437. static int
  438. value_from_file(const char *pathname, rlim_t *valuep)
  439. {
  440. char buf[128];
  441. FILE *fp;
  442. int retval;
  443. retval = 0;
  444. if ((fp = fopen(pathname, "r")) != NULL) {
  445. if (fgets(buf, sizeof(buf), fp) != NULL) {
  446. char *endptr;
  447. unsigned long long value;
  448. errno = 0;
  449. value = strtoull(buf, &endptr, 10);
  450. if (endptr != buf &&
  451. (value != ULLONG_MAX || errno == 0) &&
  452. (unsigned long long) (rlim_t) value == value) {
  453. *valuep = (rlim_t) value;
  454. retval = 1;
  455. }
  456. }
  457. fclose(fp);
  458. }
  459. return retval;
  460. }
  461. static void
  462. process_limit (const pam_handle_t *pamh, int source, const char *lim_type,
  463. const char *lim_item, const char *lim_value,
  464. int ctrl, struct pam_limit_s *pl)
  465. {
  466. int limit_item;
  467. int limit_type = 0;
  468. int int_value = 0;
  469. rlim_t rlimit_value = 0;
  470. char *endptr;
  471. const char *value_orig = lim_value;
  472. if (ctrl & PAM_DEBUG_ARG)
  473. pam_syslog(pamh, LOG_DEBUG, "%s: processing %s %s %s for %s",
  474. __FUNCTION__, lim_type, lim_item, lim_value,
  475. limits_def_names[source]);
  476. if (strcmp(lim_item, "cpu") == 0)
  477. limit_item = RLIMIT_CPU;
  478. else if (strcmp(lim_item, "fsize") == 0)
  479. limit_item = RLIMIT_FSIZE;
  480. else if (strcmp(lim_item, "data") == 0)
  481. limit_item = RLIMIT_DATA;
  482. else if (strcmp(lim_item, "stack") == 0)
  483. limit_item = RLIMIT_STACK;
  484. else if (strcmp(lim_item, "core") == 0)
  485. limit_item = RLIMIT_CORE;
  486. else if (strcmp(lim_item, "rss") == 0)
  487. limit_item = RLIMIT_RSS;
  488. else if (strcmp(lim_item, "nproc") == 0)
  489. limit_item = RLIMIT_NPROC;
  490. else if (strcmp(lim_item, "nofile") == 0)
  491. limit_item = RLIMIT_NOFILE;
  492. else if (strcmp(lim_item, "memlock") == 0)
  493. limit_item = RLIMIT_MEMLOCK;
  494. #ifdef RLIMIT_AS
  495. else if (strcmp(lim_item, "as") == 0)
  496. limit_item = RLIMIT_AS;
  497. #endif /*RLIMIT_AS*/
  498. #ifdef RLIMIT_LOCKS
  499. else if (strcmp(lim_item, "locks") == 0)
  500. limit_item = RLIMIT_LOCKS;
  501. #endif
  502. #ifdef RLIMIT_SIGPENDING
  503. else if (strcmp(lim_item, "sigpending") == 0)
  504. limit_item = RLIMIT_SIGPENDING;
  505. #endif
  506. #ifdef RLIMIT_MSGQUEUE
  507. else if (strcmp(lim_item, "msgqueue") == 0)
  508. limit_item = RLIMIT_MSGQUEUE;
  509. #endif
  510. #ifdef RLIMIT_NICE
  511. else if (strcmp(lim_item, "nice") == 0)
  512. limit_item = RLIMIT_NICE;
  513. #endif
  514. #ifdef RLIMIT_RTPRIO
  515. else if (strcmp(lim_item, "rtprio") == 0)
  516. limit_item = RLIMIT_RTPRIO;
  517. #endif
  518. else if (strcmp(lim_item, "maxlogins") == 0) {
  519. limit_item = LIMIT_LOGIN;
  520. pl->flag_numsyslogins = 0;
  521. } else if (strcmp(lim_item, "maxsyslogins") == 0) {
  522. limit_item = LIMIT_NUMSYSLOGINS;
  523. pl->flag_numsyslogins = 1;
  524. } else if (strcmp(lim_item, "priority") == 0) {
  525. limit_item = LIMIT_PRI;
  526. } else if (strcmp(lim_item, "nonewprivs") == 0) {
  527. limit_item = LIMIT_NONEWPRIVS;
  528. } else {
  529. pam_syslog(pamh, LOG_DEBUG, "unknown limit item '%s'", lim_item);
  530. return;
  531. }
  532. if (strcmp(lim_type,"soft")==0)
  533. limit_type=LIMIT_SOFT;
  534. else if (strcmp(lim_type, "hard")==0)
  535. limit_type=LIMIT_HARD;
  536. else if (strcmp(lim_type,"-")==0)
  537. limit_type=LIMIT_SOFT | LIMIT_HARD;
  538. else if (limit_item != LIMIT_LOGIN && limit_item != LIMIT_NUMSYSLOGINS
  539. && limit_item != LIMIT_NONEWPRIVS) {
  540. pam_syslog(pamh, LOG_DEBUG, "unknown limit type '%s'", lim_type);
  541. return;
  542. }
  543. if (limit_item == LIMIT_NONEWPRIVS) {
  544. /* just require a bool-style 0 or 1 */
  545. if (strcmp(lim_value, "0") == 0) {
  546. int_value = 0;
  547. } else if (strcmp(lim_value, "1") == 0) {
  548. int_value = 1;
  549. } else {
  550. pam_syslog(pamh, LOG_DEBUG,
  551. "wrong limit value '%s' for limit type '%s'",
  552. lim_value, lim_type);
  553. }
  554. } else if (limit_item != LIMIT_PRI
  555. #ifdef RLIMIT_NICE
  556. && limit_item != RLIMIT_NICE
  557. #endif
  558. && (strcmp(lim_value, "-1") == 0
  559. || strcmp(lim_value, "-") == 0 || strcmp(lim_value, "unlimited") == 0
  560. || strcmp(lim_value, "infinity") == 0)) {
  561. int_value = -1;
  562. rlimit_value = RLIM_INFINITY;
  563. } else if (limit_item == LIMIT_PRI || limit_item == LIMIT_LOGIN ||
  564. #ifdef RLIMIT_NICE
  565. limit_item == RLIMIT_NICE ||
  566. #endif
  567. limit_item == LIMIT_NUMSYSLOGINS) {
  568. long temp;
  569. temp = strtol (lim_value, &endptr, 10);
  570. temp = temp < INT_MAX ? temp : INT_MAX;
  571. int_value = temp > INT_MIN ? temp : INT_MIN;
  572. if (int_value == 0 && value_orig == endptr) {
  573. pam_syslog(pamh, LOG_DEBUG,
  574. "wrong limit value '%s' for limit type '%s'",
  575. lim_value, lim_type);
  576. return;
  577. }
  578. } else {
  579. #ifdef __USE_FILE_OFFSET64
  580. rlimit_value = strtoull (lim_value, &endptr, 10);
  581. #else
  582. rlimit_value = strtoul (lim_value, &endptr, 10);
  583. #endif
  584. if (rlimit_value == 0 && value_orig == endptr) {
  585. pam_syslog(pamh, LOG_DEBUG,
  586. "wrong limit value '%s' for limit type '%s'",
  587. lim_value, lim_type);
  588. return;
  589. }
  590. }
  591. /* one more special case when limiting logins */
  592. if ((source == LIMITS_DEF_ALL || source == LIMITS_DEF_ALLGROUP)
  593. && (limit_item != LIMIT_LOGIN)) {
  594. if (ctrl & PAM_DEBUG_ARG)
  595. pam_syslog(pamh, LOG_DEBUG,
  596. "'%%' domain valid for maxlogins type only");
  597. return;
  598. }
  599. switch(limit_item) {
  600. case RLIMIT_CPU:
  601. if (rlimit_value != RLIM_INFINITY)
  602. {
  603. if (rlimit_value >= RLIM_INFINITY/60)
  604. rlimit_value = RLIM_INFINITY;
  605. else
  606. rlimit_value *= 60;
  607. }
  608. break;
  609. case RLIMIT_FSIZE:
  610. case RLIMIT_DATA:
  611. case RLIMIT_STACK:
  612. case RLIMIT_CORE:
  613. case RLIMIT_RSS:
  614. case RLIMIT_MEMLOCK:
  615. #ifdef RLIMIT_AS
  616. case RLIMIT_AS:
  617. #endif
  618. if (rlimit_value != RLIM_INFINITY)
  619. {
  620. if (rlimit_value >= RLIM_INFINITY/1024)
  621. rlimit_value = RLIM_INFINITY;
  622. else
  623. rlimit_value *= 1024;
  624. }
  625. break;
  626. #ifdef RLIMIT_NICE
  627. case RLIMIT_NICE:
  628. if (int_value > 19)
  629. int_value = 19;
  630. if (int_value < -20)
  631. int_value = -20;
  632. rlimit_value = 20 - int_value;
  633. break;
  634. #endif
  635. case RLIMIT_NOFILE:
  636. /*
  637. * If nofile is to be set to "unlimited", try to set it to
  638. * the value in /proc/sys/fs/nr_open instead.
  639. */
  640. if (rlimit_value == RLIM_INFINITY) {
  641. if (!value_from_file("/proc/sys/fs/nr_open", &rlimit_value))
  642. pam_syslog(pamh, LOG_WARNING,
  643. "Cannot set \"nofile\" to a sensible value");
  644. else if (ctrl & PAM_DEBUG_ARG)
  645. pam_syslog(pamh, LOG_DEBUG, "Setting \"nofile\" limit to %llu",
  646. (unsigned long long) rlimit_value);
  647. }
  648. break;
  649. }
  650. if ( (limit_item != LIMIT_LOGIN)
  651. && (limit_item != LIMIT_NUMSYSLOGINS)
  652. && (limit_item != LIMIT_PRI)
  653. && (limit_item != LIMIT_NONEWPRIVS) ) {
  654. if (limit_type & LIMIT_SOFT) {
  655. if (pl->limits[limit_item].src_soft < source) {
  656. return;
  657. } else {
  658. pl->limits[limit_item].limit.rlim_cur = rlimit_value;
  659. pl->limits[limit_item].src_soft = source;
  660. }
  661. }
  662. if (limit_type & LIMIT_HARD) {
  663. if (pl->limits[limit_item].src_hard < source) {
  664. return;
  665. } else {
  666. pl->limits[limit_item].limit.rlim_max = rlimit_value;
  667. pl->limits[limit_item].src_hard = source;
  668. }
  669. }
  670. } else {
  671. /* recent kernels support negative priority limits (=raise priority) */
  672. if (limit_item == LIMIT_PRI) {
  673. pl->priority = int_value;
  674. } else if (limit_item == LIMIT_NONEWPRIVS) {
  675. pl->nonewprivs = int_value;
  676. } else {
  677. if (pl->login_limit_def < source) {
  678. return;
  679. } else {
  680. pl->login_limit = int_value;
  681. pl->login_limit_def = source;
  682. }
  683. }
  684. }
  685. return;
  686. }
  687. static int
  688. parse_uid_range(pam_handle_t *pamh, const char *domain,
  689. uid_t *min_uid, uid_t *max_uid)
  690. {
  691. const char *range = domain;
  692. char *pmax;
  693. char *endptr;
  694. int rv = LIMIT_RANGE_MM;
  695. if ((pmax=strchr(range, ':')) == NULL)
  696. return LIMIT_RANGE_NONE;
  697. ++pmax;
  698. if (range[0] == '@' || range[0] == '%')
  699. ++range;
  700. if (range[0] == ':')
  701. rv = LIMIT_RANGE_ONE;
  702. else {
  703. errno = 0;
  704. *min_uid = strtoul (range, &endptr, 10);
  705. if (errno != 0 || (range == endptr) || *endptr != ':') {
  706. pam_syslog(pamh, LOG_DEBUG,
  707. "wrong min_uid/gid value in '%s'", domain);
  708. return LIMIT_RANGE_ERR;
  709. }
  710. }
  711. if (*pmax == '\0') {
  712. if (rv == LIMIT_RANGE_ONE)
  713. return LIMIT_RANGE_ERR;
  714. else
  715. return LIMIT_RANGE_MIN;
  716. }
  717. errno = 0;
  718. *max_uid = strtoul (pmax, &endptr, 10);
  719. if (errno != 0 || (pmax == endptr) || *endptr != '\0') {
  720. pam_syslog(pamh, LOG_DEBUG,
  721. "wrong max_uid/gid value in '%s'", domain);
  722. return LIMIT_RANGE_ERR;
  723. }
  724. if (rv == LIMIT_RANGE_ONE)
  725. *min_uid = *max_uid;
  726. return rv;
  727. }
  728. static int
  729. parse_config_file(pam_handle_t *pamh, const char *uname, uid_t uid, gid_t gid,
  730. int ctrl, struct pam_limit_s *pl)
  731. {
  732. FILE *fil;
  733. char buf[LINE_LENGTH];
  734. /* check for the LIMITS_FILE */
  735. if (ctrl & PAM_DEBUG_ARG)
  736. pam_syslog(pamh, LOG_DEBUG, "reading settings from '%s'", CONF_FILE);
  737. fil = fopen(CONF_FILE, "r");
  738. if (fil == NULL) {
  739. pam_syslog (pamh, LOG_WARNING,
  740. "cannot read settings from %s: %m", CONF_FILE);
  741. return PAM_SERVICE_ERR;
  742. }
  743. /* start the show */
  744. while (fgets(buf, LINE_LENGTH, fil) != NULL) {
  745. char domain[LINE_LENGTH];
  746. char ltype[LINE_LENGTH];
  747. char item[LINE_LENGTH];
  748. char value[LINE_LENGTH];
  749. int i;
  750. int rngtype;
  751. size_t j;
  752. char *tptr,*line;
  753. uid_t min_uid = (uid_t)-1, max_uid = (uid_t)-1;
  754. line = buf;
  755. /* skip the leading white space */
  756. while (*line && isspace(*line))
  757. line++;
  758. /* Rip off the comments */
  759. tptr = strchr(line,'#');
  760. if (tptr)
  761. *tptr = '\0';
  762. /* Rip off the newline char */
  763. tptr = strchr(line,'\n');
  764. if (tptr)
  765. *tptr = '\0';
  766. /* Anything left ? */
  767. if (!strlen(line))
  768. continue;
  769. domain[0] = ltype[0] = item[0] = value[0] = '\0';
  770. i = sscanf(line,"%s%s%s%s", domain, ltype, item, value);
  771. D(("scanned line[%d]: domain[%s], ltype[%s], item[%s], value[%s]",
  772. i, domain, ltype, item, value));
  773. for(j=0; j < strlen(ltype); j++)
  774. ltype[j]=tolower(ltype[j]);
  775. if ((rngtype=parse_uid_range(pamh, domain, &min_uid, &max_uid)) < 0) {
  776. pam_syslog(pamh, LOG_WARNING, "invalid uid range '%s' - skipped", domain);
  777. continue;
  778. }
  779. if (i == 4) { /* a complete line */
  780. for(j=0; j < strlen(item); j++)
  781. item[j]=tolower(item[j]);
  782. for(j=0; j < strlen(value); j++)
  783. value[j]=tolower(value[j]);
  784. if (strcmp(uname, domain) == 0) /* this user have a limit */
  785. process_limit(pamh, LIMITS_DEF_USER, ltype, item, value, ctrl, pl);
  786. else if (domain[0]=='@') {
  787. if (ctrl & PAM_DEBUG_ARG) {
  788. pam_syslog(pamh, LOG_DEBUG,
  789. "checking if %s is in group %s",
  790. uname, domain + 1);
  791. }
  792. switch(rngtype) {
  793. case LIMIT_RANGE_NONE:
  794. if (pam_modutil_user_in_group_nam_nam(pamh, uname, domain+1))
  795. process_limit(pamh, LIMITS_DEF_GROUP, ltype, item, value, ctrl,
  796. pl);
  797. break;
  798. case LIMIT_RANGE_ONE:
  799. if (pam_modutil_user_in_group_nam_gid(pamh, uname, (gid_t)max_uid))
  800. process_limit(pamh, LIMITS_DEF_GROUP, ltype, item, value, ctrl,
  801. pl);
  802. break;
  803. case LIMIT_RANGE_MM:
  804. if (gid > (gid_t)max_uid)
  805. break;
  806. /* fallthrough */
  807. case LIMIT_RANGE_MIN:
  808. if (gid >= (gid_t)min_uid)
  809. process_limit(pamh, LIMITS_DEF_GROUP, ltype, item, value, ctrl,
  810. pl);
  811. }
  812. } else if (domain[0]=='%') {
  813. if (ctrl & PAM_DEBUG_ARG) {
  814. pam_syslog(pamh, LOG_DEBUG,
  815. "checking if %s is in group %s",
  816. uname, domain + 1);
  817. }
  818. switch(rngtype) {
  819. case LIMIT_RANGE_NONE:
  820. if (strcmp(domain,"%") == 0)
  821. process_limit(pamh, LIMITS_DEF_ALL, ltype, item, value, ctrl,
  822. pl);
  823. else if (pam_modutil_user_in_group_nam_nam(pamh, uname, domain+1)) {
  824. strcpy(pl->login_group, domain+1);
  825. process_limit(pamh, LIMITS_DEF_ALLGROUP, ltype, item, value, ctrl,
  826. pl);
  827. }
  828. break;
  829. case LIMIT_RANGE_ONE:
  830. if (pam_modutil_user_in_group_nam_gid(pamh, uname, (gid_t)max_uid)) {
  831. struct group *grp;
  832. grp = pam_modutil_getgrgid(pamh, (gid_t)max_uid);
  833. strncpy(pl->login_group, grp->gr_name, sizeof(pl->login_group));
  834. pl->login_group[sizeof(pl->login_group)-1] = '\0';
  835. process_limit(pamh, LIMITS_DEF_ALLGROUP, ltype, item, value, ctrl,
  836. pl);
  837. }
  838. break;
  839. case LIMIT_RANGE_MIN:
  840. case LIMIT_RANGE_MM:
  841. pam_syslog(pamh, LOG_WARNING, "range unsupported for %%group matching - ignored");
  842. }
  843. } else {
  844. switch(rngtype) {
  845. case LIMIT_RANGE_NONE:
  846. if (strcmp(domain, "*") == 0)
  847. process_limit(pamh, LIMITS_DEF_DEFAULT, ltype, item, value, ctrl,
  848. pl);
  849. break;
  850. case LIMIT_RANGE_ONE:
  851. if (uid != max_uid)
  852. break;
  853. /* fallthrough */
  854. case LIMIT_RANGE_MM:
  855. if (uid > max_uid)
  856. break;
  857. /* fallthrough */
  858. case LIMIT_RANGE_MIN:
  859. if (uid >= min_uid)
  860. process_limit(pamh, LIMITS_DEF_USER, ltype, item, value, ctrl, pl);
  861. }
  862. }
  863. } else if (i == 2 && ltype[0] == '-') { /* Probably a no-limit line */
  864. if (strcmp(uname, domain) == 0) {
  865. if (ctrl & PAM_DEBUG_ARG) {
  866. pam_syslog(pamh, LOG_DEBUG, "no limits for '%s'", uname);
  867. }
  868. } else if (domain[0] == '@') {
  869. switch(rngtype) {
  870. case LIMIT_RANGE_NONE:
  871. if (!pam_modutil_user_in_group_nam_nam(pamh, uname, domain+1))
  872. continue; /* next line */
  873. break;
  874. case LIMIT_RANGE_ONE:
  875. if (!pam_modutil_user_in_group_nam_gid(pamh, uname, (gid_t)max_uid))
  876. continue; /* next line */
  877. break;
  878. case LIMIT_RANGE_MM:
  879. if (gid > (gid_t)max_uid)
  880. continue; /* next line */
  881. /* fallthrough */
  882. case LIMIT_RANGE_MIN:
  883. if (gid < (gid_t)min_uid)
  884. continue; /* next line */
  885. }
  886. if (ctrl & PAM_DEBUG_ARG) {
  887. pam_syslog(pamh, LOG_DEBUG,
  888. "no limits for '%s' in group '%s'",
  889. uname, domain+1);
  890. }
  891. } else {
  892. switch(rngtype) {
  893. case LIMIT_RANGE_NONE:
  894. continue; /* next line */
  895. case LIMIT_RANGE_ONE:
  896. if (uid != max_uid)
  897. continue; /* next line */
  898. break;
  899. case LIMIT_RANGE_MM:
  900. if (uid > max_uid)
  901. continue; /* next line */
  902. /* fallthrough */
  903. case LIMIT_RANGE_MIN:
  904. if (uid >= min_uid)
  905. break;
  906. continue; /* next line */
  907. }
  908. if (ctrl & PAM_DEBUG_ARG) {
  909. pam_syslog(pamh, LOG_DEBUG, "no limits for '%s'", uname);
  910. }
  911. }
  912. fclose(fil);
  913. return PAM_IGNORE;
  914. } else {
  915. pam_syslog(pamh, LOG_WARNING, "invalid line '%s' - skipped", line);
  916. }
  917. }
  918. fclose(fil);
  919. return PAM_SUCCESS;
  920. }
  921. static int setup_limits(pam_handle_t *pamh,
  922. const char *uname, uid_t uid, int ctrl,
  923. struct pam_limit_s *pl)
  924. {
  925. int i;
  926. int status;
  927. int retval = LIMITED_OK;
  928. for (i=0, status=LIMITED_OK; i<RLIM_NLIMITS; i++) {
  929. int res;
  930. if (!pl->limits[i].supported) {
  931. /* skip it if its not known to the system */
  932. continue;
  933. }
  934. if (pl->limits[i].src_soft == LIMITS_DEF_NONE &&
  935. pl->limits[i].src_hard == LIMITS_DEF_NONE) {
  936. /* skip it if its not initialized */
  937. continue;
  938. }
  939. if (pl->limits[i].limit.rlim_cur > pl->limits[i].limit.rlim_max)
  940. pl->limits[i].limit.rlim_cur = pl->limits[i].limit.rlim_max;
  941. res = setrlimit(i, &pl->limits[i].limit);
  942. if (res != 0)
  943. pam_syslog(pamh, LOG_ERR, "Could not set limit for '%s': %m",
  944. rlimit2str(i));
  945. status |= res;
  946. }
  947. if (status) {
  948. retval = LIMIT_ERR;
  949. }
  950. status = setpriority(PRIO_PROCESS, 0, pl->priority);
  951. if (status != 0) {
  952. pam_syslog(pamh, LOG_ERR, "Could not set limit for PRIO_PROCESS: %m");
  953. retval = LIMIT_ERR;
  954. }
  955. if (uid == 0) {
  956. D(("skip login limit check for uid=0"));
  957. } else if (pl->login_limit > 0) {
  958. if (check_logins(pamh, uname, pl->login_limit, ctrl, pl) == LOGIN_ERR) {
  959. #ifdef HAVE_LIBAUDIT
  960. if (!(ctrl & PAM_NO_AUDIT)) {
  961. pam_modutil_audit_write(pamh, AUDIT_ANOM_LOGIN_SESSIONS,
  962. "pam_limits", PAM_PERM_DENIED);
  963. /* ignore return value as we fail anyway */
  964. }
  965. #endif
  966. retval |= LOGIN_ERR;
  967. }
  968. } else if (pl->login_limit == 0) {
  969. retval |= LOGIN_ERR;
  970. }
  971. if (pl->nonewprivs) {
  972. if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
  973. pam_syslog(pamh, LOG_ERR, "Could not set prctl(PR_SET_NO_NEW_PRIVS): %m");
  974. retval |= LIMIT_ERR;
  975. }
  976. }
  977. return retval;
  978. }
  979. /* now the session stuff */
  980. int
  981. pam_sm_open_session (pam_handle_t *pamh, int flags UNUSED,
  982. int argc, const char **argv)
  983. {
  984. int retval;
  985. int i;
  986. int glob_rc;
  987. char *user_name;
  988. struct passwd *pwd;
  989. int ctrl;
  990. struct pam_limit_s plstruct;
  991. struct pam_limit_s *pl = &plstruct;
  992. glob_t globbuf;
  993. const char *oldlocale;
  994. D(("called."));
  995. memset(pl, 0, sizeof(*pl));
  996. memset(&globbuf, 0, sizeof(globbuf));
  997. ctrl = _pam_parse(pamh, argc, argv, pl);
  998. retval = pam_get_item( pamh, PAM_USER, (void*) &user_name );
  999. if ( user_name == NULL || retval != PAM_SUCCESS ) {
  1000. pam_syslog(pamh, LOG_ERR, "open_session - error recovering username");
  1001. return PAM_SESSION_ERR;
  1002. }
  1003. pwd = pam_modutil_getpwnam(pamh, user_name);
  1004. if (!pwd) {
  1005. if (ctrl & PAM_DEBUG_ARG)
  1006. pam_syslog(pamh, LOG_WARNING,
  1007. "open_session username '%s' does not exist", user_name);
  1008. return PAM_USER_UNKNOWN;
  1009. }
  1010. retval = init_limits(pamh, pl, ctrl);
  1011. if (retval != PAM_SUCCESS) {
  1012. pam_syslog(pamh, LOG_ERR, "cannot initialize");
  1013. return PAM_ABORT;
  1014. }
  1015. retval = parse_config_file(pamh, pwd->pw_name, pwd->pw_uid, pwd->pw_gid, ctrl, pl);
  1016. if (retval == PAM_IGNORE) {
  1017. D(("the configuration file ('%s') has an applicable '<domain> -' entry", CONF_FILE));
  1018. return PAM_SUCCESS;
  1019. }
  1020. if (retval != PAM_SUCCESS || pl->conf_file != NULL)
  1021. /* skip reading limits.d if config file explicitly specified */
  1022. goto out;
  1023. /* Read subsequent *.conf files, if they exist. */
  1024. /* set the LC_COLLATE so the sorting order doesn't depend
  1025. on system locale */
  1026. oldlocale = setlocale(LC_COLLATE, "C");
  1027. glob_rc = glob(LIMITS_CONF_GLOB, GLOB_ERR, NULL, &globbuf);
  1028. if (oldlocale != NULL)
  1029. setlocale (LC_COLLATE, oldlocale);
  1030. if (!glob_rc) {
  1031. /* Parse the *.conf files. */
  1032. for (i = 0; globbuf.gl_pathv[i] != NULL; i++) {
  1033. pl->conf_file = globbuf.gl_pathv[i];
  1034. retval = parse_config_file(pamh, pwd->pw_name, pwd->pw_uid, pwd->pw_gid, ctrl, pl);
  1035. if (retval == PAM_IGNORE) {
  1036. D(("the configuration file ('%s') has an applicable '<domain> -' entry", pl->conf_file));
  1037. globfree(&globbuf);
  1038. return PAM_SUCCESS;
  1039. }
  1040. if (retval != PAM_SUCCESS)
  1041. goto out;
  1042. }
  1043. }
  1044. out:
  1045. globfree(&globbuf);
  1046. if (retval != PAM_SUCCESS)
  1047. {
  1048. pam_syslog(pamh, LOG_ERR, "error parsing the configuration file: '%s' ",CONF_FILE);
  1049. return retval;
  1050. }
  1051. retval = setup_limits(pamh, pwd->pw_name, pwd->pw_uid, ctrl, pl);
  1052. if (retval & LOGIN_ERR)
  1053. pam_error(pamh, _("There were too many logins for '%s'."),
  1054. pwd->pw_name);
  1055. if (retval != LIMITED_OK) {
  1056. return PAM_PERM_DENIED;
  1057. }
  1058. return PAM_SUCCESS;
  1059. }
  1060. int
  1061. pam_sm_close_session (pam_handle_t *pamh UNUSED, int flags UNUSED,
  1062. int argc UNUSED, const char **argv UNUSED)
  1063. {
  1064. /* nothing to do */
  1065. return PAM_SUCCESS;
  1066. }
  1067. /*
  1068. * Copyright (c) Cristian Gafton, 1996-1997, <gafton@redhat.com>
  1069. * All rights reserved.
  1070. *
  1071. * Redistribution and use in source and binary forms, with or without
  1072. * modification, are permitted provided that the following conditions
  1073. * are met:
  1074. * 1. Redistributions of source code must retain the above copyright
  1075. * notice, and the entire permission notice in its entirety,
  1076. * including the disclaimer of warranties.
  1077. * 2. Redistributions in binary form must reproduce the above copyright
  1078. * notice, this list of conditions and the following disclaimer in the
  1079. * documentation and/or other materials provided with the distribution.
  1080. * 3. The name of the author may not be used to endorse or promote
  1081. * products derived from this software without specific prior
  1082. * written permission.
  1083. *
  1084. * ALTERNATIVELY, this product may be distributed under the terms of
  1085. * the GNU Public License, in which case the provisions of the GPL are
  1086. * required INSTEAD OF the above restrictions. (This clause is
  1087. * necessary due to a potential bad interaction between the GPL and
  1088. * the restrictions contained in a BSD-style copyright.)
  1089. *
  1090. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  1091. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  1092. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  1093. * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
  1094. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  1095. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  1096. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  1097. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  1098. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  1099. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  1100. * OF THE POSSIBILITY OF SUCH DAMAGE.
  1101. */