In <list-11070551@2rosenthals.com>, on 10/07/24
at 08:22 PM, "Massimo S." <ecs-isp@2rosenthals.com> said:
>i'm trying to catch that challenge value to verify when they accept
>HTTP-01 to improve the script
I have appended a copy of the uacme-hook.cmd that Dan and I use.
The interesting code is above the
/*==============================================================================*/
/*=== SkelRexxFunc standards - Delete unused - Move modified above this
mark ===*/
/*==============================================================================*/
separator. Everything below is boilerplate code that is maintained by my
tools.
You may notice that the script is almost 100% generic. Since our mapping
of domain names to document roots is consistent, I saw no need to parse
the httpd conf files or read the mappings from an external file.
The relevant mapping code follows the
/* Map domain to VirtualHost docroot directory */
comment.
To handle possible uacme.exe failures, we back up the certificates before
the uacme.exe runs and configure httpd to use the certificates as created
by uacme.
Steven
--
----------------------------------------------------------------------
"Steven Levine" <steve53@earthlink.net> Warp/DIY/BlueLion etc.
www.scoug.com www.arcanoae.com www.warpcave.com
----------------------------------------------------------------------
/* uacme-hook - uacme hook script
Expects to be install where uacme.exe can find it
Expects to be able to map the ident passed to hook to challenge directory name
Ident is typically same as domain name
Typical usage is
uacme -v -h uacme-hook.cmd issue example.com
Copyright (c) 2024 Steven Levine and Associates, Inc.
All rights reserved.
This program is free software licensed under the terms of
the GNU General Public License Version 3 or newer. The GPL
Software License can be found in gnugpl3.txt or at http://www.gnu.org/licenses/licenses.html#GPL
/* FIXME to be gone somewhen */
gTesting = 0
if GetEnv('HOSTNAME') == 'slamain' then do
call LogWriteVTSC '', 'Running on slamain in test mode'
gTesting = 1
end
/* Find docs directory for server */
docsdir = left(directory(), 1) || ':\www\docs\'
if gTesting then
docsdir = left(directory(), 1) || ':\Internet\apache24-data\htdocs'
if \ IsDir(docsdir) then
call Die 'Cannot access' docsdir 'directory'
/* Map domain to VirtualHost docroot directory */
ndx = lastpos('.', gIdent)
if ndx = 0 then do
domain = gIdent
suffix = ''
end
else do
suffix = substr(gIdent, ndx + 1) /* Without dot */
domain = left(gIdent, ndx - 1)
ndx = lastpos('.', domain)
if ndx > 0 then
domain = substr(domain, ndx + 1)
end
if \ IsDir(challengeDir) then
call Die 'Cannot access' challengeDir 'directory'
gTokenFile = MakePath(challengeDir, gToken)
select
when gMethod == 'begin' then
call DoBegin
when gMethod == 'done' then
call DoDone
when gMethod == 'failed' then
call DoFailed
otherwise
call Die 'method' gMethod 'unexpected'
end
exit RESULT
/* end main */
/*=== DoBegin() Handle begin method ===*/
DoBegin: procedure expose (Globals)
if gType \== 'http-01' then
call Die 'DoBegin: type' gType 'unsupported'
/*==============================================================================*/
/*=== SkelRexxFunc standards - Delete unused - Move modified above this mark ===*/
/*==============================================================================*/
/*=== DieVTS(message) Write message to STDOUT and timestampped message to log file and die ===*/
Die:
/* Requires LogWriteVTS and dependents */
/* Requires LogWriteVTSC and dependents */
parse arg msg
callerSIGL = SIGL
/* Use say to avoid NotReady in case running detached - FIXME to be sure not ok to write to STDERR */
say
call LogWriteVTS msg
msg = gCmdName 'aborting at line' callerSIGL || '.'
call LogWriteVTSC msg
call beep 200, 300
exit 254
/* end DieVTS */
/*=== GetEnv(var) Return value for environment variable or empty string ===*/
GetEnv: procedure expose (Globals)
parse arg var
if var = '' then
call Die 'GetEnv requires an argument'
return value(var,, gEnv)
/* end GetEnv */
/*=== IsDir(dirName[, full]) return true if directory is valid, accessible directory ===*/
IsDir: procedure
/* If arg(2) not omitted, return full directory name or empty string */
parse arg dir, full
newdir = ''
do 1
if dir == '' then do
cwd = '' /* No restore needed */
leave
end
dir = translate(dir, '\', '/') /* Convert to OS/2 slashes */
s = strip(dir, 'T', '\') /* Chop trailing slashes unless root */
if s \== '' & right(s, 1) \== ":" then
dir = s /* Chop */
drv = filespec('D', dir)
cwd = directory() /* Remember */
/* If have drive letter and requested directory on some other drive */
if drv \== '' & translate(drv) \== translate(left(cwd, 2)) then do
/* Avoid slow failures and unwanted directory changes */
drvs = SysDriveMap('A:')
if pos(translate(drv), drvs) = 0 then
leave /* Unknown drive */
if SysDriveInfo(drv) == '' then
leave /* Drive not ready */
cwd2 = directory(drv) /* Remember current directory on other drive */
newdir = directory(dir) /* Try to change and get full path name */
call directory cwd2 /* Restore current directory on other drive */
leave
end
/* If no drive letter or same drive and not UNC name */
if left(dir, 2) \== '\\' then do
newdir = directory(dir) /* Try to change and get full path name */
leave
end
/* UNC name - hopefully server is accessible or this will be slow
Accept
\\server
\\server\
\\server\dir\
\\server\dir
*/
cwd = '' /* No restore needed */
wc = dir
if right(wc, 1) \== '\' then
wc = wc || '\'
i = lastpos('\', wc)
if substr(wc, 3, 1) == '\' then
leave /* Malformed UNC - no server name */
if pos('*', wc) > 0 | pos('?', wc) > 0 then
leave /* No wildcards allowed */
call SysFileTree wc, 'files', 'O'
if files.0 > 0 then do
s = files.1 /* Exists and is not empty */
i = lastpos('\', s)
newdir = left(s, i - 1) /* Extract directory name from full path name */
leave
end
/* Try wildcarded directory name */
wc = strip(wc, 'T', '\')
i = lastpos('\', wc)
base = substr(wc, i + 1)
if base == '' then
leave /* Should have matched above */
wc = substr(wc, 1, i) || '*' || base || '*'
call SysFileTree wc, 'files', 'DO'
do fileNum = 1 to files.0
/* Find directory name is list */
s = files.fileNum
i = lastpos('\', s)
s2 = substr(s, i + 1)
if translate(base) == translate(s2) then do
newdir = left(s, i - 1)
leave
end
end /* i */
end /* 1 */
if cwd \== '' then
call directory cwd /* Restore original directory and drive */
if full \== '' then
ret = newdir /* Return full directory name or empty string */
else
ret = newdir \== '' /* Return true if valid and accessible */
return ret
/* end IsDir */
/*=== LogOpen() Open log file for append ===*/
LogOpen: procedure expose (Globals)
/* Requires LogSetName unless gLogFile defined */
/* Sets gLogFile if not defined */
/* Overrides gLogFile if open fails */
if symbol('gLogFile') \== 'VAR' then
call LogSetName
/* Assume closed */
call stream gLogFile, 'C', 'OPEN WRITE'
if stream(gLogFile) \== 'READY' then do
gLogFile = '\' || gCmdName || '.log' /* Try root */
call stream gLogFile, 'C', 'OPEN WRITE'
end
return
/* end LogOpen */
/*=== LogSetName() Set log file name ===*/
/**
* Sets gLogFile if not defined
* Sets gLogDir if not defined
*/
LogSetName: procedure expose (Globals)
/* Requires LogSetDir unless gLogDir defined */
/* Requires gCmdName */
if symbol('gLogFile') \== 'VAR' then do
if symbol('gLogDir') \== 'VAR' then
call LogSetDir
/* Ensure trailing backslash unless using current directory */
dir = gLogDir
if dir \== '' & right(dir, 1) \== ':' & right(dir, 1) \== '\' then
dir = dir || '\' /* Ensure trailing backslash */
gLogFile = dir || gCmdName'.log'
end
return
/* end LogSetName */
/*=== LogSetDir() Set gLogDir and provide trailing backslash if needed ===*/
/**
* Set gLogDir if gLogDir not defined
* Tries %LOGFILES gTmpDir %TMP
* Falls back to current directory and returns null string
*/
LogSetDir: procedure expose (Globals)
if symbol('gLogDir') \== 'VAR' then do
/* Try gLogDir %LOGFILES gTmpDir %TMP */
do 1
/* Try %LOGFILES */
gLogDir = value('LOGFILES',, gEnv)
if gLogDir \== '' then leave
/* Try gTmpDir */
if symbol('gTmpDir') == 'VAR' then do
gLogDir = gTmpDir
leave
end
/* Try %TMP - return empty string if TMP not defined */
gLogDir = value('TMP',, gEnv)
end
end
return
/* end LogSetDir */
/*=== LogWriteVTS(message,...) Write multi-line message to STDOUT and timestamped message to log file ===*/
LogWriteVTS: procedure expose (Globals)
/* Requires LogOpen */
/* Requires MakeTimestamp */
if symbol('gLogFile') \== 'VAR' then
call LogOpen
do i = 1 to arg()
say arg(i)
call lineout gLogFile, MakeTimestamp() arg(i)
if symbol('gLogWrites') == 'VAR' then
gLogWrites = gLogWrites + 1
end
return
/* end LogWriteVTS */
/*=== LogWriteVTSC(message,...) Write multi-line message to STDOUT and timestamped message to log file and close log ===*/
LogWriteVTSC: procedure expose (Globals)
/* Requires LogOpen */
/* Requires MakeTimestamp */
if symbol('gLogFile') \== 'VAR' then
call LogOpen
ts = MakeTimestamp()
do i = 1 to arg()
say ts arg(i)
call lineout gLogFile, ts arg(i)
if symbol('gLogWrites') == 'VAR' then
gLogWrites = gLogWrites + 1
end
call stream gLogFile, 'C', 'CLOSE'
return
/* end LogWriteVTSC */
/*=== MakePath(pathparts,...) Make path name from parts ===*/
MakePath: procedure
/* All parts optional - code guesses what caller means.
If last arg begins with a dot and is not .. and does not
contain a slash, it is assumed to be a file extension.
To avoid this behavior, pass empty arg as last arg.
Empty args are ignored.
Automatically converts unix slashes to dos slashes.
If 1st arg is drive letter, it must have trailing colon.
*/
argCnt = arg()
path = ''
do argNum = 1 to argCnt
s = arg(argNum)
s = translate(s, '\', '/') /* Ensure DOS */
if s == '' & argNum = argCnt then
iterate /* Ignore nul last arg */
if argNum = 1 then
path = s
else do
lead = left(s, 1)
tail = right(path, 1)
if tail == ':' & argNum = 2 then
path = path || s /* Append path part to drive spec */
else if lead == '.' & argNum = argCnt & s \== '..' & pos('\', s) = 0 then
path = path || s /* Assume extension unless .. or contains \ */
else if tail == '\' & lead == '\' then
path = path || substr(s, 2) /* Drop extra backslash */
else if path \== '' & tail \== '\' & lead \== '\' then
path = path || '\' || s /* Ensure have backslash */
else
path = path || s
end
end /* for */
return path
/* end MakePath */
/*=== MakeTimestamp() Convert current date/time to sorted, delimited timestamp - yyyy/mm/dd-hh:mm:ss ===*/
/*==========================================================================*/
/*=== SkelRexx standards - Delete unused - Move modified above this mark ===*/
/*==========================================================================*/
/*=== Error() Set gErrCondition; report to STDOUT; trace and exit or return if called ===*/
Error:
say
parse source . . cmd
gErrCondition = condition('C')
say gErrCondition 'signaled at line' SIGL 'of' cmd || '.'
if condition('D') \== '' then
say 'REXX reason =' condition('D') || '.'
if gErrCondition == 'SYNTAX' & symbol('RC') == 'VAR' then
say 'REXX error =' RC '-' errortext(RC) || '.'
else if symbol('RC') == 'VAR' then
say 'RC =' RC || '.'
say 'Source =' sourceline(SIGL)
if condition('I') \== 'CALL' | gErrCondition == 'NOVALUE' | gErrCondition == 'SYNTAX' then do
trace '?A'
say 'Enter REXX commands to debug failure. Press enter to exit script.'
nop
if symbol('RC') \== 'VAR' then
RC = 255
exit RC
end
return
/* end Error */
/*=== Halt() Report HALT condition to STDOUT and exit ===*/
Halt:
say
parse source . . cmd
say condition('C') 'signaled at' cmd 'line' SIGL || '.'
say 'Source =' sourceline(SIGL)
say 'Sleeping for 2 seconds...'
call SysSleep 2
exit 253
LoadRexxUtil:
if RxFuncQuery('SysLoadFuncs') then do
call RxFuncAdd 'SysLoadFuncs', 'REXXUTIL', 'SysLoadFuncs'
if RESULT then
call Die 'Cannot load SysLoadFuncs.'
call SysLoadFuncs
end
return
/* end LoadRexxUtil */
/*=== SetCmdName() Set gCmdName to short script name ===*/
SetCmdName: procedure expose (Globals)
parse source . . cmd
cmd = filespec('N', cmd) /* Chop path */
c = lastpos('.', cmd)
if c > 1 then
cmd = left(cmd, c - 1) /* Chop extension */
gCmdName = translate(cmd, xrange('a', 'z'), xrange('A', 'Z')) /* Lowercase */
return