From 475ee1f113ccd9bdd29e5be06785ae7696f781c2 Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Wed, 6 Jul 2022 16:22:44 -0600 Subject: [PATCH] add wolfauth file for peer auth --- apps/include.am | 6 +- apps/wolfauth.c | 256 ++++++++++++++++++++++++++++++++++++++++++++++ apps/wolfconfig.c | 37 ++++++- apps/wolfsshd.c | 145 +++++++++++++++++--------- apps/wolfsshd.h | 4 + 5 files changed, 394 insertions(+), 54 deletions(-) create mode 100644 apps/wolfauth.c diff --git a/apps/include.am b/apps/include.am index eddc4c60..114ba9a0 100644 --- a/apps/include.am +++ b/apps/include.am @@ -3,9 +3,11 @@ if BUILD_SSHD bin_PROGRAMS += apps/wolfsshd -noinst_HEADERS += apps/wolfsshd.h +noinst_HEADERS += apps/wolfsshd.h \ + apps/wolfauth.h apps_wolfsshd_SOURCES = apps/wolfsshd.c \ - apps/wolfconfig.c + apps/wolfconfig.c \ + apps/wolfauth.c apps_wolfsshd_LDADD = src/libwolfssh.la apps_wolfsshd_DEPENDENCIES = src/libwolfssh.la endif diff --git a/apps/wolfauth.c b/apps/wolfauth.c new file mode 100644 index 00000000..fa98f8a4 --- /dev/null +++ b/apps/wolfauth.c @@ -0,0 +1,256 @@ +/* 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 . + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#ifdef WOLFSSH_SSHD + +#include +#include +#include +#include +#include + +#ifdef NO_INLINE + #include +#else + #define WOLFSSH_MISC_INCLUDED + #include "src/misc.c" +#endif + +#include "wolfauth.h" + +#include + +#include +#include +#include + +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 */ diff --git a/apps/wolfconfig.c b/apps/wolfconfig.c index 91d86241..c745f388 100644 --- a/apps/wolfconfig.c +++ b/apps/wolfconfig.c @@ -52,11 +52,11 @@ struct WOLFSSHD_CONFIG { char* listenAddress; char* authKeysFile; word16 port; + byte usePrivilegeSeparation; byte passwordAuth:1; byte pubKeyAuth:1; byte permitRootLogin:1; byte permitEmptyPasswords:1; - byte usePrivilegeSeparation:1; }; /* returns WS_SUCCESS on success */ @@ -141,7 +141,8 @@ static int wolfSSHD_ParseConfigLine(WOLFSSHD_CONFIG* conf, const char* l, int sz; /* supported config options */ - const char authKeyFile[] = "AuthorizedKeysFile"; + const char authKeyFile[] = "AuthorizedKeysFile"; + const char privilegeSeparation[] = "UsePrivilegeSeparation"; sz = (int)XSTRLEN(authKeyFile); if (lSz > sz && XSTRNCMP(l, authKeyFile, sz) == 0) { @@ -149,8 +150,32 @@ static int wolfSSHD_ParseConfigLine(WOLFSSHD_CONFIG* conf, const char* l, conf->heap); } - if (XSTRNCMP(l, "UsePrivilegeSeparation", 18) == 0) { - ret = WS_SUCCESS; + sz = (int)XSTRLEN(privilegeSeparation); + if (lSz > sz && XSTRNCMP(l, privilegeSeparation, sz) == 0) { + char* privType = NULL; + ret = wolfSSHD_CreateString(&privType, l + sz, lSz - sz, conf->heap); + + /* check if is an allowed option */ + if (XSTRNCMP(privType, "sandbox", 7) == 0) { + wolfSSH_Log(WS_LOG_INFO, "[SSHD] Sandbox privilege separation"); + ret = WS_SUCCESS; + } + + if (XSTRNCMP(privType, "yes", 3) == 0) { + wolfSSH_Log(WS_LOG_INFO, "[SSHD] Privilege separation enabled"); + ret = WS_SUCCESS; + } + + if (XSTRNCMP(privType, "no", 2) == 0) { + wolfSSH_Log(WS_LOG_INFO, "[SSHD] Turning off privilege separation!"); + ret = WS_SUCCESS; + } + + if (ret != WS_SUCCESS) { + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Unknown/supported privilege separation!"); + } + wolfSSHD_FreeString(&privType, conf->heap); } if (XSTRNCMP(l, "Subsystem", 9) == 0) { @@ -201,9 +226,11 @@ int wolfSSHD_LoadSSHD(WOLFSSHD_CONFIG* conf, const char* filename) f = XFOPEN(filename, "rb"); if (f == XBADFILE) { - printf("Unable to open SSHD config file %s\n", filename); + wolfSSH_Log(WS_LOG_ERROR, "Unable to open SSHD config file %s\n", + filename); return BAD_FUNC_ARG; } + wolfSSH_Log(WS_LOG_INFO, "[SSHD] parsing config file %s", filename); while ((current = XFGETS(buf, MAX_LINE_SIZE, f)) != NULL) { int currentSz = (int)XSTRLEN(current); diff --git a/apps/wolfsshd.c b/apps/wolfsshd.c index 48d9c554..1e2430c8 100644 --- a/apps/wolfsshd.c +++ b/apps/wolfsshd.c @@ -34,6 +34,7 @@ #include #include "wolfsshd.h" +#include "wolfauth.h" #include @@ -70,6 +71,8 @@ } #endif /* WOLFSSH_SHELL */ +static volatile byte debugMode = 0; /* default to off */ + /* catch interrupts and close down gracefully */ static volatile byte quit = 0; static const char defaultBanner[] = "wolfSSHD\n"; @@ -86,6 +89,7 @@ static void ShowUsage(void) printf(" -? display this help and exit\n"); printf(" -f Configuration file to use, default is /usr/locacl/etc/ssh/sshd_config\n"); printf(" -p Port number to listen on\n"); + printf(" -d Turn on debug mode\n"); } static void interruptCatch(int in) @@ -97,35 +101,10 @@ static void interruptCatch(int in) static void wolfSSHDLoggingCb(enum wolfSSH_LogLevel lvl, const char *const str) { - fprintf(stderr, "[PID %d]: %s\n", getpid(), str); - (void)lvl; -} - -static int wsUserAuth(byte authType, - WS_UserAuthData* authData, - void* ctx) -{ -// if (ctx == NULL) { -// fprintf(stderr, "wsUserAuth: ctx not set"); -// return WOLFSSH_USERAUTH_FAILURE; -// } - - if (authType != WOLFSSH_USERAUTH_PASSWORD && -#ifdef WOLFSSH_ALLOW_USERAUTH_NONE - authType != WOLFSSH_USERAUTH_NONE && -#endif - authType != WOLFSSH_USERAUTH_PUBLICKEY) { - - return WOLFSSH_USERAUTH_FAILURE; + if (debugMode) { + fprintf(stderr, "[PID %d]: %s\n", getpid(), str); } - - (void)ctx; - (void)authData; - - fprintf(stderr, "returning success always for now"); - - /* @TODO allows all connections */ - return WOLFSSH_USERAUTH_SUCCESS; + (void)lvl; } @@ -143,7 +122,7 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx) /* setup authority callback for checking peer connections */ if (ret == WS_SUCCESS) { - wolfSSH_SetUserAuth(*ctx, wsUserAuth); + wolfSSH_SetUserAuth(*ctx, DefaultUserAuth); } /* set banner to display on connection */ @@ -270,12 +249,67 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx) } -#if 0 -int SFTP_Subsystem() +#ifdef WOLFSSH_SFTP +/* handle SFTP operations + * returns 0 on success + */ +static int SFTP_Subsystem(WOLFSSH* ssh, WOLFSSHD_CONNECTION* conn) { + byte tmp[1]; + int ret = WS_SUCCESS; + int error = WS_SUCCESS; + WS_SOCKET_T sockfd; + int select_ret = 0; + sockfd = (WS_SOCKET_T)wolfSSH_get_fd(ssh); + do { +// if (threadCtx->nonBlock) { +// if (error == WS_WANT_READ) +// printf("... sftp server would read block\n"); +// else if (error == WS_WANT_WRITE) +// printf("... sftp server would write block\n"); +// } + + if (wolfSSH_stream_peek(ssh, tmp, 1) > 0) { + select_ret = WS_SELECT_RECV_READY; + } + else { + select_ret = tcp_select(sockfd, TEST_SFTP_TIMEOUT); + } + + if (select_ret == WS_SELECT_RECV_READY || + select_ret == WS_SELECT_ERROR_READY || + error == WS_WANT_WRITE) + { + ret = wolfSSH_SFTP_read(ssh); + error = wolfSSH_get_error(ssh); + } + else if (select_ret == WS_SELECT_TIMEOUT) + error = WS_WANT_READ; + else + error = WS_FATAL_ERROR; + + if (error == WS_WANT_READ || error == WS_WANT_WRITE || + error == WS_CHAN_RXD || error == WS_REKEYING || + error == WS_WINDOW_FULL) + ret = error; + + if (ret == WS_FATAL_ERROR && error == 0) { + WOLFSSH_CHANNEL* channel = + wolfSSH_ChannelNext(ssh, NULL); + if (channel && wolfSSH_ChannelGetEof(channel)) { + ret = 0; + break; + } + } + } while (ret != WS_FATAL_ERROR); + + return ret; } +#endif + +#ifdef WOLFSSH_SCP int SCP_Subsystem() { @@ -457,14 +491,25 @@ static void* wolfSSHD_HandleConnection(void* arg) } } -#ifdef WOLFSSH_SHELL - printf("ret of accept = %d\n",ret); - if (ret == WS_SUCCESS) { - printf("trying to run shell\n"); - wolfSSH_Log(WS_LOG_INFO, "[SSHD] Entering new shell"); - SHELL_Subsystem(conn, ssh); + switch (ret) { + case WS_SFTP_COMPLETE: + #ifdef WOLFSSH_SFTP + ret = SFTP_Subsystem(ssh, conn); + #else + err_sys("SFTP not compiled in. Please use --enable-sftp"); + #endif + break; + + case WS_SUCCESS: /* default success case to shell */ + #ifdef WOLFSSH_SHELL + printf("ret of accept = %d\n",ret); + if (ret == WS_SUCCESS) { + wolfSSH_Log(WS_LOG_INFO, "[SSHD] Entering new shell"); + SHELL_Subsystem(conn, ssh); + } + #endif + break; } -#endif wolfSSH_shutdown(ssh); wolfSSH_free(ssh); @@ -573,21 +618,23 @@ int main(int argc, char** argv) } - while ((ch = mygetopt(argc, argv, "?f:p:h:")) != -1) { + while ((ch = mygetopt(argc, argv, "?f:p:h:d")) != -1) { switch (ch) { case 'f': configFile = myoptarg; break; case 'p': - ret = XATOI(myoptarg); - if (ret < 0) { - printf("Issue parsing port number %s\n", myoptarg); - ret = BAD_FUNC_ARG; - } - else { - port = (word16)ret; - ret = WS_SUCCESS; + if (ret == WS_SUCCESS) { + ret = XATOI(myoptarg); + if (ret < 0) { + printf("Issue parsing port number %s\n", myoptarg); + ret = BAD_FUNC_ARG; + } + else { + port = (word16)ret; + ret = WS_SUCCESS; + } } break; @@ -595,6 +642,10 @@ int main(int argc, char** argv) hostKeyFile = myoptarg; break; + case 'd': + debugMode = 1; /* turn on debug mode */ + break; + case '?': ShowUsage(); return WS_SUCCESS; diff --git a/apps/wolfsshd.h b/apps/wolfsshd.h index aa216a3c..47650711 100644 --- a/apps/wolfsshd.h +++ b/apps/wolfsshd.h @@ -23,6 +23,10 @@ typedef struct WOLFSSHD_CONFIG WOLFSSHD_CONFIG; +#define WOLFSSHD_PRIV_SEPARAT 0 +#define WOLFSSHD_PRIV_SANDBOX 1 +#define WOLFSSHD_PRIV_OFF 2 + WOLFSSHD_CONFIG* wolfSSHD_NewConfig(void* heap); void wolfSSHD_FreeConfig(WOLFSSHD_CONFIG* conf); int wolfSSHD_LoadSSHD(WOLFSSHD_CONFIG* conf, const char* filename);