2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A/*
2N/A * Functions for managing thread-local storage for LDAP, and in particular
2N/A * for managing storage of the LDAP error state.
2N/A */
2N/A
2N/A#include <ldap.h>
2N/A#include <pthread.h>
2N/A#include <errno.h>
2N/A#include <note.h>
2N/A#include <syslog.h>
2N/A#include <string.h>
2N/A#include "solaris-int.h" /* This is a libladp5 private include file */
2N/A /* which has the defintion for */
2N/A /* struct ldap_extra_thread_fns */
2N/A#include "adutils_impl.h"
2N/A
2N/Astruct adutils_lderrno {
2N/A int le_errno;
2N/A char *le_matched;
2N/A char *le_errmsg;
2N/A};
2N/A
2N/Astatic void *adutils_mutex_alloc(void);
2N/Astatic void adutils_mutex_free(void *mutexp);
2N/Astatic int adutils_get_errno(void);
2N/Astatic void adutils_set_errno(int err);
2N/Astatic void adutils_set_lderrno(int err, char *matched, char *errmsg,
2N/A void *dummy);
2N/Astatic int adutils_get_lderrno(char **matched, char **errmsg, void *dummy);
2N/Astatic void adutils_lderrno_destructor(void *tsd);
2N/A
2N/Astatic pthread_key_t adutils_lderrno_key = PTHREAD_ONCE_KEY_NP;
2N/A
2N/Astatic struct ldap_thread_fns thread_fns = {
2N/A .ltf_mutex_alloc = adutils_mutex_alloc,
2N/A .ltf_mutex_free = adutils_mutex_free,
2N/A .ltf_mutex_lock = (int (*)(void *)) pthread_mutex_lock,
2N/A .ltf_mutex_unlock = (int (*)(void *)) pthread_mutex_unlock,
2N/A .ltf_get_errno = adutils_get_errno,
2N/A .ltf_set_errno = adutils_set_errno,
2N/A .ltf_get_lderrno = adutils_get_lderrno,
2N/A .ltf_set_lderrno = adutils_set_lderrno,
2N/A .ltf_lderrno_arg = NULL
2N/A};
2N/A
2N/Astruct ldap_extra_thread_fns extra_thread_fns = {
2N/A .ltf_threadid_fn = (void * (*)(void))pthread_self
2N/A};
2N/A
2N/A
2N/A/*
2N/A * Set up thread management functions for the specified LDAP session.
2N/A * Returns either LDAP_SUCCESS or -1.
2N/A */
2N/Aint
2N/Aadutils_set_thread_functions(LDAP *ld)
2N/A{
2N/A int rc;
2N/A
2N/A if (adutils_lderrno_key == PTHREAD_ONCE_KEY_NP) {
2N/A if ((rc = pthread_key_create_once_np(&adutils_lderrno_key,
2N/A adutils_lderrno_destructor)) != 0) {
2N/A logger(LOG_ERR, "adutils_set_thread_functions() "
2N/A "pthread_key_create_once_np failed (%s)",
2N/A strerror(rc));
2N/A rc = -1;
2N/A return (rc);
2N/A }
2N/A }
2N/A
2N/A rc = ldap_set_option(ld, LDAP_OPT_THREAD_FN_PTRS,
2N/A &thread_fns);
2N/A if (rc != LDAP_SUCCESS) {
2N/A logger(LOG_ERR,
2N/A "ldap_set_option LDAP_OPT_THREAD_FN_PTRS failed");
2N/A return (rc);
2N/A }
2N/A
2N/A rc = ldap_set_option(ld, LDAP_OPT_EXTRA_THREAD_FN_PTRS,
2N/A &extra_thread_fns);
2N/A if (rc != LDAP_SUCCESS) {
2N/A logger(LOG_ERR,
2N/A "ldap_set_option LDAP_OPT_EXTRA_THREAD_FN_PTRS failed");
2N/A return (rc);
2N/A }
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * Allocate a mutex.
2N/A */
2N/Astatic
2N/Avoid *
2N/Aadutils_mutex_alloc(void)
2N/A{
2N/A pthread_mutex_t *mutexp;
2N/A int rc;
2N/A
2N/A mutexp = malloc(sizeof (pthread_mutex_t));
2N/A if (mutexp == NULL) {
2N/A logger(LOG_ERR,
2N/A "adutils_mutex_alloc: malloc failed (%s)",
2N/A strerror(errno));
2N/A return (NULL);
2N/A }
2N/A
2N/A rc = pthread_mutex_init(mutexp, NULL);
2N/A if (rc != 0) {
2N/A logger(LOG_ERR,
2N/A "adutils_mutex_alloc: "
2N/A "pthread_mutex_init failed (%s)",
2N/A strerror(rc));
2N/A free(mutexp);
2N/A return (NULL);
2N/A }
2N/A return (mutexp);
2N/A}
2N/A
2N/A/*
2N/A * Free a mutex.
2N/A */
2N/Astatic
2N/Avoid
2N/Aadutils_mutex_free(void *mutexp)
2N/A{
2N/A (void) pthread_mutex_destroy((pthread_mutex_t *)mutexp);
2N/A free(mutexp);
2N/A}
2N/A
2N/A/*
2N/A * Get the thread's local errno.
2N/A */
2N/Astatic
2N/Aint
2N/Aadutils_get_errno(void)
2N/A{
2N/A return (errno);
2N/A}
2N/A
2N/A/*
2N/A * Set the thread's local errno.
2N/A */
2N/Astatic
2N/Avoid
2N/Aadutils_set_errno(int err)
2N/A{
2N/A errno = err;
2N/A}
2N/A
2N/A/*
2N/A * Get a pointer to the thread's local LDAP error state structure.
2N/A * Lazily allocate the thread-local storage, so that we don't need
2N/A * initialization when each thread starts.
2N/A */
2N/Astatic
2N/Astruct adutils_lderrno *
2N/Aadutils_get_lderrno_struct(void)
2N/A{
2N/A struct adutils_lderrno *le;
2N/A int rc;
2N/A
2N/A le = pthread_getspecific(adutils_lderrno_key);
2N/A if (le == NULL) {
2N/A le = calloc(1, sizeof (*le));
2N/A if (le == NULL) {
2N/A logger(LOG_ERR,
2N/A "adutils_get_lderrno_struct: calloc failed (%s)",
2N/A strerror(errno));
2N/A return (NULL);
2N/A }
2N/A rc = pthread_setspecific(adutils_lderrno_key, le);
2N/A if (rc != 0) {
2N/A logger(LOG_ERR,
2N/A "adutils_get_lderrno_struct: "
2N/A "pthread_setspecific failed (%s)",
2N/A strerror(rc));
2N/A free(le);
2N/A return (NULL);
2N/A }
2N/A }
2N/A
2N/A return (le);
2N/A}
2N/A
2N/A/*
2N/A * Store an error report in the thread's local LDAP error state structure.
2N/A */
2N/Astatic
2N/Avoid
2N/Aadutils_set_lderrno(int err, char *matched, char *errmsg, void *dummy)
2N/A{
2N/A NOTE(ARGUNUSED(dummy))
2N/A struct adutils_lderrno *le;
2N/A
2N/A le = adutils_get_lderrno_struct();
2N/A if (le != NULL) {
2N/A le->le_errno = err;
2N/A if (le->le_matched != NULL)
2N/A ldap_memfree(le->le_matched);
2N/A le->le_matched = matched;
2N/A if (le->le_errmsg != NULL)
2N/A ldap_memfree(le->le_errmsg);
2N/A le->le_errmsg = errmsg;
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Retrieve an error report from the thread's local LDAP error state structure.
2N/A */
2N/Astatic
2N/Aint
2N/Aadutils_get_lderrno(char **matched, char **errmsg, void *dummy)
2N/A{
2N/A NOTE(ARGUNUSED(dummy))
2N/A struct adutils_lderrno *le;
2N/A static struct adutils_lderrno empty = { LDAP_SUCCESS, NULL, NULL };
2N/A
2N/A le = adutils_get_lderrno_struct();
2N/A if (le == NULL)
2N/A le = &empty;
2N/A
2N/A if (matched != NULL)
2N/A *matched = le->le_matched;
2N/A if (errmsg != NULL)
2N/A *errmsg = le->le_errmsg;
2N/A return (le->le_errno);
2N/A}
2N/A
2N/A/*
2N/A * Free the thread's local LDAP error state structure.
2N/A */
2N/Astatic
2N/Avoid
2N/Aadutils_lderrno_destructor(void *tsd)
2N/A{
2N/A struct adutils_lderrno *le = tsd;
2N/A
2N/A if (le == NULL)
2N/A return;
2N/A
2N/A if (le->le_matched != NULL) {
2N/A ldap_memfree(le->le_matched);
2N/A le->le_matched = NULL;
2N/A }
2N/A if (le->le_errmsg != NULL) {
2N/A ldap_memfree(le->le_errmsg);
2N/A le->le_errmsg = NULL;
2N/A }
2N/A free(le);
2N/A}