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