1*2264Sjacobs /* 2*2264Sjacobs * CDDL HEADER START 3*2264Sjacobs * 4*2264Sjacobs * The contents of this file are subject to the terms of the 5*2264Sjacobs * Common Development and Distribution License (the "License"). 6*2264Sjacobs * You may not use this file except in compliance with the License. 7*2264Sjacobs * 8*2264Sjacobs * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*2264Sjacobs * or http://www.opensolaris.org/os/licensing. 10*2264Sjacobs * See the License for the specific language governing permissions 11*2264Sjacobs * and limitations under the License. 12*2264Sjacobs * 13*2264Sjacobs * When distributing Covered Code, include this CDDL HEADER in each 14*2264Sjacobs * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*2264Sjacobs * If applicable, add the following below this CDDL HEADER, with the 16*2264Sjacobs * fields enclosed by brackets "[]" replaced with your own identifying 17*2264Sjacobs * information: Portions Copyright [yyyy] [name of copyright owner] 18*2264Sjacobs * 19*2264Sjacobs * CDDL HEADER END 20*2264Sjacobs */ 21*2264Sjacobs 22*2264Sjacobs /* 23*2264Sjacobs * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*2264Sjacobs * Use is subject to license terms. 25*2264Sjacobs * 26*2264Sjacobs */ 27*2264Sjacobs 28*2264Sjacobs /* $Id: ipp-support.c 148 2006-04-25 16:54:17Z njacobs $ */ 29*2264Sjacobs 30*2264Sjacobs #pragma ident "%Z%%M% %I% %E% SMI" 31*2264Sjacobs 32*2264Sjacobs #include <papi_impl.h> 33*2264Sjacobs #include <stdlib.h> 34*2264Sjacobs #include <pwd.h> 35*2264Sjacobs #include <locale.h> 36*2264Sjacobs #include <errno.h> 37*2264Sjacobs #include <fcntl.h> 38*2264Sjacobs #include <sys/stat.h> 39*2264Sjacobs #include <md5.h> 40*2264Sjacobs 41*2264Sjacobs #include <config-site.h> 42*2264Sjacobs 43*2264Sjacobs papi_status_t 44*2264Sjacobs http_to_papi_status(http_status_t status) 45*2264Sjacobs { 46*2264Sjacobs switch (status) { 47*2264Sjacobs case HTTP_OK: 48*2264Sjacobs return (PAPI_OK); 49*2264Sjacobs case HTTP_BAD_REQUEST: 50*2264Sjacobs return (PAPI_BAD_REQUEST); 51*2264Sjacobs case HTTP_UNAUTHORIZED: 52*2264Sjacobs case HTTP_FORBIDDEN: 53*2264Sjacobs return (PAPI_NOT_AUTHORIZED); 54*2264Sjacobs case HTTP_NOT_FOUND: 55*2264Sjacobs return (PAPI_NOT_FOUND); 56*2264Sjacobs case HTTP_GONE: 57*2264Sjacobs return (PAPI_GONE); 58*2264Sjacobs case HTTP_SERVICE_UNAVAILABLE: 59*2264Sjacobs return (PAPI_SERVICE_UNAVAILABLE); 60*2264Sjacobs default: 61*2264Sjacobs return ((papi_status_t)status); 62*2264Sjacobs } 63*2264Sjacobs } 64*2264Sjacobs 65*2264Sjacobs papi_status_t 66*2264Sjacobs ipp_to_papi_status(uint16_t status) 67*2264Sjacobs { 68*2264Sjacobs switch (status) { 69*2264Sjacobs case IPP_OK: 70*2264Sjacobs return (PAPI_OK); 71*2264Sjacobs case IPP_OK_IGNORED_ATTRIBUTES: 72*2264Sjacobs return (PAPI_OK); 73*2264Sjacobs case IPP_OK_CONFLICTING_ATTRIBUTES: 74*2264Sjacobs return (PAPI_OK); 75*2264Sjacobs case IPP_OK_IGNORED_SUBSCRIPTIONS: 76*2264Sjacobs return (PAPI_OK_IGNORED_SUBSCRIPTIONS); 77*2264Sjacobs case IPP_OK_IGNORED_NOTIFICATIONS: 78*2264Sjacobs return (PAPI_OK_IGNORED_NOTIFICATIONS); 79*2264Sjacobs case IPP_CERR_BAD_REQUEST: 80*2264Sjacobs return (PAPI_BAD_REQUEST); 81*2264Sjacobs case IPP_CERR_FORBIDDEN: 82*2264Sjacobs return (PAPI_FORBIDDEN); 83*2264Sjacobs case IPP_CERR_NOT_AUTHENTICATED: 84*2264Sjacobs return (PAPI_NOT_AUTHENTICATED); 85*2264Sjacobs case IPP_CERR_NOT_AUTHORIZED: 86*2264Sjacobs return (PAPI_NOT_AUTHORIZED); 87*2264Sjacobs case IPP_CERR_NOT_POSSIBLE: 88*2264Sjacobs return (PAPI_NOT_POSSIBLE); 89*2264Sjacobs case IPP_CERR_TIMEOUT: 90*2264Sjacobs return (PAPI_TIMEOUT); 91*2264Sjacobs case IPP_CERR_NOT_FOUND: 92*2264Sjacobs return (PAPI_NOT_FOUND); 93*2264Sjacobs case IPP_CERR_GONE: 94*2264Sjacobs return (PAPI_GONE); 95*2264Sjacobs case IPP_CERR_REQUEST_ENTITY: 96*2264Sjacobs return (PAPI_REQUEST_ENTITY); 97*2264Sjacobs case IPP_CERR_REQUEST_VALUE: 98*2264Sjacobs return (PAPI_REQUEST_VALUE); 99*2264Sjacobs case IPP_CERR_DOCUMENT_FORMAT: 100*2264Sjacobs return (PAPI_DOCUMENT_FORMAT); 101*2264Sjacobs case IPP_CERR_ATTRIBUTES: 102*2264Sjacobs return (PAPI_ATTRIBUTES); 103*2264Sjacobs case IPP_CERR_URI_SCHEME: 104*2264Sjacobs return (PAPI_URI_SCHEME); 105*2264Sjacobs case IPP_CERR_CHARSET: 106*2264Sjacobs return (PAPI_CHARSET); 107*2264Sjacobs case IPP_CERR_CONFLICT: 108*2264Sjacobs return (PAPI_CONFLICT); 109*2264Sjacobs case IPP_CERR_COMPRESSION_NOT_SUPPORTED: 110*2264Sjacobs return (PAPI_COMPRESSION_NOT_SUPPORTED); 111*2264Sjacobs case IPP_CERR_COMPRESSION_ERROR: 112*2264Sjacobs return (PAPI_COMPRESSION_ERROR); 113*2264Sjacobs case IPP_CERR_DOCUMENT_FORMAT_ERROR: 114*2264Sjacobs return (PAPI_DOCUMENT_FORMAT_ERROR); 115*2264Sjacobs case IPP_CERR_DOCUMENT_ACCESS_ERROR: 116*2264Sjacobs return (PAPI_DOCUMENT_ACCESS_ERROR); 117*2264Sjacobs case IPP_CERR_ATTRIBUTES_NOT_SETTABLE: 118*2264Sjacobs return (PAPI_ATTRIBUTES_NOT_SETTABLE); 119*2264Sjacobs case IPP_CERR_IGNORED_ALL_SUBSCRIPTIONS: 120*2264Sjacobs return (PAPI_IGNORED_ALL_SUBSCRIPTIONS); 121*2264Sjacobs case IPP_CERR_TOO_MANY_SUBSCRIPTIONS: 122*2264Sjacobs return (PAPI_TOO_MANY_SUBSCRIPTIONS); 123*2264Sjacobs case IPP_CERR_IGNORED_ALL_NOTIFICATIONS: 124*2264Sjacobs return (PAPI_IGNORED_ALL_NOTIFICATIONS); 125*2264Sjacobs case IPP_CERR_PRINT_SUPPORT_FILE_NOT_FOUND: 126*2264Sjacobs return (PAPI_PRINT_SUPPORT_FILE_NOT_FOUND); 127*2264Sjacobs case IPP_SERR_INTERNAL: 128*2264Sjacobs return (PAPI_INTERNAL_ERROR); 129*2264Sjacobs case IPP_SERR_OPERATION_NOT_SUPPORTED: 130*2264Sjacobs return (PAPI_OPERATION_NOT_SUPPORTED); 131*2264Sjacobs case IPP_SERR_SERVICE_UNAVAILABLE: 132*2264Sjacobs return (PAPI_SERVICE_UNAVAILABLE); 133*2264Sjacobs case IPP_SERR_VERSION_NOT_SUPPORTED: 134*2264Sjacobs return (PAPI_VERSION_NOT_SUPPORTED); 135*2264Sjacobs case IPP_SERR_DEVICE_ERROR: 136*2264Sjacobs return (PAPI_DEVICE_ERROR); 137*2264Sjacobs case IPP_SERR_TEMPORARY_ERROR: 138*2264Sjacobs return (PAPI_TEMPORARY_ERROR); 139*2264Sjacobs case IPP_SERR_NOT_ACCEPTING: 140*2264Sjacobs return (PAPI_NOT_ACCEPTING); 141*2264Sjacobs case IPP_SERR_BUSY: 142*2264Sjacobs case IPP_SERR_CANCELLED: 143*2264Sjacobs default: 144*2264Sjacobs return (PAPI_TEMPORARY_ERROR); 145*2264Sjacobs } 146*2264Sjacobs } 147*2264Sjacobs 148*2264Sjacobs void 149*2264Sjacobs ipp_initialize_request(service_t *svc, papi_attribute_t ***request, 150*2264Sjacobs uint16_t operation) 151*2264Sjacobs { 152*2264Sjacobs papiAttributeListAddInteger(request, PAPI_ATTR_EXCL, 153*2264Sjacobs "version-major", 1); 154*2264Sjacobs papiAttributeListAddInteger(request, PAPI_ATTR_EXCL, 155*2264Sjacobs "version-minor", 1); 156*2264Sjacobs papiAttributeListAddInteger(request, PAPI_ATTR_EXCL, 157*2264Sjacobs "request-id", (short)lrand48()); 158*2264Sjacobs papiAttributeListAddInteger(request, PAPI_ATTR_EXCL, 159*2264Sjacobs "operation-id", operation); 160*2264Sjacobs } 161*2264Sjacobs 162*2264Sjacobs void 163*2264Sjacobs ipp_initialize_operational_attributes(service_t *svc, papi_attribute_t ***op, 164*2264Sjacobs papi_attribute_t **attributes) 165*2264Sjacobs { 166*2264Sjacobs char *charset = "utf-8"; /* default to UTF-8 encoding */ 167*2264Sjacobs char *language = setlocale(LC_ALL, ""); 168*2264Sjacobs char *user = "nobody"; 169*2264Sjacobs struct passwd *pw = NULL; 170*2264Sjacobs 171*2264Sjacobs /* 172*2264Sjacobs * All IPP requests must contain the following: 173*2264Sjacobs * attributes-charset (UTF-8) 174*2264Sjacobs * attributes-natural-language (our current locale) 175*2264Sjacobs * requesting-user-name (process user) 176*2264Sjacobs */ 177*2264Sjacobs papiAttributeListGetString(attributes, NULL, 178*2264Sjacobs "attributes-charset", &charset); 179*2264Sjacobs papiAttributeListAddString(op, PAPI_ATTR_EXCL, 180*2264Sjacobs "attributes-charset", charset); 181*2264Sjacobs 182*2264Sjacobs papiAttributeListGetString(attributes, NULL, 183*2264Sjacobs "attributes-natural-language", &language); 184*2264Sjacobs papiAttributeListAddString(op, PAPI_ATTR_EXCL, 185*2264Sjacobs "attributes-natural-language", language); 186*2264Sjacobs 187*2264Sjacobs if ((pw = getpwuid(getuid())) != NULL) 188*2264Sjacobs user = pw->pw_name; 189*2264Sjacobs /* 190*2264Sjacobs * if our euid is 0 "super user", we will allow the system supplied 191*2264Sjacobs * user name to be overridden, if the requestor wants to. 192*2264Sjacobs */ 193*2264Sjacobs if (geteuid() == 0) { 194*2264Sjacobs if (svc->user != NULL) 195*2264Sjacobs user = svc->user; 196*2264Sjacobs papiAttributeListGetString(attributes, NULL, 197*2264Sjacobs "requesting-user-name", &user); 198*2264Sjacobs } 199*2264Sjacobs papiAttributeListAddString(op, PAPI_ATTR_REPLACE, 200*2264Sjacobs "requesting-user-name", user); 201*2264Sjacobs } 202*2264Sjacobs 203*2264Sjacobs #ifndef OPID_CUPS_GET_DEFAULT /* for servers that will enumerate */ 204*2264Sjacobs #define OPID_CUPS_GET_DEFAULT 0x4001 205*2264Sjacobs #endif /* OPID_CUPS_GET_DEFAULT */ 206*2264Sjacobs 207*2264Sjacobs static papi_status_t 208*2264Sjacobs _default_destination(service_t *svc, char **uri) 209*2264Sjacobs { 210*2264Sjacobs papi_status_t result = PAPI_INTERNAL_ERROR; 211*2264Sjacobs printer_t *p = NULL; 212*2264Sjacobs papi_attribute_t **request = NULL, **op = NULL, **response = NULL; 213*2264Sjacobs char *tmp = NULL; 214*2264Sjacobs 215*2264Sjacobs if ((svc == NULL) || (uri == NULL)) 216*2264Sjacobs return (PAPI_BAD_ARGUMENT); 217*2264Sjacobs 218*2264Sjacobs /* we must be connected to find the default destination */ 219*2264Sjacobs if (svc->connection == NULL) 220*2264Sjacobs return (PAPI_NOT_POSSIBLE); 221*2264Sjacobs 222*2264Sjacobs if ((p = calloc(1, sizeof (*p))) == NULL) 223*2264Sjacobs return (PAPI_TEMPORARY_ERROR); 224*2264Sjacobs 225*2264Sjacobs ipp_initialize_request(svc, &request, OPID_CUPS_GET_DEFAULT); 226*2264Sjacobs ipp_initialize_operational_attributes(svc, &op, NULL); 227*2264Sjacobs papiAttributeListAddString(&op, PAPI_ATTR_APPEND, 228*2264Sjacobs "requested-attributes", "printer-uri-supported"); 229*2264Sjacobs papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE, 230*2264Sjacobs "operational-attributes-group", op); 231*2264Sjacobs papiAttributeListFree(op); 232*2264Sjacobs result = ipp_send_request(svc, request, &response); 233*2264Sjacobs papiAttributeListFree(request); 234*2264Sjacobs 235*2264Sjacobs op = NULL; 236*2264Sjacobs papiAttributeListGetCollection(response, NULL, 237*2264Sjacobs "printer-attributes-group", &op); 238*2264Sjacobs 239*2264Sjacobs if (uri != NULL) { 240*2264Sjacobs char *tmp = NULL; 241*2264Sjacobs 242*2264Sjacobs papiAttributeListGetString(op, NULL, "printer-uri", &tmp); 243*2264Sjacobs papiAttributeListGetString(op, NULL, 244*2264Sjacobs "printer-uri-supported", &tmp); 245*2264Sjacobs if (tmp != NULL) 246*2264Sjacobs *uri = strdup(tmp); 247*2264Sjacobs } 248*2264Sjacobs 249*2264Sjacobs papiAttributeListFree(response); 250*2264Sjacobs 251*2264Sjacobs return (result); 252*2264Sjacobs } 253*2264Sjacobs 254*2264Sjacobs void 255*2264Sjacobs ipp_add_printer_uri(service_t *svc, char *name, papi_attribute_t ***op) 256*2264Sjacobs { 257*2264Sjacobs char *uri = name; 258*2264Sjacobs char buf[BUFSIZ]; 259*2264Sjacobs uri_t *tmp = NULL; 260*2264Sjacobs 261*2264Sjacobs if (strstr(name, "://") == NULL) { /* not in URI form */ 262*2264Sjacobs if (strcmp(name, DEFAULT_DEST) != 0) { 263*2264Sjacobs /* not the "default" */ 264*2264Sjacobs snprintf(buf, sizeof (buf), "%s/%s", svc->name, name); 265*2264Sjacobs uri = buf; 266*2264Sjacobs } else 267*2264Sjacobs _default_destination(svc, &uri); 268*2264Sjacobs } 269*2264Sjacobs 270*2264Sjacobs papiAttributeListAddString(op, PAPI_ATTR_EXCL, "printer-uri", uri); 271*2264Sjacobs 272*2264Sjacobs /* save the printer-uri's path to be used by http POST request */ 273*2264Sjacobs if ((uri_from_string(uri, &tmp) == 0) && (tmp != NULL)) { 274*2264Sjacobs if (svc->post != NULL) 275*2264Sjacobs free(svc->post); 276*2264Sjacobs svc->post = strdup(tmp->path); 277*2264Sjacobs uri_free(tmp); 278*2264Sjacobs } 279*2264Sjacobs } 280*2264Sjacobs 281*2264Sjacobs 282*2264Sjacobs /* 283*2264Sjacobs * don't actually write anything, just add to the total size and return the 284*2264Sjacobs * size of what would be written, so we can figure out how big the request 285*2264Sjacobs * is going to be. 286*2264Sjacobs */ 287*2264Sjacobs static ssize_t 288*2264Sjacobs size_calculate(void *fd, void *buffer, size_t length) 289*2264Sjacobs { 290*2264Sjacobs ssize_t *size = (ssize_t *)fd; 291*2264Sjacobs 292*2264Sjacobs *size += length; 293*2264Sjacobs return (length); 294*2264Sjacobs } 295*2264Sjacobs 296*2264Sjacobs 297*2264Sjacobs static ssize_t 298*2264Sjacobs build_chunk(void *fd, void *buffer, size_t length) 299*2264Sjacobs { 300*2264Sjacobs char **s1 = fd; 301*2264Sjacobs 302*2264Sjacobs memcpy(*s1, buffer, length); 303*2264Sjacobs *s1 = *s1 + length; 304*2264Sjacobs 305*2264Sjacobs return (length); 306*2264Sjacobs } 307*2264Sjacobs 308*2264Sjacobs ssize_t 309*2264Sjacobs ipp_request_write(void *fd, void *buffer, size_t length) 310*2264Sjacobs { 311*2264Sjacobs service_t *svc = (service_t *)fd; 312*2264Sjacobs 313*2264Sjacobs #ifdef DEBUG 314*2264Sjacobs printf("ipp_request_write(0x%8.8x, 0x%8.8x, %d)\n", fd, buffer, length); 315*2264Sjacobs httpDumpData(stdout, "ipp_request_write:", buffer, length); 316*2264Sjacobs #endif 317*2264Sjacobs return (httpWrite(svc->connection, buffer, length)); 318*2264Sjacobs } 319*2264Sjacobs 320*2264Sjacobs ssize_t 321*2264Sjacobs ipp_request_read(void *fd, void *buffer, size_t length) 322*2264Sjacobs { 323*2264Sjacobs service_t *svc = (service_t *)fd; 324*2264Sjacobs ssize_t rc, i = length; 325*2264Sjacobs char *p = buffer; 326*2264Sjacobs 327*2264Sjacobs while ((rc = httpRead(svc->connection, p, i)) != i) { 328*2264Sjacobs if (rc == 0) 329*2264Sjacobs return (rc); 330*2264Sjacobs if (rc < 0) 331*2264Sjacobs return (rc); 332*2264Sjacobs i -= rc; 333*2264Sjacobs p += rc; 334*2264Sjacobs } 335*2264Sjacobs #ifdef DEBUG 336*2264Sjacobs printf("ipp_request_read(0x%8.8x, 0x%8.8x, %d) = %d\n", 337*2264Sjacobs fd, buffer, length, rc); 338*2264Sjacobs httpDumpData(stdout, "ipp_request_read:", buffer, length); 339*2264Sjacobs #endif 340*2264Sjacobs 341*2264Sjacobs return (length); 342*2264Sjacobs } 343*2264Sjacobs 344*2264Sjacobs papi_status_t 345*2264Sjacobs ipp_send_initial_request_block(service_t *svc, papi_attribute_t **request, 346*2264Sjacobs ssize_t file_size) 347*2264Sjacobs { 348*2264Sjacobs papi_status_t result = PAPI_OK; 349*2264Sjacobs ssize_t chunk_size = 0; 350*2264Sjacobs char length[32]; 351*2264Sjacobs void *chunk, *ptr; 352*2264Sjacobs http_status_t status; 353*2264Sjacobs 354*2264Sjacobs /* calculate the request size */ 355*2264Sjacobs (void) ipp_write_message(&size_calculate, &chunk_size, request); 356*2264Sjacobs 357*2264Sjacobs /* Fill in the HTTP Header information */ 358*2264Sjacobs httpClearFields(svc->connection); 359*2264Sjacobs if (svc->transfer_encoding == TRANSFER_ENCODING_CHUNKED) 360*2264Sjacobs httpSetField(svc->connection, HTTP_FIELD_TRANSFER_ENCODING, 361*2264Sjacobs "chunked"); 362*2264Sjacobs else { 363*2264Sjacobs sprintf(length, "%lu", (unsigned long)(file_size + chunk_size)); 364*2264Sjacobs httpSetField(svc->connection, HTTP_FIELD_CONTENT_LENGTH, 365*2264Sjacobs length); 366*2264Sjacobs } 367*2264Sjacobs httpSetField(svc->connection, HTTP_FIELD_CONTENT_TYPE, 368*2264Sjacobs "application/ipp"); 369*2264Sjacobs httpSetField(svc->connection, HTTP_FIELD_AUTHORIZATION, 370*2264Sjacobs svc->connection->authstring); 371*2264Sjacobs 372*2264Sjacobs /* flush any state information about this connection */ 373*2264Sjacobs httpFlush(svc->connection); 374*2264Sjacobs 375*2264Sjacobs /* if we have don't have a POST path, use the service uri path */ 376*2264Sjacobs if (svc->post == NULL) 377*2264Sjacobs svc->post = strdup(svc->uri->path); 378*2264Sjacobs /* send the HTTP POST message for the IPP request */ 379*2264Sjacobs /* if the POST fails, return the error */ 380*2264Sjacobs status = httpPost(svc->connection, svc->post); 381*2264Sjacobs if (status != 0) 382*2264Sjacobs return (http_to_papi_status(status)); 383*2264Sjacobs 384*2264Sjacobs if (httpCheck(svc->connection) != 0) { 385*2264Sjacobs status = httpUpdate(svc->connection); 386*2264Sjacobs if (status != HTTP_OK) 387*2264Sjacobs return (http_to_papi_status(status)); 388*2264Sjacobs } 389*2264Sjacobs 390*2264Sjacobs /* build the request chunk */ 391*2264Sjacobs chunk = ptr = calloc(1, chunk_size); 392*2264Sjacobs result = ipp_write_message(&build_chunk, &ptr, request); 393*2264Sjacobs #ifdef DEBUG 394*2264Sjacobs printf("request: %d (0x%x) bytes\n", chunk_size, chunk_size); 395*2264Sjacobs httpDumpData(stdout, "request:", chunk, chunk_size); 396*2264Sjacobs #endif 397*2264Sjacobs 398*2264Sjacobs /* send the actual IPP request */ 399*2264Sjacobs if (ipp_request_write(svc, chunk, chunk_size) != chunk_size) 400*2264Sjacobs result = PAPI_TEMPORARY_ERROR; 401*2264Sjacobs free(chunk); 402*2264Sjacobs 403*2264Sjacobs if (httpCheck(svc->connection) != 0) { 404*2264Sjacobs status = httpUpdate(svc->connection); 405*2264Sjacobs if (status != HTTP_OK) 406*2264Sjacobs return (http_to_papi_status(status)); 407*2264Sjacobs } 408*2264Sjacobs 409*2264Sjacobs return (result); 410*2264Sjacobs } 411*2264Sjacobs 412*2264Sjacobs static int 413*2264Sjacobs setAuthString(service_t *svc) 414*2264Sjacobs { 415*2264Sjacobs http_t *http; 416*2264Sjacobs char *user, *passphrase; 417*2264Sjacobs char encoded[BUFSIZ]; 418*2264Sjacobs 419*2264Sjacobs if ((svc == NULL) || (svc->connection == NULL) || (svc->name == NULL)) 420*2264Sjacobs return (-1); 421*2264Sjacobs 422*2264Sjacobs http = svc->connection; 423*2264Sjacobs 424*2264Sjacobs if (svc->user == NULL) { 425*2264Sjacobs struct passwd *p; 426*2264Sjacobs 427*2264Sjacobs if ((p = getpwuid(getuid())) != NULL) { 428*2264Sjacobs user = p->pw_name; 429*2264Sjacobs } else if ((user = getenv("LOGNAME")) == NULL) 430*2264Sjacobs user = getenv("USER"); 431*2264Sjacobs if (user == NULL) 432*2264Sjacobs user = "nobody"; 433*2264Sjacobs } else 434*2264Sjacobs user = svc->user; 435*2264Sjacobs 436*2264Sjacobs /* if the passphrase is not set, use the Authentication Callback */ 437*2264Sjacobs if (((svc->password == NULL) || (svc->password[0] == '\0')) && 438*2264Sjacobs (svc->authCB != NULL)) 439*2264Sjacobs (svc->authCB)(svc, svc->app_data); 440*2264Sjacobs passphrase = svc->password; 441*2264Sjacobs 442*2264Sjacobs /* if there is still no passphrase, we have to fail */ 443*2264Sjacobs if ((passphrase == NULL) || (passphrase[0] == '\0')) 444*2264Sjacobs return (-1); 445*2264Sjacobs 446*2264Sjacobs if (strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], 447*2264Sjacobs "Basic", 5) == 0) { 448*2264Sjacobs char plain[BUFSIZ]; 449*2264Sjacobs 450*2264Sjacobs snprintf(plain, sizeof (plain), "%s:%s", user, passphrase); 451*2264Sjacobs httpEncode64(encoded, plain); 452*2264Sjacobs snprintf(http->authstring, sizeof (http->authstring), 453*2264Sjacobs "Basic %s", encoded); 454*2264Sjacobs } else if (strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], 455*2264Sjacobs "Digest", 6) == 0) { 456*2264Sjacobs char realm[HTTP_MAX_VALUE]; 457*2264Sjacobs char nonce[HTTP_MAX_VALUE]; 458*2264Sjacobs char line [BUFSIZ]; 459*2264Sjacobs char urp[128]; 460*2264Sjacobs char mr[128]; 461*2264Sjacobs char *uri = svc->post; 462*2264Sjacobs 463*2264Sjacobs httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, 464*2264Sjacobs "realm", realm); 465*2264Sjacobs httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, 466*2264Sjacobs "nonce", nonce); 467*2264Sjacobs 468*2264Sjacobs snprintf(line, sizeof (line), "%s:%s:%s", user, realm, 469*2264Sjacobs passphrase); 470*2264Sjacobs md5_calc(urp, line, strlen(line)); 471*2264Sjacobs 472*2264Sjacobs snprintf(line, sizeof (line), "POST:%s", uri); 473*2264Sjacobs md5_calc(mr, line, strlen(line)); 474*2264Sjacobs 475*2264Sjacobs snprintf(line, sizeof (line), "%s:%s:%s", urp, mr, nonce); 476*2264Sjacobs md5_calc(encoded, line, strlen(line)); 477*2264Sjacobs 478*2264Sjacobs snprintf(http->authstring, sizeof (http->authstring), 479*2264Sjacobs "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", " 480*2264Sjacobs "uri=\"%s\", response=\"%s\"", user, realm, nonce, uri, 481*2264Sjacobs encoded); 482*2264Sjacobs } 483*2264Sjacobs 484*2264Sjacobs return (0); 485*2264Sjacobs } 486*2264Sjacobs 487*2264Sjacobs papi_status_t 488*2264Sjacobs ipp_status_info(service_t *svc, papi_attribute_t **response) 489*2264Sjacobs { 490*2264Sjacobs papi_attribute_t **operational = NULL; 491*2264Sjacobs int32_t status = 0; 492*2264Sjacobs 493*2264Sjacobs papiAttributeListGetCollection(response, NULL, 494*2264Sjacobs "operational-attributes-group", &operational); 495*2264Sjacobs if (operational != NULL) { 496*2264Sjacobs char *message = NULL; 497*2264Sjacobs 498*2264Sjacobs papiAttributeListGetString(response, NULL, 499*2264Sjacobs "status-message", &message); 500*2264Sjacobs papiAttributeListAddString(&svc->attributes, PAPI_ATTR_REPLACE, 501*2264Sjacobs "detailed-status-message", message); 502*2264Sjacobs } 503*2264Sjacobs papiAttributeListGetInteger(response, NULL, "status-code", &status); 504*2264Sjacobs 505*2264Sjacobs return (ipp_to_papi_status(status)); 506*2264Sjacobs } 507*2264Sjacobs 508*2264Sjacobs papi_status_t 509*2264Sjacobs ipp_send_request_with_file(service_t *svc, papi_attribute_t **request, 510*2264Sjacobs papi_attribute_t ***response, char *file) 511*2264Sjacobs { 512*2264Sjacobs papi_status_t result = PAPI_OK; 513*2264Sjacobs ssize_t size = 0; 514*2264Sjacobs int fd; 515*2264Sjacobs 516*2264Sjacobs #ifdef DEBUG 517*2264Sjacobs fprintf(stderr, "\nIPP-REQUEST: (%s)", (file ? file : "")); 518*2264Sjacobs papiAttributeListPrint(stderr, request, " "); 519*2264Sjacobs putc('\n', stderr); 520*2264Sjacobs fflush(stderr); 521*2264Sjacobs #endif 522*2264Sjacobs 523*2264Sjacobs /* 524*2264Sjacobs * if we are sending a file, open it and include it's size in the 525*2264Sjacobs * message size. 526*2264Sjacobs */ 527*2264Sjacobs if (file != NULL) { 528*2264Sjacobs if ((fd = open(file, O_RDONLY)) < 0) { 529*2264Sjacobs detailed_error(svc, "%s: %s", file, strerror(errno)); 530*2264Sjacobs return (PAPI_DOCUMENT_ACCESS_ERROR); 531*2264Sjacobs } else if (svc->transfer_encoding != 532*2264Sjacobs TRANSFER_ENCODING_CHUNKED) { 533*2264Sjacobs struct stat st; 534*2264Sjacobs 535*2264Sjacobs if (fstat(fd, &st) >= 0) 536*2264Sjacobs size = st.st_size; 537*2264Sjacobs } 538*2264Sjacobs } 539*2264Sjacobs 540*2264Sjacobs *response = NULL; 541*2264Sjacobs while (*response == NULL) { 542*2264Sjacobs http_status_t status = HTTP_CONTINUE; 543*2264Sjacobs 544*2264Sjacobs result = ipp_send_initial_request_block(svc, request, size); 545*2264Sjacobs 546*2264Sjacobs if (result == PAPI_OK) { 547*2264Sjacobs if (file != NULL) { 548*2264Sjacobs /* send the file contents if we have it */ 549*2264Sjacobs int rc; 550*2264Sjacobs char buf[BUFSIZ]; 551*2264Sjacobs 552*2264Sjacobs lseek(fd, 0L, SEEK_SET); 553*2264Sjacobs while ((rc = read(fd, buf, sizeof (buf))) > 0) { 554*2264Sjacobs if (ipp_request_write(svc, buf, rc) 555*2264Sjacobs < rc) { 556*2264Sjacobs break; 557*2264Sjacobs } 558*2264Sjacobs } 559*2264Sjacobs } 560*2264Sjacobs 561*2264Sjacobs (void) ipp_request_write(svc, "", 0); 562*2264Sjacobs } 563*2264Sjacobs 564*2264Sjacobs /* update our connection info */ 565*2264Sjacobs while (status == HTTP_CONTINUE) 566*2264Sjacobs status = httpUpdate(svc->connection); 567*2264Sjacobs 568*2264Sjacobs if (status == HTTP_UNAUTHORIZED) { 569*2264Sjacobs httpFlush(svc->connection); 570*2264Sjacobs if ((svc->connection->authstring[0] == '\0') && 571*2264Sjacobs (setAuthString(svc) == 0)) { 572*2264Sjacobs httpReconnect(svc->connection); 573*2264Sjacobs continue; 574*2264Sjacobs } 575*2264Sjacobs } else if (status == HTTP_UPGRADE_REQUIRED) { 576*2264Sjacobs /* 577*2264Sjacobs * If the transport was built with TLS support, we can 578*2264Sjacobs * try to use it. 579*2264Sjacobs */ 580*2264Sjacobs httpFlush(svc->connection); 581*2264Sjacobs httpReconnect(svc->connection); 582*2264Sjacobs httpEncryption(svc->connection, HTTP_ENCRYPT_REQUIRED); 583*2264Sjacobs continue; 584*2264Sjacobs } 585*2264Sjacobs 586*2264Sjacobs if (status != HTTP_OK) 587*2264Sjacobs return (http_to_papi_status(status)); 588*2264Sjacobs 589*2264Sjacobs /* read the IPP response */ 590*2264Sjacobs result = ipp_read_message(&ipp_request_read, svc, response, 591*2264Sjacobs IPP_TYPE_RESPONSE); 592*2264Sjacobs 593*2264Sjacobs if (result == PAPI_OK) 594*2264Sjacobs result = ipp_status_info(svc, *response); 595*2264Sjacobs #ifdef DEBUG 596*2264Sjacobs fprintf(stderr, "\nIPP-RESPONSE: (%s) (%s)", (file ? file : ""), 597*2264Sjacobs papiStatusString(result)); 598*2264Sjacobs papiAttributeListPrint(stderr, *response, " "); 599*2264Sjacobs putc('\n', stderr); 600*2264Sjacobs fflush(stderr); 601*2264Sjacobs #endif 602*2264Sjacobs } 603*2264Sjacobs 604*2264Sjacobs return (result); 605*2264Sjacobs } 606*2264Sjacobs 607*2264Sjacobs papi_status_t 608*2264Sjacobs ipp_send_request(service_t *svc, papi_attribute_t **request, 609*2264Sjacobs papi_attribute_t ***response) 610*2264Sjacobs { 611*2264Sjacobs return (ipp_send_request_with_file(svc, request, response, NULL)); 612*2264Sjacobs } 613