|
@@ -65,26 +65,6 @@ typedef struct {
|
|
#endif
|
|
#endif
|
|
#define SCRATCH_BUFFER_SZ 1200
|
|
#define SCRATCH_BUFFER_SZ 1200
|
|
|
|
|
|
-
|
|
|
|
-static byte find_char(const byte* str, const byte* buf, word32 bufSz)
|
|
|
|
-{
|
|
|
|
- const byte* cur;
|
|
|
|
-
|
|
|
|
- while (bufSz) {
|
|
|
|
- cur = str;
|
|
|
|
- while (*cur != '\0') {
|
|
|
|
- if (*cur == *buf)
|
|
|
|
- return *cur;
|
|
|
|
- cur++;
|
|
|
|
- }
|
|
|
|
- buf++;
|
|
|
|
- bufSz--;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
static int dump_stats(thread_ctx_t* ctx)
|
|
static int dump_stats(thread_ctx_t* ctx)
|
|
{
|
|
{
|
|
@@ -153,6 +133,9 @@ static void *server_worker(void* vArgs)
|
|
int ret;
|
|
int ret;
|
|
thread_ctx_t* threadCtx = (thread_ctx_t*)vArgs;
|
|
thread_ctx_t* threadCtx = (thread_ctx_t*)vArgs;
|
|
|
|
|
|
|
|
+ user_level_t user_id;
|
|
|
|
+ wolfSSH_SetUserAuthCtx(threadCtx->ssh, &user_id);
|
|
|
|
+
|
|
if (!threadCtx->nonBlock)
|
|
if (!threadCtx->nonBlock)
|
|
ret = wolfSSH_accept(threadCtx->ssh);
|
|
ret = wolfSSH_accept(threadCtx->ssh);
|
|
else
|
|
else
|
|
@@ -272,268 +255,27 @@ static INLINE void c32toa(word32 u32, byte* c)
|
|
c[3] = u32 & 0xff;
|
|
c[3] = u32 & 0xff;
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
-/* 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. */
|
|
|
|
-typedef struct PwMap {
|
|
|
|
- byte type;
|
|
|
|
- byte username[32];
|
|
|
|
- word32 usernameSz;
|
|
|
|
- byte p[SHA256_DIGEST_SIZE];
|
|
|
|
- struct PwMap* next;
|
|
|
|
-} PwMap;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-typedef struct PwMapList {
|
|
|
|
- PwMap* head;
|
|
|
|
-} PwMapList;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-static PwMap* PwMapNew(PwMapList* list, byte type, const byte* username,
|
|
|
|
- word32 usernameSz, const byte* p, word32 pSz)
|
|
|
|
-{
|
|
|
|
- PwMap* map;
|
|
|
|
-
|
|
|
|
- map = (PwMap*)malloc(sizeof(PwMap));
|
|
|
|
- if (map != NULL) {
|
|
|
|
- Sha256 sha;
|
|
|
|
- byte flatSz[4];
|
|
|
|
-
|
|
|
|
- map->type = type;
|
|
|
|
- if (usernameSz >= sizeof(map->username))
|
|
|
|
- usernameSz = sizeof(map->username) - 1;
|
|
|
|
- memcpy(map->username, username, usernameSz + 1);
|
|
|
|
- map->username[usernameSz] = 0;
|
|
|
|
- map->usernameSz = usernameSz;
|
|
|
|
-
|
|
|
|
- wc_InitSha256(&sha);
|
|
|
|
- c32toa(pSz, flatSz);
|
|
|
|
- wc_Sha256Update(&sha, flatSz, sizeof(flatSz));
|
|
|
|
- wc_Sha256Update(&sha, p, pSz);
|
|
|
|
- wc_Sha256Final(&sha, map->p);
|
|
|
|
-
|
|
|
|
- map->next = list->head;
|
|
|
|
- list->head = map;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return map;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-static void PwMapListDelete(PwMapList* list)
|
|
|
|
-{
|
|
|
|
- if (list != NULL) {
|
|
|
|
- PwMap* head = list->head;
|
|
|
|
-
|
|
|
|
- while (head != NULL) {
|
|
|
|
- PwMap* cur = head;
|
|
|
|
- head = head->next;
|
|
|
|
- memset(cur, 0, sizeof(PwMap));
|
|
|
|
- free(cur);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-static const char samplePasswordBuffer[] =
|
|
|
|
- "jill:upthehill\n"
|
|
|
|
- "jack:fetchapail\n";
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-static const char samplePublicKeyEccBuffer[] =
|
|
|
|
- "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAA"
|
|
|
|
- "BBBNkI5JTP6D0lF42tbxX19cE87hztUS6FSDoGvPfiU0CgeNSbI+aFdKIzTP5CQEJSvm25"
|
|
|
|
- "qUzgDtH7oyaQROUnNvk= hansel\n"
|
|
|
|
- "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAA"
|
|
|
|
- "BBBKAtH8cqaDbtJFjtviLobHBmjCtG56DMkP6A4M2H9zX2/YCg1h9bYS7WHd9UQDwXO1Hh"
|
|
|
|
- "IZzRYecXh7SG9P4GhRY= gretel\n";
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-static const char samplePublicKeyRsaBuffer[] =
|
|
|
|
- "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9P3ZFowOsONXHD5MwWiCciXytBRZGho"
|
|
|
|
- "MNiisWSgUs5HdHcACuHYPi2W6Z1PBFmBWT9odOrGRjoZXJfDDoPi+j8SSfDGsc/hsCmc3G"
|
|
|
|
- "p2yEhUZUEkDhtOXyqjns1ickC9Gh4u80aSVtwHRnJZh9xPhSq5tLOhId4eP61s+a5pwjTj"
|
|
|
|
- "nEhBaIPUJO2C/M0pFnnbZxKgJlX7t1Doy7h5eXxviymOIvaCZKU+x5OopfzM/wFkey0EPW"
|
|
|
|
- "NmzI5y/+pzU5afsdeEWdiQDIQc80H6Pz8fsoFPvYSG+s4/wz0duu7yeeV1Ypoho65Zr+pE"
|
|
|
|
- "nIf7dO0B8EblgWt+ud+JI8wrAhfE4x hansel\n"
|
|
|
|
- "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqDwRVTRVk/wjPhoo66+Mztrc31KsxDZ"
|
|
|
|
- "+kAV0139PHQ+wsueNpba6jNn5o6mUTEOrxrz0LMsDJOBM7CmG0983kF4gRIihECpQ0rcjO"
|
|
|
|
- "P6BSfbVTE9mfIK5IsUiZGd8SoE9kSV2pJ2FvZeBQENoAxEFk0zZL9tchPS+OCUGbK4SDjz"
|
|
|
|
- "uNZl/30Mczs73N3MBzi6J1oPo7sFlqzB6ecBjK2Kpjus4Y1rYFphJnUxtKvB0s+hoaadru"
|
|
|
|
- "biE57dK6BrH5iZwVLTQKux31uCJLPhiktI3iLbdlGZEctJkTasfVSsUizwVIyRjhVKmbdI"
|
|
|
|
- "RGwkU38D043AR1h0mUoGCPIKuqcFMf gretel\n";
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-static int LoadPasswordBuffer(byte* buf, word32 bufSz, PwMapList* list)
|
|
|
|
-{
|
|
|
|
- char* str = (char*)buf;
|
|
|
|
- char* delimiter;
|
|
|
|
- char* username;
|
|
|
|
- char* password;
|
|
|
|
-
|
|
|
|
- /* Each line of passwd.txt is in the format
|
|
|
|
- * username:password\n
|
|
|
|
- * This function modifies the passed-in buffer. */
|
|
|
|
-
|
|
|
|
- if (list == NULL)
|
|
|
|
- return -1;
|
|
|
|
-
|
|
|
|
- if (buf == NULL || bufSz == 0)
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
- while (*str != 0) {
|
|
|
|
- delimiter = strchr(str, ':');
|
|
|
|
- if (delimiter == NULL) {
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
- username = str;
|
|
|
|
- *delimiter = 0;
|
|
|
|
- password = delimiter + 1;
|
|
|
|
- str = strchr(password, '\n');
|
|
|
|
- if (str == NULL) {
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
- *str = 0;
|
|
|
|
- str++;
|
|
|
|
- if (PwMapNew(list, WOLFSSH_USERAUTH_PASSWORD,
|
|
|
|
- (byte*)username, (word32)strlen(username),
|
|
|
|
- (byte*)password, (word32)strlen(password)) == NULL ) {
|
|
|
|
-
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-static int LoadPublicKeyBuffer(byte* buf, word32 bufSz, PwMapList* list)
|
|
|
|
|
|
+static int wsUserAuth(byte authType, WS_UserAuthData* authData, void* ctx)
|
|
{
|
|
{
|
|
- char* str = (char*)buf;
|
|
|
|
- char* delimiter;
|
|
|
|
- byte* publicKey64;
|
|
|
|
- word32 publicKey64Sz;
|
|
|
|
- byte* username;
|
|
|
|
- word32 usernameSz;
|
|
|
|
- byte publicKey[300];
|
|
|
|
- word32 publicKeySz;
|
|
|
|
-
|
|
|
|
- /* Each line of passwd.txt is in the format
|
|
|
|
- * ssh-rsa AAAB3BASE64ENCODEDPUBLICKEYBLOB username\n
|
|
|
|
- * This function modifies the passed-in buffer. */
|
|
|
|
- if (list == NULL)
|
|
|
|
- return -1;
|
|
|
|
-
|
|
|
|
- if (buf == NULL || bufSz == 0)
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
- while (*str != 0) {
|
|
|
|
- /* Skip the public key type. This example will always be ssh-rsa. */
|
|
|
|
- delimiter = strchr(str, ' ');
|
|
|
|
- if (delimiter == NULL) {
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
- str = delimiter + 1;
|
|
|
|
- delimiter = strchr(str, ' ');
|
|
|
|
- if (delimiter == NULL) {
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
- publicKey64 = (byte*)str;
|
|
|
|
- *delimiter = 0;
|
|
|
|
- publicKey64Sz = (word32)(delimiter - str);
|
|
|
|
- str = delimiter + 1;
|
|
|
|
- delimiter = strchr(str, '\n');
|
|
|
|
- if (delimiter == NULL) {
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
- username = (byte*)str;
|
|
|
|
- *delimiter = 0;
|
|
|
|
- usernameSz = (word32)(delimiter - str);
|
|
|
|
- str = delimiter + 1;
|
|
|
|
- publicKeySz = sizeof(publicKey);
|
|
|
|
-
|
|
|
|
- if (Base64_Decode(publicKey64, publicKey64Sz,
|
|
|
|
- publicKey, &publicKeySz) != 0) {
|
|
|
|
-
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (PwMapNew(list, WOLFSSH_USERAUTH_PUBLICKEY,
|
|
|
|
- username, usernameSz,
|
|
|
|
- publicKey, publicKeySz) == NULL ) {
|
|
|
|
-
|
|
|
|
- return -1;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-static int wsUserAuth(byte authType,
|
|
|
|
- WS_UserAuthData* authData,
|
|
|
|
- void* ctx)
|
|
|
|
-{
|
|
|
|
- PwMapList* list;
|
|
|
|
- PwMap* map;
|
|
|
|
- byte authHash[SHA256_DIGEST_SIZE];
|
|
|
|
|
|
+ user_level_t *user_id = ctx;
|
|
|
|
|
|
if (ctx == NULL) {
|
|
if (ctx == NULL) {
|
|
printf("wsUserAuth: ctx not set");
|
|
printf("wsUserAuth: ctx not set");
|
|
return WOLFSSH_USERAUTH_FAILURE;
|
|
return WOLFSSH_USERAUTH_FAILURE;
|
|
}
|
|
}
|
|
|
|
|
|
- if (authType != WOLFSSH_USERAUTH_PASSWORD &&
|
|
|
|
- authType != WOLFSSH_USERAUTH_PUBLICKEY) {
|
|
|
|
|
|
+ if (authType != WOLFSSH_USERAUTH_PASSWORD) {
|
|
|
|
|
|
return WOLFSSH_USERAUTH_FAILURE;
|
|
return WOLFSSH_USERAUTH_FAILURE;
|
|
}
|
|
}
|
|
|
|
|
|
- /* Hash the password or public key with its length. */
|
|
|
|
- {
|
|
|
|
- Sha256 sha;
|
|
|
|
- byte flatSz[4];
|
|
|
|
- wc_InitSha256(&sha);
|
|
|
|
- if (authType == WOLFSSH_USERAUTH_PASSWORD) {
|
|
|
|
- c32toa(authData->sf.password.passwordSz, flatSz);
|
|
|
|
- wc_Sha256Update(&sha, flatSz, sizeof(flatSz));
|
|
|
|
- wc_Sha256Update(&sha,
|
|
|
|
- authData->sf.password.password,
|
|
|
|
- authData->sf.password.passwordSz);
|
|
|
|
- }
|
|
|
|
- else if (authType == WOLFSSH_USERAUTH_PUBLICKEY) {
|
|
|
|
- c32toa(authData->sf.publicKey.publicKeySz, flatSz);
|
|
|
|
- wc_Sha256Update(&sha, flatSz, sizeof(flatSz));
|
|
|
|
- wc_Sha256Update(&sha,
|
|
|
|
- authData->sf.publicKey.publicKey,
|
|
|
|
- authData->sf.publicKey.publicKeySz);
|
|
|
|
- }
|
|
|
|
- wc_Sha256Final(&sha, authHash);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- list = (PwMapList*)ctx;
|
|
|
|
- map = list->head;
|
|
|
|
-
|
|
|
|
- while (map != NULL) {
|
|
|
|
- if (authData->usernameSz == map->usernameSz &&
|
|
|
|
- memcmp(authData->username, map->username, map->usernameSz) == 0) {
|
|
|
|
-
|
|
|
|
- if (authData->type == map->type) {
|
|
|
|
- if (memcmp(map->p, authHash, SHA256_DIGEST_SIZE) == 0) {
|
|
|
|
- return WOLFSSH_USERAUTH_SUCCESS;
|
|
|
|
- }
|
|
|
|
- else {
|
|
|
|
- return (authType == WOLFSSH_USERAUTH_PASSWORD ?
|
|
|
|
- WOLFSSH_USERAUTH_INVALID_PASSWORD :
|
|
|
|
- WOLFSSH_USERAUTH_INVALID_PUBLICKEY);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- else {
|
|
|
|
- return WOLFSSH_USERAUTH_INVALID_AUTHTYPE;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- map = map->next;
|
|
|
|
|
|
+ // the incoming password is not zero-terminated
|
|
|
|
+ char password[MAX_WEB_PASSWD_LEN];
|
|
|
|
+ strncpy(password, authData->sf.password.password, sizeof(password));
|
|
|
|
+ password[min(MAX_WEB_PASSWD_LEN - 1, authData->sf.password.passwordSz)] = 0;
|
|
|
|
+ *user_id = cli_auth_user(authData->username, password);
|
|
|
|
+ if (*user_id != MAX_USER_LEVELS) {
|
|
|
|
+ return WOLFSSH_USERAUTH_SUCCESS;
|
|
}
|
|
}
|
|
|
|
|
|
return WOLFSSH_USERAUTH_INVALID_USER;
|
|
return WOLFSSH_USERAUTH_INVALID_USER;
|
|
@@ -549,14 +291,12 @@ static void ssh_server(void *arg)
|
|
#endif
|
|
#endif
|
|
wolfSSH_Init();
|
|
wolfSSH_Init();
|
|
WOLFSSH_CTX* ctx = NULL;
|
|
WOLFSSH_CTX* ctx = NULL;
|
|
- PwMapList pwMapList;
|
|
|
|
SOCKET_T listenFd = 0;
|
|
SOCKET_T listenFd = 0;
|
|
word32 defaultHighwater = EXAMPLE_HIGHWATER_MARK;
|
|
word32 defaultHighwater = EXAMPLE_HIGHWATER_MARK;
|
|
word32 threadCount = 0;
|
|
word32 threadCount = 0;
|
|
word16 port = 22;
|
|
word16 port = 22;
|
|
const char multipleConnections = 1;
|
|
const char multipleConnections = 1;
|
|
char useEcc = 1;
|
|
char useEcc = 1;
|
|
- int ch;
|
|
|
|
char nonBlock = 0;
|
|
char nonBlock = 0;
|
|
|
|
|
|
if (wolfSSH_Init() != WS_SUCCESS) {
|
|
if (wolfSSH_Init() != WS_SUCCESS) {
|
|
@@ -570,12 +310,10 @@ static void ssh_server(void *arg)
|
|
exit(EXIT_FAILURE);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
|
|
- memset(&pwMapList, 0, sizeof(pwMapList));
|
|
|
|
wolfSSH_SetUserAuth(ctx, wsUserAuth);
|
|
wolfSSH_SetUserAuth(ctx, wsUserAuth);
|
|
wolfSSH_CTX_SetBanner(ctx, serverBanner);
|
|
wolfSSH_CTX_SetBanner(ctx, serverBanner);
|
|
|
|
|
|
{
|
|
{
|
|
- const char* bufName;
|
|
|
|
byte buf[SCRATCH_BUFFER_SZ];
|
|
byte buf[SCRATCH_BUFFER_SZ];
|
|
word32 bufSz;
|
|
word32 bufSz;
|
|
|
|
|
|
@@ -589,18 +327,6 @@ static void ssh_server(void *arg)
|
|
printf("Couldn't use key buffer.\n");
|
|
printf("Couldn't use key buffer.\n");
|
|
exit(EXIT_FAILURE);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
-
|
|
|
|
- bufSz = (word32)strlen(samplePasswordBuffer);
|
|
|
|
- memcpy(buf, samplePasswordBuffer, bufSz);
|
|
|
|
- buf[bufSz] = 0;
|
|
|
|
- LoadPasswordBuffer(buf, bufSz, &pwMapList);
|
|
|
|
-
|
|
|
|
- bufName = useEcc ? samplePublicKeyEccBuffer :
|
|
|
|
- samplePublicKeyRsaBuffer;
|
|
|
|
- bufSz = (word32)strlen(bufName);
|
|
|
|
- memcpy(buf, bufName, bufSz);
|
|
|
|
- buf[bufSz] = 0;
|
|
|
|
- LoadPublicKeyBuffer(buf, bufSz, &pwMapList);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
tcp_listen(&listenFd, &port, 1, false, false);
|
|
tcp_listen(&listenFd, &port, 1, false, false);
|
|
@@ -626,7 +352,6 @@ static void ssh_server(void *arg)
|
|
printf("Couldn't allocate SSH data.\n");
|
|
printf("Couldn't allocate SSH data.\n");
|
|
exit(EXIT_FAILURE);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
- wolfSSH_SetUserAuthCtx(ssh, &pwMapList);
|
|
|
|
/* Use the session object for its own highwater callback ctx */
|
|
/* Use the session object for its own highwater callback ctx */
|
|
if (defaultHighwater > 0) {
|
|
if (defaultHighwater > 0) {
|
|
wolfSSH_SetHighwaterCtx(ssh, (void*)ssh);
|
|
wolfSSH_SetHighwaterCtx(ssh, (void*)ssh);
|
|
@@ -660,7 +385,6 @@ static void ssh_server(void *arg)
|
|
#endif /* SINGLE_THREADED */
|
|
#endif /* SINGLE_THREADED */
|
|
} while (multipleConnections);
|
|
} while (multipleConnections);
|
|
|
|
|
|
- PwMapListDelete(&pwMapList);
|
|
|
|
wolfSSH_CTX_free(ctx);
|
|
wolfSSH_CTX_free(ctx);
|
|
if (wolfSSH_Cleanup() != WS_SUCCESS) {
|
|
if (wolfSSH_Cleanup() != WS_SUCCESS) {
|
|
printf("Couldn't clean up wolfSSH.\n");
|
|
printf("Couldn't clean up wolfSSH.\n");
|
|
@@ -669,8 +393,6 @@ static void ssh_server(void *arg)
|
|
#if defined(HAVE_ECC) && defined(FP_ECC) && defined(HAVE_THREAD_LS)
|
|
#if defined(HAVE_ECC) && defined(FP_ECC) && defined(HAVE_THREAD_LS)
|
|
wc_ecc_fp_free(); /* free per thread cache */
|
|
wc_ecc_fp_free(); /* free per thread cache */
|
|
#endif
|
|
#endif
|
|
-
|
|
|
|
- return 0;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
void ssh_server_init(void)
|
|
void ssh_server_init(void)
|