12264Sjacobs /* 22264Sjacobs * CDDL HEADER START 32264Sjacobs * 42264Sjacobs * The contents of this file are subject to the terms of the 52264Sjacobs * Common Development and Distribution License (the "License"). 62264Sjacobs * You may not use this file except in compliance with the License. 72264Sjacobs * 82264Sjacobs * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92264Sjacobs * or http://www.opensolaris.org/os/licensing. 102264Sjacobs * See the License for the specific language governing permissions 112264Sjacobs * and limitations under the License. 122264Sjacobs * 132264Sjacobs * When distributing Covered Code, include this CDDL HEADER in each 142264Sjacobs * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152264Sjacobs * If applicable, add the following below this CDDL HEADER, with the 162264Sjacobs * fields enclosed by brackets "[]" replaced with your own identifying 172264Sjacobs * information: Portions Copyright [yyyy] [name of copyright owner] 182264Sjacobs * 192264Sjacobs * CDDL HEADER END 202264Sjacobs */ 212264Sjacobs 222264Sjacobs /* 23*3917Sjacobs * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 242264Sjacobs * Use is subject to license terms. 252264Sjacobs * 262264Sjacobs */ 272264Sjacobs 282264Sjacobs /* $Id: ipp-support.c 148 2006-04-25 16:54:17Z njacobs $ */ 292264Sjacobs 302264Sjacobs #pragma ident "%Z%%M% %I% %E% SMI" 312264Sjacobs 322264Sjacobs #include <papi_impl.h> 332264Sjacobs #include <stdlib.h> 342264Sjacobs #include <pwd.h> 352264Sjacobs #include <locale.h> 362264Sjacobs #include <errno.h> 372264Sjacobs #include <fcntl.h> 382264Sjacobs #include <sys/stat.h> 392264Sjacobs #include <md5.h> 402264Sjacobs 412264Sjacobs #include <config-site.h> 422264Sjacobs 433125Sjacobs #include <ipp.h> 443125Sjacobs 45*3917Sjacobs static void ipp_add_printer_uri(service_t *svc, char *name, 46*3917Sjacobs papi_attribute_t ***op); 47*3917Sjacobs 482264Sjacobs papi_status_t 492264Sjacobs http_to_papi_status(http_status_t status) 502264Sjacobs { 512264Sjacobs switch (status) { 522264Sjacobs case HTTP_OK: 532264Sjacobs return (PAPI_OK); 542264Sjacobs case HTTP_BAD_REQUEST: 552264Sjacobs return (PAPI_BAD_REQUEST); 562264Sjacobs case HTTP_UNAUTHORIZED: 572264Sjacobs case HTTP_FORBIDDEN: 582264Sjacobs return (PAPI_NOT_AUTHORIZED); 592264Sjacobs case HTTP_NOT_FOUND: 602264Sjacobs return (PAPI_NOT_FOUND); 612264Sjacobs case HTTP_GONE: 622264Sjacobs return (PAPI_GONE); 632264Sjacobs case HTTP_SERVICE_UNAVAILABLE: 642264Sjacobs return (PAPI_SERVICE_UNAVAILABLE); 652264Sjacobs default: 662264Sjacobs return ((papi_status_t)status); 672264Sjacobs } 682264Sjacobs } 692264Sjacobs 702264Sjacobs papi_status_t 712264Sjacobs ipp_to_papi_status(uint16_t status) 722264Sjacobs { 732264Sjacobs switch (status) { 742264Sjacobs case IPP_OK: 752264Sjacobs return (PAPI_OK); 762264Sjacobs case IPP_OK_IGNORED_ATTRIBUTES: 772264Sjacobs return (PAPI_OK); 782264Sjacobs case IPP_OK_CONFLICTING_ATTRIBUTES: 792264Sjacobs return (PAPI_OK); 802264Sjacobs case IPP_OK_IGNORED_SUBSCRIPTIONS: 812264Sjacobs return (PAPI_OK_IGNORED_SUBSCRIPTIONS); 822264Sjacobs case IPP_OK_IGNORED_NOTIFICATIONS: 832264Sjacobs return (PAPI_OK_IGNORED_NOTIFICATIONS); 842264Sjacobs case IPP_CERR_BAD_REQUEST: 852264Sjacobs return (PAPI_BAD_REQUEST); 862264Sjacobs case IPP_CERR_FORBIDDEN: 872264Sjacobs return (PAPI_FORBIDDEN); 882264Sjacobs case IPP_CERR_NOT_AUTHENTICATED: 892264Sjacobs return (PAPI_NOT_AUTHENTICATED); 902264Sjacobs case IPP_CERR_NOT_AUTHORIZED: 912264Sjacobs return (PAPI_NOT_AUTHORIZED); 922264Sjacobs case IPP_CERR_NOT_POSSIBLE: 932264Sjacobs return (PAPI_NOT_POSSIBLE); 942264Sjacobs case IPP_CERR_TIMEOUT: 952264Sjacobs return (PAPI_TIMEOUT); 962264Sjacobs case IPP_CERR_NOT_FOUND: 972264Sjacobs return (PAPI_NOT_FOUND); 982264Sjacobs case IPP_CERR_GONE: 992264Sjacobs return (PAPI_GONE); 1002264Sjacobs case IPP_CERR_REQUEST_ENTITY: 1012264Sjacobs return (PAPI_REQUEST_ENTITY); 1022264Sjacobs case IPP_CERR_REQUEST_VALUE: 1032264Sjacobs return (PAPI_REQUEST_VALUE); 1042264Sjacobs case IPP_CERR_DOCUMENT_FORMAT: 1052264Sjacobs return (PAPI_DOCUMENT_FORMAT); 1062264Sjacobs case IPP_CERR_ATTRIBUTES: 1072264Sjacobs return (PAPI_ATTRIBUTES); 1082264Sjacobs case IPP_CERR_URI_SCHEME: 1092264Sjacobs return (PAPI_URI_SCHEME); 1102264Sjacobs case IPP_CERR_CHARSET: 1112264Sjacobs return (PAPI_CHARSET); 1122264Sjacobs case IPP_CERR_CONFLICT: 1132264Sjacobs return (PAPI_CONFLICT); 1142264Sjacobs case IPP_CERR_COMPRESSION_NOT_SUPPORTED: 1152264Sjacobs return (PAPI_COMPRESSION_NOT_SUPPORTED); 1162264Sjacobs case IPP_CERR_COMPRESSION_ERROR: 1172264Sjacobs return (PAPI_COMPRESSION_ERROR); 1182264Sjacobs case IPP_CERR_DOCUMENT_FORMAT_ERROR: 1192264Sjacobs return (PAPI_DOCUMENT_FORMAT_ERROR); 1202264Sjacobs case IPP_CERR_DOCUMENT_ACCESS_ERROR: 1212264Sjacobs return (PAPI_DOCUMENT_ACCESS_ERROR); 1222264Sjacobs case IPP_CERR_ATTRIBUTES_NOT_SETTABLE: 1232264Sjacobs return (PAPI_ATTRIBUTES_NOT_SETTABLE); 1242264Sjacobs case IPP_CERR_IGNORED_ALL_SUBSCRIPTIONS: 1252264Sjacobs return (PAPI_IGNORED_ALL_SUBSCRIPTIONS); 1262264Sjacobs case IPP_CERR_TOO_MANY_SUBSCRIPTIONS: 1272264Sjacobs return (PAPI_TOO_MANY_SUBSCRIPTIONS); 1282264Sjacobs case IPP_CERR_IGNORED_ALL_NOTIFICATIONS: 1292264Sjacobs return (PAPI_IGNORED_ALL_NOTIFICATIONS); 1302264Sjacobs case IPP_CERR_PRINT_SUPPORT_FILE_NOT_FOUND: 1312264Sjacobs return (PAPI_PRINT_SUPPORT_FILE_NOT_FOUND); 1322264Sjacobs case IPP_SERR_INTERNAL: 1332264Sjacobs return (PAPI_INTERNAL_ERROR); 1342264Sjacobs case IPP_SERR_OPERATION_NOT_SUPPORTED: 1352264Sjacobs return (PAPI_OPERATION_NOT_SUPPORTED); 1362264Sjacobs case IPP_SERR_SERVICE_UNAVAILABLE: 1372264Sjacobs return (PAPI_SERVICE_UNAVAILABLE); 1382264Sjacobs case IPP_SERR_VERSION_NOT_SUPPORTED: 1392264Sjacobs return (PAPI_VERSION_NOT_SUPPORTED); 1402264Sjacobs case IPP_SERR_DEVICE_ERROR: 1412264Sjacobs return (PAPI_DEVICE_ERROR); 1422264Sjacobs case IPP_SERR_TEMPORARY_ERROR: 1432264Sjacobs return (PAPI_TEMPORARY_ERROR); 1442264Sjacobs case IPP_SERR_NOT_ACCEPTING: 1452264Sjacobs return (PAPI_NOT_ACCEPTING); 1462264Sjacobs case IPP_SERR_BUSY: 1472264Sjacobs case IPP_SERR_CANCELLED: 1482264Sjacobs default: 1492264Sjacobs return (PAPI_TEMPORARY_ERROR); 1502264Sjacobs } 1512264Sjacobs } 1522264Sjacobs 1532264Sjacobs void 1542264Sjacobs ipp_initialize_request(service_t *svc, papi_attribute_t ***request, 1552264Sjacobs uint16_t operation) 1562264Sjacobs { 1572264Sjacobs papiAttributeListAddInteger(request, PAPI_ATTR_EXCL, 1582264Sjacobs "version-major", 1); 1592264Sjacobs papiAttributeListAddInteger(request, PAPI_ATTR_EXCL, 1602264Sjacobs "version-minor", 1); 1612264Sjacobs papiAttributeListAddInteger(request, PAPI_ATTR_EXCL, 1622264Sjacobs "request-id", (short)lrand48()); 1632264Sjacobs papiAttributeListAddInteger(request, PAPI_ATTR_EXCL, 1642264Sjacobs "operation-id", operation); 1652264Sjacobs } 1662264Sjacobs 1672264Sjacobs void 1682264Sjacobs ipp_initialize_operational_attributes(service_t *svc, papi_attribute_t ***op, 169*3917Sjacobs char *printer, int job_id) 1702264Sjacobs { 1712264Sjacobs char *charset = "utf-8"; /* default to UTF-8 encoding */ 1722264Sjacobs char *language = setlocale(LC_ALL, ""); 1732264Sjacobs char *user = "nobody"; 1742264Sjacobs struct passwd *pw = NULL; 1752264Sjacobs 1762264Sjacobs /* 1772264Sjacobs * All IPP requests must contain the following: 1782264Sjacobs * attributes-charset (UTF-8) 1792264Sjacobs * attributes-natural-language (our current locale) 180*3917Sjacobs * (object identifier) printer-uri/job-id or job-uri 181*3917Sjacobs * requesting-user-name (process user or none) 1822264Sjacobs */ 1832264Sjacobs papiAttributeListAddString(op, PAPI_ATTR_EXCL, 1842264Sjacobs "attributes-charset", charset); 1852264Sjacobs 1862264Sjacobs papiAttributeListAddString(op, PAPI_ATTR_EXCL, 1872264Sjacobs "attributes-natural-language", language); 1882264Sjacobs 189*3917Sjacobs if (printer != NULL) 190*3917Sjacobs ipp_add_printer_uri(svc, printer, op); 191*3917Sjacobs 192*3917Sjacobs if ((printer != NULL) && (job_id >= 0)) 193*3917Sjacobs papiAttributeListAddInteger(op, PAPI_ATTR_EXCL, 194*3917Sjacobs "job-id", job_id); 195*3917Sjacobs 1962264Sjacobs if ((pw = getpwuid(getuid())) != NULL) 1972264Sjacobs user = pw->pw_name; 1982264Sjacobs /* 1992264Sjacobs * if our euid is 0 "super user", we will allow the system supplied 2002264Sjacobs * user name to be overridden, if the requestor wants to. 2012264Sjacobs */ 2022264Sjacobs if (geteuid() == 0) { 2032264Sjacobs if (svc->user != NULL) 2042264Sjacobs user = svc->user; 2052264Sjacobs } 2062264Sjacobs papiAttributeListAddString(op, PAPI_ATTR_REPLACE, 2072264Sjacobs "requesting-user-name", user); 2082264Sjacobs } 2092264Sjacobs 2102264Sjacobs #ifndef OPID_CUPS_GET_DEFAULT /* for servers that will enumerate */ 2112264Sjacobs #define OPID_CUPS_GET_DEFAULT 0x4001 2122264Sjacobs #endif /* OPID_CUPS_GET_DEFAULT */ 2132264Sjacobs 2142264Sjacobs static papi_status_t 2152264Sjacobs _default_destination(service_t *svc, char **uri) 2162264Sjacobs { 2172264Sjacobs papi_status_t result = PAPI_INTERNAL_ERROR; 2182264Sjacobs printer_t *p = NULL; 2192264Sjacobs papi_attribute_t **request = NULL, **op = NULL, **response = NULL; 2202264Sjacobs char *tmp = NULL; 2212264Sjacobs 2222264Sjacobs if ((svc == NULL) || (uri == NULL)) 2232264Sjacobs return (PAPI_BAD_ARGUMENT); 2242264Sjacobs 2252264Sjacobs /* we must be connected to find the default destination */ 2262264Sjacobs if (svc->connection == NULL) 2272264Sjacobs return (PAPI_NOT_POSSIBLE); 2282264Sjacobs 2292264Sjacobs if ((p = calloc(1, sizeof (*p))) == NULL) 2302264Sjacobs return (PAPI_TEMPORARY_ERROR); 2312264Sjacobs 2322264Sjacobs ipp_initialize_request(svc, &request, OPID_CUPS_GET_DEFAULT); 233*3917Sjacobs ipp_initialize_operational_attributes(svc, &op, NULL, -1); 2342264Sjacobs papiAttributeListAddString(&op, PAPI_ATTR_APPEND, 2352264Sjacobs "requested-attributes", "printer-uri-supported"); 2362264Sjacobs papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE, 2372264Sjacobs "operational-attributes-group", op); 2382264Sjacobs papiAttributeListFree(op); 2392264Sjacobs result = ipp_send_request(svc, request, &response); 2402264Sjacobs papiAttributeListFree(request); 2412264Sjacobs 2422264Sjacobs op = NULL; 2432264Sjacobs papiAttributeListGetCollection(response, NULL, 2442264Sjacobs "printer-attributes-group", &op); 2452264Sjacobs 2462264Sjacobs if (uri != NULL) { 2472264Sjacobs char *tmp = NULL; 2482264Sjacobs 2492264Sjacobs papiAttributeListGetString(op, NULL, "printer-uri", &tmp); 2502264Sjacobs papiAttributeListGetString(op, NULL, 2512264Sjacobs "printer-uri-supported", &tmp); 2522264Sjacobs if (tmp != NULL) 2532264Sjacobs *uri = strdup(tmp); 2542264Sjacobs } 2552264Sjacobs 2562264Sjacobs papiAttributeListFree(response); 2572264Sjacobs 2582264Sjacobs return (result); 2592264Sjacobs } 2602264Sjacobs 261*3917Sjacobs static void 2622264Sjacobs ipp_add_printer_uri(service_t *svc, char *name, papi_attribute_t ***op) 2632264Sjacobs { 2642264Sjacobs char *uri = name; 2652264Sjacobs char buf[BUFSIZ]; 2662264Sjacobs uri_t *tmp = NULL; 2672264Sjacobs 2682264Sjacobs if (strstr(name, "://") == NULL) { /* not in URI form */ 2692264Sjacobs if (strcmp(name, DEFAULT_DEST) != 0) { 2702264Sjacobs /* not the "default" */ 2712264Sjacobs snprintf(buf, sizeof (buf), "%s/%s", svc->name, name); 2722264Sjacobs uri = buf; 2732264Sjacobs } else 2742264Sjacobs _default_destination(svc, &uri); 2752264Sjacobs } 2762264Sjacobs 2772264Sjacobs papiAttributeListAddString(op, PAPI_ATTR_EXCL, "printer-uri", uri); 2782264Sjacobs 2792264Sjacobs /* save the printer-uri's path to be used by http POST request */ 2802264Sjacobs if ((uri_from_string(uri, &tmp) == 0) && (tmp != NULL)) { 2812264Sjacobs if (svc->post != NULL) 2822264Sjacobs free(svc->post); 2832264Sjacobs svc->post = strdup(tmp->path); 2842264Sjacobs uri_free(tmp); 2852264Sjacobs } 2862264Sjacobs } 2872264Sjacobs 2882264Sjacobs 2892264Sjacobs /* 2902264Sjacobs * don't actually write anything, just add to the total size and return the 2912264Sjacobs * size of what would be written, so we can figure out how big the request 2922264Sjacobs * is going to be. 2932264Sjacobs */ 2942264Sjacobs static ssize_t 2952264Sjacobs size_calculate(void *fd, void *buffer, size_t length) 2962264Sjacobs { 2972264Sjacobs ssize_t *size = (ssize_t *)fd; 2982264Sjacobs 2992264Sjacobs *size += length; 3002264Sjacobs return (length); 3012264Sjacobs } 3022264Sjacobs 3032264Sjacobs 3042264Sjacobs static ssize_t 3052264Sjacobs build_chunk(void *fd, void *buffer, size_t length) 3062264Sjacobs { 3072264Sjacobs char **s1 = fd; 3082264Sjacobs 3092264Sjacobs memcpy(*s1, buffer, length); 3102264Sjacobs *s1 = *s1 + length; 3112264Sjacobs 3122264Sjacobs return (length); 3132264Sjacobs } 3142264Sjacobs 3152264Sjacobs ssize_t 3162264Sjacobs ipp_request_write(void *fd, void *buffer, size_t length) 3172264Sjacobs { 3182264Sjacobs service_t *svc = (service_t *)fd; 3192264Sjacobs 3202264Sjacobs #ifdef DEBUG 3212264Sjacobs printf("ipp_request_write(0x%8.8x, 0x%8.8x, %d)\n", fd, buffer, length); 3222264Sjacobs httpDumpData(stdout, "ipp_request_write:", buffer, length); 3232264Sjacobs #endif 3242264Sjacobs return (httpWrite(svc->connection, buffer, length)); 3252264Sjacobs } 3262264Sjacobs 3272264Sjacobs ssize_t 3282264Sjacobs ipp_request_read(void *fd, void *buffer, size_t length) 3292264Sjacobs { 3302264Sjacobs service_t *svc = (service_t *)fd; 3312264Sjacobs ssize_t rc, i = length; 3322264Sjacobs char *p = buffer; 3332264Sjacobs 3342264Sjacobs while ((rc = httpRead(svc->connection, p, i)) != i) { 3352264Sjacobs if (rc == 0) 3362264Sjacobs return (rc); 3372264Sjacobs if (rc < 0) 3382264Sjacobs return (rc); 3392264Sjacobs i -= rc; 3402264Sjacobs p += rc; 3412264Sjacobs } 3422264Sjacobs #ifdef DEBUG 3432264Sjacobs printf("ipp_request_read(0x%8.8x, 0x%8.8x, %d) = %d\n", 3442264Sjacobs fd, buffer, length, rc); 3452264Sjacobs httpDumpData(stdout, "ipp_request_read:", buffer, length); 3462264Sjacobs #endif 3472264Sjacobs 3482264Sjacobs return (length); 3492264Sjacobs } 3502264Sjacobs 3512264Sjacobs papi_status_t 3522264Sjacobs ipp_send_initial_request_block(service_t *svc, papi_attribute_t **request, 3532264Sjacobs ssize_t file_size) 3542264Sjacobs { 3552264Sjacobs papi_status_t result = PAPI_OK; 3562264Sjacobs ssize_t chunk_size = 0; 3572264Sjacobs char length[32]; 3582264Sjacobs void *chunk, *ptr; 3592264Sjacobs http_status_t status; 3602264Sjacobs 3612264Sjacobs /* calculate the request size */ 3622264Sjacobs (void) ipp_write_message(&size_calculate, &chunk_size, request); 3632264Sjacobs 3642264Sjacobs /* Fill in the HTTP Header information */ 3652264Sjacobs httpClearFields(svc->connection); 3662264Sjacobs if (svc->transfer_encoding == TRANSFER_ENCODING_CHUNKED) 3672264Sjacobs httpSetField(svc->connection, HTTP_FIELD_TRANSFER_ENCODING, 3682264Sjacobs "chunked"); 3692264Sjacobs else { 3702264Sjacobs sprintf(length, "%lu", (unsigned long)(file_size + chunk_size)); 3712264Sjacobs httpSetField(svc->connection, HTTP_FIELD_CONTENT_LENGTH, 3722264Sjacobs length); 3732264Sjacobs } 3742264Sjacobs httpSetField(svc->connection, HTTP_FIELD_CONTENT_TYPE, 3752264Sjacobs "application/ipp"); 3762264Sjacobs httpSetField(svc->connection, HTTP_FIELD_AUTHORIZATION, 3772264Sjacobs svc->connection->authstring); 3782264Sjacobs 3792264Sjacobs /* flush any state information about this connection */ 3802264Sjacobs httpFlush(svc->connection); 3812264Sjacobs 3822264Sjacobs /* if we have don't have a POST path, use the service uri path */ 3832264Sjacobs if (svc->post == NULL) 3842264Sjacobs svc->post = strdup(svc->uri->path); 3852264Sjacobs /* send the HTTP POST message for the IPP request */ 3862264Sjacobs /* if the POST fails, return the error */ 3872264Sjacobs status = httpPost(svc->connection, svc->post); 3882264Sjacobs if (status != 0) 3892264Sjacobs return (http_to_papi_status(status)); 3902264Sjacobs 3912264Sjacobs if (httpCheck(svc->connection) != 0) { 3922264Sjacobs status = httpUpdate(svc->connection); 3932264Sjacobs if (status != HTTP_OK) 3942264Sjacobs return (http_to_papi_status(status)); 3952264Sjacobs } 3962264Sjacobs 3972264Sjacobs /* build the request chunk */ 3982264Sjacobs chunk = ptr = calloc(1, chunk_size); 3992264Sjacobs result = ipp_write_message(&build_chunk, &ptr, request); 4002264Sjacobs #ifdef DEBUG 4012264Sjacobs printf("request: %d (0x%x) bytes\n", chunk_size, chunk_size); 4022264Sjacobs httpDumpData(stdout, "request:", chunk, chunk_size); 4032264Sjacobs #endif 4042264Sjacobs 4052264Sjacobs /* send the actual IPP request */ 4062264Sjacobs if (ipp_request_write(svc, chunk, chunk_size) != chunk_size) 4072264Sjacobs result = PAPI_TEMPORARY_ERROR; 4082264Sjacobs free(chunk); 4092264Sjacobs 4102264Sjacobs if (httpCheck(svc->connection) != 0) { 4112264Sjacobs status = httpUpdate(svc->connection); 4122264Sjacobs if (status != HTTP_OK) 4132264Sjacobs return (http_to_papi_status(status)); 4142264Sjacobs } 4152264Sjacobs 4162264Sjacobs return (result); 4172264Sjacobs } 4182264Sjacobs 4192264Sjacobs static int 4202264Sjacobs setAuthString(service_t *svc) 4212264Sjacobs { 4222264Sjacobs http_t *http; 4232264Sjacobs char *user, *passphrase; 4242264Sjacobs char encoded[BUFSIZ]; 4252264Sjacobs 4262264Sjacobs if ((svc == NULL) || (svc->connection == NULL) || (svc->name == NULL)) 4272264Sjacobs return (-1); 4282264Sjacobs 4292264Sjacobs http = svc->connection; 4302264Sjacobs 4312264Sjacobs if (svc->user == NULL) { 4322264Sjacobs struct passwd *p; 4332264Sjacobs 4342264Sjacobs if ((p = getpwuid(getuid())) != NULL) { 4352264Sjacobs user = p->pw_name; 4362264Sjacobs } else if ((user = getenv("LOGNAME")) == NULL) 4372264Sjacobs user = getenv("USER"); 4382264Sjacobs if (user == NULL) 4392264Sjacobs user = "nobody"; 4402264Sjacobs } else 4412264Sjacobs user = svc->user; 4422264Sjacobs 4432264Sjacobs /* if the passphrase is not set, use the Authentication Callback */ 4442264Sjacobs if (((svc->password == NULL) || (svc->password[0] == '\0')) && 4452264Sjacobs (svc->authCB != NULL)) 4462264Sjacobs (svc->authCB)(svc, svc->app_data); 4472264Sjacobs passphrase = svc->password; 4482264Sjacobs 4492264Sjacobs /* if there is still no passphrase, we have to fail */ 4502264Sjacobs if ((passphrase == NULL) || (passphrase[0] == '\0')) 4512264Sjacobs return (-1); 4522264Sjacobs 4532264Sjacobs if (strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], 4542264Sjacobs "Basic", 5) == 0) { 4552264Sjacobs char plain[BUFSIZ]; 4562264Sjacobs 4572264Sjacobs snprintf(plain, sizeof (plain), "%s:%s", user, passphrase); 4582264Sjacobs httpEncode64(encoded, plain); 4592264Sjacobs snprintf(http->authstring, sizeof (http->authstring), 4602264Sjacobs "Basic %s", encoded); 4612264Sjacobs } else if (strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], 4622264Sjacobs "Digest", 6) == 0) { 4632264Sjacobs char realm[HTTP_MAX_VALUE]; 4642264Sjacobs char nonce[HTTP_MAX_VALUE]; 4652264Sjacobs char line [BUFSIZ]; 4662264Sjacobs char urp[128]; 4672264Sjacobs char mr[128]; 4682264Sjacobs char *uri = svc->post; 4692264Sjacobs 4702264Sjacobs httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, 4712264Sjacobs "realm", realm); 4722264Sjacobs httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, 4732264Sjacobs "nonce", nonce); 4742264Sjacobs 4752264Sjacobs snprintf(line, sizeof (line), "%s:%s:%s", user, realm, 4762264Sjacobs passphrase); 4772264Sjacobs md5_calc(urp, line, strlen(line)); 4782264Sjacobs 4792264Sjacobs snprintf(line, sizeof (line), "POST:%s", uri); 4802264Sjacobs md5_calc(mr, line, strlen(line)); 4812264Sjacobs 4822264Sjacobs snprintf(line, sizeof (line), "%s:%s:%s", urp, mr, nonce); 4832264Sjacobs md5_calc(encoded, line, strlen(line)); 4842264Sjacobs 4852264Sjacobs snprintf(http->authstring, sizeof (http->authstring), 4862264Sjacobs "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", " 4872264Sjacobs "uri=\"%s\", response=\"%s\"", user, realm, nonce, uri, 4882264Sjacobs encoded); 4892264Sjacobs } 4902264Sjacobs 4912264Sjacobs return (0); 4922264Sjacobs } 4932264Sjacobs 4942264Sjacobs papi_status_t 4952264Sjacobs ipp_status_info(service_t *svc, papi_attribute_t **response) 4962264Sjacobs { 4972264Sjacobs papi_attribute_t **operational = NULL; 4982264Sjacobs int32_t status = 0; 4992264Sjacobs 5002264Sjacobs papiAttributeListGetCollection(response, NULL, 5012264Sjacobs "operational-attributes-group", &operational); 5022264Sjacobs if (operational != NULL) { 5032264Sjacobs char *message = NULL; 5042264Sjacobs 5052264Sjacobs papiAttributeListGetString(response, NULL, 5062264Sjacobs "status-message", &message); 5072264Sjacobs papiAttributeListAddString(&svc->attributes, PAPI_ATTR_REPLACE, 5082264Sjacobs "detailed-status-message", message); 5092264Sjacobs } 5102264Sjacobs papiAttributeListGetInteger(response, NULL, "status-code", &status); 5112264Sjacobs 5122264Sjacobs return (ipp_to_papi_status(status)); 5132264Sjacobs } 5142264Sjacobs 5152264Sjacobs papi_status_t 5162264Sjacobs ipp_send_request_with_file(service_t *svc, papi_attribute_t **request, 5172264Sjacobs papi_attribute_t ***response, char *file) 5182264Sjacobs { 5192264Sjacobs papi_status_t result = PAPI_OK; 5202264Sjacobs ssize_t size = 0; 5212264Sjacobs int fd; 5222264Sjacobs 5232264Sjacobs #ifdef DEBUG 5242264Sjacobs fprintf(stderr, "\nIPP-REQUEST: (%s)", (file ? file : "")); 5252264Sjacobs papiAttributeListPrint(stderr, request, " "); 5262264Sjacobs putc('\n', stderr); 5272264Sjacobs fflush(stderr); 5282264Sjacobs #endif 5292264Sjacobs 5302264Sjacobs /* 5312264Sjacobs * if we are sending a file, open it and include it's size in the 5322264Sjacobs * message size. 5332264Sjacobs */ 5342264Sjacobs if (file != NULL) { 5352264Sjacobs if ((fd = open(file, O_RDONLY)) < 0) { 5362264Sjacobs detailed_error(svc, "%s: %s", file, strerror(errno)); 5372264Sjacobs return (PAPI_DOCUMENT_ACCESS_ERROR); 5382264Sjacobs } else if (svc->transfer_encoding != 5392264Sjacobs TRANSFER_ENCODING_CHUNKED) { 5402264Sjacobs struct stat st; 5412264Sjacobs 5422264Sjacobs if (fstat(fd, &st) >= 0) 5432264Sjacobs size = st.st_size; 5442264Sjacobs } 5452264Sjacobs } 5462264Sjacobs 5472264Sjacobs *response = NULL; 5482264Sjacobs while (*response == NULL) { 5492264Sjacobs http_status_t status = HTTP_CONTINUE; 5502264Sjacobs 5512264Sjacobs result = ipp_send_initial_request_block(svc, request, size); 5522264Sjacobs 5532264Sjacobs if (result == PAPI_OK) { 5542264Sjacobs if (file != NULL) { 5552264Sjacobs /* send the file contents if we have it */ 5562264Sjacobs int rc; 5572264Sjacobs char buf[BUFSIZ]; 5582264Sjacobs 5592264Sjacobs lseek(fd, 0L, SEEK_SET); 5602264Sjacobs while ((rc = read(fd, buf, sizeof (buf))) > 0) { 5612264Sjacobs if (ipp_request_write(svc, buf, rc) 5622264Sjacobs < rc) { 5632264Sjacobs break; 5642264Sjacobs } 5652264Sjacobs } 5662264Sjacobs } 5672264Sjacobs 5682264Sjacobs (void) ipp_request_write(svc, "", 0); 5692264Sjacobs } 5702264Sjacobs 5712264Sjacobs /* update our connection info */ 5722264Sjacobs while (status == HTTP_CONTINUE) 5732264Sjacobs status = httpUpdate(svc->connection); 5742264Sjacobs 5752264Sjacobs if (status == HTTP_UNAUTHORIZED) { 5762264Sjacobs httpFlush(svc->connection); 5772264Sjacobs if ((svc->connection->authstring[0] == '\0') && 5782264Sjacobs (setAuthString(svc) == 0)) { 5792264Sjacobs httpReconnect(svc->connection); 5802264Sjacobs continue; 5812264Sjacobs } 5822264Sjacobs } else if (status == HTTP_UPGRADE_REQUIRED) { 5832264Sjacobs /* 5842264Sjacobs * If the transport was built with TLS support, we can 5852264Sjacobs * try to use it. 5862264Sjacobs */ 5872264Sjacobs httpFlush(svc->connection); 5882264Sjacobs httpReconnect(svc->connection); 5892264Sjacobs httpEncryption(svc->connection, HTTP_ENCRYPT_REQUIRED); 5902264Sjacobs continue; 5912264Sjacobs } 5922264Sjacobs 5932264Sjacobs if (status != HTTP_OK) 5942264Sjacobs return (http_to_papi_status(status)); 5952264Sjacobs 5962264Sjacobs /* read the IPP response */ 5972264Sjacobs result = ipp_read_message(&ipp_request_read, svc, response, 5982264Sjacobs IPP_TYPE_RESPONSE); 5992264Sjacobs 6002264Sjacobs if (result == PAPI_OK) 6012264Sjacobs result = ipp_status_info(svc, *response); 6022264Sjacobs #ifdef DEBUG 6032264Sjacobs fprintf(stderr, "\nIPP-RESPONSE: (%s) (%s)", (file ? file : ""), 6042264Sjacobs papiStatusString(result)); 6052264Sjacobs papiAttributeListPrint(stderr, *response, " "); 6062264Sjacobs putc('\n', stderr); 6072264Sjacobs fflush(stderr); 6082264Sjacobs #endif 6092264Sjacobs } 6102264Sjacobs 6112264Sjacobs return (result); 6122264Sjacobs } 6132264Sjacobs 6142264Sjacobs papi_status_t 6152264Sjacobs ipp_send_request(service_t *svc, papi_attribute_t **request, 6162264Sjacobs papi_attribute_t ***response) 6172264Sjacobs { 6182264Sjacobs return (ipp_send_request_with_file(svc, request, response, NULL)); 6192264Sjacobs } 620