Home | History | Annotate | Download | only in lib
      1 /*
      2  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 #pragma ident	"%Z%%M%	%I%	%E% SMI"
      6 
      7 /* SASL server API implementation
      8  * Rob Siemborski
      9  * Tim Martin
     10  * $Id: checkpw.c,v 1.62 2003/03/19 18:25:27 rjs3 Exp $
     11  */
     12 /*
     13  * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
     14  *
     15  * Redistribution and use in source and binary forms, with or without
     16  * modification, are permitted provided that the following conditions
     17  * are met:
     18  *
     19  * 1. Redistributions of source code must retain the above copyright
     20  *    notice, this list of conditions and the following disclaimer.
     21  *
     22  * 2. Redistributions in binary form must reproduce the above copyright
     23  *    notice, this list of conditions and the following disclaimer in
     24  *    the documentation and/or other materials provided with the
     25  *    distribution.
     26  *
     27  * 3. The name "Carnegie Mellon University" must not be used to
     28  *    endorse or promote products derived from this software without
     29  *    prior written permission. For permission or any other legal
     30  *    details, please contact
     31  *      Office of Technology Transfer
     32  *      Carnegie Mellon University
     33  *      5000 Forbes Avenue
     34  *      Pittsburgh, PA  15213-3890
     35  *      (412) 268-4387, fax: (412) 268-7395
     36  *      tech-transfer (at) andrew.cmu.edu
     37  *
     38  * 4. Redistributions of any form whatsoever must retain the following
     39  *    acknowledgment:
     40  *    "This product includes software developed by Computing Services
     41  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
     42  *
     43  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
     44  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
     45  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
     46  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     47  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
     48  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     49  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     50  */
     51 
     52 #include <config.h>
     53 
     54 /* checkpw stuff */
     55 
     56 #include <stdio.h>
     57 #include "sasl.h"
     58 #include "saslutil.h"
     59 #include "saslplug.h"
     60 #include "saslint.h"
     61 
     62 #include <assert.h>
     63 #ifdef HAVE_UNISTD_H
     64 #include <unistd.h>
     65 #endif
     66 #include <fcntl.h>
     67 #ifdef USE_DOORS
     68 #include <sys/mman.h>
     69 #include <door.h>
     70 #endif
     71 
     72 #include <stdlib.h>
     73 
     74 #ifndef WIN32
     75 #include <strings.h>
     76 #include <netdb.h>
     77 #include <netinet/in.h>
     78 #include <sys/un.h>
     79 #else
     80 #include <string.h>
     81 #endif
     82 
     83 #include <sys/types.h>
     84 #include <ctype.h>
     85 
     86 #ifdef HAVE_PWD_H
     87 #include <pwd.h>
     88 #endif /* HAVE_PWD_H */
     89 #ifdef HAVE_SHADOW_H
     90 #include <shadow.h>
     91 #endif /* HAVE_SHADOW_H */
     92 
     93 #if defined(HAVE_PWCHECK) || defined(HAVE_SASLAUTHD)
     94 # include <errno.h>
     95 # include <sys/types.h>
     96 # include <sys/socket.h>
     97 # include <sys/un.h>
     98 # ifdef HAVE_UNISTD_H
     99 #  include <unistd.h>
    100 # endif
    101 
    102 extern int errno;
    103 #endif
    104 
    105 
    106 /* we store the following secret to check plaintext passwords:
    107  *
    108  * <salt> \0 <secret>
    109  *
    110  * where <secret> = MD5(<salt>, "sasldb", <pass>)
    111  */
    112 #ifdef _SUN_SDK_
    113 static int _sasl_make_plain_secret(const sasl_utils_t *utils, const char *salt,
    114 				const char *passwd, size_t passlen,
    115 				sasl_secret_t **secret)
    116 #else
    117 static int _sasl_make_plain_secret(const char *salt,
    118 				   const char *passwd, size_t passlen,
    119 				   sasl_secret_t **secret)
    120 #endif /* _SUN_SDK_ */
    121 {
    122     MD5_CTX ctx;
    123     unsigned sec_len = 16 + 1 + 16; /* salt + "\0" + hash */
    124 
    125 #ifdef _SUN_SDK_
    126     *secret = (sasl_secret_t *)utils->malloc(sizeof(sasl_secret_t) +
    127 					sec_len * sizeof(char));
    128 #else
    129     *secret = (sasl_secret_t *) sasl_ALLOC(sizeof(sasl_secret_t) +
    130 					   sec_len * sizeof(char));
    131 #endif /* _SUN_SDK_ */
    132     if (*secret == NULL) {
    133 	return SASL_NOMEM;
    134     }
    135 
    136     _sasl_MD5Init(&ctx);
    137     _sasl_MD5Update(&ctx, salt, 16);
    138     _sasl_MD5Update(&ctx, "sasldb", 6);
    139     _sasl_MD5Update(&ctx, passwd, passlen);
    140     memcpy((*secret)->data, salt, 16);
    141     (*secret)->data[16] = '\0';
    142     _sasl_MD5Final((*secret)->data + 17, &ctx);
    143     (*secret)->len = sec_len;
    144 
    145     return SASL_OK;
    146 }
    147 
    148 /* erase & dispose of a sasl_secret_t
    149  */
    150 static int auxprop_verify_password(sasl_conn_t *conn,
    151 				   const char *userstr,
    152 				   const char *passwd,
    153 				   const char *service __attribute__((unused)),
    154 				   const char *user_realm __attribute__((unused)))
    155 {
    156     int ret = SASL_FAIL;
    157     char *userid = NULL;
    158 #ifndef _SUN_SDK_
    159     char *realm = NULL;
    160 #endif /* !_SUN_SDK_ */
    161     int result = SASL_OK;
    162     sasl_server_conn_t *sconn = (sasl_server_conn_t *)conn;
    163     const char *password_request[] = { SASL_AUX_PASSWORD,
    164 				       "*cmusaslsecretPLAIN",
    165 				       NULL };
    166     struct propval auxprop_values[3];
    167 
    168     if (!conn || !userstr)
    169 	return SASL_BADPARAM;
    170 
    171     /* We need to clear any previous results and re-canonify to
    172      * ensure correctness */
    173 
    174     prop_clear(sconn->sparams->propctx, 0);
    175 
    176     /* ensure its requested */
    177     result = prop_request(sconn->sparams->propctx, password_request);
    178 
    179     if(result != SASL_OK) return result;
    180 
    181     result = _sasl_canon_user(conn, userstr, 0,
    182 			      SASL_CU_AUTHID | SASL_CU_AUTHZID,
    183 			      &(conn->oparams));
    184     if(result != SASL_OK) return result;
    185 
    186     result = prop_getnames(sconn->sparams->propctx, password_request,
    187 			   auxprop_values);
    188     if(result < 0)
    189 	return result;
    190 
    191     if((!auxprop_values[0].name
    192          || !auxprop_values[0].values || !auxprop_values[0].values[0])
    193        && (!auxprop_values[1].name
    194          || !auxprop_values[1].values || !auxprop_values[1].values[0]))
    195 	    return SASL_NOUSER;
    196 
    197     /* It is possible for us to get useful information out of just
    198      * the lookup, so we won't check that we have a password until now */
    199     if(!passwd) {
    200 	ret = SASL_BADPARAM;
    201 	goto done;
    202     }
    203 
    204     /* At the point this has been called, the username has been canonified
    205      * and we've done the auxprop lookup.  This should be easy. */
    206     if(auxprop_values[0].name
    207        && auxprop_values[0].values
    208        && auxprop_values[0].values[0]
    209        && !strcmp(auxprop_values[0].values[0], passwd)) {
    210 	/* We have a plaintext version and it matched! */
    211 	return SASL_OK;
    212     } else if(auxprop_values[1].name
    213 	      && auxprop_values[1].values
    214 	      && auxprop_values[1].values[0]) {
    215 	const char *db_secret = auxprop_values[1].values[0];
    216 	sasl_secret_t *construct;
    217 
    218 #ifdef _SUN_SDK_
    219 	ret = _sasl_make_plain_secret(sconn->sparams->utils, db_secret,
    220 				passwd, strlen(passwd),
    221 				&construct);
    222 #else
    223 	ret = _sasl_make_plain_secret(db_secret, passwd,
    224 				      strlen(passwd),
    225 				      &construct);
    226 #endif /* _SUN_SDK_ */
    227 	if (ret != SASL_OK) {
    228 	    goto done;
    229 	}
    230 
    231 	if (!memcmp(db_secret, construct->data, construct->len)) {
    232 	    /* password verified! */
    233 	    ret = SASL_OK;
    234 	} else {
    235 	    /* passwords do not match */
    236 	    ret = SASL_BADAUTH;
    237 	}
    238 
    239 #ifdef _SUN_SDK_
    240 	sconn->sparams->utils->free(construct);
    241 #else
    242 	sasl_FREE(construct);
    243 #endif /* _SUN_SDK_ */
    244     } else {
    245 	/* passwords do not match */
    246 	ret = SASL_BADAUTH;
    247     }
    248 
    249  done:
    250 #ifdef _SUN_SDK_
    251     if (userid) sconn->sparams->utils->free(userid);
    252 #else
    253     if (userid) sasl_FREE(userid);
    254     if (realm)  sasl_FREE(realm);
    255 #endif /* _SUN_SDK_ */
    256 
    257     /* We're not going to erase the property here because other people
    258      * may want it */
    259     return ret;
    260 }
    261 
    262 #ifdef DO_SASL_CHECKAPOP
    263 int _sasl_auxprop_verify_apop(sasl_conn_t *conn,
    264 			      const char *userstr,
    265 			      const char *challenge,
    266 			      const char *response,
    267 			      const char *user_realm __attribute__((unused)))
    268 {
    269     int ret = SASL_BADAUTH;
    270     char *userid = NULL;
    271 #ifndef _SUN_SDK_
    272     char *realm = NULL;
    273 #endif /* !_SUN_SDK_ */
    274     unsigned char digest[16];
    275     char digeststr[33];
    276     const char *password_request[] = { SASL_AUX_PASSWORD, NULL };
    277     struct propval auxprop_values[2];
    278     sasl_server_conn_t *sconn = (sasl_server_conn_t *)conn;
    279     MD5_CTX ctx;
    280     int i;
    281 
    282     if (!conn || !userstr || !challenge || !response)
    283        PARAMERROR(conn)
    284 
    285     /* We've done the auxprop lookup already (in our caller) */
    286     /* sadly, APOP has no provision for storing secrets */
    287     ret = prop_getnames(sconn->sparams->propctx, password_request,
    288 			auxprop_values);
    289     if(ret < 0) {
    290 #ifdef _SUN_SDK_
    291 	_sasl_log(conn, SASL_LOG_ERR, "could not perform password lookup");
    292 #else
    293 	sasl_seterror(conn, 0, "could not perform password lookup");
    294 #endif /* _SUN_SDK_ */
    295 	goto done;
    296     }
    297 
    298     if(!auxprop_values[0].name ||
    299        !auxprop_values[0].values ||
    300        !auxprop_values[0].values[0]) {
    301 #ifdef _INTEGRATED_SOLARIS_
    302 	sasl_seterror(conn, 0, gettext("could not find password"));
    303 #else
    304 	sasl_seterror(conn, 0, "could not find password");
    305 #endif /* _INTEGRATED_SOLARIS_ */
    306 	ret = SASL_NOUSER;
    307 	goto done;
    308     }
    309 
    310     _sasl_MD5Init(&ctx);
    311     _sasl_MD5Update(&ctx, challenge, strlen(challenge));
    312     _sasl_MD5Update(&ctx, auxprop_values[0].values[0],
    313 		    strlen(auxprop_values[0].values[0]));
    314     _sasl_MD5Final(digest, &ctx);
    315 
    316     /* convert digest from binary to ASCII hex */
    317     for (i = 0; i < 16; i++)
    318       sprintf(digeststr + (i*2), "%02x", digest[i]);
    319 
    320     if (!strncasecmp(digeststr, response, 32)) {
    321       /* password verified! */
    322       ret = SASL_OK;
    323     } else {
    324       /* passwords do not match */
    325       ret = SASL_BADAUTH;
    326     }
    327 
    328  done:
    329 #ifdef _INTEGRATED_SOLARIS_
    330     if (ret == SASL_BADAUTH) sasl_seterror(conn, SASL_NOLOG,
    331 					   gettext("login incorrect"));
    332 #else
    333     if (ret == SASL_BADAUTH) sasl_seterror(conn, SASL_NOLOG,
    334 					   "login incorrect");
    335 #endif /* _INTEGRATED_SOLARIS_ */
    336 #ifdef _SUN_SDK_
    337     if (userid) sconn->sparams->utils->free(userid);
    338 #else
    339     if (userid) sasl_FREE(userid);
    340     if (realm)  sasl_FREE(realm);
    341 #endif /* _SUN_SDK_ */
    342 
    343     return ret;
    344 }
    345 #endif /* DO_SASL_CHECKAPOP */
    346 
    347 #if defined(HAVE_PWCHECK) || defined(HAVE_SASLAUTHD)
    348 /*
    349  * Keep calling the writev() system call with 'fd', 'iov', and 'iovcnt'
    350  * until all the data is written out or an error occurs.
    351  */
    352 static int retry_writev(int fd, struct iovec *iov, int iovcnt)
    353 {
    354     int n;
    355     int i;
    356     int written = 0;
    357     static int iov_max =
    358 #ifdef MAXIOV
    359 	MAXIOV
    360 #else
    361 #ifdef IOV_MAX
    362 	IOV_MAX
    363 #else
    364 	8192
    365 #endif
    366 #endif
    367 	;
    368 
    369     for (;;) {
    370 	while (iovcnt && iov[0].iov_len == 0) {
    371 	    iov++;
    372 	    iovcnt--;
    373 	}
    374 
    375 	if (!iovcnt) return written;
    376 
    377 	n = writev(fd, iov, iovcnt > iov_max ? iov_max : iovcnt);
    378 	if (n == -1) {
    379 	    if (errno == EINVAL && iov_max > 10) {
    380 		iov_max /= 2;
    381 		continue;
    382 	    }
    383 	    if (errno == EINTR) continue;
    384 	    return -1;
    385 	}
    386 
    387 	written += n;
    388 
    389 	for (i = 0; i < iovcnt; i++) {
    390 	    if (iov[i].iov_len > (unsigned) n) {
    391 		iov[i].iov_base = (char *)iov[i].iov_base + n;
    392 		iov[i].iov_len -= n;
    393 		break;
    394 	    }
    395 	    n -= iov[i].iov_len;
    396 	    iov[i].iov_len = 0;
    397 	}
    398 
    399 	if (i == iovcnt) return written;
    400     }
    401 }
    402 
    403 #endif
    404 
    405 #ifdef HAVE_PWCHECK
    406 /* pwcheck daemon-authenticated login */
    407 static int pwcheck_verify_password(sasl_conn_t *conn,
    408 				   const char *userid,
    409 				   const char *passwd,
    410 				   const char *service __attribute__((unused)),
    411 				   const char *user_realm
    412 				               __attribute__((unused)))
    413 {
    414     int s;
    415     struct sockaddr_un srvaddr;
    416     int r;
    417     struct iovec iov[10];
    418     static char response[1024];
    419     unsigned start, n;
    420     char pwpath[1024];
    421 
    422     if (strlen(PWCHECKDIR)+8+1 > sizeof(pwpath)) return SASL_FAIL;
    423 
    424     strcpy(pwpath, PWCHECKDIR);
    425     strcat(pwpath, "/pwcheck");
    426 
    427     s = socket(AF_UNIX, SOCK_STREAM, 0);
    428     if (s == -1) return errno;
    429 
    430     memset((char *)&srvaddr, 0, sizeof(srvaddr));
    431     srvaddr.sun_family = AF_UNIX;
    432     strncpy(srvaddr.sun_path, pwpath, sizeof(srvaddr.sun_path));
    433     r = connect(s, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
    434     if (r == -1) {
    435 	sasl_seterror(conn,0,"cannot connect to pwcheck server");
    436 	return SASL_FAIL;
    437     }
    438 
    439     iov[0].iov_base = (char *)userid;
    440     iov[0].iov_len = strlen(userid)+1;
    441     iov[1].iov_base = (char *)passwd;
    442     iov[1].iov_len = strlen(passwd)+1;
    443 
    444     retry_writev(s, iov, 2);
    445 
    446     start = 0;
    447     while (start < sizeof(response) - 1) {
    448 	n = read(s, response+start, sizeof(response) - 1 - start);
    449 	if (n < 1) break;
    450 	start += n;
    451     }
    452 
    453     close(s);
    454 
    455     if (start > 1 && !strncmp(response, "OK", 2)) {
    456 	return SASL_OK;
    457     }
    458 
    459     response[start] = '\0';
    460     sasl_seterror(conn,0,response);
    461     return SASL_BADAUTH;
    462 }
    463 
    464 #endif
    465 
    466 #ifdef HAVE_SASLAUTHD
    467 
    468 /*
    469  * Keep calling the read() system call with 'fd', 'buf', and 'nbyte'
    470  * until all the data is read in or an error occurs.
    471  */
    472 static int retry_read(int fd, void *buf0, unsigned nbyte)
    473 {
    474     int n;
    475     int nread = 0;
    476     char *buf = buf0;
    477 
    478     if (nbyte == 0) return 0;
    479 
    480     for (;;) {
    481 	n = read(fd, buf, nbyte);
    482 	if (n == -1 || n == 0) {
    483 	    if (errno == EINTR || errno == EAGAIN) continue;
    484 	    return -1;
    485 	}
    486 
    487 	nread += n;
    488 
    489 	if (nread >= (int) nbyte) return nread;
    490 
    491 	buf += n;
    492 	nbyte -= n;
    493     }
    494 }
    495 
    496 /* saslauthd-authenticated login */
    497 static int saslauthd_verify_password(sasl_conn_t *conn,
    498 				     const char *userid,
    499 				     const char *passwd,
    500 				     const char *service,
    501 				     const char *user_realm)
    502 {
    503     char response[1024];
    504     char query[8192];
    505     char *query_end = query;
    506     int s;
    507     struct sockaddr_un srvaddr;
    508     sasl_getopt_t *getopt;
    509     void *context;
    510     char pwpath[sizeof(srvaddr.sun_path)];
    511     const char *p = NULL;
    512 #ifdef USE_DOORS
    513     door_arg_t arg;
    514 #endif
    515 
    516     /* check to see if the user configured a rundir */
    517     if (_sasl_getcallback(conn, SASL_CB_GETOPT, &getopt, &context) == SASL_OK) {
    518 	getopt(context, NULL, "saslauthd_path", &p, NULL);
    519     }
    520     if (p) {
    521 	strncpy(pwpath, p, sizeof(pwpath));
    522     } else {
    523 	if (strlen(PATH_SASLAUTHD_RUNDIR) + 4 + 1 > sizeof(pwpath))
    524 	    return SASL_FAIL;
    525 
    526 	strcpy(pwpath, PATH_SASLAUTHD_RUNDIR);
    527 	strcat(pwpath, "/mux");
    528     }
    529 
    530     /*
    531      * build request of the form:
    532      *
    533      * count authid count password count service count realm
    534      */
    535     {
    536  	unsigned short u_len, p_len, s_len, r_len;
    537 
    538  	u_len = (strlen(userid));
    539  	p_len = (strlen(passwd));
    540 	s_len = (strlen(service));
    541 	r_len = ((user_realm ? strlen(user_realm) : 0));
    542 
    543 	if (u_len + p_len + s_len + r_len + 30 > (unsigned short) sizeof(query)) {
    544 	    /* request just too damn big */
    545             sasl_seterror(conn, 0, "saslauthd request too large");
    546 	    return SASL_FAIL;
    547 	}
    548 
    549 	u_len = htons(u_len);
    550 	p_len = htons(p_len);
    551 	s_len = htons(s_len);
    552 	r_len = htons(r_len);
    553 
    554 	memcpy(query_end, &u_len, sizeof(unsigned short));
    555 	query_end += sizeof(unsigned short);
    556 	while (*userid) *query_end++ = *userid++;
    557 
    558 	memcpy(query_end, &p_len, sizeof(unsigned short));
    559 	query_end += sizeof(unsigned short);
    560 	while (*passwd) *query_end++ = *passwd++;
    561 
    562 	memcpy(query_end, &s_len, sizeof(unsigned short));
    563 	query_end += sizeof(unsigned short);
    564 	while (*service) *query_end++ = *service++;
    565 
    566 	memcpy(query_end, &r_len, sizeof(unsigned short));
    567 	query_end += sizeof(unsigned short);
    568 	if (user_realm) while (*user_realm) *query_end++ = *user_realm++;
    569     }
    570 
    571 #ifdef USE_DOORS
    572     s = open(pwpath, O_RDONLY);
    573     if (s < 0) {
    574 	sasl_seterror(conn, 0, "cannot open door to saslauthd server: %m", errno);
    575 	return SASL_FAIL;
    576     }
    577 
    578     arg.data_ptr = query;
    579     arg.data_size = query_end - query;
    580     arg.desc_ptr = NULL;
    581     arg.desc_num = 0;
    582     arg.rbuf = response;
    583     arg.rsize = sizeof(response);
    584 
    585     door_call(s, &arg);
    586 
    587     if (arg.data_ptr != response || arg.data_size >= sizeof(response)) {
    588 	/* oh damn, we got back a really long response */
    589 	munmap(arg.rbuf, arg.rsize);
    590 	sasl_seterror(conn, 0, "saslauthd sent an overly long response");
    591 	return SASL_FAIL;
    592     }
    593     response[arg.data_size] = '\0';
    594 
    595     close(s);
    596 #else
    597     /* unix sockets */
    598 
    599     s = socket(AF_UNIX, SOCK_STREAM, 0);
    600     if (s == -1) {
    601 	sasl_seterror(conn, 0, "cannot create socket for saslauthd: %m", errno);
    602 	return SASL_FAIL;
    603     }
    604 
    605     memset((char *)&srvaddr, 0, sizeof(srvaddr));
    606     srvaddr.sun_family = AF_UNIX;
    607     strncpy(srvaddr.sun_path, pwpath, sizeof(srvaddr.sun_path));
    608 
    609     {
    610 	int r = connect(s, (struct sockaddr *) &srvaddr, sizeof(srvaddr));
    611 	if (r == -1) {
    612 	    sasl_seterror(conn, 0, "cannot connect to saslauthd server: %m", errno);
    613 	    return SASL_FAIL;
    614 	}
    615     }
    616 
    617     {
    618  	struct iovec iov[8];
    619 
    620 	iov[0].iov_len = query_end - query;
    621 	iov[0].iov_base = query;
    622 
    623 	if (retry_writev(s, iov, 1) == -1) {
    624             sasl_seterror(conn, 0, "write failed");
    625   	    return SASL_FAIL;
    626   	}
    627     }
    628 
    629     {
    630 	unsigned short count = 0;
    631 
    632 	/*
    633 	 * read response of the form:
    634 	 *
    635 	 * count result
    636 	 */
    637 	if (retry_read(s, &count, sizeof(count)) < (int) sizeof(count)) {
    638 	    sasl_seterror(conn, 0, "size read failed");
    639 	    return SASL_FAIL;
    640 	}
    641 
    642 	count = ntohs(count);
    643 	if (count < 2) { /* MUST have at least "OK" or "NO" */
    644 	    close(s);
    645 	    sasl_seterror(conn, 0, "bad response from saslauthd");
    646 	    return SASL_FAIL;
    647 	}
    648 
    649 	count = (int)sizeof(response) < count ? sizeof(response) : count;
    650 	if (retry_read(s, response, count) < count) {
    651 	    close(s);
    652 	    sasl_seterror(conn, 0, "read failed");
    653 	    return SASL_FAIL;
    654 	}
    655 	response[count] = '\0';
    656     }
    657 
    658     close(s);
    659 #endif /* USE_DOORS */
    660 
    661     if (!strncmp(response, "OK", 2)) {
    662 	return SASL_OK;
    663     }
    664 
    665     sasl_seterror(conn, SASL_NOLOG, "authentication failed");
    666     return SASL_BADAUTH;
    667 }
    668 
    669 #endif
    670 
    671 #ifdef HAVE_ALWAYSTRUE
    672 static int always_true(sasl_conn_t *conn,
    673 		       const char *userstr,
    674 		       const char *passwd __attribute__((unused)),
    675 		       const char *service __attribute__((unused)),
    676 		       const char *user_realm __attribute__((unused)))
    677 {
    678     _sasl_log(conn, SASL_LOG_WARN, "AlwaysTrue Password Verifier Verified: %s",
    679 	      userstr);
    680     return SASL_OK;
    681 }
    682 #endif
    683 
    684 struct sasl_verify_password_s _sasl_verify_password[] = {
    685     { "auxprop", &auxprop_verify_password },
    686 #ifdef HAVE_PWCHECK
    687     { "pwcheck", &pwcheck_verify_password },
    688 #endif
    689 #ifdef HAVE_SASLAUTHD
    690     { "saslauthd", &saslauthd_verify_password },
    691 #endif
    692 #ifdef HAVE_ALWAYSTRUE
    693     { "alwaystrue", &always_true },
    694 #endif
    695     { NULL, NULL }
    696 };
    697