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