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