Imported Upstream version 2.2.2
[platform/upstream/cups.git] / cups / usersys.c
1 /*
2  * User, system, and password routines for CUPS.
3  *
4  * Copyright 2007-2015 by Apple Inc.
5  * Copyright 1997-2006 by Easy Software Products.
6  *
7  * These coded instructions, statements, and computer programs are the
8  * property of Apple Inc. and are protected by Federal copyright
9  * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
10  * which should have been included with this file.  If this file is
11  * missing or damaged, see the license at "http://www.cups.org/".
12  *
13  * This file is subject to the Apple OS-Developed Software exception.
14  */
15
16 /*
17  * Include necessary headers...
18  */
19
20 #include "cups-private.h"
21 #include <stdlib.h>
22 #include <sys/stat.h>
23 #ifdef WIN32
24 #  include <windows.h>
25 #else
26 #  include <pwd.h>
27 #  include <termios.h>
28 #  include <sys/utsname.h>
29 #endif /* WIN32 */
30
31
32 /*
33  * Local constants...
34  */
35
36 #ifdef __APPLE__
37 #  define kCUPSPrintingPrefs    CFSTR("org.cups.PrintingPrefs")
38 #  define kAllowAnyRootKey      CFSTR("AllowAnyRoot")
39 #  define kAllowExpiredCertsKey CFSTR("AllowExpiredCerts")
40 #  define kEncryptionKey        CFSTR("Encryption")
41 #  define kGSSServiceNameKey    CFSTR("GSSServiceName")
42 #  define kSSLOptionsKey        CFSTR("SSLOptions")
43 #  define kTrustOnFirstUseKey   CFSTR("TrustOnFirstUse")
44 #  define kValidateCertsKey     CFSTR("ValidateCerts")
45 #endif /* __APPLE__ */
46
47 #define _CUPS_PASSCHAR  '*'             /* Character that is echoed for password */
48
49
50 /*
51  * Local types...
52  */
53
54 typedef struct _cups_client_conf_s      /**** client.conf config data ****/
55 {
56 #ifdef HAVE_SSL
57   int                   ssl_options;    /* SSLOptions values */
58 #endif /* HAVE_SSL */
59   int                   trust_first,    /* Trust on first use? */
60                         any_root,       /* Allow any (e.g., self-signed) root */
61                         expired_certs,  /* Allow expired certs */
62                         validate_certs; /* Validate certificates */
63   http_encryption_t     encryption;     /* Encryption setting */
64   char                  user[65],       /* User name */
65                         server_name[256];
66                                         /* Server hostname */
67 #ifdef HAVE_GSSAPI
68   char                  gss_service_name[32];
69                                         /* Kerberos service name */
70 #endif /* HAVE_GSSAPI */
71 } _cups_client_conf_t;
72
73
74 /*
75  * Local functions...
76  */
77
78 #ifdef __APPLE__
79 static int      cups_apple_get_boolean(CFStringRef key, int *value);
80 static int      cups_apple_get_string(CFStringRef key, char *value, size_t valsize);
81 #endif /* __APPLE__ */
82 static int      cups_boolean_value(const char *value);
83 static void     cups_finalize_client_conf(_cups_client_conf_t *cc);
84 static void     cups_init_client_conf(_cups_client_conf_t *cc);
85 static void     cups_read_client_conf(cups_file_t *fp, _cups_client_conf_t *cc);
86 static void     cups_set_default_ipp_port(_cups_globals_t *cg);
87 static void     cups_set_encryption(_cups_client_conf_t *cc, const char *value);
88 #ifdef HAVE_GSSAPI
89 static void     cups_set_gss_service_name(_cups_client_conf_t *cc, const char *value);
90 #endif /* HAVE_GSSAPI */
91 static void     cups_set_server_name(_cups_client_conf_t *cc, const char *value);
92 #ifdef HAVE_SSL
93 static void     cups_set_ssl_options(_cups_client_conf_t *cc, const char *value);
94 #endif /* HAVE_SSL */
95 static void     cups_set_user(_cups_client_conf_t *cc, const char *value);
96
97
98 /*
99  * 'cupsEncryption()' - Get the current encryption settings.
100  *
101  * The default encryption setting comes from the CUPS_ENCRYPTION
102  * environment variable, then the ~/.cups/client.conf file, and finally the
103  * /etc/cups/client.conf file. If not set, the default is
104  * @code HTTP_ENCRYPTION_IF_REQUESTED@.
105  *
106  * Note: The current encryption setting is tracked separately for each thread
107  * in a program. Multi-threaded programs that override the setting via the
108  * @link cupsSetEncryption@ function need to do so in each thread for the same
109  * setting to be used.
110  */
111
112 http_encryption_t                       /* O - Encryption settings */
113 cupsEncryption(void)
114 {
115   _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
116
117
118   if (cg->encryption == (http_encryption_t)-1)
119     _cupsSetDefaults();
120
121   return (cg->encryption);
122 }
123
124
125 /*
126  * 'cupsGetPassword()' - Get a password from the user.
127  *
128  * Uses the current password callback function. Returns @code NULL@ if the
129  * user does not provide a password.
130  *
131  * Note: The current password callback function is tracked separately for each
132  * thread in a program. Multi-threaded programs that override the setting via
133  * the @link cupsSetPasswordCB@ or @link cupsSetPasswordCB2@ functions need to
134  * do so in each thread for the same function to be used.
135  */
136
137 const char *                            /* O - Password */
138 cupsGetPassword(const char *prompt)     /* I - Prompt string */
139 {
140   _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
141
142
143   return ((cg->password_cb)(prompt, NULL, NULL, NULL, cg->password_data));
144 }
145
146
147 /*
148  * 'cupsGetPassword2()' - Get a password from the user using the advanced
149  *                        password callback.
150  *
151  * Uses the current password callback function. Returns @code NULL@ if the
152  * user does not provide a password.
153  *
154  * Note: The current password callback function is tracked separately for each
155  * thread in a program. Multi-threaded programs that override the setting via
156  * the @link cupsSetPasswordCB@ or @link cupsSetPasswordCB2@ functions need to
157  * do so in each thread for the same function to be used.
158  *
159  * @since CUPS 1.4/macOS 10.6@
160  */
161
162 const char *                            /* O - Password */
163 cupsGetPassword2(const char *prompt,    /* I - Prompt string */
164                  http_t     *http,      /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
165                  const char *method,    /* I - Request method ("GET", "POST", "PUT") */
166                  const char *resource)  /* I - Resource path */
167 {
168   _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
169
170
171   if (!http)
172     http = _cupsConnect();
173
174   return ((cg->password_cb)(prompt, http, method, resource, cg->password_data));
175 }
176
177
178 /*
179  * 'cupsServer()' - Return the hostname/address of the current server.
180  *
181  * The default server comes from the CUPS_SERVER environment variable, then the
182  * ~/.cups/client.conf file, and finally the /etc/cups/client.conf file. If not
183  * set, the default is the local system - either "localhost" or a domain socket
184  * path.
185  *
186  * The returned value can be a fully-qualified hostname, a numeric IPv4 or IPv6
187  * address, or a domain socket pathname.
188  *
189  * Note: The current server is tracked separately for each thread in a program.
190  * Multi-threaded programs that override the server via the
191  * @link cupsSetServer@ function need to do so in each thread for the same
192  * server to be used.
193  */
194
195 const char *                            /* O - Server name */
196 cupsServer(void)
197 {
198   _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
199
200
201   if (!cg->server[0])
202     _cupsSetDefaults();
203
204   return (cg->server);
205 }
206
207
208 /*
209  * 'cupsSetClientCertCB()' - Set the client certificate callback.
210  *
211  * Pass @code NULL@ to restore the default callback.
212  *
213  * Note: The current certificate callback is tracked separately for each thread
214  * in a program. Multi-threaded programs that override the callback need to do
215  * so in each thread for the same callback to be used.
216  *
217  * @since CUPS 1.5/macOS 10.7@
218  */
219
220 void
221 cupsSetClientCertCB(
222     cups_client_cert_cb_t cb,           /* I - Callback function */
223     void                  *user_data)   /* I - User data pointer */
224 {
225   _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
226
227
228   cg->client_cert_cb    = cb;
229   cg->client_cert_data  = user_data;
230 }
231
232
233 /*
234  * 'cupsSetCredentials()' - Set the default credentials to be used for SSL/TLS
235  *                          connections.
236  *
237  * Note: The default credentials are tracked separately for each thread in a
238  * program. Multi-threaded programs that override the setting need to do so in
239  * each thread for the same setting to be used.
240  *
241  * @since CUPS 1.5/macOS 10.7@
242  */
243
244 int                                     /* O - Status of call (0 = success) */
245 cupsSetCredentials(
246     cups_array_t *credentials)          /* I - Array of credentials */
247 {
248   _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
249
250
251   if (cupsArrayCount(credentials) < 1)
252     return (-1);
253
254 #ifdef HAVE_SSL
255   _httpFreeCredentials(cg->tls_credentials);
256   cg->tls_credentials = _httpCreateCredentials(credentials);
257 #endif /* HAVE_SSL */
258
259   return (cg->tls_credentials ? 0 : -1);
260 }
261
262
263 /*
264  * 'cupsSetEncryption()' - Set the encryption preference.
265  *
266  * The default encryption setting comes from the CUPS_ENCRYPTION
267  * environment variable, then the ~/.cups/client.conf file, and finally the
268  * /etc/cups/client.conf file. If not set, the default is
269  * @code HTTP_ENCRYPTION_IF_REQUESTED@.
270  *
271  * Note: The current encryption setting is tracked separately for each thread
272  * in a program. Multi-threaded programs that override the setting need to do
273  * so in each thread for the same setting to be used.
274  */
275
276 void
277 cupsSetEncryption(http_encryption_t e)  /* I - New encryption preference */
278 {
279   _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
280
281
282   cg->encryption = e;
283
284   if (cg->http)
285     httpEncryption(cg->http, e);
286 }
287
288
289 /*
290  * 'cupsSetPasswordCB()' - Set the password callback for CUPS.
291  *
292  * Pass @code NULL@ to restore the default (console) password callback, which
293  * reads the password from the console. Programs should call either this
294  * function or @link cupsSetPasswordCB2@, as only one callback can be registered
295  * by a program per thread.
296  *
297  * Note: The current password callback is tracked separately for each thread
298  * in a program. Multi-threaded programs that override the callback need to do
299  * so in each thread for the same callback to be used.
300  */
301
302 void
303 cupsSetPasswordCB(cups_password_cb_t cb)/* I - Callback function */
304 {
305   _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
306
307
308   if (cb == (cups_password_cb_t)0)
309     cg->password_cb = (cups_password_cb2_t)_cupsGetPassword;
310   else
311     cg->password_cb = (cups_password_cb2_t)cb;
312
313   cg->password_data = NULL;
314 }
315
316
317 /*
318  * 'cupsSetPasswordCB2()' - Set the advanced password callback for CUPS.
319  *
320  * Pass @code NULL@ to restore the default (console) password callback, which
321  * reads the password from the console. Programs should call either this
322  * function or @link cupsSetPasswordCB2@, as only one callback can be registered
323  * by a program per thread.
324  *
325  * Note: The current password callback is tracked separately for each thread
326  * in a program. Multi-threaded programs that override the callback need to do
327  * so in each thread for the same callback to be used.
328  *
329  * @since CUPS 1.4/macOS 10.6@
330  */
331
332 void
333 cupsSetPasswordCB2(
334     cups_password_cb2_t cb,             /* I - Callback function */
335     void                *user_data)     /* I - User data pointer */
336 {
337   _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
338
339
340   if (cb == (cups_password_cb2_t)0)
341     cg->password_cb = (cups_password_cb2_t)_cupsGetPassword;
342   else
343     cg->password_cb = cb;
344
345   cg->password_data = user_data;
346 }
347
348
349 /*
350  * 'cupsSetServer()' - Set the default server name and port.
351  *
352  * The "server" string can be a fully-qualified hostname, a numeric
353  * IPv4 or IPv6 address, or a domain socket pathname. Hostnames and numeric IP
354  * addresses can be optionally followed by a colon and port number to override
355  * the default port 631, e.g. "hostname:8631". Pass @code NULL@ to restore the
356  * default server name and port.
357  *
358  * Note: The current server is tracked separately for each thread in a program.
359  * Multi-threaded programs that override the server need to do so in each
360  * thread for the same server to be used.
361  */
362
363 void
364 cupsSetServer(const char *server)       /* I - Server name */
365 {
366   char          *options,               /* Options */
367                 *port;                  /* Pointer to port */
368   _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
369
370
371   if (server)
372   {
373     strlcpy(cg->server, server, sizeof(cg->server));
374
375     if (cg->server[0] != '/' && (options = strrchr(cg->server, '/')) != NULL)
376     {
377       *options++ = '\0';
378
379       if (!strcmp(options, "version=1.0"))
380         cg->server_version = 10;
381       else if (!strcmp(options, "version=1.1"))
382         cg->server_version = 11;
383       else if (!strcmp(options, "version=2.0"))
384         cg->server_version = 20;
385       else if (!strcmp(options, "version=2.1"))
386         cg->server_version = 21;
387       else if (!strcmp(options, "version=2.2"))
388         cg->server_version = 22;
389     }
390     else
391       cg->server_version = 20;
392
393     if (cg->server[0] != '/' && (port = strrchr(cg->server, ':')) != NULL &&
394         !strchr(port, ']') && isdigit(port[1] & 255))
395     {
396       *port++ = '\0';
397
398       cg->ipp_port = atoi(port);
399     }
400
401     if (!cg->ipp_port)
402       cups_set_default_ipp_port(cg);
403
404     if (cg->server[0] == '/')
405       strlcpy(cg->servername, "localhost", sizeof(cg->servername));
406     else
407       strlcpy(cg->servername, cg->server, sizeof(cg->servername));
408   }
409   else
410   {
411     cg->server[0]      = '\0';
412     cg->servername[0]  = '\0';
413     cg->server_version = 20;
414     cg->ipp_port       = 0;
415   }
416
417   if (cg->http)
418   {
419     httpClose(cg->http);
420     cg->http = NULL;
421   }
422 }
423
424
425 /*
426  * 'cupsSetServerCertCB()' - Set the server certificate callback.
427  *
428  * Pass @code NULL@ to restore the default callback.
429  *
430  * Note: The current credentials callback is tracked separately for each thread
431  * in a program. Multi-threaded programs that override the callback need to do
432  * so in each thread for the same callback to be used.
433  *
434  * @since CUPS 1.5/macOS 10.7@
435  */
436
437 void
438 cupsSetServerCertCB(
439     cups_server_cert_cb_t cb,           /* I - Callback function */
440     void                  *user_data)   /* I - User data pointer */
441 {
442   _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
443
444
445   cg->server_cert_cb    = cb;
446   cg->server_cert_data  = user_data;
447 }
448
449
450 /*
451  * 'cupsSetUser()' - Set the default user name.
452  *
453  * Pass @code NULL@ to restore the default user name.
454  *
455  * Note: The current user name is tracked separately for each thread in a
456  * program. Multi-threaded programs that override the user name need to do so
457  * in each thread for the same user name to be used.
458  */
459
460 void
461 cupsSetUser(const char *user)           /* I - User name */
462 {
463   _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
464
465
466   if (user)
467     strlcpy(cg->user, user, sizeof(cg->user));
468   else
469     cg->user[0] = '\0';
470 }
471
472
473 /*
474  * 'cupsSetUserAgent()' - Set the default HTTP User-Agent string.
475  *
476  * Setting the string to NULL forces the default value containing the CUPS
477  * version, IPP version, and operating system version and architecture.
478  *
479  * @since CUPS 1.7/macOS 10.9@
480  */
481
482 void
483 cupsSetUserAgent(const char *user_agent)/* I - User-Agent string or @code NULL@ */
484 {
485   _cups_globals_t       *cg = _cupsGlobals();
486                                         /* Thread globals */
487 #ifdef WIN32
488   SYSTEM_INFO           sysinfo;        /* System information */
489   OSVERSIONINFO         version;        /* OS version info */
490 #else
491   struct utsname        name;           /* uname info */
492 #endif /* WIN32 */
493
494
495   if (user_agent)
496   {
497     strlcpy(cg->user_agent, user_agent, sizeof(cg->user_agent));
498     return;
499   }
500
501 #ifdef WIN32
502   version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
503   GetVersionEx(&version);
504   GetNativeSystemInfo(&sysinfo);
505
506   snprintf(cg->user_agent, sizeof(cg->user_agent),
507            CUPS_MINIMAL " (Windows %d.%d; %s) IPP/2.0",
508            version.dwMajorVersion, version.dwMinorVersion,
509            sysinfo.wProcessorArchitecture
510                == PROCESSOR_ARCHITECTURE_AMD64 ? "amd64" :
511                sysinfo.wProcessorArchitecture
512                    == PROCESSOR_ARCHITECTURE_ARM ? "arm" :
513                sysinfo.wProcessorArchitecture
514                    == PROCESSOR_ARCHITECTURE_IA64 ? "ia64" :
515                sysinfo.wProcessorArchitecture
516                    == PROCESSOR_ARCHITECTURE_INTEL ? "intel" :
517                "unknown");
518
519 #else
520   uname(&name);
521
522   snprintf(cg->user_agent, sizeof(cg->user_agent),
523            CUPS_MINIMAL " (%s %s; %s) IPP/2.0",
524            name.sysname, name.release, name.machine);
525 #endif /* WIN32 */
526 }
527
528
529 /*
530  * 'cupsUser()' - Return the current user's name.
531  *
532  * Note: The current user name is tracked separately for each thread in a
533  * program. Multi-threaded programs that override the user name with the
534  * @link cupsSetUser@ function need to do so in each thread for the same user
535  * name to be used.
536  */
537
538 const char *                            /* O - User name */
539 cupsUser(void)
540 {
541   _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
542
543
544   if (!cg->user[0])
545     _cupsSetDefaults();
546
547   return (cg->user);
548 }
549
550
551 /*
552  * 'cupsUserAgent()' - Return the default HTTP User-Agent string.
553  *
554  * @since CUPS 1.7/macOS 10.9@
555  */
556
557 const char *                            /* O - User-Agent string */
558 cupsUserAgent(void)
559 {
560   _cups_globals_t *cg = _cupsGlobals(); /* Thread globals */
561
562
563   if (!cg->user_agent[0])
564     cupsSetUserAgent(NULL);
565
566   return (cg->user_agent);
567 }
568
569
570 /*
571  * '_cupsGetPassword()' - Get a password from the user.
572  */
573
574 const char *                            /* O - Password or @code NULL@ if none */
575 _cupsGetPassword(const char *prompt)    /* I - Prompt string */
576 {
577 #ifdef WIN32
578   HANDLE                tty;            /* Console handle */
579   DWORD                 mode;           /* Console mode */
580   char                  passch,         /* Current key press */
581                         *passptr,       /* Pointer into password string */
582                         *passend;       /* End of password string */
583   DWORD                 passbytes;      /* Bytes read */
584   _cups_globals_t       *cg = _cupsGlobals();
585                                         /* Thread globals */
586
587
588  /*
589   * Disable input echo and set raw input...
590   */
591
592   if ((tty = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE)
593     return (NULL);
594
595   if (!GetConsoleMode(tty, &mode))
596     return (NULL);
597
598   if (!SetConsoleMode(tty, 0))
599     return (NULL);
600
601  /*
602   * Display the prompt...
603   */
604
605   printf("%s ", prompt);
606   fflush(stdout);
607
608  /*
609   * Read the password string from /dev/tty until we get interrupted or get a
610   * carriage return or newline...
611   */
612
613   passptr = cg->password;
614   passend = cg->password + sizeof(cg->password) - 1;
615
616   while (ReadFile(tty, &passch, 1, &passbytes, NULL))
617   {
618     if (passch == 0x0A || passch == 0x0D)
619     {
620      /*
621       * Enter/return...
622       */
623
624       break;
625     }
626     else if (passch == 0x08 || passch == 0x7F)
627     {
628      /*
629       * Backspace/delete (erase character)...
630       */
631
632       if (passptr > cg->password)
633       {
634         passptr --;
635         fputs("\010 \010", stdout);
636       }
637       else
638         putchar(0x07);
639     }
640     else if (passch == 0x15)
641     {
642      /*
643       * CTRL+U (erase line)
644       */
645
646       if (passptr > cg->password)
647       {
648         while (passptr > cg->password)
649         {
650           passptr --;
651           fputs("\010 \010", stdout);
652         }
653       }
654       else
655         putchar(0x07);
656     }
657     else if (passch == 0x03)
658     {
659      /*
660       * CTRL+C...
661       */
662
663       passptr = cg->password;
664       break;
665     }
666     else if ((passch & 255) < 0x20 || passptr >= passend)
667       putchar(0x07);
668     else
669     {
670       *passptr++ = passch;
671       putchar(_CUPS_PASSCHAR);
672     }
673
674     fflush(stdout);
675   }
676
677   putchar('\n');
678   fflush(stdout);
679
680  /*
681   * Cleanup...
682   */
683
684   SetConsoleMode(tty, mode);
685
686  /*
687   * Return the proper value...
688   */
689
690   if (passbytes == 1 && passptr > cg->password)
691   {
692     *passptr = '\0';
693     return (cg->password);
694   }
695   else
696   {
697     memset(cg->password, 0, sizeof(cg->password));
698     return (NULL);
699   }
700
701 #else
702   int                   tty;            /* /dev/tty - never read from stdin */
703   struct termios        original,       /* Original input mode */
704                         noecho;         /* No echo input mode */
705   char                  passch,         /* Current key press */
706                         *passptr,       /* Pointer into password string */
707                         *passend;       /* End of password string */
708   ssize_t               passbytes;      /* Bytes read */
709   _cups_globals_t       *cg = _cupsGlobals();
710                                         /* Thread globals */
711
712
713  /*
714   * Disable input echo and set raw input...
715   */
716
717   if ((tty = open("/dev/tty", O_RDONLY)) < 0)
718     return (NULL);
719
720   if (tcgetattr(tty, &original))
721   {
722     close(tty);
723     return (NULL);
724   }
725
726   noecho = original;
727   noecho.c_lflag &= (tcflag_t)~(ICANON | ECHO | ECHOE | ISIG);
728   noecho.c_cc[VMIN]  = 1;
729   noecho.c_cc[VTIME] = 0;
730
731   if (tcsetattr(tty, TCSAFLUSH, &noecho))
732   {
733     close(tty);
734     return (NULL);
735   }
736
737  /*
738   * Display the prompt...
739   */
740
741   printf("%s ", prompt);
742   fflush(stdout);
743
744  /*
745   * Read the password string from /dev/tty until we get interrupted or get a
746   * carriage return or newline...
747   */
748
749   passptr = cg->password;
750   passend = cg->password + sizeof(cg->password) - 1;
751
752   while ((passbytes = read(tty, &passch, 1)) == 1)
753   {
754     if (passch == noecho.c_cc[VEOL] ||
755 #  ifdef VEOL2
756         passch == noecho.c_cc[VEOL2] ||
757 #  endif /* VEOL2 */
758         passch == 0x0A || passch == 0x0D)
759     {
760      /*
761       * Enter/return...
762       */
763
764       break;
765     }
766     else if (passch == noecho.c_cc[VERASE] ||
767              passch == 0x08 || passch == 0x7F)
768     {
769      /*
770       * Backspace/delete (erase character)...
771       */
772
773       if (passptr > cg->password)
774       {
775         passptr --;
776         fputs("\010 \010", stdout);
777       }
778       else
779         putchar(0x07);
780     }
781     else if (passch == noecho.c_cc[VKILL])
782     {
783      /*
784       * CTRL+U (erase line)
785       */
786
787       if (passptr > cg->password)
788       {
789         while (passptr > cg->password)
790         {
791           passptr --;
792           fputs("\010 \010", stdout);
793         }
794       }
795       else
796         putchar(0x07);
797     }
798     else if (passch == noecho.c_cc[VINTR] || passch == noecho.c_cc[VQUIT] ||
799              passch == noecho.c_cc[VEOF])
800     {
801      /*
802       * CTRL+C, CTRL+D, or CTRL+Z...
803       */
804
805       passptr = cg->password;
806       break;
807     }
808     else if ((passch & 255) < 0x20 || passptr >= passend)
809       putchar(0x07);
810     else
811     {
812       *passptr++ = passch;
813       putchar(_CUPS_PASSCHAR);
814     }
815
816     fflush(stdout);
817   }
818
819   putchar('\n');
820   fflush(stdout);
821
822  /*
823   * Cleanup...
824   */
825
826   tcsetattr(tty, TCSAFLUSH, &original);
827   close(tty);
828
829  /*
830   * Return the proper value...
831   */
832
833   if (passbytes == 1 && passptr > cg->password)
834   {
835     *passptr = '\0';
836     return (cg->password);
837   }
838   else
839   {
840     memset(cg->password, 0, sizeof(cg->password));
841     return (NULL);
842   }
843 #endif /* WIN32 */
844 }
845
846
847 #ifdef HAVE_GSSAPI
848 /*
849  * '_cupsGSSServiceName()' - Get the GSS (Kerberos) service name.
850  */
851
852 const char *
853 _cupsGSSServiceName(void)
854 {
855   _cups_globals_t *cg = _cupsGlobals(); /* Thread globals */
856
857
858   if (!cg->gss_service_name[0])
859     _cupsSetDefaults();
860
861   return (cg->gss_service_name);
862 }
863 #endif /* HAVE_GSSAPI */
864
865
866 /*
867  * '_cupsSetDefaults()' - Set the default server, port, and encryption.
868  */
869
870 void
871 _cupsSetDefaults(void)
872 {
873   cups_file_t   *fp;                    /* File */
874   const char    *home;                  /* Home directory of user */
875   char          filename[1024];         /* Filename */
876   _cups_client_conf_t cc;               /* client.conf values */
877   _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
878
879
880   DEBUG_puts("_cupsSetDefaults()");
881
882  /*
883   * Load initial client.conf values...
884   */
885
886   cups_init_client_conf(&cc);
887
888  /*
889   * Read the /etc/cups/client.conf and ~/.cups/client.conf files, if
890   * present.
891   */
892
893   snprintf(filename, sizeof(filename), "%s/client.conf", cg->cups_serverroot);
894   if ((fp = cupsFileOpen(filename, "r")) != NULL)
895   {
896     cups_read_client_conf(fp, &cc);
897     cupsFileClose(fp);
898   }
899
900 #  ifdef HAVE_GETEUID
901   if ((geteuid() == getuid() || !getuid()) && getegid() == getgid() && (home = getenv("HOME")) != NULL)
902 #  elif !defined(WIN32)
903   if (getuid() && (home = getenv("HOME")) != NULL)
904 #  else
905   if ((home = getenv("HOME")) != NULL)
906 #  endif /* HAVE_GETEUID */
907   {
908    /*
909     * Look for ~/.cups/client.conf...
910     */
911
912     snprintf(filename, sizeof(filename), "%s/.cups/client.conf", home);
913     if ((fp = cupsFileOpen(filename, "r")) != NULL)
914     {
915       cups_read_client_conf(fp, &cc);
916       cupsFileClose(fp);
917     }
918   }
919
920  /*
921   * Finalize things so every client.conf value is set...
922   */
923
924   cups_finalize_client_conf(&cc);
925
926   if (cg->encryption == (http_encryption_t)-1)
927     cg->encryption = cc.encryption;
928
929   if (!cg->server[0] || !cg->ipp_port)
930     cupsSetServer(cc.server_name);
931
932   if (!cg->ipp_port)
933     cups_set_default_ipp_port(cg);
934
935   if (!cg->user[0])
936     strlcpy(cg->user, cc.user, sizeof(cg->user));
937
938 #ifdef HAVE_GSSAPI
939   if (!cg->gss_service_name[0])
940     strlcpy(cg->gss_service_name, cc.gss_service_name, sizeof(cg->gss_service_name));
941 #endif /* HAVE_GSSAPI */
942
943   if (cg->trust_first < 0)
944     cg->trust_first = cc.trust_first;
945
946   if (cg->any_root < 0)
947     cg->any_root = cc.any_root;
948
949   if (cg->expired_certs < 0)
950     cg->expired_certs = cc.expired_certs;
951
952   if (cg->validate_certs < 0)
953     cg->validate_certs = cc.validate_certs;
954
955 #ifdef HAVE_SSL
956   _httpTLSSetOptions(cc.ssl_options);
957 #endif /* HAVE_SSL */
958 }
959
960
961 #ifdef __APPLE__
962 /*
963  * 'cups_apple_get_boolean()' - Get a boolean setting from the CUPS preferences.
964  */
965
966 static int                              /* O - 1 if set, 0 otherwise */
967 cups_apple_get_boolean(
968     CFStringRef key,                    /* I - Key (name) */
969     int         *value)                 /* O - Boolean value */
970 {
971   Boolean       bval,                   /* Preference value */
972                 bval_set;               /* Value is set? */
973
974
975   bval = CFPreferencesGetAppBooleanValue(key, kCUPSPrintingPrefs, &bval_set);
976
977   if (bval_set)
978     *value = (int)bval;
979
980   return ((int)bval_set);
981 }
982
983
984 /*
985  * 'cups_apple_get_string()' - Get a string setting from the CUPS preferences.
986  */
987
988 static int                              /* O - 1 if set, 0 otherwise */
989 cups_apple_get_string(
990     CFStringRef key,                    /* I - Key (name) */
991     char        *value,                 /* O - String value */
992     size_t      valsize)                /* I - Size of value buffer */
993 {
994   CFStringRef   sval;                   /* String value */
995
996
997   if ((sval = CFPreferencesCopyAppValue(key, kCUPSPrintingPrefs)) != NULL)
998   {
999     Boolean result = CFStringGetCString(sval, value, (CFIndex)valsize, kCFStringEncodingUTF8);
1000
1001     CFRelease(sval);
1002
1003     if (result)
1004       return (1);
1005   }
1006
1007   return (0);
1008 }
1009 #endif /* __APPLE__ */
1010
1011
1012 /*
1013  * 'cups_boolean_value()' - Convert a string to a boolean value.
1014  */
1015
1016 static int                              /* O - Boolean value */
1017 cups_boolean_value(const char *value)   /* I - String value */
1018 {
1019   return (!_cups_strcasecmp(value, "yes") || !_cups_strcasecmp(value, "on") || !_cups_strcasecmp(value, "true"));
1020 }
1021
1022
1023 /*
1024  * 'cups_finalize_client_conf()' - Finalize client.conf values.
1025  */
1026
1027 static void
1028 cups_finalize_client_conf(
1029     _cups_client_conf_t *cc)            /* I - client.conf values */
1030 {
1031   const char    *value;                 /* Environment variable */
1032
1033
1034   if ((value = getenv("CUPS_TRUSTFIRST")) != NULL)
1035     cc->trust_first = cups_boolean_value(value);
1036
1037   if ((value = getenv("CUPS_ANYROOT")) != NULL)
1038     cc->any_root = cups_boolean_value(value);
1039
1040   if ((value = getenv("CUPS_ENCRYPTION")) != NULL)
1041     cups_set_encryption(cc, value);
1042
1043   if ((value = getenv("CUPS_EXPIREDCERTS")) != NULL)
1044     cc->expired_certs = cups_boolean_value(value);
1045
1046 #ifdef HAVE_GSSAPI
1047   if ((value = getenv("CUPS_GSSSERVICENAME")) != NULL)
1048     cups_set_gss_service_name(cc, value);
1049 #endif /* HAVE_GSSAPI */
1050
1051   if ((value = getenv("CUPS_SERVER")) != NULL)
1052     cups_set_server_name(cc, value);
1053
1054   if ((value = getenv("CUPS_USER")) != NULL)
1055     cups_set_user(cc, value);
1056
1057   if ((value = getenv("CUPS_VALIDATECERTS")) != NULL)
1058     cc->validate_certs = cups_boolean_value(value);
1059
1060  /*
1061   * Then apply defaults for those values that haven't been set...
1062   */
1063
1064   if (cc->trust_first < 0)
1065     cc->trust_first = 1;
1066
1067   if (cc->any_root < 0)
1068     cc->any_root = 1;
1069
1070   if (cc->encryption == (http_encryption_t)-1)
1071     cc->encryption = HTTP_ENCRYPTION_IF_REQUESTED;
1072
1073   if (cc->expired_certs < 0)
1074     cc->expired_certs = 0;
1075
1076 #ifdef HAVE_GSSAPI
1077   if (!cc->gss_service_name[0])
1078     cups_set_gss_service_name(cc, CUPS_DEFAULT_GSSSERVICENAME);
1079 #endif /* HAVE_GSSAPI */
1080
1081   if (!cc->server_name[0])
1082   {
1083 #ifdef CUPS_DEFAULT_DOMAINSOCKET
1084    /*
1085     * If we are compiled with domain socket support, only use the
1086     * domain socket if it exists and has the right permissions...
1087     */
1088
1089     if (!access(CUPS_DEFAULT_DOMAINSOCKET, R_OK))
1090       cups_set_server_name(cc, CUPS_DEFAULT_DOMAINSOCKET);
1091     else
1092 #endif /* CUPS_DEFAULT_DOMAINSOCKET */
1093       cups_set_server_name(cc, "localhost");
1094   }
1095
1096   if (!cc->user[0])
1097   {
1098 #ifdef WIN32
1099    /*
1100     * Get the current user name from the OS...
1101     */
1102
1103     DWORD       size;                   /* Size of string */
1104
1105     size = sizeof(cc->user);
1106     if (!GetUserName(cc->user, &size))
1107 #else
1108    /*
1109     * Try the USER environment variable as the default username...
1110     */
1111
1112     const char *envuser = getenv("USER");
1113                                         /* Default username */
1114     struct passwd *pw = NULL;           /* Account information */
1115
1116     if (envuser)
1117     {
1118      /*
1119       * Validate USER matches the current UID, otherwise don't allow it to
1120       * override things...  This makes sure that printing after doing su
1121       * or sudo records the correct username.
1122       */
1123
1124       if ((pw = getpwnam(envuser)) != NULL && pw->pw_uid != getuid())
1125         pw = NULL;
1126     }
1127
1128     if (!pw)
1129       pw = getpwuid(getuid());
1130
1131     if (pw)
1132       strlcpy(cc->user, pw->pw_name, sizeof(cc->user));
1133     else
1134 #endif /* WIN32 */
1135     {
1136      /*
1137       * Use the default "unknown" user name...
1138       */
1139
1140       strlcpy(cc->user, "unknown", sizeof(cc->user));
1141     }
1142   }
1143
1144   if (cc->validate_certs < 0)
1145     cc->validate_certs = 0;
1146 }
1147
1148
1149 /*
1150  * 'cups_init_client_conf()' - Initialize client.conf values.
1151  */
1152
1153 static void
1154 cups_init_client_conf(
1155     _cups_client_conf_t *cc)            /* I - client.conf values */
1156 {
1157  /*
1158   * Clear all values to "not set"...
1159   */
1160
1161   memset(cc, 0, sizeof(_cups_client_conf_t));
1162
1163   cc->encryption     = (http_encryption_t)-1;
1164   cc->trust_first    = -1;
1165   cc->any_root       = -1;
1166   cc->expired_certs  = -1;
1167   cc->validate_certs = -1;
1168
1169  /*
1170   * Load settings from the org.cups.PrintingPrefs plist (which trump
1171   * everything...)
1172   */
1173
1174 #ifdef __APPLE__
1175   char  sval[1024];                     /* String value */
1176   int   bval;                           /* Boolean value */
1177
1178   if (cups_apple_get_boolean(kAllowAnyRootKey, &bval))
1179     cc->any_root = bval;
1180
1181   if (cups_apple_get_boolean(kAllowExpiredCertsKey, &bval))
1182     cc->expired_certs = bval;
1183
1184   if (cups_apple_get_string(kEncryptionKey, sval, sizeof(sval)))
1185     cups_set_encryption(cc, sval);
1186
1187   if (cups_apple_get_string(kSSLOptionsKey, sval, sizeof(sval)))
1188     cups_set_ssl_options(cc, sval);
1189
1190   if (cups_apple_get_boolean(kTrustOnFirstUseKey, &bval))
1191     cc->trust_first = bval;
1192
1193   if (cups_apple_get_boolean(kValidateCertsKey, &bval))
1194     cc->validate_certs = bval;
1195 #endif /* __APPLE__ */
1196 }
1197
1198
1199 /*
1200  * 'cups_read_client_conf()' - Read a client.conf file.
1201  */
1202
1203 static void
1204 cups_read_client_conf(
1205     cups_file_t         *fp,            /* I - File to read */
1206     _cups_client_conf_t *cc)            /* I - client.conf values */
1207 {
1208   int   linenum;                        /* Current line number */
1209   char  line[1024],                     /* Line from file */
1210         *value;                         /* Pointer into line */
1211
1212
1213  /*
1214   * Read from the file...
1215   */
1216
1217   linenum = 0;
1218   while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
1219   {
1220     if (!_cups_strcasecmp(line, "Encryption") && value)
1221       cups_set_encryption(cc, value);
1222 #ifndef __APPLE__
1223    /*
1224     * The ServerName directive is not supported on macOS due to app
1225     * sandboxing restrictions, i.e. not all apps request network access.
1226     */
1227     else if (!_cups_strcasecmp(line, "ServerName") && value)
1228       cups_set_server_name(cc, value);
1229 #endif /* !__APPLE__ */
1230     else if (!_cups_strcasecmp(line, "User") && value)
1231       cups_set_user(cc, value);
1232     else if (!_cups_strcasecmp(line, "TrustOnFirstUse") && value)
1233       cc->trust_first = cups_boolean_value(value);
1234     else if (!_cups_strcasecmp(line, "AllowAnyRoot") && value)
1235       cc->any_root = cups_boolean_value(value);
1236     else if (!_cups_strcasecmp(line, "AllowExpiredCerts") &&
1237              value)
1238       cc->expired_certs = cups_boolean_value(value);
1239     else if (!_cups_strcasecmp(line, "ValidateCerts") && value)
1240       cc->validate_certs = cups_boolean_value(value);
1241 #ifdef HAVE_GSSAPI
1242     else if (!_cups_strcasecmp(line, "GSSServiceName") && value)
1243       cups_set_gss_service_name(cc, value);
1244 #endif /* HAVE_GSSAPI */
1245 #ifdef HAVE_SSL
1246     else if (!_cups_strcasecmp(line, "SSLOptions") && value)
1247       cups_set_ssl_options(cc, value);
1248 #endif /* HAVE_SSL */
1249   }
1250 }
1251
1252
1253 /*
1254  * 'cups_set_default_ipp_port()' - Set the default IPP port value.
1255  */
1256
1257 static void
1258 cups_set_default_ipp_port(
1259     _cups_globals_t *cg)                /* I - Global data */
1260 {
1261   const char    *ipp_port;              /* IPP_PORT environment variable */
1262
1263
1264   if ((ipp_port = getenv("IPP_PORT")) != NULL)
1265   {
1266     if ((cg->ipp_port = atoi(ipp_port)) <= 0)
1267       cg->ipp_port = CUPS_DEFAULT_IPP_PORT;
1268   }
1269   else
1270     cg->ipp_port = CUPS_DEFAULT_IPP_PORT;
1271 }
1272
1273 /*
1274  * 'cups_set_encryption()' - Set the Encryption value.
1275  */
1276
1277 static void
1278 cups_set_encryption(
1279     _cups_client_conf_t *cc,            /* I - client.conf values */
1280     const char          *value)         /* I - Value */
1281 {
1282   if (!_cups_strcasecmp(value, "never"))
1283     cc->encryption = HTTP_ENCRYPTION_NEVER;
1284   else if (!_cups_strcasecmp(value, "always"))
1285     cc->encryption = HTTP_ENCRYPTION_ALWAYS;
1286   else if (!_cups_strcasecmp(value, "required"))
1287     cc->encryption = HTTP_ENCRYPTION_REQUIRED;
1288   else
1289     cc->encryption = HTTP_ENCRYPTION_IF_REQUESTED;
1290 }
1291
1292
1293 /*
1294  * 'cups_set_gss_service_name()' - Set the GSSServiceName value.
1295  */
1296
1297 #ifdef HAVE_GSSAPI
1298 static void
1299 cups_set_gss_service_name(
1300     _cups_client_conf_t *cc,            /* I - client.conf values */
1301     const char          *value)         /* I - Value */
1302 {
1303   strlcpy(cc->gss_service_name, value, sizeof(cc->gss_service_name));
1304 }
1305 #endif /* HAVE_GSSAPI */
1306
1307
1308 /*
1309  * 'cups_set_server_name()' - Set the ServerName value.
1310  */
1311
1312 static void
1313 cups_set_server_name(
1314     _cups_client_conf_t *cc,            /* I - client.conf values */
1315     const char          *value)         /* I - Value */
1316 {
1317   strlcpy(cc->server_name, value, sizeof(cc->server_name));
1318 }
1319
1320
1321 /*
1322  * 'cups_set_ssl_options()' - Set the SSLOptions value.
1323  */
1324
1325 #ifdef HAVE_SSL
1326 static void
1327 cups_set_ssl_options(
1328     _cups_client_conf_t *cc,            /* I - client.conf values */
1329     const char          *value)         /* I - Value */
1330 {
1331  /*
1332   * SSLOptions [AllowRC4] [AllowSSL3] [AllowDH] [DenyTLS1.0] [None]
1333   */
1334
1335   int   options = _HTTP_TLS_NONE;       /* SSL/TLS options */
1336   char  temp[256],                      /* Copy of value */
1337         *start,                         /* Start of option */
1338         *end;                           /* End of option */
1339
1340
1341   strlcpy(temp, value, sizeof(temp));
1342
1343   for (start = temp; *start; start = end)
1344   {
1345    /*
1346     * Find end of keyword...
1347     */
1348
1349     end = start;
1350     while (*end && !_cups_isspace(*end))
1351       end ++;
1352
1353     if (*end)
1354       *end++ = '\0';
1355
1356    /*
1357     * Compare...
1358     */
1359
1360     if (!_cups_strcasecmp(start, "AllowRC4"))
1361       options |= _HTTP_TLS_ALLOW_RC4;
1362     else if (!_cups_strcasecmp(start, "AllowSSL3"))
1363       options |= _HTTP_TLS_ALLOW_SSL3;
1364     else if (!_cups_strcasecmp(start, "AllowDH"))
1365       options |= _HTTP_TLS_ALLOW_DH;
1366     else if (!_cups_strcasecmp(start, "DenyTLS1.0"))
1367       options |= _HTTP_TLS_DENY_TLS10;
1368     else if (!_cups_strcasecmp(start, "None"))
1369       options = _HTTP_TLS_NONE;
1370   }
1371
1372   cc->ssl_options = options;
1373
1374   DEBUG_printf(("4cups_set_ssl_options(cc=%p, value=\"%s\") options=%x", (void *)cc, value, options));
1375 }
1376 #endif /* HAVE_SSL */
1377
1378
1379 /*
1380  * 'cups_set_user()' - Set the User value.
1381  */
1382
1383 static void
1384 cups_set_user(
1385     _cups_client_conf_t *cc,            /* I - client.conf values */
1386     const char          *value)         /* I - Value */
1387 {
1388   strlcpy(cc->user, value, sizeof(cc->user));
1389 }