mirror of
https://git.libssh.org/projects/libssh.git
synced 2025-12-09 15:41:10 +03:00
feature: Add match_localnetwork predicate and its feature
Signed-off-by: Francesco Rollo <eferollo@gmail.com> Reviewed-by: Jakub Jelen <jjelen@redhat.com> Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
This commit is contained in:
committed by
Sahana Prasad
parent
c93a730bc1
commit
e90df71955
@@ -33,7 +33,7 @@
|
||||
# endif /* _MSC_VER */
|
||||
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
#include <sys/types.h>
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -330,6 +330,11 @@ int decompress_buffer(ssh_session session,ssh_buffer buf, size_t maxlen);
|
||||
int match_pattern_list(const char *string, const char *pattern,
|
||||
size_t len, int dolower);
|
||||
int match_hostname(const char *host, const char *pattern, unsigned int len);
|
||||
#ifndef _WIN32
|
||||
int match_cidr_address_list(const char *address,
|
||||
const char *addrlist,
|
||||
int sa_family);
|
||||
#endif
|
||||
|
||||
/* connector.c */
|
||||
int ssh_connector_set_event(ssh_connector connector, ssh_event event);
|
||||
|
||||
161
src/config.c
161
src/config.c
@@ -39,6 +39,8 @@
|
||||
# include <errno.h>
|
||||
# include <signal.h>
|
||||
# include <sys/wait.h>
|
||||
# include <ifaddrs.h>
|
||||
# include <net/if.h>
|
||||
#endif
|
||||
|
||||
#include "libssh/config_parser.h"
|
||||
@@ -160,7 +162,8 @@ enum ssh_config_match_e {
|
||||
MATCH_HOST,
|
||||
MATCH_ORIGINALHOST,
|
||||
MATCH_USER,
|
||||
MATCH_LOCALUSER
|
||||
MATCH_LOCALUSER,
|
||||
MATCH_LOCALNETWORK
|
||||
};
|
||||
|
||||
struct ssh_config_match_keyword_table_s {
|
||||
@@ -168,16 +171,18 @@ struct ssh_config_match_keyword_table_s {
|
||||
enum ssh_config_match_e opcode;
|
||||
};
|
||||
|
||||
static struct ssh_config_match_keyword_table_s ssh_config_match_keyword_table[] = {
|
||||
{ "all", MATCH_ALL },
|
||||
{ "canonical", MATCH_CANONICAL },
|
||||
{ "final", MATCH_FINAL },
|
||||
{ "exec", MATCH_EXEC },
|
||||
{ "host", MATCH_HOST },
|
||||
{ "originalhost", MATCH_ORIGINALHOST },
|
||||
{ "user", MATCH_USER },
|
||||
{ "localuser", MATCH_LOCALUSER },
|
||||
{ NULL, MATCH_UNKNOWN },
|
||||
static struct ssh_config_match_keyword_table_s
|
||||
ssh_config_match_keyword_table[] = {
|
||||
{"all", MATCH_ALL},
|
||||
{"canonical", MATCH_CANONICAL},
|
||||
{"final", MATCH_FINAL},
|
||||
{"exec", MATCH_EXEC},
|
||||
{"host", MATCH_HOST},
|
||||
{"originalhost", MATCH_ORIGINALHOST},
|
||||
{"user", MATCH_USER},
|
||||
{"localuser", MATCH_LOCALUSER},
|
||||
{"localnetwork", MATCH_LOCALNETWORK},
|
||||
{NULL, MATCH_UNKNOWN},
|
||||
};
|
||||
|
||||
static int ssh_config_parse_line(ssh_session session, const char *line,
|
||||
@@ -572,6 +577,99 @@ ssh_config_make_absolute(ssh_session session,
|
||||
return out;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
/**
|
||||
* @brief Checks if host address matches the local network specified.
|
||||
*
|
||||
* Verify whether a local network interface address matches any of the CIDR
|
||||
* patterns.
|
||||
*
|
||||
* @param addrlist The CIDR pattern-list to be checked, can contain both
|
||||
* IPv4 and IPv6 addresses and has to be comma separated
|
||||
* (',' only, space after comma not allowed).
|
||||
*
|
||||
* @param negate The negate condition. The return value is negated
|
||||
* (returns 1 instead of 0 and vice versa).
|
||||
*
|
||||
* @return 1 if match found.
|
||||
* @return 0 if no match found.
|
||||
* @return -1 on errors.
|
||||
*/
|
||||
static int
|
||||
ssh_match_localnetwork(const char *addrlist, bool negate)
|
||||
{
|
||||
struct ifaddrs *ifa = NULL, *ifaddrs = NULL;
|
||||
int r, found = 0;
|
||||
char address[NI_MAXHOST], err_msg[SSH_ERRNO_MSG_MAX] = {0};
|
||||
socklen_t sa_len;
|
||||
|
||||
r = getifaddrs(&ifaddrs);
|
||||
if (r != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"Match localnetwork: getifaddrs() failed: %s",
|
||||
ssh_strerror(r, err_msg, SSH_ERRNO_MSG_MAX));
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
|
||||
if (ifa->ifa_addr == NULL || (ifa->ifa_flags & IFF_UP) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (ifa->ifa_addr->sa_family) {
|
||||
case AF_INET:
|
||||
sa_len = sizeof(struct sockaddr_in);
|
||||
break;
|
||||
case AF_INET6:
|
||||
sa_len = sizeof(struct sockaddr_in6);
|
||||
break;
|
||||
default:
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Interface %s: unsupported address family %d",
|
||||
ifa->ifa_name,
|
||||
ifa->ifa_addr->sa_family);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = getnameinfo(ifa->ifa_addr,
|
||||
sa_len,
|
||||
address,
|
||||
sizeof(address),
|
||||
NULL,
|
||||
0,
|
||||
NI_NUMERICHOST);
|
||||
if (r != 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Interface %s getnameinfo failed: %s",
|
||||
ifa->ifa_name,
|
||||
gai_strerror(r));
|
||||
continue;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Interface %s address %s",
|
||||
ifa->ifa_name,
|
||||
address);
|
||||
|
||||
r = match_cidr_address_list(address,
|
||||
addrlist,
|
||||
ifa->ifa_addr->sa_family);
|
||||
if (r == 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Matched interface %s: address %s in %s",
|
||||
ifa->ifa_name,
|
||||
address,
|
||||
addrlist);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(ifaddrs);
|
||||
|
||||
return (found == (negate ? 0 : 1));
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
ssh_config_parse_line(ssh_session session,
|
||||
const char *line,
|
||||
@@ -795,6 +893,47 @@ ssh_config_parse_line(ssh_session session,
|
||||
args++;
|
||||
break;
|
||||
|
||||
#ifndef _WIN32
|
||||
case MATCH_LOCALNETWORK:
|
||||
/* Here we match only one argument */
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p == NULL || p[0] == '\0') {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"line %d: ERROR - Match local network keyword"
|
||||
"requires argument",
|
||||
count);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
rv = match_cidr_address_list(NULL, p, -1);
|
||||
if (rv == -1) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"line %d: ERROR - List invalid entry: %s",
|
||||
count,
|
||||
p);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
rv = ssh_match_localnetwork(p, negate);
|
||||
if (rv == -1) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"line %d: ERROR - Error while retrieving "
|
||||
"network interface information -"
|
||||
" List entry: %s",
|
||||
count,
|
||||
p);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
|
||||
result &= rv;
|
||||
args++;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case MATCH_UNKNOWN:
|
||||
default:
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
|
||||
375
src/match.c
375
src/match.c
@@ -198,3 +198,378 @@ int match_pattern_list(const char *string, const char *pattern,
|
||||
int match_hostname(const char *host, const char *pattern, unsigned int len) {
|
||||
return match_pattern_list(host, pattern, len, 1);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
/**
|
||||
* @brief Tries to match the host IPv6 address against a given network address
|
||||
* with specified prefix length in CIDR notation.
|
||||
*
|
||||
* @param[in] host_addr The host address to verify.
|
||||
*
|
||||
* @param[in] net_addr The network id address against which the match is
|
||||
* being verified
|
||||
*
|
||||
* @param[in] bits The prefix length
|
||||
*
|
||||
* @return 0 on a negative match.
|
||||
* @return 1 on a positive match.
|
||||
*/
|
||||
static int
|
||||
cidr_match_6(struct in6_addr *host_addr,
|
||||
struct in6_addr *net_addr,
|
||||
unsigned int bits)
|
||||
{
|
||||
const uint32_t *a = host_addr->s6_addr32;
|
||||
const uint32_t *b = net_addr->s6_addr32;
|
||||
|
||||
unsigned int qwords_whole, bits_left;
|
||||
|
||||
/* The number of complete 32-bit words covered by the prefix */
|
||||
qwords_whole = bits / 32;
|
||||
|
||||
/*
|
||||
* The number of bits remaining in the incomplete (last) 32-bit word
|
||||
* covered by the prefix
|
||||
*/
|
||||
bits_left = bits % 32;
|
||||
|
||||
if (qwords_whole) {
|
||||
if (memcmp(a, b, qwords_whole * 4) != 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (bits_left) {
|
||||
if ((a[qwords_whole] ^ b[qwords_whole]) &
|
||||
htonl((0xFFFFFFFFu << (32 - bits_left)) & 0xFFFFFFFFu)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tries to match the host IPv4 address against a given network address
|
||||
* with specified prefix length in CIDR notation.
|
||||
*
|
||||
* @param[in] host_addr The host address to verify.
|
||||
*
|
||||
* @param[in] net_addr The network id address against which the match is
|
||||
* being verified
|
||||
*
|
||||
* @param[in] bits The prefix length
|
||||
*
|
||||
* @return 0 on a negative match.
|
||||
* @return 1 on a positive match.
|
||||
*/
|
||||
static int
|
||||
cidr_match_4(struct in_addr *host_addr,
|
||||
struct in_addr *net_addr,
|
||||
unsigned int bits)
|
||||
{
|
||||
if (bits == 0) {
|
||||
/* C99 6.5.7 (3): u32 << 32 is undefined behaviour */
|
||||
return 1;
|
||||
}
|
||||
|
||||
return !((host_addr->s_addr ^ net_addr->s_addr) &
|
||||
htonl((0xFFFFFFFFu << (32 - bits)) & 0xFFFFFFFFu));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the mask length is valid according to the address family
|
||||
* (IPv4 or IPv6).
|
||||
*
|
||||
* @param[in] family The address family (e.g. AF_INET or AF_INET6)
|
||||
*
|
||||
* @param[in] mask The subnet mask (prefix)
|
||||
*
|
||||
* @return true if the mask length does not exceed the maximum valid length
|
||||
* according to the address family (IPv4 or IPv6).
|
||||
* @return false if the mask length exceeds the maximum valid length
|
||||
* or there is no match with IPv4 or IPv6 address family.
|
||||
*/
|
||||
static bool
|
||||
masklen_valid(int family, unsigned int mask)
|
||||
{
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
return mask <= 32;
|
||||
case AF_INET6:
|
||||
return mask <= 128;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Extracts address family given a network address.
|
||||
*
|
||||
* @param[in] address The network address.
|
||||
*
|
||||
* @return The value of the address family if no errors.
|
||||
* @return -1 in case of errors.
|
||||
*/
|
||||
static int
|
||||
get_address_family(const char *address)
|
||||
{
|
||||
struct addrinfo hints, *ai = NULL;
|
||||
int rc = -1, rv;
|
||||
|
||||
ZERO_STRUCT(hints);
|
||||
if (address == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Bad arguments");
|
||||
goto out;
|
||||
}
|
||||
|
||||
hints.ai_flags = AI_NUMERICHOST;
|
||||
rv = getaddrinfo(address, NULL, &hints, &ai);
|
||||
if (rv != 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Couldn't get address information - getaddrinfo() failed: %s",
|
||||
gai_strerror(rv));
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = ai->ai_family;
|
||||
freeaddrinfo(ai);
|
||||
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tries to match the host address against a CIDR list provided
|
||||
* by the user. If the host address family is unknown, it can be derived by
|
||||
* passing -1 as sa_family argument.
|
||||
*
|
||||
* It can be also used to validate a CIDR list when the passed address is NULL
|
||||
* and sa_family is -1.
|
||||
*
|
||||
* @param[in] address The host address to verify (NULL to validate CIDR list).
|
||||
*
|
||||
* @param[in] addrlist The CIDR list against which the match is being verified.
|
||||
* The CIDR list can contain both IPv4 and IPv6 addresses
|
||||
* and has to be comma separated
|
||||
* (',' only, space after comma not allowed).
|
||||
*
|
||||
* @param[in] sa_family The socket address family (e.g. AF_INET or AF_INET6,
|
||||
* -1 to validate CIDR list or unknown address family).
|
||||
*
|
||||
* @usage To validate CIDR list: match_cidr_address_list(NULL, addrlist, -1).
|
||||
* @usage To verify a match with unknown address family:
|
||||
* match_cidr_address_list(address, addrlist, -1).
|
||||
* @return 1 only on positive match.
|
||||
* @return 0 on negative match or valid CIDR list.
|
||||
* @return -1 on errors or invalid CIDR list.
|
||||
*/
|
||||
int
|
||||
match_cidr_address_list(const char *address,
|
||||
const char *addrlist,
|
||||
int sa_family)
|
||||
{
|
||||
char *list = NULL, *cp = NULL, *a = NULL, *b = NULL, *sp = NULL;
|
||||
char addr_buffer[64], addr[NI_MAXHOST];
|
||||
struct in_addr try_addr, match_addr;
|
||||
struct in6_addr try_addr6, match_addr6;
|
||||
unsigned long mask_len;
|
||||
size_t addr_len, tmp_len;
|
||||
int rc = 0, r, ai_family;
|
||||
|
||||
ZERO_STRUCT(try_addr);
|
||||
ZERO_STRUCT(try_addr6);
|
||||
ZERO_STRUCT(match_addr);
|
||||
ZERO_STRUCT(match_addr6);
|
||||
|
||||
if (sa_family != AF_INET && sa_family != AF_INET6 && sa_family != -1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Invalid argument: sa_family %d is not valid",
|
||||
sa_family);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (address != NULL) {
|
||||
strncpy(addr, address, NI_MAXHOST - 1);
|
||||
|
||||
/* Remove interface in case of IPv6 address: addr%interface */
|
||||
a = strchr(addr, '%');
|
||||
if (a != NULL) {
|
||||
*a = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* If sa_family is set to -1 and address is not NULL then
|
||||
* the socket address family should be derived
|
||||
*/
|
||||
if (sa_family == -1) {
|
||||
r = get_address_family(addr);
|
||||
if (r == -1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to derive address family for address "
|
||||
"\"%.100s\"",
|
||||
addr);
|
||||
return -1;
|
||||
}
|
||||
sa_family = r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate host address from dot notation to binary network format
|
||||
* according to family type,
|
||||
* i.e. IPv4 (store in in_addr) or IPv6 (store in in6_addr)
|
||||
*/
|
||||
if (sa_family == AF_INET) {
|
||||
if (inet_pton(AF_INET, addr, &try_addr) == 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Couldn't parse IPv4 address \"%.100s\"",
|
||||
addr);
|
||||
return -1;
|
||||
}
|
||||
} else if (sa_family == AF_INET6) {
|
||||
if (inet_pton(AF_INET6, addr, &try_addr6) == 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Couldn't parse IPv6 address \"%.100s\"",
|
||||
addr);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Address family %d for address \"%.100s\" "
|
||||
"is not recognized",
|
||||
sa_family,
|
||||
addr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
b = list = strdup(addrlist);
|
||||
if (b == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((cp = strsep(&list, ",")) != NULL) {
|
||||
if (*cp == '\0') {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Empty entry in list \"%.100s\"", b);
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop junk from reaching address translation. +3 for the "/prefix".
|
||||
* INET6_ADDRSTRLEN is 46 and includes space for '\0' terminator. The
|
||||
* maximum IPv6 address printable is the one that carries IPv4 too.
|
||||
* E.g. ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255 is 46 chars
|
||||
* long ('\0' included) and the maximum prefix length possible is 96.
|
||||
* This explains why +3. All the other IPv6 addresses with maximum /127
|
||||
* prefix length (39 + 4) are covered just by INET6_ADDRSTRLEN itself
|
||||
*/
|
||||
addr_len = strlen(cp);
|
||||
if (addr_len > INET6_ADDRSTRLEN + 3) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"List entry \"%.100s\" too long: %zu > %d (MAX ALLOWED)",
|
||||
cp,
|
||||
addr_len,
|
||||
INET6_ADDRSTRLEN + 3);
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
#define VALID_CIDR_CHARS "0123456789abcdefABCDEF.:/"
|
||||
tmp_len = strspn(cp, VALID_CIDR_CHARS);
|
||||
if (tmp_len != addr_len) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"List entry \"%.100s\" contains invalid characters "
|
||||
"-> \"%c\" is an invalid character",
|
||||
cp,
|
||||
cp[tmp_len]);
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
#undef VALID_CIDR_CHARS
|
||||
|
||||
strncpy(addr_buffer, cp, sizeof(addr_buffer) - 1);
|
||||
sp = strchr(addr_buffer, '/');
|
||||
if (sp != NULL) {
|
||||
*sp = '\0';
|
||||
sp++;
|
||||
mask_len = strtoul(sp, &cp, 10);
|
||||
if (*sp < '0' || *sp > '9' || *cp != '\0') {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Error while parsing prefix: %s", sp);
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
if (mask_len > 128) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Invalid prefix: %lu exceeds the maximum allowed "
|
||||
"(>128)",
|
||||
mask_len);
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Missing prefix length for list entry \"%.100s\"",
|
||||
addr_buffer);
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
ai_family = get_address_family(addr_buffer);
|
||||
if (ai_family == -1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Couldn't get address family for \"%.100s\"",
|
||||
addr_buffer);
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ai_family == AF_INET) {
|
||||
if (inet_pton(AF_INET, addr_buffer, &match_addr) == 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Couldn't parse IPv4 address \"%.100s\"",
|
||||
addr_buffer);
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
} else if (ai_family == AF_INET6) {
|
||||
if (inet_pton(AF_INET6, addr_buffer, &match_addr6) == 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Couldn't parse IPv6 address \"%.100s\"",
|
||||
addr_buffer);
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Address family %d for address \"%.100s\" "
|
||||
"is not recognized",
|
||||
ai_family,
|
||||
addr_buffer);
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (masklen_valid(ai_family, mask_len) != true) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Invalid mask length %lu for list entry \"%.100s\"",
|
||||
mask_len,
|
||||
addr_buffer);
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Verify match between host address and network address*/
|
||||
if (((ai_family == AF_INET && sa_family == AF_INET) &&
|
||||
cidr_match_4(&try_addr, &match_addr, mask_len)) ||
|
||||
((ai_family == AF_INET6 && sa_family == AF_INET6) &&
|
||||
cidr_match_6(&try_addr6, &match_addr6, mask_len))) {
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
SAFE_FREE(b);
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
#ifndef _WIN32
|
||||
/* This is needed for a standard getpwuid_r on opensolaris */
|
||||
#define _POSIX_PTHREAD_SEMANTICS
|
||||
#include <pwd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
@@ -2226,5 +2226,4 @@ int ssh_check_username_syntax(const char *username)
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
Reference in New Issue
Block a user