1 /* 2 * Administration utility API definitions for CUPS. 3 * 4 * Copyright 2007-2016 by Apple Inc. 5 * Copyright 2001-2007 by Easy Software Products. 6 * 7 * These coded instructions, statements, and computer programs are the 8 * property of Apple Inc. and are protected by Federal copyright 9 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 10 * which should have been included with this file. If this file is 11 * missing or damaged, see the license at "http://www.cups.org/". 12 * 13 * This file is subject to the Apple OS-Developed Software exception. 14 */ 15 16 /* 17 * Include necessary headers... 18 */ 19 20 #include "cups-private.h" 21 #include "ppd.h" 22 #include "adminutil.h" 23 #include <fcntl.h> 24 #include <sys/stat.h> 25 #ifdef WIN32 26 #else 27 # include <unistd.h> 28 # include <sys/wait.h> 29 #endif /* WIN32 */ 30 31 32 /* 33 * Local functions... 34 */ 35 36 static int do_samba_command(const char *command, 37 const char *address, 38 const char *subcommand, 39 const char *authfile, 40 FILE *logfile); 41 static http_status_t get_cupsd_conf(http_t *http, _cups_globals_t *cg, 42 time_t last_update, char *name, 43 size_t namelen, int *remote); 44 static void invalidate_cupsd_cache(_cups_globals_t *cg); 45 static void write_option(cups_file_t *dstfp, int order, 46 const char *name, const char *text, 47 const char *attrname, 48 ipp_attribute_t *suppattr, 49 ipp_attribute_t *defattr, int defval, 50 int valcount); 51 52 53 /* 54 * 'cupsAdminCreateWindowsPPD()' - Create the Windows PPD file for a printer. 55 * 56 * @deprecated@ 57 */ 58 59 char * /* O - PPD file or NULL */ 60 cupsAdminCreateWindowsPPD( 61 http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ 62 const char *dest, /* I - Printer or class */ 63 char *buffer, /* I - Filename buffer */ 64 int bufsize) /* I - Size of filename buffer */ 65 { 66 const char *src; /* Source PPD filename */ 67 cups_file_t *srcfp, /* Source PPD file */ 68 *dstfp; /* Destination PPD file */ 69 ipp_t *request, /* IPP request */ 70 *response; /* IPP response */ 71 ipp_attribute_t *suppattr, /* IPP -supported attribute */ 72 *defattr; /* IPP -default attribute */ 73 cups_lang_t *language; /* Current language */ 74 char line[256], /* Line from PPD file */ 75 junk[256], /* Extra junk to throw away */ 76 *ptr, /* Pointer into line */ 77 uri[1024], /* Printer URI */ 78 option[41], /* Option */ 79 choice[41]; /* Choice */ 80 int jcloption, /* In a JCL option? */ 81 jclorder, /* Next JCL order dependency */ 82 linenum; /* Current line number */ 83 time_t curtime; /* Current time */ 84 struct tm *curdate; /* Current date */ 85 static const char * const pattrs[] = /* Printer attributes we want */ 86 { 87 "job-hold-until-supported", 88 "job-hold-until-default", 89 "job-sheets-supported", 90 "job-sheets-default", 91 "job-priority-supported", 92 "job-priority-default" 93 }; 94 95 96 /* 97 * Range check the input... 98 */ 99 100 if (buffer) 101 *buffer = '\0'; 102 103 if (!http) 104 http = _cupsConnect(); 105 106 if (!http || !dest || !buffer || bufsize < 2) 107 return (NULL); 108 109 /* 110 * Get the PPD file... 111 */ 112 113 if ((src = cupsGetPPD2(http, dest)) == NULL) 114 return (NULL); 115 116 /* 117 * Get the supported banner pages, etc. for the printer... 118 */ 119 120 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); 121 122 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, 123 "localhost", 0, "/printers/%s", dest); 124 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, 125 "printer-uri", NULL, uri); 126 127 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 128 "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]), 129 NULL, pattrs); 130 131 /* 132 * Do the request and get back a response... 133 */ 134 135 response = cupsDoRequest(http, request, "/"); 136 if (!response || cupsLastError() > IPP_STATUS_OK_CONFLICTING) 137 { 138 unlink(src); 139 return (NULL); 140 } 141 142 /* 143 * Open the original PPD file... 144 */ 145 146 if ((srcfp = cupsFileOpen(src, "rb")) == NULL) 147 return (NULL); 148 149 /* 150 * Create a temporary output file using the destination buffer... 151 */ 152 153 if ((dstfp = cupsTempFile2(buffer, bufsize)) == NULL) 154 { 155 cupsFileClose(srcfp); 156 157 unlink(src); 158 159 return (NULL); 160 } 161 162 /* 163 * Write a new header explaining that this isn't the original PPD... 164 */ 165 166 cupsFilePuts(dstfp, "*PPD-Adobe: \"4.3\"\n"); 167 168 curtime = time(NULL); 169 curdate = gmtime(&curtime); 170 171 cupsFilePrintf(dstfp, "*%% Modified on %04d%02d%02d%02d%02d%02d+0000 " 172 "for CUPS Windows Driver\n", 173 curdate->tm_year + 1900, curdate->tm_mon + 1, curdate->tm_mday, 174 curdate->tm_hour, curdate->tm_min, curdate->tm_sec); 175 176 /* 177 * Read the existing PPD file, converting all PJL commands to CUPS 178 * job ticket comments... 179 */ 180 181 jcloption = 0; 182 jclorder = 0; 183 linenum = 0; 184 language = cupsLangDefault(); 185 186 while (cupsFileGets(srcfp, line, sizeof(line))) 187 { 188 linenum ++; 189 190 if (!strncmp(line, "*PPD-Adobe:", 11)) 191 { 192 /* 193 * Already wrote the PPD header... 194 */ 195 196 continue; 197 } 198 else if (!strncmp(line, "*JCLBegin:", 10) || 199 !strncmp(line, "*JCLToPSInterpreter:", 20) || 200 !strncmp(line, "*JCLEnd:", 8) || 201 !strncmp(line, "*Protocols:", 11)) 202 { 203 /* 204 * Don't use existing JCL keywords; we'll create our own, below... 205 */ 206 207 cupsFilePrintf(dstfp, "*%% Commented out for CUPS Windows Driver...\n" 208 "*%%%s\n", line + 1); 209 continue; 210 } 211 else if (!strncmp(line, "*JCLOpenUI", 10)) 212 { 213 jcloption = 1; 214 cupsFilePrintf(dstfp, "%s\n", line); 215 } 216 else if (!strncmp(line, "*JCLCloseUI", 11)) 217 { 218 jcloption = 0; 219 cupsFilePrintf(dstfp, "%s\n", line); 220 } 221 else if (jcloption && !strncmp(line, "*OrderDependency:", 17)) 222 { 223 for (ptr = line + 17; _cups_isspace(*ptr); ptr ++); 224 225 ptr = strchr(ptr, ' '); 226 227 if (ptr) 228 { 229 cupsFilePrintf(dstfp, "*OrderDependency: %d%s\n", jclorder, ptr); 230 jclorder ++; 231 } 232 else 233 cupsFilePrintf(dstfp, "%s\n", line); 234 } 235 else if (jcloption && 236 strncmp(line, "*End", 4) && 237 strncmp(line, "*Default", 8)) 238 { 239 if ((ptr = strchr(line, ':')) == NULL) 240 { 241 snprintf(line, sizeof(line), 242 _cupsLangString(language, _("Missing value on line %d.")), 243 linenum); 244 _cupsSetError(IPP_STATUS_ERROR_DOCUMENT_FORMAT_ERROR, line, 0); 245 246 cupsFileClose(srcfp); 247 cupsFileClose(dstfp); 248 249 unlink(src); 250 unlink(buffer); 251 252 *buffer = '\0'; 253 254 return (NULL); 255 } 256 257 if ((ptr = strchr(ptr, '\"')) == NULL) 258 { 259 snprintf(line, sizeof(line), 260 _cupsLangString(language, 261 _("Missing double quote on line %d.")), 262 linenum); 263 _cupsSetError(IPP_STATUS_ERROR_DOCUMENT_FORMAT_ERROR, line, 0); 264 265 cupsFileClose(srcfp); 266 cupsFileClose(dstfp); 267 268 unlink(src); 269 unlink(buffer); 270 271 *buffer = '\0'; 272 273 return (NULL); 274 } 275 276 if (sscanf(line, "*%40s%*[ \t]%40[^:/]", option, choice) != 2) 277 { 278 snprintf(line, sizeof(line), 279 _cupsLangString(language, 280 _("Bad option + choice on line %d.")), 281 linenum); 282 _cupsSetError(IPP_STATUS_ERROR_DOCUMENT_FORMAT_ERROR, line, 0); 283 284 cupsFileClose(srcfp); 285 cupsFileClose(dstfp); 286 287 unlink(src); 288 unlink(buffer); 289 290 *buffer = '\0'; 291 292 return (NULL); 293 } 294 295 if (strchr(ptr + 1, '\"') == NULL) 296 { 297 /* 298 * Skip remaining... 299 */ 300 301 while (cupsFileGets(srcfp, junk, sizeof(junk)) != NULL) 302 { 303 linenum ++; 304 305 if (!strncmp(junk, "*End", 4)) 306 break; 307 } 308 } 309 310 snprintf(ptr + 1, sizeof(line) - (size_t)(ptr - line + 1), 311 "%%cupsJobTicket: %s=%s\n\"\n*End", option, choice); 312 313 cupsFilePrintf(dstfp, "*%% Changed for CUPS Windows Driver...\n%s\n", 314 line); 315 } 316 else 317 cupsFilePrintf(dstfp, "%s\n", line); 318 } 319 320 cupsFileClose(srcfp); 321 unlink(src); 322 323 if (linenum == 0) 324 { 325 _cupsSetError(IPP_STATUS_ERROR_DOCUMENT_FORMAT_ERROR, _("Empty PPD file."), 1); 326 327 cupsFileClose(dstfp); 328 unlink(buffer); 329 330 *buffer = '\0'; 331 332 return (NULL); 333 } 334 335 /* 336 * Now add the CUPS-specific attributes and options... 337 */ 338 339 cupsFilePuts(dstfp, "\n*% CUPS Job Ticket support and options...\n"); 340 cupsFilePuts(dstfp, "*Protocols: PJL\n"); 341 cupsFilePuts(dstfp, "*JCLBegin: \"%!PS-Adobe-3.0<0A>\"\n"); 342 cupsFilePuts(dstfp, "*JCLToPSInterpreter: \"\"\n"); 343 cupsFilePuts(dstfp, "*JCLEnd: \"\"\n"); 344 345 cupsFilePuts(dstfp, "\n*OpenGroup: CUPS/CUPS Options\n\n"); 346 347 if ((defattr = ippFindAttribute(response, "job-hold-until-default", 348 IPP_TAG_ZERO)) != NULL && 349 (suppattr = ippFindAttribute(response, "job-hold-until-supported", 350 IPP_TAG_ZERO)) != NULL) 351 write_option(dstfp, jclorder ++, "cupsJobHoldUntil", "Hold Until", 352 "job-hold-until", suppattr, defattr, 0, 1); 353 354 if ((defattr = ippFindAttribute(response, "job-priority-default", 355 IPP_TAG_INTEGER)) != NULL && 356 (suppattr = ippFindAttribute(response, "job-priority-supported", 357 IPP_TAG_RANGE)) != NULL) 358 write_option(dstfp, jclorder ++, "cupsJobPriority", "Priority", 359 "job-priority", suppattr, defattr, 0, 1); 360 361 if ((defattr = ippFindAttribute(response, "job-sheets-default", 362 IPP_TAG_ZERO)) != NULL && 363 (suppattr = ippFindAttribute(response, "job-sheets-supported", 364 IPP_TAG_ZERO)) != NULL) 365 { 366 write_option(dstfp, jclorder ++, "cupsJobSheetsStart", "Start Banner", 367 "job-sheets", suppattr, defattr, 0, 2); 368 write_option(dstfp, jclorder, "cupsJobSheetsEnd", "End Banner", 369 "job-sheets", suppattr, defattr, 1, 2); 370 } 371 372 cupsFilePuts(dstfp, "*CloseGroup: CUPS\n"); 373 cupsFileClose(dstfp); 374 375 ippDelete(response); 376 377 return (buffer); 378 } 379 380 381 /* 382 * 'cupsAdminExportSamba()' - Export a printer to Samba. 383 * 384 * @deprecated@ 385 */ 386 387 int /* O - 1 on success, 0 on failure */ 388 cupsAdminExportSamba( 389 const char *dest, /* I - Destination to export */ 390 const char *ppd, /* I - PPD file */ 391 const char *samba_server, /* I - Samba server */ 392 const char *samba_user, /* I - Samba username */ 393 const char *samba_password, /* I - Samba password */ 394 FILE *logfile) /* I - Log file, if any */ 395 { 396 int status; /* Status of Samba commands */ 397 int have_drivers; /* Have drivers? */ 398 char file[1024], /* File to test for */ 399 authfile[1024], /* Temporary authentication file */ 400 address[1024], /* Address for command */ 401 subcmd[1024], /* Sub-command */ 402 message[1024]; /* Error message */ 403 cups_file_t *fp; /* Authentication file */ 404 cups_lang_t *language; /* Current language */ 405 _cups_globals_t *cg = _cupsGlobals(); 406 /* Global data */ 407 408 409 /* 410 * Range check input... 411 */ 412 413 if (!dest || !ppd || !samba_server || !samba_user || !samba_password) 414 { 415 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); 416 return (0); 417 } 418 419 /* 420 * Create a temporary authentication file for Samba... 421 */ 422 423 if ((fp = cupsTempFile2(authfile, sizeof(authfile))) == NULL) 424 { 425 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, NULL, 0); 426 return (0); 427 } 428 429 cupsFilePrintf(fp, "username = %s\n", samba_user); 430 cupsFilePrintf(fp, "password = %s\n", samba_password); 431 cupsFileClose(fp); 432 433 /* 434 * See which drivers are available; the new CUPS v6 and Adobe drivers 435 * depend on the Windows 2k PS driver, so copy that driver first: 436 * 437 * Files: 438 * 439 * ps5ui.dll 440 * pscript.hlp 441 * pscript.ntf 442 * pscript5.dll 443 */ 444 445 have_drivers = 0; 446 language = cupsLangDefault(); 447 448 snprintf(file, sizeof(file), "%s/drivers/pscript5.dll", cg->cups_datadir); 449 if (!access(file, 0)) 450 { 451 have_drivers |= 1; 452 453 /* 454 * Windows 2k driver is installed; do the smbclient commands needed 455 * to copy the Win2k drivers over... 456 */ 457 458 snprintf(address, sizeof(address), "//%s/print$", samba_server); 459 460 snprintf(subcmd, sizeof(subcmd), 461 "mkdir W32X86;" 462 "put %s W32X86/%s.ppd;" 463 "put %s/drivers/ps5ui.dll W32X86/ps5ui.dll;" 464 "put %s/drivers/pscript.hlp W32X86/pscript.hlp;" 465 "put %s/drivers/pscript.ntf W32X86/pscript.ntf;" 466 "put %s/drivers/pscript5.dll W32X86/pscript5.dll", 467 ppd, dest, cg->cups_datadir, cg->cups_datadir, 468 cg->cups_datadir, cg->cups_datadir); 469 470 if ((status = do_samba_command("smbclient", address, subcmd, 471 authfile, logfile)) != 0) 472 { 473 snprintf(message, sizeof(message), 474 _cupsLangString(language, 475 _("Unable to copy Windows 2000 printer " 476 "driver files (%d).")), status); 477 478 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0); 479 480 if (logfile) 481 _cupsLangPuts(logfile, message); 482 483 unlink(authfile); 484 485 return (0); 486 } 487 488 /* 489 * See if we also have the CUPS driver files; if so, use them! 490 */ 491 492 snprintf(file, sizeof(file), "%s/drivers/cupsps6.dll", cg->cups_datadir); 493 if (!access(file, 0)) 494 { 495 /* 496 * Copy the CUPS driver files over... 497 */ 498 499 snprintf(subcmd, sizeof(subcmd), 500 "put %s/drivers/cups6.ini W32X86/cups6.ini;" 501 "put %s/drivers/cupsps6.dll W32X86/cupsps6.dll;" 502 "put %s/drivers/cupsui6.dll W32X86/cupsui6.dll", 503 cg->cups_datadir, cg->cups_datadir, cg->cups_datadir); 504 505 if ((status = do_samba_command("smbclient", address, subcmd, 506 authfile, logfile)) != 0) 507 { 508 snprintf(message, sizeof(message), 509 _cupsLangString(language, 510 _("Unable to copy CUPS printer driver " 511 "files (%d).")), status); 512 513 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0); 514 515 if (logfile) 516 _cupsLangPuts(logfile, message); 517 518 unlink(authfile); 519 520 return (0); 521 } 522 523 /* 524 * Do the rpcclient command needed for the CUPS drivers... 525 */ 526 527 snprintf(subcmd, sizeof(subcmd), 528 "adddriver \"Windows NT x86\" \"%s:" 529 "pscript5.dll:%s.ppd:ps5ui.dll:pscript.hlp:NULL:RAW:" 530 "pscript5.dll,%s.ppd,ps5ui.dll,pscript.hlp,pscript.ntf," 531 "cups6.ini,cupsps6.dll,cupsui6.dll\"", 532 dest, dest, dest); 533 } 534 else 535 { 536 /* 537 * Don't have the CUPS drivers, so just use the standard Windows 538 * drivers... 539 */ 540 541 snprintf(subcmd, sizeof(subcmd), 542 "adddriver \"Windows NT x86\" \"%s:" 543 "pscript5.dll:%s.ppd:ps5ui.dll:pscript.hlp:NULL:RAW:" 544 "pscript5.dll,%s.ppd,ps5ui.dll,pscript.hlp,pscript.ntf\"", 545 dest, dest, dest); 546 } 547 548 if ((status = do_samba_command("rpcclient", samba_server, subcmd, 549 authfile, logfile)) != 0) 550 { 551 snprintf(message, sizeof(message), 552 _cupsLangString(language, 553 _("Unable to install Windows 2000 printer " 554 "driver files (%d).")), status); 555 556 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0); 557 558 if (logfile) 559 _cupsLangPuts(logfile, message); 560 561 unlink(authfile); 562 563 return (0); 564 } 565 } 566 567 /* 568 * See if we have the Win9x PS driver... 569 */ 570 571 snprintf(file, sizeof(file), "%s/drivers/ADOBEPS4.DRV", cg->cups_datadir); 572 if (!access(file, 0)) 573 { 574 have_drivers |= 2; 575 576 /* 577 * Do the smbclient commands needed for the Adobe Win9x drivers... 578 */ 579 580 snprintf(address, sizeof(address), "//%s/print$", samba_server); 581 582 snprintf(subcmd, sizeof(subcmd), 583 "mkdir WIN40;" 584 "put %s WIN40/%s.PPD;" 585 "put %s/drivers/ADFONTS.MFM WIN40/ADFONTS.MFM;" 586 "put %s/drivers/ADOBEPS4.DRV WIN40/ADOBEPS4.DRV;" 587 "put %s/drivers/ADOBEPS4.HLP WIN40/ADOBEPS4.HLP;" 588 "put %s/drivers/ICONLIB.DLL WIN40/ICONLIB.DLL;" 589 "put %s/drivers/PSMON.DLL WIN40/PSMON.DLL;", 590 ppd, dest, cg->cups_datadir, cg->cups_datadir, 591 cg->cups_datadir, cg->cups_datadir, cg->cups_datadir); 592 593 if ((status = do_samba_command("smbclient", address, subcmd, 594 authfile, logfile)) != 0) 595 { 596 snprintf(message, sizeof(message), 597 _cupsLangString(language, 598 _("Unable to copy Windows 9x printer " 599 "driver files (%d).")), status); 600 601 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0); 602 603 if (logfile) 604 _cupsLangPuts(logfile, message); 605 606 unlink(authfile); 607 608 return (0); 609 } 610 611 /* 612 * Do the rpcclient commands needed for the Adobe Win9x drivers... 613 */ 614 615 snprintf(subcmd, sizeof(subcmd), 616 "adddriver \"Windows 4.0\" \"%s:ADOBEPS4.DRV:%s.PPD:NULL:" 617 "ADOBEPS4.HLP:PSMON.DLL:RAW:" 618 "ADOBEPS4.DRV,%s.PPD,ADOBEPS4.HLP,PSMON.DLL,ADFONTS.MFM," 619 "ICONLIB.DLL\"", 620 dest, dest, dest); 621 622 if ((status = do_samba_command("rpcclient", samba_server, subcmd, 623 authfile, logfile)) != 0) 624 { 625 snprintf(message, sizeof(message), 626 _cupsLangString(language, 627 _("Unable to install Windows 9x printer " 628 "driver files (%d).")), status); 629 630 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0); 631 632 if (logfile) 633 _cupsLangPuts(logfile, message); 634 635 unlink(authfile); 636 637 return (0); 638 } 639 } 640 641 /* 642 * See if we have the 64-bit Windows PS driver... 643 * 644 * Files: 645 * 646 * x64/ps5ui.dll 647 * x64/pscript.hlp 648 * x64/pscript.ntf 649 * x64/pscript5.dll 650 */ 651 652 snprintf(file, sizeof(file), "%s/drivers/x64/pscript5.dll", cg->cups_datadir); 653 if (!access(file, 0)) 654 { 655 have_drivers |= 4; 656 657 /* 658 * 64-bit Windows driver is installed; do the smbclient commands needed 659 * to copy the Win64 drivers over... 660 */ 661 662 snprintf(address, sizeof(address), "//%s/print$", samba_server); 663 664 snprintf(subcmd, sizeof(subcmd), 665 "mkdir x64;" 666 "put %s x64/%s.ppd;" 667 "put %s/drivers/x64/ps5ui.dll x64/ps5ui.dll;" 668 "put %s/drivers/x64/pscript.hlp x64/pscript.hlp;" 669 "put %s/drivers/x64/pscript.ntf x64/pscript.ntf;" 670 "put %s/drivers/x64/pscript5.dll x64/pscript5.dll", 671 ppd, dest, cg->cups_datadir, cg->cups_datadir, 672 cg->cups_datadir, cg->cups_datadir); 673 674 if ((status = do_samba_command("smbclient", address, subcmd, 675 authfile, logfile)) != 0) 676 { 677 snprintf(message, sizeof(message), 678 _cupsLangString(language, 679 _("Unable to copy 64-bit Windows printer " 680 "driver files (%d).")), status); 681 682 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0); 683 684 if (logfile) 685 _cupsLangPuts(logfile, message); 686 687 unlink(authfile); 688 689 return (0); 690 } 691 692 /* 693 * See if we also have the CUPS driver files; if so, use them! 694 */ 695 696 snprintf(file, sizeof(file), "%s/drivers/x64/cupsps6.dll", cg->cups_datadir); 697 if (!access(file, 0)) 698 { 699 /* 700 * Copy the CUPS driver files over... 701 */ 702 703 snprintf(subcmd, sizeof(subcmd), 704 "put %s/drivers/x64/cups6.ini x64/cups6.ini;" 705 "put %s/drivers/x64/cupsps6.dll x64/cupsps6.dll;" 706 "put %s/drivers/x64/cupsui6.dll x64/cupsui6.dll", 707 cg->cups_datadir, cg->cups_datadir, cg->cups_datadir); 708 709 if ((status = do_samba_command("smbclient", address, subcmd, 710 authfile, logfile)) != 0) 711 { 712 snprintf(message, sizeof(message), 713 _cupsLangString(language, 714 _("Unable to copy 64-bit CUPS printer driver " 715 "files (%d).")), status); 716 717 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0); 718 719 if (logfile) 720 _cupsLangPuts(logfile, message); 721 722 unlink(authfile); 723 724 return (0); 725 } 726 727 /* 728 * Do the rpcclient command needed for the CUPS drivers... 729 */ 730 731 snprintf(subcmd, sizeof(subcmd), 732 "adddriver \"Windows x64\" \"%s:" 733 "pscript5.dll:%s.ppd:ps5ui.dll:pscript.hlp:NULL:RAW:" 734 "pscript5.dll,%s.ppd,ps5ui.dll,pscript.hlp,pscript.ntf," 735 "cups6.ini,cupsps6.dll,cupsui6.dll\"", 736 dest, dest, dest); 737 } 738 else 739 { 740 /* 741 * Don't have the CUPS drivers, so just use the standard Windows 742 * drivers... 743 */ 744 745 snprintf(subcmd, sizeof(subcmd), 746 "adddriver \"Windows x64\" \"%s:" 747 "pscript5.dll:%s.ppd:ps5ui.dll:pscript.hlp:NULL:RAW:" 748 "pscript5.dll,%s.ppd,ps5ui.dll,pscript.hlp,pscript.ntf\"", 749 dest, dest, dest); 750 } 751 752 if ((status = do_samba_command("rpcclient", samba_server, subcmd, 753 authfile, logfile)) != 0) 754 { 755 snprintf(message, sizeof(message), 756 _cupsLangString(language, 757 _("Unable to install Windows 2000 printer " 758 "driver files (%d).")), status); 759 760 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0); 761 762 if (logfile) 763 _cupsLangPuts(logfile, message); 764 765 unlink(authfile); 766 767 return (0); 768 } 769 } 770 771 if (logfile && !(have_drivers & 1)) 772 { 773 if (!have_drivers) 774 strlcpy(message, 775 _cupsLangString(language, 776 _("No Windows printer drivers are installed.")), 777 sizeof(message)); 778 else 779 strlcpy(message, 780 _cupsLangString(language, 781 _("Warning, no Windows 2000 printer drivers " 782 "are installed.")), 783 sizeof(message)); 784 785 _cupsSetError(IPP_STATUS_ERROR_NOT_FOUND, message, 0); 786 _cupsLangPuts(logfile, message); 787 } 788 789 if (have_drivers == 0) 790 { 791 _cupsSetError(IPP_STATUS_ERROR_NOT_FOUND, message, 0); 792 793 unlink(authfile); 794 795 return (0); 796 } 797 798 /* 799 * Finally, associate the drivers we just added with the queue... 800 */ 801 802 snprintf(subcmd, sizeof(subcmd), "setdriver %s %s", dest, dest); 803 804 if ((status = do_samba_command("rpcclient", samba_server, subcmd, 805 authfile, logfile)) != 0) 806 { 807 snprintf(message, sizeof(message), 808 _cupsLangString(language, 809 _("Unable to set Windows printer driver (%d).")), 810 status); 811 812 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0); 813 814 if (logfile) 815 _cupsLangPuts(logfile, message); 816 817 unlink(authfile); 818 819 return (0); 820 } 821 822 unlink(authfile); 823 824 return (1); 825 } 826 827 828 /* 829 * 'cupsAdminGetServerSettings()' - Get settings from the server. 830 * 831 * The returned settings should be freed with cupsFreeOptions() when 832 * you are done with them. 833 * 834 * @since CUPS 1.3/macOS 10.5@ 835 */ 836 837 int /* O - 1 on success, 0 on failure */ 838 cupsAdminGetServerSettings( 839 http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ 840 int *num_settings, /* O - Number of settings */ 841 cups_option_t **settings) /* O - Settings */ 842 { 843 int i; /* Looping var */ 844 cups_file_t *cupsd; /* cupsd.conf file */ 845 char cupsdconf[1024]; /* cupsd.conf filename */ 846 int remote; /* Remote cupsd.conf file? */ 847 http_status_t status; /* Status of getting cupsd.conf */ 848 char line[1024], /* Line from cupsd.conf file */ 849 *value; /* Value on line */ 850 cups_option_t *setting; /* Current setting */ 851 _cups_globals_t *cg = _cupsGlobals(); /* Global data */ 852 853 854 /* 855 * Range check input... 856 */ 857 858 if (!http) 859 { 860 /* 861 * See if we are connected to the same server... 862 */ 863 864 if (cg->http) 865 { 866 /* 867 * Compare the connection hostname, port, and encryption settings to 868 * the cached defaults; these were initialized the first time we 869 * connected... 870 */ 871 872 if (strcmp(cg->http->hostname, cg->server) || 873 cg->ipp_port != httpAddrPort(cg->http->hostaddr) || 874 (cg->http->encryption != cg->encryption && 875 cg->http->encryption == HTTP_ENCRYPTION_NEVER)) 876 { 877 /* 878 * Need to close the current connection because something has changed... 879 */ 880 881 httpClose(cg->http); 882 cg->http = NULL; 883 } 884 } 885 886 /* 887 * (Re)connect as needed... 888 */ 889 890 if (!cg->http) 891 { 892 if ((cg->http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, 893 cupsEncryption(), 1, 0, NULL)) == NULL) 894 { 895 if (errno) 896 _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, NULL, 0); 897 else 898 _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, 899 _("Unable to connect to host."), 1); 900 901 if (num_settings) 902 *num_settings = 0; 903 904 if (settings) 905 *settings = NULL; 906 907 return (0); 908 } 909 } 910 911 http = cg->http; 912 } 913 914 if (!http || !num_settings || !settings) 915 { 916 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); 917 918 if (num_settings) 919 *num_settings = 0; 920 921 if (settings) 922 *settings = NULL; 923 924 return (0); 925 } 926 927 *num_settings = 0; 928 *settings = NULL; 929 930 /* 931 * Get the cupsd.conf file... 932 */ 933 934 if ((status = get_cupsd_conf(http, cg, cg->cupsd_update, cupsdconf, 935 sizeof(cupsdconf), &remote)) == HTTP_STATUS_OK) 936 { 937 if ((cupsd = cupsFileOpen(cupsdconf, "r")) == NULL) 938 { 939 char message[1024]; /* Message string */ 940 941 942 snprintf(message, sizeof(message), 943 _cupsLangString(cupsLangDefault(), _("Open of %s failed: %s")), 944 cupsdconf, strerror(errno)); 945 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0); 946 } 947 } 948 else 949 cupsd = NULL; 950 951 if (cupsd) 952 { 953 /* 954 * Read the file, keeping track of what settings are enabled... 955 */ 956 957 int remote_access = 0, /* Remote access allowed? */ 958 remote_admin = 0, /* Remote administration allowed? */ 959 remote_any = 0, /* Remote access from anywhere allowed? */ 960 browsing = 1, /* Browsing enabled? */ 961 cancel_policy = 1, /* Cancel-job policy set? */ 962 debug_logging = 0; /* LogLevel debug set? */ 963 int linenum = 0, /* Line number in file */ 964 in_location = 0, /* In a location section? */ 965 in_policy = 0, /* In a policy section? */ 966 in_cancel_job = 0, /* In a cancel-job section? */ 967 in_admin_location = 0; /* In the /admin location? */ 968 969 970 invalidate_cupsd_cache(cg); 971 972 cg->cupsd_update = time(NULL); 973 httpGetHostname(http, cg->cupsd_hostname, sizeof(cg->cupsd_hostname)); 974 975 while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum)) 976 { 977 if (!value && strncmp(line, "</", 2)) 978 value = line + strlen(line); 979 980 if ((!_cups_strcasecmp(line, "Port") || !_cups_strcasecmp(line, "Listen")) && value) 981 { 982 char *port; /* Pointer to port number, if any */ 983 984 985 if ((port = strrchr(value, ':')) != NULL) 986 *port = '\0'; 987 else if (isdigit(*value & 255)) 988 { 989 /* 990 * Listen on a port number implies remote access... 991 */ 992 993 remote_access = 1; 994 continue; 995 } 996 997 if (_cups_strcasecmp(value, "localhost") && strcmp(value, "127.0.0.1") 998 #ifdef AF_LOCAL 999 && *value != '/' 1000 #endif /* AF_LOCAL */ 1001 #ifdef AF_INET6 1002 && strcmp(value, "[::1]") 1003 #endif /* AF_INET6 */ 1004 ) 1005 remote_access = 1; 1006 } 1007 else if (!_cups_strcasecmp(line, "Browsing")) 1008 { 1009 browsing = !_cups_strcasecmp(value, "yes") || 1010 !_cups_strcasecmp(value, "on") || 1011 !_cups_strcasecmp(value, "true"); 1012 } 1013 else if (!_cups_strcasecmp(line, "LogLevel")) 1014 { 1015 debug_logging = !_cups_strncasecmp(value, "debug", 5); 1016 } 1017 else if (!_cups_strcasecmp(line, "<Policy") && 1018 !_cups_strcasecmp(value, "default")) 1019 { 1020 in_policy = 1; 1021 } 1022 else if (!_cups_strcasecmp(line, "</Policy>")) 1023 { 1024 in_policy = 0; 1025 } 1026 else if (!_cups_strcasecmp(line, "<Limit") && in_policy && value) 1027 { 1028 /* 1029 * See if the policy limit is for the Cancel-Job operation... 1030 */ 1031 1032 char *valptr; /* Pointer into value */ 1033 1034 1035 while (*value) 1036 { 1037 for (valptr = value; *valptr && !_cups_isspace(*valptr); valptr ++); 1038 1039 if (*valptr) 1040 *valptr++ = '\0'; 1041 1042 if (!_cups_strcasecmp(value, "cancel-job") || 1043 !_cups_strcasecmp(value, "all")) 1044 { 1045 in_cancel_job = 1; 1046 break; 1047 } 1048 1049 for (value = valptr; _cups_isspace(*value); value ++); 1050 } 1051 } 1052 else if (!_cups_strcasecmp(line, "</Limit>")) 1053 { 1054 in_cancel_job = 0; 1055 } 1056 else if (!_cups_strcasecmp(line, "Require") && in_cancel_job) 1057 { 1058 cancel_policy = 0; 1059 } 1060 else if (!_cups_strcasecmp(line, "<Location") && value) 1061 { 1062 in_admin_location = !_cups_strcasecmp(value, "/admin"); 1063 in_location = 1; 1064 } 1065 else if (!_cups_strcasecmp(line, "</Location>")) 1066 { 1067 in_admin_location = 0; 1068 in_location = 0; 1069 } 1070 else if (!_cups_strcasecmp(line, "Allow") && value && 1071 _cups_strcasecmp(value, "localhost") && 1072 _cups_strcasecmp(value, "127.0.0.1") 1073 #ifdef AF_LOCAL 1074 && *value != '/' 1075 #endif /* AF_LOCAL */ 1076 #ifdef AF_INET6 1077 && strcmp(value, "::1") 1078 #endif /* AF_INET6 */ 1079 ) 1080 { 1081 if (in_admin_location) 1082 remote_admin = 1; 1083 else if (!_cups_strcasecmp(value, "all")) 1084 remote_any = 1; 1085 } 1086 else if (line[0] != '<' && !in_location && !in_policy && 1087 _cups_strcasecmp(line, "Allow") && 1088 _cups_strcasecmp(line, "AuthType") && 1089 _cups_strcasecmp(line, "Deny") && 1090 _cups_strcasecmp(line, "Order") && 1091 _cups_strcasecmp(line, "Require") && 1092 _cups_strcasecmp(line, "Satisfy")) 1093 cg->cupsd_num_settings = cupsAddOption(line, value, 1094 cg->cupsd_num_settings, 1095 &(cg->cupsd_settings)); 1096 } 1097 1098 cupsFileClose(cupsd); 1099 1100 cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING, 1101 debug_logging ? "1" : "0", 1102 cg->cupsd_num_settings, 1103 &(cg->cupsd_settings)); 1104 1105 cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN, 1106 (remote_access && remote_admin) ? 1107 "1" : "0", 1108 cg->cupsd_num_settings, 1109 &(cg->cupsd_settings)); 1110 1111 cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY, 1112 remote_any ? "1" : "0", 1113 cg->cupsd_num_settings, 1114 &(cg->cupsd_settings)); 1115 1116 cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS, 1117 (remote_access && browsing) ? "1" : 1118 "0", 1119 cg->cupsd_num_settings, 1120 &(cg->cupsd_settings)); 1121 1122 cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY, 1123 cancel_policy ? "1" : "0", 1124 cg->cupsd_num_settings, 1125 &(cg->cupsd_settings)); 1126 } 1127 else if (status != HTTP_STATUS_NOT_MODIFIED) 1128 invalidate_cupsd_cache(cg); 1129 1130 /* 1131 * Remove any temporary files and copy the settings array... 1132 */ 1133 1134 if (remote) 1135 unlink(cupsdconf); 1136 1137 for (i = cg->cupsd_num_settings, setting = cg->cupsd_settings; 1138 i > 0; 1139 i --, setting ++) 1140 *num_settings = cupsAddOption(setting->name, setting->value, 1141 *num_settings, settings); 1142 1143 return (cg->cupsd_num_settings > 0); 1144 } 1145 1146 1147 /* 1148 * 'cupsAdminSetServerSettings()' - Set settings on the server. 1149 * 1150 * @since CUPS 1.3/macOS 10.5@ 1151 */ 1152 1153 int /* O - 1 on success, 0 on failure */ 1154 cupsAdminSetServerSettings( 1155 http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ 1156 int num_settings, /* I - Number of settings */ 1157 cups_option_t *settings) /* I - Settings */ 1158 { 1159 int i; /* Looping var */ 1160 http_status_t status; /* GET/PUT status */ 1161 const char *server_port_env; /* SERVER_PORT env var */ 1162 int server_port; /* IPP port for server */ 1163 cups_file_t *cupsd; /* cupsd.conf file */ 1164 char cupsdconf[1024]; /* cupsd.conf filename */ 1165 int remote; /* Remote cupsd.conf file? */ 1166 char tempfile[1024]; /* Temporary new cupsd.conf */ 1167 cups_file_t *temp; /* Temporary file */ 1168 char line[1024], /* Line from cupsd.conf file */ 1169 *value; /* Value on line */ 1170 int linenum, /* Line number in file */ 1171 in_location, /* In a location section? */ 1172 in_policy, /* In a policy section? */ 1173 in_default_policy, /* In the default policy section? */ 1174 in_cancel_job, /* In a cancel-job section? */ 1175 in_admin_location, /* In the /admin location? */ 1176 in_conf_location, /* In the /admin/conf location? */ 1177 in_log_location, /* In the /admin/log location? */ 1178 in_root_location; /* In the / location? */ 1179 const char *val; /* Setting value */ 1180 int share_printers, /* Share local printers */ 1181 remote_admin, /* Remote administration allowed? */ 1182 remote_any, /* Remote access from anywhere? */ 1183 user_cancel_any, /* Cancel-job policy set? */ 1184 debug_logging; /* LogLevel debug set? */ 1185 int wrote_port_listen, /* Wrote the port/listen lines? */ 1186 wrote_browsing, /* Wrote the browsing lines? */ 1187 wrote_policy, /* Wrote the policy? */ 1188 wrote_loglevel, /* Wrote the LogLevel line? */ 1189 wrote_admin_location, /* Wrote the /admin location? */ 1190 wrote_conf_location, /* Wrote the /admin/conf location? */ 1191 wrote_log_location, /* Wrote the /admin/log location? */ 1192 wrote_root_location; /* Wrote the / location? */ 1193 int indent; /* Indentation */ 1194 int cupsd_num_settings; /* New number of settings */ 1195 int old_share_printers, /* Share local printers */ 1196 old_remote_admin, /* Remote administration allowed? */ 1197 old_remote_any, /* Remote access from anywhere? */ 1198 old_user_cancel_any, /* Cancel-job policy set? */ 1199 old_debug_logging; /* LogLevel debug set? */ 1200 cups_option_t *cupsd_settings, /* New settings */ 1201 *setting; /* Current setting */ 1202 _cups_globals_t *cg = _cupsGlobals(); /* Global data */ 1203 1204 1205 /* 1206 * Range check input... 1207 */ 1208 1209 if (!http) 1210 http = _cupsConnect(); 1211 1212 if (!http || !num_settings || !settings) 1213 { 1214 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); 1215 1216 return (0); 1217 } 1218 1219 /* 1220 * Get the cupsd.conf file... 1221 */ 1222 1223 if (get_cupsd_conf(http, cg, 0, cupsdconf, sizeof(cupsdconf), 1224 &remote) == HTTP_STATUS_OK) 1225 { 1226 if ((cupsd = cupsFileOpen(cupsdconf, "r")) == NULL) 1227 { 1228 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, NULL, 0); 1229 return (0); 1230 } 1231 } 1232 else 1233 return (0); 1234 1235 /* 1236 * Get current settings... 1237 */ 1238 1239 if (!cupsAdminGetServerSettings(http, &cupsd_num_settings, 1240 &cupsd_settings)) 1241 return (0); 1242 1243 if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, cupsd_num_settings, 1244 cupsd_settings)) != NULL) 1245 old_debug_logging = atoi(val); 1246 else 1247 old_debug_logging = 0; 1248 1249 DEBUG_printf(("1cupsAdminSetServerSettings: old debug_logging=%d", 1250 old_debug_logging)); 1251 1252 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, cupsd_num_settings, 1253 cupsd_settings)) != NULL) 1254 old_remote_admin = atoi(val); 1255 else 1256 old_remote_admin = 0; 1257 1258 DEBUG_printf(("1cupsAdminSetServerSettings: old remote_admin=%d", 1259 old_remote_admin)); 1260 1261 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, cupsd_num_settings, 1262 cupsd_settings)) != NULL) 1263 old_remote_any = atoi(val); 1264 else 1265 old_remote_any = 0; 1266 1267 DEBUG_printf(("1cupsAdminSetServerSettings: old remote_any=%d", 1268 old_remote_any)); 1269 1270 if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, cupsd_num_settings, 1271 cupsd_settings)) != NULL) 1272 old_share_printers = atoi(val); 1273 else 1274 old_share_printers = 0; 1275 1276 DEBUG_printf(("1cupsAdminSetServerSettings: old share_printers=%d", 1277 old_share_printers)); 1278 1279 if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, cupsd_num_settings, 1280 cupsd_settings)) != NULL) 1281 old_user_cancel_any = atoi(val); 1282 else 1283 old_user_cancel_any = 0; 1284 1285 DEBUG_printf(("1cupsAdminSetServerSettings: old user_cancel_any=%d", 1286 old_user_cancel_any)); 1287 1288 cupsFreeOptions(cupsd_num_settings, cupsd_settings); 1289 1290 /* 1291 * Get basic settings... 1292 */ 1293 1294 if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings, 1295 settings)) != NULL) 1296 { 1297 debug_logging = atoi(val); 1298 1299 if (debug_logging == old_debug_logging) 1300 { 1301 /* 1302 * No change to this setting... 1303 */ 1304 1305 debug_logging = -1; 1306 } 1307 } 1308 else 1309 debug_logging = -1; 1310 1311 DEBUG_printf(("1cupsAdminSetServerSettings: debug_logging=%d", 1312 debug_logging)); 1313 1314 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings, settings)) != NULL) 1315 { 1316 remote_any = atoi(val); 1317 1318 if (remote_any == old_remote_any) 1319 { 1320 /* 1321 * No change to this setting... 1322 */ 1323 1324 remote_any = -1; 1325 } 1326 } 1327 else 1328 remote_any = -1; 1329 1330 DEBUG_printf(("1cupsAdminSetServerSettings: remote_any=%d", remote_any)); 1331 1332 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings, 1333 settings)) != NULL) 1334 { 1335 remote_admin = atoi(val); 1336 1337 if (remote_admin == old_remote_admin) 1338 { 1339 /* 1340 * No change to this setting... 1341 */ 1342 1343 remote_admin = -1; 1344 } 1345 } 1346 else 1347 remote_admin = -1; 1348 1349 DEBUG_printf(("1cupsAdminSetServerSettings: remote_admin=%d", 1350 remote_admin)); 1351 1352 if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings, 1353 settings)) != NULL) 1354 { 1355 share_printers = atoi(val); 1356 1357 if (share_printers == old_share_printers) 1358 { 1359 /* 1360 * No change to this setting... 1361 */ 1362 1363 share_printers = -1; 1364 } 1365 } 1366 else 1367 share_printers = -1; 1368 1369 DEBUG_printf(("1cupsAdminSetServerSettings: share_printers=%d", 1370 share_printers)); 1371 1372 if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings, 1373 settings)) != NULL) 1374 { 1375 user_cancel_any = atoi(val); 1376 1377 if (user_cancel_any == old_user_cancel_any) 1378 { 1379 /* 1380 * No change to this setting... 1381 */ 1382 1383 user_cancel_any = -1; 1384 } 1385 } 1386 else 1387 user_cancel_any = -1; 1388 1389 DEBUG_printf(("1cupsAdminSetServerSettings: user_cancel_any=%d", 1390 user_cancel_any)); 1391 1392 /* 1393 * Create a temporary file for the new cupsd.conf file... 1394 */ 1395 1396 if ((temp = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL) 1397 { 1398 cupsFileClose(cupsd); 1399 1400 if (remote) 1401 unlink(cupsdconf); 1402 1403 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, NULL, 0); 1404 return (0); 1405 } 1406 1407 /* 1408 * Copy the old file to the new, making changes along the way... 1409 */ 1410 1411 cupsd_num_settings = 0; 1412 in_admin_location = 0; 1413 in_cancel_job = 0; 1414 in_conf_location = 0; 1415 in_default_policy = 0; 1416 in_location = 0; 1417 in_log_location = 0; 1418 in_policy = 0; 1419 in_root_location = 0; 1420 linenum = 0; 1421 wrote_admin_location = 0; 1422 wrote_browsing = 0; 1423 wrote_conf_location = 0; 1424 wrote_log_location = 0; 1425 wrote_loglevel = 0; 1426 wrote_policy = 0; 1427 wrote_port_listen = 0; 1428 wrote_root_location = 0; 1429 indent = 0; 1430 1431 if ((server_port_env = getenv("SERVER_PORT")) != NULL) 1432 { 1433 if ((server_port = atoi(server_port_env)) <= 0) 1434 server_port = ippPort(); 1435 } 1436 else 1437 server_port = ippPort(); 1438 1439 if (server_port <= 0) 1440 server_port = IPP_PORT; 1441 1442 while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum)) 1443 { 1444 if ((!_cups_strcasecmp(line, "Port") || !_cups_strcasecmp(line, "Listen")) && 1445 (remote_admin >= 0 || remote_any >= 0 || share_printers >= 0)) 1446 { 1447 if (!wrote_port_listen) 1448 { 1449 wrote_port_listen = 1; 1450 1451 if (remote_admin > 0 || remote_any > 0 || share_printers > 0) 1452 { 1453 cupsFilePuts(temp, "# Allow remote access\n"); 1454 cupsFilePrintf(temp, "Port %d\n", server_port); 1455 } 1456 else 1457 { 1458 cupsFilePuts(temp, "# Only listen for connections from the local " 1459 "machine.\n"); 1460 cupsFilePrintf(temp, "Listen localhost:%d\n", server_port); 1461 } 1462 1463 #ifdef CUPS_DEFAULT_DOMAINSOCKET 1464 if ((!value || strcmp(CUPS_DEFAULT_DOMAINSOCKET, value)) && 1465 !access(CUPS_DEFAULT_DOMAINSOCKET, 0)) 1466 cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n"); 1467 #endif /* CUPS_DEFAULT_DOMAINSOCKET */ 1468 } 1469 else if (value && value[0] == '/' 1470 #ifdef CUPS_DEFAULT_DOMAINSOCKET 1471 && strcmp(CUPS_DEFAULT_DOMAINSOCKET, value) 1472 #endif /* CUPS_DEFAULT_DOMAINSOCKET */ 1473 ) 1474 cupsFilePrintf(temp, "Listen %s\n", value); 1475 } 1476 else if ((!_cups_strcasecmp(line, "Browsing") || 1477 !_cups_strcasecmp(line, "BrowseLocalProtocols")) && 1478 share_printers >= 0) 1479 { 1480 if (!wrote_browsing) 1481 { 1482 int new_share_printers = (share_printers > 0 || 1483 (share_printers == -1 && 1484 old_share_printers > 0)); 1485 1486 wrote_browsing = 1; 1487 1488 if (new_share_printers) 1489 { 1490 const char *localp = cupsGetOption("BrowseLocalProtocols", 1491 num_settings, settings); 1492 1493 if (!localp || !localp[0]) 1494 localp = cupsGetOption("BrowseLocalProtocols", cupsd_num_settings, 1495 cupsd_settings); 1496 1497 cupsFilePuts(temp, "# Share local printers on the local network.\n"); 1498 cupsFilePuts(temp, "Browsing On\n"); 1499 1500 if (!localp) 1501 localp = CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS; 1502 1503 cupsFilePrintf(temp, "BrowseLocalProtocols %s\n", localp); 1504 1505 cupsd_num_settings = cupsAddOption("BrowseLocalProtocols", localp, 1506 cupsd_num_settings, 1507 &cupsd_settings); 1508 } 1509 else 1510 { 1511 cupsFilePuts(temp, "# Disable printer sharing.\n"); 1512 cupsFilePuts(temp, "Browsing Off\n"); 1513 } 1514 } 1515 } 1516 else if (!_cups_strcasecmp(line, "LogLevel") && debug_logging >= 0) 1517 { 1518 wrote_loglevel = 1; 1519 1520 if (debug_logging) 1521 { 1522 cupsFilePuts(temp, 1523 "# Show troubleshooting information in error_log.\n"); 1524 cupsFilePuts(temp, "LogLevel debug\n"); 1525 } 1526 else 1527 { 1528 cupsFilePuts(temp, "# Show general information in error_log.\n"); 1529 cupsFilePuts(temp, "LogLevel " CUPS_DEFAULT_LOG_LEVEL "\n"); 1530 } 1531 } 1532 else if (!_cups_strcasecmp(line, "<Policy")) 1533 { 1534 in_default_policy = !_cups_strcasecmp(value, "default"); 1535 in_policy = 1; 1536 1537 cupsFilePrintf(temp, "%s %s>\n", line, value); 1538 indent += 2; 1539 } 1540 else if (!_cups_strcasecmp(line, "</Policy>")) 1541 { 1542 indent -= 2; 1543 if (!wrote_policy && in_default_policy) 1544 { 1545 wrote_policy = 1; 1546 1547 if (!user_cancel_any) 1548 cupsFilePuts(temp, " # Only the owner or an administrator can " 1549 "cancel a job...\n" 1550 " <Limit Cancel-Job>\n" 1551 " Order deny,allow\n" 1552 " Require user @OWNER " 1553 CUPS_DEFAULT_PRINTOPERATOR_AUTH "\n" 1554 " </Limit>\n"); 1555 } 1556 1557 in_policy = 0; 1558 in_default_policy = 0; 1559 1560 cupsFilePuts(temp, "</Policy>\n"); 1561 } 1562 else if (!_cups_strcasecmp(line, "<Location")) 1563 { 1564 in_location = 1; 1565 indent += 2; 1566 if (!strcmp(value, "/admin")) 1567 in_admin_location = 1; 1568 else if (!strcmp(value, "/admin/conf")) 1569 in_conf_location = 1; 1570 else if (!strcmp(value, "/admin/log")) 1571 in_log_location = 1; 1572 else if (!strcmp(value, "/")) 1573 in_root_location = 1; 1574 1575 cupsFilePrintf(temp, "%s %s>\n", line, value); 1576 } 1577 else if (!_cups_strcasecmp(line, "</Location>")) 1578 { 1579 in_location = 0; 1580 indent -= 2; 1581 if (in_admin_location && remote_admin >= 0) 1582 { 1583 wrote_admin_location = 1; 1584 1585 if (remote_admin) 1586 cupsFilePuts(temp, " # Allow remote administration...\n"); 1587 else if (remote_admin == 0) 1588 cupsFilePuts(temp, " # Restrict access to the admin pages...\n"); 1589 1590 cupsFilePuts(temp, " Order allow,deny\n"); 1591 1592 if (remote_admin) 1593 cupsFilePrintf(temp, " Allow %s\n", 1594 remote_any > 0 ? "all" : "@LOCAL"); 1595 } 1596 else if (in_conf_location && remote_admin >= 0) 1597 { 1598 wrote_conf_location = 1; 1599 1600 if (remote_admin) 1601 cupsFilePuts(temp, " # Allow remote access to the configuration " 1602 "files...\n"); 1603 else 1604 cupsFilePuts(temp, " # Restrict access to the configuration " 1605 "files...\n"); 1606 1607 cupsFilePuts(temp, " Order allow,deny\n"); 1608 1609 if (remote_admin) 1610 cupsFilePrintf(temp, " Allow %s\n", 1611 remote_any > 0 ? "all" : "@LOCAL"); 1612 } 1613 else if (in_log_location && remote_admin >= 0) 1614 { 1615 wrote_log_location = 1; 1616 1617 if (remote_admin) 1618 cupsFilePuts(temp, " # Allow remote access to the log " 1619 "files...\n"); 1620 else 1621 cupsFilePuts(temp, " # Restrict access to the log " 1622 "files...\n"); 1623 1624 cupsFilePuts(temp, " Order allow,deny\n"); 1625 1626 if (remote_admin) 1627 cupsFilePrintf(temp, " Allow %s\n", 1628 remote_any > 0 ? "all" : "@LOCAL"); 1629 } 1630 else if (in_root_location && 1631 (remote_admin >= 0 || remote_any >= 0 || share_printers >= 0)) 1632 { 1633 wrote_root_location = 1; 1634 1635 if (remote_admin > 0 && share_printers > 0) 1636 cupsFilePuts(temp, " # Allow shared printing and remote " 1637 "administration...\n"); 1638 else if (remote_admin > 0) 1639 cupsFilePuts(temp, " # Allow remote administration...\n"); 1640 else if (share_printers > 0) 1641 cupsFilePuts(temp, " # Allow shared printing...\n"); 1642 else if (remote_any > 0) 1643 cupsFilePuts(temp, " # Allow remote access...\n"); 1644 else 1645 cupsFilePuts(temp, " # Restrict access to the server...\n"); 1646 1647 cupsFilePuts(temp, " Order allow,deny\n"); 1648 1649 if (remote_admin > 0 || remote_any > 0 || share_printers > 0) 1650 cupsFilePrintf(temp, " Allow %s\n", 1651 remote_any > 0 ? "all" : "@LOCAL"); 1652 } 1653 1654 in_admin_location = 0; 1655 in_conf_location = 0; 1656 in_log_location = 0; 1657 in_root_location = 0; 1658 1659 cupsFilePuts(temp, "</Location>\n"); 1660 } 1661 else if (!_cups_strcasecmp(line, "<Limit")) 1662 { 1663 if (in_default_policy) 1664 { 1665 /* 1666 * See if the policy limit is for the Cancel-Job operation... 1667 */ 1668 1669 char *valptr; /* Pointer into value */ 1670 1671 1672 if (!_cups_strcasecmp(value, "cancel-job") && user_cancel_any >= 0) 1673 { 1674 /* 1675 * Don't write anything for this limit section... 1676 */ 1677 1678 in_cancel_job = 2; 1679 } 1680 else 1681 { 1682 cupsFilePrintf(temp, "%*s%s", indent, "", line); 1683 1684 while (*value) 1685 { 1686 for (valptr = value; *valptr && !_cups_isspace(*valptr); valptr ++); 1687 1688 if (*valptr) 1689 *valptr++ = '\0'; 1690 1691 if (!_cups_strcasecmp(value, "cancel-job") && user_cancel_any >= 0) 1692 { 1693 /* 1694 * Write everything except for this definition... 1695 */ 1696 1697 in_cancel_job = 1; 1698 } 1699 else 1700 cupsFilePrintf(temp, " %s", value); 1701 1702 for (value = valptr; _cups_isspace(*value); value ++); 1703 } 1704 1705 cupsFilePuts(temp, ">\n"); 1706 } 1707 } 1708 else 1709 cupsFilePrintf(temp, "%*s%s %s>\n", indent, "", line, value); 1710 1711 indent += 2; 1712 } 1713 else if (!_cups_strcasecmp(line, "</Limit>") && in_cancel_job) 1714 { 1715 indent -= 2; 1716 1717 if (in_cancel_job == 1) 1718 cupsFilePuts(temp, " </Limit>\n"); 1719 1720 wrote_policy = 1; 1721 1722 if (!user_cancel_any) 1723 cupsFilePuts(temp, " # Only the owner or an administrator can cancel " 1724 "a job...\n" 1725 " <Limit Cancel-Job>\n" 1726 " Order deny,allow\n" 1727 " Require user @OWNER " 1728 CUPS_DEFAULT_PRINTOPERATOR_AUTH "\n" 1729 " </Limit>\n"); 1730 1731 in_cancel_job = 0; 1732 } 1733 else if ((((in_admin_location || in_conf_location || in_root_location) && 1734 (remote_admin >= 0 || remote_any >= 0)) || 1735 (in_root_location && share_printers >= 0)) && 1736 (!_cups_strcasecmp(line, "Allow") || !_cups_strcasecmp(line, "Deny") || 1737 !_cups_strcasecmp(line, "Order"))) 1738 continue; 1739 else if (in_cancel_job == 2) 1740 continue; 1741 else if (line[0] == '<') 1742 { 1743 if (value) 1744 { 1745 cupsFilePrintf(temp, "%*s%s %s>\n", indent, "", line, value); 1746 indent += 2; 1747 } 1748 else 1749 { 1750 if (line[1] == '/') 1751 indent -= 2; 1752 1753 cupsFilePrintf(temp, "%*s%s\n", indent, "", line); 1754 } 1755 } 1756 else if (!in_policy && !in_location && 1757 (val = cupsGetOption(line, num_settings, settings)) != NULL) 1758 { 1759 /* 1760 * Replace this directive's value with the new one... 1761 */ 1762 1763 cupsd_num_settings = cupsAddOption(line, val, cupsd_num_settings, 1764 &cupsd_settings); 1765 1766 /* 1767 * Write the new value in its place, without indentation since we 1768 * only support setting root directives, not in sections... 1769 */ 1770 1771 cupsFilePrintf(temp, "%s %s\n", line, val); 1772 } 1773 else if (value) 1774 { 1775 if (!in_policy && !in_location) 1776 { 1777 /* 1778 * Record the non-policy, non-location directives that we find 1779 * in the server settings, since we cache this info and record it 1780 * in cupsAdminGetServerSettings()... 1781 */ 1782 1783 cupsd_num_settings = cupsAddOption(line, value, cupsd_num_settings, 1784 &cupsd_settings); 1785 } 1786 1787 cupsFilePrintf(temp, "%*s%s %s\n", indent, "", line, value); 1788 } 1789 else 1790 cupsFilePrintf(temp, "%*s%s\n", indent, "", line); 1791 } 1792 1793 /* 1794 * Write any missing info... 1795 */ 1796 1797 if (!wrote_browsing && share_printers >= 0) 1798 { 1799 if (share_printers > 0) 1800 { 1801 cupsFilePuts(temp, "# Share local printers on the local network.\n"); 1802 cupsFilePuts(temp, "Browsing On\n"); 1803 } 1804 else 1805 { 1806 cupsFilePuts(temp, "# Disable printer sharing and shared printers.\n"); 1807 cupsFilePuts(temp, "Browsing Off\n"); 1808 } 1809 } 1810 1811 if (!wrote_loglevel && debug_logging >= 0) 1812 { 1813 if (debug_logging) 1814 { 1815 cupsFilePuts(temp, "# Show troubleshooting information in error_log.\n"); 1816 cupsFilePuts(temp, "LogLevel debug\n"); 1817 } 1818 else 1819 { 1820 cupsFilePuts(temp, "# Show general information in error_log.\n"); 1821 cupsFilePuts(temp, "LogLevel " CUPS_DEFAULT_LOG_LEVEL "\n"); 1822 } 1823 } 1824 1825 if (!wrote_port_listen && 1826 (remote_admin >= 0 || remote_any >= 0 || share_printers >= 0)) 1827 { 1828 if (remote_admin > 0 || remote_any > 0 || share_printers > 0) 1829 { 1830 cupsFilePuts(temp, "# Allow remote access\n"); 1831 cupsFilePrintf(temp, "Port %d\n", ippPort()); 1832 } 1833 else 1834 { 1835 cupsFilePuts(temp, 1836 "# Only listen for connections from the local machine.\n"); 1837 cupsFilePrintf(temp, "Listen localhost:%d\n", ippPort()); 1838 } 1839 1840 #ifdef CUPS_DEFAULT_DOMAINSOCKET 1841 if (!access(CUPS_DEFAULT_DOMAINSOCKET, 0)) 1842 cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n"); 1843 #endif /* CUPS_DEFAULT_DOMAINSOCKET */ 1844 } 1845 1846 if (!wrote_root_location && 1847 (remote_admin >= 0 || remote_any >= 0 || share_printers >= 0)) 1848 { 1849 if (remote_admin > 0 && share_printers > 0) 1850 cupsFilePuts(temp, 1851 "# Allow shared printing and remote administration...\n"); 1852 else if (remote_admin > 0) 1853 cupsFilePuts(temp, "# Allow remote administration...\n"); 1854 else if (share_printers > 0) 1855 cupsFilePuts(temp, "# Allow shared printing...\n"); 1856 else if (remote_any > 0) 1857 cupsFilePuts(temp, "# Allow remote access...\n"); 1858 else 1859 cupsFilePuts(temp, "# Restrict access to the server...\n"); 1860 1861 cupsFilePuts(temp, "<Location />\n" 1862 " Order allow,deny\n"); 1863 1864 if (remote_admin > 0 || remote_any > 0 || share_printers > 0) 1865 cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL"); 1866 1867 cupsFilePuts(temp, "</Location>\n"); 1868 } 1869 1870 if (!wrote_admin_location && remote_admin >= 0) 1871 { 1872 if (remote_admin) 1873 cupsFilePuts(temp, "# Allow remote administration...\n"); 1874 else 1875 cupsFilePuts(temp, "# Restrict access to the admin pages...\n"); 1876 1877 cupsFilePuts(temp, "<Location /admin>\n" 1878 " Order allow,deny\n"); 1879 1880 if (remote_admin) 1881 cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL"); 1882 1883 cupsFilePuts(temp, "</Location>\n"); 1884 } 1885 1886 if (!wrote_conf_location && remote_admin >= 0) 1887 { 1888 if (remote_admin) 1889 cupsFilePuts(temp, 1890 "# Allow remote access to the configuration files...\n"); 1891 else 1892 cupsFilePuts(temp, "# Restrict access to the configuration files...\n"); 1893 1894 cupsFilePuts(temp, "<Location /admin/conf>\n" 1895 " AuthType Default\n" 1896 " Require user @SYSTEM\n" 1897 " Order allow,deny\n"); 1898 1899 if (remote_admin) 1900 cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL"); 1901 1902 cupsFilePuts(temp, "</Location>\n"); 1903 } 1904 1905 if (!wrote_log_location && remote_admin >= 0) 1906 { 1907 if (remote_admin) 1908 cupsFilePuts(temp, 1909 "# Allow remote access to the log files...\n"); 1910 else 1911 cupsFilePuts(temp, "# Restrict access to the log files...\n"); 1912 1913 cupsFilePuts(temp, "<Location /admin/log>\n" 1914 " AuthType Default\n" 1915 " Require user @SYSTEM\n" 1916 " Order allow,deny\n"); 1917 1918 if (remote_admin) 1919 cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL"); 1920 1921 cupsFilePuts(temp, "</Location>\n"); 1922 } 1923 1924 if (!wrote_policy && user_cancel_any >= 0) 1925 { 1926 cupsFilePuts(temp, "<Policy default>\n" 1927 " # Job-related operations must be done by the owner " 1928 "or an administrator...\n" 1929 " <Limit Send-Document Send-URI Hold-Job Release-Job " 1930 "Restart-Job Purge-Jobs Set-Job-Attributes " 1931 "Create-Job-Subscription Renew-Subscription " 1932 "Cancel-Subscription Get-Notifications Reprocess-Job " 1933 "Cancel-Current-Job Suspend-Current-Job Resume-Job " 1934 "CUPS-Move-Job>\n" 1935 " Require user @OWNER @SYSTEM\n" 1936 " Order deny,allow\n" 1937 " </Limit>\n" 1938 " # All administration operations require an " 1939 "administrator to authenticate...\n" 1940 " <Limit Pause-Printer Resume-Printer " 1941 "Set-Printer-Attributes Enable-Printer " 1942 "Disable-Printer Pause-Printer-After-Current-Job " 1943 "Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer " 1944 "Activate-Printer Restart-Printer Shutdown-Printer " 1945 "Startup-Printer Promote-Job Schedule-Job-After " 1946 "CUPS-Add-Printer CUPS-Delete-Printer " 1947 "CUPS-Add-Class CUPS-Delete-Class " 1948 "CUPS-Accept-Jobs CUPS-Reject-Jobs " 1949 "CUPS-Set-Default CUPS-Add-Device CUPS-Delete-Device>\n" 1950 " AuthType Default\n" 1951 " Require user @SYSTEM\n" 1952 " Order deny,allow\n" 1953 "</Limit>\n"); 1954 1955 if (!user_cancel_any) 1956 cupsFilePuts(temp, " # Only the owner or an administrator can cancel " 1957 "a job...\n" 1958 " <Limit Cancel-Job>\n" 1959 " Order deny,allow\n" 1960 " Require user @OWNER " 1961 CUPS_DEFAULT_PRINTOPERATOR_AUTH "\n" 1962 " </Limit>\n"); 1963 1964 cupsFilePuts(temp, " <Limit All>\n" 1965 " Order deny,allow\n" 1966 " </Limit>\n" 1967 "</Policy>\n"); 1968 } 1969 1970 for (i = num_settings, setting = settings; i > 0; i --, setting ++) 1971 if (setting->name[0] != '_' && 1972 _cups_strcasecmp(setting->name, "Listen") && 1973 _cups_strcasecmp(setting->name, "Port") && 1974 !cupsGetOption(setting->name, cupsd_num_settings, cupsd_settings)) 1975 { 1976 /* 1977 * Add this directive to the list of directives we have written... 1978 */ 1979 1980 cupsd_num_settings = cupsAddOption(setting->name, setting->value, 1981 cupsd_num_settings, &cupsd_settings); 1982 1983 /* 1984 * Write the new value, without indentation since we only support 1985 * setting root directives, not in sections... 1986 */ 1987 1988 cupsFilePrintf(temp, "%s %s\n", setting->name, setting->value); 1989 } 1990 1991 cupsFileClose(cupsd); 1992 cupsFileClose(temp); 1993 1994 /* 1995 * Upload the configuration file to the server... 1996 */ 1997 1998 status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile); 1999 2000 if (status == HTTP_STATUS_CREATED) 2001 { 2002 /* 2003 * Updated OK, add the basic settings... 2004 */ 2005 2006 if (debug_logging >= 0) 2007 cupsd_num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING, 2008 debug_logging ? "1" : "0", 2009 cupsd_num_settings, &cupsd_settings); 2010 else 2011 cupsd_num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING, 2012 old_debug_logging ? "1" : "0", 2013 cupsd_num_settings, &cupsd_settings); 2014 2015 if (remote_admin >= 0) 2016 cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN, 2017 remote_admin ? "1" : "0", 2018 cupsd_num_settings, &cupsd_settings); 2019 else 2020 cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN, 2021 old_remote_admin ? "1" : "0", 2022 cupsd_num_settings, &cupsd_settings); 2023 2024 if (remote_any >= 0) 2025 cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY, 2026 remote_any ? "1" : "0", 2027 cupsd_num_settings, &cupsd_settings); 2028 else 2029 cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY, 2030 old_remote_any ? "1" : "0", 2031 cupsd_num_settings, &cupsd_settings); 2032 2033 if (share_printers >= 0) 2034 cupsd_num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS, 2035 share_printers ? "1" : "0", 2036 cupsd_num_settings, &cupsd_settings); 2037 else 2038 cupsd_num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS, 2039 old_share_printers ? "1" : "0", 2040 cupsd_num_settings, &cupsd_settings); 2041 2042 if (user_cancel_any >= 0) 2043 cupsd_num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY, 2044 user_cancel_any ? "1" : "0", 2045 cupsd_num_settings, &cupsd_settings); 2046 else 2047 cupsd_num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY, 2048 old_user_cancel_any ? "1" : "0", 2049 cupsd_num_settings, &cupsd_settings); 2050 2051 /* 2052 * Save the new values... 2053 */ 2054 2055 invalidate_cupsd_cache(cg); 2056 2057 cg->cupsd_num_settings = cupsd_num_settings; 2058 cg->cupsd_settings = cupsd_settings; 2059 cg->cupsd_update = time(NULL); 2060 2061 httpGetHostname(http, cg->cupsd_hostname, sizeof(cg->cupsd_hostname)); 2062 } 2063 else 2064 cupsFreeOptions(cupsd_num_settings, cupsd_settings); 2065 2066 /* 2067 * Remote our temp files and return... 2068 */ 2069 2070 if (remote) 2071 unlink(cupsdconf); 2072 2073 unlink(tempfile); 2074 2075 return (status == HTTP_STATUS_CREATED); 2076 } 2077 2078 2079 /* 2080 * 'do_samba_command()' - Do a SAMBA command. 2081 */ 2082 2083 static int /* O - Status of command */ 2084 do_samba_command(const char *command, /* I - Command to run */ 2085 const char *address, /* I - Address for command */ 2086 const char *subcmd, /* I - Sub-command */ 2087 const char *authfile, /* I - Samba authentication file */ 2088 FILE *logfile) /* I - Optional log file */ 2089 { 2090 #ifdef WIN32 2091 return (1); /* Always fail on Windows... */ 2092 2093 #else 2094 int status; /* Status of command */ 2095 int pid; /* Process ID of child */ 2096 2097 2098 if (logfile) 2099 _cupsLangPrintf(logfile, 2100 _("Running command: %s %s -N -A %s -c \'%s\'"), 2101 command, address, authfile, subcmd); 2102 2103 if ((pid = fork()) == 0) 2104 { 2105 /* 2106 * Child goes here, redirect stdin/out/err and execute the command... 2107 */ 2108 2109 int fd = open("/dev/null", O_RDONLY); 2110 2111 if (fd > 0) 2112 { 2113 dup2(fd, 0); 2114 close(fd); 2115 } 2116 2117 if (logfile) 2118 dup2(fileno(logfile), 1); 2119 else if ((fd = open("/dev/null", O_WRONLY)) > 1) 2120 { 2121 dup2(fd, 1); 2122 close(fd); 2123 } 2124 2125 dup2(1, 2); 2126 2127 execlp(command, command, address, "-N", "-A", authfile, "-c", subcmd, 2128 (char *)0); 2129 exit(errno); 2130 } 2131 else if (pid < 0) 2132 { 2133 status = -1; 2134 2135 if (logfile) 2136 _cupsLangPrintf(logfile, _("Unable to run \"%s\": %s"), 2137 command, strerror(errno)); 2138 } 2139 else 2140 { 2141 /* 2142 * Wait for the process to complete... 2143 */ 2144 2145 while (wait(&status) != pid); 2146 } 2147 2148 if (logfile) 2149 _cupsLangPuts(logfile, ""); 2150 2151 DEBUG_printf(("9do_samba_command: status=%d", status)); 2152 2153 if (WIFEXITED(status)) 2154 return (WEXITSTATUS(status)); 2155 else 2156 return (-WTERMSIG(status)); 2157 #endif /* WIN32 */ 2158 } 2159 2160 2161 /* 2162 * 'get_cupsd_conf()' - Get the current cupsd.conf file. 2163 */ 2164 2165 static http_status_t /* O - Status of request */ 2166 get_cupsd_conf( 2167 http_t *http, /* I - Connection to server */ 2168 _cups_globals_t *cg, /* I - Global data */ 2169 time_t last_update, /* I - Last update time for file */ 2170 char *name, /* I - Filename buffer */ 2171 size_t namesize, /* I - Size of filename buffer */ 2172 int *remote) /* O - Remote file? */ 2173 { 2174 int fd; /* Temporary file descriptor */ 2175 #ifndef WIN32 2176 struct stat info; /* cupsd.conf file information */ 2177 #endif /* WIN32 */ 2178 http_status_t status; /* Status of getting cupsd.conf */ 2179 char host[HTTP_MAX_HOST]; /* Hostname for connection */ 2180 2181 2182 /* 2183 * See if we already have the data we need... 2184 */ 2185 2186 httpGetHostname(http, host, sizeof(host)); 2187 2188 if (_cups_strcasecmp(cg->cupsd_hostname, host)) 2189 invalidate_cupsd_cache(cg); 2190 2191 snprintf(name, namesize, "%s/cupsd.conf", cg->cups_serverroot); 2192 *remote = 0; 2193 2194 #ifndef WIN32 2195 if (!_cups_strcasecmp(host, "localhost") && !access(name, R_OK)) 2196 { 2197 /* 2198 * Read the local file rather than using HTTP... 2199 */ 2200 2201 if (stat(name, &info)) 2202 { 2203 char message[1024]; /* Message string */ 2204 2205 2206 snprintf(message, sizeof(message), 2207 _cupsLangString(cupsLangDefault(), _("stat of %s failed: %s")), 2208 name, strerror(errno)); 2209 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0); 2210 2211 *name = '\0'; 2212 2213 return (HTTP_STATUS_SERVER_ERROR); 2214 } 2215 else if (last_update && info.st_mtime <= last_update) 2216 status = HTTP_STATUS_NOT_MODIFIED; 2217 else 2218 status = HTTP_STATUS_OK; 2219 } 2220 else 2221 #endif /* !WIN32 */ 2222 { 2223 /* 2224 * Read cupsd.conf via a HTTP GET request... 2225 */ 2226 2227 if ((fd = cupsTempFd(name, (int)namesize)) < 0) 2228 { 2229 *name = '\0'; 2230 2231 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, NULL, 0); 2232 2233 invalidate_cupsd_cache(cg); 2234 2235 return (HTTP_STATUS_SERVER_ERROR); 2236 } 2237 2238 *remote = 1; 2239 2240 httpClearFields(http); 2241 2242 if (last_update) 2243 httpSetField(http, HTTP_FIELD_IF_MODIFIED_SINCE, 2244 httpGetDateString(last_update)); 2245 2246 status = cupsGetFd(http, "/admin/conf/cupsd.conf", fd); 2247 2248 close(fd); 2249 2250 if (status != HTTP_STATUS_OK) 2251 { 2252 unlink(name); 2253 *name = '\0'; 2254 } 2255 } 2256 2257 return (status); 2258 } 2259 2260 2261 /* 2262 * 'invalidate_cupsd_cache()' - Invalidate the cached cupsd.conf settings. 2263 */ 2264 2265 static void 2266 invalidate_cupsd_cache( 2267 _cups_globals_t *cg) /* I - Global data */ 2268 { 2269 cupsFreeOptions(cg->cupsd_num_settings, cg->cupsd_settings); 2270 2271 cg->cupsd_hostname[0] = '\0'; 2272 cg->cupsd_update = 0; 2273 cg->cupsd_num_settings = 0; 2274 cg->cupsd_settings = NULL; 2275 } 2276 2277 2278 /* 2279 * 'write_option()' - Write a CUPS option to a PPD file. 2280 */ 2281 2282 static void 2283 write_option(cups_file_t *dstfp, /* I - PPD file */ 2284 int order, /* I - Order dependency */ 2285 const char *name, /* I - Option name */ 2286 const char *text, /* I - Option text */ 2287 const char *attrname, /* I - Attribute name */ 2288 ipp_attribute_t *suppattr, /* I - IPP -supported attribute */ 2289 ipp_attribute_t *defattr, /* I - IPP -default attribute */ 2290 int defval, /* I - Default value number */ 2291 int valcount) /* I - Number of values */ 2292 { 2293 int i; /* Looping var */ 2294 2295 2296 cupsFilePrintf(dstfp, "*JCLOpenUI *%s/%s: PickOne\n" 2297 "*OrderDependency: %d JCLSetup *%s\n", 2298 name, text, order, name); 2299 2300 if (defattr->value_tag == IPP_TAG_INTEGER) 2301 { 2302 /* 2303 * Do numeric options with a range or list... 2304 */ 2305 2306 cupsFilePrintf(dstfp, "*Default%s: %d\n", name, 2307 defattr->values[defval].integer); 2308 2309 if (suppattr->value_tag == IPP_TAG_RANGE) 2310 { 2311 /* 2312 * List each number in the range... 2313 */ 2314 2315 for (i = suppattr->values[0].range.lower; 2316 i <= suppattr->values[0].range.upper; 2317 i ++) 2318 { 2319 cupsFilePrintf(dstfp, "*%s %d: \"", name, i); 2320 2321 if (valcount == 1) 2322 cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%d\n\"\n*End\n", 2323 attrname, i); 2324 else if (defval == 0) 2325 cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%d\"\n", attrname, i); 2326 else if (defval < (valcount - 1)) 2327 cupsFilePrintf(dstfp, ",%d\"\n", i); 2328 else 2329 cupsFilePrintf(dstfp, ",%d\n\"\n*End\n", i); 2330 } 2331 } 2332 else 2333 { 2334 /* 2335 * List explicit numbers... 2336 */ 2337 2338 for (i = 0; i < suppattr->num_values; i ++) 2339 { 2340 cupsFilePrintf(dstfp, "*%s %d: \"", name, suppattr->values[i].integer); 2341 2342 if (valcount == 1) 2343 cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%d\n\"\n*End\n", attrname, 2344 suppattr->values[i].integer); 2345 else if (defval == 0) 2346 cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%d\"\n", attrname, 2347 suppattr->values[i].integer); 2348 else if (defval < (valcount - 1)) 2349 cupsFilePrintf(dstfp, ",%d\"\n", suppattr->values[i].integer); 2350 else 2351 cupsFilePrintf(dstfp, ",%d\n\"\n*End\n", suppattr->values[i].integer); 2352 } 2353 } 2354 } 2355 else 2356 { 2357 /* 2358 * Do text options with a list... 2359 */ 2360 2361 cupsFilePrintf(dstfp, "*Default%s: %s\n", name, 2362 defattr->values[defval].string.text); 2363 2364 for (i = 0; i < suppattr->num_values; i ++) 2365 { 2366 cupsFilePrintf(dstfp, "*%s %s: \"", name, 2367 suppattr->values[i].string.text); 2368 2369 if (valcount == 1) 2370 cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%s\n\"\n*End\n", attrname, 2371 suppattr->values[i].string.text); 2372 else if (defval == 0) 2373 cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%s\"\n", attrname, 2374 suppattr->values[i].string.text); 2375 else if (defval < (valcount - 1)) 2376 cupsFilePrintf(dstfp, ",%s\"\n", suppattr->values[i].string.text); 2377 else 2378 cupsFilePrintf(dstfp, ",%s\n\"\n*End\n", 2379 suppattr->values[i].string.text); 2380 } 2381 } 2382 2383 cupsFilePrintf(dstfp, "*JCLCloseUI: *%s\n\n", name); 2384 } 2385