1
0
mirror of https://github.com/solemnwarning/ipxwrapper synced 2024-12-30 16:45:37 +01:00

Support Windows 98 Resource Kit REG.EXE in test suite.

This commit is contained in:
Daniel Collins 2024-07-02 21:23:23 +01:00
parent 623d2c3df4
commit f20261dfa5
5 changed files with 369 additions and 11 deletions

View File

@ -51,7 +51,7 @@ TESTS := tests/addr.exe tests/addrcache.exe tests/ethernet.exe tools/fionread.ex
# Tools to compile before running the test suite.
TOOLS := tools/socket.exe tools/list-interfaces.exe tools/bind.exe tools/ipx-send.exe \
tools/ipx-recv.exe tools/spx-server.exe tools/spx-client.exe tools/ipx-isr.exe \
tools/dptool.exe
tools/dptool.exe tools/osversion.exe tools/reg-set-bin.exe
# DLLs to copy to the tools/ directory before running the test suite.
TOOL_DLLS := tools/ipxwrapper.dll tools/wsock32.dll tools/mswsock.dll tools/dpwsockx.dll

View File

@ -0,0 +1,103 @@
# IPXWrapper test suite
# Copyright (C) 2024 Daniel Collins <solemnwarning@solemnwarning.net>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 as published by
# the Free Software Foundation.
#
# This program 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
# this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
use strict;
use warnings;
package IPXWrapper::Tool::OSVersion;
use IPC::Open3;
use Test::Spec;
my %os_version_cache = ();
sub get
{
my ($class, $host) = @_;
if(defined $os_version_cache{$host})
{
return $os_version_cache{$host};
}
my @command = ("ssh", $host, "Z:\\tools\\osversion.exe");
note(join(" ", @command));
# No need for error checking here - open3 throws on failure.
my $pid = open3(my $in, my $out, undef, @command);
my $output = do {
local $/;
<$out>;
};
if($output =~ m/^(\d+).(\d+)\r?\n(\d+)\r?\n(\w+)\r?\n(.*)\r?\n$/)
{
my $self = bless({
major => $1,
minor => $2,
build => $3,
platform => $4,
extra => $5,
}, $class);
$os_version_cache{$host} = $self;
return $self;
}
else{
die("Didn't get expected output from osversion.exe:\n$output");
}
}
sub major
{
my ($self) = @_;
return $self->{major};
}
sub minor
{
my ($self) = @_;
return $self->{minor};
}
sub build
{
my ($self) = @_;
return $self->{build};
}
sub platform
{
my ($self) = @_;
return $self->{platform};
}
sub platform_is_win9x
{
my ($self) = @_;
return $self->{platform} eq "VER_PLATFORM_WIN32_WINDOWS";
}
sub platform_is_winnt
{
my ($self) = @_;
return $self->{platform} eq "VER_PLATFORM_WIN32_NT";
}
1;

View File

@ -1,5 +1,5 @@
# IPXWrapper test suite
# Copyright (C) 2014-2017 Daniel Collins <solemnwarning@solemnwarning.net>
# Copyright (C) 2014-2024 Daniel Collins <solemnwarning@solemnwarning.net>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 as published by
@ -55,6 +55,8 @@ use Net::Libdnet::Eth;
use NetPacket::IPX;
use NetPacket::IPXWrapper;
use IPXWrapper::Tool::OSVersion;
sub run_remote_cmd
{
my ($host_ip, $exe_name, @exe_args) = @_;
@ -78,7 +80,21 @@ sub reg_set_dword
{
my ($host_ip, $key, $value, $data) = @_;
run_remote_cmd($host_ip, "REG", "ADD", $key, "/v", $value, "/t", "REG_DWORD", "/d", $data, "/f");
if(IPXWrapper::Tool::OSVersion->get($host_ip)->platform_is_winnt())
{
run_remote_cmd($host_ip, "REG", "ADD", $key, "/v", $value, "/t", "REG_DWORD", "/d", $data, "/f");
}
else{
eval { run_remote_cmd($host_ip, "REG", "QUERY", "$key\\$value"); };
if($@)
{
run_remote_cmd($host_ip, "REG", "ADD", "$key\\$value=$data", "REG_DWORD");
}
else{
run_remote_cmd($host_ip, "REG", "UPDATE", "$key\\$value=$data");
}
}
}
sub reg_set_addr
@ -86,33 +102,71 @@ sub reg_set_addr
my ($host_ip, $key, $value, $data) = @_;
$data =~ s/://g;
run_remote_cmd($host_ip, "REG", "ADD", $key, "/v", $value, "/t", "REG_BINARY", "/d", $data, "/f");
if(IPXWrapper::Tool::OSVersion->get($host_ip)->platform_is_winnt())
{
run_remote_cmd($host_ip, "REG", "ADD", $key, "/v", $value, "/t", "REG_BINARY", "/d", $data, "/f");
}
else{
run_remote_cmd($host_ip, "Z:\\tools\\reg-set-bin.exe", $key, $value, $data);
}
}
sub reg_set_string
{
my ($host_ip, $key, $value, $data) = @_;
run_remote_cmd($host_ip, "REG", "ADD", $key, "/v", $value, "/t", "REG_SZ", "/d", $data, "/f");
if(IPXWrapper::Tool::OSVersion->get($host_ip)->platform_is_winnt())
{
run_remote_cmd($host_ip, "REG", "ADD", $key, "/v", $value, "/t", "REG_SZ", "/d", $data, "/f");
}
else{
eval { run_remote_cmd($host_ip, "REG", "QUERY", "$key\\$value"); };
if($@)
{
run_remote_cmd($host_ip, "REG", "ADD", "$key\\$value=$data", "REG_SZ");
}
else{
run_remote_cmd($host_ip, "REG", "UPDATE", "$key\\$value=$data");
}
}
}
sub reg_delete_key
{
my ($host_ip, $key) = @_;
# Attempting to delete a key which doesn't exist is considered to be an
# error, so we touch the key beforehand.
eval { run_remote_cmd($host_ip, "REG", "QUERY", $key); };
run_remote_cmd($host_ip, "REG", "ADD", $key, "/f");
run_remote_cmd($host_ip, "REG", "DELETE", $key, "/f");
unless($@)
{
if(IPXWrapper::Tool::OSVersion->get($host_ip)->platform_is_winnt())
{
run_remote_cmd($host_ip, "REG", "DELETE", $key, "/f");
}
else{
run_remote_cmd($host_ip, "REG", "DELETE", $key, "/FORCE");
}
}
}
sub reg_delete_value
{
my ($host_ip, $key, $value) = @_;
run_remote_cmd($host_ip, "REG", "ADD", $key, "/v", $value, "/t", "REG_SZ", "/f");
run_remote_cmd($host_ip, "REG", "DELETE", $key, "/v", $value, "/f");
eval { run_remote_cmd($host_ip, "REG", "QUERY", "$key\\$value"); };
unless($@)
{
if(IPXWrapper::Tool::OSVersion->get($host_ip)->platform_is_winnt())
{
run_remote_cmd($host_ip, "REG", "DELETE", $key, "/v", $value, "/f");
}
else{
run_remote_cmd($host_ip, "REG", "DELETE", "$key\\$value", "/FORCE");
}
}
}
sub send_ipx_over_udp

61
tools/osversion.c Normal file
View File

@ -0,0 +1,61 @@
/* IPXWrapper test tools
* Copyright (C) 2024 Daniel Collins <solemnwarning@solemnwarning.net>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program 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
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <windows.h>
#include <stdio.h>
int main(int argc, char **argv)
{
OSVERSIONINFO osver;
osver.dwOSVersionInfoSize = sizeof(osver);
if(!GetVersionEx(&osver))
{
fprintf(stderr, "GetVersionEx: %u\n", (unsigned)(GetLastError()));
return 1;
}
const char *platform;
switch(osver.dwPlatformId)
{
case VER_PLATFORM_WIN32s:
platform = "VER_PLATFORM_WIN32s";
break;
case VER_PLATFORM_WIN32_WINDOWS:
platform = "VER_PLATFORM_WIN32_WINDOWS";
break;
case VER_PLATFORM_WIN32_NT:
platform = "VER_PLATFORM_WIN32_NT";
break;
default:
platform = "VER_PLATFORM_UNKNOWN";
break;
}
printf("%u.%u\n%u\n%s\n%s\n",
(unsigned)(osver.dwMajorVersion),
(unsigned)(osver.dwMinorVersion),
(unsigned)(osver.dwBuildNumber),
platform,
osver.szCSDVersion);
return 0;
}

140
tools/reg-set-bin.c Normal file
View File

@ -0,0 +1,140 @@
/* IPXWrapper test tools
* Copyright (C) 2024 Daniel Collins <solemnwarning@solemnwarning.net>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program 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
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* "Why do you have a standalone program specifically for storing binary
* registry values rather than using REG.EXE like you do for everything else?"
*
* "I'm so glad you asked that, hypothetical voice in my head, BEHOLD."
*
* > REG ADD HKCU\Software\IPXWrapper\08:00:27:C3:6A:E6\net=00000001 REG_BINARY
* > Adding Binary Format Data is not Supported.
* > The operation completed successfully.
*/
#include <windows.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static unsigned char hex_nibble_to_bin(char hex)
{
if(hex >= '0' && hex <= '9')
{
return 0x0 + (hex - '0');
}
else if(hex >= 'A' && hex <= 'F')
{
return 0xA + (hex - 'A');
}
else if(hex >= 'a' && hex <= 'f')
{
return 0xA + (hex - 'a');
}
else{
abort();
}
}
int main(int argc, char **argv)
{
if(argc != 4)
{
fprintf(stderr, "Usage: %s <key path> <value name> <hex string>\n", argv[0]);
return 1;
}
const char *key_path = argv[1];
const char *value_name = argv[2];
const char *value_hex = argv[3];
HKEY root_key;
if(strncmp(key_path, "HKLM", 4) == 0 && (key_path[4] == '\\' || key_path[4] == '\0'))
{
root_key = HKEY_LOCAL_MACHINE;
key_path += 4;
}
else if(strncmp(key_path, "HKCU", 4) == 0 && (key_path[4] == '\\' || key_path[4] == '\0'))
{
root_key = HKEY_CURRENT_USER;
key_path += 4;
}
else{
fprintf(stderr, "Key path must begin with HKLM or HKCU\n");
return 1;
}
if(key_path[0] == '\\')
{
++key_path;
}
size_t hex_len = strlen(value_hex);
if((hex_len % 2) != 0)
{
fprintf(stderr, "Invalid byte string\n");
return 1;
}
unsigned char *data = malloc(hex_len / 2);
if(hex_len > 0 && data == NULL)
{
fprintf(stderr, "Error allocating memory\n");
return 1;
}
size_t data_len = hex_len / 2;
for(size_t i = 0; i < hex_len; i += 2)
{
char hex1 = value_hex[i];
char hex2 = value_hex[i + 1];
if(isxdigit(hex1) && isxdigit(hex2))
{
data[i / 2] = (hex_nibble_to_bin(hex1) << 4) | hex_nibble_to_bin(hex2);
}
else{
fprintf(stderr, "Invalid byte string\n");
return 1;
}
}
HKEY key;
DWORD error = RegCreateKeyEx(root_key, key_path, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &key, NULL);
if(error != ERROR_SUCCESS)
{
fprintf(stderr, "Error opening/creating registry key (error code %u)\n", (unsigned)(error));
return 1;
}
error = RegSetValueEx(key, value_name, 0, REG_BINARY, (BYTE*)(data), data_len);
RegCloseKey(key);
free(data);
if(error == ERROR_SUCCESS)
{
return 0;
}
else{
fprintf(stderr, "Error code %u when writing registry value\n", (unsigned)(error));
return 1;
}
}