Coverage Report

Created: 2025-11-11 06:34

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