Beispiel #1
0
void
route_Add(struct sticky_route **rp, int type, const struct ncprange *dst,
          const struct ncpaddr *gw)
{
  struct sticky_route *r;
  int dsttype = type & ROUTE_DSTANY;

  r = NULL;
  while (*rp) {
    if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) ||
        (!dsttype && ncprange_equal(&(*rp)->dst, dst))) {
      /* Oops, we already have this route - unlink it */
      free(r);			/* impossible really  */
      r = *rp;
      *rp = r->next;
    } else
      rp = &(*rp)->next;
  }

  if (!r)
    r = (struct sticky_route *)malloc(sizeof(struct sticky_route));
  r->type = type;
  r->next = NULL;
  ncprange_copy(&r->dst, dst);
  ncpaddr_copy(&r->gw, gw);
  *rp = r;
}
Beispiel #2
0
void
route_Change(struct bundle *bundle, struct sticky_route *r,
             const struct ncpaddr *me, const struct ncpaddr *peer)
{
  struct ncpaddr dst;

  for (; r; r = r->next) {
    ncprange_getaddr(&r->dst, &dst);
    if (ncpaddr_family(me) == AF_INET) {
      if ((r->type & ROUTE_DSTMYADDR) && !ncpaddr_equal(&dst, me)) {
        rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0);
        ncprange_sethost(&r->dst, me);
        if (r->type & ROUTE_GWHISADDR)
          ncpaddr_copy(&r->gw, peer);
      } else if ((r->type & ROUTE_DSTHISADDR) && !ncpaddr_equal(&dst, peer)) {
        rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0);
        ncprange_sethost(&r->dst, peer);
        if (r->type & ROUTE_GWHISADDR)
          ncpaddr_copy(&r->gw, peer);
      } else if ((r->type & ROUTE_DSTDNS0) && !ncpaddr_equal(&dst, peer)) {
        if (bundle->ncp.ipcp.ns.dns[0].s_addr == INADDR_NONE)
          continue;
        rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0);
        if (r->type & ROUTE_GWHISADDR)
          ncpaddr_copy(&r->gw, peer);
      } else if ((r->type & ROUTE_DSTDNS1) && !ncpaddr_equal(&dst, peer)) {
        if (bundle->ncp.ipcp.ns.dns[1].s_addr == INADDR_NONE)
          continue;
        rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0);
        if (r->type & ROUTE_GWHISADDR)
          ncpaddr_copy(&r->gw, peer);
      } else if ((r->type & ROUTE_GWHISADDR) && !ncpaddr_equal(&r->gw, peer))
        ncpaddr_copy(&r->gw, peer);
#ifndef NOINET6
    } else if (ncpaddr_family(me) == AF_INET6) {
      if ((r->type & ROUTE_DSTMYADDR6) && !ncpaddr_equal(&dst, me)) {
        rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0);
        ncprange_sethost(&r->dst, me);
        if (r->type & ROUTE_GWHISADDR)
          ncpaddr_copy(&r->gw, peer);
      } else if ((r->type & ROUTE_DSTHISADDR6) && !ncpaddr_equal(&dst, peer)) {
        rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0);
        ncprange_sethost(&r->dst, peer);
        if (r->type & ROUTE_GWHISADDR)
          ncpaddr_copy(&r->gw, peer);
      } else if ((r->type & ROUTE_GWHISADDR6) && !ncpaddr_equal(&r->gw, peer))
        ncpaddr_copy(&r->gw, peer);
#endif
    }
    rt_Set(bundle, RTM_ADD, &r->dst, &r->gw, 1, 0);
  }
}
Beispiel #3
0
int
iface_Add(struct iface *iface, struct ncp *ncp, const struct ncprange *ifa,
          const struct ncpaddr *peer, int how)
{
  int af, removed, s;
  unsigned n;
  struct ncpaddr ncplocal;
  struct iface_addr *addr, newaddr;

  af = ncprange_family(ifa);
  if ((s = ID0socket(af, SOCK_DGRAM, 0)) == -1) {
    log_Printf(LogERROR, "iface_Add: socket(): %s\n", strerror(errno));
    return 0;
  }
  ncprange_getaddr(ifa, &ncplocal);

  for (n = 0; n < iface->addrs; n++) {
    if (ncprange_contains(&iface->addr[n].ifa, &ncplocal) ||
        ncpaddr_equal(&iface->addr[n].peer, peer)) {
      /* Replace this sockaddr */
      if (!(how & IFACE_FORCE_ADD)) {
        close(s);
        return 0;	/* errno = EEXIST; */
      }

      if (ncprange_equal(&iface->addr[n].ifa, ifa) &&
          ncpaddr_equal(&iface->addr[n].peer, peer)) {
        close(s);
        ncp_IfaceAddrAdded(ncp, iface->addr + n);
        return 1;	/* Already there */
      }

      removed = iface_addr_Zap(iface->name, iface->addr + n, s);
      if (removed)
        ncp_IfaceAddrDeleted(ncp, iface->addr + n);
      ncprange_copy(&iface->addr[n].ifa, ifa);
      ncpaddr_copy(&iface->addr[n].peer, peer);
      if (!iface_addr_Add(iface->name, iface->addr + n, s)) {
        if (removed) {
          bcopy(iface->addr + n + 1, iface->addr + n,
                (iface->addrs - n - 1) * sizeof *iface->addr);
          iface->addrs--;
          n--;
        }
        close(s);
        return 0;
      }
      close(s);
      ncp_IfaceAddrAdded(ncp, iface->addr + n);
      return 1;
    }
  }

  addr = (struct iface_addr *)realloc
    (iface->addr, (iface->addrs + 1) * sizeof iface->addr[0]);
  if (addr == NULL) {
    log_Printf(LogERROR, "iface_inAdd: realloc: %s\n", strerror(errno));
    close(s);
    return 0;
  }
  iface->addr = addr;

  ncprange_copy(&newaddr.ifa, ifa);
  ncpaddr_copy(&newaddr.peer, peer);
  newaddr.system = !!(how & IFACE_SYSTEM);
  if (!iface_addr_Add(iface->name, &newaddr, s)) {
    close(s);
    return 0;
  }

  if (how & IFACE_ADD_FIRST) {
    /* Stuff it at the start of our list */
    n = 0;
    bcopy(iface->addr, iface->addr + 1, iface->addrs * sizeof *iface->addr);
  } else
    n = iface->addrs;

  iface->addrs++;
  memcpy(iface->addr + n, &newaddr, sizeof(*iface->addr));

  close(s);
  ncp_IfaceAddrAdded(ncp, iface->addr + n);

  return 1;
}
Beispiel #4
0
/*
 * rad_continue_send_request() has given us `got' (non-zero).  Deal with it.
 */
static void
radius_Process(struct radius *r, int got)
{
  char *argv[MAXARGS], *nuke;
  struct bundle *bundle;
  int argc, addrs, res, width;
  size_t len;
  struct ncprange dest;
  struct ncpaddr gw;
  const void *data;
  const char *stype;
  u_int32_t ipaddr, vendor;
  struct in_addr ip;
#ifndef NOINET6
  uint8_t ipv6addr[INET6_ADDRSTRLEN];
  struct in6_addr ip6;
#endif

  r->cx.fd = -1;		/* Stop select()ing */
  stype = r->cx.auth ? "auth" : "acct";

  switch (got) {
    case RAD_ACCESS_ACCEPT:
      log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		 "Radius(%s): ACCEPT received\n", stype);
      if (!r->cx.auth) {
        rad_close(r->cx.rad);
        return;
      }
      break;

    case RAD_ACCESS_REJECT:
      log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		 "Radius(%s): REJECT received\n", stype);
      if (!r->cx.auth) {
        rad_close(r->cx.rad);
        return;
      }
      break;

    case RAD_ACCESS_CHALLENGE:
      /* we can't deal with this (for now) ! */
      log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		 "Radius: CHALLENGE received (can't handle yet)\n");
      if (r->cx.auth)
        auth_Failure(r->cx.auth);
      rad_close(r->cx.rad);
      return;

    case RAD_ACCOUNTING_RESPONSE:
      /*
       * It's probably not ideal to log this at PHASE level as we'll see
       * too much stuff going to the log when ``set rad_alive'' is used.
       * So we differ from older behaviour (ppp version 3.1 and before)
       * and just log accounting responses to LogRADIUS.
       */
      log_Printf(LogRADIUS, "Radius(%s): Accounting response received\n",
		 stype);
      if (r->cx.auth)
        auth_Failure(r->cx.auth);		/* unexpected !!! */

      /* No further processing for accounting requests, please */
      rad_close(r->cx.rad);
      return;

    case -1:
      log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		 "radius(%s): %s\n", stype, rad_strerror(r->cx.rad));
      if (r->cx.auth)
        auth_Failure(r->cx.auth);
      rad_close(r->cx.rad);
      return;

    default:
      log_Printf(LogERROR, "rad_send_request(%s): Failed %d: %s\n", stype,
                 got, rad_strerror(r->cx.rad));
      if (r->cx.auth)
        auth_Failure(r->cx.auth);
      rad_close(r->cx.rad);
      return;
  }

  /* Let's see what we've got in our reply */
  r->ip.s_addr = r->mask.s_addr = INADDR_NONE;
  r->mtu = 0;
  r->vj = 0;
  while ((res = rad_get_attr(r->cx.rad, &data, &len)) > 0) {
    switch (res) {
      case RAD_FRAMED_IP_ADDRESS:
        r->ip = rad_cvt_addr(data);
	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		   " IP %s\n", inet_ntoa(r->ip));
        break;

      case RAD_FILTER_ID:
        free(r->filterid);
        if ((r->filterid = rad_cvt_string(data, len)) == NULL) {
          log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
          auth_Failure(r->cx.auth);
          rad_close(r->cx.rad);
          return;
        }
	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		   " Filter \"%s\"\n", r->filterid);
        break;

      case RAD_SESSION_TIMEOUT:
        r->sessiontime = rad_cvt_int(data);
	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		   " Session-Timeout %lu\n", r->sessiontime);
        break;

      case RAD_FRAMED_IP_NETMASK:
        r->mask = rad_cvt_addr(data);
	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		   " Netmask %s\n", inet_ntoa(r->mask));
        break;

      case RAD_FRAMED_MTU:
        r->mtu = rad_cvt_int(data);
	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		   " MTU %lu\n", r->mtu);
        break;

      case RAD_FRAMED_ROUTING:
        /* Disabled for now - should we automatically set up some filters ? */
        /* rad_cvt_int(data); */
        /* bit 1 = Send routing packets */
        /* bit 2 = Receive routing packets */
        break;

      case RAD_FRAMED_COMPRESSION:
        r->vj = rad_cvt_int(data) == 1 ? 1 : 0;
	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		   " VJ %sabled\n", r->vj ? "en" : "dis");
        break;

      case RAD_FRAMED_ROUTE:
        /*
         * We expect a string of the format ``dest[/bits] gw [metrics]''
         * Any specified metrics are ignored.  MYADDR and HISADDR are
         * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same
         * as ``HISADDR''.
         */

        if ((nuke = rad_cvt_string(data, len)) == NULL) {
          log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
          auth_Failure(r->cx.auth);
          rad_close(r->cx.rad);
          return;
        }

	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		   " Route: %s\n", nuke);
        bundle = r->cx.auth->physical->dl->bundle;
        ip.s_addr = INADDR_ANY;
        ncpaddr_setip4(&gw, ip);
        ncprange_setip4host(&dest, ip);
        argc = command_Interpret(nuke, strlen(nuke), argv);
        if (argc < 0)
          log_Printf(LogWARN, "radius: %s: Syntax error\n",
                     argc == 1 ? argv[0] : "\"\"");
        else if (argc < 2)
          log_Printf(LogWARN, "radius: %s: Invalid route\n",
                     argc == 1 ? argv[0] : "\"\"");
        else if ((strcasecmp(argv[0], "default") != 0 &&
                  !ncprange_aton(&dest, &bundle->ncp, argv[0])) ||
                 !ncpaddr_aton(&gw, &bundle->ncp, argv[1]))
          log_Printf(LogWARN, "radius: %s %s: Invalid route\n",
                     argv[0], argv[1]);
        else {
          ncprange_getwidth(&dest, &width);
          if (width == 32 && strchr(argv[0], '/') == NULL) {
            /* No mask specified - use the natural mask */
            ncprange_getip4addr(&dest, &ip);
            ncprange_setip4mask(&dest, addr2mask(ip));
          }
          addrs = 0;

          if (!strncasecmp(argv[0], "HISADDR", 7))
            addrs = ROUTE_DSTHISADDR;
          else if (!strncasecmp(argv[0], "MYADDR", 6))
            addrs = ROUTE_DSTMYADDR;

          if (ncpaddr_getip4addr(&gw, &ipaddr) && ipaddr == INADDR_ANY) {
            addrs |= ROUTE_GWHISADDR;
            ncpaddr_setip4(&gw, bundle->ncp.ipcp.peer_ip);
          } else if (strcasecmp(argv[1], "HISADDR") == 0)
            addrs |= ROUTE_GWHISADDR;

          route_Add(&r->routes, addrs, &dest, &gw);
        }
        free(nuke);
        break;

      case RAD_REPLY_MESSAGE:
        free(r->repstr);
        if ((r->repstr = rad_cvt_string(data, len)) == NULL) {
          log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
          auth_Failure(r->cx.auth);
          rad_close(r->cx.rad);
          return;
        }
	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		   " Reply-Message \"%s\"\n", r->repstr);
        break;

#ifndef NOINET6
      case RAD_FRAMED_IPV6_PREFIX:
	free(r->ipv6prefix);
	if ((r->ipv6prefix = rad_cvt_ipv6prefix(data, len)) == NULL) {
	  log_Printf(LogERROR, "rad_cvt_ipv6prefix: %s\n",
		     "Malformed attribute in response");
	  auth_Failure(r->cx.auth);
	  rad_close(r->cx.rad);
	  return;
	}
	inet_ntop(AF_INET6, &r->ipv6prefix[2], ipv6addr, sizeof(ipv6addr));
	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		   " IPv6 %s/%d\n", ipv6addr, r->ipv6prefix[1]);
        break;

      case RAD_FRAMED_IPV6_ROUTE:
        /*
         * We expect a string of the format ``dest[/bits] gw [metrics]''
         * Any specified metrics are ignored.  MYADDR6 and HISADDR6 are
         * understood for ``dest'' and ``gw'' and ``::'' is the same
         * as ``HISADDR6''.
         */

        if ((nuke = rad_cvt_string(data, len)) == NULL) {
          log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
          auth_Failure(r->cx.auth);
          rad_close(r->cx.rad);
          return;
        }

	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		   " IPv6 Route: %s\n", nuke);
        bundle = r->cx.auth->physical->dl->bundle;
	ncpaddr_setip6(&gw, &in6addr_any);
	ncprange_set(&dest, &gw, 0);
        argc = command_Interpret(nuke, strlen(nuke), argv);
        if (argc < 0)
          log_Printf(LogWARN, "radius: %s: Syntax error\n",
                     argc == 1 ? argv[0] : "\"\"");
        else if (argc < 2)
          log_Printf(LogWARN, "radius: %s: Invalid route\n",
                     argc == 1 ? argv[0] : "\"\"");
        else if ((strcasecmp(argv[0], "default") != 0 &&
                  !ncprange_aton(&dest, &bundle->ncp, argv[0])) ||
                 !ncpaddr_aton(&gw, &bundle->ncp, argv[1]))
          log_Printf(LogWARN, "radius: %s %s: Invalid route\n",
                     argv[0], argv[1]);
        else {
          addrs = 0;

          if (!strncasecmp(argv[0], "HISADDR6", 8))
            addrs = ROUTE_DSTHISADDR6;
          else if (!strncasecmp(argv[0], "MYADDR6", 7))
            addrs = ROUTE_DSTMYADDR6;

          if (ncpaddr_getip6(&gw, &ip6) && IN6_IS_ADDR_UNSPECIFIED(&ip6)) {
            addrs |= ROUTE_GWHISADDR6;
            ncpaddr_copy(&gw, &bundle->ncp.ipv6cp.hisaddr);
          } else if (strcasecmp(argv[1], "HISADDR6") == 0)
            addrs |= ROUTE_GWHISADDR6;

          route_Add(&r->ipv6routes, addrs, &dest, &gw);
        }
        free(nuke);
        break;
#endif

      case RAD_VENDOR_SPECIFIC:
        if ((res = rad_get_vendor_attr(&vendor, &data, &len)) <= 0) {
          log_Printf(LogERROR, "rad_get_vendor_attr: %s (failing!)\n",
                     rad_strerror(r->cx.rad));
          auth_Failure(r->cx.auth);
          rad_close(r->cx.rad);
          return;
        }

	switch (vendor) {
          case RAD_VENDOR_MICROSOFT:
            switch (res) {
#ifndef NODES
              case RAD_MICROSOFT_MS_CHAP_ERROR:
                free(r->errstr);
                if (len == 0)
                  r->errstr = NULL;
                else {
                  if (len < 3 || ((const char *)data)[1] != '=') {
                    /*
                     * Only point at the String field if we don't think the
                     * peer has misformatted the response.
                     */
                    data = (const char *)data + 1;
                    len--;
                  } else
                    log_Printf(LogWARN, "Warning: The MS-CHAP-Error "
                               "attribute is mis-formatted.  Compensating\n");
                  if ((r->errstr = rad_cvt_string((const char *)data,
                                                  len)) == NULL) {
                    log_Printf(LogERROR, "rad_cvt_string: %s\n",
                               rad_strerror(r->cx.rad));
                    auth_Failure(r->cx.auth);
                    rad_close(r->cx.rad);
                    return;
                  }
		  log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
			     " MS-CHAP-Error \"%s\"\n", r->errstr);
                }
                break;

              case RAD_MICROSOFT_MS_CHAP2_SUCCESS:
                free(r->msrepstr);
                if (len == 0)
                  r->msrepstr = NULL;
                else {
                  if (len < 3 || ((const char *)data)[1] != '=') {
                    /*
                     * Only point at the String field if we don't think the
                     * peer has misformatted the response.
                     */
                    data = (const char *)data + 1;
                    len--;
                  } else
                    log_Printf(LogWARN, "Warning: The MS-CHAP2-Success "
                               "attribute is mis-formatted.  Compensating\n");
                  if ((r->msrepstr = rad_cvt_string((const char *)data,
                                                    len)) == NULL) {
                    log_Printf(LogERROR, "rad_cvt_string: %s\n",
                               rad_strerror(r->cx.rad));
                    auth_Failure(r->cx.auth);
                    rad_close(r->cx.rad);
                    return;
                  }
		  log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
			     " MS-CHAP2-Success \"%s\"\n", r->msrepstr);
                }
                break;

              case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY:
                r->mppe.policy = rad_cvt_int(data);
		log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
			   " MS-MPPE-Encryption-Policy %s\n",
                           radius_policyname(r->mppe.policy));
                break;

              case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES:
                r->mppe.types = rad_cvt_int(data);
		log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
			   " MS-MPPE-Encryption-Types %s\n",
                           radius_typesname(r->mppe.types));
                break;

              case RAD_MICROSOFT_MS_MPPE_RECV_KEY:
                free(r->mppe.recvkey);
		demangle(r, data, len, &r->mppe.recvkey, &r->mppe.recvkeylen);
		log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
			   " MS-MPPE-Recv-Key ********\n");
                break;

              case RAD_MICROSOFT_MS_MPPE_SEND_KEY:
		demangle(r, data, len, &r->mppe.sendkey, &r->mppe.sendkeylen);
		log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
			   " MS-MPPE-Send-Key ********\n");
                break;
#endif

              default:
                log_Printf(LogDEBUG, "Dropping MICROSOFT vendor specific "
                           "RADIUS attribute %d\n", res);
                break;
            }
            break;

          default:
            log_Printf(LogDEBUG, "Dropping vendor %lu RADIUS attribute %d\n",
                       (unsigned long)vendor, res);
            break;
        }
        break;

      default:
        log_Printf(LogDEBUG, "Dropping RADIUS attribute %d\n", res);
        break;
    }
  }

  if (res == -1) {
    log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n",
               rad_strerror(r->cx.rad));
    auth_Failure(r->cx.auth);
  } else if (got == RAD_ACCESS_REJECT)
    auth_Failure(r->cx.auth);
  else {
    r->valid = 1;
    auth_Success(r->cx.auth);
  }
  rad_close(r->cx.rad);
}