security/acme-client: use common function to run shell commands

This commit is contained in:
Frank Wall
2024-01-06 16:38:05 +01:00
parent ab8853c434
commit f7837735ed
5 changed files with 40 additions and 140 deletions
@@ -1,7 +1,7 @@
<?php
/*
* Copyright (C) 2020-2021 Frank Wall
* Copyright (C) 2020-2024 Frank Wall
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,6 +29,7 @@
namespace OPNsense\AcmeClient;
use OPNsense\Core\Config;
use OPNsense\AcmeClient\LeUtils;
/**
* Manage ACME CA accounts with acme.sh
@@ -104,40 +105,23 @@ class LeAccount extends LeCommon
return true;
} else {
LeUtils::log_debug('generating a new account key for ' . (string)$this->config->name, $this->debug);
// Preparation to run acme client
$proc_env = $this->acme_env; // env variables for proc_open()
$proc_env['PATH'] = $this::ACME_ENV_PATH;
$proc_desc = array( // descriptor array for proc_open()
0 => array("pipe", "r"), // stdin
1 => array("pipe", "w"), // stdout
2 => array("pipe", "w") // stderr
);
$proc_pipes = array();
// Run acme client to generate a account key
// Preparation to run acme client
$proc_env = $this->acme_env; // add env variables
$proc_env['PATH'] = $this::ACME_ENV_PATH;
// Prepare acme.sh command to generate a account key
$acmecmd = '/usr/local/sbin/acme.sh '
. '--createAccountKey '
. implode(' ', $this->acme_args) . ' '
. LeUtils::execSafe('--accountkeylength %s', self::ACME_ACCOUNT_KEY_LENGTH) . ' '
. LeUtils::execSafe('--accountconf %s', $account_conf_file);
LeUtils::log_debug('running acme.sh command: ' . (string)$acmecmd, $this->debug);
$proc = proc_open($acmecmd, $proc_desc, $proc_pipes, null, $proc_env);
// Make sure the resource could be setup properly
if (is_resource($proc)) {
// Close all pipes
fclose($proc_pipes[0]);
fclose($proc_pipes[1]);
fclose($proc_pipes[2]);
// Get exit code
$result = proc_close($proc);
} else {
LeUtils::log_error('unable to start acme client process');
$this->setStatus(500);
return false;
}
// Run acme.sh command
$result = LeUtils::run_shell_command($acmecmd, $proc_env);
// Check exit code
// Check acme.sh result
if ($result) {
LeUtils::log_error('failed to create a new account key for ' . (string)$this->config->name);
$this->setStatus(300);
@@ -220,38 +204,20 @@ class LeAccount extends LeCommon
}
// Preparation to run acme client
$proc_env = $this->acme_env; // env variables for proc_open()
$proc_env = $this->acme_env; // add env variables
$proc_env['PATH'] = $this::ACME_ENV_PATH;
$proc_desc = array( // descriptor array for proc_open()
0 => array("pipe", "r"), // stdin
1 => array("pipe", "w"), // stdout
2 => array("pipe", "w") // stderr
);
$proc_pipes = array();
// Run acme client
// Prepare acme.sh command to register an account
$acmecmd = '/usr/local/sbin/acme.sh '
. '--registeraccount '
. implode(' ', $this->acme_args) . ' '
. LeUtils::execSafe('--accountconf %s', $this->account_conf_file);
LeUtils::log_debug('running acme.sh command: ' . (string)$acmecmd, $this->debug);
$proc = proc_open($acmecmd, $proc_desc, $proc_pipes, null, $proc_env);
// Make sure the resource could be setup properly
if (is_resource($proc)) {
// Close all pipes
fclose($proc_pipes[0]);
fclose($proc_pipes[1]);
fclose($proc_pipes[2]);
// Get exit code
$result = proc_close($proc);
} else {
LeUtils::log_error('unable to start acme client process');
$this->setStatus(500);
return false;
}
// Run acme.sh command
$result = LeUtils::run_shell_command($acmecmd, $proc_env);
// Check validation result
// Check acme.sh result
if ($result) {
LeUtils::log_error('account registration failed for ' . $this->config->name);
$this->setStatus(400);
@@ -1,7 +1,7 @@
<?php
/*
* Copyright (C) 2020-2021 Frank Wall
* Copyright (C) 2020-2024 Frank Wall
* Copyright (C) 2018 Deciso B.V.
* Copyright (C) 2018 Franco Fichtner <franco@opnsense.org>
* All rights reserved.
@@ -120,16 +120,10 @@ abstract class Base extends \OPNsense\AcmeClient\LeCommon
LeUtils::log('running automation (acme.sh): ' . $this->config->name);
// Preparation to run acme client
$proc_env = $this->acme_env; // env variables for proc_open()
$proc_env = $this->acme_env; // add env variables
$proc_env['PATH'] = $this::ACME_ENV_PATH;
$proc_desc = array( // descriptor array for proc_open()
0 => array("pipe", "r"), // stdin
1 => array("pipe", "w"), // stdout
2 => array("pipe", "w") // stderr
);
$proc_pipes = array();
// Run acme client
// Prepare acme.sh command to run a deploy hook
$acmecmd = self::ACME_CMD
. ' '
. '--deploy '
@@ -137,18 +131,8 @@ abstract class Base extends \OPNsense\AcmeClient\LeCommon
LeUtils::log_debug('running acme.sh command: ' . (string)$acmecmd, $this->debug);
$proc = proc_open($acmecmd, $proc_desc, $proc_pipes, null, $proc_env);
// Make sure the resource could be setup properly
if (is_resource($proc)) {
// Close all pipes
fclose($proc_pipes[0]);
fclose($proc_pipes[1]);
fclose($proc_pipes[2]);
// Get exit code
$result = proc_close($proc);
} else {
LeUtils::log_error('unable to start acme client process');
return false;
}
// Run acme.sh command
$result = LeUtils::run_shell_command($acmecmd, $proc_env);
// acme.sh records the last used deploy hook and would automatically
// use it on the next run. This information must be removed from the
@@ -1,7 +1,7 @@
<?php
/*
* Copyright (C) 2020-2021 Frank Wall
* Copyright (C) 2020-2024 Frank Wall
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,7 @@ use OPNsense\Core\Config;
use OPNsense\AcmeClient\LeAccount;
use OPNsense\AcmeClient\LeAutomationFactory;
use OPNsense\AcmeClient\LeValidationFactory;
use OPNsense\AcmeClient\LeUtils;
/**
* Manage ACME certificates with acme.sh
@@ -474,37 +475,20 @@ class LeCertificate extends LeCommon
LeUtils::log('wiping certificate config: ' . (string)$this->config->name);
// Preparation to run acme client
$proc_env = $this->acme_env; // env variables for proc_open()
$proc_env = $this->acme_env; // add env variables
$proc_env['PATH'] = $this::ACME_ENV_PATH;
$proc_desc = array( // descriptor array for proc_open()
0 => array("pipe", "r"), // stdin
1 => array("pipe", "w"), // stdout
2 => array("pipe", "w") // stderr
);
$proc_pipes = array();
// Run acme client to remove certificate and related config
// Prepare acme.sh command to remove certificate and related config
$acmecmd = '/usr/local/sbin/acme.sh '
. '--remove '
. implode(' ', $this->acme_args) . ' '
. LeUtils::execSafe('--domain %s', (string)$this->config->name);
LeUtils::log_debug('running acme.sh command: ' . (string)$acmecmd, $this->debug);
$proc = proc_open($acmecmd, $proc_desc, $proc_pipes, null, $proc_env);
// Make sure the resource could be setup properly
if (is_resource($proc)) {
// Close all pipes
fclose($proc_pipes[0]);
fclose($proc_pipes[1]);
fclose($proc_pipes[2]);
// Get exit code
$result = proc_close($proc);
} else {
LeUtils::log_error('unable to start acme client process');
return false;
}
// Run acme.sh command
$result = LeUtils::run_shell_command($acmecmd, $proc_env);
// Check exit code
// Check acme.sh result
if ($result) {
LeUtils::log_error('error removing certificate ' . (string)$this->config->name);
return false;
@@ -565,36 +549,19 @@ class LeCertificate extends LeCommon
$account_conf_file = $account_conf_dir . '/account.conf';
// Preparation to run acme client
$proc_env = $this->acme_env; // env variables for proc_open()
$proc_env = $this->acme_env; // add env variables
$proc_env['PATH'] = $this::ACME_ENV_PATH;
$proc_desc = array( // descriptor array for proc_open()
0 => array("pipe", "r"), // stdin
1 => array("pipe", "w"), // stdout
2 => array("pipe", "w") // stderr
);
$proc_pipes = array();
// Run acme client to revoke certificate
// Prepare acme.sh command to revoke certificate
$acmecmd = '/usr/local/sbin/acme.sh '
. '--revoke '
. implode(' ', $this->acme_args) . ' '
. LeUtils::execSafe('--domain %s', (string)$this->config->name) . ' '
. LeUtils::execSafe('--accountconf %s', $account_conf_file);
LeUtils::log_debug('running acme.sh command: ' . (string)$acmecmd, $this->debug);
$proc = proc_open($acmecmd, $proc_desc, $proc_pipes, null, $proc_env);
// Make sure the resource could be setup properly
if (is_resource($proc)) {
// Close all pipes
fclose($proc_pipes[0]);
fclose($proc_pipes[1]);
fclose($proc_pipes[2]);
// Get exit code
$result = proc_close($proc);
} else {
LeUtils::log_error('unable to start acme client process');
return false;
}
// Run acme.sh command
$result = LeUtils::run_shell_command($acmecmd, $proc_env);
// Check exit code
if ($result) {
@@ -1,7 +1,7 @@
<?php
/*
* Copyright (C) 2017-2020 Frank Wall
* Copyright (C) 2017-2024 Frank Wall
* Copyright (C) 2015 Deciso B.V.
* Copyright (C) 2010 Jim Pingle <jimp@pfsense.org>
* Copyright (C) 2008 Shrew Soft Inc. <mgrooms@shrew.net>
@@ -200,11 +200,11 @@ class LeUtils
fclose($proc_pipes[2]);
// Get exit code
$result = proc_close($proc);
log_error(sprintf("AcmeClient: The shell command '%s' returned exit code '%d'", $proc_cmd, $result));
log_error(sprintf("AcmeClient: The shell command returned exit code '%d': '%s'", $result, $proc_cmd));
return($result);
} else {
log_error(sprintf("AcmeClient: Unable to prepare shell command '%s'", $proc_cmd));
return false;
return(-999);
}
}
}
@@ -1,7 +1,7 @@
<?php
/*
* Copyright (C) 2020-2021 Frank Wall
* Copyright (C) 2020-2024 Frank Wall
* Copyright (C) 2018 Deciso B.V.
* Copyright (C) 2018 Franco Fichtner <franco@opnsense.org>
* All rights reserved.
@@ -154,16 +154,10 @@ abstract class Base extends \OPNsense\AcmeClient\LeCommon
$account_conf_file = $account_conf_dir . '/account.conf';
// Preparation to run acme client
$proc_env = $this->acme_env; // env variables for proc_open()
$proc_env = $this->acme_env; // add env variables
$proc_env['PATH'] = $this::ACME_ENV_PATH;
$proc_desc = array( // descriptor array for proc_open()
0 => array("pipe", "r"), // stdin
1 => array("pipe", "w"), // stdout
2 => array("pipe", "w") // stderr
);
$proc_pipes = array();
// Run acme client
// Prepare acme.sh command
// NOTE: We "export" certificates to our own directory, so we don't have to deal
// with domain names in filesystem, but instead can use the ID of our certObj, which
// will never change.
@@ -173,25 +167,14 @@ abstract class Base extends \OPNsense\AcmeClient\LeCommon
. implode(' ', $this->acme_args) . ' '
. LeUtils::execSafe('--accountconf %s', $account_conf_file);
LeUtils::log_debug('running acme.sh command: ' . (string)$acmecmd, $this->debug);
$proc = proc_open($acmecmd, $proc_desc, $proc_pipes, null, $proc_env);
// Make sure the resource could be setup properly
if (is_resource($proc)) {
// Close all pipes
fclose($proc_pipes[0]);
fclose($proc_pipes[1]);
fclose($proc_pipes[2]);
// Get exit code
$result = proc_close($proc);
} else {
LeUtils::log_error('unable to start acme client process');
return false;
}
// Run acme.sh command
$result = LeUtils::run_shell_command($acmecmd, $proc_env);
// Run optional cleanup tasks.
$this->cleanup();
// Check validation result
// Check acme.sh result
if ($result) {
LeUtils::log_error('domain validation failed (' . $this->getMethod() . ')');
return false;