mirror of https://github.com/wolfSSL/wolfssh.git
Add more functionality to wolfsshd, other improvements.
- Moved all wolfsshd source code into apps/wolfsshd/. Then future apps, e.g. an ssh-keygen type utility, will get their own subdirectory under apps/. - Rename wolfauth.(c|h) to auth.(c|h), rename wolfconfig.c to config.c. - Add support for checking user public keys against an authorized keys file. Doesn't support parsing options and comments in the key file, yet. Parsing special tokens (e.g. %h) and absolute paths in the AuthorizedKeysFile string are also not supported. - Comment out currently unused USER_NODE code. Could be useful later on if we integrate wolfsshd in an environment where the OS doesn't have its own username service. - Modify configure.ac to bring in libcrypt if wolfsshd is enabled.pull/435/head
parent
474527b89c
commit
787d5be900
|
|
@ -23,7 +23,9 @@
|
|||
aclocal.m4
|
||||
lt*.m4
|
||||
*.cache
|
||||
config.*
|
||||
config.h*
|
||||
configure~
|
||||
config.status
|
||||
configure
|
||||
libtool
|
||||
libtool.m4
|
||||
|
|
@ -55,7 +57,7 @@ examples/sftpclient/wolfsftp
|
|||
examples/scpclient/wolfscp
|
||||
|
||||
# applications
|
||||
apps/wolfsshd
|
||||
apps/wolfsshd/wolfsshd
|
||||
|
||||
# test output
|
||||
tests/*.test
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ EXTRA_DIST+= LICENSING README.md ChangeLog.md
|
|||
|
||||
include src/include.am
|
||||
include wolfssh/include.am
|
||||
include apps/include.am
|
||||
include apps/wolfsshd/include.am
|
||||
include examples/include.am
|
||||
include tests/include.am
|
||||
include keys/include.am
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
# vim:ft=automake
|
||||
# All paths should be given relative to the root
|
||||
|
||||
if BUILD_SSHD
|
||||
bin_PROGRAMS += apps/wolfsshd
|
||||
noinst_HEADERS += apps/wolfsshd.h \
|
||||
apps/wolfauth.h
|
||||
apps_wolfsshd_SOURCES = apps/wolfsshd.c \
|
||||
apps/wolfconfig.c \
|
||||
apps/wolfauth.c
|
||||
apps_wolfsshd_LDADD = src/libwolfssh.la
|
||||
apps_wolfsshd_DEPENDENCIES = src/libwolfssh.la
|
||||
endif
|
||||
|
||||
DISTCLEANFILES+= apps/.libs/wolfsshd
|
||||
|
||||
256
apps/wolfauth.c
256
apps/wolfauth.c
|
|
@ -1,256 +0,0 @@
|
|||
/* wolfauth.c
|
||||
*
|
||||
* Copyright (C) 2014-2021 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSH.
|
||||
*
|
||||
* wolfSSH is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSH is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with wolfSSH. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSH_SSHD
|
||||
|
||||
#include <wolfssh/ssh.h>
|
||||
#include <wolfssh/internal.h>
|
||||
#include <wolfssh/log.h>
|
||||
#include <wolfssl/wolfcrypt/wc_port.h>
|
||||
#include <wolfssl/wolfcrypt/error-crypt.h>
|
||||
|
||||
#ifdef NO_INLINE
|
||||
#include <wolfssh/misc.h>
|
||||
#else
|
||||
#define WOLFSSH_MISC_INCLUDED
|
||||
#include "src/misc.c"
|
||||
#endif
|
||||
|
||||
#include "wolfauth.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
static byte passwdRetry = 3;
|
||||
|
||||
/* Map user names to passwords */
|
||||
/* Use arrays for username and p. The password or public key can
|
||||
* be hashed and the hash stored here. Then I won't need the type. */
|
||||
struct USER_NODE {
|
||||
byte type;
|
||||
byte username[32];
|
||||
word32 usernameSz;
|
||||
byte fingerprint[WC_SHA256_DIGEST_SIZE];
|
||||
struct USER_NODE* next;
|
||||
};
|
||||
|
||||
|
||||
/* Takes a users input and adds it to the list of accepted users
|
||||
* 'value' can be a users password / public key / or certificate
|
||||
* returns an updated list on success (i.e. 'new' -> 'list' -> ...) or NULL
|
||||
* on failure
|
||||
*/
|
||||
USER_NODE* AddNewUser(USER_NODE* list, byte type, const byte* username,
|
||||
word32 usernameSz, const byte* value, word32 valueSz)
|
||||
{
|
||||
USER_NODE* map;
|
||||
|
||||
map = (USER_NODE*)WMALLOC(sizeof(USER_NODE), NULL, 0);
|
||||
if (map != NULL) {
|
||||
map->type = type;
|
||||
if (usernameSz >= sizeof(map->username))
|
||||
usernameSz = sizeof(map->username) - 1;
|
||||
WMEMCPY(map->username, username, usernameSz + 1);
|
||||
map->username[usernameSz] = 0;
|
||||
map->usernameSz = usernameSz;
|
||||
|
||||
if (type != WOLFSSH_USERAUTH_NONE) {
|
||||
wc_Sha256Hash(value, valueSz, map->fingerprint);
|
||||
}
|
||||
|
||||
map->next = list;
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
/* returns WS_SUCCESS if user/password found */
|
||||
static int CheckPassword(const byte* usr, const byte* pw, int pwSz)
|
||||
{
|
||||
int ret = WS_SUCCESS;
|
||||
struct passwd* pwInfo;
|
||||
// struct spwd* spwInfo;
|
||||
char* encPw; /* encrypted version of password */
|
||||
char tmp[256];
|
||||
|
||||
pwInfo = getpwnam((const char*)usr);
|
||||
if (pwInfo == NULL) {
|
||||
/* user name not found on system */
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
/* check for shadow password record */
|
||||
// spwInfo = getspnam(usr);
|
||||
// if (spwInfo != NULL) {
|
||||
// pwInfo->pw_passwd = spwInfo->sp_pwdp;
|
||||
// }
|
||||
//
|
||||
{
|
||||
int z;
|
||||
for (z = 0; z < pwSz; z++)
|
||||
tmp[z] = pw[z];
|
||||
tmp[z] = '\0';
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
encPw = crypt((const char*)tmp, pwInfo->pw_passwd);
|
||||
if (encPw == NULL) {
|
||||
/* error encrypting password for comparison */
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int z;
|
||||
printf("peer pw : ");
|
||||
for (z = 0; z < pwSz; z++)
|
||||
printf("%02X", pw[z]);
|
||||
printf("\n");
|
||||
printf(" pw : ");
|
||||
for (z = 0; z < pwSz; z++)
|
||||
printf("%02X", pwInfo->pw_passwd[z]);
|
||||
printf("\n");
|
||||
printf(" enc : ");
|
||||
for (z = 0; z < pwSz; z++)
|
||||
printf("%02X", encPw[z]);
|
||||
printf("\n");
|
||||
}
|
||||
if (ret == WS_SUCCESS) {
|
||||
if (XSTRCMP(encPw, pwInfo->pw_passwd) == 0) {
|
||||
wolfSSH_Log(WS_LOG_INFO, "[SSHD] User %s log in successful", usr);
|
||||
}
|
||||
else {
|
||||
wolfSSH_Log(WS_LOG_INFO, "[SSHD] User %s log in fail", usr);
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
}
|
||||
(void)pwSz;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int DefaultUserAuth(byte authType, WS_UserAuthData* authData, void* ctx)
|
||||
{
|
||||
USER_NODE* map;
|
||||
byte authHash[WC_SHA256_DIGEST_SIZE];
|
||||
int ret;
|
||||
|
||||
if (authType != WOLFSSH_USERAUTH_PASSWORD &&
|
||||
#ifdef WOLFSSH_ALLOW_USERAUTH_NONE
|
||||
authType != WOLFSSH_USERAUTH_NONE &&
|
||||
#endif
|
||||
authType != WOLFSSH_USERAUTH_PUBLICKEY) {
|
||||
|
||||
return WOLFSSH_USERAUTH_FAILURE;
|
||||
}
|
||||
map = (USER_NODE*)ctx;
|
||||
|
||||
/* check if password on system */
|
||||
if (authData->type == WOLFSSH_USERAUTH_PASSWORD) {
|
||||
if (CheckPassword(authData->username, authData->sf.password.password,
|
||||
authData->sf.password.passwordSz) == WS_SUCCESS) {
|
||||
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Password and user on system");
|
||||
return WOLFSSH_USERAUTH_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (authType == WOLFSSH_USERAUTH_PASSWORD) {
|
||||
wc_Sha256Hash(authData->sf.password.password,
|
||||
authData->sf.password.passwordSz,
|
||||
authHash);
|
||||
}
|
||||
else if (authType == WOLFSSH_USERAUTH_PUBLICKEY) {
|
||||
wc_Sha256Hash(authData->sf.publicKey.publicKey,
|
||||
authData->sf.publicKey.publicKeySz,
|
||||
authHash);
|
||||
}
|
||||
|
||||
while (map != NULL) {
|
||||
if (authData->usernameSz == map->usernameSz &&
|
||||
WMEMCMP(authData->username, map->username, map->usernameSz) == 0 &&
|
||||
authData->type == map->type) {
|
||||
|
||||
if (authData->type == WOLFSSH_USERAUTH_PUBLICKEY) {
|
||||
if (WMEMCMP(map->fingerprint, authHash,
|
||||
WC_SHA256_DIGEST_SIZE) == 0) {
|
||||
return WOLFSSH_USERAUTH_SUCCESS;
|
||||
}
|
||||
else {
|
||||
return WOLFSSH_USERAUTH_INVALID_PUBLICKEY;
|
||||
}
|
||||
}
|
||||
else if (authData->type == WOLFSSH_USERAUTH_PASSWORD) {
|
||||
if (WMEMCMP(map->fingerprint, authHash,
|
||||
WC_SHA256_DIGEST_SIZE) == 0) {
|
||||
return WOLFSSH_USERAUTH_SUCCESS;
|
||||
}
|
||||
else {
|
||||
passwdRetry--;
|
||||
return (passwdRetry > 0) ?
|
||||
WOLFSSH_USERAUTH_INVALID_PASSWORD :
|
||||
WOLFSSH_USERAUTH_REJECTED;
|
||||
}
|
||||
}
|
||||
#ifdef WOLFSSH_ALLOW_USERAUTH_NONE
|
||||
else if (authData->type == WOLFSSH_USERAUTH_NONE) {
|
||||
return WOLFSSH_USERAUTH_SUCCESS;
|
||||
}
|
||||
#endif /* WOLFSSH_ALLOW_USERAUTH_NONE */
|
||||
else {
|
||||
return WOLFSSH_USERAUTH_INVALID_AUTHTYPE;
|
||||
}
|
||||
|
||||
if (authData->type == map->type) {
|
||||
if (WMEMCMP(map->fingerprint, authHash,
|
||||
WC_SHA256_DIGEST_SIZE) == 0) {
|
||||
return WOLFSSH_USERAUTH_SUCCESS;
|
||||
}
|
||||
else {
|
||||
if (authType == WOLFSSH_USERAUTH_PASSWORD) {
|
||||
passwdRetry--;
|
||||
ret = (passwdRetry > 0) ?
|
||||
WOLFSSH_USERAUTH_INVALID_PASSWORD :
|
||||
WOLFSSH_USERAUTH_REJECTED;
|
||||
}
|
||||
else {
|
||||
ret = WOLFSSH_USERAUTH_INVALID_PUBLICKEY;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return WOLFSSH_USERAUTH_INVALID_AUTHTYPE;
|
||||
}
|
||||
}
|
||||
map = map->next;
|
||||
}
|
||||
|
||||
return WOLFSSH_USERAUTH_INVALID_USER;
|
||||
}
|
||||
#endif /* WOLFSSH_SSHD */
|
||||
|
|
@ -0,0 +1,587 @@
|
|||
/* auth.c
|
||||
*
|
||||
* Copyright (C) 2014-2021 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSH.
|
||||
*
|
||||
* wolfSSH is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSH is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with wolfSSH. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSH_SSHD
|
||||
|
||||
#include <wolfssh/ssh.h>
|
||||
#include <wolfssh/internal.h>
|
||||
#include <wolfssh/log.h>
|
||||
#include <wolfssl/wolfcrypt/wc_port.h>
|
||||
#include <wolfssl/wolfcrypt/error-crypt.h>
|
||||
#include <wolfssl/wolfcrypt/coding.h>
|
||||
|
||||
#ifdef NO_INLINE
|
||||
#include <wolfssh/misc.h>
|
||||
#else
|
||||
#define WOLFSSH_MISC_INCLUDED
|
||||
#include "src/misc.c"
|
||||
#endif
|
||||
|
||||
#include "auth.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static byte passwdRetry = 3;
|
||||
|
||||
/* Map user names to passwords */
|
||||
/* Use arrays for username and p. The password or public key can
|
||||
* be hashed and the hash stored here. Then I won't need the type. */
|
||||
struct USER_NODE {
|
||||
byte type;
|
||||
byte username[32];
|
||||
word32 usernameSz;
|
||||
byte fingerprint[WC_SHA256_DIGEST_SIZE];
|
||||
struct USER_NODE* next;
|
||||
};
|
||||
|
||||
|
||||
/* Takes a users input and adds it to the list of accepted users
|
||||
* 'value' can be a users password / public key / or certificate
|
||||
* returns an updated list on success (i.e. 'new' -> 'list' -> ...) or NULL
|
||||
* on failure
|
||||
*/
|
||||
USER_NODE* AddNewUser(USER_NODE* list, byte type, const byte* username,
|
||||
word32 usernameSz, const byte* value, word32 valueSz)
|
||||
{
|
||||
USER_NODE* map;
|
||||
|
||||
map = (USER_NODE*)WMALLOC(sizeof(USER_NODE), NULL, 0);
|
||||
if (map != NULL) {
|
||||
map->type = type;
|
||||
if (usernameSz >= sizeof(map->username))
|
||||
usernameSz = sizeof(map->username) - 1;
|
||||
WMEMCPY(map->username, username, usernameSz + 1);
|
||||
map->username[usernameSz] = 0;
|
||||
map->usernameSz = usernameSz;
|
||||
|
||||
if (type != WOLFSSH_USERAUTH_NONE) {
|
||||
wc_Sha256Hash(value, valueSz, map->fingerprint);
|
||||
}
|
||||
|
||||
map->next = list;
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
int DefaultUserAuth(byte authType, WS_UserAuthData* authData, void* ctx)
|
||||
{
|
||||
USER_NODE* map;
|
||||
byte authHash[WC_SHA256_DIGEST_SIZE];
|
||||
int ret;
|
||||
|
||||
if (authType != WOLFSSH_USERAUTH_PASSWORD &&
|
||||
#ifdef WOLFSSH_ALLOW_USERAUTH_NONE
|
||||
authType != WOLFSSH_USERAUTH_NONE &&
|
||||
#endif
|
||||
authType != WOLFSSH_USERAUTH_PUBLICKEY) {
|
||||
|
||||
return WOLFSSH_USERAUTH_FAILURE;
|
||||
}
|
||||
map = (USER_NODE*)ctx;
|
||||
|
||||
/* check if password on system */
|
||||
if (authData->type == WOLFSSH_USERAUTH_PASSWORD) {
|
||||
if (CheckPassword(authData->username, authData->sf.password.password,
|
||||
authData->sf.password.passwordSz) == WS_SUCCESS) {
|
||||
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Password and user on system");
|
||||
return WOLFSSH_USERAUTH_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (authType == WOLFSSH_USERAUTH_PASSWORD) {
|
||||
wc_Sha256Hash(authData->sf.password.password,
|
||||
authData->sf.password.passwordSz,
|
||||
authHash);
|
||||
}
|
||||
else if (authType == WOLFSSH_USERAUTH_PUBLICKEY) {
|
||||
wc_Sha256Hash(authData->sf.publicKey.publicKey,
|
||||
authData->sf.publicKey.publicKeySz,
|
||||
authHash);
|
||||
}
|
||||
|
||||
while (map != NULL) {
|
||||
if (authData->usernameSz == map->usernameSz &&
|
||||
WMEMCMP(authData->username, map->username, map->usernameSz) == 0 &&
|
||||
authData->type == map->type) {
|
||||
|
||||
if (authData->type == WOLFSSH_USERAUTH_PUBLICKEY) {
|
||||
if (WMEMCMP(map->fingerprint, authHash,
|
||||
WC_SHA256_DIGEST_SIZE) == 0) {
|
||||
return WOLFSSH_USERAUTH_SUCCESS;
|
||||
}
|
||||
else {
|
||||
return WOLFSSH_USERAUTH_INVALID_PUBLICKEY;
|
||||
}
|
||||
}
|
||||
else if (authData->type == WOLFSSH_USERAUTH_PASSWORD) {
|
||||
if (WMEMCMP(map->fingerprint, authHash,
|
||||
WC_SHA256_DIGEST_SIZE) == 0) {
|
||||
return WOLFSSH_USERAUTH_SUCCESS;
|
||||
}
|
||||
else {
|
||||
passwdRetry--;
|
||||
return (passwdRetry > 0) ?
|
||||
WOLFSSH_USERAUTH_INVALID_PASSWORD :
|
||||
WOLFSSH_USERAUTH_REJECTED;
|
||||
}
|
||||
}
|
||||
#ifdef WOLFSSH_ALLOW_USERAUTH_NONE
|
||||
else if (authData->type == WOLFSSH_USERAUTH_NONE) {
|
||||
return WOLFSSH_USERAUTH_SUCCESS;
|
||||
}
|
||||
#endif /* WOLFSSH_ALLOW_USERAUTH_NONE */
|
||||
else {
|
||||
return WOLFSSH_USERAUTH_INVALID_AUTHTYPE;
|
||||
}
|
||||
|
||||
if (authData->type == map->type) {
|
||||
if (WMEMCMP(map->fingerprint, authHash,
|
||||
WC_SHA256_DIGEST_SIZE) == 0) {
|
||||
return WOLFSSH_USERAUTH_SUCCESS;
|
||||
}
|
||||
else {
|
||||
if (authType == WOLFSSH_USERAUTH_PASSWORD) {
|
||||
passwdRetry--;
|
||||
ret = (passwdRetry > 0) ?
|
||||
WOLFSSH_USERAUTH_INVALID_PASSWORD :
|
||||
WOLFSSH_USERAUTH_REJECTED;
|
||||
}
|
||||
else {
|
||||
ret = WOLFSSH_USERAUTH_INVALID_PUBLICKEY;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return WOLFSSH_USERAUTH_INVALID_AUTHTYPE;
|
||||
}
|
||||
}
|
||||
map = map->next;
|
||||
}
|
||||
|
||||
return WOLFSSH_USERAUTH_INVALID_USER;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int CheckAuthKeysLine(char* line, word32 lineSz, const byte* key,
|
||||
word32 keySz)
|
||||
{
|
||||
int ret = WS_SUCCESS;
|
||||
char* type;
|
||||
char* keyCandBase64; /* cand == candidate */
|
||||
word32 keyCandBase64Sz;
|
||||
byte* keyCand = NULL;
|
||||
word32 keyCandSz;
|
||||
char* last;
|
||||
enum {
|
||||
NUM_ALLOWED_TYPES = 5
|
||||
};
|
||||
static const char* allowedTypes[NUM_ALLOWED_TYPES] = {
|
||||
"ssh-rsa",
|
||||
"ssh-ed25519",
|
||||
"ecdsa-sha2-nistp256",
|
||||
"ecdsa-sha2-nistp384",
|
||||
"ecdsa-sha2-nistp521"
|
||||
};
|
||||
int typeOk = 0;
|
||||
int i;
|
||||
|
||||
if (line == NULL || lineSz == 0 || key == NULL || keySz == 0) {
|
||||
ret = WS_BAD_ARGUMENT;
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
if ((type = WSTRTOK(line, " ", &last)) == NULL) {
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
else if ((keyCandBase64 = WSTRTOK(NULL, " ", &last)) == NULL) {
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
}
|
||||
if (ret == WS_SUCCESS) {
|
||||
for (i = 0; i < NUM_ALLOWED_TYPES; ++i) {
|
||||
if (WSTRCMP(type, allowedTypes[i]) == 0) {
|
||||
typeOk = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!typeOk) {
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
}
|
||||
if (ret == WS_SUCCESS) {
|
||||
keyCandBase64Sz = XSTRLEN(keyCandBase64);
|
||||
keyCandSz = (keyCandBase64Sz * 3 + 3) / 4;
|
||||
keyCand = (byte*)WMALLOC(keyCandSz, NULL, DYNTYPE_BUFFER);
|
||||
if (keyCand == NULL) {
|
||||
ret = WS_MEMORY_E;
|
||||
}
|
||||
else {
|
||||
if (Base64_Decode((byte*)keyCandBase64, keyCandBase64Sz, keyCand,
|
||||
&keyCandSz) != 0) {
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret == WS_SUCCESS && keyCandSz == keySz &&
|
||||
WMEMCMP(key, keyCand, keySz) == 0) {
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (keyCand != NULL) {
|
||||
WFREE(keyCand, NULL, DYNTYPE_BUFFER);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* returns WS_SUCCESS if user/password found */
|
||||
static int CheckPassword(const byte* usr, const byte* pw, int pwSz)
|
||||
{
|
||||
int ret = WS_SUCCESS;
|
||||
struct passwd* pwInfo;
|
||||
// struct spwd* spwInfo;
|
||||
char* encPw; /* encrypted version of password */
|
||||
char tmp[256];
|
||||
|
||||
pwInfo = getpwnam((const char*)usr);
|
||||
if (pwInfo == NULL) {
|
||||
/* user name not found on system */
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
/* check for shadow password record */
|
||||
// spwInfo = getspnam(usr);
|
||||
// if (spwInfo != NULL) {
|
||||
// pwInfo->pw_passwd = spwInfo->sp_pwdp;
|
||||
// }
|
||||
//
|
||||
{
|
||||
int z;
|
||||
for (z = 0; z < pwSz; z++)
|
||||
tmp[z] = pw[z];
|
||||
tmp[z] = '\0';
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
encPw = crypt((const char*)tmp, pwInfo->pw_passwd);
|
||||
if (encPw == NULL) {
|
||||
/* error encrypting password for comparison */
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int z;
|
||||
printf("peer pw : ");
|
||||
for (z = 0; z < pwSz; z++)
|
||||
printf("%02X", pw[z]);
|
||||
printf("\n");
|
||||
printf(" pw : ");
|
||||
for (z = 0; z < pwSz; z++)
|
||||
printf("%02X", pwInfo->pw_passwd[z]);
|
||||
printf("\n");
|
||||
printf(" enc : ");
|
||||
for (z = 0; z < pwSz; z++)
|
||||
printf("%02X", encPw[z]);
|
||||
printf("\n");
|
||||
}
|
||||
if (ret == WS_SUCCESS) {
|
||||
if (XSTRCMP(encPw, pwInfo->pw_passwd) == 0) {
|
||||
wolfSSH_Log(WS_LOG_INFO, "[SSHD] User %s log in successful", usr);
|
||||
}
|
||||
else {
|
||||
wolfSSH_Log(WS_LOG_INFO, "[SSHD] User %s log in fail", usr);
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
}
|
||||
(void)pwSz;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum {
|
||||
USER_LOOKUP_ERROR = -1,
|
||||
USER_LOOKUP_FAILURE = 0,
|
||||
USER_LOOKUP_SUCCESS = 1
|
||||
};
|
||||
|
||||
#ifndef _WIN32
|
||||
static int CheckUserUnix(const char* name) {
|
||||
int ret = USER_LOOKUP_FAILURE;
|
||||
struct passwd* pwInfo;
|
||||
|
||||
errno = 0;
|
||||
pwInfo = getpwnam(name);
|
||||
if (pwInfo == NULL) {
|
||||
if (errno != 0) {
|
||||
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error calling getpwnam for user "
|
||||
"%s.", name);
|
||||
ret = USER_LOOKUP_ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ret = USER_LOOKUP_SUCCESS;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char authKeysDefault[] = ".ssh/authorized_keys";
|
||||
static char authKeysPattern[32] = {0};
|
||||
|
||||
void SetAuthKeysPattern(const char* pattern)
|
||||
{
|
||||
if (pattern != NULL) {
|
||||
WMEMSET(authKeysPattern, 0, sizeof(authKeysPattern));
|
||||
WSTRNCPY(authKeysPattern, pattern, sizeof(authKeysPattern));
|
||||
}
|
||||
}
|
||||
|
||||
static int ResolveAuthKeysPath(const char* homeDir, char* resolved)
|
||||
{
|
||||
int ret = WS_SUCCESS;
|
||||
char* idx;
|
||||
int homeDirSz;
|
||||
const char* suffix = authKeysDefault;
|
||||
|
||||
if (homeDir == NULL || resolved == NULL) {
|
||||
ret = WS_BAD_ARGUMENT;
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
if (*authKeysPattern != 0) {
|
||||
/* TODO: token substitutions (e.g. %h) */
|
||||
if (*authKeysPattern == '/') {
|
||||
/* TODO: handle absolute path case */
|
||||
ret = WS_FATAL_ERROR;
|
||||
}
|
||||
else {
|
||||
suffix = authKeysPattern;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret == WS_SUCCESS) {
|
||||
idx = resolved;
|
||||
homeDirSz = XSTRLEN(homeDir);
|
||||
XMEMCPY(idx, homeDir, homeDirSz);
|
||||
idx += homeDirSz;
|
||||
*(idx++) = '/';
|
||||
/* Intentionally copying the null term from suffix. */
|
||||
XMEMCPY(idx, suffix, WSTRLEN(suffix));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int CheckPublicKeyUnix(const byte* name, const byte* key, word32 keySz)
|
||||
{
|
||||
int ret = WS_SUCCESS;
|
||||
struct passwd* pwInfo;
|
||||
char* authKeysFile = NULL;
|
||||
XFILE f;
|
||||
enum {
|
||||
/* TODO: Probably needs to be even bigger for larger key sizes. */
|
||||
MAX_LINE_SZ = 500,
|
||||
MAX_PATH_SZ = 80
|
||||
};
|
||||
char* lineBuf = NULL;
|
||||
char* current;
|
||||
word32 currentSz;
|
||||
int foundKey = 0;
|
||||
int rc;
|
||||
char authKeysPath[MAX_PATH_SZ];
|
||||
|
||||
errno = 0;
|
||||
pwInfo = getpwnam((const char*)name);
|
||||
if (pwInfo == NULL) {
|
||||
if (errno != 0) {
|
||||
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error calling getpwnam for user "
|
||||
"%s.", name);
|
||||
ret = WS_ERROR;
|
||||
}
|
||||
}
|
||||
if (ret == WS_SUCCESS) {
|
||||
WMEMSET(authKeysPath, 0, sizeof(authKeysPath));
|
||||
ret = ResolveAuthKeysPath(pwInfo->pw_dir, authKeysPath);
|
||||
}
|
||||
if (ret == WS_SUCCESS) {
|
||||
f = XFOPEN(authKeysPath, "rb");
|
||||
if (f == XBADFILE) {
|
||||
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Unable to open %s",
|
||||
authKeysPath);
|
||||
ret = WS_BAD_FILE_E;
|
||||
}
|
||||
}
|
||||
if (ret == WS_SUCCESS) {
|
||||
lineBuf = (char*)WMALLOC(MAX_LINE_SZ, NULL, DYNTYPE_BUFFER);
|
||||
if (lineBuf == NULL) {
|
||||
ret = WS_MEMORY_E;
|
||||
}
|
||||
}
|
||||
while (ret == WS_SUCCESS &&
|
||||
(current = XFGETS(lineBuf, MAX_LINE_SZ, f)) != NULL) {
|
||||
currentSz = XSTRLEN(current);
|
||||
|
||||
/* remove leading spaces */
|
||||
while (currentSz > 0 && current[0] == ' ') {
|
||||
currentSz = currentSz - 1;
|
||||
current = current + 1;
|
||||
}
|
||||
|
||||
if (currentSz <= 1) {
|
||||
continue; /* empty line */
|
||||
}
|
||||
|
||||
if (current[0] == '#') {
|
||||
continue; /* commented out line */
|
||||
}
|
||||
|
||||
rc = CheckAuthKeysLine(current, currentSz, key, keySz);
|
||||
if (rc == 1) {
|
||||
foundKey = 1;
|
||||
break;
|
||||
}
|
||||
else if (rc < 0) {
|
||||
ret = rc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
XFCLOSE(f);
|
||||
|
||||
if (ret == WS_SUCCESS && !foundKey) {
|
||||
ret = WS_ERROR;
|
||||
}
|
||||
|
||||
if (lineBuf != NULL) {
|
||||
WFREE(lineBuf, NULL, DYNTYPE_BUFFER);
|
||||
}
|
||||
if (authKeysFile != NULL) {
|
||||
WFREE(authKeysFile, NULL, DYNTYPE_STRING);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* !_WIN32*/
|
||||
|
||||
static int CheckUser(const char* name)
|
||||
{
|
||||
int ret = USER_LOOKUP_FAILURE;
|
||||
|
||||
#ifdef _WIN32
|
||||
/* TODO: Implement for Windows. */
|
||||
#else
|
||||
ret = CheckUserUnix(name);
|
||||
#endif
|
||||
|
||||
if (ret == USER_LOOKUP_FAILURE) {
|
||||
wolfSSH_Log(WS_LOG_INFO, "[SSHD] User %s doesn't exist.", name);
|
||||
}
|
||||
else if (ret == USER_LOOKUP_ERROR) {
|
||||
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Error looking up user %s.", name);
|
||||
}
|
||||
else {
|
||||
wolfSSH_Log(WS_LOG_INFO, "[SSHD] User ok.");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int CheckPublicKey(const byte* name, const byte* key, word32 keySz)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
/* TODO: Implement for Windows. */
|
||||
#else
|
||||
ret = CheckPublicKeyUnix(name, key, keySz);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int DefaultUserAuth(byte authType, WS_UserAuthData* authData, void* ctx)
|
||||
{
|
||||
int ret = WOLFSSH_USERAUTH_FAILURE;
|
||||
|
||||
(void)ctx;
|
||||
/* TODO: Auth will need some info from the config. For example, the auth
|
||||
* keys file path or the allowed users, if not all users are allowed. Could
|
||||
* pass the config in the ctx pointer...
|
||||
*/
|
||||
|
||||
if (authType != WOLFSSH_USERAUTH_PASSWORD &&
|
||||
#ifdef WOLFSSH_ALLOW_USERAUTH_NONE
|
||||
authType != WOLFSSH_USERAUTH_NONE &&
|
||||
#endif
|
||||
authType != WOLFSSH_USERAUTH_PUBLICKEY) {
|
||||
|
||||
ret = WOLFSSH_USERAUTH_INVALID_AUTHTYPE;
|
||||
}
|
||||
|
||||
/* Check user exists. */
|
||||
if (ret == WOLFSSH_USERAUTH_SUCCESS) {
|
||||
/* TODO: Is authData and its members guaranteed to be non-NULL? */
|
||||
if (CheckUser((const char*)authData->username) <= 0) {
|
||||
ret = WOLFSSH_USERAUTH_INVALID_USER;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if password is valid for this user. */
|
||||
if (authData->type == WOLFSSH_USERAUTH_PASSWORD) {
|
||||
if (CheckPassword(authData->username, authData->sf.password.password,
|
||||
authData->sf.password.passwordSz) == WS_SUCCESS) {
|
||||
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Password ok.");
|
||||
ret = WOLFSSH_USERAUTH_SUCCESS;
|
||||
}
|
||||
else {
|
||||
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Password incorrect.");
|
||||
ret = WOLFSSH_USERAUTH_INVALID_PASSWORD;
|
||||
}
|
||||
}
|
||||
/* Check if public key is in this user's authorized_keys file. */
|
||||
else if (authData->type == WOLFSSH_USERAUTH_PUBLICKEY) {
|
||||
if (CheckPublicKey(authData->username, authData->sf.publicKey.publicKey,
|
||||
authData->sf.publicKey.publicKeySz) == WS_SUCCESS) {
|
||||
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Public key ok.");
|
||||
ret = WOLFSSH_USERAUTH_SUCCESS;
|
||||
}
|
||||
else {
|
||||
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Public key not authorized.");
|
||||
ret = WOLFSSH_USERAUTH_INVALID_PUBLICKEY;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* WOLFSSH_SSHD */
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
/* wolfauth.h
|
||||
/* auth.h
|
||||
*
|
||||
* Copyright (C) 2014-2021 wolfSSL Inc.
|
||||
*
|
||||
|
|
@ -18,14 +18,17 @@
|
|||
* along with wolfSSH. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef WOLFAUTH_H
|
||||
#define WOLFAUTH_H
|
||||
|
||||
#if 0
|
||||
typedef struct USER_NODE USER_NODE;
|
||||
|
||||
USER_NODE* AddNewUser(USER_NODE* list, byte type, const byte* username,
|
||||
word32 usernameSz, const byte* value, word32 valueSz);
|
||||
#endif
|
||||
|
||||
void SetAuthKeysPattern(const char* pattern);
|
||||
int DefaultUserAuth(byte authType, WS_UserAuthData* authData, void* ctx);
|
||||
|
||||
#endif /* WOLFAUTH_H */
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
/* wolfconfig.c
|
||||
/* config.c
|
||||
*
|
||||
* Copyright (C) 2014-2021 wolfSSL Inc.
|
||||
*
|
||||
|
|
@ -110,7 +110,7 @@ WOLFSSHD_CONFIG* wolfSSHD_NewConfig(void* heap)
|
|||
WMEMSET(ret, 0, sizeof(WOLFSSHD_CONFIG));
|
||||
|
||||
/* default values */
|
||||
ret->port = 22;
|
||||
ret->port = 9387;
|
||||
}
|
||||
return ret;
|
||||
|
||||
|
|
@ -139,6 +139,7 @@ static int wolfSSHD_ParseConfigLine(WOLFSSHD_CONFIG* conf, const char* l,
|
|||
{
|
||||
int ret = WS_BAD_ARGUMENT;
|
||||
int sz;
|
||||
char* tmp;
|
||||
|
||||
/* supported config options */
|
||||
const char authKeyFile[] = "AuthorizedKeysFile";
|
||||
|
|
@ -146,8 +147,10 @@ static int wolfSSHD_ParseConfigLine(WOLFSSHD_CONFIG* conf, const char* l,
|
|||
|
||||
sz = (int)XSTRLEN(authKeyFile);
|
||||
if (lSz > sz && XSTRNCMP(l, authKeyFile, sz) == 0) {
|
||||
ret = wolfSSHD_CreateString(&conf->authKeysFile, l + sz, lSz - sz,
|
||||
conf->heap);
|
||||
ret = wolfSSHD_CreateString(&tmp, l + sz, lSz - sz, conf->heap);
|
||||
if (ret == WS_SUCCESS) {
|
||||
wolfSSHD_SetAuthKeysFile(conf, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
sz = (int)XSTRLEN(privilegeSeparation);
|
||||
|
|
@ -258,9 +261,29 @@ int wolfSSHD_LoadSSHD(WOLFSSHD_CONFIG* conf, const char* filename)
|
|||
}
|
||||
XFCLOSE(f);
|
||||
|
||||
SetAuthKeysPattern(conf->authKeysFile);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* wolfSSHD_GetAuthKeysFile(WOLFSSHD_CONFIG* conf)
|
||||
{
|
||||
if (conf != NULL)
|
||||
return conf->authKeysFile;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int wolfSSHD_SetAuthKeysFile(WOLFSSHD_CONFIG* conf, const char* file)
|
||||
{
|
||||
if (conf == NULL) {
|
||||
return WS_BAD_ARGUMENT;
|
||||
}
|
||||
|
||||
conf->authKeysFile = (char*)file;
|
||||
|
||||
return WS_SUCCESS;
|
||||
}
|
||||
|
||||
char* wolfSSHD_GetBanner(WOLFSSHD_CONFIG* conf)
|
||||
{
|
||||
if (conf != NULL)
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
if BUILD_SSHD
|
||||
|
||||
bin_PROGRAMS += apps/wolfsshd/wolfsshd
|
||||
noinst_HEADERS += apps/wolfsshd/wolfsshd.h \
|
||||
apps/wolfsshd/auth.h
|
||||
apps_wolfsshd_wolfsshd_SOURCES = apps/wolfsshd/wolfsshd.c \
|
||||
apps/wolfsshd/config.c \
|
||||
apps/wolfsshd/auth.c
|
||||
apps_wolfsshd_wolfsshd_LDADD = src/libwolfssh.la
|
||||
apps_wolfsshd_wolfsshd_DEPENDENCIES = src/libwolfssh.la
|
||||
|
||||
DISTCLEANFILES+= apps/wolfsshd/.libs/wolfsshd
|
||||
|
||||
endif BUILD_SSHD
|
||||
|
|
@ -29,12 +29,13 @@
|
|||
#include <wolfssh/log.h>
|
||||
#include <wolfssl/wolfcrypt/wc_port.h>
|
||||
#include <wolfssl/wolfcrypt/error-crypt.h>
|
||||
#include <wolfssl/wolfcrypt/logging.h>
|
||||
|
||||
#define WOLFSSH_TEST_SERVER
|
||||
#include <wolfssh/test.h>
|
||||
|
||||
#include "wolfsshd.h"
|
||||
#include "wolfauth.h"
|
||||
#include "auth.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
|
|
@ -87,7 +88,7 @@ static void ShowUsage(void)
|
|||
{
|
||||
printf("wolfsshd %s\n", LIBWOLFSSH_VERSION_STRING);
|
||||
printf(" -? display this help and exit\n");
|
||||
printf(" -f <file name> Configuration file to use, default is /usr/locacl/etc/ssh/sshd_config\n");
|
||||
printf(" -f <file name> Configuration file to use, default is /usr/local/etc/ssh/sshd_config\n");
|
||||
printf(" -p <int> Port number to listen on\n");
|
||||
printf(" -d Turn on debug mode\n");
|
||||
}
|
||||
|
|
@ -107,7 +108,6 @@ static void wolfSSHDLoggingCb(enum wolfSSH_LogLevel lvl, const char *const str)
|
|||
(void)lvl;
|
||||
}
|
||||
|
||||
|
||||
static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx)
|
||||
{
|
||||
int ret = WS_SUCCESS;
|
||||
|
|
@ -148,8 +148,11 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* TODO: Currently expects a private key in DER format. Add logic to handle
|
||||
* PEM, too. wc_PemToDer. */
|
||||
/* Load in host private key */
|
||||
if (ret == WS_SUCCESS) {
|
||||
|
||||
char* hostKey = wolfSSHD_GetHostPrivateKey(conf);
|
||||
|
||||
if (hostKey == NULL) {
|
||||
|
|
@ -159,7 +162,7 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx)
|
|||
else {
|
||||
FILE* f;
|
||||
|
||||
f = fopen(hostKey, "rb");
|
||||
f = XFOPEN(hostKey, "rb");
|
||||
if (f == NULL) {
|
||||
wolfSSH_Log(WS_LOG_ERROR,
|
||||
"[SSHD] Unable to open host private key");
|
||||
|
|
@ -171,8 +174,9 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx)
|
|||
|
||||
data = (byte*)WMALLOC(dataSz, NULL, 0);
|
||||
|
||||
dataSz = (int)fread(data, 1, dataSz, f);
|
||||
fclose(f);
|
||||
dataSz = (int)XFREAD(data, 1, dataSz, f);
|
||||
XFCLOSE(f);
|
||||
|
||||
if (wolfSSH_CTX_UsePrivateKey_buffer(*ctx, data, dataSz,
|
||||
WOLFSSH_FORMAT_ASN1) < 0) {
|
||||
wolfSSH_Log(WS_LOG_ERROR,
|
||||
|
|
@ -240,9 +244,6 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx)
|
|||
// #endif
|
||||
// }
|
||||
|
||||
/* Load in authorized keys */
|
||||
|
||||
|
||||
/* Set allowed connection type, i.e. public key / password */
|
||||
|
||||
return ret;
|
||||
|
|
@ -599,12 +600,12 @@ int main(int argc, char** argv)
|
|||
signal(SIGINT, interruptCatch);
|
||||
|
||||
wolfSSH_SetLoggingCb(wolfSSHDLoggingCb);
|
||||
#ifdef DEBUG_WOLFSSH
|
||||
wolfSSH_Debugging_ON();
|
||||
#endif
|
||||
#ifdef DEBUG_WOLFSSL
|
||||
wolfSSL_Debugging_ON();
|
||||
#endif
|
||||
#ifdef DEBUG_WOLFSSH
|
||||
wolfSSH_Debugging_ON();
|
||||
#endif
|
||||
#ifdef DEBUG_WOLFSSL
|
||||
wolfSSL_Debugging_ON();
|
||||
#endif
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
wolfSSH_Init();
|
||||
|
|
@ -617,7 +618,6 @@ int main(int argc, char** argv)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
while ((ch = mygetopt(argc, argv, "?f:p:h:d")) != -1) {
|
||||
switch (ch) {
|
||||
case 'f':
|
||||
|
|
@ -677,6 +677,9 @@ int main(int argc, char** argv)
|
|||
if (ret == WS_SUCCESS) {
|
||||
ret = SetupCTX(conf, &ctx);
|
||||
}
|
||||
else {
|
||||
/* TODO: handle error. */
|
||||
}
|
||||
|
||||
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Starting to listen on port %d", port);
|
||||
tcp_listen(&listenFd, &port, 1);
|
||||
|
|
@ -708,6 +711,7 @@ int main(int argc, char** argv)
|
|||
|
||||
wolfSSHD_FreeConfig(conf);
|
||||
wolfSSH_Cleanup();
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* WOLFSSH_SSHD */
|
||||
|
|
@ -21,6 +21,8 @@
|
|||
#ifndef WOLFSSHD_H
|
||||
#define WOLFSSHD_H
|
||||
|
||||
#include "auth.h"
|
||||
|
||||
typedef struct WOLFSSHD_CONFIG WOLFSSHD_CONFIG;
|
||||
|
||||
#define WOLFSSHD_PRIV_SEPARAT 0
|
||||
|
|
@ -35,6 +37,9 @@ char* wolfSSHD_GetBanner(WOLFSSHD_CONFIG* conf);
|
|||
char* wolfSSHD_GetHostPrivateKey(WOLFSSHD_CONFIG* conf);
|
||||
int wolfSSHD_SetHostPrivateKey(WOLFSSHD_CONFIG* conf, const char* hostKeyFile);
|
||||
word16 wolfSSHD_GetPort(WOLFSSHD_CONFIG* conf);
|
||||
char* wolfSSHD_GetAuthKeysFile(WOLFSSHD_CONFIG* conf);
|
||||
int wolfSSHD_SetAuthKeysFile(WOLFSSHD_CONFIG* conf, const char* file);
|
||||
|
||||
|
||||
#endif /* WOLFSSHD_H */
|
||||
|
||||
|
|
@ -238,6 +238,10 @@ AS_IF([test "x$ENABLED_SMALLSTACK" = "xyes"],
|
|||
AS_IF([test "x$ENABLED_SSHD" = "xyes"],
|
||||
[AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSH_SSHD"])
|
||||
|
||||
if test "$ENABLED_SSHD" = "yes"; then
|
||||
AC_CHECK_LIB([crypt], [crypt], [], [AC_MSG_ERROR([libcrypt is required for sshd])])
|
||||
fi
|
||||
|
||||
# Set the automake conditionals.
|
||||
AM_CONDITIONAL([BUILD_EXAMPLE_SERVERS],[test "x$ENABLED_EXAMPLES" = "xyes"])
|
||||
AM_CONDITIONAL([BUILD_EXAMPLE_CLIENTS],[test "x$ENABLED_EXAMPLES" = "xyes"])
|
||||
|
|
|
|||
Loading…
Reference in New Issue