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