xref: /aosp_15_r20/external/libwebsockets/test-apps/test-sshd.c (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker  * Example embedded sshd server using libwebsockets sshd plugin
3*1c60b9acSAndroid Build Coastguard Worker  *
4*1c60b9acSAndroid Build Coastguard Worker  * Written in 2010-2019 by Andy Green <[email protected]>
5*1c60b9acSAndroid Build Coastguard Worker  *
6*1c60b9acSAndroid Build Coastguard Worker  * This file is made available under the Creative Commons CC0 1.0
7*1c60b9acSAndroid Build Coastguard Worker  * Universal Public Domain Dedication.
8*1c60b9acSAndroid Build Coastguard Worker  *
9*1c60b9acSAndroid Build Coastguard Worker  * The person who associated a work with this deed has dedicated
10*1c60b9acSAndroid Build Coastguard Worker  * the work to the public domain by waiving all of his or her rights
11*1c60b9acSAndroid Build Coastguard Worker  * to the work worldwide under copyright law, including all related
12*1c60b9acSAndroid Build Coastguard Worker  * and neighboring rights, to the extent allowed by law. You can copy,
13*1c60b9acSAndroid Build Coastguard Worker  * modify, distribute and perform the work, even for commercial purposes,
14*1c60b9acSAndroid Build Coastguard Worker  * all without asking permission.
15*1c60b9acSAndroid Build Coastguard Worker  *
16*1c60b9acSAndroid Build Coastguard Worker  * The test apps are intended to be adapted for use in your code, which
17*1c60b9acSAndroid Build Coastguard Worker  * may be proprietary.	So unlike the library itself, they are licensed
18*1c60b9acSAndroid Build Coastguard Worker  * Public Domain.
19*1c60b9acSAndroid Build Coastguard Worker  *
20*1c60b9acSAndroid Build Coastguard Worker  *
21*1c60b9acSAndroid Build Coastguard Worker  * This test app listens on port 2200 for authorized ssh connections.  Run it
22*1c60b9acSAndroid Build Coastguard Worker  * using
23*1c60b9acSAndroid Build Coastguard Worker  *
24*1c60b9acSAndroid Build Coastguard Worker  * $ sudo libwebsockets-test-sshd
25*1c60b9acSAndroid Build Coastguard Worker  *
26*1c60b9acSAndroid Build Coastguard Worker  * Connect to it using the test private key with:
27*1c60b9acSAndroid Build Coastguard Worker  *
28*1c60b9acSAndroid Build Coastguard Worker  * $ ssh -p 2200 -i /usr/local/share/libwebsockets-test-server/lws-ssh-test-keys [email protected]
29*1c60b9acSAndroid Build Coastguard Worker  */
30*1c60b9acSAndroid Build Coastguard Worker 
31*1c60b9acSAndroid Build Coastguard Worker #include <sys/types.h>
32*1c60b9acSAndroid Build Coastguard Worker #include <sys/stat.h>
33*1c60b9acSAndroid Build Coastguard Worker #include <fcntl.h>
34*1c60b9acSAndroid Build Coastguard Worker #include <unistd.h>
35*1c60b9acSAndroid Build Coastguard Worker #include <signal.h>
36*1c60b9acSAndroid Build Coastguard Worker #include <errno.h>
37*1c60b9acSAndroid Build Coastguard Worker /* import the whole of lws-plugin-sshd-base statically */
38*1c60b9acSAndroid Build Coastguard Worker #include <lws-plugin-sshd-static-build-includes.h>
39*1c60b9acSAndroid Build Coastguard Worker 
40*1c60b9acSAndroid Build Coastguard Worker /*
41*1c60b9acSAndroid Build Coastguard Worker  * We store the test server's own key here (will be created with a new
42*1c60b9acSAndroid Build Coastguard Worker  * random key if it doesn't exist
43*1c60b9acSAndroid Build Coastguard Worker  *
44*1c60b9acSAndroid Build Coastguard Worker  * The /etc path is the only reason we have to run as root.
45*1c60b9acSAndroid Build Coastguard Worker  */
46*1c60b9acSAndroid Build Coastguard Worker #define TEST_SERVER_KEY_PATH "/etc/lws-test-sshd-server-key"
47*1c60b9acSAndroid Build Coastguard Worker struct per_vhost_data__lws_sshd_demo {
48*1c60b9acSAndroid Build Coastguard Worker 	const struct lws_protocols *ssh_base_protocol;
49*1c60b9acSAndroid Build Coastguard Worker 	int privileged_fd;
50*1c60b9acSAndroid Build Coastguard Worker };
51*1c60b9acSAndroid Build Coastguard Worker 
52*1c60b9acSAndroid Build Coastguard Worker 
53*1c60b9acSAndroid Build Coastguard Worker /*
54*1c60b9acSAndroid Build Coastguard Worker  *  This is a copy of the lws ssh test public key, you can find it in
55*1c60b9acSAndroid Build Coastguard Worker  *  /usr[/local]/share/libwebsockets-test-server/lws-ssh-test-keys.pub
56*1c60b9acSAndroid Build Coastguard Worker  *  and the matching private key there too in .../lws-ssh-test-keys
57*1c60b9acSAndroid Build Coastguard Worker  *
58*1c60b9acSAndroid Build Coastguard Worker  *  These keys are distributed for testing!  Don't use them on a real system
59*1c60b9acSAndroid Build Coastguard Worker  *  unless you want anyone with a copy of lws to access it.
60*1c60b9acSAndroid Build Coastguard Worker  */
61*1c60b9acSAndroid Build Coastguard Worker static const char *authorized_key =
62*1c60b9acSAndroid Build Coastguard Worker 	"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCnWiP+c+kSD6Lk+C6NA9KruApa45sbt"
63*1c60b9acSAndroid Build Coastguard Worker 	"94/dxT0bCITlAA/+PBk6mR1lwWgXYozOMdrHrqx34piqDyXnc4HabqCaOm/FrYhkCPL8z"
64*1c60b9acSAndroid Build Coastguard Worker 	"a26PMYqteSosuwKv//5iT6ZWhNnsMwExBwtV6MIq0MxAeWqxRnYNWpNM8iN6sFzkdG/YF"
65*1c60b9acSAndroid Build Coastguard Worker 	"dyHrIBTgwzM77NLCMl6GEkJErRCFppC2SwYxGa3BRrgUwX3LkV8HpMIaYHFo1Qgj7Scqm"
66*1c60b9acSAndroid Build Coastguard Worker 	"HwS2R75SOqi2aOWDpKjznARg9JgzDWSQi4seBMV2oL0BTwJANSDf+p0sQLsaKGJhpVpBQ"
67*1c60b9acSAndroid Build Coastguard Worker 	"yS2wUeyuGyytupWzEluQrajMZq52iotcogv5BfeulfTTFbJP4kuHOsSP0lsQ2lpMDQANS"
68*1c60b9acSAndroid Build Coastguard Worker 	"HEvXxzHJLDLXM9gXJzwJ+ZiRt6R+bfmP1nfN3MiWtxcIbBanWwQK6xTCKBe4wPaKta5EU"
69*1c60b9acSAndroid Build Coastguard Worker 	"6wsLPeakOIVzoeaOu/HsbtPZlwX0Mu/oUFcfKyKAhlkU15MOAIEfUPo8Yh52bWMlIlpZa"
70*1c60b9acSAndroid Build Coastguard Worker 	"4xWbLMGw3GrsrPPdcsAauyqvY4/NjjWQbWhP1SuUfvv5709PIiOUjVKK2HUwmR1ouch6X"
71*1c60b9acSAndroid Build Coastguard Worker 	"MQGXfMR1h1Wjvc+bkNs17gCIrQnFilAZLC3Sm3Opiz/4LO99Hw448G0RM2vQn0mJE46w"
72*1c60b9acSAndroid Build Coastguard Worker 	"Eu/B10U6Jf4Efojhh1dk85BD1LTIb+N3Q== ssh-test-key@lws";
73*1c60b9acSAndroid Build Coastguard Worker 
74*1c60b9acSAndroid Build Coastguard Worker static struct lws_context *context = NULL;
75*1c60b9acSAndroid Build Coastguard Worker static volatile char force_exit = 0;
76*1c60b9acSAndroid Build Coastguard Worker 
77*1c60b9acSAndroid Build Coastguard Worker /*
78*1c60b9acSAndroid Build Coastguard Worker  * These are our "ops" that form our customization of, and interface to, the
79*1c60b9acSAndroid Build Coastguard Worker  * generic sshd plugin.
80*1c60b9acSAndroid Build Coastguard Worker  *
81*1c60b9acSAndroid Build Coastguard Worker  * The priv struct contains our data we want to associate to each channel
82*1c60b9acSAndroid Build Coastguard Worker  * individually.
83*1c60b9acSAndroid Build Coastguard Worker  */
84*1c60b9acSAndroid Build Coastguard Worker 
85*1c60b9acSAndroid Build Coastguard Worker struct sshd_instance_priv {
86*1c60b9acSAndroid Build Coastguard Worker 	struct lws_protocol_vhost_options *env;
87*1c60b9acSAndroid Build Coastguard Worker 	struct lws_ring	*ring_stdout;
88*1c60b9acSAndroid Build Coastguard Worker 	struct lws_ring	*ring_stderr;
89*1c60b9acSAndroid Build Coastguard Worker 
90*1c60b9acSAndroid Build Coastguard Worker 	struct lws 	*wsi_stdout;
91*1c60b9acSAndroid Build Coastguard Worker 	struct lws 	*wsi_stderr;
92*1c60b9acSAndroid Build Coastguard Worker 
93*1c60b9acSAndroid Build Coastguard Worker 	uint32_t	pty_in_bloat_nl_to_crnl:1;
94*1c60b9acSAndroid Build Coastguard Worker 	uint32_t	pty_in_echo:1;
95*1c60b9acSAndroid Build Coastguard Worker 	uint32_t	pty_in_cr_to_nl:1;
96*1c60b9acSAndroid Build Coastguard Worker 
97*1c60b9acSAndroid Build Coastguard Worker 	uint32_t	insert_lf:1;
98*1c60b9acSAndroid Build Coastguard Worker };
99*1c60b9acSAndroid Build Coastguard Worker 
100*1c60b9acSAndroid Build Coastguard Worker 
101*1c60b9acSAndroid Build Coastguard Worker /* ops: channel lifecycle */
102*1c60b9acSAndroid Build Coastguard Worker 
103*1c60b9acSAndroid Build Coastguard Worker static int
ssh_ops_channel_create(struct lws * wsi,void ** _priv)104*1c60b9acSAndroid Build Coastguard Worker ssh_ops_channel_create(struct lws *wsi, void **_priv)
105*1c60b9acSAndroid Build Coastguard Worker {
106*1c60b9acSAndroid Build Coastguard Worker 	struct sshd_instance_priv *priv;
107*1c60b9acSAndroid Build Coastguard Worker 
108*1c60b9acSAndroid Build Coastguard Worker 	priv = malloc(sizeof(struct sshd_instance_priv));
109*1c60b9acSAndroid Build Coastguard Worker 	*_priv = priv;
110*1c60b9acSAndroid Build Coastguard Worker 	if (!priv)
111*1c60b9acSAndroid Build Coastguard Worker 		return 1;
112*1c60b9acSAndroid Build Coastguard Worker 
113*1c60b9acSAndroid Build Coastguard Worker 	memset(priv, 0, sizeof(*priv));
114*1c60b9acSAndroid Build Coastguard Worker 
115*1c60b9acSAndroid Build Coastguard Worker 	priv->ring_stdout = lws_ring_create(1, 1024, NULL);
116*1c60b9acSAndroid Build Coastguard Worker 	if (!priv->ring_stdout) {
117*1c60b9acSAndroid Build Coastguard Worker 		free(priv);
118*1c60b9acSAndroid Build Coastguard Worker 
119*1c60b9acSAndroid Build Coastguard Worker 		return 1;
120*1c60b9acSAndroid Build Coastguard Worker 	}
121*1c60b9acSAndroid Build Coastguard Worker 
122*1c60b9acSAndroid Build Coastguard Worker 	priv->ring_stderr = lws_ring_create(1, 1024, NULL);
123*1c60b9acSAndroid Build Coastguard Worker 	if (!priv->ring_stderr) {
124*1c60b9acSAndroid Build Coastguard Worker 		lws_ring_destroy(priv->ring_stdout);
125*1c60b9acSAndroid Build Coastguard Worker 		free(priv);
126*1c60b9acSAndroid Build Coastguard Worker 
127*1c60b9acSAndroid Build Coastguard Worker 		return 1;
128*1c60b9acSAndroid Build Coastguard Worker 	}
129*1c60b9acSAndroid Build Coastguard Worker 
130*1c60b9acSAndroid Build Coastguard Worker 	return 0;
131*1c60b9acSAndroid Build Coastguard Worker }
132*1c60b9acSAndroid Build Coastguard Worker 
133*1c60b9acSAndroid Build Coastguard Worker static int
ssh_ops_channel_destroy(void * _priv)134*1c60b9acSAndroid Build Coastguard Worker ssh_ops_channel_destroy(void *_priv)
135*1c60b9acSAndroid Build Coastguard Worker {
136*1c60b9acSAndroid Build Coastguard Worker 	struct sshd_instance_priv *priv = _priv;
137*1c60b9acSAndroid Build Coastguard Worker 	const struct lws_protocol_vhost_options *pvo = priv->env, *pvo1;
138*1c60b9acSAndroid Build Coastguard Worker 
139*1c60b9acSAndroid Build Coastguard Worker 	while (pvo) {
140*1c60b9acSAndroid Build Coastguard Worker 		pvo1 = pvo;
141*1c60b9acSAndroid Build Coastguard Worker 		free((char *)pvo->name);
142*1c60b9acSAndroid Build Coastguard Worker 		free((char *)pvo->value);
143*1c60b9acSAndroid Build Coastguard Worker 		pvo = pvo->next;
144*1c60b9acSAndroid Build Coastguard Worker 		free((void *)pvo1);
145*1c60b9acSAndroid Build Coastguard Worker 	}
146*1c60b9acSAndroid Build Coastguard Worker 	priv->env = NULL;
147*1c60b9acSAndroid Build Coastguard Worker 
148*1c60b9acSAndroid Build Coastguard Worker 	lws_ring_destroy(priv->ring_stdout);
149*1c60b9acSAndroid Build Coastguard Worker 	lws_ring_destroy(priv->ring_stderr);
150*1c60b9acSAndroid Build Coastguard Worker 	free(priv);
151*1c60b9acSAndroid Build Coastguard Worker 
152*1c60b9acSAndroid Build Coastguard Worker 	return 0;
153*1c60b9acSAndroid Build Coastguard Worker }
154*1c60b9acSAndroid Build Coastguard Worker 
155*1c60b9acSAndroid Build Coastguard Worker /* ops: IO */
156*1c60b9acSAndroid Build Coastguard Worker 
157*1c60b9acSAndroid Build Coastguard Worker static int
ssh_ops_tx_waiting(void * _priv)158*1c60b9acSAndroid Build Coastguard Worker ssh_ops_tx_waiting(void *_priv)
159*1c60b9acSAndroid Build Coastguard Worker {
160*1c60b9acSAndroid Build Coastguard Worker 	struct sshd_instance_priv *priv = _priv;
161*1c60b9acSAndroid Build Coastguard Worker 	int s = 0;
162*1c60b9acSAndroid Build Coastguard Worker 
163*1c60b9acSAndroid Build Coastguard Worker 	if (lws_ring_get_count_waiting_elements(priv->ring_stdout, NULL))
164*1c60b9acSAndroid Build Coastguard Worker 		s |= LWS_STDOUT;
165*1c60b9acSAndroid Build Coastguard Worker 	if (lws_ring_get_count_waiting_elements(priv->ring_stderr, NULL))
166*1c60b9acSAndroid Build Coastguard Worker 		s |= LWS_STDERR;
167*1c60b9acSAndroid Build Coastguard Worker 
168*1c60b9acSAndroid Build Coastguard Worker 	return s;
169*1c60b9acSAndroid Build Coastguard Worker }
170*1c60b9acSAndroid Build Coastguard Worker 
171*1c60b9acSAndroid Build Coastguard Worker static size_t
ssh_ops_tx(void * _priv,int stdch,uint8_t * buf,size_t len)172*1c60b9acSAndroid Build Coastguard Worker ssh_ops_tx(void *_priv, int stdch, uint8_t *buf, size_t len)
173*1c60b9acSAndroid Build Coastguard Worker {
174*1c60b9acSAndroid Build Coastguard Worker 	struct sshd_instance_priv *priv = _priv;
175*1c60b9acSAndroid Build Coastguard Worker 	struct lws_ring *r;
176*1c60b9acSAndroid Build Coastguard Worker 	struct lws *wsi;
177*1c60b9acSAndroid Build Coastguard Worker 	size_t n;
178*1c60b9acSAndroid Build Coastguard Worker 
179*1c60b9acSAndroid Build Coastguard Worker 	if (stdch == LWS_STDOUT) {
180*1c60b9acSAndroid Build Coastguard Worker 		r = priv->ring_stdout;
181*1c60b9acSAndroid Build Coastguard Worker 		wsi = priv->wsi_stdout;
182*1c60b9acSAndroid Build Coastguard Worker 	} else {
183*1c60b9acSAndroid Build Coastguard Worker 		r = priv->ring_stderr;
184*1c60b9acSAndroid Build Coastguard Worker 		wsi = priv->wsi_stderr;
185*1c60b9acSAndroid Build Coastguard Worker 	}
186*1c60b9acSAndroid Build Coastguard Worker 
187*1c60b9acSAndroid Build Coastguard Worker 	n = lws_ring_consume(r, NULL, buf, len);
188*1c60b9acSAndroid Build Coastguard Worker 
189*1c60b9acSAndroid Build Coastguard Worker 	if (n)
190*1c60b9acSAndroid Build Coastguard Worker 		lws_rx_flow_control(wsi, 1);
191*1c60b9acSAndroid Build Coastguard Worker 
192*1c60b9acSAndroid Build Coastguard Worker 	return n;
193*1c60b9acSAndroid Build Coastguard Worker }
194*1c60b9acSAndroid Build Coastguard Worker 
195*1c60b9acSAndroid Build Coastguard Worker 
196*1c60b9acSAndroid Build Coastguard Worker static int
ssh_ops_rx(void * _priv,struct lws * wsi,const uint8_t * buf,uint32_t len)197*1c60b9acSAndroid Build Coastguard Worker ssh_ops_rx(void *_priv, struct lws *wsi, const uint8_t *buf, uint32_t len)
198*1c60b9acSAndroid Build Coastguard Worker {
199*1c60b9acSAndroid Build Coastguard Worker 	struct sshd_instance_priv *priv = _priv;
200*1c60b9acSAndroid Build Coastguard Worker 	struct lws *wsi_stdin = lws_cgi_get_stdwsi(wsi, LWS_STDIN);
201*1c60b9acSAndroid Build Coastguard Worker 	int fd;
202*1c60b9acSAndroid Build Coastguard Worker 	uint8_t bbuf[256];
203*1c60b9acSAndroid Build Coastguard Worker 
204*1c60b9acSAndroid Build Coastguard Worker 	if (!wsi_stdin)
205*1c60b9acSAndroid Build Coastguard Worker 		return -1;
206*1c60b9acSAndroid Build Coastguard Worker 
207*1c60b9acSAndroid Build Coastguard Worker 	fd = lws_get_socket_fd(wsi_stdin);
208*1c60b9acSAndroid Build Coastguard Worker 
209*1c60b9acSAndroid Build Coastguard Worker 	if (*buf != 0x0d) {
210*1c60b9acSAndroid Build Coastguard Worker 		if (write(fd, buf, len) != (int)len)
211*1c60b9acSAndroid Build Coastguard Worker 			return -1;
212*1c60b9acSAndroid Build Coastguard Worker 		if (priv->pty_in_echo) {
213*1c60b9acSAndroid Build Coastguard Worker 			if (!lws_ring_insert(priv->ring_stdout, buf, 1))
214*1c60b9acSAndroid Build Coastguard Worker 				lwsl_notice("dropping...\n");
215*1c60b9acSAndroid Build Coastguard Worker 			lws_callback_on_writable(wsi);
216*1c60b9acSAndroid Build Coastguard Worker 		}
217*1c60b9acSAndroid Build Coastguard Worker 	} else {
218*1c60b9acSAndroid Build Coastguard Worker 		bbuf[0] = 0x0a;
219*1c60b9acSAndroid Build Coastguard Worker 		bbuf[1] = 0x0a;
220*1c60b9acSAndroid Build Coastguard Worker 		if (write(fd, bbuf, 1) != 1)
221*1c60b9acSAndroid Build Coastguard Worker 			return -1;
222*1c60b9acSAndroid Build Coastguard Worker 
223*1c60b9acSAndroid Build Coastguard Worker 		if (priv->pty_in_echo) {
224*1c60b9acSAndroid Build Coastguard Worker 			bbuf[0] = 0x0d;
225*1c60b9acSAndroid Build Coastguard Worker 			bbuf[1] = 0x0a;
226*1c60b9acSAndroid Build Coastguard Worker 			if (!lws_ring_insert(priv->ring_stdout, bbuf, 2))
227*1c60b9acSAndroid Build Coastguard Worker 				lwsl_notice("dropping...\n");
228*1c60b9acSAndroid Build Coastguard Worker 			lws_callback_on_writable(wsi);
229*1c60b9acSAndroid Build Coastguard Worker 		}
230*1c60b9acSAndroid Build Coastguard Worker 	}
231*1c60b9acSAndroid Build Coastguard Worker 
232*1c60b9acSAndroid Build Coastguard Worker 	return 0;
233*1c60b9acSAndroid Build Coastguard Worker }
234*1c60b9acSAndroid Build Coastguard Worker 
235*1c60b9acSAndroid Build Coastguard Worker /* ops: storage for the (autogenerated) persistent server key */
236*1c60b9acSAndroid Build Coastguard Worker 
237*1c60b9acSAndroid Build Coastguard Worker static size_t
ssh_ops_get_server_key(struct lws * wsi,uint8_t * buf,size_t len)238*1c60b9acSAndroid Build Coastguard Worker ssh_ops_get_server_key(struct lws *wsi, uint8_t *buf, size_t len)
239*1c60b9acSAndroid Build Coastguard Worker {
240*1c60b9acSAndroid Build Coastguard Worker 	int fd = lws_open(TEST_SERVER_KEY_PATH, O_RDONLY), n;
241*1c60b9acSAndroid Build Coastguard Worker 
242*1c60b9acSAndroid Build Coastguard Worker 	if (fd == -1) {
243*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: unable to open %s for read: %s\n", __func__,
244*1c60b9acSAndroid Build Coastguard Worker 				TEST_SERVER_KEY_PATH, strerror(errno));
245*1c60b9acSAndroid Build Coastguard Worker 
246*1c60b9acSAndroid Build Coastguard Worker 		return 0;
247*1c60b9acSAndroid Build Coastguard Worker 	}
248*1c60b9acSAndroid Build Coastguard Worker 
249*1c60b9acSAndroid Build Coastguard Worker 	n = (int)read(fd, buf, len);
250*1c60b9acSAndroid Build Coastguard Worker 	if (n < 0) {
251*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: read failed: %d\n", __func__, n);
252*1c60b9acSAndroid Build Coastguard Worker 		n = 0;
253*1c60b9acSAndroid Build Coastguard Worker 	}
254*1c60b9acSAndroid Build Coastguard Worker 
255*1c60b9acSAndroid Build Coastguard Worker 	close(fd);
256*1c60b9acSAndroid Build Coastguard Worker 
257*1c60b9acSAndroid Build Coastguard Worker 	return (size_t)n;
258*1c60b9acSAndroid Build Coastguard Worker }
259*1c60b9acSAndroid Build Coastguard Worker 
260*1c60b9acSAndroid Build Coastguard Worker static size_t
ssh_ops_set_server_key(struct lws * wsi,uint8_t * buf,size_t len)261*1c60b9acSAndroid Build Coastguard Worker ssh_ops_set_server_key(struct lws *wsi, uint8_t *buf, size_t len)
262*1c60b9acSAndroid Build Coastguard Worker {
263*1c60b9acSAndroid Build Coastguard Worker 	int fd = lws_open(TEST_SERVER_KEY_PATH, O_CREAT | O_TRUNC | O_RDWR, 0600);
264*1c60b9acSAndroid Build Coastguard Worker 	int n;
265*1c60b9acSAndroid Build Coastguard Worker 
266*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("%s: %d\n", __func__, fd);
267*1c60b9acSAndroid Build Coastguard Worker 	if (fd == -1) {
268*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: unable to open %s for write: %s\n", __func__,
269*1c60b9acSAndroid Build Coastguard Worker 				TEST_SERVER_KEY_PATH, strerror(errno));
270*1c60b9acSAndroid Build Coastguard Worker 
271*1c60b9acSAndroid Build Coastguard Worker 		return 0;
272*1c60b9acSAndroid Build Coastguard Worker 	}
273*1c60b9acSAndroid Build Coastguard Worker 
274*1c60b9acSAndroid Build Coastguard Worker 	n = (int)write(fd, buf, len);
275*1c60b9acSAndroid Build Coastguard Worker 	if (n < 0) {
276*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: read failed: %d\n", __func__, errno);
277*1c60b9acSAndroid Build Coastguard Worker 		n = 0;
278*1c60b9acSAndroid Build Coastguard Worker 	}
279*1c60b9acSAndroid Build Coastguard Worker 
280*1c60b9acSAndroid Build Coastguard Worker 	close(fd);
281*1c60b9acSAndroid Build Coastguard Worker 
282*1c60b9acSAndroid Build Coastguard Worker 	return (size_t)n;
283*1c60b9acSAndroid Build Coastguard Worker }
284*1c60b9acSAndroid Build Coastguard Worker 
285*1c60b9acSAndroid Build Coastguard Worker /* ops: auth */
286*1c60b9acSAndroid Build Coastguard Worker 
287*1c60b9acSAndroid Build Coastguard Worker static int
ssh_ops_is_pubkey_authorized(const char * username,const char * type,const uint8_t * peer,int peer_len)288*1c60b9acSAndroid Build Coastguard Worker ssh_ops_is_pubkey_authorized(const char *username, const char *type,
289*1c60b9acSAndroid Build Coastguard Worker 				 const uint8_t *peer, int peer_len)
290*1c60b9acSAndroid Build Coastguard Worker {
291*1c60b9acSAndroid Build Coastguard Worker 	char *aps, *p, *ps;
292*1c60b9acSAndroid Build Coastguard Worker 	int n = (int)strlen(type), alen = 2048, ret = 2, len;
293*1c60b9acSAndroid Build Coastguard Worker 	size_t s = 0;
294*1c60b9acSAndroid Build Coastguard Worker 
295*1c60b9acSAndroid Build Coastguard Worker 	lwsl_info("%s: checking pubkey for %s\n", __func__, username);
296*1c60b9acSAndroid Build Coastguard Worker 
297*1c60b9acSAndroid Build Coastguard Worker 	s = strlen(authorized_key) + 1;
298*1c60b9acSAndroid Build Coastguard Worker 
299*1c60b9acSAndroid Build Coastguard Worker 	aps = malloc(s);
300*1c60b9acSAndroid Build Coastguard Worker 	if (!aps) {
301*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("OOM 1\n");
302*1c60b9acSAndroid Build Coastguard Worker 		goto bail_p1;
303*1c60b9acSAndroid Build Coastguard Worker 	}
304*1c60b9acSAndroid Build Coastguard Worker 	memcpy(aps, authorized_key, s);
305*1c60b9acSAndroid Build Coastguard Worker 
306*1c60b9acSAndroid Build Coastguard Worker 	/* this is all we understand at the moment */
307*1c60b9acSAndroid Build Coastguard Worker 	if (strcmp(type, "ssh-rsa")) {
308*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("type is not ssh-rsa\n");
309*1c60b9acSAndroid Build Coastguard Worker 		goto bail_p1;
310*1c60b9acSAndroid Build Coastguard Worker 	}
311*1c60b9acSAndroid Build Coastguard Worker 	p = aps;
312*1c60b9acSAndroid Build Coastguard Worker 
313*1c60b9acSAndroid Build Coastguard Worker 	if (strncmp(p, type, (unsigned int)n)) {
314*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("lead-in string  does not match %s\n", type);
315*1c60b9acSAndroid Build Coastguard Worker 		goto bail_p1;
316*1c60b9acSAndroid Build Coastguard Worker 	}
317*1c60b9acSAndroid Build Coastguard Worker 
318*1c60b9acSAndroid Build Coastguard Worker 	p += n;
319*1c60b9acSAndroid Build Coastguard Worker 	if (*p != ' ') {
320*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("missing space at end of lead-in\n");
321*1c60b9acSAndroid Build Coastguard Worker 		goto bail_p1;
322*1c60b9acSAndroid Build Coastguard Worker 	}
323*1c60b9acSAndroid Build Coastguard Worker 
324*1c60b9acSAndroid Build Coastguard Worker 
325*1c60b9acSAndroid Build Coastguard Worker 	p++;
326*1c60b9acSAndroid Build Coastguard Worker 	ps = malloc((unsigned int)alen);
327*1c60b9acSAndroid Build Coastguard Worker 	if (!ps) {
328*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("OOM 2\n");
329*1c60b9acSAndroid Build Coastguard Worker 		free(aps);
330*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
331*1c60b9acSAndroid Build Coastguard Worker 	}
332*1c60b9acSAndroid Build Coastguard Worker 	len = lws_b64_decode_string(p, ps, alen);
333*1c60b9acSAndroid Build Coastguard Worker 	free(aps);
334*1c60b9acSAndroid Build Coastguard Worker 	if (len < 0) {
335*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("key too big\n");
336*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
337*1c60b9acSAndroid Build Coastguard Worker 	}
338*1c60b9acSAndroid Build Coastguard Worker 
339*1c60b9acSAndroid Build Coastguard Worker 	if (peer_len > len) {
340*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("peer_len %d bigger than decoded len %d\n",
341*1c60b9acSAndroid Build Coastguard Worker 				peer_len, len);
342*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
343*1c60b9acSAndroid Build Coastguard Worker 	}
344*1c60b9acSAndroid Build Coastguard Worker 
345*1c60b9acSAndroid Build Coastguard Worker 	/*
346*1c60b9acSAndroid Build Coastguard Worker 	 * once we are past that, it's the same <len32>name
347*1c60b9acSAndroid Build Coastguard Worker 	 * <len32>E<len32>N that the peer sends us
348*1c60b9acSAndroid Build Coastguard Worker 	 */
349*1c60b9acSAndroid Build Coastguard Worker 
350*1c60b9acSAndroid Build Coastguard Worker 	if (lws_timingsafe_bcmp(peer, ps, (uint32_t)peer_len)) {
351*1c60b9acSAndroid Build Coastguard Worker 		lwsl_info("factors mismatch\n");
352*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
353*1c60b9acSAndroid Build Coastguard Worker 	}
354*1c60b9acSAndroid Build Coastguard Worker 
355*1c60b9acSAndroid Build Coastguard Worker 	lwsl_info("pubkey authorized\n");
356*1c60b9acSAndroid Build Coastguard Worker 
357*1c60b9acSAndroid Build Coastguard Worker 	ret = 0;
358*1c60b9acSAndroid Build Coastguard Worker bail:
359*1c60b9acSAndroid Build Coastguard Worker 	free(ps);
360*1c60b9acSAndroid Build Coastguard Worker 
361*1c60b9acSAndroid Build Coastguard Worker 	return ret;
362*1c60b9acSAndroid Build Coastguard Worker 
363*1c60b9acSAndroid Build Coastguard Worker bail_p1:
364*1c60b9acSAndroid Build Coastguard Worker 	if (aps)
365*1c60b9acSAndroid Build Coastguard Worker 		free(aps);
366*1c60b9acSAndroid Build Coastguard Worker 
367*1c60b9acSAndroid Build Coastguard Worker 	return 1;
368*1c60b9acSAndroid Build Coastguard Worker }
369*1c60b9acSAndroid Build Coastguard Worker 
370*1c60b9acSAndroid Build Coastguard Worker /* ops: spawn subprocess */
371*1c60b9acSAndroid Build Coastguard Worker 
372*1c60b9acSAndroid Build Coastguard Worker static int
ssh_cgi_env_add(struct sshd_instance_priv * priv,const char * name,const char * value)373*1c60b9acSAndroid Build Coastguard Worker ssh_cgi_env_add(struct sshd_instance_priv *priv, const char *name,
374*1c60b9acSAndroid Build Coastguard Worker 		const char *value)
375*1c60b9acSAndroid Build Coastguard Worker {
376*1c60b9acSAndroid Build Coastguard Worker 	struct lws_protocol_vhost_options *pvo = malloc(sizeof(*pvo));
377*1c60b9acSAndroid Build Coastguard Worker 
378*1c60b9acSAndroid Build Coastguard Worker 	if (!pvo)
379*1c60b9acSAndroid Build Coastguard Worker 		return 1;
380*1c60b9acSAndroid Build Coastguard Worker 
381*1c60b9acSAndroid Build Coastguard Worker 	pvo->name = malloc(strlen(name) + 1);
382*1c60b9acSAndroid Build Coastguard Worker 	if (!pvo->name) {
383*1c60b9acSAndroid Build Coastguard Worker 		free(pvo);
384*1c60b9acSAndroid Build Coastguard Worker 		return 1;
385*1c60b9acSAndroid Build Coastguard Worker 	}
386*1c60b9acSAndroid Build Coastguard Worker 
387*1c60b9acSAndroid Build Coastguard Worker 	pvo->value = malloc(strlen(value) + 1);
388*1c60b9acSAndroid Build Coastguard Worker 	if (!pvo->value) {
389*1c60b9acSAndroid Build Coastguard Worker 		free((char *)pvo->name);
390*1c60b9acSAndroid Build Coastguard Worker 		free(pvo);
391*1c60b9acSAndroid Build Coastguard Worker 		return 1;
392*1c60b9acSAndroid Build Coastguard Worker 	}
393*1c60b9acSAndroid Build Coastguard Worker 
394*1c60b9acSAndroid Build Coastguard Worker 	strcpy((char *)pvo->name, name);
395*1c60b9acSAndroid Build Coastguard Worker 	strcpy((char *)pvo->value, value);
396*1c60b9acSAndroid Build Coastguard Worker 
397*1c60b9acSAndroid Build Coastguard Worker 	pvo->next = priv->env;
398*1c60b9acSAndroid Build Coastguard Worker 	priv->env = pvo;
399*1c60b9acSAndroid Build Coastguard Worker 
400*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("%s: ENV %s <- %s\n", __func__, name, value);
401*1c60b9acSAndroid Build Coastguard Worker 
402*1c60b9acSAndroid Build Coastguard Worker 	return 0;
403*1c60b9acSAndroid Build Coastguard Worker }
404*1c60b9acSAndroid Build Coastguard Worker 
405*1c60b9acSAndroid Build Coastguard Worker static int
ssh_ops_set_env(void * _priv,const char * name,const char * value)406*1c60b9acSAndroid Build Coastguard Worker ssh_ops_set_env(void *_priv, const char *name, const char *value)
407*1c60b9acSAndroid Build Coastguard Worker {
408*1c60b9acSAndroid Build Coastguard Worker 	struct sshd_instance_priv *priv = _priv;
409*1c60b9acSAndroid Build Coastguard Worker 
410*1c60b9acSAndroid Build Coastguard Worker 	return ssh_cgi_env_add(priv, name, value);
411*1c60b9acSAndroid Build Coastguard Worker }
412*1c60b9acSAndroid Build Coastguard Worker 
413*1c60b9acSAndroid Build Coastguard Worker 
414*1c60b9acSAndroid Build Coastguard Worker static int
ssh_ops_pty_req(void * _priv,struct lws_ssh_pty * pty)415*1c60b9acSAndroid Build Coastguard Worker ssh_ops_pty_req(void *_priv, struct lws_ssh_pty *pty)
416*1c60b9acSAndroid Build Coastguard Worker {
417*1c60b9acSAndroid Build Coastguard Worker 	struct sshd_instance_priv *priv = _priv;
418*1c60b9acSAndroid Build Coastguard Worker 	uint8_t *p = (uint8_t *)pty->modes, opc;
419*1c60b9acSAndroid Build Coastguard Worker 	uint32_t arg;
420*1c60b9acSAndroid Build Coastguard Worker 
421*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("%s: pty term %s, modes_len %d\n", __func__, pty->term,
422*1c60b9acSAndroid Build Coastguard Worker 		    pty->modes_len);
423*1c60b9acSAndroid Build Coastguard Worker 
424*1c60b9acSAndroid Build Coastguard Worker 	ssh_cgi_env_add(priv, "TERM", pty->term);
425*1c60b9acSAndroid Build Coastguard Worker 
426*1c60b9acSAndroid Build Coastguard Worker 	while (p < (uint8_t *)pty->modes + pty->modes_len) {
427*1c60b9acSAndroid Build Coastguard Worker 		if (*p >= 160)
428*1c60b9acSAndroid Build Coastguard Worker 			break;
429*1c60b9acSAndroid Build Coastguard Worker 		if (!*p)
430*1c60b9acSAndroid Build Coastguard Worker 			break;
431*1c60b9acSAndroid Build Coastguard Worker 		opc = *p++;
432*1c60b9acSAndroid Build Coastguard Worker 
433*1c60b9acSAndroid Build Coastguard Worker 		arg = (uint32_t)(*p++ << 24);
434*1c60b9acSAndroid Build Coastguard Worker 		arg |= (uint32_t)(*p++ << 16);
435*1c60b9acSAndroid Build Coastguard Worker 		arg |= (uint32_t)(*p++ << 8);
436*1c60b9acSAndroid Build Coastguard Worker 		arg |= (uint32_t)(*p++);
437*1c60b9acSAndroid Build Coastguard Worker 
438*1c60b9acSAndroid Build Coastguard Worker 		lwsl_debug("pty opc %d: 0x%x\n", opc, arg);
439*1c60b9acSAndroid Build Coastguard Worker 
440*1c60b9acSAndroid Build Coastguard Worker 		switch (opc) {
441*1c60b9acSAndroid Build Coastguard Worker 		case SSHMO_ICRNL:
442*1c60b9acSAndroid Build Coastguard Worker 			priv->pty_in_cr_to_nl = !!arg;
443*1c60b9acSAndroid Build Coastguard Worker 			lwsl_notice(" SSHMO_ICRNL: %d\n", !!arg);
444*1c60b9acSAndroid Build Coastguard Worker 			break;
445*1c60b9acSAndroid Build Coastguard Worker 		case SSHMO_ONLCR:
446*1c60b9acSAndroid Build Coastguard Worker 			priv->pty_in_bloat_nl_to_crnl = !!arg;
447*1c60b9acSAndroid Build Coastguard Worker 			lwsl_notice(" SSHMO_ONLCR: %d\n", !!arg);
448*1c60b9acSAndroid Build Coastguard Worker 			break;
449*1c60b9acSAndroid Build Coastguard Worker 		case SSHMO_ECHO:
450*1c60b9acSAndroid Build Coastguard Worker //			priv->pty_in_echo = !!arg;
451*1c60b9acSAndroid Build Coastguard Worker 			lwsl_notice(" SSHMO_ECHO: %d\n", !!arg);
452*1c60b9acSAndroid Build Coastguard Worker 			break;
453*1c60b9acSAndroid Build Coastguard Worker 		}
454*1c60b9acSAndroid Build Coastguard Worker 	}
455*1c60b9acSAndroid Build Coastguard Worker 
456*1c60b9acSAndroid Build Coastguard Worker 	return 0;
457*1c60b9acSAndroid Build Coastguard Worker }
458*1c60b9acSAndroid Build Coastguard Worker 
459*1c60b9acSAndroid Build Coastguard Worker static int
ssh_ops_child_process_io(void * _priv,struct lws * wsi,struct lws_cgi_args * args)460*1c60b9acSAndroid Build Coastguard Worker ssh_ops_child_process_io(void *_priv, struct lws *wsi,
461*1c60b9acSAndroid Build Coastguard Worker 			 struct lws_cgi_args *args)
462*1c60b9acSAndroid Build Coastguard Worker {
463*1c60b9acSAndroid Build Coastguard Worker 	struct sshd_instance_priv *priv = _priv;
464*1c60b9acSAndroid Build Coastguard Worker 	struct lws_ring *r = priv->ring_stdout;
465*1c60b9acSAndroid Build Coastguard Worker 	void *rp;
466*1c60b9acSAndroid Build Coastguard Worker 	size_t bytes;
467*1c60b9acSAndroid Build Coastguard Worker 	int n, m;
468*1c60b9acSAndroid Build Coastguard Worker 
469*1c60b9acSAndroid Build Coastguard Worker 	priv->wsi_stdout = args->stdwsi[LWS_STDOUT];
470*1c60b9acSAndroid Build Coastguard Worker 	priv->wsi_stderr = args->stdwsi[LWS_STDERR];
471*1c60b9acSAndroid Build Coastguard Worker 
472*1c60b9acSAndroid Build Coastguard Worker 	switch (args->ch) {
473*1c60b9acSAndroid Build Coastguard Worker 	case LWS_STDIN:
474*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("STDIN\n");
475*1c60b9acSAndroid Build Coastguard Worker 		break;
476*1c60b9acSAndroid Build Coastguard Worker 
477*1c60b9acSAndroid Build Coastguard Worker 	case LWS_STDERR:
478*1c60b9acSAndroid Build Coastguard Worker 		r = priv->ring_stderr;
479*1c60b9acSAndroid Build Coastguard Worker 		/* fallthru */
480*1c60b9acSAndroid Build Coastguard Worker 	case LWS_STDOUT:
481*1c60b9acSAndroid Build Coastguard Worker 		if (lws_ring_next_linear_insert_range(r, &rp, &bytes) ||
482*1c60b9acSAndroid Build Coastguard Worker 		    bytes < 1) {
483*1c60b9acSAndroid Build Coastguard Worker 			lwsl_notice("bytes %d\n", (int)bytes);
484*1c60b9acSAndroid Build Coastguard Worker 			/* no room in the fifo */
485*1c60b9acSAndroid Build Coastguard Worker 			break;
486*1c60b9acSAndroid Build Coastguard Worker 		}
487*1c60b9acSAndroid Build Coastguard Worker 		if (priv->pty_in_bloat_nl_to_crnl) {
488*1c60b9acSAndroid Build Coastguard Worker 			uint8_t buf[256], *p, *d;
489*1c60b9acSAndroid Build Coastguard Worker 
490*1c60b9acSAndroid Build Coastguard Worker 			if (bytes != 1)
491*1c60b9acSAndroid Build Coastguard Worker 				n = (int)(bytes / 2);
492*1c60b9acSAndroid Build Coastguard Worker 			else
493*1c60b9acSAndroid Build Coastguard Worker 				n = 1;
494*1c60b9acSAndroid Build Coastguard Worker 			if (n > (int)sizeof(buf))
495*1c60b9acSAndroid Build Coastguard Worker 				n = sizeof(buf);
496*1c60b9acSAndroid Build Coastguard Worker 
497*1c60b9acSAndroid Build Coastguard Worker 			if (!n)
498*1c60b9acSAndroid Build Coastguard Worker 				break;
499*1c60b9acSAndroid Build Coastguard Worker 
500*1c60b9acSAndroid Build Coastguard Worker 			m = lws_get_socket_fd(args->stdwsi[args->ch]);
501*1c60b9acSAndroid Build Coastguard Worker 			if (m < 0)
502*1c60b9acSAndroid Build Coastguard Worker 				return -1;
503*1c60b9acSAndroid Build Coastguard Worker 			n = (int)read(m, buf, (unsigned int)n);
504*1c60b9acSAndroid Build Coastguard Worker 			if (n < 0)
505*1c60b9acSAndroid Build Coastguard Worker 				return -1;
506*1c60b9acSAndroid Build Coastguard Worker 			if (n == 0) {
507*1c60b9acSAndroid Build Coastguard Worker 				lwsl_notice("zero length stdin %d\n", n);
508*1c60b9acSAndroid Build Coastguard Worker 				break;
509*1c60b9acSAndroid Build Coastguard Worker 			}
510*1c60b9acSAndroid Build Coastguard Worker 			m = 0;
511*1c60b9acSAndroid Build Coastguard Worker 			p = rp;
512*1c60b9acSAndroid Build Coastguard Worker 			d = buf;
513*1c60b9acSAndroid Build Coastguard Worker 			while (m++ < n) {
514*1c60b9acSAndroid Build Coastguard Worker 				if (priv->insert_lf) {
515*1c60b9acSAndroid Build Coastguard Worker 					priv->insert_lf = 0;
516*1c60b9acSAndroid Build Coastguard Worker 					*p++ = 0x0d;
517*1c60b9acSAndroid Build Coastguard Worker 				}
518*1c60b9acSAndroid Build Coastguard Worker 				if (*d == 0x0a)
519*1c60b9acSAndroid Build Coastguard Worker 					priv->insert_lf = 1;
520*1c60b9acSAndroid Build Coastguard Worker 
521*1c60b9acSAndroid Build Coastguard Worker 				*p++ = *d++;
522*1c60b9acSAndroid Build Coastguard Worker 			}
523*1c60b9acSAndroid Build Coastguard Worker 			n = lws_ptr_diff((void *)p, rp);
524*1c60b9acSAndroid Build Coastguard Worker 			if (n < (int)bytes && priv->insert_lf) {
525*1c60b9acSAndroid Build Coastguard Worker 				priv->insert_lf = 0;
526*1c60b9acSAndroid Build Coastguard Worker 				*p++ = 0x0d;
527*1c60b9acSAndroid Build Coastguard Worker 				n++;
528*1c60b9acSAndroid Build Coastguard Worker 			}
529*1c60b9acSAndroid Build Coastguard Worker 		} else {
530*1c60b9acSAndroid Build Coastguard Worker 			n = lws_get_socket_fd(args->stdwsi[args->ch]);
531*1c60b9acSAndroid Build Coastguard Worker 			if (n < 0)
532*1c60b9acSAndroid Build Coastguard Worker 				return -1;
533*1c60b9acSAndroid Build Coastguard Worker 			n = (int)read(n, rp, bytes);
534*1c60b9acSAndroid Build Coastguard Worker 			if (n < 0)
535*1c60b9acSAndroid Build Coastguard Worker 				return -1;
536*1c60b9acSAndroid Build Coastguard Worker 		}
537*1c60b9acSAndroid Build Coastguard Worker 
538*1c60b9acSAndroid Build Coastguard Worker 		lws_rx_flow_control(args->stdwsi[args->ch], 0);
539*1c60b9acSAndroid Build Coastguard Worker 
540*1c60b9acSAndroid Build Coastguard Worker 		lws_ring_bump_head(r, (unsigned int)n);
541*1c60b9acSAndroid Build Coastguard Worker 		lws_callback_on_writable(wsi);
542*1c60b9acSAndroid Build Coastguard Worker 		break;
543*1c60b9acSAndroid Build Coastguard Worker 	}
544*1c60b9acSAndroid Build Coastguard Worker 
545*1c60b9acSAndroid Build Coastguard Worker 	return 0;
546*1c60b9acSAndroid Build Coastguard Worker }
547*1c60b9acSAndroid Build Coastguard Worker 
548*1c60b9acSAndroid Build Coastguard Worker static int
ssh_ops_child_process_terminated(void * priv,struct lws * wsi)549*1c60b9acSAndroid Build Coastguard Worker ssh_ops_child_process_terminated(void *priv, struct lws *wsi)
550*1c60b9acSAndroid Build Coastguard Worker {
551*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("%s\n", __func__);
552*1c60b9acSAndroid Build Coastguard Worker 	return -1;
553*1c60b9acSAndroid Build Coastguard Worker }
554*1c60b9acSAndroid Build Coastguard Worker 
555*1c60b9acSAndroid Build Coastguard Worker static int
ssh_ops_exec(void * _priv,struct lws * wsi,const char * command,lws_ssh_finish_exec finish,void * finish_handle)556*1c60b9acSAndroid Build Coastguard Worker ssh_ops_exec(void *_priv, struct lws *wsi, const char *command, lws_ssh_finish_exec finish, void *finish_handle)
557*1c60b9acSAndroid Build Coastguard Worker {
558*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("%s: EXEC %s\n", __func__, command);
559*1c60b9acSAndroid Build Coastguard Worker 
560*1c60b9acSAndroid Build Coastguard Worker 	/* we don't want to exec anything */
561*1c60b9acSAndroid Build Coastguard Worker 	return 1;
562*1c60b9acSAndroid Build Coastguard Worker }
563*1c60b9acSAndroid Build Coastguard Worker 
564*1c60b9acSAndroid Build Coastguard Worker static int
ssh_ops_shell(void * _priv,struct lws * wsi,lws_ssh_finish_exec finish,void * finish_handle)565*1c60b9acSAndroid Build Coastguard Worker ssh_ops_shell(void *_priv, struct lws *wsi, lws_ssh_finish_exec finish, void *finish_handle)
566*1c60b9acSAndroid Build Coastguard Worker {
567*1c60b9acSAndroid Build Coastguard Worker 	struct sshd_instance_priv *priv = _priv;
568*1c60b9acSAndroid Build Coastguard Worker 	const char *cmd[] = {
569*1c60b9acSAndroid Build Coastguard Worker 		"/bin/bash",
570*1c60b9acSAndroid Build Coastguard Worker 		"-i",
571*1c60b9acSAndroid Build Coastguard Worker 		"-l",
572*1c60b9acSAndroid Build Coastguard Worker 		NULL
573*1c60b9acSAndroid Build Coastguard Worker 	};
574*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("%s: SHELL\n", __func__);
575*1c60b9acSAndroid Build Coastguard Worker 
576*1c60b9acSAndroid Build Coastguard Worker 	if (lws_cgi(wsi, cmd, -1, 0, priv->env)) {
577*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("shell spawn failed\n");
578*1c60b9acSAndroid Build Coastguard Worker 		return -1;
579*1c60b9acSAndroid Build Coastguard Worker 	}
580*1c60b9acSAndroid Build Coastguard Worker 
581*1c60b9acSAndroid Build Coastguard Worker 	return 0;
582*1c60b9acSAndroid Build Coastguard Worker }
583*1c60b9acSAndroid Build Coastguard Worker 
584*1c60b9acSAndroid Build Coastguard Worker /* ops: banner */
585*1c60b9acSAndroid Build Coastguard Worker 
586*1c60b9acSAndroid Build Coastguard Worker static size_t
ssh_ops_banner(char * buf,size_t max_len,char * lang,size_t max_lang_len)587*1c60b9acSAndroid Build Coastguard Worker ssh_ops_banner(char *buf, size_t max_len, char *lang, size_t max_lang_len)
588*1c60b9acSAndroid Build Coastguard Worker {
589*1c60b9acSAndroid Build Coastguard Worker 	int n = lws_snprintf(buf, max_len, "\n"
590*1c60b9acSAndroid Build Coastguard Worker 		      " |\\---/|  lws-ssh Test Server\n"
591*1c60b9acSAndroid Build Coastguard Worker 		      " | o_o |  SSH Terminal Server\n"
592*1c60b9acSAndroid Build Coastguard Worker 		      "  \\_^_/   Copyright (C) 2017-2020 Crash Barrier Ltd\n\n");
593*1c60b9acSAndroid Build Coastguard Worker 
594*1c60b9acSAndroid Build Coastguard Worker 	lws_snprintf(lang, max_lang_len, "en/US");
595*1c60b9acSAndroid Build Coastguard Worker 
596*1c60b9acSAndroid Build Coastguard Worker 	return (size_t)n;
597*1c60b9acSAndroid Build Coastguard Worker }
598*1c60b9acSAndroid Build Coastguard Worker 
599*1c60b9acSAndroid Build Coastguard Worker static void
ssh_ops_disconnect_reason(uint32_t reason,const char * desc,const char * desc_lang)600*1c60b9acSAndroid Build Coastguard Worker ssh_ops_disconnect_reason(uint32_t reason, const char *desc,
601*1c60b9acSAndroid Build Coastguard Worker 			  const char *desc_lang)
602*1c60b9acSAndroid Build Coastguard Worker {
603*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("DISCONNECT reason 0x%X, %s (lang %s)\n", reason, desc,
604*1c60b9acSAndroid Build Coastguard Worker 			desc_lang);
605*1c60b9acSAndroid Build Coastguard Worker }
606*1c60b9acSAndroid Build Coastguard Worker 
607*1c60b9acSAndroid Build Coastguard Worker static const struct lws_ssh_ops ssh_ops = {
608*1c60b9acSAndroid Build Coastguard Worker 	.channel_create			= ssh_ops_channel_create,
609*1c60b9acSAndroid Build Coastguard Worker 	.channel_destroy		= ssh_ops_channel_destroy,
610*1c60b9acSAndroid Build Coastguard Worker 	.tx_waiting			= ssh_ops_tx_waiting,
611*1c60b9acSAndroid Build Coastguard Worker 	.tx				= ssh_ops_tx,
612*1c60b9acSAndroid Build Coastguard Worker 	.rx				= ssh_ops_rx,
613*1c60b9acSAndroid Build Coastguard Worker 	.get_server_key			= ssh_ops_get_server_key,
614*1c60b9acSAndroid Build Coastguard Worker 	.set_server_key			= ssh_ops_set_server_key,
615*1c60b9acSAndroid Build Coastguard Worker 	.set_env			= ssh_ops_set_env,
616*1c60b9acSAndroid Build Coastguard Worker 	.pty_req			= ssh_ops_pty_req,
617*1c60b9acSAndroid Build Coastguard Worker 	.child_process_io		= ssh_ops_child_process_io,
618*1c60b9acSAndroid Build Coastguard Worker 	.child_process_terminated	= ssh_ops_child_process_terminated,
619*1c60b9acSAndroid Build Coastguard Worker 	.exec				= ssh_ops_exec,
620*1c60b9acSAndroid Build Coastguard Worker 	.shell				= ssh_ops_shell,
621*1c60b9acSAndroid Build Coastguard Worker 	.is_pubkey_authorized		= ssh_ops_is_pubkey_authorized,
622*1c60b9acSAndroid Build Coastguard Worker 	.banner				= ssh_ops_banner,
623*1c60b9acSAndroid Build Coastguard Worker 	.disconnect_reason		= ssh_ops_disconnect_reason,
624*1c60b9acSAndroid Build Coastguard Worker 	.server_string			= "SSH-2.0-Libwebsockets",
625*1c60b9acSAndroid Build Coastguard Worker 	.api_version			= 2,
626*1c60b9acSAndroid Build Coastguard Worker };
627*1c60b9acSAndroid Build Coastguard Worker 
628*1c60b9acSAndroid Build Coastguard Worker /*
629*1c60b9acSAndroid Build Coastguard Worker  * use per-vhost options to bind the ops struct to the instance of the
630*1c60b9acSAndroid Build Coastguard Worker  * "lws_raw_sshd" protocol instantiated on our vhost
631*1c60b9acSAndroid Build Coastguard Worker  */
632*1c60b9acSAndroid Build Coastguard Worker 
633*1c60b9acSAndroid Build Coastguard Worker static const struct lws_protocol_vhost_options pvo_ssh_ops = {
634*1c60b9acSAndroid Build Coastguard Worker 	NULL,
635*1c60b9acSAndroid Build Coastguard Worker 	NULL,
636*1c60b9acSAndroid Build Coastguard Worker 	"ops",
637*1c60b9acSAndroid Build Coastguard Worker 	(void *)&ssh_ops
638*1c60b9acSAndroid Build Coastguard Worker };
639*1c60b9acSAndroid Build Coastguard Worker 
640*1c60b9acSAndroid Build Coastguard Worker static const struct lws_protocol_vhost_options pvo_ssh = {
641*1c60b9acSAndroid Build Coastguard Worker 	NULL,
642*1c60b9acSAndroid Build Coastguard Worker 	&pvo_ssh_ops,
643*1c60b9acSAndroid Build Coastguard Worker 	"lws-ssh-base",
644*1c60b9acSAndroid Build Coastguard Worker 	"" /* ignored, just matches the protocol name above */
645*1c60b9acSAndroid Build Coastguard Worker };
646*1c60b9acSAndroid Build Coastguard Worker 
sighandler(int sig)647*1c60b9acSAndroid Build Coastguard Worker void sighandler(int sig)
648*1c60b9acSAndroid Build Coastguard Worker {
649*1c60b9acSAndroid Build Coastguard Worker 	force_exit = 1;
650*1c60b9acSAndroid Build Coastguard Worker 	lws_cancel_service(context);
651*1c60b9acSAndroid Build Coastguard Worker }
652*1c60b9acSAndroid Build Coastguard Worker 
653*1c60b9acSAndroid Build Coastguard Worker static int
callback_lws_sshd_demo(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)654*1c60b9acSAndroid Build Coastguard Worker callback_lws_sshd_demo(struct lws *wsi, enum lws_callback_reasons reason,
655*1c60b9acSAndroid Build Coastguard Worker 		       void *user, void *in, size_t len)
656*1c60b9acSAndroid Build Coastguard Worker {
657*1c60b9acSAndroid Build Coastguard Worker 	struct per_vhost_data__lws_sshd_demo *vhd =
658*1c60b9acSAndroid Build Coastguard Worker 			(struct per_vhost_data__lws_sshd_demo *)
659*1c60b9acSAndroid Build Coastguard Worker 			lws_protocol_vh_priv_get(lws_get_vhost(wsi),
660*1c60b9acSAndroid Build Coastguard Worker 						 lws_get_protocol(wsi));
661*1c60b9acSAndroid Build Coastguard Worker 
662*1c60b9acSAndroid Build Coastguard Worker 	switch (reason) {
663*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_PROTOCOL_INIT:
664*1c60b9acSAndroid Build Coastguard Worker 		vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
665*1c60b9acSAndroid Build Coastguard Worker 						  lws_get_protocol(wsi),
666*1c60b9acSAndroid Build Coastguard Worker 				sizeof(struct per_vhost_data__lws_sshd_demo));
667*1c60b9acSAndroid Build Coastguard Worker 		if (!vhd)
668*1c60b9acSAndroid Build Coastguard Worker 			return 0;
669*1c60b9acSAndroid Build Coastguard Worker 		/*
670*1c60b9acSAndroid Build Coastguard Worker 		 * During this we still have the privs / caps we were started
671*1c60b9acSAndroid Build Coastguard Worker 		 * with.  So open an fd on the server key, either just for read
672*1c60b9acSAndroid Build Coastguard Worker 		 * or for creat / trunc if doesn't exist.  This allows us to
673*1c60b9acSAndroid Build Coastguard Worker 		 * deal with it down /etc/.. when just after this we will lose
674*1c60b9acSAndroid Build Coastguard Worker 		 * the privileges needed to read / write /etc/...
675*1c60b9acSAndroid Build Coastguard Worker 		 */
676*1c60b9acSAndroid Build Coastguard Worker 		vhd->privileged_fd = lws_open(TEST_SERVER_KEY_PATH, O_RDONLY);
677*1c60b9acSAndroid Build Coastguard Worker 		if (vhd->privileged_fd == -1)
678*1c60b9acSAndroid Build Coastguard Worker 			vhd->privileged_fd = lws_open(TEST_SERVER_KEY_PATH,
679*1c60b9acSAndroid Build Coastguard Worker 					O_CREAT | O_TRUNC | O_RDWR, 0600);
680*1c60b9acSAndroid Build Coastguard Worker 		if (vhd->privileged_fd == -1) {
681*1c60b9acSAndroid Build Coastguard Worker 			lwsl_warn("%s: Can't open %s\n", __func__,
682*1c60b9acSAndroid Build Coastguard Worker 				 TEST_SERVER_KEY_PATH);
683*1c60b9acSAndroid Build Coastguard Worker 			return 0;
684*1c60b9acSAndroid Build Coastguard Worker 		}
685*1c60b9acSAndroid Build Coastguard Worker 		break;
686*1c60b9acSAndroid Build Coastguard Worker 
687*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_PROTOCOL_DESTROY:
688*1c60b9acSAndroid Build Coastguard Worker 		if (vhd)
689*1c60b9acSAndroid Build Coastguard Worker 			close(vhd->privileged_fd);
690*1c60b9acSAndroid Build Coastguard Worker 		break;
691*1c60b9acSAndroid Build Coastguard Worker 
692*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_VHOST_CERT_AGING:
693*1c60b9acSAndroid Build Coastguard Worker 		break;
694*1c60b9acSAndroid Build Coastguard Worker 
695*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_EVENT_WAIT_CANCELLED:
696*1c60b9acSAndroid Build Coastguard Worker 		break;
697*1c60b9acSAndroid Build Coastguard Worker 
698*1c60b9acSAndroid Build Coastguard Worker 	default:
699*1c60b9acSAndroid Build Coastguard Worker 		if (!vhd->ssh_base_protocol) {
700*1c60b9acSAndroid Build Coastguard Worker 			vhd->ssh_base_protocol = lws_vhost_name_to_protocol(
701*1c60b9acSAndroid Build Coastguard Worker 							lws_get_vhost(wsi),
702*1c60b9acSAndroid Build Coastguard Worker 							"lws-ssh-base");
703*1c60b9acSAndroid Build Coastguard Worker 			if (vhd->ssh_base_protocol)
704*1c60b9acSAndroid Build Coastguard Worker 				user = lws_adjust_protocol_psds(wsi,
705*1c60b9acSAndroid Build Coastguard Worker 				vhd->ssh_base_protocol->per_session_data_size);
706*1c60b9acSAndroid Build Coastguard Worker 		}
707*1c60b9acSAndroid Build Coastguard Worker 
708*1c60b9acSAndroid Build Coastguard Worker 		if (vhd->ssh_base_protocol)
709*1c60b9acSAndroid Build Coastguard Worker 			return vhd->ssh_base_protocol->callback(wsi, reason,
710*1c60b9acSAndroid Build Coastguard Worker 								user, in, len);
711*1c60b9acSAndroid Build Coastguard Worker 		else
712*1c60b9acSAndroid Build Coastguard Worker 			lwsl_notice("can't find lws-ssh-base\n");
713*1c60b9acSAndroid Build Coastguard Worker 		break;
714*1c60b9acSAndroid Build Coastguard Worker 	}
715*1c60b9acSAndroid Build Coastguard Worker 
716*1c60b9acSAndroid Build Coastguard Worker 	return 0;
717*1c60b9acSAndroid Build Coastguard Worker }
718*1c60b9acSAndroid Build Coastguard Worker 
719*1c60b9acSAndroid Build Coastguard Worker 
720*1c60b9acSAndroid Build Coastguard Worker const struct lws_protocols lws_sshd_demo_protocols[] = {
721*1c60b9acSAndroid Build Coastguard Worker 	{
722*1c60b9acSAndroid Build Coastguard Worker 		"lws-sshd-demo",
723*1c60b9acSAndroid Build Coastguard Worker 		callback_lws_sshd_demo,
724*1c60b9acSAndroid Build Coastguard Worker 		0,
725*1c60b9acSAndroid Build Coastguard Worker 		1024, /* rx buf size must be >= permessage-deflate rx size */
726*1c60b9acSAndroid Build Coastguard Worker 		0, (void *)&ssh_ops, 0
727*1c60b9acSAndroid Build Coastguard Worker 	}
728*1c60b9acSAndroid Build Coastguard Worker 
729*1c60b9acSAndroid Build Coastguard Worker };
730*1c60b9acSAndroid Build Coastguard Worker 
731*1c60b9acSAndroid Build Coastguard Worker 
main()732*1c60b9acSAndroid Build Coastguard Worker int main()
733*1c60b9acSAndroid Build Coastguard Worker {
734*1c60b9acSAndroid Build Coastguard Worker 	static struct lws_context_creation_info info;
735*1c60b9acSAndroid Build Coastguard Worker 	struct lws_vhost *vh_sshd;
736*1c60b9acSAndroid Build Coastguard Worker 	int ret = 1, n;
737*1c60b9acSAndroid Build Coastguard Worker 
738*1c60b9acSAndroid Build Coastguard Worker 	/* info is on the stack, it must be cleared down before use */
739*1c60b9acSAndroid Build Coastguard Worker 	memset(&info, 0, sizeof(info));
740*1c60b9acSAndroid Build Coastguard Worker 
741*1c60b9acSAndroid Build Coastguard Worker 	signal(SIGINT, sighandler);
742*1c60b9acSAndroid Build Coastguard Worker 	lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE
743*1c60b9acSAndroid Build Coastguard Worker 			/*| LLL_INFO */
744*1c60b9acSAndroid Build Coastguard Worker 			/* | LLL_DEBUG */, NULL);
745*1c60b9acSAndroid Build Coastguard Worker 
746*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("lws test-sshd -- Copyright (C) 2017 <[email protected]>\n");
747*1c60b9acSAndroid Build Coastguard Worker 
748*1c60b9acSAndroid Build Coastguard Worker 	/* create the lws context */
749*1c60b9acSAndroid Build Coastguard Worker 
750*1c60b9acSAndroid Build Coastguard Worker 	info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
751*1c60b9acSAndroid Build Coastguard Worker 		       LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
752*1c60b9acSAndroid Build Coastguard Worker 
753*1c60b9acSAndroid Build Coastguard Worker 	context = lws_create_context(&info);
754*1c60b9acSAndroid Build Coastguard Worker 	if (!context) {
755*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("Failed to create context\n");
756*1c60b9acSAndroid Build Coastguard Worker 		return 1;
757*1c60b9acSAndroid Build Coastguard Worker 	}
758*1c60b9acSAndroid Build Coastguard Worker 
759*1c60b9acSAndroid Build Coastguard Worker 	/* create our listening vhost */
760*1c60b9acSAndroid Build Coastguard Worker 
761*1c60b9acSAndroid Build Coastguard Worker 	info.port = 2200;
762*1c60b9acSAndroid Build Coastguard Worker 	info.options = LWS_SERVER_OPTION_ONLY_RAW;
763*1c60b9acSAndroid Build Coastguard Worker 	info.vhost_name = "sshd";
764*1c60b9acSAndroid Build Coastguard Worker 	info.protocols = lws_sshd_demo_protocols;
765*1c60b9acSAndroid Build Coastguard Worker 	info.pvo = &pvo_ssh;
766*1c60b9acSAndroid Build Coastguard Worker 
767*1c60b9acSAndroid Build Coastguard Worker 	vh_sshd = lws_create_vhost(context, &info);
768*1c60b9acSAndroid Build Coastguard Worker 	if (!vh_sshd) {
769*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("Failed to create sshd vhost\n");
770*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
771*1c60b9acSAndroid Build Coastguard Worker 	}
772*1c60b9acSAndroid Build Coastguard Worker 
773*1c60b9acSAndroid Build Coastguard Worker 	/* spin doing service */
774*1c60b9acSAndroid Build Coastguard Worker 
775*1c60b9acSAndroid Build Coastguard Worker 	n = 0;
776*1c60b9acSAndroid Build Coastguard Worker 	while (!n  && !force_exit)
777*1c60b9acSAndroid Build Coastguard Worker 		n = lws_service(context, 0);
778*1c60b9acSAndroid Build Coastguard Worker 
779*1c60b9acSAndroid Build Coastguard Worker 	ret = 0;
780*1c60b9acSAndroid Build Coastguard Worker 
781*1c60b9acSAndroid Build Coastguard Worker 	/* cleanup */
782*1c60b9acSAndroid Build Coastguard Worker 
783*1c60b9acSAndroid Build Coastguard Worker bail:
784*1c60b9acSAndroid Build Coastguard Worker 	lws_context_destroy(context);
785*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("exiting...\n");
786*1c60b9acSAndroid Build Coastguard Worker 
787*1c60b9acSAndroid Build Coastguard Worker 	return ret;
788*1c60b9acSAndroid Build Coastguard Worker }
789