2 * Copyright information at end of file.
21 #include <sys/resource.h>
22 #include <rpcsvc/ypclnt.h>
24 #include <security/_pam_macros.h>
25 #include <security/pam_modules.h>
26 #include <security/pam_ext.h>
27 #include <security/pam_modutil.h>
32 #include <selinux/selinux.h>
33 #define SELINUX_ENABLED is_selinux_enabled()>0
35 #define SELINUX_ENABLED 0
37 extern char *crypt(const char *key, const char *salt);
38 extern char *bigcrypt(const char *key, const char *salt);
40 /* this is a front-end for module-application conversations */
42 int _make_remark(pam_handle_t * pamh, unsigned int ctrl,
43 int type, const char *text)
45 int retval = PAM_SUCCESS;
47 if (off(UNIX__QUIET, ctrl)) {
48 retval = pam_prompt(pamh, type, NULL, "%s", text);
54 * set the control flags for the UNIX module.
57 int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int argc,
64 ctrl = UNIX_DEFAULTS; /* the default selection of options */
66 /* set some flags manually */
68 if (getuid() == 0 && !(flags & PAM_CHANGE_EXPIRED_AUTHTOK)) {
70 set(UNIX__IAMROOT, ctrl);
72 if (flags & PAM_UPDATE_AUTHTOK) {
73 D(("UPDATE_AUTHTOK"));
74 set(UNIX__UPDATE, ctrl);
76 if (flags & PAM_PRELIM_CHECK) {
78 set(UNIX__PRELIM, ctrl);
80 if (flags & PAM_SILENT) {
82 set(UNIX__QUIET, ctrl);
84 /* now parse the arguments to this module */
89 D(("pam_unix arg: %s", *argv));
91 for (j = 0; j < UNIX_CTRLS_; ++j) {
92 if (unix_args[j].token
93 && !strncmp(*argv, unix_args[j].token, strlen(unix_args[j].token))) {
98 if (j >= UNIX_CTRLS_) {
99 pam_syslog(pamh, LOG_ERR,
100 "unrecognized option [%s]", *argv);
102 ctrl &= unix_args[j].mask; /* for turning things off */
103 ctrl |= unix_args[j].flag; /* for turning things on */
105 if (remember != NULL) {
106 if (j == UNIX_REMEMBER_PASSWD) {
107 *remember = strtol(*argv + 9, NULL, 10);
108 if ((*remember == INT_MIN) || (*remember == INT_MAX))
116 ++argv; /* step to next argument */
119 if (flags & PAM_DISALLOW_NULL_AUTHTOK) {
120 D(("DISALLOW_NULL_AUTHTOK"));
121 set(UNIX__NONULL, ctrl);
124 /* auditing is a more sensitive version of debug */
126 if (on(UNIX_AUDIT, ctrl)) {
127 set(UNIX_DEBUG, ctrl);
129 /* return the set of flags */
135 static void _cleanup(pam_handle_t * pamh UNUSED, void *x, int error_status UNUSED)
140 /* ************************************************************** *
141 * Useful non-trivial functions *
142 * ************************************************************** */
145 * the following is used to keep track of the number of times a user fails
146 * to authenticate themself.
149 #define FAIL_PREFIX "-UN*X-FAIL-"
150 #define UNIX_MAX_RETRIES 3
152 struct _pam_failed_auth {
153 char *user; /* user that's failed to be authenticated */
154 char *name; /* attempt from user with name */
155 int uid; /* uid of calling user */
156 int euid; /* euid of calling process */
157 int count; /* number of failures so far */
160 #ifndef PAM_DATA_REPLACE
161 #error "Need to get an updated libpam 0.52 or better"
164 static void _cleanup_failures(pam_handle_t * pamh, void *fl, int err)
167 const void *service = NULL;
168 const void *ruser = NULL;
169 const void *rhost = NULL;
170 const void *tty = NULL;
171 struct _pam_failed_auth *failure;
175 quiet = err & PAM_DATA_SILENT; /* should we log something? */
176 err &= PAM_DATA_REPLACE; /* are we just replacing data? */
177 failure = (struct _pam_failed_auth *) fl;
179 if (failure != NULL) {
181 if (!quiet && !err) { /* under advisement from Sun,may go away */
183 /* log the number of authentication failures */
184 if (failure->count > 1) {
185 (void) pam_get_item(pamh, PAM_SERVICE,
187 (void) pam_get_item(pamh, PAM_RUSER,
189 (void) pam_get_item(pamh, PAM_RHOST,
191 (void) pam_get_item(pamh, PAM_TTY,
193 pam_syslog(pamh, LOG_NOTICE,
194 "%d more authentication failure%s; "
195 "logname=%s uid=%d euid=%d "
196 "tty=%s ruser=%s rhost=%s "
198 failure->count - 1, failure->count == 2 ? "" : "s",
199 failure->name, failure->uid, failure->euid,
200 tty ? (const char *)tty : "", ruser ? (const char *)ruser : "",
201 rhost ? (const char *)rhost : "",
202 (failure->user && failure->user[0] != '\0')
203 ? " user=" : "", failure->user
206 if (failure->count > UNIX_MAX_RETRIES) {
207 pam_syslog(pamh, LOG_ALERT,
208 "service(%s) ignoring max retries; %d > %d",
209 service == NULL ? "**unknown**" : (const char *)service,
215 _pam_delete(failure->user); /* tidy up */
216 _pam_delete(failure->name); /* tidy up */
222 * _unix_getpwnam() searches only /etc/passwd and NIS to find user information
224 static void _unix_cleanup(pam_handle_t *pamh UNUSED, void *data, int error_status UNUSED)
229 int _unix_getpwnam(pam_handle_t *pamh, const char *name,
230 int files, int nis, struct passwd **ret)
234 int matched = 0, buflen;
235 char *slogin, *spasswd, *suid, *sgid, *sgecos, *shome, *sshell, *p;
237 memset(buf, 0, sizeof(buf));
239 if (!matched && files) {
240 int userlen = strlen(name);
241 passwd = fopen("/etc/passwd", "r");
242 if (passwd != NULL) {
243 while (fgets(buf, sizeof(buf), passwd) != NULL) {
244 if ((buf[userlen] == ':') &&
245 (strncmp(name, buf, userlen) == 0)) {
246 p = buf + strlen(buf) - 1;
247 while (isspace(*p) && (p >= buf)) {
258 if (!matched && nis) {
259 char *userinfo = NULL, *domain = NULL;
261 len = yp_get_default_domain(&domain);
262 if (len == YPERR_SUCCESS) {
263 len = yp_bind(domain);
265 if (len == YPERR_SUCCESS) {
266 i = yp_match(domain, "passwd.byname", name,
267 strlen(name), &userinfo, &len);
269 if ((i == YPERR_SUCCESS) && ((size_t)len < sizeof(buf))) {
270 strncpy(buf, userinfo, sizeof(buf) - 1);
271 buf[sizeof(buf) - 1] = '\0';
277 if (matched && (ret != NULL)) {
282 spasswd = strchr(slogin, ':');
283 if (spasswd == NULL) {
288 suid = strchr(spasswd, ':');
294 sgid = strchr(suid, ':');
300 sgecos = strchr(sgid, ':');
301 if (sgecos == NULL) {
306 shome = strchr(sgecos, ':');
312 sshell = strchr(shome, ':');
313 if (sshell == NULL) {
318 buflen = sizeof(struct passwd) +
320 strlen(spasswd) + 1 +
326 *ret = malloc(buflen);
330 memset(*ret, '\0', buflen);
332 (*ret)->pw_uid = strtol(suid, &p, 10);
333 if ((strlen(suid) == 0) || (*p != '\0')) {
339 (*ret)->pw_gid = strtol(sgid, &p, 10);
340 if ((strlen(sgid) == 0) || (*p != '\0')) {
346 p = ((char*)(*ret)) + sizeof(struct passwd);
347 (*ret)->pw_name = strcpy(p, slogin);
349 (*ret)->pw_passwd = strcpy(p, spasswd);
351 (*ret)->pw_gecos = strcpy(p, sgecos);
353 (*ret)->pw_dir = strcpy(p, shome);
355 (*ret)->pw_shell = strcpy(p, sshell);
357 snprintf(buf, sizeof(buf), "_pam_unix_getpwnam_%s", name);
359 if (pam_set_data(pamh, buf,
360 *ret, _unix_cleanup) != PAM_SUCCESS) {
370 * _unix_comsefromsource() is a quick check to see if information about a given
371 * user comes from a particular source (just files and nis for now)
374 int _unix_comesfromsource(pam_handle_t *pamh,
375 const char *name, int files, int nis)
377 return _unix_getpwnam(pamh, name, files, nis, NULL);
381 * _unix_blankpasswd() is a quick check for a blank password
383 * returns TRUE if user does not have a password
384 * - to avoid prompting for one in such cases (CG)
388 _unix_blankpasswd (pam_handle_t *pamh, unsigned int ctrl, const char *name)
390 struct passwd *pwd = NULL;
391 struct spwd *spwdent = NULL;
398 * This function does not have to be too smart if something goes
399 * wrong, return FALSE and let this case to be treated somewhere
403 if (on(UNIX__NONULL, ctrl))
404 return 0; /* will fail but don't let on yet */
406 /* UNIX passwords area */
408 /* Get password file entry... */
409 pwd = pam_modutil_getpwnam (pamh, name);
412 if (strcmp( pwd->pw_passwd, "*NP*" ) == 0)
414 uid_t save_euid, save_uid;
416 save_euid = geteuid();
418 if (save_uid == pwd->pw_uid)
419 setreuid( save_euid, save_uid );
422 if (setreuid( -1, pwd->pw_uid ) == -1) {
425 if(setreuid( -1, pwd->pw_uid ) == -1)
426 /* Will fail elsewhere. */
431 spwdent = pam_modutil_getspnam (pamh, name);
432 if (save_uid == pwd->pw_uid)
433 setreuid( save_uid, save_euid );
435 if (setreuid( -1, 0 ) == -1)
436 setreuid( save_uid, -1 );
437 setreuid( -1, save_euid );
439 } else if (_unix_shadowed(pwd)) {
441 * ...and shadow password file entry for this user,
442 * if shadowing is enabled
444 spwdent = pam_modutil_getspnam(pamh, name);
447 salt = x_strdup(spwdent->sp_pwdp);
449 salt = x_strdup(pwd->pw_passwd);
451 /* Does this user have a password? */
455 if (strlen(salt) == 0)
470 * verify the password of a user
473 #include <sys/types.h>
474 #include <sys/wait.h>
476 static int _unix_run_helper_binary(pam_handle_t *pamh, const char *passwd,
477 unsigned int ctrl, const char *user)
479 int retval, child, fds[2];
480 void (*sighandler)(int) = NULL;
483 /* create a pipe for the password */
484 if (pipe(fds) != 0) {
485 D(("could not make pipe"));
489 if (off(UNIX_NOREAP, ctrl)) {
491 * This code arranges that the demise of the child does not cause
492 * the application to receive a signal it is not expecting - which
493 * may kill the application or worse.
495 * The "noreap" module argument is provided so that the admin can
496 * override this behavior.
498 sighandler = signal(SIGCHLD, SIG_DFL);
506 static char *envp[] = { NULL };
507 char *args[] = { NULL, NULL, NULL, NULL };
509 /* XXX - should really tidy up PAM here too */
512 /* reopen stdin as pipe */
514 dup2(fds[0], STDIN_FILENO);
516 if (getrlimit(RLIMIT_NOFILE,&rlim)==0) {
517 for (i=2; i < (int)rlim.rlim_max; i++) {
523 if (SELINUX_ENABLED && geteuid() == 0) {
524 /* must set the real uid to 0 so the helper will not error
525 out if pam is called from setuid binary (su, sudo...) */
529 /* exec binary helper */
530 args[0] = x_strdup(CHKPWD_HELPER);
531 args[1] = x_strdup(user);
532 if (off(UNIX__NONULL, ctrl)) { /* this means we've succeeded */
533 args[2]=x_strdup("nullok");
535 args[2]=x_strdup("nonull");
538 execve(CHKPWD_HELPER, args, envp);
540 /* should not get here: exit with error */
541 D(("helper binary is not available"));
542 exit(PAM_AUTHINFO_UNAVAIL);
543 } else if (child > 0) {
545 /* if the stored password is NULL */
547 if (passwd != NULL) { /* send the password to the child */
548 write(fds[1], passwd, strlen(passwd)+1);
551 write(fds[1], "", 1); /* blank password */
553 close(fds[0]); /* close here to avoid possible SIGPIPE above */
555 rc=waitpid(child, &retval, 0); /* wait for helper to complete */
557 pam_syslog(pamh, LOG_ERR, "unix_chkpwd waitpid returned %d: %m", rc);
558 retval = PAM_AUTH_ERR;
560 retval = WEXITSTATUS(retval);
566 retval = PAM_AUTH_ERR;
569 if (sighandler != NULL) {
570 (void) signal(SIGCHLD, sighandler); /* restore old signal handler */
573 D(("returning %d", retval));
577 int _unix_verify_password(pam_handle_t * pamh, const char *name
578 ,const char *p, unsigned int ctrl)
580 struct passwd *pwd = NULL;
581 struct spwd *spwdent = NULL;
590 #ifdef HAVE_PAM_FAIL_DELAY
591 if (off(UNIX_NODELAY, ctrl)) {
592 D(("setting delay"));
593 (void) pam_fail_delay(pamh, 2000000); /* 2 sec delay for on failure */
597 /* locate the entry for this user */
599 D(("locating user's record"));
601 /* UNIX passwords area */
602 pwd = pam_modutil_getpwnam (pamh, name); /* Get password file entry... */
605 if (strcmp( pwd->pw_passwd, "*NP*" ) == 0)
607 uid_t save_euid, save_uid;
609 save_euid = geteuid();
611 if (save_uid == pwd->pw_uid)
612 setreuid( save_euid, save_uid );
615 if (setreuid( -1, pwd->pw_uid ) == -1) {
618 if(setreuid( -1, pwd->pw_uid ) == -1)
619 return PAM_CRED_INSUFFICIENT;
623 spwdent = pam_modutil_getspnam (pamh, name);
624 if (save_uid == pwd->pw_uid)
625 setreuid( save_uid, save_euid );
627 if (setreuid( -1, 0 ) == -1)
628 setreuid( save_uid, -1 );
629 setreuid( -1, save_euid );
631 } else if (_unix_shadowed(pwd)) {
633 * ...and shadow password file entry for this user,
634 * if shadowing is enabled
636 spwdent = pam_modutil_getspnam (pamh, name);
639 salt = x_strdup(spwdent->sp_pwdp);
641 salt = x_strdup(pwd->pw_passwd);
644 data_name = (char *) malloc(sizeof(FAIL_PREFIX) + strlen(name));
645 if (data_name == NULL) {
646 pam_syslog(pamh, LOG_CRIT, "no memory for data-name");
648 strcpy(data_name, FAIL_PREFIX);
649 strcpy(data_name + sizeof(FAIL_PREFIX) - 1, name);
652 retval = PAM_SUCCESS;
653 if (pwd == NULL || salt == NULL || !strcmp(salt, "x") || ((salt[0] == '#') && (salt[1] == '#') && !strcmp(salt + 2, name))) {
655 if (pwd != NULL && (geteuid() || SELINUX_ENABLED)) {
656 /* we are not root perhaps this is the reason? Run helper */
657 D(("running helper binary"));
658 retval = _unix_run_helper_binary(pamh, p, ctrl, name);
660 D(("user's record unavailable"));
663 retval = PAM_USER_UNKNOWN;
665 retval = PAM_AUTHINFO_UNAVAIL;
666 if (on(UNIX_AUDIT, ctrl)) {
667 /* this might be a typo and the user has given a password
668 instead of a username. Careful with this. */
669 pam_syslog(pamh, LOG_ALERT,
670 "check pass; user (%s) unknown", name);
673 if (on(UNIX_DEBUG, ctrl) || pwd == NULL) {
674 pam_syslog(pamh, LOG_ALERT,
675 "check pass; user unknown");
677 /* don't log failure as another pam module can succeed */
683 int salt_len = strlen(salt);
685 /* the stored password is NULL */
686 if (off(UNIX__NONULL, ctrl)) {/* this means we've succeeded */
687 D(("user has empty password - access granted"));
688 retval = PAM_SUCCESS;
690 D(("user has empty password - access denied"));
691 retval = PAM_AUTH_ERR;
693 } else if (!p || (*salt == '*') || (salt_len < 13)) {
694 retval = PAM_AUTH_ERR;
696 if (!strncmp(salt, "$1$", 3)) {
697 pp = Goodcrypt_md5(p, salt);
698 if (strcmp(pp, salt) != 0) {
700 pp = Brokencrypt_md5(p, salt);
703 pp = bigcrypt(p, salt);
705 p = NULL; /* no longer needed here */
707 /* the moment of truth -- do we agree with the password? */
708 D(("comparing state of pp[%s] and salt[%s]", pp, salt));
711 * Note, we are comparing the bigcrypt of the password with
712 * the contents of the password field. If the latter was
713 * encrypted with regular crypt (and not bigcrypt) it will
714 * have been truncated for storage relative to the output
715 * of bigcrypt here. As such we need to compare only the
716 * stored string with the subset of bigcrypt's result.
717 * Bug 521314: The strncmp comparison is for legacy support.
719 if (strncmp(pp, salt, salt_len) == 0) {
720 retval = PAM_SUCCESS;
722 retval = PAM_AUTH_ERR;
727 if (retval == PAM_SUCCESS) {
728 if (data_name) /* reset failures */
729 pam_set_data(pamh, data_name, NULL, _cleanup_failures);
731 if (data_name != NULL) {
732 struct _pam_failed_auth *new = NULL;
733 const struct _pam_failed_auth *old = NULL;
735 /* get a failure recorder */
737 new = (struct _pam_failed_auth *)
738 malloc(sizeof(struct _pam_failed_auth));
742 const char *login_name;
743 const void *void_old;
746 login_name = pam_modutil_getlogin(pamh);
747 if (login_name == NULL) {
751 new->user = x_strdup(name ? name : "");
753 new->euid = geteuid();
754 new->name = x_strdup(login_name);
756 /* any previous failures for this user ? */
757 if (pam_get_data(pamh, data_name, &void_old)
764 new->count = old->count + 1;
765 if (new->count >= UNIX_MAX_RETRIES) {
766 retval = PAM_MAXTRIES;
769 const void *service=NULL;
770 const void *ruser=NULL;
771 const void *rhost=NULL;
772 const void *tty=NULL;
774 (void) pam_get_item(pamh, PAM_SERVICE,
776 (void) pam_get_item(pamh, PAM_RUSER,
778 (void) pam_get_item(pamh, PAM_RHOST,
780 (void) pam_get_item(pamh, PAM_TTY,
783 pam_syslog(pamh, LOG_NOTICE,
784 "authentication failure; "
785 "logname=%s uid=%d euid=%d "
786 "tty=%s ruser=%s rhost=%s "
788 new->name, new->uid, new->euid,
789 tty ? (const char *)tty : "",
790 ruser ? (const char *)ruser : "",
791 rhost ? (const char *)rhost : "",
792 (new->user && new->user[0] != '\0')
799 pam_set_data(pamh, data_name, new, _cleanup_failures);
802 pam_syslog(pamh, LOG_CRIT,
803 "no memory for failure recorder");
810 _pam_delete(data_name);
816 D(("done [%d].", retval));
822 * obtain a password from the user
825 int _unix_read_password(pam_handle_t * pamh
830 ,const char *data_name
834 int retval = PAM_SUCCESS;
840 * make sure nothing inappropriate gets returned
843 *pass = token = NULL;
846 * which authentication token are we getting?
849 authtok_flag = on(UNIX__OLD_PASSWD, ctrl) ? PAM_OLDAUTHTOK : PAM_AUTHTOK;
852 * should we obtain the password from a PAM item ?
855 if (on(UNIX_TRY_FIRST_PASS, ctrl) || on(UNIX_USE_FIRST_PASS, ctrl)) {
856 retval = pam_get_item(pamh, authtok_flag, pass);
857 if (retval != PAM_SUCCESS) {
859 pam_syslog(pamh, LOG_ALERT,
860 "pam_get_item returned error to unix-read-password"
863 } else if (*pass != NULL) { /* we have a password! */
865 } else if (on(UNIX_USE_FIRST_PASS, ctrl)) {
866 return PAM_AUTHTOK_RECOVERY_ERR; /* didn't work */
867 } else if (on(UNIX_USE_AUTHTOK, ctrl)
868 && off(UNIX__OLD_PASSWD, ctrl)) {
869 return PAM_AUTHTOK_ERR;
873 * getting here implies we will have to get the password from the
879 char *resp[2] = { NULL, NULL };
881 if (comment != NULL && off(UNIX__QUIET, ctrl)) {
882 retval = pam_info(pamh, "%s", comment);
885 if (retval == PAM_SUCCESS) {
886 retval = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF,
887 &resp[0], "%s", prompt1);
889 if (retval == PAM_SUCCESS && prompt2 != NULL) {
890 retval = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF,
891 &resp[1], "%s", prompt2);
896 if (resp[0] != NULL && resp[replies-1] != NULL) {
897 /* interpret the response */
899 if (retval == PAM_SUCCESS) { /* a good conversation */
904 /* verify that password entered correctly */
905 if (strcmp(token, resp[replies - 1])) {
907 retval = PAM_AUTHTOK_RECOVERY_ERR;
908 _make_remark(pamh, ctrl,
909 PAM_ERROR_MSG, MISTYPED_PASS);
913 pam_syslog(pamh, LOG_NOTICE,
914 "could not recover authentication token");
920 retval = (retval == PAM_SUCCESS)
921 ? PAM_AUTHTOK_RECOVERY_ERR : retval;
926 _pam_delete(resp[1]);
929 if (retval != PAM_SUCCESS) {
932 if (on(UNIX_DEBUG, ctrl))
933 pam_syslog(pamh, LOG_DEBUG,
934 "unable to obtain a password");
937 /* 'token' is the entered password */
939 if (off(UNIX_NOT_SET_PASS, ctrl)) {
941 /* we store this password as an item */
943 retval = pam_set_item(pamh, authtok_flag, token);
944 _pam_delete(token); /* clean it up */
945 if (retval != PAM_SUCCESS
946 || (retval = pam_get_item(pamh, authtok_flag, pass))
950 pam_syslog(pamh, LOG_CRIT, "error manipulating password");
956 * then store it as data specific to this module. pam_end()
957 * will arrange to clean it up.
960 retval = pam_set_data(pamh, data_name, (void *) token, _cleanup);
961 if (retval != PAM_SUCCESS) {
962 pam_syslog(pamh, LOG_CRIT,
963 "error manipulating password data [%s]",
964 pam_strerror(pamh, retval));
969 token = NULL; /* break link to password */
975 int _unix_shadowed(const struct passwd *pwd)
978 if (strcmp(pwd->pw_passwd, "x") == 0) {
981 if ((pwd->pw_passwd[0] == '#') &&
982 (pwd->pw_passwd[1] == '#') &&
983 (strcmp(pwd->pw_name, pwd->pw_passwd + 2) == 0)) {
990 /* ****************************************************************** *
991 * Copyright (c) Jan Rêkorajski 1999.
992 * Copyright (c) Andrew G. Morgan 1996-8.
993 * Copyright (c) Alex O. Yuriev, 1996.
994 * Copyright (c) Cristian Gafton 1996.
996 * Redistribution and use in source and binary forms, with or without
997 * modification, are permitted provided that the following conditions
999 * 1. Redistributions of source code must retain the above copyright
1000 * notice, and the entire permission notice in its entirety,
1001 * including the disclaimer of warranties.
1002 * 2. Redistributions in binary form must reproduce the above copyright
1003 * notice, this list of conditions and the following disclaimer in the
1004 * documentation and/or other materials provided with the distribution.
1005 * 3. The name of the author may not be used to endorse or promote
1006 * products derived from this software without specific prior
1007 * written permission.
1009 * ALTERNATIVELY, this product may be distributed under the terms of
1010 * the GNU Public License, in which case the provisions of the GPL are
1011 * required INSTEAD OF the above restrictions. (This clause is
1012 * necessary due to a potential bad interaction between the GPL and
1013 * the restrictions contained in a BSD-style copyright.)
1015 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
1016 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1017 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1018 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
1019 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1020 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
1021 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1022 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
1023 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1024 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
1025 * OF THE POSSIBILITY OF SUCH DAMAGE.