Coverage Report

Created: 2025-10-13 07:06

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