1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
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 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 *
26 */
27
28 /* $Id: ipp-listener.c 146 2006-03-24 00:26:54Z njacobs $ */
29
30 #pragma ident "%Z%%M% %I% %E% SMI"
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <netinet/in.h>
36 #include <assert.h>
37 #include <errno.h>
38 #include <syslog.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <fcntl.h>
42 #include <unistd.h>
43 #include <sys/systeminfo.h>
44
45 #include <papi.h>
46 #include <ipp-listener.h>
47 #include <uri.h>
48
49 typedef papi_status_t (ipp_handler_t)(papi_service_t svc,
50 papi_attribute_t **request,
51 papi_attribute_t ***response,
52 ipp_reader_t iread, void *fd);
53
54 /*
55 * protocol request handlers are inserted below. The handler must be
56 * declared extern immediately below this comment and then an entry
57 * must be inserted in the "handlers" table a little further down.
58 */
59 extern ipp_handler_t ipp_print_job;
60 extern ipp_handler_t ipp_validate_job;
61 extern ipp_handler_t ipp_create_job;
62 extern ipp_handler_t ipp_get_printer_attributes;
63 extern ipp_handler_t ipp_get_jobs;
64 extern ipp_handler_t ipp_pause_printer;
65 extern ipp_handler_t ipp_resume_printer;
66 extern ipp_handler_t ipp_disable_printer;
67 extern ipp_handler_t ipp_enable_printer;
68 extern ipp_handler_t ipp_purge_jobs;
69 extern ipp_handler_t ipp_send_document;
70 extern ipp_handler_t ipp_cancel_job;
71 extern ipp_handler_t ipp_get_job_attributes;
72 extern ipp_handler_t ipp_release_job;
73 extern ipp_handler_t ipp_hold_job;
74 extern ipp_handler_t ipp_restart_job;
75 extern ipp_handler_t ipp_set_job_attributes;
76 extern ipp_handler_t ipp_set_printer_attributes;
77 extern ipp_handler_t cups_get_default;
78 extern ipp_handler_t cups_get_printers;
79 extern ipp_handler_t cups_get_classes;
80 extern ipp_handler_t cups_accept_jobs;
81 extern ipp_handler_t cups_reject_jobs;
82 extern ipp_handler_t cups_move_job;
83
84 /* ARGSUSED0 */
85 static papi_status_t
default_handler(papi_service_t svc,papi_attribute_t ** request,papi_attribute_t *** response,ipp_reader_t iread,void * fd)86 default_handler(papi_service_t svc, papi_attribute_t **request,
87 papi_attribute_t ***response, ipp_reader_t iread, void *fd)
88 {
89 int result = (int)PAPI_INTERNAL_ERROR;
90
91 if (response != NULL)
92 (void) papiAttributeListGetInteger(*response, NULL,
93 "status-code", &result);
94
95 return ((papi_status_t)result);
96 }
97
98 static struct {
99 int16_t id;
100 char *name;
101 ipp_handler_t *function;
102 enum { OP_REQUIRED, OP_OPTIONAL, OP_VENDOR } type;
103 } handlers[] = {
104 /* Printer Operations */
105 { 0x0002, "print-job", ipp_print_job, OP_REQUIRED },
106 { 0x0003, "print-uri", NULL, OP_OPTIONAL },
107 { 0x0004, "validate-job", ipp_validate_job,
108 OP_REQUIRED },
109 { 0x0005, "create-job", ipp_create_job, OP_OPTIONAL },
110 { 0x000a, "get-jobs", ipp_get_jobs, OP_REQUIRED },
111 { 0x000b, "get-printer-attributes", ipp_get_printer_attributes,
112 OP_REQUIRED },
113 { 0x0010, "pause-printer", ipp_pause_printer,
114 OP_OPTIONAL },
115 { 0x0011, "resume-printer", ipp_resume_printer,
116 OP_OPTIONAL },
117 { 0x0012, "purge-jobs", ipp_purge_jobs, OP_OPTIONAL },
118 { 0x0013, "set-printer-attributes", ipp_set_printer_attributes,
119 OP_OPTIONAL },
120 { 0x0014, "set-job-attributes", ipp_set_job_attributes,
121 OP_OPTIONAL },
122 { 0x0022, "enable-printer", ipp_enable_printer,
123 OP_OPTIONAL },
124 { 0x0023, "disable-printer", ipp_disable_printer,
125 OP_OPTIONAL },
126 /* Job Operations */
127 { 0x0006, "send-document", ipp_send_document,
128 OP_OPTIONAL },
129 { 0x0007, "send-uri", NULL, OP_OPTIONAL },
130 { 0x0008, "cancel-job", ipp_cancel_job, OP_REQUIRED },
131 { 0x0009, "get-job-attributes", ipp_get_job_attributes,
132 OP_REQUIRED },
133 { 0x000c, "hold-job", ipp_hold_job, OP_OPTIONAL },
134 { 0x000d, "release-job", ipp_release_job,
135 OP_OPTIONAL },
136 { 0x000e, "restart-job", ipp_restart_job,
137 OP_OPTIONAL },
138 /* Other Operations */
139 { 0x4001, "cups-get-default", cups_get_default,
140 OP_VENDOR },
141 { 0x4002, "cups-get-printers", cups_get_printers,
142 OP_VENDOR },
143 { 0x4005, "cups-get-classes", cups_get_classes,
144 OP_VENDOR },
145 { 0x4008, "cups-accept-jobs", cups_accept_jobs,
146 OP_VENDOR },
147 { 0x4009, "cups-reject-jobs", cups_reject_jobs,
148 OP_VENDOR },
149 { 0x400D, "cups-move-job", cups_move_job, OP_VENDOR },
150 { 0, NULL, NULL, OP_VENDOR }
151 };
152
153 static int
ipp_operation_name_to_index(char * name)154 ipp_operation_name_to_index(char *name)
155 {
156 int i;
157
158 for (i = 0; handlers[i].name != NULL; i++)
159 if (strcasecmp(name, handlers[i].name) == 0)
160 return (i);
161
162 return (-1);
163 }
164
165 static int
ipp_operation_id_to_index(int16_t id)166 ipp_operation_id_to_index(int16_t id)
167 {
168 int i;
169
170 for (i = 0; handlers[i].name != NULL; i++)
171 if (id == handlers[i].id)
172 return (i);
173
174 return (-1);
175 }
176
177 static ipp_handler_t *
ipp_operation_handler(papi_attribute_t ** request,papi_attribute_t *** response)178 ipp_operation_handler(papi_attribute_t **request, papi_attribute_t ***response)
179 {
180 int id = 0;
181 int index;
182 papi_attribute_t **ops = NULL;
183 papi_status_t status;
184 char configured = PAPI_FALSE;
185
186 /* get the operation from the request */
187 status = papiAttributeListGetInteger(request, NULL,
188 "operation-id", &id);
189 if (status != PAPI_OK) {
190 ipp_set_status(response, PAPI_BAD_ARGUMENT,
191 "no operation specified in request");
192 return (default_handler);
193 }
194
195 /* find the operation in the handler table */
196 index = ipp_operation_id_to_index(id);
197 #ifdef DEBUG
198 if (index == -1)
199 fprintf(stderr, "Operation: 0x%4.4x\n", id);
200 else
201 fprintf(stderr, "Operation: 0x%4.4x(%s)\n", id,
202 handlers[index].name);
203 fflush(stderr);
204 #endif
205
206 if ((index == -1) || (handlers[index].function == NULL)) {
207 ipp_set_status(response, PAPI_OPERATION_NOT_SUPPORTED,
208 "operation (0x%4.4x) not implemented by server",
209 id);
210 return (default_handler);
211 }
212
213 /* find the configured operations */
214 status = papiAttributeListGetCollection(request, NULL,
215 "operations", &ops);
216 if (status != PAPI_OK) { /* this should not be possible */
217 ipp_set_status(response, PAPI_INTERNAL_ERROR,
218 "sofware error, no operations configured");
219 return (default_handler);
220 }
221
222 /* check if the requested operation is configured */
223 status = papiAttributeListGetBoolean(ops, NULL,
224 handlers[index].name, &configured);
225 if ((status != PAPI_OK) || (configured != PAPI_TRUE)) {
226 ipp_set_status(response, PAPI_OPERATION_NOT_SUPPORTED,
227 "operation (%s 0x%4.4x) not enabled on server",
228 handlers[index].name, id);
229 return (default_handler);
230 }
231
232 return (handlers[index].function);
233 }
234
235 static char
type_to_boolean(char * type)236 type_to_boolean(char *type)
237 {
238 char result = PAPI_FALSE;
239
240 if ((strcasecmp(type, "true") == 0) ||
241 (strcasecmp(type, "yes") == 0) ||
242 (strcasecmp(type, "on") == 0) ||
243 (strcasecmp(type, "enable") == 0))
244 result = PAPI_TRUE;
245
246 return (result);
247 }
248
249 static papi_status_t
ipp_configure_required_operations(papi_attribute_t *** list,char boolean)250 ipp_configure_required_operations(papi_attribute_t ***list, char boolean)
251 {
252 papi_status_t result = PAPI_OK;
253 int i;
254
255 for (i = 0; ((result == PAPI_OK) && (handlers[i].name != NULL)); i++)
256 if (handlers[i].type == OP_REQUIRED)
257 result = papiAttributeListAddBoolean(list,
258 PAPI_ATTR_REPLACE, handlers[i].name,
259 boolean);
260
261 return (result);
262
263 }
264
265 static papi_status_t
ipp_configure_all_operations(papi_attribute_t *** list,char boolean)266 ipp_configure_all_operations(papi_attribute_t ***list, char boolean)
267 {
268 papi_status_t result = PAPI_OK;
269 int i;
270
271 for (i = 0; ((result == PAPI_OK) && (handlers[i].name != NULL)); i++)
272 result = papiAttributeListAddBoolean(list, PAPI_ATTR_REPLACE,
273 handlers[i].name, boolean);
274
275 return (result);
276 }
277
278 papi_status_t
ipp_configure_operation(papi_attribute_t *** list,char * operation,char * type)279 ipp_configure_operation(papi_attribute_t ***list, char *operation, char *type)
280 {
281 papi_status_t result = PAPI_OPERATION_NOT_SUPPORTED;
282 char boolean = PAPI_FALSE;
283
284 if ((list == NULL) || (operation == NULL) || (type == NULL))
285 return (PAPI_BAD_ARGUMENT);
286
287 boolean = type_to_boolean(type);
288
289 if (strcasecmp(operation, "all") == 0) {
290 result = ipp_configure_all_operations(list, boolean);
291 } else if (strcasecmp(operation, "required") == 0) {
292 result = ipp_configure_required_operations(list, boolean);
293 } else if (ipp_operation_name_to_index(operation) != -1) {
294 result = papiAttributeListAddBoolean(list, PAPI_ATTR_REPLACE,
295 operation, boolean);
296 }
297
298 return (result);
299 }
300
301 void
ipp_operations_supported(papi_attribute_t *** list,papi_attribute_t ** request)302 ipp_operations_supported(papi_attribute_t ***list, papi_attribute_t **request)
303 {
304 papi_attribute_t **group = NULL;
305
306 (void) papiAttributeListGetCollection(request, NULL,
307 "operations", &group);
308 if (group != NULL) {
309 int i;
310
311 for (i = 0; handlers[i].name != NULL; i++) {
312 char boolean = PAPI_FALSE;
313 (void) papiAttributeListGetBoolean(group, NULL,
314 handlers[i].name, &boolean);
315
316 if (boolean == PAPI_TRUE)
317 (void) papiAttributeListAddInteger(list,
318 PAPI_ATTR_APPEND,
319 "operations-supported",
320 handlers[i].id);
321 }
322 }
323 }
324
325 static papi_status_t
ipp_initialize_response(papi_attribute_t ** request,papi_attribute_t *** response)326 ipp_initialize_response(papi_attribute_t **request,
327 papi_attribute_t ***response)
328 {
329 papi_attribute_t **operational = NULL;
330 int i;
331
332 if ((request == NULL) || (response == NULL))
333 return (PAPI_BAD_ARGUMENT);
334
335 /* If the response was initialized, start over */
336 if (*response != NULL) {
337 papiAttributeListFree(*response);
338 *response = NULL;
339 }
340
341 /* Add the basic ipp header information to the response */
342 (void) papiAttributeListGetInteger(request, NULL, "version-major", &i);
343 (void) papiAttributeListAddInteger(response, PAPI_ATTR_REPLACE,
344 "version-major", i);
345 (void) papiAttributeListGetInteger(request, NULL, "version-minor", &i);
346 (void) papiAttributeListAddInteger(response, PAPI_ATTR_REPLACE,
347 "version-minor", i);
348
349 (void) papiAttributeListGetInteger(request, NULL, "request-id", &i);
350 (void) papiAttributeListAddInteger(response, PAPI_ATTR_REPLACE,
351 "request-id", i);
352
353 /* Add a default operational attributes group to the response */
354 (void) papiAttributeListAddString(&operational, PAPI_ATTR_EXCL,
355 "attributes-charset", "utf-8");
356 (void) papiAttributeListAddString(&operational, PAPI_ATTR_EXCL,
357 "attributes-natural-language", "en-us");
358
359 (void) papiAttributeListAddCollection(response, PAPI_ATTR_REPLACE,
360 "operational-attributes-group", operational);
361 papiAttributeListFree(operational);
362
363 return (PAPI_OK);
364 }
365
366 /* simplistic check for cyclical service references */
367 static int
cyclical_service_check(char * svc_name,int port)368 cyclical_service_check(char *svc_name, int port)
369 {
370 papi_attribute_t **list;
371 char buf[BUFSIZ];
372 uri_t *uri = NULL;
373 char *s = NULL;
374
375 /* was there a service_uri? */
376 if (svc_name == NULL)
377 return (0);
378
379 if ((list = getprinterbyname(svc_name, NULL)) == NULL)
380 return (0); /* if it doesnt' resolve, we will fail later */
381
382 papiAttributeListGetString(list, NULL, "printer-uri-supported", &s);
383 if ((s == NULL) || (strcasecmp(svc_name, s) != 0))
384 return (0); /* they don't match */
385
386 /* is it in uri form? */
387 if (uri_from_string(s, &uri) < 0)
388 return (0);
389
390 if ((uri == NULL) || (uri->scheme == NULL) || (uri->host == NULL)) {
391 uri_free(uri);
392 return (0);
393 }
394
395 /* is it ipp form */
396 if (strcasecmp(uri->scheme, "ipp") != 0) {
397 uri_free(uri);
398 return (0);
399 }
400
401 /* does the host match up */
402 if (is_localhost(uri->host) != 0) {
403 uri_free(uri);
404 return (0);
405 }
406
407 /* does the port match our own */
408 if (((uri->port == NULL) && (port != 631)) ||
409 ((uri->port != NULL) && (atoi(uri->port) != port))) {
410 uri_free(uri);
411 return (0);
412 }
413
414 uri_free(uri);
415
416 return (1);
417 }
418
419 static papi_status_t
print_service_connect(papi_service_t * svc,papi_attribute_t ** request,papi_attribute_t *** response)420 print_service_connect(papi_service_t *svc, papi_attribute_t **request,
421 papi_attribute_t ***response)
422 {
423 papi_status_t status;
424 papi_attribute_t **operational = NULL;
425 char *printer_uri = NULL;
426 char *svc_name = NULL;
427 char *user = NULL;
428 int port = 631;
429
430 /* Get the operational attributes group from the request */
431 (void) papiAttributeListGetCollection(request, NULL,
432 "operational-attributes-group", &operational);
433
434 /* get the user name */
435 (void) papiAttributeListGetString(request, NULL, "default-user", &user);
436 (void) papiAttributeListGetString(operational, NULL,
437 "requesting-user-name", &user);
438
439 /* get the printer or service name */
440 (void) papiAttributeListGetString(request, NULL,
441 "default-service", &svc_name);
442 get_printer_id(operational, &svc_name, NULL);
443
444 /* get the port that we are listening on */
445 (void) papiAttributeListGetInteger(request, NULL, "uri-port", &port);
446
447 if (cyclical_service_check(svc_name, port) != 0) {
448 status = PAPI_NOT_POSSIBLE;
449 ipp_set_status(response, status, "printer-uri is cyclical");
450 return (status);
451 }
452
453 status = papiServiceCreate(svc, svc_name, user, NULL, NULL,
454 PAPI_ENCRYPT_NEVER, NULL);
455 if (status != PAPI_OK) {
456 ipp_set_status(response, status, "print service: %s",
457 papiStatusString(status));
458 return (status);
459 }
460
461 /*
462 * Trusted Solaris can't be trusting of intermediaries. Pass
463 * the socket connection to the print service to retrieve the
464 * sensativity label off of a multi-level port.
465 */
466 {
467 int fd = -1;
468
469 (void) papiAttributeListGetInteger(request, NULL,
470 "peer-socket", &fd);
471 if (fd != -1)
472 papiServiceSetPeer(*svc, fd);
473 }
474
475 return (status);
476 }
477
478 papi_status_t
ipp_process_request(papi_attribute_t ** request,papi_attribute_t *** response,ipp_reader_t iread,void * fd)479 ipp_process_request(papi_attribute_t **request, papi_attribute_t ***response,
480 ipp_reader_t iread, void *fd)
481 {
482 papi_status_t result = PAPI_OK;
483
484 ipp_initialize_response(request, response);
485
486 #ifdef DEBUG
487 fprintf(stderr, "REQUEST:");
488 papiAttributeListPrint(stderr, request, " %d ", getpid());
489 fprintf(stderr, "\n");
490 #endif
491
492 /* verify that the request is "well-formed" */
493 if ((result = ipp_validate_request(request, response)) == PAPI_OK) {
494 papi_service_t svc = NULL;
495 ipp_handler_t *handler;
496
497 result = print_service_connect(&svc, request, response);
498 handler = ipp_operation_handler(request, response);
499
500 /* process the request */
501 if ((result == PAPI_OK) && (handler != NULL))
502 result = (handler)(svc, request, response, iread, fd);
503 #ifdef DEBUG
504 fprintf(stderr, "RESULT: %s\n", papiStatusString(result));
505 #endif
506 papiServiceDestroy(svc);
507 }
508
509 (void) papiAttributeListAddInteger(response, PAPI_ATTR_EXCL,
510 "status-code", result);
511 massage_response(request, *response);
512
513 #ifdef DEBUG
514 fprintf(stderr, "RESPONSE:");
515 papiAttributeListPrint(stderr, *response, " %d ", getpid());
516 fprintf(stderr, "\n");
517 #endif
518
519 return (result);
520 }
521