예제 #1
0
파일: dirsvc.c 프로젝트: AndychenCL/cups
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);
    }

   /*
    * Get the local hostname from the dynamic store...
    */

    cupsdClearString(&DNSSDHostName);

    if ((nameRef = SCDynamicStoreCopyLocalHostName(sc)) != NULL)
    {
      if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
			     kCFStringEncodingUTF8))
      {
        cupsdLogMessage(CUPSD_LOG_DEBUG,
	                "Dynamic store host name is \"%s\".", nameBuffer);
	cupsdSetString(&DNSSDHostName, nameBuffer);
      }

      CFRelease(nameRef);
    }

    if (!DNSSDHostName)
    {
     /*
      * Use the ServerName instead...
      */

      cupsdLogMessage(CUPSD_LOG_DEBUG,
                      "Using ServerName \"%s\" as host name.", ServerName);
      cupsdSetString(&DNSSDHostName, ServerName);
    }

   /*
    * 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);
    const char	*host_fqdn = avahi_client_get_host_name_fqdn(DNSSDClient);

    cupsdSetString(&DNSSDComputerName, host_name ? host_name : ServerName);

    if (host_fqdn)
      cupsdSetString(&DNSSDHostName, host_fqdn);
    else if (strchr(ServerName, '.'))
      cupsdSetString(&DNSSDHostName, ServerName);
    else
      cupsdSetStringf(&DNSSDHostName, "%s.local", ServerName);
  }
  else
#  endif /* HAVE_AVAHI */
  {
    cupsdSetString(&DNSSDComputerName, ServerName);

    if (strchr(ServerName, '.'))
      cupsdSetString(&DNSSDHostName, ServerName);
    else
      cupsdSetStringf(&DNSSDHostName, "%s.local", ServerName);
  }

 /*
  * 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);
  }
}
예제 #2
0
static int				/* O - Zero on success, non-zero on failure */
lpd_queue(const char      *hostname,	/* I - Host to connect to */
          http_addrlist_t *addrlist,	/* I - List of host addresses */
          const char      *printer,	/* I - Printer/queue name */
	  int             print_fd,	/* I - File to print */
	  int             snmp_fd,	/* I - SNMP socket */
	  int             mode,		/* I - Print mode */
          const char      *user,	/* I - Requesting user */
	  const char      *title,	/* I - Job title */
	  int             copies,	/* I - Number of copies */
	  int             banner,	/* I - Print LPD banner? */
          int             format,	/* I - Format specifier */
          int             order,	/* I - Order of data/control files */
	  int             reserve,	/* I - Reserve ports? */
	  int             manual_copies,/* I - Do copies by hand... */
	  int             timeout,	/* I - Timeout... */
	  int             contimeout,	/* I - Connection timeout */
	  const char      *orighost)	/* I - job-originating-host-name */
{
  char			localhost[255];	/* Local host name */
  int			error;		/* Error number */
  struct stat		filestats;	/* File statistics */
  int			lport;		/* LPD connection local port */
  int			fd;		/* LPD socket */
  char			control[10240],	/* LPD control 'file' */
			*cptr;		/* Pointer into control file string */
  char			status;		/* Status byte from command */
  int			delay;		/* Delay for retries... */
  char			addrname[256];	/* Address name */
  http_addrlist_t	*addr;		/* Socket address */
  int			have_supplies;	/* Printer supports supply levels? */
  int			copy;		/* Copies written */
  time_t		start_time;	/* Time of first connect */
  size_t		nbytes;		/* Number of bytes written */
  off_t			tbytes;		/* Total bytes written */
  char			buffer[32768];	/* Output buffer */
#ifdef WIN32
  DWORD			tv;		/* Timeout in milliseconds */
#else
  struct timeval	tv;		/* Timeout in secs and usecs */
#endif /* WIN32 */


 /*
  * Remember when we started trying to connect to the printer...
  */

  start_time = time(NULL);

 /*
  * Loop forever trying to print the file...
  */

  while (!abort_job)
  {
   /*
    * First try to reserve a port for this connection...
    */

    fprintf(stderr, "DEBUG: Connecting to %s:%d for printer %s\n", hostname,
            httpAddrPort(&(addrlist->addr)), printer);
    _cupsLangPrintFilter(stderr, "INFO", _("Connecting to printer."));

    for (lport = reserve == RESERVE_RFC1179 ? 732 : 1024, addr = addrlist,
             delay = 5;;
         addr = addr->next)
    {
     /*
      * Stop if this job has been canceled...
      */

      if (abort_job)
        return (CUPS_BACKEND_FAILED);

     /*
      * Choose the next priviledged port...
      */

      if (!addr)
        addr = addrlist;

      lport --;

      if (lport < 721 && reserve == RESERVE_RFC1179)
	lport = 731;
      else if (lport < 1)
	lport = 1023;

#ifdef HAVE_GETEUID
      if (geteuid() || !reserve)
#else
      if (getuid() || !reserve)
#endif /* HAVE_GETEUID */
      {
       /*
	* Just create a regular socket...
	*/

	if ((fd = socket(addr->addr.addr.sa_family, SOCK_STREAM, 0)) < 0)
	{
	  perror("DEBUG: Unable to create socket");
	  sleep(1);

          continue;
	}

        lport = 0;
      }
      else
      {
       /*
	* We're running as root and want to comply with RFC 1179.  Reserve a
	* priviledged lport between 721 and 731...
	*/

	if ((fd = rresvport_af(&lport, addr->addr.addr.sa_family)) < 0)
	{
	  perror("DEBUG: Unable to reserve port");
	  sleep(1);

	  continue;
	}
      }

     /*
      * Connect to the printer or server...
      */

      if (abort_job)
      {
	close(fd);

	return (CUPS_BACKEND_FAILED);
      }

      if (!connect(fd, &(addr->addr.addr), httpAddrLength(&(addr->addr))))
	break;

      error = errno;
      close(fd);

      if (addr->next)
        continue;

      if (getenv("CLASS") != NULL)
      {
       /*
        * If the CLASS environment variable is set, the job was submitted
	* to a class and not to a specific queue.  In this case, we want
	* to abort immediately so that the job can be requeued on the next
	* available printer in the class.
	*/

        _cupsLangPrintFilter(stderr, "INFO",
			     _("Unable to contact printer, queuing on next "
			       "printer in class."));

       /*
        * Sleep 5 seconds to keep the job from requeuing too rapidly...
	*/

	sleep(5);

        return (CUPS_BACKEND_FAILED);
      }

      fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(error));

      if (error == ECONNREFUSED || error == EHOSTDOWN ||
          error == EHOSTUNREACH)
      {
        if (contimeout && (time(NULL) - start_time) > contimeout)
	{
	  _cupsLangPrintFilter(stderr, "ERROR",
			       _("The printer is not responding."));
	  return (CUPS_BACKEND_FAILED);
	}

	switch (error)
	{
	  case EHOSTDOWN :
	      _cupsLangPrintFilter(stderr, "WARNING",
			           _("The printer may not exist or "
			             "is unavailable at this time."));
	      break;

	  case EHOSTUNREACH :
	      _cupsLangPrintFilter(stderr, "WARNING",
			           _("The printer is unreachable at "
				     "this time."));
	      break;

	  case ECONNREFUSED :
	  default :
	      _cupsLangPrintFilter(stderr, "WARNING",
	                           _("The printer is in use."));
	      break;
        }

	sleep(delay);

	if (delay < 30)
	  delay += 5;
      }
      else if (error == EADDRINUSE)
      {
       /*
	* Try on another port...
	*/

	sleep(1);
      }
      else
      {
	_cupsLangPrintFilter(stderr, "ERROR",
	                     _("The printer is not responding."));
	sleep(30);
      }
    }

   /*
    * Set the timeout...
    */

#ifdef WIN32
    tv = (DWORD)(timeout * 1000);

    setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
    setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv));
#else
    tv.tv_sec  = timeout;
    tv.tv_usec = 0;

    setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
    setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
#endif /* WIN32 */

    fputs("STATE: -connecting-to-device\n", stderr);
    _cupsLangPrintFilter(stderr, "INFO", _("Connected to printer."));

    fprintf(stderr, "DEBUG: Connected to %s:%d (local port %d)...\n",
	    httpAddrString(&(addr->addr), addrname, sizeof(addrname)),
	    httpAddrPort(&(addr->addr)), lport);

   /*
    * See if the printer supports SNMP...
    */

    if (snmp_fd >= 0)
      have_supplies = !backendSNMPSupplies(snmp_fd, &(addrlist->addr), NULL,
                                           NULL);
    else
      have_supplies = 0;

   /*
    * Check for side-channel requests...
    */

    backendCheckSideChannel(snmp_fd, &(addrlist->addr));

   /*
    * Next, open the print file and figure out its size...
    */

    if (print_fd)
    {
     /*
      * Use the size from the print file...
      */

      if (fstat(print_fd, &filestats))
      {
	close(fd);

	perror("DEBUG: unable to stat print file");
	return (CUPS_BACKEND_FAILED);
      }

      filestats.st_size *= manual_copies;
    }
    else
    {
     /*
      * Use a "very large value" for the size so that the printer will
      * keep printing until we close the connection...
      */

#ifdef _LARGEFILE_SOURCE
      filestats.st_size = (size_t)(999999999999.0);
#else
      filestats.st_size = 2147483647;
#endif /* _LARGEFILE_SOURCE */
    }

   /*
    * Send a job header to the printer, specifying no banner page and
    * literal output...
    */

    if (lpd_command(fd, "\002%s\n",
                    printer))		/* Receive print job(s) */
    {
      close(fd);
      return (CUPS_BACKEND_FAILED);
    }

    if (orighost && _cups_strcasecmp(orighost, "localhost"))
      strlcpy(localhost, orighost, sizeof(localhost));
    else
      httpGetHostname(NULL, localhost, sizeof(localhost));

    snprintf(control, sizeof(control),
             "H%.31s\n"		/* RFC 1179, Section 7.2 - host name <= 31 chars */
	     "P%.31s\n"		/* RFC 1179, Section 7.2 - user name <= 31 chars */
	     "J%.99s\n",	/* RFC 1179, Section 7.2 - job name <= 99 chars */
	     localhost, user, title);
    cptr = control + strlen(control);

    if (banner)
    {
      snprintf(cptr, sizeof(control) - (cptr - control),
               "C%.31s\n"	/* RFC 1179, Section 7.2 - class name <= 31 chars */
	       "L%s\n",
               localhost, user);
      cptr   += strlen(cptr);
    }

    while (copies > 0)
    {
      snprintf(cptr, sizeof(control) - (cptr - control), "%cdfA%03d%.15s\n",
               format, (int)getpid() % 1000, localhost);
      cptr   += strlen(cptr);
      copies --;
    }

    snprintf(cptr, sizeof(control) - (cptr - control),
             "UdfA%03d%.15s\n"
	     "N%.131s\n",	/* RFC 1179, Section 7.2 - sourcefile name <= 131 chars */
             (int)getpid() % 1000, localhost, title);

    fprintf(stderr, "DEBUG: Control file is:\n%s", control);

    if (order == ORDER_CONTROL_DATA)
    {
     /*
      * Check for side-channel requests...
      */

      backendCheckSideChannel(snmp_fd, &(addr->addr));

     /*
      * Send the control file...
      */

      if (lpd_command(fd, "\002%d cfA%03.3d%.15s\n", strlen(control),
                      (int)getpid() % 1000, localhost))
      {
	close(fd);

        return (CUPS_BACKEND_FAILED);
      }

      fprintf(stderr, "DEBUG: Sending control file (%u bytes)\n",
	      (unsigned)strlen(control));

      if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
      {
	status = errno;
	perror("DEBUG: Unable to write control file");

      }
      else
      {
        if (read(fd, &status, 1) < 1)
	{
	  _cupsLangPrintFilter(stderr, "WARNING",
	                       _("The printer did not respond."));
	  status = errno;
	}
      }

      if (status != 0)
	_cupsLangPrintFilter(stderr, "ERROR",
			     _("Remote host did not accept control file (%d)."),
			     status);
      else
	_cupsLangPrintFilter(stderr, "INFO",
	                     _("Control file sent successfully."));
    }
    else
      status = 0;

    if (status == 0)
    {
     /*
      * Check for side-channel requests...
      */

      backendCheckSideChannel(snmp_fd, &(addr->addr));

     /*
      * Send the print file...
      */

      if (lpd_command(fd, "\003" CUPS_LLFMT " dfA%03.3d%.15s\n",
                      CUPS_LLCAST filestats.st_size, (int)getpid() % 1000,
		      localhost))
      {
	close(fd);

        return (CUPS_BACKEND_FAILED);
      }

      fprintf(stderr, "DEBUG: Sending data file (" CUPS_LLFMT " bytes)\n",
	      CUPS_LLCAST filestats.st_size);

      tbytes = 0;
      for (copy = 0; copy < manual_copies; copy ++)
      {
	lseek(print_fd, 0, SEEK_SET);

	while ((nbytes = read(print_fd, buffer, sizeof(buffer))) > 0)
	{
	  _cupsLangPrintFilter(stderr, "INFO",
			       _("Spooling job, %.0f%% complete."),
			       100.0 * tbytes / filestats.st_size);

	  if (lpd_write(fd, buffer, nbytes) < nbytes)
	  {
	    perror("DEBUG: Unable to send print file to printer");
            break;
	  }
	  else
            tbytes += nbytes;
	}
      }

      if (mode == MODE_STANDARD)
      {
	if (tbytes < filestats.st_size)
	  status = errno;
	else if (lpd_write(fd, "", 1) < 1)
	{
	  perror("DEBUG: Unable to send trailing nul to printer");
	  status = errno;
	}
	else
	{
	 /*
          * Read the status byte from the printer; if we can't read the byte
	  * back now, we should set status to "errno", however at this point
	  * we know the printer got the whole file and we don't necessarily
	  * want to requeue it over and over...
	  */

          if (recv(fd, &status, 1, 0) < 1)
	  {
	    _cupsLangPrintFilter(stderr, "WARNING",
			         _("The printer did not respond."));
	    status = 0;
          }
	}
      }
      else
        status = 0;

      if (status != 0)
	_cupsLangPrintFilter(stderr, "ERROR",
			     _("Remote host did not accept data file (%d)."),
			     status);
      else
	_cupsLangPrintFilter(stderr, "INFO",
	                     _("Data file sent successfully."));
    }

    if (status == 0 && order == ORDER_DATA_CONTROL)
    {
     /*
      * Check for side-channel requests...
      */

      backendCheckSideChannel(snmp_fd, &(addr->addr));

     /*
      * Send control file...
      */

      if (lpd_command(fd, "\002%d cfA%03.3d%.15s\n", strlen(control),
                      (int)getpid() % 1000, localhost))
      {
	close(fd);

        return (CUPS_BACKEND_FAILED);
      }

      fprintf(stderr, "DEBUG: Sending control file (%lu bytes)\n",
	      (unsigned long)strlen(control));

      if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
      {
	status = errno;
	perror("DEBUG: Unable to write control file");
      }
      else
      {
        if (read(fd, &status, 1) < 1)
	{
	  _cupsLangPrintFilter(stderr, "WARNING",
			       _("The printer did not respond."));
	  status = errno;
	}
      }

      if (status != 0)
	_cupsLangPrintFilter(stderr, "ERROR",
			     _("Remote host did not accept control file (%d)."),
			     status);
      else
	_cupsLangPrintFilter(stderr, "INFO",
	                     _("Control file sent successfully."));
    }

   /*
    * Collect the final supply levels as needed...
    */

    if (have_supplies)
      backendSNMPSupplies(snmp_fd, &(addr->addr), NULL, NULL);

   /*
    * Close the socket connection and input file...
    */

    close(fd);

    if (status == 0)
      return (CUPS_BACKEND_OK);

   /*
    * Waiting for a retry...
    */

    sleep(30);
  }

 /*
  * If we get here, then the job has been canceled...
  */

  return (CUPS_BACKEND_FAILED);
}
예제 #3
0
파일: request.c 프로젝트: jelmer/cups
http_t *				/* O - HTTP connection */
_cupsConnect(void)
{
  _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */


 /*
  * See if we are connected to the same server...
  */

  if (cg->http)
  {
   /*
    * Compare the connection hostname, port, and encryption settings to
    * the cached defaults; these were initialized the first time we
    * connected...
    */

    if (strcmp(cg->http->hostname, cg->server) ||
        cg->ipp_port != httpAddrPort(cg->http->hostaddr) ||
        (cg->http->encryption != cg->encryption &&
	 cg->http->encryption == HTTP_ENCRYPTION_NEVER))
    {
     /*
      * Need to close the current connection because something has changed...
      */

      httpClose(cg->http);
      cg->http = NULL;
    }
    else
    {
     /*
      * Same server, see if the connection is still established...
      */

      char	ch;			/* Connection check byte */
      ssize_t	n;			/* Number of bytes */

#ifdef WIN32
      if ((n = recv(cg->http->fd, &ch, 1, MSG_PEEK)) == 0 ||
          (n < 0 && WSAGetLastError() != WSAEWOULDBLOCK))
#else
      if ((n = recv(cg->http->fd, &ch, 1, MSG_PEEK | MSG_DONTWAIT)) == 0 ||
          (n < 0 && errno != EWOULDBLOCK))
#endif /* WIN32 */
      {
       /*
        * Nope, close the connection...
        */

	httpClose(cg->http);
	cg->http = NULL;
      }
    }
  }

 /*
  * (Re)connect as needed...
  */

  if (!cg->http)
  {
    if ((cg->http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC,
				 cupsEncryption(), 1, 30000, NULL)) == NULL)
    {
      if (errno)
        _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, NULL, 0);
      else
        _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE,
	              _("Unable to connect to host."), 1);
    }
  }

 /*
  * Return the cached connection...
  */

  return (cg->http);
}
예제 #4
0
파일: listen.c 프로젝트: jianglei12138/cups
void
cupsdStartListening(void)
{
  int			p;		/* Port number */
  cupsd_listener_t	*lis;		/* Current listening socket */
  char			s[256];		/* String addresss */
  const char		*have_domain;	/* Have a domain socket? */
  static const char * const encryptions[] =
		{			/* Encryption values */
		  "IfRequested",
		  "Never",
		  "Required",
		  "Always"
		};


  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners",
                  cupsArrayCount(Listeners));

 /*
  * Setup socket listeners...
  */

  for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners), LocalPort = 0,
           have_domain = NULL;
       lis;
       lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
  {
    httpAddrString(&(lis->address), s, sizeof(s));
    p = httpAddrPort(&(lis->address));

   /*
    * If needed, create a socket for listening...
    */

    if (lis->fd == -1)
    {
     /*
      * Create a socket for listening...
      */

      lis->fd = httpAddrListen(&(lis->address), p);

      if (lis->fd == -1)
      {
	cupsdLogMessage(CUPSD_LOG_ERROR,
			"Unable to open listen socket for address %s:%d - %s.",
			s, p, strerror(errno));

#ifdef AF_INET6
       /*
        * IPv6 is often disabled while DNS returns IPv6 addresses...
	*/

	if (lis->address.addr.sa_family != AF_INET6 &&
	    (FatalErrors & CUPSD_FATAL_LISTEN))
	  cupsdEndProcess(getpid(), 0);
#else
	if (FatalErrors & CUPSD_FATAL_LISTEN)
	  cupsdEndProcess(getpid(), 0);
#endif /* AF_INET6 */

	continue;
      }
    }

    if (p)
      cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...",
        	      s, p, lis->fd);
    else
      cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...",
        	      s, lis->fd);

   /*
    * Save the first port that is bound to the local loopback or
    * "any" address...
    */

    if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 &&
        (httpAddrLocalhost(&(lis->address)) ||
         httpAddrAny(&(lis->address))))
    {
      LocalPort       = p;
      LocalEncryption = lis->encryption;
    }

#ifdef AF_LOCAL
    if (lis->address.addr.sa_family == AF_LOCAL && !have_domain)
      have_domain = lis->address.un.sun_path;
#endif /* AF_LOCAL */
  }

 /*
  * Make sure that we are listening on localhost!
  */

  if (!LocalPort && !have_domain)
  {
    cupsdLogMessage(CUPSD_LOG_EMERG,
                    "No Listen or Port lines were found to allow access via "
		    "localhost.");

    if (FatalErrors & (CUPSD_FATAL_CONFIG | CUPSD_FATAL_LISTEN))
      cupsdEndProcess(getpid(), 0);
  }

 /*
  * Set the CUPS_SERVER, IPP_PORT, and CUPS_ENCRYPTION variables based on
  * the listeners...
  */

  if (have_domain)
  {
   /*
    * Use domain sockets for the local connection...
    */

    cupsdSetEnv("CUPS_SERVER", have_domain);

    LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED;
  }
  else
  {
   /*
    * Use the default local loopback address for the server...
    */

    cupsdSetEnv("CUPS_SERVER", "localhost");
  }

  cupsdSetEnv("CUPS_ENCRYPTION", encryptions[LocalEncryption]);

  if (LocalPort)
    cupsdSetEnvf("IPP_PORT", "%d", LocalPort);

 /*
  * Resume listening for connections...
  */

  cupsdResumeListening();
}
예제 #5
0
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);
}
예제 #6
0
void
cupsdStartListening(void)
{
  int			status;		/* Bind result */
  int			p,		/* Port number */
			val;		/* Parameter value */
  cupsd_listener_t	*lis;		/* Current listening socket */
  char			s[256];		/* String addresss */
  const char		*have_domain;	/* Have a domain socket? */
  static const char * const encryptions[] =
		{			/* Encryption values */
		  "IfRequested",
		  "Never",
		  "Required",
		  "Always"
		};


  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners",
                  cupsArrayCount(Listeners));

 /*
  * Setup socket listeners...
  */

  for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners), LocalPort = 0,
           have_domain = NULL;
       lis;
       lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
  {
    httpAddrString(&(lis->address), s, sizeof(s));
    p = httpAddrPort(&(lis->address));

   /*
    * If needed, create a socket for listening...
    */

    if (lis->fd == -1)
    {
     /*
      * Create a socket for listening...
      */

      lis->fd = socket(lis->address.addr.sa_family, SOCK_STREAM, 0);

      if (lis->fd == -1)
      {
	cupsdLogMessage(CUPSD_LOG_ERROR,
			"Unable to open listen socket for address %s:%d - %s.",
			s, p, strerror(errno));

#ifdef AF_INET6
       /*
        * IPv6 is often disabled while DNS returns IPv6 addresses...
	*/

	if (lis->address.addr.sa_family != AF_INET6 &&
	    (FatalErrors & CUPSD_FATAL_LISTEN))
	  cupsdEndProcess(getpid(), 0);
#else
	if (FatalErrors & CUPSD_FATAL_LISTEN)
	  cupsdEndProcess(getpid(), 0);
#endif /* AF_INET6 */

	continue;
      }

     /*
      * Set things up to reuse the local address for this port.
      */

      val = 1;
#ifdef __sun
      setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
#else
      setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
#endif /* __sun */

     /*
      * Bind to the port we found...
      */

#ifdef AF_INET6
      if (lis->address.addr.sa_family == AF_INET6)
      {
#  ifdef IPV6_V6ONLY
       /*
	* Accept only IPv6 connections on this socket, to avoid
	* potential security issues and to make all platforms behave
	* the same.
	*/

	val = 1;
#    ifdef __sun
	setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
#    else
	setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
#    endif /* __sun */
#  endif /* IPV6_V6ONLY */

	status = bind(lis->fd, (struct sockaddr *)&(lis->address),
		      httpAddrLength(&(lis->address)));
      }
      else
#endif /* AF_INET6 */
#ifdef AF_LOCAL
      if (lis->address.addr.sa_family == AF_LOCAL)
      {
	mode_t	mask;			/* Umask setting */


       /*
	* Remove any existing domain socket file...
	*/

	unlink(lis->address.un.sun_path);

       /*
	* Save the current umask and set it to 0 so that all users can access
	* the domain socket...
	*/

	mask = umask(0);

       /*
	* Bind the domain socket...
	*/

	status = bind(lis->fd, (struct sockaddr *)&(lis->address),
		      httpAddrLength(&(lis->address)));

       /*
	* Restore the umask...
	*/

	umask(mask);
      }
      else
#endif /* AF_LOCAL */
      status = bind(lis->fd, (struct sockaddr *)&(lis->address),
		    sizeof(lis->address.ipv4));

      if (status < 0)
      {
	cupsdLogMessage(CUPSD_LOG_ERROR,
			"Unable to bind socket for address %s:%d - %s.",
			s, p, strerror(errno));
	close(lis->fd);
	lis->fd = -1;

	if (FatalErrors & CUPSD_FATAL_LISTEN)
	  cupsdEndProcess(getpid(), 0);

	continue;
      }

     /*
      * Listen for new clients.
      */

      if (listen(lis->fd, ListenBackLog) < 0)
      {
	cupsdLogMessage(CUPSD_LOG_ERROR,
			"Unable to listen for clients on address %s:%d - %s.",
			s, p, strerror(errno));

	close(lis->fd);
	lis->fd = -1;

	if (FatalErrors & CUPSD_FATAL_LISTEN)
	  cupsdEndProcess(getpid(), 0);

        continue;
      }
    }

    fcntl(lis->fd, F_SETFD, fcntl(lis->fd, F_GETFD) | FD_CLOEXEC);

    if (p)
      cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...",
        	      s, p, lis->fd);
    else
    {
      cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...",
        	      s, lis->fd);

      if (chmod(s, 0140777))
	cupsdLogMessage(CUPSD_LOG_ERROR,
			"Unable to change permisssions on domain socket "
			"\"%s\" - %s", s, strerror(errno));
    }

   /*
    * Save the first port that is bound to the local loopback or
    * "any" address...
    */

    if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 &&
        (httpAddrLocalhost(&(lis->address)) ||
         httpAddrAny(&(lis->address))))
    {
      LocalPort       = p;
      LocalEncryption = lis->encryption;
    }

#ifdef AF_LOCAL
    if (lis->address.addr.sa_family == AF_LOCAL && !have_domain)
      have_domain = lis->address.un.sun_path;
#endif /* AF_LOCAL */
  }

 /*
  * Make sure that we are listening on localhost!
  */

  if (!LocalPort && !have_domain)
  {
    cupsdLogMessage(CUPSD_LOG_EMERG,
                    "No Listen or Port lines were found to allow access via "
		    "localhost!");

    if (FatalErrors & (CUPSD_FATAL_CONFIG | CUPSD_FATAL_LISTEN))
      cupsdEndProcess(getpid(), 0);
  }

 /*
  * Set the CUPS_SERVER, IPP_PORT, and CUPS_ENCRYPTION variables based on
  * the listeners...
  */

  if (have_domain)
  {
   /*
    * Use domain sockets for the local connection...
    */

    cupsdSetEnv("CUPS_SERVER", have_domain);

    LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED;
  }
  else
  {
   /*
    * Use the default local loopback address for the server...
    */

    cupsdSetEnv("CUPS_SERVER", "localhost");
  }

  cupsdSetEnv("CUPS_ENCRYPTION", encryptions[LocalEncryption]);

  if (LocalPort)
    cupsdSetEnvf("IPP_PORT", "%d", LocalPort);

 /*
  * Resume listening for connections...
  */

  cupsdResumeListening();
}
예제 #7
0
파일: adminutil.c 프로젝트: zdohnal/cups
int					/* O - 1 on success, 0 on failure */
cupsAdminGetServerSettings(
    http_t        *http,		/* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
    int           *num_settings,	/* O - Number of settings */
    cups_option_t **settings)		/* O - Settings */
{
  int		i;			/* Looping var */
  cups_file_t	*cupsd;			/* cupsd.conf file */
  char		cupsdconf[1024];	/* cupsd.conf filename */
  int		remote;			/* Remote cupsd.conf file? */
  http_status_t	status;			/* Status of getting cupsd.conf */
  char		line[1024],		/* Line from cupsd.conf file */
		*value;			/* Value on line */
  cups_option_t	*setting;		/* Current setting */
  _cups_globals_t *cg = _cupsGlobals();	/* Global data */


 /*
  * Range check input...
  */

  if (!http)
  {
   /*
    * See if we are connected to the same server...
    */

    if (cg->http)
    {
     /*
      * Compare the connection hostname, port, and encryption settings to
      * the cached defaults; these were initialized the first time we
      * connected...
      */

      if (strcmp(cg->http->hostname, cg->server) ||
          cg->ipp_port != httpAddrPort(cg->http->hostaddr) ||
	  (cg->http->encryption != cg->encryption &&
	   cg->http->encryption == HTTP_ENCRYPTION_NEVER))
      {
       /*
	* Need to close the current connection because something has changed...
	*/

	httpClose(cg->http);
	cg->http = NULL;
      }
    }

   /*
    * (Re)connect as needed...
    */

    if (!cg->http)
    {
      if ((cg->http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC,
                                   cupsEncryption(), 1, 0, NULL)) == NULL)
      {
	if (errno)
	  _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, NULL, 0);
	else
	  _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE,
			_("Unable to connect to host."), 1);

	if (num_settings)
	  *num_settings = 0;

	if (settings)
	  *settings = NULL;

	return (0);
      }
    }

    http = cg->http;
  }

  if (!http || !num_settings || !settings)
  {
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);

    if (num_settings)
      *num_settings = 0;

    if (settings)
      *settings = NULL;

    return (0);
  }

  *num_settings = 0;
  *settings     = NULL;

 /*
  * Get the cupsd.conf file...
  */

  if ((status = get_cupsd_conf(http, cg, cg->cupsd_update, cupsdconf,
                               sizeof(cupsdconf), &remote)) == HTTP_STATUS_OK)
  {
    if ((cupsd = cupsFileOpen(cupsdconf, "r")) == NULL)
    {
      char	message[1024];		/* Message string */


      snprintf(message, sizeof(message),
               _cupsLangString(cupsLangDefault(), _("Open of %s failed: %s")),
               cupsdconf, strerror(errno));
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0);
    }
  }
  else
    cupsd = NULL;

  if (cupsd)
  {
   /*
    * Read the file, keeping track of what settings are enabled...
    */

    int		remote_access = 0,	/* Remote access allowed? */
		remote_admin = 0,	/* Remote administration allowed? */
		remote_any = 0,		/* Remote access from anywhere allowed? */
		browsing = 1,		/* Browsing enabled? */
		cancel_policy = 1,	/* Cancel-job policy set? */
		debug_logging = 0;	/* LogLevel debug set? */
    int		linenum = 0,		/* Line number in file */
		in_location = 0,	/* In a location section? */
		in_policy = 0,		/* In a policy section? */
		in_cancel_job = 0,	/* In a cancel-job section? */
		in_admin_location = 0;	/* In the /admin location? */


    invalidate_cupsd_cache(cg);

    cg->cupsd_update = time(NULL);
    httpGetHostname(http, cg->cupsd_hostname, sizeof(cg->cupsd_hostname));

    while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum))
    {
      if (!value && strncmp(line, "</", 2))
        value = line + strlen(line);

      if ((!_cups_strcasecmp(line, "Port") || !_cups_strcasecmp(line, "Listen")) && value)
      {
	char	*port;			/* Pointer to port number, if any */


	if ((port = strrchr(value, ':')) != NULL)
	  *port = '\0';
	else if (isdigit(*value & 255))
	{
	 /*
	  * Listen on a port number implies remote access...
	  */

	  remote_access = 1;
	  continue;
	}

	if (_cups_strcasecmp(value, "localhost") && strcmp(value, "127.0.0.1")
#ifdef AF_LOCAL
            && *value != '/'
#endif /* AF_LOCAL */
#ifdef AF_INET6
            && strcmp(value, "[::1]")
#endif /* AF_INET6 */
	    )
	  remote_access = 1;
      }
      else if (!_cups_strcasecmp(line, "Browsing"))
      {
	browsing = !_cups_strcasecmp(value, "yes") ||
	           !_cups_strcasecmp(value, "on") ||
	           !_cups_strcasecmp(value, "true");
      }
      else if (!_cups_strcasecmp(line, "LogLevel"))
      {
	debug_logging = !_cups_strncasecmp(value, "debug", 5);
      }
      else if (!_cups_strcasecmp(line, "<Policy") &&
               !_cups_strcasecmp(value, "default"))
      {
	in_policy = 1;
      }
      else if (!_cups_strcasecmp(line, "</Policy>"))
      {
	in_policy = 0;
      }
      else if (!_cups_strcasecmp(line, "<Limit") && in_policy && value)
      {
       /*
	* See if the policy limit is for the Cancel-Job operation...
	*/

	char	*valptr;		/* Pointer into value */


	while (*value)
	{
	  for (valptr = value; *valptr && !_cups_isspace(*valptr); valptr ++);

	  if (*valptr)
	    *valptr++ = '\0';

          if (!_cups_strcasecmp(value, "cancel-job") ||
              !_cups_strcasecmp(value, "all"))
	  {
	    in_cancel_job = 1;
	    break;
	  }

          for (value = valptr; _cups_isspace(*value); value ++);
	}
      }
      else if (!_cups_strcasecmp(line, "</Limit>"))
      {
	in_cancel_job = 0;
      }
      else if (!_cups_strcasecmp(line, "Require") && in_cancel_job)
      {
	cancel_policy = 0;
      }
      else if (!_cups_strcasecmp(line, "<Location") && value)
      {
        in_admin_location = !_cups_strcasecmp(value, "/admin");
	in_location       = 1;
      }
      else if (!_cups_strcasecmp(line, "</Location>"))
      {
	in_admin_location = 0;
	in_location       = 0;
      }
      else if (!_cups_strcasecmp(line, "Allow") && value &&
               _cups_strcasecmp(value, "localhost") &&
               _cups_strcasecmp(value, "127.0.0.1")
#ifdef AF_LOCAL
	       && *value != '/'
#endif /* AF_LOCAL */
#ifdef AF_INET6
	       && strcmp(value, "::1")
#endif /* AF_INET6 */
	       )
      {
        if (in_admin_location)
	  remote_admin = 1;
        else if (!_cups_strcasecmp(value, "all"))
	  remote_any = 1;
      }
      else if (line[0] != '<' && !in_location && !in_policy &&
	       _cups_strcasecmp(line, "Allow") &&
               _cups_strcasecmp(line, "AuthType") &&
	       _cups_strcasecmp(line, "Deny") &&
	       _cups_strcasecmp(line, "Order") &&
	       _cups_strcasecmp(line, "Require") &&
	       _cups_strcasecmp(line, "Satisfy"))
        cg->cupsd_num_settings = cupsAddOption(line, value,
	                                       cg->cupsd_num_settings,
					       &(cg->cupsd_settings));
    }

    cupsFileClose(cupsd);

    cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
                                           debug_logging ? "1" : "0",
					   cg->cupsd_num_settings,
					   &(cg->cupsd_settings));

    cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
                                           (remote_access && remote_admin) ?
					       "1" : "0",
					   cg->cupsd_num_settings,
					   &(cg->cupsd_settings));

    cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY,
                                           remote_any ? "1" : "0",
					   cg->cupsd_num_settings,
					   &(cg->cupsd_settings));

    cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
                                           (remote_access && browsing) ? "1" :
                                                                         "0",
					   cg->cupsd_num_settings,
					   &(cg->cupsd_settings));

    cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
                                           cancel_policy ? "1" : "0",
					   cg->cupsd_num_settings,
					   &(cg->cupsd_settings));
  }
  else if (status != HTTP_STATUS_NOT_MODIFIED)
    invalidate_cupsd_cache(cg);

 /*
  * Remove any temporary files and copy the settings array...
  */

  if (remote)
    unlink(cupsdconf);

  for (i = cg->cupsd_num_settings, setting = cg->cupsd_settings;
       i > 0;
       i --, setting ++)
    *num_settings = cupsAddOption(setting->name, setting->value,
                                  *num_settings, settings);

  return (cg->cupsd_num_settings > 0);
}
예제 #8
0
파일: socket.c 프로젝트: jelmer/cups
int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line arguments (6 or 7) */
     char *argv[])			/* I - Command-line arguments */
{
  const char	*device_uri;		/* Device URI */
  char		scheme[255],		/* Scheme in URI */
		hostname[1024],		/* Hostname */
		username[255],		/* Username info (not used) */
		resource[1024],		/* Resource info (not used) */
		*options,		/* Pointer to options */
		*name,			/* Name of option */
		*value,			/* Value of option */
		sep;			/* Option separator */
  int		print_fd;		/* Print file */
  int		copies;			/* Number of copies to print */
  time_t	start_time;		/* Time of first connect */
  int		contimeout;		/* Connection timeout */
  int		waiteof;		/* Wait for end-of-file? */
  int		port;			/* Port number */
  char		portname[255];		/* Port name */
  int		delay;			/* Delay for retries... */
  int		device_fd;		/* AppSocket */
  int		error;			/* Error code (if any) */
  http_addrlist_t *addrlist,		/* Address list */
		*addr;			/* Connected address */
  char		addrname[256];		/* Address name */
  int		snmp_enabled = 1;	/* Is SNMP enabled? */
  int		snmp_fd,		/* SNMP socket */
		start_count,		/* Page count via SNMP at start */
		page_count,		/* Page count via SNMP */
		have_supplies;		/* Printer supports supply levels? */
  ssize_t	bytes = 0,		/* Initial bytes read */
		tbytes;			/* Total number of bytes written */
  char		buffer[1024];		/* Initial print buffer */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
  struct sigaction action;		/* Actions for POSIX signals */
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */


 /*
  * Make sure status messages are not buffered...
  */

  setbuf(stderr, NULL);

 /*
  * Ignore SIGPIPE signals...
  */

#ifdef HAVE_SIGSET
  sigset(SIGPIPE, SIG_IGN);
#elif defined(HAVE_SIGACTION)
  memset(&action, 0, sizeof(action));
  action.sa_handler = SIG_IGN;
  sigaction(SIGPIPE, &action, NULL);
#else
  signal(SIGPIPE, SIG_IGN);
#endif /* HAVE_SIGSET */

 /*
  * Check command-line...
  */

  if (argc == 1)
  {
    printf("network socket \"Unknown\" \"%s\"\n",
           _cupsLangString(cupsLangDefault(), _("AppSocket/HP JetDirect")));
    return (CUPS_BACKEND_OK);
  }
  else if (argc < 6 || argc > 7)
  {
    _cupsLangPrintf(stderr,
                    _("Usage: %s job-id user title copies options [file]"),
                    argv[0]);
    return (CUPS_BACKEND_FAILED);
  }

 /*
  * If we have 7 arguments, print the file named on the command-line.
  * Otherwise, send stdin instead...
  */

  if (argc == 6)
  {
    print_fd = 0;
    copies   = 1;
  }
  else
  {
   /*
    * Try to open the print file...
    */

    if ((print_fd = open(argv[6], O_RDONLY)) < 0)
    {
      _cupsLangPrintError("ERROR", _("Unable to open print file"));
      return (CUPS_BACKEND_FAILED);
    }

    copies = atoi(argv[4]);
  }

 /*
  * Extract the hostname and port number from the URI...
  */

  while ((device_uri = cupsBackendDeviceURI(argv)) == NULL)
  {
    _cupsLangPrintFilter(stderr, "INFO", _("Unable to locate printer."));
    sleep(10);

    if (getenv("CLASS") != NULL)
      return (CUPS_BACKEND_FAILED);
  }

  httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme),
                  username, sizeof(username), hostname, sizeof(hostname), &port,
		  resource, sizeof(resource));

  if (port == 0)
    port = 9100;	/* Default to HP JetDirect/Tektronix PhaserShare */

 /*
  * Get options, if any...
  */

  waiteof    = 1;
  contimeout = 7 * 24 * 60 * 60;

  if ((options = strchr(resource, '?')) != NULL)
  {
   /*
    * Yup, terminate the device name string and move to the first
    * character of the options...
    */

    *options++ = '\0';

   /*
    * Parse options...
    */

    while (*options)
    {
     /*
      * Get the name...
      */

      name = options;

      while (*options && *options != '=' && *options != '+' && *options != '&')
        options ++;

      if ((sep = *options) != '\0')
        *options++ = '\0';

      if (sep == '=')
      {
       /*
        * Get the value...
	*/

        value = options;

	while (*options && *options != '+' && *options != '&')
	  options ++;

        if (*options)
	  *options++ = '\0';
      }
      else
        value = (char *)"";

     /*
      * Process the option...
      */

      if (!_cups_strcasecmp(name, "waiteof"))
      {
       /*
        * Set the wait-for-eof value...
	*/

        waiteof = !value[0] || !_cups_strcasecmp(value, "on") ||
		  !_cups_strcasecmp(value, "yes") || !_cups_strcasecmp(value, "true");
      }
      else if (!_cups_strcasecmp(name, "snmp"))
      {
        /*
         * Enable/disable SNMP stuff...
         */

         snmp_enabled = !value[0] || !_cups_strcasecmp(value, "on") ||
                        _cups_strcasecmp(value, "yes") ||
                        _cups_strcasecmp(value, "true");
      }
      else if (!_cups_strcasecmp(name, "contimeout"))
      {
       /*
        * Set the connection timeout...
	*/

	if (atoi(value) > 0)
	  contimeout = atoi(value);
      }
    }
  }

 /*
  * Then try finding the remote host...
  */

  start_time = time(NULL);

  sprintf(portname, "%d", port);

  fputs("STATE: +connecting-to-device\n", stderr);
  fprintf(stderr, "DEBUG: Looking up \"%s\"...\n", hostname);

  while ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
  {
    _cupsLangPrintFilter(stderr, "INFO",
                         _("Unable to locate printer \"%s\"."), hostname);
    sleep(10);

    if (getenv("CLASS") != NULL)
    {
      fputs("STATE: -connecting-to-device\n", stderr);
      return (CUPS_BACKEND_STOP);
    }
  }

 /*
  * See if the printer supports SNMP...
  */

  if (snmp_enabled)
    snmp_fd = _cupsSNMPOpen(addrlist->addr.addr.sa_family);
  else
    snmp_fd = -1;

  if (snmp_fd >= 0)
    have_supplies = !backendSNMPSupplies(snmp_fd, &(addrlist->addr),
                                         &start_count, NULL);
  else
    have_supplies = start_count = 0;

 /*
  * Wait for data from the filter...
  */

  if (print_fd == 0)
  {
    if (!backendWaitLoop(snmp_fd, &(addrlist->addr), 1, backendNetworkSideCB))
      return (CUPS_BACKEND_OK);
    else if ((bytes = read(0, buffer, sizeof(buffer))) <= 0)
      return (CUPS_BACKEND_OK);
  }

 /*
  * Connect to the printer...
  */

  fprintf(stderr, "DEBUG: Connecting to %s:%d\n", hostname, port);
  _cupsLangPrintFilter(stderr, "INFO", _("Connecting to printer."));

  for (delay = 5;;)
  {
    if ((addr = httpAddrConnect(addrlist, &device_fd)) == NULL)
    {
      error     = errno;
      device_fd = -1;

      if (getenv("CLASS") != NULL)
      {
       /*
        * If the CLASS environment variable is set, the job was submitted
	* to a class and not to a specific queue.  In this case, we want
	* to abort immediately so that the job can be requeued on the next
	* available printer in the class.
	*/

        _cupsLangPrintFilter(stderr, "INFO",
			     _("Unable to contact printer, queuing on next "
			       "printer in class."));

       /*
        * Sleep 5 seconds to keep the job from requeuing too rapidly...
	*/

	sleep(5);

        return (CUPS_BACKEND_FAILED);
      }

      fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(error));

      if (error == ECONNREFUSED || error == EHOSTDOWN ||
          error == EHOSTUNREACH)
      {
        if (contimeout && (time(NULL) - start_time) > contimeout)
	{
	  _cupsLangPrintFilter(stderr, "ERROR",
	                       _("The printer is not responding."));
	  return (CUPS_BACKEND_FAILED);
	}

	switch (error)
	{
	  case EHOSTDOWN :
	      _cupsLangPrintFilter(stderr, "WARNING",
				   _("The printer may not exist or "
				     "is unavailable at this time."));
	      break;

	  case EHOSTUNREACH :
	      _cupsLangPrintFilter(stderr, "WARNING",
				   _("The printer is unreachable at this "
				     "time."));
	      break;

	  case ECONNREFUSED :
	  default :
	      _cupsLangPrintFilter(stderr, "WARNING",
	                           _("The printer is in use."));
	      break;
        }

	sleep(delay);

	if (delay < 30)
	  delay += 5;
      }
      else
      {
	_cupsLangPrintFilter(stderr, "ERROR",
	                     _("The printer is not responding."));
	sleep(30);
      }
    }
    else
      break;
  }

  fputs("STATE: -connecting-to-device\n", stderr);
  _cupsLangPrintFilter(stderr, "INFO", _("Connected to printer."));

  fprintf(stderr, "DEBUG: Connected to %s:%d...\n",
	  httpAddrString(&(addr->addr), addrname, sizeof(addrname)),
	  httpAddrPort(&(addr->addr)));

 /*
  * Print everything...
  */

  tbytes = 0;

  if (bytes > 0)
    tbytes += write(device_fd, buffer, bytes);

  while (copies > 0 && tbytes >= 0)
  {
    copies --;

    if (print_fd != 0)
    {
      fputs("PAGE: 1 1\n", stderr);
      lseek(print_fd, 0, SEEK_SET);
    }

    tbytes = backendRunLoop(print_fd, device_fd, snmp_fd, &(addrlist->addr), 1,
                            0, backendNetworkSideCB);

    if (print_fd != 0 && tbytes >= 0)
      _cupsLangPrintFilter(stderr, "INFO", _("Print file sent."));
  }

  fputs("STATE: +cups-waiting-for-job-completed\n", stderr);

  if (waiteof)
  {
   /*
    * Shutdown the socket and wait for the other end to finish...
    */

    _cupsLangPrintFilter(stderr, "INFO", _("Waiting for printer to finish."));

    shutdown(device_fd, 1);

    while (wait_bc(device_fd, 90) > 0);
  }

 /*
  * Collect the final page count as needed...
  */

  if (have_supplies &&
      !backendSNMPSupplies(snmp_fd, &(addrlist->addr), &page_count, NULL) &&
      page_count > start_count)
    fprintf(stderr, "PAGE: total %d\n", page_count - start_count);

 /*
  * Close the socket connection...
  */

  close(device_fd);

  httpAddrFreeList(addrlist);

 /*
  * Close the input file and return...
  */

  if (print_fd != 0)
    close(print_fd);

  return (CUPS_BACKEND_OK);
}
예제 #9
0
파일: main.c 프로젝트: apple/cups
static void
service_add_listener(int fd,		/* I - Socket file descriptor */
                     int idx)		/* I - Listener number, for logging */
{
  cupsd_listener_t	*lis;		/* Listeners array */
  http_addr_t		addr;		/* Address variable */
  socklen_t		addrlen;	/* Length of address */
  char			s[256];		/* String addresss */


  addrlen = sizeof(addr);

  if (getsockname(fd, (struct sockaddr *)&addr, &addrlen))
  {
    cupsdLogMessage(CUPSD_LOG_ERROR, "service_add_listener: Unable to get local address for listener #%d: %s", idx + 1, strerror(errno));
    return;
  }

  cupsdLogMessage(CUPSD_LOG_DEBUG, "service_add_listener: Listener #%d at fd %d, \"%s\".", idx + 1, fd, httpAddrString(&addr, s, sizeof(s)));

 /*
  * Try to match the on-demand socket address to one of the listeners...
  */

  for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
       lis;
       lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
    if (httpAddrEqual(&lis->address, &addr))
      break;

  /*
   * Add a new listener If there's no match...
   */

  if (lis)
  {
    cupsdLogMessage(CUPSD_LOG_DEBUG, "service_add_listener: Matched existing listener #%d to %s.", idx + 1, httpAddrString(&(lis->address), s, sizeof(s)));
  }
  else
  {
    cupsdLogMessage(CUPSD_LOG_DEBUG, "service_add_listener: Adding new listener #%d for %s.", idx + 1, httpAddrString(&addr, s, sizeof(s)));

    if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL)
    {
      cupsdLogMessage(CUPSD_LOG_ERROR, "service_add_listener: Unable to allocate listener: %s.", strerror(errno));
      exit(EXIT_FAILURE);
      return;
    }

    cupsArrayAdd(Listeners, lis);

    memcpy(&lis->address, &addr, sizeof(lis->address));
  }

  lis->fd        = fd;
  lis->on_demand = 1;

#  ifdef HAVE_SSL
  if (httpAddrPort(&(lis->address)) == 443)
    lis->encryption = HTTP_ENCRYPT_ALWAYS;
#  endif /* HAVE_SSL */
}
예제 #10
0
파일: http-addrlist.c 프로젝트: apple/cups
http_addrlist_t *			/* O - Connected address or NULL on failure */
httpAddrConnect2(
    http_addrlist_t *addrlist,		/* I - List of potential addresses */
    int             *sock,		/* O - Socket */
    int             msec,		/* I - Timeout in milliseconds */
    int             *cancel)		/* I - Pointer to "cancel" variable */
{
  int			val;		/* Socket option value */
#ifndef WIN32
  int			flags;		/* Socket flags */
#endif /* !WIN32 */
  int			remaining;	/* Remaining timeout */
  int			i,		/* Looping var */
			nfds,		/* Number of file descriptors */
			fds[100],	/* Socket file descriptors */
			result;		/* Result from select() or poll() */
  http_addrlist_t	*addrs[100];	/* Addresses */
#ifndef HAVE_POLL
  int			max_fd = -1;	/* Highest file descriptor */
#endif /* !HAVE_POLL */
#ifdef O_NONBLOCK
#  ifdef HAVE_POLL
  struct pollfd		pfds[100];	/* Polled file descriptors */
#  else
  fd_set		input_set,	/* select() input set */
			output_set,	/* select() output set */
			error_set;	/* select() error set */
  struct timeval	timeout;	/* Timeout */
#  endif /* HAVE_POLL */
#endif /* O_NONBLOCK */
#ifdef DEBUG
  socklen_t		len;		/* Length of value */
  http_addr_t		peer;		/* Peer address */
  char			temp[256];	/* Temporary address string */
#endif /* DEBUG */


  DEBUG_printf(("httpAddrConnect2(addrlist=%p, sock=%p, msec=%d, cancel=%p)", (void *)addrlist, (void *)sock, msec, (void *)cancel));

  if (!sock)
  {
    errno = EINVAL;
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
    return (NULL);
  }

  if (cancel && *cancel)
    return (NULL);

  if (msec <= 0)
    msec = INT_MAX;

 /*
  * Loop through each address until we connect or run out of addresses...
  */

  nfds      = 0;
  remaining = msec;

  while (remaining > 0)
  {
    if (cancel && *cancel)
    {
      while (nfds > 0)
      {
        nfds --;
	httpAddrClose(NULL, fds[nfds]);
      }

      return (NULL);
    }

    if (addrlist && nfds < (int)(sizeof(fds) / sizeof(fds[0])))
    {
     /*
      * Create the socket...
      */

      DEBUG_printf(("2httpAddrConnect2: Trying %s:%d...", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr))));

      if ((fds[nfds] = (int)socket(httpAddrFamily(&(addrlist->addr)), SOCK_STREAM, 0)) < 0)
      {
       /*
	* Don't abort yet, as this could just be an issue with the local
	* system not being configured with IPv4/IPv6/domain socket enabled.
	*
	* Just skip this address...
	*/

        addrlist = addrlist->next;
	continue;
      }

     /*
      * Set options...
      */

      val = 1;
      setsockopt(fds[nfds], SOL_SOCKET, SO_REUSEADDR, CUPS_SOCAST &val, sizeof(val));

#ifdef SO_REUSEPORT
      val = 1;
      setsockopt(fds[nfds], SOL_SOCKET, SO_REUSEPORT, CUPS_SOCAST &val, sizeof(val));
#endif /* SO_REUSEPORT */

#ifdef SO_NOSIGPIPE
      val = 1;
      setsockopt(fds[nfds], SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val));
#endif /* SO_NOSIGPIPE */

     /*
      * Using TCP_NODELAY improves responsiveness, especially on systems
      * with a slow loopback interface...
      */

      val = 1;
      setsockopt(fds[nfds], IPPROTO_TCP, TCP_NODELAY, CUPS_SOCAST &val, sizeof(val));

#ifdef FD_CLOEXEC
     /*
      * Close this socket when starting another process...
      */

      fcntl(fds[nfds], F_SETFD, FD_CLOEXEC);
#endif /* FD_CLOEXEC */

#ifdef O_NONBLOCK
     /*
      * Do an asynchronous connect by setting the socket non-blocking...
      */

      DEBUG_printf(("httpAddrConnect2: Setting non-blocking connect()"));

      flags = fcntl(fds[nfds], F_GETFL, 0);
      fcntl(fds[nfds], F_SETFL, flags | O_NONBLOCK);
#endif /* O_NONBLOCK */

     /*
      * Then connect...
      */

      if (!connect(fds[nfds], &(addrlist->addr.addr), (socklen_t)httpAddrLength(&(addrlist->addr))))
      {
	DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr))));

#ifdef O_NONBLOCK
	fcntl(fds[nfds], F_SETFL, flags);
#endif /* O_NONBLOCK */

	*sock = fds[nfds];

	while (nfds > 0)
	{
	  nfds --;
	  httpAddrClose(NULL, fds[nfds]);
	}

	return (addrlist);
      }

#ifdef WIN32
      if (WSAGetLastError() != WSAEINPROGRESS && WSAGetLastError() != WSAEWOULDBLOCK)
#else
      if (errno != EINPROGRESS && errno != EWOULDBLOCK)
#endif /* WIN32 */
      {
	DEBUG_printf(("1httpAddrConnect2: Unable to connect to %s:%d: %s", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr)), strerror(errno)));
	httpAddrClose(NULL, fds[nfds]);
	addrlist = addrlist->next;
	continue;
      }

#ifndef WIN32
      fcntl(fds[nfds], F_SETFL, flags);
#endif /* !WIN32 */

#ifndef HAVE_POLL
      if (fds[nfds] > max_fd)
	max_fd = fds[nfds];
#endif /* !HAVE_POLL */

      addrs[nfds] = addrlist;
      nfds ++;
      addrlist = addrlist->next;
    }

    if (!addrlist && nfds == 0)
      break;

   /*
    * See if we can connect to any of the addresses so far...
    */

#ifdef O_NONBLOCK
    DEBUG_puts("1httpAddrConnect2: Finishing async connect()");

    do
    {
      if (cancel && *cancel)
      {
       /*
	* Close this socket and return...
	*/

	DEBUG_puts("1httpAddrConnect2: Canceled connect()");

	while (nfds > 0)
	{
	  nfds --;
	  httpAddrClose(NULL, fds[nfds]);
	}

	*sock = -1;

	return (NULL);
      }

#  ifdef HAVE_POLL
      for (i = 0; i < nfds; i ++)
      {
	pfds[i].fd     = fds[i];
	pfds[i].events = POLLIN | POLLOUT;
      }

      result = poll(pfds, (nfds_t)nfds, addrlist ? 100 : remaining > 250 ? 250 : remaining);

      DEBUG_printf(("1httpAddrConnect2: poll() returned %d (%d)", result, errno));

#  else
      FD_ZERO(&input_set);
      for (i = 0; i < nfds; i ++)
	FD_SET(fds[i], &input_set);
      output_set = input_set;
      error_set  = input_set;

      timeout.tv_sec  = 0;
      timeout.tv_usec = (addrlist ? 100 : remaining > 250 ? 250 : remaining) * 1000;

      result = select(max_fd + 1, &input_set, &output_set, &error_set, &timeout);

      DEBUG_printf(("1httpAddrConnect2: select() returned %d (%d)", result, errno));
#  endif /* HAVE_POLL */
    }
#  ifdef WIN32
    while (result < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK));
#  else
    while (result < 0 && (errno == EINTR || errno == EAGAIN));
#  endif /* WIN32 */

    if (result > 0)
    {
      http_addrlist_t *connaddr = NULL;	/* Connected address, if any */

      for (i = 0; i < nfds; i ++)
      {
#  ifdef HAVE_POLL
	DEBUG_printf(("pfds[%d].revents=%x\n", i, pfds[i].revents));
	if (pfds[i].revents && !(pfds[i].revents & (POLLERR | POLLHUP)))
#  else
	if (FD_ISSET(fds[i], &input_set) && !FD_ISSET(fds[i], &error_set))
#  endif /* HAVE_POLL */
	{
	  *sock    = fds[i];
	  connaddr = addrs[i];

#  ifdef DEBUG
	  len   = sizeof(peer);
	  if (!getpeername(fds[i], (struct sockaddr *)&peer, &len))
	    DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...", httpAddrString(&peer, temp, sizeof(temp)), httpAddrPort(&peer)));
#  endif /* DEBUG */
	}
#  ifdef HAVE_POLL
	else if (pfds[i].revents & (POLLERR | POLLHUP))
#  else
	else if (FD_ISSET(fds[i], &error_set))
#  endif /* HAVE_POLL */
        {
         /*
          * Error on socket, remove from the "pool"...
          */

	  httpAddrClose(NULL, fds[i]);
          nfds --;
          if (i < nfds)
          {
            memmove(fds + i, fds + i + 1, (size_t)(nfds - i) * (sizeof(fds[0])));
            memmove(addrs + i, addrs + i + 1, (size_t)(nfds - i) * (sizeof(addrs[0])));
          }
          i --;
        }
      }

      if (connaddr)
        return (connaddr);
    }
#endif /* O_NONBLOCK */

    if (addrlist)
      remaining -= 100;
    else
      remaining -= 250;
  }