Coverage Report

Created: 2025-07-12 06:24

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