Beispiel #1
0
/* disable nagle on socket */
void
pamsshagentauth_set_nodelay(int fd)
{
	int opt;
	socklen_t optlen;

	optlen = sizeof opt;
	if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
		pamsshagentauth_verbose("getsockopt TCP_NODELAY: %.100s", strerror(errno));
		return;
	}
	if (opt == 1) {
		pamsshagentauth_verbose("fd %d is TCP_NODELAY", fd);
		return;
	}
	opt = 1;
	pamsshagentauth_verbose("fd %d setting TCP_NODELAY", fd);
	if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1)
		pamsshagentauth_logerror("setsockopt TCP_NODELAY: %.100s", strerror(errno));
}
Beispiel #2
0
/*
 * Returns a standardized host+port identifier string.
 * Caller must free returned string.
 */
char *
pamsshagentauth_put_host_port(const char *host, u_short port)
{
	char *hoststr;

	if (port == 0 || port == SSH_DEFAULT_PORT)
		return(pamsshagentauth_xstrdup(host));
	if (asprintf(&hoststr, "[%s]:%d", host, (int)port) < 0)
		pamsshagentauth_fatal("put_host_port: asprintf: %s", strerror(errno));
	pamsshagentauth_verbose("put_host_port: %s", hoststr);
	return hoststr;
}
Beispiel #3
0
/* set/unset filedescriptor to non-blocking */
int
pamsshagentauth_set_nonblock(int fd)
{
	int val;

	val = fcntl(fd, F_GETFL, 0);
	if (val < 0) {
		pamsshagentauth_logerror("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
		return (-1);
	}
	if (val & O_NONBLOCK) {
		pamsshagentauth_verbose("fd %d is O_NONBLOCK", fd);
		return (0);
	}
	pamsshagentauth_verbose("fd %d setting O_NONBLOCK", fd);
	val |= O_NONBLOCK;
	if (fcntl(fd, F_SETFL, val) == -1) {
		pamsshagentauth_verbose("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd,
		    strerror(errno));
		return (-1);
	}
	return (0);
}
Beispiel #4
0
/*
 * Read an entire line from a public key file into a static buffer, discarding
 * lines that exceed the buffer size.  Returns 0 on success, -1 on failure.
 */
int
read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz,
   u_long *lineno)
{
	while (fgets(buf, bufsz, f) != NULL) {
		if (buf[0] == '\0')
			continue;
		(*lineno)++;
		if (buf[strlen(buf) - 1] == '\n' || feof(f)) {
			return 0;
		} else {
			pamsshagentauth_verbose("%s: %s line %lu exceeds size limit", __func__,
			    filename, *lineno);
			/* discard remainder of line */
			while (fgetc(f) != '\n' && !feof(f))
				;	/* nothing */
		}
	}
	return -1;
}
int
pamsshagentauth_auth_secure_path(const char *name, struct stat *stp,
        const char *pw_dir, uid_t uid, char *err, size_t errlen)
{
	char buf[MAXPATHLEN], homedir[MAXPATHLEN];
	char *cp;
	int comparehome = 0;
	struct stat st;

    pamsshagentauth_verbose("auth_secure_filename: checking for uid: %u", uid);

	if (realpath(name, buf) == NULL) {
		snprintf(err, errlen, "realpath %s failed: %s", name,
		    strerror(errno));
		return -1;
	}
	/* if (realpath(pw->pw_dir, homedir) != NULL) */
    if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
		comparehome = 1;

	/* check the open file to avoid races */
	/* 
     * if (fstat(fileno(f), &st) < 0 ||
	 *    (st.st_uid != 0 && st.st_uid != uid) ||
	 *    (st.st_mode & 022) != 0) {
    */
    if (!S_ISREG(stp->st_mode)) {
        snprintf(err, errlen, "%s is not a regular file", buf);
        return -1;
    }

    if ((stp->st_uid != 0 && stp->st_uid != uid) ||
            (stp->st_mode & 022) != 0) {
		snprintf(err, errlen, "bad ownership or modes for file %s",
		    buf);
		return -1;
	}

	/* for each component of the canonical path, walking upwards */
	for (;;) {
		if ((cp = dirname(buf)) == NULL) {
			snprintf(err, errlen, "dirname() failed");
			return -1;
		}
		pamsshagentauth_strlcpy(buf, cp, sizeof(buf));

		pamsshagentauth_verbose("secure_filename: checking '%s'", buf);
		if (stat(buf, &st) < 0 ||
		    (st.st_uid != 0 && st.st_uid != uid) ||
		    (st.st_mode & 022) != 0) {
			snprintf(err, errlen,
			    "bad ownership or modes for directory %s", buf);
			return -1;
		}

		/* If are passed the homedir then we can stop */
		if (comparehome && strcmp(homedir, buf) == 0) {
			pamsshagentauth_verbose("secure_filename: terminating check at '%s'",
			    buf);
			break;
		}
		/*
		 * dirname should always complete with a "/" path,
		 * but we can be paranoid and check for "." too
		 */
		if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
			break;
	}
	return 0;
}
Beispiel #6
0
/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
int
ssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp,
    const u_char *data, u_int datalen)
{
	const EVP_MD *evp_md;
	EVP_MD_CTX md;
	u_char digest[EVP_MAX_MD_SIZE], *sig;
	u_int slen, dlen, len;
	int ok, nid;
	Buffer b;

	if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) {
		pamsshagentauth_logerror("ssh_rsa_sign: no RSA key");
		return -1;
	}
	nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
	if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
		pamsshagentauth_logerror("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid);
		return -1;
	}
	EVP_DigestInit(&md, evp_md);
	EVP_DigestUpdate(&md, data, datalen);
	EVP_DigestFinal(&md, digest, &dlen);

	slen = RSA_size(key->rsa);
	sig = pamsshagentauth_xmalloc(slen);

	ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa);
	memset(digest, 'd', sizeof(digest));

	if (ok != 1) {
		int ecode = ERR_get_error();

		pamsshagentauth_logerror("ssh_rsa_sign: RSA_sign failed: %s",
		    ERR_error_string(ecode, NULL));
		pamsshagentauth_xfree(sig);
		return -1;
	}
	if (len < slen) {
		u_int diff = slen - len;
		pamsshagentauth_verbose("slen %u > len %u", slen, len);
		memmove(sig + diff, sig, len);
		memset(sig, 0, diff);
	} else if (len > slen) {
		pamsshagentauth_logerror("ssh_rsa_sign: slen %u slen2 %u", slen, len);
		pamsshagentauth_xfree(sig);
		return -1;
	}
	/* encode signature */
	pamsshagentauth_buffer_init(&b);
	pamsshagentauth_buffer_put_cstring(&b, "ssh-rsa");
	pamsshagentauth_buffer_put_string(&b, sig, slen);
	len = pamsshagentauth_buffer_len(&b);
	if (lenp != NULL)
		*lenp = len;
	if (sigp != NULL) {
		*sigp = pamsshagentauth_xmalloc(len);
		memcpy(*sigp, pamsshagentauth_buffer_ptr(&b), len);
	}
	pamsshagentauth_buffer_free(&b);
	memset(sig, 's', slen);
	pamsshagentauth_xfree(sig);

	return 0;
}
Beispiel #7
0
int
ssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen,
    const u_char *data, u_int datalen)
{
	Buffer b;
	const EVP_MD *evp_md;
	EVP_MD_CTX md;
	char *ktype;
	u_char digest[EVP_MAX_MD_SIZE], *sigblob;
	u_int len, dlen, modlen;
	int rlen, ret, nid;

	if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) {
		pamsshagentauth_logerror("ssh_rsa_verify: no RSA key");
		return -1;
	}
	if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
		pamsshagentauth_logerror("ssh_rsa_verify: RSA modulus too small: %d < minimum %d bits",
		    BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE);
		return -1;
	}
	pamsshagentauth_buffer_init(&b);
	pamsshagentauth_buffer_append(&b, signature, signaturelen);
	ktype = pamsshagentauth_buffer_get_string(&b, NULL);
	if (strcmp("ssh-rsa", ktype) != 0) {
		pamsshagentauth_logerror("ssh_rsa_verify: cannot handle type %s", ktype);
		pamsshagentauth_buffer_free(&b);
		pamsshagentauth_xfree(ktype);
		return -1;
	}
	pamsshagentauth_xfree(ktype);
	sigblob = pamsshagentauth_buffer_get_string(&b, &len);
	rlen = pamsshagentauth_buffer_len(&b);
	pamsshagentauth_buffer_free(&b);
	if (rlen != 0) {
		pamsshagentauth_logerror("ssh_rsa_verify: remaining bytes in signature %d", rlen);
		pamsshagentauth_xfree(sigblob);
		return -1;
	}
	/* RSA_verify expects a signature of RSA_size */
	modlen = RSA_size(key->rsa);
	if (len > modlen) {
		pamsshagentauth_logerror("ssh_rsa_verify: len %u > modlen %u", len, modlen);
		pamsshagentauth_xfree(sigblob);
		return -1;
	} else if (len < modlen) {
		u_int diff = modlen - len;
		pamsshagentauth_verbose("ssh_rsa_verify: add padding: modlen %u > len %u",
		    modlen, len);
		sigblob = pamsshagentauth_xrealloc(sigblob, 1, modlen);
		memmove(sigblob + diff, sigblob, len);
		memset(sigblob, 0, diff);
		len = modlen;
	}
	nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
	if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
		pamsshagentauth_logerror("ssh_rsa_verify: EVP_get_digestbynid %d failed", nid);
		pamsshagentauth_xfree(sigblob);
		return -1;
	}
	EVP_DigestInit(&md, evp_md);
	EVP_DigestUpdate(&md, data, datalen);
	EVP_DigestFinal(&md, digest, &dlen);

	ret = openssh_RSA_verify(nid, digest, dlen, sigblob, len, key->rsa);
	memset(digest, 'd', sizeof(digest));
	memset(sigblob, 's', len);
	pamsshagentauth_xfree(sigblob);
	pamsshagentauth_verbose("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : "");
	return ret;
}
/* Modified slightly from original found in auth2-pubkey.c */
int
pam_user_key_allowed2(struct passwd *pw, Key *key, char *file)
{
	char line[SSH_MAX_PUBKEY_BYTES];
	int found_key = 0;
	FILE *f;
	u_long linenum = 0;
	struct stat st;
	Key *found;
	char *fp;

	pamsshagentauth_verbose("trying public key file %s", file);

	/* Fail not so quietly if file does not exist */
	if (stat(file, &st) < 0) {
        pamsshagentauth_verbose("File not found: %s", file);
		return 0;
	}
	/* Open the file containing the authorized keys. */
	f = fopen(file, "r");
	if (!f) {
		return 0;
	}
	if (
	    pamsshagentauth_secure_filename(f, file, pw, line, sizeof(line)) != 0) {
		fclose(f);
		pamsshagentauth_logit("Authentication refused: %s", line);
		return 0;
	}

	found_key = 0;
	found = pamsshagentauth_key_new(key->type);

	while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
		char *cp, *key_options = NULL;

		/* Skip leading whitespace, empty and comment lines. */
		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
			;
		if (!*cp || *cp == '\n' || *cp == '#')
			continue;

		if (pamsshagentauth_key_read(found, &cp) != 1) {
			/* no key?  check if there are options for this key */
			int quoted = 0;
			pamsshagentauth_verbose("user_key_allowed: check options: '%s'", cp);
			key_options = cp;
			for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
				if (*cp == '\\' && cp[1] == '"')
					cp++;	/* Skip both */
				else if (*cp == '"')
					quoted = !quoted;
			}
			/* Skip remaining whitespace. */
			for (; *cp == ' ' || *cp == '\t'; cp++)
				;
			if (pamsshagentauth_key_read(found, &cp) != 1) {
				pamsshagentauth_verbose("user_key_allowed: advance: '%s'", cp);
				/* still no key?  advance to next line*/
				continue;
			}
		}
		if (pamsshagentauth_key_equal(found, key)) {
			found_key = 1;
			pamsshagentauth_logit("matching key found: file %s, line %lu",
			    file, linenum);
			fp = pamsshagentauth_key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
			pamsshagentauth_logit("Found matching %s key: %s",
			    pamsshagentauth_key_type(found), fp);
			pamsshagentauth_xfree(fp);
			break;
		}
	}
	fclose(f);
	pamsshagentauth_key_free(found);
	if (!found_key)
		pamsshagentauth_verbose("key not found");
	return found_key;
}
Beispiel #9
0
int
pamsshagentauth_tun_open(int tun, int mode)
{
#if defined(CUSTOM_SYS_TUN_OPEN)
	return (sys_tun_open(tun, mode));
#elif defined(SSH_TUN_OPENBSD)
	struct ifreq ifr;
	char name[100];
	int fd = -1, sock;

	/* Open the tunnel device */
	if (tun <= SSH_TUNID_MAX) {
		snprintf(name, sizeof(name), "/dev/tun%d", tun);
		fd = open(name, O_RDWR);
	} else if (tun == SSH_TUNID_ANY) {
		for (tun = 100; tun >= 0; tun--) {
			snprintf(name, sizeof(name), "/dev/tun%d", tun);
			if ((fd = open(name, O_RDWR)) >= 0)
				break;
		}
	} else {
		pamsshagentauth_verbose("%s: invalid tunnel %u", __func__, tun);
		return (-1);
	}

	if (fd < 0) {
		pamsshagentauth_verbose("%s: %s open failed: %s", __func__, name, strerror(errno));
		return (-1);
	}

	pamsshagentauth_verbose("%s: %s mode %d fd %d", __func__, name, mode, fd);

	/* Set the tunnel device operation mode */
	snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tun%d", tun);
	if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
		goto failed;

	if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)
		goto failed;

	/* Set interface mode */
	ifr.ifr_flags &= ~IFF_UP;
	if (mode == SSH_TUNMODE_ETHERNET)
		ifr.ifr_flags |= IFF_LINK0;
	else
		ifr.ifr_flags &= ~IFF_LINK0;
	if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
		goto failed;

	/* Bring interface up */
	ifr.ifr_flags |= IFF_UP;
	if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
		goto failed;

	close(sock);
	return (fd);

 failed:
	if (fd >= 0)
		close(fd);
	if (sock >= 0)
		close(sock);
	pamsshagentauth_verbose("%s: failed to set %s mode %d: %s", __func__, name,
	    mode, strerror(errno));
	return (-1);
#else
    UNUSED(tun);
    UNUSED(mode);
	pamsshagentauth_logerror("Tunnel interfaces are not supported on this platform");
	return (-1);
#endif
}