]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/usersys.c
Clean up implementation for SSLOptions
[thirdparty/cups.git] / cups / usersys.c
CommitLineData
ef416fc2 1/*
83bc2aac
MS
2 * User, system, and password routines for CUPS.
3 *
53af7f21 4 * Copyright 2007-2017 by Apple Inc.
83bc2aac
MS
5 * Copyright 1997-2006 by Easy Software Products.
6 *
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * which should have been included with this file. If this file is
57b7b66b 11 * missing or damaged, see the license at "http://www.cups.org/".
83bc2aac
MS
12 *
13 * This file is subject to the Apple OS-Developed Software exception.
ef416fc2 14 */
15
16/*
17 * Include necessary headers...
18 */
19
71e16022 20#include "cups-private.h"
ef416fc2 21#include <stdlib.h>
e00b005a 22#include <sys/stat.h>
ef416fc2 23#ifdef WIN32
24# include <windows.h>
5a6b583a
MS
25#else
26# include <pwd.h>
dcb445bc 27# include <termios.h>
db8b865d 28# include <sys/utsname.h>
ef416fc2 29#endif /* WIN32 */
30
31
dcb445bc
MS
32/*
33 * Local constants...
34 */
35
08d56b1f
MS
36#ifdef __APPLE__
37# define kCUPSPrintingPrefs CFSTR("org.cups.PrintingPrefs")
38# define kAllowAnyRootKey CFSTR("AllowAnyRoot")
39# define kAllowExpiredCertsKey CFSTR("AllowExpiredCerts")
40# define kEncryptionKey CFSTR("Encryption")
41# define kGSSServiceNameKey CFSTR("GSSServiceName")
42# define kSSLOptionsKey CFSTR("SSLOptions")
43# define kTrustOnFirstUseKey CFSTR("TrustOnFirstUse")
44# define kValidateCertsKey CFSTR("ValidateCerts")
45#endif /* __APPLE__ */
46
dcb445bc
MS
47#define _CUPS_PASSCHAR '*' /* Character that is echoed for password */
48
49
3abb875b
MS
50/*
51 * Local types...
52 */
53
54typedef struct _cups_client_conf_s /**** client.conf config data ****/
55{
56#ifdef HAVE_SSL
57 int ssl_options; /* SSLOptions values */
58#endif /* HAVE_SSL */
08d56b1f
MS
59 int trust_first, /* Trust on first use? */
60 any_root, /* Allow any (e.g., self-signed) root */
3abb875b
MS
61 expired_certs, /* Allow expired certs */
62 validate_certs; /* Validate certificates */
63 http_encryption_t encryption; /* Encryption setting */
64 char user[65], /* User name */
65 server_name[256];
66 /* Server hostname */
67#ifdef HAVE_GSSAPI
68 char gss_service_name[32];
69 /* Kerberos service name */
70#endif /* HAVE_GSSAPI */
71} _cups_client_conf_t;
72
73
b423cd4c 74/*
75 * Local functions...
76 */
77
08d56b1f
MS
78#ifdef __APPLE__
79static int cups_apple_get_boolean(CFStringRef key, int *value);
80static int cups_apple_get_string(CFStringRef key, char *value, size_t valsize);
81#endif /* __APPLE__ */
82static int cups_boolean_value(const char *value);
3abb875b
MS
83static void cups_finalize_client_conf(_cups_client_conf_t *cc);
84static void cups_init_client_conf(_cups_client_conf_t *cc);
85static void cups_read_client_conf(cups_file_t *fp, _cups_client_conf_t *cc);
4b9daaf4 86static void cups_set_default_ipp_port(_cups_globals_t *cg);
3abb875b 87static void cups_set_encryption(_cups_client_conf_t *cc, const char *value);
07ed0e9a 88#ifdef HAVE_GSSAPI
3abb875b 89static void cups_set_gss_service_name(_cups_client_conf_t *cc, const char *value);
07ed0e9a 90#endif /* HAVE_GSSAPI */
3abb875b
MS
91static void cups_set_server_name(_cups_client_conf_t *cc, const char *value);
92#ifdef HAVE_SSL
93static void cups_set_ssl_options(_cups_client_conf_t *cc, const char *value);
94#endif /* HAVE_SSL */
95static void cups_set_user(_cups_client_conf_t *cc, const char *value);
b423cd4c 96
97
ef416fc2 98/*
5a6b583a 99 * 'cupsEncryption()' - Get the current encryption settings.
ef416fc2 100 *
101 * The default encryption setting comes from the CUPS_ENCRYPTION
568fa3fa 102 * environment variable, then the ~/.cups/client.conf file, and finally the
ef416fc2 103 * /etc/cups/client.conf file. If not set, the default is
cb7f98ee 104 * @code HTTP_ENCRYPTION_IF_REQUESTED@.
5a6b583a
MS
105 *
106 * Note: The current encryption setting is tracked separately for each thread
107 * in a program. Multi-threaded programs that override the setting via the
108 * @link cupsSetEncryption@ function need to do so in each thread for the same
109 * setting to be used.
ef416fc2 110 */
111
112http_encryption_t /* O - Encryption settings */
113cupsEncryption(void)
114{
ef416fc2 115 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
116
117
ef416fc2 118 if (cg->encryption == (http_encryption_t)-1)
e07d4801 119 _cupsSetDefaults();
ef416fc2 120
121 return (cg->encryption);
122}
123
124
125/*
126 * 'cupsGetPassword()' - Get a password from the user.
127 *
5a738aea 128 * Uses the current password callback function. Returns @code NULL@ if the
ecdc0628 129 * user does not provide a password.
5a6b583a
MS
130 *
131 * Note: The current password callback function is tracked separately for each
132 * thread in a program. Multi-threaded programs that override the setting via
133 * the @link cupsSetPasswordCB@ or @link cupsSetPasswordCB2@ functions need to
134 * do so in each thread for the same function to be used.
53af7f21
MS
135 *
136 * @exclude all@
ef416fc2 137 */
138
139const char * /* O - Password */
140cupsGetPassword(const char *prompt) /* I - Prompt string */
141{
f11a948a
MS
142 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
143
144
145 return ((cg->password_cb)(prompt, NULL, NULL, NULL, cg->password_data));
146}
147
148
149/*
98d88c8d 150 * 'cupsGetPassword2()' - Get a password from the user using the current
5a6b583a 151 * password callback.
f11a948a
MS
152 *
153 * Uses the current password callback function. Returns @code NULL@ if the
154 * user does not provide a password.
155 *
5a6b583a
MS
156 * Note: The current password callback function is tracked separately for each
157 * thread in a program. Multi-threaded programs that override the setting via
98d88c8d
MS
158 * the @link cupsSetPasswordCB2@ function need to do so in each thread for the
159 * same function to be used.
5a6b583a 160 *
8072030b 161 * @since CUPS 1.4/macOS 10.6@
f11a948a
MS
162 */
163
164const char * /* O - Password */
165cupsGetPassword2(const char *prompt, /* I - Prompt string */
166 http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
167 const char *method, /* I - Request method ("GET", "POST", "PUT") */
168 const char *resource) /* I - Resource path */
169{
170 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
171
172
173 if (!http)
174 http = _cupsConnect();
175
176 return ((cg->password_cb)(prompt, http, method, resource, cg->password_data));
ef416fc2 177}
178
179
ef416fc2 180/*
5a6b583a
MS
181 * 'cupsServer()' - Return the hostname/address of the current server.
182 *
183 * The default server comes from the CUPS_SERVER environment variable, then the
184 * ~/.cups/client.conf file, and finally the /etc/cups/client.conf file. If not
185 * set, the default is the local system - either "localhost" or a domain socket
186 * path.
ef416fc2 187 *
5a6b583a
MS
188 * The returned value can be a fully-qualified hostname, a numeric IPv4 or IPv6
189 * address, or a domain socket pathname.
190 *
191 * Note: The current server is tracked separately for each thread in a program.
192 * Multi-threaded programs that override the server via the
193 * @link cupsSetServer@ function need to do so in each thread for the same
194 * server to be used.
ef416fc2 195 */
196
197const char * /* O - Server name */
198cupsServer(void)
199{
ef416fc2 200 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
201
202
ef416fc2 203 if (!cg->server[0])
e07d4801 204 _cupsSetDefaults();
ef416fc2 205
e07d4801
MS
206 return (cg->server);
207}
ef416fc2 208
d09495fa 209
7cf5915e
MS
210/*
211 * 'cupsSetClientCertCB()' - Set the client certificate callback.
212 *
213 * Pass @code NULL@ to restore the default callback.
214 *
215 * Note: The current certificate callback is tracked separately for each thread
216 * in a program. Multi-threaded programs that override the callback need to do
217 * so in each thread for the same callback to be used.
218 *
8072030b 219 * @since CUPS 1.5/macOS 10.7@
7cf5915e
MS
220 */
221
222void
223cupsSetClientCertCB(
224 cups_client_cert_cb_t cb, /* I - Callback function */
225 void *user_data) /* I - User data pointer */
226{
227 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
228
229
230 cg->client_cert_cb = cb;
231 cg->client_cert_data = user_data;
232}
233
234
235/*
236 * 'cupsSetCredentials()' - Set the default credentials to be used for SSL/TLS
237 * connections.
238 *
239 * Note: The default credentials are tracked separately for each thread in a
240 * program. Multi-threaded programs that override the setting need to do so in
241 * each thread for the same setting to be used.
242 *
8072030b 243 * @since CUPS 1.5/macOS 10.7@
7cf5915e
MS
244 */
245
246int /* O - Status of call (0 = success) */
247cupsSetCredentials(
248 cups_array_t *credentials) /* I - Array of credentials */
249{
250 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
251
252
253 if (cupsArrayCount(credentials) < 1)
254 return (-1);
255
7d5824d6 256#ifdef HAVE_SSL
7cf5915e 257 _httpFreeCredentials(cg->tls_credentials);
85dda01c 258 cg->tls_credentials = _httpCreateCredentials(credentials);
7d5824d6 259#endif /* HAVE_SSL */
7cf5915e
MS
260
261 return (cg->tls_credentials ? 0 : -1);
262}
263
264
e07d4801
MS
265/*
266 * 'cupsSetEncryption()' - Set the encryption preference.
5a6b583a
MS
267 *
268 * The default encryption setting comes from the CUPS_ENCRYPTION
269 * environment variable, then the ~/.cups/client.conf file, and finally the
270 * /etc/cups/client.conf file. If not set, the default is
cb7f98ee 271 * @code HTTP_ENCRYPTION_IF_REQUESTED@.
5a6b583a
MS
272 *
273 * Note: The current encryption setting is tracked separately for each thread
274 * in a program. Multi-threaded programs that override the setting need to do
275 * so in each thread for the same setting to be used.
e07d4801 276 */
ef416fc2 277
e07d4801
MS
278void
279cupsSetEncryption(http_encryption_t e) /* I - New encryption preference */
280{
281 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
ef416fc2 282
ef416fc2 283
e07d4801 284 cg->encryption = e;
ef416fc2 285
e07d4801
MS
286 if (cg->http)
287 httpEncryption(cg->http, e);
ef416fc2 288}
289
290
291/*
292 * 'cupsSetPasswordCB()' - Set the password callback for CUPS.
293 *
5a6b583a
MS
294 * Pass @code NULL@ to restore the default (console) password callback, which
295 * reads the password from the console. Programs should call either this
296 * function or @link cupsSetPasswordCB2@, as only one callback can be registered
297 * by a program per thread.
298 *
299 * Note: The current password callback is tracked separately for each thread
300 * in a program. Multi-threaded programs that override the callback need to do
301 * so in each thread for the same callback to be used.
53af7f21
MS
302 *
303 * @exclude all@
ef416fc2 304 */
305
306void
307cupsSetPasswordCB(cups_password_cb_t cb)/* I - Callback function */
308{
309 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
310
311
f11a948a
MS
312 if (cb == (cups_password_cb_t)0)
313 cg->password_cb = (cups_password_cb2_t)_cupsGetPassword;
314 else
315 cg->password_cb = (cups_password_cb2_t)cb;
316
317 cg->password_data = NULL;
318}
319
320
321/*
322 * 'cupsSetPasswordCB2()' - Set the advanced password callback for CUPS.
323 *
5a6b583a
MS
324 * Pass @code NULL@ to restore the default (console) password callback, which
325 * reads the password from the console. Programs should call either this
326 * function or @link cupsSetPasswordCB2@, as only one callback can be registered
327 * by a program per thread.
328 *
329 * Note: The current password callback is tracked separately for each thread
330 * in a program. Multi-threaded programs that override the callback need to do
331 * so in each thread for the same callback to be used.
f11a948a 332 *
8072030b 333 * @since CUPS 1.4/macOS 10.6@
f11a948a
MS
334 */
335
336void
337cupsSetPasswordCB2(
338 cups_password_cb2_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 if (cb == (cups_password_cb2_t)0)
345 cg->password_cb = (cups_password_cb2_t)_cupsGetPassword;
ef416fc2 346 else
347 cg->password_cb = cb;
f11a948a
MS
348
349 cg->password_data = user_data;
ef416fc2 350}
351
352
353/*
5a6b583a 354 * 'cupsSetServer()' - Set the default server name and port.
ef416fc2 355 *
356 * The "server" string can be a fully-qualified hostname, a numeric
5a6b583a
MS
357 * IPv4 or IPv6 address, or a domain socket pathname. Hostnames and numeric IP
358 * addresses can be optionally followed by a colon and port number to override
359 * the default port 631, e.g. "hostname:8631". Pass @code NULL@ to restore the
360 * default server name and port.
361 *
362 * Note: The current server is tracked separately for each thread in a program.
363 * Multi-threaded programs that override the server need to do so in each
364 * thread for the same server to be used.
ef416fc2 365 */
366
367void
368cupsSetServer(const char *server) /* I - Server name */
369{
0cb67df3
MS
370 char *options, /* Options */
371 *port; /* Pointer to port */
ef416fc2 372 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
373
374
375 if (server)
376 {
377 strlcpy(cg->server, server, sizeof(cg->server));
378
0cb67df3
MS
379 if (cg->server[0] != '/' && (options = strrchr(cg->server, '/')) != NULL)
380 {
381 *options++ = '\0';
382
383 if (!strcmp(options, "version=1.0"))
384 cg->server_version = 10;
385 else if (!strcmp(options, "version=1.1"))
386 cg->server_version = 11;
387 else if (!strcmp(options, "version=2.0"))
388 cg->server_version = 20;
389 else if (!strcmp(options, "version=2.1"))
390 cg->server_version = 21;
391 else if (!strcmp(options, "version=2.2"))
392 cg->server_version = 22;
393 }
567f49cb
MS
394 else
395 cg->server_version = 20;
0cb67df3 396
ef416fc2 397 if (cg->server[0] != '/' && (port = strrchr(cg->server, ':')) != NULL &&
398 !strchr(port, ']') && isdigit(port[1] & 255))
399 {
400 *port++ = '\0';
401
e07d4801 402 cg->ipp_port = atoi(port);
ef416fc2 403 }
404
4b9daaf4
MS
405 if (!cg->ipp_port)
406 cups_set_default_ipp_port(cg);
407
ef416fc2 408 if (cg->server[0] == '/')
5a9febac 409 strlcpy(cg->servername, "localhost", sizeof(cg->servername));
ef416fc2 410 else
411 strlcpy(cg->servername, cg->server, sizeof(cg->servername));
412 }
413 else
414 {
0cb67df3
MS
415 cg->server[0] = '\0';
416 cg->servername[0] = '\0';
417 cg->server_version = 20;
4b9daaf4 418 cg->ipp_port = 0;
ef416fc2 419 }
5a738aea
MS
420
421 if (cg->http)
422 {
423 httpClose(cg->http);
424 cg->http = NULL;
425 }
ef416fc2 426}
427
428
7cf5915e
MS
429/*
430 * 'cupsSetServerCertCB()' - Set the server certificate callback.
431 *
432 * Pass @code NULL@ to restore the default callback.
433 *
434 * Note: The current credentials callback is tracked separately for each thread
435 * in a program. Multi-threaded programs that override the callback need to do
436 * so in each thread for the same callback to be used.
437 *
8072030b 438 * @since CUPS 1.5/macOS 10.7@
7cf5915e
MS
439 */
440
441void
442cupsSetServerCertCB(
443 cups_server_cert_cb_t cb, /* I - Callback function */
444 void *user_data) /* I - User data pointer */
445{
446 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
447
448
449 cg->server_cert_cb = cb;
450 cg->server_cert_data = user_data;
451}
452
453
ef416fc2 454/*
455 * 'cupsSetUser()' - Set the default user name.
456 *
5a738aea 457 * Pass @code NULL@ to restore the default user name.
5a6b583a
MS
458 *
459 * Note: The current user name is tracked separately for each thread in a
460 * program. Multi-threaded programs that override the user name need to do so
461 * in each thread for the same user name to be used.
ef416fc2 462 */
463
464void
465cupsSetUser(const char *user) /* I - User name */
466{
467 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
468
469
470 if (user)
471 strlcpy(cg->user, user, sizeof(cg->user));
472 else
473 cg->user[0] = '\0';
474}
475
476
db8b865d
MS
477/*
478 * 'cupsSetUserAgent()' - Set the default HTTP User-Agent string.
479 *
480 * Setting the string to NULL forces the default value containing the CUPS
481 * version, IPP version, and operating system version and architecture.
482 *
8072030b 483 * @since CUPS 1.7/macOS 10.9@
db8b865d
MS
484 */
485
486void
487cupsSetUserAgent(const char *user_agent)/* I - User-Agent string or @code NULL@ */
488{
489 _cups_globals_t *cg = _cupsGlobals();
490 /* Thread globals */
491#ifdef WIN32
492 SYSTEM_INFO sysinfo; /* System information */
493 OSVERSIONINFO version; /* OS version info */
494#else
495 struct utsname name; /* uname info */
496#endif /* WIN32 */
497
498
499 if (user_agent)
500 {
501 strlcpy(cg->user_agent, user_agent, sizeof(cg->user_agent));
502 return;
503 }
504
505#ifdef WIN32
506 version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
507 GetVersionEx(&version);
508 GetNativeSystemInfo(&sysinfo);
509
510 snprintf(cg->user_agent, sizeof(cg->user_agent),
511 CUPS_MINIMAL " (Windows %d.%d; %s) IPP/2.0",
512 version.dwMajorVersion, version.dwMinorVersion,
513 sysinfo.wProcessorArchitecture
514 == PROCESSOR_ARCHITECTURE_AMD64 ? "amd64" :
515 sysinfo.wProcessorArchitecture
516 == PROCESSOR_ARCHITECTURE_ARM ? "arm" :
517 sysinfo.wProcessorArchitecture
518 == PROCESSOR_ARCHITECTURE_IA64 ? "ia64" :
519 sysinfo.wProcessorArchitecture
520 == PROCESSOR_ARCHITECTURE_INTEL ? "intel" :
521 "unknown");
522
523#else
524 uname(&name);
525
526 snprintf(cg->user_agent, sizeof(cg->user_agent),
527 CUPS_MINIMAL " (%s %s; %s) IPP/2.0",
528 name.sysname, name.release, name.machine);
529#endif /* WIN32 */
530}
531
532
ef416fc2 533/*
534 * 'cupsUser()' - Return the current user's name.
5a6b583a
MS
535 *
536 * Note: The current user name is tracked separately for each thread in a
537 * program. Multi-threaded programs that override the user name with the
538 * @link cupsSetUser@ function need to do so in each thread for the same user
539 * name to be used.
ef416fc2 540 */
541
542const char * /* O - User name */
543cupsUser(void)
544{
545 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
546
547
548 if (!cg->user[0])
3e7fe0ca 549 _cupsSetDefaults();
ef416fc2 550
551 return (cg->user);
552}
553
554
db8b865d
MS
555/*
556 * 'cupsUserAgent()' - Return the default HTTP User-Agent string.
557 *
8072030b 558 * @since CUPS 1.7/macOS 10.9@
db8b865d
MS
559 */
560
561const char * /* O - User-Agent string */
562cupsUserAgent(void)
563{
564 _cups_globals_t *cg = _cupsGlobals(); /* Thread globals */
565
566
567 if (!cg->user_agent[0])
568 cupsSetUserAgent(NULL);
569
570 return (cg->user_agent);
571}
572
573
ef416fc2 574/*
575 * '_cupsGetPassword()' - Get a password from the user.
576 */
577
dcb445bc 578const char * /* O - Password or @code NULL@ if none */
ef416fc2 579_cupsGetPassword(const char *prompt) /* I - Prompt string */
580{
5a6b583a 581#ifdef WIN32
dcb445bc
MS
582 HANDLE tty; /* Console handle */
583 DWORD mode; /* Console mode */
584 char passch, /* Current key press */
585 *passptr, /* Pointer into password string */
586 *passend; /* End of password string */
12f89d24 587 DWORD passbytes; /* Bytes read */
dcb445bc
MS
588 _cups_globals_t *cg = _cupsGlobals();
589 /* Thread globals */
590
591
5a6b583a 592 /*
dcb445bc 593 * Disable input echo and set raw input...
5a6b583a
MS
594 */
595
dcb445bc
MS
596 if ((tty = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE)
597 return (NULL);
598
599 if (!GetConsoleMode(tty, &mode))
600 return (NULL);
601
602 if (!SetConsoleMode(tty, 0))
603 return (NULL);
604
605 /*
606 * Display the prompt...
607 */
608
609 printf("%s ", prompt);
610 fflush(stdout);
611
612 /*
613 * Read the password string from /dev/tty until we get interrupted or get a
614 * carriage return or newline...
615 */
616
617 passptr = cg->password;
618 passend = cg->password + sizeof(cg->password) - 1;
619
12f89d24 620 while (ReadFile(tty, &passch, 1, &passbytes, NULL))
dcb445bc
MS
621 {
622 if (passch == 0x0A || passch == 0x0D)
623 {
624 /*
625 * Enter/return...
626 */
627
628 break;
629 }
630 else if (passch == 0x08 || passch == 0x7F)
631 {
632 /*
633 * Backspace/delete (erase character)...
634 */
635
636 if (passptr > cg->password)
637 {
638 passptr --;
639 fputs("\010 \010", stdout);
640 }
641 else
642 putchar(0x07);
643 }
644 else if (passch == 0x15)
645 {
646 /*
647 * CTRL+U (erase line)
648 */
649
650 if (passptr > cg->password)
651 {
652 while (passptr > cg->password)
653 {
654 passptr --;
655 fputs("\010 \010", stdout);
656 }
657 }
658 else
659 putchar(0x07);
660 }
661 else if (passch == 0x03)
662 {
663 /*
664 * CTRL+C...
665 */
666
667 passptr = cg->password;
668 break;
669 }
670 else if ((passch & 255) < 0x20 || passptr >= passend)
671 putchar(0x07);
672 else
673 {
674 *passptr++ = passch;
675 putchar(_CUPS_PASSCHAR);
676 }
677
678 fflush(stdout);
679 }
680
681 putchar('\n');
682 fflush(stdout);
683
684 /*
685 * Cleanup...
686 */
687
688 SetConsoleMode(tty, mode);
689
690 /*
691 * Return the proper value...
692 */
693
694 if (passbytes == 1 && passptr > cg->password)
695 {
696 *passptr = '\0';
697 return (cg->password);
698 }
699 else
700 {
701 memset(cg->password, 0, sizeof(cg->password));
702 return (NULL);
703 }
5a6b583a
MS
704
705#else
dcb445bc
MS
706 int tty; /* /dev/tty - never read from stdin */
707 struct termios original, /* Original input mode */
708 noecho; /* No echo input mode */
709 char passch, /* Current key press */
710 *passptr, /* Pointer into password string */
711 *passend; /* End of password string */
712 ssize_t passbytes; /* Bytes read */
713 _cups_globals_t *cg = _cupsGlobals();
714 /* Thread globals */
715
716
5a6b583a 717 /*
dcb445bc 718 * Disable input echo and set raw input...
5a6b583a
MS
719 */
720
dcb445bc
MS
721 if ((tty = open("/dev/tty", O_RDONLY)) < 0)
722 return (NULL);
723
724 if (tcgetattr(tty, &original))
725 {
726 close(tty);
727 return (NULL);
728 }
729
730 noecho = original;
7e86f2f6 731 noecho.c_lflag &= (tcflag_t)~(ICANON | ECHO | ECHOE | ISIG);
a8db9df8
MS
732 noecho.c_cc[VMIN] = 1;
733 noecho.c_cc[VTIME] = 0;
7cf5915e 734
dcb445bc
MS
735 if (tcsetattr(tty, TCSAFLUSH, &noecho))
736 {
737 close(tty);
7cf5915e 738 return (NULL);
dcb445bc
MS
739 }
740
741 /*
742 * Display the prompt...
743 */
744
745 printf("%s ", prompt);
746 fflush(stdout);
747
748 /*
749 * Read the password string from /dev/tty until we get interrupted or get a
750 * carriage return or newline...
751 */
752
753 passptr = cg->password;
754 passend = cg->password + sizeof(cg->password) - 1;
755
756 while ((passbytes = read(tty, &passch, 1)) == 1)
757 {
8dd318e5
MS
758 if (passch == noecho.c_cc[VEOL] ||
759# ifdef VEOL2
760 passch == noecho.c_cc[VEOL2] ||
761# endif /* VEOL2 */
dcb445bc
MS
762 passch == 0x0A || passch == 0x0D)
763 {
764 /*
765 * Enter/return...
766 */
767
768 break;
769 }
770 else if (passch == noecho.c_cc[VERASE] ||
771 passch == 0x08 || passch == 0x7F)
772 {
773 /*
774 * Backspace/delete (erase character)...
775 */
776
777 if (passptr > cg->password)
778 {
779 passptr --;
780 fputs("\010 \010", stdout);
781 }
782 else
783 putchar(0x07);
784 }
785 else if (passch == noecho.c_cc[VKILL])
786 {
787 /*
788 * CTRL+U (erase line)
789 */
790
791 if (passptr > cg->password)
792 {
793 while (passptr > cg->password)
794 {
795 passptr --;
796 fputs("\010 \010", stdout);
797 }
798 }
799 else
800 putchar(0x07);
801 }
802 else if (passch == noecho.c_cc[VINTR] || passch == noecho.c_cc[VQUIT] ||
803 passch == noecho.c_cc[VEOF])
804 {
805 /*
806 * CTRL+C, CTRL+D, or CTRL+Z...
807 */
808
809 passptr = cg->password;
810 break;
811 }
812 else if ((passch & 255) < 0x20 || passptr >= passend)
813 putchar(0x07);
814 else
815 {
816 *passptr++ = passch;
817 putchar(_CUPS_PASSCHAR);
818 }
819
820 fflush(stdout);
821 }
822
823 putchar('\n');
824 fflush(stdout);
825
826 /*
827 * Cleanup...
828 */
829
830 tcsetattr(tty, TCSAFLUSH, &original);
831 close(tty);
832
833 /*
834 * Return the proper value...
835 */
836
837 if (passbytes == 1 && passptr > cg->password)
838 {
839 *passptr = '\0';
840 return (cg->password);
841 }
7cf5915e 842 else
dcb445bc
MS
843 {
844 memset(cg->password, 0, sizeof(cg->password));
845 return (NULL);
846 }
ef416fc2 847#endif /* WIN32 */
5a6b583a 848}
ef416fc2 849
850
eac3a0a0
MS
851#ifdef HAVE_GSSAPI
852/*
853 * '_cupsGSSServiceName()' - Get the GSS (Kerberos) service name.
854 */
855
856const char *
857_cupsGSSServiceName(void)
858{
859 _cups_globals_t *cg = _cupsGlobals(); /* Thread globals */
860
861
862 if (!cg->gss_service_name[0])
863 _cupsSetDefaults();
864
865 return (cg->gss_service_name);
866}
867#endif /* HAVE_GSSAPI */
868
869
ef416fc2 870/*
e07d4801 871 * '_cupsSetDefaults()' - Set the default server, port, and encryption.
b423cd4c 872 */
873
e07d4801
MS
874void
875_cupsSetDefaults(void)
b423cd4c 876{
877 cups_file_t *fp; /* File */
3abb875b 878 const char *home; /* Home directory of user */
b423cd4c 879 char filename[1024]; /* Filename */
3abb875b 880 _cups_client_conf_t cc; /* client.conf values */
b423cd4c 881 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
882
883
e07d4801
MS
884 DEBUG_puts("_cupsSetDefaults()");
885
886 /*
3abb875b
MS
887 * Load initial client.conf values...
888 */
889
890 cups_init_client_conf(&cc);
891
892 /*
893 * Read the /etc/cups/client.conf and ~/.cups/client.conf files, if
894 * present.
895 */
896
897 snprintf(filename, sizeof(filename), "%s/client.conf", cg->cups_serverroot);
898 if ((fp = cupsFileOpen(filename, "r")) != NULL)
899 {
900 cups_read_client_conf(fp, &cc);
901 cupsFileClose(fp);
902 }
903
904# ifdef HAVE_GETEUID
905 if ((geteuid() == getuid() || !getuid()) && getegid() == getgid() && (home = getenv("HOME")) != NULL)
906# elif !defined(WIN32)
907 if (getuid() && (home = getenv("HOME")) != NULL)
908# else
909 if ((home = getenv("HOME")) != NULL)
910# endif /* HAVE_GETEUID */
911 {
912 /*
913 * Look for ~/.cups/client.conf...
914 */
915
916 snprintf(filename, sizeof(filename), "%s/.cups/client.conf", home);
917 if ((fp = cupsFileOpen(filename, "r")) != NULL)
918 {
919 cups_read_client_conf(fp, &cc);
920 cupsFileClose(fp);
921 }
922 }
923
924 /*
925 * Finalize things so every client.conf value is set...
e07d4801
MS
926 */
927
3abb875b
MS
928 cups_finalize_client_conf(&cc);
929
930 if (cg->encryption == (http_encryption_t)-1)
931 cg->encryption = cc.encryption;
932
933 if (!cg->server[0] || !cg->ipp_port)
934 cupsSetServer(cc.server_name);
935
936 if (!cg->ipp_port)
4b9daaf4 937 cups_set_default_ipp_port(cg);
3abb875b
MS
938
939 if (!cg->user[0])
940 strlcpy(cg->user, cc.user, sizeof(cg->user));
941
942#ifdef HAVE_GSSAPI
943 if (!cg->gss_service_name[0])
944 strlcpy(cg->gss_service_name, cc.gss_service_name, sizeof(cg->gss_service_name));
945#endif /* HAVE_GSSAPI */
946
08d56b1f
MS
947 if (cg->trust_first < 0)
948 cg->trust_first = cc.trust_first;
949
3abb875b
MS
950 if (cg->any_root < 0)
951 cg->any_root = cc.any_root;
952
953 if (cg->expired_certs < 0)
954 cg->expired_certs = cc.expired_certs;
955
956 if (cg->validate_certs < 0)
957 cg->validate_certs = cc.validate_certs;
958
959#ifdef HAVE_SSL
c61b78bd
PE
960 if (cc.ssl_options != _HTTP_TLS_UNCHANGED)
961 {
962 _httpTLSSetOptions(cc.ssl_options);
963 }
3abb875b
MS
964#endif /* HAVE_SSL */
965}
966
967
08d56b1f
MS
968#ifdef __APPLE__
969/*
970 * 'cups_apple_get_boolean()' - Get a boolean setting from the CUPS preferences.
971 */
972
973static int /* O - 1 if set, 0 otherwise */
974cups_apple_get_boolean(
975 CFStringRef key, /* I - Key (name) */
976 int *value) /* O - Boolean value */
977{
978 Boolean bval, /* Preference value */
979 bval_set; /* Value is set? */
980
981
982 bval = CFPreferencesGetAppBooleanValue(key, kCUPSPrintingPrefs, &bval_set);
983
984 if (bval_set)
985 *value = (int)bval;
986
987 return ((int)bval_set);
988}
989
990
991/*
992 * 'cups_apple_get_string()' - Get a string setting from the CUPS preferences.
993 */
994
995static int /* O - 1 if set, 0 otherwise */
996cups_apple_get_string(
997 CFStringRef key, /* I - Key (name) */
998 char *value, /* O - String value */
999 size_t valsize) /* I - Size of value buffer */
1000{
1001 CFStringRef sval; /* String value */
1002
1003
1004 if ((sval = CFPreferencesCopyAppValue(key, kCUPSPrintingPrefs)) != NULL)
1005 {
1006 Boolean result = CFStringGetCString(sval, value, (CFIndex)valsize, kCFStringEncodingUTF8);
1007
1008 CFRelease(sval);
1009
1010 if (result)
1011 return (1);
1012 }
1013
1014 return (0);
1015}
1016#endif /* __APPLE__ */
1017
1018
3abb875b
MS
1019/*
1020 * 'cups_boolean_value()' - Convert a string to a boolean value.
1021 */
1022
1023static int /* O - Boolean value */
1024cups_boolean_value(const char *value) /* I - String value */
1025{
1026 return (!_cups_strcasecmp(value, "yes") || !_cups_strcasecmp(value, "on") || !_cups_strcasecmp(value, "true"));
1027}
1028
1029
1030/*
1031 * 'cups_finalize_client_conf()' - Finalize client.conf values.
1032 */
1033
1034static void
1035cups_finalize_client_conf(
1036 _cups_client_conf_t *cc) /* I - client.conf values */
1037{
1038 const char *value; /* Environment variable */
1039
1040
08d56b1f
MS
1041 if ((value = getenv("CUPS_TRUSTFIRST")) != NULL)
1042 cc->trust_first = cups_boolean_value(value);
1043
3abb875b
MS
1044 if ((value = getenv("CUPS_ANYROOT")) != NULL)
1045 cc->any_root = cups_boolean_value(value);
1046
1047 if ((value = getenv("CUPS_ENCRYPTION")) != NULL)
1048 cups_set_encryption(cc, value);
1049
1050 if ((value = getenv("CUPS_EXPIREDCERTS")) != NULL)
1051 cc->expired_certs = cups_boolean_value(value);
1052
07ed0e9a 1053#ifdef HAVE_GSSAPI
3abb875b
MS
1054 if ((value = getenv("CUPS_GSSSERVICENAME")) != NULL)
1055 cups_set_gss_service_name(cc, value);
07ed0e9a 1056#endif /* HAVE_GSSAPI */
3abb875b
MS
1057
1058 if ((value = getenv("CUPS_SERVER")) != NULL)
1059 cups_set_server_name(cc, value);
1060
1061 if ((value = getenv("CUPS_USER")) != NULL)
1062 cups_set_user(cc, value);
1063
1064 if ((value = getenv("CUPS_VALIDATECERTS")) != NULL)
1065 cc->validate_certs = cups_boolean_value(value);
e07d4801
MS
1066
1067 /*
3abb875b 1068 * Then apply defaults for those values that haven't been set...
e07d4801
MS
1069 */
1070
08d56b1f
MS
1071 if (cc->trust_first < 0)
1072 cc->trust_first = 1;
1073
3abb875b
MS
1074 if (cc->any_root < 0)
1075 cc->any_root = 1;
1076
1077 if (cc->encryption == (http_encryption_t)-1)
1078 cc->encryption = HTTP_ENCRYPTION_IF_REQUESTED;
1079
1080 if (cc->expired_certs < 0)
08d56b1f 1081 cc->expired_certs = 0;
3abb875b
MS
1082
1083#ifdef HAVE_GSSAPI
1084 if (!cc->gss_service_name[0])
1085 cups_set_gss_service_name(cc, CUPS_DEFAULT_GSSSERVICENAME);
1086#endif /* HAVE_GSSAPI */
1087
1088 if (!cc->server_name[0])
e07d4801 1089 {
3abb875b 1090#ifdef CUPS_DEFAULT_DOMAINSOCKET
63aefcd5 1091 /*
3abb875b
MS
1092 * If we are compiled with domain socket support, only use the
1093 * domain socket if it exists and has the right permissions...
63aefcd5
MS
1094 */
1095
89b7fd55 1096 if (!access(CUPS_DEFAULT_DOMAINSOCKET, R_OK))
3abb875b
MS
1097 cups_set_server_name(cc, CUPS_DEFAULT_DOMAINSOCKET);
1098 else
1099#endif /* CUPS_DEFAULT_DOMAINSOCKET */
1100 cups_set_server_name(cc, "localhost");
1101 }
63aefcd5 1102
3abb875b
MS
1103 if (!cc->user[0])
1104 {
1105#ifdef WIN32
63aefcd5 1106 /*
3abb875b 1107 * Get the current user name from the OS...
63aefcd5
MS
1108 */
1109
3abb875b 1110 DWORD size; /* Size of string */
63aefcd5 1111
3abb875b
MS
1112 size = sizeof(cc->user);
1113 if (!GetUserName(cc->user, &size))
1114#else
63aefcd5 1115 /*
3abb875b 1116 * Try the USER environment variable as the default username...
63aefcd5
MS
1117 */
1118
3abb875b
MS
1119 const char *envuser = getenv("USER");
1120 /* Default username */
1121 struct passwd *pw = NULL; /* Account information */
1122
1123 if (envuser)
d09495fa 1124 {
10d09e33 1125 /*
3abb875b
MS
1126 * Validate USER matches the current UID, otherwise don't allow it to
1127 * override things... This makes sure that printing after doing su
1128 * or sudo records the correct username.
10d09e33 1129 */
e07d4801 1130
3abb875b
MS
1131 if ((pw = getpwnam(envuser)) != NULL && pw->pw_uid != getuid())
1132 pw = NULL;
1133 }
1134
1135 if (!pw)
1136 pw = getpwuid(getuid());
e07d4801 1137
3abb875b
MS
1138 if (pw)
1139 strlcpy(cc->user, pw->pw_name, sizeof(cc->user));
1140 else
1141#endif /* WIN32 */
1142 {
e07d4801 1143 /*
3abb875b 1144 * Use the default "unknown" user name...
e07d4801
MS
1145 */
1146
3abb875b 1147 strlcpy(cc->user, "unknown", sizeof(cc->user));
63aefcd5 1148 }
e07d4801 1149 }
3abb875b
MS
1150
1151 if (cc->validate_certs < 0)
1152 cc->validate_certs = 0;
1153}
1154
1155
1156/*
1157 * 'cups_init_client_conf()' - Initialize client.conf values.
1158 */
1159
1160static void
1161cups_init_client_conf(
1162 _cups_client_conf_t *cc) /* I - client.conf values */
1163{
1164 /*
1165 * Clear all values to "not set"...
1166 */
1167
1168 memset(cc, 0, sizeof(_cups_client_conf_t));
1169
1170 cc->encryption = (http_encryption_t)-1;
08d56b1f 1171 cc->trust_first = -1;
3abb875b
MS
1172 cc->any_root = -1;
1173 cc->expired_certs = -1;
1174 cc->validate_certs = -1;
08d56b1f
MS
1175
1176 /*
1177 * Load settings from the org.cups.PrintingPrefs plist (which trump
1178 * everything...)
1179 */
1180
b908d72c 1181#if defined(__APPLE__) && defined(HAVE_SSL)
08d56b1f
MS
1182 char sval[1024]; /* String value */
1183 int bval; /* Boolean value */
1184
1185 if (cups_apple_get_boolean(kAllowAnyRootKey, &bval))
1186 cc->any_root = bval;
1187
1188 if (cups_apple_get_boolean(kAllowExpiredCertsKey, &bval))
1189 cc->expired_certs = bval;
1190
1191 if (cups_apple_get_string(kEncryptionKey, sval, sizeof(sval)))
1192 cups_set_encryption(cc, sval);
1193
1194 if (cups_apple_get_string(kSSLOptionsKey, sval, sizeof(sval)))
1195 cups_set_ssl_options(cc, sval);
1196
1197 if (cups_apple_get_boolean(kTrustOnFirstUseKey, &bval))
1198 cc->trust_first = bval;
1199
1200 if (cups_apple_get_boolean(kValidateCertsKey, &bval))
1201 cc->validate_certs = bval;
b908d72c 1202#endif /* __APPLE__ && HAVE_SSL */
e07d4801
MS
1203}
1204
1205
1206/*
1207 * 'cups_read_client_conf()' - Read a client.conf file.
1208 */
1209
1210static void
1211cups_read_client_conf(
3abb875b
MS
1212 cups_file_t *fp, /* I - File to read */
1213 _cups_client_conf_t *cc) /* I - client.conf values */
e07d4801
MS
1214{
1215 int linenum; /* Current line number */
1216 char line[1024], /* Line from file */
3abb875b 1217 *value; /* Pointer into line */
e07d4801
MS
1218
1219
1220 /*
1221 * Read from the file...
1222 */
1223
1224 linenum = 0;
1225 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
1226 {
3abb875b
MS
1227 if (!_cups_strcasecmp(line, "Encryption") && value)
1228 cups_set_encryption(cc, value);
85dda01c
MS
1229#ifndef __APPLE__
1230 /*
8072030b 1231 * The ServerName directive is not supported on macOS due to app
3abb875b 1232 * sandboxing restrictions, i.e. not all apps request network access.
85dda01c 1233 */
3abb875b
MS
1234 else if (!_cups_strcasecmp(line, "ServerName") && value)
1235 cups_set_server_name(cc, value);
85dda01c 1236#endif /* !__APPLE__ */
3abb875b
MS
1237 else if (!_cups_strcasecmp(line, "User") && value)
1238 cups_set_user(cc, value);
08d56b1f
MS
1239 else if (!_cups_strcasecmp(line, "TrustOnFirstUse") && value)
1240 cc->trust_first = cups_boolean_value(value);
3abb875b
MS
1241 else if (!_cups_strcasecmp(line, "AllowAnyRoot") && value)
1242 cc->any_root = cups_boolean_value(value);
1243 else if (!_cups_strcasecmp(line, "AllowExpiredCerts") &&
7cf5915e 1244 value)
3abb875b
MS
1245 cc->expired_certs = cups_boolean_value(value);
1246 else if (!_cups_strcasecmp(line, "ValidateCerts") && value)
1247 cc->validate_certs = cups_boolean_value(value);
07ed0e9a 1248#ifdef HAVE_GSSAPI
3abb875b
MS
1249 else if (!_cups_strcasecmp(line, "GSSServiceName") && value)
1250 cups_set_gss_service_name(cc, value);
07ed0e9a 1251#endif /* HAVE_GSSAPI */
22ebb7d0 1252#ifdef HAVE_SSL
3abb875b
MS
1253 else if (!_cups_strcasecmp(line, "SSLOptions") && value)
1254 cups_set_ssl_options(cc, value);
1255#endif /* HAVE_SSL */
1256 }
1257}
63aefcd5 1258
63aefcd5 1259
4b9daaf4
MS
1260/*
1261 * 'cups_set_default_ipp_port()' - Set the default IPP port value.
1262 */
1263
1264static void
1265cups_set_default_ipp_port(
1266 _cups_globals_t *cg) /* I - Global data */
1267{
1268 const char *ipp_port; /* IPP_PORT environment variable */
1269
1270
1271 if ((ipp_port = getenv("IPP_PORT")) != NULL)
1272 {
1273 if ((cg->ipp_port = atoi(ipp_port)) <= 0)
1274 cg->ipp_port = CUPS_DEFAULT_IPP_PORT;
1275 }
1276 else
1277 cg->ipp_port = CUPS_DEFAULT_IPP_PORT;
1278}
1279
3abb875b
MS
1280/*
1281 * 'cups_set_encryption()' - Set the Encryption value.
1282 */
63aefcd5 1283
3abb875b
MS
1284static void
1285cups_set_encryption(
1286 _cups_client_conf_t *cc, /* I - client.conf values */
1287 const char *value) /* I - Value */
1288{
1289 if (!_cups_strcasecmp(value, "never"))
1290 cc->encryption = HTTP_ENCRYPTION_NEVER;
1291 else if (!_cups_strcasecmp(value, "always"))
1292 cc->encryption = HTTP_ENCRYPTION_ALWAYS;
1293 else if (!_cups_strcasecmp(value, "required"))
1294 cc->encryption = HTTP_ENCRYPTION_REQUIRED;
1295 else
1296 cc->encryption = HTTP_ENCRYPTION_IF_REQUESTED;
1297}
e07d4801 1298
e07d4801 1299
3abb875b
MS
1300/*
1301 * 'cups_set_gss_service_name()' - Set the GSSServiceName value.
1302 */
b423cd4c 1303
3abb875b
MS
1304#ifdef HAVE_GSSAPI
1305static void
1306cups_set_gss_service_name(
1307 _cups_client_conf_t *cc, /* I - client.conf values */
1308 const char *value) /* I - Value */
1309{
1310 strlcpy(cc->gss_service_name, value, sizeof(cc->gss_service_name));
1311}
1312#endif /* HAVE_GSSAPI */
7cf5915e 1313
10d09e33 1314
3abb875b
MS
1315/*
1316 * 'cups_set_server_name()' - Set the ServerName value.
1317 */
10d09e33 1318
3abb875b
MS
1319static void
1320cups_set_server_name(
1321 _cups_client_conf_t *cc, /* I - client.conf values */
1322 const char *value) /* I - Value */
1323{
1324 strlcpy(cc->server_name, value, sizeof(cc->server_name));
1325}
10d09e33 1326
10d09e33 1327
3abb875b
MS
1328/*
1329 * 'cups_set_ssl_options()' - Set the SSLOptions value.
1330 */
10d09e33 1331
3abb875b
MS
1332#ifdef HAVE_SSL
1333static void
1334cups_set_ssl_options(
1335 _cups_client_conf_t *cc, /* I - client.conf values */
1336 const char *value) /* I - Value */
1337{
1338 /*
ee6226a5 1339 * SSLOptions [AllowRC4] [AllowSSL3] [AllowDH] [DenyTLS1.0] [None]
3abb875b 1340 */
10d09e33 1341
c61b78bd
PE
1342 unsigned int options = _HTTP_TLS_UNCHANGED; /* SSL/TLS options */
1343 char temp[256], /* Copy of value */
1344 *start, /* Start of option */
1345 *end; /* End of option */
3e7fe0ca 1346
3e7fe0ca 1347
3abb875b 1348 strlcpy(temp, value, sizeof(temp));
3e7fe0ca 1349
3abb875b
MS
1350 for (start = temp; *start; start = end)
1351 {
a8db9df8 1352 /*
3abb875b
MS
1353 * Find end of keyword...
1354 */
3e7fe0ca 1355
3abb875b
MS
1356 end = start;
1357 while (*end && !_cups_isspace(*end))
1358 end ++;
93e3d3f5 1359
3abb875b
MS
1360 if (*end)
1361 *end++ = '\0';
93e3d3f5 1362
3abb875b
MS
1363 /*
1364 * Compare...
1365 */
3e7fe0ca 1366
3abb875b
MS
1367 if (!_cups_strcasecmp(start, "AllowRC4"))
1368 options |= _HTTP_TLS_ALLOW_RC4;
1369 else if (!_cups_strcasecmp(start, "AllowSSL3"))
1370 options |= _HTTP_TLS_ALLOW_SSL3;
ee6226a5
MS
1371 else if (!_cups_strcasecmp(start, "AllowDH"))
1372 options |= _HTTP_TLS_ALLOW_DH;
f2e87147
MS
1373 else if (!_cups_strcasecmp(start, "DenyCBC"))
1374 options |= _HTTP_TLS_DENY_CBC;
ee6226a5
MS
1375 else if (!_cups_strcasecmp(start, "DenyTLS1.0"))
1376 options |= _HTTP_TLS_DENY_TLS10;
3abb875b 1377 else if (!_cups_strcasecmp(start, "None"))
ee6226a5 1378 options = _HTTP_TLS_NONE;
3e7fe0ca
MS
1379 }
1380
3abb875b 1381 cc->ssl_options = options;
b37d45d9 1382
807315e6 1383 DEBUG_printf(("4cups_set_ssl_options(cc=%p, value=\"%s\") options=%x", (void *)cc, value, options));
3abb875b
MS
1384}
1385#endif /* HAVE_SSL */
07ed0e9a 1386
7cf5915e 1387
3abb875b
MS
1388/*
1389 * 'cups_set_user()' - Set the User value.
1390 */
f51f3773 1391
3abb875b
MS
1392static void
1393cups_set_user(
1394 _cups_client_conf_t *cc, /* I - client.conf values */
1395 const char *value) /* I - Value */
1396{
1397 strlcpy(cc->user, value, sizeof(cc->user));
b423cd4c 1398}