4 * Copyright information at end of file.
23 #include <sys/resource.h>
24 #include <rpcsvc/ypclnt.h>
26 #include <security/_pam_macros.h>
27 #include <security/pam_modules.h>
28 #include <security/pam_ext.h>
29 #include <security/pam_modutil.h>
34 #include <selinux/selinux.h>
35 #define SELINUX_ENABLED is_selinux_enabled()>0
37 #define SELINUX_ENABLED 0
39 extern char *crypt(const char *key, const char *salt);
40 extern char *bigcrypt(const char *key, const char *salt);
42 /* this is a front-end for module-application conversations */
44 int _make_remark(pam_handle_t * pamh, unsigned int ctrl,
45 int type, const char *text)
47 int retval = PAM_SUCCESS;
49 if (off(UNIX__QUIET, ctrl)) {
50 retval = pam_prompt(pamh, type, NULL, "%s", text);
56 * set the control flags for the UNIX module.
59 int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int argc,
66 ctrl = UNIX_DEFAULTS; /* the default selection of options */
68 /* set some flags manually */
70 if (getuid() == 0 && !(flags & PAM_CHANGE_EXPIRED_AUTHTOK)) {
72 set(UNIX__IAMROOT, ctrl);
74 if (flags & PAM_UPDATE_AUTHTOK) {
75 D(("UPDATE_AUTHTOK"));
76 set(UNIX__UPDATE, ctrl);
78 if (flags & PAM_PRELIM_CHECK) {
80 set(UNIX__PRELIM, ctrl);
82 if (flags & PAM_SILENT) {
84 set(UNIX__QUIET, ctrl);
86 /* now parse the arguments to this module */
91 D(("pam_unix arg: %s", *argv));
93 for (j = 0; j < UNIX_CTRLS_; ++j) {
94 if (unix_args[j].token
95 && !strncmp(*argv, unix_args[j].token, strlen(unix_args[j].token))) {
100 if (j >= UNIX_CTRLS_) {
101 pam_syslog(pamh, LOG_ERR,
102 "unrecognized option [%s]", *argv);
104 ctrl &= unix_args[j].mask; /* for turning things off */
105 ctrl |= unix_args[j].flag; /* for turning things on */
107 if (remember != NULL) {
108 if (j == UNIX_REMEMBER_PASSWD) {
109 *remember = strtol(*argv + 9, NULL, 10);
110 if ((*remember == INT_MIN) || (*remember == INT_MAX))
118 ++argv; /* step to next argument */
121 if (flags & PAM_DISALLOW_NULL_AUTHTOK) {
122 D(("DISALLOW_NULL_AUTHTOK"));
123 set(UNIX__NONULL, ctrl);
126 /* auditing is a more sensitive version of debug */
128 if (on(UNIX_AUDIT, ctrl)) {
129 set(UNIX_DEBUG, ctrl);
131 /* return the set of flags */
137 static void _cleanup(pam_handle_t * pamh UNUSED, void *x, int error_status UNUSED)
142 /* ************************************************************** *
143 * Useful non-trivial functions *
144 * ************************************************************** */
147 * the following is used to keep track of the number of times a user fails
148 * to authenticate themself.
151 #define FAIL_PREFIX "-UN*X-FAIL-"
152 #define UNIX_MAX_RETRIES 3
154 struct _pam_failed_auth {
155 char *user; /* user that's failed to be authenticated */
156 char *name; /* attempt from user with name */
157 int uid; /* uid of calling user */
158 int euid; /* euid of calling process */
159 int count; /* number of failures so far */
162 #ifndef PAM_DATA_REPLACE
163 #error "Need to get an updated libpam 0.52 or better"
166 static void _cleanup_failures(pam_handle_t * pamh, void *fl, int err)
169 const void *service = NULL;
170 const void *ruser = NULL;
171 const void *rhost = NULL;
172 const void *tty = NULL;
173 struct _pam_failed_auth *failure;
177 quiet = err & PAM_DATA_SILENT; /* should we log something? */
178 err &= PAM_DATA_REPLACE; /* are we just replacing data? */
179 failure = (struct _pam_failed_auth *) fl;
181 if (failure != NULL) {
183 if (!quiet && !err) { /* under advisement from Sun,may go away */
185 /* log the number of authentication failures */
186 if (failure->count > 1) {
187 (void) pam_get_item(pamh, PAM_SERVICE,
189 (void) pam_get_item(pamh, PAM_RUSER,
191 (void) pam_get_item(pamh, PAM_RHOST,
193 (void) pam_get_item(pamh, PAM_TTY,
195 pam_syslog(pamh, LOG_NOTICE,
196 "%d more authentication failure%s; "
197 "logname=%s uid=%d euid=%d "
198 "tty=%s ruser=%s rhost=%s "
200 failure->count - 1, failure->count == 2 ? "" : "s",
201 failure->name, failure->uid, failure->euid,
202 tty ? (const char *)tty : "", ruser ? (const char *)ruser : "",
203 rhost ? (const char *)rhost : "",
204 (failure->user && failure->user[0] != '\0')
205 ? " user=" : "", failure->user
208 if (failure->count > UNIX_MAX_RETRIES) {
209 pam_syslog(pamh, LOG_ALERT,
210 "service(%s) ignoring max retries; %d > %d",
211 service == NULL ? "**unknown**" : (const char *)service,
217 _pam_delete(failure->user); /* tidy up */
218 _pam_delete(failure->name); /* tidy up */
224 * _unix_getpwnam() searches only /etc/passwd and NIS to find user information
226 static void _unix_cleanup(pam_handle_t *pamh UNUSED, void *data, int error_status UNUSED)
231 int _unix_getpwnam(pam_handle_t *pamh, const char *name,
232 int files, int nis, struct passwd **ret)
236 int matched = 0, buflen;
237 char *slogin, *spasswd, *suid, *sgid, *sgecos, *shome, *sshell, *p;
239 memset(buf, 0, sizeof(buf));
241 if (!matched && files) {
242 int userlen = strlen(name);
243 passwd = fopen("/etc/passwd", "r");
244 if (passwd != NULL) {
245 while (fgets(buf, sizeof(buf), passwd) != NULL) {
246 if ((buf[userlen] == ':') &&
247 (strncmp(name, buf, userlen) == 0)) {
248 p = buf + strlen(buf) - 1;
249 while (isspace(*p) && (p >= buf)) {
260 if (!matched && nis) {
261 char *userinfo = NULL, *domain = NULL;
263 len = yp_get_default_domain(&domain);
264 if (len == YPERR_SUCCESS) {
265 len = yp_bind(domain);
267 if (len == YPERR_SUCCESS) {
268 i = yp_match(domain, "passwd.byname", name,
269 strlen(name), &userinfo, &len);
271 if ((i == YPERR_SUCCESS) && ((size_t)len < sizeof(buf))) {
272 strncpy(buf, userinfo, sizeof(buf) - 1);
273 buf[sizeof(buf) - 1] = '\0';
279 if (matched && (ret != NULL)) {
284 spasswd = strchr(slogin, ':');
285 if (spasswd == NULL) {
290 suid = strchr(spasswd, ':');
296 sgid = strchr(suid, ':');
302 sgecos = strchr(sgid, ':');
303 if (sgecos == NULL) {
308 shome = strchr(sgecos, ':');
314 sshell = strchr(shome, ':');
315 if (sshell == NULL) {
320 buflen = sizeof(struct passwd) +
322 strlen(spasswd) + 1 +
328 *ret = malloc(buflen);
332 memset(*ret, '\0', buflen);
334 (*ret)->pw_uid = strtol(suid, &p, 10);
335 if ((strlen(suid) == 0) || (*p != '\0')) {
341 (*ret)->pw_gid = strtol(sgid, &p, 10);
342 if ((strlen(sgid) == 0) || (*p != '\0')) {
348 p = ((char*)(*ret)) + sizeof(struct passwd);
349 (*ret)->pw_name = strcpy(p, slogin);
351 (*ret)->pw_passwd = strcpy(p, spasswd);
353 (*ret)->pw_gecos = strcpy(p, sgecos);
355 (*ret)->pw_dir = strcpy(p, shome);
357 (*ret)->pw_shell = strcpy(p, sshell);
359 snprintf(buf, sizeof(buf), "_pam_unix_getpwnam_%s", name);
361 if (pam_set_data(pamh, buf,
362 *ret, _unix_cleanup) != PAM_SUCCESS) {
372 * _unix_comsefromsource() is a quick check to see if information about a given
373 * user comes from a particular source (just files and nis for now)
376 int _unix_comesfromsource(pam_handle_t *pamh,
377 const char *name, int files, int nis)
379 return _unix_getpwnam(pamh, name, files, nis, NULL);
383 * _unix_blankpasswd() is a quick check for a blank password
385 * returns TRUE if user does not have a password
386 * - to avoid prompting for one in such cases (CG)
390 _unix_blankpasswd (pam_handle_t *pamh, unsigned int ctrl, const char *name)
392 struct passwd *pwd = NULL;
393 struct spwd *spwdent = NULL;
400 * This function does not have to be too smart if something goes
401 * wrong, return FALSE and let this case to be treated somewhere
405 if (on(UNIX__NONULL, ctrl))
406 return 0; /* will fail but don't let on yet */
408 /* UNIX passwords area */
410 /* Get password file entry... */
411 pwd = pam_modutil_getpwnam (pamh, name);
414 if (strcmp( pwd->pw_passwd, "*NP*" ) == 0)
416 uid_t save_euid, save_uid;
418 save_euid = geteuid();
420 if (save_uid == pwd->pw_uid)
421 setreuid( save_euid, save_uid );
424 if (setreuid( -1, pwd->pw_uid ) == -1) {
427 if(setreuid( -1, pwd->pw_uid ) == -1)
428 /* Will fail elsewhere. */
433 spwdent = pam_modutil_getspnam (pamh, name);
434 if (save_uid == pwd->pw_uid)
435 setreuid( save_uid, save_euid );
437 if (setreuid( -1, 0 ) == -1)
438 setreuid( save_uid, -1 );
439 setreuid( -1, save_euid );
441 } else if (_unix_shadowed(pwd)) {
443 * ...and shadow password file entry for this user,
444 * if shadowing is enabled
446 spwdent = pam_modutil_getspnam(pamh, name);
449 salt = x_strdup(spwdent->sp_pwdp);
451 salt = x_strdup(pwd->pw_passwd);
453 /* Does this user have a password? */
457 if (strlen(salt) == 0)
472 * verify the password of a user
475 #include <sys/types.h>
476 #include <sys/wait.h>
478 static int _unix_run_helper_binary(pam_handle_t *pamh, const char *passwd,
479 unsigned int ctrl, const char *user)
481 int retval, child, fds[2];
482 void (*sighandler)(int) = NULL;
485 /* create a pipe for the password */
486 if (pipe(fds) != 0) {
487 D(("could not make pipe"));
491 if (off(UNIX_NOREAP, ctrl)) {
493 * This code arranges that the demise of the child does not cause
494 * the application to receive a signal it is not expecting - which
495 * may kill the application or worse.
497 * The "noreap" module argument is provided so that the admin can
498 * override this behavior.
500 sighandler = signal(SIGCHLD, SIG_DFL);
508 static char *envp[] = { NULL };
509 char *args[] = { NULL, NULL, NULL, NULL };
511 /* XXX - should really tidy up PAM here too */
514 /* reopen stdin as pipe */
516 dup2(fds[0], STDIN_FILENO);
518 if (getrlimit(RLIMIT_NOFILE,&rlim)==0) {
519 for (i=2; i < (int)rlim.rlim_max; i++) {
525 if (SELINUX_ENABLED && geteuid() == 0) {
526 /* must set the real uid to 0 so the helper will not error
527 out if pam is called from setuid binary (su, sudo...) */
531 /* exec binary helper */
532 args[0] = x_strdup(CHKPWD_HELPER);
533 args[1] = x_strdup(user);
534 if (off(UNIX__NONULL, ctrl)) { /* this means we've succeeded */
535 args[2]=x_strdup("nullok");
537 args[2]=x_strdup("nonull");
540 execve(CHKPWD_HELPER, args, envp);
542 /* should not get here: exit with error */
543 D(("helper binary is not available"));
544 exit(PAM_AUTHINFO_UNAVAIL);
545 } else if (child > 0) {
547 /* if the stored password is NULL */
549 if (passwd != NULL) { /* send the password to the child */
550 write(fds[1], passwd, strlen(passwd)+1);
553 write(fds[1], "", 1); /* blank password */
555 close(fds[0]); /* close here to avoid possible SIGPIPE above */
557 rc=waitpid(child, &retval, 0); /* wait for helper to complete */
559 pam_syslog(pamh, LOG_ERR, "unix_chkpwd waitpid returned %d: %m", rc);
560 retval = PAM_AUTH_ERR;
562 retval = WEXITSTATUS(retval);
568 retval = PAM_AUTH_ERR;
571 if (sighandler != NULL) {
572 (void) signal(SIGCHLD, sighandler); /* restore old signal handler */
575 D(("returning %d", retval));
579 int _unix_verify_password(pam_handle_t * pamh, const char *name
580 ,const char *p, unsigned int ctrl)
582 struct passwd *pwd = NULL;
583 struct spwd *spwdent = NULL;
592 #ifdef HAVE_PAM_FAIL_DELAY
593 if (off(UNIX_NODELAY, ctrl)) {
594 D(("setting delay"));
595 (void) pam_fail_delay(pamh, 2000000); /* 2 sec delay for on failure */
599 /* locate the entry for this user */
601 D(("locating user's record"));
603 /* UNIX passwords area */
604 pwd = pam_modutil_getpwnam (pamh, name); /* Get password file entry... */
607 if (strcmp( pwd->pw_passwd, "*NP*" ) == 0)
609 uid_t save_euid, save_uid;
611 save_euid = geteuid();
613 if (save_uid == pwd->pw_uid)
614 setreuid( save_euid, save_uid );
617 if (setreuid( -1, pwd->pw_uid ) == -1) {
620 if(setreuid( -1, pwd->pw_uid ) == -1)
621 return PAM_CRED_INSUFFICIENT;
625 spwdent = pam_modutil_getspnam (pamh, name);
626 if (save_uid == pwd->pw_uid)
627 setreuid( save_uid, save_euid );
629 if (setreuid( -1, 0 ) == -1)
630 setreuid( save_uid, -1 );
631 setreuid( -1, save_euid );
633 } else if (_unix_shadowed(pwd)) {
635 * ...and shadow password file entry for this user,
636 * if shadowing is enabled
638 spwdent = pam_modutil_getspnam (pamh, name);
641 salt = x_strdup(spwdent->sp_pwdp);
643 salt = x_strdup(pwd->pw_passwd);
646 data_name = (char *) malloc(sizeof(FAIL_PREFIX) + strlen(name));
647 if (data_name == NULL) {
648 pam_syslog(pamh, LOG_CRIT, "no memory for data-name");
650 strcpy(data_name, FAIL_PREFIX);
651 strcpy(data_name + sizeof(FAIL_PREFIX) - 1, name);
654 retval = PAM_SUCCESS;
655 if (pwd == NULL || salt == NULL || !strcmp(salt, "x") || ((salt[0] == '#') && (salt[1] == '#') && !strcmp(salt + 2, name))) {
657 if (pwd != NULL && (geteuid() || SELINUX_ENABLED)) {
658 /* we are not root perhaps this is the reason? Run helper */
659 D(("running helper binary"));
660 retval = _unix_run_helper_binary(pamh, p, ctrl, name);
662 D(("user's record unavailable"));
665 retval = PAM_USER_UNKNOWN;
667 retval = PAM_AUTHINFO_UNAVAIL;
668 if (on(UNIX_AUDIT, ctrl)) {
669 /* this might be a typo and the user has given a password
670 instead of a username. Careful with this. */
671 pam_syslog(pamh, LOG_ALERT,
672 "check pass; user (%s) unknown", name);
675 if (on(UNIX_DEBUG, ctrl) || pwd == NULL) {
676 pam_syslog(pamh, LOG_ALERT,
677 "check pass; user unknown");
679 /* don't log failure as another pam module can succeed */
685 int salt_len = strlen(salt);
687 /* the stored password is NULL */
688 if (off(UNIX__NONULL, ctrl)) {/* this means we've succeeded */
689 D(("user has empty password - access granted"));
690 retval = PAM_SUCCESS;
692 D(("user has empty password - access denied"));
693 retval = PAM_AUTH_ERR;
695 } else if (!p || (*salt == '*') || (salt_len < 13)) {
696 retval = PAM_AUTH_ERR;
698 if (!strncmp(salt, "$1$", 3)) {
699 pp = Goodcrypt_md5(p, salt);
700 if (strcmp(pp, salt) != 0) {
702 pp = Brokencrypt_md5(p, salt);
705 pp = bigcrypt(p, salt);
707 p = NULL; /* no longer needed here */
709 /* the moment of truth -- do we agree with the password? */
710 D(("comparing state of pp[%s] and salt[%s]", pp, salt));
713 * Note, we are comparing the bigcrypt of the password with
714 * the contents of the password field. If the latter was
715 * encrypted with regular crypt (and not bigcrypt) it will
716 * have been truncated for storage relative to the output
717 * of bigcrypt here. As such we need to compare only the
718 * stored string with the subset of bigcrypt's result.
719 * Bug 521314: The strncmp comparison is for legacy support.
721 if (strncmp(pp, salt, salt_len) == 0) {
722 retval = PAM_SUCCESS;
724 retval = PAM_AUTH_ERR;
729 if (retval == PAM_SUCCESS) {
730 if (data_name) /* reset failures */
731 pam_set_data(pamh, data_name, NULL, _cleanup_failures);
733 if (data_name != NULL) {
734 struct _pam_failed_auth *new = NULL;
735 const struct _pam_failed_auth *old = NULL;
737 /* get a failure recorder */
739 new = (struct _pam_failed_auth *)
740 malloc(sizeof(struct _pam_failed_auth));
744 const char *login_name;
745 const void *void_old;
748 login_name = pam_modutil_getlogin(pamh);
749 if (login_name == NULL) {
753 new->user = x_strdup(name ? name : "");
755 new->euid = geteuid();
756 new->name = x_strdup(login_name);
758 /* any previous failures for this user ? */
759 if (pam_get_data(pamh, data_name, &void_old)
766 new->count = old->count + 1;
767 if (new->count >= UNIX_MAX_RETRIES) {
768 retval = PAM_MAXTRIES;
771 const void *service=NULL;
772 const void *ruser=NULL;
773 const void *rhost=NULL;
774 const void *tty=NULL;
776 (void) pam_get_item(pamh, PAM_SERVICE,
778 (void) pam_get_item(pamh, PAM_RUSER,
780 (void) pam_get_item(pamh, PAM_RHOST,
782 (void) pam_get_item(pamh, PAM_TTY,
785 pam_syslog(pamh, LOG_NOTICE,
786 "authentication failure; "
787 "logname=%s uid=%d euid=%d "
788 "tty=%s ruser=%s rhost=%s "
790 new->name, new->uid, new->euid,
791 tty ? (const char *)tty : "",
792 ruser ? (const char *)ruser : "",
793 rhost ? (const char *)rhost : "",
794 (new->user && new->user[0] != '\0')
801 pam_set_data(pamh, data_name, new, _cleanup_failures);
804 pam_syslog(pamh, LOG_CRIT,
805 "no memory for failure recorder");
812 _pam_delete(data_name);
818 D(("done [%d].", retval));
824 * obtain a password from the user
827 int _unix_read_password(pam_handle_t * pamh
832 ,const char *data_name
836 int retval = PAM_SUCCESS;
842 * make sure nothing inappropriate gets returned
845 *pass = token = NULL;
848 * which authentication token are we getting?
851 authtok_flag = on(UNIX__OLD_PASSWD, ctrl) ? PAM_OLDAUTHTOK : PAM_AUTHTOK;
854 * should we obtain the password from a PAM item ?
857 if (on(UNIX_TRY_FIRST_PASS, ctrl) || on(UNIX_USE_FIRST_PASS, ctrl)) {
858 retval = pam_get_item(pamh, authtok_flag, pass);
859 if (retval != PAM_SUCCESS) {
861 pam_syslog(pamh, LOG_ALERT,
862 "pam_get_item returned error to unix-read-password"
865 } else if (*pass != NULL) { /* we have a password! */
867 } else if (on(UNIX_USE_FIRST_PASS, ctrl)) {
868 return PAM_AUTHTOK_RECOVER_ERR; /* didn't work */
869 } else if (on(UNIX_USE_AUTHTOK, ctrl)
870 && off(UNIX__OLD_PASSWD, ctrl)) {
871 return PAM_AUTHTOK_ERR;
875 * getting here implies we will have to get the password from the
881 char *resp[2] = { NULL, NULL };
883 if (comment != NULL && off(UNIX__QUIET, ctrl)) {
884 retval = pam_info(pamh, "%s", comment);
887 if (retval == PAM_SUCCESS) {
888 retval = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF,
889 &resp[0], "%s", prompt1);
891 if (retval == PAM_SUCCESS && prompt2 != NULL) {
892 retval = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF,
893 &resp[1], "%s", prompt2);
898 if (resp[0] != NULL && resp[replies-1] != NULL) {
899 /* interpret the response */
901 if (retval == PAM_SUCCESS) { /* a good conversation */
906 /* verify that password entered correctly */
907 if (strcmp(token, resp[replies - 1])) {
909 retval = PAM_AUTHTOK_RECOVER_ERR;
910 _make_remark(pamh, ctrl,
911 PAM_ERROR_MSG, MISTYPED_PASS);
915 pam_syslog(pamh, LOG_NOTICE,
916 "could not recover authentication token");
922 retval = (retval == PAM_SUCCESS)
923 ? PAM_AUTHTOK_RECOVER_ERR : retval;
928 _pam_delete(resp[1]);
931 if (retval != PAM_SUCCESS) {
934 if (on(UNIX_DEBUG, ctrl))
935 pam_syslog(pamh, LOG_DEBUG,
936 "unable to obtain a password");
939 /* 'token' is the entered password */
941 if (off(UNIX_NOT_SET_PASS, ctrl)) {
943 /* we store this password as an item */
945 retval = pam_set_item(pamh, authtok_flag, token);
946 _pam_delete(token); /* clean it up */
947 if (retval != PAM_SUCCESS
948 || (retval = pam_get_item(pamh, authtok_flag, pass))
952 pam_syslog(pamh, LOG_CRIT, "error manipulating password");
958 * then store it as data specific to this module. pam_end()
959 * will arrange to clean it up.
962 retval = pam_set_data(pamh, data_name, (void *) token, _cleanup);
963 if (retval != PAM_SUCCESS) {
964 pam_syslog(pamh, LOG_CRIT,
965 "error manipulating password data [%s]",
966 pam_strerror(pamh, retval));
971 token = NULL; /* break link to password */
977 int _unix_shadowed(const struct passwd *pwd)
980 if (strcmp(pwd->pw_passwd, "x") == 0) {
983 if ((pwd->pw_passwd[0] == '#') &&
984 (pwd->pw_passwd[1] == '#') &&
985 (strcmp(pwd->pw_name, pwd->pw_passwd + 2) == 0)) {
992 /* ****************************************************************** *
993 * Copyright (c) Jan Rêkorajski 1999.
994 * Copyright (c) Andrew G. Morgan 1996-8.
995 * Copyright (c) Alex O. Yuriev, 1996.
996 * Copyright (c) Cristian Gafton 1996.
998 * Redistribution and use in source and binary forms, with or without
999 * modification, are permitted provided that the following conditions
1001 * 1. Redistributions of source code must retain the above copyright
1002 * notice, and the entire permission notice in its entirety,
1003 * including the disclaimer of warranties.
1004 * 2. Redistributions in binary form must reproduce the above copyright
1005 * notice, this list of conditions and the following disclaimer in the
1006 * documentation and/or other materials provided with the distribution.
1007 * 3. The name of the author may not be used to endorse or promote
1008 * products derived from this software without specific prior
1009 * written permission.
1011 * ALTERNATIVELY, this product may be distributed under the terms of
1012 * the GNU Public License, in which case the provisions of the GPL are
1013 * required INSTEAD OF the above restrictions. (This clause is
1014 * necessary due to a potential bad interaction between the GPL and
1015 * the restrictions contained in a BSD-style copyright.)
1017 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
1018 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1019 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1020 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
1021 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1022 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
1023 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1024 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
1025 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1026 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
1027 * OF THE POSSIBILITY OF SUCH DAMAGE.