Beispiel #1
0
char *
fdevname(int fd)
{
	char	*buf;
	int	error;

	if (thr_main() != 0)
		buf = fdevname_buf;
	else {
		if (thr_once(&fdevname_init_once, fdevname_keycreate) != 0 ||
		    !fdevname_keycreated)
			return (NULL);
		if ((buf = thr_getspecific(fdevname_key)) == NULL) {
			if ((buf = malloc(sizeof fdevname_buf)) == NULL)
				return (NULL);
			if (thr_setspecific(fdevname_key, buf) != 0) {
				free(buf);
				return (NULL);
			}
		}
	}

	if (((error = fdevname_r(fd, buf, sizeof fdevname_buf))) != 0) {
		errno = error;
		return (NULL);
	}
	return (buf);
}
Beispiel #2
0
char *
fdevname(int fd)
{
	static char buf[SPECNAMELEN + 1];

	return (fdevname_r(fd, buf, sizeof(buf)));
}
Beispiel #3
0
int
ttyname_r(int fd, char *buf, size_t len)
{
	size_t used;

	*buf = '\0';

	/* Must be a terminal. */
	if (!isatty(fd))
		return (ENOTTY);
	/* Must have enough room */
	if (len <= sizeof(_PATH_DEV))
		return (ERANGE);

	strcpy(buf, _PATH_DEV);
	used = strlen(buf);
	if (fdevname_r(fd, buf + used, len - used) == NULL)
		return (ENOTTY);
	return (0);
}
Beispiel #4
0
intptr_t os_setup_tun(struct openconnect_info *vpninfo)
{
	static char tun_name[80];
	int unit_nr = 0;
	int tun_fd = -1;

#if defined(__APPLE__) && defined (HAVE_NET_UTUN_H)
	/* OS X (since 10.6) can do this as well as the traditional
	   BSD devices supported via tuntaposx. */
	struct sockaddr_ctl sc;
	struct ctl_info ci;

	if (vpninfo->ifname) {
		char *endp = NULL;

		if (!strncmp(vpninfo->ifname, "tun", 3))
			goto do_bsdtun;

		if (strncmp(vpninfo->ifname, "utun", 4) ||
		    (unit_nr = strtol(vpninfo->ifname + 4, &endp, 10), !endp) ||
		    (unit_nr && vpninfo->ifname[4] == '0') ||
		    *endp) {
			vpn_progress(vpninfo, PRG_ERR,
				     _("Invalid interface name '%s'; must match 'utun%%d' or 'tun%%d'\n"),
				     vpninfo->ifname);
			return -EINVAL;
		}
	}

	tun_fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
	if (tun_fd < 0) {
		vpn_progress(vpninfo, PRG_ERR,
			     _("Failed to open SYSPROTO_CONTROL socket: %s\n"),
			     strerror(errno));
		goto utun_fail;
	}

	snprintf(ci.ctl_name, sizeof(ci.ctl_name), UTUN_CONTROL_NAME);

	if (ioctl(tun_fd, CTLIOCGINFO, &ci) == -1) {
		vpn_progress(vpninfo, PRG_ERR,
			     _("Failed to query utun control id: %s\n"),
			       strerror(errno));
		close(tun_fd);
		goto utun_fail;
	}

	sc.sc_id = ci.ctl_id;
	sc.sc_len = sizeof(sc);
	sc.sc_family = AF_SYSTEM;
	sc.ss_sysaddr = AF_SYS_CONTROL;

	do {
		sc.sc_unit = unit_nr + 1;

		if (!connect(tun_fd, (struct sockaddr * )&sc, sizeof(sc))) {
			if (!vpninfo->ifname &&
			    asprintf(&vpninfo->ifname, "utun%d", unit_nr) == -1) {
				vpn_progress(vpninfo, PRG_ERR,
					     _("Failed to allocate utun device name\n"));
				close(tun_fd);
				goto utun_fail;
			}
			return tun_fd;
		}
		unit_nr++;

	} while (sc.sc_unit < 255 && !vpninfo->ifname);

	vpn_progress(vpninfo, PRG_ERR,
		     _("Failed to connect utun unit: %s\n"),
		     strerror(errno));
	close(tun_fd);

 utun_fail:
	/* If we were explicitly asked for a utun device, fail. Else try tuntaposx */
	if (vpninfo->ifname)
		return -EIO;

	tun_fd = -1;
 do_bsdtun:
#endif /* __APPLE__ && HAVE_NET_UTUN_H */

	if (vpninfo->ifname) {
		char *endp = NULL;
		if (strncmp(vpninfo->ifname, "tun", 3) ||
		    ((void)strtol(vpninfo->ifname + 3, &endp, 10), !endp) ||
		    *endp) {
			vpn_progress(vpninfo, PRG_ERR,
				     _("Invalid interface name '%s'; must match 'tun%%d'\n"),
				     vpninfo->ifname);
			return -EINVAL;
		}
		snprintf(tun_name, sizeof(tun_name),
			 "/dev/%s", vpninfo->ifname);
		tun_fd = bsd_open_tun(tun_name);
		if (tun_fd < 0) {
			int err = errno;
			vpn_progress(vpninfo, PRG_ERR,
				     _("Cannot open '%s': %s\n"),
				     tun_name, strerror(err));
			return -EINVAL;
		}
	}
#ifdef HAVE_FDEVNAME_R
	/* We don't have to iterate over the possible devices; on FreeBSD
	   at least, opening /dev/tun will give us the next available
	   device. */
	if (tun_fd < 0) {
		tun_fd = open("/dev/tun", O_RDWR);
		if (tun_fd >= 0) {
			if (!fdevname_r(tun_fd, tun_name, sizeof(tun_name)) ||
			    strncmp(tun_name, "tun", 3)) {
				close(tun_fd);
				tun_fd = -1;
			} else
				vpninfo->ifname = strdup(tun_name);
		}
	}
#endif
	if (tun_fd < 0) {
		for (unit_nr = 0; unit_nr < 255; unit_nr++) {
			sprintf(tun_name, "/dev/tun%d", unit_nr);
			tun_fd = bsd_open_tun(tun_name);
			if (tun_fd >= 0)
				break;
		}
		if (tun_fd < 0) {
			vpn_progress(vpninfo, PRG_ERR,
				     _("Failed to open tun device: %s\n"),
				     strerror(errno));
			return -EIO;
		}
		vpninfo->ifname = strdup(tun_name + 5);
	}
#ifdef TUNSIFHEAD
	unit_nr = 1;
	if (ioctl(tun_fd, TUNSIFHEAD, &unit_nr) < 0) {
		vpn_perror(vpninfo, _("TUNSIFHEAD"));
		close(tun_fd);
		return -EIO;
	}
#endif

	/* Ancient vpnc-scripts might not get this right */
	set_tun_mtu(vpninfo);

	return tun_fd;
}
Beispiel #5
0
intptr_t os_setup_tun(struct openconnect_info *vpninfo)
{
    int tun_fd = -1;
#ifdef IFF_TUN /* Linux */
    struct ifreq ifr;
    int tunerr;

    tun_fd = open("/dev/net/tun", O_RDWR);
    if (tun_fd < 0) {
        /* Android has /dev/tun instead of /dev/net/tun
           Since other systems might have too, just try it
           as a fallback instead of using ifdef __ANDROID__ */
        tunerr = errno;
        tun_fd = open("/dev/tun", O_RDWR);
    }
    if (tun_fd < 0) {
        /* If the error on /dev/tun is ENOENT, that's boring.
           Use the error we got on /dev/net/tun instead */
        if (errno != ENOENT)
            tunerr = errno;

        vpn_progress(vpninfo, PRG_ERR,
                     _("Failed to open tun device: %s\n"),
                     strerror(tunerr));
        return -EIO;
    }
    memset(&ifr, 0, sizeof(ifr));
    ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
    if (vpninfo->ifname)
        strncpy(ifr.ifr_name, vpninfo->ifname,
                sizeof(ifr.ifr_name) - 1);
    if (ioctl(tun_fd, TUNSETIFF, (void *) &ifr) < 0) {
        vpn_progress(vpninfo, PRG_ERR,
                     _("TUNSETIFF failed: %s\n"),
                     strerror(errno));
        close(tun_fd);
        return -EIO;
    }
    if (!vpninfo->ifname)
        vpninfo->ifname = strdup(ifr.ifr_name);
#elif defined(__sun__)
    static char tun_name[80];
    int unit_nr;

    tun_fd = open("/dev/tun", O_RDWR);
    if (tun_fd < 0) {
        perror(_("open /dev/tun"));
        return -EIO;
    }

    unit_nr = ioctl(tun_fd, TUNNEWPPA, -1);
    if (unit_nr < 0) {
        perror(_("Failed to create new tun"));
        close(tun_fd);
        return -EIO;
    }

    if (ioctl(tun_fd, I_SRDOPT, RMSGD) < 0) {
        perror(_("Failed to put tun file descriptor into message-discard mode"));
        close(tun_fd);
        return -EIO;
    }

    sprintf(tun_name, "tun%d", unit_nr);
    vpninfo->ifname = strdup(tun_name);

    vpninfo->ip_fd = link_proto(unit_nr, "/dev/udp", IFF_IPV4);
    if (vpninfo->ip_fd < 0) {
        close(tun_fd);
        return -EIO;
    }

    if (vpninfo->ip_info.addr6) {
        vpninfo->ip6_fd = link_proto(unit_nr, "/dev/udp6", IFF_IPV6);
        if (vpninfo->ip6_fd < 0) {
            close(tun_fd);
            close(vpninfo->ip_fd);
            vpninfo->ip_fd = -1;
            return -EIO;
        }
    } else
        vpninfo->ip6_fd = -1;

#else /* BSD et al have /dev/tun$x devices */
    static char tun_name[80];
    int i;

    if (vpninfo->ifname) {
        char *endp = NULL;
        if (strncmp(vpninfo->ifname, "tun", 3) ||
                ((void)strtol(vpninfo->ifname + 3, &endp, 10), !endp) ||
                *endp) {
            vpn_progress(vpninfo, PRG_ERR,
                         _("Invalid interface name '%s'; must match 'tun%%d'\n"),
                         vpninfo->ifname);
            return -EINVAL;
        }
        snprintf(tun_name, sizeof(tun_name),
                 "/dev/%s", vpninfo->ifname);
        tun_fd = bsd_open_tun(tun_name);
        if (tun_fd < 0) {
            int err = errno;
            vpn_progress(vpninfo, PRG_ERR,
                         _("Cannot open '%s': %s\n"),
                         tun_name, strerror(err));
            return -EINVAL;
        }
    }
#ifdef HAVE_FDEVNAME_R
    /* We don't have to iterate over the possible devices; on FreeBSD
       at least, opening /dev/tun will give us the next available
       device. */
    if (tun_fd < 0) {
        tun_fd = open("/dev/tun", O_RDWR);
        if (tun_fd >= 0) {
            if (!fdevname_r(tun_fd, tun_name, sizeof(tun_name)) ||
                    strncmp(tun_name, "tun", 3)) {
                close(tun_fd);
                tun_fd = -1;
            } else
                vpninfo->ifname = strdup(tun_name);
        }
    }
#endif
    if (tun_fd < 0) {
        for (i = 0; i < 255; i++) {
            sprintf(tun_name, "/dev/tun%d", i);
            tun_fd = bsd_open_tun(tun_name);
            if (tun_fd >= 0)
                break;
        }
        if (tun_fd < 0) {
            vpn_progress(vpninfo, PRG_ERR,
                         _("Failed to open tun device: %s\n"),
                         strerror(errno));
            return -EIO;
        }
        vpninfo->ifname = strdup(tun_name + 5);
    }
#ifdef TUNSIFHEAD
    i = 1;
    if (ioctl(tun_fd, TUNSIFHEAD, &i) < 0) {
        perror(_("TUNSIFHEAD"));
        close(tun_fd);
        return -EIO;
    }
#endif
#endif /* BSD-style */

    /* Ancient vpnc-scripts might not get this right */
    set_tun_mtu(vpninfo);

    return tun_fd;
}
Beispiel #6
0
int
main(int argc, char *argv[])
{
	struct stat st;
	int ch, rc, errs, am_readlink;
	int lsF, fmtchar, usestat, fn, nonl, quiet;
	const char *statfmt, *options, *synopsis;
	char dname[sizeof _PATH_DEV + SPECNAMELEN] = _PATH_DEV;
	const char *file;

	am_readlink = 0;
	lsF = 0;
	fmtchar = '\0';
	usestat = 0;
	nonl = 0;
	quiet = 0;
	linkfail = 0;
	statfmt = NULL;
	timefmt = NULL;

	if (strcmp(getprogname(), "readlink") == 0) {
		am_readlink = 1;
		options = "fn";
		synopsis = "[-fn] [file ...]";
		statfmt = "%Y";
		fmtchar = 'f';
		quiet = 1;
	} else {
		options = "f:FlLnqrst:x";
		synopsis = "[-FLnq] [-f format | -l | -r | -s | -x] "
		    "[-t timefmt] [file ...]";
	}

	while ((ch = getopt(argc, argv, options)) != -1)
		switch (ch) {
		case 'F':
			lsF = 1;
			break;
		case 'L':
			usestat = 1;
			break;
		case 'n':
			nonl = 1;
			break;
		case 'q':
			quiet = 1;
			break;
		case 'f':
			if (am_readlink) {
				statfmt = "%R";
				break;
			}
			statfmt = optarg;
			/* FALLTHROUGH */
		case 'l':
		case 'r':
		case 's':
		case 'x':
			if (fmtchar != 0)
				errx(1, "can't use format '%c' with '%c'",
				    fmtchar, ch);
			fmtchar = ch;
			break;
		case 't':
			timefmt = optarg;
			break;
		default:
			usage(synopsis);
		}

	argc -= optind;
	argv += optind;
	fn = 1;

	if (fmtchar == '\0') {
		if (lsF)
			fmtchar = 'l';
		else {
			fmtchar = 'f';
			statfmt = DEF_FORMAT;
		}
	}

	if (lsF && fmtchar != 'l')
		errx(1, "can't use format '%c' with -F", fmtchar);

	switch (fmtchar) {
	case 'f':
		/* statfmt already set */
		break;
	case 'l':
		statfmt = lsF ? LSF_FORMAT : LS_FORMAT;
		break;
	case 'r':
		statfmt = RAW_FORMAT;
		break;
	case 's':
		statfmt = SHELL_FORMAT;
		break;
	case 'x':
		statfmt = LINUX_FORMAT;
		if (timefmt == NULL)
			timefmt = "%c";
		break;
	default:
		usage(synopsis);
		/*NOTREACHED*/
	}

	if (timefmt == NULL)
		timefmt = TIME_FORMAT;

	errs = 0;
	do {
		if (argc == 0) {
			if (fdevname_r(STDIN_FILENO, dname +
			    sizeof _PATH_DEV - 1, SPECNAMELEN) != NULL)
				file = dname;
			else
				file = "(stdin)";
			rc = fstat(STDIN_FILENO, &st);
		} else {
			file = argv[0];
			if (usestat) {
				/*
				 * Try stat() and if it fails, fall back to
				 * lstat() just in case we're examining a
				 * broken symlink.
				 */
				if ((rc = stat(file, &st)) == -1 &&
				    errno == ENOENT &&
				    (rc = lstat(file, &st)) == -1)
					errno = ENOENT;
			}
			else
				rc = lstat(file, &st);
		}

		if (rc == -1) {
			errs = 1;
			linkfail = 1;
			if (!quiet)
				warn("%s: stat", file);
		}
		else
			output(&st, file, statfmt, fn, nonl);

		argv++;
		argc--;
		fn++;
	} while (argc > 0);

	return (am_readlink ? linkfail : errs);
}