Пример #1
0
int network_io_poll()
{
	int nevents;
	struct kevent events[MAXEVENTS];
	struct timespec timeout;
	int fd;
	int evs;
	int n;
	network_socket * s;
	timeout.tv_sec = 1;
	timeout.tv_nsec = 0;

	// check size
	if( g_maxFd == 0 )
	{
		// just sleep, to simulate the delay
		usleep(SLEEPSEC * 1000000);
		return 0;
	}

	nevents = kevent(g_kqueue, 0, 0, events, MAXEVENTS, &timeout);

	if( nevents < 0 )
	{
		// some error occured.
		log_write(ERROR, "FATAL: kevent() returned %d", nevents);
		return -1;
	}

	// no events
	if( nevents == 0 )
		return 0;

	// loop each each socket and handle events on each of them
	for( n = 0; n < nevents; ++n )
	{
		fd = events[n].ident;
		evs = events[n].filter;
		s = g_fds[fd];
		if( s != NULL )
		{
			if( events[n].flags & EV_EOF || events[n].flags & EV_ERROR )
			{
				if( s->event_handler(s, IOEVENT_ERROR) != 0 )
				{
					network_close(s);
					continue;
				}
			}
			else
			{
				if( evs & EVFILT_READ )
				{
					if( s->event_handler(s, IOEVENT_READ) != 0 )
					{
						network_close(s);
						continue;
					}
				}
				
				if( evs & EVFILT_WRITE )
				{
					if( s->write_handler(s, IOEVENT_WRITE) != 0 )
					{
						network_close(s);
						continue;
					}
					else
					{
						// any data left?
						if( s->outlen == 0 )
						{
							// all data written, switch back to read mode
							network_mod(s->fd, EVFILT_READ, 0);
						}
						else
						{
							// still data left, reset write event
							network_mod(s->fd, EVFILT_WRITE, 1);
						}

						// don't have to do anything
					}
				}
			}
		}
	}
	
	// no errors
	return 0;
}
Пример #2
0
static int
fakens_search(const uschar *domain, int type, uschar *answerptr, int size)
{
int len = Ustrlen(domain);
int asize = size;                  /* Locally modified */
uschar *endname;
uschar name[256];
uschar utilname[256];
uschar *aptr = answerptr;          /* Locally modified */
struct stat statbuf;

/* Remove terminating dot. */

if (domain[len - 1] == '.') len--;
Ustrncpy(name, domain, len);
name[len] = 0;
endname = name + len;

/* Look for the fakens utility, and if it exists, call it. */

(void)string_format(utilname, sizeof(utilname), "%s/bin/fakens",
  config_main_directory);

if (stat(CS utilname, &statbuf) >= 0)
  {
  pid_t pid;
  int infd, outfd, rc;
  uschar *argv[5];

  DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) using fakens\n", name, dns_text_type(type));

  argv[0] = utilname;
  argv[1] = config_main_directory;
  argv[2] = name;
  argv[3] = dns_text_type(type);
  argv[4] = NULL;

  pid = child_open(argv, NULL, 0000, &infd, &outfd, FALSE);
  if (pid < 0)
    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to run fakens: %s",
      strerror(errno));

  len = 0;
  rc = -1;
  while (asize > 0 && (rc = read(outfd, aptr, asize)) > 0)
    {
    len += rc;
    aptr += rc;       /* Don't modify the actual arguments, because they */
    asize -= rc;      /* may need to be passed on to res_search(). */
    }

  /* If we ran out of output buffer before exhasting the return,
  carry on reading and counting it. */

  if (asize == 0)
    while ((rc = read(outfd, name, sizeof(name))) > 0)
      len += rc;

  if (rc < 0)
    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "read from fakens failed: %s",
      strerror(errno));

  switch(child_close(pid, 0))
    {
    case 0: return len;
    case 1: h_errno = HOST_NOT_FOUND; return -1;
    case 2: h_errno = TRY_AGAIN; return -1;
    default:
    case 3: h_errno = NO_RECOVERY; return -1;
    case 4: h_errno = NO_DATA; return -1;
    case 5: /* Pass on to res_search() */
    DEBUG(D_dns) debug_printf("fakens returned PASS_ON\n");
    }
  }
else
  {
  DEBUG(D_dns) debug_printf("fakens (%s) not found\n", utilname);
  }

/* fakens utility not found, or it returned "pass on" */

DEBUG(D_dns) debug_printf("passing %s on to res_search()\n", domain);

return res_search(CS domain, C_IN, type, answerptr, size);
}
Пример #3
0
st_ret_t storage_add_type(storage_t st, const char *driver, const char *type) {
    st_driver_t drv;
    st_driver_init_fn init_fn = NULL;
    char mod_fullpath[PATH_MAX];
    const char *modules_path;
    st_ret_t ret;
    void *handle;

    /* startup, see if we've already registered this type */
    if(type == NULL) {
        log_debug(ZONE, "adding arbitrary types to driver '%s'", driver);

        /* see if we already have one */
        if(st->default_drv != NULL) {
            log_debug(ZONE, "we already have a default handler, ignoring this one");
            return st_FAILED;
        }
    } else {
        log_debug(ZONE, "adding type '%s' to driver '%s'", type, driver);

        /* see if we already have one */
        if(xhash_get(st->types, type) != NULL) {
            log_debug(ZONE, "we already have a handler for type '%s', ignoring this one", type);
            return st_FAILED;
        }
    }

    /* set modules path */
    modules_path = config_get_one(st->config, "storage.path", 0);

    /* get the driver */
    drv = xhash_get(st->drivers, driver);
    if(drv == NULL) {
        log_debug(ZONE, "driver not loaded, trying to init");

        log_write(st->log, LOG_INFO, "loading '%s' storage module", driver);
#ifndef _WIN32
        if (modules_path != NULL)
            snprintf(mod_fullpath, PATH_MAX, "%s/storage_%s.so", modules_path, driver);
        else
            snprintf(mod_fullpath, PATH_MAX, "%s/storage_%s.so", LIBRARY_DIR, driver);
        handle = dlopen(mod_fullpath, RTLD_LAZY);
        if (handle != NULL)
            init_fn = dlsym(handle, "st_init");
#else
        if (modules_path != NULL)
            snprintf(mod_fullpath, PATH_MAX, "%s\\storage_%s.dll", modules_path, driver);
        else
            snprintf(mod_fullpath, PATH_MAX, "storage_%s.dll", driver);
        handle = (void*) LoadLibrary(mod_fullpath);
        if (handle != NULL)
            init_fn = (st_driver_init_fn)GetProcAddress((HMODULE) handle, "st_init");
#endif
    
        if (handle != NULL && init_fn != NULL) {
            log_debug(ZONE, "preloaded module '%s' (not initialized yet)", driver);
        } else {
#ifndef _WIN32
            log_write(st->log, LOG_ERR, "failed loading storage module '%s' (%s)", driver, dlerror());
            if (handle != NULL)
                dlclose(handle);
#else
            log_write(st->log, LOG_ERR, "failed loading storage module '%s' (errcode: %x)", driver, GetLastError());
            if (handle != NULL)
                FreeLibrary((HMODULE) handle);
#endif
            return st_FAILED;
        }

        /* make a new driver structure */
        drv = (st_driver_t) calloc(1, sizeof(struct st_driver_st));

        drv->handle = handle;
        drv->st = st;

        log_debug(ZONE, "calling driver initializer");

        /* init */
        if((init_fn)(drv) == st_FAILED) {
            log_write(st->log, LOG_NOTICE, "initialisation of storage driver '%s' failed", driver);
            free(drv);
            return st_FAILED;
        }

        /* add it to the drivers hash so we can find it later */
        drv->name = pstrdup(xhash_pool(st->drivers), driver);
        xhash_put(st->drivers, drv->name, (void *) drv);

        log_write(st->log, LOG_NOTICE, "initialised storage driver '%s'", driver);
    }

    /* if its a default, set it up as such */
    if(type == NULL) {
        st->default_drv = drv;
        return st_SUCCESS;
    }

    /* its a real type, so let the driver know */
    if(type != NULL && (ret = (drv->add_type)(drv, type)) != st_SUCCESS) {
        log_debug(ZONE, "driver '%s' can't handle '%s' data", driver, type);
        return ret;
    }

    /* register the type */
    xhash_put(st->types, pstrdup(xhash_pool(st->types), type), (void *) drv);

    return st_SUCCESS;
}
Пример #4
0
static int
dnsdb_find(void *handle, uschar *filename, const uschar *keystring, int length,
  uschar **result, uschar **errmsg, uint *do_cache)
{
int rc;
int size = 256;
int ptr = 0;
int sep = 0;
int defer_mode = PASS;
int dnssec_mode = OK;
int save_retrans = dns_retrans;
int save_retry =   dns_retry;
int type;
int failrc = FAIL;
const uschar *outsep = CUS"\n";
const uschar *outsep2 = NULL;
uschar *equals, *domain, *found;

/* Because we're the working in the search pool, we try to reclaim as much
store as possible later, so we preallocate the result here */

uschar *yield = store_get(size);

dns_record *rr;
dns_answer dnsa;
dns_scan dnss;

handle = handle;           /* Keep picky compilers happy */
filename = filename;
length = length;
do_cache = do_cache;

/* If the string starts with '>' we change the output separator.
If it's followed by ';' or ',' we set the TXT output separator. */

while (isspace(*keystring)) keystring++;
if (*keystring == '>')
  {
  outsep = keystring + 1;
  keystring += 2;
  if (*keystring == ',')
    {
    outsep2 = keystring + 1;
    keystring += 2;
    }
  else if (*keystring == ';')
    {
    outsep2 = US"";
    keystring++;
    }
  while (isspace(*keystring)) keystring++;
  }

/* Check for a modifier keyword. */

for (;;)
  {
  if (strncmpic(keystring, US"defer_", 6) == 0)
    {
    keystring += 6;
    if (strncmpic(keystring, US"strict", 6) == 0)
      { defer_mode = DEFER; keystring += 6; }
    else if (strncmpic(keystring, US"lax", 3) == 0)
      { defer_mode = PASS; keystring += 3; }
    else if (strncmpic(keystring, US"never", 5) == 0)
      { defer_mode = OK; keystring += 5; }
    else
      {
      *errmsg = US"unsupported dnsdb defer behaviour";
      return DEFER;
      }
    }
  else if (strncmpic(keystring, US"dnssec_", 7) == 0)
    {
    keystring += 7;
    if (strncmpic(keystring, US"strict", 6) == 0)
      { dnssec_mode = DEFER; keystring += 6; }
    else if (strncmpic(keystring, US"lax", 3) == 0)
      { dnssec_mode = PASS; keystring += 3; }
    else if (strncmpic(keystring, US"never", 5) == 0)
      { dnssec_mode = OK; keystring += 5; }
    else
      {
      *errmsg = US"unsupported dnsdb dnssec behaviour";
      return DEFER;
      }
    }
  else if (strncmpic(keystring, US"retrans_", 8) == 0)
    {
    int timeout_sec;
    if ((timeout_sec = readconf_readtime(keystring += 8, ',', FALSE)) <= 0)
      {
      *errmsg = US"unsupported dnsdb timeout value";
      return DEFER;
      }
    dns_retrans = timeout_sec;
    while (*keystring != ',') keystring++;
    }
  else if (strncmpic(keystring, US"retry_", 6) == 0)
    {
    int retries;
    if ((retries = (int)strtol(CCS keystring + 6, CSS &keystring, 0)) < 0)
      {
      *errmsg = US"unsupported dnsdb retry count";
      return DEFER;
      }
    dns_retry = retries;
    }
  else
    break;

  while (isspace(*keystring)) keystring++;
  if (*keystring++ != ',')
    {
    *errmsg = US"dnsdb modifier syntax error";
    return DEFER;
    }
  while (isspace(*keystring)) keystring++;
  }

/* Figure out the "type" value if it is not T_TXT.
If the keystring contains an = this must be preceded by a valid type name. */

type = T_TXT;
if ((equals = Ustrchr(keystring, '=')) != NULL)
  {
  int i, len;
  uschar *tend = equals;

  while (tend > keystring && isspace(tend[-1])) tend--;
  len = tend - keystring;

  for (i = 0; i < nelem(type_names); i++)
    if (len == Ustrlen(type_names[i]) &&
        strncmpic(keystring, US type_names[i], len) == 0)
      {
      type = type_values[i];
      break;
      }

  if (i >= nelem(type_names))
    {
    *errmsg = US"unsupported DNS record type";
    return DEFER;
    }

  keystring = equals + 1;
  while (isspace(*keystring)) keystring++;
  }

/* Initialize the resolver in case this is the first time it has been used. */

dns_init(FALSE, FALSE, dnssec_mode != OK);

/* The remainder of the string must be a list of domains. As long as the lookup
for at least one of them succeeds, we return success. Failure means that none
of them were found.

The original implementation did not support a list of domains. Adding the list
feature is compatible, except in one case: when PTR records are being looked up
for a single IPv6 address. Fortunately, we can hack in a compatibility feature
here: If the type is PTR and no list separator is specified, and the entire
remaining string is valid as an IP address, set an impossible separator so that
it is treated as one item. */

if (type == T_PTR && keystring[0] != '<' &&
    string_is_ip_address(keystring, NULL) != 0)
  sep = -1;

/* SPF strings should be concatenated without a separator, thus make
it the default if not defined (see RFC 4408 section 3.1.3).
Multiple SPF records are forbidden (section 3.1.2) but are currently
not handled specially, thus they are concatenated with \n by default.
MX priority and value are space-separated by default.
SRV and TLSA record parts are space-separated by default. */

if (!outsep2) switch(type)
  {
  case T_SPF:                         outsep2 = US"";  break;
  case T_SRV: case T_MX: case T_TLSA: outsep2 = US" "; break;
  }

/* Now scan the list and do a lookup for each item */

while ((domain = string_nextinlist(&keystring, &sep, NULL, 0)))
  {
  uschar rbuffer[256];
  int searchtype = (type == T_CSA)? T_SRV :         /* record type we want */
                   (type == T_MXH)? T_MX :
                   (type == T_ZNS)? T_NS : type;

  /* If the type is PTR or CSA, we have to construct the relevant magic lookup
  key if the original is an IP address (some experimental protocols are using
  PTR records for different purposes where the key string is a host name, and
  Exim's extended CSA can be keyed by domains or IP addresses). This code for
  doing the reversal is now in a separate function. */

  if ((type == T_PTR || type == T_CSA) &&
      string_is_ip_address(domain, NULL) != 0)
    {
    dns_build_reverse(domain, rbuffer);
    domain = rbuffer;
    }

  do
    {
    DEBUG(D_lookup) debug_printf("dnsdb key: %s\n", domain);

    /* Do the lookup and sort out the result. There are four special types that
    are handled specially: T_CSA, T_ZNS, T_ADDRESSES and T_MXH.
    The first two are handled in a special lookup function so that the facility
    could be used from other parts of the Exim code. T_ADDRESSES is handled by looping
    over the types of A lookup.  T_MXH affects only what happens later on in
    this function, but for tidiness it is handled by the "special". If the
    lookup fails, continue with the next domain. In the case of DEFER, adjust
    the final "nothing found" result, but carry on to the next domain. */

    found = domain;
#if HAVE_IPV6
    if (type == T_ADDRESSES)		/* NB cannot happen unless HAVE_IPV6 */
      {
      if (searchtype == T_ADDRESSES) searchtype = T_AAAA;
      else if (searchtype == T_AAAA) searchtype = T_A;
      rc = dns_special_lookup(&dnsa, domain, searchtype, CUSS &found);
      }
    else
#endif
      rc = dns_special_lookup(&dnsa, domain, type, CUSS &found);

    lookup_dnssec_authenticated = dnssec_mode==OK ? NULL
      : dns_is_secure(&dnsa) ? US"yes" : US"no";

    if (rc == DNS_NOMATCH || rc == DNS_NODATA) continue;
    if (  rc != DNS_SUCCEED
       || (dnssec_mode == DEFER && !dns_is_secure(&dnsa))
       )
      {
      if (defer_mode == DEFER)
	{
	dns_retrans = save_retrans;
	dns_retry = save_retry;
	dns_init(FALSE, FALSE, FALSE);			/* clr dnssec bit */
	return DEFER;					/* always defer */
	}
      if (defer_mode == PASS) failrc = DEFER;         /* defer only if all do */
      continue;                                       /* treat defer as fail */
      }


    /* Search the returned records */

    for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
         rr != NULL;
         rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
      {
      if (rr->type != searchtype) continue;

      if (*do_cache > rr->ttl)
	*do_cache = rr->ttl;

      if (type == T_A || type == T_AAAA || type == T_ADDRESSES)
        {
        dns_address *da;
        for (da = dns_address_from_rr(&dnsa, rr); da; da = da->next)
          {
          if (ptr != 0) yield = string_catn(yield, &size, &ptr, outsep, 1);
          yield = string_cat(yield, &size, &ptr, da->address);
          }
        continue;
        }

      /* Other kinds of record just have one piece of data each, but there may be
      several of them, of course. */

      if (ptr != 0) yield = string_catn(yield, &size, &ptr, outsep, 1);

      if (type == T_TXT || type == T_SPF)
        {
        if (outsep2 == NULL)
          {
          /* output only the first item of data */
          yield = string_catn(yield, &size, &ptr, (uschar *)(rr->data+1),
            (rr->data)[0]);
          }
        else
          {
          /* output all items */
          int data_offset = 0;
          while (data_offset < rr->size)
            {
            uschar chunk_len = (rr->data)[data_offset++];
            if (outsep2[0] != '\0' && data_offset != 1)
              yield = string_catn(yield, &size, &ptr, outsep2, 1);
            yield = string_catn(yield, &size, &ptr,
                             US ((rr->data)+data_offset), chunk_len);
            data_offset += chunk_len;
            }
          }
        }
      else if (type == T_TLSA)
        {
        uint8_t usage, selector, matching_type;
        uint16_t i, payload_length;
        uschar s[MAX_TLSA_EXPANDED_SIZE];
	uschar * sp = s;
        uschar * p = US rr->data;

        usage = *p++;
        selector = *p++;
        matching_type = *p++;
        /* What's left after removing the first 3 bytes above */
        payload_length = rr->size - 3;
        sp += sprintf(CS s, "%d%c%d%c%d%c", usage, *outsep2,
		selector, *outsep2, matching_type, *outsep2);
        /* Now append the cert/identifier, one hex char at a time */
        for (i=0;
             i < payload_length && sp-s < (MAX_TLSA_EXPANDED_SIZE - 4);
             i++)
          sp += sprintf(CS sp, "%02x", (unsigned char)p[i]);

        yield = string_cat(yield, &size, &ptr, s);
        }
      else   /* T_CNAME, T_CSA, T_MX, T_MXH, T_NS, T_PTR, T_SOA, T_SRV */
        {
        int priority, weight, port;
        uschar s[264];
        uschar * p = US rr->data;

	switch (type)
	  {
	  case T_MXH:
	    /* mxh ignores the priority number and includes only the hostnames */
	    GETSHORT(priority, p);
	    break;

	  case T_MX:
	    GETSHORT(priority, p);
	    sprintf(CS s, "%d%c", priority, *outsep2);
	    yield = string_cat(yield, &size, &ptr, s);
	    break;

	  case T_SRV:
	    GETSHORT(priority, p);
	    GETSHORT(weight, p);
	    GETSHORT(port, p);
	    sprintf(CS s, "%d%c%d%c%d%c", priority, *outsep2,
			      weight, *outsep2, port, *outsep2);
	    yield = string_cat(yield, &size, &ptr, s);
	    break;

	  case T_CSA:
	    /* See acl_verify_csa() for more comments about CSA. */
	    GETSHORT(priority, p);
	    GETSHORT(weight, p);
	    GETSHORT(port, p);

	    if (priority != 1) continue;      /* CSA version must be 1 */

	    /* If the CSA record we found is not the one we asked for, analyse
	    the subdomain assertions in the port field, else analyse the direct
	    authorization status in the weight field. */

	    if (Ustrcmp(found, domain) != 0)
	      {
	      if (port & 1) *s = 'X';         /* explicit authorization required */
	      else *s = '?';                  /* no subdomain assertions here */
	      }
	    else
	      {
	      if (weight < 2) *s = 'N';       /* not authorized */
	      else if (weight == 2) *s = 'Y'; /* authorized */
	      else if (weight == 3) *s = '?'; /* unauthorizable */
	      else continue;                  /* invalid */
	      }

	    s[1] = ' ';
	    yield = string_catn(yield, &size, &ptr, s, 2);
	    break;

	  default:
	    break;
	  }

        /* GETSHORT() has advanced the pointer to the target domain. */

        rc = dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, p,
          (DN_EXPAND_ARG4_TYPE)s, sizeof(s));

        /* If an overlong response was received, the data will have been
        truncated and dn_expand may fail. */

        if (rc < 0)
          {
          log_write(0, LOG_MAIN, "host name alias list truncated: type=%s "
            "domain=%s", dns_text_type(type), domain);
          break;
          }
        else yield = string_cat(yield, &size, &ptr, s);

	if (type == T_SOA && outsep2 != NULL)
	  {
	  unsigned long serial, refresh, retry, expire, minimum;

	  p += rc;
	  yield = string_catn(yield, &size, &ptr, outsep2, 1);

	  rc = dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, p,
	    (DN_EXPAND_ARG4_TYPE)s, sizeof(s));
	  if (rc < 0)
	    {
	    log_write(0, LOG_MAIN, "responsible-mailbox truncated: type=%s "
	      "domain=%s", dns_text_type(type), domain);
	    break;
	    }
	  else yield = string_cat(yield, &size, &ptr, s);

	  p += rc;
	  GETLONG(serial, p); GETLONG(refresh, p);
	  GETLONG(retry,  p); GETLONG(expire,  p); GETLONG(minimum, p);
	  sprintf(CS s, "%c%lu%c%lu%c%lu%c%lu%c%lu",
	    *outsep2, serial, *outsep2, refresh,
	    *outsep2, retry,  *outsep2, expire,  *outsep2, minimum);
	  yield = string_cat(yield, &size, &ptr, s);
	  }
        }
      }    /* Loop for list of returned records */

           /* Loop for set of A-lookup types */
    } while (type == T_ADDRESSES && searchtype != T_A);

  }        /* Loop for list of domains */

/* Reclaim unused memory */

store_reset(yield + ptr + 1);

/* If ptr == 0 we have not found anything. Otherwise, insert the terminating
zero and return the result. */

dns_retrans = save_retrans;
dns_retry = save_retry;
dns_init(FALSE, FALSE, FALSE);	/* clear the dnssec bit for getaddrbyname */

if (ptr == 0) return failrc;
yield[ptr] = 0;
*result = yield;
return OK;
}
Пример #5
0
int network_add_socket(network_socket * s)
{
	// not hard, just add it to the fd map and it'll be polled next loop
	log_write(DEBUG, "adding socket %u to fd map.", s->fd);
	return fdmapper_insert_socket(s);
}
Пример #6
0
static void
add_generated(router_instance *rblock, address_item **addr_new,
  address_item *addr, address_item *generated,
  address_item_propagated *addr_prop, ugid_block *ugidptr, struct passwd *pw)
{
redirect_router_options_block *ob =
  (redirect_router_options_block *)(rblock->options_block);

while (generated != NULL)
  {
  address_item *parent;
  address_item *next = generated;
  uschar *errors_address = next->prop.errors_address;

  generated = next->next;
  next->parent = addr;
  orflag(next, addr, af_ignore_error);
  next->start_router = rblock->redirect_router;
  if (addr->child_count == SHRT_MAX)
    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s router generated more than %d "
      "child addresses for <%s>", rblock->name, SHRT_MAX, addr->address);
  addr->child_count++;

  next->next = *addr_new;
  *addr_new = next;

  /* Don't do the "one_time" thing for the first pass of a 2-stage queue run. */

  if (ob->one_time && !queue_2stage)
    {
    for (parent = addr; parent->parent != NULL; parent = parent->parent);
    next->onetime_parent = parent->address;
    }

  if (ob->hide_child_in_errmsg) setflag(next, af_hide_child);

  /* If check_ancestor is set, we want to know if any ancestor of this address
  is the address we are about to generate. The check must be done caselessly
  unless the ancestor was routed by a case-sensitive router. */

  if (ob->check_ancestor)
    {
    for (parent = addr; parent != NULL; parent = parent->parent)
      {
      if (((parent->router != NULL && parent->router->caseful_local_part)?
           Ustrcmp(next->address, parent->address)
           :
           strcmpic(next->address, parent->address)
          ) == 0)
        {
        DEBUG(D_route) debug_printf("generated parent replaced by child\n");
        next->address = string_copy(addr->address);
        break;
        }
      }
    }

  /* A user filter may, under some circumstances, set up an errors address.
  If so, we must take care to re-instate it when we copy in the propagated
  data so that it overrides any errors_to setting on the router. */

  next->prop = *addr_prop;
  if (errors_address != NULL) next->prop.errors_address = errors_address;

  /* For pipes, files, and autoreplies, record this router as handling them,
  because they don't go through the routing process again. Then set up uid,
  gid, home and current directories for transporting. */

  if (testflag(next, af_pfr))
    {
    next->router = rblock;
    rf_set_ugid(next, ugidptr);   /* Will contain pw values if not overridden */

    /* When getting the home directory out of the password information, wrap it
    in \N...\N to avoid expansion later. In Cygwin, home directories can
    contain $ characters. */

    if (rblock->home_directory != NULL)
      next->home_dir = rblock->home_directory;
    else if (rblock->check_local_user)
      next->home_dir = string_sprintf("\\N%s\\N", pw->pw_dir);
    else if (rblock->router_home_directory != NULL &&
             testflag(addr, af_home_expanded))
      {
      next->home_dir = deliver_home;
      setflag(next, af_home_expanded);
      }

    next->current_dir = rblock->current_directory;

    /* Permission options */

    if (!ob->forbid_pipe) setflag(next, af_allow_pipe);
    if (!ob->forbid_file) setflag(next, af_allow_file);
    if (!ob->forbid_filter_reply) setflag(next, af_allow_reply);

    /* If the transport setting fails, the error gets picked up at the outer
    level from the setting of basic_errno in the address. */

    if (next->address[0] == '|')
      {
      address_pipe = next->address;
      if (rf_get_transport(ob->pipe_transport_name, &(ob->pipe_transport),
          next, rblock->name, US"pipe_transport"))
        next->transport = ob->pipe_transport;
      address_pipe = NULL;
      }
    else if (next->address[0] == '>')
      {
      if (rf_get_transport(ob->reply_transport_name, &(ob->reply_transport),
          next, rblock->name, US"reply_transport"))
        next->transport = ob->reply_transport;
      }
    else  /* must be file or directory */
      {
      int len = Ustrlen(next->address);
      address_file = next->address;
      if (next->address[len-1] == '/')
        {
        if (rf_get_transport(ob->directory_transport_name,
            &(ob->directory_transport), next, rblock->name,
            US"directory_transport"))
          next->transport = ob->directory_transport;
        }
      else
        {
        if (rf_get_transport(ob->file_transport_name, &(ob->file_transport),
            next, rblock->name, US"file_transport"))
          next->transport = ob->file_transport;
        }
      address_file = NULL;
      }
    }

#ifdef SUPPORT_I18N
    next->prop.utf8_msg = string_is_utf8(next->address)
      || (sender_address && string_is_utf8(sender_address));
#endif

  DEBUG(D_route)
    {
    debug_printf("%s router generated %s\n  %serrors_to=%s transport=%s\n",
      rblock->name,
      next->address,
      testflag(next, af_pfr)? "pipe, file, or autoreply\n  " : "",
      next->prop.errors_address,
      (next->transport == NULL)? US"NULL" : next->transport->name);

    if (testflag(next, af_uid_set))
      debug_printf("  uid=%ld ", (long int)(next->uid));
    else
      debug_printf("  uid=unset ");

    if (testflag(next, af_gid_set))
      debug_printf("gid=%ld ", (long int)(next->gid));
    else
      debug_printf("gid=unset ");

#ifdef SUPPORT_I18N
    if (next->prop.utf8_msg) debug_printf("utf8 ");
#endif

    debug_printf("home=%s\n", next->home_dir);
    }
  }
}
Пример #7
0
static void report_bad_rect_order(void) {
    if (!warned) {
        log_write(LL_WARN, "Bad rectangle order in regions - not packing");
        warned = 1;
    }
}
Пример #8
0
/* priority is one of LOG_DEBUG, LOG_INFO, LOG_NOTICE, etc. See sys/syslog.h.
   OR'd to priority can be MS_TFTP, MS_DHCP, ... to be able to do log separation between
   DNS, DHCP and TFTP services.
*/
void my_syslog(int priority, const char *format, ...)
{
  va_list ap;
  struct log_entry *entry;
  time_t time_now;
  char *p;
  size_t len;
  pid_t pid = getpid();
  char *func = "";

  if ((LOG_FACMASK & priority) == MS_TFTP)
    func = "-tftp";
  else if ((LOG_FACMASK & priority) == MS_DHCP)
    func = "-dhcp";
      
#ifdef LOG_PRI
  priority = LOG_PRI(priority);
#else
  /* Solaris doesn't have LOG_PRI */
  priority &= LOG_PRIMASK;
#endif

  if (echo_stderr) 
    {
      fprintf(stderr, "dnsmasq%s: ", func);
      va_start(ap, format);
      vfprintf(stderr, format, ap);
      va_end(ap);
      fputc('\n', stderr);
    }

  if (log_fd == -1)
    {
#ifdef __ANDROID__
      /* do android-specific logging. 
	 log_fd is always -1 on Android except when logging to a file. */
      int alog_lvl;
      
      if (priority <= LOG_ERR)
	alog_lvl = ANDROID_LOG_ERROR;
      else if (priority == LOG_WARNING)
	alog_lvl = ANDROID_LOG_WARN;
      else if (priority <= LOG_INFO)
	alog_lvl = ANDROID_LOG_INFO;
      else
	alog_lvl = ANDROID_LOG_DEBUG;

      va_start(ap, format);
      __android_log_vprint(alog_lvl, "dnsmasq", format, ap);
      va_end(ap);
#else
      /* fall-back to syslog if we die during startup or 
	 fail during running (always on Solaris). */
      static int isopen = 0;

      if (!isopen)
	{
	  openlog("dnsmasq", LOG_PID, log_fac);
	  isopen = 1;
	}
      va_start(ap, format);  
      vsyslog(priority, format, ap);
      va_end(ap);
#endif

      return;
    }
  
  if ((entry = free_entries))
    free_entries = entry->next;
  else if (entries_alloced < max_logs && (entry = malloc(sizeof(struct log_entry))))
    entries_alloced++;
  
  if (!entry)
    entries_lost++;
  else
    {
      /* add to end of list, consumed from the start */
      entry->next = NULL;
      if (!entries)
	entries = entry;
      else
	{
	  struct log_entry *tmp;
	  for (tmp = entries; tmp->next; tmp = tmp->next);
	  tmp->next = entry;
	}
      
      time(&time_now);
      p = entry->payload;
      if (!log_to_file)
	p += sprintf(p, "<%d>", priority | log_fac);

      /* Omit timestamp for default daemontools situation */
      if (!log_stderr || !option_bool(OPT_NO_FORK)) 
	p += sprintf(p, "%.15s ", ctime(&time_now) + 4);
      
      p += sprintf(p, "dnsmasq%s[%d]: ", func, (int)pid);
        
      len = p - entry->payload;
      va_start(ap, format);  
      len += vsnprintf(p, MAX_MESSAGE - len, format, ap) + 1; /* include zero-terminator */
      va_end(ap);
      entry->length = len > MAX_MESSAGE ? MAX_MESSAGE : len;
      entry->offset = 0;
      entry->pid = pid;
    }
  
  /* almost always, logging won't block, so try and write this now,
     to save collecting too many log messages during a select loop. */
  log_write();
  
  /* Since we're doing things asynchronously, a cache-dump, for instance,
     can now generate log lines very fast. With a small buffer (desirable),
     that means it can overflow the log-buffer very quickly,
     so that the cache dump becomes mainly a count of how many lines 
     overflowed. To avoid this, we delay here, the delay is controlled 
     by queue-occupancy, and grows exponentially. The delay is limited to (2^8)ms.
     The scaling stuff ensures that when the queue is bigger than 8, the delay
     only occurs for the last 8 entries. Once the queue is full, we stop delaying
     to preserve performance.
  */

  if (entries && max_logs != 0)
    {
      int d;
      
      for (d = 0,entry = entries; entry; entry = entry->next, d++);
      
      if (d == max_logs)
	d = 0;
      else if (max_logs > 8)
	d -= max_logs - 8;

      if (d > 0)
	{
	  struct timespec waiter;
	  waiter.tv_sec = 0;
	  waiter.tv_nsec = 1000000 << (d - 1); /* 1 ms */
	  nanosleep(&waiter, NULL);
      
	  /* Have another go now */
	  log_write();
	}
    } 
}
Пример #9
0
void check_log_writer(fd_set *set)
{
  if (log_fd != -1 && (!set || FD_ISSET(log_fd, set)))
    log_write();
}
Пример #10
0
int parse_cramfs_archive(const char *filename, uint8_t *data, unsigned int length, const char *filepath, int detected_device)
{
	struct flash_file *flash;
	int file_device;
	char cramfs_name[2048];
	
	flash = flash_create(data, length);
	if(!flash) {
		fprintf(stderr, "%s: Memory error\n", program);
		return 0;
	}
	
	if(flash->header->magic != AOS_CRAMFS_MAGIC) {
		fprintf(stderr, "%s: Invalid Cramfs magic on file.\n", filename);
		flash_free(flash);
		return 0;
	}
	
	if(!flash_detect_key(flash, Bootloader_Keys, MPK_KNOWN_DEVICES, &file_device)) {
		printf("WARNING: %s: Signature is invalid.\n", filename);
	}
	else {
		if(detected_device != file_device) {
			printf("WARNING: %s: The detected device type for this file does not match the .aos device type (detected %s).\n", filename, mpk_device_type(file_device));
		}
		else {
			if(verbose)
				printf("\t%s: Signature is valid, detected device type %s\n", filename, mpk_device_type(file_device));
		}
	}
	
	strcpy(cramfs_name, filename);
	cramfs_name[strlen(cramfs_name)-strlen(".secure")] = 0;
	
	log_write("unpack.sh", "## .cramfs.secure: %s\n", filepath);
	log_write("unpack.sh", "rm -f -r unpacked/%s\n", cramfs_name);
	log_write("unpack.sh", "mkdir -p unpacked\n");
	if(*(uint32_t *)&flash->header->data[0] == 0x28cd3d45 /* CRAMFS_MAGIC */) {
		/* this is a cramfs with a small header (0x100 bytes), which is nonstandard for a cramfs file. */
		log_write("unpack.sh", "dd if=%s of=unpacked/%s.stripped bs=256 skip=1\n", filepath, cramfs_name);
		log_write("unpack.sh", "(cd unpacked/ && cramfsck -v -x %s %s.stripped)\n", cramfs_name, cramfs_name);
		log_write("unpack.sh", "rm unpacked/%s.stripped\n", cramfs_name);
	} else {
		/* this is a cramfs file with either no header or a standard cramfs header (0x200 bytes). */
		log_write("unpack.sh", "cramfsck -x unpacked/%s %s\n", cramfs_name, filepath);
	}
	log_write("unpack.sh", "\n");
	
	log_write("repack.sh", "## .cramfs.secure: %s\n", filepath);
	if(*(uint32_t *)&flash->header->data[0] == 0x28cd3d45 /* CRAMFS_MAGIC */) {
		log_write("repack.sh", "mkcramfs unpacked/%s unpacked/%s.tmp\n", cramfs_name, cramfs_name);
		log_write("repack.sh", "rm -f -r unpacked/%s\n", cramfs_name);
		log_write("repack.sh", "aos-fix --add-header unpacked/%s.tmp\n", cramfs_name);
		log_write("repack.sh", "mv unpacked/%s.tmp unpacked/%s.secure\n", cramfs_name, cramfs_name);
	} else {
		// create a cramfs with padding for the header, and write the header in-place
		log_write("repack.sh", "mkcramfs -p unpacked/%s unpacked/%s.secure\n", cramfs_name, cramfs_name);
		log_write("repack.sh", "rm -f -r unpacked/%s\n", cramfs_name);
		log_write("repack.sh", "aos-fix --add-header --overwrite unpacked/%s.secure\n", cramfs_name);
	}
	log_write("repack.sh", "mv unpacked/%s.secure %s\n", cramfs_name, filepath);
	log_write("repack.sh", "\n");
	
	flash_free(flash);
	
	return 1;
}
Пример #11
0
int parse_flash_partition(uint8_t *data, unsigned int length, const char *partition_name, uint32_t offset, const char *filepath, int detected_device)
{
	struct flash_file *flash;
	int file_device;
	
	flash = flash_create(data, length);
	if(!flash) {
		fprintf(stderr, "%s: Memory error\n", program);
		return 0;
	}
	
	switch(flash->header->magic) {
		case AOS_ZMfX_MAGIC: {
			if(verbose) printf("\t%s: Stage 2 bootloader\n", filepath);
			break;
		}
		case AOS_KERNEL_MAGIC: {
			if(verbose) printf("\t%s: Kernel (zImage+initramfs)\n", filepath);
			break;
		}
		case AOS_GZIP_MAGIC: {
			if(verbose) printf("\t%s: Boot Logo\n", filepath);
			break;
		}
		default: {
			if(offset == 0x3f8000 || offset == 0x000000) {
				// We know those are never signed, so we don't warn about them
				flash_free(flash);
				return 0;
			}
			
			printf("\t%s: Unknown magic, this is weird.\n", filepath);
			flash_free(flash);
			return 0;
		}
	}
	
	if(flash->header->magic != AOS_GZIP_MAGIC) {
		if(flash->header->bits != 0x400) {
			if(verbose)
				printf("\t%s: Signature is 0 bits long (SDE Firmware?).\n", filepath);
		}
		else {
			if(!flash_is_signed(flash)) {
				if(verbose)
					printf("\t%s: File is not signed.\n", filepath);
			}
			else {
				if(!flash_detect_key(flash, Bootloader_Keys, MPK_KNOWN_DEVICES, &file_device)) {
					printf("WARNING: %s: Signature is not valid.\n", filepath);
				}
				else {
					if(detected_device != file_device) {
						printf("WARNING: %s: The detected device type for this file does not match the .aos device type (detected %s).\n", filepath, mpk_device_type(file_device));
					}
					else {
						if(verbose)
							printf("\t%s: Signature is valid, detected device type %s.\n", filepath, mpk_device_type(file_device));
					}
				}
			}
		}
	}
	
	if(flash->header->magic == AOS_KERNEL_MAGIC) {
		unsigned int gz_length;
		uint8_t *gz_data;
		char *folder_name;
		char *device_shortname;
		
		gz_data = (uint8_t *)flash->header+flash->header->cpio;
		gz_length = (flash->length - flash->header->cpio);
		
		if(*(uint32_t *)gz_data == AOS_GZIP_MAGIC) {
			folder_name = strdup((const char *)&gz_data[10]);
			if(endswith(folder_name, ".cpio"))
				folder_name[strlen(folder_name)-strlen(".cpio")] = 0;
		}
		else if((*(uint32_t *)gz_data & AOS_GZIP_NONAME_MASK) == AOS_GZIP_NONAME_MAGIC) {
			folder_name = bprintf("%s", partition_name);
		}
		else {
			printf("error: Could not find GZIP magic at given offset in %s.\n", filepath);
			flash_free(flash);
			return 0;
		}
		
		switch(detected_device) {
			case MPK_DEVICE_A5: device_shortname = "a5"; break;
			case MPK_DEVICE_A5IT: device_shortname = "a5it"; break;
			case MPK_DEVICE_A3GP: device_shortname = "a3g"; break;
			default: device_shortname = "unk"; break;
		}
		
		// Unpack script
		log_write("unpack.sh", "## zImage+initramfs: %s\n", filepath);
		log_write("unpack.sh", "rm -f -r unpacked/%s/\n", folder_name);
		log_write("unpack.sh", "mkdir -p unpacked/%s/initramfs/\n", folder_name);
		log_write("unpack.sh", "aos-unpack %s --%s --output unpacked/%s/ --zimage zImage --initramfs initramfs.cpio.gz\n", filepath, device_shortname, folder_name);
		log_write("unpack.sh", "gunzip --decompress unpacked/%s/initramfs.cpio.gz\n", folder_name);
		log_write("unpack.sh", "(cd unpacked/%s/initramfs/ && cpio -i -d -H newc -F ../initramfs.cpio --no-absolute-filenames)\n", folder_name, folder_name);
		log_write("unpack.sh", "rm unpacked/%s/initramfs.cpio\n", folder_name);
		log_write("unpack.sh", "\n");
		
		// Repack script
		log_write("repack.sh", "## zImage+initramfs: %s\n", filepath);
		log_write("repack.sh", "(cd unpacked/%s/initramfs/ && find . | cpio -o -H newc -F ../initramfs.cpio)\n", folder_name);
		log_write("repack.sh", "rm -f -r unpacked/%s/initramfs/\n", folder_name);
		log_write("repack.sh", "gzip --name --best unpacked/%s/initramfs.cpio\n", folder_name);
		log_write("repack.sh", "aos-repack --kernel --output %s --zimage unpacked/%s/zImage --initramfs unpacked/%s/initramfs.cpio.gz\n", filepath, folder_name, folder_name);
		log_write("repack.sh", "rm -f -r  unpacked/%s/\n", folder_name);
		log_write("repack.sh", "\n");
		
		free(folder_name);
	}
	else if(flash->header->magic == AOS_GZIP_MAGIC) {
		const char *gz_name = (const char *)&data[10];
		
		log_write("unpack.sh", "## .gz: %s\n", filepath);
		log_write("unpack.sh", "mkdir -p unpacked/\n", gz_name);
		log_write("unpack.sh", "rm -f unpacked/%s\n", gz_name);
		log_write("unpack.sh", "cp %s unpacked/%s.gz\n", filepath, gz_name);
		log_write("unpack.sh", "gunzip -d unpacked/%s.gz\n", gz_name);
		log_write("unpack.sh", "\n");
		
		log_write("repack.sh", "## .gz: %s\n", filepath);
		log_write("repack.sh", "gzip -N --best unpacked/%s\n", gz_name);
		log_write("repack.sh", "cp unpacked/%s.gz %s\n", gz_name, filepath);
		log_write("repack.sh", "rm -f unpacked/%s.gz\n", gz_name);
		log_write("repack.sh", "\n");
	}
	
	flash_free(flash);
	
	return 1;
}
Пример #12
0
int parse_targets(struct targets *targets, char *h)
{
	int i = 0, j = 0, k = 0;
	int start, end;
	char *r, *s, *target_net;
	char *addy[5];
	char *hostexp = strdup(h);
	struct hostent *target;
	unsigned long longtmp;
	int namedhost = 0;

	bzero(targets, sizeof(*targets));
	targets->nleft = 0;
/*struct in_addr current_in;*/
	addy[0] = addy[1] = addy[2] = addy[3] = addy[4] = NULL;
	addy[0] = r = hostexp;
/* First we break the expression up into the four parts of the IP address
   + the optional '/mask' */
	target_net = strtok(hostexp, "/");
	s = strtok(NULL, "");	/* find the end of the token from hostexp */
	targets->netmask = (s) ? atoi(s) : 32;
	if ((int) targets->netmask < 0 || targets->netmask > 32) {
		fprintf(stderr, "Illegal netmask value (%d), must be /0 - /32 .  Assuming /32 (one host)\n", targets->netmask);
		targets->netmask = 32;
	}
	for (i = 0; *(hostexp + i); i++)
		if (isupper((int) *(hostexp + i))
		    || islower((int) *(hostexp + i))) {
			namedhost = 1;
			break;
		}
	if (targets->netmask != 32 || namedhost) {
		targets->maskformat = 1;
		if (!inet_aton(target_net, &(targets->start))) {
			if ((target = gethostbyname(target_net)))
				memcpy(&(targets->start), target->h_addr_list[0], sizeof(struct in_addr));
			else {
				fprintf(stderr, "Failed to resolve given hostname/IP: %s.  Note that you can't use '/mask' AND '[1-4,7,100-]' style IP ranges\n", target_net);
				free(hostexp);
				return 0;
			}
		}
		longtmp = ntohl(targets->start.s_addr);
		targets->start.s_addr = longtmp & (unsigned long) (0 - (1 << (32 - targets->netmask)));
		targets->end.s_addr = longtmp | (unsigned long) ((1 << (32 - targets->netmask)) - 1);
		targets->currentaddr = targets->start;
		if (targets->start.s_addr <= targets->end.s_addr) {
			targets->nleft = targets->end.s_addr - targets->start.s_addr + 1;
			free(hostexp);
			return 1;
		}
		fprintf(stderr, "Host specification invalid");
		free(hostexp);
		return 0;
	} else {
		i = 0;
		targets->maskformat = 0;
		while (*++r) {
			if (*r == '.' && ++i < 4) {
				*r = '\0';
				addy[i] = r + 1;
			} else if (*r == '[') {
				*r = '\0';
				addy[i]++;
			} else if (*r == ']')
				*r = '\0';
			/*else if ((*r == '/' || *r == '\\') && i == 3) {
			 *r = '\0';
			 addy[4] = r + 1;
			 }*/
			else if (*r != '*' && *r != ',' && *r != '-' && !isdigit((int) *r))
				fatal("Invalid character in  host specification.");
		}
		if (i != 3)
			fatal("Target host specification is illegal.");

		for (i = 0; i < 4; i++) {
			j = 0;
			while ((s = strchr(addy[i], ','))) {
				*s = '\0';
				if (*addy[i] == '*') {
					start = 0;
					end = 255;
				} else if (*addy[i] == '-') {
					start = 0;
					if (!addy[i] + 1)
						end = 255;
					else
						end = atoi(addy[i] + 1);
				} else {
					start = end = atoi(addy[i]);
					if ((r = strchr(addy[i], '-'))
					    && *(r + 1))
						end = atoi(r + 1);
					else if (r && !*(r + 1))
						end = 255;
				}
				if (o.debugging)
					log_write(LOG_STDOUT, "The first host is %d, and the last one is %d\n", start, end);
				if (start < 0 || start > end)
					fatal("Your host specifications are illegal!");
				for (k = start; k <= end; k++)
					targets->addresses[i][j++] = k;
				addy[i] = s + 1;
			}
			if (*addy[i] == '*') {
				start = 0;
				end = 255;
			} else if (*addy[i] == '-') {
				start = 0;
				if (!addy[i] + 1)
					end = 255;
				else
					end = atoi(addy[i] + 1);
			} else {
				start = end = atoi(addy[i]);
				if ((r = strchr(addy[i], '-')) && *(r + 1))
					end = atoi(r + 1);
				else if (r && !*(r + 1))
					end = 255;
			}
			if (o.debugging)
				log_write(LOG_STDOUT, "The first host is %d, and the last one is %d\n", start, end);
			if (start < 0 || start > end)
				fatal("Your host specifications are illegal!");
			if (j + (end - start) > 255)
				fatal("Your host specifications are illegal!");
			for (k = start; k <= end; k++)
				targets->addresses[i][j++] = k;
			targets->last[i] = j - 1;

		}
	}
	bzero((char *) targets->current, 4);
	targets->nleft = (targets->last[0] + 1) * (targets->last[1] + 1) * (targets->last[2] + 1) * (targets->last[3] + 1);
	free(hostexp);
	return 1;
}
Пример #13
0
/* If there is at least one IP address left in t, one is pulled out and placed
   in sin and then zero is returned and state information in t is updated
   to reflect that the IP was pulled out.  If t is empty, -1 is returned */
int target_struct_get(struct targets *t, struct in_addr *sin)
{
	int octet;

      startover:		/* to hande nmap --resume where I have already
				   scanned many of the IPs */

	if (t->nleft <= 0)
		return -1;

	if (t->maskformat) {
		if (t->currentaddr.s_addr <= t->end.s_addr) {
			sin->s_addr = htonl(t->currentaddr.s_addr++);
		} else {
			error("Bogus target structure passed to target_struct_get");
			t->nleft = 0;
			sin->s_addr = 0;
			return -1;
		}
	} else {
		if (o.debugging > 2) {
			log_write(LOG_STDOUT,
				  "doing %d.%d.%d.%d = %d.%d.%d.%d\n",
				  t->current[0], t->current[1],
				  t->current[2], t->current[3], t->addresses[0][t->current[0]], t->addresses[1][t->current[1]], t->addresses[2][t->current[2]], t->addresses[3][t->current[3]]);
		}
		/* Set the IP to the current value of everything */
		sin->s_addr = htonl(t->addresses[0][t->current[0]] << 24 | t->addresses[1][t->current[1]] << 16 | t->addresses[2][t->current[2]] << 8 | t->addresses[3][t->current[3]]);

		/* Now we nudge up to the next IP */
		for (octet = 3; octet >= 0; octet--) {
			if (t->current[octet] < t->last[octet]) {
				/* OK, this is the column I have room to nudge upwards */
				t->current[octet]++;
				break;
			} else {
				/* This octet is finished so I reset it to the beginning */
				t->current[octet] = 0;
			}
		}
		if (octet == -1) {
			/* It didn't find anything to bump up, I muast have taken the last IP */
			assert(t->nleft == 1);
			/* So I set current to last with the very final octet up one ... */
			/* Note that this may make t->current[3] == 256 */
			t->current[0] = t->last[0];
			t->current[1] = t->last[1];
			t->current[2] = t->last[2];
			t->current[3] = t->last[3] + 1;
		} else {
			assert(t->nleft > 1);	/* There must be at least one more IP left */
		}
	}
	t->nleft--;
	assert(t->nleft >= 0);

	/* If we are resuming from a previous scan, we have already finished
	   scans up to o.resume_ip.  */
	if (o.resume_ip.s_addr) {
		if (o.resume_ip.s_addr == sin->s_addr)
			o.resume_ip.s_addr = 0;	/* So that we will KEEP the next one */
		goto startover;	/* Try again */
	}

	return 1;
}
Пример #14
0
static int lua_on_panic(lua_State *L)
{
    log_write(LOG_ERROR, "%s\n", lua_tostring(L, -1));
    return 0;
}
Пример #15
0
Файл: in.c Проект: zipo/zipo
int in_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) {
    conn_t in = (conn_t) arg;
    s2s_t s2s = (s2s_t) arg;
    struct sockaddr_storage sa;
    int namelen = sizeof(sa), port, nbytes;
    char ipport[INET6_ADDRSTRLEN + 17];

    switch(a) {
        case action_READ:
            log_debug(ZONE, "read action on fd %d", fd->fd);

            ioctl(fd->fd, FIONREAD, &nbytes);
            if(nbytes == 0) {
                sx_kill(in->s);
                return 0;
            }

            return sx_can_read(in->s);

        case action_WRITE:
            log_debug(ZONE, "write action on fd %d", fd->fd);
            return sx_can_write(in->s);

        case action_CLOSE:
            log_debug(ZONE, "close action on fd %d", fd->fd);

            /* !!! logging */
            log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] disconnect, packets: %i", fd->fd, in->ip, in->port, in->packet_count);

            jqueue_push(in->s2s->dead, (void *) in->s, 0);

            /* remove from open streams hash if online, or open connections if not */
            if (in->online)
                xhash_zap(in->s2s->in, in->key);
            else {
                snprintf(ipport, INET6_ADDRSTRLEN + 16, "%s/%d", in->ip, in->port);
                xhash_zap(in->s2s->in_accept, ipport);
            }

            jqueue_push(in->s2s->dead_conn, (void *) in, 0);

            break;

        case action_ACCEPT:
            s2s = (s2s_t) arg;

            log_debug(ZONE, "accept action on fd %d", fd->fd);
            
            getpeername(fd->fd, (struct sockaddr *) &sa, &namelen);
            port = j_inet_getport(&sa);

            log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] incoming connection", fd->fd, (char *) data, port);

            /* new conn */
            in = (conn_t) calloc(1, sizeof(struct conn_st));

            in->s2s = s2s;

            strncpy(in->ip, (char *) data, INET6_ADDRSTRLEN);
            in->port = port;

            in->states = xhash_new(101);
            in->states_time = xhash_new(101);

            in->fd = fd;

            in->init_time = time(NULL);

            in->s = sx_new(s2s->sx_env, in->fd->fd, _in_sx_callback, (void *) in);
            mio_app(m, in->fd, in_mio_callback, (void *) in);

            if(s2s->stanza_size_limit != 0)
                in->s->rbytesmax = s2s->stanza_size_limit;

            /* add to incoming connections hash */
            snprintf(ipport, INET6_ADDRSTRLEN + 16, "%s/%d", in->ip, in->port);
            xhash_put(s2s->in_accept, pstrdup(xhash_pool(s2s->in_accept),ipport), (void *) in);

#ifdef HAVE_SSL
            sx_server_init(in->s, S2S_DB_HEADER | ((s2s->sx_ssl != NULL) ? SX_SSL_STARTTLS_OFFER : 0) );
#else
            sx_server_init(in->s, S2S_DB_HEADER);
#endif
            break;
    }

    return 0;
}
Пример #16
0
/** Run engine event loop.
 * @param[in] gen Lists of generators of various types.
 */
static void
engine_loop(struct Generators* gen)
{
  int events_count;
  struct kevent *evt;
  struct Socket* sock;
  struct timespec wait;
  int i;
  int errcode;
  socklen_t codesize;

  if ((events_count = feature_int(FEAT_POLLS_PER_LOOP)) < 20)
    events_count = 20;
  events = (struct kevent *)MyMalloc(sizeof(struct kevent) * events_count);

  while (running) {
    if ((i = feature_int(FEAT_POLLS_PER_LOOP)) >= 20 && i != events_count) {
      events = (struct kevent *)MyRealloc(events, sizeof(struct kevent) * i);
      events_count = i;
    }

    /* set up the sleep time */
    wait.tv_sec = timer_next(gen) ? (timer_next(gen) - CurrentTime) : -1;
    wait.tv_nsec = 0;

    Debug((DEBUG_ENGINE, "kqueue: delay: %Tu (%Tu) %Tu", timer_next(gen),
	   CurrentTime, wait.tv_sec));

    /* check for active events */
    events_used = kevent(kqueue_id, 0, 0, events, events_count,
                         wait.tv_sec < 0 ? 0 : &wait);

    CurrentTime = time(0); /* set current time... */

    if (events_used < 0) {
      if (errno != EINTR) { /* ignore kevent interrupts */
	/* Log the kqueue error */
	log_write(LS_SOCKET, L_ERROR, 0, "kevent() error: %m");
	if (!errors++)
	  timer_add(timer_init(&clear_error), error_clear, 0, TT_PERIODIC,
		    ERROR_EXPIRE_TIME);
	else if (errors > KQUEUE_ERROR_THRESHOLD) /* too many errors... */
	  server_restart("too many kevent errors");
      }
      /* old code did a sleep(1) here; with usage these days,
       * that may be too expensive
       */
      continue;
    }

    while (events_used > 0) {
      evt = &events[--events_used];

      if (evt->filter == EVFILT_SIGNAL) {
	/* it's a signal; deal appropriately */
	event_generate(ET_SIGNAL, evt->udata, evt->ident);
	continue; /* skip socket processing loop */
      }

      assert(evt->filter == EVFILT_READ || evt->filter == EVFILT_WRITE);

      sock = sockList[evt->ident];
      if (!sock) /* slots may become empty while processing events */
	continue;

      assert(s_fd(sock) == evt->ident);

      gen_ref_inc(sock); /* can't have it going away on us */

      Debug((DEBUG_ENGINE, "kqueue: Checking socket %p (fd %d) state %s, "
	     "events %s", sock, s_fd(sock), state_to_name(s_state(sock)),
	     sock_flags(s_events(sock))));

      if (s_state(sock) != SS_NOTSOCK) {
	errcode = 0; /* check for errors on socket */
	codesize = sizeof(errcode);
	if (getsockopt(s_fd(sock), SOL_SOCKET, SO_ERROR, &errcode,
		       &codesize) < 0)
	  errcode = errno; /* work around Solaris implementation */

	if (errcode) { /* an error occurred; generate an event */
	  Debug((DEBUG_ENGINE, "kqueue: Error %d on fd %d, socket %p", errcode,
		 s_fd(sock), sock));
	  event_generate(ET_ERROR, sock, errcode);
	  gen_ref_dec(sock); /* careful not to leak reference counts */
	  continue;
	}
      }

      switch (s_state(sock)) {
      case SS_CONNECTING:
	if (evt->filter == EVFILT_WRITE) { /* connection completed */
	  Debug((DEBUG_ENGINE, "kqueue: Connection completed"));
	  event_generate(ET_CONNECT, sock, 0);
	}
	break;

      case SS_LISTENING:
	if (evt->filter == EVFILT_READ) { /* connect. to be accept. */
	  Debug((DEBUG_ENGINE, "kqueue: Ready for accept"));
	  event_generate(ET_ACCEPT, sock, 0);
	}
	break;

      case SS_NOTSOCK: /* doing nothing socket-specific */
      case SS_CONNECTED:
	if (evt->filter == EVFILT_READ) { /* data on socket */
	  Debug((DEBUG_ENGINE, "kqueue: EOF or data to be read"));
	  event_generate(evt->flags & EV_EOF ? ET_EOF : ET_READ, sock, 0);
	}
	if (evt->filter == EVFILT_WRITE) { /* socket writable */
	  Debug((DEBUG_ENGINE, "kqueue: Data can be written"));
	  event_generate(ET_WRITE, sock, 0);
	}
	break;

      case SS_DATAGRAM: case SS_CONNECTDG:
	if (evt->filter == EVFILT_READ) { /* socket readable */
	  Debug((DEBUG_ENGINE, "kqueue: Datagram to be read"));
	  event_generate(ET_READ, sock, 0);
	}
	if (evt->filter == EVFILT_WRITE) { /* socket writable */
	  Debug((DEBUG_ENGINE, "kqueue: Datagram can be written"));
	  event_generate(ET_WRITE, sock, 0);
	}
	break;
      }

      gen_ref_dec(sock); /* we're done with it */
    }

    timer_run(); /* execute any pending timers */
  }
}
Пример #17
0
void net_print(const char *str)
{
   log_write(NULL, 0, str, strlen(str));
}
Пример #18
0
Файл: dcc.c Проект: Exim/exim
int
dcc_process(uschar **listptr)
{
  int sep = 0;
  const uschar *list = *listptr;
  FILE *data_file;
  uschar *dcc_default_ip_option = US"127.0.0.1";
  uschar *dcc_helo_option = US"localhost";
  uschar *dcc_reject_message = US"Rejected by DCC";
  uschar *xtra_hdrs = NULL;
  uschar *override_client_ip  = NULL;

  /* from local_scan */
  int i, j, k, c, retval, sockfd, resp, line;
  unsigned int portnr;
  struct sockaddr_un  serv_addr;
  struct sockaddr_in  serv_addr_in;
  struct hostent *ipaddress;
  uschar sockpath[128];
  uschar sockip[40], client_ip[40];
  uschar opts[128];
  uschar rcpt[128], from[128];
  uschar sendbuf[4096];
  uschar recvbuf[4096];
  uschar dcc_return_text[1024];
  uschar message_subdir[2];
  struct header_line *dcchdr;
  uschar *dcc_acl_options;
  uschar dcc_acl_options_buffer[10];
  uschar dcc_xtra_hdrs[1024];

  /* grep 1st option */
  if ((dcc_acl_options = string_nextinlist(&list, &sep,
		   dcc_acl_options_buffer, sizeof(dcc_acl_options_buffer))))
    {
    /* parse 1st option */
    if (  strcmpic(dcc_acl_options, US"false") == 0
       || Ustrcmp(dcc_acl_options, "0") == 0
       )
      return FAIL;	/* explicitly no matching */
    }
  else
    return FAIL;	/* empty means "don't match anything" */

  sep = 0;

  /* if we scanned this message last time, just return */
  if (dcc_ok)
    return dcc_rc;

  /* open the spooled body */
  message_subdir[1] = '\0';
  for (i = 0; i < 2; i++)
    {
    message_subdir[0] = split_spool_directory == (i == 0) ? message_id[5] : 0;

    if ((data_file = Ufopen(
	    spool_fname(US"input", message_subdir, message_id, US"-D"),
	    "rb")))
      break;
    }

  if (!data_file)
    {
    /* error while spooling */
    log_write(0, LOG_MAIN|LOG_PANIC,
           "dcc acl condition: error while opening spool file");
    return DEFER;
    }

  /* Initialize the variables */

  bzero(sockip,sizeof(sockip));
  if (dccifd_address) {
    if (dccifd_address[0] == '/')
      Ustrncpy(sockpath, dccifd_address, sizeof(sockpath));
    else
      if( sscanf(CS dccifd_address, "%s %u", sockip, &portnr) != 2) {
        log_write(0, LOG_MAIN,
          "dcc acl condition: warning - invalid dccifd address: '%s'", dccifd_address);
        (void)fclose(data_file);
        return DEFER;
      }
  }

  /* opts is what we send as dccifd options - see man dccifd */
  /* We don't support any other option than 'header' so just copy that */
  bzero(opts,sizeof(opts));
  Ustrncpy(opts, dccifd_options, sizeof(opts)-1);
  /* if $acl_m_dcc_override_client_ip is set use it */
  if (((override_client_ip = expand_string(US"$acl_m_dcc_override_client_ip")) != NULL) &&
       (override_client_ip[0] != '\0')) {
    Ustrncpy(client_ip, override_client_ip, sizeof(client_ip)-1);
    DEBUG(D_acl)
      debug_printf("DCC: Client IP (overridden): %s\n", client_ip);
  }
  else if(sender_host_address) {
  /* else if $sender_host_address is available use that? */
    Ustrncpy(client_ip, sender_host_address, sizeof(client_ip)-1);
    DEBUG(D_acl)
      debug_printf("DCC: Client IP (sender_host_address): %s\n", client_ip);
  }
  else {
    /* sender_host_address is NULL which means it comes from localhost */
    Ustrncpy(client_ip, dcc_default_ip_option, sizeof(client_ip)-1);
    DEBUG(D_acl)
      debug_printf("DCC: Client IP (default): %s\n", client_ip);
  }
  /* strncat(opts, my_request, strlen(my_request)); */
  Ustrcat(opts, "\n");
  Ustrncat(opts, client_ip, sizeof(opts)-Ustrlen(opts)-1);
  Ustrncat(opts, "\nHELO ", sizeof(opts)-Ustrlen(opts)-1);
  Ustrncat(opts, dcc_helo_option, sizeof(opts)-Ustrlen(opts)-2);
  Ustrcat(opts, "\n");

  /* initialize the other variables */
  dcchdr = header_list;
  /* we set the default return value to DEFER */
  retval = DEFER;

  bzero(sendbuf,sizeof(sendbuf));
  bzero(dcc_header_str,sizeof(dcc_header_str));
  bzero(rcpt,sizeof(rcpt));
  bzero(from,sizeof(from));

  /* send a null return path as "<>". */
  if (Ustrlen(sender_address) > 0)
    Ustrncpy(from, sender_address, sizeof(from));
  else
    Ustrncpy(from, "<>", sizeof(from));
  Ustrncat(from, "\n", sizeof(from)-Ustrlen(from)-1);

  /**************************************
   * Now creating the socket connection *
   **************************************/

  /* If sockip contains an ip, we use a tcp socket, otherwise a UNIX socket */
  if(Ustrcmp(sockip, "")){
    ipaddress = gethostbyname(CS sockip);
    bzero(CS  &serv_addr_in, sizeof(serv_addr_in));
    serv_addr_in.sin_family = AF_INET;
    bcopy(CS ipaddress->h_addr, CS &serv_addr_in.sin_addr.s_addr, ipaddress->h_length);
    serv_addr_in.sin_port = htons(portnr);
    if ((sockfd = socket(AF_INET, SOCK_STREAM,0)) < 0){
      DEBUG(D_acl)
        debug_printf("DCC: Creating TCP socket connection failed: %s\n", strerror(errno));
      log_write(0,LOG_PANIC,"DCC: Creating TCP socket connection failed: %s\n", strerror(errno));
      /* if we cannot create the socket, defer the mail */
      (void)fclose(data_file);
      return retval;
    }
    /* Now connecting the socket (INET) */
    if (connect(sockfd, (struct sockaddr *)&serv_addr_in, sizeof(serv_addr_in)) < 0){
      DEBUG(D_acl)
        debug_printf("DCC: Connecting to TCP socket failed: %s\n", strerror(errno));
      log_write(0,LOG_PANIC,"DCC: Connecting to TCP socket failed: %s\n", strerror(errno));
      /* if we cannot contact the socket, defer the mail */
      (void)fclose(data_file);
      return retval;
    }
  } else {
    /* connecting to the dccifd UNIX socket */
    bzero(&serv_addr, sizeof(serv_addr));
    serv_addr.sun_family = AF_UNIX;
    Ustrncpy(serv_addr.sun_path, sockpath, sizeof(serv_addr.sun_path));
    if ((sockfd = socket(AF_UNIX, SOCK_STREAM,0)) < 0){
      DEBUG(D_acl)
        debug_printf("DCC: Creating UNIX socket connection failed: %s\n", strerror(errno));
      log_write(0,LOG_PANIC,"DCC: Creating UNIX socket connection failed: %s\n", strerror(errno));
      /* if we cannot create the socket, defer the mail */
      (void)fclose(data_file);
      return retval;
    }
    /* Now connecting the socket (UNIX) */
    if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){
      DEBUG(D_acl)
                            debug_printf("DCC: Connecting to UNIX socket failed: %s\n", strerror(errno));
      log_write(0,LOG_PANIC,"DCC: Connecting to UNIX socket failed: %s\n", strerror(errno));
      /* if we cannot contact the socket, defer the mail */
      (void)fclose(data_file);
      return retval;
    }
  }
  /* the socket is open, now send the options to dccifd*/
  DEBUG(D_acl)
    debug_printf("\nDCC: ---------------------------\nDCC: Socket opened; now sending input\nDCC: -----------------\n");
  /* First, fill in the input buffer */
  Ustrncpy(sendbuf, opts, sizeof(sendbuf));
  Ustrncat(sendbuf, from, sizeof(sendbuf)-Ustrlen(sendbuf)-1);

  DEBUG(D_acl)
  {
    debug_printf("DCC: opts = %s\nDCC: sender = %s\nDCC: rcpt count = %d\n", opts, from, recipients_count);
    debug_printf("DCC: Sending options:\nDCC: ****************************\n");
  }

  /* let's send each of the recipients to dccifd */
  for (i = 0; i < recipients_count; i++){
    DEBUG(D_acl)
      debug_printf("DCC: recipient = %s\n",recipients_list[i].address);
    if(Ustrlen(sendbuf) + Ustrlen(recipients_list[i].address) > sizeof(sendbuf))
    {
      DEBUG(D_acl)
        debug_printf("DCC: Writing buffer: %s\n", sendbuf);
      flushbuffer(sockfd, sendbuf);
      bzero(sendbuf, sizeof(sendbuf));
    }
    Ustrncat(sendbuf, recipients_list[i].address, sizeof(sendbuf)-Ustrlen(sendbuf)-1);
    Ustrncat(sendbuf, "\r\n", sizeof(sendbuf)-Ustrlen(sendbuf)-1);
  }
  /* send a blank line between options and message */
  Ustrncat(sendbuf, "\n", sizeof(sendbuf)-Ustrlen(sendbuf)-1);
  /* Now we send the input buffer */
  DEBUG(D_acl)
    debug_printf("DCC: %s\nDCC: ****************************\n", sendbuf);
  flushbuffer(sockfd, sendbuf);

  /* now send the message */
  /* Clear the input buffer */
  bzero(sendbuf, sizeof(sendbuf));
  /* First send the headers */
  /* Now send the headers */
  DEBUG(D_acl)
    debug_printf("DCC: Sending headers:\nDCC: ****************************\n");
  Ustrncpy(sendbuf, dcchdr->text, sizeof(sendbuf)-2);
  while((dcchdr=dcchdr->next)) {
    if(dcchdr->slen > sizeof(sendbuf)-2) {
      /* The size of the header is bigger than the size of
       * the input buffer, so split it up in smaller parts. */
       flushbuffer(sockfd, sendbuf);
       bzero(sendbuf, sizeof(sendbuf));
       j = 0;
       while(j < dcchdr->slen)
       {
        for(i = 0; i < sizeof(sendbuf)-2; i++) {
          sendbuf[i] = dcchdr->text[j];
          j++;
        }
        flushbuffer(sockfd, sendbuf);
        bzero(sendbuf, sizeof(sendbuf));
       }
    } else if(Ustrlen(sendbuf) + dcchdr->slen > sizeof(sendbuf)-2) {
      flushbuffer(sockfd, sendbuf);
      bzero(sendbuf, sizeof(sendbuf));
      Ustrncpy(sendbuf, dcchdr->text, sizeof(sendbuf)-2);
    } else {
      Ustrncat(sendbuf, dcchdr->text, sizeof(sendbuf)-Ustrlen(sendbuf)-2);
    }
  }

  /* a blank line separates header from body */
  Ustrncat(sendbuf, "\n", sizeof(sendbuf)-Ustrlen(sendbuf)-1);
  flushbuffer(sockfd, sendbuf);
  DEBUG(D_acl)
    debug_printf("\nDCC: ****************************\n%s", sendbuf);

  /* Clear the input buffer */
  bzero(sendbuf, sizeof(sendbuf));

  /* now send the body */
  DEBUG(D_acl)
    debug_printf("DCC: Writing body:\nDCC: ****************************\n");
  (void)fseek(data_file, SPOOL_DATA_START_OFFSET, SEEK_SET);
  while((fread(sendbuf, 1, sizeof(sendbuf)-1, data_file)) > 0) {
    flushbuffer(sockfd, sendbuf);
    bzero(sendbuf, sizeof(sendbuf));
  }
  DEBUG(D_acl)
    debug_printf("\nDCC: ****************************\n");

  /* shutdown() the socket */
  if(shutdown(sockfd, 1) < 0){
    DEBUG(D_acl)
      debug_printf("DCC: Couldn't shutdown socket: %s\n", strerror(errno));
    log_write(0,LOG_MAIN,"DCC: Couldn't shutdown socket: %s\n", strerror(errno));
    /* If there is a problem with the shutdown()
     * defer the mail. */
    (void)fclose(data_file);
    return retval;
  }
  DEBUG(D_acl)
    debug_printf("\nDCC: -------------------------\nDCC: Input sent.\nDCC: -------------------------\n");

    /********************************
   * receiving output from dccifd *
   ********************************/
  DEBUG(D_acl)
    debug_printf("\nDCC: -------------------------------------\nDCC: Now receiving output from server\nDCC: -----------------------------------\n");

  /******************************************************************
   * We should get 3 lines:                                         *
   * 1/ First line is overall result: either 'A' for Accept,        *
   *    'R' for Reject, 'S' for accept Some recipients or           *
   *    'T' for a Temporary error.                                  *
   * 2/ Second line contains the list of Accepted/Rejected          *
   *    recipients in the form AARRA (A = accepted, R = rejected).  *
   * 3/ Third line contains the X-DCC header.                       *
   ******************************************************************/

  line = 1;    /* we start at the first line of the output */
  j = 0;       /* will be used as index for the recipients list */
  k = 0;       /* initializing the index of the X-DCC header: dcc_header_str[k] */

  /* Let's read from the socket until there's nothing left to read */
  bzero(recvbuf, sizeof(recvbuf));
  while((resp = read(sockfd, recvbuf, sizeof(recvbuf)-1)) > 0) {
    /* How much did we get from the socket */
    c = Ustrlen(recvbuf) + 1;
    DEBUG(D_acl)
      debug_printf("DCC: Length of the output buffer is: %d\nDCC: Output buffer is:\nDCC: ------------\nDCC: %s\nDCC: -----------\n", c, recvbuf);

    /* Now let's read each character and see what we've got */
    for(i = 0; i < c; i++) {
      /* First check if we reached the end of the line and
       * then increment the line counter */
      if(recvbuf[i] == '\n') {
        line++;
      }
      else {
        /* The first character of the first line is the
         * overall response. If there's another character
         * on that line it is not correct. */
        if(line == 1) {
          if(i == 0) {
            /* Now get the value and set the
             * return value accordingly */
            if(recvbuf[i] == 'A') {
              DEBUG(D_acl)
                debug_printf("DCC: Overall result = A\treturning OK\n");
              Ustrcpy(dcc_return_text, "Mail accepted by DCC");
              dcc_result = US"A";
              retval = OK;
            }
            else if(recvbuf[i] == 'R') {
              DEBUG(D_acl)
                debug_printf("DCC: Overall result = R\treturning FAIL\n");
              dcc_result = US"R";
              retval = FAIL;
              if(sender_host_name) {
                log_write(0, LOG_MAIN, "H=%s [%s] F=<%s>: rejected by DCC", sender_host_name, sender_host_address, sender_address);
              }
              else {
                log_write(0, LOG_MAIN, "H=[%s] F=<%s>: rejected by DCC", sender_host_address, sender_address);
              }
              Ustrncpy(dcc_return_text, dcc_reject_message, Ustrlen(dcc_reject_message) + 1);
            }
            else if(recvbuf[i] == 'S') {
              DEBUG(D_acl)
                debug_printf("DCC: Overall result  = S\treturning OK\n");
              Ustrcpy(dcc_return_text, "Not all recipients accepted by DCC");
              /* Since we're in an ACL we want a global result
               * so we accept for all */
              dcc_result = US"A";
              retval = OK;
            }
            else if(recvbuf[i] == 'G') {
              DEBUG(D_acl)
                debug_printf("DCC: Overall result  = G\treturning FAIL\n");
              Ustrcpy(dcc_return_text, "Greylisted by DCC");
              dcc_result = US"G";
              retval = FAIL;
            }
            else if(recvbuf[i] == 'T') {
              DEBUG(D_acl)
                debug_printf("DCC: Overall result = T\treturning DEFER\n");
              retval = DEFER;
              log_write(0,LOG_MAIN,"Temporary error with DCC: %s\n", recvbuf);
              Ustrcpy(dcc_return_text, "Temporary error with DCC");
              dcc_result = US"T";
            }
            else {
              DEBUG(D_acl)
                debug_printf("DCC: Overall result = something else\treturning DEFER\n");
              retval = DEFER;
              log_write(0,LOG_MAIN,"Unknown DCC response: %s\n", recvbuf);
              Ustrcpy(dcc_return_text, "Unknown DCC response");
              dcc_result = US"T";
            }
          }
          else {
            /* We're on the first line but not on the first character,
             * there must be something wrong. */
            DEBUG(D_acl) debug_printf("DCC: Line = %d but i = %d != 0"
		"  character is %c - This is wrong!\n", line, i, recvbuf[i]);
            log_write(0,LOG_MAIN,"Wrong header from DCC, output is %s\n", recvbuf);
          }
        }
        else if(line == 2) {
          /* On the second line we get a list of
           * answers for each recipient. We don't care about
           * it because we're in an acl and take the
           * global result. */
        }
        else if(line > 2) {
          /* The third and following lines are the X-DCC header,
           * so we store it in dcc_header_str. */
          /* check if we don't get more than we can handle */
          if(k < sizeof(dcc_header_str)) {
            dcc_header_str[k] = recvbuf[i];
            k++;
          }
          else {
            DEBUG(D_acl) debug_printf("DCC: We got more output than we can store"
		" in the X-DCC header. Truncating at 120 characters.\n");
          }
        }
        else {
          /* Wrong line number. There must be a problem with the output. */
          DEBUG(D_acl)
            debug_printf("DCC: Wrong line number in output. Line number is %d\n", line);
        }
      }
    }
    /* we reinitialize the output buffer before we read again */
    bzero(recvbuf,sizeof(recvbuf));
  }
  /* We have read everything from the socket */

  /* We need to terminate the X-DCC header with a '\n' character. This needs to be k-1
   * since dcc_header_str[k] contains '\0'. */
  dcc_header_str[k-1] = '\n';

  /* Now let's sum up what we've got. */
  DEBUG(D_acl)
    debug_printf("\nDCC: --------------------------\nDCC: Overall result = %d\nDCC: X-DCC header: %sReturn message: %s\nDCC: dcc_result: %s\n", retval, dcc_header_str, dcc_return_text, dcc_result);

  /* We only add the X-DCC header if it starts with X-DCC */
  if(!(Ustrncmp(dcc_header_str, "X-DCC", 5))){
    dcc_header = dcc_header_str;
    if(dcc_direct_add_header) {
      header_add(' ' , "%s", dcc_header_str);
  /* since the MIME ACL already writes the .eml file to disk without DCC Header we've to erase it */
      unspool_mbox();
    }
  }
  else {
    DEBUG(D_acl)
      debug_printf("DCC: Wrong format of the X-DCC header: %s\n", dcc_header_str);
  }

  /* check if we should add additional headers passed in acl_m_dcc_add_header */
  if(dcc_direct_add_header) {
    if (((xtra_hdrs = expand_string(US"$acl_m_dcc_add_header")) != NULL) && (xtra_hdrs[0] != '\0')) {
      Ustrncpy(dcc_xtra_hdrs, xtra_hdrs, sizeof(dcc_xtra_hdrs) - 2);
      if (dcc_xtra_hdrs[Ustrlen(dcc_xtra_hdrs)-1] != '\n')
        Ustrcat(dcc_xtra_hdrs, "\n");
      header_add(' ', "%s", dcc_xtra_hdrs);
      DEBUG(D_acl)
        debug_printf("DCC: adding additional headers in $acl_m_dcc_add_header: %s", dcc_xtra_hdrs);
    }
  }

  dcc_ok = 1;
  /* Now return to exim main process */
  DEBUG(D_acl)
    debug_printf("DCC: Before returning to exim main process:\nDCC: return_text = %s - retval = %d\nDCC: dcc_result = %s\n", dcc_return_text, retval, dcc_result);

  (void)fclose(data_file);
  dcc_rc = retval;
  return dcc_rc;
}
Пример #19
0
int redirect_router_entry(
  router_instance *rblock,        /* data for this instantiation */
  address_item *addr,             /* address we are working on */
  struct passwd *pw,              /* passwd entry after check_local_user */
  int verify,                     /* v_none/v_recipient/v_sender/v_expn */
  address_item **addr_local,      /* add it to this if it's local */
  address_item **addr_remote,     /* add it to this if it's remote */
  address_item **addr_new,        /* put new addresses on here */
  address_item **addr_succeed)    /* put old address here on success */
{
redirect_router_options_block *ob =
  (redirect_router_options_block *)(rblock->options_block);
address_item *generated = NULL;
const uschar *save_qualify_domain_recipient = qualify_domain_recipient;
uschar *discarded = US"discarded";
address_item_propagated addr_prop;
error_block *eblock = NULL;
ugid_block ugid;
redirect_block redirect;
int filtertype = FILTER_UNSET;
int yield = OK;
int options = ob->bit_options;
int frc = 0;
int xrc = 0;

addr_local = addr_local;     /* Keep picky compilers happy */
addr_remote = addr_remote;

/* Initialize the data to be propagated to the children */

addr_prop.address_data = deliver_address_data;
addr_prop.domain_data = deliver_domain_data;
addr_prop.localpart_data = deliver_localpart_data;
addr_prop.errors_address = NULL;
addr_prop.extra_headers = NULL;
addr_prop.remove_headers = NULL;

#ifdef EXPERIMENTAL_SRS
addr_prop.srs_sender = NULL;
#endif

/* When verifying and testing addresses, the "logwrite" command in filters
must be bypassed. */

if (verify == v_none && !address_test_mode) options |= RDO_REALLOG;

/* Sort out the fixed or dynamic uid/gid. This uid is used (a) for reading the
file (and interpreting a filter) and (b) for running the transports for
generated file and pipe addresses. It is not (necessarily) the same as the uids
that may own the file. Exim panics if an expanded string is not a number and
can't be found in the password file. Other errors set the freezing bit. */

if (!rf_get_ugid(rblock, addr, &ugid)) return DEFER;

if (!ugid.uid_set && pw != NULL)
  {
  ugid.uid = pw->pw_uid;
  ugid.uid_set = TRUE;
  }

if (!ugid.gid_set && pw != NULL)
  {
  ugid.gid = pw->pw_gid;
  ugid.gid_set = TRUE;
  }

#ifdef EXPERIMENTAL_SRS
  /* Perform SRS on recipient/return-path as required  */

  if(ob->srs != NULL)
  {
    BOOL usesrs = TRUE;

    if(ob->srs_condition != NULL)
      usesrs = expand_check_condition(ob->srs_condition, "srs_condition expansion failed", NULL);

    if(usesrs)
    {
      int srs_action = 0, n_srs;
      uschar *res;
      uschar *usedomain;

      /* What are we doing? */
      if(Ustrcmp(ob->srs, "forward") == 0)
        srs_action = 1;
      else if(Ustrcmp(ob->srs, "reverseandforward") == 0)
      {
        srs_action = 3;

        if((ob->srs_dbinsert == NULL) ^ (ob->srs_dbselect == NULL))
          return DEFER;
      }
      else if(Ustrcmp(ob->srs, "reverse") == 0)
        srs_action = 2;

      /* Reverse SRS */
      if(srs_action & 2)
      {
        srs_orig_recipient = addr->address;

        eximsrs_init();
        if(ob->srs_dbselect)
          eximsrs_db_set(TRUE, ob->srs_dbselect);
/* Comment this out for now...
//        else
//          eximsrs_db_set(TRUE, NULL);
*/

        if((n_srs = eximsrs_reverse(&res, addr->address)) == OK)
        {
          srs_recipient = res;
          DEBUG(D_any)
            debug_printf("SRS (reverse): Recipient '%s' rewritten to '%s'\n", srs_orig_recipient, srs_recipient);
        }

        eximsrs_done();

        if(n_srs != OK)
          return n_srs;
      }

      /* Forward SRS */
      /* No point in actually performing SRS if we are just verifying a recipient */
      if((srs_action & 1) && verify == v_none &&
         (sender_address ? sender_address[0] != 0 : FALSE))
      {

        srs_orig_sender = sender_address;
        eximsrs_init();
        if(ob->srs_dbinsert)
          eximsrs_db_set(FALSE, ob->srs_dbinsert);
/* Comment this out for now...
//        else
//          eximsrs_db_set(FALSE, NULL);
*/

        if(ob->srs_alias != NULL ? (usedomain = expand_string(ob->srs_alias)) == NULL : 1)
          usedomain = deliver_domain;

        if((n_srs = eximsrs_forward(&res, sender_address, usedomain)) == OK)
        {
          addr_prop.srs_sender = res;
          DEBUG(D_any)
            debug_printf("SRS (forward): Sender '%s' rewritten to '%s'\n", srs_orig_sender, res);
        }

        eximsrs_done();

        if(n_srs != OK)
          return n_srs;
      }
    }
  }
#endif

/* Call the function that interprets redirection data, either inline or from a
file. This is a separate function so that the system filter can use it. It will
run the function in a subprocess if necessary. If qualify_preserve_domain is
set, temporarily reset qualify_domain_recipient to the current domain so that
any unqualified addresses get qualified with the same domain as the incoming
address. Otherwise, if a local qualify_domain is provided, set that up. */

if (ob->qualify_preserve_domain)
  qualify_domain_recipient = addr->domain;
else if (ob->qualify_domain != NULL)
  {
  uschar *new_qdr = rf_expand_data(addr, ob->qualify_domain, &xrc);
  if (new_qdr == NULL) return xrc;
  qualify_domain_recipient = new_qdr;
  }

redirect.owners = ob->owners;
redirect.owngroups = ob->owngroups;
redirect.modemask = ob->modemask;
redirect.check_owner = ob->check_owner;
redirect.check_group = ob->check_group;
redirect.pw = pw;

if (ob->file != NULL)
  {
  redirect.string = ob->file;
  redirect.isfile = TRUE;
  }
else
  {
  redirect.string = ob->data;
  redirect.isfile = FALSE;
  }

frc = rda_interpret(&redirect, options, ob->include_directory,
  ob->sieve_vacation_directory, ob->sieve_enotify_mailto_owner,
  ob->sieve_useraddress, ob->sieve_subaddress, &ugid, &generated,
  &(addr->message), ob->skip_syntax_errors? &eblock : NULL, &filtertype,
  string_sprintf("%s router (recipient is %s)", rblock->name, addr->address));

qualify_domain_recipient = save_qualify_domain_recipient;

/* Handle exceptional returns from filtering or processing an address list.
For FAIL and FREEZE we honour any previously set up deliveries by a filter. */

switch (frc)
  {
  case FF_NONEXIST:
  addr->message = addr->user_message = NULL;
  return DECLINE;

  case FF_BLACKHOLE:
  DEBUG(D_route) debug_printf("address :blackhole:d\n");
  generated = NULL;
  discarded = US":blackhole:";
  frc = FF_DELIVERED;
  break;

  /* FF_DEFER and FF_FAIL can arise only as a result of explicit commands
  (:defer: or :fail: in an alias file or "fail" in a filter). If a configured
  message was supplied, allow it to be included in an SMTP response after
  verifying. Remove any SMTP code if it is not allowed. */

  case FF_DEFER:
  yield = DEFER;
  goto SORT_MESSAGE;

  case FF_FAIL:
  if ((xrc = sort_errors_and_headers(rblock, addr, verify, &addr_prop)) != OK)
    return xrc;
  add_generated(rblock, addr_new, addr, generated, &addr_prop, &ugid, pw);
  yield = FAIL;

  SORT_MESSAGE:
  if (addr->message == NULL)
    addr->message = (yield == FAIL)? US"forced rejection" : US"forced defer";
  else
    {
    int ovector[3];
    if (ob->forbid_smtp_code &&
        pcre_exec(regex_smtp_code, NULL, CS addr->message,
          Ustrlen(addr->message), 0, PCRE_EOPT,
          ovector, sizeof(ovector)/sizeof(int)) >= 0)
      {
      DEBUG(D_route) debug_printf("SMTP code at start of error message "
        "is ignored because forbid_smtp_code is set\n");
      addr->message += ovector[1];
      }
    addr->user_message = addr->message;
    setflag(addr, af_pass_message);
    }
  return yield;

  /* As in the case of a system filter, a freeze does not happen after a manual
  thaw. In case deliveries were set up by the filter, we set the child count
  high so that their completion does not mark the original address done. */

  case FF_FREEZE:
  if (!deliver_manual_thaw)
    {
    if ((xrc = sort_errors_and_headers(rblock, addr, verify, &addr_prop))
      != OK) return xrc;
    add_generated(rblock, addr_new, addr, generated, &addr_prop, &ugid, pw);
    if (addr->message == NULL) addr->message = US"frozen by filter";
    addr->special_action = SPECIAL_FREEZE;
    addr->child_count = 9999;
    return DEFER;
    }
  frc = FF_NOTDELIVERED;
  break;

  /* Handle syntax errors and :include: failures and lookup defers */

  case FF_ERROR:
  case FF_INCLUDEFAIL:

  /* If filtertype is still FILTER_UNSET, it means that the redirection data
  was never inspected, so the error was an expansion failure or failure to open
  the file, or whatever. In these cases, the existing error message is probably
  sufficient. */

  if (filtertype == FILTER_UNSET) return DEFER;

  /* If it was a filter and skip_syntax_errors is set, we want to set up
  the error message so that it can be logged and mailed to somebody. */

  if (filtertype != FILTER_FORWARD && ob->skip_syntax_errors)
    {
    eblock = store_get(sizeof(error_block));
    eblock->next = NULL;
    eblock->text1 = addr->message;
    eblock->text2 = NULL;
    addr->message = addr->user_message = NULL;
    }

  /* Otherwise set up the error for the address and defer. */

  else
    {
    addr->basic_errno = ERRNO_BADREDIRECT;
    addr->message = string_sprintf("error in %s %s: %s",
      (filtertype != FILTER_FORWARD)? "filter" : "redirect",
      (ob->data == NULL)? "file" : "data",
      addr->message);
    return DEFER;
    }
  }


/* Yield is either FF_DELIVERED (significant action) or FF_NOTDELIVERED (no
significant action). Before dealing with these, however, we must handle the
effect of skip_syntax_errors.

If skip_syntax_errors was set and there were syntax errors in an address list,
error messages will be present in eblock. Log them and send a message if so
configured. We cannot do this earlier, because the error message must not be
sent as the local user. If there were no valid addresses, generated will be
NULL. In this case, the router declines.

For a filter file, the error message has been fudged into an eblock. After
dealing with it, the router declines. */

if (eblock != NULL)
  {
  if (!moan_skipped_syntax_errors(
        rblock->name,                            /* For message content */
        eblock,                                  /* Ditto */
        (verify != v_none || address_test_mode)?
          NULL : ob->syntax_errors_to,           /* Who to mail */
        generated != NULL,                       /* True if not all failed */
        ob->syntax_errors_text))                 /* Custom message */
    return DEFER;

  if (filtertype != FILTER_FORWARD || generated == NULL)
    {
    addr->message = US"syntax error in redirection data";
    return DECLINE;
    }
  }

/* Sort out the errors address and any header modifications, and handle the
generated addresses, if any. If there are no generated addresses, we must avoid
calling sort_errors_and_headers() in case this router declines - that function
may modify the errors_address field in the current address, and we don't want
to do that for a decline. */

if (generated != NULL)
  {
  if ((xrc = sort_errors_and_headers(rblock, addr, verify, &addr_prop)) != OK)
    return xrc;
  add_generated(rblock, addr_new, addr, generated, &addr_prop, &ugid, pw);
  }

/* FF_DELIVERED with no generated addresses is what we get when an address list
contains :blackhole: or a filter contains "seen finish" without having
generated anything. Log what happened to this address, and return DISCARD. */

if (frc == FF_DELIVERED)
  {
  if (generated == NULL && verify == v_none && !address_test_mode)
    {
    log_write(0, LOG_MAIN, "=> %s <%s> R=%s", discarded, addr->address,
      rblock->name);
    yield = DISCARD;
    }
  }

/* For an address list, FF_NOTDELIVERED always means that no addresses were
generated. For a filter, addresses may or may not have been generated. If none
were, it's the same as an empty address list, and the router declines. However,
if addresses were generated, we can't just decline because successful delivery
of the base address gets it marked "done", so deferred generated addresses
never get tried again. We have to generate a new version of the base address,
as if there were a "deliver" command in the filter file, with the original
address as parent. */

else
  {
  address_item *next;

  if (generated == NULL) return DECLINE;

  next = deliver_make_addr(addr->address, FALSE);
  next->parent = addr;
  addr->child_count++;
  next->next = *addr_new;
  *addr_new = next;

  /* Copy relevant flags (af_propagate is a name for the set), and set the
  data that propagates. */

  copyflag(next, addr, af_propagate);
  next->prop = addr_prop;

  DEBUG(D_route) debug_printf("%s router autogenerated %s\n%s%s%s",
    rblock->name,
    next->address,
    (addr_prop.errors_address != NULL)? "  errors to " : "",
    (addr_prop.errors_address != NULL)? addr_prop.errors_address : US"",
    (addr_prop.errors_address != NULL)? "\n" : "");
  }

/* Control gets here only when the address has been completely handled. Put the
original address onto the succeed queue so that any retry items that get
attached to it get processed. */

addr->next = *addr_succeed;
*addr_succeed = addr;

return yield;
}
Пример #20
0
/** our master callback */
int sm_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) {
    sm_t sm = (sm_t) arg;
    sx_buf_t buf = (sx_buf_t) data;
    sx_error_t *sxe;
    nad_t nad;
    pkt_t pkt;
    int len, ns, elem, attr;
    char *domain;

    switch(e) {
        case event_WANT_READ:
            log_debug(ZONE, "want read");
            mio_read(sm->mio, sm->fd);
            break;

        case event_WANT_WRITE:
            log_debug(ZONE, "want write");
            mio_write(sm->mio, sm->fd);
            break;

        case event_READ:
            log_debug(ZONE, "reading from %d", sm->fd->fd);

            /* do the read */
            len = recv(sm->fd->fd, buf->data, buf->len, 0);

            if (len < 0) {
                if (MIO_WOULDBLOCK) {
                    buf->len = 0;
                    return 0;
                }

                log_write(sm->log, LOG_NOTICE, "[%d] [router] read error: %s (%d)", sm->fd->fd, MIO_STRERROR(MIO_ERROR), MIO_ERROR);

                sx_kill(s);
                
                return -1;
            }

            else if (len == 0) {
                /* they went away */
                sx_kill(s);

                return -1;
            }

            log_debug(ZONE, "read %d bytes", len);

            buf->len = len;

            return len;

        case event_WRITE:
            log_debug(ZONE, "writing to %d", sm->fd->fd);

            len = send(sm->fd->fd, buf->data, buf->len, 0);
            if (len >= 0) {
                log_debug(ZONE, "%d bytes written", len);
                return len;
            }

            if (MIO_WOULDBLOCK)
                return 0;

            log_write(sm->log, LOG_NOTICE, "[%d] [router] write error: %s (%d)", sm->fd->fd, MIO_STRERROR(MIO_ERROR), MIO_ERROR);

            sx_kill(s);

            return -1;

        case event_ERROR:
            sxe = (sx_error_t *) data;
            log_write(sm->log, LOG_NOTICE, "error from router: %s (%s)", sxe->generic, sxe->specific);

            if(sxe->code == SX_ERR_AUTH)
                sx_close(s);

            break;

        case event_STREAM:
            break;

        case event_OPEN:
            log_write(sm->log, LOG_NOTICE, "connection to router established");

            /* set connection attempts counter */
            sm->retry_left = sm->retry_lost;

            nad = nad_new();
            ns = nad_add_namespace(nad, uri_COMPONENT, NULL);
            nad_append_elem(nad, ns, "bind", 0);
            nad_append_attr(nad, -1, "name", sm->id);
            log_debug(ZONE, "requesting component bind for '%s'", sm->id);
            sx_nad_write(sm->router, nad);
            
            if(xhash_iter_first(sm->hosts))
            do {
                xhash_iter_get(sm->hosts, (void *) &domain, &len, NULL);

                /* skip already requested SM id */
                if (strlen(sm->id) == len && strncmp(sm->id, domain, len) == 0)
                    continue;

                nad = nad_new();
                ns = nad_add_namespace(nad, uri_COMPONENT, NULL);
                elem = nad_append_elem(nad, ns, "bind", 0);
                nad_set_attr(nad, elem, -1, "name", domain, len);
                nad_append_attr(nad, -1, "multi", "to");
                log_debug(ZONE, "requesting domain bind for '%.*s'", len, domain);
                sx_nad_write(sm->router, nad);
            } while(xhash_iter_next(sm->hosts));
            
            sm_update_host = 1;
            
            break;

        case event_PACKET:
            nad = (nad_t) data;

            /* drop unqualified packets */
            if (NAD_ENS(nad, 0) < 0) {
                nad_free(nad);
                return 0;
            }
            /* watch for the features packet */
            if (s->state == state_STREAM) {
                if (NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_STREAMS)
                    || strncmp(uri_STREAMS, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_STREAMS)) != 0
                    || NAD_ENAME_L(nad, 0) != 8 || strncmp("features", NAD_ENAME(nad, 0), 8) != 0) {
                    log_debug(ZONE, "got a non-features packet on an unauth'd stream, dropping");
                    nad_free(nad);
                    return 0;
                }

#ifdef HAVE_SSL
                /* starttls if we can */
                if (sm->sx_ssl != NULL && s->ssf == 0) {
                    ns = nad_find_scoped_namespace(nad, uri_TLS, NULL);
                    if (ns >= 0) {
                        elem = nad_find_elem(nad, 0, ns, "starttls", 1);
                        if (elem >= 0) {
                            if (sx_ssl_client_starttls(sm->sx_ssl, s, NULL, NULL) == 0) {
                                nad_free(nad);
                                return 0;
                            }
                            log_write(sm->log, LOG_NOTICE, "unable to establish encrypted session with router");
                        }
                    }
                }
#endif

                /* !!! pull the list of mechanisms, and choose the best one.
                 *     if there isn't an appropriate one, error and bail */

                /* authenticate */
                sx_sasl_auth(sm->sx_sasl, s, "jabberd-router", "DIGEST-MD5", sm->router_user, sm->router_pass);

                nad_free(nad);
                return 0;
            }

            /* watch for the bind response */
            if (s->state == state_OPEN && !sm->online) {
                if (NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_COMPONENT)
                    || strncmp(uri_COMPONENT, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_COMPONENT)) != 0
                    || NAD_ENAME_L(nad, 0) != 4 || strncmp("bind", NAD_ENAME(nad, 0), 4)) {
                    log_debug(ZONE, "got a packet from router, but we're not online, dropping");
                    nad_free(nad);
                    return 0;
                }

                /* catch errors */
                attr = nad_find_attr(nad, 0, -1, "error", NULL);
                if(attr >= 0) {
                    log_write(sm->log, LOG_NOTICE, "router refused bind request (%.*s)", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr));
                    exit(1);
                }

                log_debug(ZONE, "coming online");

                /* we're online */
                sm->online = sm->started = 1;
                log_write(sm->log, LOG_NOTICE, "%s ready for sessions", sm->id);

                nad_free(nad);
                return 0;
            }

            log_debug(ZONE, "got a packet");

            pkt = pkt_new(sm, nad);
            if (pkt == NULL) {
                log_debug(ZONE, "invalid packet, dropping");
                return 0;
            }

            /* go */
            dispatch(sm, pkt);

            return 0;

        case event_CLOSED:
            mio_close(sm->mio, sm->fd);
            sm->fd = NULL;
            return -1;
    }

    return 0;
}
Пример #21
0
void region_pack(RegionPtr pregion, int threshold)
{
    int i, num_rects;
    int height, overhead, area1, area2, area3;
    int joins = 0, sum_overhead = 0;
    BoxRec prev_rect, this_rect, tmp_rect;
    RegionRec tmp_region, add_region;

    num_rects = REGION_NUM_RECTS(pregion);

    if (num_rects < 2) {
        return;                     /* nothing to optimize */
    }

    REGION_INIT(&add_region, NullBox, 16);
    prev_rect = REGION_RECTS(pregion)[0];

    for (i = 1; i < num_rects; i++) {
        this_rect = REGION_RECTS(pregion)[i];

        if (this_rect.y1 == prev_rect.y1 && this_rect.y2 == prev_rect.y2) {

            /* Try to join two rectangles of the same "band" */

            if (prev_rect.x2 > this_rect.x1) {
                report_bad_rect_order();
                REGION_UNINIT(&add_region);
                return;
            }
            height = this_rect.y2 - this_rect.y1;
            overhead = (this_rect.x1 - prev_rect.x2) * height;
            if (overhead < threshold) {
                tmp_rect.y1 = prev_rect.y1;
                tmp_rect.y2 = prev_rect.y2;
                tmp_rect.x1 = prev_rect.x2;
                tmp_rect.x2 = this_rect.x1;
                REGION_INIT(&tmp_region, &tmp_rect, 1);
                REGION_UNION(&add_region, &add_region, &tmp_region);
                REGION_UNINIT(&tmp_region);
                joins++;
                sum_overhead += overhead;
            }

        } else {

            /* Try to join two rectangles of neighboring "bands" */

            area1 = (prev_rect.x2 - prev_rect.x1) * (prev_rect.y2 - prev_rect.y1);
            area2 = (this_rect.x2 - this_rect.x1) * (this_rect.y2 - this_rect.y1);
            tmp_rect.x1 = min(prev_rect.x1, this_rect.x1);
            tmp_rect.x2 = max(prev_rect.x2, this_rect.x2);
            tmp_rect.y1 = min(prev_rect.y1, this_rect.y1);
            tmp_rect.y2 = max(prev_rect.y2, this_rect.y2);
            area3 = (tmp_rect.x2 - tmp_rect.x1) * (tmp_rect.y2 - tmp_rect.y1);
            overhead = area3 - area2 - area1;
            if (overhead < threshold || overhead < (area1 + area2) / 100) {
                REGION_INIT(&tmp_region, &tmp_rect, 1);
                REGION_UNION(&add_region, &add_region, &tmp_region);
                REGION_UNINIT(&tmp_region);
                joins++;
                sum_overhead += overhead;
                this_rect = tmp_rect;   /* copy the joined one to prev_rect */
            }

        }

        prev_rect = this_rect;
    }

    if (sum_overhead) {
        REGION_UNION(pregion, pregion, &add_region);
        log_write(LL_DEBUG, "Joined rectangles: %d -> %d, overhead %d",
                  num_rects, (int)(REGION_NUM_RECTS(pregion)), sum_overhead);
    }

    REGION_UNINIT(&add_region);
}
Пример #22
0
Файл: in.c Проект: zipo/zipo
static int _in_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) {
    conn_t in = (conn_t) arg;
    sx_buf_t buf = (sx_buf_t) data;
    int len;
    sx_error_t *sxe;
    nad_t nad;
    char ipport[INET6_ADDRSTRLEN + 17];

    switch(e) {
        case event_WANT_READ:
            log_debug(ZONE, "want read");
            mio_read(in->s2s->mio, in->fd);
            break;

        case event_WANT_WRITE:
            log_debug(ZONE, "want write");
            mio_write(in->s2s->mio, in->fd);
            break;

        case event_READ:
            log_debug(ZONE, "reading from %d", in->fd->fd);

            /* do the read */
            len = recv(in->fd->fd, buf->data, buf->len, 0);

            if(len < 0) {
                if(MIO_WOULDBLOCK) {
                    buf->len = 0;
                    return 0;
                }

                log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] read error: %s (%d)", in->fd->fd, in->ip, in->port, MIO_STRERROR(MIO_ERROR), MIO_ERROR);

                sx_kill(s);
                
                return -1;
            }

            else if(len == 0) {
                /* they went away */
                sx_kill(s);

                return -1;
            }

            log_debug(ZONE, "read %d bytes", len);

            buf->len = len;

            return len;

        case event_WRITE:
            log_debug(ZONE, "writing to %d", in->fd->fd);

            len = send(in->fd->fd, buf->data, buf->len, 0);
            if(len >= 0) {
                log_debug(ZONE, "%d bytes written", len);
                return len;
            }

            if(MIO_WOULDBLOCK)
                return 0;

            log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] write error: %s (%d)", in->fd->fd, in->ip, in->port, MIO_STRERROR(MIO_ERROR), MIO_ERROR);

            sx_kill(s);

            return -1;

        case event_ERROR:
            sxe = (sx_error_t *) data;
            log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] error: %s (%s)", in->fd->fd, in->ip, in->port, sxe->generic, sxe->specific);

            break;

        case event_STREAM:
        case event_OPEN:

            log_debug(ZONE, "STREAM or OPEN event from %s port %d (id %s)", in->ip, in->port, s->id);

            /* first time, bring them online */
            if ((!in->online)||(strcmp(in->key,s->id)!=0)) { 
                log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] incoming stream online (id %s)", in->fd->fd, in->ip, in->port, s->id);

                in->online = 1;

                /* record the id */
                if (in->key != NULL) {
                   log_debug(ZONE,"adding new SSL stream id %s for stream id %s", s->id, in->key);

                   /* remove the initial (non-SSL) stream id from the in connections hash */
                   xhash_zap(in->s2s->in, in->key);
                   free(in->key);
                }

                in->key = strdup(s->id);

                /* track it - add to open streams hash and remove from new connections hash */
                xhash_put(in->s2s->in, in->key, (void *) in);

                snprintf(ipport, INET6_ADDRSTRLEN + 16, "%s/%d", in->ip, in->port);
                xhash_zap(in->s2s->in_accept, ipport);
            }  

            break;

        case event_PACKET:
            /* we're counting packets */
            in->packet_count++;
            in->s2s->packet_count++;

            nad = (nad_t) data;

            /* update last packet timestamp */
            in->last_packet = time(NULL);

            /* dialback packets */
            if(NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_DIALBACK) && strncmp(uri_DIALBACK, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_DIALBACK)) == 0) {
                /* only result and verify mean anything */
                if(NAD_ENAME_L(nad, 0) == 6) {
                    if(strncmp("result", NAD_ENAME(nad, 0), 6) == 0) {
                        _in_result(in, nad);
                        return 0;
                    }

                    if(strncmp("verify", NAD_ENAME(nad, 0), 6) == 0) {
                        _in_verify(in, nad);
                        return 0;
                    }
                }
                
                log_debug(ZONE, "unknown dialback packet, dropping it");

                nad_free(nad);
                return 0;
            }

            /*
             * not dialback, so it has to be a normal-ish jabber packet:
             *  - jabber:client or jabber:server
             *  - message, presence or iq
             *  - has to and from attributes
             */

            if(!(
                 /* must be jabber:client or jabber:server */
                 NAD_ENS(nad, 0) >= 0 &&
                 ((NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_CLIENT) && strncmp(uri_CLIENT, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_CLIENT)) == 0) ||
                 (NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_SERVER) && strncmp(uri_SERVER, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_SERVER)) == 0)) && (
                    /* can be message */
                    (NAD_ENAME_L(nad, 0) == 7 && strncmp("message", NAD_ENAME(nad, 0), 7) == 0) ||
                    /* or presence */
                    (NAD_ENAME_L(nad, 0) == 8 && strncmp("presence", NAD_ENAME(nad, 0), 8) == 0) ||
                    /* or iq */
                    (NAD_ENAME_L(nad, 0) == 2 && strncmp("iq", NAD_ENAME(nad, 0), 2) == 0)
                 ) &&
                 /* to and from required */
                 nad_find_attr(nad, 0, -1, "to", NULL) >= 0 && nad_find_attr(nad, 0, -1, "from", NULL) >= 0
               )) {
                log_debug(ZONE, "they sent us a non-jabber looking packet, dropping it");
                nad_free(nad);
                return 0;
            }

            _in_packet(in, nad);
            return 0;

        case event_CLOSED:
            mio_close(in->s2s->mio, in->fd);
            return -1;
    }

    return 0;
}
Пример #23
0
int network_io_poll()
{
	fd_set read_set;
	fd_set write_set;
	fd_set exception_set;
	int n;
	int max_fd = 0;
	int rv;
	struct timeval tv;

	FD_ZERO(&read_set);
	FD_ZERO(&write_set);
	FD_ZERO(&exception_set);

	// check size
	if( g_maximumFdMap == 0 )
	{
		// just sleep, to simulate the delay
		Sleep(SLEEPSEC * 1000);
		return 0;
	}

	// set the fds
	for( n = 0; n < g_maximumFdMap; ++n )
	{
		if( g_fdMap[n] != NULL )
		{
			FD_SET(g_fdMap[n]->fd, &read_set);
			if( g_fdMap[n]->fd >= max_fd )
				max_fd = g_fdMap[n]->fd + 1;

			if( g_fdMap[n]->outlen > 0 )
				FD_SET(g_fdMap[n]->fd, &write_set);
		}
	}

	// set the timeout
	tv.tv_sec = SLEEPSEC;
	tv.tv_usec = 0;

	// first parameter is ignored apparently in win32?
	rv = select(max_fd, &read_set, &write_set, &exception_set, &tv);

	if( rv < 0 )
	{
		// some error occured.
		log_write(ERROR, "FATAL: select() returned %d", rv);
		return -1;
	}

	// no events
	if( rv == 0 )
		return 0;

	// loop each each socket and handle events on each of them
	for( n = 0; n < g_maximumFdMap; ++n )
	{
		if( g_fdMap[n] != NULL )
		{
			if( FD_ISSET(g_fdMap[n]->fd, &exception_set) )
			{
				if( g_fdMap[n]->event_handler(g_fdMap[n], IOEVENT_ERROR) != 0 )
				{
					network_close(g_fdMap[n]);
					continue;
				}
			}
			else
			{
				if( FD_ISSET(g_fdMap[n]->fd, &read_set) )
				{
					if( g_fdMap[n]->event_handler(g_fdMap[n], IOEVENT_READ) != 0 )
					{
						network_close(g_fdMap[n]);
						continue;
					}
				}
				
				if( FD_ISSET(g_fdMap[n]->fd, &write_set) )
				{
					if( g_fdMap[n]->write_handler(g_fdMap[n], IOEVENT_WRITE) != 0 )
					{
						network_close(g_fdMap[n]);
						continue;
					}
				}
			}
		}
	}
	
	// no errors
	return 0;
}
Пример #24
0
Файл: in.c Проект: zipo/zipo
/** auth requests */
static void _in_result(conn_t in, nad_t nad) {
    int attr, ns;
    jid_t from, to;
    char *rkey;
    nad_t verify;
    pkt_t pkt;
    time_t now;

    attr = nad_find_attr(nad, 0, -1, "from", NULL);
    if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
        log_debug(ZONE, "missing or invalid from on db result packet");
        nad_free(nad);
        return;
    }

    attr = nad_find_attr(nad, 0, -1, "to", NULL);
    if(attr < 0 || (to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
        log_debug(ZONE, "missing or invalid to on db result packet");
        jid_free(from);
        nad_free(nad);
        return;
    }

    rkey = s2s_route_key(NULL, to->domain, from->domain);

    log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] received dialback auth request for route '%s'", in->fd->fd, in->ip, in->port, rkey);

    /* get current state */
    if((conn_state_t) xhash_get(in->states, rkey) == conn_VALID) {
        log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] route '%s' is already valid: sending valid", in->fd->fd, in->ip, in->port, rkey);

        /* its already valid, just reply right now */
        stanza_tofrom(nad, 0);
        nad_set_attr(nad, 0, -1, "type", "valid", 5);
        nad->elems[0].icdata = nad->elems[0].itail = -1;
        nad->elems[0].lcdata = nad->elems[0].ltail = 0;

        sx_nad_write(in->s, nad);

        free(rkey);

        jid_free(from);
        jid_free(to);

        return;
    }

    /* not valid, so we need to verify */

    /* need the key */
    if(NAD_CDATA_L(nad, 0) <= 0) {
        log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] no dialback key given with db result packet", in->fd->fd, in->ip, in->port, rkey);
        free(rkey);
        nad_free(nad);
        jid_free(from);
        jid_free(to);
        return;
    }

    log_debug(ZONE, "requesting verification for route %s", rkey);

    /* set the route status to INPROGRESS and set timestamp */
    xhash_put(in->states, pstrdup(xhash_pool(in->states), rkey), (void *) conn_INPROGRESS);

    /* record the time that we set conn_INPROGRESS state */
    now = time(NULL);
    xhash_put(in->states_time, pstrdup(xhash_pool(in->states_time), rkey), (void *) now);

    free(rkey);

    /* new packet */
    verify = nad_new();
    ns = nad_add_namespace(verify, uri_DIALBACK, "db");

    nad_append_elem(verify, ns, "verify", 0);
    nad_append_attr(verify, -1, "to", from->domain);
    nad_append_attr(verify, -1, "from", to->domain);
    nad_append_attr(verify, -1, "id", in->s->id);
    nad_append_cdata(verify, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0), 1);

    /* new packet */
    pkt = (pkt_t) calloc(1, sizeof(struct pkt_st));

    pkt->nad = verify;

    pkt->to = from;
    pkt->from = to;

    pkt->db = 1;

    /* its away */
    out_packet(in->s2s, pkt);

    nad_free(nad);
}
Пример #25
0
Файл: dns.c Проект: Chaohua/exim
static int
fakens_search(const uschar *domain, int type, uschar *answerptr, int size)
{
int len = Ustrlen(domain);
int asize = size;                  /* Locally modified */
uschar *endname;
uschar name[256];
uschar utilname[256];
uschar *aptr = answerptr;          /* Locally modified */
struct stat statbuf;

/* Remove terminating dot. */

if (domain[len - 1] == '.') len--;
Ustrncpy(name, domain, len);
name[len] = 0;
endname = name + len;

/* This code, for forcing TRY_AGAIN and NO_RECOVERY, is here so that it works
for the old test suite that uses a real nameserver. When the old test suite is
eventually abandoned, this code could be moved into the fakens utility. */

if (len >= 14 && Ustrcmp(endname - 14, "test.again.dns") == 0)
  {
  int delay = Uatoi(name);  /* digits at the start of the name */
  DEBUG(D_dns) debug_printf("Return from DNS lookup of %s (%s) faked for testing\n",
    name, dns_text_type(type));
  if (delay > 0)
    {
    DEBUG(D_dns) debug_printf("delaying %d seconds\n", delay);
    sleep(delay);
    }
  h_errno = TRY_AGAIN;
  return -1;
  }

if (len >= 13 && Ustrcmp(endname - 13, "test.fail.dns") == 0)
  {
  DEBUG(D_dns) debug_printf("Return from DNS lookup of %s (%s) faked for testing\n",
    name, dns_text_type(type));
  h_errno = NO_RECOVERY;
  return -1;
  }

/* Look for the fakens utility, and if it exists, call it. */

(void)string_format(utilname, sizeof(utilname), "%s/../bin/fakens",
  spool_directory);

if (stat(CS utilname, &statbuf) >= 0)
  {
  pid_t pid;
  int infd, outfd, rc;
  uschar *argv[5];

  DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) using fakens\n",
    name, dns_text_type(type));

  argv[0] = utilname;
  argv[1] = spool_directory;
  argv[2] = name;
  argv[3] = dns_text_type(type);
  argv[4] = NULL;

  pid = child_open(argv, NULL, 0000, &infd, &outfd, FALSE);
  if (pid < 0)
    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to run fakens: %s",
      strerror(errno));

  len = 0;
  rc = -1;
  while (asize > 0 && (rc = read(outfd, aptr, asize)) > 0)
    {
    len += rc;
    aptr += rc;       /* Don't modify the actual arguments, because they */
    asize -= rc;      /* may need to be passed on to res_search(). */
    }

  if (rc < 0)
    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "read from fakens failed: %s",
      strerror(errno));

  switch(child_close(pid, 0))
    {
    case 0: return len;
    case 1: h_errno = HOST_NOT_FOUND; return -1;
    case 2: h_errno = TRY_AGAIN; return -1;
    default:
    case 3: h_errno = NO_RECOVERY; return -1;
    case 4: h_errno = NO_DATA; return -1;
    case 5: /* Pass on to res_search() */
    DEBUG(D_dns) debug_printf("fakens returned PASS_ON\n");
    }
  }

/* fakens utility not found, or it returned "pass on" */

DEBUG(D_dns) debug_printf("passing %s on to res_search()\n", domain);

return res_search(CS domain, C_IN, type, answerptr, size);
}
Пример #26
0
Файл: in.c Проект: zipo/zipo
/** validate their key */
static void _in_verify(conn_t in, nad_t nad) {
    int attr;
    jid_t from, to;
    char *id, *dbkey, *type;
    
    attr = nad_find_attr(nad, 0, -1, "from", NULL);
    if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
        log_debug(ZONE, "missing or invalid from on db verify packet");
        nad_free(nad);
        return;
    }

    attr = nad_find_attr(nad, 0, -1, "to", NULL);
    if(attr < 0 || (to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
        log_debug(ZONE, "missing or invalid to on db verify packet");
        jid_free(from);
        nad_free(nad);
        return;
    }

    attr = nad_find_attr(nad, 0, -1, "id", NULL);
    if(attr < 0) {
        log_debug(ZONE, "missing id on db verify packet");
        jid_free(from);
        jid_free(to);
        nad_free(nad);
        return;
    }

    if(NAD_CDATA_L(nad, 0) <= 0) {
        log_debug(ZONE, "no cdata on db verify packet");
        jid_free(from);
        jid_free(to);
        nad_free(nad);
        return;
    }

    /* extract the id */
    id = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, attr) + 1));
    snprintf(id, NAD_AVAL_L(nad, attr) + 1, "%.*s", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr));

    /* generate a dialback key */
    dbkey = s2s_db_key(NULL, in->s2s->local_secret, from->domain, id);

    /* valid */
    if(NAD_CDATA_L(nad, 0) == strlen(dbkey) && strncmp(dbkey, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0)) == 0) {
        log_debug(ZONE, "valid dialback key %s, verify succeeded", dbkey);
        type = "valid";
    } else {
        log_debug(ZONE, "invalid dialback key %s, verify failed", dbkey);
        type = "invalid";
    }

    log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] checking dialback verification from %s: sending %s", in->fd->fd, in->ip, in->port, from->domain, type);

    log_debug(ZONE, "letting them know");

    /* now munge the packet and send it back to them */
    stanza_tofrom(nad, 0);
    nad_set_attr(nad, 0, -1, "type", type, 0);
    nad->elems[0].icdata = nad->elems[0].itail = -1;
    nad->elems[0].lcdata = nad->elems[0].ltail = 0;

    sx_nad_write(in->s, nad);

    free(dbkey);
    free(id);

    jid_free(from);
    jid_free(to);

    return;
}
Пример #27
0
int
dns_lookup(dns_answer *dnsa, const uschar *name, int type,
  const uschar **fully_qualified_name)
{
int i;
const uschar *orig_name = name;
BOOL secure_so_far = TRUE;

/* Loop to follow CNAME chains so far, but no further... */

for (i = 0; i < 10; i++)
  {
  uschar data[256];
  dns_record *rr, cname_rr, type_rr;
  dns_scan dnss;
  int datalen, rc;

  /* DNS lookup failures get passed straight back. */

  if ((rc = dns_basic_lookup(dnsa, name, type)) != DNS_SUCCEED) return rc;

  /* We should have either records of the required type, or a CNAME record,
  or both. We need to know whether both exist for getting the fully qualified
  name, but avoid scanning more than necessary. Note that we must copy the
  contents of any rr blocks returned by dns_next_rr() as they use the same
  area in the dnsa block. */

  cname_rr.data = type_rr.data = NULL;
  for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
       rr;
       rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
    {
    if (rr->type == type)
      {
      if (type_rr.data == NULL) type_rr = *rr;
      if (cname_rr.data != NULL) break;
      }
    else if (rr->type == T_CNAME) cname_rr = *rr;
    }

  /* For the first time round this loop, if a CNAME was found, take the fully
  qualified name from it; otherwise from the first data record, if present. */

  if (i == 0 && fully_qualified_name != NULL)
    {
    uschar * rr_name = cname_rr.data ? cname_rr.name
      : type_rr.data ? type_rr.name : NULL;
    if (  rr_name
       && Ustrcmp(rr_name, *fully_qualified_name) != 0
       && rr_name[0] != '*'
#ifdef EXPERIMENTAL_INTERNATIONAL
       && (  !string_is_utf8(*fully_qualified_name)
	  || Ustrcmp(rr_name,
	       string_domain_utf8_to_alabel(*fully_qualified_name, NULL)) != 0
	  )
#endif
       )
        *fully_qualified_name = string_copy_dnsdomain(rr_name);
    }

  /* If any data records of the correct type were found, we are done. */

  if (type_rr.data != NULL)
    {
    if (!secure_so_far)	/* mark insecure if any element of CNAME chain was */
      dns_set_insecure(dnsa);
    return DNS_SUCCEED;
    }

  /* If there are no data records, we need to re-scan the DNS using the
  domain given in the CNAME record, which should exist (otherwise we should
  have had a failure from dns_lookup). However code against the possibility of
  its not existing. */

  if (cname_rr.data == NULL) return DNS_FAIL;
  datalen = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen,
    cname_rr.data, (DN_EXPAND_ARG4_TYPE)data, sizeof(data));
  if (datalen < 0) return DNS_FAIL;
  name = data;

  if (!dns_is_secure(dnsa))
    secure_so_far = FALSE;

  DEBUG(D_dns) debug_printf("CNAME found: change to %s\n", name);
  }       /* Loop back to do another lookup */

/*Control reaches here after 10 times round the CNAME loop. Something isn't
right... */

log_write(0, LOG_MAIN, "CNAME loop for %s encountered", orig_name);
return DNS_FAIL;
}
Пример #28
0
Файл: in.c Проект: zipo/zipo
/** they're trying to send us something */
static void _in_packet(conn_t in, nad_t nad) {
    int attr, ns, sns;
    jid_t from, to;
    char *rkey;
    
    attr = nad_find_attr(nad, 0, -1, "from", NULL);
    if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
        log_debug(ZONE, "missing or invalid from on incoming packet");
        nad_free(nad);
        return;
    }

    attr = nad_find_attr(nad, 0, -1, "to", NULL);
    if(attr < 0 || (to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
        log_debug(ZONE, "missing or invalid to on incoming packet");
        jid_free(from);
        nad_free(nad);
        return;
    }

    rkey = s2s_route_key(NULL, to->domain, from->domain);

    log_debug(ZONE, "received packet from %s for %s", in->key, rkey);

    /* drop packets received on routes not valid on that connection as per XMPP 8.3.10 */
    if((conn_state_t) xhash_get(in->states, rkey) != conn_VALID) {
        log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] dropping packet on unvalidated route: '%s'", in->fd->fd, in->ip, in->port, rkey);
        free(rkey);
        nad_free(nad);
        jid_free(from);
        jid_free(to);
        return;
    }

    free(rkey);

    /* its good, off to the router with it */

    log_debug(ZONE, "incoming packet on valid route, preparing it for the router");

    /* rewrite server packets into client packets */
    ns = nad_find_namespace(nad, 0, uri_SERVER, NULL);
    if(ns >= 0) {
        if(nad->elems[0].ns == ns)
            nad->elems[0].ns = nad->nss[nad->elems[0].ns].next;
        else {
            for(sns = nad->elems[0].ns; sns >= 0 && nad->nss[sns].next != ns; sns = nad->nss[sns].next);
            nad->nss[sns].next = nad->nss[nad->nss[sns].next].next;
        }
    }

    /*
     * If stanza is not in any namespace (either because we removed the
     * jabber:server namespace above or because it's in the default
     * namespace for this stream) then this packet is intended to be
     * handled by sm (and not just routed through the server), so set the
     * jabber:client namespace.
     */
    if(ns >= 0 || nad->elems[0].ns < 0) {
        ns = nad_add_namespace(nad, uri_CLIENT, NULL);
        nad->scope = -1;
        nad->nss[ns].next = nad->elems[0].ns;
        nad->elems[0].ns = ns;
    }

    nad->elems[0].my_ns = nad->elems[0].ns;

    /* wrap up the packet */
    ns = nad_add_namespace(nad, uri_COMPONENT, "comp");

    nad_wrap_elem(nad, 0, ns, "route");

    nad_set_attr(nad, 0, -1, "to", to->domain, 0);
    nad_set_attr(nad, 0, -1, "from", in->s2s->id, 0);   /* route is from s2s, not packet source */

    log_debug(ZONE, "sending packet to %s", to->domain);

    /* go */
    sx_nad_write(in->s2s->router, nad);

    jid_free(from);
    jid_free(to);
}
Пример #29
0
int login_request(void *module_data, request *client_request)
{
	struct html_ui *html=client_request->answer;
	void *x;
	int retcode=0;

	if(client_request->user==0)
	{
		// Check login data
		char *login_decoded = b64_decode(client_request->module_request, B64_DEFAULT);
		char *delimiter_ptr;

		delimiter_ptr = strstr(login_decoded, "@##@");
		if(delimiter_ptr == NULL)
		{
			log_write("Invalid module data", LOG_DBG);
			goto LOGIN;
		}

		delimiter_ptr[0]=0;
		char *username=login_decoded;
		char *password=delimiter_ptr+4;


		if(check_user_password(module_data, username, password) == 0)
		{
			html_add_tag(&html->main, "<script>", "window.setCookie('login', 'BBBBBBBBBBBBBBBBBBBB');","</script>");
			free(login_decoded);
			return 0;
		}

LOGIN:
		free(login_decoded);
		html_add_tag(&html->main, "<script>", "lw_login_form();","</script>");

		return 0;
	}

	if(login_verify(client_request->user, \
	                client_request->group, client_request->session1, \
	                client_request->session2)!=0) goto ERROR_SERVER;


	//MODULE LIST
	int i;
	void *div=html_add_tag(&html->header, \
	                       "<script>window.lw_ModuleList = {",NULL,
	                       "}; window.lw_show_ModuleList();</script>");

	for(i=0; i<256; i++)
	{
		if(Modules[i].name!=NULL)
		{
			x=split_to_xstring(i,URL_CHARS,6,2);
			html_add_tag(&div, "'", x, "':");

			nfree(x);

			html_add_tag(&div, "'",Modules[i].name, "', ");
		}
	}

	//CALL MODULE
	if(Modules[client_request->module].func!=NULL)
	{
		if(client_request->module==0)
		{
			retcode=user_profile(module_data, client_request);
		}
		else
		{
			retcode=Modules[client_request->module].func(\
			        Modules[client_request->module].data, \
			        client_request);
		}
	}

	//LOGOUT BUTTON
	if(retcode==0)
	{
		html_add_tag(&html->header, \
		             "<script>","window.lw_logout_button();","</script>");
	}
	return retcode;

ERROR_SERVER:
	x=html_flush(&html->base,1);
	nfree(x);
	if(!retcode)html_add_tag(&html->base, HTTP_451, "", "");
	return 2;
}
Пример #30
0
/* Compare a domain with whitelist values.
    The whitelist values may be FQDN or domain only (with no prepended hostname).
    returns 1 on match, 0 on failure to match
*/
int s2s_domain_in_whitelist(s2s_t s2s, char *in_domain) {
    int segcount = 0;
    int dotcount;
    char **segments = NULL;
    char **dst = NULL;
    char *seg_tmp = NULL;    
    int seg_tmp_len;
    char matchstr[MAX_DOMAIN_LEN + 1];
    int domain_index;
    int x, i;
    int wl_index;
    int wl_len;
    int matchstr_len;
    char domain[1024];
    char *domain_ptr = &domain[0];
    int domain_len;

    strncpy(domain, in_domain, sizeof(domain));
    domain[sizeof(domain)-1] = '\0';
    domain_len = strlen((const char *)&domain);

    if (domain_len <= 0) {
        log_write(s2s->log, LOG_NOTICE, "s2s_domain_in_whitelist: in_domain is empty");
        return 0;
    }

    if (domain_len > MAX_DOMAIN_LEN) {
        log_write(s2s->log, LOG_NOTICE, "s2s_domain_in_whitelist: in_domain is longer than %s chars", MAX_DOMAIN_LEN);
        return 0;
    }

    // first try matching the FQDN with whitelist domains
    if (s2s->n_whitelist_domains <= 0)
        return 0;

    for (wl_index =0; wl_index < s2s->n_whitelist_domains; wl_index++) {
        wl_len = strlen(s2s->whitelist_domains[wl_index]);
        if (!strncmp((const char *)&domain, s2s->whitelist_domains[wl_index], (domain_len > wl_len) ? domain_len : wl_len)) {
            log_debug(ZONE, "domain \"%s\" matches whitelist entry", &domain);
            return 1;
        }
        else {
            //log_debug(ZONE, "domain: %s (len %d) does not match whitelist_domains[%d]: %s (len %d)", &domain, strlen((const char *)&domain), wl_index, s2s->whitelist_domains[wl_index], strlen(s2s->whitelist_domains[wl_index]));
        }
    }

    // break domain into segments for domain-only comparision
    for (dotcount = 0, x = 0; domain[x] != '\0'; x++) {
        if (domain[x] == '.')
            dotcount++;
    }
        
    segments = (char **)malloc(sizeof(char*) * (dotcount + 1));
    if (segments == NULL) {
        log_write(s2s->log, LOG_ERR, "s2s_domain_in_whitelist: malloc() error");
        return 0;
    }
    memset((char **)segments, 0, (sizeof(char*) * (dotcount + 1)));

    do {
        if (segcount > (dotcount+1)) {
            log_write(s2s->log, LOG_ERR, "s2s_domain_in_whitelist: did not malloc enough room for domain segments; should never get here");
            if (seg_tmp != NULL) {
                free(seg_tmp);
                seg_tmp = NULL;
            }
            for (x = 0; x < segcount; x++) {
                free(segments[x]);
                segments[x] = NULL;
            }
            free(segments);
            segments = NULL;
            return 0;
        }
        seg_tmp = strsep(&domain_ptr, ".");
        if (seg_tmp == NULL) {
            break;
        }

        seg_tmp_len = strlen(seg_tmp);
        if (seg_tmp_len > MAX_DOMAIN_LEN) {
            log_write(s2s->log, LOG_NOTICE, "s2s_domain_in_whitelist: domain contains a segment greater than %s chars", MAX_DOMAIN_LEN);
            if (seg_tmp != NULL) {
                free(seg_tmp);
                seg_tmp = NULL;
            }
            for (x = 0; x < segcount; x++) {
                free(segments[x]);
                segments[x] = NULL;
            }   
            free(segments);
            segments = NULL;
            return 0;
        }
        dst = &segments[segcount];
        *dst = (char *)malloc(seg_tmp_len + 1);
        if (*dst != NULL) {
            strncpy(*dst, seg_tmp, seg_tmp_len + 1);
            (*dst)[seg_tmp_len] = '\0';
        } else { 
            if (seg_tmp != NULL) {
                free(seg_tmp);
                seg_tmp = NULL;
            }
            for (x = 0; x < segcount; x++) {
                free(segments[x]);
                segments[x] = NULL;
            }   
            free(segments);
            segments = NULL;
            log_write(s2s->log, LOG_ERR, "s2s_domain_in_whitelist: malloc() error");
            return 0;
        }
        segcount++;
    } while (seg_tmp != NULL);

    if (segcount > 1) {
        for (domain_index = segcount-2; domain_index > 0; domain_index--) {
            matchstr[0] = '\0';
            for (i = domain_index; i < segcount; i++) {
                if (i > domain_index) {
                    strncat((char *)&matchstr, ".", sizeof(matchstr));
                    matchstr[sizeof(matchstr)-1] = '\0';
                }
                strncat((char *)&matchstr, (char *)segments[i], sizeof(matchstr)-strlen(matchstr)-1);
                matchstr[sizeof(matchstr)-1] = '\0';
            }
            for (wl_index = 0; wl_index < s2s->n_whitelist_domains; wl_index++) {
                wl_len = strlen(s2s->whitelist_domains[wl_index]);
                matchstr_len = strlen((const char *)&matchstr);
                if (!strncmp((const char *)&matchstr, s2s->whitelist_domains[wl_index], (wl_len > matchstr_len ? wl_len : matchstr_len))) {
                    log_debug(ZONE, "matchstr \"%s\" matches whitelist entry", &matchstr);
                    for (x = 0; x < segcount; x++) {
                        free(segments[x]);
                        segments[x] = NULL;
                    }   
                    free(segments);
                    segments = NULL;
                    return 1;
                } 
                else { 
                    //log_debug(ZONE, "matchstr: %s (len %d) does not match whitelist_domains[%d]: %s (len %d)", &matchstr, strlen((const char *)&matchstr), wl_index, s2s->whitelist_domains[wl_index], strlen(s2s->whitelist_domains[wl_index]));
                }
            }
        }
    }
    for (x = 0; x < segcount; x++) {
        free(segments[x]);
        segments[x] = NULL;
    }   
    free(segments);
    segments = NULL;

    return 0;    
}