1/* 2 * $Id: queries.c,v 1.22 2009-10-13 22:55:37 didg Exp $ 3 * 4 * Copyright (c) 1990,1994 Regents of The University of Michigan. 5 * All Rights Reserved. See COPYRIGHT. 6 */ 7 8#ifdef HAVE_CONFIG_H 9#include "config.h" 10#endif /* HAVE_CONFIG_H */ 11 12#include <string.h> 13#include <stdio.h> 14#include <stdlib.h> 15#include <atalk/logger.h> 16#include <sys/param.h> 17#include <sys/time.h> 18#include <sys/types.h> 19#include <netatalk/at.h> 20#include <atalk/atp.h> 21 22#ifdef KRB 23#ifdef SOLARIS 24#include <kerberos/krb.h> 25#else /* SOLARIS */ 26#include <krb.h> 27#endif /* SOLARIS */ 28#endif /* KRB */ 29 30#include "file.h" 31#include "comment.h" 32#include "printer.h" 33#include "ppd.h" 34#include "lp.h" 35#include "uam_auth.h" 36 37int cq_default( struct papfile *, struct papfile * ); 38int cq_k4login( struct papfile *, struct papfile * ); 39int cq_uameth( struct papfile *, struct papfile * ); 40 41int gq_balance( struct papfile * ); 42int gq_pagecost( struct papfile * ); 43int gq_true( struct papfile * ); 44int gq_rbispoolerid( struct papfile * ); 45int gq_rbiuamlist( struct papfile * ); 46 47int cq_query( struct papfile *, struct papfile * ); 48void cq_font_answer( char *, char *, struct papfile * ); 49int cq_font( struct papfile *, struct papfile * ); 50int cq_feature( struct papfile *, struct papfile * ); 51int cq_printer( struct papfile *, struct papfile * ); 52int cq_rmjob( struct papfile *, struct papfile * ); 53#ifndef HAVE_CUPS 54int cq_listq( struct papfile *, struct papfile * ); 55int cq_rbilogin( struct papfile *, struct papfile * ); 56#endif /* HAVE_CUPS */ 57 58 59 60int cq_default( struct papfile *in, struct papfile *out) 61{ 62 char *start, *stop, *p; 63 int linelength, crlflength; 64 struct papd_comment *comment = compeek(); 65 66 for (;;) { 67 switch ( markline( in, &start, &linelength, &crlflength )) { 68 case 0 : 69 return( 0 ); 70 71 case -1 : 72 return( CH_MORE ); 73 74 case -2 : 75 return( CH_ERROR ); 76 } 77 78 stop = start+linelength; 79 80 if ( comgetflags() == 0 ) { /* started */ 81 if ( comment->c_end ) { 82 comsetflags( 1 ); 83 } else { 84 compop(); 85 CONSUME( in, linelength + crlflength ); 86 return( CH_DONE ); 87 } 88 } else { 89 /* return default */ 90 if ( comcmp( start, start+linelength, comment->c_end, 0 ) == 0 ) { 91 for ( p = start; p < stop; p++ ) { 92 if ( *p == ':' ) { 93 break; 94 } 95 } 96 if (p < stop) { 97 p++; 98 while ( *p == ' ' ) { 99 p++; 100 } 101 } 102 103 append( out, p, stop - p + crlflength ); 104 compop(); 105 CONSUME( in, linelength + crlflength ); 106 return( CH_DONE ); 107 } 108 } 109 110 CONSUME( in, linelength + crlflength ); 111 } 112} 113 114#ifdef KRB 115char *LoginOK = "LoginOK\n"; 116char *LoginFailed = "LoginFailed\n"; 117 118#define h2b(x) (isdigit((x))?(x)-'0':(isupper((x))?(x)-'A':(x)-'a')+10) 119 120int cq_k4login( struct papfile *in, struct papfile *out) 121{ 122 char *start, *p; 123 int linelength, crlflength; 124 unsigned char *t; 125 struct papd_comment *comment = compeek(); 126 KTEXT_ST tkt; 127 AUTH_DAT ad; 128 int rc, i; 129 130 switch ( markline( in, &start, &linelength, &crlflength )) { 131 case 0 : 132 return( 0 ); 133 134 case -1 : 135 return( CH_MORE ); 136 137 case -2 : 138 return( CH_ERROR ); 139 } 140 141 p = start + strlen( comment->c_begin ); 142 while ( *p == ' ' ) { 143 p++; 144 } 145 146 bzero( &tkt, sizeof( tkt )); 147 stop = start+linelength; 148 /* FIXME */ 149 for ( i = 0, t = tkt.dat; p < stop; p += 2, t++, i++ ) { 150 *t = ( h2b( (unsigned char)*p ) << 4 ) + 151 h2b( (unsigned char)*( p + 1 )); 152 } 153 tkt.length = i; 154 155 if (( rc = krb_rd_req( &tkt, "LaserWriter", printer->p_name, 156 0, &ad, "" )) != RD_AP_OK ) { 157 LOG(log_error, logtype_papd, "cq_k4login: %s", krb_err_txt[ rc ] ); 158 append( out, LoginFailed, strlen( LoginFailed )); 159 compop(); 160 CONSUME( in, linelength + crlflength ); 161 return( CH_DONE ); 162 } 163 LOG(log_info, logtype_papd, "cq_k4login: %s.%s@%s", ad.pname, ad.pinst, 164 ad.prealm ); 165 lp_person( ad.pname ); 166 lp_host( ad.prealm ); 167 168 append( out, LoginOK, strlen( LoginOK )); 169 compop(); 170 CONSUME( in, linelength + crlflength); 171 return( CH_DONE ); 172} 173 174char *uameth = "UMICHKerberosIV\n*\n"; 175 176int cq_uameth( struct papfile *in, struct papfile *out) 177{ 178 char *start; 179 int linelength, crlflength; 180 struct papd_comment *c, *comment = compeek(); 181 182 for (;;) { 183 switch ( markline( in, &start, &linelength, &crlflength )) { 184 case 0 : 185 return( 0 ); 186 187 case -1 : 188 return( CH_MORE ); 189 190 case -2 : 191 return( CH_ERROR ); 192 } 193 194 if ( comgetflags() == 0 ) { /* start */ 195 if (( printer->p_flags & P_KRB ) == 0 ) { /* no kerberos */ 196 if ( comswitch( queries, cq_default ) < 0 ) { 197 LOG(log_error, logtype_papd, "cq_uameth: can't find default!" ); 198 exit( 1 ); 199 } 200 return( CH_DONE ); 201 } 202 comsetflags( 1 ); 203 } else { 204 if ( comcmp( start, stop, comment->c_end, 0 ) == 0 ) { /* end */ 205 append( out, uameth, strlen( uameth )); 206 compop(); 207 return( CH_DONE ); 208 } 209 } 210 211 CONSUME( in, linelength + crlflength ); 212 } 213} 214#endif /* KRB */ 215 216int gq_true( struct papfile *out) 217{ 218 if ( printer->p_flags & P_SPOOLED ) { 219 append( out, "true\n", 5 ); 220 return( 0 ); 221 } else { 222 return( -1 ); 223 } 224} 225 226int gq_pagecost( struct papfile *out) 227{ 228 char cost[ 60 ]; 229 230 /* check for spooler? XXX */ 231 if ( printer->p_pagecost_msg != NULL ) { 232 append( out, printer->p_pagecost_msg, 233 strlen( printer->p_pagecost_msg )); 234 } else if ( printer->p_flags & P_ACCOUNT ) { 235#ifdef ABS_PRINT 236 lp_pagecost(); 237#endif /* ABS_PRINT */ 238 sprintf( cost, "%d", printer->p_pagecost ); 239 append( out, cost, strlen( cost )); 240 } else { 241 return( -1 ); 242 } 243 append( out, "\n", 1 ); 244 return( 0 ); 245} 246 247#ifdef ABS_PRINT 248int gq_balance( struct papfile *out) 249{ 250 char balance[ 60 ]; 251 252 if ( lp_pagecost() != 0 ) { 253 return( -1 ); 254 } 255 sprintf( balance, "$%1.2f\n", printer->p_balance ); 256 append( out, balance, strlen( balance )); 257 return( 0 ); 258} 259#endif /* ABS_PRINT */ 260 261 262/* 263 * Handler for RBISpoolerID 264 */ 265 266static const char *spoolerid = "(PAPD Spooler) 1.0 (" VERSION ")\n"; 267 268int gq_rbispoolerid( struct papfile *out) 269{ 270 append( out, spoolerid, strlen( spoolerid )); 271 return(0); 272} 273 274 275 276/* 277 * Handler for RBIUAMListQuery 278 */ 279 280static const char *nouams = "*\n"; 281 282int gq_rbiuamlist( struct papfile *out) 283{ 284 char uamnames[128] = "\0"; 285 286 if (printer->p_flags & P_AUTH_PSSP) { 287 if (getuamnames(UAM_SERVER_PRINTAUTH, uamnames) < 0) { 288 append(out, nouams, strlen(nouams)); 289 return(0); 290 } else { 291 append(out, uamnames, strlen(uamnames)); 292 return(0); 293 } 294 } else { 295 append(out, nouams, strlen(nouams)); 296 return(0); 297 } 298} 299 300 301struct genquery { 302 char *gq_name; 303 int (*gq_handler)(); 304} genqueries[] = { 305 { "UMICHCostPerPage", gq_pagecost }, 306#ifdef notdef 307 { "UMICHUserBalance", gq_balance }, 308#endif /* notdef */ 309 { "RBISpoolerID", gq_rbispoolerid }, 310 { "RBIUAMListQuery", gq_rbiuamlist }, 311 { "ADOIsBinaryOK?", gq_true }, 312 { "UMICHListQueue", gq_true }, 313 { "UMICHDeleteJob", gq_true }, 314 { NULL, NULL }, 315}; 316 317int cq_query( struct papfile *in, struct papfile *out) 318{ 319 char *start, *stop, *p, *q; 320 int linelength, crlflength; 321 struct papd_comment *comment = compeek(); 322 struct genquery *gq; 323 324 325 for (;;) { 326 switch ( markline( in, &start, &linelength, &crlflength )) { 327 case 0 : 328 return( 0 ); 329 330 case -1 : 331 return( CH_MORE ); 332 333 case -2 : 334 return( CH_ERROR ); 335 } 336 337 stop = start+linelength; 338 339 if ( comgetflags() == 0 ) { /* started */ 340 comsetflags( 1 ); 341 342 for ( p = start; p < stop; p++ ) { 343 if ( *p == ':' ) { 344 break; 345 } 346 } 347 348 if (p < stop) for ( p++; p < stop; p++ ) { 349 if ( *p != ' ' && *p != '\t' ) { 350 break; 351 } 352 } 353 354 for ( q = p; q < stop; q++ ) { 355 if ( *q == ' ' || *q == '\t' || *q == '\r' || *q == '\n' ) { 356 break; 357 } 358 } 359 360 for ( gq = genqueries; gq->gq_name; gq++ ) { 361 if (( strlen( gq->gq_name ) == (size_t)(q - p) ) && 362 ( strncmp( gq->gq_name, p, q - p ) == 0 )) { 363 break; 364 } 365 } 366 if ( gq->gq_name == NULL || gq->gq_handler == NULL || 367 (gq->gq_handler)( out ) < 0 ) { 368 if ( comswitch( queries, cq_default ) < 0 ) { 369 LOG(log_error, logtype_papd, "cq_feature: can't find default!" ); 370 exit( 1 ); 371 } 372 return( CH_DONE ); 373 } 374 } else { 375 if ( comcmp( start, stop, comment->c_end, 0 ) == 0 ) { 376 compop(); 377 CONSUME( in, linelength + crlflength ); 378 return( CH_DONE ); 379 } 380 } 381 382 CONSUME( in, linelength + crlflength ); 383 } 384} 385 386void cq_font_answer( char *start, char *stop, struct papfile *out) 387{ 388 char *p, *q, buf[ 256 ]; 389 struct ppd_font *pfo; 390 391 p = start; 392 while ( p < stop ) { 393 unsigned int count = 0; 394 while (( *p == ' ' || *p == '\t' ) && p < stop ) { 395 p++; 396 } 397 398 q = buf; 399 while ( *p != ' ' && *p != '\t' && 400 *p != '\n' && *p != '\r' && p < stop && count < sizeof(buf)) { 401 *q++ = *p++; 402 count++; 403 } 404 405 if ( q != buf ) { 406 *q = '\0'; 407 408 append( out, "/", 1 ); 409 append( out, buf, strlen( buf )); 410 append( out, ":", 1 ); 411 412 if (( pfo = ppd_font( buf )) == NULL ) { 413 append( out, "No\n", 3 ); 414 } else { 415 append( out, "Yes\n", 4 ); 416 } 417 } 418 } 419 420 return; 421} 422 423int cq_font(struct papfile *in, struct papfile *out) 424{ 425 char *start, *stop, *p; 426 int linelength, crlflength; 427 struct papd_comment *comment = compeek(); 428 429 for (;;) { 430 switch ( markline( in, &start, &linelength, &crlflength )) { 431 case 0 : 432 return( 0 ); 433 434 case -1 : 435 return( CH_MORE ); 436 437 case -2 : 438 return( CH_ERROR ); 439 } 440 441 stop = start + linelength; 442 443 if ( comgetflags() == 0 ) { 444 comsetflags( 1 ); 445 446 for ( p = start; p < stop; p++ ) { 447 if ( *p == ':' ) { 448 break; 449 } 450 } 451 if (p < stop) 452 p++; 453 454 cq_font_answer( p, stop, out ); 455 } else { 456 if ( comgetflags() == 1 && 457 comcmp( start, stop, comcont, 0 ) == 0 ) { 458 /* continuation */ 459 460 for ( p = start; p < stop; p++ ) { 461 if ( *p == ' ' ) { 462 break; 463 } 464 } 465 if (p < stop) 466 p++; 467 468 cq_font_answer( p, stop, out ); 469 } else { 470 comsetflags( 2 ); 471 if ( comcmp( start, stop, comment->c_end, 0 ) == 0 ) { 472 append( out, "*\n", 2 ); 473 compop(); 474 CONSUME( in, linelength + crlflength ); 475 return( CH_DONE ); 476 } 477 } 478 } 479 480 CONSUME( in, linelength + crlflength ); 481 } 482} 483 484int cq_feature( struct papfile *in, struct papfile *out) 485{ 486 char *start, *stop, *p; 487 int linelength, crlflength; 488 struct papd_comment *comment = compeek(); 489 struct ppd_feature *pfe; 490 491 for (;;) { 492 switch ( markline( in, &start, &linelength, &crlflength )) { 493 case 0 : 494 return( 0 ); 495 496 case -1 : 497 return( CH_MORE ); 498 499 case -2 : 500 return( CH_ERROR ); 501 } 502 503 stop = start + linelength; 504 505 if ( comgetflags() == 0 ) { 506 comsetflags( 1 ); 507 508 /* parse for feature */ 509 for ( p = start; p < stop; p++ ) { 510 if ( *p == ':' ) { 511 break; 512 } 513 } 514 if (p < stop) 515 p++; 516 while ( *p == ' ' ) { 517 p++; 518 } 519 520 if (( pfe = ppd_feature( p, stop - p )) == NULL ) { 521 if ( comswitch( queries, cq_default ) < 0 ) { 522 LOG(log_error, logtype_papd, "cq_feature: can't find default!" ); 523 exit( 1 ); 524 } 525 return( CH_DONE ); 526 } 527 528 append( out, pfe->pd_value, strlen( pfe->pd_value )); 529 append( out, "\r", 1 ); 530 } else { 531 if ( comcmp( start, stop, comment->c_end, 0 ) == 0 ) { 532 compop(); 533 CONSUME( in, linelength + crlflength ); 534 return( CH_DONE ); 535 } 536 } 537 538 CONSUME( in, linelength + crlflength ); 539 } 540} 541 542static const char *psver = "*PSVersion\n"; 543static const char *prod = "*Product\n"; 544 545int cq_printer(struct papfile *in, struct papfile *out) 546{ 547 char *start, *p; 548 int linelength, crlflength; 549 struct papd_comment *comment = compeek(); 550 struct ppd_feature *pdpsver, *pdprod; 551 552 for (;;) { 553 switch ( markline( in, &start, &linelength, &crlflength )) { 554 case 0 : 555 return( 0 ); 556 557 case -1 : 558 return( CH_MORE ); 559 560 case -2 : 561 return( CH_ERROR ); 562 } 563 564 if ( comgetflags() == 0 ) { 565 comsetflags( 1 ); 566 567 if (( pdpsver = ppd_feature( psver, strlen( psver ))) == NULL ) { 568 if ( comswitch( queries, cq_default ) < 0 ) { 569 LOG(log_error, logtype_papd, "cq_printer: can't find default!" ); 570 exit( 1 ); 571 } 572 return( CH_DONE ); 573 } 574 575 for ( p = pdpsver->pd_value; *p != '\0'; p++ ) { 576 if ( *p == ' ' ) { 577 break; 578 } 579 } 580 if ( *p == '\0' ) { 581 LOG(log_error, logtype_papd, "cq_printer: can't parse PSVersion!" ); 582 if ( comswitch( queries, cq_default ) < 0 ) { 583 LOG(log_error, logtype_papd, "cq_printer: can't find default!" ); 584 exit( 1 ); 585 } 586 return( CH_DONE ); 587 } 588 589 if (( pdprod = ppd_feature( prod, strlen( prod ))) == NULL ) { 590 if ( comswitch( queries, cq_default ) < 0 ) { 591 LOG(log_error, logtype_papd, "cq_printer: can't find default!" ); 592 exit( 1 ); 593 } 594 return( CH_DONE ); 595 } 596 597 /* revision */ 598 append( out, p + 1, strlen( p + 1 )); 599 append( out, "\r", 1 ); 600 601 /* version */ 602 append( out, pdpsver->pd_value, p - pdpsver->pd_value ); 603 append( out, "\r", 1 ); 604 605 /* product */ 606 append( out, pdprod->pd_value, strlen( pdprod->pd_value )); 607 append( out, "\r", 1 ); 608 } else { 609 if ( comcmp( start, start+linelength, comment->c_end, 0 ) == 0 ) { 610 compop(); 611 CONSUME( in, linelength + crlflength ); 612 return( CH_DONE ); 613 } 614 } 615 616 CONSUME( in, linelength + crlflength ); 617 } 618} 619 620#ifndef HAVE_CUPS 621 622static const char *rmjobfailed = "Failed\n"; 623static const char *rmjobok = "Ok\n"; 624 625int cq_rmjob( struct papfile *in, struct papfile *out) 626{ 627 char *start, *stop, *p; 628 int linelength, crlflength; 629 int job; 630 631 switch ( markline( in, &start, &linelength, &crlflength )) { 632 case 0 : 633 return( 0 ); 634 635 case -1 : 636 return( CH_MORE ); 637 638 case -2 : 639 return( CH_ERROR ); 640 } 641 642 stop = start + linelength; 643 644 for ( p = start; p < stop; p++ ) { 645 if ( *p == ' ' || *p == '\t' ) { 646 break; 647 } 648 } 649 for ( ; p < stop; p++ ) { 650 if ( *p != ' ' && *p != '\t' ) { 651 break; 652 } 653 } 654 655 *stop = '\0'; 656 if ( p < stop && ( job = atoi( p )) > 0 ) { 657 lp_rmjob( job ); 658 append( out, rmjobok, strlen( rmjobok )); 659 } else { 660 append( out, rmjobfailed, strlen( rmjobfailed )); 661 } 662 663 compop(); 664 CONSUME( in, linelength + crlflength ); 665 return( CH_DONE ); 666} 667 668int cq_listq( struct papfile *in, struct papfile *out) 669{ 670 char *start; 671 int linelength, crlflength; 672 673 switch ( markline( in, &start, &linelength, &crlflength )) { 674 case 0 : 675 return( 0 ); 676 677 case -1 : 678 return( CH_MORE ); 679 680 case -2 : 681 return( CH_ERROR ); 682 } 683 684 if ( lp_queue( out )) { 685 LOG(log_error, logtype_papd, "cq_listq: lp_queue failed" ); 686 } 687 688 compop(); 689 CONSUME( in, linelength + crlflength ); 690 return( CH_DONE ); 691} 692#endif /* HAVE_CUPS */ 693 694 695/* 696 * Handler for RBILogin 697 */ 698 699static struct uam_obj *papd_uam = NULL; 700static const char *rbiloginok = "0\r"; 701static const char *rbiloginbad = "-1\r"; 702static const char *rbiloginerrstr = "%%[Error: SecurityError; \ 703SecurityViolation: Unknown user, incorrect password or log on is \ 704disabled ]%%\r%%[Flushing: rest of job (to end-of-file) will be \ 705ignored ]%%\r"; 706 707int cq_rbilogin( struct papfile *in, struct papfile *out) 708{ 709 char *start, *stop, *p, *begin; 710 int linelength, crlflength; 711 char username[UAM_USERNAMELEN + 1] = "\0"; 712 struct papd_comment *comment = compeek(); 713 char uamtype[20]; 714 715 for (;;) { 716 switch ( markline( in, &start, &linelength, &crlflength )) { 717 case 0 : 718 return( 0 ); 719 720 case -1 : 721 return( CH_MORE ); 722 723 case -2 : 724 return( CH_ERROR ); 725 } 726 727 stop = start + linelength; 728 729 if ( comgetflags() == 0 ) { /* first line */ 730 begin = start + strlen(comment->c_begin); 731 p = begin; 732 733 while (*p != ' ' && p < stop) { 734 p++; 735 } 736 737 memset(uamtype, 0, sizeof(uamtype)); 738 if ((size_t)(p -begin) <= sizeof(uamtype) -1) { 739 strncpy(uamtype, begin, p - begin); 740 } 741 742 if ( !*uamtype || (papd_uam = auth_uamfind(UAM_SERVER_PRINTAUTH, 743 uamtype, strlen(uamtype))) == NULL) { 744 LOG(log_info, logtype_papd, "Could not find uam: %s", uamtype); 745 append(out, rbiloginbad, strlen(rbiloginbad)); 746 append(out, rbiloginerrstr, strlen(rbiloginerrstr)); 747 } else { 748 if ( (papd_uam->u.uam_printer(p,stop,username,out)) == 0 ) { 749 lp_person( username ); 750 append(out, rbiloginok, strlen( rbiloginok )); 751 LOG(log_info, logtype_papd, "RBILogin: Logged in '%s'", username); 752 } else { 753 append(out, rbiloginbad, strlen( rbiloginbad)); 754 append(out, rbiloginerrstr, strlen(rbiloginerrstr)); 755 } 756 } 757 comsetflags( 1 ); 758 } else { 759 if ( comcmp( start, stop, comment->c_end, 0 ) == 0 ) { 760 compop(); 761 return( CH_DONE ); 762 } 763 } 764 765 CONSUME( in, linelength + crlflength ); 766 } 767} 768 769 770/* 771 * All queries start with %%?Begin and end with %%?End. Note that the 772 * "Begin"/"End" general queries have to be last. 773 */ 774struct papd_comment queries[] = { 775#ifdef KRB 776 { "%%Login: UMICHKerberosIV", NULL, cq_k4login, 0 }, 777 { "%%?BeginUAMethodsQuery", "%%?EndUAMethodsQuery:", cq_uameth,C_FULL }, 778#endif /* KRB */ 779#ifndef HAVE_CUPS 780 { "%UMICHListQueue", NULL, cq_listq, C_FULL }, 781 { "%UMICHDeleteJob", NULL, cq_rmjob, 0 }, 782#endif /* HAVE_CUPS */ 783 { "%%?BeginQuery: RBILogin ", "%%?EndQuery", cq_rbilogin, 0 }, 784 { "%%?BeginQuery", "%%?EndQuery", cq_query, 0 }, 785 { "%%?BeginFeatureQuery", "%%?EndFeatureQuery", cq_feature, 0 }, 786 { "%%?BeginFontQuery", "%%?EndFontQuery", cq_font, 0 }, 787 { "%%?BeginPrinterQuery", "%%?EndPrinterQuery", cq_printer,C_FULL }, 788 { "%%?Begin", "%%?End", cq_default, 0 }, 789 { NULL, NULL, NULL, 0 }, 790}; 791