static void read_snmp_response(int fd) /* I - SNMP socket file descriptor */ { char addrname[256]; /* Source address name */ cups_snmp_t packet; /* Decoded packet */ snmp_cache_t key, /* Search key */ *device; /* Matching device */ /* * Read the response data... */ if (!_cupsSNMPRead(fd, &packet, -1.0)) { fprintf(stderr, "ERROR: Unable to read data from socket: %s\n", strerror(errno)); return; } if (HostNameLookups) httpAddrLookup(&(packet.address), addrname, sizeof(addrname)); else httpAddrString(&(packet.address), addrname, sizeof(addrname)); debug_printf("DEBUG: %.3f Received data from %s...\n", run_time(), addrname); /* * Look for the response status code in the SNMP message header... */ if (packet.error) { fprintf(stderr, "ERROR: Bad SNMP packet from %s: %s\n", addrname, packet.error); return; } debug_printf("DEBUG: community=\"%s\"\n", packet.community); debug_printf("DEBUG: request-id=%d\n", packet.request_id); debug_printf("DEBUG: error-status=%d\n", packet.error_status); if (packet.error_status && packet.request_id != DEVICE_TYPE) return; /* * Find a matching device in the cache... */ key.addrname = addrname; device = (snmp_cache_t *)cupsArrayFind(Devices, &key); /* * Process the message... */ switch (packet.request_id) { case DEVICE_TYPE : /* * Got the device type response... */ if (device) { debug_printf("DEBUG: Discarding duplicate device type for \"%s\"...\n", addrname); return; } /* * Add the device and request the device data... */ add_cache(&(packet.address), addrname, NULL, NULL, NULL); _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community, CUPS_ASN1_GET_REQUEST, DEVICE_DESCRIPTION, DescriptionOID); _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community, CUPS_ASN1_GET_REQUEST, DEVICE_ID, DeviceIdOID); _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community, CUPS_ASN1_GET_REQUEST, DEVICE_URI, UriOID); _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community, CUPS_ASN1_GET_REQUEST, DEVICE_LOCATION, LocationOID); _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community, CUPS_ASN1_GET_REQUEST, DEVICE_PRODUCT, LexmarkProductOID); _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community, CUPS_ASN1_GET_REQUEST, DEVICE_PRODUCT, LexmarkProductOID2); _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community, CUPS_ASN1_GET_REQUEST, DEVICE_ID, LexmarkDeviceIdOID); _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community, CUPS_ASN1_GET_REQUEST, DEVICE_PRODUCT, XeroxProductOID); break; case DEVICE_DESCRIPTION : if (device && packet.object_type == CUPS_ASN1_OCTET_STRING) { /* * Update an existing cache entry... */ char make_model[256]; /* Make and model */ if (strchr((char *)packet.object_value.string.bytes, ':') && strchr((char *)packet.object_value.string.bytes, ';')) { /* * Description is the IEEE-1284 device ID... */ char *ptr; /* Pointer into device ID */ for (ptr = (char *)packet.object_value.string.bytes; *ptr; ptr ++) if (*ptr == '\n') *ptr = ';'; /* A lot of bad printers put a newline */ if (!device->id) device->id = strdup((char *)packet.object_value.string.bytes); backendGetMakeModel((char *)packet.object_value.string.bytes, make_model, sizeof(make_model)); if (device->info) free(device->info); device->info = strdup(make_model); } else { /* * Description is plain text... */ fix_make_model(make_model, (char *)packet.object_value.string.bytes, sizeof(make_model)); if (device->info) free(device->info); device->info = strdup((char *)packet.object_value.string.bytes); } if (!device->make_and_model) device->make_and_model = strdup(make_model); } break; case DEVICE_ID : if (device && packet.object_type == CUPS_ASN1_OCTET_STRING && (!device->id || strlen(device->id) < packet.object_value.string.num_bytes)) { /* * Update an existing cache entry... */ char make_model[256]; /* Make and model */ char *ptr; /* Pointer into device ID */ for (ptr = (char *)packet.object_value.string.bytes; *ptr; ptr ++) if (*ptr == '\n') *ptr = ';'; /* A lot of bad printers put a newline */ if (device->id) free(device->id); device->id = strdup((char *)packet.object_value.string.bytes); /* * Convert the ID to a make and model string... */ backendGetMakeModel((char *)packet.object_value.string.bytes, make_model, sizeof(make_model)); if (device->make_and_model) free(device->make_and_model); device->make_and_model = strdup(make_model); } break; case DEVICE_LOCATION : if (device && packet.object_type == CUPS_ASN1_OCTET_STRING && !device->location) device->location = strdup((char *)packet.object_value.string.bytes); break; case DEVICE_PRODUCT : if (device && packet.object_type == CUPS_ASN1_OCTET_STRING && !device->id) { /* * Update an existing cache entry... */ if (!device->info) device->info = strdup((char *)packet.object_value.string.bytes); if (device->make_and_model) free(device->make_and_model); device->make_and_model = strdup((char *)packet.object_value.string.bytes); } break; case DEVICE_URI : if (device && packet.object_type == CUPS_ASN1_OCTET_STRING && !device->uri && packet.object_value.string.num_bytes > 3) { /* * Update an existing cache entry... */ char scheme[32], /* URI scheme */ userpass[256], /* Username:password in URI */ hostname[256], /* Hostname in URI */ resource[1024]; /* Resource path in URI */ int port; /* Port number in URI */ if (!strncmp((char *)packet.object_value.string.bytes, "lpr:", 4)) { /* * We want "lpd://..." for the URI... */ packet.object_value.string.bytes[2] = 'd'; } if (httpSeparateURI(HTTP_URI_CODING_ALL, (char *)packet.object_value.string.bytes, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource)) >= HTTP_URI_OK) device->uri = strdup((char *)packet.object_value.string.bytes); } break; } }
void cupsdNetIFUpdate(void) { int match; /* Matching address? */ cupsd_listener_t *lis; /* Listen address */ cupsd_netif_t *temp; /* New interface */ struct ifaddrs *addrs, /* Interface address list */ *addr; /* Current interface address */ char hostname[1024]; /* Hostname for address */ size_t hostlen; /* Length of hostname */ /* * Only update the list if we need to... */ if (!NetIFUpdate) return; NetIFUpdate = 0; /* * Free the old interfaces... */ cupsdNetIFFree(); /* * Make sure we have an array... */ if (!NetIFList) NetIFList = cupsArrayNew((cups_array_func_t)compare_netif, NULL); if (!NetIFList) return; /* * Grab a new list of interfaces... */ if (getifaddrs(&addrs) < 0) { cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: Unable to get interface list - %s", strerror(errno)); return; } for (addr = addrs; addr != NULL; addr = addr->ifa_next) { /* * See if this interface address is IPv4 or IPv6... */ if (addr->ifa_addr == NULL || (addr->ifa_addr->sa_family != AF_INET #ifdef AF_INET6 && addr->ifa_addr->sa_family != AF_INET6 #endif ) || addr->ifa_netmask == NULL || addr->ifa_name == NULL) { cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: Ignoring \"%s\".", addr->ifa_name); continue; } /* * Try looking up the hostname for the address as needed... */ if (HostNameLookups) httpAddrLookup((http_addr_t *)(addr->ifa_addr), hostname, sizeof(hostname)); else { /* * Map the default server address and localhost to the server name * and localhost, respectively; for all other addresses, use the * numeric address... */ if (httpAddrLocalhost((http_addr_t *)(addr->ifa_addr))) strlcpy(hostname, "localhost", sizeof(hostname)); else httpAddrString((http_addr_t *)(addr->ifa_addr), hostname, sizeof(hostname)); } /* * Create a new address element... */ hostlen = strlen(hostname); if ((temp = calloc(1, sizeof(cupsd_netif_t) + hostlen)) == NULL) { cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: Unable to allocate memory for interface."); break; } /* * Copy all of the information... */ strlcpy(temp->name, addr->ifa_name, sizeof(temp->name)); temp->hostlen = hostlen; memcpy(temp->hostname, hostname, hostlen + 1); if (addr->ifa_addr->sa_family == AF_INET) { /* * Copy IPv4 addresses... */ memcpy(&(temp->address), addr->ifa_addr, sizeof(struct sockaddr_in)); memcpy(&(temp->mask), addr->ifa_netmask, sizeof(struct sockaddr_in)); if (addr->ifa_dstaddr) memcpy(&(temp->broadcast), addr->ifa_dstaddr, sizeof(struct sockaddr_in)); } #ifdef AF_INET6 else { /* * Copy IPv6 addresses... */ memcpy(&(temp->address), addr->ifa_addr, sizeof(struct sockaddr_in6)); memcpy(&(temp->mask), addr->ifa_netmask, sizeof(struct sockaddr_in6)); if (addr->ifa_dstaddr) memcpy(&(temp->broadcast), addr->ifa_dstaddr, sizeof(struct sockaddr_in6)); } #endif /* AF_INET6 */ if (!(addr->ifa_flags & IFF_POINTOPOINT) && !httpAddrLocalhost(&(temp->address))) temp->is_local = 1; /* * Determine which port to use when advertising printers... */ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); lis; lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) { match = 0; if (httpAddrAny(&(lis->address))) match = 1; else if (addr->ifa_addr->sa_family == AF_INET && lis->address.addr.sa_family == AF_INET && (lis->address.ipv4.sin_addr.s_addr & temp->mask.ipv4.sin_addr.s_addr) == (temp->address.ipv4.sin_addr.s_addr & temp->mask.ipv4.sin_addr.s_addr)) match = 1; #ifdef AF_INET6 else if (addr->ifa_addr->sa_family == AF_INET6 && lis->address.addr.sa_family == AF_INET6 && (lis->address.ipv6.sin6_addr.s6_addr[0] & temp->mask.ipv6.sin6_addr.s6_addr[0]) == (temp->address.ipv6.sin6_addr.s6_addr[0] & temp->mask.ipv6.sin6_addr.s6_addr[0]) && (lis->address.ipv6.sin6_addr.s6_addr[1] & temp->mask.ipv6.sin6_addr.s6_addr[1]) == (temp->address.ipv6.sin6_addr.s6_addr[1] & temp->mask.ipv6.sin6_addr.s6_addr[1]) && (lis->address.ipv6.sin6_addr.s6_addr[2] & temp->mask.ipv6.sin6_addr.s6_addr[2]) == (temp->address.ipv6.sin6_addr.s6_addr[2] & temp->mask.ipv6.sin6_addr.s6_addr[2]) && (lis->address.ipv6.sin6_addr.s6_addr[3] & temp->mask.ipv6.sin6_addr.s6_addr[3]) == (temp->address.ipv6.sin6_addr.s6_addr[3] & temp->mask.ipv6.sin6_addr.s6_addr[3])) match = 1; #endif /* AF_INET6 */ if (match) { temp->port = httpAddrPort(&(lis->address)); break; } } /* * Add it to the array... */ cupsArrayAdd(NetIFList, temp); cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: \"%s\" = %s:%d", temp->name, temp->hostname, temp->port); } freeifaddrs(addrs); }
int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { int i; /* Looping var */ int num_defaults; /* Number of default options */ cups_option_t *defaults; /* Default options */ char line[256], /* Command string */ command, /* Command code */ *dest, /* Pointer to destination */ *list, /* Pointer to list */ *agent, /* Pointer to user */ status; /* Status for client */ socklen_t hostlen; /* Size of client address */ http_addr_t hostaddr; /* Address of client */ char hostname[256], /* Name of client */ hostip[256], /* IP address */ *hostfamily; /* Address family */ int hostlookups; /* Do hostname lookups? */ #ifdef __APPLE__ vproc_transaction_t vtran = vproc_transaction_begin(NULL); #endif /* __APPLE__ */ /* * Don't buffer the output... */ setbuf(stdout, NULL); /* * Log things using the "cups-lpd" name... */ openlog("cups-lpd", LOG_PID, LOG_LPR); /* * Scan the command-line for options... */ num_defaults = 0; defaults = NULL; hostlookups = 1; for (i = 1; i < argc; i ++) if (argv[i][0] == '-') { switch (argv[i][1]) { case 'h' : /* -h hostname[:port] */ if (argv[i][2]) cupsSetServer(argv[i] + 2); else { i ++; if (i < argc) cupsSetServer(argv[i]); else syslog(LOG_WARNING, "Expected hostname string after -h option!"); } break; case 'o' : /* Option */ if (argv[i][2]) num_defaults = cupsParseOptions(argv[i] + 2, num_defaults, &defaults); else { i ++; if (i < argc) num_defaults = cupsParseOptions(argv[i], num_defaults, &defaults); else syslog(LOG_WARNING, "Expected option string after -o option!"); } break; case 'n' : /* Don't do hostname lookups */ hostlookups = 0; break; default : syslog(LOG_WARNING, "Unknown option \"%c\" ignored!", argv[i][1]); break; } } else syslog(LOG_WARNING, "Unknown command-line option \"%s\" ignored!", argv[i]); /* * Get the address of the client... */ hostlen = sizeof(hostaddr); if (getpeername(0, (struct sockaddr *)&hostaddr, &hostlen)) { syslog(LOG_WARNING, "Unable to get client address - %s", strerror(errno)); strlcpy(hostname, "unknown", sizeof(hostname)); } else { httpAddrString(&hostaddr, hostip, sizeof(hostip)); if (hostlookups) httpAddrLookup(&hostaddr, hostname, sizeof(hostname)); else strlcpy(hostname, hostip, sizeof(hostname)); #ifdef AF_INET6 if (hostaddr.addr.sa_family == AF_INET6) hostfamily = "IPv6"; else #endif /* AF_INET6 */ hostfamily = "IPv4"; syslog(LOG_INFO, "Connection from %s (%s %s)", hostname, hostfamily, hostip); } num_defaults = cupsAddOption("job-originating-host-name", hostname, num_defaults, &defaults); /* * RFC1179 specifies that only 1 daemon command can be received for * every connection. */ if (smart_gets(line, sizeof(line), stdin) == NULL) { /* * Unable to get command from client! Send an error status and return. */ syslog(LOG_ERR, "Unable to get command line from client!"); putchar(1); #ifdef __APPLE__ vproc_transaction_end(NULL, vtran); #endif /* __APPLE__ */ return (1); } /* * The first byte is the command byte. After that will be the queue name, * resource list, and/or user name. */ if ((command = line[0]) == '\0') dest = line; else dest = line + 1; if (command == 0x02) list = NULL; else { for (list = dest; *list && !isspace(*list & 255); list ++); while (isspace(*list & 255)) *list++ = '\0'; } /* * Do the command... */ switch (command) { default : /* Unknown command */ syslog(LOG_ERR, "Unknown LPD command 0x%02X!", command); syslog(LOG_ERR, "Command line = %s", line + 1); putchar(1); status = 1; break; case 0x01 : /* Print any waiting jobs */ syslog(LOG_INFO, "Print waiting jobs (no-op)"); putchar(0); status = 0; break; case 0x02 : /* Receive a printer job */ syslog(LOG_INFO, "Receive print job for %s", dest); /* recv_print_job() sends initial status byte */ status = (char)recv_print_job(dest, num_defaults, defaults); break; case 0x03 : /* Send queue state (short) */ syslog(LOG_INFO, "Send queue state (short) for %s %s", dest, list); /* no status byte for this command */ status = (char)send_state(dest, list, 0); break; case 0x04 : /* Send queue state (long) */ syslog(LOG_INFO, "Send queue state (long) for %s %s", dest, list); /* no status byte for this command */ status = (char)send_state(dest, list, 1); break; case 0x05 : /* Remove jobs */ if (list) { /* * Grab the agent and skip to the list of users and/or jobs. */ agent = list; for (; *list && !isspace(*list & 255); list ++); while (isspace(*list & 255)) *list++ = '\0'; syslog(LOG_INFO, "Remove jobs %s on %s by %s", list, dest, agent); status = (char)remove_jobs(dest, agent, list); } else status = 1; putchar(status); break; } syslog(LOG_INFO, "Closing connection"); closelog(); #ifdef __APPLE__ vproc_transaction_end(NULL, vtran); #endif /* __APPLE__ */ return (status); }
int /* O - 0 on success, -1 on failure */ _httpTLSStart(http_t *http) /* I - Connection to server */ { char hostname[256], /* Hostname */ *hostptr; /* Pointer into hostname */ int status; /* Status of handshake */ gnutls_certificate_credentials_t *credentials; /* TLS credentials */ char priority_string[1024]; /* Priority string */ DEBUG_printf(("3_httpTLSStart(http=%p)", http)); if (tls_options < 0) { DEBUG_puts("4_httpTLSStart: Setting defaults."); _cupsSetDefaults(); DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options)); } if (http->mode == _HTTP_MODE_SERVER && !tls_keypath) { DEBUG_puts("4_httpTLSStart: cupsSetServerCredentials not called."); http->error = errno = EINVAL; http->status = HTTP_STATUS_ERROR; _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Server credentials not set."), 1); return (-1); } credentials = (gnutls_certificate_credentials_t *) malloc(sizeof(gnutls_certificate_credentials_t)); if (credentials == NULL) { DEBUG_printf(("8_httpStartTLS: Unable to allocate credentials: %s", strerror(errno))); http->error = errno; http->status = HTTP_STATUS_ERROR; _cupsSetHTTPError(HTTP_STATUS_ERROR); return (-1); } gnutls_certificate_allocate_credentials(credentials); status = gnutls_init(&http->tls, http->mode == _HTTP_MODE_CLIENT ? GNUTLS_CLIENT : GNUTLS_SERVER); if (!status) status = gnutls_set_default_priority(http->tls); if (status) { http->error = EIO; http->status = HTTP_STATUS_ERROR; DEBUG_printf(("4_httpTLSStart: Unable to initialize common TLS parameters: %s", gnutls_strerror(status))); _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, gnutls_strerror(status), 0); gnutls_deinit(http->tls); gnutls_certificate_free_credentials(*credentials); free(credentials); http->tls = NULL; return (-1); } if (http->mode == _HTTP_MODE_CLIENT) { /* * Client: get the hostname to use for TLS... */ if (httpAddrLocalhost(http->hostaddr)) { strlcpy(hostname, "localhost", sizeof(hostname)); } else { /* * Otherwise make sure the hostname we have does not end in a trailing dot. */ strlcpy(hostname, http->hostname, sizeof(hostname)); if ((hostptr = hostname + strlen(hostname) - 1) >= hostname && *hostptr == '.') *hostptr = '\0'; } status = gnutls_server_name_set(http->tls, GNUTLS_NAME_DNS, hostname, strlen(hostname)); } else { /* * Server: get certificate and private key... */ char crtfile[1024], /* Certificate file */ keyfile[1024]; /* Private key file */ int have_creds = 0; /* Have credentials? */ if (http->fields[HTTP_FIELD_HOST][0]) { /* * Use hostname for TLS upgrade... */ strlcpy(hostname, http->fields[HTTP_FIELD_HOST], sizeof(hostname)); } else { /* * Resolve hostname from connection address... */ http_addr_t addr; /* Connection address */ socklen_t addrlen; /* Length of address */ addrlen = sizeof(addr); if (getsockname(http->fd, (struct sockaddr *)&addr, &addrlen)) { DEBUG_printf(("4_httpTLSStart: Unable to get socket address: %s", strerror(errno))); hostname[0] = '\0'; } else if (httpAddrLocalhost(&addr)) hostname[0] = '\0'; else { httpAddrLookup(&addr, hostname, sizeof(hostname)); DEBUG_printf(("4_httpTLSStart: Resolved socket address to \"%s\".", hostname)); } } if (isdigit(hostname[0] & 255) || hostname[0] == '[') hostname[0] = '\0'; /* Don't allow numeric addresses */ if (hostname[0]) { http_gnutls_make_path(crtfile, sizeof(crtfile), tls_keypath, hostname, "crt"); http_gnutls_make_path(keyfile, sizeof(keyfile), tls_keypath, hostname, "key"); have_creds = !access(crtfile, 0) && !access(keyfile, 0); } else if (tls_common_name) { http_gnutls_make_path(crtfile, sizeof(crtfile), tls_keypath, tls_common_name, "crt"); http_gnutls_make_path(keyfile, sizeof(keyfile), tls_keypath, tls_common_name, "key"); have_creds = !access(crtfile, 0) && !access(keyfile, 0); } if (!have_creds && tls_auto_create && (hostname[0] || tls_common_name)) { DEBUG_printf(("4_httpTLSStart: Auto-create credentials for \"%s\".", hostname[0] ? hostname : tls_common_name)); if (!cupsMakeServerCredentials(tls_keypath, hostname[0] ? hostname : tls_common_name, 0, NULL, time(NULL) + 365 * 86400)) { DEBUG_puts("4_httpTLSStart: cupsMakeServerCredentials failed."); http->error = errno = EINVAL; http->status = HTTP_STATUS_ERROR; _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create server credentials."), 1); return (-1); } } DEBUG_printf(("4_httpTLSStart: Using certificate \"%s\" and private key \"%s\".", crtfile, keyfile)); status = gnutls_certificate_set_x509_key_file(*credentials, crtfile, keyfile, GNUTLS_X509_FMT_PEM); } if (!status) status = gnutls_credentials_set(http->tls, GNUTLS_CRD_CERTIFICATE, *credentials); if (status) { http->error = EIO; http->status = HTTP_STATUS_ERROR; DEBUG_printf(("4_httpTLSStart: Unable to complete client/server setup: %s", gnutls_strerror(status))); _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, gnutls_strerror(status), 0); gnutls_deinit(http->tls); gnutls_certificate_free_credentials(*credentials); free(credentials); http->tls = NULL; return (-1); } strlcpy(priority_string, "NORMAL", sizeof(priority_string)); if (tls_options & _HTTP_TLS_DENY_TLS10) strlcat(priority_string, ":+VERS-TLS-ALL:-VERS-TLS1.0:-VERS-SSL3.0", sizeof(priority_string)); else if (tls_options & _HTTP_TLS_ALLOW_SSL3) strlcat(priority_string, ":+VERS-TLS-ALL", sizeof(priority_string)); else strlcat(priority_string, ":+VERS-TLS-ALL:-VERS-SSL3.0", sizeof(priority_string)); if (!(tls_options & _HTTP_TLS_ALLOW_RC4)) strlcat(priority_string, ":-ARCFOUR-128", sizeof(priority_string)); if (!(tls_options & _HTTP_TLS_ALLOW_DH)) strlcat(priority_string, ":!ANON-DH", sizeof(priority_string)); #ifdef HAVE_GNUTLS_PRIORITY_SET_DIRECT gnutls_priority_set_direct(http->tls, priority_string, NULL); #else gnutls_priority_t priority; /* Priority */ gnutls_priority_init(&priority, priority_string, NULL); gnutls_priority_set(http->tls, priority); gnutls_priority_deinit(priority); #endif /* HAVE_GNUTLS_PRIORITY_SET_DIRECT */ gnutls_transport_set_ptr(http->tls, (gnutls_transport_ptr_t)http); gnutls_transport_set_pull_function(http->tls, http_gnutls_read); #ifdef HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION gnutls_transport_set_pull_timeout_function(http->tls, (gnutls_pull_timeout_func)httpWait); #endif /* HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION */ gnutls_transport_set_push_function(http->tls, http_gnutls_write); while ((status = gnutls_handshake(http->tls)) != GNUTLS_E_SUCCESS) { DEBUG_printf(("5_httpStartTLS: gnutls_handshake returned %d (%s)", status, gnutls_strerror(status))); if (gnutls_error_is_fatal(status)) { http->error = EIO; http->status = HTTP_STATUS_ERROR; _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, gnutls_strerror(status), 0); gnutls_deinit(http->tls); gnutls_certificate_free_credentials(*credentials); free(credentials); http->tls = NULL; return (-1); } } http->tls_credentials = credentials; return (0); }