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