• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Global variable access routines for CUPS.
3  *
4  * Copyright © 2020-2024 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 /*
13  * Include necessary headers...
14  */
15 
16 #include "cups-private.h"
17 #include "debug-internal.h"
18 #ifndef _WIN32
19 #  include <pwd.h>
20 #endif /* !_WIN32 */
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
_cupsGlobalLock(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 */
_cupsGlobals(void)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
_cupsGlobalUnlock(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 */
DllMain(HINSTANCE hinst,DWORD reason,LPVOID reserved)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 */
cups_globals_alloc(void)181 cups_globals_alloc(void)
182 {
183   _cups_globals_t *cg = calloc(1, 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	homedir[1024] = "",	/* Home directory */
189 		installdir[1024] = "",	/* Install directory */
190 		confdir[1024] = "",	/* Server root directory */
191 		localedir[1024] = "";	/* Locale directory */
192 #endif /* _WIN32 */
193 
194 
195   if (!cg)
196     return (NULL);
197 
198  /*
199   * Clear the global storage and set the default encryption and password
200   * callback values...
201   */
202 
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 (!RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\cups.org", 0, KEY_READ, &key))
232     {
233      /*
234       * Grab the installation directory...
235       */
236 
237       char  *ptr;			/* Pointer into installdir */
238 
239       size = sizeof(installdir);
240       RegQueryValueExA(key, "installdir", NULL, NULL, installdir, &size);
241       RegCloseKey(key);
242 
243       for (ptr = installdir; *ptr;)
244       {
245         if (*ptr == '\\')
246         {
247           if (ptr[1])
248             *ptr++ = '/';
249           else
250             *ptr = '\0';		/* Strip trailing \ */
251         }
252         else if (*ptr == '/' && !ptr[1])
253           *ptr = '\0';			/* Strip trailing / */
254         else
255           ptr ++;
256       }
257     }
258 
259     snprintf(confdir, sizeof(confdir), "%s/conf", installdir);
260     snprintf(localedir, sizeof(localedir), "%s/locale", installdir);
261   }
262 
263   if ((cg->cups_datadir = getenv("CUPS_DATADIR")) == NULL)
264     cg->cups_datadir = installdir;
265 
266   if ((cg->cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
267     cg->cups_serverbin = installdir;
268 
269   if ((cg->cups_serverroot = getenv("CUPS_SERVERROOT")) == NULL)
270     cg->cups_serverroot = confdir;
271 
272   if ((cg->cups_statedir = getenv("CUPS_STATEDIR")) == NULL)
273     cg->cups_statedir = confdir;
274 
275   if ((cg->localedir = getenv("LOCALEDIR")) == NULL)
276     cg->localedir = localedir;
277 
278   if (!homedir[0])
279   {
280     const char	*userprofile = getenv("USERPROFILE");
281 				// User profile (home) directory
282     char	*homeptr;	// Pointer into homedir
283 
284     DEBUG_printf(("cups_globals_alloc: USERPROFILE=\"%s\"", userprofile));
285 
286     if (!strncmp(userprofile, "C:\\", 3))
287       userprofile += 2;
288 
289     strlcpy(homedir, userprofile, sizeof(homedir));
290     for (homeptr = homedir; *homeptr; homeptr ++)
291     {
292       // Convert back slashes to forward slashes
293       if (*homeptr == '\\')
294         *homeptr = '/';
295     }
296 
297     DEBUG_printf(("cups_globals_alloc: homedir=\"%s\"", homedir));
298   }
299 
300   cg->home = homedir;
301 
302 #else
303 #  ifdef HAVE_GETEUID
304   if ((geteuid() != getuid() && getuid()) || getegid() != getgid())
305 #  else
306   if (!getuid())
307 #  endif /* HAVE_GETEUID */
308   {
309    /*
310     * When running setuid/setgid, don't allow environment variables to override
311     * the directories...
312     */
313 
314     cg->cups_datadir    = CUPS_DATADIR;
315     cg->cups_serverbin  = CUPS_SERVERBIN;
316     cg->cups_serverroot = CUPS_SERVERROOT;
317     cg->cups_statedir   = CUPS_STATEDIR;
318     cg->localedir       = CUPS_LOCALEDIR;
319   }
320   else
321   {
322    /*
323     * Allow directories to be overridden by environment variables.
324     */
325 
326     if ((cg->cups_datadir = getenv("CUPS_DATADIR")) == NULL)
327       cg->cups_datadir = CUPS_DATADIR;
328 
329     if ((cg->cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
330       cg->cups_serverbin = CUPS_SERVERBIN;
331 
332     if ((cg->cups_serverroot = getenv("CUPS_SERVERROOT")) == NULL)
333       cg->cups_serverroot = CUPS_SERVERROOT;
334 
335     if ((cg->cups_statedir = getenv("CUPS_STATEDIR")) == NULL)
336       cg->cups_statedir = CUPS_STATEDIR;
337 
338     if ((cg->localedir = getenv("LOCALEDIR")) == NULL)
339       cg->localedir = CUPS_LOCALEDIR;
340 
341     cg->home = getenv("HOME");
342 
343 #  ifdef __APPLE__ /* Sandboxing now exposes the container as the home directory */
344     if (cg->home && strstr(cg->home, "/Library/Containers/"))
345       cg->home = NULL;
346 #  endif /* !__APPLE__ */
347   }
348 
349   if (!cg->home)
350   {
351     struct passwd	pw;		/* User info */
352     struct passwd	*result;	/* Auxiliary pointer */
353 
354     getpwuid_r(getuid(), &pw, cg->pw_buf, PW_BUF_SIZE, &result);
355     if (result)
356       cg->home = _cupsStrAlloc(pw.pw_dir);
357   }
358 #endif /* _WIN32 */
359 
360   return (cg);
361 }
362 
363 
364 /*
365  * 'cups_globals_free()' - Free global data.
366  */
367 
368 #if defined(HAVE_PTHREAD_H) || defined(_WIN32)
369 static void
cups_globals_free(_cups_globals_t * cg)370 cups_globals_free(_cups_globals_t *cg)	/* I - Pointer to global data */
371 {
372   _cups_buffer_t	*buffer,	/* Current read/write buffer */
373 			*next;		/* Next buffer */
374 
375 
376   if (cg->last_status_message)
377     _cupsStrFree(cg->last_status_message);
378 
379   for (buffer = cg->cups_buffers; buffer; buffer = next)
380   {
381     next = buffer->next;
382     free(buffer);
383   }
384 
385   cupsArrayDelete(cg->leg_size_lut);
386   cupsArrayDelete(cg->ppd_size_lut);
387   cupsArrayDelete(cg->pwg_size_lut);
388 
389   httpClose(cg->http);
390 
391 #ifdef HAVE_TLS
392   _httpFreeCredentials(cg->tls_credentials);
393 #endif /* HAVE_TLS */
394 
395   cupsFileClose(cg->stdio_files[0]);
396   cupsFileClose(cg->stdio_files[1]);
397   cupsFileClose(cg->stdio_files[2]);
398 
399   cupsFreeOptions(cg->cupsd_num_settings, cg->cupsd_settings);
400 
401   if (cg->raster_error.start)
402     free(cg->raster_error.start);
403 
404   free(cg);
405 }
406 #endif /* HAVE_PTHREAD_H || _WIN32 */
407 
408 
409 #ifdef HAVE_PTHREAD_H
410 /*
411  * 'cups_globals_init()' - Initialize environment variables.
412  */
413 
414 static void
cups_globals_init(void)415 cups_globals_init(void)
416 {
417  /*
418   * Register the global data for this thread...
419   */
420 
421   pthread_key_create(&cups_globals_key, (void (*)(void *))cups_globals_free);
422 }
423 #endif /* HAVE_PTHREAD_H */
424