original files of m241
This commit is contained in:
@@ -0,0 +1,461 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
* INTERPEAK SOURCE FILE
|
||||
*
|
||||
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipssh_c_api.c,v $ $Revision: 1.4.8.2 $
|
||||
* $Source: /home/interpeak/CVSRoot/ipssh/src/ipssh_c_api.c,v $
|
||||
* $Author: svc-cmnet $
|
||||
* $State: Exp $ $Locker: $
|
||||
*
|
||||
* INTERPEAK_COPYRIGHT_STRING
|
||||
* Design and implementation by Roger Boden <roger.boden@windriver.com>
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 1 DESCRIPTION
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 2 CONFIGURATION
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#include "ipssh_config.h"
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 3 INCLUDE FILES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#define IPCOM_USE_CLIB_PROTO
|
||||
#include "ipcom_clib.h"
|
||||
#include <ipcom_type.h>
|
||||
#include "ipcom_cstyle.h"
|
||||
#include "ipcom_err.h"
|
||||
#include "ipcom_os.h"
|
||||
#include "ipcom_sock.h"
|
||||
#include "ipcom_sock2.h"
|
||||
#include "ipcom_strlib.h"
|
||||
#ifdef IPCOM_USE_SYSLOG
|
||||
#undef IPCOM_USE_SYSLOG
|
||||
#endif
|
||||
#include "ipcom_syslog.h"
|
||||
|
||||
#include "ipssh.h"
|
||||
/* #include "ipssh_h.h" */
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 4 DEFINES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 5 TYPES
|
||||
****************************************************************************
|
||||
*/
|
||||
struct Ipssh_c_api_params_st
|
||||
{
|
||||
Ip_u16 port;
|
||||
Ip_u16 pad;
|
||||
int sh_param_len;
|
||||
Ip_u8 sh_param[1];
|
||||
};
|
||||
typedef struct Ipssh_c_api_params_st Ipssh_c_api_params;
|
||||
|
||||
|
||||
struct Ipssh_c_api_ctx_st
|
||||
{
|
||||
Ip_fd stdio_sock;
|
||||
Ip_fd peer_sock;
|
||||
};
|
||||
typedef struct Ipssh_c_api_ctx_st Ipssh_c_api_ctx;
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 6 EXTERN PROTOTYPES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 7 LOCAL PROTOTYPES
|
||||
****************************************************************************
|
||||
*/
|
||||
IPCOM_PROCESS(ipssh_c_api_proxy);
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 8 DATA
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 9 STATIC FUNCTIONS
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 10 GLOBAL FUNCTIONS
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
IPCOM_PROCESS(ipssh_c_api_proxy)
|
||||
{
|
||||
Ipssh_c_api_params *sinfo;
|
||||
char read_buf[256];
|
||||
struct Ip_addrinfo hints;
|
||||
struct Ip_linger linger;
|
||||
int enable = IP_TRUE;
|
||||
char stdio_port_str[6];
|
||||
struct Ip_addrinfo *res = IP_NULL;
|
||||
int sockerr;
|
||||
void* shell_handle;
|
||||
Ipcom_shell_ctx* sh_ctx = IP_NULL;
|
||||
Ipssh_c_api_ctx* proxy_ctx = IP_NULL;
|
||||
char* user = IP_NULL;
|
||||
|
||||
ipcom_proc_init();
|
||||
|
||||
if (ipcom_ipc_install() != IPCOM_SUCCESS)
|
||||
goto exit;
|
||||
|
||||
if (ipcom_ipc_receive(IP_NULL, &sinfo, IPC_TIMEOUT_INFINITE) != IPCOM_SUCCESS)
|
||||
goto exit;
|
||||
(void)ipcom_ipc_uninstall();
|
||||
|
||||
sh_ctx = ipcom_shell_ctx_new(sinfo->sh_param_len);
|
||||
if (!sh_ctx)
|
||||
goto exit;
|
||||
sh_ctx->len = sinfo->sh_param_len;
|
||||
ipcom_memcpy(sh_ctx->buf, sinfo->sh_param, sinfo->sh_param_len);
|
||||
|
||||
/* Get a tcp socket and connect to the SSH daemon listening port */
|
||||
ipcom_memset(&hints, 0, sizeof(hints));
|
||||
#ifdef IPCOM_USE_INET
|
||||
hints.ai_family = IP_AF_INET;
|
||||
#else
|
||||
hints.ai_family = IP_AF_INET6;
|
||||
#endif
|
||||
hints.ai_socktype = IP_SOCK_STREAM;
|
||||
ipcom_sprintf(stdio_port_str, "%d", (int)sinfo->port);
|
||||
ipcom_ipc_free(sinfo);
|
||||
if (ipcom_getaddrinfo(IP_NULL, stdio_port_str, &hints, &res) != 0)
|
||||
{
|
||||
IPCOM_LOG1(ERR, "ipssh_c_api_proxy :: ipcom_getaddrinfo() failed, errno = %d", ipcom_errno);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
proxy_ctx = ipcom_malloc(sizeof(Ipssh_c_api_ctx));
|
||||
if (!proxy_ctx)
|
||||
goto exit;
|
||||
proxy_ctx->stdio_sock = ipcom_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||
if (proxy_ctx->stdio_sock == IP_INVALID_SOCKET)
|
||||
{
|
||||
IPCOM_LOG1(ERR, "ipssh_c_api_proxy :: ipcom_socket(IP_AF_INET) failed, errno = %d", ipcom_errno);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Note! the SSH daemon side will get a "connection reset by peer" when exiting the
|
||||
shell since the linger time is set to 0 */
|
||||
linger.l_onoff = 1;
|
||||
linger.l_linger = 0;
|
||||
(void)ipcom_setsockopt(proxy_ctx->stdio_sock, IP_SOL_SOCKET, IP_SO_LINGER, &linger, sizeof(linger));
|
||||
|
||||
/*
|
||||
* Disable Nagle (enable no delay) on this socket since it is an
|
||||
* interactive connection
|
||||
*/
|
||||
(void)ipcom_setsockopt(proxy_ctx->stdio_sock, IP_IPPROTO_TCP, IP_TCP_NODELAY, &enable, sizeof(enable));
|
||||
|
||||
sockerr = ipcom_connect(proxy_ctx->stdio_sock, res->ai_addr, res->ai_addrlen);
|
||||
if (sockerr == IP_SOCKERR)
|
||||
{
|
||||
IPCOM_LOG2(ERR,
|
||||
"ipssh_c_api_proxy :: ipcom_connect(IP_AF_INET%s) failed, errno = %d",
|
||||
res->ai_family == IP_AF_INET ? "" : "6",
|
||||
ipcom_errno);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (ipcom_shell_ctx_get_int(sh_ctx, IPSSH_CLT_FD, &proxy_ctx->peer_sock) != IPCOM_SUCCESS)
|
||||
goto exit;
|
||||
user = ipcom_shell_ctx_get_user(sh_ctx);
|
||||
shell_handle = ipssh_shell_start_cb(proxy_ctx, user, sh_ctx);
|
||||
if (user)
|
||||
ipcom_free(user);
|
||||
|
||||
if (!shell_handle)
|
||||
goto exit;
|
||||
|
||||
if (ipssh_shell_welcome_msg_cb(proxy_ctx, shell_handle) != IPCOM_SUCCESS)
|
||||
goto exit;
|
||||
|
||||
/* Main stdio proxy loop */
|
||||
for (;;)
|
||||
{
|
||||
Ip_ssize_t read_bytes;
|
||||
|
||||
read_bytes = ipcom_socketread(proxy_ctx->stdio_sock, read_buf, sizeof(read_buf));
|
||||
if (read_bytes <= 0)
|
||||
{
|
||||
(void)ipssh_shell_stop_cb(proxy_ctx, shell_handle);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (ipssh_shell_stdin_cb(proxy_ctx, shell_handle, read_buf, read_bytes) != IPCOM_SUCCESS)
|
||||
goto exit;
|
||||
|
||||
}
|
||||
|
||||
exit:
|
||||
if (proxy_ctx)
|
||||
{
|
||||
if (proxy_ctx->stdio_sock != IP_INVALID_SOCKET)
|
||||
ipcom_socketclose(proxy_ctx->stdio_sock);
|
||||
ipcom_free(proxy_ctx);
|
||||
}
|
||||
if (res != IP_NULL)
|
||||
ipcom_freeaddrinfo(res);
|
||||
if (sh_ctx)
|
||||
ipcom_shell_ctx_free(sh_ctx);
|
||||
|
||||
ipcom_proc_exit();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* 11 PUBLIC FUNCTIONS
|
||||
****************************************************************************
|
||||
*/
|
||||
IP_PUBLIC Ip_err
|
||||
ipssh_start_shell_c_api(Ip_fd *stdio_sock, const Ipcom_shell_ctx* sh_ctx)
|
||||
{
|
||||
Ip_fd mother = IP_INVALID_SOCKET;
|
||||
Ip_fd shell_fd = IP_INVALID_SOCKET;
|
||||
Ip_socklen_t addr_len;
|
||||
Ipcom_ipc ipc;
|
||||
Ipssh_c_api_params *sinfo;
|
||||
char procname[40];
|
||||
Ip_err retval;
|
||||
Ipcom_proc_attr attr;
|
||||
Ip_bool ipc_opened = IP_FALSE;
|
||||
Ip_pid_t ppid, shell_pid;
|
||||
Ip_u16 mother_port;
|
||||
static Ip_u32 seqno = 0;
|
||||
struct Ip_addrinfo hints;
|
||||
struct Ip_addrinfo *res = IP_NULL;
|
||||
union Ip_sockaddr_union sa;
|
||||
Ip_size_t sh_len = (Ip_size_t) (sh_ctx ? sh_ctx->len : 0);
|
||||
|
||||
*stdio_sock = IP_INVALID_SOCKET;
|
||||
|
||||
sinfo = ipcom_ipc_malloc(sizeof(Ipssh_c_api_params)+sh_len);
|
||||
if (sinfo == IP_NULL)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipssh_start_shell_c_api :: ipcom_ipc_malloc() failed");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
sinfo->sh_param_len = (int) sh_len;
|
||||
if (sh_ctx)
|
||||
ipcom_memcpy(sinfo->sh_param, sh_ctx->buf, (Ip_size_t)sh_ctx->len);
|
||||
|
||||
/* Get a tcp socket and let the stack pick a port */
|
||||
ipcom_memset(&hints, 0, sizeof(hints));
|
||||
#ifdef IPCOM_USE_INET
|
||||
hints.ai_family = IP_AF_INET;
|
||||
#else
|
||||
hints.ai_family = IP_AF_INET6;
|
||||
|
||||
#endif
|
||||
hints.ai_socktype = IP_SOCK_STREAM;
|
||||
if (ipcom_getaddrinfo(IP_NULL, "0", &hints, &res) != 0)
|
||||
{
|
||||
IPCOM_LOG1(ERR, "ipssh_start_shell_c_api :: ipcom_getaddrinfo() failed, errno = %d", ipcom_errno);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mother = ipcom_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||
if (mother == IP_INVALID_SOCKET)
|
||||
{
|
||||
IPCOM_LOG1(ERR, "ipssh_start_shell_c_api :: ipcom_socket(IP_AF_INET) failed, errno = %d", ipcom_errno);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (ipcom_bind(mother, res->ai_addr, (Ip_socklen_t)res->ai_addrlen) == IP_SOCKERR)
|
||||
{
|
||||
IPCOM_LOG1(ERR, "ipssh_start_shell_c_api :: ipcom_bind(IP_AF_INET) failed, errno = %d", ipcom_errno);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Find out which port was assigned. */
|
||||
addr_len = sizeof(sa);
|
||||
if (ipcom_getsockname(mother, (struct Ip_sockaddr *)&sa, &addr_len) == IP_SOCKERR)
|
||||
{
|
||||
IPCOM_LOG1(ERR, "ipssh_start_shell_c_api :: ipcom_getsockname(IP_AF_INET) failed, errno = %d", ipcom_errno);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
#ifdef IPCOM_USE_INET
|
||||
if (sa.sa.sa_family == IP_AF_INET)
|
||||
mother_port = ip_ntohs(sa.sin.sin_port);
|
||||
#endif
|
||||
#ifdef IPCOM_USE_INET6
|
||||
if (sa.sa.sa_family == IP_AF_INET6)
|
||||
mother_port = ip_ntohs(sa.sin6.sin6_port);
|
||||
#endif
|
||||
|
||||
if (ipcom_listen(mother, 1) == IP_SOCKERR)
|
||||
{
|
||||
IPCOM_LOG1(ERR, "ipssh_start_shell_c_api :: ipcom_listen() failed, errno = %d", ipcom_errno);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Create and start the shell process. */
|
||||
ipcom_proc_attr_init(&attr);
|
||||
#ifdef IP_PORT_VXWORKS
|
||||
attr.stacksize = IPCOM_PROC_STACK_LARGE;
|
||||
#else
|
||||
attr.priority = IPCOM_PRIORITY_DEFAULT;
|
||||
#endif /* IP_PORT_VXWORKS */
|
||||
ppid = ipcom_getpid();
|
||||
ipcom_sprintf(procname, "c_api_proxy_%lx_%d", (long)(ppid & 0xffffffff), (int)++seqno);
|
||||
if (ipcom_proc_acreate(procname, (Ipcom_proc_func)ipssh_c_api_proxy, &attr, &shell_pid))
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipssh_start_shell_c_api :: ipcom_proc_acreate() failed");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Open IPC with c_api_proxy. */
|
||||
retval = ipcom_ipc_open(&ipc, procname, -1);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG2(ERR, "ipssh_start_shell_c_api :: ipcom_ipc_open(%s) failed, ret = %d", procname, retval);
|
||||
goto exit;
|
||||
}
|
||||
ipc_opened = IP_TRUE;
|
||||
|
||||
/* Send a message to ipcom_shell. */
|
||||
sinfo->port = mother_port;
|
||||
retval = ipcom_ipc_send(&ipc, sinfo);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG1(ERR, "ipssh_start_shell_c_api :: ipcom_ipc_send() failed, ret = %d", retval);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Wait for the shell process to connect */
|
||||
shell_fd = ipcom_accept(mother, IP_NULL, IP_NULL);
|
||||
|
||||
exit:
|
||||
if (mother != IP_INVALID_SOCKET)
|
||||
(void)ipcom_socketclose(mother);
|
||||
if (res != IP_NULL)
|
||||
ipcom_freeaddrinfo(res);
|
||||
if (ipc_opened)
|
||||
(void)ipcom_ipc_close(&ipc);
|
||||
else if (sinfo != IP_NULL)
|
||||
ipcom_ipc_free(sinfo);
|
||||
|
||||
if (shell_fd == IP_INVALID_SOCKET)
|
||||
return IPCOM_ERR_FAILED;
|
||||
else
|
||||
{
|
||||
int enable = IP_TRUE;
|
||||
|
||||
*stdio_sock = shell_fd;
|
||||
#if IPCOM_USE_SOCK != IPCOM_SOCK_IPLITE
|
||||
/*
|
||||
* Disable Nagle (enable no delay) on this socket since it is an
|
||||
* interactive connection
|
||||
*/
|
||||
(void)ipcom_setsockopt(shell_fd, IP_IPPROTO_TCP, IP_TCP_NODELAY, &enable, sizeof(enable));
|
||||
#endif
|
||||
return IPCOM_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipssh_shell_exit
|
||||
*===========================================================================
|
||||
* Description:
|
||||
* Parameters:
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_PUBLIC Ip_err
|
||||
ipssh_shell_exit(void* ssh_ctx, void* shell_ctx)
|
||||
{
|
||||
Ipssh_c_api_ctx* proxy_ctx = ssh_ctx;
|
||||
|
||||
(void)shell_ctx;
|
||||
|
||||
if (ipcom_shutdown(proxy_ctx->stdio_sock, IP_SHUT_RDWR))
|
||||
return IPCOM_ERR_FAILED;
|
||||
return IPCOM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipssh_send_shell_stdout_data
|
||||
*===========================================================================
|
||||
* Description:
|
||||
* Parameters:
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_PUBLIC int
|
||||
ipssh_send_shell_stdout_data(void* ssh_ctx, void* shell_ctx, const char* data, Ip_ssize_t len)
|
||||
{
|
||||
Ipssh_c_api_ctx* proxy_ctx = ssh_ctx;
|
||||
|
||||
(void)shell_ctx;
|
||||
|
||||
if (ipcom_socketwrite(proxy_ctx->stdio_sock, data, len) != len)
|
||||
return -1;
|
||||
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipssh_get_clt_fd
|
||||
*===========================================================================
|
||||
* Description:
|
||||
* Parameters:
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_PUBLIC Ip_fd
|
||||
ipssh_get_clt_fd(void* ssh_ctx)
|
||||
{
|
||||
Ipssh_c_api_ctx* proxy_ctx = ssh_ctx;
|
||||
|
||||
return proxy_ctx->peer_sock;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* END OF FILE
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user