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