4 * Copyright information at end of file.
8 * here is the string to inform the user that the new passwords they
9 * typed were not the same.
12 #define MISTYPED_PASS "Sorry, passwords do not match"
14 /* type definition for the control options */
18 unsigned int mask; /* shall assume 32 bits of flags */
23 * macro to determine if a given flag is on
26 #define on(x,ctrl) (unix_args[x].flag & ctrl)
29 * macro to determine that a given flag is NOT on
32 #define off(x,ctrl) (!on(x,ctrl))
35 * macro to turn on/off a ctrl flag manually
38 #define set(x,ctrl) (ctrl = ((ctrl)&unix_args[x].mask)|unix_args[x].flag)
39 #define unset(x,ctrl) (ctrl &= ~(unix_args[x].flag))
41 /* the generic mask */
43 #define _ALL_ON_ (~0U)
45 /* end of macro definitions definitions for the control flags */
47 /* ****************************************************************** *
52 * here are the various options recognized by the unix module. They
53 * are enumerated here and then defined below. Internal arguments are
57 #define UNIX__OLD_PASSWD 0 /* internal */
58 #define UNIX__VERIFY_PASSWD 1 /* internal */
59 #define UNIX__IAMROOT 2 /* internal */
61 #define UNIX_AUDIT 3 /* print more things than debug..
62 some information may be sensitive */
63 #define UNIX_USE_FIRST_PASS 4
64 #define UNIX_TRY_FIRST_PASS 5
65 #define UNIX_NOT_SET_PASS 6 /* don't set the AUTHTOK items */
67 #define UNIX__PRELIM 7 /* internal */
68 #define UNIX__UPDATE 8 /* internal */
69 #define UNIX__NONULL 9 /* internal */
70 #define UNIX__QUIET 10 /* internal */
71 #define UNIX_USE_AUTHTOK 11 /* insist on reading PAM_AUTHTOK */
72 #define UNIX_SHADOW 12 /* signal shadow on */
73 #define UNIX_MD5_PASS 13 /* force the use of MD5 passwords */
74 #define UNIX__NULLOK 14 /* Null token ok */
75 #define UNIX_RADIUS 15 /* wish to use RADIUS for password */
76 #define UNIX__SET_DB 16 /* internal - signals redirect to db */
77 #define UNIX_DEBUG 17 /* send more info to syslog(3) */
78 #define UNIX_NODELAY 18 /* admin does not want a fail-delay */
79 #define UNIX_UNIX 19 /* wish to use /etc/passwd for pwd */
80 #define UNIX_BIGCRYPT 20 /* use DEC-C2 crypt()^x function */
81 #define UNIX_LIKE_AUTH 21 /* need to auth for setcred to work */
82 #define UNIX_NOREAP 22 /* don't reap child process */
84 #define UNIX_CTRLS_ 23 /* number of ctrl arguments defined */
87 static const UNIX_Ctrls unix_args[UNIX_CTRLS_] = {
88 /* symbol token name ctrl mask ctrl *
89 * ------------------ ------------------ -------------- ---------- */
91 /* UNIX__OLD_PASSWD */ { NULL, _ALL_ON_, 01 },
92 /* UNIX__VERIFY_PASSWD */ { NULL, _ALL_ON_, 02 },
93 /* UNIX__IAMROOT */ { NULL, _ALL_ON_, 04 },
94 /* UNIX_AUDIT */ { "audit", _ALL_ON_, 010 },
95 /* UNIX_USE_FIRST_PASS */ { "use_first_pass", _ALL_ON_^(060), 020 },
96 /* UNIX_TRY_FIRST_PASS */ { "try_first_pass", _ALL_ON_^(060), 040 },
97 /* UNIX_NOT_SET_PASS */ { "not_set_pass", _ALL_ON_, 0100 },
98 /* UNIX__PRELIM */ { NULL, _ALL_ON_^(0600), 0200 },
99 /* UNIX__UPDATE */ { NULL, _ALL_ON_^(0600), 0400 },
100 /* UNIX__NONULL */ { NULL, _ALL_ON_, 01000 },
101 /* UNIX__QUIET */ { NULL, _ALL_ON_, 02000 },
102 /* UNIX_USE_AUTHTOK */ { "use_authtok", _ALL_ON_, 04000 },
103 /* UNIX_SHADOW */ { "shadow", _ALL_ON_^(0140000), 010000 },
104 /* UNIX_MD5_PASS */ { "md5", _ALL_ON_^(02000000), 020000 },
105 /* UNIX__NULLOK */ { "nullok", _ALL_ON_^(01000), 0 },
106 /* UNIX_RADIUS */ { "radius", _ALL_ON_^(0110000), 040000 },
107 /* UNIX__SET_DB */ { NULL, _ALL_ON_, 0100000 },
108 /* UNIX_DEBUG */ { "debug", _ALL_ON_, 0200000 },
109 /* UNIX_NODELAY */ { "nodelay", _ALL_ON_, 0400000 },
110 /* UNIX_UNIX */ { "unix", _ALL_ON_^(050000), 01000000 },
111 /* UNIX_BIGCRYPT */ { "bigcrypt", _ALL_ON_^(020000), 02000000 },
112 /* UNIX_LIKE_AUTH */ { "likeauth", _ALL_ON_, 04000000 },
113 /* UNIX_NOREAP */ {"noreap", _ALL_ON_, 010000000 },
116 #define UNIX_DEFAULTS (unix_args[UNIX__NONULL].flag)
118 /* syslogging function for errors and other information */
120 static void _log_err(int err, const char *format, ...)
124 va_start(args, format);
125 openlog("PAM_pwdb", LOG_CONS|LOG_PID, LOG_AUTH);
126 vsyslog(err, format, args);
131 /* this is a front-end for module-application conversations */
133 static int converse(pam_handle_t *pamh, int ctrl, int nargs
134 , struct pam_message **message
135 , struct pam_response **response)
138 struct pam_conv *conv;
140 D(("begin to converse"));
142 retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ;
143 if ( retval == PAM_SUCCESS ) {
145 retval = conv->conv(nargs, ( const struct pam_message ** ) message
146 , response, conv->appdata_ptr);
148 D(("returned from application's conversation function"));
150 if (retval != PAM_SUCCESS && on(UNIX_DEBUG,ctrl) ) {
151 _log_err(LOG_DEBUG, "conversation failure [%s]"
152 , pam_strerror(pamh, retval));
155 } else if (retval != PAM_CONV_AGAIN) {
156 _log_err(LOG_ERR, "couldn't obtain coversation function [%s]"
157 , pam_strerror(pamh, retval));
160 D(("ready to return from module conversation"));
162 return retval; /* propagate error status */
165 static int make_remark(pam_handle_t *pamh, unsigned int ctrl
166 , int type, const char *text)
168 int retval=PAM_SUCCESS;
170 if ( off(UNIX__QUIET, ctrl) ) {
171 struct pam_message *pmsg[1], msg[1];
172 struct pam_response *resp;
176 msg[0].msg_style = type;
179 retval = converse(pamh, ctrl, 1, pmsg, &resp);
182 _pam_drop_reply(resp, 1);
189 * set the control flags for the UNIX module.
192 static int set_ctrl(int flags, int argc, const char **argv)
198 ctrl = UNIX_DEFAULTS; /* the default selection of options */
200 /* set some flags manually */
202 if ( getuid() == 0 && !(flags & PAM_CHANGE_EXPIRED_AUTHTOK) ) {
203 set(UNIX__IAMROOT, ctrl);
205 if ( flags & PAM_UPDATE_AUTHTOK ) {
206 set(UNIX__UPDATE, ctrl);
208 if ( flags & PAM_PRELIM_CHECK ) {
209 set(UNIX__PRELIM, ctrl);
211 if ( flags & PAM_DISALLOW_NULL_AUTHTOK ) {
212 set(UNIX__NONULL, ctrl);
214 if ( flags & PAM_SILENT ) {
215 set(UNIX__QUIET, ctrl);
218 /* now parse the arguments to this module */
223 D(("pam_pwdb arg: %s",*argv));
225 for (j=0; j<UNIX_CTRLS_; ++j) {
226 if (unix_args[j].token
227 && ! strcmp(*argv, unix_args[j].token) ) {
232 if ( j >= UNIX_CTRLS_ ) {
233 _log_err(LOG_ERR, "unrecognized option [%s]",*argv);
235 ctrl &= unix_args[j].mask; /* for turning things off */
236 ctrl |= unix_args[j].flag; /* for turning things on */
239 ++argv; /* step to next argument */
242 /* these are used for updating passwords in specific places */
244 if (on(UNIX_SHADOW,ctrl) || on(UNIX_RADIUS,ctrl) || on(UNIX_UNIX,ctrl)) {
245 set(UNIX__SET_DB, ctrl);
248 /* auditing is a more sensitive version of debug */
250 if ( on(UNIX_AUDIT,ctrl) ) {
251 set(UNIX_DEBUG, ctrl);
254 /* return the set of flags */
260 /* use this to free strings. ESPECIALLY password strings */
262 static char *_pam_delete(register char *xx)
269 static void _cleanup(pam_handle_t *pamh, void *x, int error_status)
271 x = _pam_delete( (char *) x );
274 /* ************************************************************** *
275 * Useful non-trivial functions *
276 * ************************************************************** */
278 #include "pam_unix_md.-c"
281 * the following is used to keep track of the number of times a user fails
282 * to authenticate themself.
285 #define FAIL_PREFIX "-UN*X-FAIL-"
286 #define UNIX_MAX_RETRIES 3
288 struct _pam_failed_auth {
289 char *user; /* user that's failed to be authenticated */
290 char *name; /* attempt from user with name */
291 int id; /* uid of name'd user */
292 int count; /* number of failures so far */
295 #ifndef PAM_DATA_REPLACE
296 #error "Need to get an updated libpam 0.52 or better"
299 static void _cleanup_failures(pam_handle_t *pamh, void *fl, int err)
302 const char *service=NULL;
303 struct _pam_failed_auth *failure;
307 quiet = err & PAM_DATA_SILENT; /* should we log something? */
308 err &= PAM_DATA_REPLACE; /* are we just replacing data? */
309 failure = (struct _pam_failed_auth *) fl;
311 if ( failure != NULL ) {
313 if ( !quiet && !err ) { /* under advisement from Sun,may go away */
315 /* log the number of authentication failures */
316 if ( failure->count > 1 ) {
317 (void) pam_get_item(pamh, PAM_SERVICE
318 , (const void **)&service);
320 , "%d more authentication failure%s; %s(uid=%d) -> "
322 , failure->count-1, failure->count==2 ? "":"s"
326 , service == NULL ? "**unknown**":service
328 if ( failure->count > UNIX_MAX_RETRIES ) {
330 , "service(%s) ignoring max retries; %d > %d"
331 , service == NULL ? "**unknown**":service
333 , UNIX_MAX_RETRIES );
337 failure->user = _pam_delete(failure->user); /* tidy up */
338 failure->name = _pam_delete(failure->name); /* tidy up */
344 * verify the password of a user
348 #include <sys/types.h>
349 #include <sys/wait.h>
351 static int pwdb_run_helper_binary(pam_handle_t *pamh, const char *passwd,
352 unsigned int ctrl, const char *user)
354 int retval, child, fds[2];
355 void (*sighandler)(int) = NULL;
358 /* create a pipe for the password */
359 if (pipe(fds) != 0) {
360 D(("could not make pipe"));
364 if (off(UNIX_NOREAP, ctrl)) {
366 * This code arranges that the demise of the child does not cause
367 * the application to receive a signal it is not expecting - which
368 * may kill the application or worse.
370 * The "noreap" module argument is provided so that the admin can
371 * override this behavior.
373 sighandler = signal(SIGCHLD, SIG_IGN);
379 static char *args[] = { NULL, NULL, NULL };
380 static char *envp[] = { NULL };
382 /* XXX - should really tidy up PAM here too */
383 while (pwdb_end() == PWDB_SUCCESS);
385 /* reopen stdin as pipe */
387 dup2(fds[0], STDIN_FILENO);
389 /* exec binary helper */
390 args[0] = x_strdup(CHKPWD_HELPER);
391 args[1] = x_strdup(user);
393 execve(CHKPWD_HELPER, args, envp);
395 /* should not get here: exit with error */
396 D(("helper binary is not available"));
397 exit(PWDB_SUCCESS+1);
398 } else if (child > 0) {
400 if (passwd != NULL) { /* send the password to the child */
401 write(fds[1], passwd, strlen(passwd)+1);
404 write(fds[1], "", 1); /* blank password */
406 close(fds[0]); /* we close this after the write because we want
407 to avoid a possible SIGPIPE. */
409 (void) waitpid(child, &retval, 0); /* wait for helper to complete */
410 retval = (retval == PWDB_SUCCESS) ? PAM_SUCCESS:PAM_AUTH_ERR;
413 retval = PAM_AUTH_ERR;
416 if (sighandler != NULL) {
417 (void) signal(SIGCHLD, sighandler); /* restore old signal handler */
420 D(("returning %d", retval));
424 static int _unix_verify_password(pam_handle_t *pamh, const char *name,
425 const char *p, unsigned int ctrl)
427 const struct pwdb *pw=NULL;
428 const struct pwdb_entry *pwe=NULL;
438 #ifdef HAVE_PAM_FAIL_DELAY
439 if ( off(UNIX_NODELAY, ctrl) ) {
440 D(("setting delay"));
441 (void) pam_fail_delay(pamh, 1000000); /* 1 sec delay for on failure */
445 /* locate the entry for this user */
447 D(("locating user's record"));
448 retval = pwdb_locate("user", PWDB_DEFAULT, name, PWDB_ID_UNKNOWN, &pw);
449 if (retval == PWDB_PASS_PHRASE_REQD) {
451 * give the password to the pwdb library. It may be needed to
452 * access the database
455 retval = pwdb_set_entry( pw, "pass_phrase", p, 1+strlen(p)
457 if (retval != PWDB_SUCCESS) {
458 _log_err(LOG_ALERT, "find pass; %s", pwdb_strerror(retval));
459 (void) pwdb_delete(&pw);
461 return PAM_CRED_INSUFFICIENT;
464 retval = pwdb_locate("user", pw->source, name, PWDB_ID_UNKNOWN, &pw);
467 if (retval != PWDB_SUCCESS) {
468 D(("user's record unavailable"));
469 if ( on(UNIX_AUDIT, ctrl) ) {
470 /* this might be a typo and the user has given a password
471 instead of a username. Careful with this. */
472 _log_err(LOG_ALERT, "check pass; user (%s) unknown", name);
474 _log_err(LOG_ALERT, "check pass; user unknown");
476 (void) pwdb_delete(&pw);
478 return PAM_USER_UNKNOWN;
482 * courtesy of PWDB the password for the user is stored in
483 * encrypted form in the "passwd" entry of pw.
486 retval = pwdb_get_entry(pw, "passwd", &pwe);
487 if (retval != PWDB_SUCCESS) {
489 /* we are not root perhaps this is the reason? Run helper */
490 D(("running helper binary"));
491 retval = pwdb_run_helper_binary(pamh, p, ctrl, name);
493 retval = PAM_AUTHINFO_UNAVAIL;
494 _log_err(LOG_ALERT, "get passwd; %s", pwdb_strerror(retval));
496 (void) pwdb_delete(&pw);
500 salt = (const char *) pwe->value;
503 * XXX: Cristian, the above is not the case for RADIUS(?) Some
504 * lines should be added for RADIUS to verify the password in
508 data_name = (char *) malloc(sizeof(FAIL_PREFIX)+strlen(name));
509 if ( data_name == NULL ) {
510 _log_err(LOG_CRIT, "no memory for data-name");
512 strcpy(data_name, FAIL_PREFIX);
513 strcpy(data_name + sizeof(FAIL_PREFIX)-1, name);
515 if ( !( (salt && *salt) || (p && *p) ) ) {
517 D(("two null passwords to compare"));
519 /* the stored password is NULL */
521 if ( off(UNIX__NONULL, ctrl ) ) { /* this means we've succeeded */
522 verify_result = PAM_SUCCESS;
524 verify_result = PAM_AUTH_ERR;
527 } else if ( !( salt && p ) ) {
529 D(("one of the two to compare are NULL"));
532 verify_result = PAM_AUTH_ERR;
536 /* there is no way that p can be NULL (one can be "") */
537 pp = _pam_md(p, salt);
539 /* the moment of truth -- do we agree with the password? */
540 D(("comparing state of pp[%s] and salt[%s]", pp, salt));
542 if ( strcmp( pp, salt ) == 0 ) {
543 verify_result = PAM_SUCCESS;
546 pp = _pam_md_compat(p, salt);
547 if ( strcmp( pp, salt ) == 0 ) {
548 verify_result = PAM_SUCCESS;
550 verify_result = PAM_AUTH_ERR;
554 p = NULL; /* no longer needed here */
558 if ( verify_result == PAM_SUCCESS ) {
560 retval = PAM_SUCCESS;
561 if (data_name) { /* reset failures */
562 pam_set_data(pamh, data_name, NULL, _cleanup_failures);
567 retval = PAM_AUTH_ERR;
568 if (data_name != NULL) {
569 struct _pam_failed_auth *new=NULL;
570 const struct _pam_failed_auth *old=NULL;
572 /* get a failure recorder */
574 new = (struct _pam_failed_auth *)
575 malloc(sizeof(struct _pam_failed_auth));
579 new->user = x_strdup(name);
581 new->name = x_strdup(getlogin() ? getlogin():"" );
583 /* any previous failures for this user ? */
584 pam_get_data(pamh, data_name, (const void **)&old );
587 new->count = old->count +1;
588 if (new->count >= UNIX_MAX_RETRIES) {
589 retval = PAM_MAXTRIES;
592 const char *service=NULL;
593 (void) pam_get_item(pamh, PAM_SERVICE
594 , (const void **)&service);
596 , "authentication failure; %s(uid=%d) -> "
601 , service == NULL ? "**unknown**":service
606 pam_set_data(pamh, data_name, new, _cleanup_failures);
609 _log_err(LOG_CRIT, "no memory for failure recorder");
615 (void) pwdb_entry_delete(&pwe);
616 (void) pwdb_delete(&pw);
618 _pam_delete(data_name);
621 D(("done [%d].", retval));
627 * this function obtains the name of the current user and ensures
628 * that the PAM_USER item is set to this value
631 static int _unix_get_user(pam_handle_t *pamh, unsigned int ctrl
632 , const char *prompt, const char **user)
638 retval = pam_get_user(pamh, user, prompt);
639 if (retval != PAM_SUCCESS) {
640 D(("trouble reading username"));
645 * Various libraries at various times have had bugs related to
646 * '+' or '-' as the first character of a user name. Don't take
647 * any chances here. Require that the username starts with an
648 * alphanumeric character.
651 if (*user == NULL || !isalnum(**user)) {
653 if (on(UNIX_DEBUG,ctrl)) {
654 _log_err(LOG_ERR, "bad username [%s]", *user);
656 return PAM_USER_UNKNOWN;
659 if (retval == PAM_SUCCESS && on(UNIX_DEBUG,ctrl)) {
660 _log_err(LOG_DEBUG, "username [%s] obtained", *user);
667 * _unix_blankpasswd() is a quick check for a blank password
669 * returns TRUE if user does not have a password
670 * - to avoid prompting for one in such cases (CG)
673 static int _unix_blankpasswd(unsigned int ctrl, const char *name)
675 const struct pwdb *pw=NULL;
676 const struct pwdb_entry *pwe=NULL;
682 * This function does not have to be too smart if something goes
683 * wrong, return FALSE and let this case to be treated somewhere
687 if ( on(UNIX__NONULL, ctrl) )
688 return 0; /* will fail but don't let on yet */
690 /* find the user's database entry */
692 retval = pwdb_locate("user", PWDB_DEFAULT, name, PWDB_ID_UNKNOWN, &pw);
693 if (retval != PWDB_SUCCESS || pw == NULL ) {
699 /* Does this user have a password? */
701 retval = pwdb_get_entry(pw, "passwd", &pwe);
702 if ( retval != PWDB_SUCCESS || pwe == NULL )
704 else if ( pwe->value == NULL || ((char *)pwe->value)[0] == '\0' )
714 (void) pwdb_delete(&pw);
716 (void) pwdb_entry_delete(&pwe);
723 * obtain a password from the user
726 static int _unix_read_password( pam_handle_t *pamh
728 , const char *comment
729 , const char *prompt1
730 , const char *prompt2
731 , const char *data_name
732 , const char **pass )
742 * make sure nothing inappropriate gets returned
745 *pass = token = NULL;
748 * which authentication token are we getting?
751 authtok_flag = on(UNIX__OLD_PASSWD,ctrl) ? PAM_OLDAUTHTOK:PAM_AUTHTOK ;
754 * should we obtain the password from a PAM item ?
757 if ( on(UNIX_TRY_FIRST_PASS,ctrl) || on(UNIX_USE_FIRST_PASS,ctrl) ) {
758 retval = pam_get_item(pamh, authtok_flag, (const void **) &item);
759 if (retval != PAM_SUCCESS ) {
762 , "pam_get_item returned error to unix-read-password"
765 } else if (item != NULL) { /* we have a password! */
769 } else if (on(UNIX_USE_FIRST_PASS,ctrl)) {
770 return PAM_AUTHTOK_RECOVER_ERR; /* didn't work */
771 } else if (on(UNIX_USE_AUTHTOK, ctrl)
772 && off(UNIX__OLD_PASSWD, ctrl)) {
773 return PAM_AUTHTOK_RECOVER_ERR;
778 * getting here implies we will have to get the password from the
783 struct pam_message msg[3],*pmsg[3];
784 struct pam_response *resp;
787 /* prepare to converse */
789 if ( comment != NULL && off(UNIX__QUIET, ctrl) ) {
791 msg[0].msg_style = PAM_TEXT_INFO;
792 msg[0].msg = comment;
799 msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
800 msg[i++].msg = prompt1;
803 if ( prompt2 != NULL ) {
805 msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
806 msg[i++].msg = prompt2;
810 /* so call the conversation expecting i responses */
812 retval = converse(pamh, ctrl, i, pmsg, &resp);
816 /* interpret the response */
818 if (retval == PAM_SUCCESS) { /* a good conversation */
820 token = x_strdup(resp[i-replies].resp);
824 /* verify that password entered correctly */
826 || strcmp(token,resp[i-1].resp)) {
827 token = _pam_delete(token); /* mistyped */
828 retval = PAM_AUTHTOK_RECOVER_ERR;
829 make_remark(pamh, ctrl
830 , PAM_ERROR_MSG, MISTYPED_PASS);
836 , "could not recover authentication token");
842 * tidy up the conversation (resp_retcode) is ignored
843 * -- what is it for anyway? AGM
846 _pam_drop_reply(resp, i);
849 retval = (retval == PAM_SUCCESS)
850 ? PAM_AUTHTOK_RECOVER_ERR:retval ;
854 if (retval != PAM_SUCCESS) {
855 if ( on(UNIX_DEBUG,ctrl) )
856 _log_err(LOG_DEBUG,"unable to obtain a password");
860 /* 'token' is the entered password */
862 if ( off(UNIX_NOT_SET_PASS, ctrl) ) {
864 /* we store this password as an item */
866 retval = pam_set_item(pamh, authtok_flag, token);
867 token = _pam_delete(token); /* clean it up */
868 if ( retval != PAM_SUCCESS
869 || (retval = pam_get_item(pamh, authtok_flag
870 , (const void **)&item))
873 _log_err(LOG_CRIT, "error manipulating password");
880 * then store it as data specific to this module. pam_end()
881 * will arrange to clean it up.
884 retval = pam_set_data(pamh, data_name, (void *) token, _cleanup);
885 if (retval != PAM_SUCCESS) {
886 _log_err(LOG_CRIT, "error manipulating password data [%s]"
887 , pam_strerror(pamh, retval) );
888 token = _pam_delete(token);
892 token = NULL; /* break link to password */
896 item = NULL; /* break link to password */
901 static int _pam_unix_approve_pass(pam_handle_t *pamh
903 , const char *pass_old
904 , const char *pass_new)
906 D(("&new=%p, &old=%p",pass_old,pass_new));
907 D(("new=[%s]",pass_new));
908 D(("old=[%s]",pass_old));
910 if (pass_new == NULL || (pass_old && !strcmp(pass_old,pass_new))) {
911 if ( on(UNIX_DEBUG, ctrl) ) {
912 _log_err(LOG_DEBUG, "bad authentication token");
914 make_remark(pamh, ctrl, PAM_ERROR_MSG, pass_new == NULL ?
915 "No password supplied":"Password unchanged" );
916 return PAM_AUTHTOK_ERR;
920 * if one wanted to hardwire authentication token strength
921 * checking this would be the place - AGM
927 /* ****************************************************************** *
928 * Copyright (c) Andrew G. Morgan 1996-8.
929 * Copyright (c) Alex O. Yuriev, 1996.
930 * Copyright (c) Cristian Gafton 1996.
932 * Redistribution and use in source and binary forms, with or without
933 * modification, are permitted provided that the following conditions
935 * 1. Redistributions of source code must retain the above copyright
936 * notice, and the entire permission notice in its entirety,
937 * including the disclaimer of warranties.
938 * 2. Redistributions in binary form must reproduce the above copyright
939 * notice, this list of conditions and the following disclaimer in the
940 * documentation and/or other materials provided with the distribution.
941 * 3. The name of the author may not be used to endorse or promote
942 * products derived from this software without specific prior
943 * written permission.
945 * ALTERNATIVELY, this product may be distributed under the terms of
946 * the GNU Public License, in which case the provisions of the GPL are
947 * required INSTEAD OF the above restrictions. (This clause is
948 * necessary due to a potential bad interaction between the GPL and
949 * the restrictions contained in a BSD-style copyright.)
951 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
952 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
953 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
954 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
955 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
956 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
957 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
958 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
959 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
960 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
961 * OF THE POSSIBILITY OF SUCH DAMAGE.