1355b4669Sjacobs /*
2355b4669Sjacobs * CDDL HEADER START
3355b4669Sjacobs *
4355b4669Sjacobs * The contents of this file are subject to the terms of the
5355b4669Sjacobs * Common Development and Distribution License (the "License").
6355b4669Sjacobs * You may not use this file except in compliance with the License.
7355b4669Sjacobs *
8355b4669Sjacobs * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9355b4669Sjacobs * or http://www.opensolaris.org/os/licensing.
10355b4669Sjacobs * See the License for the specific language governing permissions
11355b4669Sjacobs * and limitations under the License.
12355b4669Sjacobs *
13355b4669Sjacobs * When distributing Covered Code, include this CDDL HEADER in each
14355b4669Sjacobs * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15355b4669Sjacobs * If applicable, add the following below this CDDL HEADER, with the
16355b4669Sjacobs * fields enclosed by brackets "[]" replaced with your own identifying
17355b4669Sjacobs * information: Portions Copyright [yyyy] [name of copyright owner]
18355b4669Sjacobs *
19355b4669Sjacobs * CDDL HEADER END
20355b4669Sjacobs */
21355b4669Sjacobs
22355b4669Sjacobs /*
23355b4669Sjacobs * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24355b4669Sjacobs * Use is subject to license terms.
25355b4669Sjacobs *
26*b0e753ddSGordon Ross * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
27355b4669Sjacobs */
28355b4669Sjacobs
29355b4669Sjacobs /* $Id: mod_ipp.c 149 2006-04-25 16:55:01Z njacobs $ */
30355b4669Sjacobs
31355b4669Sjacobs /*
32355b4669Sjacobs * Internet Printing Protocol (IPP) module for Apache.
33355b4669Sjacobs */
34355b4669Sjacobs
35355b4669Sjacobs #include "ap_config.h"
36355b4669Sjacobs
37355b4669Sjacobs #include <stdio.h>
38*b0e753ddSGordon Ross #include <unistd.h>
39355b4669Sjacobs #include <time.h>
40355b4669Sjacobs #include <sys/time.h>
41355b4669Sjacobs #include <values.h>
42355b4669Sjacobs #include <libintl.h>
43355b4669Sjacobs #include <alloca.h>
44355b4669Sjacobs
45355b4669Sjacobs #include "httpd.h"
46355b4669Sjacobs #include "http_config.h"
47355b4669Sjacobs #include "http_core.h"
48355b4669Sjacobs #include "http_protocol.h"
49355b4669Sjacobs #include "http_log.h"
50355b4669Sjacobs #include "http_main.h"
51*b0e753ddSGordon Ross #ifndef APACHE2
52355b4669Sjacobs #include "apr_compat.h"
53*b0e753ddSGordon Ross #define apr_table_get ap_table_get
54*b0e753ddSGordon Ross #endif /* APACHE2 */
55*b0e753ddSGordon Ross
56*b0e753ddSGordon Ross #include "papi.h"
57355b4669Sjacobs
58355b4669Sjacobs #include <papi.h>
59355b4669Sjacobs #include <ipp-listener.h>
60355b4669Sjacobs
61355b4669Sjacobs #ifndef APACHE2
62355b4669Sjacobs module MODULE_VAR_EXPORT ipp_module;
63355b4669Sjacobs #else
64355b4669Sjacobs module AP_MODULE_DECLARE_DATA ipp_module;
65355b4669Sjacobs #endif
66355b4669Sjacobs
67355b4669Sjacobs #ifndef AP_INIT_TAKE1 /* Apache 2.X has this, but 1.3.X does not */
68355b4669Sjacobs #define AP_INIT_NO_ARGS(directive, action, arg, where, mesg) \
69355b4669Sjacobs { directive, action, arg, where, NO_ARGS, mesg }
70355b4669Sjacobs #define AP_INIT_TAKE1(directive, action, arg, where, mesg) \
71355b4669Sjacobs { directive, action, arg, where, TAKE1, mesg }
72355b4669Sjacobs #define AP_INIT_TAKE2(directive, action, arg, where, mesg) \
73355b4669Sjacobs { directive, action, arg, where, TAKE2, mesg }
74355b4669Sjacobs #endif
75355b4669Sjacobs
76355b4669Sjacobs typedef struct {
77355b4669Sjacobs int conformance;
78355b4669Sjacobs char *default_user;
79355b4669Sjacobs char *default_svc;
80355b4669Sjacobs papi_attribute_t **operations;
81355b4669Sjacobs } IPPListenerConfig;
82355b4669Sjacobs
83355b4669Sjacobs #ifdef DEBUG
84355b4669Sjacobs void
dump_buffer(FILE * fp,char * tag,char * buffer,int bytes)85355b4669Sjacobs dump_buffer(FILE *fp, char *tag, char *buffer, int bytes)
86355b4669Sjacobs {
87355b4669Sjacobs int i, j, ch;
88355b4669Sjacobs
89355b4669Sjacobs fprintf(fp, "%s %d(0x%x) bytes\n", (tag ? tag : ""), bytes, bytes);
90355b4669Sjacobs for (i = 0; i < bytes; i += 16) {
91355b4669Sjacobs fprintf(fp, "%s ", (tag ? tag : ""));
92355b4669Sjacobs
93355b4669Sjacobs for (j = 0; j < 16 && (i + j) < bytes; j ++)
94355b4669Sjacobs fprintf(fp, " %02X", buffer[i + j] & 255);
95355b4669Sjacobs
96355b4669Sjacobs while (j < 16) {
97355b4669Sjacobs fprintf(fp, " ");
98355b4669Sjacobs j++;
99355b4669Sjacobs }
100355b4669Sjacobs
101355b4669Sjacobs fprintf(fp, " ");
102355b4669Sjacobs for (j = 0; j < 16 && (i + j) < bytes; j ++) {
103355b4669Sjacobs ch = buffer[i + j] & 255;
104355b4669Sjacobs if (ch < ' ' || ch == 127)
105355b4669Sjacobs ch = '.';
106355b4669Sjacobs putc(ch, fp);
107355b4669Sjacobs }
108355b4669Sjacobs putc('\n', fp);
109355b4669Sjacobs }
110355b4669Sjacobs fflush(fp);
111355b4669Sjacobs }
112355b4669Sjacobs #endif
113355b4669Sjacobs
114355b4669Sjacobs static ssize_t
read_data(void * fd,void * buf,size_t siz)115355b4669Sjacobs read_data(void *fd, void *buf, size_t siz)
116355b4669Sjacobs {
117355b4669Sjacobs ssize_t len_read;
118355b4669Sjacobs request_rec *ap_r = (request_rec *)fd;
119355b4669Sjacobs
120355b4669Sjacobs len_read = ap_get_client_block(ap_r, buf, siz);
121355b4669Sjacobs #ifndef APACHE2
122355b4669Sjacobs ap_reset_timeout(ap_r);
123355b4669Sjacobs #endif
124355b4669Sjacobs
125355b4669Sjacobs #ifdef DEBUG
126355b4669Sjacobs fprintf(stderr, "read_data(0x%8.8x, 0x%8.8x, %d): %d",
127355b4669Sjacobs fd, buf, siz, len_read);
128355b4669Sjacobs if (len_read < 0)
129355b4669Sjacobs fprintf(stderr, ": %s", strerror(errno));
130355b4669Sjacobs putc('\n', stderr);
131355b4669Sjacobs dump_buffer(stderr, "read_data:", buf, len_read);
132355b4669Sjacobs #endif
133355b4669Sjacobs
134355b4669Sjacobs return (len_read);
135355b4669Sjacobs }
136355b4669Sjacobs
137355b4669Sjacobs static ssize_t
write_data(void * fd,void * buf,size_t siz)138355b4669Sjacobs write_data(void *fd, void *buf, size_t siz)
139355b4669Sjacobs {
140355b4669Sjacobs ssize_t len_written;
141355b4669Sjacobs request_rec *ap_r = (request_rec *)fd;
142355b4669Sjacobs
143355b4669Sjacobs #ifndef APACHE2
144355b4669Sjacobs ap_reset_timeout(ap_r);
145355b4669Sjacobs #endif
146355b4669Sjacobs #ifdef DEBUG
147355b4669Sjacobs dump_buffer(stderr, "write_data:", buf, siz);
148355b4669Sjacobs #endif
149355b4669Sjacobs len_written = ap_rwrite(buf, siz, ap_r);
150355b4669Sjacobs
151355b4669Sjacobs return (len_written);
152355b4669Sjacobs }
153355b4669Sjacobs
154355b4669Sjacobs static void
discard_data(request_rec * r)155355b4669Sjacobs discard_data(request_rec *r)
156355b4669Sjacobs {
157355b4669Sjacobs #ifdef APACHE2
158355b4669Sjacobs (void) ap_discard_request_body(r);
159355b4669Sjacobs #else
160355b4669Sjacobs /*
161355b4669Sjacobs * This is taken from ap_discard_request_body(). The reason we can't
162355b4669Sjacobs * just use it in Apache 1.3 is that it does various timeout things we
163355b4669Sjacobs * don't want it to do. Apache 2.0 doesn't do that, so we can safely
164355b4669Sjacobs * use the normal function.
165355b4669Sjacobs */
166355b4669Sjacobs if (r->read_chunked || r->remaining > 0) {
167355b4669Sjacobs char dumpbuf[HUGE_STRING_LEN];
168355b4669Sjacobs int i;
169355b4669Sjacobs
170355b4669Sjacobs do {
171355b4669Sjacobs i = ap_get_client_block(r, dumpbuf, HUGE_STRING_LEN);
172355b4669Sjacobs #ifdef DEBUG
173355b4669Sjacobs dump_buffer(stderr, "discarded", dumpbuf, i);
174355b4669Sjacobs #endif
175355b4669Sjacobs } while (i > 0);
176355b4669Sjacobs }
177355b4669Sjacobs #endif
178355b4669Sjacobs }
179355b4669Sjacobs
_log_rerror(const char * file,int line,int level,request_rec * r,const char * fmt,...)180355b4669Sjacobs void _log_rerror(const char *file, int line, int level, request_rec *r,
181355b4669Sjacobs const char *fmt, ...)
182355b4669Sjacobs {
183355b4669Sjacobs va_list args;
184355b4669Sjacobs size_t size;
185355b4669Sjacobs char *message = alloca(BUFSIZ);
186355b4669Sjacobs
187355b4669Sjacobs va_start(args, fmt);
188355b4669Sjacobs /*
189355b4669Sjacobs * fill in the message. If the buffer is too small, allocate
190355b4669Sjacobs * one that is large enough and fill it in.
191355b4669Sjacobs */
192355b4669Sjacobs if ((size = vsnprintf(message, BUFSIZ, fmt, args)) >= BUFSIZ)
193355b4669Sjacobs if ((message = alloca(size)) != NULL)
194355b4669Sjacobs vsnprintf(message, size, fmt, args);
195355b4669Sjacobs va_end(args);
196355b4669Sjacobs
197355b4669Sjacobs #ifdef APACHE2
198*b0e753ddSGordon Ross ap_log_rerror(file, line, level, APR_SUCCESS, r, message);
199355b4669Sjacobs #else
200355b4669Sjacobs ap_log_rerror(file, line, level, r, message);
201355b4669Sjacobs #endif
202355b4669Sjacobs }
203355b4669Sjacobs
204355b4669Sjacobs static int
ipp_handler(request_rec * r)205355b4669Sjacobs ipp_handler(request_rec *r)
206355b4669Sjacobs {
207355b4669Sjacobs papi_attribute_t **request = NULL, **response = NULL;
208355b4669Sjacobs IPPListenerConfig *config;
209355b4669Sjacobs papi_status_t status;
210*b0e753ddSGordon Ross const char *s;
211*b0e753ddSGordon Ross int sockfd = -1;
212355b4669Sjacobs int ret;
213355b4669Sjacobs
214355b4669Sjacobs /* Really, IPP is all POST requests */
215355b4669Sjacobs if (r->method_number != M_POST)
216355b4669Sjacobs return (DECLINED);
217355b4669Sjacobs
218355b4669Sjacobs /*
219355b4669Sjacobs * An IPP request must have a MIME type of "application/ipp"
220355b4669Sjacobs * (RFC-2910, Section 4, page 19). If it doesn't match this
221355b4669Sjacobs * MIME type, we should decline the request and let someone else
222355b4669Sjacobs * try and handle it.
223355b4669Sjacobs */
224*b0e753ddSGordon Ross if (r->headers_in == NULL)
225355b4669Sjacobs return (DECLINED);
226*b0e753ddSGordon Ross s = apr_table_get(r->headers_in, "Content-Type");
227*b0e753ddSGordon Ross if ((s == NULL) || (strcasecmp(s, "application/ipp") != 0))
228*b0e753ddSGordon Ross return (DECLINED);
229*b0e753ddSGordon Ross
230355b4669Sjacobs /* CHUNKED_DECHUNK might not work right for IPP? */
231355b4669Sjacobs if ((ret = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) != OK)
232355b4669Sjacobs return (ret);
233355b4669Sjacobs
234355b4669Sjacobs if (!ap_should_client_block(r))
235355b4669Sjacobs return (HTTP_INTERNAL_SERVER_ERROR);
236355b4669Sjacobs
237355b4669Sjacobs #ifndef APACHE2
238355b4669Sjacobs ap_soft_timeout("ipp_module: read/reply request ", r);
239355b4669Sjacobs #endif
240355b4669Sjacobs /* read the IPP request off the network */
241355b4669Sjacobs status = ipp_read_message(read_data, r, &request, IPP_TYPE_REQUEST);
242355b4669Sjacobs
243355b4669Sjacobs if (status != PAPI_OK)
244355b4669Sjacobs _log_rerror(APLOG_MARK, APLOG_ERR, r,
245355b4669Sjacobs "read failed: %s\n", papiStatusString(status));
246355b4669Sjacobs #ifdef DEBUG
247355b4669Sjacobs papiAttributeListPrint(stderr, request, "request (%d) ", getpid());
248355b4669Sjacobs #endif
249355b4669Sjacobs
250355b4669Sjacobs #ifdef APACHE2
251*b0e753ddSGordon Ross s = ap_get_remote_host(r->connection, r->per_dir_config,
252*b0e753ddSGordon Ross REMOTE_NAME, NULL);
253355b4669Sjacobs #else
254*b0e753ddSGordon Ross s = ap_get_remote_host(r->connection, r->per_dir_config,
255*b0e753ddSGordon Ross REMOTE_NAME);
256355b4669Sjacobs #endif
257*b0e753ddSGordon Ross (void) papiAttributeListAddString(&request, PAPI_ATTR_EXCL,
258*b0e753ddSGordon Ross "originating-host", (char *)s);
259355b4669Sjacobs
260355b4669Sjacobs (void) papiAttributeListAddInteger(&request, PAPI_ATTR_EXCL,
261355b4669Sjacobs "uri-port", ap_get_server_port(r));
262*b0e753ddSGordon Ross
263355b4669Sjacobs if (r->headers_in != NULL) {
264*b0e753ddSGordon Ross char *host = (char *)apr_table_get(r->headers_in, "Host");
265355b4669Sjacobs
266355b4669Sjacobs if ((host == NULL) || (host[0] == '\0'))
267355b4669Sjacobs host = (char *)ap_get_server_name(r);
268355b4669Sjacobs
269355b4669Sjacobs (void) papiAttributeListAddString(&request, PAPI_ATTR_EXCL,
270355b4669Sjacobs "uri-host", host);
271355b4669Sjacobs }
272355b4669Sjacobs (void) papiAttributeListAddString(&request, PAPI_ATTR_EXCL,
273355b4669Sjacobs "uri-path", r->uri);
274355b4669Sjacobs
275355b4669Sjacobs config = ap_get_module_config(r->per_dir_config, &ipp_module);
276355b4669Sjacobs if (config != NULL) {
277355b4669Sjacobs (void) papiAttributeListAddInteger(&request, PAPI_ATTR_EXCL,
278355b4669Sjacobs "conformance", config->conformance);
279355b4669Sjacobs (void) papiAttributeListAddCollection(&request, PAPI_ATTR_EXCL,
280355b4669Sjacobs "operations", config->operations);
281355b4669Sjacobs if (config->default_user != NULL)
282355b4669Sjacobs (void) papiAttributeListAddString(&request,
283355b4669Sjacobs PAPI_ATTR_EXCL, "default-user",
284355b4669Sjacobs config->default_user);
285355b4669Sjacobs if (config->default_svc != NULL)
286355b4669Sjacobs (void) papiAttributeListAddString(&request,
287355b4669Sjacobs PAPI_ATTR_EXCL, "default-service",
288355b4669Sjacobs config->default_svc);
289355b4669Sjacobs }
290355b4669Sjacobs
291355b4669Sjacobs /*
292355b4669Sjacobs * For Trusted Solaris, pass the fd number of the socket connection
293355b4669Sjacobs * to the backend so the it can be forwarded to the backend print
294355b4669Sjacobs * service to retrieve the sensativity label off of a multi-level
295355b4669Sjacobs * port.
296355b4669Sjacobs */
297*b0e753ddSGordon Ross #ifdef APACHE2
298*b0e753ddSGordon Ross /*
299*b0e753ddSGordon Ross * In Apache 2.4 and later, could use: ap_get_conn_socket()
300*b0e753ddSGordon Ross * Apache 2.2 uses ap_get_module_config() but that needs
301*b0e753ddSGordon Ross * &core_module, for .module_index (which is just zero).
302*b0e753ddSGordon Ross * Could either inline that with index zero, or declare
303*b0e753ddSGordon Ross * core_module here. Latter seems less evil.
304*b0e753ddSGordon Ross */
305*b0e753ddSGordon Ross {
306*b0e753ddSGordon Ross extern module core_module;
307*b0e753ddSGordon Ross apr_socket_t *csd = ap_get_module_config(
308*b0e753ddSGordon Ross r->connection->conn_config, &core_module);
309*b0e753ddSGordon Ross if (csd != NULL)
310*b0e753ddSGordon Ross (void) apr_os_sock_get(&sockfd, csd);
311*b0e753ddSGordon Ross }
312*b0e753ddSGordon Ross #else
313*b0e753ddSGordon Ross sockfd = ap_bfileno(r->connection->client, B_RD);
314*b0e753ddSGordon Ross #endif
315*b0e753ddSGordon Ross if (sockfd != -1) {
316*b0e753ddSGordon Ross (void) papiAttributeListAddInteger(&request,
317*b0e753ddSGordon Ross PAPI_ATTR_EXCL, "peer-socket", sockfd);
318*b0e753ddSGordon Ross }
319355b4669Sjacobs
320355b4669Sjacobs /* process the request */
321355b4669Sjacobs status = ipp_process_request(request, &response, read_data, r);
322355b4669Sjacobs if (status != PAPI_OK) {
323355b4669Sjacobs errno = 0;
324355b4669Sjacobs _log_rerror(APLOG_MARK, APLOG_ERR, r,
325355b4669Sjacobs "request failed: %s\n", papiStatusString(status));
326355b4669Sjacobs discard_data(r);
327355b4669Sjacobs }
328355b4669Sjacobs #ifdef DEBUG
329355b4669Sjacobs fprintf(stderr, "processing result: %s\n", papiStatusString(status));
330355b4669Sjacobs papiAttributeListPrint(stderr, response, "response (%d) ", getpid());
331355b4669Sjacobs #endif
332355b4669Sjacobs
333355b4669Sjacobs /*
334355b4669Sjacobs * If the client is using chunking and we have not yet received the
335355b4669Sjacobs * final "0" sized chunk, we need to discard any data that may
336355b4669Sjacobs * remain in the post request.
337355b4669Sjacobs */
338355b4669Sjacobs if ((r->read_chunked != 0) &&
339*b0e753ddSGordon Ross (apr_table_get(r->headers_in, "Content-Length") == NULL))
340355b4669Sjacobs discard_data(r);
341355b4669Sjacobs
342355b4669Sjacobs /* write an IPP response back to the network */
343355b4669Sjacobs r->content_type = "application/ipp";
344355b4669Sjacobs
345355b4669Sjacobs #ifndef APACHE2
346355b4669Sjacobs ap_send_http_header(r);
347355b4669Sjacobs #endif
348355b4669Sjacobs
349355b4669Sjacobs status = ipp_write_message(write_data, r, response);
350355b4669Sjacobs if (status != PAPI_OK)
351355b4669Sjacobs _log_rerror(APLOG_MARK, APLOG_ERR, r,
352355b4669Sjacobs "write failed: %s\n", papiStatusString(status));
353355b4669Sjacobs #ifdef DEBUG
354355b4669Sjacobs fprintf(stderr, "write result: %s\n", papiStatusString(status));
355355b4669Sjacobs fflush(stderr);
356355b4669Sjacobs #endif
357355b4669Sjacobs
358355b4669Sjacobs papiAttributeListFree(request);
359355b4669Sjacobs papiAttributeListFree(response);
360355b4669Sjacobs
361355b4669Sjacobs #ifndef APACHE2
362355b4669Sjacobs ap_kill_timeout(r);
363355b4669Sjacobs if (ap_rflush(r) < 0)
364355b4669Sjacobs _log_rerror(APLOG_MARK, APLOG_ERR, r,
365355b4669Sjacobs "flush failed, response may not have been sent");
366355b4669Sjacobs #endif
367355b4669Sjacobs
368355b4669Sjacobs return (OK);
369355b4669Sjacobs }
370355b4669Sjacobs
371355b4669Sjacobs
372355b4669Sjacobs /*ARGSUSED1*/
373355b4669Sjacobs static void *
create_ipp_dir_config(pool * p,char * dirspec)374355b4669Sjacobs create_ipp_dir_config(
375355b4669Sjacobs #ifndef APACHE2
376355b4669Sjacobs pool *p,
377355b4669Sjacobs #else
378355b4669Sjacobs apr_pool_t *p,
379355b4669Sjacobs #endif
380355b4669Sjacobs char *dirspec)
381355b4669Sjacobs {
382*b0e753ddSGordon Ross IPPListenerConfig *config;
383355b4669Sjacobs #ifndef APACHE2
384*b0e753ddSGordon Ross config = ap_pcalloc(p, sizeof (*config));
385355b4669Sjacobs #else
386*b0e753ddSGordon Ross config = apr_pcalloc(p, sizeof (*config));
387355b4669Sjacobs #endif
388355b4669Sjacobs
389355b4669Sjacobs if (config != NULL) {
390355b4669Sjacobs (void) memset(config, 0, sizeof (*config));
391355b4669Sjacobs config->conformance = IPP_PARSE_CONFORMANCE_RASH;
392355b4669Sjacobs config->default_user = NULL;
393355b4669Sjacobs config->default_svc = NULL;
394*b0e753ddSGordon Ross (void) ipp_configure_operation(&config->operations,
395*b0e753ddSGordon Ross "required", "enable");
396355b4669Sjacobs }
397355b4669Sjacobs
398355b4669Sjacobs return (config);
399355b4669Sjacobs }
400355b4669Sjacobs
401355b4669Sjacobs /*ARGSUSED0*/
402355b4669Sjacobs static const char *
ipp_conformance(cmd_parms * cmd,void * cfg,const char * arg)403355b4669Sjacobs ipp_conformance(cmd_parms *cmd, void *cfg, const char *arg)
404355b4669Sjacobs {
405355b4669Sjacobs IPPListenerConfig *config = (IPPListenerConfig *)cfg;
406355b4669Sjacobs
407355b4669Sjacobs if (strncasecmp(arg, "automatic", 4) == 0) {
408355b4669Sjacobs config->conformance = IPP_PARSE_CONFORMANCE_RASH;
409355b4669Sjacobs } else if (strcasecmp(arg, "1.0") == 0) {
410355b4669Sjacobs config->conformance = IPP_PARSE_CONFORMANCE_LOOSE;
411355b4669Sjacobs } else if (strcasecmp(arg, "1.1") == 0) {
412355b4669Sjacobs config->conformance = IPP_PARSE_CONFORMANCE_STRICT;
413355b4669Sjacobs } else {
414355b4669Sjacobs return ("unknown conformance, try (automatic/1.0/1.1)");
415355b4669Sjacobs }
416355b4669Sjacobs
417355b4669Sjacobs return (NULL);
418355b4669Sjacobs }
419355b4669Sjacobs
420355b4669Sjacobs /*ARGSUSED0*/
421355b4669Sjacobs static const char *
ipp_operation(cmd_parms * cmd,void * cfg,const char * op,const char * toggle)422*b0e753ddSGordon Ross ipp_operation(cmd_parms *cmd, void *cfg, const char *op, const char *toggle)
423355b4669Sjacobs {
424355b4669Sjacobs IPPListenerConfig *config = (IPPListenerConfig *)cfg;
425355b4669Sjacobs papi_status_t status;
426355b4669Sjacobs
427*b0e753ddSGordon Ross status = ipp_configure_operation(&config->operations,
428*b0e753ddSGordon Ross (char *)op, (char *)toggle);
429355b4669Sjacobs switch (status) {
430355b4669Sjacobs case PAPI_OK:
431355b4669Sjacobs return (NULL);
432355b4669Sjacobs case PAPI_BAD_ARGUMENT:
433355b4669Sjacobs return (gettext("internal error (invalid argument)"));
434355b4669Sjacobs default:
435355b4669Sjacobs return (papiStatusString(status));
436355b4669Sjacobs }
437355b4669Sjacobs
438355b4669Sjacobs /* NOTREACHED */
439355b4669Sjacobs /* return (gettext("contact your software vendor")); */
440355b4669Sjacobs }
441355b4669Sjacobs
442355b4669Sjacobs static const char *
ipp_default_user(cmd_parms * cmd,void * cfg,const char * arg)443355b4669Sjacobs ipp_default_user(cmd_parms *cmd, void *cfg, const char *arg)
444355b4669Sjacobs {
445355b4669Sjacobs IPPListenerConfig *config = (IPPListenerConfig *)cfg;
446355b4669Sjacobs
447355b4669Sjacobs config->default_user = (char *)arg;
448355b4669Sjacobs
449355b4669Sjacobs return (NULL);
450355b4669Sjacobs }
451355b4669Sjacobs
452355b4669Sjacobs static const char *
ipp_default_svc(cmd_parms * cmd,void * cfg,const char * arg)453355b4669Sjacobs ipp_default_svc(cmd_parms *cmd, void *cfg, const char *arg)
454355b4669Sjacobs {
455355b4669Sjacobs IPPListenerConfig *config = (IPPListenerConfig *)cfg;
456355b4669Sjacobs
457355b4669Sjacobs config->default_svc = (char *)arg;
458355b4669Sjacobs
459355b4669Sjacobs return (NULL);
460355b4669Sjacobs }
461355b4669Sjacobs
462355b4669Sjacobs #ifdef DEBUG
463355b4669Sjacobs /*ARGSUSED0*/
464*b0e753ddSGordon Ross volatile int ipp_module_hang_sleeping = 1;
465355b4669Sjacobs static const char *
ipp_module_hang(cmd_parms * cmd,void * cfg)466355b4669Sjacobs ipp_module_hang(cmd_parms *cmd, void *cfg)
467355b4669Sjacobs {
468355b4669Sjacobs
469*b0e753ddSGordon Ross /*
470*b0e753ddSGordon Ross * Wait so we can attach with a debugger. Once attached,
471*b0e753ddSGordon Ross * assign ipp_module_hang_sleeping = 0 and step through.
472*b0e753ddSGordon Ross */
473*b0e753ddSGordon Ross while (ipp_module_hang_sleeping)
474*b0e753ddSGordon Ross sleep(1);
475355b4669Sjacobs
476355b4669Sjacobs return (NULL);
477355b4669Sjacobs }
478355b4669Sjacobs #endif /* DEBUG */
479355b4669Sjacobs
480355b4669Sjacobs static const command_rec ipp_cmds[] =
481355b4669Sjacobs {
482355b4669Sjacobs AP_INIT_TAKE1("ipp-conformance", ipp_conformance, NULL, ACCESS_CONF,
483355b4669Sjacobs "IPP protocol conformance (loose/strict)"),
484355b4669Sjacobs AP_INIT_TAKE2("ipp-operation", ipp_operation, NULL, ACCESS_CONF,
485355b4669Sjacobs "IPP protocol operations to enable/disable)"),
486355b4669Sjacobs AP_INIT_TAKE1("ipp-default-user", ipp_default_user, NULL, ACCESS_CONF,
487355b4669Sjacobs "default user for various operations"),
488355b4669Sjacobs AP_INIT_TAKE1("ipp-default-service", ipp_default_svc, NULL, ACCESS_CONF,
489355b4669Sjacobs "default service for various operations"),
490355b4669Sjacobs #ifdef DEBUG
491355b4669Sjacobs AP_INIT_NO_ARGS("ipp-module-hang", ipp_module_hang, NULL, ACCESS_CONF,
492355b4669Sjacobs "hang the module until we can attach a debugger (no args)"),
493355b4669Sjacobs #endif
494355b4669Sjacobs { NULL }
495355b4669Sjacobs };
496355b4669Sjacobs
497355b4669Sjacobs #ifdef APACHE2
498355b4669Sjacobs /*ARGSUSED0*/
499355b4669Sjacobs static const char *
ipp_scheme(const request_rec * r)500*b0e753ddSGordon Ross ipp_scheme(const request_rec *r)
501355b4669Sjacobs {
502355b4669Sjacobs return ("ipp");
503355b4669Sjacobs }
504355b4669Sjacobs
505355b4669Sjacobs /*ARGSUSED0*/
506355b4669Sjacobs static unsigned short
ipp_port(const request_rec * r)507355b4669Sjacobs ipp_port(const request_rec *r)
508355b4669Sjacobs {
509355b4669Sjacobs return (631);
510355b4669Sjacobs }
511355b4669Sjacobs
512355b4669Sjacobs /* Dispatch list for API hooks */
513355b4669Sjacobs /*ARGSUSED0*/
514355b4669Sjacobs static void
ipp_register_hooks(apr_pool_t * p)515355b4669Sjacobs ipp_register_hooks(apr_pool_t *p)
516355b4669Sjacobs {
517355b4669Sjacobs static const char * const modules[] = { "mod_dir.c", NULL };
518355b4669Sjacobs
519355b4669Sjacobs /* Need to make sure we don't get directory listings by accident */
520355b4669Sjacobs ap_hook_handler(ipp_handler, NULL, modules, APR_HOOK_MIDDLE);
521355b4669Sjacobs ap_hook_default_port(ipp_port, NULL, NULL, APR_HOOK_MIDDLE);
522*b0e753ddSGordon Ross ap_hook_http_scheme(ipp_scheme, NULL, NULL, APR_HOOK_MIDDLE);
523355b4669Sjacobs }
524355b4669Sjacobs
525355b4669Sjacobs module AP_MODULE_DECLARE_DATA ipp_module = {
526355b4669Sjacobs STANDARD20_MODULE_STUFF,
527355b4669Sjacobs create_ipp_dir_config, /* create per-dir config */
528355b4669Sjacobs NULL, /* merge per-dir config */
529355b4669Sjacobs NULL, /* create per-server config */
530355b4669Sjacobs NULL, /* merge per-server config */
531355b4669Sjacobs ipp_cmds, /* table of config commands */
532355b4669Sjacobs ipp_register_hooks /* register hooks */
533355b4669Sjacobs };
534355b4669Sjacobs
535355b4669Sjacobs #else /* Apache 1.X */
536355b4669Sjacobs
537355b4669Sjacobs /* Dispatch list of content handlers */
538355b4669Sjacobs static const handler_rec ipp_handlers[] = {
539355b4669Sjacobs /*
540355b4669Sjacobs * This handler association causes all IPP request with the
541355b4669Sjacobs * correct MIME type to call the protocol handler.
542355b4669Sjacobs */
543355b4669Sjacobs { "application/ipp", ipp_handler },
544355b4669Sjacobs /*
545355b4669Sjacobs * This hander association is causes everything to go through the IPP
546355b4669Sjacobs * protocol request handler. This is necessary because client POST
547355b4669Sjacobs * request may be for something outside of the normal printer-uri
548355b4669Sjacobs * space.
549355b4669Sjacobs */
550355b4669Sjacobs { "*/*", ipp_handler },
551355b4669Sjacobs
552355b4669Sjacobs { NULL, NULL }
553355b4669Sjacobs };
554355b4669Sjacobs
555355b4669Sjacobs
556355b4669Sjacobs module MODULE_VAR_EXPORT ipp_module = {
557355b4669Sjacobs STANDARD_MODULE_STUFF,
558355b4669Sjacobs NULL, /* module initializer */
559355b4669Sjacobs create_ipp_dir_config, /* create per-dir config structures */
560355b4669Sjacobs NULL, /* merge per-dir config structures */
561355b4669Sjacobs NULL, /* create per-server config structures */
562355b4669Sjacobs NULL, /* merge per-server config structures */
563355b4669Sjacobs ipp_cmds, /* table of config file commands */
564355b4669Sjacobs ipp_handlers, /* [#8] MIME-typed-dispatched handlers */
565355b4669Sjacobs NULL, /* [#1] URI to filename translation */
566355b4669Sjacobs NULL, /* [#4] validate user id from request */
567355b4669Sjacobs NULL, /* [#5] check if the user is ok _here_ */
568355b4669Sjacobs NULL, /* [#3] check access by host address */
569355b4669Sjacobs NULL, /* [#6] determine MIME type */
570355b4669Sjacobs NULL, /* [#7] pre-run fixups */
571355b4669Sjacobs NULL, /* [#9] log a transaction */
572355b4669Sjacobs NULL, /* [#2] header parser */
573355b4669Sjacobs NULL, /* child_init */
574355b4669Sjacobs NULL, /* child_exit */
575355b4669Sjacobs NULL /* [#0] post read-request */
576355b4669Sjacobs };
577355b4669Sjacobs #endif
578