diff options
Diffstat (limited to 'ldap/c-sdk/libraries/libldap/saslio.c')
-rw-r--r-- | ldap/c-sdk/libraries/libldap/saslio.c | 635 |
1 files changed, 0 insertions, 635 deletions
diff --git a/ldap/c-sdk/libraries/libldap/saslio.c b/ldap/c-sdk/libraries/libldap/saslio.c deleted file mode 100644 index 6ab6303d0..000000000 --- a/ldap/c-sdk/libraries/libldap/saslio.c +++ /dev/null @@ -1,635 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Sun LDAP C SDK. - * - * The Initial Developer of the Original Code is Sun Microsystems, Inc. - * - * Portions created by Sun Microsystems, Inc are Copyright (C) 2005 - * Sun Microsystems, Inc. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifdef LDAP_SASLIO_HOOKS -#include <assert.h> -#include "ldap-int.h" -#include "../liblber/lber-int.h" -#include <sasl.h> -/* Should be pulled in from lber-int.h */ -#define READBUFSIZ 8192 - -#define SEARCH_TIMEOUT_SECS 120 -#define NSLDAPI_SM_BUF 128 - -/* - * Data structures: - */ - -/* data structure that populates the I/O callback socket-specific arg. */ -typedef struct lextiof_socket_private { - struct ldap_x_ext_io_fns sess_io_fns; /* the saved layered ld fns from the layer we are "pushing" */ - struct lber_x_ext_io_fns sock_io_fns; /* the saved layered ber fns from the layer we are "pushing" */ - sasl_conn_t *sasl_ctx; /* the sasl context - pointer to the one from the connection */ - char *sb_sasl_ibuf; /* sasl decrypted input buffer */ - char *sb_sasl_iptr; /* current location in buffer */ - int sb_sasl_bfsz; /* Alloc'd size of input buffer */ - int sb_sasl_ilen; /* remaining length to process */ - LDAP *ld; /* used to set errno */ - Sockbuf *sb; /* pointer to our associated sockbuf */ -} SASLIOSocketArg; - -static void -destroy_SASLIOSocketArg(SASLIOSocketArg** sockarg) -{ - if (sockarg && *sockarg) { - NSLDAPI_FREE((*sockarg)->sb_sasl_ibuf); - NSLDAPI_FREE((*sockarg)); - *sockarg = NULL; - } -} - -static SASLIOSocketArg* -new_SASLIOSocketArg(sasl_conn_t *ctx, int bufsiz, LDAP *ld, Sockbuf *sb) -{ - SASLIOSocketArg *sockarg = NULL; - - if (bufsiz <= 0) { - return sockarg; - } - - sockarg = (SASLIOSocketArg*)NSLDAPI_CALLOC(1, sizeof(SASLIOSocketArg)); - if (sockarg) { - sockarg->sasl_ctx = ctx; - sockarg->sb_sasl_ibuf = NSLDAPI_MALLOC(bufsiz); - if (!sockarg->sb_sasl_ibuf) { - destroy_SASLIOSocketArg(&sockarg); - return sockarg; - } - sockarg->sb_sasl_iptr = NULL; - sockarg->sb_sasl_bfsz = bufsiz; - sockarg->sb_sasl_ilen = 0; - sockarg->ld = ld; - sockarg->sb = sb; - } - - return sockarg; -} - -/* - * SASL Dependent routines - * - * SASL security and integrity options are supported through the - * use of the extended I/O functionality. Because the extended - * I/O functions may already be in use prior to enabling encryption, - * when SASL encryption si enabled, these routine interpose themselves - * over the exitng extended I/O routines and add an additional level - * of indirection. - * IE: Before SASL: client->libldap->lber->extio - * After SASL: client->libldap->lber->saslio->extio - * Any extio function are stilled used for the raw i/O [IE prldap] - * but SASL will decrypt before passing to lber. - * SASL cannot decrypt a stream so full packaets must be read - * before proceeding. - */ - -/* - * Get the 4 octet header [size] for a sasl encrypted buffer. - * See RFC222 [section 3]. - */ -static int -nsldapi_sasl_pktlen( char *buf, int maxbufsize ) -{ - int size; - -#if defined( _WINDOWS ) || defined( _WIN32 ) - size = ntohl(*(u_long *)buf); -#else - size = ntohl(*(uint32_t *)buf); -#endif - if ( size < 0 || size > maxbufsize ) { - return (-1 ); - } - - return( size + 4 ); /* include the first 4 bytes */ -} - -/* - * SASL encryption routines - */ - -static int -nsldapi_sasl_read( int s, void *buf, int len, - struct lextiof_socket_private *arg) -{ - LDAP *ld; - const char *dbuf; - char *cp; - int ret; - unsigned dlen, blen; - - ld = (LDAP *)arg->ld; - - /* Is there anything left in the existing buffer? */ - if ((ret = arg->sb_sasl_ilen) > 0) { - ret = (ret > len ? len : ret); - SAFEMEMCPY( buf, arg->sb_sasl_iptr, ret ); - if (ret == arg->sb_sasl_ilen) { - arg->sb_sasl_ilen = 0; - arg->sb_sasl_iptr = NULL; - } else { - arg->sb_sasl_ilen -= ret; - arg->sb_sasl_iptr += ret; - } - return( ret ); - } - - /* buffer is empty - fill it */ - cp = arg->sb_sasl_ibuf; - dlen = 0; - - /* Read the length of the packet */ - while ( dlen < 4 ) { - if (arg->sock_io_fns.lbextiofn_read != NULL) { - ret = arg->sock_io_fns.lbextiofn_read( - s, cp, 4 - dlen, - arg->sock_io_fns.lbextiofn_socket_arg); - } else { - ret = read( s, cp, 4 - dlen ); - } -#ifdef EINTR - if ( ( ret < 0 ) && ( LDAP_GET_ERRNO(ld) == EINTR ) ) - continue; -#endif - if ( ret <= 0 ) - return( ret ); - - cp += ret; - dlen += ret; - } - - blen = 4; - - ret = nsldapi_sasl_pktlen( arg->sb_sasl_ibuf, arg->sb_sasl_bfsz ); - if (ret < 0) { - LDAP_SET_ERRNO(ld, EIO); - return( -1 ); - } - dlen = ret - dlen; - - /* read the rest of the encrypted packet */ - while ( dlen > 0 ) { - if (arg->sock_io_fns.lbextiofn_read != NULL) { - ret = arg->sock_io_fns.lbextiofn_read( - s, cp, dlen, - arg->sock_io_fns.lbextiofn_socket_arg); - } else { - ret = read( s, cp, dlen ); - } - -#ifdef EINTR - if ( ( ret < 0 ) && ( LDAP_GET_ERRNO(ld) == EINTR ) ) - continue; -#endif - if ( ret <= 0 ) - return( ret ); - - cp += ret; - blen += ret; - dlen -= ret; - } - - /* Decode the packet */ - ret = sasl_decode( arg->sasl_ctx, - arg->sb_sasl_ibuf, blen, - &dbuf, &dlen); - if ( ret != SASL_OK ) { - /* sb_sasl_read: failed to decode packet, drop it, error */ - arg->sb_sasl_iptr = NULL; - arg->sb_sasl_ilen = 0; - LDAP_SET_ERRNO(ld, EIO); - return( -1 ); - } - - /* copy decrypted packet to the input buffer */ - SAFEMEMCPY( arg->sb_sasl_ibuf, dbuf, dlen ); - arg->sb_sasl_iptr = arg->sb_sasl_ibuf; - arg->sb_sasl_ilen = dlen; - - ret = (dlen > (unsigned) len ? len : dlen); - SAFEMEMCPY( buf, arg->sb_sasl_iptr, ret ); - if (ret == arg->sb_sasl_ilen) { - arg->sb_sasl_ilen = 0; - arg->sb_sasl_iptr = NULL; - } else { - arg->sb_sasl_ilen -= ret; - arg->sb_sasl_iptr += ret; - } - return( ret ); -} - -static int -nsldapi_sasl_write( int s, const void *buf, int len, - struct lextiof_socket_private *arg) -{ - int ret = 0; - const char *obuf, *optr, *cbuf = (const char *)buf; - unsigned olen, clen, tlen = 0; - unsigned *maxbuf; - - ret = sasl_getprop(arg->sasl_ctx, SASL_MAXOUTBUF, - (const void **)&maxbuf); - if ( ret != SASL_OK ) { - /* just a sanity check, should never happen */ - return( -1 ); - } - - while (len > 0) { - clen = (len > *maxbuf) ? *maxbuf : len; - /* encode the next packet. */ - ret = sasl_encode( arg->sasl_ctx, cbuf, clen, &obuf, &olen); - if ( ret != SASL_OK ) { - /* XXX Log error? "sb_sasl_write: failed to encode packet..." */ - return( -1 ); - } - /* Write everything now, buffer is only good until next sasl_encode */ - optr = obuf; - while (olen > 0) { - if (arg->sock_io_fns.lbextiofn_write != NULL) { - ret = arg->sock_io_fns.lbextiofn_write( - s, optr, olen, - arg->sock_io_fns.lbextiofn_socket_arg); - } else { - ret = write( s, optr, olen); - } - if ( ret < 0 ) - return( ret ); - optr += ret; - olen -= ret; - } - len -= clen; - cbuf += clen; - tlen += clen; - } - return( tlen ); -} - -/* - * What's all this then? - * First, take a look at os-ip.c:nsldapi_add_to_cb_pollfds(). When a new descriptor is - * added to the pollfds array, the lpoll_socketarg field is initialized to the value from - * the socketarg field - sb->sb_ext_io_fns.lbextiofn_socket_arg. In our case, since we - * override this with our sasl data (see below nsldapi_sasl_install), we need to restore - * the previous value so that the layer below us (i.e. prldap) can use the lpoll_socketarg - * which it sets. - * So how do which know which fds[i] is a "sasl" fd? - * We initialize the lextiof_session_private *arg (see nsldapi_sasl_install) to point to - * the socket_private data in sb->sb_ext_io_fns.lbextiofn_socket_arg for "sasl" sockets, - * which is then used to initialize lpoll_socketarg (see above). - * So, if the arg which gets passed into nsldapi_sasl_poll is the same as the - * fds[i].lpoll_socketarg, we know it is a "sasl" socket and we need to "pop" the sasl - * layer. We do this by replacing lpoll_socketarg with the one we saved when we "pushed" - * the sasl layer. - * So why the loop to restore the sasl lpoll_socketarg? - * The lower layer only uses lpoll_socketarg during poll(). See ldappr-io.c:prldap_poll() - * for more information about how that works. However, after the polling is done, there - * is some special magic in os-ip.c in the functions nsldapi_add_to_cb_pollfds(), - * nsldapi_clear_from_cb_pollfds(), and nsldapi_find_in_cb_pollfds() to find the correct - * Sockbuf to operate on. This is the macro NSLDAPI_CB_POLL_MATCH(). For the extended - * io function callbacks to work correctly, it is not sufficient to say that the file - * descriptor in the Sockbuf matches the one that poll says has activity - we also need - * to match the lpoll_socketarg with the sb->sb_ext_io_fns.lbextiofn_socket_arg to make - * sure this really is the Sockbuf we want to use. So we have to restore the - * lpoll_socketarg with the original one. - * Why have origarg and staticorigarg? - * To avoid malloc. The sizeof staticorigarg should be large enough to accomodate almost - * all clients without incurring too much additional overhead. However, if we need more - * room, origarg will grow to nfds. If this proves to be inadequate, the size of the - * staticorigarg is a good candidate for a #define set by configure. - */ -static int -nsldapi_sasl_poll( - LDAP_X_PollFD fds[], int nfds, int timeout, - struct lextiof_session_private *arg ) -{ - LDAP_X_EXTIOF_POLL_CALLBACK *origpoll; /* poll fn from the pushed layer */ - struct lextiof_session_private *origsess = NULL; /* session arg from the pushed layer */ - SASLIOSocketArg **origarg = NULL; /* list of saved original socket args */ - SASLIOSocketArg *staticorigarg[1024]; /* default list to avoid malloc */ - int origargsize = sizeof(staticorigarg)/sizeof(staticorigarg[0]); - int rc = -1; /* the return code - -1 means failure */ - - if (arg == NULL) { /* should not happen */ - return( rc ); - } - - origarg = staticorigarg; - /* if the static array is not large enough, alloc a dynamic one */ - if (origargsize < nfds) { - origarg = (SASLIOSocketArg **)NSLDAPI_MALLOC(nfds*sizeof(SASLIOSocketArg *)); - } - - if (fds && nfds > 0) { - int i; - for(i = 0; i < nfds; i++) { - /* save the original socket arg */ - origarg[i] = fds[i].lpoll_socketarg; - if (arg == (struct lextiof_session_private *)fds[i].lpoll_socketarg) { - /* lpoll_socketarg is a sasl socket arg - we need to replace it - with the one from the layer we pushed (i.e. prldap) */ - SASLIOSocketArg *sockarg = (SASLIOSocketArg *)fds[i].lpoll_socketarg; - /* reset to pushed layer's socket arg */ - fds[i].lpoll_socketarg = sockarg->sock_io_fns.lbextiofn_socket_arg; - /* grab the pushed layers' poll fn and its session arg */ - if (!origsess) { - origpoll = sockarg->sess_io_fns.lextiof_poll; - origsess = sockarg->sess_io_fns.lextiof_session_arg; - } - } - } - } - - if (origsess == NULL) { /* should not happen */ - goto done; - } - - /* call the "real" poll function */ - rc = origpoll( fds, nfds, timeout, origsess ); - - /* reset the lpoll_socketarg values to their original values because - they must match what's in sb->iofns->lbextiofn_socket_arg in order - for NSLDAPI_CB_POLL_MATCH to work - see os-ip.c */ - if (fds && nfds > 0) { - int i; - for(i = 0; i < nfds; i++) { - if ((SASLIOSocketArg *)arg == origarg[i]) { - fds[i].lpoll_socketarg = origarg[i]; - } - } - } - -done: - /* if we had to use a dynamic array, free it */ - if (origarg != staticorigarg) { - NSLDAPI_FREE(origarg); - } - - return rc; -} - -int -nsldapi_sasl_open( LDAP *ld, LDAPConn *lconn, sasl_conn_t **ctx, sasl_ssf_t ssf ) -{ - int saslrc; - char *host = NULL; - - if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) { - LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL ); - return( LDAP_LOCAL_ERROR ); - } - - if ( lconn == NULL ) { - if ( ld->ld_defconn == NULL || - ld->ld_defconn->lconn_status != LDAP_CONNST_CONNECTED) { - int rc = nsldapi_open_ldap_defconn( ld ); - if( rc < 0 ) { - return( LDAP_GET_LDERRNO( ld, NULL, NULL ) ); - } - } - lconn = ld->ld_defconn; - } - - /* need to clear out the old context for this connection, if any */ - /* client may have re-bind-ed this connection without closing first */ - if (lconn->lconn_sasl_ctx) { - sasl_dispose(&lconn->lconn_sasl_ctx); - lconn->lconn_sasl_ctx = NULL; - } - - if ( 0 != ldap_get_option( ld, LDAP_OPT_HOST_NAME, &host ) ) { - LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL ); - return( LDAP_LOCAL_ERROR ); - } - - saslrc = sasl_client_new( "ldap", host, - NULL, NULL, /* iplocalport, ipremoteport - use defaults */ - NULL, 0, ctx ); - ldap_memfree(host); - - if ( (saslrc != SASL_OK) || (!*ctx) ) { - return( nsldapi_sasl_cvterrno( ld, saslrc, NULL ) ); - } - - if( ssf ) { - sasl_ssf_t extprops; - memset(&extprops, 0L, sizeof(extprops)); - extprops = ssf; - - (void) sasl_setprop( *ctx, SASL_SSF_EXTERNAL, - (void *) &extprops ); - } - - /* (re)set security properties */ - sasl_setprop( *ctx, SASL_SEC_PROPS, &ld->ld_sasl_secprops ); - - /* set the connection context */ - lconn->lconn_sasl_ctx = *ctx; - - return( LDAP_SUCCESS ); -} - -static int -nsldapi_sasl_close( struct lextiof_socket_private *arg ) -{ - /* undo function pointer interposing */ - ldap_set_option( arg->ld, LDAP_X_OPT_EXTIO_FN_PTRS, &arg->sess_io_fns ); - /* have to do this separately to make sure the socketarg is set correctly */ - ber_sockbuf_set_option( arg->sb, - LBER_SOCKBUF_OPT_EXT_IO_FNS, - (void *)&arg->sock_io_fns ); - - destroy_SASLIOSocketArg(&arg); - return( LDAP_SUCCESS ); -} - -static int -nsldapi_sasl_close_socket(int s, struct lextiof_socket_private *arg ) -{ - LDAP_X_EXTIOF_CLOSE_CALLBACK *origclose; - struct lextiof_socket_private *origsock; - - if (arg == NULL) { - return( -1 ); - } - - origclose = arg->sess_io_fns.lextiof_close; - origsock = arg->sock_io_fns.lbextiofn_socket_arg; - - /* undo SASL */ - nsldapi_sasl_close( arg ); - arg = NULL; - /* arg is destroyed at this point - do not use it */ - - if (origclose ) - return ( origclose( s, origsock ) ); - else { - /* This is a copy of nsldapi_os_closesocket() - * from os-ip.c. It is declared static there, - * hence the copy of it. - */ - int rc; - -#ifdef NSLDAPI_AVOID_OS_SOCKETS - rc = -1; -#else /* NSLDAPI_AVOID_OS_SOCKETS */ -#ifdef _WINDOWS - rc = closesocket( s ); -#else /* _WINDOWS */ - rc = close( s ); -#endif /* _WINDOWS */ -#endif /* NSLDAPI_AVOID_OS_SOCKETS */ - return( rc ); - } - -} - -/* - * install encryption routines if security has been negotiated - */ -int -nsldapi_sasl_install( LDAP *ld, LDAPConn *lconn ) -{ - struct lber_x_ext_io_fns fns; - struct ldap_x_ext_io_fns iofns; - sasl_security_properties_t *secprops; - int rc, value; - int bufsiz; - Sockbuf *sb = NULL; - sasl_conn_t *ctx = NULL; - SASLIOSocketArg *sockarg = NULL; - - if ( lconn == NULL ) { - lconn = ld->ld_defconn; - if ( lconn == NULL ) { - return( LDAP_LOCAL_ERROR ); - } - } - if ( (sb = lconn->lconn_sb) == NULL ) { - return( LDAP_LOCAL_ERROR ); - } - rc = ber_sockbuf_get_option( sb, - LBER_SOCKBUF_OPT_TO_FILE_ONLY, - (void *) &value); - if (rc != 0 || value != 0) { - return( LDAP_LOCAL_ERROR ); - } - - /* the sasl context in the lconn must have been set prior to this */ - ctx = lconn->lconn_sasl_ctx; - rc = sasl_getprop( ctx, SASL_SEC_PROPS, - (const void **)&secprops ); - if (rc != SASL_OK) - return( LDAP_LOCAL_ERROR ); - bufsiz = secprops->maxbufsize; - if (bufsiz <= 0) { - return( LDAP_LOCAL_ERROR ); - } - - /* create our socket specific context */ - sockarg = new_SASLIOSocketArg(ctx, bufsiz, ld, sb); - if (!sockarg) { - return( LDAP_LOCAL_ERROR ); - } - - /* save a copy of the existing io fns and the session arg */ - memset( &sockarg->sess_io_fns, 0, LDAP_X_EXTIO_FNS_SIZE ); - sockarg->sess_io_fns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE; - rc = ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, - &sockarg->sess_io_fns ); - if (rc != 0) { - destroy_SASLIOSocketArg(&sockarg); - return( LDAP_LOCAL_ERROR ); - } - - /* save a copy of the existing ber io fns and the socket arg */ - memset( &sockarg->sock_io_fns, 0, LBER_X_EXTIO_FNS_SIZE ); - sockarg->sock_io_fns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE; - rc = ber_sockbuf_get_option( sb, - LBER_SOCKBUF_OPT_EXT_IO_FNS, - (void *)&sockarg->sock_io_fns); - if (rc != 0) { - destroy_SASLIOSocketArg(&sockarg); - return( LDAP_LOCAL_ERROR ); - } - - /* Always set the ext io close fn pointer to ensure we - * clean up our sockarg context */ - memset( &iofns, 0, sizeof(iofns)); - /* first, copy struct - sets defaults */ - iofns = sockarg->sess_io_fns; - iofns.lextiof_close = nsldapi_sasl_close_socket; - iofns.lextiof_session_arg = sockarg; /* needed for close and poll */ - - /* Set new values for the other ext io funcs if there are any - - when using the native io fns (as opposed to prldap) there - won't be any */ - if ( sockarg->sess_io_fns.lextiof_read != NULL || - sockarg->sess_io_fns.lextiof_write != NULL || - sockarg->sess_io_fns.lextiof_poll != NULL || - sockarg->sess_io_fns.lextiof_connect != NULL ) { - /* next, just reset those functions we want to override */ - iofns.lextiof_read = nsldapi_sasl_read; - iofns.lextiof_write = nsldapi_sasl_write; - iofns.lextiof_poll = nsldapi_sasl_poll; - } - - /* set the ext io funcs */ - rc = ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, &iofns ); - if (rc != 0) { - /* frees everything and resets fns above */ - nsldapi_sasl_close(sockarg); - return( LDAP_LOCAL_ERROR ); - } - - /* set the new ber io funcs and socket arg */ - (void) memset( &fns, 0, LBER_X_EXTIO_FNS_SIZE); - fns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE; - fns.lbextiofn_read = nsldapi_sasl_read; - fns.lbextiofn_write = nsldapi_sasl_write; - fns.lbextiofn_socket_arg = sockarg; - rc = ber_sockbuf_set_option( sb, - LBER_SOCKBUF_OPT_EXT_IO_FNS, - (void *)&fns); - if (rc != 0) { - /* frees everything and resets fns above */ - nsldapi_sasl_close(sockarg); - return( LDAP_LOCAL_ERROR ); - } - - return( LDAP_SUCCESS ); -} - -#endif |