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