/src/libcups/cups/globals.c
Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // Global variable access routines for CUPS. |
3 | | // |
4 | | // Copyright © 2021-2022 by OpenPrinting. |
5 | | // Copyright © 2007-2019 by Apple Inc. |
6 | | // Copyright © 1997-2007 by Easy Software Products, all rights reserved. |
7 | | // |
8 | | // Licensed under Apache License v2.0. See the file "LICENSE" for more |
9 | | // information. |
10 | | // |
11 | | |
12 | | #include "cups-private.h" |
13 | | #ifndef _WIN32 |
14 | | # include <pwd.h> |
15 | | #endif // !_WIN32 |
16 | | |
17 | | |
18 | | // |
19 | | // Local globals... |
20 | | // |
21 | | |
22 | | #ifdef DEBUG |
23 | | static int cups_global_index = 0; |
24 | | // Next thread number |
25 | | #endif // DEBUG |
26 | | static cups_thread_key_t cups_globals_key = CUPS_THREADKEY_INITIALIZER; |
27 | | // Thread local storage key |
28 | | #ifndef _WIN32 |
29 | | static pthread_once_t cups_globals_key_once = PTHREAD_ONCE_INIT; |
30 | | // One-time initialization object |
31 | | #endif // !_WIN32 |
32 | | static cups_mutex_t cups_global_mutex = CUPS_MUTEX_INITIALIZER; |
33 | | // Global critical section |
34 | | |
35 | | |
36 | | // |
37 | | // Local functions... |
38 | | // |
39 | | |
40 | | #ifdef _WIN32 |
41 | | static void cups_fix_path(char *path); |
42 | | #endif // _WIN32 |
43 | | static _cups_globals_t *cups_globals_alloc(void); |
44 | | static void cups_globals_free(_cups_globals_t *g); |
45 | | #ifndef _WIN32 |
46 | | static void cups_globals_init(void); |
47 | | #endif // !_WIN32 |
48 | | |
49 | | |
50 | | // |
51 | | // '_cupsGlobalLock()' - Lock the global mutex. |
52 | | // |
53 | | |
54 | | void |
55 | | _cupsGlobalLock(void) |
56 | 0 | { |
57 | 0 | cupsMutexLock(&cups_global_mutex); |
58 | 0 | } |
59 | | |
60 | | |
61 | | // |
62 | | // '_cupsGlobals()' - Return a pointer to thread local storage |
63 | | // |
64 | | |
65 | | _cups_globals_t * // O - Pointer to global data |
66 | | _cupsGlobals(void) |
67 | 1.28M | { |
68 | 1.28M | _cups_globals_t *cg; // Pointer to global data |
69 | | |
70 | | |
71 | 1.28M | #ifndef _WIN32 |
72 | | // Initialize the global data exactly once... |
73 | 1.28M | pthread_once(&cups_globals_key_once, cups_globals_init); |
74 | 1.28M | #endif // !_WIN32 |
75 | | |
76 | | // See if we have allocated the data yet... |
77 | 1.28M | if ((cg = (_cups_globals_t *)cupsThreadGetData(cups_globals_key)) == NULL) |
78 | 1 | { |
79 | | // No, allocate memory as set the pointer for the key... |
80 | 1 | if ((cg = cups_globals_alloc()) != NULL) |
81 | 1 | cupsThreadSetData(cups_globals_key, cg); |
82 | 1 | } |
83 | | |
84 | | // Return the pointer to the data... |
85 | 1.28M | return (cg); |
86 | 1.28M | } |
87 | | |
88 | | |
89 | | // |
90 | | // '_cupsGlobalUnlock()' - Unlock the global mutex. |
91 | | // |
92 | | |
93 | | void |
94 | | _cupsGlobalUnlock(void) |
95 | 0 | { |
96 | 0 | cupsMutexUnlock(&cups_global_mutex); |
97 | 0 | } |
98 | | |
99 | | |
100 | | #ifdef _WIN32 |
101 | | // |
102 | | // 'DllMain()' - Main entry for library. |
103 | | // |
104 | | // @private@ |
105 | | // |
106 | | |
107 | | BOOL WINAPI // O - Success/failure |
108 | | DllMain(HINSTANCE hinst, // I - DLL module handle |
109 | | DWORD reason, // I - Reason |
110 | | LPVOID reserved) // I - Unused |
111 | | { |
112 | | _cups_globals_t *cg; // Global data |
113 | | |
114 | | |
115 | | (void)hinst; |
116 | | (void)reserved; |
117 | | |
118 | | switch (reason) |
119 | | { |
120 | | case DLL_PROCESS_ATTACH : // Called on library initialization |
121 | | InitializeCriticalSection(&cups_global_mutex); |
122 | | |
123 | | if ((cups_globals_key = TlsAlloc()) == TLS_OUT_OF_INDEXES) |
124 | | return (FALSE); |
125 | | break; |
126 | | |
127 | | case DLL_THREAD_DETACH : // Called when a thread terminates |
128 | | if ((cg = (_cups_globals_t *)TlsGetValue(cups_globals_key)) != NULL) |
129 | | cups_globals_free(cg); |
130 | | break; |
131 | | |
132 | | case DLL_PROCESS_DETACH : // Called when library is unloaded |
133 | | if ((cg = (_cups_globals_t *)TlsGetValue(cups_globals_key)) != NULL) |
134 | | cups_globals_free(cg); |
135 | | |
136 | | TlsFree(cups_globals_key); |
137 | | DeleteCriticalSection(&cups_global_mutex); |
138 | | break; |
139 | | |
140 | | default: |
141 | | break; |
142 | | } |
143 | | |
144 | | return (TRUE); |
145 | | } |
146 | | #endif // _WIN32 |
147 | | |
148 | | |
149 | | // |
150 | | // 'cups_globals_alloc()' - Allocate and initialize global data. |
151 | | // |
152 | | |
153 | | static _cups_globals_t * // O - Pointer to global data |
154 | | cups_globals_alloc(void) |
155 | 1 | { |
156 | 1 | _cups_globals_t *cg = malloc(sizeof(_cups_globals_t)); |
157 | | // Pointer to global data |
158 | | #ifdef _WIN32 |
159 | | HKEY key; // Registry key |
160 | | DWORD size; // Size of string |
161 | | const char *userprofile = getenv("USERPROFILE"); |
162 | | // User profile (home) directory |
163 | | char userconfig[1024], // User configuration directory |
164 | | *userptr; // Pointer into user config |
165 | | static char installdir[1024] = "", // Install directory |
166 | | sysconfig[1024] = ""; // Server configuration directory |
167 | | #endif // _WIN32 |
168 | | |
169 | | |
170 | 1 | if (!cg) |
171 | 0 | return (NULL); |
172 | | |
173 | | // Clear the global storage and set the default encryption and password callback values... |
174 | 1 | memset(cg, 0, sizeof(_cups_globals_t)); |
175 | 1 | cg->encryption = (http_encryption_t)-1; |
176 | 1 | cg->password_cb = (cups_password_cb_t)_cupsGetPassword; |
177 | 1 | cg->trust_first = -1; |
178 | 1 | cg->any_root = -1; |
179 | 1 | cg->expired_certs = -1; |
180 | 1 | cg->validate_certs = -1; |
181 | | |
182 | | #ifdef DEBUG |
183 | | // Friendly thread ID for debugging... |
184 | | cg->thread_id = ++ cups_global_index; |
185 | | #endif // DEBUG |
186 | | |
187 | | // Then set directories as appropriate... |
188 | | #ifdef _WIN32 |
189 | | if (!installdir[0]) |
190 | | { |
191 | | // Open the registry... |
192 | | cupsCopyString(installdir, "C:/Program Files/cups.org", sizeof(installdir)); |
193 | | |
194 | | if (!RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\cups.org", 0, KEY_READ, &key)) |
195 | | { |
196 | | // Grab the installation directory... |
197 | | char *ptr; // Pointer into installdir |
198 | | |
199 | | size = sizeof(installdir); |
200 | | RegQueryValueExA(key, "installdir", NULL, NULL, installdir, &size); |
201 | | RegCloseKey(key); |
202 | | |
203 | | for (ptr = installdir; *ptr;) |
204 | | { |
205 | | if (*ptr == '\\') |
206 | | { |
207 | | if (ptr[1]) |
208 | | *ptr++ = '/'; |
209 | | else |
210 | | *ptr = '\0'; // Strip trailing "\" |
211 | | } |
212 | | else if (*ptr == '/' && !ptr[1]) |
213 | | { |
214 | | *ptr = '\0'; // Strip trailing "/" |
215 | | } |
216 | | else |
217 | | { |
218 | | ptr ++; |
219 | | } |
220 | | } |
221 | | } |
222 | | |
223 | | snprintf(sysconfig, sizeof(sysconfig), "%s/conf", installdir); |
224 | | } |
225 | | |
226 | | if ((cg->datadir = getenv("CUPS_DATADIR")) == NULL) |
227 | | cg->datadir = installdir; |
228 | | |
229 | | if ((cg->sysconfig = getenv("CUPS_SERVERROOT")) == NULL) |
230 | | cg->sysconfig = sysconfig; |
231 | | |
232 | | DEBUG_printf("cups_globals_alloc: USERPROFILE=\"%s\"", userprofile); |
233 | | |
234 | | if (userprofile) |
235 | | snprintf(userconfig, sizeof(userconfig), "%s/AppData/Local/cups", userprofile); |
236 | | else |
237 | | cupsCopyString(userconfig, "C:/cups", sizeof(userconfig)); |
238 | | |
239 | | for (userptr = userconfig; *userptr; userptr ++) |
240 | | { |
241 | | // Convert back slashes to forward slashes |
242 | | if (*userptr == '\\') |
243 | | *userptr = '/'; |
244 | | } |
245 | | |
246 | | DEBUG_printf("cups_globals_alloc: userconfig=\"%s\"", userconfig); |
247 | | |
248 | | cg->userconfig = strdup(userconfig); |
249 | | |
250 | | #else |
251 | 1 | const char *home = getenv("HOME"); // HOME environment variable |
252 | 1 | char homedir[1024], // Home directory from account |
253 | 1 | temp[1024]; // Temporary directory string |
254 | 1 | # ifndef __APPLE__ |
255 | 1 | const char *snap_common = getenv("SNAP_COMMON"), |
256 | 1 | *xdg_config_home = getenv("XDG_CONFIG_HOME"); |
257 | | // Environment variables |
258 | 1 | # endif // !__APPLE__ |
259 | | |
260 | | # ifdef HAVE_GETEUID |
261 | | if ((geteuid() != getuid() && getuid()) || getegid() != getgid()) |
262 | | # else |
263 | 1 | if (!getuid()) |
264 | 1 | # endif // HAVE_GETEUID |
265 | 1 | { |
266 | | // When running setuid/setgid, don't allow environment variables to override |
267 | | // the system directories... |
268 | 1 | cg->datadir = CUPS_DATADIR; |
269 | 1 | cg->sysconfig = CUPS_SERVERROOT; |
270 | 1 | } |
271 | 0 | else |
272 | 0 | { |
273 | | // Allow directories to be overridden by environment variables. |
274 | 0 | if ((cg->datadir = getenv("CUPS_DATADIR")) == NULL) |
275 | 0 | cg->datadir = CUPS_DATADIR; |
276 | |
|
277 | 0 | if ((cg->sysconfig = getenv("CUPS_SERVERROOT")) == NULL) |
278 | 0 | cg->sysconfig = CUPS_SERVERROOT; |
279 | 0 | } |
280 | | |
281 | | # ifdef __APPLE__ |
282 | | if (!home) |
283 | | #else |
284 | 1 | if (!home && !xdg_config_home) |
285 | 0 | # endif // __APPLE__ |
286 | 0 | { |
287 | 0 | struct passwd pw; // User info |
288 | 0 | struct passwd *result; // Auxiliary pointer |
289 | |
|
290 | 0 | getpwuid_r(getuid(), &pw, cg->pw_buf, PW_BUF_SIZE, &result); |
291 | 0 | if (result) |
292 | 0 | { |
293 | 0 | cupsCopyString(homedir, pw.pw_dir, sizeof(homedir)); |
294 | 0 | home = homedir; |
295 | 0 | } |
296 | 0 | } |
297 | | |
298 | | # ifdef __APPLE__ |
299 | | if (home) |
300 | | { |
301 | | // macOS uses ~/Library/Application Support/FOO |
302 | | snprintf(temp, sizeof(temp), "%s/Library/Application Support/cups", home); |
303 | | } |
304 | | else |
305 | | { |
306 | | // Something went wrong, use temporary directory... |
307 | | snprintf(temp, sizeof(temp), "/private/tmp/cups%u", (unsigned)getuid()); |
308 | | } |
309 | | |
310 | | # else |
311 | 1 | if (snap_common) |
312 | 0 | { |
313 | | // Snaps use $SNAP_COMMON/FOO |
314 | 0 | snprintf(temp, sizeof(temp), "%s/cups", snap_common); |
315 | 0 | } |
316 | 1 | else if (xdg_config_home) |
317 | 0 | { |
318 | | // XDG uses $XDG_CONFIG_HOME/FOO |
319 | 0 | snprintf(temp, sizeof(temp), "%s/cups", xdg_config_home); |
320 | 0 | } |
321 | 1 | else if (home) |
322 | 1 | { |
323 | | // Use ~/.cups if it exists, otherwise ~/.config/cups (XDG standard) |
324 | 1 | snprintf(temp, sizeof(temp), "%s/.cups", home); |
325 | 1 | if (access(temp, 0)) |
326 | 1 | snprintf(temp, sizeof(temp), "%s/.config/cups", home); |
327 | 1 | } |
328 | 0 | else |
329 | 0 | { |
330 | | // Something went wrong, use temporary directory... |
331 | 0 | snprintf(temp, sizeof(temp), "/tmp/cups%u", (unsigned)getuid()); |
332 | 0 | } |
333 | 1 | # endif // __APPLE__ |
334 | | |
335 | | // Can't use _cupsStrAlloc since it causes a loop with debug logging enabled |
336 | 1 | cg->userconfig = strdup(temp); |
337 | 1 | #endif // _WIN32 |
338 | | |
339 | 1 | return (cg); |
340 | 1 | } |
341 | | |
342 | | |
343 | | // |
344 | | // 'cups_globals_free()' - Free global data. |
345 | | // |
346 | | |
347 | | static void |
348 | | cups_globals_free(_cups_globals_t *cg) // I - Pointer to global data |
349 | 0 | { |
350 | 0 | _cups_buffer_t *buffer, // Current read/write buffer |
351 | 0 | *next; // Next buffer |
352 | | |
353 | |
|
354 | 0 | if (cg->last_status_message) |
355 | 0 | _cupsStrFree(cg->last_status_message); |
356 | |
|
357 | 0 | for (buffer = cg->cups_buffers; buffer; buffer = next) |
358 | 0 | { |
359 | 0 | next = buffer->next; |
360 | 0 | free(buffer); |
361 | 0 | } |
362 | |
|
363 | 0 | cupsArrayDelete(cg->leg_size_lut); |
364 | 0 | cupsArrayDelete(cg->ppd_size_lut); |
365 | 0 | cupsArrayDelete(cg->pwg_size_lut); |
366 | |
|
367 | 0 | httpClose(cg->http); |
368 | |
|
369 | 0 | _httpFreeCredentials(cg->credentials); |
370 | |
|
371 | 0 | cupsFileClose(cg->stdio_files[0]); |
372 | 0 | cupsFileClose(cg->stdio_files[1]); |
373 | 0 | cupsFileClose(cg->stdio_files[2]); |
374 | |
|
375 | 0 | free(cg->userconfig); |
376 | 0 | free(cg->raster_error.start); |
377 | 0 | free(cg); |
378 | 0 | } |
379 | | |
380 | | |
381 | | #ifndef _WIN32 |
382 | | // |
383 | | // 'cups_globals_init()' - Initialize environment variables. |
384 | | // |
385 | | |
386 | | static void |
387 | | cups_globals_init(void) |
388 | 1 | { |
389 | | // Register the global data for this thread... |
390 | 1 | pthread_key_create(&cups_globals_key, (void (*)(void *))cups_globals_free); |
391 | 1 | } |
392 | | #endif // !_WIN32 |