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