Home | History | Annotate | Download | only in cups
      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