1/*  Copyright 1999 Peter Schlaile.
2 *  Copyright 1999-2002,2006,2007,2009 Alain Knaff.
3 *  This file is part of mtools.
4 *
5 *  Mtools is free software: you can redistribute it and/or modify
6 *  it under the terms of the GNU General Public License as published by
7 *  the Free Software Foundation, either version 3 of the License, or
8 *  (at your option) any later version.
9 *
10 *  Mtools is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 *  GNU General Public License for more details.
14 *
15 *  You should have received a copy of the GNU General Public License
16 *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Small install-test utility to check if a floppyd-server is running on the
19 * X-Server-Host.
20 *
21 * written by:
22 *
23 * Peter Schlaile
24 *
25 * udbz@rz.uni-karlsruhe.de
26 *
27 */
28
29#include "sysincludes.h"
30#include "stream.h"
31#include "mtools.h"
32#include "msdos.h"
33#include "scsi.h"
34#include "partition.h"
35#include "floppyd_io.h"
36
37#ifdef USE_FLOPPYD
38#include <sys/socket.h>
39#include <arpa/inet.h>
40#include <netdb.h>
41
42/* ######################################################################## */
43
44typedef unsigned char Byte;
45typedef unsigned long Dword;
46
47const char* AuthErrors[] = {
48	"Auth success!",
49	"Auth failed: Packet oversized!",
50	"Auth failed: X-Cookie doesn't match!",
51	"Auth failed: Wrong transmission protocol version!",
52	"Auth failed: Device locked!"
53};
54
55#include "byte_dword.h"
56#include "read_dword.h"
57
58static void write_dword(int handle, Dword parm)
59{
60	Byte val[4];
61
62	dword2byte(parm, val);
63
64	write(handle, val, 4);
65}
66
67
68/* ######################################################################## */
69
70static int authenticate_to_floppyd(char fullauth, int sock, char *display,
71				   int protoversion)
72{
73	off_t filelen=0;
74	Byte buf[16];
75	const char *command[] = { "xauth", "xauth", "extract", "-", 0, 0 };
76	char *xcookie = NULL;
77	Dword errcode;
78	int bytesRead;
79
80	if (fullauth) {
81		command[4] = display;
82
83		filelen=strlen(display);
84		filelen += 100;
85
86		xcookie = (char *) safe_malloc(filelen+4);
87		filelen = safePopenOut(command, xcookie+4, filelen);
88		if(filelen < 1)
89		    return AUTH_AUTHFAILED;
90	}
91	dword2byte(4,buf);
92	dword2byte(protoversion,buf+4);
93	write(sock, buf, 8);
94
95	bytesRead = read_dword(sock);
96
97	if (bytesRead != 4 && bytesRead != 12) {
98		return AUTH_WRONGVERSION;
99	}
100
101
102	errcode = read_dword(sock);
103
104	if (errcode != AUTH_SUCCESS) {
105		return errcode;
106	}
107
108
109	if(bytesRead == 8) {
110	    protoversion = read_dword(sock);
111	    read_dword(sock);
112	}
113
114	fprintf(stderr, "Protocol Version=%d\n", protoversion);
115
116	if (fullauth) {
117		dword2byte(filelen, (Byte *) xcookie);
118		write(sock, xcookie, filelen+4);
119
120		if (read_dword(sock) != 4) {
121			return AUTH_PACKETOVERSIZE;
122		}
123
124		errcode = read_dword(sock);
125	}
126
127	return errcode;
128
129}
130
131
132/* ######################################################################## */
133
134static int get_host_and_port(const char* name, char** hostname, char **display,
135			     short* port)
136{
137	char* newname = strdup(name);
138	char* p;
139	char* p2;
140
141	p = newname;
142	while (*p != '/' && *p) p++;
143	p2 = p;
144	if (*p) p++;
145	*p2 = 0;
146
147	*port = atoi(p);
148	if (*port == 0) {
149		*port = FLOPPYD_DEFAULT_PORT;
150	}
151
152	*display = strdup(newname);
153
154	p = newname;
155	while (*p != ':' && *p) p++;
156	p2 = p;
157	if (*p) p++;
158	*p2 = 0;
159
160	*port += atoi(p);  /* add display number to the port */
161
162	if (!*newname || strcmp(newname, "unix") == 0) {
163		free(newname);
164		newname = strdup("localhost");
165	}
166
167	*hostname = newname;
168	return 1;
169}
170
171/*
172 *  * Return the IP address of the specified host.
173 *  */
174static IPaddr_t getipaddress(char *ipaddr)
175{
176
177	struct hostent  *host;
178	IPaddr_t        ip;
179
180	if (((ip = inet_addr(ipaddr)) == INADDR_NONE) &&
181	    (strcmp(ipaddr, "255.255.255.255") != 0)) {
182
183		if ((host = gethostbyname(ipaddr)) != NULL) {
184			memcpy(&ip, host->h_addr, sizeof(ip));
185		}
186
187		endhostent();
188	}
189
190#ifdef DEBUG
191	fprintf(stderr, "IP lookup %s -> 0x%08lx\n", ipaddr, ip);
192#endif
193
194	return (ip);
195}
196
197/*
198 *  * Connect to the floppyd server.
199 *  */
200static int connect_to_server(IPaddr_t ip, short port)
201{
202
203	struct sockaddr_in      addr;
204	int                     sock;
205
206	/*
207	 * Allocate a socket.
208	 */
209	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
210		return (-1);
211	}
212
213	/*
214	 * Set the address to connect to.
215	 */
216
217	addr.sin_family = AF_INET;
218	addr.sin_port = htons(port);
219	addr.sin_addr.s_addr = ip;
220
221        /*
222	 * Connect our socket to the above address.
223	 */
224	if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
225		return (-1);
226	}
227
228        /*
229	 * Set the keepalive socket option to on.
230	 */
231	{
232		int             on = 1;
233		setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE,
234			   (char *)&on, sizeof(on));
235
236	}
237
238	return (sock);
239}
240
241int main (int argc, char** argv)
242{
243	char* hostname;
244	char* display;
245	char* name;
246	short port;
247	int sock;
248	int reply;
249	int rval;
250	int protoversion;
251	char fullauth = 0;
252	Byte opcode = OP_CLOSE;
253
254        if (argc < 2) {
255	       puts("Usage: floppyd_installtest [-f] Connect-String\n"
256		    "-f\tDo full X-Cookie-Authentication");
257	       return -1;
258	}
259
260	name = argv[1];
261	if (strcmp(name, "-f") == 0) {
262		fullauth = 1;
263		name = argv[2];
264	}
265
266	rval = get_host_and_port(name, &hostname, &display, &port);
267
268	if (!rval) return -1;
269
270	sock = connect_to_server(getipaddress(hostname), port);
271
272	if (sock == -1) {
273		fprintf(stderr,
274			"Can't connect to floppyd server on %s, port %i!\n",
275			hostname, port);
276		return -1;
277	}
278
279	protoversion = FLOPPYD_PROTOCOL_VERSION;
280	while(1) {
281	    reply = authenticate_to_floppyd(fullauth, sock, display,
282					    protoversion);
283	    if(protoversion == FLOPPYD_PROTOCOL_VERSION_OLD)
284		break;
285	    if(reply == AUTH_WRONGVERSION) {
286		/* fall back on old version */
287		protoversion = FLOPPYD_PROTOCOL_VERSION_OLD;
288		continue;
289	    }
290	    break;
291	}
292
293	if (reply != 0) {
294		fprintf(stderr,
295			"Connection to floppyd failed:\n"
296			"%s\n", AuthErrors[reply]);
297		return -1;
298	}
299
300	free(hostname);
301	free(display);
302
303	write_dword(sock, 1);
304	write(sock, &opcode, 1);
305
306	close(sock);
307
308	return 0;
309}
310#endif
311