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