Print this page
2837 - remove print/lp* from gate and use CUPS from userland


   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  *
  26  */



  27 
  28 /* $Id: mod_ipp.c 149 2006-04-25 16:55:01Z njacobs $ */
  29 
  30 #pragma ident   "%Z%%M% %I%     %E% SMI"
  31 
  32 /*
  33  * Internet Printing Protocol (IPP) module for Apache.
  34  */
  35 
  36 #include "ap_config.h"
  37 
  38 #include <stdio.h>
  39 #include <time.h>
  40 #include <sys/time.h>
  41 #include <values.h>
  42 #include <libintl.h>
  43 #include <alloca.h>
  44 
  45 #include "httpd.h"
  46 #include "http_config.h"
  47 #include "http_core.h"
  48 #include "http_protocol.h"
  49 #include "http_log.h"
  50 #include "http_main.h"
  51 #include "papi.h"
  52 #ifndef APACHE_RELEASE  /* appears to only exist in Apache 1.X */
  53 #define APACHE2
  54 #include "apr_compat.h"








  55 #endif
  56 
  57 #include <papi.h>
  58 #include <ipp-listener.h>
  59 
  60 #ifndef APACHE2
  61 module MODULE_VAR_EXPORT ipp_module;
  62 #else
  63 module AP_MODULE_DECLARE_DATA ipp_module;
  64 #endif
  65 
  66 #ifndef AP_INIT_TAKE1   /* Apache 2.X has this, but 1.3.X does not */
  67 #define AP_INIT_NO_ARGS(directive, action, arg, where, mesg) \
  68         { directive, action, arg, where, NO_ARGS, mesg }
  69 #define AP_INIT_TAKE1(directive, action, arg, where, mesg) \
  70         { directive, action, arg, where, TAKE1, mesg }
  71 #define AP_INIT_TAKE2(directive, action, arg, where, mesg) \
  72         { directive, action, arg, where, TAKE2, mesg }
  73 #endif
  74 
  75 typedef struct {
  76         int conformance;
  77         char *default_user;
  78         char *default_svc;
  79         papi_attribute_t **operations;
  80 } IPPListenerConfig;


 100                 fprintf(fp, "    ");
 101                 for (j = 0; j < 16 && (i + j) < bytes; j ++) {
 102                         ch = buffer[i + j] & 255;
 103                         if (ch < ' ' || ch == 127)
 104                                 ch = '.';
 105                         putc(ch, fp);
 106                 }
 107                 putc('\n', fp);
 108         }
 109         fflush(fp);
 110 }
 111 #endif
 112 
 113 static ssize_t
 114 read_data(void *fd, void *buf, size_t siz)
 115 {
 116         ssize_t len_read;
 117         request_rec *ap_r = (request_rec *)fd;
 118 
 119         len_read = ap_get_client_block(ap_r, buf, siz);
 120 #ifndef APACHE2
 121         ap_reset_timeout(ap_r);
 122 #endif
 123 
 124 #ifdef DEBUG
 125         fprintf(stderr, "read_data(0x%8.8x, 0x%8.8x, %d): %d",
 126                         fd, buf, siz, len_read);
 127         if (len_read < 0)
 128                 fprintf(stderr, ": %s", strerror(errno));
 129         putc('\n', stderr);
 130         dump_buffer(stderr, "read_data:", buf, len_read);
 131 #endif
 132 
 133         return (len_read);
 134 }
 135 
 136 static ssize_t
 137 write_data(void *fd, void *buf, size_t siz)
 138 {
 139         ssize_t len_written;
 140         request_rec *ap_r = (request_rec *)fd;
 141 
 142 #ifndef APACHE2
 143         ap_reset_timeout(ap_r);
 144 #endif
 145 #ifdef DEBUG
 146         dump_buffer(stderr, "write_data:", buf, siz);
 147 #endif
 148         len_written = ap_rwrite(buf, siz, ap_r);
 149 
 150         return (len_written);
 151 }
 152 
 153 static void
 154 discard_data(request_rec *r)
 155 {
 156 #ifdef APACHE2
 157         (void) ap_discard_request_body(r);
 158 #else
 159         /*
 160          * This is taken from ap_discard_request_body().  The reason we can't
 161          * just use it in Apache 1.3 is that it does various timeout things we
 162          * don't want it to do.  Apache 2.0 doesn't do that, so we can safely
 163          * use the normal function.
 164          */
 165         if (r->read_chunked || r->remaining > 0) {
 166                 char dumpbuf[HUGE_STRING_LEN];
 167                 int i;
 168 
 169                 do {
 170                         i = ap_get_client_block(r, dumpbuf, HUGE_STRING_LEN);
 171 #ifdef DEBUG
 172                         dump_buffer(stderr, "discarded", dumpbuf, i);
 173 #endif
 174                 } while (i > 0);
 175         }
 176 #endif
 177 }
 178 




 179 void _log_rerror(const char *file, int line, int level, request_rec *r,
 180         const char *fmt, ...)

 181 {
 182         va_list args;
 183         size_t size;
 184         char *message = alloca(BUFSIZ);
 185 
 186         va_start(args, fmt);
 187         /*
 188          * fill in the message.  If the buffer is too small, allocate
 189          * one that is large enough and fill it in.
 190          */
 191         if ((size = vsnprintf(message, BUFSIZ, fmt, args)) >= BUFSIZ)
 192                 if ((message = alloca(size)) != NULL)
 193                         vsnprintf(message, size, fmt, args);
 194         va_end(args);
 195 
 196 #ifdef APACHE2


 197         ap_log_rerror(file, line, level, NULL, r, message);
 198 #else
 199         ap_log_rerror(file, line, level, r, message);
 200 #endif
 201 }
 202 
 203 static int
 204 ipp_handler(request_rec *r)
 205 {
 206         papi_attribute_t **request = NULL, **response = NULL;
 207         IPPListenerConfig *config;
 208         papi_status_t status;
 209         int ret;




 210 
 211         /* Really, IPP is all POST requests */
 212         if (r->method_number != M_POST)
 213                 return (DECLINED);
 214 
 215 #ifndef APACHE2
 216         /*
 217          * An IPP request must have a MIME type of "application/ipp"
 218          * (RFC-2910, Section 4, page 19).  If it doesn't match this
 219          * MIME type, we should decline the request and let someone else
 220          * try and handle it.
 221          */
 222         if (r->headers_in != NULL) {
 223                 char *mime_type = (char *)ap_table_get(r->headers_in,
 224                                                         "Content-Type");
 225 
 226                 if ((mime_type == NULL) ||
 227                     (strcasecmp(mime_type, "application/ipp") != 0))
 228                         return (DECLINED);
 229         }
 230 #endif
 231         /* CHUNKED_DECHUNK might not work right for IPP? */
 232         if ((ret = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) != OK)
 233                 return (ret);
 234 
 235         if (!ap_should_client_block(r))
 236                 return (HTTP_INTERNAL_SERVER_ERROR);
 237 
 238 #ifndef APACHE2
 239         ap_soft_timeout("ipp_module: read/reply request ", r);
 240 #endif
 241         /* read the IPP request off the network */
 242         status = ipp_read_message(read_data, r, &request, IPP_TYPE_REQUEST);
 243 
 244         if (status != PAPI_OK)
 245                 _log_rerror(APLOG_MARK, APLOG_ERR, r,
 246                         "read failed: %s\n", papiStatusString(status));
 247 #ifdef DEBUG
 248         papiAttributeListPrint(stderr, request, "request (%d)  ", getpid());
 249 #endif
 250 
 251         (void) papiAttributeListAddString(&request, PAPI_ATTR_EXCL,
 252                 "originating-host", (char *)
 253 #ifdef APACHE2
 254                 ap_get_remote_host
 255                         (r->connection, r->per_dir_config, REMOTE_NAME, NULL));
 256 #else
 257                 ap_get_remote_host
 258                         (r->connection, r->per_dir_config, REMOTE_NAME));
 259 #endif
 260 
 261         (void) papiAttributeListAddInteger(&request, PAPI_ATTR_EXCL,
 262                                 "uri-port", ap_get_server_port(r));
 263         if (r->headers_in != NULL) {



 264                 char *host = (char *)ap_table_get(r->headers_in, "Host");

 265 
 266                 if ((host == NULL) || (host[0] == '\0'))
 267                         host = (char *)ap_get_server_name(r);
 268 
 269                 (void) papiAttributeListAddString(&request, PAPI_ATTR_EXCL,
 270                                 "uri-host", host);
 271         }
 272         (void) papiAttributeListAddString(&request, PAPI_ATTR_EXCL,
 273                                 "uri-path", r->uri);
 274 
 275         config = ap_get_module_config(r->per_dir_config, &ipp_module);
 276         if (config != NULL) {
 277                 (void) papiAttributeListAddInteger(&request, PAPI_ATTR_EXCL,
 278                                 "conformance", config->conformance);
 279                 (void) papiAttributeListAddCollection(&request, PAPI_ATTR_EXCL,
 280                                 "operations", config->operations);
 281                 if (config->default_user != NULL)
 282                         (void) papiAttributeListAddString(&request,
 283                                                 PAPI_ATTR_EXCL, "default-user",
 284                                                 config->default_user);
 285                 if (config->default_svc != NULL)
 286                         (void) papiAttributeListAddString(&request,
 287                                         PAPI_ATTR_EXCL, "default-service",
 288                                         config->default_svc);
 289         }
 290 
 291         /*
 292          * For Trusted Solaris, pass the fd number of the socket connection
 293          * to the backend so the it can be forwarded to the backend print
 294          * service to retrieve the sensativity label off of a multi-level
 295          * port.
 296          */







 297         (void) papiAttributeListAddInteger(&request, PAPI_ATTR_EXCL,
 298                         "peer-socket", ap_bfileno(r->connection->client, B_RD));

 299 
 300         /* process the request */
 301         status = ipp_process_request(request, &response, read_data, r);
 302         if (status != PAPI_OK) {
 303                 errno = 0;
 304                 _log_rerror(APLOG_MARK, APLOG_ERR, r,
 305                         "request failed: %s\n", papiStatusString(status));
 306                 discard_data(r);
 307         }
 308 #ifdef DEBUG
 309         fprintf(stderr, "processing result: %s\n", papiStatusString(status));
 310         papiAttributeListPrint(stderr, response, "response (%d)  ", getpid());
 311 #endif
 312 
 313         /*
 314          * If the client is using chunking and we have not yet received the
 315          * final "0" sized chunk, we need to discard any data that may
 316          * remain in the post request.
 317          */
 318         if ((r->read_chunked != 0) &&



 319             (ap_table_get(r->headers_in, "Content-Length") == NULL))

 320                 discard_data(r);
 321 
 322         /* write an IPP response back to the network */
 323         r->content_type = "application/ipp";
 324 
 325 #ifndef APACHE2
 326         ap_send_http_header(r);
 327 #endif
 328 
 329         status = ipp_write_message(write_data, r, response);
 330         if (status != PAPI_OK)
 331                 _log_rerror(APLOG_MARK, APLOG_ERR, r,
 332                         "write failed: %s\n", papiStatusString(status));
 333 #ifdef DEBUG
 334         fprintf(stderr, "write result: %s\n", papiStatusString(status));
 335         fflush(stderr);
 336 #endif
 337 
 338         papiAttributeListFree(request);
 339         papiAttributeListFree(response);
 340 
 341 #ifndef APACHE2
 342         ap_kill_timeout(r);
 343         if (ap_rflush(r) < 0)
 344                 _log_rerror(APLOG_MARK, APLOG_ERR, r,
 345                         "flush failed, response may not have been sent");
 346 #endif
 347 
 348         return (OK);
 349 }
 350 
 351 
 352 /*ARGSUSED1*/
 353 static void *
 354 create_ipp_dir_config(
 355 #ifndef APACHE2
 356         pool *p,
 357 #else
 358         apr_pool_t *p,
 359 #endif
 360         char *dirspec)
 361 {
 362         IPPListenerConfig *config =
 363 #ifndef APACHE2
 364                 ap_pcalloc(p, sizeof (*config));
 365 #else
 366                 apr_pcalloc(p, sizeof (*config));
 367 #endif
 368 
 369         if (config != NULL) {
 370                 (void) memset(config, 0, sizeof (*config));
 371                 config->conformance = IPP_PARSE_CONFORMANCE_RASH;
 372                 config->default_user = NULL;
 373                 config->default_svc = NULL;
 374                 (void) ipp_configure_operation(&config->operations, "required",
 375                                 "enable");
 376         }
 377 
 378         return (config);
 379 }
 380 
 381 /*ARGSUSED0*/
 382 static const char *
 383 ipp_conformance(cmd_parms *cmd, void *cfg, const char *arg)
 384 {
 385         IPPListenerConfig *config = (IPPListenerConfig *)cfg;
 386 
 387         if (strncasecmp(arg, "automatic", 4) == 0) {
 388                 config->conformance = IPP_PARSE_CONFORMANCE_RASH;
 389         } else if (strcasecmp(arg, "1.0") == 0) {
 390                 config->conformance = IPP_PARSE_CONFORMANCE_LOOSE;
 391         } else if (strcasecmp(arg, "1.1") == 0) {
 392                 config->conformance = IPP_PARSE_CONFORMANCE_STRICT;
 393         } else {
 394                 return ("unknown conformance, try (automatic/1.0/1.1)");
 395         }
 396 
 397         return (NULL);
 398 }
 399 
 400 /*ARGSUSED0*/
 401 static const char *
 402 ipp_operation(cmd_parms *cmd, void *cfg, char *op, char *toggle)
 403 {
 404         IPPListenerConfig *config = (IPPListenerConfig *)cfg;
 405         papi_status_t status;
 406 
 407         status = ipp_configure_operation(&config->operations, op, toggle);
 408         switch (status) {
 409         case PAPI_OK:
 410                 return (NULL);
 411         case PAPI_BAD_ARGUMENT:
 412                 return (gettext("internal error (invalid argument)"));
 413         default:
 414                 return (papiStatusString(status));
 415         }
 416 
 417         /* NOTREACHED */
 418         /* return (gettext("contact your software vendor")); */
 419 }
 420 
 421 static const char *
 422 ipp_default_user(cmd_parms *cmd, void *cfg, const char *arg)


 452 }
 453 #endif /* DEBUG */
 454 
 455 static const command_rec ipp_cmds[] =
 456 {
 457         AP_INIT_TAKE1("ipp-conformance", ipp_conformance, NULL, ACCESS_CONF,
 458                 "IPP protocol conformance (loose/strict)"),
 459         AP_INIT_TAKE2("ipp-operation", ipp_operation, NULL, ACCESS_CONF,
 460                 "IPP protocol operations to enable/disable)"),
 461         AP_INIT_TAKE1("ipp-default-user", ipp_default_user, NULL, ACCESS_CONF,
 462                 "default user for various operations"),
 463         AP_INIT_TAKE1("ipp-default-service", ipp_default_svc, NULL, ACCESS_CONF,
 464                 "default service for various operations"),
 465 #ifdef DEBUG
 466         AP_INIT_NO_ARGS("ipp-module-hang", ipp_module_hang, NULL, ACCESS_CONF,
 467                 "hang the module until we can attach a debugger (no args)"),
 468 #endif
 469         { NULL }
 470 };
 471 
 472 #ifdef APACHE2
 473 /*ARGSUSED0*/
 474 static const char *
 475 ipp_method(const request_rec *r)
 476 {
 477         return ("ipp");
 478 }
 479 
 480 /*ARGSUSED0*/
 481 static unsigned short
 482 ipp_port(const request_rec *r)
 483 {
 484         return (631);
 485 }
 486 
 487 /* Dispatch list for API hooks */
 488 /*ARGSUSED0*/
 489 static void
 490 ipp_register_hooks(apr_pool_t *p)
 491 {
 492         static const char * const modules[] = { "mod_dir.c", NULL };
 493 
 494         /* Need to make sure we don't get directory listings by accident */
 495         ap_hook_handler(ipp_handler, NULL, modules, APR_HOOK_MIDDLE);
 496         ap_hook_default_port(ipp_port, NULL, NULL, APR_HOOK_MIDDLE);



 497         ap_hook_http_method(ipp_method, NULL, NULL, APR_HOOK_MIDDLE);

 498 }
 499 
 500 module AP_MODULE_DECLARE_DATA ipp_module = {
 501         STANDARD20_MODULE_STUFF,
 502         create_ipp_dir_config,          /* create per-dir    config     */
 503         NULL,                           /* merge  per-dir    config     */
 504         NULL,                           /* create per-server config     */
 505         NULL,                           /* merge  per-server config     */
 506         ipp_cmds,                       /* table of config commands     */
 507         ipp_register_hooks              /* register hooks               */
 508 };
 509 
 510 #else   /* Apache 1.X */
 511 
 512 /* Dispatch list of content handlers */
 513 static const handler_rec ipp_handlers[] = {
 514         /*
 515          * This handler association causes all IPP request with the
 516          * correct MIME type to call the protocol handler.
 517          */




   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  *
  26  */
  27 /*
  28  * Copyright (c) 2013 Andrew Stormont.  All rights reserved.
  29  */
  30 
  31 /* $Id: mod_ipp.c 149 2006-04-25 16:55:01Z njacobs $ */
  32 


  33 /*
  34  * Internet Printing Protocol (IPP) module for Apache.
  35  */
  36 
  37 #include "ap_config.h"
  38 
  39 #include <stdio.h>
  40 #include <time.h>
  41 #include <sys/time.h>
  42 #include <values.h>
  43 #include <libintl.h>
  44 #include <alloca.h>
  45 
  46 #include "httpd.h"
  47 #include "http_config.h"
  48 #include "http_core.h"
  49 #include "http_protocol.h"
  50 #include "http_log.h"
  51 #include "http_main.h"
  52 #include "papi.h"
  53 /* Try and guess the version of apache */
  54 #ifdef APACHE_RELEASE
  55 # define AP_SERVER_MAJORVERSION_NUMBER 1
  56 # define AP_SERVER_MINORVERSION_NUMBER 0
  57 #else
  58 # ifndef AP_SERVER_MAJORVERSION_NUMBER
  59 #  define AP_SERVER_MAJORVERSION_NUMBER 2
  60 # endif
  61 # ifndef AP_SERVER_MINORVERSION_NUMBER
  62 #  define AP_SERVER_MINORVERSION_NUMBER 0
  63 # endif
  64 #endif
  65 
  66 #include <papi.h>
  67 #include <ipp-listener.h>
  68 
  69 #if AP_SERVER_MAJORVERSION_NUMBER < 2
  70 module MODULE_VAR_EXPORT ipp_module;
  71 #else
  72 module AP_MODULE_DECLARE_DATA ipp_module;
  73 #endif
  74 
  75 #ifndef AP_INIT_TAKE1   /* Apache 2.X has this, but 1.3.X does not */
  76 #define AP_INIT_NO_ARGS(directive, action, arg, where, mesg) \
  77         { directive, action, arg, where, NO_ARGS, mesg }
  78 #define AP_INIT_TAKE1(directive, action, arg, where, mesg) \
  79         { directive, action, arg, where, TAKE1, mesg }
  80 #define AP_INIT_TAKE2(directive, action, arg, where, mesg) \
  81         { directive, action, arg, where, TAKE2, mesg }
  82 #endif
  83 
  84 typedef struct {
  85         int conformance;
  86         char *default_user;
  87         char *default_svc;
  88         papi_attribute_t **operations;
  89 } IPPListenerConfig;


 109                 fprintf(fp, "    ");
 110                 for (j = 0; j < 16 && (i + j) < bytes; j ++) {
 111                         ch = buffer[i + j] & 255;
 112                         if (ch < ' ' || ch == 127)
 113                                 ch = '.';
 114                         putc(ch, fp);
 115                 }
 116                 putc('\n', fp);
 117         }
 118         fflush(fp);
 119 }
 120 #endif
 121 
 122 static ssize_t
 123 read_data(void *fd, void *buf, size_t siz)
 124 {
 125         ssize_t len_read;
 126         request_rec *ap_r = (request_rec *)fd;
 127 
 128         len_read = ap_get_client_block(ap_r, buf, siz);
 129 #if AP_SERVER_MAJORVERSION_NUMBER < 2
 130         ap_reset_timeout(ap_r);
 131 #endif
 132 
 133 #ifdef DEBUG
 134         fprintf(stderr, "read_data(0x%8.8x, 0x%8.8x, %d): %d",
 135                         fd, buf, siz, len_read);
 136         if (len_read < 0)
 137                 fprintf(stderr, ": %s", strerror(errno));
 138         putc('\n', stderr);
 139         dump_buffer(stderr, "read_data:", buf, len_read);
 140 #endif
 141 
 142         return (len_read);
 143 }
 144 
 145 static ssize_t
 146 write_data(void *fd, void *buf, size_t siz)
 147 {
 148         ssize_t len_written;
 149         request_rec *ap_r = (request_rec *)fd;
 150 
 151 #if AP_SERVER_MAJORVERSION_NUMBER < 2
 152         ap_reset_timeout(ap_r);
 153 #endif
 154 #ifdef DEBUG
 155         dump_buffer(stderr, "write_data:", buf, siz);
 156 #endif
 157         len_written = ap_rwrite(buf, siz, ap_r);
 158 
 159         return (len_written);
 160 }
 161 
 162 static void
 163 discard_data(request_rec *r)
 164 {
 165 #if AP_SERVER_MAJORVERSION_NUMBER < 2
 166         (void) ap_discard_request_body(r);
 167 #else
 168         /*
 169          * This is taken from ap_discard_request_body().  The reason we can't
 170          * just use it in Apache 1.3 is that it does various timeout things we
 171          * don't want it to do.  Apache 2.0 doesn't do that, so we can safely
 172          * use the normal function.
 173          */
 174         if (r->read_chunked || r->remaining > 0) {
 175                 char dumpbuf[HUGE_STRING_LEN];
 176                 int i;
 177 
 178                 do {
 179                         i = ap_get_client_block(r, dumpbuf, HUGE_STRING_LEN);
 180 #ifdef DEBUG
 181                         dump_buffer(stderr, "discarded", dumpbuf, i);
 182 #endif
 183                 } while (i > 0);
 184         }
 185 #endif
 186 }
 187 
 188 #if AP_SERVER_MAJORVERSION_NUMBER > 2 || AP_SERVER_MINORVERSION_NUMBER > 3
 189 void _log_rerror(const char *file, int line, int module_index,
 190         int level, request_rec *r, const char *fmt, ...)
 191 #else
 192 void _log_rerror(const char *file, int line, int level, request_rec *r,
 193         const char *fmt, ...)
 194 #endif
 195 {
 196         va_list args;
 197         size_t size;
 198         char *message = alloca(BUFSIZ);
 199 
 200         va_start(args, fmt);
 201         /*
 202          * fill in the message.  If the buffer is too small, allocate
 203          * one that is large enough and fill it in.
 204          */
 205         if ((size = vsnprintf(message, BUFSIZ, fmt, args)) >= BUFSIZ)
 206                 if ((message = alloca(size)) != NULL)
 207                         vsnprintf(message, size, fmt, args);
 208         va_end(args);
 209 
 210 #if AP_SERVER_MAJORVERSION_NUMBER > 2 || AP_SERVER_MINORVERSION_NUMBER > 3
 211         ap_log_rerror(file, line, module_index, level, APR_SUCCESS, r, message);
 212 #elif AP_SERVER_MAJORVERSION_NUMBER > 1
 213         ap_log_rerror(file, line, level, NULL, r, message);
 214 #else
 215         ap_log_rerror(file, line, level, r, message);
 216 #endif
 217 }
 218 
 219 static int
 220 ipp_handler(request_rec *r)
 221 {
 222         papi_attribute_t **request = NULL, **response = NULL;
 223         IPPListenerConfig *config;
 224         papi_status_t status;
 225         int ret;
 226 #if AP_SERVER_MAJORVERSION_NUMBER > 1
 227         apr_os_sock_t *os_sock = NULL;
 228         apr_status_t st;
 229 #endif
 230 
 231         /* Really, IPP is all POST requests */
 232         if (r->method_number != M_POST)
 233                 return (DECLINED);
 234 
 235 #if AP_SERVER_MAJORVERSION_NUMBER < 2
 236         /*
 237          * An IPP request must have a MIME type of "application/ipp"
 238          * (RFC-2910, Section 4, page 19).  If it doesn't match this
 239          * MIME type, we should decline the request and let someone else
 240          * try and handle it.
 241          */
 242         if (r->headers_in != NULL) {
 243                 char *mime_type = (char *)ap_table_get(r->headers_in,
 244                                                         "Content-Type");
 245 
 246                 if ((mime_type == NULL) ||
 247                     (strcasecmp(mime_type, "application/ipp") != 0))
 248                         return (DECLINED);
 249         }
 250 #endif
 251         /* CHUNKED_DECHUNK might not work right for IPP? */
 252         if ((ret = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) != OK)
 253                 return (ret);
 254 
 255         if (!ap_should_client_block(r))
 256                 return (HTTP_INTERNAL_SERVER_ERROR);
 257 
 258 #if AP_SERVER_MAJORVERSION_NUMBER < 2
 259         ap_soft_timeout("ipp_module: read/reply request ", r);
 260 #endif
 261         /* read the IPP request off the network */
 262         status = ipp_read_message(read_data, r, &request, IPP_TYPE_REQUEST);
 263 
 264         if (status != PAPI_OK)
 265                 _log_rerror(APLOG_MARK, APLOG_ERR, r,
 266                         "read failed: %s\n", papiStatusString(status));
 267 #ifdef DEBUG
 268         papiAttributeListPrint(stderr, request, "request (%d)  ", getpid());
 269 #endif
 270 
 271         (void) papiAttributeListAddString(&request, PAPI_ATTR_EXCL,
 272                 "originating-host", (char *)
 273 #if AP_SERVER_MAJORVERSION_NUMBER >= 2
 274                 ap_get_remote_host
 275                         (r->connection, r->per_dir_config, REMOTE_NAME, NULL));
 276 #else
 277                 ap_get_remote_host
 278                         (r->connection, r->per_dir_config, REMOTE_NAME));
 279 #endif
 280 
 281         (void) papiAttributeListAddInteger(&request, PAPI_ATTR_EXCL,
 282                                 "uri-port", ap_get_server_port(r));
 283         if (r->headers_in != NULL) {
 284 #if AP_SERVER_MAJORVERSION_NUMBER >= 2 || AP_SERVER_MINORVERSION_NUMBER > 2
 285                 char *host = (char *)apr_table_get(r->headers_in, "Host");
 286 #else
 287                 char *host = (char *)ap_table_get(r->headers_in, "Host");
 288 #endif
 289 
 290                 if ((host == NULL) || (host[0] == '\0'))
 291                         host = (char *)ap_get_server_name(r);
 292 
 293                 (void) papiAttributeListAddString(&request, PAPI_ATTR_EXCL,
 294                                 "uri-host", host);
 295         }
 296         (void) papiAttributeListAddString(&request, PAPI_ATTR_EXCL,
 297                                 "uri-path", r->uri);
 298 
 299         config = ap_get_module_config(r->per_dir_config, &ipp_module);
 300         if (config != NULL) {
 301                 (void) papiAttributeListAddInteger(&request, PAPI_ATTR_EXCL,
 302                                 "conformance", config->conformance);
 303                 (void) papiAttributeListAddCollection(&request, PAPI_ATTR_EXCL,
 304                                 "operations", config->operations);
 305                 if (config->default_user != NULL)
 306                         (void) papiAttributeListAddString(&request,
 307                                                 PAPI_ATTR_EXCL, "default-user",
 308                                                 config->default_user);
 309                 if (config->default_svc != NULL)
 310                         (void) papiAttributeListAddString(&request,
 311                                         PAPI_ATTR_EXCL, "default-service",
 312                                         config->default_svc);
 313         }
 314 
 315         /*
 316          * For Trusted Solaris, pass the fd number of the socket connection
 317          * to the backend so the it can be forwarded to the backend print
 318          * service to retrieve the sensitivity label off of a multi-level
 319          * port.
 320          */
 321 #if AP_SERVER_MAJORVERSION_NUMBER > 1
 322         st = apr_os_sock_get(os_sock, r->connection->cs->pfd.desc.s);
 323         if (st == APR_SUCCESS) {
 324                 (void) papiAttributeListAddInteger(&request, PAPI_ATTR_EXCL,
 325                         "peer-socket", (int)os_sock);
 326         }
 327 #else
 328         (void) papiAttributeListAddInteger(&request, PAPI_ATTR_EXCL,
 329                 "peer-socket", ap_bfileno(r->connection->client, B_RD));
 330 #endif
 331 
 332         /* process the request */
 333         status = ipp_process_request(request, &response, read_data, r);
 334         if (status != PAPI_OK) {
 335                 errno = 0;
 336                 _log_rerror(APLOG_MARK, APLOG_ERR, r,
 337                         "request failed: %s\n", papiStatusString(status));
 338                 discard_data(r);
 339         }
 340 #ifdef DEBUG
 341         fprintf(stderr, "processing result: %s\n", papiStatusString(status));
 342         papiAttributeListPrint(stderr, response, "response (%d)  ", getpid());
 343 #endif
 344 
 345         /*
 346          * If the client is using chunking and we have not yet received the
 347          * final "0" sized chunk, we need to discard any data that may
 348          * remain in the post request.
 349          */
 350         if ((r->read_chunked != 0) &&
 351 #if AP_SERVER_MAJORVERSION_NUMBER >= 2 || AP_SERVER_MINORVERSION_NUMBER > 2
 352             (apr_table_get(r->headers_in, "Content-Length") == NULL))
 353 #else
 354             (ap_table_get(r->headers_in, "Content-Length") == NULL))
 355 #endif
 356                 discard_data(r);
 357 
 358         /* write an IPP response back to the network */
 359         r->content_type = "application/ipp";
 360 
 361 #if AP_SERVER_MAJORVERSION_NUMBER < 2
 362         ap_send_http_header(r);
 363 #endif
 364 
 365         status = ipp_write_message(write_data, r, response);
 366         if (status != PAPI_OK)
 367                 _log_rerror(APLOG_MARK, APLOG_ERR, r,
 368                         "write failed: %s\n", papiStatusString(status));
 369 #ifdef DEBUG
 370         fprintf(stderr, "write result: %s\n", papiStatusString(status));
 371         fflush(stderr);
 372 #endif
 373 
 374         papiAttributeListFree(request);
 375         papiAttributeListFree(response);
 376 
 377 #if AP_SERVER_MAJORVERSION_NUMBER < 2
 378         ap_kill_timeout(r);
 379         if (ap_rflush(r) < 0)
 380                 _log_rerror(APLOG_MARK, APLOG_ERR, r,
 381                         "flush failed, response may not have been sent");
 382 #endif
 383 
 384         return (OK);
 385 }
 386 
 387 
 388 /*ARGSUSED1*/
 389 static void *
 390 create_ipp_dir_config(
 391 #if AP_SERVER_MAJORVERSION_NUMBER < 2
 392         pool *p,
 393 #else
 394         apr_pool_t *p,
 395 #endif
 396         char *dirspec)
 397 {
 398         IPPListenerConfig *config =
 399 #if AP_SERVER_MAJORVERSION_NUMBER < 2
 400                 ap_pcalloc(p, sizeof (*config));
 401 #else
 402                 apr_pcalloc(p, sizeof (*config));
 403 #endif
 404 
 405         if (config != NULL) {
 406                 (void) memset(config, 0, sizeof (*config));
 407                 config->conformance = IPP_PARSE_CONFORMANCE_RASH;
 408                 config->default_user = NULL;
 409                 config->default_svc = NULL;
 410                 (void) ipp_configure_operation(&config->operations, "required",
 411                                 "enable");
 412         }
 413 
 414         return (config);
 415 }
 416 
 417 /*ARGSUSED0*/
 418 static const char *
 419 ipp_conformance(cmd_parms *cmd, void *cfg, const char *arg)
 420 {
 421         IPPListenerConfig *config = (IPPListenerConfig *)cfg;
 422 
 423         if (strncasecmp(arg, "automatic", 4) == 0) {
 424                 config->conformance = IPP_PARSE_CONFORMANCE_RASH;
 425         } else if (strcasecmp(arg, "1.0") == 0) {
 426                 config->conformance = IPP_PARSE_CONFORMANCE_LOOSE;
 427         } else if (strcasecmp(arg, "1.1") == 0) {
 428                 config->conformance = IPP_PARSE_CONFORMANCE_STRICT;
 429         } else {
 430                 return ("unknown conformance, try (automatic/1.0/1.1)");
 431         }
 432 
 433         return (NULL);
 434 }
 435 
 436 /*ARGSUSED0*/
 437 static const char *
 438 ipp_operation(cmd_parms *cmd, void *cfg, const char *op, const char *toggle)
 439 {
 440         IPPListenerConfig *config = (IPPListenerConfig *)cfg;
 441         papi_status_t status;
 442 
 443         status = ipp_configure_operation(&config->operations, op, toggle);
 444         switch (status) {
 445         case PAPI_OK:
 446                 return (NULL);
 447         case PAPI_BAD_ARGUMENT:
 448                 return (gettext("internal error (invalid argument)"));
 449         default:
 450                 return (papiStatusString(status));
 451         }
 452 
 453         /* NOTREACHED */
 454         /* return (gettext("contact your software vendor")); */
 455 }
 456 
 457 static const char *
 458 ipp_default_user(cmd_parms *cmd, void *cfg, const char *arg)


 488 }
 489 #endif /* DEBUG */
 490 
 491 static const command_rec ipp_cmds[] =
 492 {
 493         AP_INIT_TAKE1("ipp-conformance", ipp_conformance, NULL, ACCESS_CONF,
 494                 "IPP protocol conformance (loose/strict)"),
 495         AP_INIT_TAKE2("ipp-operation", ipp_operation, NULL, ACCESS_CONF,
 496                 "IPP protocol operations to enable/disable)"),
 497         AP_INIT_TAKE1("ipp-default-user", ipp_default_user, NULL, ACCESS_CONF,
 498                 "default user for various operations"),
 499         AP_INIT_TAKE1("ipp-default-service", ipp_default_svc, NULL, ACCESS_CONF,
 500                 "default service for various operations"),
 501 #ifdef DEBUG
 502         AP_INIT_NO_ARGS("ipp-module-hang", ipp_module_hang, NULL, ACCESS_CONF,
 503                 "hang the module until we can attach a debugger (no args)"),
 504 #endif
 505         { NULL }
 506 };
 507 
 508 #if AP_SERVER_MAJORVERSION_NUMBER >= 2
 509 /*ARGSUSED0*/
 510 static const char *
 511 ipp_method(const request_rec *r)
 512 {
 513         return ("ipp");
 514 }
 515 
 516 /*ARGSUSED0*/
 517 static unsigned short
 518 ipp_port(const request_rec *r)
 519 {
 520         return (631);
 521 }
 522 
 523 /* Dispatch list for API hooks */
 524 /*ARGSUSED0*/
 525 static void
 526 ipp_register_hooks(apr_pool_t *p)
 527 {
 528         static const char * const modules[] = { "mod_dir.c", NULL };
 529 
 530         /* Need to make sure we don't get directory listings by accident */
 531         ap_hook_handler(ipp_handler, NULL, modules, APR_HOOK_MIDDLE);
 532         ap_hook_default_port(ipp_port, NULL, NULL, APR_HOOK_MIDDLE);
 533 #if AP_SERVER_MAJORVERSION_NUMBER >= 2
 534         ap_hook_http_scheme(ipp_method, NULL, NULL, APR_HOOK_MIDDLE);
 535 #else
 536         ap_hook_http_method(ipp_method, NULL, NULL, APR_HOOK_MIDDLE);
 537 #endif
 538 }
 539 
 540 module AP_MODULE_DECLARE_DATA ipp_module = {
 541         STANDARD20_MODULE_STUFF,
 542         create_ipp_dir_config,          /* create per-dir    config     */
 543         NULL,                           /* merge  per-dir    config     */
 544         NULL,                           /* create per-server config     */
 545         NULL,                           /* merge  per-server config     */
 546         ipp_cmds,                       /* table of config commands     */
 547         ipp_register_hooks              /* register hooks               */
 548 };
 549 
 550 #else   /* Apache 1.X */
 551 
 552 /* Dispatch list of content handlers */
 553 static const handler_rec ipp_handlers[] = {
 554         /*
 555          * This handler association causes all IPP request with the
 556          * correct MIME type to call the protocol handler.
 557          */