/* Copyright 1999 Peter Schlaile.
* Copyright 1999-2002,2006,2007,2009 Alain Knaff.
* This file is part of mtools.
*
* Mtools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mtools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mtools. If not, see .
*
* Small install-test utility to check if a floppyd-server is running on the
* X-Server-Host.
*
* written by:
*
* Peter Schlaile
*
* udbz@rz.uni-karlsruhe.de
*
*/
#include "sysincludes.h"
#include "stream.h"
#include "mtools.h"
#include "floppyd_io.h"
#ifdef USE_FLOPPYD
#include
#include
#include
/* ######################################################################## */
static const char* AuthErrors[] = {
"Auth success!",
"Auth failed: Packet oversized!",
"Auth failed: X-Cookie doesn't match!",
"Auth failed: Wrong transmission protocol version!",
"Auth failed: Device locked!"
};
#include "byte_dword.h"
#include "read_dword.h"
static int write_dword(int handle, Dword parm)
{
Byte val[4];
dword2byte(parm, val);
if(write(handle, val, 4) < 4)
return -1;
return 0;
}
/* ######################################################################## */
static uint32_t authenticate_to_floppyd(char fullauth, int sock, char *display,
uint32_t protoversion)
{
uint32_t filelen=0;
Byte buf[16];
const char *command[] = { "xauth", "xauth", "extract", "-", 0, 0 };
char *xcookie = NULL;
Dword errcode;
uint32_t bytesRead;
uint32_t cap=0;
if (fullauth) {
command[4] = display;
filelen=(uint32_t)strlen(display);
filelen += 100;
xcookie = (char *) safe_malloc(filelen+4);
filelen = (uint32_t) safePopenOut(command, xcookie+4, filelen);
if(filelen < 1)
return AUTH_AUTHFAILED;
}
dword2byte(4,buf);
dword2byte(protoversion,buf+4);
if(write(sock, buf, 8) < 8)
return AUTH_IO_ERROR;
bytesRead = read_dword(sock);
if (bytesRead != 4 && bytesRead != 12) {
return AUTH_WRONGVERSION;
}
errcode = read_dword(sock);
if (errcode != AUTH_SUCCESS) {
return errcode;
}
protoversion = FLOPPYD_PROTOCOL_VERSION_OLD;
if(bytesRead >= 12) {
protoversion = read_dword(sock);
cap = read_dword(sock);
}
fprintf(stderr, "Protocol Version=%d\n", protoversion);
if(protoversion >= FLOPPYD_PROTOCOL_VERSION) {
fprintf(stderr, "Capabilities:%s%s\n",
(cap & FLOPPYD_CAP_EXPLICIT_OPEN) ? " ExplicitOpen" : "",
(cap & FLOPPYD_CAP_LARGE_SEEK) ? " LargeFiles" : "");
}
if (fullauth) {
dword2byte(filelen, (Byte *) xcookie);
if(write(sock, xcookie, filelen+4) < (ssize_t)(filelen+4))
return AUTH_IO_ERROR;
if (read_dword(sock) != 4) {
return AUTH_PACKETOVERSIZE;
}
errcode = read_dword(sock);
}
return errcode;
}
/* ######################################################################## */
static int get_host_and_port(const char* name, char** hostname, char **display,
uint16_t* port)
{
char* newname = strdup(name);
char* p;
char* p2;
p = newname;
while (*p != '/' && *p) p++;
p2 = p;
if (*p) p++;
*p2 = 0;
*port = atou16(p);
if (*port == 0) {
*port = FLOPPYD_DEFAULT_PORT;
}
*display = strdup(newname);
p = newname;
while (*p != ':' && *p) p++;
p2 = p;
if (*p) p++;
*p2 = 0;
*port += atoi(p); /* add display number to the port */
if (!*newname || strcmp(newname, "unix") == 0) {
free(newname);
newname = strdup("localhost");
}
*hostname = newname;
return 1;
}
/*
* * Return the IP address of the specified host.
* */
static in_addr_t getipaddress(char *ipaddr)
{
struct hostent *host;
in_addr_t ip;
if (((ip = inet_addr(ipaddr)) == INADDR_NONE) &&
(strcmp(ipaddr, "255.255.255.255") != 0)) {
if ((host = gethostbyname(ipaddr)) != NULL) {
memcpy(&ip, host->h_addr, sizeof(ip));
}
endhostent();
}
#ifdef DEBUG
fprintf(stderr, "IP lookup %s -> 0x%08lx\n", ipaddr, ip);
#endif
return (ip);
}
/*
* * Connect to the floppyd server.
* */
static int connect_to_server(in_addr_t ip, uint16_t port)
{
struct sockaddr_in addr;
int sock;
/*
* Allocate a socket.
*/
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
return (-1);
}
/*
* Set the address to connect to.
*/
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = ip;
/*
* Connect our socket to the above address.
*/
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
return (-1);
}
/*
* Set the keepalive socket option to on.
*/
{
int on = 1;
setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE,
(char *)&on, sizeof(on));
}
return (sock);
}
int main (int argc, char** argv)
{
char* hostname;
char* display;
char* name;
uint16_t port;
int sock;
uint32_t reply;
int rval;
uint32_t protoversion;
char fullauth = 0;
Byte opcode = OP_CLOSE;
if (argc < 2) {
puts("Usage: floppyd_installtest [-f] Connect-String\n"
"-f\tDo full X-Cookie-Authentication");
return -1;
}
name = argv[1];
if (strcmp(name, "-f") == 0) {
fullauth = 1;
name = argv[2];
}
rval = get_host_and_port(name, &hostname, &display, &port);
if (!rval) return -1;
sock = connect_to_server(getipaddress(hostname), port);
if (sock == -1) {
fprintf(stderr,
"Can't connect to floppyd server on %s, port %i!\n",
hostname, port);
return -1;
}
protoversion = FLOPPYD_PROTOCOL_VERSION;
while(1) {
reply = authenticate_to_floppyd(fullauth, sock, display,
protoversion);
if(protoversion == FLOPPYD_PROTOCOL_VERSION_OLD)
break;
if(reply == AUTH_WRONGVERSION) {
/* fall back on old version */
protoversion = FLOPPYD_PROTOCOL_VERSION_OLD;
continue;
}
break;
}
if (reply != 0) {
fprintf(stderr,
"Connection to floppyd failed:\n"
"%s\n", AuthErrors[reply]);
return -1;
}
free(hostname);
free(display);
if(write_dword(sock, 1) < 0) {
fprintf(stderr,
"Short write to floppyd:\n"
"%s\n", strerror(errno));
}
if(write(sock, &opcode, 1) < 0) {
fprintf(stderr,
"Short write to floppyd:\n"
"%s\n", strerror(errno));
}
close(sock);
return 0;
}
#endif