1 /*
2  * VDE Cryptcab
3  * Copyright © 2006-2008 Daniele Lacamera
4  * from an idea by Renzo Davoli
5  *
6  * Released under the terms of GNU GPL v.2
7  * (http://www.gnu.org/licenses/old-licenses/gpl-2.0.html)
8  * with the additional exemption that
9  * compiling, linking, and/or using OpenSSL is allowed.
10  *
11  */
12 
13 #include "cryptcab.h"
14 #define KEEPALIVE_INTERVAL 30
15 
16 static unsigned char keepalives = 0;
17 static char *remoteusr, *remotehost;
18 static unsigned short remoteport;
19 static char *plugname, *pre_shared;
20 static struct timeval last_out_time;
21 static enum e_enc_type enc_type = ENC_SSH;
22 static char *scp_extra_options = NULL;
23 
send_keepalive(struct peer * p)24 static void send_keepalive(struct peer *p){
25 	if (!keepalives)
26 		return;
27 	vc_printlog(4,"Sending keepalive");
28 	send_udp(NULL,0,p,CMD_KEEPALIVE);
29 	gettimeofday(&last_out_time, NULL);
30 }
31 
32 
33 /*
34  * Send a login packet. This is the first phase of 4WHS
35  */
36 static void
blowfish_login(struct peer * p)37 blowfish_login(struct peer *p)
38 {
39 	send_udp((unsigned char*)p->id,FILENAMESIZE,p,CMD_LOGIN);
40 }
41 
try_to_login(struct peer * p)42 static void try_to_login(struct peer *p)
43 {
44 	static struct timeval last_login_time;
45 	struct timeval now;
46 	gettimeofday(&now, 0);
47 	if (now.tv_sec < last_login_time.tv_sec  || now.tv_sec - last_login_time.tv_sec < 5) {
48 		vc_printlog(4,"Attempt to login to  %s (udp port %hu): please wait, login in progress...",remotehost,remoteport);
49 		return;
50 	}
51 
52 	vc_printlog(2,"Logging in to %s (udp port %hu)",remotehost,remoteport);
53 	blowfish_login(p);
54 	gettimeofday(&last_login_time, 0);
55 }
56 
57 
58 /*
59  * Receive a challenge. Try to send response encrypted with local blowfish key.
60  */
61 static void
rcv_challenge(struct datagram * pkt,struct peer * p)62 rcv_challenge(struct datagram *pkt, struct peer *p)
63 {
64 	send_udp(pkt->data+1,pkt->len-1,p,CMD_RESPONSE);
65 	p->state=ST_WAIT_AUTH;
66 }
67 
68 /*
69  * Generate a new blowfish key, store it in a local file and fill the fields
70  * of peer structure.
71  * Client only.
72  */
73 static struct peer
generate_key(struct peer * ret)74 *generate_key (struct peer *ret)
75 {
76 	int i, fd=-1, od=-1;
77 	unsigned char key[16];
78 	unsigned char iv[8];
79 	unsigned char c;
80 	char *path;
81 	char random[]="/dev/urandom";
82 	if (pre_shared){
83 		path=pre_shared;
84 		vc_printlog(2,"Reading pre-shared Blowfish key...");
85 	}else{
86 		path=random;
87 		vc_printlog(2,"Generating Blowfish key...");
88 	}
89 
90 	if ( ((fd = open (path, O_RDONLY)) == -1)||
91 			 ((read (fd, key, 16)) == -1) ||
92 			 ((read (fd, iv, 8)) == -1) )
93 	{
94 
95 		perror ("Error Creating key.\n");
96 		goto failure;
97 	}
98 
99 	memset(ret,0, sizeof(struct peer));
100 
101 	for(i=0; i<FILENAMESIZE-1;i++){
102 		if (read(fd,&c,1) < 0) {
103 			perror("could not read filename ");
104 			goto failure;
105 		}
106 		c=(c%25);
107 		//fprintf(stderr,"c=%u\n",c);
108 		ret->id[i]=(char)('a' + c);
109 	}
110 	ret->id[FILENAMESIZE-1]='\0';
111 
112 	close (fd);
113 
114 	if ((od = creat ("/tmp/.blowfish.key",0600)) == -1){
115 		perror ("blowfish.key creat error");
116 		goto failure;
117 	}
118 	memcpy(ret->key,key,16);
119 	memcpy(ret->iv,iv,8);
120 	if (write(od,key,16) < 0 || write(od,iv,8) < 0) {
121 		perror("Could not write blowfish key");
122 		goto failure;
123 	}
124 	close (od);
125 	vc_printlog(2,"Done.");
126 	return ret;
127 
128 failure:
129 	if (fd != -1)
130 		close(fd);
131 	if (od != -1)
132 		close(od);
133 	return NULL;
134 }
135 
136 
137 /*
138  * Call the generate_key() and then transmit the key to the server via
139  * OpenSSH secure copy.
140  */
generate_and_xmit(struct peer * ret)141 static struct peer *generate_and_xmit(struct peer *ret){
142 	char command[255];
143 	int res;
144 	struct hostent *target;
145 
146 	ret=generate_key(ret);
147 
148 	if(!ret){
149 		fprintf(stderr,"Couldn't create the secret key.\n");
150 		exit(255);
151 	}
152 
153 	target=gethostbyname(remotehost);
154 	if (target == NULL)
155 	{
156 		fprintf(stderr,"%s not found.\n", remotehost);
157 		exit(2);
158 	}
159 	ret->in_a.sin_family = AF_INET;
160 	ret->in_a.sin_port = htons(remoteport);
161 	ret->in_a.sin_addr.s_addr=((struct in_addr *)(target->h_addr))->s_addr;
162 	if(!pre_shared){
163 		vc_printlog(2,"Sending key over ssh channel:");
164 		if(remoteusr)
165 			sprintf(command,"scp %s /tmp/.blowfish.key %s@%s:/tmp/.%s.key 2>&1",
166 				scp_extra_options?scp_extra_options:"",
167 				remoteusr, remotehost, ret->id);
168 		else
169 			sprintf(command,"scp %s /tmp/.blowfish.key %s:/tmp/.%s.key 2>&1",
170 				scp_extra_options?scp_extra_options:"",
171 				remotehost, ret->id);
172 
173 		//fprintf(stderr,"Contacting host: %s ",remotehost);
174 		res=system(command);
175 
176 		if(res==0){
177 			vc_printlog(2,"Key successfully transferred using a secure channel.");
178 		}else{
179 			fprintf(stderr,"Couldn't transfer the secret key.\n");
180 			exit(253);
181 		}
182 	}
183 	vc_printlog(2,"Done.");
184 	return ret;
185 }
186 
recv_datagram(struct datagram * pkt,int nfd,struct peer * p1)187 static int recv_datagram(struct datagram *pkt, int nfd, struct peer *p1)
188 {
189 	int pollret;
190 	static struct pollfd pfd[2];
191 	socklen_t peerlen;
192 	int datafd;
193 	struct timeval now;
194 
195 	datafd = vde_datafd(p1->plug);
196 	while(datafd < 0) {
197 		vc_printlog(4,"waiting for vde_libs...");
198 		vde_plug(p1, plugname);
199 		sleep(1);
200 		datafd = vde_datafd(p1->plug);
201 	}
202 
203 	pfd[0].fd=nfd;
204 	pfd[0].events=POLLIN|POLLHUP;
205 	pfd[1].fd = datafd;
206 	pfd[1].events = POLLIN|POLLHUP;
207 
208 	 do{
209 		pollret = poll(pfd,2,1000);
210 		if(pollret<0){
211 		 	if(errno==EINTR)
212 		   		return 0;
213 		 	perror("poll");
214 		 	exit(1);
215 		}
216 
217 		gettimeofday(&now,NULL);
218 		now.tv_sec -= KEEPALIVE_INTERVAL;
219 		if (after(now,last_out_time) && p1->state == ST_AUTH){
220 			send_keepalive(p1);
221 		}
222    	} while (pollret==0);
223 
224 
225 	for(;;){
226 		if (pfd[0].revents&POLLIN) {
227 			struct sockaddr_in ipaddress;
228 			peerlen = sizeof(struct sockaddr_in);
229 			pkt->len = recvfrom(nfd, pkt->data, MAXPKT, 0,
230 				(struct sockaddr *) &ipaddress, &peerlen);
231 			if(ipaddress.sin_addr.s_addr == p1->in_a.sin_addr.s_addr){
232 				pkt->orig=p1;
233 				pkt->src = SRC_UDP;
234 				return 1;
235 			} else {
236 				vc_printlog(1,"Warning: received packet from unknown address %s, dropping",inet_ntoa(ipaddress.sin_addr));
237 				return 0;
238 			}
239 		}
240 
241 	 	if (pfd[1].revents&POLLHUP){
242 			vc_printlog(1,"VDE Error");
243 		}
244 		if (pfd[1].revents&POLLIN) {
245 			vc_printlog(4,"VDE Pkt");
246 			pkt->len = vde_recv(p1->plug, pkt->data, MAXPKT,0);
247 			if(pkt->len<1)
248 				return 0;
249 			pkt->src = SRC_VDE;
250 			pkt->orig = p1;
251 			return 1;
252 		}
253 	}
254 	return 0;
255 }
256 
cryptcab_client(char * _plugname,unsigned short udp_port,enum e_enc_type _enc_type,char * _pre_shared,char * _remoteusr,char * _remotehost,unsigned short _remoteport,unsigned char _keepalives,char * _scp_extra_options)257 void cryptcab_client(char *_plugname, unsigned short udp_port, enum e_enc_type _enc_type, char *_pre_shared, char *_remoteusr, char *_remotehost, unsigned short _remoteport, unsigned char _keepalives, char *_scp_extra_options)
258 {
259 	int wire, r;
260 	struct sockaddr_in myaddr;
261 	struct datagram pkt, pkt_dec;
262 	struct peer _peer;
263 	struct peer *p1 = &_peer;
264 
265 	plugname = _plugname;
266 	remoteusr = _remoteusr;
267 	remotehost = _remotehost;
268 	remoteport = _remoteport;
269 	pre_shared = _pre_shared;
270 	keepalives = _keepalives;
271 	enc_type = _enc_type;
272 	scp_extra_options = _scp_extra_options;
273 
274 	memset(&last_out_time,0, sizeof(struct timeval));
275 
276 	if(enc_type == ENC_PRESHARED && (!pre_shared || access(pre_shared,R_OK)!=0)){
277 		vc_printlog(0,"Error accessing pre-shared key %s: %s\n",pre_shared,strerror(errno));
278 		exit(1);
279 	}
280 
281 	if (enc_type == ENC_NOENC)
282 		disable_encryption();
283 
284 	memset ((char *)&myaddr, 0, sizeof(myaddr));
285 	myaddr.sin_family = AF_INET;
286 	myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
287 	myaddr.sin_port = htons(udp_port);
288 
289 	wire = socket(PF_INET,SOCK_DGRAM,0);
290 	if (bind(wire,(struct sockaddr *) &myaddr, sizeof(myaddr))<0)
291 		        {perror("bind socket"); exit(3);}
292 
293 	set_nfd(wire);
294 
295 	p1 = generate_and_xmit(p1);
296 	p1->state = ST_OPENING;
297 	p1->next = NULL;
298 	try_to_login(p1);
299 	usleep(100000);
300 
301 	for(;;){
302 		r = recv_datagram(&pkt, wire, p1);
303 		if (r == 0)
304 			continue;
305 
306 		if(pkt.src==SRC_VDE){
307 			if(p1->state==ST_AUTH){
308 				vc_printlog(4,"VDE pkt received (%d Bytes)",pkt.len);
309 				send_udp(pkt.data, pkt.len, p1, PKT_DATA);
310 				gettimeofday(&last_out_time,NULL);
311 			}else{
312 				try_to_login(p1);
313 			}
314 			continue;
315 		}
316 		else if(pkt.src==SRC_UDP){
317 			switch(p1->state + pkt.data[0]) {
318 				case ST_OPENING + CMD_CHALLENGE:
319 					vc_printlog(2,"Received Challenge packet, replying:");
320 					rcv_challenge(&pkt, p1);
321 					break;
322 				case ST_WAIT_AUTH + CMD_AUTH_OK:
323 					p1->state = ST_AUTH;
324 					vc_printlog(2,"Successfully authenticated.");
325 					break;
326 				case ST_AUTH + PKT_DATA:
327 					vc_printlog(4,"Data pkt received (%d Bytes)",pkt.len);
328 					pkt_dec.len = data_decrypt(pkt.data+1, pkt_dec.data, pkt.len-1, p1);
329 
330 					vde_send(p1->plug,pkt_dec.data,pkt_dec.len,0);
331 					break;
332 				case ST_OPENING + CMD_DENY:
333 				case ST_WAIT_AUTH + CMD_DENY:
334 				case ST_AUTH + CMD_DENY:
335 					vc_printlog(2,"Received access denied from server, sending identification.");
336 					vde_close(p1->plug);
337 					p1 = (struct peer *)generate_and_xmit(p1);
338 					p1->state = ST_OPENING;
339 					try_to_login(p1);
340 					break;
341 				default:
342 					vc_printlog(4,"Unknown/undesired pkt received. (state: 0x%X code: 0x%X )", p1->state, (unsigned char)pkt.data[0]);
343 			}
344 
345 		}
346 
347 	}
348 	exit (0);
349 }
350 
351