Line | Count | Source |
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 | 0 | { |
66 | 0 | #ifdef HAVE_PTHREAD_H |
67 | 0 | pthread_mutex_lock(&cups_global_mutex); |
68 | | #elif defined(_WIN32) |
69 | | EnterCriticalSection(&cups_global_mutex.m_criticalSection); |
70 | | #endif /* HAVE_PTHREAD_H */ |
71 | 0 | } |
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 | 0 | { |
81 | 0 | _cups_globals_t *cg; /* Pointer to global data */ |
82 | | |
83 | |
|
84 | 0 | #ifdef HAVE_PTHREAD_H |
85 | | /* |
86 | | * Initialize the global data exactly once... |
87 | | */ |
88 | |
|
89 | 0 | pthread_once(&cups_globals_key_once, cups_globals_init); |
90 | 0 | #endif /* HAVE_PTHREAD_H */ |
91 | | |
92 | | /* |
93 | | * See if we have allocated the data yet... |
94 | | */ |
95 | |
|
96 | 0 | if ((cg = (_cups_globals_t *)_cupsThreadGetData(cups_globals_key)) == NULL) |
97 | 0 | { |
98 | | /* |
99 | | * No, allocate memory as set the pointer for the key... |
100 | | */ |
101 | |
|
102 | 0 | if ((cg = cups_globals_alloc()) != NULL) |
103 | 0 | _cupsThreadSetData(cups_globals_key, cg); |
104 | 0 | } |
105 | | |
106 | | /* |
107 | | * Return the pointer to the data... |
108 | | */ |
109 | |
|
110 | 0 | return (cg); |
111 | 0 | } |
112 | | |
113 | | |
114 | | /* |
115 | | * '_cupsGlobalUnlock()' - Unlock the global mutex. |
116 | | */ |
117 | | |
118 | | void |
119 | | _cupsGlobalUnlock(void) |
120 | 0 | { |
121 | 0 | #ifdef HAVE_PTHREAD_H |
122 | 0 | pthread_mutex_unlock(&cups_global_mutex); |
123 | | #elif defined(_WIN32) |
124 | | LeaveCriticalSection(&cups_global_mutex.m_criticalSection); |
125 | | #endif /* HAVE_PTHREAD_H */ |
126 | 0 | } |
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 | 0 | { |
183 | 0 | _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 | 0 | if (!cg) |
195 | 0 | return (NULL); |
196 | | |
197 | | /* |
198 | | * Clear the global storage and set the default encryption and password |
199 | | * callback values... |
200 | | */ |
201 | | |
202 | 0 | memset(cg, 0, sizeof(_cups_globals_t)); |
203 | 0 | cg->encryption = (http_encryption_t)-1; |
204 | 0 | cg->password_cb = (cups_password_cb2_t)_cupsGetPassword; |
205 | 0 | cg->trust_first = -1; |
206 | 0 | cg->any_root = -1; |
207 | 0 | cg->expired_certs = -1; |
208 | 0 | 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 | 0 | # ifdef HAVE_GETEUID |
281 | 0 | if ((geteuid() != getuid() && getuid()) || getegid() != getgid()) |
282 | | # else |
283 | | if (!getuid()) |
284 | | # endif /* HAVE_GETEUID */ |
285 | 0 | { |
286 | | /* |
287 | | * When running setuid/setgid, don't allow environment variables to override |
288 | | * the directories... |
289 | | */ |
290 | |
|
291 | 0 | cg->cups_datadir = CUPS_DATADIR; |
292 | 0 | cg->cups_serverbin = CUPS_SERVERBIN; |
293 | 0 | cg->cups_serverroot = CUPS_SERVERROOT; |
294 | 0 | cg->cups_statedir = CUPS_STATEDIR; |
295 | 0 | cg->localedir = CUPS_LOCALEDIR; |
296 | 0 | } |
297 | 0 | else |
298 | 0 | { |
299 | | /* |
300 | | * Allow directories to be overridden by environment variables. |
301 | | */ |
302 | |
|
303 | 0 | if ((cg->cups_datadir = getenv("CUPS_DATADIR")) == NULL) |
304 | 0 | cg->cups_datadir = CUPS_DATADIR; |
305 | |
|
306 | 0 | if ((cg->cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL) |
307 | 0 | cg->cups_serverbin = CUPS_SERVERBIN; |
308 | |
|
309 | 0 | if ((cg->cups_serverroot = getenv("CUPS_SERVERROOT")) == NULL) |
310 | 0 | cg->cups_serverroot = CUPS_SERVERROOT; |
311 | |
|
312 | 0 | if ((cg->cups_statedir = getenv("CUPS_STATEDIR")) == NULL) |
313 | 0 | cg->cups_statedir = CUPS_STATEDIR; |
314 | |
|
315 | 0 | if ((cg->localedir = getenv("LOCALEDIR")) == NULL) |
316 | 0 | cg->localedir = CUPS_LOCALEDIR; |
317 | 0 | } |
318 | 0 | #endif /* _WIN32 */ |
319 | |
|
320 | 0 | return (cg); |
321 | 0 | } |
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 | 0 | { |
332 | 0 | _cups_buffer_t *buffer, /* Current read/write buffer */ |
333 | 0 | *next; /* Next buffer */ |
334 | | |
335 | |
|
336 | 0 | if (cg->last_status_message) |
337 | 0 | _cupsStrFree(cg->last_status_message); |
338 | |
|
339 | 0 | for (buffer = cg->cups_buffers; buffer; buffer = next) |
340 | 0 | { |
341 | 0 | next = buffer->next; |
342 | 0 | free(buffer); |
343 | 0 | } |
344 | |
|
345 | 0 | cupsArrayDelete(cg->leg_size_lut); |
346 | 0 | cupsArrayDelete(cg->ppd_size_lut); |
347 | 0 | cupsArrayDelete(cg->pwg_size_lut); |
348 | |
|
349 | 0 | httpClose(cg->http); |
350 | |
|
351 | | #ifdef HAVE_SSL |
352 | | _httpFreeCredentials(cg->tls_credentials); |
353 | | #endif /* HAVE_SSL */ |
354 | |
|
355 | 0 | cupsFileClose(cg->stdio_files[0]); |
356 | 0 | cupsFileClose(cg->stdio_files[1]); |
357 | 0 | cupsFileClose(cg->stdio_files[2]); |
358 | |
|
359 | 0 | cupsFreeOptions(cg->cupsd_num_settings, cg->cupsd_settings); |
360 | |
|
361 | 0 | free(cg); |
362 | 0 | } |
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 | 0 | { |
374 | | /* |
375 | | * Register the global data for this thread... |
376 | | */ |
377 | |
|
378 | 0 | pthread_key_create(&cups_globals_key, (void (*)(void *))cups_globals_free); |
379 | 0 | } |
380 | | #endif /* HAVE_PTHREAD_H */ |