Coverage Report

Created: 2026-04-09 07:06

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