xref: /titanic_44/usr/src/lib/print/mod_ipp/mod_ipp.c (revision b0e753dd6a955fb2f10a0ce17d32bd33172e0400)
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