You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1869 lines
46 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/*
* Directory services routines for the CUPS scheduler.
*
* Copyright © 2007-2018 by Apple Inc.
* Copyright © 1997-2007 by Easy Software Products, all rights reserved.
*
* Licensed under Apache License v2.0. See the file "LICENSE" for more
* information.
*/
/*
* Include necessary headers...
*/
#include "cupsd.h"
#include <grp.h>
#if defined(HAVE_DNSSD) && defined(__APPLE__)
# include <nameser.h>
# include <CoreFoundation/CoreFoundation.h>
# include <SystemConfiguration/SystemConfiguration.h>
#endif /* HAVE_DNSSD && __APPLE__ */
/*
* Local globals...
*/
#ifdef HAVE_AVAHI
static int avahi_running = 0;
#endif /* HAVE_AVAHI */
/*
* Local functions...
*/
#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
static char *get_auth_info_required(cupsd_printer_t *p,
char *buffer, size_t bufsize);
#endif /* HAVE_DNSSD || HAVE_AVAHI */
#ifdef __APPLE__
static int get_hostconfig(const char *name);
#endif /* __APPLE__ */
static void update_lpd(int onoff);
static void update_smb(int onoff);
#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
# ifdef __APPLE__
static void dnssdAddAlias(const void *key, const void *value,
void *context);
# endif /* __APPLE__ */
static cupsd_txt_t dnssdBuildTxtRecord(cupsd_printer_t *p, int for_lpd);
# ifdef HAVE_AVAHI
static void dnssdClientCallback(AvahiClient *c, AvahiClientState state, void *userdata);
# endif /* HAVE_AVAHI */
static void dnssdDeregisterAllPrinters(int from_callback);
static void dnssdDeregisterInstance(cupsd_srv_t *srv, int from_callback);
static void dnssdDeregisterPrinter(cupsd_printer_t *p, int clear_name, int from_callback);
static const char *dnssdErrorString(int error);
static void dnssdFreeTxtRecord(cupsd_txt_t *txt);
static void dnssdRegisterAllPrinters(int from_callback);
# ifdef HAVE_DNSSD
static void dnssdRegisterCallback(DNSServiceRef sdRef,
DNSServiceFlags flags,
DNSServiceErrorType errorCode,
const char *name,
const char *regtype,
const char *domain,
void *context);
# else
static void dnssdRegisterCallback(AvahiEntryGroup *p,
AvahiEntryGroupState state,
void *context);
# endif /* HAVE_DNSSD */
static int dnssdRegisterInstance(cupsd_srv_t *srv, cupsd_printer_t *p, char *name, const char *type, const char *subtypes, int port, cupsd_txt_t *txt, int commit, int from_callback);
static void dnssdRegisterPrinter(cupsd_printer_t *p, int from_callback);
static void dnssdStop(void);
# ifdef HAVE_DNSSD
static void dnssdUpdate(void);
# endif /* HAVE_DNSSD */
static void dnssdUpdateDNSSDName(int from_callback);
#endif /* HAVE_DNSSD || HAVE_AVAHI */
/*
* 'cupsdDeregisterPrinter()' - Stop sending broadcast information for a
* local printer and remove any pending
* references to remote printers.
*/
void
cupsdDeregisterPrinter(
cupsd_printer_t *p, /* I - Printer to register */
int removeit) /* I - Printer being permanently removed */
{
/*
* Only deregister if browsing is enabled and it's a local printer...
*/
cupsdLogMessage(CUPSD_LOG_DEBUG,
"cupsdDeregisterPrinter(p=%p(%s), removeit=%d)", p, p->name,
removeit);
if (!Browsing || !p->shared ||
(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_SCANNER)))
return;
/*
* Announce the deletion...
*/
#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDMaster)
dnssdDeregisterPrinter(p, 1, 0);
#endif /* HAVE_DNSSD || HAVE_AVAHI */
}
/*
* 'cupsdRegisterPrinter()' - Start sending broadcast information for a
* printer or update the broadcast contents.
*/
void
cupsdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
{
cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdRegisterPrinter(p=%p(%s))", p,
p->name);
if (!Browsing || !BrowseLocalProtocols ||
(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_SCANNER)))
return;
#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDMaster)
dnssdRegisterPrinter(p, 0);
#endif /* HAVE_DNSSD || HAVE_AVAHI */
}
/*
* 'cupsdStartBrowsing()' - Start sending and receiving broadcast information.
*/
void
cupsdStartBrowsing(void)
{
if (!Browsing || !BrowseLocalProtocols)
return;
#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
if (BrowseLocalProtocols & BROWSE_DNSSD)
{
# ifdef HAVE_DNSSD
DNSServiceErrorType error; /* Error from service creation */
/*
* First create a "master" connection for all registrations...
*/
if ((error = DNSServiceCreateConnection(&DNSSDMaster))
!= kDNSServiceErr_NoError)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to create master DNS-SD reference: %d", error);
if (FatalErrors & CUPSD_FATAL_BROWSE)
cupsdEndProcess(getpid(), 0);
}
else
{
/*
* Add the master connection to the select list...
*/
int fd = DNSServiceRefSockFD(DNSSDMaster);
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
cupsdAddSelect(fd, (cupsd_selfunc_t)dnssdUpdate, NULL, NULL);
}
/*
* Set the computer name and register the web interface...
*/
DNSSDPort = 0;
cupsdUpdateDNSSDName();
# else /* HAVE_AVAHI */
if ((DNSSDMaster = avahi_threaded_poll_new()) == NULL)
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create DNS-SD thread.");
if (FatalErrors & CUPSD_FATAL_BROWSE)
cupsdEndProcess(getpid(), 0);
}
else
{
int error; /* Error code, if any */
DNSSDClient = avahi_client_new(avahi_threaded_poll_get(DNSSDMaster), AVAHI_CLIENT_NO_FAIL, dnssdClientCallback, NULL, &error);
if (DNSSDClient == NULL)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to communicate with avahi-daemon: %s",
dnssdErrorString(error));
if (FatalErrors & CUPSD_FATAL_BROWSE)
cupsdEndProcess(getpid(), 0);
avahi_threaded_poll_free(DNSSDMaster);
DNSSDMaster = NULL;
}
else
avahi_threaded_poll_start(DNSSDMaster);
}
# endif /* HAVE_DNSSD */
}
#endif /* HAVE_DNSSD || HAVE_AVAHI */
/*
* Enable LPD and SMB printer sharing as needed through external programs...
*/
if (BrowseLocalProtocols & BROWSE_LPD)
update_lpd(1);
if (BrowseLocalProtocols & BROWSE_SMB)
update_smb(1);
#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
/*
* Register the individual printers
*/
dnssdRegisterAllPrinters(0);
#endif /* HAVE_DNSSD || HAVE_AVAHI */
}
/*
* 'cupsdStopBrowsing()' - Stop sending and receiving broadcast information.
*/
void
cupsdStopBrowsing(void)
{
if (!Browsing || !BrowseLocalProtocols)
return;
#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
/*
* De-register the individual printers
*/
dnssdDeregisterAllPrinters(0);
/*
* Shut down browsing sockets...
*/
if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDMaster)
dnssdStop();
#endif /* HAVE_DNSSD || HAVE_AVAHI */
/*
* Disable LPD and SMB printer sharing as needed through external programs...
*/
if (BrowseLocalProtocols & BROWSE_LPD)
update_lpd(0);
if (BrowseLocalProtocols & BROWSE_SMB)
update_smb(0);
}
#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
/*
* 'cupsdUpdateDNSSDName()' - Update the computer name we use for browsing...
*/
void
cupsdUpdateDNSSDName(void)
{
dnssdUpdateDNSSDName(0);
}
# ifdef __APPLE__
/*
* 'dnssdAddAlias()' - Add a DNS-SD alias name.
*/
static void
dnssdAddAlias(const void *key, /* I - Key */
const void *value, /* I - Value (domain) */
void *context) /* I - Unused */
{
char valueStr[1024], /* Domain string */
hostname[1024], /* Complete hostname */
*hostptr; /* Pointer into hostname */
(void)key;
(void)context;
if (CFGetTypeID((CFStringRef)value) == CFStringGetTypeID() &&
CFStringGetCString((CFStringRef)value, valueStr, sizeof(valueStr),
kCFStringEncodingUTF8))
{
snprintf(hostname, sizeof(hostname), "%s.%s", DNSSDHostName, valueStr);
hostptr = hostname + strlen(hostname) - 1;
if (*hostptr == '.')
*hostptr = '\0'; /* Strip trailing dot */
if (!DNSSDAlias)
DNSSDAlias = cupsArrayNew(NULL, NULL);
cupsdAddAlias(DNSSDAlias, hostname);
cupsdLogMessage(CUPSD_LOG_DEBUG, "Added Back to My Mac ServerAlias %s",
hostname);
}
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Bad Back to My Mac domain in dynamic store!");
}
# endif /* __APPLE__ */
/*
* 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
*/
static cupsd_txt_t /* O - TXT record */
dnssdBuildTxtRecord(
cupsd_printer_t *p, /* I - Printer information */
int for_lpd) /* I - 1 = LPD, 0 = IPP */
{
int i, /* Looping var */
count; /* Count of key/value pairs */
char admin_hostname[256], /* Hostname for admin page */
adminurl_str[256], /* URL for the admin page */
type_str[32], /* Type to string buffer */
state_str[32], /* State to string buffer */
rp_str[1024], /* Queue name string buffer */
air_str[1024], /* auth-info-required string buffer */
*keyvalue[32][2], /* Table of key/value pairs */
*ptr; /* Pointer in string */
cupsd_txt_t txt; /* TXT record */
cupsd_listener_t *lis; /* Current listener */
const char *admin_scheme = "http"; /* Admin page URL scheme */
/*
* Load up the key value pairs...
*/
count = 0;
if (!for_lpd || (BrowseLocalProtocols & BROWSE_LPD))
{
keyvalue[count ][0] = "txtvers";
keyvalue[count++][1] = "1";
keyvalue[count ][0] = "qtotal";
keyvalue[count++][1] = "1";
keyvalue[count ][0] = "rp";
keyvalue[count++][1] = rp_str;
if (for_lpd)
strlcpy(rp_str, p->name, sizeof(rp_str));
else
snprintf(rp_str, sizeof(rp_str), "%s/%s",
(p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers",
p->name);
keyvalue[count ][0] = "ty";
keyvalue[count++][1] = p->make_model ? p->make_model : "Unknown";
/*
* Get the hostname for the admin page...
*/
if (strchr(DNSSDHostName, '.'))
{
/*
* Use the provided hostname, but make sure it ends with a period...
*/
if ((ptr = DNSSDHostName + strlen(DNSSDHostName) - 1) >= DNSSDHostName && *ptr == '.')
strlcpy(admin_hostname, DNSSDHostName, sizeof(admin_hostname));
else
snprintf(admin_hostname, sizeof(admin_hostname), "%s.", DNSSDHostName);
}
else
{
/*
* Unqualified hostname gets ".local." added to it...
*/
snprintf(admin_hostname, sizeof(admin_hostname), "%s.local.", DNSSDHostName);
}
/*
* Get the URL scheme for the admin page...
*/
# ifdef HAVE_SSL
for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); lis; lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
{
if (lis->encryption != HTTP_ENCRYPTION_NEVER)
{
admin_scheme = "https";
break;
}
}
# endif /* HAVE_SSL */
httpAssembleURIf(HTTP_URI_CODING_ALL, adminurl_str, sizeof(adminurl_str), admin_scheme, NULL, admin_hostname, DNSSDPort, "/%s/%s", (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name);
keyvalue[count ][0] = "adminurl";
keyvalue[count++][1] = adminurl_str;
if (p->location)
{
keyvalue[count ][0] = "note";
keyvalue[count++][1] = p->location;
}
keyvalue[count ][0] = "priority";
keyvalue[count++][1] = for_lpd ? "100" : "0";
keyvalue[count ][0] = "product";
keyvalue[count++][1] = p->pc && p->pc->product ? p->pc->product : "Unknown";
keyvalue[count ][0] = "pdl";
keyvalue[count++][1] = p->pdl ? p->pdl : "application/postscript";
if (get_auth_info_required(p, air_str, sizeof(air_str)))
{
keyvalue[count ][0] = "air";
keyvalue[count++][1] = air_str;
}
keyvalue[count ][0] = "UUID";
keyvalue[count++][1] = p->uuid + 9;
#ifdef HAVE_SSL
keyvalue[count ][0] = "TLS";
keyvalue[count++][1] = "1.2";
#endif /* HAVE_SSL */
if (p->type & CUPS_PRINTER_FAX)
{
keyvalue[count ][0] = "Fax";
keyvalue[count++][1] = "T";
keyvalue[count ][0] = "rfo";
keyvalue[count++][1] = rp_str;
}
if (p->type & CUPS_PRINTER_COLOR)
{
keyvalue[count ][0] = "Color";
keyvalue[count++][1] = (p->type & CUPS_PRINTER_COLOR) ? "T" : "F";
}
if (p->type & CUPS_PRINTER_DUPLEX)
{
keyvalue[count ][0] = "Duplex";
keyvalue[count++][1] = (p->type & CUPS_PRINTER_DUPLEX) ? "T" : "F";
}
if (p->type & CUPS_PRINTER_STAPLE)
{
keyvalue[count ][0] = "Staple";
keyvalue[count++][1] = (p->type & CUPS_PRINTER_STAPLE) ? "T" : "F";
}
if (p->type & CUPS_PRINTER_COPIES)
{
keyvalue[count ][0] = "Copies";
keyvalue[count++][1] = (p->type & CUPS_PRINTER_COPIES) ? "T" : "F";
}
if (p->type & CUPS_PRINTER_COLLATE)
{
keyvalue[count ][0] = "Collate";
keyvalue[count++][1] = (p->type & CUPS_PRINTER_COLLATE) ? "T" : "F";
}
if (p->type & CUPS_PRINTER_PUNCH)
{
keyvalue[count ][0] = "Punch";
keyvalue[count++][1] = (p->type & CUPS_PRINTER_PUNCH) ? "T" : "F";
}
if (p->type & CUPS_PRINTER_BIND)
{
keyvalue[count ][0] = "Bind";
keyvalue[count++][1] = (p->type & CUPS_PRINTER_BIND) ? "T" : "F";
}
if (p->type & CUPS_PRINTER_SORT)
{
keyvalue[count ][0] = "Sort";
keyvalue[count++][1] = (p->type & CUPS_PRINTER_SORT) ? "T" : "F";
}
if (p->type & CUPS_PRINTER_MFP)
{
keyvalue[count ][0] = "Scan";
keyvalue[count++][1] = (p->type & CUPS_PRINTER_MFP) ? "T" : "F";
}
snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE);
snprintf(state_str, sizeof(state_str), "%d", p->state);
keyvalue[count ][0] = "printer-state";
keyvalue[count++][1] = state_str;
keyvalue[count ][0] = "printer-type";
keyvalue[count++][1] = type_str;
}
/*
* Then pack them into a proper txt record...
*/
# ifdef HAVE_DNSSD
TXTRecordCreate(&txt, 0, NULL);
for (i = 0; i < count; i ++)
{
size_t len = strlen(keyvalue[i][1]);
if (len < 256)
TXTRecordSetValue(&txt, keyvalue[i][0], (uint8_t)len, keyvalue[i][1]);
}
# else
for (i = 0, txt = NULL; i < count; i ++)
txt = avahi_string_list_add_printf(txt, "%s=%s", keyvalue[i][0],
keyvalue[i][1]);
# endif /* HAVE_DNSSD */
return (txt);
}
# ifdef HAVE_AVAHI
/*
* 'dnssdClientCallback()' - Client callback for Avahi.
*
* Called whenever the client or server state changes...
*/
static void
dnssdClientCallback(
AvahiClient *c, /* I - Client */
AvahiClientState state, /* I - Current state */
void *userdata) /* I - User data (unused) */
{
int error; /* Error code, if any */
(void)userdata;
if (!c)
return;
/*
* Make sure DNSSDClient is already set also if this callback function is
* already running before avahi_client_new() in dnssdStartBrowsing()
* finishes.
*/
if (!DNSSDClient)
DNSSDClient = c;
switch (state)
{
case AVAHI_CLIENT_S_REGISTERING:
case AVAHI_CLIENT_S_RUNNING:
case AVAHI_CLIENT_S_COLLISION:
cupsdLogMessage(CUPSD_LOG_DEBUG, "Avahi server connection now available, registering printers for Bonjour broadcasting.");
/*
* Mark that Avahi server is running...
*/
avahi_running = 1;
/*
* Set the computer name and register the web interface...
*/
DNSSDPort = 0;
dnssdUpdateDNSSDName(1);
/*
* Register the individual printers
*/
dnssdRegisterAllPrinters(1);
break;
case AVAHI_CLIENT_FAILURE:
if (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED)
{
cupsdLogMessage(CUPSD_LOG_DEBUG, "Avahi server disappeared, unregistering printers for Bonjour broadcasting.");
/*
* Unregister everything and close the client...
*/
dnssdDeregisterAllPrinters(1);
dnssdDeregisterInstance(&WebIFSrv, 1);
avahi_client_free(DNSSDClient);
DNSSDClient = NULL;
/*
* Mark that Avahi server is not running...
*/
avahi_running = 0;
/*
* Renew Avahi client...
*/
DNSSDClient = avahi_client_new(avahi_threaded_poll_get(DNSSDMaster), AVAHI_CLIENT_NO_FAIL, dnssdClientCallback, NULL, &error);
if (!DNSSDClient)
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to communicate with avahi-daemon: %s", dnssdErrorString(error));
if (FatalErrors & CUPSD_FATAL_BROWSE)
cupsdEndProcess(getpid(), 0);
}
}
else
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Communication with avahi-daemon has failed: %s", avahi_strerror(avahi_client_errno(c)));
if (FatalErrors & CUPSD_FATAL_BROWSE)
cupsdEndProcess(getpid(), 0);
}
break;
default:
break;
}
}
# endif /* HAVE_AVAHI */
/*
* 'dnssdDeregisterAllPrinters()' - Deregister all printers.
*/
static void
dnssdDeregisterAllPrinters(
int from_callback) /* I - Deregistering because of callback? */
{
cupsd_printer_t *p; /* Current printer */
if (!DNSSDMaster)
return;
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
p;
p = (cupsd_printer_t *)cupsArrayNext(Printers))
if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_SCANNER)))
dnssdDeregisterPrinter(p, 1, from_callback);
}
/*
* 'dnssdDeregisterInstance()' - Deregister a DNS-SD service instance.
*/
static void
dnssdDeregisterInstance(
cupsd_srv_t *srv, /* I - Service */
int from_callback) /* I - Called from callback? */
{
if (!srv || !*srv)
return;
# ifdef HAVE_DNSSD
(void)from_callback;
DNSServiceRefDeallocate(*srv);
*srv = NULL;
# else /* HAVE_AVAHI */
if (!from_callback)
avahi_threaded_poll_lock(DNSSDMaster);
if (*srv)
{
avahi_entry_group_free(*srv);
*srv = NULL;
}
if (!from_callback)
avahi_threaded_poll_unlock(DNSSDMaster);
# endif /* HAVE_DNSSD */
}
/*
* 'dnssdDeregisterPrinter()' - Deregister all services for a printer.
*/
static void
dnssdDeregisterPrinter(
cupsd_printer_t *p, /* I - Printer */
int clear_name, /* I - Clear the name? */
int from_callback) /* I - Called from callback? */
{
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"dnssdDeregisterPrinter(p=%p(%s), clear_name=%d)", p, p->name,
clear_name);
if (p->ipp_srv)
{
dnssdDeregisterInstance(&p->ipp_srv, from_callback);
# ifdef HAVE_DNSSD
# ifdef HAVE_SSL
dnssdDeregisterInstance(&p->ipps_srv, from_callback);
# endif /* HAVE_SSL */
dnssdDeregisterInstance(&p->printer_srv, from_callback);
# endif /* HAVE_DNSSD */
}
/*
* Remove the printer from the array of DNS-SD printers but keep the
* registered name...
*/
cupsArrayRemove(DNSSDPrinters, p);
/*
* Optionally clear the service name...
*/
if (clear_name)
cupsdClearString(&p->reg_name);
}
/*
* 'dnssdErrorString()' - Return an error string for an error code.
*/
static const char * /* O - Error message */
dnssdErrorString(int error) /* I - Error number */
{
# ifdef HAVE_DNSSD
switch (error)
{
case kDNSServiceErr_NoError :
return ("OK.");
default :
case kDNSServiceErr_Unknown :
return ("Unknown error.");
case kDNSServiceErr_NoSuchName :
return ("Service not found.");
case kDNSServiceErr_NoMemory :
return ("Out of memory.");
case kDNSServiceErr_BadParam :
return ("Bad parameter.");
case kDNSServiceErr_BadReference :
return ("Bad service reference.");
case kDNSServiceErr_BadState :
return ("Bad state.");
case kDNSServiceErr_BadFlags :
return ("Bad flags.");
case kDNSServiceErr_Unsupported :
return ("Unsupported.");
case kDNSServiceErr_NotInitialized :
return ("Not initialized.");
case kDNSServiceErr_AlreadyRegistered :
return ("Already registered.");
case kDNSServiceErr_NameConflict :
return ("Name conflict.");
case kDNSServiceErr_Invalid :
return ("Invalid name.");
case kDNSServiceErr_Firewall :
return ("Firewall prevents registration.");
case kDNSServiceErr_Incompatible :
return ("Client library incompatible.");
case kDNSServiceErr_BadInterfaceIndex :
return ("Bad interface index.");
case kDNSServiceErr_Refused :
return ("Server prevents registration.");
case kDNSServiceErr_NoSuchRecord :
return ("Record not found.");
case kDNSServiceErr_NoAuth :
return ("Authentication required.");
case kDNSServiceErr_NoSuchKey :
return ("Encryption key not found.");
case kDNSServiceErr_NATTraversal :
return ("Unable to traverse NAT boundary.");
case kDNSServiceErr_DoubleNAT :
return ("Unable to traverse double-NAT boundary.");
case kDNSServiceErr_BadTime :
return ("Bad system time.");
case kDNSServiceErr_BadSig :
return ("Bad signature.");
case kDNSServiceErr_BadKey :
return ("Bad encryption key.");
case kDNSServiceErr_Transient :
return ("Transient error occurred - please try again.");
case kDNSServiceErr_ServiceNotRunning :
return ("Server not running.");
case kDNSServiceErr_NATPortMappingUnsupported :
return ("NAT doesn't support NAT-PMP or UPnP.");
case kDNSServiceErr_NATPortMappingDisabled :
return ("NAT supports NAT-PNP or UPnP but it is disabled.");
case kDNSServiceErr_NoRouter :
return ("No Internet/default router configured.");
case kDNSServiceErr_PollingMode :
return ("Service polling mode error.");
case kDNSServiceErr_Timeout :
return ("Service timeout.");
}
# else /* HAVE_AVAHI */
return (avahi_strerror(error));
# endif /* HAVE_DNSSD */
}
/*
* 'dnssdRegisterCallback()' - Free a TXT record.
*/
static void
dnssdFreeTxtRecord(cupsd_txt_t *txt) /* I - TXT record */
{
# ifdef HAVE_DNSSD
TXTRecordDeallocate(txt);
# else /* HAVE_AVAHI */
avahi_string_list_free(*txt);
*txt = NULL;
# endif /* HAVE_DNSSD */
}
/*
* 'dnssdRegisterAllPrinters()' - Register all printers.
*/
static void
dnssdRegisterAllPrinters(int from_callback) /* I - Called from callback? */
{
cupsd_printer_t *p; /* Current printer */
if (!DNSSDMaster)
return;
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
p;
p = (cupsd_printer_t *)cupsArrayNext(Printers))
if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_SCANNER)))
dnssdRegisterPrinter(p, from_callback);
}
/*
* 'dnssdRegisterCallback()' - DNSServiceRegister callback.
*/
# ifdef HAVE_DNSSD
static void
dnssdRegisterCallback(
DNSServiceRef sdRef, /* I - DNS Service reference */
DNSServiceFlags flags, /* I - Reserved for future use */
DNSServiceErrorType errorCode, /* I - Error code */
const char *name, /* I - Service name */
const char *regtype, /* I - Service type */
const char *domain, /* I - Domain. ".local" for now */
void *context) /* I - Printer */
{
cupsd_printer_t *p = (cupsd_printer_t *)context;
/* Current printer */
(void)sdRef;
(void)flags;
(void)domain;
cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterCallback(%s, %s) for %s (%s)",
name, regtype, p ? p->name : "Web Interface",
p ? (p->reg_name ? p->reg_name : "(null)") : "NA");
if (errorCode)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"DNSServiceRegister failed with error %d", (int)errorCode);
return;
}
else if (p && (!p->reg_name || _cups_strcasecmp(name, p->reg_name)))
{
cupsdLogMessage(CUPSD_LOG_INFO, "Using service name \"%s\" for \"%s\"",
name, p->name);
cupsArrayRemove(DNSSDPrinters, p);
cupsdSetString(&p->reg_name, name);
cupsArrayAdd(DNSSDPrinters, p);
LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED;
}
}
# else /* HAVE_AVAHI */
static void
dnssdRegisterCallback(
AvahiEntryGroup *srv, /* I - Service */
AvahiEntryGroupState state, /* I - Registration state */
void *context) /* I - Printer */
{
cupsd_printer_t *p = (cupsd_printer_t *)context;
/* Current printer */
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"dnssdRegisterCallback(srv=%p, state=%d, context=%p) "
"for %s (%s)", srv, state, context,
p ? p->name : "Web Interface",
p ? (p->reg_name ? p->reg_name : "(null)") : "NA");
/* TODO: Handle collisions with avahi_alternate_service_name(p->reg_name)? */
}
# endif /* HAVE_DNSSD */
/*
* 'dnssdRegisterInstance()' - Register an instance of a printer service.
*/
static int /* O - 1 on success, 0 on failure */
dnssdRegisterInstance(
cupsd_srv_t *srv, /* O - Service */
cupsd_printer_t *p, /* I - Printer */
char *name, /* I - DNS-SD service name */
const char *type, /* I - DNS-SD service type */
const char *subtypes, /* I - Subtypes to register or NULL */
int port, /* I - Port number or 0 */
cupsd_txt_t *txt, /* I - TXT record */
int commit, /* I - Commit registration? */
int from_callback) /* I - Called from callback? */
{
char temp[256], /* Temporary string */
*ptr; /* Pointer into string */
int error; /* Any error */
# ifdef HAVE_DNSSD
(void)from_callback;
# endif /* HAVE_DNSSD */
cupsdLogMessage(CUPSD_LOG_DEBUG, "Registering \"%s\" with DNS-SD type \"%s\".", name, type);
if (p && !srv)
{
/*
* Assign the correct pointer for "srv"...
*/
# ifdef HAVE_DNSSD
if (!strcmp(type, "_printer._tcp"))
srv = &p->printer_srv; /* Target LPD service */
# ifdef HAVE_SSL
else if (!strcmp(type, "_ipps._tcp"))
srv = &p->ipps_srv; /* Target IPPS service */
# endif /* HAVE_SSL */
else
srv = &p->ipp_srv; /* Target IPP service */
# else /* HAVE_AVAHI */
srv = &p->ipp_srv; /* Target service group */
# endif /* HAVE_DNSSD */
}
# ifdef HAVE_DNSSD
(void)commit;
# else /* HAVE_AVAHI */
if (!from_callback)
avahi_threaded_poll_lock(DNSSDMaster);
if (!*srv)
*srv = avahi_entry_group_new(DNSSDClient, dnssdRegisterCallback, NULL);
if (!*srv)
{
if (!from_callback)
avahi_threaded_poll_unlock(DNSSDMaster);
cupsdLogMessage(CUPSD_LOG_WARN, "DNS-SD registration of \"%s\" failed: %s",
name, dnssdErrorString(avahi_client_errno(DNSSDClient)));
return (0);
}
# endif /* HAVE_DNSSD */
/*
* Make sure the name is <= 63 octets, and when we truncate be sure to
* properly truncate any UTF-8 characters...
*/
ptr = name + strlen(name);
while ((ptr - name) > 63)
{
do
{
ptr --;
}
while (ptr > name && (*ptr & 0xc0) == 0x80);
if (ptr > name)
*ptr = '\0';
}
/*
* Register the service...
*/
# ifdef HAVE_DNSSD
if (subtypes)
snprintf(temp, sizeof(temp), "%s,%s", type, subtypes);
else
strlcpy(temp, type, sizeof(temp));
*srv = DNSSDMaster;
error = DNSServiceRegister(srv, kDNSServiceFlagsShareConnection,
0, name, temp, NULL, DNSSDHostName, htons(port),
txt ? TXTRecordGetLength(txt) : 0,
txt ? TXTRecordGetBytesPtr(txt) : NULL,
dnssdRegisterCallback, p);
# else /* HAVE_AVAHI */
if (txt)
{
AvahiStringList *temptxt;
for (temptxt = *txt; temptxt; temptxt = temptxt->next)
cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS_SD \"%s\" %s", name, temptxt->text);
}
error = avahi_entry_group_add_service_strlst(*srv, AVAHI_IF_UNSPEC,
AVAHI_PROTO_UNSPEC, 0, name,
type, NULL, DNSSDHostName, port,
txt ? *txt : NULL);
if (error)
cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS-SD service add for \"%s\" failed.",
name);
if (!error && subtypes)
{
/*
* Register all of the subtypes...
*/
char *start, /* Start of subtype */
subtype[256]; /* Subtype string */
strlcpy(temp, subtypes, sizeof(temp));
for (start = temp; *start; start = ptr)
{
/*
* Skip leading whitespace...
*/
while (*start && isspace(*start & 255))
start ++;
/*
* Grab everything up to the next comma or the end of the string...
*/
for (ptr = start; *ptr && *ptr != ','; ptr ++);
if (*ptr)
*ptr++ = '\0';
if (!*start)
break;
/*
* Register the subtype...
*/
snprintf(subtype, sizeof(subtype), "%s._sub.%s", start, type);
error = avahi_entry_group_add_service_subtype(*srv, AVAHI_IF_UNSPEC,
AVAHI_PROTO_UNSPEC, 0,
name, type, NULL, subtype);
if (error)
{
cupsdLogMessage(CUPSD_LOG_DEBUG,
"DNS-SD subtype %s registration for \"%s\" failed." ,
subtype, name);
break;
}
}
}
if (!error && commit)
{
if ((error = avahi_entry_group_commit(*srv)) != 0)
cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS-SD commit of \"%s\" failed.",
name);
}
if (!from_callback)
avahi_threaded_poll_unlock(DNSSDMaster);
# endif /* HAVE_DNSSD */
if (error)
{
cupsdLogMessage(CUPSD_LOG_WARN, "DNS-SD registration of \"%s\" failed: %s",
name, dnssdErrorString(error));
cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS-SD type: %s", type);
if (subtypes)
cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS-SD sub-types: %s", subtypes);
}
return (!error);
}
/*
* 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
* or update the broadcast contents.
*/
static void
dnssdRegisterPrinter(
cupsd_printer_t *p, /* I - Printer */
int from_callback) /* I - Called from callback? */
{
char name[256]; /* Service name */
int printer_port; /* LPD port number */
int status; /* Registration status */
cupsd_txt_t ipp_txt, /* IPP(S) TXT record */
printer_txt; /* LPD TXT record */
cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
!p->ipp_srv ? "new" : "update");
# ifdef HAVE_AVAHI
if (!avahi_running)
return;
# endif /* HAVE_AVAHI */
/*
* Remove the current registrations if we have them and then return if
* per-printer sharing was just disabled...
*/
dnssdDeregisterPrinter(p, 0, from_callback);
if (!p->shared)
return;
/*
* Set the registered name as needed; the registered name takes the form of
* "<printer-info> @ <computer name>"...
*/
if (!p->reg_name)
{
if (p->info && strlen(p->info) > 0)
{
if (DNSSDComputerName)
snprintf(name, sizeof(name), "%s @ %s", p->info, DNSSDComputerName);
else
strlcpy(name, p->info, sizeof(name));
}
else if (DNSSDComputerName)
snprintf(name, sizeof(name), "%s @ %s", p->name, DNSSDComputerName);
else
strlcpy(name, p->name, sizeof(name));
}
else
strlcpy(name, p->reg_name, sizeof(name));
/*
* Register IPP and LPD...
*
* We always must register the "_printer" service type in order to reserve
* our name, but use port number 0 if we haven't actually configured cups-lpd
* to share via LPD...
*/
ipp_txt = dnssdBuildTxtRecord(p, 0);
printer_txt = dnssdBuildTxtRecord(p, 1);
if (BrowseLocalProtocols & BROWSE_LPD)
printer_port = 515;
else
printer_port = 0;
status = dnssdRegisterInstance(NULL, p, name, "_printer._tcp", NULL, printer_port, &printer_txt, 0, from_callback);
# ifdef HAVE_SSL
if (status)
dnssdRegisterInstance(NULL, p, name, "_ipps._tcp", DNSSDSubTypes, DNSSDPort, &ipp_txt, 0, from_callback);
# endif /* HAVE_SSL */
if (status)
{
/*
* Use the "_fax-ipp" service type for fax queues, otherwise use "_ipp"...
*/
if (p->type & CUPS_PRINTER_FAX)
status = dnssdRegisterInstance(NULL, p, name, "_fax-ipp._tcp", DNSSDSubTypes, DNSSDPort, &ipp_txt, 1, from_callback);
else
status = dnssdRegisterInstance(NULL, p, name, "_ipp._tcp", DNSSDSubTypes, DNSSDPort, &ipp_txt, 1, from_callback);
}
dnssdFreeTxtRecord(&ipp_txt);
dnssdFreeTxtRecord(&printer_txt);
if (status)
{
/*
* Save the registered name and add the printer to the array of DNS-SD
* printers...
*/
cupsdSetString(&p->reg_name, name);
cupsArrayAdd(DNSSDPrinters, p);
}
else
{
/*
* Registration failed for this printer...
*/
dnssdDeregisterInstance(&p->ipp_srv, from_callback);
# ifdef HAVE_DNSSD
# ifdef HAVE_SSL
dnssdDeregisterInstance(&p->ipps_srv, from_callback);
# endif /* HAVE_SSL */
dnssdDeregisterInstance(&p->printer_srv, from_callback);
# endif /* HAVE_DNSSD */
}
}
/*
* 'dnssdStop()' - Stop all DNS-SD registrations.
*/
static void
dnssdStop(void)
{
cupsd_printer_t *p; /* Current printer */
/*
* De-register the individual printers
*/
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
p;
p = (cupsd_printer_t *)cupsArrayNext(Printers))
dnssdDeregisterPrinter(p, 1, 0);
/*
* Shutdown the rest of the service refs...
*/
dnssdDeregisterInstance(&WebIFSrv, 0);
# ifdef HAVE_DNSSD
cupsdRemoveSelect(DNSServiceRefSockFD(DNSSDMaster));
DNSServiceRefDeallocate(DNSSDMaster);
DNSSDMaster = NULL;
# else /* HAVE_AVAHI */
if (DNSSDMaster)
avahi_threaded_poll_stop(DNSSDMaster);
if (DNSSDClient)
{
avahi_client_free(DNSSDClient);
DNSSDClient = NULL;
}
if (DNSSDMaster)
{
avahi_threaded_poll_free(DNSSDMaster);
DNSSDMaster = NULL;
}
# endif /* HAVE_DNSSD */
cupsArrayDelete(DNSSDPrinters);
DNSSDPrinters = NULL;
DNSSDPort = 0;
}
# ifdef HAVE_DNSSD
/*
* 'dnssdUpdate()' - Handle DNS-SD queries.
*/
static void
dnssdUpdate(void)
{
DNSServiceErrorType sdErr; /* Service discovery error */
if ((sdErr = DNSServiceProcessResult(DNSSDMaster)) != kDNSServiceErr_NoError)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"DNS Service Discovery registration error %d!",
sdErr);
dnssdStop();
}
}
# endif /* HAVE_DNSSD */
/*
* 'dnssdUpdateDNSSDName()' - Update the listen port, computer name, and web interface registration.
*/
static void
dnssdUpdateDNSSDName(int from_callback) /* I - Called from callback? */
{
char webif[1024]; /* Web interface share name */
# ifdef __APPLE__
SCDynamicStoreRef sc; /* Context for dynamic store */
CFDictionaryRef btmm; /* Back-to-My-Mac domains */
CFStringEncoding nameEncoding; /* Encoding of computer name */
CFStringRef nameRef; /* Host name CFString */
char nameBuffer[1024]; /* C-string buffer */
# endif /* __APPLE__ */
/*
* Only share the web interface and printers when non-local listening is
* enabled...
*/
if (!DNSSDPort)
{
/*
* Get the port we use for registrations. If we are not listening on any
* non-local ports, there is no sense sharing local printers via Bonjour...
*/
cupsd_listener_t *lis; /* Current listening socket */
for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
lis;
lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
{
if (httpAddrLocalhost(&(lis->address)))
continue;
DNSSDPort = httpAddrPort(&(lis->address));
break;
}
}
if (!DNSSDPort)
return;
/*
* Get the computer name as a c-string...
*/
# ifdef __APPLE__
sc = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("cupsd"), NULL, NULL);
if (sc)
{
/*
* Get the computer name from the dynamic store...
*/
cupsdClearString(&DNSSDComputerName);
if ((nameRef = SCDynamicStoreCopyComputerName(sc, &nameEncoding)) != NULL)
{
if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
kCFStringEncodingUTF8))
{
cupsdLogMessage(CUPSD_LOG_DEBUG,
"Dynamic store computer name is \"%s\".", nameBuffer);
cupsdSetString(&DNSSDComputerName, nameBuffer);
}
CFRelease(nameRef);
}
if (!DNSSDComputerName)
{
/*
* Use the ServerName instead...
*/
cupsdLogMessage(CUPSD_LOG_DEBUG,
"Using ServerName \"%s\" as computer name.", ServerName);
cupsdSetString(&DNSSDComputerName, ServerName);
}
if (!DNSSDHostName)
{
/*
* Get the local hostname from the dynamic store...
*/
if ((nameRef = SCDynamicStoreCopyLocalHostName(sc)) != NULL)
{
if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
kCFStringEncodingUTF8))
{
cupsdLogMessage(CUPSD_LOG_DEBUG, "Dynamic store host name is \"%s\".", nameBuffer);
if (strchr(nameBuffer, '.'))
cupsdSetString(&DNSSDHostName, nameBuffer);
else
cupsdSetStringf(&DNSSDHostName, "%s.local", nameBuffer);
cupsdLogMessage(CUPSD_LOG_INFO, "Defaulting to \"DNSSDHostName %s\".", DNSSDHostName);
}
CFRelease(nameRef);
}
}
if (!DNSSDHostName)
{
/*
* Use the ServerName instead...
*/
cupsdLogMessage(CUPSD_LOG_DEBUG, "Using ServerName \"%s\" as host name.", ServerName);
cupsdSetString(&DNSSDHostName, ServerName);
cupsdLogMessage(CUPSD_LOG_INFO, "Defaulting to \"DNSSDHostName %s\".", DNSSDHostName);
}
/*
* Get any Back-to-My-Mac domains and add them as aliases...
*/
cupsdFreeAliases(DNSSDAlias);
DNSSDAlias = NULL;
btmm = SCDynamicStoreCopyValue(sc, CFSTR("Setup:/Network/BackToMyMac"));
if (btmm && CFGetTypeID(btmm) == CFDictionaryGetTypeID())
{
cupsdLogMessage(CUPSD_LOG_DEBUG, "%d Back to My Mac aliases to add.",
(int)CFDictionaryGetCount(btmm));
CFDictionaryApplyFunction(btmm, dnssdAddAlias, NULL);
}
else if (btmm)
cupsdLogMessage(CUPSD_LOG_ERROR,
"Bad Back to My Mac data in dynamic store!");
else
cupsdLogMessage(CUPSD_LOG_DEBUG, "No Back to My Mac aliases to add.");
if (btmm)
CFRelease(btmm);
CFRelease(sc);
}
else
# endif /* __APPLE__ */
# ifdef HAVE_AVAHI
if (DNSSDClient)
{
const char *host_name = avahi_client_get_host_name(DNSSDClient);
cupsdSetString(&DNSSDComputerName, host_name ? host_name : ServerName);
if (!DNSSDHostName)
{
const char *host_fqdn = avahi_client_get_host_name_fqdn(DNSSDClient);
if (host_fqdn)
cupsdSetString(&DNSSDHostName, host_fqdn);
else if (strchr(ServerName, '.'))
cupsdSetString(&DNSSDHostName, ServerName);
else
cupsdSetStringf(&DNSSDHostName, "%s.local", ServerName);
cupsdLogMessage(CUPSD_LOG_INFO, "Defaulting to \"DNSSDHostName %s\".", DNSSDHostName);
}
}
else
# endif /* HAVE_AVAHI */
{
cupsdSetString(&DNSSDComputerName, ServerName);
if (!DNSSDHostName)
{
if (strchr(ServerName, '.'))
cupsdSetString(&DNSSDHostName, ServerName);
else
cupsdSetStringf(&DNSSDHostName, "%s.local", ServerName);
cupsdLogMessage(CUPSD_LOG_INFO, "Defaulting to \"DNSSDHostName %s\".", DNSSDHostName);
}
}
/*
* Then (re)register the web interface if enabled...
*/
if (BrowseWebIF)
{
if (DNSSDComputerName)
snprintf(webif, sizeof(webif), "CUPS @ %s", DNSSDComputerName);
else
strlcpy(webif, "CUPS", sizeof(webif));
dnssdDeregisterInstance(&WebIFSrv, from_callback);
dnssdRegisterInstance(&WebIFSrv, NULL, webif, "_http._tcp", "_printer", DNSSDPort, NULL, 1, from_callback);
}
}
/*
* 'get_auth_info_required()' - Get the auth-info-required value to advertise.
*/
static char * /* O - String or NULL if none */
get_auth_info_required(
cupsd_printer_t *p, /* I - Printer */
char *buffer, /* I - Value buffer */
size_t bufsize) /* I - Size of value buffer */
{
cupsd_location_t *auth; /* Pointer to authentication element */
char resource[1024]; /* Printer/class resource path */
/*
* If auth-info-required is set for this printer, return that...
*/
if (p->num_auth_info_required > 0 && strcmp(p->auth_info_required[0], "none"))
{
int i; /* Looping var */
char *bufptr; /* Pointer into buffer */
for (i = 0, bufptr = buffer; i < p->num_auth_info_required; i ++)
{
if (bufptr >= (buffer + bufsize - 2))
break;
if (i)
*bufptr++ = ',';
strlcpy(bufptr, p->auth_info_required[i], bufsize - (size_t)(bufptr - buffer));
bufptr += strlen(bufptr);
}
return (buffer);
}
/*
* Figure out the authentication data requirements to advertise...
*/
if (p->type & CUPS_PRINTER_CLASS)
snprintf(resource, sizeof(resource), "/classes/%s", p->name);
else
snprintf(resource, sizeof(resource), "/printers/%s", p->name);
if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL ||
auth->type == CUPSD_AUTH_NONE)
auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
if (auth)
{
int auth_type; /* Authentication type */
if ((auth_type = auth->type) == CUPSD_AUTH_DEFAULT)
auth_type = cupsdDefaultAuthType();
switch (auth_type)
{
case CUPSD_AUTH_NONE :
return (NULL);
case CUPSD_AUTH_NEGOTIATE :
strlcpy(buffer, "negotiate", bufsize);
break;
default :
strlcpy(buffer, "username,password", bufsize);
break;
}
return (buffer);
}
return ("none");
}
#endif /* HAVE_DNSSD || HAVE_AVAHI */
#ifdef __APPLE__
/*
* 'get_hostconfig()' - Get an /etc/hostconfig service setting.
*/
static int /* O - 1 for YES or AUTOMATIC, 0 for NO */
get_hostconfig(const char *name) /* I - Name of service */
{
cups_file_t *fp; /* Hostconfig file */
char line[1024], /* Line from file */
*ptr; /* Pointer to value */
int state = 1; /* State of service */
/*
* Try opening the /etc/hostconfig file; if we can't open it, assume that
* the service is enabled/auto.
*/
if ((fp = cupsFileOpen("/etc/hostconfig", "r")) != NULL)
{
/*
* Read lines from the file until we find the service...
*/
while (cupsFileGets(fp, line, sizeof(line)))
{
if (line[0] == '#' || (ptr = strchr(line, '=')) == NULL)
continue;
*ptr++ = '\0';
if (!_cups_strcasecmp(line, name))
{
/*
* Found the service, see if it is set to "-NO-"...
*/
if (!_cups_strncasecmp(ptr, "-NO-", 4))
state = 0;
break;
}
}
cupsFileClose(fp);
}
return (state);
}
#endif /* __APPLE__ */
/*
* 'update_lpd()' - Update the LPD configuration as needed.
*/
static void
update_lpd(int onoff) /* - 1 = turn on, 0 = turn off */
{
if (!LPDConfigFile)
return;
#ifdef __APPLE__
/*
* Allow /etc/hostconfig CUPS_LPD service setting to override cupsd.conf
* setting for backwards-compatibility.
*/
if (onoff && !get_hostconfig("CUPS_LPD"))
onoff = 0;
#endif /* __APPLE__ */
if (!strncmp(LPDConfigFile, "xinetd:///", 10))
{
/*
* Enable/disable LPD via the xinetd.d config file for cups-lpd...
*/
char newfile[1024]; /* New cups-lpd.N file */
cups_file_t *ofp, /* Original file pointer */
*nfp; /* New file pointer */
char line[1024]; /* Line from file */
snprintf(newfile, sizeof(newfile), "%s.N", LPDConfigFile + 9);
if ((ofp = cupsFileOpen(LPDConfigFile + 9, "r")) == NULL)
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
LPDConfigFile + 9, strerror(errno));
return;
}
if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
newfile, strerror(errno));
cupsFileClose(ofp);
return;
}
/*
* Copy all of the lines from the cups-lpd file...
*/
while (cupsFileGets(ofp, line, sizeof(line)))
{
if (line[0] == '{')
{
cupsFilePrintf(nfp, "%s\n", line);
snprintf(line, sizeof(line), "\tdisable = %s",
onoff ? "no" : "yes");
}
else if (!strstr(line, "disable ="))
cupsFilePrintf(nfp, "%s\n", line);
}
cupsFileClose(nfp);
cupsFileClose(ofp);
rename(newfile, LPDConfigFile + 9);
}
#ifdef __APPLE__
else if (!strncmp(LPDConfigFile, "launchd:///", 11))
{
/*
* Enable/disable LPD via the launchctl command...
*/
char *argv[5], /* Arguments for command */
*envp[MAX_ENV]; /* Environment for command */
int pid; /* Process ID */
cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
argv[0] = (char *)"launchctl";
argv[1] = (char *)(onoff ? "load" : "unload");
argv[2] = (char *)"-w";
argv[3] = LPDConfigFile + 10;
argv[4] = NULL;
cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1,
NULL, NULL, &pid);
}
#endif /* __APPLE__ */
else
cupsdLogMessage(CUPSD_LOG_INFO, "Unknown LPDConfigFile scheme!");
}
/*
* 'update_smb()' - Update the SMB configuration as needed.
*/
static void
update_smb(int onoff) /* I - 1 = turn on, 0 = turn off */
{
if (!SMBConfigFile)
return;
if (!strncmp(SMBConfigFile, "samba:///", 9))
{
/*
* Enable/disable SMB via the specified smb.conf config file...
*/
char newfile[1024]; /* New smb.conf.N file */
cups_file_t *ofp, /* Original file pointer */
*nfp; /* New file pointer */
char line[1024]; /* Line from file */
int in_printers; /* In [printers] section? */
snprintf(newfile, sizeof(newfile), "%s.N", SMBConfigFile + 8);
if ((ofp = cupsFileOpen(SMBConfigFile + 8, "r")) == NULL)
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
SMBConfigFile + 8, strerror(errno));
return;
}
if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
newfile, strerror(errno));
cupsFileClose(ofp);
return;
}
/*
* Copy all of the lines from the smb.conf file...
*/
in_printers = 0;
while (cupsFileGets(ofp, line, sizeof(line)))
{
if (in_printers && strstr(line, "printable ="))
snprintf(line, sizeof(line), " printable = %s",
onoff ? "yes" : "no");
cupsFilePrintf(nfp, "%s\n", line);
if (line[0] == '[')
in_printers = !strcmp(line, "[printers]");
}
cupsFileClose(nfp);
cupsFileClose(ofp);
rename(newfile, SMBConfigFile + 8);
}
else
cupsdLogMessage(CUPSD_LOG_INFO, "Unknown SMBConfigFile scheme!");
}