* (i.e. "..").
* make_certificate() - Make a self-signed SSL/TLS certificate.
* pipe_command() - Pipe the output of a command to the remote client.
+ * valid_host() - Is the Host: field valid?
* write_file() - Send a file via HTTP.
* write_pipe() - Flag that data is available on the CGI pipe.
*/
#endif /* HAVE_SSL */
static int pipe_command(cupsd_client_t *con, int infile, int *outfile,
char *command, char *options, int root);
+static int valid_host(cupsd_client_t *con);
static int write_file(cupsd_client_t *con, http_status_t code,
char *filename, char *type,
struct stat *filestats);
#ifdef AF_INET6
if (temp.addr.sa_family == AF_INET6)
{
- if (HostNameLookups)
- httpAddrLookup(&temp, con->servername, sizeof(con->servername));
- else if (httpAddrLocalhost(&temp))
+ if (httpAddrLocalhost(&temp))
strlcpy(con->servername, "localhost", sizeof(con->servername));
+ else if (HostNameLookups || RemotePort)
+ httpAddrLookup(&temp, con->servername, sizeof(con->servername));
else
httpAddrString(&temp, con->servername, sizeof(con->servername));
#endif /* AF_INET6 */
if (temp.addr.sa_family == AF_INET)
{
- if (HostNameLookups)
- httpAddrLookup(&temp, con->servername, sizeof(con->servername));
- else if (httpAddrLocalhost(&temp))
+ if (httpAddrLocalhost(&temp))
strlcpy(con->servername, "localhost", sizeof(con->servername));
+ else if (HostNameLookups || RemotePort)
+ httpAddrLookup(&temp, con->servername, sizeof(con->servername));
else
httpAddrString(&temp, con->servername, sizeof(con->servername));
#endif /* HAVE_LIBSSL */
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCloseClient(con=%p(%d))", con,
- con->http.fd);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdCloseClient: %d", con->http.fd);
/*
* Flush pending writes before closing...
"CHUNKED" : "LENGTH",
CUPS_LLCAST con->http.data_remaining, con->file);
- if (con->http.error)
- {
- cupsdCloseClient(con);
- return;
- }
-
#ifdef HAVE_SSL
if (con->auto_ssl)
{
if (httpGets(line, sizeof(line) - 1, HTTP(con)) == NULL)
{
+ if (con->http.error && con->http.error != EPIPE)
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d WAITING Closing for error %d "
+ "(%s)", con->http.fd, con->http.error,
+ strerror(con->http.error));
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d WAITING Closing on EOF",
+ con->http.fd);
+
cupsdCloseClient(con);
return;
}
}
#ifdef HAVE_GSSAPI
- con->gss_have_creds = 0;
+ {
+ OM_uint32 minor_status;
+ gss_release_cred(&minor_status, &con->gss_creds);
+ }
#endif /* HAVE_GSSAPI */
/*
}
else
{
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unsupported request line \"%s\" from %s!",
+ line, con->http.hostname);
cupsdSendError(con, HTTP_NOT_SUPPORTED, CUPSD_AUTH_NONE);
cupsdCloseClient(con);
return;
if (status != HTTP_OK && status != HTTP_CONTINUE)
{
+ if (con->http.error && con->http.error != EPIPE)
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d FIELDS Closing for error %d "
+ "(%s)", con->http.fd, con->http.error,
+ strerror(con->http.error));
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d FIELDS Closing on EOF",
+ con->http.fd);
+
cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
cupsdCloseClient(con);
return;
* Connection closed...
*/
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d Closing on EOF", con->http.fd);
cupsdCloseClient(con);
return;
}
* fields...
*/
- if ((ptr = strchr(con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE], ',')) != NULL)
+ if ((ptr = strchr(con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE],
+ ',')) != NULL)
*ptr = '\0';
- if ((ptr = strchr(con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE], ';')) != NULL)
+ if ((ptr = strchr(con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE],
+ ';')) != NULL)
*ptr = '\0';
- if ((ptr = strstr(con->http.fields[HTTP_FIELD_CONTENT_TYPE], "charset=")) != NULL)
+ if ((ptr = strstr(con->http.fields[HTTP_FIELD_CONTENT_TYPE],
+ "charset=")) != NULL)
{
/*
* Combine language and charset, and trim any extra params in the
cupsdAuthorize(con);
- if (!strncasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Keep-Alive", 10) &&
- KeepAlive)
+ if (!strncasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Keep-Alive",
+ 10) && KeepAlive)
con->http.keep_alive = HTTP_KEEPALIVE_ON;
else if (!strncasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "close", 5))
con->http.keep_alive = HTTP_KEEPALIVE_OFF;
if (!cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE))
{
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Missing Host: field in request!");
cupsdCloseClient(con);
return;
}
}
- else if (httpAddrLocalhost(con->http.hostaddr) &&
- strcasecmp(con->http.fields[HTTP_FIELD_HOST], "localhost") &&
- strncasecmp(con->http.fields[HTTP_FIELD_HOST], "localhost:", 10) &&
- strcmp(con->http.fields[HTTP_FIELD_HOST], "127.0.0.1") &&
- strncmp(con->http.fields[HTTP_FIELD_HOST], "127.0.0.1:", 10) &&
- strcmp(con->http.fields[HTTP_FIELD_HOST], "[::1]") &&
- strncmp(con->http.fields[HTTP_FIELD_HOST], "[::1]:", 6))
+ else if (!valid_host(con))
{
/*
* Access to localhost must use "localhost" or the corresponding IPv4
* or IPv6 values in the Host: field.
*/
- cupsdLogMessage(CUPSD_LOG_WARN,
+ cupsdLogMessage(CUPSD_LOG_ERROR,
"Request from \"%s\" using invalid Host: field \"%s\"",
con->http.hostname, con->http.fields[HTTP_FIELD_HOST]);
* Send 417-expectation-failed header...
*/
- if (!cupsdSendHeader(con, HTTP_EXPECTATION_FAILED, NULL, CUPSD_AUTH_NONE))
+ if (!cupsdSendHeader(con, HTTP_EXPECTATION_FAILED, NULL,
+ CUPSD_AUTH_NONE))
{
cupsdCloseClient(con);
return;
else if ((filename = get_file(con, &filestats, buf,
sizeof(buf))) == NULL)
{
- if (!cupsdSendHeader(con, HTTP_NOT_FOUND, "text/html", CUPSD_AUTH_NONE))
+ if (!cupsdSendHeader(con, HTTP_NOT_FOUND, "text/html",
+ CUPSD_AUTH_NONE))
{
cupsdCloseClient(con);
return;
{
if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0)
{
+ if (con->http.error && con->http.error != EPIPE)
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d PUT_RECV Closing for error "
+ "%d (%s)", con->http.fd, con->http.error,
+ strerror(con->http.error));
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d PUT_RECV Closing on EOF",
+ con->http.fd);
+
cupsdCloseClient(con);
return;
}
case HTTP_POST_RECV :
do
{
- if (con->request)
+ if (con->request && con->file < 0)
{
/*
* Grab any request data from the connection...
break;
}
else
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdReadClient: %d %d.%d %s %d",
+ con->http.fd, con->request->request.op.version[0],
+ con->request->request.op.version[1],
+ ippOpString(con->request->request.op.operation_id),
+ con->request->request.op.request_id);
con->bytes += ippLength(con->request);
+ }
}
if (con->file < 0 && con->http.state != HTTP_POST_SEND)
* Create a file as needed for the request data...
*/
- cupsdSetStringf(&con->filename, "%s/%08x", RequestRoot, request_id ++);
+ cupsdSetStringf(&con->filename, "%s/%08x", RequestRoot,
+ request_id ++);
con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
if (con->file < 0)
{
if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0)
{
+ if (con->http.error && con->http.error != EPIPE)
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d POST_SEND Closing for "
+ "error %d (%s)", con->http.fd, con->http.error,
+ strerror(con->http.error));
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d POST_SEND Closing on EOF",
+ con->http.fd);
+
cupsdCloseClient(con);
return;
}
if (write(con->file, line, bytes) < bytes)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdReadClient: Unable to write %d bytes to %s: %s",
- bytes, con->filename, strerror(errno));
+ "cupsdReadClient: Unable to write %d bytes to "
+ "%s: %s", bytes, con->filename,
+ strerror(errno));
close(con->file);
con->file = -1;
unlink(con->filename);
cupsdClearString(&con->filename);
- if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE))
+ if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE,
+ CUPSD_AUTH_NONE))
{
cupsdCloseClient(con);
return;
return;
else if (con->http.state != HTTP_POST_SEND)
{
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d Closing on unknown HTTP "
+ "state %d", con->http.fd, con->http.state);
cupsdCloseClient(con);
return;
}
if (con->http.state == HTTP_WAITING)
{
if (!con->http.keep_alive)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdReadClient: %d Closing because Keep-Alive disabled",
+ con->http.fd);
cupsdCloseClient(con);
+ }
else
{
cupsArrayRemove(ActiveClients, con);
strlcpy(auth_str, "Negotiate", sizeof(auth_str));
#endif /* HAVE_GSSAPI */
-#ifdef HAVE_AUTHORIZATION_H
- if (con->best && auth_type != CUPSD_AUTH_NEGOTIATE)
+ if (con->best && auth_type != CUPSD_AUTH_NEGOTIATE &&
+ !strcasecmp(con->http.hostname, "localhost"))
{
- int i; /* Looping var */
+ /*
+ * Add a "trc" (try root certification) parameter for local non-Kerberos
+ * requests when the request requires system group membership - then the
+ * client knows the root certificate can/should be used.
+ *
+ * Also, for Mac OS X we also look for @AUTHKEY and add an "authkey"
+ * parameter as needed...
+ */
+
+ int i; /* Looping var */
char *auth_key; /* Auth key buffer */
size_t auth_size; /* Size of remaining buffer */
-
auth_key = auth_str + strlen(auth_str);
auth_size = sizeof(auth_str) - (auth_key - auth_str);
for (i = 0; i < con->best->num_names; i ++)
{
+#ifdef HAVE_AUTHORIZATION_H
if (!strncasecmp(con->best->names[i], "@AUTHKEY(", 9))
{
snprintf(auth_key, auth_size, ", authkey=\"%s\"",
/* end parenthesis is stripped in conf.c */
break;
}
- else if (!strcasecmp(con->best->names[i], "@SYSTEM") &&
- SystemGroupAuthKey)
+ else
+#endif /* HAVE_AUTHORIZATION_H */
+ if (!strcasecmp(con->best->names[i], "@SYSTEM"))
{
- snprintf(auth_key, auth_size, ", authkey=\"%s\"", SystemGroupAuthKey);
+#ifdef HAVE_AUTHORIZATION_H
+ if (SystemGroupAuthKey)
+ snprintf(auth_key, auth_size,
+ ", authkey=\"%s\", trc=\"y\"",
+ SystemGroupAuthKey);
+ else
+#else
+ strlcpy(auth_key, ", trc=\"y\"", auth_size);
+#endif /* HAVE_AUTHORIZATION_H */
break;
}
}
}
-#endif /* HAVE_AUTHORIZATION_H */
if (auth_str[0])
{
* connection and we need to shut it down...
*/
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdWriteClient: %d Closing on unknown HTTP state %d",
+ con->http.fd, con->http.state);
cupsdCloseClient(con);
return;
}
{
if (httpWrite2(HTTP(con), buf, bytes) < 0)
{
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdWriteClient: %d Closing for error %d (%s)",
+ con->http.fd, con->http.error,
+ strerror(con->http.error));
cupsdCloseClient(con);
return;
}
if (bytes <= 0 ||
(con->http.state != HTTP_GET_SEND && con->http.state != HTTP_POST_SEND))
{
- if (!con->sent_header && !con->response)
+ if (!con->sent_header && con->pipe_pid)
cupsdSendError(con, HTTP_SERVER_ERROR, CUPSD_AUTH_NONE);
else
{
{
if (httpWrite2(HTTP(con), "", 0) < 0)
{
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdWriteClient: %d Closing for error %d (%s)",
+ con->http.fd, con->http.error,
+ strerror(con->http.error));
cupsdCloseClient(con);
return;
}
if (!con->http.keep_alive)
{
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdWriteClient: %d Closing because Keep-Alive disabled",
+ con->http.fd);
cupsdCloseClient(con);
return;
}
+ else
+ {
+ cupsArrayRemove(ActiveClients, con);
+ cupsdSetBusyState();
+ }
}
con->http.activity = time(NULL);
ssl_options.ServerName = con->servername;
ssl_options.ServerNameLen = strlen(con->servername);
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "get_cdsa_certificate: Looking for certs for \"%s\"...",
+ con->servername);
+
options.Data = (uint8 *)&ssl_options;
options.Length = sizeof(ssl_options);
envp[envc++] = home;
envp[envc] = NULL;
- if (!cupsdStartProcess(command, argv, envp, -1, -1, -1, -1, -1, 1, NULL, 0,
- &pid))
+ if (!cupsdStartProcess(command, argv, envp, -1, -1, -1, -1, -1, 1, NULL,
+ NULL, &pid))
{
unlink(seedfile);
return (0);
infofd = open(infofile, O_RDONLY);
if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, NULL,
- 0, &pid))
+ NULL, &pid))
{
close(infofd);
unlink(infofile);
infofd = open(infofile, O_RDONLY);
if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, NULL,
- 0, &pid))
+ NULL, &pid))
{
close(infofd);
unlink(infofile);
server_name[1024], /* SERVER_NAME environment variable */
server_port[1024]; /* SERVER_PORT environment variable */
ipp_attribute_t *attr; /* attributes-natural-language attribute */
-#ifdef HAVE_GSSAPI
- krb5_ccache ccache = NULL; /* Kerberos credentials */
-# if defined(HAVE_KRB5_CC_NEW_UNIQUE) || defined(HAVE_HEIMDAL)
- char krb5ccname[1024]; /* KRB5CCNAME environment variable */
-# endif /* HAVE_KRB5_CC_NEW_UNIQUE || HAVE_HEIMDAL */
-#endif /* HAVE_GSSAPI */
+ void *ccache = NULL; /* Kerberos credentials */
/*
*/
#ifdef HAVE_GSSAPI
- if (con->gss_have_creds)
- {
-# if !defined(HAVE_KRB5_CC_NEW_UNIQUE) && !defined(HAVE_HEIMDAL)
- cupsdLogMessage(CUPSD_LOG_INFO,
- "Sorry, your version of Kerberos does not support "
- "delegated credentials!");
-
-# else
- krb5_error_code error; /* Kerberos error code */
- OM_uint32 major_status, /* Major status code */
- minor_status; /* Minor status code */
- krb5_principal principal; /* Kerberos principal */
-
-
-# ifdef __APPLE__
- /*
- * If the weak-linked GSSAPI/Kerberos library is not present, don't try
- * to use it...
- */
-
- if (krb5_init_context != NULL)
- {
-# endif /* __APPLE__ */
-
- if (!KerberosInitialized)
- {
- /*
- * Setup a Kerberos context for the scheduler to use...
- */
-
- KerberosInitialized = 1;
-
- if (krb5_init_context(&KerberosContext))
- {
- KerberosContext = NULL;
-
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to initialize Kerberos context");
- }
- }
-
- /*
- * We MUST create a file-based cache because memory-based caches are
- * only valid for the current process/address space.
- *
- * Due to various bugs/features in different versions of Kerberos, we
- * need either the krb5_cc_new_unique() function or Heimdal's version
- * of krb5_cc_gen_new() to create a new FILE: credential cache that
- * can be passed to the backend. These functions create a temporary
- * file (typically in /tmp) containing the cached credentials, which
- * are removed when we have successfully printed a job.
- */
-
- if (KerberosContext)
- {
-# ifdef HAVE_KRB5_CC_NEW_UNIQUE
- if ((error = krb5_cc_new_unique(KerberosContext, "FILE", NULL,
- &ccache)) != 0)
-# else /* HAVE_HEIMDAL */
- if ((error = krb5_cc_gen_new(KerberosContext, &krb5_fcc_ops,
- &ccache)) != 0)
-# endif /* HAVE_KRB5_CC_NEW_UNIQUE */
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to create new credentials cache (%d/%s)",
- error, strerror(errno));
- ccache = NULL;
- }
- else if ((error = krb5_parse_name(KerberosContext, con->username,
- &principal)) != 0)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to parse kerberos username (%d/%s)", error,
- strerror(errno));
- krb5_cc_destroy(KerberosContext, ccache);
- ccache = NULL;
- }
- else if ((error = krb5_cc_initialize(KerberosContext, ccache,
- principal)))
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to initialize credentials cache (%d/%s)",
- error, strerror(errno));
- krb5_cc_destroy(KerberosContext, ccache);
- krb5_free_principal(KerberosContext, principal);
- ccache = NULL;
- }
- else
- {
- krb5_free_principal(KerberosContext, principal);
-
- /*
- * Copy the user's credentials to the new cache file...
- */
-
- major_status = gss_krb5_copy_ccache(&minor_status,
- con->gss_delegated_cred, ccache);
-
- if (GSS_ERROR(major_status))
- {
- cupsdLogGSSMessage(CUPSD_LOG_ERROR, major_status, minor_status,
- "Unable to import client credentials cache");
- krb5_cc_destroy(KerberosContext, ccache);
- ccache = NULL;
- }
- else
- {
- /*
- * Add the KRB5CCNAME environment variable to the job so that the
- * backend can use the credentials when printing.
- */
-
- snprintf(krb5ccname, sizeof(krb5ccname), "KRB5CCNAME=FILE:%s",
- krb5_cc_get_name(KerberosContext, ccache));
- envp[envc++] = krb5ccname;
-
- if (!RunUser)
- chown(krb5_cc_get_name(KerberosContext, ccache), User, Group);
- }
- }
- }
-# ifdef __APPLE__
- }
-# endif /* __APPLE__ */
-# endif /* HAVE_KRB5_CC_NEW_UNIQUE || HAVE_HEIMDAL */
- }
+ if (con->gss_creds)
+ ccache = cupsdCopyKrb5Creds(con);
#endif /* HAVE_GSSAPI */
}
envp[envc] = NULL;
- if (LogLevel == CUPSD_LOG_DEBUG2)
+ if (LogLevel >= CUPSD_LOG_DEBUG)
{
for (i = 0; i < argc; i ++)
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "pipe_command: argv[%d] = \"%s\"", i, argv[i]);
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "[CGI] argv[%d] = \"%s\"", i, argv[i]);
for (i = 0; i < envc; i ++)
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "pipe_command: envp[%d] = \"%s\"", i, envp[i]);
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "[CGI] envp[%d] = \"%s\"", i, envp[i]);
}
/*
if (cupsdOpenPipe(fds))
{
- cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create pipes for CGI %s - %s",
+ cupsdLogMessage(CUPSD_LOG_ERROR, "[CGI] Unable to create pipe for %s - %s",
argv[0], strerror(errno));
return (0);
}
*/
if (cupsdStartProcess(command, argv, envp, infile, fds[1], CGIPipes[1],
- -1, -1, root, DefaultProfile, 0, &pid) < 0)
+ -1, -1, root, DefaultProfile, NULL, &pid) < 0)
{
/*
* Error - can't fork!
*/
- cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to fork for CGI %s - %s", argv[0],
+ cupsdLogMessage(CUPSD_LOG_ERROR, "[CGI] Unable to start %s - %s", argv[0],
strerror(errno));
cupsdClosePipe(fds);
*/
if (con->username[0])
-#ifdef HAVE_GSSAPI
cupsdAddCert(pid, con->username, ccache);
-#else
- cupsdAddCert(pid, con->username, NULL);
-#endif /* HAVE_GSSAPI */
- cupsdLogMessage(CUPSD_LOG_DEBUG, "[CGI] %s started - PID = %d",
- command, pid);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "[CGI] Started %s (PID %d)", command, pid);
*outfile = fds[0];
close(fds[1]);
}
+/*
+ * 'valid_host()' - Is the Host: field valid?
+ */
+
+static int /* O - 1 if valid, 0 if not */
+valid_host(cupsd_client_t *con) /* I - Client connection */
+{
+ cupsd_alias_t *a; /* Current alias */
+ cupsd_netif_t *netif; /* Current network interface */
+ const char *host, /* Host field */
+ *end; /* End character */
+
+
+ host = con->http.fields[HTTP_FIELD_HOST];
+
+ if (httpAddrLocalhost(con->http.hostaddr))
+ {
+ /*
+ * Only allow "localhost" or the equivalent IPv4 or IPv6 numerical
+ * addresses when accessing CUPS via the loopback interface...
+ */
+
+ return (!strcasecmp(host, "localhost") ||
+ !strncasecmp(host, "localhost:", 10) ||
+ !strcasecmp(host, "localhost.") ||
+ !strncasecmp(host, "localhost.:", 11) ||
+#ifdef __linux
+ !strcasecmp(host, "localhost.localdomain") ||
+ !strncasecmp(host, "localhost.localdomain:", 22) ||
+#endif /* __linux */
+ !strcmp(host, "127.0.0.1") ||
+ !strncmp(host, "127.0.0.1:", 10) ||
+ !strcmp(host, "[::1]") ||
+ !strncmp(host, "[::1]:", 6));
+ }
+
+#ifdef HAVE_DNSSD
+ /*
+ * Check if the hostname is something.local (Bonjour); if so, allow it.
+ */
+
+ if ((end = strrchr(host, '.')) != NULL &&
+ (!strcasecmp(end, ".local") || !strncasecmp(end, ".local:", 7) ||
+ !strcasecmp(end, ".local.") || !strncasecmp(end, ".local.:", 8)))
+ return (1);
+#endif /* HAVE_DNSSD */
+
+ /*
+ * Check if the hostname is an IP address...
+ */
+
+ if (isdigit(*host & 255) || *host == '[')
+ {
+ /*
+ * Possible IPv4/IPv6 address...
+ */
+
+ char temp[1024], /* Temporary string */
+ *ptr; /* Pointer into temporary string */
+ http_addrlist_t *addrlist; /* List of addresses */
+
+
+ strlcpy(temp, host, sizeof(temp));
+ if ((ptr = strrchr(temp, ':')) != NULL && !strchr(ptr, ']'))
+ *ptr = '\0'; /* Strip :port from host value */
+
+ if ((addrlist = httpAddrGetList(temp, AF_UNSPEC, NULL)) != NULL)
+ {
+ /*
+ * Good IPv4/IPv6 address...
+ */
+
+ httpAddrFreeList(addrlist);
+ return (1);
+ }
+ }
+
+ /*
+ * Check for (alias) name matches...
+ */
+
+ for (a = (cupsd_alias_t *)cupsArrayFirst(ServerAlias);
+ a;
+ a = (cupsd_alias_t *)cupsArrayNext(ServerAlias))
+ {
+ /*
+ * "ServerAlias *" allows all host values through...
+ */
+
+ if (!strcmp(a->name, "*"))
+ return (1);
+
+ if (!strncasecmp(host, a->name, a->namelen))
+ {
+ /*
+ * Prefix matches; check the character at the end - it must be ":", ".",
+ * ".:", or nul...
+ */
+
+ end = host + a->namelen;
+
+ if (!*end || *end == ':' || (*end == '.' && (!end[1] || end[1] == ':')))
+ return (1);
+ }
+ }
+
+#ifdef HAVE_DNSSD
+ for (a = (cupsd_alias_t *)cupsArrayFirst(DNSSDAlias);
+ a;
+ a = (cupsd_alias_t *)cupsArrayNext(DNSSDAlias))
+ {
+ /*
+ * "ServerAlias *" allows all host values through...
+ */
+
+ if (!strcmp(a->name, "*"))
+ return (1);
+
+ if (!strncasecmp(host, a->name, a->namelen))
+ {
+ /*
+ * Prefix matches; check the character at the end - it must be ":", ".",
+ * ".:", or nul...
+ */
+
+ end = host + a->namelen;
+
+ if (!*end || *end == ':' || (*end == '.' && (!end[1] || end[1] == ':')))
+ return (1);
+ }
+ }
+#endif /* HAVE_DNSSD */
+
+ /*
+ * Check for interface hostname matches...
+ */
+
+ for (netif = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
+ netif;
+ netif = (cupsd_netif_t *)cupsArrayNext(NetIFList))
+ {
+ if (!strncasecmp(host, netif->hostname, netif->hostlen))
+ {
+ /*
+ * Prefix matches; check the character at the end - it must be ":", ".",
+ * ".:", or nul...
+ */
+
+ end = host + netif->hostlen;
+
+ if (!*end || *end == ':' || (*end == '.' && (!end[1] || end[1] == ':')))
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+
/*
* 'write_file()' - Send a file via HTTP.
*/