]> arthur.barton.de Git - netatalk.git/blob - etc/papd/queries.c
check buffer size
[netatalk.git] / etc / papd / queries.c
1 /*
2  * $Id: queries.c,v 1.20 2009-02-02 12:46:45 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         unsigned int count = 0;
402         while (( *p == ' ' || *p == '\t' ) && p < stop ) {
403             p++;
404         }
405
406         q = buf;
407         while ( *p != ' ' && *p != '\t' &&
408                 *p != '\n' && *p != '\r' && p < stop && count < sizeof(buf)) {
409             *q++ = *p++;
410             count++;
411         }
412
413         if ( q != buf ) {
414             *q = '\0';
415
416             append( out, "/", 1 );
417             append( out, buf, strlen( buf ));
418             append( out, ":", 1 );
419
420             if (( pfo = ppd_font( buf )) == NULL ) {
421                 append( out, "No\n", 3 );
422             } else {
423                 append( out, "Yes\n", 4 );
424             }
425         }
426     }
427
428     return;
429 }
430
431 int cq_font( in, out )
432     struct papfile      *in, *out;
433 {
434     char                *start, *stop, *p;
435     int                 linelength, crlflength;
436     struct papd_comment *comment = compeek();
437
438     for (;;) {
439         switch ( markline( in, &start, &linelength, &crlflength )) {
440         case 0 :
441             return( 0 );
442
443         case -1 :
444             return( CH_MORE );
445
446         case -2 :
447             return( CH_ERROR );
448         }
449
450         stop = start + linelength;
451
452         if ( comgetflags() == 0 ) {
453             comsetflags( 1 );
454
455             for ( p = start; p < stop; p++ ) {
456                 if ( *p == ':' ) {
457                     break;
458                 }
459             }
460             p++;
461
462             cq_font_answer( p, stop, out );
463         } else {
464             if ( comgetflags() == 1 &&
465                     comcmp( start, stop, comcont, 0 ) == 0 ) {
466                 /* continuation */
467
468                 for ( p = start; p < stop; p++ ) {
469                     if ( *p == ' ' ) {
470                         break;
471                     }
472                 }
473                 p++;
474
475                 cq_font_answer( p, stop, out );
476             } else {
477                 comsetflags( 2 );
478                 if ( comcmp( start, stop, comment->c_end, 0 ) == 0 ) {
479                     append( out, "*\n", 2 );
480                     compop();
481                     CONSUME( in, linelength + crlflength );
482                     return( CH_DONE );
483                 }
484             }
485         }
486
487         CONSUME( in, linelength + crlflength );
488     }
489 }
490
491 int cq_feature( in, out )
492     struct papfile      *in, *out;
493 {
494     char                *start, *stop, *p;
495     int                 linelength, crlflength;
496     struct papd_comment *comment = compeek();
497     struct ppd_feature  *pfe;
498
499     for (;;) {
500         switch ( markline( in, &start, &linelength, &crlflength )) {
501         case 0 :
502             return( 0 );
503
504         case -1 :
505             return( CH_MORE );
506
507         case -2 :
508             return( CH_ERROR );
509         }
510
511         stop = start + linelength;
512
513         if ( comgetflags() == 0 ) {
514             comsetflags( 1 );
515
516             /* parse for feature */
517             for ( p = start; p < stop; p++ ) {
518                 if ( *p == ':' ) {
519                     break;
520                 }
521             }
522             p++;
523             while ( *p == ' ' ) {
524                 p++;
525             }
526
527             if (( pfe = ppd_feature( p, stop - p )) == NULL ) {
528                 if ( comswitch( queries, cq_default ) < 0 ) {
529                     LOG(log_error, logtype_papd, "cq_feature: can't find default!" );
530                     exit( 1 );
531                 }
532                 return( CH_DONE );
533             }
534
535             append( out, pfe->pd_value, strlen( pfe->pd_value ));
536             append( out, "\r", 1 );
537         } else {
538             if ( comcmp( start, stop, comment->c_end, 0 ) == 0 ) {
539                 compop();
540                 CONSUME( in, linelength + crlflength );
541                 return( CH_DONE );
542             }
543         }
544
545         CONSUME( in, linelength + crlflength );
546     }
547 }
548
549 static const char       *psver = "*PSVersion\n";
550 static const char       *prod = "*Product\n";
551
552 int cq_printer( in, out )
553     struct papfile      *in, *out;
554 {
555     char                *start, *p;
556     int                 linelength, crlflength;
557     struct papd_comment *comment = compeek();
558     struct ppd_feature  *pdpsver, *pdprod;
559
560     for (;;) {
561         switch ( markline( in, &start, &linelength, &crlflength )) {
562         case 0 :
563             return( 0 );
564
565         case -1 :
566             return( CH_MORE );
567
568         case -2 :
569             return( CH_ERROR );
570         }
571
572         if ( comgetflags() == 0 ) {
573             comsetflags( 1 );
574
575             if (( pdpsver = ppd_feature( psver, strlen( psver ))) == NULL ) {
576                 if ( comswitch( queries, cq_default ) < 0 ) {
577                     LOG(log_error, logtype_papd, "cq_printer: can't find default!" );
578                     exit( 1 );
579                 }
580                 return( CH_DONE );
581             }
582
583             for ( p = pdpsver->pd_value; *p != '\0'; p++ ) {
584                 if ( *p == ' ' ) {
585                     break;
586                 }
587             }
588             if ( *p == '\0' ) {
589                 LOG(log_error, logtype_papd, "cq_printer: can't parse PSVersion!" );
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             if (( pdprod = ppd_feature( prod, strlen( prod ))) == NULL ) {
598                 if ( comswitch( queries, cq_default ) < 0 ) {
599                     LOG(log_error, logtype_papd, "cq_printer: can't find default!" );
600                     exit( 1 );
601                 }
602                 return( CH_DONE );
603             }
604
605             /* revision */
606             append( out, p + 1, strlen( p + 1 ));
607             append( out, "\r", 1 );
608
609             /* version */
610             append( out, pdpsver->pd_value, p - pdpsver->pd_value );
611             append( out, "\r", 1 );
612
613             /* product */
614             append( out, pdprod->pd_value, strlen( pdprod->pd_value ));
615             append( out, "\r", 1 );
616         } else {
617             if ( comcmp( start, start+linelength, comment->c_end, 0 ) == 0 ) {
618                 compop();
619                 CONSUME( in, linelength + crlflength );
620                 return( CH_DONE );
621             }
622         }
623
624         CONSUME( in, linelength + crlflength );
625     }
626 }
627
628 #ifndef HAVE_CUPS
629
630 static const char       *rmjobfailed = "Failed\n";
631 static const char       *rmjobok = "Ok\n";
632
633 int cq_rmjob( in, out )
634     struct papfile      *in, *out;
635 {
636     char                *start, *stop, *p;
637     int                 linelength, crlflength;
638     int                 job;
639
640     switch ( markline( in, &start, &linelength, &crlflength )) {
641     case 0 :
642         return( 0 );
643
644     case -1 :
645         return( CH_MORE );
646
647     case -2 :
648         return( CH_ERROR );
649     }
650
651     stop = start + linelength;
652
653     for ( p = start; p < stop; p++ ) {
654         if ( *p == ' ' || *p == '\t' ) {
655             break;
656         }
657     }
658     for ( ; p < stop; p++ ) {
659         if ( *p != ' ' && *p != '\t' ) {
660             break;
661         }
662     }
663
664     *stop = '\0';
665     if ( p < stop && ( job = atoi( p )) > 0 ) {
666         lp_rmjob( job );
667         append( out, rmjobok, strlen( rmjobok ));
668     } else {
669         append( out, rmjobfailed, strlen( rmjobfailed ));
670     }
671
672     compop();
673     CONSUME( in, linelength + crlflength );
674     return( CH_DONE );
675 }
676
677 int cq_listq( in, out )
678     struct papfile      *in, *out;
679 {
680     char                *start;
681     int                 linelength, crlflength;
682
683     switch ( markline( in, &start, &linelength, &crlflength )) {
684     case 0 :
685         return( 0 );
686
687     case -1 :
688         return( CH_MORE );
689
690     case -2 :
691         return( CH_ERROR );
692     }
693
694     if ( lp_queue( out )) {
695         LOG(log_error, logtype_papd, "cq_listq: lp_queue failed" );
696     }
697
698     compop();
699     CONSUME( in, linelength + crlflength );
700     return( CH_DONE );
701 }
702 #endif /* HAVE_CUPS */
703
704
705 /*
706  * Handler for RBILogin
707  */
708
709 static struct uam_obj *papd_uam = NULL;
710 static const char *rbiloginok = "0\r";
711 static const char *rbiloginbad = "-1\r";
712 static const char *rbiloginerrstr = "%%[Error: SecurityError; \
713 SecurityViolation: Unknown user, incorrect password or log on is \
714 disabled ]%%\r%%[Flushing: rest of job (to end-of-file) will be \
715 ignored ]%%\r";
716
717 int cq_rbilogin( in, out )
718     struct papfile      *in, *out;
719 {
720     char                *start, *stop, *p, *begin;
721     int                 linelength, crlflength;
722     char                username[UAM_USERNAMELEN + 1] = "\0";
723     struct papd_comment *comment = compeek();
724     char                uamtype[20];
725
726     for (;;) {
727         switch ( markline( in, &start, &linelength, &crlflength )) {
728         case 0 :
729             return( 0 );
730
731         case -1 :
732             return( CH_MORE );
733
734         case -2 :
735             return( CH_ERROR );
736         }
737
738         stop = start + linelength;
739
740         if ( comgetflags() == 0 ) { /* first line */
741             begin = start + strlen(comment->c_begin);
742             p = begin;
743
744             while (*p != ' ' && p < stop) {
745                 p++;
746             }
747
748             memset(uamtype, 0, sizeof(uamtype));
749             if ((size_t)(p -begin) <= sizeof(uamtype) -1) {
750                 strncpy(uamtype, begin, p - begin);
751             }
752
753             if ( !*uamtype || (papd_uam = auth_uamfind(UAM_SERVER_PRINTAUTH,
754                                 uamtype, strlen(uamtype))) == NULL) {
755                 LOG(log_info, logtype_papd, "Could not find uam: %s", uamtype);
756                 append(out, rbiloginbad, strlen(rbiloginbad));
757                 append(out, rbiloginerrstr, strlen(rbiloginerrstr));
758             } else {
759                 if ( (papd_uam->u.uam_printer(p,stop,username,out)) == 0 ) {
760                     lp_person( username );
761                    append(out, rbiloginok, strlen( rbiloginok ));
762                    LOG(log_info, logtype_papd, "RBILogin: Logged in '%s'", username);
763                 } else {
764                     append(out, rbiloginbad, strlen( rbiloginbad));
765                     append(out, rbiloginerrstr, strlen(rbiloginerrstr));
766                 }
767             }
768             comsetflags( 1 );
769         } else {
770             if ( comcmp( start, stop, comment->c_end, 0 ) == 0 ) {
771                 compop();
772                 return( CH_DONE );
773             }
774         }
775
776         CONSUME( in, linelength + crlflength );
777     }
778 }
779
780
781 /*
782  * All queries start with %%?Begin and end with %%?End.  Note that the
783  * "Begin"/"End" general queries have to be last.
784  */
785 struct papd_comment     queries[] = {
786 #ifdef KRB
787     { "%%Login: UMICHKerberosIV", NULL,                 cq_k4login,     0 },
788     { "%%?BeginUAMethodsQuery", "%%?EndUAMethodsQuery:", cq_uameth,C_FULL },
789 #endif /* KRB */
790 #ifndef HAVE_CUPS
791     { "%UMICHListQueue",        NULL,                   cq_listq,  C_FULL },
792     { "%UMICHDeleteJob",        NULL,                   cq_rmjob,       0 },
793 #endif /* HAVE_CUPS */
794     { "%%?BeginQuery: RBILogin ", "%%?EndQuery",        cq_rbilogin,    0 },
795     { "%%?BeginQuery",          "%%?EndQuery",          cq_query,       0 },
796     { "%%?BeginFeatureQuery",   "%%?EndFeatureQuery",   cq_feature,     0 },
797     { "%%?BeginFontQuery",      "%%?EndFontQuery",      cq_font,        0 },
798     { "%%?BeginPrinterQuery",   "%%?EndPrinterQuery",   cq_printer,C_FULL },
799     { "%%?Begin",               "%%?End",               cq_default,     0 },
800     { NULL,                     NULL,                   NULL,           0 },
801 };