Coverage Report

Created: 2026-10-17 07:24

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