xref: /aosp_15_r20/external/libwebsockets/plugins/protocol_lws_sshd_demo.c (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker  * ws protocol handler plugin for sshd demo
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  * These test plugins 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 #if !defined (LWS_PLUGIN_STATIC)
22*1c60b9acSAndroid Build Coastguard Worker #if !defined(LWS_DLL)
23*1c60b9acSAndroid Build Coastguard Worker #define LWS_DLL
24*1c60b9acSAndroid Build Coastguard Worker #endif
25*1c60b9acSAndroid Build Coastguard Worker #if !defined(LWS_INTERNAL)
26*1c60b9acSAndroid Build Coastguard Worker #define LWS_INTERNAL
27*1c60b9acSAndroid Build Coastguard Worker #endif
28*1c60b9acSAndroid Build Coastguard Worker #include <libwebsockets.h>
29*1c60b9acSAndroid Build Coastguard Worker #endif
30*1c60b9acSAndroid Build Coastguard Worker 
31*1c60b9acSAndroid Build Coastguard Worker #include <lws-ssh.h>
32*1c60b9acSAndroid Build Coastguard Worker 
33*1c60b9acSAndroid Build Coastguard Worker #include <string.h>
34*1c60b9acSAndroid Build Coastguard Worker #include <stdlib.h>
35*1c60b9acSAndroid Build Coastguard Worker #include <errno.h>
36*1c60b9acSAndroid Build Coastguard Worker #include <fcntl.h>
37*1c60b9acSAndroid Build Coastguard Worker 
38*1c60b9acSAndroid Build Coastguard Worker #define TEST_SERVER_KEY_PATH "/etc/lws-test-sshd-server-key"
39*1c60b9acSAndroid Build Coastguard Worker 
40*1c60b9acSAndroid Build Coastguard Worker struct per_vhost_data__lws_sshd_demo {
41*1c60b9acSAndroid Build Coastguard Worker 	const struct lws_protocols *ssh_base_protocol;
42*1c60b9acSAndroid Build Coastguard Worker 	int privileged_fd;
43*1c60b9acSAndroid Build Coastguard Worker };
44*1c60b9acSAndroid Build Coastguard Worker 
45*1c60b9acSAndroid Build Coastguard Worker /*
46*1c60b9acSAndroid Build Coastguard Worker  *  This is a copy of the lws ssh test public key, you can find it in
47*1c60b9acSAndroid Build Coastguard Worker  *  /usr[/local]/share/libwebsockets-test-server/lws-ssh-test-keys.pub
48*1c60b9acSAndroid Build Coastguard Worker  *  and the matching private key there too in .../lws-ssh-test-keys
49*1c60b9acSAndroid Build Coastguard Worker  *
50*1c60b9acSAndroid Build Coastguard Worker  *  If the vhost with this protocol is using localhost:2222, you can test with
51*1c60b9acSAndroid Build Coastguard Worker  *  the matching private key like this:
52*1c60b9acSAndroid Build Coastguard Worker  *
53*1c60b9acSAndroid Build Coastguard Worker  *  ssh -p 2222 -i /usr/local/share/libwebsockets-test-server/lws-ssh-test-keys [email protected]
54*1c60b9acSAndroid Build Coastguard Worker  *
55*1c60b9acSAndroid Build Coastguard Worker  *  These keys are distributed for testing!  Don't use them on a real system
56*1c60b9acSAndroid Build Coastguard Worker  *  unless you want anyone with a copy of lws to access it.
57*1c60b9acSAndroid Build Coastguard Worker  */
58*1c60b9acSAndroid Build Coastguard Worker static const char *authorized_key =
59*1c60b9acSAndroid Build Coastguard Worker 	"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCnWiP+c+kSD6Lk+C6NA9KruApa45sbt"
60*1c60b9acSAndroid Build Coastguard Worker 	"94/dxT0bCITlAA/+PBk6mR1lwWgXYozOMdrHrqx34piqDyXnc4HabqCaOm/FrYhkCPL8z"
61*1c60b9acSAndroid Build Coastguard Worker 	"a26PMYqteSosuwKv//5iT6ZWhNnsMwExBwtV6MIq0MxAeWqxRnYNWpNM8iN6sFzkdG/YF"
62*1c60b9acSAndroid Build Coastguard Worker 	"dyHrIBTgwzM77NLCMl6GEkJErRCFppC2SwYxGa3BRrgUwX3LkV8HpMIaYHFo1Qgj7Scqm"
63*1c60b9acSAndroid Build Coastguard Worker 	"HwS2R75SOqi2aOWDpKjznARg9JgzDWSQi4seBMV2oL0BTwJANSDf+p0sQLsaKGJhpVpBQ"
64*1c60b9acSAndroid Build Coastguard Worker 	"yS2wUeyuGyytupWzEluQrajMZq52iotcogv5BfeulfTTFbJP4kuHOsSP0lsQ2lpMDQANS"
65*1c60b9acSAndroid Build Coastguard Worker 	"HEvXxzHJLDLXM9gXJzwJ+ZiRt6R+bfmP1nfN3MiWtxcIbBanWwQK6xTCKBe4wPaKta5EU"
66*1c60b9acSAndroid Build Coastguard Worker 	"6wsLPeakOIVzoeaOu/HsbtPZlwX0Mu/oUFcfKyKAhlkU15MOAIEfUPo8Yh52bWMlIlpZa"
67*1c60b9acSAndroid Build Coastguard Worker 	"4xWbLMGw3GrsrPPdcsAauyqvY4/NjjWQbWhP1SuUfvv5709PIiOUjVKK2HUwmR1ouch6X"
68*1c60b9acSAndroid Build Coastguard Worker 	"MQGXfMR1h1Wjvc+bkNs17gCIrQnFilAZLC3Sm3Opiz/4LO99Hw448G0RM2vQn0mJE46w"
69*1c60b9acSAndroid Build Coastguard Worker 	"Eu/B10U6Jf4Efojhh1dk85BD1LTIb+N3Q== ssh-test-key@lws";
70*1c60b9acSAndroid Build Coastguard Worker 
71*1c60b9acSAndroid Build Coastguard Worker enum states {
72*1c60b9acSAndroid Build Coastguard Worker 	SSH_TEST_GREET,
73*1c60b9acSAndroid Build Coastguard Worker 	SSH_TEST_PRESSED,
74*1c60b9acSAndroid Build Coastguard Worker 	SSH_TEST_DONE,
75*1c60b9acSAndroid Build Coastguard Worker };
76*1c60b9acSAndroid Build Coastguard Worker 
77*1c60b9acSAndroid Build Coastguard Worker static const char * const strings[] =
78*1c60b9acSAndroid Build Coastguard Worker 	{
79*1c60b9acSAndroid Build Coastguard Worker 		/* SSH_TEST_GREET */
80*1c60b9acSAndroid Build Coastguard Worker 		"Thanks for logging to lws sshd server demo.\n\r"
81*1c60b9acSAndroid Build Coastguard Worker 		"\n\r"
82*1c60b9acSAndroid Build Coastguard Worker 		"This demo is very simple, it waits for you to press\n\r"
83*1c60b9acSAndroid Build Coastguard Worker 		"a key, and acknowledges it.  Then press another key\n\r"
84*1c60b9acSAndroid Build Coastguard Worker 		"and it will exit.  But actually that demos the basic\n\r"
85*1c60b9acSAndroid Build Coastguard Worker 		"sshd functions underneath.  You can use the ops struct\n\r"
86*1c60b9acSAndroid Build Coastguard Worker 		"members to add a pty / shell or whatever you want.\n\r"
87*1c60b9acSAndroid Build Coastguard Worker 		"\n\r"
88*1c60b9acSAndroid Build Coastguard Worker 		"Press a key...\n\r",
89*1c60b9acSAndroid Build Coastguard Worker 
90*1c60b9acSAndroid Build Coastguard Worker 		/* SSH_TEST_PRESSED */
91*1c60b9acSAndroid Build Coastguard Worker 		"Thanks for pressing a key.  Press another to exit.\n\r",
92*1c60b9acSAndroid Build Coastguard Worker 
93*1c60b9acSAndroid Build Coastguard Worker 		/* SSH_TEST_DONE */
94*1c60b9acSAndroid Build Coastguard Worker 		"Bye!\n\r"
95*1c60b9acSAndroid Build Coastguard Worker 	};
96*1c60b9acSAndroid Build Coastguard Worker 
97*1c60b9acSAndroid Build Coastguard Worker struct sshd_instance_priv {
98*1c60b9acSAndroid Build Coastguard Worker 	struct lws *wsi;
99*1c60b9acSAndroid Build Coastguard Worker 	enum states state;
100*1c60b9acSAndroid Build Coastguard Worker 	const char *ptr;
101*1c60b9acSAndroid Build Coastguard Worker 	int pos;
102*1c60b9acSAndroid Build Coastguard Worker 	int len;
103*1c60b9acSAndroid Build Coastguard Worker };
104*1c60b9acSAndroid Build Coastguard Worker 
105*1c60b9acSAndroid Build Coastguard Worker static void
enter_state(struct sshd_instance_priv * priv,enum states state)106*1c60b9acSAndroid Build Coastguard Worker enter_state(struct sshd_instance_priv *priv, enum states state)
107*1c60b9acSAndroid Build Coastguard Worker {
108*1c60b9acSAndroid Build Coastguard Worker 	priv->state = state;
109*1c60b9acSAndroid Build Coastguard Worker 	priv->ptr = strings[state];
110*1c60b9acSAndroid Build Coastguard Worker 	priv->pos = 0;
111*1c60b9acSAndroid Build Coastguard Worker 	priv->len = (int)strlen(priv->ptr);
112*1c60b9acSAndroid Build Coastguard Worker 
113*1c60b9acSAndroid Build Coastguard Worker 	lws_callback_on_writable(priv->wsi);
114*1c60b9acSAndroid Build Coastguard Worker }
115*1c60b9acSAndroid Build Coastguard Worker 
116*1c60b9acSAndroid Build Coastguard Worker /* ops: channel lifecycle */
117*1c60b9acSAndroid Build Coastguard Worker 
118*1c60b9acSAndroid Build Coastguard Worker static int
ssh_ops_channel_create(struct lws * wsi,void ** _priv)119*1c60b9acSAndroid Build Coastguard Worker ssh_ops_channel_create(struct lws *wsi, void **_priv)
120*1c60b9acSAndroid Build Coastguard Worker {
121*1c60b9acSAndroid Build Coastguard Worker 	struct sshd_instance_priv *priv;
122*1c60b9acSAndroid Build Coastguard Worker 
123*1c60b9acSAndroid Build Coastguard Worker 	priv = malloc(sizeof(struct sshd_instance_priv));
124*1c60b9acSAndroid Build Coastguard Worker 	*_priv = priv;
125*1c60b9acSAndroid Build Coastguard Worker 	if (!priv)
126*1c60b9acSAndroid Build Coastguard Worker 		return 1;
127*1c60b9acSAndroid Build Coastguard Worker 
128*1c60b9acSAndroid Build Coastguard Worker 	memset(priv, 0, sizeof(*priv));
129*1c60b9acSAndroid Build Coastguard Worker 	priv->wsi = wsi;
130*1c60b9acSAndroid Build Coastguard Worker 
131*1c60b9acSAndroid Build Coastguard Worker 	return 0;
132*1c60b9acSAndroid Build Coastguard Worker }
133*1c60b9acSAndroid Build Coastguard Worker 
134*1c60b9acSAndroid Build Coastguard Worker static int
ssh_ops_channel_destroy(void * _priv)135*1c60b9acSAndroid Build Coastguard Worker ssh_ops_channel_destroy(void *_priv)
136*1c60b9acSAndroid Build Coastguard Worker {
137*1c60b9acSAndroid Build Coastguard Worker 	struct sshd_instance_priv *priv = _priv;
138*1c60b9acSAndroid Build Coastguard Worker 
139*1c60b9acSAndroid Build Coastguard Worker 	free(priv);
140*1c60b9acSAndroid Build Coastguard Worker 
141*1c60b9acSAndroid Build Coastguard Worker 	return 0;
142*1c60b9acSAndroid Build Coastguard Worker }
143*1c60b9acSAndroid Build Coastguard Worker 
144*1c60b9acSAndroid Build Coastguard Worker /* ops: IO */
145*1c60b9acSAndroid Build Coastguard Worker 
146*1c60b9acSAndroid Build Coastguard Worker static int
ssh_ops_tx_waiting(void * _priv)147*1c60b9acSAndroid Build Coastguard Worker ssh_ops_tx_waiting(void *_priv)
148*1c60b9acSAndroid Build Coastguard Worker {
149*1c60b9acSAndroid Build Coastguard Worker 	struct sshd_instance_priv *priv = _priv;
150*1c60b9acSAndroid Build Coastguard Worker 
151*1c60b9acSAndroid Build Coastguard Worker 	if (priv->state == SSH_TEST_DONE &&
152*1c60b9acSAndroid Build Coastguard Worker 	    priv->pos == priv->len)
153*1c60b9acSAndroid Build Coastguard Worker 		return -1; /* exit */
154*1c60b9acSAndroid Build Coastguard Worker 
155*1c60b9acSAndroid Build Coastguard Worker 	if (priv->pos != priv->len)
156*1c60b9acSAndroid Build Coastguard Worker 		return LWS_STDOUT;
157*1c60b9acSAndroid Build Coastguard Worker 
158*1c60b9acSAndroid Build Coastguard Worker 	return 0;
159*1c60b9acSAndroid Build Coastguard Worker }
160*1c60b9acSAndroid Build Coastguard Worker 
161*1c60b9acSAndroid Build Coastguard Worker static size_t
ssh_ops_tx(void * _priv,int stdch,uint8_t * buf,size_t len)162*1c60b9acSAndroid Build Coastguard Worker ssh_ops_tx(void *_priv, int stdch, uint8_t *buf, size_t len)
163*1c60b9acSAndroid Build Coastguard Worker {
164*1c60b9acSAndroid Build Coastguard Worker 	struct sshd_instance_priv *priv = _priv;
165*1c60b9acSAndroid Build Coastguard Worker 	size_t chunk = len;
166*1c60b9acSAndroid Build Coastguard Worker 
167*1c60b9acSAndroid Build Coastguard Worker 	if (stdch != LWS_STDOUT)
168*1c60b9acSAndroid Build Coastguard Worker 		return 0;
169*1c60b9acSAndroid Build Coastguard Worker 
170*1c60b9acSAndroid Build Coastguard Worker 	if ((size_t)(priv->len - priv->pos) < chunk)
171*1c60b9acSAndroid Build Coastguard Worker 		chunk = (size_t)(priv->len - priv->pos);
172*1c60b9acSAndroid Build Coastguard Worker 
173*1c60b9acSAndroid Build Coastguard Worker 	if (!chunk)
174*1c60b9acSAndroid Build Coastguard Worker 		return 0;
175*1c60b9acSAndroid Build Coastguard Worker 
176*1c60b9acSAndroid Build Coastguard Worker 	memcpy(buf, priv->ptr + priv->pos, chunk);
177*1c60b9acSAndroid Build Coastguard Worker 	priv->pos += (int)chunk;
178*1c60b9acSAndroid Build Coastguard Worker 
179*1c60b9acSAndroid Build Coastguard Worker 	if (priv->state == SSH_TEST_DONE && priv->pos == priv->len) {
180*1c60b9acSAndroid Build Coastguard Worker 		/*
181*1c60b9acSAndroid Build Coastguard Worker 		 * we are sending the last thing we want to send
182*1c60b9acSAndroid Build Coastguard Worker 		 * before exiting.  Make it ask again at ssh_ops_tx_waiting()
183*1c60b9acSAndroid Build Coastguard Worker 		 * and we will exit then, after this has been sent
184*1c60b9acSAndroid Build Coastguard Worker 		 */
185*1c60b9acSAndroid Build Coastguard Worker 		lws_callback_on_writable(priv->wsi);
186*1c60b9acSAndroid Build Coastguard Worker 	}
187*1c60b9acSAndroid Build Coastguard Worker 
188*1c60b9acSAndroid Build Coastguard Worker 	return chunk;
189*1c60b9acSAndroid Build Coastguard Worker }
190*1c60b9acSAndroid Build Coastguard Worker 
191*1c60b9acSAndroid Build Coastguard Worker 
192*1c60b9acSAndroid Build Coastguard Worker static int
ssh_ops_rx(void * _priv,struct lws * wsi,const uint8_t * buf,uint32_t len)193*1c60b9acSAndroid Build Coastguard Worker ssh_ops_rx(void *_priv, struct lws *wsi, const uint8_t *buf, uint32_t len)
194*1c60b9acSAndroid Build Coastguard Worker {
195*1c60b9acSAndroid Build Coastguard Worker 	struct sshd_instance_priv *priv = _priv;
196*1c60b9acSAndroid Build Coastguard Worker 
197*1c60b9acSAndroid Build Coastguard Worker 	if (priv->state < SSH_TEST_DONE)
198*1c60b9acSAndroid Build Coastguard Worker 		enter_state(priv, priv->state + 1);
199*1c60b9acSAndroid Build Coastguard Worker 	else
200*1c60b9acSAndroid Build Coastguard Worker 		return -1;
201*1c60b9acSAndroid Build Coastguard Worker 
202*1c60b9acSAndroid Build Coastguard Worker 	return 0;
203*1c60b9acSAndroid Build Coastguard Worker }
204*1c60b9acSAndroid Build Coastguard Worker 
205*1c60b9acSAndroid Build Coastguard Worker /* ops: storage for the (autogenerated) persistent server key */
206*1c60b9acSAndroid Build Coastguard Worker 
207*1c60b9acSAndroid Build Coastguard Worker static size_t
ssh_ops_get_server_key(struct lws * wsi,uint8_t * buf,size_t len)208*1c60b9acSAndroid Build Coastguard Worker ssh_ops_get_server_key(struct lws *wsi, uint8_t *buf, size_t len)
209*1c60b9acSAndroid Build Coastguard Worker {
210*1c60b9acSAndroid Build Coastguard Worker 	struct per_vhost_data__lws_sshd_demo *vhd =
211*1c60b9acSAndroid Build Coastguard Worker 			(struct per_vhost_data__lws_sshd_demo *)
212*1c60b9acSAndroid Build Coastguard Worker 			lws_protocol_vh_priv_get(lws_get_vhost(wsi),
213*1c60b9acSAndroid Build Coastguard Worker 						 lws_get_protocol(wsi));
214*1c60b9acSAndroid Build Coastguard Worker 	int n;
215*1c60b9acSAndroid Build Coastguard Worker 
216*1c60b9acSAndroid Build Coastguard Worker 	if (lseek(vhd->privileged_fd, 0, SEEK_SET) < 0)
217*1c60b9acSAndroid Build Coastguard Worker 		return 0;
218*1c60b9acSAndroid Build Coastguard Worker 	n = (int)read(vhd->privileged_fd, buf, (unsigned int)len);
219*1c60b9acSAndroid Build Coastguard Worker 	if (n < 0) {
220*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: read failed: %d\n", __func__, n);
221*1c60b9acSAndroid Build Coastguard Worker 		n = 0;
222*1c60b9acSAndroid Build Coastguard Worker 	}
223*1c60b9acSAndroid Build Coastguard Worker 
224*1c60b9acSAndroid Build Coastguard Worker 	return (size_t)n;
225*1c60b9acSAndroid Build Coastguard Worker }
226*1c60b9acSAndroid Build Coastguard Worker 
227*1c60b9acSAndroid Build Coastguard Worker static size_t
ssh_ops_set_server_key(struct lws * wsi,uint8_t * buf,size_t len)228*1c60b9acSAndroid Build Coastguard Worker ssh_ops_set_server_key(struct lws *wsi, uint8_t *buf, size_t len)
229*1c60b9acSAndroid Build Coastguard Worker {
230*1c60b9acSAndroid Build Coastguard Worker 	struct per_vhost_data__lws_sshd_demo *vhd =
231*1c60b9acSAndroid Build Coastguard Worker 			(struct per_vhost_data__lws_sshd_demo *)
232*1c60b9acSAndroid Build Coastguard Worker 			lws_protocol_vh_priv_get(lws_get_vhost(wsi),
233*1c60b9acSAndroid Build Coastguard Worker 						 lws_get_protocol(wsi));
234*1c60b9acSAndroid Build Coastguard Worker 	int n;
235*1c60b9acSAndroid Build Coastguard Worker 
236*1c60b9acSAndroid Build Coastguard Worker 	n = (int)write(vhd->privileged_fd, buf, (unsigned int)len);
237*1c60b9acSAndroid Build Coastguard Worker 	if (n < 0) {
238*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: read failed: %d\n", __func__, errno);
239*1c60b9acSAndroid Build Coastguard Worker 		n = 0;
240*1c60b9acSAndroid Build Coastguard Worker 	}
241*1c60b9acSAndroid Build Coastguard Worker 
242*1c60b9acSAndroid Build Coastguard Worker 	return (size_t)n;
243*1c60b9acSAndroid Build Coastguard Worker }
244*1c60b9acSAndroid Build Coastguard Worker 
245*1c60b9acSAndroid Build Coastguard Worker /* ops: auth */
246*1c60b9acSAndroid Build Coastguard Worker 
247*1c60b9acSAndroid Build Coastguard Worker static int
ssh_ops_is_pubkey_authorized(const char * username,const char * type,const uint8_t * peer,int peer_len)248*1c60b9acSAndroid Build Coastguard Worker ssh_ops_is_pubkey_authorized(const char *username, const char *type,
249*1c60b9acSAndroid Build Coastguard Worker 				 const uint8_t *peer, int peer_len)
250*1c60b9acSAndroid Build Coastguard Worker {
251*1c60b9acSAndroid Build Coastguard Worker 	char *aps, *p, *ps;
252*1c60b9acSAndroid Build Coastguard Worker 	int n = (int)strlen(type), alen = 2048, ret = 2, len;
253*1c60b9acSAndroid Build Coastguard Worker 	size_t s = 0;
254*1c60b9acSAndroid Build Coastguard Worker 
255*1c60b9acSAndroid Build Coastguard Worker 	lwsl_info("%s: checking pubkey for %s\n", __func__, username);
256*1c60b9acSAndroid Build Coastguard Worker 
257*1c60b9acSAndroid Build Coastguard Worker 	s = strlen(authorized_key) + 1;
258*1c60b9acSAndroid Build Coastguard Worker 
259*1c60b9acSAndroid Build Coastguard Worker 	aps = malloc(s);
260*1c60b9acSAndroid Build Coastguard Worker 	if (!aps) {
261*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("OOM 1\n");
262*1c60b9acSAndroid Build Coastguard Worker 		goto bail_p1;
263*1c60b9acSAndroid Build Coastguard Worker 	}
264*1c60b9acSAndroid Build Coastguard Worker 	memcpy(aps, authorized_key, s);
265*1c60b9acSAndroid Build Coastguard Worker 
266*1c60b9acSAndroid Build Coastguard Worker 	/* we only understand RSA */
267*1c60b9acSAndroid Build Coastguard Worker 	if (strcmp(type, "ssh-rsa")) {
268*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("type is not ssh-rsa\n");
269*1c60b9acSAndroid Build Coastguard Worker 		goto bail_p1;
270*1c60b9acSAndroid Build Coastguard Worker 	}
271*1c60b9acSAndroid Build Coastguard Worker 	p = aps;
272*1c60b9acSAndroid Build Coastguard Worker 
273*1c60b9acSAndroid Build Coastguard Worker 	if (strncmp(p, type, (unsigned int)n)) {
274*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("lead-in string  does not match %s\n", type);
275*1c60b9acSAndroid Build Coastguard Worker 		goto bail_p1;
276*1c60b9acSAndroid Build Coastguard Worker 	}
277*1c60b9acSAndroid Build Coastguard Worker 
278*1c60b9acSAndroid Build Coastguard Worker 	p += n;
279*1c60b9acSAndroid Build Coastguard Worker 	if (*p != ' ') {
280*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("missing space at end of lead-in\n");
281*1c60b9acSAndroid Build Coastguard Worker 		goto bail_p1;
282*1c60b9acSAndroid Build Coastguard Worker 	}
283*1c60b9acSAndroid Build Coastguard Worker 
284*1c60b9acSAndroid Build Coastguard Worker 	p++;
285*1c60b9acSAndroid Build Coastguard Worker 	ps = malloc((unsigned int)alen);
286*1c60b9acSAndroid Build Coastguard Worker 	if (!ps) {
287*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("OOM 2\n");
288*1c60b9acSAndroid Build Coastguard Worker 		free(aps);
289*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
290*1c60b9acSAndroid Build Coastguard Worker 	}
291*1c60b9acSAndroid Build Coastguard Worker 	len = lws_b64_decode_string(p, ps, alen);
292*1c60b9acSAndroid Build Coastguard Worker 	free(aps);
293*1c60b9acSAndroid Build Coastguard Worker 	if (len < 0) {
294*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("key too big\n");
295*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
296*1c60b9acSAndroid Build Coastguard Worker 	}
297*1c60b9acSAndroid Build Coastguard Worker 
298*1c60b9acSAndroid Build Coastguard Worker 	if (peer_len > len) {
299*1c60b9acSAndroid Build Coastguard Worker 		lwsl_notice("peer_len %d bigger than decoded len %d\n",
300*1c60b9acSAndroid Build Coastguard Worker 				peer_len, len);
301*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
302*1c60b9acSAndroid Build Coastguard Worker 	}
303*1c60b9acSAndroid Build Coastguard Worker 
304*1c60b9acSAndroid Build Coastguard Worker 	/*
305*1c60b9acSAndroid Build Coastguard Worker 	 * once we are past that, it's the same <len32>name
306*1c60b9acSAndroid Build Coastguard Worker 	 * <len32>E<len32>N that the peer sends us
307*1c60b9acSAndroid Build Coastguard Worker 	 */
308*1c60b9acSAndroid Build Coastguard Worker 	if (memcmp(peer, ps, (unsigned int)peer_len)) {
309*1c60b9acSAndroid Build Coastguard Worker 		lwsl_info("%s: factors mismatch, rejecting key\n", __func__);
310*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
311*1c60b9acSAndroid Build Coastguard Worker 	}
312*1c60b9acSAndroid Build Coastguard Worker 
313*1c60b9acSAndroid Build Coastguard Worker 	lwsl_info("pubkey authorized\n");
314*1c60b9acSAndroid Build Coastguard Worker 
315*1c60b9acSAndroid Build Coastguard Worker 	ret = 0;
316*1c60b9acSAndroid Build Coastguard Worker bail:
317*1c60b9acSAndroid Build Coastguard Worker 	free(ps);
318*1c60b9acSAndroid Build Coastguard Worker 
319*1c60b9acSAndroid Build Coastguard Worker 	return ret;
320*1c60b9acSAndroid Build Coastguard Worker 
321*1c60b9acSAndroid Build Coastguard Worker bail_p1:
322*1c60b9acSAndroid Build Coastguard Worker 	if (aps)
323*1c60b9acSAndroid Build Coastguard Worker 		free(aps);
324*1c60b9acSAndroid Build Coastguard Worker 
325*1c60b9acSAndroid Build Coastguard Worker 	return 1;
326*1c60b9acSAndroid Build Coastguard Worker }
327*1c60b9acSAndroid Build Coastguard Worker 
328*1c60b9acSAndroid Build Coastguard Worker static int
ssh_ops_shell(void * _priv,struct lws * wsi,lws_ssh_finish_exec finish,void * finish_handle)329*1c60b9acSAndroid Build Coastguard Worker ssh_ops_shell(void *_priv, struct lws *wsi, lws_ssh_finish_exec finish, void *finish_handle)
330*1c60b9acSAndroid Build Coastguard Worker {
331*1c60b9acSAndroid Build Coastguard Worker 	struct sshd_instance_priv *priv = _priv;
332*1c60b9acSAndroid Build Coastguard Worker 
333*1c60b9acSAndroid Build Coastguard Worker 	/* for this demo, we don't open a real shell */
334*1c60b9acSAndroid Build Coastguard Worker 
335*1c60b9acSAndroid Build Coastguard Worker 	enter_state(priv, SSH_TEST_GREET);
336*1c60b9acSAndroid Build Coastguard Worker 
337*1c60b9acSAndroid Build Coastguard Worker 	return 0;
338*1c60b9acSAndroid Build Coastguard Worker }
339*1c60b9acSAndroid Build Coastguard Worker 
340*1c60b9acSAndroid Build Coastguard Worker /* ops: banner */
341*1c60b9acSAndroid Build Coastguard Worker 
342*1c60b9acSAndroid Build Coastguard Worker static size_t
ssh_ops_banner(char * buf,size_t max_len,char * lang,size_t max_lang_len)343*1c60b9acSAndroid Build Coastguard Worker ssh_ops_banner(char *buf, size_t max_len, char *lang, size_t max_lang_len)
344*1c60b9acSAndroid Build Coastguard Worker {
345*1c60b9acSAndroid Build Coastguard Worker 	int n = lws_snprintf(buf, max_len, "\n"
346*1c60b9acSAndroid Build Coastguard Worker 		      " |\\---/|  lws-ssh Test Server\n"
347*1c60b9acSAndroid Build Coastguard Worker 		      " | o_o |  SSH Terminal Server\n"
348*1c60b9acSAndroid Build Coastguard Worker 		      "  \\_^_/   Copyright (C) 2017 Crash Barrier Ltd\n\n");
349*1c60b9acSAndroid Build Coastguard Worker 
350*1c60b9acSAndroid Build Coastguard Worker 	lws_snprintf(lang, max_lang_len, "en/US");
351*1c60b9acSAndroid Build Coastguard Worker 
352*1c60b9acSAndroid Build Coastguard Worker 	return (size_t)n;
353*1c60b9acSAndroid Build Coastguard Worker }
354*1c60b9acSAndroid Build Coastguard Worker 
355*1c60b9acSAndroid Build Coastguard Worker static void
ssh_ops_disconnect_reason(uint32_t reason,const char * desc,const char * desc_lang)356*1c60b9acSAndroid Build Coastguard Worker ssh_ops_disconnect_reason(uint32_t reason, const char *desc,
357*1c60b9acSAndroid Build Coastguard Worker 			  const char *desc_lang)
358*1c60b9acSAndroid Build Coastguard Worker {
359*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("DISCONNECT reason 0x%X, %s (lang %s)\n", reason, desc,
360*1c60b9acSAndroid Build Coastguard Worker 		    desc_lang);
361*1c60b9acSAndroid Build Coastguard Worker }
362*1c60b9acSAndroid Build Coastguard Worker 
363*1c60b9acSAndroid Build Coastguard Worker 
364*1c60b9acSAndroid Build Coastguard Worker static const struct lws_ssh_ops ssh_ops = {
365*1c60b9acSAndroid Build Coastguard Worker 	.channel_create			= ssh_ops_channel_create,
366*1c60b9acSAndroid Build Coastguard Worker 	.channel_destroy		= ssh_ops_channel_destroy,
367*1c60b9acSAndroid Build Coastguard Worker 	.tx_waiting			= ssh_ops_tx_waiting,
368*1c60b9acSAndroid Build Coastguard Worker 	.tx				= ssh_ops_tx,
369*1c60b9acSAndroid Build Coastguard Worker 	.rx				= ssh_ops_rx,
370*1c60b9acSAndroid Build Coastguard Worker 	.get_server_key			= ssh_ops_get_server_key,
371*1c60b9acSAndroid Build Coastguard Worker 	.set_server_key			= ssh_ops_set_server_key,
372*1c60b9acSAndroid Build Coastguard Worker 	.set_env			= NULL,
373*1c60b9acSAndroid Build Coastguard Worker 	.pty_req			= NULL,
374*1c60b9acSAndroid Build Coastguard Worker 	.child_process_io		= NULL,
375*1c60b9acSAndroid Build Coastguard Worker 	.child_process_terminated	= NULL,
376*1c60b9acSAndroid Build Coastguard Worker 	.exec				= NULL,
377*1c60b9acSAndroid Build Coastguard Worker 	.shell				= ssh_ops_shell,
378*1c60b9acSAndroid Build Coastguard Worker 	.is_pubkey_authorized		= ssh_ops_is_pubkey_authorized,
379*1c60b9acSAndroid Build Coastguard Worker 	.banner				= ssh_ops_banner,
380*1c60b9acSAndroid Build Coastguard Worker 	.disconnect_reason		= ssh_ops_disconnect_reason,
381*1c60b9acSAndroid Build Coastguard Worker 	.server_string			= "SSH-2.0-Libwebsockets",
382*1c60b9acSAndroid Build Coastguard Worker 	.api_version			= 2,
383*1c60b9acSAndroid Build Coastguard Worker };
384*1c60b9acSAndroid Build Coastguard Worker 
385*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)386*1c60b9acSAndroid Build Coastguard Worker callback_lws_sshd_demo(struct lws *wsi, enum lws_callback_reasons reason,
387*1c60b9acSAndroid Build Coastguard Worker 		       void *user, void *in, size_t len)
388*1c60b9acSAndroid Build Coastguard Worker {
389*1c60b9acSAndroid Build Coastguard Worker 	struct per_vhost_data__lws_sshd_demo *vhd =
390*1c60b9acSAndroid Build Coastguard Worker 			(struct per_vhost_data__lws_sshd_demo *)
391*1c60b9acSAndroid Build Coastguard Worker 			lws_protocol_vh_priv_get(lws_get_vhost(wsi),
392*1c60b9acSAndroid Build Coastguard Worker 						 lws_get_protocol(wsi));
393*1c60b9acSAndroid Build Coastguard Worker 
394*1c60b9acSAndroid Build Coastguard Worker 	switch (reason) {
395*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_PROTOCOL_INIT:
396*1c60b9acSAndroid Build Coastguard Worker 		vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
397*1c60b9acSAndroid Build Coastguard Worker 						  lws_get_protocol(wsi),
398*1c60b9acSAndroid Build Coastguard Worker 				sizeof(struct per_vhost_data__lws_sshd_demo));
399*1c60b9acSAndroid Build Coastguard Worker 		if (!vhd)
400*1c60b9acSAndroid Build Coastguard Worker 			return 0;
401*1c60b9acSAndroid Build Coastguard Worker 		/*
402*1c60b9acSAndroid Build Coastguard Worker 		 * During this we still have the privs / caps we were started
403*1c60b9acSAndroid Build Coastguard Worker 		 * with.  So open an fd on the server key, either just for read
404*1c60b9acSAndroid Build Coastguard Worker 		 * or for creat / trunc if doesn't exist.  This allows us to
405*1c60b9acSAndroid Build Coastguard Worker 		 * deal with it down /etc/.. when just after this we will lose
406*1c60b9acSAndroid Build Coastguard Worker 		 * the privileges needed to read / write /etc/...
407*1c60b9acSAndroid Build Coastguard Worker 		 */
408*1c60b9acSAndroid Build Coastguard Worker 		vhd->privileged_fd = lws_open(TEST_SERVER_KEY_PATH, O_RDONLY);
409*1c60b9acSAndroid Build Coastguard Worker 		if (vhd->privileged_fd == -1)
410*1c60b9acSAndroid Build Coastguard Worker 			vhd->privileged_fd = lws_open(TEST_SERVER_KEY_PATH,
411*1c60b9acSAndroid Build Coastguard Worker 					O_CREAT | O_TRUNC | O_RDWR, 0600);
412*1c60b9acSAndroid Build Coastguard Worker 		if (vhd->privileged_fd == -1) {
413*1c60b9acSAndroid Build Coastguard Worker 			lwsl_warn("%s: Can't open %s\n", __func__,
414*1c60b9acSAndroid Build Coastguard Worker 				 TEST_SERVER_KEY_PATH);
415*1c60b9acSAndroid Build Coastguard Worker 			return 0;
416*1c60b9acSAndroid Build Coastguard Worker 		}
417*1c60b9acSAndroid Build Coastguard Worker 		break;
418*1c60b9acSAndroid Build Coastguard Worker 
419*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_PROTOCOL_DESTROY:
420*1c60b9acSAndroid Build Coastguard Worker 		if (vhd)
421*1c60b9acSAndroid Build Coastguard Worker 			close(vhd->privileged_fd);
422*1c60b9acSAndroid Build Coastguard Worker 		break;
423*1c60b9acSAndroid Build Coastguard Worker 
424*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_VHOST_CERT_AGING:
425*1c60b9acSAndroid Build Coastguard Worker 		break;
426*1c60b9acSAndroid Build Coastguard Worker 
427*1c60b9acSAndroid Build Coastguard Worker 	case LWS_CALLBACK_EVENT_WAIT_CANCELLED:
428*1c60b9acSAndroid Build Coastguard Worker 		break;
429*1c60b9acSAndroid Build Coastguard Worker 
430*1c60b9acSAndroid Build Coastguard Worker 	default:
431*1c60b9acSAndroid Build Coastguard Worker 		if (!vhd->ssh_base_protocol) {
432*1c60b9acSAndroid Build Coastguard Worker 			vhd->ssh_base_protocol = lws_vhost_name_to_protocol(
433*1c60b9acSAndroid Build Coastguard Worker 							lws_get_vhost(wsi),
434*1c60b9acSAndroid Build Coastguard Worker 							"lws-ssh-base");
435*1c60b9acSAndroid Build Coastguard Worker 			if (vhd->ssh_base_protocol)
436*1c60b9acSAndroid Build Coastguard Worker 				user = lws_adjust_protocol_psds(wsi,
437*1c60b9acSAndroid Build Coastguard Worker 				vhd->ssh_base_protocol->per_session_data_size);
438*1c60b9acSAndroid Build Coastguard Worker 		}
439*1c60b9acSAndroid Build Coastguard Worker 
440*1c60b9acSAndroid Build Coastguard Worker 		if (vhd->ssh_base_protocol)
441*1c60b9acSAndroid Build Coastguard Worker 			return vhd->ssh_base_protocol->callback(wsi, reason,
442*1c60b9acSAndroid Build Coastguard Worker 								user, in, len);
443*1c60b9acSAndroid Build Coastguard Worker 		else
444*1c60b9acSAndroid Build Coastguard Worker 			lwsl_notice("can't find lws-ssh-base\n");
445*1c60b9acSAndroid Build Coastguard Worker 		break;
446*1c60b9acSAndroid Build Coastguard Worker 	}
447*1c60b9acSAndroid Build Coastguard Worker 
448*1c60b9acSAndroid Build Coastguard Worker 	return 0;
449*1c60b9acSAndroid Build Coastguard Worker }
450*1c60b9acSAndroid Build Coastguard Worker 
451*1c60b9acSAndroid Build Coastguard Worker #define LWS_PLUGIN_PROTOCOL_LWS_SSHD_DEMO \
452*1c60b9acSAndroid Build Coastguard Worker 	{ \
453*1c60b9acSAndroid Build Coastguard Worker 		"lws-sshd-demo", \
454*1c60b9acSAndroid Build Coastguard Worker 		callback_lws_sshd_demo, \
455*1c60b9acSAndroid Build Coastguard Worker 		0, \
456*1c60b9acSAndroid Build Coastguard Worker 		1024, /* rx buf size must be >= permessage-deflate rx size */ \
457*1c60b9acSAndroid Build Coastguard Worker 		0, (void *)&ssh_ops, 0 \
458*1c60b9acSAndroid Build Coastguard Worker 	}
459*1c60b9acSAndroid Build Coastguard Worker 
460*1c60b9acSAndroid Build Coastguard Worker #if !defined (LWS_PLUGIN_STATIC)
461*1c60b9acSAndroid Build Coastguard Worker 
462*1c60b9acSAndroid Build Coastguard Worker LWS_VISIBLE const struct lws_protocols lws_sshd_demo_protocols[] = {
463*1c60b9acSAndroid Build Coastguard Worker 		LWS_PLUGIN_PROTOCOL_LWS_SSHD_DEMO
464*1c60b9acSAndroid Build Coastguard Worker };
465*1c60b9acSAndroid Build Coastguard Worker 
466*1c60b9acSAndroid Build Coastguard Worker LWS_VISIBLE const lws_plugin_protocol_t lws_sshd_demo = {
467*1c60b9acSAndroid Build Coastguard Worker 	.hdr = {
468*1c60b9acSAndroid Build Coastguard Worker 		"lws sshd demo",
469*1c60b9acSAndroid Build Coastguard Worker 		"lws_protocol_plugin",
470*1c60b9acSAndroid Build Coastguard Worker 		LWS_BUILD_HASH,
471*1c60b9acSAndroid Build Coastguard Worker 		LWS_PLUGIN_API_MAGIC
472*1c60b9acSAndroid Build Coastguard Worker 	},
473*1c60b9acSAndroid Build Coastguard Worker 
474*1c60b9acSAndroid Build Coastguard Worker 	.protocols = lws_sshd_demo_protocols,
475*1c60b9acSAndroid Build Coastguard Worker 	.count_protocols = LWS_ARRAY_SIZE(lws_sshd_demo_protocols),
476*1c60b9acSAndroid Build Coastguard Worker 	.extensions = NULL,
477*1c60b9acSAndroid Build Coastguard Worker 	.count_extensions = 0,
478*1c60b9acSAndroid Build Coastguard Worker };
479*1c60b9acSAndroid Build Coastguard Worker 
480*1c60b9acSAndroid Build Coastguard Worker #endif
481