1#!/bin/sh 2# Copyright (C) 2020 Michel Stam <michel@reverze.net> 3# 4# This file is part of uacme. 5# 6# uacme is free software: you can redistribute it and/or modify it 7# under the terms of the GNU General Public License as published by 8# the Free Software Foundation, either version 3 of the License, or 9# (at your option) any later version. 10# 11# uacme is distributed in the hope that it will be useful, but 12# WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14# General Public License for more details. 15# 16# You should have received a copy of the GNU General Public License 17# along with this program. If not, see <http://www.gnu.org/licenses/>. 18 19# Commands 20DIG=dig 21NSUPDATE=nsupdate 22 23# Files 24# RNDC_KEY_{NSUPDATE,DIG} 25# if you wish to specify an RDC key for TSIG transactions, do so 26# here. If you do, also make sure /etc/named.conf specifies the 27# key "KEYNAME"; in the zone that must be updated (and disallow 28# all others for safety) 29RNDC_KEY_NSUPDATE= 30RNDC_KEY_DIG= 31 32# Arguments 33METHOD=$1 34TYPE=$2 35IDENT=$3 36TOKEN=$4 37AUTH=$5 38 39ns_getdomain() 40{ 41 local domain=$1 42 43 [ -n "$domain" ] || return 44 set -- $($DIG ${RNDC_KEY_DIG:+-k ${RNDC_KEY_DIG}} +noall +authority "$domain" SOA 2>/dev/null) 45 46 echo $1 47} 48 49ns_getprimary() 50{ 51 local domain=$1 52 53 [ -n "$domain" ] || return 54 set -- $($DIG ${RNDC_KEY_DIG:+-k ${RNDC_KEY_DIG}} +short "$domain" SOA 2>/dev/null) 55 56 echo $1 57} 58 59ns_getall() 60{ 61 local domain=$1 62 63 [ -n "$domain" ] || return 1 64 65 $DIG ${RNDC_KEY_DIG:+-k ${RNDC_KEY_DIG}} +short "$domain" NS 2>/dev/null 66} 67 68ns_ispresent() 69{ 70 local fqhn="$1" 71 local expect="$2" 72 local domain=$(ns_getdomain "$fqhn") 73 local nameservers=$(ns_getall "$domain") 74 local res 75 local ret 76 77 for NS in $nameservers; do 78 OLDIFS="${IFS}" 79 IFS='.' 80 set -- $($DIG ${RNDC_KEY_DIG:+-k ${RNDC_KEY_DIG}} +short "@$NS" "$fqhn" TXT 2>/dev/null) 81 IFS="${OLDIFS}" 82 { [ "$*" = "$expect" ] || [ "$*" = "\"$expect\"" ] ; } || return 1 83 done 84 85 return 0 86} 87 88ns_doupdate() 89{ 90 local fqhn="$1" 91 local challenge="$2" 92 local ttl=600 93 local domain=$(ns_getdomain "$fqhn") 94 local nameserver=$(ns_getprimary "$domain") 95 local action= 96 97 [ -n "$nameserver" ] || return 98 99 if [ -n "${challenge}" ]; then 100 action="update add ${fqhn}. ${ttl} IN TXT ${challenge}" 101 else 102 action="update del ${fqhn}." 103 fi 104 105 $NSUPDATE ${RNDC_KEY_NSUPDATE:+-k ${RNDC_KEY_NSUPDATE}} -v <<-EOF 106 server ${nameserver} 107 ${action} 108 send 109EOF 110 111 return $? 112} 113 114ns_update() 115{ 116 local fqhn="$1" 117 local challenge="$2" 118 local count=0 119 local res 120 121 res=1 122 while [ $res -ne 0 ]; do 123 if [ $count -eq 0 ]; then 124 ns_doupdate "$fqhn" "$challenge" 125 res=$? 126 [ $res -eq 0 ] || break 127 else 128 sleep 1 129 fi 130 131 count=$(((count + 1) % 5)) 132 ns_ispresent "$fqhn" "$challenge" 133 res=$? 134 done 135 136 return $? 137} 138 139ARGS=5 140E_BADARGS=85 141 142if [ $# -ne "$ARGS" ]; then 143 echo "Usage: $(basename "$0") method type ident token auth" 1>&2 144 exit $E_BADARGS 145fi 146 147case "$METHOD" in 148 "begin") 149 case "$TYPE" in 150 dns-01) 151 ns_update "_acme-challenge.$IDENT" "$AUTH" 152 exit $? 153 ;; 154 *) 155 exit 1 156 ;; 157 esac 158 ;; 159 160 "done"|"failed") 161 case "$TYPE" in 162 dns-01) 163 ns_update "_acme-challenge.$IDENT" 164 exit $? 165 ;; 166 *) 167 exit 1 168 ;; 169 esac 170 ;; 171 172 *) 173 echo "$0: invalid method" 1>&2 174 exit 1 175esac 176