Files
m241Neelima/components/ip_net2-6.9/ipssh/src/ipssh_c_api.c
T
2026-07-30 11:19:44 +05:30

462 lines
13 KiB
C

/*
******************************************************************************
* 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
****************************************************************************
*/