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 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 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 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 * 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 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 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 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 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 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 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 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 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 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