Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfixes, and minor changes to the client #184

Merged
merged 8 commits into from
Nov 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
- 5432:5432
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Run Go tests
run: |
cd server/service
Expand All @@ -44,7 +44,7 @@ jobs:
- name: Docker save
run: docker save nivlheim | gzip > nivlheim-image.tar.gz
- name: Upload artifact
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: nivlheim-image.tar.gz
path: nivlheim-image.tar.gz
Expand All @@ -54,7 +54,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Docker build
run: docker build --file ci/docker/Dockerfile --tag nivlheim-www:latest .
- name: Docker save
Expand All @@ -63,7 +63,7 @@ jobs:
docker inspect $IMAGE
docker save nivlheim-www | gzip > nivlheim-www.tar.gz
- name: Upload artifact
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: nivlheim-www.tar.gz
path: nivlheim-www.tar.gz
Expand All @@ -73,7 +73,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Docker build
run: |
cp client/client.yaml tmp_client.yaml
Expand All @@ -82,7 +82,7 @@ jobs:
docker save nivlheimclient | gzip > nivlheim-client.tar.gz
rm tmp_client.yaml
- name: Upload artifact
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: nivlheim-client.tar.gz
path: nivlheim-client.tar.gz
Expand All @@ -102,9 +102,9 @@ jobs:
- powershell.sh
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Download artifacts
uses: actions/download-artifact@v2
uses: actions/download-artifact@v3
# the name input parameter is not provided, so all artifacts will be downloaded
- name: Load images
run: |
Expand Down Expand Up @@ -146,7 +146,7 @@ jobs:
contents: read
steps:
- name: Download artifact
uses: actions/download-artifact@v2
uses: actions/download-artifact@v3
with:
name: nivlheim-image.tar.gz
- name: Load image
Expand Down Expand Up @@ -176,7 +176,7 @@ jobs:
contents: read
steps:
- name: Download artifact
uses: actions/download-artifact@v2
uses: actions/download-artifact@v3
with:
name: nivlheim-www.tar.gz
- name: Load image
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.7.15
2.7.16
23 changes: 15 additions & 8 deletions client/nivlheim_client
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ my $NAME = 'nivlheim_client';
my $AUTHOR = 'Øyvind Hagberg';
my $CONTACT = '[email protected]';
my $RIGHTS = 'USIT/IT-DRIFT/GD/GID, University of Oslo, Norway';
my $VERSION = '2.7.15';
my $VERSION = '2.7.16';

# Usage text
my $USAGE = <<"END_USAGE";
Expand All @@ -79,6 +79,7 @@ my $HELP = <<'END_HELP';

OPTIONS:
-c, --config Specify configuration file
-s, --server Specify server hostname
--ssl-ca SSL CA file
--ssl-cert SSL CERT file
--ssl-key SSL key file
Expand All @@ -101,6 +102,7 @@ END_LICENSE
# Get options
my %opt;
GetOptions('c|config=s' => \$opt{config},
's|server=s' => \$opt{server},
'ssl-ca=s' => \$opt{ca_file},
'ssl-cert=s' => \$opt{cert_file},
'ssl-key=s' => \$opt{key_file},
Expand Down Expand Up @@ -210,14 +212,18 @@ foreach (keys %defaultopt) {
}
}

# Verify that we have a server url. It must have trailing slash.
if (!defined($config{'settings'}) || !defined($config{'settings'}{'server'})) {
# Verify that a "server" argument or config option was given
if (defined($opt{server})) {
$server_url = 'https://' . $opt{server} . '/cgi-bin/';
} elsif (defined($config{'settings'}{'server'})) {
$server_url = 'https://' . $config{'settings'}{'server'} . '/cgi-bin/';
} else {
print "The config file $configfile must have a section [settings] "
."that contains a \"server\" option "
."with the hostname or ip address of the server.\n";
print "Alternatively, you may pass it as an argument with -s / --server.\n";
exit 1;
}
$server_url = 'https://' . $config{'settings'}{'server'} . '/cgi-bin/';

# Show options in effect
if ($opt{debug}) {
Expand Down Expand Up @@ -393,7 +399,7 @@ elsif ($have_cert && !$cert_works) {
}
}

createPKCS8() unless (-f "/var/nivlheim/pkcs8.key");
createPKCS8() unless (-f dirname($opt{key_file})."/pkcs8.key");

# Determine which files to send
my @filelist = @{$config{'files'}} if defined($config{'files'});
Expand Down Expand Up @@ -514,7 +520,7 @@ print "Signed the archive file\n" if ($opt{debug});

# nonce
my $nonce = 0;
my $noncefile = "/var/nivlheim/nonce";
my $noncefile = dirname($opt{key_file})."/nonce";
if (-r $noncefile) {
open(my $F, $noncefile);
$nonce = <$F>;
Expand Down Expand Up @@ -913,8 +919,9 @@ sub parse_certificate_response($) {
}

sub createPKCS8() {
system("openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in /var/nivlheim/my.key -out /var/nivlheim/pkcs8.key");
chmod(0600, "/var/nivlheim/pkcs8.key");
my $dir = dirname($opt{key_file});
system("openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in ".$opt{key_file}." -out $dir/pkcs8.key");
chmod(0600, "$dir/pkcs8.key");
}

sub sign_with_cfengine_key() {
Expand Down
2 changes: 1 addition & 1 deletion client/windows/nivlheim_client.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ param(
[bool]$nosleep = $false
)

Set-Variable version -option Constant -value "2.7.15"
Set-Variable version -option Constant -value "2.7.16"
Set-Variable useragent -option Constant -value "NivlheimPowershellClient/$version"
Set-PSDebug -strict
Set-StrictMode -version "Latest" # http://technet.microsoft.com/en-us/library/hh849692.aspx
Expand Down
7 changes: 4 additions & 3 deletions debian/changelog
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
nivlheim (2.7.15-1) buster; urgency=low
nivlheim (2.7.16-1) buster; urgency=low

* Upstream changes, no changes in the client
* Added a --server option to the client
* Removed hard-coded references to /var/nivlheim

-- Øyvind Hagberg <[email protected]> Mon, 10 Oct 2022 13:55:00 +0200
-- Øyvind Hagberg <[email protected]> Wed, 26 Oct 2022 17:03:00 +0200

nivlheim (2.7.13-1) buster; urgency=low

Expand Down
3 changes: 1 addition & 2 deletions server/cgi/Database.pm
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ sub connect_to_db() {
$dbparams{'PGPORT'} = 5432; # default

# Try to read connection parameters from /etc/nivlheim/server.conf
open(my $F, "/etc/nivlheim/server.conf");
if ($F) {
if (open(my $F, "/etc/nivlheim/server.conf")) {
while (<$F>) {
if (/^([pP[gG][a-zA-Z]+)=(.*)/) {
$dbparams{uc $1} = $2;
Expand Down
9 changes: 5 additions & 4 deletions server/service/host_owner.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ func (job determineHostOwnershipJob) Run(db *sql.DB) {
}
pluginAccess.AllowOnlyLocalhost()
tempKey := GenerateTemporaryAPIKey(pluginAccess)
defer func() {
// When the function exits, even if panic, make the key expire right away
pluginAccess.expires = time.Now()
}()
// Loop through those hosts and call the plugin to determine ownership for each of them
for _, host := range list {
if devmode {
Expand All @@ -83,7 +87,7 @@ func (job determineHostOwnershipJob) Run(db *sql.DB) {
// Check the http status
if resp.StatusCode > 299 {
// oops, the statuscode indicates an error
continue
log.Panicf("http status %d from host owner plugin", resp.StatusCode)
}
// Parse the response from the plugin. Should be one line of text
// that only contains the owner group name, nothing else.
Expand All @@ -93,7 +97,4 @@ func (job determineHostOwnershipJob) Run(db *sql.DB) {
"WHERE certfp=$2", ownerGroup, host.certfp)
}
}
// All done. Now make the key expire right away
pluginAccess.expires = time.Now()

}
6 changes: 3 additions & 3 deletions server/service/parseFiles.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ func parseFile(database *sql.DB, fileID int64) {
}

if strings.EqualFold(filename.String, "(Get-WmiObject Win32_OperatingSystem).Caption") {
reWinX := regexp.MustCompile(`Microsoft Windows (\d+) (.*)`)
reWinX := regexp.MustCompile(`Microsoft Windows (\d+) (\w*)`)
reWinServer := regexp.MustCompile(`Microsoft®? Windows Server®? (\d+)( R2)?`)
if m := reWinX.FindStringSubmatch(content.String); m != nil {
_, err = tx.Exec("UPDATE hostinfo SET os=$1, os_edition=$2, os_family='Windows' "+
Expand Down Expand Up @@ -301,7 +301,7 @@ func parseFile(database *sql.DB, fileID int64) {
serial.String = m[1]
serial.Valid = len(serial.String) > 0
}
_, err = tx.Exec("UPDATE hostinfo SET manufacturer=$1,product=$2,serialno=$3"+
_, err = tx.Exec("UPDATE hostinfo SET manufacturer=$1,product=$2,serialno=$3 "+
"WHERE certfp=$4", manufacturer, product, serial, certfp.String)
return
}
Expand All @@ -319,7 +319,7 @@ func parseFile(database *sql.DB, fileID int64) {
serial.String = m[1]
serial.Valid = len(serial.String) > 0
}
_, err = tx.Exec("UPDATE hostinfo SET manufacturer='Apple',product=$1,serialno=$2"+
_, err = tx.Exec("UPDATE hostinfo SET manufacturer='Apple',product=$1,serialno=$2 "+
"WHERE certfp=$3", product, serial, certfp.String)
return
}
Expand Down
15 changes: 12 additions & 3 deletions server/service/parseFiles_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ func TestParseFilesWindows(t *testing.T) {
"VersionString": "Microsoft Windows NT 10.0.17763.0"
}`,
},
{
filename: "(Get-WmiObject Win32_OperatingSystem).Caption",
content: "Microsoft Windows 10 Enterprise\r\n",
},
}
for _, f := range testfiles {
_, err := db.Exec("INSERT INTO files(certfp,filename,content,received) "+
Expand All @@ -146,10 +150,10 @@ func TestParseFilesWindows(t *testing.T) {
job.Run(db)

// verify the results
var kernel, manufacturer, product, serial sql.NullString
err := db.QueryRow("SELECT kernel,manufacturer,product,serialno "+
var kernel, manufacturer, product, serial, edition sql.NullString
err := db.QueryRow("SELECT kernel,manufacturer,product,serialno,os_edition "+
"FROM hostinfo WHERE certfp='1234'").
Scan(&kernel, &manufacturer, &product, &serial)
Scan(&kernel, &manufacturer, &product, &serial, &edition)
if err == sql.ErrNoRows {
t.Fatal("No hostinfo row found")
}
Expand All @@ -176,6 +180,11 @@ func TestParseFilesWindows(t *testing.T) {
if kernel.String != expectedKernel {
t.Errorf("Kernel = %s, expected %s", kernel.String, expectedKernel)
}

expectedEdition := "Enterprise"
if edition.String != expectedEdition {
t.Errorf("OS Edition = %s, expected %s", edition.String, expectedEdition)
}
}

func TestParseFilesMacOS(t *testing.T) {
Expand Down
17 changes: 17 additions & 0 deletions tests/test_cert_handling.sh
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,23 @@ if ! grep -qi "revoked" $tempdir/renewresult; then
exit 1
fi

# Run with other paths for cert/key, verify that cert, key, pkcs8 and nonce files were created there.
echo "Running the client with another path for cert and key, empty config, and server given by argument"
mkdir -p $tempdir/foo; rm -f $tempdir/foo/*
touch $tempdir/foo/emptyfile
if ! docker run --rm --network host --mount type=bind,source=$tempdir/foo,target=/foo nivlheimclient \
--ssl-cert /foo/a.crt --ssl-key /foo/a.key -c /foo/emptyfile --server localhost --debug >$tempdir/output2 2>&1; then
echo "The client failed to post data successfully when run with cert/key arguments:"
echo "--------------------------------------------"
cat $tempdir/output2
exit 1
fi
if [ ! -f $tempdir/foo/a.crt ] || [ ! -f $tempdir/foo/a.key ] || [ ! -f $tempdir/foo/pkcs8.key ] || [ ! -f $tempdir/foo/nonce ]; then
echo "Some output files are missing. These are present:"
ls $tempdir/foo
exit 1;
fi

# Check logs for errors
if docker exec -t docker_nivlheimweb_1 grep -A1 "ERROR" /var/log/nivlheim/system.log; then
exit 1
Expand Down