]> git.proxmox.com Git - proxmox-acme.git/blame - src/proxmox-acme
plugin-caller: make no-ops always successful
[proxmox-acme.git] / src / proxmox-acme
CommitLineData
1a8ba4f0 1#!/bin/bash
92b88a9e 2
3f11a215 3VER=1.0
ece42f2f
WL
4
5PROJECT_NAME="ProxmoxACME"
6
7USER_AGENT="$PROJECT_NAME/$VER"
8
9DNS_PLUGIN_PATH="/usr/share/proxmox-acme/dnsapi"
bb2e0864
WL
10HTTP_HEADER="$(mktemp)"
11
54fd0088
WL
12DEBUG="0"
13
92b88a9e 14_base64() {
bb2e0864 15 openssl base64 -e | tr -d '\r\n'
92b88a9e
WL
16}
17
92b88a9e 18_dbase64() {
bb2e0864 19 openssl base64 -d
92b88a9e
WL
20}
21
22# Usage: hashalg [outputhex]
23# Output Base64-encoded digest
24_digest() {
25 alg="$1"
92b88a9e
WL
26
27 if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then
bb2e0864
WL
28 if [ "$2" ]; then
29 openssl dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' '
92b88a9e 30 else
bb2e0864 31 openssl dgst -"$alg" -binary | _base64
92b88a9e 32 fi
92b88a9e 33 fi
92b88a9e
WL
34}
35
79364a8c
SI
36_usage() {
37 __red "$@" >&2
38 printf "\n" >&2
39}
40
92b88a9e
WL
41_upper_case() {
42 # shellcheck disable=SC2018,SC2019
43 tr 'a-z' 'A-Z'
44}
45
46_lower_case() {
47 # shellcheck disable=SC2018,SC2019
48 tr 'A-Z' 'a-z'
49}
50
51_startswith() {
52 _str="$1"
53 _sub="$2"
54 echo "$_str" | grep "^$_sub" >/dev/null 2>&1
55}
56
57_endswith() {
58 _str="$1"
59 _sub="$2"
60 echo "$_str" | grep -- "$_sub\$" >/dev/null 2>&1
61}
62
63_contains() {
64 _str="$1"
65 _sub="$2"
66 echo "$_str" | grep -- "$_sub" >/dev/null 2>&1
67}
68
69# str index [sep]
70_getfield() {
71 _str="$1"
72 _findex="$2"
73 _sep="$3"
74
92b88a9e
WL
75 if [ -z "$_sep" ]; then
76 _sep=","
77 fi
78
79 _ffi="$_findex"
80 while [ "$_ffi" -gt "0" ]; do
81 _fv="$(echo "$_str" | cut -d "$_sep" -f "$_ffi")"
82 if [ "$_fv" ]; then
83 printf -- "%s" "$_fv"
84 return 0
85 fi
86 _ffi="$(_math "$_ffi" - 1)"
87 done
88
89 printf -- "%s" "$_str"
90
91}
92
93_exists() {
94 cmd="$1"
92b88a9e 95 if eval type type >/dev/null 2>&1; then
bb2e0864
WL
96 type "$cmd" >/dev/null 2>&1
97 else command
92b88a9e 98 command -v "$cmd" >/dev/null 2>&1
92b88a9e
WL
99 fi
100 ret="$?"
92b88a9e
WL
101 return $ret
102}
103
104# a + b
105_math() {
106 _m_opts="$@"
107 printf "%s" "$(($_m_opts))"
108}
109
110_egrep_o() {
111 if ! egrep -o "$1" 2>/dev/null; then
112 sed -n 's/.*\('"$1"'\).*/\1/p'
113 fi
114}
115
79364a8c
SI
116_h2b() {
117 if _exists xxd; then
118 if _contains "$(xxd --help 2>&1)" "assumes -c30"; then
119 if xxd -r -p -c 9999 2>/dev/null; then
120 return
121 fi
122 else
123 if xxd -r -p 2>/dev/null; then
124 return
125 fi
126 fi
127 fi
128
129 hex=$(cat)
130 ic=""
131 jc=""
132 _debug2 _URGLY_PRINTF "$_URGLY_PRINTF"
133 if [ -z "$_URGLY_PRINTF" ]; then
134 if [ "$_ESCAPE_XARGS" ] && _exists xargs; then
135 _debug2 "xargs"
136 echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/g' | xargs printf
137 else
138 for h in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/ \1/g'); do
139 if [ -z "$h" ]; then
140 break
141 fi
142 printf "\x$h%s"
143 done
144 fi
145 else
146 for c in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\)/ \1/g'); do
147 if [ -z "$ic" ]; then
148 ic=$c
149 continue
150 fi
151 jc=$c
152 ic="$(_h_char_2_dec "$ic")"
153 jc="$(_h_char_2_dec "$jc")"
154 printf '\'"$(printf "%o" "$(_math "$ic" \* 16 + $jc)")""%s"
155 ic=""
156 jc=""
157 done
158 fi
159
160}
161
162#Usage: keyfile hashalg
163#Output: Base64-encoded signature value
164_sign() {
165 keyfile="$1"
166 alg="$2"
167 if [ -z "$alg" ]; then
168 _usage "Usage: _sign keyfile hashalg"
169 return 1
170 fi
171
172 _sign_openssl="${ACME_OPENSSL_BIN:-openssl} dgst -sign $keyfile "
173
174 if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1 || grep "BEGIN PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
175 $_sign_openssl -$alg | _base64
176 elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
177 if ! _signedECText="$($_sign_openssl -sha$__ECC_KEY_LEN | ${ACME_OPENSSL_BIN:-openssl} asn1parse -inform DER)"; then
178 _err "Sign failed: $_sign_openssl"
179 _err "Key file: $keyfile"
180 _err "Key content:$(wc -l <"$keyfile") lines"
181 return 1
182 fi
183 _debug3 "_signedECText" "$_signedECText"
184 _ec_r="$(echo "$_signedECText" | _head_n 2 | _tail_n 1 | cut -d : -f 4 | tr -d "\r\n")"
185 _ec_s="$(echo "$_signedECText" | _head_n 3 | _tail_n 1 | cut -d : -f 4 | tr -d "\r\n")"
186 if [ "$__ECC_KEY_LEN" -eq "256" ]; then
187 while [ "${#_ec_r}" -lt "64" ]; do
188 _ec_r="0${_ec_r}"
189 done
190 while [ "${#_ec_s}" -lt "64" ]; do
191 _ec_s="0${_ec_s}"
192 done
193 fi
194 if [ "$__ECC_KEY_LEN" -eq "384" ]; then
195 while [ "${#_ec_r}" -lt "96" ]; do
196 _ec_r="0${_ec_r}"
197 done
198 while [ "${#_ec_s}" -lt "96" ]; do
199 _ec_s="0${_ec_s}"
200 done
201 fi
202 if [ "$__ECC_KEY_LEN" -eq "512" ]; then
203 while [ "${#_ec_r}" -lt "132" ]; do
204 _ec_r="0${_ec_r}"
205 done
206 while [ "${#_ec_s}" -lt "132" ]; do
207 _ec_s="0${_ec_s}"
208 done
209 fi
210 _debug3 "_ec_r" "$_ec_r"
211 _debug3 "_ec_s" "$_ec_s"
212 printf "%s" "$_ec_r$_ec_s" | _h2b | _base64
213 else
214 _err "Unknown key file format."
215 return 1
216 fi
217
218}
219
220#dummy function because proxmox-acme does not call inithttp
221_resethttp() {
222 :
223}
224
92b88a9e
WL
225# body url [needbase64] [POST|PUT|DELETE] [ContentType]
226_post() {
227 body="$1"
228 _post_url="$2"
229 needbase64="$3"
230 httpmethod="$4"
231 _postContentType="$5"
232
233 if [ -z "$httpmethod" ]; then
234 httpmethod="POST"
235 fi
92b88a9e 236
bb2e0864
WL
237 _CURL="curl -L --silent --dump-header $HTTP_HEADER -g "
238 if [ "$HTTPS_INSECURE" ]; then
239 _CURL="$_CURL --insecure "
240 fi
241 if [ "$httpmethod" = "HEAD" ]; then
242 _CURL="$_CURL -I "
243 fi
244 if [ "$needbase64" ]; then
245 if [ "$body" ]; then
246 if [ "$_postContentType" ]; then
247 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)"
92b88a9e 248 else
bb2e0864 249 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)"
92b88a9e
WL
250 fi
251 else
bb2e0864
WL
252 if [ "$_postContentType" ]; then
253 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url" | _base64)"
92b88a9e 254 else
bb2e0864 255 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url" | _base64)"
92b88a9e
WL
256 fi
257 fi
bb2e0864
WL
258 else
259 if [ "$body" ]; then
260 if [ "$_postContentType" ]; then
261 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")"
92b88a9e 262 else
bb2e0864 263 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")"
92b88a9e
WL
264 fi
265 else
bb2e0864
WL
266 if [ "$_postContentType" ]; then
267 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url")"
92b88a9e 268 else
bb2e0864 269 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url")"
92b88a9e
WL
270 fi
271 fi
92b88a9e 272 fi
bb2e0864
WL
273 _ret="$?"
274 if [ "$_ret" != "0" ]; then
275 _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret"
276 fi
92b88a9e
WL
277 printf "%s" "$response"
278 return $_ret
279}
280
281# url getheader timeout
282_get() {
92b88a9e
WL
283 url="$1"
284 onlyheader="$2"
285 t="$3"
92b88a9e 286
bb2e0864
WL
287 _CURL="curl -L --silent --dump-header $HTTP_HEADER -g "
288 if [ "$HTTPS_INSECURE" ]; then
289 _CURL="$_CURL --insecure "
290 fi
291 if [ "$t" ]; then
292 _CURL="$_CURL --connect-timeout $t"
293 fi
294 if [ "$onlyheader" ]; then
295 $_CURL -I --user-agent "USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url"
92b88a9e 296 else
bb2e0864
WL
297 $_CURL --user-agent "USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url"
298 fi
299 ret=$?
300 if [ "$ret" != "0" ]; then
301 _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $ret"
92b88a9e 302 fi
92b88a9e
WL
303 return $ret
304}
305
306_head_n() {
307 head -n "$1"
308}
309
310_tail_n() {
bb2e0864 311 tail -n "$1"
92b88a9e
WL
312}
313
314# stdin output hexstr splited by one space
315# input:"abc"
316# output: " 61 62 63"
317_hex_dump() {
bb2e0864 318 od -A n -v -t x1 | tr -s " " | sed 's/ $//' | tr -d "\r\t\n"
92b88a9e
WL
319}
320
321# stdin stdout
322_url_encode() {
323 _hex_str=$(_hex_dump)
92b88a9e
WL
324 for _hex_code in $_hex_str; do
325 #upper case
326 case "${_hex_code}" in
327 "41")
328 printf "%s" "A"
329 ;;
330 "42")
331 printf "%s" "B"
332 ;;
333 "43")
334 printf "%s" "C"
335 ;;
336 "44")
337 printf "%s" "D"
338 ;;
339 "45")
340 printf "%s" "E"
341 ;;
342 "46")
343 printf "%s" "F"
344 ;;
345 "47")
346 printf "%s" "G"
347 ;;
348 "48")
349 printf "%s" "H"
350 ;;
351 "49")
352 printf "%s" "I"
353 ;;
354 "4a")
355 printf "%s" "J"
356 ;;
357 "4b")
358 printf "%s" "K"
359 ;;
360 "4c")
361 printf "%s" "L"
362 ;;
363 "4d")
364 printf "%s" "M"
365 ;;
366 "4e")
367 printf "%s" "N"
368 ;;
369 "4f")
370 printf "%s" "O"
371 ;;
372 "50")
373 printf "%s" "P"
374 ;;
375 "51")
376 printf "%s" "Q"
377 ;;
378 "52")
379 printf "%s" "R"
380 ;;
381 "53")
382 printf "%s" "S"
383 ;;
384 "54")
385 printf "%s" "T"
386 ;;
387 "55")
388 printf "%s" "U"
389 ;;
390 "56")
391 printf "%s" "V"
392 ;;
393 "57")
394 printf "%s" "W"
395 ;;
396 "58")
397 printf "%s" "X"
398 ;;
399 "59")
400 printf "%s" "Y"
401 ;;
402 "5a")
403 printf "%s" "Z"
404 ;;
405
406 #lower case
407 "61")
408 printf "%s" "a"
409 ;;
410 "62")
411 printf "%s" "b"
412 ;;
413 "63")
414 printf "%s" "c"
415 ;;
416 "64")
417 printf "%s" "d"
418 ;;
419 "65")
420 printf "%s" "e"
421 ;;
422 "66")
423 printf "%s" "f"
424 ;;
425 "67")
426 printf "%s" "g"
427 ;;
428 "68")
429 printf "%s" "h"
430 ;;
431 "69")
432 printf "%s" "i"
433 ;;
434 "6a")
435 printf "%s" "j"
436 ;;
437 "6b")
438 printf "%s" "k"
439 ;;
440 "6c")
441 printf "%s" "l"
442 ;;
443 "6d")
444 printf "%s" "m"
445 ;;
446 "6e")
447 printf "%s" "n"
448 ;;
449 "6f")
450 printf "%s" "o"
451 ;;
452 "70")
453 printf "%s" "p"
454 ;;
455 "71")
456 printf "%s" "q"
457 ;;
458 "72")
459 printf "%s" "r"
460 ;;
461 "73")
462 printf "%s" "s"
463 ;;
464 "74")
465 printf "%s" "t"
466 ;;
467 "75")
468 printf "%s" "u"
469 ;;
470 "76")
471 printf "%s" "v"
472 ;;
473 "77")
474 printf "%s" "w"
475 ;;
476 "78")
477 printf "%s" "x"
478 ;;
479 "79")
480 printf "%s" "y"
481 ;;
482 "7a")
483 printf "%s" "z"
484 ;;
bb2e0864 485
92b88a9e
WL
486 #numbers
487 "30")
488 printf "%s" "0"
489 ;;
490 "31")
491 printf "%s" "1"
492 ;;
493 "32")
494 printf "%s" "2"
495 ;;
496 "33")
497 printf "%s" "3"
498 ;;
499 "34")
500 printf "%s" "4"
501 ;;
502 "35")
503 printf "%s" "5"
504 ;;
505 "36")
506 printf "%s" "6"
507 ;;
508 "37")
509 printf "%s" "7"
510 ;;
511 "38")
512 printf "%s" "8"
513 ;;
514 "39")
515 printf "%s" "9"
516 ;;
517 "2d")
518 printf "%s" "-"
519 ;;
520 "5f")
521 printf "%s" "_"
522 ;;
523 "2e")
524 printf "%s" "."
525 ;;
526 "7e")
527 printf "%s" "~"
528 ;;
bb2e0864 529
92b88a9e
WL
530 #other hex
531 *)
532 printf '%%%s' "$_hex_code"
533 ;;
534 esac
535 done
536}
537
538# Usage: hashalg secret_hex [outputhex]
539# Output binary hmac
540_hmac() {
541 alg="$1"
542 secret_hex="$2"
543 outputhex="$3"
544
92b88a9e
WL
545 if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then
546 if [ "$outputhex" ]; then
bb2e0864 547 (openssl dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" 2>/dev/null || openssl dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)") | cut -d = -f 2 | tr -d ' '
92b88a9e 548 else
bb2e0864 549 openssl dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary 2>/dev/null || openssl dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)" -binary
92b88a9e 550 fi
92b88a9e 551 fi
92b88a9e
WL
552}
553
554# domain
555_is_idn() {
556 _is_idn_d="$1"
92b88a9e 557 _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '*.,-_')
92b88a9e
WL
558 [ "$_idn_temp" ]
559}
560
561# aa.com
92b88a9e
WL
562_idn() {
563 __idn_d="$1"
564 if ! _is_idn "$__idn_d"; then
565 printf "%s" "$__idn_d"
566 return 0
567 fi
568
569 if _exists idn; then
bb2e0864 570 idn "$__idn_d" | tr -d "\r\n"
92b88a9e
WL
571 else
572 _err "Please install idn to process IDN names."
573 fi
574}
575
576_normalizeJson() {
577 sed "s/\" *: *\([\"{\[]\)/\":\1/g" | sed "s/^ *\([^ ]\)/\1/" | tr -d "\r\n"
578}
579
580# options file
581_sed_i() {
bb2e0864 582 sed -i "$1" "$2"
92b88a9e
WL
583}
584
585# sleep sec
586_sleep() {
bb2e0864 587 sleep "$1"
92b88a9e
WL
588}
589
590_stat() {
bb2e0864 591 stat -c '%U:%G' "$1" 2>/dev/null
92b88a9e
WL
592}
593
92b88a9e
WL
594_time() {
595 date -u "+%s"
596}
597
598_utc_date() {
599 date -u "+%Y-%m-%d %H:%M:%S"
600}
601
602# stubbed/aliased:
603__green() {
92b88a9e
WL
604 printf -- "%b" "$1"
605}
606
607__red() {
92b88a9e
WL
608 printf -- "%b" "$1"
609}
610
611_log() {
b0d717c7 612 return 0
92b88a9e
WL
613}
614
615_info() {
bb2e0864
WL
616 printf -- "%s" "[$(date)] " >&1
617 echo "$1"
92b88a9e
WL
618}
619
620_err() {
bb2e0864 621 printf -- "%s" "[$(date)] " >&2
92b88a9e
WL
622 if [ -z "$2" ]; then
623 __red "$1" >&2
624 else
625 __red "$1='$2'" >&2
626 fi
627 printf "\n" >&2
628 return 1
629}
630
631# key
632_readaccountconf() {
1a8ba4f0 633 echo "${!1}"
92b88a9e
WL
634}
635
636# key
637_readaccountconf_mutable() {
bb2e0864
WL
638 _readaccountconf "$1"
639}
640
641# no-ops:
642_clearaccountconf() {
b0d717c7 643 return 0
bb2e0864
WL
644}
645
646_cleardomainconf() {
b0d717c7 647 return 0
bb2e0864
WL
648}
649
650_debug() {
54fd0088
WL
651 if [[ $DEBUG -eq 0 ]]; then
652 return
653 fi
654 printf -- "%s" "[$(date)] " >&1
655 echo "$1 $2"
bb2e0864
WL
656}
657
658_debug2() {
54fd0088 659 _debug $1 $2
bb2e0864
WL
660}
661
662_debug3() {
54fd0088 663 _debug $1 $2
bb2e0864
WL
664}
665
666_secure_debug() {
54fd0088 667 _debug $1 $2
92b88a9e 668}
bb2e0864
WL
669
670_secure_debug2() {
54fd0088 671 _debug $1 $2
bb2e0864
WL
672}
673
674_secure_debug3() {
54fd0088 675 _debug $1 $2
bb2e0864
WL
676}
677
678_saveaccountconf() {
b0d717c7 679 return 0
bb2e0864
WL
680}
681
682_saveaccountconf_mutable() {
b0d717c7 683 return 0
bb2e0864
WL
684}
685
686_save_conf() {
b0d717c7 687 return 0
bb2e0864
WL
688}
689
690_savedomainconf() {
b0d717c7 691 return 0
bb2e0864
WL
692}
693
694_source_plugin_config() {
b0d717c7 695 return 0
bb2e0864
WL
696}
697
216d4f1d
WL
698# Proxmox implementation to inject the DNSAPI variables
699_load_plugin_config() {
13bc64ea
FG
700 while IFS= read -r line; do
701 ADDR=(${line/=/ })
216d4f1d
WL
702 key="${ADDR[0]}"
703 value="${ADDR[1]}"
704
216d4f1d 705 # acme.sh uses eval insted of export
13bc64ea
FG
706 if [ -n "$key" ]; then
707 export "$key"="$value"
708 fi
216d4f1d
WL
709 done
710}
ece42f2f
WL
711
712# call setup and teardown direct
713# the parameter must be set in the correct order
714# $1 <String> DNS Plugin name
715# $2 <String> Fully Qualified Domain Name
716# $3 <String> value for TXT record
717# $4 <String> DNS plugin auth and config parameter separated by ","
54fd0088 718# $5 <Integer> 0 is off, and the default all others are on.
ece42f2f
WL
719
720setup() {
721 dns_plugin="dns_$1"
722 dns_plugin_path="${DNS_PLUGIN_PATH}/${dns_plugin}.sh"
723 fqdn="_acme-challenge.$2"
13bc64ea
FG
724 DEBUG=$3
725 IFS= read -r txtvalue
ece42f2f
WL
726 plugin_conf_string=$4
727
13bc64ea 728 _load_plugin_config
ece42f2f
WL
729
730 if ! . "$dns_plugin_path"; then
731 _err "Load file $dns_plugin error."
732 return 1
733 fi
734
735 addcommand="${dns_plugin}_add"
736 if ! _exists "$addcommand"; then
737 _err "It seems that your api file is not correct, it must have a function named: $addcommand"
738 return 1
739 fi
740
741 if ! $addcommand "$fqdn" "$txtvalue"; then
742 _err "Error add txt for domain:$fulldomain"
743 return 1
744 fi
745}
746
747teardown() {
748 dns_plugin="dns_$1"
749 dns_plugin_path="${DNS_PLUGIN_PATH}/${dns_plugin}.sh"
750 fqdn="_acme-challenge.$2"
13bc64ea
FG
751 DEBUG=$3
752 IFS= read -r txtvalue
ece42f2f 753
13bc64ea 754 _load_plugin_config
ece42f2f
WL
755
756 if ! . "$dns_plugin_path"; then
757 _err "Load file $dns_plugin error."
758 return 1
759 fi
760
761 rmcommand="${dns_plugin}_rm"
762 if ! _exists "$rmcommand"; then
763 _err "It seems that your api file is not correct, it must have a function named: $rmcommand"
764 return 1
765 fi
766
767 if ! $rmcommand "$fqdn" "$txtvalue"; then
768 _err "Error add txt for domain:$fulldomain"
769 return 1
770 fi
771}
772
773"$@"