util/prosodyctl/cert.lua
author Kim Alvefur <zash@zash.se>
Wed, 27 Mar 2024 19:33:11 +0100
changeset 13471 c2a476f4712a
parent 12979 d10957394a3c
permissions -rw-r--r--
util.startup: Fix exiting on pidfile trouble prosody.shutdown() relies on prosody.main_thread, which has not been set yet at this point. Doing a clean shutdown might actually be harmful in case it tears down things set up by the conflicting Prosody, such as the very pidfile we were looking at. Thanks again SigmaTel71 for noticing
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
10875
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     1
local lfs = require "lfs";
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     2
12979
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12790
diff changeset
     3
local pctl = require "prosody.util.prosodyctl";
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12790
diff changeset
     4
local hi = require "prosody.util.human.io";
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12790
diff changeset
     5
local configmanager = require "prosody.core.configmanager";
10875
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     6
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     7
local openssl;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     8
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     9
local cert_commands = {};
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    10
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    11
-- If a file already exists, ask if the user wants to use it or replace it
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    12
-- Backups the old file if replaced
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    13
local function use_existing(filename)
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    14
	local attrs = lfs.attributes(filename);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    15
	if attrs then
11207
d10f59ac7f74 util.prosodyctl.cert: Fix for prompt functions having moved to util.human.io
Kim Alvefur <zash@zash.se>
parents: 10875
diff changeset
    16
		if hi.show_yesno(filename .. " exists, do you want to replace it? [y/n]") then
10875
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    17
			local backup = filename..".bkp~"..os.date("%FT%T", attrs.change);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    18
			os.rename(filename, backup);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    19
			pctl.show_message("%s backed up to %s", filename, backup);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    20
		else
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    21
			-- Use the existing file
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    22
			return true;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    23
		end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    24
	end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    25
end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    26
12979
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12790
diff changeset
    27
local have_pposix, pposix = pcall(require, "prosody.util.pposix");
10875
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    28
local cert_basedir = prosody.paths.data == "." and "./certs" or prosody.paths.data;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    29
if have_pposix and pposix.getuid() == 0 then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    30
	-- FIXME should be enough to check if this directory is writable
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    31
	local cert_dir = configmanager.get("*", "certificates") or "certs";
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    32
	cert_basedir = configmanager.resolve_relative_path(prosody.paths.config, cert_dir);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    33
end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    34
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    35
function cert_commands.config(arg)
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    36
	if #arg >= 1 and arg[1] ~= "--help" then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    37
		local conf_filename = cert_basedir .. "/" .. arg[1] .. ".cnf";
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    38
		if use_existing(conf_filename) then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    39
			return nil, conf_filename;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    40
		end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    41
		local distinguished_name;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    42
		if arg[#arg]:find("^/") then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    43
			distinguished_name = table.remove(arg);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    44
		end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    45
		local conf = openssl.config.new();
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    46
		conf:from_prosody(prosody.hosts, configmanager, arg);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    47
		if distinguished_name then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    48
			local dn = {};
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    49
			for k, v in distinguished_name:gmatch("/([^=/]+)=([^/]+)") do
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    50
				table.insert(dn, k);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    51
				dn[k] = v;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    52
			end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    53
			conf.distinguished_name = dn;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    54
		else
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    55
			pctl.show_message("Please provide details to include in the certificate config file.");
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    56
			pctl.show_message("Leave the field empty to use the default value or '.' to exclude the field.")
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    57
			for _, k in ipairs(openssl._DN_order) do
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    58
				local v = conf.distinguished_name[k];
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    59
				if v then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    60
					local nv = nil;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    61
					if k == "commonName" then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    62
						v = arg[1]
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    63
					elseif k == "emailAddress" then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    64
						v = "xmpp@" .. arg[1];
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    65
					elseif k == "countryName" then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    66
						local tld = arg[1]:match"%.([a-z]+)$";
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    67
						if tld and #tld == 2 and tld ~= "uk" then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    68
							v = tld:upper();
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    69
						end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    70
					end
11207
d10f59ac7f74 util.prosodyctl.cert: Fix for prompt functions having moved to util.human.io
Kim Alvefur <zash@zash.se>
parents: 10875
diff changeset
    71
					nv = hi.show_prompt(("%s (%s):"):format(k, nv or v));
10875
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    72
					nv = (not nv or nv == "") and v or nv;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    73
					if nv:find"[\192-\252][\128-\191]+" then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    74
						conf.req.string_mask = "utf8only"
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    75
					end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    76
					conf.distinguished_name[k] = nv ~= "." and nv or nil;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    77
				end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    78
			end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    79
		end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    80
		local conf_file, err = io.open(conf_filename, "w");
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    81
		if not conf_file then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    82
			pctl.show_warning("Could not open OpenSSL config file for writing");
12203
12eaa2fdd75b util.prosodyctl.cert: Pass variables via formatting instead of concatenation
Kim Alvefur <zash@zash.se>
parents: 12173
diff changeset
    83
			pctl.show_warning("%s", err);
10875
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    84
			os.exit(1);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    85
		end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    86
		conf_file:write(conf:serialize());
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    87
		conf_file:close();
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    88
		print("");
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    89
		pctl.show_message("Config written to %s", conf_filename);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    90
		return nil, conf_filename;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    91
	else
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    92
		pctl.show_usage("cert config HOSTNAME [HOSTNAME+]", "Builds a certificate config file covering the supplied hostname(s)")
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    93
	end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    94
end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    95
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    96
function cert_commands.key(arg)
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    97
	if #arg >= 1 and arg[1] ~= "--help" then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    98
		local key_filename = cert_basedir .. "/" .. arg[1] .. ".key";
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    99
		if use_existing(key_filename) then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   100
			return nil, key_filename;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   101
		end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   102
		os.remove(key_filename); -- This file, if it exists is unlikely to have write permissions
11207
d10f59ac7f74 util.prosodyctl.cert: Fix for prompt functions having moved to util.human.io
Kim Alvefur <zash@zash.se>
parents: 10875
diff changeset
   103
		local key_size = tonumber(arg[2] or hi.show_prompt("Choose key size (2048):") or 2048);
10875
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   104
		local old_umask = pposix.umask("0377");
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   105
		if openssl.genrsa{out=key_filename, key_size} then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   106
			os.execute(("chmod 400 '%s'"):format(key_filename));
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   107
			pctl.show_message("Key written to %s", key_filename);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   108
			pposix.umask(old_umask);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   109
			return nil, key_filename;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   110
		end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   111
		pctl.show_message("There was a problem, see OpenSSL output");
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   112
	else
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   113
		pctl.show_usage("cert key HOSTNAME <bits>", "Generates a RSA key named HOSTNAME.key\n "
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   114
		.."Prompts for a key size if none given")
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   115
	end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   116
end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   117
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   118
function cert_commands.request(arg)
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   119
	if #arg >= 1 and arg[1] ~= "--help" then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   120
		local req_filename = cert_basedir .. "/" .. arg[1] .. ".req";
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   121
		if use_existing(req_filename) then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   122
			return nil, req_filename;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   123
		end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   124
		local _, key_filename = cert_commands.key({arg[1]});
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   125
		local _, conf_filename = cert_commands.config(arg);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   126
		if openssl.req{new=true, key=key_filename, utf8=true, sha256=true, config=conf_filename, out=req_filename} then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   127
			pctl.show_message("Certificate request written to %s", req_filename);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   128
		else
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   129
			pctl.show_message("There was a problem, see OpenSSL output");
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   130
		end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   131
	else
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   132
		pctl.show_usage("cert request HOSTNAME [HOSTNAME+]", "Generates a certificate request for the supplied hostname(s)")
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   133
	end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   134
end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   135
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   136
function cert_commands.generate(arg)
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   137
	if #arg >= 1 and arg[1] ~= "--help" then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   138
		local cert_filename = cert_basedir .. "/" .. arg[1] .. ".crt";
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   139
		if use_existing(cert_filename) then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   140
			return nil, cert_filename;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   141
		end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   142
		local _, key_filename = cert_commands.key({arg[1]});
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   143
		local _, conf_filename = cert_commands.config(arg);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   144
		if key_filename and conf_filename and cert_filename
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   145
			and openssl.req{new=true, x509=true, nodes=true, key=key_filename,
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   146
				days=365, sha256=true, utf8=true, config=conf_filename, out=cert_filename} then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   147
			pctl.show_message("Certificate written to %s", cert_filename);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   148
			print();
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   149
		else
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   150
			pctl.show_message("There was a problem, see OpenSSL output");
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   151
		end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   152
	else
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   153
		pctl.show_usage("cert generate HOSTNAME [HOSTNAME+]", "Generates a self-signed certificate for the current hostname(s)")
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   154
	end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   155
end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   156
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   157
local function sh_esc(s)
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   158
	return "'" .. s:gsub("'", "'\\''") .. "'";
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   159
end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   160
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   161
local function copy(from, to, umask, owner, group)
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   162
	local old_umask = umask and pposix.umask(umask);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   163
	local attrs = lfs.attributes(to);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   164
	if attrs then -- Move old file out of the way
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   165
		local backup = to..".bkp~"..os.date("%FT%T", attrs.change);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   166
		os.rename(to, backup);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   167
	end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   168
	-- FIXME friendlier error handling, maybe move above backup back?
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   169
	local input = assert(io.open(from));
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   170
	local output = assert(io.open(to, "w"));
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   171
	local data = input:read(2^11);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   172
	while data and output:write(data) do
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   173
		data = input:read(2^11);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   174
	end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   175
	assert(input:close());
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   176
	assert(output:close());
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   177
	if not prosody.installed then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   178
		-- FIXME this is possibly specific to GNU chown
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   179
		os.execute(("chown -c --reference=%s %s"):format(sh_esc(cert_basedir), sh_esc(to)));
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   180
	elseif owner and group then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   181
		local ok = os.execute(("chown %s:%s %s"):format(sh_esc(owner), sh_esc(group), sh_esc(to)));
12790
5d4957c8a972 util.prosodyctl.cert: Remove Lua 5.1 os.execute() return value compat
Kim Alvefur <zash@zash.se>
parents: 12391
diff changeset
   182
		assert(ok, "Failed to change ownership of "..to);
10875
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   183
	end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   184
	if old_umask then pposix.umask(old_umask); end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   185
	return true;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   186
end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   187
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   188
function cert_commands.import(arg)
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   189
	local hostnames = {};
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   190
	-- Move hostname arguments out of arg, the rest should be a list of paths
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   191
	while arg[1] and prosody.hosts[ arg[1] ] do
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   192
		table.insert(hostnames, table.remove(arg, 1));
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   193
	end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   194
	if hostnames[1] == nil then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   195
		local domains = os.getenv"RENEWED_DOMAINS"; -- Set if invoked via certbot
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   196
		if domains then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   197
			for host in domains:gmatch("%S+") do
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   198
				table.insert(hostnames, host);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   199
			end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   200
		else
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   201
			for host in pairs(prosody.hosts) do
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   202
				if host ~= "*" and configmanager.get(host, "enabled") ~= false then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   203
					table.insert(hostnames, host);
12223
0a44def211fa util.prosodyctl.cert: Look for certs matching 'http_host'
Kim Alvefur <zash@zash.se>
parents: 12220
diff changeset
   204
					local http_host = configmanager.get(host, "http_host") or host;
0a44def211fa util.prosodyctl.cert: Look for certs matching 'http_host'
Kim Alvefur <zash@zash.se>
parents: 12220
diff changeset
   205
					if http_host ~= host then
0a44def211fa util.prosodyctl.cert: Look for certs matching 'http_host'
Kim Alvefur <zash@zash.se>
parents: 12220
diff changeset
   206
						table.insert(hostnames, http_host);
0a44def211fa util.prosodyctl.cert: Look for certs matching 'http_host'
Kim Alvefur <zash@zash.se>
parents: 12220
diff changeset
   207
					end
10875
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   208
				end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   209
			end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   210
		end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   211
	end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   212
	if not arg[1] or arg[1] == "--help" then -- Probably forgot the path
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   213
		pctl.show_usage("cert import [HOSTNAME+] /path/to/certs [/other/paths/]+",
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   214
			"Copies certificates to "..cert_basedir);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   215
		return 1;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   216
	end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   217
	local owner, group;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   218
	if pposix.getuid() == 0 then -- We need root to change ownership
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   219
		owner = configmanager.get("*", "prosody_user") or "prosody";
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   220
		group = configmanager.get("*", "prosody_group") or owner;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   221
	end
12979
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12790
diff changeset
   222
	local cm = require "prosody.core.certmanager";
12108
29765ac7f72f prosodyctl cert: use the indexing functions for better UX
Jonas Schäfer <jonas@wielicki.name>
parents: 11207
diff changeset
   223
	local files_by_name = {}
29765ac7f72f prosodyctl cert: use the indexing functions for better UX
Jonas Schäfer <jonas@wielicki.name>
parents: 11207
diff changeset
   224
	for _, dir in ipairs(arg) do
29765ac7f72f prosodyctl cert: use the indexing functions for better UX
Jonas Schäfer <jonas@wielicki.name>
parents: 11207
diff changeset
   225
		cm.index_certs(dir, files_by_name);
29765ac7f72f prosodyctl cert: use the indexing functions for better UX
Jonas Schäfer <jonas@wielicki.name>
parents: 11207
diff changeset
   226
	end
10875
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   227
	local imported = {};
12220
0f5d04c3092f util.prosodyctl.cert: Look for certificates in a consistent order
Kim Alvefur <zash@zash.se>
parents: 12204
diff changeset
   228
	table.sort(hostnames, function (a, b)
0f5d04c3092f util.prosodyctl.cert: Look for certificates in a consistent order
Kim Alvefur <zash@zash.se>
parents: 12204
diff changeset
   229
		-- Try to find base domain name before sub-domains, then alphabetically, so
0f5d04c3092f util.prosodyctl.cert: Look for certificates in a consistent order
Kim Alvefur <zash@zash.se>
parents: 12204
diff changeset
   230
		-- that the order and choice of file name is deterministic.
0f5d04c3092f util.prosodyctl.cert: Look for certificates in a consistent order
Kim Alvefur <zash@zash.se>
parents: 12204
diff changeset
   231
		if #a == #b then
0f5d04c3092f util.prosodyctl.cert: Look for certificates in a consistent order
Kim Alvefur <zash@zash.se>
parents: 12204
diff changeset
   232
			return a < b;
0f5d04c3092f util.prosodyctl.cert: Look for certificates in a consistent order
Kim Alvefur <zash@zash.se>
parents: 12204
diff changeset
   233
		else
0f5d04c3092f util.prosodyctl.cert: Look for certificates in a consistent order
Kim Alvefur <zash@zash.se>
parents: 12204
diff changeset
   234
			return #a < #b;
0f5d04c3092f util.prosodyctl.cert: Look for certificates in a consistent order
Kim Alvefur <zash@zash.se>
parents: 12204
diff changeset
   235
		end
0f5d04c3092f util.prosodyctl.cert: Look for certificates in a consistent order
Kim Alvefur <zash@zash.se>
parents: 12204
diff changeset
   236
	end);
10875
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   237
	for _, host in ipairs(hostnames) do
12108
29765ac7f72f prosodyctl cert: use the indexing functions for better UX
Jonas Schäfer <jonas@wielicki.name>
parents: 11207
diff changeset
   238
		local paths = cm.find_cert_in_index(files_by_name, host);
12173
866d06644956 util.prosodyctl.cert: Fix boolean logic bug
Kim Alvefur <zash@zash.se>
parents: 12111
diff changeset
   239
		if paths and imported[paths.certificate] then
12391
05c250fa335a Spelling: Fix various spelling mistakes (thanks timeless)
Kim Alvefur <zash@zash.se>
parents: 12223
diff changeset
   240
			-- One certificate, many names!
12111
8a5a9c1adb90 util.prosodyctl.cert: Copy SAN/wildcard certs only once
Kim Alvefur <zash@zash.se>
parents: 12108
diff changeset
   241
			table.insert(imported, host);
8a5a9c1adb90 util.prosodyctl.cert: Copy SAN/wildcard certs only once
Kim Alvefur <zash@zash.se>
parents: 12108
diff changeset
   242
		elseif paths then
12204
2bb4ee5f42be util.prosodyctl.cert: Check success of copy operations, warn on fail
Kim Alvefur <zash@zash.se>
parents: 12203
diff changeset
   243
			local c = copy(paths.certificate, cert_basedir .. "/" .. host .. ".crt", nil, owner, group);
2bb4ee5f42be util.prosodyctl.cert: Check success of copy operations, warn on fail
Kim Alvefur <zash@zash.se>
parents: 12203
diff changeset
   244
			local k = copy(paths.key, cert_basedir .. "/" .. host .. ".key", "0377", owner, group);
2bb4ee5f42be util.prosodyctl.cert: Check success of copy operations, warn on fail
Kim Alvefur <zash@zash.se>
parents: 12203
diff changeset
   245
			if c and k then
2bb4ee5f42be util.prosodyctl.cert: Check success of copy operations, warn on fail
Kim Alvefur <zash@zash.se>
parents: 12203
diff changeset
   246
				table.insert(imported, host);
2bb4ee5f42be util.prosodyctl.cert: Check success of copy operations, warn on fail
Kim Alvefur <zash@zash.se>
parents: 12203
diff changeset
   247
				imported[paths.certificate] = true;
2bb4ee5f42be util.prosodyctl.cert: Check success of copy operations, warn on fail
Kim Alvefur <zash@zash.se>
parents: 12203
diff changeset
   248
			else
2bb4ee5f42be util.prosodyctl.cert: Check success of copy operations, warn on fail
Kim Alvefur <zash@zash.se>
parents: 12203
diff changeset
   249
				if not c then pctl.show_warning("Could not copy certificate '%s'", paths.certificate); end
2bb4ee5f42be util.prosodyctl.cert: Check success of copy operations, warn on fail
Kim Alvefur <zash@zash.se>
parents: 12203
diff changeset
   250
				if not k then pctl.show_warning("Could not copy key '%s'", paths.key); end
2bb4ee5f42be util.prosodyctl.cert: Check success of copy operations, warn on fail
Kim Alvefur <zash@zash.se>
parents: 12203
diff changeset
   251
			end
12108
29765ac7f72f prosodyctl cert: use the indexing functions for better UX
Jonas Schäfer <jonas@wielicki.name>
parents: 11207
diff changeset
   252
		else
29765ac7f72f prosodyctl cert: use the indexing functions for better UX
Jonas Schäfer <jonas@wielicki.name>
parents: 11207
diff changeset
   253
			-- TODO Say where we looked
12203
12eaa2fdd75b util.prosodyctl.cert: Pass variables via formatting instead of concatenation
Kim Alvefur <zash@zash.se>
parents: 12173
diff changeset
   254
			pctl.show_warning("No certificate for host %s found :(", host);
10875
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   255
		end
12108
29765ac7f72f prosodyctl cert: use the indexing functions for better UX
Jonas Schäfer <jonas@wielicki.name>
parents: 11207
diff changeset
   256
		-- TODO Additional checks
29765ac7f72f prosodyctl cert: use the indexing functions for better UX
Jonas Schäfer <jonas@wielicki.name>
parents: 11207
diff changeset
   257
		-- Certificate names matches the hostname
29765ac7f72f prosodyctl cert: use the indexing functions for better UX
Jonas Schäfer <jonas@wielicki.name>
parents: 11207
diff changeset
   258
		-- Private key matches public key in certificate
10875
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   259
	end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   260
	if imported[1] then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   261
		pctl.show_message("Imported certificate and key for hosts %s", table.concat(imported, ", "));
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   262
		local ok, err = pctl.reload();
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   263
		if not ok and err ~= "not-running" then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   264
			pctl.show_message(pctl.error_messages[err]);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   265
		end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   266
	else
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   267
		pctl.show_warning("No certificates imported :(");
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   268
		return 1;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   269
	end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   270
end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   271
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   272
local function cert(arg)
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   273
	if #arg >= 1 and arg[1] ~= "--help" then
12979
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12790
diff changeset
   274
		openssl = require "prosody.util.openssl";
10875
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   275
		lfs = require "lfs";
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   276
		local cert_dir_attrs = lfs.attributes(cert_basedir);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   277
		if not cert_dir_attrs then
12203
12eaa2fdd75b util.prosodyctl.cert: Pass variables via formatting instead of concatenation
Kim Alvefur <zash@zash.se>
parents: 12173
diff changeset
   278
			pctl.show_warning("The directory %s does not exist", cert_basedir);
10875
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   279
			return 1; -- TODO Should we create it?
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   280
		end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   281
		local uid = pposix.getuid();
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   282
		if uid ~= 0 and uid ~= cert_dir_attrs.uid then
12203
12eaa2fdd75b util.prosodyctl.cert: Pass variables via formatting instead of concatenation
Kim Alvefur <zash@zash.se>
parents: 12173
diff changeset
   283
			pctl.show_warning("The directory %s is not owned by the current user, won't be able to write files to it", cert_basedir);
10875
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   284
			return 1;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   285
		elseif not cert_dir_attrs.permissions then -- COMPAT with LuaFilesystem < 1.6.2 (hey CentOS!)
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   286
			pctl.show_message("Unable to check permissions on %s (LuaFilesystem 1.6.2+ required)", cert_basedir);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   287
			pctl.show_message("Please confirm that Prosody (and only Prosody) can write to this directory)");
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   288
		elseif cert_dir_attrs.permissions:match("^%.w..%-..%-.$") then
12203
12eaa2fdd75b util.prosodyctl.cert: Pass variables via formatting instead of concatenation
Kim Alvefur <zash@zash.se>
parents: 12173
diff changeset
   289
			pctl.show_warning("The directory %s not only writable by its owner", cert_basedir);
10875
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   290
			return 1;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   291
		end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   292
		local subcmd = table.remove(arg, 1);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   293
		if type(cert_commands[subcmd]) == "function" then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   294
			if subcmd ~= "import" then -- hostnames are optional for import
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   295
				if not arg[1] then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   296
					pctl.show_message"You need to supply at least one hostname"
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   297
					arg = { "--help" };
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   298
				end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   299
				if arg[1] ~= "--help" and not prosody.hosts[arg[1]] then
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   300
					pctl.show_message(pctl.error_messages["no-such-host"]);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   301
					return 1;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   302
				end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   303
			end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   304
			return cert_commands[subcmd](arg);
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   305
		elseif subcmd == "check" then
12979
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12790
diff changeset
   306
			return require "prosody.util.prosodyctl.check".check({"certs"});
10875
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   307
		end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   308
	end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   309
	pctl.show_usage("cert config|request|generate|key|import", "Helpers for generating X.509 certificates and keys.")
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   310
	for _, cmd in pairs(cert_commands) do
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   311
		print()
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   312
		cmd{ "--help" }
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   313
	end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   314
end
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   315
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   316
return {
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   317
	cert = cert;
e5dee71d0ebb prosodyctl+util.prosodyctl.*: Start breaking up the ever-growing prosodyctl
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   318
};