• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * User, system, and password routines for CUPS.
3  *
4  * Copyright © 2020-2025 by OpenPrinting.
5  * Copyright © 2007-2019 by Apple Inc.
6  * Copyright © 1997-2006 by Easy Software Products.
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 #include <stdlib.h>
19 #include <sys/stat.h>
20 #ifdef _WIN32
21 #  include <windows.h>
22 #else
23 #  include <pwd.h>
24 #  include <termios.h>
25 #  include <sys/utsname.h>
26 #endif /* _WIN32 */
27 #ifdef __APPLE__
28 #  include <sys/sysctl.h>
29 #endif /* __APPLE__ */
30 
31 
32 /*
33  * Local constants...
34  */
35 
36 #ifdef __APPLE__
37 #  if TARGET_OS_OSX
38 #    define kCUPSPrintingPrefs	CFSTR("org.cups.PrintingPrefs")
39 #    define kPREFIX		""
40 #  else
41 #    define kCUPSPrintingPrefs	CFSTR(".GlobalPreferences")
42 #    define kPREFIX		"AirPrint"
43 #  endif /* TARGET_OS_OSX */
44 #  define kDigestOptionsKey	CFSTR(kPREFIX "DigestOptions")
45 #  define kUserKey		CFSTR(kPREFIX "User")
46 #  define kUserAgentTokensKey	CFSTR(kPREFIX "UserAgentTokens")
47 #  define kAllowAnyRootKey	CFSTR(kPREFIX "AllowAnyRoot")
48 #  define kAllowExpiredCertsKey	CFSTR(kPREFIX "AllowExpiredCerts")
49 #  define kEncryptionKey	CFSTR(kPREFIX "Encryption")
50 #  define kGSSServiceNameKey	CFSTR(kPREFIX "GSSServiceName")
51 #  define kSSLOptionsKey	CFSTR(kPREFIX "SSLOptions")
52 #  define kTrustOnFirstUseKey	CFSTR(kPREFIX "TrustOnFirstUse")
53 #  define kValidateCertsKey	CFSTR(kPREFIX "ValidateCerts")
54 /* Deprecated */
55 #  define kAllowRC4		CFSTR(kPREFIX "AllowRC4")
56 #  define kAllowSSL3		CFSTR(kPREFIX "AllowSSL3")
57 #  define kAllowDH		CFSTR(kPREFIX "AllowDH")
58 #endif /* __APPLE__ */
59 
60 #define _CUPS_PASSCHAR	'*'		/* Character that is echoed for password */
61 
62 
63 /*
64  * Local types...
65  */
66 
67 typedef struct _cups_client_conf_s	/**** client.conf config data ****/
68 {
69   _cups_digestoptions_t	digestoptions;	/* DigestOptions values */
70   _cups_uatokens_t	uatokens;	/* UserAgentTokens values */
71 #ifdef HAVE_TLS
72   int			ssl_options,	/* SSLOptions values */
73 			ssl_min_version,/* Minimum SSL/TLS version */
74 			ssl_max_version;/* Maximum SSL/TLS version */
75 #endif /* HAVE_TLS */
76   int			trust_first,	/* Trust on first use? */
77 			any_root,	/* Allow any (e.g., self-signed) root */
78 			expired_certs,	/* Allow expired certs */
79 			validate_certs;	/* Validate certificates */
80   http_encryption_t	encryption;	/* Encryption setting */
81   char			user[65],	/* User name */
82 			server_name[256];
83 					/* Server hostname */
84 #ifdef HAVE_GSSAPI
85   char			gss_service_name[32];
86   					/* Kerberos service name */
87 #endif /* HAVE_GSSAPI */
88 } _cups_client_conf_t;
89 
90 
91 /*
92  * Local functions...
93  */
94 
95 #ifdef __APPLE__
96 #  ifdef HAVE_TLS
97 static int	cups_apple_get_boolean(CFStringRef key, int *value);
98 #  endif /* HAVE_TLS */
99 static int	cups_apple_get_string(CFStringRef key, char *value, size_t valsize);
100 #endif /* __APPLE__ */
101 static int	cups_boolean_value(const char *value);
102 static void	cups_finalize_client_conf(_cups_client_conf_t *cc);
103 static void	cups_init_client_conf(_cups_client_conf_t *cc);
104 static void	cups_read_client_conf(cups_file_t *fp, _cups_client_conf_t *cc);
105 static void	cups_set_default_ipp_port(_cups_globals_t *cg);
106 static void	cups_set_digestoptions(_cups_client_conf_t *cc, const char *value);
107 static void	cups_set_encryption(_cups_client_conf_t *cc, const char *value);
108 #ifdef HAVE_GSSAPI
109 static void	cups_set_gss_service_name(_cups_client_conf_t *cc, const char *value);
110 #endif /* HAVE_GSSAPI */
111 static void	cups_set_server_name(_cups_client_conf_t *cc, const char *value);
112 #ifdef HAVE_TLS
113 static void	cups_set_ssl_options(_cups_client_conf_t *cc, const char *value);
114 #endif /* HAVE_TLS */
115 static void	cups_set_uatokens(_cups_client_conf_t *cc, const char *value);
116 static void	cups_set_user(_cups_client_conf_t *cc, const char *value);
117 
118 
119 /*
120  * 'cupsEncryption()' - Get the current encryption settings.
121  *
122  * The default encryption setting comes from the CUPS_ENCRYPTION
123  * environment variable, then the ~/.cups/client.conf file, and finally the
124  * /etc/cups/client.conf file. If not set, the default is
125  * @code HTTP_ENCRYPTION_IF_REQUESTED@.
126  *
127  * Note: The current encryption setting is tracked separately for each thread
128  * in a program. Multi-threaded programs that override the setting via the
129  * @link cupsSetEncryption@ function need to do so in each thread for the same
130  * setting to be used.
131  */
132 
133 http_encryption_t			/* O - Encryption settings */
cupsEncryption(void)134 cupsEncryption(void)
135 {
136   _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
137 
138 
139   if (cg->encryption == (http_encryption_t)-1)
140     _cupsSetDefaults();
141 
142   return (cg->encryption);
143 }
144 
145 
146 /*
147  * 'cupsGetPassword()' - Get a password from the user.
148  *
149  * Uses the current password callback function. Returns @code NULL@ if the
150  * user does not provide a password.
151  *
152  * Note: The current password callback function is tracked separately for each
153  * thread in a program. Multi-threaded programs that override the setting via
154  * the @link cupsSetPasswordCB@ or @link cupsSetPasswordCB2@ functions need to
155  * do so in each thread for the same function to be used.
156  *
157  * @exclude all@
158  */
159 
160 const char *				/* O - Password */
cupsGetPassword(const char * prompt)161 cupsGetPassword(const char *prompt)	/* I - Prompt string */
162 {
163   _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
164 
165 
166   return ((cg->password_cb)(prompt, NULL, NULL, NULL, cg->password_data));
167 }
168 
169 
170 /*
171  * 'cupsGetPassword2()' - Get a password from the user using the current
172  *                        password callback.
173  *
174  * Uses the current password callback function. Returns @code NULL@ if the
175  * user does not provide a password.
176  *
177  * Note: The current password callback function is tracked separately for each
178  * thread in a program. Multi-threaded programs that override the setting via
179  * the @link cupsSetPasswordCB2@ function need to do so in each thread for the
180  * same function to be used.
181  *
182  * @since CUPS 1.4/macOS 10.6@
183  */
184 
185 const char *				/* O - Password */
cupsGetPassword2(const char * prompt,http_t * http,const char * method,const char * resource)186 cupsGetPassword2(const char *prompt,	/* I - Prompt string */
187 		 http_t     *http,	/* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
188 		 const char *method,	/* I - Request method ("GET", "POST", "PUT") */
189 		 const char *resource)	/* I - Resource path */
190 {
191   _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
192 
193 
194   if (!http)
195     http = _cupsConnect();
196 
197   return ((cg->password_cb)(prompt, http, method, resource, cg->password_data));
198 }
199 
200 
201 /*
202  * 'cupsServer()' - Return the hostname/address of the current server.
203  *
204  * The default server comes from the CUPS_SERVER environment variable, then the
205  * ~/.cups/client.conf file, and finally the /etc/cups/client.conf file. If not
206  * set, the default is the local system - either "localhost" or a domain socket
207  * path.
208  *
209  * The returned value can be a fully-qualified hostname, a numeric IPv4 or IPv6
210  * address, or a domain socket pathname.
211  *
212  * Note: The current server is tracked separately for each thread in a program.
213  * Multi-threaded programs that override the server via the
214  * @link cupsSetServer@ function need to do so in each thread for the same
215  * server to be used.
216  */
217 
218 const char *				/* O - Server name */
cupsServer(void)219 cupsServer(void)
220 {
221   _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
222 
223 
224   if (!cg->server[0])
225     _cupsSetDefaults();
226 
227   return (cg->server);
228 }
229 
230 
231 /*
232  * 'cupsSetClientCertCB()' - Set the client certificate callback.
233  *
234  * Pass @code NULL@ to restore the default callback.
235  *
236  * Note: The current certificate callback is tracked separately for each thread
237  * in a program. Multi-threaded programs that override the callback need to do
238  * so in each thread for the same callback to be used.
239  *
240  * @since CUPS 1.5/macOS 10.7@
241  */
242 
243 void
cupsSetClientCertCB(cups_client_cert_cb_t cb,void * user_data)244 cupsSetClientCertCB(
245     cups_client_cert_cb_t cb,		/* I - Callback function */
246     void                  *user_data)	/* I - User data pointer */
247 {
248   _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
249 
250 
251   cg->client_cert_cb	= cb;
252   cg->client_cert_data	= user_data;
253 }
254 
255 
256 /*
257  * 'cupsSetCredentials()' - Set the default credentials to be used for SSL/TLS
258  *			    connections.
259  *
260  * Note: The default credentials are tracked separately for each thread in a
261  * program. Multi-threaded programs that override the setting need to do so in
262  * each thread for the same setting to be used.
263  *
264  * @since CUPS 1.5/macOS 10.7@
265  */
266 
267 int					/* O - Status of call (0 = success) */
cupsSetCredentials(cups_array_t * credentials)268 cupsSetCredentials(
269     cups_array_t *credentials)		/* I - Array of credentials */
270 {
271   _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
272 
273 
274   if (cupsArrayCount(credentials) < 1)
275     return (-1);
276 
277 #ifdef HAVE_TLS
278   _httpFreeCredentials(cg->tls_credentials);
279   cg->tls_credentials = _httpCreateCredentials(credentials);
280 #endif /* HAVE_TLS */
281 
282   return (cg->tls_credentials ? 0 : -1);
283 }
284 
285 
286 /*
287  * 'cupsSetEncryption()' - Set the encryption preference.
288  *
289  * The default encryption setting comes from the CUPS_ENCRYPTION
290  * environment variable, then the ~/.cups/client.conf file, and finally the
291  * /etc/cups/client.conf file. If not set, the default is
292  * @code HTTP_ENCRYPTION_IF_REQUESTED@.
293  *
294  * Note: The current encryption setting is tracked separately for each thread
295  * in a program. Multi-threaded programs that override the setting need to do
296  * so in each thread for the same setting to be used.
297  */
298 
299 void
cupsSetEncryption(http_encryption_t e)300 cupsSetEncryption(http_encryption_t e)	/* I - New encryption preference */
301 {
302   _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
303 
304 
305   cg->encryption = e;
306 
307   if (cg->http)
308     httpEncryption(cg->http, e);
309 }
310 
311 
312 /*
313  * 'cupsSetOAuthCB()' - Set the OAuth 2.0 callback for CUPS.
314  *
315  * This function sets the OAuth 2.0 callback for the various CUPS APIs that
316  * send HTTP requests. Pass @code NULL@ to restore the default (console-based)
317  * callback.
318  *
319  * The OAuth callback receives the HTTP connection, realm name, scope name (if
320  * any), resource path, and the "user_data" pointer for each request that
321  * requires an OAuth access token. The function then returns either the Bearer
322  * token string or `NULL` if no authorization could be obtained.
323  *
324  * Beyond reusing the Bearer token for subsequent requests on the same HTTP
325  * connection, no caching of the token is done by the CUPS library.  The
326  * callback can determine whether to refresh a cached token by examining any
327  * existing token returned by the @link httpGetAuthString@ function.
328  *
329  * Note: The current OAuth callback is tracked separately for each thread in a
330  * program. Multi-threaded programs that override the callback need to do so in
331  * each thread for the same callback to be used.
332  *
333  * @since CUPS 2.4@
334  */
335 
336 void
cupsSetOAuthCB(cups_oauth_cb_t cb,void * user_data)337 cupsSetOAuthCB(
338     cups_oauth_cb_t cb,			/* I - Callback function */
339     void            *user_data)		/* I - User data pointer */
340 {
341   _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
342 
343 
344   cg->oauth_cb   = cb;
345   cg->oauth_data = user_data;
346 }
347 
348 
349 /*
350  * 'cupsSetPasswordCB()' - Set the password callback for CUPS.
351  *
352  * Pass @code NULL@ to restore the default (console) password callback, which
353  * reads the password from the console. Programs should call either this
354  * function or @link cupsSetPasswordCB2@, as only one callback can be registered
355  * by a program per thread.
356  *
357  * Note: The current password callback is tracked separately for each thread
358  * in a program. Multi-threaded programs that override the callback need to do
359  * so in each thread for the same callback to be used.
360  *
361  * @exclude all@
362  */
363 
364 void
cupsSetPasswordCB(cups_password_cb_t cb)365 cupsSetPasswordCB(cups_password_cb_t cb)/* I - Callback function */
366 {
367   _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
368 
369 
370   if (cb == (cups_password_cb_t)0)
371     cg->password_cb = (cups_password_cb2_t)_cupsGetPassword;
372   else
373     cg->password_cb = (cups_password_cb2_t)cb;
374 
375   cg->password_data = NULL;
376 }
377 
378 
379 /*
380  * 'cupsSetPasswordCB2()' - Set the advanced password callback for CUPS.
381  *
382  * Pass @code NULL@ to restore the default (console) password callback, which
383  * reads the password from the console. Programs should call either this
384  * function or @link cupsSetPasswordCB2@, as only one callback can be registered
385  * by a program per thread.
386  *
387  * Note: The current password callback is tracked separately for each thread
388  * in a program. Multi-threaded programs that override the callback need to do
389  * so in each thread for the same callback to be used.
390  *
391  * @since CUPS 1.4/macOS 10.6@
392  */
393 
394 void
cupsSetPasswordCB2(cups_password_cb2_t cb,void * user_data)395 cupsSetPasswordCB2(
396     cups_password_cb2_t cb,		/* I - Callback function */
397     void                *user_data)	/* I - User data pointer */
398 {
399   _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
400 
401 
402   if (cb == (cups_password_cb2_t)0)
403     cg->password_cb = (cups_password_cb2_t)_cupsGetPassword;
404   else
405     cg->password_cb = cb;
406 
407   cg->password_data = user_data;
408 }
409 
410 
411 /*
412  * 'cupsSetServer()' - Set the default server name and port.
413  *
414  * The "server" string can be a fully-qualified hostname, a numeric
415  * IPv4 or IPv6 address, or a domain socket pathname. Hostnames and numeric IP
416  * addresses can be optionally followed by a colon and port number to override
417  * the default port 631, e.g. "hostname:8631". Pass @code NULL@ to restore the
418  * default server name and port.
419  *
420  * Note: The current server is tracked separately for each thread in a program.
421  * Multi-threaded programs that override the server need to do so in each
422  * thread for the same server to be used.
423  */
424 
425 void
cupsSetServer(const char * server)426 cupsSetServer(const char *server)	/* I - Server name */
427 {
428   char		*options,		/* Options */
429 		*port;			/* Pointer to port */
430   _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
431 
432 
433   if (server)
434   {
435     strlcpy(cg->server, server, sizeof(cg->server));
436 
437     if (cg->server[0] != '/' && (options = strrchr(cg->server, '/')) != NULL)
438     {
439       *options++ = '\0';
440 
441       if (!strcmp(options, "version=1.0"))
442         cg->server_version = 10;
443       else if (!strcmp(options, "version=1.1"))
444         cg->server_version = 11;
445       else if (!strcmp(options, "version=2.0"))
446         cg->server_version = 20;
447       else if (!strcmp(options, "version=2.1"))
448         cg->server_version = 21;
449       else if (!strcmp(options, "version=2.2"))
450         cg->server_version = 22;
451     }
452     else
453       cg->server_version = 20;
454 
455     if (cg->server[0] != '/' && (port = strrchr(cg->server, ':')) != NULL &&
456         !strchr(port, ']') && isdigit(port[1] & 255))
457     {
458       *port++ = '\0';
459 
460       cg->ipp_port = atoi(port);
461     }
462 
463     if (!cg->ipp_port)
464       cups_set_default_ipp_port(cg);
465 
466     if (cg->server[0] == '/')
467       strlcpy(cg->servername, "localhost", sizeof(cg->servername));
468     else
469       strlcpy(cg->servername, cg->server, sizeof(cg->servername));
470   }
471   else
472   {
473     cg->server[0]      = '\0';
474     cg->servername[0]  = '\0';
475     cg->server_version = 20;
476     cg->ipp_port       = 0;
477   }
478 
479   if (cg->http)
480   {
481     httpClose(cg->http);
482     cg->http = NULL;
483   }
484 }
485 
486 
487 /*
488  * 'cupsSetServerCertCB()' - Set the server certificate callback.
489  *
490  * Pass @code NULL@ to restore the default callback.
491  *
492  * Note: The current credentials callback is tracked separately for each thread
493  * in a program. Multi-threaded programs that override the callback need to do
494  * so in each thread for the same callback to be used.
495  *
496  * @since CUPS 1.5/macOS 10.7@
497  */
498 
499 void
cupsSetServerCertCB(cups_server_cert_cb_t cb,void * user_data)500 cupsSetServerCertCB(
501     cups_server_cert_cb_t cb,		/* I - Callback function */
502     void		  *user_data)	/* I - User data pointer */
503 {
504   _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
505 
506 
507   cg->server_cert_cb	= cb;
508   cg->server_cert_data	= user_data;
509 }
510 
511 
512 /*
513  * 'cupsSetUser()' - Set the default user name.
514  *
515  * Pass @code NULL@ to restore the default user name.
516  *
517  * Note: The current user name is tracked separately for each thread in a
518  * program. Multi-threaded programs that override the user name need to do so
519  * in each thread for the same user name to be used.
520  */
521 
522 void
cupsSetUser(const char * user)523 cupsSetUser(const char *user)		/* I - User name */
524 {
525   _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
526 
527 
528   if (user)
529     strlcpy(cg->user, user, sizeof(cg->user));
530   else
531     cg->user[0] = '\0';
532 }
533 
534 
535 /*
536  * 'cupsSetUserAgent()' - Set the default HTTP User-Agent string.
537  *
538  * Setting the string to NULL forces the default value containing the CUPS
539  * version, IPP version, and operating system version and architecture.
540  *
541  * @since CUPS 1.7/macOS 10.9@
542  */
543 
544 void
cupsSetUserAgent(const char * user_agent)545 cupsSetUserAgent(const char *user_agent)/* I - User-Agent string or @code NULL@ */
546 {
547   _cups_globals_t	*cg = _cupsGlobals();
548 					/* Thread globals */
549 #ifdef _WIN32
550   SYSTEM_INFO		sysinfo;	/* System information */
551   OSVERSIONINFOW	version;	/* OS version info */
552   const char		*machine;	/* Hardware/machine name */
553 #elif defined(__APPLE__)
554   struct utsname	name;		/* uname info */
555   char			version[256];	/* macOS/iOS version */
556   size_t		len;		/* Length of value */
557 #else
558   struct utsname	name;		/* uname info */
559 #endif /* _WIN32 */
560 
561 
562   if (user_agent)
563   {
564     strlcpy(cg->user_agent, user_agent, sizeof(cg->user_agent));
565     return;
566   }
567 
568   if (cg->uatokens < _CUPS_UATOKENS_OS)
569   {
570     switch (cg->uatokens)
571     {
572       default :
573       case _CUPS_UATOKENS_NONE :
574 	  cg->user_agent[0] = '\0';
575 	  break;
576       case _CUPS_UATOKENS_PRODUCT_ONLY :
577 	  strlcpy(cg->user_agent, "CUPS IPP", sizeof(cg->user_agent));
578 	  break;
579       case _CUPS_UATOKENS_MAJOR :
580 	  snprintf(cg->user_agent, sizeof(cg->user_agent), "CUPS/%d IPP/2", CUPS_VERSION_MAJOR);
581 	  break;
582       case _CUPS_UATOKENS_MINOR :
583 	  snprintf(cg->user_agent, sizeof(cg->user_agent), "CUPS/%d.%d IPP/2.1", CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR);
584 	  break;
585       case _CUPS_UATOKENS_MINIMAL :
586 	  strlcpy(cg->user_agent, CUPS_MINIMAL " IPP/2.1", sizeof(cg->user_agent));
587 	  break;
588     }
589     return;
590   }
591 
592 #ifdef _WIN32
593  /*
594   * Gather Windows version information for the User-Agent string...
595   */
596 
597   typedef NTSTATUS(WINAPI * RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
598 
599   memset(&version, 0, sizeof(version));
600   version.dwOSVersionInfoSize = sizeof(version);
601 
602   /* RtlGetVersion gets the current native version of Windows, even when running in compatibility mode */
603   RtlGetVersionPtr RtlGetVersionInternal = (RtlGetVersionPtr)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlGetVersion");
604   if (RtlGetVersionInternal)
605   {
606     RtlGetVersionInternal((PRTL_OSVERSIONINFOW)&version);
607   }
608   else
609   {
610     /* Should not happen, but just in case, fallback to deprecated GetVersionExW */
611     GetVersionExW(&version);
612   }
613   GetNativeSystemInfo(&sysinfo);
614 
615   switch (sysinfo.wProcessorArchitecture)
616   {
617     case PROCESSOR_ARCHITECTURE_AMD64 :
618         machine = "amd64";
619         break;
620 
621     case PROCESSOR_ARCHITECTURE_ARM :
622         machine = "arm";
623         break;
624 
625     case PROCESSOR_ARCHITECTURE_IA64 :
626         machine = "ia64";
627         break;
628 
629     case PROCESSOR_ARCHITECTURE_INTEL :
630         machine = "intel";
631         break;
632 
633     default :
634         machine = "unknown";
635         break;
636   }
637 
638   if (cg->uatokens == _CUPS_UATOKENS_OS)
639     snprintf(cg->user_agent, sizeof(cg->user_agent), CUPS_MINIMAL " (Windows %lu.%lu) IPP/2.0", version.dwMajorVersion, version.dwMinorVersion);
640   else
641     snprintf(cg->user_agent, sizeof(cg->user_agent), CUPS_MINIMAL " (Windows %lu.%lu; %s) IPP/2.0", version.dwMajorVersion, version.dwMinorVersion, machine);
642 
643 #elif defined(__APPLE__)
644  /*
645   * Gather macOS/iOS version information for the User-Agent string...
646   */
647 
648   uname(&name);
649 
650   len = sizeof(version) - 1;
651   if (!sysctlbyname("kern.osproductversion", version, &len, NULL, 0))
652     version[len] = '\0';
653   else
654     strlcpy(version, "unknown", sizeof(version));
655 
656 #  if TARGET_OS_OSX
657   if (cg->uatokens == _CUPS_UATOKENS_OS)
658     snprintf(cg->user_agent, sizeof(cg->user_agent), CUPS_MINIMAL " (macOS %s) IPP/2.0", version);
659   else
660     snprintf(cg->user_agent, sizeof(cg->user_agent), CUPS_MINIMAL " (macOS %s; %s) IPP/2.0", version, name.machine);
661 
662 #  else
663   if (cg->uatokens == _CUPS_UATOKENS_OS)
664     snprintf(cg->user_agent, sizeof(cg->user_agent), CUPS_MINIMAL " (iOS %s) IPP/2.0", version);
665   else
666     snprintf(cg->user_agent, sizeof(cg->user_agent), CUPS_MINIMAL " (iOS %s; %s) IPP/2.0", version, name.machine);
667 #  endif /* TARGET_OS_OSX */
668 
669 #else
670  /*
671   * Gather generic UNIX version information for the User-Agent string...
672   */
673 
674   uname(&name);
675 
676   if (cg->uatokens == _CUPS_UATOKENS_OS)
677     snprintf(cg->user_agent, sizeof(cg->user_agent), CUPS_MINIMAL " (%s %s) IPP/2.0", name.sysname, name.release);
678   else
679     snprintf(cg->user_agent, sizeof(cg->user_agent), CUPS_MINIMAL " (%s %s; %s) IPP/2.0", name.sysname, name.release, name.machine);
680 #endif /* _WIN32 */
681 }
682 
683 
684 /*
685  * 'cupsUser()' - Return the current user's name.
686  *
687  * Note: The current user name is tracked separately for each thread in a
688  * program. Multi-threaded programs that override the user name with the
689  * @link cupsSetUser@ function need to do so in each thread for the same user
690  * name to be used.
691  */
692 
693 const char *				/* O - User name */
cupsUser(void)694 cupsUser(void)
695 {
696   _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
697 
698 
699   if (!cg->user[0])
700     _cupsSetDefaults();
701 
702   return (cg->user);
703 }
704 
705 
706 /*
707  * 'cupsUserAgent()' - Return the default HTTP User-Agent string.
708  *
709  * @since CUPS 1.7/macOS 10.9@
710  */
711 
712 const char *				/* O - User-Agent string */
cupsUserAgent(void)713 cupsUserAgent(void)
714 {
715   _cups_globals_t *cg = _cupsGlobals();	/* Thread globals */
716 
717 
718   if (!cg->user_agent[0])
719     cupsSetUserAgent(NULL);
720 
721   return (cg->user_agent);
722 }
723 
724 
725 /*
726  * '_cupsGetPassword()' - Get a password from the user.
727  */
728 
729 const char *				/* O - Password or @code NULL@ if none */
_cupsGetPassword(const char * prompt)730 _cupsGetPassword(const char *prompt)	/* I - Prompt string */
731 {
732 #ifdef _WIN32
733   HANDLE		tty;		/* Console handle */
734   DWORD			mode;		/* Console mode */
735   char			passch,		/* Current key press */
736 			*passptr,	/* Pointer into password string */
737 			*passend;	/* End of password string */
738   DWORD			passbytes;	/* Bytes read */
739   _cups_globals_t	*cg = _cupsGlobals();
740 					/* Thread globals */
741 
742 
743  /*
744   * Disable input echo and set raw input...
745   */
746 
747   if ((tty = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE)
748     return (NULL);
749 
750   if (!GetConsoleMode(tty, &mode))
751     return (NULL);
752 
753   if (!SetConsoleMode(tty, 0))
754     return (NULL);
755 
756  /*
757   * Display the prompt...
758   */
759 
760   printf("%s ", prompt);
761   fflush(stdout);
762 
763  /*
764   * Read the password string from /dev/tty until we get interrupted or get a
765   * carriage return or newline...
766   */
767 
768   passptr = cg->password;
769   passend = cg->password + sizeof(cg->password) - 1;
770 
771   while (ReadFile(tty, &passch, 1, &passbytes, NULL))
772   {
773     if (passch == 0x0A || passch == 0x0D)
774     {
775      /*
776       * Enter/return...
777       */
778 
779       break;
780     }
781     else if (passch == 0x08 || passch == 0x7F)
782     {
783      /*
784       * Backspace/delete (erase character)...
785       */
786 
787       if (passptr > cg->password)
788       {
789         passptr --;
790         fputs("\010 \010", stdout);
791       }
792       else
793         putchar(0x07);
794     }
795     else if (passch == 0x15)
796     {
797      /*
798       * CTRL+U (erase line)
799       */
800 
801       if (passptr > cg->password)
802       {
803 	while (passptr > cg->password)
804 	{
805           passptr --;
806           fputs("\010 \010", stdout);
807         }
808       }
809       else
810         putchar(0x07);
811     }
812     else if (passch == 0x03)
813     {
814      /*
815       * CTRL+C...
816       */
817 
818       passptr = cg->password;
819       break;
820     }
821     else if ((passch & 255) < 0x20 || passptr >= passend)
822       putchar(0x07);
823     else
824     {
825       *passptr++ = passch;
826       putchar(_CUPS_PASSCHAR);
827     }
828 
829     fflush(stdout);
830   }
831 
832   putchar('\n');
833   fflush(stdout);
834 
835  /*
836   * Cleanup...
837   */
838 
839   SetConsoleMode(tty, mode);
840 
841  /*
842   * Return the proper value...
843   */
844 
845   if (passbytes == 1 && passptr > cg->password)
846   {
847     *passptr = '\0';
848     return (cg->password);
849   }
850   else
851   {
852     memset(cg->password, 0, sizeof(cg->password));
853     return (NULL);
854   }
855 
856 #else
857   int			tty;		/* /dev/tty - never read from stdin */
858   struct termios	original,	/* Original input mode */
859 			noecho;		/* No echo input mode */
860   char			passch,		/* Current key press */
861 			*passptr,	/* Pointer into password string */
862 			*passend;	/* End of password string */
863   ssize_t		passbytes;	/* Bytes read */
864   _cups_globals_t	*cg = _cupsGlobals();
865 					/* Thread globals */
866 
867 
868  /*
869   * Disable input echo and set raw input...
870   */
871 
872   if ((tty = open("/dev/tty", O_RDONLY)) < 0)
873     return (NULL);
874 
875   if (tcgetattr(tty, &original))
876   {
877     close(tty);
878     return (NULL);
879   }
880 
881   noecho = original;
882   noecho.c_lflag &= (tcflag_t)~(ICANON | ECHO | ECHOE | ISIG);
883   noecho.c_cc[VMIN]  = 1;
884   noecho.c_cc[VTIME] = 0;
885 
886   if (tcsetattr(tty, TCSAFLUSH, &noecho))
887   {
888     close(tty);
889     return (NULL);
890   }
891 
892  /*
893   * Display the prompt...
894   */
895 
896   printf("%s ", prompt);
897   fflush(stdout);
898 
899  /*
900   * Read the password string from /dev/tty until we get interrupted or get a
901   * carriage return or newline...
902   */
903 
904   passptr = cg->password;
905   passend = cg->password + sizeof(cg->password) - 1;
906 
907   while ((passbytes = read(tty, &passch, 1)) == 1)
908   {
909     if (passch == noecho.c_cc[VEOL] ||
910 #  ifdef VEOL2
911         passch == noecho.c_cc[VEOL2] ||
912 #  endif /* VEOL2 */
913         passch == 0x0A || passch == 0x0D)
914     {
915      /*
916       * Enter/return...
917       */
918 
919       break;
920     }
921     else if (passch == noecho.c_cc[VERASE] ||
922              passch == 0x08 || passch == 0x7F)
923     {
924      /*
925       * Backspace/delete (erase character)...
926       */
927 
928       if (passptr > cg->password)
929       {
930         passptr --;
931         fputs("\010 \010", stdout);
932       }
933       else
934         putchar(0x07);
935     }
936     else if (passch == noecho.c_cc[VKILL])
937     {
938      /*
939       * CTRL+U (erase line)
940       */
941 
942       if (passptr > cg->password)
943       {
944 	while (passptr > cg->password)
945 	{
946           passptr --;
947           fputs("\010 \010", stdout);
948         }
949       }
950       else
951         putchar(0x07);
952     }
953     else if (passch == noecho.c_cc[VINTR] || passch == noecho.c_cc[VQUIT] ||
954              passch == noecho.c_cc[VEOF])
955     {
956      /*
957       * CTRL+C, CTRL+D, or CTRL+Z...
958       */
959 
960       passptr = cg->password;
961       break;
962     }
963     else if ((passch & 255) < 0x20 || passptr >= passend)
964       putchar(0x07);
965     else
966     {
967       *passptr++ = passch;
968       putchar(_CUPS_PASSCHAR);
969     }
970 
971     fflush(stdout);
972   }
973 
974   putchar('\n');
975   fflush(stdout);
976 
977  /*
978   * Cleanup...
979   */
980 
981   tcsetattr(tty, TCSAFLUSH, &original);
982   close(tty);
983 
984  /*
985   * Return the proper value...
986   */
987 
988   if (passbytes == 1 && passptr > cg->password)
989   {
990     *passptr = '\0';
991     return (cg->password);
992   }
993   else
994   {
995     memset(cg->password, 0, sizeof(cg->password));
996     return (NULL);
997   }
998 #endif /* _WIN32 */
999 }
1000 
1001 
1002 #ifdef HAVE_GSSAPI
1003 /*
1004  * '_cupsGSSServiceName()' - Get the GSS (Kerberos) service name.
1005  */
1006 
1007 const char *
_cupsGSSServiceName(void)1008 _cupsGSSServiceName(void)
1009 {
1010   _cups_globals_t *cg = _cupsGlobals();	/* Thread globals */
1011 
1012 
1013   if (!cg->gss_service_name[0])
1014     _cupsSetDefaults();
1015 
1016   return (cg->gss_service_name);
1017 }
1018 #endif /* HAVE_GSSAPI */
1019 
1020 
1021 /*
1022  * '_cupsSetDefaults()' - Set the default server, port, and encryption.
1023  */
1024 
1025 void
_cupsSetDefaults(void)1026 _cupsSetDefaults(void)
1027 {
1028   cups_file_t	*fp;			/* File */
1029   char		filename[1024];		/* Filename */
1030   _cups_client_conf_t cc;		/* client.conf values */
1031   _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
1032 
1033 
1034   DEBUG_puts("_cupsSetDefaults()");
1035 
1036  /*
1037   * Load initial client.conf values...
1038   */
1039 
1040   cups_init_client_conf(&cc);
1041 
1042  /*
1043   * Read the /etc/cups/client.conf and ~/.cups/client.conf files, if
1044   * present.
1045   */
1046 
1047   snprintf(filename, sizeof(filename), "%s/client.conf", cg->cups_serverroot);
1048   if ((fp = cupsFileOpen(filename, "r")) != NULL)
1049   {
1050     cups_read_client_conf(fp, &cc);
1051     cupsFileClose(fp);
1052   }
1053 
1054   if (cg->home)
1055   {
1056    /*
1057     * Look for ~/.cups/client.conf...
1058     */
1059 
1060 #if _WIN32
1061     snprintf(filename, sizeof(filename), "%s/AppData/Local/cups/client.conf", cg->home);
1062 #else
1063     snprintf(filename, sizeof(filename), "%s/.cups/client.conf", cg->home);
1064 #endif // _WIN32
1065 
1066     if ((fp = cupsFileOpen(filename, "r")) != NULL)
1067     {
1068       cups_read_client_conf(fp, &cc);
1069       cupsFileClose(fp);
1070     }
1071   }
1072 
1073  /*
1074   * Finalize things so every client.conf value is set...
1075   */
1076 
1077   cups_finalize_client_conf(&cc);
1078 
1079   cg->uatokens = cc.uatokens;
1080 
1081   if (cg->encryption == (http_encryption_t)-1)
1082     cg->encryption = cc.encryption;
1083 
1084   if (!cg->server[0] || !cg->ipp_port)
1085     cupsSetServer(cc.server_name);
1086 
1087   if (!cg->ipp_port)
1088     cups_set_default_ipp_port(cg);
1089 
1090   if (!cg->user[0])
1091     strlcpy(cg->user, cc.user, sizeof(cg->user));
1092 
1093 #ifdef HAVE_GSSAPI
1094   if (!cg->gss_service_name[0])
1095     strlcpy(cg->gss_service_name, cc.gss_service_name, sizeof(cg->gss_service_name));
1096 #endif /* HAVE_GSSAPI */
1097 
1098   if (cg->trust_first < 0)
1099     cg->trust_first = cc.trust_first;
1100 
1101   if (cg->any_root < 0)
1102     cg->any_root = cc.any_root;
1103 
1104   if (cg->expired_certs < 0)
1105     cg->expired_certs = cc.expired_certs;
1106 
1107   if (cg->validate_certs < 0)
1108     cg->validate_certs = cc.validate_certs;
1109 
1110 #ifdef HAVE_TLS
1111   _httpTLSSetOptions(cc.ssl_options | _HTTP_TLS_SET_DEFAULT, cc.ssl_min_version, cc.ssl_max_version);
1112 #endif /* HAVE_TLS */
1113 }
1114 
1115 
1116 #ifdef __APPLE__
1117 #  ifdef HAVE_TLS
1118 /*
1119  * 'cups_apple_get_boolean()' - Get a boolean setting from the CUPS preferences.
1120  */
1121 
1122 static int				/* O - 1 if set, 0 otherwise */
cups_apple_get_boolean(CFStringRef key,int * value)1123 cups_apple_get_boolean(
1124     CFStringRef key,			/* I - Key (name) */
1125     int         *value)			/* O - Boolean value */
1126 {
1127   Boolean	bval,			/* Preference value */
1128 		bval_set;		/* Value is set? */
1129 
1130 
1131   bval = CFPreferencesGetAppBooleanValue(key, kCUPSPrintingPrefs, &bval_set);
1132 
1133   if (bval_set)
1134     *value = (int)bval;
1135 
1136   return ((int)bval_set);
1137 }
1138 #  endif /* HAVE_TLS */
1139 
1140 
1141 /*
1142  * 'cups_apple_get_string()' - Get a string setting from the CUPS preferences.
1143  */
1144 
1145 static int				/* O - 1 if set, 0 otherwise */
cups_apple_get_string(CFStringRef key,char * value,size_t valsize)1146 cups_apple_get_string(
1147     CFStringRef key,			/* I - Key (name) */
1148     char        *value,			/* O - String value */
1149     size_t      valsize)		/* I - Size of value buffer */
1150 {
1151   CFStringRef	sval;			/* String value */
1152 
1153 
1154   if ((sval = CFPreferencesCopyAppValue(key, kCUPSPrintingPrefs)) != NULL)
1155   {
1156     Boolean result = CFStringGetCString(sval, value, (CFIndex)valsize, kCFStringEncodingUTF8);
1157 
1158     CFRelease(sval);
1159 
1160     if (result)
1161       return (1);
1162   }
1163 
1164   return (0);
1165 }
1166 #endif /* __APPLE__ */
1167 
1168 
1169 /*
1170  * 'cups_boolean_value()' - Convert a string to a boolean value.
1171  */
1172 
1173 static int				/* O - Boolean value */
cups_boolean_value(const char * value)1174 cups_boolean_value(const char *value)	/* I - String value */
1175 {
1176   return (!_cups_strcasecmp(value, "yes") || !_cups_strcasecmp(value, "on") || !_cups_strcasecmp(value, "true"));
1177 }
1178 
1179 
1180 /*
1181  * 'cups_finalize_client_conf()' - Finalize client.conf values.
1182  */
1183 
1184 static void
cups_finalize_client_conf(_cups_client_conf_t * cc)1185 cups_finalize_client_conf(
1186     _cups_client_conf_t *cc)		/* I - client.conf values */
1187 {
1188   const char	*value;			/* Environment variable */
1189 
1190 
1191   if ((value = getenv("CUPS_TRUSTFIRST")) != NULL)
1192     cc->trust_first = cups_boolean_value(value);
1193 
1194   if ((value = getenv("CUPS_ANYROOT")) != NULL)
1195     cc->any_root = cups_boolean_value(value);
1196 
1197   if ((value = getenv("CUPS_ENCRYPTION")) != NULL)
1198     cups_set_encryption(cc, value);
1199 
1200   if ((value = getenv("CUPS_EXPIREDCERTS")) != NULL)
1201     cc->expired_certs = cups_boolean_value(value);
1202 
1203 #ifdef HAVE_GSSAPI
1204   if ((value = getenv("CUPS_GSSSERVICENAME")) != NULL)
1205     cups_set_gss_service_name(cc, value);
1206 #endif /* HAVE_GSSAPI */
1207 
1208   if ((value = getenv("CUPS_SERVER")) != NULL)
1209     cups_set_server_name(cc, value);
1210 
1211   if ((value = getenv("CUPS_USER")) != NULL)
1212     cups_set_user(cc, value);
1213 
1214   if ((value = getenv("CUPS_VALIDATECERTS")) != NULL)
1215     cc->validate_certs = cups_boolean_value(value);
1216 
1217  /*
1218   * Then apply defaults for those values that haven't been set...
1219   */
1220 
1221   if (cc->trust_first < 0)
1222     cc->trust_first = 1;
1223 
1224   if (cc->any_root < 0)
1225     cc->any_root = 1;
1226 
1227   if (cc->encryption == (http_encryption_t)-1)
1228     cc->encryption = HTTP_ENCRYPTION_IF_REQUESTED;
1229 
1230   if (cc->expired_certs < 0)
1231     cc->expired_certs = 0;
1232 
1233 #ifdef HAVE_GSSAPI
1234   if (!cc->gss_service_name[0])
1235     cups_set_gss_service_name(cc, CUPS_DEFAULT_GSSSERVICENAME);
1236 #endif /* HAVE_GSSAPI */
1237 
1238   if (!cc->server_name[0])
1239   {
1240    /*
1241     * If we are compiled with domain socket support, only use the
1242     * domain socket if it exists and has the right permissions...
1243     */
1244 
1245 #if defined(__APPLE__) && !TARGET_OS_OSX
1246     cups_set_server_name(cc, "/private/var/run/printd");
1247 
1248 #else
1249 #  ifdef CUPS_DEFAULT_DOMAINSOCKET
1250     if (!access(CUPS_DEFAULT_DOMAINSOCKET, R_OK))
1251       cups_set_server_name(cc, CUPS_DEFAULT_DOMAINSOCKET);
1252     else
1253 #  endif /* CUPS_DEFAULT_DOMAINSOCKET */
1254     cups_set_server_name(cc, "localhost");
1255 #endif /* __APPLE__ && !TARGET_OS_OSX */
1256   }
1257 
1258   if (!cc->user[0])
1259   {
1260 #ifdef _WIN32
1261    /*
1262     * Get the current user name from the OS...
1263     */
1264 
1265     DWORD	size;			/* Size of string */
1266 
1267     size = sizeof(cc->user);
1268     if (!GetUserNameA(cc->user, &size))
1269 #else
1270    /*
1271     * Try the USER environment variable as the default username...
1272     */
1273 
1274     const char *envuser = getenv("USER");	/* Default username */
1275     struct passwd pw;				/* Account information */
1276     struct passwd *result = NULL;		/* Auxiliary pointer */
1277     _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
1278 
1279     if (envuser)
1280     {
1281      /*
1282       * Validate USER matches the current UID, otherwise don't allow it to
1283       * override things...  This makes sure that printing after doing su
1284       * or sudo records the correct username.
1285       */
1286       getpwnam_r(envuser, &pw, cg->pw_buf, PW_BUF_SIZE, &result);
1287       if (result && pw.pw_uid != getuid())
1288         result = NULL;
1289     }
1290 
1291     if (!result)
1292       getpwuid_r(getuid(), &pw, cg->pw_buf, PW_BUF_SIZE, &result);
1293 
1294     if (result)
1295       strlcpy(cc->user, pw.pw_name, sizeof(cc->user));
1296     else
1297 #endif /* _WIN32 */
1298     {
1299      /*
1300       * Use the default "unknown" user name...
1301       */
1302 
1303       strlcpy(cc->user, "unknown", sizeof(cc->user));
1304     }
1305   }
1306 
1307   if (cc->validate_certs < 0)
1308     cc->validate_certs = 0;
1309 }
1310 
1311 
1312 /*
1313  * 'cups_init_client_conf()' - Initialize client.conf values.
1314  */
1315 
1316 static void
cups_init_client_conf(_cups_client_conf_t * cc)1317 cups_init_client_conf(
1318     _cups_client_conf_t *cc)		/* I - client.conf values */
1319 {
1320  /*
1321   * Clear all values to "not set"...
1322   */
1323 
1324   memset(cc, 0, sizeof(_cups_client_conf_t));
1325 
1326   cc->uatokens = _CUPS_UATOKENS_MINIMAL;
1327 
1328 #if defined(__APPLE__) && !TARGET_OS_OSX
1329   cups_set_user(cc, "mobile");
1330 #endif /* __APPLE__ && !TARGET_OS_OSX */
1331 
1332 #ifdef HAVE_TLS
1333   cc->ssl_min_version = _HTTP_TLS_1_0;
1334   cc->ssl_max_version = _HTTP_TLS_MAX;
1335 #endif /* HAVE_TLS */
1336   cc->encryption      = (http_encryption_t)-1;
1337   cc->trust_first     = -1;
1338   cc->any_root        = -1;
1339   cc->expired_certs   = -1;
1340   cc->validate_certs  = -1;
1341 
1342  /*
1343   * Load settings from the org.cups.PrintingPrefs plist (which trump
1344   * everything...)
1345   */
1346 
1347 #if defined(__APPLE__)
1348   char	sval[1024];			/* String value */
1349 #  ifdef HAVE_TLS
1350   int	bval;				/* Boolean value */
1351 
1352   if (cups_apple_get_boolean(kAllowAnyRootKey, &bval))
1353     cc->any_root = bval;
1354 
1355   if (cups_apple_get_boolean(kAllowExpiredCertsKey, &bval))
1356     cc->expired_certs = bval;
1357 
1358   if (cups_apple_get_string(kEncryptionKey, sval, sizeof(sval)))
1359     cups_set_encryption(cc, sval);
1360 
1361   if (cups_apple_get_string(kSSLOptionsKey, sval, sizeof(sval)))
1362   {
1363     cups_set_ssl_options(cc, sval);
1364   }
1365   else
1366   {
1367     sval[0] = '\0';
1368 
1369     if (cups_apple_get_boolean(kAllowRC4, &bval) && bval)
1370       strlcat(sval, " AllowRC4", sizeof(sval));
1371     if (cups_apple_get_boolean(kAllowSSL3, &bval) && bval)
1372       strlcat(sval, " AllowSSL3", sizeof(sval));
1373     if (cups_apple_get_boolean(kAllowDH, &bval) && bval)
1374       strlcat(sval, " AllowDH", sizeof(sval));
1375 
1376     if (sval[0])
1377       cups_set_ssl_options(cc, sval);
1378   }
1379 
1380   if (cups_apple_get_boolean(kTrustOnFirstUseKey, &bval))
1381     cc->trust_first = bval;
1382 
1383   if (cups_apple_get_boolean(kValidateCertsKey, &bval))
1384     cc->validate_certs = bval;
1385 #  endif /* HAVE_TLS */
1386 
1387   if (cups_apple_get_string(kDigestOptionsKey, sval, sizeof(sval)))
1388     cups_set_digestoptions(cc, sval);
1389 
1390   if (cups_apple_get_string(kUserKey, sval, sizeof(sval)))
1391     strlcpy(cc->user, sval, sizeof(cc->user));
1392 
1393   if (cups_apple_get_string(kUserAgentTokensKey, sval, sizeof(sval)))
1394     cups_set_uatokens(cc, sval);
1395 #endif /* __APPLE__ */
1396 }
1397 
1398 
1399 /*
1400  * 'cups_read_client_conf()' - Read a client.conf file.
1401  */
1402 
1403 static void
cups_read_client_conf(cups_file_t * fp,_cups_client_conf_t * cc)1404 cups_read_client_conf(
1405     cups_file_t         *fp,		/* I - File to read */
1406     _cups_client_conf_t *cc)		/* I - client.conf values */
1407 {
1408   int	linenum;			/* Current line number */
1409   char	line[1024],			/* Line from file */
1410         *value;				/* Pointer into line */
1411 
1412 
1413  /*
1414   * Read from the file...
1415   */
1416 
1417   linenum = 0;
1418   while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
1419   {
1420     if (!_cups_strcasecmp(line, "DigestOptions") && value)
1421       cups_set_digestoptions(cc, value);
1422     else if (!_cups_strcasecmp(line, "Encryption") && value)
1423       cups_set_encryption(cc, value);
1424 #ifndef __APPLE__
1425    /*
1426     * The ServerName directive is not supported on macOS due to app
1427     * sandboxing restrictions, i.e. not all apps request network access.
1428     */
1429     else if (!_cups_strcasecmp(line, "ServerName") && value)
1430       cups_set_server_name(cc, value);
1431 #endif /* !__APPLE__ */
1432     else if (!_cups_strcasecmp(line, "User") && value)
1433       cups_set_user(cc, value);
1434     else if (!_cups_strcasecmp(line, "UserAgentTokens") && value)
1435       cups_set_uatokens(cc, value);
1436     else if (!_cups_strcasecmp(line, "TrustOnFirstUse") && value)
1437       cc->trust_first = cups_boolean_value(value);
1438     else if (!_cups_strcasecmp(line, "AllowAnyRoot") && value)
1439       cc->any_root = cups_boolean_value(value);
1440     else if (!_cups_strcasecmp(line, "AllowExpiredCerts") &&
1441              value)
1442       cc->expired_certs = cups_boolean_value(value);
1443     else if (!_cups_strcasecmp(line, "ValidateCerts") && value)
1444       cc->validate_certs = cups_boolean_value(value);
1445 #ifdef HAVE_GSSAPI
1446     else if (!_cups_strcasecmp(line, "GSSServiceName") && value)
1447       cups_set_gss_service_name(cc, value);
1448 #endif /* HAVE_GSSAPI */
1449 #ifdef HAVE_TLS
1450     else if (!_cups_strcasecmp(line, "SSLOptions") && value)
1451       cups_set_ssl_options(cc, value);
1452 #endif /* HAVE_TLS */
1453   }
1454 }
1455 
1456 
1457 /*
1458  * 'cups_set_default_ipp_port()' - Set the default IPP port value.
1459  */
1460 
1461 static void
cups_set_default_ipp_port(_cups_globals_t * cg)1462 cups_set_default_ipp_port(
1463     _cups_globals_t *cg)		/* I - Global data */
1464 {
1465   const char	*ipp_port;		/* IPP_PORT environment variable */
1466 
1467 
1468   if ((ipp_port = getenv("IPP_PORT")) != NULL)
1469   {
1470     if ((cg->ipp_port = atoi(ipp_port)) <= 0)
1471       cg->ipp_port = CUPS_DEFAULT_IPP_PORT;
1472   }
1473   else
1474     cg->ipp_port = CUPS_DEFAULT_IPP_PORT;
1475 }
1476 
1477 
1478 /*
1479  * 'cups_set_digestoptions()' - Set the DigestOptions value.
1480  */
1481 
1482 static void
cups_set_digestoptions(_cups_client_conf_t * cc,const char * value)1483 cups_set_digestoptions(
1484     _cups_client_conf_t *cc,		/* I - client.conf values */
1485     const char          *value)		/* I - Value */
1486 {
1487   if (!_cups_strcasecmp(value, "DenyMD5"))
1488     cc->digestoptions = _CUPS_DIGESTOPTIONS_DENYMD5;
1489   else if (!_cups_strcasecmp(value, "None"))
1490     cc->digestoptions = _CUPS_DIGESTOPTIONS_NONE;
1491 }
1492 
1493 
1494 /*
1495  * 'cups_set_encryption()' - Set the Encryption value.
1496  */
1497 
1498 static void
cups_set_encryption(_cups_client_conf_t * cc,const char * value)1499 cups_set_encryption(
1500     _cups_client_conf_t *cc,		/* I - client.conf values */
1501     const char          *value)		/* I - Value */
1502 {
1503   if (!_cups_strcasecmp(value, "never"))
1504     cc->encryption = HTTP_ENCRYPTION_NEVER;
1505   else if (!_cups_strcasecmp(value, "always"))
1506     cc->encryption = HTTP_ENCRYPTION_ALWAYS;
1507   else if (!_cups_strcasecmp(value, "required"))
1508     cc->encryption = HTTP_ENCRYPTION_REQUIRED;
1509   else
1510     cc->encryption = HTTP_ENCRYPTION_IF_REQUESTED;
1511 }
1512 
1513 
1514 /*
1515  * 'cups_set_gss_service_name()' - Set the GSSServiceName value.
1516  */
1517 
1518 #ifdef HAVE_GSSAPI
1519 static void
cups_set_gss_service_name(_cups_client_conf_t * cc,const char * value)1520 cups_set_gss_service_name(
1521     _cups_client_conf_t *cc,		/* I - client.conf values */
1522     const char          *value)		/* I - Value */
1523 {
1524   strlcpy(cc->gss_service_name, value, sizeof(cc->gss_service_name));
1525 }
1526 #endif /* HAVE_GSSAPI */
1527 
1528 
1529 /*
1530  * 'cups_set_server_name()' - Set the ServerName value.
1531  */
1532 
1533 static void
cups_set_server_name(_cups_client_conf_t * cc,const char * value)1534 cups_set_server_name(
1535     _cups_client_conf_t *cc,		/* I - client.conf values */
1536     const char          *value)		/* I - Value */
1537 {
1538   strlcpy(cc->server_name, value, sizeof(cc->server_name));
1539 }
1540 
1541 
1542 /*
1543  * 'cups_set_ssl_options()' - Set the SSLOptions value.
1544  */
1545 
1546 #ifdef HAVE_TLS
1547 static void
cups_set_ssl_options(_cups_client_conf_t * cc,const char * value)1548 cups_set_ssl_options(
1549     _cups_client_conf_t *cc,		/* I - client.conf values */
1550     const char          *value)		/* I - Value */
1551 {
1552  /*
1553   * SSLOptions [AllowRC4] [AllowSSL3] [AllowDH] [DenyTLS1.0] [None]
1554   */
1555 
1556   int	options = _HTTP_TLS_NONE,	/* SSL/TLS options */
1557 	min_version = _HTTP_TLS_1_0,	/* Minimum SSL/TLS version */
1558 	max_version = _HTTP_TLS_MAX;	/* Maximum SSL/TLS version */
1559   char	temp[256],			/* Copy of value */
1560 	*start,				/* Start of option */
1561 	*end;				/* End of option */
1562 
1563 
1564   strlcpy(temp, value, sizeof(temp));
1565 
1566   for (start = temp; *start; start = end)
1567   {
1568    /*
1569     * Find end of keyword...
1570     */
1571 
1572     end = start;
1573     while (*end && !_cups_isspace(*end))
1574       end ++;
1575 
1576     if (*end)
1577       *end++ = '\0';
1578 
1579    /*
1580     * Compare...
1581     */
1582 
1583     if (!_cups_strcasecmp(start, "AllowRC4"))
1584       options |= _HTTP_TLS_ALLOW_RC4;
1585     else if (!_cups_strcasecmp(start, "AllowSSL3"))
1586       min_version = _HTTP_TLS_SSL3;
1587     else if (!_cups_strcasecmp(start, "AllowDH"))
1588       options |= _HTTP_TLS_ALLOW_DH;
1589     else if (!_cups_strcasecmp(start, "DenyCBC"))
1590       options |= _HTTP_TLS_DENY_CBC;
1591     else if (!_cups_strcasecmp(start, "DenyTLS1.0"))
1592       min_version = _HTTP_TLS_1_1;
1593     else if (!_cups_strcasecmp(start, "MaxTLS1.0"))
1594       max_version = _HTTP_TLS_1_0;
1595     else if (!_cups_strcasecmp(start, "MaxTLS1.1"))
1596       max_version = _HTTP_TLS_1_1;
1597     else if (!_cups_strcasecmp(start, "MaxTLS1.2"))
1598       max_version = _HTTP_TLS_1_2;
1599     else if (!_cups_strcasecmp(start, "MaxTLS1.3"))
1600       max_version = _HTTP_TLS_1_3;
1601     else if (!_cups_strcasecmp(start, "MinTLS1.0"))
1602       min_version = _HTTP_TLS_1_0;
1603     else if (!_cups_strcasecmp(start, "MinTLS1.1"))
1604       min_version = _HTTP_TLS_1_1;
1605     else if (!_cups_strcasecmp(start, "MinTLS1.2"))
1606       min_version = _HTTP_TLS_1_2;
1607     else if (!_cups_strcasecmp(start, "MinTLS1.3"))
1608       min_version = _HTTP_TLS_1_3;
1609     else if (!_cups_strcasecmp(start, "None"))
1610       options = _HTTP_TLS_NONE;
1611     else if (!_cups_strcasecmp(start, "NoSystem"))
1612       options |= _HTTP_TLS_NO_SYSTEM;
1613   }
1614 
1615   cc->ssl_options     = options;
1616   cc->ssl_max_version = max_version;
1617   cc->ssl_min_version = min_version;
1618 
1619   DEBUG_printf(("4cups_set_ssl_options(cc=%p, value=\"%s\") options=%x, min_version=%d, max_version=%d", (void *)cc, value, options, min_version, max_version));
1620 }
1621 #endif /* HAVE_TLS */
1622 
1623 
1624 /*
1625  * 'cups_set_uatokens()' - Set the UserAgentTokens value.
1626  */
1627 
1628 static void
cups_set_uatokens(_cups_client_conf_t * cc,const char * value)1629 cups_set_uatokens(
1630     _cups_client_conf_t *cc,		/* I - client.conf values */
1631     const char          *value)		/* I - Value */
1632 {
1633   int	i;				/* Looping var */
1634   static const char * const uatokens[] =/* UserAgentTokens values */
1635   {
1636     "NONE",
1637     "PRODUCTONLY",
1638     "MAJOR",
1639     "MINOR",
1640     "MINIMAL",
1641     "OS",
1642     "FULL"
1643   };
1644 
1645   for (i = 0; i < (int)(sizeof(uatokens) / sizeof(uatokens[0])); i ++)
1646   {
1647     if (!_cups_strcasecmp(value, uatokens[i]))
1648     {
1649       cc->uatokens = (_cups_uatokens_t)i;
1650       return;
1651     }
1652   }
1653 }
1654 
1655 
1656 /*
1657  * 'cups_set_user()' - Set the User value.
1658  */
1659 
1660 static void
cups_set_user(_cups_client_conf_t * cc,const char * value)1661 cups_set_user(
1662     _cups_client_conf_t *cc,		/* I - client.conf values */
1663     const char          *value)		/* I - Value */
1664 {
1665   strlcpy(cc->user, value, sizeof(cc->user));
1666 }
1667