1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include <stdio.h> 34 #include <string.h> 35 #include <errno.h> 36 #include <limits.h> 37 #include <sys/types.h> 38 #include <stdlib.h> 39 #include <libintl.h> 40 41 #include "lp.h" 42 #include "class.h" 43 #include "printers.h" 44 #include "msgs.h" 45 46 #define WHO_AM_I I_AM_LPADMIN 47 #include "oam.h" 48 49 #include "lpadmin.h" 50 51 extern void fromallclasses(); 52 53 #if !defined(PATH_MAX) 54 # define PATH_MAX 1024 55 #endif 56 #if PATH_MAX < 1024 57 # undef PATH_MAX 58 # define PATH_MAX 1024 59 #endif 60 61 extern char *label; 62 static void configure_printer(); 63 static char *fullpath(); 64 char *nameit(); 65 66 /** 67 ** do_printer() - CREATE OR CHANGE PRINTER 68 **/ 69 70 void do_printer () 71 { 72 int rc; 73 74 /* 75 * Set or change the printer configuration. 76 */ 77 if (strlen(modifications)) 78 configure_printer (modifications); 79 80 /* 81 * Allow/deny forms. 82 */ 83 BEGIN_CRITICAL 84 if (!oldp) 85 if (allow_form_printer(getlist(NAME_NONE, "", ","), p) == -1) { 86 LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR); 87 done(1); 88 } 89 90 if (f_allow || f_deny) { 91 if (f_allow && allow_form_printer(f_allow, p) == -1) { 92 LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR); 93 done(1); 94 } 95 96 if (f_deny && deny_form_printer(f_deny, p) == -1) { 97 LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR); 98 done(1); 99 } 100 } 101 END_CRITICAL 102 103 /* Add/remove types of paper */ 104 105 BEGIN_CRITICAL 106 if (!oldp) 107 if (add_paper_to_printer(getlist(NAME_NONE, "", ","),p) == -1) { 108 LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR); 109 done(1); 110 } 111 112 113 if (p_add && add_paper_to_printer(p_add, p) == -1) { 114 LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR); 115 done(1); 116 } 117 118 if (p_remove && remove_paper_from_printer(p_remove, p) == -1) { 119 LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR); 120 done(1); 121 } 122 END_CRITICAL 123 124 /* 125 * Allow/deny users. 126 */ 127 BEGIN_CRITICAL 128 if (!oldp) 129 if (allow_user_printer(getlist(NAME_ALL, "", ","), p) == -1) { 130 LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR); 131 done(1); 132 } 133 134 if (u_allow || u_deny) { 135 if (u_allow && allow_user_printer(u_allow, p) == -1) { 136 LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR); 137 done(1); 138 } 139 140 if (u_deny && deny_user_printer(u_deny, p) == -1) { 141 LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR); 142 done(1); 143 } 144 } 145 END_CRITICAL 146 147 /* 148 * Tell the Spooler about the printer 149 */ 150 send_message(S_LOAD_PRINTER, p, "", ""); 151 rc = output(R_LOAD_PRINTER); 152 153 switch (rc) { 154 case MOK: 155 break; 156 157 case MNODEST: 158 case MERRDEST: 159 LP_ERRMSG (ERROR, E_ADM_ERRDEST); 160 done (1); 161 /*NOTREACHED*/ 162 163 case MNOSPACE: 164 LP_ERRMSG (WARNING, E_ADM_NOPSPACE); 165 break; 166 167 case MNOPERM: /* taken care of up front */ 168 default: 169 LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, rc); 170 done (1); 171 /*NOTREACHED*/ 172 } 173 174 /* 175 * Now that the Spooler knows about the printer, 176 * we can do the balance of the changes. 177 */ 178 179 /* 180 * Mount or unmount form, print-wheel. 181 */ 182 if (M) 183 do_mount(p, (f? f : (char *)0), (S? *S : (char *)0)); 184 else if (t) do_max_trays(p); 185 186 /* 187 * Display the alert type. 188 */ 189 if (A && STREQU(A, NAME_LIST)) { 190 if (label) 191 (void) printf(gettext("Printer %s: "), label); 192 printalert (stdout, &(oldp->fault_alert), 1); 193 } 194 195 /* 196 * -A quiet. 197 */ 198 if (A && STREQU(A, NAME_QUIET)) { 199 200 send_message(S_QUIET_ALERT, p, (char *)QA_PRINTER, ""); 201 rc = output(R_QUIET_ALERT); 202 203 switch(rc) { 204 case MOK: 205 break; 206 207 case MNODEST: /* not quite, but not a lie either */ 208 case MERRDEST: 209 LP_ERRMSG1 (WARNING, E_LP_NOQUIET, p); 210 break; 211 212 case MNOPERM: /* taken care of up front */ 213 default: 214 LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, rc); 215 done (1); 216 /*NOTREACHED*/ 217 } 218 } 219 220 /* 221 * Add printer p to class c 222 */ 223 if (c) { 224 CLASS *pc, 225 clsbuf; 226 227 if (STREQU(c, NAME_ANY)) 228 c = NAME_ALL; 229 230 Loop: if (!(pc = getclass(c))) { 231 if (STREQU(c, NAME_ALL)) 232 goto Done; 233 234 if (errno != ENOENT) { 235 LP_ERRMSG2 ( 236 ERROR, 237 E_LP_GETCLASS, 238 c, 239 PERROR 240 ); 241 done (1); 242 } 243 244 /* 245 * Create the class 246 */ 247 clsbuf.name = strdup(c); 248 clsbuf.members = 0; 249 if (addlist(&clsbuf.members, p) == -1) { 250 LP_ERRMSG (ERROR, E_LP_MALLOC); 251 done (1); 252 } 253 pc = &clsbuf; 254 255 } else if (searchlist(p, pc->members)) 256 LP_ERRMSG2 (WARNING, E_ADM_INCLASS, p, pc->name); 257 258 else if (addlist(&pc->members, p) == -1) { 259 LP_ERRMSG (ERROR, E_LP_MALLOC); 260 done (1); 261 } 262 263 BEGIN_CRITICAL 264 if (putclass(pc->name, pc) == -1) { 265 LP_ERRMSG2 ( 266 ERROR, 267 E_LP_PUTCLASS, 268 pc->name, 269 PERROR 270 ); 271 done(1); 272 } 273 END_CRITICAL 274 275 send_message (S_LOAD_CLASS, pc->name); 276 rc = output(R_LOAD_CLASS); 277 278 switch(rc) { 279 case MOK: 280 break; 281 282 case MNODEST: 283 case MERRDEST: 284 LP_ERRMSG (ERROR, E_ADM_ERRDEST); 285 done (1); 286 /*NOTREACHED*/ 287 288 case MNOSPACE: 289 LP_ERRMSG (WARNING, E_ADM_NOCSPACE); 290 break; 291 292 case MNOPERM: /* taken care of up front */ 293 default: 294 LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, rc); 295 done (1); 296 /*NOTREACHED*/ 297 } 298 299 if (STREQU(c, NAME_ALL)) 300 goto Loop; 301 } 302 Done: 303 /* 304 * Remove printer p from class r 305 */ 306 if (r) { 307 if (STREQU(r, NAME_ALL) || STREQU(r, NAME_ANY)) 308 fromallclasses(p); 309 else 310 fromclass(p, r); 311 } 312 313 return; 314 } 315 316 /** 317 ** configure_printer() - SET OR CHANGE CONFIGURATION OF PRINTER 318 **/ 319 320 static void configure_printer (list) 321 char *list; 322 { 323 register PRINTER *prbufp; 324 325 PRINTER printer_struct; 326 327 char type; 328 char * infile_opts = NULL; 329 330 331 if (oldp) { 332 333 prbufp = oldp; 334 335 if (!T) 336 T = prbufp->printer_types; 337 338 if (!i && !e && !m) 339 /* 340 * Don't copy the original interface program 341 * again, but do keep the name of the original. 342 */ 343 ignprinter = BAD_INTERFACE; 344 else 345 ignprinter = 0; 346 347 /* 348 * If we are making this a remote printer, 349 * make sure that local-only attributes are 350 * cleared. 351 */ 352 if (s) { 353 prbufp->banner = 0; 354 prbufp->cpi.val = 0; 355 prbufp->cpi.sc = 0; 356 prbufp->device = 0; 357 prbufp->dial_info = 0; 358 prbufp->fault_rec = 0; 359 prbufp->interface = 0; 360 prbufp->lpi.val = 0; 361 prbufp->lpi.sc = 0; 362 prbufp->plen.val = 0; 363 prbufp->plen.sc = 0; 364 prbufp->login = 0; 365 prbufp->speed = 0; 366 prbufp->stty = 0; 367 prbufp->pwid.val = 0; 368 prbufp->pwid.sc = 0; 369 prbufp->fault_alert.shcmd = strdup(NAME_NONE); 370 prbufp->fault_alert.Q = 0; 371 prbufp->fault_alert.W = 0; 372 #if defined(CAN_DO_MODULES) 373 prbufp->modules = 0; 374 #endif 375 376 /* 377 * If we are making this a local printer, make 378 * sure that some local-only attributes are set. 379 * (If the user has specified these as well, his/her 380 * values will overwrite what we set here.) 381 */ 382 } else if (oldp->remote) { 383 prbufp->banner = BAN_ALWAYS; 384 prbufp->interface = makepath(Lp_Model, STANDARD, (char *)0); 385 prbufp->fault_alert.shcmd = nameit(NAME_MAIL); 386 387 /* 388 * Being here means "!s && oldp->remote" is true, 389 * i.e. this printer never had an interface pgm 390 * before. Thus we can safely clear the following. 391 * This is needed to let "putprinter()" copy the 392 * (default) interface program. 393 */ 394 ignprinter = 0; 395 } 396 397 } else { 398 /* 399 * The following takes care of the lion's share 400 * of the initialization of a new printer structure. 401 * However, special initialization (e.g. non-zero, 402 * or substructure members) needs to be considered 403 * for EACH NEW MEMBER added to the structure. 404 */ 405 (void)memset (&printer_struct, 0, sizeof(printer_struct)); 406 407 prbufp = &printer_struct; 408 prbufp->banner = BAN_ALWAYS; 409 prbufp->cpi.val = 0; 410 prbufp->cpi.sc = 0; 411 if (!s) 412 prbufp->interface = makepath(Lp_Model, m, (char *)0); 413 prbufp->lpi.val = 0; 414 prbufp->lpi.sc = 0; 415 prbufp->plen.val = 0; 416 prbufp->plen.sc = 0; 417 prbufp->pwid.val = 0; 418 prbufp->pwid.sc = 0; 419 if (!s && !A) 420 prbufp->fault_alert.shcmd = nameit(NAME_MAIL); 421 prbufp->fault_alert.Q = 0; 422 prbufp->fault_alert.W = 0; 423 prbufp->options = NULL; 424 } 425 426 while ((type = *list++) != '\0') switch(type) { 427 428 case 'A': 429 if (!s) { 430 if (STREQU(A, NAME_MAIL) || STREQU(A, NAME_WRITE)) 431 prbufp->fault_alert.shcmd = nameit(A); 432 else if (!STREQU(A, NAME_QUIET)) 433 prbufp->fault_alert.shcmd = A; 434 } 435 break; 436 437 case 'b': 438 if (!s) 439 prbufp->banner = banner; 440 break; 441 442 case 'c': 443 if (!s) 444 prbufp->cpi = cpi_sdn; 445 break; 446 447 case 'D': 448 prbufp->description = D; 449 break; 450 451 case 'e': 452 if (!s) { 453 prbufp->interface = makepath( 454 Lp_A_Interfaces, 455 e, 456 (char *)0 457 ); 458 } 459 break; 460 461 case 'F': 462 if (!s) 463 prbufp->fault_rec = F; 464 break; 465 466 #if defined(CAN_DO_MODULES) 467 case 'H': 468 if (!s) 469 prbufp->modules = H; 470 break; 471 #endif 472 473 case 'h': 474 if (!s) 475 prbufp->login = 0; 476 break; 477 478 case 'i': 479 if (!s) 480 prbufp->interface = fullpath(i); 481 break; 482 483 case 'I': 484 prbufp->input_types = I; 485 break; 486 487 case 'l': 488 if (!s) 489 prbufp->login = 1; 490 break; 491 492 case 'L': 493 if (!s) 494 prbufp->plen = length_sdn; 495 break; 496 497 case 'm': 498 if (!s) 499 prbufp->interface = makepath(Lp_Model, m, (char *)0); 500 break; 501 502 case 'M': 503 if (!s) 504 prbufp->lpi = lpi_sdn; 505 break; 506 507 #ifdef LP_USE_PAPI_ATTR 508 case 'n': 509 { 510 if (n_opt != NULL) 511 { 512 if (*n_opt == '/') 513 { 514 prbufp->ppd = fullpath(n_opt); 515 } 516 else 517 { 518 prbufp->ppd = 519 makepath(Lp_Model, "ppd", n_opt, (char *)0); 520 } 521 ppdopt = 1; 522 } 523 break; 524 } 525 #endif 526 527 case 'o': 528 /* 529 * The "undefined" key-value -o options 530 * 531 * Options requires special handling. It is a 532 * list whose members are to be handled 533 * individually. 534 * 535 * Need to: set new options, keep old options if not 536 * redefined, remove old options if defined as "key=". 537 * 538 * 539 * "p" is a global containing the printer name 540 */ 541 542 if (!s) { 543 544 if ((infile_opts = getpentry(p, PR_OPTIONS)) == NULL) 545 prbufp->options = o_options; 546 else { 547 prbufp->options = 548 pick_opts(infile_opts, o_options); 549 } 550 } 551 break; 552 553 case 'R': 554 if (s) { 555 prbufp->remote = s; 556 prbufp->dial_info = 0; 557 prbufp->device = 0; 558 } else 559 prbufp->remote = 0; 560 break; 561 562 case 's': 563 if (!s) { 564 /* 565 * lpadmin always defers to stty 566 */ 567 prbufp->speed = 0; 568 prbufp->stty = stty_opt; 569 } 570 break; 571 572 case 'S': 573 if (!M) 574 if (STREQU(*S, NAME_NONE)) 575 prbufp->char_sets = 0; 576 else 577 prbufp->char_sets = S; 578 break; 579 580 case 'T': 581 prbufp->printer_types = T; 582 break; 583 584 case 'U': 585 if (!s) { 586 prbufp->dial_info = U; 587 prbufp->device = 0; 588 prbufp->remote = 0; 589 } 590 break; 591 592 case 'v': 593 if (!s) { 594 prbufp->device = v; 595 prbufp->dial_info = 0; 596 prbufp->remote = 0; 597 } 598 break; 599 600 case 'w': 601 if (!s) 602 prbufp->pwid = width_sdn; 603 break; 604 605 case 'W': 606 if (!s) 607 prbufp->fault_alert.W = W; 608 break; 609 610 } 611 612 613 BEGIN_CRITICAL 614 if (putprinter(p, prbufp) == -1) { 615 if ( 616 errno == EINVAL 617 && (badprinter & BAD_INTERFACE) 618 ) 619 LP_ERRMSG1 ( 620 ERROR, 621 E_ADM_BADINTF, 622 prbufp->interface 623 ); 624 else 625 LP_ERRMSG2 ( 626 ERROR, 627 E_LP_PUTPRINTER, 628 p, 629 PERROR 630 ); 631 done(1); 632 } 633 END_CRITICAL 634 635 return; 636 } 637 638 /** 639 ** fullpath() 640 **/ 641 642 static char *fullpath (str) 643 char *str; 644 { 645 register char *cur_dir, 646 *path; 647 648 649 while (*str && *str == ' ') 650 str++; 651 if (*str == '/') 652 return (str); 653 654 if (!(cur_dir = malloc(PATH_MAX + 1))) 655 return (str); 656 657 getcwd (cur_dir, PATH_MAX); 658 path = makepath(cur_dir, str, (char *)0); 659 660 /* 661 * Here we could be nice and strip out /./ and /../ 662 * stuff, but it isn't necessary. 663 */ 664 665 return (path); 666 } 667 668 /** 669 ** nameit() - ADD USER NAME TO COMMAND 670 **/ 671 672 char *nameit (cmd) 673 char *cmd; 674 { 675 register char *nm = getname(), 676 *copy = malloc( 677 (unsigned) (strlen(cmd) + 1 + 678 strlen(nm) + 1) 679 ); 680 681 (void) strcpy (copy, cmd); 682 (void) strcat (copy, " "); 683 (void) strcat (copy, nm); 684 return (copy); 685 } 686