2837 - remove print/lp* from gate and use CUPS from userland
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 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 152 ipp_operation_name_to_index(const 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 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 * 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 234 type_to_boolean(const 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 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 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 277 ipp_configure_operation(papi_attribute_t ***list, const char *operation, const 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 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 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 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 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 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 } --- EOF ---