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_threadid(void); 50 static void *adutils_mutex_alloc(void); 51 static void adutils_mutex_free(void *mutexp); 52 static int adutils_get_errno(void); 53 static void adutils_set_errno(int err); 54 static void adutils_set_lderrno(int err, char *matched, char *errmsg, 55 void *dummy); 56 static int adutils_get_lderrno(char **matched, char **errmsg, void *dummy); 57 static void adutils_lderrno_destructor(void *tsd); 58 59 static pthread_key_t adutils_lderrno_key = PTHREAD_ONCE_KEY_NP; 60 61 static struct ldap_thread_fns thread_fns = { 62 .ltf_mutex_alloc = adutils_mutex_alloc, 63 .ltf_mutex_free = adutils_mutex_free, 64 .ltf_mutex_lock = (int (*)(void *)) pthread_mutex_lock, 65 .ltf_mutex_unlock = (int (*)(void *)) pthread_mutex_unlock, 66 .ltf_get_errno = adutils_get_errno, 67 .ltf_set_errno = adutils_set_errno, 68 .ltf_get_lderrno = adutils_get_lderrno, 69 .ltf_set_lderrno = adutils_set_lderrno, 70 .ltf_lderrno_arg = NULL 71 }; 72 73 struct ldap_extra_thread_fns extra_thread_fns = { 74 .ltf_threadid_fn = adutils_threadid 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 static void * 116 adutils_threadid(void) 117 { 118 return ((void *)(uintptr_t)pthread_self()); 119 } 120 121 /* 122 * Allocate a mutex. 123 */ 124 static 125 void * 126 adutils_mutex_alloc(void) 127 { 128 pthread_mutex_t *mutexp; 129 int rc; 130 131 mutexp = malloc(sizeof (pthread_mutex_t)); 132 if (mutexp == NULL) { 133 logger(LOG_ERR, 134 "adutils_mutex_alloc: malloc failed (%s)", 135 strerror(errno)); 136 return (NULL); 137 } 138 139 rc = pthread_mutex_init(mutexp, NULL); 140 if (rc != 0) { 141 logger(LOG_ERR, 142 "adutils_mutex_alloc: " 143 "pthread_mutex_init failed (%s)", 144 strerror(rc)); 145 free(mutexp); 146 return (NULL); 147 } 148 return (mutexp); 149 } 150 151 /* 152 * Free a mutex. 153 */ 154 static 155 void 156 adutils_mutex_free(void *mutexp) 157 { 158 (void) pthread_mutex_destroy((pthread_mutex_t *)mutexp); 159 free(mutexp); 160 } 161 162 /* 163 * Get the thread's local errno. 164 */ 165 static 166 int 167 adutils_get_errno(void) 168 { 169 return (errno); 170 } 171 172 /* 173 * Set the thread's local errno. 174 */ 175 static 176 void 177 adutils_set_errno(int err) 178 { 179 errno = err; 180 } 181 182 /* 183 * Get a pointer to the thread's local LDAP error state structure. 184 * Lazily allocate the thread-local storage, so that we don't need 185 * initialization when each thread starts. 186 */ 187 static 188 struct adutils_lderrno * 189 adutils_get_lderrno_struct(void) 190 { 191 struct adutils_lderrno *le; 192 int rc; 193 194 le = pthread_getspecific(adutils_lderrno_key); 195 if (le == NULL) { 196 le = calloc(1, sizeof (*le)); 197 if (le == NULL) { 198 logger(LOG_ERR, 199 "adutils_get_lderrno_struct: calloc failed (%s)", 200 strerror(errno)); 201 return (NULL); 202 } 203 rc = pthread_setspecific(adutils_lderrno_key, le); 204 if (rc != 0) { 205 logger(LOG_ERR, 206 "adutils_get_lderrno_struct: " 207 "pthread_setspecific failed (%s)", 208 strerror(rc)); 209 free(le); 210 return (NULL); 211 } 212 } 213 214 return (le); 215 } 216 217 /* 218 * Store an error report in the thread's local LDAP error state structure. 219 */ 220 static 221 void 222 adutils_set_lderrno(int err, char *matched, char *errmsg, void *dummy) 223 { 224 NOTE(ARGUNUSED(dummy)) 225 struct adutils_lderrno *le; 226 227 le = adutils_get_lderrno_struct(); 228 if (le != NULL) { 229 le->le_errno = err; 230 if (le->le_matched != NULL) 231 ldap_memfree(le->le_matched); 232 le->le_matched = matched; 233 if (le->le_errmsg != NULL) 234 ldap_memfree(le->le_errmsg); 235 le->le_errmsg = errmsg; 236 } 237 } 238 239 /* 240 * Retrieve an error report from the thread's local LDAP error state structure. 241 */ 242 static 243 int 244 adutils_get_lderrno(char **matched, char **errmsg, void *dummy) 245 { 246 NOTE(ARGUNUSED(dummy)) 247 struct adutils_lderrno *le; 248 static struct adutils_lderrno empty = { LDAP_SUCCESS, NULL, NULL }; 249 250 le = adutils_get_lderrno_struct(); 251 if (le == NULL) 252 le = ∅ 253 254 if (matched != NULL) 255 *matched = le->le_matched; 256 if (errmsg != NULL) 257 *errmsg = le->le_errmsg; 258 return (le->le_errno); 259 } 260 261 /* 262 * Free the thread's local LDAP error state structure. 263 */ 264 static 265 void 266 adutils_lderrno_destructor(void *tsd) 267 { 268 struct adutils_lderrno *le = tsd; 269 270 if (le == NULL) 271 return; 272 273 if (le->le_matched != NULL) { 274 ldap_memfree(le->le_matched); 275 le->le_matched = NULL; 276 } 277 if (le->le_errmsg != NULL) { 278 ldap_memfree(le->le_errmsg); 279 le->le_errmsg = NULL; 280 } 281 free(le); 282 } 283