]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/usersys.c
Fixed builds when no SSL/TLS library is available, or when explicitly disabled
[thirdparty/cups.git] / cups / usersys.c
1 /*
2 * "$Id$"
3 *
4 * User, system, and password routines for CUPS.
5 *
6 * Copyright 2007-2014 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 functions...
43 */
44
45 static void cups_read_client_conf(cups_file_t *fp,
46 _cups_globals_t *cg,
47 const char *cups_encryption,
48 const char *cups_server,
49 const char *cups_user,
50 #ifdef HAVE_GSSAPI
51 const char *cups_gssservicename,
52 #endif /* HAVE_GSSAPI */
53 const char *cups_anyroot,
54 const char *cups_expiredcerts,
55 const char *cups_validatecerts,
56 int ssl_options);
57
58
59 /*
60 * 'cupsEncryption()' - Get the current encryption settings.
61 *
62 * The default encryption setting comes from the CUPS_ENCRYPTION
63 * environment variable, then the ~/.cups/client.conf file, and finally the
64 * /etc/cups/client.conf file. If not set, the default is
65 * @code HTTP_ENCRYPTION_IF_REQUESTED@.
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.
71 */
72
73 http_encryption_t /* O - Encryption settings */
74 cupsEncryption(void)
75 {
76 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
77
78
79 if (cg->encryption == (http_encryption_t)-1)
80 _cupsSetDefaults();
81
82 return (cg->encryption);
83 }
84
85
86 /*
87 * 'cupsGetPassword()' - Get a password from the user.
88 *
89 * Uses the current password callback function. Returns @code NULL@ if the
90 * user does not provide a password.
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.
96 */
97
98 const char * /* O - Password */
99 cupsGetPassword(const char *prompt) /* I - Prompt string */
100 {
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
110 * password callback.
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 * @since CUPS 1.4/OS X 10.6@
121 */
122
123 const char * /* O - Password */
124 cupsGetPassword2(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));
136 }
137
138
139 /*
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.
146 *
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.
154 */
155
156 const char * /* O - Server name */
157 cupsServer(void)
158 {
159 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
160
161
162 if (!cg->server[0])
163 _cupsSetDefaults();
164
165 return (cg->server);
166 }
167
168
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 *
178 * @since CUPS 1.5/OS X 10.7@
179 */
180
181 void
182 cupsSetClientCertCB(
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 *
202 * @since CUPS 1.5/OS X 10.7@
203 */
204
205 int /* O - Status of call (0 = success) */
206 cupsSetCredentials(
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
215 #ifdef HAVE_SSL
216 _httpFreeCredentials(cg->tls_credentials);
217 cg->tls_credentials = _httpCreateCredentials(credentials);
218 #endif /* HAVE_SSL */
219
220 return (cg->tls_credentials ? 0 : -1);
221 }
222
223
224 /*
225 * 'cupsSetEncryption()' - Set the encryption preference.
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
230 * @code HTTP_ENCRYPTION_IF_REQUESTED@.
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.
235 */
236
237 void
238 cupsSetEncryption(http_encryption_t e) /* I - New encryption preference */
239 {
240 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
241
242
243 cg->encryption = e;
244
245 if (cg->http)
246 httpEncryption(cg->http, e);
247 }
248
249
250 /*
251 * 'cupsSetPasswordCB()' - Set the password callback for CUPS.
252 *
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.
261 */
262
263 void
264 cupsSetPasswordCB(cups_password_cb_t cb)/* I - Callback function */
265 {
266 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
267
268
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 *
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.
289 *
290 * @since CUPS 1.4/OS X 10.6@
291 */
292
293 void
294 cupsSetPasswordCB2(
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;
303 else
304 cg->password_cb = cb;
305
306 cg->password_data = user_data;
307 }
308
309
310 /*
311 * 'cupsSetServer()' - Set the default server name and port.
312 *
313 * The "server" string can be a fully-qualified hostname, a numeric
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.
322 */
323
324 void
325 cupsSetServer(const char *server) /* I - Server name */
326 {
327 char *options, /* Options */
328 *port; /* Pointer to port */
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
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 }
351 else
352 cg->server_version = 20;
353
354 if (cg->server[0] != '/' && (port = strrchr(cg->server, ':')) != NULL &&
355 !strchr(port, ']') && isdigit(port[1] & 255))
356 {
357 *port++ = '\0';
358
359 cg->ipp_port = atoi(port);
360 }
361
362 if (cg->server[0] == '/')
363 strlcpy(cg->servername, "localhost", sizeof(cg->servername));
364 else
365 strlcpy(cg->servername, cg->server, sizeof(cg->servername));
366 }
367 else
368 {
369 cg->server[0] = '\0';
370 cg->servername[0] = '\0';
371 cg->server_version = 20;
372 }
373
374 if (cg->http)
375 {
376 httpClose(cg->http);
377 cg->http = NULL;
378 }
379 }
380
381
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 *
391 * @since CUPS 1.5/OS X 10.7@
392 */
393
394 void
395 cupsSetServerCertCB(
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
407 /*
408 * 'cupsSetUser()' - Set the default user name.
409 *
410 * Pass @code NULL@ to restore the default user name.
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.
415 */
416
417 void
418 cupsSetUser(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
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 *
436 * @since CUPS 1.7/OS X 10.9@
437 */
438
439 void
440 cupsSetUserAgent(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
486 /*
487 * 'cupsUser()' - Return the current user's name.
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.
493 */
494
495 const char * /* O - User name */
496 cupsUser(void)
497 {
498 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
499
500
501 if (!cg->user[0])
502 _cupsSetDefaults();
503
504 return (cg->user);
505 }
506
507
508 /*
509 * 'cupsUserAgent()' - Return the default HTTP User-Agent string.
510 *
511 * @since CUPS 1.7/OS X 10.9@
512 */
513
514 const char * /* O - User-Agent string */
515 cupsUserAgent(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
527 /*
528 * '_cupsGetPassword()' - Get a password from the user.
529 */
530
531 const char * /* O - Password or @code NULL@ if none */
532 _cupsGetPassword(const char *prompt) /* I - Prompt string */
533 {
534 #ifdef WIN32
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 */
540 DWORD passbytes; /* Bytes read */
541 _cups_globals_t *cg = _cupsGlobals();
542 /* Thread globals */
543
544
545 /*
546 * Disable input echo and set raw input...
547 */
548
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
573 while (ReadFile(tty, &passch, 1, &passbytes, NULL))
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 }
657
658 #else
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
670 /*
671 * Disable input echo and set raw input...
672 */
673
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;
684 noecho.c_lflag &= (tcflag_t)~(ICANON | ECHO | ECHOE | ISIG);
685
686 if (tcsetattr(tty, TCSAFLUSH, &noecho))
687 {
688 close(tty);
689 return (NULL);
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 {
709 if (passch == noecho.c_cc[VEOL] ||
710 # ifdef VEOL2
711 passch == noecho.c_cc[VEOL2] ||
712 # endif /* VEOL2 */
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 }
793 else
794 {
795 memset(cg->password, 0, sizeof(cg->password));
796 return (NULL);
797 }
798 #endif /* WIN32 */
799 }
800
801
802 #ifdef HAVE_GSSAPI
803 /*
804 * '_cupsGSSServiceName()' - Get the GSS (Kerberos) service name.
805 */
806
807 const 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
821 /*
822 * '_cupsSetDefaults()' - Set the default server, port, and encryption.
823 */
824
825 void
826 _cupsSetDefaults(void)
827 {
828 cups_file_t *fp; /* File */
829 const char *home, /* Home directory of user */
830 *cups_encryption, /* CUPS_ENCRYPTION env var */
831 *cups_server, /* CUPS_SERVER env var */
832 *cups_user, /* CUPS_USER/USER env var */
833 #ifdef HAVE_GSSAPI
834 *cups_gssservicename, /* CUPS_GSSSERVICENAME env var */
835 #endif /* HAVE_GSSAPI */
836 *cups_anyroot, /* CUPS_ANYROOT env var */
837 *cups_expiredcerts, /* CUPS_EXPIREDCERTS env var */
838 *cups_validatecerts; /* CUPS_VALIDATECERTS env var */
839 char filename[1024]; /* Filename */
840 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
841
842
843 DEBUG_puts("_cupsSetDefaults()");
844
845 /*
846 * First collect environment variables...
847 */
848
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");
855 cups_expiredcerts = getenv("CUPS_EXPIREDCERTS");
856 cups_user = getenv("CUPS_USER");
857 cups_validatecerts = getenv("CUPS_VALIDATECERTS");
858
859 /*
860 * Then, if needed, read the ~/.cups/client.conf or /etc/cups/client.conf
861 * files to get the default values...
862 */
863
864 if (cg->encryption == (http_encryption_t)-1 || !cg->server[0] ||
865 !cg->user[0] || !cg->ipp_port)
866 {
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
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
896 if ((home = getenv("HOME")) != NULL)
897 # endif /* HAVE_GETEUID */
898 {
899 /*
900 * Look for ~/.cups/client.conf...
901 */
902
903 snprintf(filename, sizeof(filename), "%s/.cups/client.conf", home);
904 fp = cupsFileOpen(filename, "r");
905
906 /*
907 * Read the configuration file and apply any environment variables; both
908 * functions handle NULL cups_file_t pointers...
909 */
910
911 cups_read_client_conf(fp, cg, cups_encryption, cups_server, cups_user,
912 #ifdef HAVE_GSSAPI
913 cups_gssservicename,
914 #endif /* HAVE_GSSAPI */
915 cups_anyroot, cups_expiredcerts, cups_validatecerts, 0);
916 cupsFileClose(fp);
917 }
918 }
919 }
920
921
922 /*
923 * 'cups_read_client_conf()' - Read a client.conf file.
924 */
925
926 static void
927 cups_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 */
931 const char *cups_server, /* I - CUPS_SERVER env var */
932 const char *cups_user, /* I - CUPS_USER env var */
933 #ifdef HAVE_GSSAPI
934 const char *cups_gssservicename,
935 /* I - CUPS_GSSSERVICENAME env var */
936 #endif /* HAVE_GSSAPI */
937 const char *cups_anyroot, /* I - CUPS_ANYROOT env var */
938 const char *cups_expiredcerts, /* I - CUPS_EXPIREDCERTS env var */
939 const char *cups_validatecerts,/* I - CUPS_VALIDATECERTS env var */
940 int ssl_options) /* I - Allow setting of SSLOptions? */
941 {
942 int linenum; /* Current line number */
943 char line[1024], /* Line from file */
944 *value, /* Pointer into line */
945 encryption[1024], /* Encryption value */
946 #ifndef __APPLE__
947 server_name[1024], /* ServerName value */
948 #endif /* !__APPLE__ */
949 user[256], /* User value */
950 any_root[1024], /* AllowAnyRoot value */
951 expired_certs[1024], /* AllowExpiredCerts value */
952 validate_certs[1024]; /* ValidateCerts value */
953 #ifdef HAVE_GSSAPI
954 char gss_service_name[32]; /* GSSServiceName value */
955 #endif /* HAVE_GSSAPI */
956
957
958 (void)ssl_options; /* Silence compiler warning */
959
960 /*
961 * Read from the file...
962 */
963
964 linenum = 0;
965 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
966 {
967 if (!cups_encryption && cg->encryption == (http_encryption_t)-1 &&
968 !_cups_strcasecmp(line, "Encryption") && value)
969 {
970 strlcpy(encryption, value, sizeof(encryption));
971 cups_encryption = encryption;
972 }
973 #ifndef __APPLE__
974 /*
975 * The Server directive is not supported on OS X due to app sandboxing
976 * restrictions, i.e. not all apps request network access.
977 */
978 else if (!cups_server && (!cg->server[0] || !cg->ipp_port) &&
979 !_cups_strcasecmp(line, "ServerName") && value)
980 {
981 strlcpy(server_name, value, sizeof(server_name));
982 cups_server = server_name;
983 }
984 #endif /* !__APPLE__ */
985 else if (!cups_user && !_cups_strcasecmp(line, "User") && value)
986 {
987 strlcpy(user, value, sizeof(user));
988 cups_user = user;
989 }
990 else if (!cups_anyroot && !_cups_strcasecmp(line, "AllowAnyRoot") && value)
991 {
992 strlcpy(any_root, value, sizeof(any_root));
993 cups_anyroot = any_root;
994 }
995 else if (!cups_expiredcerts && !_cups_strcasecmp(line, "AllowExpiredCerts") &&
996 value)
997 {
998 strlcpy(expired_certs, value, sizeof(expired_certs));
999 cups_expiredcerts = expired_certs;
1000 }
1001 else if (!cups_validatecerts && !_cups_strcasecmp(line, "ValidateCerts") && value)
1002 {
1003 strlcpy(validate_certs, value, sizeof(validate_certs));
1004 cups_validatecerts = validate_certs;
1005 }
1006 #ifdef HAVE_GSSAPI
1007 else if (!cups_gssservicename && !_cups_strcasecmp(line, "GSSServiceName") &&
1008 value)
1009 {
1010 strlcpy(gss_service_name, value, sizeof(gss_service_name));
1011 cups_gssservicename = gss_service_name;
1012 }
1013 #endif /* HAVE_GSSAPI */
1014 #ifdef HAVE_SSL
1015 else if (ssl_options && !_cups_strcasecmp(line, "SSLOptions") && value)
1016 {
1017 /*
1018 * SSLOptions [AllowRC4] [AllowSSL3] [None]
1019 */
1020
1021 int options = 0; /* SSL/TLS options */
1022 char *start, /* Start of option */
1023 *end; /* End of option */
1024
1025 for (start = value; *start; start = end)
1026 {
1027 /*
1028 * Find end of keyword...
1029 */
1030
1031 end = start;
1032 while (*end && !_cups_isspace(*end))
1033 end ++;
1034
1035 if (*end)
1036 *end++ = '\0';
1037
1038 /*
1039 * Compare...
1040 */
1041
1042 if (!_cups_strcasecmp(start, "AllowRC4"))
1043 options |= _HTTP_TLS_ALLOW_RC4;
1044 else if (!_cups_strcasecmp(start, "AllowSSL3"))
1045 options |= _HTTP_TLS_ALLOW_SSL3;
1046 else if (!_cups_strcasecmp(start, "None"))
1047 options = 0;
1048 }
1049
1050 _httpTLSSetOptions(options);
1051 }
1052 #endif /* HAVE_SSL */
1053 }
1054
1055 /*
1056 * Set values...
1057 */
1058
1059 if (cg->encryption == (http_encryption_t)-1 && cups_encryption)
1060 {
1061 if (!_cups_strcasecmp(cups_encryption, "never"))
1062 cg->encryption = HTTP_ENCRYPTION_NEVER;
1063 else if (!_cups_strcasecmp(cups_encryption, "always"))
1064 cg->encryption = HTTP_ENCRYPTION_ALWAYS;
1065 else if (!_cups_strcasecmp(cups_encryption, "required"))
1066 cg->encryption = HTTP_ENCRYPTION_REQUIRED;
1067 else
1068 cg->encryption = HTTP_ENCRYPTION_IF_REQUESTED;
1069 }
1070
1071 if ((!cg->server[0] || !cg->ipp_port) && cups_server)
1072 cupsSetServer(cups_server);
1073
1074 if (!cg->server[0])
1075 {
1076 #ifdef CUPS_DEFAULT_DOMAINSOCKET
1077 /*
1078 * If we are compiled with domain socket support, only use the
1079 * domain socket if it exists and has the right permissions...
1080 */
1081
1082 struct stat sockinfo; /* Domain socket information */
1083
1084 if (!stat(CUPS_DEFAULT_DOMAINSOCKET, &sockinfo) &&
1085 (sockinfo.st_mode & S_IRWXO) == S_IRWXO)
1086 cups_server = CUPS_DEFAULT_DOMAINSOCKET;
1087 else
1088 #endif /* CUPS_DEFAULT_DOMAINSOCKET */
1089 cups_server = "localhost";
1090
1091 cupsSetServer(cups_server);
1092 }
1093
1094 if (!cg->ipp_port)
1095 {
1096 const char *ipp_port; /* IPP_PORT environment variable */
1097
1098 if ((ipp_port = getenv("IPP_PORT")) != NULL)
1099 {
1100 if ((cg->ipp_port = atoi(ipp_port)) <= 0)
1101 cg->ipp_port = CUPS_DEFAULT_IPP_PORT;
1102 }
1103 else
1104 cg->ipp_port = CUPS_DEFAULT_IPP_PORT;
1105 }
1106
1107 if (!cg->user[0])
1108 {
1109 if (cups_user)
1110 strlcpy(cg->user, cups_user, sizeof(cg->user));
1111 else
1112 {
1113 #ifdef WIN32
1114 /*
1115 * Get the current user name from the OS...
1116 */
1117
1118 DWORD size; /* Size of string */
1119
1120 size = sizeof(cg->user);
1121 if (!GetUserName(cg->user, &size))
1122 #else
1123 /*
1124 * Try the USER environment variable as the default username...
1125 */
1126
1127 const char *envuser = getenv("USER");
1128 /* Default username */
1129 struct passwd *pw = NULL; /* Account information */
1130
1131 if (envuser)
1132 {
1133 /*
1134 * Validate USER matches the current UID, otherwise don't allow it to
1135 * override things... This makes sure that printing after doing su or
1136 * sudo records the correct username.
1137 */
1138
1139 if ((pw = getpwnam(envuser)) != NULL && pw->pw_uid != getuid())
1140 pw = NULL;
1141 }
1142
1143 if (!pw)
1144 pw = getpwuid(getuid());
1145
1146 if (pw)
1147 strlcpy(cg->user, pw->pw_name, sizeof(cg->user));
1148 else
1149 #endif /* WIN32 */
1150 {
1151 /*
1152 * Use the default "unknown" user name...
1153 */
1154
1155 strlcpy(cg->user, "unknown", sizeof(cg->user));
1156 }
1157 }
1158 }
1159
1160 #ifdef HAVE_GSSAPI
1161 if (!cups_gssservicename)
1162 cups_gssservicename = CUPS_DEFAULT_GSSSERVICENAME;
1163
1164 strlcpy(cg->gss_service_name, cups_gssservicename,
1165 sizeof(cg->gss_service_name));
1166 #endif /* HAVE_GSSAPI */
1167
1168 if (cups_anyroot)
1169 cg->any_root = !_cups_strcasecmp(cups_anyroot, "yes") ||
1170 !_cups_strcasecmp(cups_anyroot, "on") ||
1171 !_cups_strcasecmp(cups_anyroot, "true");
1172
1173 if (cups_expiredcerts)
1174 cg->expired_certs = !_cups_strcasecmp(cups_expiredcerts, "yes") ||
1175 !_cups_strcasecmp(cups_expiredcerts, "on") ||
1176 !_cups_strcasecmp(cups_expiredcerts, "true");
1177
1178 if (cups_validatecerts)
1179 cg->validate_certs = !_cups_strcasecmp(cups_validatecerts, "yes") ||
1180 !_cups_strcasecmp(cups_validatecerts, "on") ||
1181 !_cups_strcasecmp(cups_validatecerts, "true");
1182 }
1183
1184
1185 /*
1186 * End of "$Id$".
1187 */