]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/usersys.c
42294a9e8aaf893f2257007d038bb52556015eb8
[thirdparty/cups.git] / cups / usersys.c
1 /*
2 * "$Id$"
3 *
4 * User, system, and password routines for CUPS.
5 *
6 * Copyright 2007-2015 by Apple Inc.
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.
16 */
17
18 /*
19 * Include necessary headers...
20 */
21
22 #include "cups-private.h"
23 #include <stdlib.h>
24 #include <sys/stat.h>
25 #ifdef WIN32
26 # include <windows.h>
27 #else
28 # include <pwd.h>
29 # include <termios.h>
30 # include <sys/utsname.h>
31 #endif /* WIN32 */
32
33
34 /*
35 * Local constants...
36 */
37
38 #define _CUPS_PASSCHAR '*' /* Character that is echoed for password */
39
40
41 /*
42 * Local types...
43 */
44
45 typedef 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
64 /*
65 * Local functions...
66 */
67
68 static void cups_finalize_client_conf(_cups_client_conf_t *cc);
69 static void cups_init_client_conf(_cups_client_conf_t *cc);
70 static void cups_read_client_conf(cups_file_t *fp, _cups_client_conf_t *cc);
71 static void cups_set_encryption(_cups_client_conf_t *cc, const char *value);
72 #ifdef HAVE_GSSAPI
73 static void cups_set_gss_service_name(_cups_client_conf_t *cc, const char *value);
74 #endif /* HAVE_GSSAPI */
75 static void cups_set_server_name(_cups_client_conf_t *cc, const char *value);
76 #ifdef HAVE_SSL
77 static void cups_set_ssl_options(_cups_client_conf_t *cc, const char *value);
78 #endif /* HAVE_SSL */
79 static void cups_set_user(_cups_client_conf_t *cc, const char *value);
80
81
82 /*
83 * 'cupsEncryption()' - Get the current encryption settings.
84 *
85 * The default encryption setting comes from the CUPS_ENCRYPTION
86 * environment variable, then the ~/.cups/client.conf file, and finally the
87 * /etc/cups/client.conf file. If not set, the default is
88 * @code HTTP_ENCRYPTION_IF_REQUESTED@.
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.
94 */
95
96 http_encryption_t /* O - Encryption settings */
97 cupsEncryption(void)
98 {
99 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
100
101
102 if (cg->encryption == (http_encryption_t)-1)
103 _cupsSetDefaults();
104
105 return (cg->encryption);
106 }
107
108
109 /*
110 * 'cupsGetPassword()' - Get a password from the user.
111 *
112 * Uses the current password callback function. Returns @code NULL@ if the
113 * user does not provide a password.
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.
119 */
120
121 const char * /* O - Password */
122 cupsGetPassword(const char *prompt) /* I - Prompt string */
123 {
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
133 * password callback.
134 *
135 * Uses the current password callback function. Returns @code NULL@ if the
136 * user does not provide a password.
137 *
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 *
143 * @since CUPS 1.4/OS X 10.6@
144 */
145
146 const char * /* O - Password */
147 cupsGetPassword2(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));
159 }
160
161
162 /*
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.
169 *
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.
177 */
178
179 const char * /* O - Server name */
180 cupsServer(void)
181 {
182 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
183
184
185 if (!cg->server[0])
186 _cupsSetDefaults();
187
188 return (cg->server);
189 }
190
191
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 *
201 * @since CUPS 1.5/OS X 10.7@
202 */
203
204 void
205 cupsSetClientCertCB(
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 *
225 * @since CUPS 1.5/OS X 10.7@
226 */
227
228 int /* O - Status of call (0 = success) */
229 cupsSetCredentials(
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
238 #ifdef HAVE_SSL
239 _httpFreeCredentials(cg->tls_credentials);
240 cg->tls_credentials = _httpCreateCredentials(credentials);
241 #endif /* HAVE_SSL */
242
243 return (cg->tls_credentials ? 0 : -1);
244 }
245
246
247 /*
248 * 'cupsSetEncryption()' - Set the encryption preference.
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
253 * @code HTTP_ENCRYPTION_IF_REQUESTED@.
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.
258 */
259
260 void
261 cupsSetEncryption(http_encryption_t e) /* I - New encryption preference */
262 {
263 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
264
265
266 cg->encryption = e;
267
268 if (cg->http)
269 httpEncryption(cg->http, e);
270 }
271
272
273 /*
274 * 'cupsSetPasswordCB()' - Set the password callback for CUPS.
275 *
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.
284 */
285
286 void
287 cupsSetPasswordCB(cups_password_cb_t cb)/* I - Callback function */
288 {
289 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
290
291
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 *
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.
312 *
313 * @since CUPS 1.4/OS X 10.6@
314 */
315
316 void
317 cupsSetPasswordCB2(
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;
326 else
327 cg->password_cb = cb;
328
329 cg->password_data = user_data;
330 }
331
332
333 /*
334 * 'cupsSetServer()' - Set the default server name and port.
335 *
336 * The "server" string can be a fully-qualified hostname, a numeric
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.
345 */
346
347 void
348 cupsSetServer(const char *server) /* I - Server name */
349 {
350 char *options, /* Options */
351 *port; /* Pointer to port */
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
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 }
374 else
375 cg->server_version = 20;
376
377 if (cg->server[0] != '/' && (port = strrchr(cg->server, ':')) != NULL &&
378 !strchr(port, ']') && isdigit(port[1] & 255))
379 {
380 *port++ = '\0';
381
382 cg->ipp_port = atoi(port);
383 }
384
385 if (cg->server[0] == '/')
386 strlcpy(cg->servername, "localhost", sizeof(cg->servername));
387 else
388 strlcpy(cg->servername, cg->server, sizeof(cg->servername));
389 }
390 else
391 {
392 cg->server[0] = '\0';
393 cg->servername[0] = '\0';
394 cg->server_version = 20;
395 }
396
397 if (cg->http)
398 {
399 httpClose(cg->http);
400 cg->http = NULL;
401 }
402 }
403
404
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 *
414 * @since CUPS 1.5/OS X 10.7@
415 */
416
417 void
418 cupsSetServerCertCB(
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
430 /*
431 * 'cupsSetUser()' - Set the default user name.
432 *
433 * Pass @code NULL@ to restore the default user name.
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.
438 */
439
440 void
441 cupsSetUser(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
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 *
459 * @since CUPS 1.7/OS X 10.9@
460 */
461
462 void
463 cupsSetUserAgent(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
509 /*
510 * 'cupsUser()' - Return the current user's name.
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.
516 */
517
518 const char * /* O - User name */
519 cupsUser(void)
520 {
521 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
522
523
524 if (!cg->user[0])
525 _cupsSetDefaults();
526
527 return (cg->user);
528 }
529
530
531 /*
532 * 'cupsUserAgent()' - Return the default HTTP User-Agent string.
533 *
534 * @since CUPS 1.7/OS X 10.9@
535 */
536
537 const char * /* O - User-Agent string */
538 cupsUserAgent(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
550 /*
551 * '_cupsGetPassword()' - Get a password from the user.
552 */
553
554 const char * /* O - Password or @code NULL@ if none */
555 _cupsGetPassword(const char *prompt) /* I - Prompt string */
556 {
557 #ifdef WIN32
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 */
563 DWORD passbytes; /* Bytes read */
564 _cups_globals_t *cg = _cupsGlobals();
565 /* Thread globals */
566
567
568 /*
569 * Disable input echo and set raw input...
570 */
571
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
596 while (ReadFile(tty, &passch, 1, &passbytes, NULL))
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 }
680
681 #else
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
693 /*
694 * Disable input echo and set raw input...
695 */
696
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;
707 noecho.c_lflag &= (tcflag_t)~(ICANON | ECHO | ECHOE | ISIG);
708
709 if (tcsetattr(tty, TCSAFLUSH, &noecho))
710 {
711 close(tty);
712 return (NULL);
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 {
732 if (passch == noecho.c_cc[VEOL] ||
733 # ifdef VEOL2
734 passch == noecho.c_cc[VEOL2] ||
735 # endif /* VEOL2 */
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 }
816 else
817 {
818 memset(cg->password, 0, sizeof(cg->password));
819 return (NULL);
820 }
821 #endif /* WIN32 */
822 }
823
824
825 #ifdef HAVE_GSSAPI
826 /*
827 * '_cupsGSSServiceName()' - Get the GSS (Kerberos) service name.
828 */
829
830 const 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
844 /*
845 * '_cupsSetDefaults()' - Set the default server, port, and encryption.
846 */
847
848 void
849 _cupsSetDefaults(void)
850 {
851 cups_file_t *fp; /* File */
852 const char *home; /* Home directory of user */
853 char filename[1024]; /* Filename */
854 _cups_client_conf_t cc; /* client.conf values */
855 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
856
857
858 DEBUG_puts("_cupsSetDefaults()");
859
860 /*
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...
900 */
901
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
950 static int /* O - Boolean value */
951 cups_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
961 static void
962 cups_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
977 #ifdef HAVE_GSSAPI
978 if ((value = getenv("CUPS_GSSSERVICENAME")) != NULL)
979 cups_set_gss_service_name(cc, value);
980 #endif /* HAVE_GSSAPI */
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);
990
991 /*
992 * Then apply defaults for those values that haven't been set...
993 */
994
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])
1010 {
1011 #ifdef CUPS_DEFAULT_DOMAINSOCKET
1012 /*
1013 * If we are compiled with domain socket support, only use the
1014 * domain socket if it exists and has the right permissions...
1015 */
1016
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 }
1026
1027 if (!cc->user[0])
1028 {
1029 #ifdef WIN32
1030 /*
1031 * Get the current user name from the OS...
1032 */
1033
1034 DWORD size; /* Size of string */
1035
1036 size = sizeof(cc->user);
1037 if (!GetUserName(cc->user, &size))
1038 #else
1039 /*
1040 * Try the USER environment variable as the default username...
1041 */
1042
1043 const char *envuser = getenv("USER");
1044 /* Default username */
1045 struct passwd *pw = NULL; /* Account information */
1046
1047 if (envuser)
1048 {
1049 /*
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.
1053 */
1054
1055 if ((pw = getpwnam(envuser)) != NULL && pw->pw_uid != getuid())
1056 pw = NULL;
1057 }
1058
1059 if (!pw)
1060 pw = getpwuid(getuid());
1061
1062 if (pw)
1063 strlcpy(cc->user, pw->pw_name, sizeof(cc->user));
1064 else
1065 #endif /* WIN32 */
1066 {
1067 /*
1068 * Use the default "unknown" user name...
1069 */
1070
1071 strlcpy(cc->user, "unknown", sizeof(cc->user));
1072 }
1073 }
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
1084 static void
1085 cups_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;
1098 }
1099
1100
1101 /*
1102 * 'cups_read_client_conf()' - Read a client.conf file.
1103 */
1104
1105 static void
1106 cups_read_client_conf(
1107 cups_file_t *fp, /* I - File to read */
1108 _cups_client_conf_t *cc) /* I - client.conf values */
1109 {
1110 int linenum; /* Current line number */
1111 char line[1024], /* Line from file */
1112 *value; /* Pointer into line */
1113
1114
1115 /*
1116 * Read from the file...
1117 */
1118
1119 linenum = 0;
1120 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
1121 {
1122 if (!_cups_strcasecmp(line, "Encryption") && value)
1123 cups_set_encryption(cc, value);
1124 #ifndef __APPLE__
1125 /*
1126 * The ServerName directive is not supported on OS X due to app
1127 * sandboxing restrictions, i.e. not all apps request network access.
1128 */
1129 else if (!_cups_strcasecmp(line, "ServerName") && value)
1130 cups_set_server_name(cc, value);
1131 #endif /* !__APPLE__ */
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") &&
1137 value)
1138 cc->expired_certs = cups_boolean_value(value);
1139 else if (!_cups_strcasecmp(line, "ValidateCerts") && value)
1140 cc->validate_certs = cups_boolean_value(value);
1141 #ifdef HAVE_GSSAPI
1142 else if (!_cups_strcasecmp(line, "GSSServiceName") && value)
1143 cups_set_gss_service_name(cc, value);
1144 #endif /* HAVE_GSSAPI */
1145 #ifdef HAVE_SSL
1146 else if (!_cups_strcasecmp(line, "SSLOptions") && value)
1147 cups_set_ssl_options(cc, value);
1148 #endif /* HAVE_SSL */
1149 }
1150 }
1151
1152
1153 /*
1154 * 'cups_set_encryption()' - Set the Encryption value.
1155 */
1156
1157 static void
1158 cups_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 }
1171
1172
1173 /*
1174 * 'cups_set_gss_service_name()' - Set the GSSServiceName value.
1175 */
1176
1177 #ifdef HAVE_GSSAPI
1178 static void
1179 cups_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 */
1186
1187
1188 /*
1189 * 'cups_set_server_name()' - Set the ServerName value.
1190 */
1191
1192 static void
1193 cups_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 }
1199
1200
1201 /*
1202 * 'cups_set_ssl_options()' - Set the SSLOptions value.
1203 */
1204
1205 #ifdef HAVE_SSL
1206 static void
1207 cups_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] [AllowDH] [DenyTLS1.0] [None]
1213 */
1214
1215 int options = _HTTP_TLS_NONE; /* SSL/TLS options */
1216 char temp[256], /* Copy of value */
1217 *start, /* Start of option */
1218 *end; /* End of option */
1219
1220
1221 strlcpy(temp, value, sizeof(temp));
1222
1223 for (start = temp; *start; start = end)
1224 {
1225 /*
1226 * Find end of keyword...
1227 */
1228
1229 end = start;
1230 while (*end && !_cups_isspace(*end))
1231 end ++;
1232
1233 if (*end)
1234 *end++ = '\0';
1235
1236 /*
1237 * Compare...
1238 */
1239
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, "AllowDH"))
1245 options |= _HTTP_TLS_ALLOW_DH;
1246 else if (!_cups_strcasecmp(start, "DenyTLS1.0"))
1247 options |= _HTTP_TLS_DENY_TLS10;
1248 else if (!_cups_strcasecmp(start, "None"))
1249 options = _HTTP_TLS_NONE;
1250 }
1251
1252 cc->ssl_options = options;
1253 }
1254 #endif /* HAVE_SSL */
1255
1256
1257 /*
1258 * 'cups_set_user()' - Set the User value.
1259 */
1260
1261 static void
1262 cups_set_user(
1263 _cups_client_conf_t *cc, /* I - client.conf values */
1264 const char *value) /* I - Value */
1265 {
1266 strlcpy(cc->user, value, sizeof(cc->user));
1267 }
1268
1269
1270 /*
1271 * End of "$Id$".
1272 */