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