1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Functions for managing thread-local storage for LDAP, and in particular 29 * for managing storage of the LDAP error state. 30 */ 31 32 #include <ldap.h> 33 #include <pthread.h> 34 #include <errno.h> 35 #include <note.h> 36 #include <syslog.h> 37 #include <string.h> 38 #include "solaris-int.h" /* This is a libladp5 private include file */ 39 /* which has the defintion for */ 40 /* struct ldap_extra_thread_fns */ 41 #include "adutils_impl.h" 42 43 struct adutils_lderrno { 44 int le_errno; 45 char *le_matched; 46 char *le_errmsg; 47 }; 48 49 static void *adutils_mutex_alloc(void); 50 static void adutils_mutex_free(void *mutexp); 51 static int adutils_get_errno(void); 52 static void adutils_set_errno(int err); 53 static void adutils_set_lderrno(int err, char *matched, char *errmsg, 54 void *dummy); 55 static int adutils_get_lderrno(char **matched, char **errmsg, void *dummy); 56 static void adutils_lderrno_destructor(void *tsd); 57 58 static pthread_key_t adutils_lderrno_key = PTHREAD_ONCE_KEY_NP; 59 60 static struct ldap_thread_fns thread_fns = { 61 .ltf_mutex_alloc = adutils_mutex_alloc, 62 .ltf_mutex_free = adutils_mutex_free, 63 .ltf_mutex_lock = (int (*)(void *)) pthread_mutex_lock, 64 .ltf_mutex_unlock = (int (*)(void *)) pthread_mutex_unlock, 65 .ltf_get_errno = adutils_get_errno, 66 .ltf_set_errno = adutils_set_errno, 67 .ltf_get_lderrno = adutils_get_lderrno, 68 .ltf_set_lderrno = adutils_set_lderrno, 69 .ltf_lderrno_arg = NULL 70 }; 71 72 struct ldap_extra_thread_fns extra_thread_fns = { 73 .ltf_threadid_fn = (void * (*)(void))pthread_self 74 }; 75 76 77 /* 78 * Set up thread management functions for the specified LDAP session. 79 * Returns either LDAP_SUCCESS or -1. 80 */ 81 int 82 adutils_set_thread_functions(LDAP *ld) 83 { 84 int rc; 85 86 if (adutils_lderrno_key == PTHREAD_ONCE_KEY_NP) { 87 if ((rc = pthread_key_create_once_np(&adutils_lderrno_key, 88 adutils_lderrno_destructor)) != 0) { 89 logger(LOG_ERR, "adutils_set_thread_functions() " 90 "pthread_key_create_once_np failed (%s)", 91 strerror(rc)); 92 rc = -1; 93 return (rc); 94 } 95 } 96 97 rc = ldap_set_option(ld, LDAP_OPT_THREAD_FN_PTRS, 98 &thread_fns); 99 if (rc != LDAP_SUCCESS) { 100 logger(LOG_ERR, 101 "ldap_set_option LDAP_OPT_THREAD_FN_PTRS failed"); 102 return (rc); 103 } 104 105 rc = ldap_set_option(ld, LDAP_OPT_EXTRA_THREAD_FN_PTRS, 106 &extra_thread_fns); 107 if (rc != LDAP_SUCCESS) { 108 logger(LOG_ERR, 109 "ldap_set_option LDAP_OPT_EXTRA_THREAD_FN_PTRS failed"); 110 return (rc); 111 } 112 return (rc); 113 } 114 115 /* 116 * Allocate a mutex. 117 */ 118 static 119 void * 120 adutils_mutex_alloc(void) 121 { 122 pthread_mutex_t *mutexp; 123 int rc; 124 125 mutexp = malloc(sizeof (pthread_mutex_t)); 126 if (mutexp == NULL) { 127 logger(LOG_ERR, 128 "adutils_mutex_alloc: malloc failed (%s)", 129 strerror(errno)); 130 return (NULL); 131 } 132 133 rc = pthread_mutex_init(mutexp, NULL); 134 if (rc != 0) { 135 logger(LOG_ERR, 136 "adutils_mutex_alloc: " 137 "pthread_mutex_init failed (%s)", 138 strerror(rc)); 139 free(mutexp); 140 return (NULL); 141 } 142 return (mutexp); 143 } 144 145 /* 146 * Free a mutex. 147 */ 148 static 149 void 150 adutils_mutex_free(void *mutexp) 151 { 152 (void) pthread_mutex_destroy((pthread_mutex_t *)mutexp); 153 free(mutexp); 154 } 155 156 /* 157 * Get the thread's local errno. 158 */ 159 static 160 int 161 adutils_get_errno(void) 162 { 163 return (errno); 164 } 165 166 /* 167 * Set the thread's local errno. 168 */ 169 static 170 void 171 adutils_set_errno(int err) 172 { 173 errno = err; 174 } 175 176 /* 177 * Get a pointer to the thread's local LDAP error state structure. 178 * Lazily allocate the thread-local storage, so that we don't need 179 * initialization when each thread starts. 180 */ 181 static 182 struct adutils_lderrno * 183 adutils_get_lderrno_struct(void) 184 { 185 struct adutils_lderrno *le; 186 int rc; 187 188 le = pthread_getspecific(adutils_lderrno_key); 189 if (le == NULL) { 190 le = calloc(1, sizeof (*le)); 191 if (le == NULL) { 192 logger(LOG_ERR, 193 "adutils_get_lderrno_struct: calloc failed (%s)", 194 strerror(errno)); 195 return (NULL); 196 } 197 rc = pthread_setspecific(adutils_lderrno_key, le); 198 if (rc != 0) { 199 logger(LOG_ERR, 200 "adutils_get_lderrno_struct: " 201 "pthread_setspecific failed (%s)", 202 strerror(rc)); 203 free(le); 204 return (NULL); 205 } 206 } 207 208 return (le); 209 } 210 211 /* 212 * Store an error report in the thread's local LDAP error state structure. 213 */ 214 static 215 void 216 adutils_set_lderrno(int err, char *matched, char *errmsg, void *dummy) 217 { 218 NOTE(ARGUNUSED(dummy)) 219 struct adutils_lderrno *le; 220 221 le = adutils_get_lderrno_struct(); 222 if (le != NULL) { 223 le->le_errno = err; 224 if (le->le_matched != NULL) 225 ldap_memfree(le->le_matched); 226 le->le_matched = matched; 227 if (le->le_errmsg != NULL) 228 ldap_memfree(le->le_errmsg); 229 le->le_errmsg = errmsg; 230 } 231 } 232 233 /* 234 * Retrieve an error report from the thread's local LDAP error state structure. 235 */ 236 static 237 int 238 adutils_get_lderrno(char **matched, char **errmsg, void *dummy) 239 { 240 NOTE(ARGUNUSED(dummy)) 241 struct adutils_lderrno *le; 242 static struct adutils_lderrno empty = { LDAP_SUCCESS, NULL, NULL }; 243 244 le = adutils_get_lderrno_struct(); 245 if (le == NULL) 246 le = ∅ 247 248 if (matched != NULL) 249 *matched = le->le_matched; 250 if (errmsg != NULL) 251 *errmsg = le->le_errmsg; 252 return (le->le_errno); 253 } 254 255 /* 256 * Free the thread's local LDAP error state structure. 257 */ 258 static 259 void 260 adutils_lderrno_destructor(void *tsd) 261 { 262 struct adutils_lderrno *le = tsd; 263 264 if (le == NULL) 265 return; 266 267 if (le->le_matched != NULL) { 268 ldap_memfree(le->le_matched); 269 le->le_matched = NULL; 270 } 271 if (le->le_errmsg != NULL) { 272 ldap_memfree(le->le_errmsg); 273 le->le_errmsg = NULL; 274 } 275 free(le); 276 } 277