1 /* 2 * Global variable access routines for CUPS. 3 * 4 * Copyright 2007-2015 by Apple Inc. 5 * Copyright 1997-2007 by Easy Software Products, all rights reserved. 6 * 7 * These coded instructions, statements, and computer programs are the 8 * property of Apple Inc. and are protected by Federal copyright 9 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 10 * which should have been included with this file. If this file is 11 * missing or damaged, see the license at "http://www.cups.org/". 12 * 13 * This file is subject to the Apple OS-Developed Software exception. 14 */ 15 16 /* 17 * Include necessary headers... 18 */ 19 20 #include "cups-private.h" 21 22 23 /* 24 * Local globals... 25 */ 26 27 #ifdef DEBUG 28 static int cups_global_index = 0; 29 /* Next thread number */ 30 #endif /* DEBUG */ 31 static _cups_threadkey_t cups_globals_key = _CUPS_THREADKEY_INITIALIZER; 32 /* Thread local storage key */ 33 #ifdef HAVE_PTHREAD_H 34 static pthread_once_t cups_globals_key_once = PTHREAD_ONCE_INIT; 35 /* One-time initialization object */ 36 #endif /* HAVE_PTHREAD_H */ 37 #if defined(HAVE_PTHREAD_H) || defined(WIN32) 38 static _cups_mutex_t cups_global_mutex = _CUPS_MUTEX_INITIALIZER; 39 /* Global critical section */ 40 #endif /* HAVE_PTHREAD_H || WIN32 */ 41 42 43 /* 44 * Local functions... 45 */ 46 47 #ifdef WIN32 48 static void cups_fix_path(char *path); 49 #endif /* WIN32 */ 50 static _cups_globals_t *cups_globals_alloc(void); 51 #if defined(HAVE_PTHREAD_H) || defined(WIN32) 52 static void cups_globals_free(_cups_globals_t *g); 53 #endif /* HAVE_PTHREAD_H || WIN32 */ 54 #ifdef HAVE_PTHREAD_H 55 static void cups_globals_init(void); 56 #endif /* HAVE_PTHREAD_H */ 57 58 59 /* 60 * '_cupsGlobalLock()' - Lock the global mutex. 61 */ 62 63 void 64 _cupsGlobalLock(void) 65 { 66 #ifdef HAVE_PTHREAD_H 67 pthread_mutex_lock(&cups_global_mutex); 68 #elif defined(WIN32) 69 EnterCriticalSection(&cups_global_mutex.m_criticalSection); 70 #endif /* HAVE_PTHREAD_H */ 71 } 72 73 74 /* 75 * '_cupsGlobals()' - Return a pointer to thread local storage 76 */ 77 78 _cups_globals_t * /* O - Pointer to global data */ 79 _cupsGlobals(void) 80 { 81 _cups_globals_t *cg; /* Pointer to global data */ 82 83 84 #ifdef HAVE_PTHREAD_H 85 /* 86 * Initialize the global data exactly once... 87 */ 88 89 pthread_once(&cups_globals_key_once, cups_globals_init); 90 #endif /* HAVE_PTHREAD_H */ 91 92 /* 93 * See if we have allocated the data yet... 94 */ 95 96 if ((cg = (_cups_globals_t *)_cupsThreadGetData(cups_globals_key)) == NULL) 97 { 98 /* 99 * No, allocate memory as set the pointer for the key... 100 */ 101 102 if ((cg = cups_globals_alloc()) != NULL) 103 _cupsThreadSetData(cups_globals_key, cg); 104 } 105 106 /* 107 * Return the pointer to the data... 108 */ 109 110 return (cg); 111 } 112 113 114 /* 115 * '_cupsGlobalUnlock()' - Unlock the global mutex. 116 */ 117 118 void 119 _cupsGlobalUnlock(void) 120 { 121 #ifdef HAVE_PTHREAD_H 122 pthread_mutex_unlock(&cups_global_mutex); 123 #elif defined(WIN32) 124 LeaveCriticalSection(&cups_global_mutex.m_criticalSection); 125 #endif /* HAVE_PTHREAD_H */ 126 } 127 128 129 #ifdef WIN32 130 /* 131 * 'DllMain()' - Main entry for library. 132 */ 133 134 BOOL WINAPI /* O - Success/failure */ 135 DllMain(HINSTANCE hinst, /* I - DLL module handle */ 136 DWORD reason, /* I - Reason */ 137 LPVOID reserved) /* I - Unused */ 138 { 139 _cups_globals_t *cg; /* Global data */ 140 141 142 (void)hinst; 143 (void)reserved; 144 145 switch (reason) 146 { 147 case DLL_PROCESS_ATTACH : /* Called on library initialization */ 148 InitializeCriticalSection(&cups_global_mutex.m_criticalSection); 149 150 if ((cups_globals_key = TlsAlloc()) == TLS_OUT_OF_INDEXES) 151 return (FALSE); 152 break; 153 154 case DLL_THREAD_DETACH : /* Called when a thread terminates */ 155 if ((cg = (_cups_globals_t *)TlsGetValue(cups_globals_key)) != NULL) 156 cups_globals_free(cg); 157 break; 158 159 case DLL_PROCESS_DETACH : /* Called when library is unloaded */ 160 if ((cg = (_cups_globals_t *)TlsGetValue(cups_globals_key)) != NULL) 161 cups_globals_free(cg); 162 163 TlsFree(cups_globals_key); 164 DeleteCriticalSection(&cups_global_mutex.m_criticalSection); 165 break; 166 167 default: 168 break; 169 } 170 171 return (TRUE); 172 } 173 #endif /* WIN32 */ 174 175 176 /* 177 * 'cups_globals_alloc()' - Allocate and initialize global data. 178 */ 179 180 static _cups_globals_t * /* O - Pointer to global data */ 181 cups_globals_alloc(void) 182 { 183 _cups_globals_t *cg = malloc(sizeof(_cups_globals_t)); 184 /* Pointer to global data */ 185 #ifdef WIN32 186 HKEY key; /* Registry key */ 187 DWORD size; /* Size of string */ 188 static char installdir[1024] = "", /* Install directory */ 189 confdir[1024] = "", /* Server root directory */ 190 localedir[1024] = ""; /* Locale directory */ 191 #endif /* WIN32 */ 192 193 194 if (!cg) 195 return (NULL); 196 197 /* 198 * Clear the global storage and set the default encryption and password 199 * callback values... 200 */ 201 202 memset(cg, 0, sizeof(_cups_globals_t)); 203 cg->encryption = (http_encryption_t)-1; 204 cg->password_cb = (cups_password_cb2_t)_cupsGetPassword; 205 cg->trust_first = -1; 206 cg->any_root = -1; 207 cg->expired_certs = -1; 208 cg->validate_certs = -1; 209 210 #ifdef DEBUG 211 /* 212 * Friendly thread ID for debugging... 213 */ 214 215 cg->thread_id = ++ cups_global_index; 216 #endif /* DEBUG */ 217 218 /* 219 * Then set directories as appropriate... 220 */ 221 222 #ifdef WIN32 223 if (!installdir[0]) 224 { 225 /* 226 * Open the registry... 227 */ 228 229 strlcpy(installdir, "C:/Program Files/cups.org", sizeof(installdir)); 230 231 if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\cups.org", 0, KEY_READ, 232 &key)) 233 { 234 /* 235 * Grab the installation directory... 236 */ 237 238 char *ptr; /* Pointer into installdir */ 239 240 size = sizeof(installdir); 241 RegQueryValueEx(key, "installdir", NULL, NULL, installdir, &size); 242 RegCloseKey(key); 243 244 for (ptr = installdir; *ptr;) 245 { 246 if (*ptr == '\\') 247 { 248 if (ptr[1]) 249 *ptr++ = '/'; 250 else 251 *ptr = '\0'; /* Strip trailing \ */ 252 } 253 else if (*ptr == '/' && !ptr[1]) 254 *ptr = '\0'; /* Strip trailing / */ 255 else 256 ptr ++; 257 } 258 } 259 260 snprintf(confdir, sizeof(confdir), "%s/conf", installdir); 261 snprintf(localedir, sizeof(localedir), "%s/locale", installdir); 262 } 263 264 if ((cg->cups_datadir = getenv("CUPS_DATADIR")) == NULL) 265 cg->cups_datadir = installdir; 266 267 if ((cg->cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL) 268 cg->cups_serverbin = installdir; 269 270 if ((cg->cups_serverroot = getenv("CUPS_SERVERROOT")) == NULL) 271 cg->cups_serverroot = confdir; 272 273 if ((cg->cups_statedir = getenv("CUPS_STATEDIR")) == NULL) 274 cg->cups_statedir = confdir; 275 276 if ((cg->localedir = getenv("LOCALEDIR")) == NULL) 277 cg->localedir = localedir; 278 279 #else 280 # ifdef HAVE_GETEUID 281 if ((geteuid() != getuid() && getuid()) || getegid() != getgid()) 282 # else 283 if (!getuid()) 284 # endif /* HAVE_GETEUID */ 285 { 286 /* 287 * When running setuid/setgid, don't allow environment variables to override 288 * the directories... 289 */ 290 291 cg->cups_datadir = CUPS_DATADIR; 292 cg->cups_serverbin = CUPS_SERVERBIN; 293 cg->cups_serverroot = CUPS_SERVERROOT; 294 cg->cups_statedir = CUPS_STATEDIR; 295 cg->localedir = CUPS_LOCALEDIR; 296 } 297 else 298 { 299 /* 300 * Allow directories to be overridden by environment variables. 301 */ 302 303 if ((cg->cups_datadir = getenv("CUPS_DATADIR")) == NULL) 304 cg->cups_datadir = CUPS_DATADIR; 305 306 if ((cg->cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL) 307 cg->cups_serverbin = CUPS_SERVERBIN; 308 309 if ((cg->cups_serverroot = getenv("CUPS_SERVERROOT")) == NULL) 310 cg->cups_serverroot = CUPS_SERVERROOT; 311 312 if ((cg->cups_statedir = getenv("CUPS_STATEDIR")) == NULL) 313 cg->cups_statedir = CUPS_STATEDIR; 314 315 if ((cg->localedir = getenv("LOCALEDIR")) == NULL) 316 cg->localedir = CUPS_LOCALEDIR; 317 } 318 #endif /* WIN32 */ 319 320 return (cg); 321 } 322 323 324 /* 325 * 'cups_globals_free()' - Free global data. 326 */ 327 328 #if defined(HAVE_PTHREAD_H) || defined(WIN32) 329 static void 330 cups_globals_free(_cups_globals_t *cg) /* I - Pointer to global data */ 331 { 332 _cups_buffer_t *buffer, /* Current read/write buffer */ 333 *next; /* Next buffer */ 334 335 336 if (cg->last_status_message) 337 _cupsStrFree(cg->last_status_message); 338 339 for (buffer = cg->cups_buffers; buffer; buffer = next) 340 { 341 next = buffer->next; 342 free(buffer); 343 } 344 345 cupsArrayDelete(cg->leg_size_lut); 346 cupsArrayDelete(cg->ppd_size_lut); 347 cupsArrayDelete(cg->pwg_size_lut); 348 349 httpClose(cg->http); 350 351 #ifdef HAVE_SSL 352 _httpFreeCredentials(cg->tls_credentials); 353 #endif /* HAVE_SSL */ 354 355 cupsFileClose(cg->stdio_files[0]); 356 cupsFileClose(cg->stdio_files[1]); 357 cupsFileClose(cg->stdio_files[2]); 358 359 cupsFreeOptions(cg->cupsd_num_settings, cg->cupsd_settings); 360 361 free(cg); 362 } 363 #endif /* HAVE_PTHREAD_H || WIN32 */ 364 365 366 #ifdef HAVE_PTHREAD_H 367 /* 368 * 'cups_globals_init()' - Initialize environment variables. 369 */ 370 371 static void 372 cups_globals_init(void) 373 { 374 /* 375 * Register the global data for this thread... 376 */ 377 378 pthread_key_create(&cups_globals_key, (void (*)(void *))cups_globals_free); 379 } 380 #endif /* HAVE_PTHREAD_H */ 381