Coverage Report

Created: 2026-02-26 06:24

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