From 4dd26c445b35b3e562ba22816710c2572764b637 Mon Sep 17 00:00:00 2001 From: caelebfi Date: Wed, 27 Oct 2021 14:28:05 +0200 Subject: [PATCH] Initial commit --- .etckeeper | 1312 +++ .fstab | 8 + .gitignore | 54 + .java/.systemPrefs/.system.lock | 0 .java/.systemPrefs/.systemRootModFile | 0 ImageMagick-6/coder.xml | 23 + ImageMagick-6/colors.xml | 28 + ImageMagick-6/delegates.xml | 122 + ImageMagick-6/log.xml | 80 + ImageMagick-6/magic.xml | 23 + ImageMagick-6/mime.xml | 1145 +++ ImageMagick-6/policy.xml | 96 + ImageMagick-6/quantization-table.xml | 68 + ImageMagick-6/thresholds.xml | 336 + ImageMagick-6/type-apple.xml | 1367 +++ ImageMagick-6/type-dejavu.xml | 58 + ImageMagick-6/type-ghostscript.xml | 50 + ImageMagick-6/type-urw-base35.xml | 50 + ImageMagick-6/type-windows.xml | 105 + ImageMagick-6/type.xml | 17 + NetworkManager/dispatcher.d/ntp | 12 + X11/Xreset | 34 + X11/Xreset.d/README | 4 + X11/Xresources/x11-common | 10 + X11/Xsession | 113 + X11/Xsession.d/20x11-common_process-args | 70 + X11/Xsession.d/30x11-common_xresources | 26 + X11/Xsession.d/35x11-common_xhost-local | 10 + X11/Xsession.d/40x11-common_xsessionrc | 6 + X11/Xsession.d/50x11-common_determine-startup | 47 + X11/Xsession.d/90gpg-agent | 22 + X11/Xsession.d/90x11-common_ssh-agent | 24 + X11/Xsession.d/99x11-common_start | 7 + X11/Xsession.options | 9 + X11/rgb.txt | 754 ++ adduser.conf | 85 + aliases | 13 + alternatives/ABORT.7.gz | 1 + alternatives/ALTER_AGGREGATE.7.gz | 1 + alternatives/ALTER_COLLATION.7.gz | 1 + alternatives/ALTER_CONVERSION.7.gz | 1 + alternatives/ALTER_DATABASE.7.gz | 1 + alternatives/ALTER_DEFAULT_PRIVILEGES.7.gz | 1 + alternatives/ALTER_DOMAIN.7.gz | 1 + alternatives/ALTER_EVENT_TRIGGER.7.gz | 1 + alternatives/ALTER_EXTENSION.7.gz | 1 + alternatives/ALTER_FOREIGN_DATA_WRAPPER.7.gz | 1 + alternatives/ALTER_FOREIGN_TABLE.7.gz | 1 + alternatives/ALTER_FUNCTION.7.gz | 1 + alternatives/ALTER_GROUP.7.gz | 1 + alternatives/ALTER_INDEX.7.gz | 1 + alternatives/ALTER_LANGUAGE.7.gz | 1 + alternatives/ALTER_LARGE_OBJECT.7.gz | 1 + alternatives/ALTER_MATERIALIZED_VIEW.7.gz | 1 + alternatives/ALTER_OPERATOR.7.gz | 1 + alternatives/ALTER_OPERATOR_CLASS.7.gz | 1 + alternatives/ALTER_OPERATOR_FAMILY.7.gz | 1 + alternatives/ALTER_POLICY.7.gz | 1 + alternatives/ALTER_PROCEDURE.7.gz | 1 + alternatives/ALTER_PUBLICATION.7.gz | 1 + alternatives/ALTER_ROLE.7.gz | 1 + alternatives/ALTER_ROUTINE.7.gz | 1 + alternatives/ALTER_RULE.7.gz | 1 + alternatives/ALTER_SCHEMA.7.gz | 1 + alternatives/ALTER_SEQUENCE.7.gz | 1 + alternatives/ALTER_SERVER.7.gz | 1 + alternatives/ALTER_STATISTICS.7.gz | 1 + alternatives/ALTER_SUBSCRIPTION.7.gz | 1 + alternatives/ALTER_SYSTEM.7.gz | 1 + alternatives/ALTER_TABLE.7.gz | 1 + alternatives/ALTER_TABLESPACE.7.gz | 1 + .../ALTER_TEXT_SEARCH_CONFIGURATION.7.gz | 1 + .../ALTER_TEXT_SEARCH_DICTIONARY.7.gz | 1 + alternatives/ALTER_TEXT_SEARCH_PARSER.7.gz | 1 + alternatives/ALTER_TEXT_SEARCH_TEMPLATE.7.gz | 1 + alternatives/ALTER_TRIGGER.7.gz | 1 + alternatives/ALTER_TYPE.7.gz | 1 + alternatives/ALTER_USER.7.gz | 1 + alternatives/ALTER_USER_MAPPING.7.gz | 1 + alternatives/ALTER_VIEW.7.gz | 1 + alternatives/ANALYZE.7.gz | 1 + alternatives/BEGIN.7.gz | 1 + alternatives/CALL.7.gz | 1 + alternatives/CHECKPOINT.7.gz | 1 + alternatives/CLOSE.7.gz | 1 + alternatives/CLUSTER.7.gz | 1 + alternatives/COMMENT.7.gz | 1 + alternatives/COMMIT.7.gz | 1 + alternatives/COMMIT_PREPARED.7.gz | 1 + alternatives/COPY.7.gz | 1 + alternatives/CREATE_ACCESS_METHOD.7.gz | 1 + alternatives/CREATE_AGGREGATE.7.gz | 1 + alternatives/CREATE_CAST.7.gz | 1 + alternatives/CREATE_COLLATION.7.gz | 1 + alternatives/CREATE_CONVERSION.7.gz | 1 + alternatives/CREATE_DATABASE.7.gz | 1 + alternatives/CREATE_DOMAIN.7.gz | 1 + alternatives/CREATE_EVENT_TRIGGER.7.gz | 1 + alternatives/CREATE_EXTENSION.7.gz | 1 + alternatives/CREATE_FOREIGN_DATA_WRAPPER.7.gz | 1 + alternatives/CREATE_FOREIGN_TABLE.7.gz | 1 + alternatives/CREATE_FUNCTION.7.gz | 1 + alternatives/CREATE_GROUP.7.gz | 1 + alternatives/CREATE_INDEX.7.gz | 1 + alternatives/CREATE_LANGUAGE.7.gz | 1 + alternatives/CREATE_MATERIALIZED_VIEW.7.gz | 1 + alternatives/CREATE_OPERATOR.7.gz | 1 + alternatives/CREATE_OPERATOR_CLASS.7.gz | 1 + alternatives/CREATE_OPERATOR_FAMILY.7.gz | 1 + alternatives/CREATE_POLICY.7.gz | 1 + alternatives/CREATE_PROCEDURE.7.gz | 1 + alternatives/CREATE_PUBLICATION.7.gz | 1 + alternatives/CREATE_ROLE.7.gz | 1 + alternatives/CREATE_RULE.7.gz | 1 + alternatives/CREATE_SCHEMA.7.gz | 1 + alternatives/CREATE_SEQUENCE.7.gz | 1 + alternatives/CREATE_SERVER.7.gz | 1 + alternatives/CREATE_STATISTICS.7.gz | 1 + alternatives/CREATE_SUBSCRIPTION.7.gz | 1 + alternatives/CREATE_TABLE.7.gz | 1 + alternatives/CREATE_TABLESPACE.7.gz | 1 + alternatives/CREATE_TABLE_AS.7.gz | 1 + .../CREATE_TEXT_SEARCH_CONFIGURATION.7.gz | 1 + .../CREATE_TEXT_SEARCH_DICTIONARY.7.gz | 1 + alternatives/CREATE_TEXT_SEARCH_PARSER.7.gz | 1 + alternatives/CREATE_TEXT_SEARCH_TEMPLATE.7.gz | 1 + alternatives/CREATE_TRANSFORM.7.gz | 1 + alternatives/CREATE_TRIGGER.7.gz | 1 + alternatives/CREATE_TYPE.7.gz | 1 + alternatives/CREATE_USER.7.gz | 1 + alternatives/CREATE_USER_MAPPING.7.gz | 1 + alternatives/CREATE_VIEW.7.gz | 1 + alternatives/DEALLOCATE.7.gz | 1 + alternatives/DECLARE.7.gz | 1 + alternatives/DELETE.7.gz | 1 + alternatives/DISCARD.7.gz | 1 + alternatives/DO.7.gz | 1 + alternatives/DROP_ACCESS_METHOD.7.gz | 1 + alternatives/DROP_AGGREGATE.7.gz | 1 + alternatives/DROP_CAST.7.gz | 1 + alternatives/DROP_COLLATION.7.gz | 1 + alternatives/DROP_CONVERSION.7.gz | 1 + alternatives/DROP_DATABASE.7.gz | 1 + alternatives/DROP_DOMAIN.7.gz | 1 + alternatives/DROP_EVENT_TRIGGER.7.gz | 1 + alternatives/DROP_EXTENSION.7.gz | 1 + alternatives/DROP_FOREIGN_DATA_WRAPPER.7.gz | 1 + alternatives/DROP_FOREIGN_TABLE.7.gz | 1 + alternatives/DROP_FUNCTION.7.gz | 1 + alternatives/DROP_GROUP.7.gz | 1 + alternatives/DROP_INDEX.7.gz | 1 + alternatives/DROP_LANGUAGE.7.gz | 1 + alternatives/DROP_MATERIALIZED_VIEW.7.gz | 1 + alternatives/DROP_OPERATOR.7.gz | 1 + alternatives/DROP_OPERATOR_CLASS.7.gz | 1 + alternatives/DROP_OPERATOR_FAMILY.7.gz | 1 + alternatives/DROP_OWNED.7.gz | 1 + alternatives/DROP_POLICY.7.gz | 1 + alternatives/DROP_PROCEDURE.7.gz | 1 + alternatives/DROP_PUBLICATION.7.gz | 1 + alternatives/DROP_ROLE.7.gz | 1 + alternatives/DROP_ROUTINE.7.gz | 1 + alternatives/DROP_RULE.7.gz | 1 + alternatives/DROP_SCHEMA.7.gz | 1 + alternatives/DROP_SEQUENCE.7.gz | 1 + alternatives/DROP_SERVER.7.gz | 1 + alternatives/DROP_STATISTICS.7.gz | 1 + alternatives/DROP_SUBSCRIPTION.7.gz | 1 + alternatives/DROP_TABLE.7.gz | 1 + alternatives/DROP_TABLESPACE.7.gz | 1 + .../DROP_TEXT_SEARCH_CONFIGURATION.7.gz | 1 + alternatives/DROP_TEXT_SEARCH_DICTIONARY.7.gz | 1 + alternatives/DROP_TEXT_SEARCH_PARSER.7.gz | 1 + alternatives/DROP_TEXT_SEARCH_TEMPLATE.7.gz | 1 + alternatives/DROP_TRANSFORM.7.gz | 1 + alternatives/DROP_TRIGGER.7.gz | 1 + alternatives/DROP_TYPE.7.gz | 1 + alternatives/DROP_USER.7.gz | 1 + alternatives/DROP_USER_MAPPING.7.gz | 1 + alternatives/DROP_VIEW.7.gz | 1 + alternatives/END.7.gz | 1 + alternatives/EXECUTE.7.gz | 1 + alternatives/EXPLAIN.7.gz | 1 + alternatives/FETCH.7.gz | 1 + alternatives/GRANT.7.gz | 1 + alternatives/IMPORT_FOREIGN_SCHEMA.7.gz | 1 + alternatives/INSERT.7.gz | 1 + alternatives/LISTEN.7.gz | 1 + alternatives/LOAD.7.gz | 1 + alternatives/LOCK.7.gz | 1 + alternatives/MOVE.7.gz | 1 + alternatives/NOTIFY.7.gz | 1 + alternatives/PREPARE.7.gz | 1 + alternatives/PREPARE_TRANSACTION.7.gz | 1 + alternatives/README | 2 + alternatives/REASSIGN_OWNED.7.gz | 1 + alternatives/REFRESH_MATERIALIZED_VIEW.7.gz | 1 + alternatives/REINDEX.7.gz | 1 + alternatives/RELEASE_SAVEPOINT.7.gz | 1 + alternatives/RESET.7.gz | 1 + alternatives/REVOKE.7.gz | 1 + alternatives/ROLLBACK.7.gz | 1 + alternatives/ROLLBACK_PREPARED.7.gz | 1 + alternatives/ROLLBACK_TO_SAVEPOINT.7.gz | 1 + alternatives/SAVEPOINT.7.gz | 1 + alternatives/SECURITY_LABEL.7.gz | 1 + alternatives/SELECT.7.gz | 1 + alternatives/SELECT_INTO.7.gz | 1 + alternatives/SET.7.gz | 1 + alternatives/SET_CONSTRAINTS.7.gz | 1 + alternatives/SET_ROLE.7.gz | 1 + alternatives/SET_SESSION_AUTHORIZATION.7.gz | 1 + alternatives/SET_TRANSACTION.7.gz | 1 + alternatives/SHOW.7.gz | 1 + alternatives/START_TRANSACTION.7.gz | 1 + alternatives/TABLE.7.gz | 1 + alternatives/TRUNCATE.7.gz | 1 + alternatives/UNLISTEN.7.gz | 1 + alternatives/UPDATE.7.gz | 1 + alternatives/VACUUM.7.gz | 1 + alternatives/VALUES.7.gz | 1 + alternatives/WITH.7.gz | 1 + alternatives/arptables | 1 + alternatives/arptables-restore | 1 + alternatives/arptables-save | 1 + alternatives/awk | 1 + alternatives/awk.1.gz | 1 + alternatives/builtins.7.gz | 1 + alternatives/c++ | 1 + alternatives/c89 | 1 + alternatives/c89.1.gz | 1 + alternatives/c99 | 1 + alternatives/c99.1.gz | 1 + alternatives/cc | 1 + alternatives/clusterdb.1.gz | 1 + alternatives/cpp | 1 + alternatives/createdb.1.gz | 1 + alternatives/createuser.1.gz | 1 + alternatives/dhcpcd | 1 + alternatives/dhcpcd.8.gz | 1 + alternatives/dotlock | 1 + alternatives/dotlock.1.gz | 1 + alternatives/dropdb.1.gz | 1 + alternatives/dropuser.1.gz | 1 + alternatives/ebtables | 1 + alternatives/ebtables-restore | 1 + alternatives/ebtables-save | 1 + alternatives/editor | 1 + alternatives/editor.1.gz | 1 + alternatives/ex | 1 + alternatives/ex.1.gz | 1 + alternatives/ex.da.1.gz | 1 + alternatives/ex.de.1.gz | 1 + alternatives/ex.fr.1.gz | 1 + alternatives/ex.it.1.gz | 1 + alternatives/ex.ja.1.gz | 1 + alternatives/ex.pl.1.gz | 1 + alternatives/ex.ru.1.gz | 1 + alternatives/faked.1.gz | 1 + alternatives/faked.es.1.gz | 1 + alternatives/faked.fr.1.gz | 1 + alternatives/faked.sv.1.gz | 1 + alternatives/fakeroot | 1 + alternatives/fakeroot.1.gz | 1 + alternatives/fakeroot.es.1.gz | 1 + alternatives/fakeroot.fr.1.gz | 1 + alternatives/fakeroot.sv.1.gz | 1 + alternatives/frm | 1 + alternatives/frm.1.gz | 1 + alternatives/from | 1 + alternatives/from.1.gz | 1 + alternatives/idmap-plugin | 1 + alternatives/idmap-plugin.8.gz | 1 + alternatives/infobrowser | 1 + alternatives/infobrowser.1.gz | 1 + alternatives/ip6tables | 1 + alternatives/ip6tables-restore | 1 + alternatives/ip6tables-save | 1 + alternatives/iptables | 1 + alternatives/iptables-restore | 1 + alternatives/iptables-save | 1 + alternatives/java | 1 + alternatives/java.1.gz | 1 + alternatives/jexec | 1 + alternatives/jexec-binfmt | 1 + alternatives/jjs | 1 + alternatives/jjs.1.gz | 1 + alternatives/keytool | 1 + alternatives/keytool.1.gz | 1 + alternatives/lft | 1 + alternatives/lft.1.gz | 1 + alternatives/lua-compiler | 1 + alternatives/lua-compiler-manual | 1 + alternatives/lua-interpreter | 1 + alternatives/lua-manual | 1 + alternatives/lzcat | 1 + alternatives/lzcat.1.gz | 1 + alternatives/lzcmp | 1 + alternatives/lzcmp.1.gz | 1 + alternatives/lzdiff | 1 + alternatives/lzdiff.1.gz | 1 + alternatives/lzegrep | 1 + alternatives/lzegrep.1.gz | 1 + alternatives/lzfgrep | 1 + alternatives/lzfgrep.1.gz | 1 + alternatives/lzgrep | 1 + alternatives/lzgrep.1.gz | 1 + alternatives/lzless | 1 + alternatives/lzless.1.gz | 1 + alternatives/lzma | 1 + alternatives/lzma.1.gz | 1 + alternatives/lzmore | 1 + alternatives/lzmore.1.gz | 1 + alternatives/mail | 1 + alternatives/mail.1.gz | 1 + alternatives/mailx | 1 + alternatives/mailx.1.gz | 1 + alternatives/messages | 1 + alternatives/messages.1.gz | 1 + alternatives/movemail | 1 + alternatives/movemail.1.gz | 1 + alternatives/mt | 1 + alternatives/mt.1.gz | 1 + alternatives/my.cnf | 1 + alternatives/nawk | 1 + alternatives/nawk.1.gz | 1 + alternatives/nc | 1 + alternatives/nc.1.gz | 1 + alternatives/netcat | 1 + alternatives/netcat.1.gz | 1 + alternatives/nodejs | 1 + alternatives/nodejs.1.gz | 1 + alternatives/pack200 | 1 + alternatives/pack200.1.gz | 1 + alternatives/pager | 1 + alternatives/pager.1.gz | 1 + alternatives/pg_basebackup.1.gz | 1 + alternatives/pg_dump.1.gz | 1 + alternatives/pg_dumpall.1.gz | 1 + alternatives/pg_isready.1.gz | 1 + alternatives/pg_receivewal.1.gz | 1 + alternatives/pg_recvlogical.1.gz | 1 + alternatives/pg_restore.1.gz | 1 + alternatives/phar | 1 + alternatives/phar.1.gz | 1 + alternatives/phar.phar | 1 + alternatives/phar.phar.1.gz | 1 + alternatives/php | 1 + alternatives/php-cgi | 1 + alternatives/php-cgi-bin | 1 + alternatives/php-cgi.1.gz | 1 + alternatives/php.1.gz | 1 + alternatives/pico | 1 + alternatives/pico.1.gz | 1 + alternatives/pinentry | 1 + alternatives/pinentry.1.gz | 1 + alternatives/psql.1.gz | 1 + alternatives/rcp | 1 + alternatives/rcp.1.gz | 1 + alternatives/readmsg | 1 + alternatives/readmsg.1.gz | 1 + alternatives/reindexdb.1.gz | 1 + alternatives/rlogin | 1 + alternatives/rlogin.1.gz | 1 + alternatives/rmid | 1 + alternatives/rmid.1.gz | 1 + alternatives/rmiregistry | 1 + alternatives/rmiregistry.1.gz | 1 + alternatives/rmt | 1 + alternatives/rmt.8.gz | 1 + alternatives/rsh | 1 + alternatives/rsh.1.gz | 1 + alternatives/rview | 1 + alternatives/tcptraceroute | 1 + alternatives/tcptraceroute.8.gz | 1 + alternatives/telnet | 1 + alternatives/telnet.1.gz | 1 + alternatives/traceproto | 1 + alternatives/traceproto.1.gz | 1 + alternatives/traceroute | 1 + alternatives/traceroute.1.gz | 1 + alternatives/traceroute.sbin | 1 + alternatives/traceroute6 | 1 + alternatives/traceroute6.1.gz | 1 + alternatives/unlzma | 1 + alternatives/unlzma.1.gz | 1 + alternatives/unpack200 | 1 + alternatives/unpack200.1.gz | 1 + alternatives/vacuumdb.1.gz | 1 + alternatives/vi | 1 + alternatives/vi.1.gz | 1 + alternatives/vi.da.1.gz | 1 + alternatives/vi.de.1.gz | 1 + alternatives/vi.fr.1.gz | 1 + alternatives/vi.it.1.gz | 1 + alternatives/vi.ja.1.gz | 1 + alternatives/vi.pl.1.gz | 1 + alternatives/vi.ru.1.gz | 1 + alternatives/view | 1 + alternatives/view.1.gz | 1 + alternatives/view.da.1.gz | 1 + alternatives/view.de.1.gz | 1 + alternatives/view.fr.1.gz | 1 + alternatives/view.it.1.gz | 1 + alternatives/view.ja.1.gz | 1 + alternatives/view.pl.1.gz | 1 + alternatives/view.ru.1.gz | 1 + alternatives/w | 1 + alternatives/w.1.gz | 1 + alternatives/write | 1 + alternatives/write.1.gz | 1 + apparmor.d/local/usr.bin.man | 0 apparmor.d/local/usr.sbin.ntpd | 0 apparmor.d/tunables/ntpd | 15 + apparmor.d/usr.bin.man | 101 + apparmor.d/usr.sbin.ntpd | 89 + .../network-interface-security/usr.sbin.ntpd | 1 + apt/apt.conf.d/01autoremove | 59 + apt/apt.conf.d/01autoremove-kernels | 56 + apt/apt.conf.d/01autoremove-postgresql | 17 + apt/apt.conf.d/05etckeeper | 5 + apt/apt.conf.d/15update-stamp | 2 + apt/apt.conf.d/20listchanges | 3 + apt/apt.conf.d/50raspi | 5 + apt/apt.conf.d/70debconf | 3 + apt/listchanges.conf | 10 + apt/preferences | 0 apt/sources.list | 3 + apt/sources.list.d/docker.list | 1 + apt/sources.list.d/mosquitto-buster.list | 1 + apt/sources.list.d/nginx.list | 3 + apt/sources.list.d/nodesource.list | 2 + apt/sources.list.d/raspi.list | 3 + apt/sources.list.d/vscode.list | 1 + apt/trusted.gpg | Bin 0 -> 15380 bytes apt/trusted.gpg.d/microsoft.gpg | 0 avahi/avahi-daemon.conf | 68 + avahi/hosts | 27 + bash.bashrc | 58 + bash_completion | 1 + bash_completion.d/git-prompt | 11 + bindresvport.blacklist | 15 + bluetooth/input.conf | 26 + bluetooth/main.conf | 108 + bluetooth/network.conf | 6 + ca-certificates.conf | 152 + ca-certificates/update.d/jks-keystore | 89 + calendar/default | 15 + check_mk/cmk-update-agent.cfg | 31 + check_mk/docker.cfg | 7 + check_mk/mk_inventory.cfg | 5 + cifs-utils/idmap-plugin | 1 + cmk-update-agent.state | 1 + console-setup/cached_Lat15-Fixed16.psf.gz | Bin 0 -> 2429 bytes console-setup/cached_UTF-8_del.kmap.gz | Bin 0 -> 4452 bytes console-setup/cached_setup_font.sh | 19 + console-setup/cached_setup_keyboard.sh | 13 + console-setup/cached_setup_terminal.sh | 5 + console-setup/compose.ARMSCII-8.inc | 1 + console-setup/compose.CP1251.inc | 1 + console-setup/compose.CP1255.inc | 1 + console-setup/compose.CP1256.inc | 1 + console-setup/compose.GEORGIAN-ACADEMY.inc | 1 + console-setup/compose.GEORGIAN-PS.inc | 1 + console-setup/compose.IBM1133.inc | 1 + console-setup/compose.ISIRI-3342.inc | 1 + console-setup/compose.ISO-8859-1.inc | 155 + console-setup/compose.ISO-8859-10.inc | 1 + console-setup/compose.ISO-8859-11.inc | 1 + console-setup/compose.ISO-8859-13.inc | 161 + console-setup/compose.ISO-8859-14.inc | 130 + console-setup/compose.ISO-8859-15.inc | 153 + console-setup/compose.ISO-8859-16.inc | 1 + console-setup/compose.ISO-8859-2.inc | 124 + console-setup/compose.ISO-8859-3.inc | 146 + console-setup/compose.ISO-8859-4.inc | 121 + console-setup/compose.ISO-8859-5.inc | 1 + console-setup/compose.ISO-8859-6.inc | 1 + console-setup/compose.ISO-8859-7.inc | 52 + console-setup/compose.ISO-8859-8.inc | 1 + console-setup/compose.ISO-8859-9.inc | 156 + console-setup/compose.KOI8-R.inc | 1 + console-setup/compose.KOI8-U.inc | 1 + console-setup/compose.TIS-620.inc | 1 + console-setup/compose.VISCII.inc | 1 + console-setup/remap.inc | 32 + containerd/config.toml | 31 + cron.d/.placeholder | 2 + cron.d/php | 14 + cron.d/sysstat | 9 + cron.daily/.placeholder | 2 + cron.daily/apt-compat | 55 + cron.daily/bsdmainutils | 16 + cron.daily/dpkg | 36 + cron.daily/etckeeper | 8 + cron.daily/exim4-base | 105 + cron.daily/logrotate | 11 + cron.daily/man-db | 43 + cron.daily/ntp | 39 + cron.daily/passwd | 9 + cron.daily/sysstat | 18 + cron.hourly/.placeholder | 2 + cron.hourly/fake-hwclock | 8 + cron.monthly/.placeholder | 2 + cron.weekly/.placeholder | 2 + cron.weekly/man-db | 34 + crontab | 25 + cruft/filters-unex/etckeeper | 13 + dbus-1/system.d/avahi-dbus.conf | 32 + dbus-1/system.d/bluetooth.conf | 43 + dbus-1/system.d/wpa_supplicant.conf | 33 + debconf.conf | 83 + debian_version | 1 + default/avahi-daemon | 4 + default/bluetooth | 20 + default/bsdmainutils | 4 + default/cacerts | 10 + default/console-setup | 16 + default/crda | 11 + default/cron | 28 + default/dbus | 7 + default/docker | 20 + default/exim4 | 24 + default/fake-hwclock | 2 + default/hwclock | 19 + default/keyboard | 10 + default/locale | 2 + default/netfilter-persistent | 4 + default/networking | 31 + default/nfs-common | 19 + default/nginx | 10 + default/nss | 37 + default/ntp | 1 + default/raspberrypi-kernel | 11 + default/redis-server | 7 + default/rng-tools | 17 + default/rpi-eeprom-update | 1 + default/rsync | 47 + default/rsyslog | 4 + default/snmpd | 12 + default/ssh | 5 + default/sysstat | 10 + default/tftpd-hpa | 6 + default/triggerhappy | 17 + default/useradd | 37 + default/xinetd | 12 + deluser.conf | 20 + dhcp/debug | 38 + dhcp/dhclient-enter-hooks.d/debug | 1 + dhcp/dhclient-enter-hooks.d/resolvconf | 81 + dhcp/dhclient-exit-hooks.d/debug | 1 + dhcp/dhclient-exit-hooks.d/ntp | 64 + .../rfc3442-classless-routes | 78 + dhcp/dhclient-exit-hooks.d/timesyncd | 42 + dhcp/dhclient.conf | 54 + dhcpcd.conf | 63 + dkms/framework.conf | 28 + dkms/template-dkms-mkbmdeb/Makefile | 18 + .../debian/README.Debian | 5 + dkms/template-dkms-mkbmdeb/debian/changelog | 6 + dkms/template-dkms-mkbmdeb/debian/compat | 1 + dkms/template-dkms-mkbmdeb/debian/control | 14 + dkms/template-dkms-mkbmdeb/debian/copyright | 2 + dkms/template-dkms-mkbmdeb/debian/rules | 58 + dkms/template-dkms-mkdeb/Makefile | 28 + dkms/template-dkms-mkdeb/debian/README.Debian | 5 + dkms/template-dkms-mkdeb/debian/changelog | 6 + dkms/template-dkms-mkdeb/debian/compat | 1 + dkms/template-dkms-mkdeb/debian/control | 11 + dkms/template-dkms-mkdeb/debian/copyright | 2 + dkms/template-dkms-mkdeb/debian/dirs | 1 + dkms/template-dkms-mkdeb/debian/postinst | 49 + dkms/template-dkms-mkdeb/debian/prerm | 28 + dkms/template-dkms-mkdeb/debian/rules | 54 + docker/daemon.json | 3 + docker/key.json | 1 + dphys-swapfile | 26 + dpkg/dpkg.cfg | 13 + dpkg/dpkg.cfg.d/pkg-config-hook-config | 1 + dpkg/origins/debian | 3 + dpkg/origins/default | 1 + dpkg/origins/raspbian | 4 + dpkg/shlibs.default | 7 + dpkg/shlibs.override | 8 + email-addresses | 9 + environment | 0 etckeeper/commit.d/10vcs-test | 17 + etckeeper/commit.d/20store-metadata | 1 + etckeeper/commit.d/30bzr-add | 8 + etckeeper/commit.d/30darcs-add | 14 + etckeeper/commit.d/30git-add | 8 + etckeeper/commit.d/30hg-addremove | 8 + etckeeper/commit.d/50vcs-commit | 135 + etckeeper/commit.d/99push | 14 + etckeeper/commit.d/README | 3 + etckeeper/daily | 17 + etckeeper/etckeeper.conf | 45 + etckeeper/init.d/10restore-metadata | 14 + etckeeper/init.d/20restore-etckeeper | 22 + etckeeper/init.d/40vcs-init | 17 + etckeeper/init.d/50vcs-ignore | 4 + etckeeper/init.d/50vcs-perm | 12 + etckeeper/init.d/50vcs-pre-commit-hook | 49 + etckeeper/init.d/60darcs-deleted-symlinks | 48 + etckeeper/init.d/70vcs-add | 27 + etckeeper/init.d/README | 13 + etckeeper/list-installed.d/50list-installed | 27 + etckeeper/post-install.d/50vcs-commit | 43 + etckeeper/post-install.d/README | 2 + etckeeper/pre-commit.d/20warn-problem-files | 30 + etckeeper/pre-commit.d/30store-metadata | 175 + etckeeper/pre-commit.d/README | 2 + etckeeper/pre-install.d/10packagelist | 5 + etckeeper/pre-install.d/50uncommitted-changes | 15 + etckeeper/pre-install.d/README | 3 + etckeeper/unclean.d/50test | 12 + etckeeper/unclean.d/README | 2 + etckeeper/uninit.d/01prompt | 20 + etckeeper/uninit.d/50remove-metadata | 6 + etckeeper/uninit.d/50vcs-uninit | 54 + etckeeper/uninit.d/README | 2 + etckeeper/update-ignore.d/01update-ignore | 209 + etckeeper/update-ignore.d/README | 2 + etckeeper/vcs.d/50vcs-cmd | 11 + exim4/conf.d/acl/00_exim4-config_header | 8 + .../acl/20_exim4-config_local_deny_exceptions | 49 + exim4/conf.d/acl/30_exim4-config_check_mail | 11 + exim4/conf.d/acl/30_exim4-config_check_rcpt | 375 + exim4/conf.d/acl/40_exim4-config_check_data | 95 + exim4/conf.d/auth/00_exim4-config_header | 8 + exim4/conf.d/auth/30_exim4-config_examples | 254 + .../main/01_exim4-config_listmacrosdefs | 81 + exim4/conf.d/main/02_exim4-config_options | 222 + exim4/conf.d/main/03_exim4-config_tlsoptions | 85 + .../conf.d/main/90_exim4-config_log_selector | 10 + exim4/conf.d/retry/00_exim4-config_header | 7 + exim4/conf.d/retry/30_exim4-config | 19 + exim4/conf.d/rewrite/00_exim4-config_header | 7 + .../conf.d/rewrite/31_exim4-config_rewriting | 16 + exim4/conf.d/router/00_exim4-config_header | 11 + .../router/100_exim4-config_domain_literal | 18 + .../router/150_exim4-config_hubbed_hosts | 18 + exim4/conf.d/router/200_exim4-config_primary | 92 + .../conf.d/router/300_exim4-config_real_local | 22 + .../router/400_exim4-config_system_aliases | 44 + exim4/conf.d/router/500_exim4-config_hubuser | 31 + .../router/600_exim4-config_userforward | 51 + exim4/conf.d/router/700_exim4-config_procmail | 15 + exim4/conf.d/router/800_exim4-config_maildrop | 14 + exim4/conf.d/router/850_exim4-config_lowuid | 29 + .../conf.d/router/900_exim4-config_local_user | 15 + exim4/conf.d/router/mmm_mail4root | 17 + exim4/conf.d/transport/00_exim4-config_header | 13 + .../10_exim4-config_transport-macros | 16 + .../transport/30_exim4-config_address_file | 11 + .../transport/30_exim4-config_address_pipe | 10 + .../transport/30_exim4-config_address_reply | 8 + .../transport/30_exim4-config_mail_spool | 17 + .../transport/30_exim4-config_maildir_home | 41 + .../transport/30_exim4-config_maildrop_pipe | 12 + .../transport/30_exim4-config_procmail_pipe | 10 + .../transport/30_exim4-config_remote_smtp | 57 + .../30_exim4-config_remote_smtp_smarthost | 48 + .../35_exim4-config_address_directory | 14 + exim4/exim4.conf.template | 2121 +++++ exim4/passwd.client | 7 + exim4/update-exim4.conf.conf | 31 + fb.modes | 1003 +++ .../20-unhint-small-dejavu-lgc-sans-mono.conf | 26 + .../20-unhint-small-dejavu-lgc-sans.conf | 26 + .../20-unhint-small-dejavu-lgc-serif.conf | 26 + .../20-unhint-small-dejavu-sans-mono.conf | 26 + .../20-unhint-small-dejavu-sans.conf | 26 + .../20-unhint-small-dejavu-serif.conf | 26 + fonts/conf.avail/30-droid-noto-mono.conf | 10 + fonts/conf.avail/57-dejavu-sans-mono.conf | 62 + fonts/conf.avail/57-dejavu-sans.conf | 87 + fonts/conf.avail/57-dejavu-serif.conf | 69 + fonts/conf.avail/58-dejavu-lgc-sans-mono.conf | 62 + fonts/conf.avail/58-dejavu-lgc-sans.conf | 87 + fonts/conf.avail/58-dejavu-lgc-serif.conf | 69 + fonts/conf.avail/65-droid-sans-fallback.conf | 10 + fonts/conf.d/10-hinting-slight.conf | 1 + fonts/conf.d/10-scale-bitmap-fonts.conf | 1 + fonts/conf.d/11-lcdfilter-default.conf | 1 + .../20-unhint-small-dejavu-lgc-sans-mono.conf | 1 + .../20-unhint-small-dejavu-lgc-sans.conf | 1 + .../20-unhint-small-dejavu-lgc-serif.conf | 1 + .../20-unhint-small-dejavu-sans-mono.conf | 1 + fonts/conf.d/20-unhint-small-dejavu-sans.conf | 1 + .../conf.d/20-unhint-small-dejavu-serif.conf | 1 + fonts/conf.d/20-unhint-small-vera.conf | 1 + fonts/conf.d/30-metric-aliases.conf | 1 + fonts/conf.d/40-nonlatin.conf | 1 + fonts/conf.d/45-generic.conf | 1 + fonts/conf.d/45-latin.conf | 1 + fonts/conf.d/49-sansserif.conf | 1 + fonts/conf.d/50-user.conf | 1 + fonts/conf.d/51-local.conf | 1 + fonts/conf.d/57-dejavu-sans-mono.conf | 1 + fonts/conf.d/57-dejavu-sans.conf | 1 + fonts/conf.d/57-dejavu-serif.conf | 1 + fonts/conf.d/58-dejavu-lgc-sans-mono.conf | 1 + fonts/conf.d/58-dejavu-lgc-sans.conf | 1 + fonts/conf.d/58-dejavu-lgc-serif.conf | 1 + fonts/conf.d/60-generic.conf | 1 + fonts/conf.d/60-latin.conf | 1 + fonts/conf.d/65-fonts-persian.conf | 1 + fonts/conf.d/65-nonlatin.conf | 1 + fonts/conf.d/69-unifont.conf | 1 + fonts/conf.d/70-no-bitmaps.conf | 1 + fonts/conf.d/80-delicious.conf | 1 + fonts/conf.d/90-synthetic.conf | 1 + fonts/conf.d/README | 23 + fonts/fonts.conf | 108 + fstab | 12 + fuse.conf | 8 + gai.conf | 65 + gdb/gdbinit | 1 + .../cidfmap.d/90gs-cjk-resource-cns1.conf | 9 + .../cidfmap.d/90gs-cjk-resource-gb1.conf | 9 + .../cidfmap.d/90gs-cjk-resource-japan1.conf | 8 + .../cidfmap.d/90gs-cjk-resource-japan2.conf | 4 + .../cidfmap.d/90gs-cjk-resource-korea1.conf | 9 + ghostscript/fontmap.d/10gsfonts.conf | 74 + gitea/app.ini | 75 + groff/man.local | 33 + groff/mdoc.local | 33 + group | 71 + group- | 70 + gshadow | 71 + gshadow- | 70 + host.conf | 1 + hostname | 1 + hosts | 7 + hosts.allow | 10 + hosts.deny | 17 + idmapd.conf | 11 + ifplugd/action.d/action_wpa | 1 + init.d/alsa-utils | 209 + init.d/avahi-daemon | 104 + init.d/bluetooth | 134 + init.d/console-setup.sh | 46 + init.d/cron | 92 + init.d/dbus | 122 + init.d/dhcpcd | 96 + init.d/docker | 156 + init.d/dphys-swapfile | 78 + init.d/exim4 | 289 + init.d/fake-hwclock | 38 + init.d/hwclock.sh | 120 + init.d/keyboard-setup.sh | 50 + init.d/kmod | 92 + init.d/mosquitto | 138 + init.d/netfilter-persistent | 50 + init.d/networking | 195 + init.d/nfs-common | 283 + init.d/nginx | 196 + init.d/ntp | 72 + init.d/paxctld | 125 + init.d/php7.3-fpm | 191 + init.d/postgresql | 61 + init.d/procps | 34 + init.d/raspi-config | 42 + init.d/redis-server | 89 + init.d/resolvconf | 135 + init.d/rng-tools | 96 + init.d/rpcbind | 101 + init.d/rsync | 156 + init.d/rsyslog | 129 + init.d/snmpd | 42 + init.d/ssh | 162 + init.d/sudo | 44 + init.d/sysstat | 62 + init.d/tftpd-hpa | 106 + init.d/triggerhappy | 133 + init.d/udev | 256 + init.d/x11-common | 122 + init.d/xinetd | 84 + init/docker.conf | 72 + init/paxctld.conf | 13 + init/php7.3-fpm.conf | 19 + init/resolvconf.conf | 19 + init/tftpd-hpa.conf | 51 + initramfs-tools/initramfs.conf | 72 + initramfs-tools/modules | 11 + initramfs-tools/update-initramfs.conf | 20 + inputrc | 71 + insserv.conf.d/rpcbind | 1 + iproute2/bpf_pinning | 6 + iproute2/ematch_map | 8 + iproute2/group | 2 + iproute2/nl_protos | 23 + iproute2/rt_dsfield | 26 + iproute2/rt_protos | 23 + iproute2/rt_protos.d/README | 2 + iproute2/rt_realms | 13 + iproute2/rt_scopes | 11 + iproute2/rt_tables | 11 + iproute2/rt_tables.d/README | 2 + issue | 2 + issue.net | 1 + java-11-openjdk/accessibility.properties | 10 + java-11-openjdk/jfr/default.jfc | 890 ++ java-11-openjdk/jfr/profile.jfc | 891 ++ java-11-openjdk/jvm-armhf.cfg | 3 + java-11-openjdk/logging.properties | 63 + java-11-openjdk/management/jmxremote.access | 79 + .../management/management.properties | 302 + java-11-openjdk/net.properties | 121 + java-11-openjdk/psfont.properties.ja | 119 + java-11-openjdk/psfontj2d.properties | 323 + java-11-openjdk/security/blacklisted.certs | 39 + java-11-openjdk/security/default.policy | 219 + java-11-openjdk/security/java.policy | 44 + java-11-openjdk/security/java.security | 1363 +++ java-11-openjdk/security/nss.cfg | 4 + java-11-openjdk/security/policy/README.txt | 54 + .../policy/limited/default_US_export.policy | 6 + .../policy/limited/default_local.policy | 14 + .../policy/limited/exempt_local.policy | 13 + .../policy/unlimited/default_US_export.policy | 6 + .../policy/unlimited/default_local.policy | 6 + .../security/public_suffix_list.dat | Bin 0 -> 232578 bytes java-11-openjdk/sound.properties | 39 + java-11-openjdk/swing.properties | 2 + kernel/header_postinst.d/dkms | 46 + kernel/postinst.d/apt-auto-removal | 83 + kernel/postinst.d/dkms | 46 + kernel/postinst.d/initramfs-tools | 36 + kernel/postrm.d/initramfs-tools | 36 + kernel/prerm.d/dkms | 30 + ld.so.conf | 2 + ld.so.conf.d/00-vmcs.conf | 1 + ld.so.conf.d/arm-linux-gnueabihf.conf | 4 + .../fakeroot-arm-linux-gnueabihf.conf | 1 + ld.so.conf.d/libc.conf | 2 + ld.so.preload | 1 + ldap/ldap.conf | 17 + letsencrypt/account.conf | 10 + letsencrypt/acme.sh | 7468 +++++++++++++++++ letsencrypt/acme.sh.env | 2 + .../acme-v02.api.letsencrypt.org/account.json | 1 + .../acme-v02.api.letsencrypt.org/account.key | 27 + .../ca/acme-v02.api.letsencrypt.org/ca.conf | 3 + letsencrypt/deploy/README.md | 6 + letsencrypt/deploy/apache.sh | 26 + letsencrypt/deploy/cleverreach.sh | 70 + letsencrypt/deploy/cpanel_uapi.sh | 62 + letsencrypt/deploy/docker.sh | 287 + letsencrypt/deploy/dovecot.sh | 26 + letsencrypt/deploy/exim4.sh | 114 + letsencrypt/deploy/fritzbox.sh | 118 + letsencrypt/deploy/gcore_cdn.sh | 139 + letsencrypt/deploy/gitlab.sh | 80 + letsencrypt/deploy/haproxy.sh | 275 + letsencrypt/deploy/keychain.sh | 25 + letsencrypt/deploy/kong.sh | 77 + letsencrypt/deploy/mailcow.sh | 58 + letsencrypt/deploy/myapi.sh | 28 + letsencrypt/deploy/mydevil.sh | 59 + letsencrypt/deploy/mysqld.sh | 26 + letsencrypt/deploy/nginx.sh | 26 + letsencrypt/deploy/opensshd.sh | 26 + letsencrypt/deploy/openstack.sh | 262 + letsencrypt/deploy/panos.sh | 139 + letsencrypt/deploy/pureftpd.sh | 26 + letsencrypt/deploy/qiniu.sh | 96 + letsencrypt/deploy/routeros.sh | 111 + letsencrypt/deploy/ssh.sh | 286 + letsencrypt/deploy/strongswan.sh | 55 + letsencrypt/deploy/synology_dsm.sh | 152 + letsencrypt/deploy/unifi.sh | 100 + letsencrypt/deploy/vault.sh | 67 + letsencrypt/deploy/vault_cli.sh | 61 + letsencrypt/deploy/vsftpd.sh | 110 + letsencrypt/dnsapi/README.md | 6 + letsencrypt/dnsapi/dns_1984hosting.sh | 236 + letsencrypt/dnsapi/dns_acmedns.sh | 55 + letsencrypt/dnsapi/dns_acmeproxy.sh | 83 + letsencrypt/dnsapi/dns_active24.sh | 141 + letsencrypt/dnsapi/dns_ad.sh | 147 + letsencrypt/dnsapi/dns_ali.sh | 203 + letsencrypt/dnsapi/dns_anx.sh | 150 + letsencrypt/dnsapi/dns_arvan.sh | 163 + letsencrypt/dnsapi/dns_autodns.sh | 264 + letsencrypt/dnsapi/dns_aws.sh | 365 + letsencrypt/dnsapi/dns_azure.sh | 348 + letsencrypt/dnsapi/dns_cf.sh | 234 + letsencrypt/dnsapi/dns_clouddns.sh | 197 + letsencrypt/dnsapi/dns_cloudns.sh | 184 + letsencrypt/dnsapi/dns_cn.sh | 157 + letsencrypt/dnsapi/dns_conoha.sh | 253 + letsencrypt/dnsapi/dns_constellix.sh | 141 + letsencrypt/dnsapi/dns_cx.sh | 185 + letsencrypt/dnsapi/dns_cyon.sh | 328 + letsencrypt/dnsapi/dns_da.sh | 184 + letsencrypt/dnsapi/dns_ddnss.sh | 130 + letsencrypt/dnsapi/dns_desec.sh | 204 + letsencrypt/dnsapi/dns_df.sh | 65 + letsencrypt/dnsapi/dns_dgon.sh | 250 + letsencrypt/dnsapi/dns_dnsimple.sh | 198 + letsencrypt/dnsapi/dns_do.sh | 148 + letsencrypt/dnsapi/dns_doapi.sh | 59 + letsencrypt/dnsapi/dns_domeneshop.sh | 155 + letsencrypt/dnsapi/dns_dp.sh | 161 + letsencrypt/dnsapi/dns_dpi.sh | 161 + letsencrypt/dnsapi/dns_dreamhost.sh | 97 + letsencrypt/dnsapi/dns_duckdns.sh | 132 + letsencrypt/dnsapi/dns_durabledns.sh | 176 + letsencrypt/dnsapi/dns_dyn.sh | 339 + letsencrypt/dnsapi/dns_dynu.sh | 232 + letsencrypt/dnsapi/dns_dynv6.sh | 285 + letsencrypt/dnsapi/dns_easydns.sh | 171 + letsencrypt/dnsapi/dns_edgedns.sh | 466 + letsencrypt/dnsapi/dns_euserv.sh | 358 + letsencrypt/dnsapi/dns_exoscale.sh | 168 + letsencrypt/dnsapi/dns_freedns.sh | 371 + letsencrypt/dnsapi/dns_gandi_livedns.sh | 175 + letsencrypt/dnsapi/dns_gcloud.sh | 167 + letsencrypt/dnsapi/dns_gd.sh | 176 + letsencrypt/dnsapi/dns_gdnsdk.sh | 177 + letsencrypt/dnsapi/dns_he.sh | 173 + letsencrypt/dnsapi/dns_hetzner.sh | 252 + letsencrypt/dnsapi/dns_hexonet.sh | 156 + letsencrypt/dnsapi/dns_hostingde.sh | 178 + letsencrypt/dnsapi/dns_huaweicloud.sh | 255 + letsencrypt/dnsapi/dns_infoblox.sh | 102 + letsencrypt/dnsapi/dns_infomaniak.sh | 199 + letsencrypt/dnsapi/dns_internetbs.sh | 180 + letsencrypt/dnsapi/dns_inwx.sh | 420 + letsencrypt/dnsapi/dns_ispconfig.sh | 176 + letsencrypt/dnsapi/dns_jd.sh | 286 + letsencrypt/dnsapi/dns_joker.sh | 129 + letsencrypt/dnsapi/dns_kappernet.sh | 150 + letsencrypt/dnsapi/dns_kas.sh | 168 + letsencrypt/dnsapi/dns_kinghost.sh | 107 + letsencrypt/dnsapi/dns_knot.sh | 95 + letsencrypt/dnsapi/dns_leaseweb.sh | 149 + letsencrypt/dnsapi/dns_lexicon.sh | 113 + letsencrypt/dnsapi/dns_linode.sh | 183 + letsencrypt/dnsapi/dns_linode_v4.sh | 186 + letsencrypt/dnsapi/dns_loopia.sh | 302 + letsencrypt/dnsapi/dns_lua.sh | 154 + letsencrypt/dnsapi/dns_maradns.sh | 69 + letsencrypt/dnsapi/dns_me.sh | 157 + letsencrypt/dnsapi/dns_miab.sh | 210 + letsencrypt/dnsapi/dns_misaka.sh | 159 + letsencrypt/dnsapi/dns_myapi.sh | 37 + letsencrypt/dnsapi/dns_mydevil.sh | 97 + letsencrypt/dnsapi/dns_mydnsjp.sh | 210 + letsencrypt/dnsapi/dns_namecheap.sh | 407 + letsencrypt/dnsapi/dns_namecom.sh | 173 + letsencrypt/dnsapi/dns_namesilo.sh | 142 + letsencrypt/dnsapi/dns_nederhost.sh | 131 + letsencrypt/dnsapi/dns_neodigit.sh | 181 + letsencrypt/dnsapi/dns_netcup.sh | 134 + letsencrypt/dnsapi/dns_netlify.sh | 162 + letsencrypt/dnsapi/dns_nic.sh | 205 + letsencrypt/dnsapi/dns_njalla.sh | 168 + letsencrypt/dnsapi/dns_nm.sh | 88 + letsencrypt/dnsapi/dns_nsd.sh | 64 + letsencrypt/dnsapi/dns_nsone.sh | 158 + letsencrypt/dnsapi/dns_nsupdate.sh | 98 + letsencrypt/dnsapi/dns_nw.sh | 211 + letsencrypt/dnsapi/dns_one.sh | 279 + letsencrypt/dnsapi/dns_online.sh | 217 + letsencrypt/dnsapi/dns_openprovider.sh | 247 + letsencrypt/dnsapi/dns_openstack.sh | 348 + letsencrypt/dnsapi/dns_opnsense.sh | 273 + letsencrypt/dnsapi/dns_ovh.sh | 318 + letsencrypt/dnsapi/dns_pdns.sh | 232 + letsencrypt/dnsapi/dns_pleskxml.sh | 417 + letsencrypt/dnsapi/dns_pointhq.sh | 164 + letsencrypt/dnsapi/dns_rackspace.sh | 207 + letsencrypt/dnsapi/dns_rcode0.sh | 224 + letsencrypt/dnsapi/dns_regru.sh | 126 + letsencrypt/dnsapi/dns_schlundtech.sh | 261 + letsencrypt/dnsapi/dns_selectel.sh | 161 + letsencrypt/dnsapi/dns_servercow.sh | 170 + letsencrypt/dnsapi/dns_tele3.sh | 69 + letsencrypt/dnsapi/dns_transip.sh | 162 + letsencrypt/dnsapi/dns_ultra.sh | 164 + letsencrypt/dnsapi/dns_unoeuro.sh | 179 + letsencrypt/dnsapi/dns_variomedia.sh | 147 + letsencrypt/dnsapi/dns_vscale.sh | 149 + letsencrypt/dnsapi/dns_vultr.sh | 161 + letsencrypt/dnsapi/dns_world4you.sh | 191 + letsencrypt/dnsapi/dns_yandex.sh | 121 + letsencrypt/dnsapi/dns_zilore.sh | 139 + letsencrypt/dnsapi/dns_zone.sh | 149 + letsencrypt/dnsapi/dns_zonomi.sh | 85 + .../ghost.realm.local/ghost.realm.local.conf | 8 + .../ghost.realm.local/ghost.realm.local.csr | 17 + .../ghost.realm.local.csr.conf | 8 + .../ghost.realm.local/ghost.realm.local.key | 27 + letsencrypt/http.header | 10 + letsencrypt/notify/cqhttp.sh | 64 + letsencrypt/notify/dingtalk.sh | 68 + letsencrypt/notify/ifttt.sh | 86 + letsencrypt/notify/mail.sh | 143 + letsencrypt/notify/mailgun.sh | 131 + letsencrypt/notify/pop.sh | 15 + letsencrypt/notify/postmark.sh | 58 + letsencrypt/notify/pushover.sh | 63 + letsencrypt/notify/sendgrid.sh | 56 + letsencrypt/notify/slack.sh | 55 + letsencrypt/notify/smtp.sh | 15 + letsencrypt/notify/teams.sh | 86 + letsencrypt/notify/xmpp.sh | 90 + libaudit.conf | 7 + libnl-3/classid | 45 + libnl-3/pktloc | 76 + lighttpd/external.conf | 0 lighttpd/lighttpd.conf.orig | 51 + locale.alias | 82 + locale.gen | 501 ++ localtime | 1 + logcheck/ignore.d.server/gpg-agent | 11 + logcheck/ignore.d.server/rng-tools | 5 + logcheck/ignore.d.server/rsyslog | 5 + logcheck/violations.ignore.d/rng-tools | 5 + login.defs | 340 + logrotate.conf | 9 + logrotate.d/apt | 14 + logrotate.d/btmp | 9 + logrotate.d/dpkg | 14 + logrotate.d/exim4-base | 9 + logrotate.d/exim4-paniclog | 10 + logrotate.d/mosquitto | 14 + logrotate.d/nginx | 18 + logrotate.d/nodered | 9 + logrotate.d/php7.3-fpm | 11 + logrotate.d/postgresql-common | 10 + logrotate.d/rsyslog | 15 + logrotate.d/syslog | 14 + logrotate.d/wtmp | 9 + machine-id | 1 + magic | 3 + magic.mime | 3 + mailcap | 66 + mailcap.order | 10 + mailname | 1 + manpath.config | 131 + mime.types | 845 ++ mke2fs.conf | 47 + modprobe.d/blacklist-8192cu.conf | 1 + modprobe.d/blacklist-rtl8xxxu.conf | 1 + modprobe.d/dkms.conf | 4 + modules | 5 + modules-load.d/modules.conf | 1 + mosquitto/ca_certificates/README | 1 + mosquitto/certs/README | 3 + mosquitto/conf.d/README | 2 + mosquitto/mosquitto.conf | 13 + mysql/conf.d/mysql.cnf | 1 + mysql/conf.d/mysqldump.cnf | 4 + mysql/mariadb.cnf | 23 + mysql/my.cnf | 1 + mysql/my.cnf.fallback | 23 + nanorc | 272 + neofetch/neofetch.config | 771 ++ netconfig | 19 + network/if-down.d/resolvconf | 16 + network/if-down.d/wpasupplicant | 1 + network/if-post-down.d/wireless-tools | 78 + network/if-post-down.d/wpasupplicant | 1 + network/if-pre-up.d/ethtool | 14 + network/if-pre-up.d/wireless-tools | 143 + network/if-pre-up.d/wpasupplicant | 1 + network/if-up.d/000resolvconf | 47 + network/if-up.d/ethtool | 55 + network/if-up.d/wpasupplicant | 1 + network/interfaces | 7 + networks | 4 + nginx/.htpasswd | 1 + nginx/fastcgi.conf | 26 + nginx/fastcgi_params | 25 + nginx/koi-utf | 109 + nginx/koi-win | 103 + nginx/mime.types | 78 + .../modules-enabled/50-mod-http-auth-pam.conf | 1 + .../modules-enabled/50-mod-http-dav-ext.conf | 1 + nginx/modules-enabled/50-mod-http-echo.conf | 1 + nginx/modules-enabled/50-mod-http-geoip.conf | 1 + .../50-mod-http-image-filter.conf | 1 + .../50-mod-http-subs-filter.conf | 1 + .../50-mod-http-upstream-fair.conf | 1 + .../50-mod-http-xslt-filter.conf | 1 + nginx/modules-enabled/50-mod-mail.conf | 1 + nginx/modules-enabled/50-mod-stream.conf | 1 + nginx/nginx.conf | 66 + nginx/proxy_params | 4 + nginx/scgi_params | 17 + .../sites-available/adguard.realm.local.conf | 51 + .../sites-available/checkmk.realm.local.conf | 51 + nginx/sites-available/default | 91 + nginx/sites-available/gitea.realm.local.conf | 51 + .../sites-available/grafana.realm.local.conf | 51 + .../sites-available/influxdb.realm.local.conf | 51 + .../sites-available/openhab.realm.local.conf | 51 + .../photoprism.realm.local.conf | 56 + .../portainer.realm.local.conf | 51 + nginx/sites-enabled/adguard.realm.local.conf | 1 + nginx/sites-enabled/checkmk.realm.local.conf | 1 + nginx/sites-enabled/default | 1 + nginx/sites-enabled/gitea.realm.local.conf | 1 + nginx/sites-enabled/grafana.realm.local.conf | 1 + nginx/sites-enabled/influxdb.realm.local.conf | 1 + nginx/sites-enabled/openhab.realm.local.conf | 1 + .../sites-enabled/photoprism.realm.local.conf | 1 + .../sites-enabled/portainer.realm.local.conf | 1 + nginx/snippets/fastcgi-php.conf | 13 + nginx/snippets/snakeoil.conf | 5 + nginx/ssl/certs/adguard.realm.local/cert.pem | 20 + nginx/ssl/certs/adguard.realm.local/key.pem | 27 + nginx/ssl/certs/checkmk.realm.local/cert.pem | 20 + nginx/ssl/certs/checkmk.realm.local/key.pem | 27 + nginx/ssl/certs/gitea.realm.local/cert.pem | 20 + nginx/ssl/certs/gitea.realm.local/key.pem | 27 + nginx/ssl/certs/grafana.realm.local/cert.pem | 20 + nginx/ssl/certs/grafana.realm.local/key.pem | 27 + nginx/ssl/certs/influxdb.realm.local/cert.pem | 20 + nginx/ssl/certs/influxdb.realm.local/key.pem | 27 + nginx/ssl/certs/openhab.realm.local/cert.pem | 20 + nginx/ssl/certs/openhab.realm.local/key.pem | 27 + .../ssl/certs/photoprism.realm.local/cert.pem | 20 + .../ssl/certs/photoprism.realm.local/key.pem | 27 + .../ssl/certs/portainer.realm.local/cert.pem | 20 + nginx/ssl/certs/portainer.realm.local/key.pem | 27 + nginx/ssl/certs/realm.local/cert.pem | 20 + nginx/ssl/certs/realm.local/key.pem | 27 + nginx/uwsgi_params | 17 + nginx/win-utf | 125 + nsswitch.conf | 20 + ntp.conf | 30 + os-release | 1 + pam.conf | 15 + pam.d/chfn | 16 + pam.d/chpasswd | 5 + pam.d/chsh | 20 + pam.d/common-account | 25 + pam.d/common-auth | 25 + pam.d/common-password | 33 + pam.d/common-session | 27 + pam.d/common-session-noninteractive | 25 + pam.d/cron | 21 + pam.d/login | 116 + pam.d/newusers | 5 + pam.d/other | 16 + pam.d/passwd | 6 + pam.d/polkit-1 | 8 + pam.d/runuser | 5 + pam.d/runuser-l | 5 + pam.d/sshd | 55 + pam.d/su | 61 + pam.d/su-l | 6 + pam.d/sudo | 5 + pam.d/systemd-user | 12 + papersize | 1 + passwd | 41 + passwd- | 42 + paxctld.conf | 114 + perl/Net/libnet.cfg | 21 + php/7.3/cgi/conf.d/10-mysqlnd.ini | 1 + php/7.3/cgi/conf.d/10-opcache.ini | 1 + php/7.3/cgi/conf.d/10-pdo.ini | 1 + php/7.3/cgi/conf.d/15-xml.ini | 1 + php/7.3/cgi/conf.d/20-calendar.ini | 1 + php/7.3/cgi/conf.d/20-ctype.ini | 1 + php/7.3/cgi/conf.d/20-dom.ini | 1 + php/7.3/cgi/conf.d/20-exif.ini | 1 + php/7.3/cgi/conf.d/20-fileinfo.ini | 1 + php/7.3/cgi/conf.d/20-ftp.ini | 1 + php/7.3/cgi/conf.d/20-gettext.ini | 1 + php/7.3/cgi/conf.d/20-iconv.ini | 1 + php/7.3/cgi/conf.d/20-intl.ini | 1 + php/7.3/cgi/conf.d/20-json.ini | 1 + php/7.3/cgi/conf.d/20-mysqli.ini | 1 + php/7.3/cgi/conf.d/20-pdo_mysql.ini | 1 + php/7.3/cgi/conf.d/20-pdo_sqlite.ini | 1 + php/7.3/cgi/conf.d/20-phar.ini | 1 + php/7.3/cgi/conf.d/20-posix.ini | 1 + php/7.3/cgi/conf.d/20-readline.ini | 1 + php/7.3/cgi/conf.d/20-shmop.ini | 1 + php/7.3/cgi/conf.d/20-simplexml.ini | 1 + php/7.3/cgi/conf.d/20-sockets.ini | 1 + php/7.3/cgi/conf.d/20-sqlite3.ini | 1 + php/7.3/cgi/conf.d/20-sysvmsg.ini | 1 + php/7.3/cgi/conf.d/20-sysvsem.ini | 1 + php/7.3/cgi/conf.d/20-sysvshm.ini | 1 + php/7.3/cgi/conf.d/20-tokenizer.ini | 1 + php/7.3/cgi/conf.d/20-wddx.ini | 1 + php/7.3/cgi/conf.d/20-xmlreader.ini | 1 + php/7.3/cgi/conf.d/20-xmlwriter.ini | 1 + php/7.3/cgi/conf.d/20-xsl.ini | 1 + php/7.3/cgi/php.ini | 1939 +++++ php/7.3/cli/conf.d/10-mysqlnd.ini | 1 + php/7.3/cli/conf.d/10-opcache.ini | 1 + php/7.3/cli/conf.d/10-pdo.ini | 1 + php/7.3/cli/conf.d/15-xml.ini | 1 + php/7.3/cli/conf.d/20-calendar.ini | 1 + php/7.3/cli/conf.d/20-ctype.ini | 1 + php/7.3/cli/conf.d/20-dom.ini | 1 + php/7.3/cli/conf.d/20-exif.ini | 1 + php/7.3/cli/conf.d/20-fileinfo.ini | 1 + php/7.3/cli/conf.d/20-ftp.ini | 1 + php/7.3/cli/conf.d/20-gettext.ini | 1 + php/7.3/cli/conf.d/20-iconv.ini | 1 + php/7.3/cli/conf.d/20-intl.ini | 1 + php/7.3/cli/conf.d/20-json.ini | 1 + php/7.3/cli/conf.d/20-mysqli.ini | 1 + php/7.3/cli/conf.d/20-pdo_mysql.ini | 1 + php/7.3/cli/conf.d/20-pdo_sqlite.ini | 1 + php/7.3/cli/conf.d/20-phar.ini | 1 + php/7.3/cli/conf.d/20-posix.ini | 1 + php/7.3/cli/conf.d/20-readline.ini | 1 + php/7.3/cli/conf.d/20-shmop.ini | 1 + php/7.3/cli/conf.d/20-simplexml.ini | 1 + php/7.3/cli/conf.d/20-sockets.ini | 1 + php/7.3/cli/conf.d/20-sqlite3.ini | 1 + php/7.3/cli/conf.d/20-sysvmsg.ini | 1 + php/7.3/cli/conf.d/20-sysvsem.ini | 1 + php/7.3/cli/conf.d/20-sysvshm.ini | 1 + php/7.3/cli/conf.d/20-tokenizer.ini | 1 + php/7.3/cli/conf.d/20-wddx.ini | 1 + php/7.3/cli/conf.d/20-xmlreader.ini | 1 + php/7.3/cli/conf.d/20-xmlwriter.ini | 1 + php/7.3/cli/conf.d/20-xsl.ini | 1 + php/7.3/cli/php.ini | 1939 +++++ php/7.3/fpm/conf.d/10-mysqlnd.ini | 1 + php/7.3/fpm/conf.d/10-opcache.ini | 1 + php/7.3/fpm/conf.d/10-pdo.ini | 1 + php/7.3/fpm/conf.d/15-xml.ini | 1 + php/7.3/fpm/conf.d/20-calendar.ini | 1 + php/7.3/fpm/conf.d/20-ctype.ini | 1 + php/7.3/fpm/conf.d/20-dom.ini | 1 + php/7.3/fpm/conf.d/20-exif.ini | 1 + php/7.3/fpm/conf.d/20-fileinfo.ini | 1 + php/7.3/fpm/conf.d/20-ftp.ini | 1 + php/7.3/fpm/conf.d/20-gettext.ini | 1 + php/7.3/fpm/conf.d/20-iconv.ini | 1 + php/7.3/fpm/conf.d/20-intl.ini | 1 + php/7.3/fpm/conf.d/20-json.ini | 1 + php/7.3/fpm/conf.d/20-mysqli.ini | 1 + php/7.3/fpm/conf.d/20-pdo_mysql.ini | 1 + php/7.3/fpm/conf.d/20-pdo_sqlite.ini | 1 + php/7.3/fpm/conf.d/20-phar.ini | 1 + php/7.3/fpm/conf.d/20-posix.ini | 1 + php/7.3/fpm/conf.d/20-readline.ini | 1 + php/7.3/fpm/conf.d/20-shmop.ini | 1 + php/7.3/fpm/conf.d/20-simplexml.ini | 1 + php/7.3/fpm/conf.d/20-sockets.ini | 1 + php/7.3/fpm/conf.d/20-sqlite3.ini | 1 + php/7.3/fpm/conf.d/20-sysvmsg.ini | 1 + php/7.3/fpm/conf.d/20-sysvsem.ini | 1 + php/7.3/fpm/conf.d/20-sysvshm.ini | 1 + php/7.3/fpm/conf.d/20-tokenizer.ini | 1 + php/7.3/fpm/conf.d/20-wddx.ini | 1 + php/7.3/fpm/conf.d/20-xmlreader.ini | 1 + php/7.3/fpm/conf.d/20-xmlwriter.ini | 1 + php/7.3/fpm/conf.d/20-xsl.ini | 1 + php/7.3/fpm/php-fpm.conf | 143 + php/7.3/fpm/php.ini | 1939 +++++ php/7.3/fpm/pool.d/www.conf | 439 + php/7.3/mods-available/calendar.ini | 3 + php/7.3/mods-available/ctype.ini | 3 + php/7.3/mods-available/dom.ini | 3 + php/7.3/mods-available/exif.ini | 3 + php/7.3/mods-available/fileinfo.ini | 3 + php/7.3/mods-available/ftp.ini | 3 + php/7.3/mods-available/gettext.ini | 3 + php/7.3/mods-available/iconv.ini | 3 + php/7.3/mods-available/intl.ini | 3 + php/7.3/mods-available/json.ini | 3 + php/7.3/mods-available/mysqli.ini | 3 + php/7.3/mods-available/mysqlnd.ini | 3 + php/7.3/mods-available/opcache.ini | 3 + php/7.3/mods-available/pdo.ini | 3 + php/7.3/mods-available/pdo_mysql.ini | 3 + php/7.3/mods-available/pdo_sqlite.ini | 3 + php/7.3/mods-available/phar.ini | 3 + php/7.3/mods-available/posix.ini | 3 + php/7.3/mods-available/readline.ini | 3 + php/7.3/mods-available/shmop.ini | 3 + php/7.3/mods-available/simplexml.ini | 3 + php/7.3/mods-available/sockets.ini | 3 + php/7.3/mods-available/sqlite3.ini | 3 + php/7.3/mods-available/sysvmsg.ini | 3 + php/7.3/mods-available/sysvsem.ini | 3 + php/7.3/mods-available/sysvshm.ini | 3 + php/7.3/mods-available/tokenizer.ini | 3 + php/7.3/mods-available/wddx.ini | 3 + php/7.3/mods-available/xml.ini | 3 + php/7.3/mods-available/xmlreader.ini | 3 + php/7.3/mods-available/xmlwriter.ini | 3 + php/7.3/mods-available/xsl.ini | 3 + pip.conf | 2 + .../50-localauthority.conf | 10 + .../localauthority.conf.d/51-debian-sudo.conf | 2 + .../nullbackend.conf.d/50-nullbackend.conf | 16 + postgresql-common/createcluster.conf | 41 + postgresql-common/root.crt | 11 + postgresql-common/supported_versions | 2 + postgresql-common/user_clusters | 22 + postgresql/11/main/environment | 7 + postgresql/11/main/pg_ctl.conf | 5 + postgresql/11/main/pg_hba.conf | 101 + postgresql/11/main/pg_ident.conf | 42 + postgresql/11/main/postgresql.conf | 692 ++ postgresql/11/main/start.conf | 8 + ppp/ip-down.d/000resolvconf | 21 + ppp/ip-up.d/000resolvconf | 33 + ppp/ip-up.d/exim4 | 15 + prelink.conf.d/cmk-update-agent.conf | 1 + profile | 34 + profile.d/at-dbus-fix.sh | 3 + profile.d/bash_completion.sh | 15 + profile.d/sshpwd.sh | 10 + profile.d/wifi-check.sh | 18 + protocols | 64 + python/debian_config | 3 + python2.7/sitecustomize.py | 7 + python3.7/sitecustomize.py | 7 + python3/debian_config | 3 + rc.local | 29 + rc0.d/K01alsa-utils | 1 + rc0.d/K01avahi-daemon | 1 + rc0.d/K01bluetooth | 1 + rc0.d/K01dhcpcd | 1 + rc0.d/K01docker | 1 + rc0.d/K01exim4 | 1 + rc0.d/K01fake-hwclock | 1 + rc0.d/K01hwclock.sh | 1 + rc0.d/K01mosquitto | 1 + rc0.d/K01netfilter-persistent | 1 + rc0.d/K01networking | 1 + rc0.d/K01nfs-common | 1 + rc0.d/K01nginx | 1 + rc0.d/K01paxctld | 1 + rc0.d/K01php7.3-fpm | 1 + rc0.d/K01pihole-FTL | 1 + rc0.d/K01postgresql | 1 + rc0.d/K01redis-server | 1 + rc0.d/K01resolvconf | 1 + rc0.d/K01rng-tools | 1 + rc0.d/K01rpcbind | 1 + rc0.d/K01rsyslog | 1 + rc0.d/K01snmpd | 1 + rc0.d/K01tftpd-hpa | 1 + rc0.d/K01triggerhappy | 1 + rc0.d/K01udev | 1 + rc0.d/K01xinetd | 1 + rc1.d/K01alsa-utils | 1 + rc1.d/K01avahi-daemon | 1 + rc1.d/K01bluetooth | 1 + rc1.d/K01dhcpcd | 1 + rc1.d/K01docker | 1 + rc1.d/K01exim4 | 1 + rc1.d/K01fake-hwclock | 1 + rc1.d/K01mosquitto | 1 + rc1.d/K01netfilter-persistent | 1 + rc1.d/K01nfs-common | 1 + rc1.d/K01nginx | 1 + rc1.d/K01paxctld | 1 + rc1.d/K01php7.3-fpm | 1 + rc1.d/K01pihole-FTL | 1 + rc1.d/K01postgresql | 1 + rc1.d/K01redis-server | 1 + rc1.d/K01rng-tools | 1 + rc1.d/K01rpcbind | 1 + rc1.d/K01rsyslog | 1 + rc1.d/K01snmpd | 1 + rc1.d/K01tftpd-hpa | 1 + rc1.d/K01triggerhappy | 1 + rc1.d/K01xinetd | 1 + rc2.d/K01mosquitto | 1 + rc2.d/K01pihole-FTL | 1 + rc2.d/K01snmpd | 1 + rc2.d/S01avahi-daemon | 1 + rc2.d/S01bluetooth | 1 + rc2.d/S01console-setup.sh | 1 + rc2.d/S01cron | 1 + rc2.d/S01dbus | 1 + rc2.d/S01dhcpcd | 1 + rc2.d/S01docker | 1 + rc2.d/S01dphys-swapfile | 1 + rc2.d/S01exim4 | 1 + rc2.d/S01nginx | 1 + rc2.d/S01ntp | 1 + rc2.d/S01paxctld | 1 + rc2.d/S01php7.3-fpm | 1 + rc2.d/S01postgresql | 1 + rc2.d/S01raspi-config | 1 + rc2.d/S01redis-server | 1 + rc2.d/S01rng-tools | 1 + rc2.d/S01rsync | 1 + rc2.d/S01rsyslog | 1 + rc2.d/S01ssh | 1 + rc2.d/S01sudo | 1 + rc2.d/S01sysstat | 1 + rc2.d/S01tftpd-hpa | 1 + rc2.d/S01triggerhappy | 1 + rc2.d/S01xinetd | 1 + rc3.d/K01mosquitto | 1 + rc3.d/K01pihole-FTL | 1 + rc3.d/K01snmpd | 1 + rc3.d/S01avahi-daemon | 1 + rc3.d/S01bluetooth | 1 + rc3.d/S01console-setup.sh | 1 + rc3.d/S01cron | 1 + rc3.d/S01dbus | 1 + rc3.d/S01dhcpcd | 1 + rc3.d/S01docker | 1 + rc3.d/S01dphys-swapfile | 1 + rc3.d/S01exim4 | 1 + rc3.d/S01nginx | 1 + rc3.d/S01ntp | 1 + rc3.d/S01paxctld | 1 + rc3.d/S01php7.3-fpm | 1 + rc3.d/S01postgresql | 1 + rc3.d/S01raspi-config | 1 + rc3.d/S01redis-server | 1 + rc3.d/S01rng-tools | 1 + rc3.d/S01rsync | 1 + rc3.d/S01rsyslog | 1 + rc3.d/S01ssh | 1 + rc3.d/S01sudo | 1 + rc3.d/S01sysstat | 1 + rc3.d/S01tftpd-hpa | 1 + rc3.d/S01triggerhappy | 1 + rc3.d/S01xinetd | 1 + rc4.d/K01mosquitto | 1 + rc4.d/K01pihole-FTL | 1 + rc4.d/K01snmpd | 1 + rc4.d/S01avahi-daemon | 1 + rc4.d/S01bluetooth | 1 + rc4.d/S01console-setup.sh | 1 + rc4.d/S01cron | 1 + rc4.d/S01dbus | 1 + rc4.d/S01dhcpcd | 1 + rc4.d/S01docker | 1 + rc4.d/S01dphys-swapfile | 1 + rc4.d/S01exim4 | 1 + rc4.d/S01nginx | 1 + rc4.d/S01ntp | 1 + rc4.d/S01paxctld | 1 + rc4.d/S01php7.3-fpm | 1 + rc4.d/S01postgresql | 1 + rc4.d/S01raspi-config | 1 + rc4.d/S01redis-server | 1 + rc4.d/S01rng-tools | 1 + rc4.d/S01rsync | 1 + rc4.d/S01rsyslog | 1 + rc4.d/S01ssh | 1 + rc4.d/S01sudo | 1 + rc4.d/S01sysstat | 1 + rc4.d/S01tftpd-hpa | 1 + rc4.d/S01triggerhappy | 1 + rc4.d/S01xinetd | 1 + rc5.d/K01mosquitto | 1 + rc5.d/K01pihole-FTL | 1 + rc5.d/K01snmpd | 1 + rc5.d/S01avahi-daemon | 1 + rc5.d/S01bluetooth | 1 + rc5.d/S01console-setup.sh | 1 + rc5.d/S01cron | 1 + rc5.d/S01dbus | 1 + rc5.d/S01dhcpcd | 1 + rc5.d/S01docker | 1 + rc5.d/S01dphys-swapfile | 1 + rc5.d/S01exim4 | 1 + rc5.d/S01nginx | 1 + rc5.d/S01ntp | 1 + rc5.d/S01paxctld | 1 + rc5.d/S01php7.3-fpm | 1 + rc5.d/S01postgresql | 1 + rc5.d/S01raspi-config | 1 + rc5.d/S01redis-server | 1 + rc5.d/S01rng-tools | 1 + rc5.d/S01rsync | 1 + rc5.d/S01rsyslog | 1 + rc5.d/S01ssh | 1 + rc5.d/S01sudo | 1 + rc5.d/S01sysstat | 1 + rc5.d/S01tftpd-hpa | 1 + rc5.d/S01triggerhappy | 1 + rc5.d/S01xinetd | 1 + rc6.d/K01alsa-utils | 1 + rc6.d/K01avahi-daemon | 1 + rc6.d/K01bluetooth | 1 + rc6.d/K01dhcpcd | 1 + rc6.d/K01docker | 1 + rc6.d/K01exim4 | 1 + rc6.d/K01fake-hwclock | 1 + rc6.d/K01hwclock.sh | 1 + rc6.d/K01mosquitto | 1 + rc6.d/K01netfilter-persistent | 1 + rc6.d/K01networking | 1 + rc6.d/K01nfs-common | 1 + rc6.d/K01nginx | 1 + rc6.d/K01paxctld | 1 + rc6.d/K01php7.3-fpm | 1 + rc6.d/K01pihole-FTL | 1 + rc6.d/K01postgresql | 1 + rc6.d/K01redis-server | 1 + rc6.d/K01resolvconf | 1 + rc6.d/K01rng-tools | 1 + rc6.d/K01rpcbind | 1 + rc6.d/K01rsyslog | 1 + rc6.d/K01snmpd | 1 + rc6.d/K01tftpd-hpa | 1 + rc6.d/K01triggerhappy | 1 + rc6.d/K01udev | 1 + rc6.d/K01xinetd | 1 + rcS.d/K01hwclock.sh | 1 + rcS.d/K01nfs-common | 1 + rcS.d/K01rpcbind | 1 + rcS.d/S01alsa-utils | 1 + rcS.d/S01fake-hwclock | 1 + rcS.d/S01keyboard-setup.sh | 1 + rcS.d/S01kmod | 1 + rcS.d/S01netfilter-persistent | 1 + rcS.d/S01networking | 1 + rcS.d/S01procps | 1 + rcS.d/S01raspi-config | 1 + rcS.d/S01resolvconf | 1 + rcS.d/S01udev | 1 + rcS.d/S01x11-common | 1 + redis/redis.conf | 1378 +++ request-key.conf | 43 + request-key.d/cifs.idmap.conf | 1 + request-key.d/cifs.spnego.conf | 1 + request-key.d/id_resolver.conf | 1 + resolv.conf | 1 + resolv.conf.bak | 1 + resolvconf.conf | 13 + resolvconf/interface-order | 23 + resolvconf/resolv.conf.d/base | 0 resolvconf/resolv.conf.d/head | 2 + resolvconf/resolv.conf.d/original | 4 + resolvconf/resolv.conf.d/tail | 0 resolvconf/run | 1 + resolvconf/update.d/libc | 161 + rmt | 1 + rpc | 40 + rpi-issue | 2 + rsyslog-keys/ca.pem | 25 + rsyslog.conf | 92 + rsyslog.d/rsyslog-tls.conf | 9 + securetty | 412 + security/access.conf | 122 + security/group.conf | 106 + security/limits.conf | 56 + security/namespace.conf | 28 + security/namespace.init | 25 + security/opasswd | 0 security/pam_env.conf | 73 + security/sepermit.conf | 11 + security/time.conf | 65 + selinux/semanage.conf | 45 + sensors.d/.placeholder | 0 sensors3.conf | 536 ++ services | 578 ++ shadow | 41 + shadow- | 42 + shells | 5 + skel/.bash_logout | 7 + skel/.bashrc | 113 + skel/.profile | 27 + snmp-mibs-downloader/cisco.conf | 10 + snmp-mibs-downloader/ciscolist | 1431 ++++ snmp-mibs-downloader/iana.conf | 10 + snmp-mibs-downloader/ianalist | 14 + snmp-mibs-downloader/ianarfc.conf | 10 + snmp-mibs-downloader/ianarfclist | 4 + snmp-mibs-downloader/junos.conf | 10 + snmp-mibs-downloader/junoslist | 74 + snmp-mibs-downloader/rfc.conf | 13 + snmp-mibs-downloader/rfclist | 266 + snmp-mibs-downloader/rfcmibs.diff | 509 ++ snmp-mibs-downloader/screenos.conf | 10 + snmp-mibs-downloader/screenoslist | 47 + snmp-mibs-downloader/simplelist | 2 + snmp-mibs-downloader/simpleweb.conf | 7 + .../snmp-mibs-downloader.conf | 4 + snmp/snmp.conf | 4 + snmp/snmpd.conf | 196 + ssh/moduli | 427 + ssh/ssh_config | 51 + ssh/ssh_host_dsa_key | 21 + ssh/ssh_host_dsa_key.pub | 1 + ssh/ssh_host_ecdsa_key | 9 + ssh/ssh_host_ecdsa_key.pub | 1 + ssh/ssh_host_ed25519_key | 7 + ssh/ssh_host_ed25519_key.pub | 1 + ssh/ssh_host_rsa_key | 27 + ssh/ssh_host_rsa_key.pub | 1 + ssh/ssh_import_id | 4 + ssh/sshd_config | 121 + ssl/certs/02265526.0 | 1 + ssl/certs/03179a64.0 | 1 + ssl/certs/062cdee6.0 | 1 + ssl/certs/064e0aa9.0 | 1 + ssl/certs/06dc52d5.0 | 1 + ssl/certs/080911ac.0 | 1 + ssl/certs/09789157.0 | 1 + ssl/certs/0a775a30.0 | 1 + ssl/certs/0b1b94ef.0 | 1 + ssl/certs/0bf05006.0 | 1 + ssl/certs/0c4c9b6c.0 | 1 + ssl/certs/0f5dc4f3.0 | 1 + ssl/certs/0f6fa695.0 | 1 + ssl/certs/1001acf7.0 | 1 + ssl/certs/106f3e4d.0 | 1 + ssl/certs/128805a3.0 | 1 + ssl/certs/14bc7599.0 | 1 + ssl/certs/1636090b.0 | 1 + ssl/certs/18856ac4.0 | 1 + ssl/certs/1d3472b9.0 | 1 + ssl/certs/1e08bfd1.0 | 1 + ssl/certs/1e09d511.0 | 1 + ssl/certs/244b5494.0 | 1 + ssl/certs/2923b3f9.0 | 1 + ssl/certs/2ae6433e.0 | 1 + ssl/certs/2b349938.0 | 1 + ssl/certs/2e5ac55d.0 | 1 + ssl/certs/32888f65.0 | 1 + ssl/certs/349f2832.0 | 1 + ssl/certs/3513523f.0 | 1 + ssl/certs/3bde41ac.0 | 1 + ssl/certs/3e44d2f7.0 | 1 + ssl/certs/3e45d192.0 | 1 + ssl/certs/40193066.0 | 1 + ssl/certs/4042bcee.0 | 1 + ssl/certs/40547a79.0 | 1 + ssl/certs/406c9bb1.0 | 1 + ssl/certs/4304c5e5.0 | 1 + ssl/certs/48bec511.0 | 1 + ssl/certs/4a6481c9.0 | 1 + ssl/certs/4b718d9b.0 | 1 + ssl/certs/4bfab552.0 | 1 + ssl/certs/4ed8e614 | 1 + ssl/certs/4f316efb.0 | 1 + ssl/certs/5273a94c.0 | 1 + ssl/certs/5443e9e3.0 | 1 + ssl/certs/54657681.0 | 1 + ssl/certs/57bcb2da.0 | 1 + ssl/certs/5a4d6896.0 | 1 + ssl/certs/5ad8a5d6.0 | 1 + ssl/certs/5c44d531.0 | 1 + ssl/certs/5cd81ad7.0 | 1 + ssl/certs/5d3033c5.0 | 1 + ssl/certs/5e98733a.0 | 1 + ssl/certs/5f15c80c.0 | 1 + ssl/certs/607986c7.0 | 1 + ssl/certs/626dceaf.0 | 1 + ssl/certs/6410666e.0 | 1 + ssl/certs/653b494a.0 | 1 + ssl/certs/68dd7389.0 | 1 + ssl/certs/6b99d060.0 | 1 + ssl/certs/6d41d539.0 | 1 + ssl/certs/6fa5da56.0 | 1 + ssl/certs/706f604c.0 | 1 + ssl/certs/749e9e03.0 | 1 + ssl/certs/75d1b2ed.0 | 1 + ssl/certs/76cb8f92.0 | 1 + ssl/certs/76faf6c0.0 | 1 + ssl/certs/7719f463.0 | 1 + ssl/certs/773e07ad.0 | 1 + ssl/certs/7aaf71c0.0 | 1 + ssl/certs/7f3d5d1d.0 | 1 + ssl/certs/8160b96c.0 | 1 + ssl/certs/8867006a.0 | 1 + ssl/certs/8cb5ee0f.0 | 1 + ssl/certs/8d86cdd1.0 | 1 + ssl/certs/930ac5d2.0 | 1 + ssl/certs/93bc0acc.0 | 1 + ssl/certs/988a38cb.0 | 1 + ssl/certs/9c2e7d30.0 | 1 + ssl/certs/9c8dfbd4.0 | 1 + ssl/certs/9d04f354.0 | 1 + ssl/certs/ACCVRAIZ1.pem | 1 + ssl/certs/AC_RAIZ_FNMT-RCM.pem | 1 + ssl/certs/Actalis_Authentication_Root_CA.pem | 1 + ssl/certs/AffirmTrust_Commercial.pem | 1 + ssl/certs/AffirmTrust_Networking.pem | 1 + ssl/certs/AffirmTrust_Premium.pem | 1 + ssl/certs/AffirmTrust_Premium_ECC.pem | 1 + ssl/certs/Amazon_Root_CA_1.pem | 1 + ssl/certs/Amazon_Root_CA_2.pem | 1 + ssl/certs/Amazon_Root_CA_3.pem | 1 + ssl/certs/Amazon_Root_CA_4.pem | 1 + ssl/certs/Atos_TrustedRoot_2011.pem | 1 + ...icacion_Firmaprofesional_CIF_A62634068.pem | 1 + ssl/certs/Baltimore_CyberTrust_Root.pem | 1 + ssl/certs/Buypass_Class_2_Root_CA.pem | 1 + ssl/certs/Buypass_Class_3_Root_CA.pem | 1 + ssl/certs/CA_Disig_Root_R2.pem | 1 + ssl/certs/CFCA_EV_ROOT.pem | 1 + ssl/certs/COMODO_Certification_Authority.pem | 1 + .../COMODO_ECC_Certification_Authority.pem | 1 + .../COMODO_RSA_Certification_Authority.pem | 1 + ssl/certs/Certigna.pem | 1 + ssl/certs/Certigna_Root_CA.pem | 1 + ssl/certs/Certum_Trusted_Network_CA.pem | 1 + ssl/certs/Certum_Trusted_Network_CA_2.pem | 1 + .../Chambers_of_Commerce_Root_-_2008.pem | 1 + ssl/certs/Comodo_AAA_Services_root.pem | 1 + ssl/certs/Cybertrust_Global_Root.pem | 1 + ssl/certs/D-TRUST_Root_Class_3_CA_2_2009.pem | 1 + .../D-TRUST_Root_Class_3_CA_2_EV_2009.pem | 1 + ssl/certs/DST_Root_CA_X3.pem | 1 + ssl/certs/DigiCert_Assured_ID_Root_CA.pem | 1 + ssl/certs/DigiCert_Assured_ID_Root_G2.pem | 1 + ssl/certs/DigiCert_Assured_ID_Root_G3.pem | 1 + ssl/certs/DigiCert_Global_Root_CA.pem | 1 + ssl/certs/DigiCert_Global_Root_G2.pem | 1 + ssl/certs/DigiCert_Global_Root_G3.pem | 1 + .../DigiCert_High_Assurance_EV_Root_CA.pem | 1 + ssl/certs/DigiCert_Trusted_Root_G4.pem | 1 + ssl/certs/E-Tugra_Certification_Authority.pem | 1 + ssl/certs/EC-ACC.pem | 1 + ssl/certs/EE_Certification_Centre_Root_CA.pem | 1 + ...rust.net_Premium_2048_Secure_Server_CA.pem | 1 + .../Entrust_Root_Certification_Authority.pem | 1 + ...ust_Root_Certification_Authority_-_EC1.pem | 1 + ...rust_Root_Certification_Authority_-_G2.pem | 1 + ...rust_Root_Certification_Authority_-_G4.pem | 1 + ssl/certs/GDCA_TrustAUTH_R5_ROOT.pem | 1 + ssl/certs/GTS_Root_R1.pem | 1 + ssl/certs/GTS_Root_R2.pem | 1 + ssl/certs/GTS_Root_R3.pem | 1 + ssl/certs/GTS_Root_R4.pem | 1 + ssl/certs/GeoTrust_Universal_CA_2.pem | 1 + ssl/certs/GlobalSign_ECC_Root_CA_-_R4.pem | 1 + ssl/certs/GlobalSign_ECC_Root_CA_-_R5.pem | 1 + ssl/certs/GlobalSign_Root_CA.pem | 1 + ssl/certs/GlobalSign_Root_CA_-_R2.pem | 1 + ssl/certs/GlobalSign_Root_CA_-_R3.pem | 1 + ssl/certs/GlobalSign_Root_CA_-_R6.pem | 1 + ssl/certs/Global_Chambersign_Root_-_2008.pem | 1 + ssl/certs/Go_Daddy_Class_2_CA.pem | 1 + ..._Daddy_Root_Certificate_Authority_-_G2.pem | 1 + ..._Research_Institutions_ECC_RootCA_2015.pem | 1 + ..._and_Research_Institutions_RootCA_2011.pem | 1 + ..._and_Research_Institutions_RootCA_2015.pem | 1 + ssl/certs/Hongkong_Post_Root_CA_1.pem | 1 + ssl/certs/Hongkong_Post_Root_CA_3.pem | 1 + ssl/certs/ISRG_Root_X1.pem | 1 + ssl/certs/IdenTrust_Commercial_Root_CA_1.pem | 1 + .../IdenTrust_Public_Sector_Root_CA_1.pem | 1 + ssl/certs/Izenpe.com.pem | 1 + ssl/certs/LuxTrust_Global_Root_2.pem | 1 + ssl/certs/Microsec_e-Szigno_Root_CA_2009.pem | 1 + ...tLock_Arany_=Class_Gold=_Főtanúsítvány.pem | 1 + ...etwork_Solutions_Certificate_Authority.pem | 1 + ssl/certs/OISTE_WISeKey_Global_Root_GA_CA.pem | 1 + ssl/certs/OISTE_WISeKey_Global_Root_GB_CA.pem | 1 + ssl/certs/OISTE_WISeKey_Global_Root_GC_CA.pem | 1 + ssl/certs/QuoVadis_Root_CA.pem | 1 + ssl/certs/QuoVadis_Root_CA_1_G3.pem | 1 + ssl/certs/QuoVadis_Root_CA_2.pem | 1 + ssl/certs/QuoVadis_Root_CA_2_G3.pem | 1 + ssl/certs/QuoVadis_Root_CA_3.pem | 1 + ssl/certs/QuoVadis_Root_CA_3_G3.pem | 1 + ...om_EV_Root_Certification_Authority_ECC.pem | 1 + ...EV_Root_Certification_Authority_RSA_R2.pem | 1 + ...L.com_Root_Certification_Authority_ECC.pem | 1 + ...L.com_Root_Certification_Authority_RSA.pem | 1 + ssl/certs/SZAFIR_ROOT_CA2.pem | 1 + ssl/certs/SecureSign_RootCA11.pem | 1 + ssl/certs/SecureTrust_CA.pem | 1 + ssl/certs/Secure_Global_CA.pem | 1 + ssl/certs/Security_Communication_RootCA2.pem | 1 + ssl/certs/Security_Communication_Root_CA.pem | 1 + ssl/certs/Sonera_Class_2_Root_CA.pem | 1 + .../Staat_der_Nederlanden_EV_Root_CA.pem | 1 + .../Staat_der_Nederlanden_Root_CA_-_G2.pem | 1 + .../Staat_der_Nederlanden_Root_CA_-_G3.pem | 1 + ssl/certs/Starfield_Class_2_CA.pem | 1 + ...rfield_Root_Certificate_Authority_-_G2.pem | 1 + ...rvices_Root_Certificate_Authority_-_G2.pem | 1 + ssl/certs/SwissSign_Gold_CA_-_G2.pem | 1 + ssl/certs/SwissSign_Silver_CA_-_G2.pem | 1 + ssl/certs/T-TeleSec_GlobalRoot_Class_2.pem | 1 + ssl/certs/T-TeleSec_GlobalRoot_Class_3.pem | 1 + ..._Kamu_SM_SSL_Kok_Sertifikasi_-_Surum_1.pem | 1 + ssl/certs/TWCA_Global_Root_CA.pem | 1 + .../TWCA_Root_Certification_Authority.pem | 1 + ssl/certs/Taiwan_GRCA.pem | 1 + ssl/certs/TeliaSonera_Root_CA_v1.pem | 1 + ssl/certs/TrustCor_ECA-1.pem | 1 + ssl/certs/TrustCor_RootCert_CA-1.pem | 1 + ssl/certs/TrustCor_RootCert_CA-2.pem | 1 + ssl/certs/Trustis_FPS_Root_CA.pem | 1 + ssl/certs/UCA_Extended_Validation_Root.pem | 1 + ssl/certs/UCA_Global_G2_Root.pem | 1 + .../USERTrust_ECC_Certification_Authority.pem | 1 + .../USERTrust_RSA_Certification_Authority.pem | 1 + ...c_Primary_Certification_Authority_-_G3.pem | 1 + ssl/certs/XRamp_Global_CA_Root.pem | 1 + ssl/certs/a3418fda.0 | 1 + ssl/certs/a94d09e5.0 | 1 + ssl/certs/aee5f10d.0 | 1 + ssl/certs/b0e59380.0 | 1 + ssl/certs/b1159c4c.0 | 1 + ssl/certs/b1b8a7f3.0 | 1 + ssl/certs/b66938e9.0 | 1 + ssl/certs/b727005e.0 | 1 + ssl/certs/b7a5b843.0 | 1 + ssl/certs/c01eb047.0 | 1 + ssl/certs/c0ff1f52.0 | 1 + ssl/certs/c28a8a30.0 | 1 + ssl/certs/c47d9980.0 | 1 + ssl/certs/ca-certificates.crt | 3256 +++++++ ssl/certs/ca6e4ad9.0 | 1 + ssl/certs/cbf06781.0 | 1 + ssl/certs/cc450945.0 | 1 + ssl/certs/cd58d51e.0 | 1 + ssl/certs/cd8c0d63.0 | 1 + ssl/certs/ce5e74ef.0 | 1 + ssl/certs/certSIGN_ROOT_CA.pem | 1 + ssl/certs/d4dae3dd.0 | 1 + ssl/certs/d6325660.0 | 1 + ssl/certs/d7e8dc79.0 | 1 + ssl/certs/d853d49e.0 | 1 + ssl/certs/dc4d6a89.0 | 1 + ssl/certs/dd8e9d41.0 | 1 + ssl/certs/de6d66f3.0 | 1 + ssl/certs/def36a68.0 | 1 + ssl/certs/e113c810.0 | 1 + ssl/certs/e18bfb83.0 | 1 + ssl/certs/e36a6752.0 | 1 + ssl/certs/e73d606e.0 | 1 + ssl/certs/e8de2f56.0 | 1 + .../ePKI_Root_Certification_Authority.pem | 1 + ssl/certs/ee64a828.0 | 1 + ssl/certs/eed8c118.0 | 1 + ssl/certs/ef954a4e.0 | 1 + ssl/certs/emSign_ECC_Root_CA_-_C3.pem | 1 + ssl/certs/emSign_ECC_Root_CA_-_G3.pem | 1 + ssl/certs/emSign_Root_CA_-_C1.pem | 1 + ssl/certs/emSign_Root_CA_-_G1.pem | 1 + ssl/certs/f081611a.0 | 1 + ssl/certs/f0c70a8d.0 | 1 + ssl/certs/f30dd6ad.0 | 1 + ssl/certs/f3377b1b.0 | 1 + ssl/certs/f387163d.0 | 1 + ssl/certs/f39fc864.0 | 1 + ssl/certs/f51bb24c.0 | 1 + ssl/certs/fc5a8f99.0 | 1 + ssl/certs/fe8a2cd8.0 | 1 + ssl/certs/ff34af3f.0 | 1 + ssl/certs/java/cacerts | Bin 0 -> 150031 bytes ssl/certs/ssl-cert-snakeoil.pem | 18 + ssl/openssl.cnf | 362 + ssl/private/ssl-cert-snakeoil.key | 28 + subgid | 2 + subgid- | 1 + subuid | 2 + subuid- | 1 + sudoers | 27 + sudoers.d/010_at-export | 1 + sudoers.d/010_pi-nopasswd | 1 + sudoers.d/010_proxy | 5 + sudoers.d/README | 21 + sudoers.d/iobroker | 25 + sysctl.conf | 71 + sysctl.d/30-postgresql-shm.conf | 12 + sysctl.d/98-rpi.conf | 3 + sysctl.d/99-sysctl.conf | 1 + sysctl.d/README.sysctl | 13 + sysctl.d/protect-links.conf | 8 + sysstat/sysstat | 31 + sysstat/sysstat.ioconf | 273 + systemd/journald.conf | 43 + systemd/logind.conf | 37 + systemd/network/99-default.link | 1 + systemd/networkd.conf | 16 + systemd/resolved.conf | 24 + systemd/sleep.conf | 25 + systemd/system.conf | 64 + systemd/system/AdGuardHome.service | 22 + systemd/system/autologin@.service | 47 + .../bluetooth.target.wants/bluetooth.service | 1 + systemd/system/check-mk-agent-async.service | 14 + systemd/system/check-mk-agent.socket | 11 + systemd/system/check-mk-agent@.service | 16 + .../system/dbus-fi.w1.wpa_supplicant1.service | 1 + systemd/system/dbus-org.bluez.service | 1 + .../system/dbus-org.freedesktop.Avahi.service | 1 + .../dbus-org.freedesktop.timesync1.service | 1 + systemd/system/dhcpcd.service.d/wait.conf | 3 + systemd/system/dhcpcd5.service | 1 + .../getty.target.wants/getty@tty1.service | 1 + .../system/getty@tty1.service.d/noclear.conf | 2 + systemd/system/gitea.service | 83 + .../rpi-display-backlight.service | 1 + systemd/system/mosquitto.service | 1 + .../AdGuardHome.service | 1 + .../avahi-daemon.service | 1 + .../check-mk-agent-async.service | 1 + .../console-setup.service | 1 + .../containerd.service | 1 + .../multi-user.target.wants/cron.service | 1 + .../multi-user.target.wants/dhcpcd.service | 1 + .../multi-user.target.wants/docker.service | 1 + .../dphys-swapfile.service | 1 + .../multi-user.target.wants/etckeeper.timer | 1 + .../multi-user.target.wants/gitea.service | 1 + .../multi-user.target.wants/hciuart.service | 1 + .../multi-user.target.wants/mosquitto.service | 1 + .../netfilter-persistent.service | 1 + .../networking.service | 1 + .../multi-user.target.wants/nfs-client.target | 1 + .../multi-user.target.wants/nginx.service | 1 + .../multi-user.target.wants/ntp.service | 1 + .../php7.3-fpm.service | 1 + .../postgresql.service | 1 + .../raspberrypi-net-mods.service | 1 + .../redis-server.service | 1 + .../multi-user.target.wants/remote-fs.target | 1 + .../rpi-eeprom-update.service | 1 + .../multi-user.target.wants/rsync.service | 1 + .../multi-user.target.wants/rsyslog.service | 1 + .../multi-user.target.wants/ssh.service | 1 + .../multi-user.target.wants/sshswitch.service | 1 + .../multi-user.target.wants/sysstat.service | 1 + .../triggerhappy.service | 1 + .../wpa_supplicant.service | 1 + systemd/system/netfilter-persistent.service | 1 + .../networking.service | 1 + .../rpi-display-backlight.service | 1 + .../system/rc-local.service.d/ttyoutput.conf | 2 + .../rpi-display-backlight.service | 1 + .../remote-fs.target.wants/nfs-client.target | 1 + .../sockets.target.wants/avahi-daemon.socket | 1 + .../check-mk-agent.socket | 1 + .../system/sockets.target.wants/docker.socket | 1 + .../sockets.target.wants/triggerhappy.socket | 1 + systemd/system/sshd.service | 1 + .../sysinit.target.wants/fake-hwclock.service | 1 + .../keyboard-setup.service | 1 + .../sysinit.target.wants/resolvconf.service | 1 + .../systemd-timesyncd.service | 1 + systemd/system/syslog.service | 1 + .../apt-daily-upgrade.timer | 1 + .../timers.target.wants/apt-daily.timer | 1 + .../timers.target.wants/logrotate.timer | 1 + .../system/timers.target.wants/man-db.timer | 1 + .../timers.target.wants/phpsessionclean.timer | 1 + systemd/timesyncd.conf | 19 + systemd/user.conf | 44 + terminfo/README | 3 + timezone | 1 + ucf.conf | 39 + udev/rules.d/99-com.rules | 56 + udev/udev.conf | 10 + ufw/applications.d/nginx | 14 + ufw/applications.d/openssh-server | 4 + update-motd.d/00-motd | 3 + usb_modeswitch.conf | 40 + vim/vimrc | 55 + vim/vimrc.tiny | 13 + wgetrc | 138 + wireguard_2021-01-28-103503.tar.gz | Bin 0 -> 119 bytes wireshark/init.lua | 703 ++ wpa_supplicant/action_wpa.sh | 50 + wpa_supplicant/functions.sh | 993 +++ wpa_supplicant/ifupdown.sh | 172 + wpa_supplicant/wpa_supplicant.conf | 10 + xattr.conf | 21 + xdg/autostart/xdg-user-dirs.desktop | 10 + xdg/systemd/user | 1 + xdg/user-dirs.conf | 11 + xdg/user-dirs.defaults | 16 + xinetd.conf | 14 + xinetd.d/chargen | 28 + xinetd.d/chargen-udp | 14 + xinetd.d/daytime | 26 + xinetd.d/daytime-udp | 14 + xinetd.d/discard | 25 + xinetd.d/discard-udp | 14 + xinetd.d/echo | 26 + xinetd.d/echo-udp | 14 + xinetd.d/servers | 13 + xinetd.d/services | 13 + xinetd.d/time | 28 + xinetd.d/time-udp | 14 + 1990 files changed, 91001 insertions(+) create mode 100755 .etckeeper create mode 100644 .fstab create mode 100644 .gitignore create mode 100644 .java/.systemPrefs/.system.lock create mode 100644 .java/.systemPrefs/.systemRootModFile create mode 100644 ImageMagick-6/coder.xml create mode 100644 ImageMagick-6/colors.xml create mode 100644 ImageMagick-6/delegates.xml create mode 100644 ImageMagick-6/log.xml create mode 100644 ImageMagick-6/magic.xml create mode 100644 ImageMagick-6/mime.xml create mode 100644 ImageMagick-6/policy.xml create mode 100644 ImageMagick-6/quantization-table.xml create mode 100644 ImageMagick-6/thresholds.xml create mode 100644 ImageMagick-6/type-apple.xml create mode 100644 ImageMagick-6/type-dejavu.xml create mode 100644 ImageMagick-6/type-ghostscript.xml create mode 100644 ImageMagick-6/type-urw-base35.xml create mode 100644 ImageMagick-6/type-windows.xml create mode 100644 ImageMagick-6/type.xml create mode 100755 NetworkManager/dispatcher.d/ntp create mode 100755 X11/Xreset create mode 100644 X11/Xreset.d/README create mode 100644 X11/Xresources/x11-common create mode 100755 X11/Xsession create mode 100644 X11/Xsession.d/20x11-common_process-args create mode 100644 X11/Xsession.d/30x11-common_xresources create mode 100644 X11/Xsession.d/35x11-common_xhost-local create mode 100644 X11/Xsession.d/40x11-common_xsessionrc create mode 100644 X11/Xsession.d/50x11-common_determine-startup create mode 100644 X11/Xsession.d/90gpg-agent create mode 100644 X11/Xsession.d/90x11-common_ssh-agent create mode 100644 X11/Xsession.d/99x11-common_start create mode 100644 X11/Xsession.options create mode 100644 X11/rgb.txt create mode 100644 adduser.conf create mode 100644 aliases create mode 120000 alternatives/ABORT.7.gz create mode 120000 alternatives/ALTER_AGGREGATE.7.gz create mode 120000 alternatives/ALTER_COLLATION.7.gz create mode 120000 alternatives/ALTER_CONVERSION.7.gz create mode 120000 alternatives/ALTER_DATABASE.7.gz create mode 120000 alternatives/ALTER_DEFAULT_PRIVILEGES.7.gz create mode 120000 alternatives/ALTER_DOMAIN.7.gz create mode 120000 alternatives/ALTER_EVENT_TRIGGER.7.gz create mode 120000 alternatives/ALTER_EXTENSION.7.gz create mode 120000 alternatives/ALTER_FOREIGN_DATA_WRAPPER.7.gz create mode 120000 alternatives/ALTER_FOREIGN_TABLE.7.gz create mode 120000 alternatives/ALTER_FUNCTION.7.gz create mode 120000 alternatives/ALTER_GROUP.7.gz create mode 120000 alternatives/ALTER_INDEX.7.gz create mode 120000 alternatives/ALTER_LANGUAGE.7.gz create mode 120000 alternatives/ALTER_LARGE_OBJECT.7.gz create mode 120000 alternatives/ALTER_MATERIALIZED_VIEW.7.gz create mode 120000 alternatives/ALTER_OPERATOR.7.gz create mode 120000 alternatives/ALTER_OPERATOR_CLASS.7.gz create mode 120000 alternatives/ALTER_OPERATOR_FAMILY.7.gz create mode 120000 alternatives/ALTER_POLICY.7.gz create mode 120000 alternatives/ALTER_PROCEDURE.7.gz create mode 120000 alternatives/ALTER_PUBLICATION.7.gz create mode 120000 alternatives/ALTER_ROLE.7.gz create mode 120000 alternatives/ALTER_ROUTINE.7.gz create mode 120000 alternatives/ALTER_RULE.7.gz create mode 120000 alternatives/ALTER_SCHEMA.7.gz create mode 120000 alternatives/ALTER_SEQUENCE.7.gz create mode 120000 alternatives/ALTER_SERVER.7.gz create mode 120000 alternatives/ALTER_STATISTICS.7.gz create mode 120000 alternatives/ALTER_SUBSCRIPTION.7.gz create mode 120000 alternatives/ALTER_SYSTEM.7.gz create mode 120000 alternatives/ALTER_TABLE.7.gz create mode 120000 alternatives/ALTER_TABLESPACE.7.gz create mode 120000 alternatives/ALTER_TEXT_SEARCH_CONFIGURATION.7.gz create mode 120000 alternatives/ALTER_TEXT_SEARCH_DICTIONARY.7.gz create mode 120000 alternatives/ALTER_TEXT_SEARCH_PARSER.7.gz create mode 120000 alternatives/ALTER_TEXT_SEARCH_TEMPLATE.7.gz create mode 120000 alternatives/ALTER_TRIGGER.7.gz create mode 120000 alternatives/ALTER_TYPE.7.gz create mode 120000 alternatives/ALTER_USER.7.gz create mode 120000 alternatives/ALTER_USER_MAPPING.7.gz create mode 120000 alternatives/ALTER_VIEW.7.gz create mode 120000 alternatives/ANALYZE.7.gz create mode 120000 alternatives/BEGIN.7.gz create mode 120000 alternatives/CALL.7.gz create mode 120000 alternatives/CHECKPOINT.7.gz create mode 120000 alternatives/CLOSE.7.gz create mode 120000 alternatives/CLUSTER.7.gz create mode 120000 alternatives/COMMENT.7.gz create mode 120000 alternatives/COMMIT.7.gz create mode 120000 alternatives/COMMIT_PREPARED.7.gz create mode 120000 alternatives/COPY.7.gz create mode 120000 alternatives/CREATE_ACCESS_METHOD.7.gz create mode 120000 alternatives/CREATE_AGGREGATE.7.gz create mode 120000 alternatives/CREATE_CAST.7.gz create mode 120000 alternatives/CREATE_COLLATION.7.gz create mode 120000 alternatives/CREATE_CONVERSION.7.gz create mode 120000 alternatives/CREATE_DATABASE.7.gz create mode 120000 alternatives/CREATE_DOMAIN.7.gz create mode 120000 alternatives/CREATE_EVENT_TRIGGER.7.gz create mode 120000 alternatives/CREATE_EXTENSION.7.gz create mode 120000 alternatives/CREATE_FOREIGN_DATA_WRAPPER.7.gz create mode 120000 alternatives/CREATE_FOREIGN_TABLE.7.gz create mode 120000 alternatives/CREATE_FUNCTION.7.gz create mode 120000 alternatives/CREATE_GROUP.7.gz create mode 120000 alternatives/CREATE_INDEX.7.gz create mode 120000 alternatives/CREATE_LANGUAGE.7.gz create mode 120000 alternatives/CREATE_MATERIALIZED_VIEW.7.gz create mode 120000 alternatives/CREATE_OPERATOR.7.gz create mode 120000 alternatives/CREATE_OPERATOR_CLASS.7.gz create mode 120000 alternatives/CREATE_OPERATOR_FAMILY.7.gz create mode 120000 alternatives/CREATE_POLICY.7.gz create mode 120000 alternatives/CREATE_PROCEDURE.7.gz create mode 120000 alternatives/CREATE_PUBLICATION.7.gz create mode 120000 alternatives/CREATE_ROLE.7.gz create mode 120000 alternatives/CREATE_RULE.7.gz create mode 120000 alternatives/CREATE_SCHEMA.7.gz create mode 120000 alternatives/CREATE_SEQUENCE.7.gz create mode 120000 alternatives/CREATE_SERVER.7.gz create mode 120000 alternatives/CREATE_STATISTICS.7.gz create mode 120000 alternatives/CREATE_SUBSCRIPTION.7.gz create mode 120000 alternatives/CREATE_TABLE.7.gz create mode 120000 alternatives/CREATE_TABLESPACE.7.gz create mode 120000 alternatives/CREATE_TABLE_AS.7.gz create mode 120000 alternatives/CREATE_TEXT_SEARCH_CONFIGURATION.7.gz create mode 120000 alternatives/CREATE_TEXT_SEARCH_DICTIONARY.7.gz create mode 120000 alternatives/CREATE_TEXT_SEARCH_PARSER.7.gz create mode 120000 alternatives/CREATE_TEXT_SEARCH_TEMPLATE.7.gz create mode 120000 alternatives/CREATE_TRANSFORM.7.gz create mode 120000 alternatives/CREATE_TRIGGER.7.gz create mode 120000 alternatives/CREATE_TYPE.7.gz create mode 120000 alternatives/CREATE_USER.7.gz create mode 120000 alternatives/CREATE_USER_MAPPING.7.gz create mode 120000 alternatives/CREATE_VIEW.7.gz create mode 120000 alternatives/DEALLOCATE.7.gz create mode 120000 alternatives/DECLARE.7.gz create mode 120000 alternatives/DELETE.7.gz create mode 120000 alternatives/DISCARD.7.gz create mode 120000 alternatives/DO.7.gz create mode 120000 alternatives/DROP_ACCESS_METHOD.7.gz create mode 120000 alternatives/DROP_AGGREGATE.7.gz create mode 120000 alternatives/DROP_CAST.7.gz create mode 120000 alternatives/DROP_COLLATION.7.gz create mode 120000 alternatives/DROP_CONVERSION.7.gz create mode 120000 alternatives/DROP_DATABASE.7.gz create mode 120000 alternatives/DROP_DOMAIN.7.gz create mode 120000 alternatives/DROP_EVENT_TRIGGER.7.gz create mode 120000 alternatives/DROP_EXTENSION.7.gz create mode 120000 alternatives/DROP_FOREIGN_DATA_WRAPPER.7.gz create mode 120000 alternatives/DROP_FOREIGN_TABLE.7.gz create mode 120000 alternatives/DROP_FUNCTION.7.gz create mode 120000 alternatives/DROP_GROUP.7.gz create mode 120000 alternatives/DROP_INDEX.7.gz create mode 120000 alternatives/DROP_LANGUAGE.7.gz create mode 120000 alternatives/DROP_MATERIALIZED_VIEW.7.gz create mode 120000 alternatives/DROP_OPERATOR.7.gz create mode 120000 alternatives/DROP_OPERATOR_CLASS.7.gz create mode 120000 alternatives/DROP_OPERATOR_FAMILY.7.gz create mode 120000 alternatives/DROP_OWNED.7.gz create mode 120000 alternatives/DROP_POLICY.7.gz create mode 120000 alternatives/DROP_PROCEDURE.7.gz create mode 120000 alternatives/DROP_PUBLICATION.7.gz create mode 120000 alternatives/DROP_ROLE.7.gz create mode 120000 alternatives/DROP_ROUTINE.7.gz create mode 120000 alternatives/DROP_RULE.7.gz create mode 120000 alternatives/DROP_SCHEMA.7.gz create mode 120000 alternatives/DROP_SEQUENCE.7.gz create mode 120000 alternatives/DROP_SERVER.7.gz create mode 120000 alternatives/DROP_STATISTICS.7.gz create mode 120000 alternatives/DROP_SUBSCRIPTION.7.gz create mode 120000 alternatives/DROP_TABLE.7.gz create mode 120000 alternatives/DROP_TABLESPACE.7.gz create mode 120000 alternatives/DROP_TEXT_SEARCH_CONFIGURATION.7.gz create mode 120000 alternatives/DROP_TEXT_SEARCH_DICTIONARY.7.gz create mode 120000 alternatives/DROP_TEXT_SEARCH_PARSER.7.gz create mode 120000 alternatives/DROP_TEXT_SEARCH_TEMPLATE.7.gz create mode 120000 alternatives/DROP_TRANSFORM.7.gz create mode 120000 alternatives/DROP_TRIGGER.7.gz create mode 120000 alternatives/DROP_TYPE.7.gz create mode 120000 alternatives/DROP_USER.7.gz create mode 120000 alternatives/DROP_USER_MAPPING.7.gz create mode 120000 alternatives/DROP_VIEW.7.gz create mode 120000 alternatives/END.7.gz create mode 120000 alternatives/EXECUTE.7.gz create mode 120000 alternatives/EXPLAIN.7.gz create mode 120000 alternatives/FETCH.7.gz create mode 120000 alternatives/GRANT.7.gz create mode 120000 alternatives/IMPORT_FOREIGN_SCHEMA.7.gz create mode 120000 alternatives/INSERT.7.gz create mode 120000 alternatives/LISTEN.7.gz create mode 120000 alternatives/LOAD.7.gz create mode 120000 alternatives/LOCK.7.gz create mode 120000 alternatives/MOVE.7.gz create mode 120000 alternatives/NOTIFY.7.gz create mode 120000 alternatives/PREPARE.7.gz create mode 120000 alternatives/PREPARE_TRANSACTION.7.gz create mode 100644 alternatives/README create mode 120000 alternatives/REASSIGN_OWNED.7.gz create mode 120000 alternatives/REFRESH_MATERIALIZED_VIEW.7.gz create mode 120000 alternatives/REINDEX.7.gz create mode 120000 alternatives/RELEASE_SAVEPOINT.7.gz create mode 120000 alternatives/RESET.7.gz create mode 120000 alternatives/REVOKE.7.gz create mode 120000 alternatives/ROLLBACK.7.gz create mode 120000 alternatives/ROLLBACK_PREPARED.7.gz create mode 120000 alternatives/ROLLBACK_TO_SAVEPOINT.7.gz create mode 120000 alternatives/SAVEPOINT.7.gz create mode 120000 alternatives/SECURITY_LABEL.7.gz create mode 120000 alternatives/SELECT.7.gz create mode 120000 alternatives/SELECT_INTO.7.gz create mode 120000 alternatives/SET.7.gz create mode 120000 alternatives/SET_CONSTRAINTS.7.gz create mode 120000 alternatives/SET_ROLE.7.gz create mode 120000 alternatives/SET_SESSION_AUTHORIZATION.7.gz create mode 120000 alternatives/SET_TRANSACTION.7.gz create mode 120000 alternatives/SHOW.7.gz create mode 120000 alternatives/START_TRANSACTION.7.gz create mode 120000 alternatives/TABLE.7.gz create mode 120000 alternatives/TRUNCATE.7.gz create mode 120000 alternatives/UNLISTEN.7.gz create mode 120000 alternatives/UPDATE.7.gz create mode 120000 alternatives/VACUUM.7.gz create mode 120000 alternatives/VALUES.7.gz create mode 120000 alternatives/WITH.7.gz create mode 120000 alternatives/arptables create mode 120000 alternatives/arptables-restore create mode 120000 alternatives/arptables-save create mode 120000 alternatives/awk create mode 120000 alternatives/awk.1.gz create mode 120000 alternatives/builtins.7.gz create mode 120000 alternatives/c++ create mode 120000 alternatives/c89 create mode 120000 alternatives/c89.1.gz create mode 120000 alternatives/c99 create mode 120000 alternatives/c99.1.gz create mode 120000 alternatives/cc create mode 120000 alternatives/clusterdb.1.gz create mode 120000 alternatives/cpp create mode 120000 alternatives/createdb.1.gz create mode 120000 alternatives/createuser.1.gz create mode 120000 alternatives/dhcpcd create mode 120000 alternatives/dhcpcd.8.gz create mode 120000 alternatives/dotlock create mode 120000 alternatives/dotlock.1.gz create mode 120000 alternatives/dropdb.1.gz create mode 120000 alternatives/dropuser.1.gz create mode 120000 alternatives/ebtables create mode 120000 alternatives/ebtables-restore create mode 120000 alternatives/ebtables-save create mode 120000 alternatives/editor create mode 120000 alternatives/editor.1.gz create mode 120000 alternatives/ex create mode 120000 alternatives/ex.1.gz create mode 120000 alternatives/ex.da.1.gz create mode 120000 alternatives/ex.de.1.gz create mode 120000 alternatives/ex.fr.1.gz create mode 120000 alternatives/ex.it.1.gz create mode 120000 alternatives/ex.ja.1.gz create mode 120000 alternatives/ex.pl.1.gz create mode 120000 alternatives/ex.ru.1.gz create mode 120000 alternatives/faked.1.gz create mode 120000 alternatives/faked.es.1.gz create mode 120000 alternatives/faked.fr.1.gz create mode 120000 alternatives/faked.sv.1.gz create mode 120000 alternatives/fakeroot create mode 120000 alternatives/fakeroot.1.gz create mode 120000 alternatives/fakeroot.es.1.gz create mode 120000 alternatives/fakeroot.fr.1.gz create mode 120000 alternatives/fakeroot.sv.1.gz create mode 120000 alternatives/frm create mode 120000 alternatives/frm.1.gz create mode 120000 alternatives/from create mode 120000 alternatives/from.1.gz create mode 120000 alternatives/idmap-plugin create mode 120000 alternatives/idmap-plugin.8.gz create mode 120000 alternatives/infobrowser create mode 120000 alternatives/infobrowser.1.gz create mode 120000 alternatives/ip6tables create mode 120000 alternatives/ip6tables-restore create mode 120000 alternatives/ip6tables-save create mode 120000 alternatives/iptables create mode 120000 alternatives/iptables-restore create mode 120000 alternatives/iptables-save create mode 120000 alternatives/java create mode 120000 alternatives/java.1.gz create mode 120000 alternatives/jexec create mode 120000 alternatives/jexec-binfmt create mode 120000 alternatives/jjs create mode 120000 alternatives/jjs.1.gz create mode 120000 alternatives/keytool create mode 120000 alternatives/keytool.1.gz create mode 120000 alternatives/lft create mode 120000 alternatives/lft.1.gz create mode 120000 alternatives/lua-compiler create mode 120000 alternatives/lua-compiler-manual create mode 120000 alternatives/lua-interpreter create mode 120000 alternatives/lua-manual create mode 120000 alternatives/lzcat create mode 120000 alternatives/lzcat.1.gz create mode 120000 alternatives/lzcmp create mode 120000 alternatives/lzcmp.1.gz create mode 120000 alternatives/lzdiff create mode 120000 alternatives/lzdiff.1.gz create mode 120000 alternatives/lzegrep create mode 120000 alternatives/lzegrep.1.gz create mode 120000 alternatives/lzfgrep create mode 120000 alternatives/lzfgrep.1.gz create mode 120000 alternatives/lzgrep create mode 120000 alternatives/lzgrep.1.gz create mode 120000 alternatives/lzless create mode 120000 alternatives/lzless.1.gz create mode 120000 alternatives/lzma create mode 120000 alternatives/lzma.1.gz create mode 120000 alternatives/lzmore create mode 120000 alternatives/lzmore.1.gz create mode 120000 alternatives/mail create mode 120000 alternatives/mail.1.gz create mode 120000 alternatives/mailx create mode 120000 alternatives/mailx.1.gz create mode 120000 alternatives/messages create mode 120000 alternatives/messages.1.gz create mode 120000 alternatives/movemail create mode 120000 alternatives/movemail.1.gz create mode 120000 alternatives/mt create mode 120000 alternatives/mt.1.gz create mode 120000 alternatives/my.cnf create mode 120000 alternatives/nawk create mode 120000 alternatives/nawk.1.gz create mode 120000 alternatives/nc create mode 120000 alternatives/nc.1.gz create mode 120000 alternatives/netcat create mode 120000 alternatives/netcat.1.gz create mode 120000 alternatives/nodejs create mode 120000 alternatives/nodejs.1.gz create mode 120000 alternatives/pack200 create mode 120000 alternatives/pack200.1.gz create mode 120000 alternatives/pager create mode 120000 alternatives/pager.1.gz create mode 120000 alternatives/pg_basebackup.1.gz create mode 120000 alternatives/pg_dump.1.gz create mode 120000 alternatives/pg_dumpall.1.gz create mode 120000 alternatives/pg_isready.1.gz create mode 120000 alternatives/pg_receivewal.1.gz create mode 120000 alternatives/pg_recvlogical.1.gz create mode 120000 alternatives/pg_restore.1.gz create mode 120000 alternatives/phar create mode 120000 alternatives/phar.1.gz create mode 120000 alternatives/phar.phar create mode 120000 alternatives/phar.phar.1.gz create mode 120000 alternatives/php create mode 120000 alternatives/php-cgi create mode 120000 alternatives/php-cgi-bin create mode 120000 alternatives/php-cgi.1.gz create mode 120000 alternatives/php.1.gz create mode 120000 alternatives/pico create mode 120000 alternatives/pico.1.gz create mode 120000 alternatives/pinentry create mode 120000 alternatives/pinentry.1.gz create mode 120000 alternatives/psql.1.gz create mode 120000 alternatives/rcp create mode 120000 alternatives/rcp.1.gz create mode 120000 alternatives/readmsg create mode 120000 alternatives/readmsg.1.gz create mode 120000 alternatives/reindexdb.1.gz create mode 120000 alternatives/rlogin create mode 120000 alternatives/rlogin.1.gz create mode 120000 alternatives/rmid create mode 120000 alternatives/rmid.1.gz create mode 120000 alternatives/rmiregistry create mode 120000 alternatives/rmiregistry.1.gz create mode 120000 alternatives/rmt create mode 120000 alternatives/rmt.8.gz create mode 120000 alternatives/rsh create mode 120000 alternatives/rsh.1.gz create mode 120000 alternatives/rview create mode 120000 alternatives/tcptraceroute create mode 120000 alternatives/tcptraceroute.8.gz create mode 120000 alternatives/telnet create mode 120000 alternatives/telnet.1.gz create mode 120000 alternatives/traceproto create mode 120000 alternatives/traceproto.1.gz create mode 120000 alternatives/traceroute create mode 120000 alternatives/traceroute.1.gz create mode 120000 alternatives/traceroute.sbin create mode 120000 alternatives/traceroute6 create mode 120000 alternatives/traceroute6.1.gz create mode 120000 alternatives/unlzma create mode 120000 alternatives/unlzma.1.gz create mode 120000 alternatives/unpack200 create mode 120000 alternatives/unpack200.1.gz create mode 120000 alternatives/vacuumdb.1.gz create mode 120000 alternatives/vi create mode 120000 alternatives/vi.1.gz create mode 120000 alternatives/vi.da.1.gz create mode 120000 alternatives/vi.de.1.gz create mode 120000 alternatives/vi.fr.1.gz create mode 120000 alternatives/vi.it.1.gz create mode 120000 alternatives/vi.ja.1.gz create mode 120000 alternatives/vi.pl.1.gz create mode 120000 alternatives/vi.ru.1.gz create mode 120000 alternatives/view create mode 120000 alternatives/view.1.gz create mode 120000 alternatives/view.da.1.gz create mode 120000 alternatives/view.de.1.gz create mode 120000 alternatives/view.fr.1.gz create mode 120000 alternatives/view.it.1.gz create mode 120000 alternatives/view.ja.1.gz create mode 120000 alternatives/view.pl.1.gz create mode 120000 alternatives/view.ru.1.gz create mode 120000 alternatives/w create mode 120000 alternatives/w.1.gz create mode 120000 alternatives/write create mode 120000 alternatives/write.1.gz create mode 100644 apparmor.d/local/usr.bin.man create mode 100644 apparmor.d/local/usr.sbin.ntpd create mode 100644 apparmor.d/tunables/ntpd create mode 100644 apparmor.d/usr.bin.man create mode 100644 apparmor.d/usr.sbin.ntpd create mode 120000 apparmor/init/network-interface-security/usr.sbin.ntpd create mode 100644 apt/apt.conf.d/01autoremove create mode 100644 apt/apt.conf.d/01autoremove-kernels create mode 100644 apt/apt.conf.d/01autoremove-postgresql create mode 100644 apt/apt.conf.d/05etckeeper create mode 100644 apt/apt.conf.d/15update-stamp create mode 100644 apt/apt.conf.d/20listchanges create mode 100644 apt/apt.conf.d/50raspi create mode 100644 apt/apt.conf.d/70debconf create mode 100644 apt/listchanges.conf create mode 100644 apt/preferences create mode 100644 apt/sources.list create mode 100644 apt/sources.list.d/docker.list create mode 100644 apt/sources.list.d/mosquitto-buster.list create mode 100644 apt/sources.list.d/nginx.list create mode 100644 apt/sources.list.d/nodesource.list create mode 100644 apt/sources.list.d/raspi.list create mode 100644 apt/sources.list.d/vscode.list create mode 100644 apt/trusted.gpg create mode 100644 apt/trusted.gpg.d/microsoft.gpg create mode 100644 avahi/avahi-daemon.conf create mode 100644 avahi/hosts create mode 100644 bash.bashrc create mode 100644 bash_completion create mode 100644 bash_completion.d/git-prompt create mode 100644 bindresvport.blacklist create mode 100644 bluetooth/input.conf create mode 100644 bluetooth/main.conf create mode 100644 bluetooth/network.conf create mode 100644 ca-certificates.conf create mode 100755 ca-certificates/update.d/jks-keystore create mode 100644 calendar/default create mode 100644 check_mk/cmk-update-agent.cfg create mode 100644 check_mk/docker.cfg create mode 100644 check_mk/mk_inventory.cfg create mode 120000 cifs-utils/idmap-plugin create mode 100644 cmk-update-agent.state create mode 100644 console-setup/cached_Lat15-Fixed16.psf.gz create mode 100644 console-setup/cached_UTF-8_del.kmap.gz create mode 100755 console-setup/cached_setup_font.sh create mode 100755 console-setup/cached_setup_keyboard.sh create mode 100755 console-setup/cached_setup_terminal.sh create mode 100644 console-setup/compose.ARMSCII-8.inc create mode 100644 console-setup/compose.CP1251.inc create mode 100644 console-setup/compose.CP1255.inc create mode 100644 console-setup/compose.CP1256.inc create mode 100644 console-setup/compose.GEORGIAN-ACADEMY.inc create mode 100644 console-setup/compose.GEORGIAN-PS.inc create mode 100644 console-setup/compose.IBM1133.inc create mode 100644 console-setup/compose.ISIRI-3342.inc create mode 100644 console-setup/compose.ISO-8859-1.inc create mode 100644 console-setup/compose.ISO-8859-10.inc create mode 100644 console-setup/compose.ISO-8859-11.inc create mode 100644 console-setup/compose.ISO-8859-13.inc create mode 100644 console-setup/compose.ISO-8859-14.inc create mode 100644 console-setup/compose.ISO-8859-15.inc create mode 100644 console-setup/compose.ISO-8859-16.inc create mode 100644 console-setup/compose.ISO-8859-2.inc create mode 100644 console-setup/compose.ISO-8859-3.inc create mode 100644 console-setup/compose.ISO-8859-4.inc create mode 100644 console-setup/compose.ISO-8859-5.inc create mode 100644 console-setup/compose.ISO-8859-6.inc create mode 100644 console-setup/compose.ISO-8859-7.inc create mode 100644 console-setup/compose.ISO-8859-8.inc create mode 100644 console-setup/compose.ISO-8859-9.inc create mode 100644 console-setup/compose.KOI8-R.inc create mode 100644 console-setup/compose.KOI8-U.inc create mode 100644 console-setup/compose.TIS-620.inc create mode 100644 console-setup/compose.VISCII.inc create mode 100644 console-setup/remap.inc create mode 100644 containerd/config.toml create mode 100644 cron.d/.placeholder create mode 100644 cron.d/php create mode 100644 cron.d/sysstat create mode 100644 cron.daily/.placeholder create mode 100755 cron.daily/apt-compat create mode 100755 cron.daily/bsdmainutils create mode 100755 cron.daily/dpkg create mode 100755 cron.daily/etckeeper create mode 100755 cron.daily/exim4-base create mode 100755 cron.daily/logrotate create mode 100755 cron.daily/man-db create mode 100755 cron.daily/ntp create mode 100755 cron.daily/passwd create mode 100755 cron.daily/sysstat create mode 100644 cron.hourly/.placeholder create mode 100755 cron.hourly/fake-hwclock create mode 100644 cron.monthly/.placeholder create mode 100644 cron.weekly/.placeholder create mode 100755 cron.weekly/man-db create mode 100644 crontab create mode 100644 cruft/filters-unex/etckeeper create mode 100644 dbus-1/system.d/avahi-dbus.conf create mode 100644 dbus-1/system.d/bluetooth.conf create mode 100644 dbus-1/system.d/wpa_supplicant.conf create mode 100644 debconf.conf create mode 100644 debian_version create mode 100644 default/avahi-daemon create mode 100644 default/bluetooth create mode 100644 default/bsdmainutils create mode 100644 default/cacerts create mode 100644 default/console-setup create mode 100644 default/crda create mode 100644 default/cron create mode 100644 default/dbus create mode 100644 default/docker create mode 100644 default/exim4 create mode 100644 default/fake-hwclock create mode 100644 default/hwclock create mode 100644 default/keyboard create mode 100644 default/locale create mode 100644 default/netfilter-persistent create mode 100644 default/networking create mode 100644 default/nfs-common create mode 100644 default/nginx create mode 100644 default/nss create mode 100644 default/ntp create mode 100644 default/raspberrypi-kernel create mode 100644 default/redis-server create mode 100644 default/rng-tools create mode 100644 default/rpi-eeprom-update create mode 100644 default/rsync create mode 100644 default/rsyslog create mode 100644 default/snmpd create mode 100644 default/ssh create mode 100644 default/sysstat create mode 100644 default/tftpd-hpa create mode 100644 default/triggerhappy create mode 100644 default/useradd create mode 100644 default/xinetd create mode 100644 deluser.conf create mode 100644 dhcp/debug create mode 120000 dhcp/dhclient-enter-hooks.d/debug create mode 100644 dhcp/dhclient-enter-hooks.d/resolvconf create mode 120000 dhcp/dhclient-exit-hooks.d/debug create mode 100644 dhcp/dhclient-exit-hooks.d/ntp create mode 100644 dhcp/dhclient-exit-hooks.d/rfc3442-classless-routes create mode 100644 dhcp/dhclient-exit-hooks.d/timesyncd create mode 100644 dhcp/dhclient.conf create mode 100644 dhcpcd.conf create mode 100644 dkms/framework.conf create mode 100644 dkms/template-dkms-mkbmdeb/Makefile create mode 100644 dkms/template-dkms-mkbmdeb/debian/README.Debian create mode 100644 dkms/template-dkms-mkbmdeb/debian/changelog create mode 100644 dkms/template-dkms-mkbmdeb/debian/compat create mode 100644 dkms/template-dkms-mkbmdeb/debian/control create mode 100644 dkms/template-dkms-mkbmdeb/debian/copyright create mode 100755 dkms/template-dkms-mkbmdeb/debian/rules create mode 100644 dkms/template-dkms-mkdeb/Makefile create mode 100644 dkms/template-dkms-mkdeb/debian/README.Debian create mode 100644 dkms/template-dkms-mkdeb/debian/changelog create mode 100644 dkms/template-dkms-mkdeb/debian/compat create mode 100644 dkms/template-dkms-mkdeb/debian/control create mode 100644 dkms/template-dkms-mkdeb/debian/copyright create mode 100644 dkms/template-dkms-mkdeb/debian/dirs create mode 100755 dkms/template-dkms-mkdeb/debian/postinst create mode 100755 dkms/template-dkms-mkdeb/debian/prerm create mode 100755 dkms/template-dkms-mkdeb/debian/rules create mode 100644 docker/daemon.json create mode 100644 docker/key.json create mode 100644 dphys-swapfile create mode 100644 dpkg/dpkg.cfg create mode 100644 dpkg/dpkg.cfg.d/pkg-config-hook-config create mode 100644 dpkg/origins/debian create mode 120000 dpkg/origins/default create mode 100644 dpkg/origins/raspbian create mode 100644 dpkg/shlibs.default create mode 100644 dpkg/shlibs.override create mode 100644 email-addresses create mode 100644 environment create mode 100755 etckeeper/commit.d/10vcs-test create mode 120000 etckeeper/commit.d/20store-metadata create mode 100755 etckeeper/commit.d/30bzr-add create mode 100755 etckeeper/commit.d/30darcs-add create mode 100755 etckeeper/commit.d/30git-add create mode 100755 etckeeper/commit.d/30hg-addremove create mode 100755 etckeeper/commit.d/50vcs-commit create mode 100755 etckeeper/commit.d/99push create mode 100644 etckeeper/commit.d/README create mode 100755 etckeeper/daily create mode 100644 etckeeper/etckeeper.conf create mode 100755 etckeeper/init.d/10restore-metadata create mode 100755 etckeeper/init.d/20restore-etckeeper create mode 100755 etckeeper/init.d/40vcs-init create mode 100755 etckeeper/init.d/50vcs-ignore create mode 100755 etckeeper/init.d/50vcs-perm create mode 100755 etckeeper/init.d/50vcs-pre-commit-hook create mode 100755 etckeeper/init.d/60darcs-deleted-symlinks create mode 100755 etckeeper/init.d/70vcs-add create mode 100644 etckeeper/init.d/README create mode 100755 etckeeper/list-installed.d/50list-installed create mode 100755 etckeeper/post-install.d/50vcs-commit create mode 100644 etckeeper/post-install.d/README create mode 100755 etckeeper/pre-commit.d/20warn-problem-files create mode 100755 etckeeper/pre-commit.d/30store-metadata create mode 100644 etckeeper/pre-commit.d/README create mode 100755 etckeeper/pre-install.d/10packagelist create mode 100755 etckeeper/pre-install.d/50uncommitted-changes create mode 100644 etckeeper/pre-install.d/README create mode 100755 etckeeper/unclean.d/50test create mode 100644 etckeeper/unclean.d/README create mode 100755 etckeeper/uninit.d/01prompt create mode 100755 etckeeper/uninit.d/50remove-metadata create mode 100755 etckeeper/uninit.d/50vcs-uninit create mode 100644 etckeeper/uninit.d/README create mode 100755 etckeeper/update-ignore.d/01update-ignore create mode 100644 etckeeper/update-ignore.d/README create mode 100755 etckeeper/vcs.d/50vcs-cmd create mode 100644 exim4/conf.d/acl/00_exim4-config_header create mode 100644 exim4/conf.d/acl/20_exim4-config_local_deny_exceptions create mode 100644 exim4/conf.d/acl/30_exim4-config_check_mail create mode 100644 exim4/conf.d/acl/30_exim4-config_check_rcpt create mode 100644 exim4/conf.d/acl/40_exim4-config_check_data create mode 100644 exim4/conf.d/auth/00_exim4-config_header create mode 100644 exim4/conf.d/auth/30_exim4-config_examples create mode 100644 exim4/conf.d/main/01_exim4-config_listmacrosdefs create mode 100644 exim4/conf.d/main/02_exim4-config_options create mode 100644 exim4/conf.d/main/03_exim4-config_tlsoptions create mode 100644 exim4/conf.d/main/90_exim4-config_log_selector create mode 100644 exim4/conf.d/retry/00_exim4-config_header create mode 100644 exim4/conf.d/retry/30_exim4-config create mode 100644 exim4/conf.d/rewrite/00_exim4-config_header create mode 100644 exim4/conf.d/rewrite/31_exim4-config_rewriting create mode 100644 exim4/conf.d/router/00_exim4-config_header create mode 100644 exim4/conf.d/router/100_exim4-config_domain_literal create mode 100644 exim4/conf.d/router/150_exim4-config_hubbed_hosts create mode 100644 exim4/conf.d/router/200_exim4-config_primary create mode 100644 exim4/conf.d/router/300_exim4-config_real_local create mode 100644 exim4/conf.d/router/400_exim4-config_system_aliases create mode 100644 exim4/conf.d/router/500_exim4-config_hubuser create mode 100644 exim4/conf.d/router/600_exim4-config_userforward create mode 100644 exim4/conf.d/router/700_exim4-config_procmail create mode 100644 exim4/conf.d/router/800_exim4-config_maildrop create mode 100644 exim4/conf.d/router/850_exim4-config_lowuid create mode 100644 exim4/conf.d/router/900_exim4-config_local_user create mode 100644 exim4/conf.d/router/mmm_mail4root create mode 100644 exim4/conf.d/transport/00_exim4-config_header create mode 100644 exim4/conf.d/transport/10_exim4-config_transport-macros create mode 100644 exim4/conf.d/transport/30_exim4-config_address_file create mode 100644 exim4/conf.d/transport/30_exim4-config_address_pipe create mode 100644 exim4/conf.d/transport/30_exim4-config_address_reply create mode 100644 exim4/conf.d/transport/30_exim4-config_mail_spool create mode 100644 exim4/conf.d/transport/30_exim4-config_maildir_home create mode 100644 exim4/conf.d/transport/30_exim4-config_maildrop_pipe create mode 100644 exim4/conf.d/transport/30_exim4-config_procmail_pipe create mode 100644 exim4/conf.d/transport/30_exim4-config_remote_smtp create mode 100644 exim4/conf.d/transport/30_exim4-config_remote_smtp_smarthost create mode 100644 exim4/conf.d/transport/35_exim4-config_address_directory create mode 100644 exim4/exim4.conf.template create mode 100644 exim4/passwd.client create mode 100644 exim4/update-exim4.conf.conf create mode 100644 fb.modes create mode 100644 fonts/conf.avail/20-unhint-small-dejavu-lgc-sans-mono.conf create mode 100644 fonts/conf.avail/20-unhint-small-dejavu-lgc-sans.conf create mode 100644 fonts/conf.avail/20-unhint-small-dejavu-lgc-serif.conf create mode 100644 fonts/conf.avail/20-unhint-small-dejavu-sans-mono.conf create mode 100644 fonts/conf.avail/20-unhint-small-dejavu-sans.conf create mode 100644 fonts/conf.avail/20-unhint-small-dejavu-serif.conf create mode 100644 fonts/conf.avail/30-droid-noto-mono.conf create mode 100644 fonts/conf.avail/57-dejavu-sans-mono.conf create mode 100644 fonts/conf.avail/57-dejavu-sans.conf create mode 100644 fonts/conf.avail/57-dejavu-serif.conf create mode 100644 fonts/conf.avail/58-dejavu-lgc-sans-mono.conf create mode 100644 fonts/conf.avail/58-dejavu-lgc-sans.conf create mode 100644 fonts/conf.avail/58-dejavu-lgc-serif.conf create mode 100644 fonts/conf.avail/65-droid-sans-fallback.conf create mode 120000 fonts/conf.d/10-hinting-slight.conf create mode 120000 fonts/conf.d/10-scale-bitmap-fonts.conf create mode 120000 fonts/conf.d/11-lcdfilter-default.conf create mode 120000 fonts/conf.d/20-unhint-small-dejavu-lgc-sans-mono.conf create mode 120000 fonts/conf.d/20-unhint-small-dejavu-lgc-sans.conf create mode 120000 fonts/conf.d/20-unhint-small-dejavu-lgc-serif.conf create mode 120000 fonts/conf.d/20-unhint-small-dejavu-sans-mono.conf create mode 120000 fonts/conf.d/20-unhint-small-dejavu-sans.conf create mode 120000 fonts/conf.d/20-unhint-small-dejavu-serif.conf create mode 120000 fonts/conf.d/20-unhint-small-vera.conf create mode 120000 fonts/conf.d/30-metric-aliases.conf create mode 120000 fonts/conf.d/40-nonlatin.conf create mode 120000 fonts/conf.d/45-generic.conf create mode 120000 fonts/conf.d/45-latin.conf create mode 120000 fonts/conf.d/49-sansserif.conf create mode 120000 fonts/conf.d/50-user.conf create mode 120000 fonts/conf.d/51-local.conf create mode 120000 fonts/conf.d/57-dejavu-sans-mono.conf create mode 120000 fonts/conf.d/57-dejavu-sans.conf create mode 120000 fonts/conf.d/57-dejavu-serif.conf create mode 120000 fonts/conf.d/58-dejavu-lgc-sans-mono.conf create mode 120000 fonts/conf.d/58-dejavu-lgc-sans.conf create mode 120000 fonts/conf.d/58-dejavu-lgc-serif.conf create mode 120000 fonts/conf.d/60-generic.conf create mode 120000 fonts/conf.d/60-latin.conf create mode 120000 fonts/conf.d/65-fonts-persian.conf create mode 120000 fonts/conf.d/65-nonlatin.conf create mode 120000 fonts/conf.d/69-unifont.conf create mode 120000 fonts/conf.d/70-no-bitmaps.conf create mode 120000 fonts/conf.d/80-delicious.conf create mode 120000 fonts/conf.d/90-synthetic.conf create mode 100644 fonts/conf.d/README create mode 100644 fonts/fonts.conf create mode 100644 fstab create mode 100644 fuse.conf create mode 100644 gai.conf create mode 100644 gdb/gdbinit create mode 100644 ghostscript/cidfmap.d/90gs-cjk-resource-cns1.conf create mode 100644 ghostscript/cidfmap.d/90gs-cjk-resource-gb1.conf create mode 100644 ghostscript/cidfmap.d/90gs-cjk-resource-japan1.conf create mode 100644 ghostscript/cidfmap.d/90gs-cjk-resource-japan2.conf create mode 100644 ghostscript/cidfmap.d/90gs-cjk-resource-korea1.conf create mode 100644 ghostscript/fontmap.d/10gsfonts.conf create mode 100644 gitea/app.ini create mode 100644 groff/man.local create mode 100644 groff/mdoc.local create mode 100644 group create mode 100644 group- create mode 100644 gshadow create mode 100644 gshadow- create mode 100644 host.conf create mode 100644 hostname create mode 100644 hosts create mode 100644 hosts.allow create mode 100644 hosts.deny create mode 100644 idmapd.conf create mode 120000 ifplugd/action.d/action_wpa create mode 100755 init.d/alsa-utils create mode 100755 init.d/avahi-daemon create mode 100755 init.d/bluetooth create mode 100755 init.d/console-setup.sh create mode 100755 init.d/cron create mode 100755 init.d/dbus create mode 100755 init.d/dhcpcd create mode 100755 init.d/docker create mode 100755 init.d/dphys-swapfile create mode 100755 init.d/exim4 create mode 100755 init.d/fake-hwclock create mode 100755 init.d/hwclock.sh create mode 100755 init.d/keyboard-setup.sh create mode 100755 init.d/kmod create mode 100755 init.d/mosquitto create mode 100755 init.d/netfilter-persistent create mode 100755 init.d/networking create mode 100755 init.d/nfs-common create mode 100755 init.d/nginx create mode 100755 init.d/ntp create mode 100755 init.d/paxctld create mode 100755 init.d/php7.3-fpm create mode 100755 init.d/postgresql create mode 100755 init.d/procps create mode 100755 init.d/raspi-config create mode 100755 init.d/redis-server create mode 100755 init.d/resolvconf create mode 100755 init.d/rng-tools create mode 100755 init.d/rpcbind create mode 100755 init.d/rsync create mode 100755 init.d/rsyslog create mode 100755 init.d/snmpd create mode 100755 init.d/ssh create mode 100755 init.d/sudo create mode 100755 init.d/sysstat create mode 100755 init.d/tftpd-hpa create mode 100755 init.d/triggerhappy create mode 100755 init.d/udev create mode 100755 init.d/x11-common create mode 100755 init.d/xinetd create mode 100644 init/docker.conf create mode 100644 init/paxctld.conf create mode 100644 init/php7.3-fpm.conf create mode 100644 init/resolvconf.conf create mode 100644 init/tftpd-hpa.conf create mode 100644 initramfs-tools/initramfs.conf create mode 100644 initramfs-tools/modules create mode 100644 initramfs-tools/update-initramfs.conf create mode 100644 inputrc create mode 100644 insserv.conf.d/rpcbind create mode 100644 iproute2/bpf_pinning create mode 100644 iproute2/ematch_map create mode 100644 iproute2/group create mode 100644 iproute2/nl_protos create mode 100644 iproute2/rt_dsfield create mode 100644 iproute2/rt_protos create mode 100644 iproute2/rt_protos.d/README create mode 100644 iproute2/rt_realms create mode 100644 iproute2/rt_scopes create mode 100644 iproute2/rt_tables create mode 100644 iproute2/rt_tables.d/README create mode 100644 issue create mode 100644 issue.net create mode 100644 java-11-openjdk/accessibility.properties create mode 100644 java-11-openjdk/jfr/default.jfc create mode 100644 java-11-openjdk/jfr/profile.jfc create mode 100644 java-11-openjdk/jvm-armhf.cfg create mode 100644 java-11-openjdk/logging.properties create mode 100644 java-11-openjdk/management/jmxremote.access create mode 100644 java-11-openjdk/management/management.properties create mode 100644 java-11-openjdk/net.properties create mode 100644 java-11-openjdk/psfont.properties.ja create mode 100644 java-11-openjdk/psfontj2d.properties create mode 100644 java-11-openjdk/security/blacklisted.certs create mode 100644 java-11-openjdk/security/default.policy create mode 100644 java-11-openjdk/security/java.policy create mode 100644 java-11-openjdk/security/java.security create mode 100644 java-11-openjdk/security/nss.cfg create mode 100644 java-11-openjdk/security/policy/README.txt create mode 100644 java-11-openjdk/security/policy/limited/default_US_export.policy create mode 100644 java-11-openjdk/security/policy/limited/default_local.policy create mode 100644 java-11-openjdk/security/policy/limited/exempt_local.policy create mode 100644 java-11-openjdk/security/policy/unlimited/default_US_export.policy create mode 100644 java-11-openjdk/security/policy/unlimited/default_local.policy create mode 100644 java-11-openjdk/security/public_suffix_list.dat create mode 100644 java-11-openjdk/sound.properties create mode 100644 java-11-openjdk/swing.properties create mode 100755 kernel/header_postinst.d/dkms create mode 100755 kernel/postinst.d/apt-auto-removal create mode 100755 kernel/postinst.d/dkms create mode 100755 kernel/postinst.d/initramfs-tools create mode 100755 kernel/postrm.d/initramfs-tools create mode 100755 kernel/prerm.d/dkms create mode 100644 ld.so.conf create mode 100644 ld.so.conf.d/00-vmcs.conf create mode 100644 ld.so.conf.d/arm-linux-gnueabihf.conf create mode 100644 ld.so.conf.d/fakeroot-arm-linux-gnueabihf.conf create mode 100644 ld.so.conf.d/libc.conf create mode 100644 ld.so.preload create mode 100644 ldap/ldap.conf create mode 100644 letsencrypt/account.conf create mode 100755 letsencrypt/acme.sh create mode 100644 letsencrypt/acme.sh.env create mode 100644 letsencrypt/ca/acme-v02.api.letsencrypt.org/account.json create mode 100644 letsencrypt/ca/acme-v02.api.letsencrypt.org/account.key create mode 100644 letsencrypt/ca/acme-v02.api.letsencrypt.org/ca.conf create mode 100644 letsencrypt/deploy/README.md create mode 100644 letsencrypt/deploy/apache.sh create mode 100644 letsencrypt/deploy/cleverreach.sh create mode 100644 letsencrypt/deploy/cpanel_uapi.sh create mode 100755 letsencrypt/deploy/docker.sh create mode 100644 letsencrypt/deploy/dovecot.sh create mode 100644 letsencrypt/deploy/exim4.sh create mode 100644 letsencrypt/deploy/fritzbox.sh create mode 100644 letsencrypt/deploy/gcore_cdn.sh create mode 100644 letsencrypt/deploy/gitlab.sh create mode 100644 letsencrypt/deploy/haproxy.sh create mode 100644 letsencrypt/deploy/keychain.sh create mode 100755 letsencrypt/deploy/kong.sh create mode 100644 letsencrypt/deploy/mailcow.sh create mode 100755 letsencrypt/deploy/myapi.sh create mode 100755 letsencrypt/deploy/mydevil.sh create mode 100644 letsencrypt/deploy/mysqld.sh create mode 100644 letsencrypt/deploy/nginx.sh create mode 100644 letsencrypt/deploy/opensshd.sh create mode 100644 letsencrypt/deploy/openstack.sh create mode 100644 letsencrypt/deploy/panos.sh create mode 100644 letsencrypt/deploy/pureftpd.sh create mode 100644 letsencrypt/deploy/qiniu.sh create mode 100644 letsencrypt/deploy/routeros.sh create mode 100644 letsencrypt/deploy/ssh.sh create mode 100644 letsencrypt/deploy/strongswan.sh create mode 100644 letsencrypt/deploy/synology_dsm.sh create mode 100644 letsencrypt/deploy/unifi.sh create mode 100644 letsencrypt/deploy/vault.sh create mode 100644 letsencrypt/deploy/vault_cli.sh create mode 100644 letsencrypt/deploy/vsftpd.sh create mode 100644 letsencrypt/dnsapi/README.md create mode 100755 letsencrypt/dnsapi/dns_1984hosting.sh create mode 100644 letsencrypt/dnsapi/dns_acmedns.sh create mode 100644 letsencrypt/dnsapi/dns_acmeproxy.sh create mode 100755 letsencrypt/dnsapi/dns_active24.sh create mode 100755 letsencrypt/dnsapi/dns_ad.sh create mode 100755 letsencrypt/dnsapi/dns_ali.sh create mode 100644 letsencrypt/dnsapi/dns_anx.sh create mode 100644 letsencrypt/dnsapi/dns_arvan.sh create mode 100644 letsencrypt/dnsapi/dns_autodns.sh create mode 100755 letsencrypt/dnsapi/dns_aws.sh create mode 100644 letsencrypt/dnsapi/dns_azure.sh create mode 100755 letsencrypt/dnsapi/dns_cf.sh create mode 100755 letsencrypt/dnsapi/dns_clouddns.sh create mode 100755 letsencrypt/dnsapi/dns_cloudns.sh create mode 100644 letsencrypt/dnsapi/dns_cn.sh create mode 100755 letsencrypt/dnsapi/dns_conoha.sh create mode 100644 letsencrypt/dnsapi/dns_constellix.sh create mode 100755 letsencrypt/dnsapi/dns_cx.sh create mode 100644 letsencrypt/dnsapi/dns_cyon.sh create mode 100755 letsencrypt/dnsapi/dns_da.sh create mode 100644 letsencrypt/dnsapi/dns_ddnss.sh create mode 100644 letsencrypt/dnsapi/dns_desec.sh create mode 100644 letsencrypt/dnsapi/dns_df.sh create mode 100755 letsencrypt/dnsapi/dns_dgon.sh create mode 100644 letsencrypt/dnsapi/dns_dnsimple.sh create mode 100755 letsencrypt/dnsapi/dns_do.sh create mode 100755 letsencrypt/dnsapi/dns_doapi.sh create mode 100644 letsencrypt/dnsapi/dns_domeneshop.sh create mode 100755 letsencrypt/dnsapi/dns_dp.sh create mode 100755 letsencrypt/dnsapi/dns_dpi.sh create mode 100644 letsencrypt/dnsapi/dns_dreamhost.sh create mode 100755 letsencrypt/dnsapi/dns_duckdns.sh create mode 100644 letsencrypt/dnsapi/dns_durabledns.sh create mode 100644 letsencrypt/dnsapi/dns_dyn.sh create mode 100644 letsencrypt/dnsapi/dns_dynu.sh create mode 100644 letsencrypt/dnsapi/dns_dynv6.sh create mode 100644 letsencrypt/dnsapi/dns_easydns.sh create mode 100755 letsencrypt/dnsapi/dns_edgedns.sh create mode 100644 letsencrypt/dnsapi/dns_euserv.sh create mode 100755 letsencrypt/dnsapi/dns_exoscale.sh create mode 100755 letsencrypt/dnsapi/dns_freedns.sh create mode 100644 letsencrypt/dnsapi/dns_gandi_livedns.sh create mode 100755 letsencrypt/dnsapi/dns_gcloud.sh create mode 100755 letsencrypt/dnsapi/dns_gd.sh create mode 100755 letsencrypt/dnsapi/dns_gdnsdk.sh create mode 100755 letsencrypt/dnsapi/dns_he.sh create mode 100644 letsencrypt/dnsapi/dns_hetzner.sh create mode 100755 letsencrypt/dnsapi/dns_hexonet.sh create mode 100644 letsencrypt/dnsapi/dns_hostingde.sh create mode 100644 letsencrypt/dnsapi/dns_huaweicloud.sh create mode 100644 letsencrypt/dnsapi/dns_infoblox.sh create mode 100755 letsencrypt/dnsapi/dns_infomaniak.sh create mode 100755 letsencrypt/dnsapi/dns_internetbs.sh create mode 100755 letsencrypt/dnsapi/dns_inwx.sh create mode 100755 letsencrypt/dnsapi/dns_ispconfig.sh create mode 100644 letsencrypt/dnsapi/dns_jd.sh create mode 100644 letsencrypt/dnsapi/dns_joker.sh create mode 100644 letsencrypt/dnsapi/dns_kappernet.sh create mode 100755 letsencrypt/dnsapi/dns_kas.sh create mode 100644 letsencrypt/dnsapi/dns_kinghost.sh create mode 100644 letsencrypt/dnsapi/dns_knot.sh create mode 100644 letsencrypt/dnsapi/dns_leaseweb.sh create mode 100755 letsencrypt/dnsapi/dns_lexicon.sh create mode 100755 letsencrypt/dnsapi/dns_linode.sh create mode 100755 letsencrypt/dnsapi/dns_linode_v4.sh create mode 100644 letsencrypt/dnsapi/dns_loopia.sh create mode 100755 letsencrypt/dnsapi/dns_lua.sh create mode 100755 letsencrypt/dnsapi/dns_maradns.sh create mode 100644 letsencrypt/dnsapi/dns_me.sh create mode 100644 letsencrypt/dnsapi/dns_miab.sh create mode 100755 letsencrypt/dnsapi/dns_misaka.sh create mode 100755 letsencrypt/dnsapi/dns_myapi.sh create mode 100755 letsencrypt/dnsapi/dns_mydevil.sh create mode 100755 letsencrypt/dnsapi/dns_mydnsjp.sh create mode 100755 letsencrypt/dnsapi/dns_namecheap.sh create mode 100755 letsencrypt/dnsapi/dns_namecom.sh create mode 100755 letsencrypt/dnsapi/dns_namesilo.sh create mode 100755 letsencrypt/dnsapi/dns_nederhost.sh create mode 100644 letsencrypt/dnsapi/dns_neodigit.sh create mode 100644 letsencrypt/dnsapi/dns_netcup.sh create mode 100644 letsencrypt/dnsapi/dns_netlify.sh create mode 100644 letsencrypt/dnsapi/dns_nic.sh create mode 100644 letsencrypt/dnsapi/dns_njalla.sh create mode 100644 letsencrypt/dnsapi/dns_nm.sh create mode 100644 letsencrypt/dnsapi/dns_nsd.sh create mode 100644 letsencrypt/dnsapi/dns_nsone.sh create mode 100755 letsencrypt/dnsapi/dns_nsupdate.sh create mode 100644 letsencrypt/dnsapi/dns_nw.sh create mode 100644 letsencrypt/dnsapi/dns_one.sh create mode 100755 letsencrypt/dnsapi/dns_online.sh create mode 100755 letsencrypt/dnsapi/dns_openprovider.sh create mode 100755 letsencrypt/dnsapi/dns_openstack.sh create mode 100755 letsencrypt/dnsapi/dns_opnsense.sh create mode 100755 letsencrypt/dnsapi/dns_ovh.sh create mode 100755 letsencrypt/dnsapi/dns_pdns.sh create mode 100644 letsencrypt/dnsapi/dns_pleskxml.sh create mode 100644 letsencrypt/dnsapi/dns_pointhq.sh create mode 100644 letsencrypt/dnsapi/dns_rackspace.sh create mode 100755 letsencrypt/dnsapi/dns_rcode0.sh create mode 100644 letsencrypt/dnsapi/dns_regru.sh create mode 100644 letsencrypt/dnsapi/dns_schlundtech.sh create mode 100644 letsencrypt/dnsapi/dns_selectel.sh create mode 100755 letsencrypt/dnsapi/dns_servercow.sh create mode 100644 letsencrypt/dnsapi/dns_tele3.sh create mode 100644 letsencrypt/dnsapi/dns_transip.sh create mode 100644 letsencrypt/dnsapi/dns_ultra.sh create mode 100644 letsencrypt/dnsapi/dns_unoeuro.sh create mode 100644 letsencrypt/dnsapi/dns_variomedia.sh create mode 100755 letsencrypt/dnsapi/dns_vscale.sh create mode 100644 letsencrypt/dnsapi/dns_vultr.sh create mode 100644 letsencrypt/dnsapi/dns_world4you.sh create mode 100755 letsencrypt/dnsapi/dns_yandex.sh create mode 100644 letsencrypt/dnsapi/dns_zilore.sh create mode 100755 letsencrypt/dnsapi/dns_zone.sh create mode 100644 letsencrypt/dnsapi/dns_zonomi.sh create mode 100644 letsencrypt/ghost.realm.local/ghost.realm.local.conf create mode 100644 letsencrypt/ghost.realm.local/ghost.realm.local.csr create mode 100644 letsencrypt/ghost.realm.local/ghost.realm.local.csr.conf create mode 100644 letsencrypt/ghost.realm.local/ghost.realm.local.key create mode 100644 letsencrypt/http.header create mode 100644 letsencrypt/notify/cqhttp.sh create mode 100644 letsencrypt/notify/dingtalk.sh create mode 100644 letsencrypt/notify/ifttt.sh create mode 100644 letsencrypt/notify/mail.sh create mode 100644 letsencrypt/notify/mailgun.sh create mode 100644 letsencrypt/notify/pop.sh create mode 100644 letsencrypt/notify/postmark.sh create mode 100644 letsencrypt/notify/pushover.sh create mode 100644 letsencrypt/notify/sendgrid.sh create mode 100644 letsencrypt/notify/slack.sh create mode 100644 letsencrypt/notify/smtp.sh create mode 100644 letsencrypt/notify/teams.sh create mode 100644 letsencrypt/notify/xmpp.sh create mode 100644 libaudit.conf create mode 100644 libnl-3/classid create mode 100644 libnl-3/pktloc create mode 100644 lighttpd/external.conf create mode 100644 lighttpd/lighttpd.conf.orig create mode 100644 locale.alias create mode 100644 locale.gen create mode 120000 localtime create mode 100644 logcheck/ignore.d.server/gpg-agent create mode 100644 logcheck/ignore.d.server/rng-tools create mode 100644 logcheck/ignore.d.server/rsyslog create mode 100644 logcheck/violations.ignore.d/rng-tools create mode 100644 login.defs create mode 100644 logrotate.conf create mode 100644 logrotate.d/apt create mode 100644 logrotate.d/btmp create mode 100644 logrotate.d/dpkg create mode 100644 logrotate.d/exim4-base create mode 100644 logrotate.d/exim4-paniclog create mode 100644 logrotate.d/mosquitto create mode 100644 logrotate.d/nginx create mode 100644 logrotate.d/nodered create mode 100644 logrotate.d/php7.3-fpm create mode 100644 logrotate.d/postgresql-common create mode 100644 logrotate.d/rsyslog create mode 100644 logrotate.d/syslog create mode 100644 logrotate.d/wtmp create mode 100644 machine-id create mode 100644 magic create mode 100644 magic.mime create mode 100644 mailcap create mode 100644 mailcap.order create mode 100644 mailname create mode 100644 manpath.config create mode 100644 mime.types create mode 100644 mke2fs.conf create mode 100644 modprobe.d/blacklist-8192cu.conf create mode 100644 modprobe.d/blacklist-rtl8xxxu.conf create mode 100644 modprobe.d/dkms.conf create mode 100644 modules create mode 120000 modules-load.d/modules.conf create mode 100644 mosquitto/ca_certificates/README create mode 100644 mosquitto/certs/README create mode 100644 mosquitto/conf.d/README create mode 100644 mosquitto/mosquitto.conf create mode 100644 mysql/conf.d/mysql.cnf create mode 100644 mysql/conf.d/mysqldump.cnf create mode 100644 mysql/mariadb.cnf create mode 120000 mysql/my.cnf create mode 100644 mysql/my.cnf.fallback create mode 100644 nanorc create mode 100644 neofetch/neofetch.config create mode 100644 netconfig create mode 100755 network/if-down.d/resolvconf create mode 120000 network/if-down.d/wpasupplicant create mode 100755 network/if-post-down.d/wireless-tools create mode 120000 network/if-post-down.d/wpasupplicant create mode 100755 network/if-pre-up.d/ethtool create mode 100755 network/if-pre-up.d/wireless-tools create mode 120000 network/if-pre-up.d/wpasupplicant create mode 100755 network/if-up.d/000resolvconf create mode 100755 network/if-up.d/ethtool create mode 120000 network/if-up.d/wpasupplicant create mode 100644 network/interfaces create mode 100644 networks create mode 100644 nginx/.htpasswd create mode 100644 nginx/fastcgi.conf create mode 100644 nginx/fastcgi_params create mode 100644 nginx/koi-utf create mode 100644 nginx/koi-win create mode 100644 nginx/mime.types create mode 120000 nginx/modules-enabled/50-mod-http-auth-pam.conf create mode 120000 nginx/modules-enabled/50-mod-http-dav-ext.conf create mode 120000 nginx/modules-enabled/50-mod-http-echo.conf create mode 120000 nginx/modules-enabled/50-mod-http-geoip.conf create mode 120000 nginx/modules-enabled/50-mod-http-image-filter.conf create mode 120000 nginx/modules-enabled/50-mod-http-subs-filter.conf create mode 120000 nginx/modules-enabled/50-mod-http-upstream-fair.conf create mode 120000 nginx/modules-enabled/50-mod-http-xslt-filter.conf create mode 120000 nginx/modules-enabled/50-mod-mail.conf create mode 120000 nginx/modules-enabled/50-mod-stream.conf create mode 100644 nginx/nginx.conf create mode 100644 nginx/proxy_params create mode 100644 nginx/scgi_params create mode 100644 nginx/sites-available/adguard.realm.local.conf create mode 100644 nginx/sites-available/checkmk.realm.local.conf create mode 100644 nginx/sites-available/default create mode 100644 nginx/sites-available/gitea.realm.local.conf create mode 100644 nginx/sites-available/grafana.realm.local.conf create mode 100644 nginx/sites-available/influxdb.realm.local.conf create mode 100644 nginx/sites-available/openhab.realm.local.conf create mode 100644 nginx/sites-available/photoprism.realm.local.conf create mode 100644 nginx/sites-available/portainer.realm.local.conf create mode 120000 nginx/sites-enabled/adguard.realm.local.conf create mode 120000 nginx/sites-enabled/checkmk.realm.local.conf create mode 120000 nginx/sites-enabled/default create mode 120000 nginx/sites-enabled/gitea.realm.local.conf create mode 120000 nginx/sites-enabled/grafana.realm.local.conf create mode 120000 nginx/sites-enabled/influxdb.realm.local.conf create mode 120000 nginx/sites-enabled/openhab.realm.local.conf create mode 120000 nginx/sites-enabled/photoprism.realm.local.conf create mode 120000 nginx/sites-enabled/portainer.realm.local.conf create mode 100644 nginx/snippets/fastcgi-php.conf create mode 100644 nginx/snippets/snakeoil.conf create mode 100644 nginx/ssl/certs/adguard.realm.local/cert.pem create mode 100644 nginx/ssl/certs/adguard.realm.local/key.pem create mode 100644 nginx/ssl/certs/checkmk.realm.local/cert.pem create mode 100644 nginx/ssl/certs/checkmk.realm.local/key.pem create mode 100644 nginx/ssl/certs/gitea.realm.local/cert.pem create mode 100644 nginx/ssl/certs/gitea.realm.local/key.pem create mode 100644 nginx/ssl/certs/grafana.realm.local/cert.pem create mode 100644 nginx/ssl/certs/grafana.realm.local/key.pem create mode 100644 nginx/ssl/certs/influxdb.realm.local/cert.pem create mode 100644 nginx/ssl/certs/influxdb.realm.local/key.pem create mode 100644 nginx/ssl/certs/openhab.realm.local/cert.pem create mode 100644 nginx/ssl/certs/openhab.realm.local/key.pem create mode 100644 nginx/ssl/certs/photoprism.realm.local/cert.pem create mode 100644 nginx/ssl/certs/photoprism.realm.local/key.pem create mode 100644 nginx/ssl/certs/portainer.realm.local/cert.pem create mode 100644 nginx/ssl/certs/portainer.realm.local/key.pem create mode 100644 nginx/ssl/certs/realm.local/cert.pem create mode 100644 nginx/ssl/certs/realm.local/key.pem create mode 100644 nginx/uwsgi_params create mode 100644 nginx/win-utf create mode 100644 nsswitch.conf create mode 100644 ntp.conf create mode 120000 os-release create mode 100644 pam.conf create mode 100644 pam.d/chfn create mode 100644 pam.d/chpasswd create mode 100644 pam.d/chsh create mode 100644 pam.d/common-account create mode 100644 pam.d/common-auth create mode 100644 pam.d/common-password create mode 100644 pam.d/common-session create mode 100644 pam.d/common-session-noninteractive create mode 100644 pam.d/cron create mode 100644 pam.d/login create mode 100644 pam.d/newusers create mode 100644 pam.d/other create mode 100644 pam.d/passwd create mode 100644 pam.d/polkit-1 create mode 100644 pam.d/runuser create mode 100644 pam.d/runuser-l create mode 100644 pam.d/sshd create mode 100644 pam.d/su create mode 100644 pam.d/su-l create mode 100644 pam.d/sudo create mode 100644 pam.d/systemd-user create mode 100644 papersize create mode 100644 passwd create mode 100644 passwd- create mode 100644 paxctld.conf create mode 100644 perl/Net/libnet.cfg create mode 120000 php/7.3/cgi/conf.d/10-mysqlnd.ini create mode 120000 php/7.3/cgi/conf.d/10-opcache.ini create mode 120000 php/7.3/cgi/conf.d/10-pdo.ini create mode 120000 php/7.3/cgi/conf.d/15-xml.ini create mode 120000 php/7.3/cgi/conf.d/20-calendar.ini create mode 120000 php/7.3/cgi/conf.d/20-ctype.ini create mode 120000 php/7.3/cgi/conf.d/20-dom.ini create mode 120000 php/7.3/cgi/conf.d/20-exif.ini create mode 120000 php/7.3/cgi/conf.d/20-fileinfo.ini create mode 120000 php/7.3/cgi/conf.d/20-ftp.ini create mode 120000 php/7.3/cgi/conf.d/20-gettext.ini create mode 120000 php/7.3/cgi/conf.d/20-iconv.ini create mode 120000 php/7.3/cgi/conf.d/20-intl.ini create mode 120000 php/7.3/cgi/conf.d/20-json.ini create mode 120000 php/7.3/cgi/conf.d/20-mysqli.ini create mode 120000 php/7.3/cgi/conf.d/20-pdo_mysql.ini create mode 120000 php/7.3/cgi/conf.d/20-pdo_sqlite.ini create mode 120000 php/7.3/cgi/conf.d/20-phar.ini create mode 120000 php/7.3/cgi/conf.d/20-posix.ini create mode 120000 php/7.3/cgi/conf.d/20-readline.ini create mode 120000 php/7.3/cgi/conf.d/20-shmop.ini create mode 120000 php/7.3/cgi/conf.d/20-simplexml.ini create mode 120000 php/7.3/cgi/conf.d/20-sockets.ini create mode 120000 php/7.3/cgi/conf.d/20-sqlite3.ini create mode 120000 php/7.3/cgi/conf.d/20-sysvmsg.ini create mode 120000 php/7.3/cgi/conf.d/20-sysvsem.ini create mode 120000 php/7.3/cgi/conf.d/20-sysvshm.ini create mode 120000 php/7.3/cgi/conf.d/20-tokenizer.ini create mode 120000 php/7.3/cgi/conf.d/20-wddx.ini create mode 120000 php/7.3/cgi/conf.d/20-xmlreader.ini create mode 120000 php/7.3/cgi/conf.d/20-xmlwriter.ini create mode 120000 php/7.3/cgi/conf.d/20-xsl.ini create mode 100644 php/7.3/cgi/php.ini create mode 120000 php/7.3/cli/conf.d/10-mysqlnd.ini create mode 120000 php/7.3/cli/conf.d/10-opcache.ini create mode 120000 php/7.3/cli/conf.d/10-pdo.ini create mode 120000 php/7.3/cli/conf.d/15-xml.ini create mode 120000 php/7.3/cli/conf.d/20-calendar.ini create mode 120000 php/7.3/cli/conf.d/20-ctype.ini create mode 120000 php/7.3/cli/conf.d/20-dom.ini create mode 120000 php/7.3/cli/conf.d/20-exif.ini create mode 120000 php/7.3/cli/conf.d/20-fileinfo.ini create mode 120000 php/7.3/cli/conf.d/20-ftp.ini create mode 120000 php/7.3/cli/conf.d/20-gettext.ini create mode 120000 php/7.3/cli/conf.d/20-iconv.ini create mode 120000 php/7.3/cli/conf.d/20-intl.ini create mode 120000 php/7.3/cli/conf.d/20-json.ini create mode 120000 php/7.3/cli/conf.d/20-mysqli.ini create mode 120000 php/7.3/cli/conf.d/20-pdo_mysql.ini create mode 120000 php/7.3/cli/conf.d/20-pdo_sqlite.ini create mode 120000 php/7.3/cli/conf.d/20-phar.ini create mode 120000 php/7.3/cli/conf.d/20-posix.ini create mode 120000 php/7.3/cli/conf.d/20-readline.ini create mode 120000 php/7.3/cli/conf.d/20-shmop.ini create mode 120000 php/7.3/cli/conf.d/20-simplexml.ini create mode 120000 php/7.3/cli/conf.d/20-sockets.ini create mode 120000 php/7.3/cli/conf.d/20-sqlite3.ini create mode 120000 php/7.3/cli/conf.d/20-sysvmsg.ini create mode 120000 php/7.3/cli/conf.d/20-sysvsem.ini create mode 120000 php/7.3/cli/conf.d/20-sysvshm.ini create mode 120000 php/7.3/cli/conf.d/20-tokenizer.ini create mode 120000 php/7.3/cli/conf.d/20-wddx.ini create mode 120000 php/7.3/cli/conf.d/20-xmlreader.ini create mode 120000 php/7.3/cli/conf.d/20-xmlwriter.ini create mode 120000 php/7.3/cli/conf.d/20-xsl.ini create mode 100644 php/7.3/cli/php.ini create mode 120000 php/7.3/fpm/conf.d/10-mysqlnd.ini create mode 120000 php/7.3/fpm/conf.d/10-opcache.ini create mode 120000 php/7.3/fpm/conf.d/10-pdo.ini create mode 120000 php/7.3/fpm/conf.d/15-xml.ini create mode 120000 php/7.3/fpm/conf.d/20-calendar.ini create mode 120000 php/7.3/fpm/conf.d/20-ctype.ini create mode 120000 php/7.3/fpm/conf.d/20-dom.ini create mode 120000 php/7.3/fpm/conf.d/20-exif.ini create mode 120000 php/7.3/fpm/conf.d/20-fileinfo.ini create mode 120000 php/7.3/fpm/conf.d/20-ftp.ini create mode 120000 php/7.3/fpm/conf.d/20-gettext.ini create mode 120000 php/7.3/fpm/conf.d/20-iconv.ini create mode 120000 php/7.3/fpm/conf.d/20-intl.ini create mode 120000 php/7.3/fpm/conf.d/20-json.ini create mode 120000 php/7.3/fpm/conf.d/20-mysqli.ini create mode 120000 php/7.3/fpm/conf.d/20-pdo_mysql.ini create mode 120000 php/7.3/fpm/conf.d/20-pdo_sqlite.ini create mode 120000 php/7.3/fpm/conf.d/20-phar.ini create mode 120000 php/7.3/fpm/conf.d/20-posix.ini create mode 120000 php/7.3/fpm/conf.d/20-readline.ini create mode 120000 php/7.3/fpm/conf.d/20-shmop.ini create mode 120000 php/7.3/fpm/conf.d/20-simplexml.ini create mode 120000 php/7.3/fpm/conf.d/20-sockets.ini create mode 120000 php/7.3/fpm/conf.d/20-sqlite3.ini create mode 120000 php/7.3/fpm/conf.d/20-sysvmsg.ini create mode 120000 php/7.3/fpm/conf.d/20-sysvsem.ini create mode 120000 php/7.3/fpm/conf.d/20-sysvshm.ini create mode 120000 php/7.3/fpm/conf.d/20-tokenizer.ini create mode 120000 php/7.3/fpm/conf.d/20-wddx.ini create mode 120000 php/7.3/fpm/conf.d/20-xmlreader.ini create mode 120000 php/7.3/fpm/conf.d/20-xmlwriter.ini create mode 120000 php/7.3/fpm/conf.d/20-xsl.ini create mode 100644 php/7.3/fpm/php-fpm.conf create mode 100644 php/7.3/fpm/php.ini create mode 100644 php/7.3/fpm/pool.d/www.conf create mode 100644 php/7.3/mods-available/calendar.ini create mode 100644 php/7.3/mods-available/ctype.ini create mode 100644 php/7.3/mods-available/dom.ini create mode 100644 php/7.3/mods-available/exif.ini create mode 100644 php/7.3/mods-available/fileinfo.ini create mode 100644 php/7.3/mods-available/ftp.ini create mode 100644 php/7.3/mods-available/gettext.ini create mode 100644 php/7.3/mods-available/iconv.ini create mode 100644 php/7.3/mods-available/intl.ini create mode 100644 php/7.3/mods-available/json.ini create mode 100644 php/7.3/mods-available/mysqli.ini create mode 100644 php/7.3/mods-available/mysqlnd.ini create mode 100644 php/7.3/mods-available/opcache.ini create mode 100644 php/7.3/mods-available/pdo.ini create mode 100644 php/7.3/mods-available/pdo_mysql.ini create mode 100644 php/7.3/mods-available/pdo_sqlite.ini create mode 100644 php/7.3/mods-available/phar.ini create mode 100644 php/7.3/mods-available/posix.ini create mode 100644 php/7.3/mods-available/readline.ini create mode 100644 php/7.3/mods-available/shmop.ini create mode 100644 php/7.3/mods-available/simplexml.ini create mode 100644 php/7.3/mods-available/sockets.ini create mode 100644 php/7.3/mods-available/sqlite3.ini create mode 100644 php/7.3/mods-available/sysvmsg.ini create mode 100644 php/7.3/mods-available/sysvsem.ini create mode 100644 php/7.3/mods-available/sysvshm.ini create mode 100644 php/7.3/mods-available/tokenizer.ini create mode 100644 php/7.3/mods-available/wddx.ini create mode 100644 php/7.3/mods-available/xml.ini create mode 100644 php/7.3/mods-available/xmlreader.ini create mode 100644 php/7.3/mods-available/xmlwriter.ini create mode 100644 php/7.3/mods-available/xsl.ini create mode 100644 pip.conf create mode 100644 polkit-1/localauthority.conf.d/50-localauthority.conf create mode 100644 polkit-1/localauthority.conf.d/51-debian-sudo.conf create mode 100644 polkit-1/nullbackend.conf.d/50-nullbackend.conf create mode 100644 postgresql-common/createcluster.conf create mode 100644 postgresql-common/root.crt create mode 100644 postgresql-common/supported_versions create mode 100644 postgresql-common/user_clusters create mode 100644 postgresql/11/main/environment create mode 100644 postgresql/11/main/pg_ctl.conf create mode 100644 postgresql/11/main/pg_hba.conf create mode 100644 postgresql/11/main/pg_ident.conf create mode 100644 postgresql/11/main/postgresql.conf create mode 100644 postgresql/11/main/start.conf create mode 100755 ppp/ip-down.d/000resolvconf create mode 100755 ppp/ip-up.d/000resolvconf create mode 100755 ppp/ip-up.d/exim4 create mode 100644 prelink.conf.d/cmk-update-agent.conf create mode 100644 profile create mode 100644 profile.d/at-dbus-fix.sh create mode 100644 profile.d/bash_completion.sh create mode 100644 profile.d/sshpwd.sh create mode 100644 profile.d/wifi-check.sh create mode 100644 protocols create mode 100644 python/debian_config create mode 100644 python2.7/sitecustomize.py create mode 100644 python3.7/sitecustomize.py create mode 100644 python3/debian_config create mode 100755 rc.local create mode 120000 rc0.d/K01alsa-utils create mode 120000 rc0.d/K01avahi-daemon create mode 120000 rc0.d/K01bluetooth create mode 120000 rc0.d/K01dhcpcd create mode 120000 rc0.d/K01docker create mode 120000 rc0.d/K01exim4 create mode 120000 rc0.d/K01fake-hwclock create mode 120000 rc0.d/K01hwclock.sh create mode 120000 rc0.d/K01mosquitto create mode 120000 rc0.d/K01netfilter-persistent create mode 120000 rc0.d/K01networking create mode 120000 rc0.d/K01nfs-common create mode 120000 rc0.d/K01nginx create mode 120000 rc0.d/K01paxctld create mode 120000 rc0.d/K01php7.3-fpm create mode 120000 rc0.d/K01pihole-FTL create mode 120000 rc0.d/K01postgresql create mode 120000 rc0.d/K01redis-server create mode 120000 rc0.d/K01resolvconf create mode 120000 rc0.d/K01rng-tools create mode 120000 rc0.d/K01rpcbind create mode 120000 rc0.d/K01rsyslog create mode 120000 rc0.d/K01snmpd create mode 120000 rc0.d/K01tftpd-hpa create mode 120000 rc0.d/K01triggerhappy create mode 120000 rc0.d/K01udev create mode 120000 rc0.d/K01xinetd create mode 120000 rc1.d/K01alsa-utils create mode 120000 rc1.d/K01avahi-daemon create mode 120000 rc1.d/K01bluetooth create mode 120000 rc1.d/K01dhcpcd create mode 120000 rc1.d/K01docker create mode 120000 rc1.d/K01exim4 create mode 120000 rc1.d/K01fake-hwclock create mode 120000 rc1.d/K01mosquitto create mode 120000 rc1.d/K01netfilter-persistent create mode 120000 rc1.d/K01nfs-common create mode 120000 rc1.d/K01nginx create mode 120000 rc1.d/K01paxctld create mode 120000 rc1.d/K01php7.3-fpm create mode 120000 rc1.d/K01pihole-FTL create mode 120000 rc1.d/K01postgresql create mode 120000 rc1.d/K01redis-server create mode 120000 rc1.d/K01rng-tools create mode 120000 rc1.d/K01rpcbind create mode 120000 rc1.d/K01rsyslog create mode 120000 rc1.d/K01snmpd create mode 120000 rc1.d/K01tftpd-hpa create mode 120000 rc1.d/K01triggerhappy create mode 120000 rc1.d/K01xinetd create mode 120000 rc2.d/K01mosquitto create mode 120000 rc2.d/K01pihole-FTL create mode 120000 rc2.d/K01snmpd create mode 120000 rc2.d/S01avahi-daemon create mode 120000 rc2.d/S01bluetooth create mode 120000 rc2.d/S01console-setup.sh create mode 120000 rc2.d/S01cron create mode 120000 rc2.d/S01dbus create mode 120000 rc2.d/S01dhcpcd create mode 120000 rc2.d/S01docker create mode 120000 rc2.d/S01dphys-swapfile create mode 120000 rc2.d/S01exim4 create mode 120000 rc2.d/S01nginx create mode 120000 rc2.d/S01ntp create mode 120000 rc2.d/S01paxctld create mode 120000 rc2.d/S01php7.3-fpm create mode 120000 rc2.d/S01postgresql create mode 120000 rc2.d/S01raspi-config create mode 120000 rc2.d/S01redis-server create mode 120000 rc2.d/S01rng-tools create mode 120000 rc2.d/S01rsync create mode 120000 rc2.d/S01rsyslog create mode 120000 rc2.d/S01ssh create mode 120000 rc2.d/S01sudo create mode 120000 rc2.d/S01sysstat create mode 120000 rc2.d/S01tftpd-hpa create mode 120000 rc2.d/S01triggerhappy create mode 120000 rc2.d/S01xinetd create mode 120000 rc3.d/K01mosquitto create mode 120000 rc3.d/K01pihole-FTL create mode 120000 rc3.d/K01snmpd create mode 120000 rc3.d/S01avahi-daemon create mode 120000 rc3.d/S01bluetooth create mode 120000 rc3.d/S01console-setup.sh create mode 120000 rc3.d/S01cron create mode 120000 rc3.d/S01dbus create mode 120000 rc3.d/S01dhcpcd create mode 120000 rc3.d/S01docker create mode 120000 rc3.d/S01dphys-swapfile create mode 120000 rc3.d/S01exim4 create mode 120000 rc3.d/S01nginx create mode 120000 rc3.d/S01ntp create mode 120000 rc3.d/S01paxctld create mode 120000 rc3.d/S01php7.3-fpm create mode 120000 rc3.d/S01postgresql create mode 120000 rc3.d/S01raspi-config create mode 120000 rc3.d/S01redis-server create mode 120000 rc3.d/S01rng-tools create mode 120000 rc3.d/S01rsync create mode 120000 rc3.d/S01rsyslog create mode 120000 rc3.d/S01ssh create mode 120000 rc3.d/S01sudo create mode 120000 rc3.d/S01sysstat create mode 120000 rc3.d/S01tftpd-hpa create mode 120000 rc3.d/S01triggerhappy create mode 120000 rc3.d/S01xinetd create mode 120000 rc4.d/K01mosquitto create mode 120000 rc4.d/K01pihole-FTL create mode 120000 rc4.d/K01snmpd create mode 120000 rc4.d/S01avahi-daemon create mode 120000 rc4.d/S01bluetooth create mode 120000 rc4.d/S01console-setup.sh create mode 120000 rc4.d/S01cron create mode 120000 rc4.d/S01dbus create mode 120000 rc4.d/S01dhcpcd create mode 120000 rc4.d/S01docker create mode 120000 rc4.d/S01dphys-swapfile create mode 120000 rc4.d/S01exim4 create mode 120000 rc4.d/S01nginx create mode 120000 rc4.d/S01ntp create mode 120000 rc4.d/S01paxctld create mode 120000 rc4.d/S01php7.3-fpm create mode 120000 rc4.d/S01postgresql create mode 120000 rc4.d/S01raspi-config create mode 120000 rc4.d/S01redis-server create mode 120000 rc4.d/S01rng-tools create mode 120000 rc4.d/S01rsync create mode 120000 rc4.d/S01rsyslog create mode 120000 rc4.d/S01ssh create mode 120000 rc4.d/S01sudo create mode 120000 rc4.d/S01sysstat create mode 120000 rc4.d/S01tftpd-hpa create mode 120000 rc4.d/S01triggerhappy create mode 120000 rc4.d/S01xinetd create mode 120000 rc5.d/K01mosquitto create mode 120000 rc5.d/K01pihole-FTL create mode 120000 rc5.d/K01snmpd create mode 120000 rc5.d/S01avahi-daemon create mode 120000 rc5.d/S01bluetooth create mode 120000 rc5.d/S01console-setup.sh create mode 120000 rc5.d/S01cron create mode 120000 rc5.d/S01dbus create mode 120000 rc5.d/S01dhcpcd create mode 120000 rc5.d/S01docker create mode 120000 rc5.d/S01dphys-swapfile create mode 120000 rc5.d/S01exim4 create mode 120000 rc5.d/S01nginx create mode 120000 rc5.d/S01ntp create mode 120000 rc5.d/S01paxctld create mode 120000 rc5.d/S01php7.3-fpm create mode 120000 rc5.d/S01postgresql create mode 120000 rc5.d/S01raspi-config create mode 120000 rc5.d/S01redis-server create mode 120000 rc5.d/S01rng-tools create mode 120000 rc5.d/S01rsync create mode 120000 rc5.d/S01rsyslog create mode 120000 rc5.d/S01ssh create mode 120000 rc5.d/S01sudo create mode 120000 rc5.d/S01sysstat create mode 120000 rc5.d/S01tftpd-hpa create mode 120000 rc5.d/S01triggerhappy create mode 120000 rc5.d/S01xinetd create mode 120000 rc6.d/K01alsa-utils create mode 120000 rc6.d/K01avahi-daemon create mode 120000 rc6.d/K01bluetooth create mode 120000 rc6.d/K01dhcpcd create mode 120000 rc6.d/K01docker create mode 120000 rc6.d/K01exim4 create mode 120000 rc6.d/K01fake-hwclock create mode 120000 rc6.d/K01hwclock.sh create mode 120000 rc6.d/K01mosquitto create mode 120000 rc6.d/K01netfilter-persistent create mode 120000 rc6.d/K01networking create mode 120000 rc6.d/K01nfs-common create mode 120000 rc6.d/K01nginx create mode 120000 rc6.d/K01paxctld create mode 120000 rc6.d/K01php7.3-fpm create mode 120000 rc6.d/K01pihole-FTL create mode 120000 rc6.d/K01postgresql create mode 120000 rc6.d/K01redis-server create mode 120000 rc6.d/K01resolvconf create mode 120000 rc6.d/K01rng-tools create mode 120000 rc6.d/K01rpcbind create mode 120000 rc6.d/K01rsyslog create mode 120000 rc6.d/K01snmpd create mode 120000 rc6.d/K01tftpd-hpa create mode 120000 rc6.d/K01triggerhappy create mode 120000 rc6.d/K01udev create mode 120000 rc6.d/K01xinetd create mode 120000 rcS.d/K01hwclock.sh create mode 120000 rcS.d/K01nfs-common create mode 120000 rcS.d/K01rpcbind create mode 120000 rcS.d/S01alsa-utils create mode 120000 rcS.d/S01fake-hwclock create mode 120000 rcS.d/S01keyboard-setup.sh create mode 120000 rcS.d/S01kmod create mode 120000 rcS.d/S01netfilter-persistent create mode 120000 rcS.d/S01networking create mode 120000 rcS.d/S01procps create mode 120000 rcS.d/S01raspi-config create mode 120000 rcS.d/S01resolvconf create mode 120000 rcS.d/S01udev create mode 120000 rcS.d/S01x11-common create mode 100644 redis/redis.conf create mode 100644 request-key.conf create mode 100644 request-key.d/cifs.idmap.conf create mode 100644 request-key.d/cifs.spnego.conf create mode 100644 request-key.d/id_resolver.conf create mode 120000 resolv.conf create mode 100644 resolv.conf.bak create mode 100644 resolvconf.conf create mode 100644 resolvconf/interface-order create mode 100644 resolvconf/resolv.conf.d/base create mode 100644 resolvconf/resolv.conf.d/head create mode 100644 resolvconf/resolv.conf.d/original create mode 100644 resolvconf/resolv.conf.d/tail create mode 120000 resolvconf/run create mode 100755 resolvconf/update.d/libc create mode 120000 rmt create mode 100644 rpc create mode 100644 rpi-issue create mode 100644 rsyslog-keys/ca.pem create mode 100644 rsyslog.conf create mode 100644 rsyslog.d/rsyslog-tls.conf create mode 100644 securetty create mode 100644 security/access.conf create mode 100644 security/group.conf create mode 100644 security/limits.conf create mode 100644 security/namespace.conf create mode 100755 security/namespace.init create mode 100644 security/opasswd create mode 100644 security/pam_env.conf create mode 100644 security/sepermit.conf create mode 100644 security/time.conf create mode 100644 selinux/semanage.conf create mode 100644 sensors.d/.placeholder create mode 100644 sensors3.conf create mode 100644 services create mode 100644 shadow create mode 100644 shadow- create mode 100644 shells create mode 100644 skel/.bash_logout create mode 100644 skel/.bashrc create mode 100644 skel/.profile create mode 100644 snmp-mibs-downloader/cisco.conf create mode 100644 snmp-mibs-downloader/ciscolist create mode 100644 snmp-mibs-downloader/iana.conf create mode 100644 snmp-mibs-downloader/ianalist create mode 100644 snmp-mibs-downloader/ianarfc.conf create mode 100644 snmp-mibs-downloader/ianarfclist create mode 100644 snmp-mibs-downloader/junos.conf create mode 100644 snmp-mibs-downloader/junoslist create mode 100644 snmp-mibs-downloader/rfc.conf create mode 100644 snmp-mibs-downloader/rfclist create mode 100644 snmp-mibs-downloader/rfcmibs.diff create mode 100644 snmp-mibs-downloader/screenos.conf create mode 100644 snmp-mibs-downloader/screenoslist create mode 100644 snmp-mibs-downloader/simplelist create mode 100644 snmp-mibs-downloader/simpleweb.conf create mode 100644 snmp-mibs-downloader/snmp-mibs-downloader.conf create mode 100644 snmp/snmp.conf create mode 100644 snmp/snmpd.conf create mode 100644 ssh/moduli create mode 100644 ssh/ssh_config create mode 100644 ssh/ssh_host_dsa_key create mode 100644 ssh/ssh_host_dsa_key.pub create mode 100644 ssh/ssh_host_ecdsa_key create mode 100644 ssh/ssh_host_ecdsa_key.pub create mode 100644 ssh/ssh_host_ed25519_key create mode 100644 ssh/ssh_host_ed25519_key.pub create mode 100644 ssh/ssh_host_rsa_key create mode 100644 ssh/ssh_host_rsa_key.pub create mode 100644 ssh/ssh_import_id create mode 100644 ssh/sshd_config create mode 120000 ssl/certs/02265526.0 create mode 120000 ssl/certs/03179a64.0 create mode 120000 ssl/certs/062cdee6.0 create mode 120000 ssl/certs/064e0aa9.0 create mode 120000 ssl/certs/06dc52d5.0 create mode 120000 ssl/certs/080911ac.0 create mode 120000 ssl/certs/09789157.0 create mode 120000 ssl/certs/0a775a30.0 create mode 120000 ssl/certs/0b1b94ef.0 create mode 120000 ssl/certs/0bf05006.0 create mode 120000 ssl/certs/0c4c9b6c.0 create mode 120000 ssl/certs/0f5dc4f3.0 create mode 120000 ssl/certs/0f6fa695.0 create mode 120000 ssl/certs/1001acf7.0 create mode 120000 ssl/certs/106f3e4d.0 create mode 120000 ssl/certs/128805a3.0 create mode 120000 ssl/certs/14bc7599.0 create mode 120000 ssl/certs/1636090b.0 create mode 120000 ssl/certs/18856ac4.0 create mode 120000 ssl/certs/1d3472b9.0 create mode 120000 ssl/certs/1e08bfd1.0 create mode 120000 ssl/certs/1e09d511.0 create mode 120000 ssl/certs/244b5494.0 create mode 120000 ssl/certs/2923b3f9.0 create mode 120000 ssl/certs/2ae6433e.0 create mode 120000 ssl/certs/2b349938.0 create mode 120000 ssl/certs/2e5ac55d.0 create mode 120000 ssl/certs/32888f65.0 create mode 120000 ssl/certs/349f2832.0 create mode 120000 ssl/certs/3513523f.0 create mode 120000 ssl/certs/3bde41ac.0 create mode 120000 ssl/certs/3e44d2f7.0 create mode 120000 ssl/certs/3e45d192.0 create mode 120000 ssl/certs/40193066.0 create mode 120000 ssl/certs/4042bcee.0 create mode 120000 ssl/certs/40547a79.0 create mode 120000 ssl/certs/406c9bb1.0 create mode 120000 ssl/certs/4304c5e5.0 create mode 120000 ssl/certs/48bec511.0 create mode 120000 ssl/certs/4a6481c9.0 create mode 120000 ssl/certs/4b718d9b.0 create mode 120000 ssl/certs/4bfab552.0 create mode 120000 ssl/certs/4ed8e614 create mode 120000 ssl/certs/4f316efb.0 create mode 120000 ssl/certs/5273a94c.0 create mode 120000 ssl/certs/5443e9e3.0 create mode 120000 ssl/certs/54657681.0 create mode 120000 ssl/certs/57bcb2da.0 create mode 120000 ssl/certs/5a4d6896.0 create mode 120000 ssl/certs/5ad8a5d6.0 create mode 120000 ssl/certs/5c44d531.0 create mode 120000 ssl/certs/5cd81ad7.0 create mode 120000 ssl/certs/5d3033c5.0 create mode 120000 ssl/certs/5e98733a.0 create mode 120000 ssl/certs/5f15c80c.0 create mode 120000 ssl/certs/607986c7.0 create mode 120000 ssl/certs/626dceaf.0 create mode 120000 ssl/certs/6410666e.0 create mode 120000 ssl/certs/653b494a.0 create mode 120000 ssl/certs/68dd7389.0 create mode 120000 ssl/certs/6b99d060.0 create mode 120000 ssl/certs/6d41d539.0 create mode 120000 ssl/certs/6fa5da56.0 create mode 120000 ssl/certs/706f604c.0 create mode 120000 ssl/certs/749e9e03.0 create mode 120000 ssl/certs/75d1b2ed.0 create mode 120000 ssl/certs/76cb8f92.0 create mode 120000 ssl/certs/76faf6c0.0 create mode 120000 ssl/certs/7719f463.0 create mode 120000 ssl/certs/773e07ad.0 create mode 120000 ssl/certs/7aaf71c0.0 create mode 120000 ssl/certs/7f3d5d1d.0 create mode 120000 ssl/certs/8160b96c.0 create mode 120000 ssl/certs/8867006a.0 create mode 120000 ssl/certs/8cb5ee0f.0 create mode 120000 ssl/certs/8d86cdd1.0 create mode 120000 ssl/certs/930ac5d2.0 create mode 120000 ssl/certs/93bc0acc.0 create mode 120000 ssl/certs/988a38cb.0 create mode 120000 ssl/certs/9c2e7d30.0 create mode 120000 ssl/certs/9c8dfbd4.0 create mode 120000 ssl/certs/9d04f354.0 create mode 120000 ssl/certs/ACCVRAIZ1.pem create mode 120000 ssl/certs/AC_RAIZ_FNMT-RCM.pem create mode 120000 ssl/certs/Actalis_Authentication_Root_CA.pem create mode 120000 ssl/certs/AffirmTrust_Commercial.pem create mode 120000 ssl/certs/AffirmTrust_Networking.pem create mode 120000 ssl/certs/AffirmTrust_Premium.pem create mode 120000 ssl/certs/AffirmTrust_Premium_ECC.pem create mode 120000 ssl/certs/Amazon_Root_CA_1.pem create mode 120000 ssl/certs/Amazon_Root_CA_2.pem create mode 120000 ssl/certs/Amazon_Root_CA_3.pem create mode 120000 ssl/certs/Amazon_Root_CA_4.pem create mode 120000 ssl/certs/Atos_TrustedRoot_2011.pem create mode 120000 ssl/certs/Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.pem create mode 120000 ssl/certs/Baltimore_CyberTrust_Root.pem create mode 120000 ssl/certs/Buypass_Class_2_Root_CA.pem create mode 120000 ssl/certs/Buypass_Class_3_Root_CA.pem create mode 120000 ssl/certs/CA_Disig_Root_R2.pem create mode 120000 ssl/certs/CFCA_EV_ROOT.pem create mode 120000 ssl/certs/COMODO_Certification_Authority.pem create mode 120000 ssl/certs/COMODO_ECC_Certification_Authority.pem create mode 120000 ssl/certs/COMODO_RSA_Certification_Authority.pem create mode 120000 ssl/certs/Certigna.pem create mode 120000 ssl/certs/Certigna_Root_CA.pem create mode 120000 ssl/certs/Certum_Trusted_Network_CA.pem create mode 120000 ssl/certs/Certum_Trusted_Network_CA_2.pem create mode 120000 ssl/certs/Chambers_of_Commerce_Root_-_2008.pem create mode 120000 ssl/certs/Comodo_AAA_Services_root.pem create mode 120000 ssl/certs/Cybertrust_Global_Root.pem create mode 120000 ssl/certs/D-TRUST_Root_Class_3_CA_2_2009.pem create mode 120000 ssl/certs/D-TRUST_Root_Class_3_CA_2_EV_2009.pem create mode 120000 ssl/certs/DST_Root_CA_X3.pem create mode 120000 ssl/certs/DigiCert_Assured_ID_Root_CA.pem create mode 120000 ssl/certs/DigiCert_Assured_ID_Root_G2.pem create mode 120000 ssl/certs/DigiCert_Assured_ID_Root_G3.pem create mode 120000 ssl/certs/DigiCert_Global_Root_CA.pem create mode 120000 ssl/certs/DigiCert_Global_Root_G2.pem create mode 120000 ssl/certs/DigiCert_Global_Root_G3.pem create mode 120000 ssl/certs/DigiCert_High_Assurance_EV_Root_CA.pem create mode 120000 ssl/certs/DigiCert_Trusted_Root_G4.pem create mode 120000 ssl/certs/E-Tugra_Certification_Authority.pem create mode 120000 ssl/certs/EC-ACC.pem create mode 120000 ssl/certs/EE_Certification_Centre_Root_CA.pem create mode 120000 ssl/certs/Entrust.net_Premium_2048_Secure_Server_CA.pem create mode 120000 ssl/certs/Entrust_Root_Certification_Authority.pem create mode 120000 ssl/certs/Entrust_Root_Certification_Authority_-_EC1.pem create mode 120000 ssl/certs/Entrust_Root_Certification_Authority_-_G2.pem create mode 120000 ssl/certs/Entrust_Root_Certification_Authority_-_G4.pem create mode 120000 ssl/certs/GDCA_TrustAUTH_R5_ROOT.pem create mode 120000 ssl/certs/GTS_Root_R1.pem create mode 120000 ssl/certs/GTS_Root_R2.pem create mode 120000 ssl/certs/GTS_Root_R3.pem create mode 120000 ssl/certs/GTS_Root_R4.pem create mode 120000 ssl/certs/GeoTrust_Universal_CA_2.pem create mode 120000 ssl/certs/GlobalSign_ECC_Root_CA_-_R4.pem create mode 120000 ssl/certs/GlobalSign_ECC_Root_CA_-_R5.pem create mode 120000 ssl/certs/GlobalSign_Root_CA.pem create mode 120000 ssl/certs/GlobalSign_Root_CA_-_R2.pem create mode 120000 ssl/certs/GlobalSign_Root_CA_-_R3.pem create mode 120000 ssl/certs/GlobalSign_Root_CA_-_R6.pem create mode 120000 ssl/certs/Global_Chambersign_Root_-_2008.pem create mode 120000 ssl/certs/Go_Daddy_Class_2_CA.pem create mode 120000 ssl/certs/Go_Daddy_Root_Certificate_Authority_-_G2.pem create mode 120000 ssl/certs/Hellenic_Academic_and_Research_Institutions_ECC_RootCA_2015.pem create mode 120000 ssl/certs/Hellenic_Academic_and_Research_Institutions_RootCA_2011.pem create mode 120000 ssl/certs/Hellenic_Academic_and_Research_Institutions_RootCA_2015.pem create mode 120000 ssl/certs/Hongkong_Post_Root_CA_1.pem create mode 120000 ssl/certs/Hongkong_Post_Root_CA_3.pem create mode 120000 ssl/certs/ISRG_Root_X1.pem create mode 120000 ssl/certs/IdenTrust_Commercial_Root_CA_1.pem create mode 120000 ssl/certs/IdenTrust_Public_Sector_Root_CA_1.pem create mode 120000 ssl/certs/Izenpe.com.pem create mode 120000 ssl/certs/LuxTrust_Global_Root_2.pem create mode 120000 ssl/certs/Microsec_e-Szigno_Root_CA_2009.pem create mode 120000 ssl/certs/NetLock_Arany_=Class_Gold=_Főtanúsítvány.pem create mode 120000 ssl/certs/Network_Solutions_Certificate_Authority.pem create mode 120000 ssl/certs/OISTE_WISeKey_Global_Root_GA_CA.pem create mode 120000 ssl/certs/OISTE_WISeKey_Global_Root_GB_CA.pem create mode 120000 ssl/certs/OISTE_WISeKey_Global_Root_GC_CA.pem create mode 120000 ssl/certs/QuoVadis_Root_CA.pem create mode 120000 ssl/certs/QuoVadis_Root_CA_1_G3.pem create mode 120000 ssl/certs/QuoVadis_Root_CA_2.pem create mode 120000 ssl/certs/QuoVadis_Root_CA_2_G3.pem create mode 120000 ssl/certs/QuoVadis_Root_CA_3.pem create mode 120000 ssl/certs/QuoVadis_Root_CA_3_G3.pem create mode 120000 ssl/certs/SSL.com_EV_Root_Certification_Authority_ECC.pem create mode 120000 ssl/certs/SSL.com_EV_Root_Certification_Authority_RSA_R2.pem create mode 120000 ssl/certs/SSL.com_Root_Certification_Authority_ECC.pem create mode 120000 ssl/certs/SSL.com_Root_Certification_Authority_RSA.pem create mode 120000 ssl/certs/SZAFIR_ROOT_CA2.pem create mode 120000 ssl/certs/SecureSign_RootCA11.pem create mode 120000 ssl/certs/SecureTrust_CA.pem create mode 120000 ssl/certs/Secure_Global_CA.pem create mode 120000 ssl/certs/Security_Communication_RootCA2.pem create mode 120000 ssl/certs/Security_Communication_Root_CA.pem create mode 120000 ssl/certs/Sonera_Class_2_Root_CA.pem create mode 120000 ssl/certs/Staat_der_Nederlanden_EV_Root_CA.pem create mode 120000 ssl/certs/Staat_der_Nederlanden_Root_CA_-_G2.pem create mode 120000 ssl/certs/Staat_der_Nederlanden_Root_CA_-_G3.pem create mode 120000 ssl/certs/Starfield_Class_2_CA.pem create mode 120000 ssl/certs/Starfield_Root_Certificate_Authority_-_G2.pem create mode 120000 ssl/certs/Starfield_Services_Root_Certificate_Authority_-_G2.pem create mode 120000 ssl/certs/SwissSign_Gold_CA_-_G2.pem create mode 120000 ssl/certs/SwissSign_Silver_CA_-_G2.pem create mode 120000 ssl/certs/T-TeleSec_GlobalRoot_Class_2.pem create mode 120000 ssl/certs/T-TeleSec_GlobalRoot_Class_3.pem create mode 120000 ssl/certs/TUBITAK_Kamu_SM_SSL_Kok_Sertifikasi_-_Surum_1.pem create mode 120000 ssl/certs/TWCA_Global_Root_CA.pem create mode 120000 ssl/certs/TWCA_Root_Certification_Authority.pem create mode 120000 ssl/certs/Taiwan_GRCA.pem create mode 120000 ssl/certs/TeliaSonera_Root_CA_v1.pem create mode 120000 ssl/certs/TrustCor_ECA-1.pem create mode 120000 ssl/certs/TrustCor_RootCert_CA-1.pem create mode 120000 ssl/certs/TrustCor_RootCert_CA-2.pem create mode 120000 ssl/certs/Trustis_FPS_Root_CA.pem create mode 120000 ssl/certs/UCA_Extended_Validation_Root.pem create mode 120000 ssl/certs/UCA_Global_G2_Root.pem create mode 120000 ssl/certs/USERTrust_ECC_Certification_Authority.pem create mode 120000 ssl/certs/USERTrust_RSA_Certification_Authority.pem create mode 120000 ssl/certs/Verisign_Class_3_Public_Primary_Certification_Authority_-_G3.pem create mode 120000 ssl/certs/XRamp_Global_CA_Root.pem create mode 120000 ssl/certs/a3418fda.0 create mode 120000 ssl/certs/a94d09e5.0 create mode 120000 ssl/certs/aee5f10d.0 create mode 120000 ssl/certs/b0e59380.0 create mode 120000 ssl/certs/b1159c4c.0 create mode 120000 ssl/certs/b1b8a7f3.0 create mode 120000 ssl/certs/b66938e9.0 create mode 120000 ssl/certs/b727005e.0 create mode 120000 ssl/certs/b7a5b843.0 create mode 120000 ssl/certs/c01eb047.0 create mode 120000 ssl/certs/c0ff1f52.0 create mode 120000 ssl/certs/c28a8a30.0 create mode 120000 ssl/certs/c47d9980.0 create mode 100644 ssl/certs/ca-certificates.crt create mode 120000 ssl/certs/ca6e4ad9.0 create mode 120000 ssl/certs/cbf06781.0 create mode 120000 ssl/certs/cc450945.0 create mode 120000 ssl/certs/cd58d51e.0 create mode 120000 ssl/certs/cd8c0d63.0 create mode 120000 ssl/certs/ce5e74ef.0 create mode 120000 ssl/certs/certSIGN_ROOT_CA.pem create mode 120000 ssl/certs/d4dae3dd.0 create mode 120000 ssl/certs/d6325660.0 create mode 120000 ssl/certs/d7e8dc79.0 create mode 120000 ssl/certs/d853d49e.0 create mode 120000 ssl/certs/dc4d6a89.0 create mode 120000 ssl/certs/dd8e9d41.0 create mode 120000 ssl/certs/de6d66f3.0 create mode 120000 ssl/certs/def36a68.0 create mode 120000 ssl/certs/e113c810.0 create mode 120000 ssl/certs/e18bfb83.0 create mode 120000 ssl/certs/e36a6752.0 create mode 120000 ssl/certs/e73d606e.0 create mode 120000 ssl/certs/e8de2f56.0 create mode 120000 ssl/certs/ePKI_Root_Certification_Authority.pem create mode 120000 ssl/certs/ee64a828.0 create mode 120000 ssl/certs/eed8c118.0 create mode 120000 ssl/certs/ef954a4e.0 create mode 120000 ssl/certs/emSign_ECC_Root_CA_-_C3.pem create mode 120000 ssl/certs/emSign_ECC_Root_CA_-_G3.pem create mode 120000 ssl/certs/emSign_Root_CA_-_C1.pem create mode 120000 ssl/certs/emSign_Root_CA_-_G1.pem create mode 120000 ssl/certs/f081611a.0 create mode 120000 ssl/certs/f0c70a8d.0 create mode 120000 ssl/certs/f30dd6ad.0 create mode 120000 ssl/certs/f3377b1b.0 create mode 120000 ssl/certs/f387163d.0 create mode 120000 ssl/certs/f39fc864.0 create mode 120000 ssl/certs/f51bb24c.0 create mode 120000 ssl/certs/fc5a8f99.0 create mode 120000 ssl/certs/fe8a2cd8.0 create mode 120000 ssl/certs/ff34af3f.0 create mode 100644 ssl/certs/java/cacerts create mode 100644 ssl/certs/ssl-cert-snakeoil.pem create mode 100644 ssl/openssl.cnf create mode 100644 ssl/private/ssl-cert-snakeoil.key create mode 100644 subgid create mode 100644 subgid- create mode 100644 subuid create mode 100644 subuid- create mode 100644 sudoers create mode 100644 sudoers.d/010_at-export create mode 100644 sudoers.d/010_pi-nopasswd create mode 100644 sudoers.d/010_proxy create mode 100644 sudoers.d/README create mode 100644 sudoers.d/iobroker create mode 100644 sysctl.conf create mode 100644 sysctl.d/30-postgresql-shm.conf create mode 100644 sysctl.d/98-rpi.conf create mode 120000 sysctl.d/99-sysctl.conf create mode 100644 sysctl.d/README.sysctl create mode 100644 sysctl.d/protect-links.conf create mode 100644 sysstat/sysstat create mode 100644 sysstat/sysstat.ioconf create mode 100644 systemd/journald.conf create mode 100644 systemd/logind.conf create mode 120000 systemd/network/99-default.link create mode 100644 systemd/networkd.conf create mode 100644 systemd/resolved.conf create mode 100644 systemd/sleep.conf create mode 100644 systemd/system.conf create mode 100644 systemd/system/AdGuardHome.service create mode 100644 systemd/system/autologin@.service create mode 120000 systemd/system/bluetooth.target.wants/bluetooth.service create mode 100644 systemd/system/check-mk-agent-async.service create mode 100644 systemd/system/check-mk-agent.socket create mode 100644 systemd/system/check-mk-agent@.service create mode 120000 systemd/system/dbus-fi.w1.wpa_supplicant1.service create mode 120000 systemd/system/dbus-org.bluez.service create mode 120000 systemd/system/dbus-org.freedesktop.Avahi.service create mode 120000 systemd/system/dbus-org.freedesktop.timesync1.service create mode 100644 systemd/system/dhcpcd.service.d/wait.conf create mode 120000 systemd/system/dhcpcd5.service create mode 120000 systemd/system/getty.target.wants/getty@tty1.service create mode 100644 systemd/system/getty@tty1.service.d/noclear.conf create mode 100644 systemd/system/gitea.service create mode 120000 systemd/system/halt.target.wants/rpi-display-backlight.service create mode 120000 systemd/system/mosquitto.service create mode 120000 systemd/system/multi-user.target.wants/AdGuardHome.service create mode 120000 systemd/system/multi-user.target.wants/avahi-daemon.service create mode 120000 systemd/system/multi-user.target.wants/check-mk-agent-async.service create mode 120000 systemd/system/multi-user.target.wants/console-setup.service create mode 120000 systemd/system/multi-user.target.wants/containerd.service create mode 120000 systemd/system/multi-user.target.wants/cron.service create mode 120000 systemd/system/multi-user.target.wants/dhcpcd.service create mode 120000 systemd/system/multi-user.target.wants/docker.service create mode 120000 systemd/system/multi-user.target.wants/dphys-swapfile.service create mode 120000 systemd/system/multi-user.target.wants/etckeeper.timer create mode 120000 systemd/system/multi-user.target.wants/gitea.service create mode 120000 systemd/system/multi-user.target.wants/hciuart.service create mode 120000 systemd/system/multi-user.target.wants/mosquitto.service create mode 120000 systemd/system/multi-user.target.wants/netfilter-persistent.service create mode 120000 systemd/system/multi-user.target.wants/networking.service create mode 120000 systemd/system/multi-user.target.wants/nfs-client.target create mode 120000 systemd/system/multi-user.target.wants/nginx.service create mode 120000 systemd/system/multi-user.target.wants/ntp.service create mode 120000 systemd/system/multi-user.target.wants/php7.3-fpm.service create mode 120000 systemd/system/multi-user.target.wants/postgresql.service create mode 120000 systemd/system/multi-user.target.wants/raspberrypi-net-mods.service create mode 120000 systemd/system/multi-user.target.wants/redis-server.service create mode 120000 systemd/system/multi-user.target.wants/remote-fs.target create mode 120000 systemd/system/multi-user.target.wants/rpi-eeprom-update.service create mode 120000 systemd/system/multi-user.target.wants/rsync.service create mode 120000 systemd/system/multi-user.target.wants/rsyslog.service create mode 120000 systemd/system/multi-user.target.wants/ssh.service create mode 120000 systemd/system/multi-user.target.wants/sshswitch.service create mode 120000 systemd/system/multi-user.target.wants/sysstat.service create mode 120000 systemd/system/multi-user.target.wants/triggerhappy.service create mode 120000 systemd/system/multi-user.target.wants/wpa_supplicant.service create mode 120000 systemd/system/netfilter-persistent.service create mode 120000 systemd/system/network-online.target.wants/networking.service create mode 120000 systemd/system/poweroff.target.wants/rpi-display-backlight.service create mode 100644 systemd/system/rc-local.service.d/ttyoutput.conf create mode 120000 systemd/system/reboot.target.wants/rpi-display-backlight.service create mode 120000 systemd/system/remote-fs.target.wants/nfs-client.target create mode 120000 systemd/system/sockets.target.wants/avahi-daemon.socket create mode 120000 systemd/system/sockets.target.wants/check-mk-agent.socket create mode 120000 systemd/system/sockets.target.wants/docker.socket create mode 120000 systemd/system/sockets.target.wants/triggerhappy.socket create mode 120000 systemd/system/sshd.service create mode 120000 systemd/system/sysinit.target.wants/fake-hwclock.service create mode 120000 systemd/system/sysinit.target.wants/keyboard-setup.service create mode 120000 systemd/system/sysinit.target.wants/resolvconf.service create mode 120000 systemd/system/sysinit.target.wants/systemd-timesyncd.service create mode 120000 systemd/system/syslog.service create mode 120000 systemd/system/timers.target.wants/apt-daily-upgrade.timer create mode 120000 systemd/system/timers.target.wants/apt-daily.timer create mode 120000 systemd/system/timers.target.wants/logrotate.timer create mode 120000 systemd/system/timers.target.wants/man-db.timer create mode 120000 systemd/system/timers.target.wants/phpsessionclean.timer create mode 100644 systemd/timesyncd.conf create mode 100644 systemd/user.conf create mode 100644 terminfo/README create mode 100644 timezone create mode 100644 ucf.conf create mode 100644 udev/rules.d/99-com.rules create mode 100644 udev/udev.conf create mode 100644 ufw/applications.d/nginx create mode 100644 ufw/applications.d/openssh-server create mode 100755 update-motd.d/00-motd create mode 100644 usb_modeswitch.conf create mode 100644 vim/vimrc create mode 100644 vim/vimrc.tiny create mode 100644 wgetrc create mode 100644 wireguard_2021-01-28-103503.tar.gz create mode 100644 wireshark/init.lua create mode 100755 wpa_supplicant/action_wpa.sh create mode 100644 wpa_supplicant/functions.sh create mode 100755 wpa_supplicant/ifupdown.sh create mode 100644 wpa_supplicant/wpa_supplicant.conf create mode 100644 xattr.conf create mode 100644 xdg/autostart/xdg-user-dirs.desktop create mode 120000 xdg/systemd/user create mode 100644 xdg/user-dirs.conf create mode 100644 xdg/user-dirs.defaults create mode 100644 xinetd.conf create mode 100644 xinetd.d/chargen create mode 100644 xinetd.d/chargen-udp create mode 100644 xinetd.d/daytime create mode 100644 xinetd.d/daytime-udp create mode 100644 xinetd.d/discard create mode 100644 xinetd.d/discard-udp create mode 100644 xinetd.d/echo create mode 100644 xinetd.d/echo-udp create mode 100644 xinetd.d/servers create mode 100644 xinetd.d/services create mode 100644 xinetd.d/time create mode 100644 xinetd.d/time-udp diff --git a/.etckeeper b/.etckeeper new file mode 100755 index 00000000..cbce010b --- /dev/null +++ b/.etckeeper @@ -0,0 +1,1312 @@ +# Generated by etckeeper. Do not edit. + +mkdir -p './X11/xkb' +mkdir -p './apache2/conf-available' +mkdir -p './apache2/mods-available' +mkdir -p './apt/auth.conf.d' +mkdir -p './apt/preferences.d' +mkdir -p './avahi/services' +mkdir -p './binfmt.d' +mkdir -p './dbus-1/session.d' +mkdir -p './dnsmasq.d' +mkdir -p './gss/mech.d' +mkdir -p './initramfs-tools/conf.d' +mkdir -p './initramfs-tools/hooks' +mkdir -p './initramfs-tools/scripts/init-bottom' +mkdir -p './initramfs-tools/scripts/init-premount' +mkdir -p './initramfs-tools/scripts/init-top' +mkdir -p './initramfs-tools/scripts/local-bottom' +mkdir -p './initramfs-tools/scripts/local-premount' +mkdir -p './initramfs-tools/scripts/local-top' +mkdir -p './initramfs-tools/scripts/nfs-bottom' +mkdir -p './initramfs-tools/scripts/nfs-premount' +mkdir -p './initramfs-tools/scripts/nfs-top' +mkdir -p './initramfs-tools/scripts/panic' +mkdir -p './kernel/install.d' +mkdir -p './libpaper.d' +mkdir -p './mysql/mariadb.conf.d' +mkdir -p './network/interfaces.d' +mkdir -p './nginx/conf.d' +mkdir -p './nginx/conf.mail.d' +mkdir -p './nginx/conf.stream.d' +mkdir -p './nginx/modules-available' +mkdir -p './nginx/streams-available' +mkdir -p './nginx/streams-enabled' +mkdir -p './opt' +mkdir -p './perl/CPAN' +mkdir -p './polkit-1/localauthority/10-vendor.d' +mkdir -p './polkit-1/localauthority/20-org.d' +mkdir -p './polkit-1/localauthority/30-site.d' +mkdir -p './polkit-1/localauthority/50-local.d' +mkdir -p './polkit-1/localauthority/90-mandatory.d' +mkdir -p './postgresql-common/pg_upgradecluster.d' +mkdir -p './postgresql/11/main/conf.d' +mkdir -p './resolvconf/update-libc.d' +mkdir -p './security/limits.d' +mkdir -p './security/namespace.d' +mkdir -p './systemd/system/docker.service.d' +mkdir -p './systemd/user' +mkdir -p './tmpfiles.d' +mkdir -p './triggerhappy/triggers.d' +mkdir -p './udev/hwdb.d' +mkdir -p './usb_modeswitch.d' +mkdir -p './wireguard' +maybe chmod 0755 '.' +maybe chmod 0700 '.etckeeper' +maybe chmod 0644 '.fstab' +maybe chmod 0644 '.gitignore' +maybe chmod 0755 '.java' +maybe chmod 0755 '.java/.systemPrefs' +maybe chmod 0644 '.java/.systemPrefs/.system.lock' +maybe chmod 0644 '.java/.systemPrefs/.systemRootModFile' +maybe chmod 0755 'ImageMagick-6' +maybe chmod 0644 'ImageMagick-6/coder.xml' +maybe chmod 0644 'ImageMagick-6/colors.xml' +maybe chmod 0644 'ImageMagick-6/delegates.xml' +maybe chmod 0644 'ImageMagick-6/log.xml' +maybe chmod 0644 'ImageMagick-6/magic.xml' +maybe chmod 0644 'ImageMagick-6/mime.xml' +maybe chmod 0644 'ImageMagick-6/policy.xml' +maybe chmod 0644 'ImageMagick-6/quantization-table.xml' +maybe chmod 0644 'ImageMagick-6/thresholds.xml' +maybe chmod 0644 'ImageMagick-6/type-apple.xml' +maybe chmod 0644 'ImageMagick-6/type-dejavu.xml' +maybe chmod 0644 'ImageMagick-6/type-ghostscript.xml' +maybe chmod 0644 'ImageMagick-6/type-urw-base35.xml' +maybe chmod 0644 'ImageMagick-6/type-windows.xml' +maybe chmod 0644 'ImageMagick-6/type.xml' +maybe chmod 0755 'NetworkManager' +maybe chmod 0755 'NetworkManager/dispatcher.d' +maybe chmod 0755 'NetworkManager/dispatcher.d/ntp' +maybe chmod 0755 'X11' +maybe chmod 0755 'X11/Xreset' +maybe chmod 0755 'X11/Xreset.d' +maybe chmod 0644 'X11/Xreset.d/README' +maybe chmod 0755 'X11/Xresources' +maybe chmod 0644 'X11/Xresources/x11-common' +maybe chmod 0755 'X11/Xsession' +maybe chmod 0755 'X11/Xsession.d' +maybe chmod 0644 'X11/Xsession.d/20x11-common_process-args' +maybe chmod 0644 'X11/Xsession.d/30x11-common_xresources' +maybe chmod 0644 'X11/Xsession.d/35x11-common_xhost-local' +maybe chmod 0644 'X11/Xsession.d/40x11-common_xsessionrc' +maybe chmod 0644 'X11/Xsession.d/50x11-common_determine-startup' +maybe chmod 0644 'X11/Xsession.d/90gpg-agent' +maybe chmod 0644 'X11/Xsession.d/90x11-common_ssh-agent' +maybe chmod 0644 'X11/Xsession.d/99x11-common_start' +maybe chmod 0644 'X11/Xsession.options' +maybe chmod 0644 'X11/rgb.txt' +maybe chmod 0755 'X11/xkb' +maybe chmod 0644 'adduser.conf' +maybe chmod 0644 'aliases' +maybe chmod 0755 'alternatives' +maybe chmod 0644 'alternatives/README' +maybe chmod 0755 'apache2' +maybe chmod 0755 'apache2/conf-available' +maybe chmod 0755 'apache2/mods-available' +maybe chmod 0755 'apparmor' +maybe chmod 0755 'apparmor.d' +maybe chmod 0755 'apparmor.d/local' +maybe chmod 0644 'apparmor.d/local/usr.bin.man' +maybe chmod 0644 'apparmor.d/local/usr.sbin.ntpd' +maybe chmod 0755 'apparmor.d/tunables' +maybe chmod 0644 'apparmor.d/tunables/ntpd' +maybe chmod 0644 'apparmor.d/usr.bin.man' +maybe chmod 0644 'apparmor.d/usr.sbin.ntpd' +maybe chmod 0755 'apparmor/init' +maybe chmod 0755 'apparmor/init/network-interface-security' +maybe chmod 0755 'apt' +maybe chmod 0755 'apt/apt.conf.d' +maybe chmod 0644 'apt/apt.conf.d/01autoremove' +maybe chmod 0444 'apt/apt.conf.d/01autoremove-kernels' +maybe chmod 0644 'apt/apt.conf.d/01autoremove-postgresql' +maybe chmod 0644 'apt/apt.conf.d/05etckeeper' +maybe chmod 0644 'apt/apt.conf.d/15update-stamp' +maybe chmod 0644 'apt/apt.conf.d/20listchanges' +maybe chmod 0644 'apt/apt.conf.d/50raspi' +maybe chmod 0644 'apt/apt.conf.d/70debconf' +maybe chmod 0755 'apt/auth.conf.d' +maybe chmod 0644 'apt/listchanges.conf' +maybe chmod 0644 'apt/preferences' +maybe chmod 0755 'apt/preferences.d' +maybe chmod 0644 'apt/sources.list' +maybe chmod 0755 'apt/sources.list.d' +maybe chmod 0644 'apt/sources.list.d/docker.list' +maybe chmod 0644 'apt/sources.list.d/mosquitto-buster.list' +maybe chmod 0644 'apt/sources.list.d/nginx.list' +maybe chmod 0644 'apt/sources.list.d/nodesource.list' +maybe chmod 0644 'apt/sources.list.d/raspi.list' +maybe chmod 0644 'apt/sources.list.d/vscode.list' +maybe chmod 0644 'apt/trusted.gpg' +maybe chmod 0755 'apt/trusted.gpg.d' +maybe chmod 0644 'apt/trusted.gpg.d/microsoft.gpg' +maybe chmod 0755 'avahi' +maybe chmod 0644 'avahi/avahi-daemon.conf' +maybe chmod 0644 'avahi/hosts' +maybe chmod 0755 'avahi/services' +maybe chmod 0644 'bash.bashrc' +maybe chmod 0644 'bash_completion' +maybe chmod 0755 'bash_completion.d' +maybe chmod 0644 'bash_completion.d/git-prompt' +maybe chmod 0644 'bindresvport.blacklist' +maybe chmod 0755 'binfmt.d' +maybe chmod 0755 'bluetooth' +maybe chmod 0644 'bluetooth/input.conf' +maybe chmod 0644 'bluetooth/main.conf' +maybe chmod 0644 'bluetooth/network.conf' +maybe chmod 0755 'ca-certificates' +maybe chmod 0644 'ca-certificates.conf' +maybe chmod 0755 'ca-certificates/update.d' +maybe chmod 0755 'ca-certificates/update.d/jks-keystore' +maybe chmod 0755 'calendar' +maybe chmod 0644 'calendar/default' +maybe chmod 0770 'check_mk' +maybe chmod 0640 'check_mk/cmk-update-agent.cfg' +maybe chmod 0640 'check_mk/docker.cfg' +maybe chmod 0640 'check_mk/mk_inventory.cfg' +maybe chmod 0755 'cifs-utils' +maybe chmod 0600 'cmk-update-agent.state' +maybe chmod 0755 'console-setup' +maybe chmod 0644 'console-setup/cached_Lat15-Fixed16.psf.gz' +maybe chmod 0644 'console-setup/cached_UTF-8_del.kmap.gz' +maybe chmod 0755 'console-setup/cached_setup_font.sh' +maybe chmod 0755 'console-setup/cached_setup_keyboard.sh' +maybe chmod 0755 'console-setup/cached_setup_terminal.sh' +maybe chmod 0644 'console-setup/compose.ARMSCII-8.inc' +maybe chmod 0644 'console-setup/compose.CP1251.inc' +maybe chmod 0644 'console-setup/compose.CP1255.inc' +maybe chmod 0644 'console-setup/compose.CP1256.inc' +maybe chmod 0644 'console-setup/compose.GEORGIAN-ACADEMY.inc' +maybe chmod 0644 'console-setup/compose.GEORGIAN-PS.inc' +maybe chmod 0644 'console-setup/compose.IBM1133.inc' +maybe chmod 0644 'console-setup/compose.ISIRI-3342.inc' +maybe chmod 0644 'console-setup/compose.ISO-8859-1.inc' +maybe chmod 0644 'console-setup/compose.ISO-8859-10.inc' +maybe chmod 0644 'console-setup/compose.ISO-8859-11.inc' +maybe chmod 0644 'console-setup/compose.ISO-8859-13.inc' +maybe chmod 0644 'console-setup/compose.ISO-8859-14.inc' +maybe chmod 0644 'console-setup/compose.ISO-8859-15.inc' +maybe chmod 0644 'console-setup/compose.ISO-8859-16.inc' +maybe chmod 0644 'console-setup/compose.ISO-8859-2.inc' +maybe chmod 0644 'console-setup/compose.ISO-8859-3.inc' +maybe chmod 0644 'console-setup/compose.ISO-8859-4.inc' +maybe chmod 0644 'console-setup/compose.ISO-8859-5.inc' +maybe chmod 0644 'console-setup/compose.ISO-8859-6.inc' +maybe chmod 0644 'console-setup/compose.ISO-8859-7.inc' +maybe chmod 0644 'console-setup/compose.ISO-8859-8.inc' +maybe chmod 0644 'console-setup/compose.ISO-8859-9.inc' +maybe chmod 0644 'console-setup/compose.KOI8-R.inc' +maybe chmod 0644 'console-setup/compose.KOI8-U.inc' +maybe chmod 0644 'console-setup/compose.TIS-620.inc' +maybe chmod 0644 'console-setup/compose.VISCII.inc' +maybe chmod 0644 'console-setup/remap.inc' +maybe chmod 0755 'containerd' +maybe chmod 0644 'containerd/config.toml' +maybe chmod 0755 'cron.d' +maybe chmod 0644 'cron.d/.placeholder' +maybe chmod 0644 'cron.d/php' +maybe chmod 0644 'cron.d/sysstat' +maybe chmod 0755 'cron.daily' +maybe chmod 0644 'cron.daily/.placeholder' +maybe chmod 0755 'cron.daily/apt-compat' +maybe chmod 0755 'cron.daily/bsdmainutils' +maybe chmod 0755 'cron.daily/dpkg' +maybe chmod 0755 'cron.daily/etckeeper' +maybe chmod 0755 'cron.daily/exim4-base' +maybe chmod 0700 'cron.daily/logrotate' +maybe chmod 0755 'cron.daily/man-db' +maybe chmod 0755 'cron.daily/ntp' +maybe chmod 0755 'cron.daily/passwd' +maybe chmod 0755 'cron.daily/sysstat' +maybe chmod 0755 'cron.hourly' +maybe chmod 0644 'cron.hourly/.placeholder' +maybe chmod 0755 'cron.hourly/fake-hwclock' +maybe chmod 0755 'cron.monthly' +maybe chmod 0644 'cron.monthly/.placeholder' +maybe chmod 0755 'cron.weekly' +maybe chmod 0644 'cron.weekly/.placeholder' +maybe chmod 0755 'cron.weekly/man-db' +maybe chmod 0644 'crontab' +maybe chmod 0755 'cruft' +maybe chmod 0755 'cruft/filters-unex' +maybe chmod 0644 'cruft/filters-unex/etckeeper' +maybe chmod 0755 'dbus-1' +maybe chmod 0755 'dbus-1/session.d' +maybe chmod 0755 'dbus-1/system.d' +maybe chmod 0644 'dbus-1/system.d/avahi-dbus.conf' +maybe chmod 0644 'dbus-1/system.d/bluetooth.conf' +maybe chmod 0644 'dbus-1/system.d/wpa_supplicant.conf' +maybe chmod 0644 'debconf.conf' +maybe chmod 0644 'debian_version' +maybe chmod 0755 'default' +maybe chmod 0644 'default/avahi-daemon' +maybe chmod 0644 'default/bluetooth' +maybe chmod 0644 'default/bsdmainutils' +maybe chmod 0600 'default/cacerts' +maybe chmod 0644 'default/console-setup' +maybe chmod 0644 'default/crda' +maybe chmod 0644 'default/cron' +maybe chmod 0644 'default/dbus' +maybe chmod 0644 'default/docker' +maybe chmod 0644 'default/exim4' +maybe chmod 0644 'default/fake-hwclock' +maybe chmod 0644 'default/hwclock' +maybe chmod 0644 'default/keyboard' +maybe chmod 0644 'default/locale' +maybe chmod 0644 'default/netfilter-persistent' +maybe chmod 0644 'default/networking' +maybe chmod 0644 'default/nfs-common' +maybe chmod 0644 'default/nginx' +maybe chmod 0644 'default/nss' +maybe chmod 0644 'default/ntp' +maybe chmod 0644 'default/raspberrypi-kernel' +maybe chmod 0644 'default/redis-server' +maybe chmod 0644 'default/rng-tools' +maybe chmod 0644 'default/rpi-eeprom-update' +maybe chmod 0644 'default/rsync' +maybe chmod 0644 'default/rsyslog' +maybe chmod 0644 'default/snmpd' +maybe chmod 0644 'default/ssh' +maybe chmod 0644 'default/sysstat' +maybe chmod 0644 'default/tftpd-hpa' +maybe chmod 0644 'default/triggerhappy' +maybe chmod 0644 'default/useradd' +maybe chmod 0644 'default/xinetd' +maybe chmod 0644 'deluser.conf' +maybe chmod 0755 'dhcp' +maybe chmod 0644 'dhcp/debug' +maybe chmod 0755 'dhcp/dhclient-enter-hooks.d' +maybe chmod 0644 'dhcp/dhclient-enter-hooks.d/resolvconf' +maybe chmod 0755 'dhcp/dhclient-exit-hooks.d' +maybe chmod 0644 'dhcp/dhclient-exit-hooks.d/ntp' +maybe chmod 0644 'dhcp/dhclient-exit-hooks.d/rfc3442-classless-routes' +maybe chmod 0644 'dhcp/dhclient-exit-hooks.d/timesyncd' +maybe chmod 0644 'dhcp/dhclient.conf' +maybe chgrp 'netdev' 'dhcpcd.conf' +maybe chmod 0664 'dhcpcd.conf' +maybe chmod 0755 'dkms' +maybe chmod 0644 'dkms/framework.conf' +maybe chmod 0755 'dkms/template-dkms-mkbmdeb' +maybe chmod 0644 'dkms/template-dkms-mkbmdeb/Makefile' +maybe chmod 0755 'dkms/template-dkms-mkbmdeb/debian' +maybe chmod 0644 'dkms/template-dkms-mkbmdeb/debian/README.Debian' +maybe chmod 0644 'dkms/template-dkms-mkbmdeb/debian/changelog' +maybe chmod 0644 'dkms/template-dkms-mkbmdeb/debian/compat' +maybe chmod 0644 'dkms/template-dkms-mkbmdeb/debian/control' +maybe chmod 0644 'dkms/template-dkms-mkbmdeb/debian/copyright' +maybe chmod 0755 'dkms/template-dkms-mkbmdeb/debian/rules' +maybe chmod 0755 'dkms/template-dkms-mkdeb' +maybe chmod 0644 'dkms/template-dkms-mkdeb/Makefile' +maybe chmod 0755 'dkms/template-dkms-mkdeb/debian' +maybe chmod 0644 'dkms/template-dkms-mkdeb/debian/README.Debian' +maybe chmod 0644 'dkms/template-dkms-mkdeb/debian/changelog' +maybe chmod 0644 'dkms/template-dkms-mkdeb/debian/compat' +maybe chmod 0644 'dkms/template-dkms-mkdeb/debian/control' +maybe chmod 0644 'dkms/template-dkms-mkdeb/debian/copyright' +maybe chmod 0644 'dkms/template-dkms-mkdeb/debian/dirs' +maybe chmod 0755 'dkms/template-dkms-mkdeb/debian/postinst' +maybe chmod 0755 'dkms/template-dkms-mkdeb/debian/prerm' +maybe chmod 0755 'dkms/template-dkms-mkdeb/debian/rules' +maybe chmod 0755 'dnsmasq.d' +maybe chmod 0755 'docker' +maybe chmod 0644 'docker/daemon.json' +maybe chmod 0600 'docker/key.json' +maybe chmod 0644 'dphys-swapfile' +maybe chmod 0755 'dpkg' +maybe chmod 0644 'dpkg/dpkg.cfg' +maybe chmod 0755 'dpkg/dpkg.cfg.d' +maybe chmod 0644 'dpkg/dpkg.cfg.d/pkg-config-hook-config' +maybe chmod 0755 'dpkg/origins' +maybe chmod 0644 'dpkg/origins/debian' +maybe chmod 0644 'dpkg/origins/raspbian' +maybe chmod 0644 'dpkg/shlibs.default' +maybe chmod 0644 'dpkg/shlibs.override' +maybe chmod 0644 'email-addresses' +maybe chmod 0644 'environment' +maybe chmod 0755 'etckeeper' +maybe chmod 0755 'etckeeper/commit.d' +maybe chmod 0755 'etckeeper/commit.d/10vcs-test' +maybe chmod 0755 'etckeeper/commit.d/30bzr-add' +maybe chmod 0755 'etckeeper/commit.d/30darcs-add' +maybe chmod 0755 'etckeeper/commit.d/30git-add' +maybe chmod 0755 'etckeeper/commit.d/30hg-addremove' +maybe chmod 0755 'etckeeper/commit.d/50vcs-commit' +maybe chmod 0755 'etckeeper/commit.d/99push' +maybe chmod 0644 'etckeeper/commit.d/README' +maybe chmod 0755 'etckeeper/daily' +maybe chmod 0644 'etckeeper/etckeeper.conf' +maybe chmod 0755 'etckeeper/init.d' +maybe chmod 0755 'etckeeper/init.d/10restore-metadata' +maybe chmod 0755 'etckeeper/init.d/20restore-etckeeper' +maybe chmod 0755 'etckeeper/init.d/40vcs-init' +maybe chmod 0755 'etckeeper/init.d/50vcs-ignore' +maybe chmod 0755 'etckeeper/init.d/50vcs-perm' +maybe chmod 0755 'etckeeper/init.d/50vcs-pre-commit-hook' +maybe chmod 0755 'etckeeper/init.d/60darcs-deleted-symlinks' +maybe chmod 0755 'etckeeper/init.d/70vcs-add' +maybe chmod 0644 'etckeeper/init.d/README' +maybe chmod 0755 'etckeeper/list-installed.d' +maybe chmod 0755 'etckeeper/list-installed.d/50list-installed' +maybe chmod 0755 'etckeeper/post-install.d' +maybe chmod 0755 'etckeeper/post-install.d/50vcs-commit' +maybe chmod 0644 'etckeeper/post-install.d/README' +maybe chmod 0755 'etckeeper/pre-commit.d' +maybe chmod 0755 'etckeeper/pre-commit.d/20warn-problem-files' +maybe chmod 0755 'etckeeper/pre-commit.d/30store-metadata' +maybe chmod 0644 'etckeeper/pre-commit.d/README' +maybe chmod 0755 'etckeeper/pre-install.d' +maybe chmod 0755 'etckeeper/pre-install.d/10packagelist' +maybe chmod 0755 'etckeeper/pre-install.d/50uncommitted-changes' +maybe chmod 0644 'etckeeper/pre-install.d/README' +maybe chmod 0755 'etckeeper/unclean.d' +maybe chmod 0755 'etckeeper/unclean.d/50test' +maybe chmod 0644 'etckeeper/unclean.d/README' +maybe chmod 0755 'etckeeper/uninit.d' +maybe chmod 0755 'etckeeper/uninit.d/01prompt' +maybe chmod 0755 'etckeeper/uninit.d/50remove-metadata' +maybe chmod 0755 'etckeeper/uninit.d/50vcs-uninit' +maybe chmod 0644 'etckeeper/uninit.d/README' +maybe chmod 0755 'etckeeper/update-ignore.d' +maybe chmod 0755 'etckeeper/update-ignore.d/01update-ignore' +maybe chmod 0644 'etckeeper/update-ignore.d/README' +maybe chmod 0755 'etckeeper/vcs.d' +maybe chmod 0755 'etckeeper/vcs.d/50vcs-cmd' +maybe chmod 0755 'exim4' +maybe chmod 0755 'exim4/conf.d' +maybe chmod 0755 'exim4/conf.d/acl' +maybe chmod 0644 'exim4/conf.d/acl/00_exim4-config_header' +maybe chmod 0644 'exim4/conf.d/acl/20_exim4-config_local_deny_exceptions' +maybe chmod 0644 'exim4/conf.d/acl/30_exim4-config_check_mail' +maybe chmod 0644 'exim4/conf.d/acl/30_exim4-config_check_rcpt' +maybe chmod 0644 'exim4/conf.d/acl/40_exim4-config_check_data' +maybe chmod 0755 'exim4/conf.d/auth' +maybe chmod 0644 'exim4/conf.d/auth/00_exim4-config_header' +maybe chmod 0644 'exim4/conf.d/auth/30_exim4-config_examples' +maybe chmod 0755 'exim4/conf.d/main' +maybe chmod 0644 'exim4/conf.d/main/01_exim4-config_listmacrosdefs' +maybe chmod 0644 'exim4/conf.d/main/02_exim4-config_options' +maybe chmod 0644 'exim4/conf.d/main/03_exim4-config_tlsoptions' +maybe chmod 0644 'exim4/conf.d/main/90_exim4-config_log_selector' +maybe chmod 0755 'exim4/conf.d/retry' +maybe chmod 0644 'exim4/conf.d/retry/00_exim4-config_header' +maybe chmod 0644 'exim4/conf.d/retry/30_exim4-config' +maybe chmod 0755 'exim4/conf.d/rewrite' +maybe chmod 0644 'exim4/conf.d/rewrite/00_exim4-config_header' +maybe chmod 0644 'exim4/conf.d/rewrite/31_exim4-config_rewriting' +maybe chmod 0755 'exim4/conf.d/router' +maybe chmod 0644 'exim4/conf.d/router/00_exim4-config_header' +maybe chmod 0644 'exim4/conf.d/router/100_exim4-config_domain_literal' +maybe chmod 0644 'exim4/conf.d/router/150_exim4-config_hubbed_hosts' +maybe chmod 0644 'exim4/conf.d/router/200_exim4-config_primary' +maybe chmod 0644 'exim4/conf.d/router/300_exim4-config_real_local' +maybe chmod 0644 'exim4/conf.d/router/400_exim4-config_system_aliases' +maybe chmod 0644 'exim4/conf.d/router/500_exim4-config_hubuser' +maybe chmod 0644 'exim4/conf.d/router/600_exim4-config_userforward' +maybe chmod 0644 'exim4/conf.d/router/700_exim4-config_procmail' +maybe chmod 0644 'exim4/conf.d/router/800_exim4-config_maildrop' +maybe chmod 0644 'exim4/conf.d/router/850_exim4-config_lowuid' +maybe chmod 0644 'exim4/conf.d/router/900_exim4-config_local_user' +maybe chmod 0644 'exim4/conf.d/router/mmm_mail4root' +maybe chmod 0755 'exim4/conf.d/transport' +maybe chmod 0644 'exim4/conf.d/transport/00_exim4-config_header' +maybe chmod 0644 'exim4/conf.d/transport/10_exim4-config_transport-macros' +maybe chmod 0644 'exim4/conf.d/transport/30_exim4-config_address_file' +maybe chmod 0644 'exim4/conf.d/transport/30_exim4-config_address_pipe' +maybe chmod 0644 'exim4/conf.d/transport/30_exim4-config_address_reply' +maybe chmod 0644 'exim4/conf.d/transport/30_exim4-config_mail_spool' +maybe chmod 0644 'exim4/conf.d/transport/30_exim4-config_maildir_home' +maybe chmod 0644 'exim4/conf.d/transport/30_exim4-config_maildrop_pipe' +maybe chmod 0644 'exim4/conf.d/transport/30_exim4-config_procmail_pipe' +maybe chmod 0644 'exim4/conf.d/transport/30_exim4-config_remote_smtp' +maybe chmod 0644 'exim4/conf.d/transport/30_exim4-config_remote_smtp_smarthost' +maybe chmod 0644 'exim4/conf.d/transport/35_exim4-config_address_directory' +maybe chmod 0644 'exim4/exim4.conf.template' +maybe chgrp 'Debian-exim' 'exim4/passwd.client' +maybe chmod 0640 'exim4/passwd.client' +maybe chmod 0644 'exim4/update-exim4.conf.conf' +maybe chmod 0644 'fb.modes' +maybe chmod 0755 'fonts' +maybe chmod 0755 'fonts/conf.avail' +maybe chmod 0644 'fonts/conf.avail/20-unhint-small-dejavu-lgc-sans-mono.conf' +maybe chmod 0644 'fonts/conf.avail/20-unhint-small-dejavu-lgc-sans.conf' +maybe chmod 0644 'fonts/conf.avail/20-unhint-small-dejavu-lgc-serif.conf' +maybe chmod 0644 'fonts/conf.avail/20-unhint-small-dejavu-sans-mono.conf' +maybe chmod 0644 'fonts/conf.avail/20-unhint-small-dejavu-sans.conf' +maybe chmod 0644 'fonts/conf.avail/20-unhint-small-dejavu-serif.conf' +maybe chmod 0644 'fonts/conf.avail/30-droid-noto-mono.conf' +maybe chmod 0644 'fonts/conf.avail/57-dejavu-sans-mono.conf' +maybe chmod 0644 'fonts/conf.avail/57-dejavu-sans.conf' +maybe chmod 0644 'fonts/conf.avail/57-dejavu-serif.conf' +maybe chmod 0644 'fonts/conf.avail/58-dejavu-lgc-sans-mono.conf' +maybe chmod 0644 'fonts/conf.avail/58-dejavu-lgc-sans.conf' +maybe chmod 0644 'fonts/conf.avail/58-dejavu-lgc-serif.conf' +maybe chmod 0644 'fonts/conf.avail/65-droid-sans-fallback.conf' +maybe chmod 0755 'fonts/conf.d' +maybe chmod 0644 'fonts/conf.d/README' +maybe chmod 0644 'fonts/fonts.conf' +maybe chmod 0644 'fstab' +maybe chmod 0644 'fuse.conf' +maybe chmod 0644 'gai.conf' +maybe chmod 0755 'gdb' +maybe chmod 0644 'gdb/gdbinit' +maybe chmod 0755 'ghostscript' +maybe chmod 0755 'ghostscript/cidfmap.d' +maybe chmod 0644 'ghostscript/cidfmap.d/90gs-cjk-resource-cns1.conf' +maybe chmod 0644 'ghostscript/cidfmap.d/90gs-cjk-resource-gb1.conf' +maybe chmod 0644 'ghostscript/cidfmap.d/90gs-cjk-resource-japan1.conf' +maybe chmod 0644 'ghostscript/cidfmap.d/90gs-cjk-resource-japan2.conf' +maybe chmod 0644 'ghostscript/cidfmap.d/90gs-cjk-resource-korea1.conf' +maybe chmod 0755 'ghostscript/fontmap.d' +maybe chmod 0644 'ghostscript/fontmap.d/10gsfonts.conf' +maybe chgrp 'git' 'gitea' +maybe chmod 0770 'gitea' +maybe chown 'git' 'gitea/app.ini' +maybe chgrp 'git' 'gitea/app.ini' +maybe chmod 0644 'gitea/app.ini' +maybe chmod 0755 'groff' +maybe chmod 0644 'groff/man.local' +maybe chmod 0644 'groff/mdoc.local' +maybe chmod 0644 'group' +maybe chmod 0644 'group-' +maybe chgrp 'shadow' 'gshadow' +maybe chmod 0640 'gshadow' +maybe chgrp 'shadow' 'gshadow-' +maybe chmod 0640 'gshadow-' +maybe chmod 0755 'gss' +maybe chmod 0755 'gss/mech.d' +maybe chmod 0644 'host.conf' +maybe chmod 0644 'hostname' +maybe chmod 0644 'hosts' +maybe chmod 0644 'hosts.allow' +maybe chmod 0644 'hosts.deny' +maybe chmod 0644 'idmapd.conf' +maybe chmod 0755 'ifplugd' +maybe chmod 0755 'ifplugd/action.d' +maybe chmod 0755 'init' +maybe chmod 0755 'init.d' +maybe chmod 0755 'init.d/alsa-utils' +maybe chmod 0755 'init.d/avahi-daemon' +maybe chmod 0755 'init.d/bluetooth' +maybe chmod 0755 'init.d/console-setup.sh' +maybe chmod 0755 'init.d/cron' +maybe chmod 0755 'init.d/dbus' +maybe chmod 0755 'init.d/dhcpcd' +maybe chmod 0755 'init.d/docker' +maybe chmod 0755 'init.d/dphys-swapfile' +maybe chmod 0755 'init.d/exim4' +maybe chmod 0755 'init.d/fake-hwclock' +maybe chmod 0755 'init.d/hwclock.sh' +maybe chmod 0755 'init.d/keyboard-setup.sh' +maybe chmod 0755 'init.d/kmod' +maybe chmod 0755 'init.d/mosquitto' +maybe chmod 0755 'init.d/netfilter-persistent' +maybe chmod 0755 'init.d/networking' +maybe chmod 0755 'init.d/nfs-common' +maybe chmod 0755 'init.d/nginx' +maybe chmod 0755 'init.d/ntp' +maybe chmod 0755 'init.d/paxctld' +maybe chmod 0755 'init.d/php7.3-fpm' +maybe chmod 0755 'init.d/postgresql' +maybe chmod 0755 'init.d/procps' +maybe chmod 0755 'init.d/raspi-config' +maybe chmod 0755 'init.d/redis-server' +maybe chmod 0755 'init.d/resolvconf' +maybe chmod 0755 'init.d/rng-tools' +maybe chmod 0755 'init.d/rpcbind' +maybe chmod 0755 'init.d/rsync' +maybe chmod 0755 'init.d/rsyslog' +maybe chmod 0755 'init.d/snmpd' +maybe chmod 0755 'init.d/ssh' +maybe chmod 0755 'init.d/sudo' +maybe chmod 0755 'init.d/sysstat' +maybe chmod 0755 'init.d/tftpd-hpa' +maybe chmod 0755 'init.d/triggerhappy' +maybe chmod 0755 'init.d/udev' +maybe chmod 0755 'init.d/x11-common' +maybe chmod 0755 'init.d/xinetd' +maybe chmod 0644 'init/docker.conf' +maybe chmod 0644 'init/paxctld.conf' +maybe chmod 0644 'init/php7.3-fpm.conf' +maybe chmod 0644 'init/resolvconf.conf' +maybe chmod 0644 'init/tftpd-hpa.conf' +maybe chmod 0755 'initramfs-tools' +maybe chmod 0755 'initramfs-tools/conf.d' +maybe chmod 0755 'initramfs-tools/hooks' +maybe chmod 0644 'initramfs-tools/initramfs.conf' +maybe chmod 0644 'initramfs-tools/modules' +maybe chmod 0755 'initramfs-tools/scripts' +maybe chmod 0755 'initramfs-tools/scripts/init-bottom' +maybe chmod 0755 'initramfs-tools/scripts/init-premount' +maybe chmod 0755 'initramfs-tools/scripts/init-top' +maybe chmod 0755 'initramfs-tools/scripts/local-bottom' +maybe chmod 0755 'initramfs-tools/scripts/local-premount' +maybe chmod 0755 'initramfs-tools/scripts/local-top' +maybe chmod 0755 'initramfs-tools/scripts/nfs-bottom' +maybe chmod 0755 'initramfs-tools/scripts/nfs-premount' +maybe chmod 0755 'initramfs-tools/scripts/nfs-top' +maybe chmod 0755 'initramfs-tools/scripts/panic' +maybe chmod 0644 'initramfs-tools/update-initramfs.conf' +maybe chmod 0644 'inputrc' +maybe chmod 0755 'insserv.conf.d' +maybe chmod 0644 'insserv.conf.d/rpcbind' +maybe chmod 0755 'iproute2' +maybe chmod 0644 'iproute2/bpf_pinning' +maybe chmod 0644 'iproute2/ematch_map' +maybe chmod 0644 'iproute2/group' +maybe chmod 0644 'iproute2/nl_protos' +maybe chmod 0644 'iproute2/rt_dsfield' +maybe chmod 0644 'iproute2/rt_protos' +maybe chmod 0755 'iproute2/rt_protos.d' +maybe chmod 0644 'iproute2/rt_protos.d/README' +maybe chmod 0644 'iproute2/rt_realms' +maybe chmod 0644 'iproute2/rt_scopes' +maybe chmod 0644 'iproute2/rt_tables' +maybe chmod 0755 'iproute2/rt_tables.d' +maybe chmod 0644 'iproute2/rt_tables.d/README' +maybe chmod 0644 'issue' +maybe chmod 0644 'issue.net' +maybe chmod 0755 'java-11-openjdk' +maybe chmod 0644 'java-11-openjdk/accessibility.properties' +maybe chmod 0755 'java-11-openjdk/jfr' +maybe chmod 0644 'java-11-openjdk/jfr/default.jfc' +maybe chmod 0644 'java-11-openjdk/jfr/profile.jfc' +maybe chmod 0644 'java-11-openjdk/jvm-armhf.cfg' +maybe chmod 0644 'java-11-openjdk/logging.properties' +maybe chmod 0755 'java-11-openjdk/management' +maybe chmod 0644 'java-11-openjdk/management/jmxremote.access' +maybe chmod 0644 'java-11-openjdk/management/management.properties' +maybe chmod 0644 'java-11-openjdk/net.properties' +maybe chmod 0644 'java-11-openjdk/psfont.properties.ja' +maybe chmod 0644 'java-11-openjdk/psfontj2d.properties' +maybe chmod 0755 'java-11-openjdk/security' +maybe chmod 0644 'java-11-openjdk/security/blacklisted.certs' +maybe chmod 0644 'java-11-openjdk/security/default.policy' +maybe chmod 0644 'java-11-openjdk/security/java.policy' +maybe chmod 0644 'java-11-openjdk/security/java.security' +maybe chmod 0644 'java-11-openjdk/security/nss.cfg' +maybe chmod 0755 'java-11-openjdk/security/policy' +maybe chmod 0644 'java-11-openjdk/security/policy/README.txt' +maybe chmod 0755 'java-11-openjdk/security/policy/limited' +maybe chmod 0644 'java-11-openjdk/security/policy/limited/default_US_export.policy' +maybe chmod 0644 'java-11-openjdk/security/policy/limited/default_local.policy' +maybe chmod 0644 'java-11-openjdk/security/policy/limited/exempt_local.policy' +maybe chmod 0755 'java-11-openjdk/security/policy/unlimited' +maybe chmod 0644 'java-11-openjdk/security/policy/unlimited/default_US_export.policy' +maybe chmod 0644 'java-11-openjdk/security/policy/unlimited/default_local.policy' +maybe chmod 0644 'java-11-openjdk/security/public_suffix_list.dat' +maybe chmod 0644 'java-11-openjdk/sound.properties' +maybe chmod 0644 'java-11-openjdk/swing.properties' +maybe chmod 0755 'kernel' +maybe chmod 0755 'kernel/header_postinst.d' +maybe chmod 0755 'kernel/header_postinst.d/dkms' +maybe chmod 0755 'kernel/install.d' +maybe chmod 0755 'kernel/postinst.d' +maybe chmod 0755 'kernel/postinst.d/apt-auto-removal' +maybe chmod 0755 'kernel/postinst.d/dkms' +maybe chmod 0755 'kernel/postinst.d/initramfs-tools' +maybe chmod 0755 'kernel/postrm.d' +maybe chmod 0755 'kernel/postrm.d/initramfs-tools' +maybe chmod 0755 'kernel/prerm.d' +maybe chmod 0755 'kernel/prerm.d/dkms' +maybe chmod 0644 'ld.so.conf' +maybe chmod 0755 'ld.so.conf.d' +maybe chmod 0644 'ld.so.conf.d/00-vmcs.conf' +maybe chmod 0644 'ld.so.conf.d/arm-linux-gnueabihf.conf' +maybe chmod 0644 'ld.so.conf.d/fakeroot-arm-linux-gnueabihf.conf' +maybe chmod 0644 'ld.so.conf.d/libc.conf' +maybe chmod 0644 'ld.so.preload' +maybe chmod 0755 'ldap' +maybe chmod 0644 'ldap/ldap.conf' +maybe chmod 0755 'letsencrypt' +maybe chmod 0644 'letsencrypt/account.conf' +maybe chmod 0755 'letsencrypt/acme.sh' +maybe chmod 0644 'letsencrypt/acme.sh.env' +maybe chmod 0755 'letsencrypt/ca' +maybe chmod 0755 'letsencrypt/ca/acme-v02.api.letsencrypt.org' +maybe chmod 0644 'letsencrypt/ca/acme-v02.api.letsencrypt.org/account.json' +maybe chmod 0600 'letsencrypt/ca/acme-v02.api.letsencrypt.org/account.key' +maybe chmod 0644 'letsencrypt/ca/acme-v02.api.letsencrypt.org/ca.conf' +maybe chmod 0755 'letsencrypt/deploy' +maybe chmod 0644 'letsencrypt/deploy/README.md' +maybe chmod 0644 'letsencrypt/deploy/apache.sh' +maybe chmod 0644 'letsencrypt/deploy/cleverreach.sh' +maybe chmod 0644 'letsencrypt/deploy/cpanel_uapi.sh' +maybe chmod 0755 'letsencrypt/deploy/docker.sh' +maybe chmod 0644 'letsencrypt/deploy/dovecot.sh' +maybe chmod 0644 'letsencrypt/deploy/exim4.sh' +maybe chmod 0644 'letsencrypt/deploy/fritzbox.sh' +maybe chmod 0644 'letsencrypt/deploy/gcore_cdn.sh' +maybe chmod 0644 'letsencrypt/deploy/gitlab.sh' +maybe chmod 0644 'letsencrypt/deploy/haproxy.sh' +maybe chmod 0644 'letsencrypt/deploy/keychain.sh' +maybe chmod 0755 'letsencrypt/deploy/kong.sh' +maybe chmod 0644 'letsencrypt/deploy/mailcow.sh' +maybe chmod 0755 'letsencrypt/deploy/myapi.sh' +maybe chmod 0755 'letsencrypt/deploy/mydevil.sh' +maybe chmod 0644 'letsencrypt/deploy/mysqld.sh' +maybe chmod 0644 'letsencrypt/deploy/nginx.sh' +maybe chmod 0644 'letsencrypt/deploy/opensshd.sh' +maybe chmod 0644 'letsencrypt/deploy/openstack.sh' +maybe chmod 0644 'letsencrypt/deploy/panos.sh' +maybe chmod 0644 'letsencrypt/deploy/pureftpd.sh' +maybe chmod 0644 'letsencrypt/deploy/qiniu.sh' +maybe chmod 0644 'letsencrypt/deploy/routeros.sh' +maybe chmod 0644 'letsencrypt/deploy/ssh.sh' +maybe chmod 0644 'letsencrypt/deploy/strongswan.sh' +maybe chmod 0644 'letsencrypt/deploy/synology_dsm.sh' +maybe chmod 0644 'letsencrypt/deploy/unifi.sh' +maybe chmod 0644 'letsencrypt/deploy/vault.sh' +maybe chmod 0644 'letsencrypt/deploy/vault_cli.sh' +maybe chmod 0644 'letsencrypt/deploy/vsftpd.sh' +maybe chmod 0755 'letsencrypt/dnsapi' +maybe chmod 0644 'letsencrypt/dnsapi/README.md' +maybe chmod 0755 'letsencrypt/dnsapi/dns_1984hosting.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_acmedns.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_acmeproxy.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_active24.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_ad.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_ali.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_anx.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_arvan.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_autodns.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_aws.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_azure.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_cf.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_clouddns.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_cloudns.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_cn.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_conoha.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_constellix.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_cx.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_cyon.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_da.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_ddnss.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_desec.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_df.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_dgon.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_dnsimple.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_do.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_doapi.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_domeneshop.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_dp.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_dpi.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_dreamhost.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_duckdns.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_durabledns.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_dyn.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_dynu.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_dynv6.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_easydns.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_edgedns.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_euserv.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_exoscale.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_freedns.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_gandi_livedns.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_gcloud.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_gd.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_gdnsdk.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_he.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_hetzner.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_hexonet.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_hostingde.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_huaweicloud.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_infoblox.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_infomaniak.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_internetbs.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_inwx.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_ispconfig.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_jd.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_joker.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_kappernet.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_kas.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_kinghost.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_knot.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_leaseweb.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_lexicon.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_linode.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_linode_v4.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_loopia.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_lua.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_maradns.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_me.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_miab.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_misaka.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_myapi.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_mydevil.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_mydnsjp.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_namecheap.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_namecom.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_namesilo.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_nederhost.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_neodigit.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_netcup.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_netlify.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_nic.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_njalla.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_nm.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_nsd.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_nsone.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_nsupdate.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_nw.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_one.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_online.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_openprovider.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_openstack.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_opnsense.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_ovh.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_pdns.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_pleskxml.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_pointhq.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_rackspace.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_rcode0.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_regru.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_schlundtech.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_selectel.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_servercow.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_tele3.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_transip.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_ultra.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_unoeuro.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_variomedia.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_vscale.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_vultr.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_world4you.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_yandex.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_zilore.sh' +maybe chmod 0755 'letsencrypt/dnsapi/dns_zone.sh' +maybe chmod 0644 'letsencrypt/dnsapi/dns_zonomi.sh' +maybe chmod 0755 'letsencrypt/ghost.realm.local' +maybe chmod 0644 'letsencrypt/ghost.realm.local/ghost.realm.local.conf' +maybe chmod 0644 'letsencrypt/ghost.realm.local/ghost.realm.local.csr' +maybe chmod 0644 'letsencrypt/ghost.realm.local/ghost.realm.local.csr.conf' +maybe chmod 0644 'letsencrypt/ghost.realm.local/ghost.realm.local.key' +maybe chmod 0644 'letsencrypt/http.header' +maybe chmod 0755 'letsencrypt/notify' +maybe chmod 0644 'letsencrypt/notify/cqhttp.sh' +maybe chmod 0644 'letsencrypt/notify/dingtalk.sh' +maybe chmod 0644 'letsencrypt/notify/ifttt.sh' +maybe chmod 0644 'letsencrypt/notify/mail.sh' +maybe chmod 0644 'letsencrypt/notify/mailgun.sh' +maybe chmod 0644 'letsencrypt/notify/pop.sh' +maybe chmod 0644 'letsencrypt/notify/postmark.sh' +maybe chmod 0644 'letsencrypt/notify/pushover.sh' +maybe chmod 0644 'letsencrypt/notify/sendgrid.sh' +maybe chmod 0644 'letsencrypt/notify/slack.sh' +maybe chmod 0644 'letsencrypt/notify/smtp.sh' +maybe chmod 0644 'letsencrypt/notify/teams.sh' +maybe chmod 0644 'letsencrypt/notify/xmpp.sh' +maybe chmod 0644 'libaudit.conf' +maybe chmod 0755 'libnl-3' +maybe chmod 0644 'libnl-3/classid' +maybe chmod 0644 'libnl-3/pktloc' +maybe chmod 0755 'libpaper.d' +maybe chmod 0755 'lighttpd' +maybe chmod 0644 'lighttpd/external.conf' +maybe chmod 0644 'lighttpd/lighttpd.conf.orig' +maybe chmod 0644 'locale.alias' +maybe chmod 0644 'locale.gen' +maybe chmod 0755 'logcheck' +maybe chmod 0755 'logcheck/ignore.d.server' +maybe chmod 0644 'logcheck/ignore.d.server/gpg-agent' +maybe chmod 0644 'logcheck/ignore.d.server/rng-tools' +maybe chmod 0644 'logcheck/ignore.d.server/rsyslog' +maybe chmod 0755 'logcheck/violations.ignore.d' +maybe chmod 0644 'logcheck/violations.ignore.d/rng-tools' +maybe chmod 0644 'login.defs' +maybe chmod 0644 'logrotate.conf' +maybe chmod 0755 'logrotate.d' +maybe chmod 0644 'logrotate.d/apt' +maybe chmod 0644 'logrotate.d/btmp' +maybe chmod 0644 'logrotate.d/dpkg' +maybe chmod 0644 'logrotate.d/exim4-base' +maybe chmod 0644 'logrotate.d/exim4-paniclog' +maybe chmod 0644 'logrotate.d/mosquitto' +maybe chmod 0644 'logrotate.d/nginx' +maybe chmod 0644 'logrotate.d/nodered' +maybe chmod 0644 'logrotate.d/php7.3-fpm' +maybe chmod 0644 'logrotate.d/postgresql-common' +maybe chmod 0644 'logrotate.d/rsyslog' +maybe chmod 0644 'logrotate.d/syslog' +maybe chmod 0644 'logrotate.d/wtmp' +maybe chmod 0444 'machine-id' +maybe chmod 0644 'magic' +maybe chmod 0644 'magic.mime' +maybe chmod 0644 'mailcap' +maybe chmod 0644 'mailcap.order' +maybe chmod 0644 'mailname' +maybe chmod 0644 'manpath.config' +maybe chmod 0644 'mime.types' +maybe chmod 0644 'mke2fs.conf' +maybe chmod 0755 'modprobe.d' +maybe chmod 0644 'modprobe.d/blacklist-8192cu.conf' +maybe chmod 0644 'modprobe.d/blacklist-rtl8xxxu.conf' +maybe chmod 0644 'modprobe.d/dkms.conf' +maybe chmod 0644 'modules' +maybe chmod 0755 'modules-load.d' +maybe chmod 0755 'mosquitto' +maybe chmod 0755 'mosquitto/ca_certificates' +maybe chmod 0644 'mosquitto/ca_certificates/README' +maybe chmod 0755 'mosquitto/certs' +maybe chmod 0644 'mosquitto/certs/README' +maybe chmod 0755 'mosquitto/conf.d' +maybe chmod 0644 'mosquitto/conf.d/README' +maybe chmod 0644 'mosquitto/mosquitto.conf' +maybe chmod 0755 'mysql' +maybe chmod 0755 'mysql/conf.d' +maybe chmod 0644 'mysql/conf.d/mysql.cnf' +maybe chmod 0644 'mysql/conf.d/mysqldump.cnf' +maybe chmod 0644 'mysql/mariadb.cnf' +maybe chmod 0755 'mysql/mariadb.conf.d' +maybe chmod 0644 'mysql/my.cnf.fallback' +maybe chmod 0644 'nanorc' +maybe chmod 0755 'neofetch' +maybe chmod 0644 'neofetch/neofetch.config' +maybe chmod 0644 'netconfig' +maybe chmod 0755 'network' +maybe chmod 0755 'network/if-down.d' +maybe chmod 0755 'network/if-down.d/resolvconf' +maybe chmod 0755 'network/if-post-down.d' +maybe chmod 0755 'network/if-post-down.d/wireless-tools' +maybe chmod 0755 'network/if-pre-up.d' +maybe chmod 0755 'network/if-pre-up.d/ethtool' +maybe chmod 0755 'network/if-pre-up.d/wireless-tools' +maybe chmod 0755 'network/if-up.d' +maybe chmod 0755 'network/if-up.d/000resolvconf' +maybe chmod 0755 'network/if-up.d/ethtool' +maybe chmod 0644 'network/interfaces' +maybe chmod 0755 'network/interfaces.d' +maybe chmod 0644 'networks' +maybe chmod 0755 'nginx' +maybe chmod 0644 'nginx/.htpasswd' +maybe chmod 0755 'nginx/conf.d' +maybe chmod 0755 'nginx/conf.mail.d' +maybe chmod 0755 'nginx/conf.stream.d' +maybe chmod 0644 'nginx/fastcgi.conf' +maybe chmod 0644 'nginx/fastcgi_params' +maybe chmod 0644 'nginx/koi-utf' +maybe chmod 0644 'nginx/koi-win' +maybe chmod 0644 'nginx/mime.types' +maybe chmod 0755 'nginx/modules-available' +maybe chmod 0755 'nginx/modules-enabled' +maybe chmod 0644 'nginx/nginx.conf' +maybe chmod 0644 'nginx/proxy_params' +maybe chmod 0644 'nginx/scgi_params' +maybe chmod 0755 'nginx/sites-available' +maybe chmod 0644 'nginx/sites-available/adguard.realm.local.conf' +maybe chmod 0644 'nginx/sites-available/checkmk.realm.local.conf' +maybe chmod 0644 'nginx/sites-available/default' +maybe chmod 0644 'nginx/sites-available/gitea.realm.local.conf' +maybe chmod 0644 'nginx/sites-available/grafana.realm.local.conf' +maybe chmod 0644 'nginx/sites-available/influxdb.realm.local.conf' +maybe chmod 0644 'nginx/sites-available/openhab.realm.local.conf' +maybe chmod 0644 'nginx/sites-available/photoprism.realm.local.conf' +maybe chmod 0644 'nginx/sites-available/portainer.realm.local.conf' +maybe chmod 0755 'nginx/sites-enabled' +maybe chmod 0755 'nginx/snippets' +maybe chmod 0644 'nginx/snippets/fastcgi-php.conf' +maybe chmod 0644 'nginx/snippets/snakeoil.conf' +maybe chmod 0755 'nginx/ssl' +maybe chmod 0755 'nginx/ssl/certs' +maybe chmod 0700 'nginx/ssl/certs/adguard.realm.local' +maybe chmod 0600 'nginx/ssl/certs/adguard.realm.local/cert.pem' +maybe chmod 0600 'nginx/ssl/certs/adguard.realm.local/key.pem' +maybe chmod 0700 'nginx/ssl/certs/checkmk.realm.local' +maybe chmod 0600 'nginx/ssl/certs/checkmk.realm.local/cert.pem' +maybe chmod 0600 'nginx/ssl/certs/checkmk.realm.local/key.pem' +maybe chmod 0700 'nginx/ssl/certs/gitea.realm.local' +maybe chmod 0600 'nginx/ssl/certs/gitea.realm.local/cert.pem' +maybe chmod 0600 'nginx/ssl/certs/gitea.realm.local/key.pem' +maybe chmod 0700 'nginx/ssl/certs/grafana.realm.local' +maybe chmod 0600 'nginx/ssl/certs/grafana.realm.local/cert.pem' +maybe chmod 0600 'nginx/ssl/certs/grafana.realm.local/key.pem' +maybe chmod 0700 'nginx/ssl/certs/influxdb.realm.local' +maybe chmod 0600 'nginx/ssl/certs/influxdb.realm.local/cert.pem' +maybe chmod 0600 'nginx/ssl/certs/influxdb.realm.local/key.pem' +maybe chmod 0700 'nginx/ssl/certs/openhab.realm.local' +maybe chmod 0600 'nginx/ssl/certs/openhab.realm.local/cert.pem' +maybe chmod 0600 'nginx/ssl/certs/openhab.realm.local/key.pem' +maybe chmod 0700 'nginx/ssl/certs/photoprism.realm.local' +maybe chmod 0600 'nginx/ssl/certs/photoprism.realm.local/cert.pem' +maybe chmod 0600 'nginx/ssl/certs/photoprism.realm.local/key.pem' +maybe chmod 0700 'nginx/ssl/certs/portainer.realm.local' +maybe chmod 0600 'nginx/ssl/certs/portainer.realm.local/cert.pem' +maybe chmod 0600 'nginx/ssl/certs/portainer.realm.local/key.pem' +maybe chmod 0700 'nginx/ssl/certs/realm.local' +maybe chmod 0600 'nginx/ssl/certs/realm.local/cert.pem' +maybe chmod 0600 'nginx/ssl/certs/realm.local/key.pem' +maybe chmod 0755 'nginx/streams-available' +maybe chmod 0755 'nginx/streams-enabled' +maybe chmod 0644 'nginx/uwsgi_params' +maybe chmod 0644 'nginx/win-utf' +maybe chmod 0644 'nsswitch.conf' +maybe chmod 0644 'ntp.conf' +maybe chmod 0755 'opt' +maybe chmod 0644 'pam.conf' +maybe chmod 0755 'pam.d' +maybe chmod 0644 'pam.d/chfn' +maybe chmod 0644 'pam.d/chpasswd' +maybe chmod 0644 'pam.d/chsh' +maybe chmod 0644 'pam.d/common-account' +maybe chmod 0644 'pam.d/common-auth' +maybe chmod 0644 'pam.d/common-password' +maybe chmod 0644 'pam.d/common-session' +maybe chmod 0644 'pam.d/common-session-noninteractive' +maybe chmod 0644 'pam.d/cron' +maybe chmod 0644 'pam.d/login' +maybe chmod 0644 'pam.d/newusers' +maybe chmod 0644 'pam.d/other' +maybe chmod 0644 'pam.d/passwd' +maybe chmod 0644 'pam.d/polkit-1' +maybe chmod 0644 'pam.d/runuser' +maybe chmod 0644 'pam.d/runuser-l' +maybe chmod 0644 'pam.d/sshd' +maybe chmod 0644 'pam.d/su' +maybe chmod 0644 'pam.d/su-l' +maybe chmod 0644 'pam.d/sudo' +maybe chmod 0644 'pam.d/systemd-user' +maybe chmod 0644 'papersize' +maybe chmod 0644 'passwd' +maybe chmod 0644 'passwd-' +maybe chmod 0644 'paxctld.conf' +maybe chmod 0755 'perl' +maybe chmod 0755 'perl/CPAN' +maybe chmod 0755 'perl/Net' +maybe chmod 0644 'perl/Net/libnet.cfg' +maybe chmod 0755 'php' +maybe chmod 0755 'php/7.3' +maybe chmod 0755 'php/7.3/cgi' +maybe chmod 0755 'php/7.3/cgi/conf.d' +maybe chmod 0644 'php/7.3/cgi/php.ini' +maybe chmod 0755 'php/7.3/cli' +maybe chmod 0755 'php/7.3/cli/conf.d' +maybe chmod 0644 'php/7.3/cli/php.ini' +maybe chmod 0755 'php/7.3/fpm' +maybe chmod 0755 'php/7.3/fpm/conf.d' +maybe chmod 0644 'php/7.3/fpm/php-fpm.conf' +maybe chmod 0644 'php/7.3/fpm/php.ini' +maybe chmod 0755 'php/7.3/fpm/pool.d' +maybe chmod 0644 'php/7.3/fpm/pool.d/www.conf' +maybe chmod 0755 'php/7.3/mods-available' +maybe chmod 0644 'php/7.3/mods-available/calendar.ini' +maybe chmod 0644 'php/7.3/mods-available/ctype.ini' +maybe chmod 0644 'php/7.3/mods-available/dom.ini' +maybe chmod 0644 'php/7.3/mods-available/exif.ini' +maybe chmod 0644 'php/7.3/mods-available/fileinfo.ini' +maybe chmod 0644 'php/7.3/mods-available/ftp.ini' +maybe chmod 0644 'php/7.3/mods-available/gettext.ini' +maybe chmod 0644 'php/7.3/mods-available/iconv.ini' +maybe chmod 0644 'php/7.3/mods-available/intl.ini' +maybe chmod 0644 'php/7.3/mods-available/json.ini' +maybe chmod 0644 'php/7.3/mods-available/mysqli.ini' +maybe chmod 0644 'php/7.3/mods-available/mysqlnd.ini' +maybe chmod 0644 'php/7.3/mods-available/opcache.ini' +maybe chmod 0644 'php/7.3/mods-available/pdo.ini' +maybe chmod 0644 'php/7.3/mods-available/pdo_mysql.ini' +maybe chmod 0644 'php/7.3/mods-available/pdo_sqlite.ini' +maybe chmod 0644 'php/7.3/mods-available/phar.ini' +maybe chmod 0644 'php/7.3/mods-available/posix.ini' +maybe chmod 0644 'php/7.3/mods-available/readline.ini' +maybe chmod 0644 'php/7.3/mods-available/shmop.ini' +maybe chmod 0644 'php/7.3/mods-available/simplexml.ini' +maybe chmod 0644 'php/7.3/mods-available/sockets.ini' +maybe chmod 0644 'php/7.3/mods-available/sqlite3.ini' +maybe chmod 0644 'php/7.3/mods-available/sysvmsg.ini' +maybe chmod 0644 'php/7.3/mods-available/sysvsem.ini' +maybe chmod 0644 'php/7.3/mods-available/sysvshm.ini' +maybe chmod 0644 'php/7.3/mods-available/tokenizer.ini' +maybe chmod 0644 'php/7.3/mods-available/wddx.ini' +maybe chmod 0644 'php/7.3/mods-available/xml.ini' +maybe chmod 0644 'php/7.3/mods-available/xmlreader.ini' +maybe chmod 0644 'php/7.3/mods-available/xmlwriter.ini' +maybe chmod 0644 'php/7.3/mods-available/xsl.ini' +maybe chmod 0644 'pip.conf' +maybe chmod 0755 'polkit-1' +maybe chmod 0700 'polkit-1/localauthority' +maybe chmod 0755 'polkit-1/localauthority.conf.d' +maybe chmod 0644 'polkit-1/localauthority.conf.d/50-localauthority.conf' +maybe chmod 0644 'polkit-1/localauthority.conf.d/51-debian-sudo.conf' +maybe chmod 0755 'polkit-1/localauthority/10-vendor.d' +maybe chmod 0755 'polkit-1/localauthority/20-org.d' +maybe chmod 0755 'polkit-1/localauthority/30-site.d' +maybe chmod 0755 'polkit-1/localauthority/50-local.d' +maybe chmod 0755 'polkit-1/localauthority/90-mandatory.d' +maybe chmod 0755 'polkit-1/nullbackend.conf.d' +maybe chmod 0644 'polkit-1/nullbackend.conf.d/50-nullbackend.conf' +maybe chown 'postgres' 'postgresql' +maybe chgrp 'postgres' 'postgresql' +maybe chmod 0755 'postgresql' +maybe chmod 0755 'postgresql-common' +maybe chmod 0644 'postgresql-common/createcluster.conf' +maybe chmod 0755 'postgresql-common/pg_upgradecluster.d' +maybe chmod 0644 'postgresql-common/root.crt' +maybe chmod 0644 'postgresql-common/supported_versions' +maybe chmod 0644 'postgresql-common/user_clusters' +maybe chown 'postgres' 'postgresql/11' +maybe chgrp 'postgres' 'postgresql/11' +maybe chmod 0755 'postgresql/11' +maybe chown 'postgres' 'postgresql/11/main' +maybe chgrp 'postgres' 'postgresql/11/main' +maybe chmod 0755 'postgresql/11/main' +maybe chown 'postgres' 'postgresql/11/main/conf.d' +maybe chgrp 'postgres' 'postgresql/11/main/conf.d' +maybe chmod 0755 'postgresql/11/main/conf.d' +maybe chown 'postgres' 'postgresql/11/main/environment' +maybe chgrp 'postgres' 'postgresql/11/main/environment' +maybe chmod 0644 'postgresql/11/main/environment' +maybe chown 'postgres' 'postgresql/11/main/pg_ctl.conf' +maybe chgrp 'postgres' 'postgresql/11/main/pg_ctl.conf' +maybe chmod 0644 'postgresql/11/main/pg_ctl.conf' +maybe chown 'postgres' 'postgresql/11/main/pg_hba.conf' +maybe chgrp 'postgres' 'postgresql/11/main/pg_hba.conf' +maybe chmod 0640 'postgresql/11/main/pg_hba.conf' +maybe chown 'postgres' 'postgresql/11/main/pg_ident.conf' +maybe chgrp 'postgres' 'postgresql/11/main/pg_ident.conf' +maybe chmod 0640 'postgresql/11/main/pg_ident.conf' +maybe chown 'postgres' 'postgresql/11/main/postgresql.conf' +maybe chgrp 'postgres' 'postgresql/11/main/postgresql.conf' +maybe chmod 0644 'postgresql/11/main/postgresql.conf' +maybe chown 'postgres' 'postgresql/11/main/start.conf' +maybe chgrp 'postgres' 'postgresql/11/main/start.conf' +maybe chmod 0644 'postgresql/11/main/start.conf' +maybe chmod 0755 'ppp' +maybe chmod 0755 'ppp/ip-down.d' +maybe chmod 0755 'ppp/ip-down.d/000resolvconf' +maybe chmod 0755 'ppp/ip-up.d' +maybe chmod 0755 'ppp/ip-up.d/000resolvconf' +maybe chmod 0755 'ppp/ip-up.d/exim4' +maybe chmod 0770 'prelink.conf.d' +maybe chmod 0644 'prelink.conf.d/cmk-update-agent.conf' +maybe chmod 0644 'profile' +maybe chmod 0755 'profile.d' +maybe chmod 0644 'profile.d/at-dbus-fix.sh' +maybe chmod 0644 'profile.d/bash_completion.sh' +maybe chmod 0644 'profile.d/sshpwd.sh' +maybe chmod 0644 'profile.d/wifi-check.sh' +maybe chmod 0644 'protocols' +maybe chmod 0755 'python' +maybe chmod 0644 'python/debian_config' +maybe chmod 0755 'python2.7' +maybe chmod 0644 'python2.7/sitecustomize.py' +maybe chmod 0755 'python3' +maybe chmod 0755 'python3.7' +maybe chmod 0644 'python3.7/sitecustomize.py' +maybe chmod 0644 'python3/debian_config' +maybe chmod 0755 'rc.local' +maybe chmod 0755 'rc0.d' +maybe chmod 0755 'rc1.d' +maybe chmod 0755 'rc2.d' +maybe chmod 0755 'rc3.d' +maybe chmod 0755 'rc4.d' +maybe chmod 0755 'rc5.d' +maybe chmod 0755 'rc6.d' +maybe chmod 0755 'rcS.d' +maybe chmod 0755 'redis' +maybe chown 'redis' 'redis/redis.conf' +maybe chgrp 'redis' 'redis/redis.conf' +maybe chmod 0640 'redis/redis.conf' +maybe chmod 0644 'request-key.conf' +maybe chmod 0755 'request-key.d' +maybe chmod 0644 'request-key.d/cifs.idmap.conf' +maybe chmod 0644 'request-key.d/cifs.spnego.conf' +maybe chmod 0644 'request-key.d/id_resolver.conf' +maybe chmod 0644 'resolv.conf.bak' +maybe chmod 0755 'resolvconf' +maybe chmod 0644 'resolvconf.conf' +maybe chmod 0644 'resolvconf/interface-order' +maybe chmod 0755 'resolvconf/resolv.conf.d' +maybe chmod 0644 'resolvconf/resolv.conf.d/base' +maybe chmod 0644 'resolvconf/resolv.conf.d/head' +maybe chmod 0644 'resolvconf/resolv.conf.d/original' +maybe chmod 0644 'resolvconf/resolv.conf.d/tail' +maybe chmod 0755 'resolvconf/update-libc.d' +maybe chmod 0755 'resolvconf/update.d' +maybe chmod 0755 'resolvconf/update.d/libc' +maybe chmod 0644 'rpc' +maybe chmod 0644 'rpi-issue' +maybe chmod 0755 'rsyslog-keys' +maybe chmod 0644 'rsyslog-keys/ca.pem' +maybe chmod 0644 'rsyslog.conf' +maybe chmod 0755 'rsyslog.d' +maybe chmod 0644 'rsyslog.d/rsyslog-tls.conf' +maybe chmod 0644 'securetty' +maybe chmod 0755 'security' +maybe chmod 0644 'security/access.conf' +maybe chmod 0644 'security/group.conf' +maybe chmod 0644 'security/limits.conf' +maybe chmod 0755 'security/limits.d' +maybe chmod 0644 'security/namespace.conf' +maybe chmod 0755 'security/namespace.d' +maybe chmod 0755 'security/namespace.init' +maybe chmod 0600 'security/opasswd' +maybe chmod 0644 'security/pam_env.conf' +maybe chmod 0644 'security/sepermit.conf' +maybe chmod 0644 'security/time.conf' +maybe chmod 0755 'selinux' +maybe chmod 0644 'selinux/semanage.conf' +maybe chmod 0755 'sensors.d' +maybe chmod 0644 'sensors.d/.placeholder' +maybe chmod 0644 'sensors3.conf' +maybe chmod 0644 'services' +maybe chgrp 'shadow' 'shadow' +maybe chmod 0640 'shadow' +maybe chgrp 'shadow' 'shadow-' +maybe chmod 0640 'shadow-' +maybe chmod 0644 'shells' +maybe chmod 0755 'skel' +maybe chmod 0644 'skel/.bash_logout' +maybe chmod 0644 'skel/.bashrc' +maybe chmod 0644 'skel/.profile' +maybe chmod 0755 'snmp' +maybe chmod 0755 'snmp-mibs-downloader' +maybe chmod 0644 'snmp-mibs-downloader/cisco.conf' +maybe chmod 0644 'snmp-mibs-downloader/ciscolist' +maybe chmod 0644 'snmp-mibs-downloader/iana.conf' +maybe chmod 0644 'snmp-mibs-downloader/ianalist' +maybe chmod 0644 'snmp-mibs-downloader/ianarfc.conf' +maybe chmod 0644 'snmp-mibs-downloader/ianarfclist' +maybe chmod 0644 'snmp-mibs-downloader/junos.conf' +maybe chmod 0644 'snmp-mibs-downloader/junoslist' +maybe chmod 0644 'snmp-mibs-downloader/rfc.conf' +maybe chmod 0644 'snmp-mibs-downloader/rfclist' +maybe chmod 0644 'snmp-mibs-downloader/rfcmibs.diff' +maybe chmod 0644 'snmp-mibs-downloader/screenos.conf' +maybe chmod 0644 'snmp-mibs-downloader/screenoslist' +maybe chmod 0644 'snmp-mibs-downloader/simplelist' +maybe chmod 0644 'snmp-mibs-downloader/simpleweb.conf' +maybe chmod 0644 'snmp-mibs-downloader/snmp-mibs-downloader.conf' +maybe chmod 0644 'snmp/snmp.conf' +maybe chmod 0600 'snmp/snmpd.conf' +maybe chmod 0755 'ssh' +maybe chmod 0644 'ssh/moduli' +maybe chmod 0644 'ssh/ssh_config' +maybe chmod 0600 'ssh/ssh_host_dsa_key' +maybe chmod 0644 'ssh/ssh_host_dsa_key.pub' +maybe chmod 0600 'ssh/ssh_host_ecdsa_key' +maybe chmod 0644 'ssh/ssh_host_ecdsa_key.pub' +maybe chmod 0600 'ssh/ssh_host_ed25519_key' +maybe chmod 0644 'ssh/ssh_host_ed25519_key.pub' +maybe chmod 0600 'ssh/ssh_host_rsa_key' +maybe chmod 0644 'ssh/ssh_host_rsa_key.pub' +maybe chmod 0644 'ssh/ssh_import_id' +maybe chmod 0644 'ssh/sshd_config' +maybe chmod 0755 'ssl' +maybe chmod 0755 'ssl/certs' +maybe chmod 0644 'ssl/certs/ca-certificates.crt' +maybe chmod 0755 'ssl/certs/java' +maybe chmod 0644 'ssl/certs/java/cacerts' +maybe chmod 0644 'ssl/certs/ssl-cert-snakeoil.pem' +maybe chmod 0644 'ssl/openssl.cnf' +maybe chgrp 'ssl-cert' 'ssl/private' +maybe chmod 0710 'ssl/private' +maybe chgrp 'ssl-cert' 'ssl/private/ssl-cert-snakeoil.key' +maybe chmod 0640 'ssl/private/ssl-cert-snakeoil.key' +maybe chmod 0644 'subgid' +maybe chmod 0644 'subgid-' +maybe chmod 0644 'subuid' +maybe chmod 0644 'subuid-' +maybe chmod 0440 'sudoers' +maybe chmod 0755 'sudoers.d' +maybe chmod 0440 'sudoers.d/010_at-export' +maybe chmod 0440 'sudoers.d/010_pi-nopasswd' +maybe chmod 0440 'sudoers.d/010_proxy' +maybe chmod 0440 'sudoers.d/README' +maybe chmod 0440 'sudoers.d/iobroker' +maybe chmod 0644 'sysctl.conf' +maybe chmod 0755 'sysctl.d' +maybe chmod 0644 'sysctl.d/30-postgresql-shm.conf' +maybe chmod 0644 'sysctl.d/98-rpi.conf' +maybe chmod 0644 'sysctl.d/README.sysctl' +maybe chmod 0644 'sysctl.d/protect-links.conf' +maybe chmod 0755 'sysstat' +maybe chmod 0644 'sysstat/sysstat' +maybe chmod 0644 'sysstat/sysstat.ioconf' +maybe chmod 0755 'systemd' +maybe chmod 0644 'systemd/journald.conf' +maybe chmod 0644 'systemd/logind.conf' +maybe chmod 0755 'systemd/network' +maybe chmod 0644 'systemd/networkd.conf' +maybe chmod 0644 'systemd/resolved.conf' +maybe chmod 0644 'systemd/sleep.conf' +maybe chmod 0755 'systemd/system' +maybe chmod 0644 'systemd/system.conf' +maybe chmod 0644 'systemd/system/AdGuardHome.service' +maybe chmod 0644 'systemd/system/autologin@.service' +maybe chmod 0755 'systemd/system/bluetooth.target.wants' +maybe chmod 0644 'systemd/system/check-mk-agent-async.service' +maybe chmod 0644 'systemd/system/check-mk-agent.socket' +maybe chmod 0644 'systemd/system/check-mk-agent@.service' +maybe chmod 0755 'systemd/system/dhcpcd.service.d' +maybe chmod 0644 'systemd/system/dhcpcd.service.d/wait.conf' +maybe chmod 0755 'systemd/system/docker.service.d' +maybe chmod 0755 'systemd/system/getty.target.wants' +maybe chmod 0755 'systemd/system/getty@tty1.service.d' +maybe chmod 0644 'systemd/system/getty@tty1.service.d/noclear.conf' +maybe chmod 0644 'systemd/system/gitea.service' +maybe chmod 0755 'systemd/system/halt.target.wants' +maybe chmod 0755 'systemd/system/multi-user.target.wants' +maybe chmod 0755 'systemd/system/network-online.target.wants' +maybe chmod 0755 'systemd/system/poweroff.target.wants' +maybe chmod 0755 'systemd/system/rc-local.service.d' +maybe chmod 0644 'systemd/system/rc-local.service.d/ttyoutput.conf' +maybe chmod 0755 'systemd/system/reboot.target.wants' +maybe chmod 0755 'systemd/system/remote-fs.target.wants' +maybe chmod 0755 'systemd/system/sockets.target.wants' +maybe chmod 0755 'systemd/system/sysinit.target.wants' +maybe chmod 0755 'systemd/system/timers.target.wants' +maybe chmod 0644 'systemd/timesyncd.conf' +maybe chmod 0755 'systemd/user' +maybe chmod 0644 'systemd/user.conf' +maybe chmod 0755 'terminfo' +maybe chmod 0644 'terminfo/README' +maybe chmod 0644 'timezone' +maybe chmod 0755 'tmpfiles.d' +maybe chmod 0755 'triggerhappy' +maybe chmod 0755 'triggerhappy/triggers.d' +maybe chmod 0644 'ucf.conf' +maybe chmod 0755 'udev' +maybe chmod 0755 'udev/hwdb.d' +maybe chmod 0755 'udev/rules.d' +maybe chmod 0644 'udev/rules.d/99-com.rules' +maybe chmod 0644 'udev/udev.conf' +maybe chmod 0755 'ufw' +maybe chmod 0755 'ufw/applications.d' +maybe chmod 0644 'ufw/applications.d/nginx' +maybe chmod 0644 'ufw/applications.d/openssh-server' +maybe chmod 0755 'update-motd.d' +maybe chmod 0755 'update-motd.d/00-motd' +maybe chmod 0644 'usb_modeswitch.conf' +maybe chmod 0755 'usb_modeswitch.d' +maybe chmod 0755 'vim' +maybe chmod 0644 'vim/vimrc' +maybe chmod 0644 'vim/vimrc.tiny' +maybe chmod 0644 'wgetrc' +maybe chmod 0700 'wireguard' +maybe chmod 0600 'wireguard_2021-01-28-103503.tar.gz' +maybe chmod 0755 'wireshark' +maybe chmod 0644 'wireshark/init.lua' +maybe chmod 0755 'wpa_supplicant' +maybe chmod 0755 'wpa_supplicant/action_wpa.sh' +maybe chmod 0644 'wpa_supplicant/functions.sh' +maybe chmod 0755 'wpa_supplicant/ifupdown.sh' +maybe chmod 0600 'wpa_supplicant/wpa_supplicant.conf' +maybe chmod 0644 'xattr.conf' +maybe chmod 0755 'xdg' +maybe chmod 0755 'xdg/autostart' +maybe chmod 0644 'xdg/autostart/xdg-user-dirs.desktop' +maybe chmod 0755 'xdg/systemd' +maybe chmod 0644 'xdg/user-dirs.conf' +maybe chmod 0644 'xdg/user-dirs.defaults' +maybe chmod 0644 'xinetd.conf' +maybe chmod 0755 'xinetd.d' +maybe chmod 0644 'xinetd.d/chargen' +maybe chmod 0644 'xinetd.d/chargen-udp' +maybe chmod 0644 'xinetd.d/daytime' +maybe chmod 0644 'xinetd.d/daytime-udp' +maybe chmod 0644 'xinetd.d/discard' +maybe chmod 0644 'xinetd.d/discard-udp' +maybe chmod 0644 'xinetd.d/echo' +maybe chmod 0644 'xinetd.d/echo-udp' +maybe chmod 0644 'xinetd.d/servers' +maybe chmod 0644 'xinetd.d/services' +maybe chmod 0644 'xinetd.d/time' +maybe chmod 0644 'xinetd.d/time-udp' diff --git a/.fstab b/.fstab new file mode 100644 index 00000000..7bcc6740 --- /dev/null +++ b/.fstab @@ -0,0 +1,8 @@ +proc /proc proc defaults 0 0 +PARTUUID=6c586e13-01 /boot vfat defaults 0 2 +PARTUUID=6c586e13-02 / ext4 defaults,noatime 0 1 + +# cifs mount +#//192.168.0.40/video /mnt/library/video cifs auto,user,defaults,username=plex,password=#gentoo#,iocharset=utf8 0 0 +#//192.168.0.40/music /mnt/library/music cifs auto,user,defaults,username=plex,password=#gentoo#,iocharset=utf8 0 0 +#//192.168.0.40/photo /mnt/library/photo cifs auto,user,defaults,username=plex,password=#gentoo#,iocharset=utf8 0 0 diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..9196cf5c --- /dev/null +++ b/.gitignore @@ -0,0 +1,54 @@ +# begin section managed by etckeeper (do not edit this section by hand) + +# new and old versions of conffiles, stored by dpkg +*.dpkg-* +# new and old versions of conffiles, stored by ucf +*.ucf-* + +# old versions of files +*.old + +# mount(8) records system state here, no need to store these +blkid.tab +blkid.tab.old + +# some other files in /etc that typically do not need to be tracked +nologin +ld.so.cache +prelink.cache +mtab +mtab.fuselock +.pwd.lock +*.LOCK +network/run +adjtime +lvm/cache +lvm/archive +X11/xdm/authdir/authfiles/* +ntp.conf.dhcp +.initctl +webmin/fsdump/*.status +webmin/webmin/oscache +apparmor.d/cache/* +service/*/supervise/* +service/*/log/supervise/* +sv/*/supervise/* +sv/*/log/supervise/* +*.elc +*.pyc +*.pyo +init.d/.depend.* +openvpn/openvpn-status.log +cups/subscriptions.conf +cups/subscriptions.conf.O +fake-hwclock.data +check_mk/logwatch.state + +# editor temp files +*~ +.*.sw? +.sw? +\#*\# +DEADJOE + +# end section managed by etckeeper diff --git a/.java/.systemPrefs/.system.lock b/.java/.systemPrefs/.system.lock new file mode 100644 index 00000000..e69de29b diff --git a/.java/.systemPrefs/.systemRootModFile b/.java/.systemPrefs/.systemRootModFile new file mode 100644 index 00000000..e69de29b diff --git a/ImageMagick-6/coder.xml b/ImageMagick-6/coder.xml new file mode 100644 index 00000000..4d2394fe --- /dev/null +++ b/ImageMagick-6/coder.xml @@ -0,0 +1,23 @@ + + + + + +]> + + + + + + diff --git a/ImageMagick-6/colors.xml b/ImageMagick-6/colors.xml new file mode 100644 index 00000000..55bfb5d8 --- /dev/null +++ b/ImageMagick-6/colors.xml @@ -0,0 +1,28 @@ + + + + + + +]> + + + + + + + + + + + + diff --git a/ImageMagick-6/delegates.xml b/ImageMagick-6/delegates.xml new file mode 100644 index 00000000..ea0efd85 --- /dev/null +++ b/ImageMagick-6/delegates.xml @@ -0,0 +1,122 @@ + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ImageMagick-6/log.xml b/ImageMagick-6/log.xml new file mode 100644 index 00000000..8a290992 --- /dev/null +++ b/ImageMagick-6/log.xml @@ -0,0 +1,80 @@ + + + + + + + + + +]> + + + + + + + + + diff --git a/ImageMagick-6/magic.xml b/ImageMagick-6/magic.xml new file mode 100644 index 00000000..7f17731b --- /dev/null +++ b/ImageMagick-6/magic.xml @@ -0,0 +1,23 @@ + + + + + + +]> + + + + + + + diff --git a/ImageMagick-6/mime.xml b/ImageMagick-6/mime.xml new file mode 100644 index 00000000..9530fc8d --- /dev/null +++ b/ImageMagick-6/mime.xml @@ -0,0 +1,1145 @@ + + + + + + + + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ImageMagick-6/policy.xml b/ImageMagick-6/policy.xml new file mode 100644 index 00000000..82a3d0b6 --- /dev/null +++ b/ImageMagick-6/policy.xml @@ -0,0 +1,96 @@ + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ImageMagick-6/quantization-table.xml b/ImageMagick-6/quantization-table.xml new file mode 100644 index 00000000..fb718749 --- /dev/null +++ b/ImageMagick-6/quantization-table.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + +]> + + + + Luma Quantization Table + + 16, 16, 16, 18, 25, 37, 56, 85, + 16, 17, 20, 27, 34, 40, 53, 75, + 16, 20, 24, 31, 43, 62, 91, 135, + 18, 27, 31, 40, 53, 74, 106, 156, + 25, 34, 43, 53, 69, 94, 131, 189, + 37, 40, 62, 74, 94, 124, 169, 238, + 56, 53, 91, 106, 131, 169, 226, 311, + 85, 75, 135, 156, 189, 238, 311, 418 + +
+ +
+ diff --git a/ImageMagick-6/thresholds.xml b/ImageMagick-6/thresholds.xml new file mode 100644 index 00000000..02b96a85 --- /dev/null +++ b/ImageMagick-6/thresholds.xml @@ -0,0 +1,336 @@ + + + + + + + + + +]> + + + + + + Threshold 1x1 (non-dither) + + 1 + + + + + Checkerboard 2x1 (dither) + + 1 2 + 2 1 + + + + + + Ordered 2x2 (dispersed) + + 1 3 + 4 2 + + + + + Ordered 3x3 (dispersed) + + 3 7 4 + 6 1 9 + 2 8 5 + + + + + + Ordered 4x4 (dispersed) + + 1 9 3 11 + 13 5 15 7 + 4 12 2 10 + 16 8 14 6 + + + + + + Ordered 8x8 (dispersed) + + 1 49 13 61 4 52 16 64 + 33 17 45 29 36 20 48 32 + 9 57 5 53 12 60 8 56 + 41 25 37 21 44 28 40 24 + 3 51 15 63 2 50 14 62 + 35 19 47 31 34 18 46 30 + 11 59 7 55 10 58 6 54 + 43 27 39 23 42 26 38 22 + + + + + + Halftone 4x4 (angled) + + 4 2 7 5 + 3 1 8 6 + 7 5 4 2 + 8 6 3 1 + + + + + Halftone 6x6 (angled) + + 14 13 10 8 2 3 + 16 18 12 7 1 4 + 15 17 11 9 6 5 + 8 2 3 14 13 10 + 7 1 4 16 18 12 + 9 6 5 15 17 11 + + + + + Halftone 8x8 (angled) + + 13 7 8 14 17 21 22 18 + 6 1 3 9 28 31 29 23 + 5 2 4 10 27 32 30 24 + 16 12 11 15 20 26 25 19 + 17 21 22 18 13 7 8 14 + 28 31 29 23 6 1 3 9 + 27 32 30 24 5 2 4 10 + 20 26 25 19 16 12 11 15 + + + + + + Halftone 4x4 (orthogonal) + + 7 13 11 4 + 12 16 14 8 + 10 15 6 2 + 5 9 3 1 + + + + + Halftone 6x6 (orthogonal) + + 7 17 27 14 9 4 + 21 29 33 31 18 11 + 24 32 36 34 25 22 + 19 30 35 28 20 10 + 8 15 26 16 6 2 + 5 13 23 12 3 1 + + + + + Halftone 8x8 (orthogonal) + + 7 21 33 43 36 19 9 4 + 16 27 51 55 49 29 14 11 + 31 47 57 61 59 45 35 23 + 41 53 60 64 62 52 40 38 + 37 44 58 63 56 46 30 22 + 15 28 48 54 50 26 17 10 + 8 18 34 42 32 20 6 2 + 5 13 25 39 24 12 3 1 + + + + + + Halftone 16x16 (orthogonal) + + 4 12 24 44 72 100 136 152 150 134 98 70 42 23 11 3 + 7 16 32 52 76 104 144 160 158 142 102 74 50 31 15 6 + 19 27 40 60 92 132 168 180 178 166 130 90 58 39 26 18 + 36 48 56 80 124 176 188 204 203 187 175 122 79 55 47 35 + 64 68 84 116 164 200 212 224 223 211 199 162 114 83 67 63 + 88 96 112 156 192 216 232 240 239 231 214 190 154 111 95 87 + 108 120 148 184 208 228 244 252 251 243 226 206 182 147 119 107 + 128 140 172 196 219 235 247 256 255 246 234 218 194 171 139 127 + 126 138 170 195 220 236 248 253 254 245 233 217 193 169 137 125 + 106 118 146 183 207 227 242 249 250 241 225 205 181 145 117 105 + 86 94 110 155 191 215 229 238 237 230 213 189 153 109 93 85 + 62 66 82 115 163 198 210 221 222 209 197 161 113 81 65 61 + 34 46 54 78 123 174 186 202 201 185 173 121 77 53 45 33 + 20 28 37 59 91 131 167 179 177 165 129 89 57 38 25 17 + 8 13 29 51 75 103 143 159 157 141 101 73 49 30 14 5 + 1 9 21 43 71 99 135 151 149 133 97 69 41 22 10 2 + + + + + + + Circles 5x5 (black) + + 1 21 16 15 4 + 5 17 20 19 14 + 6 21 25 24 12 + 7 18 22 23 11 + 2 8 9 10 3 + + + + + + Circles 5x5 (white) + + 25 21 10 11 22 + 20 9 6 7 12 + 19 5 1 2 13 + 18 8 4 3 14 + 24 17 16 15 23 + + + + + Circles 6x6 (black) + + 1 5 14 13 12 4 + 6 22 28 27 21 11 + 15 29 35 34 26 20 + 16 30 36 33 25 19 + 7 23 31 32 24 10 + 2 8 17 18 9 3 + + + + + Circles 6x6 (white) + + 36 32 23 24 25 33 + 31 15 9 10 16 26 + 22 8 2 3 11 17 + 21 7 1 4 12 18 + 30 14 6 5 13 27 + 35 29 20 19 28 34 + + + + + Circles 7x7 (black) + + 3 9 18 28 17 8 2 + 10 24 33 39 32 23 7 + 19 34 44 48 43 31 16 + 25 40 45 49 47 38 27 + 20 35 41 46 42 29 15 + 11 21 36 37 28 22 6 + 4 12 13 26 14 5 1 + + + + + + Circles 7x7 (white) + + 47 41 32 22 33 42 48 + 40 26 17 11 18 27 43 + 31 16 6 2 7 19 34 + 25 10 5 1 3 12 23 + 30 15 9 4 8 20 35 + 39 29 14 13 21 28 44 + 46 38 37 24 36 45 49 + + + + + + + diff --git a/ImageMagick-6/type-apple.xml b/ImageMagick-6/type-apple.xml new file mode 100644 index 00000000..57fe9d14 --- /dev/null +++ b/ImageMagick-6/type-apple.xml @@ -0,0 +1,1367 @@ + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ImageMagick-6/type-dejavu.xml b/ImageMagick-6/type-dejavu.xml new file mode 100644 index 00000000..29b3c204 --- /dev/null +++ b/ImageMagick-6/type-dejavu.xml @@ -0,0 +1,58 @@ + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ImageMagick-6/type-ghostscript.xml b/ImageMagick-6/type-ghostscript.xml new file mode 100644 index 00000000..b5162310 --- /dev/null +++ b/ImageMagick-6/type-ghostscript.xml @@ -0,0 +1,50 @@ + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ImageMagick-6/type-urw-base35.xml b/ImageMagick-6/type-urw-base35.xml new file mode 100644 index 00000000..2f70e723 --- /dev/null +++ b/ImageMagick-6/type-urw-base35.xml @@ -0,0 +1,50 @@ + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ImageMagick-6/type-windows.xml b/ImageMagick-6/type-windows.xml new file mode 100644 index 00000000..621eec42 --- /dev/null +++ b/ImageMagick-6/type-windows.xml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ImageMagick-6/type.xml b/ImageMagick-6/type.xml new file mode 100644 index 00000000..a9c39bf9 --- /dev/null +++ b/ImageMagick-6/type.xml @@ -0,0 +1,17 @@ + + + + + +]> + + + + diff --git a/NetworkManager/dispatcher.d/ntp b/NetworkManager/dispatcher.d/ntp new file mode 100755 index 00000000..1775eaf6 --- /dev/null +++ b/NetworkManager/dispatcher.d/ntp @@ -0,0 +1,12 @@ +#!/bin/sh + +old_ntp_servers="unknown and invalid" +new_ntp_servers=$DHCP4_NTP_SERVERS +case "$2" in + up|vpn-up) reason=BOUND; ;; + down|vpn-down) reason=RELEASE; ;; + *) exit 0; ;; +esac + +test -f /etc/dhcp/dhclient-exit-hooks.d/ntp || exit 0 +. /etc/dhcp/dhclient-exit-hooks.d/ntp diff --git a/X11/Xreset b/X11/Xreset new file mode 100755 index 00000000..7a0974cf --- /dev/null +++ b/X11/Xreset @@ -0,0 +1,34 @@ +#!/bin/sh +# +# /etc/X11/Xreset +# +# global Xreset file -- for use by display managers + +# $Id: Xsession 967 2005-12-27 07:20:55Z dnusinow $ + +set -e + +PROGNAME=Xreset +SYSSESSIONDIR=/etc/X11/Xreset.d + +if [ ! -d "$SYSSESSIONDIR" ]; then + # Nothing to do, exiting + exit 0 +fi + +# use run-parts to source every file in the session directory; we source +# instead of executing so that the variables and functions defined above +# are available to the scripts, and so that they can pass variables to each +# other +SESSIONFILES=$(run-parts --list $SYSSESSIONDIR) +if [ -n "$SESSIONFILES" ]; then + set +e + for SESSIONFILE in $SESSIONFILES; do + . $SESSIONFILE + done + set -e +fi + +exit 0 + +# vim:set ai et sts=2 sw=2 tw=80: diff --git a/X11/Xreset.d/README b/X11/Xreset.d/README new file mode 100644 index 00000000..3c03f424 --- /dev/null +++ b/X11/Xreset.d/README @@ -0,0 +1,4 @@ +# Scripts in this directory are executed as root when a user log out from +# a display manager using /etc/X11/Xreset. +# The username of the user logging out is provided in the $USER environment +# variable. diff --git a/X11/Xresources/x11-common b/X11/Xresources/x11-common new file mode 100644 index 00000000..76412072 --- /dev/null +++ b/X11/Xresources/x11-common @@ -0,0 +1,10 @@ +! $Id$ + +! load color-specific resources for clients that have them +#ifdef COLOR +*customization: -color +#endif + +! make Xaw (Athena widget set) clients understand the delete key +! this causes problems with some non-Xaw apps, use with care +! *Text.translations: #override ~Shift ~Meta Delete: delete-next-character() diff --git a/X11/Xsession b/X11/Xsession new file mode 100755 index 00000000..6ad7d6ed --- /dev/null +++ b/X11/Xsession @@ -0,0 +1,113 @@ +#!/bin/sh +# +# /etc/X11/Xsession +# +# global Xsession file -- used by display managers and xinit (startx) + +# $Id: Xsession 967 2005-12-27 07:20:55Z dnusinow $ + +set -e + +PROGNAME=Xsession + +message () { + # pretty-print messages of arbitrary length; use xmessage if it + # is available and $DISPLAY is set + MESSAGE="$PROGNAME: $*" + echo "$MESSAGE" | fold -s -w ${COLUMNS:-80} >&2 + if [ -n "$DISPLAY" ] && which xmessage > /dev/null 2>&1; then + echo "$MESSAGE" | fold -s -w ${COLUMNS:-80} | xmessage -center -file - + fi +} + +message_nonl () { + # pretty-print messages of arbitrary length (no trailing newline); use + # xmessage if it is available and $DISPLAY is set + MESSAGE="$PROGNAME: $*" + echo -n "$MESSAGE" | fold -s -w ${COLUMNS:-80} >&2; + if [ -n "$DISPLAY" ] && which xmessage > /dev/null 2>&1; then + echo -n "$MESSAGE" | fold -s -w ${COLUMNS:-80} | xmessage -center -file - + fi +} + +errormsg () { + # exit script with error + message "$*" + exit 1 +} + +internal_errormsg () { + # exit script with error; essentially a "THIS SHOULD NEVER HAPPEN" message + # One big call to message() for the sake of xmessage; if we had two then + # the user would have dismissed the error we want reported before seeing the + # request to report it. + errormsg "$*" \ + "Please report the installed version of the \"x11-common\"" \ + "package and the complete text of this error message to" \ + "." +} + +# initialize variables for use by all session scripts + +OPTIONFILE=/etc/X11/Xsession.options + +SYSRESOURCES=/etc/X11/Xresources +USRRESOURCES=$HOME/.Xresources + +SYSSESSIONDIR=/etc/X11/Xsession.d +USERXSESSION=$HOME/.xsession +USERXSESSIONRC=$HOME/.xsessionrc +ALTUSERXSESSION=$HOME/.Xsession +ERRFILE=$HOME/.xsession-errors + +# attempt to create an error file; abort if we cannot +if (umask 077 && touch "$ERRFILE") 2> /dev/null && [ -w "$ERRFILE" ] && + [ ! -L "$ERRFILE" ]; then + chmod 600 "$ERRFILE" +elif ERRFILE=$(tempfile 2> /dev/null); then + if ! ln -sf "$ERRFILE" "${TMPDIR:=/tmp}/xsession-$USER"; then + message "warning: unable to symlink \"$TMPDIR/xsession-$USER\" to" \ + "\"$ERRFILE\"; look for session log/errors in" \ + "\"$TMPDIR/xsession-$USER\"." + fi +else + errormsg "unable to create X session log/error file; aborting." +fi + +exec >>"$ERRFILE" 2>&1 + +echo "$PROGNAME: X session started for $LOGNAME at $(date)" + +# sanity check; is our session script directory present? +if [ ! -d "$SYSSESSIONDIR" ]; then + errormsg "no \"$SYSSESSIONDIR\" directory found; aborting." +fi + +# Attempt to create a file of non-zero length in /tmp; a full filesystem can +# cause mysterious X session failures. We do not use touch, :, or test -w +# because they won't actually create a file with contents. We also let standard +# error from tempfile and echo go to the error file to aid the user in +# determining what went wrong. +WRITE_TEST=$(tempfile) +if ! echo "*" >>"$WRITE_TEST"; then + message "warning: unable to write to ${WRITE_TEST%/*}; X session may exit" \ + "with an error" +fi +rm -f "$WRITE_TEST" + +# use run-parts to source every file in the session directory; we source +# instead of executing so that the variables and functions defined above +# are available to the scripts, and so that they can pass variables to each +# other +SESSIONFILES=$(run-parts --list $SYSSESSIONDIR) +if [ -n "$SESSIONFILES" ]; then + set +e + for SESSIONFILE in $SESSIONFILES; do + . $SESSIONFILE + done + set -e +fi + +exit 0 + +# vim:set ai et sts=2 sw=2 tw=80: diff --git a/X11/Xsession.d/20x11-common_process-args b/X11/Xsession.d/20x11-common_process-args new file mode 100644 index 00000000..93e46538 --- /dev/null +++ b/X11/Xsession.d/20x11-common_process-args @@ -0,0 +1,70 @@ +# $Id: 20x11-common_process-args 305 2005-07-03 18:51:43Z dnusinow $ + +# This file is sourced by Xsession(5), not executed. + +# read OPTIONFILE +OPTIONS=$(cat "$OPTIONFILE") || true + +has_option() { + if [ "${OPTIONS#* +$1}" != "$OPTIONS" ]; then + return 0 + else + return 1 + fi +} + +# Determine how many arguments were provided. +case $# in + 0) + # No arguments given; use default behavior. + ;; + 1) + # One argument given; see what it was. + case "$1" in + failsafe) + # Failsafe session was requested. + if has_option allow-failsafe; then + if [ -e /usr/bin/x-terminal-emulator ]; then + if [ -x /usr/bin/x-terminal-emulator ]; then + exec x-terminal-emulator -geometry +1+1 + else + # fatal error + errormsg "unable to launch failsafe X session ---" \ + "x-terminal-emulator not executable; aborting." + fi + else + # fatal error + errormsg "unable to launch failsafe X session ---" \ + "x-terminal-emulator not found; aborting." + fi + fi + ;; + default) + # Default behavior was requested. + ;; + *) + # Specific program was requested. + STARTUP_FULL_PATH=$(/usr/bin/which "$1" || true) + if [ -n "$STARTUP_FULL_PATH" ] && [ -e "$STARTUP_FULL_PATH" ]; then + if [ -x "$STARTUP_FULL_PATH" ]; then + STARTUP="$1" + else + message "unable to launch \"$1\" X session ---" \ + "\"$1\" not executable; falling back to default session." + fi + else + message "unable to launch \"$1\" X session ---" \ + "\"$1\" not found; falling back to default session." + fi + ;; + esac + ;; + *) + # More than one argument given; we don't know what to do. + message "unsupported number of arguments ($#); falling back to default" \ + "session." + ;; +esac + +# vim:set ai et sts=2 sw=2 tw=80: diff --git a/X11/Xsession.d/30x11-common_xresources b/X11/Xsession.d/30x11-common_xresources new file mode 100644 index 00000000..c3f53a83 --- /dev/null +++ b/X11/Xsession.d/30x11-common_xresources @@ -0,0 +1,26 @@ +# $Id: 30x11-common_xresources 305 2005-07-03 18:51:43Z dnusinow $ + +# This file is sourced by Xsession(5), not executed. + +# If xrdb (from xbase-clients) is installed, merge system-wide X resources. +# Then merge the user's X resources, if the options file is so configured. +if [ -d "$SYSRESOURCES" ] && type xrdb >/dev/null 2>&1; then + RESOURCEFILES=$(run-parts --list $SYSRESOURCES) + if [ -n "$RESOURCEFILES" ]; then + for RESOURCEFILE in $RESOURCEFILES; do + xrdb -merge $RESOURCEFILE + done + fi +fi + +if has_option allow-user-resources && [ -f "$USRRESOURCES" ]; then + if type xrdb >/dev/null 2>&1; then + xrdb -merge $USRRESOURCES + else + # Comment out this command if you desire a legacy-free X environment, and find + # the warning spurious. + message "warning: xrdb command not found; X resources not merged." + fi +fi + +# vim:set ai et sts=2 sw=2 tw=80: diff --git a/X11/Xsession.d/35x11-common_xhost-local b/X11/Xsession.d/35x11-common_xhost-local new file mode 100644 index 00000000..d127a6c7 --- /dev/null +++ b/X11/Xsession.d/35x11-common_xhost-local @@ -0,0 +1,10 @@ +# This file is sourced by Xsession(5), not executed. + +# If xhost (from x11-xserver-utils) is installed, use it to give access +# to the X server to any process from the same user on the local host. +# Unlike other uses of xhost, this is safe since the kernel can check +# the actual owner of the calling process. + +if type xhost >/dev/null 2>&1; then + xhost +si:localuser:$(id -un) || : +fi diff --git a/X11/Xsession.d/40x11-common_xsessionrc b/X11/Xsession.d/40x11-common_xsessionrc new file mode 100644 index 00000000..305f363d --- /dev/null +++ b/X11/Xsession.d/40x11-common_xsessionrc @@ -0,0 +1,6 @@ +# This file is sourced by Xsession(5), not executed. + +#Source user defined xsessionrc (locales and other environment variables) +if [ -r "$USERXSESSIONRC" ]; then + . "$USERXSESSIONRC" +fi diff --git a/X11/Xsession.d/50x11-common_determine-startup b/X11/Xsession.d/50x11-common_determine-startup new file mode 100644 index 00000000..4e135058 --- /dev/null +++ b/X11/Xsession.d/50x11-common_determine-startup @@ -0,0 +1,47 @@ +# $Id: 50x11-common_determine-startup 305 2005-07-03 18:51:43Z dnusinow $ + +# This file is sourced by Xsession(5), not executed. + +# If no X session startup program was passed to the Xsession script as an +# argument (e.g., by the display manager), or if that program was not +# executable, fall back to looking for a user's custom X session script, if +# allowed by the options file. +if [ -z "$STARTUP" ]; then + if has_option allow-user-xsession; then + for STARTUPFILE in "$USERXSESSION" "$ALTUSERXSESSION"; do + if [ -e "$STARTUPFILE" ]; then + if [ -x "$STARTUPFILE" ]; then + STARTUP="$STARTUPFILE" + else + shell=${SHELL:-sh} + STARTUP="$shell $STARTUPFILE" + fi + break + fi + done + fi +fi + +# If there is still nothing to use for a startup program, try the system +# default session manager, window manager, and terminal emulator. +if [ -z "$STARTUP" ]; then + if [ -x /usr/bin/x-session-manager ]; then + STARTUP=x-session-manager + elif [ -x /usr/bin/x-window-manager ]; then + STARTUP=x-window-manager + elif [ -x /usr/bin/x-terminal-emulator ]; then + STARTUP=x-terminal-emulator + fi +fi + +# If we still have not found a startup program, give up. +if [ -z "$STARTUP" ]; then + ERRMSG="unable to start X session ---" + if has_option allow-user-xsession; then + ERRMSG="$ERRMSG no \"$USERXSESSION\" file, no \"$ALTUSERXSESSION\" file," + fi + errormsg "$ERRMSG no session managers, no window managers, and no terminal" \ + "emulators found; aborting." +fi + +# vim:set ai et sts=2 sw=2 tw=80: diff --git a/X11/Xsession.d/90gpg-agent b/X11/Xsession.d/90gpg-agent new file mode 100644 index 00000000..8b45b05d --- /dev/null +++ b/X11/Xsession.d/90gpg-agent @@ -0,0 +1,22 @@ +# On systems with systemd running, we expect the agent to be launched +# via systemd's user mode (see +# /usr/lib/systemd/user/gpg-agent.{socket,service} and +# systemd.unit(5)). This allows systemd to clean up the agent +# automatically at logout. + +# If systemd is absent from your system, or you do not permit it to +# run in user mode, then you may need to manually launch gpg-agent +# from your session initialization with something like "gpgconf +# --launch gpg-agent" + +# Nonetheless, ssh and older versions of gpg require environment +# variables to be set in order to find the agent, so we will set those +# here. + +agent_sock=$(gpgconf --list-dirs agent-socket) +export GPG_AGENT_INFO=${agent_sock}:0:1 +if [ -n "$(gpgconf --list-options gpg-agent | \ + awk -F: '/^enable-ssh-support:/{ print $10 }')" ]; then + export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket) +fi + diff --git a/X11/Xsession.d/90x11-common_ssh-agent b/X11/Xsession.d/90x11-common_ssh-agent new file mode 100644 index 00000000..53974340 --- /dev/null +++ b/X11/Xsession.d/90x11-common_ssh-agent @@ -0,0 +1,24 @@ +# $Id: 90x11-common_ssh-agent 305 2005-07-03 18:51:43Z dnusinow $ + +# This file is sourced by Xsession(5), not executed. + +STARTSSH= +SSHAGENT=/usr/bin/ssh-agent +SSHAGENTARGS= + +if has_option use-ssh-agent; then + if [ -x "$SSHAGENT" ] && [ -z "$SSH_AUTH_SOCK" ] \ + && [ -z "$SSH2_AUTH_SOCK" ]; then + STARTSSH=yes + if [ -f /usr/bin/ssh-add1 ] && cmp -s $SSHAGENT /usr/bin/ssh-agent2; then + # use ssh-agent2's ssh-agent1 compatibility mode + SSHAGENTARGS=-1 + fi + fi +fi + +if [ -n "$STARTSSH" ]; then + STARTUP="$SSHAGENT $SSHAGENTARGS ${TMPDIR:+env TMPDIR=$TMPDIR} $STARTUP" +fi + +# vim:set ai et sts=2 sw=2 tw=80: diff --git a/X11/Xsession.d/99x11-common_start b/X11/Xsession.d/99x11-common_start new file mode 100644 index 00000000..36a96529 --- /dev/null +++ b/X11/Xsession.d/99x11-common_start @@ -0,0 +1,7 @@ +# $Id: 99x11-common_start 305 2005-07-03 18:51:43Z dnusinow $ + +# This file is sourced by Xsession(5), not executed. + +exec $STARTUP + +# vim:set ai et sts=2 sw=2 tw=80: diff --git a/X11/Xsession.options b/X11/Xsession.options new file mode 100644 index 00000000..fc45bf94 --- /dev/null +++ b/X11/Xsession.options @@ -0,0 +1,9 @@ +# $Id: Xsession.options 189 2005-06-11 00:04:27Z branden $ +# +# configuration options for /etc/X11/Xsession +# See Xsession.options(5) for an explanation of the available options. +allow-failsafe +allow-user-resources +allow-user-xsession +use-ssh-agent +use-session-dbus diff --git a/X11/rgb.txt b/X11/rgb.txt new file mode 100644 index 00000000..b9e56c60 --- /dev/null +++ b/X11/rgb.txt @@ -0,0 +1,754 @@ +! $Xorg: rgb.txt,v 1.3 2000/08/17 19:54:00 cpqbld Exp $ +255 250 250 snow +248 248 255 ghost white +248 248 255 GhostWhite +245 245 245 white smoke +245 245 245 WhiteSmoke +220 220 220 gainsboro +255 250 240 floral white +255 250 240 FloralWhite +253 245 230 old lace +253 245 230 OldLace +250 240 230 linen +250 235 215 antique white +250 235 215 AntiqueWhite +255 239 213 papaya whip +255 239 213 PapayaWhip +255 235 205 blanched almond +255 235 205 BlanchedAlmond +255 228 196 bisque +255 218 185 peach puff +255 218 185 PeachPuff +255 222 173 navajo white +255 222 173 NavajoWhite +255 228 181 moccasin +255 248 220 cornsilk +255 255 240 ivory +255 250 205 lemon chiffon +255 250 205 LemonChiffon +255 245 238 seashell +240 255 240 honeydew +245 255 250 mint cream +245 255 250 MintCream +240 255 255 azure +240 248 255 alice blue +240 248 255 AliceBlue +230 230 250 lavender +255 240 245 lavender blush +255 240 245 LavenderBlush +255 228 225 misty rose +255 228 225 MistyRose +255 255 255 white + 0 0 0 black + 47 79 79 dark slate gray + 47 79 79 DarkSlateGray + 47 79 79 dark slate grey + 47 79 79 DarkSlateGrey +105 105 105 dim gray +105 105 105 DimGray +105 105 105 dim grey +105 105 105 DimGrey +112 128 144 slate gray +112 128 144 SlateGray +112 128 144 slate grey +112 128 144 SlateGrey +119 136 153 light slate gray +119 136 153 LightSlateGray +119 136 153 light slate grey +119 136 153 LightSlateGrey +190 190 190 gray +190 190 190 grey +211 211 211 light grey +211 211 211 LightGrey +211 211 211 light gray +211 211 211 LightGray + 25 25 112 midnight blue + 25 25 112 MidnightBlue + 0 0 128 navy + 0 0 128 navy blue + 0 0 128 NavyBlue +100 149 237 cornflower blue +100 149 237 CornflowerBlue + 72 61 139 dark slate blue + 72 61 139 DarkSlateBlue +106 90 205 slate blue +106 90 205 SlateBlue +123 104 238 medium slate blue +123 104 238 MediumSlateBlue +132 112 255 light slate blue +132 112 255 LightSlateBlue + 0 0 205 medium blue + 0 0 205 MediumBlue + 65 105 225 royal blue + 65 105 225 RoyalBlue + 0 0 255 blue + 30 144 255 dodger blue + 30 144 255 DodgerBlue + 0 191 255 deep sky blue + 0 191 255 DeepSkyBlue +135 206 235 sky blue +135 206 235 SkyBlue +135 206 250 light sky blue +135 206 250 LightSkyBlue + 70 130 180 steel blue + 70 130 180 SteelBlue +176 196 222 light steel blue +176 196 222 LightSteelBlue +173 216 230 light blue +173 216 230 LightBlue +176 224 230 powder blue +176 224 230 PowderBlue +175 238 238 pale turquoise +175 238 238 PaleTurquoise + 0 206 209 dark turquoise + 0 206 209 DarkTurquoise + 72 209 204 medium turquoise + 72 209 204 MediumTurquoise + 64 224 208 turquoise + 0 255 255 cyan +224 255 255 light cyan +224 255 255 LightCyan + 95 158 160 cadet blue + 95 158 160 CadetBlue +102 205 170 medium aquamarine +102 205 170 MediumAquamarine +127 255 212 aquamarine + 0 100 0 dark green + 0 100 0 DarkGreen + 85 107 47 dark olive green + 85 107 47 DarkOliveGreen +143 188 143 dark sea green +143 188 143 DarkSeaGreen + 46 139 87 sea green + 46 139 87 SeaGreen + 60 179 113 medium sea green + 60 179 113 MediumSeaGreen + 32 178 170 light sea green + 32 178 170 LightSeaGreen +152 251 152 pale green +152 251 152 PaleGreen + 0 255 127 spring green + 0 255 127 SpringGreen +124 252 0 lawn green +124 252 0 LawnGreen + 0 255 0 green +127 255 0 chartreuse + 0 250 154 medium spring green + 0 250 154 MediumSpringGreen +173 255 47 green yellow +173 255 47 GreenYellow + 50 205 50 lime green + 50 205 50 LimeGreen +154 205 50 yellow green +154 205 50 YellowGreen + 34 139 34 forest green + 34 139 34 ForestGreen +107 142 35 olive drab +107 142 35 OliveDrab +189 183 107 dark khaki +189 183 107 DarkKhaki +240 230 140 khaki +238 232 170 pale goldenrod +238 232 170 PaleGoldenrod +250 250 210 light goldenrod yellow +250 250 210 LightGoldenrodYellow +255 255 224 light yellow +255 255 224 LightYellow +255 255 0 yellow +255 215 0 gold +238 221 130 light goldenrod +238 221 130 LightGoldenrod +218 165 32 goldenrod +184 134 11 dark goldenrod +184 134 11 DarkGoldenrod +188 143 143 rosy brown +188 143 143 RosyBrown +205 92 92 indian red +205 92 92 IndianRed +139 69 19 saddle brown +139 69 19 SaddleBrown +160 82 45 sienna +205 133 63 peru +222 184 135 burlywood +245 245 220 beige +245 222 179 wheat +244 164 96 sandy brown +244 164 96 SandyBrown +210 180 140 tan +210 105 30 chocolate +178 34 34 firebrick +165 42 42 brown +233 150 122 dark salmon +233 150 122 DarkSalmon +250 128 114 salmon +255 160 122 light salmon +255 160 122 LightSalmon +255 165 0 orange +255 140 0 dark orange +255 140 0 DarkOrange +255 127 80 coral +240 128 128 light coral +240 128 128 LightCoral +255 99 71 tomato +255 69 0 orange red +255 69 0 OrangeRed +255 0 0 red +255 105 180 hot pink +255 105 180 HotPink +255 20 147 deep pink +255 20 147 DeepPink +255 192 203 pink +255 182 193 light pink +255 182 193 LightPink +219 112 147 pale violet red +219 112 147 PaleVioletRed +176 48 96 maroon +199 21 133 medium violet red +199 21 133 MediumVioletRed +208 32 144 violet red +208 32 144 VioletRed +255 0 255 magenta +238 130 238 violet +221 160 221 plum +218 112 214 orchid +186 85 211 medium orchid +186 85 211 MediumOrchid +153 50 204 dark orchid +153 50 204 DarkOrchid +148 0 211 dark violet +148 0 211 DarkViolet +138 43 226 blue violet +138 43 226 BlueViolet +160 32 240 purple +147 112 219 medium purple +147 112 219 MediumPurple +216 191 216 thistle +255 250 250 snow1 +238 233 233 snow2 +205 201 201 snow3 +139 137 137 snow4 +255 245 238 seashell1 +238 229 222 seashell2 +205 197 191 seashell3 +139 134 130 seashell4 +255 239 219 AntiqueWhite1 +238 223 204 AntiqueWhite2 +205 192 176 AntiqueWhite3 +139 131 120 AntiqueWhite4 +255 228 196 bisque1 +238 213 183 bisque2 +205 183 158 bisque3 +139 125 107 bisque4 +255 218 185 PeachPuff1 +238 203 173 PeachPuff2 +205 175 149 PeachPuff3 +139 119 101 PeachPuff4 +255 222 173 NavajoWhite1 +238 207 161 NavajoWhite2 +205 179 139 NavajoWhite3 +139 121 94 NavajoWhite4 +255 250 205 LemonChiffon1 +238 233 191 LemonChiffon2 +205 201 165 LemonChiffon3 +139 137 112 LemonChiffon4 +255 248 220 cornsilk1 +238 232 205 cornsilk2 +205 200 177 cornsilk3 +139 136 120 cornsilk4 +255 255 240 ivory1 +238 238 224 ivory2 +205 205 193 ivory3 +139 139 131 ivory4 +240 255 240 honeydew1 +224 238 224 honeydew2 +193 205 193 honeydew3 +131 139 131 honeydew4 +255 240 245 LavenderBlush1 +238 224 229 LavenderBlush2 +205 193 197 LavenderBlush3 +139 131 134 LavenderBlush4 +255 228 225 MistyRose1 +238 213 210 MistyRose2 +205 183 181 MistyRose3 +139 125 123 MistyRose4 +240 255 255 azure1 +224 238 238 azure2 +193 205 205 azure3 +131 139 139 azure4 +131 111 255 SlateBlue1 +122 103 238 SlateBlue2 +105 89 205 SlateBlue3 + 71 60 139 SlateBlue4 + 72 118 255 RoyalBlue1 + 67 110 238 RoyalBlue2 + 58 95 205 RoyalBlue3 + 39 64 139 RoyalBlue4 + 0 0 255 blue1 + 0 0 238 blue2 + 0 0 205 blue3 + 0 0 139 blue4 + 30 144 255 DodgerBlue1 + 28 134 238 DodgerBlue2 + 24 116 205 DodgerBlue3 + 16 78 139 DodgerBlue4 + 99 184 255 SteelBlue1 + 92 172 238 SteelBlue2 + 79 148 205 SteelBlue3 + 54 100 139 SteelBlue4 + 0 191 255 DeepSkyBlue1 + 0 178 238 DeepSkyBlue2 + 0 154 205 DeepSkyBlue3 + 0 104 139 DeepSkyBlue4 +135 206 255 SkyBlue1 +126 192 238 SkyBlue2 +108 166 205 SkyBlue3 + 74 112 139 SkyBlue4 +176 226 255 LightSkyBlue1 +164 211 238 LightSkyBlue2 +141 182 205 LightSkyBlue3 + 96 123 139 LightSkyBlue4 +198 226 255 SlateGray1 +185 211 238 SlateGray2 +159 182 205 SlateGray3 +108 123 139 SlateGray4 +202 225 255 LightSteelBlue1 +188 210 238 LightSteelBlue2 +162 181 205 LightSteelBlue3 +110 123 139 LightSteelBlue4 +191 239 255 LightBlue1 +178 223 238 LightBlue2 +154 192 205 LightBlue3 +104 131 139 LightBlue4 +224 255 255 LightCyan1 +209 238 238 LightCyan2 +180 205 205 LightCyan3 +122 139 139 LightCyan4 +187 255 255 PaleTurquoise1 +174 238 238 PaleTurquoise2 +150 205 205 PaleTurquoise3 +102 139 139 PaleTurquoise4 +152 245 255 CadetBlue1 +142 229 238 CadetBlue2 +122 197 205 CadetBlue3 + 83 134 139 CadetBlue4 + 0 245 255 turquoise1 + 0 229 238 turquoise2 + 0 197 205 turquoise3 + 0 134 139 turquoise4 + 0 255 255 cyan1 + 0 238 238 cyan2 + 0 205 205 cyan3 + 0 139 139 cyan4 +151 255 255 DarkSlateGray1 +141 238 238 DarkSlateGray2 +121 205 205 DarkSlateGray3 + 82 139 139 DarkSlateGray4 +127 255 212 aquamarine1 +118 238 198 aquamarine2 +102 205 170 aquamarine3 + 69 139 116 aquamarine4 +193 255 193 DarkSeaGreen1 +180 238 180 DarkSeaGreen2 +155 205 155 DarkSeaGreen3 +105 139 105 DarkSeaGreen4 + 84 255 159 SeaGreen1 + 78 238 148 SeaGreen2 + 67 205 128 SeaGreen3 + 46 139 87 SeaGreen4 +154 255 154 PaleGreen1 +144 238 144 PaleGreen2 +124 205 124 PaleGreen3 + 84 139 84 PaleGreen4 + 0 255 127 SpringGreen1 + 0 238 118 SpringGreen2 + 0 205 102 SpringGreen3 + 0 139 69 SpringGreen4 + 0 255 0 green1 + 0 238 0 green2 + 0 205 0 green3 + 0 139 0 green4 +127 255 0 chartreuse1 +118 238 0 chartreuse2 +102 205 0 chartreuse3 + 69 139 0 chartreuse4 +192 255 62 OliveDrab1 +179 238 58 OliveDrab2 +154 205 50 OliveDrab3 +105 139 34 OliveDrab4 +202 255 112 DarkOliveGreen1 +188 238 104 DarkOliveGreen2 +162 205 90 DarkOliveGreen3 +110 139 61 DarkOliveGreen4 +255 246 143 khaki1 +238 230 133 khaki2 +205 198 115 khaki3 +139 134 78 khaki4 +255 236 139 LightGoldenrod1 +238 220 130 LightGoldenrod2 +205 190 112 LightGoldenrod3 +139 129 76 LightGoldenrod4 +255 255 224 LightYellow1 +238 238 209 LightYellow2 +205 205 180 LightYellow3 +139 139 122 LightYellow4 +255 255 0 yellow1 +238 238 0 yellow2 +205 205 0 yellow3 +139 139 0 yellow4 +255 215 0 gold1 +238 201 0 gold2 +205 173 0 gold3 +139 117 0 gold4 +255 193 37 goldenrod1 +238 180 34 goldenrod2 +205 155 29 goldenrod3 +139 105 20 goldenrod4 +255 185 15 DarkGoldenrod1 +238 173 14 DarkGoldenrod2 +205 149 12 DarkGoldenrod3 +139 101 8 DarkGoldenrod4 +255 193 193 RosyBrown1 +238 180 180 RosyBrown2 +205 155 155 RosyBrown3 +139 105 105 RosyBrown4 +255 106 106 IndianRed1 +238 99 99 IndianRed2 +205 85 85 IndianRed3 +139 58 58 IndianRed4 +255 130 71 sienna1 +238 121 66 sienna2 +205 104 57 sienna3 +139 71 38 sienna4 +255 211 155 burlywood1 +238 197 145 burlywood2 +205 170 125 burlywood3 +139 115 85 burlywood4 +255 231 186 wheat1 +238 216 174 wheat2 +205 186 150 wheat3 +139 126 102 wheat4 +255 165 79 tan1 +238 154 73 tan2 +205 133 63 tan3 +139 90 43 tan4 +255 127 36 chocolate1 +238 118 33 chocolate2 +205 102 29 chocolate3 +139 69 19 chocolate4 +255 48 48 firebrick1 +238 44 44 firebrick2 +205 38 38 firebrick3 +139 26 26 firebrick4 +255 64 64 brown1 +238 59 59 brown2 +205 51 51 brown3 +139 35 35 brown4 +255 140 105 salmon1 +238 130 98 salmon2 +205 112 84 salmon3 +139 76 57 salmon4 +255 160 122 LightSalmon1 +238 149 114 LightSalmon2 +205 129 98 LightSalmon3 +139 87 66 LightSalmon4 +255 165 0 orange1 +238 154 0 orange2 +205 133 0 orange3 +139 90 0 orange4 +255 127 0 DarkOrange1 +238 118 0 DarkOrange2 +205 102 0 DarkOrange3 +139 69 0 DarkOrange4 +255 114 86 coral1 +238 106 80 coral2 +205 91 69 coral3 +139 62 47 coral4 +255 99 71 tomato1 +238 92 66 tomato2 +205 79 57 tomato3 +139 54 38 tomato4 +255 69 0 OrangeRed1 +238 64 0 OrangeRed2 +205 55 0 OrangeRed3 +139 37 0 OrangeRed4 +255 0 0 red1 +238 0 0 red2 +205 0 0 red3 +139 0 0 red4 +215 7 81 DebianRed +255 20 147 DeepPink1 +238 18 137 DeepPink2 +205 16 118 DeepPink3 +139 10 80 DeepPink4 +255 110 180 HotPink1 +238 106 167 HotPink2 +205 96 144 HotPink3 +139 58 98 HotPink4 +255 181 197 pink1 +238 169 184 pink2 +205 145 158 pink3 +139 99 108 pink4 +255 174 185 LightPink1 +238 162 173 LightPink2 +205 140 149 LightPink3 +139 95 101 LightPink4 +255 130 171 PaleVioletRed1 +238 121 159 PaleVioletRed2 +205 104 137 PaleVioletRed3 +139 71 93 PaleVioletRed4 +255 52 179 maroon1 +238 48 167 maroon2 +205 41 144 maroon3 +139 28 98 maroon4 +255 62 150 VioletRed1 +238 58 140 VioletRed2 +205 50 120 VioletRed3 +139 34 82 VioletRed4 +255 0 255 magenta1 +238 0 238 magenta2 +205 0 205 magenta3 +139 0 139 magenta4 +255 131 250 orchid1 +238 122 233 orchid2 +205 105 201 orchid3 +139 71 137 orchid4 +255 187 255 plum1 +238 174 238 plum2 +205 150 205 plum3 +139 102 139 plum4 +224 102 255 MediumOrchid1 +209 95 238 MediumOrchid2 +180 82 205 MediumOrchid3 +122 55 139 MediumOrchid4 +191 62 255 DarkOrchid1 +178 58 238 DarkOrchid2 +154 50 205 DarkOrchid3 +104 34 139 DarkOrchid4 +155 48 255 purple1 +145 44 238 purple2 +125 38 205 purple3 + 85 26 139 purple4 +171 130 255 MediumPurple1 +159 121 238 MediumPurple2 +137 104 205 MediumPurple3 + 93 71 139 MediumPurple4 +255 225 255 thistle1 +238 210 238 thistle2 +205 181 205 thistle3 +139 123 139 thistle4 + 0 0 0 gray0 + 0 0 0 grey0 + 3 3 3 gray1 + 3 3 3 grey1 + 5 5 5 gray2 + 5 5 5 grey2 + 8 8 8 gray3 + 8 8 8 grey3 + 10 10 10 gray4 + 10 10 10 grey4 + 13 13 13 gray5 + 13 13 13 grey5 + 15 15 15 gray6 + 15 15 15 grey6 + 18 18 18 gray7 + 18 18 18 grey7 + 20 20 20 gray8 + 20 20 20 grey8 + 23 23 23 gray9 + 23 23 23 grey9 + 26 26 26 gray10 + 26 26 26 grey10 + 28 28 28 gray11 + 28 28 28 grey11 + 31 31 31 gray12 + 31 31 31 grey12 + 33 33 33 gray13 + 33 33 33 grey13 + 36 36 36 gray14 + 36 36 36 grey14 + 38 38 38 gray15 + 38 38 38 grey15 + 41 41 41 gray16 + 41 41 41 grey16 + 43 43 43 gray17 + 43 43 43 grey17 + 46 46 46 gray18 + 46 46 46 grey18 + 48 48 48 gray19 + 48 48 48 grey19 + 51 51 51 gray20 + 51 51 51 grey20 + 54 54 54 gray21 + 54 54 54 grey21 + 56 56 56 gray22 + 56 56 56 grey22 + 59 59 59 gray23 + 59 59 59 grey23 + 61 61 61 gray24 + 61 61 61 grey24 + 64 64 64 gray25 + 64 64 64 grey25 + 66 66 66 gray26 + 66 66 66 grey26 + 69 69 69 gray27 + 69 69 69 grey27 + 71 71 71 gray28 + 71 71 71 grey28 + 74 74 74 gray29 + 74 74 74 grey29 + 77 77 77 gray30 + 77 77 77 grey30 + 79 79 79 gray31 + 79 79 79 grey31 + 82 82 82 gray32 + 82 82 82 grey32 + 84 84 84 gray33 + 84 84 84 grey33 + 87 87 87 gray34 + 87 87 87 grey34 + 89 89 89 gray35 + 89 89 89 grey35 + 92 92 92 gray36 + 92 92 92 grey36 + 94 94 94 gray37 + 94 94 94 grey37 + 97 97 97 gray38 + 97 97 97 grey38 + 99 99 99 gray39 + 99 99 99 grey39 +102 102 102 gray40 +102 102 102 grey40 +105 105 105 gray41 +105 105 105 grey41 +107 107 107 gray42 +107 107 107 grey42 +110 110 110 gray43 +110 110 110 grey43 +112 112 112 gray44 +112 112 112 grey44 +115 115 115 gray45 +115 115 115 grey45 +117 117 117 gray46 +117 117 117 grey46 +120 120 120 gray47 +120 120 120 grey47 +122 122 122 gray48 +122 122 122 grey48 +125 125 125 gray49 +125 125 125 grey49 +127 127 127 gray50 +127 127 127 grey50 +130 130 130 gray51 +130 130 130 grey51 +133 133 133 gray52 +133 133 133 grey52 +135 135 135 gray53 +135 135 135 grey53 +138 138 138 gray54 +138 138 138 grey54 +140 140 140 gray55 +140 140 140 grey55 +143 143 143 gray56 +143 143 143 grey56 +145 145 145 gray57 +145 145 145 grey57 +148 148 148 gray58 +148 148 148 grey58 +150 150 150 gray59 +150 150 150 grey59 +153 153 153 gray60 +153 153 153 grey60 +156 156 156 gray61 +156 156 156 grey61 +158 158 158 gray62 +158 158 158 grey62 +161 161 161 gray63 +161 161 161 grey63 +163 163 163 gray64 +163 163 163 grey64 +166 166 166 gray65 +166 166 166 grey65 +168 168 168 gray66 +168 168 168 grey66 +171 171 171 gray67 +171 171 171 grey67 +173 173 173 gray68 +173 173 173 grey68 +176 176 176 gray69 +176 176 176 grey69 +179 179 179 gray70 +179 179 179 grey70 +181 181 181 gray71 +181 181 181 grey71 +184 184 184 gray72 +184 184 184 grey72 +186 186 186 gray73 +186 186 186 grey73 +189 189 189 gray74 +189 189 189 grey74 +191 191 191 gray75 +191 191 191 grey75 +194 194 194 gray76 +194 194 194 grey76 +196 196 196 gray77 +196 196 196 grey77 +199 199 199 gray78 +199 199 199 grey78 +201 201 201 gray79 +201 201 201 grey79 +204 204 204 gray80 +204 204 204 grey80 +207 207 207 gray81 +207 207 207 grey81 +209 209 209 gray82 +209 209 209 grey82 +212 212 212 gray83 +212 212 212 grey83 +214 214 214 gray84 +214 214 214 grey84 +217 217 217 gray85 +217 217 217 grey85 +219 219 219 gray86 +219 219 219 grey86 +222 222 222 gray87 +222 222 222 grey87 +224 224 224 gray88 +224 224 224 grey88 +227 227 227 gray89 +227 227 227 grey89 +229 229 229 gray90 +229 229 229 grey90 +232 232 232 gray91 +232 232 232 grey91 +235 235 235 gray92 +235 235 235 grey92 +237 237 237 gray93 +237 237 237 grey93 +240 240 240 gray94 +240 240 240 grey94 +242 242 242 gray95 +242 242 242 grey95 +245 245 245 gray96 +245 245 245 grey96 +247 247 247 gray97 +247 247 247 grey97 +250 250 250 gray98 +250 250 250 grey98 +252 252 252 gray99 +252 252 252 grey99 +255 255 255 gray100 +255 255 255 grey100 +169 169 169 dark grey +169 169 169 DarkGrey +169 169 169 dark gray +169 169 169 DarkGray +0 0 139 dark blue +0 0 139 DarkBlue +0 139 139 dark cyan +0 139 139 DarkCyan +139 0 139 dark magenta +139 0 139 DarkMagenta +139 0 0 dark red +139 0 0 DarkRed +144 238 144 light green +144 238 144 LightGreen diff --git a/adduser.conf b/adduser.conf new file mode 100644 index 00000000..d045994f --- /dev/null +++ b/adduser.conf @@ -0,0 +1,85 @@ +# /etc/adduser.conf: `adduser' configuration. +# See adduser(8) and adduser.conf(5) for full documentation. + +# The DSHELL variable specifies the default login shell on your +# system. +DSHELL=/bin/bash + +# The DHOME variable specifies the directory containing users' home +# directories. +DHOME=/home + +# If GROUPHOMES is "yes", then the home directories will be created as +# /home/groupname/user. +GROUPHOMES=no + +# If LETTERHOMES is "yes", then the created home directories will have +# an extra directory - the first letter of the user name. For example: +# /home/u/user. +LETTERHOMES=no + +# The SKEL variable specifies the directory containing "skeletal" user +# files; in other words, files such as a sample .profile that will be +# copied to the new user's home directory when it is created. +SKEL=/etc/skel + +# FIRST_SYSTEM_[GU]ID to LAST_SYSTEM_[GU]ID inclusive is the range for UIDs +# for dynamically allocated administrative and system accounts/groups. +# Please note that system software, such as the users allocated by the base-passwd +# package, may assume that UIDs less than 100 are unallocated. +FIRST_SYSTEM_UID=100 +LAST_SYSTEM_UID=999 + +FIRST_SYSTEM_GID=100 +LAST_SYSTEM_GID=999 + +# FIRST_[GU]ID to LAST_[GU]ID inclusive is the range of UIDs of dynamically +# allocated user accounts/groups. +FIRST_UID=1000 +LAST_UID=59999 + +FIRST_GID=1000 +LAST_GID=59999 + +# The USERGROUPS variable can be either "yes" or "no". If "yes" each +# created user will be given their own group to use as a default. If +# "no", each created user will be placed in the group whose gid is +# USERS_GID (see below). +USERGROUPS=yes + +# If USERGROUPS is "no", then USERS_GID should be the GID of the group +# `users' (or the equivalent group) on your system. +USERS_GID=100 + +# If DIR_MODE is set, directories will be created with the specified +# mode. Otherwise the default mode 0755 will be used. +DIR_MODE=0755 + +# If SETGID_HOME is "yes" home directories for users with their own +# group the setgid bit will be set. This was the default for +# versions << 3.13 of adduser. Because it has some bad side effects we +# no longer do this per default. If you want it nevertheless you can +# still set it here. +SETGID_HOME=no + +# If QUOTAUSER is set, a default quota will be set from that user with +# `edquota -p QUOTAUSER newuser' +QUOTAUSER="" + +# If SKEL_IGNORE_REGEX is set, adduser will ignore files matching this +# regular expression when creating a new home directory +SKEL_IGNORE_REGEX="dpkg-(old|new|dist|save)" + +# Set this if you want the --add_extra_groups option to adduser to add +# new users to other groups. +# This is the list of groups that new non-system users will be added to +# Default: +#EXTRA_GROUPS="dialout cdrom floppy audio video plugdev users" + +# If ADD_EXTRA_GROUPS is set to something non-zero, the EXTRA_GROUPS +# option above will be default behavior for adding new, non-system users +#ADD_EXTRA_GROUPS=1 + + +# check user and group names also against this regular expression. +#NAME_REGEX="^[a-z][-a-z0-9_]*\$" diff --git a/aliases b/aliases new file mode 100644 index 00000000..f12213f2 --- /dev/null +++ b/aliases @@ -0,0 +1,13 @@ +# /etc/aliases +mailer-daemon: postmaster +postmaster: root +nobody: root +hostmaster: root +usenet: root +news: root +webmaster: root +www: root +ftp: root +abuse: root +noc: root +security: root diff --git a/alternatives/ABORT.7.gz b/alternatives/ABORT.7.gz new file mode 120000 index 00000000..2886449b --- /dev/null +++ b/alternatives/ABORT.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ABORT.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_AGGREGATE.7.gz b/alternatives/ALTER_AGGREGATE.7.gz new file mode 120000 index 00000000..c1f67f2a --- /dev/null +++ b/alternatives/ALTER_AGGREGATE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_AGGREGATE.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_COLLATION.7.gz b/alternatives/ALTER_COLLATION.7.gz new file mode 120000 index 00000000..26bc8fc6 --- /dev/null +++ b/alternatives/ALTER_COLLATION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_COLLATION.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_CONVERSION.7.gz b/alternatives/ALTER_CONVERSION.7.gz new file mode 120000 index 00000000..f65b8994 --- /dev/null +++ b/alternatives/ALTER_CONVERSION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_CONVERSION.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_DATABASE.7.gz b/alternatives/ALTER_DATABASE.7.gz new file mode 120000 index 00000000..b0e4cef2 --- /dev/null +++ b/alternatives/ALTER_DATABASE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_DATABASE.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_DEFAULT_PRIVILEGES.7.gz b/alternatives/ALTER_DEFAULT_PRIVILEGES.7.gz new file mode 120000 index 00000000..4e4657bc --- /dev/null +++ b/alternatives/ALTER_DEFAULT_PRIVILEGES.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_DEFAULT_PRIVILEGES.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_DOMAIN.7.gz b/alternatives/ALTER_DOMAIN.7.gz new file mode 120000 index 00000000..8574a35a --- /dev/null +++ b/alternatives/ALTER_DOMAIN.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_DOMAIN.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_EVENT_TRIGGER.7.gz b/alternatives/ALTER_EVENT_TRIGGER.7.gz new file mode 120000 index 00000000..ffe7e624 --- /dev/null +++ b/alternatives/ALTER_EVENT_TRIGGER.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_EVENT_TRIGGER.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_EXTENSION.7.gz b/alternatives/ALTER_EXTENSION.7.gz new file mode 120000 index 00000000..8b78646b --- /dev/null +++ b/alternatives/ALTER_EXTENSION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_EXTENSION.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_FOREIGN_DATA_WRAPPER.7.gz b/alternatives/ALTER_FOREIGN_DATA_WRAPPER.7.gz new file mode 120000 index 00000000..74d74ea9 --- /dev/null +++ b/alternatives/ALTER_FOREIGN_DATA_WRAPPER.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_FOREIGN_DATA_WRAPPER.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_FOREIGN_TABLE.7.gz b/alternatives/ALTER_FOREIGN_TABLE.7.gz new file mode 120000 index 00000000..8e326ef3 --- /dev/null +++ b/alternatives/ALTER_FOREIGN_TABLE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_FOREIGN_TABLE.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_FUNCTION.7.gz b/alternatives/ALTER_FUNCTION.7.gz new file mode 120000 index 00000000..5350ae4e --- /dev/null +++ b/alternatives/ALTER_FUNCTION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_FUNCTION.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_GROUP.7.gz b/alternatives/ALTER_GROUP.7.gz new file mode 120000 index 00000000..fec54865 --- /dev/null +++ b/alternatives/ALTER_GROUP.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_GROUP.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_INDEX.7.gz b/alternatives/ALTER_INDEX.7.gz new file mode 120000 index 00000000..cd0863c2 --- /dev/null +++ b/alternatives/ALTER_INDEX.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_INDEX.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_LANGUAGE.7.gz b/alternatives/ALTER_LANGUAGE.7.gz new file mode 120000 index 00000000..5ecdda71 --- /dev/null +++ b/alternatives/ALTER_LANGUAGE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_LANGUAGE.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_LARGE_OBJECT.7.gz b/alternatives/ALTER_LARGE_OBJECT.7.gz new file mode 120000 index 00000000..1f6a6ba9 --- /dev/null +++ b/alternatives/ALTER_LARGE_OBJECT.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_LARGE_OBJECT.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_MATERIALIZED_VIEW.7.gz b/alternatives/ALTER_MATERIALIZED_VIEW.7.gz new file mode 120000 index 00000000..a2c19b66 --- /dev/null +++ b/alternatives/ALTER_MATERIALIZED_VIEW.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_MATERIALIZED_VIEW.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_OPERATOR.7.gz b/alternatives/ALTER_OPERATOR.7.gz new file mode 120000 index 00000000..2620f171 --- /dev/null +++ b/alternatives/ALTER_OPERATOR.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_OPERATOR.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_OPERATOR_CLASS.7.gz b/alternatives/ALTER_OPERATOR_CLASS.7.gz new file mode 120000 index 00000000..70b369e9 --- /dev/null +++ b/alternatives/ALTER_OPERATOR_CLASS.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_OPERATOR_CLASS.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_OPERATOR_FAMILY.7.gz b/alternatives/ALTER_OPERATOR_FAMILY.7.gz new file mode 120000 index 00000000..e96e135b --- /dev/null +++ b/alternatives/ALTER_OPERATOR_FAMILY.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_OPERATOR_FAMILY.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_POLICY.7.gz b/alternatives/ALTER_POLICY.7.gz new file mode 120000 index 00000000..62fd11e9 --- /dev/null +++ b/alternatives/ALTER_POLICY.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_POLICY.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_PROCEDURE.7.gz b/alternatives/ALTER_PROCEDURE.7.gz new file mode 120000 index 00000000..2780a2be --- /dev/null +++ b/alternatives/ALTER_PROCEDURE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_PROCEDURE.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_PUBLICATION.7.gz b/alternatives/ALTER_PUBLICATION.7.gz new file mode 120000 index 00000000..eceaa1b5 --- /dev/null +++ b/alternatives/ALTER_PUBLICATION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_PUBLICATION.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_ROLE.7.gz b/alternatives/ALTER_ROLE.7.gz new file mode 120000 index 00000000..4e5408fc --- /dev/null +++ b/alternatives/ALTER_ROLE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_ROLE.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_ROUTINE.7.gz b/alternatives/ALTER_ROUTINE.7.gz new file mode 120000 index 00000000..e22d2f2c --- /dev/null +++ b/alternatives/ALTER_ROUTINE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_ROUTINE.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_RULE.7.gz b/alternatives/ALTER_RULE.7.gz new file mode 120000 index 00000000..d86e376b --- /dev/null +++ b/alternatives/ALTER_RULE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_RULE.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_SCHEMA.7.gz b/alternatives/ALTER_SCHEMA.7.gz new file mode 120000 index 00000000..4707c603 --- /dev/null +++ b/alternatives/ALTER_SCHEMA.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_SCHEMA.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_SEQUENCE.7.gz b/alternatives/ALTER_SEQUENCE.7.gz new file mode 120000 index 00000000..22b22fde --- /dev/null +++ b/alternatives/ALTER_SEQUENCE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_SEQUENCE.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_SERVER.7.gz b/alternatives/ALTER_SERVER.7.gz new file mode 120000 index 00000000..335fb732 --- /dev/null +++ b/alternatives/ALTER_SERVER.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_SERVER.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_STATISTICS.7.gz b/alternatives/ALTER_STATISTICS.7.gz new file mode 120000 index 00000000..781e24ad --- /dev/null +++ b/alternatives/ALTER_STATISTICS.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_STATISTICS.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_SUBSCRIPTION.7.gz b/alternatives/ALTER_SUBSCRIPTION.7.gz new file mode 120000 index 00000000..e3b61853 --- /dev/null +++ b/alternatives/ALTER_SUBSCRIPTION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_SUBSCRIPTION.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_SYSTEM.7.gz b/alternatives/ALTER_SYSTEM.7.gz new file mode 120000 index 00000000..56f762cd --- /dev/null +++ b/alternatives/ALTER_SYSTEM.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_SYSTEM.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_TABLE.7.gz b/alternatives/ALTER_TABLE.7.gz new file mode 120000 index 00000000..92a36e67 --- /dev/null +++ b/alternatives/ALTER_TABLE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_TABLE.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_TABLESPACE.7.gz b/alternatives/ALTER_TABLESPACE.7.gz new file mode 120000 index 00000000..83f5f3ed --- /dev/null +++ b/alternatives/ALTER_TABLESPACE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_TABLESPACE.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_TEXT_SEARCH_CONFIGURATION.7.gz b/alternatives/ALTER_TEXT_SEARCH_CONFIGURATION.7.gz new file mode 120000 index 00000000..bfcf5247 --- /dev/null +++ b/alternatives/ALTER_TEXT_SEARCH_CONFIGURATION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_TEXT_SEARCH_CONFIGURATION.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_TEXT_SEARCH_DICTIONARY.7.gz b/alternatives/ALTER_TEXT_SEARCH_DICTIONARY.7.gz new file mode 120000 index 00000000..0ae226b7 --- /dev/null +++ b/alternatives/ALTER_TEXT_SEARCH_DICTIONARY.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_TEXT_SEARCH_DICTIONARY.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_TEXT_SEARCH_PARSER.7.gz b/alternatives/ALTER_TEXT_SEARCH_PARSER.7.gz new file mode 120000 index 00000000..8cebf122 --- /dev/null +++ b/alternatives/ALTER_TEXT_SEARCH_PARSER.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_TEXT_SEARCH_PARSER.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_TEXT_SEARCH_TEMPLATE.7.gz b/alternatives/ALTER_TEXT_SEARCH_TEMPLATE.7.gz new file mode 120000 index 00000000..a6854451 --- /dev/null +++ b/alternatives/ALTER_TEXT_SEARCH_TEMPLATE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_TEXT_SEARCH_TEMPLATE.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_TRIGGER.7.gz b/alternatives/ALTER_TRIGGER.7.gz new file mode 120000 index 00000000..9b75046b --- /dev/null +++ b/alternatives/ALTER_TRIGGER.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_TRIGGER.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_TYPE.7.gz b/alternatives/ALTER_TYPE.7.gz new file mode 120000 index 00000000..5225bddf --- /dev/null +++ b/alternatives/ALTER_TYPE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_TYPE.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_USER.7.gz b/alternatives/ALTER_USER.7.gz new file mode 120000 index 00000000..d18b7b2b --- /dev/null +++ b/alternatives/ALTER_USER.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_USER.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_USER_MAPPING.7.gz b/alternatives/ALTER_USER_MAPPING.7.gz new file mode 120000 index 00000000..e45b5c02 --- /dev/null +++ b/alternatives/ALTER_USER_MAPPING.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_USER_MAPPING.7.gz \ No newline at end of file diff --git a/alternatives/ALTER_VIEW.7.gz b/alternatives/ALTER_VIEW.7.gz new file mode 120000 index 00000000..1153777c --- /dev/null +++ b/alternatives/ALTER_VIEW.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ALTER_VIEW.7.gz \ No newline at end of file diff --git a/alternatives/ANALYZE.7.gz b/alternatives/ANALYZE.7.gz new file mode 120000 index 00000000..c67b0c79 --- /dev/null +++ b/alternatives/ANALYZE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ANALYZE.7.gz \ No newline at end of file diff --git a/alternatives/BEGIN.7.gz b/alternatives/BEGIN.7.gz new file mode 120000 index 00000000..dd616ffe --- /dev/null +++ b/alternatives/BEGIN.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/BEGIN.7.gz \ No newline at end of file diff --git a/alternatives/CALL.7.gz b/alternatives/CALL.7.gz new file mode 120000 index 00000000..64a55618 --- /dev/null +++ b/alternatives/CALL.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CALL.7.gz \ No newline at end of file diff --git a/alternatives/CHECKPOINT.7.gz b/alternatives/CHECKPOINT.7.gz new file mode 120000 index 00000000..b98eb9b1 --- /dev/null +++ b/alternatives/CHECKPOINT.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CHECKPOINT.7.gz \ No newline at end of file diff --git a/alternatives/CLOSE.7.gz b/alternatives/CLOSE.7.gz new file mode 120000 index 00000000..373f4933 --- /dev/null +++ b/alternatives/CLOSE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CLOSE.7.gz \ No newline at end of file diff --git a/alternatives/CLUSTER.7.gz b/alternatives/CLUSTER.7.gz new file mode 120000 index 00000000..c8fcb1ed --- /dev/null +++ b/alternatives/CLUSTER.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CLUSTER.7.gz \ No newline at end of file diff --git a/alternatives/COMMENT.7.gz b/alternatives/COMMENT.7.gz new file mode 120000 index 00000000..953cab11 --- /dev/null +++ b/alternatives/COMMENT.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/COMMENT.7.gz \ No newline at end of file diff --git a/alternatives/COMMIT.7.gz b/alternatives/COMMIT.7.gz new file mode 120000 index 00000000..b71bacb3 --- /dev/null +++ b/alternatives/COMMIT.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/COMMIT.7.gz \ No newline at end of file diff --git a/alternatives/COMMIT_PREPARED.7.gz b/alternatives/COMMIT_PREPARED.7.gz new file mode 120000 index 00000000..8d4cfb9d --- /dev/null +++ b/alternatives/COMMIT_PREPARED.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/COMMIT_PREPARED.7.gz \ No newline at end of file diff --git a/alternatives/COPY.7.gz b/alternatives/COPY.7.gz new file mode 120000 index 00000000..8e2833d9 --- /dev/null +++ b/alternatives/COPY.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/COPY.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_ACCESS_METHOD.7.gz b/alternatives/CREATE_ACCESS_METHOD.7.gz new file mode 120000 index 00000000..9d42cdb7 --- /dev/null +++ b/alternatives/CREATE_ACCESS_METHOD.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_ACCESS_METHOD.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_AGGREGATE.7.gz b/alternatives/CREATE_AGGREGATE.7.gz new file mode 120000 index 00000000..41e72e45 --- /dev/null +++ b/alternatives/CREATE_AGGREGATE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_AGGREGATE.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_CAST.7.gz b/alternatives/CREATE_CAST.7.gz new file mode 120000 index 00000000..4e67f60b --- /dev/null +++ b/alternatives/CREATE_CAST.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_CAST.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_COLLATION.7.gz b/alternatives/CREATE_COLLATION.7.gz new file mode 120000 index 00000000..cb9f0180 --- /dev/null +++ b/alternatives/CREATE_COLLATION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_COLLATION.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_CONVERSION.7.gz b/alternatives/CREATE_CONVERSION.7.gz new file mode 120000 index 00000000..b1e5a0be --- /dev/null +++ b/alternatives/CREATE_CONVERSION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_CONVERSION.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_DATABASE.7.gz b/alternatives/CREATE_DATABASE.7.gz new file mode 120000 index 00000000..05ef1213 --- /dev/null +++ b/alternatives/CREATE_DATABASE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_DATABASE.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_DOMAIN.7.gz b/alternatives/CREATE_DOMAIN.7.gz new file mode 120000 index 00000000..e985f852 --- /dev/null +++ b/alternatives/CREATE_DOMAIN.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_DOMAIN.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_EVENT_TRIGGER.7.gz b/alternatives/CREATE_EVENT_TRIGGER.7.gz new file mode 120000 index 00000000..4251776f --- /dev/null +++ b/alternatives/CREATE_EVENT_TRIGGER.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_EVENT_TRIGGER.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_EXTENSION.7.gz b/alternatives/CREATE_EXTENSION.7.gz new file mode 120000 index 00000000..0e97cb42 --- /dev/null +++ b/alternatives/CREATE_EXTENSION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_EXTENSION.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_FOREIGN_DATA_WRAPPER.7.gz b/alternatives/CREATE_FOREIGN_DATA_WRAPPER.7.gz new file mode 120000 index 00000000..ad66ff91 --- /dev/null +++ b/alternatives/CREATE_FOREIGN_DATA_WRAPPER.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_FOREIGN_DATA_WRAPPER.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_FOREIGN_TABLE.7.gz b/alternatives/CREATE_FOREIGN_TABLE.7.gz new file mode 120000 index 00000000..462a3b28 --- /dev/null +++ b/alternatives/CREATE_FOREIGN_TABLE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_FOREIGN_TABLE.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_FUNCTION.7.gz b/alternatives/CREATE_FUNCTION.7.gz new file mode 120000 index 00000000..9529633b --- /dev/null +++ b/alternatives/CREATE_FUNCTION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_FUNCTION.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_GROUP.7.gz b/alternatives/CREATE_GROUP.7.gz new file mode 120000 index 00000000..4674d971 --- /dev/null +++ b/alternatives/CREATE_GROUP.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_GROUP.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_INDEX.7.gz b/alternatives/CREATE_INDEX.7.gz new file mode 120000 index 00000000..50dd5563 --- /dev/null +++ b/alternatives/CREATE_INDEX.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_INDEX.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_LANGUAGE.7.gz b/alternatives/CREATE_LANGUAGE.7.gz new file mode 120000 index 00000000..6f0dc143 --- /dev/null +++ b/alternatives/CREATE_LANGUAGE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_LANGUAGE.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_MATERIALIZED_VIEW.7.gz b/alternatives/CREATE_MATERIALIZED_VIEW.7.gz new file mode 120000 index 00000000..6b7f564b --- /dev/null +++ b/alternatives/CREATE_MATERIALIZED_VIEW.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_MATERIALIZED_VIEW.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_OPERATOR.7.gz b/alternatives/CREATE_OPERATOR.7.gz new file mode 120000 index 00000000..1a70a46a --- /dev/null +++ b/alternatives/CREATE_OPERATOR.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_OPERATOR.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_OPERATOR_CLASS.7.gz b/alternatives/CREATE_OPERATOR_CLASS.7.gz new file mode 120000 index 00000000..cbffa81d --- /dev/null +++ b/alternatives/CREATE_OPERATOR_CLASS.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_OPERATOR_CLASS.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_OPERATOR_FAMILY.7.gz b/alternatives/CREATE_OPERATOR_FAMILY.7.gz new file mode 120000 index 00000000..d3d9a4bc --- /dev/null +++ b/alternatives/CREATE_OPERATOR_FAMILY.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_OPERATOR_FAMILY.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_POLICY.7.gz b/alternatives/CREATE_POLICY.7.gz new file mode 120000 index 00000000..9ecd9102 --- /dev/null +++ b/alternatives/CREATE_POLICY.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_POLICY.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_PROCEDURE.7.gz b/alternatives/CREATE_PROCEDURE.7.gz new file mode 120000 index 00000000..eee6d4ee --- /dev/null +++ b/alternatives/CREATE_PROCEDURE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_PROCEDURE.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_PUBLICATION.7.gz b/alternatives/CREATE_PUBLICATION.7.gz new file mode 120000 index 00000000..b853bf24 --- /dev/null +++ b/alternatives/CREATE_PUBLICATION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_PUBLICATION.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_ROLE.7.gz b/alternatives/CREATE_ROLE.7.gz new file mode 120000 index 00000000..79e3cd8e --- /dev/null +++ b/alternatives/CREATE_ROLE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_ROLE.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_RULE.7.gz b/alternatives/CREATE_RULE.7.gz new file mode 120000 index 00000000..c3c7ac74 --- /dev/null +++ b/alternatives/CREATE_RULE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_RULE.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_SCHEMA.7.gz b/alternatives/CREATE_SCHEMA.7.gz new file mode 120000 index 00000000..bfc6cb9a --- /dev/null +++ b/alternatives/CREATE_SCHEMA.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_SCHEMA.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_SEQUENCE.7.gz b/alternatives/CREATE_SEQUENCE.7.gz new file mode 120000 index 00000000..fa611715 --- /dev/null +++ b/alternatives/CREATE_SEQUENCE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_SEQUENCE.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_SERVER.7.gz b/alternatives/CREATE_SERVER.7.gz new file mode 120000 index 00000000..de6bf1ec --- /dev/null +++ b/alternatives/CREATE_SERVER.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_SERVER.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_STATISTICS.7.gz b/alternatives/CREATE_STATISTICS.7.gz new file mode 120000 index 00000000..f9de6c6f --- /dev/null +++ b/alternatives/CREATE_STATISTICS.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_STATISTICS.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_SUBSCRIPTION.7.gz b/alternatives/CREATE_SUBSCRIPTION.7.gz new file mode 120000 index 00000000..211898b8 --- /dev/null +++ b/alternatives/CREATE_SUBSCRIPTION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_SUBSCRIPTION.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_TABLE.7.gz b/alternatives/CREATE_TABLE.7.gz new file mode 120000 index 00000000..42b46a70 --- /dev/null +++ b/alternatives/CREATE_TABLE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_TABLE.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_TABLESPACE.7.gz b/alternatives/CREATE_TABLESPACE.7.gz new file mode 120000 index 00000000..9e0ee4a3 --- /dev/null +++ b/alternatives/CREATE_TABLESPACE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_TABLESPACE.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_TABLE_AS.7.gz b/alternatives/CREATE_TABLE_AS.7.gz new file mode 120000 index 00000000..1bd8ea7f --- /dev/null +++ b/alternatives/CREATE_TABLE_AS.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_TABLE_AS.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_TEXT_SEARCH_CONFIGURATION.7.gz b/alternatives/CREATE_TEXT_SEARCH_CONFIGURATION.7.gz new file mode 120000 index 00000000..6f7631fb --- /dev/null +++ b/alternatives/CREATE_TEXT_SEARCH_CONFIGURATION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_TEXT_SEARCH_CONFIGURATION.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_TEXT_SEARCH_DICTIONARY.7.gz b/alternatives/CREATE_TEXT_SEARCH_DICTIONARY.7.gz new file mode 120000 index 00000000..40aa1c30 --- /dev/null +++ b/alternatives/CREATE_TEXT_SEARCH_DICTIONARY.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_TEXT_SEARCH_DICTIONARY.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_TEXT_SEARCH_PARSER.7.gz b/alternatives/CREATE_TEXT_SEARCH_PARSER.7.gz new file mode 120000 index 00000000..171eff81 --- /dev/null +++ b/alternatives/CREATE_TEXT_SEARCH_PARSER.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_TEXT_SEARCH_PARSER.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_TEXT_SEARCH_TEMPLATE.7.gz b/alternatives/CREATE_TEXT_SEARCH_TEMPLATE.7.gz new file mode 120000 index 00000000..9708ce51 --- /dev/null +++ b/alternatives/CREATE_TEXT_SEARCH_TEMPLATE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_TEXT_SEARCH_TEMPLATE.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_TRANSFORM.7.gz b/alternatives/CREATE_TRANSFORM.7.gz new file mode 120000 index 00000000..1f5a4ebb --- /dev/null +++ b/alternatives/CREATE_TRANSFORM.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_TRANSFORM.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_TRIGGER.7.gz b/alternatives/CREATE_TRIGGER.7.gz new file mode 120000 index 00000000..cd4aba84 --- /dev/null +++ b/alternatives/CREATE_TRIGGER.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_TRIGGER.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_TYPE.7.gz b/alternatives/CREATE_TYPE.7.gz new file mode 120000 index 00000000..5137ec86 --- /dev/null +++ b/alternatives/CREATE_TYPE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_TYPE.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_USER.7.gz b/alternatives/CREATE_USER.7.gz new file mode 120000 index 00000000..c63eaa41 --- /dev/null +++ b/alternatives/CREATE_USER.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_USER.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_USER_MAPPING.7.gz b/alternatives/CREATE_USER_MAPPING.7.gz new file mode 120000 index 00000000..efc859de --- /dev/null +++ b/alternatives/CREATE_USER_MAPPING.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_USER_MAPPING.7.gz \ No newline at end of file diff --git a/alternatives/CREATE_VIEW.7.gz b/alternatives/CREATE_VIEW.7.gz new file mode 120000 index 00000000..0fc9caee --- /dev/null +++ b/alternatives/CREATE_VIEW.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/CREATE_VIEW.7.gz \ No newline at end of file diff --git a/alternatives/DEALLOCATE.7.gz b/alternatives/DEALLOCATE.7.gz new file mode 120000 index 00000000..8c39216a --- /dev/null +++ b/alternatives/DEALLOCATE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DEALLOCATE.7.gz \ No newline at end of file diff --git a/alternatives/DECLARE.7.gz b/alternatives/DECLARE.7.gz new file mode 120000 index 00000000..cacf675a --- /dev/null +++ b/alternatives/DECLARE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DECLARE.7.gz \ No newline at end of file diff --git a/alternatives/DELETE.7.gz b/alternatives/DELETE.7.gz new file mode 120000 index 00000000..ab359893 --- /dev/null +++ b/alternatives/DELETE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DELETE.7.gz \ No newline at end of file diff --git a/alternatives/DISCARD.7.gz b/alternatives/DISCARD.7.gz new file mode 120000 index 00000000..9d895438 --- /dev/null +++ b/alternatives/DISCARD.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DISCARD.7.gz \ No newline at end of file diff --git a/alternatives/DO.7.gz b/alternatives/DO.7.gz new file mode 120000 index 00000000..19ba3e85 --- /dev/null +++ b/alternatives/DO.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DO.7.gz \ No newline at end of file diff --git a/alternatives/DROP_ACCESS_METHOD.7.gz b/alternatives/DROP_ACCESS_METHOD.7.gz new file mode 120000 index 00000000..35a769f4 --- /dev/null +++ b/alternatives/DROP_ACCESS_METHOD.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_ACCESS_METHOD.7.gz \ No newline at end of file diff --git a/alternatives/DROP_AGGREGATE.7.gz b/alternatives/DROP_AGGREGATE.7.gz new file mode 120000 index 00000000..2654a793 --- /dev/null +++ b/alternatives/DROP_AGGREGATE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_AGGREGATE.7.gz \ No newline at end of file diff --git a/alternatives/DROP_CAST.7.gz b/alternatives/DROP_CAST.7.gz new file mode 120000 index 00000000..bab9850f --- /dev/null +++ b/alternatives/DROP_CAST.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_CAST.7.gz \ No newline at end of file diff --git a/alternatives/DROP_COLLATION.7.gz b/alternatives/DROP_COLLATION.7.gz new file mode 120000 index 00000000..ea44c00b --- /dev/null +++ b/alternatives/DROP_COLLATION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_COLLATION.7.gz \ No newline at end of file diff --git a/alternatives/DROP_CONVERSION.7.gz b/alternatives/DROP_CONVERSION.7.gz new file mode 120000 index 00000000..ca86eee9 --- /dev/null +++ b/alternatives/DROP_CONVERSION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_CONVERSION.7.gz \ No newline at end of file diff --git a/alternatives/DROP_DATABASE.7.gz b/alternatives/DROP_DATABASE.7.gz new file mode 120000 index 00000000..5bb27ad0 --- /dev/null +++ b/alternatives/DROP_DATABASE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_DATABASE.7.gz \ No newline at end of file diff --git a/alternatives/DROP_DOMAIN.7.gz b/alternatives/DROP_DOMAIN.7.gz new file mode 120000 index 00000000..9e03a949 --- /dev/null +++ b/alternatives/DROP_DOMAIN.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_DOMAIN.7.gz \ No newline at end of file diff --git a/alternatives/DROP_EVENT_TRIGGER.7.gz b/alternatives/DROP_EVENT_TRIGGER.7.gz new file mode 120000 index 00000000..79d3d38a --- /dev/null +++ b/alternatives/DROP_EVENT_TRIGGER.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_EVENT_TRIGGER.7.gz \ No newline at end of file diff --git a/alternatives/DROP_EXTENSION.7.gz b/alternatives/DROP_EXTENSION.7.gz new file mode 120000 index 00000000..c01f9d0a --- /dev/null +++ b/alternatives/DROP_EXTENSION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_EXTENSION.7.gz \ No newline at end of file diff --git a/alternatives/DROP_FOREIGN_DATA_WRAPPER.7.gz b/alternatives/DROP_FOREIGN_DATA_WRAPPER.7.gz new file mode 120000 index 00000000..90e5d883 --- /dev/null +++ b/alternatives/DROP_FOREIGN_DATA_WRAPPER.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_FOREIGN_DATA_WRAPPER.7.gz \ No newline at end of file diff --git a/alternatives/DROP_FOREIGN_TABLE.7.gz b/alternatives/DROP_FOREIGN_TABLE.7.gz new file mode 120000 index 00000000..1d2d3e14 --- /dev/null +++ b/alternatives/DROP_FOREIGN_TABLE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_FOREIGN_TABLE.7.gz \ No newline at end of file diff --git a/alternatives/DROP_FUNCTION.7.gz b/alternatives/DROP_FUNCTION.7.gz new file mode 120000 index 00000000..1552fb6b --- /dev/null +++ b/alternatives/DROP_FUNCTION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_FUNCTION.7.gz \ No newline at end of file diff --git a/alternatives/DROP_GROUP.7.gz b/alternatives/DROP_GROUP.7.gz new file mode 120000 index 00000000..f2abf9ff --- /dev/null +++ b/alternatives/DROP_GROUP.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_GROUP.7.gz \ No newline at end of file diff --git a/alternatives/DROP_INDEX.7.gz b/alternatives/DROP_INDEX.7.gz new file mode 120000 index 00000000..6aae909b --- /dev/null +++ b/alternatives/DROP_INDEX.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_INDEX.7.gz \ No newline at end of file diff --git a/alternatives/DROP_LANGUAGE.7.gz b/alternatives/DROP_LANGUAGE.7.gz new file mode 120000 index 00000000..20a672ed --- /dev/null +++ b/alternatives/DROP_LANGUAGE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_LANGUAGE.7.gz \ No newline at end of file diff --git a/alternatives/DROP_MATERIALIZED_VIEW.7.gz b/alternatives/DROP_MATERIALIZED_VIEW.7.gz new file mode 120000 index 00000000..cf38749f --- /dev/null +++ b/alternatives/DROP_MATERIALIZED_VIEW.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_MATERIALIZED_VIEW.7.gz \ No newline at end of file diff --git a/alternatives/DROP_OPERATOR.7.gz b/alternatives/DROP_OPERATOR.7.gz new file mode 120000 index 00000000..1ddc2cf2 --- /dev/null +++ b/alternatives/DROP_OPERATOR.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_OPERATOR.7.gz \ No newline at end of file diff --git a/alternatives/DROP_OPERATOR_CLASS.7.gz b/alternatives/DROP_OPERATOR_CLASS.7.gz new file mode 120000 index 00000000..b5470085 --- /dev/null +++ b/alternatives/DROP_OPERATOR_CLASS.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_OPERATOR_CLASS.7.gz \ No newline at end of file diff --git a/alternatives/DROP_OPERATOR_FAMILY.7.gz b/alternatives/DROP_OPERATOR_FAMILY.7.gz new file mode 120000 index 00000000..d0a921c0 --- /dev/null +++ b/alternatives/DROP_OPERATOR_FAMILY.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_OPERATOR_FAMILY.7.gz \ No newline at end of file diff --git a/alternatives/DROP_OWNED.7.gz b/alternatives/DROP_OWNED.7.gz new file mode 120000 index 00000000..199a3f3c --- /dev/null +++ b/alternatives/DROP_OWNED.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_OWNED.7.gz \ No newline at end of file diff --git a/alternatives/DROP_POLICY.7.gz b/alternatives/DROP_POLICY.7.gz new file mode 120000 index 00000000..863f5a29 --- /dev/null +++ b/alternatives/DROP_POLICY.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_POLICY.7.gz \ No newline at end of file diff --git a/alternatives/DROP_PROCEDURE.7.gz b/alternatives/DROP_PROCEDURE.7.gz new file mode 120000 index 00000000..eaed5005 --- /dev/null +++ b/alternatives/DROP_PROCEDURE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_PROCEDURE.7.gz \ No newline at end of file diff --git a/alternatives/DROP_PUBLICATION.7.gz b/alternatives/DROP_PUBLICATION.7.gz new file mode 120000 index 00000000..b6456a2c --- /dev/null +++ b/alternatives/DROP_PUBLICATION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_PUBLICATION.7.gz \ No newline at end of file diff --git a/alternatives/DROP_ROLE.7.gz b/alternatives/DROP_ROLE.7.gz new file mode 120000 index 00000000..39202ad4 --- /dev/null +++ b/alternatives/DROP_ROLE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_ROLE.7.gz \ No newline at end of file diff --git a/alternatives/DROP_ROUTINE.7.gz b/alternatives/DROP_ROUTINE.7.gz new file mode 120000 index 00000000..95eb2ff4 --- /dev/null +++ b/alternatives/DROP_ROUTINE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_ROUTINE.7.gz \ No newline at end of file diff --git a/alternatives/DROP_RULE.7.gz b/alternatives/DROP_RULE.7.gz new file mode 120000 index 00000000..31d2086c --- /dev/null +++ b/alternatives/DROP_RULE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_RULE.7.gz \ No newline at end of file diff --git a/alternatives/DROP_SCHEMA.7.gz b/alternatives/DROP_SCHEMA.7.gz new file mode 120000 index 00000000..05434518 --- /dev/null +++ b/alternatives/DROP_SCHEMA.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_SCHEMA.7.gz \ No newline at end of file diff --git a/alternatives/DROP_SEQUENCE.7.gz b/alternatives/DROP_SEQUENCE.7.gz new file mode 120000 index 00000000..de4182a4 --- /dev/null +++ b/alternatives/DROP_SEQUENCE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_SEQUENCE.7.gz \ No newline at end of file diff --git a/alternatives/DROP_SERVER.7.gz b/alternatives/DROP_SERVER.7.gz new file mode 120000 index 00000000..77867bbf --- /dev/null +++ b/alternatives/DROP_SERVER.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_SERVER.7.gz \ No newline at end of file diff --git a/alternatives/DROP_STATISTICS.7.gz b/alternatives/DROP_STATISTICS.7.gz new file mode 120000 index 00000000..7b453a5c --- /dev/null +++ b/alternatives/DROP_STATISTICS.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_STATISTICS.7.gz \ No newline at end of file diff --git a/alternatives/DROP_SUBSCRIPTION.7.gz b/alternatives/DROP_SUBSCRIPTION.7.gz new file mode 120000 index 00000000..1b97ead0 --- /dev/null +++ b/alternatives/DROP_SUBSCRIPTION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_SUBSCRIPTION.7.gz \ No newline at end of file diff --git a/alternatives/DROP_TABLE.7.gz b/alternatives/DROP_TABLE.7.gz new file mode 120000 index 00000000..eae131f2 --- /dev/null +++ b/alternatives/DROP_TABLE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_TABLE.7.gz \ No newline at end of file diff --git a/alternatives/DROP_TABLESPACE.7.gz b/alternatives/DROP_TABLESPACE.7.gz new file mode 120000 index 00000000..99ee88a2 --- /dev/null +++ b/alternatives/DROP_TABLESPACE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_TABLESPACE.7.gz \ No newline at end of file diff --git a/alternatives/DROP_TEXT_SEARCH_CONFIGURATION.7.gz b/alternatives/DROP_TEXT_SEARCH_CONFIGURATION.7.gz new file mode 120000 index 00000000..ddca1306 --- /dev/null +++ b/alternatives/DROP_TEXT_SEARCH_CONFIGURATION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_TEXT_SEARCH_CONFIGURATION.7.gz \ No newline at end of file diff --git a/alternatives/DROP_TEXT_SEARCH_DICTIONARY.7.gz b/alternatives/DROP_TEXT_SEARCH_DICTIONARY.7.gz new file mode 120000 index 00000000..c9939611 --- /dev/null +++ b/alternatives/DROP_TEXT_SEARCH_DICTIONARY.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_TEXT_SEARCH_DICTIONARY.7.gz \ No newline at end of file diff --git a/alternatives/DROP_TEXT_SEARCH_PARSER.7.gz b/alternatives/DROP_TEXT_SEARCH_PARSER.7.gz new file mode 120000 index 00000000..4db2be51 --- /dev/null +++ b/alternatives/DROP_TEXT_SEARCH_PARSER.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_TEXT_SEARCH_PARSER.7.gz \ No newline at end of file diff --git a/alternatives/DROP_TEXT_SEARCH_TEMPLATE.7.gz b/alternatives/DROP_TEXT_SEARCH_TEMPLATE.7.gz new file mode 120000 index 00000000..4e34a0fc --- /dev/null +++ b/alternatives/DROP_TEXT_SEARCH_TEMPLATE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_TEXT_SEARCH_TEMPLATE.7.gz \ No newline at end of file diff --git a/alternatives/DROP_TRANSFORM.7.gz b/alternatives/DROP_TRANSFORM.7.gz new file mode 120000 index 00000000..ee7cc844 --- /dev/null +++ b/alternatives/DROP_TRANSFORM.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_TRANSFORM.7.gz \ No newline at end of file diff --git a/alternatives/DROP_TRIGGER.7.gz b/alternatives/DROP_TRIGGER.7.gz new file mode 120000 index 00000000..1fcab303 --- /dev/null +++ b/alternatives/DROP_TRIGGER.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_TRIGGER.7.gz \ No newline at end of file diff --git a/alternatives/DROP_TYPE.7.gz b/alternatives/DROP_TYPE.7.gz new file mode 120000 index 00000000..5dbcd164 --- /dev/null +++ b/alternatives/DROP_TYPE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_TYPE.7.gz \ No newline at end of file diff --git a/alternatives/DROP_USER.7.gz b/alternatives/DROP_USER.7.gz new file mode 120000 index 00000000..466eaa1e --- /dev/null +++ b/alternatives/DROP_USER.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_USER.7.gz \ No newline at end of file diff --git a/alternatives/DROP_USER_MAPPING.7.gz b/alternatives/DROP_USER_MAPPING.7.gz new file mode 120000 index 00000000..eb70e2c9 --- /dev/null +++ b/alternatives/DROP_USER_MAPPING.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_USER_MAPPING.7.gz \ No newline at end of file diff --git a/alternatives/DROP_VIEW.7.gz b/alternatives/DROP_VIEW.7.gz new file mode 120000 index 00000000..04215f9b --- /dev/null +++ b/alternatives/DROP_VIEW.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/DROP_VIEW.7.gz \ No newline at end of file diff --git a/alternatives/END.7.gz b/alternatives/END.7.gz new file mode 120000 index 00000000..f71b8b8b --- /dev/null +++ b/alternatives/END.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/END.7.gz \ No newline at end of file diff --git a/alternatives/EXECUTE.7.gz b/alternatives/EXECUTE.7.gz new file mode 120000 index 00000000..15ff77bb --- /dev/null +++ b/alternatives/EXECUTE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/EXECUTE.7.gz \ No newline at end of file diff --git a/alternatives/EXPLAIN.7.gz b/alternatives/EXPLAIN.7.gz new file mode 120000 index 00000000..a22f79ba --- /dev/null +++ b/alternatives/EXPLAIN.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/EXPLAIN.7.gz \ No newline at end of file diff --git a/alternatives/FETCH.7.gz b/alternatives/FETCH.7.gz new file mode 120000 index 00000000..ec9bb2bc --- /dev/null +++ b/alternatives/FETCH.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/FETCH.7.gz \ No newline at end of file diff --git a/alternatives/GRANT.7.gz b/alternatives/GRANT.7.gz new file mode 120000 index 00000000..20df7a4c --- /dev/null +++ b/alternatives/GRANT.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/GRANT.7.gz \ No newline at end of file diff --git a/alternatives/IMPORT_FOREIGN_SCHEMA.7.gz b/alternatives/IMPORT_FOREIGN_SCHEMA.7.gz new file mode 120000 index 00000000..c53e03fd --- /dev/null +++ b/alternatives/IMPORT_FOREIGN_SCHEMA.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/IMPORT_FOREIGN_SCHEMA.7.gz \ No newline at end of file diff --git a/alternatives/INSERT.7.gz b/alternatives/INSERT.7.gz new file mode 120000 index 00000000..e1079aed --- /dev/null +++ b/alternatives/INSERT.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/INSERT.7.gz \ No newline at end of file diff --git a/alternatives/LISTEN.7.gz b/alternatives/LISTEN.7.gz new file mode 120000 index 00000000..8e150c03 --- /dev/null +++ b/alternatives/LISTEN.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/LISTEN.7.gz \ No newline at end of file diff --git a/alternatives/LOAD.7.gz b/alternatives/LOAD.7.gz new file mode 120000 index 00000000..cbfc5fb6 --- /dev/null +++ b/alternatives/LOAD.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/LOAD.7.gz \ No newline at end of file diff --git a/alternatives/LOCK.7.gz b/alternatives/LOCK.7.gz new file mode 120000 index 00000000..fc43b9fe --- /dev/null +++ b/alternatives/LOCK.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/LOCK.7.gz \ No newline at end of file diff --git a/alternatives/MOVE.7.gz b/alternatives/MOVE.7.gz new file mode 120000 index 00000000..888bb96f --- /dev/null +++ b/alternatives/MOVE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/MOVE.7.gz \ No newline at end of file diff --git a/alternatives/NOTIFY.7.gz b/alternatives/NOTIFY.7.gz new file mode 120000 index 00000000..00fb00a5 --- /dev/null +++ b/alternatives/NOTIFY.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/NOTIFY.7.gz \ No newline at end of file diff --git a/alternatives/PREPARE.7.gz b/alternatives/PREPARE.7.gz new file mode 120000 index 00000000..7be835e8 --- /dev/null +++ b/alternatives/PREPARE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/PREPARE.7.gz \ No newline at end of file diff --git a/alternatives/PREPARE_TRANSACTION.7.gz b/alternatives/PREPARE_TRANSACTION.7.gz new file mode 120000 index 00000000..c6844efc --- /dev/null +++ b/alternatives/PREPARE_TRANSACTION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/PREPARE_TRANSACTION.7.gz \ No newline at end of file diff --git a/alternatives/README b/alternatives/README new file mode 100644 index 00000000..4c4d2156 --- /dev/null +++ b/alternatives/README @@ -0,0 +1,2 @@ +Please read the update-alternatives(1) man page for information on this +directory and its contents. diff --git a/alternatives/REASSIGN_OWNED.7.gz b/alternatives/REASSIGN_OWNED.7.gz new file mode 120000 index 00000000..c43fd436 --- /dev/null +++ b/alternatives/REASSIGN_OWNED.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/REASSIGN_OWNED.7.gz \ No newline at end of file diff --git a/alternatives/REFRESH_MATERIALIZED_VIEW.7.gz b/alternatives/REFRESH_MATERIALIZED_VIEW.7.gz new file mode 120000 index 00000000..b66775d2 --- /dev/null +++ b/alternatives/REFRESH_MATERIALIZED_VIEW.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/REFRESH_MATERIALIZED_VIEW.7.gz \ No newline at end of file diff --git a/alternatives/REINDEX.7.gz b/alternatives/REINDEX.7.gz new file mode 120000 index 00000000..bc50b7cc --- /dev/null +++ b/alternatives/REINDEX.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/REINDEX.7.gz \ No newline at end of file diff --git a/alternatives/RELEASE_SAVEPOINT.7.gz b/alternatives/RELEASE_SAVEPOINT.7.gz new file mode 120000 index 00000000..62daede7 --- /dev/null +++ b/alternatives/RELEASE_SAVEPOINT.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/RELEASE_SAVEPOINT.7.gz \ No newline at end of file diff --git a/alternatives/RESET.7.gz b/alternatives/RESET.7.gz new file mode 120000 index 00000000..76f04f83 --- /dev/null +++ b/alternatives/RESET.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/RESET.7.gz \ No newline at end of file diff --git a/alternatives/REVOKE.7.gz b/alternatives/REVOKE.7.gz new file mode 120000 index 00000000..bb87ad96 --- /dev/null +++ b/alternatives/REVOKE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/REVOKE.7.gz \ No newline at end of file diff --git a/alternatives/ROLLBACK.7.gz b/alternatives/ROLLBACK.7.gz new file mode 120000 index 00000000..7edca551 --- /dev/null +++ b/alternatives/ROLLBACK.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ROLLBACK.7.gz \ No newline at end of file diff --git a/alternatives/ROLLBACK_PREPARED.7.gz b/alternatives/ROLLBACK_PREPARED.7.gz new file mode 120000 index 00000000..1e3c2fab --- /dev/null +++ b/alternatives/ROLLBACK_PREPARED.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ROLLBACK_PREPARED.7.gz \ No newline at end of file diff --git a/alternatives/ROLLBACK_TO_SAVEPOINT.7.gz b/alternatives/ROLLBACK_TO_SAVEPOINT.7.gz new file mode 120000 index 00000000..cdcf5af0 --- /dev/null +++ b/alternatives/ROLLBACK_TO_SAVEPOINT.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/ROLLBACK_TO_SAVEPOINT.7.gz \ No newline at end of file diff --git a/alternatives/SAVEPOINT.7.gz b/alternatives/SAVEPOINT.7.gz new file mode 120000 index 00000000..b2031b87 --- /dev/null +++ b/alternatives/SAVEPOINT.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/SAVEPOINT.7.gz \ No newline at end of file diff --git a/alternatives/SECURITY_LABEL.7.gz b/alternatives/SECURITY_LABEL.7.gz new file mode 120000 index 00000000..9af7100e --- /dev/null +++ b/alternatives/SECURITY_LABEL.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/SECURITY_LABEL.7.gz \ No newline at end of file diff --git a/alternatives/SELECT.7.gz b/alternatives/SELECT.7.gz new file mode 120000 index 00000000..6dd84865 --- /dev/null +++ b/alternatives/SELECT.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/SELECT.7.gz \ No newline at end of file diff --git a/alternatives/SELECT_INTO.7.gz b/alternatives/SELECT_INTO.7.gz new file mode 120000 index 00000000..0bb9c9aa --- /dev/null +++ b/alternatives/SELECT_INTO.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/SELECT_INTO.7.gz \ No newline at end of file diff --git a/alternatives/SET.7.gz b/alternatives/SET.7.gz new file mode 120000 index 00000000..0da3c0a9 --- /dev/null +++ b/alternatives/SET.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/SET.7.gz \ No newline at end of file diff --git a/alternatives/SET_CONSTRAINTS.7.gz b/alternatives/SET_CONSTRAINTS.7.gz new file mode 120000 index 00000000..a40b3d26 --- /dev/null +++ b/alternatives/SET_CONSTRAINTS.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/SET_CONSTRAINTS.7.gz \ No newline at end of file diff --git a/alternatives/SET_ROLE.7.gz b/alternatives/SET_ROLE.7.gz new file mode 120000 index 00000000..d739ddfa --- /dev/null +++ b/alternatives/SET_ROLE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/SET_ROLE.7.gz \ No newline at end of file diff --git a/alternatives/SET_SESSION_AUTHORIZATION.7.gz b/alternatives/SET_SESSION_AUTHORIZATION.7.gz new file mode 120000 index 00000000..bd20f5e9 --- /dev/null +++ b/alternatives/SET_SESSION_AUTHORIZATION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/SET_SESSION_AUTHORIZATION.7.gz \ No newline at end of file diff --git a/alternatives/SET_TRANSACTION.7.gz b/alternatives/SET_TRANSACTION.7.gz new file mode 120000 index 00000000..06ec4441 --- /dev/null +++ b/alternatives/SET_TRANSACTION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/SET_TRANSACTION.7.gz \ No newline at end of file diff --git a/alternatives/SHOW.7.gz b/alternatives/SHOW.7.gz new file mode 120000 index 00000000..2fab119a --- /dev/null +++ b/alternatives/SHOW.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/SHOW.7.gz \ No newline at end of file diff --git a/alternatives/START_TRANSACTION.7.gz b/alternatives/START_TRANSACTION.7.gz new file mode 120000 index 00000000..7d5cd26b --- /dev/null +++ b/alternatives/START_TRANSACTION.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/START_TRANSACTION.7.gz \ No newline at end of file diff --git a/alternatives/TABLE.7.gz b/alternatives/TABLE.7.gz new file mode 120000 index 00000000..80232572 --- /dev/null +++ b/alternatives/TABLE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/TABLE.7.gz \ No newline at end of file diff --git a/alternatives/TRUNCATE.7.gz b/alternatives/TRUNCATE.7.gz new file mode 120000 index 00000000..f4d90ff4 --- /dev/null +++ b/alternatives/TRUNCATE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/TRUNCATE.7.gz \ No newline at end of file diff --git a/alternatives/UNLISTEN.7.gz b/alternatives/UNLISTEN.7.gz new file mode 120000 index 00000000..f0e59abd --- /dev/null +++ b/alternatives/UNLISTEN.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/UNLISTEN.7.gz \ No newline at end of file diff --git a/alternatives/UPDATE.7.gz b/alternatives/UPDATE.7.gz new file mode 120000 index 00000000..eac2418d --- /dev/null +++ b/alternatives/UPDATE.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/UPDATE.7.gz \ No newline at end of file diff --git a/alternatives/VACUUM.7.gz b/alternatives/VACUUM.7.gz new file mode 120000 index 00000000..774dd2db --- /dev/null +++ b/alternatives/VACUUM.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/VACUUM.7.gz \ No newline at end of file diff --git a/alternatives/VALUES.7.gz b/alternatives/VALUES.7.gz new file mode 120000 index 00000000..d434d614 --- /dev/null +++ b/alternatives/VALUES.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/VALUES.7.gz \ No newline at end of file diff --git a/alternatives/WITH.7.gz b/alternatives/WITH.7.gz new file mode 120000 index 00000000..cfd6d520 --- /dev/null +++ b/alternatives/WITH.7.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man7/WITH.7.gz \ No newline at end of file diff --git a/alternatives/arptables b/alternatives/arptables new file mode 120000 index 00000000..f8fcc7ba --- /dev/null +++ b/alternatives/arptables @@ -0,0 +1 @@ +/usr/sbin/arptables-nft \ No newline at end of file diff --git a/alternatives/arptables-restore b/alternatives/arptables-restore new file mode 120000 index 00000000..95e87dc8 --- /dev/null +++ b/alternatives/arptables-restore @@ -0,0 +1 @@ +/usr/sbin/arptables-nft-restore \ No newline at end of file diff --git a/alternatives/arptables-save b/alternatives/arptables-save new file mode 120000 index 00000000..9bb15960 --- /dev/null +++ b/alternatives/arptables-save @@ -0,0 +1 @@ +/usr/sbin/arptables-nft-save \ No newline at end of file diff --git a/alternatives/awk b/alternatives/awk new file mode 120000 index 00000000..6190dcb8 --- /dev/null +++ b/alternatives/awk @@ -0,0 +1 @@ +/usr/bin/mawk \ No newline at end of file diff --git a/alternatives/awk.1.gz b/alternatives/awk.1.gz new file mode 120000 index 00000000..5d8f19b4 --- /dev/null +++ b/alternatives/awk.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/mawk.1.gz \ No newline at end of file diff --git a/alternatives/builtins.7.gz b/alternatives/builtins.7.gz new file mode 120000 index 00000000..96d1b740 --- /dev/null +++ b/alternatives/builtins.7.gz @@ -0,0 +1 @@ +/usr/share/man/man7/bash-builtins.7.gz \ No newline at end of file diff --git a/alternatives/c++ b/alternatives/c++ new file mode 120000 index 00000000..e51afadf --- /dev/null +++ b/alternatives/c++ @@ -0,0 +1 @@ +/usr/bin/g++ \ No newline at end of file diff --git a/alternatives/c89 b/alternatives/c89 new file mode 120000 index 00000000..9e67d743 --- /dev/null +++ b/alternatives/c89 @@ -0,0 +1 @@ +/usr/bin/c89-gcc \ No newline at end of file diff --git a/alternatives/c89.1.gz b/alternatives/c89.1.gz new file mode 120000 index 00000000..3a742380 --- /dev/null +++ b/alternatives/c89.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/c89-gcc.1.gz \ No newline at end of file diff --git a/alternatives/c99 b/alternatives/c99 new file mode 120000 index 00000000..323b6db2 --- /dev/null +++ b/alternatives/c99 @@ -0,0 +1 @@ +/usr/bin/c99-gcc \ No newline at end of file diff --git a/alternatives/c99.1.gz b/alternatives/c99.1.gz new file mode 120000 index 00000000..e033f2d4 --- /dev/null +++ b/alternatives/c99.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/c99-gcc.1.gz \ No newline at end of file diff --git a/alternatives/cc b/alternatives/cc new file mode 120000 index 00000000..cd91449a --- /dev/null +++ b/alternatives/cc @@ -0,0 +1 @@ +/usr/bin/gcc \ No newline at end of file diff --git a/alternatives/clusterdb.1.gz b/alternatives/clusterdb.1.gz new file mode 120000 index 00000000..27280fbd --- /dev/null +++ b/alternatives/clusterdb.1.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man1/clusterdb.1.gz \ No newline at end of file diff --git a/alternatives/cpp b/alternatives/cpp new file mode 120000 index 00000000..00fc3c4e --- /dev/null +++ b/alternatives/cpp @@ -0,0 +1 @@ +/usr/bin/cpp \ No newline at end of file diff --git a/alternatives/createdb.1.gz b/alternatives/createdb.1.gz new file mode 120000 index 00000000..09eebd44 --- /dev/null +++ b/alternatives/createdb.1.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man1/createdb.1.gz \ No newline at end of file diff --git a/alternatives/createuser.1.gz b/alternatives/createuser.1.gz new file mode 120000 index 00000000..ad4b75f1 --- /dev/null +++ b/alternatives/createuser.1.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man1/createuser.1.gz \ No newline at end of file diff --git a/alternatives/dhcpcd b/alternatives/dhcpcd new file mode 120000 index 00000000..981de745 --- /dev/null +++ b/alternatives/dhcpcd @@ -0,0 +1 @@ +/sbin/dhcpcd5 \ No newline at end of file diff --git a/alternatives/dhcpcd.8.gz b/alternatives/dhcpcd.8.gz new file mode 120000 index 00000000..e8ddb349 --- /dev/null +++ b/alternatives/dhcpcd.8.gz @@ -0,0 +1 @@ +/usr/share/man/man8/dhcpcd5.8.gz \ No newline at end of file diff --git a/alternatives/dotlock b/alternatives/dotlock new file mode 120000 index 00000000..423e8888 --- /dev/null +++ b/alternatives/dotlock @@ -0,0 +1 @@ +/usr/bin/dotlock.mailutils \ No newline at end of file diff --git a/alternatives/dotlock.1.gz b/alternatives/dotlock.1.gz new file mode 120000 index 00000000..48fb5955 --- /dev/null +++ b/alternatives/dotlock.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/dotlock.mailutils.1.gz \ No newline at end of file diff --git a/alternatives/dropdb.1.gz b/alternatives/dropdb.1.gz new file mode 120000 index 00000000..2599d1cb --- /dev/null +++ b/alternatives/dropdb.1.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man1/dropdb.1.gz \ No newline at end of file diff --git a/alternatives/dropuser.1.gz b/alternatives/dropuser.1.gz new file mode 120000 index 00000000..7011fac1 --- /dev/null +++ b/alternatives/dropuser.1.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man1/dropuser.1.gz \ No newline at end of file diff --git a/alternatives/ebtables b/alternatives/ebtables new file mode 120000 index 00000000..8d5f660c --- /dev/null +++ b/alternatives/ebtables @@ -0,0 +1 @@ +/usr/sbin/ebtables-nft \ No newline at end of file diff --git a/alternatives/ebtables-restore b/alternatives/ebtables-restore new file mode 120000 index 00000000..c2e5813b --- /dev/null +++ b/alternatives/ebtables-restore @@ -0,0 +1 @@ +/usr/sbin/ebtables-nft-restore \ No newline at end of file diff --git a/alternatives/ebtables-save b/alternatives/ebtables-save new file mode 120000 index 00000000..600f8c2d --- /dev/null +++ b/alternatives/ebtables-save @@ -0,0 +1 @@ +/usr/sbin/ebtables-nft-save \ No newline at end of file diff --git a/alternatives/editor b/alternatives/editor new file mode 120000 index 00000000..7a06612b --- /dev/null +++ b/alternatives/editor @@ -0,0 +1 @@ +/bin/nano \ No newline at end of file diff --git a/alternatives/editor.1.gz b/alternatives/editor.1.gz new file mode 120000 index 00000000..bb2d082c --- /dev/null +++ b/alternatives/editor.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/nano.1.gz \ No newline at end of file diff --git a/alternatives/ex b/alternatives/ex new file mode 120000 index 00000000..0d516727 --- /dev/null +++ b/alternatives/ex @@ -0,0 +1 @@ +/usr/bin/vim.tiny \ No newline at end of file diff --git a/alternatives/ex.1.gz b/alternatives/ex.1.gz new file mode 120000 index 00000000..e02a6af1 --- /dev/null +++ b/alternatives/ex.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/ex.da.1.gz b/alternatives/ex.da.1.gz new file mode 120000 index 00000000..c90068fa --- /dev/null +++ b/alternatives/ex.da.1.gz @@ -0,0 +1 @@ +/usr/share/man/da/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/ex.de.1.gz b/alternatives/ex.de.1.gz new file mode 120000 index 00000000..d89833a7 --- /dev/null +++ b/alternatives/ex.de.1.gz @@ -0,0 +1 @@ +/usr/share/man/de/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/ex.fr.1.gz b/alternatives/ex.fr.1.gz new file mode 120000 index 00000000..af52858f --- /dev/null +++ b/alternatives/ex.fr.1.gz @@ -0,0 +1 @@ +/usr/share/man/fr/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/ex.it.1.gz b/alternatives/ex.it.1.gz new file mode 120000 index 00000000..4498a3d4 --- /dev/null +++ b/alternatives/ex.it.1.gz @@ -0,0 +1 @@ +/usr/share/man/it/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/ex.ja.1.gz b/alternatives/ex.ja.1.gz new file mode 120000 index 00000000..071acfbb --- /dev/null +++ b/alternatives/ex.ja.1.gz @@ -0,0 +1 @@ +/usr/share/man/ja/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/ex.pl.1.gz b/alternatives/ex.pl.1.gz new file mode 120000 index 00000000..345590a8 --- /dev/null +++ b/alternatives/ex.pl.1.gz @@ -0,0 +1 @@ +/usr/share/man/pl/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/ex.ru.1.gz b/alternatives/ex.ru.1.gz new file mode 120000 index 00000000..ea9aa167 --- /dev/null +++ b/alternatives/ex.ru.1.gz @@ -0,0 +1 @@ +/usr/share/man/ru/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/faked.1.gz b/alternatives/faked.1.gz new file mode 120000 index 00000000..06829846 --- /dev/null +++ b/alternatives/faked.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/faked-sysv.1.gz \ No newline at end of file diff --git a/alternatives/faked.es.1.gz b/alternatives/faked.es.1.gz new file mode 120000 index 00000000..2a0233d4 --- /dev/null +++ b/alternatives/faked.es.1.gz @@ -0,0 +1 @@ +/usr/share/man/es/man1/faked-sysv.1.gz \ No newline at end of file diff --git a/alternatives/faked.fr.1.gz b/alternatives/faked.fr.1.gz new file mode 120000 index 00000000..9950991d --- /dev/null +++ b/alternatives/faked.fr.1.gz @@ -0,0 +1 @@ +/usr/share/man/fr/man1/faked-sysv.1.gz \ No newline at end of file diff --git a/alternatives/faked.sv.1.gz b/alternatives/faked.sv.1.gz new file mode 120000 index 00000000..7d76ada7 --- /dev/null +++ b/alternatives/faked.sv.1.gz @@ -0,0 +1 @@ +/usr/share/man/sv/man1/faked-sysv.1.gz \ No newline at end of file diff --git a/alternatives/fakeroot b/alternatives/fakeroot new file mode 120000 index 00000000..0b2f1ee9 --- /dev/null +++ b/alternatives/fakeroot @@ -0,0 +1 @@ +/usr/bin/fakeroot-sysv \ No newline at end of file diff --git a/alternatives/fakeroot.1.gz b/alternatives/fakeroot.1.gz new file mode 120000 index 00000000..6abf7c35 --- /dev/null +++ b/alternatives/fakeroot.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/fakeroot-sysv.1.gz \ No newline at end of file diff --git a/alternatives/fakeroot.es.1.gz b/alternatives/fakeroot.es.1.gz new file mode 120000 index 00000000..6c5981a0 --- /dev/null +++ b/alternatives/fakeroot.es.1.gz @@ -0,0 +1 @@ +/usr/share/man/es/man1/fakeroot-sysv.1.gz \ No newline at end of file diff --git a/alternatives/fakeroot.fr.1.gz b/alternatives/fakeroot.fr.1.gz new file mode 120000 index 00000000..ab31fe06 --- /dev/null +++ b/alternatives/fakeroot.fr.1.gz @@ -0,0 +1 @@ +/usr/share/man/fr/man1/fakeroot-sysv.1.gz \ No newline at end of file diff --git a/alternatives/fakeroot.sv.1.gz b/alternatives/fakeroot.sv.1.gz new file mode 120000 index 00000000..73d056ff --- /dev/null +++ b/alternatives/fakeroot.sv.1.gz @@ -0,0 +1 @@ +/usr/share/man/sv/man1/fakeroot-sysv.1.gz \ No newline at end of file diff --git a/alternatives/frm b/alternatives/frm new file mode 120000 index 00000000..def5353e --- /dev/null +++ b/alternatives/frm @@ -0,0 +1 @@ +/usr/bin/frm.mailutils \ No newline at end of file diff --git a/alternatives/frm.1.gz b/alternatives/frm.1.gz new file mode 120000 index 00000000..ec4c4915 --- /dev/null +++ b/alternatives/frm.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/frm.mailutils.1.gz \ No newline at end of file diff --git a/alternatives/from b/alternatives/from new file mode 120000 index 00000000..f4e6cdc4 --- /dev/null +++ b/alternatives/from @@ -0,0 +1 @@ +/usr/bin/from.mailutils \ No newline at end of file diff --git a/alternatives/from.1.gz b/alternatives/from.1.gz new file mode 120000 index 00000000..d20001af --- /dev/null +++ b/alternatives/from.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/from.mailutils.1.gz \ No newline at end of file diff --git a/alternatives/idmap-plugin b/alternatives/idmap-plugin new file mode 120000 index 00000000..5de0ea24 --- /dev/null +++ b/alternatives/idmap-plugin @@ -0,0 +1 @@ +/usr/lib/arm-linux-gnueabihf/cifs-utils/idmapwb.so \ No newline at end of file diff --git a/alternatives/idmap-plugin.8.gz b/alternatives/idmap-plugin.8.gz new file mode 120000 index 00000000..dbcb2e6d --- /dev/null +++ b/alternatives/idmap-plugin.8.gz @@ -0,0 +1 @@ +/usr/share/man/man8/idmapwb.8.gz \ No newline at end of file diff --git a/alternatives/infobrowser b/alternatives/infobrowser new file mode 120000 index 00000000..2404fe4b --- /dev/null +++ b/alternatives/infobrowser @@ -0,0 +1 @@ +/usr/bin/info \ No newline at end of file diff --git a/alternatives/infobrowser.1.gz b/alternatives/infobrowser.1.gz new file mode 120000 index 00000000..7152786e --- /dev/null +++ b/alternatives/infobrowser.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/info.1.gz \ No newline at end of file diff --git a/alternatives/ip6tables b/alternatives/ip6tables new file mode 120000 index 00000000..4c913e2d --- /dev/null +++ b/alternatives/ip6tables @@ -0,0 +1 @@ +/usr/sbin/ip6tables-nft \ No newline at end of file diff --git a/alternatives/ip6tables-restore b/alternatives/ip6tables-restore new file mode 120000 index 00000000..46918a9c --- /dev/null +++ b/alternatives/ip6tables-restore @@ -0,0 +1 @@ +/usr/sbin/ip6tables-nft-restore \ No newline at end of file diff --git a/alternatives/ip6tables-save b/alternatives/ip6tables-save new file mode 120000 index 00000000..04525f05 --- /dev/null +++ b/alternatives/ip6tables-save @@ -0,0 +1 @@ +/usr/sbin/ip6tables-nft-save \ No newline at end of file diff --git a/alternatives/iptables b/alternatives/iptables new file mode 120000 index 00000000..c55fd508 --- /dev/null +++ b/alternatives/iptables @@ -0,0 +1 @@ +/usr/sbin/iptables-nft \ No newline at end of file diff --git a/alternatives/iptables-restore b/alternatives/iptables-restore new file mode 120000 index 00000000..9553657e --- /dev/null +++ b/alternatives/iptables-restore @@ -0,0 +1 @@ +/usr/sbin/iptables-nft-restore \ No newline at end of file diff --git a/alternatives/iptables-save b/alternatives/iptables-save new file mode 120000 index 00000000..051d68bd --- /dev/null +++ b/alternatives/iptables-save @@ -0,0 +1 @@ +/usr/sbin/iptables-nft-save \ No newline at end of file diff --git a/alternatives/java b/alternatives/java new file mode 120000 index 00000000..0c7fa34d --- /dev/null +++ b/alternatives/java @@ -0,0 +1 @@ +/usr/lib/jvm/java-11-openjdk-armhf/bin/java \ No newline at end of file diff --git a/alternatives/java.1.gz b/alternatives/java.1.gz new file mode 120000 index 00000000..887eb408 --- /dev/null +++ b/alternatives/java.1.gz @@ -0,0 +1 @@ +/usr/lib/jvm/java-11-openjdk-armhf/man/man1/java.1.gz \ No newline at end of file diff --git a/alternatives/jexec b/alternatives/jexec new file mode 120000 index 00000000..4a96b6ec --- /dev/null +++ b/alternatives/jexec @@ -0,0 +1 @@ +/usr/lib/jvm/java-11-openjdk-armhf/lib/jexec \ No newline at end of file diff --git a/alternatives/jexec-binfmt b/alternatives/jexec-binfmt new file mode 120000 index 00000000..10d7b4b7 --- /dev/null +++ b/alternatives/jexec-binfmt @@ -0,0 +1 @@ +/usr/lib/jvm/java-11-openjdk-armhf/lib/jar.binfmt \ No newline at end of file diff --git a/alternatives/jjs b/alternatives/jjs new file mode 120000 index 00000000..18e086cb --- /dev/null +++ b/alternatives/jjs @@ -0,0 +1 @@ +/usr/lib/jvm/java-11-openjdk-armhf/bin/jjs \ No newline at end of file diff --git a/alternatives/jjs.1.gz b/alternatives/jjs.1.gz new file mode 120000 index 00000000..214150f7 --- /dev/null +++ b/alternatives/jjs.1.gz @@ -0,0 +1 @@ +/usr/lib/jvm/java-11-openjdk-armhf/man/man1/jjs.1.gz \ No newline at end of file diff --git a/alternatives/keytool b/alternatives/keytool new file mode 120000 index 00000000..e8b6310b --- /dev/null +++ b/alternatives/keytool @@ -0,0 +1 @@ +/usr/lib/jvm/java-11-openjdk-armhf/bin/keytool \ No newline at end of file diff --git a/alternatives/keytool.1.gz b/alternatives/keytool.1.gz new file mode 120000 index 00000000..4348e906 --- /dev/null +++ b/alternatives/keytool.1.gz @@ -0,0 +1 @@ +/usr/lib/jvm/java-11-openjdk-armhf/man/man1/keytool.1.gz \ No newline at end of file diff --git a/alternatives/lft b/alternatives/lft new file mode 120000 index 00000000..cbc60061 --- /dev/null +++ b/alternatives/lft @@ -0,0 +1 @@ +/usr/bin/lft.db \ No newline at end of file diff --git a/alternatives/lft.1.gz b/alternatives/lft.1.gz new file mode 120000 index 00000000..c1cf08c3 --- /dev/null +++ b/alternatives/lft.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/lft.db.1.gz \ No newline at end of file diff --git a/alternatives/lua-compiler b/alternatives/lua-compiler new file mode 120000 index 00000000..c96d33b4 --- /dev/null +++ b/alternatives/lua-compiler @@ -0,0 +1 @@ +/usr/bin/luac5.1 \ No newline at end of file diff --git a/alternatives/lua-compiler-manual b/alternatives/lua-compiler-manual new file mode 120000 index 00000000..5b70ec9f --- /dev/null +++ b/alternatives/lua-compiler-manual @@ -0,0 +1 @@ +/usr/share/man/man1/luac5.1.1.gz \ No newline at end of file diff --git a/alternatives/lua-interpreter b/alternatives/lua-interpreter new file mode 120000 index 00000000..7b2ed890 --- /dev/null +++ b/alternatives/lua-interpreter @@ -0,0 +1 @@ +/usr/bin/lua5.1 \ No newline at end of file diff --git a/alternatives/lua-manual b/alternatives/lua-manual new file mode 120000 index 00000000..3779d1ba --- /dev/null +++ b/alternatives/lua-manual @@ -0,0 +1 @@ +/usr/share/man/man1/lua5.1.1.gz \ No newline at end of file diff --git a/alternatives/lzcat b/alternatives/lzcat new file mode 120000 index 00000000..1482e0d3 --- /dev/null +++ b/alternatives/lzcat @@ -0,0 +1 @@ +/usr/bin/xzcat \ No newline at end of file diff --git a/alternatives/lzcat.1.gz b/alternatives/lzcat.1.gz new file mode 120000 index 00000000..c0785451 --- /dev/null +++ b/alternatives/lzcat.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/xzcat.1.gz \ No newline at end of file diff --git a/alternatives/lzcmp b/alternatives/lzcmp new file mode 120000 index 00000000..5cdef995 --- /dev/null +++ b/alternatives/lzcmp @@ -0,0 +1 @@ +/usr/bin/xzcmp \ No newline at end of file diff --git a/alternatives/lzcmp.1.gz b/alternatives/lzcmp.1.gz new file mode 120000 index 00000000..f0bafbe6 --- /dev/null +++ b/alternatives/lzcmp.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/xzcmp.1.gz \ No newline at end of file diff --git a/alternatives/lzdiff b/alternatives/lzdiff new file mode 120000 index 00000000..0e429214 --- /dev/null +++ b/alternatives/lzdiff @@ -0,0 +1 @@ +/usr/bin/xzdiff \ No newline at end of file diff --git a/alternatives/lzdiff.1.gz b/alternatives/lzdiff.1.gz new file mode 120000 index 00000000..5687b0a0 --- /dev/null +++ b/alternatives/lzdiff.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/xzdiff.1.gz \ No newline at end of file diff --git a/alternatives/lzegrep b/alternatives/lzegrep new file mode 120000 index 00000000..5fee0249 --- /dev/null +++ b/alternatives/lzegrep @@ -0,0 +1 @@ +/usr/bin/xzegrep \ No newline at end of file diff --git a/alternatives/lzegrep.1.gz b/alternatives/lzegrep.1.gz new file mode 120000 index 00000000..c9ad6de9 --- /dev/null +++ b/alternatives/lzegrep.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/xzegrep.1.gz \ No newline at end of file diff --git a/alternatives/lzfgrep b/alternatives/lzfgrep new file mode 120000 index 00000000..1b64c1bc --- /dev/null +++ b/alternatives/lzfgrep @@ -0,0 +1 @@ +/usr/bin/xzfgrep \ No newline at end of file diff --git a/alternatives/lzfgrep.1.gz b/alternatives/lzfgrep.1.gz new file mode 120000 index 00000000..b292ba91 --- /dev/null +++ b/alternatives/lzfgrep.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/xzfgrep.1.gz \ No newline at end of file diff --git a/alternatives/lzgrep b/alternatives/lzgrep new file mode 120000 index 00000000..05ef59bb --- /dev/null +++ b/alternatives/lzgrep @@ -0,0 +1 @@ +/usr/bin/xzgrep \ No newline at end of file diff --git a/alternatives/lzgrep.1.gz b/alternatives/lzgrep.1.gz new file mode 120000 index 00000000..8ccd2c57 --- /dev/null +++ b/alternatives/lzgrep.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/xzgrep.1.gz \ No newline at end of file diff --git a/alternatives/lzless b/alternatives/lzless new file mode 120000 index 00000000..54157364 --- /dev/null +++ b/alternatives/lzless @@ -0,0 +1 @@ +/usr/bin/xzless \ No newline at end of file diff --git a/alternatives/lzless.1.gz b/alternatives/lzless.1.gz new file mode 120000 index 00000000..bc81750d --- /dev/null +++ b/alternatives/lzless.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/xzless.1.gz \ No newline at end of file diff --git a/alternatives/lzma b/alternatives/lzma new file mode 120000 index 00000000..cdc9bb5f --- /dev/null +++ b/alternatives/lzma @@ -0,0 +1 @@ +/usr/bin/xz \ No newline at end of file diff --git a/alternatives/lzma.1.gz b/alternatives/lzma.1.gz new file mode 120000 index 00000000..16e4bccf --- /dev/null +++ b/alternatives/lzma.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/xz.1.gz \ No newline at end of file diff --git a/alternatives/lzmore b/alternatives/lzmore new file mode 120000 index 00000000..1fad3616 --- /dev/null +++ b/alternatives/lzmore @@ -0,0 +1 @@ +/usr/bin/xzmore \ No newline at end of file diff --git a/alternatives/lzmore.1.gz b/alternatives/lzmore.1.gz new file mode 120000 index 00000000..e79dfa46 --- /dev/null +++ b/alternatives/lzmore.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/xzmore.1.gz \ No newline at end of file diff --git a/alternatives/mail b/alternatives/mail new file mode 120000 index 00000000..e4c76436 --- /dev/null +++ b/alternatives/mail @@ -0,0 +1 @@ +/usr/bin/mail.mailutils \ No newline at end of file diff --git a/alternatives/mail.1.gz b/alternatives/mail.1.gz new file mode 120000 index 00000000..b8055c83 --- /dev/null +++ b/alternatives/mail.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/mail.mailutils.1.gz \ No newline at end of file diff --git a/alternatives/mailx b/alternatives/mailx new file mode 120000 index 00000000..e4c76436 --- /dev/null +++ b/alternatives/mailx @@ -0,0 +1 @@ +/usr/bin/mail.mailutils \ No newline at end of file diff --git a/alternatives/mailx.1.gz b/alternatives/mailx.1.gz new file mode 120000 index 00000000..b8055c83 --- /dev/null +++ b/alternatives/mailx.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/mail.mailutils.1.gz \ No newline at end of file diff --git a/alternatives/messages b/alternatives/messages new file mode 120000 index 00000000..e66edd38 --- /dev/null +++ b/alternatives/messages @@ -0,0 +1 @@ +/usr/bin/messages.mailutils \ No newline at end of file diff --git a/alternatives/messages.1.gz b/alternatives/messages.1.gz new file mode 120000 index 00000000..88847607 --- /dev/null +++ b/alternatives/messages.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/messages.mailutils.1.gz \ No newline at end of file diff --git a/alternatives/movemail b/alternatives/movemail new file mode 120000 index 00000000..8d4efb3f --- /dev/null +++ b/alternatives/movemail @@ -0,0 +1 @@ +/usr/bin/movemail.mailutils \ No newline at end of file diff --git a/alternatives/movemail.1.gz b/alternatives/movemail.1.gz new file mode 120000 index 00000000..32b35202 --- /dev/null +++ b/alternatives/movemail.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/movemail.mailutils.1.gz \ No newline at end of file diff --git a/alternatives/mt b/alternatives/mt new file mode 120000 index 00000000..46c25966 --- /dev/null +++ b/alternatives/mt @@ -0,0 +1 @@ +/bin/mt-gnu \ No newline at end of file diff --git a/alternatives/mt.1.gz b/alternatives/mt.1.gz new file mode 120000 index 00000000..cac0e182 --- /dev/null +++ b/alternatives/mt.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/mt-gnu.1.gz \ No newline at end of file diff --git a/alternatives/my.cnf b/alternatives/my.cnf new file mode 120000 index 00000000..c0fe3dd7 --- /dev/null +++ b/alternatives/my.cnf @@ -0,0 +1 @@ +/etc/mysql/mariadb.cnf \ No newline at end of file diff --git a/alternatives/nawk b/alternatives/nawk new file mode 120000 index 00000000..6190dcb8 --- /dev/null +++ b/alternatives/nawk @@ -0,0 +1 @@ +/usr/bin/mawk \ No newline at end of file diff --git a/alternatives/nawk.1.gz b/alternatives/nawk.1.gz new file mode 120000 index 00000000..5d8f19b4 --- /dev/null +++ b/alternatives/nawk.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/mawk.1.gz \ No newline at end of file diff --git a/alternatives/nc b/alternatives/nc new file mode 120000 index 00000000..42844ed5 --- /dev/null +++ b/alternatives/nc @@ -0,0 +1 @@ +/bin/nc.openbsd \ No newline at end of file diff --git a/alternatives/nc.1.gz b/alternatives/nc.1.gz new file mode 120000 index 00000000..e288d80e --- /dev/null +++ b/alternatives/nc.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/nc_openbsd.1.gz \ No newline at end of file diff --git a/alternatives/netcat b/alternatives/netcat new file mode 120000 index 00000000..42844ed5 --- /dev/null +++ b/alternatives/netcat @@ -0,0 +1 @@ +/bin/nc.openbsd \ No newline at end of file diff --git a/alternatives/netcat.1.gz b/alternatives/netcat.1.gz new file mode 120000 index 00000000..e288d80e --- /dev/null +++ b/alternatives/netcat.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/nc_openbsd.1.gz \ No newline at end of file diff --git a/alternatives/nodejs b/alternatives/nodejs new file mode 120000 index 00000000..194c4b8d --- /dev/null +++ b/alternatives/nodejs @@ -0,0 +1 @@ +/usr/bin/node \ No newline at end of file diff --git a/alternatives/nodejs.1.gz b/alternatives/nodejs.1.gz new file mode 120000 index 00000000..d93c1e96 --- /dev/null +++ b/alternatives/nodejs.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/node.1.gz \ No newline at end of file diff --git a/alternatives/pack200 b/alternatives/pack200 new file mode 120000 index 00000000..2a8b0dac --- /dev/null +++ b/alternatives/pack200 @@ -0,0 +1 @@ +/usr/lib/jvm/java-11-openjdk-armhf/bin/pack200 \ No newline at end of file diff --git a/alternatives/pack200.1.gz b/alternatives/pack200.1.gz new file mode 120000 index 00000000..dea6db36 --- /dev/null +++ b/alternatives/pack200.1.gz @@ -0,0 +1 @@ +/usr/lib/jvm/java-11-openjdk-armhf/man/man1/pack200.1.gz \ No newline at end of file diff --git a/alternatives/pager b/alternatives/pager new file mode 120000 index 00000000..cbce297b --- /dev/null +++ b/alternatives/pager @@ -0,0 +1 @@ +/bin/less \ No newline at end of file diff --git a/alternatives/pager.1.gz b/alternatives/pager.1.gz new file mode 120000 index 00000000..c1430af1 --- /dev/null +++ b/alternatives/pager.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/less.1.gz \ No newline at end of file diff --git a/alternatives/pg_basebackup.1.gz b/alternatives/pg_basebackup.1.gz new file mode 120000 index 00000000..0f040ae3 --- /dev/null +++ b/alternatives/pg_basebackup.1.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man1/pg_basebackup.1.gz \ No newline at end of file diff --git a/alternatives/pg_dump.1.gz b/alternatives/pg_dump.1.gz new file mode 120000 index 00000000..41c9bcbc --- /dev/null +++ b/alternatives/pg_dump.1.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man1/pg_dump.1.gz \ No newline at end of file diff --git a/alternatives/pg_dumpall.1.gz b/alternatives/pg_dumpall.1.gz new file mode 120000 index 00000000..db4db6bb --- /dev/null +++ b/alternatives/pg_dumpall.1.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man1/pg_dumpall.1.gz \ No newline at end of file diff --git a/alternatives/pg_isready.1.gz b/alternatives/pg_isready.1.gz new file mode 120000 index 00000000..9df68ae4 --- /dev/null +++ b/alternatives/pg_isready.1.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man1/pg_isready.1.gz \ No newline at end of file diff --git a/alternatives/pg_receivewal.1.gz b/alternatives/pg_receivewal.1.gz new file mode 120000 index 00000000..64fe49cc --- /dev/null +++ b/alternatives/pg_receivewal.1.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man1/pg_receivewal.1.gz \ No newline at end of file diff --git a/alternatives/pg_recvlogical.1.gz b/alternatives/pg_recvlogical.1.gz new file mode 120000 index 00000000..bd554556 --- /dev/null +++ b/alternatives/pg_recvlogical.1.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man1/pg_recvlogical.1.gz \ No newline at end of file diff --git a/alternatives/pg_restore.1.gz b/alternatives/pg_restore.1.gz new file mode 120000 index 00000000..a300ac47 --- /dev/null +++ b/alternatives/pg_restore.1.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man1/pg_restore.1.gz \ No newline at end of file diff --git a/alternatives/phar b/alternatives/phar new file mode 120000 index 00000000..b3b4ae71 --- /dev/null +++ b/alternatives/phar @@ -0,0 +1 @@ +/usr/bin/phar7.3 \ No newline at end of file diff --git a/alternatives/phar.1.gz b/alternatives/phar.1.gz new file mode 120000 index 00000000..f308505e --- /dev/null +++ b/alternatives/phar.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/phar7.3.1.gz \ No newline at end of file diff --git a/alternatives/phar.phar b/alternatives/phar.phar new file mode 120000 index 00000000..a03cf84f --- /dev/null +++ b/alternatives/phar.phar @@ -0,0 +1 @@ +/usr/bin/phar.phar7.3 \ No newline at end of file diff --git a/alternatives/phar.phar.1.gz b/alternatives/phar.phar.1.gz new file mode 120000 index 00000000..74ee7f36 --- /dev/null +++ b/alternatives/phar.phar.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/phar.phar7.3.1.gz \ No newline at end of file diff --git a/alternatives/php b/alternatives/php new file mode 120000 index 00000000..c890124a --- /dev/null +++ b/alternatives/php @@ -0,0 +1 @@ +/usr/bin/php7.3 \ No newline at end of file diff --git a/alternatives/php-cgi b/alternatives/php-cgi new file mode 120000 index 00000000..c483401e --- /dev/null +++ b/alternatives/php-cgi @@ -0,0 +1 @@ +/usr/bin/php-cgi7.3 \ No newline at end of file diff --git a/alternatives/php-cgi-bin b/alternatives/php-cgi-bin new file mode 120000 index 00000000..f945cd5b --- /dev/null +++ b/alternatives/php-cgi-bin @@ -0,0 +1 @@ +/usr/lib/cgi-bin/php7.3 \ No newline at end of file diff --git a/alternatives/php-cgi.1.gz b/alternatives/php-cgi.1.gz new file mode 120000 index 00000000..6b146712 --- /dev/null +++ b/alternatives/php-cgi.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/php-cgi7.3.1.gz \ No newline at end of file diff --git a/alternatives/php.1.gz b/alternatives/php.1.gz new file mode 120000 index 00000000..4338797d --- /dev/null +++ b/alternatives/php.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/php7.3.1.gz \ No newline at end of file diff --git a/alternatives/pico b/alternatives/pico new file mode 120000 index 00000000..7a06612b --- /dev/null +++ b/alternatives/pico @@ -0,0 +1 @@ +/bin/nano \ No newline at end of file diff --git a/alternatives/pico.1.gz b/alternatives/pico.1.gz new file mode 120000 index 00000000..bb2d082c --- /dev/null +++ b/alternatives/pico.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/nano.1.gz \ No newline at end of file diff --git a/alternatives/pinentry b/alternatives/pinentry new file mode 120000 index 00000000..01990a3f --- /dev/null +++ b/alternatives/pinentry @@ -0,0 +1 @@ +/usr/bin/pinentry-curses \ No newline at end of file diff --git a/alternatives/pinentry.1.gz b/alternatives/pinentry.1.gz new file mode 120000 index 00000000..8e9ab4f2 --- /dev/null +++ b/alternatives/pinentry.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/pinentry-curses.1.gz \ No newline at end of file diff --git a/alternatives/psql.1.gz b/alternatives/psql.1.gz new file mode 120000 index 00000000..c89d77bc --- /dev/null +++ b/alternatives/psql.1.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man1/psql.1.gz \ No newline at end of file diff --git a/alternatives/rcp b/alternatives/rcp new file mode 120000 index 00000000..594df9eb --- /dev/null +++ b/alternatives/rcp @@ -0,0 +1 @@ +/usr/bin/scp \ No newline at end of file diff --git a/alternatives/rcp.1.gz b/alternatives/rcp.1.gz new file mode 120000 index 00000000..63bfff3f --- /dev/null +++ b/alternatives/rcp.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/scp.1.gz \ No newline at end of file diff --git a/alternatives/readmsg b/alternatives/readmsg new file mode 120000 index 00000000..99bcf73c --- /dev/null +++ b/alternatives/readmsg @@ -0,0 +1 @@ +/usr/bin/readmsg.mailutils \ No newline at end of file diff --git a/alternatives/readmsg.1.gz b/alternatives/readmsg.1.gz new file mode 120000 index 00000000..322d3a6e --- /dev/null +++ b/alternatives/readmsg.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/readmsg.mailutils.1.gz \ No newline at end of file diff --git a/alternatives/reindexdb.1.gz b/alternatives/reindexdb.1.gz new file mode 120000 index 00000000..18661f43 --- /dev/null +++ b/alternatives/reindexdb.1.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man1/reindexdb.1.gz \ No newline at end of file diff --git a/alternatives/rlogin b/alternatives/rlogin new file mode 120000 index 00000000..8db89a86 --- /dev/null +++ b/alternatives/rlogin @@ -0,0 +1 @@ +/usr/bin/slogin \ No newline at end of file diff --git a/alternatives/rlogin.1.gz b/alternatives/rlogin.1.gz new file mode 120000 index 00000000..be0c6db9 --- /dev/null +++ b/alternatives/rlogin.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/slogin.1.gz \ No newline at end of file diff --git a/alternatives/rmid b/alternatives/rmid new file mode 120000 index 00000000..a0d0d14e --- /dev/null +++ b/alternatives/rmid @@ -0,0 +1 @@ +/usr/lib/jvm/java-11-openjdk-armhf/bin/rmid \ No newline at end of file diff --git a/alternatives/rmid.1.gz b/alternatives/rmid.1.gz new file mode 120000 index 00000000..6eb9c078 --- /dev/null +++ b/alternatives/rmid.1.gz @@ -0,0 +1 @@ +/usr/lib/jvm/java-11-openjdk-armhf/man/man1/rmid.1.gz \ No newline at end of file diff --git a/alternatives/rmiregistry b/alternatives/rmiregistry new file mode 120000 index 00000000..71b175db --- /dev/null +++ b/alternatives/rmiregistry @@ -0,0 +1 @@ +/usr/lib/jvm/java-11-openjdk-armhf/bin/rmiregistry \ No newline at end of file diff --git a/alternatives/rmiregistry.1.gz b/alternatives/rmiregistry.1.gz new file mode 120000 index 00000000..3cd77c09 --- /dev/null +++ b/alternatives/rmiregistry.1.gz @@ -0,0 +1 @@ +/usr/lib/jvm/java-11-openjdk-armhf/man/man1/rmiregistry.1.gz \ No newline at end of file diff --git a/alternatives/rmt b/alternatives/rmt new file mode 120000 index 00000000..82958a9a --- /dev/null +++ b/alternatives/rmt @@ -0,0 +1 @@ +/usr/sbin/rmt-tar \ No newline at end of file diff --git a/alternatives/rmt.8.gz b/alternatives/rmt.8.gz new file mode 120000 index 00000000..8c87e219 --- /dev/null +++ b/alternatives/rmt.8.gz @@ -0,0 +1 @@ +/usr/share/man/man8/rmt-tar.8.gz \ No newline at end of file diff --git a/alternatives/rsh b/alternatives/rsh new file mode 120000 index 00000000..50a1cff7 --- /dev/null +++ b/alternatives/rsh @@ -0,0 +1 @@ +/usr/bin/ssh \ No newline at end of file diff --git a/alternatives/rsh.1.gz b/alternatives/rsh.1.gz new file mode 120000 index 00000000..b3b36c07 --- /dev/null +++ b/alternatives/rsh.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/ssh.1.gz \ No newline at end of file diff --git a/alternatives/rview b/alternatives/rview new file mode 120000 index 00000000..0d516727 --- /dev/null +++ b/alternatives/rview @@ -0,0 +1 @@ +/usr/bin/vim.tiny \ No newline at end of file diff --git a/alternatives/tcptraceroute b/alternatives/tcptraceroute new file mode 120000 index 00000000..c828cd9e --- /dev/null +++ b/alternatives/tcptraceroute @@ -0,0 +1 @@ +/usr/sbin/tcptraceroute.db \ No newline at end of file diff --git a/alternatives/tcptraceroute.8.gz b/alternatives/tcptraceroute.8.gz new file mode 120000 index 00000000..815a50c2 --- /dev/null +++ b/alternatives/tcptraceroute.8.gz @@ -0,0 +1 @@ +/usr/share/man/man8/tcptraceroute.db.8.gz \ No newline at end of file diff --git a/alternatives/telnet b/alternatives/telnet new file mode 120000 index 00000000..9276cede --- /dev/null +++ b/alternatives/telnet @@ -0,0 +1 @@ +/usr/bin/telnet.netkit \ No newline at end of file diff --git a/alternatives/telnet.1.gz b/alternatives/telnet.1.gz new file mode 120000 index 00000000..9cd371e7 --- /dev/null +++ b/alternatives/telnet.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/telnet.netkit.1.gz \ No newline at end of file diff --git a/alternatives/traceproto b/alternatives/traceproto new file mode 120000 index 00000000..d6973c9c --- /dev/null +++ b/alternatives/traceproto @@ -0,0 +1 @@ +/usr/bin/traceproto.db \ No newline at end of file diff --git a/alternatives/traceproto.1.gz b/alternatives/traceproto.1.gz new file mode 120000 index 00000000..3353595c --- /dev/null +++ b/alternatives/traceproto.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/traceproto.db.1.gz \ No newline at end of file diff --git a/alternatives/traceroute b/alternatives/traceroute new file mode 120000 index 00000000..fd696326 --- /dev/null +++ b/alternatives/traceroute @@ -0,0 +1 @@ +/usr/bin/traceroute.db \ No newline at end of file diff --git a/alternatives/traceroute.1.gz b/alternatives/traceroute.1.gz new file mode 120000 index 00000000..e9586f92 --- /dev/null +++ b/alternatives/traceroute.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/traceroute.db.1.gz \ No newline at end of file diff --git a/alternatives/traceroute.sbin b/alternatives/traceroute.sbin new file mode 120000 index 00000000..fd696326 --- /dev/null +++ b/alternatives/traceroute.sbin @@ -0,0 +1 @@ +/usr/bin/traceroute.db \ No newline at end of file diff --git a/alternatives/traceroute6 b/alternatives/traceroute6 new file mode 120000 index 00000000..7958fcf4 --- /dev/null +++ b/alternatives/traceroute6 @@ -0,0 +1 @@ +/usr/bin/traceroute6.db \ No newline at end of file diff --git a/alternatives/traceroute6.1.gz b/alternatives/traceroute6.1.gz new file mode 120000 index 00000000..7977291e --- /dev/null +++ b/alternatives/traceroute6.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/traceroute6.db.1.gz \ No newline at end of file diff --git a/alternatives/unlzma b/alternatives/unlzma new file mode 120000 index 00000000..c730a4a2 --- /dev/null +++ b/alternatives/unlzma @@ -0,0 +1 @@ +/usr/bin/unxz \ No newline at end of file diff --git a/alternatives/unlzma.1.gz b/alternatives/unlzma.1.gz new file mode 120000 index 00000000..c772f41c --- /dev/null +++ b/alternatives/unlzma.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/unxz.1.gz \ No newline at end of file diff --git a/alternatives/unpack200 b/alternatives/unpack200 new file mode 120000 index 00000000..cac9c070 --- /dev/null +++ b/alternatives/unpack200 @@ -0,0 +1 @@ +/usr/lib/jvm/java-11-openjdk-armhf/bin/unpack200 \ No newline at end of file diff --git a/alternatives/unpack200.1.gz b/alternatives/unpack200.1.gz new file mode 120000 index 00000000..6b48e7a6 --- /dev/null +++ b/alternatives/unpack200.1.gz @@ -0,0 +1 @@ +/usr/lib/jvm/java-11-openjdk-armhf/man/man1/unpack200.1.gz \ No newline at end of file diff --git a/alternatives/vacuumdb.1.gz b/alternatives/vacuumdb.1.gz new file mode 120000 index 00000000..2993adad --- /dev/null +++ b/alternatives/vacuumdb.1.gz @@ -0,0 +1 @@ +/usr/share/postgresql/11/man/man1/vacuumdb.1.gz \ No newline at end of file diff --git a/alternatives/vi b/alternatives/vi new file mode 120000 index 00000000..0d516727 --- /dev/null +++ b/alternatives/vi @@ -0,0 +1 @@ +/usr/bin/vim.tiny \ No newline at end of file diff --git a/alternatives/vi.1.gz b/alternatives/vi.1.gz new file mode 120000 index 00000000..e02a6af1 --- /dev/null +++ b/alternatives/vi.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/vi.da.1.gz b/alternatives/vi.da.1.gz new file mode 120000 index 00000000..c90068fa --- /dev/null +++ b/alternatives/vi.da.1.gz @@ -0,0 +1 @@ +/usr/share/man/da/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/vi.de.1.gz b/alternatives/vi.de.1.gz new file mode 120000 index 00000000..d89833a7 --- /dev/null +++ b/alternatives/vi.de.1.gz @@ -0,0 +1 @@ +/usr/share/man/de/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/vi.fr.1.gz b/alternatives/vi.fr.1.gz new file mode 120000 index 00000000..af52858f --- /dev/null +++ b/alternatives/vi.fr.1.gz @@ -0,0 +1 @@ +/usr/share/man/fr/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/vi.it.1.gz b/alternatives/vi.it.1.gz new file mode 120000 index 00000000..4498a3d4 --- /dev/null +++ b/alternatives/vi.it.1.gz @@ -0,0 +1 @@ +/usr/share/man/it/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/vi.ja.1.gz b/alternatives/vi.ja.1.gz new file mode 120000 index 00000000..071acfbb --- /dev/null +++ b/alternatives/vi.ja.1.gz @@ -0,0 +1 @@ +/usr/share/man/ja/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/vi.pl.1.gz b/alternatives/vi.pl.1.gz new file mode 120000 index 00000000..345590a8 --- /dev/null +++ b/alternatives/vi.pl.1.gz @@ -0,0 +1 @@ +/usr/share/man/pl/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/vi.ru.1.gz b/alternatives/vi.ru.1.gz new file mode 120000 index 00000000..ea9aa167 --- /dev/null +++ b/alternatives/vi.ru.1.gz @@ -0,0 +1 @@ +/usr/share/man/ru/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/view b/alternatives/view new file mode 120000 index 00000000..0d516727 --- /dev/null +++ b/alternatives/view @@ -0,0 +1 @@ +/usr/bin/vim.tiny \ No newline at end of file diff --git a/alternatives/view.1.gz b/alternatives/view.1.gz new file mode 120000 index 00000000..e02a6af1 --- /dev/null +++ b/alternatives/view.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/view.da.1.gz b/alternatives/view.da.1.gz new file mode 120000 index 00000000..c90068fa --- /dev/null +++ b/alternatives/view.da.1.gz @@ -0,0 +1 @@ +/usr/share/man/da/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/view.de.1.gz b/alternatives/view.de.1.gz new file mode 120000 index 00000000..d89833a7 --- /dev/null +++ b/alternatives/view.de.1.gz @@ -0,0 +1 @@ +/usr/share/man/de/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/view.fr.1.gz b/alternatives/view.fr.1.gz new file mode 120000 index 00000000..af52858f --- /dev/null +++ b/alternatives/view.fr.1.gz @@ -0,0 +1 @@ +/usr/share/man/fr/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/view.it.1.gz b/alternatives/view.it.1.gz new file mode 120000 index 00000000..4498a3d4 --- /dev/null +++ b/alternatives/view.it.1.gz @@ -0,0 +1 @@ +/usr/share/man/it/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/view.ja.1.gz b/alternatives/view.ja.1.gz new file mode 120000 index 00000000..071acfbb --- /dev/null +++ b/alternatives/view.ja.1.gz @@ -0,0 +1 @@ +/usr/share/man/ja/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/view.pl.1.gz b/alternatives/view.pl.1.gz new file mode 120000 index 00000000..345590a8 --- /dev/null +++ b/alternatives/view.pl.1.gz @@ -0,0 +1 @@ +/usr/share/man/pl/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/view.ru.1.gz b/alternatives/view.ru.1.gz new file mode 120000 index 00000000..ea9aa167 --- /dev/null +++ b/alternatives/view.ru.1.gz @@ -0,0 +1 @@ +/usr/share/man/ru/man1/vim.1.gz \ No newline at end of file diff --git a/alternatives/w b/alternatives/w new file mode 120000 index 00000000..11c34c45 --- /dev/null +++ b/alternatives/w @@ -0,0 +1 @@ +/usr/bin/w.procps \ No newline at end of file diff --git a/alternatives/w.1.gz b/alternatives/w.1.gz new file mode 120000 index 00000000..7391b640 --- /dev/null +++ b/alternatives/w.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/w.procps.1.gz \ No newline at end of file diff --git a/alternatives/write b/alternatives/write new file mode 120000 index 00000000..121ab03a --- /dev/null +++ b/alternatives/write @@ -0,0 +1 @@ +/usr/bin/bsd-write \ No newline at end of file diff --git a/alternatives/write.1.gz b/alternatives/write.1.gz new file mode 120000 index 00000000..9bcde455 --- /dev/null +++ b/alternatives/write.1.gz @@ -0,0 +1 @@ +/usr/share/man/man1/bsd-write.1.gz \ No newline at end of file diff --git a/apparmor.d/local/usr.bin.man b/apparmor.d/local/usr.bin.man new file mode 100644 index 00000000..e69de29b diff --git a/apparmor.d/local/usr.sbin.ntpd b/apparmor.d/local/usr.sbin.ntpd new file mode 100644 index 00000000..e69de29b diff --git a/apparmor.d/tunables/ntpd b/apparmor.d/tunables/ntpd new file mode 100644 index 00000000..1fc2d8fa --- /dev/null +++ b/apparmor.d/tunables/ntpd @@ -0,0 +1,15 @@ +# vim:syntax=apparmor +# ------------------------------------------------------------------ +# +# Copyright (C) 2002-2005 Novell/SUSE +# Copyright (C) 2011 Canonical, Ltd. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of version 2 of the GNU General Public +# License published by the Free Software Foundation. +# +# ------------------------------------------------------------------ + +#Add your ntpd devices here eg. if you have a DCF clock +# @{NTPD_DEVICE}="/dev/ttyS1" +@{NTPD_DEVICE}="/dev/null" diff --git a/apparmor.d/usr.bin.man b/apparmor.d/usr.bin.man new file mode 100644 index 00000000..569aec91 --- /dev/null +++ b/apparmor.d/usr.bin.man @@ -0,0 +1,101 @@ +# vim:syntax=apparmor + +#include + +/usr/bin/man { + #include + + # Use a special profile when man calls anything groff-related. We only + # include the programs that actually parse input data in a non-trivial + # way, not wrappers such as groff and nroff, since the latter would need a + # broader profile. + /usr/bin/eqn rmCx -> &man_groff, + /usr/bin/grap rmCx -> &man_groff, + /usr/bin/pic rmCx -> &man_groff, + /usr/bin/preconv rmCx -> &man_groff, + /usr/bin/refer rmCx -> &man_groff, + /usr/bin/tbl rmCx -> &man_groff, + /usr/bin/troff rmCx -> &man_groff, + /usr/bin/vgrind rmCx -> &man_groff, + + # Similarly, use a special profile when man calls decompressors and other + # simple filters. + /{,usr/}bin/bzip2 rmCx -> &man_filter, + /{,usr/}bin/gzip rmCx -> &man_filter, + /usr/bin/col rmCx -> &man_filter, + /usr/bin/compress rmCx -> &man_filter, + /usr/bin/iconv rmCx -> &man_filter, + /usr/bin/lzip.lzip rmCx -> &man_filter, + /usr/bin/tr rmCx -> &man_filter, + /usr/bin/xz rmCx -> &man_filter, + + # Allow basically anything in terms of file system access, subject to DAC. + # The purpose of this profile isn't to confine man itself (that might be + # nice in the future, but is tricky since it's quite configurable), but to + # confine the processes it calls that parse untrusted data. + /** mrixwlk, + unix, + + capability setuid, + capability setgid, + + signal peer=@{profile_name}, + signal peer=/usr/bin/man//&man_groff, + signal peer=/usr/bin/man//&man_filter, + + # Site-specific additions and overrides. See local/README for details. + #include +} + +profile man_groff { + #include + # Recent kernels revalidate open FDs, and there are often some still + # open on TTYs. This is temporary until man learns to close irrelevant + # open FDs before execve. + #include + # man always runs its groff pipeline with the input file open on stdin, + # so we can skip . + + /usr/bin/eqn rm, + /usr/bin/grap rm, + /usr/bin/pic rm, + /usr/bin/preconv rm, + /usr/bin/refer rm, + /usr/bin/tbl rm, + /usr/bin/troff rm, + /usr/bin/vgrind rm, + + /etc/groff/** r, + /usr/lib/groff/site-tmac/** r, + /usr/share/groff/** r, + + signal peer=/usr/bin/man, + # @{profile_name} doesn't seem to work here. + signal peer=/usr/bin/man//&man_groff, +} + +profile man_filter { + #include + # Recent kernels revalidate open FDs, and there are often some still + # open on TTYs. This is temporary until man learns to close irrelevant + # open FDs before execve. + #include + + /{,usr/}bin/bzip2 rm, + /{,usr/}bin/gzip rm, + /usr/bin/col rm, + /usr/bin/compress rm, + /usr/bin/iconv rm, + /usr/bin/lzip.lzip rm, + /usr/bin/tr rm, + /usr/bin/xz rm, + + # Manual pages can be more or less anywhere, especially with "man -l", and + # there's no harm in allowing wide read access here since the worst it can + # do is feed data to the invoking man process. + /** r, + + signal peer=/usr/bin/man, + # @{profile_name} doesn't seem to work here. + signal peer=/usr/bin/man//&man_filter, +} diff --git a/apparmor.d/usr.sbin.ntpd b/apparmor.d/usr.sbin.ntpd new file mode 100644 index 00000000..18ccc39e --- /dev/null +++ b/apparmor.d/usr.sbin.ntpd @@ -0,0 +1,89 @@ +# vim:syntax=apparmor +# Updated for Ubuntu by: Jamie Strandboge +# ------------------------------------------------------------------ +# +# Copyright (C) 2002-2005 Novell/SUSE +# Copyright (C) 2009-2012 Canonical Ltd. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of version 2 of the GNU General Public +# License published by the Free Software Foundation. +# +# ------------------------------------------------------------------ + +#include +#include +/usr/sbin/ntpd flags=(attach_disconnected) { + #include + #include + #include + + capability ipc_lock, + capability net_bind_service, + capability setgid, + capability setuid, + capability sys_chroot, + capability sys_resource, + capability sys_time, + capability sys_nice, + + # ntp uses AF_INET, AF_INET6 and AF_UNSPEC + network dgram, + network stream, + + @{PROC}/net/if_inet6 r, + @{PROC}/*/net/if_inet6 r, + @{NTPD_DEVICE} rw, + # pps devices are almost exclusively used with NTP + /dev/pps[0-9]* rw, + + /{,s}bin/ r, + /usr/{,s}bin/ r, + /usr/local/{,s}bin/ r, + /usr/sbin/ntpd rmix, + + /etc/ntp.conf r, + /etc/ntp.conf.dhcp r, + /etc/ntpd.conf r, + /etc/ntpd.conf.tmp r, + /run/ntp.conf.dhcp r, + + /etc/ntp.keys r, + /etc/ntp/** r, + + /etc/ntp.drift rwl, + /etc/ntp.drift.TEMP rwl, + /etc/ntp/drift* rwl, + /var/lib/ntp/*drift rw, + /var/lib/ntp/*drift.TEMP rw, + + /var/log/ntp w, + /var/log/ntp.log w, + /var/log/ntpd w, + /var/log/ntpstats/clockstats* rwl, + /var/log/ntpstats/loopstats* rwl, + /var/log/ntpstats/peerstats* rwl, + /var/log/ntpstats/protostats* rwl, + /var/log/ntpstats/rawstats* rwl, + /var/log/ntpstats/sysstats* rwl, + + /{,var/}run/ntpd.pid w, + + # to be able to check for running ntpdate + /run/lock/ntpdate wk, + + # samba4 ntp signing socket + /{,var/}run/samba/ntp_signd/socket rw, + + # samba4 winbindd pipe + /run/samba/winbindd/pipe rw, + + # For use with clocks that report via shared memory (e.g. gpsd), + # you may need to give ntpd access to all of shared memory, though + # this can be considered dangerous. See https://launchpad.net/bugs/722815 + # for details. To enable, add this to local/usr.sbin.ntpd: + # capability ipc_owner, + + # Site-specific additions and overrides. See local/README for details. + #include +} diff --git a/apparmor/init/network-interface-security/usr.sbin.ntpd b/apparmor/init/network-interface-security/usr.sbin.ntpd new file mode 120000 index 00000000..dbd958f8 --- /dev/null +++ b/apparmor/init/network-interface-security/usr.sbin.ntpd @@ -0,0 +1 @@ +../../../apparmor.d/usr.sbin.ntpd \ No newline at end of file diff --git a/apt/apt.conf.d/01autoremove b/apt/apt.conf.d/01autoremove new file mode 100644 index 00000000..f9d9e85d --- /dev/null +++ b/apt/apt.conf.d/01autoremove @@ -0,0 +1,59 @@ +APT +{ + NeverAutoRemove + { + "^firmware-linux.*"; + "^linux-firmware$"; + "^linux-image-[a-z0-9]*$"; + "^linux-image-[a-z0-9]*-[a-z0-9]*$"; + }; + + VersionedKernelPackages + { + # linux kernels + "linux-image"; + "linux-headers"; + "linux-image-extra"; + "linux-modules"; + "linux-modules-extra"; + "linux-signed-image"; + "linux-image-unsigned"; + # kfreebsd kernels + "kfreebsd-image"; + "kfreebsd-headers"; + # hurd kernels + "gnumach-image"; + # (out-of-tree) modules + ".*-modules"; + ".*-kernel"; + "linux-backports-modules-.*"; + "linux-modules-.*"; + # tools + "linux-tools"; + "linux-cloud-tools"; + # build info + "linux-buildinfo"; + # source code + "linux-source"; + }; + + Never-MarkAuto-Sections + { + "metapackages"; + "contrib/metapackages"; + "non-free/metapackages"; + "restricted/metapackages"; + "universe/metapackages"; + "multiverse/metapackages"; + }; + + Move-Autobit-Sections + { + "oldlibs"; + "contrib/oldlibs"; + "non-free/oldlibs"; + "restricted/oldlibs"; + "universe/oldlibs"; + "multiverse/oldlibs"; + }; +}; diff --git a/apt/apt.conf.d/01autoremove-kernels b/apt/apt.conf.d/01autoremove-kernels new file mode 100644 index 00000000..8b439a97 --- /dev/null +++ b/apt/apt.conf.d/01autoremove-kernels @@ -0,0 +1,56 @@ +// DO NOT EDIT! File autogenerated by /etc/kernel/postinst.d/apt-auto-removal +APT::NeverAutoRemove +{ + "^linux-image-5\.10\.60-v7\+$"; + "^linux-image-5\.10\.63-v8\+$"; + "^linux-headers-5\.10\.60-v7\+$"; + "^linux-headers-5\.10\.63-v8\+$"; + "^linux-image-extra-5\.10\.60-v7\+$"; + "^linux-image-extra-5\.10\.63-v8\+$"; + "^linux-modules-5\.10\.60-v7\+$"; + "^linux-modules-5\.10\.63-v8\+$"; + "^linux-modules-extra-5\.10\.60-v7\+$"; + "^linux-modules-extra-5\.10\.63-v8\+$"; + "^linux-signed-image-5\.10\.60-v7\+$"; + "^linux-signed-image-5\.10\.63-v8\+$"; + "^linux-image-unsigned-5\.10\.60-v7\+$"; + "^linux-image-unsigned-5\.10\.63-v8\+$"; + "^kfreebsd-image-5\.10\.60-v7\+$"; + "^kfreebsd-image-5\.10\.63-v8\+$"; + "^kfreebsd-headers-5\.10\.60-v7\+$"; + "^kfreebsd-headers-5\.10\.63-v8\+$"; + "^gnumach-image-5\.10\.60-v7\+$"; + "^gnumach-image-5\.10\.63-v8\+$"; + "^.*-modules-5\.10\.60-v7\+$"; + "^.*-modules-5\.10\.63-v8\+$"; + "^.*-kernel-5\.10\.60-v7\+$"; + "^.*-kernel-5\.10\.63-v8\+$"; + "^linux-backports-modules-.*-5\.10\.60-v7\+$"; + "^linux-backports-modules-.*-5\.10\.63-v8\+$"; + "^linux-modules-.*-5\.10\.60-v7\+$"; + "^linux-modules-.*-5\.10\.63-v8\+$"; + "^linux-tools-5\.10\.60-v7\+$"; + "^linux-tools-5\.10\.63-v8\+$"; + "^linux-cloud-tools-5\.10\.60-v7\+$"; + "^linux-cloud-tools-5\.10\.63-v8\+$"; + "^linux-buildinfo-5\.10\.60-v7\+$"; + "^linux-buildinfo-5\.10\.63-v8\+$"; + "^linux-source-5\.10\.60-v7\+$"; + "^linux-source-5\.10\.63-v8\+$"; +}; +/* Debug information: +# dpkg list: +# list of installed kernel packages: + +# list of different kernel versions: + +# Installing kernel: (5.10.63-v8+) +# Running kernel: ignored (5.10.60-v7+) +# Last kernel: +# Previous kernel: +# Kernel versions list to keep: + +# Kernel packages (version part) to protect: +5\.10\.60-v7\+ +5\.10\.63-v8\+ +*/ diff --git a/apt/apt.conf.d/01autoremove-postgresql b/apt/apt.conf.d/01autoremove-postgresql new file mode 100644 index 00000000..3f473d1d --- /dev/null +++ b/apt/apt.conf.d/01autoremove-postgresql @@ -0,0 +1,17 @@ +// File installed by postgresql-common. Currently not updated automatically, +// but might be in future releases. +// +// We mark all PostgreSQL packages as NeverAutoRemove because otherwise apt +// would remove the old postgresql-NN package when the "postgresql" meta +// package changes its dependencies to a new version, rendering the old +// database cluster inaccessible. As access to the cluster might depend on +// other modules (like datatypes), we use a pretty wide pattern here. We might +// tighten this to match only actually used PostgreSQL versions in the future. + +APT +{ + NeverAutoRemove + { + "^postgresql-"; + }; +}; diff --git a/apt/apt.conf.d/05etckeeper b/apt/apt.conf.d/05etckeeper new file mode 100644 index 00000000..5e690a2d --- /dev/null +++ b/apt/apt.conf.d/05etckeeper @@ -0,0 +1,5 @@ +DPkg::Pre-Invoke { "if [ -x /usr/bin/etckeeper ]; then etckeeper pre-install; fi"; }; +DPkg::Post-Invoke { "if [ -x /usr/bin/etckeeper ]; then etckeeper post-install; fi"; }; + +RPM::Pre-Invoke { "if [ -x /usr/bin/etckeeper ]; then etckeeper pre-install; fi"; }; +RPM::Post-Invoke { "if [ -x /usr/bin/etckeeper ]; then etckeeper post-install; fi"; }; diff --git a/apt/apt.conf.d/15update-stamp b/apt/apt.conf.d/15update-stamp new file mode 100644 index 00000000..d818d2dd --- /dev/null +++ b/apt/apt.conf.d/15update-stamp @@ -0,0 +1,2 @@ +// This file is managed by Puppet. DO NOT EDIT. +APT::Update::Post-Invoke-Success {"touch /var/lib/apt/periodic/update-success-stamp 2>/dev/null || true";}; diff --git a/apt/apt.conf.d/20listchanges b/apt/apt.conf.d/20listchanges new file mode 100644 index 00000000..17687351 --- /dev/null +++ b/apt/apt.conf.d/20listchanges @@ -0,0 +1,3 @@ +DPkg::Pre-Install-Pkgs { "/usr/bin/apt-listchanges --apt || test $? -lt 10"; }; +DPkg::Tools::Options::/usr/bin/apt-listchanges::Version "2"; +DPkg::Tools::Options::/usr/bin/apt-listchanges::InfoFD "20"; diff --git a/apt/apt.conf.d/50raspi b/apt/apt.conf.d/50raspi new file mode 100644 index 00000000..da3bd489 --- /dev/null +++ b/apt/apt.conf.d/50raspi @@ -0,0 +1,5 @@ +# never use pdiffs. Current implementation is very slow on low-powered devices +Acquire::PDiffs "0"; + +# download up to 5 pdiffs: +#Acquire::PDiffs::FileLimit "5"; diff --git a/apt/apt.conf.d/70debconf b/apt/apt.conf.d/70debconf new file mode 100644 index 00000000..0c8b4ca4 --- /dev/null +++ b/apt/apt.conf.d/70debconf @@ -0,0 +1,3 @@ +// Pre-configure all packages with debconf before they are installed. +// If you don't like it, comment it out. +DPkg::Pre-Install-Pkgs {"/usr/sbin/dpkg-preconfigure --apt || true";}; diff --git a/apt/listchanges.conf b/apt/listchanges.conf new file mode 100644 index 00000000..d2056d62 --- /dev/null +++ b/apt/listchanges.conf @@ -0,0 +1,10 @@ +[apt] +frontend=pager +which=news +email_address=root +email_format=text +confirm=false +headers=false +reverse=false +save_seen=/var/lib/apt/listchanges.db + diff --git a/apt/preferences b/apt/preferences new file mode 100644 index 00000000..e69de29b diff --git a/apt/sources.list b/apt/sources.list new file mode 100644 index 00000000..61820ac0 --- /dev/null +++ b/apt/sources.list @@ -0,0 +1,3 @@ +deb http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi +# Uncomment line below then 'apt-get update' to enable 'apt-get source' +#deb-src http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi diff --git a/apt/sources.list.d/docker.list b/apt/sources.list.d/docker.list new file mode 100644 index 00000000..3b8dbc2b --- /dev/null +++ b/apt/sources.list.d/docker.list @@ -0,0 +1 @@ +deb [arch=armhf] https://download.docker.com/linux/raspbian buster stable diff --git a/apt/sources.list.d/mosquitto-buster.list b/apt/sources.list.d/mosquitto-buster.list new file mode 100644 index 00000000..00778b88 --- /dev/null +++ b/apt/sources.list.d/mosquitto-buster.list @@ -0,0 +1 @@ +#deb https://repo.mosquitto.org/debian buster main diff --git a/apt/sources.list.d/nginx.list b/apt/sources.list.d/nginx.list new file mode 100644 index 00000000..b5a1bb41 --- /dev/null +++ b/apt/sources.list.d/nginx.list @@ -0,0 +1,3 @@ +# This file is managed by Puppet. DO NOT EDIT. +# nginx +#deb https://nginx.org/packages/debian buster nginx diff --git a/apt/sources.list.d/nodesource.list b/apt/sources.list.d/nodesource.list new file mode 100644 index 00000000..d299bd8b --- /dev/null +++ b/apt/sources.list.d/nodesource.list @@ -0,0 +1,2 @@ +#deb https://deb.nodesource.com/node_12.x buster main +#deb-src https://deb.nodesource.com/node_12.x buster main diff --git a/apt/sources.list.d/raspi.list b/apt/sources.list.d/raspi.list new file mode 100644 index 00000000..122287e1 --- /dev/null +++ b/apt/sources.list.d/raspi.list @@ -0,0 +1,3 @@ +deb http://archive.raspberrypi.org/debian/ buster main +# Uncomment line below then 'apt-get update' to enable 'apt-get source' +#deb-src http://archive.raspberrypi.org/debian/ buster main diff --git a/apt/sources.list.d/vscode.list b/apt/sources.list.d/vscode.list new file mode 100644 index 00000000..7b602246 --- /dev/null +++ b/apt/sources.list.d/vscode.list @@ -0,0 +1 @@ +### Disabled by raspberrypi-sys-mods ### diff --git a/apt/trusted.gpg b/apt/trusted.gpg new file mode 100644 index 0000000000000000000000000000000000000000..df670fd0af9e99c568b1101cfc908199e1924cff GIT binary patch literal 15380 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

(h?scqJGv|YSqKmg#7&_I_M;=@BJjJV( zBBEf*WEZmVk#=Nll!^<2p;rK&m|zwpN=s*hjpimd@_8Q?ke)Y@Axt!Gl`Q#hqhlxA z=Y@tmcN>7#*Ieb`RHT3B^R)NI{q&U{U7c!$Y(!`8RX*dMrLNc-VpkvbvJt?vOosk^ zJ+H#^RVT95vmNmzznm3pcNtLenB}Pfb|uh_1-l$qqLna4C)`1U<~mcBT_ub-CMtOr z@Uz87AoB9>iy$`NUdQ%4A9pb|iuRpPdsRT#4`Pd|9K-fLQ~3hEQ(FN)@?tU_#-Ko_ zFv>lVaV}|{pW{>&tE2JZyRhFl10A-#l7`2T>sZlOJB2R$^9DG9+*^W|-Cr11Fj7|O ziIodkh@vI9w2eJ~6iGqDL2%v*CYF>d5)E6m?NPib%FOM=kHqOMn@>%O>tnp|l|i1` zJfs>gf+}M46mr`Q`<`wv#^f1Gp{m)m6_&;_IY3qT03o!3Ygh){XJ@5yQ5vDOyelJE zg&_p+5l%PwjRf;d-!iVK(RHf~Yk5o-dg=kV^yx1q!6e)++%D2@eel_M3u#t{acTzk(T&5;d00eX{MZc^LKT(=@J3DX?)!L)Zi^TR8)2TEq}Z zEGx<7+@Wzr+{1ui+>kl4BYX>}&K=}AO0aJUb)0zN4z{ZpV%}?R+5aWPk%-6AoU+zp zV=D?4QfU*abvC+iIM+Cd&@azz-!2@Oci||vUEzs`K2Y(3uHXSO7eRb7q+hpW>?J}k zhPc=H3&(u+FUWA5o{P_k%!3w7hx!L>AXEfz0V=(h?@D?(n5j9wxkHNqn!h4_MR7=I z{ZSla?wG}RlGS4PrU>?uF9b#LBTWtyv8h0=i6*W|LBCUYD#qrT8oa?98!`|O&RN5h zsPv+@p5>dlGH)7x8st#0ic1RtQ`9x`#LxIcGEw?ObLfP8tDB{JiFXib@vwOD)T54? zFr}2oAGr1F3Ur3XX(P9=F&9r#^4!lkkcJ(W1O8xC^pddhwg7D+{&XiZxC6~h_G#3Y z<~AW2spm3=I*bWhb&qM)g`QBmqoqn4#u9tfd?7i!73c={3NL!M&g-w?7~14}_g!9) zy2r2&5eoTxkMVAHwQ%%^&$X?h+ODzVK90I&kB{*+L~C)#zFeZ+HzhLS0fTslPHJw95GI#1iQd z(rlbF=?+r8A87kDz$x8^QGOY6T7I6&8P|ci)+4P3Fgv(SEENm$!rAJT-NF23(-q(j7qz9xL zV9+D?pqmPX*R3{)PwVbn@A}O#z9hN!X7LuPKHM*uzvB71g$VV`TLm$AQ6DB}4)g)KXWOI6pXB2;6ox^K z!?xBl{0c0Qp26SBEf0*ajrQ^r#!1L8E9zO$DO4nqt+?t!kcSkT@1k(z_u! zH_?s5lj2!{oo5AGBWmY(Ya&lfcxpnQpsAqZdWa~*@7v0Je7WG#XN7!LjZU-%iuzrqBtt!k?#QK^q>%OH(kSfH$R*I(JtoeTt_320^R`i=QpoVi5lLT(T%k&ZThsf3Wh~6RA|J zQvC8nJ8FsUpU^9(C|^SCs`(tofs_Jp`i345sH=P&#;hWB7ta~abQ4RfizM5D%9Ee& zv=zqWbO!fYpeqmBYsqn#L0gjp_nRVDqf=E@-fOM2N)AI5ceVy-sH^JcI;V!HWCAbv zElbWN?qEErN|A_pKnhP+Oud-}qP@=fQWALy+9EYuPHDXxUVz*?o|6Q&JTjwG`^8q7 zQB>Ub+xdrUSn22W9A8{b4gl8um6YsUOF1=4+~nF(4#`)0nCev4&cns_c5TJ4)}VWb z$f@p-1DJSzqE2hT0Ho~n$}&N8-Y1p8!rGeXZaaS!7(&1ah9hC?Q+z?+A4~6qR3`u^ z^`Zk;U%pO3dMc^Ih&sI23W`En{t&N{7GgTWYUr72^ZYyMFV^gQ$`!mZ|x8N*7n@2k@X@(o%HFfpoBtn zq6PGc`ly%T&5keG--p%2R3CzZkf%@b^TMqU+eJQE4a^P6_UoKwE6DgWc9@Um7}-0=!H z@o?-<$!v*~()Q7e`bZLHpI$K$dcxE)n*bNRf_L7k(7dzb$w<4r#=?Db}%$dDV^Pxan~8q^GSZ0bQeyPbdmBsYW_zIxhp#UyxhRI1{tuNhg={a8ZA zDbE{+CokzvF_stU7NtKxWEfhQx{A1h(fzklTR3+7*uKvb<+vMTGrr-9DCgdb+nr`f zYa#_Fm@YN&P%s%uN^DSz?ulc4_>^qH>7WJxiqg2fF)Lbz2pWp$#vB=4%3alAqj;#_-Zq?CUEv-RLg~aE- z?qjjI=0oG6C}F9@BCOqC!>=J&9;grfz-`L7*JU_!!SV!ZikJJD=1LVb;J8G3MG|W^ zbujO^i?Od`*MauAm^^gv1tDNHEBEyV_@$Wx75N6^e6tGoz&x+qQiVUac`$dvbI zBNekMogOWs?+%Q?)hhM+D$J-SM%4ZEopiK?`r20ddqa$G%XOh0L>NEzCbrfku|OFW zkF1oS-kN(xhmj5sr;XtDoV1cgR<${w5(g^eOpdVF5VU5W(zyO7cV&-`csgBk50aBT zi*PX3Pr(3=l#9M1wR59<)ene38<)&J6?A4bJol5(?1Gp5H8157D2~ba@O@)PCp{?v z#=BiK#{DT%@u?||d|u?IHG!IkY*phuCqve7mJ)BTwhYK#L^D~A^;I&P)_B+x&E=XS z`gRvIj!ywBS>h^Bh8n86E#~dm)#$MGAb-M?<3>af-FfiS@e`V0&PN0f2i1|`Ty@1a z<;bTg>@Q44?uD zfbSP0_A}CG+?qeA^$^B^-$nG^?vQj%(|T_utU0O`fACnX#7`$3zblWYQ+8F)@@2oE zoAUDuf3WXB-pudEd?HB1N69X`^A6I(D6}B#cz2?k(xC$HnIaSx>>zh=Syp8X9K z&+L-E8@spV1s(WL3&>|2yf3BYHs@y%xr|4BBPmmO*`>Qx$;L>EIXqye=YtS6mS({k zVS%Eix_u=6yhb8~Cjy?y<`%4O*6tHGC=?XxbQt??ZxzOKoW(AFki*9z|ZNKMiG($l$GB zNmxF#*lCBnRKFpIiJ;}0z69Zk5Z0Q5wAMpDuWSv{8(qoyM9?CaPIY|zF}*xKWTkm&M`^T>L=j#1swfa z)&L(!U7ULe*!`w^M5*bDWRM$G&RQ>~cG${m7@HdMEI-9%Lsg(b%>zKM>D};7X>kUt zgp8$rd_{cM#U%`ybH$o>y;ih?&+Qcu0M3tNr+6!9M?|7k0+*3?nLTv-4oh{1E=>A1 ze++?O5h(P5(NLR)>-%Z}uY6|smaUPc9a{H6j|XupA^Pppp@c}4g9kpz@f&k%^GLYW zOowUoXeP$;24t|f{O-yg*mP=i{x{{u!WQw?rd%I4Bg1D3*E_qPYQsj99dWdD>3Hzn zG@p|O4L8m3pIU1ivriuci~`tvK;AH_YJ8eH&eP_`8!X3`w&uW<-$ zcG&R&jp}wxqgxBU_TQC#QHLzdMRw`(c-(h)-QE$h>2Q{BgT-p?IjoS$EN?wEfn`!^ z?0OnD%d{_7+|0*ksxLBuIaPl*26m1I58;d^2{lI7^k?Z!_>|siO%=A}_=(i3aJin{ zaie5u?*wknGFw82?qrnMv$$*JOKYUH?!(sW)YY%*%ry{f1#VBNbB{ILbOnLxGlOg2 zDc>b2U0hH0Hb$VcRoDM2qGsDX#3uX7)FlG zdf9E+UimMWz4Kl^7DiWH2;=%6mIeX*>^`o!g&jC%j4KYm2l!*Vcp K>&Bmr<^KWKNJ_o{ literal 0 HcmV?d00001 diff --git a/apt/trusted.gpg.d/microsoft.gpg b/apt/trusted.gpg.d/microsoft.gpg new file mode 100644 index 00000000..e69de29b diff --git a/avahi/avahi-daemon.conf b/avahi/avahi-daemon.conf new file mode 100644 index 00000000..ff9a4c58 --- /dev/null +++ b/avahi/avahi-daemon.conf @@ -0,0 +1,68 @@ +# This file is part of avahi. +# +# avahi is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# avahi is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +# License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with avahi; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +# See avahi-daemon.conf(5) for more information on this configuration +# file! + +[server] +#host-name=foo +#domain-name=local +#browse-domains=0pointer.de, zeroconf.org +use-ipv4=yes +use-ipv6=yes +#allow-interfaces=eth0 +#deny-interfaces=eth1 +#check-response-ttl=no +#use-iff-running=no +#enable-dbus=yes +#disallow-other-stacks=no +#allow-point-to-point=no +#cache-entries-max=4096 +#clients-max=4096 +#objects-per-client-max=1024 +#entries-per-entry-group-max=32 +ratelimit-interval-usec=1000000 +ratelimit-burst=1000 + +[wide-area] +enable-wide-area=yes + +[publish] +#disable-publishing=no +#disable-user-service-publishing=no +#add-service-cookie=no +#publish-addresses=yes +publish-hinfo=no +publish-workstation=no +#publish-domain=yes +#publish-dns-servers=192.168.50.1, 192.168.50.2 +#publish-resolv-conf-dns-servers=yes +#publish-aaaa-on-ipv4=yes +#publish-a-on-ipv6=no + +[reflector] +#enable-reflector=no +#reflect-ipv=no + +[rlimits] +#rlimit-as= +#rlimit-core=0 +#rlimit-data=8388608 +#rlimit-fsize=0 +#rlimit-nofile=768 +#rlimit-stack=8388608 +#rlimit-nproc=3 diff --git a/avahi/hosts b/avahi/hosts new file mode 100644 index 00000000..4483340f --- /dev/null +++ b/avahi/hosts @@ -0,0 +1,27 @@ +# This file is part of avahi. +# +# avahi is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# avahi is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +# License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with avahi; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +# This file contains static ip address <-> host name mappings. These +# can be useful to publish services on behalf of a non-avahi enabled +# device. Please bear in mind that host names are expected to be +# fully qualified domain names, i.e. ending in .local! + +# See avahi.hosts(5) for more information on this configuration file! + +# Examples: +# 192.168.0.1 router.local +# 2001::81:1 test.local diff --git a/bash.bashrc b/bash.bashrc new file mode 100644 index 00000000..7fabe82a --- /dev/null +++ b/bash.bashrc @@ -0,0 +1,58 @@ +# System-wide .bashrc file for interactive bash(1) shells. + +# To enable the settings / commands in this file for login shells as well, +# this file has to be sourced in /etc/profile. + +# If not running interactively, don't do anything +[ -z "$PS1" ] && return + +# check the window size after each command and, if necessary, +# update the values of LINES and COLUMNS. +shopt -s checkwinsize + +# set variable identifying the chroot you work in (used in the prompt below) +if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then + debian_chroot=$(cat /etc/debian_chroot) +fi + +# set a fancy prompt (non-color, overwrite the one in /etc/profile) +# but only if not SUDOing and have SUDO_PS1 set; then assume smart user. +if ! [ -n "${SUDO_USER}" -a -n "${SUDO_PS1}" ]; then + PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' +fi + +# Commented out, don't overwrite xterm -T "title" -n "icontitle" by default. +# If this is an xterm set the title to user@host:dir +#case "$TERM" in +#xterm*|rxvt*) +# PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"' +# ;; +#*) +# ;; +#esac + +# enable bash completion in interactive shells +#if ! shopt -oq posix; then +# if [ -f /usr/share/bash-completion/bash_completion ]; then +# . /usr/share/bash-completion/bash_completion +# elif [ -f /etc/bash_completion ]; then +# . /etc/bash_completion +# fi +#fi + +# if the command-not-found package is installed, use it +if [ -x /usr/lib/command-not-found -o -x /usr/share/command-not-found/command-not-found ]; then + function command_not_found_handle { + # check because c-n-f could've been removed in the meantime + if [ -x /usr/lib/command-not-found ]; then + /usr/lib/command-not-found -- "$1" + return $? + elif [ -x /usr/share/command-not-found/command-not-found ]; then + /usr/share/command-not-found/command-not-found -- "$1" + return $? + else + printf "%s: command not found\n" "$1" >&2 + return 127 + fi + } +fi diff --git a/bash_completion b/bash_completion new file mode 100644 index 00000000..41ffe595 --- /dev/null +++ b/bash_completion @@ -0,0 +1 @@ +. /usr/share/bash-completion/bash_completion diff --git a/bash_completion.d/git-prompt b/bash_completion.d/git-prompt new file mode 100644 index 00000000..8b5852a9 --- /dev/null +++ b/bash_completion.d/git-prompt @@ -0,0 +1,11 @@ +# In git versions < 1.7.12, this shell library was part of the +# git completion script. +# +# Some users rely on the __git_ps1 function becoming available +# when bash-completion is loaded. Continue to load this library +# at bash-completion startup for now, to ease the transition to a +# world order where the prompt function is requested separately. +# +if [[ -e /usr/lib/git-core/git-sh-prompt ]]; then + . /usr/lib/git-core/git-sh-prompt +fi diff --git a/bindresvport.blacklist b/bindresvport.blacklist new file mode 100644 index 00000000..1dc056eb --- /dev/null +++ b/bindresvport.blacklist @@ -0,0 +1,15 @@ +# +# This file contains a list of port numbers between 600 and 1024, +# which should not be used by bindresvport. bindresvport is mostly +# called by RPC services. This mostly solves the problem, that a +# RPC service uses a well known port of another service. +# +631 # cups +636 # ldaps +655 # tinc +774 # rpasswd +783 # spamd +873 # rsync +921 # lwresd +993 # imaps +995 # pops diff --git a/bluetooth/input.conf b/bluetooth/input.conf new file mode 100644 index 00000000..4c70bc56 --- /dev/null +++ b/bluetooth/input.conf @@ -0,0 +1,26 @@ +# Configuration file for the input service + +# This section contains options which are not specific to any +# particular interface +[General] + +# Set idle timeout (in minutes) before the connection will +# be disconnect (defaults to 0 for no timeout) +#IdleTimeout=30 + +# Enable HID protocol handling in userspace input profile +# Defaults to false (HIDP handled in HIDP kernel module) +#UserspaceHID=true + +# Limit HID connections to bonded devices +# The HID Profile does not specify that devices must be bonded, however some +# platforms may want to make sure that input connections only come from bonded +# device connections. Several older mice have been known for not supporting +# pairing/encryption. +# Defaults to false to maximize device compatibility. +#ClassicBondedOnly=true + +# LE upgrade security +# Enables upgrades of security automatically if required. +# Defaults to true to maximize device compatibility. +#LEAutoSecurity=true diff --git a/bluetooth/main.conf b/bluetooth/main.conf new file mode 100644 index 00000000..49d47c57 --- /dev/null +++ b/bluetooth/main.conf @@ -0,0 +1,108 @@ +[General] + +# Defaults to 'BlueZ X.YZ', if Name is not set here and plugin 'hostname' is not loaded. +# The plugin 'hostname' is loaded by default and overides the Name set here so +# consider modifying /etc/machine-info with variable PRETTY_HOSTNAME= instead. +#Name = BlueZ + +# Default device class. Only the major and minor device class bits are +# considered. Defaults to '0x000000'. +#Class = 0x000100 + +# How long to stay in discoverable mode before going back to non-discoverable +# The value is in seconds. Default is 180, i.e. 3 minutes. +# 0 = disable timer, i.e. stay discoverable forever +#DiscoverableTimeout = 0 + +# How long to stay in pairable mode before going back to non-discoverable +# The value is in seconds. Default is 0. +# 0 = disable timer, i.e. stay pairable forever +#PairableTimeout = 0 + +# Use vendor id source (assigner), vendor, product and version information for +# DID profile support. The values are separated by ":" and assigner, VID, PID +# and version. +# Possible vendor id source values: bluetooth, usb (defaults to usb) +#DeviceID = bluetooth:1234:5678:abcd + +# Do reverse service discovery for previously unknown devices that connect to +# us. This option is really only needed for qualification since the BITE tester +# doesn't like us doing reverse SDP for some test cases (though there could in +# theory be other useful purposes for this too). Defaults to 'true'. +#ReverseServiceDiscovery = true + +# Enable name resolving after inquiry. Set it to 'false' if you don't need +# remote devices name and want shorter discovery cycle. Defaults to 'true'. +#NameResolving = true + +# Enable runtime persistency of debug link keys. Default is false which +# makes debug link keys valid only for the duration of the connection +# that they were created for. +#DebugKeys = false + +# Restricts all controllers to the specified transport. Default value +# is "dual", i.e. both BR/EDR and LE enabled (when supported by the HW). +# Possible values: "dual", "bredr", "le" +#ControllerMode = dual + +# Enables Multi Profile Specification support. This allows to specify if +# system supports only Multiple Profiles Single Device (MPSD) configuration +# or both Multiple Profiles Single Device (MPSD) and Multiple Profiles Multiple +# Devices (MPMD) configurations. +# Possible values: "off", "single", "multiple" +#MultiProfile = off + +# Permanently enables the Fast Connectable setting for adapters that +# support it. When enabled other devices can connect faster to us, +# however the tradeoff is increased power consumptions. This feature +# will fully work only on kernel version 4.1 and newer. Defaults to +# 'false'. +#FastConnectable = false + +# Default privacy setting. +# Enables use of private address. +# Possible values: "off", "device", "network" +# "network" option not supported currently +# Defaults to "off" +# Privacy = off + +[GATT] +# GATT attribute cache. +# Possible values: +# always: Always cache attributes even for devices not paired, this is +# recommended as it is best for interoperability, with more consistent +# reconnection times and enables proper tracking of notifications for all +# devices. +# yes: Only cache attributes of paired devices. +# no: Never cache attributes +# Default: always +#Cache = always + +# Minimum required Encryption Key Size for accessing secured characteristics. +# Possible values: 0 and 7-16. 0 means don't care. +# Defaults to 0 +# MinEncKeySize = 0 + +[Policy] +# +# The ReconnectUUIDs defines the set of remote services that should try +# to be reconnected to in case of a link loss (link supervision +# timeout). The policy plugin should contain a sane set of values by +# default, but this list can be overridden here. By setting the list to +# empty the reconnection feature gets disabled. +#ReconnectUUIDs=00001112-0000-1000-8000-00805f9b34fb,0000111f-0000-1000-8000-00805f9b34fb,0000110a-0000-1000-8000-00805f9b34fb + +# ReconnectAttempts define the number of attempts to reconnect after a link +# lost. Setting the value to 0 disables reconnecting feature. +#ReconnectAttempts=7 + +# ReconnectIntervals define the set of intervals in seconds to use in between +# attempts. +# If the number of attempts defined in ReconnectAttempts is bigger than the +# set of intervals the last interval is repeated until the last attempt. +#ReconnectIntervals=1,2,4,8,16,32,64 + +# AutoEnable defines option to enable all controllers when they are found. +# This includes adapters present on start as well as adapters that are plugged +# in later on. Defaults to 'false'. +AutoEnable=true diff --git a/bluetooth/network.conf b/bluetooth/network.conf new file mode 100644 index 00000000..5f116395 --- /dev/null +++ b/bluetooth/network.conf @@ -0,0 +1,6 @@ +# Configuration file for the network service + +[General] + +# Disable link encryption: default=false +#DisableSecurity=true diff --git a/ca-certificates.conf b/ca-certificates.conf new file mode 100644 index 00000000..b85102b9 --- /dev/null +++ b/ca-certificates.conf @@ -0,0 +1,152 @@ +# This file lists certificates that you wish to use or to ignore to be +# installed in /etc/ssl/certs. +# update-ca-certificates(8) will update /etc/ssl/certs by reading this file. +# +# This is autogenerated by dpkg-reconfigure ca-certificates. +# Certificates should be installed under /usr/share/ca-certificates +# and files with extension '.crt' is recognized as available certs. +# +# line begins with # is comment. +# line begins with ! is certificate filename to be deselected. +# +mozilla/ACCVRAIZ1.crt +mozilla/AC_RAIZ_FNMT-RCM.crt +mozilla/Actalis_Authentication_Root_CA.crt +!mozilla/AddTrust_External_Root.crt +mozilla/AffirmTrust_Commercial.crt +mozilla/AffirmTrust_Networking.crt +mozilla/AffirmTrust_Premium.crt +mozilla/AffirmTrust_Premium_ECC.crt +mozilla/Amazon_Root_CA_1.crt +mozilla/Amazon_Root_CA_2.crt +mozilla/Amazon_Root_CA_3.crt +mozilla/Amazon_Root_CA_4.crt +mozilla/Atos_TrustedRoot_2011.crt +mozilla/Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.crt +mozilla/Baltimore_CyberTrust_Root.crt +mozilla/Buypass_Class_2_Root_CA.crt +mozilla/Buypass_Class_3_Root_CA.crt +mozilla/CA_Disig_Root_R2.crt +mozilla/Certigna.crt +!mozilla/Certinomis_-_Root_CA.crt +!mozilla/Certplus_Class_2_Primary_CA.crt +mozilla/certSIGN_ROOT_CA.crt +mozilla/Certum_Trusted_Network_CA_2.crt +mozilla/Certum_Trusted_Network_CA.crt +mozilla/CFCA_EV_ROOT.crt +mozilla/Chambers_of_Commerce_Root_-_2008.crt +mozilla/Comodo_AAA_Services_root.crt +mozilla/COMODO_Certification_Authority.crt +mozilla/COMODO_ECC_Certification_Authority.crt +mozilla/COMODO_RSA_Certification_Authority.crt +mozilla/Cybertrust_Global_Root.crt +!mozilla/Deutsche_Telekom_Root_CA_2.crt +mozilla/DigiCert_Assured_ID_Root_CA.crt +mozilla/DigiCert_Assured_ID_Root_G2.crt +mozilla/DigiCert_Assured_ID_Root_G3.crt +mozilla/DigiCert_Global_Root_CA.crt +mozilla/DigiCert_Global_Root_G2.crt +mozilla/DigiCert_Global_Root_G3.crt +mozilla/DigiCert_High_Assurance_EV_Root_CA.crt +mozilla/DigiCert_Trusted_Root_G4.crt +mozilla/DST_Root_CA_X3.crt +mozilla/D-TRUST_Root_Class_3_CA_2_2009.crt +mozilla/D-TRUST_Root_Class_3_CA_2_EV_2009.crt +mozilla/EC-ACC.crt +mozilla/EE_Certification_Centre_Root_CA.crt +mozilla/Entrust.net_Premium_2048_Secure_Server_CA.crt +mozilla/Entrust_Root_Certification_Authority.crt +mozilla/Entrust_Root_Certification_Authority_-_EC1.crt +mozilla/Entrust_Root_Certification_Authority_-_G2.crt +mozilla/ePKI_Root_Certification_Authority.crt +mozilla/E-Tugra_Certification_Authority.crt +mozilla/GDCA_TrustAUTH_R5_ROOT.crt +!mozilla/GeoTrust_Global_CA.crt +!mozilla/GeoTrust_Primary_Certification_Authority.crt +!mozilla/GeoTrust_Primary_Certification_Authority_-_G2.crt +!mozilla/GeoTrust_Primary_Certification_Authority_-_G3.crt +mozilla/GeoTrust_Universal_CA_2.crt +!mozilla/GeoTrust_Universal_CA.crt +mozilla/Global_Chambersign_Root_-_2008.crt +mozilla/GlobalSign_ECC_Root_CA_-_R4.crt +mozilla/GlobalSign_ECC_Root_CA_-_R5.crt +mozilla/GlobalSign_Root_CA.crt +mozilla/GlobalSign_Root_CA_-_R2.crt +mozilla/GlobalSign_Root_CA_-_R3.crt +mozilla/GlobalSign_Root_CA_-_R6.crt +mozilla/Go_Daddy_Class_2_CA.crt +mozilla/Go_Daddy_Root_Certificate_Authority_-_G2.crt +mozilla/Hellenic_Academic_and_Research_Institutions_ECC_RootCA_2015.crt +mozilla/Hellenic_Academic_and_Research_Institutions_RootCA_2011.crt +mozilla/Hellenic_Academic_and_Research_Institutions_RootCA_2015.crt +mozilla/Hongkong_Post_Root_CA_1.crt +mozilla/IdenTrust_Commercial_Root_CA_1.crt +mozilla/IdenTrust_Public_Sector_Root_CA_1.crt +mozilla/ISRG_Root_X1.crt +mozilla/Izenpe.com.crt +mozilla/LuxTrust_Global_Root_2.crt +mozilla/Microsec_e-Szigno_Root_CA_2009.crt +mozilla/NetLock_Arany_=Class_Gold=_FÅ‘tanúsítvány.crt +mozilla/Network_Solutions_Certificate_Authority.crt +mozilla/OISTE_WISeKey_Global_Root_GA_CA.crt +mozilla/OISTE_WISeKey_Global_Root_GB_CA.crt +mozilla/OISTE_WISeKey_Global_Root_GC_CA.crt +mozilla/QuoVadis_Root_CA_1_G3.crt +mozilla/QuoVadis_Root_CA_2.crt +mozilla/QuoVadis_Root_CA_2_G3.crt +mozilla/QuoVadis_Root_CA_3.crt +mozilla/QuoVadis_Root_CA_3_G3.crt +mozilla/QuoVadis_Root_CA.crt +mozilla/Secure_Global_CA.crt +mozilla/SecureSign_RootCA11.crt +mozilla/SecureTrust_CA.crt +mozilla/Security_Communication_RootCA2.crt +mozilla/Security_Communication_Root_CA.crt +mozilla/Sonera_Class_2_Root_CA.crt +mozilla/SSL.com_EV_Root_Certification_Authority_ECC.crt +mozilla/SSL.com_EV_Root_Certification_Authority_RSA_R2.crt +mozilla/SSL.com_Root_Certification_Authority_ECC.crt +mozilla/SSL.com_Root_Certification_Authority_RSA.crt +mozilla/Staat_der_Nederlanden_EV_Root_CA.crt +mozilla/Staat_der_Nederlanden_Root_CA_-_G2.crt +mozilla/Staat_der_Nederlanden_Root_CA_-_G3.crt +mozilla/Starfield_Class_2_CA.crt +mozilla/Starfield_Root_Certificate_Authority_-_G2.crt +mozilla/Starfield_Services_Root_Certificate_Authority_-_G2.crt +mozilla/SwissSign_Gold_CA_-_G2.crt +mozilla/SwissSign_Silver_CA_-_G2.crt +mozilla/SZAFIR_ROOT_CA2.crt +mozilla/Taiwan_GRCA.crt +mozilla/TeliaSonera_Root_CA_v1.crt +!mozilla/thawte_Primary_Root_CA.crt +!mozilla/thawte_Primary_Root_CA_-_G2.crt +!mozilla/thawte_Primary_Root_CA_-_G3.crt +mozilla/TrustCor_ECA-1.crt +mozilla/TrustCor_RootCert_CA-1.crt +mozilla/TrustCor_RootCert_CA-2.crt +mozilla/Trustis_FPS_Root_CA.crt +mozilla/T-TeleSec_GlobalRoot_Class_2.crt +mozilla/T-TeleSec_GlobalRoot_Class_3.crt +mozilla/TUBITAK_Kamu_SM_SSL_Kok_Sertifikasi_-_Surum_1.crt +mozilla/TWCA_Global_Root_CA.crt +mozilla/TWCA_Root_Certification_Authority.crt +mozilla/USERTrust_ECC_Certification_Authority.crt +mozilla/USERTrust_RSA_Certification_Authority.crt +mozilla/Verisign_Class_3_Public_Primary_Certification_Authority_-_G3.crt +!mozilla/VeriSign_Class_3_Public_Primary_Certification_Authority_-_G4.crt +!mozilla/VeriSign_Class_3_Public_Primary_Certification_Authority_-_G5.crt +!mozilla/VeriSign_Universal_Root_Certification_Authority.crt +mozilla/XRamp_Global_CA_Root.crt +mozilla/Certigna_Root_CA.crt +mozilla/emSign_ECC_Root_CA_-_C3.crt +mozilla/emSign_ECC_Root_CA_-_G3.crt +mozilla/emSign_Root_CA_-_C1.crt +mozilla/emSign_Root_CA_-_G1.crt +mozilla/Entrust_Root_Certification_Authority_-_G4.crt +mozilla/GTS_Root_R1.crt +mozilla/GTS_Root_R2.crt +mozilla/GTS_Root_R3.crt +mozilla/GTS_Root_R4.crt +mozilla/Hongkong_Post_Root_CA_3.crt +mozilla/UCA_Extended_Validation_Root.crt +mozilla/UCA_Global_G2_Root.crt diff --git a/ca-certificates/update.d/jks-keystore b/ca-certificates/update.d/jks-keystore new file mode 100755 index 00000000..e0c3445a --- /dev/null +++ b/ca-certificates/update.d/jks-keystore @@ -0,0 +1,89 @@ +#!/bin/sh + +set -e + +# use the locale C.UTF-8 +unset LC_ALL +LC_CTYPE=C.UTF-8 +export LC_CTYPE + +storepass='changeit' +if [ -f /etc/default/cacerts ]; then + . /etc/default/cacerts +fi + +arch=`dpkg --print-architecture` +JAR=/usr/share/ca-certificates-java/ca-certificates-java.jar + +nsslib_name() +{ + if dpkg --assert-multi-arch 2>/dev/null; then + echo "libnss3:${arch}" + else + echo "libnss3" + fi +} + +echo "" +if [ "$cacerts_updates" != yes ] || [ "$CACERT_UPDATES" = disabled ] || [ ! -e $JAR ]; then + echo "updates of cacerts keystore disabled." + exit 0 +fi + +if ! mountpoint -q /proc; then + echo >&2 "the keytool command requires a mounted proc fs (/proc)." + exit 1 +fi + +for jvm in java-7-openjdk-$arch java-7-openjdk \ + oracle-java7-jre-$arch oracle-java7-server-jre-$arch oracle-java7-jdk-$arch \ + java-8-openjdk-$arch java-8-openjdk \ + oracle-java8-jre-$arch oracle-java8-server-jre-$arch oracle-java8-jdk-$arch \ + java-9-openjdk-$arch java-9-openjdk \ + oracle-java9-jre-$arch oracle-java9-server-jre-$arch oracle-java9-jdk-$arch \ + java-10-openjdk-$arch java-10-openjdk \ + oracle-java10-jre-$arch oracle-java10-server-jre-$arch oracle-java10-jdk-$arch \ + java-11-openjdk-$arch java-11-openjdk \ + oracle-java11-jre-$arch oracle-java11-server-jre-$arch oracle-java11-jdk-$arch; do + if [ -x /usr/lib/jvm/$jvm/bin/java ]; then + export JAVA_HOME=/usr/lib/jvm/$jvm + PATH=$JAVA_HOME/bin:$PATH + break + fi +done + +if dpkg-query --version >/dev/null; then + nsspkg=$(dpkg-query -L "$(nsslib_name)" | sed -n 's,\(.*\)/libnss3\.so$,\1,p'|head -n 1) + nsscfg=/etc/${jvm%-$arch}/security/nss.cfg + nssjdk=$(test ! -f $nsscfg || sed -n '/nssLibraryDirectory/s/.*= *\(.*\)/\1/p' $nsscfg) + if [ -n "$nsspkg" ] && [ -n "$nssjdk" ] && [ "$nsspkg" != "$nssjdk" ]; then + ln -sf $nsspkg/libnss3.so $nssjdk/libnss3.so + fi + softokn3pkg=$(dpkg-query -L "$(nsslib_name)" | sed -n 's,\(.*\)/libsoftokn3\.so$,\1,p'|head -n 1) + if [ -n "$softokn3pkg" ] && [ -n "$nssjdk" ] && [ "$softokn3pkg" != "$nssjdk" ]; then + ln -sf $softokn3pkg/libsoftokn3.so $nssjdk/libsoftokn3.so + fi +fi + +do_cleanup() +{ + [ -z "$temp_jvm_cfg" ] || rm -f $temp_jvm_cfg + if [ -n "$nsspkg" ] && [ -n "$nssjdk" ] && [ "$nsspkg" != "$nssjdk" ] + then + rm -f $nssjdk/libnss3.so + fi + if [ -n "$softokn3pkg" ] && [ -n "$nssjdk" ] \ + && [ "$softokn3pkg" != "$nssjdk" ] + then + rm -f $nssjdk/libsoftokn3.so + fi +} + +if java -Xmx64m -jar $JAR -storepass "$storepass"; then + do_cleanup +else + do_cleanup + exit 1 +fi + +echo "done." diff --git a/calendar/default b/calendar/default new file mode 100644 index 00000000..fa521807 --- /dev/null +++ b/calendar/default @@ -0,0 +1,15 @@ +/* This is the system-wide default calendar file, used if calendar(1) + * is invoked by a user without a ~/calendar or ~/.calendar/calendar file. + * It may be edited or even deleted to reflect local policy. + * + * In the standard setup, we simply include the default calendar + * definitions from /usr/share/calendar/calendar.all. If you want + * only some of those definitions, copy calendar.all to /etc/calendar + * and edit it there. That way, your changes will be kept next time + * you upgrade. + * + * The search path for include files is: + * /etc/calendar + * /usr/share/calendar + */ +#include "calendar.all" diff --git a/check_mk/cmk-update-agent.cfg b/check_mk/cmk-update-agent.cfg new file mode 100644 index 00000000..1dea3256 --- /dev/null +++ b/check_mk/cmk-update-agent.cfg @@ -0,0 +1,31 @@ +# Created by Check_MK Agent Bakery. +# This file is managed via WATO, do not edit manually or you +# lose your changes next time when you update the agent. + +{'activated': True, + 'certificates': [], + 'ignore_update_url': True, + 'interval': 3600, + 'protocol': 'http', + 'proxy': None, + 'server': '192.168.0.99', + 'signature_keys': ['-----BEGIN CERTIFICATE-----\n' + 'MIIC2DCCAcACAQEwDQYJKoZIhvcNAQEFBQAwMTEcMBoGA1UECgwTQ2hlY2tfTUsg\n' + 'U2l0ZSByZWFsbTERMA8GA1UEAwwIY21rYWRtaW4wIBcNMjAwODIxMDk0NjE0WhgP\n' + 'MjA1MDA4MTQwOTQ2MTRaMDExHDAaBgNVBAoME0NoZWNrX01LIFNpdGUgcmVhbG0x\n' + 'ETAPBgNVBAMMCGNta2FkbWluMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\n' + 'AQEAvBdk25ubecYpjBvPTuon1X9ZC5VQXbLkCZqMvKazygF/JwTluENnwZlDo4xn\n' + 'CIYcVTg7AP6D2dbX7+jrhlp5TuMyISKR5CuQX4gOwIrOVrufHdI7Bv19LwrFhKjZ\n' + 'Z0i1nycBgZBIlc5RN2fN25pLhMzqQppPHrKBNVEf/ARWjz4iQ4DmwAS+iqnFmw4x\n' + 'BYF0bSA25Cc+T/krptICidmoPJ2YbW8J0S/VBo1LUQ1pavGLgQ0X4cnZ98w86I+I\n' + 'izqOh9fl1BVdJm4j1l8qk87IkEDXLlnm4umUyLG8WBCFrG/Dnfjf0Akk+YQxhrZ8\n' + '028Sl4ZHJiCHXeyF7BAMl2S+kwIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA6j4uL\n' + 'qItEiNZp9RWO+Woon6Nj+zerIjz+ObYC86QLO8mwTSN2oQymssfXXy/iAfSoRsqK\n' + 'dZ6R/Jgc0iWukEnXTsEdWwHE8jGzwXncI6K7hJ+Yb4eaqlPIcAArodVAs6NwQ+BO\n' + 'Su6oKMuuKRZdeF2u7OxZTAG3uuNmFYwK0s32QthUYmqhDD9kuZCHSNfPjIg8Na1H\n' + 'sbmssgGLWZYZU3l4uFjT++F70u/GuQPx1ajE4E/Wjg1n4U4d3FnMIi77ZIS/Bb/R\n' + 'aQr14hY/weN8PXc8rs0+qwdYKfGg1+mxye62obUQt4I6EuAc1Sv5XnNwIefEDxVN\n' + 'wFWG11DIXR5sSb78\n' + '-----END CERTIFICATE-----\n'], + 'site': 'realm', + 'use_proxy_env': False} diff --git a/check_mk/docker.cfg b/check_mk/docker.cfg new file mode 100644 index 00000000..e6f196c6 --- /dev/null +++ b/check_mk/docker.cfg @@ -0,0 +1,7 @@ +# Created by Check_MK Agent Bakery. +# This file is managed via WATO, do not edit manually or you +# lose your changes next time when you update the agent. + +[DOCKER] +# skip_sections: no sections skipped +container_id: short diff --git a/check_mk/mk_inventory.cfg b/check_mk/mk_inventory.cfg new file mode 100644 index 00000000..dcf88d44 --- /dev/null +++ b/check_mk/mk_inventory.cfg @@ -0,0 +1,5 @@ +# Created by Check_MK Agent Bakery. +# This file is managed via WATO, do not edit manually or you +# lose your changes next time when you update the agent. + +INVENTORY_INTERVAL=14400 diff --git a/cifs-utils/idmap-plugin b/cifs-utils/idmap-plugin new file mode 120000 index 00000000..a8687521 --- /dev/null +++ b/cifs-utils/idmap-plugin @@ -0,0 +1 @@ +/etc/alternatives/idmap-plugin \ No newline at end of file diff --git a/cmk-update-agent.state b/cmk-update-agent.state new file mode 100644 index 00000000..7adb4969 --- /dev/null +++ b/cmk-update-agent.state @@ -0,0 +1 @@ +{'protocol': 'http', 'installed_aghash': 'fc6545d6e125c4c9', 'last_error': None, 'site': 'realm', 'last_check': 1635334174.3900735, 'host_name': 'serviceraspi.realm.local', 'server': '192.168.0.99', 'last_update': 1634028399.218944, 'host_secret': 'pntxhkgisefetedlluhmbneceelnviymvmrfcsaezocoirlcjurakqmfhjuunxlv', 'user': 'caelebfi'} diff --git a/console-setup/cached_Lat15-Fixed16.psf.gz b/console-setup/cached_Lat15-Fixed16.psf.gz new file mode 100644 index 0000000000000000000000000000000000000000..8d002b7c93c256b626d1f58016555bb26f20de42 GIT binary patch literal 2429 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 literal 0 HcmV?d00001 diff --git a/console-setup/cached_UTF-8_del.kmap.gz b/console-setup/cached_UTF-8_del.kmap.gz new file mode 100644 index 0000000000000000000000000000000000000000..311fca37d7d7c1dfbf0560efc424ecff0091c4d8 GIT binary patch literal 4452 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/dev/null 2>/dev/null; then + for i in /dev/vcs[0-9]*; do + { : + + } < /dev/tty${i#/dev/vcs} > /dev/tty${i#/dev/vcs} + done +fi + +mkdir -p /run/console-setup +> /run/console-setup/font-loaded +for i in /dev/vcs[0-9]*; do + { : +printf '\033%%G' + } < /dev/tty${i#/dev/vcs} > /dev/tty${i#/dev/vcs} +done diff --git a/console-setup/cached_setup_keyboard.sh b/console-setup/cached_setup_keyboard.sh new file mode 100755 index 00000000..30b46c1b --- /dev/null +++ b/console-setup/cached_setup_keyboard.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +if [ -f /run/console-setup/keymap_loaded ]; then + rm /run/console-setup/keymap_loaded + exit 0 +fi +kbd_mode '-u' < '/dev/tty1' +kbd_mode '-u' < '/dev/tty2' +kbd_mode '-u' < '/dev/tty3' +kbd_mode '-u' < '/dev/tty4' +kbd_mode '-u' < '/dev/tty5' +kbd_mode '-u' < '/dev/tty6' +loadkeys '/etc/console-setup/cached_UTF-8_del.kmap.gz' > '/dev/null' diff --git a/console-setup/cached_setup_terminal.sh b/console-setup/cached_setup_terminal.sh new file mode 100755 index 00000000..494e3638 --- /dev/null +++ b/console-setup/cached_setup_terminal.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +{ : +printf '\033%%G' +} < /dev/tty${1#vcs} > /dev/tty${1#vcs} diff --git a/console-setup/compose.ARMSCII-8.inc b/console-setup/compose.ARMSCII-8.inc new file mode 100644 index 00000000..ca8d3c91 --- /dev/null +++ b/console-setup/compose.ARMSCII-8.inc @@ -0,0 +1 @@ +# Compose sequences for ARMSCII-8 diff --git a/console-setup/compose.CP1251.inc b/console-setup/compose.CP1251.inc new file mode 100644 index 00000000..4fb90dac --- /dev/null +++ b/console-setup/compose.CP1251.inc @@ -0,0 +1 @@ +# Compose sequences for CP1251 diff --git a/console-setup/compose.CP1255.inc b/console-setup/compose.CP1255.inc new file mode 100644 index 00000000..93e6a7b3 --- /dev/null +++ b/console-setup/compose.CP1255.inc @@ -0,0 +1 @@ +# Compose sequences for CP1255 diff --git a/console-setup/compose.CP1256.inc b/console-setup/compose.CP1256.inc new file mode 100644 index 00000000..a792b8ca --- /dev/null +++ b/console-setup/compose.CP1256.inc @@ -0,0 +1 @@ +# Compose sequences for CP1256 diff --git a/console-setup/compose.GEORGIAN-ACADEMY.inc b/console-setup/compose.GEORGIAN-ACADEMY.inc new file mode 100644 index 00000000..33869fd3 --- /dev/null +++ b/console-setup/compose.GEORGIAN-ACADEMY.inc @@ -0,0 +1 @@ +# Compose sequences for GEORGIAN-ACADEMY diff --git a/console-setup/compose.GEORGIAN-PS.inc b/console-setup/compose.GEORGIAN-PS.inc new file mode 100644 index 00000000..a4d20c47 --- /dev/null +++ b/console-setup/compose.GEORGIAN-PS.inc @@ -0,0 +1 @@ +# Compose sequences for GEORGIAN-PS diff --git a/console-setup/compose.IBM1133.inc b/console-setup/compose.IBM1133.inc new file mode 100644 index 00000000..93696454 --- /dev/null +++ b/console-setup/compose.IBM1133.inc @@ -0,0 +1 @@ +# Compose sequences for IBM1133 diff --git a/console-setup/compose.ISIRI-3342.inc b/console-setup/compose.ISIRI-3342.inc new file mode 100644 index 00000000..242f739b --- /dev/null +++ b/console-setup/compose.ISIRI-3342.inc @@ -0,0 +1 @@ +# Compose sequences for ISIRI-3342 diff --git a/console-setup/compose.ISO-8859-1.inc b/console-setup/compose.ISO-8859-1.inc new file mode 100644 index 00000000..a285ddfc --- /dev/null +++ b/console-setup/compose.ISO-8859-1.inc @@ -0,0 +1,155 @@ +# Compose sequences for ISO-8859-1 +compose '!' '!' to '¡' +compose '!' '^' to '¦' +compose '!' 'p' to '¶' +compose '!' 's' to '§' +compose '"' '"' to '¨' +compose '"' 'A' to 'Ä' +compose '"' 'E' to 'Ë' +compose '"' 'I' to 'Ï' +compose '"' 'O' to 'Ö' +compose '"' 'U' to 'Ü' +compose '"' 'a' to 'ä' +compose '"' 'e' to 'ë' +compose '"' 'i' to 'ï' +compose '"' 'o' to 'ö' +compose '"' 'u' to 'ü' +compose '"' 'y' to 'ÿ' +compose '(' '(' to '[' +compose '(' '-' to '{' +compose '(' 'c' to '©' +compose '(' 'r' to '®' +compose ')' ')' to ']' +compose ')' '-' to '}' +compose '*' '0' to '°' +compose '*' 'A' to 'Å' +compose '*' 'a' to 'å' +compose '+' '+' to '#' +compose '+' '-' to '±' +compose ',' ',' to '¸' +compose ',' '-' to '¬' +compose ',' 'C' to 'Ç' +compose ',' 'c' to 'ç' +compose '-' '(' to '{' +compose '-' ')' to '}' +compose '-' '+' to '±' +compose '-' ',' to '¬' +compose '-' '-' to '­' +compose '-' ':' to '÷' +compose '-' 'A' to 'Ã' +compose '-' 'D' to 'Ð' +compose '-' 'N' to 'Ñ' +compose '-' 'O' to 'Õ' +compose '-' '^' to '¯' +compose '-' 'a' to 'ã' +compose '-' 'd' to 'ð' +compose '-' 'l' to '£' +compose '-' 'n' to 'ñ' +compose '-' 'o' to 'õ' +compose '-' 'y' to '¥' +compose '.' '.' to '·' +compose '.' '^' to '·' +compose '/' '/' to '\\' +compose '/' '<' to '\\' +compose '/' 'O' to 'Ø' +compose '/' '^' to '|' +compose '/' 'c' to '¢' +compose '/' 'o' to 'ø' +compose '/' 'u' to 'µ' +compose '1' '2' to '½' +compose '1' '4' to '¼' +compose '3' '4' to '¾' +compose ':' '-' to '÷' +compose '<' '/' to '\\' +compose '<' '<' to '«' +compose '=' 'l' to '£' +compose '=' 'y' to '¥' +compose '>' '>' to '»' +compose '>' 'A' to 'Â' +compose '>' 'E' to 'Ê' +compose '>' 'I' to 'Î' +compose '>' 'O' to 'Ô' +compose '>' 'U' to 'Û' +compose '>' 'a' to 'â' +compose '>' 'e' to 'ê' +compose '>' 'i' to 'î' +compose '>' 'o' to 'ô' +compose '>' 'u' to 'û' +compose '?' '?' to '¿' +compose 'A' 'E' to 'Æ' +compose 'A' 'O' to 'Å' +compose 'T' 'H' to 'Þ' +compose '\'' 'A' to 'Á' +compose '\'' 'C' to 'Ç' +compose '\'' 'E' to 'É' +compose '\'' 'I' to 'Í' +compose '\'' 'O' to 'Ó' +compose '\'' 'U' to 'Ú' +compose '\'' 'Y' to 'Ý' +compose '\'' '\'' to '´' +compose '\'' 'a' to 'á' +compose '\'' 'c' to 'ç' +compose '\'' 'e' to 'é' +compose '\'' 'i' to 'í' +compose '\'' 'o' to 'ó' +compose '\'' 'u' to 'ú' +compose '\'' 'y' to 'ý' +compose '^' '!' to '¦' +compose '^' '-' to '¯' +compose '^' '.' to '·' +compose '^' '/' to '|' +compose '^' '0' to '°' +compose '^' '1' to '¹' +compose '^' '2' to '²' +compose '^' '3' to '³' +compose '^' 'A' to 'Â' +compose '^' 'E' to 'Ê' +compose '^' 'I' to 'Î' +compose '^' 'O' to 'Ô' +compose '^' 'U' to 'Û' +compose '^' '_' to '¯' +compose '^' 'a' to 'â' +compose '^' 'e' to 'ê' +compose '^' 'i' to 'î' +compose '^' 'o' to 'ô' +compose '^' 'u' to 'û' +compose '_' '^' to '¯' +compose '_' '_' to '¯' +compose '_' 'a' to 'ª' +compose '_' 'o' to 'º' +compose '`' 'A' to 'À' +compose '`' 'E' to 'È' +compose '`' 'I' to 'Ì' +compose '`' 'O' to 'Ò' +compose '`' 'U' to 'Ù' +compose '`' 'a' to 'à' +compose '`' 'e' to 'è' +compose '`' 'i' to 'ì' +compose '`' 'o' to 'ò' +compose '`' 'u' to 'ù' +compose 'a' 'e' to 'æ' +compose 'a' 'o' to 'å' +compose 'a' 't' to '@' +compose 'c' '0' to '©' +compose 'c' 'o' to '©' +compose 'o' 'c' to '©' +compose 'o' 'x' to '¤' +compose 'r' 'o' to '®' +compose 's' '0' to '§' +compose 's' '1' to '¹' +compose 's' '2' to '²' +compose 's' '3' to '³' +compose 's' 'o' to '§' +compose 't' 'h' to 'þ' +compose 'v' 'b' to '¦' +compose 'v' 'l' to '|' +compose 'x' '0' to '¤' +compose 'x' 'o' to '¤' +compose '|' 'c' to '¢' +compose '|' '|' to '¦' +compose '~' 'A' to 'Ã' +compose '~' 'N' to 'Ñ' +compose '~' 'O' to 'Õ' +compose '~' 'a' to 'ã' +compose '~' 'n' to 'ñ' +compose '~' 'o' to 'õ' diff --git a/console-setup/compose.ISO-8859-10.inc b/console-setup/compose.ISO-8859-10.inc new file mode 100644 index 00000000..7ca7b107 --- /dev/null +++ b/console-setup/compose.ISO-8859-10.inc @@ -0,0 +1 @@ +# Compose sequences for ISO-8859-10 diff --git a/console-setup/compose.ISO-8859-11.inc b/console-setup/compose.ISO-8859-11.inc new file mode 100644 index 00000000..add3f6ad --- /dev/null +++ b/console-setup/compose.ISO-8859-11.inc @@ -0,0 +1 @@ +# Compose sequences for ISO-8859-11 diff --git a/console-setup/compose.ISO-8859-13.inc b/console-setup/compose.ISO-8859-13.inc new file mode 100644 index 00000000..5b45a261 --- /dev/null +++ b/console-setup/compose.ISO-8859-13.inc @@ -0,0 +1,161 @@ +# Compose sequences for ISO-8859-13 +compose '!' '^' to '¦' +compose '!' 'p' to '¶' +compose '!' 's' to '§' +compose '"' '<' to '´' +compose '"' '>' to '¡' +compose '"' 'A' to 'Ä' +compose '"' 'O' to 'Ö' +compose '"' 'U' to 'Ü' +compose '"' 'a' to 'ä' +compose '"' 'o' to 'ö' +compose '"' 'u' to 'ü' +compose '(' '(' to '[' +compose '(' '-' to '{' +compose '(' 'c' to '©' +compose '(' 'r' to '®' +compose ')' ')' to ']' +compose ')' '-' to '}' +compose '*' '0' to '°' +compose '*' 'A' to 'Å' +compose '*' 'a' to 'å' +compose '+' '+' to '#' +compose '+' '-' to '±' +compose ',' '-' to '¬' +compose ',' '>' to '¥' +compose ',' 'A' to 'À' +compose ',' 'E' to 'Æ' +compose ',' 'G' to 'Ì' +compose ',' 'I' to 'Á' +compose ',' 'K' to 'Í' +compose ',' 'L' to 'Ï' +compose ',' 'N' to 'Ò' +compose ',' 'R' to 'ª' +compose ',' 'U' to 'Ø' +compose ',' 'a' to 'à' +compose ',' 'e' to 'æ' +compose ',' 'g' to 'ì' +compose ',' 'i' to 'á' +compose ',' 'k' to 'í' +compose ',' 'l' to 'ï' +compose ',' 'n' to 'ò' +compose ',' 'r' to 'º' +compose ',' 'u' to 'ø' +compose '-' '(' to '{' +compose '-' ')' to '}' +compose '-' '+' to '±' +compose '-' ',' to '¬' +compose '-' '-' to '­' +compose '-' ':' to '÷' +compose '-' 'A' to 'Â' +compose '-' 'E' to 'Ç' +compose '-' 'I' to 'Î' +compose '-' 'L' to 'Ù' +compose '-' 'O' to 'Ô' +compose '-' 'U' to 'Û' +compose '-' 'a' to 'â' +compose '-' 'e' to 'ç' +compose '-' 'i' to 'î' +compose '-' 'l' to 'ù' +compose '-' 'o' to 'ô' +compose '-' 'u' to 'û' +compose '.' '.' to '·' +compose '.' 'A' to 'Å' +compose '.' 'E' to 'Ë' +compose '.' 'Z' to 'Ý' +compose '.' '^' to '·' +compose '.' 'a' to 'å' +compose '.' 'e' to 'ë' +compose '.' 'z' to 'ý' +compose '/' '/' to '\\' +compose '/' '<' to '\\' +compose '/' 'L' to 'Ù' +compose '/' 'O' to '¨' +compose '/' '^' to '|' +compose '/' 'c' to '¢' +compose '/' 'l' to 'ù' +compose '/' 'o' to '¸' +compose '/' 'u' to 'µ' +compose '1' '2' to '½' +compose '1' '4' to '¼' +compose '3' '4' to '¾' +compose ':' '-' to '÷' +compose ';' 'A' to 'À' +compose ';' 'E' to 'Æ' +compose ';' 'I' to 'Á' +compose ';' 'U' to 'Ø' +compose ';' 'a' to 'à' +compose ';' 'e' to 'æ' +compose ';' 'i' to 'á' +compose ';' 'u' to 'ø' +compose '<' '"' to '´' +compose '<' '/' to '\\' +compose '<' '<' to '«' +compose '<' 'C' to 'È' +compose '<' 'S' to 'Ð' +compose '<' 'Z' to 'Þ' +compose '<' '\'' to '`' +compose '<' 'c' to 'è' +compose '<' 's' to 'ð' +compose '<' 'z' to 'þ' +compose '=' 'l' to '£' +compose '>' '"' to '¡' +compose '>' ',' to '¥' +compose '>' '>' to '»' +compose '>' '\'' to 'ÿ' +compose '?' '?' to '¿' +compose 'A' 'E' to '¯' +compose 'A' 'O' to 'Å' +compose '\'' '<' to '`' +compose '\'' '>' to 'ÿ' +compose '\'' 'C' to 'Ã' +compose '\'' 'E' to 'É' +compose '\'' 'N' to 'Ñ' +compose '\'' 'O' to 'Ó' +compose '\'' 'S' to 'Ú' +compose '\'' 'Z' to 'Ê' +compose '\'' '\'' to 'ÿ' +compose '\'' 'c' to 'ã' +compose '\'' 'e' to 'é' +compose '\'' 'n' to 'ñ' +compose '\'' 'o' to 'ó' +compose '\'' 's' to 'ú' +compose '\'' 'z' to 'ê' +compose '^' '!' to '¦' +compose '^' '.' to '·' +compose '^' '/' to '|' +compose '^' '0' to '°' +compose '^' '1' to '¹' +compose '^' '2' to '²' +compose '^' '3' to '³' +compose '_' 'A' to 'Â' +compose '_' 'E' to 'Ç' +compose '_' 'I' to 'Î' +compose '_' 'O' to 'Ô' +compose '_' 'U' to 'Û' +compose '_' 'a' to 'â' +compose '_' 'e' to 'ç' +compose '_' 'i' to 'î' +compose '_' 'o' to 'ô' +compose '_' 'u' to 'û' +compose 'a' 'e' to '¿' +compose 'a' 'o' to 'å' +compose 'a' 't' to '@' +compose 'c' '0' to '©' +compose 'c' 'o' to '©' +compose 'm' 'u' to 'µ' +compose 'o' 'c' to '©' +compose 'o' 'x' to '¤' +compose 'r' 'o' to '®' +compose 's' '0' to '§' +compose 's' '1' to '¹' +compose 's' '2' to '²' +compose 's' '3' to '³' +compose 's' 'o' to '§' +compose 'v' 'b' to '¦' +compose 'x' '0' to '¤' +compose 'x' 'o' to '¤' +compose '|' 'c' to '¢' +compose '|' '|' to '¦' +compose '~' 'O' to 'Õ' +compose '~' 'o' to 'õ' diff --git a/console-setup/compose.ISO-8859-14.inc b/console-setup/compose.ISO-8859-14.inc new file mode 100644 index 00000000..e2835df6 --- /dev/null +++ b/console-setup/compose.ISO-8859-14.inc @@ -0,0 +1,130 @@ +# Compose sequences for ISO-8859-14 +compose '!' 'p' to '¶' +compose '!' 's' to '§' +compose '"' 'A' to 'Ä' +compose '"' 'E' to 'Ë' +compose '"' 'I' to 'Ï' +compose '"' 'O' to 'Ö' +compose '"' 'U' to 'Ü' +compose '"' 'W' to '½' +compose '"' 'Y' to '¯' +compose '"' 'a' to 'ä' +compose '"' 'e' to 'ë' +compose '"' 'i' to 'ï' +compose '"' 'o' to 'ö' +compose '"' 'u' to 'ü' +compose '"' 'w' to '¾' +compose '"' 'y' to 'ÿ' +compose '(' '(' to '[' +compose '(' '-' to '{' +compose ')' ')' to ']' +compose ')' '-' to '}' +compose '*' 'A' to 'Å' +compose '*' 'a' to 'å' +compose '+' '+' to '#' +compose ',' 'C' to 'Ç' +compose ',' 'c' to 'ç' +compose '-' '(' to '{' +compose '-' ')' to '}' +compose '-' '-' to '­' +compose '-' 'A' to 'Ã' +compose '-' 'N' to 'Ñ' +compose '-' 'O' to 'Õ' +compose '-' 'a' to 'ã' +compose '-' 'l' to '£' +compose '-' 'n' to 'ñ' +compose '-' 'o' to 'õ' +compose '.' 'B' to '¡' +compose '.' 'D' to '¦' +compose '.' 'F' to '°' +compose '.' 'G' to '²' +compose '.' 'M' to '´' +compose '.' 'P' to '·' +compose '.' 'S' to '»' +compose '.' 'T' to '×' +compose '.' 'b' to '¢' +compose '.' 'c' to '¥' +compose '.' 'd' to '«' +compose '.' 'f' to '±' +compose '.' 'g' to '³' +compose '.' 'm' to 'µ' +compose '.' 'p' to '¹' +compose '.' 's' to '¿' +compose '.' 't' to '÷' +compose '/' '/' to '\\' +compose '/' '<' to '\\' +compose '/' 'O' to 'Ø' +compose '/' '^' to '|' +compose '/' 'o' to 'ø' +compose '<' '/' to '\\' +compose '=' 'l' to '£' +compose '>' 'A' to 'Â' +compose '>' 'E' to 'Ê' +compose '>' 'I' to 'Î' +compose '>' 'O' to 'Ô' +compose '>' 'U' to 'Û' +compose '>' 'a' to 'â' +compose '>' 'e' to 'ê' +compose '>' 'i' to 'î' +compose '>' 'o' to 'ô' +compose '>' 'u' to 'û' +compose 'A' 'E' to 'Æ' +compose '\'' 'A' to 'Á' +compose '\'' 'E' to 'É' +compose '\'' 'I' to 'Í' +compose '\'' 'O' to 'Ó' +compose '\'' 'U' to 'Ú' +compose '\'' 'W' to 'ª' +compose '\'' 'Y' to 'Ý' +compose '\'' 'a' to 'á' +compose '\'' 'e' to 'é' +compose '\'' 'i' to 'í' +compose '\'' 'o' to 'ó' +compose '\'' 'u' to 'ú' +compose '\'' 'w' to 'º' +compose '\'' 'y' to 'ý' +compose '^' '/' to '|' +compose '^' 'A' to 'Â' +compose '^' 'E' to 'Ê' +compose '^' 'I' to 'Î' +compose '^' 'O' to 'Ô' +compose '^' 'U' to 'Û' +compose '^' 'W' to 'Ð' +compose '^' 'Y' to 'Þ' +compose '^' 'a' to 'â' +compose '^' 'e' to 'ê' +compose '^' 'i' to 'î' +compose '^' 'o' to 'ô' +compose '^' 'u' to 'û' +compose '^' 'w' to 'ð' +compose '^' 'y' to 'þ' +compose '`' 'A' to 'À' +compose '`' 'E' to 'È' +compose '`' 'I' to 'Ì' +compose '`' 'O' to 'Ò' +compose '`' 'U' to 'Ù' +compose '`' 'W' to '¨' +compose '`' 'Y' to '¬' +compose '`' 'a' to 'à' +compose '`' 'e' to 'è' +compose '`' 'i' to 'ì' +compose '`' 'o' to 'ò' +compose '`' 'u' to 'ù' +compose '`' 'w' to '¸' +compose '`' 'y' to '¼' +compose 'a' 'e' to 'æ' +compose 'a' 't' to '@' +compose 'c' '0' to '©' +compose 'c' 'o' to '©' +compose 'o' 'c' to '©' +compose 'r' '0' to '®' +compose 'r' 'o' to '®' +compose 's' '0' to '§' +compose 's' 'o' to '§' +compose 'v' 'l' to '|' +compose '~' 'A' to 'Ã' +compose '~' 'N' to 'Ñ' +compose '~' 'O' to 'Õ' +compose '~' 'a' to 'ã' +compose '~' 'n' to 'ñ' +compose '~' 'o' to 'õ' diff --git a/console-setup/compose.ISO-8859-15.inc b/console-setup/compose.ISO-8859-15.inc new file mode 100644 index 00000000..79c92ed8 --- /dev/null +++ b/console-setup/compose.ISO-8859-15.inc @@ -0,0 +1,153 @@ +# Compose sequences for ISO-8859-15 +compose '!' '!' to '¡' +compose '!' 'p' to '¶' +compose '!' 's' to '§' +compose '"' '"' to '"' +compose '"' 'A' to 'Ä' +compose '"' 'E' to 'Ë' +compose '"' 'I' to 'Ï' +compose '"' 'O' to 'Ö' +compose '"' 'U' to 'Ü' +compose '"' 'Y' to '¾' +compose '"' 'a' to 'ä' +compose '"' 'e' to 'ë' +compose '"' 'i' to 'ï' +compose '"' 'o' to 'ö' +compose '"' 'u' to 'ü' +compose '"' 'y' to 'ÿ' +compose '(' '(' to '[' +compose '(' '-' to '{' +compose '(' 'c' to '©' +compose '(' 'r' to '®' +compose ')' ')' to ']' +compose ')' '-' to '}' +compose '*' '0' to '°' +compose '*' 'A' to 'Å' +compose '*' 'a' to 'å' +compose '+' '+' to '#' +compose '+' '-' to '±' +compose ',' '-' to '¬' +compose ',' 'C' to 'Ç' +compose ',' 'c' to 'ç' +compose '-' '(' to '{' +compose '-' ')' to '}' +compose '-' '+' to '±' +compose '-' ',' to '¬' +compose '-' '-' to '­' +compose '-' ':' to '÷' +compose '-' 'A' to 'Ã' +compose '-' 'D' to 'Ð' +compose '-' 'N' to 'Ñ' +compose '-' 'O' to 'Õ' +compose '-' '^' to '¯' +compose '-' 'a' to 'ã' +compose '-' 'd' to 'ð' +compose '-' 'l' to '£' +compose '-' 'n' to 'ñ' +compose '-' 'o' to 'õ' +compose '-' 'y' to '¥' +compose '.' '.' to '·' +compose '.' '^' to '·' +compose '/' '/' to '\\' +compose '/' '<' to '\\' +compose '/' 'O' to 'Ø' +compose '/' '^' to '|' +compose '/' 'c' to '¢' +compose '/' 'o' to 'ø' +compose '/' 'u' to 'µ' +compose ':' '-' to '÷' +compose '<' '/' to '\\' +compose '<' '<' to '«' +compose '<' 'S' to '¦' +compose '<' 'Z' to '´' +compose '<' 's' to '¨' +compose '<' 'z' to '¸' +compose '=' 'c' to '¤' +compose '=' 'l' to '£' +compose '=' 'y' to '¥' +compose '>' '>' to '»' +compose '>' 'A' to 'Â' +compose '>' 'E' to 'Ê' +compose '>' 'I' to 'Î' +compose '>' 'O' to 'Ô' +compose '>' 'U' to 'Û' +compose '>' 'a' to 'â' +compose '>' 'e' to 'ê' +compose '>' 'i' to 'î' +compose '>' 'o' to 'ô' +compose '>' 'u' to 'û' +compose '?' '?' to '¿' +compose 'A' 'E' to 'Æ' +compose 'A' 'O' to 'Å' +compose 'O' 'E' to '¼' +compose 'T' 'H' to 'Þ' +compose '\'' 'A' to 'Á' +compose '\'' 'C' to 'Ç' +compose '\'' 'E' to 'É' +compose '\'' 'I' to 'Í' +compose '\'' 'O' to 'Ó' +compose '\'' 'U' to 'Ú' +compose '\'' 'Y' to 'Ý' +compose '\'' '\'' to '\'' +compose '\'' 'a' to 'á' +compose '\'' 'c' to 'ç' +compose '\'' 'e' to 'é' +compose '\'' 'i' to 'í' +compose '\'' 'o' to 'ó' +compose '\'' 'u' to 'ú' +compose '\'' 'y' to 'ý' +compose '^' '-' to '¯' +compose '^' '.' to '·' +compose '^' '/' to '|' +compose '^' '0' to '°' +compose '^' '1' to '¹' +compose '^' '2' to '²' +compose '^' '3' to '³' +compose '^' 'A' to 'Â' +compose '^' 'E' to 'Ê' +compose '^' 'I' to 'Î' +compose '^' 'O' to 'Ô' +compose '^' 'U' to 'Û' +compose '^' '_' to '¯' +compose '^' 'a' to 'â' +compose '^' 'e' to 'ê' +compose '^' 'i' to 'î' +compose '^' 'o' to 'ô' +compose '^' 'u' to 'û' +compose '_' '^' to '¯' +compose '_' '_' to '¯' +compose '_' 'a' to 'ª' +compose '_' 'o' to 'º' +compose '`' 'A' to 'À' +compose '`' 'E' to 'È' +compose '`' 'I' to 'Ì' +compose '`' 'O' to 'Ò' +compose '`' 'U' to 'Ù' +compose '`' 'a' to 'à' +compose '`' 'e' to 'è' +compose '`' 'i' to 'ì' +compose '`' 'o' to 'ò' +compose '`' 'u' to 'ù' +compose 'a' 'e' to 'æ' +compose 'a' 'o' to 'å' +compose 'a' 't' to '@' +compose 'c' '0' to '©' +compose 'c' 'o' to '©' +compose 'e' '=' to '¤' +compose 'o' 'c' to '©' +compose 'o' 'e' to '½' +compose 'r' 'o' to '®' +compose 's' '0' to '§' +compose 's' '1' to '¹' +compose 's' '2' to '²' +compose 's' '3' to '³' +compose 's' 'o' to '§' +compose 't' 'h' to 'þ' +compose 'v' 'l' to '|' +compose '|' 'c' to '¢' +compose '~' 'A' to 'Ã' +compose '~' 'N' to 'Ñ' +compose '~' 'O' to 'Õ' +compose '~' 'a' to 'ã' +compose '~' 'n' to 'ñ' +compose '~' 'o' to 'õ' diff --git a/console-setup/compose.ISO-8859-16.inc b/console-setup/compose.ISO-8859-16.inc new file mode 100644 index 00000000..96c38aea --- /dev/null +++ b/console-setup/compose.ISO-8859-16.inc @@ -0,0 +1 @@ +# Compose sequences for ISO-8859-16 diff --git a/console-setup/compose.ISO-8859-2.inc b/console-setup/compose.ISO-8859-2.inc new file mode 100644 index 00000000..6692ee34 --- /dev/null +++ b/console-setup/compose.ISO-8859-2.inc @@ -0,0 +1,124 @@ +# Compose sequences for ISO-8859-2 +compose '!' 'p' to '¶' +compose '!' 's' to '§' +compose '"' '"' to '¨' +compose '"' 'A' to 'Ä' +compose '"' 'E' to 'Ë' +compose '"' 'O' to 'Ö' +compose '"' 'U' to 'Ü' +compose '"' 'a' to 'ä' +compose '"' 'e' to 'ë' +compose '"' 'o' to 'ö' +compose '"' 'u' to 'ü' +compose '(' '(' to '[' +compose '(' '-' to '{' +compose ')' ')' to ']' +compose ')' '-' to '}' +compose '*' '0' to '°' +compose '*' 'U' to 'Ù' +compose '*' 'u' to 'ù' +compose '+' '+' to '#' +compose ',' ',' to '¸' +compose ',' 'A' to '¡' +compose ',' 'C' to 'Ç' +compose ',' 'E' to 'Ê' +compose ',' 'S' to 'ª' +compose ',' 'T' to 'Þ' +compose ',' 'a' to '±' +compose ',' 'c' to 'ç' +compose ',' 'e' to 'ê' +compose ',' 's' to 'º' +compose ',' 't' to 'þ' +compose '-' '(' to '{' +compose '-' ')' to '}' +compose '-' '-' to '­' +compose '-' ':' to '÷' +compose '-' 'D' to 'Ð' +compose '-' 'd' to 'ð' +compose '.' '.' to 'ÿ' +compose '.' 'C' to 'Å' +compose '.' 'E' to 'Ì' +compose '.' 'I' to '©' +compose '.' 'U' to 'Ù' +compose '.' 'Z' to '¯' +compose '.' 'c' to 'å' +compose '.' 'e' to 'ì' +compose '.' 'i' to '¹' +compose '.' 'u' to 'ù' +compose '.' 'z' to '¿' +compose '/' '/' to '\\' +compose '/' '<' to '\\' +compose '/' '^' to '|' +compose ':' '-' to '÷' +compose '<' '/' to '\\' +compose '<' '<' to '·' +compose '<' 'C' to 'È' +compose '<' 'D' to 'Ï' +compose '<' 'E' to 'Ì' +compose '<' 'L' to '¥' +compose '<' 'N' to 'Ò' +compose '<' 'R' to 'Ø' +compose '<' 'S' to '©' +compose '<' 'T' to '«' +compose '<' 'Z' to '®' +compose '<' 'c' to 'è' +compose '<' 'd' to 'ï' +compose '<' 'e' to 'ì' +compose '<' 'l' to 'µ' +compose '<' 'n' to 'ò' +compose '<' 'r' to 'ø' +compose '<' 's' to '¹' +compose '<' 't' to '»' +compose '<' 'z' to '¾' +compose '>' 'A' to 'Â' +compose '>' 'I' to 'Î' +compose '>' 'O' to 'Ô' +compose '>' 'a' to 'â' +compose '>' 'i' to 'î' +compose '>' 'o' to 'ô' +compose 'A' 'U' to 'Ã' +compose 'L' '-' to '£' +compose 'O' 'E' to '¼' +compose 'Z' '.' to '¯' +compose '\'' 'A' to 'Á' +compose '\'' 'C' to 'Æ' +compose '\'' 'E' to 'É' +compose '\'' 'I' to 'Í' +compose '\'' 'L' to 'Å' +compose '\'' 'N' to 'Ñ' +compose '\'' 'O' to 'Ó' +compose '\'' 'R' to 'À' +compose '\'' 'S' to '¦' +compose '\'' 'U' to 'Ú' +compose '\'' 'Y' to 'Ý' +compose '\'' 'Z' to '¬' +compose '\'' '\'' to '½' +compose '\'' 'a' to 'á' +compose '\'' 'c' to 'æ' +compose '\'' 'e' to 'é' +compose '\'' 'i' to 'í' +compose '\'' 'l' to 'å' +compose '\'' 'n' to 'ñ' +compose '\'' 'o' to 'ó' +compose '\'' 'r' to 'à' +compose '\'' 's' to '¶' +compose '\'' 'u' to 'ú' +compose '\'' 'y' to 'ý' +compose '\'' 'z' to '¼' +compose '^' '/' to '|' +compose '^' 'A' to 'Â' +compose '^' 'I' to 'Î' +compose '^' 'O' to 'Ô' +compose '^' 'a' to 'â' +compose '^' 'i' to 'î' +compose '^' 'o' to 'ô' +compose 'a' 'U' to 'ã' +compose 'l' '-' to '³' +compose 'o' 'e' to '½' +compose 'o' 'x' to '¤' +compose 's' '0' to '§' +compose 's' 'o' to '§' +compose 'v' 'l' to '|' +compose 'x' '0' to '¤' +compose 'x' 'o' to '¤' +compose 'z' '.' to '¿' diff --git a/console-setup/compose.ISO-8859-3.inc b/console-setup/compose.ISO-8859-3.inc new file mode 100644 index 00000000..7e50b6c5 --- /dev/null +++ b/console-setup/compose.ISO-8859-3.inc @@ -0,0 +1,146 @@ +# Compose sequences for ISO-8859-3 +compose '!' 's' to '§' +compose '"' '"' to '¨' +compose '"' 'A' to 'Ä' +compose '"' 'E' to 'Ë' +compose '"' 'I' to 'Ï' +compose '"' 'O' to 'Ö' +compose '"' 'U' to 'Ü' +compose '"' 'Y' to '¾' +compose '"' 'a' to 'ä' +compose '"' 'e' to 'ë' +compose '"' 'i' to 'ï' +compose '"' 'o' to 'ö' +compose '"' 'u' to 'ü' +compose '"' 'y' to 'ÿ' +compose '(' '(' to '[' +compose '(' '-' to '{' +compose '(' 'G' to '«' +compose '(' 'U' to 'Ý' +compose '(' 'g' to '»' +compose '(' 'r' to '®' +compose '(' 'u' to 'ý' +compose ')' ')' to ']' +compose ')' '-' to '}' +compose '*' '0' to '°' +compose '+' '+' to '#' +compose ',' ',' to '¸' +compose ',' 'C' to 'Ç' +compose ',' 'S' to 'ª' +compose ',' 'c' to 'ç' +compose ',' 's' to 'º' +compose '-' '(' to '{' +compose '-' ')' to '}' +compose '-' '-' to '­' +compose '-' ':' to '÷' +compose '-' 'A' to 'Ã' +compose '-' 'D' to 'Ð' +compose '-' 'H' to '¡' +compose '-' 'O' to 'Õ' +compose '-' 'a' to 'ã' +compose '-' 'd' to 'ð' +compose '-' 'h' to '±' +compose '-' 'l' to '£' +compose '-' 'o' to 'õ' +compose '-' 'y' to '¥' +compose '.' '.' to '·' +compose '.' 'C' to 'Å' +compose '.' 'G' to 'Õ' +compose '.' 'I' to '©' +compose '.' 'Z' to '¯' +compose '.' '^' to '·' +compose '.' 'c' to 'å' +compose '.' 'g' to 'õ' +compose '.' 'i' to '¹' +compose '.' 'z' to '¿' +compose '/' '/' to '\\' +compose '/' '<' to '\\' +compose '/' '^' to '|' +compose '/' 'u' to 'µ' +compose ':' '-' to '÷' +compose '<' '/' to '\\' +compose '=' 'c' to '¤' +compose '=' 'e' to '¤' +compose '=' 'l' to '£' +compose '=' 'y' to '¥' +compose '>' 'A' to 'Â' +compose '>' 'C' to 'Æ' +compose '>' 'E' to 'Ê' +compose '>' 'G' to 'Ø' +compose '>' 'H' to '¦' +compose '>' 'I' to 'Î' +compose '>' 'J' to '¬' +compose '>' 'O' to 'Ô' +compose '>' 'S' to 'Þ' +compose '>' 'U' to 'Û' +compose '>' 'a' to 'â' +compose '>' 'c' to 'æ' +compose '>' 'e' to 'ê' +compose '>' 'g' to 'ø' +compose '>' 'h' to '¶' +compose '>' 'i' to 'î' +compose '>' 'j' to '¼' +compose '>' 'o' to 'ô' +compose '>' 's' to 'þ' +compose '>' 'u' to 'û' +compose 'G' 'U' to '«' +compose '\'' 'A' to 'Á' +compose '\'' 'E' to 'É' +compose '\'' 'I' to 'Í' +compose '\'' 'O' to 'Ó' +compose '\'' 'U' to 'Ú' +compose '\'' 'Y' to 'Ý' +compose '\'' '\'' to '´' +compose '\'' 'a' to 'á' +compose '\'' 'e' to 'é' +compose '\'' 'i' to 'í' +compose '\'' 'o' to 'ó' +compose '\'' 'u' to 'ú' +compose '\'' 'y' to 'ý' +compose '^' '.' to '·' +compose '^' '/' to '|' +compose '^' '0' to '°' +compose '^' '2' to '²' +compose '^' '3' to '³' +compose '^' 'A' to 'Â' +compose '^' 'C' to 'Æ' +compose '^' 'E' to 'Ê' +compose '^' 'G' to 'Ø' +compose '^' 'H' to '¦' +compose '^' 'I' to 'Î' +compose '^' 'J' to '¬' +compose '^' 'O' to 'Ô' +compose '^' 'S' to 'Þ' +compose '^' 'U' to 'Û' +compose '^' 'a' to 'â' +compose '^' 'c' to 'æ' +compose '^' 'e' to 'ê' +compose '^' 'g' to 'ø' +compose '^' 'h' to '¶' +compose '^' 'i' to 'î' +compose '^' 'j' to '¼' +compose '^' 'o' to 'ô' +compose '^' 's' to 'þ' +compose '^' 'u' to 'û' +compose '`' 'A' to 'À' +compose '`' 'E' to 'È' +compose '`' 'I' to 'Ì' +compose '`' 'O' to 'Ò' +compose '`' 'U' to 'Ù' +compose '`' 'a' to 'à' +compose '`' 'e' to 'è' +compose '`' 'i' to 'ì' +compose '`' 'o' to 'ò' +compose '`' 'u' to 'ù' +compose 'g' 'U' to '»' +compose 'r' 'o' to '®' +compose 's' '0' to '§' +compose 's' '2' to '²' +compose 's' '3' to '³' +compose 's' 'o' to '§' +compose 'u' 'u' to 'ý' +compose 'v' 'l' to '|' +compose '~' 'A' to 'Ã' +compose '~' 'O' to 'Õ' +compose '~' 'a' to 'ã' +compose '~' 'o' to 'õ' diff --git a/console-setup/compose.ISO-8859-4.inc b/console-setup/compose.ISO-8859-4.inc new file mode 100644 index 00000000..4598a22a --- /dev/null +++ b/console-setup/compose.ISO-8859-4.inc @@ -0,0 +1,121 @@ +# Compose sequences for ISO-8859-4 +compose '!' 's' to '§' +compose '"' '"' to '¨' +compose '"' 'A' to 'Ä' +compose '"' 'E' to 'Ë' +compose '"' 'O' to 'Ö' +compose '"' 'U' to 'Ü' +compose '"' 'a' to 'ä' +compose '"' 'e' to 'ë' +compose '"' 'o' to 'ö' +compose '"' 'u' to 'ü' +compose '*' '0' to '°' +compose '*' 'A' to 'Å' +compose '*' 'a' to 'å' +compose ',' ',' to '¸' +compose ',' 'A' to '¡' +compose ',' 'E' to 'Ê' +compose ',' 'G' to '«' +compose ',' 'I' to 'Ç' +compose ',' 'K' to 'Ó' +compose ',' 'L' to '¦' +compose ',' 'N' to 'Ñ' +compose ',' 'R' to '£' +compose ',' 'U' to 'Ù' +compose ',' 'a' to '±' +compose ',' 'e' to 'ê' +compose ',' 'g' to '»' +compose ',' 'i' to 'ç' +compose ',' 'k' to 'ó' +compose ',' 'l' to '¶' +compose ',' 'n' to 'ñ' +compose ',' 'r' to '³' +compose ',' 'u' to 'ù' +compose '-' '-' to '­' +compose '-' ':' to '÷' +compose '-' 'A' to 'À' +compose '-' 'D' to 'Ð' +compose '-' 'E' to 'ª' +compose '-' 'I' to 'Ï' +compose '-' 'O' to 'Ò' +compose '-' 'U' to 'Þ' +compose '-' '^' to '¯' +compose '-' 'a' to 'à' +compose '-' 'd' to 'ð' +compose '-' 'e' to 'º' +compose '-' 'i' to 'ï' +compose '-' 'o' to 'ò' +compose '-' 'u' to 'þ' +compose '.' '.' to 'ÿ' +compose '.' 'E' to 'Ì' +compose '.' 'e' to 'ì' +compose '/' 'O' to 'Ø' +compose '/' 'T' to '¬' +compose '/' 'o' to 'ø' +compose '/' 't' to '¼' +compose ':' '-' to '÷' +compose '<' '<' to '·' +compose '<' 'C' to 'È' +compose '<' 'S' to '©' +compose '<' 'Z' to '®' +compose '<' 'c' to 'è' +compose '<' 's' to '¹' +compose '<' 'z' to '¾' +compose '>' 'A' to 'Â' +compose '>' 'I' to 'Î' +compose '>' 'O' to 'Ô' +compose '>' 'U' to 'Û' +compose '>' 'a' to 'â' +compose '>' 'i' to 'î' +compose '>' 'o' to 'ô' +compose '>' 'u' to 'û' +compose 'A' 'E' to 'Æ' +compose 'N' 'G' to '½' +compose 'T' '-' to '¬' +compose '\'' 'A' to 'Á' +compose '\'' 'E' to 'É' +compose '\'' 'I' to 'Í' +compose '\'' 'U' to 'Ú' +compose '\'' '\'' to '´' +compose '\'' 'a' to 'á' +compose '\'' 'e' to 'é' +compose '\'' 'i' to 'í' +compose '\'' 'u' to 'ú' +compose '^' '-' to '¯' +compose '^' 'A' to 'Â' +compose '^' 'I' to 'Î' +compose '^' 'O' to 'Ô' +compose '^' 'U' to 'Û' +compose '^' '_' to '¯' +compose '^' 'a' to 'â' +compose '^' 'i' to 'î' +compose '^' 'o' to 'ô' +compose '^' 'u' to 'û' +compose '_' 'A' to 'À' +compose '_' 'E' to 'ª' +compose '_' 'I' to 'Ï' +compose '_' 'O' to 'Ò' +compose '_' 'U' to 'Þ' +compose '_' '^' to '¯' +compose '_' '_' to '¯' +compose '_' 'a' to 'à' +compose '_' 'e' to 'º' +compose '_' 'i' to 'ï' +compose '_' 'o' to 'ò' +compose '_' 'u' to 'þ' +compose 'a' 'e' to 'æ' +compose 'n' 'g' to '¿' +compose 'o' 'x' to '¤' +compose 's' '0' to '§' +compose 's' 'o' to '§' +compose 't' '-' to '¼' +compose 'x' '0' to '¤' +compose 'x' 'o' to '¤' +compose '~' 'A' to 'Ã' +compose '~' 'I' to '¥' +compose '~' 'O' to 'Õ' +compose '~' 'U' to 'Ý' +compose '~' 'a' to 'ã' +compose '~' 'i' to 'µ' +compose '~' 'o' to 'õ' +compose '~' 'u' to 'ý' diff --git a/console-setup/compose.ISO-8859-5.inc b/console-setup/compose.ISO-8859-5.inc new file mode 100644 index 00000000..90c4f07e --- /dev/null +++ b/console-setup/compose.ISO-8859-5.inc @@ -0,0 +1 @@ +# Compose sequences for ISO-8859-5 diff --git a/console-setup/compose.ISO-8859-6.inc b/console-setup/compose.ISO-8859-6.inc new file mode 100644 index 00000000..1a4f93fb --- /dev/null +++ b/console-setup/compose.ISO-8859-6.inc @@ -0,0 +1 @@ +# Compose sequences for ISO-8859-6 diff --git a/console-setup/compose.ISO-8859-7.inc b/console-setup/compose.ISO-8859-7.inc new file mode 100644 index 00000000..1aa936a8 --- /dev/null +++ b/console-setup/compose.ISO-8859-7.inc @@ -0,0 +1,52 @@ +# Compose sequences for ISO-8859-7 +compose '!' '^' to '¦' +compose '!' 's' to '§' +compose '"' '"' to '¨' +compose '(' '(' to '[' +compose '(' '-' to '{' +compose '(' 'c' to '©' +compose ')' ')' to ']' +compose ')' '-' to '}' +compose '*' '0' to '°' +compose '+' '+' to '#' +compose '+' '-' to '±' +compose ',' '-' to '¬' +compose '-' '(' to '{' +compose '-' ')' to '}' +compose '-' '+' to '±' +compose '-' ',' to '¬' +compose '-' '-' to '­' +compose '-' 'l' to '£' +compose '.' '.' to '·' +compose '.' '^' to '·' +compose '/' '/' to '\\' +compose '/' '<' to '\\' +compose '/' '^' to '|' +compose '1' '2' to '½' +compose '<' '/' to '\\' +compose '<' '<' to '«' +compose '<' '\'' to '¡' +compose '=' 'l' to '£' +compose '>' '>' to '»' +compose '>' '\'' to '¢' +compose '\'' '<' to '¡' +compose '\'' '>' to '¢' +compose '\'' '\'' to '´' +compose '^' '!' to '¦' +compose '^' '.' to '·' +compose '^' '/' to '|' +compose '^' '0' to '°' +compose '^' '2' to '²' +compose '^' '3' to '³' +compose 'a' 't' to '@' +compose 'c' '0' to '©' +compose 'c' 'o' to '©' +compose 'o' 'c' to '©' +compose 's' '0' to '§' +compose 's' '2' to '²' +compose 's' '3' to '³' +compose 's' 'o' to '§' +compose 'v' 'b' to '¦' +compose 'v' 'l' to '|' +compose '|' '|' to '¦' +compose '~' '~' to '¯' diff --git a/console-setup/compose.ISO-8859-8.inc b/console-setup/compose.ISO-8859-8.inc new file mode 100644 index 00000000..1fbb453c --- /dev/null +++ b/console-setup/compose.ISO-8859-8.inc @@ -0,0 +1 @@ +# Compose sequences for ISO-8859-8 diff --git a/console-setup/compose.ISO-8859-9.inc b/console-setup/compose.ISO-8859-9.inc new file mode 100644 index 00000000..e642e1b7 --- /dev/null +++ b/console-setup/compose.ISO-8859-9.inc @@ -0,0 +1,156 @@ +# Compose sequences for ISO-8859-9 +compose '!' '!' to '¡' +compose '!' 'p' to '¶' +compose '!' 's' to '§' +compose '"' '"' to '¨' +compose '"' 'A' to 'Ä' +compose '"' 'E' to 'Ë' +compose '"' 'I' to 'Ï' +compose '"' 'O' to 'Ö' +compose '"' 'U' to 'Ü' +compose '"' 'Y' to '¾' +compose '"' 'a' to 'ä' +compose '"' 'e' to 'ë' +compose '"' 'i' to 'ï' +compose '"' 'o' to 'ö' +compose '"' 'u' to 'ü' +compose '"' 'y' to 'ÿ' +compose '(' '(' to '[' +compose '(' '-' to '{' +compose '(' 'G' to 'Ð' +compose '(' 'c' to '©' +compose '(' 'g' to 'ð' +compose '(' 'r' to '®' +compose ')' ')' to ']' +compose ')' '-' to '}' +compose '*' '0' to '°' +compose '*' 'A' to 'Å' +compose '*' 'a' to 'å' +compose '+' '+' to '#' +compose '+' '-' to '±' +compose ',' ',' to '¸' +compose ',' '-' to '¬' +compose ',' 'C' to 'Ç' +compose ',' 'S' to 'Þ' +compose ',' 'c' to 'ç' +compose ',' 's' to 'þ' +compose '-' '(' to '{' +compose '-' ')' to '}' +compose '-' '+' to '±' +compose '-' ',' to '¬' +compose '-' '-' to '­' +compose '-' ':' to '÷' +compose '-' 'A' to 'Ã' +compose '-' 'D' to 'Ð' +compose '-' 'N' to 'Ñ' +compose '-' 'O' to 'Õ' +compose '-' '^' to '¯' +compose '-' 'a' to 'ã' +compose '-' 'd' to 'ð' +compose '-' 'l' to '£' +compose '-' 'n' to 'ñ' +compose '-' 'o' to 'õ' +compose '-' 'y' to '¥' +compose '.' '.' to '·' +compose '.' 'I' to 'Ý' +compose '.' '^' to '·' +compose '.' 'i' to 'ý' +compose '/' '/' to '\\' +compose '/' '<' to '\\' +compose '/' 'O' to 'Ø' +compose '/' '^' to '|' +compose '/' 'c' to '¢' +compose '/' 'o' to 'ø' +compose '/' 'u' to 'µ' +compose ':' '-' to '÷' +compose '<' '/' to '\\' +compose '<' '<' to '«' +compose '<' 'Z' to '´' +compose '<' 'z' to '¸' +compose '=' 'c' to '¤' +compose '=' 'e' to '¤' +compose '=' 'l' to '£' +compose '=' 'y' to '¥' +compose '>' '>' to '»' +compose '>' 'A' to 'Â' +compose '>' 'E' to 'Ê' +compose '>' 'I' to 'Î' +compose '>' 'O' to 'Ô' +compose '>' 'U' to 'Û' +compose '>' 'a' to 'â' +compose '>' 'e' to 'ê' +compose '>' 'i' to 'î' +compose '>' 'o' to 'ô' +compose '>' 'u' to 'û' +compose '?' '?' to '¿' +compose 'A' 'E' to 'Æ' +compose 'G' 'U' to 'Ð' +compose 'T' 'H' to 'Þ' +compose '\'' 'A' to 'Á' +compose '\'' 'E' to 'É' +compose '\'' 'I' to 'Í' +compose '\'' 'O' to 'Ó' +compose '\'' 'U' to 'Ú' +compose '\'' 'Y' to 'Ý' +compose '\'' '\'' to '´' +compose '\'' 'a' to 'á' +compose '\'' 'e' to 'é' +compose '\'' 'i' to 'í' +compose '\'' 'o' to 'ó' +compose '\'' 'u' to 'ú' +compose '\'' 'y' to 'ý' +compose '^' '-' to '¯' +compose '^' '.' to '·' +compose '^' '/' to '|' +compose '^' '0' to '°' +compose '^' '1' to '¹' +compose '^' '2' to '²' +compose '^' '3' to '³' +compose '^' 'A' to 'Â' +compose '^' 'E' to 'Ê' +compose '^' 'I' to 'Î' +compose '^' 'O' to 'Ô' +compose '^' 'U' to 'Û' +compose '^' '_' to '¯' +compose '^' 'a' to 'â' +compose '^' 'e' to 'ê' +compose '^' 'i' to 'î' +compose '^' 'o' to 'ô' +compose '^' 'u' to 'û' +compose '_' '^' to '¯' +compose '_' '_' to '¯' +compose '_' 'a' to 'ª' +compose '_' 'o' to 'º' +compose '`' 'A' to 'À' +compose '`' 'E' to 'È' +compose '`' 'I' to 'Ì' +compose '`' 'O' to 'Ò' +compose '`' 'U' to 'Ù' +compose '`' 'a' to 'à' +compose '`' 'e' to 'è' +compose '`' 'i' to 'ì' +compose '`' 'o' to 'ò' +compose '`' 'u' to 'ù' +compose 'a' 'e' to 'æ' +compose 'c' '0' to '©' +compose 'c' 'o' to '©' +compose 'g' 'U' to 'ð' +compose 'o' 'c' to '©' +compose 'o' 'e' to '¼' +compose 'r' 'o' to '®' +compose 's' '0' to '§' +compose 's' '1' to '¹' +compose 's' '2' to '²' +compose 's' '3' to '³' +compose 's' 'o' to '§' +compose 't' 'h' to 'þ' +compose 'v' 'Z' to '´' +compose 'v' 'l' to '|' +compose 'v' 'z' to '¸' +compose '|' 'c' to '¢' +compose '~' 'A' to 'Ã' +compose '~' 'N' to 'Ñ' +compose '~' 'O' to 'Õ' +compose '~' 'a' to 'ã' +compose '~' 'n' to 'ñ' +compose '~' 'o' to 'õ' diff --git a/console-setup/compose.KOI8-R.inc b/console-setup/compose.KOI8-R.inc new file mode 100644 index 00000000..da0c7aee --- /dev/null +++ b/console-setup/compose.KOI8-R.inc @@ -0,0 +1 @@ +# Compose sequences for KOI8-R diff --git a/console-setup/compose.KOI8-U.inc b/console-setup/compose.KOI8-U.inc new file mode 100644 index 00000000..38e91277 --- /dev/null +++ b/console-setup/compose.KOI8-U.inc @@ -0,0 +1 @@ +# Compose sequences for KOI8-U diff --git a/console-setup/compose.TIS-620.inc b/console-setup/compose.TIS-620.inc new file mode 100644 index 00000000..4b229cc7 --- /dev/null +++ b/console-setup/compose.TIS-620.inc @@ -0,0 +1 @@ +# Compose sequences for TIS-620 diff --git a/console-setup/compose.VISCII.inc b/console-setup/compose.VISCII.inc new file mode 100644 index 00000000..b9576aba --- /dev/null +++ b/console-setup/compose.VISCII.inc @@ -0,0 +1 @@ +# Compose sequences for VISCII diff --git a/console-setup/remap.inc b/console-setup/remap.inc new file mode 100644 index 00000000..a5475c66 --- /dev/null +++ b/console-setup/remap.inc @@ -0,0 +1,32 @@ +# The content of this file will be appended to the keyboard layout. +# The following is an example how to make Alt+j switch to to the next +# console and Alt+k switch to the previous console. + +# Uncomment the following lines for Linux. Notice that everything is +# replicated for all possible values of the modifiers shiftl, shiftr +# and ctrll (shiftl and shiftr are used for groups 1..4 of XKB and +# ctrll is used to fix the broken CapsLock when Linux console is in +# Unicode mode). + +# alt keycode 36 = Incr_Console +# shiftl alt keycode 36 = Incr_Console +# shiftr alt keycode 36 = Incr_Console +# shiftr shiftl alt keycode 36 = Incr_Console +# ctrll alt keycode 36 = Incr_Console +# ctrll shiftl alt keycode 36 = Incr_Console +# ctrll shiftr alt keycode 36 = Incr_Console +# ctrll shiftr shiftl alt keycode 36 = Incr_Console +# +# alt keycode 37 = Decr_Console +# shiftl alt keycode 37 = Decr_Console +# shiftr alt keycode 37 = Decr_Console +# shiftr shiftl alt keycode 37 = Decr_Console +# ctrll alt keycode 37 = Decr_Console +# ctrll shiftl alt keycode 37 = Decr_Console +# ctrll shiftr alt keycode 37 = Decr_Console +# ctrll shiftr shiftl alt keycode 37 = Decr_Console + +# For the same result on FreeBSD uncomment the following lines: + +# 036 'j' 'J' nl nl nscr nscr nl nl C +# 037 'k' 'K' vt vt pscr pscr nl nl C diff --git a/containerd/config.toml b/containerd/config.toml new file mode 100644 index 00000000..ccbbd5b4 --- /dev/null +++ b/containerd/config.toml @@ -0,0 +1,31 @@ +# Copyright 2018-2020 Docker Inc. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +disabled_plugins = ["cri"] + +#root = "/var/lib/containerd" +#state = "/run/containerd" +#subreaper = true +#oom_score = 0 + +#[grpc] +# address = "/run/containerd/containerd.sock" +# uid = 0 +# gid = 0 + +#[debug] +# address = "/run/containerd/debug.sock" +# uid = 0 +# gid = 0 +# level = "info" diff --git a/cron.d/.placeholder b/cron.d/.placeholder new file mode 100644 index 00000000..76cb8d07 --- /dev/null +++ b/cron.d/.placeholder @@ -0,0 +1,2 @@ +# DO NOT EDIT OR REMOVE +# This file is a simple placeholder to keep dpkg from removing this directory diff --git a/cron.d/php b/cron.d/php new file mode 100644 index 00000000..84e5d10d --- /dev/null +++ b/cron.d/php @@ -0,0 +1,14 @@ +# /etc/cron.d/php@PHP_VERSION@: crontab fragment for PHP +# This purges session files in session.save_path older than X, +# where X is defined in seconds as the largest value of +# session.gc_maxlifetime from all your SAPI php.ini files +# or 24 minutes if not defined. The script triggers only +# when session.save_handler=files. +# +# WARNING: The scripts tries hard to honour all relevant +# session PHP options, but if you do something unusual +# you have to disable this script and take care of your +# sessions yourself. + +# Look for and purge old sessions every 30 minutes +09,39 * * * * root [ -x /usr/lib/php/sessionclean ] && if [ ! -d /run/systemd/system ]; then /usr/lib/php/sessionclean; fi diff --git a/cron.d/sysstat b/cron.d/sysstat new file mode 100644 index 00000000..66325cef --- /dev/null +++ b/cron.d/sysstat @@ -0,0 +1,9 @@ +# The first element of the path is a directory where the debian-sa1 +# script is located +PATH=/usr/lib/sysstat:/usr/sbin:/usr/sbin:/usr/bin:/sbin:/bin + +# Activity reports every 10 minutes everyday +5-55/10 * * * * root command -v debian-sa1 > /dev/null && debian-sa1 1 1 + +# Additional run at 23:59 to rotate the statistics file +59 23 * * * root command -v debian-sa1 > /dev/null && debian-sa1 60 2 diff --git a/cron.daily/.placeholder b/cron.daily/.placeholder new file mode 100644 index 00000000..76cb8d07 --- /dev/null +++ b/cron.daily/.placeholder @@ -0,0 +1,2 @@ +# DO NOT EDIT OR REMOVE +# This file is a simple placeholder to keep dpkg from removing this directory diff --git a/cron.daily/apt-compat b/cron.daily/apt-compat new file mode 100755 index 00000000..b0b55376 --- /dev/null +++ b/cron.daily/apt-compat @@ -0,0 +1,55 @@ +#!/bin/sh + +set -e + +# Systemd systems use a systemd timer unit which is preferable to +# run. We want to randomize the apt update and unattended-upgrade +# runs as much as possible to avoid hitting the mirrors all at the +# same time. The systemd time is better at this than the fixed +# cron.daily time +if [ -d /run/systemd/system ]; then + exit 0 +fi + +check_power() +{ + # laptop check, on_ac_power returns: + # 0 (true) System is on main power + # 1 (false) System is not on main power + # 255 (false) Power status could not be determined + # Desktop systems always return 255 it seems + if which on_ac_power >/dev/null 2>&1; then + if on_ac_power; then + : + elif [ $? -eq 1 ]; then + return 1 + fi + fi + return 0 +} + +# sleep for a random interval of time (default 30min) +# (some code taken from cron-apt, thanks) +random_sleep() +{ + RandomSleep=1800 + eval $(apt-config shell RandomSleep APT::Periodic::RandomSleep) + if [ $RandomSleep -eq 0 ]; then + return + fi + if [ -z "$RANDOM" ] ; then + # A fix for shells that do not have this bash feature. + RANDOM=$(( $(dd if=/dev/urandom bs=2 count=1 2> /dev/null | cksum | cut -d' ' -f1) % 32767 )) + fi + TIME=$(($RANDOM % $RandomSleep)) + sleep $TIME +} + +# delay the job execution by a random amount of time +random_sleep + +# ensure we don't do this on battery +check_power || exit 0 + +# run daily job +exec /usr/lib/apt/apt.systemd.daily diff --git a/cron.daily/bsdmainutils b/cron.daily/bsdmainutils new file mode 100755 index 00000000..e65cbd3b --- /dev/null +++ b/cron.daily/bsdmainutils @@ -0,0 +1,16 @@ +#!/bin/sh +# /etc/cron.daily/calendar: BSD mainutils calendar daily maintenance script +# Written by Austin Donnelly + +. /etc/default/bsdmainutils + +[ x$RUN_DAILY = xtrue ] || exit 0 + +[ -x /usr/sbin/sendmail ] || exit 0 + +if [ ! -x /usr/bin/cpp ]; then + echo "The cpp package is needed to run calendar." + exit 1 +fi + +/usr/bin/calendar -a diff --git a/cron.daily/dpkg b/cron.daily/dpkg new file mode 100755 index 00000000..62da8172 --- /dev/null +++ b/cron.daily/dpkg @@ -0,0 +1,36 @@ +#!/bin/sh + +dbdir=/var/lib/dpkg + +# Backup the 7 last versions of dpkg databases containing user data. +if cd /var/backups ; then + # We backup all relevant database files if any has changed, so that + # the rotation number always contains an internally consistent set. + dbchanged=no + dbfiles="arch status diversions statoverride" + for db in $dbfiles ; do + if ! cmp -s "dpkg.${db}.0" "$dbdir/$db"; then + dbchanged=yes + break; + fi + done + if [ "$dbchanged" = "yes" ] ; then + for db in $dbfiles ; do + [ -e "$dbdir/$db" ] || continue + cp -p "$dbdir/$db" "dpkg.$db" + savelog -c 7 "dpkg.$db" >/dev/null + done + fi + + # The alternatives database is independent from the dpkg database. + dbalt=alternatives + + # XXX: Ideally we'd use --warning=none instead of discarding stderr, but + # as of GNU tar 1.27.1, it does not seem to work reliably (see #749307). + if ! test -e ${dbalt}.tar.0 || + ! tar -df ${dbalt}.tar.0 -C $dbdir $dbalt >/dev/null 2>&1 ; + then + tar -cf ${dbalt}.tar -C $dbdir $dbalt >/dev/null 2>&1 + savelog -c 7 ${dbalt}.tar >/dev/null + fi +fi diff --git a/cron.daily/etckeeper b/cron.daily/etckeeper new file mode 100755 index 00000000..eb74401a --- /dev/null +++ b/cron.daily/etckeeper @@ -0,0 +1,8 @@ +#!/bin/sh +set -e +if [ -e /etc/etckeeper/daily ] && [ -e /etc/etckeeper/etckeeper.conf ]; then + . /etc/etckeeper/etckeeper.conf + if [ "$AVOID_DAILY_AUTOCOMMITS" != "1" ]; then + /etc/etckeeper/daily + fi +fi diff --git a/cron.daily/exim4-base b/cron.daily/exim4-base new file mode 100755 index 00000000..9ee41406 --- /dev/null +++ b/cron.daily/exim4-base @@ -0,0 +1,105 @@ +#!/bin/sh + +if [ -n "$EX4DEBUG" ]; then + echo "now debugging $0 $@" + set -x +fi + + +# set this to some other value if you don't want the panic log to be +# watched by this script, for example when you're using your own log +# checking mechanisms or don't care. + +E4BCD_DAILY_REPORT_TO="" +E4BCD_DAILY_REPORT_OPTIONS="" +E4BCD_WATCH_PANICLOG="yes" +# Number of lines of paniclog quoted in warning email. +E4BCD_PANICLOG_LINES="10" +E4BCD_PANICLOG_NOISE="" + +# Only do anything if exim4 is actually installed +if [ ! -x /usr/lib/exim4/exim4 ]; then + exit 0 +fi + +[ -f /etc/default/exim4 ] && . /etc/default/exim4 + +SPOOLDIR="$(exim4 -bP spool_directory | sed 's/.*=[[:space:]]\(.*\)/\1/')" + +# The log processing code used in this cron script is not very +# sophisticated. It relies on this cron job being executed earlier than +# the log rotation job, and will have false results if the log is not +# rotated exactly once daily in the daily cron processing. Even in the +# default configuration, it will ignore log entries made between this +# cron job and the log rotation job. + +# Patches for more sophisticated processing are appreciated via the +# Debian BTS. + +E4BCD_MAINLOG_NOISE="^[[:digit:][:space:]:-]\{20\}\(\(Start\|End\) queue run: pid=[[:digit:]]\+\|exim [[:digit:]\.]\+ daemon started: pid=[[:digit:]]\+, .*\)$" + +if [ -n "$E4BCD_DAILY_REPORT_TO" ]; then + if [ -x "$(command -v eximstats)" ] && [ -x "$(command -v mail)" ]; then + if [ "$(< /var/log/exim4/mainlog grep -v "$E4BCD_MAINLOG_NOISE" | wc -l)" -gt "0" ]; then + < /var/log/exim4/mainlog grep -v "$E4BCD_MAINLOG_NOISE" \ + | eximstats $E4BCD_DAILY_REPORT_OPTIONS \ + | mail -s"$(hostname --fqdn) Daily e-mail activity report" \ + $E4BCD_DAILY_REPORT_TO + else + echo "no mail activity in this interval" \ + | mail -s"$(hostname --fqdn) Daily e-mail activity report" \ + $E4BCD_DAILY_REPORT_TO + fi + else + echo "The exim4 cron job is configured to send a daily report, but eximstats" + echo "and/or mail cannot be found. Please check and make sure that these two" + echo "binaries are available" + fi +fi + +log_this() { + TEXT="$@" + if ! logger -t exim4 -p mail.alert $TEXT; then + RET="$?" + echo >&2 "ALERT: could not syslog $TEXT, logger return value $RET" + fi +} + +if [ "$E4BCD_WATCH_PANICLOG" != "no" ]; then + if [ -s "/var/log/exim4/paniclog" ]; then + if [ -x "/usr/local/lib/exim4/nonzero_paniclog_hook" ]; then + /usr/local/lib/exim4/nonzero_paniclog_hook + fi + if [ -z "$E4BCD_PANICLOG_NOISE" ] || grep -vq "$E4BCD_PANICLOG_NOISE" /var/log/exim4/paniclog; then + log_this "ALERT: exim paniclog /var/log/exim4/paniclog has non-zero size, mail system possibly broken" + if ! printf "Subject: exim paniclog on %s has non-zero size\nTo: root\n\nexim paniclog /var/log/exim4/paniclog on %s has non-zero size, mail system might be broken. The last ${E4BCD_PANICLOG_LINES} lines are quoted below.\n\n%s\n" \ + "$(hostname --fqdn)" "$(hostname --fqdn)" \ + "$(tail -n "${E4BCD_PANICLOG_LINES}" /var/log/exim4/paniclog)" \ + | exim4 root; then + log_this "PANIC: sending out e-mail warning has failed, exim has non-zero return code" + fi + if [ "$E4BCD_WATCH_PANICLOG" = "once" ]; then + logrotate -f /etc/logrotate.d/exim4-paniclog + fi + fi + fi +fi + +# run tidydb as Debian-exim:Debian-exim. +if [ -x /usr/sbin/exim_tidydb ]; then + cd $SPOOLDIR/db || exit 1 + if ! find $SPOOLDIR/db -maxdepth 1 -name '*.lockfile' -or -name 'log.*' \ + -or -type f -printf '%f\0' | \ + xargs -0r -n 1 \ + start-stop-daemon --start --exec /usr/sbin/exim_tidydb \ + --chuid Debian-exim:Debian-exim -- $SPOOLDIR > /dev/null; then + # if we reach this, invoking exim_tidydb from start-stop-daemon has + # failed, most probably because of libpam-tmpdir being in use + # (see #373786 and #376165) + find $SPOOLDIR/db -maxdepth 1 -name '*.lockfile' -or -name 'log.*' \ + -or -type f -printf '%f\0' | \ + runuser --shell=/bin/bash \ + --command="xargs -0r -n 1 /usr/sbin/exim_tidydb $SPOOLDIR > /dev/null" \ + Debian-exim + fi +fi diff --git a/cron.daily/logrotate b/cron.daily/logrotate new file mode 100755 index 00000000..f48c56a7 --- /dev/null +++ b/cron.daily/logrotate @@ -0,0 +1,11 @@ +#!/bin/sh +# THIS FILE IS AUTOMATICALLY DISTRIBUTED BY PUPPET. ANY CHANGES WILL BE +# OVERWRITTEN. + +OUTPUT=$(/usr/sbin/logrotate /etc/logrotate.conf 2>&1) +EXITVALUE=$? +if [ $EXITVALUE != 0 ]; then + /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]" + echo "${OUTPUT}" +fi +exit $EXITVALUE diff --git a/cron.daily/man-db b/cron.daily/man-db new file mode 100755 index 00000000..1342bc68 --- /dev/null +++ b/cron.daily/man-db @@ -0,0 +1,43 @@ +#!/bin/sh +# +# man-db cron daily + +set -e + +if [ -d /run/systemd/system ]; then + # Skip in favour of systemd timer. + exit 0 +fi + +iosched_idle= +# Don't try to change I/O priority in a vserver or OpenVZ. +if ! egrep -q '(envID|VxID):.*[1-9]' /proc/self/status && \ + ([ ! -d /proc/vz ] || [ -d /proc/bc ]); then + iosched_idle='--iosched idle' +fi + +if ! [ -d /var/cache/man ]; then + # Recover from deletion, per FHS. + install -d -o man -g man -m 0755 /var/cache/man +fi + +# expunge old catman pages which have not been read in a week +if [ -d /var/cache/man ]; then + cd / + start-stop-daemon --start --pidfile /dev/null --startas /bin/sh \ + --oknodo --chuid man $iosched_idle -- -c \ + "find /var/cache/man -type f -name '*.gz' -atime +6 -print0 | \ + xargs -r0 rm -f" +fi + +# regenerate man database +if [ -x /usr/bin/mandb ]; then + # --pidfile /dev/null so it always starts; mandb isn't really a daemon, + # but we want to start it like one. + start-stop-daemon --start --pidfile /dev/null \ + --startas /usr/bin/mandb --oknodo --chuid man \ + $iosched_idle \ + -- --no-purge --quiet +fi + +exit 0 diff --git a/cron.daily/ntp b/cron.daily/ntp new file mode 100755 index 00000000..1fe08153 --- /dev/null +++ b/cron.daily/ntp @@ -0,0 +1,39 @@ +#!/bin/sh + +# The default Debian ntp.conf enables logging of various statistics to +# the /var/log/ntpstats directory. The daemon automatically changes +# to a new datestamped set of files at midnight, so all we need to do +# is delete old ones, and compress the ones we're keeping so disk +# usage is controlled. + +statsdir=$(cat /etc/ntp.conf | grep -v '^#' | sed -nr 's/^statsdir[[:space:]]+([^[:space:]]+).*$/\1/p') + +if [ -n "$statsdir" ] && [ -d "$statsdir" ]; then + # only keep a week's depth of these. Delete only files exactly + # within the directory and do not descend into subdirectories + # to avoid security risks on platforms where find is not using + # fts-library. + find "$statsdir" -maxdepth 1 -type f -name "*stats*" -mtime +7 -delete + + # compress whatever is left to save space but make sure to really + # do it only in the expected directory. + cd "$statsdir" || exit 1 + ls -d -- *stats.???????? > /dev/null 2>&1 + if [ $? -eq 0 ]; then + # Note that gzip won't compress the file names that + # are hard links to the live/current files, so this + # compresses yesterday and previous, leaving the live + # log alone. We suppress the warnings gzip issues + # about not compressing the linked file. + gzip --best --quiet -- *stats.???????? + return=$? + case $return in + 2) + exit 0 # squash all warnings + ;; + *) + exit $return # but let real errors through + ;; + esac + fi +fi diff --git a/cron.daily/passwd b/cron.daily/passwd new file mode 100755 index 00000000..4778bf09 --- /dev/null +++ b/cron.daily/passwd @@ -0,0 +1,9 @@ +#!/bin/sh + +cd /var/backups || exit 0 + +for FILE in passwd group shadow gshadow; do + test -f /etc/$FILE || continue + cmp -s $FILE.bak /etc/$FILE && continue + cp -p /etc/$FILE $FILE.bak && chmod 600 $FILE.bak +done diff --git a/cron.daily/sysstat b/cron.daily/sysstat new file mode 100755 index 00000000..7c7a5dff --- /dev/null +++ b/cron.daily/sysstat @@ -0,0 +1,18 @@ +#!/bin/sh +# Generate a daily summary of process accounting. Since this will probably +# get kicked off in the morning, it is run against the previous day data. + +# our configuration file +DEFAULT=/etc/default/sysstat +# default settings, overriden in the above file +ENABLED=false + +[ ! -x /usr/lib/sysstat/sa2 ] && exit 0 + +# read our config +[ -r "$DEFAULT" ] && . "$DEFAULT" + +[ "$ENABLED" = "true" ] || exit 0 + +exec /usr/lib/sysstat/sa2 -A + diff --git a/cron.hourly/.placeholder b/cron.hourly/.placeholder new file mode 100644 index 00000000..76cb8d07 --- /dev/null +++ b/cron.hourly/.placeholder @@ -0,0 +1,2 @@ +# DO NOT EDIT OR REMOVE +# This file is a simple placeholder to keep dpkg from removing this directory diff --git a/cron.hourly/fake-hwclock b/cron.hourly/fake-hwclock new file mode 100755 index 00000000..ec215407 --- /dev/null +++ b/cron.hourly/fake-hwclock @@ -0,0 +1,8 @@ +#!/bin/sh +# +# Simple cron script - save the current clock periodically in case of +# a power failure or other crash + +if (command -v fake-hwclock >/dev/null 2>&1) ; then + fake-hwclock save +fi diff --git a/cron.monthly/.placeholder b/cron.monthly/.placeholder new file mode 100644 index 00000000..76cb8d07 --- /dev/null +++ b/cron.monthly/.placeholder @@ -0,0 +1,2 @@ +# DO NOT EDIT OR REMOVE +# This file is a simple placeholder to keep dpkg from removing this directory diff --git a/cron.weekly/.placeholder b/cron.weekly/.placeholder new file mode 100644 index 00000000..76cb8d07 --- /dev/null +++ b/cron.weekly/.placeholder @@ -0,0 +1,2 @@ +# DO NOT EDIT OR REMOVE +# This file is a simple placeholder to keep dpkg from removing this directory diff --git a/cron.weekly/man-db b/cron.weekly/man-db new file mode 100755 index 00000000..6e3ad83a --- /dev/null +++ b/cron.weekly/man-db @@ -0,0 +1,34 @@ +#!/bin/sh +# +# man-db cron weekly + +set -e + +if [ -d /run/systemd/system ]; then + # Skip in favour of systemd timer. + exit 0 +fi + +iosched_idle= +# Don't try to change I/O priority in a vserver or OpenVZ. +if ! egrep -q '(envID|VxID):.*[1-9]' /proc/self/status && \ + ([ ! -d /proc/vz ] || [ -d /proc/bc ]); then + iosched_idle='--iosched idle' +fi + +if ! [ -d /var/cache/man ]; then + # Recover from deletion, per FHS. + install -d -o man -g man -m 0755 /var/cache/man +fi + +# regenerate man database +if [ -x /usr/bin/mandb ]; then + # --pidfile /dev/null so it always starts; mandb isn't really a daemon, + # but we want to start it like one. + start-stop-daemon --start --pidfile /dev/null \ + --startas /usr/bin/mandb --oknodo --chuid man \ + $iosched_idle \ + -- --quiet +fi + +exit 0 diff --git a/crontab b/crontab new file mode 100644 index 00000000..ee82cb5d --- /dev/null +++ b/crontab @@ -0,0 +1,25 @@ +# /etc/crontab: system-wide crontab +# Unlike any other crontab you don't have to run the `crontab' +# command to install the new version when you edit this file +# and files in /etc/cron.d. These files also have username fields, +# that none of the other crontabs do. + +SHELL=/bin/sh +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + +# Example of job definition: +# .---------------- minute (0 - 59) +# | .------------- hour (0 - 23) +# | | .---------- day of month (1 - 31) +# | | | .------- month (1 - 12) OR jan,feb,mar,apr ... +# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat +# | | | | | +# * * * * * user-name command to be executed +17 * * * * root cd / && run-parts --report /etc/cron.hourly +25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily ) +47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly ) +52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly ) +# + +# etcbackup starts at 5:05 +5 5 * * * root /usr/local/bin/etcbackup.sh > /dev/null 2>&1 diff --git a/cruft/filters-unex/etckeeper b/cruft/filters-unex/etckeeper new file mode 100644 index 00000000..edd5f33a --- /dev/null +++ b/cruft/filters-unex/etckeeper @@ -0,0 +1,13 @@ +/etc/.etckeeper +/etc/.gitignore +/etc/.git +/etc/.git/** +/etc/.hgignore +/etc/.hg +/etc/.hg/** +/etc/.bzrignore +/etc/.bzr +/etc/.bzr/** +/etc/.darcsignore +/etc/_darcs +/etc/_darcs/** diff --git a/dbus-1/system.d/avahi-dbus.conf b/dbus-1/system.d/avahi-dbus.conf new file mode 100644 index 00000000..44b1a670 --- /dev/null +++ b/dbus-1/system.d/avahi-dbus.conf @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dbus-1/system.d/bluetooth.conf b/dbus-1/system.d/bluetooth.conf new file mode 100644 index 00000000..66444515 --- /dev/null +++ b/dbus-1/system.d/bluetooth.conf @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dbus-1/system.d/wpa_supplicant.conf b/dbus-1/system.d/wpa_supplicant.conf new file mode 100644 index 00000000..e375cdc2 --- /dev/null +++ b/dbus-1/system.d/wpa_supplicant.conf @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/debconf.conf b/debconf.conf new file mode 100644 index 00000000..549c1d59 --- /dev/null +++ b/debconf.conf @@ -0,0 +1,83 @@ +# This is the main config file for debconf. It tells debconf where to +# store data. The format of this file is a set of stanzas. Each stanza +# except the first sets up a database for debconf to use. For details, see +# debconf.conf(5) (in the debconf-doc package). +# +# So first things first. This first stanza gives the names of two databases. + +# Debconf will use this database to store the data you enter into it, +# and some other dynamic data. +Config: configdb +# Debconf will use this database to store static template data. +Templates: templatedb + +# World-readable, and accepts everything but passwords. +Name: config +Driver: File +Mode: 644 +Reject-Type: password +Filename: /var/cache/debconf/config.dat + +# Not world readable (the default), and accepts only passwords. +Name: passwords +Driver: File +Mode: 600 +Backup: false +Required: false +Accept-Type: password +Filename: /var/cache/debconf/passwords.dat + +# Set up the configdb database. By default, it consists of a stack of two +# databases, one to hold passwords and one for everything else. +Name: configdb +Driver: Stack +Stack: config, passwords + +# Set up the templatedb database, which is a single flat text file +# by default. +Name: templatedb +Driver: File +Mode: 644 +Filename: /var/cache/debconf/templates.dat + +# Well that was pretty straightforward, and it will be enough for most +# people's needs, but debconf's database drivers can be used to do much +# more interesting things. For example, suppose you want to use config +# data from another host, which is mounted over nfs or perhaps the database +# is accessed via LDAP. You don't want to write to the remote debconf database, +# just read from it, so you still need a local database for local changes. +# +# A remote NFS mounted database, read-only. It is optional; if debconf +# fails to use it it will not abort. +#Name: remotedb +#Driver: DirTree +#Directory: /mnt/otherhost/var/cache/debconf/config +#Readonly: true +#Required: false +# +# A remote LDAP database. It is also read-only. The password is really +# only necessary if the database is not accessible anonymously. +# Option KeyByKey instructs the backend to retrieve keys from the LDAP +# server individually (when they are requested), instead of loading all +# keys at startup. The default is 0, and should only be enabled if you +# want to track accesses to individual keys on the LDAP server side. +#Name: remotedb +#Driver: LDAP +#Server: remotehost +#BaseDN: cn=debconf,dc=domain,dc=com +#BindDN: uid=admin,dc=domain,dc=com +#BindPasswd: secret +#KeyByKey: 0 +# +# A stack consisting of two databases. Values will be read from +# the first database in the stack to contain a value. In this example, +# writes always go to the first database. +#Name: fulldb +#Driver: Stack +#Stack: configdb, remotedb +# +# In this example, we'd use Config: fulldb at the top of the file +# to make it use the combination of the databases. +# +# Even more complex and interesting setups are possible, see the +# debconf.conf(5) page for details. diff --git a/debian_version b/debian_version new file mode 100644 index 00000000..7f0c091e --- /dev/null +++ b/debian_version @@ -0,0 +1 @@ +10.11 diff --git a/default/avahi-daemon b/default/avahi-daemon new file mode 100644 index 00000000..3756df73 --- /dev/null +++ b/default/avahi-daemon @@ -0,0 +1,4 @@ +# 1 = Try to detect unicast dns servers that serve .local and disable avahi in +# that case, 0 = Don't try to detect .local unicast dns servers, can cause +# troubles on misconfigured networks +AVAHI_DAEMON_DETECT_LOCAL=1 diff --git a/default/bluetooth b/default/bluetooth new file mode 100644 index 00000000..5b604a1f --- /dev/null +++ b/default/bluetooth @@ -0,0 +1,20 @@ +# Defaults for bluez + +# start bluetooth on boot? +# compatibility note: if this variable is _not_ found bluetooth will start +BLUETOOTH_ENABLED=1 + +# This setting used to switch HID devices (e.g mouse/keyboad) to HCI mode, that +# is you will have bluetooth functionality from your dongle instead of only +# HID. This is accomplished for supported devices by udev in +# /lib/udev/rules.d/62-bluez-hid2hci.rules by invoking hid2hci with correct +# parameters. +# See /usr/share/doc/bluez/NEWS.Debian.gz for further information. + +# Older daemons like pand dund and hidd can be found in bluez-compat package as +# they are deprecated and provided for backward compatibility only. + +# Note that not every bluetooth dongle is capable of switching back to HID mode, +# see http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=355497 +HID2HCI_ENABLED=0 +HID2HCI_UNDO=0 diff --git a/default/bsdmainutils b/default/bsdmainutils new file mode 100644 index 00000000..e4ac0543 --- /dev/null +++ b/default/bsdmainutils @@ -0,0 +1,4 @@ +# Uncomment the following line if you'd like all of your users' +# ~/calendar files to be checked daily. Calendar will send them mail +# to remind them of upcoming events. See calendar(1) for more details. +#RUN_DAILY=true diff --git a/default/cacerts b/default/cacerts new file mode 100644 index 00000000..d03ec9d1 --- /dev/null +++ b/default/cacerts @@ -0,0 +1,10 @@ +# defaults for ca-certificates-java + +# The password which is used to protect the integrity of the keystore. +# storepass must be at least 6 characters long. It must be provided to +# all commands that access the keystore contents. +# Only change this if adding private certificates. +#storepass='' + +# enable/disable updates of the keystore /etc/ssl/certs/java/cacerts +cacerts_updates=yes diff --git a/default/console-setup b/default/console-setup new file mode 100644 index 00000000..6508cdc5 --- /dev/null +++ b/default/console-setup @@ -0,0 +1,16 @@ +# CONFIGURATION FILE FOR SETUPCON + +# Consult the console-setup(5) manual page. + +ACTIVE_CONSOLES="/dev/tty[1-6]" + +CHARMAP="UTF-8" + +CODESET="guess" +FONTFACE="" +FONTSIZE="" + +VIDEOMODE= + +# The following is an example how to use a braille font +# FONT='lat9w-08.psf.gz brl-8x8.psf' diff --git a/default/crda b/default/crda new file mode 100644 index 00000000..36b62bdc --- /dev/null +++ b/default/crda @@ -0,0 +1,11 @@ +# Set REGDOMAIN to a ISO/IEC 3166-1 alpha2 country code so that iw(8) may set +# the initial regulatory domain setting for IEEE 802.11 devices which operate +# on this system. +# +# Governments assert the right to regulate usage of radio spectrum within +# their respective territories so make sure you select a ISO/IEC 3166-1 alpha2 +# country code suitable for your location or you may infringe on local +# legislature. See `/usr/share/zoneinfo/zone.tab' for a table of timezone +# descriptions containing ISO/IEC 3166-1 alpha2 country codes. + +REGDOMAIN= diff --git a/default/cron b/default/cron new file mode 100644 index 00000000..f62b7be8 --- /dev/null +++ b/default/cron @@ -0,0 +1,28 @@ +# Cron configuration options + +# Whether to read the system's default environment files (if present) +# If set to "yes", cron will set a proper mail charset from the +# locale information. If set to something other than 'yes', the default +# charset 'C' (canonical name: ANSI_X3.4-1968) will be used. +# +# This has no effect on tasks running under cron; their environment can +# only be changed via PAM or from within the crontab; see crontab(5). +READ_ENV="yes" + +# Extra options for cron, see cron(8) +# +# For example, to enable LSB name support in /etc/cron.d/, use +# EXTRA_OPTS='-l' +# +# Or, to log standard messages, plus jobs with exit status != 0: +# EXTRA_OPTS='-L 5' +# +# For quick reference, the currently available log levels are: +# 0 no logging (errors are logged regardless) +# 1 log start of jobs +# 2 log end of jobs +# 4 log jobs with exit status != 0 +# 8 log the process identifier of child process (in all logs) +# +#EXTRA_OPTS="" + diff --git a/default/dbus b/default/dbus new file mode 100644 index 00000000..4bc8e1b6 --- /dev/null +++ b/default/dbus @@ -0,0 +1,7 @@ +# This is a configuration file for /etc/init.d/dbus; it allows you to +# perform common modifications to the behavior of the dbus daemon +# startup without editing the init script (and thus getting prompted +# by dpkg on upgrades). We all love dpkg prompts. + +# Parameters to pass to dbus. +PARAMS="" diff --git a/default/docker b/default/docker new file mode 100644 index 00000000..c4e93199 --- /dev/null +++ b/default/docker @@ -0,0 +1,20 @@ +# Docker Upstart and SysVinit configuration file + +# +# THIS FILE DOES NOT APPLY TO SYSTEMD +# +# Please see the documentation for "systemd drop-ins": +# https://docs.docker.com/engine/admin/systemd/ +# + +# Customize location of Docker binary (especially for development testing). +#DOCKERD="/usr/local/bin/dockerd" + +# Use DOCKER_OPTS to modify the daemon startup options. +#DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4" + +# If you need Docker to use an HTTP proxy, it can also be specified here. +#export http_proxy="http://127.0.0.1:3128/" + +# This is also a handy place to tweak where Docker's temporary files go. +#export DOCKER_TMPDIR="/mnt/bigdrive/docker-tmp" diff --git a/default/exim4 b/default/exim4 new file mode 100644 index 00000000..d46485ed --- /dev/null +++ b/default/exim4 @@ -0,0 +1,24 @@ +# /etc/default/exim4 +EX4DEF_VERSION='' + +# 'combined' - one daemon running queue and listening on SMTP port +# 'no' - no daemon running the queue +# 'separate' - two separate daemons +# 'ppp' - only run queue with /etc/ppp/ip-up.d/exim4. +# 'nodaemon' - no daemon is started at all. +# 'queueonly' - only a queue running daemon is started, no SMTP listener. +# setting this to 'no' will also disable queueruns from /etc/ppp/ip-up.d/exim4 +QUEUERUNNER='combined' +# how often should we run the queue +QUEUEINTERVAL='30m' +# options common to quez-runner and listening daemon +COMMONOPTIONS='' +# more options for the daemon/process running the queue (applies to the one +# started in /etc/ppp/ip-up.d/exim4, too. +QUEUERUNNEROPTIONS='' +# special flags given to exim directly after the -q. See exim(8) +QFLAGS='' +# Options for the SMTP listener daemon. By default, it is listening on +# port 25 only. To listen on more ports, it is recommended to use +# -oX 25:587:10025 -oP /run/exim4/exim.pid +SMTPLISTENEROPTIONS='' diff --git a/default/fake-hwclock b/default/fake-hwclock new file mode 100644 index 00000000..fd667619 --- /dev/null +++ b/default/fake-hwclock @@ -0,0 +1,2 @@ +# Uncomment to set clock even if saved value appears to be in the past +#FORCE=force diff --git a/default/hwclock b/default/hwclock new file mode 100644 index 00000000..dcf5451f --- /dev/null +++ b/default/hwclock @@ -0,0 +1,19 @@ +# Defaults for the hwclock init script. See hwclock(5) and hwclock(8). + +# This is used to specify that the hardware clock incapable of storing +# years outside the range of 1994-1999. Set to yes if the hardware is +# broken or no if working correctly. +#BADYEAR=no + +# Set this to yes if it is possible to access the hardware clock, +# or no if it is not. +#HWCLOCKACCESS=yes + +# Set this to any options you might need to give to hwclock, such +# as machine hardware clock type for Alphas. +#HWCLOCKPARS= + +# Set this to the hardware clock device you want to use, it should +# probably match the CONFIG_RTC_HCTOSYS_DEVICE kernel config option. +#HCTOSYS_DEVICE=rtc0 + diff --git a/default/keyboard b/default/keyboard new file mode 100644 index 00000000..b6e69253 --- /dev/null +++ b/default/keyboard @@ -0,0 +1,10 @@ +# KEYBOARD CONFIGURATION FILE + +# Consult the keyboard(5) manual page. + +XKBMODEL="pc105" +XKBLAYOUT="gb" +XKBVARIANT="" +XKBOPTIONS="" + +BACKSPACE="guess" diff --git a/default/locale b/default/locale new file mode 100644 index 00000000..f99e1622 --- /dev/null +++ b/default/locale @@ -0,0 +1,2 @@ +# File generated by update-locale +LANG=en_GB.UTF-8 diff --git a/default/netfilter-persistent b/default/netfilter-persistent new file mode 100644 index 00000000..7b31799e --- /dev/null +++ b/default/netfilter-persistent @@ -0,0 +1,4 @@ +# Configuration for netfilter-persistent +# Plugins may extend this file or have their own + +FLUSH_ON_STOP=0 diff --git a/default/networking b/default/networking new file mode 100644 index 00000000..96553592 --- /dev/null +++ b/default/networking @@ -0,0 +1,31 @@ +# Configuration for networking init script being run during +# the boot sequence + +# Set to 'no' to skip interfaces configuration on boot +#CONFIGURE_INTERFACES=yes + +# Don't configure these interfaces. Shell wildcards supported/ +#EXCLUDE_INTERFACES= + +# Set to 'yes' to enable additional verbosity +#VERBOSE=no + +# Method to wait for the network to become online, +# for services that depend on a working network: +# - ifup: wait for ifup to have configured an interface. +# - route: wait for a route to a given address to appear. +# - ping/ping6: wait for a host to respond to ping packets. +# - none: don't wait. +#WAIT_ONLINE_METHOD=ifup + +# Which interface to wait for. +# If none given, wait for all auto interfaces, or if there are none, +# wait for at least one hotplug interface. +#WAIT_ONLINE_IFACE= + +# Which address to wait for for route, ping and ping6 methods. +# If none is given for route, it waits for a default gateway. +#WAIT_ONLINE_ADDRESS= + +# Timeout in seconds for waiting for the network to come online. +#WAIT_ONLINE_TIMEOUT=300 diff --git a/default/nfs-common b/default/nfs-common new file mode 100644 index 00000000..0e373e65 --- /dev/null +++ b/default/nfs-common @@ -0,0 +1,19 @@ +# If you do not set values for the NEED_ options, they will be attempted +# autodetected; this should be sufficient for most people. Valid alternatives +# for the NEED_ options are "yes" and "no". + +# Do you want to start the statd daemon? It is not needed for NFSv4. +NEED_STATD= + +# Options for rpc.statd. +# Should rpc.statd listen on a specific port? This is especially useful +# when you have a port-based firewall. To use a fixed port, set this +# this variable to a statd argument like: "--port 4000 --outgoing-port 4001". +# For more information, see rpc.statd(8) or http://wiki.debian.org/SecuringNFS +STATDOPTS= + +# Do you want to start the idmapd daemon? It is only needed for NFSv4. +NEED_IDMAPD= + +# Do you want to start the gssd daemon? It is required for Kerberos mounts. +NEED_GSSD= diff --git a/default/nginx b/default/nginx new file mode 100644 index 00000000..09b8fd0a --- /dev/null +++ b/default/nginx @@ -0,0 +1,10 @@ +# Note: You may want to look at the following page before setting the ULIMIT. +# http://wiki.nginx.org/CoreModule#worker_rlimit_nofile +# Set the ulimit variable if you need defaults to change. +# Example: ULIMIT="-n 4096" +#ULIMIT="-n 4096" + +# Define the stop schedule for nginx +# see the start-stop-daemon --retry documentation for more information +# +#STOP_SCHEDULE="QUIT/5/TERM/5/KILL/5" diff --git a/default/nss b/default/nss new file mode 100644 index 00000000..c43e88b9 --- /dev/null +++ b/default/nss @@ -0,0 +1,37 @@ +# /etc/default/nss +# This file can theoretically contain a bunch of customization variables +# for Name Service Switch in the GNU C library. For now there are only +# four variables: +# +# NETID_AUTHORITATIVE +# If set to TRUE, the initgroups() function will accept the information +# from the netid.byname NIS map as authoritative. This can speed up the +# function significantly if the group.byname map is large. The content +# of the netid.byname map is used AS IS. The system administrator has +# to make sure it is correctly generated. +#NETID_AUTHORITATIVE=TRUE +# +# SERVICES_AUTHORITATIVE +# If set to TRUE, the getservbyname{,_r}() function will assume +# services.byservicename NIS map exists and is authoritative, particularly +# that it contains both keys with /proto and without /proto for both +# primary service names and service aliases. The system administrator +# has to make sure it is correctly generated. +#SERVICES_AUTHORITATIVE=TRUE +# +# SETENT_BATCH_READ +# If set to TRUE, various setXXent() functions will read the entire +# database at once and then hand out the requests one by one from +# memory with every getXXent() call. Otherwise each getXXent() call +# might result into a network communication with the server to get +# the next entry. +#SETENT_BATCH_READ=TRUE +# +# ADJUNCT_AS_SHADOW +# If set to TRUE, the passwd routines in the NIS NSS module will not +# use the passwd.adjunct.byname tables to fill in the password data +# in the passwd structure. This is a security problem if the NIS +# server cannot be trusted to send the passwd.adjuct table only to +# privileged clients. Instead the passwd.adjunct.byname table is +# used to synthesize the shadow.byname table if it does not exist. +ADJUNCT_AS_SHADOW=TRUE diff --git a/default/ntp b/default/ntp new file mode 100644 index 00000000..af78139b --- /dev/null +++ b/default/ntp @@ -0,0 +1 @@ +NTPD_OPTS='-g' diff --git a/default/raspberrypi-kernel b/default/raspberrypi-kernel new file mode 100644 index 00000000..36610827 --- /dev/null +++ b/default/raspberrypi-kernel @@ -0,0 +1,11 @@ +# Defaults for raspberrypi-kernel + +# Uncomment the following line to enable generation of +# /boot/initrd.img-KVER files (requires initramfs-tools) + +#INITRD=Yes + +# Uncomment the following line to enable generation of +# /boot/initrd(7).img files (requires rpi-initramfs-tools) + +#RPI_INITRD=Yes diff --git a/default/redis-server b/default/redis-server new file mode 100644 index 00000000..f98f6c1c --- /dev/null +++ b/default/redis-server @@ -0,0 +1,7 @@ +# redis-server configure options + +# ULIMIT: Call ulimit -n with this argument prior to invoking Redis itself. +# This may be required for high-concurrency environments. Redis itself cannot +# alter its limits as it is not being run as root. (default: 65536) +# +ULIMIT=65536 diff --git a/default/rng-tools b/default/rng-tools new file mode 100644 index 00000000..5a756427 --- /dev/null +++ b/default/rng-tools @@ -0,0 +1,17 @@ +# Configuration for the rng-tools initscript +# $Id: rng-tools.default,v 1.1.2.5 2008-06-10 19:51:37 hmh Exp $ + +# This is a POSIX shell fragment + +# Set to the input source for random data, leave undefined +# for the initscript to attempt auto-detection. Set to /dev/null +# for the viapadlock driver. +#HRNGDEVICE=/dev/hwrng +#HRNGDEVICE=/dev/null + +# Additional options to send to rngd. See the rngd(8) manpage for +# more information. Do not specify -r/--rng-device here, use +# HRNGDEVICE for that instead. +#RNGDOPTIONS="--hrng=intelfwh --fill-watermark=90% --feed-interval=1" +#RNGDOPTIONS="--hrng=viakernel --fill-watermark=90% --feed-interval=1" +#RNGDOPTIONS="--hrng=viapadlock --fill-watermark=90% --feed-interval=1" diff --git a/default/rpi-eeprom-update b/default/rpi-eeprom-update new file mode 100644 index 00000000..9e9d0797 --- /dev/null +++ b/default/rpi-eeprom-update @@ -0,0 +1 @@ +FIRMWARE_RELEASE_STATUS="default" diff --git a/default/rsync b/default/rsync new file mode 100644 index 00000000..424b1c0f --- /dev/null +++ b/default/rsync @@ -0,0 +1,47 @@ +# defaults file for rsync daemon mode +# +# This file is only used for init.d based systems! +# If this system uses systemd, you can specify options etc. for rsync +# in daemon mode by copying /lib/systemd/system/rsync.service to +# /etc/systemd/system/rsync.service and modifying the copy; add required +# options to the ExecStart line. + +# start rsync in daemon mode from init.d script? +# only allowed values are "true", "false", and "inetd" +# Use "inetd" if you want to start the rsyncd from inetd, +# all this does is prevent the init.d script from printing a message +# about not starting rsyncd (you still need to modify inetd's config yourself). +RSYNC_ENABLE=false + +# which file should be used as the configuration file for rsync. +# This file is used instead of the default /etc/rsyncd.conf +# Warning: This option has no effect if the daemon is accessed +# using a remote shell. When using a different file for +# rsync you might want to symlink /etc/rsyncd.conf to +# that file. +# RSYNC_CONFIG_FILE= + +# what extra options to give rsync --daemon? +# that excludes the --daemon; that's always done in the init.d script +# Possibilities are: +# --address=123.45.67.89 (bind to a specific IP address) +# --port=8730 (bind to specified port; default 873) +RSYNC_OPTS='' + +# run rsyncd at a nice level? +# the rsync daemon can impact performance due to much I/O and CPU usage, +# so you may want to run it at a nicer priority than the default priority. +# Allowed values are 0 - 19 inclusive; 10 is a reasonable value. +RSYNC_NICE='' + +# run rsyncd with ionice? +# "ionice" does for IO load what "nice" does for CPU load. +# As rsync is often used for backups which aren't all that time-critical, +# reducing the rsync IO priority will benefit the rest of the system. +# See the manpage for ionice for allowed options. +# -c3 is recommended, this will run rsync IO at "idle" priority. Uncomment +# the next line to activate this. +# RSYNC_IONICE='-c3' + +# Don't forget to create an appropriate config file, +# else the daemon will not start. diff --git a/default/rsyslog b/default/rsyslog new file mode 100644 index 00000000..8ec3ea0b --- /dev/null +++ b/default/rsyslog @@ -0,0 +1,4 @@ +# Options for rsyslogd +# -x disables DNS lookups for remote messages +# See rsyslogd(8) for more details +RSYSLOGD_OPTIONS="" diff --git a/default/snmpd b/default/snmpd new file mode 100644 index 00000000..eede856d --- /dev/null +++ b/default/snmpd @@ -0,0 +1,12 @@ +# This file controls the behaviour of /etc/init.d/snmpd +# but not of the corresponding systemd service file. +# If needed, create an override file in +# /etc/systemd/system/snmpd.service.d/local.conf +# see man 5 systemd.unit and man 5 systemd.service + +# Don't load any MIBs by default. +# You might comment this lines once you have the MIBs downloaded. +export MIBS= + +# snmpd options (use syslog, close stdin/out/err). +#SNMPDOPTS='-Lsd -Lf /dev/null -u Debian-snmp -g Debian-snmp -I -smux,mteTrigger,mteTriggerConf -p /run/snmpd.pid' diff --git a/default/ssh b/default/ssh new file mode 100644 index 00000000..30404222 --- /dev/null +++ b/default/ssh @@ -0,0 +1,5 @@ +# Default settings for openssh-server. This file is sourced by /bin/sh from +# /etc/init.d/ssh. + +# Options to pass to sshd +SSHD_OPTS= diff --git a/default/sysstat b/default/sysstat new file mode 100644 index 00000000..dfeb7e01 --- /dev/null +++ b/default/sysstat @@ -0,0 +1,10 @@ +# +# Default settings for /etc/init.d/sysstat, /etc/cron.d/sysstat +# and /etc/cron.daily/sysstat files +# + +# Should sadc collect system activity informations? Valid values +# are "true" and "false". Please do not put other values, they +# will be overwritten by debconf! +ENABLED="false" + diff --git a/default/tftpd-hpa b/default/tftpd-hpa new file mode 100644 index 00000000..cf06c2f2 --- /dev/null +++ b/default/tftpd-hpa @@ -0,0 +1,6 @@ +# /etc/default/tftpd-hpa + +TFTP_USERNAME="tftp" +TFTP_DIRECTORY="/srv/tftp" +TFTP_ADDRESS="0.0.0.0:69" +TFTP_OPTIONS="--secure" diff --git a/default/triggerhappy b/default/triggerhappy new file mode 100644 index 00000000..002dcf92 --- /dev/null +++ b/default/triggerhappy @@ -0,0 +1,17 @@ +# Defaults for triggerhappy initscript +# sourced by /etc/init.d/triggerhappy +# installed at /etc/default/triggerhappy by the maintainer scripts + +# +# This is a POSIX shell fragment +# + +# Additional options that are passed to the Daemon. +DAEMON_OPTS="" + +# The Triggerhappy daemon (thd) drops its root privileges after +# startup and becomes "nobody". If you want it to retain its root +# status (e.g. to run commands only accessible to the system user), +# uncomment the following line or specifiy the user option yourself: +# +# DAEMON_OPTS="--user root" diff --git a/default/useradd b/default/useradd new file mode 100644 index 00000000..9738ccb8 --- /dev/null +++ b/default/useradd @@ -0,0 +1,37 @@ +# Default values for useradd(8) +# +# The SHELL variable specifies the default login shell on your +# system. +# Similar to DHSELL in adduser. However, we use "sh" here because +# useradd is a low level utility and should be as general +# as possible +SHELL=/bin/bash +# +# The default group for users +# 100=users on Debian systems +# Same as USERS_GID in adduser +# This argument is used when the -n flag is specified. +# The default behavior (when -n and -g are not specified) is to create a +# primary user group with the same name as the user being added to the +# system. +# GROUP=100 +# +# The default home directory. Same as DHOME for adduser +# HOME=/home +# +# The number of days after a password expires until the account +# is permanently disabled +# INACTIVE=-1 +# +# The default expire date +# EXPIRE= +# +# The SKEL variable specifies the directory containing "skeletal" user +# files; in other words, files such as a sample .profile that will be +# copied to the new user's home directory when it is created. +SKEL=/etc/skel +# +# Defines whether the mail spool should be created while +# creating the account +# CREATE_MAIL_SPOOL=yes + diff --git a/default/xinetd b/default/xinetd new file mode 100644 index 00000000..20a38e3f --- /dev/null +++ b/default/xinetd @@ -0,0 +1,12 @@ +# Default settings for xinetd. This file is sourced by /bin/sh from +# /etc/init.d/xinetd + +# enable xinetd Inetd compat mode +INETD_COMPAT=Yes + +# Options to pass to xinetd +# +# -stayalive comes by default : it can be removed if xinetd is expected +# not to start when no service is configured +# +XINETD_OPTS="-stayalive" diff --git a/deluser.conf b/deluser.conf new file mode 100644 index 00000000..fff8d813 --- /dev/null +++ b/deluser.conf @@ -0,0 +1,20 @@ +# /etc/deluser.conf: `deluser' configuration. + +# Remove home directory and mail spool when user is removed +REMOVE_HOME = 0 + +# Remove all files on the system owned by the user to be removed +REMOVE_ALL_FILES = 0 + +# Backup files before removing them. This options has only an effect if +# REMOVE_HOME or REMOVE_ALL_FILES is set. +BACKUP = 0 + +# target directory for the backup file +BACKUP_TO = "." + +# delete a group even there are still users in this group +ONLY_IF_EMPTY = 0 + +# exclude these filesystem types when searching for files of a user to backup +EXCLUDE_FSTYPES = "(proc|sysfs|usbfs|devpts|tmpfs|afs)" diff --git a/dhcp/debug b/dhcp/debug new file mode 100644 index 00000000..593e7df2 --- /dev/null +++ b/dhcp/debug @@ -0,0 +1,38 @@ +# +# The purpose of this script is just to show the variables that are +# available to all the scripts in this directory. All these scripts are +# called from dhclient-script, which exports all the variables shown +# before. If you want to debug a problem with your DHCP setup you can +# enable this script and take a look at /tmp/dhclient-script.debug. + +# To enable this script set the following variable to "yes" +RUN="no" + +if [ "$RUN" = "yes" ]; then + echo "$(date): entering ${1%/*}, dumping variables." \ + >> /tmp/dhclient-script.debug + + # loop over the 4 possible prefixes: (empty), cur_, new_, old_ + for prefix in '' 'cur_' 'new_' 'old_'; do + # loop over the DHCP variables passed to dhclient-script + for basevar in reason interface medium alias_ip_address \ + ip_address host_name network_number subnet_mask \ + broadcast_address routers static_routes \ + rfc3442_classless_static_routes \ + domain_name domain_search domain_name_servers \ + netbios_name_servers netbios_scope \ + ntp_servers \ + ip6_address ip6_prefix ip6_prefixlen \ + dhcp6_domain_search dhcp6_name_servers ; do + var="${prefix}${basevar}" + eval "content=\$$var" + + # show only variables with values set + if [ -n "${content}" ]; then + echo "$var='${content}'" >> /tmp/dhclient-script.debug + fi + done + done + + echo '--------------------------' >> /tmp/dhclient-script.debug +fi diff --git a/dhcp/dhclient-enter-hooks.d/debug b/dhcp/dhclient-enter-hooks.d/debug new file mode 120000 index 00000000..ee34fdcc --- /dev/null +++ b/dhcp/dhclient-enter-hooks.d/debug @@ -0,0 +1 @@ +../debug \ No newline at end of file diff --git a/dhcp/dhclient-enter-hooks.d/resolvconf b/dhcp/dhclient-enter-hooks.d/resolvconf new file mode 100644 index 00000000..72b2be7c --- /dev/null +++ b/dhcp/dhclient-enter-hooks.d/resolvconf @@ -0,0 +1,81 @@ +# +# Script fragment to make dhclient supply nameserver information to resolvconf +# + +# Tips: +# * Be careful about changing the environment since this is sourced +# * This script fragment uses bash features +# * As of isc-dhcp-client 4.2 the "reason" (for running the script) can be one of the following. +# (Listed on man page:) MEDIUM(0) PREINIT(0) BOUND(M) RENEW(M) REBIND(M) REBOOT(M) EXPIRE(D) FAIL(D) RELEASE(D) STOP(D) NBI(-) TIMEOUT(M) +# (Also used in master script:) ARPCHECK(0), ARPSEND(0) +# (Also used in master script:) PREINIT6(0) BOUND6(M) RENEW6(M) REBIND6(M) DEPREF6(0) EXPIRE6(D) RELEASE6(D) STOP6(D) +# (0) = master script does not run make_resolv_conf +# (M) = master script runs make_resolv_conf +# (D) = master script downs interface +# (-) = master script does nothing with this + +if [ -x /sbin/resolvconf ] ; then + # For safety, first undefine the nasty default make_resolv_conf() + make_resolv_conf() { : ; } + case "$reason" in + BOUND|RENEW|REBIND|REBOOT|TIMEOUT) + # Define a resolvconf-compatible m_r_c() function + # It gets run later (or, in the TIMEOUT case, MAY get run later) + make_resolv_conf() { + local R + local N + R="" + if [ "$new_domain_name_servers" ] && [ "$new_domain_name" ] ; then + R="${R}domain $new_domain_name +" + fi + if [ "$new_domain_name_servers" ] && [ "$new_domain_search" ] ; then + R="${R}search $new_domain_search +" + fi + for N in $new_domain_name_servers ; do + R="${R}nameserver $N +" + done + [ ! "$interface" ] || echo -n "$R" | /sbin/resolvconf -a "${interface}.dhclient" + } + ;; + BOUND6|RENEW6|REBIND6) + # Define a resolvconf-compatible m_r_c() function + # It gets run later (or, in the TIMEOUT case, MAY get run later) + make_resolv_conf() { + local R + local N + local N_LOW + local ZONE_ID + R="" + if [ "$new_dhcp6_name_servers" ] && [ "$new_dhcp6_domain_search" ] ; then + R="${R}search $new_dhcp6_domain_search +" + fi + for N in $new_dhcp6_name_servers ; do + + # If the nameserver has a link-local address + # then add a zone ID (interface name) to it. + N_LOW="$(echo "$N" | tr '[:upper:]' '[:lower:]')" + if expr "$N_LOW" : ^fe80:: >/dev/null ; then + ZONE_ID="%$interface" + else + ZONE_ID="" + fi + R="${R}nameserver $N$ZONE_ID +" + done + [ ! "$interface" ] || echo -n "$R" | /sbin/resolvconf -a "${interface}.ip6.dhclient" + } + ;; + EXPIRE|FAIL|RELEASE|STOP) + # Delete resolv.conf info + [ ! "$interface" ] || /sbin/resolvconf -d "${interface}.dhclient" + ;; + EXPIRE6|RELEASE6|STOP6) + # Delete resolv.conf info + [ ! "$interface" ] || /sbin/resolvconf -d "${interface}.ip6.dhclient" + ;; + esac +fi diff --git a/dhcp/dhclient-exit-hooks.d/debug b/dhcp/dhclient-exit-hooks.d/debug new file mode 120000 index 00000000..ee34fdcc --- /dev/null +++ b/dhcp/dhclient-exit-hooks.d/debug @@ -0,0 +1 @@ +../debug \ No newline at end of file diff --git a/dhcp/dhclient-exit-hooks.d/ntp b/dhcp/dhclient-exit-hooks.d/ntp new file mode 100644 index 00000000..eedf6d92 --- /dev/null +++ b/dhcp/dhclient-exit-hooks.d/ntp @@ -0,0 +1,64 @@ +NTP_CONF=/etc/ntp.conf +NTP_DHCP_CONF=/run/ntp.conf.dhcp + + +ntp_server_restart() { + invoke-rc.d ntp try-restart +} + + +ntp_servers_setup_remove() { + if [ ! -e $NTP_DHCP_CONF ]; then + return + fi + rm -f $NTP_DHCP_CONF + ntp_server_restart +} + + +ntp_servers_setup_add() { + if [ -e $NTP_DHCP_CONF ] && [ "$new_ntp_servers" = "$old_ntp_servers" ]; then + return + fi + + if [ -z "$new_ntp_servers" ]; then + ntp_servers_setup_remove + return + fi + + tmp=$(mktemp "$NTP_DHCP_CONF.XXXXXX") || return + chmod --reference=$NTP_CONF $tmp + chown --reference=$NTP_CONF $tmp + + ( + echo "# This file was copied from $NTP_CONF with the server options changed" + echo "# to reflect the information sent by the DHCP server. Any changes made" + echo "# here will be lost at the next DHCP event. Edit $NTP_CONF instead." + echo + echo "# NTP server entries received from DHCP server" + for server in $new_ntp_servers; do + echo "server $server iburst" + done + echo + sed '/^[[:space:]]*\(server\|peer\|pool\)[[:space:]]/d' $NTP_CONF + ) >>$tmp + + mv $tmp $NTP_DHCP_CONF + + ntp_server_restart +} + + +ntp_servers_setup() { + case $reason in + BOUND|RENEW|REBIND|REBOOT) + ntp_servers_setup_add + ;; + EXPIRE|FAIL|RELEASE|STOP) + ntp_servers_setup_remove + ;; + esac +} + + +ntp_servers_setup diff --git a/dhcp/dhclient-exit-hooks.d/rfc3442-classless-routes b/dhcp/dhclient-exit-hooks.d/rfc3442-classless-routes new file mode 100644 index 00000000..1ef7b8a2 --- /dev/null +++ b/dhcp/dhclient-exit-hooks.d/rfc3442-classless-routes @@ -0,0 +1,78 @@ +# set classless routes based on the format specified in RFC3442 +# e.g.: +# new_rfc3442_classless_static_routes='24 192 168 10 192 168 1 1 8 10 10 17 66 41' +# specifies the routes: +# 192.168.10.0/24 via 192.168.1.1 +# 10.0.0.0/8 via 10.10.17.66.41 + +RUN="yes" + + +if [ "$RUN" = "yes" ]; then + if [ -n "$new_rfc3442_classless_static_routes" ]; then + if [ "$reason" = "BOUND" ] || [ "$reason" = "REBOOT" ]; then + + set -- $new_rfc3442_classless_static_routes + + while [ $# -gt 0 ]; do + net_length=$1 + via_arg='' + + case $net_length in + 32|31|30|29|28|27|26|25) + if [ $# -lt 9 ]; then + return 1 + fi + net_address="${2}.${3}.${4}.${5}" + gateway="${6}.${7}.${8}.${9}" + shift 9 + ;; + 24|23|22|21|20|19|18|17) + if [ $# -lt 8 ]; then + return 1 + fi + net_address="${2}.${3}.${4}.0" + gateway="${5}.${6}.${7}.${8}" + shift 8 + ;; + 16|15|14|13|12|11|10|9) + if [ $# -lt 7 ]; then + return 1 + fi + net_address="${2}.${3}.0.0" + gateway="${4}.${5}.${6}.${7}" + shift 7 + ;; + 8|7|6|5|4|3|2|1) + if [ $# -lt 6 ]; then + return 1 + fi + net_address="${2}.0.0.0" + gateway="${3}.${4}.${5}.${6}" + shift 6 + ;; + 0) # default route + if [ $# -lt 5 ]; then + return 1 + fi + net_address="0.0.0.0" + gateway="${2}.${3}.${4}.${5}" + shift 5 + ;; + *) # error + return 1 + ;; + esac + + # take care of link-local routes + if [ "${gateway}" != '0.0.0.0' ]; then + via_arg="via ${gateway}" + fi + + # set route (ip detects host routes automatically) + ip -4 route add "${net_address}/${net_length}" \ + ${via_arg} dev "${interface}" >/dev/null 2>&1 + done + fi + fi +fi diff --git a/dhcp/dhclient-exit-hooks.d/timesyncd b/dhcp/dhclient-exit-hooks.d/timesyncd new file mode 100644 index 00000000..3cde9929 --- /dev/null +++ b/dhcp/dhclient-exit-hooks.d/timesyncd @@ -0,0 +1,42 @@ +TIMESYNCD_CONF=/run/systemd/timesyncd.conf.d/01-dhclient.conf + +timesyncd_servers_setup_remove() { + if [ -e $TIMESYNCD_CONF ]; then + rm -f $TIMESYNCD_CONF + systemctl try-restart systemd-timesyncd.service || true + fi +} + +timesyncd_servers_setup_add() { + if [ ! -d /run/systemd/system ]; then + return + fi + + if [ -e $TIMESYNCD_CONF ] && [ "$new_ntp_servers" = "$old_ntp_servers" ]; then + return + fi + + if [ -z "$new_ntp_servers" ]; then + timesyncd_servers_setup_remove + return + fi + + mkdir -p $(dirname $TIMESYNCD_CONF) + cat < ${TIMESYNCD_CONF}.new +# NTP server entries received from DHCP server +[Time] +NTP=$new_ntp_servers +EOF + mv ${TIMESYNCD_CONF}.new ${TIMESYNCD_CONF} + systemctl try-restart systemd-timesyncd.service || true +} + + +case $reason in + BOUND|RENEW|REBIND|REBOOT) + timesyncd_servers_setup_add + ;; + EXPIRE|FAIL|RELEASE|STOP) + timesyncd_servers_setup_remove + ;; +esac diff --git a/dhcp/dhclient.conf b/dhcp/dhclient.conf new file mode 100644 index 00000000..b85301b1 --- /dev/null +++ b/dhcp/dhclient.conf @@ -0,0 +1,54 @@ +# Configuration file for /sbin/dhclient. +# +# This is a sample configuration file for dhclient. See dhclient.conf's +# man page for more information about the syntax of this file +# and a more comprehensive list of the parameters understood by +# dhclient. +# +# Normally, if the DHCP server provides reasonable information and does +# not leave anything out (like the domain name, for example), then +# few changes must be made to this file, if any. +# + +option rfc3442-classless-static-routes code 121 = array of unsigned integer 8; + +send host-name = gethostname(); +request subnet-mask, broadcast-address, time-offset, routers, + domain-name, domain-name-servers, domain-search, host-name, + dhcp6.name-servers, dhcp6.domain-search, dhcp6.fqdn, dhcp6.sntp-servers, + netbios-name-servers, netbios-scope, interface-mtu, + rfc3442-classless-static-routes, ntp-servers; + +#send dhcp-client-identifier 1:0:a0:24:ab:fb:9c; +#send dhcp-lease-time 3600; +#supersede domain-name "fugue.com home.vix.com"; +#prepend domain-name-servers 127.0.0.1; +#require subnet-mask, domain-name-servers; +#timeout 60; +#retry 60; +#reboot 10; +#select-timeout 5; +#initial-interval 2; +#script "/sbin/dhclient-script"; +#media "-link0 -link1 -link2", "link0 link1"; +#reject 192.33.137.209; + +#alias { +# interface "eth0"; +# fixed-address 192.5.5.213; +# option subnet-mask 255.255.255.255; +#} + +#lease { +# interface "eth0"; +# fixed-address 192.33.137.200; +# medium "link0 link1"; +# option host-name "andare.swiftmedia.com"; +# option subnet-mask 255.255.255.0; +# option broadcast-address 192.33.137.255; +# option routers 192.33.137.250; +# option domain-name-servers 127.0.0.1; +# renew 2 2000/1/12 00:00:01; +# rebind 2 2000/1/12 00:00:01; +# expire 2 2000/1/12 00:00:01; +#} diff --git a/dhcpcd.conf b/dhcpcd.conf new file mode 100644 index 00000000..a4f33d56 --- /dev/null +++ b/dhcpcd.conf @@ -0,0 +1,63 @@ +# A sample configuration for dhcpcd. +# See dhcpcd.conf(5) for details. + +# Allow users of this group to interact with dhcpcd via the control socket. +#controlgroup wheel + +# Inform the DHCP server of our hostname for DDNS. +hostname + +# Use the hardware address of the interface for the Client ID. +clientid +# or +# Use the same DUID + IAID as set in DHCPv6 for DHCPv4 ClientID as per RFC4361. +# Some non-RFC compliant DHCP servers do not reply with this set. +# In this case, comment out duid and enable clientid above. +#duid + +# Persist interface configuration when dhcpcd exits. +persistent + +# Rapid commit support. +# Safe to enable by default because it requires the equivalent option set +# on the server to actually work. +option rapid_commit + +# A list of options to request from the DHCP server. +option domain_name_servers, domain_name, domain_search, host_name +option classless_static_routes +# Respect the network MTU. This is applied to DHCP routes. +option interface_mtu + +# Most distributions have NTP support. +#option ntp_servers + +# A ServerID is required by RFC2131. +require dhcp_server_identifier + +# Generate SLAAC address using the Hardware Address of the interface +#slaac hwaddr +# OR generate Stable Private IPv6 Addresses based from the DUID +slaac private + +# Example static IP configuration: +#interface eth0 +static ip_address=192.168.0.28/24 +#static ip6_address=fd51:42f8:caae:d92e::ff/64 +static routers=192.168.0.1 +static domain_name_servers=127.0.0.1 192.168.0.1 + +# It is possible to fall back to a static IP if DHCP fails: +# define static profile +#profile static_eth0 +#static ip_address=192.168.1.23/24 +#static routers=192.168.1.1 +#static domain_name_servers=192.168.1.1 + +# fallback to static profile on eth0 +#interface eth0 +#fallback static_eth0 +#interface wlan0 +# static ip_address=192.168.0.28/24 +# static routers=192.168.0.1 +# static domain_name_servers=127.0.0.1 diff --git a/dkms/framework.conf b/dkms/framework.conf new file mode 100644 index 00000000..852f3b7c --- /dev/null +++ b/dkms/framework.conf @@ -0,0 +1,28 @@ +## This configuration file modifies the behavior of +## DKMS (Dynamic Kernel Module Support) and is sourced +## in by DKMS every time it is run. + +## Source Tree Location (default: /usr/src) +# source_tree="/usr/src" + +## DKMS Tree Location (default: /var/lib/dkms) +# dkms_tree="/var/lib/dkms" + +## Install Tree Location (default: /lib/modules) +# install_tree="/lib/modules" + +## tmp Location (default: /tmp) +# tmp_location="/tmp" + +## verbosity setting (verbose will be active if you set it to a non-null value) +# verbose="" + +## symlink kernel modules (will be active if you set it to a non-null value) +## This creates symlinks from the install_tree into the dkms_tree instead of +## copying the modules. This preserves some space on the costs of being less +## safe. +# symlink_modules="" + +## Automatic installation and upgrade for all installed kernels (if set to a +## non-null value) +# autoinstall_all_kernels="" diff --git a/dkms/template-dkms-mkbmdeb/Makefile b/dkms/template-dkms-mkbmdeb/Makefile new file mode 100644 index 00000000..210b9984 --- /dev/null +++ b/dkms/template-dkms-mkbmdeb/Makefile @@ -0,0 +1,18 @@ +#/usr/bin/make +SRC = $(DESTDIR)/usr/src +SHARE = $(DESTDIR)/usr/share/$(NAME)-dkms + +all: + +clean: + +install: + +#tarball, possibly with binaries +ifeq ("$(wildcard $(NAME)-$(VERSION).dkms.tar.gz)", "$(NAME)-$(VERSION).dkms.tar.gz") + tar zxvf "$(NAME)-$(VERSION).dkms.tar.gz" + install -d "$(DESTDIR)/lib/modules/$(KVER)/updates/dkms/" + install -m 644 dkms_main_tree/$(KVER)/$(KARCH)/module/*.ko "$(DESTDIR)/lib/modules/$(KVER)/updates/dkms/" + rm -rf dkms_main_tree/ dkms_binaries_only/ +endif + diff --git a/dkms/template-dkms-mkbmdeb/debian/README.Debian b/dkms/template-dkms-mkbmdeb/debian/README.Debian new file mode 100644 index 00000000..f8495d91 --- /dev/null +++ b/dkms/template-dkms-mkbmdeb/debian/README.Debian @@ -0,0 +1,5 @@ +MODULE_NAME DKMS module for Debian + +This package was automatically generated by the DKMS system, +for distribution on Debian based operating systems. + diff --git a/dkms/template-dkms-mkbmdeb/debian/changelog b/dkms/template-dkms-mkbmdeb/debian/changelog new file mode 100644 index 00000000..b6cc91d8 --- /dev/null +++ b/dkms/template-dkms-mkbmdeb/debian/changelog @@ -0,0 +1,6 @@ +DEBIAN_PACKAGE-dkms-bin (MODULE_VERSION) stable; urgency=low + + * Automatically packaged by DKMS. + + -- Dynamic Kernel Modules Support Team DATE_STAMP + diff --git a/dkms/template-dkms-mkbmdeb/debian/compat b/dkms/template-dkms-mkbmdeb/debian/compat new file mode 100644 index 00000000..7f8f011e --- /dev/null +++ b/dkms/template-dkms-mkbmdeb/debian/compat @@ -0,0 +1 @@ +7 diff --git a/dkms/template-dkms-mkbmdeb/debian/control b/dkms/template-dkms-mkbmdeb/debian/control new file mode 100644 index 00000000..ef239751 --- /dev/null +++ b/dkms/template-dkms-mkbmdeb/debian/control @@ -0,0 +1,14 @@ +Source: DEBIAN_PACKAGE-dkms-bin +Section: misc +Priority: optional +Maintainer: Dynamic Kernel Modules Support Team +Build-Depends: debhelper (>= 7), dkms +Standards-Version: 3.8.1 + +Package: DEBIAN_PACKAGE-modules-KERNEL_VERSION +Architecture: DEBIAN_BUILD_ARCH +Depends: ${misc:Depends}, linux-image-KERNEL_VERSION +Provides: DEBIAN_PACKAGE-modules +Description: DEBIAN_PACKAGE binary drivers for linux-image-KERNEL_VERSION + This package contains DEBIAN_PACKAGE drivers for the KERNEL_VERSION Linux kernel, + built from DEBIAN_PACKAGE-dkms for the DEBIAN_BUILD_ARCH architecture. diff --git a/dkms/template-dkms-mkbmdeb/debian/copyright b/dkms/template-dkms-mkbmdeb/debian/copyright new file mode 100644 index 00000000..ad983f3d --- /dev/null +++ b/dkms/template-dkms-mkbmdeb/debian/copyright @@ -0,0 +1,2 @@ + +This copyright has not been completed by the author of this package. diff --git a/dkms/template-dkms-mkbmdeb/debian/rules b/dkms/template-dkms-mkbmdeb/debian/rules new file mode 100755 index 00000000..5cd07317 --- /dev/null +++ b/dkms/template-dkms-mkbmdeb/debian/rules @@ -0,0 +1,58 @@ +#!/usr/bin/make -f +# -*- makefile -*- + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +DEB_NAME=DEBIAN_PACKAGE +NAME=MODULE_NAME +VERSION=MODULE_VERSION +KVER=KERNEL_VERSION + +configure: configure-stamp +configure-stamp: + dh_testdir + touch configure-stamp + + +build: build-stamp + +build-stamp: configure-stamp + dh_testdir + $(MAKE) + touch $@ + +clean: + dh_testdir + dh_testroot + rm -f build-stamp configure-stamp + -$(MAKE) clean + dh_clean + +install: build + dh_testdir + dh_testroot + dh_prep + dh_installdirs + $(MAKE) DESTDIR=$(CURDIR)/debian/$(DEB_NAME)-modules-$(KVER) NAME=$(NAME) VERSION=$(VERSION) install + +binary-arch: build install + +binary-indep: build install + dh_testdir + dh_testroot + dh_link + dh_strip + dh_compress + dh_installmodules + dh_installdocs + dh_installchangelogs + dh_fixperms + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure diff --git a/dkms/template-dkms-mkdeb/Makefile b/dkms/template-dkms-mkdeb/Makefile new file mode 100644 index 00000000..57e13d83 --- /dev/null +++ b/dkms/template-dkms-mkdeb/Makefile @@ -0,0 +1,28 @@ +#/usr/bin/make +SRC = $(DESTDIR)/usr/src +SHARE = $(DESTDIR)/usr/share/$(NAME)-dkms + +all: + +clean: + +install: + +#source tree +ifeq ("$(wildcard $(NAME)-$(VERSION))", "$(NAME)-$(VERSION)") + install -d "$(SRC)" + cp -a $(NAME)-$(VERSION) $(SRC) + chmod 644 -R "$(SRC)/$(NAME)-$(VERSION)" +endif + +#tarball, possibly with binaries +ifeq ("$(wildcard $(NAME)-$(VERSION).dkms.tar.gz)", "$(NAME)-$(VERSION).dkms.tar.gz") + install -d "$(SHARE)" + install -m 644 $(NAME)-$(VERSION).dkms.tar.gz "$(SHARE)" +endif + +#postinst, only if we are supporting legacy mode +ifeq ("$(wildcard common.postinst)", "common.postinst") + install -d "$(SHARE)" + install -m 755 $(PREFIX)/usr/lib/dkms/common.postinst $(SHARE)/postinst +endif diff --git a/dkms/template-dkms-mkdeb/debian/README.Debian b/dkms/template-dkms-mkdeb/debian/README.Debian new file mode 100644 index 00000000..f8495d91 --- /dev/null +++ b/dkms/template-dkms-mkdeb/debian/README.Debian @@ -0,0 +1,5 @@ +MODULE_NAME DKMS module for Debian + +This package was automatically generated by the DKMS system, +for distribution on Debian based operating systems. + diff --git a/dkms/template-dkms-mkdeb/debian/changelog b/dkms/template-dkms-mkdeb/debian/changelog new file mode 100644 index 00000000..2434da03 --- /dev/null +++ b/dkms/template-dkms-mkdeb/debian/changelog @@ -0,0 +1,6 @@ +DEBIAN_PACKAGE-dkms (MODULE_VERSION) stable; urgency=low + + * Automatically packaged by DKMS. + + -- Dynamic Kernel Modules Support Team DATE_STAMP + diff --git a/dkms/template-dkms-mkdeb/debian/compat b/dkms/template-dkms-mkdeb/debian/compat new file mode 100644 index 00000000..7f8f011e --- /dev/null +++ b/dkms/template-dkms-mkdeb/debian/compat @@ -0,0 +1 @@ +7 diff --git a/dkms/template-dkms-mkdeb/debian/control b/dkms/template-dkms-mkdeb/debian/control new file mode 100644 index 00000000..1fe029a4 --- /dev/null +++ b/dkms/template-dkms-mkdeb/debian/control @@ -0,0 +1,11 @@ +Source: DEBIAN_PACKAGE-dkms +Section: misc +Priority: optional +Maintainer: Dynamic Kernel Modules Support Team +Build-Depends: debhelper (>= 7), dkms +Standards-Version: 3.8.1 + +Package: DEBIAN_PACKAGE-dkms +Architecture: DEBIAN_BUILD_ARCH +Depends: dkms (>= 1.95), ${misc:Depends} +Description: DEBIAN_PACKAGE driver in DKMS format. diff --git a/dkms/template-dkms-mkdeb/debian/copyright b/dkms/template-dkms-mkdeb/debian/copyright new file mode 100644 index 00000000..ad983f3d --- /dev/null +++ b/dkms/template-dkms-mkdeb/debian/copyright @@ -0,0 +1,2 @@ + +This copyright has not been completed by the author of this package. diff --git a/dkms/template-dkms-mkdeb/debian/dirs b/dkms/template-dkms-mkdeb/debian/dirs new file mode 100644 index 00000000..b601f22c --- /dev/null +++ b/dkms/template-dkms-mkdeb/debian/dirs @@ -0,0 +1 @@ +usr/src diff --git a/dkms/template-dkms-mkdeb/debian/postinst b/dkms/template-dkms-mkdeb/debian/postinst new file mode 100755 index 00000000..c4ad0da4 --- /dev/null +++ b/dkms/template-dkms-mkdeb/debian/postinst @@ -0,0 +1,49 @@ +#!/bin/sh +# Copyright (C) 2002-2005 Flavio Stanchina +# Copyright (C) 2005-2006 Aric Cyr +# Copyright (C) 2007 Mario Limonciello +# Copyright (C) 2009 Alberto Milone + +set -e + +NAME=MODULE_NAME +PACKAGE_NAME=$NAME-dkms +DEB_NAME=$(echo $PACKAGE_NAME | sed 's,_,-,') +CVERSION=`dpkg-query -W -f='${Version}' $DEB_NAME | awk -F "-" '{print $1}' | cut -d\: -f2` +ARCH=`dpkg --print-architecture` + +dkms_configure () { + for POSTINST in /usr/lib/dkms/common.postinst "/usr/share/$PACKAGE_NAME/postinst"; do + if [ -f "$POSTINST" ]; then + "$POSTINST" "$NAME" "$CVERSION" "/usr/share/$PACKAGE_NAME" "$ARCH" "$2" + return $? + fi + echo "WARNING: $POSTINST does not exist." >&2 + done + echo "ERROR: DKMS version is too old and $PACKAGE_NAME was not" >&2 + echo "built with legacy DKMS support." >&2 + echo "You must either rebuild $PACKAGE_NAME with legacy postinst" >&2 + echo "support or upgrade DKMS to a more current version." >&2 + return 1 +} + +case "$1" in + configure) + dkms_configure + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/dkms/template-dkms-mkdeb/debian/prerm b/dkms/template-dkms-mkdeb/debian/prerm new file mode 100755 index 00000000..f42d2931 --- /dev/null +++ b/dkms/template-dkms-mkdeb/debian/prerm @@ -0,0 +1,28 @@ +#!/bin/sh + +NAME=MODULE_NAME +VERSION=MODULE_VERSION + +set -e + +case "$1" in + remove|upgrade|deconfigure) + if [ "`dkms status -m $NAME`" ]; then + dkms remove -m $NAME -v $VERSION --all + fi + ;; + + failed-upgrade) + ;; + + *) + echo "prerm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +#DEBHELPER# + +exit 0 + + diff --git a/dkms/template-dkms-mkdeb/debian/rules b/dkms/template-dkms-mkdeb/debian/rules new file mode 100755 index 00000000..7426e582 --- /dev/null +++ b/dkms/template-dkms-mkdeb/debian/rules @@ -0,0 +1,54 @@ +#!/usr/bin/make -f +# -*- makefile -*- + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +DEB_NAME=DEBIAN_PACKAGE +NAME=MODULE_NAME +VERSION=MODULE_VERSION + +configure: configure-stamp +configure-stamp: + dh_testdir + touch configure-stamp + + +build: build-stamp + +build-stamp: configure-stamp + dh_testdir + $(MAKE) + touch $@ + +clean: + dh_testdir + dh_testroot + rm -f build-stamp configure-stamp + -$(MAKE) clean + dh_clean + +install: build + dh_testdir + dh_testroot + dh_prep + dh_installdirs + $(MAKE) DESTDIR=$(CURDIR)/debian/$(DEB_NAME)-dkms NAME=$(NAME) VERSION=$(VERSION) install + +binary-arch: build install + +binary-indep: build install + dh_testdir + dh_testroot + dh_link + dh_strip + dh_compress + dh_fixperms + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure diff --git a/docker/daemon.json b/docker/daemon.json new file mode 100644 index 00000000..a1e1069f --- /dev/null +++ b/docker/daemon.json @@ -0,0 +1,3 @@ +{ + "data-root": "/docker" +} diff --git a/docker/key.json b/docker/key.json new file mode 100644 index 00000000..39a4de54 --- /dev/null +++ b/docker/key.json @@ -0,0 +1 @@ +{"crv":"P-256","d":"7HdxqdNOrIKjkfFO-jTpk1eTz9L1N8oyal3VA9nKAZE","kid":"YGGU:PNW6:KD4R:FHGZ:GIGV:F54K:V5CE:XNJJ:JYLL:44CK:6T3I:QTUI","kty":"EC","x":"plxSJl26J4-VsLAyLHzoqYLDwVQeBbQdFWtSybP6ym0","y":"w1yqg6dq_xSMQ6haecdx8spp1Fh4WutX23mx-mnLJ0c"} \ No newline at end of file diff --git a/dphys-swapfile b/dphys-swapfile new file mode 100644 index 00000000..fd97b748 --- /dev/null +++ b/dphys-swapfile @@ -0,0 +1,26 @@ +# /etc/dphys-swapfile - user settings for dphys-swapfile package +# author Neil Franklin, last modification 2010.05.05 +# copyright ETH Zuerich Physics Departement +# use under either modified/non-advertising BSD or GPL license + +# this file is sourced with . so full normal sh syntax applies + +# the default settings are added as commented out CONF_*=* lines + + +# where we want the swapfile to be, this is the default +#CONF_SWAPFILE=/var/swap + +# set size to absolute value, leaving empty (default) then uses computed value +# you most likely don't want this, unless you have an special disk situation +CONF_SWAPSIZE=2048 + +# set size to computed value, this times RAM size, dynamically adapts, +# guarantees that there is enough swap without wasting disk space on excess +#CONF_SWAPFACTOR=2 + +# restrict size (computed and absolute!) to maximally this limit +# can be set to empty for no limit, but beware of filled partitions! +# this is/was a (outdated?) 32bit kernel limit (in MBytes), do not overrun it +# but is also sensible on 64bit to prevent filling /var or even / partition +#CONF_MAXSWAP=2048 diff --git a/dpkg/dpkg.cfg b/dpkg/dpkg.cfg new file mode 100644 index 00000000..ba898ee8 --- /dev/null +++ b/dpkg/dpkg.cfg @@ -0,0 +1,13 @@ +# dpkg configuration file +# +# This file can contain default options for dpkg. All command-line +# options are allowed. Values can be specified by putting them after +# the option, separated by whitespace and/or an `=' sign. +# + +# Do not enable debsig-verify by default; since the distribution is not using +# embedded signatures, debsig-verify would reject all packages. +no-debsig + +# Log status changes and actions to a file. +log /var/log/dpkg.log diff --git a/dpkg/dpkg.cfg.d/pkg-config-hook-config b/dpkg/dpkg.cfg.d/pkg-config-hook-config new file mode 100644 index 00000000..b230b27f --- /dev/null +++ b/dpkg/dpkg.cfg.d/pkg-config-hook-config @@ -0,0 +1 @@ +post-invoke=if { test "$DPKG_HOOK_ACTION" = add-architecture || test "$DPKG_HOOK_ACTION" = remove-architecture; } && test -x /usr/share/pkg-config-dpkghook; then /usr/share/pkg-config-dpkghook update; fi diff --git a/dpkg/origins/debian b/dpkg/origins/debian new file mode 100644 index 00000000..91f6ed1d --- /dev/null +++ b/dpkg/origins/debian @@ -0,0 +1,3 @@ +Vendor: Debian +Vendor-URL: http://www.debian.org/ +Bugs: debbugs://bugs.debian.org diff --git a/dpkg/origins/default b/dpkg/origins/default new file mode 120000 index 00000000..1729d401 --- /dev/null +++ b/dpkg/origins/default @@ -0,0 +1 @@ +raspbian \ No newline at end of file diff --git a/dpkg/origins/raspbian b/dpkg/origins/raspbian new file mode 100644 index 00000000..0c2309d7 --- /dev/null +++ b/dpkg/origins/raspbian @@ -0,0 +1,4 @@ +Vendor: Raspbian +Vendor-URL: http://www.raspbian.org/ +Bugs: https://bugs.launchpad.net/raspbian/+filebug +Parent: Debian diff --git a/dpkg/shlibs.default b/dpkg/shlibs.default new file mode 100644 index 00000000..661a889d --- /dev/null +++ b/dpkg/shlibs.default @@ -0,0 +1,7 @@ +# dpkg shlibs defaults file +# +# This file contains shlibs entries that are used as a last resort when +# no matching entries are found elsewhere. For more information see the +# dpkg-shlibdeps(1) manual page. +# +# diff --git a/dpkg/shlibs.override b/dpkg/shlibs.override new file mode 100644 index 00000000..fbdb68d4 --- /dev/null +++ b/dpkg/shlibs.override @@ -0,0 +1,8 @@ +# dpkg shlibs override file +# +# Entries in this file will override all others, only use if you +# are really sure that is what you want! +# +# For more information see the dpkg-shlibdeps(1) manual page. +# +# diff --git a/email-addresses b/email-addresses new file mode 100644 index 00000000..8e4f2cb4 --- /dev/null +++ b/email-addresses @@ -0,0 +1,9 @@ +# This is /etc/email-addresses. It is part of the exim package +# +# This file contains email addresses to use for outgoing mail. Any local +# part not in here will be qualified by the system domain as normal. +# +# It should contain lines of the form: +# +#user: someone@isp.com +#otheruser: someoneelse@anotherisp.com diff --git a/environment b/environment new file mode 100644 index 00000000..e69de29b diff --git a/etckeeper/commit.d/10vcs-test b/etckeeper/commit.d/10vcs-test new file mode 100755 index 00000000..e33d7341 --- /dev/null +++ b/etckeeper/commit.d/10vcs-test @@ -0,0 +1,17 @@ +#!/bin/sh +set -e + +not_enabled_warning() { + echo "etckeeper warning: etckeeper is not yet enabled for $(pwd)" >&2 + echo "etckeeper warning: run etckeeper init to enable it" >&2 +} + +if [ "$VCS" = git ] && [ ! -d .git ]; then + not_enabled_warning +elif [ "$VCS" = hg ] && [ ! -d .hg ]; then + not_enabled_warning +elif [ "$VCS" = bzr ] && [ ! -d .bzr ]; then + not_enabled_warning +elif [ "$VCS" = darcs ] && [ ! -d _darcs ]; then + not_enabled_warning +fi diff --git a/etckeeper/commit.d/20store-metadata b/etckeeper/commit.d/20store-metadata new file mode 120000 index 00000000..5698d643 --- /dev/null +++ b/etckeeper/commit.d/20store-metadata @@ -0,0 +1 @@ +../pre-commit.d/30store-metadata \ No newline at end of file diff --git a/etckeeper/commit.d/30bzr-add b/etckeeper/commit.d/30bzr-add new file mode 100755 index 00000000..3e7e95d9 --- /dev/null +++ b/etckeeper/commit.d/30bzr-add @@ -0,0 +1,8 @@ +#!/bin/sh +set -e + +if [ "$VCS" = bzr ] && [ -d .bzr ]; then + if ! bzr add -q .; then + echo "etckeeper warning: bzr add failed" >&2 + fi +fi diff --git a/etckeeper/commit.d/30darcs-add b/etckeeper/commit.d/30darcs-add new file mode 100755 index 00000000..98be4bf0 --- /dev/null +++ b/etckeeper/commit.d/30darcs-add @@ -0,0 +1,14 @@ +#!/bin/sh +set -e + +if [ "$VCS" = darcs ] && [ -d _darcs ]; then + rc=0 + res=$( darcs add -qr . 2>&1 ) || rc=$? + if test $rc -ne 0; then + if ! test $rc -eq 2 -a "${res%No files were added}" != "$res"; then + printf "%s" "$res" + echo "etckeeper warning: darcs add failed" >&2 + fi + fi + unset rc res +fi diff --git a/etckeeper/commit.d/30git-add b/etckeeper/commit.d/30git-add new file mode 100755 index 00000000..b08b5838 --- /dev/null +++ b/etckeeper/commit.d/30git-add @@ -0,0 +1,8 @@ +#!/bin/sh +set -e + +if [ "$VCS" = git ] && [ -d .git ]; then + if ! git add --all; then + echo "etckeeper warning: git add --all" >&2 + fi +fi diff --git a/etckeeper/commit.d/30hg-addremove b/etckeeper/commit.d/30hg-addremove new file mode 100755 index 00000000..1b999bbb --- /dev/null +++ b/etckeeper/commit.d/30hg-addremove @@ -0,0 +1,8 @@ +#!/bin/sh +set -e + +if [ "$VCS" = hg ] && [ -d .hg ]; then + if ! hg addremove .; then + echo "etckeeper warning: hg addremove failed" >&2 + fi +fi diff --git a/etckeeper/commit.d/50vcs-commit b/etckeeper/commit.d/50vcs-commit new file mode 100755 index 00000000..f970d3d5 --- /dev/null +++ b/etckeeper/commit.d/50vcs-commit @@ -0,0 +1,135 @@ +#!/bin/sh +set -e + +cleanup () { + if [ -n "$logfile" ]; then + rm -f "$logfile" + fi +} +if [ -n "$1" ]; then + trap cleanup EXIT + logfile="$(mktemp -t etckeeper-$VCS.XXXXXXXXXX)" + if [ "x$1" = "x--stdin" ]; then + cat > "$logfile" + else + if [ "x$1" = "x-m" ]; then + shift 1 + fi + echo "$1" > "$logfile" + fi +else + logfile="" +fi + +hostname=`hostname` +hostname="${hostname%%.*}" +dnsdomainname=`dnsdomainname 2>/dev/null || true` +if [ -n "$dnsdomainname" ]; then + hostname="$hostname.$dnsdomainname" +fi + +ORIG_USER=$USER +USER= +if [ -n "$SUDO_USER" ]; then + USER="$SUDO_USER" +else + # try to check tty ownership, in case user su'd to root + TTY="$(tty 2>/dev/null || true)" + if [ -n "$TTY" ] && [ -c "$TTY" ]; then + USER="$(find "$TTY" -printf "%u")" + fi +fi + +if [ "$VCS" = git ] && [ -d .git ]; then + # When not su'd to root, still set environment variables, + # since git's own code to determine the author and committer + # has several edge cases where it fails and would prevent the + # commit. + if [ -z "$USER" ]; then + USER="$(whoami)" + fi + if [ -n "$USER" ]; then + # Use user.name and user.email from the gitconfig belonging + # to USER. + USER_HOME="$(getent passwd "$USER" | cut -d: -f6)" + if [ -n "$USER_HOME" ] && [ -e "$USER_HOME/.gitconfig" ]; then + if [ -z "$GIT_AUTHOR_NAME" ]; then + GIT_AUTHOR_NAME="$(git config -f "$USER_HOME/.gitconfig" user.name)" || true + export GIT_AUTHOR_NAME + fi + if [ -z "$GIT_AUTHOR_EMAIL" ]; then + GIT_AUTHOR_EMAIL="$(git config -f "$USER_HOME/.gitconfig" user.email)" || true + export GIT_AUTHOR_EMAIL + fi + fi + if [ -z "$GIT_AUTHOR_NAME" ] || [ -z "$GIT_AUTHOR_EMAIL" ]; then + if [ -n "$USER_HOME" ] && [ -e "$USER_HOME/.config/git/config" ]; then + if [ -z "$GIT_AUTHOR_NAME" ]; then + GIT_AUTHOR_NAME="$(git config -f "$USER_HOME/.config/git/config" user.name)" || true + export GIT_AUTHOR_NAME + fi + if [ -z "$GIT_AUTHOR_EMAIL" ]; then + GIT_AUTHOR_EMAIL="$(git config -f "$USER_HOME/.config/git/config" user.email)" || true + export GIT_AUTHOR_EMAIL + fi + fi + fi + + if [ -z "$GIT_COMMITTER_EMAIL" ]; then + GIT_COMMITTER_EMAIL="$(git config --global user.email)" || true + export GIT_COMMITTER_EMAIL + fi + if [ -z "$GIT_AUTHOR_NAME" ]; then + GIT_AUTHOR_NAME="$USER" + export GIT_AUTHOR_NAME + fi + if [ -z "$GIT_AUTHOR_EMAIL" ]; then + GIT_AUTHOR_EMAIL="$USER@$hostname" + export GIT_AUTHOR_EMAIL + fi + if [ -z "$GIT_COMMITTER_EMAIL" ]; then + GIT_COMMITTER_EMAIL=`whoami`"@$hostname" + export GIT_COMMITTER_EMAIL + fi + fi + if [ -n "$logfile" ]; then + git commit $GIT_COMMIT_OPTIONS -F "$logfile" + else + git commit $GIT_COMMIT_OPTIONS + fi +elif [ "$VCS" = hg ] && [ -d .hg ]; then + if [ -n "$USER" ]; then + LOGNAME="$USER" + export LOGNAME + fi + if [ -z "$HGUSER" ]; then + HGUSER="$USER@$hostname" + export HGUSER + fi + if [ -n "$logfile" ]; then + hg commit $HG_COMMIT_OPTIONS -l "$logfile" + else + hg commit $HG_COMMIT_OPTIONS + fi +elif [ "$VCS" = bzr ] && [ -d .bzr ]; then + if [ -z "$EMAIL" ] && [ -n "$USER" ]; then + EMAIL="$USER <$USER@$hostname>" + export EMAIL + else + bzr whoami >/dev/null 2>&1 || export EMAIL="$ORIG_USER <$ORIG_USER@$hostname>" + fi + if [ -n "$logfile" ]; then + bzr commit $BZR_COMMIT_OPTIONS -F "$logfile" + else + bzr commit $BZR_COMMIT_OPTIONS + fi +elif [ "$VCS" = darcs ] && [ -d _darcs ]; then + if [ -z "$USER" ]; then + USER=root + fi + if [ -n "$logfile" ]; then + darcs record --author="$USER" $DARCS_COMMIT_OPTIONS --logfile="$logfile" + else + darcs record --author="$USER" $DARCS_COMMIT_OPTIONS + fi +fi diff --git a/etckeeper/commit.d/99push b/etckeeper/commit.d/99push new file mode 100755 index 00000000..3df1350b --- /dev/null +++ b/etckeeper/commit.d/99push @@ -0,0 +1,14 @@ +#!/bin/sh +if [ -n "$PUSH_REMOTE" ]; then + if [ "$VCS" = git ] && [ -d .git ]; then + for REMOTE in $PUSH_REMOTE; do + git push "$REMOTE" || true + done + elif [ "$VCS" = hg ] && [ -d .hg ]; then + for REMOTE in $PUSH_REMOTE; do + hg push "$REMOTE" || true + done + else + echo "PUSH_REMOTE not yet supported for $VCS" >&2 + fi +fi diff --git a/etckeeper/commit.d/README b/etckeeper/commit.d/README new file mode 100644 index 00000000..25d0d458 --- /dev/null +++ b/etckeeper/commit.d/README @@ -0,0 +1,3 @@ +Files in this directory are run when there might be changes to commit. +(Before and after packages are installed, upgraded, etc.) +They should commit changes and new files in /etc to repository. diff --git a/etckeeper/daily b/etckeeper/daily new file mode 100755 index 00000000..f98c6add --- /dev/null +++ b/etckeeper/daily @@ -0,0 +1,17 @@ +#!/bin/sh +# Script that can be run daily to autocommit /etc changes. +set -e +if [ -x /usr/bin/etckeeper ] && [ -e /etc/etckeeper/etckeeper.conf ]; then + # avoid autocommit if an install run is in progress + lockfile=/var/cache/etckeeper/packagelist.pre-install + if [ -e "$lockfile" ] && [ -n "$(find "$lockfile" -mtime +1)" ]; then + rm -f "$lockfile" # stale + fi + if [ ! -e "$lockfile" ]; then + AVOID_SPECIAL_FILE_WARNING=1 + export AVOID_SPECIAL_FILE_WARNING + if etckeeper unclean; then + etckeeper commit "daily autocommit" >/dev/null + fi + fi +fi diff --git a/etckeeper/etckeeper.conf b/etckeeper/etckeeper.conf new file mode 100644 index 00000000..f13de1c5 --- /dev/null +++ b/etckeeper/etckeeper.conf @@ -0,0 +1,45 @@ +# The VCS to use. +#VCS="hg" +VCS="git" +#VCS="bzr" +#VCS="darcs" + +# Options passed to git commit when run by etckeeper. +GIT_COMMIT_OPTIONS="" + +# Options passed to hg commit when run by etckeeper. +HG_COMMIT_OPTIONS="" + +# Options passed to bzr commit when run by etckeeper. +BZR_COMMIT_OPTIONS="" + +# Options passed to darcs record when run by etckeeper. +DARCS_COMMIT_OPTIONS="-a" + +# Etckeeper includes both a cron job and a systemd timer, which each +# can commit exiting changes to /etc automatically once per day. +# To enable the systemd timer, run: systemctl enable etckeeper.timer +# The cron job is enabled by default; to disable it, uncomment this next line. +#AVOID_DAILY_AUTOCOMMITS=1 + +# Uncomment the following to avoid special file warning +# (the option is enabled automatically for daily autocommits regardless). +#AVOID_SPECIAL_FILE_WARNING=1 + +# Uncomment to avoid etckeeper committing existing changes to +# /etc before installation. It will cancel the installation, +# so you can commit the changes by hand. +#AVOID_COMMIT_BEFORE_INSTALL=1 + +# The high-level package manager that's being used. +# (apt, pacman, pacman-g2, yum, dnf, zypper, apk etc) +HIGHLEVEL_PACKAGE_MANAGER=apt + +# The low-level package manager that's being used. +# (dpkg, rpm, pacman, pacmatic, pacman-g2, apk etc) +LOWLEVEL_PACKAGE_MANAGER=dpkg + +# To push each commit to a remote, put the name of the remote here. +# (eg, "origin" for git). Space-separated lists of multiple remotes +# also work (eg, "origin gitlab github" for git). +PUSH_REMOTE="" diff --git a/etckeeper/init.d/10restore-metadata b/etckeeper/init.d/10restore-metadata new file mode 100755 index 00000000..9c2bf65b --- /dev/null +++ b/etckeeper/init.d/10restore-metadata @@ -0,0 +1,14 @@ +#!/bin/sh +set -e + +# Note that metastore doesn't check that the .metastore file only changes +# perms of files in the current directory. It's ok to trust the .metastore +# file won't do anything shady, because, as documented, etckeeper-init +# should only be run on repositories you trust. +if [ -e .metadata ]; then + if which metastore >/dev/null; then + metastore --apply --mtime + else + echo "etckeeper warning: legacy .metastore file is present but metastore is not installed" >&2 + fi +fi diff --git a/etckeeper/init.d/20restore-etckeeper b/etckeeper/init.d/20restore-etckeeper new file mode 100755 index 00000000..0485e63c --- /dev/null +++ b/etckeeper/init.d/20restore-etckeeper @@ -0,0 +1,22 @@ +#!/bin/sh +set -e + +# Used by .etckeeper to run a command if the file it acts on +# (the last parameter) exists. +maybe () { + command="$1" + shift 1 + + if eval [ -e "\"\$$#\"" ]; then + "$command" "$@" + fi +} + +# Yes, this runs code from the repository. As documented, etckeeper-init +# should only be run on repositories you trust. +if [ -e .etckeeper ]; then + . ./.etckeeper +else + touch .etckeeper + chmod 600 .etckeeper +fi diff --git a/etckeeper/init.d/40vcs-init b/etckeeper/init.d/40vcs-init new file mode 100755 index 00000000..3c7a3bb9 --- /dev/null +++ b/etckeeper/init.d/40vcs-init @@ -0,0 +1,17 @@ +#!/bin/sh +set -e + +if [ "$VCS" = git ] && [ ! -e .git ]; then + git init + echo "$(hostname) /etc repository" > .git/description +elif [ "$VCS" = hg ] && [ ! -e .hg ]; then + hg init + echo "[web]" > .hg/hgrc + echo "description = $(hostname) /etc repository" >> .hg/hgrc +elif [ "$VCS" = bzr ] && [ ! -e .bzr ]; then + bzr init + bzr nick "$(hostname) /etc repository" +elif [ "$VCS" = darcs ] && [ ! -e _darcs ]; then + darcs initialize + echo "$(hostname) /etc repository" > _darcs/prefs/motd +fi diff --git a/etckeeper/init.d/50vcs-ignore b/etckeeper/init.d/50vcs-ignore new file mode 100755 index 00000000..33d79d3c --- /dev/null +++ b/etckeeper/init.d/50vcs-ignore @@ -0,0 +1,4 @@ +#!/bin/sh +set -e + +etckeeper update-ignore -a || true diff --git a/etckeeper/init.d/50vcs-perm b/etckeeper/init.d/50vcs-perm new file mode 100755 index 00000000..4dd080b7 --- /dev/null +++ b/etckeeper/init.d/50vcs-perm @@ -0,0 +1,12 @@ +#!/bin/sh +set -e + +if [ "$VCS" = git ]; then + chmod 700 .git +elif [ "$VCS" = hg ]; then + chmod 700 .hg +elif [ "$VCS" = bzr ]; then + chmod 700 .bzr +elif [ "$VCS" = darcs ]; then + chmod 700 _darcs +fi diff --git a/etckeeper/init.d/50vcs-pre-commit-hook b/etckeeper/init.d/50vcs-pre-commit-hook new file mode 100755 index 00000000..60459816 --- /dev/null +++ b/etckeeper/init.d/50vcs-pre-commit-hook @@ -0,0 +1,49 @@ +#!/bin/sh +set -e + +case "$VCS" in + git) + if [ -x .git/hooks/pre-commit ]; then + if ! grep -q "etckeeper pre-commit" .git/hooks/pre-commit; then + echo "etckeeper warning: .git/hooks/pre-commit needs to be manually modified to run: etckeeper pre-commit -d `pwd`" >&2 + fi + else + cat >.git/hooks/pre-commit <&2 + fi + else + touch .hg/hgrc + cat >>.hg/hgrc <&2 + fi + else + cat >_darcs/prefs/defaults < "$patternsfile" || true + grep -Evf "$patternsfile" + rm -f "$patternsfile" + unset patternsfile + else + cat - + fi +} + + +if [ "$VCS" = darcs ];then + NOVCS='. -path ./.git -prune -o -path ./.bzr -prune -o -path ./.hg -prune -o -path ./_darcs -prune -o' + + # We assume that if .etckeeper is empty this is the first run + if [ -s .etckeeper ]; then + linksindex="$( mktemp -t etckeeper-$VCS.XXXXXXXXXX )" + grep '^ln -s' .etckeeper | while IFS="'" read n n n link n; do + printf "%s\n" "$link" >> "$linksindex" + done + + # Warn about symbolic links that shouldn't exist + if links=$( find $NOVCS -type l -print | filter_ignore | grep -vFf "$linksindex" ); then + printf "%s\n%s\n" \ + "The following symbolic links should not exist:" \ + "$links" >&2 + fi + + rm -f "$linksindex" + unset links linksindex + fi + +fi diff --git a/etckeeper/init.d/70vcs-add b/etckeeper/init.d/70vcs-add new file mode 100755 index 00000000..9a9ec455 --- /dev/null +++ b/etckeeper/init.d/70vcs-add @@ -0,0 +1,27 @@ +#!/bin/sh +set -e + +if [ "$VCS" = git ]; then + if ! git add .; then + echo "etckeeper warning: git add failed" >&2 + fi +elif [ "$VCS" = hg ]; then + if ! hg add .; then + echo "etckeeper warning: hg add failed" >&2 + fi +elif [ "$VCS" = bzr ]; then + if ! bzr add .; then + echo "etckeeper warning: bzr add failed" >&2 + fi +elif [ "$VCS" = darcs ]; then + # Don't warn if all the files were already added. + rc=0 + res=$( darcs add -qr . 2>&1 ) || rc=$? + if test $rc -ne 0; then + if ! test $rc -eq 2 -a "${res%No files were added}" != "$res"; then + printf "%s" "$res" + echo "etckeeper warning: darcs add failed" >&2 + fi + fi + unset rc res +fi diff --git a/etckeeper/init.d/README b/etckeeper/init.d/README new file mode 100644 index 00000000..90aec677 --- /dev/null +++ b/etckeeper/init.d/README @@ -0,0 +1,13 @@ +Executable files in this directory are run to initialise the working directory +for use by etckeeper. If the working directory is not already in version +control, that includes setting up the version control, but not actually +committing anything. If the working directory is in version control, +it includes applying stored metadata to the checked out files in the +working directory. + +Please be careful to *never* overwrite existing files/directories +in the working directory (or use absolute care when doing so). If a file +you need to write already exists, check if its contents are sane, and +if not, emit a warning on stderr. + +If initialisation fails, exit nonzero and no later files will be run. diff --git a/etckeeper/list-installed.d/50list-installed b/etckeeper/list-installed.d/50list-installed new file mode 100755 index 00000000..d89b8cee --- /dev/null +++ b/etckeeper/list-installed.d/50list-installed @@ -0,0 +1,27 @@ +#!/bin/sh +if [ "$1" = fmt ]; then + # If the list format changes, change the fmt + if [ "$LOWLEVEL_PACKAGE_MANAGER" = dpkg ]; then + echo 2 + else + echo "" + fi +else + # Output to stdout a *sorted* list of all currently installed + # (or removed but still with config-files) packages, in the + # format "package version\n" (or something similar). + if [ "$LOWLEVEL_PACKAGE_MANAGER" = dpkg ]; then + dpkg-query -W -f '${Status}\t${Package} ${Version} ${Architecture}\n' | \ + egrep '(ok installed|ok config-files)' | cut -f2,3 + elif [ "$LOWLEVEL_PACKAGE_MANAGER" = rpm ]; then + rpm -qa --qf "%|epoch?{%{epoch}}:{0}|:%{name}-%{version}-%{release}.%{arch}\n" | sort + elif [ "$LOWLEVEL_PACKAGE_MANAGER" = pacman ]; then + pacman -Q + elif [ "$LOWLEVEL_PACKAGE_MANAGER" = pacmatic ]; then + pacmatic -Q + elif [ "$LOWLEVEL_PACKAGE_MANAGER" = pkgng ]; then + pkg info -E "*" + elif [ "$LOWLEVEL_PACKAGE_MANAGER" = apk ]; then + apk info -v | sort + fi +fi diff --git a/etckeeper/post-install.d/50vcs-commit b/etckeeper/post-install.d/50vcs-commit new file mode 100755 index 00000000..bc9cdf05 --- /dev/null +++ b/etckeeper/post-install.d/50vcs-commit @@ -0,0 +1,43 @@ +#!/bin/sh +set -e + +pl="/var/cache/etckeeper/packagelist" + +# Parent process is etckeeper +# (Only procps ps is currently supported, others will fail, +# so this may end up empty.) +ETCKEEPER_PID=$( ps --no-headers -o ppid "${PPID}" 2>/dev/null | sed 's/^ *//' ) + +# Find the parent of etckeeper and get the command line of the process +if ! [ -z "${ETCKEEPER_PID}" ]; then + ETCKEEPER_PPID=$( ps --no-headers -o ppid "${ETCKEEPER_PID}" | sed 's/^ *//' ) + ETCKEEPER_PARENT_COMMAND_LINE=$( ps --no-headers -o args "${ETCKEEPER_PPID}" ) +fi + +if etckeeper unclean; then + if [ -z "${ETCKEEPER_PARENT_COMMAND_LINE}" ]; then + message="committing changes in /etc after $HIGHLEVEL_PACKAGE_MANAGER run" + else + message="committing changes in /etc made by \"$ETCKEEPER_PARENT_COMMAND_LINE\"" + fi + + set +e + if [ -e $pl.pre-install ] && [ "$(cat $pl.fmt 2>/dev/null || true)" = "$(etckeeper list-installed fmt)" ]; then + ( + echo "$message" + echo + echo "Package changes:" + etckeeper list-installed | diff -U0 $pl.pre-install - | tail -n+4 | egrep '^[-+]' || true + ) | etckeeper commit --stdin + else + etckeeper commit "$(printf "$message")" + fi + status=$? + set -e + + if [ "$status" != 0 ]; then + echo "warning: etckeeper failed to commit changes in /etc using $VCS" >&2 + fi +fi + +rm -f $pl.pre-install $pl.fmt diff --git a/etckeeper/post-install.d/README b/etckeeper/post-install.d/README new file mode 100644 index 00000000..62f4f9c4 --- /dev/null +++ b/etckeeper/post-install.d/README @@ -0,0 +1,2 @@ +Files in this directory are run after packages are installed, upgraded, etc. +They should commit changes and new files in /etc to repository. diff --git a/etckeeper/pre-commit.d/20warn-problem-files b/etckeeper/pre-commit.d/20warn-problem-files new file mode 100755 index 00000000..6bd5c2bc --- /dev/null +++ b/etckeeper/pre-commit.d/20warn-problem-files @@ -0,0 +1,30 @@ +#!/bin/sh +set -e + +exclude_internal () { + egrep -v '(^|/)(\.git|\.hg|\.bzr|_darcs)/' +} + +if [ "$VCS" = bzr ] || [ "$VCS" = darcs ]; then + special=$(find . ! -type d ! -type f ! -type l | exclude_internal) || true + hardlinks=$(find . -type f ! -links 1 | exclude_internal ) || true +elif [ "$VCS" = hg ]; then + special=$(find . ! -type d ! -type f ! -type l | exclude_internal) || true + hardlinks=$(find . -type f ! -links 1 -exec hg status {} \; | exclude_internal ) || true +elif [ "$VCS" = git ]; then + special=$(find . ! -type d ! -type f ! -type l -exec git ls-files --exclude-standard --cached --others {} + | exclude_internal) || true + hardlinks=$(find . -type f ! -links 1 -exec git ls-files --exclude-standard --cached --others {} + | exclude_internal) || true +else + special="" +fi + +if [ -n "$special" ] && [ -z "$AVOID_SPECIAL_FILE_WARNING" ]; then + echo "etckeeper warning: special files could cause problems with $VCS:" >&2 + echo "$special" >&2 +fi +if [ -n "$hardlinks" ] && [ -z "$AVOID_SPECIAL_FILE_WARNING" ]; then + echo "etckeeper warning: hardlinked files could cause problems with $VCS:" >&2 + echo "$hardlinks" >&2 +fi + +true diff --git a/etckeeper/pre-commit.d/30store-metadata b/etckeeper/pre-commit.d/30store-metadata new file mode 100755 index 00000000..ce014d12 --- /dev/null +++ b/etckeeper/pre-commit.d/30store-metadata @@ -0,0 +1,175 @@ +#!/bin/sh +set -e + +# Make sure sort always sorts in same order. +LANG=C +export LANG + +filter_ignore() { + case "$VCS" in + darcs) ignorefile=.darcsignore ;; + git) ignorefile=.gitignore ;; + esac + + if [ -n "$ignorefile" ] && [ -e "$ignorefile" ]; then + listfile="$( mktemp -t etckeeper-$VCS.XXXXXXXXXX )" + case "$VCS" in + darcs) + grep -v '^[[:space:]]*\(#\|$\)' "$ignorefile" > "$listfile" || true + grep -Evf "$listfile" + ;; + git) + (git ls-files -oi --exclude-standard; git ls-files -oi --exclude-standard --directory) | sort | uniq > "$listfile" || true + if [ -s "$listfile" ]; then + sed 's/^\.\///' | grep -xFvf "$listfile" + else + cat - + fi + ;; + esac + rm -f "$listfile" + unset listfile + else + cat - + fi +} + +shellquote() { + # Single quotes text, escaping existing single quotes. + sed -e "s/'/'\"'\"'/g" -e "s/^/'/" -e "s/$/'/" +} + +generate_metadata() { + # This function generates the script commands to fix any file + # ownerships that aren't owner=root, group=root, as well as to + # store the permissions of files. + # The script is produced on stdout. Errors go to stderr. + # + # The script can use a 'maybe' function, which only runs a command + # if the file in its last argument exists. + + # We want files in the directory containing VCS data + # but we want find to ignore the VCS files themselves. + # + # (Note that when using this, the find expression must end with + # -print or -exec, else the excluded directories will actually be + # printed!) + NOVCS='. -path ./.git -prune -o -path ./.bzr -prune -o -path ./.hg -prune -o -path ./_darcs -prune -o' + + # Keep the sort order the same at all times. + LC_COLLATE=C + export LC_COLLATE + unset LC_ALL + + if [ "$VCS" = git ] || [ "$VCS" = hg ]; then + # These version control systems do not track directories, + # so empty directories must be stored specially. + find $NOVCS -type d -empty -print | + sort | shellquote | sed -e "s/^/mkdir -p /" + fi + + if [ "$VCS" = darcs ]; then + # This version control system does not track symlinks, + # so they must be stored specially. + find $NOVCS -type l -print | sort | filter_ignore | while read link; do + dest=$( readlink "$link" ) + printf "ln -sf '%s' '%s'\n" "$(echo "$dest" | shellquote)" "$(echo "$link" | shellquote)" + done + fi + + # Store things that don't have the default user or group. + # Store all file modes, in case the user has an unusual umask. + find $NOVCS \( -type f -or -type d \) -print | filter_ignore | sort | maybe_chmod_chown + + # We don't handle xattrs. + # Maybe check for getfattr/setfattr and use them if they're available? +} + +maybe_chmod_chown() { + if [ "$(which perl 2>/dev/null)" != "" ]; then + perl -ne ' + BEGIN { $q=chr(39) } + sub uidname { + my $want=shift; + if (exists $uidcache{$want}) { + return $uidcache{$want}; + } + my $name=scalar getpwuid($want); + return $uidcache{$want}=defined $name ? $name : $want; + } + sub gidname { + my $want=shift; + if (exists $gidcache{$want}) { + return $gidcache{$want}; + } + my $name=scalar getgrgid($want); + return $gidcache{$want}=defined $name ? $name : $want; + } + chomp; + my @stat=stat($_); + my $mode = $stat[2]; + my $uid = $stat[4]; + my $gid = $stat[5]; + s/$q/$q"$q"$q/g; # escape single quotes + s/^/$q/; + s/$/$q/; + if ($uid != $>) { + printf "maybe chown $q%s$q %s\n", uidname($uid), $_; + } + if ($gid != $)) { + printf "maybe chgrp $q%s$q %s\n", gidname($gid), $_; + } + printf "maybe chmod %04o %s\n", $mode & 07777, $_; + ' + return $? + else + # fallback if perl isn't present + euid=$(id -u) + egid=$(id -g) + q="'" + while read x; do + stat=$(stat -c "%f:%u:%g:%a:%U:%G" $x) + IFS=":" read mode uid gid perm uname gname < .etckeeper + echo >> .etckeeper + + # Make sure the file is not readable by others, since it can leak + # information about contents of non-readable directories in /etc. + chmod 700 .etckeeper + + generate_metadata >> .etckeeper + + # stage the file as part of the current commit + if [ "$VCS" = git ]; then + # this will do nothing if the metadata file is unchanged. + git add .etckeeper + fi + # hg, bzr and darcs add not done, they will automatically + # include the file in the current commit +fi diff --git a/etckeeper/pre-commit.d/README b/etckeeper/pre-commit.d/README new file mode 100644 index 00000000..051d0947 --- /dev/null +++ b/etckeeper/pre-commit.d/README @@ -0,0 +1,2 @@ +This is run by a git pre-commit hook before committing changes to the +repository. This can be used for storing metadata, and for sanity checks. diff --git a/etckeeper/pre-install.d/10packagelist b/etckeeper/pre-install.d/10packagelist new file mode 100755 index 00000000..fbd4ac38 --- /dev/null +++ b/etckeeper/pre-install.d/10packagelist @@ -0,0 +1,5 @@ +#!/bin/sh +# This list will be later used when committing. +mkdir -p /var/cache/etckeeper/ +etckeeper list-installed > /var/cache/etckeeper/packagelist.pre-install +etckeeper list-installed fmt > /var/cache/etckeeper/packagelist.fmt diff --git a/etckeeper/pre-install.d/50uncommitted-changes b/etckeeper/pre-install.d/50uncommitted-changes new file mode 100755 index 00000000..969d3413 --- /dev/null +++ b/etckeeper/pre-install.d/50uncommitted-changes @@ -0,0 +1,15 @@ +#!/bin/sh +set -e + +if etckeeper unclean; then + if [ "$AVOID_COMMIT_BEFORE_INSTALL" = 1 ]; then + echo "" >&2 + echo "** etckeeper detected uncommitted changes in /etc prior to $HIGHLEVEL_PACKAGE_MANAGER run" >&2 + echo "** Aborting $HIGHLEVEL_PACKAGE_MANAGER run. Manually commit and restart." >&2 + echo "" >&2 + exit 1 + fi + if ! etckeeper commit "saving uncommitted changes in /etc prior to $HIGHLEVEL_PACKAGE_MANAGER run"; then + echo "warning: etckeeper failed to commit changes in /etc using $VCS" >&2 + fi +fi diff --git a/etckeeper/pre-install.d/README b/etckeeper/pre-install.d/README new file mode 100644 index 00000000..a3b5a57b --- /dev/null +++ b/etckeeper/pre-install.d/README @@ -0,0 +1,3 @@ +Files in this directory are run before packages are installed, upgraded, +etc. This is mostly used for sanity checks, ie, does /etc have any +uncommitted changes? diff --git a/etckeeper/unclean.d/50test b/etckeeper/unclean.d/50test new file mode 100755 index 00000000..e52003f7 --- /dev/null +++ b/etckeeper/unclean.d/50test @@ -0,0 +1,12 @@ +#!/bin/sh +set -e + +if [ "$VCS" = git ]; then + [ -d .git ] && [ -n "`git status --porcelain`" ] +elif [ "$VCS" = hg ]; then + [ -d .hg ] && ! hg status 2>&1 | wc -l | grep -q "^0$" +elif [ "$VCS" = bzr ]; then + [ -d .bzr ] && ! bzr version-info --custom --template="{clean}\n" | grep -q "^1$" +elif [ "$VCS" = darcs ]; then + [ -d _darcs ] && darcs whatsnew -l >/dev/null +fi diff --git a/etckeeper/unclean.d/README b/etckeeper/unclean.d/README new file mode 100644 index 00000000..74bfbdde --- /dev/null +++ b/etckeeper/unclean.d/README @@ -0,0 +1,2 @@ +Files in this directory are used to test if the working copy has +uncommitted changes. diff --git a/etckeeper/uninit.d/01prompt b/etckeeper/uninit.d/01prompt new file mode 100755 index 00000000..8b439375 --- /dev/null +++ b/etckeeper/uninit.d/01prompt @@ -0,0 +1,20 @@ +#!/bin/sh +set -e + +if [ "$1" != "-f" ]; then + echo "** Warning: This will DESTROY all recorded history for $ETCKEEPER_DIR," + echo "** including the $VCS repository." + echo "" + printf "Are you sure you want to do this? [yN] " + read answer + case "$answer" in + [Yy]*) + echo "Proceeding.." + exit 0 + ;; + *) + echo "Aborting etckeeper uninit." + exit 1 + ;; + esac +fi diff --git a/etckeeper/uninit.d/50remove-metadata b/etckeeper/uninit.d/50remove-metadata new file mode 100755 index 00000000..0be8d363 --- /dev/null +++ b/etckeeper/uninit.d/50remove-metadata @@ -0,0 +1,6 @@ +#!/bin/sh +set -e + +# Files generated by etckeeper to store metadata the VCS cannot preserve. +rm -f .etckeeper +rm -f .metadata # only generated by old versions diff --git a/etckeeper/uninit.d/50vcs-uninit b/etckeeper/uninit.d/50vcs-uninit new file mode 100755 index 00000000..06317c56 --- /dev/null +++ b/etckeeper/uninit.d/50vcs-uninit @@ -0,0 +1,54 @@ +#!/bin/sh +set -e + +if [ "$VCS" = git ]; then + rm -rf .git + file=.gitignore +elif [ "$VCS" = hg ]; then + rm -rf .hg + file=.hgignore +elif [ "$VCS" = bzr ]; then + rm -rf .bzr + file=.bzrignore +elif [ "$VCS" = darcs ]; then + rm -rf _darcs + file=.darcsignore +fi + +managed_by_etckeeper="managed by etckeeper" + +if ! grep -q "$managed_by_etckeeper" "$file"; then + exit 0 +else + realfile="$file" + if which tempfile >/dev/null 2>&1 || type tempfile >/dev/null 2>&1; then + tempfile="tempfile" + elif which mktemp >/dev/null 2>&1 || type mktemp >/dev/null 2>&1; then + tempfile="mktemp" + else + echo "etckeeper warning: can't find tempfile or mktemp" >&2 + exit 1 + fi + file=$($tempfile) + otherentries= + skipping= + while read -r line; do + if echo "$line" | grep -q "$managed_by_etckeeper"; then + if [ ! "$skipping" ]; then + skipping=1 + else + skipping= + fi + elif [ ! "$skipping" ]; then + echo "$line" >> "$file" + otherentries=1 + fi + done <"$realfile" + + if [ "$otherentries" ]; then + mv -f "$file" "$realfile" + else + rm -f "$file" + rm -f "$realfile" + fi +fi diff --git a/etckeeper/uninit.d/README b/etckeeper/uninit.d/README new file mode 100644 index 00000000..d1a4eaa2 --- /dev/null +++ b/etckeeper/uninit.d/README @@ -0,0 +1,2 @@ +Executable files in this directory are run to uninitialise the working +directory, removing files added by `etckeeper init`. diff --git a/etckeeper/update-ignore.d/01update-ignore b/etckeeper/update-ignore.d/01update-ignore new file mode 100755 index 00000000..8733a85f --- /dev/null +++ b/etckeeper/update-ignore.d/01update-ignore @@ -0,0 +1,209 @@ +#!/bin/sh +set -e + +if [ "$VCS" = git ]; then + dir=.git + file=.gitignore +elif [ "$VCS" = hg ]; then + dir=.hg + file=.hgignore +elif [ "$VCS" = bzr ]; then + dir=.bzr + file=.bzrignore +elif [ "$VCS" = darcs ]; then + dir=_darcs + file=.darcsignore +else + echo "etckeeper: unsupported VCS $VCS" >&2 + exit 1 +fi + +if [ ! -d "$dir" ]; then + exit 0 +fi + +managed_by_etckeeper="managed by etckeeper" + +nl() { + echo >>"$file" +} + +comment() { + comment="$1" + echo "# $comment" >>"$file" +} + +ignore() { + glob="$1" + + case "$VCS" in + git) + # escape "#" in ignores, as otherwise it may + # be considered a comment + echo "$glob" | sed 's/#/\\#/g' >>"$file" + ;; + bzr) + echo "$glob" >>"$file" + ;; + hg) + # rather than converting the glob to a regexp, just + # configure hg to use globs + if [ -z "$hg_syntax_printed" ]; then + comment "use glob syntax" + echo "syntax: glob" >>"$file" + nl + hg_syntax_printed=1 + fi + echo "$glob" | sed 's/#/\\#/g' >>"$file" + ;; + darcs) + # darcs doesn't understand globs, so we need to + # translate them into regexs. Not a complete converter, + # but suitable for given globs. + if [ "${glob%\*}" != "$glob" ]; then + glob="${glob%\*}" + else + glob="$glob"'($|/)' + fi + if [ "${glob#\*}" != "$glob" ]; then + glob="${glob#\*}" + else + glob='(^|/)'"$glob" + fi + glob="$( printf %s $glob | sed -e 's/\./\\./g;s/\*/[^\/]*/g;s/\?/[^\/]/g' )" + echo "$glob" >>"$file" + esac +} + +writefile () { + comment "begin section $managed_by_etckeeper (do not edit this section by hand)" + nl + + if [ "$VCS" = darcs ]; then + darcs setpref boringfile .darcsignore + fi + + if [ "$LOWLEVEL_PACKAGE_MANAGER" = dpkg ]; then + comment "new and old versions of conffiles, stored by dpkg" + ignore "*.dpkg-*" + comment "new and old versions of conffiles, stored by ucf" + ignore "*.ucf-*" + nl + elif [ "$LOWLEVEL_PACKAGE_MANAGER" = "rpm" ]; then + comment "new and old versions of conffiles, stored by apt/rpm" + ignore "*.rpm*" + nl + elif [ "$LOWLEVEL_PACKAGE_MANAGER" = "pacman-g2" -o "$LOWLEVEL_PACKAGE_MANAGER" = "pacman" -o "$LOWLEVEL_PACKAGE_MANAGER" = "pacmatic" ]; then + comment "new and old versions of conffiles, stored by pacman" + ignore "*.pacnew" + ignore "*.pacorig" + ignore "*.pacsave" + nl + elif [ "$LOWLEVEL_PACKAGE_MANAGER" = "apk" ]; then + comment "new versions of conffiles, stored by apk" + ignore "*.apk-new" + nl + fi + + comment "old versions of files" + ignore "*.old" + # Not currently ignored as admins tend to rely on these files. + #ignore "passwd-" + #ignore "group-" + #ignore "shadow-" + #ignore "gshadow-" + nl + + comment "mount(8) records system state here, no need to store these" + ignore blkid.tab + ignore blkid.tab.old + nl + + comment "some other files in /etc that typically do not need to be tracked" + ignore nologin + ignore ld.so.cache + ignore prelink.cache + ignore mtab + ignore mtab.fuselock + ignore .pwd.lock + ignore "*.LOCK" + ignore network/run + ignore adjtime + ignore lvm/cache + ignore lvm/archive + ignore "X11/xdm/authdir/authfiles/*" + ignore ntp.conf.dhcp + ignore .initctl + ignore "webmin/fsdump/*.status" + ignore "webmin/webmin/oscache" + ignore "apparmor.d/cache/*" + ignore "service/*/supervise/*" + ignore "service/*/log/supervise/*" + ignore "sv/*/supervise/*" + ignore "sv/*/log/supervise/*" + ignore "*.elc" + ignore "*.pyc" + ignore "*.pyo" + ignore "init.d/.depend.*" + ignore "openvpn/openvpn-status.log" + ignore "cups/subscriptions.conf" + ignore "cups/subscriptions.conf.O" + ignore "fake-hwclock.data" + ignore "check_mk/logwatch.state" + nl + + comment "editor temp files" + ignore "*~" + ignore ".*.sw?" + ignore ".sw?" + ignore "#*#" + ignore DEADJOE + + nl + comment "end section $managed_by_etckeeper" +} + +if [ -e "$file" ]; then + if ! grep -q "$managed_by_etckeeper" "$file"; then + if [ "$1" != "-a" ]; then + echo "etckeeper: "$file" does not contain \"$managed_by_etckeeper\" comment; not updating" + exit 1 + else + echo "etckeeper: "$file" exists but does not contain \"$managed_by_etckeeper\" comment; updating" + writefile + exit 0 + fi + fi + realfile="$file" + if which tempfile >/dev/null 2>&1 || type tempfile >/dev/null 2>&1; then + tempfile="tempfile" + elif which mktemp >/dev/null 2>&1 || type mktemp >/dev/null 2>&1; then + tempfile="mktemp" + else + echo "etckeeper warning: can't find tempfile or mktemp" >&2 + fi + file=$($tempfile) + ( + skipping= + while read -r line; do + if echo "$line" | grep -q "$managed_by_etckeeper"; then + if [ ! "$skipping" ]; then + skipping=1 + else + skipping= + writefile + fi + elif [ ! "$skipping" ]; then + echo "$line" >> "$file" + fi + done + if [ "$skipping" ]; then + # reached end of file w/o ending block + writefile + fi + ) <"$realfile" + + mv -f "$file" "$realfile" +else + writefile +fi diff --git a/etckeeper/update-ignore.d/README b/etckeeper/update-ignore.d/README new file mode 100644 index 00000000..a5731356 --- /dev/null +++ b/etckeeper/update-ignore.d/README @@ -0,0 +1,2 @@ +Executable files in this directory are run to update the VCS ignore file, +or create it if it does not exist. diff --git a/etckeeper/vcs.d/50vcs-cmd b/etckeeper/vcs.d/50vcs-cmd new file mode 100755 index 00000000..f515abbe --- /dev/null +++ b/etckeeper/vcs.d/50vcs-cmd @@ -0,0 +1,11 @@ +#!/bin/sh +set -e + +# check whether we can locate the vcs binary +if [ -n "$VCS" ] && which "$VCS" > /dev/null; then + # pass commands to the VCS application + $VCS "$@" +else + echo "error: VCS ($VCS) not set or not in PATH" >&2 + exit 1 +fi diff --git a/exim4/conf.d/acl/00_exim4-config_header b/exim4/conf.d/acl/00_exim4-config_header new file mode 100644 index 00000000..76b017e5 --- /dev/null +++ b/exim4/conf.d/acl/00_exim4-config_header @@ -0,0 +1,8 @@ + +###################################################################### +# ACL CONFIGURATION # +# Specifies access control lists for incoming SMTP mail # +###################################################################### +begin acl + + diff --git a/exim4/conf.d/acl/20_exim4-config_local_deny_exceptions b/exim4/conf.d/acl/20_exim4-config_local_deny_exceptions new file mode 100644 index 00000000..23727959 --- /dev/null +++ b/exim4/conf.d/acl/20_exim4-config_local_deny_exceptions @@ -0,0 +1,49 @@ + +### acl/20_exim4-config_local_deny_exceptions +################################# + +# This is used to determine whitelisted senders and hosts. +# It checks for CONFDIR/host_local_deny_exceptions and +# CONFDIR/sender_local_deny_exceptions. +# +# It is meant to be used from some other acl entry. +# +# See exim4-config_files(5) for details. +# +# If the files do not exist, the white list never matches, which is +# the desired behaviour. +# +# The old file names CONFDIR/local_host_whitelist and +# CONFDIR/local_sender_whitelist will continue to be honored for a +# transition period. Their use is deprecated. + +acl_local_deny_exceptions: + accept + hosts = ${if exists{CONFDIR/host_local_deny_exceptions}\ + {CONFDIR/host_local_deny_exceptions}\ + {}} + accept + senders = ${if exists{CONFDIR/sender_local_deny_exceptions}\ + {CONFDIR/sender_local_deny_exceptions}\ + {}} + accept + hosts = ${if exists{CONFDIR/local_host_whitelist}\ + {CONFDIR/local_host_whitelist}\ + {}} + accept + senders = ${if exists{CONFDIR/local_sender_whitelist}\ + {CONFDIR/local_sender_whitelist}\ + {}} + + # This hook allows you to hook in your own ACLs without having to + # modify this file. If you do it like we suggest, you'll end up with + # a small performance penalty since there is an additional file being + # accessed. This doesn't happen if you leave the macro unset. + .ifdef LOCAL_DENY_EXCEPTIONS_LOCAL_ACL_FILE + .include LOCAL_DENY_EXCEPTIONS_LOCAL_ACL_FILE + .endif + + # this is still supported for a transition period and is deprecated. + .ifdef WHITELIST_LOCAL_DENY_LOCAL_ACL_FILE + .include WHITELIST_LOCAL_DENY_LOCAL_ACL_FILE + .endif diff --git a/exim4/conf.d/acl/30_exim4-config_check_mail b/exim4/conf.d/acl/30_exim4-config_check_mail new file mode 100644 index 00000000..f8c53d6e --- /dev/null +++ b/exim4/conf.d/acl/30_exim4-config_check_mail @@ -0,0 +1,11 @@ + +### acl/30_exim4-config_check_mail +################################# + +# This access control list is used for every MAIL command in an incoming +# SMTP message. The tests are run in order until the address is either +# accepted or denied. +# +acl_check_mail: + + accept diff --git a/exim4/conf.d/acl/30_exim4-config_check_rcpt b/exim4/conf.d/acl/30_exim4-config_check_rcpt new file mode 100644 index 00000000..b8bde1e3 --- /dev/null +++ b/exim4/conf.d/acl/30_exim4-config_check_rcpt @@ -0,0 +1,375 @@ + +### acl/30_exim4-config_check_rcpt +################################# + +# define macros to be used below in this file to check recipient +# local parts for strange characters. Documentation below. +# This blocks local parts that begin with a dot or contain a quite +# broad range of non-alphanumeric characters. + +.ifndef CHECK_RCPT_LOCAL_LOCALPARTS +CHECK_RCPT_LOCAL_LOCALPARTS = ^[.] : ^.*[@%!/|`#&?] +.endif + +.ifndef CHECK_RCPT_REMOTE_LOCALPARTS +CHECK_RCPT_REMOTE_LOCALPARTS = ^[./|] : ^.*[@%!`#&?] : ^.*/\\.\\./ +.endif + +# This access control list is used for every RCPT command in an incoming +# SMTP message. The tests are run in order until the address is either +# accepted or denied. +# +acl_check_rcpt: + + # Accept if the source is local SMTP (i.e. not over TCP/IP). We do this by + # testing for an empty sending host field. + accept + hosts = : + control = dkim_disable_verify + + # Do not try to verify DKIM signatures of incoming mail if DC_minimaldns + # or DISABLE_DKIM_VERIFY are set. +.ifdef DC_minimaldns + warn + control = dkim_disable_verify +.else +.ifdef DISABLE_DKIM_VERIFY + warn + control = dkim_disable_verify +.endif +.endif + + # The following section of the ACL is concerned with local parts that contain + # certain non-alphanumeric characters. Dots in unusual places are + # handled by this ACL as well. + # + # Non-alphanumeric characters other than dots are rarely found in genuine + # local parts, but are often tried by people looking to circumvent + # relaying restrictions. Therefore, although they are valid in local + # parts, these rules disallow certain non-alphanumeric characters, as + # a precaution. + # + # Empty components (two dots in a row) are not valid in RFC 2822, but Exim + # allows them because they have been encountered. (Consider local parts + # constructed as "firstinitial.secondinitial.familyname" when applied to + # a name without a second initial.) However, a local part starting + # with a dot or containing /../ can cause trouble if it is used as part of a + # file name (e.g. for a mailing list). This is also true for local parts that + # contain slashes. A pipe symbol can also be troublesome if the local part is + # incorporated unthinkingly into a shell command line. + # + # These ACL components will block recipient addresses that are valid + # from an RFC5322 point of view. We chose to have them blocked by + # default for security reasons. + # + # If you feel that your site should have less strict recipient + # checking, please feel free to change the default values of the macros + # defined in main/01_exim4-config_listmacrosdefs or override them from a + # local configuration file. + # + # Two different rules are used. The first one has a quite strict + # default, and is applied to messages that are addressed to one of the + # local domains handled by this host. + + # The default value of CHECK_RCPT_LOCAL_LOCALPARTS is defined + # at the top of this file. + .ifdef CHECK_RCPT_LOCAL_LOCALPARTS + deny + domains = +local_domains + local_parts = CHECK_RCPT_LOCAL_LOCALPARTS + message = restricted characters in address + .endif + + + # The second rule applies to all other domains, and its default is + # considerably less strict. + + # The default value of CHECK_RCPT_REMOTE_LOCALPARTS is defined in + # main/01_exim4-config_listmacrosdefs: + # CHECK_RCPT_REMOTE_LOCALPARTS = ^[./|] : ^.*[@%!`#&?] : ^.*/\\.\\./ + + # It allows local users to send outgoing messages to sites + # that use slashes and vertical bars in their local parts. It blocks + # local parts that begin with a dot, slash, or vertical bar, but allows + # these characters within the local part. However, the sequence /../ is + # barred. The use of some other non-alphanumeric characters is blocked. + # Single quotes might probably be dangerous as well, but they're + # allowed by the default regexps to avoid rejecting mails to Ireland. + # The motivation here is to prevent local users (or local users' malware) + # from mounting certain kinds of attack on remote sites. + .ifdef CHECK_RCPT_REMOTE_LOCALPARTS + deny + domains = !+local_domains + local_parts = CHECK_RCPT_REMOTE_LOCALPARTS + message = restricted characters in address + .endif + + + # Accept mail to postmaster in any local domain, regardless of the source, + # and without verifying the sender. + # + accept + .ifndef CHECK_RCPT_POSTMASTER + local_parts = postmaster + .else + local_parts = CHECK_RCPT_POSTMASTER + .endif + domains = +local_domains : +relay_to_domains + + + # Deny unless the sender address can be verified. + # + # This is disabled by default so that DNSless systems don't break. If + # your system can do DNS lookups without delay or cost, you might want + # to enable this feature. + # + # This feature does not work in smarthost and satellite setups as + # with these setups all domains pass verification. See spec.txt section + # "Access control lists" subsection "Address verification" with the added + # information that a smarthost/satellite setup routes all non-local e-mail + # to the smarthost. + .ifdef CHECK_RCPT_VERIFY_SENDER + deny + message = Sender verification failed + !acl = acl_local_deny_exceptions + !verify = sender + .endif + + # Verify senders listed in local_sender_callout with a callout. + # + # In smarthost and satellite setups, this causes the callout to be + # done to the smarthost. Verification will thus only be reliable if the + # smarthost does reject illegal addresses in the SMTP dialog. + deny + !acl = acl_local_deny_exceptions + senders = ${if exists{CONFDIR/local_sender_callout}\ + {CONFDIR/local_sender_callout}\ + {}} + !verify = sender/callout + + + # Accept if the message comes from one of the hosts for which we are an + # outgoing relay. It is assumed that such hosts are most likely to be MUAs, + # so we set control=submission to make Exim treat the message as a + # submission. It will fix up various errors in the message, for example, the + # lack of a Date: header line. If you are actually relaying out out from + # MTAs, you may want to disable this. If you are handling both relaying from + # MTAs and submissions from MUAs you should probably split them into two + # lists, and handle them differently. + + # Recipient verification is omitted here, because in many cases the clients + # are dumb MUAs that don't cope well with SMTP error responses. If you are + # actually relaying out from MTAs, you should probably add recipient + # verification here. + + # Note that, by putting this test before any DNS black list checks, you will + # always accept from these hosts, even if they end up on a black list. The + # assumption is that they are your friends, and if they get onto black + # list, it is a mistake. + accept + hosts = +relay_from_hosts + control = submission/sender_retain + control = dkim_disable_verify + + + # Accept if the message arrived over an authenticated connection, from + # any host. Again, these messages are usually from MUAs, so recipient + # verification is omitted, and submission mode is set. And again, we do this + # check before any black list tests. + accept + authenticated = * + control = submission/sender_retain + control = dkim_disable_verify + + # Insist that a HELO/EHLO was accepted. + + require message = nice hosts say HELO first + condition = ${if def:sender_helo_name} + + # Insist that any other recipient address that we accept is either in one of + # our local domains, or is in a domain for which we explicitly allow + # relaying. Any other domain is rejected as being unacceptable for relaying. + require + message = relay not permitted + domains = +local_domains : +relay_to_domains + + + # We also require all accepted addresses to be verifiable. This check will + # do local part verification for local domains, but only check the domain + # for remote domains. + require + verify = recipient + + + # Verify recipients listed in local_rcpt_callout with a callout. + # This is especially handy for forwarding MX hosts (secondary MX or + # mail hubs) of domains that receive a lot of spam to non-existent + # addresses. The only way to check local parts for remote relay + # domains is to use a callout (add /callout), but please read the + # documentation about callouts before doing this. + deny + !acl = acl_local_deny_exceptions + recipients = ${if exists{CONFDIR/local_rcpt_callout}\ + {CONFDIR/local_rcpt_callout}\ + {}} + !verify = recipient/callout + + + # CONFDIR/local_sender_blacklist holds a list of envelope senders that + # should have their access denied to the local host. Incoming messages + # with one of these senders are rejected at RCPT time. + # + # The explicit white lists are honored as well as negative items in + # the black list. See exim4-config_files(5) for details. + deny + message = sender envelope address $sender_address is locally blacklisted here. If you think this is wrong, get in touch with postmaster + log_message = sender envelope address is locally blacklisted. + !acl = acl_local_deny_exceptions + senders = ${if exists{CONFDIR/local_sender_blacklist}\ + {CONFDIR/local_sender_blacklist}\ + {}} + + + # deny bad sites (IP address) + # CONFDIR/local_host_blacklist holds a list of host names, IP addresses + # and networks (CIDR notation) that should have their access denied to + # The local host. Messages coming in from a listed host will have all + # RCPT statements rejected. + # + # The explicit white lists are honored as well as negative items in + # the black list. See exim4-config_files(5) for details. + deny + message = sender IP address $sender_host_address is locally blacklisted here. If you think this is wrong, get in touch with postmaster + log_message = sender IP address is locally blacklisted. + !acl = acl_local_deny_exceptions + hosts = ${if exists{CONFDIR/local_host_blacklist}\ + {CONFDIR/local_host_blacklist}\ + {}} + + + # Warn if the sender host does not have valid reverse DNS. + # + # If your system can do DNS lookups without delay or cost, you might want + # to enable this. + # If sender_host_address is defined, it's a remote call. If + # sender_host_name is not defined, then reverse lookup failed. Use + # this instead of !verify = reverse_host_lookup to catch deferrals + # as well as outright failures. + .ifdef CHECK_RCPT_REVERSE_DNS + warn + condition = ${if and{{def:sender_host_address}{!def:sender_host_name}}\ + {yes}{no}} + add_header = X-Host-Lookup-Failed: Reverse DNS lookup failed for $sender_host_address (${if eq{$host_lookup_failed}{1}{failed}{deferred}}) + .endif + + + # Use spfquery to perform a pair of SPF checks (for details, see + # http://www.openspf.org/) + # + # This is quite costly in terms of DNS lookups (~6 lookups per mail). Do not + # enable if that's an issue. Also note that if you enable this, you must + # install "spf-tools-perl" which provides the spfquery command. + # Missing spf-tools-perl will trigger the "Unexpected error in + # SPF check" warning. + .ifdef CHECK_RCPT_SPF + deny + message = [SPF] $sender_host_address is not allowed to send mail from \ + ${if def:sender_address_domain {$sender_address_domain}{$sender_helo_name}}. \ + Please see \ + http://www.openspf.org/Why?scope=${if def:sender_address_domain \ + {mfrom}{helo}};identity=${if def:sender_address_domain \ + {$sender_address}{$sender_helo_name}};ip=$sender_host_address + log_message = SPF check failed. + !acl = acl_local_deny_exceptions + condition = ${run{/usr/bin/spfquery.mail-spf-perl --ip \ + ${quote:$sender_host_address} --identity \ + ${if def:sender_address_domain \ + {--scope mfrom --identity ${quote:$sender_address}}\ + {--scope helo --identity ${quote:$sender_helo_name}}}}\ + {no}{${if eq {$runrc}{1}{yes}{no}}}} + + defer + message = Temporary DNS error while checking SPF record. Try again later. + !acl = acl_local_deny_exceptions + condition = ${if eq {$runrc}{5}{yes}{no}} + + warn + condition = ${if <={$runrc}{6}{yes}{no}} + add_header = Received-SPF: ${if eq {$runrc}{0}{pass}\ + {${if eq {$runrc}{2}{softfail}\ + {${if eq {$runrc}{3}{neutral}\ + {${if eq {$runrc}{4}{permerror}\ + {${if eq {$runrc}{6}{none}{error}}}}}}}}}\ + } client-ip=$sender_host_address; \ + ${if def:sender_address_domain \ + {envelope-from=${sender_address}; }{}}\ + helo=$sender_helo_name + + warn + log_message = Unexpected error in SPF check. + condition = ${if >{$runrc}{6}{yes}{no}} + .endif + + + # Check against classic DNS "black" lists (DNSBLs) which list + # sender IP addresses + .ifdef CHECK_RCPT_IP_DNSBLS + warn + dnslists = CHECK_RCPT_IP_DNSBLS + add_header = X-Warning: $sender_host_address is listed at $dnslist_domain ($dnslist_value: $dnslist_text) + log_message = $sender_host_address is listed at $dnslist_domain ($dnslist_value: $dnslist_text) + .endif + + + # Check against DNSBLs which list sender domains, with an option to locally + # whitelist certain domains that might be blacklisted. + # + # Note: If you define CHECK_RCPT_DOMAIN_DNSBLS, you must append + # "/$sender_address_domain" after each domain. For example: + # CHECK_RCPT_DOMAIN_DNSBLS = rhsbl.foo.org/$sender_address_domain \ + # : rhsbl.bar.org/$sender_address_domain + .ifdef CHECK_RCPT_DOMAIN_DNSBLS + warn + !senders = ${if exists{CONFDIR/local_domain_dnsbl_whitelist}\ + {CONFDIR/local_domain_dnsbl_whitelist}\ + {}} + dnslists = CHECK_RCPT_DOMAIN_DNSBLS + add_header = X-Warning: $sender_address_domain is listed at $dnslist_domain ($dnslist_value: $dnslist_text) + log_message = $sender_address_domain is listed at $dnslist_domain ($dnslist_value: $dnslist_text) + .endif + + + # This hook allows you to hook in your own ACLs without having to + # modify this file. If you do it like we suggest, you'll end up with + # a small performance penalty since there is an additional file being + # accessed. This doesn't happen if you leave the macro unset. + .ifdef CHECK_RCPT_LOCAL_ACL_FILE + .include CHECK_RCPT_LOCAL_ACL_FILE + .endif + + + ############################################################################# + # This check is commented out because it is recognized that not every + # sysadmin will want to do it. If you enable it, the check performs + # Client SMTP Authorization (csa) checks on the sending host. These checks + # do DNS lookups for SRV records. The CSA proposal is currently (May 2005) + # an Internet draft. You can, of course, add additional conditions to this + # ACL statement to restrict the CSA checks to certain hosts only. + # + # require verify = csa + ############################################################################# + + + # Accept if the address is in a domain for which we are an incoming relay, + # but again, only if the recipient can be verified. + + accept + domains = +relay_to_domains + endpass + verify = recipient + + + # At this point, the address has passed all the checks that have been + # configured, so we accept it unconditionally. + + accept diff --git a/exim4/conf.d/acl/40_exim4-config_check_data b/exim4/conf.d/acl/40_exim4-config_check_data new file mode 100644 index 00000000..5b5c099c --- /dev/null +++ b/exim4/conf.d/acl/40_exim4-config_check_data @@ -0,0 +1,95 @@ + +### acl/40_exim4-config_check_data +################################# + +# This ACL is used after the contents of a message have been received. This +# is the ACL in which you can test a message's headers or body, and in +# particular, this is where you can invoke external virus or spam scanners. + +acl_check_data: + + # Deny if the message contains an overlong line. Per the standards + # we should never receive one such via SMTP. + # + .ifndef IGNORE_SMTP_LINE_LENGTH_LIMIT + deny message = maximum allowed line length is 998 octets, \ + got $max_received_linelength + condition = ${if > {$max_received_linelength}{998}} + .endif + + # Deny if the headers contain badly-formed addresses. + # + .ifndef NO_CHECK_DATA_VERIFY_HEADER_SYNTAX + deny + !acl = acl_local_deny_exceptions + !verify = header_syntax + message = header syntax + log_message = header syntax ($acl_verify_message) + .endif + + + # require that there is a verifiable sender address in at least + # one of the "Sender:", "Reply-To:", or "From:" header lines. + .ifdef CHECK_DATA_VERIFY_HEADER_SENDER + deny + message = No verifiable sender address in message headers + !acl = acl_local_deny_exceptions + !verify = header_sender + .endif + + + # Deny if the message contains malware. Before enabling this check, you + # must install a virus scanner and set the av_scanner option in the + # main configuration. + # + # exim4-daemon-heavy must be used for this section to work. + # + # deny + # malware = * + # message = This message was detected as possible malware ($malware_name). + + + # Add headers to a message if it is judged to be spam. Before enabling this, + # you must install SpamAssassin. You may also need to set the spamd_address + # option in the main configuration. + # + # exim4-daemon-heavy must be used for this section to work. + # + # Please note that this is only suiteable as an example. See + # /usr/share/doc/exim4-base/README.Debian.gz + # + # See the exim docs and the exim wiki for more suitable examples. + # + # # Remove internal headers + # warn + # remove_header = X-Spam_score: X-Spam_score_int : X-Spam_bar : \ + # X-Spam_report + # + # warn + # condition = ${if <{$message_size}{120k}{1}{0}} + # # ":true" to add headers/acl variables even if not spam + # spam = nobody:true + # add_header = X-Spam_score: $spam_score + # add_header = X-Spam_bar: $spam_bar + # # Do not enable this unless you have shorted SpamAssassin's report + # #add_header = X-Spam_report: $spam_report + # + # Reject spam messages (score >15.0). + # This breaks mailing list and forward messages. + # deny + # message = Classified as spam (score $spam_score) + # condition = ${if <{$message_size}{120k}{1}{0}} + # condition = ${if >{$spam_score_int}{150}{true}{false}} + + + # This hook allows you to hook in your own ACLs without having to + # modify this file. If you do it like we suggest, you'll end up with + # a small performance penalty since there is an additional file being + # accessed. This doesn't happen if you leave the macro unset. + .ifdef CHECK_DATA_LOCAL_ACL_FILE + .include CHECK_DATA_LOCAL_ACL_FILE + .endif + + + # accept otherwise + accept diff --git a/exim4/conf.d/auth/00_exim4-config_header b/exim4/conf.d/auth/00_exim4-config_header new file mode 100644 index 00000000..c5f8fc15 --- /dev/null +++ b/exim4/conf.d/auth/00_exim4-config_header @@ -0,0 +1,8 @@ + +###################################################################### +# AUTHENTICATION CONFIGURATION # +###################################################################### + +begin authenticators + + diff --git a/exim4/conf.d/auth/30_exim4-config_examples b/exim4/conf.d/auth/30_exim4-config_examples new file mode 100644 index 00000000..b3b1ce69 --- /dev/null +++ b/exim4/conf.d/auth/30_exim4-config_examples @@ -0,0 +1,254 @@ + +### auth/30_exim4-config_examples +################################# + +# The examples below are for server side authentication, when the +# local exim is SMTP server and clients authenticate to the local exim. + +# They allow two styles of plain-text authentication against an +# CONFDIR/passwd file whose syntax is described in exim4_passwd(5). + +# Hosts that are allowed to use AUTH are defined by the +# auth_advertise_hosts option in the main configuration. The default is +# "*", which allows authentication to all hosts over all kinds of +# connections if there is at least one authenticator defined here. +# Authenticators which rely on unencrypted clear text passwords don't +# advertise on unencrypted connections by default. Thus, it might be +# wise to set up TLS to allow encrypted connections. If TLS cannot be +# used for some reason, you can set AUTH_SERVER_ALLOW_NOTLS_PASSWORDS to +# advertise unencrypted clear text password based authenticators on all +# connections. As this is severely reducing security, using TLS is +# preferred over allowing clear text password based authenticators on +# unencrypted connections. + +# PLAIN authentication has no server prompts. The client sends its +# credentials in one lump, containing an authorization ID (which we do not +# use), an authentication ID, and a password. The latter two appear as +# $auth2 and $auth3 in the configuration and should be checked against a +# valid username and password. In a real configuration you would typically +# use $auth2 as a lookup key, and compare $auth3 against the result of the +# lookup, perhaps using the crypteq{}{} condition. + +# plain_server: +# driver = plaintext +# public_name = PLAIN +# server_condition = "${if crypteq{$auth3}{${extract{1}{:}{${lookup{$auth2}lsearch{CONFDIR/passwd}{$value}{*:*}}}}}{1}{0}}" +# server_set_id = $auth2 +# server_prompts = : +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif + +# LOGIN authentication has traditional prompts and responses. There is no +# authorization ID in this mechanism, so unlike PLAIN the username and +# password are $auth1 and $auth2. Apart from that you can use the same +# server_condition setting for both authenticators. + +# login_server: +# driver = plaintext +# public_name = LOGIN +# server_prompts = "Username:: : Password::" +# server_condition = "${if crypteq{$auth2}{${extract{1}{:}{${lookup{$auth1}lsearch{CONFDIR/passwd}{$value}{*:*}}}}}{1}{0}}" +# server_set_id = $auth1 +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif +# +# cram_md5_server: +# driver = cram_md5 +# public_name = CRAM-MD5 +# server_secret = ${extract{2}{:}{${lookup{$auth1}lsearch{CONFDIR/passwd}{$value}fail}}} +# server_set_id = $auth1 + +# Here is an example of CRAM-MD5 authentication against PostgreSQL: +# +# psqldb_auth_server: +# driver = cram_md5 +# public_name = CRAM-MD5 +# server_secret = ${lookup pgsql{SELECT pw FROM users WHERE username = '${quote_pgsql:$auth1}'}{$value}fail} +# server_set_id = $auth1 + +# Authenticate against local passwords using sasl2-bin +# Requires exim_uid to be a member of sasl group, see README.Debian.gz +# plain_saslauthd_server: +# driver = plaintext +# public_name = PLAIN +# server_condition = ${if saslauthd{{$auth2}{$auth3}}{1}{0}} +# server_set_id = $auth2 +# server_prompts = : +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif +# +# login_saslauthd_server: +# driver = plaintext +# public_name = LOGIN +# server_prompts = "Username:: : Password::" +# # don't send system passwords over unencrypted connections +# server_condition = ${if saslauthd{{$auth1}{$auth2}}{1}{0}} +# server_set_id = $auth1 +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif +# +# ntlm_sasl_server: +# driver = cyrus_sasl +# public_name = NTLM +# server_realm = +# server_set_id = $auth1 +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif +# +# digest_md5_sasl_server: +# driver = cyrus_sasl +# public_name = DIGEST-MD5 +# server_realm = +# server_set_id = $auth1 +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif + +# Authentcate against cyrus-sasl +# This is mainly untested, please report any problems to +# pkg-exim4-users@lists.alioth.debian.org. +# cram_md5_sasl_server: +# driver = cyrus_sasl +# public_name = CRAM-MD5 +# server_realm = +# server_set_id = $auth1 +# +# plain_sasl_server: +# driver = cyrus_sasl +# public_name = PLAIN +# server_realm = +# server_set_id = $auth1 +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif +# +# login_sasl_server: +# driver = cyrus_sasl +# public_name = LOGIN +# server_realm = +# server_set_id = $auth1 +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif + +# Authenticate against courier authdaemon + +# This is now the (working!) example from +# http://www.exim.org/eximwiki/FAQ/Policy_controls/Q0730 +# Possible pitfall: access rights on /var/run/courier/authdaemon/socket. +# plain_courier_authdaemon: +# driver = plaintext +# public_name = PLAIN +# server_condition = \ +# ${extract {ADDRESS} \ +# {${readsocket{/var/run/courier/authdaemon/socket} \ +# {AUTH ${strlen:exim\nlogin\n$auth2\n$auth3\n}\nexim\nlogin\n$auth2\n$auth3\n} }} \ +# {yes} \ +# fail} +# server_set_id = $auth2 +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif + +# login_courier_authdaemon: +# driver = plaintext +# public_name = LOGIN +# server_prompts = Username:: : Password:: +# server_condition = \ +# ${extract {ADDRESS} \ +# {${readsocket{/var/run/courier/authdaemon/socket} \ +# {AUTH ${strlen:exim\nlogin\n$auth1\n$auth2\n}\nexim\nlogin\n$auth1\n$auth2\n} }} \ +# {yes} \ +# fail} +# server_set_id = $auth1 +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif + +# This one is a bad hack to support the broken version 4.xx of +# Microsoft Outlook Express which violates the RFCs by demanding +# "250-AUTH=" instead of "250-AUTH ". +# If your list of offered authenticators is other than PLAIN and LOGIN, +# you need to adapt the public_name line manually. +# It has to be the last authenticator to work and has not been tested +# well. Use at your own risk. +# See the thread entry point from +# http://www.exim.org/mail-archives/exim-users/Week-of-Mon-20050214/msg00213.html +# for the related discussion on the exim-users mailing list. +# Thanks to Fred Viles for this great work. + +# support_broken_outlook_express_4_server: +# driver = plaintext +# public_name = "\r\n250-AUTH=PLAIN LOGIN" +# server_prompts = User Name : Password +# server_condition = no +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif + +############## +# See /usr/share/doc/exim4-base/README.Debian.gz +############## + +# These examples below are the equivalent for client side authentication. +# They get the passwords from CONFDIR/passwd.client, whose format is +# defined in exim4_passwd_client(5) + +# Because AUTH PLAIN and AUTH LOGIN send the password in clear, we +# only allow these mechanisms over encrypted connections by default. +# You can set AUTH_CLIENT_ALLOW_NOTLS_PASSWORDS to allow unencrypted +# clear text password authentication on all connections. + +cram_md5: + driver = cram_md5 + public_name = CRAM-MD5 + client_name = ${extract{1}{:}{${lookup{$host}nwildlsearch{CONFDIR/passwd.client}{$value}fail}}} + client_secret = ${extract{2}{:}{${lookup{$host}nwildlsearch{CONFDIR/passwd.client}{$value}fail}}} + +# this returns the matching line from passwd.client and doubles all ^ +PASSWDLINE=${sg{\ + ${lookup{$host}nwildlsearch{CONFDIR/passwd.client}{$value}fail}\ + }\ + {\\N[\\^]\\N}\ + {^^}\ + } + +plain: + driver = plaintext + public_name = PLAIN +.ifndef AUTH_CLIENT_ALLOW_NOTLS_PASSWORDS + client_send = "<; ${if !eq{$tls_out_cipher}{}\ + {^${extract{1}{:}{PASSWDLINE}}\ + ^${sg{PASSWDLINE}{\\N([^:]+:)(.*)\\N}{\\$2}}\ + }fail}" +.else + client_send = "<; ^${extract{1}{:}{PASSWDLINE}}\ + ^${sg{PASSWDLINE}{\\N([^:]+:)(.*)\\N}{\\$2}}" +.endif + +login: + driver = plaintext + public_name = LOGIN +.ifndef AUTH_CLIENT_ALLOW_NOTLS_PASSWORDS + # Return empty string if not non-TLS AND looking up $host in passwd-file + # yields a non-empty string; fail otherwise. + client_send = "<; ${if and{\ + {!eq{$tls_out_cipher}{}}\ + {!eq{PASSWDLINE}{}}\ + }\ + {}fail}\ + ; ${extract{1}{::}{PASSWDLINE}}\ + ; ${sg{PASSWDLINE}{\\N([^:]+:)(.*)\\N}{\\$2}}" +.else + # Return empty string if looking up $host in passwd-file yields a + # non-empty string; fail otherwise. + client_send = "<; ${if !eq{PASSWDLINE}{}\ + {}fail}\ + ; ${extract{1}{::}{PASSWDLINE}}\ + ; ${sg{PASSWDLINE}{\\N([^:]+:)(.*)\\N}{\\$2}}" +.endif diff --git a/exim4/conf.d/main/01_exim4-config_listmacrosdefs b/exim4/conf.d/main/01_exim4-config_listmacrosdefs new file mode 100644 index 00000000..baa48faa --- /dev/null +++ b/exim4/conf.d/main/01_exim4-config_listmacrosdefs @@ -0,0 +1,81 @@ +###################################################################### +# Runtime configuration file for Exim 4 (Debian Packaging) # +###################################################################### + +###################################################################### +# /etc/exim4/exim4.conf.template is only used with the non-split +# configuration scheme. +# /etc/exim4/conf.d/main/01_exim4-config_listmacrosdefs is only used +# with the split configuration scheme. +# If you find this comment anywhere else, somebody copied it there. +# Documentation about the Debian exim4 configuration scheme can be +# found in /usr/share/doc/exim4-base/README.Debian.gz. +###################################################################### + +###################################################################### +# MAIN CONFIGURATION SETTINGS # +###################################################################### + +# Just for reference and scripts. +# On Debian systems, the main binary is installed as exim4 to avoid +# conflicts with the exim 3 packages. +exim_path = /usr/sbin/exim4 + +# Macro defining the main configuration directory. +# We do not use absolute paths. +.ifndef CONFDIR +CONFDIR = /etc/exim4 +.endif + +# debconf-driven macro definitions get inserted after this line +UPEX4CmacrosUPEX4C = 1 + +# Create domain and host lists for relay control +# '@' refers to 'the name of the local host' + +# List of domains considered local for exim. Domains not listed here +# need to be deliverable remotely. +domainlist local_domains = MAIN_LOCAL_DOMAINS + +# List of recipient domains to relay _to_. Use this list if you're - +# for example - fallback MX or mail gateway for domains. +domainlist relay_to_domains = MAIN_RELAY_TO_DOMAINS + +# List of sender networks (IP addresses) to _unconditionally_ relay +# _for_. If you intend to be SMTP AUTH server, you do not need to enter +# anything here. +hostlist relay_from_hosts = MAIN_RELAY_NETS + + +# Decide which domain to use to add to all unqualified addresses. +# If MAIN_PRIMARY_HOSTNAME_AS_QUALIFY_DOMAIN is defined, the primary +# hostname is used. If not, but MAIN_QUALIFY_DOMAIN is set, the value +# of MAIN_QUALIFY_DOMAIN is used. If both macros are not defined, +# the first line of /etc/mailname is used. +.ifndef MAIN_PRIMARY_HOSTNAME_AS_QUALIFY_DOMAIN +.ifndef MAIN_QUALIFY_DOMAIN +qualify_domain = ETC_MAILNAME +.else +qualify_domain = MAIN_QUALIFY_DOMAIN +.endif +.endif + +# listen on all all interfaces? +.ifdef MAIN_LOCAL_INTERFACES +local_interfaces = MAIN_LOCAL_INTERFACES +.endif + +.ifndef LOCAL_DELIVERY +# The default transport, set in /etc/exim4/update-exim4.conf.conf, +# defaulting to mail_spool. See CONFDIR/conf.d/transport/ for possibilities +LOCAL_DELIVERY=mail_spool +.endif + +# The gecos field in /etc/passwd holds not only the name. see passwd(5). +gecos_pattern = ^([^,:]*) +gecos_name = $1 + +# always log tls_peerdn as we use TLS for outgoing connects by default +.ifndef MAIN_LOG_SELECTOR +MAIN_LOG_SELECTOR = +smtp_protocol_error +smtp_syntax_error +tls_certificate_verified +tls_peerdn +.endif diff --git a/exim4/conf.d/main/02_exim4-config_options b/exim4/conf.d/main/02_exim4-config_options new file mode 100644 index 00000000..abff1d8b --- /dev/null +++ b/exim4/conf.d/main/02_exim4-config_options @@ -0,0 +1,222 @@ + +### main/02_exim4-config_options +################################# + + +# Defines the access control list that is run when an +# SMTP MAIL command is received. +# +.ifndef MAIN_ACL_CHECK_MAIL +MAIN_ACL_CHECK_MAIL = acl_check_mail +.endif +acl_smtp_mail = MAIN_ACL_CHECK_MAIL + + +# Defines the access control list that is run when an +# SMTP RCPT command is received. +# +.ifndef MAIN_ACL_CHECK_RCPT +MAIN_ACL_CHECK_RCPT = acl_check_rcpt +.endif +acl_smtp_rcpt = MAIN_ACL_CHECK_RCPT + + +# Defines the access control list that is run when an +# SMTP DATA command is received. +# +.ifndef MAIN_ACL_CHECK_DATA +MAIN_ACL_CHECK_DATA = acl_check_data +.endif +acl_smtp_data = MAIN_ACL_CHECK_DATA + + +# Message size limit. The default (used when MESSAGE_SIZE_LIMIT +# is unset) is 50 MB +.ifdef MESSAGE_SIZE_LIMIT +message_size_limit = MESSAGE_SIZE_LIMIT +.endif + + +# If you are running exim4-daemon-heavy or a custom version of Exim that +# was compiled with the content-scanning extension, you can cause incoming +# messages to be automatically scanned for viruses. You have to modify the +# configuration in two places to set this up. The first of them is here, +# where you define the interface to your scanner. This example is typical +# for ClamAV; see the manual for details of what to set for other virus +# scanners. The second modification is in the acl_check_data access +# control list. + +# av_scanner = clamd:/var/run/clamav/clamd.ctl + + +# For spam scanning, there is a similar option that defines the interface to +# SpamAssassin. You do not need to set this if you are using the default, which +# is shown in this commented example. As for virus scanning, you must also +# modify the acl_check_data access control list to enable spam scanning. + +# spamd_address = 127.0.0.1 783 + +# Domain used to qualify unqualified recipient addresses +# If this option is not set, the qualify_domain value is used. +# qualify_recipient = + + +# Allow Exim to recognize addresses of the form "user@[10.11.12.13]", +# where the domain part is a "domain literal" (an IP address) instead +# of a named domain. The RFCs require this facility, but it is disabled +# in the default config since it is rarely used and frequently abused. +# Domain literal support also needs a special router, which is automatically +# enabled if you use the enable macro MAIN_ALLOW_DOMAIN_LITERALS. +# Additionally, you might want to make your local IP addresses (or @[]) +# local domains. +.ifdef MAIN_ALLOW_DOMAIN_LITERALS +allow_domain_literals +.endif + + +# Do a reverse DNS lookup on all incoming IP calls, in order to get the +# true host name. If you feel this is too expensive, the networks for +# which a lookup is done can be listed here. +.ifndef DC_minimaldns +.ifndef MAIN_HOST_LOOKUP +MAIN_HOST_LOOKUP = * +.endif +host_lookup = MAIN_HOST_LOOKUP +.endif + +# The setting below causes Exim to try to initialize the system resolver +# library with DNSSEC support. It has no effect if your library lacks +# DNSSEC support. +dns_dnssec_ok = 1 + +# In a minimaldns setup, update-exim4.conf guesses the hostname and +# dumps it here to avoid DNS lookups being done at Exim run time. +.ifdef MAIN_HARDCODE_PRIMARY_HOSTNAME +primary_hostname = MAIN_HARDCODE_PRIMARY_HOSTNAME +.endif + +# The settings below cause Exim to make RFC 1413 (ident) callbacks +# for all incoming SMTP calls. You can limit the hosts to which these +# calls are made, and/or change the timeout that is used. If you set +# the timeout to zero, all RFC 1413 calls are disabled. RFC 1413 calls +# are cheap and can provide useful information for tracing problem +# messages, but some hosts and firewalls have problems with them. +# This can result in a timeout instead of an immediate refused +# connection, leading to delays on starting up SMTP sessions. +# (The default was reduced from 30s to 5s for release 4.61. and to +# disabled for release 4.86) +# +#rfc1413_hosts = * +#rfc1413_query_timeout = 5s + + +# Enable an efficiency feature. We advertise the feature; clients +# may request to use it. For multi-recipient mails we then can +# reject or accept per-user after the message is received. +# +prdr_enable = true + +# When using an external relay tester (such as rt.njabl.org and/or the +# currently defunct relay-test.mail-abuse.org, the test may be aborted +# since exim complains about "too many nonmail commands". If you want +# the test to complete, add the host from where "your" relay tester +# connects from to the MAIN_SMTP_ACCEPT_MAX_NOMAIL_HOSTS macro. +# Please note that a non-empty setting may cause extra DNS lookups to +# happen, which is the reason why this option is commented out in the +# default settings. +# MAIN_SMTP_ACCEPT_MAX_NOMAIL_HOSTS = !rt.njabl.org +.ifdef MAIN_SMTP_ACCEPT_MAX_NOMAIL_HOSTS +smtp_accept_max_nonmail_hosts = MAIN_SMTP_ACCEPT_MAX_NOMAIL_HOSTS +.endif + +# By default, exim forces a Sender: header containing the local +# account name at the local host name in all locally submitted messages +# that don't have the local account name at the local host name in the +# From: header, deletes any Sender: header present in the submitted +# message and forces the envelope sender of all locally submitted +# messages to the local account name at the local host name. +# The following settings allow local users to specify their own envelope sender +# in a locally submitted message. Sender: headers existing in a locally +# submitted message are not removed, and no automatic Sender: headers +# are added. These settings are fine for most hosts. +# If you run exim on a classical multi-user systems where all users +# have local mailboxes that can be reached via SMTP from the Internet +# with the local FQDN as the domain part of the address, you might want +# to disable the following three lines for traceability reasons. +.ifndef MAIN_FORCE_SENDER +local_from_check = false +local_sender_retain = true +untrusted_set_sender = * +.endif + + +# By default, Exim expects all envelope addresses to be fully qualified, that +# is, they must contain both a local part and a domain. Configure exim +# to accept unqualified addresses from certain hosts. When this is done, +# unqualified addresses are qualified using the settings of qualify_domain +# and/or qualify_recipient (see above). +# sender_unqualified_hosts = +# recipient_unqualified_hosts = + + +# Configure Exim to support the "percent hack" for certain domains. +# The "percent hack" is the feature by which mail addressed to x%y@z +# (where z is one of the domains listed) is locally rerouted to x@y +# and sent on. If z is not one of the "percent hack" domains, x%y is +# treated as an ordinary local part. The percent hack is rarely needed +# nowadays but frequently abused. You should not enable it unless you +# are sure that you really need it. +# percent_hack_domains = + + +# Bounce handling +.ifndef MAIN_IGNORE_BOUNCE_ERRORS_AFTER +MAIN_IGNORE_BOUNCE_ERRORS_AFTER = 2d +.endif +ignore_bounce_errors_after = MAIN_IGNORE_BOUNCE_ERRORS_AFTER + +.ifndef MAIN_TIMEOUT_FROZEN_AFTER +MAIN_TIMEOUT_FROZEN_AFTER = 7d +.endif +timeout_frozen_after = MAIN_TIMEOUT_FROZEN_AFTER + +.ifndef MAIN_FREEZE_TELL +MAIN_FREEZE_TELL = postmaster +.endif +freeze_tell = MAIN_FREEZE_TELL + + +# Define spool directory +.ifndef SPOOLDIR +SPOOLDIR = /var/spool/exim4 +.endif +spool_directory = SPOOLDIR + + +# trusted users can set envelope-from to arbitrary values +.ifndef MAIN_TRUSTED_USERS +MAIN_TRUSTED_USERS = uucp +.endif +trusted_users = MAIN_TRUSTED_USERS +.ifdef MAIN_TRUSTED_GROUPS +trusted_groups = MAIN_TRUSTED_GROUPS +.endif + + +# users in admin group can do many other things +# admin_groups = + + +# SMTP Banner. The example includes the Debian version in the SMTP dialog +# MAIN_SMTP_BANNER = "${primary_hostname} ESMTP Exim ${version_number} (Debian package MAIN_PACKAGE_VERSION) ${tod_full}" +# smtp_banner = $smtp_active_hostname ESMTP Exim $version_number $tod_full + +.ifdef MAIN_KEEP_ENVIRONMENT +keep_environment = MAIN_KEEP_ENVIRONMENT +.else +# set option to empty value to avoid warning. +keep_environment = +.endif +.ifdef MAIN_ADD_ENVIRONMENT +add_environment = MAIN_ADD_ENVIRONMENT +.endif diff --git a/exim4/conf.d/main/03_exim4-config_tlsoptions b/exim4/conf.d/main/03_exim4-config_tlsoptions new file mode 100644 index 00000000..86299e16 --- /dev/null +++ b/exim4/conf.d/main/03_exim4-config_tlsoptions @@ -0,0 +1,85 @@ + +### main/03_exim4-config_tlsoptions +################################# + +# TLS/SSL configuration for exim as an SMTP server. +# See /usr/share/doc/exim4-base/README.Debian.gz for explanations. + +.ifdef MAIN_TLS_ENABLE +# Defines what hosts to 'advertise' STARTTLS functionality to. The +# default, *, will advertise to all hosts that connect with EHLO. +.ifndef MAIN_TLS_ADVERTISE_HOSTS +MAIN_TLS_ADVERTISE_HOSTS = * +.endif +tls_advertise_hosts = MAIN_TLS_ADVERTISE_HOSTS + + +# Full paths to Certificate and Private Key. The Private Key file +# must be kept 'secret' and should be owned by root.Debian-exim mode +# 640 (-rw-r-----). exim-gencert takes care of these prerequisites. +# Normally, exim4 looks for certificate and key in different files: +# MAIN_TLS_CERTIFICATE - path to certificate file, +# CONFDIR/exim.crt if unset +# MAIN_TLS_PRIVATEKEY - path to private key file +# CONFDIR/exim.key if unset +# You can also configure exim to look for certificate and key in the +# same file, set MAIN_TLS_CERTKEY to that file to enable. This takes +# precedence over all other settings regarding certificate and key file. +.ifdef MAIN_TLS_CERTKEY +tls_certificate = MAIN_TLS_CERTKEY +.else +.ifndef MAIN_TLS_CERTIFICATE +MAIN_TLS_CERTIFICATE = CONFDIR/exim.crt +.endif +tls_certificate = MAIN_TLS_CERTIFICATE + +.ifndef MAIN_TLS_PRIVATEKEY +MAIN_TLS_PRIVATEKEY = CONFDIR/exim.key +.endif +tls_privatekey = MAIN_TLS_PRIVATEKEY +.endif + +# Pointer to the CA Certificates against which client certificates are +# checked. This is controlled by the `tls_verify_hosts' and +# `tls_try_verify_hosts' lists below. +# If you want to check server certificates, you need to add an +# tls_verify_certificates statement to the smtp transport. +# /etc/ssl/certs/ca-certificates.crt is generated by +# the "ca-certificates" package's update-ca-certificates(8) command. +.ifndef MAIN_TLS_VERIFY_CERTIFICATES +MAIN_TLS_VERIFY_CERTIFICATES = ${if exists{/etc/ssl/certs/ca-certificates.crt}\ + {/etc/ssl/certs/ca-certificates.crt}\ + {/dev/null}} +.endif +tls_verify_certificates = MAIN_TLS_VERIFY_CERTIFICATES + + +# A list of hosts which are constrained by `tls_verify_certificates'. A host +# that matches `tls_verify_host' must present a certificate that is +# verifyable through `tls_verify_certificates' in order to be accepted as an +# SMTP client. If it does not, the connection is aborted. +.ifdef MAIN_TLS_VERIFY_HOSTS +tls_verify_hosts = MAIN_TLS_VERIFY_HOSTS +.endif + +# A weaker form of checking: if a client matches `tls_try_verify_hosts' (but +# not `tls_verify_hosts'), request a certificate and check it against +# `tls_verify_certificates' but do not abort the connection if there is no +# certificate or if the certificate presented does not match. (This +# condition can be tested for in ACLs through `verify = certificate') +# By default, this check is done for all hosts. It is known that some +# clients (including incredimail's version downloadable in February +# 2008) choke on this. To disable, set MAIN_TLS_TRY_VERIFY_HOSTS to an +# empty value. +.ifdef MAIN_TLS_TRY_VERIFY_HOSTS +tls_try_verify_hosts = MAIN_TLS_TRY_VERIFY_HOSTS +.endif + +.ifdef _HAVE_GNUTLS +tls_dhparam = historic +.endif + +.else +# Don't advertise TLS if MAIN_TLS_ENABLE is not set. +tls_advertise_hosts = +.endif diff --git a/exim4/conf.d/main/90_exim4-config_log_selector b/exim4/conf.d/main/90_exim4-config_log_selector new file mode 100644 index 00000000..685c404c --- /dev/null +++ b/exim4/conf.d/main/90_exim4-config_log_selector @@ -0,0 +1,10 @@ + +### main/90_exim4-config_log_selector +################################# + +# uncomment this for debugging +# MAIN_LOG_SELECTOR == MAIN_LOG_SELECTOR +all -subject -arguments + +.ifdef MAIN_LOG_SELECTOR +log_selector = MAIN_LOG_SELECTOR +.endif diff --git a/exim4/conf.d/retry/00_exim4-config_header b/exim4/conf.d/retry/00_exim4-config_header new file mode 100644 index 00000000..e2bb4a48 --- /dev/null +++ b/exim4/conf.d/retry/00_exim4-config_header @@ -0,0 +1,7 @@ + +###################################################################### +# RETRY CONFIGURATION # +###################################################################### + +begin retry + diff --git a/exim4/conf.d/retry/30_exim4-config b/exim4/conf.d/retry/30_exim4-config new file mode 100644 index 00000000..52b002f3 --- /dev/null +++ b/exim4/conf.d/retry/30_exim4-config @@ -0,0 +1,19 @@ + +### retry/30_exim4-config +################################# + +# This single retry rule applies to all domains and all errors. It specifies +# retries every 15 minutes for 2 hours, then increasing retry intervals, +# starting at 1 hour and increasing each time by a factor of 1.5, up to 16 +# hours, then retries every 6 hours until 4 days have passed since the first +# failed delivery. + +# Please note that these rules only limit the frequency of retries, the +# effective retry-time depends on the frequency of queue-running, too. +# See QUEUEINTERVAL in /etc/default/exim4. + +# Address or Domain Error Retries +# ----------------- ----- ------- + +* * F,2h,15m; G,16h,1h,1.5; F,4d,6h + diff --git a/exim4/conf.d/rewrite/00_exim4-config_header b/exim4/conf.d/rewrite/00_exim4-config_header new file mode 100644 index 00000000..a32db174 --- /dev/null +++ b/exim4/conf.d/rewrite/00_exim4-config_header @@ -0,0 +1,7 @@ + +###################################################################### +# REWRITE CONFIGURATION # +###################################################################### + +begin rewrite + diff --git a/exim4/conf.d/rewrite/31_exim4-config_rewriting b/exim4/conf.d/rewrite/31_exim4-config_rewriting new file mode 100644 index 00000000..b7415b6c --- /dev/null +++ b/exim4/conf.d/rewrite/31_exim4-config_rewriting @@ -0,0 +1,16 @@ + +### rewrite/31_exim4-config_rewriting +################################# + +# This rewriting rule is particularly useful for dialup users who +# don't have their own domain, but could be useful for anyone. +# It looks up the real address of all local users in a file +.ifndef NO_EAA_REWRITE_REWRITE +*@+local_domains "${lookup{${local_part}}lsearch{/etc/email-addresses}\ + {$value}fail}" Ffrs +# identical rewriting rule for /etc/mailname +*@ETC_MAILNAME "${lookup{${local_part}}lsearch{/etc/email-addresses}\ + {$value}fail}" Ffrs +.endif + + diff --git a/exim4/conf.d/router/00_exim4-config_header b/exim4/conf.d/router/00_exim4-config_header new file mode 100644 index 00000000..531e21f1 --- /dev/null +++ b/exim4/conf.d/router/00_exim4-config_header @@ -0,0 +1,11 @@ + +###################################################################### +# ROUTERS CONFIGURATION # +# Specifies how addresses are handled # +###################################################################### +# THE ORDER IN WHICH THE ROUTERS ARE DEFINED IS IMPORTANT! # +# An address is passed to each router in turn until it is accepted. # +###################################################################### + +begin routers + diff --git a/exim4/conf.d/router/100_exim4-config_domain_literal b/exim4/conf.d/router/100_exim4-config_domain_literal new file mode 100644 index 00000000..d37fea6f --- /dev/null +++ b/exim4/conf.d/router/100_exim4-config_domain_literal @@ -0,0 +1,18 @@ + +### router/100_exim4-config_domain_literal +################################# + +# This router handles e-mail addresses in "domain literal" form like +# . The RFCs require this facility, but it is disabled +# in the default config since it is rarely used and frequently abused. +# Domain literal support also needs to be enabled in the main config, +# which is automatically done if you use the enable macro +# MAIN_ALLOW_DOMAIN_LITERALS. + +.ifdef MAIN_ALLOW_DOMAIN_LITERALS +domain_literal: + debug_print = "R: domain_literal for $local_part@$domain" + driver = ipliteral + domains = ! +local_domains + transport = remote_smtp +.endif diff --git a/exim4/conf.d/router/150_exim4-config_hubbed_hosts b/exim4/conf.d/router/150_exim4-config_hubbed_hosts new file mode 100644 index 00000000..a0fcb267 --- /dev/null +++ b/exim4/conf.d/router/150_exim4-config_hubbed_hosts @@ -0,0 +1,18 @@ + +# router/150_exim4-config_hubbed_hosts +################################# + +# route specific domains manually. +# +# see exim4-config_files(5) and spec.txt chapter 20.3 through 20.7 for +# more detailed documentation. + +hubbed_hosts: + debug_print = "R: hubbed_hosts for $domain" + driver = manualroute + domains = "${if exists{CONFDIR/hubbed_hosts}\ + {partial-lsearch;CONFDIR/hubbed_hosts}\ + fail}" + same_domain_copy_routing = yes + route_data = ${lookup{$domain}partial-lsearch{CONFDIR/hubbed_hosts}} + transport = remote_smtp diff --git a/exim4/conf.d/router/200_exim4-config_primary b/exim4/conf.d/router/200_exim4-config_primary new file mode 100644 index 00000000..8b03ae7a --- /dev/null +++ b/exim4/conf.d/router/200_exim4-config_primary @@ -0,0 +1,92 @@ + +### router/200_exim4-config_primary +################################# +# This file holds the primary router, responsible for nonlocal mails + +.ifdef DCconfig_internet +# configtype=internet +# +# deliver mail to the recipient if recipient domain is a domain we +# relay for. We do not ignore any target hosts here since delivering to +# a site local or even a link local address might be wanted here, and if +# such an address has found its way into the MX record of such a domain, +# the local admin is probably in a place where that broken MX record +# could be fixed. + +dnslookup_relay_to_domains: + debug_print = "R: dnslookup_relay_to_domains for $local_part@$domain" + driver = dnslookup + domains = ! +local_domains : +relay_to_domains + transport = remote_smtp + same_domain_copy_routing = yes + dnssec_request_domains = * + no_more + +# deliver mail directly to the recipient. This router is only reached +# for domains that we do not relay for. Since we most probably can't +# have broken MX records pointing to site local or link local IP +# addresses fixed, we ignore target hosts pointing to these addresses. + +dnslookup: + debug_print = "R: dnslookup for $local_part@$domain" + driver = dnslookup + domains = ! +local_domains + transport = remote_smtp + same_domain_copy_routing = yes + # ignore private rfc1918 and APIPA addresses + ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8 : 192.168.0.0/16 :\ + 172.16.0.0/12 : 10.0.0.0/8 : 169.254.0.0/16 :\ + 255.255.255.255 + dnssec_request_domains = * + no_more + +.endif + + +.ifdef DCconfig_local +# configtype=local +# +# Stand-alone system, so generate an error for mail to a non-local domain +nonlocal: + debug_print = "R: nonlocal for $local_part@$domain" + driver = redirect + domains = ! +local_domains + allow_fail + data = :fail: Mailing to remote domains not supported + no_more + +.endif + + +.ifdef DCconfig_smarthost DCconfig_satellite +# configtype=smarthost or configtype=satellite +# +# Send all non-local mail to a single other machine (smarthost). +# +# This means _ALL_ non-local mail goes to the smarthost. This will most +# probably not do what you want for domains that are listed in +# relay_domains. The most typical use for relay_domains is to control +# relaying for incoming e-mail on secondary MX hosts. In that case, +# it doesn't make sense to send the mail to the smarthost since the +# smarthost will probably send the message right back here, causing a +# loop. +# +# If you want to use a smarthost while being secondary MX for some +# domains, you'll need to copy the dnslookup_relay_to_domains router +# here so that mail to relay_domains is handled separately. + +smarthost: + debug_print = "R: smarthost for $local_part@$domain" + driver = manualroute + domains = ! +local_domains + transport = remote_smtp_smarthost + route_list = * DCsmarthost byname + host_find_failed = ignore + same_domain_copy_routing = yes + no_more + +.endif + + +# The "no_more" above means that all later routers are for +# domains in the local_domains list, i.e. just like Exim 3 directors. diff --git a/exim4/conf.d/router/300_exim4-config_real_local b/exim4/conf.d/router/300_exim4-config_real_local new file mode 100644 index 00000000..34ea2820 --- /dev/null +++ b/exim4/conf.d/router/300_exim4-config_real_local @@ -0,0 +1,22 @@ + +### router/300_exim4-config_real_local +################################# + +# This router allows reaching a local user while avoiding local +# processing. This can be used to inform a user of a broken .forward +# file, for example. The userforward router does this. + +COND_LOCAL_SUBMITTER = "\ + ${if match_ip{$sender_host_address}{:@[]}\ + {1}{0}\ + }" + +real_local: + debug_print = "R: real_local for $local_part@$domain" + driver = accept + domains = +local_domains + condition = COND_LOCAL_SUBMITTER + local_part_prefix = real- + check_local_user + transport = LOCAL_DELIVERY + diff --git a/exim4/conf.d/router/400_exim4-config_system_aliases b/exim4/conf.d/router/400_exim4-config_system_aliases new file mode 100644 index 00000000..f5f5f1c2 --- /dev/null +++ b/exim4/conf.d/router/400_exim4-config_system_aliases @@ -0,0 +1,44 @@ + +### router/400_exim4-config_system_aliases +################################# + +# This router handles aliasing using a traditional /etc/aliases file. +# +##### NB You must ensure that /etc/aliases exists. It used to be the case +##### NB that every Unix had that file, because it was the Sendmail default. +##### NB These days, there are systems that don't have it. Your aliases +##### NB file should at least contain an alias for "postmaster". +# +# This router handles the local part in a case-insensitive way which +# satisfies the RFCs requirement that postmaster be reachable regardless +# of case. If you decide to handle /etc/aliases in a caseful way, you +# need to make arrangements for a caseless postmaster. +# +# Delivery to arbitrary directories, files, and piping to programs in +# /etc/aliases is disabled per default. +# If that is a problem for you, see +# /usr/share/doc/exim4-base/README.Debian.gz +# for explanation and some workarounds. + +system_aliases: + debug_print = "R: system_aliases for $local_part@$domain" + driver = redirect + domains = +local_domains + allow_fail + allow_defer + data = ${lookup{$local_part}lsearch{/etc/aliases}} + .ifdef SYSTEM_ALIASES_USER + user = SYSTEM_ALIASES_USER + .endif + .ifdef SYSTEM_ALIASES_GROUP + group = SYSTEM_ALIASES_GROUP + .endif + .ifdef SYSTEM_ALIASES_FILE_TRANSPORT + file_transport = SYSTEM_ALIASES_FILE_TRANSPORT + .endif + .ifdef SYSTEM_ALIASES_PIPE_TRANSPORT + pipe_transport = SYSTEM_ALIASES_PIPE_TRANSPORT + .endif + .ifdef SYSTEM_ALIASES_DIRECTORY_TRANSPORT + directory_transport = SYSTEM_ALIASES_DIRECTORY_TRANSPORT + .endif diff --git a/exim4/conf.d/router/500_exim4-config_hubuser b/exim4/conf.d/router/500_exim4-config_hubuser new file mode 100644 index 00000000..1884b21d --- /dev/null +++ b/exim4/conf.d/router/500_exim4-config_hubuser @@ -0,0 +1,31 @@ + +### router/500_exim4-config_hubuser +################################# + +.ifdef DCconfig_satellite +# This router is only used for configtype=satellite. +# It takes care to route all mail targeted to +# to the host where we read our mail +# +hub_user: + debug_print = "R: hub_user for $local_part@$domain" + driver = redirect + domains = +local_domains + data = ${local_part}@DCreadhost + check_local_user + +# Grab the redirected mail and deliver it. +# This is a duplicate of the smarthost router, needed because +# DCreadhost might end up as part of +local_domains +hub_user_smarthost: + debug_print = "R: hub_user_smarthost for $local_part@$domain" + driver = manualroute + domains = DCreadhost + transport = remote_smtp_smarthost + route_list = * DCsmarthost byname + host_find_failed = ignore + same_domain_copy_routing = yes + check_local_user +.endif + + diff --git a/exim4/conf.d/router/600_exim4-config_userforward b/exim4/conf.d/router/600_exim4-config_userforward new file mode 100644 index 00000000..59259ca8 --- /dev/null +++ b/exim4/conf.d/router/600_exim4-config_userforward @@ -0,0 +1,51 @@ + +### router/600_exim4-config_userforward +################################# + +# This router handles forwarding using traditional .forward files in users' +# home directories. It also allows mail filtering with a forward file +# starting with the string "# Exim filter" or "# Sieve filter". +# +# The no_verify setting means that this router is skipped when Exim is +# verifying addresses. Similarly, no_expn means that this router is skipped if +# Exim is processing an EXPN command. +# +# The check_ancestor option means that if the forward file generates an +# address that is an ancestor of the current one, the current one gets +# passed on instead. This covers the case where A is aliased to B and B +# has a .forward file pointing to A. +# +# The four transports specified at the end are those that are used when +# forwarding generates a direct delivery to a directory, or a file, or to a +# pipe, or sets up an auto-reply, respectively. +# +userforward: + debug_print = "R: userforward for $local_part@$domain" + driver = redirect + domains = +local_domains + check_local_user + file = $home/.forward + require_files = $local_part:$home/.forward + no_verify + no_expn + check_ancestor + allow_filter + forbid_smtp_code = true + directory_transport = address_directory + file_transport = address_file + pipe_transport = address_pipe + reply_transport = address_reply + skip_syntax_errors + syntax_errors_to = real-$local_part@$domain + syntax_errors_text = \ + This is an automatically generated message. An error has\n\ + been found in your .forward file. Details of the error are\n\ + reported below. While this error persists, you will receive\n\ + a copy of this message for every message that is addressed\n\ + to you. If your .forward file is a filter file, or if it is\n\ + a non-filter file containing no valid forwarding addresses,\n\ + a copy of each incoming message will be put in your normal\n\ + mailbox. If a non-filter file contains at least one valid\n\ + forwarding address, forwarding to the valid addresses will\n\ + happen, and those will be the only deliveries that occur. + diff --git a/exim4/conf.d/router/700_exim4-config_procmail b/exim4/conf.d/router/700_exim4-config_procmail new file mode 100644 index 00000000..8d827c7c --- /dev/null +++ b/exim4/conf.d/router/700_exim4-config_procmail @@ -0,0 +1,15 @@ + +procmail: + debug_print = "R: procmail for $local_part@$domain" + driver = accept + domains = +local_domains + check_local_user + transport = procmail_pipe + # emulate OR with "if exists"-expansion + require_files = ${local_part}:\ + ${if exists{/etc/procmailrc}\ + {/etc/procmailrc}{${home}/.procmailrc}}:\ + +/usr/bin/procmail + no_verify + no_expn + diff --git a/exim4/conf.d/router/800_exim4-config_maildrop b/exim4/conf.d/router/800_exim4-config_maildrop new file mode 100644 index 00000000..0c57fc6a --- /dev/null +++ b/exim4/conf.d/router/800_exim4-config_maildrop @@ -0,0 +1,14 @@ + +### router/800_exim4-config_maildrop +################################# + +maildrop: + debug_print = "R: maildrop for $local_part@$domain" + driver = accept + domains = +local_domains + check_local_user + transport = maildrop_pipe + require_files = ${local_part}:${home}/.mailfilter:+/usr/bin/maildrop + no_verify + no_expn + diff --git a/exim4/conf.d/router/850_exim4-config_lowuid b/exim4/conf.d/router/850_exim4-config_lowuid new file mode 100644 index 00000000..43741c65 --- /dev/null +++ b/exim4/conf.d/router/850_exim4-config_lowuid @@ -0,0 +1,29 @@ + +### router/850_exim4-config_lowuid +################################# + +.ifndef FIRST_USER_ACCOUNT_UID +FIRST_USER_ACCOUNT_UID = 0 +.endif + +.ifndef DEFAULT_SYSTEM_ACCOUNT_ALIAS +DEFAULT_SYSTEM_ACCOUNT_ALIAS = :fail: no mail to system accounts +.endif + +COND_SYSTEM_USER_AND_REMOTE_SUBMITTER = "\ + ${if and{{! match_ip{$sender_host_address}{:@[]}}\ + {<{$local_user_uid}{FIRST_USER_ACCOUNT_UID}}}\ + {1}{0}\ + }" + +lowuid_aliases: + debug_print = "R: lowuid_aliases for $local_part@$domain (UID $local_user_uid)" + check_local_user + driver = redirect + allow_fail + domains = +local_domains + condition = COND_SYSTEM_USER_AND_REMOTE_SUBMITTER + data = ${if exists{CONFDIR/lowuid-aliases}\ + {${lookup{$local_part}lsearch{CONFDIR/lowuid-aliases}\ + {$value}{DEFAULT_SYSTEM_ACCOUNT_ALIAS}}}\ + {DEFAULT_SYSTEM_ACCOUNT_ALIAS}} diff --git a/exim4/conf.d/router/900_exim4-config_local_user b/exim4/conf.d/router/900_exim4-config_local_user new file mode 100644 index 00000000..423c7296 --- /dev/null +++ b/exim4/conf.d/router/900_exim4-config_local_user @@ -0,0 +1,15 @@ + +### router/900_exim4-config_local_user +################################# + +# This router matches local user mailboxes. If the router fails, the error +# message is "Unknown user". + +local_user: + debug_print = "R: local_user for $local_part@$domain" + driver = accept + domains = +local_domains + check_local_user + local_parts = ! root + transport = LOCAL_DELIVERY + cannot_route_message = Unknown user diff --git a/exim4/conf.d/router/mmm_mail4root b/exim4/conf.d/router/mmm_mail4root new file mode 100644 index 00000000..88017ba2 --- /dev/null +++ b/exim4/conf.d/router/mmm_mail4root @@ -0,0 +1,17 @@ + +### router/mmm_mail4root +################################# +# deliver mail addressed to root to /var/mail/mail as user mail:mail +# if it was not redirected in /etc/aliases or by other means +# Exim cannot deliver as root since 4.24 (FIXED_NEVER_USERS) + +mail4root: + debug_print = "R: mail4root for $local_part@$domain" + driver = redirect + domains = +local_domains + data = /var/mail/mail + file_transport = address_file + local_parts = root + user = mail + group = mail + diff --git a/exim4/conf.d/transport/00_exim4-config_header b/exim4/conf.d/transport/00_exim4-config_header new file mode 100644 index 00000000..48e45da8 --- /dev/null +++ b/exim4/conf.d/transport/00_exim4-config_header @@ -0,0 +1,13 @@ + +###################################################################### +# TRANSPORTS CONFIGURATION # +###################################################################### +# ORDER DOES NOT MATTER # +# Only one appropriate transport is called for each delivery. # +###################################################################### + +# A transport is used only when referenced from a router that successfully +# handles an address. + +begin transports + diff --git a/exim4/conf.d/transport/10_exim4-config_transport-macros b/exim4/conf.d/transport/10_exim4-config_transport-macros new file mode 100644 index 00000000..449fb319 --- /dev/null +++ b/exim4/conf.d/transport/10_exim4-config_transport-macros @@ -0,0 +1,16 @@ + +### transport/10_exim4-config_transport-macros +################################# + +.ifdef HIDE_MAILNAME +REMOTE_SMTP_HEADERS_REWRITE=*@+local_domains $1@DCreadhost frs : *@ETC_MAILNAME $1@DCreadhost frs +REMOTE_SMTP_RETURN_PATH=${if match_domain{$sender_address_domain}{+local_domains}{${sender_address_local_part}@DCreadhost}{${if match_domain{$sender_address_domain}{ETC_MAILNAME}{${sender_address_local_part}@DCreadhost}fail}}} +.endif + +.ifdef REMOTE_SMTP_HELO_FROM_DNS +.ifdef REMOTE_SMTP_HELO_DATA +REMOTE_SMTP_HELO_DATA==${lookup dnsdb {ptr=$sending_ip_address}{$value}{$primary_hostname}} +.else +REMOTE_SMTP_HELO_DATA=${lookup dnsdb {ptr=$sending_ip_address}{$value}{$primary_hostname}} +.endif +.endif diff --git a/exim4/conf.d/transport/30_exim4-config_address_file b/exim4/conf.d/transport/30_exim4-config_address_file new file mode 100644 index 00000000..82b55e27 --- /dev/null +++ b/exim4/conf.d/transport/30_exim4-config_address_file @@ -0,0 +1,11 @@ + +# This transport is used for handling deliveries directly to files that are +# generated by aliasing or forwarding. +# +address_file: + debug_print = "T: address_file for $local_part@$domain" + driver = appendfile + delivery_date_add + envelope_to_add + return_path_add + diff --git a/exim4/conf.d/transport/30_exim4-config_address_pipe b/exim4/conf.d/transport/30_exim4-config_address_pipe new file mode 100644 index 00000000..c5f1828c --- /dev/null +++ b/exim4/conf.d/transport/30_exim4-config_address_pipe @@ -0,0 +1,10 @@ + +# This transport is used for handling pipe deliveries generated by +# .forward files. If the commands fails and produces any output on standard +# output or standard error streams, the output is returned to the sender +# of the message as a delivery error. +address_pipe: + debug_print = "T: address_pipe for $local_part@$domain" + driver = pipe + return_fail_output + diff --git a/exim4/conf.d/transport/30_exim4-config_address_reply b/exim4/conf.d/transport/30_exim4-config_address_reply new file mode 100644 index 00000000..b2b88625 --- /dev/null +++ b/exim4/conf.d/transport/30_exim4-config_address_reply @@ -0,0 +1,8 @@ + +# This transport is used for handling autoreplies generated by the filtering +# option of the userforward router. +# +address_reply: + debug_print = "T: autoreply for $local_part@$domain" + driver = autoreply + diff --git a/exim4/conf.d/transport/30_exim4-config_mail_spool b/exim4/conf.d/transport/30_exim4-config_mail_spool new file mode 100644 index 00000000..21dfae4a --- /dev/null +++ b/exim4/conf.d/transport/30_exim4-config_mail_spool @@ -0,0 +1,17 @@ + +### transport/30_exim4-config_mail_spool + +# This transport is used for local delivery to user mailboxes in traditional +# BSD mailbox format. +# +mail_spool: + debug_print = "T: appendfile for $local_part@$domain" + driver = appendfile + file = /var/mail/$local_part + delivery_date_add + envelope_to_add + return_path_add + group = mail + mode = 0660 + mode_fail_narrower = false + diff --git a/exim4/conf.d/transport/30_exim4-config_maildir_home b/exim4/conf.d/transport/30_exim4-config_maildir_home new file mode 100644 index 00000000..a872accf --- /dev/null +++ b/exim4/conf.d/transport/30_exim4-config_maildir_home @@ -0,0 +1,41 @@ + +### transport/30_exim4-config_maildir_home +################################# + +# Use this instead of mail_spool if you want to to deliver to Maildir in +# home-directory - change the definition of LOCAL_DELIVERY +# +maildir_home: + debug_print = "T: maildir_home for $local_part@$domain" + driver = appendfile + .ifdef MAILDIR_HOME_MAILDIR_LOCATION + directory = MAILDIR_HOME_MAILDIR_LOCATION + .else + directory = $home/Maildir + .endif + .ifdef MAILDIR_HOME_CREATE_DIRECTORY + create_directory + .endif + .ifdef MAILDIR_HOME_CREATE_FILE + create_file = MAILDIR_HOME_CREATE_FILE + .endif + delivery_date_add + envelope_to_add + return_path_add + maildir_format + .ifdef MAILDIR_HOME_DIRECTORY_MODE + directory_mode = MAILDIR_HOME_DIRECTORY_MODE + .else + directory_mode = 0700 + .endif + .ifdef MAILDIR_HOME_MODE + mode = MAILDIR_HOME_MODE + .else + mode = 0600 + .endif + mode_fail_narrower = false + # This transport always chdirs to $home before trying to deliver. If + # $home is not accessible, this chdir fails and prevents delivery. + # If you are in a setup where home directories might not be + # accessible, uncomment the current_directory line below. + # current_directory = / diff --git a/exim4/conf.d/transport/30_exim4-config_maildrop_pipe b/exim4/conf.d/transport/30_exim4-config_maildrop_pipe new file mode 100644 index 00000000..3bd89246 --- /dev/null +++ b/exim4/conf.d/transport/30_exim4-config_maildrop_pipe @@ -0,0 +1,12 @@ + +maildrop_pipe: + debug_print = "T: maildrop_pipe for $local_part@$domain" + driver = pipe + path = "/bin:/usr/bin:/usr/local/bin" + command = "/usr/bin/maildrop" + message_prefix = + message_suffix = + return_path_add + delivery_date_add + envelope_to_add + diff --git a/exim4/conf.d/transport/30_exim4-config_procmail_pipe b/exim4/conf.d/transport/30_exim4-config_procmail_pipe new file mode 100644 index 00000000..5fb03ff7 --- /dev/null +++ b/exim4/conf.d/transport/30_exim4-config_procmail_pipe @@ -0,0 +1,10 @@ + +procmail_pipe: + debug_print = "T: procmail_pipe for $local_part@$domain" + driver = pipe + path = "/bin:/usr/bin:/usr/local/bin" + command = "/usr/bin/procmail" + return_path_add + delivery_date_add + envelope_to_add + diff --git a/exim4/conf.d/transport/30_exim4-config_remote_smtp b/exim4/conf.d/transport/30_exim4-config_remote_smtp new file mode 100644 index 00000000..bbad5fd7 --- /dev/null +++ b/exim4/conf.d/transport/30_exim4-config_remote_smtp @@ -0,0 +1,57 @@ + +### transport/30_exim4-config_remote_smtp +################################# +# This transport is used for delivering messages over SMTP connections. +# Refuse to send any message with over-long lines, which could have +# been received other than via SMTP. The use of message_size_limit to +# enforce this is a red herring. + +remote_smtp: + debug_print = "T: remote_smtp for $local_part@$domain" + driver = smtp +.ifndef IGNORE_SMTP_LINE_LENGTH_LIMIT + message_size_limit = ${if > {$max_received_linelength}{998} {1}{0}} +.endif +.ifdef REMOTE_SMTP_HOSTS_AVOID_TLS + hosts_avoid_tls = REMOTE_SMTP_HOSTS_AVOID_TLS +.endif +.ifdef REMOTE_SMTP_HEADERS_REWRITE + headers_rewrite = REMOTE_SMTP_HEADERS_REWRITE +.endif +.ifdef REMOTE_SMTP_RETURN_PATH + return_path = REMOTE_SMTP_RETURN_PATH +.endif +.ifdef REMOTE_SMTP_HELO_DATA + helo_data=REMOTE_SMTP_HELO_DATA +.endif +.ifdef DKIM_DOMAIN +dkim_domain = DKIM_DOMAIN +.endif +.ifdef DKIM_SELECTOR +dkim_selector = DKIM_SELECTOR +.endif +.ifdef DKIM_PRIVATE_KEY +dkim_private_key = DKIM_PRIVATE_KEY +.endif +.ifdef DKIM_CANON +dkim_canon = DKIM_CANON +.endif +.ifdef DKIM_STRICT +dkim_strict = DKIM_STRICT +.endif +.ifdef DKIM_SIGN_HEADERS +dkim_sign_headers = DKIM_SIGN_HEADERS +.endif +.ifdef TLS_DH_MIN_BITS +tls_dh_min_bits = TLS_DH_MIN_BITS +.endif +.ifdef REMOTE_SMTP_TLS_CERTIFICATE +tls_certificate = REMOTE_SMTP_TLS_CERTIFICATE +.endif +.ifdef REMOTE_SMTP_PRIVATEKEY +tls_privatekey = REMOTE_SMTP_PRIVATEKEY +.endif +.ifndef REMOTE_SMTP_DISABLE_DANE +dnssec_request_domains = * +hosts_try_dane = * +.endif diff --git a/exim4/conf.d/transport/30_exim4-config_remote_smtp_smarthost b/exim4/conf.d/transport/30_exim4-config_remote_smtp_smarthost new file mode 100644 index 00000000..8c6b757b --- /dev/null +++ b/exim4/conf.d/transport/30_exim4-config_remote_smtp_smarthost @@ -0,0 +1,48 @@ + +### transport/30_exim4-config_remote_smtp_smarthost +################################# + +# This transport is used for delivering messages over SMTP connections +# to a smarthost. The local host tries to authenticate. +# This transport is used for smarthost and satellite configurations. +# Refuse to send any messsage with over-long lines, which could have +# been received other than via SMTP. The use of message_size_limit to +# enforce this is a red herring. + +remote_smtp_smarthost: + debug_print = "T: remote_smtp_smarthost for $local_part@$domain" + driver = smtp + multi_domain +.ifndef IGNORE_SMTP_LINE_LENGTH_LIMIT + message_size_limit = ${if > {$max_received_linelength}{998} {1}{0}} +.endif + hosts_try_auth = <; ${if exists{CONFDIR/passwd.client} \ + {\ + ${lookup{$host}nwildlsearch{CONFDIR/passwd.client}{$host_address}}\ + }\ + {} \ + } +.ifdef REMOTE_SMTP_SMARTHOST_HOSTS_AVOID_TLS + hosts_avoid_tls = REMOTE_SMTP_SMARTHOST_HOSTS_AVOID_TLS +.endif +.ifdef REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS + hosts_require_tls = REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS +.endif +.ifdef REMOTE_SMTP_HEADERS_REWRITE + headers_rewrite = REMOTE_SMTP_HEADERS_REWRITE +.endif +.ifdef REMOTE_SMTP_RETURN_PATH + return_path = REMOTE_SMTP_RETURN_PATH +.endif +.ifdef REMOTE_SMTP_HELO_DATA + helo_data=REMOTE_SMTP_HELO_DATA +.endif +.ifdef TLS_DH_MIN_BITS +tls_dh_min_bits = TLS_DH_MIN_BITS +.endif +.ifdef REMOTE_SMTP_SMARTHOST_TLS_CERTIFICATE +tls_certificate = REMOTE_SMTP_SMARTHOST_TLS_CERTIFICATE +.endif +.ifdef REMOTE_SMTP_SMARTHOST_PRIVATEKEY +tls_privatekey = REMOTE_SMTP_SMARTHOST_PRIVATEKEY +.endif diff --git a/exim4/conf.d/transport/35_exim4-config_address_directory b/exim4/conf.d/transport/35_exim4-config_address_directory new file mode 100644 index 00000000..6861426b --- /dev/null +++ b/exim4/conf.d/transport/35_exim4-config_address_directory @@ -0,0 +1,14 @@ +# This transport is used for handling file addresses generated by alias +# or .forward files if the path ends in "/", which causes it to be treated +# as a directory name rather than a file name. + +address_directory: + debug_print = "T: address_directory for $local_part@$domain" + driver = appendfile + delivery_date_add + envelope_to_add + return_path_add + check_string = "" + escape_string = "" + maildir_format + diff --git a/exim4/exim4.conf.template b/exim4/exim4.conf.template new file mode 100644 index 00000000..7ddb5293 --- /dev/null +++ b/exim4/exim4.conf.template @@ -0,0 +1,2121 @@ +##################################################### +### main/01_exim4-config_listmacrosdefs +##################################################### +###################################################################### +# Runtime configuration file for Exim 4 (Debian Packaging) # +###################################################################### + +###################################################################### +# /etc/exim4/exim4.conf.template is only used with the non-split +# configuration scheme. +# /etc/exim4/conf.d/main/01_exim4-config_listmacrosdefs is only used +# with the split configuration scheme. +# If you find this comment anywhere else, somebody copied it there. +# Documentation about the Debian exim4 configuration scheme can be +# found in /usr/share/doc/exim4-base/README.Debian.gz. +###################################################################### + +###################################################################### +# MAIN CONFIGURATION SETTINGS # +###################################################################### + +# Just for reference and scripts. +# On Debian systems, the main binary is installed as exim4 to avoid +# conflicts with the exim 3 packages. +exim_path = /usr/sbin/exim4 + +# Macro defining the main configuration directory. +# We do not use absolute paths. +.ifndef CONFDIR +CONFDIR = /etc/exim4 +.endif + +# debconf-driven macro definitions get inserted after this line +UPEX4CmacrosUPEX4C = 1 + +# Create domain and host lists for relay control +# '@' refers to 'the name of the local host' + +# List of domains considered local for exim. Domains not listed here +# need to be deliverable remotely. +domainlist local_domains = MAIN_LOCAL_DOMAINS + +# List of recipient domains to relay _to_. Use this list if you're - +# for example - fallback MX or mail gateway for domains. +domainlist relay_to_domains = MAIN_RELAY_TO_DOMAINS + +# List of sender networks (IP addresses) to _unconditionally_ relay +# _for_. If you intend to be SMTP AUTH server, you do not need to enter +# anything here. +hostlist relay_from_hosts = MAIN_RELAY_NETS + + +# Decide which domain to use to add to all unqualified addresses. +# If MAIN_PRIMARY_HOSTNAME_AS_QUALIFY_DOMAIN is defined, the primary +# hostname is used. If not, but MAIN_QUALIFY_DOMAIN is set, the value +# of MAIN_QUALIFY_DOMAIN is used. If both macros are not defined, +# the first line of /etc/mailname is used. +.ifndef MAIN_PRIMARY_HOSTNAME_AS_QUALIFY_DOMAIN +.ifndef MAIN_QUALIFY_DOMAIN +qualify_domain = ETC_MAILNAME +.else +qualify_domain = MAIN_QUALIFY_DOMAIN +.endif +.endif + +# listen on all all interfaces? +.ifdef MAIN_LOCAL_INTERFACES +local_interfaces = MAIN_LOCAL_INTERFACES +.endif + +.ifndef LOCAL_DELIVERY +# The default transport, set in /etc/exim4/update-exim4.conf.conf, +# defaulting to mail_spool. See CONFDIR/conf.d/transport/ for possibilities +LOCAL_DELIVERY=mail_spool +.endif + +# The gecos field in /etc/passwd holds not only the name. see passwd(5). +gecos_pattern = ^([^,:]*) +gecos_name = $1 + +# always log tls_peerdn as we use TLS for outgoing connects by default +.ifndef MAIN_LOG_SELECTOR +MAIN_LOG_SELECTOR = +smtp_protocol_error +smtp_syntax_error +tls_certificate_verified +tls_peerdn +.endif +##################################################### +### end main/01_exim4-config_listmacrosdefs +##################################################### +##################################################### +### main/02_exim4-config_options +##################################################### + +### main/02_exim4-config_options +################################# + + +# Defines the access control list that is run when an +# SMTP MAIL command is received. +# +.ifndef MAIN_ACL_CHECK_MAIL +MAIN_ACL_CHECK_MAIL = acl_check_mail +.endif +acl_smtp_mail = MAIN_ACL_CHECK_MAIL + + +# Defines the access control list that is run when an +# SMTP RCPT command is received. +# +.ifndef MAIN_ACL_CHECK_RCPT +MAIN_ACL_CHECK_RCPT = acl_check_rcpt +.endif +acl_smtp_rcpt = MAIN_ACL_CHECK_RCPT + + +# Defines the access control list that is run when an +# SMTP DATA command is received. +# +.ifndef MAIN_ACL_CHECK_DATA +MAIN_ACL_CHECK_DATA = acl_check_data +.endif +acl_smtp_data = MAIN_ACL_CHECK_DATA + + +# Message size limit. The default (used when MESSAGE_SIZE_LIMIT +# is unset) is 50 MB +.ifdef MESSAGE_SIZE_LIMIT +message_size_limit = MESSAGE_SIZE_LIMIT +.endif + + +# If you are running exim4-daemon-heavy or a custom version of Exim that +# was compiled with the content-scanning extension, you can cause incoming +# messages to be automatically scanned for viruses. You have to modify the +# configuration in two places to set this up. The first of them is here, +# where you define the interface to your scanner. This example is typical +# for ClamAV; see the manual for details of what to set for other virus +# scanners. The second modification is in the acl_check_data access +# control list. + +# av_scanner = clamd:/var/run/clamav/clamd.ctl + + +# For spam scanning, there is a similar option that defines the interface to +# SpamAssassin. You do not need to set this if you are using the default, which +# is shown in this commented example. As for virus scanning, you must also +# modify the acl_check_data access control list to enable spam scanning. + +# spamd_address = 127.0.0.1 783 + +# Domain used to qualify unqualified recipient addresses +# If this option is not set, the qualify_domain value is used. +# qualify_recipient = + + +# Allow Exim to recognize addresses of the form "user@[10.11.12.13]", +# where the domain part is a "domain literal" (an IP address) instead +# of a named domain. The RFCs require this facility, but it is disabled +# in the default config since it is rarely used and frequently abused. +# Domain literal support also needs a special router, which is automatically +# enabled if you use the enable macro MAIN_ALLOW_DOMAIN_LITERALS. +# Additionally, you might want to make your local IP addresses (or @[]) +# local domains. +.ifdef MAIN_ALLOW_DOMAIN_LITERALS +allow_domain_literals +.endif + + +# Do a reverse DNS lookup on all incoming IP calls, in order to get the +# true host name. If you feel this is too expensive, the networks for +# which a lookup is done can be listed here. +.ifndef DC_minimaldns +.ifndef MAIN_HOST_LOOKUP +MAIN_HOST_LOOKUP = * +.endif +host_lookup = MAIN_HOST_LOOKUP +.endif + +# The setting below causes Exim to try to initialize the system resolver +# library with DNSSEC support. It has no effect if your library lacks +# DNSSEC support. +dns_dnssec_ok = 1 + +# In a minimaldns setup, update-exim4.conf guesses the hostname and +# dumps it here to avoid DNS lookups being done at Exim run time. +.ifdef MAIN_HARDCODE_PRIMARY_HOSTNAME +primary_hostname = MAIN_HARDCODE_PRIMARY_HOSTNAME +.endif + +# The settings below cause Exim to make RFC 1413 (ident) callbacks +# for all incoming SMTP calls. You can limit the hosts to which these +# calls are made, and/or change the timeout that is used. If you set +# the timeout to zero, all RFC 1413 calls are disabled. RFC 1413 calls +# are cheap and can provide useful information for tracing problem +# messages, but some hosts and firewalls have problems with them. +# This can result in a timeout instead of an immediate refused +# connection, leading to delays on starting up SMTP sessions. +# (The default was reduced from 30s to 5s for release 4.61. and to +# disabled for release 4.86) +# +#rfc1413_hosts = * +#rfc1413_query_timeout = 5s + + +# Enable an efficiency feature. We advertise the feature; clients +# may request to use it. For multi-recipient mails we then can +# reject or accept per-user after the message is received. +# +prdr_enable = true + +# When using an external relay tester (such as rt.njabl.org and/or the +# currently defunct relay-test.mail-abuse.org, the test may be aborted +# since exim complains about "too many nonmail commands". If you want +# the test to complete, add the host from where "your" relay tester +# connects from to the MAIN_SMTP_ACCEPT_MAX_NOMAIL_HOSTS macro. +# Please note that a non-empty setting may cause extra DNS lookups to +# happen, which is the reason why this option is commented out in the +# default settings. +# MAIN_SMTP_ACCEPT_MAX_NOMAIL_HOSTS = !rt.njabl.org +.ifdef MAIN_SMTP_ACCEPT_MAX_NOMAIL_HOSTS +smtp_accept_max_nonmail_hosts = MAIN_SMTP_ACCEPT_MAX_NOMAIL_HOSTS +.endif + +# By default, exim forces a Sender: header containing the local +# account name at the local host name in all locally submitted messages +# that don't have the local account name at the local host name in the +# From: header, deletes any Sender: header present in the submitted +# message and forces the envelope sender of all locally submitted +# messages to the local account name at the local host name. +# The following settings allow local users to specify their own envelope sender +# in a locally submitted message. Sender: headers existing in a locally +# submitted message are not removed, and no automatic Sender: headers +# are added. These settings are fine for most hosts. +# If you run exim on a classical multi-user systems where all users +# have local mailboxes that can be reached via SMTP from the Internet +# with the local FQDN as the domain part of the address, you might want +# to disable the following three lines for traceability reasons. +.ifndef MAIN_FORCE_SENDER +local_from_check = false +local_sender_retain = true +untrusted_set_sender = * +.endif + + +# By default, Exim expects all envelope addresses to be fully qualified, that +# is, they must contain both a local part and a domain. Configure exim +# to accept unqualified addresses from certain hosts. When this is done, +# unqualified addresses are qualified using the settings of qualify_domain +# and/or qualify_recipient (see above). +# sender_unqualified_hosts = +# recipient_unqualified_hosts = + + +# Configure Exim to support the "percent hack" for certain domains. +# The "percent hack" is the feature by which mail addressed to x%y@z +# (where z is one of the domains listed) is locally rerouted to x@y +# and sent on. If z is not one of the "percent hack" domains, x%y is +# treated as an ordinary local part. The percent hack is rarely needed +# nowadays but frequently abused. You should not enable it unless you +# are sure that you really need it. +# percent_hack_domains = + + +# Bounce handling +.ifndef MAIN_IGNORE_BOUNCE_ERRORS_AFTER +MAIN_IGNORE_BOUNCE_ERRORS_AFTER = 2d +.endif +ignore_bounce_errors_after = MAIN_IGNORE_BOUNCE_ERRORS_AFTER + +.ifndef MAIN_TIMEOUT_FROZEN_AFTER +MAIN_TIMEOUT_FROZEN_AFTER = 7d +.endif +timeout_frozen_after = MAIN_TIMEOUT_FROZEN_AFTER + +.ifndef MAIN_FREEZE_TELL +MAIN_FREEZE_TELL = postmaster +.endif +freeze_tell = MAIN_FREEZE_TELL + + +# Define spool directory +.ifndef SPOOLDIR +SPOOLDIR = /var/spool/exim4 +.endif +spool_directory = SPOOLDIR + + +# trusted users can set envelope-from to arbitrary values +.ifndef MAIN_TRUSTED_USERS +MAIN_TRUSTED_USERS = uucp +.endif +trusted_users = MAIN_TRUSTED_USERS +.ifdef MAIN_TRUSTED_GROUPS +trusted_groups = MAIN_TRUSTED_GROUPS +.endif + + +# users in admin group can do many other things +# admin_groups = + + +# SMTP Banner. The example includes the Debian version in the SMTP dialog +# MAIN_SMTP_BANNER = "${primary_hostname} ESMTP Exim ${version_number} (Debian package MAIN_PACKAGE_VERSION) ${tod_full}" +# smtp_banner = $smtp_active_hostname ESMTP Exim $version_number $tod_full + +.ifdef MAIN_KEEP_ENVIRONMENT +keep_environment = MAIN_KEEP_ENVIRONMENT +.else +# set option to empty value to avoid warning. +keep_environment = +.endif +.ifdef MAIN_ADD_ENVIRONMENT +add_environment = MAIN_ADD_ENVIRONMENT +.endif +##################################################### +### end main/02_exim4-config_options +##################################################### +##################################################### +### main/03_exim4-config_tlsoptions +##################################################### + +### main/03_exim4-config_tlsoptions +################################# + +# TLS/SSL configuration for exim as an SMTP server. +# See /usr/share/doc/exim4-base/README.Debian.gz for explanations. + +.ifdef MAIN_TLS_ENABLE +# Defines what hosts to 'advertise' STARTTLS functionality to. The +# default, *, will advertise to all hosts that connect with EHLO. +.ifndef MAIN_TLS_ADVERTISE_HOSTS +MAIN_TLS_ADVERTISE_HOSTS = * +.endif +tls_advertise_hosts = MAIN_TLS_ADVERTISE_HOSTS + + +# Full paths to Certificate and Private Key. The Private Key file +# must be kept 'secret' and should be owned by root.Debian-exim mode +# 640 (-rw-r-----). exim-gencert takes care of these prerequisites. +# Normally, exim4 looks for certificate and key in different files: +# MAIN_TLS_CERTIFICATE - path to certificate file, +# CONFDIR/exim.crt if unset +# MAIN_TLS_PRIVATEKEY - path to private key file +# CONFDIR/exim.key if unset +# You can also configure exim to look for certificate and key in the +# same file, set MAIN_TLS_CERTKEY to that file to enable. This takes +# precedence over all other settings regarding certificate and key file. +.ifdef MAIN_TLS_CERTKEY +tls_certificate = MAIN_TLS_CERTKEY +.else +.ifndef MAIN_TLS_CERTIFICATE +MAIN_TLS_CERTIFICATE = CONFDIR/exim.crt +.endif +tls_certificate = MAIN_TLS_CERTIFICATE + +.ifndef MAIN_TLS_PRIVATEKEY +MAIN_TLS_PRIVATEKEY = CONFDIR/exim.key +.endif +tls_privatekey = MAIN_TLS_PRIVATEKEY +.endif + +# Pointer to the CA Certificates against which client certificates are +# checked. This is controlled by the `tls_verify_hosts' and +# `tls_try_verify_hosts' lists below. +# If you want to check server certificates, you need to add an +# tls_verify_certificates statement to the smtp transport. +# /etc/ssl/certs/ca-certificates.crt is generated by +# the "ca-certificates" package's update-ca-certificates(8) command. +.ifndef MAIN_TLS_VERIFY_CERTIFICATES +MAIN_TLS_VERIFY_CERTIFICATES = ${if exists{/etc/ssl/certs/ca-certificates.crt}\ + {/etc/ssl/certs/ca-certificates.crt}\ + {/dev/null}} +.endif +tls_verify_certificates = MAIN_TLS_VERIFY_CERTIFICATES + + +# A list of hosts which are constrained by `tls_verify_certificates'. A host +# that matches `tls_verify_host' must present a certificate that is +# verifyable through `tls_verify_certificates' in order to be accepted as an +# SMTP client. If it does not, the connection is aborted. +.ifdef MAIN_TLS_VERIFY_HOSTS +tls_verify_hosts = MAIN_TLS_VERIFY_HOSTS +.endif + +# A weaker form of checking: if a client matches `tls_try_verify_hosts' (but +# not `tls_verify_hosts'), request a certificate and check it against +# `tls_verify_certificates' but do not abort the connection if there is no +# certificate or if the certificate presented does not match. (This +# condition can be tested for in ACLs through `verify = certificate') +# By default, this check is done for all hosts. It is known that some +# clients (including incredimail's version downloadable in February +# 2008) choke on this. To disable, set MAIN_TLS_TRY_VERIFY_HOSTS to an +# empty value. +.ifdef MAIN_TLS_TRY_VERIFY_HOSTS +tls_try_verify_hosts = MAIN_TLS_TRY_VERIFY_HOSTS +.endif + +.ifdef _HAVE_GNUTLS +tls_dhparam = historic +.endif + +.else +# Don't advertise TLS if MAIN_TLS_ENABLE is not set. +tls_advertise_hosts = +.endif +##################################################### +### end main/03_exim4-config_tlsoptions +##################################################### +##################################################### +### main/90_exim4-config_log_selector +##################################################### + +### main/90_exim4-config_log_selector +################################# + +# uncomment this for debugging +# MAIN_LOG_SELECTOR == MAIN_LOG_SELECTOR +all -subject -arguments + +.ifdef MAIN_LOG_SELECTOR +log_selector = MAIN_LOG_SELECTOR +.endif +##################################################### +### end main/90_exim4-config_log_selector +##################################################### +##################################################### +### acl/00_exim4-config_header +##################################################### + +###################################################################### +# ACL CONFIGURATION # +# Specifies access control lists for incoming SMTP mail # +###################################################################### +begin acl + + +##################################################### +### end acl/00_exim4-config_header +##################################################### +##################################################### +### acl/20_exim4-config_local_deny_exceptions +##################################################### + +### acl/20_exim4-config_local_deny_exceptions +################################# + +# This is used to determine whitelisted senders and hosts. +# It checks for CONFDIR/host_local_deny_exceptions and +# CONFDIR/sender_local_deny_exceptions. +# +# It is meant to be used from some other acl entry. +# +# See exim4-config_files(5) for details. +# +# If the files do not exist, the white list never matches, which is +# the desired behaviour. +# +# The old file names CONFDIR/local_host_whitelist and +# CONFDIR/local_sender_whitelist will continue to be honored for a +# transition period. Their use is deprecated. + +acl_local_deny_exceptions: + accept + hosts = ${if exists{CONFDIR/host_local_deny_exceptions}\ + {CONFDIR/host_local_deny_exceptions}\ + {}} + accept + senders = ${if exists{CONFDIR/sender_local_deny_exceptions}\ + {CONFDIR/sender_local_deny_exceptions}\ + {}} + accept + hosts = ${if exists{CONFDIR/local_host_whitelist}\ + {CONFDIR/local_host_whitelist}\ + {}} + accept + senders = ${if exists{CONFDIR/local_sender_whitelist}\ + {CONFDIR/local_sender_whitelist}\ + {}} + + # This hook allows you to hook in your own ACLs without having to + # modify this file. If you do it like we suggest, you'll end up with + # a small performance penalty since there is an additional file being + # accessed. This doesn't happen if you leave the macro unset. + .ifdef LOCAL_DENY_EXCEPTIONS_LOCAL_ACL_FILE + .include LOCAL_DENY_EXCEPTIONS_LOCAL_ACL_FILE + .endif + + # this is still supported for a transition period and is deprecated. + .ifdef WHITELIST_LOCAL_DENY_LOCAL_ACL_FILE + .include WHITELIST_LOCAL_DENY_LOCAL_ACL_FILE + .endif +##################################################### +### end acl/20_exim4-config_local_deny_exceptions +##################################################### +##################################################### +### acl/30_exim4-config_check_mail +##################################################### + +### acl/30_exim4-config_check_mail +################################# + +# This access control list is used for every MAIL command in an incoming +# SMTP message. The tests are run in order until the address is either +# accepted or denied. +# +acl_check_mail: + + accept +##################################################### +### end acl/30_exim4-config_check_mail +##################################################### +##################################################### +### acl/30_exim4-config_check_rcpt +##################################################### + +### acl/30_exim4-config_check_rcpt +################################# + +# define macros to be used below in this file to check recipient +# local parts for strange characters. Documentation below. +# This blocks local parts that begin with a dot or contain a quite +# broad range of non-alphanumeric characters. + +.ifndef CHECK_RCPT_LOCAL_LOCALPARTS +CHECK_RCPT_LOCAL_LOCALPARTS = ^[.] : ^.*[@%!/|`#&?] +.endif + +.ifndef CHECK_RCPT_REMOTE_LOCALPARTS +CHECK_RCPT_REMOTE_LOCALPARTS = ^[./|] : ^.*[@%!`#&?] : ^.*/\\.\\./ +.endif + +# This access control list is used for every RCPT command in an incoming +# SMTP message. The tests are run in order until the address is either +# accepted or denied. +# +acl_check_rcpt: + + # Accept if the source is local SMTP (i.e. not over TCP/IP). We do this by + # testing for an empty sending host field. + accept + hosts = : + control = dkim_disable_verify + + # Do not try to verify DKIM signatures of incoming mail if DC_minimaldns + # or DISABLE_DKIM_VERIFY are set. +.ifdef DC_minimaldns + warn + control = dkim_disable_verify +.else +.ifdef DISABLE_DKIM_VERIFY + warn + control = dkim_disable_verify +.endif +.endif + + # The following section of the ACL is concerned with local parts that contain + # certain non-alphanumeric characters. Dots in unusual places are + # handled by this ACL as well. + # + # Non-alphanumeric characters other than dots are rarely found in genuine + # local parts, but are often tried by people looking to circumvent + # relaying restrictions. Therefore, although they are valid in local + # parts, these rules disallow certain non-alphanumeric characters, as + # a precaution. + # + # Empty components (two dots in a row) are not valid in RFC 2822, but Exim + # allows them because they have been encountered. (Consider local parts + # constructed as "firstinitial.secondinitial.familyname" when applied to + # a name without a second initial.) However, a local part starting + # with a dot or containing /../ can cause trouble if it is used as part of a + # file name (e.g. for a mailing list). This is also true for local parts that + # contain slashes. A pipe symbol can also be troublesome if the local part is + # incorporated unthinkingly into a shell command line. + # + # These ACL components will block recipient addresses that are valid + # from an RFC5322 point of view. We chose to have them blocked by + # default for security reasons. + # + # If you feel that your site should have less strict recipient + # checking, please feel free to change the default values of the macros + # defined in main/01_exim4-config_listmacrosdefs or override them from a + # local configuration file. + # + # Two different rules are used. The first one has a quite strict + # default, and is applied to messages that are addressed to one of the + # local domains handled by this host. + + # The default value of CHECK_RCPT_LOCAL_LOCALPARTS is defined + # at the top of this file. + .ifdef CHECK_RCPT_LOCAL_LOCALPARTS + deny + domains = +local_domains + local_parts = CHECK_RCPT_LOCAL_LOCALPARTS + message = restricted characters in address + .endif + + + # The second rule applies to all other domains, and its default is + # considerably less strict. + + # The default value of CHECK_RCPT_REMOTE_LOCALPARTS is defined in + # main/01_exim4-config_listmacrosdefs: + # CHECK_RCPT_REMOTE_LOCALPARTS = ^[./|] : ^.*[@%!`#&?] : ^.*/\\.\\./ + + # It allows local users to send outgoing messages to sites + # that use slashes and vertical bars in their local parts. It blocks + # local parts that begin with a dot, slash, or vertical bar, but allows + # these characters within the local part. However, the sequence /../ is + # barred. The use of some other non-alphanumeric characters is blocked. + # Single quotes might probably be dangerous as well, but they're + # allowed by the default regexps to avoid rejecting mails to Ireland. + # The motivation here is to prevent local users (or local users' malware) + # from mounting certain kinds of attack on remote sites. + .ifdef CHECK_RCPT_REMOTE_LOCALPARTS + deny + domains = !+local_domains + local_parts = CHECK_RCPT_REMOTE_LOCALPARTS + message = restricted characters in address + .endif + + + # Accept mail to postmaster in any local domain, regardless of the source, + # and without verifying the sender. + # + accept + .ifndef CHECK_RCPT_POSTMASTER + local_parts = postmaster + .else + local_parts = CHECK_RCPT_POSTMASTER + .endif + domains = +local_domains : +relay_to_domains + + + # Deny unless the sender address can be verified. + # + # This is disabled by default so that DNSless systems don't break. If + # your system can do DNS lookups without delay or cost, you might want + # to enable this feature. + # + # This feature does not work in smarthost and satellite setups as + # with these setups all domains pass verification. See spec.txt section + # "Access control lists" subsection "Address verification" with the added + # information that a smarthost/satellite setup routes all non-local e-mail + # to the smarthost. + .ifdef CHECK_RCPT_VERIFY_SENDER + deny + message = Sender verification failed + !acl = acl_local_deny_exceptions + !verify = sender + .endif + + # Verify senders listed in local_sender_callout with a callout. + # + # In smarthost and satellite setups, this causes the callout to be + # done to the smarthost. Verification will thus only be reliable if the + # smarthost does reject illegal addresses in the SMTP dialog. + deny + !acl = acl_local_deny_exceptions + senders = ${if exists{CONFDIR/local_sender_callout}\ + {CONFDIR/local_sender_callout}\ + {}} + !verify = sender/callout + + + # Accept if the message comes from one of the hosts for which we are an + # outgoing relay. It is assumed that such hosts are most likely to be MUAs, + # so we set control=submission to make Exim treat the message as a + # submission. It will fix up various errors in the message, for example, the + # lack of a Date: header line. If you are actually relaying out out from + # MTAs, you may want to disable this. If you are handling both relaying from + # MTAs and submissions from MUAs you should probably split them into two + # lists, and handle them differently. + + # Recipient verification is omitted here, because in many cases the clients + # are dumb MUAs that don't cope well with SMTP error responses. If you are + # actually relaying out from MTAs, you should probably add recipient + # verification here. + + # Note that, by putting this test before any DNS black list checks, you will + # always accept from these hosts, even if they end up on a black list. The + # assumption is that they are your friends, and if they get onto black + # list, it is a mistake. + accept + hosts = +relay_from_hosts + control = submission/sender_retain + control = dkim_disable_verify + + + # Accept if the message arrived over an authenticated connection, from + # any host. Again, these messages are usually from MUAs, so recipient + # verification is omitted, and submission mode is set. And again, we do this + # check before any black list tests. + accept + authenticated = * + control = submission/sender_retain + control = dkim_disable_verify + + # Insist that a HELO/EHLO was accepted. + + require message = nice hosts say HELO first + condition = ${if def:sender_helo_name} + + # Insist that any other recipient address that we accept is either in one of + # our local domains, or is in a domain for which we explicitly allow + # relaying. Any other domain is rejected as being unacceptable for relaying. + require + message = relay not permitted + domains = +local_domains : +relay_to_domains + + + # We also require all accepted addresses to be verifiable. This check will + # do local part verification for local domains, but only check the domain + # for remote domains. + require + verify = recipient + + + # Verify recipients listed in local_rcpt_callout with a callout. + # This is especially handy for forwarding MX hosts (secondary MX or + # mail hubs) of domains that receive a lot of spam to non-existent + # addresses. The only way to check local parts for remote relay + # domains is to use a callout (add /callout), but please read the + # documentation about callouts before doing this. + deny + !acl = acl_local_deny_exceptions + recipients = ${if exists{CONFDIR/local_rcpt_callout}\ + {CONFDIR/local_rcpt_callout}\ + {}} + !verify = recipient/callout + + + # CONFDIR/local_sender_blacklist holds a list of envelope senders that + # should have their access denied to the local host. Incoming messages + # with one of these senders are rejected at RCPT time. + # + # The explicit white lists are honored as well as negative items in + # the black list. See exim4-config_files(5) for details. + deny + message = sender envelope address $sender_address is locally blacklisted here. If you think this is wrong, get in touch with postmaster + log_message = sender envelope address is locally blacklisted. + !acl = acl_local_deny_exceptions + senders = ${if exists{CONFDIR/local_sender_blacklist}\ + {CONFDIR/local_sender_blacklist}\ + {}} + + + # deny bad sites (IP address) + # CONFDIR/local_host_blacklist holds a list of host names, IP addresses + # and networks (CIDR notation) that should have their access denied to + # The local host. Messages coming in from a listed host will have all + # RCPT statements rejected. + # + # The explicit white lists are honored as well as negative items in + # the black list. See exim4-config_files(5) for details. + deny + message = sender IP address $sender_host_address is locally blacklisted here. If you think this is wrong, get in touch with postmaster + log_message = sender IP address is locally blacklisted. + !acl = acl_local_deny_exceptions + hosts = ${if exists{CONFDIR/local_host_blacklist}\ + {CONFDIR/local_host_blacklist}\ + {}} + + + # Warn if the sender host does not have valid reverse DNS. + # + # If your system can do DNS lookups without delay or cost, you might want + # to enable this. + # If sender_host_address is defined, it's a remote call. If + # sender_host_name is not defined, then reverse lookup failed. Use + # this instead of !verify = reverse_host_lookup to catch deferrals + # as well as outright failures. + .ifdef CHECK_RCPT_REVERSE_DNS + warn + condition = ${if and{{def:sender_host_address}{!def:sender_host_name}}\ + {yes}{no}} + add_header = X-Host-Lookup-Failed: Reverse DNS lookup failed for $sender_host_address (${if eq{$host_lookup_failed}{1}{failed}{deferred}}) + .endif + + + # Use spfquery to perform a pair of SPF checks (for details, see + # http://www.openspf.org/) + # + # This is quite costly in terms of DNS lookups (~6 lookups per mail). Do not + # enable if that's an issue. Also note that if you enable this, you must + # install "spf-tools-perl" which provides the spfquery command. + # Missing spf-tools-perl will trigger the "Unexpected error in + # SPF check" warning. + .ifdef CHECK_RCPT_SPF + deny + message = [SPF] $sender_host_address is not allowed to send mail from \ + ${if def:sender_address_domain {$sender_address_domain}{$sender_helo_name}}. \ + Please see \ + http://www.openspf.org/Why?scope=${if def:sender_address_domain \ + {mfrom}{helo}};identity=${if def:sender_address_domain \ + {$sender_address}{$sender_helo_name}};ip=$sender_host_address + log_message = SPF check failed. + !acl = acl_local_deny_exceptions + condition = ${run{/usr/bin/spfquery.mail-spf-perl --ip \ + ${quote:$sender_host_address} --identity \ + ${if def:sender_address_domain \ + {--scope mfrom --identity ${quote:$sender_address}}\ + {--scope helo --identity ${quote:$sender_helo_name}}}}\ + {no}{${if eq {$runrc}{1}{yes}{no}}}} + + defer + message = Temporary DNS error while checking SPF record. Try again later. + !acl = acl_local_deny_exceptions + condition = ${if eq {$runrc}{5}{yes}{no}} + + warn + condition = ${if <={$runrc}{6}{yes}{no}} + add_header = Received-SPF: ${if eq {$runrc}{0}{pass}\ + {${if eq {$runrc}{2}{softfail}\ + {${if eq {$runrc}{3}{neutral}\ + {${if eq {$runrc}{4}{permerror}\ + {${if eq {$runrc}{6}{none}{error}}}}}}}}}\ + } client-ip=$sender_host_address; \ + ${if def:sender_address_domain \ + {envelope-from=${sender_address}; }{}}\ + helo=$sender_helo_name + + warn + log_message = Unexpected error in SPF check. + condition = ${if >{$runrc}{6}{yes}{no}} + .endif + + + # Check against classic DNS "black" lists (DNSBLs) which list + # sender IP addresses + .ifdef CHECK_RCPT_IP_DNSBLS + warn + dnslists = CHECK_RCPT_IP_DNSBLS + add_header = X-Warning: $sender_host_address is listed at $dnslist_domain ($dnslist_value: $dnslist_text) + log_message = $sender_host_address is listed at $dnslist_domain ($dnslist_value: $dnslist_text) + .endif + + + # Check against DNSBLs which list sender domains, with an option to locally + # whitelist certain domains that might be blacklisted. + # + # Note: If you define CHECK_RCPT_DOMAIN_DNSBLS, you must append + # "/$sender_address_domain" after each domain. For example: + # CHECK_RCPT_DOMAIN_DNSBLS = rhsbl.foo.org/$sender_address_domain \ + # : rhsbl.bar.org/$sender_address_domain + .ifdef CHECK_RCPT_DOMAIN_DNSBLS + warn + !senders = ${if exists{CONFDIR/local_domain_dnsbl_whitelist}\ + {CONFDIR/local_domain_dnsbl_whitelist}\ + {}} + dnslists = CHECK_RCPT_DOMAIN_DNSBLS + add_header = X-Warning: $sender_address_domain is listed at $dnslist_domain ($dnslist_value: $dnslist_text) + log_message = $sender_address_domain is listed at $dnslist_domain ($dnslist_value: $dnslist_text) + .endif + + + # This hook allows you to hook in your own ACLs without having to + # modify this file. If you do it like we suggest, you'll end up with + # a small performance penalty since there is an additional file being + # accessed. This doesn't happen if you leave the macro unset. + .ifdef CHECK_RCPT_LOCAL_ACL_FILE + .include CHECK_RCPT_LOCAL_ACL_FILE + .endif + + + ############################################################################# + # This check is commented out because it is recognized that not every + # sysadmin will want to do it. If you enable it, the check performs + # Client SMTP Authorization (csa) checks on the sending host. These checks + # do DNS lookups for SRV records. The CSA proposal is currently (May 2005) + # an Internet draft. You can, of course, add additional conditions to this + # ACL statement to restrict the CSA checks to certain hosts only. + # + # require verify = csa + ############################################################################# + + + # Accept if the address is in a domain for which we are an incoming relay, + # but again, only if the recipient can be verified. + + accept + domains = +relay_to_domains + endpass + verify = recipient + + + # At this point, the address has passed all the checks that have been + # configured, so we accept it unconditionally. + + accept +##################################################### +### end acl/30_exim4-config_check_rcpt +##################################################### +##################################################### +### acl/40_exim4-config_check_data +##################################################### + +### acl/40_exim4-config_check_data +################################# + +# This ACL is used after the contents of a message have been received. This +# is the ACL in which you can test a message's headers or body, and in +# particular, this is where you can invoke external virus or spam scanners. + +acl_check_data: + + # Deny if the message contains an overlong line. Per the standards + # we should never receive one such via SMTP. + # + .ifndef IGNORE_SMTP_LINE_LENGTH_LIMIT + deny message = maximum allowed line length is 998 octets, \ + got $max_received_linelength + condition = ${if > {$max_received_linelength}{998}} + .endif + + # Deny if the headers contain badly-formed addresses. + # + .ifndef NO_CHECK_DATA_VERIFY_HEADER_SYNTAX + deny + !acl = acl_local_deny_exceptions + !verify = header_syntax + message = header syntax + log_message = header syntax ($acl_verify_message) + .endif + + + # require that there is a verifiable sender address in at least + # one of the "Sender:", "Reply-To:", or "From:" header lines. + .ifdef CHECK_DATA_VERIFY_HEADER_SENDER + deny + message = No verifiable sender address in message headers + !acl = acl_local_deny_exceptions + !verify = header_sender + .endif + + + # Deny if the message contains malware. Before enabling this check, you + # must install a virus scanner and set the av_scanner option in the + # main configuration. + # + # exim4-daemon-heavy must be used for this section to work. + # + # deny + # malware = * + # message = This message was detected as possible malware ($malware_name). + + + # Add headers to a message if it is judged to be spam. Before enabling this, + # you must install SpamAssassin. You may also need to set the spamd_address + # option in the main configuration. + # + # exim4-daemon-heavy must be used for this section to work. + # + # Please note that this is only suiteable as an example. See + # /usr/share/doc/exim4-base/README.Debian.gz + # + # See the exim docs and the exim wiki for more suitable examples. + # + # # Remove internal headers + # warn + # remove_header = X-Spam_score: X-Spam_score_int : X-Spam_bar : \ + # X-Spam_report + # + # warn + # condition = ${if <{$message_size}{120k}{1}{0}} + # # ":true" to add headers/acl variables even if not spam + # spam = nobody:true + # add_header = X-Spam_score: $spam_score + # add_header = X-Spam_bar: $spam_bar + # # Do not enable this unless you have shorted SpamAssassin's report + # #add_header = X-Spam_report: $spam_report + # + # Reject spam messages (score >15.0). + # This breaks mailing list and forward messages. + # deny + # message = Classified as spam (score $spam_score) + # condition = ${if <{$message_size}{120k}{1}{0}} + # condition = ${if >{$spam_score_int}{150}{true}{false}} + + + # This hook allows you to hook in your own ACLs without having to + # modify this file. If you do it like we suggest, you'll end up with + # a small performance penalty since there is an additional file being + # accessed. This doesn't happen if you leave the macro unset. + .ifdef CHECK_DATA_LOCAL_ACL_FILE + .include CHECK_DATA_LOCAL_ACL_FILE + .endif + + + # accept otherwise + accept +##################################################### +### end acl/40_exim4-config_check_data +##################################################### +##################################################### +### router/00_exim4-config_header +##################################################### + +###################################################################### +# ROUTERS CONFIGURATION # +# Specifies how addresses are handled # +###################################################################### +# THE ORDER IN WHICH THE ROUTERS ARE DEFINED IS IMPORTANT! # +# An address is passed to each router in turn until it is accepted. # +###################################################################### + +begin routers + +##################################################### +### end router/00_exim4-config_header +##################################################### +##################################################### +### router/100_exim4-config_domain_literal +##################################################### + +### router/100_exim4-config_domain_literal +################################# + +# This router handles e-mail addresses in "domain literal" form like +# . The RFCs require this facility, but it is disabled +# in the default config since it is rarely used and frequently abused. +# Domain literal support also needs to be enabled in the main config, +# which is automatically done if you use the enable macro +# MAIN_ALLOW_DOMAIN_LITERALS. + +.ifdef MAIN_ALLOW_DOMAIN_LITERALS +domain_literal: + debug_print = "R: domain_literal for $local_part@$domain" + driver = ipliteral + domains = ! +local_domains + transport = remote_smtp +.endif +##################################################### +### end router/100_exim4-config_domain_literal +##################################################### +##################################################### +### router/150_exim4-config_hubbed_hosts +##################################################### + +# router/150_exim4-config_hubbed_hosts +################################# + +# route specific domains manually. +# +# see exim4-config_files(5) and spec.txt chapter 20.3 through 20.7 for +# more detailed documentation. + +hubbed_hosts: + debug_print = "R: hubbed_hosts for $domain" + driver = manualroute + domains = "${if exists{CONFDIR/hubbed_hosts}\ + {partial-lsearch;CONFDIR/hubbed_hosts}\ + fail}" + same_domain_copy_routing = yes + route_data = ${lookup{$domain}partial-lsearch{CONFDIR/hubbed_hosts}} + transport = remote_smtp +##################################################### +### end router/150_exim4-config_hubbed_hosts +##################################################### +##################################################### +### router/200_exim4-config_primary +##################################################### + +### router/200_exim4-config_primary +################################# +# This file holds the primary router, responsible for nonlocal mails + +.ifdef DCconfig_internet +# configtype=internet +# +# deliver mail to the recipient if recipient domain is a domain we +# relay for. We do not ignore any target hosts here since delivering to +# a site local or even a link local address might be wanted here, and if +# such an address has found its way into the MX record of such a domain, +# the local admin is probably in a place where that broken MX record +# could be fixed. + +dnslookup_relay_to_domains: + debug_print = "R: dnslookup_relay_to_domains for $local_part@$domain" + driver = dnslookup + domains = ! +local_domains : +relay_to_domains + transport = remote_smtp + same_domain_copy_routing = yes + dnssec_request_domains = * + no_more + +# deliver mail directly to the recipient. This router is only reached +# for domains that we do not relay for. Since we most probably can't +# have broken MX records pointing to site local or link local IP +# addresses fixed, we ignore target hosts pointing to these addresses. + +dnslookup: + debug_print = "R: dnslookup for $local_part@$domain" + driver = dnslookup + domains = ! +local_domains + transport = remote_smtp + same_domain_copy_routing = yes + # ignore private rfc1918 and APIPA addresses + ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8 : 192.168.0.0/16 :\ + 172.16.0.0/12 : 10.0.0.0/8 : 169.254.0.0/16 :\ + 255.255.255.255 + dnssec_request_domains = * + no_more + +.endif + + +.ifdef DCconfig_local +# configtype=local +# +# Stand-alone system, so generate an error for mail to a non-local domain +nonlocal: + debug_print = "R: nonlocal for $local_part@$domain" + driver = redirect + domains = ! +local_domains + allow_fail + data = :fail: Mailing to remote domains not supported + no_more + +.endif + + +.ifdef DCconfig_smarthost DCconfig_satellite +# configtype=smarthost or configtype=satellite +# +# Send all non-local mail to a single other machine (smarthost). +# +# This means _ALL_ non-local mail goes to the smarthost. This will most +# probably not do what you want for domains that are listed in +# relay_domains. The most typical use for relay_domains is to control +# relaying for incoming e-mail on secondary MX hosts. In that case, +# it doesn't make sense to send the mail to the smarthost since the +# smarthost will probably send the message right back here, causing a +# loop. +# +# If you want to use a smarthost while being secondary MX for some +# domains, you'll need to copy the dnslookup_relay_to_domains router +# here so that mail to relay_domains is handled separately. + +smarthost: + debug_print = "R: smarthost for $local_part@$domain" + driver = manualroute + domains = ! +local_domains + transport = remote_smtp_smarthost + route_list = * DCsmarthost byname + host_find_failed = ignore + same_domain_copy_routing = yes + no_more + +.endif + + +# The "no_more" above means that all later routers are for +# domains in the local_domains list, i.e. just like Exim 3 directors. +##################################################### +### end router/200_exim4-config_primary +##################################################### +##################################################### +### router/300_exim4-config_real_local +##################################################### + +### router/300_exim4-config_real_local +################################# + +# This router allows reaching a local user while avoiding local +# processing. This can be used to inform a user of a broken .forward +# file, for example. The userforward router does this. + +COND_LOCAL_SUBMITTER = "\ + ${if match_ip{$sender_host_address}{:@[]}\ + {1}{0}\ + }" + +real_local: + debug_print = "R: real_local for $local_part@$domain" + driver = accept + domains = +local_domains + condition = COND_LOCAL_SUBMITTER + local_part_prefix = real- + check_local_user + transport = LOCAL_DELIVERY + +##################################################### +### end router/300_exim4-config_real_local +##################################################### +##################################################### +### router/400_exim4-config_system_aliases +##################################################### + +### router/400_exim4-config_system_aliases +################################# + +# This router handles aliasing using a traditional /etc/aliases file. +# +##### NB You must ensure that /etc/aliases exists. It used to be the case +##### NB that every Unix had that file, because it was the Sendmail default. +##### NB These days, there are systems that don't have it. Your aliases +##### NB file should at least contain an alias for "postmaster". +# +# This router handles the local part in a case-insensitive way which +# satisfies the RFCs requirement that postmaster be reachable regardless +# of case. If you decide to handle /etc/aliases in a caseful way, you +# need to make arrangements for a caseless postmaster. +# +# Delivery to arbitrary directories, files, and piping to programs in +# /etc/aliases is disabled per default. +# If that is a problem for you, see +# /usr/share/doc/exim4-base/README.Debian.gz +# for explanation and some workarounds. + +system_aliases: + debug_print = "R: system_aliases for $local_part@$domain" + driver = redirect + domains = +local_domains + allow_fail + allow_defer + data = ${lookup{$local_part}lsearch{/etc/aliases}} + .ifdef SYSTEM_ALIASES_USER + user = SYSTEM_ALIASES_USER + .endif + .ifdef SYSTEM_ALIASES_GROUP + group = SYSTEM_ALIASES_GROUP + .endif + .ifdef SYSTEM_ALIASES_FILE_TRANSPORT + file_transport = SYSTEM_ALIASES_FILE_TRANSPORT + .endif + .ifdef SYSTEM_ALIASES_PIPE_TRANSPORT + pipe_transport = SYSTEM_ALIASES_PIPE_TRANSPORT + .endif + .ifdef SYSTEM_ALIASES_DIRECTORY_TRANSPORT + directory_transport = SYSTEM_ALIASES_DIRECTORY_TRANSPORT + .endif +##################################################### +### end router/400_exim4-config_system_aliases +##################################################### +##################################################### +### router/500_exim4-config_hubuser +##################################################### + +### router/500_exim4-config_hubuser +################################# + +.ifdef DCconfig_satellite +# This router is only used for configtype=satellite. +# It takes care to route all mail targeted to +# to the host where we read our mail +# +hub_user: + debug_print = "R: hub_user for $local_part@$domain" + driver = redirect + domains = +local_domains + data = ${local_part}@DCreadhost + check_local_user + +# Grab the redirected mail and deliver it. +# This is a duplicate of the smarthost router, needed because +# DCreadhost might end up as part of +local_domains +hub_user_smarthost: + debug_print = "R: hub_user_smarthost for $local_part@$domain" + driver = manualroute + domains = DCreadhost + transport = remote_smtp_smarthost + route_list = * DCsmarthost byname + host_find_failed = ignore + same_domain_copy_routing = yes + check_local_user +.endif + + +##################################################### +### end router/500_exim4-config_hubuser +##################################################### +##################################################### +### router/600_exim4-config_userforward +##################################################### + +### router/600_exim4-config_userforward +################################# + +# This router handles forwarding using traditional .forward files in users' +# home directories. It also allows mail filtering with a forward file +# starting with the string "# Exim filter" or "# Sieve filter". +# +# The no_verify setting means that this router is skipped when Exim is +# verifying addresses. Similarly, no_expn means that this router is skipped if +# Exim is processing an EXPN command. +# +# The check_ancestor option means that if the forward file generates an +# address that is an ancestor of the current one, the current one gets +# passed on instead. This covers the case where A is aliased to B and B +# has a .forward file pointing to A. +# +# The four transports specified at the end are those that are used when +# forwarding generates a direct delivery to a directory, or a file, or to a +# pipe, or sets up an auto-reply, respectively. +# +userforward: + debug_print = "R: userforward for $local_part@$domain" + driver = redirect + domains = +local_domains + check_local_user + file = $home/.forward + require_files = $local_part:$home/.forward + no_verify + no_expn + check_ancestor + allow_filter + forbid_smtp_code = true + directory_transport = address_directory + file_transport = address_file + pipe_transport = address_pipe + reply_transport = address_reply + skip_syntax_errors + syntax_errors_to = real-$local_part@$domain + syntax_errors_text = \ + This is an automatically generated message. An error has\n\ + been found in your .forward file. Details of the error are\n\ + reported below. While this error persists, you will receive\n\ + a copy of this message for every message that is addressed\n\ + to you. If your .forward file is a filter file, or if it is\n\ + a non-filter file containing no valid forwarding addresses,\n\ + a copy of each incoming message will be put in your normal\n\ + mailbox. If a non-filter file contains at least one valid\n\ + forwarding address, forwarding to the valid addresses will\n\ + happen, and those will be the only deliveries that occur. + +##################################################### +### end router/600_exim4-config_userforward +##################################################### +##################################################### +### router/700_exim4-config_procmail +##################################################### + +procmail: + debug_print = "R: procmail for $local_part@$domain" + driver = accept + domains = +local_domains + check_local_user + transport = procmail_pipe + # emulate OR with "if exists"-expansion + require_files = ${local_part}:\ + ${if exists{/etc/procmailrc}\ + {/etc/procmailrc}{${home}/.procmailrc}}:\ + +/usr/bin/procmail + no_verify + no_expn + +##################################################### +### end router/700_exim4-config_procmail +##################################################### +##################################################### +### router/800_exim4-config_maildrop +##################################################### + +### router/800_exim4-config_maildrop +################################# + +maildrop: + debug_print = "R: maildrop for $local_part@$domain" + driver = accept + domains = +local_domains + check_local_user + transport = maildrop_pipe + require_files = ${local_part}:${home}/.mailfilter:+/usr/bin/maildrop + no_verify + no_expn + +##################################################### +### end router/800_exim4-config_maildrop +##################################################### +##################################################### +### router/850_exim4-config_lowuid +##################################################### + +### router/850_exim4-config_lowuid +################################# + +.ifndef FIRST_USER_ACCOUNT_UID +FIRST_USER_ACCOUNT_UID = 0 +.endif + +.ifndef DEFAULT_SYSTEM_ACCOUNT_ALIAS +DEFAULT_SYSTEM_ACCOUNT_ALIAS = :fail: no mail to system accounts +.endif + +COND_SYSTEM_USER_AND_REMOTE_SUBMITTER = "\ + ${if and{{! match_ip{$sender_host_address}{:@[]}}\ + {<{$local_user_uid}{FIRST_USER_ACCOUNT_UID}}}\ + {1}{0}\ + }" + +lowuid_aliases: + debug_print = "R: lowuid_aliases for $local_part@$domain (UID $local_user_uid)" + check_local_user + driver = redirect + allow_fail + domains = +local_domains + condition = COND_SYSTEM_USER_AND_REMOTE_SUBMITTER + data = ${if exists{CONFDIR/lowuid-aliases}\ + {${lookup{$local_part}lsearch{CONFDIR/lowuid-aliases}\ + {$value}{DEFAULT_SYSTEM_ACCOUNT_ALIAS}}}\ + {DEFAULT_SYSTEM_ACCOUNT_ALIAS}} +##################################################### +### end router/850_exim4-config_lowuid +##################################################### +##################################################### +### router/900_exim4-config_local_user +##################################################### + +### router/900_exim4-config_local_user +################################# + +# This router matches local user mailboxes. If the router fails, the error +# message is "Unknown user". + +local_user: + debug_print = "R: local_user for $local_part@$domain" + driver = accept + domains = +local_domains + check_local_user + local_parts = ! root + transport = LOCAL_DELIVERY + cannot_route_message = Unknown user +##################################################### +### end router/900_exim4-config_local_user +##################################################### +##################################################### +### router/mmm_mail4root +##################################################### + +### router/mmm_mail4root +################################# +# deliver mail addressed to root to /var/mail/mail as user mail:mail +# if it was not redirected in /etc/aliases or by other means +# Exim cannot deliver as root since 4.24 (FIXED_NEVER_USERS) + +mail4root: + debug_print = "R: mail4root for $local_part@$domain" + driver = redirect + domains = +local_domains + data = /var/mail/mail + file_transport = address_file + local_parts = root + user = mail + group = mail + +##################################################### +### end router/mmm_mail4root +##################################################### +##################################################### +### transport/00_exim4-config_header +##################################################### + +###################################################################### +# TRANSPORTS CONFIGURATION # +###################################################################### +# ORDER DOES NOT MATTER # +# Only one appropriate transport is called for each delivery. # +###################################################################### + +# A transport is used only when referenced from a router that successfully +# handles an address. + +begin transports + +##################################################### +### end transport/00_exim4-config_header +##################################################### +##################################################### +### transport/10_exim4-config_transport-macros +##################################################### + +### transport/10_exim4-config_transport-macros +################################# + +.ifdef HIDE_MAILNAME +REMOTE_SMTP_HEADERS_REWRITE=*@+local_domains $1@DCreadhost frs : *@ETC_MAILNAME $1@DCreadhost frs +REMOTE_SMTP_RETURN_PATH=${if match_domain{$sender_address_domain}{+local_domains}{${sender_address_local_part}@DCreadhost}{${if match_domain{$sender_address_domain}{ETC_MAILNAME}{${sender_address_local_part}@DCreadhost}fail}}} +.endif + +.ifdef REMOTE_SMTP_HELO_FROM_DNS +.ifdef REMOTE_SMTP_HELO_DATA +REMOTE_SMTP_HELO_DATA==${lookup dnsdb {ptr=$sending_ip_address}{$value}{$primary_hostname}} +.else +REMOTE_SMTP_HELO_DATA=${lookup dnsdb {ptr=$sending_ip_address}{$value}{$primary_hostname}} +.endif +.endif +##################################################### +### end transport/10_exim4-config_transport-macros +##################################################### +##################################################### +### transport/30_exim4-config_address_file +##################################################### + +# This transport is used for handling deliveries directly to files that are +# generated by aliasing or forwarding. +# +address_file: + debug_print = "T: address_file for $local_part@$domain" + driver = appendfile + delivery_date_add + envelope_to_add + return_path_add + +##################################################### +### end transport/30_exim4-config_address_file +##################################################### +##################################################### +### transport/30_exim4-config_address_pipe +##################################################### + +# This transport is used for handling pipe deliveries generated by +# .forward files. If the commands fails and produces any output on standard +# output or standard error streams, the output is returned to the sender +# of the message as a delivery error. +address_pipe: + debug_print = "T: address_pipe for $local_part@$domain" + driver = pipe + return_fail_output + +##################################################### +### end transport/30_exim4-config_address_pipe +##################################################### +##################################################### +### transport/30_exim4-config_address_reply +##################################################### + +# This transport is used for handling autoreplies generated by the filtering +# option of the userforward router. +# +address_reply: + debug_print = "T: autoreply for $local_part@$domain" + driver = autoreply + +##################################################### +### end transport/30_exim4-config_address_reply +##################################################### +##################################################### +### transport/30_exim4-config_mail_spool +##################################################### + +### transport/30_exim4-config_mail_spool + +# This transport is used for local delivery to user mailboxes in traditional +# BSD mailbox format. +# +mail_spool: + debug_print = "T: appendfile for $local_part@$domain" + driver = appendfile + file = /var/mail/$local_part + delivery_date_add + envelope_to_add + return_path_add + group = mail + mode = 0660 + mode_fail_narrower = false + +##################################################### +### end transport/30_exim4-config_mail_spool +##################################################### +##################################################### +### transport/30_exim4-config_maildir_home +##################################################### + +### transport/30_exim4-config_maildir_home +################################# + +# Use this instead of mail_spool if you want to to deliver to Maildir in +# home-directory - change the definition of LOCAL_DELIVERY +# +maildir_home: + debug_print = "T: maildir_home for $local_part@$domain" + driver = appendfile + .ifdef MAILDIR_HOME_MAILDIR_LOCATION + directory = MAILDIR_HOME_MAILDIR_LOCATION + .else + directory = $home/Maildir + .endif + .ifdef MAILDIR_HOME_CREATE_DIRECTORY + create_directory + .endif + .ifdef MAILDIR_HOME_CREATE_FILE + create_file = MAILDIR_HOME_CREATE_FILE + .endif + delivery_date_add + envelope_to_add + return_path_add + maildir_format + .ifdef MAILDIR_HOME_DIRECTORY_MODE + directory_mode = MAILDIR_HOME_DIRECTORY_MODE + .else + directory_mode = 0700 + .endif + .ifdef MAILDIR_HOME_MODE + mode = MAILDIR_HOME_MODE + .else + mode = 0600 + .endif + mode_fail_narrower = false + # This transport always chdirs to $home before trying to deliver. If + # $home is not accessible, this chdir fails and prevents delivery. + # If you are in a setup where home directories might not be + # accessible, uncomment the current_directory line below. + # current_directory = / +##################################################### +### end transport/30_exim4-config_maildir_home +##################################################### +##################################################### +### transport/30_exim4-config_maildrop_pipe +##################################################### + +maildrop_pipe: + debug_print = "T: maildrop_pipe for $local_part@$domain" + driver = pipe + path = "/bin:/usr/bin:/usr/local/bin" + command = "/usr/bin/maildrop" + message_prefix = + message_suffix = + return_path_add + delivery_date_add + envelope_to_add + +##################################################### +### end transport/30_exim4-config_maildrop_pipe +##################################################### +##################################################### +### transport/30_exim4-config_procmail_pipe +##################################################### + +procmail_pipe: + debug_print = "T: procmail_pipe for $local_part@$domain" + driver = pipe + path = "/bin:/usr/bin:/usr/local/bin" + command = "/usr/bin/procmail" + return_path_add + delivery_date_add + envelope_to_add + +##################################################### +### end transport/30_exim4-config_procmail_pipe +##################################################### +##################################################### +### transport/30_exim4-config_remote_smtp +##################################################### + +### transport/30_exim4-config_remote_smtp +################################# +# This transport is used for delivering messages over SMTP connections. +# Refuse to send any message with over-long lines, which could have +# been received other than via SMTP. The use of message_size_limit to +# enforce this is a red herring. + +remote_smtp: + debug_print = "T: remote_smtp for $local_part@$domain" + driver = smtp +.ifndef IGNORE_SMTP_LINE_LENGTH_LIMIT + message_size_limit = ${if > {$max_received_linelength}{998} {1}{0}} +.endif +.ifdef REMOTE_SMTP_HOSTS_AVOID_TLS + hosts_avoid_tls = REMOTE_SMTP_HOSTS_AVOID_TLS +.endif +.ifdef REMOTE_SMTP_HEADERS_REWRITE + headers_rewrite = REMOTE_SMTP_HEADERS_REWRITE +.endif +.ifdef REMOTE_SMTP_RETURN_PATH + return_path = REMOTE_SMTP_RETURN_PATH +.endif +.ifdef REMOTE_SMTP_HELO_DATA + helo_data=REMOTE_SMTP_HELO_DATA +.endif +.ifdef DKIM_DOMAIN +dkim_domain = DKIM_DOMAIN +.endif +.ifdef DKIM_SELECTOR +dkim_selector = DKIM_SELECTOR +.endif +.ifdef DKIM_PRIVATE_KEY +dkim_private_key = DKIM_PRIVATE_KEY +.endif +.ifdef DKIM_CANON +dkim_canon = DKIM_CANON +.endif +.ifdef DKIM_STRICT +dkim_strict = DKIM_STRICT +.endif +.ifdef DKIM_SIGN_HEADERS +dkim_sign_headers = DKIM_SIGN_HEADERS +.endif +.ifdef TLS_DH_MIN_BITS +tls_dh_min_bits = TLS_DH_MIN_BITS +.endif +.ifdef REMOTE_SMTP_TLS_CERTIFICATE +tls_certificate = REMOTE_SMTP_TLS_CERTIFICATE +.endif +.ifdef REMOTE_SMTP_PRIVATEKEY +tls_privatekey = REMOTE_SMTP_PRIVATEKEY +.endif +.ifndef REMOTE_SMTP_DISABLE_DANE +dnssec_request_domains = * +hosts_try_dane = * +.endif +##################################################### +### end transport/30_exim4-config_remote_smtp +##################################################### +##################################################### +### transport/30_exim4-config_remote_smtp_smarthost +##################################################### + +### transport/30_exim4-config_remote_smtp_smarthost +################################# + +# This transport is used for delivering messages over SMTP connections +# to a smarthost. The local host tries to authenticate. +# This transport is used for smarthost and satellite configurations. +# Refuse to send any messsage with over-long lines, which could have +# been received other than via SMTP. The use of message_size_limit to +# enforce this is a red herring. + +remote_smtp_smarthost: + debug_print = "T: remote_smtp_smarthost for $local_part@$domain" + driver = smtp + multi_domain +.ifndef IGNORE_SMTP_LINE_LENGTH_LIMIT + message_size_limit = ${if > {$max_received_linelength}{998} {1}{0}} +.endif + hosts_try_auth = <; ${if exists{CONFDIR/passwd.client} \ + {\ + ${lookup{$host}nwildlsearch{CONFDIR/passwd.client}{$host_address}}\ + }\ + {} \ + } +.ifdef REMOTE_SMTP_SMARTHOST_HOSTS_AVOID_TLS + hosts_avoid_tls = REMOTE_SMTP_SMARTHOST_HOSTS_AVOID_TLS +.endif +.ifdef REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS + hosts_require_tls = REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS +.endif +.ifdef REMOTE_SMTP_HEADERS_REWRITE + headers_rewrite = REMOTE_SMTP_HEADERS_REWRITE +.endif +.ifdef REMOTE_SMTP_RETURN_PATH + return_path = REMOTE_SMTP_RETURN_PATH +.endif +.ifdef REMOTE_SMTP_HELO_DATA + helo_data=REMOTE_SMTP_HELO_DATA +.endif +.ifdef TLS_DH_MIN_BITS +tls_dh_min_bits = TLS_DH_MIN_BITS +.endif +.ifdef REMOTE_SMTP_SMARTHOST_TLS_CERTIFICATE +tls_certificate = REMOTE_SMTP_SMARTHOST_TLS_CERTIFICATE +.endif +.ifdef REMOTE_SMTP_SMARTHOST_PRIVATEKEY +tls_privatekey = REMOTE_SMTP_SMARTHOST_PRIVATEKEY +.endif +##################################################### +### end transport/30_exim4-config_remote_smtp_smarthost +##################################################### +##################################################### +### transport/35_exim4-config_address_directory +##################################################### +# This transport is used for handling file addresses generated by alias +# or .forward files if the path ends in "/", which causes it to be treated +# as a directory name rather than a file name. + +address_directory: + debug_print = "T: address_directory for $local_part@$domain" + driver = appendfile + delivery_date_add + envelope_to_add + return_path_add + check_string = "" + escape_string = "" + maildir_format + +##################################################### +### end transport/35_exim4-config_address_directory +##################################################### +##################################################### +### retry/00_exim4-config_header +##################################################### + +###################################################################### +# RETRY CONFIGURATION # +###################################################################### + +begin retry + +##################################################### +### end retry/00_exim4-config_header +##################################################### +##################################################### +### retry/30_exim4-config +##################################################### + +### retry/30_exim4-config +################################# + +# This single retry rule applies to all domains and all errors. It specifies +# retries every 15 minutes for 2 hours, then increasing retry intervals, +# starting at 1 hour and increasing each time by a factor of 1.5, up to 16 +# hours, then retries every 6 hours until 4 days have passed since the first +# failed delivery. + +# Please note that these rules only limit the frequency of retries, the +# effective retry-time depends on the frequency of queue-running, too. +# See QUEUEINTERVAL in /etc/default/exim4. + +# Address or Domain Error Retries +# ----------------- ----- ------- + +* * F,2h,15m; G,16h,1h,1.5; F,4d,6h + +##################################################### +### end retry/30_exim4-config +##################################################### +##################################################### +### rewrite/00_exim4-config_header +##################################################### + +###################################################################### +# REWRITE CONFIGURATION # +###################################################################### + +begin rewrite + +##################################################### +### end rewrite/00_exim4-config_header +##################################################### +##################################################### +### rewrite/31_exim4-config_rewriting +##################################################### + +### rewrite/31_exim4-config_rewriting +################################# + +# This rewriting rule is particularly useful for dialup users who +# don't have their own domain, but could be useful for anyone. +# It looks up the real address of all local users in a file +.ifndef NO_EAA_REWRITE_REWRITE +*@+local_domains "${lookup{${local_part}}lsearch{/etc/email-addresses}\ + {$value}fail}" Ffrs +# identical rewriting rule for /etc/mailname +*@ETC_MAILNAME "${lookup{${local_part}}lsearch{/etc/email-addresses}\ + {$value}fail}" Ffrs +.endif + + +##################################################### +### end rewrite/31_exim4-config_rewriting +##################################################### +##################################################### +### auth/00_exim4-config_header +##################################################### + +###################################################################### +# AUTHENTICATION CONFIGURATION # +###################################################################### + +begin authenticators + + +##################################################### +### end auth/00_exim4-config_header +##################################################### +##################################################### +### auth/30_exim4-config_examples +##################################################### + +### auth/30_exim4-config_examples +################################# + +# The examples below are for server side authentication, when the +# local exim is SMTP server and clients authenticate to the local exim. + +# They allow two styles of plain-text authentication against an +# CONFDIR/passwd file whose syntax is described in exim4_passwd(5). + +# Hosts that are allowed to use AUTH are defined by the +# auth_advertise_hosts option in the main configuration. The default is +# "*", which allows authentication to all hosts over all kinds of +# connections if there is at least one authenticator defined here. +# Authenticators which rely on unencrypted clear text passwords don't +# advertise on unencrypted connections by default. Thus, it might be +# wise to set up TLS to allow encrypted connections. If TLS cannot be +# used for some reason, you can set AUTH_SERVER_ALLOW_NOTLS_PASSWORDS to +# advertise unencrypted clear text password based authenticators on all +# connections. As this is severely reducing security, using TLS is +# preferred over allowing clear text password based authenticators on +# unencrypted connections. + +# PLAIN authentication has no server prompts. The client sends its +# credentials in one lump, containing an authorization ID (which we do not +# use), an authentication ID, and a password. The latter two appear as +# $auth2 and $auth3 in the configuration and should be checked against a +# valid username and password. In a real configuration you would typically +# use $auth2 as a lookup key, and compare $auth3 against the result of the +# lookup, perhaps using the crypteq{}{} condition. + +# plain_server: +# driver = plaintext +# public_name = PLAIN +# server_condition = "${if crypteq{$auth3}{${extract{1}{:}{${lookup{$auth2}lsearch{CONFDIR/passwd}{$value}{*:*}}}}}{1}{0}}" +# server_set_id = $auth2 +# server_prompts = : +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif + +# LOGIN authentication has traditional prompts and responses. There is no +# authorization ID in this mechanism, so unlike PLAIN the username and +# password are $auth1 and $auth2. Apart from that you can use the same +# server_condition setting for both authenticators. + +# login_server: +# driver = plaintext +# public_name = LOGIN +# server_prompts = "Username:: : Password::" +# server_condition = "${if crypteq{$auth2}{${extract{1}{:}{${lookup{$auth1}lsearch{CONFDIR/passwd}{$value}{*:*}}}}}{1}{0}}" +# server_set_id = $auth1 +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif +# +# cram_md5_server: +# driver = cram_md5 +# public_name = CRAM-MD5 +# server_secret = ${extract{2}{:}{${lookup{$auth1}lsearch{CONFDIR/passwd}{$value}fail}}} +# server_set_id = $auth1 + +# Here is an example of CRAM-MD5 authentication against PostgreSQL: +# +# psqldb_auth_server: +# driver = cram_md5 +# public_name = CRAM-MD5 +# server_secret = ${lookup pgsql{SELECT pw FROM users WHERE username = '${quote_pgsql:$auth1}'}{$value}fail} +# server_set_id = $auth1 + +# Authenticate against local passwords using sasl2-bin +# Requires exim_uid to be a member of sasl group, see README.Debian.gz +# plain_saslauthd_server: +# driver = plaintext +# public_name = PLAIN +# server_condition = ${if saslauthd{{$auth2}{$auth3}}{1}{0}} +# server_set_id = $auth2 +# server_prompts = : +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif +# +# login_saslauthd_server: +# driver = plaintext +# public_name = LOGIN +# server_prompts = "Username:: : Password::" +# # don't send system passwords over unencrypted connections +# server_condition = ${if saslauthd{{$auth1}{$auth2}}{1}{0}} +# server_set_id = $auth1 +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif +# +# ntlm_sasl_server: +# driver = cyrus_sasl +# public_name = NTLM +# server_realm = +# server_set_id = $auth1 +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif +# +# digest_md5_sasl_server: +# driver = cyrus_sasl +# public_name = DIGEST-MD5 +# server_realm = +# server_set_id = $auth1 +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif + +# Authentcate against cyrus-sasl +# This is mainly untested, please report any problems to +# pkg-exim4-users@lists.alioth.debian.org. +# cram_md5_sasl_server: +# driver = cyrus_sasl +# public_name = CRAM-MD5 +# server_realm = +# server_set_id = $auth1 +# +# plain_sasl_server: +# driver = cyrus_sasl +# public_name = PLAIN +# server_realm = +# server_set_id = $auth1 +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif +# +# login_sasl_server: +# driver = cyrus_sasl +# public_name = LOGIN +# server_realm = +# server_set_id = $auth1 +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif + +# Authenticate against courier authdaemon + +# This is now the (working!) example from +# http://www.exim.org/eximwiki/FAQ/Policy_controls/Q0730 +# Possible pitfall: access rights on /var/run/courier/authdaemon/socket. +# plain_courier_authdaemon: +# driver = plaintext +# public_name = PLAIN +# server_condition = \ +# ${extract {ADDRESS} \ +# {${readsocket{/var/run/courier/authdaemon/socket} \ +# {AUTH ${strlen:exim\nlogin\n$auth2\n$auth3\n}\nexim\nlogin\n$auth2\n$auth3\n} }} \ +# {yes} \ +# fail} +# server_set_id = $auth2 +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif + +# login_courier_authdaemon: +# driver = plaintext +# public_name = LOGIN +# server_prompts = Username:: : Password:: +# server_condition = \ +# ${extract {ADDRESS} \ +# {${readsocket{/var/run/courier/authdaemon/socket} \ +# {AUTH ${strlen:exim\nlogin\n$auth1\n$auth2\n}\nexim\nlogin\n$auth1\n$auth2\n} }} \ +# {yes} \ +# fail} +# server_set_id = $auth1 +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif + +# This one is a bad hack to support the broken version 4.xx of +# Microsoft Outlook Express which violates the RFCs by demanding +# "250-AUTH=" instead of "250-AUTH ". +# If your list of offered authenticators is other than PLAIN and LOGIN, +# you need to adapt the public_name line manually. +# It has to be the last authenticator to work and has not been tested +# well. Use at your own risk. +# See the thread entry point from +# http://www.exim.org/mail-archives/exim-users/Week-of-Mon-20050214/msg00213.html +# for the related discussion on the exim-users mailing list. +# Thanks to Fred Viles for this great work. + +# support_broken_outlook_express_4_server: +# driver = plaintext +# public_name = "\r\n250-AUTH=PLAIN LOGIN" +# server_prompts = User Name : Password +# server_condition = no +# .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS +# server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}} +# .endif + +############## +# See /usr/share/doc/exim4-base/README.Debian.gz +############## + +# These examples below are the equivalent for client side authentication. +# They get the passwords from CONFDIR/passwd.client, whose format is +# defined in exim4_passwd_client(5) + +# Because AUTH PLAIN and AUTH LOGIN send the password in clear, we +# only allow these mechanisms over encrypted connections by default. +# You can set AUTH_CLIENT_ALLOW_NOTLS_PASSWORDS to allow unencrypted +# clear text password authentication on all connections. + +cram_md5: + driver = cram_md5 + public_name = CRAM-MD5 + client_name = ${extract{1}{:}{${lookup{$host}nwildlsearch{CONFDIR/passwd.client}{$value}fail}}} + client_secret = ${extract{2}{:}{${lookup{$host}nwildlsearch{CONFDIR/passwd.client}{$value}fail}}} + +# this returns the matching line from passwd.client and doubles all ^ +PASSWDLINE=${sg{\ + ${lookup{$host}nwildlsearch{CONFDIR/passwd.client}{$value}fail}\ + }\ + {\\N[\\^]\\N}\ + {^^}\ + } + +plain: + driver = plaintext + public_name = PLAIN +.ifndef AUTH_CLIENT_ALLOW_NOTLS_PASSWORDS + client_send = "<; ${if !eq{$tls_out_cipher}{}\ + {^${extract{1}{:}{PASSWDLINE}}\ + ^${sg{PASSWDLINE}{\\N([^:]+:)(.*)\\N}{\\$2}}\ + }fail}" +.else + client_send = "<; ^${extract{1}{:}{PASSWDLINE}}\ + ^${sg{PASSWDLINE}{\\N([^:]+:)(.*)\\N}{\\$2}}" +.endif + +login: + driver = plaintext + public_name = LOGIN +.ifndef AUTH_CLIENT_ALLOW_NOTLS_PASSWORDS + # Return empty string if not non-TLS AND looking up $host in passwd-file + # yields a non-empty string; fail otherwise. + client_send = "<; ${if and{\ + {!eq{$tls_out_cipher}{}}\ + {!eq{PASSWDLINE}{}}\ + }\ + {}fail}\ + ; ${extract{1}{::}{PASSWDLINE}}\ + ; ${sg{PASSWDLINE}{\\N([^:]+:)(.*)\\N}{\\$2}}" +.else + # Return empty string if looking up $host in passwd-file yields a + # non-empty string; fail otherwise. + client_send = "<; ${if !eq{PASSWDLINE}{}\ + {}fail}\ + ; ${extract{1}{::}{PASSWDLINE}}\ + ; ${sg{PASSWDLINE}{\\N([^:]+:)(.*)\\N}{\\$2}}" +.endif +##################################################### +### end auth/30_exim4-config_examples +##################################################### diff --git a/exim4/passwd.client b/exim4/passwd.client new file mode 100644 index 00000000..2f06b8d5 --- /dev/null +++ b/exim4/passwd.client @@ -0,0 +1,7 @@ +# password file used when the local exim is authenticating to a remote +# host as a client. +# +# see exim4_passwd_client(5) for more documentation +# +# Example: +### target.mail.server.example:login:password diff --git a/exim4/update-exim4.conf.conf b/exim4/update-exim4.conf.conf new file mode 100644 index 00000000..27dbd0dd --- /dev/null +++ b/exim4/update-exim4.conf.conf @@ -0,0 +1,31 @@ +# /etc/exim4/update-exim4.conf.conf +# +# Edit this file and /etc/mailname by hand and execute update-exim4.conf +# yourself or use 'dpkg-reconfigure exim4-config' +# +# Please note that this is _not_ a dpkg-conffile and that automatic changes +# to this file might happen. The code handling this will honor your local +# changes, so this is usually fine, but will break local schemes that mess +# around with multiple versions of the file. +# +# update-exim4.conf uses this file to determine variable values to generate +# exim configuration macros for the configuration file. +# +# Most settings found in here do have corresponding questions in the +# Debconf configuration, but not all of them. +# +# This is a Debian specific file + +dc_eximconfig_configtype='local' +dc_other_hostnames='serviceraspi.realm.local' +dc_local_interfaces='127.0.0.1 ; ::1' +dc_readhost='' +dc_relay_domains='' +dc_minimaldns='false' +dc_relay_nets='' +dc_smarthost='' +CFILEMODE='644' +dc_use_split_config='false' +dc_hide_mailname='' +dc_mailname_in_oh='true' +dc_localdelivery='mail_spool' diff --git a/fb.modes b/fb.modes new file mode 100644 index 00000000..e6a4fb7b --- /dev/null +++ b/fb.modes @@ -0,0 +1,1003 @@ +# +# Sample video modes +# +# These data are based on the CRTC parameters in +# +# Mach64 Programmer's Guide, Appendix C +# (C) 1998 ATI Technologies Inc. +# +# Kop: this are very generic modes and not only for ATI cards. +# + +# +# 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) +# +# Horizontal Vertical +# Resolution 640 480 +# Scan Frequency 31.469 kHz 59.94 Hz +# Sync Width 3.813 us 0.064 ms +# 12 chars 2 lines +# Front Porch 0.636 us 0.318 ms +# 2 chars 10 lines +# Back Porch 1.907 us 1.048 ms +# 6 chars 33 lines +# Active Time 25.422 us 15.253 ms +# 80 chars 480 lines +# Blank Time 6.356 us 1.430 ms +# 20 chars 45 lines +# Polarity negative negative +# + +mode "640x480-60" + # D: 25.175 MHz, H: 31.469 kHz, V: 59.94 Hz + geometry 640 480 640 480 8 + timings 39722 48 16 33 10 96 2 +endmode + +# +# 640x480, 72 Hz, Non-Interlaced (31.20 MHz dotclock) +# +# Horizontal Vertical +# Resolution 640 480 +# Scan Frequency 37.500 kHz 72.12 Hz +# Sync Width 1.282 us 0.080 ms +# 5 chars 3 lines +# Front Porch 0.769 us 0.240 ms +# 3 chars 9 lines +# Back Porch 4.103 us 0.747 ms +# 16 chars 28 lines +# Active Time 20.513 us 12.800 ms +# 80 chars 480 lines +# Blank Time 6.154 us 1.067 ms +# 24 chars 40 lines +# Polarity negative negative +# + +mode "640x480-72" + # D: 31.20 MHz, H: 37.500 kHz, V: 72.12 Hz + geometry 640 480 640 480 8 + timings 32052 128 24 28 9 40 3 +endmode + +# +# 640x480, 75 Hz, Non-Interlaced (31.50 MHz dotclock) +# +# Horizontal Vertical +# Resolution 640 480 +# Scan Frequency 37.500 kHz 75.00 Hz +# Sync Width 2.032 us 0.080 ms +# 8 chars 3 lines +# Front Porch 0.508 us 0.027 ms +# 2 chars 1 lines +# Back Porch 3.810 us 0.427 ms +# 15 chars 16 lines +# Active Time 20.317 us 12.800 ms +# 80 chars 480 lines +# Blank Time 6.349 us 0.533 ms +# 25 chars 20 lines +# Polarity negative negative +# + +mode "640x480-75" + # D: 31.50 MHz, H: 37.500 kHz, V: 75.00 Hz + geometry 640 480 640 480 8 + timings 31747 120 16 16 1 64 3 +endmode + +# +# 640x480, 90 Hz, Non-Interlaced (39.91 MHz dotclock) +# +# Horizontal Vertical +# Resolution 640 480 +# Scan Frequency 47.969 kHz 90.00 Hz +# Sync Width 1.002 us 0.292 ms +# 5 chars 14 lines +# Front Porch 0.902 us 0.521 ms +# 4 chars 25 lines +# Back Porch 2.907 us 0.292 ms +# 15 chars 14 lines +# Active Time 16.036 us 10.007 ms +# 80 chars 480 lines +# Blank Time 4.811 us 1.105 ms +# 24 chars 53 lines +# Polarity negative negative +# + +mode "640x480-90" + # D: 39.91 MHz, H: 47.969 kHz, V: 90.00 Hz + geometry 640 480 640 480 8 + timings 25057 120 32 14 25 40 14 +endmode + +# +# 640x480, 100 Hz, Non-Interlaced (44.90 MHz dotclock) +# +# Horizontal Vertical +# Resolution 640 480 +# Scan Frequency 52.948 kHz 99.71 Hz +# Sync Width 2.851 us 0.227 ms +# 16 chars 12 lines +# Front Porch 0.801 us 0.416 ms +# 4 chars 22 lines +# Back Porch 0.981 us 0.322 ms +# 6 chars 17 lines +# Active Time 14.254 us 9.065 ms +# 80 chars 480 lines +# Blank Time 4.633 us 0.963 ms +# 26 chars 51 lines +# Polarity negative negative +# + +mode "640x480-100" + # D: 44.90 MHz, H: 52.948 kHz, V: 99.71 Hz + geometry 640 480 640 480 8 + timings 22272 48 32 17 22 128 12 +endmode + + +# +# 768x576, 75 Hz, Non-Interlaced (49.188 MHz dotclock) +# +# Horizontal Vertical +# Resolution 768 576 +# Scan Frequency 46.580 kHz 75.008 Hz +# Sync Width us ms +# chars lines +# Front Porch us ms +# chars lines +# Back Porch us ms +# chars lines +# Active Time us ms +# chars lines +# Blank Time us ms +# chars lines +# Polarity negative negative +# +# This is a mode often used, because fbtv suggests this, since +# this is the mode for "normal" TVs. +# + +mode "768x576-75" + # D: 49.188 MHz, H: 46.580 kHz, V: 75.008 Hz + geometry 768 576 768 576 32 + timings 20330 128 32 32 8 128 5 +endmode + + +# +# 800x600, 48 Hz, Interlaced (36.00 MHz dotclock) +# +# Horizontal Vertical +# Resolution 800 600 +# Scan Frequency 33.835 kHz 96.39 Hz +# Sync Width 3.556 us 0.177 ms +# 16 chars 12 lines +# Front Porch 2.222 us 0.163 ms +# 10 chars 11 lines +# Back Porch 1.555 us 1.167 ms +# 7 chars 79 lines +# Active Time 22.222 us 8.867 ms +# 100 chars 600 lines +# Blank Time 7.333 us 1.507 ms +# 33 chars 102 lines +# Polarity positive positive +# + +mode "800x600-48-lace" + # D: 36.00 MHz, H: 33.835 kHz, V: 96.39 Hz + geometry 800 600 800 600 8 + timings 27778 56 80 79 11 128 12 + laced true + hsync high + vsync high +endmode + +# +# 800x600, 56 Hz, Non-Interlaced (36.00 MHz dotclock) +# +# Horizontal Vertical +# Resolution 800 600 +# Scan Frequency 35.156 kHz 56.25 Hz +# Sync Width 2.000 us 0.057 ms +# 9 chars 2 lines +# Front Porch 0.667 us 0.028 ms +# 3 chars 1 lines +# Back Porch 3.555 us 0.626 ms +# 16 chars 22 lines +# Active Time 22.222 us 17.067 ms +# 100 chars 600 lines +# Blank Time 6.222 us 0.711 ms +# 28 chars 25 lines +# Polarity positive positive +# + +mode "800x600-56" + # D: 36.00 MHz, H: 35.156 kHz, V: 56.25 Hz + geometry 800 600 800 600 8 + timings 27778 128 24 22 1 72 2 + hsync high + vsync high +endmode + +# +# 800x600, 60 Hz, Non-Interlaced (40.00 MHz dotclock) +# +# Horizontal Vertical +# Resolution 800 600 +# Scan Frequency 37.879 kHz 60.32 Hz +# Sync Width 3.200 us 0.106 ms +# 16 chars 4 lines +# Front Porch 1.000 us 0.026 ms +# 5 chars 1 lines +# Back Porch 2.200 us 0.607 ms +# 11 chars 23 lines +# Active Time 20.000 us 15.840 ms +# 100 chars 600 lines +# Blank Time 6.400 us 0.739 ms +# 32 chars 28 lines +# Polarity positive positive +# + +mode "800x600-60" + # D: 40.00 MHz, H: 37.879 kHz, V: 60.32 Hz + geometry 800 600 800 600 8 + timings 25000 88 40 23 1 128 4 + hsync high + vsync high +endmode + +# +# 800x600, 70 Hz, Non-Interlaced (44.90 MHz dotclock) +# +# Horizontal Vertical +# Resolution 800 600 +# Scan Frequency 44.544 kHz 70.04 Hz +# Sync Width 3.207 us 0.269 ms +# 18 chars 12 lines +# Front Porch 0.535 us 0.202 ms +# 3 chars 9 lines +# Back Porch 0.891 us 0.337 ms +# 5 chars 15 lines +# Active Time 17.817 us 13.470 ms +# 100 chars 600 lines +# Blank Time 4.633 us 0.808 ms +# 26 chars 36 lines +# Polarity positive negative +# + +mode "800x600-70" + # D: 44.90 MHz, H: 44.544 kHz, V: 70.04 Hz + geometry 800 600 800 600 8 + timings 22272 40 24 15 9 144 12 + hsync high +endmode + +# +# 800x600, 72 Hz, Non-Interlaced (50.00 MHz dotclock) +# +# Horizontal Vertical +# Resolution 800 600 +# Scan Frequency 48.090 kHz 72.19 Hz +# Sync Width 2.400 us 0.125 ms +# 15 chars 6 lines +# Front Porch 1.120 us 0.769 ms +# 7 chars 37 lines +# Back Porch 1.280 us 0.478 ms +# 8 chars 23 lines +# Active Time 16.000 us 12.477 ms +# 100 chars 600 lines +# Blank Time 4.800 us 1.372 ms +# 30 chars 66 lines +# Polarity positive positive +# + +mode "800x600-72" + # D: 50.00 MHz, H: 48.090 kHz, V: 72.19 Hz + geometry 800 600 800 600 8 + timings 20000 64 56 23 37 120 6 + hsync high + vsync high +endmode + +# +# 800x600, 75 Hz, Non-Interlaced (49.50 MHz dotclock) +# +# Horizontal Vertical +# Resolution 800 600 +# Scan Frequency 46.875 kHz 75.00 Hz +# Sync Width 1.616 us 0.064 ms +# 10 chars 3 lines +# Front Porch 0.323 us 0.021 ms +# 2 chars 1 lines +# Back Porch 3.232 us 0.448 ms +# 20 chars 21 lines +# Active Time 16.162 us 12.800 ms +# 100 chars 600 lines +# Blank Time 5.172 us 0.533 ms +# 32 chars 25 lines +# Polarity positive positive +# + +mode "800x600-75" + # D: 49.50 MHz, H: 46.875 kHz, V: 75.00 Hz + geometry 800 600 800 600 8 + timings 20203 160 16 21 1 80 3 + hsync high + vsync high +endmode + +# +# 800x600, 90 Hz, Non-Interlaced (56.64 MHz dotclock) +# +# Horizontal Vertical +# Resolution 800 600 +# Scan Frequency 57.097 kHz 89.92 Hz +# Sync Width 1.130 us 0.193 ms +# 8 chars 11 lines +# Front Porch 0.071 us 0.140 ms +# 1 chars 8 lines +# Back Porch 2.189 us 0.280 ms +# 15 chars 16 lines +# Active Time 14.124 us 10.508 ms +# 100 chars 600 lines +# Blank Time 3.390 us 0.613 ms +# 24 chars 35 lines +# Polarity positive positive +# + +mode "800x600-90" + # D: 56.64 MHz, H: 57.097 kHz, V: 89.92 Hz + geometry 800 600 800 600 8 + timings 17656 120 8 16 8 64 11 + hsync high + vsync high +endmode + +# +# 800x600, 100 Hz, Non-Interlaced (67.50 MHz dotclock) +# +# Horizontal Vertical +# Resolution 800 600 +# Scan Frequency 62.500 kHz 100.00 Hz +# Sync Width 0.948 us 0.064 ms +# 8 chars 4 lines +# Front Porch 0.000 us 0.112 ms +# 0 chars 7 lines +# Back Porch 3.200 us 0.224 ms +# 27 chars 14 lines +# Active Time 11.852 us 9.600 ms +# 100 chars 600 lines +# Blank Time 4.148 us 0.400 ms +# 35 chars 25 lines +# Polarity positive positive +# + +mode "800x600-100" + # D: 67.50 MHz, H: 62.500 kHz, V: 100.00 Hz + geometry 800 600 800 600 8 + timings 14815 216 0 14 7 64 4 + hsync high + vsync high +endmode + +# +# 1024x768, 43 Hz, Interlaced (44.90 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1024 768 +# Scan Frequency 35.522 kHz 86.96 Hz +# Sync Width 3.920 us 0.113 ms +# 22 chars 8 lines +# Front Porch 0.178 us 0.014 ms +# 1 chars 1 lines +# Back Porch 1.247 us 0.563 ms +# 7 chars 40 lines +# Active Time 22.806 us 10.810 ms +# 128 chars 768 lines +# Blank Time 5.345 us 0.690 ms +# 30 chars 49 lines +# Polarity positive positive +# + +mode "1024x768-43-lace" + # D: 44.90 MHz, H: 35.522 kHz, V: 86.96 Hz + geometry 1024 768 1024 768 8 + timings 22272 56 8 40 1 176 8 + laced true + hsync high + vsync high +endmode + +# +# 1024x768, 60 Hz, Non-Interlaced (65.00 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1024 768 +# Scan Frequency 48.363 kHz 60.00 Hz +# Sync Width 2.092 us 0.124 ms +# 17 chars 6 lines +# Front Porch 0.369 us 0.062 ms +# 3 chars 3 lines +# Back Porch 2.462 us 0.601 ms +# 20 chars 29 lines +# Active Time 15.754 us 15.880 ms +# 128 chars 768 lines +# Blank Time 4.923 us 0.786 ms +# 40 chars 38 lines +# Polarity negative negative +# + +mode "1024x768-60" + # D: 65.00 MHz, H: 48.363 kHz, V: 60.00 Hz + geometry 1024 768 1024 768 8 + timings 15385 160 24 29 3 136 6 +endmode + +# +# 1024x768, 70 Hz, Non-Interlaced (75.00 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1024 768 +# Scan Frequency 56.476 kHz 70.07 Hz +# Sync Width 1.813 us 0.106 ms +# 17 chars 6 lines +# Front Porch 0.320 us 0.053 ms +# 3 chars 3 lines +# Back Porch 1.921 us 0.514 ms +# 18 chars 29 lines +# Active Time 13.653 us 13.599 ms +# 128 chars 768 lines +# Blank Time 4.053 us 0.673 ms +# 38 chars 38 lines +# Polarity negative negative +# + +mode "1024x768-70" + # D: 75.00 MHz, H: 56.476 kHz, V: 70.07 Hz + geometry 1024 768 1024 768 8 + timings 13334 144 24 29 3 136 6 +endmode + +# +# 1024x768, 72 Hz, Non-Interlaced (75.00 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1024 768 +# Scan Frequency 58.230 kHz 72.245 Hz +# Sync Width 1.813 us 0.103 ms +# 17 chars 6 lines +# Front Porch 0.320 us 0.052 ms +# 3 chars 3 lines +# Back Porch 1.387 us 0.498 ms +# 13 chars 29 lines +# Active Time 13.653 us 13.189 ms +# 128 chars 768 lines +# Blank Time 3.520 us 0.653 ms +# 33 chars 38 lines +# Polarity negative negative +# + +mode "1024x768-72" + # D: 75.00 MHz, H: 58.230 kHz, V: 72.245 Hz + geometry 1024 768 1024 768 8 + timings 13334 104 24 29 3 136 6 +endmode + +# +# 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1024 768 +# Scan Frequency 60.023 kHz 75.03 Hz +# Sync Width 1.219 us 0.050 ms +# 12 chars 3 lines +# Front Porch 0.203 us 0.017 ms +# 2 chars 1 lines +# Back Porch 2.235 us 0.466 ms +# 22 chars 28 lines +# Active Time 13.003 us 12.795 ms +# 128 chars 768 lines +# Blank Time 3.657 us 0.533 ms +# 36 chars 32 lines +# Polarity positive positive +# + +mode "1024x768-75" + # D: 78.75 MHz, H: 60.023 kHz, V: 75.03 Hz + geometry 1024 768 1024 768 8 + timings 12699 176 16 28 1 96 3 + hsync high + vsync high +endmode + +# +# 1024x768, 90 Hz, Non-Interlaced (100.0 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1024 768 +# Scan Frequency 76.220 kHz 90.20 Hz +# Sync Width 0.960 us 0.197 ms +# 12 chars 15 lines +# Front Porch 0.000 us 0.276 ms +# 0 chars 21 lines +# Back Porch 1.920 us 0.537 ms +# 24 chars 41 lines +# Active Time 10.240 us 10.076 ms +# 128 chars 768 lines +# Blank Time 2.880 us 1.010 ms +# 36 chars 77 lines +# Polarity negative negative +# + +mode "1024x768-90" + # D: 100.0 MHz, H: 76.220 kHz, V: 90.20 Hz + geometry 1024 768 1024 768 8 + timings 10000 192 0 41 21 96 15 +endmode + +# +# 1024x768, 100 Hz, Non-Interlaced (110.0 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1024 768 +# Scan Frequency 79.023 kHz 99.78 Hz +# Sync Width 0.800 us 0.101 ms +# 11 chars 8 lines +# Front Porch 0.000 us 0.000 ms +# 0 chars 0 lines +# Back Porch 2.545 us 0.202 ms +# 35 chars 16 lines +# Active Time 9.309 us 9.719 ms +# 128 chars 768 lines +# Blank Time 3.345 us 0.304 ms +# 46 chars 24 lines +# Polarity negative negative +# + +mode "1024x768-100" + # D: 110.0 MHz, H: 79.023 kHz, V: 99.78 Hz + geometry 1024 768 1024 768 8 + timings 9091 280 0 16 0 88 8 +endmode + +# +# 1152x864, 43 Hz, Interlaced (65.0 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1152 864 +# Scan Frequency 45.904 kHz 87.02 Hz +# Sync Width 1.969 us 0.098 ms +# 16 chars 9 lines +# Front Porch 1.062 us 0.850 ms +# 9 chars 78 lines +# Back Porch 1.031 us 1.133 ms +# 8 chars 104 lines +# Active Time 17.723 us 9.411 ms +# 144 chars 864 lines +# Blank Time 4.062 us 2.080 ms +# 33 chars 191 lines +# Polarity positive positive +# + +mode "1152x864-43-lace" + # D: 65.0 MHz, H: 45.904 kHz, V: 87.02 Hz + geometry 1152 864 1152 864 8 + timings 15385 64 72 104 78 128 9 + laced true + hsync high + vsync high +endmode + +# +# 1152x864, 47 Hz, Interlaced (65.0 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1152 864 +# Scan Frequency 44.890 kHz 94.80 Hz +# Sync Width 1.969 us 0.100 ms +# 16 chars 9 lines +# Front Porch 1.415 us 0.334 ms +# 11 chars 30 lines +# Back Porch 1.170 us 0.490 ms +# 10 chars 44 lines +# Active Time 17.723 us 9.624 ms +# 144 chars 864 lines +# Blank Time 4.554 us 0.924 ms +# 37 chars 83 lines +# Polarity positive positive +# + +mode "1152x864-47-lace" + # D: 65.0 MHz, H: 44.890 kHz, V: 94.80 Hz + geometry 1152 864 1152 864 8 + timings 15385 80 88 44 30 128 9 + laced true + hsync high + vsync high +endmode + +# +# 1152x864, 60 Hz, Non-Interlaced (80.0 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1152 864 +# Scan Frequency 54.945 kHz 59.98 Hz +# Sync Width 1.400 us 0.091 ms +# 14 chars 5 lines +# Front Porch 0.800 us 0.109 ms +# 8 chars 6 lines +# Back Porch 1.600 us 0.746 ms +# 16 chars 41 lines +# Active Time 14.400 us 15.725 ms +# 144 chars 864 lines +# Blank Time 3.800 us 0.946 ms +# 38 chars 52 lines +# Polarity positive positive +# + +mode "1152x864-60" + # D: 80.0 MHz, H: 54.945 kHz, V: 59.98 Hz + geometry 1152 864 1152 864 8 + timings 12500 128 64 41 6 112 5 + hsync high + vsync high +endmode + +# +# 1152x864, 70 Hz, Non-Interlaced (100.0 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1152 864 +# Scan Frequency 66.138 kHz 69.99 Hz +# Sync Width 1.520 us 0.166 ms +# 19 chars 11 lines +# Front Porch 0.390 us 0.197 ms +# 5 chars 13 lines +# Back Porch 1.690 us 0.862 ms +# 21 chars 57 lines +# Active Time 11.520 us 13.064 ms +# 144 chars 864 lines +# Blank Time 3.600 us 1.225 ms +# 45 chars 81 lines +# Polarity positive positive +# + +mode "1152x864-70" + # D: 100.0 MHz, H: 66.138 kHz, V: 69.99 Hz + geometry 1152 864 1152 864 8 + timings 10000 168 40 57 13 152 11 + hsync high + vsync high +endmode + +# +# 1152x864, 75 Hz, Non-Interlaced (110.0 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1152 864 +# Scan Frequency 75.137 kHz 74.99 Hz +# Sync Width 1.309 us 0.106 ms +# 18 chars 8 lines +# Front Porch 0.245 us 0.599 ms +# 3 chars 45 lines +# Back Porch 1.282 us 1.132 ms +# 18 chars 85 lines +# Active Time 10.473 us 11.499 ms +# 144 chars 864 lines +# Blank Time 2.836 us 1.837 ms +# 39 chars 138 lines +# Polarity positive positive +# + +mode "1152x864-75" + # D: 110.0 MHz, H: 75.137 kHz, V: 74.99 Hz + geometry 1152 864 1152 864 8 + timings 9091 144 24 85 45 144 8 + hsync high + vsync high +endmode + +# +# 1152x864, 80 Hz, Non-Interlaced (110.0 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1152 864 +# Scan Frequency 76.389 kHz 79.74 Hz +# Sync Width 1.018 us 0.092 ms +# 14 chars 7 lines +# Front Porch 0.127 us 0.393 ms +# 2 chars 30 lines +# Back Porch 1.473 us 0.747 ms +# 20 chars 57 lines +# Active Time 10.473 us 11.311 ms +# 144 chars 864 lines +# Blank Time 2.618 us 1.231 ms +# 36 chars 94 lines +# Polarity positive positive +# + +mode "1152x864-80" + # D: 110.0 MHz, H: 76.389 kHz, V: 79.74 Hz + geometry 1152 864 1152 864 8 + timings 9091 160 16 57 30 112 7 + hsync high + vsync high +endmode + +# +# 1280x960, 75 Hz, Non-Interlaced (126.00 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1280 960 +# Scan Frequency 74.788 kHz 74.788 Hz +# Sync Width 1.018 us 0.092 ms +# 14 chars 7 lines +# Front Porch 0.127 us 0.393 ms +# 2 chars 30 lines +# Back Porch 1.473 us 0.747 ms +# 20 chars 57 lines +# Active Time 10.473 us 11.311 ms +# 144 chars 864 lines +# Blank Time 2.618 us 1.231 ms +# 36 chars 94 lines +# Polarity positive positive +# + +mode "1280x960-75-8" + # D: 125.644 MHz, H: 74.788 kHz, V: 74.788 Hz + geometry 1280 960 1280 960 8 + timings 7959 224 32 36 1 144 3 +endmode + +mode "1280x960-75" + # D: 125.644 MHz, H: 74.788 kHz, V: 74.788 Hz + geometry 1280 960 1280 960 16 + timings 7959 224 32 36 1 144 3 +endmode + +mode "1280x960-75-32" + # D: 125.644 MHz, H: 74.788 kHz, V: 74.788 Hz + geometry 1280 960 1280 960 32 + timings 7959 224 32 36 1 144 3 +endmode + + +# +# 1280x1024, 43 Hz, Interlaced (80.00 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1024 1024 +# Scan Frequency 50.000 kHz 87.03 Hz +# Sync Width 1.000 us 0.100 ms +# 10 chars 10 lines +# Front Porch 1.000 us 0.500 ms +# 10 chars 50 lines +# Back Porch 2.000 us 0.650 ms +# 20 chars 65 lines +# Active Time 16.000 us 10.240 ms +# 160 chars 1024 lines +# Blank Time 4.000 us 1.250 ms +# 40 chars 125 lines +# Polarity positive positive +# + +mode "1280x1024-43-lace" + # D: 80.00 MHz, H: 50.000 kHz, V: 87.03 Hz + geometry 1024 1024 1024 1024 8 + timings 12500 160 80 65 50 80 10 + laced true + hsync high + vsync high +endmode + +# +# 1280x1024, 47 Hz, Interlaced (80.00 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1280 1024 +# Scan Frequency 50.000 kHz 94.97 Hz +# Sync Width 1.000 us 0.100 ms +# 10 chars 10 lines +# Front Porch 1.000 us 0.010 ms +# 10 chars 1 lines +# Back Porch 2.000 us 0.180 ms +# 20 chars 18 lines +# Active Time 16.000 us 10.240 ms +# 160 chars 1024 lines +# Blank Time 4.000 us 0.290 ms +# 40 chars 29 lines +# Polarity positive positive +# + +mode "1280x1024-47-lace" + # D: 80.00 MHz, H: 50.000 kHz, V: 94.97 Hz + geometry 1280 1024 1280 1024 8 + timings 12500 160 80 18 1 80 10 + laced true + hsync high + vsync high +endmode + +# +# 1280x1024, 60 Hz, Non-Interlaced (108.00 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1280 1024 +# Scan Frequency 63.981 kHz 60.02 Hz +# Sync Width 1.037 us 0.047 ms +# 14 chars 3 lines +# Front Porch 0.444 us 0.015 ms +# 6 chars 1 lines +# Back Porch 2.297 us 0.594 ms +# 31 chars 38 lines +# Active Time 11.852 us 16.005 ms +# 160 chars 1024 lines +# Blank Time 3.778 us 0.656 ms +# 51 chars 42 lines +# Polarity positive positive +# + +mode "1280x1024-60" + # D: 108.00 MHz, H: 63.981 kHz, V: 60.02 Hz + geometry 1280 1024 1280 1024 8 + timings 9260 248 48 38 1 112 3 + hsync high + vsync high +endmode + +# +# 1280x1024, 70 Hz, Non-Interlaced (126.00 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1280 1024 +# Scan Frequency 74.645 kHz 70.02 Hz +# Sync Width 0.889 us 0.067 ms +# 14 chars 5 lines +# Front Porch 0.635 us 0.013 ms +# 10 chars 1 lines +# Back Porch 1.714 us 0.483 ms +# 27 chars 36 lines +# Active Time 10.159 us 13.718 ms +# 160 chars 1024 lines +# Blank Time 3.238 us 0.563 ms +# 51 chars 42 lines +# Polarity positive positive +# + +mode "1280x1024-70" + # D: 126.00 MHz, H: 74.645 kHz, V: 70.02 Hz + geometry 1280 1024 1280 1024 8 + timings 7937 216 80 36 1 112 5 + hsync high + vsync high +endmode + +# +# 1280x1024, 74 Hz, Non-Interlaced (135.00 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1280 1024 +# Scan Frequency 78.855 kHz 74.11 Hz +# Sync Width 1.067 us 0.380 ms +# 18 chars 30 lines +# Front Porch 0.237 us 0.000 ms +# 4 chars 0 lines +# Back Porch 1.896 us 0.127 ms +# 32 chars 10 lines +# Active Time 9.481 us 12.986 ms +# 160 chars 1024 lines +# Blank Time 3.200 us 0.507 ms +# 54 chars 40 lines +# Polarity positive positive +# + +mode "1280x1024-74" + # D: 135.00 MHz, H: 78.855 kHz, V: 74.11 Hz + geometry 1280 1024 1280 1024 8 + timings 7408 256 32 10 0 144 30 + hsync high + vsync high +endmode + +# +# 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1280 1024 +# Scan Frequency 79.976 kHz 75.02 Hz +# Sync Width 1.067 us 0.038 ms +# 18 chars 3 lines +# Front Porch 0.119 us 0.012 ms +# 2 chars 1 lines +# Back Porch 1.837 us 0.475 ms +# 31 chars 38 lines +# Active Time 9.481 us 12.804 ms +# 160 chars 1024 lines +# Blank Time 3.022 us 0.525 ms +# 51 chars 42 lines +# Polarity positive positive +# + +mode "1280x1024-75" + # D: 134.880 MHz, H: 79.905 kHz, V: 74.958 Hz + geometry 1280 1024 1280 3264 8 + timings 7414 232 64 38 1 112 3 + hsync high + vsync high +endmode + +# +# 1600x1200, 60 Hz, Non-Interlaced (156.00 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1600 1200 +# Scan Frequency 76.200 kHz 60.00 Hz +# Sync Width 1.026 us 0.105 ms +# 20 chars 8 lines +# Front Porch 0.205 us 0.131 ms +# 4 chars 10 lines +# Back Porch 1.636 us 0.682 ms +# 32 chars 52 lines +# Active Time 10.256 us 15.748 ms +# 200 chars 1200 lines +# Blank Time 2.872 us 0.866 ms +# 56 chars 66 lines +# Polarity negative negative +# + +mode "1600x1200-60" + # D: 156.00 MHz, H: 76.200 kHz, V: 60.00 Hz + geometry 1600 1200 1600 1200 8 + timings 6411 256 32 52 10 160 8 +endmode + +# +# 1600x1200, 66 Hz, Non-Interlaced (172.00 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1600 1200 +# Scan Frequency 82.700 kHz 66.00 Hz +# Sync Width 0.791 us 0.036 ms +# 17 chars 3 lines +# Front Porch 0.233 us 0.036 ms +# 5 chars 3 lines +# Back Porch 1.767 us 0.567 ms +# 38 chars 47 lines +# Active Time 9.302 us 14.512 ms +# 200 chars 1200 lines +# Blank Time 2.791 us 0.532 ms +# 60 chars 44 lines +# Polarity negative negative +# + +mode "1600x1200-66" + # D: 172.00 MHz, H: 82.700 kHz, V: 66.00 Hz + geometry 1600 1200 1600 1200 8 + timings 5814 304 40 47 3 136 3 +endmode + +# +# 1600x1200, 76 Hz, Non-Interlaced (198.00 MHz dotclock) +# +# Horizontal Vertical +# Resolution 1600 1200 +# Scan Frequency 95.200 kHz 76.00 Hz +# Sync Width 0.687 us 0.052 ms +# 17 chars 5 lines +# Front Porch 0.202 us 0.032 ms +# 5 chars 3 lines +# Back Porch 1.535 us 0.441 ms +# 38 chars 42 lines +# Active Time 8.081 us 12.606 ms +# 200 chars 1200 lines +# Blank Time 2.424 us 0.525 ms +# 60 chars 50 lines +# Polarity negative negative +# + +mode "1600x1200-76" + # D: 198.00 MHz, H: 95.200 kHz, V: 76.00 Hz + geometry 1600 1200 1600 1200 8 + timings 5051 304 40 42 3 136 5 +endmode + diff --git a/fonts/conf.avail/20-unhint-small-dejavu-lgc-sans-mono.conf b/fonts/conf.avail/20-unhint-small-dejavu-lgc-sans-mono.conf new file mode 100644 index 00000000..9036e83e --- /dev/null +++ b/fonts/conf.avail/20-unhint-small-dejavu-lgc-sans-mono.conf @@ -0,0 +1,26 @@ + + + + + + + DejaVu LGC Sans Mono + + + 7.5 + + + false + + + diff --git a/fonts/conf.avail/20-unhint-small-dejavu-lgc-sans.conf b/fonts/conf.avail/20-unhint-small-dejavu-lgc-sans.conf new file mode 100644 index 00000000..35abebd5 --- /dev/null +++ b/fonts/conf.avail/20-unhint-small-dejavu-lgc-sans.conf @@ -0,0 +1,26 @@ + + + + + + + DejaVu LGC Sans + + + 7.5 + + + false + + + diff --git a/fonts/conf.avail/20-unhint-small-dejavu-lgc-serif.conf b/fonts/conf.avail/20-unhint-small-dejavu-lgc-serif.conf new file mode 100644 index 00000000..54486e87 --- /dev/null +++ b/fonts/conf.avail/20-unhint-small-dejavu-lgc-serif.conf @@ -0,0 +1,26 @@ + + + + + + + DejaVu LGC Serif + + + 7.5 + + + false + + + diff --git a/fonts/conf.avail/20-unhint-small-dejavu-sans-mono.conf b/fonts/conf.avail/20-unhint-small-dejavu-sans-mono.conf new file mode 100644 index 00000000..102dbcc4 --- /dev/null +++ b/fonts/conf.avail/20-unhint-small-dejavu-sans-mono.conf @@ -0,0 +1,26 @@ + + + + + + + DejaVu Sans Mono + + + 7.5 + + + false + + + diff --git a/fonts/conf.avail/20-unhint-small-dejavu-sans.conf b/fonts/conf.avail/20-unhint-small-dejavu-sans.conf new file mode 100644 index 00000000..ee69996d --- /dev/null +++ b/fonts/conf.avail/20-unhint-small-dejavu-sans.conf @@ -0,0 +1,26 @@ + + + + + + + DejaVu Sans + + + 7.5 + + + false + + + diff --git a/fonts/conf.avail/20-unhint-small-dejavu-serif.conf b/fonts/conf.avail/20-unhint-small-dejavu-serif.conf new file mode 100644 index 00000000..cf6caa2c --- /dev/null +++ b/fonts/conf.avail/20-unhint-small-dejavu-serif.conf @@ -0,0 +1,26 @@ + + + + + + + DejaVu Serif + + + 7.5 + + + false + + + diff --git a/fonts/conf.avail/30-droid-noto-mono.conf b/fonts/conf.avail/30-droid-noto-mono.conf new file mode 100644 index 00000000..690a67ec --- /dev/null +++ b/fonts/conf.avail/30-droid-noto-mono.conf @@ -0,0 +1,10 @@ + + + + + Droid Mono + + Noto Mono + + + diff --git a/fonts/conf.avail/57-dejavu-sans-mono.conf b/fonts/conf.avail/57-dejavu-sans-mono.conf new file mode 100644 index 00000000..cc42561e --- /dev/null +++ b/fonts/conf.avail/57-dejavu-sans-mono.conf @@ -0,0 +1,62 @@ + + + + + + + Bepa Mono + + DejaVu Sans Mono + + + + Bitstream Prima Sans Mono + + DejaVu Sans Mono + + + + Bitstream Vera Sans Mono + + DejaVu Sans Mono + + + + DejaVu LGC Sans Mono + + DejaVu Sans Mono + + + + Olwen Sans Mono + + DejaVu Sans Mono + + + + SUSE Sans Mono + + DejaVu Sans Mono + + + + + DejaVu Sans Mono + + monospace + + + + + monospace + + DejaVu Sans Mono + + + diff --git a/fonts/conf.avail/57-dejavu-sans.conf b/fonts/conf.avail/57-dejavu-sans.conf new file mode 100644 index 00000000..565cab5f --- /dev/null +++ b/fonts/conf.avail/57-dejavu-sans.conf @@ -0,0 +1,87 @@ + + + + + + + Arev Sans + + DejaVu Sans + + + + Bepa + + DejaVu Sans + + + + Bitstream Prima Sans + + DejaVu Sans + + + + Bitstream Vera Sans + + DejaVu Sans + + + + DejaVu LGC Sans + + DejaVu Sans + + + + Hunky Sans + + DejaVu Sans + + + + Olwen Sans + + DejaVu Sans + + + + SUSE Sans + + DejaVu Sans + + + + Verajja + + DejaVu Sans + + + + + VerajjaPDA + + DejaVu Sans + + + + + DejaVu Sans + + sans-serif + + + + + sans-serif + + DejaVu Sans + + + diff --git a/fonts/conf.avail/57-dejavu-serif.conf b/fonts/conf.avail/57-dejavu-serif.conf new file mode 100644 index 00000000..a922e9b2 --- /dev/null +++ b/fonts/conf.avail/57-dejavu-serif.conf @@ -0,0 +1,69 @@ + + + + + + + Bitstream Prima Serif + + DejaVu Serif + + + + Bitstream Vera Serif + + DejaVu Serif + + + + DejaVu LGC Serif + + DejaVu Serif + + + + Hunky Serif + + DejaVu Serif + + + + Olwen Serif + + DejaVu Serif + + + + SUSE Serif + + DejaVu Serif + + + + + Verajja Serif + + DejaVu Serif + + + + + DejaVu Serif + + serif + + + + + serif + + DejaVu Serif + + + diff --git a/fonts/conf.avail/58-dejavu-lgc-sans-mono.conf b/fonts/conf.avail/58-dejavu-lgc-sans-mono.conf new file mode 100644 index 00000000..9d0a8b26 --- /dev/null +++ b/fonts/conf.avail/58-dejavu-lgc-sans-mono.conf @@ -0,0 +1,62 @@ + + + + + + + Bepa Mono + + DejaVu LGC Sans Mono + + + + Bitstream Prima Sans Mono + + DejaVu LGC Sans Mono + + + + Bitstream Vera Sans Mono + + DejaVu LGC Sans Mono + + + + DejaVu Sans Mono + + DejaVu LGC Sans Mono + + + + Olwen Sans Mono + + DejaVu LGC Sans Mono + + + + SUSE Sans Mono + + DejaVu LGC Sans Mono + + + + + DejaVu LGC Sans Mono + + monospace + + + + + monospace + + DejaVu LGC Sans Mono + + + diff --git a/fonts/conf.avail/58-dejavu-lgc-sans.conf b/fonts/conf.avail/58-dejavu-lgc-sans.conf new file mode 100644 index 00000000..decd2a31 --- /dev/null +++ b/fonts/conf.avail/58-dejavu-lgc-sans.conf @@ -0,0 +1,87 @@ + + + + + + + Arev Sans + + DejaVu LGC Sans + + + + Bepa + + DejaVu LGC Sans + + + + Bitstream Prima Sans + + DejaVu LGC Sans + + + + Bitstream Vera Sans + + DejaVu LGC Sans + + + + DejaVu Sans + + DejaVu LGC Sans + + + + Hunky Sans + + DejaVu LGC Sans + + + + Olwen Sans + + DejaVu LGC Sans + + + + SUSE Sans + + DejaVu LGC Sans + + + + Verajja + + DejaVu LGC Sans + + + + + VerajjaPDA + + DejaVu LGC Sans + + + + + DejaVu LGC Sans + + sans-serif + + + + + sans-serif + + DejaVu LGC Sans + + + diff --git a/fonts/conf.avail/58-dejavu-lgc-serif.conf b/fonts/conf.avail/58-dejavu-lgc-serif.conf new file mode 100644 index 00000000..01045e84 --- /dev/null +++ b/fonts/conf.avail/58-dejavu-lgc-serif.conf @@ -0,0 +1,69 @@ + + + + + + + Bitstream Prima Serif + + DejaVu LGC Serif + + + + Bitstream Vera Serif + + DejaVu LGC Serif + + + + DejaVu Serif + + DejaVu LGC Serif + + + + Hunky Serif + + DejaVu LGC Serif + + + + Olwen Serif + + DejaVu LGC Serif + + + + SUSE Serif + + DejaVu LGC Serif + + + + + Verajja Serif + + DejaVu LGC Serif + + + + + DejaVu LGC Serif + + serif + + + + + serif + + DejaVu LGC Serif + + + diff --git a/fonts/conf.avail/65-droid-sans-fallback.conf b/fonts/conf.avail/65-droid-sans-fallback.conf new file mode 100644 index 00000000..045808b4 --- /dev/null +++ b/fonts/conf.avail/65-droid-sans-fallback.conf @@ -0,0 +1,10 @@ + + + + + sans-serif + + Droid Sans Fallback + + + diff --git a/fonts/conf.d/10-hinting-slight.conf b/fonts/conf.d/10-hinting-slight.conf new file mode 120000 index 00000000..99241c8a --- /dev/null +++ b/fonts/conf.d/10-hinting-slight.conf @@ -0,0 +1 @@ +/usr/share/fontconfig/conf.avail/10-hinting-slight.conf \ No newline at end of file diff --git a/fonts/conf.d/10-scale-bitmap-fonts.conf b/fonts/conf.d/10-scale-bitmap-fonts.conf new file mode 120000 index 00000000..7e506117 --- /dev/null +++ b/fonts/conf.d/10-scale-bitmap-fonts.conf @@ -0,0 +1 @@ +/usr/share/fontconfig/conf.avail/10-scale-bitmap-fonts.conf \ No newline at end of file diff --git a/fonts/conf.d/11-lcdfilter-default.conf b/fonts/conf.d/11-lcdfilter-default.conf new file mode 120000 index 00000000..fbc10b03 --- /dev/null +++ b/fonts/conf.d/11-lcdfilter-default.conf @@ -0,0 +1 @@ +/usr/share/fontconfig/conf.avail/11-lcdfilter-default.conf \ No newline at end of file diff --git a/fonts/conf.d/20-unhint-small-dejavu-lgc-sans-mono.conf b/fonts/conf.d/20-unhint-small-dejavu-lgc-sans-mono.conf new file mode 120000 index 00000000..068e8ea1 --- /dev/null +++ b/fonts/conf.d/20-unhint-small-dejavu-lgc-sans-mono.conf @@ -0,0 +1 @@ +../conf.avail/20-unhint-small-dejavu-lgc-sans-mono.conf \ No newline at end of file diff --git a/fonts/conf.d/20-unhint-small-dejavu-lgc-sans.conf b/fonts/conf.d/20-unhint-small-dejavu-lgc-sans.conf new file mode 120000 index 00000000..4c767100 --- /dev/null +++ b/fonts/conf.d/20-unhint-small-dejavu-lgc-sans.conf @@ -0,0 +1 @@ +../conf.avail/20-unhint-small-dejavu-lgc-sans.conf \ No newline at end of file diff --git a/fonts/conf.d/20-unhint-small-dejavu-lgc-serif.conf b/fonts/conf.d/20-unhint-small-dejavu-lgc-serif.conf new file mode 120000 index 00000000..1c8a1076 --- /dev/null +++ b/fonts/conf.d/20-unhint-small-dejavu-lgc-serif.conf @@ -0,0 +1 @@ +../conf.avail/20-unhint-small-dejavu-lgc-serif.conf \ No newline at end of file diff --git a/fonts/conf.d/20-unhint-small-dejavu-sans-mono.conf b/fonts/conf.d/20-unhint-small-dejavu-sans-mono.conf new file mode 120000 index 00000000..e075245d --- /dev/null +++ b/fonts/conf.d/20-unhint-small-dejavu-sans-mono.conf @@ -0,0 +1 @@ +../conf.avail/20-unhint-small-dejavu-sans-mono.conf \ No newline at end of file diff --git a/fonts/conf.d/20-unhint-small-dejavu-sans.conf b/fonts/conf.d/20-unhint-small-dejavu-sans.conf new file mode 120000 index 00000000..61320a1e --- /dev/null +++ b/fonts/conf.d/20-unhint-small-dejavu-sans.conf @@ -0,0 +1 @@ +../conf.avail/20-unhint-small-dejavu-sans.conf \ No newline at end of file diff --git a/fonts/conf.d/20-unhint-small-dejavu-serif.conf b/fonts/conf.d/20-unhint-small-dejavu-serif.conf new file mode 120000 index 00000000..7abd5e1e --- /dev/null +++ b/fonts/conf.d/20-unhint-small-dejavu-serif.conf @@ -0,0 +1 @@ +../conf.avail/20-unhint-small-dejavu-serif.conf \ No newline at end of file diff --git a/fonts/conf.d/20-unhint-small-vera.conf b/fonts/conf.d/20-unhint-small-vera.conf new file mode 120000 index 00000000..cde2cced --- /dev/null +++ b/fonts/conf.d/20-unhint-small-vera.conf @@ -0,0 +1 @@ +/usr/share/fontconfig/conf.avail/20-unhint-small-vera.conf \ No newline at end of file diff --git a/fonts/conf.d/30-metric-aliases.conf b/fonts/conf.d/30-metric-aliases.conf new file mode 120000 index 00000000..1880d961 --- /dev/null +++ b/fonts/conf.d/30-metric-aliases.conf @@ -0,0 +1 @@ +/usr/share/fontconfig/conf.avail/30-metric-aliases.conf \ No newline at end of file diff --git a/fonts/conf.d/40-nonlatin.conf b/fonts/conf.d/40-nonlatin.conf new file mode 120000 index 00000000..c46eb4e9 --- /dev/null +++ b/fonts/conf.d/40-nonlatin.conf @@ -0,0 +1 @@ +/usr/share/fontconfig/conf.avail/40-nonlatin.conf \ No newline at end of file diff --git a/fonts/conf.d/45-generic.conf b/fonts/conf.d/45-generic.conf new file mode 120000 index 00000000..da483b3a --- /dev/null +++ b/fonts/conf.d/45-generic.conf @@ -0,0 +1 @@ +/usr/share/fontconfig/conf.avail/45-generic.conf \ No newline at end of file diff --git a/fonts/conf.d/45-latin.conf b/fonts/conf.d/45-latin.conf new file mode 120000 index 00000000..cb1c08fa --- /dev/null +++ b/fonts/conf.d/45-latin.conf @@ -0,0 +1 @@ +/usr/share/fontconfig/conf.avail/45-latin.conf \ No newline at end of file diff --git a/fonts/conf.d/49-sansserif.conf b/fonts/conf.d/49-sansserif.conf new file mode 120000 index 00000000..26255166 --- /dev/null +++ b/fonts/conf.d/49-sansserif.conf @@ -0,0 +1 @@ +/usr/share/fontconfig/conf.avail/49-sansserif.conf \ No newline at end of file diff --git a/fonts/conf.d/50-user.conf b/fonts/conf.d/50-user.conf new file mode 120000 index 00000000..62f8b144 --- /dev/null +++ b/fonts/conf.d/50-user.conf @@ -0,0 +1 @@ +/usr/share/fontconfig/conf.avail/50-user.conf \ No newline at end of file diff --git a/fonts/conf.d/51-local.conf b/fonts/conf.d/51-local.conf new file mode 120000 index 00000000..39557bdd --- /dev/null +++ b/fonts/conf.d/51-local.conf @@ -0,0 +1 @@ +/usr/share/fontconfig/conf.avail/51-local.conf \ No newline at end of file diff --git a/fonts/conf.d/57-dejavu-sans-mono.conf b/fonts/conf.d/57-dejavu-sans-mono.conf new file mode 120000 index 00000000..c0c1959c --- /dev/null +++ b/fonts/conf.d/57-dejavu-sans-mono.conf @@ -0,0 +1 @@ +../conf.avail/57-dejavu-sans-mono.conf \ No newline at end of file diff --git a/fonts/conf.d/57-dejavu-sans.conf b/fonts/conf.d/57-dejavu-sans.conf new file mode 120000 index 00000000..92a40d61 --- /dev/null +++ b/fonts/conf.d/57-dejavu-sans.conf @@ -0,0 +1 @@ +../conf.avail/57-dejavu-sans.conf \ No newline at end of file diff --git a/fonts/conf.d/57-dejavu-serif.conf b/fonts/conf.d/57-dejavu-serif.conf new file mode 120000 index 00000000..b7e74810 --- /dev/null +++ b/fonts/conf.d/57-dejavu-serif.conf @@ -0,0 +1 @@ +../conf.avail/57-dejavu-serif.conf \ No newline at end of file diff --git a/fonts/conf.d/58-dejavu-lgc-sans-mono.conf b/fonts/conf.d/58-dejavu-lgc-sans-mono.conf new file mode 120000 index 00000000..89ea6b27 --- /dev/null +++ b/fonts/conf.d/58-dejavu-lgc-sans-mono.conf @@ -0,0 +1 @@ +../conf.avail/58-dejavu-lgc-sans-mono.conf \ No newline at end of file diff --git a/fonts/conf.d/58-dejavu-lgc-sans.conf b/fonts/conf.d/58-dejavu-lgc-sans.conf new file mode 120000 index 00000000..ca377e05 --- /dev/null +++ b/fonts/conf.d/58-dejavu-lgc-sans.conf @@ -0,0 +1 @@ +../conf.avail/58-dejavu-lgc-sans.conf \ No newline at end of file diff --git a/fonts/conf.d/58-dejavu-lgc-serif.conf b/fonts/conf.d/58-dejavu-lgc-serif.conf new file mode 120000 index 00000000..603352a7 --- /dev/null +++ b/fonts/conf.d/58-dejavu-lgc-serif.conf @@ -0,0 +1 @@ +../conf.avail/58-dejavu-lgc-serif.conf \ No newline at end of file diff --git a/fonts/conf.d/60-generic.conf b/fonts/conf.d/60-generic.conf new file mode 120000 index 00000000..ff9243f3 --- /dev/null +++ b/fonts/conf.d/60-generic.conf @@ -0,0 +1 @@ +/usr/share/fontconfig/conf.avail/60-generic.conf \ No newline at end of file diff --git a/fonts/conf.d/60-latin.conf b/fonts/conf.d/60-latin.conf new file mode 120000 index 00000000..020a7637 --- /dev/null +++ b/fonts/conf.d/60-latin.conf @@ -0,0 +1 @@ +/usr/share/fontconfig/conf.avail/60-latin.conf \ No newline at end of file diff --git a/fonts/conf.d/65-fonts-persian.conf b/fonts/conf.d/65-fonts-persian.conf new file mode 120000 index 00000000..c5ceafcf --- /dev/null +++ b/fonts/conf.d/65-fonts-persian.conf @@ -0,0 +1 @@ +/usr/share/fontconfig/conf.avail/65-fonts-persian.conf \ No newline at end of file diff --git a/fonts/conf.d/65-nonlatin.conf b/fonts/conf.d/65-nonlatin.conf new file mode 120000 index 00000000..eee5d466 --- /dev/null +++ b/fonts/conf.d/65-nonlatin.conf @@ -0,0 +1 @@ +/usr/share/fontconfig/conf.avail/65-nonlatin.conf \ No newline at end of file diff --git a/fonts/conf.d/69-unifont.conf b/fonts/conf.d/69-unifont.conf new file mode 120000 index 00000000..313ab54f --- /dev/null +++ b/fonts/conf.d/69-unifont.conf @@ -0,0 +1 @@ +/usr/share/fontconfig/conf.avail/69-unifont.conf \ No newline at end of file diff --git a/fonts/conf.d/70-no-bitmaps.conf b/fonts/conf.d/70-no-bitmaps.conf new file mode 120000 index 00000000..dbfc647f --- /dev/null +++ b/fonts/conf.d/70-no-bitmaps.conf @@ -0,0 +1 @@ +/usr/share/fontconfig/conf.avail/70-no-bitmaps.conf \ No newline at end of file diff --git a/fonts/conf.d/80-delicious.conf b/fonts/conf.d/80-delicious.conf new file mode 120000 index 00000000..e2d1d220 --- /dev/null +++ b/fonts/conf.d/80-delicious.conf @@ -0,0 +1 @@ +/usr/share/fontconfig/conf.avail/80-delicious.conf \ No newline at end of file diff --git a/fonts/conf.d/90-synthetic.conf b/fonts/conf.d/90-synthetic.conf new file mode 120000 index 00000000..20e176b3 --- /dev/null +++ b/fonts/conf.d/90-synthetic.conf @@ -0,0 +1 @@ +/usr/share/fontconfig/conf.avail/90-synthetic.conf \ No newline at end of file diff --git a/fonts/conf.d/README b/fonts/conf.d/README new file mode 100644 index 00000000..6a774c5d --- /dev/null +++ b/fonts/conf.d/README @@ -0,0 +1,23 @@ +conf.d/README + +Each file in this directory is a fontconfig configuration file. Fontconfig +scans this directory, loading all files of the form [0-9][0-9]*.conf. +These files are normally installed in /usr/share/fontconfig/conf.avail +and then symlinked here, allowing them to be easily installed and then +enabled/disabled by adjusting the symlinks. + +The files are loaded in numeric order, the structure of the configuration +has led to the following conventions in usage: + + Files begining with: Contain: + + 00 through 09 Font directories + 10 through 19 system rendering defaults (AA, etc) + 20 through 29 font rendering options + 30 through 39 family substitution + 40 through 49 generic identification, map family->generic + 50 through 59 alternate config file loading + 60 through 69 generic aliases, map generic->family + 70 through 79 select font (adjust which fonts are available) + 80 through 89 match target="scan" (modify scanned patterns) + 90 through 99 font synthesis diff --git a/fonts/fonts.conf b/fonts/fonts.conf new file mode 100644 index 00000000..e908e5a0 --- /dev/null +++ b/fonts/fonts.conf @@ -0,0 +1,108 @@ + + + + + + + + + Default configuration file + + + + + +

/usr/share/fonts + /usr/X11R6/lib/X11/fonts /usr/local/share/fonts + fonts + + ~/.fonts + + + + + mono + + + monospace + + + + + + + sans serif + + + sans-serif + + + + + + + sans + + + sans-serif + + + + + + + *.dpkg-tmp + + + + + *.dpkg-new + + + + + conf.d + + + + /var/cache/fontconfig + fontconfig + + ~/.fontconfig + + + + + 30 + + + + diff --git a/fstab b/fstab new file mode 100644 index 00000000..c24aecb3 --- /dev/null +++ b/fstab @@ -0,0 +1,12 @@ +proc /proc proc defaults 0 0 +PARTUUID=6c586e13-01 /boot vfat defaults 0 2 +PARTUUID=6c586e13-02 / ext4 defaults,noatime 0 1 + +# cifs mount +#//192.168.0.40/NetBackup /backup cifs auto,user,defaults,username=gorden,password=$Gentoo12,iocharset=utf8 0 0 +#//192.168.0.40/music /mnt/library/music cifs auto,user,defaults,username=plex,password=#gentoo#,iocharset=utf8 0 0 +#//192.168.0.40/photo /mnt/library/photo cifs auto,user,defaults,username=plex,password=#gentoo#,iocharset=utf8 0 0 +# a swapfile is not a swap partition, no line here +# use dphys-swapfile swap[on|off] for that + +192.168.0.40:/volume1/NetBackup /backup nfs rw,soft,bg,_netdev 0 0 diff --git a/fuse.conf b/fuse.conf new file mode 100644 index 00000000..ae194a07 --- /dev/null +++ b/fuse.conf @@ -0,0 +1,8 @@ +# /etc/fuse.conf - Configuration file for Filesystem in Userspace (FUSE) + +# Set the maximum number of FUSE mounts allowed to non-root users. +# The default is 1000. +#mount_max = 1000 + +# Allow non-root users to specify the allow_other or allow_root mount options. +#user_allow_other diff --git a/gai.conf b/gai.conf new file mode 100644 index 00000000..4616ed00 --- /dev/null +++ b/gai.conf @@ -0,0 +1,65 @@ +# Configuration for getaddrinfo(3). +# +# So far only configuration for the destination address sorting is needed. +# RFC 3484 governs the sorting. But the RFC also says that system +# administrators should be able to overwrite the defaults. This can be +# achieved here. +# +# All lines have an initial identifier specifying the option followed by +# up to two values. Information specified in this file replaces the +# default information. Complete absence of data of one kind causes the +# appropriate default information to be used. The supported commands include: +# +# reload +# If set to yes, each getaddrinfo(3) call will check whether this file +# changed and if necessary reload. This option should not really be +# used. There are possible runtime problems. The default is no. +# +# label +# Add another rule to the RFC 3484 label table. See section 2.1 in +# RFC 3484. The default is: +# +#label ::1/128 0 +#label ::/0 1 +#label 2002::/16 2 +#label ::/96 3 +#label ::ffff:0:0/96 4 +#label fec0::/10 5 +#label fc00::/7 6 +#label 2001:0::/32 7 +# +# This default differs from the tables given in RFC 3484 by handling +# (now obsolete) site-local IPv6 addresses and Unique Local Addresses. +# The reason for this difference is that these addresses are never +# NATed while IPv4 site-local addresses most probably are. Given +# the precedence of IPv6 over IPv4 (see below) on machines having only +# site-local IPv4 and IPv6 addresses a lookup for a global address would +# see the IPv6 be preferred. The result is a long delay because the +# site-local IPv6 addresses cannot be used while the IPv4 address is +# (at least for the foreseeable future) NATed. We also treat Teredo +# tunnels special. +# +# precedence +# Add another rule to the RFC 3484 precedence table. See section 2.1 +# and 10.3 in RFC 3484. The default is: +# +#precedence ::1/128 50 +#precedence ::/0 40 +#precedence 2002::/16 30 +#precedence ::/96 20 +#precedence ::ffff:0:0/96 10 +# +# For sites which prefer IPv4 connections change the last line to +# +#precedence ::ffff:0:0/96 100 + +# +# scopev4 +# Add another rule to the RFC 6724 scope table for IPv4 addresses. +# By default the scope IDs described in section 3.2 in RFC 6724 are +# used. Changing these defaults should hardly ever be necessary. +# The defaults are equivalent to: +# +#scopev4 ::ffff:169.254.0.0/112 2 +#scopev4 ::ffff:127.0.0.0/104 2 +#scopev4 ::ffff:0.0.0.0/96 14 diff --git a/gdb/gdbinit b/gdb/gdbinit new file mode 100644 index 00000000..ccb3b0d4 --- /dev/null +++ b/gdb/gdbinit @@ -0,0 +1 @@ +# System-wide GDB initialization file. diff --git a/ghostscript/cidfmap.d/90gs-cjk-resource-cns1.conf b/ghostscript/cidfmap.d/90gs-cjk-resource-cns1.conf new file mode 100644 index 00000000..6fd3b986 --- /dev/null +++ b/ghostscript/cidfmap.d/90gs-cjk-resource-cns1.conf @@ -0,0 +1,9 @@ +/ZenKai-Medium << /FileType /TrueType /Path (/usr/share/fonts/truetype/arphic/ukai.ttc) /SubfontID 0 /CSI [(CNS1) 4] >> ; +/ShanHeiSun-Light << /FileType /TrueType /Path (/usr/share/fonts/truetype/arphic/uming.ttc) /SubfontID 0 /CSI [(CNS1) 4] >> ; +/MOESung-Regular /ShanHeiSun-Light ; +/MSung-Light /ShanHeiSun-Light ; +/MSung-Medium /ZenKai-Medium ; +/MHei-Medium /ZenKai-Medium ; +/MKai-Medium /ZenKai-Medium ; +/Adobe-CNS1 /ShanHeiSun-Light ; +/Adobe-CNS1-Bold /ZenKai-Medium ; diff --git a/ghostscript/cidfmap.d/90gs-cjk-resource-gb1.conf b/ghostscript/cidfmap.d/90gs-cjk-resource-gb1.conf new file mode 100644 index 00000000..6801f62d --- /dev/null +++ b/ghostscript/cidfmap.d/90gs-cjk-resource-gb1.conf @@ -0,0 +1,9 @@ +/BousungEG-Light-GB << /FileType /TrueType /Path (/usr/share/fonts/truetype/arphic/uming.ttc) /SubfontID 0 /CSI [(GB1) 4] >> ; +/GBZenKai-Medium << /FileType /TrueType /Path (/usr/share/fonts/truetype/arphic/ukai.ttc) /SubfontID 0 /CSI [(GB1) 4] >> ; +/Song-Medium /GBZenKai-Medium ; +/STSong-Light /BousungEG-Light-GB ; +/STFangsong-Light /BousungEG-Light-GB ; +/STHeiti-Regular /BousungEG-Light-GB ; +/STKaiti-Regular /BousungEG-Light-GB ; +/Adobe-GB1 /BousungEG-Light-GB ; +/Adobe-GB1-Bold /GBZenKai-Medium ; diff --git a/ghostscript/cidfmap.d/90gs-cjk-resource-japan1.conf b/ghostscript/cidfmap.d/90gs-cjk-resource-japan1.conf new file mode 100644 index 00000000..841f438e --- /dev/null +++ b/ghostscript/cidfmap.d/90gs-cjk-resource-japan1.conf @@ -0,0 +1,8 @@ +/Japanese-Mincho-Regular << /FileType /TrueType /Path (/usr/share/fonts/truetype/fonts-japanese-mincho.ttf) /SubfontID 0 /CSI [(Japan1) 4] >> ; +/Japanese-Gothic-Regular << /FileType /TrueType /Path (/usr/share/fonts/truetype/fonts-japanese-gothic.ttf) /SubfontID 0 /CSI [(Japan1) 4] >> ; +/Ryumin-Light /Japanese-Mincho-Regular ; +/Adobe-Japan1 /Japanese-Mincho-Regular ; +/HeiseiMin-W3 /Japanese-Mincho-Regular ; +/GothicBBB-Medium /Japanese-Gothic-Regular ; +/Adobe-Japan1-Bold /Japanese-Gothic-Regular ; +/HeiseiKakuGo-W5 /Japanese-Gothic-Regular ; diff --git a/ghostscript/cidfmap.d/90gs-cjk-resource-japan2.conf b/ghostscript/cidfmap.d/90gs-cjk-resource-japan2.conf new file mode 100644 index 00000000..c2258267 --- /dev/null +++ b/ghostscript/cidfmap.d/90gs-cjk-resource-japan2.conf @@ -0,0 +1,4 @@ +/Japanese-Mincho-Regular-JaH << /FileType /TrueType /Path (/usr/share/fonts/truetype/ttf-japanese-mincho.ttf) /SubfontID 0 /CSI [(Japan2) 4] >> ; +/Japanese-Gothic-Regular-JaH << /FileType /TrueType /Path (/usr/share/fonts/truetype/ttf-japanese-gothic.ttf) /SubfontID 0 /CSI [(Japan2) 4] >> ; +/Adobe-Japan2 /Japanese-Mincho-Regular-JaH ; +/Adobe-Japan2-Bold /Japanese-Gothic-Regular-JaH ; diff --git a/ghostscript/cidfmap.d/90gs-cjk-resource-korea1.conf b/ghostscript/cidfmap.d/90gs-cjk-resource-korea1.conf new file mode 100644 index 00000000..2d71ae6d --- /dev/null +++ b/ghostscript/cidfmap.d/90gs-cjk-resource-korea1.conf @@ -0,0 +1,9 @@ +/NanumMyeongjo-Regular << /FileType /TrueType /Path (/usr/share/fonts/truetype/nanum/NanumMyeongjo.ttf) /SubfontID 0 /CSI [(Korea1) 2] >> ; +/NanumBarunGothic-Regular << /FileType /TrueType /Path (/usr/share/fonts/truetype/nanum/NanumBarunGothic.ttf) /SubfontID 0 /CSI [(Korea1) 2] >> ; +/NanumBarunGothic-Bold << /FileType /TrueType /Path (/usr/share/fonts/truetype/nanum/NanumBarunGothicBold.ttf) /SubfontID 0 /CSI [(Korea1) 2] >> ; +/NanumGothic-Regular << /FileType /TrueType /Path (/usr/share/fonts/truetype/nanum/NanumGothic.ttf) /SubfontID 0 /CSI [(Korea1) 2] >> ; +/HYSMyeongJo-Medium /NanumMyeongjo-Regular ; +/HYGoThic-Medium /NanumBarunGothic-Regular ; +/HYRGoThic-Medium /NanumGothic-Regular ; +/Adobe-Korea1 /NanumBarunGothic-Regular ; +/Adobe-Korea1-Bold /NanumBarunGothic-Bold ; diff --git a/ghostscript/fontmap.d/10gsfonts.conf b/ghostscript/fontmap.d/10gsfonts.conf new file mode 100644 index 00000000..9128470d --- /dev/null +++ b/ghostscript/fontmap.d/10gsfonts.conf @@ -0,0 +1,74 @@ +/URWGothicL-Book (/usr/share/fonts/type1/gsfonts/a010013l.pfb) ; +/AvantGarde-Book /URWGothicL-Book ; +/URWGothicL-Demi (/usr/share/fonts/type1/gsfonts/a010015l.pfb) ; +/AvantGarde-Demi /URWGothicL-Demi ; +/URWGothicL-BookObli (/usr/share/fonts/type1/gsfonts/a010033l.pfb) ; +/AvantGarde-BookOblique /URWGothicL-BookObli ; +/URWGothicL-DemiObli (/usr/share/fonts/type1/gsfonts/a010035l.pfb) ; +/AvantGarde-DemiOblique /URWGothicL-DemiObli ; +/URWBookmanL-Ligh (/usr/share/fonts/type1/gsfonts/b018012l.pfb) ; +/Bookman-Light /URWBookmanL-Ligh ; +/URWBookmanL-DemiBold (/usr/share/fonts/type1/gsfonts/b018015l.pfb) ; +/Bookman-Demi /URWBookmanL-DemiBold ; +/URWBookmanL-LighItal (/usr/share/fonts/type1/gsfonts/b018032l.pfb) ; +/Bookman-LightItalic /URWBookmanL-LighItal ; +/URWBookmanL-DemiBoldItal (/usr/share/fonts/type1/gsfonts/b018035l.pfb) ; +/Bookman-DemiItalic /URWBookmanL-DemiBoldItal ; +/CenturySchL-Roma (/usr/share/fonts/type1/gsfonts/c059013l.pfb) ; +/NewCenturySchlbk-Roman /CenturySchL-Roma ; +/CenturySchL-Bold (/usr/share/fonts/type1/gsfonts/c059016l.pfb) ; +/NewCenturySchlbk-Bold /CenturySchL-Bold ; +/CenturySchL-Ital (/usr/share/fonts/type1/gsfonts/c059033l.pfb) ; +/NewCenturySchlbk-Italic /CenturySchL-Ital ; +/CenturySchL-BoldItal (/usr/share/fonts/type1/gsfonts/c059036l.pfb) ; +/NewCenturySchlbk-BoldItalic /CenturySchL-BoldItal ; +/Dingbats (/usr/share/fonts/type1/gsfonts/d050000l.pfb) ; +/ZapfDingbats /Dingbats ; +/NimbusSanL-Regu (/usr/share/fonts/type1/gsfonts/n019003l.pfb) ; +/Helvetica /NimbusSanL-Regu ; +/NimbusSanL-Bold (/usr/share/fonts/type1/gsfonts/n019004l.pfb) ; +/Helvetica-Bold /NimbusSanL-Bold ; +/NimbusSanL-ReguItal (/usr/share/fonts/type1/gsfonts/n019023l.pfb) ; +/Helvetica-Oblique /NimbusSanL-ReguItal ; +/NimbusSanL-BoldItal (/usr/share/fonts/type1/gsfonts/n019024l.pfb) ; +/Helvetica-BoldOblique /NimbusSanL-BoldItal ; +/NimbusSanL-ReguCond (/usr/share/fonts/type1/gsfonts/n019043l.pfb) ; +/Helvetica-Narrow /NimbusSanL-ReguCond ; +/HelveticaNarrow /NimbusSanL-ReguCond ; +/NimbusSanL-BoldCond (/usr/share/fonts/type1/gsfonts/n019044l.pfb) ; +/Helvetica-Narrow-Bold /NimbusSanL-BoldCond ; +/HelveticaNarrow-Bold /NimbusSanL-BoldCond ; +/NimbusSanL-ReguCondItal (/usr/share/fonts/type1/gsfonts/n019063l.pfb) ; +/Helvetica-Narrow-Oblique /NimbusSanL-ReguCondItal ; +/HelveticaNarrow-Oblique /NimbusSanL-ReguCondItal ; +/NimbusSanL-BoldCondItal (/usr/share/fonts/type1/gsfonts/n019064l.pfb) ; +/Helvetica-Narrow-BoldOblique /NimbusSanL-BoldCondItal ; +/HelveticaNarrow-BoldOblique /NimbusSanL-BoldCondItal ; +/NimbusRomNo9L-Regu (/usr/share/fonts/type1/gsfonts/n021003l.pfb) ; +/Times-Roman /NimbusRomNo9L-Regu ; +/NimbusRomNo9L-Medi (/usr/share/fonts/type1/gsfonts/n021004l.pfb) ; +/Times-Bold /NimbusRomNo9L-Medi ; +/NimbusRomNo9L-ReguItal (/usr/share/fonts/type1/gsfonts/n021023l.pfb) ; +/Times-Italic /NimbusRomNo9L-ReguItal ; +/NimbusRomNo9L-MediItal (/usr/share/fonts/type1/gsfonts/n021024l.pfb) ; +/Times-BoldItalic /NimbusRomNo9L-MediItal ; +/NimbusMonL-Regu (/usr/share/fonts/type1/gsfonts/n022003l.pfb) ; +/Courier /NimbusMonL-Regu ; +/NimbusMonL-Bold (/usr/share/fonts/type1/gsfonts/n022004l.pfb) ; +/Courier-Bold /NimbusMonL-Bold ; +/NimbusMonL-ReguObli (/usr/share/fonts/type1/gsfonts/n022023l.pfb) ; +/Courier-Oblique /NimbusMonL-ReguObli ; +/NimbusMonL-BoldObli (/usr/share/fonts/type1/gsfonts/n022024l.pfb) ; +/Courier-BoldOblique /NimbusMonL-BoldObli ; +/URWPalladioL-Roma (/usr/share/fonts/type1/gsfonts/p052003l.pfb) ; +/Palatino-Roman /URWPalladioL-Roma ; +/URWPalladioL-Bold (/usr/share/fonts/type1/gsfonts/p052004l.pfb) ; +/Palatino-Bold /URWPalladioL-Bold ; +/URWPalladioL-Ital (/usr/share/fonts/type1/gsfonts/p052023l.pfb) ; +/Palatino-Italic /URWPalladioL-Ital ; +/URWPalladioL-BoldItal (/usr/share/fonts/type1/gsfonts/p052024l.pfb) ; +/Palatino-BoldItalic /URWPalladioL-BoldItal ; +/StandardSymL (/usr/share/fonts/type1/gsfonts/s050000l.pfb) ; +/Symbol /StandardSymL ; +/URWChanceryL-MediItal (/usr/share/fonts/type1/gsfonts/z003034l.pfb) ; +/ZapfChancery-MediumItalic /URWChanceryL-MediItal ; diff --git a/gitea/app.ini b/gitea/app.ini new file mode 100644 index 00000000..02ffbe5f --- /dev/null +++ b/gitea/app.ini @@ -0,0 +1,75 @@ +APP_NAME = Gitea - Realm Instance +RUN_USER = git +RUN_MODE = prod + +[oauth2] +JWT_SECRET = tWeFJH4pgM-VGScd4HaCXhweAwk576JHg2ulR7v9X5I + +[security] +INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE1OTQwNDE3NDR9.LJvJ2ikYaHFJttCWAWn5QtlsYsG_nbFstZSGB81S_ek +INSTALL_LOCK = true +SECRET_KEY = FitqNGSx7JUHfuwIel44G8mZrXrjQfWJViTrOF7wk6IUtCCrLWZVSed6p8PyHyr1 + +[database] +DB_TYPE = mysql +HOST = 192.168.0.40:3306 +NAME = giteadb +USER = gitea +PASSWD = W,?pn6aJB7D{M8f! +SCHEMA = +SSL_MODE = disable +CHARSET = utf8 +PATH = /var/lib/gitea/data/gitea.db + +[repository] +ROOT = /home/git/gitea-repositories + +[server] +SSH_DOMAIN = 192.168.0.28 +DOMAIN = realm.local +HTTP_PORT = 3000 +ROOT_URL = http://192.168.0.28:3000/ +DISABLE_SSH = false +SSH_PORT = 22 +LFS_START_SERVER = true +LFS_CONTENT_PATH = /var/lib/gitea/data/lfs +LFS_JWT_SECRET = mGjOrQ7PXiRxJPZrBz3ptgqt_9bp0VJ6CHCGeK9aqiE +OFFLINE_MODE = false + +[mailer] +ENABLED = true +HOST = mail.solusar.de +FROM = gitea@solusar.de +USER = admin@solusar.de +PASSWD = `#gentoo#` + +[service] +REGISTER_EMAIL_CONFIRM = true +ENABLE_NOTIFY_MAIL = true +DISABLE_REGISTRATION = true +ALLOW_ONLY_EXTERNAL_REGISTRATION = false +ENABLE_CAPTCHA = false +REQUIRE_SIGNIN_VIEW = false +DEFAULT_KEEP_EMAIL_PRIVATE = false +DEFAULT_ALLOW_CREATE_ORGANIZATION = false +DEFAULT_ENABLE_TIMETRACKING = true +NO_REPLY_ADDRESS = noreply.solusar.de + +[picture] +DISABLE_GRAVATAR = false +ENABLE_FEDERATED_AVATAR = true + +[openid] +ENABLE_OPENID_SIGNIN = false +ENABLE_OPENID_SIGNUP = false + +[session] +PROVIDER = file + +[log] +MODE = file +LEVEL = info +ROOT_PATH = /var/lib/gitea/log + +[ui] +DEFAULT_THEME = arc-green diff --git a/groff/man.local b/groff/man.local new file mode 100644 index 00000000..0c5cd9a6 --- /dev/null +++ b/groff/man.local @@ -0,0 +1,33 @@ +.\" -*- nroff -*- +.\" +.\" This file is loaded after an-old.tmac. +.\" Put any local modifications to an-old.tmac here. +. +.if n \{\ +. \" Debian: Map \(oq to ' rather than ` in nroff mode for devices other +. \" than utf8. +. if !'\*[.T]'utf8' \ +. tr \[oq]' +. +. \" Debian: Disable the use of SGR (ANSI colour) escape sequences by +. \" grotty. +. if '\V[GROFF_SGR]'' \ +. output x X tty: sgr 0 +. +. \" Debian: Strictly, "-" is a hyphen while "\-" is a minus sign, and the +. \" former may not always be rendered in the form expected for things like +. \" command-line options. Uncomment this if you want to make sure that +. \" manual pages you're writing are clear of this problem. +. \" if '\*[.T]'utf8' \ +. \" char - \[hy] +. +. \" Debian: "\-" is more commonly used for option dashes than for minus +. \" signs in manual pages, so map it to plain "-" for HTML/XHTML output +. \" rather than letting it be rendered as "−". +. ie '\*[.T]'html' \ +. char \- \N'45' +. el \{\ +. if '\*[.T]'xhtml' \ +. char \- \N'45' +. \} +.\} diff --git a/groff/mdoc.local b/groff/mdoc.local new file mode 100644 index 00000000..c29fac80 --- /dev/null +++ b/groff/mdoc.local @@ -0,0 +1,33 @@ +.\" -*- nroff -*- +.\" +.\" This file is loaded after doc.tmac. +.\" Put any local modifications to doc.tmac here. +. +.if n \{\ +. \" Debian: Map \(oq to ' rather than ` in nroff mode for devices other +. \" than utf8. +. if !'\*[.T]'utf8' \ +. tr \[oq]' +. +. \" Debian: Disable the use of SGR (ANSI colour) escape sequences by +. \" grotty. +. if '\V[GROFF_SGR]'' \ +. output x X tty: sgr 0 +. +. \" Debian: Strictly, "-" is a hyphen while "\-" is a minus sign, and the +. \" former may not always be rendered in the form expected for things like +. \" command-line options. Uncomment this if you want to make sure that +. \" manual pages you're writing are clear of this problem. +. \" if '\*[.T]'utf8' \ +. \" char - \[hy] +. +. \" Debian: "\-" is more commonly used for option dashes than for minus +. \" signs in manual pages, so map it to plain "-" for HTML/XHTML output +. \" rather than letting it be rendered as "−". +. ie '\*[.T]'html' \ +. char \- \N'45' +. el \{\ +. if '\*[.T]'xhtml' \ +. char \- \N'45' +. \} +.\} diff --git a/group b/group new file mode 100644 index 00000000..3bc7fd4c --- /dev/null +++ b/group @@ -0,0 +1,71 @@ +root:x:0: +daemon:x:1: +bin:x:2: +sys:x:3: +adm:x:4:pi +tty:x:5:iobroker +disk:x:6: +lp:x:7: +mail:x:8: +news:x:9: +uucp:x:10: +man:x:12: +proxy:x:13: +kmem:x:15: +dialout:x:20:pi,iobroker +fax:x:21: +voice:x:22: +cdrom:x:24:pi +floppy:x:25: +tape:x:26: +sudo:x:27:pi +audio:x:29:pi,iobroker +dip:x:30: +www-data:x:33: +backup:x:34: +operator:x:37: +list:x:38: +irc:x:39: +src:x:40: +gnats:x:41: +shadow:x:42: +utmp:x:43: +video:x:44:pi,iobroker +sasl:x:45: +plugdev:x:46:pi +staff:x:50: +games:x:60:pi +users:x:100:pi +nogroup:x:65534: +systemd-journal:x:101: +systemd-timesync:x:102: +systemd-network:x:103: +systemd-resolve:x:104: +input:x:105:pi +kvm:x:106: +render:x:107: +crontab:x:108: +netdev:x:109:pi +pi:x:1000: +messagebus:x:110: +ssh:x:111: +bluetooth:x:112:iobroker +avahi:x:113: +spi:x:999:pi +i2c:x:998:pi,iobroker +gpio:x:997:pi,iobroker +systemd-coredump:x:996: +redis:x:114:iobroker +mosquitto:x:116: +Debian-snmp:x:117: +plex:x:994: +git:x:118: +ssl-cert:x:119:postgres +postgres:x:120: +puppet:x:121: +ntp:x:122: +tftp:x:123: +Debian-exim:x:124: +iobroker:x:1001: +ghost:x:993: +docker:x:995: diff --git a/group- b/group- new file mode 100644 index 00000000..a0877f7c --- /dev/null +++ b/group- @@ -0,0 +1,70 @@ +root:x:0: +daemon:x:1: +bin:x:2: +sys:x:3: +adm:x:4:pi +tty:x:5:iobroker +disk:x:6: +lp:x:7: +mail:x:8: +news:x:9: +uucp:x:10: +man:x:12: +proxy:x:13: +kmem:x:15: +dialout:x:20:pi,iobroker +fax:x:21: +voice:x:22: +cdrom:x:24:pi +floppy:x:25: +tape:x:26: +sudo:x:27:pi +audio:x:29:pi,iobroker +dip:x:30: +www-data:x:33: +backup:x:34: +operator:x:37: +list:x:38: +irc:x:39: +src:x:40: +gnats:x:41: +shadow:x:42: +utmp:x:43: +video:x:44:pi,iobroker +sasl:x:45: +plugdev:x:46:pi +staff:x:50: +games:x:60:pi +users:x:100:pi +nogroup:x:65534: +systemd-journal:x:101: +systemd-timesync:x:102: +systemd-network:x:103: +systemd-resolve:x:104: +input:x:105:pi +kvm:x:106: +render:x:107: +crontab:x:108: +netdev:x:109:pi +pi:x:1000: +messagebus:x:110: +ssh:x:111: +bluetooth:x:112:iobroker +avahi:x:113: +spi:x:999:pi +i2c:x:998:pi,iobroker +gpio:x:997:pi,iobroker +systemd-coredump:x:996: +redis:x:114:iobroker +mosquitto:x:116: +Debian-snmp:x:117: +plex:x:994: +git:x:118: +ssl-cert:x:119:postgres +postgres:x:120: +puppet:x:121: +ntp:x:122: +tftp:x:123: +Debian-exim:x:124: +iobroker:x:1001: +ghost:x:993: diff --git a/gshadow b/gshadow new file mode 100644 index 00000000..6c5d627e --- /dev/null +++ b/gshadow @@ -0,0 +1,71 @@ +root:*:: +daemon:*:: +bin:*:: +sys:*:: +adm:*::pi +tty:*::iobroker +disk:*:: +lp:*:: +mail:*:: +news:*:: +uucp:*:: +man:*:: +proxy:*:: +kmem:*:: +dialout:*::pi,iobroker +fax:*:: +voice:*:: +cdrom:*::pi +floppy:*:: +tape:*:: +sudo:*::pi +audio:*::pi,iobroker +dip:*:: +www-data:*:: +backup:*:: +operator:*:: +list:*:: +irc:*:: +src:*:: +gnats:*:: +shadow:*:: +utmp:*:: +video:*::pi,iobroker +sasl:*:: +plugdev:*::pi +staff:*:: +games:*::pi +users:*::pi +nogroup:*:: +systemd-journal:!:: +systemd-timesync:!:: +systemd-network:!:: +systemd-resolve:!:: +input:!::pi +kvm:!:: +render:!:: +crontab:!:: +netdev:!::pi +pi:!:: +messagebus:!:: +ssh:!:: +bluetooth:!::iobroker +avahi:!:: +spi:!::pi +i2c:!::pi,iobroker +gpio:!::pi,iobroker +systemd-coredump:!!:: +redis:!::iobroker +mosquitto:!:: +Debian-snmp:!:: +plex:!:: +git:!:: +ssl-cert:!::postgres +postgres:!:: +puppet:!:: +ntp:!:: +tftp:!:: +Debian-exim:!:: +iobroker:!:: +ghost:!:: +docker:!:: diff --git a/gshadow- b/gshadow- new file mode 100644 index 00000000..bee5745c --- /dev/null +++ b/gshadow- @@ -0,0 +1,70 @@ +root:*:: +daemon:*:: +bin:*:: +sys:*:: +adm:*::pi +tty:*::iobroker +disk:*:: +lp:*:: +mail:*:: +news:*:: +uucp:*:: +man:*:: +proxy:*:: +kmem:*:: +dialout:*::pi,iobroker +fax:*:: +voice:*:: +cdrom:*::pi +floppy:*:: +tape:*:: +sudo:*::pi +audio:*::pi,iobroker +dip:*:: +www-data:*:: +backup:*:: +operator:*:: +list:*:: +irc:*:: +src:*:: +gnats:*:: +shadow:*:: +utmp:*:: +video:*::pi,iobroker +sasl:*:: +plugdev:*::pi +staff:*:: +games:*::pi +users:*::pi +nogroup:*:: +systemd-journal:!:: +systemd-timesync:!:: +systemd-network:!:: +systemd-resolve:!:: +input:!::pi +kvm:!:: +render:!:: +crontab:!:: +netdev:!::pi +pi:!:: +messagebus:!:: +ssh:!:: +bluetooth:!::iobroker +avahi:!:: +spi:!::pi +i2c:!::pi,iobroker +gpio:!::pi,iobroker +systemd-coredump:!!:: +redis:!::iobroker +mosquitto:!:: +Debian-snmp:!:: +plex:!:: +git:!:: +ssl-cert:!::postgres +postgres:!:: +puppet:!:: +ntp:!:: +tftp:!:: +Debian-exim:!:: +iobroker:!:: +ghost:!:: diff --git a/host.conf b/host.conf new file mode 100644 index 00000000..d1a59f73 --- /dev/null +++ b/host.conf @@ -0,0 +1 @@ +multi on diff --git a/hostname b/hostname new file mode 100644 index 00000000..3f2a1851 --- /dev/null +++ b/hostname @@ -0,0 +1 @@ +serviceraspi diff --git a/hosts b/hosts new file mode 100644 index 00000000..3a3ef331 --- /dev/null +++ b/hosts @@ -0,0 +1,7 @@ +127.0.0.1 localhost +::1 localhost ip6-localhost ip6-loopback +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters + +127.0.1.1 serviceraspi.realm.local serviceraspi +192.168.0.99 puppet.realm.local puppet diff --git a/hosts.allow b/hosts.allow new file mode 100644 index 00000000..4c12673f --- /dev/null +++ b/hosts.allow @@ -0,0 +1,10 @@ +# /etc/hosts.allow: list of hosts that are allowed to access the system. +# See the manual pages hosts_access(5) and hosts_options(5). +# +# Example: ALL: LOCAL @some_netgroup +# ALL: .foobar.edu EXCEPT terminalserver.foobar.edu +# +# If you're going to protect the portmapper use the name "rpcbind" for the +# daemon name. See rpcbind(8) and rpc.mountd(8) for further information. +# + diff --git a/hosts.deny b/hosts.deny new file mode 100644 index 00000000..f393e64d --- /dev/null +++ b/hosts.deny @@ -0,0 +1,17 @@ +# /etc/hosts.deny: list of hosts that are _not_ allowed to access the system. +# See the manual pages hosts_access(5) and hosts_options(5). +# +# Example: ALL: some.host.name, .some.domain +# ALL EXCEPT in.fingerd: other.host.name, .other.domain +# +# If you're going to protect the portmapper use the name "rpcbind" for the +# daemon name. See rpcbind(8) and rpc.mountd(8) for further information. +# +# The PARANOID wildcard matches any host whose name does not match its +# address. +# +# You may wish to enable this to ensure any programs that don't +# validate looked up hostnames still leave understandable logs. In past +# versions of Debian this has been the default. +# ALL: PARANOID + diff --git a/idmapd.conf b/idmapd.conf new file mode 100644 index 00000000..d5ffef7e --- /dev/null +++ b/idmapd.conf @@ -0,0 +1,11 @@ +[General] + +Verbosity = 0 +Pipefs-Directory = /run/rpc_pipefs +# set your own domain here, if it differs from FQDN minus hostname +# Domain = localdomain + +[Mapping] + +Nobody-User = nobody +Nobody-Group = nogroup diff --git a/ifplugd/action.d/action_wpa b/ifplugd/action.d/action_wpa new file mode 120000 index 00000000..8e48c386 --- /dev/null +++ b/ifplugd/action.d/action_wpa @@ -0,0 +1 @@ +../../wpa_supplicant/action_wpa.sh \ No newline at end of file diff --git a/init.d/alsa-utils b/init.d/alsa-utils new file mode 100755 index 00000000..e6a6e921 --- /dev/null +++ b/init.d/alsa-utils @@ -0,0 +1,209 @@ +#!/bin/sh +# +# alsa-utils initscript +# +### BEGIN INIT INFO +# Provides: alsa-utils +# Required-Start: $local_fs $remote_fs +# Required-Stop: $remote_fs +# Default-Start: S +# Default-Stop: 0 1 6 +# Short-Description: Restore and store ALSA driver settings +# Description: This script stores and restores mixer levels on +# shutdown and bootup.On sysv-rc systems: to +# disable storing of mixer levels on shutdown, +# remove /etc/rc[06].d/K50alsa-utils. To disable +# restoring of mixer levels on bootup, rename the +# "S50alsa-utils" symbolic link in /etc/rcS.d/ to +# "K50alsa-utils". +### END INIT INFO + +# Don't use set -e; check exit status instead + +# Exit silently if package is no longer installed +[ -x /usr/sbin/alsactl ] || exit 0 + +PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +MYNAME=/etc/init.d/alsa-utils +ALSACTLHOME=/run/alsa + +[ -d "$ALSACTLHOME" ] || mkdir -p "$ALSACTLHOME" + +. /lib/lsb/init-functions +. /usr/share/alsa/utils.sh + +# $1 EXITSTATUS +# [$2 MESSAGE] +log_action_end_msg_and_exit() +{ + log_action_end_msg "$1" ${2:+"$2"} + exit $1 +} + +# $1 PROGRAM +executable() +{ + # If which is not available then we must be running before + # /usr is mounted on a system that has which in /usr/bin/. + # Conclude that $1 is not executable. + [ -x /bin/which ] || [ -x /usr/bin/which ] || return 1 + which "$1" >/dev/null 2>&1 +} + +executable amixer || { echo "${MYNAME}: Error: No amixer program available." >&2 ; exit 1 ; } + +# $1 | "all" +restore_levels() +{ + [ -f /var/lib/alsa/asound.state ] || return 1 + CARD="$1" + [ "$1" = all ] && CARD="" + # Assume that if alsactl prints a message on stderr + # then it failed somehow. This works around the fact + # that alsactl doesn't return nonzero status when it + # can't restore settings for the card + if MSG="$(alsactl -E HOME="$ALSACTLHOME" restore $CARD 2>&1 >/dev/null)" && [ ! "$MSG" ] ; then + return 0 + else + # Retry with the "force" option. This restores more levels + # but it results in much longer error messages. + alsactl -F restore $CARD >/dev/null 2>&1 + log_action_cont_msg "warning: 'alsactl -E HOME="$ALSACTLHOME" restore${CARD:+ $CARD}' failed with error message '$MSG'" + return 1 + fi +} + +# $1 | "all" +store_levels() +{ + CARD="$1" + [ "$1" = all ] && CARD="" + if MSG="$(alsactl -E HOME="$ALSACTLHOME" store $CARD 2>&1)" ; then + sleep 1 + return 0 + else + log_action_cont_msg "warning: 'alsactl store${CARD:+ $CARD}' failed with error message '$MSG'" + return 1 + fi +} + + +# $1 +mute_and_zero_levels_on_card() +{ + CARDOPT="-c $1" + for CTL in \ + Master \ + PCM \ + Synth \ + CD \ + Line \ + Mic \ + "PCM,1" \ + Wave \ + Music \ + AC97 \ + "Master Digital" \ + DAC \ + "DAC,0" \ + "DAC,1" \ + Headphone \ + Speaker \ + Playback + do + mute_and_zero_level "$CTL" + done +# for CTL in \ +# "Audigy Analog/Digital Output Jack" \ +# "SB Live Analog/Digital Output Jack" +# do +# switch_control "$CTL" off +# done + return 0 +} + +# $1 | "all" +mute_and_zero_levels() +{ + TTZML_RETURNSTATUS=0 + case "$1" in + all) + for CARD in $(echo_card_indices) ; do + mute_and_zero_levels_on_card "$CARD" || TTZML_RETURNSTATUS=1 + done + ;; + *) + mute_and_zero_levels_on_card "$1" || TTZML_RETURNSTATUS=1 + ;; + esac + return $TTZML_RETURNSTATUS +} + + +# $1 | "all" +card_OK() +{ + [ "$1" ] || bugout + if [ "$1" = all ] ; then + [ -d /proc/asound ] + return $? + else + [ -d "/proc/asound/card$1" ] || [ -d "/proc/asound/$1" ] + return $? + fi +} + +# If a card identifier is provided in $2 then regard it as an error +# if that card is not present; otherwise don't regard it as an error. + +case "$1" in + start) + EXITSTATUS=0 + TARGET_CARD="$2" + case "$TARGET_CARD" in + ""|all) TARGET_CARD=all ; log_action_begin_msg "Setting up ALSA" ;; + *) log_action_begin_msg "Setting up ALSA card ${TARGET_CARD}" ;; + esac + card_OK "$TARGET_CARD" || log_action_end_msg_and_exit "$( [ ! "$2" ] ; echo $? ; )" "none loaded" + preinit_levels "$TARGET_CARD" || EXITSTATUS=1 + if ! restore_levels "$TARGET_CARD" ; then + sanify_levels "$TARGET_CARD" || EXITSTATUS=1 + restore_levels "$TARGET_CARD" >/dev/null 2>&1 || : + fi + log_action_end_msg_and_exit "$EXITSTATUS" + ;; + stop) + EXITSTATUS=0 + TARGET_CARD="$2" + case "$TARGET_CARD" in + ""|all) TARGET_CARD=all ; log_action_begin_msg "Shutting down ALSA" ;; + *) log_action_begin_msg "Shutting down ALSA card ${TARGET_CARD}" ;; + esac + card_OK "$TARGET_CARD" || log_action_end_msg_and_exit "$( [ ! "$2" ] ; echo $? ; )" "none loaded" + store_levels "$TARGET_CARD" || EXITSTATUS=1 + #mute_and_zero_levels "$TARGET_CARD" || EXITSTATUS=1 + log_action_end_msg_and_exit "$EXITSTATUS" + ;; + restart|force-reload) + EXITSTATUS=0 + $0 stop || EXITSTATUS=1 + $0 start || EXITSTATUS=1 + exit $EXITSTATUS + ;; + reset) + TARGET_CARD="$2" + case "$TARGET_CARD" in + ""|all) TARGET_CARD=all ; log_action_begin_msg "Resetting ALSA" ;; + *) log_action_begin_msg "Resetting ALSA card ${TARGET_CARD}" ;; + esac + card_OK "$TARGET_CARD" || log_action_end_msg_and_exit "$( [ ! "$2" ] ; echo $? ; )" "none loaded" + preinit_levels "$TARGET_CARD" + sanify_levels "$TARGET_CARD" + log_action_end_msg_and_exit "$?" + ;; + *) + echo "Usage: $MYNAME {start [CARD]|stop [CARD]|restart [CARD]|reset [CARD]}" >&2 + exit 3 + ;; +esac + diff --git a/init.d/avahi-daemon b/init.d/avahi-daemon new file mode 100755 index 00000000..66749b00 --- /dev/null +++ b/init.d/avahi-daemon @@ -0,0 +1,104 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: avahi avahi-daemon +# Required-Start: $remote_fs dbus +# Required-Stop: $remote_fs dbus +# Should-Start: $syslog +# Should-Stop: $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Avahi mDNS/DNS-SD Daemon +# Description: Zeroconf daemon for configuring your network +# automatically +### END INIT INFO + +PATH=/sbin:/bin:/usr/sbin:/usr/bin +DESC="Avahi mDNS/DNS-SD Daemon" +NAME="avahi-daemon" +DAEMON="/usr/sbin/$NAME" +SCRIPTNAME=/etc/init.d/$NAME + +# Gracefully exit if the package has been removed. +test -x $DAEMON || exit 0 + +. /lib/lsb/init-functions + +# Include avahi-daemon defaults if available. +test -f /etc/default/avahi-daemon && . /etc/default/avahi-daemon + +DISABLE_TAG="/var/run/avahi-daemon/disabled-for-unicast-local" + +# +# Function that starts the daemon/service. +# +d_start() { + $DAEMON -c && return 0 + + if [ -e $DISABLE_TAG -a "$AVAHI_DAEMON_DETECT_LOCAL" != "0" ]; then + # Disabled because of the existance of an unicast .local domain + log_warning_msg "avahi-daemon disabled because there is a unicast .local domain" + exit 0; + fi; + + $DAEMON -D +} + +# +# Function that stops the daemon/service. +# +d_stop() { + if $DAEMON -c ; then + $DAEMON -k + fi +} + +# +# Function that reload the config file for the daemon/service. +# +d_reload() { + $DAEMON -c && $DAEMON -r +} + +# +# Function that check the status of the daemon/service. +# +d_status() { + $DAEMON -c && { echo "$DESC is running"; exit 0; } || { echo "$DESC is not running"; exit 3; } +} + +case "$1" in + start) + log_daemon_msg "Starting $DESC" "$NAME" + d_start + log_end_msg $? + ;; + stop) + log_daemon_msg "Stopping $DESC" "$NAME" + d_stop + log_end_msg $? + ;; + reload|force-reload) + log_daemon_msg "Reloading services for $DESC" "$NAME" + d_reload + log_end_msg $? + ;; + restart) + log_daemon_msg "Restarting $DESC" "$NAME" + d_stop + if [ "$?" -eq 0 ]; then + d_start + log_end_msg $? + else + log_end_msg 1 + fi + ;; + status) + d_status + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload|reload|status}" >&2 + exit 3 + ;; +esac + +exit 0 diff --git a/init.d/bluetooth b/init.d/bluetooth new file mode 100755 index 00000000..01a1923e --- /dev/null +++ b/init.d/bluetooth @@ -0,0 +1,134 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: bluetooth +# Required-Start: $local_fs $syslog $remote_fs dbus +# Required-Stop: $local_fs $syslog $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start bluetooth daemons +### END INIT INFO +# +# bluez Bluetooth subsystem starting and stopping +# +# originally from bluez's scripts/bluetooth.init +# +# Edd Dumbill +# LSB 3.0 compilance and enhancements by Filippo Giunchedi +# +# Updated for bluez 4.7 by Mario Limonciello +# Updated for bluez 5.5 by Nobuhiro Iwamatsu +# +# Note: older daemons like dund pand hidd are now shipped inside the +# bluez-compat package + +PATH=/sbin:/bin:/usr/sbin:/usr/bin +DESC=bluetooth + +DAEMON=/usr/sbin/bluetoothd +HCIATTACH=/usr/bin/hciattach + +HID2HCI_ENABLED=1 +HID2HCI_UNDO=1 + +SDPTOOL=/usr/bin/sdptool + +# If you want to be ignore error of "org.freedesktop.hostname1", +# please enable NOPLUGIN_OPTION. +# NOPLUGIN_OPTION="--noplugin=hostname" +NOPLUGIN_OPTION="" +SSD_OPTIONS="--oknodo --quiet --exec $DAEMON -- $NOPLUGIN_OPTION" + +test -f $DAEMON || exit 0 + +# FIXME: any of the sourced files may fail if/with syntax errors +test -f /etc/default/bluetooth && . /etc/default/bluetooth +test -f /etc/default/rcS && . /etc/default/rcS + +. /lib/lsb/init-functions + +set -e + +# FIXME: this function is possibly a no-op +run_sdptool() +{ + # declaring IFS local in this function, removes the need to + # save/restore it + local IFS o + + test -x $SDPTOOL || return 1 + +# FIXME: where does SDPTOOL_OPTIONS come from? + if ! test -z "$SDPTOOL_OPTIONS" ; then + IFS=";" + for o in $SDPTOOL_OPTIONS ; do + #echo "execing $SDPTOOL $o" + IFS=" " + if [ "$VERBOSE" != no ]; then + $SDPTOOL $o + else + $SDPTOOL $o >/dev/null 2>&1 + fi + done + fi +} + +hci_input() +{ + log_progress_msg "switching to HID/HCI no longer done in init script, see /usr/share/doc/bluez/NEWS.Debian.gz" || : +} +alias enable_hci_input=hci_input +alias disable_hci_input=hci_input + +case $1 in + start) + log_daemon_msg "Starting $DESC" + + if test "$BLUETOOTH_ENABLED" = 0; then + log_progress_msg "disabled. see /etc/default/bluetooth" + log_end_msg 0 + exit 0 + fi + + start-stop-daemon --start --background $SSD_OPTIONS + log_progress_msg "${DAEMON##*/}" + + run_sdptool || : + + if test "$HID2HCI_ENABLED" = 1; then + enable_hci_input + fi + + log_end_msg 0 + ;; + stop) + log_daemon_msg "Stopping $DESC" + if test "$BLUETOOTH_ENABLED" = 0; then + log_progress_msg "disabled." + log_end_msg 0 + exit 0 + fi + if test "$HID2HCI_UNDO" = 1; then + disable_hci_input + fi + start-stop-daemon --stop $SSD_OPTIONS + log_progress_msg "${DAEMON}" + log_end_msg 0 + ;; + restart|force-reload) + $0 stop + sleep 1 + $0 start + ;; + status) + status_of_proc "$DAEMON" "$DESC" && exit 0 || exit $? + ;; + *) + N=/etc/init.d/bluetooth + echo "Usage: $N {start|stop|restart|force-reload|status}" >&2 + exit 1 + ;; +esac + +exit 0 + +# vim:noet diff --git a/init.d/console-setup.sh b/init.d/console-setup.sh new file mode 100755 index 00000000..292d8318 --- /dev/null +++ b/init.d/console-setup.sh @@ -0,0 +1,46 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: console-setup.sh +# Required-Start: $remote_fs +# Required-Stop: +# Should-Start: console-screen kbd +# Default-Start: 2 3 4 5 +# Default-Stop: +# X-Interactive: true +# Short-Description: Set console font and keymap +### END INIT INFO + +if [ -f /bin/setupcon ]; then + case "$1" in + stop|status) + # console-setup isn't a daemon + ;; + start|force-reload|restart|reload) + if [ -f /lib/lsb/init-functions ]; then + . /lib/lsb/init-functions + else + log_action_begin_msg () { + echo -n "$@... " + } + + log_action_end_msg () { + if [ "$1" -eq 0 ]; then + echo done. + else + echo failed. + fi + } + fi + log_action_begin_msg "Setting up console font and keymap" + if /lib/console-setup/console-setup.sh; then + log_action_end_msg 0 + else + log_action_end_msg $? + fi + ;; + *) + echo 'Usage: /etc/init.d/console-setup {start|reload|restart|force-reload|stop|status}' + exit 3 + ;; + esac +fi diff --git a/init.d/cron b/init.d/cron new file mode 100755 index 00000000..c90dc1e3 --- /dev/null +++ b/init.d/cron @@ -0,0 +1,92 @@ +#!/bin/sh +# Start/stop the cron daemon. +# +### BEGIN INIT INFO +# Provides: cron +# Required-Start: $remote_fs $syslog $time +# Required-Stop: $remote_fs $syslog $time +# Should-Start: $network $named slapd autofs ypbind nscd nslcd winbind sssd +# Should-Stop: $network $named slapd autofs ypbind nscd nslcd winbind sssd +# Default-Start: 2 3 4 5 +# Default-Stop: +# Short-Description: Regular background program processing daemon +# Description: cron is a standard UNIX program that runs user-specified +# programs at periodic scheduled times. vixie cron adds a +# number of features to the basic UNIX cron, including better +# security and more powerful configuration options. +### END INIT INFO + +PATH=/bin:/usr/bin:/sbin:/usr/sbin +DESC="cron daemon" +NAME=cron +DAEMON=/usr/sbin/cron +PIDFILE=/var/run/crond.pid +SCRIPTNAME=/etc/init.d/"$NAME" + +test -f $DAEMON || exit 0 + +. /lib/lsb/init-functions + +[ -r /etc/default/cron ] && . /etc/default/cron + +# Read the system's locale and set cron's locale. This is only used for +# setting the charset of mails generated by cron. To provide locale +# information to tasks running under cron, see /etc/pam.d/cron. +# +# We read /etc/environment, but warn about locale information in +# there because it should be in /etc/default/locale. +parse_environment () +{ + for ENV_FILE in /etc/environment /etc/default/locale; do + [ -r "$ENV_FILE" ] || continue + [ -s "$ENV_FILE" ] || continue + + for var in LANG LANGUAGE LC_ALL LC_CTYPE; do + value=`egrep "^${var}=" "$ENV_FILE" | tail -n1 | cut -d= -f2` + [ -n "$value" ] && eval export $var=$value + + if [ -n "$value" ] && [ "$ENV_FILE" = /etc/environment ]; then + log_warning_msg "/etc/environment has been deprecated for locale information; use /etc/default/locale for $var=$value instead" + fi + done + done + +# Get the timezone set. + if [ -z "$TZ" -a -e /etc/timezone ]; then + TZ=`cat /etc/timezone` + fi +} + +# Parse the system's environment +if [ "$READ_ENV" = "yes" ] ; then + parse_environment +fi + + +case "$1" in +start) log_daemon_msg "Starting periodic command scheduler" "cron" + start_daemon -p $PIDFILE $DAEMON $EXTRA_OPTS + log_end_msg $? + ;; +stop) log_daemon_msg "Stopping periodic command scheduler" "cron" + killproc -p $PIDFILE $DAEMON + RETVAL=$? + [ $RETVAL -eq 0 ] && [ -e "$PIDFILE" ] && rm -f $PIDFILE + log_end_msg $RETVAL + ;; +restart) log_daemon_msg "Restarting periodic command scheduler" "cron" + $0 stop + $0 start + ;; +reload|force-reload) log_daemon_msg "Reloading configuration files for periodic command scheduler" "cron" + # cron reloads automatically + log_end_msg 0 + ;; +status) + status_of_proc -p $PIDFILE $DAEMON $NAME && exit 0 || exit $? + ;; +*) log_action_msg "Usage: /etc/init.d/cron {start|stop|status|restart|reload|force-reload}" + exit 2 + ;; +esac +exit 0 diff --git a/init.d/dbus b/init.d/dbus new file mode 100755 index 00000000..4f41293f --- /dev/null +++ b/init.d/dbus @@ -0,0 +1,122 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: dbus +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: +# Short-Description: D-Bus systemwide message bus +# Description: D-Bus is a simple interprocess messaging system, used +# for sending messages between applications. +### END INIT INFO +# -*- coding: utf-8 -*- +# Debian init.d script for D-BUS +# Copyright © 2003 Colin Walters +# Copyright © 2005 Sjoerd Simons + +set -e + +DAEMON=/usr/bin/dbus-daemon +UUIDGEN=/usr/bin/dbus-uuidgen +UUIDGEN_OPTS=--ensure +NAME=dbus +DAEMONUSER=messagebus +PIDDIR=/var/run/dbus +PIDFILE=$PIDDIR/pid +DESC="system message bus" + +test -x $DAEMON || exit 0 + +. /lib/lsb/init-functions + +# Source defaults file; edit that file to configure this script. +PARAMS="" +if [ -e /etc/default/dbus ]; then + . /etc/default/dbus +fi + +create_machineid() { + # Create machine-id file + if [ -x $UUIDGEN ]; then + $UUIDGEN $UUIDGEN_OPTS + fi +} + +start_it_up() +{ + if [ ! -d $PIDDIR ]; then + mkdir -p $PIDDIR + chown $DAEMONUSER $PIDDIR + chgrp $DAEMONUSER $PIDDIR + fi + + if ! mountpoint -q /proc/ ; then + log_failure_msg "Can't start $DESC - /proc is not mounted" + return + fi + + if [ -e $PIDFILE ]; then + if $0 status > /dev/null ; then + log_success_msg "$DESC already started; not starting." + return + else + log_success_msg "Removing stale PID file $PIDFILE." + rm -f $PIDFILE + fi + fi + + create_machineid + + log_daemon_msg "Starting $DESC" "$NAME" + start-stop-daemon --start --quiet --pidfile $PIDFILE \ + --exec $DAEMON -- --system $PARAMS + log_end_msg $? +} + +shut_it_down() +{ + log_daemon_msg "Stopping $DESC" "$NAME" + start-stop-daemon --stop --retry 5 --quiet --oknodo --pidfile $PIDFILE \ + --user $DAEMONUSER + # We no longer include these arguments so that start-stop-daemon + # can do its job even given that we may have been upgraded. + # We rely on the pidfile being sanely managed + # --exec $DAEMON -- --system $PARAMS + log_end_msg $? + rm -f $PIDFILE +} + +reload_it() +{ + create_machineid + log_action_begin_msg "Reloading $DESC config" + dbus-send --print-reply --system --type=method_call \ + --dest=org.freedesktop.DBus \ + / org.freedesktop.DBus.ReloadConfig > /dev/null + # hopefully this is enough time for dbus to reload it's config file. + log_action_end_msg $? +} + +case "$1" in + start) + start_it_up + ;; + stop) + shut_it_down + ;; + reload|force-reload) + reload_it + ;; + restart) + shut_it_down + start_it_up + ;; + status) + status_of_proc -p $PIDFILE $DAEMON $NAME && exit 0 || exit $? + ;; + *) + echo "Usage: /etc/init.d/$NAME {start|stop|reload|restart|force-reload|status}" >&2 + exit 2 + ;; +esac + diff --git a/init.d/dhcpcd b/init.d/dhcpcd new file mode 100755 index 00000000..f0b24ac9 --- /dev/null +++ b/init.d/dhcpcd @@ -0,0 +1,96 @@ +#!/bin/sh +# +### BEGIN INIT INFO +# Provides: dhcpcd +# Required-Start: $remote_fs $local_fs +# Required-Stop: $remote_fs $local_fs +# Should-Start: +# Should-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: IPv4 DHCP client with IPv4LL support +# Description: +### END INIT INFO + +PATH=/sbin:/bin:/usr/sbin:/usr/bin +DHCPCD=/sbin/dhcpcd +NAME=dhcpcd +PIDFILE=/var/run/dhcpcd.pid + +test -x $DHCPCD || exit 0 + +INTERFACES=/etc/network/interfaces + +. /lib/lsb/init-functions + +sanity() +{ + local x= + + case "$($DHCPCD --version)" in + [1234].*) + log_failure_msg "Not running $NAME because an older version" \ + "is currently preferred" + exit 6 + esac + + for x in /var/run/dhcpcd-*.pid; do + [ -f "$x" ] || continue + log_failure_msg "Not running $NAME because there is aleady an" \ + "interface specific instance" + log_failure_msg "$x" + exit 6 + done + + if grep -q "^[[:space:]]*iface[[:space:]]*.*[[:space:]]*inet[[:space:]]*dhcp" \ + $INTERFACES; then + log_failure_msg "Not running $NAME because $INTERFACES" + log_failure_msg "defines some interfaces that will use a" \ + "DHCP client" + exit 6 + fi +} + +case "$1" in +start) + sanity + if pidofproc -p $PIDFILE $DHCPCD >/dev/null; then + log_warning_msg "$NAME is already running" + exit 0 + fi + $DHCPCD + ;; +stop) + sanity + $DHCPCD -x + ;; +restart|force-reload) + sanity + $DHCPCD -x + $DHCPCD + ;; +try-restart) + if ! pidofproc -p $PIDFILE $DHCPCD >/dev/null; then + log_warning_msg "$NAME is not running" + else + sanity + $DHCPCD -x + $DHCPCD + fi + ;; +reload) + if ! pidofproc -p $PIDFILE $DHCPCD >/dev/null; then + log_failure_msg "$NAME is not running" + exit 7 + fi + sanity + $DHCPCD -n + ;; +status) + status_of_proc -p $PIDFILE $DHCPCD "$NAME" || exit $? + ;; +*) + log_failure_msg "Usage: /etc/init.d/dhcpcd {start|stop|restart|try-restart|force-reload|status}" + exit 1 + ;; +esac diff --git a/init.d/docker b/init.d/docker new file mode 100755 index 00000000..9c8fa6be --- /dev/null +++ b/init.d/docker @@ -0,0 +1,156 @@ +#!/bin/sh +set -e + +### BEGIN INIT INFO +# Provides: docker +# Required-Start: $syslog $remote_fs +# Required-Stop: $syslog $remote_fs +# Should-Start: cgroupfs-mount cgroup-lite +# Should-Stop: cgroupfs-mount cgroup-lite +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Create lightweight, portable, self-sufficient containers. +# Description: +# Docker is an open-source project to easily create lightweight, portable, +# self-sufficient containers from any application. The same container that a +# developer builds and tests on a laptop can run at scale, in production, on +# VMs, bare metal, OpenStack clusters, public clouds and more. +### END INIT INFO + +export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin + +BASE=docker + +# modify these in /etc/default/$BASE (/etc/default/docker) +DOCKERD=/usr/bin/dockerd +# This is the pid file managed by docker itself +DOCKER_PIDFILE=/var/run/$BASE.pid +# This is the pid file created/managed by start-stop-daemon +DOCKER_SSD_PIDFILE=/var/run/$BASE-ssd.pid +DOCKER_LOGFILE=/var/log/$BASE.log +DOCKER_OPTS= +DOCKER_DESC="Docker" + +# Get lsb functions +. /lib/lsb/init-functions + +if [ -f /etc/default/$BASE ]; then + . /etc/default/$BASE +fi + +# Check docker is present +if [ ! -x $DOCKERD ]; then + log_failure_msg "$DOCKERD not present or not executable" + exit 1 +fi + +check_init() { + # see also init_is_upstart in /lib/lsb/init-functions (which isn't available in Ubuntu 12.04, or we'd use it directly) + if [ -x /sbin/initctl ] && /sbin/initctl version 2>/dev/null | grep -q upstart; then + log_failure_msg "$DOCKER_DESC is managed via upstart, try using service $BASE $1" + exit 1 + fi +} + +fail_unless_root() { + if [ "$(id -u)" != '0' ]; then + log_failure_msg "$DOCKER_DESC must be run as root" + exit 1 + fi +} + +cgroupfs_mount() { + # see also https://github.com/tianon/cgroupfs-mount/blob/master/cgroupfs-mount + if grep -v '^#' /etc/fstab | grep -q cgroup \ + || [ ! -e /proc/cgroups ] \ + || [ ! -d /sys/fs/cgroup ]; then + return + fi + if ! mountpoint -q /sys/fs/cgroup; then + mount -t tmpfs -o uid=0,gid=0,mode=0755 cgroup /sys/fs/cgroup + fi + ( + cd /sys/fs/cgroup + for sys in $(awk '!/^#/ { if ($4 == 1) print $1 }' /proc/cgroups); do + mkdir -p $sys + if ! mountpoint -q $sys; then + if ! mount -n -t cgroup -o $sys cgroup $sys; then + rmdir $sys || true + fi + fi + done + ) +} + +case "$1" in + start) + check_init + + fail_unless_root + + cgroupfs_mount + + touch "$DOCKER_LOGFILE" + chgrp docker "$DOCKER_LOGFILE" + + ulimit -n 1048576 + + # Having non-zero limits causes performance problems due to accounting overhead + # in the kernel. We recommend using cgroups to do container-local accounting. + if [ "$BASH" ]; then + ulimit -u unlimited + else + ulimit -p unlimited + fi + + log_begin_msg "Starting $DOCKER_DESC: $BASE" + start-stop-daemon --start --background \ + --no-close \ + --exec "$DOCKERD" \ + --pidfile "$DOCKER_SSD_PIDFILE" \ + --make-pidfile \ + -- \ + -p "$DOCKER_PIDFILE" \ + $DOCKER_OPTS \ + >> "$DOCKER_LOGFILE" 2>&1 + log_end_msg $? + ;; + + stop) + check_init + fail_unless_root + if [ -f "$DOCKER_SSD_PIDFILE" ]; then + log_begin_msg "Stopping $DOCKER_DESC: $BASE" + start-stop-daemon --stop --pidfile "$DOCKER_SSD_PIDFILE" --retry 10 + log_end_msg $? + else + log_warning_msg "Docker already stopped - file $DOCKER_SSD_PIDFILE not found." + fi + ;; + + restart) + check_init + fail_unless_root + docker_pid=`cat "$DOCKER_SSD_PIDFILE" 2>/dev/null` + [ -n "$docker_pid" ] \ + && ps -p $docker_pid > /dev/null 2>&1 \ + && $0 stop + $0 start + ;; + + force-reload) + check_init + fail_unless_root + $0 restart + ;; + + status) + check_init + status_of_proc -p "$DOCKER_SSD_PIDFILE" "$DOCKERD" "$DOCKER_DESC" + ;; + + *) + echo "Usage: service docker {start|stop|restart|status}" + exit 1 + ;; +esac diff --git a/init.d/dphys-swapfile b/init.d/dphys-swapfile new file mode 100755 index 00000000..5e495d3a --- /dev/null +++ b/init.d/dphys-swapfile @@ -0,0 +1,78 @@ +#!/bin/sh +# /etc/init.d/dphys-swapfile - automatically set up an swapfile +# author Neil Franklin, last modification 2006.09.15 +# This script is copyright ETH Zuerich Physics Departement, +# use under either modified/non-advertising BSD or GPL license + +# this init.d script is intended to be run from rcS.d +# must run after mount of /var which may only happen in S35mountall.sh +# for this reason we can not build swapfile until after S35mountall.sh +# so we also need to use init.d start|stop to swapon|off our file +# and sensibly before the lots of stuff which may happen in S40networking +# so we run it as rcS.d/S37dphys-config + +### BEGIN INIT INFO +# Provides: dphys-swapfile +# Required-Start: $syslog $remote_fs +# Required-Stop: $syslog $remote_fs +# Should-Start: $local_fs +# Should-Stop: $local_fs +# Default-Start: 2 3 4 5 +# Default-Stop: +# Short-Description: Autogenerate and use a swap file +# Description: This init.d script exists so one does not need to have a fixed size +# swap partition. Instead install without swap partition and then run +# this, with file size (re-)computed automatically to fit the current +# RAM size. +### END INIT INFO + +. /lib/lsb/init-functions + +# get ready to work +PATH=/sbin:/bin:/usr/sbin:/usr/bin +export PATH + +# what we are +NAME=dphys-swapfile + +case "$1" in + + start) + /bin/echo "Starting ${NAME} swapfile setup ..." + + # (re-)size/-generate (and also first time install) + # this will produce output, so no -n in above echo + /sbin/dphys-swapfile setup + + # as S35mountall.sh has already run, do this from here + # as there can be no swapon in /etc/fstab + /sbin/dphys-swapfile swapon + + /bin/echo "done." + ;; + + + stop|default-stop) + /bin/echo -n "Stopping ${NAME} swapfile setup ..." + + # as no swapon or swapoff in /etc/fstab, do this from here + /sbin/dphys-swapfile swapoff + + /bin/echo ", done." + ;; + + + restart|reload|force-reload|status) + /bin/echo "No daemon to (force-)re[start|load] or status check in ${NAME}" + ;; + + + *) + /bin/echo "Usage: $0 {start|stop}" + + exit 1 + ;; + +esac + +exit 0 diff --git a/init.d/exim4 b/init.d/exim4 new file mode 100755 index 00000000..61f2affe --- /dev/null +++ b/init.d/exim4 @@ -0,0 +1,289 @@ +#! /bin/sh +# /etc/init.d/exim4 +# +# Written by Miquel van Smoorenburg . +# Modified for Debian GNU/Linux by Ian Murdock . +# Modified for exim by Tim Cutts +# Modified for exim4 by Andreas Metzler +# and Marc Haber + +### BEGIN INIT INFO +# Provides: exim4 +# Required-Start: $remote_fs $syslog $named $network $time +# Required-Stop: $remote_fs $syslog $named $network +# Should-Start: postgresql mysql clamav-daemon greylist spamassassin +# Should-Stop: postgresql mysql clamav-daemon greylist spamassassin +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: exim Mail Transport Agent +# Description: exim is a Mail Transport agent +### END INIT INFO + +set -e + +test -x /usr/lib/exim4/exim4 || exit 0 + +. /lib/lsb/init-functions + +if [ -n "$EX4DEBUG" ]; then + echo "now debugging $0 $@" + set -x +fi + +LANG=C +export LANG + +#read default file +QUEUERUNNER='combined' +QUEUEINTERVAL='30m' +UPEX4OPTS='' +[ -f /etc/default/exim4 ] && . /etc/default/exim4 +PIDFILE="/run/exim4/exim.pid" +QRPIDFILE="/run/exim4/eximqr.pid" + +upex4conf() { + UPEX4CONF="update-exim4.conf" + OLDIFS="$IFS" + IFS=: + for p in $PATH; do + if [ -x "$p/$UPEX4CONF" ]; then + IFS="$OLDIFS" + $p/$UPEX4CONF $UPEX4OPTS $1 + return 0 + fi + done + IFS="$OLDIFS" +} + +# Exit if exim runs from /etc/inetd.conf +if [ -f /etc/inetd.conf ] && grep -E -q '^[[:space:]]*((\*|[[:alnum:].-]+):)?smtp[[:space:]]' /etc/inetd.conf +then + upex4conf + exit 0 +fi + + +DAEMON="/usr/sbin/exim4" +NAME="exim4" + +# this is from madduck on IRC, 2006-07-06 +# There should be a better possibility to give daemon error messages +# and/or to log things +log() +{ + case "$1" in + [[:digit:]]*) success=$1; shift;; + *) :;; + esac + log_action_begin_msg "$1"; shift + log_action_end_msg ${success:-0} "$*" +} + +start_exim() +{ + [ -e /run/exim4 ] || \ + install -d -oDebian-exim -gDebian-exim -m750 /run/exim4 + case ${QUEUERUNNER} in + combined) + start_daemon -p "$PIDFILE" \ + "$DAEMON" -bd "-q${QFLAGS}${QUEUEINTERVAL}" \ + ${COMMONOPTIONS} \ + ${QUEUERUNNEROPTIONS} \ + ${SMTPLISTENEROPTIONS} + log_progress_msg "exim4" + ;; + separate) + start_daemon -p "$PIDFILE" \ + "$DAEMON" -bd \ + ${COMMONOPTIONS} \ + ${SMTPLISTENEROPTIONS} + log_progress_msg "exim4_listener" + start_daemon -p "$QRPIDFILE" \ + "$DAEMON" -oP $QRPIDFILE \ + "-q${QFLAGS}${QUEUEINTERVAL}" \ + ${COMMONOPTIONS} \ + ${QUEUERUNNEROPTIONS} + log_progress_msg "exim4_queuerunner" + ;; + queueonly) + start_daemon -p "$PIDFILE" \ + "$DAEMON" -oP $PIDFILE \ + "-q${QFLAGS}${QUEUEINTERVAL}" \ + ${COMMONOPTIONS} \ + ${QUEUERUNNEROPTIONS} + log_progress_msg "exim4_queuerunner" + ;; + no|ppp) + start_daemon -p "$PIDFILE" \ + "$DAEMON" -bd \ + ${COMMONOPTIONS} \ + ${SMTPLISTENEROPTIONS} + log_progress_msg "exim4_listener" + ;; + nodaemon) + ;; + esac +} + +stop_exim() +{ +# we try to kill eximqr and exim SMTP listener, no matter what +# ${QUEUERUNNER} is set to, we could have switched since starting. + if [ -f "$QRPIDFILE" ]; then + start-stop-daemon --stop --retry 5 --quiet --oknodo --remove-pidfile \ + --pidfile "$QRPIDFILE" \ + --exec "$DAEMON" + # exim does not remove the pidfile + if [ $? -eq 2 ] ; then rm -f "$QRPIDFILE" ; fi + log_progress_msg "exim4_queuerunner" + fi + if [ -f "$PIDFILE" ]; then + start-stop-daemon --stop --retry 5 --quiet --oknodo --remove-pidfile \ + --pidfile "$PIDFILE" \ + --exec "$DAEMON" + # exim does not remove the pidfile + if [ $? -eq 2 ] ; then rm -f "$PIDFILE" ; fi + log_progress_msg "exim4_listener" + fi +} + +reload_exim() +{ + case ${QUEUERUNNER} in + combined|no|ppp|queueonly) + start-stop-daemon --stop --signal HUP --quiet --oknodo \ + --pidfile "$PIDFILE" \ + --exec "$DAEMON" + log_progress_msg "exim4" + ;; + separate) + start-stop-daemon --stop --signal HUP --quiet --oknodo \ + --pidfile "$PIDFILE" \ + --exec "$DAEMON" + log_progress_msg "exim4_listener" + start-stop-daemon --stop --signal HUP --quiet --oknodo \ + --pidfile "$QRPIDFILE" \ + --exec "$DAEMON" + log_progress_msg "exim4_queuerunner" + ;; + esac +} + +kill_all_exims() +{ SIG="${1:-TERM}" + for pid in $(pidof $NAME); do + if [ "$(readlink /proc/$pid/root)" = "/" ]; then + kill -$SIG $pid + fi + done +} + +status() +{ + # the exit value of this function reflects the status of the SMTP + # service. Output shows the status of the queue runner as well. + SMTPNAME="SMTP listener daemon" + QRNAME="separate queue runner daemon" + if [ "${QUEUERUNNER}" = "combined" ]; then + SMTPNAME="combined SMTP listener and queue runner daemon" + elif [ "${QUEUERUNNER}" = "queueonly" ]; then + SMTPNAME="separate queue runner daemon" + fi + log_action_begin_msg "checking $QRNAME" + if pidofproc -p "$QRPIDFILE" "$DAEMON" >/dev/null; then + log_action_end_msg 0 "running" + else + if [ -e "$QRPIDFILE" ]; then + log_action_end_msg 1 "$QRNAME failed" + else + log_action_end_msg 0 "not running" + fi + fi + log_action_begin_msg "checking $SMTPNAME" + if pidofproc -p "$PIDFILE" "$DAEMON" >/dev/null; then + log_action_end_msg 0 "running" + exit 0 + else + if [ -e "$PIDFILE" ]; then + log_action_end_msg 1 "$SMTPNAME failed" + exit 1 + else + log_action_end_msg 0 "not running" + exit 3 + fi + fi +} + +# check for valid configuration file +isconfigvalid() +{ +if ! $DAEMON -bV > /dev/null ; then + log 1 "Warning! Invalid configuration file for $NAME. Exiting." + exit 1 +fi +} + +# check for non-empty paniclog +warn_paniclog() +{ + if [ -s "/var/log/exim4/paniclog" ]; then + if [ -z "$E4BCD_PANICLOG_NOISE" ] || grep -vq "$E4BCD_PANICLOG_NOISE" /var/log/exim4/paniclog; then + echo "ALERT: exim paniclog /var/log/exim4/paniclog has non-zero size, mail system possibly broken" 1>&2 + fi + fi +} + +case "$1" in + start) + log_daemon_msg "Starting MTA" + # regenerate exim4.conf + upex4conf + isconfigvalid + start_exim + log_end_msg 0 + warn_paniclog + ;; + stop) + log_daemon_msg "Stopping MTA" + stop_exim + log_end_msg 0 + warn_paniclog + ;; + restart) + # check whether newly generated config would work + upex4conf --check + log_daemon_msg "Stopping MTA for restart" + stop_exim + # regenerate exim4.conf + upex4conf + isconfigvalid + log_end_msg 0 + sleep 2 + log_daemon_msg "Restarting MTA" + start_exim + log_end_msg 0 + warn_paniclog + ;; + reload|force-reload) + log_daemon_msg "Reloading $NAME configuration files" + # regenerate exim4.conf + upex4conf + isconfigvalid + reload_exim + log_end_msg 0 + warn_paniclog + ;; + status) + status + ;; + force-stop) + kill_all_exims $2 + ;; + *) + echo "Usage: $0 {start|stop|restart|reload|status|force-stop}" + exit 1 + ;; +esac + +exit 0 +# vim:tabstop=2:expandtab:shiftwidth=2 diff --git a/init.d/fake-hwclock b/init.d/fake-hwclock new file mode 100755 index 00000000..86ff24a2 --- /dev/null +++ b/init.d/fake-hwclock @@ -0,0 +1,38 @@ +#!/bin/sh + +### BEGIN INIT INFO +# Provides: fake-hwclock +# Required-Start: +# Required-Stop: umountroot +# Should-Stop: +# X-Start-Before: checkroot +# Default-Start: S +# Default-Stop: 0 1 6 +# Short-Description: Restore / save the current clock +# Description: +### END INIT INFO + +set -e + +# Include core init functions if needed +. /lib/lsb/init-functions + +PARAM=/etc/default/fake-hwclock +if [ -f $PARAM ]; then + . "$PARAM" +fi + +case "${1:-}" in + stop|reload|restart|force-reload) + echo "Stopping fake hwclock: saving system time." + fake-hwclock save;; + + start) + echo "Starting fake hwclock: loading system time." + fake-hwclock load $FORCE ;; + + *) + echo "Usage: ${0:-} {start|stop|status|restart|reload|force-reload}" >&2 + exit 1 + ;; +esac diff --git a/init.d/hwclock.sh b/init.d/hwclock.sh new file mode 100755 index 00000000..208ca2d5 --- /dev/null +++ b/init.d/hwclock.sh @@ -0,0 +1,120 @@ +#!/bin/sh +# hwclock.sh Set and adjust the CMOS clock. +# +# Version: @(#)hwclock.sh 2.00 14-Dec-1998 miquels@cistron.nl +# +# Patches: +# 2000-01-30 Henrique M. Holschuh +# - Minor cosmetic changes in an attempt to help new +# users notice something IS changing their clocks +# during startup/shutdown. +# - Added comments to alert users of hwclock issues +# and discourage tampering without proper doc reading. +# 2012-02-16 Roger Leigh +# - Use the UTC/LOCAL setting in /etc/adjtime rather than +# the UTC setting in /etc/default/rcS. Additionally +# source /etc/default/hwclock to permit configuration. + +### BEGIN INIT INFO +# Provides: hwclock +# Required-Start: mountdevsubfs +# Required-Stop: mountdevsubfs +# Should-Stop: umountfs +# Default-Start: S +# X-Start-Before: checkroot +# Default-Stop: 0 6 +# Short-Description: Sync hardware and system clock time. +### END INIT INFO + +# These defaults are user-overridable in /etc/default/hwclock +BADYEAR=no +HWCLOCKACCESS=yes +HWCLOCKPARS= +HCTOSYS_DEVICE=rtc0 + +# We only want to use the system timezone or else we'll get +# potential inconsistency at startup. +unset TZ + +hwclocksh() +{ + [ ! -x /sbin/hwclock ] && return 0 + [ ! -r /etc/default/rcS ] || . /etc/default/rcS + [ ! -r /etc/default/hwclock ] || . /etc/default/hwclock + + . /lib/lsb/init-functions + verbose_log_action_msg() { [ "$VERBOSE" = no ] || log_action_msg "$@"; } + + case "$BADYEAR" in + no|"") BADYEAR="" ;; + yes) BADYEAR="--badyear" ;; + *) log_action_msg "unknown BADYEAR setting: \"$BADYEAR\""; return 1 ;; + esac + + case "$1" in + start) + # If the admin deleted the hwclock config, create a blank + # template with the defaults. + if [ -w /etc ] && [ ! -f /etc/adjtime ] && [ ! -e /etc/adjtime ]; then + printf "0.0 0 0.0\n0\nUTC\n" > /etc/adjtime + fi + + if [ -d /run/udev ] || [ -d /dev/.udev ]; then + return 0 + fi + + if [ "$HWCLOCKACCESS" != no ]; then + log_action_msg "Setting the system clock" + + # Just for reporting. + if sed '3!d' /etc/adjtime | grep -q '^UTC$'; then + UTC="--utc" + else + UTC= + fi + # Copies Hardware Clock time to System Clock using the correct + # timezone for hardware clocks in local time, and sets kernel + # timezone. DO NOT REMOVE. + if /sbin/hwclock --rtc=/dev/$HCTOSYS_DEVICE --hctosys $HWCLOCKPARS $BADYEAR; then + # Announce the local time. + verbose_log_action_msg "System Clock set to: `date $UTC`" + else + log_warning_msg "Unable to set System Clock to: `date $UTC`" + fi + else + verbose_log_action_msg "Not setting System Clock" + fi + ;; + stop|restart|reload|force-reload) + # + # Updates the Hardware Clock with the System Clock time. + # This will *override* any changes made to the Hardware Clock. + # + # WARNING: If you disable this, any changes to the system + # clock will not be carried across reboots. + # + + if [ "$HWCLOCKACCESS" != no ]; then + log_action_msg "Saving the system clock" + if /sbin/hwclock --rtc=/dev/$HCTOSYS_DEVICE --systohc $HWCLOCKPARS $BADYEAR; then + verbose_log_action_msg "Hardware Clock updated to `date`" + fi + else + verbose_log_action_msg "Not saving System Clock" + fi + ;; + show) + if [ "$HWCLOCKACCESS" != no ]; then + /sbin/hwclock --rtc=/dev/$HCTOSYS_DEVICE --show $HWCLOCKPARS $BADYEAR + fi + ;; + *) + log_success_msg "Usage: hwclock.sh {start|stop|reload|force-reload|show}" + log_success_msg " start sets kernel (system) clock from hardware (RTC) clock" + log_success_msg " stop and reload set hardware (RTC) clock from kernel (system) clock" + return 1 + ;; + esac +} + +hwclocksh "$@" diff --git a/init.d/keyboard-setup.sh b/init.d/keyboard-setup.sh new file mode 100755 index 00000000..f1ab5bae --- /dev/null +++ b/init.d/keyboard-setup.sh @@ -0,0 +1,50 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: keyboard-setup.sh +# Required-Start: mountkernfs +# Required-Stop: +# X-Start-Before: checkroot +# Default-Start: S +# Default-Stop: +# X-Interactive: true +# Short-Description: Set the console keyboard layout +# Description: Set the console keyboard as early as possible +# so during the file systems checks the administrator +# can interact. At this stage of the boot process +# only the ASCII symbols are supported. +### END INIT INFO + +if [ -f /bin/setupcon ]; then + case "$1" in + stop|status) + # console-setup isn't a daemon + ;; + start|force-reload|restart|reload) + if [ -f /lib/lsb/init-functions ]; then + . /lib/lsb/init-functions + else + log_action_begin_msg () { + echo -n "$@... " + } + + log_action_end_msg () { + if [ "$1" -eq 0 ]; then + echo done. + else + echo failed. + fi + } + fi + log_action_begin_msg "Setting up keyboard layout" + if /lib/console-setup/keyboard-setup.sh; then + log_action_end_msg 0 + else + log_action_end_msg $? + fi + ;; + *) + echo 'Usage: /etc/init.d/keyboard-setup {start|reload|restart|force-reload|stop|status}' + exit 3 + ;; + esac +fi diff --git a/init.d/kmod b/init.d/kmod new file mode 100755 index 00000000..d7ec083c --- /dev/null +++ b/init.d/kmod @@ -0,0 +1,92 @@ +#!/bin/sh -e +### BEGIN INIT INFO +# Provides: kmod +# Required-Start: +# Required-Stop: +# Should-Start: checkroot +# Should-Stop: +# Default-Start: S +# Default-Stop: +# Short-Description: Load the modules listed in /etc/modules. +# Description: Load the modules listed in /etc/modules. +### END INIT INFO + +# Silently exit if the kernel does not support modules. +[ -f /proc/modules ] || exit 0 +[ -x /sbin/modprobe ] || exit 0 + +[ -f /etc/default/rcS ] && . /etc/default/rcS +. /lib/lsb/init-functions + +PATH='/sbin:/bin' + +case "$1" in + start) + ;; + + stop|restart|reload|force-reload) + log_warning_msg "Action '$1' is meaningless for this init script" + exit 0 + ;; + + *) + log_success_msg "Usage: $0 start" + exit 1 +esac + +load_module() { + local module args + module="$1" + args="$2" + + if [ "$VERBOSE" != no ]; then + log_action_msg "Loading kernel module $module" + modprobe $module $args || true + else + modprobe $module $args > /dev/null 2>&1 || true + fi +} + +modules_files() { + local modules_load_dirs='/etc/modules-load.d /run/modules-load.d /usr/local/lib/modules-load.d /usr/lib/modules-load.d /lib/modules-load.d' + local processed=' ' + local add_etc_modules=true + + for dir in $modules_load_dirs; do + [ -d $dir ] || continue + for file in $(run-parts --list --regex='\.conf$' $dir 2> /dev/null || true); do + local base=${file##*/} + if echo -n "$processed" | grep -qF " $base "; then + continue + fi + if [ "$add_etc_modules" -a -L $file \ + -a "$(readlink -f $file)" = /etc/modules ]; then + add_etc_modules= + fi + processed="$processed$base " + echo $file + done + done + + if [ "$add_etc_modules" ]; then + echo /etc/modules + fi +} + +if [ "$VERBOSE" = no ]; then + log_action_begin_msg 'Loading kernel modules' +fi + +files=$(modules_files) +if [ "$files" ] ; then + grep -h '^[^#]' $files | + while read module args; do + [ "$module" ] || continue + load_module "$module" "$args" + done +fi + +if [ "$VERBOSE" = no ]; then + log_action_end_msg 0 +fi + diff --git a/init.d/mosquitto b/init.d/mosquitto new file mode 100755 index 00000000..97282e1b --- /dev/null +++ b/init.d/mosquitto @@ -0,0 +1,138 @@ +#! /bin/sh + +### BEGIN INIT INFO +# Provides: mosquitto +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: mosquitto MQTT v3.1 message broker +# Description: +# This is a message broker that supports version 3.1 of the MQ Telemetry +# Transport (MQTT) protocol. +# +# MQTT provides a method of carrying out messaging using a publish/subscribe +# model. It is lightweight, both in terms of bandwidth usage and ease of +# implementation. This makes it particularly useful at the edge of the network +# where a sensor or other simple device may be implemented using an arduino for +# example. +### END INIT INFO + +set -e + +PIDFILE=/var/run/mosquitto.pid +DAEMON=/usr/sbin/mosquitto + +# /etc/init.d/mosquitto: start and stop the mosquitto MQTT message broker + +test -x ${DAEMON} || exit 0 + +umask 022 + +. /lib/lsb/init-functions + +# Are we running from init? +run_by_init() { + ([ "$previous" ] && [ "$runlevel" ]) || [ "$runlevel" = S ] +} + +export PATH="${PATH:+$PATH:}/usr/sbin:/sbin" + +case "$1" in + start) + if init_is_upstart; then + exit 1 + fi + log_daemon_msg "Starting network daemon:" "mosquitto" + if start-stop-daemon --start --quiet --oknodo --background --make-pidfile --pidfile ${PIDFILE} --exec ${DAEMON} -- -c /etc/mosquitto/mosquitto.conf ; then + log_end_msg 0 + else + log_end_msg 1 + fi + ;; + stop) + if init_is_upstart; then + exit 0 + fi + log_daemon_msg "Stopping network daemon:" "mosquitto" + if start-stop-daemon --stop --quiet --oknodo --pidfile ${PIDFILE}; then + log_end_msg 0 + rm -f ${PIDFILE} + else + log_end_msg 1 + fi + ;; + + + reload|force-reload) + if init_is_upstart; then + exit 1 + fi + log_daemon_msg "Reloading network daemon configuration:" "mosquitto" + if start-stop-daemon --stop --signal HUP --quiet --oknodo --pidfile $PIDFILE; then + log_end_msg 0 + else + log_end_msg 1 + fi + ;; + + restart) + if init_is_upstart; then + exit 1 + fi + log_daemon_msg "Restarting network daemon:" "mosquitto" + if start-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile ${PIDFILE}; then + rm -f ${PIDFILE} + fi + if start-stop-daemon --start --quiet --oknodo --background --make-pidfile --pidfile ${PIDFILE} --exec ${DAEMON} -- -c /etc/mosquitto/mosquitto.conf ; then + log_end_msg 0 + else + log_end_msg 1 + fi + ;; + + try-restart) + if init_is_upstart; then + exit 1 + fi + log_daemon_msg "Restarting Mosquitto message broker" "mosquitto" + set +e + start-stop-daemon --stop --quiet --retry 30 --pidfile ${PIDFILE} + RET="$?" + set -e + case $RET in + 0) + # old daemon stopped + rm -f ${PIDFILE} + if start-stop-daemon --start --quiet --oknodo --background --make-pidfile --pidfile ${PIDFILE} --exec ${DAEMON} -- -c /etc/mosquitto/mosquitto.conf ; then + log_end_msg 0 + else + log_end_msg 1 + fi + ;; + 1) + # daemon not running + log_progress_msg "(not running)" + log_end_msg 0 + ;; + *) + # failed to stop + log_progress_msg "(failed to stop)" + log_end_msg 1 + ;; + esac + ;; + + status) + if init_is_upstart; then + exit 1 + fi + status_of_proc -p ${PIDFILE} ${DAEMON} mosquitto && exit 0 || exit $? + ;; + + *) + log_action_msg "Usage: /etc/init.d/mosquitto {start|stop|reload|force-reload|restart|try-restart|status}" + exit 1 +esac + +exit 0 diff --git a/init.d/netfilter-persistent b/init.d/netfilter-persistent new file mode 100755 index 00000000..1b4f1c0a --- /dev/null +++ b/init.d/netfilter-persistent @@ -0,0 +1,50 @@ +#!/bin/sh + +# This file is part of netfilter-persistent +# Copyright (C) 2014 Jonathan Wiltshire +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, either version 3 +# of the License, or (at your option) any later version. + +### BEGIN INIT INFO +# Provides: netfilter-persistent +# Required-Start: mountkernfs $remote_fs +# Required-Stop: $remote_fs +# Default-Start: S +# Default-Stop: 0 1 6 +# Short-Description: Load boot-time netfilter configuration +# Description: Loads boot-time netfilter configuration +### END INIT INFO + +. /lib/lsb/init-functions + +case "$1" in +start|restart|reload|force-reload) + log_action_begin_msg "Loading netfilter rules" + /usr/sbin/netfilter-persistent start + log_action_end_msg $? + ;; +save) + log_action_begin_msg "Saving netfilter rules" + /usr/sbin/netfilter-persistent save + log_action_end_msg $? + ;; +stop) + log_action_begin_msg "Stopping netfilter rules" + /usr/sbin/netfilter-persistent stop + log_action_end_msg $? + ;; +flush) + log_action_begin_msg "Flushing netfilter rules" + /usr/sbin/netfilter-persistent flush + log_action_end_msg $? + ;; +*) + echo "Usage: $0 {start|restart|reload|force-reload|save|flush}" >&2 + exit 1 + ;; +esac + +exit $rc diff --git a/init.d/networking b/init.d/networking new file mode 100755 index 00000000..b5380511 --- /dev/null +++ b/init.d/networking @@ -0,0 +1,195 @@ +#!/bin/sh -e +### BEGIN INIT INFO +# Provides: networking ifupdown +# Required-Start: mountkernfs $local_fs urandom +# Required-Stop: $local_fs +# Default-Start: S +# Default-Stop: 0 6 +# Short-Description: Raise network interfaces. +# Description: Prepare /run/network directory, ifstate file and raise network interfaces, or take them down. +### END INIT INFO + +PATH="/sbin:/bin" +RUN_DIR="/run/network" +IFSTATE="$RUN_DIR/ifstate" +STATEDIR="$RUN_DIR/state" + +[ -x /sbin/ifup ] || exit 0 +[ -x /sbin/ifdown ] || exit 0 + +. /lib/lsb/init-functions + +CONFIGURE_INTERFACES=yes +EXCLUDE_INTERFACES= +VERBOSE=no + +[ -f /etc/default/networking ] && . /etc/default/networking + +verbose="" +[ "$VERBOSE" = yes ] && verbose=-v + +process_exclusions() { + set -- $EXCLUDE_INTERFACES + exclusions="" + for d + do + exclusions="-X $d $exclusions" + done + echo $exclusions +} + +process_options() { + [ -e /etc/network/options ] || return 0 + log_warning_msg "/etc/network/options still exists and it will be IGNORED! Please use /etc/sysctl.conf instead." +} + +check_ifstate() { + if [ ! -d "$RUN_DIR" ] ; then + if ! mkdir -p "$RUN_DIR" ; then + log_failure_msg "can't create $RUN_DIR" + exit 1 + fi + if ! chown root:netdev "$RUN_DIR" ; then + log_warning_msg "can't chown $RUN_DIR" + fi + fi + if [ ! -r "$IFSTATE" ] ; then + if ! :> "$IFSTATE" ; then + log_failure_msg "can't initialise $IFSTATE" + exit 1 + fi + fi +} + +check_network_file_systems() { + [ -e /proc/mounts ] || return 0 + + if [ -e /etc/iscsi/iscsi.initramfs ]; then + log_warning_msg "not deconfiguring network interfaces: iSCSI root is mounted." + exit 0 + fi + + while read DEV MTPT FSTYPE REST; do + case $DEV in + /dev/nbd*|/dev/nd[a-z]*|/dev/etherd/e*|curlftpfs*) + log_warning_msg "not deconfiguring network interfaces: network devices still mounted." + exit 0 + ;; + esac + case $FSTYPE in + nfs|nfs4|smbfs|ncp|ncpfs|cifs|coda|ocfs2|gfs|pvfs|pvfs2|fuse.httpfs|fuse.curlftpfs) + log_warning_msg "not deconfiguring network interfaces: network file systems still mounted." + exit 0 + ;; + esac + done < /proc/mounts +} + +check_network_swap() { + [ -e /proc/swaps ] || return 0 + + while read DEV MTPT FSTYPE REST; do + case $DEV in + /dev/nbd*|/dev/nd[a-z]*|/dev/etherd/e*) + log_warning_msg "not deconfiguring network interfaces: network swap still mounted." + exit 0 + ;; + esac + done < /proc/swaps +} + +ifup_hotplug () { + if [ -d /sys/class/net ] + then + ifaces=$(for iface in $(ifquery --list --allow=hotplug) + do + link=${iface##:*} + link=${link##.*} + if [ -e "/sys/class/net/$link" ] + then + echo "$iface" + fi + done) + if [ -n "$ifaces" ] + then + ifup $ifaces "$@" || true + fi + fi +} + +case "$1" in +start) + process_options + check_ifstate + + if [ "$CONFIGURE_INTERFACES" = no ] + then + log_action_msg "Not configuring network interfaces, see /etc/default/networking" + exit 0 + fi + set -f + exclusions=$(process_exclusions) + log_action_begin_msg "Configuring network interfaces" + if [ -x /bin/udevadm ]; then + if [ -n "$(ifquery --list --exclude=lo)" ] || [ -n "$(ifquery --list --allow=hotplug)" ]; then + /bin/udevadm settle || true + fi + fi + if ifup -a $exclusions $verbose && ifup_hotplug $exclusions $verbose + then + log_action_end_msg $? + else + log_action_end_msg $? + fi + ;; + +stop) + check_network_file_systems + check_network_swap + + log_action_begin_msg "Deconfiguring network interfaces" + if ifdown -a --exclude=lo $verbose; then + log_action_end_msg $? + else + log_action_end_msg $? + fi + ;; + +reload) + process_options + + log_action_begin_msg "Reloading network interfaces configuration" + state=$(ifquery --state) + ifdown -a --exclude=lo $verbose || true + if ifup --exclude=lo $state $verbose ; then + log_action_end_msg $? + else + log_action_end_msg $? + fi + ;; + +force-reload|restart) + process_options + + log_warning_msg "Running $0 $1 is deprecated because it may not re-enable some interfaces" + log_action_begin_msg "Reconfiguring network interfaces" + ifdown -a --exclude=lo $verbose || true + set -f + exclusions=$(process_exclusions) + if ifup -a --exclude=lo $exclusions $verbose && ifup_hotplug $exclusions $verbose + then + log_action_end_msg $? + else + log_action_end_msg $? + fi + ;; + +*) + echo "Usage: /etc/init.d/networking {start|stop|reload|restart|force-reload}" + exit 1 + ;; +esac + +exit 0 + +# vim: noet ts=8 diff --git a/init.d/nfs-common b/init.d/nfs-common new file mode 100755 index 00000000..052de51a --- /dev/null +++ b/init.d/nfs-common @@ -0,0 +1,283 @@ +#!/bin/bash + +### BEGIN INIT INFO +# Provides: nfs-common +# Required-Start: $portmap $time +# Required-Stop: $time +# Default-Start: S +# Default-Stop: 0 1 6 +# Short-Description: NFS support files common to client and server +# Description: NFS is a popular protocol for file sharing across +# TCP/IP networks. This service provides various +# support functions for NFS mounts. +### END INIT INFO + +# What is this? +DESC="NFS common utilities" + +# Read config +DEFAULTFILE=/etc/default/nfs-common +NEED_STATD= +NEED_GSSD= +PIPEFS_MOUNTPOINT=/run/rpc_pipefs +RPCGSSDOPTS= +if [ -f $DEFAULTFILE ]; then + . $DEFAULTFILE +fi + +. /lib/lsb/init-functions + +# Exit if required binaries are missing. +[ -x /sbin/rpc.statd ] || exit 0 + +# +# Parse the fstab file, and determine whether we need gssd. (The +# /etc/defaults settings, if any, will override our autodetection.) This code +# is partially adapted from the mountnfs.sh script in the sysvinit package. +# +AUTO_NEED_GSSD=no + +if [ -f /etc/fstab ]; then + exec 9<&0 /dev/null 2>&1 + RET=$? + if [ $RET != 0 ]; then + echo + log_warning_msg "Not starting: portmapper is not running" + exit 0 + fi + fi + start-stop-daemon --start --oknodo --quiet \ + --pidfile /run/rpc.statd.pid \ + --exec /sbin/rpc.statd -- $STATDOPTS + RET=$? + if [ $RET != 0 ]; then + log_end_msg $RET + exit $RET + else + if [ -d /run/sendsigs.omit.d ]; then + rm -f /run/sendsigs.omit.d/statd + ln -s /run/rpc.statd.pid /run/sendsigs.omit.d/statd + fi + fi + fi + + # Don't start idmapd and gssd if we don't have them (say, if /usr is not + # up yet). + [ -x /usr/sbin/rpc.idmapd ] || NEED_IDMAPD=no + [ -x /usr/sbin/rpc.gssd ] || NEED_GSSD=no + + if [ "$NEED_IDMAPD" = yes ] || [ "$NEED_GSSD" = yes ] + then + do_modprobe sunrpc + do_modprobe nfs + do_modprobe nfsd + mkdir -p "$PIPEFS_MOUNTPOINT" + if do_mount rpc_pipefs $PIPEFS_MOUNTPOINT + then + if [ "$NEED_IDMAPD" = yes ] + then + log_progress_msg "idmapd" + start-stop-daemon --start --oknodo --quiet \ + --exec /usr/sbin/rpc.idmapd + RET=$? + if [ $RET != 0 ]; then + log_end_msg $RET + exit $RET + fi + fi + if [ "$NEED_GSSD" = yes ] + then + do_modprobe rpcsec_gss_krb5 + log_progress_msg "gssd" + + # we need this available; better to fail now than + # mysteriously on the first mount + if ! grep -q -E '^nfs[ ]' /etc/services; then + log_action_end_msg 1 "broken /etc/services, please see /usr/share/doc/nfs-common/README.Debian.nfsv4" + exit 1 + fi + + start-stop-daemon --start --oknodo --quiet \ + --exec /usr/sbin/rpc.gssd -- $RPCGSSDOPTS + RET=$? + if [ $RET != 0 ]; then + log_end_msg $RET + exit $RET + fi + fi + fi + fi + log_end_msg 0 + ;; + + stop) + log_daemon_msg "Stopping $DESC" + + if [ "$NEED_GSSD" = yes ] + then + log_progress_msg "gssd" + start-stop-daemon --stop --oknodo --quiet \ + --name rpc.gssd + RET=$? + if [ $RET != 0 ]; then + log_end_msg $RET + exit $RET + fi + fi + if [ "$NEED_IDMAPD" = yes ] + then + log_progress_msg "idmapd" + start-stop-daemon --stop --oknodo --quiet \ + --name rpc.idmapd + RET=$? + if [ $RET != 0 ]; then + log_end_msg $RET + exit $RET + fi + fi + if [ "$NEED_STATD" = yes ] + then + log_progress_msg "statd" + start-stop-daemon --stop --oknodo --quiet \ + --name rpc.statd + RET=$? + if [ $RET != 0 ]; then + log_end_msg $RET + exit $RET + fi + fi + do_umount $PIPEFS_MOUNTPOINT 2>/dev/null || true + log_end_msg 0 + ;; + + status) + if [ "$NEED_STATD" = yes ] + then + if ! pidof rpc.statd >/dev/null + then + echo "rpc.statd not running" + exit 3 + fi + fi + + if [ "$NEED_GSSD" = yes ] + then + if ! pidof rpc.gssd >/dev/null + then + echo "rpc.gssd not running" + exit 3 + fi + fi + + if [ "$NEED_IDMAPD" = yes ] + then + if ! pidof rpc.idmapd >/dev/null + then + echo "rpc.idmapd not running" + exit 3 + fi + fi + + echo "all daemons running" + exit 0 + ;; + + restart | force-reload) + $0 stop + sleep 1 + $0 start + ;; + + *) + log_success_msg "Usage: nfs-common {start|stop|status|restart}" + exit 1 + ;; +esac + +exit 0 diff --git a/init.d/nginx b/init.d/nginx new file mode 100755 index 00000000..db10b7df --- /dev/null +++ b/init.d/nginx @@ -0,0 +1,196 @@ +#!/bin/sh + +### BEGIN INIT INFO +# Provides: nginx +# Required-Start: $local_fs $remote_fs $network $syslog $named +# Required-Stop: $local_fs $remote_fs $network $syslog $named +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: starts the nginx web server +# Description: starts nginx using start-stop-daemon +### END INIT INFO + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/nginx +NAME=nginx +DESC=nginx + +# Include nginx defaults if available +if [ -r /etc/default/nginx ]; then + . /etc/default/nginx +fi + +STOP_SCHEDULE="${STOP_SCHEDULE:-QUIT/5/TERM/5/KILL/5}" + +test -x $DAEMON || exit 0 + +. /lib/init/vars.sh +. /lib/lsb/init-functions + +# Try to extract nginx pidfile +PID=$(cat /etc/nginx/nginx.conf | grep -Ev '^\s*#' | awk 'BEGIN { RS="[;{}]" } { if ($1 == "pid") print $2 }' | head -n1) +if [ -z "$PID" ]; then + PID=/run/nginx.pid +fi + +if [ -n "$ULIMIT" ]; then + # Set ulimit if it is set in /etc/default/nginx + ulimit $ULIMIT +fi + +start_nginx() { + # Start the daemon/service + # + # Returns: + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + start-stop-daemon --start --quiet --pidfile $PID --exec $DAEMON --test > /dev/null \ + || return 1 + start-stop-daemon --start --quiet --pidfile $PID --exec $DAEMON -- \ + $DAEMON_OPTS 2>/dev/null \ + || return 2 +} + +test_config() { + # Test the nginx configuration + $DAEMON -t $DAEMON_OPTS >/dev/null 2>&1 +} + +stop_nginx() { + # Stops the daemon/service + # + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + start-stop-daemon --stop --quiet --retry=$STOP_SCHEDULE --pidfile $PID --name $NAME + RETVAL="$?" + sleep 1 + return "$RETVAL" +} + +reload_nginx() { + # Function that sends a SIGHUP to the daemon/service + start-stop-daemon --stop --signal HUP --quiet --pidfile $PID --name $NAME + return 0 +} + +rotate_logs() { + # Rotate log files + start-stop-daemon --stop --signal USR1 --quiet --pidfile $PID --name $NAME + return 0 +} + +upgrade_nginx() { + # Online upgrade nginx executable + # http://nginx.org/en/docs/control.html + # + # Return + # 0 if nginx has been successfully upgraded + # 1 if nginx is not running + # 2 if the pid files were not created on time + # 3 if the old master could not be killed + if start-stop-daemon --stop --signal USR2 --quiet --pidfile $PID --name $NAME; then + # Wait for both old and new master to write their pid file + while [ ! -s "${PID}.oldbin" ] || [ ! -s "${PID}" ]; do + cnt=`expr $cnt + 1` + if [ $cnt -gt 10 ]; then + return 2 + fi + sleep 1 + done + # Everything is ready, gracefully stop the old master + if start-stop-daemon --stop --signal QUIT --quiet --pidfile "${PID}.oldbin" --name $NAME; then + return 0 + else + return 3 + fi + else + return 1 + fi +} + +case "$1" in + start) + log_daemon_msg "Starting $DESC" "$NAME" + start_nginx + case "$?" in + 0|1) log_end_msg 0 ;; + 2) log_end_msg 1 ;; + esac + ;; + stop) + log_daemon_msg "Stopping $DESC" "$NAME" + stop_nginx + case "$?" in + 0|1) log_end_msg 0 ;; + 2) log_end_msg 1 ;; + esac + ;; + restart) + log_daemon_msg "Restarting $DESC" "$NAME" + + # Check configuration before stopping nginx + if ! test_config; then + log_end_msg 1 # Configuration error + exit $? + fi + + stop_nginx + case "$?" in + 0|1) + start_nginx + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + reload|force-reload) + log_daemon_msg "Reloading $DESC configuration" "$NAME" + + # Check configuration before stopping nginx + # + # This is not entirely correct since the on-disk nginx binary + # may differ from the in-memory one, but that's not common. + # We prefer to check the configuration and return an error + # to the administrator. + if ! test_config; then + log_end_msg 1 # Configuration error + exit $? + fi + + reload_nginx + log_end_msg $? + ;; + configtest|testconfig) + log_daemon_msg "Testing $DESC configuration" + test_config + log_end_msg $? + ;; + status) + status_of_proc -p $PID "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + upgrade) + log_daemon_msg "Upgrading binary" "$NAME" + upgrade_nginx + log_end_msg $? + ;; + rotate) + log_daemon_msg "Re-opening $DESC log files" "$NAME" + rotate_logs + log_end_msg $? + ;; + *) + echo "Usage: $NAME {start|stop|restart|reload|force-reload|status|configtest|rotate|upgrade}" >&2 + exit 3 + ;; +esac diff --git a/init.d/ntp b/init.d/ntp new file mode 100755 index 00000000..0e599ab2 --- /dev/null +++ b/init.d/ntp @@ -0,0 +1,72 @@ +#!/bin/sh + +### BEGIN INIT INFO +# Provides: ntp +# Required-Start: $network $remote_fs $syslog +# Required-Stop: $network $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: +# Short-Description: Start NTP daemon +### END INIT INFO + +PATH=/sbin:/bin:/usr/sbin:/usr/bin + +. /lib/lsb/init-functions + +DAEMON=/usr/sbin/ntpd +PIDFILE=/var/run/ntpd.pid + +test -x $DAEMON || exit 0 + +if [ -r /etc/default/ntp ]; then + . /etc/default/ntp +fi + +if [ -e /run/ntp.conf.dhcp ]; then + NTPD_OPTS="$NTPD_OPTS -c /run/ntp.conf.dhcp" +fi + + +RUNASUSER=ntp +UGID=$(getent passwd $RUNASUSER | cut -f 3,4 -d:) || true +if test "$(uname -s)" = "Linux"; then + NTPD_OPTS="$NTPD_OPTS -u $UGID" +fi + +case $1 in + start) + log_daemon_msg "Starting NTP server" "ntpd" + if [ -z "$UGID" ]; then + log_failure_msg "user \"$RUNASUSER\" does not exist" + exit 1 + fi + start-stop-daemon --start --quiet --oknodo --pidfile $PIDFILE --startas $DAEMON -- -p $PIDFILE $NTPD_OPTS + log_end_msg $? + ;; + stop) + log_daemon_msg "Stopping NTP server" "ntpd" + start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE --retry=TERM/30/KILL/5 --exec $DAEMON + log_end_msg $? + rm -f $PIDFILE + ;; + restart|force-reload) + $0 stop && sleep 2 && $0 start + ;; + try-restart) + if $0 status >/dev/null; then + $0 restart + else + exit 0 + fi + ;; + reload) + exit 3 + ;; + status) + status_of_proc $DAEMON "NTP server" + ;; + *) + echo "Usage: $0 {start|stop|restart|try-restart|force-reload|status}" + exit 2 + ;; +esac diff --git a/init.d/paxctld b/init.d/paxctld new file mode 100755 index 00000000..11326b41 --- /dev/null +++ b/init.d/paxctld @@ -0,0 +1,125 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: paxctld +# Required-Start: $local_fs $network $remote_fs $syslog +# Required-Stop: $local_fs $network $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +### END INIT INFO + +# Author: Brad Spengler + +# Do NOT "set -e" + +# PATH should only include /usr/* if it runs after the mountnfs.sh script +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="PaX flags maintenance daemon" +NAME=paxctld +DAEMON=/sbin/paxctld +PIDFILE=/var/run/$NAME.pid +DAEMON_ARGS="-d -p $PIDFILE" +SCRIPTNAME=/etc/init.d/$NAME + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.2-14) to ensure that this file is present +# and status_of_proc is working. +. /lib/lsb/init-functions + +check_for_upstart() { + if init_is_upstart; then + exit $1 + fi +} + +# +# Function that starts the daemon/service +# +do_start() +{ + # Return + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ + || return 1 + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ + $DAEMON_ARGS \ + || return 2 +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME + RETVAL="$?" + [ "$RETVAL" = 2 ] && return 2 + start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON + [ "$?" = 2 ] && return 2 + # Many daemons don't delete their pidfiles when they exit. + rm -f $PIDFILE + return "$RETVAL" +} + +case "$1" in + start) + check_for_upstart 1 + log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) log_end_msg 0 ;; + 2) log_end_msg 1 ;; + esac + ;; + stop) + check_for_upstart 0 + log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) log_end_msg 0 ;; + 2) log_end_msg 1 ;; + esac + ;; + status) + check_for_upstart 1 + status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + restart|force-reload) + check_for_upstart 1 + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 + echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 + exit 3 + ;; +esac + +: diff --git a/init.d/php7.3-fpm b/init.d/php7.3-fpm new file mode 100755 index 00000000..088c8b03 --- /dev/null +++ b/init.d/php7.3-fpm @@ -0,0 +1,191 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: php7.3-fpm +# Required-Start: $remote_fs $network +# Required-Stop: $remote_fs $network +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: starts php7.3-fpm +# Description: Starts The PHP FastCGI Process Manager Daemon +### END INIT INFO + +# Author: Ondrej Sury + +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="PHP 7.3 FastCGI Process Manager" +NAME=php-fpm7.3 +CONFFILE=/etc/php/7.3/fpm/php-fpm.conf +DAEMON=/usr/sbin/$NAME +DAEMON_ARGS="--daemonize --fpm-config $CONFFILE" +CONF_PIDFILE=$(sed -n 's/^pid[ =]*//p' $CONFFILE) +PIDFILE=${CONF_PIDFILE:-/run/php/php7.3-fpm.pid} +TIMEOUT=30 +SCRIPTNAME=/etc/init.d/$NAME + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Read configuration variable file if it is present +[ -r /etc/default/$NAME ] && . /etc/default/$NAME + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.0-6) to ensure that this file is present. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() +{ + # Return + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ + || return 1 + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ + $DAEMON_ARGS 2>/dev/null \ + || return 2 + # Add code here, if necessary, that waits for the process to be ready + # to handle requests from services started subsequently which depend + # on this one. As a last resort, sleep for some time. +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + start-stop-daemon --stop --quiet --retry=QUIT/$TIMEOUT/TERM/5/KILL/5 --pidfile $PIDFILE --name $NAME + RETVAL="$?" + [ "$RETVAL" = 2 ] && return 2 + # Wait for children to finish too if this is a daemon that forks + # and if the daemon is only ever run from this initscript. + # If the above conditions are not satisfied then add some other code + # that waits for the process to drop all resources that could be + # needed by services started subsequently. A last resort is to + # sleep for some time. + start-stop-daemon --stop --quiet --oknodo --retry=0/30/TERM/5/KILL/5 --exec $DAEMON + [ "$?" = 2 ] && return 2 + # Many daemons don't delete their pidfiles when they exit. + rm -f $PIDFILE + return "$RETVAL" +} + +# +# Function that sends a SIGHUP to the daemon/service +# +do_reload() { + # + # If the daemon can reload its configuration without + # restarting (for example, when it is sent a SIGHUP), + # then implement that here. + # + start-stop-daemon --stop --signal USR2 --quiet --pidfile $PIDFILE --name $NAME + return 0 +} + +do_tmpfiles() { + local type path mode user group + + [ "$1" != no ] && V=-v + + TMPFILES=/usr/lib/tmpfiles.d/php7.3-fpm.conf + + if [ -r "$TMPFILES" ]; then + while read type path mode user group age argument; do + if [ "$type" = "d" ]; then + mkdir $V -p "$path" + chmod $V "$mode" "$path" + chown $V "$user:$group" "$path" + fi + done < "$TMPFILES" + fi +} + +case "$1" in + start) + if init_is_upstart; then + exit 1 + fi + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_tmpfiles $VERBOSE + case "$?" in + 0) + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + 1) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + if init_is_upstart; then + exit 0 + fi + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + reload|force-reload) + if init_is_upstart; then + exit 1 + fi + log_daemon_msg "Reloading $DESC" "$NAME" + do_reload + log_end_msg $? + ;; + reopen-logs) + log_daemon_msg "Reopening $DESC logs" $NAME + if start-stop-daemon --stop --signal USR1 --oknodo --quiet \ + --pidfile $PIDFILE --exec $DAEMON + then + log_end_msg 0 + else + log_end_msg 1 + fi + ;; + restart) + if init_is_upstart; then + exit 1 + fi + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|status|restart|reload|force-reload}" >&2 + exit 1 + ;; +esac + +: diff --git a/init.d/postgresql b/init.d/postgresql new file mode 100755 index 00000000..579fdd2f --- /dev/null +++ b/init.d/postgresql @@ -0,0 +1,61 @@ +#!/bin/sh +set -e + +### BEGIN INIT INFO +# Provides: postgresql +# Required-Start: $local_fs $remote_fs $network $time +# Required-Stop: $local_fs $remote_fs $network $time +# Should-Start: $syslog +# Should-Stop: $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: PostgreSQL RDBMS server +### END INIT INFO + +# Setting environment variables for the postmaster here does not work; please +# set them in /etc/postgresql///environment instead. + +[ -r /usr/share/postgresql-common/init.d-functions ] || exit 0 + +. /usr/share/postgresql-common/init.d-functions + +# versions can be specified explicitly +if [ -n "$2" ]; then + versions="$2 $3 $4 $5 $6 $7 $8 $9" +else + get_versions +fi + +case "$1" in + start|stop|restart|reload) + if [ "$1" = "start" ]; then + create_socket_directory + fi + if [ -z "`pg_lsclusters -h`" ]; then + log_warning_msg 'No PostgreSQL clusters exist; see "man pg_createcluster"' + exit 0 + fi + for v in $versions; do + $1 $v || EXIT=$? + done + exit ${EXIT:-0} + ;; + status) + LS=`pg_lsclusters -h` + # no clusters -> unknown status + [ -n "$LS" ] || exit 4 + echo "$LS" | awk 'BEGIN {rc=0} {if (match($4, "down")) rc=3; printf ("%s/%s (port %s): %s\n", $1, $2, $3, $4)}; END {exit rc}' + ;; + force-reload) + for v in $versions; do + reload $v + done + ;; + *) + echo "Usage: $0 {start|stop|restart|reload|force-reload|status} [version ..]" + exit 1 + ;; +esac + +exit 0 + diff --git a/init.d/procps b/init.d/procps new file mode 100755 index 00000000..4d7f4ceb --- /dev/null +++ b/init.d/procps @@ -0,0 +1,34 @@ +#! /bin/sh +# kFreeBSD do not accept scripts as interpreters, using #!/bin/sh and sourcing. +if [ true != "$INIT_D_SCRIPT_SOURCED" ] ; then + set "$0" "$@"; INIT_D_SCRIPT_SOURCED=true . /lib/init/init-d-script +fi +### BEGIN INIT INFO +# Provides: procps +# Required-Start: mountkernfs $local_fs +# Required-Stop: +# Should-Start: udev module-init-tools +# X-Start-Before: $network +# Default-Start: S +# Default-Stop: +# Short-Description: Configure kernel parameters at boottime +# Description: Loads kernel parameters that are specified in /etc/sysctl.conf +### END INIT INFO +# +# written by Elrond + +DESC="Setting kernel variables" +DAEMON=/sbin/sysctl +PIDFILE=none + +# Comment this out for sysctl to print every item changed +QUIET_SYSCTL="-q" + +do_start_cmd() { + STATUS=0 + $DAEMON $QUIET_SYSCTL --system || STATUS=$? + return $STATUS +} + +do_stop() { return 0; } +do_status() { return 0; } diff --git a/init.d/raspi-config b/init.d/raspi-config new file mode 100755 index 00000000..886273b1 --- /dev/null +++ b/init.d/raspi-config @@ -0,0 +1,42 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: raspi-config +# Required-Start: udev mountkernfs $remote_fs +# Required-Stop: +# Default-Start: S 2 3 4 5 +# Default-Stop: +# Short-Description: Switch to ondemand cpu governor (unless shift key is pressed) +# Description: +### END INIT INFO + +. /lib/lsb/init-functions + +case "$1" in + start) + log_daemon_msg "Checking if shift key is held down" + if [ -x /usr/sbin/thd ] && timeout 1 thd --dump /dev/input/event* | grep -q "LEFTSHIFT\|RIGHTSHIFT"; then + printf " Yes. Not enabling ondemand scaling governor" + log_end_msg 0 + else + printf " No. Switching to ondemand scaling governor" + SYS_CPUFREQ_GOVERNOR=/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor + if [ -e $SYS_CPUFREQ_GOVERNOR ]; then + echo "ondemand" > $SYS_CPUFREQ_GOVERNOR + echo 50 > /sys/devices/system/cpu/cpufreq/ondemand/up_threshold + echo 100000 > /sys/devices/system/cpu/cpufreq/ondemand/sampling_rate + echo 50 > /sys/devices/system/cpu/cpufreq/ondemand/sampling_down_factor + fi + log_end_msg 0 + fi + ;; + stop) + ;; + restart) + ;; + force-reload) + ;; + *) + echo "Usage: $0 start" >&2 + exit 3 + ;; +esac diff --git a/init.d/redis-server b/init.d/redis-server new file mode 100755 index 00000000..132fede0 --- /dev/null +++ b/init.d/redis-server @@ -0,0 +1,89 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: redis-server +# Required-Start: $syslog $remote_fs +# Required-Stop: $syslog $remote_fs +# Should-Start: $local_fs +# Should-Stop: $local_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: redis-server - Persistent key-value db +# Description: redis-server - Persistent key-value db +### END INIT INFO + + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/bin/redis-server +DAEMON_ARGS=/etc/redis/redis.conf +NAME=redis-server +DESC=redis-server + +RUNDIR=/var/run/redis +PIDFILE=$RUNDIR/redis-server.pid + +test -x $DAEMON || exit 0 + +if [ -r /etc/default/$NAME ] +then + . /etc/default/$NAME +fi + +. /lib/lsb/init-functions + +set -e + +if [ "$(id -u)" != "0" ] +then + log_failure_msg "Must be run as root." + exit 1 +fi + +case "$1" in + start) + echo -n "Starting $DESC: " + mkdir -p $RUNDIR + touch $PIDFILE + chown redis:redis $RUNDIR $PIDFILE + chmod 755 $RUNDIR + + if [ -n "$ULIMIT" ] + then + ulimit -n $ULIMIT || true + fi + + if start-stop-daemon --start --quiet --oknodo --umask 007 --pidfile $PIDFILE --chuid redis:redis --exec $DAEMON -- $DAEMON_ARGS + then + echo "$NAME." + else + echo "failed" + fi + ;; + stop) + echo -n "Stopping $DESC: " + + if start-stop-daemon --stop --retry forever/TERM/1 --quiet --oknodo --pidfile $PIDFILE --exec $DAEMON + then + echo "$NAME." + else + echo "failed" + fi + rm -f $PIDFILE + sleep 1 + ;; + + restart|force-reload) + ${0} stop + ${0} start + ;; + + status) + status_of_proc -p ${PIDFILE} ${DAEMON} ${NAME} + ;; + + *) + echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload|status}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/init.d/resolvconf b/init.d/resolvconf new file mode 100755 index 00000000..c478014a --- /dev/null +++ b/init.d/resolvconf @@ -0,0 +1,135 @@ +#!/bin/sh +# +### BEGIN INIT INFO +# Provides: resolvconf +# Required-Start: $local_fs +# Required-Stop: $local_fs +# X-Start-Before: networking ifupdown +# Default-Start: S +# Default-Stop: 0 6 +# Short-Description: Nameserver information manager +# Description: This service manages the list of nameserver addresses +# used by the libc resolver and name service caches +### END INIT INFO +# +# This file is part of the resolvconf package. +# +# We really need "X-Stop-Before: networking ifupdown" too because +# terminal ifdowns shouldn't update resolv.conf; +# however there is unfortunately no such thing as "X-Stop-Before". +# +# This file is not used in Ubuntu. +# + +# Don't use set -e; check return status instead. + +[ -x /sbin/resolvconf ] || exit 0 + +PATH=/sbin:/bin +RUN_DIR=/etc/resolvconf/run +ENABLE_UPDATES_FLAGFILE="${RUN_DIR}/enable-updates" +POSTPONED_UPDATE_FLAGFILE="${RUN_DIR}/postponed-update" + +. /lib/lsb/init-functions + +# Abort if Upstart is in use, as per Policy §9.11.1. +case "$1" in + start|restart|force-reload) + init_is_upstart && exit 1 + ;; + stop) + init_is_upstart && exit 0 + ;; +esac + +# $1 EXITSTATUS +# [$2 MESSAGE] +log_action_end_msg_and_exit() +{ + log_action_end_msg "$1" ${2:+"$2"} + exit $1 +} + +create_runtime_directories() +{ + umask 022 + if [ ! -d "$RUN_DIR" ] ; then + [ -L "$RUN_DIR" ] || log_action_end_msg_and_exit 1 "$RUN_DIR is neither a directory nor a symbolic link" + # It's a symlink. Its target is not a dir. + { RUN_CANONICALDIR="$(readlink -f "$RUN_DIR")" && [ "$RUN_CANONICALDIR" ] ; } || log_action_end_msg_and_exit 1 "Canonical path of the run directory could not be determined" + # Create directory at the target + mkdir "$RUN_CANONICALDIR" || log_action_end_msg_and_exit 1 "Error creating directory $RUN_CANONICALDIR" + fi + # The resolvconf run directory now exists. + if [ ! -d "${RUN_DIR}/interface" ] ; then + mkdir "${RUN_DIR}/interface" || log_action_end_msg_and_exit 1 "Error creating directory ${RUN_DIR}/interface" + fi + # The interface directory now exists. We are done. + return +} + +wipe_runtime_directories() +{ + # Delete files in the resolvconf run directory (target) but not the directory itself + [ -d "$RUN_DIR" ] || return + rm -f "$RUN_DIR"/resolv.conf + rm -f "$ENABLE_UPDATES_FLAGFILE" + rm -f "$POSTPONED_UPDATE_FLAGFILE" + rm -rf "${RUN_DIR}/interface/*" + return +} + +case "$1" in + start) + # The "start" method should only be used at boot time. + # Don't run this on package upgrade, for example. + log_action_begin_msg "Setting up resolvconf" + # Wipe runtime directories in case they aren't on a tmpfs + wipe_runtime_directories + # Create runtime directories in case they are on a tmpfs + create_runtime_directories + # Request a postponed update (needed in case the base file has content). + :> "$POSTPONED_UPDATE_FLAGFILE" || log_action_end_msg_and_exit 1 "failed requesting update" + # Enable updates and perform the postponed update. + resolvconf --enable-updates || log_action_end_msg_and_exit 1 "failed to enable updates" + log_action_end_msg_and_exit 0 + ;; + stop) + # The "stop" method should only be used at shutdown time. + log_action_begin_msg "Stopping resolvconf" + resolvconf --disable-updates || log_action_end_msg_and_exit 1 "failed to disable updates" + log_action_end_msg_and_exit 0 + ;; + restart) + log_action_begin_msg "Restarting resolvconf" + resolvconf --enable-updates || log_action_end_msg_and_exit 1 "failed to enable updates" + log_action_end_msg_and_exit 0 + ;; + reload|force-reload) + resolvconf -u || log_action_end_msg_and_exit 1 "failed to update" + exit 0 + ;; + enable-updates) + resolvconf --enable-updates || log_action_end_msg_and_exit 1 "failed to enable updates" + exit 0 + ;; + disable-updates) + resolvconf --disable-updates || log_action_end_msg_and_exit 1 "failed to disable updates" + exit 0 + ;; + status) + if resolvconf --updates-are-enabled ; then + log_success_msg "resolvconf updates are enabled" + else + log_failure_msg "resolvconf updates are disabled" + fi + exit 0 + ;; + *) + echo "Usage: /etc/init.d/resolvconf {start|stop|restart|reload|force-reload|enable-updates|disable-updates|status}" >&2 + exit 3 + ;; +esac + +# Don't reach here +exit 99 diff --git a/init.d/rng-tools b/init.d/rng-tools new file mode 100755 index 00000000..e66cc2ce --- /dev/null +++ b/init.d/rng-tools @@ -0,0 +1,96 @@ +#! /bin/sh +# +# rng-tools initscript for the rng-tools package +# Copr. 2003 by Henrique de Moraes Holschuh +# Copr. 2002 by Viral Shah +# +### BEGIN INIT INFO +# Provides: rng-tools +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +### END INIT INFO +# +# +# $Id: rng-tools.init,v 1.6.2.10 2008-06-10 19:51:37 hmh Exp $ + +PATH=/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/rngd +NAME=rngd +DESC="Hardware RNG entropy gatherer daemon" +PIDFILE=/var/run/rngd.pid + +DEVICELIST="hwrng hw_random hwrandom intel_rng i810_rng" + +HRNGDEVICE=/dev/hwrng +RNGDOPTIONS= +[ -r /etc/default/rng-tools ] && . /etc/default/rng-tools + +test -f ${DAEMON} || exit 0 + +set -e + +finddevice () { + [ -c "${HRNGDEVICE}" ] && return 0 + for i in ${DEVICELIST} ; do + if [ -c "/dev/$i" ] ; then + HRNGDEVICE="/dev/$i" + return 0 + fi + if [ -c "/dev/misc/$i" ] ; then + HRNGDEVICE="/dev/misc/$i" + return 0 + fi + done + + echo "(Hardware RNG device inode not found)" + echo "$0: Cannot find a hardware RNG device to use." >&2 + exit 1 +} + +START="--start --quiet --pidfile ${PIDFILE} --startas ${DAEMON} --name ${NAME}" +case "$1" in + start) + echo -n "Starting $DESC: " + finddevice + START="${START} -- -r ${HRNGDEVICE} ${RNGDOPTIONS}" + if start-stop-daemon ${START} >/dev/null 2>&1 ; then + echo "${NAME}." + else + if start-stop-daemon --test ${START} >/dev/null 2>&1; then + echo "(failed)." + exit 1 + else + echo "${DAEMON} already running." + exit 0 + fi + fi + ;; + stop) + echo -n "Stopping $DESC: " + if start-stop-daemon --stop --quiet --pidfile ${PIDFILE} \ + --startas ${DAEMON} --retry 10 --name ${NAME} \ + >/dev/null 2>&1 ; then + echo "${NAME}." + else + if start-stop-daemon --test ${START} >/dev/null 2>&1; then + echo "(not running)." + exit 0 + else + echo "(failed)." + exit 1 + fi + fi + ;; + restart|force-reload) + $0 stop + exec $0 start + ;; + *) + echo "Usage: $0 {start|stop|restart|force-reload}" 1>&2 + exit 1 + ;; +esac + +exit 0 diff --git a/init.d/rpcbind b/init.d/rpcbind new file mode 100755 index 00000000..e36578ae --- /dev/null +++ b/init.d/rpcbind @@ -0,0 +1,101 @@ +#!/bin/sh +# +# start/stop rpcbind daemon. + +### BEGIN INIT INFO +# Provides: rpcbind +# Required-Start: $network $local_fs +# Required-Stop: $network $local_fs +# Default-Start: S +# Default-Stop: 0 1 6 +# Short-Description: RPC portmapper replacement +# Description: rpcbind is a server that converts RPC (Remote +# Procedure Call) program numbers into DARPA +# protocol port numbers. It must be running in +# order to make RPC calls. Services that use +# RPC include NFS and NIS. +### END INIT INFO + +test -f /sbin/rpcbind || exit 0 + +. /lib/lsb/init-functions + +OPTIONS="-w" +STATEDIR=/run/rpcbind +PIDFILE=/run/rpcbind.pid + +if [ -f /etc/default/rpcbind ] +then + . /etc/default/rpcbind +elif [ -f /etc/rpcbind.conf ] +then + . /etc/rpcbind.conf +fi + +start () +{ + if [ ! -d $STATEDIR ] ; then + mkdir $STATEDIR + chown _rpc:root $STATEDIR + chmod 0755 $STATEDIR + fi + if [ "$(LC_ALL=C stat -c '%U %g %a %F' "$STATEDIR")" != "_rpc 0 755 directory" ] ; then + log_begin_msg "$STATEDIR not owned by root" + log_end_msg 1 + exit 1 + fi + [ -x /sbin/restorecon ] && /sbin/restorecon $STATEDIR + pid=$( pidofproc /sbin/rpcbind ) + if [ -n "$pid" ] + then + log_action_msg "Already running: rcpbind" + exit 0 + fi + log_daemon_msg "Starting RPC port mapper daemon" "rpcbind" + start-stop-daemon --start --quiet --oknodo --exec /sbin/rpcbind -- "$@" + pid=$( pidofproc /sbin/rpcbind ) + echo -n "$pid" >"$PIDFILE" + # /run/sendsigs.omit.d is created by /etc/init.d/mountkernfs.sh + ln -sf "$PIDFILE" /run/sendsigs.omit.d/rpcbind + log_end_msg $? + +} + +stop () +{ + log_daemon_msg "Stopping RPC port mapper daemon" "rpcbind" + start-stop-daemon --stop --quiet --oknodo --exec /sbin/rpcbind + rm -f "$PIDFILE" + log_end_msg $? +} + +case "$1" in + start) + if init_is_upstart; then + exit 1 + fi + start $OPTIONS + ;; + stop) + if init_is_upstart; then + exit 0 + fi + stop + ;; + restart|force-reload) + if init_is_upstart; then + exit 1 + fi + stop + start $OPTIONS + ;; + status) + status_of_proc /sbin/rpcbind rpcbind && exit 0 || exit $? + ;; + *) + log_success_msg "Usage: /etc/init.d/rpcbind {start|stop|force-reload|restart|status}" + exit 1 + ;; +esac + +exit 0 diff --git a/init.d/rsync b/init.d/rsync new file mode 100755 index 00000000..3cb04477 --- /dev/null +++ b/init.d/rsync @@ -0,0 +1,156 @@ +#! /bin/sh + +### BEGIN INIT INFO +# Provides: rsyncd +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Should-Start: $named autofs +# Default-Start: 2 3 4 5 +# Default-Stop: +# Short-Description: fast remote file copy program daemon +# Description: rsync is a program that allows files to be copied to and +# from remote machines in much the same way as rcp. +# This provides rsyncd daemon functionality. +### END INIT INFO + +set -e + +# /etc/init.d/rsync: start and stop the rsync daemon + +DAEMON=/usr/bin/rsync +RSYNC_ENABLE=false +RSYNC_OPTS='' +RSYNC_DEFAULTS_FILE=/etc/default/rsync +RSYNC_CONFIG_FILE=/etc/rsyncd.conf +RSYNC_PID_FILE=/var/run/rsync.pid +RSYNC_NICE_PARM='' +RSYNC_IONICE_PARM='' + +test -x $DAEMON || exit 0 + +. /lib/lsb/init-functions + +if [ -s $RSYNC_DEFAULTS_FILE ]; then + . $RSYNC_DEFAULTS_FILE + case "x$RSYNC_ENABLE" in + xtrue|xfalse) ;; + xinetd) exit 0 + ;; + *) log_failure_msg "Value of RSYNC_ENABLE in $RSYNC_DEFAULTS_FILE must be either 'true' or 'false';" + log_failure_msg "not starting rsync daemon." + exit 1 + ;; + esac + case "x$RSYNC_NICE" in + x[0-9]|x1[0-9]) RSYNC_NICE_PARM="--nicelevel $RSYNC_NICE";; + x) ;; + *) log_warning_msg "Value of RSYNC_NICE in $RSYNC_DEFAULTS_FILE must be a value between 0 and 19 (inclusive);" + log_warning_msg "ignoring RSYNC_NICE now." + ;; + esac + case "x$RSYNC_IONICE" in + x-c[123]*) RSYNC_IONICE_PARM="$RSYNC_IONICE";; + x) ;; + *) log_warning_msg "Value of RSYNC_IONICE in $RSYNC_DEFAULTS_FILE must be -c1, -c2 or -c3;" + log_warning_msg "ignoring RSYNC_IONICE now." + ;; + esac +fi + +export PATH="${PATH:+$PATH:}/usr/sbin:/sbin" + +rsync_start() { + if [ ! -s "$RSYNC_CONFIG_FILE" ]; then + log_failure_msg "missing or empty config file $RSYNC_CONFIG_FILE" + log_end_msg 1 + exit 0 + fi + # See ionice(1) + if [ -n "$RSYNC_IONICE_PARM" ] && [ -x /usr/bin/ionice ] && + /usr/bin/ionice "$RSYNC_IONICE_PARM" true 2>/dev/null; then + /usr/bin/ionice "$RSYNC_IONICE_PARM" -p$$ > /dev/null 2>&1 + fi + if start-stop-daemon --start --quiet --background \ + --pidfile $RSYNC_PID_FILE --make-pidfile \ + $RSYNC_NICE_PARM --exec $DAEMON \ + -- --no-detach --daemon --config "$RSYNC_CONFIG_FILE" $RSYNC_OPTS + then + rc=0 + sleep 1 + if ! kill -0 $(cat $RSYNC_PID_FILE) >/dev/null 2>&1; then + log_failure_msg "rsync daemon failed to start" + rc=1 + fi + else + rc=1 + fi + if [ $rc -eq 0 ]; then + log_end_msg 0 + else + log_end_msg 1 + rm -f $RSYNC_PID_FILE + fi +} # rsync_start + + +case "$1" in + start) + if "$RSYNC_ENABLE"; then + log_daemon_msg "Starting rsync daemon" "rsync" + if [ -s $RSYNC_PID_FILE ] && kill -0 $(cat $RSYNC_PID_FILE) >/dev/null 2>&1; then + log_progress_msg "apparently already running" + log_end_msg 0 + exit 0 + fi + rsync_start + else + if [ -s "$RSYNC_CONFIG_FILE" ]; then + [ "$VERBOSE" != no ] && log_warning_msg "rsync daemon not enabled in $RSYNC_DEFAULTS_FILE, not starting..." + fi + fi + ;; + stop) + log_daemon_msg "Stopping rsync daemon" "rsync" + start-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile $RSYNC_PID_FILE + RETVAL="$?" + log_end_msg $RETVAL + if [ $RETVAL != 0 ] + then + exit 1 + fi + rm -f $RSYNC_PID_FILE + ;; + + reload|force-reload) + log_warning_msg "Reloading rsync daemon: not needed, as the daemon" + log_warning_msg "re-reads the config file whenever a client connects." + ;; + + restart) + set +e + if $RSYNC_ENABLE; then + log_daemon_msg "Restarting rsync daemon" "rsync" + if [ -s $RSYNC_PID_FILE ] && kill -0 $(cat $RSYNC_PID_FILE) >/dev/null 2>&1; then + start-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile $RSYNC_PID_FILE + else + log_warning_msg "rsync daemon not running, attempting to start." + rm -f $RSYNC_PID_FILE + fi + rsync_start + else + if [ -s "$RSYNC_CONFIG_FILE" ]; then + [ "$VERBOSE" != no ] && log_warning_msg "rsync daemon not enabled in $RSYNC_DEFAULTS_FILE, not starting..." + fi + fi + ;; + + status) + status_of_proc -p $RSYNC_PID_FILE "$DAEMON" rsync + exit $? # notreached due to set -e + ;; + *) + echo "Usage: /etc/init.d/rsync {start|stop|reload|force-reload|restart|status}" + exit 1 +esac + +exit 0 diff --git a/init.d/rsyslog b/init.d/rsyslog new file mode 100755 index 00000000..14017cfc --- /dev/null +++ b/init.d/rsyslog @@ -0,0 +1,129 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: rsyslog +# Required-Start: $remote_fs $time +# Required-Stop: umountnfs $time +# X-Stop-After: sendsigs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: enhanced syslogd +# Description: Rsyslog is an enhanced multi-threaded syslogd. +# It is quite compatible to stock sysklogd and can be +# used as a drop-in replacement. +### END INIT INFO + +# +# Author: Michael Biebl +# + +# PATH should only include /usr/* if it runs after the mountnfs.sh script +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="enhanced syslogd" +NAME=rsyslog + +RSYSLOGD=rsyslogd +DAEMON=/usr/sbin/rsyslogd +PIDFILE=/run/rsyslogd.pid + +SCRIPTNAME=/etc/init.d/$NAME + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Read configuration variable file if it is present +[ -r /etc/default/$NAME ] && . /etc/default/$NAME + +# Define LSB log_* functions. +. /lib/lsb/init-functions + +do_start() +{ + # Return + # 0 if daemon has been started + # 1 if daemon was already running + # other if daemon could not be started or a failure occured + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- $RSYSLOGD_OPTIONS +} + +do_stop() +{ + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # other if daemon could not be stopped or a failure occurred + start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --exec $DAEMON +} + +# +# Tell rsyslogd to close all open files +# +do_rotate() { + start-stop-daemon --stop --signal HUP --quiet --pidfile $PIDFILE --exec $DAEMON +} + +create_xconsole() { + XCONSOLE=/dev/xconsole + if [ "$(uname -s)" != "Linux" ]; then + XCONSOLE=/run/xconsole + ln -sf $XCONSOLE /dev/xconsole + fi + if [ ! -e $XCONSOLE ]; then + mknod -m 640 $XCONSOLE p + chown root:adm $XCONSOLE + [ -x /sbin/restorecon ] && /sbin/restorecon $XCONSOLE + fi +} + +sendsigs_omit() { + OMITDIR=/run/sendsigs.omit.d + mkdir -p $OMITDIR + ln -sf $PIDFILE $OMITDIR/rsyslog +} + +case "$1" in + start) + log_daemon_msg "Starting $DESC" "$RSYSLOGD" + create_xconsole + do_start + case "$?" in + 0) sendsigs_omit + log_end_msg 0 ;; + 1) log_progress_msg "already started" + log_end_msg 0 ;; + *) log_end_msg 1 ;; + esac + + ;; + stop) + log_daemon_msg "Stopping $DESC" "$RSYSLOGD" + do_stop + case "$?" in + 0) log_end_msg 0 ;; + 1) log_progress_msg "already stopped" + log_end_msg 0 ;; + *) log_end_msg 1 ;; + esac + + ;; + rotate) + log_daemon_msg "Closing open files" "$RSYSLOGD" + do_rotate + log_end_msg $? + ;; + restart|force-reload) + $0 stop + $0 start + ;; + try-restart) + $0 status >/dev/null 2>&1 && $0 restart + ;; + status) + status_of_proc -p $PIDFILE $DAEMON $RSYSLOGD && exit 0 || exit $? + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|rotate|restart|force-reload|try-restart|status}" >&2 + exit 3 + ;; +esac + +: diff --git a/init.d/snmpd b/init.d/snmpd new file mode 100755 index 00000000..8bc98561 --- /dev/null +++ b/init.d/snmpd @@ -0,0 +1,42 @@ +#!/bin/sh +# kFreeBSD do not accept scripts as interpreters, using #!/bin/sh and sourcing. +if [ true != "$INIT_D_SCRIPT_SOURCED" ] ; then + set "$0" "$@"; INIT_D_SCRIPT_SOURCED=true . /lib/init/init-d-script +fi +### BEGIN INIT INFO +# Provides: snmpd +# Required-Start: $network $remote_fs $syslog +# Required-Stop: $network $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: SNMP agents +# Description: NET SNMP (Simple Network Management Protocol) Agents +### END INIT INFO +# +# Author: Jochen Friedrich +# + +DESC="SNMP Services" +DAEMON=/usr/sbin/snmpd +PIDFILE="/run/snmpd.pid" + +# Defaults +OLD_MIBS_DIR="/usr/share/mibs/site:/usr/share/snmp/mibs:/usr/share/mibs/iana:/usr/share/mibs/ietf:/usr/share/mibs/netsnmp" +MIBS_DIR="/usr/share/snmp/mibs:/usr/share/snmp/mibs/iana:/usr/share/snmp/mibs/ietf" +export MIBDIRS="$MIBS_DIR:$OLD_MIBS_DIR" + +DEFAULT_SNMPDOPTS="-Lsd -Lf /dev/null -u Debian-snmp -g Debian-snmp -I -smux,mteTrigger,mteTriggerConf" +[ -z "$SNMPDOPTS" ] && SNMPDOPTS=$DEFAULT_SNMPDOPTS + +DAEMON_ARGS="$SNMPDOPTS -p $PIDFILE" + +do_start_prepare() +{ + # remove old symlink with previous version + if [ -L /var/run/agentx ]; then + rm -f /var/run/agentx + fi + if [ ! -d /var/run/agentx ]; then + mkdir -p /var/run/agentx + fi +} diff --git a/init.d/ssh b/init.d/ssh new file mode 100755 index 00000000..620af70e --- /dev/null +++ b/init.d/ssh @@ -0,0 +1,162 @@ +#! /bin/sh + +### BEGIN INIT INFO +# Provides: sshd +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: +# Short-Description: OpenBSD Secure Shell server +### END INIT INFO + +set -e + +# /etc/init.d/ssh: start and stop the OpenBSD "secure shell(tm)" daemon + +test -x /usr/sbin/sshd || exit 0 +( /usr/sbin/sshd -\? 2>&1 | grep -q OpenSSH ) 2>/dev/null || exit 0 + +umask 022 + +if test -f /etc/default/ssh; then + . /etc/default/ssh +fi + +. /lib/lsb/init-functions + +if [ -n "$2" ]; then + SSHD_OPTS="$SSHD_OPTS $2" +fi + +# Are we running from init? +run_by_init() { + ([ "$previous" ] && [ "$runlevel" ]) || [ "$runlevel" = S ] +} + +check_for_no_start() { + # forget it if we're trying to start, and /etc/ssh/sshd_not_to_be_run exists + if [ -e /etc/ssh/sshd_not_to_be_run ]; then + if [ "$1" = log_end_msg ]; then + log_end_msg 0 || true + fi + if ! run_by_init; then + log_action_msg "OpenBSD Secure Shell server not in use (/etc/ssh/sshd_not_to_be_run)" || true + fi + exit 0 + fi +} + +check_dev_null() { + if [ ! -c /dev/null ]; then + if [ "$1" = log_end_msg ]; then + log_end_msg 1 || true + fi + if ! run_by_init; then + log_action_msg "/dev/null is not a character device!" || true + fi + exit 1 + fi +} + +check_privsep_dir() { + # Create the PrivSep empty dir if necessary + if [ ! -d /run/sshd ]; then + mkdir /run/sshd + chmod 0755 /run/sshd + fi +} + +check_config() { + if [ ! -e /etc/ssh/sshd_not_to_be_run ]; then + /usr/sbin/sshd $SSHD_OPTS -t || exit 1 + fi +} + +export PATH="${PATH:+$PATH:}/usr/sbin:/sbin" + +case "$1" in + start) + check_privsep_dir + check_for_no_start + check_dev_null + log_daemon_msg "Starting OpenBSD Secure Shell server" "sshd" || true + if start-stop-daemon --start --quiet --oknodo --chuid 0:0 --pidfile /run/sshd.pid --exec /usr/sbin/sshd -- $SSHD_OPTS; then + log_end_msg 0 || true + else + log_end_msg 1 || true + fi + ;; + stop) + log_daemon_msg "Stopping OpenBSD Secure Shell server" "sshd" || true + if start-stop-daemon --stop --quiet --oknodo --pidfile /run/sshd.pid --exec /usr/sbin/sshd; then + log_end_msg 0 || true + else + log_end_msg 1 || true + fi + ;; + + reload|force-reload) + check_for_no_start + check_config + log_daemon_msg "Reloading OpenBSD Secure Shell server's configuration" "sshd" || true + if start-stop-daemon --stop --signal 1 --quiet --oknodo --pidfile /run/sshd.pid --exec /usr/sbin/sshd; then + log_end_msg 0 || true + else + log_end_msg 1 || true + fi + ;; + + restart) + check_privsep_dir + check_config + log_daemon_msg "Restarting OpenBSD Secure Shell server" "sshd" || true + start-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile /run/sshd.pid --exec /usr/sbin/sshd + check_for_no_start log_end_msg + check_dev_null log_end_msg + if start-stop-daemon --start --quiet --oknodo --chuid 0:0 --pidfile /run/sshd.pid --exec /usr/sbin/sshd -- $SSHD_OPTS; then + log_end_msg 0 || true + else + log_end_msg 1 || true + fi + ;; + + try-restart) + check_privsep_dir + check_config + log_daemon_msg "Restarting OpenBSD Secure Shell server" "sshd" || true + RET=0 + start-stop-daemon --stop --quiet --retry 30 --pidfile /run/sshd.pid --exec /usr/sbin/sshd || RET="$?" + case $RET in + 0) + # old daemon stopped + check_for_no_start log_end_msg + check_dev_null log_end_msg + if start-stop-daemon --start --quiet --oknodo --chuid 0:0 --pidfile /run/sshd.pid --exec /usr/sbin/sshd -- $SSHD_OPTS; then + log_end_msg 0 || true + else + log_end_msg 1 || true + fi + ;; + 1) + # daemon not running + log_progress_msg "(not running)" || true + log_end_msg 0 || true + ;; + *) + # failed to stop + log_progress_msg "(failed to stop)" || true + log_end_msg 1 || true + ;; + esac + ;; + + status) + status_of_proc -p /run/sshd.pid /usr/sbin/sshd sshd && exit 0 || exit $? + ;; + + *) + log_action_msg "Usage: /etc/init.d/ssh {start|stop|reload|force-reload|restart|try-restart|status}" || true + exit 1 +esac + +exit 0 diff --git a/init.d/sudo b/init.d/sudo new file mode 100755 index 00000000..c9713101 --- /dev/null +++ b/init.d/sudo @@ -0,0 +1,44 @@ +#! /bin/sh + +### BEGIN INIT INFO +# Provides: sudo +# Required-Start: $local_fs $remote_fs +# Required-Stop: +# X-Start-Before: rmnologin +# Default-Start: 2 3 4 5 +# Default-Stop: +# Short-Description: Provide limited super user privileges to specific users +# Description: Provide limited super user privileges to specific users. +### END INIT INFO + +. /lib/lsb/init-functions + +N=/etc/init.d/sudo + +set -e + +case "$1" in + start) + # make sure privileges don't persist across reboots + # if the /run/sudo directory doesn't exist, let's create it with the + # correct permissions and SELinux label + if [ -d /run/sudo ] + then + find /run/sudo -exec touch -d @0 '{}' \; + else + mkdir /run/sudo /run/sudo/ts + chown root:root /run/sudo /run/sudo/ts + chmod 0711 /run/sudo + chmod 0700 /run/sudo/ts + [ -x /sbin/restorecon ] && /sbin/restorecon /run/sudo /run/sudo/ts + fi + ;; + stop|reload|restart|force-reload|status) + ;; + *) + echo "Usage: $N {start|stop|restart|force-reload|status}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/init.d/sysstat b/init.d/sysstat new file mode 100755 index 00000000..34209a54 --- /dev/null +++ b/init.d/sysstat @@ -0,0 +1,62 @@ +#! /bin/sh +# vim:ft=sh:et +### BEGIN INIT INFO +# Provides: sysstat +# Required-Start: $remote_fs $local_fs $syslog +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: +# Short-Description: Start/stop sysstat's sadc +# Description: Sysstat contains system performance tools for Linux +# The init file runs the sadc command in order to write +# the "LINUX RESTART" mark to the daily data file +### END INIT INFO + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/lib/sysstat/debian-sa1 +NAME=sadc +DESC="the system activity data collector" + +test -f "$DAEMON" || exit 0 +umask 022 + +# our configuration file +DEFAULT=/etc/default/sysstat + +# default setting... +ENABLED="false" + +# ...overridden in the configuration file +test -r "$DEFAULT" && . "$DEFAULT" + +set -e +status=0 + +. /lib/lsb/init-functions + +case "$1" in + start|restart|reload|force-reload) + if [ "$ENABLED" = "true" ] ; then + log_daemon_msg "Starting $DESC" "$NAME" + start-stop-daemon --start --quiet --exec $DAEMON -- --boot || status=$? + log_end_msg $status + fi + ;; + stop) + ;; + status) + if [ "$ENABLED" = "true" ] ; then + log_success_msg "sadc cron jobs are enabled" + exit 0 + else + log_failure_msg "sadc cron jobs are disabled" + exit 3 + fi + ;; + *) + log_failure_msg "Usage: $0 {start|stop|restart|reload|force-reload|status}" + exit 1 + ;; +esac + +exit $status diff --git a/init.d/tftpd-hpa b/init.d/tftpd-hpa new file mode 100755 index 00000000..115ca4e6 --- /dev/null +++ b/init.d/tftpd-hpa @@ -0,0 +1,106 @@ +#!/bin/sh + +### BEGIN INIT INFO +# Provides: tftpd-hpa +# Required-Start: $local_fs $remote_fs $syslog $network +# Required-Stop: $local_fs $remote_fs $syslog $network +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: HPA's tftp server +# Description: Trivial File Transfer Protocol (TFTP) is a file transfer +# protocol, mainly to serve boot images over the network +# to other machines (PXE). +### END INIT INFO + +PATH="/sbin:/bin:/usr/sbin:/usr/bin" +DAEMON="/usr/sbin/in.tftpd" + +test -x "$DAEMON" || exit 0 + +NAME="in.tftpd" +DESC="HPA's tftpd" +PIDFILE="/var/run/tftpd-hpa.pid" +DEFAULTS="/etc/default/tftpd-hpa" + +set -e + +[ -r "$DEFAULTS" ] && . "$DEFAULTS" + +. /lib/lsb/init-functions + + +do_start() +{ + # Ensure --secure and multiple server directories are not used at the + # same time + if [ "$(echo $TFTP_DIRECTORY | wc -w)" -ge 2 ] && \ + echo $TFTP_OPTIONS | grep -qs secure + then + echo + echo "When --secure is specified, exactly one directory can be specified." + echo "Please correct your $DEFAULTS." + exit 1 + fi + + # Ensure server directories exist + for d in $TFTP_DIRECTORY + do + if [ ! -d "$d" ] + then + echo "$d missing, aborting." + exit 1 + fi + done + + start-stop-daemon --start --quiet --oknodo --exec $DAEMON -- \ + --listen --user $TFTP_USERNAME --address $TFTP_ADDRESS \ + $TFTP_OPTIONS $TFTP_DIRECTORY +} + +do_stop () +{ + start-stop-daemon --stop --quiet --oknodo --name $NAME +} + +do_reload () +{ + start-stop-daemon --stop --quiet --oknodo --name $NAME --signal 1 +} + +case "$1" in + start) + init_is_upstart > /dev/null 2>&1 && exit 1 + + log_daemon_msg "Starting $DESC" "$NAME" + do_start + log_end_msg $? + ;; + + stop) + init_is_upstart > /dev/null 2>&1 && exit 0 + + log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + log_end_msg $? + ;; + + restart|force-reload) + init_is_upstart > /dev/null 2>&1 && exit 1 + + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + sleep 1 + do_start + log_end_msg $? + ;; + + status) + status_of_proc $DAEMON $NAME + ;; + + *) + echo "Usage: $0 {start|stop|restart|force-reload|status}" >&2 + exit 3 + ;; +esac + diff --git a/init.d/triggerhappy b/init.d/triggerhappy new file mode 100755 index 00000000..850088ef --- /dev/null +++ b/init.d/triggerhappy @@ -0,0 +1,133 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: triggerhappy +# Required-Start: $local_fs $remote_fs +# Required-Stop: $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: triggerhappy hotkey daemon +# Description: triggerhappy hotkey daemon +### END INIT INFO + +# Author: Stefan Tomanek + +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="input event daemon" +NAME=thd +PNAME=triggerhappy +DAEMON=/usr/sbin/thd +PIDFILE=/var/run/$NAME.pid +DAEMON_ARGS="--daemon --triggers /etc/triggerhappy/triggers.d/ --socket /var/run/thd.socket --pidfile $PIDFILE --user nobody /dev/input/event*" +DAEMON_OPTS="" +SCRIPTNAME=/etc/init.d/$PNAME + +# Exit if the package is not installed +[ -x $DAEMON ] || exit 0 + +# Read configuration variable file if it is present +[ -r /etc/default/$PNAME ] && . /etc/default/$PNAME + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.0-6) to ensure that this file is present. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() +{ + # Return + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ + || return 1 + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ + $DAEMON_ARGS $DAEMON_OPTS \ + || return 2 +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME + RETVAL="$?" + [ "$RETVAL" = 2 ] && return 2 + # Many daemons don't delete their pidfiles when they exit. + rm -f $PIDFILE + return "$RETVAL" +} + +# +# Function that sends a SIGHUP to the daemon/service +# +do_reload() { + # + # If the daemon can reload its configuration without + # restarting (for example, when it is sent a SIGHUP), + # then implement that here. + # + start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME + return 0 +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + reload|force-reload) + log_daemon_msg "Reloading $DESC" "$NAME" + do_reload + log_end_msg $? + ;; + restart) + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|status|restart|reload|force-reload}" >&2 + exit 3 + ;; +esac + +: diff --git a/init.d/udev b/init.d/udev new file mode 100755 index 00000000..a10a586c --- /dev/null +++ b/init.d/udev @@ -0,0 +1,256 @@ +#!/bin/sh -e +### BEGIN INIT INFO +# Provides: udev +# Required-Start: mountkernfs +# Required-Stop: umountroot +# Default-Start: S +# Default-Stop: 0 6 +# Short-Description: Start systemd-udevd, populate /dev and load drivers. +### END INIT INFO + +PATH="/sbin:/bin" +NAME="systemd-udevd" +DAEMON="/lib/systemd/systemd-udevd" +DESC="hotplug events dispatcher" +PIDFILE="/run/udev.pid" +CTRLFILE="/run/udev/control" +OMITDIR="/run/sendsigs.omit.d" + +# we need to unmount /dev/pts/ and remount it later over the devtmpfs +unmount_devpts() { + if mountpoint -q /dev/pts/; then + umount -n -l /dev/pts/ + fi + + if mountpoint -q /dev/shm/; then + umount -n -l /dev/shm/ + fi +} + +# mount a devtmpfs over /dev, if somebody did not already do it +mount_devtmpfs() { + if grep -E -q "^[^[:space:]]+ /dev devtmpfs" /proc/mounts; then + mount -n -o remount,nosuid,size=$tmpfs_size,mode=0755 -t devtmpfs devtmpfs /dev + return + fi + + if ! mount -n -o nosuid,size=$tmpfs_size,mode=0755 -t devtmpfs devtmpfs /dev; then + log_failure_msg "udev requires devtmpfs support, not started" + log_end_msg 1 + fi + + return 0 +} + +create_dev_makedev() { + if [ -e /sbin/MAKEDEV ]; then + ln -sf /sbin/MAKEDEV /dev/MAKEDEV + else + ln -sf /bin/true /dev/MAKEDEV + fi +} + +# shell version of /usr/bin/tty +my_tty() { + [ -x /bin/readlink ] || return 0 + [ -e /proc/self/fd/0 ] || return 0 + readlink --silent /proc/self/fd/0 || true +} + +warn_if_interactive() { + if [ "$RUNLEVEL" = "S" -a "$PREVLEVEL" = "N" ]; then + return + fi + + TTY=$(my_tty) + if [ -z "$TTY" -o "$TTY" = "/dev/console" -o "$TTY" = "/dev/null" ]; then + return + fi + + printf "\n\n\nIt has been detected that the command\n\n\t$0 $*\n\n" + printf "has been run from an interactive shell.\n" + printf "It will probably not do what you expect, so this script will wait\n" + printf "60 seconds before continuing. Press ^C to stop it.\n" + printf "RUNNING THIS COMMAND IS HIGHLY DISCOURAGED!\n\n\n\n" + sleep 60 +} + +make_static_nodes() { + [ -e /lib/modules/$(uname -r)/modules.devname ] || return 0 + [ -x /bin/kmod ] || return 0 + + /bin/kmod static-nodes --format=tmpfiles --output=/proc/self/fd/1 | \ + while read type name mode uid gid age arg; do + [ -e $name ] && continue + case "$type" in + c|b|c!|b!) mknod -m $mode $name $type $(echo $arg | sed 's/:/ /') ;; + d|d!) mkdir $name ;; + *) echo "unparseable line ($type $name $mode $uid $gid $age $arg)" >&2 ;; + esac + + if [ -x /sbin/restorecon ]; then + /sbin/restorecon $name + fi + done +} + + +############################################################################## + + +[ -x $DAEMON ] || exit 0 + +# defaults +tmpfs_size="10M" + +if [ -e /etc/udev/udev.conf ]; then + . /etc/udev/udev.conf +fi + +. /lib/lsb/init-functions + +if [ ! -e /proc/filesystems ]; then + log_failure_msg "udev requires a mounted procfs, not started" + log_end_msg 1 +fi + +if ! grep -q '[[:space:]]devtmpfs$' /proc/filesystems; then + log_failure_msg "udev requires devtmpfs support, not started" + log_end_msg 1 +fi + +if [ ! -d /sys/class/ ]; then + log_failure_msg "udev requires a mounted sysfs, not started" + log_end_msg 1 +fi + +if [ ! -w /sys ]; then + log_warning_msg "udev does not support containers, not started" + exit 0 +fi + +if [ -d /sys/class/mem/null -a ! -L /sys/class/mem/null ] || \ + [ -e /sys/block -a ! -e /sys/class/block ]; then + log_warning_msg "CONFIG_SYSFS_DEPRECATED must not be selected" + log_warning_msg "Booting will continue in 30 seconds but many things will be broken" + sleep 30 +fi + +# When modifying this script, do not forget that between the time that the +# new /dev has been mounted and udevadm trigger has been run there will be +# no /dev/null. This also means that you cannot use the "&" shell command. + +case "$1" in + start) + if [ ! -e "/run/udev/" ]; then + warn_if_interactive + fi + + if [ -w /sys/kernel/uevent_helper ]; then + echo > /sys/kernel/uevent_helper + fi + + if ! mountpoint -q /dev/; then + unmount_devpts + mount_devtmpfs + [ -d /proc/1 ] || mount -n /proc + fi + + make_static_nodes + + # clean up parts of the database created by the initramfs udev + udevadm info --cleanup-db + + # set the SELinux context for devices created in the initramfs + [ -x /sbin/restorecon ] && /sbin/restorecon -R /dev + + log_daemon_msg "Starting $DESC" "$NAME" + if start-stop-daemon --start --name $NAME --user root --quiet \ + --pidfile $PIDFILE --exec $DAEMON --background --make-pidfile \ + --notify-await; then + # prevents udevd to be killed by sendsigs (see #791944) + mkdir -p $OMITDIR + ln -sf $PIDFILE $OMITDIR/$NAME + log_end_msg $? + else + log_warning_msg $? + log_warning_msg "Waiting 15 seconds and trying to continue anyway" + sleep 15 + fi + + log_action_begin_msg "Synthesizing the initial hotplug events (subsystems)" + if udevadm trigger --type=subsystems --action=add; then + log_action_end_msg $? + else + log_action_end_msg $? + fi + log_action_begin_msg "Synthesizing the initial hotplug events (devices)" + if udevadm trigger --type=devices --action=add; then + log_action_end_msg $? + else + log_action_end_msg $? + fi + + create_dev_makedev + + # wait for the systemd-udevd childs to finish + log_action_begin_msg "Waiting for /dev to be fully populated" + if udevadm settle; then + log_action_end_msg 0 + else + log_action_end_msg 0 'timeout' + fi + ;; + + stop) + log_daemon_msg "Stopping $DESC" "$NAME" + if start-stop-daemon --stop --name $NAME --user root --quiet \ + --pidfile $PIDFILE --remove-pidfile --oknodo --retry 5; then + # prevents cryptsetup/dmsetup hangs (see #791944) + rm -f $CTRLFILE + log_end_msg $? + else + log_end_msg $? + fi + ;; + + restart) + log_daemon_msg "Stopping $DESC" "$NAME" + if start-stop-daemon --stop --name $NAME --user root --quiet \ + --pidfile $PIDFILE --remove-pidfile --oknodo --retry 5; then + # prevents cryptsetup/dmsetup hangs (see #791944) + rm -f $CTRLFILE + log_end_msg $? + else + log_end_msg $? || true + fi + + log_daemon_msg "Starting $DESC" "$NAME" + if start-stop-daemon --start --name $NAME --user root --quiet \ + --pidfile $PIDFILE --exec $DAEMON --background --make-pidfile \ + --notify-await; then + # prevents udevd to be killed by sendsigs (see #791944) + mkdir -p $OMITDIR + ln -sf $PIDFILE $OMITDIR/$NAME + log_end_msg $? + else + log_end_msg $? + fi + ;; + + reload|force-reload) + udevadm control --reload-rules + ;; + + status) + status_of_proc $DAEMON $NAME && exit 0 || exit $? + ;; + + *) + echo "Usage: /etc/init.d/udev {start|stop|restart|reload|force-reload|status}" >&2 + exit 1 + ;; +esac + +exit 0 + diff --git a/init.d/x11-common b/init.d/x11-common new file mode 100755 index 00000000..63c3c307 --- /dev/null +++ b/init.d/x11-common @@ -0,0 +1,122 @@ +#!/bin/sh +# /etc/init.d/x11-common: set up the X server and ICE socket directories +### BEGIN INIT INFO +# Provides: x11-common +# Required-Start: $remote_fs +# Required-Stop: $remote_fs +# Default-Start: S +# Default-Stop: +# Short-Description: set up the X server and ICE socket directories +### END INIT INFO + +set -e + +PATH=/usr/bin:/usr/sbin:/bin:/sbin +SOCKET_DIR=.X11-unix +ICE_DIR=.ICE-unix + +. /lib/lsb/init-functions +if [ -f /etc/default/rcS ]; then + . /etc/default/rcS +fi + +do_restorecon () { + # Restore file security context (SELinux). + if which restorecon >/dev/null 2>&1; then + restorecon "$1" + fi +} + +# create a directory in /tmp. +# assumes /tmp has a sticky bit set (or is only writeable by root) +set_up_dir () { + DIR="/tmp/$1" + + if [ "$VERBOSE" != no ]; then + log_progress_msg "$DIR" + fi + # if $DIR exists and isn't a directory, move it aside + if [ -e $DIR ] && ! [ -d $DIR ] || [ -h $DIR ]; then + mv "$DIR" "$(mktemp -d $DIR.XXXXXX)" + fi + + error=0 + while :; do + if [ $error -ne 0 ] ; then + # an error means the file-system is readonly or an attacker + # is doing evil things, distinguish by creating a temporary file, + # but give up after a while. + if [ $error -gt 5 ]; then + log_failure_msg "failed to set up $DIR" + return 1 + fi + fn="$(mktemp /tmp/testwriteable.XXXXXXXXXX)" || return 1 + rm "$fn" + fi + mkdir -p -m 01777 "$DIR" || { rm "$DIR" || error=$((error + 1)) ; continue ; } + case "$(LC_ALL=C stat -c '%u %g %a %F' "$DIR")" in + "0 0 1777 directory") + # everything as it is supposed to be + break + ;; + "0 0 "*" directory") + # as it is owned by root, cannot be replaced with a symlink: + chmod 01777 "$DIR" + break + ;; + *" directory") + # if the chown succeeds, the next step can change it savely + chown -h root:root "$DIR" || error=$((error + 1)) + continue + ;; + *) + log_failure_msg "failed to set up $DIR" + return 1 + ;; + esac + done + do_restorecon "$DIR" + + return 0 +} + +do_status () { + if [ -d "/tmp/$ICE_DIR" ] && [ -d "/tmp/$SOCKET_DIR" ]; then + return 0 + else + return 4 + fi +} + +case "$1" in + start) + if [ "$VERBOSE" != no ]; then + log_begin_msg "Setting up X socket directories..." + fi + set_up_dir "$SOCKET_DIR" + set_up_dir "$ICE_DIR" + if [ "$VERBOSE" != no ]; then + log_end_msg 0 + fi + ;; + + restart|reload|force-reload) + /etc/init.d/x11-common start + ;; + + stop) + : + ;; + + status) + do_status + ;; + *) + log_success_msg "Usage: /etc/init.d/x11-common {start|stop|status|restart|reload|force-reload}" + exit 1 + ;; +esac + +exit 0 + +# vim:set ai et sts=2 sw=2 tw=0: diff --git a/init.d/xinetd b/init.d/xinetd new file mode 100755 index 00000000..c8ea9c39 --- /dev/null +++ b/init.d/xinetd @@ -0,0 +1,84 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: xinetd inetd +# Required-Start: $local_fs $remote_fs $network +# Required-Stop: $local_fs $remote_fs $network +# Should-Start: $syslog +# Should-Stop: $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Starts or stops the xinetd daemon. +# Description: Starts and stops xinetd, an inetd replacement +### END INIT INFO + +# clear poisonned environment +unset TMPDIR + +NAME=xinetd +DAEMON=/usr/sbin/$NAME +PIDFILE=/run/$NAME.pid + +test -x "$DAEMON" || exit 0 + +test -e /etc/default/$NAME && . /etc/default/$NAME +case "$INETD_COMPAT" in + [Yy]*) + XINETD_OPTS="$XINETD_OPTS -inetd_compat" + if perl -MSocket -e 'exit (!socket($sock, AF_INET6, SOCK_STREAM, 0))'; then + XINETD_OPTS="$XINETD_OPTS -inetd_ipv6" + fi + ;; +esac + +. /lib/lsb/init-functions + +checkportmap () { + if grep "^[^ *#]" /etc/xinetd.conf | grep -q 'rpc/'; then + if ! rpcinfo -u localhost portmapper >/dev/null 2>&1; then + echo + echo "WARNING: portmapper inactive - RPC services unavailable!" + echo " Commenting out or removing the RPC services from" + echo " the /etc/xinetd.conf file will remove this message." + echo + fi + fi +} + +case "$1" in + start) + checkportmap + log_daemon_msg "Starting internet superserver" "$NAME" + start-stop-daemon --pidfile "$PIDFILE" --start --quiet --background --exec "$DAEMON" -- \ + -pidfile "$PIDFILE" $XINETD_OPTS + log_end_msg $? + ;; + stop) + log_daemon_msg "Stopping internet superserver" "$NAME" + start-stop-daemon --pidfile "$PIDFILE" --stop --signal 3 --quiet --oknodo --exec "$DAEMON" + log_end_msg $? + ;; + reload) + log_daemon_msg "Reloading internet superserver configuration" "$NAME" + start-stop-daemon --pidfile "$PIDFILE" --stop --signal 1 --quiet --oknodo --exec "$DAEMON" + log_end_msg $? + ;; + restart|force-reload) + $0 stop + $0 start + ;; + status) + status_of_proc -p "$PIDFILE" "$DAEMON" + R=$? + if test "$R" = "0" ; then + kill -10 $(cat "$PIDFILE") + cat /var/run/xinetd.dump + fi + exit $R + ;; + *) + echo "Usage: /etc/init.d/xinetd {start|stop|reload|force-reload|restart|status}" + exit 1 + ;; +esac + +exit 0 diff --git a/init/docker.conf b/init/docker.conf new file mode 100644 index 00000000..d58f7d6a --- /dev/null +++ b/init/docker.conf @@ -0,0 +1,72 @@ +description "Docker daemon" + +start on (filesystem and net-device-up IFACE!=lo) +stop on runlevel [!2345] + +limit nofile 524288 1048576 + +# Having non-zero limits causes performance problems due to accounting overhead +# in the kernel. We recommend using cgroups to do container-local accounting. +limit nproc unlimited unlimited + +respawn + +kill timeout 20 + +pre-start script + # see also https://github.com/tianon/cgroupfs-mount/blob/master/cgroupfs-mount + if grep -v '^#' /etc/fstab | grep -q cgroup \ + || [ ! -e /proc/cgroups ] \ + || [ ! -d /sys/fs/cgroup ]; then + exit 0 + fi + if ! mountpoint -q /sys/fs/cgroup; then + mount -t tmpfs -o uid=0,gid=0,mode=0755 cgroup /sys/fs/cgroup + fi + ( + cd /sys/fs/cgroup + for sys in $(awk '!/^#/ { if ($4 == 1) print $1 }' /proc/cgroups); do + mkdir -p $sys + if ! mountpoint -q $sys; then + if ! mount -n -t cgroup -o $sys cgroup $sys; then + rmdir $sys || true + fi + fi + done + ) +end script + +script + # modify these in /etc/default/$UPSTART_JOB (/etc/default/docker) + DOCKERD=/usr/bin/dockerd + DOCKER_OPTS= + if [ -f /etc/default/$UPSTART_JOB ]; then + . /etc/default/$UPSTART_JOB + fi + exec "$DOCKERD" $DOCKER_OPTS --raw-logs +end script + +# Don't emit "started" event until docker.sock is ready. +# See https://github.com/docker/docker/issues/6647 +post-start script + DOCKER_OPTS= + DOCKER_SOCKET= + if [ -f /etc/default/$UPSTART_JOB ]; then + . /etc/default/$UPSTART_JOB + fi + + if ! printf "%s" "$DOCKER_OPTS" | grep -qE -e '-H|--host'; then + DOCKER_SOCKET=/var/run/docker.sock + else + DOCKER_SOCKET=$(printf "%s" "$DOCKER_OPTS" | grep -oP -e '(-H|--host)\W*unix://\K(\S+)' | sed 1q) + fi + + if [ -n "$DOCKER_SOCKET" ]; then + while ! [ -e "$DOCKER_SOCKET" ]; do + initctl status $UPSTART_JOB | grep -qE "(stop|respawn)/" && exit 1 + echo "Waiting for $DOCKER_SOCKET" + sleep 0.1 + done + echo "$DOCKER_SOCKET is up" + fi +end script diff --git a/init/paxctld.conf b/init/paxctld.conf new file mode 100644 index 00000000..3d1864f2 --- /dev/null +++ b/init/paxctld.conf @@ -0,0 +1,13 @@ +description "PaX flags maintenance daemon" + +start on runlevel [2345] +stop on runlevel [!2345] + +console none + +pre-start script + test -x /sbin/paxctld || { stop; exit 0; } +end script + +exec /sbin/paxctld + diff --git a/init/php7.3-fpm.conf b/init/php7.3-fpm.conf new file mode 100644 index 00000000..d3d51767 --- /dev/null +++ b/init/php7.3-fpm.conf @@ -0,0 +1,19 @@ +# php7.3-fpm - The PHP FastCGI Process Manager + +description "The PHP 7.3 FastCGI Process Manager" +author "OndÅ™ej Surý " + +start on runlevel [2345] +stop on runlevel [016] + +# you can uncomment this with recent upstart +# reload signal USR2 + +pre-start script +mkdir -p /run/php +chmod 0755 /run/php +chown www-data:www-data /run/php +end script + +respawn +exec /usr/sbin/php-fpm7.3 --nodaemonize --fpm-config /etc/php/7.3/fpm/php-fpm.conf \ No newline at end of file diff --git a/init/resolvconf.conf b/init/resolvconf.conf new file mode 100644 index 00000000..93460111 --- /dev/null +++ b/init/resolvconf.conf @@ -0,0 +1,19 @@ +# upstart script for resolvconf + +description "Initialize or finalize resolvconf" + +start on mounted MOUNTPOINT=/run + +stop on runlevel [06] + +pre-start script + mkdir -p /run/resolvconf/interface + # Request a postponed update (needed in case the base file has content). + touch /run/resolvconf/postponed-update + # Enable updates and perform the postponed update. + resolvconf --enable-updates +end script + +post-stop script + resolvconf --disable-updates +end script diff --git a/init/tftpd-hpa.conf b/init/tftpd-hpa.conf new file mode 100644 index 00000000..9da3b710 --- /dev/null +++ b/init/tftpd-hpa.conf @@ -0,0 +1,51 @@ +description "tftp-hpa server" + +start on runlevel [2345] +stop on runlevel [!2345] + +expect fork +respawn + +env DEFAULTS="/etc/default/tftpd-hpa" +env PIDFILE="/var/run/tftpd-hpa.pid" + +pre-start script + if [ -f ${DEFAULTS} ] + then + . ${DEFAULTS} + fi + + # Ensure --secure and multiple server directories are not used at the + # same time + if [ "$(echo ${TFTP_DIRECTORY} | wc -w)" -ge 2 ] && echo ${TFTP_OPTIONS} | grep -qs secure + then + echo + echo "When --secure is specified, exactly one directory can be specified." + echo "Please correct your /etc/default/tftpd-hpa." + + stop + exit 0 + fi + + # Ensure server directories are existing + for _DIRECTORY in ${TFTP_DIRECTORY} + do + if [ ! -d "${_DIRECTORY}" ] + then + echo "${_DIRECTORY} missing, aborting." + + stop + exit 0 + fi + done + +end script + +script + if [ -f ${DEFAULTS} ] + then + . ${DEFAULTS} + fi + + exec /usr/sbin/in.tftpd --listen --user ${TFTP_USERNAME} --address ${TFTP_ADDRESS} ${TFTP_OPTIONS} ${TFTP_DIRECTORY} +end script diff --git a/initramfs-tools/initramfs.conf b/initramfs-tools/initramfs.conf new file mode 100644 index 00000000..dd76996c --- /dev/null +++ b/initramfs-tools/initramfs.conf @@ -0,0 +1,72 @@ +# +# initramfs.conf +# Configuration file for mkinitramfs(8). See initramfs.conf(5). +# +# Note that configuration options from this file can be overridden +# by config files in the /etc/initramfs-tools/conf.d directory. + +# +# MODULES: [ most | netboot | dep | list ] +# +# most - Add most filesystem and all harddrive drivers. +# +# dep - Try and guess which modules to load. +# +# netboot - Add the base modules, network modules, but skip block devices. +# +# list - Only include modules from the 'additional modules' list +# + +MODULES=most + +# +# BUSYBOX: [ y | n | auto ] +# +# Use busybox shell and utilities. If set to n, klibc utilities will be used. +# If set to auto (or unset), busybox will be used if installed and klibc will +# be used otherwise. +# + +BUSYBOX=auto + +# +# KEYMAP: [ y | n ] +# +# Load a keymap during the initramfs stage. +# + +KEYMAP=n + +# +# COMPRESS: [ gzip | bzip2 | lz4 | lzma | lzop | xz ] +# + +COMPRESS=gzip + +# +# NFS Section of the config. +# + +# +# DEVICE: ... +# +# Specify a specific network interface, like eth0 +# Overridden by optional ip= or BOOTIF= bootarg +# + +DEVICE= + +# +# NFSROOT: [ auto | HOST:MOUNT ] +# + +NFSROOT=auto + +# +# RUNSIZE: ... +# +# The size of the /run tmpfs mount point, like 256M or 10% +# Overridden by optional initramfs.runsize= bootarg +# + +RUNSIZE=10% diff --git a/initramfs-tools/modules b/initramfs-tools/modules new file mode 100644 index 00000000..dd9dc54e --- /dev/null +++ b/initramfs-tools/modules @@ -0,0 +1,11 @@ +# List of modules that you want to include in your initramfs. +# They will be loaded at boot time in the order below. +# +# Syntax: module_name [args ...] +# +# You must run update-initramfs(8) to effect this change. +# +# Examples: +# +# raid1 +# sd_mod diff --git a/initramfs-tools/update-initramfs.conf b/initramfs-tools/update-initramfs.conf new file mode 100644 index 00000000..31823e26 --- /dev/null +++ b/initramfs-tools/update-initramfs.conf @@ -0,0 +1,20 @@ +# +# Configuration file for update-initramfs(8) +# + +# +# update_initramfs [ yes | all | no ] +# +# Default is yes +# If set to all update-initramfs will update all initramfs +# If set to no disables any update to initramfs beside kernel upgrade + +update_initramfs=yes + +# +# backup_initramfs [ yes | no ] +# +# Default is no +# If set to no leaves no .bak backup files. + +backup_initramfs=no diff --git a/inputrc b/inputrc new file mode 100644 index 00000000..b095bacc --- /dev/null +++ b/inputrc @@ -0,0 +1,71 @@ +# /etc/inputrc - global inputrc for libreadline +# See readline(3readline) and `info rluserman' for more information. + +# Be 8 bit clean. +set input-meta on +set output-meta on + +# To allow the use of 8bit-characters like the german umlauts, uncomment +# the line below. However this makes the meta key not work as a meta key, +# which is annoying to those which don't need to type in 8-bit characters. + +# set convert-meta off + +# try to enable the application keypad when it is called. Some systems +# need this to enable the arrow keys. +# set enable-keypad on + +# see /usr/share/doc/bash/inputrc.arrows for other codes of arrow keys + +# do not bell on tab-completion +# set bell-style none +# set bell-style visible + +# some defaults / modifications for the emacs mode +$if mode=emacs + +# allow the use of the Home/End keys +"\e[1~": beginning-of-line +"\e[4~": end-of-line + +# allow the use of the Delete/Insert keys +"\e[3~": delete-char +"\e[2~": quoted-insert + +# mappings for "page up" and "page down" to step to the beginning/end +# of the history +# "\e[5~": beginning-of-history +# "\e[6~": end-of-history + +# alternate mappings for "page up" and "page down" to search the history +# "\e[5~": history-search-backward +# "\e[6~": history-search-forward + +# mappings for Ctrl-left-arrow and Ctrl-right-arrow for word moving +"\e[1;5C": forward-word +"\e[1;5D": backward-word +"\e[5C": forward-word +"\e[5D": backward-word +"\e\e[C": forward-word +"\e\e[D": backward-word + +$if term=rxvt +"\e[7~": beginning-of-line +"\e[8~": end-of-line +"\eOc": forward-word +"\eOd": backward-word +$endif + +# for non RH/Debian xterm, can't hurt for RH/Debian xterm +# "\eOH": beginning-of-line +# "\eOF": end-of-line + +# for freebsd console +# "\e[H": beginning-of-line +# "\e[F": end-of-line + +$endif + +# mappings for up and down arrows search history +# "\e[B": history-search-forward +# "\e[A": history-search-backward diff --git a/insserv.conf.d/rpcbind b/insserv.conf.d/rpcbind new file mode 100644 index 00000000..5e930f5e --- /dev/null +++ b/insserv.conf.d/rpcbind @@ -0,0 +1 @@ +$portmap rpcbind diff --git a/iproute2/bpf_pinning b/iproute2/bpf_pinning new file mode 100644 index 00000000..2b39c709 --- /dev/null +++ b/iproute2/bpf_pinning @@ -0,0 +1,6 @@ +# +# subpath mappings from mount point for pinning +# +#3 tracing +#4 foo/bar +#5 tc/cls1 diff --git a/iproute2/ematch_map b/iproute2/ematch_map new file mode 100644 index 00000000..4d6bb2f0 --- /dev/null +++ b/iproute2/ematch_map @@ -0,0 +1,8 @@ +# lookup table for ematch kinds +1 cmp +2 nbyte +3 u32 +4 meta +7 canid +8 ipset +9 ipt diff --git a/iproute2/group b/iproute2/group new file mode 100644 index 00000000..6f000b24 --- /dev/null +++ b/iproute2/group @@ -0,0 +1,2 @@ +# device group names +0 default diff --git a/iproute2/nl_protos b/iproute2/nl_protos new file mode 100644 index 00000000..7c17cf0f --- /dev/null +++ b/iproute2/nl_protos @@ -0,0 +1,23 @@ +# Netlink protocol names mapping + +0 rtnl +1 unused +2 usersock +3 fw +4 tcpdiag +5 nflog +6 xfrm +7 selinux +8 iscsi +9 audit +10 fiblookup +11 connector +12 nft +13 ip6fw +14 dec-rt +15 uevent +16 genl +18 scsi-trans +19 ecryptfs +20 rdma +21 crypto diff --git a/iproute2/rt_dsfield b/iproute2/rt_dsfield new file mode 100644 index 00000000..1426d601 --- /dev/null +++ b/iproute2/rt_dsfield @@ -0,0 +1,26 @@ +# Differentiated field values +# These include the DSCP and unused bits +0x0 default +# Newer RFC2597 values +0x28 AF11 +0x30 AF12 +0x38 AF13 +0x48 AF21 +0x50 AF22 +0x58 AF23 +0x68 AF31 +0x70 AF32 +0x78 AF33 +0x88 AF41 +0x90 AF42 +0x98 AF43 +# Older values RFC2474 +0x20 CS1 +0x40 CS2 +0x60 CS3 +0x80 CS4 +0xA0 CS5 +0xC0 CS6 +0xE0 CS7 +# RFC 2598 +0xB8 EF diff --git a/iproute2/rt_protos b/iproute2/rt_protos new file mode 100644 index 00000000..b3a0ec8f --- /dev/null +++ b/iproute2/rt_protos @@ -0,0 +1,23 @@ +# +# Reserved protocols. +# +0 unspec +1 redirect +2 kernel +3 boot +4 static +8 gated +9 ra +10 mrt +11 zebra +12 bird +13 dnrouted +14 xorp +15 ntk +16 dhcp +42 babel +186 bgp +187 isis +188 ospf +189 rip +192 eigrp diff --git a/iproute2/rt_protos.d/README b/iproute2/rt_protos.d/README new file mode 100644 index 00000000..f9c599c6 --- /dev/null +++ b/iproute2/rt_protos.d/README @@ -0,0 +1,2 @@ +Each file in this directory is an rt_protos configuration file. iproute2 +commands scan this directory processing all files that end in '.conf'. diff --git a/iproute2/rt_realms b/iproute2/rt_realms new file mode 100644 index 00000000..eedd76d2 --- /dev/null +++ b/iproute2/rt_realms @@ -0,0 +1,13 @@ +# +# reserved values +# +0 cosmos +# +# local +# +#1 inr.ac +#2 inr.ruhep +#3 freenet +#4 radio-msu +#5 russia +#6 internet diff --git a/iproute2/rt_scopes b/iproute2/rt_scopes new file mode 100644 index 00000000..8514bc11 --- /dev/null +++ b/iproute2/rt_scopes @@ -0,0 +1,11 @@ +# +# reserved values +# +0 global +255 nowhere +254 host +253 link +# +# pseudo-reserved +# +200 site diff --git a/iproute2/rt_tables b/iproute2/rt_tables new file mode 100644 index 00000000..541abfd2 --- /dev/null +++ b/iproute2/rt_tables @@ -0,0 +1,11 @@ +# +# reserved values +# +255 local +254 main +253 default +0 unspec +# +# local +# +#1 inr.ruhep diff --git a/iproute2/rt_tables.d/README b/iproute2/rt_tables.d/README new file mode 100644 index 00000000..0920cb16 --- /dev/null +++ b/iproute2/rt_tables.d/README @@ -0,0 +1,2 @@ +Each file in this directory is an rt_tables configuration file. iproute2 +commands scan this directory processing all files that end in '.conf'. diff --git a/issue b/issue new file mode 100644 index 00000000..0ecbda47 --- /dev/null +++ b/issue @@ -0,0 +1,2 @@ +Raspbian GNU/Linux 10 \n \l + diff --git a/issue.net b/issue.net new file mode 100644 index 00000000..588f12ac --- /dev/null +++ b/issue.net @@ -0,0 +1 @@ +Raspbian GNU/Linux 10 diff --git a/java-11-openjdk/accessibility.properties b/java-11-openjdk/accessibility.properties new file mode 100644 index 00000000..c1bdc487 --- /dev/null +++ b/java-11-openjdk/accessibility.properties @@ -0,0 +1,10 @@ +# +# The following line specifies the assistive technology classes +# that should be loaded into the Java VM when the AWT is initailized. +# Specify multiple classes by separating them with commas. +# Note: the line below cannot end the file (there must be at +# a minimum a blank line following it). +# +# Doesn't work, see LP: #935296 +#assistive_technologies=org.GNOME.Accessibility.AtkWrapper + diff --git a/java-11-openjdk/jfr/default.jfc b/java-11-openjdk/jfr/default.jfc new file mode 100644 index 00000000..1a1d420d --- /dev/null +++ b/java-11-openjdk/jfr/default.jfc @@ -0,0 +1,890 @@ + + + + + + + + true + everyChunk + + + + true + 1000 ms + + + + true + everyChunk + + + + true + 1000 ms + + + + true + true + + + + true + + + + true + true + 20 ms + + + + true + true + 20 ms + + + + true + true + 20 ms + + + + true + true + 20 ms + + + + false + true + 20 ms + + + + true + true + 0 ms + + + + true + true + 0 ms + + + + true + true + 0 ms + + + + true + true + + + + false + true + 0 ms + + + + false + true + + + + false + + + + true + beginChunk + + + + true + beginChunk + + + + true + 20 ms + + + + true + 20 ms + + + + true + 10 ms + + + + false + 10 ms + + + + false + 10 ms + + + + false + 10 ms + + + + false + 10 ms + + + + false + 10 ms + + + + true + 10 ms + + + + true + true + + + + true + everyChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + false + everyChunk + + + + true + everyChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + false + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + true + + + + true + true + + + + true + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + false + 0 ms + + + + false + 0 ms + + + + true + 0 ms + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + false + + + + false + + + + true + + + + false + true + + + + true + + + + false + everyChunk + + + + false + + + + false + everyChunk + + + + false + + + + true + false + 0 ns + + + + true + beginChunk + + + + true + 1000 ms + + + + true + 1000 ms + + + + true + 60 s + + + + false + + + + false + + + + true + beginChunk + + + + true + everyChunk + + + + true + 100 ms + + + + true + beginChunk + + + + true + everyChunk + + + + true + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + 10 s + + + + true + 1000 ms + + + + true + 10 s + + + + true + beginChunk + + + + true + endChunk + + + + true + 5 s + + + + true + beginChunk + + + + true + everyChunk + + + + false + true + + + + false + true + + + + true + everyChunk + + + + true + endChunk + + + + true + endChunk + + + + true + true + 20 ms + + + + true + true + 20 ms + + + + true + true + 20 ms + + + + true + true + 20 ms + + + + true + true + 20 ms + + + + false + true + + + + false + true + + + + false + true + + + + false + true + + + + false + true + + + + true + true + + + + true + 1000 ms + + + + true + + + + true + + + + true + + + + true + + + + true + 10 ms + + + + true + 0 ms + + + + true + 10 ms + + + + true + 10 ms + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 20 ms + + 20 ms + + 20 ms + + false + + + + diff --git a/java-11-openjdk/jfr/profile.jfc b/java-11-openjdk/jfr/profile.jfc new file mode 100644 index 00000000..edde79ce --- /dev/null +++ b/java-11-openjdk/jfr/profile.jfc @@ -0,0 +1,891 @@ + + + + + + + + true + everyChunk + + + + true + 1000 ms + + + + true + everyChunk + + + + true + 1000 ms + + + + true + true + + + + true + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + 0 ms + + + + true + true + 0 ms + + + + true + true + 0 ms + + + + true + true + + + + false + true + 0 ms + + + + false + true + + + + false + + + + true + beginChunk + + + + true + beginChunk + + + + true + 10 ms + + + + true + 20 ms + + + + true + 0 ms + + + + false + 0 ms + + + + false + 0 ms + + + + false + 0 ms + + + + false + 0 ms + + + + false + 0 ms + + + + true + 0 ms + + + + true + true + + + + true + 60 s + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + false + everyChunk + + + + true + everyChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + false + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + true + + + + true + true + + + + true + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + true + 0 ms + + + + false + 0 ms + + + + false + 0 ms + + + + true + 0 ms + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + false + true + + + + true + + + + false + everyChunk + + + + false + + + + false + everyChunk + + + + false + + + + true + true + 0 ns + + + + true + beginChunk + + + + true + 1000 ms + + + + true + 100 ms + + + + true + 10 s + + + + true + + + + false + + + + true + beginChunk + + + + true + everyChunk + + + + true + 100 ms + + + + true + beginChunk + + + + true + everyChunk + + + + true + + + + true + beginChunk + + + + true + beginChunk + + + + true + beginChunk + + + + true + 10 s + + + + true + 1000 ms + + + + true + 10 s + + + + true + beginChunk + + + + true + endChunk + + + + true + 5 s + + + + true + beginChunk + + + + true + everyChunk + + + + true + true + + + + true + true + + + + true + everyChunk + + + + true + endChunk + + + + true + endChunk + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + true + true + 10 ms + + + + false + true + + + + false + true + + + + false + true + + + + false + true + + + + false + true + + + + true + true + + + + true + 1000 ms + + + + true + + + + true + + + + true + + + + true + + + + true + 10 ms + + + + true + 0 ms + + + + 10 ms + true + + + + true + 10 ms + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 ms + + 10 ms + + 10 ms + + false + + + + diff --git a/java-11-openjdk/jvm-armhf.cfg b/java-11-openjdk/jvm-armhf.cfg new file mode 100644 index 00000000..76516d10 --- /dev/null +++ b/java-11-openjdk/jvm-armhf.cfg @@ -0,0 +1,3 @@ +-server KNOWN +-client IGNORE +-zero KNOWN diff --git a/java-11-openjdk/logging.properties b/java-11-openjdk/logging.properties new file mode 100644 index 00000000..58997e5f --- /dev/null +++ b/java-11-openjdk/logging.properties @@ -0,0 +1,63 @@ +############################################################ +# Default Logging Configuration File +# +# You can use a different file by specifying a filename +# with the java.util.logging.config.file system property. +# For example java -Djava.util.logging.config.file=myfile +############################################################ + +############################################################ +# Global properties +############################################################ + +# "handlers" specifies a comma separated list of log Handler +# classes. These handlers will be installed during VM startup. +# Note that these classes must be on the system classpath. +# By default we only configure a ConsoleHandler, which will only +# show messages at the INFO and above levels. +handlers= java.util.logging.ConsoleHandler + +# To also add the FileHandler, use the following line instead. +#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler + +# Default global logging level. +# This specifies which kinds of events are logged across +# all loggers. For any given facility this global level +# can be overriden by a facility specific level +# Note that the ConsoleHandler also has a separate level +# setting to limit messages printed to the console. +.level= INFO + +############################################################ +# Handler specific properties. +# Describes specific configuration info for Handlers. +############################################################ + +# default file output is in user's home directory. +java.util.logging.FileHandler.pattern = %h/java%u.log +java.util.logging.FileHandler.limit = 50000 +java.util.logging.FileHandler.count = 1 +# Default number of locks FileHandler can obtain synchronously. +# This specifies maximum number of attempts to obtain lock file by FileHandler +# implemented by incrementing the unique field %u as per FileHandler API documentation. +java.util.logging.FileHandler.maxLocks = 100 +java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter + +# Limit the message that are printed on the console to INFO and above. +java.util.logging.ConsoleHandler.level = INFO +java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter + +# Example to customize the SimpleFormatter output format +# to print one-line log message like this: +# : [] +# +# java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n + +############################################################ +# Facility specific properties. +# Provides extra control for each logger. +############################################################ + +# For example, set the com.xyz.foo logger to only log SEVERE +# messages: +com.xyz.foo.level = SEVERE diff --git a/java-11-openjdk/management/jmxremote.access b/java-11-openjdk/management/jmxremote.access new file mode 100644 index 00000000..a09e008f --- /dev/null +++ b/java-11-openjdk/management/jmxremote.access @@ -0,0 +1,79 @@ +###################################################################### +# Default Access Control File for Remote JMX(TM) Monitoring +###################################################################### +# +# Access control file for Remote JMX API access to monitoring. +# This file defines the allowed access for different roles. The +# password file (jmxremote.password by default) defines the roles and their +# passwords. To be functional, a role must have an entry in +# both the password and the access files. +# +# The default location of this file is $JRE/conf/management/jmxremote.access +# You can specify an alternate location by specifying a property in +# the management config file $JRE/conf/management/management.properties +# (See that file for details) +# +# The file format for password and access files is syntactically the same +# as the Properties file format. The syntax is described in the Javadoc +# for java.util.Properties.load. +# A typical access file has multiple lines, where each line is blank, +# a comment (like this one), or an access control entry. +# +# An access control entry consists of a role name, and an +# associated access level. The role name is any string that does not +# itself contain spaces or tabs. It corresponds to an entry in the +# password file (jmxremote.password). The access level is one of the +# following: +# "readonly" grants access to read attributes of MBeans. +# For monitoring, this means that a remote client in this +# role can read measurements but cannot perform any action +# that changes the environment of the running program. +# "readwrite" grants access to read and write attributes of MBeans, +# to invoke operations on them, and optionally +# to create or remove them. This access should be granted +# only to trusted clients, since they can potentially +# interfere with the smooth operation of a running program. +# +# The "readwrite" access level can optionally be followed by the "create" and/or +# "unregister" keywords. The "unregister" keyword grants access to unregister +# (delete) MBeans. The "create" keyword grants access to create MBeans of a +# particular class or of any class matching a particular pattern. Access +# should only be granted to create MBeans of known and trusted classes. +# +# For example, the following entry would grant readwrite access +# to "controlRole", as well as access to create MBeans of the class +# javax.management.monitor.CounterMonitor and to unregister any MBean: +# controlRole readwrite \ +# create javax.management.monitor.CounterMonitorMBean \ +# unregister +# or equivalently: +# controlRole readwrite unregister create javax.management.monitor.CounterMBean +# +# The following entry would grant readwrite access as well as access to create +# MBeans of any class in the packages javax.management.monitor and +# javax.management.timer: +# controlRole readwrite \ +# create javax.management.monitor.*,javax.management.timer.* \ +# unregister +# +# The \ character is defined in the Properties file syntax to allow continuation +# lines as shown here. A * in a class pattern matches a sequence of characters +# other than dot (.), so javax.management.monitor.* matches +# javax.management.monitor.CounterMonitor but not +# javax.management.monitor.foo.Bar. +# +# A given role should have at most one entry in this file. If a role +# has no entry, it has no access. +# If multiple entries are found for the same role name, then the last +# access entry is used. +# +# +# Default access control entries: +# o The "monitorRole" role has readonly access. +# o The "controlRole" role has readwrite access and can create the standard +# Timer and Monitor MBeans defined by the JMX API. + +monitorRole readonly +controlRole readwrite \ + create javax.management.monitor.*,javax.management.timer.* \ + unregister diff --git a/java-11-openjdk/management/management.properties b/java-11-openjdk/management/management.properties new file mode 100644 index 00000000..0c14bd61 --- /dev/null +++ b/java-11-openjdk/management/management.properties @@ -0,0 +1,302 @@ +##################################################################### +# Default Configuration File for Java Platform Management +##################################################################### +# +# The Management Configuration file (in java.util.Properties format) +# will be read if one of the following system properties is set: +# -Dcom.sun.management.jmxremote.port= +# or -Dcom.sun.management.config.file= +# +# The default Management Configuration file is: +# +# $JRE/conf/management/management.properties +# +# Another location for the Management Configuration File can be specified +# by the following property on the Java command line: +# +# -Dcom.sun.management.config.file= +# +# If -Dcom.sun.management.config.file= is set, the port +# number for the management agent can be specified in the config file +# using the following lines: +# +# ################ Management Agent Port ######################### +# +# For setting the JMX RMI agent port use the following line +# com.sun.management.jmxremote.port= +# + +##################################################################### +# Optional Instrumentation +##################################################################### +# +# By default only the basic instrumentation with low overhead is on. +# The following properties allow to selectively turn on optional +# instrumentation which are off by default and may have some +# additional overhead. +# +# com.sun.management.enableThreadContentionMonitoring +# +# This option enables thread contention monitoring if the +# Java virtual machine supports such instrumentation. +# Refer to the specification for the java.lang.management.ThreadMBean +# interface - see isThreadContentionMonitoringSupported() method. +# + +# To enable thread contention monitoring, uncomment the following line +# com.sun.management.enableThreadContentionMonitoring + +##################################################################### +# RMI Management Properties +##################################################################### +# +# If system property -Dcom.sun.management.jmxremote.port= +# is set then +# - A MBean server is started +# - JRE Platform MBeans are registered in the MBean server +# - RMI connector is published in a private readonly registry at +# specified port using a well known name, "jmxrmi" +# - the following properties are read for JMX remote management. +# +# The configuration can be specified only at startup time. +# Later changes to above system property (e.g. via setProperty method), +# this config file, the password file, or the access file have no effect to the +# running MBean server, the connector, or the registry. +# + +# +# ########## RMI connector settings for local management ########## +# +# com.sun.management.jmxremote.local.only=true|false +# Default for this property is true. (Case for true/false ignored) +# If this property is specified as true then the local JMX RMI connector +# server will only accept connection requests from clients running on +# the host where the out-of-the-box JMX management agent is running. +# In order to ensure backwards compatibility this property could be +# set to false. However, deploying the local management agent in this +# way is discouraged because the local JMX RMI connector server will +# accept connection requests from any client either local or remote. +# For remote management the remote JMX RMI connector server should +# be used instead with authentication and SSL/TLS encryption enabled. +# + +# For allowing the local management agent accept local +# and remote connection requests use the following line +# com.sun.management.jmxremote.local.only=false + +# +# ###################### RMI SSL ############################# +# +# com.sun.management.jmxremote.ssl=true|false +# Default for this property is true. (Case for true/false ignored) +# If this property is specified as false then SSL is not used. +# + +# For RMI monitoring without SSL use the following line +# com.sun.management.jmxremote.ssl=false + +# com.sun.management.jmxremote.ssl.config.file=filepath +# Specifies the location of the SSL configuration file. A properties +# file can be used to supply the keystore and truststore location and +# password settings thus avoiding to pass them as cleartext in the +# command-line. +# +# The current implementation of the out-of-the-box management agent will +# look up and use the properties specified below to configure the SSL +# keystore and truststore, if present: +# javax.net.ssl.keyStore= +# javax.net.ssl.keyStorePassword= +# javax.net.ssl.trustStore= +# javax.net.ssl.trustStorePassword= +# Any other properties in the file will be ignored. This will allow us +# to extend the property set in the future if required by the default +# SSL implementation. +# +# If the property "com.sun.management.jmxremote.ssl" is set to false, +# then this property is ignored. +# + +# For supplying the keystore settings in a file use the following line +# com.sun.management.jmxremote.ssl.config.file=filepath + +# com.sun.management.jmxremote.ssl.enabled.cipher.suites= +# The value of this property is a string that is a comma-separated list +# of SSL/TLS cipher suites to enable. This property can be specified in +# conjunction with the previous property "com.sun.management.jmxremote.ssl" +# in order to control which particular SSL/TLS cipher suites are enabled +# for use by accepted connections. If this property is not specified then +# the SSL/TLS RMI Server Socket Factory uses the SSL/TLS cipher suites that +# are enabled by default. +# + +# com.sun.management.jmxremote.ssl.enabled.protocols= +# The value of this property is a string that is a comma-separated list +# of SSL/TLS protocol versions to enable. This property can be specified in +# conjunction with the previous property "com.sun.management.jmxremote.ssl" +# in order to control which particular SSL/TLS protocol versions are +# enabled for use by accepted connections. If this property is not +# specified then the SSL/TLS RMI Server Socket Factory uses the SSL/TLS +# protocol versions that are enabled by default. +# + +# com.sun.management.jmxremote.ssl.need.client.auth=true|false +# Default for this property is false. (Case for true/false ignored) +# If this property is specified as true in conjunction with the previous +# property "com.sun.management.jmxremote.ssl" then the SSL/TLS RMI Server +# Socket Factory will require client authentication. +# + +# For RMI monitoring with SSL client authentication use the following line +# com.sun.management.jmxremote.ssl.need.client.auth=true + +# com.sun.management.jmxremote.registry.ssl=true|false +# Default for this property is false. (Case for true/false ignored) +# If this property is specified as true then the RMI registry used +# to bind the RMIServer remote object is protected with SSL/TLS +# RMI Socket Factories that can be configured with the properties: +# com.sun.management.jmxremote.ssl.config.file +# com.sun.management.jmxremote.ssl.enabled.cipher.suites +# com.sun.management.jmxremote.ssl.enabled.protocols +# com.sun.management.jmxremote.ssl.need.client.auth +# If the two properties below are true at the same time, i.e. +# com.sun.management.jmxremote.ssl=true +# com.sun.management.jmxremote.registry.ssl=true +# then the RMIServer remote object and the RMI registry are +# both exported with the same SSL/TLS RMI Socket Factories. +# + +# For using an SSL/TLS protected RMI registry use the following line +# com.sun.management.jmxremote.registry.ssl=true + +# +# ################ RMI User authentication ################ +# +# com.sun.management.jmxremote.authenticate=true|false +# Default for this property is true. (Case for true/false ignored) +# If this property is specified as false then no authentication is +# performed and all users are allowed all access. +# + +# For RMI monitoring without any checking use the following line +# com.sun.management.jmxremote.authenticate=false + +# +# ################ RMI Login configuration ################### +# +# com.sun.management.jmxremote.login.config= +# Specifies the name of a JAAS login configuration entry to use when +# authenticating users of RMI monitoring. +# +# Setting this property is optional - the default login configuration +# specifies a file-based authentication that uses the password file. +# +# When using this property to override the default login configuration +# then the named configuration entry must be in a file that gets loaded +# by JAAS. In addition, the login module(s) specified in the configuration +# should use the name and/or password callbacks to acquire the user's +# credentials. See the NameCallback and PasswordCallback classes in the +# javax.security.auth.callback package for more details. +# +# If the property "com.sun.management.jmxremote.authenticate" is set to +# false, then this property and the password & access files are ignored. +# + +# For a non-default login configuration use the following line +# com.sun.management.jmxremote.login.config= + +# +# ################ RMI Password file location ################## +# +# com.sun.management.jmxremote.password.file=filepath +# Specifies location for password file +# This is optional - default location is +# $JRE/conf/management/jmxremote.password +# +# If the property "com.sun.management.jmxremote.authenticate" is set to +# false, then this property and the password & access files are ignored. +# Otherwise the password file must exist and be in the valid format. +# If the password file is empty or non-existent then no access is allowed. +# + +# For a non-default password file location use the following line +# com.sun.management.jmxremote.password.file=filepath + +# +# ################# Hash passwords in password file ############## +# com.sun.management.jmxremote.password.toHashes = true|false +# Default for this property is true. +# Specifies if passwords in the password file should be hashed or not. +# If this property is true, and if the password file is writable, and if the +# system security policy allows writing into the password file, +# all the clear passwords in the password file will be replaced by +# their SHA3-512 hash when the file is read by the server +# + +# +# ################ RMI Access file location ##################### +# +# com.sun.management.jmxremote.access.file=filepath +# Specifies location for access file +# This is optional - default location is +# $JRE/conf/management/jmxremote.access +# +# If the property "com.sun.management.jmxremote.authenticate" is set to +# false, then this property and the password & access files are ignored. +# Otherwise, the access file must exist and be in the valid format. +# If the access file is empty or non-existent then no access is allowed. +# + +# For a non-default password file location use the following line +# com.sun.management.jmxremote.access.file=filepath +# + +# ################ Management agent listen interface ######################### +# +# com.sun.management.jmxremote.host= +# Specifies the local interface on which the JMX RMI agent will bind. +# This is useful when running on machines which have several +# interfaces defined. It makes it possible to listen to a specific +# subnet accessible through that interface. +# +# The format of the value for that property is any string accepted +# by java.net.InetAddress.getByName(String). +# + +# ################ Filter for ObjectInputStream ############################# +# com.sun.management.jmxremote.serial.filter.pattern= +# A filter, if configured, is used by java.io.ObjectInputStream during +# deserialization of parameters sent to the JMX default agent to validate the +# contents of the stream. +# A filter is configured as a sequence of patterns, each pattern is either +# matched against the name of a class in the stream or defines a limit. +# Patterns are separated by ";" (semicolon). +# Whitespace is significant and is considered part of the pattern. +# +# If a pattern includes a "=", it sets a limit. +# If a limit appears more than once the last value is used. +# Limits are checked before classes regardless of the order in the sequence of patterns. +# If any of the limits are exceeded, the filter status is REJECTED. +# +# maxdepth=value - the maximum depth of a graph +# maxrefs=value - the maximum number of internal references +# maxbytes=value - the maximum number of bytes in the input stream +# maxarray=value - the maximum array length allowed +# +# Other patterns, from left to right, match the class or package name as +# returned from Class.getName. +# If the class is an array type, the class or package to be matched is the element type. +# Arrays of any number of dimensions are treated the same as the element type. +# For example, a pattern of "!example.Foo", rejects creation of any instance or +# array of example.Foo. +# +# If the pattern starts with "!", the status is REJECTED if the remaining pattern +# is matched; otherwise the status is ALLOWED if the pattern matches. +# If the pattern contains "/", the non-empty prefix up to the "/" is the module name; +# if the module name matches the module name of the class then +# the remaining pattern is matched with the class name. +# If there is no "/", the module name is not compared. +# If the pattern ends with ".**" it matches any class in the package and all subpackages. +# If the pattern ends with ".*" it matches any class in the package. +# If the pattern ends with "*", it matches any class with the pattern as a prefix. +# If the pattern is equal to the class name, it matches. +# Otherwise, the status is UNDECIDED. diff --git a/java-11-openjdk/net.properties b/java-11-openjdk/net.properties new file mode 100644 index 00000000..d95715d5 --- /dev/null +++ b/java-11-openjdk/net.properties @@ -0,0 +1,121 @@ +############################################################ +# Default Networking Configuration File +# +# This file may contain default values for the networking system properties. +# These values are only used when the system properties are not specified +# on the command line or set programmatically. +# For now, only the various proxy settings can be configured here. +############################################################ + +# Whether or not the DefaultProxySelector will default to System Proxy +# settings when they do exist. +# Set it to 'true' to enable this feature and check for platform +# specific proxy settings +# Note that the system properties that do explicitly set proxies +# (like http.proxyHost) do take precedence over the system settings +# even if java.net.useSystemProxies is set to true. + +java.net.useSystemProxies=false + +#------------------------------------------------------------------------ +# Proxy configuration for the various protocol handlers. +# DO NOT uncomment these lines if you have set java.net.useSystemProxies +# to true as the protocol specific properties will take precedence over +# system settings. +#------------------------------------------------------------------------ + +# HTTP Proxy settings. proxyHost is the name of the proxy server +# (e.g. proxy.mydomain.com), proxyPort is the port number to use (default +# value is 80) and nonProxyHosts is a '|' separated list of hostnames which +# should be accessed directly, ignoring the proxy server (default value is +# localhost & 127.0.0.1). +# +# http.proxyHost= +# http.proxyPort=80 +http.nonProxyHosts=localhost|127.*|[::1] +# +# HTTPS Proxy Settings. proxyHost is the name of the proxy server +# (e.g. proxy.mydomain.com), proxyPort is the port number to use (default +# value is 443). The HTTPS protocol handlers uses the http nonProxyHosts list. +# +# https.proxyHost= +# https.proxyPort=443 +# +# FTP Proxy settings. proxyHost is the name of the proxy server +# (e.g. proxy.mydomain.com), proxyPort is the port number to use (default +# value is 80) and nonProxyHosts is a '|' separated list of hostnames which +# should be accessed directly, ignoring the proxy server (default value is +# localhost & 127.0.0.1). +# +# ftp.proxyHost= +# ftp.proxyPort=80 +ftp.nonProxyHosts=localhost|127.*|[::1] +# +# Gopher Proxy settings. proxyHost is the name of the proxy server +# (e.g. proxy.mydomain.com), proxyPort is the port number to use (default +# value is 80) +# +# gopher.proxyHost= +# gopher.proxyPort=80 +# +# Socks proxy settings. socksProxyHost is the name of the proxy server +# (e.g. socks.domain.com), socksProxyPort is the port number to use +# (default value is 1080) +# +# socksProxyHost= +# socksProxyPort=1080 +# +# HTTP Keep Alive settings. remainingData is the maximum amount of data +# in kilobytes that will be cleaned off the underlying socket so that it +# can be reused (default value is 512K), queuedConnections is the maximum +# number of Keep Alive connections to be on the queue for clean up (default +# value is 10). +# http.KeepAlive.remainingData=512 +# http.KeepAlive.queuedConnections=10 + +# Authentication Scheme restrictions for HTTP and HTTPS. +# +# In some environments certain authentication schemes may be undesirable +# when proxying HTTP or HTTPS. For example, "Basic" results in effectively the +# cleartext transmission of the user's password over the physical network. +# This section describes the mechanism for disabling authentication schemes +# based on the scheme name. Disabled schemes will be treated as if they are not +# supported by the implementation. +# +# The 'jdk.http.auth.tunneling.disabledSchemes' property lists the authentication +# schemes that will be disabled when tunneling HTTPS over a proxy, HTTP CONNECT. +# The 'jdk.http.auth.proxying.disabledSchemes' property lists the authentication +# schemes that will be disabled when proxying HTTP. +# +# In both cases the property is a comma-separated list of, case-insensitive, +# authentication scheme names, as defined by their relevant RFCs. An +# implementation may, but is not required to, support common schemes whose names +# include: 'Basic', 'Digest', 'NTLM', 'Kerberos', 'Negotiate'. A scheme that +# is not known, or not supported, by the implementation is ignored. +# +# Note: This property is currently used by the JDK Reference implementation. It +# is not guaranteed to be examined and used by other implementations. +# +#jdk.http.auth.proxying.disabledSchemes= +jdk.http.auth.tunneling.disabledSchemes=Basic + +# +# Transparent NTLM HTTP authentication mode on Windows. Transparent authentication +# can be used for the NTLM scheme, where the security credentials based on the +# currently logged in user's name and password can be obtained directly from the +# operating system, without prompting the user. This property has three possible +# values which regulate the behavior as shown below. Other unrecognized values +# are handled the same as 'disabled'. Note, that NTLM is not considered to be a +# strongly secure authentication scheme and care should be taken before enabling +# this mechanism. +# +# Transparent authentication never used. +#jdk.http.ntlm.transparentAuth=disabled +# +# Enabled for all hosts. +#jdk.http.ntlm.transparentAuth=allHosts +# +# Enabled for hosts that are trusted in Windows Internet settings +#jdk.http.ntlm.transparentAuth=trustedHosts +# +jdk.http.ntlm.transparentAuth=disabled diff --git a/java-11-openjdk/psfont.properties.ja b/java-11-openjdk/psfont.properties.ja new file mode 100644 index 00000000..d17cf40d --- /dev/null +++ b/java-11-openjdk/psfont.properties.ja @@ -0,0 +1,119 @@ +# +# +# Copyright (c) 1996, 2000, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# +# Japanese PostScript printer property file +# +font.num=16 +# +serif=serif +timesroman=serif +sansserif=sansserif +helvetica=sansserif +monospaced=monospaced +courier=monospaced +dialog=sansserif +dialoginput=monospaced +# +serif.latin1.plain=Times-Roman +serif.latin1.italic=Times-Italic +serif.latin1.bolditalic=Times-BoldItalic +serif.latin1.bold=Times-Bold +# +sansserif.latin1.plain=Helvetica +sansserif.latin1.italic=Helvetica-Oblique +sansserif.latin1.bolditalic=Helvetica-BoldOblique +sansserif.latin1.bold=Helvetica-Bold +# +monospaced.latin1.plain=Courier +monospaced.latin1.italic=Courier-Oblique +monospaced.latin1.bolditalic=Courier-BoldOblique +monospaced.latin1.bold=Courier-Bold +# +serif.x11jis0208.plain=Ryumin-Light-H +serif.x11jis0208.italic=Ryumin-Light-H +serif.x11jis0208.bolditalic=Ryumin-Light-H +serif.x11jis0208.bold=Ryumin-Light-H +# +sansserif.x11jis0208.plain=GothicBBB-Medium-H +sansserif.x11jis0208.italic=GothicBBB-Medium-H +sansserif.x11jis0208.bolditalic=GothicBBB-Medium-H +sansserif.x11jis0208.bold=GothicBBB-Medium-H +# +monospaced.x11jis0208.plain=GothicBBB-Medium-H +monospaced.x11jis0208.italic=GothicBBB-Medium-H +monospaced.x11jis0208.bolditalic=GothicBBB-Medium-H +monospaced.x11jis0208.bold=GothicBBB-Medium-H +# +serif.x11jis0201.plain=Ryumin-Light.Hankaku +serif.x11jis0201.italic=Ryumin-Light.Hankaku +serif.x11jis0201.bolditalic=Ryumin-Light.Hankaku +serif.x11jis0201.bold=Ryumin-Light.Hankaku +# +sansserif.x11jis0201.plain=GothicBBB-Medium.Hankaku +sansserif.x11jis0201.italic=GothicBBB-Medium.Hankaku +sansserif.x11jis0201.bolditalic=GothicBBB-Medium.Hankaku +sansserif.x11jis0201.bold=GothicBBB-Medium.Hankaku +# +monospaced.x11jis0201.plain=GothicBBB-Medium.Hankaku +monospaced.x11jis0201.italic=GothicBBB-Medium.Hankaku +monospaced.x11jis0201.bolditalic=GothicBBB-Medium.Hankaku +monospaced.x11jis0201.bold=GothicBBB-Medium.Hankaku +# +Helvetica=0 +Helvetica-Bold=1 +Helvetica-Oblique=2 +Helvetica-BoldOblique=3 +Times-Roman=4 +Times-Bold=5 +Times-Italic=6 +Times-BoldItalic=7 +Courier=8 +Courier-Bold=9 +Courier-Oblique=10 +Courier-BoldOblique=11 +GothicBBB-Medium-H=12 +Ryumin-Light-H=13 +GothicBBB-Medium.Hankaku=14 +Ryumin-Light.Hankaku=15 +# +font.0=Helvetica ISOF +font.1=Helvetica-Bold ISOF +font.2=Helvetica-Oblique ISOF +font.3=Helvetica-BoldOblique ISOF +font.4=Times-Roman ISOF +font.5=Times-Bold ISOF +font.6=Times-Italic ISOF +font.7=Times-BoldItalic ISOF +font.8=Courier ISOF +font.9=Courier-Bold ISOF +font.10=Courier-Oblique ISOF +font.11=Courier-BoldOblique ISOF +font.12=GothicBBB-Medium-H findfont +font.13=Ryumin-Light-H findfont +font.14=GothicBBB-Medium.Hankaku findfont +font.15=Ryumin-Light.Hankaku findfont +# diff --git a/java-11-openjdk/psfontj2d.properties b/java-11-openjdk/psfontj2d.properties new file mode 100644 index 00000000..5eb2c4b8 --- /dev/null +++ b/java-11-openjdk/psfontj2d.properties @@ -0,0 +1,323 @@ +# +# +# Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. + +# +# PostScript printer property file for Java 2D printing. +# +# WARNING: This is an internal implementation file, not a public file. +# Any customisation or reliance on the existence of this file and its +# contents or syntax is discouraged and unsupported. +# It may be incompatibly changed or removed without any notice. +# +# +font.num=35 +# +# Legacy logical font family names and logical font aliases should all +# map to the primary logical font names. +# +serif=serif +times=serif +timesroman=serif +sansserif=sansserif +helvetica=sansserif +dialog=sansserif +dialoginput=monospaced +monospaced=monospaced +courier=monospaced +# +# Next, physical fonts which can be safely mapped to standard postscript fonts +# These keys generally map to a value which is the same as the key, so +# the key/value is just a way to say the font has a mapping. +# Sometimes however we map more than one screen font to the same PS font. +# +avantgarde=avantgarde_book +avantgarde_book=avantgarde_book +avantgarde_demi=avantgarde_demi +avantgarde_book_oblique=avantgarde_book_oblique +avantgarde_demi_oblique=avantgarde_demi_oblique +# +itcavantgarde=avantgarde_book +itcavantgarde=avantgarde_book +itcavantgarde_demi=avantgarde_demi +itcavantgarde_oblique=avantgarde_book_oblique +itcavantgarde_demi_oblique=avantgarde_demi_oblique +# +bookman=bookman_light +bookman_light=bookman_light +bookman_demi=bookman_demi +bookman_light_italic=bookman_light_italic +bookman_demi_italic=bookman_demi_italic +# +# Exclude "helvetica" on its own as that's a legacy name for a logical font +helvetica_bold=helvetica_bold +helvetica_oblique=helvetica_oblique +helvetica_bold_oblique=helvetica_bold_oblique +# +itcbookman_light=bookman_light +itcbookman_demi=bookman_demi +itcbookman_light_italic=bookman_light_italic +itcbookman_demi_italic=bookman_demi_italic +# +# Exclude "courier" on its own as that's a legacy name for a logical font +courier_bold=courier_bold +courier_oblique=courier_oblique +courier_bold_oblique=courier_bold_oblique +# +courier_new=courier +courier_new_bold=courier_bold +# +monotype_century_schoolbook=newcenturyschoolbook +monotype_century_schoolbook_bold=newcenturyschoolbook_bold +monotype_century_schoolbook_italic=newcenturyschoolbook_italic +monotype_century_schoolbook_bold_italic=newcenturyschoolbook_bold_italic +# +newcenturyschoolbook=newcenturyschoolbook +newcenturyschoolbook_bold=newcenturyschoolbook_bold +newcenturyschoolbook_italic=newcenturyschoolbook_italic +newcenturyschoolbook_bold_italic=newcenturyschoolbook_bold_italic +# +palatino=palatino +palatino_bold=palatino_bold +palatino_italic=palatino_italic +palatino_bold_italic=palatino_bold_italic +# +# Exclude "times" on its own as that's a legacy name for a logical font +times_bold=times_roman_bold +times_italic=times_roman_italic +times_bold_italic=times_roman_bold_italic +# +times_roman=times_roman +times_roman_bold=times_roman_bold +times_roman_italic=times_roman_italic +times_roman_bold_italic=times_roman_bold_italic +# +times_new_roman=times_roman +times_new_roman_bold=times_roman_bold +times_new_roman_italic=times_roman_italic +times_new_roman_bold_italic=times_roman_bold_italic +# +zapfchancery_italic=zapfchancery_italic +itczapfchancery_italic=zapfchancery_italic +# +# Next the mapping of the font name + charset + style to Postscript font name +# for the logical fonts. +# +serif.latin1.plain=Times-Roman +serif.latin1.bold=Times-Bold +serif.latin1.italic=Times-Italic +serif.latin1.bolditalic=Times-BoldItalic +serif.symbol.plain=Symbol +serif.dingbats.plain=ZapfDingbats +serif.symbol.bold=Symbol +serif.dingbats.bold=ZapfDingbats +serif.symbol.italic=Symbol +serif.dingbats.italic=ZapfDingbats +serif.symbol.bolditalic=Symbol +serif.dingbats.bolditalic=ZapfDingbats +# +sansserif.latin1.plain=Helvetica +sansserif.latin1.bold=Helvetica-Bold +sansserif.latin1.italic=Helvetica-Oblique +sansserif.latin1.bolditalic=Helvetica-BoldOblique +sansserif.symbol.plain=Symbol +sansserif.dingbats.plain=ZapfDingbats +sansserif.symbol.bold=Symbol +sansserif.dingbats.bold=ZapfDingbats +sansserif.symbol.italic=Symbol +sansserif.dingbats.italic=ZapfDingbats +sansserif.symbol.bolditalic=Symbol +sansserif.dingbats.bolditalic=ZapfDingbats +# +monospaced.latin1.plain=Courier +monospaced.latin1.bold=Courier-Bold +monospaced.latin1.italic=Courier-Oblique +monospaced.latin1.bolditalic=Courier-BoldOblique +monospaced.symbol.plain=Symbol +monospaced.dingbats.plain=ZapfDingbats +monospaced.symbol.bold=Symbol +monospaced.dingbats.bold=ZapfDingbats +monospaced.symbol.italic=Symbol +monospaced.dingbats.italic=ZapfDingbats +monospaced.symbol.bolditalic=Symbol +monospaced.dingbats.bolditalic=ZapfDingbats +# +# Next the mapping of the font name + charset + style to Postscript font name +# for the physical fonts. Since these always report style as plain, the +# style key is always plain. So we map using the face name to the correct +# style for the postscript font. This is possible since the face names can +# be replied upon to be different for each style. +# However an application may try to create a Font applying a style to an +# physical name. We want to map to the correct Postscript font there too +# if possible but we do not map cases where the application tries to +# augment a style (eg ask for a bold version of a bold font) +# Defer to the 2D package to attempt create an artificially styled version +# +avantgarde_book.latin1.plain=AvantGarde-Book +avantgarde_demi.latin1.plain=AvantGarde-Demi +avantgarde_book_oblique.latin1.plain=AvantGarde-BookOblique +avantgarde_demi_oblique.latin1.plain=AvantGarde-DemiOblique +# +avantgarde_book.latin1.bold=AvantGarde-Demi +avantgarde_book.latin1.italic=AvantGarde-BookOblique +avantgarde_book.latin1.bolditalic=AvantGarde-DemiOblique +avantgarde_demi.latin1.italic=AvantGarde-DemiOblique +avantgarde_book_oblique.latin1.bold=AvantGarde-DemiOblique +# +bookman_light.latin1.plain=Bookman-Light +bookman_demi.latin1.plain=Bookman-Demi +bookman_light_italic.latin1.plain=Bookman-LightItalic +bookman_demi_italic.latin1.plain=Bookman-DemiItalic +# +bookman_light.latin1.bold=Bookman-Demi +bookman_light.latin1.italic=Bookman-LightItalic +bookman_light.latin1.bolditalic=Bookman-DemiItalic +bookman_light_bold.latin1.italic=Bookman-DemiItalic +bookman_light_italic.latin1.bold=Bookman-DemiItalic +# +courier.latin1.plain=Courier +courier_bold.latin1.plain=Courier-Bold +courier_oblique.latin1.plain=Courier-Oblique +courier_bold_oblique.latin1.plain=Courier-BoldOblique +courier.latin1.bold=Courier-Bold +courier.latin1.italic=Courier-Oblique +courier.latin1.bolditalic=Courier-BoldOblique +courier_bold.latin1.italic=Courier-BoldOblique +courier_italic.latin1.bold=Courier-BoldOblique +# +helvetica_bold.latin1.plain=Helvetica-Bold +helvetica_oblique.latin1.plain=Helvetica-Oblique +helvetica_bold_oblique.latin1.plain=Helvetica-BoldOblique +helvetica.latin1.bold=Helvetica-Bold +helvetica.latin1.italic=Helvetica-Oblique +helvetica.latin1.bolditalic=Helvetica-BoldOblique +helvetica_bold.latin1.italic=Helvetica-BoldOblique +helvetica_italic.latin1.bold=Helvetica-BoldOblique +# +newcenturyschoolbook.latin1.plain=NewCenturySchlbk-Roman +newcenturyschoolbook_bold.latin1.plain=NewCenturySchlbk-Bold +newcenturyschoolbook_italic.latin1.plain=NewCenturySchlbk-Italic +newcenturyschoolbook_bold_italic.latin1.plain=NewCenturySchlbk-BoldItalic +newcenturyschoolbook.latin1.bold=NewCenturySchlbk-Bold +newcenturyschoolbook.latin1.italic=NewCenturySchlbk-Italic +newcenturyschoolbook.latin1.bolditalic=NewCenturySchlbk-BoldItalic +newcenturyschoolbook_bold.latin1.italic=NewCenturySchlbk-BoldItalic +newcenturyschoolbook_italic.latin1.bold=NewCenturySchlbk-BoldItalic +# +palatino.latin1.plain=Palatino-Roman +palatino_bold.latin1.plain=Palatino-Bold +palatino_italic.latin1.plain=Palatino-Italic +palatino_bold_italic.latin1.plain=Palatino-BoldItalic +palatino.latin1.bold=Palatino-Bold +palatino.latin1.italic=Palatino-Italic +palatino.latin1.bolditalic=Palatino-BoldItalic +palatino_bold.latin1.italic=Palatino-BoldItalic +palatino_italic.latin1.bold=Palatino-BoldItalic +# +times_roman.latin1.plain=Times-Roman +times_roman_bold.latin1.plain=Times-Bold +times_roman_italic.latin1.plain=Times-Italic +times_roman_bold_italic.latin1.plain=Times-BoldItalic +times_roman.latin1.bold=Times-Bold +times_roman.latin1.italic=Times-Italic +times_roman.latin1.bolditalic=Times-BoldItalic +times_roman_bold.latin1.italic=Times-BoldItalic +times_roman_italic.latin1.bold=Times-BoldItalic +# +zapfchancery_italic.latin1.plain=ZapfChancery-MediumItalic +# +# Finally the mappings of PS font names to indexes. +# +AvantGarde-Book=0 +AvantGarde-BookOblique=1 +AvantGarde-Demi=2 +AvantGarde-DemiOblique=3 +Bookman-Demi=4 +Bookman-DemiItalic=5 +Bookman-Light=6 +Bookman-LightItalic=7 +Courier=8 +Courier-Bold=9 +Courier-BoldOblique=10 +Courier-Oblique=11 +Helvetica=12 +Helvetica-Bold=13 +Helvetica-BoldOblique=14 +Helvetica-Narrow=15 +Helvetica-Narrow-Bold=16 +Helvetica-Narrow-BoldOblique=17 +Helvetica-Narrow-Oblique=18 +Helvetica-Oblique=19 +NewCenturySchlbk-Bold=20 +NewCenturySchlbk-BoldItalic=21 +NewCenturySchlbk-Italic=22 +NewCenturySchlbk-Roman=23 +Palatino-Bold=24 +Palatino-BoldItalic=25 +Palatino-Italic=26 +Palatino-Roman=27 +Symbol=28 +Times-Bold=29 +Times-BoldItalic=30 +Times-Italic=31 +Times-Roman=32 +ZapfDingbats=33 +ZapfChancery-MediumItalic=34 +# +font.0=AvantGarde-Book ISOF +font.1=AvantGarde-BookOblique ISOF +font.2=AvantGarde-Demi ISOF +font.3=AvantGarde-DemiOblique ISOF +font.4=Bookman-Demi ISOF +font.5=Bookman-DemiItalic ISOF +font.6=Bookman-Light ISOF +font.7=Bookman-LightItalic ISOF +font.8=Courier ISOF +font.9=Courier-Bold ISOF +font.10=Courier-BoldOblique ISOF +font.11=Courier-Oblique ISOF +font.12=Helvetica ISOF +font.13=Helvetica-Bold ISOF +font.14=Helvetica-BoldOblique ISOF +font.15=Helvetica-Narrow ISOF +font.16=Helvetica-Narrow-Bold ISOF +font.17=Helvetica-Narrow-BoldOblique ISOF +font.18=Helvetica-Narrow-Oblique ISOF +font.19=Helvetica-Oblique ISOF +font.20=NewCenturySchlbk-Bold ISOF +font.21=NewCenturySchlbk-BoldItalic ISOF +font.22=NewCenturySchlbk-Italic ISOF +font.23=NewCenturySchlbk-Roman ISOF +font.24=Palatino-Bold ISOF +font.25=Palatino-BoldItalic ISOF +font.26=Palatino-Italic ISOF +font.27=Palatino-Roman ISOF +font.28=Symbol findfont +font.29=Times-Bold ISOF +font.30=Times-BoldItalic ISOF +font.31=Times-Italic ISOF +font.32=Times-Roman ISOF +font.33=ZapfDingbats findfont +font.34=ZapfChancery-MediumItalic ISOF +# diff --git a/java-11-openjdk/security/blacklisted.certs b/java-11-openjdk/security/blacklisted.certs new file mode 100644 index 00000000..beded9ed --- /dev/null +++ b/java-11-openjdk/security/blacklisted.certs @@ -0,0 +1,39 @@ +Algorithm=SHA-256 +03DB9E5E79FE6117177F81C11595AF598CB176AF766290DBCEB2C318B32E39A2 +08C396C006A21055D00826A5781A5CCFCE2C8D053AB3C197637A4A7A5BB9A650 +14E6D2764A4B06701C6CBC376A253775F79C782FBCB6C0EE6F99DE4BA1024ADD +1C5E6985ACC09221DBD1A4B7BBC6D3A8C3F8540D19F20763A9537FDD42B4FFE7 +1F6BF8A3F2399AF7FD04516C2719C566CBAD51F412738F66D0457E1E6BDE6F2D +2A464E4113141352C7962FBD1706ED4B88533EF24D7BBA6CCC5D797FD202F1C4 +31C8FD37DB9B56E708B03D1F01848B068C6DA66F36FB5D82C008C6040FA3E133 +3946901F46B0071E90D78279E82FABABCA177231A704BE72C5B0E8918566EA66 +3E11CF90719F6FB44D94EAC9A156B89BEBE7B8598F28EC58913F2BFCAF91D0C0 +423279423B9FC8CB06F1BB7C3B247522B948D5F18939F378ECC901126DE40BFB +450F1B421BB05C8609854884559C323319619E8B06B001EA2DCBB74A23AA3BE2 +4CBBF8256BC9888A8007B2F386940A2E394378B0D903CBB3863C5A6394B889CE +4FEE0163686ECBD65DB968E7494F55D84B25486D438E9DE558D629D28CD4D176 +535D04DFCE027C70BD5F8A9E0AD4F218E9AFDCF5BBCF9B6DE0D81E148E2E3172 +568FAF38D9F155F624838E2181B1CEB4D8459305EE652B0F810C97C3611BFE19 +585CFE6B7436CBD4E732763A2137D7F49599BA9B1790E688FCEC799C58EB84A6 +5E83124D68D24E8E177E306DF643D5EA99C5A94D6FC34B072F7544A1CABB7C7B +71CB00749B9130FB2707A2664BFF958D0FCC8E161D9674C7450BA0FC2BEAF9D3 +76A45A496031E4DD2D7ED23E8F6FF97DBDEA980BAAC8B0BA94D7EDB551348645 +8A1BD21661C60015065212CC98B1ABB50DFD14C872A208E66BAE890F25C448AF +9ED8F9B0E8E42A1656B8E1DD18F42BA42DC06FE52686173BA2FC70E756F207DC +9FADCE80D62A959F9930D748488C1E22E821F4E1E4A43584B848C2FC11E04D77 +A686FEE577C88AB664D0787ECDFFF035F4806F3DE418DC9E4D516324FFF02083 +A90132CEA1D4F7185E4F688EFFD16F6AC14DFD78356A807599A5DABBEEF3333E +B8686723E415534BC0DBD16326F9486F85B0B0799BF6639334E61DAAE67F36CD +C0D1F42B9F4BF7ACC045B7BB5D4805E10737F67B6310CE505248D543D0D5FE07 +D0156949F1381943442C6974E9B5B49EF441BB799EF20477B90A89C3F33620CE +D151962D954970501C60079258EBCFA38502E0A9F03CD640322B08C0A3117FE5 +D24566BF315F4E597D6E381C87119FB4198F5E9E2607F5F4AB362EF7E2E7672F +D3A936E1A7775A45217C8296A1F22AC5631DCDEC45594099E78EEEBBEDCBA967 +D6CEAE5D9E047FAF7D797858D229AC991AD44316D1E2A37A21926D763153593A +DF21016B00FC54F9FE3BC8B039911BB216E9162FAD2FD14D990AB96E951B49BE +E0E740E4B0F8B3548181FF75B5372FAF4C70B99EC995D694ED0FB91B03FF8D21 +EC30C9C3065A06BB07DC5B1C6B497F370C1CA65C0F30C08E042BA6BCECC78F2C +F5B6F88F75D391A4B1EB336F9E201239FB6B1377DB8CFA7B84736216E5AFFFD7 +FBB12938ABD86C125796EDF4162D291028890A7D6C0C1CCA75FD4B95EBFA7A1A +FC02FD48DB92D4DCE6F11679D38354CF750CFC7F584A520EB90BDE80E241F2BD +FDEDB5BDFCB67411513A61AEE5CB5B5D7C52AF06028EFC996CC1B05B1D6CEA2B diff --git a/java-11-openjdk/security/default.policy b/java-11-openjdk/security/default.policy new file mode 100644 index 00000000..ab59a334 --- /dev/null +++ b/java-11-openjdk/security/default.policy @@ -0,0 +1,219 @@ +// +// Permissions required by modules stored in a run-time image and loaded +// by the platform class loader. +// +// NOTE that this file is not intended to be modified. If additional +// permissions need to be granted to the modules in this file, it is +// recommended that they be configured in a separate policy file or +// ${java.home}/conf/security/java.policy. +// + + +grant codeBase "jrt:/java.compiler" { + permission java.security.AllPermission; +}; + + +grant codeBase "jrt:/java.net.http" { + permission java.lang.RuntimePermission "accessClassInPackage.sun.net"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www"; + permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc"; + permission java.net.SocketPermission "*","connect,resolve"; + permission java.net.URLPermission "http:*","*:*"; + permission java.net.URLPermission "https:*","*:*"; + permission java.net.URLPermission "ws:*","*:*"; + permission java.net.URLPermission "wss:*","*:*"; + permission java.net.URLPermission "socket:*","CONNECT"; // proxy + // For request/response body processors, fromFile, asFile + permission java.io.FilePermission "<>","read,write,delete"; + permission java.util.PropertyPermission "*","read"; + permission java.net.NetPermission "getProxySelector"; +}; + +grant codeBase "jrt:/java.scripting" { + permission java.security.AllPermission; +}; + +grant codeBase "jrt:/java.security.jgss" { + permission java.security.AllPermission; +}; + +grant codeBase "jrt:/java.smartcardio" { + permission javax.smartcardio.CardPermission "*", "*"; + permission java.lang.RuntimePermission "loadLibrary.j2pcsc"; + permission java.lang.RuntimePermission + "accessClassInPackage.sun.security.jca"; + permission java.lang.RuntimePermission + "accessClassInPackage.sun.security.util"; + permission java.util.PropertyPermission + "javax.smartcardio.TerminalFactory.DefaultType", "read"; + permission java.util.PropertyPermission "os.name", "read"; + permission java.util.PropertyPermission "os.arch", "read"; + permission java.util.PropertyPermission "sun.arch.data.model", "read"; + permission java.util.PropertyPermission + "sun.security.smartcardio.library", "read"; + permission java.util.PropertyPermission + "sun.security.smartcardio.t0GetResponse", "read"; + permission java.util.PropertyPermission + "sun.security.smartcardio.t1GetResponse", "read"; + permission java.util.PropertyPermission + "sun.security.smartcardio.t1StripLe", "read"; + // needed for looking up native PC/SC library + permission java.io.FilePermission "<>","read"; + permission java.security.SecurityPermission "putProviderProperty.SunPCSC"; + permission java.security.SecurityPermission + "clearProviderProperties.SunPCSC"; + permission java.security.SecurityPermission + "removeProviderProperty.SunPCSC"; +}; + +grant codeBase "jrt:/java.sql" { + permission java.security.AllPermission; +}; + +grant codeBase "jrt:/java.sql.rowset" { + permission java.security.AllPermission; +}; + + +grant codeBase "jrt:/java.xml.crypto" { + permission java.lang.RuntimePermission + "accessClassInPackage.sun.security.util"; + permission java.util.PropertyPermission "*", "read"; + permission java.security.SecurityPermission "putProviderProperty.XMLDSig"; + permission java.security.SecurityPermission + "clearProviderProperties.XMLDSig"; + permission java.security.SecurityPermission + "removeProviderProperty.XMLDSig"; + permission java.security.SecurityPermission + "com.sun.org.apache.xml.internal.security.register"; + permission java.security.SecurityPermission + "getProperty.jdk.xml.dsig.secureValidationPolicy"; + permission java.lang.RuntimePermission + "accessClassInPackage.com.sun.org.apache.xml.internal.*"; + permission java.lang.RuntimePermission + "accessClassInPackage.com.sun.org.apache.xpath.internal"; + permission java.lang.RuntimePermission + "accessClassInPackage.com.sun.org.apache.xpath.internal.*"; +}; + + +grant codeBase "jrt:/jdk.accessibility" { + permission java.lang.RuntimePermission "accessClassInPackage.sun.awt"; +}; + +grant codeBase "jrt:/jdk.charsets" { + permission java.util.PropertyPermission "os.name", "read"; + permission java.util.PropertyPermission "sun.nio.cs.map", "read"; + permission java.lang.RuntimePermission "charsetProvider"; + permission java.lang.RuntimePermission + "accessClassInPackage.jdk.internal.misc"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.cs"; +}; + +grant codeBase "jrt:/jdk.crypto.ec" { + permission java.lang.RuntimePermission + "accessClassInPackage.sun.security.*"; + permission java.lang.RuntimePermission "loadLibrary.sunec"; + permission java.security.SecurityPermission "putProviderProperty.SunEC"; + permission java.security.SecurityPermission "clearProviderProperties.SunEC"; + permission java.security.SecurityPermission "removeProviderProperty.SunEC"; +}; + +grant codeBase "jrt:/jdk.crypto.cryptoki" { + permission java.lang.RuntimePermission + "accessClassInPackage.com.sun.crypto.provider"; + permission java.lang.RuntimePermission + "accessClassInPackage.sun.security.*"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; + permission java.lang.RuntimePermission "loadLibrary.j2pkcs11"; + permission java.util.PropertyPermission "sun.security.pkcs11.allowSingleThreadedModules", "read"; + permission java.util.PropertyPermission "sun.security.pkcs11.disableKeyExtraction", "read"; + permission java.util.PropertyPermission "os.name", "read"; + permission java.util.PropertyPermission "os.arch", "read"; + permission java.util.PropertyPermission "jdk.crypto.KeyAgreement.legacyKDF", "read"; + permission java.security.SecurityPermission "putProviderProperty.*"; + permission java.security.SecurityPermission "clearProviderProperties.*"; + permission java.security.SecurityPermission "removeProviderProperty.*"; + permission java.security.SecurityPermission + "getProperty.auth.login.defaultCallbackHandler"; + permission java.security.SecurityPermission "authProvider.*"; + // Needed for reading PKCS11 config file and NSS library check + permission java.io.FilePermission "<>", "read"; +}; + +grant codeBase "jrt:/jdk.desktop" { + permission java.lang.RuntimePermission "accessClassInPackage.com.sun.awt"; +}; + +grant codeBase "jrt:/jdk.dynalink" { + permission java.security.AllPermission; +}; + +grant codeBase "jrt:/jdk.httpserver" { + permission java.security.AllPermission; +}; + +grant codeBase "jrt:/jdk.internal.le" { + permission java.security.AllPermission; +}; + +grant codeBase "jrt:/jdk.internal.vm.compiler" { + permission java.security.AllPermission; +}; + +grant codeBase "jrt:/jdk.internal.vm.compiler.management" { + permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.vm.compiler.collections"; + permission java.lang.RuntimePermission "accessClassInPackage.jdk.vm.ci.runtime"; + permission java.lang.RuntimePermission "accessClassInPackage.org.graalvm.compiler.core.common"; + permission java.lang.RuntimePermission "accessClassInPackage.org.graalvm.compiler.debug"; + permission java.lang.RuntimePermission "accessClassInPackage.org.graalvm.compiler.hotspot"; + permission java.lang.RuntimePermission "accessClassInPackage.org.graalvm.compiler.options"; + permission java.lang.RuntimePermission "accessClassInPackage.org.graalvm.compiler.phases.common.jmx"; + permission java.lang.RuntimePermission "accessClassInPackage.org.graalvm.compiler.serviceprovider"; +}; + +grant codeBase "jrt:/jdk.jsobject" { + permission java.security.AllPermission; +}; + +grant codeBase "jrt:/jdk.localedata" { + permission java.lang.RuntimePermission "accessClassInPackage.sun.text.*"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.util.*"; +}; + +grant codeBase "jrt:/jdk.naming.dns" { + permission java.security.AllPermission; +}; + +grant codeBase "jrt:/jdk.scripting.nashorn" { + permission java.security.AllPermission; +}; + +grant codeBase "jrt:/jdk.scripting.nashorn.shell" { + permission java.security.AllPermission; +}; + +grant codeBase "jrt:/jdk.security.auth" { + permission java.security.AllPermission; +}; + +grant codeBase "jrt:/jdk.security.jgss" { + permission java.security.AllPermission; +}; + +grant codeBase "jrt:/jdk.zipfs" { + permission java.io.FilePermission "<>", "read,write,delete"; + permission java.lang.RuntimePermission "fileSystemProvider"; + permission java.lang.RuntimePermission "accessUserInformation"; + permission java.util.PropertyPermission "os.name", "read"; +}; + +// permissions needed by applications using java.desktop module +grant { + permission java.lang.RuntimePermission "accessClassInPackage.com.sun.beans"; + permission java.lang.RuntimePermission "accessClassInPackage.com.sun.beans.*"; + permission java.lang.RuntimePermission "accessClassInPackage.com.sun.java.swing.plaf.*"; + permission java.lang.RuntimePermission "accessClassInPackage.com.apple.*"; +}; diff --git a/java-11-openjdk/security/java.policy b/java-11-openjdk/security/java.policy new file mode 100644 index 00000000..1554541d --- /dev/null +++ b/java-11-openjdk/security/java.policy @@ -0,0 +1,44 @@ +// +// This system policy file grants a set of default permissions to all domains +// and can be configured to grant additional permissions to modules and other +// code sources. The code source URL scheme for modules linked into a +// run-time image is "jrt". +// +// For example, to grant permission to read the "foo" property to the module +// "com.greetings", the grant entry is: +// +// grant codeBase "jrt:/com.greetings" { +// permission java.util.PropertyPermission "foo", "read"; +// }; +// + +// default permissions granted to all domains +grant { + // allows anyone to listen on dynamic ports + permission java.net.SocketPermission "localhost:0", "listen"; + + // "standard" properies that can be read by anyone + permission java.util.PropertyPermission "java.version", "read"; + permission java.util.PropertyPermission "java.vendor", "read"; + permission java.util.PropertyPermission "java.vendor.url", "read"; + permission java.util.PropertyPermission "java.class.version", "read"; + permission java.util.PropertyPermission "os.name", "read"; + permission java.util.PropertyPermission "os.version", "read"; + permission java.util.PropertyPermission "os.arch", "read"; + permission java.util.PropertyPermission "file.separator", "read"; + permission java.util.PropertyPermission "path.separator", "read"; + permission java.util.PropertyPermission "line.separator", "read"; + permission java.util.PropertyPermission + "java.specification.version", "read"; + permission java.util.PropertyPermission "java.specification.vendor", "read"; + permission java.util.PropertyPermission "java.specification.name", "read"; + permission java.util.PropertyPermission + "java.vm.specification.version", "read"; + permission java.util.PropertyPermission + "java.vm.specification.vendor", "read"; + permission java.util.PropertyPermission + "java.vm.specification.name", "read"; + permission java.util.PropertyPermission "java.vm.version", "read"; + permission java.util.PropertyPermission "java.vm.vendor", "read"; + permission java.util.PropertyPermission "java.vm.name", "read"; +}; diff --git a/java-11-openjdk/security/java.security b/java-11-openjdk/security/java.security new file mode 100644 index 00000000..30a1f37b --- /dev/null +++ b/java-11-openjdk/security/java.security @@ -0,0 +1,1363 @@ +# +# This is the "master security properties file". +# +# An alternate java.security properties file may be specified +# from the command line via the system property +# +# -Djava.security.properties= +# +# This properties file appends to the master security properties file. +# If both properties files specify values for the same key, the value +# from the command-line properties file is selected, as it is the last +# one loaded. +# +# Also, if you specify +# +# -Djava.security.properties== (2 equals), +# +# then that properties file completely overrides the master security +# properties file. +# +# To disable the ability to specify an additional properties file from +# the command line, set the key security.overridePropertiesFile +# to false in the master security properties file. It is set to true +# by default. + +# In this file, various security properties are set for use by +# java.security classes. This is where users can statically register +# Cryptography Package Providers ("providers" for short). The term +# "provider" refers to a package or set of packages that supply a +# concrete implementation of a subset of the cryptography aspects of +# the Java Security API. A provider may, for example, implement one or +# more digital signature algorithms or message digest algorithms. +# +# Each provider must implement a subclass of the Provider class. +# To register a provider in this master security properties file, +# specify the provider and priority in the format +# +# security.provider.= +# +# This declares a provider, and specifies its preference +# order n. The preference order is the order in which providers are +# searched for requested algorithms (when no specific provider is +# requested). The order is 1-based; 1 is the most preferred, followed +# by 2, and so on. +# +# must specify the name of the Provider as passed to its super +# class java.security.Provider constructor. This is for providers loaded +# through the ServiceLoader mechanism. +# +# must specify the subclass of the Provider class whose +# constructor sets the values of various properties that are required +# for the Java Security API to look up the algorithms or other +# facilities implemented by the provider. This is for providers loaded +# through classpath. +# +# Note: Providers can be dynamically registered instead by calls to +# either the addProvider or insertProviderAt method in the Security +# class. + +# +# List of providers and their preference orders (see above): +# +security.provider.1=SUN +security.provider.2=SunRsaSign +security.provider.3=SunEC +security.provider.4=SunJSSE +security.provider.5=SunJCE +security.provider.6=SunJGSS +security.provider.7=SunSASL +security.provider.8=XMLDSig +security.provider.9=SunPCSC +security.provider.10=JdkLDAP +security.provider.11=JdkSASL +security.provider.12=SunPKCS11 + +# +# A list of preferred providers for specific algorithms. These providers will +# be searched for matching algorithms before the list of registered providers. +# Entries containing errors (parsing, etc) will be ignored. Use the +# -Djava.security.debug=jca property to debug these errors. +# +# The property is a comma-separated list of serviceType.algorithm:provider +# entries. The serviceType (example: "MessageDigest") is optional, and if +# not specified, the algorithm applies to all service types that support it. +# The algorithm is the standard algorithm name or transformation. +# Transformations can be specified in their full standard name +# (ex: AES/CBC/PKCS5Padding), or as partial matches (ex: AES, AES/CBC). +# The provider is the name of the provider. Any provider that does not +# also appear in the registered list will be ignored. +# +# There is a special serviceType for this property only to group a set of +# algorithms together. The type is "Group" and is followed by an algorithm +# keyword. Groups are to simplify and lessen the entries on the property +# line. Current groups are: +# Group.SHA2 = SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256 +# Group.HmacSHA2 = HmacSHA224, HmacSHA256, HmacSHA384, HmacSHA512 +# Group.SHA2RSA = SHA224withRSA, SHA256withRSA, SHA384withRSA, SHA512withRSA +# Group.SHA2DSA = SHA224withDSA, SHA256withDSA, SHA384withDSA, SHA512withDSA +# Group.SHA2ECDSA = SHA224withECDSA, SHA256withECDSA, SHA384withECDSA, \ +# SHA512withECDSA +# Group.SHA3 = SHA3-224, SHA3-256, SHA3-384, SHA3-512 +# Group.HmacSHA3 = HmacSHA3-224, HmacSHA3-256, HmacSHA3-384, HmacSHA3-512 +# +# Example: +# jdk.security.provider.preferred=AES/GCM/NoPadding:SunJCE, \ +# MessageDigest.SHA-256:SUN, Group.HmacSHA2:SunJCE +# +#jdk.security.provider.preferred= + + +# +# Sun Provider SecureRandom seed source. +# +# Select the primary source of seed data for the "NativePRNG", "SHA1PRNG" +# and "DRBG" SecureRandom implementations in the "Sun" provider. +# (Other SecureRandom implementations might also use this property.) +# +# On Unix-like systems (for example, Solaris/Linux/MacOS), the +# "NativePRNG", "SHA1PRNG" and "DRBG" implementations obtains seed data from +# special device files such as file:/dev/random. +# +# On Windows systems, specifying the URLs "file:/dev/random" or +# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding +# mechanism for SHA1PRNG and DRBG. +# +# By default, an attempt is made to use the entropy gathering device +# specified by the "securerandom.source" Security property. If an +# exception occurs while accessing the specified URL: +# +# NativePRNG: +# a default value of /dev/random will be used. If neither +# are available, the implementation will be disabled. +# "file" is the only currently supported protocol type. +# +# SHA1PRNG and DRBG: +# the traditional system/thread activity algorithm will be used. +# +# The entropy gathering device can also be specified with the System +# property "java.security.egd". For example: +# +# % java -Djava.security.egd=file:/dev/random MainClass +# +# Specifying this System property will override the +# "securerandom.source" Security property. +# +# In addition, if "file:/dev/random" or "file:/dev/urandom" is +# specified, the "NativePRNG" implementation will be more preferred than +# DRBG and SHA1PRNG in the Sun provider. +# +securerandom.source=file:/dev/random + +# +# A list of known strong SecureRandom implementations. +# +# To help guide applications in selecting a suitable strong +# java.security.SecureRandom implementation, Java distributions should +# indicate a list of known strong implementations using the property. +# +# This is a comma-separated list of algorithm and/or algorithm:provider +# entries. +# +securerandom.strongAlgorithms=NativePRNGBlocking:SUN,DRBG:SUN + +# +# Sun provider DRBG configuration and default instantiation request. +# +# NIST SP 800-90Ar1 lists several DRBG mechanisms. Each can be configured +# with a DRBG algorithm name, and can be instantiated with a security strength, +# prediction resistance support, etc. This property defines the configuration +# and the default instantiation request of "DRBG" SecureRandom implementations +# in the SUN provider. (Other DRBG implementations can also use this property.) +# Applications can request different instantiation parameters like security +# strength, capability, personalization string using one of the +# getInstance(...,SecureRandomParameters,...) methods with a +# DrbgParameters.Instantiation argument, but other settings such as the +# mechanism and DRBG algorithm names are not currently configurable by any API. +# +# Please note that the SUN implementation of DRBG always supports reseeding. +# +# The value of this property is a comma-separated list of all configurable +# aspects. The aspects can appear in any order but the same aspect can only +# appear at most once. Its BNF-style definition is: +# +# Value: +# aspect { "," aspect } +# +# aspect: +# mech_name | algorithm_name | strength | capability | df +# +# // The DRBG mechanism to use. Default "Hash_DRBG" +# mech_name: +# "Hash_DRBG" | "HMAC_DRBG" | "CTR_DRBG" +# +# // The DRBG algorithm name. The "SHA-***" names are for Hash_DRBG and +# // HMAC_DRBG, default "SHA-256". The "AES-***" names are for CTR_DRBG, +# // default "AES-128" when using the limited cryptographic or "AES-256" +# // when using the unlimited. +# algorithm_name: +# "SHA-224" | "SHA-512/224" | "SHA-256" | +# "SHA-512/256" | "SHA-384" | "SHA-512" | +# "AES-128" | "AES-192" | "AES-256" +# +# // Security strength requested. Default "128" +# strength: +# "112" | "128" | "192" | "256" +# +# // Prediction resistance and reseeding request. Default "none" +# // "pr_and_reseed" - Both prediction resistance and reseeding +# // support requested +# // "reseed_only" - Only reseeding support requested +# // "none" - Neither prediction resistance not reseeding +# // support requested +# pr: +# "pr_and_reseed" | "reseed_only" | "none" +# +# // Whether a derivation function should be used. only applicable +# // to CTR_DRBG. Default "use_df" +# df: +# "use_df" | "no_df" +# +# Examples, +# securerandom.drbg.config=Hash_DRBG,SHA-224,112,none +# securerandom.drbg.config=CTR_DRBG,AES-256,192,pr_and_reseed,use_df +# +# The default value is an empty string, which is equivalent to +# securerandom.drbg.config=Hash_DRBG,SHA-256,128,none +# +securerandom.drbg.config= + +# +# Class to instantiate as the javax.security.auth.login.Configuration +# provider. +# +login.configuration.provider=sun.security.provider.ConfigFile + +# +# Default login configuration file +# +#login.config.url.1=file:${user.home}/.java.login.config + +# +# Class to instantiate as the system Policy. This is the name of the class +# that will be used as the Policy object. The system class loader is used to +# locate this class. +# +policy.provider=sun.security.provider.PolicyFile + +# The default is to have a single system-wide policy file, +# and a policy file in the user's home directory. +# +policy.url.1=file:${java.home}/conf/security/java.policy +policy.url.2=file:${user.home}/.java.policy + +# whether or not we expand properties in the policy file +# if this is set to false, properties (${...}) will not be expanded in policy +# files. +# +policy.expandProperties=true + +# whether or not we allow an extra policy to be passed on the command line +# with -Djava.security.policy=somefile. Comment out this line to disable +# this feature. +# +policy.allowSystemProperty=true + +# whether or not we look into the IdentityScope for trusted Identities +# when encountering a 1.1 signed JAR file. If the identity is found +# and is trusted, we grant it AllPermission. Note: the default policy +# provider (sun.security.provider.PolicyFile) does not support this property. +# +policy.ignoreIdentityScope=false + +# +# Default keystore type. +# +keystore.type=pkcs12 + +# +# Controls compatibility mode for JKS and PKCS12 keystore types. +# +# When set to 'true', both JKS and PKCS12 keystore types support loading +# keystore files in either JKS or PKCS12 format. When set to 'false' the +# JKS keystore type supports loading only JKS keystore files and the PKCS12 +# keystore type supports loading only PKCS12 keystore files. +# +keystore.type.compat=true + +# +# List of comma-separated packages that start with or equal this string +# will cause a security exception to be thrown when passed to the +# SecurityManager::checkPackageAccess method unless the corresponding +# RuntimePermission("accessClassInPackage."+package) has been granted. +# +package.access=sun.misc.,\ + sun.reflect.,\ + org.GNOME.Accessibility. + +# +# List of comma-separated packages that start with or equal this string +# will cause a security exception to be thrown when passed to the +# SecurityManager::checkPackageDefinition method unless the corresponding +# RuntimePermission("defineClassInPackage."+package) has been granted. +# +# By default, none of the class loaders supplied with the JDK call +# checkPackageDefinition. +# +package.definition=sun.misc.,\ + sun.reflect. + +# +# Determines whether this properties file can be appended to +# or overridden on the command line via -Djava.security.properties +# +security.overridePropertiesFile=true + +# +# Determines the default key and trust manager factory algorithms for +# the javax.net.ssl package. +# +ssl.KeyManagerFactory.algorithm=SunX509 +ssl.TrustManagerFactory.algorithm=PKIX + +# +# The Java-level namelookup cache policy for successful lookups: +# +# any negative value: caching forever +# any positive value: the number of seconds to cache an address for +# zero: do not cache +# +# default value is forever (FOREVER). For security reasons, this +# caching is made forever when a security manager is set. When a security +# manager is not set, the default behavior in this implementation +# is to cache for 30 seconds. +# +# NOTE: setting this to anything other than the default value can have +# serious security implications. Do not set it unless +# you are sure you are not exposed to DNS spoofing attack. +# +#networkaddress.cache.ttl=-1 + +# The Java-level namelookup cache policy for failed lookups: +# +# any negative value: cache forever +# any positive value: the number of seconds to cache negative lookup results +# zero: do not cache +# +# In some Microsoft Windows networking environments that employ +# the WINS name service in addition to DNS, name service lookups +# that fail may take a noticeably long time to return (approx. 5 seconds). +# For this reason the default caching policy is to maintain these +# results for 10 seconds. +# +networkaddress.cache.negative.ttl=10 + +# +# Properties to configure OCSP for certificate revocation checking +# + +# Enable OCSP +# +# By default, OCSP is not used for certificate revocation checking. +# This property enables the use of OCSP when set to the value "true". +# +# NOTE: SocketPermission is required to connect to an OCSP responder. +# +# Example, +# ocsp.enable=true + +# +# Location of the OCSP responder +# +# By default, the location of the OCSP responder is determined implicitly +# from the certificate being validated. This property explicitly specifies +# the location of the OCSP responder. The property is used when the +# Authority Information Access extension (defined in RFC 5280) is absent +# from the certificate or when it requires overriding. +# +# Example, +# ocsp.responderURL=http://ocsp.example.net:80 + +# +# Subject name of the OCSP responder's certificate +# +# By default, the certificate of the OCSP responder is that of the issuer +# of the certificate being validated. This property identifies the certificate +# of the OCSP responder when the default does not apply. Its value is a string +# distinguished name (defined in RFC 2253) which identifies a certificate in +# the set of certificates supplied during cert path validation. In cases where +# the subject name alone is not sufficient to uniquely identify the certificate +# then both the "ocsp.responderCertIssuerName" and +# "ocsp.responderCertSerialNumber" properties must be used instead. When this +# property is set then those two properties are ignored. +# +# Example, +# ocsp.responderCertSubjectName=CN=OCSP Responder, O=XYZ Corp + +# +# Issuer name of the OCSP responder's certificate +# +# By default, the certificate of the OCSP responder is that of the issuer +# of the certificate being validated. This property identifies the certificate +# of the OCSP responder when the default does not apply. Its value is a string +# distinguished name (defined in RFC 2253) which identifies a certificate in +# the set of certificates supplied during cert path validation. When this +# property is set then the "ocsp.responderCertSerialNumber" property must also +# be set. When the "ocsp.responderCertSubjectName" property is set then this +# property is ignored. +# +# Example, +# ocsp.responderCertIssuerName=CN=Enterprise CA, O=XYZ Corp + +# +# Serial number of the OCSP responder's certificate +# +# By default, the certificate of the OCSP responder is that of the issuer +# of the certificate being validated. This property identifies the certificate +# of the OCSP responder when the default does not apply. Its value is a string +# of hexadecimal digits (colon or space separators may be present) which +# identifies a certificate in the set of certificates supplied during cert path +# validation. When this property is set then the "ocsp.responderCertIssuerName" +# property must also be set. When the "ocsp.responderCertSubjectName" property +# is set then this property is ignored. +# +# Example, +# ocsp.responderCertSerialNumber=2A:FF:00 + +# +# Policy for failed Kerberos KDC lookups: +# +# When a KDC is unavailable (network error, service failure, etc), it is +# put inside a blacklist and accessed less often for future requests. The +# value (case-insensitive) for this policy can be: +# +# tryLast +# KDCs in the blacklist are always tried after those not on the list. +# +# tryLess[:max_retries,timeout] +# KDCs in the blacklist are still tried by their order in the configuration, +# but with smaller max_retries and timeout values. max_retries and timeout +# are optional numerical parameters (default 1 and 5000, which means once +# and 5 seconds). Please notes that if any of the values defined here is +# more than what is defined in krb5.conf, it will be ignored. +# +# Whenever a KDC is detected as available, it is removed from the blacklist. +# The blacklist is reset when krb5.conf is reloaded. You can add +# refreshKrb5Config=true to a JAAS configuration file so that krb5.conf is +# reloaded whenever a JAAS authentication is attempted. +# +# Example, +# krb5.kdc.bad.policy = tryLast +# krb5.kdc.bad.policy = tryLess:2,2000 +# +krb5.kdc.bad.policy = tryLast + +# +# Kerberos cross-realm referrals (RFC 6806) +# +# OpenJDK's Kerberos client supports cross-realm referrals as defined in +# RFC 6806. This allows to setup more dynamic environments in which clients +# do not need to know in advance how to reach the realm of a target principal +# (either a user or service). +# +# When a client issues an AS or a TGS request, the "canonicalize" option +# is set to announce support of this feature. A KDC server may fulfill the +# request or reply referring the client to a different one. If referred, +# the client will issue a new request and the cycle repeats. +# +# In addition to referrals, the "canonicalize" option allows the KDC server +# to change the client name in response to an AS request. For security reasons, +# RFC 6806 (section 11) FAST scheme is enforced. +# +# Disable Kerberos cross-realm referrals. Value may be overwritten with a +# System property (-Dsun.security.krb5.disableReferrals). +sun.security.krb5.disableReferrals=false + +# Maximum number of AS or TGS referrals to avoid infinite loops. Value may +# be overwritten with a System property (-Dsun.security.krb5.maxReferrals). +sun.security.krb5.maxReferrals=5 + +# +# This property contains a list of disabled EC Named Curves that can be included +# in the jdk.[tls|certpath|jar].disabledAlgorithms properties. To include this +# list in any of the disabledAlgorithms properties, add the property name as +# an entry. +jdk.disabled.namedCurves = secp112r1, secp112r2, secp128r1, secp128r2, \ + secp160k1, secp160r1, secp160r2, secp192k1, secp192r1, secp224k1, \ + secp224r1, secp256k1, sect113r1, sect113r2, sect131r1, sect131r2, \ + sect163k1, sect163r1, sect163r2, sect193r1, sect193r2, sect233k1, \ + sect233r1, sect239k1, sect283k1, sect283r1, sect409k1, sect409r1, \ + sect571k1, sect571r1, X9.62 c2tnb191v1, X9.62 c2tnb191v2, \ + X9.62 c2tnb191v3, X9.62 c2tnb239v1, X9.62 c2tnb239v2, X9.62 c2tnb239v3, \ + X9.62 c2tnb359v1, X9.62 c2tnb431r1, X9.62 prime192v2, X9.62 prime192v3, \ + X9.62 prime239v1, X9.62 prime239v2, X9.62 prime239v3, brainpoolP256r1, \ + brainpoolP320r1, brainpoolP384r1, brainpoolP512r1 + +# +# Algorithm restrictions for certification path (CertPath) processing +# +# In some environments, certain algorithms or key lengths may be undesirable +# for certification path building and validation. For example, "MD2" is +# generally no longer considered to be a secure hash algorithm. This section +# describes the mechanism for disabling algorithms based on algorithm name +# and/or key length. This includes algorithms used in certificates, as well +# as revocation information such as CRLs and signed OCSP Responses. +# The syntax of the disabled algorithm string is described as follows: +# DisabledAlgorithms: +# " DisabledAlgorithm { , DisabledAlgorithm } " +# +# DisabledAlgorithm: +# AlgorithmName [Constraint] { '&' Constraint } | IncludeProperty +# +# AlgorithmName: +# (see below) +# +# Constraint: +# KeySizeConstraint | CAConstraint | DenyAfterConstraint | +# UsageConstraint +# +# KeySizeConstraint: +# keySize Operator KeyLength +# +# Operator: +# <= | < | == | != | >= | > +# +# KeyLength: +# Integer value of the algorithm's key length in bits +# +# CAConstraint: +# jdkCA +# +# DenyAfterConstraint: +# denyAfter YYYY-MM-DD +# +# UsageConstraint: +# usage [TLSServer] [TLSClient] [SignedJAR] +# +# IncludeProperty: +# include +# +# The "AlgorithmName" is the standard algorithm name of the disabled +# algorithm. See the Java Security Standard Algorithm Names Specification +# for information about Standard Algorithm Names. Matching is +# performed using a case-insensitive sub-element matching rule. (For +# example, in "SHA1withECDSA" the sub-elements are "SHA1" for hashing and +# "ECDSA" for signatures.) If the assertion "AlgorithmName" is a +# sub-element of the certificate algorithm name, the algorithm will be +# rejected during certification path building and validation. For example, +# the assertion algorithm name "DSA" will disable all certificate algorithms +# that rely on DSA, such as NONEwithDSA, SHA1withDSA. However, the assertion +# will not disable algorithms related to "ECDSA". +# +# The "IncludeProperty" allows a implementation-defined security property that +# can be included in the disabledAlgorithms properties. These properties are +# to help manage common actions easier across multiple disabledAlgorithm +# properties. +# There is one defined security property: jdk.disabled.NamedCurves +# See the property for more specific details. +# +# +# A "Constraint" defines restrictions on the keys and/or certificates for +# a specified AlgorithmName: +# +# KeySizeConstraint: +# keySize Operator KeyLength +# The constraint requires a key of a valid size range if the +# "AlgorithmName" is of a key algorithm. The "KeyLength" indicates +# the key size specified in number of bits. For example, +# "RSA keySize <= 1024" indicates that any RSA key with key size less +# than or equal to 1024 bits should be disabled, and +# "RSA keySize < 1024, RSA keySize > 2048" indicates that any RSA key +# with key size less than 1024 or greater than 2048 should be disabled. +# This constraint is only used on algorithms that have a key size. +# +# CAConstraint: +# jdkCA +# This constraint prohibits the specified algorithm only if the +# algorithm is used in a certificate chain that terminates at a marked +# trust anchor in the lib/security/cacerts keystore. If the jdkCA +# constraint is not set, then all chains using the specified algorithm +# are restricted. jdkCA may only be used once in a DisabledAlgorithm +# expression. +# Example: To apply this constraint to SHA-1 certificates, include +# the following: "SHA1 jdkCA" +# +# DenyAfterConstraint: +# denyAfter YYYY-MM-DD +# This constraint prohibits a certificate with the specified algorithm +# from being used after the date regardless of the certificate's +# validity. JAR files that are signed and timestamped before the +# constraint date with certificates containing the disabled algorithm +# will not be restricted. The date is processed in the UTC timezone. +# This constraint can only be used once in a DisabledAlgorithm +# expression. +# Example: To deny usage of RSA 2048 bit certificates after Feb 3 2020, +# use the following: "RSA keySize == 2048 & denyAfter 2020-02-03" +# +# UsageConstraint: +# usage [TLSServer] [TLSClient] [SignedJAR] +# This constraint prohibits the specified algorithm for +# a specified usage. This should be used when disabling an algorithm +# for all usages is not practical. 'TLSServer' restricts the algorithm +# in TLS server certificate chains when server authentication is +# performed. 'TLSClient' restricts the algorithm in TLS client +# certificate chains when client authentication is performed. +# 'SignedJAR' constrains use of certificates in signed jar files. +# The usage type follows the keyword and more than one usage type can +# be specified with a whitespace delimiter. +# Example: "SHA1 usage TLSServer TLSClient" +# +# When an algorithm must satisfy more than one constraint, it must be +# delimited by an ampersand '&'. For example, to restrict certificates in a +# chain that terminate at a distribution provided trust anchor and contain +# RSA keys that are less than or equal to 1024 bits, add the following +# constraint: "RSA keySize <= 1024 & jdkCA". +# +# All DisabledAlgorithms expressions are processed in the order defined in the +# property. This requires lower keysize constraints to be specified +# before larger keysize constraints of the same algorithm. For example: +# "RSA keySize < 1024 & jdkCA, RSA keySize < 2048". +# +# Note: The algorithm restrictions do not apply to trust anchors or +# self-signed certificates. +# +# Note: This property is currently used by Oracle's PKIX implementation. It +# is not guaranteed to be examined and used by other implementations. +# +# Example: +# jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048 +# +# +jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & usage TLSServer, \ + RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224, \ + include jdk.disabled.namedCurves + +# +# Legacy algorithms for certification path (CertPath) processing and +# signed JAR files. +# +# In some environments, a certain algorithm or key length may be undesirable +# but is not yet disabled. +# +# Tools such as keytool and jarsigner may emit warnings when these legacy +# algorithms are used. See the man pages for those tools for more information. +# +# The syntax is the same as the "jdk.certpath.disabledAlgorithms" and +# "jdk.jar.disabledAlgorithms" security properties. +# +# Note: This property is currently used by the JDK Reference +# implementation. It is not guaranteed to be examined and used by other +# implementations. + +jdk.security.legacyAlgorithms=SHA1, \ + RSA keySize < 2048, DSA keySize < 2048 + +# +# Algorithm restrictions for signed JAR files +# +# In some environments, certain algorithms or key lengths may be undesirable +# for signed JAR validation. For example, "MD2" is generally no longer +# considered to be a secure hash algorithm. This section describes the +# mechanism for disabling algorithms based on algorithm name and/or key length. +# JARs signed with any of the disabled algorithms or key sizes will be treated +# as unsigned. +# +# The syntax of the disabled algorithm string is described as follows: +# DisabledAlgorithms: +# " DisabledAlgorithm { , DisabledAlgorithm } " +# +# DisabledAlgorithm: +# AlgorithmName [Constraint] { '&' Constraint } +# +# AlgorithmName: +# (see below) +# +# Constraint: +# KeySizeConstraint | DenyAfterConstraint +# +# KeySizeConstraint: +# keySize Operator KeyLength +# +# DenyAfterConstraint: +# denyAfter YYYY-MM-DD +# +# Operator: +# <= | < | == | != | >= | > +# +# KeyLength: +# Integer value of the algorithm's key length in bits +# +# Note: This property is currently used by the JDK Reference +# implementation. It is not guaranteed to be examined and used by other +# implementations. +# +# See "jdk.certpath.disabledAlgorithms" for syntax descriptions. +# +jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \ + DSA keySize < 1024, include jdk.disabled.namedCurves + +# +# Algorithm restrictions for Secure Socket Layer/Transport Layer Security +# (SSL/TLS/DTLS) processing +# +# In some environments, certain algorithms or key lengths may be undesirable +# when using SSL/TLS/DTLS. This section describes the mechanism for disabling +# algorithms during SSL/TLS/DTLS security parameters negotiation, including +# protocol version negotiation, cipher suites selection, named groups +# selection, signature schemes selection, peer authentication and key +# exchange mechanisms. +# +# Disabled algorithms will not be negotiated for SSL/TLS connections, even +# if they are enabled explicitly in an application. +# +# For PKI-based peer authentication and key exchange mechanisms, this list +# of disabled algorithms will also be checked during certification path +# building and validation, including algorithms used in certificates, as +# well as revocation information such as CRLs and signed OCSP Responses. +# This is in addition to the jdk.certpath.disabledAlgorithms property above. +# +# See the specification of "jdk.certpath.disabledAlgorithms" for the +# syntax of the disabled algorithm string. +# +# Note: The algorithm restrictions do not apply to trust anchors or +# self-signed certificates. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +# Example: +# jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048, \ +# rsa_pkcs1_sha1, secp224r1 +jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5withRSA, \ + DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \ + include jdk.disabled.namedCurves + +# +# Legacy algorithms for Secure Socket Layer/Transport Layer Security (SSL/TLS) +# processing in JSSE implementation. +# +# In some environments, a certain algorithm may be undesirable but it +# cannot be disabled because of its use in legacy applications. Legacy +# algorithms may still be supported, but applications should not use them +# as the security strength of legacy algorithms are usually not strong enough +# in practice. +# +# During SSL/TLS security parameters negotiation, legacy algorithms will +# not be negotiated unless there are no other candidates. +# +# The syntax of the legacy algorithms string is described as this Java +# BNF-style: +# LegacyAlgorithms: +# " LegacyAlgorithm { , LegacyAlgorithm } " +# +# LegacyAlgorithm: +# AlgorithmName (standard JSSE algorithm name) +# +# See the specification of security property "jdk.certpath.disabledAlgorithms" +# for the syntax and description of the "AlgorithmName" notation. +# +# Per SSL/TLS specifications, cipher suites have the form: +# SSL_KeyExchangeAlg_WITH_CipherAlg_MacAlg +# or +# TLS_KeyExchangeAlg_WITH_CipherAlg_MacAlg +# +# For example, the cipher suite TLS_RSA_WITH_AES_128_CBC_SHA uses RSA as the +# key exchange algorithm, AES_128_CBC (128 bits AES cipher algorithm in CBC +# mode) as the cipher (encryption) algorithm, and SHA-1 as the message digest +# algorithm for HMAC. +# +# The LegacyAlgorithm can be one of the following standard algorithm names: +# 1. JSSE cipher suite name, e.g., TLS_RSA_WITH_AES_128_CBC_SHA +# 2. JSSE key exchange algorithm name, e.g., RSA +# 3. JSSE cipher (encryption) algorithm name, e.g., AES_128_CBC +# 4. JSSE message digest algorithm name, e.g., SHA +# +# See SSL/TLS specifications and the Java Security Standard Algorithm Names +# Specification for information about the algorithm names. +# +# Note: If a legacy algorithm is also restricted through the +# jdk.tls.disabledAlgorithms property or the +# java.security.AlgorithmConstraints API (See +# javax.net.ssl.SSLParameters.setAlgorithmConstraints()), +# then the algorithm is completely disabled and will not be negotiated. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# There is no guarantee the property will continue to exist or be of the +# same syntax in future releases. +# +# Example: +# jdk.tls.legacyAlgorithms=DH_anon, DES_CBC, SSL_RSA_WITH_RC4_128_MD5 +# +jdk.tls.legacyAlgorithms= \ + K_NULL, C_NULL, M_NULL, \ + DH_anon, ECDH_anon, \ + RC4_128, RC4_40, DES_CBC, DES40_CBC, \ + 3DES_EDE_CBC + +# +# The pre-defined default finite field Diffie-Hellman ephemeral (DHE) +# parameters for Transport Layer Security (SSL/TLS/DTLS) processing. +# +# In traditional SSL/TLS/DTLS connections where finite field DHE parameters +# negotiation mechanism is not used, the server offers the client group +# parameters, base generator g and prime modulus p, for DHE key exchange. +# It is recommended to use dynamic group parameters. This property defines +# a mechanism that allows you to specify custom group parameters. +# +# The syntax of this property string is described as this Java BNF-style: +# DefaultDHEParameters: +# DefinedDHEParameters { , DefinedDHEParameters } +# +# DefinedDHEParameters: +# "{" DHEPrimeModulus , DHEBaseGenerator "}" +# +# DHEPrimeModulus: +# HexadecimalDigits +# +# DHEBaseGenerator: +# HexadecimalDigits +# +# HexadecimalDigits: +# HexadecimalDigit { HexadecimalDigit } +# +# HexadecimalDigit: one of +# 0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f +# +# Whitespace characters are ignored. +# +# The "DefinedDHEParameters" defines the custom group parameters, prime +# modulus p and base generator g, for a particular size of prime modulus p. +# The "DHEPrimeModulus" defines the hexadecimal prime modulus p, and the +# "DHEBaseGenerator" defines the hexadecimal base generator g of a group +# parameter. It is recommended to use safe primes for the custom group +# parameters. +# +# If this property is not defined or the value is empty, the underlying JSSE +# provider's default group parameter is used for each connection. +# +# If the property value does not follow the grammar, or a particular group +# parameter is not valid, the connection will fall back and use the +# underlying JSSE provider's default group parameter. +# +# Note: This property is currently used by OpenJDK's JSSE implementation. It +# is not guaranteed to be examined and used by other implementations. +# +# Example: +# jdk.tls.server.defaultDHEParameters= +# { \ +# FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 \ +# 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD \ +# EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 \ +# E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED \ +# EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381 \ +# FFFFFFFF FFFFFFFF, 2} + +# +# TLS key limits on symmetric cryptographic algorithms +# +# This security property sets limits on algorithms key usage in TLS 1.3. +# When the amount of data encrypted exceeds the algorithm value listed below, +# a KeyUpdate message will trigger a key change. This is for symmetric ciphers +# with TLS 1.3 only. +# +# The syntax for the property is described below: +# KeyLimits: +# " KeyLimit { , KeyLimit } " +# +# WeakKeyLimit: +# AlgorithmName Action Length +# +# AlgorithmName: +# A full algorithm transformation. +# +# Action: +# KeyUpdate +# +# Length: +# The amount of encrypted data in a session before the Action occurs +# This value may be an integer value in bytes, or as a power of two, 2^29. +# +# KeyUpdate: +# The TLS 1.3 KeyUpdate handshake process begins when the Length amount +# is fulfilled. +# +# Note: This property is currently used by OpenJDK's JSSE implementation. It +# is not guaranteed to be examined and used by other implementations. +# +jdk.tls.keyLimits=AES/GCM/NoPadding KeyUpdate 2^37 + +# +# Cryptographic Jurisdiction Policy defaults +# +# Import and export control rules on cryptographic software vary from +# country to country. By default, Java provides two different sets of +# cryptographic policy files[1]: +# +# unlimited: These policy files contain no restrictions on cryptographic +# strengths or algorithms +# +# limited: These policy files contain more restricted cryptographic +# strengths +# +# The default setting is determined by the value of the "crypto.policy" +# Security property below. If your country or usage requires the +# traditional restrictive policy, the "limited" Java cryptographic +# policy is still available and may be appropriate for your environment. +# +# If you have restrictions that do not fit either use case mentioned +# above, Java provides the capability to customize these policy files. +# The "crypto.policy" security property points to a subdirectory +# within /conf/security/policy/ which can be customized. +# Please see the /conf/security/policy/README.txt file or consult +# the Java Security Guide/JCA documentation for more information. +# +# YOU ARE ADVISED TO CONSULT YOUR EXPORT/IMPORT CONTROL COUNSEL OR ATTORNEY +# TO DETERMINE THE EXACT REQUIREMENTS. +# +# [1] Please note that the JCE for Java SE, including the JCE framework, +# cryptographic policy files, and standard JCE providers provided with +# the Java SE, have been reviewed and approved for export as mass market +# encryption item by the US Bureau of Industry and Security. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +crypto.policy=unlimited + +# +# The policy for the XML Signature secure validation mode. The mode is +# enabled by setting the property "org.jcp.xml.dsig.secureValidation" to +# true with the javax.xml.crypto.XMLCryptoContext.setProperty() method, +# or by running the code with a SecurityManager. +# +# Policy: +# Constraint {"," Constraint } +# Constraint: +# AlgConstraint | MaxTransformsConstraint | MaxReferencesConstraint | +# ReferenceUriSchemeConstraint | KeySizeConstraint | OtherConstraint +# AlgConstraint +# "disallowAlg" Uri +# MaxTransformsConstraint: +# "maxTransforms" Integer +# MaxReferencesConstraint: +# "maxReferences" Integer +# ReferenceUriSchemeConstraint: +# "disallowReferenceUriSchemes" String { String } +# KeySizeConstraint: +# "minKeySize" KeyAlg Integer +# OtherConstraint: +# "noDuplicateIds" | "noRetrievalMethodLoops" +# +# For AlgConstraint, Uri is the algorithm URI String that is not allowed. +# See the XML Signature Recommendation for more information on algorithm +# URI Identifiers. For KeySizeConstraint, KeyAlg is the standard algorithm +# name of the key type (ex: "RSA"). If the MaxTransformsConstraint, +# MaxReferencesConstraint or KeySizeConstraint (for the same key type) is +# specified more than once, only the last entry is enforced. +# +# Note: This property is currently used by the JDK Reference implementation. It +# is not guaranteed to be examined and used by other implementations. +# +jdk.xml.dsig.secureValidationPolicy=\ + disallowAlg http://www.w3.org/TR/1999/REC-xslt-19991116,\ + disallowAlg http://www.w3.org/2001/04/xmldsig-more#rsa-md5,\ + disallowAlg http://www.w3.org/2001/04/xmldsig-more#hmac-md5,\ + disallowAlg http://www.w3.org/2001/04/xmldsig-more#md5,\ + maxTransforms 5,\ + maxReferences 30,\ + disallowReferenceUriSchemes file http https,\ + minKeySize RSA 1024,\ + minKeySize DSA 1024,\ + minKeySize EC 224,\ + noDuplicateIds,\ + noRetrievalMethodLoops + +# +# Serialization process-wide filter +# +# A filter, if configured, is used by java.io.ObjectInputStream during +# deserialization to check the contents of the stream. +# A filter is configured as a sequence of patterns, each pattern is either +# matched against the name of a class in the stream or defines a limit. +# Patterns are separated by ";" (semicolon). +# Whitespace is significant and is considered part of the pattern. +# +# If the system property jdk.serialFilter is also specified on the command +# line, it supersedes the security property value defined here. +# +# If a pattern includes a "=", it sets a limit. +# If a limit appears more than once the last value is used. +# Limits are checked before classes regardless of the order in the +# sequence of patterns. +# If any of the limits are exceeded, the filter status is REJECTED. +# +# maxdepth=value - the maximum depth of a graph +# maxrefs=value - the maximum number of internal references +# maxbytes=value - the maximum number of bytes in the input stream +# maxarray=value - the maximum array length allowed +# +# Other patterns, from left to right, match the class or package name as +# returned from Class.getName. +# If the class is an array type, the class or package to be matched is the +# element type. +# Arrays of any number of dimensions are treated the same as the element type. +# For example, a pattern of "!example.Foo", rejects creation of any instance or +# array of example.Foo. +# +# If the pattern starts with "!", the status is REJECTED if the remaining +# pattern is matched; otherwise the status is ALLOWED if the pattern matches. +# If the pattern contains "/", the non-empty prefix up to the "/" is the +# module name; +# if the module name matches the module name of the class then +# the remaining pattern is matched with the class name. +# If there is no "/", the module name is not compared. +# If the pattern ends with ".**" it matches any class in the package and all +# subpackages. +# If the pattern ends with ".*" it matches any class in the package. +# If the pattern ends with "*", it matches any class with the pattern as a +# prefix. +# If the pattern is equal to the class name, it matches. +# Otherwise, the status is UNDECIDED. +# +#jdk.serialFilter=pattern;pattern + +# +# RMI Registry Serial Filter +# +# The filter pattern uses the same format as jdk.serialFilter. +# This filter can override the builtin filter if additional types need to be +# allowed or rejected from the RMI Registry or to decrease limits but not +# to increase limits. +# If the limits (maxdepth, maxrefs, or maxbytes) are exceeded, the object is rejected. +# +# Each non-array type is allowed or rejected if it matches one of the patterns, +# evaluated from left to right, and is otherwise allowed. Arrays of any +# component type, including subarrays and arrays of primitives, are allowed. +# +# Array construction of any component type, including subarrays and arrays of +# primitives, are allowed unless the length is greater than the maxarray limit. +# The filter is applied to each array element. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +# The built-in filter allows subclasses of allowed classes and +# can approximately be represented as the pattern: +# +#sun.rmi.registry.registryFilter=\ +# maxarray=1000000;\ +# maxdepth=20;\ +# java.lang.String;\ +# java.lang.Number;\ +# java.lang.reflect.Proxy;\ +# java.rmi.Remote;\ +# sun.rmi.server.UnicastRef;\ +# sun.rmi.server.RMIClientSocketFactory;\ +# sun.rmi.server.RMIServerSocketFactory;\ +# java.rmi.activation.ActivationID;\ +# java.rmi.server.UID +# +# RMI Distributed Garbage Collector (DGC) Serial Filter +# +# The filter pattern uses the same format as jdk.serialFilter. +# This filter can override the builtin filter if additional types need to be +# allowed or rejected from the RMI DGC. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +# The builtin DGC filter can approximately be represented as the filter pattern: +# +#sun.rmi.transport.dgcFilter=\ +# java.rmi.server.ObjID;\ +# java.rmi.server.UID;\ +# java.rmi.dgc.VMID;\ +# java.rmi.dgc.Lease;\ +# maxdepth=5;maxarray=10000 + +# CORBA ORBIorTypeCheckRegistryFilter +# Type check enhancement for ORB::string_to_object processing +# +# An IOR type check filter, if configured, is used by an ORB during +# an ORB::string_to_object invocation to check the veracity of the type encoded +# in the ior string. +# +# The filter pattern consists of a semi-colon separated list of class names. +# The configured list contains the binary class names of the IDL interface types +# corresponding to the IDL stub class to be instantiated. +# As such, a filter specifies a list of IDL stub classes that will be +# allowed by an ORB when an ORB::string_to_object is invoked. +# It is used to specify a white list configuration of acceptable +# IDL stub types which may be contained in a stringified IOR +# parameter passed as input to an ORB::string_to_object method. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +#com.sun.CORBA.ORBIorTypeCheckRegistryFilter=binary_class_name;binary_class_name + +# The iteration count used for password-based encryption (PBE) in JCEKS +# keystores. Values in the range 10000 to 5000000 are considered valid. +# If the value is out of this range, or is not a number, or is unspecified; +# a default of 200000 is used. +# +# If the system property jdk.jceks.iterationCount is also specified, it +# supersedes the security property value defined here. +# +#jdk.jceks.iterationCount = 200000 + +# +# JCEKS Encrypted Key Serial Filter +# +# This filter, if configured, is used by the JCEKS KeyStore during the +# deserialization of the encrypted Key object stored inside a key entry. +# If not configured or the filter result is UNDECIDED (i.e. none of the patterns +# matches), the filter configured by jdk.serialFilter will be consulted. +# +# If the system property jceks.key.serialFilter is also specified, it supersedes +# the security property value defined here. +# +# The filter pattern uses the same format as jdk.serialFilter. The default +# pattern allows java.lang.Enum, java.security.KeyRep, java.security.KeyRep$Type, +# and javax.crypto.spec.SecretKeySpec and rejects all the others. +jceks.key.serialFilter = java.base/java.lang.Enum;java.base/java.security.KeyRep;\ + java.base/java.security.KeyRep$Type;java.base/javax.crypto.spec.SecretKeySpec;!* + +# +# PKCS12 KeyStore properties +# +# The following properties, if configured, are used by the PKCS12 KeyStore +# implementation during the creation of a new keystore. Several of the +# properties may also be used when modifying an existing keystore. The +# properties can be overridden by a KeyStore API that specifies its own +# algorithms and parameters. +# +# If an existing PKCS12 keystore is loaded and then stored, the algorithm and +# parameter used to generate the existing Mac will be reused. If the existing +# keystore does not have a Mac, no Mac will be created while storing. If there +# is at least one certificate in the existing keystore, the algorithm and +# parameters used to encrypt the last certificate in the existing keystore will +# be reused to encrypt all certificates while storing. If the last certificate +# in the existing keystore is not encrypted, all certificates will be stored +# unencrypted. If there is no certificate in the existing keystore, any newly +# added certificate will be encrypted (or stored unencrypted if algorithm +# value is "NONE") using the "keystore.pkcs12.certProtectionAlgorithm" and +# "keystore.pkcs12.certPbeIterationCount" values defined here. Existing private +# and secret key(s) are not changed. Newly set private and secret key(s) will +# be encrypted using the "keystore.pkcs12.keyProtectionAlgorithm" and +# "keystore.pkcs12.keyPbeIterationCount" values defined here. +# +# In order to apply new algorithms and parameters to all entries in an +# existing keystore, one can create a new keystore and add entries in the +# existing keystore into the new keystore. This can be achieved by calling the +# "keytool -importkeystore" command. +# +# If a system property of the same name is also specified, it supersedes the +# security property value defined here. +# +# If the property is set to an illegal value, +# an iteration count that is not a positive integer, or an unknown algorithm +# name, an exception will be thrown when the property is used. +# If the property is not set or empty, a default value will be used. +# +# Note: These properties are currently used by the JDK Reference implementation. +# They are not guaranteed to be examined and used by other implementations. + +# The algorithm used to encrypt a certificate. This can be any non-Hmac PBE +# algorithm defined in the Cipher section of the Java Security Standard +# Algorithm Names Specification. When set to "NONE", the certificate +# is not encrypted. The default value is "PBEWithHmacSHA256AndAES_256". +#keystore.pkcs12.certProtectionAlgorithm = PBEWithHmacSHA256AndAES_256 + +# The iteration count used by the PBE algorithm when encrypting a certificate. +# This value must be a positive integer. The default value is 10000. +#keystore.pkcs12.certPbeIterationCount = 10000 + +# The algorithm used to encrypt a private key or secret key. This can be +# any non-Hmac PBE algorithm defined in the Cipher section of the Java +# Security Standard Algorithm Names Specification. The value must not be "NONE". +# The default value is "PBEWithHmacSHA256AndAES_256". +#keystore.pkcs12.keyProtectionAlgorithm = PBEWithHmacSHA256AndAES_256 + +# The iteration count used by the PBE algorithm when encrypting a private key +# or a secret key. This value must be a positive integer. The default value +# is 10000. +#keystore.pkcs12.keyPbeIterationCount = 10000 + +# The algorithm used to calculate the optional MacData at the end of a PKCS12 +# file. This can be any HmacPBE algorithm defined in the Mac section of the +# Java Security Standard Algorithm Names Specification. When set to "NONE", +# no Mac is generated. The default value is "HmacPBESHA1". +#keystore.pkcs12.macAlgorithm = HmacPBESHA1 + +# The iteration count used by the MacData algorithm. This value must be a +# positive integer. The default value is 100000. +#keystore.pkcs12.macIterationCount = 100000 + +# +# Enhanced exception message information +# +# By default, exception messages should not include potentially sensitive +# information such as file names, host names, or port numbers. This property +# accepts one or more comma separated values, each of which represents a +# category of enhanced exception message information to enable. Values are +# case-insensitive. Leading and trailing whitespaces, surrounding each value, +# are ignored. Unknown values are ignored. +# +# NOTE: Use caution before setting this property. Setting this property +# exposes sensitive information in Exceptions, which could, for example, +# propagate to untrusted code or be emitted in stack traces that are +# inadvertently disclosed and made accessible over a public network. +# +# The categories are: +# +# hostInfo - IOExceptions thrown by java.net.Socket and the socket types in the +# java.nio.channels package will contain enhanced exception +# message information +# +# The property setting in this file can be overridden by a system property of +# the same name, with the same syntax and possible values. +# +#jdk.includeInExceptions=hostInfo + +# +# Disabled mechanisms for the Simple Authentication and Security Layer (SASL) +# +# Disabled mechanisms will not be negotiated by both SASL clients and servers. +# These mechanisms will be ignored if they are specified in the "mechanisms" +# argument of "Sasl.createSaslClient" or the "mechanism" argument of +# "Sasl.createSaslServer". +# +# The value of this property is a comma-separated list of SASL mechanisms. +# The mechanisms are case-sensitive. Whitespaces around the commas are ignored. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +# Example: +# jdk.sasl.disabledMechanisms=PLAIN, CRAM-MD5, DIGEST-MD5 +jdk.sasl.disabledMechanisms= + +# +# Policies for distrusting Certificate Authorities (CAs). +# +# This is a comma separated value of one or more case-sensitive strings, each +# of which represents a policy for determining if a CA should be distrusted. +# The supported values are: +# +# SYMANTEC_TLS : Distrust TLS Server certificates anchored by a Symantec +# root CA and issued after April 16, 2019 unless issued by one of the +# following subordinate CAs which have a later distrust date: +# 1. Apple IST CA 2 - G1, SHA-256 fingerprint: +# AC2B922ECFD5E01711772FEA8ED372DE9D1E2245FCE3F57A9CDBEC77296A424B +# Distrust after December 31, 2019. +# 2. Apple IST CA 8 - G1, SHA-256 fingerprint: +# A4FE7C7F15155F3F0AEF7AAA83CF6E06DEB97CA3F909DF920AC1490882D488ED +# Distrust after December 31, 2019. +# +# Leading and trailing whitespace surrounding each value are ignored. +# Unknown values are ignored. If the property is commented out or set to the +# empty String, no policies are enforced. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be supported by other SE implementations. Also, this +# property does not override other security properties which can restrict +# certificates such as jdk.tls.disabledAlgorithms or +# jdk.certpath.disabledAlgorithms; those restrictions are still enforced even +# if this property is not enabled. +# +jdk.security.caDistrustPolicies=SYMANTEC_TLS + +# +# FilePermission path canonicalization +# +# This security property dictates how the path argument is processed and stored +# while constructing a FilePermission object. If the value is set to true, the +# path argument is canonicalized and FilePermission methods (such as implies, +# equals, and hashCode) are implemented based on this canonicalized result. +# Otherwise, the path argument is not canonicalized and FilePermission methods are +# implemented based on the original input. See the implementation note of the +# FilePermission class for more details. +# +# If a system property of the same name is also specified, it supersedes the +# security property value defined here. +# +# The default value for this property is false. +# +jdk.io.permissionsUseCanonicalPath=false + + +# +# Policies for the proxy_impersonator Kerberos ccache configuration entry +# +# The proxy_impersonator ccache configuration entry indicates that the ccache +# is a synthetic delegated credential for use with S4U2Proxy by an intermediate +# server. The ccache file should also contain the TGT of this server and +# an evidence ticket from the default principal of the ccache to this server. +# +# This security property determines how Java uses this configuration entry. +# There are 3 possible values: +# +# no-impersonate - Ignore this configuration entry, and always act as +# the owner of the TGT (if it exists). +# +# try-impersonate - Try impersonation when this configuration entry exists. +# If no matching TGT or evidence ticket is found, +# fallback to no-impersonate. +# +# always-impersonate - Always impersonate when this configuration entry exists. +# If no matching TGT or evidence ticket is found, +# no initial credential is read from the ccache. +# +# The default value is "always-impersonate". +# +# If a system property of the same name is also specified, it supersedes the +# security property value defined here. +# +#jdk.security.krb5.default.initiate.credential=always-impersonate + +# +# Trust Anchor Certificates - CA Basic Constraint check +# +# X.509 v3 certificates used as Trust Anchors (to validate signed code or TLS +# connections) must have the cA Basic Constraint field set to 'true'. Also, if +# they include a Key Usage extension, the keyCertSign bit must be set. These +# checks, enabled by default, can be disabled for backward-compatibility +# purposes with the jdk.security.allowNonCaAnchor System and Security +# properties. In the case that both properties are simultaneously set, the +# System value prevails. The default value of the property is "false". +# +#jdk.security.allowNonCaAnchor=true + +# JNDI Object Factories Filter +# +# This filter is used by the JNDI runtime to control the set of object factory classes +# which will be allowed to instantiate objects from object references returned by +# naming/directory systems. The factory class named by the reference instance will be +# matched against this filter. The filter property supports pattern-based filter syntax +# with the same format as jdk.serialFilter. +# +# Each pattern is matched against the factory class name to allow or disallow it's +# instantiation. The access to a factory class is allowed unless the filter returns +# REJECTED. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +# If the system property jdk.jndi.object.factoriesFilter is also specified, it supersedes +# the security property value defined here. The default value of the property is "*". +# +# The default pattern value allows any object factory class specified by the reference +# instance to recreate the referenced object. +#jdk.jndi.object.factoriesFilter=* + +# +# The default Character set name (java.nio.charset.Charset.forName()) +# for converting TLS ALPN values between byte arrays and Strings. +# Prior versions of the JDK may use UTF-8 as the default charset. If +# you experience interoperability issues, setting this property to UTF-8 +# may help. +# +# jdk.tls.alpnCharset=UTF-8 +jdk.tls.alpnCharset=ISO_8859_1 diff --git a/java-11-openjdk/security/nss.cfg b/java-11-openjdk/security/nss.cfg new file mode 100644 index 00000000..3535a400 --- /dev/null +++ b/java-11-openjdk/security/nss.cfg @@ -0,0 +1,4 @@ +name = NSS +nssDbMode = noDb +attributes = compatibility +handleStartupErrors = ignoreMultipleInitialisation diff --git a/java-11-openjdk/security/policy/README.txt b/java-11-openjdk/security/policy/README.txt new file mode 100644 index 00000000..fdf77d3e --- /dev/null +++ b/java-11-openjdk/security/policy/README.txt @@ -0,0 +1,54 @@ + + Java(TM) Cryptography Extension Policy Files + for the Java(TM) Platform, Standard Edition Runtime Environment + + README +------------------------------------------------------------------------ + +Import and export control rules on cryptographic software vary from +country to country. The Java Cryptography Extension (JCE) architecture +allows flexible cryptographic key strength to be configured via the +jurisdiction policy files which are referenced by the "crypto.policy" +security property in the /conf/security/java.security file. + +By default, Java provides two different sets of cryptographic policy +files: + + unlimited: These policy files contain no restrictions on cryptographic + strengths or algorithms + + limited: These policy files contain more restricted cryptographic + strengths + +These files reside in /conf/security/policy in the "unlimited" +or "limited" subdirectories respectively. + +Each subdirectory contains a complete policy configuration, +and subdirectories can be added/edited/removed to reflect your +import or export control product requirements. + +Within a subdirectory, the effective policy is the combined minimum +permissions of the grant statements in the file(s) matching the filename +pattern "default_*.policy". At least one grant is required. For example: + + limited = Export (all) + Import (limited) = Limited + unlimited = Export (all) + Import (all) = Unlimited + +The effective exemption policy is the combined minimum permissions +of the grant statements in the file(s) matching the filename pattern +"exempt_*.policy". Exemption grants are optional. For example: + + limited = grants exemption permissions, by which the + effective policy can be circumvented. + e.g. KeyRecovery/KeyEscrow/KeyWeakening. + +Please see the Java Cryptography Architecture (JCA) documentation for +additional information on these files and formats. + +YOU ARE ADVISED TO CONSULT YOUR EXPORT/IMPORT CONTROL COUNSEL OR ATTORNEY +TO DETERMINE THE EXACT REQUIREMENTS. + +Please note that the JCE for Java SE, including the JCE framework, +cryptographic policy files, and standard JCE providers provided with +the Java SE, have been reviewed and approved for export as mass market +encryption item by the US Bureau of Industry and Security. diff --git a/java-11-openjdk/security/policy/limited/default_US_export.policy b/java-11-openjdk/security/policy/limited/default_US_export.policy new file mode 100644 index 00000000..1f389340 --- /dev/null +++ b/java-11-openjdk/security/policy/limited/default_US_export.policy @@ -0,0 +1,6 @@ +// Default US Export policy file. + +grant { + // There is no restriction to any algorithms. + permission javax.crypto.CryptoAllPermission; +}; diff --git a/java-11-openjdk/security/policy/limited/default_local.policy b/java-11-openjdk/security/policy/limited/default_local.policy new file mode 100644 index 00000000..2a6d5134 --- /dev/null +++ b/java-11-openjdk/security/policy/limited/default_local.policy @@ -0,0 +1,14 @@ +// Some countries have import limits on crypto strength. This policy file +// is worldwide importable. + +grant { + permission javax.crypto.CryptoPermission "DES", 64; + permission javax.crypto.CryptoPermission "DESede", *; + permission javax.crypto.CryptoPermission "RC2", 128, + "javax.crypto.spec.RC2ParameterSpec", 128; + permission javax.crypto.CryptoPermission "RC4", 128; + permission javax.crypto.CryptoPermission "RC5", 128, + "javax.crypto.spec.RC5ParameterSpec", *, 12, *; + permission javax.crypto.CryptoPermission "RSA", *; + permission javax.crypto.CryptoPermission *, 128; +}; diff --git a/java-11-openjdk/security/policy/limited/exempt_local.policy b/java-11-openjdk/security/policy/limited/exempt_local.policy new file mode 100644 index 00000000..9dd5b91b --- /dev/null +++ b/java-11-openjdk/security/policy/limited/exempt_local.policy @@ -0,0 +1,13 @@ +// Some countries have import limits on crypto strength, but may allow for +// these exemptions if the exemption mechanism is used. + +grant { + // There is no restriction to any algorithms if KeyRecovery is enforced. + permission javax.crypto.CryptoPermission *, "KeyRecovery"; + + // There is no restriction to any algorithms if KeyEscrow is enforced. + permission javax.crypto.CryptoPermission *, "KeyEscrow"; + + // There is no restriction to any algorithms if KeyWeakening is enforced. + permission javax.crypto.CryptoPermission *, "KeyWeakening"; +}; diff --git a/java-11-openjdk/security/policy/unlimited/default_US_export.policy b/java-11-openjdk/security/policy/unlimited/default_US_export.policy new file mode 100644 index 00000000..1f389340 --- /dev/null +++ b/java-11-openjdk/security/policy/unlimited/default_US_export.policy @@ -0,0 +1,6 @@ +// Default US Export policy file. + +grant { + // There is no restriction to any algorithms. + permission javax.crypto.CryptoAllPermission; +}; diff --git a/java-11-openjdk/security/policy/unlimited/default_local.policy b/java-11-openjdk/security/policy/unlimited/default_local.policy new file mode 100644 index 00000000..2b907e25 --- /dev/null +++ b/java-11-openjdk/security/policy/unlimited/default_local.policy @@ -0,0 +1,6 @@ +// Country-specific policy file for countries with no limits on crypto strength. + +grant { + // There is no restriction to any algorithms. + permission javax.crypto.CryptoAllPermission; +}; diff --git a/java-11-openjdk/security/public_suffix_list.dat b/java-11-openjdk/security/public_suffix_list.dat new file mode 100644 index 0000000000000000000000000000000000000000..029aa3c58da4345799290f0bba24883f309f9bc9 GIT binary patch literal 232578 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

@mzui*Uz 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�Wqv}GQppx!!n7gwz$ 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 /dev/null +fi + +if ! _check_kernel_dir $inst_kern ; then + echo "dkms: WARNING: $kernel headers are missing, which may explain the above failures." >&2 + echo " please install the $header_pkg package to fix this." >&2 +fi + diff --git a/kernel/postinst.d/apt-auto-removal b/kernel/postinst.d/apt-auto-removal new file mode 100755 index 00000000..2c32b0c9 --- /dev/null +++ b/kernel/postinst.d/apt-auto-removal @@ -0,0 +1,83 @@ +#!/bin/sh +set -e +# Mark as not-for-autoremoval those kernel packages that are: +# - the currently booted version +# - the kernel version we've been called for +# - the latest kernel version (as determined by debian version number) +# - the second-latest kernel version +# +# In the common case this results in two kernels saved (booted into the +# second-latest kernel, we install the latest kernel in an upgrade), but +# can save up to four. Kernel refers here to a distinct release, which can +# potentially be installed in multiple flavours counting as one kernel. + +eval $(apt-config shell APT_CONF_D Dir::Etc::parts/d) +test -n "${APT_CONF_D}" || APT_CONF_D="/etc/apt/apt.conf.d" +config_file="${APT_CONF_D}/01autoremove-kernels" + +eval $(apt-config shell DPKG Dir::bin::dpkg/f) +test -n "$DPKG" || DPKG="/usr/bin/dpkg" + +list="$("${DPKG}" -l | awk '/^[ih][^nc][ ]+(linux|kfreebsd|gnumach)-image-[0-9]+\./ && $2 !~ /-dbg(:.*)?$/ && $2 !~ /-dbgsym(:.*)?$/ { print $2,$3; }' \ + | sed -e 's#^\(linux\|kfreebsd\|gnumach\)-image-##' -e 's#:[^:]\+ # #')" +debverlist="$(echo "$list" | cut -d' ' -f 2 | sort --unique --reverse --version-sort)" + +if [ -n "$1" ]; then + installed_version="$(echo "$list" | awk "\$1 == \"$1\" { print \$2;exit; }")" +fi +unamer="$(uname -r | tr '[A-Z]' '[a-z]')" +if [ -n "$unamer" ]; then + running_version="$(echo "$list" | awk "\$1 == \"$unamer\" { print \$2;exit; }")" +fi +# ignore the currently running version if attempting a reproducible build +if [ -n "${SOURCE_DATE_EPOCH}" ]; then + unamer="" + running_version="" +fi +latest_version="$(echo "$debverlist" | sed -n 1p)" +previous_version="$(echo "$debverlist" | sed -n 2p)" + +debkernels="$(echo "$latest_version +$installed_version +$running_version +$previous_version" | sort -u | sed -e '/^$/ d')" +kernels="$( (echo "$1 +$unamer"; for deb in $debkernels; do echo "$list" | awk "\$2 == \"$deb\" { print \$1; }"; done; ) \ + | sed -e 's#\([\.\+]\)#\\\1#g' -e '/^$/ d' | sort -u)" + +generateconfig() { + cat < "${config_file}.dpkg-new" +mv -f "${config_file}.dpkg-new" "$config_file" +chmod 444 "$config_file" diff --git a/kernel/postinst.d/dkms b/kernel/postinst.d/dkms new file mode 100755 index 00000000..3752beef --- /dev/null +++ b/kernel/postinst.d/dkms @@ -0,0 +1,46 @@ +#!/bin/bash + +# We're passed the version of the kernel being installed +inst_kern=$1 + +uname_s=$(uname -s) + +_get_kernel_dir() { + KVER=$1 + case ${uname_s} in + Linux) DIR="/lib/modules/$KVER/build" ;; + GNU/kFreeBSD) DIR="/usr/src/kfreebsd-headers-$KVER/sys" ;; + esac + echo $DIR +} + +_check_kernel_dir() { + DIR=$(_get_kernel_dir $1) + case ${uname_s} in + Linux) test -e $DIR/include ;; + GNU/kFreeBSD) test -e $DIR/kern && test -e $DIR/conf/kmod.mk ;; + *) return 1 ;; + esac + return $? +} + +case "${uname_s}" in + Linux) + header_pkg="linux-headers-$inst_kern" + kernel="Linux" + ;; + GNU/kFreeBSD) + header_pkg="kfreebsd-headers-$inst_kern" + kernel="kFreeBSD" + ;; +esac + +if [ -x /usr/lib/dkms/dkms_autoinstaller ]; then + exec /usr/lib/dkms/dkms_autoinstaller start $inst_kern > /dev/null +fi + +if ! _check_kernel_dir $inst_kern ; then + echo "dkms: WARNING: $kernel headers are missing, which may explain the above failures." >&2 + echo " please install the $header_pkg package to fix this." >&2 +fi + diff --git a/kernel/postinst.d/initramfs-tools b/kernel/postinst.d/initramfs-tools new file mode 100755 index 00000000..5d02e570 --- /dev/null +++ b/kernel/postinst.d/initramfs-tools @@ -0,0 +1,36 @@ +#!/bin/sh -e + +version="$1" +bootopt="" + +command -v update-initramfs >/dev/null 2>&1 || exit 0 + +# passing the kernel version is required +if [ -z "${version}" ]; then + echo >&2 "W: initramfs-tools: ${DPKG_MAINTSCRIPT_PACKAGE:-kernel package} did not pass a version number" + exit 2 +fi + +# exit if kernel does not need an initramfs +if [ "$INITRD" = 'No' ]; then + exit 0 +fi + +# absolute file name of kernel image may be passed as a second argument; +# create the initrd in the same directory +if [ -n "$2" ]; then + bootdir=$(dirname "$2") + bootopt="-b ${bootdir}" +fi + +# avoid running multiple times +if [ -n "$DEB_MAINT_PARAMS" ]; then + eval set -- "$DEB_MAINT_PARAMS" + if [ -z "$1" ] || [ "$1" != "configure" ]; then + exit 0 + fi +fi + +# we're good - create initramfs. update runs do_bootloader +# shellcheck disable=SC2086 +INITRAMFS_TOOLS_KERNEL_HOOK=1 update-initramfs -c -k "${version}" ${bootopt} >&2 diff --git a/kernel/postrm.d/initramfs-tools b/kernel/postrm.d/initramfs-tools new file mode 100755 index 00000000..471da863 --- /dev/null +++ b/kernel/postrm.d/initramfs-tools @@ -0,0 +1,36 @@ +#!/bin/sh -e + +version="$1" +bootopt="" + +[ -x /usr/sbin/update-initramfs ] || exit 0 + +# passing the kernel version is required +if [ -z "${version}" ]; then + echo >&2 "W: initramfs-tools: ${DPKG_MAINTSCRIPT_PACKAGE:-kernel package} did not pass a version number" + exit 0 +fi + +# exit if custom kernel does not need an initramfs +if [ "$INITRD" = 'No' ]; then + exit 0 +fi + +# absolute file name of kernel image may be passed as a second argument; +# create the initrd in the same directory +if [ -n "$2" ]; then + bootdir=$(dirname "$2") + bootopt="-b ${bootdir}" +fi + +# avoid running multiple times +if [ -n "$DEB_MAINT_PARAMS" ]; then + eval set -- "$DEB_MAINT_PARAMS" + if [ -z "$1" ] || [ "$1" != "remove" ]; then + exit 0 + fi +fi + +# delete initramfs +# shellcheck disable=SC2086 +INITRAMFS_TOOLS_KERNEL_HOOK=1 update-initramfs -d -k "${version}" ${bootopt} >&2 diff --git a/kernel/prerm.d/dkms b/kernel/prerm.d/dkms new file mode 100755 index 00000000..c9a997ee --- /dev/null +++ b/kernel/prerm.d/dkms @@ -0,0 +1,30 @@ +#!/bin/bash + +# We're passed the version of the kernel being removed +inst_kern=$1 + +# This is applied from make_initrd function in dkms command, which +# creates the possible initrd backup file. +remove_initrd_backup() { + for initrd in "initrd-$1.img" "initramfs-$1.img" "initrd.img-$1" "initrd-$1"; do + rm -fv /boot/"${initrd}".old-dkms >&2 + done +} + +if [ -x /usr/sbin/dkms ]; then +while read line; do + name=`echo "$line" | awk '{print $1}' | sed 's/,$//'` + vers=`echo "$line" | awk '{print $2}' | sed 's/,$//'` + arch=`echo "$line" | awk '{print $4}' | sed 's/:$//'` + echo "dkms: removing: $name $vers ($inst_kern) ($arch)" >&2 + dkms uninstall -m $name -v $vers -k $inst_kern -a $arch +done < <(dkms status -k $inst_kern 2>/dev/null | grep ": installed") +fi + +remove_initrd_backup "$inst_kern" + +rmdir --ignore-fail-on-non-empty \ + "/lib/modules/$inst_kern/updates/dkms" \ + "/lib/modules/$inst_kern/updates" 2>/dev/null + +exit 0 diff --git a/ld.so.conf b/ld.so.conf new file mode 100644 index 00000000..20c97630 --- /dev/null +++ b/ld.so.conf @@ -0,0 +1,2 @@ +include /etc/ld.so.conf.d/*.conf + diff --git a/ld.so.conf.d/00-vmcs.conf b/ld.so.conf.d/00-vmcs.conf new file mode 100644 index 00000000..b0a1aeb3 --- /dev/null +++ b/ld.so.conf.d/00-vmcs.conf @@ -0,0 +1 @@ +/opt/vc/lib diff --git a/ld.so.conf.d/arm-linux-gnueabihf.conf b/ld.so.conf.d/arm-linux-gnueabihf.conf new file mode 100644 index 00000000..ffaa59c0 --- /dev/null +++ b/ld.so.conf.d/arm-linux-gnueabihf.conf @@ -0,0 +1,4 @@ +# Multiarch support +/usr/local/lib/arm-linux-gnueabihf +/lib/arm-linux-gnueabihf +/usr/lib/arm-linux-gnueabihf diff --git a/ld.so.conf.d/fakeroot-arm-linux-gnueabihf.conf b/ld.so.conf.d/fakeroot-arm-linux-gnueabihf.conf new file mode 100644 index 00000000..06472aa7 --- /dev/null +++ b/ld.so.conf.d/fakeroot-arm-linux-gnueabihf.conf @@ -0,0 +1 @@ +/usr/lib/arm-linux-gnueabihf/libfakeroot diff --git a/ld.so.conf.d/libc.conf b/ld.so.conf.d/libc.conf new file mode 100644 index 00000000..463b8bb7 --- /dev/null +++ b/ld.so.conf.d/libc.conf @@ -0,0 +1,2 @@ +# libc default configuration +/usr/local/lib diff --git a/ld.so.preload b/ld.so.preload new file mode 100644 index 00000000..64772a77 --- /dev/null +++ b/ld.so.preload @@ -0,0 +1 @@ +/usr/lib/arm-linux-gnueabihf/libarmmem-${PLATFORM}.so diff --git a/ldap/ldap.conf b/ldap/ldap.conf new file mode 100644 index 00000000..42d42b0d --- /dev/null +++ b/ldap/ldap.conf @@ -0,0 +1,17 @@ +# +# LDAP Defaults +# + +# See ldap.conf(5) for details +# This file should be world readable but not world writable. + +#BASE dc=example,dc=com +#URI ldap://ldap.example.com ldap://ldap-master.example.com:666 + +#SIZELIMIT 12 +#TIMELIMIT 15 +#DEREF never + +# TLS certificates (needed for GnuTLS) +TLS_CACERT /etc/ssl/certs/ca-certificates.crt + diff --git a/letsencrypt/account.conf b/letsencrypt/account.conf new file mode 100644 index 00000000..c4929794 --- /dev/null +++ b/letsencrypt/account.conf @@ -0,0 +1,10 @@ + + +#LOG_FILE="/etc/letsencrypt/acme.sh.log" +#LOG_LEVEL=1 + +#AUTO_UPGRADE="1" + +#NO_TIMESTAMP=1 + + diff --git a/letsencrypt/acme.sh b/letsencrypt/acme.sh new file mode 100755 index 00000000..5a9a350d --- /dev/null +++ b/letsencrypt/acme.sh @@ -0,0 +1,7468 @@ +#!/bin/bash + +VER=2.8.8 + +PROJECT_NAME="acme.sh" + +PROJECT_ENTRY="acme.sh" + +PROJECT="https://github.com/acmesh-official/$PROJECT_NAME" + +DEFAULT_INSTALL_HOME="$HOME/.$PROJECT_NAME" + +_WINDOWS_SCHEDULER_NAME="$PROJECT_NAME.cron" + +_SCRIPT_="$0" + +_SUB_FOLDER_NOTIFY="notify" +_SUB_FOLDER_DNSAPI="dnsapi" +_SUB_FOLDER_DEPLOY="deploy" + +_SUB_FOLDERS="$_SUB_FOLDER_DNSAPI $_SUB_FOLDER_DEPLOY $_SUB_FOLDER_NOTIFY" + +LETSENCRYPT_CA_V1="https://acme-v01.api.letsencrypt.org/directory" +LETSENCRYPT_STAGING_CA_V1="https://acme-staging.api.letsencrypt.org/directory" + +CA_LETSENCRYPT_V2="https://acme-v02.api.letsencrypt.org/directory" +CA_LETSENCRYPT_V2_TEST="https://acme-staging-v02.api.letsencrypt.org/directory" + +CA_BUYPASS="https://api.buypass.com/acme/directory" +CA_BUYPASS_TEST="https://api.test4.buypass.no/acme/directory" + +CA_ZEROSSL="https://acme.zerossl.com/v2/DV90" +_ZERO_EAB_ENDPOINT="http://api.zerossl.com/acme/eab-credentials-email" + +DEFAULT_CA=$CA_LETSENCRYPT_V2 +DEFAULT_STAGING_CA=$CA_LETSENCRYPT_V2_TEST + +CA_NAMES=" +LetsEncrypt.org,letsencrypt +LetsEncrypt.org_test,letsencrypt_test,letsencrypttest +BuyPass.com,buypass +BuyPass.com_test,buypass_test,buypasstest +ZeroSSL.com,zerossl +" + +CA_SERVERS="$CA_LETSENCRYPT_V2,$CA_LETSENCRYPT_V2_TEST,$CA_BUYPASS,$CA_BUYPASS_TEST,$CA_ZEROSSL" + +DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" + +DEFAULT_ACCOUNT_KEY_LENGTH=2048 +DEFAULT_DOMAIN_KEY_LENGTH=2048 + +DEFAULT_OPENSSL_BIN="openssl" + +VTYPE_HTTP="http-01" +VTYPE_DNS="dns-01" +VTYPE_ALPN="tls-alpn-01" + +LOCAL_ANY_ADDRESS="0.0.0.0" + +DEFAULT_RENEW=60 + +NO_VALUE="no" + +W_DNS="dns" +W_ALPN="alpn" +DNS_ALIAS_PREFIX="=" + +MODE_STATELESS="stateless" + +STATE_VERIFIED="verified_ok" + +NGINX="nginx:" +NGINX_START="#ACME_NGINX_START" +NGINX_END="#ACME_NGINX_END" + +BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----" +END_CSR="-----END CERTIFICATE REQUEST-----" + +BEGIN_CERT="-----BEGIN CERTIFICATE-----" +END_CERT="-----END CERTIFICATE-----" + +CONTENT_TYPE_JSON="application/jose+json" +RENEW_SKIP=2 + +B64CONF_START="__ACME_BASE64__START_" +B64CONF_END="__ACME_BASE64__END_" + +ECC_SEP="_" +ECC_SUFFIX="${ECC_SEP}ecc" + +LOG_LEVEL_1=1 +LOG_LEVEL_2=2 +LOG_LEVEL_3=3 +DEFAULT_LOG_LEVEL="$LOG_LEVEL_1" + +DEBUG_LEVEL_1=1 +DEBUG_LEVEL_2=2 +DEBUG_LEVEL_3=3 +DEBUG_LEVEL_DEFAULT=$DEBUG_LEVEL_1 +DEBUG_LEVEL_NONE=0 + +DOH_CLOUDFLARE=1 +DOH_GOOGLE=2 + +HIDDEN_VALUE="[hidden](please add '--output-insecure' to see this value)" + +SYSLOG_ERROR="user.error" +SYSLOG_INFO="user.info" +SYSLOG_DEBUG="user.debug" + +#error +SYSLOG_LEVEL_ERROR=3 +#info +SYSLOG_LEVEL_INFO=6 +#debug +SYSLOG_LEVEL_DEBUG=7 +#debug2 +SYSLOG_LEVEL_DEBUG_2=8 +#debug3 +SYSLOG_LEVEL_DEBUG_3=9 + +SYSLOG_LEVEL_DEFAULT=$SYSLOG_LEVEL_ERROR +#none +SYSLOG_LEVEL_NONE=0 + +NOTIFY_LEVEL_DISABLE=0 +NOTIFY_LEVEL_ERROR=1 +NOTIFY_LEVEL_RENEW=2 +NOTIFY_LEVEL_SKIP=3 + +NOTIFY_LEVEL_DEFAULT=$NOTIFY_LEVEL_RENEW + +NOTIFY_MODE_BULK=0 +NOTIFY_MODE_CERT=1 + +NOTIFY_MODE_DEFAULT=$NOTIFY_MODE_BULK + +_DEBUG_WIKI="https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh" + +_PREPARE_LINK="https://github.com/acmesh-official/acme.sh/wiki/Install-preparations" + +_STATELESS_WIKI="https://github.com/acmesh-official/acme.sh/wiki/Stateless-Mode" + +_DNS_ALIAS_WIKI="https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mode" + +_DNS_MANUAL_WIKI="https://github.com/acmesh-official/acme.sh/wiki/dns-manual-mode" + +_DNS_API_WIKI="https://github.com/acmesh-official/acme.sh/wiki/dnsapi" + +_NOTIFY_WIKI="https://github.com/acmesh-official/acme.sh/wiki/notify" + +_SUDO_WIKI="https://github.com/acmesh-official/acme.sh/wiki/sudo" + +_REVOKE_WIKI="https://github.com/acmesh-official/acme.sh/wiki/revokecert" + +_ZEROSSL_WIKI="https://github.com/acmesh-official/acme.sh/wiki/ZeroSSL.com-CA" + +_SERVER_WIKI="https://github.com/acmesh-official/acme.sh/wiki/Server" + +_PREFERRED_CHAIN_WIKI="https://github.com/acmesh-official/acme.sh/wiki/Preferred-Chain" + +_DNS_MANUAL_ERR="The dns manual mode can not renew automatically, you must issue it again manually. You'd better use the other modes instead." + +_DNS_MANUAL_WARN="It seems that you are using dns manual mode. please take care: $_DNS_MANUAL_ERR" + +_DNS_MANUAL_ERROR="It seems that you are using dns manual mode. Read this link first: $_DNS_MANUAL_WIKI" + +__INTERACTIVE="" +if [ -t 1 ]; then + __INTERACTIVE="1" +fi + +__green() { + if [ "${__INTERACTIVE}${ACME_NO_COLOR:-0}" = "10" -o "${ACME_FORCE_COLOR}" = "1" ]; then + printf '\33[1;32m%b\33[0m' "$1" + return + fi + printf -- "%b" "$1" +} + +__red() { + if [ "${__INTERACTIVE}${ACME_NO_COLOR:-0}" = "10" -o "${ACME_FORCE_COLOR}" = "1" ]; then + printf '\33[1;31m%b\33[0m' "$1" + return + fi + printf -- "%b" "$1" +} + +_printargs() { + _exitstatus="$?" + if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then + printf -- "%s" "[$(date)] " + fi + if [ -z "$2" ]; then + printf -- "%s" "$1" + else + printf -- "%s" "$1='$2'" + fi + printf "\n" + # return the saved exit status + return "$_exitstatus" +} + +_dlg_versions() { + echo "Diagnosis versions: " + echo "openssl:$ACME_OPENSSL_BIN" + if _exists "${ACME_OPENSSL_BIN:-openssl}"; then + ${ACME_OPENSSL_BIN:-openssl} version 2>&1 + else + echo "$ACME_OPENSSL_BIN doesn't exist." + fi + + echo "apache:" + if [ "$_APACHECTL" ] && _exists "$_APACHECTL"; then + $_APACHECTL -V 2>&1 + else + echo "apache doesn't exist." + fi + + echo "nginx:" + if _exists "nginx"; then + nginx -V 2>&1 + else + echo "nginx doesn't exist." + fi + + echo "socat:" + if _exists "socat"; then + socat -V 2>&1 + else + _debug "socat doesn't exist." + fi +} + +#class +_syslog() { + _exitstatus="$?" + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" = "$SYSLOG_LEVEL_NONE" ]; then + return + fi + _logclass="$1" + shift + if [ -z "$__logger_i" ]; then + if _contains "$(logger --help 2>&1)" "-i"; then + __logger_i="logger -i" + else + __logger_i="logger" + fi + fi + $__logger_i -t "$PROJECT_NAME" -p "$_logclass" "$(_printargs "$@")" >/dev/null 2>&1 + return "$_exitstatus" +} + +_log() { + [ -z "$LOG_FILE" ] && return + _printargs "$@" >>"$LOG_FILE" +} + +_info() { + _log "$@" + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_INFO" ]; then + _syslog "$SYSLOG_INFO" "$@" + fi + _printargs "$@" +} + +_err() { + _syslog "$SYSLOG_ERROR" "$@" + _log "$@" + if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then + printf -- "%s" "[$(date)] " >&2 + fi + if [ -z "$2" ]; then + __red "$1" >&2 + else + __red "$1='$2'" >&2 + fi + printf "\n" >&2 + return 1 +} + +_usage() { + __red "$@" >&2 + printf "\n" >&2 +} + +__debug_bash_helper() { + # At this point only do for --debug 3 + if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -lt "$DEBUG_LEVEL_3" ]; then + return + fi + # Return extra debug info when running with bash, otherwise return empty + # string. + if [ -z "${BASH_VERSION}" ]; then + return + fi + # We are a bash shell at this point, return the filename, function name, and + # line number as a string + _dbh_saveIFS=$IFS + IFS=" " + # Must use eval or syntax error happens under dash. The eval should use + # single quotes as older versions of busybox had a bug with double quotes and + # eval. + # Use 'caller 1' as we want one level up the stack as we should be called + # by one of the _debug* functions + eval '_dbh_called=($(caller 1))' + IFS=$_dbh_saveIFS + eval '_dbh_file=${_dbh_called[2]}' + if [ -n "${_script_home}" ]; then + # Trim off the _script_home directory name + eval '_dbh_file=${_dbh_file#$_script_home/}' + fi + eval '_dbh_function=${_dbh_called[1]}' + eval '_dbh_lineno=${_dbh_called[0]}' + printf "%-40s " "$_dbh_file:${_dbh_function}:${_dbh_lineno}" +} + +_debug() { + if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_1" ]; then + _log "$@" + fi + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG" ]; then + _syslog "$SYSLOG_DEBUG" "$@" + fi + if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_1" ]; then + _bash_debug=$(__debug_bash_helper) + _printargs "${_bash_debug}$@" >&2 + fi +} + +#output the sensitive messages +_secure_debug() { + if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_1" ]; then + if [ "$OUTPUT_INSECURE" = "1" ]; then + _log "$@" + else + _log "$1" "$HIDDEN_VALUE" + fi + fi + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG" ]; then + _syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE" + fi + if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_1" ]; then + if [ "$OUTPUT_INSECURE" = "1" ]; then + _printargs "$@" >&2 + else + _printargs "$1" "$HIDDEN_VALUE" >&2 + fi + fi +} + +_debug2() { + if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then + _log "$@" + fi + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_2" ]; then + _syslog "$SYSLOG_DEBUG" "$@" + fi + if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_2" ]; then + _bash_debug=$(__debug_bash_helper) + _printargs "${_bash_debug}$@" >&2 + fi +} + +_secure_debug2() { + if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then + if [ "$OUTPUT_INSECURE" = "1" ]; then + _log "$@" + else + _log "$1" "$HIDDEN_VALUE" + fi + fi + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_2" ]; then + _syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE" + fi + if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_2" ]; then + if [ "$OUTPUT_INSECURE" = "1" ]; then + _printargs "$@" >&2 + else + _printargs "$1" "$HIDDEN_VALUE" >&2 + fi + fi +} + +_debug3() { + if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then + _log "$@" + fi + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_3" ]; then + _syslog "$SYSLOG_DEBUG" "$@" + fi + if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_3" ]; then + _bash_debug=$(__debug_bash_helper) + _printargs "${_bash_debug}$@" >&2 + fi +} + +_secure_debug3() { + if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then + if [ "$OUTPUT_INSECURE" = "1" ]; then + _log "$@" + else + _log "$1" "$HIDDEN_VALUE" + fi + fi + if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_3" ]; then + _syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE" + fi + if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_3" ]; then + if [ "$OUTPUT_INSECURE" = "1" ]; then + _printargs "$@" >&2 + else + _printargs "$1" "$HIDDEN_VALUE" >&2 + fi + fi +} + +_upper_case() { + # shellcheck disable=SC2018,SC2019 + tr 'a-z' 'A-Z' +} + +_lower_case() { + # shellcheck disable=SC2018,SC2019 + tr 'A-Z' 'a-z' +} + +_startswith() { + _str="$1" + _sub="$2" + echo "$_str" | grep "^$_sub" >/dev/null 2>&1 +} + +_endswith() { + _str="$1" + _sub="$2" + echo "$_str" | grep -- "$_sub\$" >/dev/null 2>&1 +} + +_contains() { + _str="$1" + _sub="$2" + echo "$_str" | grep -- "$_sub" >/dev/null 2>&1 +} + +_hasfield() { + _str="$1" + _field="$2" + _sep="$3" + if [ -z "$_field" ]; then + _usage "Usage: str field [sep]" + return 1 + fi + + if [ -z "$_sep" ]; then + _sep="," + fi + + for f in $(echo "$_str" | tr "$_sep" ' '); do + if [ "$f" = "$_field" ]; then + _debug2 "'$_str' contains '$_field'" + return 0 #contains ok + fi + done + _debug2 "'$_str' does not contain '$_field'" + return 1 #not contains +} + +# str index [sep] +_getfield() { + _str="$1" + _findex="$2" + _sep="$3" + + if [ -z "$_findex" ]; then + _usage "Usage: str field [sep]" + return 1 + fi + + if [ -z "$_sep" ]; then + _sep="," + fi + + _ffi="$_findex" + while [ "$_ffi" -gt "0" ]; do + _fv="$(echo "$_str" | cut -d "$_sep" -f "$_ffi")" + if [ "$_fv" ]; then + printf -- "%s" "$_fv" + return 0 + fi + _ffi="$(_math "$_ffi" - 1)" + done + + printf -- "%s" "$_str" + +} + +_exists() { + cmd="$1" + if [ -z "$cmd" ]; then + _usage "Usage: _exists cmd" + return 1 + fi + + if eval type type >/dev/null 2>&1; then + eval type "$cmd" >/dev/null 2>&1 + elif command >/dev/null 2>&1; then + command -v "$cmd" >/dev/null 2>&1 + else + which "$cmd" >/dev/null 2>&1 + fi + ret="$?" + _debug3 "$cmd exists=$ret" + return $ret +} + +#a + b +_math() { + _m_opts="$@" + printf "%s" "$(($_m_opts))" +} + +_h_char_2_dec() { + _ch=$1 + case "${_ch}" in + a | A) + printf "10" + ;; + b | B) + printf "11" + ;; + c | C) + printf "12" + ;; + d | D) + printf "13" + ;; + e | E) + printf "14" + ;; + f | F) + printf "15" + ;; + *) + printf "%s" "$_ch" + ;; + esac + +} + +_URGLY_PRINTF="" +if [ "$(printf '\x41')" != 'A' ]; then + _URGLY_PRINTF=1 +fi + +_ESCAPE_XARGS="" +if _exists xargs && [ "$(printf %s '\\x41' | xargs printf)" = 'A' ]; then + _ESCAPE_XARGS=1 +fi + +_h2b() { + if _exists xxd && xxd -r -p 2>/dev/null; then + return + fi + + hex=$(cat) + ic="" + jc="" + _debug2 _URGLY_PRINTF "$_URGLY_PRINTF" + if [ -z "$_URGLY_PRINTF" ]; then + if [ "$_ESCAPE_XARGS" ] && _exists xargs; then + _debug2 "xargs" + echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/g' | xargs printf + else + for h in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/ \1/g'); do + if [ -z "$h" ]; then + break + fi + printf "\x$h%s" + done + fi + else + for c in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\)/ \1/g'); do + if [ -z "$ic" ]; then + ic=$c + continue + fi + jc=$c + ic="$(_h_char_2_dec "$ic")" + jc="$(_h_char_2_dec "$jc")" + printf '\'"$(printf "%o" "$(_math "$ic" \* 16 + $jc)")""%s" + ic="" + jc="" + done + fi + +} + +_is_solaris() { + _contains "${__OS__:=$(uname -a)}" "solaris" || _contains "${__OS__:=$(uname -a)}" "SunOS" +} + +#_ascii_hex str +#this can only process ascii chars, should only be used when od command is missing as a backup way. +_ascii_hex() { + _debug2 "Using _ascii_hex" + _str="$1" + _str_len=${#_str} + _h_i=1 + while [ "$_h_i" -le "$_str_len" ]; do + _str_c="$(printf "%s" "$_str" | cut -c "$_h_i")" + printf " %02x" "'$_str_c" + _h_i="$(_math "$_h_i" + 1)" + done +} + +#stdin output hexstr splited by one space +#input:"abc" +#output: " 61 62 63" +_hex_dump() { + if _exists od; then + od -A n -v -t x1 | tr -s " " | sed 's/ $//' | tr -d "\r\t\n" + elif _exists hexdump; then + _debug3 "using hexdump" + hexdump -v -e '/1 ""' -e '/1 " %02x" ""' + elif _exists xxd; then + _debug3 "using xxd" + xxd -ps -c 20 -i | sed "s/ 0x/ /g" | tr -d ",\n" | tr -s " " + else + _debug3 "using _ascii_hex" + str=$(cat) + _ascii_hex "$str" + fi +} + +#url encode, no-preserved chars +#A B C D E F G H I J K L M N O P Q R S T U V W X Y Z +#41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a + +#a b c d e f g h i j k l m n o p q r s t u v w x y z +#61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a + +#0 1 2 3 4 5 6 7 8 9 - _ . ~ +#30 31 32 33 34 35 36 37 38 39 2d 5f 2e 7e + +#stdin stdout +_url_encode() { + _hex_str=$(_hex_dump) + _debug3 "_url_encode" + _debug3 "_hex_str" "$_hex_str" + for _hex_code in $_hex_str; do + #upper case + case "${_hex_code}" in + "41") + printf "%s" "A" + ;; + "42") + printf "%s" "B" + ;; + "43") + printf "%s" "C" + ;; + "44") + printf "%s" "D" + ;; + "45") + printf "%s" "E" + ;; + "46") + printf "%s" "F" + ;; + "47") + printf "%s" "G" + ;; + "48") + printf "%s" "H" + ;; + "49") + printf "%s" "I" + ;; + "4a") + printf "%s" "J" + ;; + "4b") + printf "%s" "K" + ;; + "4c") + printf "%s" "L" + ;; + "4d") + printf "%s" "M" + ;; + "4e") + printf "%s" "N" + ;; + "4f") + printf "%s" "O" + ;; + "50") + printf "%s" "P" + ;; + "51") + printf "%s" "Q" + ;; + "52") + printf "%s" "R" + ;; + "53") + printf "%s" "S" + ;; + "54") + printf "%s" "T" + ;; + "55") + printf "%s" "U" + ;; + "56") + printf "%s" "V" + ;; + "57") + printf "%s" "W" + ;; + "58") + printf "%s" "X" + ;; + "59") + printf "%s" "Y" + ;; + "5a") + printf "%s" "Z" + ;; + + #lower case + "61") + printf "%s" "a" + ;; + "62") + printf "%s" "b" + ;; + "63") + printf "%s" "c" + ;; + "64") + printf "%s" "d" + ;; + "65") + printf "%s" "e" + ;; + "66") + printf "%s" "f" + ;; + "67") + printf "%s" "g" + ;; + "68") + printf "%s" "h" + ;; + "69") + printf "%s" "i" + ;; + "6a") + printf "%s" "j" + ;; + "6b") + printf "%s" "k" + ;; + "6c") + printf "%s" "l" + ;; + "6d") + printf "%s" "m" + ;; + "6e") + printf "%s" "n" + ;; + "6f") + printf "%s" "o" + ;; + "70") + printf "%s" "p" + ;; + "71") + printf "%s" "q" + ;; + "72") + printf "%s" "r" + ;; + "73") + printf "%s" "s" + ;; + "74") + printf "%s" "t" + ;; + "75") + printf "%s" "u" + ;; + "76") + printf "%s" "v" + ;; + "77") + printf "%s" "w" + ;; + "78") + printf "%s" "x" + ;; + "79") + printf "%s" "y" + ;; + "7a") + printf "%s" "z" + ;; + #numbers + "30") + printf "%s" "0" + ;; + "31") + printf "%s" "1" + ;; + "32") + printf "%s" "2" + ;; + "33") + printf "%s" "3" + ;; + "34") + printf "%s" "4" + ;; + "35") + printf "%s" "5" + ;; + "36") + printf "%s" "6" + ;; + "37") + printf "%s" "7" + ;; + "38") + printf "%s" "8" + ;; + "39") + printf "%s" "9" + ;; + "2d") + printf "%s" "-" + ;; + "5f") + printf "%s" "_" + ;; + "2e") + printf "%s" "." + ;; + "7e") + printf "%s" "~" + ;; + #other hex + *) + printf '%%%s' "$_hex_code" + ;; + esac + done +} + +_json_encode() { + _j_str="$(sed 's/"/\\"/g' | sed "s/\r/\\r/g")" + _debug3 "_json_encode" + _debug3 "_j_str" "$_j_str" + echo "$_j_str" | _hex_dump | _lower_case | sed 's/0a/5c 6e/g' | tr -d ' ' | _h2b | tr -d "\r\n" +} + +#from: http:\/\/ to http:// +_json_decode() { + _j_str="$(sed 's#\\/#/#g')" + _debug3 "_json_decode" + _debug3 "_j_str" "$_j_str" + echo "$_j_str" +} + +#options file +_sed_i() { + options="$1" + filename="$2" + if [ -z "$filename" ]; then + _usage "Usage:_sed_i options filename" + return 1 + fi + _debug2 options "$options" + if sed -h 2>&1 | grep "\-i\[SUFFIX]" >/dev/null 2>&1; then + _debug "Using sed -i" + sed -i "$options" "$filename" + else + _debug "No -i support in sed" + text="$(cat "$filename")" + echo "$text" | sed "$options" >"$filename" + fi +} + +_egrep_o() { + if ! egrep -o "$1" 2>/dev/null; then + sed -n 's/.*\('"$1"'\).*/\1/p' + fi +} + +#Usage: file startline endline +_getfile() { + filename="$1" + startline="$2" + endline="$3" + if [ -z "$endline" ]; then + _usage "Usage: file startline endline" + return 1 + fi + + i="$(grep -n -- "$startline" "$filename" | cut -d : -f 1)" + if [ -z "$i" ]; then + _err "Can not find start line: $startline" + return 1 + fi + i="$(_math "$i" + 1)" + _debug i "$i" + + j="$(grep -n -- "$endline" "$filename" | cut -d : -f 1)" + if [ -z "$j" ]; then + _err "Can not find end line: $endline" + return 1 + fi + j="$(_math "$j" - 1)" + _debug j "$j" + + sed -n "$i,${j}p" "$filename" + +} + +#Usage: multiline +_base64() { + [ "" ] #urgly + if [ "$1" ]; then + _debug3 "base64 multiline:'$1'" + ${ACME_OPENSSL_BIN:-openssl} base64 -e + else + _debug3 "base64 single line." + ${ACME_OPENSSL_BIN:-openssl} base64 -e | tr -d '\r\n' + fi +} + +#Usage: multiline +_dbase64() { + if [ "$1" ]; then + ${ACME_OPENSSL_BIN:-openssl} base64 -d -A + else + ${ACME_OPENSSL_BIN:-openssl} base64 -d + fi +} + +#file +_checkcert() { + _cf="$1" + if [ "$DEBUG" ]; then + ${ACME_OPENSSL_BIN:-openssl} x509 -noout -text -in "$_cf" + else + ${ACME_OPENSSL_BIN:-openssl} x509 -noout -text -in "$_cf" >/dev/null 2>&1 + fi +} + +#Usage: hashalg [outputhex] +#Output Base64-encoded digest +_digest() { + alg="$1" + if [ -z "$alg" ]; then + _usage "Usage: _digest hashalg" + return 1 + fi + + outputhex="$2" + + if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then + if [ "$outputhex" ]; then + ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' ' + else + ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -binary | _base64 + fi + else + _err "$alg is not supported yet" + return 1 + fi + +} + +#Usage: hashalg secret_hex [outputhex] +#Output binary hmac +_hmac() { + alg="$1" + secret_hex="$2" + outputhex="$3" + + if [ -z "$secret_hex" ]; then + _usage "Usage: _hmac hashalg secret [outputhex]" + return 1 + fi + + if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then + if [ "$outputhex" ]; then + (${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" 2>/dev/null || ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)") | cut -d = -f 2 | tr -d ' ' + else + ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary 2>/dev/null || ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)" -binary + fi + else + _err "$alg is not supported yet" + return 1 + fi + +} + +#Usage: keyfile hashalg +#Output: Base64-encoded signature value +_sign() { + keyfile="$1" + alg="$2" + if [ -z "$alg" ]; then + _usage "Usage: _sign keyfile hashalg" + return 1 + fi + + _sign_openssl="${ACME_OPENSSL_BIN:-openssl} dgst -sign $keyfile " + + if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1 || grep "BEGIN PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then + $_sign_openssl -$alg | _base64 + elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then + if ! _signedECText="$($_sign_openssl -sha$__ECC_KEY_LEN | ${ACME_OPENSSL_BIN:-openssl} asn1parse -inform DER)"; then + _err "Sign failed: $_sign_openssl" + _err "Key file: $keyfile" + _err "Key content:$(wc -l <"$keyfile") lines" + return 1 + fi + _debug3 "_signedECText" "$_signedECText" + _ec_r="$(echo "$_signedECText" | _head_n 2 | _tail_n 1 | cut -d : -f 4 | tr -d "\r\n")" + _ec_s="$(echo "$_signedECText" | _head_n 3 | _tail_n 1 | cut -d : -f 4 | tr -d "\r\n")" + if [ "$__ECC_KEY_LEN" -eq "256" ]; then + while [ "${#_ec_r}" -lt "64" ]; do + _ec_r="0${_ec_r}" + done + while [ "${#_ec_s}" -lt "64" ]; do + _ec_s="0${_ec_s}" + done + fi + if [ "$__ECC_KEY_LEN" -eq "384" ]; then + while [ "${#_ec_r}" -lt "96" ]; do + _ec_r="0${_ec_r}" + done + while [ "${#_ec_s}" -lt "96" ]; do + _ec_s="0${_ec_s}" + done + fi + if [ "$__ECC_KEY_LEN" -eq "512" ]; then + while [ "${#_ec_r}" -lt "132" ]; do + _ec_r="0${_ec_r}" + done + while [ "${#_ec_s}" -lt "132" ]; do + _ec_s="0${_ec_s}" + done + fi + _debug3 "_ec_r" "$_ec_r" + _debug3 "_ec_s" "$_ec_s" + printf "%s" "$_ec_r$_ec_s" | _h2b | _base64 + else + _err "Unknown key file format." + return 1 + fi + +} + +#keylength or isEcc flag (empty str => not ecc) +_isEccKey() { + _length="$1" + + if [ -z "$_length" ]; then + return 1 + fi + + [ "$_length" != "1024" ] && + [ "$_length" != "2048" ] && + [ "$_length" != "3072" ] && + [ "$_length" != "4096" ] && + [ "$_length" != "8192" ] +} + +# _createkey 2048|ec-256 file +_createkey() { + length="$1" + f="$2" + _debug2 "_createkey for file:$f" + eccname="$length" + if _startswith "$length" "ec-"; then + length=$(printf "%s" "$length" | cut -d '-' -f 2-100) + + if [ "$length" = "256" ]; then + eccname="prime256v1" + fi + if [ "$length" = "384" ]; then + eccname="secp384r1" + fi + if [ "$length" = "521" ]; then + eccname="secp521r1" + fi + + fi + + if [ -z "$length" ]; then + length=2048 + fi + + _debug "Use length $length" + + if ! touch "$f" >/dev/null 2>&1; then + _f_path="$(dirname "$f")" + _debug _f_path "$_f_path" + if ! mkdir -p "$_f_path"; then + _err "Can not create path: $_f_path" + return 1 + fi + fi + + if _isEccKey "$length"; then + _debug "Using ec name: $eccname" + if _opkey="$(${ACME_OPENSSL_BIN:-openssl} ecparam -name "$eccname" -genkey 2>/dev/null)"; then + echo "$_opkey" >"$f" + else + _err "error ecc key name: $eccname" + return 1 + fi + else + _debug "Using RSA: $length" + if _opkey="$(${ACME_OPENSSL_BIN:-openssl} genrsa "$length" 2>/dev/null)"; then + echo "$_opkey" >"$f" + else + _err "error rsa key: $length" + return 1 + fi + fi + + if [ "$?" != "0" ]; then + _err "Create key error." + return 1 + fi +} + +#domain +_is_idn() { + _is_idn_d="$1" + _debug2 _is_idn_d "$_is_idn_d" + _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '*.,-_') + _debug2 _idn_temp "$_idn_temp" + [ "$_idn_temp" ] +} + +#aa.com +#aa.com,bb.com,cc.com +_idn() { + __idn_d="$1" + if ! _is_idn "$__idn_d"; then + printf "%s" "$__idn_d" + return 0 + fi + + if _exists idn; then + if _contains "$__idn_d" ','; then + _i_first="1" + for f in $(echo "$__idn_d" | tr ',' ' '); do + [ -z "$f" ] && continue + if [ -z "$_i_first" ]; then + printf "%s" "," + else + _i_first="" + fi + idn --quiet "$f" | tr -d "\r\n" + done + else + idn "$__idn_d" | tr -d "\r\n" + fi + else + _err "Please install idn to process IDN names." + fi +} + +#_createcsr cn san_list keyfile csrfile conf acmeValidationv1 +_createcsr() { + _debug _createcsr + domain="$1" + domainlist="$2" + csrkey="$3" + csr="$4" + csrconf="$5" + acmeValidationv1="$6" + _debug2 domain "$domain" + _debug2 domainlist "$domainlist" + _debug2 csrkey "$csrkey" + _debug2 csr "$csr" + _debug2 csrconf "$csrconf" + + printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]\n\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment" >"$csrconf" + + if [ "$acmeValidationv1" ]; then + domainlist="$(_idn "$domainlist")" + printf -- "\nsubjectAltName=DNS:$domainlist" >>"$csrconf" + elif [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then + #single domain + _info "Single domain" "$domain" + printf -- "\nsubjectAltName=DNS:$(_idn "$domain")" >>"$csrconf" + else + domainlist="$(_idn "$domainlist")" + _debug2 domainlist "$domainlist" + if _contains "$domainlist" ","; then + alt="DNS:$(_idn "$domain"),DNS:$(echo "$domainlist" | sed "s/,,/,/g" | sed "s/,/,DNS:/g")" + else + alt="DNS:$(_idn "$domain"),DNS:$domainlist" + fi + #multi + _info "Multi domain" "$alt" + printf -- "\nsubjectAltName=$alt" >>"$csrconf" + fi + if [ "$Le_OCSP_Staple" = "1" ]; then + _savedomainconf Le_OCSP_Staple "$Le_OCSP_Staple" + printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf" + fi + + if [ "$acmeValidationv1" ]; then + printf "\n1.3.6.1.5.5.7.1.31=critical,DER:04:20:${acmeValidationv1}" >>"${csrconf}" + fi + + _csr_cn="$(_idn "$domain")" + _debug2 _csr_cn "$_csr_cn" + if _contains "$(uname -a)" "MINGW"; then + ${ACME_OPENSSL_BIN:-openssl} req -new -sha256 -key "$csrkey" -subj "//CN=$_csr_cn" -config "$csrconf" -out "$csr" + else + ${ACME_OPENSSL_BIN:-openssl} req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr" + fi +} + +#_signcsr key csr conf cert +_signcsr() { + key="$1" + csr="$2" + conf="$3" + cert="$4" + _debug "_signcsr" + + _msg="$(${ACME_OPENSSL_BIN:-openssl} x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)" + _ret="$?" + _debug "$_msg" + return $_ret +} + +#_csrfile +_readSubjectFromCSR() { + _csrfile="$1" + if [ -z "$_csrfile" ]; then + _usage "_readSubjectFromCSR mycsr.csr" + return 1 + fi + ${ACME_OPENSSL_BIN:-openssl} req -noout -in "$_csrfile" -subject | tr ',' "\n" | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d ' \n' +} + +#_csrfile +#echo comma separated domain list +_readSubjectAltNamesFromCSR() { + _csrfile="$1" + if [ -z "$_csrfile" ]; then + _usage "_readSubjectAltNamesFromCSR mycsr.csr" + return 1 + fi + + _csrsubj="$(_readSubjectFromCSR "$_csrfile")" + _debug _csrsubj "$_csrsubj" + + _dnsAltnames="$(${ACME_OPENSSL_BIN:-openssl} req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')" + _debug _dnsAltnames "$_dnsAltnames" + + if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then + _debug "AltNames contains subject" + _excapedAlgnames="$(echo "$_dnsAltnames" | tr '*' '#')" + _debug _excapedAlgnames "$_excapedAlgnames" + _escapedSubject="$(echo "$_csrsubj" | tr '*' '#')" + _debug _escapedSubject "$_escapedSubject" + _dnsAltnames="$(echo "$_excapedAlgnames," | sed "s/DNS:$_escapedSubject,//g" | tr '#' '*' | sed "s/,\$//g")" + _debug _dnsAltnames "$_dnsAltnames" + else + _debug "AltNames doesn't contain subject" + fi + + echo "$_dnsAltnames" | sed "s/DNS://g" +} + +#_csrfile +_readKeyLengthFromCSR() { + _csrfile="$1" + if [ -z "$_csrfile" ]; then + _usage "_readKeyLengthFromCSR mycsr.csr" + return 1 + fi + + _outcsr="$(${ACME_OPENSSL_BIN:-openssl} req -noout -text -in "$_csrfile")" + _debug2 _outcsr "$_outcsr" + if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then + _debug "ECC CSR" + echo "$_outcsr" | tr "\t" " " | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' ' + else + _debug "RSA CSR" + _rkl="$(echo "$_outcsr" | tr "\t" " " | _egrep_o "^ *Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1)" + if [ "$_rkl" ]; then + echo "$_rkl" + else + echo "$_outcsr" | tr "\t" " " | _egrep_o "RSA Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1 + fi + fi +} + +_ss() { + _port="$1" + + if _exists "ss"; then + _debug "Using: ss" + ss -ntpl 2>/dev/null | grep ":$_port " + return 0 + fi + + if _exists "netstat"; then + _debug "Using: netstat" + if netstat -help 2>&1 | grep "\-p proto" >/dev/null; then + #for windows version netstat tool + netstat -an -p tcp | grep "LISTENING" | grep ":$_port " + else + if netstat -help 2>&1 | grep "\-p protocol" >/dev/null; then + netstat -an -p tcp | grep LISTEN | grep ":$_port " + elif netstat -help 2>&1 | grep -- '-P protocol' >/dev/null; then + #for solaris + netstat -an -P tcp | grep "\.$_port " | grep "LISTEN" + elif netstat -help 2>&1 | grep "\-p" >/dev/null; then + #for full linux + netstat -ntpl | grep ":$_port " + else + #for busybox (embedded linux; no pid support) + netstat -ntl 2>/dev/null | grep ":$_port " + fi + fi + return 0 + fi + + return 1 +} + +#outfile key cert cacert [password [name [caname]]] +_toPkcs() { + _cpfx="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + pfxPassword="$5" + pfxName="$6" + pfxCaname="$7" + + if [ "$pfxCaname" ]; then + ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword" -name "$pfxName" -caname "$pfxCaname" + elif [ "$pfxName" ]; then + ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword" -name "$pfxName" + elif [ "$pfxPassword" ]; then + ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword" + else + ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" + fi + +} + +#domain [password] [isEcc] +toPkcs() { + domain="$1" + pfxPassword="$2" + if [ -z "$domain" ]; then + _usage "Usage: $PROJECT_ENTRY --to-pkcs12 --domain [--password ] [--ecc]" + return 1 + fi + + _isEcc="$3" + + _initpath "$domain" "$_isEcc" + + _toPkcs "$CERT_PFX_PATH" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$pfxPassword" + + if [ "$?" = "0" ]; then + _info "Success, Pfx is exported to: $CERT_PFX_PATH" + fi + +} + +#domain [isEcc] +toPkcs8() { + domain="$1" + + if [ -z "$domain" ]; then + _usage "Usage: $PROJECT_ENTRY --to-pkcs8 --domain [--ecc]" + return 1 + fi + + _isEcc="$2" + + _initpath "$domain" "$_isEcc" + + ${ACME_OPENSSL_BIN:-openssl} pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in "$CERT_KEY_PATH" -out "$CERT_PKCS8_PATH" + + if [ "$?" = "0" ]; then + _info "Success, $CERT_PKCS8_PATH" + fi + +} + +#[2048] +createAccountKey() { + _info "Creating account key" + if [ -z "$1" ]; then + _usage "Usage: $PROJECT_ENTRY --create-account-key [--accountkeylength ]" + return + fi + + length=$1 + _create_account_key "$length" + +} + +_create_account_key() { + + length=$1 + + if [ -z "$length" ] || [ "$length" = "$NO_VALUE" ]; then + _debug "Use default length $DEFAULT_ACCOUNT_KEY_LENGTH" + length="$DEFAULT_ACCOUNT_KEY_LENGTH" + fi + + _debug length "$length" + _initpath + + mkdir -p "$CA_DIR" + if [ -s "$ACCOUNT_KEY_PATH" ]; then + _info "Account key exists, skip" + return 0 + else + #generate account key + if _createkey "$length" "$ACCOUNT_KEY_PATH"; then + chmod 600 "$ACCOUNT_KEY_PATH" + _info "Create account key ok." + return 0 + else + _err "Create account key error." + return 1 + fi + fi + +} + +#domain [length] +createDomainKey() { + _info "Creating domain key" + if [ -z "$1" ]; then + _usage "Usage: $PROJECT_ENTRY --create-domain-key --domain [--keylength ]" + return + fi + + domain=$1 + _cdl=$2 + + if [ -z "$_cdl" ]; then + _debug "Use DEFAULT_DOMAIN_KEY_LENGTH=$DEFAULT_DOMAIN_KEY_LENGTH" + _cdl="$DEFAULT_DOMAIN_KEY_LENGTH" + fi + + _initpath "$domain" "$_cdl" + + if [ ! -f "$CERT_KEY_PATH" ] || [ ! -s "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$_ACME_IS_RENEW" ]) || [ "$Le_ForceNewDomainKey" = "1" ]; then + if _createkey "$_cdl" "$CERT_KEY_PATH"; then + _savedomainconf Le_Keylength "$_cdl" + _info "The domain key is here: $(__green $CERT_KEY_PATH)" + return 0 + else + _err "Can not create domain key" + return 1 + fi + else + if [ "$_ACME_IS_RENEW" ]; then + _info "Domain key exists, skip" + return 0 + else + _err "Domain key exists, do you want to overwrite the key?" + _err "Add '--force', and try again." + return 1 + fi + fi + +} + +# domain domainlist isEcc +createCSR() { + _info "Creating csr" + if [ -z "$1" ]; then + _usage "Usage: $PROJECT_ENTRY --create-csr --domain [--domain ...]" + return + fi + + domain="$1" + domainlist="$2" + _isEcc="$3" + + _initpath "$domain" "$_isEcc" + + if [ -f "$CSR_PATH" ] && [ "$_ACME_IS_RENEW" ] && [ -z "$FORCE" ]; then + _info "CSR exists, skip" + return + fi + + if [ ! -f "$CERT_KEY_PATH" ]; then + _err "The key file is not found: $CERT_KEY_PATH" + _err "Please create the key file first." + return 1 + fi + _createcsr "$domain" "$domainlist" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF" + +} + +_url_replace() { + tr '/+' '_-' | tr -d '= ' +} + +#base64 string +_durl_replace_base64() { + _l=$((${#1} % 4)) + if [ $_l -eq 2 ]; then + _s="$1"'==' + elif [ $_l -eq 3 ]; then + _s="$1"'=' + else + _s="$1" + fi + echo "$_s" | tr '_-' '/+' +} + +_time2str() { + #BSD + if date -u -r "$1" 2>/dev/null; then + return + fi + + #Linux + if date -u -d@"$1" 2>/dev/null; then + return + fi + + #Solaris + if _exists adb; then + _t_s_a=$(echo "0t${1}=Y" | adb) + echo "$_t_s_a" + fi + + #Busybox + if echo "$1" | awk '{ print strftime("%c", $0); }' 2>/dev/null; then + return + fi +} + +_normalizeJson() { + sed "s/\" *: *\([\"{\[]\)/\":\1/g" | sed "s/^ *\([^ ]\)/\1/" | tr -d "\r\n" +} + +_stat() { + #Linux + if stat -c '%U:%G' "$1" 2>/dev/null; then + return + fi + + #BSD + if stat -f '%Su:%Sg' "$1" 2>/dev/null; then + return + fi + + return 1 #error, 'stat' not found +} + +#keyfile +_calcjwk() { + keyfile="$1" + if [ -z "$keyfile" ]; then + _usage "Usage: _calcjwk keyfile" + return 1 + fi + + if [ "$JWK_HEADER" ] && [ "$__CACHED_JWK_KEY_FILE" = "$keyfile" ]; then + _debug2 "Use cached jwk for file: $__CACHED_JWK_KEY_FILE" + return 0 + fi + + if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then + _debug "RSA key" + pub_exp=$(${ACME_OPENSSL_BIN:-openssl} rsa -in "$keyfile" -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1) + if [ "${#pub_exp}" = "5" ]; then + pub_exp=0$pub_exp + fi + _debug3 pub_exp "$pub_exp" + + e=$(echo "$pub_exp" | _h2b | _base64) + _debug3 e "$e" + + modulus=$(${ACME_OPENSSL_BIN:-openssl} rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2) + _debug3 modulus "$modulus" + n="$(printf "%s" "$modulus" | _h2b | _base64 | _url_replace)" + _debug3 n "$n" + + jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' + _debug3 jwk "$jwk" + + JWK_HEADER='{"alg": "RS256", "jwk": '$jwk'}' + JWK_HEADERPLACE_PART1='{"nonce": "' + JWK_HEADERPLACE_PART2='", "alg": "RS256"' + elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then + _debug "EC key" + crv="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")" + _debug3 crv "$crv" + __ECC_KEY_LEN=$(echo "$crv" | cut -d "-" -f 2) + if [ "$__ECC_KEY_LEN" = "521" ]; then + __ECC_KEY_LEN=512 + fi + _debug3 __ECC_KEY_LEN "$__ECC_KEY_LEN" + if [ -z "$crv" ]; then + _debug "Let's try ASN1 OID" + crv_oid="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")" + _debug3 crv_oid "$crv_oid" + case "${crv_oid}" in + "prime256v1") + crv="P-256" + __ECC_KEY_LEN=256 + ;; + "secp384r1") + crv="P-384" + __ECC_KEY_LEN=384 + ;; + "secp521r1") + crv="P-521" + __ECC_KEY_LEN=512 + ;; + *) + _err "ECC oid : $crv_oid" + return 1 + ;; + esac + _debug3 crv "$crv" + fi + + pubi="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)" + pubi=$(_math "$pubi" + 1) + _debug3 pubi "$pubi" + + pubj="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)" + pubj=$(_math "$pubj" - 1) + _debug3 pubj "$pubj" + + pubtext="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")" + _debug3 pubtext "$pubtext" + + xlen="$(printf "%s" "$pubtext" | tr -d ':' | wc -c)" + xlen=$(_math "$xlen" / 4) + _debug3 xlen "$xlen" + + xend=$(_math "$xlen" + 1) + x="$(printf "%s" "$pubtext" | cut -d : -f 2-"$xend")" + _debug3 x "$x" + + x64="$(printf "%s" "$x" | tr -d : | _h2b | _base64 | _url_replace)" + _debug3 x64 "$x64" + + xend=$(_math "$xend" + 1) + y="$(printf "%s" "$pubtext" | cut -d : -f "$xend"-10000)" + _debug3 y "$y" + + y64="$(printf "%s" "$y" | tr -d : | _h2b | _base64 | _url_replace)" + _debug3 y64 "$y64" + + jwk='{"crv": "'$crv'", "kty": "EC", "x": "'$x64'", "y": "'$y64'"}' + _debug3 jwk "$jwk" + + JWK_HEADER='{"alg": "ES'$__ECC_KEY_LEN'", "jwk": '$jwk'}' + JWK_HEADERPLACE_PART1='{"nonce": "' + JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'"' + else + _err "Only RSA or EC key is supported. keyfile=$keyfile" + _debug2 "$(cat "$keyfile")" + return 1 + fi + + _debug3 JWK_HEADER "$JWK_HEADER" + __CACHED_JWK_KEY_FILE="$keyfile" +} + +_time() { + date -u "+%s" +} + +_utc_date() { + date -u "+%Y-%m-%d %H:%M:%S" +} + +_mktemp() { + if _exists mktemp; then + if mktemp 2>/dev/null; then + return 0 + elif _contains "$(mktemp 2>&1)" "-t prefix" && mktemp -t "$PROJECT_NAME" 2>/dev/null; then + #for Mac osx + return 0 + fi + fi + if [ -d "/tmp" ]; then + echo "/tmp/${PROJECT_NAME}wefADf24sf.$(_time).tmp" + return 0 + elif [ "$LE_TEMP_DIR" ] && mkdir -p "$LE_TEMP_DIR"; then + echo "/$LE_TEMP_DIR/wefADf24sf.$(_time).tmp" + return 0 + fi + _err "Can not create temp file." +} + +#clear all the https envs to cause _inithttp() to run next time. +_resethttp() { + __HTTP_INITIALIZED="" + _ACME_CURL="" + _ACME_WGET="" + ACME_HTTP_NO_REDIRECTS="" +} + +_inithttp() { + + if [ -z "$HTTP_HEADER" ] || ! touch "$HTTP_HEADER"; then + HTTP_HEADER="$(_mktemp)" + _debug2 HTTP_HEADER "$HTTP_HEADER" + fi + + if [ "$__HTTP_INITIALIZED" ]; then + if [ "$_ACME_CURL$_ACME_WGET" ]; then + _debug2 "Http already initialized." + return 0 + fi + fi + + if [ -z "$_ACME_CURL" ] && _exists "curl"; then + _ACME_CURL="curl --silent --dump-header $HTTP_HEADER " + if [ -z "$ACME_HTTP_NO_REDIRECTS" ]; then + _ACME_CURL="$_ACME_CURL -L " + fi + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then + _CURL_DUMP="$(_mktemp)" + _ACME_CURL="$_ACME_CURL --trace-ascii $_CURL_DUMP " + fi + + if [ "$CA_PATH" ]; then + _ACME_CURL="$_ACME_CURL --capath $CA_PATH " + elif [ "$CA_BUNDLE" ]; then + _ACME_CURL="$_ACME_CURL --cacert $CA_BUNDLE " + fi + + if _contains "$(curl --help 2>&1)" "--globoff"; then + _ACME_CURL="$_ACME_CURL -g " + fi + fi + + if [ -z "$_ACME_WGET" ] && _exists "wget"; then + _ACME_WGET="wget -q" + if [ "$ACME_HTTP_NO_REDIRECTS" ]; then + _ACME_WGET="$_ACME_WGET --max-redirect 0 " + fi + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then + _ACME_WGET="$_ACME_WGET -d " + fi + if [ "$CA_PATH" ]; then + _ACME_WGET="$_ACME_WGET --ca-directory=$CA_PATH " + elif [ "$CA_BUNDLE" ]; then + _ACME_WGET="$_ACME_WGET --ca-certificate=$CA_BUNDLE " + fi + fi + + #from wget 1.14: do not skip body on 404 error + if [ "$_ACME_WGET" ] && _contains "$($_ACME_WGET --help 2>&1)" "--content-on-error"; then + _ACME_WGET="$_ACME_WGET --content-on-error " + fi + + __HTTP_INITIALIZED=1 + +} + +# body url [needbase64] [POST|PUT|DELETE] [ContentType] +_post() { + body="$1" + _post_url="$2" + needbase64="$3" + httpmethod="$4" + _postContentType="$5" + + if [ -z "$httpmethod" ]; then + httpmethod="POST" + fi + _debug $httpmethod + _debug "_post_url" "$_post_url" + _debug2 "body" "$body" + _debug2 "_postContentType" "$_postContentType" + + _inithttp + + if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then + _CURL="$_ACME_CURL" + if [ "$HTTPS_INSECURE" ]; then + _CURL="$_CURL --insecure " + fi + if [ "$httpmethod" = "HEAD" ]; then + _CURL="$_CURL -I " + fi + _debug "_CURL" "$_CURL" + if [ "$needbase64" ]; then + if [ "$body" ]; then + if [ "$_postContentType" ]; then + 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)" + else + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)" + fi + else + if [ "$_postContentType" ]; then + 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)" + else + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url" | _base64)" + fi + fi + else + if [ "$body" ]; then + if [ "$_postContentType" ]; then + 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")" + else + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")" + fi + else + if [ "$_postContentType" ]; then + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "Content-Type: $_postContentType" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url")" + else + response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$_post_url")" + fi + fi + fi + _ret="$?" + if [ "$_ret" != "0" ]; then + _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret" + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then + _err "Here is the curl dump log:" + _err "$(cat "$_CURL_DUMP")" + fi + fi + elif [ "$_ACME_WGET" ]; then + _WGET="$_ACME_WGET" + if [ "$HTTPS_INSECURE" ]; then + _WGET="$_WGET --no-check-certificate " + fi + if [ "$httpmethod" = "HEAD" ]; then + _WGET="$_WGET --read-timeout=3.0 --tries=2 " + fi + _debug "_WGET" "$_WGET" + if [ "$needbase64" ]; then + if [ "$httpmethod" = "POST" ]; then + if [ "$_postContentType" ]; then + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" + else + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" + fi + else + if [ "$_postContentType" ]; then + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" + else + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)" + fi + fi + else + if [ "$httpmethod" = "POST" ]; then + if [ "$_postContentType" ]; then + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")" + else + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")" + fi + elif [ "$httpmethod" = "HEAD" ]; then + if [ "$_postContentType" ]; then + response="$($_WGET --spider -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")" + else + response="$($_WGET --spider -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")" + fi + else + if [ "$_postContentType" ]; then + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --header "Content-Type: $_postContentType" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")" + else + response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")" + fi + fi + fi + _ret="$?" + if [ "$_ret" = "8" ]; then + _ret=0 + _debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later." + fi + if [ "$_ret" != "0" ]; then + _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret" + fi + _sed_i "s/^ *//g" "$HTTP_HEADER" + else + _ret="$?" + _err "Neither curl nor wget is found, can not do $httpmethod." + fi + _debug "_ret" "$_ret" + printf "%s" "$response" + return $_ret +} + +# url getheader timeout +_get() { + _debug GET + url="$1" + onlyheader="$2" + t="$3" + _debug url "$url" + _debug "timeout=$t" + + _inithttp + + if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then + _CURL="$_ACME_CURL" + if [ "$HTTPS_INSECURE" ]; then + _CURL="$_CURL --insecure " + fi + if [ "$t" ]; then + _CURL="$_CURL --connect-timeout $t" + fi + _debug "_CURL" "$_CURL" + if [ "$onlyheader" ]; then + $_CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url" + else + $_CURL --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url" + fi + ret=$? + if [ "$ret" != "0" ]; then + _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $ret" + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then + _err "Here is the curl dump log:" + _err "$(cat "$_CURL_DUMP")" + fi + fi + elif [ "$_ACME_WGET" ]; then + _WGET="$_ACME_WGET" + if [ "$HTTPS_INSECURE" ]; then + _WGET="$_WGET --no-check-certificate " + fi + if [ "$t" ]; then + _WGET="$_WGET --timeout=$t" + fi + _debug "_WGET" "$_WGET" + if [ "$onlyheader" ]; then + $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null "$url" 2>&1 | sed 's/^[ ]*//g' + else + $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - "$url" + fi + ret=$? + if [ "$ret" = "8" ]; then + ret=0 + _debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later." + fi + if [ "$ret" != "0" ]; then + _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret" + fi + else + ret=$? + _err "Neither curl nor wget is found, can not do GET." + fi + _debug "ret" "$ret" + return $ret +} + +_head_n() { + head -n "$1" +} + +_tail_n() { + if ! tail -n "$1" 2>/dev/null; then + #fix for solaris + tail -"$1" + fi +} + +# url payload needbase64 keyfile +_send_signed_request() { + url=$1 + payload=$2 + needbase64=$3 + keyfile=$4 + if [ -z "$keyfile" ]; then + keyfile="$ACCOUNT_KEY_PATH" + fi + _debug url "$url" + _debug payload "$payload" + + if ! _calcjwk "$keyfile"; then + return 1 + fi + + __request_conent_type="$CONTENT_TYPE_JSON" + + payload64=$(printf "%s" "$payload" | _base64 | _url_replace) + _debug3 payload64 "$payload64" + + MAX_REQUEST_RETRY_TIMES=20 + _sleep_retry_sec=1 + _request_retry_times=0 + while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do + _request_retry_times=$(_math "$_request_retry_times" + 1) + _debug3 _request_retry_times "$_request_retry_times" + if [ -z "$_CACHED_NONCE" ]; then + _headers="" + if [ "$ACME_NEW_NONCE" ]; then + _debug2 "Get nonce with HEAD. ACME_NEW_NONCE" "$ACME_NEW_NONCE" + nonceurl="$ACME_NEW_NONCE" + if _post "" "$nonceurl" "" "HEAD" "$__request_conent_type" >/dev/null; then + _headers="$(cat "$HTTP_HEADER")" + _debug2 _headers "$_headers" + _CACHED_NONCE="$(echo "$_headers" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" + fi + fi + if [ -z "$_CACHED_NONCE" ]; then + _debug2 "Get nonce with GET. ACME_DIRECTORY" "$ACME_DIRECTORY" + nonceurl="$ACME_DIRECTORY" + _headers="$(_get "$nonceurl" "onlyheader")" + _debug2 _headers "$_headers" + _CACHED_NONCE="$(echo "$_headers" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" + fi + if [ -z "$_CACHED_NONCE" ] && [ "$ACME_NEW_NONCE" ]; then + _debug2 "Get nonce with GET. ACME_NEW_NONCE" "$ACME_NEW_NONCE" + nonceurl="$ACME_NEW_NONCE" + _headers="$(_get "$nonceurl" "onlyheader")" + _debug2 _headers "$_headers" + _CACHED_NONCE="$(echo "$_headers" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" + fi + _debug2 _CACHED_NONCE "$_CACHED_NONCE" + if [ "$?" != "0" ]; then + _err "Can not connect to $nonceurl to get nonce." + return 1 + fi + else + _debug2 "Use _CACHED_NONCE" "$_CACHED_NONCE" + fi + nonce="$_CACHED_NONCE" + _debug2 nonce "$nonce" + if [ -z "$nonce" ]; then + _info "Could not get nonce, let's try again." + _sleep 2 + continue + fi + if [ "$ACME_VERSION" = "2" ]; then + if [ "$url" = "$ACME_NEW_ACCOUNT" ]; then + protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}' + elif [ "$url" = "$ACME_REVOKE_CERT" ] && [ "$keyfile" != "$ACCOUNT_KEY_PATH" ]; then + protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}' + else + protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"kid\": \"${ACCOUNT_URL}\""'}' + fi + else + protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}' + fi + _debug3 protected "$protected" + + protected64="$(printf "%s" "$protected" | _base64 | _url_replace)" + _debug3 protected64 "$protected64" + + if ! _sig_t="$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256")"; then + _err "Sign request failed." + return 1 + fi + _debug3 _sig_t "$_sig_t" + + sig="$(printf "%s" "$_sig_t" | _url_replace)" + _debug3 sig "$sig" + + body="{\"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" + _debug3 body "$body" + + response="$(_post "$body" "$url" "$needbase64" "POST" "$__request_conent_type")" + _CACHED_NONCE="" + + if [ "$?" != "0" ]; then + _err "Can not post to $url" + return 1 + fi + + responseHeaders="$(cat "$HTTP_HEADER")" + _debug2 responseHeaders "$responseHeaders" + + code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")" + _debug code "$code" + + _debug2 original "$response" + if echo "$responseHeaders" | grep -i "Content-Type: *application/json" >/dev/null 2>&1; then + response="$(echo "$response" | _json_decode | _normalizeJson)" + fi + _debug2 response "$response" + + _CACHED_NONCE="$(echo "$responseHeaders" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" + + if ! _startswith "$code" "2"; then + _body="$response" + if [ "$needbase64" ]; then + _body="$(echo "$_body" | _dbase64 multiline)" + _debug3 _body "$_body" + fi + + if _contains "$_body" "JWS has invalid anti-replay nonce" || _contains "$_body" "JWS has an invalid anti-replay nonce"; then + _info "It seems the CA server is busy now, let's wait and retry. Sleeping $_sleep_retry_sec seconds." + _CACHED_NONCE="" + _sleep $_sleep_retry_sec + continue + fi + fi + return 0 + done + _info "Giving up sending to CA server after $MAX_REQUEST_RETRY_TIMES retries." + return 1 + +} + +#setopt "file" "opt" "=" "value" [";"] +_setopt() { + __conf="$1" + __opt="$2" + __sep="$3" + __val="$4" + __end="$5" + if [ -z "$__opt" ]; then + _usage usage: _setopt '"file" "opt" "=" "value" [";"]' + return + fi + if [ ! -f "$__conf" ]; then + touch "$__conf" + fi + + if grep -n "^$__opt$__sep" "$__conf" >/dev/null; then + _debug3 OK + if _contains "$__val" "&"; then + __val="$(echo "$__val" | sed 's/&/\\&/g')" + fi + text="$(cat "$__conf")" + printf -- "%s\n" "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" + + elif grep -n "^#$__opt$__sep" "$__conf" >/dev/null; then + if _contains "$__val" "&"; then + __val="$(echo "$__val" | sed 's/&/\\&/g')" + fi + text="$(cat "$__conf")" + printf -- "%s\n" "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf" + + else + _debug3 APP + echo "$__opt$__sep$__val$__end" >>"$__conf" + fi + _debug3 "$(grep -n "^$__opt$__sep" "$__conf")" +} + +#_save_conf file key value base64encode +#save to conf +_save_conf() { + _s_c_f="$1" + _sdkey="$2" + _sdvalue="$3" + _b64encode="$4" + if [ "$_sdvalue" ] && [ "$_b64encode" ]; then + _sdvalue="${B64CONF_START}$(printf "%s" "${_sdvalue}" | _base64)${B64CONF_END}" + fi + if [ "$_s_c_f" ]; then + _setopt "$_s_c_f" "$_sdkey" "=" "'$_sdvalue'" + else + _err "config file is empty, can not save $_sdkey=$_sdvalue" + fi +} + +#_clear_conf file key +_clear_conf() { + _c_c_f="$1" + _sdkey="$2" + if [ "$_c_c_f" ]; then + _conf_data="$(cat "$_c_c_f")" + echo "$_conf_data" | sed "s/^$_sdkey *=.*$//" >"$_c_c_f" + else + _err "config file is empty, can not clear" + fi +} + +#_read_conf file key +_read_conf() { + _r_c_f="$1" + _sdkey="$2" + if [ -f "$_r_c_f" ]; then + _sdv="$( + eval "$(grep "^$_sdkey *=" "$_r_c_f")" + eval "printf \"%s\" \"\$$_sdkey\"" + )" + if _startswith "$_sdv" "${B64CONF_START}" && _endswith "$_sdv" "${B64CONF_END}"; then + _sdv="$(echo "$_sdv" | sed "s/${B64CONF_START}//" | sed "s/${B64CONF_END}//" | _dbase64)" + fi + printf "%s" "$_sdv" + else + _debug "config file is empty, can not read $_sdkey" + fi +} + +#_savedomainconf key value base64encode +#save to domain.conf +_savedomainconf() { + _save_conf "$DOMAIN_CONF" "$@" +} + +#_cleardomainconf key +_cleardomainconf() { + _clear_conf "$DOMAIN_CONF" "$1" +} + +#_readdomainconf key +_readdomainconf() { + _read_conf "$DOMAIN_CONF" "$1" +} + +#key value base64encode +_savedeployconf() { + _savedomainconf "SAVED_$1" "$2" "$3" + #remove later + _cleardomainconf "$1" +} + +#key +_getdeployconf() { + _rac_key="$1" + _rac_value="$(eval echo \$"$_rac_key")" + if [ "$_rac_value" ]; then + if _startswith "$_rac_value" '"' && _endswith "$_rac_value" '"'; then + _debug2 "trim quotation marks" + eval "export $_rac_key=$_rac_value" + fi + return 0 # do nothing + fi + _saved=$(_readdomainconf "SAVED_$_rac_key") + eval "export $_rac_key=\"$_saved\"" +} + +#_saveaccountconf key value base64encode +_saveaccountconf() { + _save_conf "$ACCOUNT_CONF_PATH" "$@" +} + +#key value base64encode +_saveaccountconf_mutable() { + _save_conf "$ACCOUNT_CONF_PATH" "SAVED_$1" "$2" "$3" + #remove later + _clearaccountconf "$1" +} + +#key +_readaccountconf() { + _read_conf "$ACCOUNT_CONF_PATH" "$1" +} + +#key +_readaccountconf_mutable() { + _rac_key="$1" + _readaccountconf "SAVED_$_rac_key" +} + +#_clearaccountconf key +_clearaccountconf() { + _clear_conf "$ACCOUNT_CONF_PATH" "$1" +} + +#_savecaconf key value +_savecaconf() { + _save_conf "$CA_CONF" "$1" "$2" +} + +#_readcaconf key +_readcaconf() { + _read_conf "$CA_CONF" "$1" +} + +#_clearaccountconf key +_clearcaconf() { + _clear_conf "$CA_CONF" "$1" +} + +# content localaddress +_startserver() { + content="$1" + ncaddr="$2" + _debug "content" "$content" + _debug "ncaddr" "$ncaddr" + + _debug "startserver: $$" + + _debug Le_HTTPPort "$Le_HTTPPort" + _debug Le_Listen_V4 "$Le_Listen_V4" + _debug Le_Listen_V6 "$Le_Listen_V6" + + _NC="socat" + if [ "$Le_Listen_V4" ]; then + _NC="$_NC -4" + elif [ "$Le_Listen_V6" ]; then + _NC="$_NC -6" + fi + + if [ "$DEBUG" ] && [ "$DEBUG" -gt "1" ]; then + _NC="$_NC -d -d -v" + fi + + SOCAT_OPTIONS=TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork + + #Adding bind to local-address + if [ "$ncaddr" ]; then + SOCAT_OPTIONS="$SOCAT_OPTIONS,bind=${ncaddr}" + fi + + _content_len="$(printf "%s" "$content" | wc -c)" + _debug _content_len "$_content_len" + _debug "_NC" "$_NC $SOCAT_OPTIONS" + $_NC $SOCAT_OPTIONS SYSTEM:"sleep 1; \ +echo 'HTTP/1.0 200 OK'; \ +echo 'Content-Length\: $_content_len'; \ +echo ''; \ +printf -- '$content';" & + serverproc="$!" +} + +_stopserver() { + pid="$1" + _debug "pid" "$pid" + if [ -z "$pid" ]; then + return + fi + + kill $pid + +} + +# sleep sec +_sleep() { + _sleep_sec="$1" + if [ "$__INTERACTIVE" ]; then + _sleep_c="$_sleep_sec" + while [ "$_sleep_c" -ge "0" ]; do + printf "\r \r" + __green "$_sleep_c" + _sleep_c="$(_math "$_sleep_c" - 1)" + sleep 1 + done + printf "\r" + else + sleep "$_sleep_sec" + fi +} + +# _starttlsserver san_a san_b port content _ncaddr acmeValidationv1 +_starttlsserver() { + _info "Starting tls server." + san_a="$1" + san_b="$2" + port="$3" + content="$4" + opaddr="$5" + acmeValidationv1="$6" + + _debug san_a "$san_a" + _debug san_b "$san_b" + _debug port "$port" + _debug acmeValidationv1 "$acmeValidationv1" + + #create key TLS_KEY + if ! _createkey "2048" "$TLS_KEY"; then + _err "Create tls validation key error." + return 1 + fi + + #create csr + alt="$san_a" + if [ "$san_b" ]; then + alt="$alt,$san_b" + fi + if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" "$acmeValidationv1"; then + _err "Create tls validation csr error." + return 1 + fi + + #self signed + if ! _signcsr "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" "$TLS_CERT"; then + _err "Create tls validation cert error." + return 1 + fi + + __S_OPENSSL="${ACME_OPENSSL_BIN:-openssl} s_server -www -cert $TLS_CERT -key $TLS_KEY " + if [ "$opaddr" ]; then + __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port" + else + __S_OPENSSL="$__S_OPENSSL -accept $port" + fi + + _debug Le_Listen_V4 "$Le_Listen_V4" + _debug Le_Listen_V6 "$Le_Listen_V6" + if [ "$Le_Listen_V4" ]; then + __S_OPENSSL="$__S_OPENSSL -4" + elif [ "$Le_Listen_V6" ]; then + __S_OPENSSL="$__S_OPENSSL -6" + fi + + if [ "$acmeValidationv1" ]; then + __S_OPENSSL="$__S_OPENSSL -alpn acme-tls/1" + fi + + _debug "$__S_OPENSSL" + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then + $__S_OPENSSL -tlsextdebug & + else + $__S_OPENSSL >/dev/null 2>&1 & + fi + + serverproc="$!" + sleep 1 + _debug serverproc "$serverproc" +} + +#file +_readlink() { + _rf="$1" + if ! readlink -f "$_rf" 2>/dev/null; then + if _startswith "$_rf" "/"; then + echo "$_rf" + return 0 + fi + echo "$(pwd)/$_rf" | _conapath + fi +} + +_conapath() { + sed "s#/\./#/#g" +} + +__initHome() { + if [ -z "$_SCRIPT_HOME" ]; then + if _exists readlink && _exists dirname; then + _debug "Lets find script dir." + _debug "_SCRIPT_" "$_SCRIPT_" + _script="$(_readlink "$_SCRIPT_")" + _debug "_script" "$_script" + _script_home="$(dirname "$_script")" + _debug "_script_home" "$_script_home" + if [ -d "$_script_home" ]; then + _SCRIPT_HOME="$_script_home" + else + _err "It seems the script home is not correct:$_script_home" + fi + fi + fi + + # if [ -z "$LE_WORKING_DIR" ]; then + # if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ]; then + # _debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME" + # LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" + # else + # LE_WORKING_DIR="$_SCRIPT_HOME" + # fi + # fi + + if [ -z "$LE_WORKING_DIR" ]; then + _debug "Using default home:$DEFAULT_INSTALL_HOME" + LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" + fi + export LE_WORKING_DIR + + if [ -z "$LE_CONFIG_HOME" ]; then + LE_CONFIG_HOME="$LE_WORKING_DIR" + fi + _debug "Using config home:$LE_CONFIG_HOME" + export LE_CONFIG_HOME + + _DEFAULT_ACCOUNT_CONF_PATH="$LE_CONFIG_HOME/account.conf" + + if [ -z "$ACCOUNT_CONF_PATH" ]; then + if [ -f "$_DEFAULT_ACCOUNT_CONF_PATH" ]; then + . "$_DEFAULT_ACCOUNT_CONF_PATH" + fi + fi + + if [ -z "$ACCOUNT_CONF_PATH" ]; then + ACCOUNT_CONF_PATH="$_DEFAULT_ACCOUNT_CONF_PATH" + fi + _debug3 ACCOUNT_CONF_PATH "$ACCOUNT_CONF_PATH" + DEFAULT_LOG_FILE="$LE_CONFIG_HOME/$PROJECT_NAME.log" + + DEFAULT_CA_HOME="$LE_CONFIG_HOME/ca" + + if [ -z "$LE_TEMP_DIR" ]; then + LE_TEMP_DIR="$LE_CONFIG_HOME/tmp" + fi +} + +#server +_initAPI() { + _api_server="${1:-$ACME_DIRECTORY}" + _debug "_init api for server: $_api_server" + + if [ -z "$ACME_NEW_ACCOUNT" ]; then + response=$(_get "$_api_server") + if [ "$?" != "0" ]; then + _debug2 "response" "$response" + _err "Can not init api." + return 1 + fi + response=$(echo "$response" | _json_decode) + _debug2 "response" "$response" + + ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'key-change" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_KEY_CHANGE" ]; then + ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'keyChange" *: *"[^"]*"' | cut -d '"' -f 3) + fi + export ACME_KEY_CHANGE + + ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'new-authz" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_NEW_AUTHZ" ]; then + ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'newAuthz" *: *"[^"]*"' | cut -d '"' -f 3) + fi + export ACME_NEW_AUTHZ + + ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) + ACME_NEW_ORDER_RES="new-cert" + if [ -z "$ACME_NEW_ORDER" ]; then + ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-order" *: *"[^"]*"' | cut -d '"' -f 3) + ACME_NEW_ORDER_RES="new-order" + if [ -z "$ACME_NEW_ORDER" ]; then + ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'newOrder" *: *"[^"]*"' | cut -d '"' -f 3) + fi + fi + export ACME_NEW_ORDER + export ACME_NEW_ORDER_RES + + ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3) + ACME_NEW_ACCOUNT_RES="new-reg" + if [ -z "$ACME_NEW_ACCOUNT" ]; then + ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-account" *: *"[^"]*"' | cut -d '"' -f 3) + ACME_NEW_ACCOUNT_RES="new-account" + if [ -z "$ACME_NEW_ACCOUNT" ]; then + ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'newAccount" *: *"[^"]*"' | cut -d '"' -f 3) + if [ "$ACME_NEW_ACCOUNT" ]; then + export ACME_VERSION=2 + fi + fi + fi + export ACME_NEW_ACCOUNT + export ACME_NEW_ACCOUNT_RES + + ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_REVOKE_CERT" ]; then + ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revokeCert" *: *"[^"]*"' | cut -d '"' -f 3) + fi + export ACME_REVOKE_CERT + + ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'new-nonce" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_NEW_NONCE" ]; then + ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'newNonce" *: *"[^"]*"' | cut -d '"' -f 3) + fi + export ACME_NEW_NONCE + + ACME_AGREEMENT=$(echo "$response" | _egrep_o 'terms-of-service" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_AGREEMENT" ]; then + ACME_AGREEMENT=$(echo "$response" | _egrep_o 'termsOfService" *: *"[^"]*"' | cut -d '"' -f 3) + fi + export ACME_AGREEMENT + + _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" + _debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ" + _debug "ACME_NEW_ORDER" "$ACME_NEW_ORDER" + _debug "ACME_NEW_ACCOUNT" "$ACME_NEW_ACCOUNT" + _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" + _debug "ACME_AGREEMENT" "$ACME_AGREEMENT" + _debug "ACME_NEW_NONCE" "$ACME_NEW_NONCE" + _debug "ACME_VERSION" "$ACME_VERSION" + + fi +} + +#[domain] [keylength or isEcc flag] +_initpath() { + domain="$1" + _ilength="$2" + + __initHome + + if [ -f "$ACCOUNT_CONF_PATH" ]; then + . "$ACCOUNT_CONF_PATH" + fi + + if [ "$_ACME_IN_CRON" ]; then + if [ ! "$_USER_PATH_EXPORTED" ]; then + _USER_PATH_EXPORTED=1 + export PATH="$USER_PATH:$PATH" + fi + fi + + if [ -z "$CA_HOME" ]; then + CA_HOME="$DEFAULT_CA_HOME" + fi + + if [ -z "$ACME_DIRECTORY" ]; then + if [ "$STAGE" ]; then + ACME_DIRECTORY="$DEFAULT_STAGING_CA" + _info "Using ACME_DIRECTORY: $ACME_DIRECTORY" + else + default_acme_server=$(_readaccountconf "DEFAULT_ACME_SERVER") + _debug default_acme_server "$default_acme_server" + if [ "$default_acme_server" ]; then + ACME_DIRECTORY="$default_acme_server" + else + ACME_DIRECTORY="$DEFAULT_CA" + fi + fi + fi + + _debug ACME_DIRECTORY "$ACME_DIRECTORY" + _ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -s / | cut -d / -f 2)" + _debug2 "_ACME_SERVER_HOST" "$_ACME_SERVER_HOST" + + CA_DIR="$CA_HOME/$_ACME_SERVER_HOST" + + _DEFAULT_CA_CONF="$CA_DIR/ca.conf" + + if [ -z "$CA_CONF" ]; then + CA_CONF="$_DEFAULT_CA_CONF" + fi + _debug3 CA_CONF "$CA_CONF" + + if [ -f "$CA_CONF" ]; then + . "$CA_CONF" + fi + + if [ -z "$ACME_DIR" ]; then + ACME_DIR="/home/.acme" + fi + + if [ -z "$APACHE_CONF_BACKUP_DIR" ]; then + APACHE_CONF_BACKUP_DIR="$LE_CONFIG_HOME" + fi + + if [ -z "$USER_AGENT" ]; then + USER_AGENT="$DEFAULT_USER_AGENT" + fi + + if [ -z "$HTTP_HEADER" ]; then + HTTP_HEADER="$LE_CONFIG_HOME/http.header" + fi + + _OLD_ACCOUNT_KEY="$LE_WORKING_DIR/account.key" + _OLD_ACCOUNT_JSON="$LE_WORKING_DIR/account.json" + + _DEFAULT_ACCOUNT_KEY_PATH="$CA_DIR/account.key" + _DEFAULT_ACCOUNT_JSON_PATH="$CA_DIR/account.json" + if [ -z "$ACCOUNT_KEY_PATH" ]; then + ACCOUNT_KEY_PATH="$_DEFAULT_ACCOUNT_KEY_PATH" + fi + + if [ -z "$ACCOUNT_JSON_PATH" ]; then + ACCOUNT_JSON_PATH="$_DEFAULT_ACCOUNT_JSON_PATH" + fi + + _DEFAULT_CERT_HOME="$LE_CONFIG_HOME" + if [ -z "$CERT_HOME" ]; then + CERT_HOME="$_DEFAULT_CERT_HOME" + fi + + if [ -z "$ACME_OPENSSL_BIN" ] || [ ! -f "$ACME_OPENSSL_BIN" ] || [ ! -x "$ACME_OPENSSL_BIN" ]; then + ACME_OPENSSL_BIN="$DEFAULT_OPENSSL_BIN" + fi + + if [ -z "$domain" ]; then + return 0 + fi + + if [ -z "$DOMAIN_PATH" ]; then + domainhome="$CERT_HOME/$domain" + domainhomeecc="$CERT_HOME/$domain$ECC_SUFFIX" + + DOMAIN_PATH="$domainhome" + + if _isEccKey "$_ilength"; then + DOMAIN_PATH="$domainhomeecc" + else + if [ ! -d "$domainhome" ] && [ -d "$domainhomeecc" ]; then + _info "The domain '$domain' seems to have a ECC cert already, please add '$(__red "--ecc")' parameter if you want to use that cert." + fi + fi + _debug DOMAIN_PATH "$DOMAIN_PATH" + fi + + if [ -z "$DOMAIN_BACKUP_PATH" ]; then + DOMAIN_BACKUP_PATH="$DOMAIN_PATH/backup" + fi + + if [ -z "$DOMAIN_CONF" ]; then + DOMAIN_CONF="$DOMAIN_PATH/$domain.conf" + fi + + if [ -z "$DOMAIN_SSL_CONF" ]; then + DOMAIN_SSL_CONF="$DOMAIN_PATH/$domain.csr.conf" + fi + + if [ -z "$CSR_PATH" ]; then + CSR_PATH="$DOMAIN_PATH/$domain.csr" + fi + if [ -z "$CERT_KEY_PATH" ]; then + CERT_KEY_PATH="$DOMAIN_PATH/$domain.key" + fi + if [ -z "$CERT_PATH" ]; then + CERT_PATH="$DOMAIN_PATH/$domain.cer" + fi + if [ -z "$CA_CERT_PATH" ]; then + CA_CERT_PATH="$DOMAIN_PATH/ca.cer" + fi + if [ -z "$CERT_FULLCHAIN_PATH" ]; then + CERT_FULLCHAIN_PATH="$DOMAIN_PATH/fullchain.cer" + fi + if [ -z "$CERT_PFX_PATH" ]; then + CERT_PFX_PATH="$DOMAIN_PATH/$domain.pfx" + fi + if [ -z "$CERT_PKCS8_PATH" ]; then + CERT_PKCS8_PATH="$DOMAIN_PATH/$domain.pkcs8" + fi + + if [ -z "$TLS_CONF" ]; then + TLS_CONF="$DOMAIN_PATH/tls.validation.conf" + fi + if [ -z "$TLS_CERT" ]; then + TLS_CERT="$DOMAIN_PATH/tls.validation.cert" + fi + if [ -z "$TLS_KEY" ]; then + TLS_KEY="$DOMAIN_PATH/tls.validation.key" + fi + if [ -z "$TLS_CSR" ]; then + TLS_CSR="$DOMAIN_PATH/tls.validation.csr" + fi + +} + +_exec() { + if [ -z "$_EXEC_TEMP_ERR" ]; then + _EXEC_TEMP_ERR="$(_mktemp)" + fi + + if [ "$_EXEC_TEMP_ERR" ]; then + eval "$@ 2>>$_EXEC_TEMP_ERR" + else + eval "$@" + fi +} + +_exec_err() { + [ "$_EXEC_TEMP_ERR" ] && _err "$(cat "$_EXEC_TEMP_ERR")" && echo "" >"$_EXEC_TEMP_ERR" +} + +_apachePath() { + _APACHECTL="apachectl" + if ! _exists apachectl; then + if _exists apache2ctl; then + _APACHECTL="apache2ctl" + else + _err "'apachectl not found. It seems that apache is not installed, or you are not root user.'" + _err "Please use webroot mode to try again." + return 1 + fi + fi + + if ! _exec $_APACHECTL -V >/dev/null; then + _exec_err + return 1 + fi + + if [ "$APACHE_HTTPD_CONF" ]; then + _saveaccountconf APACHE_HTTPD_CONF "$APACHE_HTTPD_CONF" + httpdconf="$APACHE_HTTPD_CONF" + httpdconfname="$(basename "$httpdconfname")" + else + httpdconfname="$($_APACHECTL -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"')" + _debug httpdconfname "$httpdconfname" + + if [ -z "$httpdconfname" ]; then + _err "Can not read apache config file." + return 1 + fi + + if _startswith "$httpdconfname" '/'; then + httpdconf="$httpdconfname" + httpdconfname="$(basename "$httpdconfname")" + else + httpdroot="$($_APACHECTL -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"')" + _debug httpdroot "$httpdroot" + httpdconf="$httpdroot/$httpdconfname" + httpdconfname="$(basename "$httpdconfname")" + fi + fi + _debug httpdconf "$httpdconf" + _debug httpdconfname "$httpdconfname" + if [ ! -f "$httpdconf" ]; then + _err "Apache Config file not found" "$httpdconf" + return 1 + fi + return 0 +} + +_restoreApache() { + if [ -z "$usingApache" ]; then + return 0 + fi + _initpath + if ! _apachePath; then + return 1 + fi + + if [ ! -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" ]; then + _debug "No config file to restore." + return 0 + fi + + cat "$APACHE_CONF_BACKUP_DIR/$httpdconfname" >"$httpdconf" + _debug "Restored: $httpdconf." + if ! _exec $_APACHECTL -t; then + _exec_err + _err "Sorry, restore apache config error, please contact me." + return 1 + fi + _debug "Restored successfully." + rm -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" + return 0 +} + +_setApache() { + _initpath + if ! _apachePath; then + return 1 + fi + + #test the conf first + _info "Checking if there is an error in the apache config file before starting." + + if ! _exec "$_APACHECTL" -t >/dev/null; then + _exec_err + _err "The apache config file has error, please fix it first, then try again." + _err "Don't worry, there is nothing changed to your system." + return 1 + else + _info "OK" + fi + + #backup the conf + _debug "Backup apache config file" "$httpdconf" + if ! cp "$httpdconf" "$APACHE_CONF_BACKUP_DIR/"; then + _err "Can not backup apache config file, so abort. Don't worry, the apache config is not changed." + _err "This might be a bug of $PROJECT_NAME , please report issue: $PROJECT" + return 1 + fi + _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname" + _info "In case there is an error that can not be restored automatically, you may try restore it yourself." + _info "The backup file will be deleted on success, just forget it." + + #add alias + + apacheVer="$($_APACHECTL -V | grep "Server version:" | cut -d : -f 2 | cut -d " " -f 2 | cut -d '/' -f 2)" + _debug "apacheVer" "$apacheVer" + apacheMajor="$(echo "$apacheVer" | cut -d . -f 1)" + apacheMinor="$(echo "$apacheVer" | cut -d . -f 2)" + + if [ "$apacheVer" ] && [ "$apacheMajor$apacheMinor" -ge "24" ]; then + echo " +Alias /.well-known/acme-challenge $ACME_DIR + + +Require all granted + + " >>"$httpdconf" + else + echo " +Alias /.well-known/acme-challenge $ACME_DIR + + +Order allow,deny +Allow from all + + " >>"$httpdconf" + fi + + _msg="$($_APACHECTL -t 2>&1)" + if [ "$?" != "0" ]; then + _err "Sorry, apache config error" + if _restoreApache; then + _err "The apache config file is restored." + else + _err "Sorry, the apache config file can not be restored, please report bug." + fi + return 1 + fi + + if [ ! -d "$ACME_DIR" ]; then + mkdir -p "$ACME_DIR" + chmod 755 "$ACME_DIR" + fi + + if ! _exec "$_APACHECTL" graceful; then + _exec_err + _err "$_APACHECTL graceful error, please contact me." + _restoreApache + return 1 + fi + usingApache="1" + return 0 +} + +#find the real nginx conf file +#backup +#set the nginx conf +#returns the real nginx conf file +_setNginx() { + _d="$1" + _croot="$2" + _thumbpt="$3" + + FOUND_REAL_NGINX_CONF="" + FOUND_REAL_NGINX_CONF_LN="" + BACKUP_NGINX_CONF="" + _debug _croot "$_croot" + _start_f="$(echo "$_croot" | cut -d : -f 2)" + _debug _start_f "$_start_f" + if [ -z "$_start_f" ]; then + _debug "find start conf from nginx command" + if [ -z "$NGINX_CONF" ]; then + if ! _exists "nginx"; then + _err "nginx command is not found." + return 1 + fi + NGINX_CONF="$(nginx -V 2>&1 | _egrep_o "--conf-path=[^ ]* " | tr -d " ")" + _debug NGINX_CONF "$NGINX_CONF" + NGINX_CONF="$(echo "$NGINX_CONF" | cut -d = -f 2)" + _debug NGINX_CONF "$NGINX_CONF" + if [ -z "$NGINX_CONF" ]; then + _err "Can not find nginx conf." + NGINX_CONF="" + return 1 + fi + if [ ! -f "$NGINX_CONF" ]; then + _err "'$NGINX_CONF' doesn't exist." + NGINX_CONF="" + return 1 + fi + _debug "Found nginx conf file:$NGINX_CONF" + fi + _start_f="$NGINX_CONF" + fi + _debug "Start detect nginx conf for $_d from:$_start_f" + if ! _checkConf "$_d" "$_start_f"; then + _err "Can not find conf file for domain $d" + return 1 + fi + _info "Found conf file: $FOUND_REAL_NGINX_CONF" + + _ln=$FOUND_REAL_NGINX_CONF_LN + _debug "_ln" "$_ln" + + _lnn=$(_math $_ln + 1) + _debug _lnn "$_lnn" + _start_tag="$(sed -n "$_lnn,${_lnn}p" "$FOUND_REAL_NGINX_CONF")" + _debug "_start_tag" "$_start_tag" + if [ "$_start_tag" = "$NGINX_START" ]; then + _info "The domain $_d is already configured, skip" + FOUND_REAL_NGINX_CONF="" + return 0 + fi + + mkdir -p "$DOMAIN_BACKUP_PATH" + _backup_conf="$DOMAIN_BACKUP_PATH/$_d.nginx.conf" + _debug _backup_conf "$_backup_conf" + BACKUP_NGINX_CONF="$_backup_conf" + _info "Backup $FOUND_REAL_NGINX_CONF to $_backup_conf" + if ! cp "$FOUND_REAL_NGINX_CONF" "$_backup_conf"; then + _err "backup error." + FOUND_REAL_NGINX_CONF="" + return 1 + fi + + if ! _exists "nginx"; then + _err "nginx command is not found." + return 1 + fi + _info "Check the nginx conf before setting up." + if ! _exec "nginx -t" >/dev/null; then + _exec_err + return 1 + fi + + _info "OK, Set up nginx config file" + + if ! sed -n "1,${_ln}p" "$_backup_conf" >"$FOUND_REAL_NGINX_CONF"; then + cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" + _err "write nginx conf error, but don't worry, the file is restored to the original version." + return 1 + fi + + echo "$NGINX_START +location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" { + default_type text/plain; + return 200 \"\$1.$_thumbpt\"; +} +#NGINX_START +" >>"$FOUND_REAL_NGINX_CONF" + + if ! sed -n "${_lnn},99999p" "$_backup_conf" >>"$FOUND_REAL_NGINX_CONF"; then + cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" + _err "write nginx conf error, but don't worry, the file is restored." + return 1 + fi + _debug3 "Modified config:$(cat $FOUND_REAL_NGINX_CONF)" + _info "nginx conf is done, let's check it again." + if ! _exec "nginx -t" >/dev/null; then + _exec_err + _err "It seems that nginx conf was broken, let's restore." + cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" + return 1 + fi + + _info "Reload nginx" + if ! _exec "nginx -s reload" >/dev/null; then + _exec_err + _err "It seems that nginx reload error, let's restore." + cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF" + return 1 + fi + + return 0 +} + +#d , conf +_checkConf() { + _d="$1" + _c_file="$2" + _debug "Start _checkConf from:$_c_file" + if [ ! -f "$2" ] && ! echo "$2" | grep '*$' >/dev/null && echo "$2" | grep '*' >/dev/null; then + _debug "wildcard" + for _w_f in $2; do + if [ -f "$_w_f" ] && _checkConf "$1" "$_w_f"; then + return 0 + fi + done + #not found + return 1 + elif [ -f "$2" ]; then + _debug "single" + if _isRealNginxConf "$1" "$2"; then + _debug "$2 is found." + FOUND_REAL_NGINX_CONF="$2" + return 0 + fi + if cat "$2" | tr "\t" " " | grep "^ *include *.*;" >/dev/null; then + _debug "Try include files" + for included in $(cat "$2" | tr "\t" " " | grep "^ *include *.*;" | sed "s/include //" | tr -d " ;"); do + _debug "check included $included" + if _checkConf "$1" "$included"; then + return 0 + fi + done + fi + return 1 + else + _debug "$2 not found." + return 1 + fi + return 1 +} + +#d , conf +_isRealNginxConf() { + _debug "_isRealNginxConf $1 $2" + if [ -f "$2" ]; then + for _fln in $(tr "\t" ' ' <"$2" | grep -n "^ *server_name.* $1" | cut -d : -f 1); do + _debug _fln "$_fln" + if [ "$_fln" ]; then + _start=$(tr "\t" ' ' <"$2" | _head_n "$_fln" | grep -n "^ *server *" | grep -v server_name | _tail_n 1) + _debug "_start" "$_start" + _start_n=$(echo "$_start" | cut -d : -f 1) + _start_nn=$(_math $_start_n + 1) + _debug "_start_n" "$_start_n" + _debug "_start_nn" "$_start_nn" + + _left="$(sed -n "${_start_nn},99999p" "$2")" + _debug2 _left "$_left" + _end="$(echo "$_left" | tr "\t" ' ' | grep -n "^ *server *" | grep -v server_name | _head_n 1)" + _debug "_end" "$_end" + if [ "$_end" ]; then + _end_n=$(echo "$_end" | cut -d : -f 1) + _debug "_end_n" "$_end_n" + _seg_n=$(echo "$_left" | sed -n "1,${_end_n}p") + else + _seg_n="$_left" + fi + + _debug "_seg_n" "$_seg_n" + + _skip_ssl=1 + for _listen_i in $(echo "$_seg_n" | tr "\t" ' ' | grep "^ *listen" | tr -d " "); do + if [ "$_listen_i" ]; then + if [ "$(echo "$_listen_i" | _egrep_o "listen.*ssl")" ]; then + _debug2 "$_listen_i is ssl" + else + _debug2 "$_listen_i is plain text" + _skip_ssl="" + break + fi + fi + done + + if [ "$_skip_ssl" = "1" ]; then + _debug "ssl on, skip" + else + FOUND_REAL_NGINX_CONF_LN=$_fln + _debug3 "found FOUND_REAL_NGINX_CONF_LN" "$FOUND_REAL_NGINX_CONF_LN" + return 0 + fi + fi + done + fi + return 1 +} + +#restore all the nginx conf +_restoreNginx() { + if [ -z "$NGINX_RESTORE_VLIST" ]; then + _debug "No need to restore nginx, skip." + return + fi + _debug "_restoreNginx" + _debug "NGINX_RESTORE_VLIST" "$NGINX_RESTORE_VLIST" + + for ng_entry in $(echo "$NGINX_RESTORE_VLIST" | tr "$dvsep" ' '); do + _debug "ng_entry" "$ng_entry" + _nd=$(echo "$ng_entry" | cut -d "$sep" -f 1) + _ngconf=$(echo "$ng_entry" | cut -d "$sep" -f 2) + _ngbackupconf=$(echo "$ng_entry" | cut -d "$sep" -f 3) + _info "Restoring from $_ngbackupconf to $_ngconf" + cat "$_ngbackupconf" >"$_ngconf" + done + + _info "Reload nginx" + if ! _exec "nginx -s reload" >/dev/null; then + _exec_err + _err "It seems that nginx reload error, please report bug." + return 1 + fi + return 0 +} + +_clearup() { + _stopserver "$serverproc" + serverproc="" + _restoreApache + _restoreNginx + _clearupdns + if [ -z "$DEBUG" ]; then + rm -f "$TLS_CONF" + rm -f "$TLS_CERT" + rm -f "$TLS_KEY" + rm -f "$TLS_CSR" + fi +} + +_clearupdns() { + _debug "_clearupdns" + _debug "dns_entries" "$dns_entries" + + if [ -z "$dns_entries" ]; then + _debug "skip dns." + return + fi + _info "Removing DNS records." + + for entry in $dns_entries; do + d=$(_getfield "$entry" 1) + txtdomain=$(_getfield "$entry" 2) + aliasDomain=$(_getfield "$entry" 3) + _currentRoot=$(_getfield "$entry" 4) + txt=$(_getfield "$entry" 5) + d_api=$(_getfield "$entry" 6) + _debug "d" "$d" + _debug "txtdomain" "$txtdomain" + _debug "aliasDomain" "$aliasDomain" + _debug "_currentRoot" "$_currentRoot" + _debug "txt" "$txt" + _debug "d_api" "$d_api" + if [ "$d_api" = "$txt" ]; then + d_api="" + fi + + if [ -z "$d_api" ]; then + _info "Not Found domain api file: $d_api" + continue + fi + + if [ "$aliasDomain" ]; then + txtdomain="$aliasDomain" + fi + + ( + if ! . "$d_api"; then + _err "Load file $d_api error. Please check your api file and try again." + return 1 + fi + + rmcommand="${_currentRoot}_rm" + if ! _exists "$rmcommand"; then + _err "It seems that your api file doesn't define $rmcommand" + return 1 + fi + _info "Removing txt: $txt for domain: $txtdomain" + if ! $rmcommand "$txtdomain" "$txt"; then + _err "Error removing txt for domain:$txtdomain" + return 1 + fi + _info "Removed: Success" + ) + + done +} + +# webroot removelevel tokenfile +_clearupwebbroot() { + __webroot="$1" + if [ -z "$__webroot" ]; then + _debug "no webroot specified, skip" + return 0 + fi + + _rmpath="" + if [ "$2" = '1' ]; then + _rmpath="$__webroot/.well-known" + elif [ "$2" = '2' ]; then + _rmpath="$__webroot/.well-known/acme-challenge" + elif [ "$2" = '3' ]; then + _rmpath="$__webroot/.well-known/acme-challenge/$3" + else + _debug "Skip for removelevel:$2" + fi + + if [ "$_rmpath" ]; then + if [ "$DEBUG" ]; then + _debug "Debugging, skip removing: $_rmpath" + else + rm -rf "$_rmpath" + fi + fi + + return 0 + +} + +_on_before_issue() { + _chk_web_roots="$1" + _chk_main_domain="$2" + _chk_alt_domains="$3" + _chk_pre_hook="$4" + _chk_local_addr="$5" + _debug _on_before_issue + _debug _chk_main_domain "$_chk_main_domain" + _debug _chk_alt_domains "$_chk_alt_domains" + #run pre hook + if [ "$_chk_pre_hook" ]; then + _info "Run pre hook:'$_chk_pre_hook'" + if ! ( + cd "$DOMAIN_PATH" && eval "$_chk_pre_hook" + ); then + _err "Error when run pre hook." + return 1 + fi + fi + + if _hasfield "$_chk_web_roots" "$NO_VALUE"; then + if ! _exists "socat"; then + _err "Please install socat tools first." + return 1 + fi + fi + + _debug Le_LocalAddress "$_chk_local_addr" + + _index=1 + _currentRoot="" + _addrIndex=1 + _w_index=1 + while true; do + d="$(echo "$_chk_main_domain,$_chk_alt_domains," | cut -d , -f "$_w_index")" + _w_index="$(_math "$_w_index" + 1)" + _debug d "$d" + if [ -z "$d" ]; then + break + fi + _debug "Check for domain" "$d" + _currentRoot="$(_getfield "$_chk_web_roots" $_index)" + _debug "_currentRoot" "$_currentRoot" + _index=$(_math $_index + 1) + _checkport="" + if [ "$_currentRoot" = "$NO_VALUE" ]; then + _info "Standalone mode." + if [ -z "$Le_HTTPPort" ]; then + Le_HTTPPort=80 + _cleardomainconf "Le_HTTPPort" + else + _savedomainconf "Le_HTTPPort" "$Le_HTTPPort" + fi + _checkport="$Le_HTTPPort" + elif [ "$_currentRoot" = "$W_ALPN" ]; then + _info "Standalone alpn mode." + if [ -z "$Le_TLSPort" ]; then + Le_TLSPort=443 + else + _savedomainconf "Le_TLSPort" "$Le_TLSPort" + fi + _checkport="$Le_TLSPort" + fi + + if [ "$_checkport" ]; then + _debug _checkport "$_checkport" + _checkaddr="$(_getfield "$_chk_local_addr" $_addrIndex)" + _debug _checkaddr "$_checkaddr" + + _addrIndex="$(_math $_addrIndex + 1)" + + _netprc="$(_ss "$_checkport" | grep "$_checkport")" + netprc="$(echo "$_netprc" | grep "$_checkaddr")" + if [ -z "$netprc" ]; then + netprc="$(echo "$_netprc" | grep "$LOCAL_ANY_ADDRESS")" + fi + if [ "$netprc" ]; then + _err "$netprc" + _err "tcp port $_checkport is already used by $(echo "$netprc" | cut -d : -f 4)" + _err "Please stop it first" + return 1 + fi + fi + done + + if _hasfield "$_chk_web_roots" "apache"; then + if ! _setApache; then + _err "set up apache error. Report error to me." + return 1 + fi + else + usingApache="" + fi + +} + +_on_issue_err() { + _chk_post_hook="$1" + _chk_vlist="$2" + _debug _on_issue_err + + if [ "$LOG_FILE" ]; then + _err "Please check log file for more details: $LOG_FILE" + else + _err "Please add '--debug' or '--log' to check more details." + _err "See: $_DEBUG_WIKI" + fi + + #run the post hook + if [ "$_chk_post_hook" ]; then + _info "Run post hook:'$_chk_post_hook'" + if ! ( + cd "$DOMAIN_PATH" && eval "$_chk_post_hook" + ); then + _err "Error when run post hook." + return 1 + fi + fi + + #trigger the validation to flush the pending authz + _debug2 "_chk_vlist" "$_chk_vlist" + if [ "$_chk_vlist" ]; then + ( + _debug2 "start to deactivate authz" + ventries=$(echo "$_chk_vlist" | tr "$dvsep" ' ') + for ventry in $ventries; do + d=$(echo "$ventry" | cut -d "$sep" -f 1) + keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) + uri=$(echo "$ventry" | cut -d "$sep" -f 3) + vtype=$(echo "$ventry" | cut -d "$sep" -f 4) + _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) + __trigger_validation "$uri" "$keyauthorization" + done + ) + fi + + if [ "$_ACME_IS_RENEW" = "1" ] && _hasfield "$Le_Webroot" "$W_DNS"; then + _err "$_DNS_MANUAL_ERR" + fi + + if [ "$DEBUG" ] && [ "$DEBUG" -gt "0" ]; then + _debug "$(_dlg_versions)" + fi + +} + +_on_issue_success() { + _chk_post_hook="$1" + _chk_renew_hook="$2" + _debug _on_issue_success + + #run the post hook + if [ "$_chk_post_hook" ]; then + _info "Run post hook:'$_chk_post_hook'" + if ! ( + export CERT_PATH + export CERT_KEY_PATH + export CA_CERT_PATH + export CERT_FULLCHAIN_PATH + export Le_Domain="$_main_domain" + cd "$DOMAIN_PATH" && eval "$_chk_post_hook" + ); then + _err "Error when run post hook." + return 1 + fi + fi + + #run renew hook + if [ "$_ACME_IS_RENEW" ] && [ "$_chk_renew_hook" ]; then + _info "Run renew hook:'$_chk_renew_hook'" + if ! ( + export CERT_PATH + export CERT_KEY_PATH + export CA_CERT_PATH + export CERT_FULLCHAIN_PATH + export Le_Domain="$_main_domain" + cd "$DOMAIN_PATH" && eval "$_chk_renew_hook" + ); then + _err "Error when run renew hook." + return 1 + fi + fi + + if _hasfield "$Le_Webroot" "$W_DNS" && [ -z "$FORCE_DNS_MANUAL" ]; then + _err "$_DNS_MANUAL_WARN" + fi + +} + +#account_key_length eab-kid eab-hmac-key +registeraccount() { + _account_key_length="$1" + _eab_id="$2" + _eab_hmac_key="$3" + _initpath + _regAccount "$_account_key_length" "$_eab_id" "$_eab_hmac_key" +} + +__calcAccountKeyHash() { + [ -f "$ACCOUNT_KEY_PATH" ] && _digest sha256 <"$ACCOUNT_KEY_PATH" +} + +__calc_account_thumbprint() { + printf "%s" "$jwk" | tr -d ' ' | _digest "sha256" | _url_replace +} + +_getAccountEmail() { + if [ "$ACCOUNT_EMAIL" ]; then + echo "$ACCOUNT_EMAIL" + return 0 + fi + if [ -z "$CA_EMAIL" ]; then + CA_EMAIL="$(_readcaconf CA_EMAIL)" + fi + if [ "$CA_EMAIL" ]; then + echo "$CA_EMAIL" + return 0 + fi + _readaccountconf "ACCOUNT_EMAIL" +} + +#keylength +_regAccount() { + _initpath + _reg_length="$1" + _eab_id="$2" + _eab_hmac_key="$3" + _debug3 _regAccount "$_regAccount" + _initAPI + + mkdir -p "$CA_DIR" + if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then + _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH" + mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH" + fi + + if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then + _info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH" + mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH" + fi + + if [ ! -f "$ACCOUNT_KEY_PATH" ]; then + if ! _create_account_key "$_reg_length"; then + _err "Create account key error." + return 1 + fi + fi + + if ! _calcjwk "$ACCOUNT_KEY_PATH"; then + return 1 + fi + if [ "$_eab_id" ] && [ "$_eab_hmac_key" ]; then + _savecaconf CA_EAB_KEY_ID "$_eab_id" + _savecaconf CA_EAB_HMAC_KEY "$_eab_hmac_key" + fi + _eab_id=$(_readcaconf "CA_EAB_KEY_ID") + _eab_hmac_key=$(_readcaconf "CA_EAB_HMAC_KEY") + _secure_debug3 _eab_id "$_eab_id" + _secure_debug3 _eab_hmac_key "$_eab_hmac_key" + _email="$(_getAccountEmail)" + if [ "$_email" ]; then + _savecaconf "CA_EMAIL" "$_email" + fi + if [ "$ACME_VERSION" = "2" ]; then + if [ "$ACME_DIRECTORY" = "$CA_ZEROSSL" ]; then + if [ -z "$_eab_id" ] || [ -z "$_eab_hmac_key" ]; then + _info "No EAB credentials found for ZeroSSL, let's get one" + if [ -z "$_email" ]; then + _err "Please provide a email address for ZeroSSL account." + _err "See ZeroSSL usage: $_ZEROSSL_WIKI" + return 1 + fi + _eabresp=$(_post "email=$_email" $_ZERO_EAB_ENDPOINT) + if [ "$?" != "0" ]; then + _debug2 "$_eabresp" + _err "Can not get EAB credentials from ZeroSSL." + return 1 + fi + _eab_id="$(echo "$_eabresp" | tr ',}' '\n' | grep '"eab_kid"' | cut -d : -f 2 | tr -d '"')" + if [ -z "$_eab_id" ]; then + _err "Can not resolve _eab_id" + return 1 + fi + _eab_hmac_key="$(echo "$_eabresp" | tr ',}' '\n' | grep '"eab_hmac_key"' | cut -d : -f 2 | tr -d '"')" + if [ -z "$_eab_hmac_key" ]; then + _err "Can not resolve _eab_hmac_key" + return 1 + fi + _savecaconf CA_EAB_KEY_ID "$_eab_id" + _savecaconf CA_EAB_HMAC_KEY "$_eab_hmac_key" + fi + fi + if [ "$_eab_id" ] && [ "$_eab_hmac_key" ]; then + eab_protected="{\"alg\":\"HS256\",\"kid\":\"$_eab_id\",\"url\":\"${ACME_NEW_ACCOUNT}\"}" + _debug3 eab_protected "$eab_protected" + + eab_protected64=$(printf "%s" "$eab_protected" | _base64 | _url_replace) + _debug3 eab_protected64 "$eab_protected64" + + eab_payload64=$(printf "%s" "$jwk" | _base64 | _url_replace) + _debug3 eab_payload64 "$eab_payload64" + + eab_sign_t="$eab_protected64.$eab_payload64" + _debug3 eab_sign_t "$eab_sign_t" + + key_hex="$(_durl_replace_base64 "$_eab_hmac_key" | _dbase64 | _hex_dump | tr -d ' ')" + _debug3 key_hex "$key_hex" + + eab_signature=$(printf "%s" "$eab_sign_t" | _hmac sha256 $key_hex | _base64 | _url_replace) + _debug3 eab_signature "$eab_signature" + + externalBinding=",\"externalAccountBinding\":{\"protected\":\"$eab_protected64\", \"payload\":\"$eab_payload64\", \"signature\":\"$eab_signature\"}" + _debug3 externalBinding "$externalBinding" + fi + if [ "$_email" ]; then + email_sg="\"contact\": [\"mailto:$_email\"], " + fi + regjson="{$email_sg\"termsOfServiceAgreed\": true$externalBinding}" + else + _reg_res="$ACME_NEW_ACCOUNT_RES" + regjson='{"resource": "'$_reg_res'", "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' + if [ "$_email" ]; then + regjson='{"resource": "'$_reg_res'", "contact": ["mailto:'$_email'"], "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}' + fi + fi + + _info "Registering account: $ACME_DIRECTORY" + + if ! _send_signed_request "${ACME_NEW_ACCOUNT}" "$regjson"; then + _err "Register account Error: $response" + return 1 + fi + + _eabAlreadyBound="" + if [ "$code" = "" ] || [ "$code" = '201' ]; then + echo "$response" >"$ACCOUNT_JSON_PATH" + _info "Registered" + elif [ "$code" = '409' ] || [ "$code" = '200' ]; then + _info "Already registered" + elif [ "$code" = '400' ] && _contains "$response" 'The account is not awaiting external account binding'; then + _info "Already register EAB." + _eabAlreadyBound=1 + else + _err "Register account Error: $response" + return 1 + fi + + if [ -z "$_eabAlreadyBound" ]; then + _debug2 responseHeaders "$responseHeaders" + _accUri="$(echo "$responseHeaders" | grep -i "^Location:" | _head_n 1 | cut -d ':' -f 2- | tr -d "\r\n ")" + _debug "_accUri" "$_accUri" + if [ -z "$_accUri" ]; then + _err "Can not find account id url." + _err "$responseHeaders" + return 1 + fi + _savecaconf "ACCOUNT_URL" "$_accUri" + else + ACCOUNT_URL="$(_readcaconf ACCOUNT_URL)" + fi + export ACCOUNT_URL="$_accUri" + + CA_KEY_HASH="$(__calcAccountKeyHash)" + _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH" + _savecaconf CA_KEY_HASH "$CA_KEY_HASH" + + if [ "$code" = '403' ]; then + _err "It seems that the account key is already deactivated, please use a new account key." + return 1 + fi + + ACCOUNT_THUMBPRINT="$(__calc_account_thumbprint)" + _info "ACCOUNT_THUMBPRINT" "$ACCOUNT_THUMBPRINT" +} + +#implement updateaccount +updateaccount() { + _initpath + + if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then + _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH" + mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH" + fi + + if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then + _info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH" + mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH" + fi + + if [ ! -f "$ACCOUNT_KEY_PATH" ]; then + _err "Account key is not found at: $ACCOUNT_KEY_PATH" + return 1 + fi + + _accUri=$(_readcaconf "ACCOUNT_URL") + _debug _accUri "$_accUri" + + if [ -z "$_accUri" ]; then + _err "The account url is empty, please run '--update-account' first to update the account info first," + _err "Then try again." + return 1 + fi + + if ! _calcjwk "$ACCOUNT_KEY_PATH"; then + return 1 + fi + _initAPI + + _email="$(_getAccountEmail)" + if [ "$ACME_VERSION" = "2" ]; then + if [ "$ACCOUNT_EMAIL" ]; then + updjson='{"contact": ["mailto:'$_email'"]}' + else + updjson='{"contact": []}' + fi + else + # ACMEv1: Updates happen the same way a registration is done. + # https://tools.ietf.org/html/draft-ietf-acme-acme-01#section-6.3 + _regAccount + return + fi + + # this part handles ACMEv2 account updates. + _send_signed_request "$_accUri" "$updjson" + + if [ "$code" = '200' ]; then + echo "$response" >"$ACCOUNT_JSON_PATH" + _info "account update success for $_accUri." + else + _info "Error. The account was not updated." + return 1 + fi +} + +#Implement deactivate account +deactivateaccount() { + _initpath + + if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then + _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH" + mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH" + fi + + if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then + _info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH" + mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH" + fi + + if [ ! -f "$ACCOUNT_KEY_PATH" ]; then + _err "Account key is not found at: $ACCOUNT_KEY_PATH" + return 1 + fi + + _accUri=$(_readcaconf "ACCOUNT_URL") + _debug _accUri "$_accUri" + + if [ -z "$_accUri" ]; then + _err "The account url is empty, please run '--update-account' first to update the account info first," + _err "Then try again." + return 1 + fi + + if ! _calcjwk "$ACCOUNT_KEY_PATH"; then + return 1 + fi + _initAPI + + if [ "$ACME_VERSION" = "2" ]; then + _djson="{\"status\":\"deactivated\"}" + else + _djson="{\"resource\": \"reg\", \"status\":\"deactivated\"}" + fi + if _send_signed_request "$_accUri" "$_djson" && _contains "$response" '"deactivated"'; then + _info "Deactivate account success for $_accUri." + _accid=$(echo "$response" | _egrep_o "\"id\" *: *[^,]*," | cut -d : -f 2 | tr -d ' ,') + elif [ "$code" = "403" ]; then + _info "The account is already deactivated." + _accid=$(_getfield "$_accUri" "999" "/") + else + _err "Deactivate: account failed for $_accUri." + return 1 + fi + + _debug "Account id: $_accid" + if [ "$_accid" ]; then + _deactivated_account_path="$CA_DIR/deactivated/$_accid" + _debug _deactivated_account_path "$_deactivated_account_path" + if mkdir -p "$_deactivated_account_path"; then + _info "Moving deactivated account info to $_deactivated_account_path/" + mv "$CA_CONF" "$_deactivated_account_path/" + mv "$ACCOUNT_JSON_PATH" "$_deactivated_account_path/" + mv "$ACCOUNT_KEY_PATH" "$_deactivated_account_path/" + else + _err "Can not create dir: $_deactivated_account_path, try to remove the deactivated account key." + rm -f "$CA_CONF" + rm -f "$ACCOUNT_JSON_PATH" + rm -f "$ACCOUNT_KEY_PATH" + fi + fi +} + +# domain folder file +_findHook() { + _hookdomain="$1" + _hookcat="$2" + _hookname="$3" + + if [ -f "$_SCRIPT_HOME/$_hookcat/$_hookname" ]; then + d_api="$_SCRIPT_HOME/$_hookcat/$_hookname" + elif [ -f "$_SCRIPT_HOME/$_hookcat/$_hookname.sh" ]; then + d_api="$_SCRIPT_HOME/$_hookcat/$_hookname.sh" + elif [ "$_hookdomain" ] && [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname" ]; then + d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname" + elif [ "$_hookdomain" ] && [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname.sh" ]; then + d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname.sh" + elif [ -f "$LE_WORKING_DIR/$_hookname" ]; then + d_api="$LE_WORKING_DIR/$_hookname" + elif [ -f "$LE_WORKING_DIR/$_hookname.sh" ]; then + d_api="$LE_WORKING_DIR/$_hookname.sh" + elif [ -f "$LE_WORKING_DIR/$_hookcat/$_hookname" ]; then + d_api="$LE_WORKING_DIR/$_hookcat/$_hookname" + elif [ -f "$LE_WORKING_DIR/$_hookcat/$_hookname.sh" ]; then + d_api="$LE_WORKING_DIR/$_hookcat/$_hookname.sh" + fi + + printf "%s" "$d_api" +} + +#domain +__get_domain_new_authz() { + _gdnd="$1" + _info "Getting new-authz for domain" "$_gdnd" + _initAPI + _Max_new_authz_retry_times=5 + _authz_i=0 + while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do + _debug "Try new-authz for the $_authz_i time." + if ! _send_signed_request "${ACME_NEW_AUTHZ}" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then + _err "Can not get domain new authz." + return 1 + fi + if _contains "$response" "No registration exists matching provided key"; then + _err "It seems there is an error, but it's recovered now, please try again." + _err "If you see this message for a second time, please report bug: $(__green "$PROJECT")" + _clearcaconf "CA_KEY_HASH" + break + fi + if ! _contains "$response" "An error occurred while processing your request"; then + _info "The new-authz request is ok." + break + fi + _authz_i="$(_math "$_authz_i" + 1)" + _info "The server is busy, Sleep $_authz_i to retry." + _sleep "$_authz_i" + done + + if [ "$_authz_i" = "$_Max_new_authz_retry_times" ]; then + _err "new-authz retry reach the max $_Max_new_authz_retry_times times." + fi + + if [ "$code" ] && [ "$code" != '201' ]; then + _err "new-authz error: $response" + return 1 + fi + +} + +#uri keyAuthorization +__trigger_validation() { + _debug2 "Trigger domain validation." + _t_url="$1" + _debug2 _t_url "$_t_url" + _t_key_authz="$2" + _debug2 _t_key_authz "$_t_key_authz" + _t_vtype="$3" + _debug2 _t_vtype "$_t_vtype" + if [ "$ACME_VERSION" = "2" ]; then + _send_signed_request "$_t_url" "{}" + else + _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"type\": \"$_t_vtype\", \"keyAuthorization\": \"$_t_key_authz\"}" + fi +} + +#endpoint domain type +_ns_lookup_impl() { + _ns_ep="$1" + _ns_domain="$2" + _ns_type="$3" + _debug2 "_ns_ep" "$_ns_ep" + _debug2 "_ns_domain" "$_ns_domain" + _debug2 "_ns_type" "$_ns_type" + + response="$(_H1="accept: application/dns-json" _get "$_ns_ep?name=$_ns_domain&type=$_ns_type")" + _ret=$? + _debug2 "response" "$response" + if [ "$_ret" != "0" ]; then + return $_ret + fi + _answers="$(echo "$response" | tr '{}' '<>' | _egrep_o '"Answer":\[[^]]*]' | tr '<>' '\n\n')" + _debug2 "_answers" "$_answers" + echo "$_answers" +} + +#domain, type +_ns_lookup_cf() { + _cf_ld="$1" + _cf_ld_type="$2" + _cf_ep="https://cloudflare-dns.com/dns-query" + _ns_lookup_impl "$_cf_ep" "$_cf_ld" "$_cf_ld_type" +} + +#domain, type +_ns_purge_cf() { + _cf_d="$1" + _cf_d_type="$2" + _debug "Cloudflare purge $_cf_d_type record for domain $_cf_d" + _cf_purl="https://cloudflare-dns.com/api/v1/purge?domain=$_cf_d&type=$_cf_d_type" + response="$(_post "" "$_cf_purl")" + _debug2 response "$response" +} + +#checks if cf server is available +_ns_is_available_cf() { + if _get "https://cloudflare-dns.com" >/dev/null 2>&1; then + return 0 + else + return 1 + fi +} + +#domain, type +_ns_lookup_google() { + _cf_ld="$1" + _cf_ld_type="$2" + _cf_ep="https://dns.google/resolve" + _ns_lookup_impl "$_cf_ep" "$_cf_ld" "$_cf_ld_type" +} + +#domain, type +_ns_lookup() { + if [ -z "$DOH_USE" ]; then + _debug "Detect dns server first." + if _ns_is_available_cf; then + _debug "Use cloudflare doh server" + export DOH_USE=$DOH_CLOUDFLARE + else + _debug "Use google doh server" + export DOH_USE=$DOH_GOOGLE + fi + fi + + if [ "$DOH_USE" = "$DOH_CLOUDFLARE" ] || [ -z "$DOH_USE" ]; then + _ns_lookup_cf "$@" + else + _ns_lookup_google "$@" + fi + +} + +#txtdomain, alias, txt +__check_txt() { + _c_txtdomain="$1" + _c_aliasdomain="$2" + _c_txt="$3" + _debug "_c_txtdomain" "$_c_txtdomain" + _debug "_c_aliasdomain" "$_c_aliasdomain" + _debug "_c_txt" "$_c_txt" + _answers="$(_ns_lookup "$_c_aliasdomain" TXT)" + _contains "$_answers" "$_c_txt" + +} + +#txtdomain +__purge_txt() { + _p_txtdomain="$1" + _debug _p_txtdomain "$_p_txtdomain" + if [ "$DOH_USE" = "$DOH_CLOUDFLARE" ] || [ -z "$DOH_USE" ]; then + _ns_purge_cf "$_p_txtdomain" "TXT" + else + _debug "no purge api for google dns api, just sleep 5 secs" + _sleep 5 + fi + +} + +#wait and check each dns entries +_check_dns_entries() { + _success_txt="," + _end_time="$(_time)" + _end_time="$(_math "$_end_time" + 1200)" #let's check no more than 20 minutes. + + while [ "$(_time)" -le "$_end_time" ]; do + _left="" + for entry in $dns_entries; do + d=$(_getfield "$entry" 1) + txtdomain=$(_getfield "$entry" 2) + txtdomain=$(_idn "$txtdomain") + aliasDomain=$(_getfield "$entry" 3) + aliasDomain=$(_idn "$aliasDomain") + txt=$(_getfield "$entry" 5) + d_api=$(_getfield "$entry" 6) + _debug "d" "$d" + _debug "txtdomain" "$txtdomain" + _debug "aliasDomain" "$aliasDomain" + _debug "txt" "$txt" + _debug "d_api" "$d_api" + _info "Checking $d for $aliasDomain" + if _contains "$_success_txt" ",$txt,"; then + _info "Already success, continue next one." + continue + fi + + if __check_txt "$txtdomain" "$aliasDomain" "$txt"; then + _info "Domain $d '$aliasDomain' success." + _success_txt="$_success_txt,$txt," + continue + fi + _left=1 + _info "Not valid yet, let's wait 10 seconds and check next one." + __purge_txt "$txtdomain" + if [ "$txtdomain" != "$aliasDomain" ]; then + __purge_txt "$aliasDomain" + fi + _sleep 10 + done + if [ "$_left" ]; then + _info "Let's wait 10 seconds and check again". + _sleep 10 + else + _info "All success, let's return" + return 0 + fi + done + _info "Timed out waiting for DNS." + return 1 + +} + +#file +_get_cert_issuers() { + _cfile="$1" + if _contains "$(${ACME_OPENSSL_BIN:-openssl} help crl2pkcs7 2>&1)" "Usage: crl2pkcs7" || _contains "$(${ACME_OPENSSL_BIN:-openssl} crl2pkcs7 help 2>&1)" "unknown option help"; then + ${ACME_OPENSSL_BIN:-openssl} crl2pkcs7 -nocrl -certfile $_cfile | ${ACME_OPENSSL_BIN:-openssl} pkcs7 -print_certs -text -noout | grep 'Issuer:' | _egrep_o "CN *=[^,]*" | cut -d = -f 2 + else + ${ACME_OPENSSL_BIN:-openssl} x509 -in $_cfile -text -noout | grep 'Issuer:' | _egrep_o "CN *=[^,]*" | cut -d = -f 2 + fi +} + +#cert issuer +_match_issuer() { + _cfile="$1" + _missuer="$2" + _fissuers="$(_get_cert_issuers $_cfile)" + _debug2 _fissuers "$_fissuers" + if _contains "$_fissuers" "$_missuer"; then + return 0 + fi + _fissuers="$(echo "$_fissuers" | _lower_case)" + _missuer="$(echo "$_missuer" | _lower_case)" + _contains "$_fissuers" "$_missuer" +} + +#webroot, domain domainlist keylength +issue() { + if [ -z "$2" ]; then + _usage "Usage: $PROJECT_ENTRY --issue --domain --webroot " + return 1 + fi + if [ -z "$1" ]; then + _usage "Please specify at least one validation method: '--webroot', '--standalone', '--apache', '--nginx' or '--dns' etc." + return 1 + fi + _web_roots="$1" + _main_domain="$2" + _alt_domains="$3" + + if _contains "$_main_domain" ","; then + _main_domain=$(echo "$2,$3" | cut -d , -f 1) + _alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//") + fi + _debug _main_domain "$_main_domain" + _debug _alt_domains "$_alt_domains" + + _key_length="$4" + _real_cert="$5" + _real_key="$6" + _real_ca="$7" + _reload_cmd="$8" + _real_fullchain="$9" + _pre_hook="${10}" + _post_hook="${11}" + _renew_hook="${12}" + _local_addr="${13}" + _challenge_alias="${14}" + _preferred_chain="${15}" + + if [ -z "$_ACME_IS_RENEW" ]; then + _initpath "$_main_domain" "$_key_length" + mkdir -p "$DOMAIN_PATH" + fi + + if _hasfield "$_web_roots" "$W_DNS" && [ -z "$FORCE_DNS_MANUAL" ]; then + _err "$_DNS_MANUAL_ERROR" + return 1 + fi + + _debug "Using ACME_DIRECTORY: $ACME_DIRECTORY" + + _initAPI + + if [ -f "$DOMAIN_CONF" ]; then + Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime) + _debug Le_NextRenewTime "$Le_NextRenewTime" + if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then + _saved_domain=$(_readdomainconf Le_Domain) + _debug _saved_domain "$_saved_domain" + _saved_alt=$(_readdomainconf Le_Alt) + _debug _saved_alt "$_saved_alt" + if [ "$_saved_domain,$_saved_alt" = "$_main_domain,$_alt_domains" ]; then + _info "Domains not changed." + _info "Skip, Next renewal time is: $(__green "$(_readdomainconf Le_NextRenewTimeStr)")" + _info "Add '$(__red '--force')' to force to renew." + return $RENEW_SKIP + else + _info "Domains have changed." + fi + fi + fi + + _savedomainconf "Le_Domain" "$_main_domain" + _savedomainconf "Le_Alt" "$_alt_domains" + _savedomainconf "Le_Webroot" "$_web_roots" + + _savedomainconf "Le_PreHook" "$_pre_hook" "base64" + _savedomainconf "Le_PostHook" "$_post_hook" "base64" + _savedomainconf "Le_RenewHook" "$_renew_hook" "base64" + + if [ "$_local_addr" ]; then + _savedomainconf "Le_LocalAddress" "$_local_addr" + else + _cleardomainconf "Le_LocalAddress" + fi + if [ "$_challenge_alias" ]; then + _savedomainconf "Le_ChallengeAlias" "$_challenge_alias" + else + _cleardomainconf "Le_ChallengeAlias" + fi + if [ "$_preferred_chain" ]; then + _savedomainconf "Le_Preferred_Chain" "$_preferred_chain" "base64" + else + _cleardomainconf "Le_Preferred_Chain" + fi + + Le_API="$ACME_DIRECTORY" + _savedomainconf "Le_API" "$Le_API" + + _info "Using CA: $ACME_DIRECTORY" + if [ "$_alt_domains" = "$NO_VALUE" ]; then + _alt_domains="" + fi + + if [ "$_key_length" = "$NO_VALUE" ]; then + _key_length="" + fi + + if ! _on_before_issue "$_web_roots" "$_main_domain" "$_alt_domains" "$_pre_hook" "$_local_addr"; then + _err "_on_before_issue." + return 1 + fi + + _saved_account_key_hash="$(_readcaconf "CA_KEY_HASH")" + _debug2 _saved_account_key_hash "$_saved_account_key_hash" + + if [ -z "$ACCOUNT_URL" ] || [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ]; then + if ! _regAccount "$_accountkeylength"; then + _on_issue_err "$_post_hook" + return 1 + fi + else + _debug "_saved_account_key_hash is not changed, skip register account." + fi + + if [ -f "$CSR_PATH" ] && [ ! -f "$CERT_KEY_PATH" ]; then + _info "Signing from existing CSR." + else + _key=$(_readdomainconf Le_Keylength) + _debug "Read key length:$_key" + if [ ! -f "$CERT_KEY_PATH" ] || [ "$_key_length" != "$_key" ] || [ "$Le_ForceNewDomainKey" = "1" ]; then + if ! createDomainKey "$_main_domain" "$_key_length"; then + _err "Create domain key error." + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + fi + + if ! _createcsr "$_main_domain" "$_alt_domains" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then + _err "Create CSR error." + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + fi + + _savedomainconf "Le_Keylength" "$_key_length" + + vlist="$Le_Vlist" + _cleardomainconf "Le_Vlist" + _info "Getting domain auth token for each domain" + sep='#' + dvsep=',' + if [ -z "$vlist" ]; then + if [ "$ACME_VERSION" = "2" ]; then + #make new order request + _identifiers="{\"type\":\"dns\",\"value\":\"$(_idn "$_main_domain")\"}" + _w_index=1 + while true; do + d="$(echo "$_alt_domains," | cut -d , -f "$_w_index")" + _w_index="$(_math "$_w_index" + 1)" + _debug d "$d" + if [ -z "$d" ]; then + break + fi + _identifiers="$_identifiers,{\"type\":\"dns\",\"value\":\"$(_idn "$d")\"}" + done + _debug2 _identifiers "$_identifiers" + if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then + _err "Create new order error." + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + Le_LinkOrder="$(echo "$responseHeaders" | grep -i '^Location.*$' | _tail_n 1 | tr -d "\r\n " | cut -d ":" -f 2-)" + _debug Le_LinkOrder "$Le_LinkOrder" + Le_OrderFinalize="$(echo "$response" | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)" + _debug Le_OrderFinalize "$Le_OrderFinalize" + if [ -z "$Le_OrderFinalize" ]; then + _err "Create new order error. Le_OrderFinalize not found. $response" + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + + #for dns manual mode + _savedomainconf "Le_OrderFinalize" "$Le_OrderFinalize" + + _authorizations_seg="$(echo "$response" | _json_decode | _egrep_o '"authorizations" *: *\[[^\[]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')" + _debug2 _authorizations_seg "$_authorizations_seg" + if [ -z "$_authorizations_seg" ]; then + _err "_authorizations_seg not found." + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + + #domain and authz map + _authorizations_map="" + for _authz_url in $(echo "$_authorizations_seg" | tr ',' ' '); do + _debug2 "_authz_url" "$_authz_url" + if ! _send_signed_request "$_authz_url"; then + _err "get to authz error." + _err "_authorizations_seg" "$_authorizations_seg" + _err "_authz_url" "$_authz_url" + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + + response="$(echo "$response" | _normalizeJson)" + _debug2 response "$response" + _d="$(echo "$response" | _egrep_o '"value" *: *"[^"]*"' | cut -d : -f 2 | tr -d ' "')" + if _contains "$response" "\"wildcard\" *: *true"; then + _d="*.$_d" + fi + _debug2 _d "$_d" + _authorizations_map="$_d,$response +$_authorizations_map" + done + _debug2 _authorizations_map "$_authorizations_map" + fi + + _index=0 + _currentRoot="" + _w_index=1 + while true; do + d="$(echo "$_main_domain,$_alt_domains," | cut -d , -f "$_w_index")" + _w_index="$(_math "$_w_index" + 1)" + _debug d "$d" + if [ -z "$d" ]; then + break + fi + _info "Getting webroot for domain" "$d" + _index=$(_math $_index + 1) + _w="$(echo $_web_roots | cut -d , -f $_index)" + _debug _w "$_w" + if [ "$_w" ]; then + _currentRoot="$_w" + fi + _debug "_currentRoot" "$_currentRoot" + + vtype="$VTYPE_HTTP" + #todo, v2 wildcard force to use dns + if _startswith "$_currentRoot" "$W_DNS"; then + vtype="$VTYPE_DNS" + fi + + if [ "$_currentRoot" = "$W_ALPN" ]; then + vtype="$VTYPE_ALPN" + fi + + if [ "$ACME_VERSION" = "2" ]; then + _idn_d="$(_idn "$d")" + _candidates="$(echo "$_authorizations_map" | grep -i "^$_idn_d,")" + _debug2 _candidates "$_candidates" + if [ "$(echo "$_candidates" | wc -l)" -gt 1 ]; then + for _can in $_candidates; do + if _startswith "$(echo "$_can" | tr '.' '|')" "$(echo "$_idn_d" | tr '.' '|'),"; then + _candidates="$_can" + break + fi + done + fi + response="$(echo "$_candidates" | sed "s/$_idn_d,//")" + _debug2 "response" "$response" + if [ -z "$response" ]; then + _err "get to authz error." + _err "_authorizations_map" "$_authorizations_map" + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + else + if ! __get_domain_new_authz "$d"; then + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + fi + + if [ -z "$thumbprint" ]; then + thumbprint="$(__calc_account_thumbprint)" + fi + + entry="$(echo "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" + _debug entry "$entry" + keyauthorization="" + if [ -z "$entry" ]; then + if ! _startswith "$d" '*.'; then + _debug "Not a wildcard domain, lets check whether the validation is already valid." + if echo "$response" | grep '"status":"valid"' >/dev/null 2>&1; then + _debug "$d is already valid." + keyauthorization="$STATE_VERIFIED" + _debug keyauthorization "$keyauthorization" + fi + fi + if [ -z "$keyauthorization" ]; then + _err "Error, can not get domain token entry $d for $vtype" + _supported_vtypes="$(echo "$response" | _egrep_o "\"challenges\":\[[^]]*]" | tr '{' "\n" | grep type | cut -d '"' -f 4 | tr "\n" ' ')" + if [ "$_supported_vtypes" ]; then + _err "The supported validation types are: $_supported_vtypes, but you specified: $vtype" + fi + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + fi + + if [ -z "$keyauthorization" ]; then + token="$(echo "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" + _debug token "$token" + + if [ -z "$token" ]; then + _err "Error, can not get domain token $entry" + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + if [ "$ACME_VERSION" = "2" ]; then + uri="$(echo "$entry" | _egrep_o '"url":"[^"]*' | cut -d '"' -f 4 | _head_n 1)" + else + uri="$(echo "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)" + fi + _debug uri "$uri" + + if [ -z "$uri" ]; then + _err "Error, can not get domain uri. $entry" + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + keyauthorization="$token.$thumbprint" + _debug keyauthorization "$keyauthorization" + + if printf "%s" "$response" | grep '"status":"valid"' >/dev/null 2>&1; then + _debug "$d is already verified." + keyauthorization="$STATE_VERIFIED" + _debug keyauthorization "$keyauthorization" + fi + fi + + dvlist="$d$sep$keyauthorization$sep$uri$sep$vtype$sep$_currentRoot" + _debug dvlist "$dvlist" + + vlist="$vlist$dvlist$dvsep" + + done + _debug vlist "$vlist" + #add entry + dns_entries="" + dnsadded="" + ventries=$(echo "$vlist" | tr "$dvsep" ' ') + _alias_index=1 + for ventry in $ventries; do + d=$(echo "$ventry" | cut -d "$sep" -f 1) + keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) + vtype=$(echo "$ventry" | cut -d "$sep" -f 4) + _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) + _debug d "$d" + if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then + _debug "$d is already verified, skip $vtype." + _alias_index="$(_math "$_alias_index" + 1)" + continue + fi + + if [ "$vtype" = "$VTYPE_DNS" ]; then + dnsadded='0' + _dns_root_d="$d" + if _startswith "$_dns_root_d" "*."; then + _dns_root_d="$(echo "$_dns_root_d" | sed 's/*.//')" + fi + _d_alias="$(_getfield "$_challenge_alias" "$_alias_index")" + _alias_index="$(_math "$_alias_index" + 1)" + _debug "_d_alias" "$_d_alias" + if [ "$_d_alias" ]; then + if _startswith "$_d_alias" "$DNS_ALIAS_PREFIX"; then + txtdomain="$(echo "$_d_alias" | sed "s/$DNS_ALIAS_PREFIX//")" + else + txtdomain="_acme-challenge.$_d_alias" + fi + dns_entry="${_dns_root_d}${dvsep}_acme-challenge.$_dns_root_d$dvsep$txtdomain$dvsep$_currentRoot" + else + txtdomain="_acme-challenge.$_dns_root_d" + dns_entry="${_dns_root_d}${dvsep}_acme-challenge.$_dns_root_d$dvsep$dvsep$_currentRoot" + fi + + _debug txtdomain "$txtdomain" + txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)" + _debug txt "$txt" + + d_api="$(_findHook "$_dns_root_d" $_SUB_FOLDER_DNSAPI "$_currentRoot")" + _debug d_api "$d_api" + + dns_entry="$dns_entry$dvsep$txt${dvsep}$d_api" + _debug2 dns_entry "$dns_entry" + if [ "$d_api" ]; then + _debug "Found domain api file: $d_api" + else + if [ "$_currentRoot" != "$W_DNS" ]; then + _err "Can not find dns api hook for: $_currentRoot" + _info "You need to add the txt record manually." + fi + _info "$(__red "Add the following TXT record:")" + _info "$(__red "Domain: '$(__green "$txtdomain")'")" + _info "$(__red "TXT value: '$(__green "$txt")'")" + _info "$(__red "Please be aware that you prepend _acme-challenge. before your domain")" + _info "$(__red "so the resulting subdomain will be: $txtdomain")" + continue + fi + + ( + if ! . "$d_api"; then + _err "Load file $d_api error. Please check your api file and try again." + return 1 + fi + + addcommand="${_currentRoot}_add" + if ! _exists "$addcommand"; then + _err "It seems that your api file is not correct, it must have a function named: $addcommand" + return 1 + fi + _info "Adding txt value: $txt for domain: $txtdomain" + if ! $addcommand "$txtdomain" "$txt"; then + _err "Error add txt for domain:$txtdomain" + return 1 + fi + _info "The txt record is added: Success." + ) + + if [ "$?" != "0" ]; then + _on_issue_err "$_post_hook" "$vlist" + _clearup + return 1 + fi + dns_entries="$dns_entries$dns_entry +" + _debug2 "$dns_entries" + dnsadded='1' + fi + done + + if [ "$dnsadded" = '0' ]; then + _savedomainconf "Le_Vlist" "$vlist" + _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit." + _err "Please add the TXT records to the domains, and re-run with --renew." + _on_issue_err "$_post_hook" + _clearup + return 1 + fi + + fi + + if [ "$dns_entries" ]; then + if [ -z "$Le_DNSSleep" ]; then + _info "Let's check each DNS record now. Sleep 20 seconds first." + _sleep 20 + if ! _check_dns_entries; then + _err "check dns error." + _on_issue_err "$_post_hook" + _clearup + return 1 + fi + else + _savedomainconf "Le_DNSSleep" "$Le_DNSSleep" + _info "Sleep $(__green $Le_DNSSleep) seconds for the txt records to take effect" + _sleep "$Le_DNSSleep" + fi + fi + + NGINX_RESTORE_VLIST="" + _debug "ok, let's start to verify" + + _ncIndex=1 + ventries=$(echo "$vlist" | tr "$dvsep" ' ') + for ventry in $ventries; do + d=$(echo "$ventry" | cut -d "$sep" -f 1) + keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2) + uri=$(echo "$ventry" | cut -d "$sep" -f 3) + vtype=$(echo "$ventry" | cut -d "$sep" -f 4) + _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5) + + if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then + _info "$d is already verified, skip $vtype." + continue + fi + + _info "Verifying: $d" + _debug "d" "$d" + _debug "keyauthorization" "$keyauthorization" + _debug "uri" "$uri" + removelevel="" + token="$(printf "%s" "$keyauthorization" | cut -d '.' -f 1)" + + _debug "_currentRoot" "$_currentRoot" + + if [ "$vtype" = "$VTYPE_HTTP" ]; then + if [ "$_currentRoot" = "$NO_VALUE" ]; then + _info "Standalone mode server" + _ncaddr="$(_getfield "$_local_addr" "$_ncIndex")" + _ncIndex="$(_math $_ncIndex + 1)" + _startserver "$keyauthorization" "$_ncaddr" + if [ "$?" != "0" ]; then + _clearup + _on_issue_err "$_post_hook" "$vlist" + return 1 + fi + sleep 1 + _debug serverproc "$serverproc" + elif [ "$_currentRoot" = "$MODE_STATELESS" ]; then + _info "Stateless mode for domain:$d" + _sleep 1 + elif _startswith "$_currentRoot" "$NGINX"; then + _info "Nginx mode for domain:$d" + #set up nginx server + FOUND_REAL_NGINX_CONF="" + BACKUP_NGINX_CONF="" + if ! _setNginx "$d" "$_currentRoot" "$thumbprint"; then + _clearup + _on_issue_err "$_post_hook" "$vlist" + return 1 + fi + + if [ "$FOUND_REAL_NGINX_CONF" ]; then + _realConf="$FOUND_REAL_NGINX_CONF" + _backup="$BACKUP_NGINX_CONF" + _debug _realConf "$_realConf" + NGINX_RESTORE_VLIST="$d$sep$_realConf$sep$_backup$dvsep$NGINX_RESTORE_VLIST" + fi + _sleep 1 + else + if [ "$_currentRoot" = "apache" ]; then + wellknown_path="$ACME_DIR" + else + wellknown_path="$_currentRoot/.well-known/acme-challenge" + if [ ! -d "$_currentRoot/.well-known" ]; then + removelevel='1' + elif [ ! -d "$_currentRoot/.well-known/acme-challenge" ]; then + removelevel='2' + else + removelevel='3' + fi + fi + + _debug wellknown_path "$wellknown_path" + + _debug "writing token:$token to $wellknown_path/$token" + + mkdir -p "$wellknown_path" + + if ! printf "%s" "$keyauthorization" >"$wellknown_path/$token"; then + _err "$d:Can not write token to file : $wellknown_path/$token" + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" + _clearup + _on_issue_err "$_post_hook" "$vlist" + return 1 + fi + + if [ ! "$usingApache" ]; then + if webroot_owner=$(_stat "$_currentRoot"); then + _debug "Changing owner/group of .well-known to $webroot_owner" + if ! _exec "chown -R \"$webroot_owner\" \"$_currentRoot/.well-known\""; then + _debug "$(cat "$_EXEC_TEMP_ERR")" + _exec_err >/dev/null 2>&1 + fi + else + _debug "not changing owner/group of webroot" + fi + fi + + fi + elif [ "$vtype" = "$VTYPE_ALPN" ]; then + acmevalidationv1="$(printf "%s" "$keyauthorization" | _digest "sha256" "hex")" + _debug acmevalidationv1 "$acmevalidationv1" + if ! _starttlsserver "$d" "" "$Le_TLSPort" "$keyauthorization" "$_ncaddr" "$acmevalidationv1"; then + _err "Start tls server error." + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" + _clearup + _on_issue_err "$_post_hook" "$vlist" + return 1 + fi + fi + + if ! __trigger_validation "$uri" "$keyauthorization" "$vtype"; then + _err "$d:Can not get challenge: $response" + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" + _clearup + _on_issue_err "$_post_hook" "$vlist" + return 1 + fi + + if [ "$code" ] && [ "$code" != '202' ]; then + if [ "$code" = '200' ]; then + _debug "trigger validation code: $code" + else + _err "$d:Challenge error: $response" + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" + _clearup + _on_issue_err "$_post_hook" "$vlist" + return 1 + fi + fi + + waittimes=0 + if [ -z "$MAX_RETRY_TIMES" ]; then + MAX_RETRY_TIMES=30 + fi + + while true; do + waittimes=$(_math "$waittimes" + 1) + if [ "$waittimes" -ge "$MAX_RETRY_TIMES" ]; then + _err "$d:Timeout" + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" + _clearup + _on_issue_err "$_post_hook" "$vlist" + return 1 + fi + + _debug "sleep 2 secs to verify" + sleep 2 + _debug "checking" + if [ "$ACME_VERSION" = "2" ]; then + _send_signed_request "$uri" + else + response="$(_get "$uri")" + fi + if [ "$?" != "0" ]; then + _err "$d:Verify error:$response" + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" + _clearup + _on_issue_err "$_post_hook" "$vlist" + return 1 + fi + _debug2 original "$response" + + response="$(echo "$response" | _normalizeJson)" + _debug2 response "$response" + + status=$(echo "$response" | _egrep_o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"') + if [ "$status" = "valid" ]; then + _info "$(__green Success)" + _stopserver "$serverproc" + serverproc="" + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" + break + fi + + if [ "$status" = "invalid" ]; then + error="$(echo "$response" | _egrep_o '"error":\{[^\}]*')" + _debug2 error "$error" + errordetail="$(echo "$error" | _egrep_o '"detail": *"[^"]*' | cut -d '"' -f 4)" + _debug2 errordetail "$errordetail" + if [ "$errordetail" ]; then + _err "$d:Verify error:$errordetail" + else + _err "$d:Verify error:$error" + fi + if [ "$DEBUG" ]; then + if [ "$vtype" = "$VTYPE_HTTP" ]; then + _debug "Debug: get token url." + _get "http://$d/.well-known/acme-challenge/$token" "" 1 + fi + fi + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" + _clearup + _on_issue_err "$_post_hook" "$vlist" + return 1 + fi + + if [ "$status" = "pending" ]; then + _info "Pending" + elif [ "$status" = "processing" ]; then + _info "Processing" + else + _err "$d:Verify error:$response" + _clearupwebbroot "$_currentRoot" "$removelevel" "$token" + _clearup + _on_issue_err "$_post_hook" "$vlist" + return 1 + fi + + done + + done + + _clearup + _info "Verify finished, start to sign." + der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" + + if [ "$ACME_VERSION" = "2" ]; then + _info "Lets finalize the order." + _info "Le_OrderFinalize" "$Le_OrderFinalize" + if ! _send_signed_request "${Le_OrderFinalize}" "{\"csr\": \"$der\"}"; then + _err "Sign failed." + _on_issue_err "$_post_hook" + return 1 + fi + if [ "$code" != "200" ]; then + _err "Sign failed, finalize code is not 200." + _err "$response" + _on_issue_err "$_post_hook" + return 1 + fi + if [ -z "$Le_LinkOrder" ]; then + Le_LinkOrder="$(echo "$responseHeaders" | grep -i '^Location.*$' | _tail_n 1 | tr -d "\r\n \t" | cut -d ":" -f 2-)" + fi + + _savedomainconf "Le_LinkOrder" "$Le_LinkOrder" + + _link_cert_retry=0 + _MAX_CERT_RETRY=30 + while [ "$_link_cert_retry" -lt "$_MAX_CERT_RETRY" ]; do + if _contains "$response" "\"status\":\"valid\""; then + _debug "Order status is valid." + Le_LinkCert="$(echo "$response" | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)" + _debug Le_LinkCert "$Le_LinkCert" + if [ -z "$Le_LinkCert" ]; then + _err "Sign error, can not find Le_LinkCert" + _err "$response" + _on_issue_err "$_post_hook" + return 1 + fi + break + elif _contains "$response" "\"processing\""; then + _info "Order status is processing, lets sleep and retry." + _retryafter=$(echo "$responseHeaders" | grep -i "^Retry-After *:" | cut -d : -f 2 | tr -d ' ' | tr -d '\r') + _debug "_retryafter" "$_retryafter" + if [ "$_retryafter" ]; then + _info "Retry after: $_retryafter" + _sleep $_retryafter + else + _sleep 2 + fi + else + _err "Sign error, wrong status" + _err "$response" + _on_issue_err "$_post_hook" + return 1 + fi + #the order is processing, so we are going to poll order status + if [ -z "$Le_LinkOrder" ]; then + _err "Sign error, can not get order link location header" + _err "responseHeaders" "$responseHeaders" + _on_issue_err "$_post_hook" + return 1 + fi + _info "Polling order status: $Le_LinkOrder" + if ! _send_signed_request "$Le_LinkOrder"; then + _err "Sign failed, can not post to Le_LinkOrder cert:$Le_LinkOrder." + _err "$response" + _on_issue_err "$_post_hook" + return 1 + fi + _link_cert_retry="$(_math $_link_cert_retry + 1)" + done + + if [ -z "$Le_LinkCert" ]; then + _err "Sign failed, can not get Le_LinkCert, retry time limit." + _err "$response" + _on_issue_err "$_post_hook" + return 1 + fi + _info "Downloading cert." + _info "Le_LinkCert" "$Le_LinkCert" + if ! _send_signed_request "$Le_LinkCert"; then + _err "Sign failed, can not download cert:$Le_LinkCert." + _err "$response" + _on_issue_err "$_post_hook" + return 1 + fi + + echo "$response" >"$CERT_PATH" + _split_cert_chain "$CERT_PATH" "$CERT_FULLCHAIN_PATH" "$CA_CERT_PATH" + + if [ "$_preferred_chain" ] && [ -f "$CERT_FULLCHAIN_PATH" ]; then + if ! _match_issuer "$CERT_FULLCHAIN_PATH" "$_preferred_chain"; then + rels="$(echo "$responseHeaders" | tr -d ' <>' | grep -i "^link:" | grep -i 'rel="alternate"' | cut -d : -f 2- | cut -d ';' -f 1)" + _debug2 "rels" "$rels" + for rel in $rels; do + _info "Try rel: $rel" + if ! _send_signed_request "$rel"; then + _err "Sign failed, can not download cert:$rel" + _err "$response" + continue + fi + _relcert="$CERT_PATH.alt" + _relfullchain="$CERT_FULLCHAIN_PATH.alt" + _relca="$CA_CERT_PATH.alt" + echo "$response" >"$_relcert" + _split_cert_chain "$_relcert" "$_relfullchain" "$_relca" + if _match_issuer "$_relfullchain" "$_preferred_chain"; then + _info "Matched issuer in: $rel" + cat $_relcert >"$CERT_PATH" + cat $_relfullchain >"$CERT_FULLCHAIN_PATH" + cat $_relca >"$CA_CERT_PATH" + break + fi + done + fi + fi + else + if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then + _err "Sign failed. $response" + _on_issue_err "$_post_hook" + return 1 + fi + _rcert="$response" + Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _tail_n 1 | tr -d "\r\n" | cut -d " " -f 2)" + echo "$BEGIN_CERT" >"$CERT_PATH" + + #if ! _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" ; then + # _debug "Get cert failed. Let's try last response." + # printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >> "$CERT_PATH" + #fi + + if ! printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >>"$CERT_PATH"; then + _debug "Try cert link." + _get "$Le_LinkCert" | _base64 "multiline" >>"$CERT_PATH" + fi + + echo "$END_CERT" >>"$CERT_PATH" + fi + + _debug "Le_LinkCert" "$Le_LinkCert" + _savedomainconf "Le_LinkCert" "$Le_LinkCert" + + if [ -z "$Le_LinkCert" ] || ! _checkcert "$CERT_PATH"; then + response="$(echo "$response" | _dbase64 "multiline" | tr -d '\0' | _normalizeJson)" + _err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')" + _on_issue_err "$_post_hook" + return 1 + fi + + if [ "$Le_LinkCert" ]; then + _info "$(__green "Cert success.")" + cat "$CERT_PATH" + + _info "Your cert is in $(__green " $CERT_PATH ")" + + if [ -f "$CERT_KEY_PATH" ]; then + _info "Your cert key is in $(__green " $CERT_KEY_PATH ")" + fi + + if [ ! "$USER_PATH" ] || [ ! "$_ACME_IN_CRON" ]; then + USER_PATH="$PATH" + _saveaccountconf "USER_PATH" "$USER_PATH" + fi + fi + + if [ "$ACME_VERSION" = "2" ]; then + _debug "v2 chain." + else + cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH" + Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>') + + if [ "$Le_LinkIssuer" ]; then + if ! _contains "$Le_LinkIssuer" ":"; then + _info "$(__red "Relative issuer link found.")" + Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer" + fi + _debug Le_LinkIssuer "$Le_LinkIssuer" + _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" + + _link_issuer_retry=0 + _MAX_ISSUER_RETRY=5 + while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do + _debug _link_issuer_retry "$_link_issuer_retry" + if [ "$ACME_VERSION" = "2" ]; then + if _send_signed_request "$Le_LinkIssuer"; then + echo "$response" >"$CA_CERT_PATH" + break + fi + else + if _get "$Le_LinkIssuer" >"$CA_CERT_PATH.der"; then + echo "$BEGIN_CERT" >"$CA_CERT_PATH" + _base64 "multiline" <"$CA_CERT_PATH.der" >>"$CA_CERT_PATH" + echo "$END_CERT" >>"$CA_CERT_PATH" + if ! _checkcert "$CA_CERT_PATH"; then + _err "Can not get the ca cert." + break + fi + cat "$CA_CERT_PATH" >>"$CERT_FULLCHAIN_PATH" + rm -f "$CA_CERT_PATH.der" + break + fi + fi + _link_issuer_retry=$(_math $_link_issuer_retry + 1) + _sleep "$_link_issuer_retry" + done + if [ "$_link_issuer_retry" = "$_MAX_ISSUER_RETRY" ]; then + _err "Max retry for issuer ca cert is reached." + fi + else + _debug "No Le_LinkIssuer header found." + fi + fi + [ -f "$CA_CERT_PATH" ] && _info "The intermediate CA cert is in $(__green " $CA_CERT_PATH ")" + [ -f "$CERT_FULLCHAIN_PATH" ] && _info "And the full chain certs is there: $(__green " $CERT_FULLCHAIN_PATH ")" + + Le_CertCreateTime=$(_time) + _savedomainconf "Le_CertCreateTime" "$Le_CertCreateTime" + + Le_CertCreateTimeStr=$(date -u) + _savedomainconf "Le_CertCreateTimeStr" "$Le_CertCreateTimeStr" + + if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ]; then + Le_RenewalDays="$DEFAULT_RENEW" + else + _savedomainconf "Le_RenewalDays" "$Le_RenewalDays" + fi + + if [ "$CA_BUNDLE" ]; then + _saveaccountconf CA_BUNDLE "$CA_BUNDLE" + else + _clearaccountconf "CA_BUNDLE" + fi + + if [ "$CA_PATH" ]; then + _saveaccountconf CA_PATH "$CA_PATH" + else + _clearaccountconf "CA_PATH" + fi + + if [ "$HTTPS_INSECURE" ]; then + _saveaccountconf HTTPS_INSECURE "$HTTPS_INSECURE" + else + _clearaccountconf "HTTPS_INSECURE" + fi + + if [ "$Le_Listen_V4" ]; then + _savedomainconf "Le_Listen_V4" "$Le_Listen_V4" + _cleardomainconf Le_Listen_V6 + elif [ "$Le_Listen_V6" ]; then + _savedomainconf "Le_Listen_V6" "$Le_Listen_V6" + _cleardomainconf Le_Listen_V4 + fi + + if [ "$Le_ForceNewDomainKey" = "1" ]; then + _savedomainconf "Le_ForceNewDomainKey" "$Le_ForceNewDomainKey" + else + _cleardomainconf Le_ForceNewDomainKey + fi + + Le_NextRenewTime=$(_math "$Le_CertCreateTime" + "$Le_RenewalDays" \* 24 \* 60 \* 60) + + Le_NextRenewTimeStr=$(_time2str "$Le_NextRenewTime") + _savedomainconf "Le_NextRenewTimeStr" "$Le_NextRenewTimeStr" + + Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400) + _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" + + if [ "$_real_cert$_real_key$_real_ca$_reload_cmd$_real_fullchain" ]; then + _savedomainconf "Le_RealCertPath" "$_real_cert" + _savedomainconf "Le_RealCACertPath" "$_real_ca" + _savedomainconf "Le_RealKeyPath" "$_real_key" + _savedomainconf "Le_ReloadCmd" "$_reload_cmd" "base64" + _savedomainconf "Le_RealFullChainPath" "$_real_fullchain" + if ! _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd"; then + return 1 + fi + fi + + if ! _on_issue_success "$_post_hook" "$_renew_hook"; then + _err "Call hook error." + return 1 + fi +} + +#in_out_cert out_fullchain out_ca +_split_cert_chain() { + _certf="$1" + _fullchainf="$2" + _caf="$3" + if [ "$(grep -- "$BEGIN_CERT" "$_certf" | wc -l)" -gt "1" ]; then + _debug "Found cert chain" + cat "$_certf" >"$_fullchainf" + _end_n="$(grep -n -- "$END_CERT" "$_fullchainf" | _head_n 1 | cut -d : -f 1)" + _debug _end_n "$_end_n" + sed -n "1,${_end_n}p" "$_fullchainf" >"$_certf" + _end_n="$(_math $_end_n + 1)" + sed -n "${_end_n},9999p" "$_fullchainf" >"$_caf" + fi +} + +#domain [isEcc] +renew() { + Le_Domain="$1" + if [ -z "$Le_Domain" ]; then + _usage "Usage: $PROJECT_ENTRY --renew --domain [--ecc]" + return 1 + fi + + _isEcc="$2" + + _initpath "$Le_Domain" "$_isEcc" + + _info "$(__green "Renew: '$Le_Domain'")" + if [ ! -f "$DOMAIN_CONF" ]; then + _info "'$Le_Domain' is not an issued domain, skip." + return $RENEW_SKIP + fi + + if [ "$Le_RenewalDays" ]; then + _savedomainconf Le_RenewalDays "$Le_RenewalDays" + fi + + . "$DOMAIN_CONF" + _debug Le_API "$Le_API" + + if [ "$Le_API" = "$LETSENCRYPT_CA_V1" ]; then + _cleardomainconf Le_API + Le_API="$DEFAULT_CA" + fi + if [ "$Le_API" = "$LETSENCRYPT_STAGING_CA_V1" ]; then + _cleardomainconf Le_API + Le_API="$DEFAULT_STAGING_CA" + fi + + if [ "$Le_API" ]; then + export ACME_DIRECTORY="$Le_API" + #reload ca configs + ACCOUNT_KEY_PATH="" + ACCOUNT_JSON_PATH="" + CA_CONF="" + _debug3 "initpath again." + _initpath "$Le_Domain" "$_isEcc" + fi + + if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then + _info "Skip, Next renewal time is: $(__green "$Le_NextRenewTimeStr")" + _info "Add '$(__red '--force')' to force to renew." + return "$RENEW_SKIP" + fi + + if [ "$_ACME_IN_CRON" = "1" ] && [ -z "$Le_CertCreateTime" ]; then + _info "Skip invalid cert for: $Le_Domain" + return $RENEW_SKIP + fi + + _ACME_IS_RENEW="1" + Le_ReloadCmd="$(_readdomainconf Le_ReloadCmd)" + Le_PreHook="$(_readdomainconf Le_PreHook)" + Le_PostHook="$(_readdomainconf Le_PostHook)" + Le_RenewHook="$(_readdomainconf Le_RenewHook)" + Le_Preferred_Chain="$(_readdomainconf Le_Preferred_Chain)" + issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" "$Le_LocalAddress" "$Le_ChallengeAlias" "$Le_Preferred_Chain" + res="$?" + if [ "$res" != "0" ]; then + return "$res" + fi + + if [ "$Le_DeployHook" ]; then + _deploy "$Le_Domain" "$Le_DeployHook" + res="$?" + fi + + _ACME_IS_RENEW="" + + return "$res" +} + +#renewAll [stopRenewOnError] +renewAll() { + _initpath + _stopRenewOnError="$1" + _debug "_stopRenewOnError" "$_stopRenewOnError" + _ret="0" + _success_msg="" + _error_msg="" + _skipped_msg="" + _error_level=$NOTIFY_LEVEL_SKIP + _notify_code=$RENEW_SKIP + _set_level=${NOTIFY_LEVEL:-$NOTIFY_LEVEL_DEFAULT} + _debug "_set_level" "$_set_level" + for di in "${CERT_HOME}"/*.*/; do + _debug di "$di" + if ! [ -d "$di" ]; then + _debug "Not a directory, skip: $di" + continue + fi + d=$(basename "$di") + _debug d "$d" + ( + if _endswith "$d" "$ECC_SUFFIX"; then + _isEcc=$(echo "$d" | cut -d "$ECC_SEP" -f 2) + d=$(echo "$d" | cut -d "$ECC_SEP" -f 1) + fi + renew "$d" "$_isEcc" + ) + rc="$?" + _debug "Return code: $rc" + if [ "$rc" = "0" ]; then + if [ $_error_level -gt $NOTIFY_LEVEL_RENEW ]; then + _error_level="$NOTIFY_LEVEL_RENEW" + _notify_code=0 + fi + if [ "$_ACME_IN_CRON" ]; then + if [ $_set_level -ge $NOTIFY_LEVEL_RENEW ]; then + if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then + _send_notify "Renew $d success" "Good, the cert is renewed." "$NOTIFY_HOOK" 0 + fi + fi + fi + _success_msg="${_success_msg} $d +" + elif [ "$rc" = "$RENEW_SKIP" ]; then + if [ $_error_level -gt $NOTIFY_LEVEL_SKIP ]; then + _error_level="$NOTIFY_LEVEL_SKIP" + _notify_code=$RENEW_SKIP + fi + if [ "$_ACME_IN_CRON" ]; then + if [ $_set_level -ge $NOTIFY_LEVEL_SKIP ]; then + if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then + _send_notify "Renew $d skipped" "Good, the cert is skipped." "$NOTIFY_HOOK" "$RENEW_SKIP" + fi + fi + fi + _info "Skipped $d" + _skipped_msg="${_skipped_msg} $d +" + else + if [ $_error_level -gt $NOTIFY_LEVEL_ERROR ]; then + _error_level="$NOTIFY_LEVEL_ERROR" + _notify_code=1 + fi + if [ "$_ACME_IN_CRON" ]; then + if [ $_set_level -ge $NOTIFY_LEVEL_ERROR ]; then + if [ "$NOTIFY_MODE" = "$NOTIFY_MODE_CERT" ]; then + _send_notify "Renew $d error" "There is an error." "$NOTIFY_HOOK" 1 + fi + fi + fi + _error_msg="${_error_msg} $d +" + if [ "$_stopRenewOnError" ]; then + _err "Error renew $d, stop now." + _ret="$rc" + break + else + _ret="$rc" + _err "Error renew $d." + fi + fi + done + _debug _error_level "$_error_level" + _debug _set_level "$_set_level" + if [ "$_ACME_IN_CRON" ] && [ $_error_level -le $_set_level ]; then + if [ -z "$NOTIFY_MODE" ] || [ "$NOTIFY_MODE" = "$NOTIFY_MODE_BULK" ]; then + _msg_subject="Renew" + if [ "$_error_msg" ]; then + _msg_subject="${_msg_subject} Error" + _msg_data="Error certs: +${_error_msg} +" + fi + if [ "$_success_msg" ]; then + _msg_subject="${_msg_subject} Success" + _msg_data="${_msg_data}Success certs: +${_success_msg} +" + fi + if [ "$_skipped_msg" ]; then + _msg_subject="${_msg_subject} Skipped" + _msg_data="${_msg_data}Skipped certs: +${_skipped_msg} +" + fi + + _send_notify "$_msg_subject" "$_msg_data" "$NOTIFY_HOOK" "$_notify_code" + fi + fi + + return "$_ret" +} + +#csr webroot +signcsr() { + _csrfile="$1" + _csrW="$2" + if [ -z "$_csrfile" ] || [ -z "$_csrW" ]; then + _usage "Usage: $PROJECT_ENTRY --sign-csr --csr --webroot " + return 1 + fi + + _real_cert="$3" + _real_key="$4" + _real_ca="$5" + _reload_cmd="$6" + _real_fullchain="$7" + _pre_hook="${8}" + _post_hook="${9}" + _renew_hook="${10}" + _local_addr="${11}" + _challenge_alias="${12}" + + _csrsubj=$(_readSubjectFromCSR "$_csrfile") + if [ "$?" != "0" ]; then + _err "Can not read subject from csr: $_csrfile" + return 1 + fi + _debug _csrsubj "$_csrsubj" + if _contains "$_csrsubj" ' ' || ! _contains "$_csrsubj" '.'; then + _info "It seems that the subject: $_csrsubj is not a valid domain name. Drop it." + _csrsubj="" + fi + + _csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile") + if [ "$?" != "0" ]; then + _err "Can not read domain list from csr: $_csrfile" + return 1 + fi + _debug "_csrdomainlist" "$_csrdomainlist" + + if [ -z "$_csrsubj" ]; then + _csrsubj="$(_getfield "$_csrdomainlist" 1)" + _debug _csrsubj "$_csrsubj" + _csrdomainlist="$(echo "$_csrdomainlist" | cut -d , -f 2-)" + _debug "_csrdomainlist" "$_csrdomainlist" + fi + + if [ -z "$_csrsubj" ]; then + _err "Can not read subject from csr: $_csrfile" + return 1 + fi + + _csrkeylength=$(_readKeyLengthFromCSR "$_csrfile") + if [ "$?" != "0" ] || [ -z "$_csrkeylength" ]; then + _err "Can not read key length from csr: $_csrfile" + return 1 + fi + + if [ -z "$ACME_VERSION" ] && _contains "$_csrsubj,$_csrdomainlist" "*."; then + export ACME_VERSION=2 + fi + _initpath "$_csrsubj" "$_csrkeylength" + mkdir -p "$DOMAIN_PATH" + + _info "Copy csr to: $CSR_PATH" + cp "$_csrfile" "$CSR_PATH" + + issue "$_csrW" "$_csrsubj" "$_csrdomainlist" "$_csrkeylength" "$_real_cert" "$_real_key" "$_real_ca" "$_reload_cmd" "$_real_fullchain" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_addr" "$_challenge_alias" + +} + +showcsr() { + _csrfile="$1" + _csrd="$2" + if [ -z "$_csrfile" ] && [ -z "$_csrd" ]; then + _usage "Usage: $PROJECT_ENTRY --show-csr --csr " + return 1 + fi + + _initpath + + _csrsubj=$(_readSubjectFromCSR "$_csrfile") + if [ "$?" != "0" ] || [ -z "$_csrsubj" ]; then + _err "Can not read subject from csr: $_csrfile" + return 1 + fi + + _info "Subject=$_csrsubj" + + _csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile") + if [ "$?" != "0" ]; then + _err "Can not read domain list from csr: $_csrfile" + return 1 + fi + _debug "_csrdomainlist" "$_csrdomainlist" + + _info "SubjectAltNames=$_csrdomainlist" + + _csrkeylength=$(_readKeyLengthFromCSR "$_csrfile") + if [ "$?" != "0" ] || [ -z "$_csrkeylength" ]; then + _err "Can not read key length from csr: $_csrfile" + return 1 + fi + _info "KeyLength=$_csrkeylength" +} + +#listraw domain +list() { + _raw="$1" + _domain="$2" + _initpath + + _sep="|" + if [ "$_raw" ]; then + if [ -z "$_domain" ]; then + printf "%s\n" "Main_Domain${_sep}KeyLength${_sep}SAN_Domains${_sep}CA${_sep}Created${_sep}Renew" + fi + for di in "${CERT_HOME}"/*.*/; do + d=$(basename "$di") + _debug d "$d" + ( + if _endswith "$d" "$ECC_SUFFIX"; then + _isEcc="ecc" + d=$(echo "$d" | cut -d "$ECC_SEP" -f 1) + fi + DOMAIN_CONF="$di/$d.conf" + if [ -f "$DOMAIN_CONF" ]; then + . "$DOMAIN_CONF" + _ca="$(_getCAShortName "$Le_API")" + if [ -z "$_domain" ]; then + printf "%s\n" "$Le_Domain${_sep}\"$Le_Keylength\"${_sep}$Le_Alt${_sep}$_ca${_sep}$Le_CertCreateTimeStr${_sep}$Le_NextRenewTimeStr" + else + if [ "$_domain" = "$d" ]; then + cat "$DOMAIN_CONF" + fi + fi + fi + ) + done + else + if _exists column; then + list "raw" "$_domain" | column -t -s "$_sep" + else + list "raw" "$_domain" | tr "$_sep" '\t' + fi + fi + +} + +_deploy() { + _d="$1" + _hooks="$2" + + for _d_api in $(echo "$_hooks" | tr ',' " "); do + _deployApi="$(_findHook "$_d" $_SUB_FOLDER_DEPLOY "$_d_api")" + if [ -z "$_deployApi" ]; then + _err "The deploy hook $_d_api is not found." + return 1 + fi + _debug _deployApi "$_deployApi" + + if ! ( + if ! . "$_deployApi"; then + _err "Load file $_deployApi error. Please check your api file and try again." + return 1 + fi + + d_command="${_d_api}_deploy" + if ! _exists "$d_command"; then + _err "It seems that your api file is not correct, it must have a function named: $d_command" + return 1 + fi + + if ! $d_command "$_d" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH"; then + _err "Error deploy for domain:$_d" + return 1 + fi + ); then + _err "Deploy error." + return 1 + else + _info "$(__green Success)" + fi + done +} + +#domain hooks +deploy() { + _d="$1" + _hooks="$2" + _isEcc="$3" + if [ -z "$_hooks" ]; then + _usage "Usage: $PROJECT_ENTRY --deploy --domain --deploy-hook [--ecc] " + return 1 + fi + + _initpath "$_d" "$_isEcc" + if [ ! -d "$DOMAIN_PATH" ]; then + _err "The domain '$_d' is not a cert name. You must use the cert name to specify the cert to install." + _err "Can not find path:'$DOMAIN_PATH'" + return 1 + fi + + . "$DOMAIN_CONF" + + _savedomainconf Le_DeployHook "$_hooks" + + _deploy "$_d" "$_hooks" +} + +installcert() { + _main_domain="$1" + if [ -z "$_main_domain" ]; then + _usage "Usage: $PROJECT_ENTRY --install-cert --domain [--ecc] [--cert-file ] [--key-file ] [--ca-file ] [ --reloadcmd ] [--fullchain-file ]" + return 1 + fi + + _real_cert="$2" + _real_key="$3" + _real_ca="$4" + _reload_cmd="$5" + _real_fullchain="$6" + _isEcc="$7" + + _initpath "$_main_domain" "$_isEcc" + if [ ! -d "$DOMAIN_PATH" ]; then + _err "The domain '$_main_domain' is not a cert name. You must use the cert name to specify the cert to install." + _err "Can not find path:'$DOMAIN_PATH'" + return 1 + fi + + _savedomainconf "Le_RealCertPath" "$_real_cert" + _savedomainconf "Le_RealCACertPath" "$_real_ca" + _savedomainconf "Le_RealKeyPath" "$_real_key" + _savedomainconf "Le_ReloadCmd" "$_reload_cmd" "base64" + _savedomainconf "Le_RealFullChainPath" "$_real_fullchain" + + _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd" +} + +#domain cert key ca fullchain reloadcmd backup-prefix +_installcert() { + _main_domain="$1" + _real_cert="$2" + _real_key="$3" + _real_ca="$4" + _real_fullchain="$5" + _reload_cmd="$6" + _backup_prefix="$7" + + if [ "$_real_cert" = "$NO_VALUE" ]; then + _real_cert="" + fi + if [ "$_real_key" = "$NO_VALUE" ]; then + _real_key="" + fi + if [ "$_real_ca" = "$NO_VALUE" ]; then + _real_ca="" + fi + if [ "$_reload_cmd" = "$NO_VALUE" ]; then + _reload_cmd="" + fi + if [ "$_real_fullchain" = "$NO_VALUE" ]; then + _real_fullchain="" + fi + + _backup_path="$DOMAIN_BACKUP_PATH/$_backup_prefix" + mkdir -p "$_backup_path" + + if [ "$_real_cert" ]; then + _info "Installing cert to:$_real_cert" + if [ -f "$_real_cert" ] && [ ! "$_ACME_IS_RENEW" ]; then + cp "$_real_cert" "$_backup_path/cert.bak" + fi + cat "$CERT_PATH" >"$_real_cert" || return 1 + fi + + if [ "$_real_ca" ]; then + _info "Installing CA to:$_real_ca" + if [ "$_real_ca" = "$_real_cert" ]; then + echo "" >>"$_real_ca" + cat "$CA_CERT_PATH" >>"$_real_ca" || return 1 + else + if [ -f "$_real_ca" ] && [ ! "$_ACME_IS_RENEW" ]; then + cp "$_real_ca" "$_backup_path/ca.bak" + fi + cat "$CA_CERT_PATH" >"$_real_ca" || return 1 + fi + fi + + if [ "$_real_key" ]; then + _info "Installing key to:$_real_key" + if [ -f "$_real_key" ] && [ ! "$_ACME_IS_RENEW" ]; then + cp "$_real_key" "$_backup_path/key.bak" + fi + if [ -f "$_real_key" ]; then + cat "$CERT_KEY_PATH" >"$_real_key" || return 1 + else + cat "$CERT_KEY_PATH" >"$_real_key" || return 1 + chmod 600 "$_real_key" + fi + fi + + if [ "$_real_fullchain" ]; then + _info "Installing full chain to:$_real_fullchain" + if [ -f "$_real_fullchain" ] && [ ! "$_ACME_IS_RENEW" ]; then + cp "$_real_fullchain" "$_backup_path/fullchain.bak" + fi + cat "$CERT_FULLCHAIN_PATH" >"$_real_fullchain" || return 1 + fi + + if [ "$_reload_cmd" ]; then + _info "Run reload cmd: $_reload_cmd" + if ( + export CERT_PATH + export CERT_KEY_PATH + export CA_CERT_PATH + export CERT_FULLCHAIN_PATH + export Le_Domain="$_main_domain" + cd "$DOMAIN_PATH" && eval "$_reload_cmd" + ); then + _info "$(__green "Reload success")" + else + _err "Reload error for :$Le_Domain" + fi + fi + +} + +__read_password() { + unset _pp + prompt="Enter Password:" + while IFS= read -p "$prompt" -r -s -n 1 char; do + if [ "$char" = $'\0' ]; then + break + fi + prompt='*' + _pp="$_pp$char" + done + echo "$_pp" +} + +_install_win_taskscheduler() { + _lesh="$1" + _centry="$2" + _randomminute="$3" + if ! _exists cygpath; then + _err "cygpath not found" + return 1 + fi + if ! _exists schtasks; then + _err "schtasks.exe is not found, are you on Windows?" + return 1 + fi + _winbash="$(cygpath -w $(which bash))" + _debug _winbash "$_winbash" + if [ -z "$_winbash" ]; then + _err "can not find bash path" + return 1 + fi + _myname="$(whoami)" + _debug "_myname" "$_myname" + if [ -z "$_myname" ]; then + _err "can not find my user name" + return 1 + fi + _debug "_lesh" "$_lesh" + + _info "To install scheduler task in your Windows account, you must input your windows password." + _info "$PROJECT_NAME doesn't save your password." + _info "Please input your Windows password for: $(__green "$_myname")" + _password="$(__read_password)" + #SCHTASKS.exe '/create' '/SC' 'DAILY' '/TN' "$_WINDOWS_SCHEDULER_NAME" '/F' '/ST' "00:$_randomminute" '/RU' "$_myname" '/RP' "$_password" '/TR' "$_winbash -l -c '$_lesh --cron --home \"$LE_WORKING_DIR\" $_centry'" >/dev/null + echo SCHTASKS.exe '/create' '/SC' 'DAILY' '/TN' "$_WINDOWS_SCHEDULER_NAME" '/F' '/ST' "00:$_randomminute" '/RU' "$_myname" '/RP' "$_password" '/TR' "\"$_winbash -l -c '$_lesh --cron --home \"$LE_WORKING_DIR\" $_centry'\"" | cmd.exe >/dev/null + echo + +} + +_uninstall_win_taskscheduler() { + if ! _exists schtasks; then + _err "schtasks.exe is not found, are you on Windows?" + return 1 + fi + if ! echo SCHTASKS /query /tn "$_WINDOWS_SCHEDULER_NAME" | cmd.exe >/dev/null; then + _debug "scheduler $_WINDOWS_SCHEDULER_NAME is not found." + else + _info "Removing $_WINDOWS_SCHEDULER_NAME" + echo SCHTASKS /delete /f /tn "$_WINDOWS_SCHEDULER_NAME" | cmd.exe >/dev/null + fi +} + +#confighome +installcronjob() { + _c_home="$1" + _initpath + _CRONTAB="crontab" + if [ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ]; then + lesh="\"$LE_WORKING_DIR\"/$PROJECT_ENTRY" + else + _err "Can not install cronjob, $PROJECT_ENTRY not found." + return 1 + fi + if [ "$_c_home" ]; then + _c_entry="--config-home \"$_c_home\" " + fi + _t=$(_time) + random_minute=$(_math $_t % 60) + + if ! _exists "$_CRONTAB" && _exists "fcrontab"; then + _CRONTAB="fcrontab" + fi + + if ! _exists "$_CRONTAB"; then + if _exists cygpath && _exists schtasks.exe; then + _info "It seems you are on Windows, let's install Windows scheduler task." + if _install_win_taskscheduler "$lesh" "$_c_entry" "$random_minute"; then + _info "Install Windows scheduler task success." + return 0 + else + _err "Install Windows scheduler task failed." + return 1 + fi + fi + _err "crontab/fcrontab doesn't exist, so, we can not install cron jobs." + _err "All your certs will not be renewed automatically." + _err "You must add your own cron job to call '$PROJECT_ENTRY --cron' everyday." + return 1 + fi + _info "Installing cron job" + if ! $_CRONTAB -l | grep "$PROJECT_ENTRY --cron"; then + if _exists uname && uname -a | grep SunOS >/dev/null; then + $_CRONTAB -l | { + cat + echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null" + } | $_CRONTAB -- + else + $_CRONTAB -l | { + cat + echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null" + } | $_CRONTAB - + fi + fi + if [ "$?" != "0" ]; then + _err "Install cron job failed. You need to manually renew your certs." + _err "Or you can add cronjob by yourself:" + _err "$lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null" + return 1 + fi +} + +uninstallcronjob() { + _CRONTAB="crontab" + if ! _exists "$_CRONTAB" && _exists "fcrontab"; then + _CRONTAB="fcrontab" + fi + + if ! _exists "$_CRONTAB"; then + if _exists cygpath && _exists schtasks.exe; then + _info "It seems you are on Windows, let's uninstall Windows scheduler task." + if _uninstall_win_taskscheduler; then + _info "Uninstall Windows scheduler task success." + return 0 + else + _err "Uninstall Windows scheduler task failed." + return 1 + fi + fi + return + fi + _info "Removing cron job" + cr="$($_CRONTAB -l | grep "$PROJECT_ENTRY --cron")" + if [ "$cr" ]; then + if _exists uname && uname -a | grep solaris >/dev/null; then + $_CRONTAB -l | sed "/$PROJECT_ENTRY --cron/d" | $_CRONTAB -- + else + $_CRONTAB -l | sed "/$PROJECT_ENTRY --cron/d" | $_CRONTAB - + fi + LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 9 | tr -d '"')" + _info LE_WORKING_DIR "$LE_WORKING_DIR" + if _contains "$cr" "--config-home"; then + LE_CONFIG_HOME="$(echo "$cr" | cut -d ' ' -f 11 | tr -d '"')" + _debug LE_CONFIG_HOME "$LE_CONFIG_HOME" + fi + fi + _initpath + +} + +#domain isECC revokeReason +revoke() { + Le_Domain="$1" + if [ -z "$Le_Domain" ]; then + _usage "Usage: $PROJECT_ENTRY --revoke --domain [--ecc]" + return 1 + fi + + _isEcc="$2" + _reason="$3" + if [ -z "$_reason" ]; then + _reason="0" + fi + _initpath "$Le_Domain" "$_isEcc" + if [ ! -f "$DOMAIN_CONF" ]; then + _err "$Le_Domain is not a issued domain, skip." + return 1 + fi + + if [ ! -f "$CERT_PATH" ]; then + _err "Cert for $Le_Domain $CERT_PATH is not found, skip." + return 1 + fi + + cert="$(_getfile "${CERT_PATH}" "${BEGIN_CERT}" "${END_CERT}" | tr -d "\r\n" | _url_replace)" + + if [ -z "$cert" ]; then + _err "Cert for $Le_Domain is empty found, skip." + return 1 + fi + + _initAPI + + if [ "$ACME_VERSION" = "2" ]; then + data="{\"certificate\": \"$cert\",\"reason\":$_reason}" + else + data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}" + fi + uri="${ACME_REVOKE_CERT}" + + if [ -f "$CERT_KEY_PATH" ]; then + _info "Try domain key first." + if _send_signed_request "$uri" "$data" "" "$CERT_KEY_PATH"; then + if [ -z "$response" ]; then + _info "Revoke success." + rm -f "$CERT_PATH" + return 0 + else + _err "Revoke error by domain key." + _err "$response" + fi + fi + else + _info "Domain key file doesn't exist." + fi + + _info "Try account key." + + if _send_signed_request "$uri" "$data" "" "$ACCOUNT_KEY_PATH"; then + if [ -z "$response" ]; then + _info "Revoke success." + rm -f "$CERT_PATH" + return 0 + else + _err "Revoke error." + _debug "$response" + fi + fi + return 1 +} + +#domain ecc +remove() { + Le_Domain="$1" + if [ -z "$Le_Domain" ]; then + _usage "Usage: $PROJECT_ENTRY --remove --domain [--ecc]" + return 1 + fi + + _isEcc="$2" + + _initpath "$Le_Domain" "$_isEcc" + _removed_conf="$DOMAIN_CONF.removed" + if [ ! -f "$DOMAIN_CONF" ]; then + if [ -f "$_removed_conf" ]; then + _err "$Le_Domain is already removed, You can remove the folder by yourself: $DOMAIN_PATH" + else + _err "$Le_Domain is not a issued domain, skip." + fi + return 1 + fi + + if mv "$DOMAIN_CONF" "$_removed_conf"; then + _info "$Le_Domain is removed, the key and cert files are in $(__green $DOMAIN_PATH)" + _info "You can remove them by yourself." + return 0 + else + _err "Remove $Le_Domain failed." + return 1 + fi +} + +#domain vtype +_deactivate() { + _d_domain="$1" + _d_type="$2" + _initpath + + if [ "$ACME_VERSION" = "2" ]; then + _identifiers="{\"type\":\"dns\",\"value\":\"$_d_domain\"}" + if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then + _err "Can not get domain new order." + return 1 + fi + _authorizations_seg="$(echo "$response" | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')" + _debug2 _authorizations_seg "$_authorizations_seg" + if [ -z "$_authorizations_seg" ]; then + _err "_authorizations_seg not found." + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + + authzUri="$_authorizations_seg" + _debug2 "authzUri" "$authzUri" + if ! _send_signed_request "$authzUri"; then + _err "get to authz error." + _err "_authorizations_seg" "$_authorizations_seg" + _err "authzUri" "$authzUri" + _clearup + _on_issue_err "$_post_hook" + return 1 + fi + + response="$(echo "$response" | _normalizeJson)" + _debug2 response "$response" + _URL_NAME="url" + else + if ! __get_domain_new_authz "$_d_domain"; then + _err "Can not get domain new authz token." + return 1 + fi + + authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ':' -f 2- | tr -d "\r\n")" + _debug "authzUri" "$authzUri" + if [ "$code" ] && [ ! "$code" = '201' ]; then + _err "new-authz error: $response" + return 1 + fi + _URL_NAME="uri" + fi + + entries="$(echo "$response" | tr '][' '==' | _egrep_o "challenges\": *=[^=]*=" | tr '}{' '\n' | grep "\"status\": *\"valid\"")" + if [ -z "$entries" ]; then + _info "No valid entries found." + if [ -z "$thumbprint" ]; then + thumbprint="$(__calc_account_thumbprint)" + fi + _debug "Trigger validation." + vtype="$VTYPE_DNS" + entry="$(echo "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" + _debug entry "$entry" + if [ -z "$entry" ]; then + _err "Error, can not get domain token $d" + return 1 + fi + token="$(echo "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')" + _debug token "$token" + + uri="$(echo "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*" | cut -d : -f 2,3 | tr -d '"')" + _debug uri "$uri" + + keyauthorization="$token.$thumbprint" + _debug keyauthorization "$keyauthorization" + __trigger_validation "$uri" "$keyauthorization" + + fi + + _d_i=0 + _d_max_retry=$(echo "$entries" | wc -l) + while [ "$_d_i" -lt "$_d_max_retry" ]; do + _info "Deactivate: $_d_domain" + _d_i="$(_math $_d_i + 1)" + entry="$(echo "$entries" | sed -n "${_d_i}p")" + _debug entry "$entry" + + if [ -z "$entry" ]; then + _info "No more valid entry found." + break + fi + + _vtype="$(echo "$entry" | _egrep_o '"type": *"[^"]*"' | cut -d : -f 2 | tr -d '"')" + _debug _vtype "$_vtype" + _info "Found $_vtype" + + uri="$(echo "$entry" | _egrep_o "\"$_URL_NAME\":\"[^\"]*\"" | tr -d '" ' | cut -d : -f 2-)" + _debug uri "$uri" + + if [ "$_d_type" ] && [ "$_d_type" != "$_vtype" ]; then + _info "Skip $_vtype" + continue + fi + + _info "Deactivate: $_vtype" + + if [ "$ACME_VERSION" = "2" ]; then + _djson="{\"status\":\"deactivated\"}" + else + _djson="{\"resource\": \"authz\", \"status\":\"deactivated\"}" + fi + + if _send_signed_request "$authzUri" "$_djson" && _contains "$response" '"deactivated"'; then + _info "Deactivate: $_vtype success." + else + _err "Can not deactivate $_vtype." + break + fi + + done + _debug "$_d_i" + if [ "$_d_i" -eq "$_d_max_retry" ]; then + _info "Deactivated success!" + else + _err "Deactivate failed." + fi + +} + +deactivate() { + _d_domain_list="$1" + _d_type="$2" + _initpath + _initAPI + _debug _d_domain_list "$_d_domain_list" + if [ -z "$(echo $_d_domain_list | cut -d , -f 1)" ]; then + _usage "Usage: $PROJECT_ENTRY --deactivate --domain [--domain ...]" + return 1 + fi + for _d_dm in $(echo "$_d_domain_list" | tr ',' ' '); do + if [ -z "$_d_dm" ] || [ "$_d_dm" = "$NO_VALUE" ]; then + continue + fi + if ! _deactivate "$_d_dm" "$_d_type"; then + return 1 + fi + done +} + +# Detect profile file if not specified as environment variable +_detect_profile() { + if [ -n "$PROFILE" -a -f "$PROFILE" ]; then + echo "$PROFILE" + return + fi + + DETECTED_PROFILE='' + SHELLTYPE="$(basename "/$SHELL")" + + if [ "$SHELLTYPE" = "bash" ]; then + if [ -f "$HOME/.bashrc" ]; then + DETECTED_PROFILE="$HOME/.bashrc" + elif [ -f "$HOME/.bash_profile" ]; then + DETECTED_PROFILE="$HOME/.bash_profile" + fi + elif [ "$SHELLTYPE" = "zsh" ]; then + DETECTED_PROFILE="$HOME/.zshrc" + fi + + if [ -z "$DETECTED_PROFILE" ]; then + if [ -f "$HOME/.profile" ]; then + DETECTED_PROFILE="$HOME/.profile" + elif [ -f "$HOME/.bashrc" ]; then + DETECTED_PROFILE="$HOME/.bashrc" + elif [ -f "$HOME/.bash_profile" ]; then + DETECTED_PROFILE="$HOME/.bash_profile" + elif [ -f "$HOME/.zshrc" ]; then + DETECTED_PROFILE="$HOME/.zshrc" + fi + fi + + echo "$DETECTED_PROFILE" +} + +_initconf() { + _initpath + if [ ! -f "$ACCOUNT_CONF_PATH" ]; then + echo " + +#LOG_FILE=\"$DEFAULT_LOG_FILE\" +#LOG_LEVEL=1 + +#AUTO_UPGRADE=\"1\" + +#NO_TIMESTAMP=1 + + " >"$ACCOUNT_CONF_PATH" + fi +} + +# nocron +_precheck() { + _nocron="$1" + + if ! _exists "curl" && ! _exists "wget"; then + _err "Please install curl or wget first, we need to access http resources." + return 1 + fi + + if [ -z "$_nocron" ]; then + if ! _exists "crontab" && ! _exists "fcrontab"; then + if _exists cygpath && _exists schtasks.exe; then + _info "It seems you are on Windows, we will install Windows scheduler task." + else + _err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'." + _err "We need to set cron job to renew the certs automatically." + _err "Otherwise, your certs will not be able to be renewed automatically." + if [ -z "$FORCE" ]; then + _err "Please add '--force' and try install again to go without crontab." + _err "./$PROJECT_ENTRY --install --force" + return 1 + fi + fi + fi + fi + + if ! _exists "${ACME_OPENSSL_BIN:-openssl}"; then + _err "Please install openssl first. ACME_OPENSSL_BIN=$ACME_OPENSSL_BIN" + _err "We need openssl to generate keys." + return 1 + fi + + if ! _exists "socat"; then + _err "It is recommended to install socat first." + _err "We use socat for standalone server if you use standalone mode." + _err "If you don't use standalone mode, just ignore this warning." + fi + + return 0 +} + +_setShebang() { + _file="$1" + _shebang="$2" + if [ -z "$_shebang" ]; then + _usage "Usage: file shebang" + return 1 + fi + cp "$_file" "$_file.tmp" + echo "$_shebang" >"$_file" + sed -n 2,99999p "$_file.tmp" >>"$_file" + rm -f "$_file.tmp" +} + +#confighome +_installalias() { + _c_home="$1" + _initpath + + _envfile="$LE_WORKING_DIR/$PROJECT_ENTRY.env" + if [ "$_upgrading" ] && [ "$_upgrading" = "1" ]; then + echo "$(cat "$_envfile")" | sed "s|^LE_WORKING_DIR.*$||" >"$_envfile" + echo "$(cat "$_envfile")" | sed "s|^alias le.*$||" >"$_envfile" + echo "$(cat "$_envfile")" | sed "s|^alias le.sh.*$||" >"$_envfile" + fi + + if [ "$_c_home" ]; then + _c_entry=" --config-home '$_c_home'" + fi + + _setopt "$_envfile" "export LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\"" + if [ "$_c_home" ]; then + _setopt "$_envfile" "export LE_CONFIG_HOME" "=" "\"$LE_CONFIG_HOME\"" + else + _sed_i "/^export LE_CONFIG_HOME/d" "$_envfile" + fi + _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\"" + + _profile="$(_detect_profile)" + if [ "$_profile" ]; then + _debug "Found profile: $_profile" + _info "Installing alias to '$_profile'" + _setopt "$_profile" ". \"$_envfile\"" + _info "OK, Close and reopen your terminal to start using $PROJECT_NAME" + else + _info "No profile is found, you will need to go into $LE_WORKING_DIR to use $PROJECT_NAME" + fi + + #for csh + _cshfile="$LE_WORKING_DIR/$PROJECT_ENTRY.csh" + _csh_profile="$HOME/.cshrc" + if [ -f "$_csh_profile" ]; then + _info "Installing alias to '$_csh_profile'" + _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" + if [ "$_c_home" ]; then + _setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\"" + else + _sed_i "/^setenv LE_CONFIG_HOME/d" "$_cshfile" + fi + _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\"" + _setopt "$_csh_profile" "source \"$_cshfile\"" + fi + + #for tcsh + _tcsh_profile="$HOME/.tcshrc" + if [ -f "$_tcsh_profile" ]; then + _info "Installing alias to '$_tcsh_profile'" + _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\"" + if [ "$_c_home" ]; then + _setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\"" + fi + _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\"" + _setopt "$_tcsh_profile" "source \"$_cshfile\"" + fi + +} + +# nocron confighome noprofile +install() { + + if [ -z "$LE_WORKING_DIR" ]; then + LE_WORKING_DIR="$DEFAULT_INSTALL_HOME" + fi + + _nocron="$1" + _c_home="$2" + _noprofile="$3" + if ! _initpath; then + _err "Install failed." + return 1 + fi + if [ "$_nocron" ]; then + _debug "Skip install cron job" + fi + + if [ "$_ACME_IN_CRON" != "1" ]; then + if ! _precheck "$_nocron"; then + _err "Pre-check failed, can not install." + return 1 + fi + fi + + if [ -z "$_c_home" ] && [ "$LE_CONFIG_HOME" != "$LE_WORKING_DIR" ]; then + _info "Using config home: $LE_CONFIG_HOME" + _c_home="$LE_CONFIG_HOME" + fi + + #convert from le + if [ -d "$HOME/.le" ]; then + for envfile in "le.env" "le.sh.env"; do + if [ -f "$HOME/.le/$envfile" ]; then + if grep "le.sh" "$HOME/.le/$envfile" >/dev/null; then + _upgrading="1" + _info "You are upgrading from le.sh" + _info "Renaming \"$HOME/.le\" to $LE_WORKING_DIR" + mv "$HOME/.le" "$LE_WORKING_DIR" + mv "$LE_WORKING_DIR/$envfile" "$LE_WORKING_DIR/$PROJECT_ENTRY.env" + break + fi + fi + done + fi + + _info "Installing to $LE_WORKING_DIR" + + if [ ! -d "$LE_WORKING_DIR" ]; then + if ! mkdir -p "$LE_WORKING_DIR"; then + _err "Can not create working dir: $LE_WORKING_DIR" + return 1 + fi + + chmod 700 "$LE_WORKING_DIR" + fi + + if [ ! -d "$LE_CONFIG_HOME" ]; then + if ! mkdir -p "$LE_CONFIG_HOME"; then + _err "Can not create config dir: $LE_CONFIG_HOME" + return 1 + fi + + chmod 700 "$LE_CONFIG_HOME" + fi + + cp "$PROJECT_ENTRY" "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY" + + if [ "$?" != "0" ]; then + _err "Install failed, can not copy $PROJECT_ENTRY" + return 1 + fi + + _info "Installed to $LE_WORKING_DIR/$PROJECT_ENTRY" + + if [ "$_ACME_IN_CRON" != "1" ] && [ -z "$_noprofile" ]; then + _installalias "$_c_home" + fi + + for subf in $_SUB_FOLDERS; do + if [ -d "$subf" ]; then + mkdir -p "$LE_WORKING_DIR/$subf" + cp "$subf"/* "$LE_WORKING_DIR"/"$subf"/ + fi + done + + if [ ! -f "$ACCOUNT_CONF_PATH" ]; then + _initconf + fi + + if [ "$_DEFAULT_ACCOUNT_CONF_PATH" != "$ACCOUNT_CONF_PATH" ]; then + _setopt "$_DEFAULT_ACCOUNT_CONF_PATH" "ACCOUNT_CONF_PATH" "=" "\"$ACCOUNT_CONF_PATH\"" + fi + + if [ "$_DEFAULT_CERT_HOME" != "$CERT_HOME" ]; then + _saveaccountconf "CERT_HOME" "$CERT_HOME" + fi + + if [ "$_DEFAULT_ACCOUNT_KEY_PATH" != "$ACCOUNT_KEY_PATH" ]; then + _saveaccountconf "ACCOUNT_KEY_PATH" "$ACCOUNT_KEY_PATH" + fi + + if [ -z "$_nocron" ]; then + installcronjob "$_c_home" + fi + + if [ -z "$NO_DETECT_SH" ]; then + #Modify shebang + if _exists bash; then + _bash_path="$(bash -c "command -v bash 2>/dev/null")" + if [ -z "$_bash_path" ]; then + _bash_path="$(bash -c 'echo $SHELL')" + fi + fi + if [ "$_bash_path" ]; then + _info "Good, bash is found, so change the shebang to use bash as preferred." + _shebang='#!'"$_bash_path" + _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang" + for subf in $_SUB_FOLDERS; do + if [ -d "$LE_WORKING_DIR/$subf" ]; then + for _apifile in "$LE_WORKING_DIR/$subf/"*.sh; do + _setShebang "$_apifile" "$_shebang" + done + fi + done + fi + fi + + _info OK +} + +# nocron +uninstall() { + _nocron="$1" + if [ -z "$_nocron" ]; then + uninstallcronjob + fi + _initpath + + _uninstallalias + + rm -f "$LE_WORKING_DIR/$PROJECT_ENTRY" + _info "The keys and certs are in \"$(__green "$LE_CONFIG_HOME")\", you can remove them by yourself." + +} + +_uninstallalias() { + _initpath + + _profile="$(_detect_profile)" + if [ "$_profile" ]; then + _info "Uninstalling alias from: '$_profile'" + text="$(cat "$_profile")" + echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.env\"$||" >"$_profile" + fi + + _csh_profile="$HOME/.cshrc" + if [ -f "$_csh_profile" ]; then + _info "Uninstalling alias from: '$_csh_profile'" + text="$(cat "$_csh_profile")" + echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" >"$_csh_profile" + fi + + _tcsh_profile="$HOME/.tcshrc" + if [ -f "$_tcsh_profile" ]; then + _info "Uninstalling alias from: '$_csh_profile'" + text="$(cat "$_tcsh_profile")" + echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" >"$_tcsh_profile" + fi + +} + +cron() { + export _ACME_IN_CRON=1 + _initpath + _info "$(__green "===Starting cron===")" + if [ "$AUTO_UPGRADE" = "1" ]; then + export LE_WORKING_DIR + ( + if ! upgrade; then + _err "Cron:Upgrade failed!" + return 1 + fi + ) + . "$LE_WORKING_DIR/$PROJECT_ENTRY" >/dev/null + + if [ -t 1 ]; then + __INTERACTIVE="1" + fi + + _info "Auto upgraded to: $VER" + fi + renewAll + _ret="$?" + _ACME_IN_CRON="" + _info "$(__green "===End cron===")" + exit $_ret +} + +version() { + echo "$PROJECT" + echo "v$VER" +} + +# subject content hooks code +_send_notify() { + _nsubject="$1" + _ncontent="$2" + _nhooks="$3" + _nerror="$4" + + if [ "$NOTIFY_LEVEL" = "$NOTIFY_LEVEL_DISABLE" ]; then + _debug "The NOTIFY_LEVEL is $NOTIFY_LEVEL, disabled, just return." + return 0 + fi + + if [ -z "$_nhooks" ]; then + _debug "The NOTIFY_HOOK is empty, just return." + return 0 + fi + + _send_err=0 + for _n_hook in $(echo "$_nhooks" | tr ',' " "); do + _n_hook_file="$(_findHook "" $_SUB_FOLDER_NOTIFY "$_n_hook")" + _info "Sending via: $_n_hook" + _debug "Found $_n_hook_file for $_n_hook" + if [ -z "$_n_hook_file" ]; then + _err "Can not find the hook file for $_n_hook" + continue + fi + if ! ( + if ! . "$_n_hook_file"; then + _err "Load file $_n_hook_file error. Please check your api file and try again." + return 1 + fi + + d_command="${_n_hook}_send" + if ! _exists "$d_command"; then + _err "It seems that your api file is not correct, it must have a function named: $d_command" + return 1 + fi + + if ! $d_command "$_nsubject" "$_ncontent" "$_nerror"; then + _err "Error send message by $d_command" + return 1 + fi + + return 0 + ); then + _err "Set $_n_hook_file error." + _send_err=1 + else + _info "$_n_hook $(__green Success)" + fi + done + return $_send_err + +} + +# hook +_set_notify_hook() { + _nhooks="$1" + + _test_subject="Hello, this is a notification from $PROJECT_NAME" + _test_content="If you receive this message, your notification works." + + _send_notify "$_test_subject" "$_test_content" "$_nhooks" 0 + +} + +#[hook] [level] [mode] +setnotify() { + _nhook="$1" + _nlevel="$2" + _nmode="$3" + + _initpath + + if [ -z "$_nhook$_nlevel$_nmode" ]; then + _usage "Usage: $PROJECT_ENTRY --set-notify [--notify-hook ] [--notify-level <0|1|2|3>] [--notify-mode <0|1>]" + _usage "$_NOTIFY_WIKI" + return 1 + fi + + if [ "$_nlevel" ]; then + _info "Set notify level to: $_nlevel" + export "NOTIFY_LEVEL=$_nlevel" + _saveaccountconf "NOTIFY_LEVEL" "$NOTIFY_LEVEL" + fi + + if [ "$_nmode" ]; then + _info "Set notify mode to: $_nmode" + export "NOTIFY_MODE=$_nmode" + _saveaccountconf "NOTIFY_MODE" "$NOTIFY_MODE" + fi + + if [ "$_nhook" ]; then + _info "Set notify hook to: $_nhook" + if [ "$_nhook" = "$NO_VALUE" ]; then + _info "Clear notify hook" + _clearaccountconf "NOTIFY_HOOK" + else + if _set_notify_hook "$_nhook"; then + export NOTIFY_HOOK="$_nhook" + _saveaccountconf "NOTIFY_HOOK" "$NOTIFY_HOOK" + return 0 + else + _err "Can not set notify hook to: $_nhook" + return 1 + fi + fi + fi + +} + +showhelp() { + _initpath + version + echo "Usage: $PROJECT_ENTRY ... [parameters ...] +Commands: + -h, --help Show this help message. + -v, --version Show version info. + --install Install $PROJECT_NAME to your system. + --uninstall Uninstall $PROJECT_NAME, and uninstall the cron job. + --upgrade Upgrade $PROJECT_NAME to the latest code from $PROJECT. + --issue Issue a cert. + --deploy Deploy the cert to your server. + -i, --install-cert Install the issued cert to apache/nginx or any other server. + -r, --renew Renew a cert. + --renew-all Renew all the certs. + --revoke Revoke a cert. + --remove Remove the cert from list of certs known to $PROJECT_NAME. + --list List all the certs. + --to-pkcs12 Export the certificate and key to a pfx file. + --to-pkcs8 Convert to pkcs8 format. + --sign-csr Issue a cert from an existing csr. + --show-csr Show the content of a csr. + -ccr, --create-csr Create CSR, professional use. + --create-domain-key Create an domain private key, professional use. + --update-account Update account info. + --register-account Register account key. + --deactivate-account Deactivate the account. + --create-account-key Create an account private key, professional use. + --install-cronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job. + --uninstall-cronjob Uninstall the cron job. The 'uninstall' command can do this automatically. + --cron Run cron job to renew all the certs. + --set-notify Set the cron notification hook, level or mode. + --deactivate Deactivate the domain authz, professional use. + --set-default-ca Used with '--server', Set the default CA to use. + See: $_SERVER_WIKI + + +Parameters: + -d, --domain Specifies a domain, used to issue, renew or revoke etc. + --challenge-alias The challenge domain alias for DNS alias mode. + See: $_DNS_ALIAS_WIKI + + --domain-alias The domain alias for DNS alias mode. + See: $_DNS_ALIAS_WIKI + + --preferred-chain If the CA offers multiple certificate chains, prefer the chain with an issuer matching this Subject Common Name. + If no match, the default offered chain will be used. (default: empty) + See: $_PREFERRED_CHAIN_WIKI + + -f, --force Force install, force cert renewal or override sudo restrictions. + --staging, --test Use staging server, for testing. + --debug [0|1|2|3] Output debug info. Defaults to 1 if argument is omitted. + --output-insecure Output all the sensitive messages. + By default all the credentials/sensitive messages are hidden from the output/debug/log for security. + -w, --webroot Specifies the web root folder for web root mode. + --standalone Use standalone mode. + --alpn Use standalone alpn mode. + --stateless Use stateless mode. + See: $_STATELESS_WIKI + + --apache Use apache mode. + --dns [dns_hook] Use dns manual mode or dns api. Defaults to manual mode when argument is omitted. + See: $_DNS_API_WIKI + + --dnssleep The time in seconds to wait for all the txt records to propagate in dns api mode. + It's not necessary to use this by default, $PROJECT_NAME polls dns status by DOH automatically. + -k, --keylength Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384, ec-521. + -ak, --accountkeylength Specifies the account key length: 2048, 3072, 4096 + --log [file] Specifies the log file. Defaults to \"$DEFAULT_LOG_FILE\" if argument is omitted. + --log-level <1|2> Specifies the log level, default is 1. + --syslog <0|3|6|7> Syslog level, 0: disable syslog, 3: error, 6: info, 7: debug. + --eab-kid Key Identifier for External Account Binding. + --eab-hmac-key HMAC key for External Account Binding. + + + These parameters are to install the cert to nginx/apache or any other server after issue/renew a cert: + + --cert-file Path to copy the cert file to after issue/renew.. + --key-file Path to copy the key file to after issue/renew. + --ca-file Path to copy the intermediate cert file to after issue/renew. + --fullchain-file Path to copy the fullchain cert file to after issue/renew. + --reloadcmd Command to execute after issue/renew to reload the server. + + --server ACME Directory Resource URI. (default: $DEFAULT_CA) + See: $_SERVER_WIKI + + --accountconf Specifies a customized account config file. + --home Specifies the home dir for $PROJECT_NAME. + --cert-home Specifies the home dir to save all the certs, only valid for '--install' command. + --config-home Specifies the home dir to save all the configurations. + --useragent Specifies the user agent string. it will be saved for future use too. + -m, --accountemail Specifies the account email, only valid for the '--install' and '--update-account' command. + --accountkey Specifies the account key path, only valid for the '--install' command. + --days Specifies the days to renew the cert when using '--issue' command. The default value is $DEFAULT_RENEW days. + --httpport Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer. + --tlsport Specifies the standalone tls listening port. Only valid if the server is behind a reverse proxy or load balancer. + --local-address Specifies the standalone/tls server listening address, in case you have multiple ip addresses. + --listraw Only used for '--list' command, list the certs in raw format. + -se, --stop-renew-on-error Only valid for '--renew-all' command. Stop if one cert has error in renewal. + --insecure Do not check the server certificate, in some devices, the api server's certificate may not be trusted. + --ca-bundle Specifies the path to the CA certificate bundle to verify api server's certificate. + --ca-path Specifies directory containing CA certificates in PEM format, used by wget or curl. + --nocron Only valid for '--install' command, which means: do not install the default cron job. + In this case, the certs will not be renewed automatically. + --noprofile Only valid for '--install' command, which means: do not install aliases to user profile. + --no-color Do not output color text. + --force-color Force output of color text. Useful for non-interactive use with the aha tool for HTML E-Mails. + --ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--to-pkcs12' and '--create-csr' + --csr Specifies the input csr. + --pre-hook Command to be run before obtaining any certificates. + --post-hook Command to be run after attempting to obtain/renew certificates. Runs regardless of whether obtain/renew succeeded or failed. + --renew-hook Command to be run after each successfully renewed certificate. + --deploy-hook The hook file to deploy cert + --ocsp, --ocsp-must-staple Generate OCSP-Must-Staple extension. + --always-force-new-domain-key Generate new domain key on renewal. Otherwise, the domain key is not changed by default. + --auto-upgrade [0|1] Valid for '--upgrade' command, indicating whether to upgrade automatically in future. Defaults to 1 if argument is omitted. + --listen-v4 Force standalone/tls server to listen at ipv4. + --listen-v6 Force standalone/tls server to listen at ipv6. + --openssl-bin Specifies a custom openssl bin location. + --use-wget Force to use wget, if you have both curl and wget installed. + --yes-I-know-dns-manual-mode-enough-go-ahead-please Force use of dns manual mode. + See: $_DNS_MANUAL_WIKI + + -b, --branch Only valid for '--upgrade' command, specifies the branch name to upgrade to. + --notify-level <0|1|2|3> Set the notification level: Default value is $NOTIFY_LEVEL_DEFAULT. + 0: disabled, no notification will be sent. + 1: send notifications only when there is an error. + 2: send notifications when a cert is successfully renewed, or there is an error. + 3: send notifications when a cert is skipped, renewed, or error. + --notify-mode <0|1> Set notification mode. Default value is $NOTIFY_MODE_DEFAULT. + 0: Bulk mode. Send all the domain's notifications in one message(mail). + 1: Cert mode. Send a message for every single cert. + --notify-hook Set the notify hook + --revoke-reason <0-10> The reason for revocation, can be used in conjunction with the '--revoke' command. + See: $_REVOKE_WIKI + + --password Add a password to exported pfx file. Use with --to-pkcs12. + + +" +} + +# nocron noprofile +_installOnline() { + _info "Installing from online archive." + _nocron="$1" + _noprofile="$2" + if [ ! "$BRANCH" ]; then + BRANCH="master" + fi + + target="$PROJECT/archive/$BRANCH.tar.gz" + _info "Downloading $target" + localname="$BRANCH.tar.gz" + if ! _get "$target" >$localname; then + _err "Download error." + return 1 + fi + ( + _info "Extracting $localname" + if ! (tar xzf $localname || gtar xzf $localname); then + _err "Extraction error." + exit 1 + fi + + cd "$PROJECT_NAME-$BRANCH" + chmod +x $PROJECT_ENTRY + if ./$PROJECT_ENTRY install "$_nocron" "" "$_noprofile"; then + _info "Install success!" + _initpath + _saveaccountconf "UPGRADE_HASH" "$(_getUpgradeHash)" + fi + + cd .. + + rm -rf "$PROJECT_NAME-$BRANCH" + rm -f "$localname" + ) +} + +_getRepoHash() { + _hash_path=$1 + shift + _hash_url="https://api.github.com/repos/acmesh-official/$PROJECT_NAME/git/refs/$_hash_path" + _get $_hash_url | tr -d "\r\n" | tr '{},' '\n' | grep '"sha":' | cut -d '"' -f 4 +} + +_getUpgradeHash() { + _b="$BRANCH" + if [ -z "$_b" ]; then + _b="master" + fi + _hash=$(_getRepoHash "heads/$_b") + if [ -z "$_hash" ]; then _hash=$(_getRepoHash "tags/$_b"); fi + echo $_hash +} + +upgrade() { + if ( + _initpath + [ -z "$FORCE" ] && [ "$(_getUpgradeHash)" = "$(_readaccountconf "UPGRADE_HASH")" ] && _info "Already uptodate!" && exit 0 + export LE_WORKING_DIR + cd "$LE_WORKING_DIR" + _installOnline "nocron" "noprofile" + ); then + _info "Upgrade success!" + exit 0 + else + _err "Upgrade failed!" + exit 1 + fi +} + +_processAccountConf() { + if [ "$_useragent" ]; then + _saveaccountconf "USER_AGENT" "$_useragent" + elif [ "$USER_AGENT" ] && [ "$USER_AGENT" != "$DEFAULT_USER_AGENT" ]; then + _saveaccountconf "USER_AGENT" "$USER_AGENT" + fi + + if [ "$_openssl_bin" ]; then + _saveaccountconf "ACME_OPENSSL_BIN" "$_openssl_bin" + elif [ "$ACME_OPENSSL_BIN" ] && [ "$ACME_OPENSSL_BIN" != "$DEFAULT_OPENSSL_BIN" ]; then + _saveaccountconf "ACME_OPENSSL_BIN" "$ACME_OPENSSL_BIN" + fi + + if [ "$_auto_upgrade" ]; then + _saveaccountconf "AUTO_UPGRADE" "$_auto_upgrade" + elif [ "$AUTO_UPGRADE" ]; then + _saveaccountconf "AUTO_UPGRADE" "$AUTO_UPGRADE" + fi + + if [ "$_use_wget" ]; then + _saveaccountconf "ACME_USE_WGET" "$_use_wget" + elif [ "$ACME_USE_WGET" ]; then + _saveaccountconf "ACME_USE_WGET" "$ACME_USE_WGET" + fi + +} + +_checkSudo() { + if [ "$SUDO_GID" ] && [ "$SUDO_COMMAND" ] && [ "$SUDO_USER" ] && [ "$SUDO_UID" ]; then + if [ "$SUDO_USER" = "root" ] && [ "$SUDO_UID" = "0" ]; then + #it's root using sudo, no matter it's using sudo or not, just fine + return 0 + fi + if [ -n "$SUDO_COMMAND" ]; then + #it's a normal user doing "sudo su", or `sudo -i` or `sudo -s`, or `sudo su acmeuser1` + _endswith "$SUDO_COMMAND" /bin/su || _contains "$SUDO_COMMAND" "/bin/su " || grep "^$SUDO_COMMAND\$" /etc/shells >/dev/null 2>&1 + return $? + fi + #otherwise + return 1 + fi + return 0 +} + +#server +_selectServer() { + _server="$1" + _server_lower="$(echo "$_server" | _lower_case)" + _sindex=0 + for snames in $CA_NAMES; do + snames="$(echo "$snames" | _lower_case)" + _sindex="$(_math $_sindex + 1)" + _debug2 "_selectServer try snames" "$snames" + for sname in $(echo "$snames" | tr ',' ' '); do + if [ "$_server_lower" = "$sname" ]; then + _debug2 "_selectServer match $sname" + _serverdir="$(_getfield "$CA_SERVERS" $_sindex)" + _debug "Selected server: $_serverdir" + ACME_DIRECTORY="$_serverdir" + export ACME_DIRECTORY + return + fi + done + done + ACME_DIRECTORY="$_server" + export ACME_DIRECTORY +} + +#url +_getCAShortName() { + caurl="$1" + if [ -z "$caurl" ]; then + caurl="$DEFAULT_CA" + fi + caurl_lower="$(echo $caurl | _lower_case)" + _sindex=0 + for surl in $(echo "$CA_SERVERS" | _lower_case | tr , ' '); do + _sindex="$(_math $_sindex + 1)" + if [ "$caurl_lower" = "$surl" ]; then + _nindex=0 + for snames in $CA_NAMES; do + _nindex="$(_math $_nindex + 1)" + if [ $_nindex -ge $_sindex ]; then + _getfield "$snames" 1 + return + fi + done + fi + done + echo "$caurl" +} + +#set default ca to $ACME_DIRECTORY +setdefaultca() { + if [ -z "$ACME_DIRECTORY" ]; then + _err "Please give a --server parameter." + return 1 + fi + _saveaccountconf "DEFAULT_ACME_SERVER" "$ACME_DIRECTORY" + _info "Changed default CA to: $(__green "$ACME_DIRECTORY")" +} + +_process() { + _CMD="" + _domain="" + _altdomains="$NO_VALUE" + _webroot="" + _challenge_alias="" + _keylength="" + _accountkeylength="" + _cert_file="" + _key_file="" + _ca_file="" + _fullchain_file="" + _reloadcmd="" + _password="" + _accountconf="" + _useragent="" + _accountemail="" + _accountkey="" + _certhome="" + _confighome="" + _httpport="" + _tlsport="" + _dnssleep="" + _listraw="" + _stopRenewOnError="" + #_insecure="" + _ca_bundle="" + _ca_path="" + _nocron="" + _noprofile="" + _ecc="" + _csr="" + _pre_hook="" + _post_hook="" + _renew_hook="" + _deploy_hook="" + _logfile="" + _log="" + _local_address="" + _log_level="" + _auto_upgrade="" + _listen_v4="" + _listen_v6="" + _openssl_bin="" + _syslog="" + _use_wget="" + _server="" + _notify_hook="" + _notify_level="" + _notify_mode="" + _revoke_reason="" + _eab_kid="" + _eab_hmac_key="" + _preferred_chain="" + while [ ${#} -gt 0 ]; do + case "${1}" in + + --help | -h) + showhelp + return + ;; + --version | -v) + version + return + ;; + --install) + _CMD="install" + ;; + --uninstall) + _CMD="uninstall" + ;; + --upgrade) + _CMD="upgrade" + ;; + --issue) + _CMD="issue" + ;; + --deploy) + _CMD="deploy" + ;; + --sign-csr | --signcsr) + _CMD="signcsr" + ;; + --show-csr | --showcsr) + _CMD="showcsr" + ;; + -i | --install-cert | --installcert) + _CMD="installcert" + ;; + --renew | -r) + _CMD="renew" + ;; + --renew-all | --renewAll | --renewall) + _CMD="renewAll" + ;; + --revoke) + _CMD="revoke" + ;; + --remove) + _CMD="remove" + ;; + --list) + _CMD="list" + ;; + --install-cronjob | --installcronjob) + _CMD="installcronjob" + ;; + --uninstall-cronjob | --uninstallcronjob) + _CMD="uninstallcronjob" + ;; + --cron) + _CMD="cron" + ;; + --to-pkcs12 | --to-pkcs | --toPkcs) + _CMD="toPkcs" + ;; + --to-pkcs8 | --toPkcs8) + _CMD="toPkcs8" + ;; + --create-account-key | --createAccountKey | --createaccountkey | -cak) + _CMD="createAccountKey" + ;; + --create-domain-key | --createDomainKey | --createdomainkey | -cdk) + _CMD="createDomainKey" + ;; + -ccr | --create-csr | --createCSR | --createcsr) + _CMD="createCSR" + ;; + --deactivate) + _CMD="deactivate" + ;; + --update-account | --updateaccount) + _CMD="updateaccount" + ;; + --register-account | --registeraccount) + _CMD="registeraccount" + ;; + --deactivate-account) + _CMD="deactivateaccount" + ;; + --set-notify) + _CMD="setnotify" + ;; + --set-default-ca) + _CMD="setdefaultca" + ;; + -d | --domain) + _dvalue="$2" + + if [ "$_dvalue" ]; then + if _startswith "$_dvalue" "-"; then + _err "'$_dvalue' is not a valid domain for parameter '$1'" + return 1 + fi + if _is_idn "$_dvalue" && ! _exists idn; then + _err "It seems that $_dvalue is an IDN( Internationalized Domain Names), please install 'idn' command first." + return 1 + fi + + if _startswith "$_dvalue" "*."; then + _debug "Wildcard domain" + export ACME_VERSION=2 + fi + if [ -z "$_domain" ]; then + _domain="$_dvalue" + else + if [ "$_altdomains" = "$NO_VALUE" ]; then + _altdomains="$_dvalue" + else + _altdomains="$_altdomains,$_dvalue" + fi + fi + fi + + shift + ;; + + -f | --force) + FORCE="1" + ;; + --staging | --test) + STAGE="1" + ;; + --server) + _server="$2" + _selectServer "$_server" + shift + ;; + --debug) + if [ -z "$2" ] || _startswith "$2" "-"; then + DEBUG="$DEBUG_LEVEL_DEFAULT" + else + DEBUG="$2" + shift + fi + ;; + --output-insecure) + export OUTPUT_INSECURE=1 + ;; + -w | --webroot) + wvalue="$2" + if [ -z "$_webroot" ]; then + _webroot="$wvalue" + else + _webroot="$_webroot,$wvalue" + fi + shift + ;; + --challenge-alias) + cvalue="$2" + _challenge_alias="$_challenge_alias$cvalue," + shift + ;; + --domain-alias) + cvalue="$DNS_ALIAS_PREFIX$2" + _challenge_alias="$_challenge_alias$cvalue," + shift + ;; + --standalone) + wvalue="$NO_VALUE" + if [ -z "$_webroot" ]; then + _webroot="$wvalue" + else + _webroot="$_webroot,$wvalue" + fi + ;; + --alpn) + wvalue="$W_ALPN" + if [ -z "$_webroot" ]; then + _webroot="$wvalue" + else + _webroot="$_webroot,$wvalue" + fi + ;; + --stateless) + wvalue="$MODE_STATELESS" + if [ -z "$_webroot" ]; then + _webroot="$wvalue" + else + _webroot="$_webroot,$wvalue" + fi + ;; + --local-address) + lvalue="$2" + _local_address="$_local_address$lvalue," + shift + ;; + --apache) + wvalue="apache" + if [ -z "$_webroot" ]; then + _webroot="$wvalue" + else + _webroot="$_webroot,$wvalue" + fi + ;; + --nginx) + wvalue="$NGINX" + if [ "$2" ] && ! _startswith "$2" "-"; then + wvalue="$NGINX$2" + shift + fi + if [ -z "$_webroot" ]; then + _webroot="$wvalue" + else + _webroot="$_webroot,$wvalue" + fi + ;; + --dns) + wvalue="$W_DNS" + if [ "$2" ] && ! _startswith "$2" "-"; then + wvalue="$2" + shift + fi + if [ -z "$_webroot" ]; then + _webroot="$wvalue" + else + _webroot="$_webroot,$wvalue" + fi + ;; + --dnssleep) + _dnssleep="$2" + Le_DNSSleep="$_dnssleep" + shift + ;; + + --keylength | -k) + _keylength="$2" + shift + ;; + -ak | --accountkeylength) + _accountkeylength="$2" + shift + ;; + + --cert-file | --certpath) + _cert_file="$2" + shift + ;; + --key-file | --keypath) + _key_file="$2" + shift + ;; + --ca-file | --capath) + _ca_file="$2" + shift + ;; + --fullchain-file | --fullchainpath) + _fullchain_file="$2" + shift + ;; + --reloadcmd | --reloadCmd) + _reloadcmd="$2" + shift + ;; + --password) + _password="$2" + shift + ;; + --accountconf) + _accountconf="$2" + ACCOUNT_CONF_PATH="$_accountconf" + shift + ;; + --home) + LE_WORKING_DIR="$2" + shift + ;; + --cert-home | --certhome) + _certhome="$2" + CERT_HOME="$_certhome" + shift + ;; + --config-home) + _confighome="$2" + LE_CONFIG_HOME="$_confighome" + shift + ;; + --useragent) + _useragent="$2" + USER_AGENT="$_useragent" + shift + ;; + -m | --accountemail) + _accountemail="$2" + ACCOUNT_EMAIL="$_accountemail" + shift + ;; + --accountkey) + _accountkey="$2" + ACCOUNT_KEY_PATH="$_accountkey" + shift + ;; + --days) + _days="$2" + Le_RenewalDays="$_days" + shift + ;; + --httpport) + _httpport="$2" + Le_HTTPPort="$_httpport" + shift + ;; + --tlsport) + _tlsport="$2" + Le_TLSPort="$_tlsport" + shift + ;; + --listraw) + _listraw="raw" + ;; + -se | --stop-renew-on-error | --stopRenewOnError | --stoprenewonerror) + _stopRenewOnError="1" + ;; + --insecure) + #_insecure="1" + HTTPS_INSECURE="1" + ;; + --ca-bundle) + _ca_bundle="$(_readlink "$2")" + CA_BUNDLE="$_ca_bundle" + shift + ;; + --ca-path) + _ca_path="$2" + CA_PATH="$_ca_path" + shift + ;; + --nocron) + _nocron="1" + ;; + --noprofile) + _noprofile="1" + ;; + --no-color) + export ACME_NO_COLOR=1 + ;; + --force-color) + export ACME_FORCE_COLOR=1 + ;; + --ecc) + _ecc="isEcc" + ;; + --csr) + _csr="$2" + shift + ;; + --pre-hook) + _pre_hook="$2" + shift + ;; + --post-hook) + _post_hook="$2" + shift + ;; + --renew-hook) + _renew_hook="$2" + shift + ;; + --deploy-hook) + if [ -z "$2" ] || _startswith "$2" "-"; then + _usage "Please specify a value for '--deploy-hook'" + return 1 + fi + _deploy_hook="$_deploy_hook$2," + shift + ;; + --ocsp-must-staple | --ocsp) + Le_OCSP_Staple="1" + ;; + --always-force-new-domain-key) + if [ -z "$2" ] || _startswith "$2" "-"; then + Le_ForceNewDomainKey=1 + else + Le_ForceNewDomainKey="$2" + shift + fi + ;; + --yes-I-know-dns-manual-mode-enough-go-ahead-please) + export FORCE_DNS_MANUAL=1 + ;; + --log | --logfile) + _log="1" + _logfile="$2" + if _startswith "$_logfile" '-'; then + _logfile="" + else + shift + fi + LOG_FILE="$_logfile" + if [ -z "$LOG_LEVEL" ]; then + LOG_LEVEL="$DEFAULT_LOG_LEVEL" + fi + ;; + --log-level) + _log_level="$2" + LOG_LEVEL="$_log_level" + shift + ;; + --syslog) + if ! _startswith "$2" '-'; then + _syslog="$2" + shift + fi + if [ -z "$_syslog" ]; then + _syslog="$SYSLOG_LEVEL_DEFAULT" + fi + ;; + --auto-upgrade) + _auto_upgrade="$2" + if [ -z "$_auto_upgrade" ] || _startswith "$_auto_upgrade" '-'; then + _auto_upgrade="1" + else + shift + fi + AUTO_UPGRADE="$_auto_upgrade" + ;; + --listen-v4) + _listen_v4="1" + Le_Listen_V4="$_listen_v4" + ;; + --listen-v6) + _listen_v6="1" + Le_Listen_V6="$_listen_v6" + ;; + --openssl-bin) + _openssl_bin="$2" + ACME_OPENSSL_BIN="$_openssl_bin" + shift + ;; + --use-wget) + _use_wget="1" + ACME_USE_WGET="1" + ;; + --branch | -b) + export BRANCH="$2" + shift + ;; + --notify-hook) + _nhook="$2" + if _startswith "$_nhook" "-"; then + _err "'$_nhook' is not a hook name for '$1'" + return 1 + fi + if [ "$_notify_hook" ]; then + _notify_hook="$_notify_hook,$_nhook" + else + _notify_hook="$_nhook" + fi + shift + ;; + --notify-level) + _nlevel="$2" + if _startswith "$_nlevel" "-"; then + _err "'$_nlevel' is not a integer for '$1'" + return 1 + fi + _notify_level="$_nlevel" + shift + ;; + --notify-mode) + _nmode="$2" + if _startswith "$_nmode" "-"; then + _err "'$_nmode' is not a integer for '$1'" + return 1 + fi + _notify_mode="$_nmode" + shift + ;; + --revoke-reason) + _revoke_reason="$2" + if _startswith "$_revoke_reason" "-"; then + _err "'$_revoke_reason' is not a integer for '$1'" + return 1 + fi + shift + ;; + --eab-kid) + _eab_kid="$2" + shift + ;; + --eab-hmac-key) + _eab_hmac_key="$2" + shift + ;; + --preferred-chain) + _preferred_chain="$2" + shift + ;; + *) + _err "Unknown parameter : $1" + return 1 + ;; + esac + + shift 1 + done + + if [ "${_CMD}" != "install" ]; then + if [ "$__INTERACTIVE" ] && ! _checkSudo; then + if [ -z "$FORCE" ]; then + #Use "echo" here, instead of _info. it's too early + echo "It seems that you are using sudo, please read this link first:" + echo "$_SUDO_WIKI" + return 1 + fi + fi + __initHome + if [ "$_log" ]; then + if [ -z "$_logfile" ]; then + _logfile="$DEFAULT_LOG_FILE" + fi + fi + if [ "$_logfile" ]; then + _saveaccountconf "LOG_FILE" "$_logfile" + LOG_FILE="$_logfile" + fi + + if [ "$_log_level" ]; then + _saveaccountconf "LOG_LEVEL" "$_log_level" + LOG_LEVEL="$_log_level" + fi + + if [ "$_syslog" ]; then + if _exists logger; then + if [ "$_syslog" = "0" ]; then + _clearaccountconf "SYS_LOG" + else + _saveaccountconf "SYS_LOG" "$_syslog" + fi + SYS_LOG="$_syslog" + else + _err "The 'logger' command is not found, can not enable syslog." + _clearaccountconf "SYS_LOG" + SYS_LOG="" + fi + fi + + _processAccountConf + fi + + _debug2 LE_WORKING_DIR "$LE_WORKING_DIR" + + if [ "$DEBUG" ]; then + version + if [ "$_server" ]; then + _debug "Using server: $_server" + fi + fi + _debug "Running cmd: ${_CMD}" + case "${_CMD}" in + install) install "$_nocron" "$_confighome" "$_noprofile" ;; + uninstall) uninstall "$_nocron" ;; + upgrade) upgrade ;; + issue) + issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" "$_challenge_alias" "$_preferred_chain" + ;; + deploy) + deploy "$_domain" "$_deploy_hook" "$_ecc" + ;; + signcsr) + signcsr "$_csr" "$_webroot" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" "$_challenge_alias" + ;; + showcsr) + showcsr "$_csr" "$_domain" + ;; + installcert) + installcert "$_domain" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_ecc" + ;; + renew) + renew "$_domain" "$_ecc" + ;; + renewAll) + renewAll "$_stopRenewOnError" + ;; + revoke) + revoke "$_domain" "$_ecc" "$_revoke_reason" + ;; + remove) + remove "$_domain" "$_ecc" + ;; + deactivate) + deactivate "$_domain,$_altdomains" + ;; + registeraccount) + registeraccount "$_accountkeylength" "$_eab_kid" "$_eab_hmac_key" + ;; + updateaccount) + updateaccount + ;; + deactivateaccount) + deactivateaccount + ;; + list) + list "$_listraw" "$_domain" + ;; + installcronjob) installcronjob "$_confighome" ;; + uninstallcronjob) uninstallcronjob ;; + cron) cron ;; + toPkcs) + toPkcs "$_domain" "$_password" "$_ecc" + ;; + toPkcs8) + toPkcs8 "$_domain" "$_ecc" + ;; + createAccountKey) + createAccountKey "$_accountkeylength" + ;; + createDomainKey) + createDomainKey "$_domain" "$_keylength" + ;; + createCSR) + createCSR "$_domain" "$_altdomains" "$_ecc" + ;; + setnotify) + setnotify "$_notify_hook" "$_notify_level" "$_notify_mode" + ;; + setdefaultca) + setdefaultca + ;; + *) + if [ "$_CMD" ]; then + _err "Invalid command: $_CMD" + fi + showhelp + return 1 + ;; + esac + _ret="$?" + if [ "$_ret" != "0" ]; then + return $_ret + fi + + if [ "${_CMD}" = "install" ]; then + if [ "$_log" ]; then + if [ -z "$LOG_FILE" ]; then + LOG_FILE="$DEFAULT_LOG_FILE" + fi + _saveaccountconf "LOG_FILE" "$LOG_FILE" + fi + + if [ "$_log_level" ]; then + _saveaccountconf "LOG_LEVEL" "$_log_level" + fi + + if [ "$_syslog" ]; then + if _exists logger; then + if [ "$_syslog" = "0" ]; then + _clearaccountconf "SYS_LOG" + else + _saveaccountconf "SYS_LOG" "$_syslog" + fi + else + _err "The 'logger' command is not found, can not enable syslog." + _clearaccountconf "SYS_LOG" + SYS_LOG="" + fi + fi + + _processAccountConf + fi + +} + +if [ "$INSTALLONLINE" ]; then + INSTALLONLINE="" + _installOnline + exit +fi + +main() { + [ -z "$1" ] && showhelp && return + if _startswith "$1" '-'; then _process "$@"; else "$@"; fi +} + +main "$@" diff --git a/letsencrypt/acme.sh.env b/letsencrypt/acme.sh.env new file mode 100644 index 00000000..407cd941 --- /dev/null +++ b/letsencrypt/acme.sh.env @@ -0,0 +1,2 @@ +export LE_WORKING_DIR="/etc/letsencrypt" +alias acme.sh="/etc/letsencrypt/acme.sh" diff --git a/letsencrypt/ca/acme-v02.api.letsencrypt.org/account.json b/letsencrypt/ca/acme-v02.api.letsencrypt.org/account.json new file mode 100644 index 00000000..afc29e61 --- /dev/null +++ b/letsencrypt/ca/acme-v02.api.letsencrypt.org/account.json @@ -0,0 +1 @@ +{"key":{"kty":"RSA","n":"rmknIf85wlcw_ofsDvKO_oxmuQaRP73y56YXvvxW3sXcHEO6jG9GbAvW979JOW9w2A0Jk8TUsuENX00A16yIqKCCfAnOFpKTY2fAZWyRfBFzghKs8wre8K4Q8AlXlixODlLX-SL_1HVXKjHlnRFAFOX0HhuhUCVBeXmGEhbkVlhP6MdvfYPRqYkweLe0De73aoWkFK1nUu9Kj31fwHTJHaNyc9LhO0L8ZFAS5XDtOrrkkPc63EWVoto316jCFLjd_jjGYbu9qvcyPvzImMTdQMB5cFjVCMzj5WkmCID8XzZ_kg7J3Ka2_13bDwigVESwo-EKLuu6TojeB6j84bO_3w","e":"AQAB"},"contact":["mailto:gorden.mende@solusar.de"],"initialIp":"79.194.104.173","createdAt":"2021-01-20T12:47:52.197016456Z","status":"valid"} diff --git a/letsencrypt/ca/acme-v02.api.letsencrypt.org/account.key b/letsencrypt/ca/acme-v02.api.letsencrypt.org/account.key new file mode 100644 index 00000000..a57ec823 --- /dev/null +++ b/letsencrypt/ca/acme-v02.api.letsencrypt.org/account.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEArmknIf85wlcw/ofsDvKO/oxmuQaRP73y56YXvvxW3sXcHEO6 +jG9GbAvW979JOW9w2A0Jk8TUsuENX00A16yIqKCCfAnOFpKTY2fAZWyRfBFzghKs +8wre8K4Q8AlXlixODlLX+SL/1HVXKjHlnRFAFOX0HhuhUCVBeXmGEhbkVlhP6Mdv +fYPRqYkweLe0De73aoWkFK1nUu9Kj31fwHTJHaNyc9LhO0L8ZFAS5XDtOrrkkPc6 +3EWVoto316jCFLjd/jjGYbu9qvcyPvzImMTdQMB5cFjVCMzj5WkmCID8XzZ/kg7J +3Ka2/13bDwigVESwo+EKLuu6TojeB6j84bO/3wIDAQABAoIBACJsYKvmGvlPij0C +iMXee/ijr3afZDWngPTVpGQum9q2RJ5Tg9NJ9yVGJPSbDZHHfAc4c4Z11+FCaAhC +Q4NN618U5wwiR0nPPkXlaWTbS8+oBhtLIlWJ9LyeLnuh7GaYcgODuFrU3JeLXVvX +o1Ef4Xz+cfMrUuhlogmewaZ6XDDqQ8oNHRSLxTA6tz5vygIUhIvBUBeOWViOXeuz +iu+08AlXtfPFxK5Y6P4z2Kkh6OpK8pUpLr/Aqb9BIRIFSGClDBm9oT/AajRvd9IP +jluSTr++7yjOp/Gydb6/7FjudWVEYVYwWVKNkCv4VyyyuPKdxCzFzh7Zm8seigdb +zQXk6mkCgYEA26pQhtjRQ54P2vxQkrKpCRMiKYlpW3dH3+Z/V5JqG1DACzFocZzd +PWFF/l6HfNYbawTtQm4W980Q0IVa5ZgU9B7bMg8pBzr35336phelbn6KXH2Ybswe +wh7lTLDlEais0O/T/J0kvrL8Yw7gC4FYUS/+gc2jJZG7HQnkOJvXnssCgYEAy0KL +HPBIhL4w43coUuWLWKym8zvVsTI09E6YsCSz5jg9uY/OHZn46EEv52xSJ1bpCphV +fuS+T58lP5jztEXALjdInuIvZqRfE5/zELqzwwdeSo1sh2ZzmbTUBX/ZOUUeV5mq +kpvG3madIvTwXILVcF0Q4tAo18aiJpoGJkP2DL0CgYAeocJ2+3c7GaiWXgcSXe2q +gUuLRUk24wxX0bnCSX2Yb4tIREyPQ1OqwozTKvVz2BucseQwFlAHoEYO/fmt+KY7 +YK4qbejHxFZbprq0PKnqHaVHvo/qK3bClTJennBjJQVsYXVLTdKY8Ta2zZU6pX/e +WnYAPd/ZVlgkdYOozTqlPwKBgGJM8VhygK/qB1zK0O6eYvDktu0lf+htfpy0sjVl +2rc5deibOrSoNW+lrxQ+F9E8wAHGwHpZCA0by3jhcOM7ZIE1bWKhwwjh77VfAr+R +e8STeK+Xi+hDzR6GDJAIT7bZzZ3SDGNRATGn8NDqIqCrCayI5dS7lTUdtGf0z4qM +DaAFAoGBALsZbfZ2xjYnzCSy6o2m4VBD9idct0jaCNZz4gYZNK2Zp8LmbLI9uR6G +KfV/X8zd3gDoOS3FovK8T0VSt5THtFALhGn+JON/JXc0pNKjTmSWf4em8rM5l/wP +zExpo2bExjExb74opGkhZjE5azvZ0L4vDpDsc1mzmUhl8AqdFlYD +-----END RSA PRIVATE KEY----- diff --git a/letsencrypt/ca/acme-v02.api.letsencrypt.org/ca.conf b/letsencrypt/ca/acme-v02.api.letsencrypt.org/ca.conf new file mode 100644 index 00000000..a2db9161 --- /dev/null +++ b/letsencrypt/ca/acme-v02.api.letsencrypt.org/ca.conf @@ -0,0 +1,3 @@ +CA_EMAIL='gorden.mende@solusar.de' +ACCOUNT_URL='https://acme-v02.api.letsencrypt.org/acme/acct/110150126' +CA_KEY_HASH='xbWNsc3ZE/DEBVcEpG+NbeYWzEdOa203lfga39xm3JE=' diff --git a/letsencrypt/deploy/README.md b/letsencrypt/deploy/README.md new file mode 100644 index 00000000..e3f239fa --- /dev/null +++ b/letsencrypt/deploy/README.md @@ -0,0 +1,6 @@ +# Using deploy api + +deploy hook usage: + +https://github.com/acmesh-official/acme.sh/wiki/deployhooks + diff --git a/letsencrypt/deploy/apache.sh b/letsencrypt/deploy/apache.sh new file mode 100644 index 00000000..ae74e8bb --- /dev/null +++ b/letsencrypt/deploy/apache.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +#Here is a script to deploy cert to apache server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +apache_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "Deploy cert to apache server, Not implemented yet" + return 1 + +} diff --git a/letsencrypt/deploy/cleverreach.sh b/letsencrypt/deploy/cleverreach.sh new file mode 100644 index 00000000..1abaf0bf --- /dev/null +++ b/letsencrypt/deploy/cleverreach.sh @@ -0,0 +1,70 @@ +#!/bin/bash +# Here is the script to deploy the cert to your CleverReach Account using the CleverReach REST API. +# Your OAuth needs the right scope, please contact CleverReach support for that. +# +# Written by Jan-Philipp Benecke +# Public domain, 2020 +# +# Following environment variables must be set: +# +#export DEPLOY_CLEVERREACH_CLIENT_ID=myid +#export DEPLOY_CLEVERREACH_CLIENT_SECRET=mysecret + +cleverreach_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _getdeployconf DEPLOY_CLEVERREACH_CLIENT_ID + _getdeployconf DEPLOY_CLEVERREACH_CLIENT_SECRET + + if [ -z "${DEPLOY_CLEVERREACH_CLIENT_ID}" ]; then + _err "CleverReach Client ID is not found, please define DEPLOY_CLEVERREACH_CLIENT_ID." + return 1 + fi + if [ -z "${DEPLOY_CLEVERREACH_CLIENT_SECRET}" ]; then + _err "CleverReach client secret is not found, please define DEPLOY_CLEVERREACH_CLIENT_SECRET." + return 1 + fi + + _savedeployconf DEPLOY_CLEVERREACH_CLIENT_ID "${DEPLOY_CLEVERREACH_CLIENT_ID}" + _savedeployconf DEPLOY_CLEVERREACH_CLIENT_SECRET "${DEPLOY_CLEVERREACH_CLIENT_SECRET}" + + _info "Obtaining a CleverReach access token" + + _data="{\"grant_type\": \"client_credentials\", \"client_id\": \"${DEPLOY_CLEVERREACH_CLIENT_ID}\", \"client_secret\": \"${DEPLOY_CLEVERREACH_CLIENT_SECRET}\"}" + _auth_result="$(_post "$_data" "https://rest.cleverreach.com/oauth/token.php" "" "POST" "application/json")" + + _debug _data "$_data" + _debug _auth_result "$_auth_result" + + _regex=".*\"access_token\":\"\([-._0-9A-Za-z]*\)\".*$" + _debug _regex "$_regex" + _access_token=$(echo "$_auth_result" | _json_decode | sed -n "s/$_regex/\1/p") + + _info "Uploading certificate and key to CleverReach" + + _certData="{\"cert\":\"$(_json_encode <"$_cfullchain")\", \"key\":\"$(_json_encode <"$_ckey")\"}" + export _H1="Authorization: Bearer ${_access_token}" + _add_cert_result="$(_post "$_certData" "https://rest.cleverreach.com/v3/ssl" "" "POST" "application/json")" + + _debug "Destroying token at CleverReach" + _post "" "https://rest.cleverreach.com/v3/oauth/token.json" "" "DELETE" "application/json" + + if ! echo "$_add_cert_result" | grep '"error":' >/dev/null; then + _info "Uploaded certificate successfully" + return 0 + else + _debug _add_cert_result "$_add_cert_result" + _err "Unable to update certificate" + return 1 + fi +} diff --git a/letsencrypt/deploy/cpanel_uapi.sh b/letsencrypt/deploy/cpanel_uapi.sh new file mode 100644 index 00000000..d2a34b80 --- /dev/null +++ b/letsencrypt/deploy/cpanel_uapi.sh @@ -0,0 +1,62 @@ +#!/bin/bash +# Here is the script to deploy the cert to your cpanel using the cpanel API. +# Uses command line uapi. --user option is needed only if run as root. +# Returns 0 when success. +# +# Please note that I am no longer using Github. If you want to report an issue +# or contact me, visit https://forum.webseodesigners.com/web-design-seo-and-hosting-f16/ +# +# Written by Santeri Kannisto +# Public domain, 2017-2018 + +#export DEPLOY_CPANEL_USER=myusername + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain + +cpanel_uapi_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + if ! _exists uapi; then + _err "The command uapi is not found." + return 1 + fi + # read cert and key files and urlencode both + _cert=$(_url_encode <"$_ccert") + _key=$(_url_encode <"$_ckey") + + _debug _cert "$_cert" + _debug _key "$_key" + + if [ "$(id -u)" = 0 ]; then + if [ -z "$DEPLOY_CPANEL_USER" ]; then + _err "It seems that you are root, please define the target user name: export DEPLOY_CPANEL_USER=username" + return 1 + fi + _savedomainconf DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER" + _response=$(uapi --user="$DEPLOY_CPANEL_USER" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") + else + _response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key") + fi + error_response="status: 0" + if test "${_response#*$error_response}" != "$_response"; then + _err "Error in deploying certificate:" + _err "$_response" + return 1 + fi + + _debug response "$_response" + _info "Certificate successfully deployed" + return 0 +} diff --git a/letsencrypt/deploy/docker.sh b/letsencrypt/deploy/docker.sh new file mode 100755 index 00000000..85547c4c --- /dev/null +++ b/letsencrypt/deploy/docker.sh @@ -0,0 +1,287 @@ +#!/bin/bash + +#DEPLOY_DOCKER_CONTAINER_LABEL="xxxxxxx" + +#DEPLOY_DOCKER_CONTAINER_KEY_FILE="/path/to/key.pem" +#DEPLOY_DOCKER_CONTAINER_CERT_FILE="/path/to/cert.pem" +#DEPLOY_DOCKER_CONTAINER_CA_FILE="/path/to/ca.pem" +#DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE="/path/to/fullchain.pem" +#DEPLOY_DOCKER_CONTAINER_RELOAD_CMD="service nginx force-reload" + +_DEPLOY_DOCKER_WIKI="https://github.com/acmesh-official/acme.sh/wiki/deploy-to-docker-containers" + +_DOCKER_HOST_DEFAULT="/var/run/docker.sock" + +docker_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + _debug _cdomain "$_cdomain" + _getdeployconf DEPLOY_DOCKER_CONTAINER_LABEL + _debug2 DEPLOY_DOCKER_CONTAINER_LABEL "$DEPLOY_DOCKER_CONTAINER_LABEL" + if [ -z "$DEPLOY_DOCKER_CONTAINER_LABEL" ]; then + _err "The DEPLOY_DOCKER_CONTAINER_LABEL variable is not defined, we use this label to find the container." + _err "See: $_DEPLOY_DOCKER_WIKI" + fi + + _savedeployconf DEPLOY_DOCKER_CONTAINER_LABEL "$DEPLOY_DOCKER_CONTAINER_LABEL" + + if [ "$DOCKER_HOST" ]; then + _saveaccountconf DOCKER_HOST "$DOCKER_HOST" + fi + + if _exists docker && docker version | grep -i docker >/dev/null; then + _info "Using docker command" + export _USE_DOCKER_COMMAND=1 + else + export _USE_DOCKER_COMMAND= + fi + + export _USE_UNIX_SOCKET= + if [ -z "$_USE_DOCKER_COMMAND" ]; then + export _USE_REST= + if [ "$DOCKER_HOST" ]; then + _debug "Try use docker host: $DOCKER_HOST" + export _USE_REST=1 + else + export _DOCKER_SOCK="$_DOCKER_HOST_DEFAULT" + _debug "Try use $_DOCKER_SOCK" + if [ ! -e "$_DOCKER_SOCK" ] || [ ! -w "$_DOCKER_SOCK" ]; then + _err "$_DOCKER_SOCK is not available" + return 1 + fi + export _USE_UNIX_SOCKET=1 + if ! _exists "curl"; then + _err "Please install curl first." + _err "We need curl to work." + return 1 + fi + if ! _check_curl_version; then + return 1 + fi + fi + fi + + _getdeployconf DEPLOY_DOCKER_CONTAINER_KEY_FILE + _debug2 DEPLOY_DOCKER_CONTAINER_KEY_FILE "$DEPLOY_DOCKER_CONTAINER_KEY_FILE" + if [ "$DEPLOY_DOCKER_CONTAINER_KEY_FILE" ]; then + _savedeployconf DEPLOY_DOCKER_CONTAINER_KEY_FILE "$DEPLOY_DOCKER_CONTAINER_KEY_FILE" + fi + + _getdeployconf DEPLOY_DOCKER_CONTAINER_CERT_FILE + _debug2 DEPLOY_DOCKER_CONTAINER_CERT_FILE "$DEPLOY_DOCKER_CONTAINER_CERT_FILE" + if [ "$DEPLOY_DOCKER_CONTAINER_CERT_FILE" ]; then + _savedeployconf DEPLOY_DOCKER_CONTAINER_CERT_FILE "$DEPLOY_DOCKER_CONTAINER_CERT_FILE" + fi + + _getdeployconf DEPLOY_DOCKER_CONTAINER_CA_FILE + _debug2 DEPLOY_DOCKER_CONTAINER_CA_FILE "$DEPLOY_DOCKER_CONTAINER_CA_FILE" + if [ "$DEPLOY_DOCKER_CONTAINER_CA_FILE" ]; then + _savedeployconf DEPLOY_DOCKER_CONTAINER_CA_FILE "$DEPLOY_DOCKER_CONTAINER_CA_FILE" + fi + + _getdeployconf DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE + _debug2 DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE" + if [ "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE" ]; then + _savedeployconf DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE" + fi + + _getdeployconf DEPLOY_DOCKER_CONTAINER_RELOAD_CMD + _debug2 DEPLOY_DOCKER_CONTAINER_RELOAD_CMD "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" + if [ "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" ]; then + _savedeployconf DEPLOY_DOCKER_CONTAINER_RELOAD_CMD "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" "base64" + fi + + _cid="$(_get_id "$DEPLOY_DOCKER_CONTAINER_LABEL")" + _info "Container id: $_cid" + if [ -z "$_cid" ]; then + _err "can not find container id" + return 1 + fi + + if [ "$DEPLOY_DOCKER_CONTAINER_KEY_FILE" ]; then + if ! _docker_cp "$_cid" "$_ckey" "$DEPLOY_DOCKER_CONTAINER_KEY_FILE"; then + return 1 + fi + fi + + if [ "$DEPLOY_DOCKER_CONTAINER_CERT_FILE" ]; then + if ! _docker_cp "$_cid" "$_ccert" "$DEPLOY_DOCKER_CONTAINER_CERT_FILE"; then + return 1 + fi + fi + + if [ "$DEPLOY_DOCKER_CONTAINER_CA_FILE" ]; then + if ! _docker_cp "$_cid" "$_cca" "$DEPLOY_DOCKER_CONTAINER_CA_FILE"; then + return 1 + fi + fi + + if [ "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE" ]; then + if ! _docker_cp "$_cid" "$_cfullchain" "$DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE"; then + return 1 + fi + fi + + if [ "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" ]; then + _info "Reloading: $DEPLOY_DOCKER_CONTAINER_RELOAD_CMD" + if ! _docker_exec "$_cid" "$DEPLOY_DOCKER_CONTAINER_RELOAD_CMD"; then + return 1 + fi + fi + return 0 +} + +#label +_get_id() { + _label="$1" + if [ "$_USE_DOCKER_COMMAND" ]; then + docker ps -f label="$_label" --format "{{.ID}}" + elif [ "$_USE_REST" ]; then + _err "Not implemented yet." + return 1 + elif [ "$_USE_UNIX_SOCKET" ]; then + _req="{\"label\":[\"$_label\"]}" + _debug2 _req "$_req" + _req="$(printf "%s" "$_req" | _url_encode)" + _debug2 _req "$_req" + listjson="$(_curl_unix_sock "${_DOCKER_SOCK:-$_DOCKER_HOST_DEFAULT}" GET "/containers/json?filters=$_req")" + _debug2 "listjson" "$listjson" + echo "$listjson" | tr '{,' '\n' | grep -i '"id":' | _head_n 1 | cut -d '"' -f 4 + else + _err "Not implemented yet." + return 1 + fi +} + +#id cmd +_docker_exec() { + _eargs="$*" + _debug2 "_docker_exec $_eargs" + _dcid="$1" + shift + if [ "$_USE_DOCKER_COMMAND" ]; then + docker exec -i "$_dcid" sh -c "$*" + elif [ "$_USE_REST" ]; then + _err "Not implemented yet." + return 1 + elif [ "$_USE_UNIX_SOCKET" ]; then + _cmd="$*" + #_cmd="$(printf "%s" "$_cmd" | sed 's/ /","/g')" + _debug2 _cmd "$_cmd" + #create exec instance: + cjson="$(_curl_unix_sock "$_DOCKER_SOCK" POST "/containers/$_dcid/exec" "{\"Cmd\": [\"sh\", \"-c\", \"$_cmd\"]}")" + _debug2 cjson "$cjson" + execid="$(echo "$cjson" | cut -d '"' -f 4)" + _debug execid "$execid" + ejson="$(_curl_unix_sock "$_DOCKER_SOCK" POST "/exec/$execid/start" "{\"Detach\": false,\"Tty\": false}")" + _debug2 ejson "$ejson" + if [ "$ejson" ]; then + _err "$ejson" + return 1 + fi + else + _err "Not implemented yet." + return 1 + fi +} + +#id from to +_docker_cp() { + _dcid="$1" + _from="$2" + _to="$3" + _info "Copying file from $_from to $_to" + _dir="$(dirname "$_to")" + _debug2 _dir "$_dir" + if ! _docker_exec "$_dcid" mkdir -p "$_dir"; then + _err "Can not create dir: $_dir" + return 1 + fi + if [ "$_USE_DOCKER_COMMAND" ]; then + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then + _docker_exec "$_dcid" tee "$_to" <"$_from" + else + _docker_exec "$_dcid" tee "$_to" <"$_from" >/dev/null + fi + if [ "$?" = "0" ]; then + _info "Success" + return 0 + else + _info "Error" + return 1 + fi + elif [ "$_USE_REST" ]; then + _err "Not implemented yet." + return 1 + elif [ "$_USE_UNIX_SOCKET" ]; then + _frompath="$_from" + if _startswith "$_frompath" '/'; then + _frompath="$(echo "$_from" | cut -b 2-)" #remove the first '/' char + fi + _debug2 "_frompath" "$_frompath" + _toname="$(basename "$_to")" + _debug2 "_toname" "$_toname" + _debug2 "_from" "$_from" + if ! tar --transform="s,$(printf "%s" "$_frompath" | tr '*' .),$_toname," -cz "$_from" 2>/dev/null | _curl_unix_sock "$_DOCKER_SOCK" PUT "/containers/$_dcid/archive?noOverwriteDirNonDir=1&path=$(printf "%s" "$_dir" | _url_encode)" '@-' "Content-Type: application/octet-stream"; then + _err "copy error" + return 1 + fi + return 0 + else + _err "Not implemented yet." + return 1 + fi + +} + +#sock method endpoint data content-type +_curl_unix_sock() { + _socket="$1" + _method="$2" + _endpoint="$3" + _data="$4" + _ctype="$5" + if [ -z "$_ctype" ]; then + _ctype="Content-Type: application/json" + fi + _debug _data "$_data" + _debug2 "url" "http://localhost$_endpoint" + if [ "$_CURL_NO_HOST" ]; then + _cux_url="http:$_endpoint" + else + _cux_url="http://localhost$_endpoint" + fi + + if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then + curl -vvv --silent --unix-socket "$_socket" -X "$_method" --data-binary "$_data" --header "$_ctype" "$_cux_url" + else + curl --silent --unix-socket "$_socket" -X "$_method" --data-binary "$_data" --header "$_ctype" "$_cux_url" + fi + +} + +_check_curl_version() { + _cversion="$(curl -V | grep '^curl ' | cut -d ' ' -f 2)" + _debug2 "_cversion" "$_cversion" + + _major="$(_getfield "$_cversion" 1 '.')" + _debug2 "_major" "$_major" + + _minor="$(_getfield "$_cversion" 2 '.')" + _debug2 "_minor" "$_minor" + + if [ "$_major$_minor" -lt "740" ]; then + _err "curl v$_cversion doesn't support unit socket" + return 1 + fi + if [ "$_major$_minor" -lt "750" ]; then + _debug "Use short host name" + export _CURL_NO_HOST=1 + else + export _CURL_NO_HOST= + fi + return 0 +} diff --git a/letsencrypt/deploy/dovecot.sh b/letsencrypt/deploy/dovecot.sh new file mode 100644 index 00000000..f06c8f5b --- /dev/null +++ b/letsencrypt/deploy/dovecot.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +#Here is a script to deploy cert to dovecot server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +dovecot_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "Not implemented yet" + return 1 + +} diff --git a/letsencrypt/deploy/exim4.sh b/letsencrypt/deploy/exim4.sh new file mode 100644 index 00000000..27d9048e --- /dev/null +++ b/letsencrypt/deploy/exim4.sh @@ -0,0 +1,114 @@ +#!/bin/bash + +#Here is a script to deploy cert to exim4 server. + +#returns 0 means success, otherwise error. + +#DEPLOY_EXIM4_CONF="/etc/exim/exim.conf" +#DEPLOY_EXIM4_RELOAD="service exim4 restart" + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +exim4_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _ssl_path="/etc/acme.sh/exim4" + if ! mkdir -p "$_ssl_path"; then + _err "Can not create folder:$_ssl_path" + return 1 + fi + + _info "Copying key and cert" + _real_key="$_ssl_path/exim4.key" + if ! cat "$_ckey" >"$_real_key"; then + _err "Error: write key file to: $_real_key" + return 1 + fi + _real_fullchain="$_ssl_path/exim4.pem" + if ! cat "$_cfullchain" >"$_real_fullchain"; then + _err "Error: write key file to: $_real_fullchain" + return 1 + fi + + DEFAULT_EXIM4_RELOAD="service exim4 restart" + _reload="${DEPLOY_EXIM4_RELOAD:-$DEFAULT_EXIM4_RELOAD}" + + if [ -z "$IS_RENEW" ]; then + DEFAULT_EXIM4_CONF="/etc/exim/exim.conf" + if [ ! -f "$DEFAULT_EXIM4_CONF" ]; then + DEFAULT_EXIM4_CONF="/etc/exim4/exim4.conf.template" + fi + _exim4_conf="${DEPLOY_EXIM4_CONF:-$DEFAULT_EXIM4_CONF}" + _debug _exim4_conf "$_exim4_conf" + if [ ! -f "$_exim4_conf" ]; then + if [ -z "$DEPLOY_EXIM4_CONF" ]; then + _err "exim4 conf is not found, please define DEPLOY_EXIM4_CONF" + return 1 + else + _err "It seems that the specified exim4 conf is not valid, please check." + return 1 + fi + fi + if [ ! -w "$_exim4_conf" ]; then + _err "The file $_exim4_conf is not writable, please change the permission." + return 1 + fi + _backup_conf="$DOMAIN_BACKUP_PATH/exim4.conf.bak" + _info "Backup $_exim4_conf to $_backup_conf" + cp "$_exim4_conf" "$_backup_conf" + + _info "Modify exim4 conf: $_exim4_conf" + if _setopt "$_exim4_conf" "tls_certificate" "=" "$_real_fullchain" && + _setopt "$_exim4_conf" "tls_privatekey" "=" "$_real_key"; then + _info "Set config success!" + else + _err "Config exim4 server error, please report bug to us." + _info "Restoring exim4 conf" + if cat "$_backup_conf" >"$_exim4_conf"; then + _info "Restore conf success" + eval "$_reload" + else + _err "Oops, error restore exim4 conf, please report bug to us." + fi + return 1 + fi + fi + + _info "Run reload: $_reload" + if eval "$_reload"; then + _info "Reload success!" + if [ "$DEPLOY_EXIM4_CONF" ]; then + _savedomainconf DEPLOY_EXIM4_CONF "$DEPLOY_EXIM4_CONF" + else + _cleardomainconf DEPLOY_EXIM4_CONF + fi + if [ "$DEPLOY_EXIM4_RELOAD" ]; then + _savedomainconf DEPLOY_EXIM4_RELOAD "$DEPLOY_EXIM4_RELOAD" + else + _cleardomainconf DEPLOY_EXIM4_RELOAD + fi + return 0 + else + _err "Reload error, restoring" + if cat "$_backup_conf" >"$_exim4_conf"; then + _info "Restore conf success" + eval "$_reload" + else + _err "Oops, error restore exim4 conf, please report bug to us." + fi + return 1 + fi + return 0 + +} diff --git a/letsencrypt/deploy/fritzbox.sh b/letsencrypt/deploy/fritzbox.sh new file mode 100644 index 00000000..c0c471b6 --- /dev/null +++ b/letsencrypt/deploy/fritzbox.sh @@ -0,0 +1,118 @@ +#!/bin/bash + +#Here is a script to deploy cert to an AVM FRITZ!Box router. + +#returns 0 means success, otherwise error. + +#DEPLOY_FRITZBOX_USERNAME="username" +#DEPLOY_FRITZBOX_PASSWORD="password" +#DEPLOY_FRITZBOX_URL="https://fritz.box" + +# Kudos to wikrie at Github for his FRITZ!Box update script: +# https://gist.github.com/wikrie/f1d5747a714e0a34d0582981f7cb4cfb + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +fritzbox_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + if ! _exists iconv; then + if ! _exists uconv; then + if ! _exists perl; then + _err "iconv or uconv or perl not found" + return 1 + fi + fi + fi + + _fritzbox_username="${DEPLOY_FRITZBOX_USERNAME}" + _fritzbox_password="${DEPLOY_FRITZBOX_PASSWORD}" + _fritzbox_url="${DEPLOY_FRITZBOX_URL}" + + _debug _fritzbox_url "$_fritzbox_url" + _debug _fritzbox_username "$_fritzbox_username" + _secure_debug _fritzbox_password "$_fritzbox_password" + if [ -z "$_fritzbox_username" ]; then + _err "FRITZ!Box username is not found, please define DEPLOY_FRITZBOX_USERNAME." + return 1 + fi + if [ -z "$_fritzbox_password" ]; then + _err "FRITZ!Box password is not found, please define DEPLOY_FRITZBOX_PASSWORD." + return 1 + fi + if [ -z "$_fritzbox_url" ]; then + _err "FRITZ!Box url is not found, please define DEPLOY_FRITZBOX_URL." + return 1 + fi + + _saveaccountconf DEPLOY_FRITZBOX_USERNAME "${_fritzbox_username}" + _saveaccountconf DEPLOY_FRITZBOX_PASSWORD "${_fritzbox_password}" + _saveaccountconf DEPLOY_FRITZBOX_URL "${_fritzbox_url}" + + # Do not check for a valid SSL certificate, because initially the cert is not valid, so it could not install the LE generated certificate + export HTTPS_INSECURE=1 + + _info "Log in to the FRITZ!Box" + _fritzbox_challenge="$(_get "${_fritzbox_url}/login_sid.lua" | sed -e 's/^.*//' -e 's/<\/Challenge>.*$//')" + if _exists iconv; then + _fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | _digest md5 hex)" + elif _exists uconv; then + _fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | uconv -f ASCII -t UTF16LE | _digest md5 hex)" + else + _fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | perl -p -e 'use Encode qw/encode/; print encode("UTF-16LE","$_"); $_="";' | _digest md5 hex)" + fi + _fritzbox_sid="$(_get "${_fritzbox_url}/login_sid.lua?sid=0000000000000000&username=${_fritzbox_username}&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*//' -e 's/<\/SID>.*$//')" + + if [ -z "${_fritzbox_sid}" ] || [ "${_fritzbox_sid}" = "0000000000000000" ]; then + _err "Logging in to the FRITZ!Box failed. Please check username, password and URL." + return 1 + fi + + _info "Generate form POST request" + _post_request="$(_mktemp)" + _post_boundary="---------------------------$(date +%Y%m%d%H%M%S)" + # _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a password. But if they ever do, here's the place to use it! + _CERTPASSWORD_= + { + printf -- "--" + printf -- "%s\r\n" "${_post_boundary}" + printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n%s\r\n" "${_fritzbox_sid}" + printf -- "--" + printf -- "%s\r\n" "${_post_boundary}" + printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n%s\r\n" "${_CERTPASSWORD_}" + printf -- "--" + printf -- "%s\r\n" "${_post_boundary}" + printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n" + printf "Content-Type: application/octet-stream\r\n\r\n" + cat "${_ckey}" "${_cfullchain}" + printf "\r\n" + printf -- "--" + printf -- "%s--" "${_post_boundary}" + } >>"${_post_request}" + + _info "Upload certificate to the FRITZ!Box" + + export _H1="Content-type: multipart/form-data boundary=${_post_boundary}" + _post "$(cat "${_post_request}")" "${_fritzbox_url}/cgi-bin/firmwarecfg" | grep SSL + + retval=$? + if [ $retval = 0 ]; then + _info "Upload successful" + else + _err "Upload failed" + fi + rm "${_post_request}" + + return $retval +} diff --git a/letsencrypt/deploy/gcore_cdn.sh b/letsencrypt/deploy/gcore_cdn.sh new file mode 100644 index 00000000..7de47126 --- /dev/null +++ b/letsencrypt/deploy/gcore_cdn.sh @@ -0,0 +1,139 @@ +#!/bin/bash + +# Here is the script to deploy the cert to G-Core CDN service (https://gcorelabs.com/ru/) using the G-Core Labs API (https://docs.gcorelabs.com/cdn/). +# Returns 0 when success. +# +# Written by temoffey +# Public domain, 2019 + +#export DEPLOY_GCORE_CDN_USERNAME=myusername +#export DEPLOY_GCORE_CDN_PASSWORD=mypassword + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain + +gcore_cdn_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _fullchain=$(tr '\r\n' '*#' <"$_cfullchain" | sed 's/*#/#/g;s/##/#/g;s/#/\\n/g') + _key=$(tr '\r\n' '*#' <"$_ckey" | sed 's/*#/#/g;s/#/\\n/g') + + _debug _fullchain "$_fullchain" + _debug _key "$_key" + + if [ -z "$DEPLOY_GCORE_CDN_USERNAME" ]; then + if [ -z "$Le_Deploy_gcore_cdn_username" ]; then + _err "Please define the target username: export DEPLOY_GCORE_CDN_USERNAME=username" + return 1 + fi + else + Le_Deploy_gcore_cdn_username="$DEPLOY_GCORE_CDN_USERNAME" + _savedomainconf Le_Deploy_gcore_cdn_username "$Le_Deploy_gcore_cdn_username" + fi + + if [ -z "$DEPLOY_GCORE_CDN_PASSWORD" ]; then + if [ -z "$Le_Deploy_gcore_cdn_password" ]; then + _err "Please define the target password: export DEPLOY_GCORE_CDN_PASSWORD=password" + return 1 + fi + else + Le_Deploy_gcore_cdn_password="$DEPLOY_GCORE_CDN_PASSWORD" + _savedomainconf Le_Deploy_gcore_cdn_password "$Le_Deploy_gcore_cdn_password" + fi + + _info "Get authorization token" + _request="{\"username\":\"$Le_Deploy_gcore_cdn_username\",\"password\":\"$Le_Deploy_gcore_cdn_password\"}" + _debug _request "$_request" + export _H1="Content-Type:application/json" + _response=$(_post "$_request" "https://api.gcdn.co/auth/signin") + _debug _response "$_response" + _regex=".*\"token\":\"\([-._0-9A-Za-z]*\)\".*$" + _debug _regex "$_regex" + _token=$(echo "$_response" | sed -n "s/$_regex/\1/p") + _debug _token "$_token" + + if [ -z "$_token" ]; then + _err "Error G-Core Labs API authorization" + return 1 + fi + + _info "Find CDN resource with cname $_cdomain" + export _H2="Authorization:Token $_token" + _response=$(_get "https://api.gcdn.co/resources") + _debug _response "$_response" + _regex=".*(\"id\".*?\"cname\":\"$_cdomain\".*?})" + _regex="^.*\"cname\":\"$_cdomain\".*$" + _debug _regex "$_regex" + _resource=$(echo "$_response" | sed 's/},{/},\n{/g' | _egrep_o "$_regex") + _debug _resource "$_resource" + _regex=".*\"id\":\([0-9]*\).*\"rules\".*$" + _debug _regex "$_regex" + _resourceId=$(echo "$_resource" | sed -n "s/$_regex/\1/p") + _debug _resourceId "$_resourceId" + _regex=".*\"sslData\":\([0-9]*\).*$" + _debug _regex "$_regex" + _sslDataOld=$(echo "$_resource" | sed -n "s/$_regex/\1/p") + _debug _sslDataOld "$_sslDataOld" + _regex=".*\"originGroup\":\([0-9]*\).*$" + _debug _regex "$_regex" + _originGroup=$(echo "$_resource" | sed -n "s/$_regex/\1/p") + _debug _originGroup "$_originGroup" + + if [ -z "$_resourceId" ] || [ -z "$_originGroup" ]; then + _err "Not found CDN resource with cname $_cdomain" + return 1 + fi + + _info "Add new SSL certificate" + _date=$(date "+%d.%m.%Y %H:%M:%S") + _request="{\"name\":\"$_cdomain ($_date)\",\"sslCertificate\":\"$_fullchain\",\"sslPrivateKey\":\"$_key\"}" + _debug _request "$_request" + _response=$(_post "$_request" "https://api.gcdn.co/sslData") + _debug _response "$_response" + _regex=".*\"id\":\([0-9]*\).*$" + _debug _regex "$_regex" + _sslDataAdd=$(echo "$_response" | sed -n "s/$_regex/\1/p") + _debug _sslDataAdd "$_sslDataAdd" + + if [ -z "$_sslDataAdd" ]; then + _err "Error new SSL certificate add" + return 1 + fi + + _info "Update CDN resource" + _request="{\"originGroup\":$_originGroup,\"sslData\":$_sslDataAdd}" + _debug _request "$_request" + _response=$(_post "$_request" "https://api.gcdn.co/resources/$_resourceId" '' "PUT") + _debug _response "$_response" + _regex=".*\"sslData\":\([0-9]*\).*$" + _debug _regex "$_regex" + _sslDataNew=$(echo "$_response" | sed -n "s/$_regex/\1/p") + _debug _sslDataNew "$_sslDataNew" + + if [ "$_sslDataNew" != "$_sslDataAdd" ]; then + _err "Error CDN resource update" + return 1 + fi + + if [ -z "$_sslDataOld" ] || [ "$_sslDataOld" = "null" ]; then + _info "Not found old SSL certificate" + else + _info "Delete old SSL certificate" + _response=$(_post '' "https://api.gcdn.co/sslData/$_sslDataOld" '' "DELETE") + _debug _response "$_response" + fi + + _info "Certificate successfully deployed" + return 0 +} diff --git a/letsencrypt/deploy/gitlab.sh b/letsencrypt/deploy/gitlab.sh new file mode 100644 index 00000000..d9183f6f --- /dev/null +++ b/letsencrypt/deploy/gitlab.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +# Script to deploy certificate to a Gitlab hosted page + +# The following variables exported from environment will be used. +# If not set then values previously saved in domain.conf file are used. + +# All the variables are required + +# export GITLAB_TOKEN="xxxxxxx" +# export GITLAB_PROJECT_ID=012345 +# export GITLAB_DOMAIN="mydomain.com" + +gitlab_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + if [ -z "$GITLAB_TOKEN" ]; then + if [ -z "$Le_Deploy_gitlab_token" ]; then + _err "GITLAB_TOKEN not defined." + return 1 + fi + else + Le_Deploy_gitlab_token="$GITLAB_TOKEN" + _savedomainconf Le_Deploy_gitlab_token "$Le_Deploy_gitlab_token" + fi + + if [ -z "$GITLAB_PROJECT_ID" ]; then + if [ -z "$Le_Deploy_gitlab_project_id" ]; then + _err "GITLAB_PROJECT_ID not defined." + return 1 + fi + else + Le_Deploy_gitlab_project_id="$GITLAB_PROJECT_ID" + _savedomainconf Le_Deploy_gitlab_project_id "$Le_Deploy_gitlab_project_id" + fi + + if [ -z "$GITLAB_DOMAIN" ]; then + if [ -z "$Le_Deploy_gitlab_domain" ]; then + _err "GITLAB_DOMAIN not defined." + return 1 + fi + else + Le_Deploy_gitlab_domain="$GITLAB_DOMAIN" + _savedomainconf Le_Deploy_gitlab_domain "$Le_Deploy_gitlab_domain" + fi + + string_fullchain=$(_url_encode <"$_cfullchain") + string_key=$(_url_encode <"$_ckey") + + body="certificate=$string_fullchain&key=$string_key" + + export _H1="PRIVATE-TOKEN: $Le_Deploy_gitlab_token" + + gitlab_url="https://gitlab.com/api/v4/projects/$Le_Deploy_gitlab_project_id/pages/domains/$Le_Deploy_gitlab_domain" + + _response=$(_post "$body" "$gitlab_url" 0 PUT | _dbase64 "multiline") + + error_response="error" + + if test "${_response#*$error_response}" != "$_response"; then + _err "Error in deploying certificate:" + _err "$_response" + return 1 + fi + + _debug response "$_response" + _info "Certificate successfully deployed" + + return 0 +} diff --git a/letsencrypt/deploy/haproxy.sh b/letsencrypt/deploy/haproxy.sh new file mode 100644 index 00000000..861b75af --- /dev/null +++ b/letsencrypt/deploy/haproxy.sh @@ -0,0 +1,275 @@ +#!/bin/bash + +# Script for acme.sh to deploy certificates to haproxy +# +# The following variables can be exported: +# +# export DEPLOY_HAPROXY_PEM_NAME="${domain}.pem" +# +# Defines the name of the PEM file. +# Defaults to ".pem" +# +# export DEPLOY_HAPROXY_PEM_PATH="/etc/haproxy" +# +# Defines location of PEM file for HAProxy. +# Defaults to /etc/haproxy +# +# export DEPLOY_HAPROXY_RELOAD="systemctl reload haproxy" +# +# OPTIONAL: Reload command used post deploy +# This defaults to be a no-op (ie "true"). +# It is strongly recommended to set this something that makes sense +# for your distro. +# +# export DEPLOY_HAPROXY_ISSUER="no" +# +# OPTIONAL: Places CA file as "${DEPLOY_HAPROXY_PEM}.issuer" +# Note: Required for OCSP stapling to work +# +# export DEPLOY_HAPROXY_BUNDLE="no" +# +# OPTIONAL: Deploy this certificate as part of a multi-cert bundle +# This adds a suffix to the certificate based on the certificate type +# eg RSA certificates will have .rsa as a suffix to the file name +# HAProxy will load all certificates and provide one or the other +# depending on client capabilities +# Note: This functionality requires HAProxy was compiled against +# a version of OpenSSL that supports this. +# + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +haproxy_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + # Some defaults + DEPLOY_HAPROXY_PEM_PATH_DEFAULT="/etc/haproxy" + DEPLOY_HAPROXY_PEM_NAME_DEFAULT="${_cdomain}.pem" + DEPLOY_HAPROXY_BUNDLE_DEFAULT="no" + DEPLOY_HAPROXY_ISSUER_DEFAULT="no" + DEPLOY_HAPROXY_RELOAD_DEFAULT="true" + + if [ -f "${DOMAIN_CONF}" ]; then + # shellcheck disable=SC1090 + . "${DOMAIN_CONF}" + fi + + _debug _cdomain "${_cdomain}" + _debug _ckey "${_ckey}" + _debug _ccert "${_ccert}" + _debug _cca "${_cca}" + _debug _cfullchain "${_cfullchain}" + + # PEM_PATH is optional. If not provided then assume "${DEPLOY_HAPROXY_PEM_PATH_DEFAULT}" + if [ -n "${DEPLOY_HAPROXY_PEM_PATH}" ]; then + Le_Deploy_haproxy_pem_path="${DEPLOY_HAPROXY_PEM_PATH}" + _savedomainconf Le_Deploy_haproxy_pem_path "${Le_Deploy_haproxy_pem_path}" + elif [ -z "${Le_Deploy_haproxy_pem_path}" ]; then + Le_Deploy_haproxy_pem_path="${DEPLOY_HAPROXY_PEM_PATH_DEFAULT}" + fi + + # Ensure PEM_PATH exists + if [ -d "${Le_Deploy_haproxy_pem_path}" ]; then + _debug "PEM_PATH ${Le_Deploy_haproxy_pem_path} exists" + else + _err "PEM_PATH ${Le_Deploy_haproxy_pem_path} does not exist" + return 1 + fi + + # PEM_NAME is optional. If not provided then assume "${DEPLOY_HAPROXY_PEM_NAME_DEFAULT}" + if [ -n "${DEPLOY_HAPROXY_PEM_NAME}" ]; then + Le_Deploy_haproxy_pem_name="${DEPLOY_HAPROXY_PEM_NAME}" + _savedomainconf Le_Deploy_haproxy_pem_name "${Le_Deploy_haproxy_pem_name}" + elif [ -z "${Le_Deploy_haproxy_pem_name}" ]; then + Le_Deploy_haproxy_pem_name="${DEPLOY_HAPROXY_PEM_NAME_DEFAULT}" + fi + + # BUNDLE is optional. If not provided then assume "${DEPLOY_HAPROXY_BUNDLE_DEFAULT}" + if [ -n "${DEPLOY_HAPROXY_BUNDLE}" ]; then + Le_Deploy_haproxy_bundle="${DEPLOY_HAPROXY_BUNDLE}" + _savedomainconf Le_Deploy_haproxy_bundle "${Le_Deploy_haproxy_bundle}" + elif [ -z "${Le_Deploy_haproxy_bundle}" ]; then + Le_Deploy_haproxy_bundle="${DEPLOY_HAPROXY_BUNDLE_DEFAULT}" + fi + + # ISSUER is optional. If not provided then assume "${DEPLOY_HAPROXY_ISSUER_DEFAULT}" + if [ -n "${DEPLOY_HAPROXY_ISSUER}" ]; then + Le_Deploy_haproxy_issuer="${DEPLOY_HAPROXY_ISSUER}" + _savedomainconf Le_Deploy_haproxy_issuer "${Le_Deploy_haproxy_issuer}" + elif [ -z "${Le_Deploy_haproxy_issuer}" ]; then + Le_Deploy_haproxy_issuer="${DEPLOY_HAPROXY_ISSUER_DEFAULT}" + fi + + # RELOAD is optional. If not provided then assume "${DEPLOY_HAPROXY_RELOAD_DEFAULT}" + if [ -n "${DEPLOY_HAPROXY_RELOAD}" ]; then + Le_Deploy_haproxy_reload="${DEPLOY_HAPROXY_RELOAD}" + _savedomainconf Le_Deploy_haproxy_reload "${Le_Deploy_haproxy_reload}" + elif [ -z "${Le_Deploy_haproxy_reload}" ]; then + Le_Deploy_haproxy_reload="${DEPLOY_HAPROXY_RELOAD_DEFAULT}" + fi + + # Set the suffix depending if we are creating a bundle or not + if [ "${Le_Deploy_haproxy_bundle}" = "yes" ]; then + _info "Bundle creation requested" + # Initialise $Le_Keylength if its not already set + if [ -z "${Le_Keylength}" ]; then + Le_Keylength="" + fi + if _isEccKey "${Le_Keylength}"; then + _info "ECC key type detected" + _suffix=".ecdsa" + else + _info "RSA key type detected" + _suffix=".rsa" + fi + else + _suffix="" + fi + _debug _suffix "${_suffix}" + + # Set variables for later + _pem="${Le_Deploy_haproxy_pem_path}/${Le_Deploy_haproxy_pem_name}${_suffix}" + _issuer="${_pem}.issuer" + _ocsp="${_pem}.ocsp" + _reload="${Le_Deploy_haproxy_reload}" + + _info "Deploying PEM file" + # Create a temporary PEM file + _temppem="$(_mktemp)" + _debug _temppem "${_temppem}" + cat "${_ckey}" "${_ccert}" "${_cca}" >"${_temppem}" + _ret="$?" + + # Check that we could create the temporary file + if [ "${_ret}" != "0" ]; then + _err "Error code ${_ret} returned during PEM file creation" + [ -f "${_temppem}" ] && rm -f "${_temppem}" + return ${_ret} + fi + + # Move PEM file into place + _info "Moving new certificate into place" + _debug _pem "${_pem}" + cat "${_temppem}" >"${_pem}" + _ret=$? + + # Clean up temp file + [ -f "${_temppem}" ] && rm -f "${_temppem}" + + # Deal with any failure of moving PEM file into place + if [ "${_ret}" != "0" ]; then + _err "Error code ${_ret} returned while moving new certificate into place" + return ${_ret} + fi + + # Update .issuer file if requested + if [ "${Le_Deploy_haproxy_issuer}" = "yes" ]; then + _info "Updating .issuer file" + _debug _issuer "${_issuer}" + cat "${_cca}" >"${_issuer}" + _ret="$?" + + if [ "${_ret}" != "0" ]; then + _err "Error code ${_ret} returned while copying issuer/CA certificate into place" + return ${_ret} + fi + else + [ -f "${_issuer}" ] && _err "Issuer file update not requested but .issuer file exists" + fi + + # Update .ocsp file if certificate was requested with --ocsp/--ocsp-must-staple option + if [ -z "${Le_OCSP_Staple}" ]; then + Le_OCSP_Staple="0" + fi + if [ "${Le_OCSP_Staple}" = "1" ]; then + _info "Updating OCSP stapling info" + _debug _ocsp "${_ocsp}" + _info "Extracting OCSP URL" + _ocsp_url=$(openssl x509 -noout -ocsp_uri -in "${_pem}") + _debug _ocsp_url "${_ocsp_url}" + + # Only process OCSP if URL was present + if [ "${_ocsp_url}" != "" ]; then + # Extract the hostname from the OCSP URL + _info "Extracting OCSP URL" + _ocsp_host=$(echo "${_ocsp_url}" | cut -d/ -f3) + _debug _ocsp_host "${_ocsp_host}" + + # Only process the certificate if we have a .issuer file + if [ -r "${_issuer}" ]; then + # Check if issuer cert is also a root CA cert + _subjectdn=$(openssl x509 -in "${_issuer}" -subject -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10) + _debug _subjectdn "${_subjectdn}" + _issuerdn=$(openssl x509 -in "${_issuer}" -issuer -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10) + _debug _issuerdn "${_issuerdn}" + _info "Requesting OCSP response" + # If the issuer is a CA cert then our command line has "-CAfile" added + if [ "${_subjectdn}" = "${_issuerdn}" ]; then + _cafile_argument="-CAfile \"${_issuer}\"" + else + _cafile_argument="" + fi + _debug _cafile_argument "${_cafile_argument}" + # if OpenSSL/LibreSSL is v1.1 or above, the format for the -header option has changed + _openssl_version=$(openssl version | cut -d' ' -f2) + _debug _openssl_version "${_openssl_version}" + _openssl_major=$(echo "${_openssl_version}" | cut -d '.' -f1) + _openssl_minor=$(echo "${_openssl_version}" | cut -d '.' -f2) + if [ "${_openssl_major}" -eq "1" ] && [ "${_openssl_minor}" -ge "1" ] || [ "${_openssl_major}" -ge "2" ]; then + _header_sep="=" + else + _header_sep=" " + fi + # Request the OCSP response from the issuer and store it + _openssl_ocsp_cmd="openssl ocsp \ + -issuer \"${_issuer}\" \ + -cert \"${_pem}\" \ + -url \"${_ocsp_url}\" \ + -header Host${_header_sep}\"${_ocsp_host}\" \ + -respout \"${_ocsp}\" \ + -verify_other \"${_issuer}\" \ + ${_cafile_argument} \ + | grep -q \"${_pem}: good\"" + _debug _openssl_ocsp_cmd "${_openssl_ocsp_cmd}" + eval "${_openssl_ocsp_cmd}" + _ret=$? + else + # Non fatal: No issuer file was present so no OCSP stapling file created + _err "OCSP stapling in use but no .issuer file was present" + fi + else + # Non fatal: No OCSP url was found int the certificate + _err "OCSP update requested but no OCSP URL was found in certificate" + fi + + # Non fatal: Check return code of openssl command + if [ "${_ret}" != "0" ]; then + _err "Updating OCSP stapling failed with return code ${_ret}" + fi + else + # An OCSP file was already present but certificate did not have OCSP extension + if [ -f "${_ocsp}" ]; then + _err "OCSP was not requested but .ocsp file exists." + # Could remove the file at this step, although HAProxy just ignores it in this case + # rm -f "${_ocsp}" || _err "Problem removing stale .ocsp file" + fi + fi + + # Reload HAProxy + _debug _reload "${_reload}" + eval "${_reload}" + _ret=$? + if [ "${_ret}" != "0" ]; then + _err "Error code ${_ret} during reload" + return ${_ret} + else + _info "Reload successful" + fi + + return 0 +} diff --git a/letsencrypt/deploy/keychain.sh b/letsencrypt/deploy/keychain.sh new file mode 100644 index 00000000..b8545d5f --- /dev/null +++ b/letsencrypt/deploy/keychain.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +keychain_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + /usr/bin/security import "$_ckey" -k "/Library/Keychains/System.keychain" + /usr/bin/security import "$_ccert" -k "/Library/Keychains/System.keychain" + /usr/bin/security import "$_cca" -k "/Library/Keychains/System.keychain" + /usr/bin/security import "$_cfullchain" -k "/Library/Keychains/System.keychain" + + return 0 +} diff --git a/letsencrypt/deploy/kong.sh b/letsencrypt/deploy/kong.sh new file mode 100755 index 00000000..1a9c4184 --- /dev/null +++ b/letsencrypt/deploy/kong.sh @@ -0,0 +1,77 @@ +#!/bin/bash +# If certificate already exists it will update only cert and key, not touching other parameters +# If certificate doesn't exist it will only upload cert and key, and not set other parameters +# Note that we deploy full chain +# Written by Geoffroi Genot + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +kong_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + _info "Deploying certificate on Kong instance" + if [ -z "$KONG_URL" ]; then + _debug "KONG_URL Not set, using default http://localhost:8001" + KONG_URL="http://localhost:8001" + fi + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + #Get ssl_uuid linked to the domain + ssl_uuid=$(_get "$KONG_URL/certificates/$_cdomain" | _normalizeJson | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') + if [ -z "$ssl_uuid" ]; then + _debug "Unable to get Kong ssl_uuid for domain $_cdomain" + _debug "Make sure that KONG_URL is correctly configured" + _debug "Make sure that a Kong certificate match the sni" + _debug "Kong url: $KONG_URL" + _info "No existing certificate, creating..." + #return 1 + fi + #Save kong url if it's succesful (First run case) + _saveaccountconf KONG_URL "$KONG_URL" + #Generate DEIM + delim="-----MultipartDelimiter$(date "+%s%N")" + nl="\015\012" + #Set Header + _H1="Content-Type: multipart/form-data; boundary=$delim" + #Generate data for request (Multipart/form-data with mixed content) + if [ -z "$ssl_uuid" ]; then + #set sni to domain + content="--$delim${nl}Content-Disposition: form-data; name=\"snis\"${nl}${nl}$_cdomain" + fi + #add key + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")" + #Add cert + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"cert\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")" + #Close multipart + content="$content${nl}--$delim--${nl}" + #Convert CRLF + content=$(printf %b "$content") + #DEBUG + _debug header "$_H1" + _debug content "$content" + #Check if sslcreated (if not => POST else => PATCH) + + if [ -z "$ssl_uuid" ]; then + #Post certificate to Kong + response=$(_post "$content" "$KONG_URL/certificates" "" "POST") + else + #patch + response=$(_post "$content" "$KONG_URL/certificates/$ssl_uuid" "" "PATCH") + fi + if ! [ "$(echo "$response" | _egrep_o "created_at")" = "created_at" ]; then + _err "An error occurred with cert upload. Check response:" + _err "$response" + return 1 + fi + _debug response "$response" + _info "Certificate successfully deployed" +} diff --git a/letsencrypt/deploy/mailcow.sh b/letsencrypt/deploy/mailcow.sh new file mode 100644 index 00000000..fc0379ec --- /dev/null +++ b/letsencrypt/deploy/mailcow.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +#Here is a script to deploy cert to mailcow. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +mailcow_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _mailcow_path="${DEPLOY_MAILCOW_PATH}" + + if [ -z "$_mailcow_path" ]; then + _err "Mailcow path is not found, please define DEPLOY_MAILCOW_PATH." + return 1 + fi + + _ssl_path="${_mailcow_path}/data/assets/ssl/" + if [ ! -d "$_ssl_path" ]; then + _err "Cannot find mailcow ssl path: $_ssl_path" + return 1 + fi + + _info "Copying key and cert" + _real_key="$_ssl_path/key.pem" + if ! cat "$_ckey" >"$_real_key"; then + _err "Error: write key file to: $_real_key" + return 1 + fi + + _real_fullchain="$_ssl_path/cert.pem" + if ! cat "$_cfullchain" >"$_real_fullchain"; then + _err "Error: write cert file to: $_real_fullchain" + return 1 + fi + + DEFAULT_MAILCOW_RELOAD="cd ${_mailcow_path} && docker-compose restart postfix-mailcow dovecot-mailcow nginx-mailcow" + _reload="${DEPLOY_MAILCOW_RELOAD:-$DEFAULT_MAILCOW_RELOAD}" + + _info "Run reload: $_reload" + if eval "$_reload"; then + _info "Reload success!" + fi + return 0 + +} diff --git a/letsencrypt/deploy/myapi.sh b/letsencrypt/deploy/myapi.sh new file mode 100755 index 00000000..cf2b2db7 --- /dev/null +++ b/letsencrypt/deploy/myapi.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +#Here is a sample custom api script. +#This file name is "myapi.sh" +#So, here must be a method myapi_deploy() +#Which will be called by acme.sh to deploy the cert +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +myapi_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "Not implemented yet" + return 1 + +} diff --git a/letsencrypt/deploy/mydevil.sh b/letsencrypt/deploy/mydevil.sh new file mode 100755 index 00000000..974a4c51 --- /dev/null +++ b/letsencrypt/deploy/mydevil.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +# MyDevil.net API (2019-02-03) +# +# MyDevil.net already supports automatic Let's Encrypt certificates, +# except for wildcard domains. +# +# This script depends on `devil` command that MyDevil.net provides, +# which means that it works only on server side. +# +# Author: Marcin Konicki +# +######## Public functions ##################### + +# Usage: mydevil_deploy domain keyfile certfile cafile fullchain +mydevil_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + ip="" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + if ! _exists "devil"; then + _err "Could not find 'devil' command." + return 1 + fi + + ip=$(mydevil_get_ip "$_cdomain") + if [ -z "$ip" ]; then + _err "Could not find IP for domain $_cdomain." + return 1 + fi + + # Delete old certificate first + _info "Removing old certificate for $_cdomain at $ip" + devil ssl www del "$ip" "$_cdomain" + + # Add new certificate + _info "Adding new certificate for $_cdomain at $ip" + devil ssl www add "$ip" "$_cfullchain" "$_ckey" "$_cdomain" || return 1 + + return 0 +} + +#################### Private functions below ################################## + +# Usage: ip=$(mydevil_get_ip domain.com) +# echo $ip +mydevil_get_ip() { + devil dns list "$1" | cut -w -s -f 3,7 | grep "^A$(printf '\t')" | cut -w -s -f 2 || return 1 + return 0 +} diff --git a/letsencrypt/deploy/mysqld.sh b/letsencrypt/deploy/mysqld.sh new file mode 100644 index 00000000..97157d0c --- /dev/null +++ b/letsencrypt/deploy/mysqld.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +#Here is a script to deploy cert to mysqld server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +mysqld_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to mysqld server, Not implemented yet" + return 1 + +} diff --git a/letsencrypt/deploy/nginx.sh b/letsencrypt/deploy/nginx.sh new file mode 100644 index 00000000..a4e9de45 --- /dev/null +++ b/letsencrypt/deploy/nginx.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +#Here is a script to deploy cert to nginx server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +nginx_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to nginx server, Not implemented yet" + return 1 + +} diff --git a/letsencrypt/deploy/opensshd.sh b/letsencrypt/deploy/opensshd.sh new file mode 100644 index 00000000..3c14d661 --- /dev/null +++ b/letsencrypt/deploy/opensshd.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +#Here is a script to deploy cert to opensshd server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +opensshd_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to opensshd server, Not implemented yet" + return 1 + +} diff --git a/letsencrypt/deploy/openstack.sh b/letsencrypt/deploy/openstack.sh new file mode 100644 index 00000000..69d9b543 --- /dev/null +++ b/letsencrypt/deploy/openstack.sh @@ -0,0 +1,262 @@ +#!/bin/bash + +# OpenStack Barbican deploy hook +# +# This requires you to have OpenStackClient and python-barbicanclient +# installed. +# +# You will require Keystone V3 credentials loaded into your environment, which +# could be either password or v3applicationcredential type. +# +# Author: Andy Botting + +openstack_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + if ! _exists openstack; then + _err "OpenStack client not found" + return 1 + fi + + _openstack_credentials || return $? + + _info "Generate import pkcs12" + _import_pkcs12="$(_mktemp)" + if ! _openstack_to_pkcs "$_import_pkcs12" "$_ckey" "$_ccert" "$_cca"; then + _err "Error creating pkcs12 certificate" + return 1 + fi + _debug _import_pkcs12 "$_import_pkcs12" + _base64_pkcs12=$(_base64 "multiline" <"$_import_pkcs12") + + secretHrefs=$(_openstack_get_secrets) + _debug secretHrefs "$secretHrefs" + _openstack_store_secret || return $? + + if [ -n "$secretHrefs" ]; then + _info "Cleaning up existing secret" + _openstack_delete_secrets || return $? + fi + + _info "Certificate successfully deployed" + return 0 +} + +_openstack_store_secret() { + if ! openstack secret store --name "$_cdomain." -t 'application/octet-stream' -e base64 --payload "$_base64_pkcs12"; then + _err "Failed to create OpenStack secret" + return 1 + fi + return +} + +_openstack_delete_secrets() { + echo "$secretHrefs" | while read -r secretHref; do + _info "Deleting old secret $secretHref" + if ! openstack secret delete "$secretHref"; then + _err "Failed to delete OpenStack secret" + return 1 + fi + done + return +} + +_openstack_get_secrets() { + if ! secretHrefs=$(openstack secret list -f value --name "$_cdomain." | cut -d' ' -f1); then + _err "Failed to list secrets" + return 1 + fi + echo "$secretHrefs" +} + +_openstack_to_pkcs() { + # The existing _toPkcs command can't allow an empty password, due to sh + # -z test, so copied here and forcing the empty password. + _cpfx="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + + ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:" +} + +_openstack_credentials() { + _debug "Check OpenStack credentials" + + # If we have OS_AUTH_URL already set in the environment, then assume we want + # to use those, otherwise use stored credentials + if [ -n "$OS_AUTH_URL" ]; then + _debug "OS_AUTH_URL env var found, using environment" + else + _debug "OS_AUTH_URL not found, loading stored credentials" + OS_AUTH_URL="${OS_AUTH_URL:-$(_readaccountconf_mutable OS_AUTH_URL)}" + OS_IDENTITY_API_VERSION="${OS_IDENTITY_API_VERSION:-$(_readaccountconf_mutable OS_IDENTITY_API_VERSION)}" + OS_AUTH_TYPE="${OS_AUTH_TYPE:-$(_readaccountconf_mutable OS_AUTH_TYPE)}" + OS_APPLICATION_CREDENTIAL_ID="${OS_APPLICATION_CREDENTIAL_ID:-$(_readaccountconf_mutable OS_APPLICATION_CREDENTIAL_ID)}" + OS_APPLICATION_CREDENTIAL_SECRET="${OS_APPLICATION_CREDENTIAL_SECRET:-$(_readaccountconf_mutable OS_APPLICATION_CREDENTIAL_SECRET)}" + OS_USERNAME="${OS_USERNAME:-$(_readaccountconf_mutable OS_USERNAME)}" + OS_PASSWORD="${OS_PASSWORD:-$(_readaccountconf_mutable OS_PASSWORD)}" + OS_PROJECT_NAME="${OS_PROJECT_NAME:-$(_readaccountconf_mutable OS_PROJECT_NAME)}" + OS_PROJECT_ID="${OS_PROJECT_ID:-$(_readaccountconf_mutable OS_PROJECT_ID)}" + OS_USER_DOMAIN_NAME="${OS_USER_DOMAIN_NAME:-$(_readaccountconf_mutable OS_USER_DOMAIN_NAME)}" + OS_USER_DOMAIN_ID="${OS_USER_DOMAIN_ID:-$(_readaccountconf_mutable OS_USER_DOMAIN_ID)}" + OS_PROJECT_DOMAIN_NAME="${OS_PROJECT_DOMAIN_NAME:-$(_readaccountconf_mutable OS_PROJECT_DOMAIN_NAME)}" + OS_PROJECT_DOMAIN_ID="${OS_PROJECT_DOMAIN_ID:-$(_readaccountconf_mutable OS_PROJECT_DOMAIN_ID)}" + fi + + # Check each var and either save or clear it depending on whether its set. + # The helps us clear out old vars in the case where a user may want + # to switch between password and app creds + _debug "OS_AUTH_URL" "$OS_AUTH_URL" + if [ -n "$OS_AUTH_URL" ]; then + export OS_AUTH_URL + _saveaccountconf_mutable OS_AUTH_URL "$OS_AUTH_URL" + else + unset OS_AUTH_URL + _clearaccountconf SAVED_OS_AUTH_URL + fi + + _debug "OS_IDENTITY_API_VERSION" "$OS_IDENTITY_API_VERSION" + if [ -n "$OS_IDENTITY_API_VERSION" ]; then + export OS_IDENTITY_API_VERSION + _saveaccountconf_mutable OS_IDENTITY_API_VERSION "$OS_IDENTITY_API_VERSION" + else + unset OS_IDENTITY_API_VERSION + _clearaccountconf SAVED_OS_IDENTITY_API_VERSION + fi + + _debug "OS_AUTH_TYPE" "$OS_AUTH_TYPE" + if [ -n "$OS_AUTH_TYPE" ]; then + export OS_AUTH_TYPE + _saveaccountconf_mutable OS_AUTH_TYPE "$OS_AUTH_TYPE" + else + unset OS_AUTH_TYPE + _clearaccountconf SAVED_OS_AUTH_TYPE + fi + + _debug "OS_APPLICATION_CREDENTIAL_ID" "$OS_APPLICATION_CREDENTIAL_ID" + if [ -n "$OS_APPLICATION_CREDENTIAL_ID" ]; then + export OS_APPLICATION_CREDENTIAL_ID + _saveaccountconf_mutable OS_APPLICATION_CREDENTIAL_ID "$OS_APPLICATION_CREDENTIAL_ID" + else + unset OS_APPLICATION_CREDENTIAL_ID + _clearaccountconf SAVED_OS_APPLICATION_CREDENTIAL_ID + fi + + _secure_debug "OS_APPLICATION_CREDENTIAL_SECRET" "$OS_APPLICATION_CREDENTIAL_SECRET" + if [ -n "$OS_APPLICATION_CREDENTIAL_SECRET" ]; then + export OS_APPLICATION_CREDENTIAL_SECRET + _saveaccountconf_mutable OS_APPLICATION_CREDENTIAL_SECRET "$OS_APPLICATION_CREDENTIAL_SECRET" + else + unset OS_APPLICATION_CREDENTIAL_SECRET + _clearaccountconf SAVED_OS_APPLICATION_CREDENTIAL_SECRET + fi + + _debug "OS_USERNAME" "$OS_USERNAME" + if [ -n "$OS_USERNAME" ]; then + export OS_USERNAME + _saveaccountconf_mutable OS_USERNAME "$OS_USERNAME" + else + unset OS_USERNAME + _clearaccountconf SAVED_OS_USERNAME + fi + + _secure_debug "OS_PASSWORD" "$OS_PASSWORD" + if [ -n "$OS_PASSWORD" ]; then + export OS_PASSWORD + _saveaccountconf_mutable OS_PASSWORD "$OS_PASSWORD" + else + unset OS_PASSWORD + _clearaccountconf SAVED_OS_PASSWORD + fi + + _debug "OS_PROJECT_NAME" "$OS_PROJECT_NAME" + if [ -n "$OS_PROJECT_NAME" ]; then + export OS_PROJECT_NAME + _saveaccountconf_mutable OS_PROJECT_NAME "$OS_PROJECT_NAME" + else + unset OS_PROJECT_NAME + _clearaccountconf SAVED_OS_PROJECT_NAME + fi + + _debug "OS_PROJECT_ID" "$OS_PROJECT_ID" + if [ -n "$OS_PROJECT_ID" ]; then + export OS_PROJECT_ID + _saveaccountconf_mutable OS_PROJECT_ID "$OS_PROJECT_ID" + else + unset OS_PROJECT_ID + _clearaccountconf SAVED_OS_PROJECT_ID + fi + + _debug "OS_USER_DOMAIN_NAME" "$OS_USER_DOMAIN_NAME" + if [ -n "$OS_USER_DOMAIN_NAME" ]; then + export OS_USER_DOMAIN_NAME + _saveaccountconf_mutable OS_USER_DOMAIN_NAME "$OS_USER_DOMAIN_NAME" + else + unset OS_USER_DOMAIN_NAME + _clearaccountconf SAVED_OS_USER_DOMAIN_NAME + fi + + _debug "OS_USER_DOMAIN_ID" "$OS_USER_DOMAIN_ID" + if [ -n "$OS_USER_DOMAIN_ID" ]; then + export OS_USER_DOMAIN_ID + _saveaccountconf_mutable OS_USER_DOMAIN_ID "$OS_USER_DOMAIN_ID" + else + unset OS_USER_DOMAIN_ID + _clearaccountconf SAVED_OS_USER_DOMAIN_ID + fi + + _debug "OS_PROJECT_DOMAIN_NAME" "$OS_PROJECT_DOMAIN_NAME" + if [ -n "$OS_PROJECT_DOMAIN_NAME" ]; then + export OS_PROJECT_DOMAIN_NAME + _saveaccountconf_mutable OS_PROJECT_DOMAIN_NAME "$OS_PROJECT_DOMAIN_NAME" + else + unset OS_PROJECT_DOMAIN_NAME + _clearaccountconf SAVED_OS_PROJECT_DOMAIN_NAME + fi + + _debug "OS_PROJECT_DOMAIN_ID" "$OS_PROJECT_DOMAIN_ID" + if [ -n "$OS_PROJECT_DOMAIN_ID" ]; then + export OS_PROJECT_DOMAIN_ID + _saveaccountconf_mutable OS_PROJECT_DOMAIN_ID "$OS_PROJECT_DOMAIN_ID" + else + unset OS_PROJECT_DOMAIN_ID + _clearaccountconf SAVED_OS_PROJECT_DOMAIN_ID + fi + + if [ "$OS_AUTH_TYPE" = "v3applicationcredential" ]; then + # Application Credential auth + if [ -z "$OS_APPLICATION_CREDENTIAL_ID" ] || [ -z "$OS_APPLICATION_CREDENTIAL_SECRET" ]; then + _err "When using OpenStack application credentials, OS_APPLICATION_CREDENTIAL_ID" + _err "and OS_APPLICATION_CREDENTIAL_SECRET must be set." + _err "Please check your credentials and try again." + return 1 + fi + else + # Password auth + if [ -z "$OS_USERNAME" ] || [ -z "$OS_PASSWORD" ]; then + _err "OpenStack username or password not found." + _err "Please check your credentials and try again." + return 1 + fi + + if [ -z "$OS_PROJECT_NAME" ] && [ -z "$OS_PROJECT_ID" ]; then + _err "When using password authentication, OS_PROJECT_NAME or" + _err "OS_PROJECT_ID must be set." + _err "Please check your credentials and try again." + return 1 + fi + fi + + return 0 +} diff --git a/letsencrypt/deploy/panos.sh b/letsencrypt/deploy/panos.sh new file mode 100644 index 00000000..93a35071 --- /dev/null +++ b/letsencrypt/deploy/panos.sh @@ -0,0 +1,139 @@ +#!/bin/bash + +# Script to deploy certificates to Palo Alto Networks PANOS via API +# Note PANOS API KEY and IP address needs to be set prior to running. +# The following variables exported from environment will be used. +# If not set then values previously saved in domain.conf file are used. +# +# Firewall admin with superuser and IP address is required. +# +# export PANOS_USER="" # required +# export PANOS_PASS="" # required +# export PANOS_HOST="" # required + +# This function is to parse the XML +parse_response() { + type=$2 + if [ "$type" = 'keygen' ]; then + status=$(echo "$1" | sed 's/^.*\(['\'']\)\([a-z]*\)'\''.*/\2/g') + if [ "$status" = "success" ]; then + panos_key=$(echo "$1" | sed 's/^.*\(\)\(.*\)<\/key>.*/\2/g') + _panos_key=$panos_key + else + message="PAN-OS Key could not be set." + fi + else + status=$(echo "$1" | sed 's/^.*"\([a-z]*\)".*/\1/g') + message=$(echo "$1" | sed 's/^.*\(.*\)<\/result.*/\1/g') + fi + return 0 +} + +deployer() { + content="" + type=$1 # Types are keygen, cert, key, commit + _debug "**** Deploying $type *****" + panos_url="https://$_panos_host/api/" + if [ "$type" = 'keygen' ]; then + _H1="Content-Type: application/x-www-form-urlencoded" + content="type=keygen&user=$_panos_user&password=$_panos_pass" + # content="$content${nl}--$delim${nl}Content-Disposition: form-data; type=\"keygen\"; user=\"$_panos_user\"; password=\"$_panos_pass\"${nl}Content-Type: application/octet-stream${nl}${nl}" + fi + + if [ "$type" = 'cert' ] || [ "$type" = 'key' ]; then + #Generate DEIM + delim="-----MultipartDelimiter$(date "+%s%N")" + nl="\015\012" + #Set Header + export _H1="Content-Type: multipart/form-data; boundary=$delim" + if [ "$type" = 'cert' ]; then + panos_url="${panos_url}?type=import" + content="--$delim${nl}Content-Disposition: form-data; name=\"category\"\r\n\r\ncertificate" + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"certificate-name\"\r\n\r\n$_cdomain" + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"\r\n\r\n$_panos_key" + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"format\"\r\n\r\npem" + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"file\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")" + fi + if [ "$type" = 'key' ]; then + panos_url="${panos_url}?type=import" + content="--$delim${nl}Content-Disposition: form-data; name=\"category\"\r\n\r\nprivate-key" + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"certificate-name\"\r\n\r\n$_cdomain" + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"\r\n\r\n$_panos_key" + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"format\"\r\n\r\npem" + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"passphrase\"\r\n\r\n123456" + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"file\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")" + fi + #Close multipart + content="$content${nl}--$delim--${nl}${nl}" + #Convert CRLF + content=$(printf %b "$content") + fi + + if [ "$type" = 'commit' ]; then + export _H1="Content-Type: application/x-www-form-urlencoded" + cmd=$(printf "%s" "<$_panos_user>" | _url_encode) + content="type=commit&key=$_panos_key&cmd=$cmd" + fi + response=$(_post "$content" "$panos_url" "" "POST") + parse_response "$response" "$type" + # Saving response to variables + response_status=$status + #DEBUG + _debug response_status "$response_status" + if [ "$response_status" = "success" ]; then + _debug "Successfully deployed $type" + return 0 + else + _err "Deploy of type $type failed. Try deploying with --debug to troubleshoot." + _debug "$message" + return 1 + fi +} + +# This is the main function that will call the other functions to deploy everything. +panos_deploy() { + _cdomain="$1" + _ckey="$2" + _cfullchain="$5" + # PANOS ENV VAR check + if [ -z "$PANOS_USER" ] || [ -z "$PANOS_PASS" ] || [ -z "$PANOS_HOST" ]; then + _debug "No ENV variables found lets check for saved variables" + _getdeployconf PANOS_USER + _getdeployconf PANOS_PASS + _getdeployconf PANOS_HOST + _panos_user=$PANOS_USER + _panos_pass=$PANOS_PASS + _panos_host=$PANOS_HOST + if [ -z "$_panos_user" ] && [ -z "$_panos_pass" ] && [ -z "$_panos_host" ]; then + _err "No host, user and pass found.. If this is the first time deploying please set PANOS_HOST, PANOS_USER and PANOS_PASS in environment variables. Delete them after you have succesfully deployed certs." + return 1 + else + _debug "Using saved env variables." + fi + else + _debug "Detected ENV variables to be saved to the deploy conf." + # Encrypt and save user + _savedeployconf PANOS_USER "$PANOS_USER" 1 + _savedeployconf PANOS_PASS "$PANOS_PASS" 1 + _savedeployconf PANOS_HOST "$PANOS_HOST" 1 + _panos_user="$PANOS_USER" + _panos_pass="$PANOS_PASS" + _panos_host="$PANOS_HOST" + fi + _debug "Let's use username and pass to generate token." + if [ -z "$_panos_user" ] || [ -z "$_panos_pass" ] || [ -z "$_panos_host" ]; then + _err "Please pass username and password and host as env variables PANOS_USER, PANOS_PASS and PANOS_HOST" + return 1 + else + _debug "Getting PANOS KEY" + deployer keygen + if [ -z "$_panos_key" ]; then + _err "Missing apikey." + return 1 + else + deployer cert + deployer key + deployer commit + fi + fi +} diff --git a/letsencrypt/deploy/pureftpd.sh b/letsencrypt/deploy/pureftpd.sh new file mode 100644 index 00000000..c7664a9f --- /dev/null +++ b/letsencrypt/deploy/pureftpd.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +#Here is a script to deploy cert to pureftpd server. + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +pureftpd_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _err "deploy cert to pureftpd server, Not implemented yet" + return 1 + +} diff --git a/letsencrypt/deploy/qiniu.sh b/letsencrypt/deploy/qiniu.sh new file mode 100644 index 00000000..31d70bd9 --- /dev/null +++ b/letsencrypt/deploy/qiniu.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +# Script to create certificate to qiniu.com +# +# This deployment required following variables +# export QINIU_AK="QINIUACCESSKEY" +# export QINIU_SK="QINIUSECRETKEY" +# export QINIU_CDN_DOMAIN="cdn.example.com" +# If you have more than one domain, just +# export QINIU_CDN_DOMAIN="cdn1.example.com cdn2.example.com" + +QINIU_API_BASE="https://api.qiniu.com" + +qiniu_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + if [ -z "$QINIU_AK" ]; then + _err "QINIU_AK is not defined." + return 1 + else + _savedomainconf QINIU_AK "$QINIU_AK" + fi + + if [ -z "$QINIU_SK" ]; then + _err "QINIU_SK is not defined." + return 1 + else + _savedomainconf QINIU_SK "$QINIU_SK" + fi + + if [ "$QINIU_CDN_DOMAIN" ]; then + _savedomainconf QINIU_CDN_DOMAIN "$QINIU_CDN_DOMAIN" + else + QINIU_CDN_DOMAIN="$_cdomain" + fi + + ## upload certificate + string_fullchain=$(sed 's/$/\\n/' "$_cfullchain" | tr -d '\n') + string_key=$(sed 's/$/\\n/' "$_ckey" | tr -d '\n') + + sslcert_path="/sslcert" + sslcerl_body="{\"name\":\"$_cdomain\",\"common_name\":\"$QINIU_CDN_DOMAIN\",\"ca\":\"$string_fullchain\",\"pri\":\"$string_key\"}" + sslcert_access_token="$(_make_access_token "$sslcert_path")" + _debug sslcert_access_token "$sslcert_access_token" + export _H1="Authorization: QBox $sslcert_access_token" + sslcert_response=$(_post "$sslcerl_body" "$QINIU_API_BASE$sslcert_path" 0 "POST" "application/json" | _dbase64 "multiline") + + if ! _contains "$sslcert_response" "certID"; then + _err "Error in creating certificate:" + _err "$sslcert_response" + return 1 + fi + + _debug sslcert_response "$sslcert_response" + _info "Certificate successfully uploaded, updating domain $_cdomain" + + ## extract certId + _certId="$(printf "%s" "$sslcert_response" | _normalizeJson | _egrep_o "certID\": *\"[^\"]*\"" | cut -d : -f 2)" + _debug certId "$_certId" + + ## update domain ssl config + update_body="{\"certid\":$_certId,\"forceHttps\":false}" + for domain in $QINIU_CDN_DOMAIN; do + update_path="/domain/$domain/httpsconf" + update_access_token="$(_make_access_token "$update_path")" + _debug update_access_token "$update_access_token" + export _H1="Authorization: QBox $update_access_token" + update_response=$(_post "$update_body" "$QINIU_API_BASE$update_path" 0 "PUT" "application/json" | _dbase64 "multiline") + + if _contains "$update_response" "error"; then + _err "Error in updating domain $domain httpsconf:" + _err "$update_response" + return 1 + fi + + _debug update_response "$update_response" + _info "Domain $domain certificate has been deployed successfully" + done + + return 0 +} + +_make_access_token() { + _token="$(printf "%s\n" "$1" | _hmac "sha1" "$(printf "%s" "$QINIU_SK" | _hex_dump | tr -d " ")" | _base64 | tr -- '+/' '-_')" + echo "$QINIU_AK:$_token" +} diff --git a/letsencrypt/deploy/routeros.sh b/letsencrypt/deploy/routeros.sh new file mode 100644 index 00000000..25eb4cc2 --- /dev/null +++ b/letsencrypt/deploy/routeros.sh @@ -0,0 +1,111 @@ +#!/bin/bash + +# Here is a script to deploy cert to routeros router. +# Deploy the cert to remote routeros +# +# ```sh +# acme.sh --deploy -d ftp.example.com --deploy-hook routeros +# ``` +# +# Before you can deploy the certificate to router os, you need +# to add the id_rsa.pub key to the routeros and assign a user +# to that key. +# +# The user need to have access to ssh, ftp, read and write. +# +# There are no need to enable ftp service for the script to work, +# as they are transmitted over SCP, however ftp is needed to store +# the files on the router. +# +# Then you need to set the environment variables for the +# deploy script to work. +# +# ```sh +# export ROUTER_OS_USERNAME=certuser +# export ROUTER_OS_HOST=router.example.com +# +# acme.sh --deploy -d ftp.example.com --deploy-hook routeros +# ``` +# +# The deploy script will remove previously deployed certificates, +# and it does this with an assumption on how RouterOS names imported +# certificates, adding a "cer_0" suffix at the end. This is true for +# versions 6.32 -> 6.41.3, but it is not guaranteed that it will be +# true for future versions when upgrading. +# +# If the router have other certificates with the same name as the one +# beeing deployed, then this script will remove those certificates. +# +# At the end of the script, the services that use those certificates +# could be updated. Currently only the www-ssl service is beeing +# updated, but more services could be added. +# +# For instance: +# ```sh +# export ROUTER_OS_ADDITIONAL_SERVICES="/ip service set api-ssl certificate=$_cdomain.cer_0" +# ``` +# +# One optional thing to do as well is to create a script that updates +# all the required services and run that script in a single command. +# +# returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +routeros_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + if [ -z "$ROUTER_OS_HOST" ]; then + _debug "Using _cdomain as ROUTER_OS_HOST, please set if not correct." + ROUTER_OS_HOST="$_cdomain" + fi + + if [ -z "$ROUTER_OS_USERNAME" ]; then + _err "Need to set the env variable ROUTER_OS_USERNAME" + return 1 + fi + + if [ -z "$ROUTER_OS_ADDITIONAL_SERVICES" ]; then + _debug "Not enabling additional services" + ROUTER_OS_ADDITIONAL_SERVICES="" + fi + + _info "Trying to push key '$_ckey' to router" + scp "$_ckey" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.key" + _info "Trying to push cert '$_cfullchain' to router" + scp "$_cfullchain" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.cer" + DEPLOY_SCRIPT_CMD="/system script add name=\"LE Cert Deploy - $_cdomain\" owner=admin policy=ftp,read,write,password,sensitive \ +source=\"## generated by routeros deploy script in acme.sh;\ +\n/certificate remove [ find name=$_cdomain.cer_0 ];\ +\n/certificate remove [ find name=$_cdomain.cer_1 ];\ +\ndelay 1;\ +\n/certificate import file-name=$_cdomain.cer passphrase=\\\"\\\";\ +\n/certificate import file-name=$_cdomain.key passphrase=\\\"\\\";\ +\ndelay 1;\ +\n/file remove $_cdomain.cer;\ +\n/file remove $_cdomain.key;\ +\ndelay 2;\ +\n/ip service set www-ssl certificate=$_cdomain.cer_0;\ +\n$ROUTER_OS_ADDITIONAL_SERVICES;\ +\n\" +" + # shellcheck disable=SC2029 + ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "$DEPLOY_SCRIPT_CMD" + # shellcheck disable=SC2029 + ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "/system script run \"LE Cert Deploy - $_cdomain\"" + # shellcheck disable=SC2029 + ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "/system script remove \"LE Cert Deploy - $_cdomain\"" + + return 0 +} diff --git a/letsencrypt/deploy/ssh.sh b/letsencrypt/deploy/ssh.sh new file mode 100644 index 00000000..9a9567f1 --- /dev/null +++ b/letsencrypt/deploy/ssh.sh @@ -0,0 +1,286 @@ +#!/bin/bash + +# Script to deploy certificates to remote server by SSH +# Note that SSH must be able to login to remote host without a password... +# SSH Keys must have been exchanged with the remote host. Validate and +# test that you can login to USER@SERVER from the host running acme.sh before +# using this script. +# +# The following variables exported from environment will be used. +# If not set then values previously saved in domain.conf file are used. +# +# Only a username is required. All others are optional. +# +# The following examples are for QNAP NAS running QTS 4.2 +# export DEPLOY_SSH_CMD="" # defaults to "ssh -T" +# export DEPLOY_SSH_USER="admin" # required +# export DEPLOY_SSH_SERVER="qnap" # defaults to domain name +# export DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem" +# export DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem" +# export DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem" +# export DEPLOY_SSH_FULLCHAIN="" +# export DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart" +# export DEPLOY_SSH_BACKUP="" # yes or no, default to yes or previously saved value +# export DEPLOY_SSH_BACKUP_PATH=".acme_ssh_deploy" # path on remote system. Defaults to .acme_ssh_deploy +# export DEPLOY_SSH_MULTI_CALL="" # yes or no, default to no or previously saved value +# +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +ssh_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + _deploy_ssh_servers="" + + if [ -f "$DOMAIN_CONF" ]; then + # shellcheck disable=SC1090 + . "$DOMAIN_CONF" + fi + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + # USER is required to login by SSH to remote host. + if [ -z "$DEPLOY_SSH_USER" ]; then + if [ -z "$Le_Deploy_ssh_user" ]; then + _err "DEPLOY_SSH_USER not defined." + return 1 + fi + else + Le_Deploy_ssh_user="$DEPLOY_SSH_USER" + _savedomainconf Le_Deploy_ssh_user "$Le_Deploy_ssh_user" + fi + + # SERVER is optional. If not provided then use _cdomain + if [ -n "$DEPLOY_SSH_SERVER" ]; then + Le_Deploy_ssh_server="$DEPLOY_SSH_SERVER" + _savedomainconf Le_Deploy_ssh_server "$Le_Deploy_ssh_server" + elif [ -z "$Le_Deploy_ssh_server" ]; then + Le_Deploy_ssh_server="$_cdomain" + fi + + # CMD is optional. If not provided then use ssh + if [ -n "$DEPLOY_SSH_CMD" ]; then + Le_Deploy_ssh_cmd="$DEPLOY_SSH_CMD" + _savedomainconf Le_Deploy_ssh_cmd "$Le_Deploy_ssh_cmd" + elif [ -z "$Le_Deploy_ssh_cmd" ]; then + Le_Deploy_ssh_cmd="ssh -T" + fi + + # BACKUP is optional. If not provided then default to previously saved value or yes. + if [ "$DEPLOY_SSH_BACKUP" = "no" ]; then + Le_Deploy_ssh_backup="no" + elif [ -z "$Le_Deploy_ssh_backup" ] || [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then + Le_Deploy_ssh_backup="yes" + fi + _savedomainconf Le_Deploy_ssh_backup "$Le_Deploy_ssh_backup" + + # BACKUP_PATH is optional. If not provided then default to previously saved value or .acme_ssh_deploy + if [ -n "$DEPLOY_SSH_BACKUP_PATH" ]; then + Le_Deploy_ssh_backup_path="$DEPLOY_SSH_BACKUP_PATH" + elif [ -z "$Le_Deploy_ssh_backup_path" ]; then + Le_Deploy_ssh_backup_path=".acme_ssh_deploy" + fi + _savedomainconf Le_Deploy_ssh_backup_path "$Le_Deploy_ssh_backup_path" + + # MULTI_CALL is optional. If not provided then default to previously saved + # value (which may be undefined... equivalent to "no"). + if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then + Le_Deploy_ssh_multi_call="yes" + _savedomainconf Le_Deploy_ssh_multi_call "$Le_Deploy_ssh_multi_call" + elif [ "$DEPLOY_SSH_MULTI_CALL" = "no" ]; then + Le_Deploy_ssh_multi_call="" + _cleardomainconf Le_Deploy_ssh_multi_call + fi + + _deploy_ssh_servers=$Le_Deploy_ssh_server + for Le_Deploy_ssh_server in $_deploy_ssh_servers; do + _ssh_deploy + done +} + +_ssh_deploy() { + _err_code=0 + _cmdstr="" + _backupprefix="" + _backupdir="" + + _info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server" + if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then + _info "Using MULTI_CALL mode... Required commands sent in multiple calls to remote host" + else + _info "Required commands batched and sent in single call to remote host" + fi + + if [ "$Le_Deploy_ssh_backup" = "yes" ]; then + _backupprefix="$Le_Deploy_ssh_backup_path/$_cdomain-backup" + _backupdir="$_backupprefix-$(_utc_date | tr ' ' '-')" + # run cleanup on the backup directory, erase all older + # than 180 days (15552000 seconds). + _cmdstr="{ now=\"\$(date -u +%s)\"; for fn in $_backupprefix*; \ +do if [ -d \"\$fn\" ] && [ \"\$(expr \$now - \$(date -ur \$fn +%s) )\" -ge \"15552000\" ]; \ +then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; done; }; $_cmdstr" + # Alternate version of above... _cmdstr="find $_backupprefix* -type d -mtime +180 2>/dev/null | xargs rm -rf; $_cmdstr" + # Create our backup directory for overwritten cert files. + _cmdstr="mkdir -p $_backupdir; $_cmdstr" + _info "Backup of old certificate files will be placed in remote directory $_backupdir" + _info "Backup directories erased after 180 days." + if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then + if ! _ssh_remote_cmd "$_cmdstr"; then + return $_err_code + fi + _cmdstr="" + fi + fi + + # KEYFILE is optional. + # If provided then private key will be copied to provided filename. + if [ -n "$DEPLOY_SSH_KEYFILE" ]; then + Le_Deploy_ssh_keyfile="$DEPLOY_SSH_KEYFILE" + _savedomainconf Le_Deploy_ssh_keyfile "$Le_Deploy_ssh_keyfile" + fi + if [ -n "$Le_Deploy_ssh_keyfile" ]; then + if [ "$Le_Deploy_ssh_backup" = "yes" ]; then + # backup file we are about to overwrite. + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir >/dev/null;" + fi + # copy new certificate into file. + _cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $Le_Deploy_ssh_keyfile;" + _info "will copy private key to remote file $Le_Deploy_ssh_keyfile" + if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then + if ! _ssh_remote_cmd "$_cmdstr"; then + return $_err_code + fi + _cmdstr="" + fi + fi + + # CERTFILE is optional. + # If provided then certificate will be copied or appended to provided filename. + if [ -n "$DEPLOY_SSH_CERTFILE" ]; then + Le_Deploy_ssh_certfile="$DEPLOY_SSH_CERTFILE" + _savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile" + fi + if [ -n "$Le_Deploy_ssh_certfile" ]; then + _pipe=">" + if [ "$Le_Deploy_ssh_certfile" = "$Le_Deploy_ssh_keyfile" ]; then + # if filename is same as previous file then append. + _pipe=">>" + elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then + # backup file we are about to overwrite. + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir >/dev/null;" + fi + # copy new certificate into file. + _cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $Le_Deploy_ssh_certfile;" + _info "will copy certificate to remote file $Le_Deploy_ssh_certfile" + if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then + if ! _ssh_remote_cmd "$_cmdstr"; then + return $_err_code + fi + _cmdstr="" + fi + fi + + # CAFILE is optional. + # If provided then CA intermediate certificate will be copied or appended to provided filename. + if [ -n "$DEPLOY_SSH_CAFILE" ]; then + Le_Deploy_ssh_cafile="$DEPLOY_SSH_CAFILE" + _savedomainconf Le_Deploy_ssh_cafile "$Le_Deploy_ssh_cafile" + fi + if [ -n "$Le_Deploy_ssh_cafile" ]; then + _pipe=">" + if [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_keyfile" ] || + [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_certfile" ]; then + # if filename is same as previous file then append. + _pipe=">>" + elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then + # backup file we are about to overwrite. + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir >/dev/null;" + fi + # copy new certificate into file. + _cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $Le_Deploy_ssh_cafile;" + _info "will copy CA file to remote file $Le_Deploy_ssh_cafile" + if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then + if ! _ssh_remote_cmd "$_cmdstr"; then + return $_err_code + fi + _cmdstr="" + fi + fi + + # FULLCHAIN is optional. + # If provided then fullchain certificate will be copied or appended to provided filename. + if [ -n "$DEPLOY_SSH_FULLCHAIN" ]; then + Le_Deploy_ssh_fullchain="$DEPLOY_SSH_FULLCHAIN" + _savedomainconf Le_Deploy_ssh_fullchain "$Le_Deploy_ssh_fullchain" + fi + if [ -n "$Le_Deploy_ssh_fullchain" ]; then + _pipe=">" + if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_keyfile" ] || + [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_certfile" ] || + [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_cafile" ]; then + # if filename is same as previous file then append. + _pipe=">>" + elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then + # backup file we are about to overwrite. + _cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir >/dev/null;" + fi + # copy new certificate into file. + _cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $Le_Deploy_ssh_fullchain;" + _info "will copy fullchain to remote file $Le_Deploy_ssh_fullchain" + if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then + if ! _ssh_remote_cmd "$_cmdstr"; then + return $_err_code + fi + _cmdstr="" + fi + fi + + # REMOTE_CMD is optional. + # If provided then this command will be executed on remote host. + if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then + Le_Deploy_ssh_remote_cmd="$DEPLOY_SSH_REMOTE_CMD" + _savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd" + fi + if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then + _cmdstr="$_cmdstr $Le_Deploy_ssh_remote_cmd;" + _info "Will execute remote command $Le_Deploy_ssh_remote_cmd" + if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then + if ! _ssh_remote_cmd "$_cmdstr"; then + return $_err_code + fi + _cmdstr="" + fi + fi + + # if commands not all sent in multiple calls then all commands sent in a single SSH call now... + if [ -n "$_cmdstr" ]; then + if ! _ssh_remote_cmd "$_cmdstr"; then + return $_err_code + fi + fi + return 0 +} + +#cmd +_ssh_remote_cmd() { + _cmd="$1" + _secure_debug "Remote commands to execute: $_cmd" + _info "Submitting sequence of commands to remote server by ssh" + # quotations in bash cmd below intended. Squash travis spellcheck error + # shellcheck disable=SC2029 + $Le_Deploy_ssh_cmd "$Le_Deploy_ssh_user@$Le_Deploy_ssh_server" sh -c "'$_cmd'" + _err_code="$?" + + if [ "$_err_code" != "0" ]; then + _err "Error code $_err_code returned from ssh" + fi + + return $_err_code +} diff --git a/letsencrypt/deploy/strongswan.sh b/letsencrypt/deploy/strongswan.sh new file mode 100644 index 00000000..40d312c9 --- /dev/null +++ b/letsencrypt/deploy/strongswan.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +#Here is a sample custom api script. +#This file name is "myapi.sh" +#So, here must be a method myapi_deploy() +#Which will be called by acme.sh to deploy the cert +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +strongswan_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _info "Using strongswan" + + if [ -x /usr/sbin/ipsec ]; then + _ipsec=/usr/sbin/ipsec + elif [ -x /usr/sbin/strongswan ]; then + _ipsec=/usr/sbin/strongswan + elif [ -x /usr/local/sbin/ipsec ]; then + _ipsec=/usr/local/sbin/ipsec + else + _err "no strongswan or ipsec command is detected" + return 1 + fi + + _info _ipsec "$_ipsec" + + _confdir=$($_ipsec --confdir) + if [ $? -ne 0 ] || [ -z "$_confdir" ]; then + _err "no strongswan --confdir is detected" + return 1 + fi + + _info _confdir "$_confdir" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + cat "$_ckey" >"${_confdir}/ipsec.d/private/$(basename "$_ckey")" + cat "$_ccert" >"${_confdir}/ipsec.d/certs/$(basename "$_ccert")" + cat "$_cca" >"${_confdir}/ipsec.d/cacerts/$(basename "$_cca")" + cat "$_cfullchain" >"${_confdir}/ipsec.d/cacerts/$(basename "$_cfullchain")" + + $_ipsec reload + +} diff --git a/letsencrypt/deploy/synology_dsm.sh b/letsencrypt/deploy/synology_dsm.sh new file mode 100644 index 00000000..352dfbad --- /dev/null +++ b/letsencrypt/deploy/synology_dsm.sh @@ -0,0 +1,152 @@ +#!/bin/bash + +# Here is a script to deploy cert to Synology DSM +# +# it requires the jq and curl are in the $PATH and the following +# environment variables must be set: +# +# SYNO_Username - Synology Username to login (must be an administrator) +# SYNO_Password - Synology Password to login +# SYNO_Certificate - Certificate description to target for replacement +# +# The following environmental variables may be set if you don't like their +# default values: +# +# SYNO_Scheme - defaults to http +# SYNO_Hostname - defaults to localhost +# SYNO_Port - defaults to 5000 +# SYNO_DID - device ID to skip OTP - defaults to empty +# +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +_syno_get_cookie_data() { + grep -i "\W$1=" | grep -i "^Set-Cookie:" | _tail_n 1 | _egrep_o "$1=[^;]*;" | tr -d ';' +} + +#domain keyfile certfile cafile fullchain +synology_dsm_deploy() { + + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + + _debug _cdomain "$_cdomain" + + # Get Username and Password, but don't save until we successfully authenticate + _getdeployconf SYNO_Username + _getdeployconf SYNO_Password + _getdeployconf SYNO_Create + _getdeployconf SYNO_DID + if [ -z "${SYNO_Username:-}" ] || [ -z "${SYNO_Password:-}" ]; then + _err "SYNO_Username & SYNO_Password must be set" + return 1 + fi + _debug2 SYNO_Username "$SYNO_Username" + _secure_debug2 SYNO_Password "$SYNO_Password" + + # Optional scheme, hostname, and port for Synology DSM + _getdeployconf SYNO_Scheme + _getdeployconf SYNO_Hostname + _getdeployconf SYNO_Port + + # default vaules for scheme, hostname, and port + # defaulting to localhost and http because it's localhost... + [ -n "${SYNO_Scheme}" ] || SYNO_Scheme="http" + [ -n "${SYNO_Hostname}" ] || SYNO_Hostname="localhost" + [ -n "${SYNO_Port}" ] || SYNO_Port="5000" + + _savedeployconf SYNO_Scheme "$SYNO_Scheme" + _savedeployconf SYNO_Hostname "$SYNO_Hostname" + _savedeployconf SYNO_Port "$SYNO_Port" + + _debug2 SYNO_Scheme "$SYNO_Scheme" + _debug2 SYNO_Hostname "$SYNO_Hostname" + _debug2 SYNO_Port "$SYNO_Port" + + # Get the certificate description, but don't save it until we verfiy it's real + _getdeployconf SYNO_Certificate + _debug SYNO_Certificate "${SYNO_Certificate:-}" + + _base_url="$SYNO_Scheme://$SYNO_Hostname:$SYNO_Port" + _debug _base_url "$_base_url" + + # Login, get the token from JSON and session id from cookie + _info "Logging into $SYNO_Hostname:$SYNO_Port" + encoded_username="$(printf "%s" "$SYNO_Username" | _url_encode)" + encoded_password="$(printf "%s" "$SYNO_Password" | _url_encode)" + encoded_did="$(printf "%s" "$SYNO_DID" | _url_encode)" + response=$(_get "$_base_url/webman/login.cgi?username=$encoded_username&passwd=$encoded_password&enable_syno_token=yes&device_id=$encoded_did" 1) + token=$(echo "$response" | grep -i "X-SYNO-TOKEN:" | sed -n 's/^X-SYNO-TOKEN: \(.*\)$/\1/pI' | tr -d "\r\n") + _debug3 response "$response" + _debug token "$token" + + if [ -z "$token" ]; then + _err "Unable to authenticate to $SYNO_Hostname:$SYNO_Port using $SYNO_Scheme." + _err "Check your username and password." + return 1 + fi + + _H1="Cookie: $(echo "$response" | _syno_get_cookie_data "id"); $(echo "$response" | _syno_get_cookie_data "smid")" + _H2="X-SYNO-TOKEN: $token" + export _H1 + export _H2 + _debug2 H1 "${_H1}" + _debug2 H2 "${_H2}" + + # Now that we know the username and password are good, save them + _savedeployconf SYNO_Username "$SYNO_Username" + _savedeployconf SYNO_Password "$SYNO_Password" + _savedeployconf SYNO_DID "$SYNO_DID" + + _info "Getting certificates in Synology DSM" + response=$(_post "api=SYNO.Core.Certificate.CRT&method=list&version=1" "$_base_url/webapi/entry.cgi") + _debug3 response "$response" + id=$(echo "$response" | sed -n "s/.*\"desc\":\"$SYNO_Certificate\",\"id\":\"\([^\"]*\).*/\1/p") + _debug2 id "$id" + + if [ -z "$id" ] && [ -z "${SYNO_Create:-}" ]; then + _err "Unable to find certificate: $SYNO_Certificate and \$SYNO_Create is not set" + return 1 + fi + + # we've verified this certificate description is a thing, so save it + _savedeployconf SYNO_Certificate "$SYNO_Certificate" + + default=false + if echo "$response" | sed -n "s/.*\"desc\":\"$SYNO_Certificate\",\([^{]*\).*/\1/p" | grep -- 'is_default":true' >/dev/null; then + default=true + fi + _debug2 default "$default" + + _info "Generate form POST request" + nl="\0015\0012" + delim="--------------------------$(_utc_date | tr -d -- '-: ')" + content="--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")\0012" + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"cert\"; filename=\"$(basename "$_ccert")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ccert")\0012" + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"inter_cert\"; filename=\"$(basename "$_cca")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cca")\0012" + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"id\"${nl}${nl}$id" + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"desc\"${nl}${nl}${SYNO_Certificate}" + content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"as_default\"${nl}${nl}${default}" + content="$content${nl}--$delim--${nl}" + content="$(printf "%b_" "$content")" + content="${content%_}" # protect trailing \n + + _info "Upload certificate to the Synology DSM" + response=$(_post "$content" "$_base_url/webapi/entry.cgi?api=SYNO.Core.Certificate&method=import&version=1&SynoToken=$token" "" "POST" "multipart/form-data; boundary=${delim}") + _debug3 response "$response" + + if ! echo "$response" | grep '"error":' >/dev/null; then + if echo "$response" | grep '"restart_httpd":true' >/dev/null; then + _info "http services were restarted" + else + _info "http services were NOT restarted" + fi + return 0 + else + _err "Unable to update certificate, error code $response" + return 1 + fi +} diff --git a/letsencrypt/deploy/unifi.sh b/letsencrypt/deploy/unifi.sh new file mode 100644 index 00000000..3d10ad17 --- /dev/null +++ b/letsencrypt/deploy/unifi.sh @@ -0,0 +1,100 @@ +#!/bin/bash + +#Here is a script to deploy cert to unifi server. + +#returns 0 means success, otherwise error. + +#DEPLOY_UNIFI_KEYSTORE="/usr/lib/unifi/data/keystore" +#DEPLOY_UNIFI_KEYPASS="aircontrolenterprise" +#DEPLOY_UNIFI_RELOAD="service unifi restart" + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +unifi_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + if ! _exists keytool; then + _err "keytool not found" + return 1 + fi + + DEFAULT_UNIFI_KEYSTORE="/usr/lib/unifi/data/keystore" + _unifi_keystore="${DEPLOY_UNIFI_KEYSTORE:-$DEFAULT_UNIFI_KEYSTORE}" + DEFAULT_UNIFI_KEYPASS="aircontrolenterprise" + _unifi_keypass="${DEPLOY_UNIFI_KEYPASS:-$DEFAULT_UNIFI_KEYPASS}" + DEFAULT_UNIFI_RELOAD="service unifi restart" + _reload="${DEPLOY_UNIFI_RELOAD:-$DEFAULT_UNIFI_RELOAD}" + + _debug _unifi_keystore "$_unifi_keystore" + if [ ! -f "$_unifi_keystore" ]; then + if [ -z "$DEPLOY_UNIFI_KEYSTORE" ]; then + _err "unifi keystore is not found, please define DEPLOY_UNIFI_KEYSTORE" + return 1 + else + _err "It seems that the specified unifi keystore is not valid, please check." + return 1 + fi + fi + if [ ! -w "$_unifi_keystore" ]; then + _err "The file $_unifi_keystore is not writable, please change the permission." + return 1 + fi + + _info "Generate import pkcs12" + _import_pkcs12="$(_mktemp)" + _toPkcs "$_import_pkcs12" "$_ckey" "$_ccert" "$_cca" "$_unifi_keypass" unifi root + if [ "$?" != "0" ]; then + _err "Oops, error creating import pkcs12, please report bug to us." + return 1 + fi + + _info "Modify unifi keystore: $_unifi_keystore" + if keytool -importkeystore \ + -deststorepass "$_unifi_keypass" -destkeypass "$_unifi_keypass" -destkeystore "$_unifi_keystore" \ + -srckeystore "$_import_pkcs12" -srcstoretype PKCS12 -srcstorepass "$_unifi_keypass" \ + -alias unifi -noprompt; then + _info "Import keystore success!" + rm "$_import_pkcs12" + else + _err "Import unifi keystore error, please report bug to us." + rm "$_import_pkcs12" + return 1 + fi + + _info "Run reload: $_reload" + if eval "$_reload"; then + _info "Reload success!" + if [ "$DEPLOY_UNIFI_KEYSTORE" ]; then + _savedomainconf DEPLOY_UNIFI_KEYSTORE "$DEPLOY_UNIFI_KEYSTORE" + else + _cleardomainconf DEPLOY_UNIFI_KEYSTORE + fi + if [ "$DEPLOY_UNIFI_KEYPASS" ]; then + _savedomainconf DEPLOY_UNIFI_KEYPASS "$DEPLOY_UNIFI_KEYPASS" + else + _cleardomainconf DEPLOY_UNIFI_KEYPASS + fi + if [ "$DEPLOY_UNIFI_RELOAD" ]; then + _savedomainconf DEPLOY_UNIFI_RELOAD "$DEPLOY_UNIFI_RELOAD" + else + _cleardomainconf DEPLOY_UNIFI_RELOAD + fi + return 0 + else + _err "Reload error" + return 1 + fi + return 0 + +} diff --git a/letsencrypt/deploy/vault.sh b/letsencrypt/deploy/vault.sh new file mode 100644 index 00000000..b5ccad44 --- /dev/null +++ b/letsencrypt/deploy/vault.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +# Here is a script to deploy cert to hashicorp vault using curl +# (https://www.vaultproject.io/) +# +# it requires following environment variables: +# +# VAULT_PREFIX - this contains the prefix path in vault +# VAULT_ADDR - vault requires this to find your vault server +# +# additionally, you need to ensure that VAULT_TOKEN is avialable +# to access the vault server + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +vault_deploy() { + + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + # validate required env vars + _getdeployconf VAULT_PREFIX + if [ -z "$VAULT_PREFIX" ]; then + _err "VAULT_PREFIX needs to be defined (contains prefix path in vault)" + return 1 + fi + _savedeployconf VAULT_PREFIX "$VAULT_PREFIX" + + _getdeployconf VAULT_ADDR + if [ -z "$VAULT_ADDR" ]; then + _err "VAULT_ADDR needs to be defined (contains vault connection address)" + return 1 + fi + _savedeployconf VAULT_ADDR "$VAULT_ADDR" + + # JSON does not allow multiline strings. + # So replacing new-lines with "\n" here + _ckey=$(sed -z 's/\n/\\n/g' <"$2") + _ccert=$(sed -z 's/\n/\\n/g' <"$3") + _cca=$(sed -z 's/\n/\\n/g' <"$4") + _cfullchain=$(sed -z 's/\n/\\n/g' <"$5") + + URL="$VAULT_ADDR/v1/$VAULT_PREFIX/$_cdomain" + export _H1="X-Vault-Token: $VAULT_TOKEN" + + if [ -n "$FABIO" ]; then + _post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL" + else + _post "{\"value\": \"$_ccert\"}" "$URL/cert.pem" + _post "{\"value\": \"$_ckey\"}" "$URL/cert.key" + _post "{\"value\": \"$_cca\"}" "$URL/chain.pem" + _post "{\"value\": \"$_cfullchain\"}" "$URL/fullchain.pem" + fi + +} diff --git a/letsencrypt/deploy/vault_cli.sh b/letsencrypt/deploy/vault_cli.sh new file mode 100644 index 00000000..b89579b6 --- /dev/null +++ b/letsencrypt/deploy/vault_cli.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +# Here is a script to deploy cert to hashicorp vault +# (https://www.vaultproject.io/) +# +# it requires the vault binary to be available in PATH, and the following +# environment variables: +# +# VAULT_PREFIX - this contains the prefix path in vault +# VAULT_ADDR - vault requires this to find your vault server +# +# additionally, you need to ensure that VAULT_TOKEN is avialable or +# `vault auth` has applied the appropriate authorization for the vault binary +# to access the vault server + +#returns 0 means success, otherwise error. + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +vault_cli_deploy() { + + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + # validate required env vars + if [ -z "$VAULT_PREFIX" ]; then + _err "VAULT_PREFIX needs to be defined (contains prefix path in vault)" + return 1 + fi + + if [ -z "$VAULT_ADDR" ]; then + _err "VAULT_ADDR needs to be defined (contains vault connection address)" + return 1 + fi + + VAULT_CMD=$(command -v vault) + if [ ! $? ]; then + _err "cannot find vault binary!" + return 1 + fi + + if [ -n "$FABIO" ]; then + $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}" cert=@"$_cfullchain" key=@"$_ckey" || return 1 + else + $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1 + $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1 + $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1 + $VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1 + fi + +} diff --git a/letsencrypt/deploy/vsftpd.sh b/letsencrypt/deploy/vsftpd.sh new file mode 100644 index 00000000..e99d937b --- /dev/null +++ b/letsencrypt/deploy/vsftpd.sh @@ -0,0 +1,110 @@ +#!/bin/bash + +#Here is a script to deploy cert to vsftpd server. + +#returns 0 means success, otherwise error. + +#DEPLOY_VSFTPD_CONF="/etc/vsftpd.conf" +#DEPLOY_VSFTPD_RELOAD="service vsftpd restart" + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +vsftpd_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + + _ssl_path="/etc/acme.sh/vsftpd" + if ! mkdir -p "$_ssl_path"; then + _err "Can not create folder:$_ssl_path" + return 1 + fi + + _info "Copying key and cert" + _real_key="$_ssl_path/vsftpd.key" + if ! cat "$_ckey" >"$_real_key"; then + _err "Error: write key file to: $_real_key" + return 1 + fi + _real_fullchain="$_ssl_path/vsftpd.chain.pem" + if ! cat "$_cfullchain" >"$_real_fullchain"; then + _err "Error: write key file to: $_real_fullchain" + return 1 + fi + + DEFAULT_VSFTPD_RELOAD="service vsftpd restart" + _reload="${DEPLOY_VSFTPD_RELOAD:-$DEFAULT_VSFTPD_RELOAD}" + + if [ -z "$IS_RENEW" ]; then + DEFAULT_VSFTPD_CONF="/etc/vsftpd.conf" + _vsftpd_conf="${DEPLOY_VSFTPD_CONF:-$DEFAULT_VSFTPD_CONF}" + if [ ! -f "$_vsftpd_conf" ]; then + if [ -z "$DEPLOY_VSFTPD_CONF" ]; then + _err "vsftpd conf is not found, please define DEPLOY_VSFTPD_CONF" + return 1 + else + _err "It seems that the specified vsftpd conf is not valid, please check." + return 1 + fi + fi + if [ ! -w "$_vsftpd_conf" ]; then + _err "The file $_vsftpd_conf is not writable, please change the permission." + return 1 + fi + _backup_conf="$DOMAIN_BACKUP_PATH/vsftpd.conf.bak" + _info "Backup $_vsftpd_conf to $_backup_conf" + cp "$_vsftpd_conf" "$_backup_conf" + + _info "Modify vsftpd conf: $_vsftpd_conf" + if _setopt "$_vsftpd_conf" "rsa_cert_file" "=" "$_real_fullchain" && + _setopt "$_vsftpd_conf" "rsa_private_key_file" "=" "$_real_key" && + _setopt "$_vsftpd_conf" "ssl_enable" "=" "YES"; then + _info "Set config success!" + else + _err "Config vsftpd server error, please report bug to us." + _info "Restoring vsftpd conf" + if cat "$_backup_conf" >"$_vsftpd_conf"; then + _info "Restore conf success" + eval "$_reload" + else + _err "Oops, error restore vsftpd conf, please report bug to us." + fi + return 1 + fi + fi + + _info "Run reload: $_reload" + if eval "$_reload"; then + _info "Reload success!" + if [ "$DEPLOY_VSFTPD_CONF" ]; then + _savedomainconf DEPLOY_VSFTPD_CONF "$DEPLOY_VSFTPD_CONF" + else + _cleardomainconf DEPLOY_VSFTPD_CONF + fi + if [ "$DEPLOY_VSFTPD_RELOAD" ]; then + _savedomainconf DEPLOY_VSFTPD_RELOAD "$DEPLOY_VSFTPD_RELOAD" + else + _cleardomainconf DEPLOY_VSFTPD_RELOAD + fi + return 0 + else + _err "Reload error, restoring" + if cat "$_backup_conf" >"$_vsftpd_conf"; then + _info "Restore conf success" + eval "$_reload" + else + _err "Oops, error restore vsftpd conf, please report bug to us." + fi + return 1 + fi + return 0 +} diff --git a/letsencrypt/dnsapi/README.md b/letsencrypt/dnsapi/README.md new file mode 100644 index 00000000..e81f7916 --- /dev/null +++ b/letsencrypt/dnsapi/README.md @@ -0,0 +1,6 @@ +# How to use DNS API +DNS api usage: + + +https://github.com/acmesh-official/acme.sh/wiki/dnsapi + diff --git a/letsencrypt/dnsapi/dns_1984hosting.sh b/letsencrypt/dnsapi/dns_1984hosting.sh new file mode 100755 index 00000000..76bb9c79 --- /dev/null +++ b/letsencrypt/dnsapi/dns_1984hosting.sh @@ -0,0 +1,236 @@ +#!/bin/bash +#This file name is "dns_1984hosting.sh" +#So, here must be a method dns_1984hosting_add() +#Which will be called by acme.sh to add the txt record to your api system. +#returns 0 means success, otherwise error. + +#Author: Adrian Fedoreanu +#Report Bugs here: https://github.com/acmesh-official/acme.sh +# or here... https://github.com/acmesh-official/acme.sh/issues/2851 +# +######## Public functions ##################### + +# Export 1984HOSTING username and password in following variables +# +# One984HOSTING_Username=username +# One984HOSTING_Password=password +# +# sessionid cookie is saved in ~/.acme.sh/account.conf +# username/password need to be set only when changed. + +#Usage: dns_1984hosting_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_1984hosting_add() { + fulldomain=$1 + txtvalue=$2 + + _info "Add TXT record using 1984Hosting" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + if ! _1984hosting_login; then + _err "1984Hosting login failed for user $One984HOSTING_Username. Check $HTTP_HEADER file" + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" "$fulldomain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Add TXT record $fulldomain with value '$txtvalue'" + value="$(printf '%s' "$txtvalue" | _url_encode)" + url="https://management.1984hosting.com/domains/entry/" + + postdata="entry=new" + postdata="$postdata&type=TXT" + postdata="$postdata&ttl=3600" + postdata="$postdata&zone=$_domain" + postdata="$postdata&host=$_sub_domain" + postdata="$postdata&rdata=%22$value%22" + _debug2 postdata "$postdata" + + _authpost "$postdata" "$url" + response="$(echo "$_response" | _normalizeJson)" + _debug2 response "$response" + + if _contains "$response" '"haserrors": true'; then + _err "1984Hosting failed to add TXT record for $_sub_domain bad RC from _post" + return 1 + elif _contains "$response" ""; then + _err "1984Hosting failed to add TXT record for $_sub_domain. Check $HTTP_HEADER file" + return 1 + elif _contains "$response" '"auth": false'; then + _err "1984Hosting failed to add TXT record for $_sub_domain. Invalid or expired cookie" + return 1 + fi + + _info "Added acme challenge TXT record for $fulldomain at 1984Hosting" + return 0 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_1984hosting_rm() { + fulldomain=$1 + txtvalue=$2 + + _info "Delete TXT record using 1984Hosting" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + if ! _1984hosting_login; then + _err "1984Hosting login failed for user $One984HOSTING_Username. Check $HTTP_HEADER file" + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" "$fulldomain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Delete $fulldomain TXT record" + url="https://management.1984hosting.com/domains" + + _htmlget "$url" "$_domain" + _debug2 _response "$_response" + zone_id="$(echo "$_response" | _egrep_o 'zone\/[0-9]+')" + _debug2 zone_id "$zone_id" + if [ -z "$zone_id" ]; then + _err "Error getting zone_id for $1" + return 1 + fi + + _htmlget "$url/$zone_id" "$_sub_domain" + _debug2 _response "$_response" + entry_id="$(echo "$_response" | _egrep_o 'entry_[0-9]+' | sed 's/entry_//')" + _debug2 entry_id "$entry_id" + if [ -z "$entry_id" ]; then + _err "Error getting TXT entry_id for $1" + return 1 + fi + + _authpost "entry=$entry_id" "$url/delentry/" + response="$(echo "$_response" | _normalizeJson)" + _debug2 response "$response" + + if ! _contains "$response" '"ok": true'; then + _err "1984Hosting failed to delete TXT record for $entry_id bad RC from _post" + return 1 + fi + + _info "Deleted acme challenge TXT record for $fulldomain at 1984Hosting" + return 0 +} + +#################### Private functions below ################################## + +# usage: _1984hosting_login username password +# returns 0 success +_1984hosting_login() { + if ! _check_credentials; then return 1; fi + + if _check_cookie; then + _debug "Already logged in" + return 0 + fi + + _debug "Login to 1984Hosting as user $One984HOSTING_Username" + username=$(printf '%s' "$One984HOSTING_Username" | _url_encode) + password=$(printf '%s' "$One984HOSTING_Password" | _url_encode) + url="https://management.1984hosting.com/accounts/checkuserauth/" + + response="$(_post "username=$username&password=$password&otpkey=" "$url")" + response="$(echo "$response" | _normalizeJson)" + _debug2 response "$response" + + if _contains "$response" '"loggedin": true'; then + One984HOSTING_COOKIE="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _tail_n 1 | _egrep_o 'sessionid=[^;]*;' | tr -d ';')" + export One984HOSTING_COOKIE + _saveaccountconf_mutable One984HOSTING_COOKIE "$One984HOSTING_COOKIE" + return 0 + fi + return 1 +} + +_check_credentials() { + if [ -z "$One984HOSTING_Username" ] || [ -z "$One984HOSTING_Password" ]; then + One984HOSTING_Username="" + One984HOSTING_Password="" + _err "You haven't specified 1984Hosting username or password yet." + _err "Please export as One984HOSTING_Username / One984HOSTING_Password and try again." + return 1 + fi + return 0 +} + +_check_cookie() { + One984HOSTING_COOKIE="${One984HOSTING_COOKIE:-$(_readaccountconf_mutable One984HOSTING_COOKIE)}" + if [ -z "$One984HOSTING_COOKIE" ]; then + _debug "No cached cookie found" + return 1 + fi + + _authget "https://management.1984hosting.com/accounts/loginstatus/" + response="$(echo "$_response" | _normalizeJson)" + if _contains "$response" '"ok": true'; then + _debug "Cached cookie still valid" + return 0 + fi + _debug "Cached cookie no longer valid" + One984HOSTING_COOKIE="" + _saveaccountconf_mutable One984HOSTING_COOKIE "$One984HOSTING_COOKIE" + return 1 +} + +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain="$1" + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + + if [ -z "$h" ]; then + #not valid + return 1 + fi + + _authget "https://management.1984hosting.com/domains/soacheck/?zone=$h&nameserver=ns0.1984.is." + if _contains "$_response" "serial"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +# add extra headers to request +_authget() { + export _H1="Cookie: $One984HOSTING_COOKIE" + _response=$(_get "$1") +} + +# truncate huge HTML response +# echo: Argument list too long +_htmlget() { + export _H1="Cookie: $One984HOSTING_COOKIE" + _response=$(_get "$1" | grep "$2" | _head_n 1) +} + +# add extra headers to request +_authpost() { + export _H1="Cookie: $One984HOSTING_COOKIE" + _response=$(_post "$1" "$2") +} diff --git a/letsencrypt/dnsapi/dns_acmedns.sh b/letsencrypt/dnsapi/dns_acmedns.sh new file mode 100644 index 00000000..80975f7f --- /dev/null +++ b/letsencrypt/dnsapi/dns_acmedns.sh @@ -0,0 +1,55 @@ +#!/bin/bash +# +#Author: Wolfgang Ebner +#Report Bugs here: https://github.com/webner/acme.sh +# +######## Public functions ##################### + +#Usage: dns_acmedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_acmedns_add() { + fulldomain=$1 + txtvalue=$2 + _info "Using acme-dns" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + ACMEDNS_UPDATE_URL="${ACMEDNS_UPDATE_URL:-$(_readaccountconf_mutable ACMEDNS_UPDATE_URL)}" + ACMEDNS_USERNAME="${ACMEDNS_USERNAME:-$(_readaccountconf_mutable ACMEDNS_USERNAME)}" + ACMEDNS_PASSWORD="${ACMEDNS_PASSWORD:-$(_readaccountconf_mutable ACMEDNS_PASSWORD)}" + ACMEDNS_SUBDOMAIN="${ACMEDNS_SUBDOMAIN:-$(_readaccountconf_mutable ACMEDNS_SUBDOMAIN)}" + + if [ "$ACMEDNS_UPDATE_URL" = "" ]; then + ACMEDNS_UPDATE_URL="https://auth.acme-dns.io/update" + fi + + _saveaccountconf_mutable ACMEDNS_UPDATE_URL "$ACMEDNS_UPDATE_URL" + _saveaccountconf_mutable ACMEDNS_USERNAME "$ACMEDNS_USERNAME" + _saveaccountconf_mutable ACMEDNS_PASSWORD "$ACMEDNS_PASSWORD" + _saveaccountconf_mutable ACMEDNS_SUBDOMAIN "$ACMEDNS_SUBDOMAIN" + + export _H1="X-Api-User: $ACMEDNS_USERNAME" + export _H2="X-Api-Key: $ACMEDNS_PASSWORD" + data="{\"subdomain\":\"$ACMEDNS_SUBDOMAIN\", \"txt\": \"$txtvalue\"}" + + _debug data "$data" + response="$(_post "$data" "$ACMEDNS_UPDATE_URL" "" "POST")" + _debug response "$response" + + if ! echo "$response" | grep "\"$txtvalue\"" >/dev/null; then + _err "invalid response of acme-dns" + return 1 + fi + +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_acmedns_rm() { + fulldomain=$1 + txtvalue=$2 + _info "Using acme-dns" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" +} + +#################### Private functions below ################################## diff --git a/letsencrypt/dnsapi/dns_acmeproxy.sh b/letsencrypt/dnsapi/dns_acmeproxy.sh new file mode 100644 index 00000000..5396f3af --- /dev/null +++ b/letsencrypt/dnsapi/dns_acmeproxy.sh @@ -0,0 +1,83 @@ +#!/bin/bash + +## Acmeproxy DNS provider to be used with acmeproxy (http://github.com/mdbraber/acmeproxy) +## API integration by Maarten den Braber +## +## Report any bugs via https://github.com/mdbraber/acme.sh + +dns_acmeproxy_add() { + fulldomain="${1}" + txtvalue="${2}" + action="present" + + _debug "Calling: _acmeproxy_request() '${fulldomain}' '${txtvalue}' '${action}'" + _acmeproxy_request "$fulldomain" "$txtvalue" "$action" +} + +dns_acmeproxy_rm() { + fulldomain="${1}" + txtvalue="${2}" + action="cleanup" + + _debug "Calling: _acmeproxy_request() '${fulldomain}' '${txtvalue}' '${action}'" + _acmeproxy_request "$fulldomain" "$txtvalue" "$action" +} + +_acmeproxy_request() { + + ## Nothing to see here, just some housekeeping + fulldomain=$1 + txtvalue=$2 + action=$3 + + _info "Using acmeproxy" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + ACMEPROXY_ENDPOINT="${ACMEPROXY_ENDPOINT:-$(_readaccountconf_mutable ACMEPROXY_ENDPOINT)}" + ACMEPROXY_USERNAME="${ACMEPROXY_USERNAME:-$(_readaccountconf_mutable ACMEPROXY_USERNAME)}" + ACMEPROXY_PASSWORD="${ACMEPROXY_PASSWORD:-$(_readaccountconf_mutable ACMEPROXY_PASSWORD)}" + + ## Check for the endpoint + if [ -z "$ACMEPROXY_ENDPOINT" ]; then + ACMEPROXY_ENDPOINT="" + _err "You didn't specify the endpoint" + _err "Please set them via 'export ACMEPROXY_ENDPOINT=https://ip:port' and try again." + return 1 + fi + + ## Save the credentials to the account file + _saveaccountconf_mutable ACMEPROXY_ENDPOINT "$ACMEPROXY_ENDPOINT" + _saveaccountconf_mutable ACMEPROXY_USERNAME "$ACMEPROXY_USERNAME" + _saveaccountconf_mutable ACMEPROXY_PASSWORD "$ACMEPROXY_PASSWORD" + + if [ -z "$ACMEPROXY_USERNAME" ] || [ -z "$ACMEPROXY_PASSWORD" ]; then + _info "ACMEPROXY_USERNAME and/or ACMEPROXY_PASSWORD not set - using without client authentication! Make sure you're using server authentication (e.g. IP-based)" + export _H1="Accept: application/json" + export _H2="Content-Type: application/json" + else + ## Base64 encode the credentials + credentials=$(printf "%b" "$ACMEPROXY_USERNAME:$ACMEPROXY_PASSWORD" | _base64) + + ## Construct the HTTP Authorization header + export _H1="Authorization: Basic $credentials" + export _H2="Accept: application/json" + export _H3="Content-Type: application/json" + fi + + ## Add the challenge record to the acmeproxy grid member + response="$(_post "{\"fqdn\": \"$fulldomain.\", \"value\": \"$txtvalue\"}" "$ACMEPROXY_ENDPOINT/$action" "" "POST")" + + ## Let's see if we get something intelligible back from the unit + if echo "$response" | grep "\"$txtvalue\"" >/dev/null; then + _info "Successfully updated the txt record" + return 0 + else + _err "Error encountered during record addition" + _err "$response" + return 1 + fi + +} + +#################### Private functions below ################################## diff --git a/letsencrypt/dnsapi/dns_active24.sh b/letsencrypt/dnsapi/dns_active24.sh new file mode 100755 index 00000000..e027c559 --- /dev/null +++ b/letsencrypt/dnsapi/dns_active24.sh @@ -0,0 +1,141 @@ +#!/bin/bash + +#ACTIVE24_Token="sdfsdfsdfljlbjkljlkjsdfoiwje" + +ACTIVE24_Api="https://api.active24.com" + +######## Public functions ##################### + +# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to add txt record +dns_active24_add() { + fulldomain=$1 + txtvalue=$2 + + _active24_init + + _info "Adding txt record" + if _active24_rest POST "dns/$_domain/txt/v1" "{\"name\":\"$_sub_domain\",\"text\":\"$txtvalue\",\"ttl\":0}"; then + if _contains "$response" "errors"; then + _err "Add txt record error." + return 1 + else + _info "Added, OK" + return 0 + fi + fi + _err "Add txt record error." + return 1 +} + +# Usage: fulldomain txtvalue +# Used to remove the txt record after validation +dns_active24_rm() { + fulldomain=$1 + txtvalue=$2 + + _active24_init + + _debug "Getting txt records" + _active24_rest GET "dns/$_domain/records/v1" + + if _contains "$response" "errors"; then + _err "Error" + return 1 + fi + + hash_ids=$(echo "$response" | _egrep_o "[^{]+${txtvalue}[^}]+" | _egrep_o "hashId\":\"[^\"]+" | cut -c10-) + + for hash_id in $hash_ids; do + _debug "Removing hash_id" "$hash_id" + if _active24_rest DELETE "dns/$_domain/$hash_id/v1" ""; then + if _contains "$response" "errors"; then + _err "Unable to remove txt record." + return 1 + else + _info "Removed txt record." + return 0 + fi + fi + done + + _err "No txt records found." + return 1 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + + if ! _active24_rest GET "dns/domains/v1"; then + return 1 + fi + + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug "h" "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "\"$h\"" >/dev/null; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_active24_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Authorization: Bearer $ACTIVE24_Token" + + if [ "$m" != "GET" ]; then + _debug "data" "$data" + response="$(_post "$data" "$ACTIVE24_Api/$ep" "" "$m" "application/json")" + else + response="$(_get "$ACTIVE24_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} + +_active24_init() { + ACTIVE24_Token="${ACTIVE24_Token:-$(_readaccountconf_mutable ACTIVE24_Token)}" + if [ -z "$ACTIVE24_Token" ]; then + ACTIVE24_Token="" + _err "You didn't specify a Active24 api token yet." + _err "Please create the token and try again." + return 1 + fi + + _saveaccountconf_mutable ACTIVE24_Token "$ACTIVE24_Token" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" +} diff --git a/letsencrypt/dnsapi/dns_ad.sh b/letsencrypt/dnsapi/dns_ad.sh new file mode 100755 index 00000000..fe75184d --- /dev/null +++ b/letsencrypt/dnsapi/dns_ad.sh @@ -0,0 +1,147 @@ +#!/bin/bash + +# +#AD_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" + +#This is the Alwaysdata api wrapper for acme.sh +# +#Author: Paul Koppen +#Report Bugs here: https://github.com/wpk-/acme.sh + +AD_API_URL="https://$AD_API_KEY:@api.alwaysdata.com/v1" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_ad_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$AD_API_KEY" ]; then + AD_API_KEY="" + _err "You didn't specify the AD api key yet." + _err "Please create you key and try again." + return 1 + fi + + _saveaccountconf AD_API_KEY "$AD_API_KEY" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _ad_tmpl_json="{\"domain\":$_domain_id,\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\"}" + + if _ad_rest POST "record/" "$_ad_tmpl_json" && [ -z "$response" ]; then + _info "txt record updated success." + return 0 + fi + + return 1 +} + +#fulldomain txtvalue +dns_ad_rm() { + fulldomain=$1 + txtvalue=$2 + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _ad_rest GET "record/?domain=$_domain_id&name=$_sub_domain" + + if [ -n "$response" ]; then + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) + _debug record_id "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if _ad_rest DELETE "record/$record_id/" && [ -z "$response" ]; then + _info "txt record deleted success." + return 0 + fi + _debug response "$response" + return 1 + fi + + return 1 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=12345 +_get_root() { + domain=$1 + i=2 + p=1 + + if _ad_rest GET "domain/"; then + response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + hostedzone="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$h\".*}")" + if [ "$hostedzone" ]; then + _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + fi + return 1 +} + +#method uri qstr data +_ad_rest() { + mtd="$1" + ep="$2" + data="$3" + + _debug mtd "$mtd" + _debug ep "$ep" + + export _H1="Accept: application/json" + export _H2="Content-Type: application/json" + + if [ "$mtd" != "GET" ]; then + # both POST and DELETE. + _debug data "$data" + response="$(_post "$data" "$AD_API_URL/$ep" "" "$mtd")" + else + response="$(_get "$AD_API_URL/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_ali.sh b/letsencrypt/dnsapi/dns_ali.sh new file mode 100755 index 00000000..a8abdfbb --- /dev/null +++ b/letsencrypt/dnsapi/dns_ali.sh @@ -0,0 +1,203 @@ +#!/bin/bash + +Ali_API="https://alidns.aliyuncs.com/" + +#Ali_Key="LTqIA87hOKdjevsf5" +#Ali_Secret="0p5EYueFNq501xnCPzKNbx6K51qPH2" + +#Usage: dns_ali_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_ali_add() { + fulldomain=$1 + txtvalue=$2 + + Ali_Key="${Ali_Key:-$(_readaccountconf_mutable Ali_Key)}" + Ali_Secret="${Ali_Secret:-$(_readaccountconf_mutable Ali_Secret)}" + if [ -z "$Ali_Key" ] || [ -z "$Ali_Secret" ]; then + Ali_Key="" + Ali_Secret="" + _err "You don't specify aliyun api key and secret yet." + return 1 + fi + + #save the api key and secret to the account conf file. + _saveaccountconf_mutable Ali_Key "$Ali_Key" + _saveaccountconf_mutable Ali_Secret "$Ali_Secret" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + return 1 + fi + + _debug "Add record" + _add_record_query "$_domain" "$_sub_domain" "$txtvalue" && _ali_rest "Add record" +} + +dns_ali_rm() { + fulldomain=$1 + txtvalue=$2 + Ali_Key="${Ali_Key:-$(_readaccountconf_mutable Ali_Key)}" + Ali_Secret="${Ali_Secret:-$(_readaccountconf_mutable Ali_Secret)}" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + return 1 + fi + + _clean +} + +#################### Private functions below ################################## + +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + #not valid + return 1 + fi + + _describe_records_query "$h" + if ! _ali_rest "Get root" "ignore"; then + return 1 + fi + + if _contains "$response" "PageNumber"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _debug _sub_domain "$_sub_domain" + _domain="$h" + _debug _domain "$_domain" + return 0 + fi + p="$i" + i=$(_math "$i" + 1) + done + return 1 +} + +_ali_rest() { + signature=$(printf "%s" "GET&%2F&$(_ali_urlencode "$query")" | _hmac "sha1" "$(printf "%s" "$Ali_Secret&" | _hex_dump | tr -d " ")" | _base64) + signature=$(_ali_urlencode "$signature") + url="$Ali_API?$query&Signature=$signature" + + if ! response="$(_get "$url")"; then + _err "Error <$1>" + return 1 + fi + + _debug2 response "$response" + if [ -z "$2" ]; then + message="$(echo "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")" + if [ "$message" ]; then + _err "$message" + return 1 + fi + fi +} + +_ali_urlencode() { + _str="$1" + _str_len=${#_str} + _u_i=1 + while [ "$_u_i" -le "$_str_len" ]; do + _str_c="$(printf "%s" "$_str" | cut -c "$_u_i")" + case $_str_c in [a-zA-Z0-9.~_-]) + printf "%s" "$_str_c" + ;; + *) + printf "%%%02X" "'$_str_c" + ;; + esac + _u_i="$(_math "$_u_i" + 1)" + done +} + +_ali_nonce() { + #_head_n 1 /dev/null +} + +#################### Private functions below ################################## + +_is_uuid() { + pattern='^\{?[A-Z0-9a-z]{8}-[A-Z0-9a-z]{4}-[A-Z0-9a-z]{4}-[A-Z0-9a-z]{4}-[A-Z0-9a-z]{12}\}?$' + if echo "$1" | _egrep_o "$pattern" >/dev/null; then + return 0 + fi + return 1 +} + +_get_record_id() { + _debug subdomain "$_sub_domain" + _debug domain "$_domain" + + if _anx_rest GET "zone.json/${_domain}/records?name=$_sub_domain&type=TXT"; then + _debug response "$response" + if _contains "$response" "\"name\":\"$_sub_domain\"" >/dev/null; then + _record_id=$(printf "%s\n" "$response" | _egrep_o "\[.\"identifier\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") + else + _record_id='' + fi + else + _err "Search existing record" + fi +} + +_anx_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Content-Type: application/json" + export _H2="Authorization: Token $ANX_Token" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "${ANX_API}/$ep" "" "$m")" + else + response="$(_get "${ANX_API}/$ep")" + fi + + # shellcheck disable=SC2181 + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug response "$response" + return 0 +} + +_get_root() { + domain=$1 + i=1 + p=1 + + _anx_rest GET "zone.json" + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "\"name\":\"$h\""; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + + p=$i + i=$(_math "$i" + 1) + done + return 1 +} diff --git a/letsencrypt/dnsapi/dns_arvan.sh b/letsencrypt/dnsapi/dns_arvan.sh new file mode 100644 index 00000000..e241993d --- /dev/null +++ b/letsencrypt/dnsapi/dns_arvan.sh @@ -0,0 +1,163 @@ +#!/bin/bash + +#Arvan_Token="xxxx" + +ARVAN_API_URL="https://napi.arvancloud.com/cdn/4.0/domains" + +#Author: Ehsan Aliakbar +#Report Bugs here: https://github.com/Neilpang/acme.sh +# +######## Public functions ##################### + +#Usage: dns_arvan_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_arvan_add() { + fulldomain=$1 + txtvalue=$2 + _info "Using Arvan" + + Arvan_Token="${Arvan_Token:-$(_readaccountconf_mutable Arvan_Token)}" + + if [ -z "$Arvan_Token" ]; then + _err "You didn't specify \"Arvan_Token\" token yet." + _err "You can get yours from here https://npanel.arvancloud.com/profile/api-keys" + return 1 + fi + #save the api token to the account conf file. + _saveaccountconf_mutable Arvan_Token "$Arvan_Token" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _info "Adding record" + if _arvan_rest POST "$_domain/dns-records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":{\"text\":\"$txtvalue\"},\"ttl\":120}"; then + if _contains "$response" "$txtvalue"; then + _info "Added, OK" + return 0 + elif _contains "$response" "Record Data is Duplicated"; then + _info "Already exists, OK" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + return 1 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_arvan_rm() { + fulldomain=$1 + txtvalue=$2 + _info "Using Arvan" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + Arvan_Token="${Arvan_Token:-$(_readaccountconf_mutable Arvan_Token)}" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + shorted_txtvalue=$(printf "%s" "$txtvalue" | cut -d "-" -d "_" -f1) + _arvan_rest GET "${_domain}/dns-records?search=$shorted_txtvalue" + + if ! printf "%s" "$response" | grep \"current_page\":1 >/dev/null; then + _err "Error on Arvan Api" + _err "Please create a github issue with debbug log" + return 1 + fi + + count=$(printf "%s\n" "$response" | _egrep_o "\"total\":[^,]*" | cut -d : -f 2) + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Don't need to remove." + else + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) + _debug "record_id" "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if ! _arvan_rest "DELETE" "${_domain}/dns-records/$record_id"; then + _err "Delete record error." + return 1 + fi + _debug "$response" + _contains "$response" 'dns record deleted' + fi +} + +#################### Private functions below ################################## + +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=1 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _arvan_rest GET "?search=$h"; then + return 1 + fi + + if _contains "$response" "\"domain\":\"$h\"" || _contains "$response" '"total":1'; then + _domain_id=$(echo "$response" | _egrep_o "\[.\"id\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_arvan_rest() { + mtd="$1" + ep="$2" + data="$3" + + token_trimmed=$(echo "$Arvan_Token" | tr -d '"') + + export _H1="Authorization: $token_trimmed" + + if [ "$mtd" = "DELETE" ]; then + #DELETE Request shouldn't have Content-Type + _debug data "$data" + response="$(_post "$data" "$ARVAN_API_URL/$ep" "" "$mtd")" + elif [ "$mtd" = "POST" ]; then + export _H2="Content-Type: application/json" + _debug data "$data" + response="$(_post "$data" "$ARVAN_API_URL/$ep" "" "$mtd")" + else + response="$(_get "$ARVAN_API_URL/$ep$data")" + fi +} diff --git a/letsencrypt/dnsapi/dns_autodns.sh b/letsencrypt/dnsapi/dns_autodns.sh new file mode 100644 index 00000000..c24d7409 --- /dev/null +++ b/letsencrypt/dnsapi/dns_autodns.sh @@ -0,0 +1,264 @@ +#!/bin/bash +# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*- + +# This is the InternetX autoDNS xml api wrapper for acme.sh +# Author: auerswald@gmail.com +# Created: 2018-01-14 +# +# export AUTODNS_USER="username" +# export AUTODNS_PASSWORD="password" +# export AUTODNS_CONTEXT="context" +# +# Usage: +# acme.sh --issue --dns dns_autodns -d example.com + +AUTODNS_API="https://gateway.autodns.com" + +# Arguments: +# txtdomain +# txt +dns_autodns_add() { + fulldomain="$1" + txtvalue="$2" + + AUTODNS_USER="${AUTODNS_USER:-$(_readaccountconf_mutable AUTODNS_USER)}" + AUTODNS_PASSWORD="${AUTODNS_PASSWORD:-$(_readaccountconf_mutable AUTODNS_PASSWORD)}" + AUTODNS_CONTEXT="${AUTODNS_CONTEXT:-$(_readaccountconf_mutable AUTODNS_CONTEXT)}" + + if [ -z "$AUTODNS_USER" ] || [ -z "$AUTODNS_CONTEXT" ] || [ -z "$AUTODNS_PASSWORD" ]; then + _err "You don't specify autodns user, password and context." + return 1 + fi + + _saveaccountconf_mutable AUTODNS_USER "$AUTODNS_USER" + _saveaccountconf_mutable AUTODNS_PASSWORD "$AUTODNS_PASSWORD" + _saveaccountconf_mutable AUTODNS_CONTEXT "$AUTODNS_CONTEXT" + + _debug "First detect the root zone" + + if ! _get_autodns_zone "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _zone "$_zone" + _debug _system_ns "$_system_ns" + + _info "Adding TXT record" + + autodns_response="$(_autodns_zone_update "$_zone" "$_sub_domain" "$txtvalue" "$_system_ns")" + + if [ "$?" -eq "0" ]; then + _info "Added, OK" + return 0 + fi + + return 1 +} + +# Arguments: +# txtdomain +# txt +dns_autodns_rm() { + fulldomain="$1" + txtvalue="$2" + + AUTODNS_USER="${AUTODNS_USER:-$(_readaccountconf_mutable AUTODNS_USER)}" + AUTODNS_PASSWORD="${AUTODNS_PASSWORD:-$(_readaccountconf_mutable AUTODNS_PASSWORD)}" + AUTODNS_CONTEXT="${AUTODNS_CONTEXT:-$(_readaccountconf_mutable AUTODNS_CONTEXT)}" + + if [ -z "$AUTODNS_USER" ] || [ -z "$AUTODNS_CONTEXT" ] || [ -z "$AUTODNS_PASSWORD" ]; then + _err "You don't specify autodns user, password and context." + return 1 + fi + + _debug "First detect the root zone" + + if ! _get_autodns_zone "$fulldomain"; then + _err "zone not found" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _zone "$_zone" + _debug _system_ns "$_system_ns" + + _info "Delete TXT record" + + autodns_response="$(_autodns_zone_cleanup "$_zone" "$_sub_domain" "$txtvalue" "$_system_ns")" + + if [ "$?" -eq "0" ]; then + _info "Deleted, OK" + return 0 + fi + + return 1 +} + +#################### Private functions below ################################## + +# Arguments: +# fulldomain +# Returns: +# _sub_domain=_acme-challenge.www +# _zone=domain.com +# _system_ns +_get_autodns_zone() { + domain="$1" + + i=2 + p=1 + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + + if [ -z "$h" ]; then + # not valid + return 1 + fi + + autodns_response="$(_autodns_zone_inquire "$h")" + + if [ "$?" -ne "0" ]; then + _err "invalid domain" + return 1 + fi + + if _contains "$autodns_response" "

1" >/dev/null; then + _zone="$(echo "$autodns_response" | _egrep_o '[^<]*' | cut -d '>' -f 2 | cut -d '<' -f 1)" + _system_ns="$(echo "$autodns_response" | _egrep_o '[^<]*' | cut -d '>' -f 2 | cut -d '<' -f 1)" + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + return 0 + fi + + p=$i + i=$(_math "$i" + 1) + done + + return 1 +} + +_build_request_auth_xml() { + printf " + %s + %s + %s + " "$AUTODNS_USER" "$AUTODNS_PASSWORD" "$AUTODNS_CONTEXT" +} + +# Arguments: +# zone +_build_zone_inquire_xml() { + printf " + + %s + + 0205 + + 1 + 1 + + + name + eq + %s + + + " "$(_build_request_auth_xml)" "$1" +} + +# Arguments: +# zone +# subdomain +# txtvalue +# system_ns +_build_zone_update_xml() { + printf " + + %s + + 0202001 + + + %s + 600 + TXT + %s + + + + %s + %s + + + " "$(_build_request_auth_xml)" "$2" "$3" "$1" "$4" +} + +# Arguments: +# zone +_autodns_zone_inquire() { + request_data="$(_build_zone_inquire_xml "$1")" + autodns_response="$(_autodns_api_call "$request_data")" + ret="$?" + + printf "%s" "$autodns_response" + return "$ret" +} + +# Arguments: +# zone +# subdomain +# txtvalue +# system_ns +_autodns_zone_update() { + request_data="$(_build_zone_update_xml "$1" "$2" "$3" "$4")" + autodns_response="$(_autodns_api_call "$request_data")" + ret="$?" + + printf "%s" "$autodns_response" + return "$ret" +} + +# Arguments: +# zone +# subdomain +# txtvalue +# system_ns +_autodns_zone_cleanup() { + request_data="$(_build_zone_update_xml "$1" "$2" "$3" "$4")" + # replace 'rr_add>' with 'rr_rem>' in request_data + request_data="$(printf -- "%s" "$request_data" | sed 's/rr_add>/rr_rem>/g')" + autodns_response="$(_autodns_api_call "$request_data")" + ret="$?" + + printf "%s" "$autodns_response" + return "$ret" +} + +# Arguments: +# request_data +_autodns_api_call() { + request_data="$1" + + _debug request_data "$request_data" + + autodns_response="$(_post "$request_data" "$AUTODNS_API")" + ret="$?" + + _debug autodns_response "$autodns_response" + + if [ "$ret" -ne "0" ]; then + _err "error" + return 1 + fi + + if _contains "$autodns_response" "success" >/dev/null; then + _info "success" + printf "%s" "$autodns_response" + return 0 + fi + + return 1 +} diff --git a/letsencrypt/dnsapi/dns_aws.sh b/letsencrypt/dnsapi/dns_aws.sh new file mode 100755 index 00000000..fcf8d7ac --- /dev/null +++ b/letsencrypt/dnsapi/dns_aws.sh @@ -0,0 +1,365 @@ +#!/bin/bash + +# +#AWS_ACCESS_KEY_ID="sdfsdfsdfljlbjkljlkjsdfoiwje" +# +#AWS_SECRET_ACCESS_KEY="xxxxxxx" + +#This is the Amazon Route53 api wrapper for acme.sh +#All `_sleep` commands are included to avoid Route53 throttling, see +#https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/DNSLimitations.html#limits-api-requests + +AWS_HOST="route53.amazonaws.com" +AWS_URL="https://$AWS_HOST" + +AWS_WIKI="https://github.com/acmesh-official/acme.sh/wiki/How-to-use-Amazon-Route53-API" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_aws_add() { + fulldomain=$1 + txtvalue=$2 + + AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID:-$(_readaccountconf_mutable AWS_ACCESS_KEY_ID)}" + AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-$(_readaccountconf_mutable AWS_SECRET_ACCESS_KEY)}" + AWS_DNS_SLOWRATE="${AWS_DNS_SLOWRATE:-$(_readaccountconf_mutable AWS_DNS_SLOWRATE)}" + + if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then + _use_container_role || _use_instance_role + fi + + if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then + AWS_ACCESS_KEY_ID="" + AWS_SECRET_ACCESS_KEY="" + _err "You haven't specifed the aws route53 api key id and and api key secret yet." + _err "Please create your key and try again. see $(__green $AWS_WIKI)" + return 1 + fi + + #save for future use, unless using a role which will be fetched as needed + if [ -z "$_using_role" ]; then + _saveaccountconf_mutable AWS_ACCESS_KEY_ID "$AWS_ACCESS_KEY_ID" + _saveaccountconf_mutable AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY" + _saveaccountconf_mutable AWS_DNS_SLOWRATE "$AWS_DNS_SLOWRATE" + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + _sleep 1 + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _info "Getting existing records for $fulldomain" + if ! aws_rest GET "2013-04-01$_domain_id/rrset" "name=$fulldomain&type=TXT"; then + _sleep 1 + return 1 + fi + + if _contains "$response" "$fulldomain."; then + _resource_record="$(echo "$response" | sed 's//"/g' | tr '"' "\n" | grep "$fulldomain." | _egrep_o "" | sed "s///" | sed "s###")" + _debug "_resource_record" "$_resource_record" + else + _debug "single new add" + fi + + if [ "$_resource_record" ] && _contains "$response" "$txtvalue"; then + _info "The TXT record already exists. Skipping." + _sleep 1 + return 0 + fi + + _debug "Adding records" + + _aws_tmpl_xml="UPSERT$fulldomainTXT300$_resource_record\"$txtvalue\"" + + if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then + _info "TXT record updated successfully." + if [ -n "$AWS_DNS_SLOWRATE" ]; then + _info "Slow rate activated: sleeping for $AWS_DNS_SLOWRATE seconds" + _sleep "$AWS_DNS_SLOWRATE" + else + _sleep 1 + fi + + return 0 + fi + _sleep 1 + return 1 +} + +#fulldomain txtvalue +dns_aws_rm() { + fulldomain=$1 + txtvalue=$2 + + AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID:-$(_readaccountconf_mutable AWS_ACCESS_KEY_ID)}" + AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-$(_readaccountconf_mutable AWS_SECRET_ACCESS_KEY)}" + AWS_DNS_SLOWRATE="${AWS_DNS_SLOWRATE:-$(_readaccountconf_mutable AWS_DNS_SLOWRATE)}" + + if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then + _use_container_role || _use_instance_role + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + _sleep 1 + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _info "Getting existing records for $fulldomain" + if ! aws_rest GET "2013-04-01$_domain_id/rrset" "name=$fulldomain&type=TXT"; then + _sleep 1 + return 1 + fi + + if _contains "$response" "$fulldomain."; then + _resource_record="$(echo "$response" | sed 's//"/g' | tr '"' "\n" | grep "$fulldomain." | _egrep_o "" | sed "s///" | sed "s###")" + _debug "_resource_record" "$_resource_record" + else + _debug "no records exist, skip" + _sleep 1 + return 0 + fi + + _aws_tmpl_xml="DELETE$_resource_record$fulldomain.TXT300" + + if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then + _info "TXT record deleted successfully." + if [ -n "$AWS_DNS_SLOWRATE" ]; then + _info "Slow rate activated: sleeping for $AWS_DNS_SLOWRATE seconds" + _sleep "$AWS_DNS_SLOWRATE" + else + _sleep 1 + fi + + return 0 + fi + _sleep 1 + return 1 + +} + +#################### Private functions below ################################## + +_get_root() { + domain=$1 + i=2 + p=1 + + if aws_rest GET "2013-04-01/hostedzone"; then + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug2 "Checking domain: $h" + if [ -z "$h" ]; then + if _contains "$response" "true" && _contains "$response" ""; then + _debug "IsTruncated" + _nextMarker="$(echo "$response" | _egrep_o ".*" | cut -d '>' -f 2 | cut -d '<' -f 1)" + _debug "NextMarker" "$_nextMarker" + if aws_rest GET "2013-04-01/hostedzone" "marker=$_nextMarker"; then + _debug "Truncated request OK" + i=2 + p=1 + continue + else + _err "Truncated request error." + fi + fi + #not valid + _err "Invalid domain" + return 1 + fi + + if _contains "$response" "$h."; then + hostedzone="$(echo "$response" | sed 's//#&/g' | tr '#' '\n' | _egrep_o "[^<]*<.Id>$h.<.Name>.*false<.PrivateZone>.*<.HostedZone>")" + _debug hostedzone "$hostedzone" + if [ "$hostedzone" ]; then + _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o ".*<.Id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>") + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + _err "Can't find domain with id: $h" + return 1 + fi + fi + p=$i + i=$(_math "$i" + 1) + done + fi + return 1 +} + +_use_container_role() { + # automatically set if running inside ECS + if [ -z "$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" ]; then + _debug "No ECS environment variable detected" + return 1 + fi + _use_metadata "169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" +} + +_use_instance_role() { + _url="http://169.254.169.254/latest/meta-data/iam/security-credentials/" + _debug "_url" "$_url" + if ! _get "$_url" true 1 | _head_n 1 | grep -Fq 200; then + _debug "Unable to fetch IAM role from instance metadata" + return 1 + fi + _aws_role=$(_get "$_url" "" 1) + _debug "_aws_role" "$_aws_role" + _use_metadata "$_url$_aws_role" +} + +_use_metadata() { + _aws_creds="$( + _get "$1" "" 1 | + _normalizeJson | + tr '{,}' '\n' | + while read -r _line; do + _key="$(echo "${_line%%:*}" | tr -d '"')" + _value="${_line#*:}" + _debug3 "_key" "$_key" + _secure_debug3 "_value" "$_value" + case "$_key" in + AccessKeyId) echo "AWS_ACCESS_KEY_ID=$_value" ;; + SecretAccessKey) echo "AWS_SECRET_ACCESS_KEY=$_value" ;; + Token) echo "AWS_SESSION_TOKEN=$_value" ;; + esac + done | + paste -sd' ' - + )" + _secure_debug "_aws_creds" "$_aws_creds" + + if [ -z "$_aws_creds" ]; then + return 1 + fi + + eval "$_aws_creds" + _using_role=true +} + +#method uri qstr data +aws_rest() { + mtd="$1" + ep="$2" + qsr="$3" + data="$4" + + _debug mtd "$mtd" + _debug ep "$ep" + _debug qsr "$qsr" + _debug data "$data" + + CanonicalURI="/$ep" + _debug2 CanonicalURI "$CanonicalURI" + + CanonicalQueryString="$qsr" + _debug2 CanonicalQueryString "$CanonicalQueryString" + + RequestDate="$(date -u +"%Y%m%dT%H%M%SZ")" + _debug2 RequestDate "$RequestDate" + + #RequestDate="20161120T141056Z" ############## + + export _H1="x-amz-date: $RequestDate" + + aws_host="$AWS_HOST" + CanonicalHeaders="host:$aws_host\nx-amz-date:$RequestDate\n" + SignedHeaders="host;x-amz-date" + if [ -n "$AWS_SESSION_TOKEN" ]; then + export _H3="x-amz-security-token: $AWS_SESSION_TOKEN" + CanonicalHeaders="${CanonicalHeaders}x-amz-security-token:$AWS_SESSION_TOKEN\n" + SignedHeaders="${SignedHeaders};x-amz-security-token" + fi + _debug2 CanonicalHeaders "$CanonicalHeaders" + _debug2 SignedHeaders "$SignedHeaders" + + RequestPayload="$data" + _debug2 RequestPayload "$RequestPayload" + + Hash="sha256" + + CanonicalRequest="$mtd\n$CanonicalURI\n$CanonicalQueryString\n$CanonicalHeaders\n$SignedHeaders\n$(printf "%s" "$RequestPayload" | _digest "$Hash" hex)" + _debug2 CanonicalRequest "$CanonicalRequest" + + HashedCanonicalRequest="$(printf "$CanonicalRequest%s" | _digest "$Hash" hex)" + _debug2 HashedCanonicalRequest "$HashedCanonicalRequest" + + Algorithm="AWS4-HMAC-SHA256" + _debug2 Algorithm "$Algorithm" + + RequestDateOnly="$(echo "$RequestDate" | cut -c 1-8)" + _debug2 RequestDateOnly "$RequestDateOnly" + + Region="us-east-1" + Service="route53" + + CredentialScope="$RequestDateOnly/$Region/$Service/aws4_request" + _debug2 CredentialScope "$CredentialScope" + + StringToSign="$Algorithm\n$RequestDate\n$CredentialScope\n$HashedCanonicalRequest" + + _debug2 StringToSign "$StringToSign" + + kSecret="AWS4$AWS_SECRET_ACCESS_KEY" + + #kSecret="wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" ############################ + + _secure_debug2 kSecret "$kSecret" + + kSecretH="$(printf "%s" "$kSecret" | _hex_dump | tr -d " ")" + _secure_debug2 kSecretH "$kSecretH" + + kDateH="$(printf "$RequestDateOnly%s" | _hmac "$Hash" "$kSecretH" hex)" + _debug2 kDateH "$kDateH" + + kRegionH="$(printf "$Region%s" | _hmac "$Hash" "$kDateH" hex)" + _debug2 kRegionH "$kRegionH" + + kServiceH="$(printf "$Service%s" | _hmac "$Hash" "$kRegionH" hex)" + _debug2 kServiceH "$kServiceH" + + kSigningH="$(printf "%s" "aws4_request" | _hmac "$Hash" "$kServiceH" hex)" + _debug2 kSigningH "$kSigningH" + + signature="$(printf "$StringToSign%s" | _hmac "$Hash" "$kSigningH" hex)" + _debug2 signature "$signature" + + Authorization="$Algorithm Credential=$AWS_ACCESS_KEY_ID/$CredentialScope, SignedHeaders=$SignedHeaders, Signature=$signature" + _debug2 Authorization "$Authorization" + + _H2="Authorization: $Authorization" + _debug _H2 "$_H2" + + url="$AWS_URL/$ep" + if [ "$qsr" ]; then + url="$AWS_URL/$ep?$qsr" + fi + + if [ "$mtd" = "GET" ]; then + response="$(_get "$url")" + else + response="$(_post "$data" "$url")" + fi + + _ret="$?" + _debug2 response "$response" + if [ "$_ret" = "0" ]; then + if _contains "$response" ""$HTTP_HEADER" + _debug "$ep" + if [ "$m" != "GET" ]; then + _secure_debug2 "data $data" + response="$(_post "$data" "$ep" "" "$m")" + else + response="$(_get "$ep")" + fi + _ret="$?" + _secure_debug2 "response $response" + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" + _debug "http response code $_code" + if [ "$_code" = "401" ]; then + # we have an invalid access token set to expired + _saveaccountconf_mutable AZUREDNS_TOKENVALIDTO "0" + _err "access denied make sure your Azure settings are correct. See $WIKI" + return 1 + fi + # See https://docs.microsoft.com/en-us/azure/architecture/best-practices/retry-service-specific#general-rest-and-retry-guidelines for retryable HTTP codes + if [ "$_ret" != "0" ] || [ -z "$_code" ] || [ "$_code" = "408" ] || [ "$_code" = "500" ] || [ "$_code" = "503" ] || [ "$_code" = "504" ]; then + _request_retry_times="$(_math "$_request_retry_times" + 1)" + _info "REST call error $_code retrying $ep in $_request_retry_times s" + _sleep "$_request_retry_times" + continue + fi + break + done + if [ "$_request_retry_times" = "$MAX_REQUEST_RETRY_TIMES" ]; then + _err "Error Azure REST called was retried $MAX_REQUEST_RETRY_TIMES times." + _err "Calling $ep failed." + return 1 + fi + response="$(echo "$response" | _normalizeJson)" + return 0 +} + +## Ref: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service#request-an-access-token +_azure_getaccess_token() { + tenantID=$1 + clientID=$2 + clientSecret=$3 + + accesstoken="${AZUREDNS_BEARERTOKEN:-$(_readaccountconf_mutable AZUREDNS_BEARERTOKEN)}" + expires_on="${AZUREDNS_TOKENVALIDTO:-$(_readaccountconf_mutable AZUREDNS_TOKENVALIDTO)}" + + # can we reuse the bearer token? + if [ -n "$accesstoken" ] && [ -n "$expires_on" ]; then + if [ "$(_time)" -lt "$expires_on" ]; then + # brearer token is still valid - reuse it + _debug "reusing bearer token" + printf "%s" "$accesstoken" + return 0 + else + _debug "bearer token expired" + fi + fi + _debug "getting new bearer token" + + export _H1="accept: application/json" + export _H2="Content-Type: application/x-www-form-urlencoded" + + body="resource=$(printf "%s" 'https://management.core.windows.net/' | _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret" | _url_encode)&grant_type=client_credentials" + _secure_debug2 "data $body" + response="$(_post "$body" "https://login.microsoftonline.com/$tenantID/oauth2/token" "" "POST")" + _ret="$?" + _secure_debug2 "response $response" + response="$(echo "$response" | _normalizeJson)" + accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") + expires_on=$(echo "$response" | _egrep_o "\"expires_on\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") + + if [ -z "$accesstoken" ]; then + _err "no acccess token received. Check your Azure settings see $WIKI" + return 1 + fi + if [ "$_ret" != "0" ]; then + _err "error $response" + return 1 + fi + _saveaccountconf_mutable AZUREDNS_BEARERTOKEN "$accesstoken" + _saveaccountconf_mutable AZUREDNS_TOKENVALIDTO "$expires_on" + printf "%s" "$accesstoken" + return 0 +} + +_get_root() { + domain=$1 + subscriptionId=$2 + accesstoken=$3 + i=1 + p=1 + + ## Ref: https://docs.microsoft.com/en-us/rest/api/dns/zones/list + ## returns up to 100 zones in one response therefore handling more results is not not implemented + ## (ZoneListResult with continuation token for the next page of results) + ## Per https://docs.microsoft.com/en-us/azure/azure-subscription-service-limits#dns-limits you are limited to 100 Zone/subscriptions anyways + ## + _azure_rest GET "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Network/dnszones?\$top=500&api-version=2017-09-01" "" "$accesstoken" + # Find matching domain name in Json response + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug2 "Checking domain: $h" + if [ -z "$h" ]; then + #not valid + _err "Invalid domain" + return 1 + fi + + if _contains "$response" "\"name\":\"$h\"" >/dev/null; then + _domain_id=$(echo "$response" | _egrep_o "\\{\"id\":\"[^\"]*\\/$h\"" | head -n 1 | cut -d : -f 2 | tr -d \") + if [ "$_domain_id" ]; then + if [ "$i" = 1 ]; then + #create the record at the domain apex (@) if only the domain name was provided as --domain-alias + _sub_domain="@" + else + _sub_domain=$(echo "$domain" | cut -d . -f 1-$p) + fi + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} diff --git a/letsencrypt/dnsapi/dns_cf.sh b/letsencrypt/dnsapi/dns_cf.sh new file mode 100755 index 00000000..c58c3ee4 --- /dev/null +++ b/letsencrypt/dnsapi/dns_cf.sh @@ -0,0 +1,234 @@ +#!/bin/bash + +# +#CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# +#CF_Email="xxxx@sss.com" + +#CF_Token="xxxx" +#CF_Account_ID="xxxx" +#CF_Zone_ID="xxxx" + +CF_Api="https://api.cloudflare.com/client/v4" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_cf_add() { + fulldomain=$1 + txtvalue=$2 + + CF_Token="${CF_Token:-$(_readaccountconf_mutable CF_Token)}" + CF_Account_ID="${CF_Account_ID:-$(_readaccountconf_mutable CF_Account_ID)}" + CF_Zone_ID="${CF_Zone_ID:-$(_readaccountconf_mutable CF_Zone_ID)}" + CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}" + CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}" + + if [ "$CF_Token" ]; then + _saveaccountconf_mutable CF_Token "$CF_Token" + _saveaccountconf_mutable CF_Account_ID "$CF_Account_ID" + _saveaccountconf_mutable CF_Zone_ID "$CF_Zone_ID" + else + if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then + CF_Key="" + CF_Email="" + _err "You didn't specify a Cloudflare api key and email yet." + _err "You can get yours from here https://dash.cloudflare.com/profile." + return 1 + fi + + if ! _contains "$CF_Email" "@"; then + _err "It seems that the CF_Email=$CF_Email is not a valid email address." + _err "Please check and retry." + return 1 + fi + #save the api key and email to the account conf file. + _saveaccountconf_mutable CF_Key "$CF_Key" + _saveaccountconf_mutable CF_Email "$CF_Email" + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _cf_rest GET "zones/${_domain_id}/dns_records?type=TXT&name=$fulldomain" + + if ! echo "$response" | tr -d " " | grep \"success\":true >/dev/null; then + _err "Error" + return 1 + fi + + # For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so + # we can not use updating anymore. + # count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) + # _debug count "$count" + # if [ "$count" = "0" ]; then + _info "Adding record" + if _cf_rest POST "zones/$_domain_id/dns_records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then + if _contains "$response" "$txtvalue"; then + _info "Added, OK" + return 0 + elif _contains "$response" "The record already exists"; then + _info "Already exists, OK" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + return 1 + +} + +#fulldomain txtvalue +dns_cf_rm() { + fulldomain=$1 + txtvalue=$2 + + CF_Token="${CF_Token:-$(_readaccountconf_mutable CF_Token)}" + CF_Account_ID="${CF_Account_ID:-$(_readaccountconf_mutable CF_Account_ID)}" + CF_Zone_ID="${CF_Zone_ID:-$(_readaccountconf_mutable CF_Zone_ID)}" + CF_Key="${CF_Key:-$(_readaccountconf_mutable CF_Key)}" + CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _cf_rest GET "zones/${_domain_id}/dns_records?type=TXT&name=$fulldomain&content=$txtvalue" + + if ! echo "$response" | tr -d " " | grep \"success\":true >/dev/null; then + _err "Error: $response" + return 1 + fi + + count=$(echo "$response" | _egrep_o "\"count\": *[^,]*" | cut -d : -f 2 | tr -d " ") + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Don't need to remove." + else + record_id=$(echo "$response" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | _head_n 1 | tr -d " ") + _debug "record_id" "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if ! _cf_rest DELETE "zones/$_domain_id/dns_records/$record_id"; then + _err "Delete record error." + return 1 + fi + echo "$response" | tr -d " " | grep \"success\":true >/dev/null + fi + +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=1 + p=1 + + # Use Zone ID directly if provided + if [ "$CF_Zone_ID" ]; then + if ! _cf_rest GET "zones/$CF_Zone_ID"; then + return 1 + else + if echo "$response" | tr -d " " | grep \"success\":true >/dev/null; then + _domain=$(echo "$response" | _egrep_o "\"name\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | _head_n 1 | tr -d " ") + if [ "$_domain" ]; then + _cutlength=$((${#domain} - ${#_domain} - 1)) + _sub_domain=$(printf "%s" "$domain" | cut -c "1-$_cutlength") + _domain_id=$CF_Zone_ID + return 0 + else + return 1 + fi + else + return 1 + fi + fi + fi + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if [ "$CF_Account_ID" ]; then + if ! _cf_rest GET "zones?name=$h&account.id=$CF_Account_ID"; then + return 1 + fi + else + if ! _cf_rest GET "zones?name=$h"; then + return 1 + fi + fi + + if _contains "$response" "\"name\":\"$h\"" || _contains "$response" '"total_count":1'; then + _domain_id=$(echo "$response" | _egrep_o "\[.\"id\": *\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \" | tr -d " ") + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_cf_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + email_trimmed=$(echo "$CF_Email" | tr -d '"') + key_trimmed=$(echo "$CF_Key" | tr -d '"') + token_trimmed=$(echo "$CF_Token" | tr -d '"') + + export _H1="Content-Type: application/json" + if [ "$token_trimmed" ]; then + export _H2="Authorization: Bearer $token_trimmed" + else + export _H2="X-Auth-Email: $email_trimmed" + export _H3="X-Auth-Key: $key_trimmed" + fi + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$CF_Api/$ep" "" "$m")" + else + response="$(_get "$CF_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_clouddns.sh b/letsencrypt/dnsapi/dns_clouddns.sh new file mode 100755 index 00000000..b235ddb2 --- /dev/null +++ b/letsencrypt/dnsapi/dns_clouddns.sh @@ -0,0 +1,197 @@ +#!/bin/bash + +# Author: Radek Sprta + +#CLOUDDNS_EMAIL=XXXXX +#CLOUDDNS_PASSWORD="YYYYYYYYY" +#CLOUDDNS_CLIENT_ID=XXXXX + +CLOUDDNS_API='https://admin.vshosting.cloud/clouddns' +CLOUDDNS_LOGIN_API='https://admin.vshosting.cloud/api/public/auth/login' + +######## Public functions ##################### + +# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_clouddns_add() { + fulldomain=$1 + txtvalue=$2 + _debug "fulldomain" "$fulldomain" + + CLOUDDNS_CLIENT_ID="${CLOUDDNS_CLIENT_ID:-$(_readaccountconf_mutable CLOUDDNS_CLIENT_ID)}" + CLOUDDNS_EMAIL="${CLOUDDNS_EMAIL:-$(_readaccountconf_mutable CLOUDDNS_EMAIL)}" + CLOUDDNS_PASSWORD="${CLOUDDNS_PASSWORD:-$(_readaccountconf_mutable CLOUDDNS_PASSWORD)}" + + if [ -z "$CLOUDDNS_PASSWORD" ] || [ -z "$CLOUDDNS_EMAIL" ] || [ -z "$CLOUDDNS_CLIENT_ID" ]; then + CLOUDDNS_CLIENT_ID="" + CLOUDDNS_EMAIL="" + CLOUDDNS_PASSWORD="" + _err "You didn't specify a CloudDNS password, email and client ID yet." + return 1 + fi + if ! _contains "$CLOUDDNS_EMAIL" "@"; then + _err "It seems that the CLOUDDNS_EMAIL=$CLOUDDNS_EMAIL is not a valid email address." + _err "Please check and retry." + return 1 + fi + # Save CloudDNS client id, email and password to config file + _saveaccountconf_mutable CLOUDDNS_CLIENT_ID "$CLOUDDNS_CLIENT_ID" + _saveaccountconf_mutable CLOUDDNS_EMAIL "$CLOUDDNS_EMAIL" + _saveaccountconf_mutable CLOUDDNS_PASSWORD "$CLOUDDNS_PASSWORD" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "Invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + # Add TXT record + data="{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"value\":\"$txtvalue\",\"domainId\":\"$_domain_id\"}" + if _clouddns_api POST "record-txt" "$data"; then + if _contains "$response" "$txtvalue"; then + _info "Added, OK" + elif _contains "$response" '"code":4136'; then + _info "Already exists, OK" + else + _err "Add TXT record error." + return 1 + fi + fi + + _debug "Publishing record changes" + _clouddns_api PUT "domain/$_domain_id/publish" "{\"soaTtl\":300}" +} + +# Usage: rm _acme-challenge.www.domain.com +dns_clouddns_rm() { + fulldomain=$1 + _debug "fulldomain" "$fulldomain" + + CLOUDDNS_CLIENT_ID="${CLOUDDNS_CLIENT_ID:-$(_readaccountconf_mutable CLOUDDNS_CLIENT_ID)}" + CLOUDDNS_EMAIL="${CLOUDDNS_EMAIL:-$(_readaccountconf_mutable CLOUDDNS_EMAIL)}" + CLOUDDNS_PASSWORD="${CLOUDDNS_PASSWORD:-$(_readaccountconf_mutable CLOUDDNS_PASSWORD)}" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "Invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + # Get record ID + _clouddns_api GET "domain/$_domain_id" + if _contains "$response" "lastDomainRecordList"; then + re="\"lastDomainRecordList\".*\"id\":\"([^\"}]*)\"[^}]*\"name\":\"$fulldomain.\"," + _last_domains=$(echo "$response" | _egrep_o "$re") + re2="\"id\":\"([^\"}]*)\"[^}]*\"name\":\"$fulldomain.\"," + _record_id=$(echo "$_last_domains" | _egrep_o "$re2" | _head_n 1 | cut -d : -f 2 | cut -d , -f 1 | tr -d "\"") + _debug _record_id "$_record_id" + else + _err "Could not retrieve record ID" + return 1 + fi + + _info "Removing record" + if _clouddns_api DELETE "record/$_record_id"; then + if _contains "$response" "\"error\":"; then + _err "Could not remove record" + return 1 + fi + fi + + _debug "Publishing record changes" + _clouddns_api PUT "domain/$_domain_id/publish" "{\"soaTtl\":300}" +} + +#################### Private functions below ################################## + +# Usage: _get_root _acme-challenge.www.domain.com +# Returns: +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + + # Get domain root + data="{\"search\": [{\"name\": \"clientId\", \"operator\": \"eq\", \"value\": \"$CLOUDDNS_CLIENT_ID\"}]}" + _clouddns_api "POST" "domain/search" "$data" + domain_slice="$domain" + while [ -z "$domain_root" ]; do + if _contains "$response" "\"domainName\":\"$domain_slice\.\""; then + domain_root="$domain_slice" + _debug domain_root "$domain_root" + fi + domain_slice="$(echo "$domain_slice" | cut -d . -f 2-)" + done + + # Get domain id + data="{\"search\": [{\"name\": \"clientId\", \"operator\": \"eq\", \"value\": \"$CLOUDDNS_CLIENT_ID\"}, \ + {\"name\": \"domainName\", \"operator\": \"eq\", \"value\": \"$domain_root.\"}]}" + _clouddns_api "POST" "domain/search" "$data" + if _contains "$response" "\"id\":\""; then + re='domainType\":\"[^\"]*\",\"id\":\"([^\"]*)\",' # Match domain id + _domain_id=$(echo "$response" | _egrep_o "$re" | _head_n 1 | cut -d : -f 3 | tr -d "\",") + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | sed "s/.$domain_root//") + _domain="$domain_root" + return 0 + fi + _err 'Domain name not found on your CloudDNS account' + return 1 + fi + return 1 +} + +# Usage: _clouddns_api GET domain/search '{"data": "value"}' +# Returns: +# response='{"message": "api response"}' +_clouddns_api() { + method=$1 + endpoint="$2" + data="$3" + _debug endpoint "$endpoint" + + if [ -z "$CLOUDDNS_TOKEN" ]; then + _clouddns_login + fi + _debug CLOUDDNS_TOKEN "$CLOUDDNS_TOKEN" + + export _H1="Content-Type: application/json" + export _H2="Authorization: Bearer $CLOUDDNS_TOKEN" + + if [ "$method" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$CLOUDDNS_API/$endpoint" "" "$method" | tr -d '\t\r\n ')" + else + response="$(_get "$CLOUDDNS_API/$endpoint" | tr -d '\t\r\n ')" + fi + + # shellcheck disable=SC2181 + if [ "$?" != "0" ]; then + _err "Error $endpoint" + return 1 + fi + _debug2 response "$response" + return 0 +} + +# Returns: +# CLOUDDNS_TOKEN=dslfje2rj23l +_clouddns_login() { + login_data="{\"email\": \"$CLOUDDNS_EMAIL\", \"password\": \"$CLOUDDNS_PASSWORD\"}" + response="$(_post "$login_data" "$CLOUDDNS_LOGIN_API" "" "POST" "Content-Type: application/json")" + + if _contains "$response" "\"accessToken\":\""; then + CLOUDDNS_TOKEN=$(echo "$response" | _egrep_o "\"accessToken\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") + export CLOUDDNS_TOKEN + else + echo 'Could not get CloudDNS access token; check your credentials' + return 1 + fi + return 0 +} diff --git a/letsencrypt/dnsapi/dns_cloudns.sh b/letsencrypt/dnsapi/dns_cloudns.sh new file mode 100755 index 00000000..801835e5 --- /dev/null +++ b/letsencrypt/dnsapi/dns_cloudns.sh @@ -0,0 +1,184 @@ +#!/bin/bash + +# Author: Boyan Peychev +# Repository: https://github.com/ClouDNS/acme.sh/ + +#CLOUDNS_AUTH_ID=XXXXX +#CLOUDNS_SUB_AUTH_ID=XXXXX +#CLOUDNS_AUTH_PASSWORD="YYYYYYYYY" +CLOUDNS_API="https://api.cloudns.net" + +######## Public functions ##################### + +#Usage: dns_cloudns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_cloudns_add() { + _info "Using cloudns" + + if ! _dns_cloudns_init_check; then + return 1 + fi + + zone="$(_dns_cloudns_get_zone_name "$1")" + if [ -z "$zone" ]; then + _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." + return 1 + fi + + host="$(echo "$1" | sed "s/\.$zone\$//")" + record=$2 + + _debug zone "$zone" + _debug host "$host" + _debug record "$record" + + _info "Adding the TXT record for $1" + _dns_cloudns_http_api_call "dns/add-record.json" "domain-name=$zone&record-type=TXT&host=$host&record=$record&ttl=60" + if ! _contains "$response" "\"status\":\"Success\""; then + _err "Record cannot be added." + return 1 + fi + _info "Added." + + return 0 +} + +#Usage: dns_cloudns_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_cloudns_rm() { + _info "Using cloudns" + + if ! _dns_cloudns_init_check; then + return 1 + fi + + if [ -z "$zone" ]; then + zone="$(_dns_cloudns_get_zone_name "$1")" + if [ -z "$zone" ]; then + _err "Missing DNS zone at ClouDNS. Please log into your control panel and create the required DNS zone for the initial setup." + return 1 + fi + fi + + host="$(echo "$1" | sed "s/\.$zone\$//")" + record=$2 + + _dns_cloudns_http_api_call "dns/records.json" "domain-name=$zone&host=$host&type=TXT" + if ! _contains "$response" "\"id\":"; then + return 1 + fi + + for i in $(echo "$response" | tr '{' "\n" | grep "$record"); do + record_id=$(echo "$i" | tr ',' "\n" | grep -E '^"id"' | sed -re 's/^\"id\"\:\"([0-9]+)\"$/\1/g') + + if [ -n "$record_id" ]; then + _debug zone "$zone" + _debug host "$host" + _debug record "$record" + _debug record_id "$record_id" + + _info "Deleting the TXT record for $1" + _dns_cloudns_http_api_call "dns/delete-record.json" "domain-name=$zone&record-id=$record_id" + + if ! _contains "$response" "\"status\":\"Success\""; then + _err "The TXT record for $1 cannot be deleted." + else + _info "Deleted." + fi + fi + done + + return 0 +} + +#################### Private functions below ################################## +_dns_cloudns_init_check() { + if [ -n "$CLOUDNS_INIT_CHECK_COMPLETED" ]; then + return 0 + fi + + CLOUDNS_AUTH_ID="${CLOUDNS_AUTH_ID:-$(_readaccountconf_mutable CLOUDNS_AUTH_ID)}" + CLOUDNS_SUB_AUTH_ID="${CLOUDNS_SUB_AUTH_ID:-$(_readaccountconf_mutable CLOUDNS_SUB_AUTH_ID)}" + CLOUDNS_AUTH_PASSWORD="${CLOUDNS_AUTH_PASSWORD:-$(_readaccountconf_mutable CLOUDNS_AUTH_PASSWORD)}" + if [ -z "$CLOUDNS_AUTH_ID$CLOUDNS_SUB_AUTH_ID" ] || [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then + CLOUDNS_AUTH_ID="" + CLOUDNS_SUB_AUTH_ID="" + CLOUDNS_AUTH_PASSWORD="" + _err "You don't specify cloudns api id and password yet." + _err "Please create you id and password and try again." + return 1 + fi + + if [ -z "$CLOUDNS_AUTH_ID" ] && [ -z "$CLOUDNS_SUB_AUTH_ID" ]; then + _err "CLOUDNS_AUTH_ID or CLOUDNS_SUB_AUTH_ID is not configured" + return 1 + fi + + if [ -z "$CLOUDNS_AUTH_PASSWORD" ]; then + _err "CLOUDNS_AUTH_PASSWORD is not configured" + return 1 + fi + + _dns_cloudns_http_api_call "dns/login.json" "" + + if ! _contains "$response" "\"status\":\"Success\""; then + _err "Invalid CLOUDNS_AUTH_ID or CLOUDNS_AUTH_PASSWORD. Please check your login credentials." + return 1 + fi + + # save the api id and password to the account conf file. + _saveaccountconf_mutable CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" + _saveaccountconf_mutable CLOUDNS_SUB_AUTH_ID "$CLOUDNS_SUB_AUTH_ID" + _saveaccountconf_mutable CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" + + CLOUDNS_INIT_CHECK_COMPLETED=1 + + return 0 +} + +_dns_cloudns_get_zone_name() { + i=2 + while true; do + zoneForCheck=$(printf "%s" "$1" | cut -d . -f $i-100) + + if [ -z "$zoneForCheck" ]; then + return 1 + fi + + _debug zoneForCheck "$zoneForCheck" + + _dns_cloudns_http_api_call "dns/get-zone-info.json" "domain-name=$zoneForCheck" + + if ! _contains "$response" "\"status\":\"Failed\""; then + echo "$zoneForCheck" + return 0 + fi + + i=$(_math "$i" + 1) + done + return 1 +} + +_dns_cloudns_http_api_call() { + method=$1 + + _debug CLOUDNS_AUTH_ID "$CLOUDNS_AUTH_ID" + _debug CLOUDNS_SUB_AUTH_ID "$CLOUDNS_SUB_AUTH_ID" + _debug CLOUDNS_AUTH_PASSWORD "$CLOUDNS_AUTH_PASSWORD" + + if [ -n "$CLOUDNS_SUB_AUTH_ID" ]; then + auth_user="sub-auth-id=$CLOUDNS_SUB_AUTH_ID" + else + auth_user="auth-id=$CLOUDNS_AUTH_ID" + fi + + if [ -z "$2" ]; then + data="$auth_user&auth-password=$CLOUDNS_AUTH_PASSWORD" + else + data="$auth_user&auth-password=$CLOUDNS_AUTH_PASSWORD&$2" + fi + + response="$(_get "$CLOUDNS_API/$method?$data")" + + _debug response "$response" + + return 0 +} diff --git a/letsencrypt/dnsapi/dns_cn.sh b/letsencrypt/dnsapi/dns_cn.sh new file mode 100644 index 00000000..c1c40433 --- /dev/null +++ b/letsencrypt/dnsapi/dns_cn.sh @@ -0,0 +1,157 @@ +#!/bin/bash + +# DNS API for acme.sh for Core-Networks (https://beta.api.core-networks.de/doc/). +# created by 5ll and francis + +CN_API="https://beta.api.core-networks.de" + +######## Public functions ##################### + +dns_cn_add() { + fulldomain=$1 + txtvalue=$2 + + if ! _cn_login; then + _err "login failed" + return 1 + fi + + _debug "First detect the root zone" + if ! _cn_get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug "_sub_domain $_sub_domain" + _debug "_domain $_domain" + + _info "Adding record" + curData="{\"name\":\"$_sub_domain\",\"ttl\":120,\"type\":\"TXT\",\"data\":\"$txtvalue\"}" + curResult="$(_post "${curData}" "${CN_API}/dnszones/${_domain}/records/")" + + _debug "curData $curData" + _debug "curResult $curResult" + + if _contains "$curResult" ""; then + _info "Added, OK" + + if ! _cn_commit; then + _err "commiting changes failed" + return 1 + fi + return 0 + + else + _err "Add txt record error." + _debug "curData is $curData" + _debug "curResult is $curResult" + _err "error adding text record, response was $curResult" + return 1 + fi +} + +dns_cn_rm() { + fulldomain=$1 + txtvalue=$2 + + if ! _cn_login; then + _err "login failed" + return 1 + fi + + _debug "First detect the root zone" + if ! _cn_get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _info "Deleting record" + curData="{\"name\":\"$_sub_domain\",\"data\":\"$txtvalue\"}" + curResult="$(_post "${curData}" "${CN_API}/dnszones/${_domain}/records/delete")" + _debug curData is "$curData" + + _info "commiting changes" + if ! _cn_commit; then + _err "commiting changes failed" + return 1 + fi + + _info "Deletet txt record" + return 0 +} + +################### Private functions below ################################## +_cn_login() { + CN_User="${CN_User:-$(_readaccountconf_mutable CN_User)}" + CN_Password="${CN_Password:-$(_readaccountconf_mutable CN_Password)}" + if [ -z "$CN_User" ] || [ -z "$CN_Password" ]; then + CN_User="" + CN_Password="" + _err "You must export variables: CN_User and CN_Password" + return 1 + fi + + #save the config variables to the account conf file. + _saveaccountconf_mutable CN_User "$CN_User" + _saveaccountconf_mutable CN_Password "$CN_Password" + + _info "Getting an AUTH-Token" + curData="{\"login\":\"${CN_User}\",\"password\":\"${CN_Password}\"}" + curResult="$(_post "${curData}" "${CN_API}/auth/token")" + _debug "Calling _CN_login: '${curData}' '${CN_API}/auth/token'" + + if _contains "${curResult}" '"token":"'; then + authToken=$(echo "${curResult}" | cut -d ":" -f2 | cut -d "," -f1 | sed 's/^.\(.*\).$/\1/') + export _H1="Authorization: Bearer $authToken" + _info "Successfully acquired AUTH-Token" + _debug "AUTH-Token: '${authToken}'" + _debug "_H1 '${_H1}'" + else + _err "Couldn't acquire an AUTH-Token" + return 1 + fi +} + +# Commit changes +_cn_commit() { + _info "Commiting changes" + _post "" "${CN_API}/dnszones/$h/records/commit" +} + +_cn_get_root() { + domain=$1 + i=2 + p=1 + while true; do + + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + _debug _H1 "${_H1}" + + if [ -z "$h" ]; then + #not valid + return 1 + fi + + _cn_zonelist="$(_get ${CN_API}/dnszones/)" + _debug _cn_zonelist "${_cn_zonelist}" + + if [ "$?" != "0" ]; then + _err "something went wrong while getting the zone list" + return 1 + fi + + if _contains "$_cn_zonelist" "\"name\":\"$h\"" >/dev/null; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + else + _debug "Zonelist does not contain domain - iterating " + fi + p=$i + i=$(_math "$i" + 1) + + done + _err "Zonelist does not contain domain - exiting" + return 1 +} diff --git a/letsencrypt/dnsapi/dns_conoha.sh b/letsencrypt/dnsapi/dns_conoha.sh new file mode 100755 index 00000000..e02bff31 --- /dev/null +++ b/letsencrypt/dnsapi/dns_conoha.sh @@ -0,0 +1,253 @@ +#!/bin/bash + +CONOHA_DNS_EP_PREFIX_REGEXP="https://dns-service\." + +######## Public functions ##################### + +#Usage: dns_conoha_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_conoha_add() { + fulldomain=$1 + txtvalue=$2 + _info "Using conoha" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + _debug "Check uesrname and password" + CONOHA_Username="${CONOHA_Username:-$(_readaccountconf_mutable CONOHA_Username)}" + CONOHA_Password="${CONOHA_Password:-$(_readaccountconf_mutable CONOHA_Password)}" + CONOHA_TenantId="${CONOHA_TenantId:-$(_readaccountconf_mutable CONOHA_TenantId)}" + CONOHA_IdentityServiceApi="${CONOHA_IdentityServiceApi:-$(_readaccountconf_mutable CONOHA_IdentityServiceApi)}" + if [ -z "$CONOHA_Username" ] || [ -z "$CONOHA_Password" ] || [ -z "$CONOHA_TenantId" ] || [ -z "$CONOHA_IdentityServiceApi" ]; then + CONOHA_Username="" + CONOHA_Password="" + CONOHA_TenantId="" + CONOHA_IdentityServiceApi="" + _err "You didn't specify a conoha api username and password yet." + _err "Please create the user and try again." + return 1 + fi + + _saveaccountconf_mutable CONOHA_Username "$CONOHA_Username" + _saveaccountconf_mutable CONOHA_Password "$CONOHA_Password" + _saveaccountconf_mutable CONOHA_TenantId "$CONOHA_TenantId" + _saveaccountconf_mutable CONOHA_IdentityServiceApi "$CONOHA_IdentityServiceApi" + + if token="$(_conoha_get_accesstoken "$CONOHA_IdentityServiceApi/tokens" "$CONOHA_Username" "$CONOHA_Password" "$CONOHA_TenantId")"; then + accesstoken="$(printf "%s" "$token" | sed -n 1p)" + CONOHA_Api="$(printf "%s" "$token" | sed -n 2p)" + else + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain" "$CONOHA_Api" "$accesstoken"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _info "Adding record" + body="{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"data\":\"$txtvalue\",\"ttl\":60}" + if _conoha_rest POST "$CONOHA_Api/v1/domains/$_domain_id/records" "$body" "$accesstoken"; then + if _contains "$response" '"data":"'"$txtvalue"'"'; then + _info "Added, OK" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + + _err "Add txt record error." + return 1 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_conoha_rm() { + fulldomain=$1 + txtvalue=$2 + _info "Using conoha" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + _debug "Check uesrname and password" + CONOHA_Username="${CONOHA_Username:-$(_readaccountconf_mutable CONOHA_Username)}" + CONOHA_Password="${CONOHA_Password:-$(_readaccountconf_mutable CONOHA_Password)}" + CONOHA_TenantId="${CONOHA_TenantId:-$(_readaccountconf_mutable CONOHA_TenantId)}" + CONOHA_IdentityServiceApi="${CONOHA_IdentityServiceApi:-$(_readaccountconf_mutable CONOHA_IdentityServiceApi)}" + if [ -z "$CONOHA_Username" ] || [ -z "$CONOHA_Password" ] || [ -z "$CONOHA_TenantId" ] || [ -z "$CONOHA_IdentityServiceApi" ]; then + CONOHA_Username="" + CONOHA_Password="" + CONOHA_TenantId="" + CONOHA_IdentityServiceApi="" + _err "You didn't specify a conoha api username and password yet." + _err "Please create the user and try again." + return 1 + fi + + _saveaccountconf_mutable CONOHA_Username "$CONOHA_Username" + _saveaccountconf_mutable CONOHA_Password "$CONOHA_Password" + _saveaccountconf_mutable CONOHA_TenantId "$CONOHA_TenantId" + _saveaccountconf_mutable CONOHA_IdentityServiceApi "$CONOHA_IdentityServiceApi" + + if token="$(_conoha_get_accesstoken "$CONOHA_IdentityServiceApi/tokens" "$CONOHA_Username" "$CONOHA_Password" "$CONOHA_TenantId")"; then + accesstoken="$(printf "%s" "$token" | sed -n 1p)" + CONOHA_Api="$(printf "%s" "$token" | sed -n 2p)" + else + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain" "$CONOHA_Api" "$accesstoken"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + if ! _conoha_rest GET "$CONOHA_Api/v1/domains/$_domain_id/records" "" "$accesstoken"; then + _err "Error" + return 1 + fi + + record_id=$(printf "%s" "$response" | _egrep_o '{[^}]*}' | + grep '"type":"TXT"' | grep "\"data\":\"$txtvalue\"" | _egrep_o "\"id\":\"[^\"]*\"" | + _head_n 1 | cut -d : -f 2 | tr -d \") + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + _debug record_id "$record_id" + + _info "Removing the txt record" + if ! _conoha_rest DELETE "$CONOHA_Api/v1/domains/$_domain_id/records/$record_id" "" "$accesstoken"; then + _err "Delete record error." + return 1 + fi + + return 0 +} + +#################### Private functions below ################################## + +_conoha_rest() { + m="$1" + ep="$2" + data="$3" + accesstoken="$4" + + export _H1="Accept: application/json" + export _H2="Content-Type: application/json" + if [ -n "$accesstoken" ]; then + export _H3="X-Auth-Token: $accesstoken" + fi + + _debug "$ep" + if [ "$m" != "GET" ]; then + _secure_debug2 data "$data" + response="$(_post "$data" "$ep" "" "$m")" + else + response="$(_get "$ep")" + fi + _ret="$?" + _secure_debug2 response "$response" + if [ "$_ret" != "0" ]; then + _err "error $ep" + return 1 + fi + + response="$(printf "%s" "$response" | _normalizeJson)" + return 0 +} + +_conoha_get_accesstoken() { + ep="$1" + username="$2" + password="$3" + tenantId="$4" + + accesstoken="$(_readaccountconf_mutable conoha_accesstoken)" + expires="$(_readaccountconf_mutable conoha_tokenvalidto)" + CONOHA_Api="$(_readaccountconf_mutable conoha_dns_ep)" + + # can we reuse the access token? + if [ -n "$accesstoken" ] && [ -n "$expires" ] && [ -n "$CONOHA_Api" ]; then + utc_date="$(_utc_date | sed "s/ /T/")" + if expr "$utc_date" "<" "$expires" >/dev/null; then + # access token is still valid - reuse it + _debug "reusing access token" + printf "%s\n%s\n" "$accesstoken" "$CONOHA_Api" + return 0 + else + _debug "access token expired" + fi + fi + _debug "getting new access token" + + body="$(printf '{"auth":{"passwordCredentials":{"username":"%s","password":"%s"},"tenantId":"%s"}}' "$username" "$password" "$tenantId")" + if ! _conoha_rest POST "$ep" "$body" ""; then + _err error "$response" + return 1 + fi + accesstoken=$(printf "%s" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") + expires=$(printf "%s" "$response" | _egrep_o "\"expires\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2-4 | tr -d \" | tr -d Z) #expect UTC + if [ -z "$accesstoken" ] || [ -z "$expires" ]; then + _err "no acccess token received. Check your Conoha settings see $WIKI" + return 1 + fi + _saveaccountconf_mutable conoha_accesstoken "$accesstoken" + _saveaccountconf_mutable conoha_tokenvalidto "$expires" + + CONOHA_Api=$(printf "%s" "$response" | _egrep_o 'publicURL":"'"$CONOHA_DNS_EP_PREFIX_REGEXP"'[^"]*"' | _head_n 1 | cut -d : -f 2-3 | tr -d \") + if [ -z "$CONOHA_Api" ]; then + _err "failed to get conoha dns endpoint url" + return 1 + fi + _saveaccountconf_mutable conoha_dns_ep "$CONOHA_Api" + + printf "%s\n%s\n" "$accesstoken" "$CONOHA_Api" + return 0 +} + +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain="$1" + ep="$2" + accesstoken="$3" + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100). + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _conoha_rest GET "$ep/v1/domains?name=$h" "" "$accesstoken"; then + return 1 + fi + + if _contains "$response" "\"name\":\"$h\"" >/dev/null; then + _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \") + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} diff --git a/letsencrypt/dnsapi/dns_constellix.sh b/letsencrypt/dnsapi/dns_constellix.sh new file mode 100644 index 00000000..f46f6ee0 --- /dev/null +++ b/letsencrypt/dnsapi/dns_constellix.sh @@ -0,0 +1,141 @@ +#!/bin/bash + +# Author: Wout Decre + +CONSTELLIX_Api="https://api.dns.constellix.com/v1" +#CONSTELLIX_Key="XXX" +#CONSTELLIX_Secret="XXX" + +######## Public functions ##################### + +# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to add txt record +dns_constellix_add() { + fulldomain=$1 + txtvalue=$2 + + CONSTELLIX_Key="${CONSTELLIX_Key:-$(_readaccountconf_mutable CONSTELLIX_Key)}" + CONSTELLIX_Secret="${CONSTELLIX_Secret:-$(_readaccountconf_mutable CONSTELLIX_Secret)}" + + if [ -z "$CONSTELLIX_Key" ] || [ -z "$CONSTELLIX_Secret" ]; then + _err "You did not specify the Contellix API key and secret yet." + return 1 + fi + + _saveaccountconf_mutable CONSTELLIX_Key "$CONSTELLIX_Key" + _saveaccountconf_mutable CONSTELLIX_Secret "$CONSTELLIX_Secret" + + if ! _get_root "$fulldomain"; then + _err "Invalid domain" + return 1 + fi + + _info "Adding TXT record" + if _constellix_rest POST "domains/${_domain_id}/records" "[{\"type\":\"txt\",\"add\":true,\"set\":{\"name\":\"${_sub_domain}\",\"ttl\":120,\"roundRobin\":[{\"value\":\"${txtvalue}\"}]}}]"; then + if printf -- "%s" "$response" | grep "{\"success\":\"1 record(s) added, 0 record(s) updated, 0 record(s) deleted\"}" >/dev/null; then + _info "Added" + return 0 + else + _err "Error adding TXT record" + return 1 + fi + fi +} + +# Usage: fulldomain txtvalue +# Used to remove the txt record after validation +dns_constellix_rm() { + fulldomain=$1 + txtvalue=$2 + + CONSTELLIX_Key="${CONSTELLIX_Key:-$(_readaccountconf_mutable CONSTELLIX_Key)}" + CONSTELLIX_Secret="${CONSTELLIX_Secret:-$(_readaccountconf_mutable CONSTELLIX_Secret)}" + + if [ -z "$CONSTELLIX_Key" ] || [ -z "$CONSTELLIX_Secret" ]; then + _err "You did not specify the Contellix API key and secret yet." + return 1 + fi + + if ! _get_root "$fulldomain"; then + _err "Invalid domain" + return 1 + fi + + _info "Removing TXT record" + if _constellix_rest POST "domains/${_domain_id}/records" "[{\"type\":\"txt\",\"delete\":true,\"filter\":{\"field\":\"name\",\"op\":\"eq\",\"value\":\"${_sub_domain}\"}}]"; then + if printf -- "%s" "$response" | grep "{\"success\":\"0 record(s) added, 0 record(s) updated, 1 record(s) deleted\"}" >/dev/null; then + _info "Removed" + return 0 + else + _err "Error removing TXT record" + return 1 + fi + fi +} + +#################### Private functions below ################################## + +_get_root() { + domain=$1 + i=2 + p=1 + _debug "Detecting root zone" + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + return 1 + fi + + if ! _constellix_rest GET "domains/search?exact=$h"; then + return 1 + fi + + if _contains "$response" "\"name\":\"$h\""; then + _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[0-9]+" | cut -d ':' -f 2) + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d '.' -f 1-$p) + _domain="$h" + + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_constellix_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + rdate=$(date +"%s")"000" + hmac=$(printf "%s" "$rdate" | _hmac sha1 "$(printf "%s" "$CONSTELLIX_Secret" | _hex_dump | tr -d ' ')" | _base64) + + export _H1="x-cnsdns-apiKey: $CONSTELLIX_Key" + export _H2="x-cnsdns-requestDate: $rdate" + export _H3="x-cnsdns-hmac: $hmac" + export _H4="Accept: application/json" + export _H5="Content-Type: application/json" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$CONSTELLIX_Api/$ep" "" "$m")" + else + response="$(_get "$CONSTELLIX_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "Error $ep" + return 1 + fi + + _debug response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_cx.sh b/letsencrypt/dnsapi/dns_cx.sh new file mode 100755 index 00000000..67f9155d --- /dev/null +++ b/letsencrypt/dnsapi/dns_cx.sh @@ -0,0 +1,185 @@ +#!/bin/bash + +# CloudXNS Domain api +# +#CX_Key="1234" +# +#CX_Secret="sADDsdasdgdsf" + +CX_Api="https://www.cloudxns.net/api2" + +#REST_API +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_cx_add() { + fulldomain=$1 + txtvalue=$2 + + CX_Key="${CX_Key:-$(_readaccountconf_mutable CX_Key)}" + CX_Secret="${CX_Secret:-$(_readaccountconf_mutable CX_Secret)}" + if [ -z "$CX_Key" ] || [ -z "$CX_Secret" ]; then + CX_Key="" + CX_Secret="" + _err "You don't specify cloudxns.net api key or secret yet." + _err "Please create you key and try again." + return 1 + fi + + REST_API="$CX_Api" + + #save the api key and email to the account conf file. + _saveaccountconf_mutable CX_Key "$CX_Key" + _saveaccountconf_mutable CX_Secret "$CX_Secret" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + add_record "$_domain" "$_sub_domain" "$txtvalue" +} + +#fulldomain txtvalue +dns_cx_rm() { + fulldomain=$1 + txtvalue=$2 + CX_Key="${CX_Key:-$(_readaccountconf_mutable CX_Key)}" + CX_Secret="${CX_Secret:-$(_readaccountconf_mutable CX_Secret)}" + REST_API="$CX_Api" + if _get_root "$fulldomain"; then + record_id="" + existing_records "$_domain" "$_sub_domain" "$txtvalue" + if [ "$record_id" ]; then + _rest DELETE "record/$record_id/$_domain_id" "{}" + _info "Deleted record ${fulldomain}" + fi + fi +} + +#usage: root sub +#return if the sub record already exists. +#echos the existing records count. +# '0' means doesn't exist +existing_records() { + _debug "Getting txt records" + root=$1 + sub=$2 + if ! _rest GET "record/$_domain_id?:domain_id?host_id=0&offset=0&row_num=100"; then + return 1 + fi + + seg=$(printf "%s\n" "$response" | _egrep_o '"record_id":[^{]*host":"'"$_sub_domain"'"[^}]*\}') + _debug seg "$seg" + if [ -z "$seg" ]; then + return 0 + fi + + if printf "%s" "$response" | grep '"type":"TXT"' >/dev/null; then + record_id=$(printf "%s\n" "$seg" | _egrep_o '"record_id":"[^"]*"' | cut -d : -f 2 | tr -d \" | _head_n 1) + _debug record_id "$record_id" + return 0 + fi + +} + +#add the txt record. +#usage: root sub txtvalue +add_record() { + root=$1 + sub=$2 + txtvalue=$3 + fulldomain="$sub.$root" + + _info "Adding record" + + if ! _rest POST "record" "{\"domain_id\": $_domain_id, \"host\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"type\":\"TXT\",\"ttl\":600, \"line_id\":1}"; then + return 1 + fi + + return 0 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + + if ! _rest GET "domain"; then + return 1 + fi + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "$h."; then + seg=$(printf "%s\n" "$response" | _egrep_o '"id":[^{]*"'"$h"'."[^}]*}') + _debug seg "$seg" + _domain_id=$(printf "%s\n" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") + _debug _domain_id "$_domain_id" + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _debug _sub_domain "$_sub_domain" + _domain="$h" + _debug _domain "$_domain" + return 0 + fi + return 1 + fi + p="$i" + i=$(_math "$i" + 1) + done + return 1 +} + +#Usage: method URI data +_rest() { + m=$1 + ep="$2" + _debug ep "$ep" + url="$REST_API/$ep" + _debug url "$url" + + cdate=$(date -u "+%Y-%m-%d %H:%M:%S UTC") + _debug cdate "$cdate" + + data="$3" + _debug data "$data" + + sec="$CX_Key$url$data$cdate$CX_Secret" + _debug sec "$sec" + hmac=$(printf "%s" "$sec" | _digest md5 hex) + _debug hmac "$hmac" + + export _H1="API-KEY: $CX_Key" + export _H2="API-REQUEST-DATE: $cdate" + export _H3="API-HMAC: $hmac" + export _H4="Content-Type: application/json" + + if [ "$data" ]; then + response="$(_post "$data" "$url" "" "$m")" + else + response="$(_get "$url")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + + _contains "$response" '"code":1' + +} diff --git a/letsencrypt/dnsapi/dns_cyon.sh b/letsencrypt/dnsapi/dns_cyon.sh new file mode 100644 index 00000000..28e9f332 --- /dev/null +++ b/letsencrypt/dnsapi/dns_cyon.sh @@ -0,0 +1,328 @@ +#!/bin/bash + +######## +# Custom cyon.ch DNS API for use with [acme.sh](https://github.com/acmesh-official/acme.sh) +# +# Usage: acme.sh --issue --dns dns_cyon -d www.domain.com +# +# Dependencies: +# ------------- +# - oathtool (When using 2 Factor Authentication) +# +# Issues: +# ------- +# Any issues / questions / suggestions can be posted here: +# https://github.com/noplanman/cyon-api/issues +# +# Author: Armando Lüscher +######## + +dns_cyon_add() { + _cyon_load_credentials && + _cyon_load_parameters "$@" && + _cyon_print_header "add" && + _cyon_login && + _cyon_change_domain_env && + _cyon_add_txt && + _cyon_logout +} + +dns_cyon_rm() { + _cyon_load_credentials && + _cyon_load_parameters "$@" && + _cyon_print_header "delete" && + _cyon_login && + _cyon_change_domain_env && + _cyon_delete_txt && + _cyon_logout +} + +######################### +### PRIVATE FUNCTIONS ### +######################### + +_cyon_load_credentials() { + # Convert loaded password to/from base64 as needed. + if [ "${CY_Password_B64}" ]; then + CY_Password="$(printf "%s" "${CY_Password_B64}" | _dbase64 "multiline")" + elif [ "${CY_Password}" ]; then + CY_Password_B64="$(printf "%s" "${CY_Password}" | _base64)" + fi + + if [ -z "${CY_Username}" ] || [ -z "${CY_Password}" ]; then + # Dummy entries to satisfy script checker. + CY_Username="" + CY_Password="" + CY_OTP_Secret="" + + _err "" + _err "You haven't set your cyon.ch login credentials yet." + _err "Please set the required cyon environment variables." + _err "" + return 1 + fi + + # Save the login credentials to the account.conf file. + _debug "Save credentials to account.conf" + _saveaccountconf CY_Username "${CY_Username}" + _saveaccountconf CY_Password_B64 "$CY_Password_B64" + if [ -n "${CY_OTP_Secret}" ]; then + _saveaccountconf CY_OTP_Secret "$CY_OTP_Secret" + else + _clearaccountconf CY_OTP_Secret + fi +} + +_cyon_is_idn() { + _idn_temp="$(printf "%s" "${1}" | tr -d "0-9a-zA-Z.,-_")" + _idn_temp2="$(printf "%s" "${1}" | grep -o "xn--")" + [ "$_idn_temp" ] || [ "$_idn_temp2" ] +} + +_cyon_load_parameters() { + # Read the required parameters to add the TXT entry. + # shellcheck disable=SC2018,SC2019 + fulldomain="$(printf "%s" "${1}" | tr "A-Z" "a-z")" + fulldomain_idn="${fulldomain}" + + # Special case for IDNs, as cyon needs a domain environment change, + # which uses the "pretty" instead of the punycode version. + if _cyon_is_idn "${fulldomain}"; then + if ! _exists idn; then + _err "Please install idn to process IDN names." + _err "" + return 1 + fi + + fulldomain="$(idn -u "${fulldomain}")" + fulldomain_idn="$(idn -a "${fulldomain}")" + fi + + _debug fulldomain "${fulldomain}" + _debug fulldomain_idn "${fulldomain_idn}" + + txtvalue="${2}" + _debug txtvalue "${txtvalue}" + + # This header is required for curl calls. + _H1="X-Requested-With: XMLHttpRequest" + export _H1 +} + +_cyon_print_header() { + if [ "${1}" = "add" ]; then + _info "" + _info "+---------------------------------------------+" + _info "| Adding DNS TXT entry to your cyon.ch domain |" + _info "+---------------------------------------------+" + _info "" + _info " * Full Domain: ${fulldomain}" + _info " * TXT Value: ${txtvalue}" + _info "" + elif [ "${1}" = "delete" ]; then + _info "" + _info "+-------------------------------------------------+" + _info "| Deleting DNS TXT entry from your cyon.ch domain |" + _info "+-------------------------------------------------+" + _info "" + _info " * Full Domain: ${fulldomain}" + _info "" + fi +} + +_cyon_get_cookie_header() { + printf "Cookie: %s" "$(grep "cyon=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'cyon=[^;]*;' | tr -d ';')" +} + +_cyon_login() { + _info " - Logging in..." + + username_encoded="$(printf "%s" "${CY_Username}" | _url_encode)" + password_encoded="$(printf "%s" "${CY_Password}" | _url_encode)" + + login_url="https://my.cyon.ch/auth/index/dologin-async" + login_data="$(printf "%s" "username=${username_encoded}&password=${password_encoded}&pathname=%2F")" + + login_response="$(_post "$login_data" "$login_url")" + _debug login_response "${login_response}" + + # Bail if login fails. + if [ "$(printf "%s" "${login_response}" | _cyon_get_response_success)" != "success" ]; then + _err " $(printf "%s" "${login_response}" | _cyon_get_response_message)" + _err "" + return 1 + fi + + _info " success" + + # NECESSARY!! Load the main page after login, to get the new cookie. + _H2="$(_cyon_get_cookie_header)" + export _H2 + + _get "https://my.cyon.ch/" >/dev/null + + # todo: instead of just checking if the env variable is defined, check if we actually need to do a 2FA auth request. + + # 2FA authentication with OTP? + if [ -n "${CY_OTP_Secret}" ]; then + _info " - Authorising with OTP code..." + + if ! _exists oathtool; then + _err "Please install oathtool to use 2 Factor Authentication." + _err "" + return 1 + fi + + # Get OTP code with the defined secret. + otp_code="$(oathtool --base32 --totp "${CY_OTP_Secret}" 2>/dev/null)" + + login_otp_url="https://my.cyon.ch/auth/multi-factor/domultifactorauth-async" + login_otp_data="totpcode=${otp_code}&pathname=%2F&rememberme=0" + + login_otp_response="$(_post "$login_otp_data" "$login_otp_url")" + _debug login_otp_response "${login_otp_response}" + + # Bail if OTP authentication fails. + if [ "$(printf "%s" "${login_otp_response}" | _cyon_get_response_success)" != "success" ]; then + _err " $(printf "%s" "${login_otp_response}" | _cyon_get_response_message)" + _err "" + return 1 + fi + + _info " success" + fi + + _info "" +} + +_cyon_logout() { + _info " - Logging out..." + + _get "https://my.cyon.ch/auth/index/dologout" >/dev/null + + _info " success" + _info "" +} + +_cyon_change_domain_env() { + _info " - Changing domain environment..." + + # Get the "example.com" part of the full domain name. + domain_env="$(printf "%s" "${fulldomain}" | sed -E -e 's/.*\.(.*\..*)$/\1/')" + _debug "Changing domain environment to ${domain_env}" + + gloo_item_key="$(_get "https://my.cyon.ch/domain/" | tr '\n' ' ' | sed -E -e "s/.*data-domain=\"${domain_env}\"[^<]*data-itemkey=\"([^\"]*).*/\1/")" + _debug gloo_item_key "${gloo_item_key}" + + domain_env_url="https://my.cyon.ch/user/environment/setdomain/d/${domain_env}/gik/${gloo_item_key}" + + domain_env_response="$(_get "${domain_env_url}")" + _debug domain_env_response "${domain_env_response}" + + if ! _cyon_check_if_2fa_missed "${domain_env_response}"; then return 1; fi + + domain_env_success="$(printf "%s" "${domain_env_response}" | _egrep_o '"authenticated":\w*' | cut -d : -f 2)" + + # Bail if domain environment change fails. + if [ "${domain_env_success}" != "true" ]; then + _err " $(printf "%s" "${domain_env_response}" | _cyon_get_response_message)" + _err "" + return 1 + fi + + _info " success" + _info "" +} + +_cyon_add_txt() { + _info " - Adding DNS TXT entry..." + + add_txt_url="https://my.cyon.ch/domain/dnseditor/add-record-async" + add_txt_data="zone=${fulldomain_idn}.&ttl=900&type=TXT&value=${txtvalue}" + + add_txt_response="$(_post "$add_txt_data" "$add_txt_url")" + _debug add_txt_response "${add_txt_response}" + + if ! _cyon_check_if_2fa_missed "${add_txt_response}"; then return 1; fi + + add_txt_message="$(printf "%s" "${add_txt_response}" | _cyon_get_response_message)" + add_txt_status="$(printf "%s" "${add_txt_response}" | _cyon_get_response_status)" + + # Bail if adding TXT entry fails. + if [ "${add_txt_status}" != "true" ]; then + _err " ${add_txt_message}" + _err "" + return 1 + fi + + _info " success (TXT|${fulldomain_idn}.|${txtvalue})" + _info "" +} + +_cyon_delete_txt() { + _info " - Deleting DNS TXT entry..." + + list_txt_url="https://my.cyon.ch/domain/dnseditor/list-async" + + list_txt_response="$(_get "${list_txt_url}" | sed -e 's/data-hash/\\ndata-hash/g')" + _debug list_txt_response "${list_txt_response}" + + if ! _cyon_check_if_2fa_missed "${list_txt_response}"; then return 1; fi + + # Find and delete all acme challenge entries for the $fulldomain. + _dns_entries="$(printf "%b\n" "${list_txt_response}" | sed -n 's/data-hash=\\"\([^"]*\)\\" data-identifier=\\"\([^"]*\)\\".*/\1 \2/p')" + + printf "%s" "${_dns_entries}" | while read -r _hash _identifier; do + dns_type="$(printf "%s" "$_identifier" | cut -d'|' -f1)" + dns_domain="$(printf "%s" "$_identifier" | cut -d'|' -f2)" + + if [ "${dns_type}" != "TXT" ] || [ "${dns_domain}" != "${fulldomain_idn}." ]; then + continue + fi + + hash_encoded="$(printf "%s" "${_hash}" | _url_encode)" + identifier_encoded="$(printf "%s" "${_identifier}" | _url_encode)" + + delete_txt_url="https://my.cyon.ch/domain/dnseditor/delete-record-async" + delete_txt_data="$(printf "%s" "hash=${hash_encoded}&identifier=${identifier_encoded}")" + + delete_txt_response="$(_post "$delete_txt_data" "$delete_txt_url")" + _debug delete_txt_response "${delete_txt_response}" + + if ! _cyon_check_if_2fa_missed "${delete_txt_response}"; then return 1; fi + + delete_txt_message="$(printf "%s" "${delete_txt_response}" | _cyon_get_response_message)" + delete_txt_status="$(printf "%s" "${delete_txt_response}" | _cyon_get_response_status)" + + # Skip if deleting TXT entry fails. + if [ "${delete_txt_status}" != "true" ]; then + _err " ${delete_txt_message} (${_identifier})" + else + _info " success (${_identifier})" + fi + done + + _info " done" + _info "" +} + +_cyon_get_response_message() { + _egrep_o '"message":"[^"]*"' | cut -d : -f 2 | tr -d '"' +} + +_cyon_get_response_status() { + _egrep_o '"status":\w*' | cut -d : -f 2 +} + +_cyon_get_response_success() { + _egrep_o '"onSuccess":"[^"]*"' | cut -d : -f 2 | tr -d '"' +} + +_cyon_check_if_2fa_missed() { + # Did we miss the 2FA? + if test "${1#*multi_factor_form}" != "${1}"; then + _err " Missed OTP authentication!" + _err "" + return 1 + fi +} diff --git a/letsencrypt/dnsapi/dns_da.sh b/letsencrypt/dnsapi/dns_da.sh new file mode 100755 index 00000000..e4faa10b --- /dev/null +++ b/letsencrypt/dnsapi/dns_da.sh @@ -0,0 +1,184 @@ +#!/bin/bash +# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*- +# vim: et ts=2 sw=2 +# +# DirectAdmin 1.41.0 API +# The DirectAdmin interface has it's own Let's encrypt functionality, but this +# script can be used to generate certificates for names which are not hosted on +# DirectAdmin +# +# User must provide login data and URL to DirectAdmin incl. port. +# You can create login key, by using the Login Keys function +# ( https://da.example.com:8443/CMD_LOGIN_KEYS ), which only has access to +# - CMD_API_DNS_CONTROL +# - CMD_API_SHOW_DOMAINS +# +# See also https://www.directadmin.com/api.php and +# https://www.directadmin.com/features.php?id=1298 +# +# Report bugs to https://github.com/TigerP/acme.sh/issues +# +# Values to export: +# export DA_Api="https://remoteUser:remotePassword@da.example.com:8443" +# export DA_Api_Insecure=1 +# +# Set DA_Api_Insecure to 1 for insecure and 0 for secure -> difference is +# whether ssl cert is checked for validity (0) or whether it is just accepted +# (1) +# +######## Public functions ##################### + +# Usage: dns_myapi_add _acme-challenge.www.example.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to add txt record +dns_da_add() { + fulldomain="${1}" + txtvalue="${2}" + _debug "Calling: dns_da_add() '${fulldomain}' '${txtvalue}'" + _DA_credentials && _DA_getDomainInfo && _DA_addTxt +} + +# Usage: dns_da_rm _acme-challenge.www.example.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to remove the txt record after validation +dns_da_rm() { + fulldomain="${1}" + txtvalue="${2}" + _debug "Calling: dns_da_rm() '${fulldomain}' '${txtvalue}'" + _DA_credentials && _DA_getDomainInfo && _DA_rmTxt +} + +#################### Private functions below ################################## +# Usage: _DA_credentials +# It will check if the needed settings are available +_DA_credentials() { + DA_Api="${DA_Api:-$(_readaccountconf_mutable DA_Api)}" + DA_Api_Insecure="${DA_Api_Insecure:-$(_readaccountconf_mutable DA_Api_Insecure)}" + if [ -z "${DA_Api}" ] || [ -z "${DA_Api_Insecure}" ]; then + DA_Api="" + DA_Api_Insecure="" + _err "You haven't specified the DirectAdmin Login data, URL and whether you want check the DirectAdmin SSL cert. Please try again." + return 1 + else + _saveaccountconf_mutable DA_Api "${DA_Api}" + _saveaccountconf_mutable DA_Api_Insecure "${DA_Api_Insecure}" + # Set whether curl should use secure or insecure mode + export HTTPS_INSECURE="${DA_Api_Insecure}" + fi +} + +# Usage: _get_root _acme-challenge.www.example.com +# Split the full domain to a domain and subdomain +#returns +# _sub_domain=_acme-challenge.www +# _domain=example.com +_get_root() { + domain=$1 + i=2 + p=1 + # Get a list of all the domains + # response will contain "list[]=example.com&list[]=example.org" + _da_api CMD_API_SHOW_DOMAINS "" "${domain}" + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + # not valid + _debug "The given domain $h is not valid" + return 1 + fi + if _contains "$response" "$h" >/dev/null; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + _debug "Stop on 100" + return 1 +} + +# Usage: _da_api CMD_API_* data example.com +# Use the DirectAdmin API and check the result +# returns +# response="error=0&text=Result text&details=" +_da_api() { + cmd=$1 + data=$2 + domain=$3 + _debug "$domain; $data" + response="$(_post "$data" "$DA_Api/$cmd" "" "POST")" + + if [ "$?" != "0" ]; then + _err "error $cmd" + return 1 + fi + _debug response "$response" + + case "${cmd}" in + CMD_API_DNS_CONTROL) + # Parse the result in general + # error=0&text=Records Deleted&details= + # error=1&text=Cannot View Dns Record&details=No domain provided + err_field="$(_getfield "$response" 1 '&')" + txt_field="$(_getfield "$response" 2 '&')" + details_field="$(_getfield "$response" 3 '&')" + error="$(_getfield "$err_field" 2 '=')" + text="$(_getfield "$txt_field" 2 '=')" + details="$(_getfield "$details_field" 2 '=')" + _debug "error: ${error}, text: ${text}, details: ${details}" + if [ "$error" != "0" ]; then + _err "error $response" + return 1 + fi + ;; + CMD_API_SHOW_DOMAINS) ;; + esac + return 0 +} + +# Usage: _DA_getDomainInfo +# Get the root zone if possible +_DA_getDomainInfo() { + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + else + _debug "The root domain: $_domain" + _debug "The sub domain: $_sub_domain" + fi + return 0 +} + +# Usage: _DA_addTxt +# Use the API to add a record +_DA_addTxt() { + curData="domain=${_domain}&action=add&type=TXT&name=${_sub_domain}&value=\"${txtvalue}\"" + _debug "Calling _DA_addTxt: '${curData}' '${DA_Api}/CMD_API_DNS_CONTROL'" + _da_api CMD_API_DNS_CONTROL "${curData}" "${_domain}" + _debug "Result of _DA_addTxt: '$response'" + if _contains "${response}" 'error=0'; then + _debug "Add TXT succeeded" + return 0 + fi + _debug "Add TXT failed" + return 1 +} + +# Usage: _DA_rmTxt +# Use the API to remove a record +_DA_rmTxt() { + curData="domain=${_domain}&action=select&txtrecs0=name=${_sub_domain}&value=\"${txtvalue}\"" + _debug "Calling _DA_rmTxt: '${curData}' '${DA_Api}/CMD_API_DNS_CONTROL'" + if _da_api CMD_API_DNS_CONTROL "${curData}" "${_domain}"; then + _debug "Result of _DA_rmTxt: '$response'" + else + _err "Result of _DA_rmTxt: '$response'" + fi + if _contains "${response}" 'error=0'; then + _debug "RM TXT succeeded" + return 0 + fi + _debug "RM TXT failed" + return 1 +} diff --git a/letsencrypt/dnsapi/dns_ddnss.sh b/letsencrypt/dnsapi/dns_ddnss.sh new file mode 100644 index 00000000..c52d6191 --- /dev/null +++ b/letsencrypt/dnsapi/dns_ddnss.sh @@ -0,0 +1,130 @@ +#!/bin/bash + +#Created by RaidenII, to use DuckDNS's API to add/remove text records +#modified by helbgd @ 03/13/2018 to support ddnss.de +#modified by mod242 @ 04/24/2018 to support different ddnss domains +#Please note: the Wildcard Feature must be turned on for the Host record +#and the checkbox for TXT needs to be enabled + +# Pass credentials before "acme.sh --issue --dns dns_ddnss ..." +# -- +# export DDNSS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" +# -- +# + +DDNSS_DNS_API="https://ip4.ddnss.de/upd.php" + +######## Public functions ##################### + +#Usage: dns_ddnss_add _acme-challenge.domain.ddnss.de "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_ddnss_add() { + fulldomain=$1 + txtvalue=$2 + + DDNSS_Token="${DDNSS_Token:-$(_readaccountconf_mutable DDNSS_Token)}" + if [ -z "$DDNSS_Token" ]; then + _err "You must export variable: DDNSS_Token" + _err "The token for your DDNSS account is necessary." + _err "You can look it up in your DDNSS account." + return 1 + fi + + # Now save the credentials. + _saveaccountconf_mutable DDNSS_Token "$DDNSS_Token" + + # Unfortunately, DDNSS does not seems to support lookup domain through API + # So I assume your credentials (which are your domain and token) are correct + # If something goes wrong, we will get a KO response from DDNSS + + if ! _ddnss_get_domain; then + return 1 + fi + + # Now add the TXT record to DDNSS DNS + _info "Trying to add TXT record" + if _ddnss_rest GET "key=$DDNSS_Token&host=$_ddnss_domain&txtm=1&txt=$txtvalue"; then + if [ "$response" = "Updated 1 hostname." ]; then + _info "TXT record has been successfully added to your DDNSS domain." + _info "Note that all subdomains under this domain uses the same TXT record." + return 0 + else + _err "Errors happened during adding the TXT record, response=$response" + return 1 + fi + else + _err "Errors happened during adding the TXT record." + return 1 + fi +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_ddnss_rm() { + fulldomain=$1 + txtvalue=$2 + + DDNSS_Token="${DDNSS_Token:-$(_readaccountconf_mutable DDNSS_Token)}" + if [ -z "$DDNSS_Token" ]; then + _err "You must export variable: DDNSS_Token" + _err "The token for your DDNSS account is necessary." + _err "You can look it up in your DDNSS account." + return 1 + fi + + if ! _ddnss_get_domain; then + return 1 + fi + + # Now remove the TXT record from DDNS DNS + _info "Trying to remove TXT record" + if _ddnss_rest GET "key=$DDNSS_Token&host=$_ddnss_domain&txtm=1&txt=."; then + if [ "$response" = "Updated 1 hostname." ]; then + _info "TXT record has been successfully removed from your DDNSS domain." + return 0 + else + _err "Errors happened during removing the TXT record, response=$response" + return 1 + fi + else + _err "Errors happened during removing the TXT record." + return 1 + fi +} + +#################### Private functions below ################################## + +#fulldomain=_acme-challenge.domain.ddnss.de +#returns +# _ddnss_domain=domain +_ddnss_get_domain() { + + # We'll extract the domain/username from full domain + _ddnss_domain="$(echo "$fulldomain" | _lower_case | _egrep_o '[.][^.][^.]*[.](ddnss|dyn-ip24|dyndns|dyn|dyndns1|home-webserver|myhome-server|dynip)\..*' | cut -d . -f 2-)" + + if [ -z "$_ddnss_domain" ]; then + _err "Error extracting the domain." + return 1 + fi + + return 0 +} + +#Usage: method URI +_ddnss_rest() { + method=$1 + param="$2" + _debug param "$param" + url="$DDNSS_DNS_API?$param" + _debug url "$url" + + # DDNSS uses GET to update domain info + if [ "$method" = "GET" ]; then + response="$(_get "$url" | sed 's/<[a-zA-Z\/][^>]*>//g' | tr -s "\n" | _tail_n 1)" + else + _err "Unsupported method" + return 1 + fi + + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_desec.sh b/letsencrypt/dnsapi/dns_desec.sh new file mode 100644 index 00000000..5affa0e1 --- /dev/null +++ b/letsencrypt/dnsapi/dns_desec.sh @@ -0,0 +1,204 @@ +#!/bin/bash +# +# deSEC.io Domain API +# +# Author: Zheng Qian +# +# deSEC API doc +# https://desec.readthedocs.io/en/latest/ + +REST_API="https://desec.io/api/v1/domains" + +######## Public functions ##################### + +#Usage: dns_desec_add _acme-challenge.foobar.dedyn.io "d41d8cd98f00b204e9800998ecf8427e" +dns_desec_add() { + fulldomain=$1 + txtvalue=$2 + _info "Using desec.io api" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + DEDYN_TOKEN="${DEDYN_TOKEN:-$(_readaccountconf_mutable DEDYN_TOKEN)}" + DEDYN_NAME="${DEDYN_NAME:-$(_readaccountconf_mutable DEDYN_NAME)}" + + if [ -z "$DEDYN_TOKEN" ] || [ -z "$DEDYN_NAME" ]; then + DEDYN_TOKEN="" + DEDYN_NAME="" + _err "You did not specify DEDYN_TOKEN and DEDYN_NAME yet." + _err "Please create your key and try again." + _err "e.g." + _err "export DEDYN_TOKEN=d41d8cd98f00b204e9800998ecf8427e" + _err "export DEDYN_NAME=foobar.dedyn.io" + return 1 + fi + #save the api token and name to the account conf file. + _saveaccountconf_mutable DEDYN_TOKEN "$DEDYN_TOKEN" + _saveaccountconf_mutable DEDYN_NAME "$DEDYN_NAME" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain" "$REST_API/"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + # Get existing TXT record + _debug "Getting txt records" + txtvalues="\"\\\"$txtvalue\\\"\"" + _desec_rest GET "$REST_API/$DEDYN_NAME/rrsets/$_sub_domain/TXT/" + + if [ "$_code" = "200" ]; then + oldtxtvalues="$(echo "$response" | _egrep_o "\"records\":\\[\"\\S*\"\\]" | cut -d : -f 2 | tr -d "[]\\\\\"" | sed "s/,/ /g")" + _debug "existing TXT found" + _debug oldtxtvalues "$oldtxtvalues" + if [ -n "$oldtxtvalues" ]; then + for oldtxtvalue in $oldtxtvalues; do + txtvalues="$txtvalues, \"\\\"$oldtxtvalue\\\"\"" + done + fi + fi + _debug txtvalues "$txtvalues" + _info "Adding record" + body="[{\"subname\":\"$_sub_domain\", \"type\":\"TXT\", \"records\":[$txtvalues], \"ttl\":3600}]" + + if _desec_rest PUT "$REST_API/$DEDYN_NAME/rrsets/" "$body"; then + if _contains "$response" "$txtvalue"; then + _info "Added, OK" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + + _err "Add txt record error." + return 1 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_desec_rm() { + fulldomain=$1 + txtvalue=$2 + _info "Using desec.io api" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + DEDYN_TOKEN="${DEDYN_TOKEN:-$(_readaccountconf_mutable DEDYN_TOKEN)}" + DEDYN_NAME="${DEDYN_NAME:-$(_readaccountconf_mutable DEDYN_NAME)}" + + if [ -z "$DEDYN_TOKEN" ] || [ -z "$DEDYN_NAME" ]; then + DEDYN_TOKEN="" + DEDYN_NAME="" + _err "You did not specify DEDYN_TOKEN and DEDYN_NAME yet." + _err "Please create your key and try again." + _err "e.g." + _err "export DEDYN_TOKEN=d41d8cd98f00b204e9800998ecf8427e" + _err "export DEDYN_NAME=foobar.dedyn.io" + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain" "$REST_API/"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + # Get existing TXT record + _debug "Getting txt records" + txtvalues="" + _desec_rest GET "$REST_API/$DEDYN_NAME/rrsets/$_sub_domain/TXT/" + + if [ "$_code" = "200" ]; then + oldtxtvalues="$(echo "$response" | _egrep_o "\"records\":\\[\"\\S*\"\\]" | cut -d : -f 2 | tr -d "[]\\\\\"" | sed "s/,/ /g")" + _debug "existing TXT found" + _debug oldtxtvalues "$oldtxtvalues" + if [ -n "$oldtxtvalues" ]; then + for oldtxtvalue in $oldtxtvalues; do + if [ "$txtvalue" != "$oldtxtvalue" ]; then + txtvalues="$txtvalues, \"\\\"$oldtxtvalue\\\"\"" + fi + done + fi + fi + txtvalues="$(echo "$txtvalues" | cut -c3-)" + _debug txtvalues "$txtvalues" + + _info "Deleting record" + body="[{\"subname\":\"$_sub_domain\", \"type\":\"TXT\", \"records\":[$txtvalues], \"ttl\":3600}]" + _desec_rest PUT "$REST_API/$DEDYN_NAME/rrsets/" "$body" + if [ "$_code" = "200" ]; then + _info "Deleted, OK" + return 0 + fi + + _err "Delete txt record error." + return 1 +} + +#################### Private functions below ################################## + +_desec_rest() { + m="$1" + ep="$2" + data="$3" + + export _H1="Authorization: Token $DEDYN_TOKEN" + export _H2="Accept: application/json" + export _H3="Content-Type: application/json" + + if [ "$m" != "GET" ]; then + _secure_debug2 data "$data" + response="$(_post "$data" "$ep" "" "$m")" + else + response="$(_get "$ep")" + fi + _ret="$?" + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" + _debug "http response code $_code" + _secure_debug2 response "$response" + if [ "$_ret" != "0" ]; then + _err "error $ep" + return 1 + fi + + response="$(printf "%s" "$response" | _normalizeJson)" + return 0 +} + +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain="$1" + ep="$2" + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _desec_rest GET "$ep"; then + return 1 + fi + + if _contains "$response" "\"name\":\"$h\"" >/dev/null; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} diff --git a/letsencrypt/dnsapi/dns_df.sh b/letsencrypt/dnsapi/dns_df.sh new file mode 100644 index 00000000..452b5941 --- /dev/null +++ b/letsencrypt/dnsapi/dns_df.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +######################################################################## +# https://dyndnsfree.de hook script for acme.sh +# +# Environment variables: +# +# - $DF_user (your dyndnsfree.de username) +# - $DF_password (your dyndnsfree.de password) +# +# Author: Thilo Gass +# Git repo: https://github.com/ThiloGa/acme.sh + +#-- dns_df_add() - Add TXT record -------------------------------------- +# Usage: dns_df_add _acme-challenge.subdomain.domain.com "XyZ123..." + +dyndnsfree_api="https://dynup.de/acme.php" + +dns_df_add() { + fulldomain=$1 + txt_value=$2 + _info "Using DNS-01 dyndnsfree.de hook" + + DF_user="${DF_user:-$(_readaccountconf_mutable DF_user)}" + DF_password="${DF_password:-$(_readaccountconf_mutable DF_password)}" + if [ -z "$DF_user" ] || [ -z "$DF_password" ]; then + DF_user="" + DF_password="" + _err "No auth details provided. Please set user credentials using the \$DF_user and \$DF_password environment variables." + return 1 + fi + #save the api user and password to the account conf file. + _debug "Save user and password" + _saveaccountconf_mutable DF_user "$DF_user" + _saveaccountconf_mutable DF_password "$DF_password" + + domain="$(printf "%s" "$fulldomain" | cut -d"." -f2-)" + + get="$dyndnsfree_api?username=$DF_user&password=$DF_password&hostname=$domain&add_hostname=$fulldomain&txt=$txt_value" + + if ! erg="$(_get "$get")"; then + _err "error Adding $fulldomain TXT: $txt_value" + return 1 + fi + + if _contains "$erg" "success"; then + _info "Success, TXT Added, OK" + else + _err "error Adding $fulldomain TXT: $txt_value erg: $erg" + return 1 + fi + + _debug "ok Auto $fulldomain TXT: $txt_value erg: $erg" + return 0 +} + +dns_df_rm() { + + fulldomain=$1 + txtvalue=$2 + _info "TXT enrty in $fulldomain is deleted automatically" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + +} diff --git a/letsencrypt/dnsapi/dns_dgon.sh b/letsencrypt/dnsapi/dns_dgon.sh new file mode 100755 index 00000000..e1ae4082 --- /dev/null +++ b/letsencrypt/dnsapi/dns_dgon.sh @@ -0,0 +1,250 @@ +#!/bin/bash + +## Will be called by acme.sh to add the txt record to your api system. +## returns 0 means success, otherwise error. + +## Author: thewer +## GitHub: https://github.com/gitwer/acme.sh + +## +## Environment Variables Required: +## +## DO_API_KEY="75310dc4ca779ac39a19f6355db573b49ce92ae126553ebd61ac3a3ae34834cc" +## + +##################### Public functions ##################### + +## Create the text record for validation. +## Usage: fulldomain txtvalue +## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs" +dns_dgon_add() { + fulldomain="$(echo "$1" | _lower_case)" + txtvalue=$2 + + DO_API_KEY="${DO_API_KEY:-$(_readaccountconf_mutable DO_API_KEY)}" + # Check if API Key Exists + if [ -z "$DO_API_KEY" ]; then + DO_API_KEY="" + _err "You did not specify DigitalOcean API key." + _err "Please export DO_API_KEY and try again." + return 1 + fi + + _info "Using digitalocean dns validation - add record" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + ## save the env vars (key and domain split location) for later automated use + _saveaccountconf_mutable DO_API_KEY "$DO_API_KEY" + + ## split the domain for DO API + if ! _get_base_domain "$fulldomain"; then + _err "domain not found in your account for addition" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + ## Set the header with our post type and key auth key + export _H1="Content-Type: application/json" + export _H2="Authorization: Bearer $DO_API_KEY" + PURL='https://api.digitalocean.com/v2/domains/'$_domain'/records' + PBODY='{"type":"TXT","name":"'$_sub_domain'","data":"'$txtvalue'","ttl":120}' + + _debug PURL "$PURL" + _debug PBODY "$PBODY" + + ## the create request - post + ## args: BODY, URL, [need64, httpmethod] + response="$(_post "$PBODY" "$PURL")" + + ## check response + if [ "$?" != "0" ]; then + _err "error in response: $response" + return 1 + fi + _debug2 response "$response" + + ## finished correctly + return 0 +} + +## Remove the txt record after validation. +## Usage: fulldomain txtvalue +## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs" +dns_dgon_rm() { + fulldomain="$(echo "$1" | _lower_case)" + txtvalue=$2 + + DO_API_KEY="${DO_API_KEY:-$(_readaccountconf_mutable DO_API_KEY)}" + # Check if API Key Exists + if [ -z "$DO_API_KEY" ]; then + DO_API_KEY="" + _err "You did not specify DigitalOcean API key." + _err "Please export DO_API_KEY and try again." + return 1 + fi + + _info "Using digitalocean dns validation - remove record" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + ## split the domain for DO API + if ! _get_base_domain "$fulldomain"; then + _err "domain not found in your account for removal" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + ## Set the header with our post type and key auth key + export _H1="Content-Type: application/json" + export _H2="Authorization: Bearer $DO_API_KEY" + ## get URL for the list of domains + ## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}} + GURL="https://api.digitalocean.com/v2/domains/$_domain/records" + + ## Get all the matching records + while true; do + ## 1) get the URL + ## the create request - get + ## args: URL, [onlyheader, timeout] + domain_list="$(_get "$GURL")" + + ## check response + if [ "$?" != "0" ]; then + _err "error in domain_list response: $domain_list" + return 1 + fi + _debug2 domain_list "$domain_list" + + ## 2) find records + ## check for what we are looking for: "type":"A","name":"$_sub_domain" + record="$(echo "$domain_list" | _egrep_o "\"id\"\s*\:\s*\"*[0-9]+\"*[^}]*\"name\"\s*\:\s*\"$_sub_domain\"[^}]*\"data\"\s*\:\s*\"$txtvalue\"")" + + if [ -n "$record" ]; then + + ## we found records + rec_ids="$(echo "$record" | _egrep_o "id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")" + _debug rec_ids "$rec_ids" + if [ -n "$rec_ids" ]; then + echo "$rec_ids" | while IFS= read -r rec_id; do + ## delete the record + ## delete URL for removing the one we dont want + DURL="https://api.digitalocean.com/v2/domains/$_domain/records/$rec_id" + + ## the create request - delete + ## args: BODY, URL, [need64, httpmethod] + response="$(_post "" "$DURL" "" "DELETE")" + + ## check response (sort of) + if [ "$?" != "0" ]; then + _err "error in remove response: $response" + return 1 + fi + _debug2 response "$response" + + done + fi + fi + + ## 3) find the next page + nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=[0-9]+")" + if [ -z "$nextpage" ]; then + break + fi + _debug2 nextpage "$nextpage" + GURL="$nextpage" + + done + + ## finished correctly + return 0 +} + +##################### Private functions below ##################### + +## Split the domain provided into the "bade domain" and the "start prefix". +## This function searches for the longest subdomain in your account +## for the full domain given and splits it into the base domain (zone) +## and the prefix/record to be added/removed +## USAGE: fulldomain +## EG: "_acme-challenge.two.three.four.domain.com" +## returns +## _sub_domain="_acme-challenge.two" +## _domain="three.four.domain.com" *IF* zone "three.four.domain.com" exists +## if only "domain.com" exists it will return +## _sub_domain="_acme-challenge.two.three.four" +## _domain="domain.com" +_get_base_domain() { + # args + fulldomain="$(echo "$1" | _lower_case)" + _debug fulldomain "$fulldomain" + + # domain max legal length = 253 + MAX_DOM=255 + + ## get a list of domains for the account to check thru + ## Set the headers + export _H1="Content-Type: application/json" + export _H2="Authorization: Bearer $DO_API_KEY" + _debug DO_API_KEY "$DO_API_KEY" + ## get URL for the list of domains + ## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}} + DOMURL="https://api.digitalocean.com/v2/domains" + + ## while we dont have a matching domain we keep going + while [ -z "$found" ]; do + ## get the domain list (current page) + domain_list="$(_get "$DOMURL")" + + ## check response + if [ "$?" != "0" ]; then + _err "error in domain_list response: $domain_list" + return 1 + fi + _debug2 domain_list "$domain_list" + + ## for each shortening of our $fulldomain, check if it exists in the $domain_list + ## can never start on 1 (aka whole $fulldomain) as $fulldomain starts with "_acme-challenge" + i=2 + while [ $i -gt 0 ]; do + ## get next longest domain + _domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM") + ## check we got something back from our cut (or are we at the end) + if [ -z "$_domain" ]; then + break + fi + ## we got part of a domain back - grep it out + found="$(echo "$domain_list" | _egrep_o "\"name\"\s*\:\s*\"$_domain\"")" + ## check if it exists + if [ -n "$found" ]; then + ## exists - exit loop returning the parts + sub_point=$(_math $i - 1) + _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point") + _debug _domain "$_domain" + _debug _sub_domain "$_sub_domain" + return 0 + fi + ## increment cut point $i + i=$(_math $i + 1) + done + + if [ -z "$found" ]; then + ## find the next page if we dont have a match + nextpage="$(echo "$domain_list" | _egrep_o "\"links\".*" | _egrep_o "\"next\".*" | _egrep_o "http.*page\=[0-9]+")" + if [ -z "$nextpage" ]; then + _err "no record and no nextpage in digital ocean DNS removal" + return 1 + fi + _debug2 nextpage "$nextpage" + DOMURL="$nextpage" + fi + + done + + ## we went through the entire domain zone list and dint find one that matched + ## doesnt look like we can add in the record + _err "domain not found in DigitalOcean account, but we should never get here" + return 1 +} diff --git a/letsencrypt/dnsapi/dns_dnsimple.sh b/letsencrypt/dnsapi/dns_dnsimple.sh new file mode 100644 index 00000000..37297635 --- /dev/null +++ b/letsencrypt/dnsapi/dns_dnsimple.sh @@ -0,0 +1,198 @@ +#!/bin/bash + +# DNSimple domain api +# https://github.com/pho3nixf1re/acme.sh/issues +# +# This is your oauth token which can be acquired on the account page. Please +# note that this must be an _account_ token and not a _user_ token. +# https://dnsimple.com/a//account/access_tokens +# DNSimple_OAUTH_TOKEN="sdfsdfsdfljlbjkljlkjsdfoiwje" + +DNSimple_API="https://api.dnsimple.com/v2" + +######## Public functions ##################### + +# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_dnsimple_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$DNSimple_OAUTH_TOKEN" ]; then + DNSimple_OAUTH_TOKEN="" + _err "You have not set the dnsimple oauth token yet." + _err "Please visit https://dnsimple.com/user to generate it." + return 1 + fi + + # save the oauth token for later + _saveaccountconf DNSimple_OAUTH_TOKEN "$DNSimple_OAUTH_TOKEN" + + if ! _get_account_id; then + _err "failed to retrive account id" + return 1 + fi + + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _get_records "$_account_id" "$_domain" "$_sub_domain" + + _info "Adding record" + if _dnsimple_rest POST "$_account_id/zones/$_domain/records" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then + if printf -- "%s" "$response" | grep "\"name\":\"$_sub_domain\"" >/dev/null; then + _info "Added" + return 0 + else + _err "Unexpected response while adding text record." + return 1 + fi + fi + _err "Add txt record error." +} + +# fulldomain +dns_dnsimple_rm() { + fulldomain=$1 + + if ! _get_account_id; then + _err "failed to retrive account id" + return 1 + fi + + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _get_records "$_account_id" "$_domain" "$_sub_domain" + + _extract_record_id "$_records" "$_sub_domain" + if [ "$_record_id" ]; then + echo "$_record_id" | while read -r item; do + if _dnsimple_rest DELETE "$_account_id/zones/$_domain/records/$item"; then + _info "removed record" "$item" + return 0 + else + _err "failed to remove record" "$item" + return 1 + fi + done + fi +} + +#################### Private functions bellow ################################## +# _acme-challenge.www.domain.com +# returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain=$1 + i=2 + previous=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + # not valid + return 1 + fi + + if ! _dnsimple_rest GET "$_account_id/zones/$h"; then + return 1 + fi + + if _contains "$response" 'not found'; then + _debug "$h not found" + else + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$previous) + _domain="$h" + + _debug _domain "$_domain" + _debug _sub_domain "$_sub_domain" + + return 0 + fi + + previous="$i" + i=$(_math "$i" + 1) + done + return 1 +} + +# returns _account_id +_get_account_id() { + _debug "retrive account id" + if ! _dnsimple_rest GET "whoami"; then + return 1 + fi + + if _contains "$response" "\"account\":null"; then + _err "no account associated with this token" + return 1 + fi + + if _contains "$response" "timeout"; then + _err "timeout retrieving account id" + return 1 + fi + + _account_id=$(printf "%s" "$response" | _egrep_o "\"id\":[^,]*,\"email\":" | cut -d: -f2 | cut -d, -f1) + _debug _account_id "$_account_id" + + return 0 +} + +# returns +# _records +# _records_count +_get_records() { + account_id=$1 + domain=$2 + sub_domain=$3 + + _debug "fetching txt records" + _dnsimple_rest GET "$account_id/zones/$domain/records?per_page=5000&sort=id:desc" + + if ! _contains "$response" "\"id\":"; then + _err "failed to retrieve records" + return 1 + fi + + _records_count=$(printf "%s" "$response" | _egrep_o "\"name\":\"$sub_domain\"" | wc -l | _egrep_o "[0-9]+") + _records=$response + _debug _records_count "$_records_count" +} + +# returns _record_id +_extract_record_id() { + _record_id=$(printf "%s" "$_records" | _egrep_o "\"id\":[^,]*,\"zone_id\":\"[^,]*\",\"parent_id\":null,\"name\":\"$_sub_domain\"" | cut -d: -f2 | cut -d, -f1) + _debug "_record_id" "$_record_id" +} + +# returns response +_dnsimple_rest() { + method=$1 + path="$2" + data="$3" + request_url="$DNSimple_API/$path" + _debug "$path" + + export _H1="Accept: application/json" + export _H2="Authorization: Bearer $DNSimple_OAUTH_TOKEN" + + if [ "$data" ] || [ "$method" = "DELETE" ]; then + _H1="Content-Type: application/json" + _debug data "$data" + response="$(_post "$data" "$request_url" "" "$method")" + else + response="$(_get "$request_url" "" "" "$method")" + fi + + if [ "$?" != "0" ]; then + _err "error $request_url" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_do.sh b/letsencrypt/dnsapi/dns_do.sh new file mode 100755 index 00000000..61f4b9fe --- /dev/null +++ b/letsencrypt/dnsapi/dns_do.sh @@ -0,0 +1,148 @@ +#!/bin/bash + +# DNS API for Domain-Offensive / Resellerinterface / Domainrobot + +# Report bugs at https://github.com/seidler2547/acme.sh/issues + +# set these environment variables to match your customer ID and password: +# DO_PID="KD-1234567" +# DO_PW="cdfkjl3n2" + +DO_URL="https://soap.resellerinterface.de/" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_do_add() { + fulldomain=$1 + txtvalue=$2 + if _dns_do_authenticate; then + _info "Adding TXT record to ${_domain} as ${fulldomain}" + _dns_do_soap createRR origin "${_domain}" name "${fulldomain}" type TXT data "${txtvalue}" ttl 300 + if _contains "${response}" '>success<'; then + return 0 + fi + _err "Could not create resource record, check logs" + fi + return 1 +} + +#fulldomain +dns_do_rm() { + fulldomain=$1 + if _dns_do_authenticate; then + if _dns_do_list_rrs; then + _dns_do_had_error=0 + for _rrid in ${_rr_list}; do + _info "Deleting resource record $_rrid for $_domain" + _dns_do_soap deleteRR origin "${_domain}" rrid "${_rrid}" + if ! _contains "${response}" '>success<'; then + _dns_do_had_error=1 + _err "Could not delete resource record for ${_domain}, id ${_rrid}" + fi + done + return $_dns_do_had_error + fi + fi + return 1 +} + +#################### Private functions below ################################## +_dns_do_authenticate() { + _info "Authenticating as ${DO_PID}" + _dns_do_soap authPartner partner "${DO_PID}" password "${DO_PW}" + if _contains "${response}" '>success<'; then + _get_root "$fulldomain" + _debug "_domain $_domain" + return 0 + else + _err "Authentication failed, are DO_PID and DO_PW set correctly?" + fi + return 1 +} + +_dns_do_list_rrs() { + _dns_do_soap getRRList origin "${_domain}" + if ! _contains "${response}" 'SOAP-ENC:Array'; then + _err "getRRList origin ${_domain} failed" + return 1 + fi + _rr_list="$(echo "${response}" | + tr -d "\n\r\t" | + sed -e 's//\n/g' | + grep ">$(_regexcape "$fulldomain")
" | + sed -e 's/<\/item>/\n/g' | + grep '>id
[0-9]{1,16}<' | + tr -d '><')" + [ "${_rr_list}" ] +} + +_dns_do_soap() { + func="$1" + shift + # put the parameters to xml + body="" + while [ "$1" ]; do + _k="$1" + shift + _v="$1" + shift + body="$body<$_k>$_v" + done + body="$body" + _debug2 "SOAP request ${body}" + + # build SOAP XML + _xml=' + + '"$body"' +' + + # set SOAP headers + export _H1="SOAPAction: ${DO_URL}#${func}" + + if ! response="$(_post "${_xml}" "${DO_URL}")"; then + _err "Error <$1>" + return 1 + fi + _debug2 "SOAP response $response" + + # retrieve cookie header + _H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | _head_n 1)" + export _H2 + + return 0 +} + +_get_root() { + domain=$1 + i=1 + + _dns_do_soap getDomainList + _all_domains="$(echo "${response}" | + tr -d "\n\r\t " | + _egrep_o 'domain]+>[^<]+' | + sed -e 's/^domain<\/key>]*>//g')" + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + return 1 + fi + + if _contains "${_all_domains}" "^$(_regexcape "$h")\$"; then + _domain="$h" + return 0 + fi + + i=$(_math $i + 1) + done + _debug "$domain not found" + + return 1 +} + +_regexcape() { + echo "$1" | sed -e 's/\([]\.$*^[]\)/\\\1/g' +} diff --git a/letsencrypt/dnsapi/dns_doapi.sh b/letsencrypt/dnsapi/dns_doapi.sh new file mode 100755 index 00000000..ac7b37f2 --- /dev/null +++ b/letsencrypt/dnsapi/dns_doapi.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +# Official Let's Encrypt API for do.de / Domain-Offensive +# +# This is different from the dns_do adapter, because dns_do is only usable for enterprise customers +# This API is also available to private customers/individuals +# +# Provide the required LetsEncrypt token like this: +# DO_LETOKEN="FmD408PdqT1E269gUK57" + +DO_API="https://www.do.de/api/letsencrypt" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_doapi_add() { + fulldomain=$1 + txtvalue=$2 + + DO_LETOKEN="${DO_LETOKEN:-$(_readaccountconf_mutable DO_LETOKEN)}" + if [ -z "$DO_LETOKEN" ]; then + DO_LETOKEN="" + _err "You didn't configure a do.de API token yet." + _err "Please set DO_LETOKEN and try again." + return 1 + fi + _saveaccountconf_mutable DO_LETOKEN "$DO_LETOKEN" + + _info "Adding TXT record to ${fulldomain}" + response="$(_get "$DO_API?token=$DO_LETOKEN&domain=${fulldomain}&value=${txtvalue}")" + if _contains "${response}" 'success'; then + return 0 + fi + _err "Could not create resource record, check logs" + _err "${response}" + return 1 +} + +dns_doapi_rm() { + fulldomain=$1 + + DO_LETOKEN="${DO_LETOKEN:-$(_readaccountconf_mutable DO_LETOKEN)}" + if [ -z "$DO_LETOKEN" ]; then + DO_LETOKEN="" + _err "You didn't configure a do.de API token yet." + _err "Please set DO_LETOKEN and try again." + return 1 + fi + _saveaccountconf_mutable DO_LETOKEN "$DO_LETOKEN" + + _info "Deleting resource record $fulldomain" + response="$(_get "$DO_API?token=$DO_LETOKEN&domain=${fulldomain}&action=delete")" + if _contains "${response}" 'success'; then + return 0 + fi + _err "Could not delete resource record, check logs" + _err "${response}" + return 1 +} diff --git a/letsencrypt/dnsapi/dns_domeneshop.sh b/letsencrypt/dnsapi/dns_domeneshop.sh new file mode 100644 index 00000000..77aef779 --- /dev/null +++ b/letsencrypt/dnsapi/dns_domeneshop.sh @@ -0,0 +1,155 @@ +#!/bin/bash + +DOMENESHOP_Api_Endpoint="https://api.domeneshop.no/v0" + +##################### Public functions ##################### + +# Usage: dns_domeneshop_add +# Example: dns_domeneshop_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_domeneshop_add() { + fulldomain=$1 + txtvalue=$2 + + # Get token and secret + DOMENESHOP_Token="${DOMENESHOP_Token:-$(_readaccountconf_mutable DOMENESHOP_Token)}" + DOMENESHOP_Secret="${DOMENESHOP_Secret:-$(_readaccountconf_mutable DOMENESHOP_Secret)}" + + if [ -z "$DOMENESHOP_Token" ] || [ -z "$DOMENESHOP_Secret" ]; then + DOMENESHOP_Token="" + DOMENESHOP_Secret="" + _err "You need to spesify a Domeneshop/Domainnameshop API Token and Secret." + return 1 + fi + + # Save the api token and secret. + _saveaccountconf_mutable DOMENESHOP_Token "$DOMENESHOP_Token" + _saveaccountconf_mutable DOMENESHOP_Secret "$DOMENESHOP_Secret" + + # Get the domain name id + if ! _get_domainid "$fulldomain"; then + _err "Did not find domainname" + return 1 + fi + + # Create record + _domeneshop_rest POST "domains/$_domainid/dns" "{\"type\":\"TXT\",\"host\":\"$_sub_domain\",\"data\":\"$txtvalue\",\"ttl\":120}" +} + +# Usage: dns_domeneshop_rm +# Example: dns_domeneshop_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_domeneshop_rm() { + fulldomain=$1 + txtvalue=$2 + + # Get token and secret + DOMENESHOP_Token="${DOMENESHOP_Token:-$(_readaccountconf_mutable DOMENESHOP_Token)}" + DOMENESHOP_Secret="${DOMENESHOP_Secret:-$(_readaccountconf_mutable DOMENESHOP_Secret)}" + + if [ -z "$DOMENESHOP_Token" ] || [ -z "$DOMENESHOP_Secret" ]; then + DOMENESHOP_Token="" + DOMENESHOP_Secret="" + _err "You need to spesify a Domeneshop/Domainnameshop API Token and Secret." + return 1 + fi + + # Get the domain name id + if ! _get_domainid "$fulldomain"; then + _err "Did not find domainname" + return 1 + fi + + # Find record + if ! _get_recordid "$_domainid" "$_sub_domain" "$txtvalue"; then + _err "Did not find dns record" + return 1 + fi + + # Remove record + _domeneshop_rest DELETE "domains/$_domainid/dns/$_recordid" +} + +##################### Private functions ##################### + +_get_domainid() { + domain=$1 + + # Get domains + _domeneshop_rest GET "domains" + + if ! _contains "$response" "\"id\":"; then + _err "failed to get domain names" + return 1 + fi + + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug "h" "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "\"$h\"" >/dev/null; then + # We have found the domain name. + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + _domainid=$(printf "%s" "$response" | _egrep_o "[^{]*\"domain\":\"$_domain\"[^}]*" | _egrep_o "\"id\":[0-9]+" | cut -d : -f 2) + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_get_recordid() { + domainid=$1 + subdomain=$2 + txtvalue=$3 + + # Get all dns records for the domainname + _domeneshop_rest GET "domains/$domainid/dns" + + if ! _contains "$response" "\"id\":"; then + _debug "No records in dns" + return 1 + fi + + if ! _contains "$response" "\"host\":\"$subdomain\""; then + _debug "Record does not exist" + return 1 + fi + + # Get the id of the record in question + _recordid=$(printf "%s" "$response" | _egrep_o "[^{]*\"host\":\"$subdomain\"[^}]*" | _egrep_o "[^{]*\"data\":\"$txtvalue\"[^}]*" | _egrep_o "\"id\":[0-9]+" | cut -d : -f 2) + if [ -z "$_recordid" ]; then + return 1 + fi + return 0 +} + +_domeneshop_rest() { + method=$1 + endpoint=$2 + data=$3 + + credentials=$(printf "%b" "$DOMENESHOP_Token:$DOMENESHOP_Secret" | _base64) + + export _H1="Authorization: Basic $credentials" + export _H2="Content-Type: application/json" + + if [ "$method" != "GET" ]; then + response="$(_post "$data" "$DOMENESHOP_Api_Endpoint/$endpoint" "" "$method")" + else + response="$(_get "$DOMENESHOP_Api_Endpoint/$endpoint")" + fi + + if [ "$?" != "0" ]; then + _err "error $endpoint" + return 1 + fi + + return 0 +} diff --git a/letsencrypt/dnsapi/dns_dp.sh b/letsencrypt/dnsapi/dns_dp.sh new file mode 100755 index 00000000..6e19c10e --- /dev/null +++ b/letsencrypt/dnsapi/dns_dp.sh @@ -0,0 +1,161 @@ +#!/bin/bash + +# Dnspod.cn Domain api +# +#DP_Id="1234" +# +#DP_Key="sADDsdasdgdsf" + +REST_API="https://dnsapi.cn" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_dp_add() { + fulldomain=$1 + txtvalue=$2 + + DP_Id="${DP_Id:-$(_readaccountconf_mutable DP_Id)}" + DP_Key="${DP_Key:-$(_readaccountconf_mutable DP_Key)}" + if [ -z "$DP_Id" ] || [ -z "$DP_Key" ]; then + DP_Id="" + DP_Key="" + _err "You don't specify dnspod api key and key id yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable DP_Id "$DP_Id" + _saveaccountconf_mutable DP_Key "$DP_Key" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + add_record "$_domain" "$_sub_domain" "$txtvalue" + +} + +#fulldomain txtvalue +dns_dp_rm() { + fulldomain=$1 + txtvalue=$2 + + DP_Id="${DP_Id:-$(_readaccountconf_mutable DP_Id)}" + DP_Key="${DP_Key:-$(_readaccountconf_mutable DP_Key)}" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + if ! _rest POST "Record.List" "login_token=$DP_Id,$DP_Key&format=json&lang=en&domain_id=$_domain_id&sub_domain=$_sub_domain"; then + _err "Record.Lis error." + return 1 + fi + + if _contains "$response" 'No records'; then + _info "Don't need to remove." + return 0 + fi + + record_id=$(echo "$response" | tr "{" "\n" | grep -- "$txtvalue" | grep '^"id"' | cut -d : -f 2 | cut -d '"' -f 2) + _debug record_id "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id." + return 1 + fi + + if ! _rest POST "Record.Remove" "login_token=$DP_Id,$DP_Key&format=json&lang=en&domain_id=$_domain_id&record_id=$record_id"; then + _err "Record.Remove error." + return 1 + fi + + _contains "$response" "successful" + +} + +#add the txt record. +#usage: root sub txtvalue +add_record() { + root=$1 + sub=$2 + txtvalue=$3 + fulldomain="$sub.$root" + + _info "Adding record" + + if ! _rest POST "Record.Create" "login_token=$DP_Id,$DP_Key&format=json&lang=en&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=默认"; then + return 1 + fi + + _contains "$response" "successful" || _contains "$response" "Domain record already exists" +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _rest POST "Domain.Info" "login_token=$DP_Id,$DP_Key&format=json&lang=en&domain=$h"; then + return 1 + fi + + if _contains "$response" "successful"; then + _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") + _debug _domain_id "$_domain_id" + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _debug _sub_domain "$_sub_domain" + _domain="$h" + _debug _domain "$_domain" + return 0 + fi + return 1 + fi + p="$i" + i=$(_math "$i" + 1) + done + return 1 +} + +#Usage: method URI data +_rest() { + m="$1" + ep="$2" + data="$3" + _debug "$ep" + url="$REST_API/$ep" + + _debug url "$url" + + if [ "$m" = "GET" ]; then + response="$(_get "$url" | tr -d '\r')" + else + _debug2 data "$data" + response="$(_post "$data" "$url" | tr -d '\r')" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_dpi.sh b/letsencrypt/dnsapi/dns_dpi.sh new file mode 100755 index 00000000..57b409eb --- /dev/null +++ b/letsencrypt/dnsapi/dns_dpi.sh @@ -0,0 +1,161 @@ +#!/bin/bash + +# Dnspod.com Domain api +# +#DPI_Id="1234" +# +#DPI_Key="sADDsdasdgdsf" + +REST_API="https://api.dnspod.com" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_dpi_add() { + fulldomain=$1 + txtvalue=$2 + + DPI_Id="${DPI_Id:-$(_readaccountconf_mutable DPI_Id)}" + DPI_Key="${DPI_Key:-$(_readaccountconf_mutable DPI_Key)}" + if [ -z "$DPI_Id" ] || [ -z "$DPI_Key" ]; then + DPI_Id="" + DPI_Key="" + _err "You don't specify dnspod api key and key id yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable DPI_Id "$DPI_Id" + _saveaccountconf_mutable DPI_Key "$DPI_Key" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + add_record "$_domain" "$_sub_domain" "$txtvalue" + +} + +#fulldomain txtvalue +dns_dpi_rm() { + fulldomain=$1 + txtvalue=$2 + + DPI_Id="${DPI_Id:-$(_readaccountconf_mutable DPI_Id)}" + DPI_Key="${DPI_Key:-$(_readaccountconf_mutable DPI_Key)}" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + if ! _rest POST "Record.List" "user_token=$DPI_Id,$DPI_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain"; then + _err "Record.Lis error." + return 1 + fi + + if _contains "$response" 'No records'; then + _info "Don't need to remove." + return 0 + fi + + record_id=$(echo "$response" | _egrep_o '{[^{]*"value":"'"$txtvalue"'"' | cut -d , -f 1 | cut -d : -f 2 | tr -d \") + _debug record_id "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id." + return 1 + fi + + if ! _rest POST "Record.Remove" "user_token=$DPI_Id,$DPI_Key&format=json&domain_id=$_domain_id&record_id=$record_id"; then + _err "Record.Remove error." + return 1 + fi + + _contains "$response" "Operation successful" + +} + +#add the txt record. +#usage: root sub txtvalue +add_record() { + root=$1 + sub=$2 + txtvalue=$3 + fulldomain="$sub.$root" + + _info "Adding record" + + if ! _rest POST "Record.Create" "user_token=$DPI_Id,$DPI_Key&format=json&domain_id=$_domain_id&sub_domain=$_sub_domain&record_type=TXT&value=$txtvalue&record_line=default"; then + return 1 + fi + + _contains "$response" "Operation successful" || _contains "$response" "Domain record already exists" +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _rest POST "Domain.Info" "user_token=$DPI_Id,$DPI_Key&format=json&domain=$h"; then + return 1 + fi + + if _contains "$response" "Operation successful"; then + _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \") + _debug _domain_id "$_domain_id" + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _debug _sub_domain "$_sub_domain" + _domain="$h" + _debug _domain "$_domain" + return 0 + fi + return 1 + fi + p="$i" + i=$(_math "$i" + 1) + done + return 1 +} + +#Usage: method URI data +_rest() { + m="$1" + ep="$2" + data="$3" + _debug "$ep" + url="$REST_API/$ep" + + _debug url "$url" + + if [ "$m" = "GET" ]; then + response="$(_get "$url" | tr -d '\r')" + else + _debug2 data "$data" + response="$(_post "$data" "$url" | tr -d '\r')" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_dreamhost.sh b/letsencrypt/dnsapi/dns_dreamhost.sh new file mode 100644 index 00000000..45905a66 --- /dev/null +++ b/letsencrypt/dnsapi/dns_dreamhost.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +#Author: RhinoLance +#Report Bugs here: https://github.com/RhinoLance/acme.sh +# + +#define the api endpoint +DH_API_ENDPOINT="https://api.dreamhost.com/" +querystring="" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_dreamhost_add() { + fulldomain=$1 + txtvalue=$2 + + if ! validate "$fulldomain" "$txtvalue"; then + return 1 + fi + + querystring="key=$DH_API_KEY&cmd=dns-add_record&record=$fulldomain&type=TXT&value=$txtvalue" + if ! submit "$querystring"; then + return 1 + fi + + return 0 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_dreamhost_rm() { + fulldomain=$1 + txtvalue=$2 + + if ! validate "$fulldomain" "$txtvalue"; then + return 1 + fi + + querystring="key=$DH_API_KEY&cmd=dns-remove_record&record=$fulldomain&type=TXT&value=$txtvalue" + if ! submit "$querystring"; then + return 1 + fi + + return 0 +} + +#################### Private functions below ################################## + +#send the command to the api endpoint. +submit() { + querystring=$1 + + url="$DH_API_ENDPOINT?$querystring" + + _debug url "$url" + + if ! response="$(_get "$url")"; then + _err "Error <$1>" + return 1 + fi + + if [ -z "$2" ]; then + message="$(echo "$response" | _egrep_o "\"Message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")" + if [ -n "$message" ]; then + _err "$message" + return 1 + fi + fi + + _debug response "$response" + + return 0 +} + +#check that we have a valid API Key +validate() { + fulldomain=$1 + txtvalue=$2 + + _info "Using dreamhost" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + #retrieve the API key from the environment variable if it exists, otherwise look for a saved key. + DH_API_KEY="${DH_API_KEY:-$(_readaccountconf_mutable DH_API_KEY)}" + + if [ -z "$DH_API_KEY" ]; then + DH_API_KEY="" + _err "You didn't specify the DreamHost api key yet (export DH_API_KEY=\"\")" + _err "Please login to your control panel, create a key and try again." + return 1 + fi + + #save the api key to the account conf file. + _saveaccountconf_mutable DH_API_KEY "$DH_API_KEY" +} diff --git a/letsencrypt/dnsapi/dns_duckdns.sh b/letsencrypt/dnsapi/dns_duckdns.sh new file mode 100755 index 00000000..a9ee9c05 --- /dev/null +++ b/letsencrypt/dnsapi/dns_duckdns.sh @@ -0,0 +1,132 @@ +#!/bin/bash + +#Created by RaidenII, to use DuckDNS's API to add/remove text records +#06/27/2017 + +# Pass credentials before "acme.sh --issue --dns dns_duckdns ..." +# -- +# export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" +# -- +# +# Due to the fact that DuckDNS uses StartSSL as cert provider, --insecure may need to be used with acme.sh + +DuckDNS_API="https://www.duckdns.org/update" + +######## Public functions ##################### + +#Usage: dns_duckdns_add _acme-challenge.domain.duckdns.org "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_duckdns_add() { + fulldomain=$1 + txtvalue=$2 + + DuckDNS_Token="${DuckDNS_Token:-$(_readaccountconf_mutable DuckDNS_Token)}" + if [ -z "$DuckDNS_Token" ]; then + _err "You must export variable: DuckDNS_Token" + _err "The token for your DuckDNS account is necessary." + _err "You can look it up in your DuckDNS account." + return 1 + fi + + # Now save the credentials. + _saveaccountconf_mutable DuckDNS_Token "$DuckDNS_Token" + + # Unfortunately, DuckDNS does not seems to support lookup domain through API + # So I assume your credentials (which are your domain and token) are correct + # If something goes wrong, we will get a KO response from DuckDNS + + if ! _duckdns_get_domain; then + return 1 + fi + + # Now add the TXT record to DuckDNS + _info "Trying to add TXT record" + if _duckdns_rest GET "domains=$_duckdns_domain&token=$DuckDNS_Token&txt=$txtvalue"; then + if [ "$response" = "OK" ]; then + _info "TXT record has been successfully added to your DuckDNS domain." + _info "Note that all subdomains under this domain uses the same TXT record." + return 0 + else + _err "Errors happened during adding the TXT record, response=$response" + return 1 + fi + else + _err "Errors happened during adding the TXT record." + return 1 + fi +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_duckdns_rm() { + fulldomain=$1 + txtvalue=$2 + + DuckDNS_Token="${DuckDNS_Token:-$(_readaccountconf_mutable DuckDNS_Token)}" + if [ -z "$DuckDNS_Token" ]; then + _err "You must export variable: DuckDNS_Token" + _err "The token for your DuckDNS account is necessary." + _err "You can look it up in your DuckDNS account." + return 1 + fi + + if ! _duckdns_get_domain; then + return 1 + fi + + # Now remove the TXT record from DuckDNS + _info "Trying to remove TXT record" + if _duckdns_rest GET "domains=$_duckdns_domain&token=$DuckDNS_Token&txt=&clear=true"; then + if [ "$response" = "OK" ]; then + _info "TXT record has been successfully removed from your DuckDNS domain." + return 0 + else + _err "Errors happened during removing the TXT record, response=$response" + return 1 + fi + else + _err "Errors happened during removing the TXT record." + return 1 + fi +} + +#################### Private functions below ################################## + +# fulldomain may be 'domain.duckdns.org' (if using --domain-alias) or '_acme-challenge.domain.duckdns.org' +# either way, return 'domain'. (duckdns does not allow further subdomains and restricts domains to [a-z0-9-].) +_duckdns_get_domain() { + + # We'll extract the domain/username from full domain + _duckdns_domain="$(printf "%s" "$fulldomain" | _lower_case | _egrep_o '^(_acme-challenge\.)?[a-z0-9-]*\.duckdns\.org' | sed 's/^\(_acme-challenge\.\)\?\([a-z0-9-]*\)\.duckdns\.org/\2/')" + + if [ -z "$_duckdns_domain" ]; then + _err "Error extracting the domain." + return 1 + fi + + return 0 +} + +#Usage: method URI +_duckdns_rest() { + method=$1 + param="$2" + _debug param "$param" + url="$DuckDNS_API?$param" + if [ "$DEBUG" -gt 0 ]; then + url="$url&verbose=true" + fi + _debug url "$url" + + # DuckDNS uses GET to update domain info + if [ "$method" = "GET" ]; then + response="$(_get "$url")" + _debug2 response "$response" + if [ "$DEBUG" -gt 0 ] && _contains "$response" "UPDATED" && _contains "$response" "OK"; then + response="OK" + fi + else + _err "Unsupported method" + return 1 + fi + return 0 +} diff --git a/letsencrypt/dnsapi/dns_durabledns.sh b/letsencrypt/dnsapi/dns_durabledns.sh new file mode 100644 index 00000000..bc9f989c --- /dev/null +++ b/letsencrypt/dnsapi/dns_durabledns.sh @@ -0,0 +1,176 @@ +#!/bin/bash + +#DD_API_User="xxxxx" +#DD_API_Key="xxxxxx" + +_DD_BASE="https://durabledns.com/services/dns" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_durabledns_add() { + fulldomain=$1 + txtvalue=$2 + + DD_API_User="${DD_API_User:-$(_readaccountconf_mutable DD_API_User)}" + DD_API_Key="${DD_API_Key:-$(_readaccountconf_mutable DD_API_Key)}" + if [ -z "$DD_API_User" ] || [ -z "$DD_API_Key" ]; then + DD_API_User="" + DD_API_Key="" + _err "You didn't specify a durabledns api user or key yet." + _err "You can get yours from here https://durabledns.com/dashboard/index.php" + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable DD_API_User "$DD_API_User" + _saveaccountconf_mutable DD_API_Key "$DD_API_Key" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _dd_soap createRecord string zonename "$_domain." string name "$_sub_domain" string type "TXT" string data "$txtvalue" int aux 0 int ttl 10 string ddns_enabled N + _contains "$response" "createRecordResponse" +} + +dns_durabledns_rm() { + fulldomain=$1 + txtvalue=$2 + + DD_API_User="${DD_API_User:-$(_readaccountconf_mutable DD_API_User)}" + DD_API_Key="${DD_API_Key:-$(_readaccountconf_mutable DD_API_Key)}" + if [ -z "$DD_API_User" ] || [ -z "$DD_API_Key" ]; then + DD_API_User="" + DD_API_Key="" + _err "You didn't specify a durabledns api user or key yet." + _err "You can get yours from here https://durabledns.com/dashboard/index.php" + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Find record id" + if ! _dd_soap listRecords string zonename "$_domain."; then + _err "can not listRecords" + return 1 + fi + + subtxt="$(echo "$txtvalue" | cut -c 1-30)" + record="$(echo "$response" | sed 's//#/g' | tr '#' '\n' | grep ">$subtxt")" + _debug record "$record" + if [ -z "$record" ]; then + _err "can not find record for txtvalue" "$txtvalue" + _err "$response" + return 1 + fi + + recordid="$(echo "$record" | _egrep_o '[0-9]*' | cut -d '>' -f 2 | cut -d '<' -f 1)" + _debug recordid "$recordid" + if [ -z "$recordid" ]; then + _err "can not find record id" + return 1 + fi + + if ! _dd_soap deleteRecord string zonename "$_domain." int id "$recordid"; then + _err "delete error" + return 1 + fi + + _contains "$response" "Success" +} + +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain=$1 + if ! _dd_soap "listZones"; then + return 1 + fi + + i=1 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" ">$h."; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 + +} + +#method +_dd_soap() { + _method="$1" + shift + _urn="${_method}wsdl" + # put the parameters to xml + body=" + $DD_API_User + $DD_API_Key + " + while [ "$1" ]; do + _t="$1" + shift + _k="$1" + shift + _v="$1" + shift + body="$body<$_k xsi:type=\"xsd:$_t\">$_v" + done + body="$body" + _debug2 "SOAP request ${body}" + + # build SOAP XML + _xml=' + + '"$body"' +' + + _debug2 _xml "$_xml" + # set SOAP headers + _action="SOAPAction: \"urn:$_urn#$_method\"" + _debug2 "_action" "$_action" + export _H1="$_action" + export _H2="Content-Type: text/xml; charset=utf-8" + + _url="$_DD_BASE/$_method.php" + _debug "_url" "$_url" + if ! response="$(_post "${_xml}" "${_url}")"; then + _err "Error <$1>" + return 1 + fi + _debug2 "response" "$response" + response="$(echo "$response" | tr -d "\r\n" | _egrep_o ":${_method}Response .*:${_method}Response><")" + _debug2 "response" "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_dyn.sh b/letsencrypt/dnsapi/dns_dyn.sh new file mode 100644 index 00000000..6c6a6aa8 --- /dev/null +++ b/letsencrypt/dnsapi/dns_dyn.sh @@ -0,0 +1,339 @@ +#!/bin/bash +# +# Dyn.com Domain API +# +# Author: Gerd Naschenweng +# https://github.com/magicdude4eva +# +# Dyn Managed DNS API +# https://help.dyn.com/dns-api-knowledge-base/ +# +# It is recommended to add a "Dyn Managed DNS" user specific for API access. +# The "Zones & Records Permissions" required by this script are: +# -- +# RecordAdd +# RecordUpdate +# RecordDelete +# RecordGet +# ZoneGet +# ZoneAddNode +# ZoneRemoveNode +# ZonePublish +# -- +# +# Pass credentials before "acme.sh --issue --dns dns_dyn ..." +# -- +# export DYN_Customer="customer" +# export DYN_Username="apiuser" +# export DYN_Password="secret" +# -- + +DYN_API="https://api.dynect.net/REST" + +#REST_API +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "Challenge-code" +dns_dyn_add() { + fulldomain="$1" + txtvalue="$2" + + DYN_Customer="${DYN_Customer:-$(_readaccountconf_mutable DYN_Customer)}" + DYN_Username="${DYN_Username:-$(_readaccountconf_mutable DYN_Username)}" + DYN_Password="${DYN_Password:-$(_readaccountconf_mutable DYN_Password)}" + if [ -z "$DYN_Customer" ] || [ -z "$DYN_Username" ] || [ -z "$DYN_Password" ]; then + DYN_Customer="" + DYN_Username="" + DYN_Password="" + _err "You must export variables: DYN_Customer, DYN_Username and DYN_Password" + return 1 + fi + + #save the config variables to the account conf file. + _saveaccountconf_mutable DYN_Customer "$DYN_Customer" + _saveaccountconf_mutable DYN_Username "$DYN_Username" + _saveaccountconf_mutable DYN_Password "$DYN_Password" + + if ! _dyn_get_authtoken; then + return 1 + fi + + if [ -z "$_dyn_authtoken" ]; then + _dyn_end_session + return 1 + fi + + if ! _dyn_get_zone; then + _dyn_end_session + return 1 + fi + + if ! _dyn_add_record; then + _dyn_end_session + return 1 + fi + + if ! _dyn_publish_zone; then + _dyn_end_session + return 1 + fi + + _dyn_end_session + + return 0 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_dyn_rm() { + fulldomain="$1" + txtvalue="$2" + + DYN_Customer="${DYN_Customer:-$(_readaccountconf_mutable DYN_Customer)}" + DYN_Username="${DYN_Username:-$(_readaccountconf_mutable DYN_Username)}" + DYN_Password="${DYN_Password:-$(_readaccountconf_mutable DYN_Password)}" + if [ -z "$DYN_Customer" ] || [ -z "$DYN_Username" ] || [ -z "$DYN_Password" ]; then + DYN_Customer="" + DYN_Username="" + DYN_Password="" + _err "You must export variables: DYN_Customer, DYN_Username and DYN_Password" + return 1 + fi + + if ! _dyn_get_authtoken; then + return 1 + fi + + if [ -z "$_dyn_authtoken" ]; then + _dyn_end_session + return 1 + fi + + if ! _dyn_get_zone; then + _dyn_end_session + return 1 + fi + + if ! _dyn_get_record_id; then + _dyn_end_session + return 1 + fi + + if [ -z "$_dyn_record_id" ]; then + _dyn_end_session + return 1 + fi + + if ! _dyn_rm_record; then + _dyn_end_session + return 1 + fi + + if ! _dyn_publish_zone; then + _dyn_end_session + return 1 + fi + + _dyn_end_session + + return 0 +} + +#################### Private functions below ################################## + +#get Auth-Token +_dyn_get_authtoken() { + + _info "Start Dyn API Session" + + data="{\"customer_name\":\"$DYN_Customer\", \"user_name\":\"$DYN_Username\", \"password\":\"$DYN_Password\"}" + dyn_url="$DYN_API/Session/" + method="POST" + + _debug data "$data" + _debug dyn_url "$dyn_url" + + export _H1="Content-Type: application/json" + + response="$(_post "$data" "$dyn_url" "" "$method")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _dyn_authtoken="$(printf "%s\n" "$response" | _egrep_o '"token" *: *"[^"]*' | _head_n 1 | sed 's#^"token" *: *"##')" + _info "Token received" + _debug _dyn_authtoken "$_dyn_authtoken" + return 0 + fi + + _dyn_authtoken="" + _err "get token failed" + return 1 +} + +#fulldomain=_acme-challenge.www.domain.com +#returns +# _dyn_zone=domain.com +_dyn_get_zone() { + i=2 + while true; do + domain="$(printf "%s" "$fulldomain" | cut -d . -f "$i-100")" + if [ -z "$domain" ]; then + break + fi + + dyn_url="$DYN_API/Zone/$domain/" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_get "$dyn_url" "" "")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" + + _debug dyn_url "$dyn_url" + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _dyn_zone="$domain" + return 0 + fi + i=$(_math "$i" + 1) + done + + _dyn_zone="" + _err "get zone failed" + return 1 +} + +#add TXT record +_dyn_add_record() { + + _info "Adding TXT record" + + data="{\"rdata\":{\"txtdata\":\"$txtvalue\"},\"ttl\":\"300\"}" + dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/" + method="POST" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_post "$data" "$dyn_url" "" "$method")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _info "TXT Record successfully added" + return 0 + fi + + _err "add TXT record failed" + return 1 +} + +#publish the zone +_dyn_publish_zone() { + + _info "Publishing zone" + + data="{\"publish\":\"true\"}" + dyn_url="$DYN_API/Zone/$_dyn_zone/" + method="PUT" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_post "$data" "$dyn_url" "" "$method")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _info "Zone published" + return 0 + fi + + _err "publish zone failed" + return 1 +} + +#get record_id of TXT record so we can delete the record +_dyn_get_record_id() { + + _info "Getting record_id of TXT record" + + dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_get "$dyn_url" "" "")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _dyn_record_id="$(printf "%s\n" "$response" | _egrep_o "\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/[^\"]*" | _head_n 1 | sed "s#^\"data\" *: *\[\"/REST/TXTRecord/$_dyn_zone/$fulldomain/##")" + _debug _dyn_record_id "$_dyn_record_id" + return 0 + fi + + _dyn_record_id="" + _err "getting record_id failed" + return 1 +} + +#delete TXT record +_dyn_rm_record() { + + _info "Deleting TXT record" + + dyn_url="$DYN_API/TXTRecord/$_dyn_zone/$fulldomain/$_dyn_record_id/" + method="DELETE" + + _debug dyn_url "$dyn_url" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_post "" "$dyn_url" "" "$method")" + sessionstatus="$(printf "%s\n" "$response" | _egrep_o '"status" *: *"[^"]*' | _head_n 1 | sed 's#^"status" *: *"##')" + + _debug response "$response" + _debug sessionstatus "$sessionstatus" + + if [ "$sessionstatus" = "success" ]; then + _info "TXT record successfully deleted" + return 0 + fi + + _err "delete TXT record failed" + return 1 +} + +#logout +_dyn_end_session() { + + _info "End Dyn API Session" + + dyn_url="$DYN_API/Session/" + method="DELETE" + + _debug dyn_url "$dyn_url" + + export _H1="Auth-Token: $_dyn_authtoken" + export _H2="Content-Type: application/json" + + response="$(_post "" "$dyn_url" "" "$method")" + + _debug response "$response" + + _dyn_authtoken="" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_dynu.sh b/letsencrypt/dnsapi/dns_dynu.sh new file mode 100644 index 00000000..2189e35b --- /dev/null +++ b/letsencrypt/dnsapi/dns_dynu.sh @@ -0,0 +1,232 @@ +#!/bin/bash + +#Client ID +#Dynu_ClientId="0b71cae7-a099-4f6b-8ddf-94571cdb760d" +# +#Secret +#Dynu_Secret="aCUEY4BDCV45KI8CSIC3sp2LKQ9" +# +#Token +Dynu_Token="" +# +#Endpoint +Dynu_EndPoint="https://api.dynu.com/v2" +# +#Author: Dynu Systems, Inc. +#Report Bugs here: https://github.com/shar0119/acme.sh +# +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_dynu_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$Dynu_ClientId" ] || [ -z "$Dynu_Secret" ]; then + Dynu_ClientId="" + Dynu_Secret="" + _err "Dynu client id and secret is not specified." + _err "Please create you API client id and secret and try again." + return 1 + fi + + #save the client id and secret to the account conf file. + _saveaccountconf Dynu_ClientId "$Dynu_ClientId" + _saveaccountconf Dynu_Secret "$Dynu_Secret" + + if [ -z "$Dynu_Token" ]; then + _info "Getting Dynu token." + if ! _dynu_authentication; then + _err "Can not get token." + fi + fi + + _debug "Detect root zone" + if ! _get_root "$fulldomain"; then + _err "Invalid domain." + return 1 + fi + + _debug _node "$_node" + _debug _domain_name "$_domain_name" + + _info "Creating TXT record." + if ! _dynu_rest POST "dns/$dnsId/record" "{\"domainId\":\"$dnsId\",\"nodeName\":\"$_node\",\"recordType\":\"TXT\",\"textData\":\"$txtvalue\",\"state\":true,\"ttl\":90}"; then + return 1 + fi + + if ! _contains "$response" "200"; then + _err "Could not add TXT record." + return 1 + fi + + return 0 +} + +#Usage: rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_dynu_rm() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$Dynu_ClientId" ] || [ -z "$Dynu_Secret" ]; then + Dynu_ClientId="" + Dynu_Secret="" + _err "Dynu client id and secret is not specified." + _err "Please create you API client id and secret and try again." + return 1 + fi + + #save the client id and secret to the account conf file. + _saveaccountconf Dynu_ClientId "$Dynu_ClientId" + _saveaccountconf Dynu_Secret "$Dynu_Secret" + + if [ -z "$Dynu_Token" ]; then + _info "Getting Dynu token." + if ! _dynu_authentication; then + _err "Can not get token." + fi + fi + + _debug "Detect root zone." + if ! _get_root "$fulldomain"; then + _err "Invalid domain." + return 1 + fi + + _debug _node "$_node" + _debug _domain_name "$_domain_name" + + _info "Checking for TXT record." + if ! _get_recordid "$fulldomain" "$txtvalue"; then + _err "Could not get TXT record id." + return 1 + fi + + if [ "$_dns_record_id" = "" ]; then + _err "TXT record not found." + return 1 + fi + + _info "Removing TXT record." + if ! _delete_txt_record "$_dns_record_id"; then + _err "Could not remove TXT record $_dns_record_id." + fi + + return 0 +} + +######## Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _node=_acme-challenge.www +# _domain_name=domain.com +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _dynu_rest GET "dns/getroot/$h"; then + return 1 + fi + + if _contains "$response" "\"domainName\":\"$h\"" >/dev/null; then + dnsId=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 2 | cut -d : -f 2) + _domain_name=$h + _node=$(printf "%s" "$domain" | cut -d . -f 1-$p) + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 + +} + +_get_recordid() { + fulldomain=$1 + txtvalue=$2 + + if ! _dynu_rest GET "dns/$dnsId/record"; then + return 1 + fi + + if ! _contains "$response" "$txtvalue"; then + _dns_record_id=0 + return 0 + fi + + _dns_record_id=$(printf "%s" "$response" | sed -e 's/[^{]*\({[^}]*}\)[^{]*/\1\n/g' | grep "\"textData\":\"$txtvalue\"" | sed -e 's/.*"id":\([^,]*\).*/\1/') + return 0 +} + +_delete_txt_record() { + _dns_record_id=$1 + + if ! _dynu_rest DELETE "dns/$dnsId/record/$_dns_record_id"; then + return 1 + fi + + if ! _contains "$response" "200"; then + return 1 + fi + + return 0 +} + +_dynu_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Authorization: Bearer $Dynu_Token" + export _H2="Content-Type: application/json" + + if [ "$data" ] || [ "$m" = "DELETE" ]; then + _debug data "$data" + response="$(_post "$data" "$Dynu_EndPoint/$ep" "" "$m")" + else + _info "Getting $Dynu_EndPoint/$ep" + response="$(_get "$Dynu_EndPoint/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} + +_dynu_authentication() { + realm="$(printf "%s" "$Dynu_ClientId:$Dynu_Secret" | _base64)" + + export _H1="Authorization: Basic $realm" + export _H2="Content-Type: application/json" + + response="$(_get "$Dynu_EndPoint/oauth2/token")" + if [ "$?" != "0" ]; then + _err "Authentication failed." + return 1 + fi + if _contains "$response" "Authentication Exception"; then + _err "Authentication failed." + return 1 + fi + if _contains "$response" "access_token"; then + Dynu_Token=$(printf "%s" "$response" | tr -d "{}" | cut -d , -f 1 | cut -d : -f 2 | cut -d '"' -f 2) + fi + if _contains "$Dynu_Token" "null"; then + Dynu_Token="" + fi + + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_dynv6.sh b/letsencrypt/dnsapi/dns_dynv6.sh new file mode 100644 index 00000000..e89dad77 --- /dev/null +++ b/letsencrypt/dnsapi/dns_dynv6.sh @@ -0,0 +1,285 @@ +#!/bin/bash +#Author StefanAbl +#Usage specify a private keyfile to use with dynv6 'export KEY="path/to/keyfile"' +#or use the HTTP REST API by by specifying a token 'export DYNV6_TOKEN="value" +#if no keyfile is specified, you will be asked if you want to create one in /home/$USER/.ssh/dynv6 and /home/$USER/.ssh/dynv6.pub + +dynv6_api="https://dynv6.com/api/v2" +######## Public functions ##################### +# Please Read this guide first: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide +#Usage: dns_dynv6_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_dynv6_add() { + fulldomain=$1 + txtvalue=$2 + _info "Using dynv6 api" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + _get_authentication + if [ "$dynv6_token" ]; then + _dns_dynv6_add_http + return $? + else + _info "using key file $dynv6_keyfile" + _your_hosts="$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts)" + if ! _get_domain "$fulldomain" "$_your_hosts"; then + _err "Host not found on your account" + return 1 + fi + _debug "found host on your account" + returnval="$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts \""$_host"\" records set \""$_record"\" txt data \""$txtvalue"\")" + _debug "Dynv6 returned this after record was added: $returnval" + if _contains "$returnval" "created"; then + return 0 + elif _contains "$returnval" "updated"; then + return 0 + else + _err "Something went wrong! it does not seem like the record was added successfully" + return 1 + fi + return 1 + fi + return 1 +} +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_dynv6_rm() { + fulldomain=$1 + txtvalue=$2 + _info "Using dynv6 API" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + _get_authentication + if [ "$dynv6_token" ]; then + _dns_dynv6_rm_http + return $? + else + _info "using key file $dynv6_keyfile" + _your_hosts="$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts)" + if ! _get_domain "$fulldomain" "$_your_hosts"; then + _err "Host not found on your account" + return 1 + fi + _debug "found host on your account" + _info "$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts "\"$_host\"" records del "\"$_record\"" txt)" + return 0 + fi +} +#################### Private functions below ################################## +#Usage: No Input required +#returns +#dynv6_keyfile the path to the new key file that has been generated +_generate_new_key() { + dynv6_keyfile="$(eval echo ~"$USER")/.ssh/dynv6" + _info "Path to key file used: $dynv6_keyfile" + if [ ! -f "$dynv6_keyfile" ] && [ ! -f "$dynv6_keyfile.pub" ]; then + _debug "generating key in $dynv6_keyfile and $dynv6_keyfile.pub" + ssh-keygen -f "$dynv6_keyfile" -t ssh-ed25519 -N '' + else + _err "There is already a file in $dynv6_keyfile or $dynv6_keyfile.pub" + return 1 + fi +} + +#Usage: _acme-challenge.www.example.dynv6.net "$_your_hosts" +#where _your_hosts is the output of ssh -i ~/.ssh/dynv6.pub api@dynv6.com hosts +#returns +#_host= example.dynv6.net +#_record=_acme-challenge.www +#aborts if not a valid domain +_get_domain() { + #_your_hosts="$(ssh -i ~/.ssh/dynv6.pub api@dynv6.com hosts)" + _full_domain="$1" + _your_hosts="$2" + + _your_hosts="$(echo "$_your_hosts" | awk '/\./ {print $1}')" + for l in $_your_hosts; do + #echo "host: $l" + if test "${_full_domain#*$l}" != "$_full_domain"; then + _record="${_full_domain%.$l}" + _host=$l + _debug "The host is $_host and the record $_record" + return 0 + fi + done + _err "Either their is no such host on your dnyv6 account or it cannot be accessed with this key" + return 1 +} + +# Usage: No input required +#returns +#dynv6_keyfile path to the key that will be used +_get_authentication() { + dynv6_token="${DYNV6_TOKEN:-$(_readaccountconf_mutable dynv6_token)}" + if [ "$dynv6_token" ]; then + _debug "Found HTTP Token. Going to use the HTTP API and not the SSH API" + if [ "$DYNV6_TOKEN" ]; then + _saveaccountconf_mutable dynv6_token "$dynv6_token" + fi + else + _debug "no HTTP token found. Looking for an SSH key" + dynv6_keyfile="${dynv6_keyfile:-$(_readaccountconf_mutable dynv6_keyfile)}" + _debug "Your key is $dynv6_keyfile" + if [ -z "$dynv6_keyfile" ]; then + if [ -z "$KEY" ]; then + _err "You did not specify a key to use with dynv6" + _info "Creating new dynv6 API key to add to dynv6.com" + _generate_new_key + _info "Please add this key to dynv6.com $(cat "$dynv6_keyfile.pub")" + _info "Hit Enter to continue" + read -r _ + #save the credentials to the account conf file. + else + dynv6_keyfile="$KEY" + fi + _saveaccountconf_mutable dynv6_keyfile "$dynv6_keyfile" + fi + fi +} + +_dns_dynv6_add_http() { + _debug "Got HTTP token form _get_authentication method. Going to use the HTTP API" + if ! _get_zone_id "$fulldomain"; then + _err "Could not find a matching zone for $fulldomain. Maybe your HTTP Token is not authorized to access the zone" + return 1 + fi + _get_zone_name "$_zone_id" + record="${fulldomain%%.$_zone_name}" + _set_record TXT "$record" "$txtvalue" + if _contains "$response" "$txtvalue"; then + _info "Successfully added record" + return 0 + else + _err "Something went wrong while adding the record" + return 1 + fi +} + +_dns_dynv6_rm_http() { + _debug "Got HTTP token form _get_authentication method. Going to use the HTTP API" + if ! _get_zone_id "$fulldomain"; then + _err "Could not find a matching zone for $fulldomain. Maybe your HTTP Token is not authorized to access the zone" + return 1 + fi + _get_zone_name "$_zone_id" + record="${fulldomain%%.$_zone_name}" + _get_record_id "$_zone_id" "$record" "$txtvalue" + _del_record "$_zone_id" "$_record_id" + if [ -z "$response" ]; then + _info "Successfully deleted record" + return 0 + else + _err "Something went wrong while deleting the record" + return 1 + fi +} + +#get the zoneid for a specifc record or zone +#usage: _get_zone_id §record +#where $record is the record to get the id for +#returns _zone_id the id of the zone +_get_zone_id() { + record="$1" + _debug "getting zone id for $record" + _dynv6_rest GET zones + + zones="$(echo "$response" | tr '}' '\n' | tr ',' '\n' | grep name | sed 's/\[//g' | tr -d '{' | tr -d '"')" + #echo $zones + + selected="" + for z in $zones; do + z="${z#name:}" + _debug zone: "$z" + if _contains "$record" "$z"; then + _debug "$z found in $record" + selected="$z" + fi + done + if [ -z "$selected" ]; then + _err "no zone found" + return 1 + fi + + zone_id="$(echo "$response" | tr '}' '\n' | grep "$selected" | tr ',' '\n' | grep id | tr -d '"')" + _zone_id="${zone_id#id:}" + _debug "zone id: $_zone_id" +} + +_get_zone_name() { + _zone_id="$1" + _dynv6_rest GET zones/"$_zone_id" + _zone_name="$(echo "$response" | tr ',' '\n' | tr -d '{' | grep name | tr -d '"')" + _zone_name="${_zone_name#name:}" +} + +#usaage _get_record_id $zone_id $record +# where zone_id is thevalue returned by _get_zone_id +# and record ist in the form _acme.www for an fqdn of _acme.www.example.com +# returns _record_id +_get_record_id() { + _zone_id="$1" + record="$2" + value="$3" + _dynv6_rest GET "zones/$_zone_id/records" + if ! _get_record_id_from_response "$response"; then + _err "no such record $record found in zone $_zone_id" + return 1 + fi +} + +_get_record_id_from_response() { + response="$1" + _record_id="$(echo "$response" | tr '}' '\n' | grep "\"name\":\"$record\"" | grep "\"data\":\"$value\"" | tr ',' '\n' | grep id | tr -d '"' | tr -d 'id:')" + #_record_id="${_record_id#id:}" + if [ -z "$_record_id" ]; then + _err "no such record: $record found in zone $_zone_id" + return 1 + fi + _debug "record id: $_record_id" + return 0 +} +#usage: _set_record TXT _acme_challenge.www longvalue 12345678 +#zone id is optional can also be set as vairable bevor calling this method +_set_record() { + type="$1" + record="$2" + value="$3" + if [ "$4" ]; then + _zone_id="$4" + fi + data="{\"name\": \"$record\", \"data\": \"$value\", \"type\": \"$type\"}" + #data='{ "name": "acme.test.thorn.dynv6.net", "type": "A", "data": "192.168.0.1"}' + echo "$data" + #"{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}" + _dynv6_rest POST "zones/$_zone_id/records" "$data" +} +_del_record() { + _zone_id=$1 + _record_id=$2 + _dynv6_rest DELETE zones/"$_zone_id"/records/"$_record_id" +} + +_dynv6_rest() { + m=$1 #method GET,POST,DELETE or PUT + ep="$2" #the endpoint + data="$3" + _debug "$ep" + + token_trimmed=$(echo "$dynv6_token" | tr -d '"') + + export _H1="Authorization: Bearer $token_trimmed" + export _H2="Content-Type: application/json" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$dynv6_api/$ep" "" "$m")" + else + response="$(_get "$dynv6_api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_easydns.sh b/letsencrypt/dnsapi/dns_easydns.sh new file mode 100644 index 00000000..7cc18011 --- /dev/null +++ b/letsencrypt/dnsapi/dns_easydns.sh @@ -0,0 +1,171 @@ +#!/bin/bash + +####################################################### +# +# easyDNS REST API for acme.sh by Neilpang based on dns_cf.sh +# +# API Documentation: https://sandbox.rest.easydns.net:3001/ +# +# Author: wurzelpanzer [wurzelpanzer@maximolider.net] +# Report Bugs here: https://github.com/acmesh-official/acme.sh/issues/2647 +# +#################### Public functions ################# + +#EASYDNS_Key="xxxxxxxxxxxxxxxxxxxxxxxx" +#EASYDNS_Token="xxxxxxxxxxxxxxxxxxxxxxxx" +EASYDNS_Api="https://rest.easydns.net" + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_easydns_add() { + fulldomain=$1 + txtvalue=$2 + + EASYDNS_Token="${EASYDNS_Token:-$(_readaccountconf_mutable EASYDNS_Token)}" + EASYDNS_Key="${EASYDNS_Key:-$(_readaccountconf_mutable EASYDNS_Key)}" + + if [ -z "$EASYDNS_Token" ] || [ -z "$EASYDNS_Key" ]; then + _err "You didn't specify an easydns.net token or api key. Signup at https://cp.easydns.com/manage/security/api/signup.php" + return 1 + else + _saveaccountconf_mutable EASYDNS_Token "$EASYDNS_Token" + _saveaccountconf_mutable EASYDNS_Key "$EASYDNS_Key" + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _EASYDNS_rest GET "zones/records/all/${_domain}/search/${_sub_domain}" + + if ! printf "%s" "$response" | grep \"status\":200 >/dev/null; then + _err "Error" + return 1 + fi + + _info "Adding record" + if _EASYDNS_rest PUT "zones/records/add/$_domain/TXT" "{\"host\":\"$_sub_domain\",\"rdata\":\"$txtvalue\"}"; then + if _contains "$response" "\"status\":201"; then + _info "Added, OK" + return 0 + elif _contains "$response" "Record already exists"; then + _info "Already exists, OK" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + return 1 + +} + +dns_easydns_rm() { + fulldomain=$1 + txtvalue=$2 + + EASYDNS_Token="${EASYDNS_Token:-$(_readaccountconf_mutable EASYDNS_Token)}" + EASYDNS_Key="${EASYDNS_Key:-$(_readaccountconf_mutable EASYDNS_Key)}" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _EASYDNS_rest GET "zones/records/all/${_domain}/search/${_sub_domain}" + + if ! printf "%s" "$response" | grep \"status\":200 >/dev/null; then + _err "Error" + return 1 + fi + + count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Don't need to remove." + else + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) + _debug "record_id" "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if ! _EASYDNS_rest DELETE "zones/records/$_domain/$record_id"; then + _err "Delete record error." + return 1 + fi + _contains "$response" "\"status\":200" + fi + +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain=$1 + i=1 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _EASYDNS_rest GET "zones/records/all/$h"; then + return 1 + fi + + if _contains "$response" "\"status\":200"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_EASYDNS_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + basicauth=$(printf "%s" "$EASYDNS_Token":"$EASYDNS_Key" | _base64) + + export _H1="accept: application/json" + if [ "$basicauth" ]; then + export _H2="Authorization: Basic $basicauth" + fi + + if [ "$m" != "GET" ]; then + export _H3="Content-Type: application/json" + _debug data "$data" + response="$(_post "$data" "$EASYDNS_Api/$ep" "" "$m")" + else + response="$(_get "$EASYDNS_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_edgedns.sh b/letsencrypt/dnsapi/dns_edgedns.sh new file mode 100755 index 00000000..d1b1c882 --- /dev/null +++ b/letsencrypt/dnsapi/dns_edgedns.sh @@ -0,0 +1,466 @@ +#!/bin/bash + +# Akamai Edge DNS v2 API +# User must provide Open Edgegrid API credentials to the EdgeDNS installation. The remote user in EdgeDNS must have CRUD access to +# Edge DNS Zones and Recordsets, e.g. DNS—Zone Record Management authorization + +# Report bugs to https://control.akamai.com/apps/support-ui/#/contact-support + +# Values to export: +# --EITHER-- +# *** TBD. NOT IMPLEMENTED YET *** +# specify Edgegrid credentials file and section +# AKAMAI_EDGERC= +# AKAMAI_EDGERC_SECTION="default" +## --OR-- +# specify indiviual credentials +# export AKAMAI_HOST = +# export AKAMAI_ACCESS_TOKEN = +# export AKAMAI_CLIENT_TOKEN = +# export AKAMAI_CLIENT_SECRET = + +ACME_EDGEDNS_VERSION="0.1.0" + +######## Public functions ##################### + +# Usage: dns_edgedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to add txt record +# +dns_edgedns_add() { + fulldomain=$1 + txtvalue=$2 + _debug "ENTERING DNS_EDGEDNS_ADD" + _debug2 "fulldomain" "$fulldomain" + _debug2 "txtvalue" "$txtvalue" + + if ! _EDGEDNS_credentials; then + _err "$@" + return 1 + fi + if ! _EDGEDNS_getZoneInfo "$fulldomain"; then + _err "Invalid domain" + return 1 + fi + + _debug2 "Add: zone" "$zone" + acmeRecordURI=$(printf "%s/%s/names/%s/types/TXT" "$edge_endpoint" "$zone" "$fulldomain") + _debug3 "Add URL" "$acmeRecordURI" + # Get existing TXT record + _edge_result=$(_edgedns_rest GET "$acmeRecordURI") + _api_status="$?" + _debug3 "_edge_result" "$_edge_result" + if [ "$_api_status" -ne 0 ]; then + if [ "$curResult" = "FATAL" ]; then + _err "$(printf "Fatal error: acme API function call : %s" "$retVal")" + fi + if [ "$_edge_result" != "404" ]; then + _err "$(printf "Failure accessing Akamai Edge DNS API Server. Error: %s" "$_edge_result")" + return 1 + fi + fi + rdata="\"${txtvalue}\"" + record_op="POST" + if [ "$_api_status" -eq 0 ]; then + # record already exists. Get existing record data and update + record_op="PUT" + rdlist="${_edge_result#*\"rdata\":[}" + rdlist="${rdlist%%]*}" + rdlist=$(echo "$rdlist" | tr -d '"' | tr -d "\\\\") + _debug3 "existing TXT found" + _debug3 "record data" "$rdlist" + # value already there? + if _contains "$rdlist" "$txtvalue"; then + return 0 + fi + _txt_val="" + while [ "$_txt_val" != "$rdlist" ] && [ "${rdlist}" ]; do + _txt_val="${rdlist%%,*}" + rdlist="${rdlist#*,}" + rdata="${rdata},\"${_txt_val}\"" + done + fi + # Add the txtvalue TXT Record + body="{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"ttl\":600, \"rdata\":"[${rdata}]"}" + _debug3 "Add body '${body}'" + _edge_result=$(_edgedns_rest "$record_op" "$acmeRecordURI" "$body") + _api_status="$?" + if [ "$_api_status" -eq 0 ]; then + _log "$(printf "Text value %s added to recordset %s" "$txtvalue" "$fulldomain")" + return 0 + else + _err "$(printf "error adding TXT record for validation. Error: %s" "$_edge_result")" + return 1 + fi +} + +# Usage: dns_edgedns_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to delete txt record +# +dns_edgedns_rm() { + fulldomain=$1 + txtvalue=$2 + _debug "ENTERING DNS_EDGEDNS_RM" + _debug2 "fulldomain" "$fulldomain" + _debug2 "txtvalue" "$txtvalue" + + if ! _EDGEDNS_credentials; then + _err "$@" + return 1 + fi + if ! _EDGEDNS_getZoneInfo "$fulldomain"; then + _err "Invalid domain" + return 1 + fi + _debug2 "RM: zone" "${zone}" + acmeRecordURI=$(printf "%s/%s/names/%s/types/TXT" "${edge_endpoint}" "$zone" "$fulldomain") + _debug3 "RM URL" "$acmeRecordURI" + # Get existing TXT record + _edge_result=$(_edgedns_rest GET "$acmeRecordURI") + _api_status="$?" + if [ "$_api_status" -ne 0 ]; then + if [ "$curResult" = "FATAL" ]; then + _err "$(printf "Fatal error: acme API function call : %s" "$retVal")" + fi + if [ "$_edge_result" != "404" ]; then + _err "$(printf "Failure accessing Akamai Edge DNS API Server. Error: %s" "$_edge_result")" + return 1 + fi + fi + _debug3 "_edge_result" "$_edge_result" + record_op="DELETE" + body="" + if [ "$_api_status" -eq 0 ]; then + # record already exists. Get existing record data and update + rdlist="${_edge_result#*\"rdata\":[}" + rdlist="${rdlist%%]*}" + rdlist=$(echo "$rdlist" | tr -d '"' | tr -d "\\\\") + _debug3 "rdlist" "$rdlist" + if [ -n "$rdlist" ]; then + record_op="PUT" + comma="" + rdata="" + _txt_val="" + while [ "$_txt_val" != "$rdlist" ] && [ "$rdlist" ]; do + _txt_val="${rdlist%%,*}" + rdlist="${rdlist#*,}" + _debug3 "_txt_val" "$_txt_val" + _debug3 "txtvalue" "$txtvalue" + if ! _contains "$_txt_val" "$txtvalue"; then + rdata="${rdata}${comma}\"${_txt_val}\"" + comma="," + fi + done + if [ -z "$rdata" ]; then + record_op="DELETE" + else + # Recreate the txtvalue TXT Record + body="{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"ttl\":600, \"rdata\":"[${rdata}]"}" + _debug3 "body" "$body" + fi + fi + fi + _edge_result=$(_edgedns_rest "$record_op" "$acmeRecordURI" "$body") + _api_status="$?" + if [ "$_api_status" -eq 0 ]; then + _log "$(printf "Text value %s removed from recordset %s" "$txtvalue" "$fulldomain")" + return 0 + else + _err "$(printf "error removing TXT record for validation. Error: %s" "$_edge_result")" + return 1 + fi +} + +#################### Private functions below ################################## + +_EDGEDNS_credentials() { + _debug "GettingEdge DNS credentials" + _log "$(printf "ACME DNSAPI Edge DNS version %s" ${ACME_EDGEDNS_VERSION})" + args_missing=0 + if [ -z "$AKAMAI_ACCESS_TOKEN" ]; then + AKAMAI_ACCESS_TOKEN="" + AKAMAI_CLIENT_TOKEN="" + AKAMAI_HOST="" + AKAMAI_CLIENT_SECRET="" + _err "AKAMAI_ACCESS_TOKEN is missing" + args_missing=1 + fi + if [ -z "$AKAMAI_CLIENT_TOKEN" ]; then + AKAMAI_ACCESS_TOKEN="" + AKAMAI_CLIENT_TOKEN="" + AKAMAI_HOST="" + AKAMAI_CLIENT_SECRET="" + _err "AKAMAI_CLIENT_TOKEN is missing" + args_missing=1 + fi + if [ -z "$AKAMAI_HOST" ]; then + AKAMAI_ACCESS_TOKEN="" + AKAMAI_CLIENT_TOKEN="" + AKAMAI_HOST="" + AKAMAI_CLIENT_SECRET="" + _err "AKAMAI_HOST is missing" + args_missing=1 + fi + if [ -z "$AKAMAI_CLIENT_SECRET" ]; then + AKAMAI_ACCESS_TOKEN="" + AKAMAI_CLIENT_TOKEN="" + AKAMAI_HOST="" + AKAMAI_CLIENT_SECRET="" + _err "AKAMAI_CLIENT_SECRET is missing" + args_missing=1 + fi + + if [ "$args_missing" = 1 ]; then + _err "You have not properly specified the EdgeDNS Open Edgegrid API credentials. Please try again." + return 1 + else + _saveaccountconf_mutable AKAMAI_ACCESS_TOKEN "$AKAMAI_ACCESS_TOKEN" + _saveaccountconf_mutable AKAMAI_CLIENT_TOKEN "$AKAMAI_CLIENT_TOKEN" + _saveaccountconf_mutable AKAMAI_HOST "$AKAMAI_HOST" + _saveaccountconf_mutable AKAMAI_CLIENT_SECRET "$AKAMAI_CLIENT_SECRET" + # Set whether curl should use secure or insecure mode + fi + export HTTPS_INSECURE=0 # All Edgegrid API calls are secure + edge_endpoint=$(printf "https://%s/config-dns/v2/zones" "$AKAMAI_HOST") + _debug3 "Edge API Endpoint:" "$edge_endpoint" + +} + +_EDGEDNS_getZoneInfo() { + _debug "Getting Zoneinfo" + zoneEnd=false + curZone=$1 + while [ -n "$zoneEnd" ]; do + # we can strip the first part of the fulldomain, since its just the _acme-challenge string + curZone="${curZone#*.}" + # suffix . needed for zone -> domain.tld. + # create zone get url + get_zone_url=$(printf "%s/%s" "$edge_endpoint" "$curZone") + _debug3 "Zone Get: " "${get_zone_url}" + curResult=$(_edgedns_rest GET "$get_zone_url") + retVal=$? + if [ "$retVal" -ne 0 ]; then + if [ "$curResult" = "FATAL" ]; then + _err "$(printf "Fatal error: acme API function call : %s" "$retVal")" + fi + if [ "$curResult" != "404" ]; then + _err "$(printf "Managed zone validation failed. Error response: %s" "$retVal")" + return 1 + fi + fi + if _contains "$curResult" "\"zone\":"; then + _debug2 "Zone data" "${curResult}" + zone=$(echo "${curResult}" | _egrep_o "\"zone\"\\s*:\\s*\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d "\"") + _debug3 "Zone" "${zone}" + zoneEnd="" + return 0 + fi + + if [ "${curZone#*.}" != "$curZone" ]; then + _debug3 "$(printf "%s still contains a '.' - so we can check next higher level" "$curZone")" + else + zoneEnd=true + _err "Couldn't retrieve zone data." + return 1 + fi + done + _err "Failed to retrieve zone data." + return 2 +} + +_edgedns_headers="" + +_edgedns_rest() { + _debug "Handling API Request" + m=$1 + # Assume endpoint is complete path, including query args if applicable + ep=$2 + body_data=$3 + _edgedns_content_type="" + _request_url_path="$ep" + _request_body="$body_data" + _request_method="$m" + _edgedns_headers="" + tab="" + _edgedns_headers="${_edgedns_headers}${tab}Host: ${AKAMAI_HOST}" + tab="\t" + # Set in acme.sh _post/_get + #_edgedns_headers="${_edgedns_headers}${tab}User-Agent:ACME DNSAPI Edge DNS version ${ACME_EDGEDNS_VERSION}" + _edgedns_headers="${_edgedns_headers}${tab}Accept: application/json,*/*" + if [ "$m" != "GET" ] && [ "$m" != "DELETE" ]; then + _edgedns_content_type="application/json" + _debug3 "_request_body" "$_request_body" + _body_len=$(echo "$_request_body" | tr -d "\n\r" | awk '{print length}') + _edgedns_headers="${_edgedns_headers}${tab}Content-Length: ${_body_len}" + fi + _edgedns_make_auth_header + _edgedns_headers="${_edgedns_headers}${tab}Authorization: ${_signed_auth_header}" + _secure_debug2 "Made Auth Header" "$_signed_auth_header" + hdr_indx=1 + work_header="${_edgedns_headers}${tab}" + _debug3 "work_header" "$work_header" + while [ "$work_header" ]; do + entry="${work_header%%\\t*}" + work_header="${work_header#*\\t}" + export "$(printf "_H%s=%s" "$hdr_indx" "$entry")" + _debug2 "Request Header " "$entry" + hdr_indx=$((hdr_indx + 1)) + done + + # clear headers from previous request to avoid getting wrong http code on timeouts + : >"$HTTP_HEADER" + _debug2 "$ep" + if [ "$m" != "GET" ]; then + _debug3 "Method data" "$data" + # body url [needbase64] [POST|PUT|DELETE] [ContentType] + response=$(_post "$_request_body" "$ep" false "$m" "$_edgedns_content_type") + else + response=$(_get "$ep") + fi + _ret="$?" + if [ "$_ret" -ne 0 ]; then + _err "$(printf "acme.sh API function call failed. Error: %s" "$_ret")" + echo "FATAL" + return "$_ret" + fi + _debug2 "response" "${response}" + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" + _debug2 "http response code" "$_code" + if [ "$_code" = "200" ] || [ "$_code" = "201" ]; then + # All good + response="$(echo "${response}" | _normalizeJson)" + echo "$response" + return 0 + fi + + if [ "$_code" = "204" ]; then + # Success, no body + echo "$_code" + return 0 + fi + + if [ "$_code" = "400" ]; then + _err "Bad request presented" + _log "$(printf "Headers: %s" "$_edgedns_headers")" + _log "$(printf "Method: %s" "$_request_method")" + _log "$(printf "URL: %s" "$ep")" + _log "$(printf "Data: %s" "$data")" + fi + + if [ "$_code" = "403" ]; then + _err "access denied make sure your Edgegrid cedentials are correct." + fi + + echo "$_code" + return 1 +} + +_edgedns_eg_timestamp() { + _debug "Generating signature Timestamp" + _debug3 "Retriving ntp time" + _timeheaders="$(_get "https://www.ntp.org" "onlyheader")" + _debug3 "_timeheaders" "$_timeheaders" + _ntpdate="$(echo "$_timeheaders" | grep -i "Date:" | _head_n 1 | cut -d ':' -f 2- | tr -d "\r\n")" + _debug3 "_ntpdate" "$_ntpdate" + _ntpdate="$(echo "${_ntpdate}" | sed -e 's/^[[:space:]]*//')" + _debug3 "_NTPDATE" "$_ntpdate" + _ntptime="$(echo "${_ntpdate}" | _head_n 1 | cut -d " " -f 5 | tr -d "\r\n")" + _debug3 "_ntptime" "$_ntptime" + _eg_timestamp=$(date -u "+%Y%m%dT") + _eg_timestamp="$(printf "%s%s+0000" "$_eg_timestamp" "$_ntptime")" + _debug "_eg_timestamp" "$_eg_timestamp" +} + +_edgedns_new_nonce() { + _debug "Generating Nonce" + _nonce=$(echo "EDGEDNS$(_time)" | _digest sha1 hex | cut -c 1-32) + _debug3 "_nonce" "$_nonce" +} + +_edgedns_make_auth_header() { + _debug "Constructing Auth Header" + _edgedns_new_nonce + _edgedns_eg_timestamp + # "Unsigned authorization header: 'EG1-HMAC-SHA256 client_token=block;access_token=block;timestamp=20200806T14:16:33+0000;nonce=72cde72c-82d9-4721-9854-2ba057929d67;'" + _auth_header="$(printf "EG1-HMAC-SHA256 client_token=%s;access_token=%s;timestamp=%s;nonce=%s;" "$AKAMAI_CLIENT_TOKEN" "$AKAMAI_ACCESS_TOKEN" "$_eg_timestamp" "$_nonce")" + _secure_debug2 "Unsigned Auth Header: " "$_auth_header" + + _edgedns_sign_request + _signed_auth_header="$(printf "%ssignature=%s" "$_auth_header" "$_signed_req")" + _secure_debug2 "Signed Auth Header: " "${_signed_auth_header}" +} + +_edgedns_sign_request() { + _debug2 "Signing http request" + _edgedns_make_data_to_sign "$_auth_header" + _secure_debug2 "Returned signed data" "$_mdata" + _edgedns_make_signing_key "$_eg_timestamp" + _edgedns_base64_hmac_sha256 "$_mdata" "$_signing_key" + _signed_req="$_hmac_out" + _secure_debug2 "Signed Request" "$_signed_req" +} + +_edgedns_make_signing_key() { + _debug2 "Creating sigining key" + ts=$1 + _edgedns_base64_hmac_sha256 "$ts" "$AKAMAI_CLIENT_SECRET" + _signing_key="$_hmac_out" + _secure_debug2 "Signing Key" "$_signing_key" + +} + +_edgedns_make_data_to_sign() { + _debug2 "Processing data to sign" + hdr=$1 + _secure_debug2 "hdr" "$hdr" + _edgedns_make_content_hash + path="$(echo "$_request_url_path" | tr -d "\n\r" | sed 's/https\?:\/\///')" + path="${path#*$AKAMAI_HOST}" + _debug "hier path" "$path" + # dont expose headers to sign so use MT string + _mdata="$(printf "%s\thttps\t%s\t%s\t%s\t%s\t%s" "$_request_method" "$AKAMAI_HOST" "$path" "" "$_hash" "$hdr")" + _secure_debug2 "Data to Sign" "$_mdata" +} + +_edgedns_make_content_hash() { + _debug2 "Generating content hash" + _hash="" + _debug2 "Request method" "${_request_method}" + if [ "$_request_method" != "POST" ] || [ -z "$_request_body" ]; then + return 0 + fi + _debug2 "Req body" "$_request_body" + _edgedns_base64_sha256 "$_request_body" + _hash="$_sha256_out" + _debug2 "Content hash" "$_hash" +} + +_edgedns_base64_hmac_sha256() { + _debug2 "Generating hmac" + data=$1 + key=$2 + encoded_data="$(echo "$data" | iconv -t utf-8)" + encoded_key="$(echo "$key" | iconv -t utf-8)" + _secure_debug2 "encoded data" "$encoded_data" + _secure_debug2 "encoded key" "$encoded_key" + + encoded_key_hex=$(printf "%s" "$encoded_key" | _hex_dump | tr -d ' ') + data_sig="$(echo "$encoded_data" | tr -d "\n\r" | _hmac sha256 "$encoded_key_hex" | _base64)" + + _secure_debug2 "data_sig:" "$data_sig" + _hmac_out="$(echo "$data_sig" | tr -d "\n\r" | iconv -f utf-8)" + _secure_debug2 "hmac" "$_hmac_out" +} + +_edgedns_base64_sha256() { + _debug2 "Creating sha256 digest" + trg=$1 + _secure_debug2 "digest data" "$trg" + digest="$(echo "$trg" | tr -d "\n\r" | _digest "sha256")" + _sha256_out="$(echo "$digest" | tr -d "\n\r" | iconv -f utf-8)" + _secure_debug2 "digest decode" "$_sha256_out" +} + +#_edgedns_parse_edgerc() { +# filepath=$1 +# section=$2 +#} diff --git a/letsencrypt/dnsapi/dns_euserv.sh b/letsencrypt/dnsapi/dns_euserv.sh new file mode 100644 index 00000000..03075c7f --- /dev/null +++ b/letsencrypt/dnsapi/dns_euserv.sh @@ -0,0 +1,358 @@ +#!/bin/bash + +#This is the euserv.eu api wrapper for acme.sh +# +#Author: Michael Brueckner +#Report Bugs: https://www.github.com/initit/acme.sh or mbr@initit.de + +# +#EUSERV_Username="username" +# +#EUSERV_Password="password" +# +# Dependencies: +# ------------- +# - none - + +EUSERV_Api="https://api.euserv.net" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_euserv_add() { + fulldomain="$(echo "$1" | _lower_case)" + txtvalue=$2 + + EUSERV_Username="${EUSERV_Username:-$(_readaccountconf_mutable EUSERV_Username)}" + EUSERV_Password="${EUSERV_Password:-$(_readaccountconf_mutable EUSERV_Password)}" + if [ -z "$EUSERV_Username" ] || [ -z "$EUSERV_Password" ]; then + EUSERV_Username="" + EUSERV_Password="" + _err "You don't specify euserv user and password yet." + _err "Please create your key and try again." + return 1 + fi + + #save the user and email to the account conf file. + _saveaccountconf_mutable EUSERV_Username "$EUSERV_Username" + _saveaccountconf_mutable EUSERV_Password "$EUSERV_Password" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug "_sub_domain" "$_sub_domain" + _debug "_domain" "$_domain" + _info "Adding record" + if ! _euserv_add_record "$_domain" "$_sub_domain" "$txtvalue"; then + return 1 + fi + +} + +#fulldomain txtvalue +dns_euserv_rm() { + + fulldomain="$(echo "$1" | _lower_case)" + txtvalue=$2 + + EUSERV_Username="${EUSERV_Username:-$(_readaccountconf_mutable EUSERV_Username)}" + EUSERV_Password="${EUSERV_Password:-$(_readaccountconf_mutable EUSERV_Password)}" + if [ -z "$EUSERV_Username" ] || [ -z "$EUSERV_Password" ]; then + EUSERV_Username="" + EUSERV_Password="" + _err "You don't specify euserv user and password yet." + _err "Please create your key and try again." + return 1 + fi + + #save the user and email to the account conf file. + _saveaccountconf_mutable EUSERV_Username "$EUSERV_Username" + _saveaccountconf_mutable EUSERV_Password "$EUSERV_Password" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug "_sub_domain" "$_sub_domain" + _debug "_domain" "$_domain" + + _debug "Getting txt records" + + xml_content=$(printf ' + + domain.dns_get_active_records + + + + + + login + + %s + + + + password + + %s + + + + domain_id + + %s + + + + + + + ' "$EUSERV_Username" "$EUSERV_Password" "$_euserv_domain_id") + + export _H1="Content-Type: text/xml" + response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" + + if ! _contains "$response" "status100"; then + _err "Error could not get txt records" + _debug "xml_content" "$xml_content" + _debug "response" "$response" + return 1 + fi + + if ! echo "$response" | grep '>dns_record_content<.*>'"$txtvalue"'<' >/dev/null; then + _info "Do not need to delete record" + else + # find XML block where txtvalue is in. The record_id is allways prior this line! + _endLine=$(echo "$response" | grep -n '>dns_record_content<.*>'"$txtvalue"'<' | cut -d ':' -f 1) + # record_id is the last Tag with a number before the row _endLine, identified by + _record_id=$(echo "$response" | sed -n '1,'"$_endLine"'p' | grep '' | _tail_n 1 | sed 's/.*\([0-9]*\)<\/name>.*/\1/') + _info "Deleting record" + _euserv_delete_record "$_record_id" + fi + +} + +#################### Private functions below ################################## + +_get_root() { + domain=$1 + _debug "get root" + + # Just to read the domain_orders once + + domain=$1 + i=2 + p=1 + + if ! _euserv_get_domain_orders; then + return 1 + fi + + # Get saved response with domain_orders + response="$_euserv_domain_orders" + + while true; do + h=$(echo "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "$h"; then + _sub_domain=$(echo "$domain" | cut -d . -f 1-$p) + _domain="$h" + if ! _euserv_get_domain_id "$_domain"; then + _err "invalid domain" + return 1 + fi + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + + return 1 +} + +_euserv_get_domain_orders() { + # returns: _euserv_domain_orders + + _debug "get domain_orders" + + xml_content=$(printf ' + + domain.get_domain_orders + + + + + + login + %s + + + password + %s + + + + + + ' "$EUSERV_Username" "$EUSERV_Password") + + export _H1="Content-Type: text/xml" + response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" + + if ! _contains "$response" "status100"; then + _err "Error could not get domain orders" + _debug "xml_content" "$xml_content" + _debug "response" "$response" + return 1 + fi + + # save response to reduce API calls + _euserv_domain_orders="$response" + return 0 +} + +_euserv_get_domain_id() { + # returns: _euserv_domain_id + domain=$1 + _debug "get domain_id" + + # find line where the domain name is within the $response + _startLine=$(echo "$_euserv_domain_orders" | grep -n '>domain_name<.*>'"$domain"'<' | cut -d ':' -f 1) + # next occurency of domain_id after the domain_name is the correct one + _euserv_domain_id=$(echo "$_euserv_domain_orders" | sed -n "$_startLine"',$p' | grep '>domain_id<' | _head_n 1 | sed 's/.*\([0-9]*\)<\/i4>.*/\1/') + + if [ -z "$_euserv_domain_id" ]; then + _err "Could not find domain_id for domain $domain" + _debug "_euserv_domain_orders" "$_euserv_domain_orders" + return 1 + fi + + return 0 +} + +_euserv_delete_record() { + record_id=$1 + xml_content=$(printf ' + + domain.dns_delete_record + + + + + + login + + %s + + + + password + + %s + + + + dns_record_id + + %s + + + + + + + ' "$EUSERV_Username" "$EUSERV_Password" "$record_id") + + export _H1="Content-Type: text/xml" + response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" + + if ! _contains "$response" "status100"; then + _err "Error deleting record" + _debug "xml_content" "$xml_content" + _debug "response" "$response" + return 1 + fi + + return 0 + +} + +_euserv_add_record() { + domain=$1 + sub_domain=$2 + txtval=$3 + + xml_content=$(printf ' + + domain.dns_create_record + + + + + + login + + %s + + + + password + + %s + + + domain_id + + %s + + + + dns_record_subdomain + + %s + + + + dns_record_type + + TXT + + + + dns_record_value + + %s + + + + dns_record_ttl + + 300 + + + + + + + ' "$EUSERV_Username" "$EUSERV_Password" "$_euserv_domain_id" "$sub_domain" "$txtval") + + export _H1="Content-Type: text/xml" + response="$(_post "$xml_content" "$EUSERV_Api" "" "POST")" + + if ! _contains "$response" "status100"; then + _err "Error could not create record" + _debug "xml_content" "$xml_content" + _debug "response" "$response" + return 1 + fi + + return 0 +} diff --git a/letsencrypt/dnsapi/dns_exoscale.sh b/letsencrypt/dnsapi/dns_exoscale.sh new file mode 100755 index 00000000..f600aa22 --- /dev/null +++ b/letsencrypt/dnsapi/dns_exoscale.sh @@ -0,0 +1,168 @@ +#!/bin/bash + +EXOSCALE_API=https://api.exoscale.com/dns/v1 + +######## Public functions ##################### + +# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to add txt record +dns_exoscale_add() { + fulldomain=$1 + txtvalue=$2 + + if ! _checkAuth; then + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _info "Adding record" + if _exoscale_rest POST "domains/$_domain_id/records" "{\"record\":{\"name\":\"$_sub_domain\",\"record_type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":120}}" "$_domain_token"; then + if _contains "$response" "$txtvalue"; then + _info "Added, OK" + return 0 + fi + fi + _err "Add txt record error." + return 1 + +} + +# Usage: fulldomain txtvalue +# Used to remove the txt record after validation +dns_exoscale_rm() { + fulldomain=$1 + txtvalue=$2 + + if ! _checkAuth; then + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _exoscale_rest GET "domains/${_domain_id}/records?type=TXT&name=$_sub_domain" "" "$_domain_token" + if _contains "$response" "\"name\":\"$_sub_domain\"" >/dev/null; then + _record_id=$(echo "$response" | tr '{' "\n" | grep "\"content\":\"$txtvalue\"" | _egrep_o "\"id\":[^,]+" | _head_n 1 | cut -d : -f 2 | tr -d \") + fi + + if [ -z "$_record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + + _debug "Deleting record $_record_id" + + if ! _exoscale_rest DELETE "domains/$_domain_id/records/$_record_id" "" "$_domain_token"; then + _err "Delete record error." + return 1 + fi + + return 0 +} + +#################### Private functions below ################################## + +_checkAuth() { + EXOSCALE_API_KEY="${EXOSCALE_API_KEY:-$(_readaccountconf_mutable EXOSCALE_API_KEY)}" + EXOSCALE_SECRET_KEY="${EXOSCALE_SECRET_KEY:-$(_readaccountconf_mutable EXOSCALE_SECRET_KEY)}" + + if [ -z "$EXOSCALE_API_KEY" ] || [ -z "$EXOSCALE_SECRET_KEY" ]; then + EXOSCALE_API_KEY="" + EXOSCALE_SECRET_KEY="" + _err "You don't specify Exoscale application key and application secret yet." + _err "Please create you key and try again." + return 1 + fi + + _saveaccountconf_mutable EXOSCALE_API_KEY "$EXOSCALE_API_KEY" + _saveaccountconf_mutable EXOSCALE_SECRET_KEY "$EXOSCALE_SECRET_KEY" + + return 0 +} + +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +# _domain_token=sdjkglgdfewsdfg +_get_root() { + + if ! _exoscale_rest GET "domains"; then + return 1 + fi + + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "\"name\":\"$h\"" >/dev/null; then + _domain_id=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"id\":[^,]+" | _head_n 1 | cut -d : -f 2 | tr -d \") + _domain_token=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \") + if [ "$_domain_token" ] && [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +# returns response +_exoscale_rest() { + method=$1 + path="$2" + data="$3" + token="$4" + request_url="$EXOSCALE_API/$path" + _debug "$path" + + export _H1="Accept: application/json" + + if [ "$token" ]; then + export _H2="X-DNS-Domain-Token: $token" + else + export _H2="X-DNS-Token: $EXOSCALE_API_KEY:$EXOSCALE_SECRET_KEY" + fi + + if [ "$data" ] || [ "$method" = "DELETE" ]; then + export _H3="Content-Type: application/json" + _debug data "$data" + response="$(_post "$data" "$request_url" "" "$method")" + else + response="$(_get "$request_url" "" "" "$method")" + fi + + if [ "$?" != "0" ]; then + _err "error $request_url" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_freedns.sh b/letsencrypt/dnsapi/dns_freedns.sh new file mode 100755 index 00000000..15cd01ae --- /dev/null +++ b/letsencrypt/dnsapi/dns_freedns.sh @@ -0,0 +1,371 @@ +#!/bin/bash + +#This file name is "dns_freedns.sh" +#So, here must be a method dns_freedns_add() +#Which will be called by acme.sh to add the txt record to your api system. +#returns 0 means success, otherwise error. +# +#Author: David Kerr +#Report Bugs here: https://github.com/dkerr64/acme.sh +#or here... https://github.com/acmesh-official/acme.sh/issues/2305 +# +######## Public functions ##################### + +# Export FreeDNS userid and password in following variables... +# FREEDNS_User=username +# FREEDNS_Password=password +# login cookie is saved in acme account config file so userid / pw +# need to be set only when changed. + +#Usage: dns_freedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_freedns_add() { + fulldomain="$1" + txtvalue="$2" + + _info "Add TXT record using FreeDNS" + _debug "fulldomain: $fulldomain" + _debug "txtvalue: $txtvalue" + + if [ -z "$FREEDNS_User" ] || [ -z "$FREEDNS_Password" ]; then + FREEDNS_User="" + FREEDNS_Password="" + if [ -z "$FREEDNS_COOKIE" ]; then + _err "You did not specify the FreeDNS username and password yet." + _err "Please export as FREEDNS_User / FREEDNS_Password and try again." + return 1 + fi + using_cached_cookies="true" + else + FREEDNS_COOKIE="$(_freedns_login "$FREEDNS_User" "$FREEDNS_Password")" + if [ -z "$FREEDNS_COOKIE" ]; then + return 1 + fi + using_cached_cookies="false" + fi + + _debug "FreeDNS login cookies: $FREEDNS_COOKIE (cached = $using_cached_cookies)" + + _saveaccountconf FREEDNS_COOKIE "$FREEDNS_COOKIE" + + # We may have to cycle through the domain name to find the + # TLD that we own... + i=1 + wmax="$(echo "$fulldomain" | tr '.' ' ' | wc -w)" + while [ "$i" -lt "$wmax" ]; do + # split our full domain name into two parts... + sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")" + i="$(_math "$i" + 1)" + top_domain="$(echo "$fulldomain" | cut -d. -f "$i"-100)" + _debug "sub_domain: $sub_domain" + _debug "top_domain: $top_domain" + + DNSdomainid="$(_freedns_domain_id "$top_domain")" + if [ "$?" = "0" ]; then + _info "Domain $top_domain found at FreeDNS, domain_id $DNSdomainid" + break + else + _info "Domain $top_domain not found at FreeDNS, try with next level of TLD" + fi + done + + if [ -z "$DNSdomainid" ]; then + # If domain ID is empty then something went wrong (top level + # domain not found at FreeDNS). + _err "Domain $top_domain not found at FreeDNS" + return 1 + fi + + # Add in new TXT record with the value provided + _debug "Adding TXT record for $fulldomain, $txtvalue" + _freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue" + return $? +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_freedns_rm() { + fulldomain="$1" + txtvalue="$2" + + _info "Delete TXT record using FreeDNS" + _debug "fulldomain: $fulldomain" + _debug "txtvalue: $txtvalue" + + # Need to read cookie from conf file again in case new value set + # during login to FreeDNS when TXT record was created. + FREEDNS_COOKIE="$(_readaccountconf "FREEDNS_COOKIE")" + _debug "FreeDNS login cookies: $FREEDNS_COOKIE" + + TXTdataid="$(_freedns_data_id "$fulldomain" "TXT")" + if [ "$?" != "0" ]; then + _info "Cannot delete TXT record for $fulldomain, record does not exist at FreeDNS" + return 1 + fi + _debug "Data ID's found, $TXTdataid" + + # now we have one (or more) TXT record data ID's. Load the page + # for that record and search for the record txt value. If match + # then we can delete it. + lines="$(echo "$TXTdataid" | wc -l)" + _debug "Found $lines TXT data records for $fulldomain" + i=0 + while [ "$i" -lt "$lines" ]; do + i="$(_math "$i" + 1)" + dataid="$(echo "$TXTdataid" | sed -n "${i}p")" + _debug "$dataid" + + htmlpage="$(_freedns_retrieve_data_page "$FREEDNS_COOKIE" "$dataid")" + if [ "$?" != "0" ]; then + if [ "$using_cached_cookies" = "true" ]; then + _err "Has your FreeDNS username and password changed? If so..." + _err "Please export as FREEDNS_User / FREEDNS_Password and try again." + fi + return 1 + fi + + echo "$htmlpage" | grep "value=\""$txtvalue"\"" >/dev/null + if [ "$?" = "0" ]; then + # Found a match... delete the record and return + _info "Deleting TXT record for $fulldomain, $txtvalue" + _freedns_delete_txt_record "$FREEDNS_COOKIE" "$dataid" + return $? + fi + done + + # If we get this far we did not find a match + # Not necessarily an error, but log anyway. + _info "Cannot delete TXT record for $fulldomain, $txtvalue. Does not exist at FreeDNS" + return 0 +} + +#################### Private functions below ################################## + +# usage: _freedns_login username password +# print string "cookie=value" etc. +# returns 0 success +_freedns_login() { + export _H1="Accept-Language:en-US" + username="$1" + password="$2" + url="https://freedns.afraid.org/zc.php?step=2" + + _debug "Login to FreeDNS as user $username" + + htmlpage="$(_post "username=$(printf '%s' "$username" | _url_encode)&password=$(printf '%s' "$password" | _url_encode)&submit=Login&action=auth" "$url")" + + if [ "$?" != "0" ]; then + _err "FreeDNS login failed for user $username bad RC from _post" + return 1 + fi + + cookies="$(grep -i '^Set-Cookie.*dns_cookie.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)" + + # if cookies is not empty then logon successful + if [ -z "$cookies" ]; then + _debug3 "htmlpage: $htmlpage" + _err "FreeDNS login failed for user $username. Check $HTTP_HEADER file" + return 1 + fi + + printf "%s" "$cookies" + return 0 +} + +# usage _freedns_retrieve_subdomain_page login_cookies +# echo page retrieved (html) +# returns 0 success +_freedns_retrieve_subdomain_page() { + export _H1="Cookie:$1" + export _H2="Accept-Language:en-US" + url="https://freedns.afraid.org/subdomain/" + + _debug "Retrieve subdomain page from FreeDNS" + + htmlpage="$(_get "$url")" + + if [ "$?" != "0" ]; then + _err "FreeDNS retrieve subdomains failed bad RC from _get" + return 1 + elif [ -z "$htmlpage" ]; then + _err "FreeDNS returned empty subdomain page" + return 1 + fi + + _debug3 "htmlpage: $htmlpage" + + printf "%s" "$htmlpage" + return 0 +} + +# usage _freedns_retrieve_data_page login_cookies data_id +# echo page retrieved (html) +# returns 0 success +_freedns_retrieve_data_page() { + export _H1="Cookie:$1" + export _H2="Accept-Language:en-US" + data_id="$2" + url="https://freedns.afraid.org/subdomain/edit.php?data_id=$2" + + _debug "Retrieve data page for ID $data_id from FreeDNS" + + htmlpage="$(_get "$url")" + + if [ "$?" != "0" ]; then + _err "FreeDNS retrieve data page failed bad RC from _get" + return 1 + elif [ -z "$htmlpage" ]; then + _err "FreeDNS returned empty data page" + return 1 + fi + + _debug3 "htmlpage: $htmlpage" + + printf "%s" "$htmlpage" + return 0 +} + +# usage _freedns_add_txt_record login_cookies domain_id subdomain value +# returns 0 success +_freedns_add_txt_record() { + export _H1="Cookie:$1" + export _H2="Accept-Language:en-US" + domain_id="$2" + subdomain="$3" + value="$(printf '%s' "$4" | _url_encode)" + url="https://freedns.afraid.org/subdomain/save.php?step=2" + + htmlpage="$(_post "type=TXT&domain_id=$domain_id&subdomain=$subdomain&address=%22$value%22&send=Save%21" "$url")" + + if [ "$?" != "0" ]; then + _err "FreeDNS failed to add TXT record for $subdomain bad RC from _post" + return 1 + elif ! grep "200 OK" "$HTTP_HEADER" >/dev/null; then + _debug3 "htmlpage: $htmlpage" + _err "FreeDNS failed to add TXT record for $subdomain. Check $HTTP_HEADER file" + return 1 + elif _contains "$htmlpage" "security code was incorrect"; then + _debug3 "htmlpage: $htmlpage" + _err "FreeDNS failed to add TXT record for $subdomain as FreeDNS requested security code" + _err "Note that you cannot use automatic DNS validation for FreeDNS public domains" + return 1 + fi + + _debug3 "htmlpage: $htmlpage" + _info "Added acme challenge TXT record for $fulldomain at FreeDNS" + return 0 +} + +# usage _freedns_delete_txt_record login_cookies data_id +# returns 0 success +_freedns_delete_txt_record() { + export _H1="Cookie:$1" + export _H2="Accept-Language:en-US" + data_id="$2" + url="https://freedns.afraid.org/subdomain/delete2.php" + + htmlheader="$(_get "$url?data_id%5B%5D=$data_id&submit=delete+selected" "onlyheader")" + + if [ "$?" != "0" ]; then + _err "FreeDNS failed to delete TXT record for $data_id bad RC from _get" + return 1 + elif ! _contains "$htmlheader" "200 OK"; then + _debug2 "htmlheader: $htmlheader" + _err "FreeDNS failed to delete TXT record $data_id" + return 1 + fi + + _info "Deleted acme challenge TXT record for $fulldomain at FreeDNS" + return 0 +} + +# usage _freedns_domain_id domain_name +# echo the domain_id if found +# return 0 success +_freedns_domain_id() { + # Start by escaping the dots in the domain name + search_domain="$(echo "$1" | sed 's/\./\\./g')" + + # Sometimes FreeDNS does not return the subdomain page but rather + # returns a page regarding becoming a premium member. This usually + # happens after a period of inactivity. Immediately trying again + # returns the correct subdomain page. So, we will try twice to + # load the page and obtain our domain ID + attempts=2 + while [ "$attempts" -gt "0" ]; do + attempts="$(_math "$attempts" - 1)" + + htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" + if [ "$?" != "0" ]; then + if [ "$using_cached_cookies" = "true" ]; then + _err "Has your FreeDNS username and password changed? If so..." + _err "Please export as FREEDNS_User / FREEDNS_Password and try again." + fi + return 1 + fi + + domain_id="$(echo "$htmlpage" | tr -d " \t\r\n\v\f" | sed 's//@/g' | tr '@' '\n' | + grep "$search_domain\|$search_domain(.*)" | + sed -n 's/.*\(edit\.php?edit_domain_id=[0-9a-zA-Z]*\).*/\1/p' | + cut -d = -f 2)" + # The above beauty extracts domain ID from the html page... + # strip out all blank space and new lines. Then insert newlines + # before each table row + # search for the domain within each row (which may or may not have + # a text string in brackets (.*) after it. + # And finally extract the domain ID. + if [ -n "$domain_id" ]; then + printf "%s" "$domain_id" + return 0 + fi + _debug "Domain $search_domain not found. Retry loading subdomain page ($attempts attempts remaining)" + done + _debug "Domain $search_domain not found after retry" + return 1 +} + +# usage _freedns_data_id domain_name record_type +# echo the data_id(s) if found +# return 0 success +_freedns_data_id() { + # Start by escaping the dots in the domain name + search_domain="$(echo "$1" | sed 's/\./\\./g')" + record_type="$2" + + # Sometimes FreeDNS does not return the subdomain page but rather + # returns a page regarding becoming a premium member. This usually + # happens after a period of inactivity. Immediately trying again + # returns the correct subdomain page. So, we will try twice to + # load the page and obtain our domain ID + attempts=2 + while [ "$attempts" -gt "0" ]; do + attempts="$(_math "$attempts" - 1)" + + htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")" + if [ "$?" != "0" ]; then + if [ "$using_cached_cookies" = "true" ]; then + _err "Has your FreeDNS username and password changed? If so..." + _err "Please export as FREEDNS_User / FREEDNS_Password and try again." + fi + return 1 + fi + + data_id="$(echo "$htmlpage" | tr -d " \t\r\n\v\f" | sed 's//@/g' | tr '@' '\n' | + grep "$record_type" | + grep "$search_domain" | + sed -n 's/.*\(edit\.php?data_id=[0-9a-zA-Z]*\).*/\1/p' | + cut -d = -f 2)" + # The above beauty extracts data ID from the html page... + # strip out all blank space and new lines. Then insert newlines + # before each table row + # search for the record type withing each row (e.g. TXT) + # search for the domain within each row (which is within a + # anchor. And finally extract the domain ID. + if [ -n "$data_id" ]; then + printf "%s" "$data_id" + return 0 + fi + _debug "Domain $search_domain not found. Retry loading subdomain page ($attempts attempts remaining)" + done + _debug "Domain $search_domain not found after retry" + return 1 +} diff --git a/letsencrypt/dnsapi/dns_gandi_livedns.sh b/letsencrypt/dnsapi/dns_gandi_livedns.sh new file mode 100644 index 00000000..b3178c79 --- /dev/null +++ b/letsencrypt/dnsapi/dns_gandi_livedns.sh @@ -0,0 +1,175 @@ +#!/bin/bash + +# Gandi LiveDNS v5 API +# http://doc.livedns.gandi.net/ +# currently under beta +# +# Requires GANDI API KEY set in GANDI_LIVEDNS_KEY set as environment variable +# +#Author: Frédéric Crozat +# Dominik Röttsches +#Report Bugs here: https://github.com/fcrozat/acme.sh +# +######## Public functions ##################### + +GANDI_LIVEDNS_API="https://dns.api.gandi.net/api/v5" + +#Usage: dns_gandi_livedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_gandi_livedns_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$GANDI_LIVEDNS_KEY" ]; then + _err "No API key specified for Gandi LiveDNS." + _err "Create your key and export it as GANDI_LIVEDNS_KEY" + return 1 + fi + + _saveaccountconf GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + _debug domain "$_domain" + _debug sub_domain "$_sub_domain" + + _dns_gandi_append_record "$_domain" "$_sub_domain" "$txtvalue" +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_gandi_livedns_rm() { + fulldomain=$1 + txtvalue=$2 + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug fulldomain "$fulldomain" + _debug domain "$_domain" + _debug sub_domain "$_sub_domain" + _debug txtvalue "$txtvalue" + + if ! _dns_gandi_existing_rrset_values "$_domain" "$_sub_domain"; then + return 1 + fi + _new_rrset_values=$(echo "$_rrset_values" | sed "s/...$txtvalue...//g") + # Cleanup dangling commata. + _new_rrset_values=$(echo "$_new_rrset_values" | sed "s/, ,/ ,/g") + _new_rrset_values=$(echo "$_new_rrset_values" | sed "s/, *\]/\]/g") + _new_rrset_values=$(echo "$_new_rrset_values" | sed "s/\[ *,/\[/g") + _debug "New rrset_values" "$_new_rrset_values" + + _gandi_livedns_rest PUT \ + "domains/$_domain/records/$_sub_domain/TXT" \ + "{\"rrset_ttl\": 300, \"rrset_values\": $_new_rrset_values}" && + _contains "$response" '{"message": "DNS Record Created"}' && + _info "Removing record $(__green "success")" +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _gandi_livedns_rest GET "domains/$h"; then + return 1 + fi + + if _contains "$response" '"code": 401'; then + _err "$response" + return 1 + elif _contains "$response" '"code": 404'; then + _debug "$h not found" + else + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p="$i" + i=$(_math "$i" + 1) + done + return 1 +} + +_dns_gandi_append_record() { + domain=$1 + sub_domain=$2 + txtvalue=$3 + + if _dns_gandi_existing_rrset_values "$domain" "$sub_domain"; then + _debug "Appending new value" + _rrset_values=$(echo "$_rrset_values" | sed "s/\"]/\",\"$txtvalue\"]/") + else + _debug "Creating new record" "$_rrset_values" + _rrset_values="[\"$txtvalue\"]" + fi + _debug new_rrset_values "$_rrset_values" + _gandi_livedns_rest PUT "domains/$_domain/records/$sub_domain/TXT" \ + "{\"rrset_ttl\": 300, \"rrset_values\": $_rrset_values}" && + _contains "$response" '{"message": "DNS Record Created"}' && + _info "Adding record $(__green "success")" +} + +_dns_gandi_existing_rrset_values() { + domain=$1 + sub_domain=$2 + if ! _gandi_livedns_rest GET "domains/$domain/records/$sub_domain"; then + return 1 + fi + if ! _contains "$response" '"rrset_type": "TXT"'; then + _debug "Does not have a _acme-challenge TXT record yet." + return 1 + fi + if _contains "$response" '"rrset_values": \[\]'; then + _debug "Empty rrset_values for TXT record, no previous TXT record." + return 1 + fi + _debug "Already has TXT record." + _rrset_values=$(echo "$response" | _egrep_o 'rrset_values.*\[.*\]' | + _egrep_o '\[".*\"]') + return 0 +} + +_gandi_livedns_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Content-Type: application/json" + export _H2="X-Api-Key: $GANDI_LIVEDNS_KEY" + + if [ "$m" = "GET" ]; then + response="$(_get "$GANDI_LIVEDNS_API/$ep")" + else + _debug data "$data" + response="$(_post "$data" "$GANDI_LIVEDNS_API/$ep" "" "$m")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_gcloud.sh b/letsencrypt/dnsapi/dns_gcloud.sh new file mode 100755 index 00000000..e79d2995 --- /dev/null +++ b/letsencrypt/dnsapi/dns_gcloud.sh @@ -0,0 +1,167 @@ +#!/bin/bash + +# Author: Janos Lenart + +######## Public functions ##################### + +# Usage: dns_gcloud_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_gcloud_add() { + fulldomain=$1 + txtvalue=$2 + _info "Using gcloud" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + _dns_gcloud_find_zone || return $? + + # Add an extra RR + _dns_gcloud_start_tr || return $? + _dns_gcloud_get_rrdatas || return $? + echo "$rrdatas" | _dns_gcloud_remove_rrs || return $? + printf "%s\n%s\n" "$rrdatas" "\"$txtvalue\"" | grep -v '^$' | _dns_gcloud_add_rrs || return $? + _dns_gcloud_execute_tr || return $? + + _info "$fulldomain record added" +} + +# Usage: dns_gcloud_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Remove the txt record after validation. +dns_gcloud_rm() { + fulldomain=$1 + txtvalue=$2 + _info "Using gcloud" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + _dns_gcloud_find_zone || return $? + + # Remove one RR + _dns_gcloud_start_tr || return $? + _dns_gcloud_get_rrdatas || return $? + echo "$rrdatas" | _dns_gcloud_remove_rrs || return $? + echo "$rrdatas" | grep -F -v "\"$txtvalue\"" | _dns_gcloud_add_rrs || return $? + _dns_gcloud_execute_tr || return $? + + _info "$fulldomain record added" +} + +#################### Private functions below ################################## + +_dns_gcloud_start_tr() { + if ! trd=$(mktemp -d); then + _err "_dns_gcloud_start_tr: failed to create temporary directory" + return 1 + fi + tr="$trd/tr.yaml" + _debug tr "$tr" + + if ! gcloud dns record-sets transaction start \ + --transaction-file="$tr" \ + --zone="$managedZone"; then + rm -r "$trd" + _err "_dns_gcloud_start_tr: failed to execute transaction" + return 1 + fi +} + +_dns_gcloud_execute_tr() { + if ! gcloud dns record-sets transaction execute \ + --transaction-file="$tr" \ + --zone="$managedZone"; then + _debug tr "$(cat "$tr")" + rm -r "$trd" + _err "_dns_gcloud_execute_tr: failed to execute transaction" + return 1 + fi + rm -r "$trd" + + for i in $(seq 1 120); do + if gcloud dns record-sets changes list \ + --zone="$managedZone" \ + --filter='status != done' | + grep -q '^.*'; then + _info "_dns_gcloud_execute_tr: waiting for transaction to be comitted ($i/120)..." + sleep 5 + else + return 0 + fi + done + + _err "_dns_gcloud_execute_tr: transaction is still pending after 10 minutes" + rm -r "$trd" + return 1 +} + +_dns_gcloud_remove_rrs() { + if ! xargs -r gcloud dns record-sets transaction remove \ + --name="$fulldomain." \ + --ttl="$ttl" \ + --type=TXT \ + --zone="$managedZone" \ + --transaction-file="$tr"; then + _debug tr "$(cat "$tr")" + rm -r "$trd" + _err "_dns_gcloud_remove_rrs: failed to remove RRs" + return 1 + fi +} + +_dns_gcloud_add_rrs() { + ttl=60 + if ! xargs -r gcloud dns record-sets transaction add \ + --name="$fulldomain." \ + --ttl="$ttl" \ + --type=TXT \ + --zone="$managedZone" \ + --transaction-file="$tr"; then + _debug tr "$(cat "$tr")" + rm -r "$trd" + _err "_dns_gcloud_add_rrs: failed to add RRs" + return 1 + fi +} + +_dns_gcloud_find_zone() { + # Prepare a filter that matches zones that are suiteable for this entry. + # For example, _acme-challenge.something.domain.com might need to go into something.domain.com or domain.com; + # this function finds the longest postfix that has a managed zone. + part="$fulldomain" + filter="dnsName=( " + while [ "$part" != "" ]; do + filter="$filter$part. " + part="$(echo "$part" | sed 's/[^.]*\.*//')" + done + filter="$filter) AND visibility=public" + _debug filter "$filter" + + # List domains and find the zone with the deepest sub-domain (in case of some levels of delegation) + if ! match=$(gcloud dns managed-zones list \ + --format="value(name, dnsName)" \ + --filter="$filter" | + while read -r dnsName name; do + printf "%s\t%s\t%s\n" "$(echo "$name" | awk -F"." '{print NF-1}')" "$dnsName" "$name" + done | + sort -n -r | _head_n 1 | cut -f2,3 | grep '^.*'); then + _err "_dns_gcloud_find_zone: Can't find a matching managed zone! Perhaps wrong project or gcloud credentials?" + return 1 + fi + + dnsName=$(echo "$match" | cut -f2) + _debug dnsName "$dnsName" + managedZone=$(echo "$match" | cut -f1) + _debug managedZone "$managedZone" +} + +_dns_gcloud_get_rrdatas() { + if ! rrdatas=$(gcloud dns record-sets list \ + --zone="$managedZone" \ + --name="$fulldomain." \ + --type=TXT \ + --format="value(ttl,rrdatas)"); then + _err "_dns_gcloud_get_rrdatas: Failed to list record-sets" + rm -r "$trd" + return 1 + fi + ttl=$(echo "$rrdatas" | cut -f1) + rrdatas=$(echo "$rrdatas" | cut -f2 | sed 's/","/"\n"/g') +} diff --git a/letsencrypt/dnsapi/dns_gd.sh b/letsencrypt/dnsapi/dns_gd.sh new file mode 100755 index 00000000..894ec41c --- /dev/null +++ b/letsencrypt/dnsapi/dns_gd.sh @@ -0,0 +1,176 @@ +#!/bin/bash + +#Godaddy domain api +# +#GD_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# +#GD_Secret="asdfsdfsfsdfsdfdfsdf" + +GD_Api="https://api.godaddy.com/v1" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_gd_add() { + fulldomain=$1 + txtvalue=$2 + + GD_Key="${GD_Key:-$(_readaccountconf_mutable GD_Key)}" + GD_Secret="${GD_Secret:-$(_readaccountconf_mutable GD_Secret)}" + if [ -z "$GD_Key" ] || [ -z "$GD_Secret" ]; then + GD_Key="" + GD_Secret="" + _err "You don't specify godaddy api key and secret yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable GD_Key "$GD_Key" + _saveaccountconf_mutable GD_Secret "$GD_Secret" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting existing records" + if ! _gd_rest GET "domains/$_domain/records/TXT/$_sub_domain"; then + return 1 + fi + + if _contains "$response" "$txtvalue"; then + _info "The record is existing, skip" + return 0 + fi + + _add_data="{\"data\":\"$txtvalue\"}" + for t in $(echo "$response" | tr '{' "\n" | grep "\"name\":\"$_sub_domain\"" | tr ',' "\n" | grep '"data"' | cut -d : -f 2); do + _debug2 t "$t" + if [ "$t" ]; then + _add_data="$_add_data,{\"data\":$t}" + fi + done + _debug2 _add_data "$_add_data" + + _info "Adding record" + if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; then + _info "Added, sleeping 10 seconds" + _sleep 10 + #todo: check if the record takes effect + return 0 + fi + _err "Add txt record error." + return 1 +} + +#fulldomain +dns_gd_rm() { + fulldomain=$1 + txtvalue=$2 + + GD_Key="${GD_Key:-$(_readaccountconf_mutable GD_Key)}" + GD_Secret="${GD_Secret:-$(_readaccountconf_mutable GD_Secret)}" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting existing records" + if ! _gd_rest GET "domains/$_domain/records/TXT/$_sub_domain"; then + return 1 + fi + + if ! _contains "$response" "$txtvalue"; then + _info "The record does not exist, skip" + return 0 + fi + + _add_data="" + for t in $(echo "$response" | tr '{' "\n" | grep "\"name\":\"$_sub_domain\"" | tr ',' "\n" | grep '"data"' | cut -d : -f 2); do + _debug2 t "$t" + if [ "$t" ] && [ "$t" != "\"$txtvalue\"" ]; then + if [ "$_add_data" ]; then + _add_data="$_add_data,{\"data\":$t}" + else + _add_data="{\"data\":$t}" + fi + fi + done + if [ -z "$_add_data" ]; then + _add_data="{\"data\":\"\"}" + fi + _debug2 _add_data "$_add_data" + + _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]" +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _gd_rest GET "domains/$h"; then + return 1 + fi + + if _contains "$response" '"code":"NOT_FOUND"'; then + _debug "$h not found" + else + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p="$i" + i=$(_math "$i" + 1) + done + return 1 +} + +_gd_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Authorization: sso-key $GD_Key:$GD_Secret" + export _H2="Content-Type: application/json" + + if [ "$data" ]; then + _debug data "$data" + response="$(_post "$data" "$GD_Api/$ep" "" "$m")" + else + response="$(_get "$GD_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + if _contains "$response" "UNABLE_TO_AUTHENTICATE"; then + _err "It seems that your api key or secret is not correct." + return 1 + fi + return 0 +} diff --git a/letsencrypt/dnsapi/dns_gdnsdk.sh b/letsencrypt/dnsapi/dns_gdnsdk.sh new file mode 100755 index 00000000..2419e9a3 --- /dev/null +++ b/letsencrypt/dnsapi/dns_gdnsdk.sh @@ -0,0 +1,177 @@ +#!/bin/bash +#Author: Herman Sletteng +#Report Bugs here: https://github.com/loial/acme.sh +# +# +# Note, gratisdns requires a login first, so the script needs to handle +# temporary cookies. Since acme.sh _get/_post currently don't directly support +# cookies, I've defined wrapper functions _myget/_mypost to set the headers + +GDNSDK_API="https://admin.gratisdns.com" +######## Public functions ##################### +#Usage: dns_gdnsdk_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_gdnsdk_add() { + fulldomain=$1 + txtvalue=$2 + _info "Using gratisdns.dk" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + if ! _gratisdns_login; then + _err "Login failed!" + return 1 + fi + #finding domain zone + if ! _get_domain; then + _err "No matching root domain for $fulldomain found" + return 1 + fi + # adding entry + _info "Adding the entry" + _mypost "action=dns_primary_record_added_txt&user_domain=$_domain&name=$fulldomain&txtdata=$txtvalue&ttl=1" + if _successful_update; then return 0; fi + _err "Couldn't create entry!" + return 1 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_gdnsdk_rm() { + fulldomain=$1 + txtvalue=$2 + _info "Using gratisdns.dk" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + if ! _gratisdns_login; then + _err "Login failed!" + return 1 + fi + if ! _get_domain; then + _err "No matching root domain for $fulldomain found" + return 1 + fi + _findentry "$fulldomain" "$txtvalue" + if [ -z "$_id" ]; then + _info "Entry doesn't exist, nothing to delete" + return 0 + fi + _debug "Deleting record..." + _mypost "action=dns_primary_delete_txt&user_domain=$_domain&id=$_id" + # removing entry + + if _successful_update; then return 0; fi + _err "Couldn't delete entry!" + return 1 +} + +#################### Private functions below ################################## + +_checkcredentials() { + GDNSDK_Username="${GDNSDK_Username:-$(_readaccountconf_mutable GDNSDK_Username)}" + GDNSDK_Password="${GDNSDK_Password:-$(_readaccountconf_mutable GDNSDK_Password)}" + + if [ -z "$GDNSDK_Username" ] || [ -z "$GDNSDK_Password" ]; then + GDNSDK_Username="" + GDNSDK_Password="" + _err "You haven't specified gratisdns.dk username and password yet." + _err "Please add credentials and try again." + return 1 + fi + #save the credentials to the account conf file. + _saveaccountconf_mutable GDNSDK_Username "$GDNSDK_Username" + _saveaccountconf_mutable GDNSDK_Password "$GDNSDK_Password" + return 0 +} + +_checkcookie() { + GDNSDK_Cookie="${GDNSDK_Cookie:-$(_readaccountconf_mutable GDNSDK_Cookie)}" + if [ -z "$GDNSDK_Cookie" ]; then + _debug "No cached cookie found" + return 1 + fi + _myget "action=" + if (echo "$_result" | grep -q "logmeout"); then + _debug "Cached cookie still valid" + return 0 + fi + _debug "Cached cookie no longer valid" + GDNSDK_Cookie="" + _saveaccountconf_mutable GDNSDK_Cookie "$GDNSDK_Cookie" + return 1 +} + +_gratisdns_login() { + if ! _checkcredentials; then return 1; fi + + if _checkcookie; then + _debug "Already logged in" + return 0 + fi + _debug "Logging into GratisDNS with user $GDNSDK_Username" + + if ! _mypost "login=$GDNSDK_Username&password=$GDNSDK_Password&action=logmein"; then + _err "GratisDNS login failed for user $GDNSDK_Username bad RC from _post" + return 1 + fi + + GDNSDK_Cookie="$(grep -A 15 '302 Found' "$HTTP_HEADER" | _egrep_o 'Cookie: [^;]*' | _head_n 1 | cut -d ' ' -f2)" + + if [ -z "$GDNSDK_Cookie" ]; then + _err "GratisDNS login failed for user $GDNSDK_Username. Check $HTTP_HEADER file" + return 1 + fi + export GDNSDK_Cookie + _saveaccountconf_mutable GDNSDK_Cookie "$GDNSDK_Cookie" + return 0 +} + +_myget() { + #Adds cookie to request + export _H1="Cookie: $GDNSDK_Cookie" + _result=$(_get "$GDNSDK_API?$1") +} +_mypost() { + #Adds cookie to request + export _H1="Cookie: $GDNSDK_Cookie" + _result=$(_post "$1" "$GDNSDK_API") +} + +_get_domain() { + _myget 'action=dns_primarydns' + _domains=$(echo "$_result" | _egrep_o ' domain="[[:alnum:]._-]+' | sed 's/^.*"//') + if [ -z "$_domains" ]; then + _err "Primary domain list not found!" + return 1 + fi + for _domain in $_domains; do + if (_endswith "$fulldomain" "$_domain"); then + _debug "Root domain: $_domain" + return 0 + fi + done + return 1 +} + +_successful_update() { + if (echo "$_result" | grep -q 'table-success'); then return 0; fi + return 1 +} + +_findentry() { + #args $1: fulldomain, $2: txtvalue + #returns id of dns entry, if it exists + _myget "action=dns_primary_changeDNSsetup&user_domain=$_domain" + _debug3 "_result: $_result" + + _tmp_result=$(echo "$_result" | tr -d '\n\r' | _egrep_o "$1\s*$2[^?]*[^&]*&id=[^&]*") + _debug _tmp_result "$_tmp_result" + if [ -z "${_tmp_result:-}" ]; then + _debug "The variable is _tmp_result is not supposed to be empty, there may be something wrong with the script" + fi + + _id=$(echo "$_tmp_result" | sed 's/^.*=//') + if [ -n "$_id" ]; then + _debug "Entry found with _id=$_id" + return 0 + fi + return 1 +} diff --git a/letsencrypt/dnsapi/dns_he.sh b/letsencrypt/dnsapi/dns_he.sh new file mode 100755 index 00000000..a9d6d404 --- /dev/null +++ b/letsencrypt/dnsapi/dns_he.sh @@ -0,0 +1,173 @@ +#!/bin/bash + +######################################################################## +# Hurricane Electric hook script for acme.sh +# +# Environment variables: +# +# - $HE_Username (your dns.he.net username) +# - $HE_Password (your dns.he.net password) +# +# Author: Ondrej Simek +# Git repo: https://github.com/angel333/acme.sh + +#-- dns_he_add() - Add TXT record -------------------------------------- +# Usage: dns_he_add _acme-challenge.subdomain.domain.com "XyZ123..." + +dns_he_add() { + _full_domain=$1 + _txt_value=$2 + _info "Using DNS-01 Hurricane Electric hook" + + HE_Username="${HE_Username:-$(_readaccountconf_mutable HE_Username)}" + HE_Password="${HE_Password:-$(_readaccountconf_mutable HE_Password)}" + if [ -z "$HE_Username" ] || [ -z "$HE_Password" ]; then + HE_Username= + HE_Password= + _err "No auth details provided. Please set user credentials using the \$HE_Username and \$HE_Password environment variables." + return 1 + fi + _saveaccountconf_mutable HE_Username "$HE_Username" + _saveaccountconf_mutable HE_Password "$HE_Password" + + # Fills in the $_zone_id + _find_zone "$_full_domain" || return 1 + _debug "Zone id \"$_zone_id\" will be used." + username_encoded="$(printf "%s" "${HE_Username}" | _url_encode)" + password_encoded="$(printf "%s" "${HE_Password}" | _url_encode)" + body="email=${username_encoded}&pass=${password_encoded}" + body="$body&account=" + body="$body&menu=edit_zone" + body="$body&Type=TXT" + body="$body&hosted_dns_zoneid=$_zone_id" + body="$body&hosted_dns_recordid=" + body="$body&hosted_dns_editzone=1" + body="$body&Priority=" + body="$body&Name=$_full_domain" + body="$body&Content=$_txt_value" + body="$body&TTL=300" + body="$body&hosted_dns_editrecord=Submit" + response="$(_post "$body" "https://dns.he.net/")" + exit_code="$?" + if [ "$exit_code" -eq 0 ]; then + _info "TXT record added successfully." + else + _err "Couldn't add the TXT record." + fi + _debug2 response "$response" + return "$exit_code" +} + +#-- dns_he_rm() - Remove TXT record ------------------------------------ +# Usage: dns_he_rm _acme-challenge.subdomain.domain.com "XyZ123..." + +dns_he_rm() { + _full_domain=$1 + _txt_value=$2 + _info "Cleaning up after DNS-01 Hurricane Electric hook" + HE_Username="${HE_Username:-$(_readaccountconf_mutable HE_Username)}" + HE_Password="${HE_Password:-$(_readaccountconf_mutable HE_Password)}" + # fills in the $_zone_id + _find_zone "$_full_domain" || return 1 + _debug "Zone id \"$_zone_id\" will be used." + + # Find the record id to clean + username_encoded="$(printf "%s" "${HE_Username}" | _url_encode)" + password_encoded="$(printf "%s" "${HE_Password}" | _url_encode)" + body="email=${username_encoded}&pass=${password_encoded}" + body="$body&hosted_dns_zoneid=$_zone_id" + body="$body&menu=edit_zone" + body="$body&hosted_dns_editzone=" + + response="$(_post "$body" "https://dns.he.net/")" + _debug2 "response" "$response" + if ! _contains "$response" "$_txt_value"; then + _debug "The txt record is not found, just skip" + return 0 + fi + _record_id="$(echo "$response" | tr -d "#" | sed "s/Successfully removed record.' \ + >/dev/null + exit_code="$?" + if [ "$exit_code" -eq 0 ]; then + _info "Record removed successfully." + else + _err "Could not clean (remove) up the record. Please go to HE administration interface and clean it by hand." + return "$exit_code" + fi +} + +########################## PRIVATE FUNCTIONS ########################### + +_find_zone() { + _domain="$1" + username_encoded="$(printf "%s" "${HE_Username}" | _url_encode)" + password_encoded="$(printf "%s" "${HE_Password}" | _url_encode)" + body="email=${username_encoded}&pass=${password_encoded}" + response="$(_post "$body" "https://dns.he.net/")" + _debug2 response "$response" + if _contains "$response" '>Incorrect<'; then + _err "Unable to login to dns.he.net please check username and password" + return 1 + fi + _table="$(echo "$response" | tr -d "#" | sed "s//dev/null + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" + if [ "$_code" != "202" ]; then + _err "dns_huaweicloud: http code ${_code}" + return 1 + fi + return 0 +} + +# _rm_record $token $zoneid $recordid +# assume ${dns_api} exist +# no output +# return 0 +_rm_record() { + _token=$1 + _zone_id=$2 + _record_id=$3 + + export _H2="Content-Type: application/json" + export _H1="X-Auth-Token: ${_token}" + + _post "" "${dns_api}/v2/zones/${_zone_id}/recordsets/${_record_id}" false "DELETE" >/dev/null + return $? +} + +_get_token() { + _username=$1 + _password=$2 + _project=$3 + + _debug "Getting Token" + body="{ + \"auth\": { + \"identity\": { + \"methods\": [ + \"password\" + ], + \"password\": { + \"user\": { + \"name\": \"${_username}\", + \"password\": \"${_password}\", + \"domain\": { + \"name\": \"${_username}\" + } + } + } + }, + \"scope\": { + \"project\": { + \"id\": \"${_project}\" + } + } + } + }" + export _H1="Content-Type: application/json;charset=utf8" + _post "${body}" "${iam_api}/v3/auth/tokens" >/dev/null + _code=$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n") + _token=$(grep "^X-Subject-Token" "$HTTP_HEADER" | cut -d " " -f 2-) + _debug2 "${_code}" + printf "%s" "${_token}" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_infoblox.sh b/letsencrypt/dnsapi/dns_infoblox.sh new file mode 100644 index 00000000..1d091140 --- /dev/null +++ b/letsencrypt/dnsapi/dns_infoblox.sh @@ -0,0 +1,102 @@ +#!/bin/bash + +## Infoblox API integration by Jason Keller and Elijah Tenai +## +## Report any bugs via https://github.com/jasonkeller/acme.sh + +dns_infoblox_add() { + + ## Nothing to see here, just some housekeeping + fulldomain=$1 + txtvalue=$2 + baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View" + + _info "Using Infoblox API" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + ## Check for the credentials + if [ -z "$Infoblox_Creds" ] || [ -z "$Infoblox_Server" ]; then + Infoblox_Creds="" + Infoblox_Server="" + _err "You didn't specify the credentials, server or infoblox view yet (Infoblox_Creds, Infoblox_Server and Infoblox_View)." + _err "Please set them via EXPORT ([username:password], [ip or hostname]) and try again." + return 1 + fi + + if [ -z "$Infoblox_View" ]; then + Infoblox_View="default" + fi + + ## Save the credentials to the account file + _saveaccountconf Infoblox_Creds "$Infoblox_Creds" + _saveaccountconf Infoblox_Server "$Infoblox_Server" + _saveaccountconf Infoblox_View "$Infoblox_View" + + ## Base64 encode the credentials + Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64) + + ## Construct the HTTP Authorization header + export _H1="Accept-Language:en-US" + export _H2="Authorization: Basic $Infoblox_CredsEncoded" + + ## Add the challenge record to the Infoblox grid member + result="$(_post "" "$baseurlnObject" "" "POST")" + + ## Let's see if we get something intelligible back from the unit + if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then + _info "Successfully created the txt record" + return 0 + else + _err "Error encountered during record addition" + _err "$result" + return 1 + fi + +} + +dns_infoblox_rm() { + + ## Nothing to see here, just some housekeeping + fulldomain=$1 + txtvalue=$2 + + _info "Using Infoblox API" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + ## Base64 encode the credentials + Infoblox_CredsEncoded="$(printf "%b" "$Infoblox_Creds" | _base64)" + + ## Construct the HTTP Authorization header + export _H1="Accept-Language:en-US" + export _H2="Authorization: Basic $Infoblox_CredsEncoded" + + ## Does the record exist? Let's check. + baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View&_return_type=xml-pretty" + result="$(_get "$baseurlnObject")" + + ## Let's see if we get something intelligible back from the grid + if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then + ## Extract the object reference + objRef="$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" + objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef" + ## Delete them! All the stale records! + rmResult="$(_post "" "$objRmUrl" "" "DELETE")" + ## Let's see if that worked + if [ "$(echo "$rmResult" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then + _info "Successfully deleted $objRef" + return 0 + else + _err "Error occurred during txt record delete" + _err "$rmResult" + return 1 + fi + else + _err "Record to delete didn't match an existing record" + _err "$result" + return 1 + fi +} + +#################### Private functions below ################################## diff --git a/letsencrypt/dnsapi/dns_infomaniak.sh b/letsencrypt/dnsapi/dns_infomaniak.sh new file mode 100755 index 00000000..85d7cd19 --- /dev/null +++ b/letsencrypt/dnsapi/dns_infomaniak.sh @@ -0,0 +1,199 @@ +#!/bin/bash + +############################################################################### +# Infomaniak API integration +# +# To use this API you need visit the API dashboard of your account +# once logged into https://manager.infomaniak.com add /api/dashboard to the URL +# +# Please report bugs to +# https://github.com/acmesh-official/acme.sh/issues/3188 +# +# Note: the URL looks like this: +# https://manager.infomaniak.com/v3//api/dashboard +# Then generate a token with the scope Domain +# this is given as an environment variable INFOMANIAK_API_TOKEN +############################################################################### + +# base variables + +DEFAULT_INFOMANIAK_API_URL="https://api.infomaniak.com" +DEFAULT_INFOMANIAK_TTL=300 + +######## Public functions ##################### + +#Usage: dns_infomaniak_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_infomaniak_add() { + + INFOMANIAK_API_TOKEN="${INFOMANIAK_API_TOKEN:-$(_readaccountconf_mutable INFOMANIAK_API_TOKEN)}" + INFOMANIAK_API_URL="${INFOMANIAK_API_URL:-$(_readaccountconf_mutable INFOMANIAK_API_URL)}" + INFOMANIAK_TTL="${INFOMANIAK_TTL:-$(_readaccountconf_mutable INFOMANIAK_TTL)}" + + if [ -z "$INFOMANIAK_API_TOKEN" ]; then + INFOMANIAK_API_TOKEN="" + _err "Please provide a valid Infomaniak API token in variable INFOMANIAK_API_TOKEN" + return 1 + fi + + if [ -z "$INFOMANIAK_API_URL" ]; then + INFOMANIAK_API_URL="$DEFAULT_INFOMANIAK_API_URL" + fi + + if [ -z "$INFOMANIAK_TTL" ]; then + INFOMANIAK_TTL="$DEFAULT_INFOMANIAK_TTL" + fi + + #save the token to the account conf file. + _saveaccountconf_mutable INFOMANIAK_API_TOKEN "$INFOMANIAK_API_TOKEN" + + if [ "$INFOMANIAK_API_URL" != "$DEFAULT_INFOMANIAK_API_URL" ]; then + _saveaccountconf_mutable INFOMANIAK_API_URL "$INFOMANIAK_API_URL" + fi + + if [ "$INFOMANIAK_TTL" != "$DEFAULT_INFOMANIAK_TTL" ]; then + _saveaccountconf_mutable INFOMANIAK_TTL "$INFOMANIAK_TTL" + fi + + export _H1="Authorization: Bearer $INFOMANIAK_API_TOKEN" + export _H2="Content-Type: application/json" + + fulldomain="$1" + txtvalue="$2" + + _info "Infomaniak DNS API" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + fqdn=${fulldomain#_acme-challenge.} + + # guess which base domain to add record to + zone_and_id=$(_find_zone "$fqdn") + if [ -z "$zone_and_id" ]; then + _err "cannot find zone to modify" + return 1 + fi + zone=${zone_and_id% *} + domain_id=${zone_and_id#* } + + # extract first part of domain + key=${fulldomain%.$zone} + + _debug "zone:$zone id:$domain_id key:$key" + + # payload + data="{\"type\": \"TXT\", \"source\": \"$key\", \"target\": \"$txtvalue\", \"ttl\": $INFOMANIAK_TTL}" + + # API call + response=$(_post "$data" "${INFOMANIAK_API_URL}/1/domain/$domain_id/dns/record") + if [ -n "$response" ] && echo "$response" | _contains '"result":"success"'; then + _info "Record added" + _debug "Response: $response" + return 0 + fi + _err "could not create record" + _debug "Response: $response" + return 1 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_infomaniak_rm() { + + INFOMANIAK_API_TOKEN="${INFOMANIAK_API_TOKEN:-$(_readaccountconf_mutable INFOMANIAK_API_TOKEN)}" + INFOMANIAK_API_URL="${INFOMANIAK_API_URL:-$(_readaccountconf_mutable INFOMANIAK_API_URL)}" + INFOMANIAK_TTL="${INFOMANIAK_TTL:-$(_readaccountconf_mutable INFOMANIAK_TTL)}" + + if [ -z "$INFOMANIAK_API_TOKEN" ]; then + INFOMANIAK_API_TOKEN="" + _err "Please provide a valid Infomaniak API token in variable INFOMANIAK_API_TOKEN" + return 1 + fi + + if [ -z "$INFOMANIAK_API_URL" ]; then + INFOMANIAK_API_URL="$DEFAULT_INFOMANIAK_API_URL" + fi + + if [ -z "$INFOMANIAK_TTL" ]; then + INFOMANIAK_TTL="$DEFAULT_INFOMANIAK_TTL" + fi + + #save the token to the account conf file. + _saveaccountconf_mutable INFOMANIAK_API_TOKEN "$INFOMANIAK_API_TOKEN" + + if [ "$INFOMANIAK_API_URL" != "$DEFAULT_INFOMANIAK_API_URL" ]; then + _saveaccountconf_mutable INFOMANIAK_API_URL "$INFOMANIAK_API_URL" + fi + + if [ "$INFOMANIAK_TTL" != "$DEFAULT_INFOMANIAK_TTL" ]; then + _saveaccountconf_mutable INFOMANIAK_TTL "$INFOMANIAK_TTL" + fi + + export _H1="Authorization: Bearer $INFOMANIAK_API_TOKEN" + export _H2="ContentType: application/json" + + fulldomain=$1 + txtvalue=$2 + _info "Infomaniak DNS API" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + fqdn=${fulldomain#_acme-challenge.} + + # guess which base domain to add record to + zone_and_id=$(_find_zone "$fqdn") + if [ -z "$zone_and_id" ]; then + _err "cannot find zone to modify" + return 1 + fi + zone=${zone_and_id% *} + domain_id=${zone_and_id#* } + + # extract first part of domain + key=${fulldomain%.$zone} + + _debug "zone:$zone id:$domain_id key:$key" + + # find previous record + # shellcheck disable=SC1004 + record_id=$(_get "${INFOMANIAK_API_URL}/1/domain/$domain_id/dns/record" | sed 's/.*"data":\[\(.*\)\]}/\1/; s/},{/}\ +{/g' | sed -n 's/.*"id":"*\([0-9]*\)"*.*"source_idn":"'"$fulldomain"'".*"target_idn":"'"$txtvalue"'".*/\1/p') + if [ -z "$record_id" ]; then + _err "could not find record to delete" + return 1 + fi + _debug "record_id: $record_id" + + # API call + response=$(_post "" "${INFOMANIAK_API_URL}/1/domain/$domain_id/dns/record/$record_id" "" DELETE) + if [ -n "$response" ] && echo "$response" | _contains '"result":"success"'; then + _info "Record deleted" + return 0 + fi + _err "could not delete record" + return 1 +} + +#################### Private functions below ################################## + +_get_domain_id() { + domain="$1" + + # shellcheck disable=SC1004 + _get "${INFOMANIAK_API_URL}/1/product?service_name=domain&customer_name=$domain" | sed 's/.*"data":\[{\(.*\)}\]}/\1/; s/,/\ +/g' | sed -n 's/^"id":\(.*\)/\1/p' +} + +_find_zone() { + zone="$1" + + # find domain in list, removing . parts sequentialy + while _contains "$zone" '\.'; do + _debug "testing $zone" + id=$(_get_domain_id "$zone") + if [ -n "$id" ]; then + echo "$zone $id" + return + fi + zone=${zone#*.} + done +} diff --git a/letsencrypt/dnsapi/dns_internetbs.sh b/letsencrypt/dnsapi/dns_internetbs.sh new file mode 100755 index 00000000..ba344939 --- /dev/null +++ b/letsencrypt/dnsapi/dns_internetbs.sh @@ -0,0 +1,180 @@ +#!/bin/bash + +#This is the Internet.BS api wrapper for acme.sh +# +#Author: Ne-Lexa +#Report Bugs here: https://github.com/Ne-Lexa/acme.sh + +#INTERNETBS_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" +#INTERNETBS_API_PASSWORD="sdfsdfsdfljlbjkljlkjsdfoiwje" + +INTERNETBS_API_URL="https://api.internet.bs" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_internetbs_add() { + fulldomain=$1 + txtvalue=$2 + + INTERNETBS_API_KEY="${INTERNETBS_API_KEY:-$(_readaccountconf_mutable INTERNETBS_API_KEY)}" + INTERNETBS_API_PASSWORD="${INTERNETBS_API_PASSWORD:-$(_readaccountconf_mutable INTERNETBS_API_PASSWORD)}" + + if [ -z "$INTERNETBS_API_KEY" ] || [ -z "$INTERNETBS_API_PASSWORD" ]; then + INTERNETBS_API_KEY="" + INTERNETBS_API_PASSWORD="" + _err "You didn't specify the INTERNET.BS api key and password yet." + _err "Please create you key and try again." + return 1 + fi + + _saveaccountconf_mutable INTERNETBS_API_KEY "$INTERNETBS_API_KEY" + _saveaccountconf_mutable INTERNETBS_API_PASSWORD "$INTERNETBS_API_PASSWORD" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + # https://testapi.internet.bs/Domain/DnsRecord/Add?ApiKey=testapi&Password=testpass&FullRecordName=w3.test-api-domain7.net&Type=CNAME&Value=www.internet.bs%&ResponseFormat=json + if _internetbs_rest POST "Domain/DnsRecord/Add" "FullRecordName=${_sub_domain}.${_domain}&Type=TXT&Value=${txtvalue}&ResponseFormat=json"; then + if ! _contains "$response" "\"status\":\"SUCCESS\""; then + _err "ERROR add TXT record" + _err "$response" + return 1 + fi + + _info "txt record add success." + return 0 + fi + + return 1 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_internetbs_rm() { + fulldomain=$1 + txtvalue=$2 + + INTERNETBS_API_KEY="${INTERNETBS_API_KEY:-$(_readaccountconf_mutable INTERNETBS_API_KEY)}" + INTERNETBS_API_PASSWORD="${INTERNETBS_API_PASSWORD:-$(_readaccountconf_mutable INTERNETBS_API_PASSWORD)}" + + if [ -z "$INTERNETBS_API_KEY" ] || [ -z "$INTERNETBS_API_PASSWORD" ]; then + INTERNETBS_API_KEY="" + INTERNETBS_API_PASSWORD="" + _err "You didn't specify the INTERNET.BS api key and password yet." + _err "Please create you key and try again." + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + # https://testapi.internet.bs/Domain/DnsRecord/List?ApiKey=testapi&Password=testpass&Domain=test-api-domain7.net&FilterType=CNAME&ResponseFormat=json + _internetbs_rest POST "Domain/DnsRecord/List" "Domain=$_domain&FilterType=TXT&ResponseFormat=json" + + if ! _contains "$response" "\"status\":\"SUCCESS\""; then + _err "ERROR list dns records" + _err "$response" + return 1 + fi + + if _contains "$response" "\name\":\"${_sub_domain}.${_domain}\""; then + _info "txt record find." + + # https://testapi.internet.bs/Domain/DnsRecord/Remove?ApiKey=testapi&Password=testpass&FullRecordName=www.test-api-domain7.net&Type=cname&ResponseFormat=json + _internetbs_rest POST "Domain/DnsRecord/Remove" "FullRecordName=${_sub_domain}.${_domain}&Type=TXT&ResponseFormat=json" + + if ! _contains "$response" "\"status\":\"SUCCESS\""; then + _err "ERROR remove dns record" + _err "$response" + return 1 + fi + + _info "txt record deleted success." + return 0 + fi + + return 1 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=12345 +_get_root() { + domain=$1 + i=2 + p=1 + + # https://testapi.internet.bs/Domain/List?ApiKey=testapi&Password=testpass&CompactList=yes&ResponseFormat=json + if _internetbs_rest POST "Domain/List" "CompactList=yes&ResponseFormat=json"; then + + if ! _contains "$response" "\"status\":\"SUCCESS\""; then + _err "ERROR fetch domain list" + _err "$response" + return 1 + fi + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f ${i}-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "\"$h\""; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-${p}) + _domain=${h} + return 0 + fi + + p=${i} + i=$(_math "$i" + 1) + done + fi + return 1 +} + +#Usage: method URI data +_internetbs_rest() { + m="$1" + ep="$2" + data="$3" + url="${INTERNETBS_API_URL}/${ep}" + + _debug url "$url" + + apiKey="$(printf "%s" "${INTERNETBS_API_KEY}" | _url_encode)" + password="$(printf "%s" "${INTERNETBS_API_PASSWORD}" | _url_encode)" + + if [ "$m" = "GET" ]; then + response="$(_get "${url}?ApiKey=${apiKey}&Password=${password}&${data}" | tr -d '\r')" + else + _debug2 data "$data" + response="$(_post "$data" "${url}?ApiKey=${apiKey}&Password=${password}" | tr -d '\r')" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_inwx.sh b/letsencrypt/dnsapi/dns_inwx.sh new file mode 100755 index 00000000..b7bedfec --- /dev/null +++ b/letsencrypt/dnsapi/dns_inwx.sh @@ -0,0 +1,420 @@ +#!/bin/bash + +# +#INWX_User="username" +# +#INWX_Password="password" +# +# Dependencies: +# ------------- +# - oathtool (When using 2 Factor Authentication) + +INWX_Api="https://api.domrobot.com/xmlrpc/" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_inwx_add() { + fulldomain=$1 + txtvalue=$2 + + INWX_User="${INWX_User:-$(_readaccountconf_mutable INWX_User)}" + INWX_Password="${INWX_Password:-$(_readaccountconf_mutable INWX_Password)}" + INWX_Shared_Secret="${INWX_Shared_Secret:-$(_readaccountconf_mutable INWX_Shared_Secret)}" + if [ -z "$INWX_User" ] || [ -z "$INWX_Password" ]; then + INWX_User="" + INWX_Password="" + _err "You don't specify inwx user and password yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable INWX_User "$INWX_User" + _saveaccountconf_mutable INWX_Password "$INWX_Password" + _saveaccountconf_mutable INWX_Shared_Secret "$INWX_Shared_Secret" + + if ! _inwx_login; then + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _info "Adding record" + _inwx_add_record "$_domain" "$_sub_domain" "$txtvalue" + +} + +#fulldomain txtvalue +dns_inwx_rm() { + + fulldomain=$1 + txtvalue=$2 + + INWX_User="${INWX_User:-$(_readaccountconf_mutable INWX_User)}" + INWX_Password="${INWX_Password:-$(_readaccountconf_mutable INWX_Password)}" + INWX_Shared_Secret="${INWX_Shared_Secret:-$(_readaccountconf_mutable INWX_Shared_Secret)}" + if [ -z "$INWX_User" ] || [ -z "$INWX_Password" ]; then + INWX_User="" + INWX_Password="" + _err "You don't specify inwx user and password yet." + _err "Please create you key and try again." + return 1 + fi + + if ! _inwx_login; then + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + + xml_content=$(printf ' + + nameserver.info + + + + + + domain + + %s + + + + type + + TXT + + + + name + + %s + + + + + + + ' "$_domain" "$_sub_domain") + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + + if ! _contains "$response" "Command completed successfully"; then + _err "Error could not get txt records" + return 1 + fi + + if ! printf "%s" "$response" | grep "count" >/dev/null; then + _info "Do not need to delete record" + else + _record_id=$(printf '%s' "$response" | _egrep_o '.*(record){1}(.*)([0-9]+){1}' | _egrep_o 'id<\/name>[0-9]+' | _egrep_o '[0-9]+') + _info "Deleting record" + _inwx_delete_record "$_record_id" + fi + +} + +#################### Private functions below ################################## + +_inwx_check_cookie() { + INWX_Cookie="${INWX_Cookie:-$(_readaccountconf_mutable INWX_Cookie)}" + if [ -z "$INWX_Cookie" ]; then + _debug "No cached cookie found" + return 1 + fi + _H1="$INWX_Cookie" + export _H1 + + xml_content=$(printf ' + + account.info + ') + + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + + if _contains "$response" "code1000"; then + _debug "Cached cookie still valid" + return 0 + fi + + _debug "Cached cookie no longer valid" + _H1="" + export _H1 + INWX_Cookie="" + _saveaccountconf_mutable INWX_Cookie "$INWX_Cookie" + return 1 +} + +_inwx_login() { + + if _inwx_check_cookie; then + _debug "Already logged in" + return 0 + fi + + xml_content=$(printf ' + + account.login + + + + + + user + + %s + + + + pass + + %s + + + + + + + ' "$INWX_User" "$INWX_Password") + + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + + INWX_Cookie=$(printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')") + _H1=$INWX_Cookie + export _H1 + export INWX_Cookie + _saveaccountconf_mutable INWX_Cookie "$INWX_Cookie" + + if ! _contains "$response" "code1000"; then + _err "INWX API: Authentication error (username/password correct?)" + return 1 + fi + + #https://github.com/inwx/php-client/blob/master/INWX/Domrobot.php#L71 + if _contains "$response" "tfaGOOGLE-AUTH"; then + if [ -z "$INWX_Shared_Secret" ]; then + _err "INWX API: Mobile TAN detected." + _err "Please define a shared secret." + return 1 + fi + + if ! _exists oathtool; then + _err "Please install oathtool to use 2 Factor Authentication." + _err "" + return 1 + fi + + tan="$(oathtool --base32 --totp "${INWX_Shared_Secret}" 2>/dev/null)" + + xml_content=$(printf ' + + account.unlock + + + + + + tan + + %s + + + + + + + ' "$tan") + + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + + if ! _contains "$response" "code1000"; then + _err "INWX API: Mobile TAN not correct." + return 1 + fi + fi + +} + +_get_root() { + domain=$1 + _debug "get root" + + domain=$1 + i=2 + p=1 + + xml_content=' + + nameserver.list + + + + + + pagelimit + + 9999 + + + + + + + ' + + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "$h"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 + +} + +_inwx_delete_record() { + record_id=$1 + xml_content=$(printf ' + + nameserver.deleteRecord + + + + + + id + + %s + + + + + + + ' "$record_id") + + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + + if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then + _err "Error" + return 1 + fi + return 0 + +} + +_inwx_update_record() { + record_id=$1 + txtval=$2 + xml_content=$(printf ' + + nameserver.updateRecord + + + + + + content + + %s + + + + id + + %s + + + + + + + ' "$txtval" "$record_id") + + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + + if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then + _err "Error" + return 1 + fi + return 0 + +} + +_inwx_add_record() { + + domain=$1 + sub_domain=$2 + txtval=$3 + + xml_content=$(printf ' + + nameserver.createRecord + + + + + + domain + + %s + + + + type + + TXT + + + + content + + %s + + + + name + + %s + + + + + + + ' "$domain" "$txtval" "$sub_domain") + + response="$(_post "$xml_content" "$INWX_Api" "" "POST")" + + if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then + _err "Error" + return 1 + fi + return 0 +} diff --git a/letsencrypt/dnsapi/dns_ispconfig.sh b/letsencrypt/dnsapi/dns_ispconfig.sh new file mode 100755 index 00000000..60fe9966 --- /dev/null +++ b/letsencrypt/dnsapi/dns_ispconfig.sh @@ -0,0 +1,176 @@ +#!/bin/bash + +# ISPConfig 3.1 API +# User must provide login data and URL to the ISPConfig installation incl. port. The remote user in ISPConfig must have access to: +# - DNS txt Functions + +# Report bugs to https://github.com/sjau/acme.sh + +# Values to export: +# export ISPC_User="remoteUser" +# export ISPC_Password="remotePassword" +# export ISPC_Api="https://ispc.domain.tld:8080/remote/json.php" +# export ISPC_Api_Insecure=1 # Set 1 for insecure and 0 for secure -> difference is whether ssl cert is checked for validity (0) or whether it is just accepted (1) + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_ispconfig_add() { + fulldomain="${1}" + txtvalue="${2}" + _debug "Calling: dns_ispconfig_add() '${fulldomain}' '${txtvalue}'" + _ISPC_credentials && _ISPC_login && _ISPC_getZoneInfo && _ISPC_addTxt +} + +#Usage: dns_myapi_rm _acme-challenge.www.domain.com +dns_ispconfig_rm() { + fulldomain="${1}" + _debug "Calling: dns_ispconfig_rm() '${fulldomain}'" + _ISPC_credentials && _ISPC_login && _ISPC_rmTxt +} + +#################### Private functions below ################################## + +_ISPC_credentials() { + if [ -z "${ISPC_User}" ] || [ -z "$ISPC_Password" ] || [ -z "${ISPC_Api}" ] || [ -z "${ISPC_Api_Insecure}" ]; then + ISPC_User="" + ISPC_Password="" + ISPC_Api="" + ISPC_Api_Insecure="" + _err "You haven't specified the ISPConfig Login data, URL and whether you want check the ISPC SSL cert. Please try again." + return 1 + else + _saveaccountconf ISPC_User "${ISPC_User}" + _saveaccountconf ISPC_Password "${ISPC_Password}" + _saveaccountconf ISPC_Api "${ISPC_Api}" + _saveaccountconf ISPC_Api_Insecure "${ISPC_Api_Insecure}" + # Set whether curl should use secure or insecure mode + export HTTPS_INSECURE="${ISPC_Api_Insecure}" + fi +} + +_ISPC_login() { + _info "Getting Session ID" + curData="{\"username\":\"${ISPC_User}\",\"password\":\"${ISPC_Password}\",\"client_login\":false}" + curResult="$(_post "${curData}" "${ISPC_Api}?login")" + _debug "Calling _ISPC_login: '${curData}' '${ISPC_Api}?login'" + _debug "Result of _ISPC_login: '$curResult'" + if _contains "${curResult}" '"code":"ok"'; then + sessionID=$(echo "${curResult}" | _egrep_o "response.*" | cut -d ':' -f 2 | cut -d '"' -f 2) + _info "Retrieved Session ID." + _debug "Session ID: '${sessionID}'" + else + _err "Couldn't retrieve the Session ID." + return 1 + fi +} + +_ISPC_getZoneInfo() { + _info "Getting Zoneinfo" + zoneEnd=false + curZone="${fulldomain}" + while [ "${zoneEnd}" = false ]; do + # we can strip the first part of the fulldomain, since it's just the _acme-challenge string + curZone="${curZone#*.}" + # suffix . needed for zone -> domain.tld. + curData="{\"session_id\":\"${sessionID}\",\"primary_id\":{\"origin\":\"${curZone}.\"}}" + curResult="$(_post "${curData}" "${ISPC_Api}?dns_zone_get")" + _debug "Calling _ISPC_getZoneInfo: '${curData}' '${ISPC_Api}?login'" + _debug "Result of _ISPC_getZoneInfo: '$curResult'" + if _contains "${curResult}" '"id":"'; then + zoneFound=true + zoneEnd=true + _info "Retrieved zone data." + _debug "Zone data: '${curResult}'" + fi + if [ "${curZone#*.}" != "$curZone" ]; then + _debug2 "$curZone still contains a '.' - so we can check next higher level" + else + zoneEnd=true + _err "Couldn't retrieve zone data." + return 1 + fi + done + if [ "${zoneFound}" ]; then + server_id=$(echo "${curResult}" | _egrep_o "server_id.*" | cut -d ':' -f 2 | cut -d '"' -f 2) + _debug "Server ID: '${server_id}'" + case "${server_id}" in + '' | *[!0-9]*) + _err "Server ID is not numeric." + return 1 + ;; + *) _info "Retrieved Server ID" ;; + esac + zone=$(echo "${curResult}" | _egrep_o "\"id.*" | cut -d ':' -f 2 | cut -d '"' -f 2) + _debug "Zone: '${zone}'" + case "${zone}" in + '' | *[!0-9]*) + _err "Zone ID is not numeric." + return 1 + ;; + *) _info "Retrieved Zone ID" ;; + esac + client_id=$(echo "${curResult}" | _egrep_o "sys_userid.*" | cut -d ':' -f 2 | cut -d '"' -f 2) + _debug "Client ID: '${client_id}'" + case "${client_id}" in + '' | *[!0-9]*) + _err "Client ID is not numeric." + return 1 + ;; + *) _info "Retrieved Client ID." ;; + esac + zoneFound="" + zoneEnd="" + fi +} + +_ISPC_addTxt() { + curSerial="$(date +%s)" + curStamp="$(date +'%F %T')" + params="\"server_id\":\"${server_id}\",\"zone\":\"${zone}\",\"name\":\"${fulldomain}.\",\"type\":\"txt\",\"data\":\"${txtvalue}\",\"aux\":\"0\",\"ttl\":\"3600\",\"active\":\"y\",\"stamp\":\"${curStamp}\",\"serial\":\"${curSerial}\"" + curData="{\"session_id\":\"${sessionID}\",\"client_id\":\"${client_id}\",\"params\":{${params}},\"update_serial\":true}" + curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_add")" + _debug "Calling _ISPC_addTxt: '${curData}' '${ISPC_Api}?dns_txt_add'" + _debug "Result of _ISPC_addTxt: '$curResult'" + record_id=$(echo "${curResult}" | _egrep_o "\"response.*" | cut -d ':' -f 2 | cut -d '"' -f 2) + _debug "Record ID: '${record_id}'" + case "${record_id}" in + '' | *[!0-9]*) + _err "Couldn't add ACME Challenge TXT record to zone." + return 1 + ;; + *) _info "Added ACME Challenge TXT record to zone." ;; + esac +} + +_ISPC_rmTxt() { + # Need to get the record ID. + curData="{\"session_id\":\"${sessionID}\",\"primary_id\":{\"name\":\"${fulldomain}.\",\"type\":\"TXT\"}}" + curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_get")" + _debug "Calling _ISPC_rmTxt: '${curData}' '${ISPC_Api}?dns_txt_get'" + _debug "Result of _ISPC_rmTxt: '$curResult'" + if _contains "${curResult}" '"code":"ok"'; then + record_id=$(echo "${curResult}" | _egrep_o "\"id.*" | cut -d ':' -f 2 | cut -d '"' -f 2) + _debug "Record ID: '${record_id}'" + case "${record_id}" in + '' | *[!0-9]*) + _err "Record ID is not numeric." + return 1 + ;; + *) + unset IFS + _info "Retrieved Record ID." + curData="{\"session_id\":\"${sessionID}\",\"primary_id\":\"${record_id}\",\"update_serial\":true}" + curResult="$(_post "${curData}" "${ISPC_Api}?dns_txt_delete")" + _debug "Calling _ISPC_rmTxt: '${curData}' '${ISPC_Api}?dns_txt_delete'" + _debug "Result of _ISPC_rmTxt: '$curResult'" + if _contains "${curResult}" '"code":"ok"'; then + _info "Removed ACME Challenge TXT record from zone." + else + _err "Couldn't remove ACME Challenge TXT record from zone." + return 1 + fi + ;; + esac + fi +} diff --git a/letsencrypt/dnsapi/dns_jd.sh b/letsencrypt/dnsapi/dns_jd.sh new file mode 100644 index 00000000..f462ca14 --- /dev/null +++ b/letsencrypt/dnsapi/dns_jd.sh @@ -0,0 +1,286 @@ +#!/bin/bash + +# +#JD_ACCESS_KEY_ID="sdfsdfsdfljlbjkljlkjsdfoiwje" +#JD_ACCESS_KEY_SECRET="xxxxxxx" +#JD_REGION="cn-north-1" + +_JD_ACCOUNT="https://uc.jdcloud.com/account/accesskey" + +_JD_PROD="clouddnsservice" +_JD_API="jdcloud-api.com" + +_JD_API_VERSION="v1" +_JD_DEFAULT_REGION="cn-north-1" + +_JD_HOST="$_JD_PROD.$_JD_API" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_jd_add() { + fulldomain=$1 + txtvalue=$2 + + JD_ACCESS_KEY_ID="${JD_ACCESS_KEY_ID:-$(_readaccountconf_mutable JD_ACCESS_KEY_ID)}" + JD_ACCESS_KEY_SECRET="${JD_ACCESS_KEY_SECRET:-$(_readaccountconf_mutable JD_ACCESS_KEY_SECRET)}" + JD_REGION="${JD_REGION:-$(_readaccountconf_mutable JD_REGION)}" + + if [ -z "$JD_ACCESS_KEY_ID" ] || [ -z "$JD_ACCESS_KEY_SECRET" ]; then + JD_ACCESS_KEY_ID="" + JD_ACCESS_KEY_SECRET="" + _err "You haven't specifed the jdcloud api key id or api key secret yet." + _err "Please create your key and try again. see $(__green $_JD_ACCOUNT)" + return 1 + fi + + _saveaccountconf_mutable JD_ACCESS_KEY_ID "$JD_ACCESS_KEY_ID" + _saveaccountconf_mutable JD_ACCESS_KEY_SECRET "$JD_ACCESS_KEY_SECRET" + if [ -z "$JD_REGION" ]; then + _debug "Using default region: $_JD_DEFAULT_REGION" + JD_REGION="$_JD_DEFAULT_REGION" + else + _saveaccountconf_mutable JD_REGION "$JD_REGION" + fi + _JD_BASE_URI="$_JD_API_VERSION/regions/$JD_REGION" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + #_debug "Getting getViewTree" + + _debug "Adding records" + + _addrr="{\"req\":{\"hostRecord\":\"$_sub_domain\",\"hostValue\":\"$txtvalue\",\"ttl\":300,\"type\":\"TXT\",\"viewValue\":-1},\"regionId\":\"$JD_REGION\",\"domainId\":\"$_domain_id\"}" + #_addrr='{"req":{"hostRecord":"xx","hostValue":"\"value4\"","jcloudRes":false,"mxPriority":null,"port":null,"ttl":300,"type":"TXT","weight":null,"viewValue":-1},"regionId":"cn-north-1","domainId":"8824"}' + if jd_rest POST "domain/$_domain_id/RRAdd" "" "$_addrr"; then + _rid="$(echo "$response" | tr '{},' '\n' | grep '"id":' | cut -d : -f 2)" + if [ -z "$_rid" ]; then + _err "Can not find record id from the result." + return 1 + fi + _info "TXT record added successfully." + _srid="$(_readdomainconf "JD_CLOUD_RIDS")" + if [ "$_srid" ]; then + _rid="$_srid,$_rid" + fi + _savedomainconf "JD_CLOUD_RIDS" "$_rid" + return 0 + fi + + return 1 +} + +dns_jd_rm() { + fulldomain=$1 + txtvalue=$2 + + JD_ACCESS_KEY_ID="${JD_ACCESS_KEY_ID:-$(_readaccountconf_mutable JD_ACCESS_KEY_ID)}" + JD_ACCESS_KEY_SECRET="${JD_ACCESS_KEY_SECRET:-$(_readaccountconf_mutable JD_ACCESS_KEY_SECRET)}" + JD_REGION="${JD_REGION:-$(_readaccountconf_mutable JD_REGION)}" + + if [ -z "$JD_REGION" ]; then + _debug "Using default region: $_JD_DEFAULT_REGION" + JD_REGION="$_JD_DEFAULT_REGION" + fi + + _JD_BASE_URI="$_JD_API_VERSION/regions/$JD_REGION" + + _info "Getting existing records for $fulldomain" + _srid="$(_readdomainconf "JD_CLOUD_RIDS")" + _debug _srid "$_srid" + + if [ -z "$_srid" ]; then + _err "Not rid skip" + return 0 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _cleardomainconf JD_CLOUD_RIDS + + _aws_tmpl_xml="{\"ids\":[$_srid],\"action\":\"del\",\"regionId\":\"$JD_REGION\",\"domainId\":\"$_domain_id\"}" + + if jd_rest POST "domain/$_domain_id/RROperate" "" "$_aws_tmpl_xml" && _contains "$response" "\"code\":\"OK\""; then + _info "TXT record deleted successfully." + return 0 + fi + return 1 + +} + +#################### Private functions below ################################## + +_get_root() { + domain=$1 + i=1 + p=1 + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug2 "Checking domain: $h" + if ! jd_rest GET "domain"; then + _err "error get domain list" + return 1 + fi + if [ -z "$h" ]; then + #not valid + _err "Invalid domain" + return 1 + fi + + if _contains "$response" "\"domainName\":\"$h\""; then + hostedzone="$(echo "$response" | tr '{}' '\n' | grep "\"domainName\":\"$h\"")" + _debug hostedzone "$hostedzone" + if [ "$hostedzone" ]; then + _domain_id="$(echo "$hostedzone" | tr ',' '\n' | grep "\"id\":" | cut -d : -f 2)" + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + fi + _err "Can't find domain with id: $h" + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + + return 1 +} + +#method uri qstr data +jd_rest() { + mtd="$1" + ep="$2" + qsr="$3" + data="$4" + + _debug mtd "$mtd" + _debug ep "$ep" + _debug qsr "$qsr" + _debug data "$data" + + CanonicalURI="/$_JD_BASE_URI/$ep" + _debug2 CanonicalURI "$CanonicalURI" + + CanonicalQueryString="$qsr" + _debug2 CanonicalQueryString "$CanonicalQueryString" + + RequestDate="$(date -u +"%Y%m%dT%H%M%SZ")" + #RequestDate="20190713T082155Z" ###################################################### + _debug2 RequestDate "$RequestDate" + export _H1="X-Jdcloud-Date: $RequestDate" + + RequestNonce="2bd0852a-8bae-4087-b2d5-$(_time)" + #RequestNonce="894baff5-72d4-4244-883a-7b2eb51e7fbe" ################################# + _debug2 RequestNonce "$RequestNonce" + export _H2="X-Jdcloud-Nonce: $RequestNonce" + + if [ "$data" ]; then + CanonicalHeaders="content-type:application/json\n" + SignedHeaders="content-type;" + else + CanonicalHeaders="" + SignedHeaders="" + fi + CanonicalHeaders="${CanonicalHeaders}host:$_JD_HOST\nx-jdcloud-date:$RequestDate\nx-jdcloud-nonce:$RequestNonce\n" + SignedHeaders="${SignedHeaders}host;x-jdcloud-date;x-jdcloud-nonce" + + _debug2 CanonicalHeaders "$CanonicalHeaders" + _debug2 SignedHeaders "$SignedHeaders" + + Hash="sha256" + + RequestPayload="$data" + _debug2 RequestPayload "$RequestPayload" + + RequestPayloadHash="$(printf "%s" "$RequestPayload" | _digest "$Hash" hex | _lower_case)" + _debug2 RequestPayloadHash "$RequestPayloadHash" + + CanonicalRequest="$mtd\n$CanonicalURI\n$CanonicalQueryString\n$CanonicalHeaders\n$SignedHeaders\n$RequestPayloadHash" + _debug2 CanonicalRequest "$CanonicalRequest" + + HashedCanonicalRequest="$(printf "$CanonicalRequest%s" | _digest "$Hash" hex)" + _debug2 HashedCanonicalRequest "$HashedCanonicalRequest" + + Algorithm="JDCLOUD2-HMAC-SHA256" + _debug2 Algorithm "$Algorithm" + + RequestDateOnly="$(echo "$RequestDate" | cut -c 1-8)" + _debug2 RequestDateOnly "$RequestDateOnly" + + Region="$JD_REGION" + Service="$_JD_PROD" + + CredentialScope="$RequestDateOnly/$Region/$Service/jdcloud2_request" + _debug2 CredentialScope "$CredentialScope" + + StringToSign="$Algorithm\n$RequestDate\n$CredentialScope\n$HashedCanonicalRequest" + + _debug2 StringToSign "$StringToSign" + + kSecret="JDCLOUD2$JD_ACCESS_KEY_SECRET" + + _secure_debug2 kSecret "$kSecret" + + kSecretH="$(printf "%s" "$kSecret" | _hex_dump | tr -d " ")" + _secure_debug2 kSecretH "$kSecretH" + + kDateH="$(printf "$RequestDateOnly%s" | _hmac "$Hash" "$kSecretH" hex)" + _debug2 kDateH "$kDateH" + + kRegionH="$(printf "$Region%s" | _hmac "$Hash" "$kDateH" hex)" + _debug2 kRegionH "$kRegionH" + + kServiceH="$(printf "$Service%s" | _hmac "$Hash" "$kRegionH" hex)" + _debug2 kServiceH "$kServiceH" + + kSigningH="$(printf "%s" "jdcloud2_request" | _hmac "$Hash" "$kServiceH" hex)" + _debug2 kSigningH "$kSigningH" + + signature="$(printf "$StringToSign%s" | _hmac "$Hash" "$kSigningH" hex)" + _debug2 signature "$signature" + + Authorization="$Algorithm Credential=$JD_ACCESS_KEY_ID/$CredentialScope, SignedHeaders=$SignedHeaders, Signature=$signature" + _debug2 Authorization "$Authorization" + + _H3="Authorization: $Authorization" + _debug _H3 "$_H3" + + url="https://$_JD_HOST$CanonicalURI" + if [ "$qsr" ]; then + url="https://$_JD_HOST$CanonicalURI?$qsr" + fi + + if [ "$mtd" = "GET" ]; then + response="$(_get "$url")" + else + response="$(_post "$data" "$url" "" "$mtd" "application/json")" + fi + + _ret="$?" + _debug2 response "$response" + if [ "$_ret" = "0" ]; then + if _contains "$response" "\"error\""; then + _err "Response error:$response" + return 1 + fi + fi + + return "$_ret" +} diff --git a/letsencrypt/dnsapi/dns_joker.sh b/letsencrypt/dnsapi/dns_joker.sh new file mode 100644 index 00000000..2d32274a --- /dev/null +++ b/letsencrypt/dnsapi/dns_joker.sh @@ -0,0 +1,129 @@ +#!/bin/bash + +# Joker.com API for acme.sh +# +# This script adds the necessary TXT record to a domain in Joker.com. +# +# You must activate Dynamic DNS in Joker.com DNS configuration first. +# Username and password below refer to Dynamic DNS authentication, +# not your Joker.com login credentials. +# See: https://joker.com/faq/content/11/427/en/what-is-dynamic-dns-dyndns.html +# +# NOTE: This script does not support wildcard certificates, because +# Joker.com API does not support adding two TXT records with the same +# subdomain. Adding the second record will overwrite the first one. +# See: https://joker.com/faq/content/6/496/en/let_s-encrypt-support.html +# "... this request will replace all TXT records for the specified +# label by the provided content" +# +# Author: aattww (https://github.com/aattww/) +# +# Report bugs to https://github.com/acmesh-official/acme.sh/issues/2840 +# +# JOKER_USERNAME="xxxx" +# JOKER_PASSWORD="xxxx" + +JOKER_API="https://svc.joker.com/nic/replace" + +######## Public functions ##################### + +#Usage: dns_joker_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_joker_add() { + fulldomain=$1 + txtvalue=$2 + + JOKER_USERNAME="${JOKER_USERNAME:-$(_readaccountconf_mutable JOKER_USERNAME)}" + JOKER_PASSWORD="${JOKER_PASSWORD:-$(_readaccountconf_mutable JOKER_PASSWORD)}" + + if [ -z "$JOKER_USERNAME" ] || [ -z "$JOKER_PASSWORD" ]; then + _err "No Joker.com username and password specified." + return 1 + fi + + _saveaccountconf_mutable JOKER_USERNAME "$JOKER_USERNAME" + _saveaccountconf_mutable JOKER_PASSWORD "$JOKER_PASSWORD" + + if ! _get_root "$fulldomain"; then + _err "Invalid domain" + return 1 + fi + + _info "Adding TXT record" + if _joker_rest "username=$JOKER_USERNAME&password=$JOKER_PASSWORD&zone=$_domain&label=$_sub_domain&type=TXT&value=$txtvalue"; then + if _startswith "$response" "OK"; then + _info "Added, OK" + return 0 + fi + fi + _err "Error adding TXT record." + return 1 +} + +#fulldomain txtvalue +dns_joker_rm() { + fulldomain=$1 + txtvalue=$2 + + JOKER_USERNAME="${JOKER_USERNAME:-$(_readaccountconf_mutable JOKER_USERNAME)}" + JOKER_PASSWORD="${JOKER_PASSWORD:-$(_readaccountconf_mutable JOKER_PASSWORD)}" + + if ! _get_root "$fulldomain"; then + _err "Invalid domain" + return 1 + fi + + _info "Removing TXT record" + # TXT record is removed by setting its value to empty. + if _joker_rest "username=$JOKER_USERNAME&password=$JOKER_PASSWORD&zone=$_domain&label=$_sub_domain&type=TXT&value="; then + if _startswith "$response" "OK"; then + _info "Removed, OK" + return 0 + fi + fi + _err "Error removing TXT record." + return 1 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + fulldomain=$1 + i=1 + while true; do + h=$(printf "%s" "$fulldomain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + return 1 + fi + + # Try to remove a test record. With correct root domain, username and password this will return "OK: ..." regardless + # of record in question existing or not. + if _joker_rest "username=$JOKER_USERNAME&password=$JOKER_PASSWORD&zone=$h&label=jokerTXTUpdateTest&type=TXT&value="; then + if _startswith "$response" "OK"; then + _sub_domain="$(echo "$fulldomain" | sed "s/\\.$h\$//")" + _domain=$h + return 0 + fi + fi + + i=$(_math "$i" + 1) + done + + _debug "Root domain not found" + return 1 +} + +_joker_rest() { + data="$1" + _debug data "$data" + + if ! response="$(_post "$data" "$JOKER_API" "" "POST")"; then + _err "Error POSTing" + return 1 + fi + _debug response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_kappernet.sh b/letsencrypt/dnsapi/dns_kappernet.sh new file mode 100644 index 00000000..8fb78ecf --- /dev/null +++ b/letsencrypt/dnsapi/dns_kappernet.sh @@ -0,0 +1,150 @@ +#!/bin/bash + +# kapper.net domain api +# for further questions please contact: support@kapper.net +# please report issues here: https://github.com/acmesh-official/acme.sh/issues/2977 + +#KAPPERNETDNS_Key="yourKAPPERNETapikey" +#KAPPERNETDNS_Secret="yourKAPPERNETapisecret" + +KAPPERNETDNS_Api="https://dnspanel.kapper.net/API/1.2?APIKey=$KAPPERNETDNS_Key&APISecret=$KAPPERNETDNS_Secret" + +############################################################################### +# called with +# fullhostname: something.example.com +# txtvalue: someacmegenerated string +dns_kappernet_add() { + fullhostname=$1 + txtvalue=$2 + + KAPPERNETDNS_Key="${KAPPERNETDNS_Key:-$(_readaccountconf_mutable KAPPERNETDNS_Key)}" + KAPPERNETDNS_Secret="${KAPPERNETDNS_Secret:-$(_readaccountconf_mutable KAPPERNETDNS_Secret)}" + + if [ -z "$KAPPERNETDNS_Key" ] || [ -z "$KAPPERNETDNS_Secret" ]; then + KAPPERNETDNS_Key="" + KAPPERNETDNS_Secret="" + _err "Please specify your kapper.net api key and secret." + _err "If you have not received yours - send your mail to" + _err "support@kapper.net to get your key and secret." + return 1 + fi + + #store the api key and email to the account conf file. + _saveaccountconf_mutable KAPPERNETDNS_Key "$KAPPERNETDNS_Key" + _saveaccountconf_mutable KAPPERNETDNS_Secret "$KAPPERNETDNS_Secret" + _debug "Checking Domain ..." + if ! _get_root "$fullhostname"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "SUBDOMAIN: $_sub_domain" + _debug _domain "DOMAIN: $_domain" + + _info "Trying to add TXT DNS Record" + data="%7B%22name%22%3A%22$fullhostname%22%2C%22type%22%3A%22TXT%22%2C%22content%22%3A%22$txtvalue%22%2C%22ttl%22%3A%223600%22%2C%22prio%22%3A%22%22%7D" + if _kappernet_api GET "action=new&subject=$_domain&data=$data"; then + + if _contains "$response" "{\"OK\":true"; then + _info "Waiting 120 seconds for DNS to spread the new record" + _sleep 120 + return 0 + else + _err "Error creating a TXT DNS Record: $fullhostname TXT $txtvalue" + _err "Error Message: $response" + return 1 + fi + fi + _err "Failed creating TXT Record" +} + +############################################################################### +# called with +# fullhostname: something.example.com +dns_kappernet_rm() { + fullhostname=$1 + txtvalue=$2 + + KAPPERNETDNS_Key="${KAPPERNETDNS_Key:-$(_readaccountconf_mutable KAPPERNETDNS_Key)}" + KAPPERNETDNS_Secret="${KAPPERNETDNS_Secret:-$(_readaccountconf_mutable KAPPERNETDNS_Secret)}" + + if [ -z "$KAPPERNETDNS_Key" ] || [ -z "$KAPPERNETDNS_Secret" ]; then + KAPPERNETDNS_Key="" + KAPPERNETDNS_Secret="" + _err "Please specify your kapper.net api key and secret." + _err "If you have not received yours - send your mail to" + _err "support@kapper.net to get your key and secret." + return 1 + fi + + #store the api key and email to the account conf file. + _saveaccountconf_mutable KAPPERNETDNS_Key "$KAPPERNETDNS_Key" + _saveaccountconf_mutable KAPPERNETDNS_Secret "$KAPPERNETDNS_Secret" + + _info "Trying to remove the TXT Record: $fullhostname containing $txtvalue" + data="%7B%22name%22%3A%22$fullhostname%22%2C%22type%22%3A%22TXT%22%2C%22content%22%3A%22$txtvalue%22%2C%22ttl%22%3A%223600%22%2C%22prio%22%3A%22%22%7D" + if _kappernet_api GET "action=del&subject=$fullhostname&data=$data"; then + if _contains "$response" "{\"OK\":true"; then + return 0 + else + _err "Error deleting DNS Record: $fullhostname containing $txtvalue" + _err "Problem: $response" + return 1 + fi + fi + _err "Problem deleting TXT DNS record" +} + +#################### Private functions below ################################## +# called with hostname +# e.g._acme-challenge.www.domain.com returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + #not valid + return 1 + fi + if ! _kappernet_api GET "action=list&subject=$h"; then + return 1 + fi + if _contains "$response" '"OK":false'; then + _debug "$h not found" + else + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p="$i" + i=$(_math "$i" + 1) + done + return 1 +} + +################################################################################ +# calls the kapper.net DNS Panel API +# with +# method +# param +_kappernet_api() { + method=$1 + param="$2" + + _debug param "PARAMETER=$param" + url="$KAPPERNETDNS_Api&$param" + _debug url "URL=$url" + + if [ "$method" = "GET" ]; then + response="$(_get "$url")" + else + _err "Unsupported method" + return 1 + fi + + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_kas.sh b/letsencrypt/dnsapi/dns_kas.sh new file mode 100755 index 00000000..54a051dd --- /dev/null +++ b/letsencrypt/dnsapi/dns_kas.sh @@ -0,0 +1,168 @@ +#!/bin/bash +######################################################################## +# All-inkl Kasserver hook script for acme.sh +# +# Environment variables: +# +# - $KAS_Login (Kasserver API login name) +# - $KAS_Authtype (Kasserver API auth type. Default: sha1) +# - $KAS_Authdata (Kasserver API auth data.) +# +# Author: Martin Kammerlander, Phlegx Systems OG +# Updated by: Marc-Oliver Lange +# Credits: Inspired by dns_he.sh. Thanks a lot man! +# Git repo: https://github.com/phlegx/acme.sh +# TODO: Better Error handling +######################################################################## +KAS_Api="https://kasapi.kasserver.com/dokumentation/formular.php" +######## Public functions ##################### +dns_kas_add() { + _fulldomain=$1 + _txtvalue=$2 + _info "Using DNS-01 All-inkl/Kasserver hook" + _info "Adding $_fulldomain DNS TXT entry on All-inkl/Kasserver" + _info "Check and Save Props" + _check_and_save + _info "Checking Zone and Record_Name" + _get_zone_and_record_name "$_fulldomain" + _info "Getting Record ID" + _get_record_id + + _info "Creating TXT DNS record" + params="?kas_login=$KAS_Login" + params="$params&kas_auth_type=$KAS_Authtype" + params="$params&kas_auth_data=$KAS_Authdata" + params="$params&var1=record_name" + params="$params&wert1=$_record_name" + params="$params&var2=record_type" + params="$params&wert2=TXT" + params="$params&var3=record_data" + params="$params&wert3=$_txtvalue" + params="$params&var4=record_aux" + params="$params&wert4=0" + params="$params&kas_action=add_dns_settings" + params="$params&var5=zone_host" + params="$params&wert5=$_zone" + _debug2 "Wait for 10 seconds by default before calling KAS API." + _sleep 10 + response="$(_get "$KAS_Api$params")" + _debug2 "response" "$response" + + if ! _contains "$response" "TRUE"; then + _err "An unkown error occurred, please check manually." + return 1 + fi + return 0 +} + +dns_kas_rm() { + _fulldomain=$1 + _txtvalue=$2 + _info "Using DNS-01 All-inkl/Kasserver hook" + _info "Cleaning up after All-inkl/Kasserver hook" + _info "Removing $_fulldomain DNS TXT entry on All-inkl/Kasserver" + + _info "Check and Save Props" + _check_and_save + _info "Checking Zone and Record_Name" + _get_zone_and_record_name "$_fulldomain" + _info "Getting Record ID" + _get_record_id + + # If there is a record_id, delete the entry + if [ -n "$_record_id" ]; then + params="?kas_login=$KAS_Login" + params="$params&kas_auth_type=$KAS_Authtype" + params="$params&kas_auth_data=$KAS_Authdata" + params="$params&kas_action=delete_dns_settings" + + for i in $_record_id; do + params2="$params&var1=record_id" + params2="$params2&wert1=$i" + _debug2 "Wait for 10 seconds by default before calling KAS API." + _sleep 10 + response="$(_get "$KAS_Api$params2")" + _debug2 "response" "$response" + if ! _contains "$response" "TRUE"; then + _err "Either the txt record is not found or another error occurred, please check manually." + return 1 + fi + done + else # Cannot delete or unkown error + _err "No record_id found that can be deleted. Please check manually." + return 1 + fi + return 0 +} + +########################## PRIVATE FUNCTIONS ########################### + +# Checks for the ENV variables and saves them +_check_and_save() { + KAS_Login="${KAS_Login:-$(_readaccountconf_mutable KAS_Login)}" + KAS_Authtype="${KAS_Authtype:-$(_readaccountconf_mutable KAS_Authtype)}" + KAS_Authdata="${KAS_Authdata:-$(_readaccountconf_mutable KAS_Authdata)}" + + if [ -z "$KAS_Login" ] || [ -z "$KAS_Authtype" ] || [ -z "$KAS_Authdata" ]; then + KAS_Login= + KAS_Authtype= + KAS_Authdata= + _err "No auth details provided. Please set user credentials using the \$KAS_Login, \$KAS_Authtype, and \$KAS_Authdata environment variables." + return 1 + fi + _saveaccountconf_mutable KAS_Login "$KAS_Login" + _saveaccountconf_mutable KAS_Authtype "$KAS_Authtype" + _saveaccountconf_mutable KAS_Authdata "$KAS_Authdata" + return 0 +} + +# Gets back the base domain/zone and record name. +# See: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide +_get_zone_and_record_name() { + params="?kas_login=$KAS_Login" + params="?kas_login=$KAS_Login" + params="$params&kas_auth_type=$KAS_Authtype" + params="$params&kas_auth_data=$KAS_Authdata" + params="$params&kas_action=get_domains" + + _debug2 "Wait for 10 seconds by default before calling KAS API." + _sleep 10 + response="$(_get "$KAS_Api$params")" + _debug2 "response" "$response" + _zonen="$(echo "$response" | tr -d "\n\r" | tr -d " " | tr '[]' '<>' | sed "s/=>Array/\n=> Array/g" | tr ' ' '\n' | grep "domain_name" | tr '<' '\n' | grep "domain_name" | sed "s/domain_name>=>//g")" + _domain="$1" + _temp_domain="$(echo "$1" | sed 's/\.$//')" + _rootzone="$_domain" + for i in $_zonen; do + l1=${#_rootzone} + l2=${#i} + if _endswith "$_domain" "$i" && [ "$l1" -ge "$l2" ]; then + _rootzone="$i" + fi + done + _zone="${_rootzone}." + _temp_record_name="$(echo "$_temp_domain" | sed "s/$_rootzone//g")" + _record_name="$(echo "$_temp_record_name" | sed 's/\.$//')" + _debug2 "Zone:" "$_zone" + _debug2 "Domain:" "$_domain" + _debug2 "Record_Name:" "$_record_name" + return 0 +} + +# Retrieve the DNS record ID +_get_record_id() { + params="?kas_login=$KAS_Login" + params="$params&kas_auth_type=$KAS_Authtype" + params="$params&kas_auth_data=$KAS_Authdata" + params="$params&kas_action=get_dns_settings" + params="$params&var1=zone_host" + params="$params&wert1=$_zone" + + _debug2 "Wait for 10 seconds by default before calling KAS API." + _sleep 10 + response="$(_get "$KAS_Api$params")" + _debug2 "response" "$response" + _record_id="$(echo "$response" | tr -d "\n\r" | tr -d " " | tr '[]' '<>' | sed "s/=>Array/\n=> Array/g" | tr ' ' '\n' | grep "=>$_record_name<" | grep '>TXT<' | tr '<' '\n' | grep record_id | sed "s/record_id>=>//g")" + _debug2 _record_id "$_record_id" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_kinghost.sh b/letsencrypt/dnsapi/dns_kinghost.sh new file mode 100644 index 00000000..e38715f1 --- /dev/null +++ b/letsencrypt/dnsapi/dns_kinghost.sh @@ -0,0 +1,107 @@ +#!/bin/bash + +############################################################ +# KingHost API support # +# http://api.kinghost.net/doc/ # +# # +# Author: Felipe Keller Braz # +# Report Bugs here: https://github.com/kinghost/acme.sh # +# # +# Values to export: # +# export KINGHOST_Username="email@provider.com" # +# export KINGHOST_Password="xxxxxxxxxx" # +############################################################ + +KING_Api="https://api.kinghost.net/acme" + +# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Used to add txt record +dns_kinghost_add() { + fulldomain=$1 + txtvalue=$2 + + KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}" + KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" + if [ -z "$KINGHOST_Username" ] || [ -z "$KINGHOST_Password" ]; then + KINGHOST_Username="" + KINGHOST_Password="" + _err "You don't specify KingHost api password and email yet." + _err "Please create you key and try again." + return 1 + fi + + #save the credentials to the account conf file. + _saveaccountconf_mutable KINGHOST_Username "$KINGHOST_Username" + _saveaccountconf_mutable KINGHOST_Password "$KINGHOST_Password" + + _debug "Getting txt records" + _kinghost_rest GET "dns" "name=$fulldomain&content=$txtvalue" + + #This API call returns "status":"ok" if dns record does not exist + #We are creating a new txt record here, so we expect the "ok" status + if ! echo "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + _kinghost_rest POST "dns" "name=$fulldomain&content=$txtvalue" + if ! echo "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + return 0 +} + +# Usage: fulldomain txtvalue +# Used to remove the txt record after validation +dns_kinghost_rm() { + fulldomain=$1 + txtvalue=$2 + + KINGHOST_Password="${KINGHOST_Password:-$(_readaccountconf_mutable KINGHOST_Password)}" + KINGHOST_Username="${KINGHOST_Username:-$(_readaccountconf_mutable KINGHOST_Username)}" + if [ -z "$KINGHOST_Password" ] || [ -z "$KINGHOST_Username" ]; then + KINGHOST_Password="" + KINGHOST_Username="" + _err "You don't specify KingHost api key and email yet." + _err "Please create you key and try again." + return 1 + fi + + _kinghost_rest DELETE "dns" "name=$fulldomain&content=$txtvalue" + if ! echo "$response" | grep '"status":"ok"' >/dev/null; then + _err "Error" + _err "$response" + return 1 + fi + + return 0 +} + +#################### Private functions below ################################## +_kinghost_rest() { + method=$1 + uri="$2" + data="$3" + _debug "$uri" + + export _H1="X-Auth-Email: $KINGHOST_Username" + export _H2="X-Auth-Key: $KINGHOST_Password" + + if [ "$method" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$KING_Api/$uri.json" "" "$method")" + else + response="$(_get "$KING_Api/$uri.json?$data")" + fi + + if [ "$?" != "0" ]; then + _err "error $uri" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_knot.sh b/letsencrypt/dnsapi/dns_knot.sh new file mode 100644 index 00000000..d610f927 --- /dev/null +++ b/letsencrypt/dnsapi/dns_knot.sh @@ -0,0 +1,95 @@ +#!/bin/bash + +######## Public functions ##################### + +#Usage: dns_knot_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_knot_add() { + fulldomain=$1 + txtvalue=$2 + _checkKey || return 1 + [ -n "${KNOT_SERVER}" ] || KNOT_SERVER="localhost" + # save the dns server and key to the account.conf file. + _saveaccountconf KNOT_SERVER "${KNOT_SERVER}" + _saveaccountconf KNOT_KEY "${KNOT_KEY}" + + if ! _get_root "$fulldomain"; then + _err "Domain does not exist." + return 1 + fi + + _info "Adding ${fulldomain}. 60 TXT \"${txtvalue}\"" + + knsupdate -y "${KNOT_KEY}" < +#Utilize leaseweb.com API to finish dns-01 verifications. +#Requires a Leaseweb API Key (export LSW_Key="Your Key") +#See http://developer.leaseweb.com for more information. +######## Public functions ##################### + +LSW_API="https://api.leaseweb.com/hosting/v2/domains/" + +#Usage: dns_leaseweb_add _acme-challenge.www.domain.com +dns_leaseweb_add() { + fulldomain=$1 + txtvalue=$2 + + LSW_Key="${LSW_Key:-$(_readaccountconf_mutable LSW_Key)}" + if [ -z "$LSW_Key" ]; then + LSW_Key="" + _err "You don't specify Leaseweb api key yet." + _err "Please create your key and try again." + return 1 + fi + + #save the api key to the account conf file. + _saveaccountconf_mutable LSW_Key "$LSW_Key" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _root_domain "$_domain" + _debug _domain "$fulldomain" + + if _lsw_api "POST" "$_domain" "$fulldomain" "$txtvalue"; then + if [ "$_code" = "201" ]; then + _info "Added, OK" + return 0 + else + _err "Add txt record error, invalid code. Code: $_code" + return 1 + fi + fi + _err "Add txt record error." + + return 1 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_leaseweb_rm() { + fulldomain=$1 + txtvalue=$2 + + LSW_Key="${LSW_Key:-$(_readaccountconf_mutable LSW_Key)}" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _root_domain "$_domain" + _debug _domain "$fulldomain" + + if _lsw_api "DELETE" "$_domain" "$fulldomain" "$txtvalue"; then + if [ "$_code" = "204" ]; then + _info "Deleted, OK" + return 0 + else + _err "Delete txt record error." + return 1 + fi + fi + _err "Delete txt record error." + + return 1 +} + +#################### Private functions below ################################## +# _acme-challenge.www.domain.com +# returns +# _domain=domain.com +_get_root() { + rdomain=$1 + i="$(echo "$rdomain" | tr '.' ' ' | wc -w)" + i=$(_math "$i" - 1) + + while true; do + h=$(printf "%s" "$rdomain" | cut -d . -f "$i"-100) + _debug h "$h" + if [ -z "$h" ]; then + return 1 #not valid domain + fi + + #Check API if domain exists + if _lsw_api "GET" "$h"; then + if [ "$_code" = "200" ]; then + _domain="$h" + return 0 + fi + fi + i=$(_math "$i" - 1) + if [ "$i" -lt 2 ]; then + return 1 #not found, no need to check _acme-challenge.sub.domain in leaseweb api. + fi + done + + return 1 +} + +_lsw_api() { + cmd=$1 + d=$2 + fd=$3 + tvalue=$4 + + # Construct the HTTP Authorization header + export _H2="Content-Type: application/json" + export _H1="X-Lsw-Auth: ${LSW_Key}" + + if [ "$cmd" = "GET" ]; then + response="$(_get "$LSW_API/$d")" + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" + _debug "http response code $_code" + _debug response "$response" + return 0 + fi + + if [ "$cmd" = "POST" ]; then + data="{\"name\": \"$fd.\",\"type\": \"TXT\",\"content\": [\"$tvalue\"],\"ttl\": 60}" + response="$(_post "$data" "$LSW_API/$d/resourceRecordSets" "$data" "POST")" + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" + _debug "http response code $_code" + _debug response "$response" + return 0 + fi + + if [ "$cmd" = "DELETE" ]; then + response="$(_post "" "$LSW_API/$d/resourceRecordSets/$fd/TXT" "" "DELETE")" + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" + _debug "http response code $_code" + _debug response "$response" + return 0 + fi + + return 1 +} diff --git a/letsencrypt/dnsapi/dns_lexicon.sh b/letsencrypt/dnsapi/dns_lexicon.sh new file mode 100755 index 00000000..99c461c7 --- /dev/null +++ b/letsencrypt/dnsapi/dns_lexicon.sh @@ -0,0 +1,113 @@ +#!/bin/bash + +# dns api wrapper of lexicon for acme.sh + +# https://github.com/AnalogJ/lexicon +lexicon_cmd="lexicon" + +wiki="https://github.com/acmesh-official/acme.sh/wiki/How-to-use-lexicon-dns-api" + +_lexicon_init() { + if ! _exists "$lexicon_cmd"; then + _err "Please install $lexicon_cmd first: $wiki" + return 1 + fi + + PROVIDER="${PROVIDER:-$(_readdomainconf PROVIDER)}" + if [ -z "$PROVIDER" ]; then + PROVIDER="" + _err "Please define env PROVIDER first: $wiki" + return 1 + fi + + _savedomainconf PROVIDER "$PROVIDER" + export PROVIDER + + # e.g. busybox-ash does not know [:upper:] + # shellcheck disable=SC2018,SC2019 + Lx_name=$(echo LEXICON_"${PROVIDER}"_USERNAME | tr 'a-z' 'A-Z') + eval "$Lx_name=\${$Lx_name:-$(_readaccountconf_mutable "$Lx_name")}" + Lx_name_v=$(eval echo \$"$Lx_name") + _secure_debug "$Lx_name" "$Lx_name_v" + if [ "$Lx_name_v" ]; then + _saveaccountconf_mutable "$Lx_name" "$Lx_name_v" + eval export "$Lx_name" + fi + + # shellcheck disable=SC2018,SC2019 + Lx_token=$(echo LEXICON_"${PROVIDER}"_TOKEN | tr 'a-z' 'A-Z') + eval "$Lx_token=\${$Lx_token:-$(_readaccountconf_mutable "$Lx_token")}" + Lx_token_v=$(eval echo \$"$Lx_token") + _secure_debug "$Lx_token" "$Lx_token_v" + if [ "$Lx_token_v" ]; then + _saveaccountconf_mutable "$Lx_token" "$Lx_token_v" + eval export "$Lx_token" + fi + + # shellcheck disable=SC2018,SC2019 + Lx_password=$(echo LEXICON_"${PROVIDER}"_PASSWORD | tr 'a-z' 'A-Z') + eval "$Lx_password=\${$Lx_password:-$(_readaccountconf_mutable "$Lx_password")}" + Lx_password_v=$(eval echo \$"$Lx_password") + _secure_debug "$Lx_password" "$Lx_password_v" + if [ "$Lx_password_v" ]; then + _saveaccountconf_mutable "$Lx_password" "$Lx_password_v" + eval export "$Lx_password" + fi + + # shellcheck disable=SC2018,SC2019 + Lx_domaintoken=$(echo LEXICON_"${PROVIDER}"_DOMAINTOKEN | tr 'a-z' 'A-Z') + eval "$Lx_domaintoken=\${$Lx_domaintoken:-$(_readaccountconf_mutable "$Lx_domaintoken")}" + Lx_domaintoken_v=$(eval echo \$"$Lx_domaintoken") + _secure_debug "$Lx_domaintoken" "$Lx_domaintoken_v" + if [ "$Lx_domaintoken_v" ]; then + _saveaccountconf_mutable "$Lx_domaintoken" "$Lx_domaintoken_v" + eval export "$Lx_domaintoken" + fi + + # shellcheck disable=SC2018,SC2019 + Lx_api_key=$(echo LEXICON_"${PROVIDER}"_API_KEY | tr 'a-z' 'A-Z') + eval "$Lx_api_key=\${$Lx_api_key:-$(_readaccountconf_mutable "$Lx_api_key")}" + Lx_api_key_v=$(eval echo \$"$Lx_api_key") + _secure_debug "$Lx_api_key" "$Lx_api_key_v" + if [ "$Lx_api_key_v" ]; then + _saveaccountconf_mutable "$Lx_api_key" "$Lx_api_key_v" + eval export "$Lx_api_key" + fi +} + +######## Public functions ##################### + +#Usage: dns_lexicon_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_lexicon_add() { + fulldomain=$1 + txtvalue=$2 + + if ! _lexicon_init; then + return 1 + fi + + domain=$(printf "%s" "$fulldomain" | cut -d . -f 2-999) + + _secure_debug LEXICON_OPTS "$LEXICON_OPTS" + _savedomainconf LEXICON_OPTS "$LEXICON_OPTS" + + # shellcheck disable=SC2086 + $lexicon_cmd "$PROVIDER" $LEXICON_OPTS create "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}" --output QUIET + +} + +#Usage: dns_lexicon_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_lexicon_rm() { + fulldomain=$1 + txtvalue=$2 + + if ! _lexicon_init; then + return 1 + fi + + domain=$(printf "%s" "$fulldomain" | cut -d . -f 2-999) + + # shellcheck disable=SC2086 + $lexicon_cmd "$PROVIDER" $LEXICON_OPTS delete "${domain}" TXT --name="_acme-challenge.${domain}." --content="${txtvalue}" --output QUIET + +} diff --git a/letsencrypt/dnsapi/dns_linode.sh b/letsencrypt/dnsapi/dns_linode.sh new file mode 100755 index 00000000..ef6a8de4 --- /dev/null +++ b/letsencrypt/dnsapi/dns_linode.sh @@ -0,0 +1,183 @@ +#!/bin/bash + +#Author: Philipp Grosswiler + +LINODE_API_URL="https://api.linode.com/?api_key=$LINODE_API_KEY&api_action=" + +######## Public functions ##################### + +#Usage: dns_linode_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_linode_add() { + fulldomain="${1}" + txtvalue="${2}" + + if ! _Linode_API; then + return 1 + fi + + _info "Using Linode" + _debug "Calling: dns_linode_add() '${fulldomain}' '${txtvalue}'" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "Domain does not exist." + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _parameters="&DomainID=$_domain_id&Type=TXT&Name=$_sub_domain&Target=$txtvalue" + + if _rest GET "domain.resource.create" "$_parameters" && [ -n "$response" ]; then + _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) + _debug _resource_id "$_resource_id" + + if [ -z "$_resource_id" ]; then + _err "Error adding the domain resource." + return 1 + fi + + _info "Domain resource successfully added." + return 0 + fi + + return 1 +} + +#Usage: dns_linode_rm _acme-challenge.www.domain.com +dns_linode_rm() { + fulldomain="${1}" + + if ! _Linode_API; then + return 1 + fi + + _info "Using Linode" + _debug "Calling: dns_linode_rm() '${fulldomain}'" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "Domain does not exist." + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _parameters="&DomainID=$_domain_id" + + if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then + response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" + + resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")" + if [ "$resource" ]; then + _resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"RESOURCEID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) + if [ "$_resource_id" ]; then + _debug _resource_id "$_resource_id" + + _parameters="&DomainID=$_domain_id&ResourceID=$_resource_id" + + if _rest GET "domain.resource.delete" "$_parameters" && [ -n "$response" ]; then + _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) + _debug _resource_id "$_resource_id" + + if [ -z "$_resource_id" ]; then + _err "Error deleting the domain resource." + return 1 + fi + + _info "Domain resource successfully deleted." + return 0 + fi + fi + + return 1 + fi + + return 0 + fi + + return 1 +} + +#################### Private functions below ################################## + +_Linode_API() { + if [ -z "$LINODE_API_KEY" ]; then + LINODE_API_KEY="" + + _err "You didn't specify the Linode API key yet." + _err "Please create your key and try again." + + return 1 + fi + + _saveaccountconf LINODE_API_KEY "$LINODE_API_KEY" +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=12345 +_get_root() { + domain=$1 + i=2 + p=1 + + if _rest GET "domain.list"; then + response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + hostedzone="$(echo "$response" | _egrep_o "{.*\"DOMAIN\":\s*\"$h\".*}")" + if [ "$hostedzone" ]; then + _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"DOMAINID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + fi + return 1 +} + +#method method action data +_rest() { + mtd="$1" + ep="$2" + data="$3" + + _debug mtd "$mtd" + _debug ep "$ep" + + export _H1="Accept: application/json" + export _H2="Content-Type: application/json" + + if [ "$mtd" != "GET" ]; then + # both POST and DELETE. + _debug data "$data" + response="$(_post "$data" "$LINODE_API_URL$ep" "" "$mtd")" + else + response="$(_get "$LINODE_API_URL$ep$data")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_linode_v4.sh b/letsencrypt/dnsapi/dns_linode_v4.sh new file mode 100755 index 00000000..15e51526 --- /dev/null +++ b/letsencrypt/dnsapi/dns_linode_v4.sh @@ -0,0 +1,186 @@ +#!/bin/bash + +#Original Author: Philipp Grosswiler +#v4 Update Author: Aaron W. Swenson + +LINODE_V4_API_URL="https://api.linode.com/v4/domains" + +######## Public functions ##################### + +#Usage: dns_linode_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_linode_v4_add() { + fulldomain="${1}" + txtvalue="${2}" + + if ! _Linode_API; then + return 1 + fi + + _info "Using Linode" + _debug "Calling: dns_linode_add() '${fulldomain}' '${txtvalue}'" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "Domain does not exist." + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _payload="{ + \"type\": \"TXT\", + \"name\": \"$_sub_domain\", + \"target\": \"$txtvalue\", + \"ttl_sec\": 300 + }" + + if _rest POST "/$_domain_id/records" "$_payload" && [ -n "$response" ]; then + _resource_id=$(printf "%s\n" "$response" | _egrep_o "\"id\": *[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) + _debug _resource_id "$_resource_id" + + if [ -z "$_resource_id" ]; then + _err "Error adding the domain resource." + return 1 + fi + + _info "Domain resource successfully added." + return 0 + fi + + return 1 +} + +#Usage: dns_linode_rm _acme-challenge.www.domain.com +dns_linode_v4_rm() { + fulldomain="${1}" + + if ! _Linode_API; then + return 1 + fi + + _info "Using Linode" + _debug "Calling: dns_linode_rm() '${fulldomain}'" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "Domain does not exist." + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + if _rest GET "/$_domain_id/records" && [ -n "$response" ]; then + response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" + + resource="$(echo "$response" | _egrep_o "\{.*\"name\": *\"$_sub_domain\".*}")" + if [ "$resource" ]; then + _resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"id\": *[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) + if [ "$_resource_id" ]; then + _debug _resource_id "$_resource_id" + + if _rest DELETE "/$_domain_id/records/$_resource_id" && [ -n "$response" ]; then + # On 200/OK, empty set is returned. Check for error, if any. + _error_response=$(printf "%s\n" "$response" | _egrep_o "\"errors\"" | cut -d : -f 2 | tr -d " " | _head_n 1) + + if [ -n "$_error_response" ]; then + _err "Error deleting the domain resource: $_error_response" + return 1 + fi + + _info "Domain resource successfully deleted." + return 0 + fi + fi + + return 1 + fi + + return 0 + fi + + return 1 +} + +#################### Private functions below ################################## + +_Linode_API() { + if [ -z "$LINODE_V4_API_KEY" ]; then + LINODE_V4_API_KEY="" + + _err "You didn't specify the Linode v4 API key yet." + _err "Please create your key and try again." + + return 1 + fi + + _saveaccountconf LINODE_V4_API_KEY "$LINODE_V4_API_KEY" +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=12345 +_get_root() { + domain=$1 + i=2 + p=1 + + if _rest GET; then + response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")" + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + hostedzone="$(echo "$response" | _egrep_o "\{.*\"domain\": *\"$h\".*}")" + if [ "$hostedzone" ]; then + _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\": *[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + fi + return 1 +} + +#method method action data +_rest() { + mtd="$1" + ep="$2" + data="$3" + + _debug mtd "$mtd" + _debug ep "$ep" + + export _H1="Accept: application/json" + export _H2="Content-Type: application/json" + export _H3="Authorization: Bearer $LINODE_V4_API_KEY" + + if [ "$mtd" != "GET" ]; then + # both POST and DELETE. + _debug data "$data" + response="$(_post "$data" "$LINODE_V4_API_URL$ep" "" "$mtd")" + else + response="$(_get "$LINODE_V4_API_URL$ep$data")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_loopia.sh b/letsencrypt/dnsapi/dns_loopia.sh new file mode 100644 index 00000000..e44e7ed9 --- /dev/null +++ b/letsencrypt/dnsapi/dns_loopia.sh @@ -0,0 +1,302 @@ +#!/bin/bash + +# +#LOOPIA_User="username" +# +#LOOPIA_Password="password" +# +#LOOPIA_Api="https://api.loopia./RPCSERV" + +LOOPIA_Api_Default="https://api.loopia.se/RPCSERV" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_loopia_add() { + fulldomain=$1 + txtvalue=$2 + + if ! _loopia_load_config; then + return 1 + fi + + _loopia_save_config + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _info "Adding record" + + _loopia_add_sub_domain "$_domain" "$_sub_domain" + _loopia_add_record "$_domain" "$_sub_domain" "$txtvalue" + +} + +dns_loopia_rm() { + fulldomain=$1 + txtvalue=$2 + + if ! _loopia_load_config; then + return 1 + fi + + _loopia_save_config + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + xml_content=$(printf ' + + removeSubdomain + + + %s + + + %s + + + %s + + + %s + + + ' "$LOOPIA_User" "$LOOPIA_Password" "$_domain" "$_sub_domain") + + response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" + + if ! _contains "$response" "OK"; then + _err "Error could not get txt records" + return 1 + fi +} + +#################### Private functions below ################################## + +_loopia_load_config() { + LOOPIA_Api="${LOOPIA_Api:-$(_readaccountconf_mutable LOOPIA_Api)}" + LOOPIA_User="${LOOPIA_User:-$(_readaccountconf_mutable LOOPIA_User)}" + LOOPIA_Password="${LOOPIA_Password:-$(_readaccountconf_mutable LOOPIA_Password)}" + + if [ -z "$LOOPIA_Api" ]; then + LOOPIA_Api="$LOOPIA_Api_Default" + fi + + if [ -z "$LOOPIA_User" ] || [ -z "$LOOPIA_Password" ]; then + LOOPIA_User="" + LOOPIA_Password="" + + _err "A valid Loopia API user and password not provided." + _err "Please provide a valid API user and try again." + + return 1 + fi + + return 0 +} + +_loopia_save_config() { + if [ "$LOOPIA_Api" != "$LOOPIA_Api_Default" ]; then + _saveaccountconf_mutable LOOPIA_Api "$LOOPIA_Api" + fi + _saveaccountconf_mutable LOOPIA_User "$LOOPIA_User" + _saveaccountconf_mutable LOOPIA_Password "$LOOPIA_Password" +} + +_loopia_get_records() { + domain=$1 + sub_domain=$2 + + xml_content=$(printf ' + + getZoneRecords + + + %s + + + %s + + + %s + + + %s + + + ' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain") + + response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" + if ! _contains "$response" ""; then + _err "Error" + return 1 + fi + return 0 +} + +_get_root() { + domain=$1 + _debug "get root" + + domain=$1 + i=2 + p=1 + + xml_content=$(printf ' + + getDomains + + + %s + + + %s + + + ' $LOOPIA_User $LOOPIA_Password) + + response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" + while true; do + h=$(echo "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "$h"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 + +} + +_loopia_add_record() { + domain=$1 + sub_domain=$2 + txtval=$3 + + xml_content=$(printf ' + + addZoneRecord + + + %s + + + %s + + + %s + + + %s + + + + + type + TXT + + + priority + 0 + + + ttl + 300 + + + rdata + %s + + + + + ' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain" "$txtval") + + response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" + + if ! _contains "$response" "OK"; then + _err "Error" + return 1 + fi + return 0 +} + +_sub_domain_exists() { + domain=$1 + sub_domain=$2 + + xml_content=$(printf ' + + getSubdomains + + + %s + + + %s + + + %s + + + ' $LOOPIA_User $LOOPIA_Password "$domain") + + response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" + + if _contains "$response" "$sub_domain"; then + return 0 + fi + return 1 +} + +_loopia_add_sub_domain() { + domain=$1 + sub_domain=$2 + + if _sub_domain_exists "$domain" "$sub_domain"; then + return 0 + fi + + xml_content=$(printf ' + + addSubdomain + + + %s + + + %s + + + %s + + + %s + + + ' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain") + + response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")" + + if ! _contains "$response" "OK"; then + _err "Error" + return 1 + fi + return 0 +} diff --git a/letsencrypt/dnsapi/dns_lua.sh b/letsencrypt/dnsapi/dns_lua.sh new file mode 100755 index 00000000..9bf8cd9c --- /dev/null +++ b/letsencrypt/dnsapi/dns_lua.sh @@ -0,0 +1,154 @@ +#!/bin/bash + +# bug reports to dev@1e.ca + +# +#LUA_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# +#LUA_Email="user@luadns.net" + +LUA_Api="https://api.luadns.com/v1" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_lua_add() { + fulldomain=$1 + txtvalue=$2 + + LUA_Key="${LUA_Key:-$(_readaccountconf_mutable LUA_Key)}" + LUA_Email="${LUA_Email:-$(_readaccountconf_mutable LUA_Email)}" + LUA_auth=$(printf "%s" "$LUA_Email:$LUA_Key" | _base64) + + if [ -z "$LUA_Key" ] || [ -z "$LUA_Email" ]; then + LUA_Key="" + LUA_Email="" + _err "You don't specify luadns api key and email yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable LUA_Key "$LUA_Key" + _saveaccountconf_mutable LUA_Email "$LUA_Email" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _info "Adding record" + if _LUA_rest POST "zones/$_domain_id/records" "{\"type\":\"TXT\",\"name\":\"$fulldomain.\",\"content\":\"$txtvalue\",\"ttl\":120}"; then + if _contains "$response" "$fulldomain"; then + _info "Added" + #todo: check if the record takes effect + return 0 + else + _err "Add txt record error." + return 1 + fi + fi +} + +#fulldomain +dns_lua_rm() { + fulldomain=$1 + txtvalue=$2 + + LUA_Key="${LUA_Key:-$(_readaccountconf_mutable LUA_Key)}" + LUA_Email="${LUA_Email:-$(_readaccountconf_mutable LUA_Email)}" + LUA_auth=$(printf "%s" "$LUA_Email:$LUA_Key" | _base64) + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _LUA_rest GET "zones/${_domain_id}/records" + + count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | wc -l | tr -d " ") + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Don't need to remove." + else + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$fulldomain.\",\"type\":\"TXT\"" | _head_n 1 | cut -d: -f2 | cut -d, -f1) + _debug "record_id" "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if ! _LUA_rest DELETE "/zones/$_domain_id/records/$record_id"; then + _err "Delete record error." + return 1 + fi + _contains "$response" "$record_id" + fi +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + if ! _LUA_rest GET "zones"; then + return 1 + fi + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "\"name\":\"$h\""; then + _domain_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*,\"name\":\"$h\"" | cut -d : -f 2 | cut -d , -f 1) + _debug _domain_id "$_domain_id" + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_LUA_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Accept: application/json" + export _H2="Authorization: Basic $LUA_auth" + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$LUA_Api/$ep" "" "$m")" + else + response="$(_get "$LUA_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_maradns.sh b/letsencrypt/dnsapi/dns_maradns.sh new file mode 100755 index 00000000..b77c4308 --- /dev/null +++ b/letsencrypt/dnsapi/dns_maradns.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +#Usage: dns_maradns_add _acme-challenge.www.domain.com "token" +dns_maradns_add() { + fulldomain="$1" + txtvalue="$2" + + MARA_ZONE_FILE="${MARA_ZONE_FILE:-$(_readaccountconf_mutable MARA_ZONE_FILE)}" + MARA_DUENDE_PID_PATH="${MARA_DUENDE_PID_PATH:-$(_readaccountconf_mutable MARA_DUENDE_PID_PATH)}" + + _check_zone_file "$MARA_ZONE_FILE" || return 1 + _check_duende_pid_path "$MARA_DUENDE_PID_PATH" || return 1 + + _saveaccountconf_mutable MARA_ZONE_FILE "$MARA_ZONE_FILE" + _saveaccountconf_mutable MARA_DUENDE_PID_PATH "$MARA_DUENDE_PID_PATH" + + printf "%s. TXT '%s' ~\n" "$fulldomain" "$txtvalue" >>"$MARA_ZONE_FILE" + _reload_maradns "$MARA_DUENDE_PID_PATH" || return 1 +} + +#Usage: dns_maradns_rm _acme-challenge.www.domain.com "token" +dns_maradns_rm() { + fulldomain="$1" + txtvalue="$2" + + MARA_ZONE_FILE="${MARA_ZONE_FILE:-$(_readaccountconf_mutable MARA_ZONE_FILE)}" + MARA_DUENDE_PID_PATH="${MARA_DUENDE_PID_PATH:-$(_readaccountconf_mutable MARA_DUENDE_PID_PATH)}" + + _check_zone_file "$MARA_ZONE_FILE" || return 1 + _check_duende_pid_path "$MARA_DUENDE_PID_PATH" || return 1 + + _saveaccountconf_mutable MARA_ZONE_FILE "$MARA_ZONE_FILE" + _saveaccountconf_mutable MARA_DUENDE_PID_PATH "$MARA_DUENDE_PID_PATH" + + _sed_i "/^$fulldomain.\+TXT '$txtvalue' ~/d" "$MARA_ZONE_FILE" + _reload_maradns "$MARA_DUENDE_PID_PATH" || return 1 +} + +_check_zone_file() { + zonefile="$1" + if [ -z "$zonefile" ]; then + _err "MARA_ZONE_FILE not passed!" + return 1 + elif [ ! -w "$zonefile" ]; then + _err "MARA_ZONE_FILE not writable: $zonefile" + return 1 + fi +} + +_check_duende_pid_path() { + pidpath="$1" + if [ -z "$pidpath" ]; then + _err "MARA_DUENDE_PID_PATH not passed!" + return 1 + fi + if [ ! -r "$pidpath" ]; then + _err "MARA_DUENDE_PID_PATH not readable: $pidpath" + return 1 + fi +} + +_reload_maradns() { + pidpath="$1" + kill -s HUP -- "$(cat "$pidpath")" + if [ $? -ne 0 ]; then + _err "Unable to reload MaraDNS, kill returned $?" + return 1 + fi +} diff --git a/letsencrypt/dnsapi/dns_me.sh b/letsencrypt/dnsapi/dns_me.sh new file mode 100644 index 00000000..de5392b5 --- /dev/null +++ b/letsencrypt/dnsapi/dns_me.sh @@ -0,0 +1,157 @@ +#!/bin/bash + +# bug reports to dev@1e.ca + +# ME_Key=qmlkdjflmkqdjf +# ME_Secret=qmsdlkqmlksdvnnpae + +ME_Api=https://api.dnsmadeeasy.com/V2.0/dns/managed + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_me_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$ME_Key" ] || [ -z "$ME_Secret" ]; then + ME_Key="" + ME_Secret="" + _err "You didn't specify DNSMadeEasy api key and secret yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf ME_Key "$ME_Key" + _saveaccountconf ME_Secret "$ME_Secret" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _me_rest GET "${_domain_id}/records?recordName=$_sub_domain&type=TXT" + + if ! _contains "$response" "\"totalRecords\":"; then + _err "Error" + return 1 + fi + + _info "Adding record" + if _me_rest POST "$_domain_id/records/" "{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"value\":\"$txtvalue\",\"gtdLocation\":\"DEFAULT\",\"ttl\":120}"; then + if printf -- "%s" "$response" | grep \"id\": >/dev/null; then + _info "Added" + #todo: check if the record takes effect + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + +} + +#fulldomain +dns_me_rm() { + fulldomain=$1 + txtvalue=$2 + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _me_rest GET "${_domain_id}/records?recordName=$_sub_domain&type=TXT" + + count=$(printf "%s\n" "$response" | _egrep_o "\"totalRecords\":[^,]*" | cut -d : -f 2) + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Don't need to remove." + else + record_id=$(printf "%s\n" "$response" | _egrep_o ",\"value\":\"..$txtvalue..\",\"id\":[^,]*" | cut -d : -f 3 | head -n 1) + _debug "record_id" "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if ! _me_rest DELETE "$_domain_id/records/$record_id"; then + _err "Delete record error." + return 1 + fi + _contains "$response" '' + fi +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _me_rest GET "name?domainname=$h"; then + return 1 + fi + + if _contains "$response" "\"name\":\"$h\""; then + _domain_id=$(printf "%s\n" "$response" | sed 's/^{//; s/}$//; s/{.*}//' | sed -r 's/^.*"id":([0-9]+).*$/\1/') + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_me_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + cdate=$(LANG=C date -u +"%a, %d %b %Y %T %Z") + hmac=$(printf "%s" "$cdate" | _hmac sha1 "$(printf "%s" "$ME_Secret" | _hex_dump | tr -d " ")" hex) + + export _H1="x-dnsme-apiKey: $ME_Key" + export _H2="x-dnsme-requestDate: $cdate" + export _H3="x-dnsme-hmac: $hmac" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$ME_Api/$ep" "" "$m")" + else + response="$(_get "$ME_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_miab.sh b/letsencrypt/dnsapi/dns_miab.sh new file mode 100644 index 00000000..3589e73a --- /dev/null +++ b/letsencrypt/dnsapi/dns_miab.sh @@ -0,0 +1,210 @@ +#!/bin/bash + +# Name: dns_miab.sh +# +# Authors: +# Darven Dissek 2018 +# William Gertz 2019 +# +# Thanks to Neil Pang and other developers here for code reused from acme.sh from DNS-01 +# used to communicate with the MailinaBox Custom DNS API +# Report Bugs here: +# https://github.com/billgertz/MIAB_dns_api (for dns_miab.sh) +# https://github.com/acmesh-official/acme.sh (for acme.sh) +# +######## Public functions ##################### + +#Usage: dns_miab_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_miab_add() { + fulldomain=$1 + txtvalue=$2 + _info "Using miab challange add" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + #retrieve MIAB environemt vars + if ! _retrieve_miab_env; then + return 1 + fi + + #check domain and seperate into doamin and host + if ! _get_root "$fulldomain"; then + _err "Cannot find any part of ${fulldomain} is hosted on ${MIAB_Server}" + return 1 + fi + + _debug2 _sub_domain "$_sub_domain" + _debug2 _domain "$_domain" + + #add the challenge record + _api_path="custom/${fulldomain}/txt" + _miab_rest "$txtvalue" "$_api_path" "POST" + + #check if result was good + if _contains "$response" "updated DNS"; then + _info "Successfully created the txt record" + return 0 + else + _err "Error encountered during record add" + _err "$response" + return 1 + fi +} + +#Usage: dns_miab_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_miab_rm() { + fulldomain=$1 + txtvalue=$2 + + _info "Using miab challage delete" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + #retrieve MIAB environemt vars + if ! _retrieve_miab_env; then + return 1 + fi + + #check domain and seperate into doamin and host + if ! _get_root "$fulldomain"; then + _err "Cannot find any part of ${fulldomain} is hosted on ${MIAB_Server}" + return 1 + fi + + _debug2 _sub_domain "$_sub_domain" + _debug2 _domain "$_domain" + + #Remove the challenge record + _api_path="custom/${fulldomain}/txt" + _miab_rest "$txtvalue" "$_api_path" "DELETE" + + #check if result was good + if _contains "$response" "updated DNS"; then + _info "Successfully removed the txt record" + return 0 + else + _err "Error encountered during record remove" + _err "$response" + return 1 + fi +} + +#################### Private functions below ################################## +# +#Usage: _get_root _acme-challenge.www.domain.com +#Returns: +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + _passed_domain=$1 + _debug _passed_domain "$_passed_domain" + _i=2 + _p=1 + + #get the zones hosed on MIAB server, must be a json stream + _miab_rest "" "zones" "GET" + + if ! _is_json "$response"; then + _err "ERROR fetching domain list" + _err "$response" + return 1 + fi + + #cycle through the passed domain seperating out a test domain discarding + # the subdomain by marching thorugh the dots + while true; do + _test_domain=$(printf "%s" "$_passed_domain" | cut -d . -f ${_i}-100) + _debug _test_domain "$_test_domain" + + if [ -z "$_test_domain" ]; then + return 1 + fi + + #report found if the test domain is in the json response and + # report the subdomain + if _contains "$response" "\"$_test_domain\""; then + _sub_domain=$(printf "%s" "$_passed_domain" | cut -d . -f 1-${_p}) + _domain=${_test_domain} + return 0 + fi + + #cycle to the next dot in the passed domain + _p=${_i} + _i=$(_math "$_i" + 1) + done + + return 1 +} + +#Usage: _retrieve_miab_env +#Returns (from store or environment variables): +# MIAB_Username +# MIAB_Password +# MIAB_Server +#retrieve MIAB environment variables, report errors and quit if problems +_retrieve_miab_env() { + MIAB_Username="${MIAB_Username:-$(_readaccountconf_mutable MIAB_Username)}" + MIAB_Password="${MIAB_Password:-$(_readaccountconf_mutable MIAB_Password)}" + MIAB_Server="${MIAB_Server:-$(_readaccountconf_mutable MIAB_Server)}" + + #debug log the environmental variables + _debug MIAB_Username "$MIAB_Username" + _debug MIAB_Password "$MIAB_Password" + _debug MIAB_Server "$MIAB_Server" + + #check if MIAB environemt vars set and quit if not + if [ -z "$MIAB_Username" ] || [ -z "$MIAB_Password" ] || [ -z "$MIAB_Server" ]; then + _err "You didn't specify one or more of MIAB_Username, MIAB_Password or MIAB_Server." + _err "Please check these environment variables and try again." + return 1 + fi + + #save the credentials to the account conf file. + _saveaccountconf_mutable MIAB_Username "$MIAB_Username" + _saveaccountconf_mutable MIAB_Password "$MIAB_Password" + _saveaccountconf_mutable MIAB_Server "$MIAB_Server" +} + +#Useage: _miab_rest "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" "custom/_acme-challenge.www.domain.com/txt "POST" +#Returns: "updated DNS: domain.com" +#rest interface MIAB dns +_miab_rest() { + _data="$1" + _api_path="$2" + _httpmethod="$3" + + #encode username and password for basic authentication + _credentials="$(printf "%s" "$MIAB_Username:$MIAB_Password" | _base64)" + export _H1="Authorization: Basic $_credentials" + _url="https://${MIAB_Server}/admin/dns/${_api_path}" + + _debug2 _data "$_data" + _debug _api_path "$_api_path" + _debug2 _url "$_url" + _debug2 _credentails "$_credentials" + _debug _httpmethod "$_httpmethod" + + if [ "$_httpmethod" = "GET" ]; then + response="$(_get "$_url")" + else + response="$(_post "$_data" "$_url" "" "$_httpmethod")" + fi + + _retcode="$?" + + if [ "$_retcode" != "0" ]; then + _err "MIAB REST authentication failed on $_httpmethod" + return 1 + fi + + _debug response "$response" + return 0 +} + +#Usage: _is_json "\[\n "mydomain.com"\n]" +#Reurns "\[\n "mydomain.com"\n]" +#returns the string if it begins and ends with square braces +_is_json() { + _str="$(echo "$1" | _normalizeJson)" + echo "$_str" | grep '^\[.*\]$' >/dev/null 2>&1 +} diff --git a/letsencrypt/dnsapi/dns_misaka.sh b/letsencrypt/dnsapi/dns_misaka.sh new file mode 100755 index 00000000..a14ae605 --- /dev/null +++ b/letsencrypt/dnsapi/dns_misaka.sh @@ -0,0 +1,159 @@ +#!/bin/bash + +# bug reports to support+acmesh@misaka.io +# based on dns_nsone.sh by dev@1e.ca + +# +#Misaka_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# + +Misaka_Api="https://dnsapi.misaka.io/dns" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_misaka_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$Misaka_Key" ]; then + Misaka_Key="" + _err "You didn't specify misaka.io dns api key yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf Misaka_Key "$Misaka_Key" + + _debug "checking root zone [$fulldomain]" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _misaka_rest GET "zones/${_domain}/recordsets?search=${_sub_domain}" + + if ! _contains "$response" "\"results\":"; then + _err "Error" + return 1 + fi + + count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$_sub_domain\",[^{]*\"type\":\"TXT\"" | wc -l | tr -d " ") + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Adding record" + + if _misaka_rest POST "zones/${_domain}/recordsets/${_sub_domain}/TXT" "{\"records\":[{\"value\":\"\\\"$txtvalue\\\"\"}],\"filters\":[],\"ttl\":1}"; then + _debug response "$response" + if _contains "$response" "$_sub_domain"; then + _info "Added" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + else + _info "Updating record" + + _misaka_rest PUT "zones/${_domain}/recordsets/${_sub_domain}/TXT?append=true" "{\"records\": [{\"value\": \"\\\"$txtvalue\\\"\"}],\"ttl\":1}" + if [ "$?" = "0" ] && _contains "$response" "$_sub_domain"; then + _info "Updated!" + #todo: check if the record takes effect + return 0 + fi + _err "Update error" + return 1 + fi + +} + +#fulldomain +dns_misaka_rm() { + fulldomain=$1 + txtvalue=$2 + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _misaka_rest GET "zones/${_domain}/recordsets?search=${_sub_domain}" + + count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$_sub_domain\",[^{]*\"type\":\"TXT\"" | wc -l | tr -d " ") + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Don't need to remove." + else + if ! _misaka_rest DELETE "zones/${_domain}/recordsets/${_sub_domain}/TXT"; then + _err "Delete record error." + return 1 + fi + _contains "$response" "" + fi +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + if ! _misaka_rest GET "zones?limit=1000"; then + return 1 + fi + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "\"name\":\"$h\""; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_misaka_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Content-Type: application/json" + export _H2="User-Agent: acme.sh/$VER misaka-dns-acmesh/20191213" + export _H3="Authorization: Token $Misaka_Key" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$Misaka_Api/$ep" "" "$m")" + else + response="$(_get "$Misaka_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_myapi.sh b/letsencrypt/dnsapi/dns_myapi.sh new file mode 100755 index 00000000..56753e52 --- /dev/null +++ b/letsencrypt/dnsapi/dns_myapi.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +#Here is a sample custom api script. +#This file name is "dns_myapi.sh" +#So, here must be a method dns_myapi_add() +#Which will be called by acme.sh to add the txt record to your api system. +#returns 0 means success, otherwise error. +# +#Author: Neilpang +#Report Bugs here: https://github.com/acmesh-official/acme.sh +# +######## Public functions ##################### + +# Please Read this guide first: https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Dev-Guide + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_myapi_add() { + fulldomain=$1 + txtvalue=$2 + _info "Using myapi" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + _err "Not implemented!" + return 1 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_myapi_rm() { + fulldomain=$1 + txtvalue=$2 + _info "Using myapi" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" +} + +#################### Private functions below ################################## diff --git a/letsencrypt/dnsapi/dns_mydevil.sh b/letsencrypt/dnsapi/dns_mydevil.sh new file mode 100755 index 00000000..a5cc30f9 --- /dev/null +++ b/letsencrypt/dnsapi/dns_mydevil.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +# MyDevil.net API (2019-02-03) +# +# MyDevil.net already supports automatic Let's Encrypt certificates, +# except for wildcard domains. +# +# This script depends on `devil` command that MyDevil.net provides, +# which means that it works only on server side. +# +# Author: Marcin Konicki +# +######## Public functions ##################### + +#Usage: dns_mydevil_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_mydevil_add() { + fulldomain=$1 + txtvalue=$2 + domain="" + + if ! _exists "devil"; then + _err "Could not find 'devil' command." + return 1 + fi + + _info "Using mydevil" + + domain=$(mydevil_get_domain "$fulldomain") + if [ -z "$domain" ]; then + _err "Invalid domain name: could not find root domain of $fulldomain." + return 1 + fi + + # No need to check if record name exists, `devil` always adds new record. + # In worst case scenario, we end up with multiple identical records. + + _info "Adding $fulldomain record for domain $domain" + if devil dns add "$domain" "$fulldomain" TXT "$txtvalue"; then + _info "Successfully added TXT record, ready for validation." + return 0 + else + _err "Unable to add DNS record." + return 1 + fi +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_mydevil_rm() { + fulldomain=$1 + txtvalue=$2 + domain="" + + if ! _exists "devil"; then + _err "Could not find 'devil' command." + return 1 + fi + + _info "Using mydevil" + + domain=$(mydevil_get_domain "$fulldomain") + if [ -z "$domain" ]; then + _err "Invalid domain name: could not find root domain of $fulldomain." + return 1 + fi + + # catch one or more numbers + num='[0-9][0-9]*' + # catch one or more whitespace + w=$(printf '[\t ][\t ]*') + # catch anything, except newline + any='.*' + # filter to make sure we do not delete other records + validRecords="^${num}${w}${fulldomain}${w}TXT${w}${any}${txtvalue}$" + for id in $(devil dns list "$domain" | tail -n+2 | grep "${validRecords}" | cut -w -s -f 1); do + _info "Removing record $id from domain $domain" + devil dns del "$domain" "$id" || _err "Could not remove DNS record." + done +} + +#################### Private functions below ################################## + +# Usage: domain=$(mydevil_get_domain "_acme-challenge.www.domain.com" || _err "Invalid domain name") +# echo $domain +mydevil_get_domain() { + fulldomain=$1 + domain="" + + for domain in $(devil dns list | cut -w -s -f 1 | tail -n+2); do + if _endswith "$fulldomain" "$domain"; then + printf -- "%s" "$domain" + return 0 + fi + done + + return 1 +} diff --git a/letsencrypt/dnsapi/dns_mydnsjp.sh b/letsencrypt/dnsapi/dns_mydnsjp.sh new file mode 100755 index 00000000..5dd57a6b --- /dev/null +++ b/letsencrypt/dnsapi/dns_mydnsjp.sh @@ -0,0 +1,210 @@ +#!/bin/bash + +#Here is a api script for MyDNS.JP. +#This file name is "dns_mydnsjp.sh" +#So, here must be a method dns_mydnsjp_add() +#Which will be called by acme.sh to add the txt record to your api system. +#returns 0 means success, otherwise error. +# +#Author: epgdatacapbon +#Report Bugs here: https://github.com/epgdatacapbon/acme.sh +# +######## Public functions ##################### + +# Export MyDNS.JP MasterID and Password in following variables... +# MYDNSJP_MasterID=MasterID +# MYDNSJP_Password=Password + +MYDNSJP_API="https://www.mydns.jp" + +#Usage: dns_mydnsjp_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_mydnsjp_add() { + fulldomain=$1 + txtvalue=$2 + + _info "Using mydnsjp" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + # Load the credentials from the account conf file + MYDNSJP_MasterID="${MYDNSJP_MasterID:-$(_readaccountconf_mutable MYDNSJP_MasterID)}" + MYDNSJP_Password="${MYDNSJP_Password:-$(_readaccountconf_mutable MYDNSJP_Password)}" + if [ -z "$MYDNSJP_MasterID" ] || [ -z "$MYDNSJP_Password" ]; then + MYDNSJP_MasterID="" + MYDNSJP_Password="" + _err "You don't specify mydnsjp api MasterID and Password yet." + _err "Please export as MYDNSJP_MasterID / MYDNSJP_Password and try again." + return 1 + fi + + # Save the credentials to the account conf file + _saveaccountconf_mutable MYDNSJP_MasterID "$MYDNSJP_MasterID" + _saveaccountconf_mutable MYDNSJP_Password "$MYDNSJP_Password" + + _debug "First detect the root zone." + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + if _mydnsjp_api "REGIST" "$_domain" "$txtvalue"; then + if printf -- "%s" "$response" | grep "OK." >/dev/null; then + _info "Added, OK" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + + return 1 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_mydnsjp_rm() { + fulldomain=$1 + txtvalue=$2 + + _info "Removing TXT record" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + # Load the credentials from the account conf file + MYDNSJP_MasterID="${MYDNSJP_MasterID:-$(_readaccountconf_mutable MYDNSJP_MasterID)}" + MYDNSJP_Password="${MYDNSJP_Password:-$(_readaccountconf_mutable MYDNSJP_Password)}" + if [ -z "$MYDNSJP_MasterID" ] || [ -z "$MYDNSJP_Password" ]; then + MYDNSJP_MasterID="" + MYDNSJP_Password="" + _err "You don't specify mydnsjp api MasterID and Password yet." + _err "Please export as MYDNSJP_MasterID / MYDNSJP_Password and try again." + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + if _mydnsjp_api "DELETE" "$_domain" "$txtvalue"; then + if printf -- "%s" "$response" | grep "OK." >/dev/null; then + _info "Deleted, OK" + return 0 + else + _err "Delete txt record error." + return 1 + fi + fi + _err "Delete txt record error." + + return 1 +} + +#################### Private functions below ################################## +# _acme-challenge.www.domain.com +# returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + fulldomain=$1 + i=2 + p=1 + + # Get the root domain + _mydnsjp_retrieve_domain + if [ "$?" != "0" ]; then + # not valid + return 1 + fi + + while true; do + _domain=$(printf "%s" "$fulldomain" | cut -d . -f $i-100) + + if [ -z "$_domain" ]; then + # not valid + return 1 + fi + + if [ "$_domain" = "$_root_domain" ]; then + _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-$p) + return 0 + fi + + p=$i + i=$(_math "$i" + 1) + done + + return 1 +} + +# Retrieve the root domain +# returns 0 success +_mydnsjp_retrieve_domain() { + _debug "Login to MyDNS.JP" + + response="$(_post "masterid=$MYDNSJP_MasterID&masterpwd=$MYDNSJP_Password" "$MYDNSJP_API/?MENU=100")" + cookie="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2)" + + # If cookies is not empty then logon successful + if [ -z "$cookie" ]; then + _err "Fail to get a cookie." + return 1 + fi + + _debug "Retrieve DOMAIN INFO page" + + export _H1="Cookie:${cookie}" + + response="$(_get "$MYDNSJP_API/?MENU=300")" + + if [ "$?" != "0" ]; then + _err "Fail to retrieve DOMAIN INFO." + return 1 + fi + + _root_domain=$(echo "$response" | grep "DNSINFO\[domainname\]" | sed 's/^.*value="\([^"]*\)".*/\1/') + + # Logout + response="$(_get "$MYDNSJP_API/?MENU=090")" + + _debug _root_domain "$_root_domain" + + if [ -z "$_root_domain" ]; then + _err "Fail to get the root domain." + return 1 + fi + + return 0 +} + +_mydnsjp_api() { + cmd=$1 + domain=$2 + txtvalue=$3 + + # Base64 encode the credentials + credentials=$(printf "%s:%s" "$MYDNSJP_MasterID" "$MYDNSJP_Password" | _base64) + + # Construct the HTTP Authorization header + export _H1="Content-Type: application/x-www-form-urlencoded" + export _H2="Authorization: Basic ${credentials}" + + response="$(_post "CERTBOT_DOMAIN=$domain&CERTBOT_VALIDATION=$txtvalue&EDIT_CMD=$cmd" "$MYDNSJP_API/directedit.html")" + + if [ "$?" != "0" ]; then + _err "error $domain" + return 1 + fi + + _debug2 response "$response" + + return 0 +} diff --git a/letsencrypt/dnsapi/dns_namecheap.sh b/letsencrypt/dnsapi/dns_namecheap.sh new file mode 100755 index 00000000..670f995e --- /dev/null +++ b/letsencrypt/dnsapi/dns_namecheap.sh @@ -0,0 +1,407 @@ +#!/bin/bash + +# Namecheap API +# https://www.namecheap.com/support/api/intro.aspx +# +# Requires Namecheap API key set in +#NAMECHEAP_API_KEY, +#NAMECHEAP_USERNAME, +#NAMECHEAP_SOURCEIP +# Due to Namecheap's API limitation all the records of your domain will be read and re applied, make sure to have a backup of your records you could apply if any issue would arise. + +######## Public functions ##################### + +NAMECHEAP_API="https://api.namecheap.com/xml.response" + +#Usage: dns_namecheap_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_namecheap_add() { + fulldomain=$1 + txtvalue=$2 + + if ! _namecheap_check_config; then + _err "$error" + return 1 + fi + + if ! _namecheap_set_publicip; then + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + _debug domain "$_domain" + _debug sub_domain "$_sub_domain" + + _set_namecheap_TXT "$_domain" "$_sub_domain" "$txtvalue" +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_namecheap_rm() { + fulldomain=$1 + txtvalue=$2 + + if ! _namecheap_set_publicip; then + return 1 + fi + + if ! _namecheap_check_config; then + _err "$error" + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + _debug domain "$_domain" + _debug sub_domain "$_sub_domain" + + _del_namecheap_TXT "$_domain" "$_sub_domain" "$txtvalue" +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + fulldomain=$1 + + if ! _get_root_by_getList "$fulldomain"; then + _debug "Failed domain lookup via domains.getList api call. Trying domain lookup via domains.dns.getHosts api." + # The above "getList" api will only return hosts *owned* by the calling user. However, if the calling + # user is not the owner, but still has administrative rights, we must query the getHosts api directly. + # See this comment and the official namecheap response: http://disq.us/p/1q6v9x9 + if ! _get_root_by_getHosts "$fulldomain"; then + return 1 + fi + fi + + return 0 +} + +_get_root_by_getList() { + domain=$1 + + if ! _namecheap_post "namecheap.domains.getList"; then + _err "$error" + return 1 + fi + + i=2 + p=1 + + while true; do + + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + if ! _contains "$h" "\\."; then + #not valid + return 1 + fi + + if ! _contains "$response" "$h"; then + _debug "$h not found" + else + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p="$i" + i=$(_math "$i" + 1) + done + return 1 +} + +_get_root_by_getHosts() { + i=100 + p=99 + + while [ $p -ne 0 ]; do + + h=$(printf "%s" "$1" | cut -d . -f $i-100) + if [ -n "$h" ]; then + if _contains "$h" "\\."; then + _debug h "$h" + if _namecheap_set_tld_sld "$h"; then + _sub_domain=$(printf "%s" "$1" | cut -d . -f 1-$p) + _domain="$h" + return 0 + else + _debug "$h not found" + fi + fi + fi + i="$p" + p=$(_math "$p" - 1) + done + return 1 +} + +_namecheap_set_publicip() { + + if [ -z "$NAMECHEAP_SOURCEIP" ]; then + _err "No Source IP specified for Namecheap API." + _err "Use your public ip address or an url to retrieve it (e.g. https://ipconfig.co/ip) and export it as NAMECHEAP_SOURCEIP" + return 1 + else + _saveaccountconf NAMECHEAP_SOURCEIP "$NAMECHEAP_SOURCEIP" + _debug sourceip "$NAMECHEAP_SOURCEIP" + + ip=$(echo "$NAMECHEAP_SOURCEIP" | _egrep_o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}') + addr=$(echo "$NAMECHEAP_SOURCEIP" | _egrep_o '(http|https):\/\/.*') + + _debug2 ip "$ip" + _debug2 addr "$addr" + + if [ -n "$ip" ]; then + _publicip="$ip" + elif [ -n "$addr" ]; then + _publicip=$(_get "$addr") + else + _err "No Source IP specified for Namecheap API." + _err "Use your public ip address or an url to retrieve it (e.g. https://ipconfig.co/ip) and export it as NAMECHEAP_SOURCEIP" + return 1 + fi + fi + + _debug publicip "$_publicip" + + return 0 +} + +_namecheap_post() { + command=$1 + data="ApiUser=${NAMECHEAP_USERNAME}&ApiKey=${NAMECHEAP_API_KEY}&ClientIp=${_publicip}&UserName=${NAMECHEAP_USERNAME}&Command=${command}" + _debug2 "_namecheap_post data" "$data" + response="$(_post "$data" "$NAMECHEAP_API" "" "POST")" + _debug2 response "$response" + + if _contains "$response" "Status=\"ERROR\"" >/dev/null; then + error=$(echo "$response" | _egrep_o ">.*<\\/Error>" | cut -d '<' -f 1 | tr -d '>') + _err "error $error" + return 1 + fi + + return 0 +} + +_namecheap_parse_host() { + _host=$1 + _debug _host "$_host" + + _hostid=$(echo "$_host" | _egrep_o ' HostId="[^"]*' | cut -d '"' -f 2) + _hostname=$(echo "$_host" | _egrep_o ' Name="[^"]*' | cut -d '"' -f 2) + _hosttype=$(echo "$_host" | _egrep_o ' Type="[^"]*' | cut -d '"' -f 2) + _hostaddress=$(echo "$_host" | _egrep_o ' Address="[^"]*' | cut -d '"' -f 2) + _hostmxpref=$(echo "$_host" | _egrep_o ' MXPref="[^"]*' | cut -d '"' -f 2) + _hostttl=$(echo "$_host" | _egrep_o ' TTL="[^"]*' | cut -d '"' -f 2) + + _debug hostid "$_hostid" + _debug hostname "$_hostname" + _debug hosttype "$_hosttype" + _debug hostaddress "$_hostaddress" + _debug hostmxpref "$_hostmxpref" + _debug hostttl "$_hostttl" +} + +_namecheap_check_config() { + + if [ -z "$NAMECHEAP_API_KEY" ]; then + _err "No API key specified for Namecheap API." + _err "Create your key and export it as NAMECHEAP_API_KEY" + return 1 + fi + + if [ -z "$NAMECHEAP_USERNAME" ]; then + _err "No username key specified for Namecheap API." + _err "Create your key and export it as NAMECHEAP_USERNAME" + return 1 + fi + + _saveaccountconf NAMECHEAP_API_KEY "$NAMECHEAP_API_KEY" + _saveaccountconf NAMECHEAP_USERNAME "$NAMECHEAP_USERNAME" + + return 0 +} + +_set_namecheap_TXT() { + subdomain=$2 + txt=$3 + + if ! _namecheap_set_tld_sld "$1"; then + return 1 + fi + + request="namecheap.domains.dns.getHosts&SLD=${_sld}&TLD=${_tld}" + + if ! _namecheap_post "$request"; then + _err "$error" + return 1 + fi + + hosts=$(echo "$response" | _egrep_o ']*') + _debug hosts "$hosts" + + if [ -z "$hosts" ]; then + _error "Hosts not found" + return 1 + fi + + _namecheap_reset_hostList + + while read -r host; do + if _contains "$host" "]*') + _debug hosts "$hosts" + + if [ -z "$hosts" ]; then + _error "Hosts not found" + return 1 + fi + + _namecheap_reset_hostList + + found=0 + + while read -r host; do + if _contains "$host" "300") + if [ "$retcode" ]; then + _info "Successfully added TXT record, ready for validation." + return 0 + else + _err "Unable to add the DNS record." + return 1 + fi + fi +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_namesilo_rm() { + fulldomain=$1 + txtvalue=$2 + + if ! _get_root "$fulldomain"; then + _err "Unable to find domain specified." + return 1 + fi + + # Get the record id. + if _namesilo_rest GET "dnsListRecords?version=1&type=xml&key=$Namesilo_Key&domain=$_domain"; then + retcode=$(printf "%s\n" "$response" | _egrep_o "300") + if [ "$retcode" ]; then + _record_id=$(echo "$response" | _egrep_o "([^<]*)TXT$fulldomain" | _egrep_o "([^<]*)" | sed -r "s/([^<]*)<\/record_id>/\1/" | tail -n 1) + _debug _record_id "$_record_id" + if [ "$_record_id" ]; then + _info "Successfully retrieved the record id for ACME challenge." + else + _info "Empty record id, it seems no such record." + return 0 + fi + else + _err "Unable to retrieve the record id." + return 1 + fi + fi + + # Remove the DNS record using record id. + if _namesilo_rest GET "dnsDeleteRecord?version=1&type=xml&key=$Namesilo_Key&domain=$_domain&rrid=$_record_id"; then + retcode=$(printf "%s\n" "$response" | _egrep_o "300") + if [ "$retcode" ]; then + _info "Successfully removed the TXT record." + return 0 + else + _err "Unable to remove the DNS record." + return 1 + fi + fi +} + +#################### Private functions below ################################## + +# _acme-challenge.www.domain.com +# returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain=$1 + i=2 + p=1 + + if ! _namesilo_rest GET "listDomains?version=1&type=xml&key=$Namesilo_Key"; then + return 1 + fi + + # Need to exclude the last field (tld) + numfields=$(echo "$domain" | _egrep_o "\." | wc -l) + while [ $i -le "$numfields" ]; do + host=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug host "$host" + if [ -z "$host" ]; then + return 1 + fi + + if _contains "$response" "$host"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$host" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_namesilo_rest() { + method=$1 + param=$2 + data=$3 + + if [ "$method" != "GET" ]; then + response="$(_post "$data" "$Namesilo_API/$param" "" "$method")" + else + response="$(_get "$Namesilo_API/$param")" + fi + + if [ "$?" != "0" ]; then + _err "error $param" + return 1 + fi + + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_nederhost.sh b/letsencrypt/dnsapi/dns_nederhost.sh new file mode 100755 index 00000000..c7a92f5f --- /dev/null +++ b/letsencrypt/dnsapi/dns_nederhost.sh @@ -0,0 +1,131 @@ +#!/bin/bash + +#NederHost_Key="sdfgikogfdfghjklkjhgfcdcfghjk" + +NederHost_Api="https://api.nederhost.nl/dns/v1" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_nederhost_add() { + fulldomain=$1 + txtvalue=$2 + + NederHost_Key="${NederHost_Key:-$(_readaccountconf_mutable NederHost_Key)}" + if [ -z "$NederHost_Key" ]; then + NederHost_Key="" + _err "You didn't specify a NederHost api key." + _err "You can get yours from https://www.nederhost.nl/mijn_nederhost" + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable NederHost_Key "$NederHost_Key" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _info "Adding record" + if _nederhost_rest PATCH "zones/$_domain/records/$fulldomain/TXT" "[{\"content\":\"$txtvalue\",\"ttl\":60}]"; then + if _contains "$response" "$fulldomain"; then + _info "Added, OK" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + return 1 + +} + +#fulldomain txtvalue +dns_nederhost_rm() { + fulldomain=$1 + txtvalue=$2 + + NederHost_Key="${NederHost_Key:-$(_readaccountconf_mutable NederHost_Key)}" + if [ -z "$NederHost_Key" ]; then + NederHost_Key="" + _err "You didn't specify a NederHost api key." + _err "You can get yours from https://www.nederhost.nl/mijn_nederhost" + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Removing txt record" + _nederhost_rest DELETE "zones/${_domain}/records/$fulldomain/TXT?content=$txtvalue" + +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + _domain=$(printf "%s" "$domain" | cut -d . -f $i-100) + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _debug _domain "$_domain" + if [ -z "$_domain" ]; then + #not valid + return 1 + fi + + if _nederhost_rest GET "zones/${_domain}"; then + if [ "${_code}" = "204" ]; then + return 0 + fi + else + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_nederhost_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Authorization: Bearer $NederHost_Key" + export _H2="Content-Type: application/json" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$NederHost_Api/$ep" "" "$m")" + else + response="$(_get "$NederHost_Api/$ep")" + fi + + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" + _debug "http response code $_code" + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_neodigit.sh b/letsencrypt/dnsapi/dns_neodigit.sh new file mode 100644 index 00000000..bf843ad5 --- /dev/null +++ b/letsencrypt/dnsapi/dns_neodigit.sh @@ -0,0 +1,181 @@ +#!/bin/bash + +# +# NEODIGIT_API_TOKEN="jasdfhklsjadhflnhsausdfas" + +# This is Neodigit.net api wrapper for acme.sh +# +# Author: Adrian Almenar +# Report Bugs here: https://github.com/tecnocratica/acme.sh +# +NEODIGIT_API_URL="https://api.neodigit.net/v1" +# +######## Public functions ##################### + +# Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_neodigit_add() { + fulldomain=$1 + txtvalue=$2 + + NEODIGIT_API_TOKEN="${NEODIGIT_API_TOKEN:-$(_readaccountconf_mutable NEODIGIT_API_TOKEN)}" + if [ -z "$NEODIGIT_API_TOKEN" ]; then + NEODIGIT_API_TOKEN="" + _err "You haven't specified a Token api key." + _err "Please create the key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable NEODIGIT_API_TOKEN "$NEODIGIT_API_TOKEN" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + _debug domain "$_domain" + _debug sub_domain "$_sub_domain" + + _debug "Getting txt records" + _neo_rest GET "dns/zones/${_domain_id}/records?type=TXT&name=$fulldomain" + + _debug _code "$_code" + + if [ "$_code" != "200" ]; then + _err "error retrieving data!" + return 1 + fi + + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + _debug domain "$_domain" + _debug sub_domain "$_sub_domain" + + _info "Adding record" + if _neo_rest POST "dns/zones/$_domain_id/records" "{\"record\":{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":60}}"; then + if printf -- "%s" "$response" | grep "$_sub_domain" >/dev/null; then + _info "Added, OK" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + return 1 +} + +#fulldomain txtvalue +dns_neodigit_rm() { + fulldomain=$1 + txtvalue=$2 + + NEODIGIT_API_TOKEN="${NEODIGIT_API_TOKEN:-$(_readaccountconf_mutable NEODIGIT_API_TOKEN)}" + if [ -z "$NEODIGIT_API_TOKEN" ]; then + NEODIGIT_API_TOKEN="" + _err "You haven't specified a Token api key." + _err "Please create the key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable NEODIGIT_API_TOKEN "$NEODIGIT_API_TOKEN" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _neo_rest GET "dns/zones/${_domain_id}/records?type=TXT&name=$fulldomain&content=$txtvalue" + + if [ "$_code" != "200" ]; then + _err "error retrieving data!" + return 1 + fi + + record_id=$(echo "$response" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d: -f2 | cut -d, -f1) + _debug "record_id" "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if ! _neo_rest DELETE "dns/zones/$_domain_id/records/$record_id"; then + _err "Delete record error." + return 1 + fi + +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=dasfdsafsadg5ythd +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _neo_rest GET "dns/zones?name=$h"; then + return 1 + fi + + _debug p "$p" + + if _contains "$response" "\"name\":\"$h\"" >/dev/null; then + _domain_id=$(echo "$response" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d: -f2 | cut -d, -f1) + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_neo_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="X-TCPanel-Token: $NEODIGIT_API_TOKEN" + export _H2="Content-Type: application/json" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$NEODIGIT_API_URL/$ep" "" "$m")" + else + response="$(_get "$NEODIGIT_API_URL/$ep")" + fi + + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_netcup.sh b/letsencrypt/dnsapi/dns_netcup.sh new file mode 100644 index 00000000..d9b2933e --- /dev/null +++ b/letsencrypt/dnsapi/dns_netcup.sh @@ -0,0 +1,134 @@ +#!/bin/bash +#developed by linux-insideDE + +NC_Apikey="${NC_Apikey:-$(_readaccountconf_mutable NC_Apikey)}" +NC_Apipw="${NC_Apipw:-$(_readaccountconf_mutable NC_Apipw)}" +NC_CID="${NC_CID:-$(_readaccountconf_mutable NC_CID)}" +end="https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON" +client="" + +dns_netcup_add() { + _debug NC_Apikey "$NC_Apikey" + login + if [ "$NC_Apikey" = "" ] || [ "$NC_Apipw" = "" ] || [ "$NC_CID" = "" ]; then + _err "No Credentials given" + return 1 + fi + _saveaccountconf_mutable NC_Apikey "$NC_Apikey" + _saveaccountconf_mutable NC_Apipw "$NC_Apipw" + _saveaccountconf_mutable NC_CID "$NC_CID" + fulldomain=$1 + txtvalue=$2 + domain="" + exit=$(echo "$fulldomain" | tr -dc '.' | wc -c) + exit=$(_math "$exit" + 1) + i=$exit + + while + [ "$exit" -gt 0 ] + do + tmp=$(echo "$fulldomain" | cut -d'.' -f"$exit") + if [ "$(_math "$i" - "$exit")" -eq 0 ]; then + domain="$tmp" + else + domain="$tmp.$domain" + fi + if [ "$(_math "$i" - "$exit")" -ge 1 ]; then + msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$domain\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"\", \"hostname\": \"$fulldomain.\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"false\", \"state\": \"yes\"} ]}}}" "$end" "" "POST") + _debug "$msg" + if [ "$(_getfield "$msg" "5" | sed 's/"statuscode"://g')" != 5028 ]; then + if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then + _err "$msg" + return 1 + else + break + fi + fi + fi + exit=$(_math "$exit" - 1) + done + logout +} + +dns_netcup_rm() { + login + fulldomain=$1 + txtvalue=$2 + + domain="" + exit=$(echo "$fulldomain" | tr -dc '.' | wc -c) + exit=$(_math "$exit" + 1) + i=$exit + rec="" + + while + [ "$exit" -gt 0 ] + do + tmp=$(echo "$fulldomain" | cut -d'.' -f"$exit") + if [ "$(_math "$i" - "$exit")" -eq 0 ]; then + domain="$tmp" + else + domain="$tmp.$domain" + fi + if [ "$(_math "$i" - "$exit")" -ge 1 ]; then + msg=$(_post "{\"action\": \"infoDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\", \"domainname\": \"$domain\"}}" "$end" "" "POST") + rec=$(echo "$msg" | sed 's/\[//g' | sed 's/\]//g' | sed 's/{\"serverrequestid\".*\"dnsrecords\"://g' | sed 's/},{/};{/g' | sed 's/{//g' | sed 's/}//g') + _debug "$msg" + if [ "$(_getfield "$msg" "5" | sed 's/"statuscode"://g')" != 5028 ]; then + if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then + _err "$msg" + return 1 + else + break + fi + fi + fi + exit=$(_math "$exit" - 1) + done + + ida=0000 + idv=0001 + ids=0000000000 + i=1 + while + [ "$i" -ne 0 ] + do + specrec=$(_getfield "$rec" "$i" ";") + idv="$ida" + ida=$(_getfield "$specrec" "1" "," | sed 's/\"id\":\"//g' | sed 's/\"//g') + txtv=$(_getfield "$specrec" "5" "," | sed 's/\"destination\":\"//g' | sed 's/\"//g') + i=$(_math "$i" + 1) + if [ "$txtvalue" = "$txtv" ]; then + i=0 + ids="$ida" + fi + if [ "$ida" = "$idv" ]; then + i=0 + fi + done + msg=$(_post "{\"action\": \"updateDnsRecords\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\",\"clientrequestid\": \"$client\" , \"domainname\": \"$domain\", \"dnsrecordset\": { \"dnsrecords\": [ {\"id\": \"$ids\", \"hostname\": \"$fulldomain.\", \"type\": \"TXT\", \"priority\": \"\", \"destination\": \"$txtvalue\", \"deleterecord\": \"TRUE\", \"state\": \"yes\"} ]}}}" "$end" "" "POST") + _debug "$msg" + if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then + _err "$msg" + return 1 + fi + logout +} + +login() { + tmp=$(_post "{\"action\": \"login\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apipassword\": \"$NC_Apipw\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST") + sid=$(echo "$tmp" | tr '{}' '\n' | grep apisessionid | cut -d '"' -f 4) + _debug "$tmp" + if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then + _err "$msg" + return 1 + fi +} +logout() { + tmp=$(_post "{\"action\": \"logout\", \"param\": {\"apikey\": \"$NC_Apikey\", \"apisessionid\": \"$sid\", \"customernumber\": \"$NC_CID\"}}" "$end" "" "POST") + _debug "$tmp" + if [ "$(_getfield "$msg" "4" | sed s/\"status\":\"//g | sed s/\"//g)" != "success" ]; then + _err "$msg" + return 1 + fi +} diff --git a/letsencrypt/dnsapi/dns_netlify.sh b/letsencrypt/dnsapi/dns_netlify.sh new file mode 100644 index 00000000..da3f14e1 --- /dev/null +++ b/letsencrypt/dnsapi/dns_netlify.sh @@ -0,0 +1,162 @@ +#!/bin/bash + +#NETLIFY_ACCESS_TOKEN="xxxx" + +NETLIFY_HOST="api.netlify.com/api/v1/" +NETLIFY_URL="https://$NETLIFY_HOST" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_netlify_add() { + fulldomain=$1 + txtvalue=$2 + + NETLIFY_ACCESS_TOKEN="${NETLIFY_ACCESS_TOKEN:-$(_readaccountconf_mutable NETLIFY_ACCESS_TOKEN)}" + + if [ -z "$NETLIFY_ACCESS_TOKEN" ]; then + NETLIFY_ACCESS_TOKEN="" + _err "Please specify your Netlify Access Token and try again." + return 1 + fi + + _info "Using Netlify" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + _saveaccountconf_mutable NETLIFY_ACCESS_TOKEN "$NETLIFY_ACCESS_TOKEN" + + if ! _get_root "$fulldomain" "$accesstoken"; then + _err "invalid domain" + return 1 + fi + + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + dnsRecordURI="dns_zones/$_domain_id/dns_records" + + body="{\"type\":\"TXT\", \"hostname\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"ttl\":\"10\"}" + + _netlify_rest POST "$dnsRecordURI" "$body" "$NETLIFY_ACCESS_TOKEN" + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" + if [ "$_code" = "200" ] || [ "$_code" = '201' ]; then + _info "validation value added" + return 0 + else + _err "error adding validation value ($_code)" + return 1 + fi + + _err "Not fully implemented!" + return 1 +} + +#Usage: dns_myapi_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +#Remove the txt record after validation. +dns_netlify_rm() { + _info "Using Netlify" + txtdomain="$1" + txt="$2" + _debug txtdomain "$txtdomain" + _debug txt "$txt" + + _saveaccountconf_mutable NETLIFY_ACCESS_TOKEN "$NETLIFY_ACCESS_TOKEN" + + if ! _get_root "$txtdomain" "$accesstoken"; then + _err "invalid domain" + return 1 + fi + + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + dnsRecordURI="dns_zones/$_domain_id/dns_records" + + _netlify_rest GET "$dnsRecordURI" "" "$NETLIFY_ACCESS_TOKEN" + + _record_id=$(echo "$response" | _egrep_o "\"type\":\"TXT\",[^\}]*\"value\":\"$txt\"" | head -n 1 | _egrep_o "\"id\":\"[^\"\}]*\"" | cut -d : -f 2 | tr -d \") + _debug _record_id "$_record_id" + if [ "$_record_id" ]; then + _netlify_rest DELETE "$dnsRecordURI/$_record_id" "" "$NETLIFY_ACCESS_TOKEN" + _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" + if [ "$_code" = "200" ] || [ "$_code" = '204' ]; then + _info "validation value removed" + return 0 + else + _err "error removing validation value ($_code)" + return 1 + fi + return 0 + fi + return 1 +} + +#################### Private functions below ################################## + +_get_root() { + domain=$1 + accesstoken=$2 + i=1 + p=1 + + _netlify_rest GET "dns_zones" "" "$accesstoken" + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug2 "Checking domain: $h" + if [ -z "$h" ]; then + #not valid + _err "Invalid domain" + return 1 + fi + + if _contains "$response" "\"name\":\"$h\"" >/dev/null; then + _domain_id=$(echo "$response" | _egrep_o "\"[^\"]*\",\"name\":\"$h" | cut -d , -f 1 | tr -d \") + if [ "$_domain_id" ]; then + if [ "$i" = 1 ]; then + #create the record at the domain apex (@) if only the domain name was provided as --domain-alias + _sub_domain="@" + else + _sub_domain=$(echo "$domain" | cut -d . -f 1-$p) + fi + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_netlify_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + token_trimmed=$(echo "$NETLIFY_ACCESS_TOKEN" | tr -d '"') + + export _H1="Content-Type: application/json" + export _H2="Authorization: Bearer $token_trimmed" + + : >"$HTTP_HEADER" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$NETLIFY_URL$ep" "" "$m")" + else + response="$(_get "$NETLIFY_URL$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_nic.sh b/letsencrypt/dnsapi/dns_nic.sh new file mode 100644 index 00000000..8a3885bd --- /dev/null +++ b/letsencrypt/dnsapi/dns_nic.sh @@ -0,0 +1,205 @@ +#!/bin/bash + +# +#NIC_ClientID='0dc0xxxxxxxxxxxxxxxxxxxxxxxxce88' +#NIC_ClientSecret='3LTtxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxnuW8' +#NIC_Username="000000/NIC-D" +#NIC_Password="xxxxxxx" + +NIC_Api="https://api.nic.ru" + +dns_nic_add() { + fulldomain="${1}" + txtvalue="${2}" + + if ! _nic_get_authtoken save; then + _err "get NIC auth token failed" + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "Invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + _debug _service "$_service" + + _info "Adding record" + if ! _nic_rest PUT "services/$_service/zones/$_domain/records" "$_sub_domainTXT$txtvalue"; then + _err "Add TXT record error" + return 1 + fi + + if ! _nic_rest POST "services/$_service/zones/$_domain/commit" ""; then + return 1 + fi + _info "Added, OK" +} + +dns_nic_rm() { + fulldomain="${1}" + txtvalue="${2}" + + if ! _nic_get_authtoken; then + _err "get NIC auth token failed" + return 1 + fi + + if ! _get_root "$fulldomain"; then + _err "Invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + _debug _service "$_service" + + if ! _nic_rest GET "services/$_service/zones/$_domain/records"; then + _err "Get records error" + return 1 + fi + + _domain_id=$(printf "%s" "$response" | grep "$_sub_domain" | grep -- "$txtvalue" | sed -r "s/.*"; then + error=$(printf "%s" "$response" | grep "error code" | sed -r "s/.*(.*)<\/error>/\1/g") + _err "Error: $error" + return 1 + fi + + if ! _contains "$response" "success"; then + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_njalla.sh b/letsencrypt/dnsapi/dns_njalla.sh new file mode 100644 index 00000000..dfd12271 --- /dev/null +++ b/letsencrypt/dnsapi/dns_njalla.sh @@ -0,0 +1,168 @@ +#!/bin/bash + +# +#NJALLA_Token="sdfsdfsdfljlbjkljlkjsdfoiwje" + +NJALLA_Api="https://njal.la/api/1/" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_njalla_add() { + fulldomain=$1 + txtvalue=$2 + + NJALLA_Token="${NJALLA_Token:-$(_readaccountconf_mutable NJALLA_Token)}" + + if [ "$NJALLA_Token" ]; then + _saveaccountconf_mutable NJALLA_Token "$NJALLA_Token" + else + NJALLA_Token="" + _err "You didn't specify a Njalla api token yet." + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + # For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so + # we can not use updating anymore. + # count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2) + # _debug count "$count" + # if [ "$count" = "0" ]; then + _info "Adding record" + if _njalla_rest "{\"method\":\"add-record\",\"params\":{\"domain\":\"$_domain\",\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":120}}"; then + if _contains "$response" "$txtvalue"; then + _info "Added, OK" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + return 1 + +} + +#fulldomain txtvalue +dns_njalla_rm() { + fulldomain=$1 + txtvalue=$2 + + NJALLA_Token="${NJALLA_Token:-$(_readaccountconf_mutable NJALLA_Token)}" + + if [ "$NJALLA_Token" ]; then + _saveaccountconf_mutable NJALLA_Token "$NJALLA_Token" + else + NJALLA_Token="" + _err "You didn't specify a Njalla api token yet." + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting records for domain" + if ! _njalla_rest "{\"method\":\"list-records\",\"params\":{\"domain\":\"${_domain}\"}}"; then + return 1 + fi + + if ! echo "$response" | tr -d " " | grep "\"id\":" >/dev/null; then + _err "Error: $response" + return 1 + fi + + records=$(echo "$response" | _egrep_o "\"records\":\s?\[(.*)\]\}" | _egrep_o "\[.*\]" | _egrep_o "\{[^\{\}]*\"id\":[^\{\}]*\}") + count=$(echo "$records" | wc -l) + _debug count "$count" + + if [ "$count" = "0" ]; then + _info "Don't need to remove." + else + echo "$records" | while read -r record; do + record_name=$(echo "$record" | _egrep_o "\"name\":\s?\"[^\"]*\"" | cut -d : -f 2 | tr -d " " | tr -d \") + record_content=$(echo "$record" | _egrep_o "\"content\":\s?\"[^\"]*\"" | cut -d : -f 2 | tr -d " " | tr -d \") + record_id=$(echo "$record" | _egrep_o "\"id\":\s?[0-9]+" | cut -d : -f 2 | tr -d " " | tr -d \") + if [ "$_sub_domain" = "$record_name" ]; then + if [ "$txtvalue" = "$record_content" ]; then + _debug "record_id" "$record_id" + if ! _njalla_rest "{\"method\":\"remove-record\",\"params\":{\"domain\":\"${_domain}\",\"id\":${record_id}}}"; then + _err "Delete record error." + return 1 + fi + echo "$response" | tr -d " " | grep "\"result\"" >/dev/null + fi + fi + done + fi + +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=1 + p=1 + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _njalla_rest "{\"method\":\"get-domain\",\"params\":{\"domain\":\"${h}\"}}"; then + return 1 + fi + + if _contains "$response" "\"$h\""; then + _domain_returned=$(echo "$response" | _egrep_o "\{\"name\": *\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \" | tr -d " ") + if [ "$_domain_returned" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_njalla_rest() { + data="$1" + + token_trimmed=$(echo "$NJALLA_Token" | tr -d '"') + + export _H1="Content-Type: application/json" + export _H2="Accept: application/json" + export _H3="Authorization: Njalla $token_trimmed" + + _debug data "$data" + response="$(_post "$data" "$NJALLA_Api" "" "POST")" + + if [ "$?" != "0" ]; then + _err "error $data" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_nm.sh b/letsencrypt/dnsapi/dns_nm.sh new file mode 100644 index 00000000..6574dd99 --- /dev/null +++ b/letsencrypt/dnsapi/dns_nm.sh @@ -0,0 +1,88 @@ +#!/bin/bash + +######################################################################## +# https://namemaster.de hook script for acme.sh +# +# Environment variables: +# +# - $NM_user (your namemaster.de API username) +# - $NM_sha256 (your namemaster.de API password_as_sha256hash) +# +# Author: Thilo Gass +# Git repo: https://github.com/ThiloGa/acme.sh + +#-- dns_nm_add() - Add TXT record -------------------------------------- +# Usage: dns_nm_add _acme-challenge.subdomain.domain.com "XyZ123..." + +namemaster_api="https://namemaster.de/api/api.php" + +dns_nm_add() { + fulldomain=$1 + txt_value=$2 + _info "Using DNS-01 namemaster hook" + + NM_user="${NM_user:-$(_readaccountconf_mutable NM_user)}" + NM_sha256="${NM_sha256:-$(_readaccountconf_mutable NM_sha256)}" + if [ -z "$NM_user" ] || [ -z "$NM_sha256" ]; then + NM_user="" + NM_sha256="" + _err "No auth details provided. Please set user credentials using the \$NM_user and \$NM_sha256 environment variables." + return 1 + fi + #save the api user and sha256 password to the account conf file. + _debug "Save user and hash" + _saveaccountconf_mutable NM_user "$NM_user" + _saveaccountconf_mutable NM_sha256 "$NM_sha256" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" "$fulldomain" + return 1 + fi + + _info "die Zone lautet:" "$zone" + + get="$namemaster_api?User=$NM_user&Password=$NM_sha256&Antwort=csv&Typ=ACME&zone=$zone&hostname=$fulldomain&TXT=$txt_value&Action=Auto&Lifetime=3600" + + if ! erg="$(_get "$get")"; then + _err "error Adding $fulldomain TXT: $txt_value" + return 1 + fi + + if _contains "$erg" "Success"; then + _info "Success, TXT Added, OK" + else + _err "error Adding $fulldomain TXT: $txt_value erg: $erg" + return 1 + fi + + _debug "ok Auto $fulldomain TXT: $txt_value erg: $erg" + return 0 +} + +dns_nm_rm() { + + fulldomain=$1 + txtvalue=$2 + _info "TXT enrty in $fulldomain is deleted automatically" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + +} + +_get_root() { + + domain=$1 + + get="$namemaster_api?User=$NM_user&Password=$NM_sha256&Typ=acme&hostname=$domain&Action=getzone&antwort=csv" + + if ! zone="$(_get "$get")"; then + _err "error getting Zone" + return 1 + else + if _contains "$zone" "hostname not found"; then + return 1 + fi + fi + +} diff --git a/letsencrypt/dnsapi/dns_nsd.sh b/letsencrypt/dnsapi/dns_nsd.sh new file mode 100644 index 00000000..d73c804b --- /dev/null +++ b/letsencrypt/dnsapi/dns_nsd.sh @@ -0,0 +1,64 @@ +#!/bin/bash + +#Nsd_ZoneFile="/etc/nsd/zones/example.com.zone" +#Nsd_Command="sudo nsd-control reload" + +# args: fulldomain txtvalue +dns_nsd_add() { + fulldomain=$1 + txtvalue=$2 + ttlvalue=300 + + Nsd_ZoneFile="${Nsd_ZoneFile:-$(_readdomainconf Nsd_ZoneFile)}" + Nsd_Command="${Nsd_Command:-$(_readdomainconf Nsd_Command)}" + + # Arg checks + if [ -z "$Nsd_ZoneFile" ] || [ -z "$Nsd_Command" ]; then + Nsd_ZoneFile="" + Nsd_Command="" + _err "Specify ENV vars Nsd_ZoneFile and Nsd_Command" + return 1 + fi + + if [ ! -f "$Nsd_ZoneFile" ]; then + Nsd_ZoneFile="" + Nsd_Command="" + _err "No such file: $Nsd_ZoneFile" + return 1 + fi + + _savedomainconf Nsd_ZoneFile "$Nsd_ZoneFile" + _savedomainconf Nsd_Command "$Nsd_Command" + + echo "$fulldomain. $ttlvalue IN TXT \"$txtvalue\"" >>"$Nsd_ZoneFile" + _info "Added TXT record for $fulldomain" + _debug "Running $Nsd_Command" + if eval "$Nsd_Command"; then + _info "Successfully updated the zone" + return 0 + else + _err "Problem updating the zone" + return 1 + fi +} + +# args: fulldomain txtvalue +dns_nsd_rm() { + fulldomain=$1 + txtvalue=$2 + ttlvalue=300 + + Nsd_ZoneFile="${Nsd_ZoneFile:-$(_readdomainconf Nsd_ZoneFile)}" + Nsd_Command="${Nsd_Command:-$(_readdomainconf Nsd_Command)}" + + sed -i "/$fulldomain. $ttlvalue IN TXT \"$txtvalue\"/d" "$Nsd_ZoneFile" + _info "Removed TXT record for $fulldomain" + _debug "Running $Nsd_Command" + if eval "$Nsd_Command"; then + _info "Successfully reloaded NSD " + return 0 + else + _err "Problem reloading NSD" + return 1 + fi +} diff --git a/letsencrypt/dnsapi/dns_nsone.sh b/letsencrypt/dnsapi/dns_nsone.sh new file mode 100644 index 00000000..e2b8c140 --- /dev/null +++ b/letsencrypt/dnsapi/dns_nsone.sh @@ -0,0 +1,158 @@ +#!/bin/bash + +# bug reports to dev@1e.ca + +# +#NS1_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# + +NS1_Api="https://api.nsone.net/v1" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_nsone_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$NS1_Key" ]; then + NS1_Key="" + _err "You didn't specify nsone dns api key yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf NS1_Key "$NS1_Key" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _nsone_rest GET "zones/${_domain}" + + if ! _contains "$response" "\"records\":"; then + _err "Error" + return 1 + fi + + count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",[^{]*\"type\":\"TXT\"" | wc -l | tr -d " ") + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Adding record" + + if _nsone_rest PUT "zones/$_domain/$fulldomain/TXT" "{\"answers\":[{\"answer\":[\"$txtvalue\"]}],\"type\":\"TXT\",\"domain\":\"$fulldomain\",\"zone\":\"$_domain\",\"ttl\":0}"; then + if _contains "$response" "$fulldomain"; then + _info "Added" + #todo: check if the record takes effect + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + else + _info "Updating record" + prev_txt=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",\"short_answers\":\[\"[^,]*\]" | _head_n 1 | cut -d: -f3 | cut -d, -f1) + _debug "prev_txt" "$prev_txt" + + _nsone_rest POST "zones/$_domain/$fulldomain/TXT" "{\"answers\": [{\"answer\": [\"$txtvalue\"]},{\"answer\": $prev_txt}],\"type\": \"TXT\",\"domain\":\"$fulldomain\",\"zone\": \"$_domain\",\"ttl\":0}" + if [ "$?" = "0" ] && _contains "$response" "$fulldomain"; then + _info "Updated!" + #todo: check if the record takes effect + return 0 + fi + _err "Update error" + return 1 + fi + +} + +#fulldomain +dns_nsone_rm() { + fulldomain=$1 + txtvalue=$2 + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _nsone_rest GET "zones/${_domain}/$fulldomain/TXT" + + count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",.*\"type\":\"TXT\"" | wc -l | tr -d " ") + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Don't need to remove." + else + if ! _nsone_rest DELETE "zones/${_domain}/$fulldomain/TXT"; then + _err "Delete record error." + return 1 + fi + _contains "$response" "" + fi +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + if ! _nsone_rest GET "zones"; then + return 1 + fi + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "\"zone\":\"$h\""; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_nsone_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Accept: application/json" + export _H2="X-NSONE-Key: $NS1_Key" + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$NS1_Api/$ep" "" "$m")" + else + response="$(_get "$NS1_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_nsupdate.sh b/letsencrypt/dnsapi/dns_nsupdate.sh new file mode 100755 index 00000000..a6ac9051 --- /dev/null +++ b/letsencrypt/dnsapi/dns_nsupdate.sh @@ -0,0 +1,98 @@ +#!/bin/bash + +######## Public functions ##################### + +#Usage: dns_nsupdate_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_nsupdate_add() { + fulldomain=$1 + txtvalue=$2 + NSUPDATE_SERVER="${NSUPDATE_SERVER:-$(_readaccountconf_mutable NSUPDATE_SERVER)}" + NSUPDATE_SERVER_PORT="${NSUPDATE_SERVER_PORT:-$(_readaccountconf_mutable NSUPDATE_SERVER_PORT)}" + NSUPDATE_KEY="${NSUPDATE_KEY:-$(_readaccountconf_mutable NSUPDATE_KEY)}" + NSUPDATE_ZONE="${NSUPDATE_ZONE:-$(_readaccountconf_mutable NSUPDATE_ZONE)}" + + _checkKeyFile || return 1 + + # save the dns server and key to the account conf file. + _saveaccountconf_mutable NSUPDATE_SERVER "${NSUPDATE_SERVER}" + _saveaccountconf_mutable NSUPDATE_SERVER_PORT "${NSUPDATE_SERVER_PORT}" + _saveaccountconf_mutable NSUPDATE_KEY "${NSUPDATE_KEY}" + _saveaccountconf_mutable NSUPDATE_ZONE "${NSUPDATE_ZONE}" + + [ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost" + [ -n "${NSUPDATE_SERVER_PORT}" ] || NSUPDATE_SERVER_PORT=53 + + _info "adding ${fulldomain}. 60 in txt \"${txtvalue}\"" + [ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_1" ] && nsdebug="-d" + [ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_2" ] && nsdebug="-D" + if [ -z "${NSUPDATE_ZONE}" ]; then + nsupdate -k "${NSUPDATE_KEY}" $nsdebug < + +NW_API_VERSION="0" + +# dns_nw_add() - Add TXT record +# Usage: dns_nw_add _acme-challenge.subdomain.domain.com "XyZ123..." +dns_nw_add() { + host="${1}" + txtvalue="${2}" + + _debug host "${host}" + _debug txtvalue "${txtvalue}" + + if ! _check_nw_api_creds; then + return 1 + fi + + _info "Using NocWorx (${NW_API_ENDPOINT})" + _debug "Calling: dns_nw_add() '${host}' '${txtvalue}'" + + _debug "Detecting root zone" + if ! _get_root "${host}"; then + _err "Zone for domain does not exist." + return 1 + fi + _debug _zone_id "${_zone_id}" + _debug _sub_domain "${_sub_domain}" + _debug _domain "${_domain}" + + _post_data="{\"zone_id\": \"${_zone_id}\", \"type\": \"TXT\", \"host\": \"${host}\", \"target\": \"${txtvalue}\", \"ttl\": \"300\"}" + + if _rest POST "dns-record" "${_post_data}" && [ -n "${response}" ]; then + _record_id=$(printf "%s\n" "${response}" | _egrep_o "\"record_id\": *[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1) + _debug _record_id "${_record_id}" + + if [ -z "$_record_id" ]; then + _err "Error adding the TXT record." + return 1 + fi + + _info "TXT record successfully added." + return 0 + fi + + return 1 +} + +# dns_nw_rm() - Remove TXT record +# Usage: dns_nw_rm _acme-challenge.subdomain.domain.com "XyZ123..." +dns_nw_rm() { + host="${1}" + txtvalue="${2}" + + _debug host "${host}" + _debug txtvalue "${txtvalue}" + + if ! _check_nw_api_creds; then + return 1 + fi + + _info "Using NocWorx (${NW_API_ENDPOINT})" + _debug "Calling: dns_nw_rm() '${host}'" + + _debug "Detecting root zone" + if ! _get_root "${host}"; then + _err "Zone for domain does not exist." + return 1 + fi + _debug _zone_id "${_zone_id}" + _debug _sub_domain "${_sub_domain}" + _debug _domain "${_domain}" + + _parameters="?zone_id=${_zone_id}" + + if _rest GET "dns-record" "${_parameters}" && [ -n "${response}" ]; then + response="$(echo "${response}" | tr -d "\n" | sed 's/^\[\(.*\)\]$/\1/' | sed -e 's/{"record_id":/|"record_id":/g' | sed 's/|/&{/g' | tr "|" "\n")" + _debug response "${response}" + + record="$(echo "${response}" | _egrep_o "{.*\"host\": *\"${_sub_domain}\", *\"target\": *\"${txtvalue}\".*}")" + _debug record "${record}" + + if [ "${record}" ]; then + _record_id=$(printf "%s\n" "${record}" | _egrep_o "\"record_id\": *[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) + if [ "${_record_id}" ]; then + _debug _record_id "${_record_id}" + + _rest DELETE "dns-record/${_record_id}" + + _info "TXT record successfully deleted." + return 0 + fi + + return 1 + fi + + return 0 + fi + + return 1 +} + +_check_nw_api_creds() { + NW_API_TOKEN="${NW_API_TOKEN:-$(_readaccountconf_mutable NW_API_TOKEN)}" + NW_API_ENDPOINT="${NW_API_ENDPOINT:-$(_readaccountconf_mutable NW_API_ENDPOINT)}" + + if [ -z "${NW_API_ENDPOINT}" ]; then + NW_API_ENDPOINT="https://portal.nexcess.net" + fi + + if [ -z "${NW_API_TOKEN}" ]; then + _err "You have not defined your NW_API_TOKEN." + _err "Please create your token and try again." + _err "If you need to generate a new token, please visit one of the following URLs:" + _err " - https://portal.nexcess.net/api-token" + _err " - https://core.thermo.io/api-token" + _err " - https://my.futurehosting.com/api-token" + + return 1 + fi + + _saveaccountconf_mutable NW_API_TOKEN "${NW_API_TOKEN}" + _saveaccountconf_mutable NW_API_ENDPOINT "${NW_API_ENDPOINT}" +} + +_get_root() { + domain="${1}" + i=2 + p=1 + + if _rest GET "dns-zone"; then + response="$(echo "${response}" | tr -d "\n" | sed 's/^\[\(.*\)\]$/\1/' | sed -e 's/{"zone_id":/|"zone_id":/g' | sed 's/|/&{/g' | tr "|" "\n")" + + _debug response "${response}" + while true; do + h=$(printf "%s" "${domain}" | cut -d . -f $i-100) + _debug h "${h}" + if [ -z "${h}" ]; then + #not valid + return 1 + fi + + hostedzone="$(echo "${response}" | _egrep_o "{.*\"domain\": *\"${h}\".*}")" + if [ "${hostedzone}" ]; then + _zone_id=$(printf "%s\n" "${hostedzone}" | _egrep_o "\"zone_id\": *[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) + if [ "${_zone_id}" ]; then + _sub_domain=$(printf "%s" "${domain}" | cut -d . -f 1-${p}) + _domain="${h}" + return 0 + fi + return 1 + fi + p=$i + i=$(_math "${i}" + 1) + done + fi + return 1 +} + +_rest() { + method="${1}" + ep="/${2}" + data="${3}" + + _debug method "${method}" + _debug ep "${ep}" + + export _H1="Accept: application/json" + export _H2="Content-Type: application/json" + export _H3="Api-Version: ${NW_API_VERSION}" + export _H4="User-Agent: NW-ACME-CLIENT" + export _H5="Authorization: Bearer ${NW_API_TOKEN}" + + if [ "${method}" != "GET" ]; then + _debug data "${data}" + response="$(_post "${data}" "${NW_API_ENDPOINT}${ep}" "" "${method}")" + else + response="$(_get "${NW_API_ENDPOINT}${ep}${data}")" + fi + + if [ "${?}" != "0" ]; then + _err "error ${ep}" + return 1 + fi + _debug2 response "${response}" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_one.sh b/letsencrypt/dnsapi/dns_one.sh new file mode 100644 index 00000000..38911365 --- /dev/null +++ b/letsencrypt/dnsapi/dns_one.sh @@ -0,0 +1,279 @@ +#!/bin/bash +# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*- + +# one.com ui wrapper for acme.sh +# Author: github: @diseq +# Created: 2019-02-17 +# Fixed by: @der-berni +# Modified: 2020-04-07 +# +# Use ONECOM_KeepCnameProxy to keep the CNAME DNS record +# export ONECOM_KeepCnameProxy="1" +# +# export ONECOM_User="username" +# export ONECOM_Password="password" +# +# Usage: +# acme.sh --issue --dns dns_one -d example.com +# +# only single domain supported atm + +dns_one_add() { + fulldomain=$1 + txtvalue=$2 + + if ! _dns_one_login; then + _err "login failed" + return 1 + fi + + _debug "detect the root domain" + if ! _get_root "$fulldomain"; then + _err "root domain not found" + return 1 + fi + + subdomain="${_sub_domain}" + maindomain=${_domain} + + useProxy=0 + if [ "${_sub_domain}" = "_acme-challenge" ]; then + subdomain="proxy${_sub_domain}" + useProxy=1 + fi + + _debug subdomain "$subdomain" + _debug maindomain "$maindomain" + + if [ $useProxy -eq 1 ]; then + #Check if the CNAME exists + _dns_one_getrecord "CNAME" "$_sub_domain" "$subdomain.$maindomain" + if [ -z "$id" ]; then + _info "$(__red "Add CNAME Proxy record: '$(__green "\"$_sub_domain\" => \"$subdomain.$maindomain\"")'")" + _dns_one_addrecord "CNAME" "$_sub_domain" "$subdomain.$maindomain" + + _info "Not valid yet, let's wait 1 hour to take effect." + _sleep 3600 + fi + fi + + #Check if the TXT exists + _dns_one_getrecord "TXT" "$subdomain" "$txtvalue" + if [ -n "$id" ]; then + _info "$(__green "Txt record with the same value found. Skip adding.")" + return 0 + fi + + _dns_one_addrecord "TXT" "$subdomain" "$txtvalue" + if [ -z "$id" ]; then + _err "Add TXT record error." + return 1 + else + _info "$(__green "Added, OK ($id)")" + return 0 + fi +} + +dns_one_rm() { + fulldomain=$1 + txtvalue=$2 + + if ! _dns_one_login; then + _err "login failed" + return 1 + fi + + _debug "detect the root domain" + if ! _get_root "$fulldomain"; then + _err "root domain not found" + return 1 + fi + + subdomain="${_sub_domain}" + maindomain=${_domain} + + useProxy=0 + if [ "${_sub_domain}" = "_acme-challenge" ]; then + subdomain="proxy${_sub_domain}" + useProxy=1 + fi + + _debug subdomain "$subdomain" + _debug maindomain "$maindomain" + if [ $useProxy -eq 1 ]; then + if [ "$ONECOM_KeepCnameProxy" = "1" ]; then + _info "$(__red "Keeping CNAME Proxy record: '$(__green "\"$_sub_domain\" => \"$subdomain.$maindomain\"")'")" + else + #Check if the CNAME exists + _dns_one_getrecord "CNAME" "$_sub_domain" "$subdomain.$maindomain" + if [ -n "$id" ]; then + _info "$(__red "Removing CNAME Proxy record: '$(__green "\"$_sub_domain\" => \"$subdomain.$maindomain\"")'")" + _dns_one_delrecord "$id" + fi + fi + fi + + #Check if the TXT exists + _dns_one_getrecord "TXT" "$subdomain" "$txtvalue" + if [ -z "$id" ]; then + _err "Txt record not found." + return 1 + fi + + # delete entry + if _dns_one_delrecord "$id"; then + _info "$(__green Removed, OK)" + return 0 + else + _err "Removing txt record error." + return 1 + fi +} + +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain="$1" + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + + if [ -z "$h" ]; then + #not valid + return 1 + fi + + response="$(_get "https://www.one.com/admin/api/domains/$h/dns/custom_records")" + + if ! _contains "$response" "CRMRST_000302"; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + _err "Unable to parse this domain" + return 1 +} + +_dns_one_login() { + + # get credentials + ONECOM_KeepCnameProxy="${ONECOM_KeepCnameProxy:-$(_readaccountconf_mutable ONECOM_KeepCnameProxy)}" + ONECOM_KeepCnameProxy="${ONECOM_KeepCnameProxy:-0}" + ONECOM_User="${ONECOM_User:-$(_readaccountconf_mutable ONECOM_User)}" + ONECOM_Password="${ONECOM_Password:-$(_readaccountconf_mutable ONECOM_Password)}" + if [ -z "$ONECOM_User" ] || [ -z "$ONECOM_Password" ]; then + ONECOM_User="" + ONECOM_Password="" + _err "You didn't specify a one.com username and password yet." + _err "Please create the key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable ONECOM_KeepCnameProxy "$ONECOM_KeepCnameProxy" + _saveaccountconf_mutable ONECOM_User "$ONECOM_User" + _saveaccountconf_mutable ONECOM_Password "$ONECOM_Password" + + # Login with user and password + postdata="loginDomain=true" + postdata="$postdata&displayUsername=$ONECOM_User" + postdata="$postdata&username=$ONECOM_User" + postdata="$postdata&targetDomain=" + postdata="$postdata&password1=$ONECOM_Password" + postdata="$postdata&loginTarget=" + #_debug postdata "$postdata" + + response="$(_post "$postdata" "https://www.one.com/admin/login.do" "" "POST" "application/x-www-form-urlencoded")" + #_debug response "$response" + + # Get SessionID + JSESSIONID="$(grep "OneSIDCrmAdmin" "$HTTP_HEADER" | grep "^[Ss]et-[Cc]ookie:" | _head_n 1 | _egrep_o 'OneSIDCrmAdmin=[^;]*;' | tr -d ';')" + _debug jsessionid "$JSESSIONID" + + if [ -z "$JSESSIONID" ]; then + _err "error sessionid cookie not found" + return 1 + fi + + export _H1="Cookie: ${JSESSIONID}" + + return 0 +} + +_dns_one_getrecord() { + type="$1" + name="$2" + value="$3" + if [ -z "$type" ]; then + type="TXT" + fi + if [ -z "$name" ]; then + _err "Record name is empty." + return 1 + fi + + response="$(_get "https://www.one.com/admin/api/domains/$maindomain/dns/custom_records")" + response="$(echo "$response" | _normalizeJson)" + _debug response "$response" + + if [ -z "${value}" ]; then + id=$(printf -- "%s" "$response" | sed -n "s/.*{\"type\":\"dns_custom_records\",\"id\":\"\([^\"]*\)\",\"attributes\":{\"prefix\":\"${name}\",\"type\":\"${type}\",\"content\":\"[^\"]*\",\"priority\":0,\"ttl\":600}.*/\1/p") + response=$(printf -- "%s" "$response" | sed -n "s/.*{\"type\":\"dns_custom_records\",\"id\":\"[^\"]*\",\"attributes\":{\"prefix\":\"${name}\",\"type\":\"${type}\",\"content\":\"\([^\"]*\)\",\"priority\":0,\"ttl\":600}.*/\1/p") + else + id=$(printf -- "%s" "$response" | sed -n "s/.*{\"type\":\"dns_custom_records\",\"id\":\"\([^\"]*\)\",\"attributes\":{\"prefix\":\"${name}\",\"type\":\"${type}\",\"content\":\"${value}\",\"priority\":0,\"ttl\":600}.*/\1/p") + fi + if [ -z "$id" ]; then + return 1 + fi + return 0 +} + +_dns_one_addrecord() { + type="$1" + name="$2" + value="$3" + if [ -z "$type" ]; then + type="TXT" + fi + if [ -z "$name" ]; then + _err "Record name is empty." + return 1 + fi + + postdata="{\"type\":\"dns_custom_records\",\"attributes\":{\"priority\":0,\"ttl\":600,\"type\":\"${type}\",\"prefix\":\"${name}\",\"content\":\"${value}\"}}" + _debug postdata "$postdata" + response="$(_post "$postdata" "https://www.one.com/admin/api/domains/$maindomain/dns/custom_records" "" "POST" "application/json")" + response="$(echo "$response" | _normalizeJson)" + _debug response "$response" + + id=$(echo "$response" | sed -n "s/{\"result\":{\"data\":{\"type\":\"dns_custom_records\",\"id\":\"\([^\"]*\)\",\"attributes\":{\"prefix\":\"$subdomain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"priority\":0,\"ttl\":600}}},\"metadata\":null}/\1/p") + + if [ -z "$id" ]; then + return 1 + else + return 0 + fi +} + +_dns_one_delrecord() { + id="$1" + if [ -z "$id" ]; then + return 1 + fi + + response="$(_post "" "https://www.one.com/admin/api/domains/$maindomain/dns/custom_records/$id" "" "DELETE" "application/json")" + response="$(echo "$response" | _normalizeJson)" + _debug response "$response" + + if [ "$response" = '{"result":null,"metadata":null}' ]; then + return 0 + else + return 1 + fi +} diff --git a/letsencrypt/dnsapi/dns_online.sh b/letsencrypt/dnsapi/dns_online.sh new file mode 100755 index 00000000..c330fe4f --- /dev/null +++ b/letsencrypt/dnsapi/dns_online.sh @@ -0,0 +1,217 @@ +#!/bin/bash + +# Online API +# https://console.online.net/en/api/ +# +# Requires Online API key set in ONLINE_API_KEY + +######## Public functions ##################### + +ONLINE_API="https://api.online.net/api/v1" + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_online_add() { + fulldomain=$1 + txtvalue=$2 + + if ! _online_check_config; then + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + _debug _real_dns_version "$_real_dns_version" + + _info "Creating temporary zone version" + _online_create_temporary_zone_version + _info "Enabling temporary zone version" + _online_enable_zone "$_temporary_dns_version" + + _info "Adding record" + _online_create_TXT_record "$_real_dns_version" "$_sub_domain" "$txtvalue" + _info "Disabling temporary version" + _online_enable_zone "$_real_dns_version" + _info "Destroying temporary version" + _online_destroy_zone "$_temporary_dns_version" + + _info "Record added." + return 0 +} + +#fulldomain +dns_online_rm() { + fulldomain=$1 + txtvalue=$2 + + if ! _online_check_config; then + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + _debug _real_dns_version "$_real_dns_version" + + _debug "Getting txt records" + if ! _online_rest GET "domain/$_domain/version/active"; then + return 1 + fi + + rid=$(echo "$response" | _egrep_o "\"id\":[0-9]+,\"name\":\"$_sub_domain\",\"data\":\"\\\u0022$txtvalue\\\u0022\"" | cut -d ':' -f 2 | cut -d ',' -f 1) + _debug rid "$rid" + if [ -z "$rid" ]; then + return 1 + fi + + _info "Creating temporary zone version" + _online_create_temporary_zone_version + _info "Enabling temporary zone version" + _online_enable_zone "$_temporary_dns_version" + + _info "Removing DNS record" + _online_rest DELETE "domain/$_domain/version/$_real_dns_version/zone/$rid" + _info "Disabling temporary version" + _online_enable_zone "$_real_dns_version" + _info "Destroying temporary version" + _online_destroy_zone "$_temporary_dns_version" + + return 0 +} + +#################### Private functions below ################################## + +_online_check_config() { + ONLINE_API_KEY="${ONLINE_API_KEY:-$(_readaccountconf_mutable ONLINE_API_KEY)}" + if [ -z "$ONLINE_API_KEY" ]; then + _err "No API key specified for Online API." + _err "Create your key and export it as ONLINE_API_KEY" + return 1 + fi + if ! _online_rest GET "domain/"; then + _err "Invalid API key specified for Online API." + return 1 + fi + + _saveaccountconf_mutable ONLINE_API_KEY "$ONLINE_API_KEY" + + return 0 +} + +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + #not valid + return 1 + fi + + _online_rest GET "domain/$h/version/active" + + if ! _contains "$response" "Domain not found" >/dev/null; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + _real_dns_version=$(echo "$response" | _egrep_o '"uuid_ref":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + _err "Unable to retrive DNS zone matching this domain" + return 1 +} + +# this function create a temporary zone version +# as online.net does not allow updating an active version +_online_create_temporary_zone_version() { + + _online_rest POST "domain/$_domain/version" "name=acme.sh" + if [ "$?" != "0" ]; then + return 1 + fi + + _temporary_dns_version=$(echo "$response" | _egrep_o '"uuid_ref":.*' | cut -d ':' -f 2 | cut -d '"' -f 2) + + # Creating a dummy record in this temporary version, because online.net doesn't accept enabling an empty version + _online_create_TXT_record "$_temporary_dns_version" "dummy.acme.sh" "dummy" + + return 0 +} + +_online_destroy_zone() { + version_id=$1 + _online_rest DELETE "domain/$_domain/version/$version_id" + + if [ "$?" != "0" ]; then + return 1 + fi + return 0 +} + +_online_enable_zone() { + version_id=$1 + _online_rest PATCH "domain/$_domain/version/$version_id/enable" + + if [ "$?" != "0" ]; then + return 1 + fi + return 0 +} + +_online_create_TXT_record() { + version=$1 + txt_name=$2 + txt_value=$3 + + _online_rest POST "domain/$_domain/version/$version/zone" "type=TXT&name=$txt_name&data=%22$txt_value%22&ttl=60&priority=0" + + # Note : the normal, expected response SHOULD be "Unknown method". + # this happens because the API HTTP response contains a Location: header, that redirect + # to an unknown online.net endpoint. + if [ "$?" != "0" ] || _contains "$response" "Unknown method" || _contains "$response" "\$ref"; then + return 0 + else + _err "error $response" + return 1 + fi +} + +_online_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + _online_url="$ONLINE_API/$ep" + _debug2 _online_url "$_online_url" + export _H1="Authorization: Bearer $ONLINE_API_KEY" + export _H2="X-Pretty-JSON: 1" + if [ "$data" ] || [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$_online_url" "" "$m")" + else + response="$(_get "$_online_url")" + fi + if [ "$?" != "0" ] || _contains "$response" "invalid_grant" || _contains "$response" "Method not allowed"; then + _err "error $response" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_openprovider.sh b/letsencrypt/dnsapi/dns_openprovider.sh new file mode 100755 index 00000000..84058f60 --- /dev/null +++ b/letsencrypt/dnsapi/dns_openprovider.sh @@ -0,0 +1,247 @@ +#!/bin/bash + +# This is the OpenProvider API wrapper for acme.sh +# +# Author: Sylvia van Os +# Report Bugs here: https://github.com/acmesh-official/acme.sh/issues/2104 +# +# export OPENPROVIDER_USER="username" +# export OPENPROVIDER_PASSWORDHASH="hashed_password" +# +# Usage: +# acme.sh --issue --dns dns_openprovider -d example.com + +OPENPROVIDER_API="https://api.openprovider.eu/" +#OPENPROVIDER_API="https://api.cte.openprovider.eu/" # Test API + +######## Public functions ##################### + +#Usage: dns_openprovider_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_openprovider_add() { + fulldomain="$1" + txtvalue="$2" + + OPENPROVIDER_USER="${OPENPROVIDER_USER:-$(_readaccountconf_mutable OPENPROVIDER_USER)}" + OPENPROVIDER_PASSWORDHASH="${OPENPROVIDER_PASSWORDHASH:-$(_readaccountconf_mutable OPENPROVIDER_PASSWORDHASH)}" + + if [ -z "$OPENPROVIDER_USER" ] || [ -z "$OPENPROVIDER_PASSWORDHASH" ]; then + _err "You didn't specify the openprovider user and/or password hash." + return 1 + fi + + # save the username and password to the account conf file. + _saveaccountconf_mutable OPENPROVIDER_USER "$OPENPROVIDER_USER" + _saveaccountconf_mutable OPENPROVIDER_PASSWORDHASH "$OPENPROVIDER_PASSWORDHASH" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _domain_name "$_domain_name" + _debug _domain_extension "$_domain_extension" + + _debug "Getting current records" + existing_items="" + results_retrieved=0 + while true; do + _openprovider_request "$(printf '%s.%s%s' "$_domain_name" "$_domain_extension" "$results_retrieved")" + + items="$response" + while true; do + item="$(echo "$items" | _egrep_o '.*<\/openXML>' | sed -n 's/.*\(.*<\/item>\).*/\1/p')" + _debug existing_items "$existing_items" + _debug results_retrieved "$results_retrieved" + _debug item "$item" + + if [ -z "$item" ]; then + break + fi + + tmpitem="$(echo "$item" | sed 's/\*/\\*/g')" + items="$(echo "$items" | sed "s|${tmpitem}||")" + + results_retrieved="$(_math "$results_retrieved" + 1)" + new_item="$(echo "$item" | sed -n 's/.*.*\(\(.*\)\.'"$_domain_name"'\.'"$_domain_extension"'<\/name>.*\(.*<\/type>\).*\(.*<\/value>\).*\(.*<\/prio>\).*\(.*<\/ttl>\)\).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p')" + if [ -z "$new_item" ]; then + # Domain apex + new_item="$(echo "$item" | sed -n 's/.*.*\(\(.*\)'"$_domain_name"'\.'"$_domain_extension"'<\/name>.*\(.*<\/type>\).*\(.*<\/value>\).*\(.*<\/prio>\).*\(.*<\/ttl>\)\).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p')" + fi + + if [ -z "$(echo "$new_item" | _egrep_o ".*(A|AAAA|CNAME|MX|SPF|SRV|TXT|TLSA|SSHFP|CAA|NS)<\/type>.*")" ]; then + _debug "not an allowed record type, skipping" "$new_item" + continue + fi + + existing_items="$existing_items$new_item" + done + + total="$(echo "$response" | _egrep_o '.*?<\/total>' | sed -n 's/.*\(.*\)<\/total>.*/\1/p')" + + _debug total "$total" + if [ "$results_retrieved" -eq "$total" ]; then + break + fi + done + + _debug "Creating acme record" + acme_record="$(echo "$fulldomain" | sed -e "s/.$_domain_name.$_domain_extension$//")" + _openprovider_request "$(printf '%s%smaster%s%sTXT%s600' "$_domain_name" "$_domain_extension" "$existing_items" "$acme_record" "$txtvalue")" + + return 0 +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_openprovider_rm() { + fulldomain="$1" + txtvalue="$2" + + OPENPROVIDER_USER="${OPENPROVIDER_USER:-$(_readaccountconf_mutable OPENPROVIDER_USER)}" + OPENPROVIDER_PASSWORDHASH="${OPENPROVIDER_PASSWORDHASH:-$(_readaccountconf_mutable OPENPROVIDER_PASSWORDHASH)}" + + if [ -z "$OPENPROVIDER_USER" ] || [ -z "$OPENPROVIDER_PASSWORDHASH" ]; then + _err "You didn't specify the openprovider user and/or password hash." + return 1 + fi + + # save the username and password to the account conf file. + _saveaccountconf_mutable OPENPROVIDER_USER "$OPENPROVIDER_USER" + _saveaccountconf_mutable OPENPROVIDER_PASSWORDHASH "$OPENPROVIDER_PASSWORDHASH" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _domain_name "$_domain_name" + _debug _domain_extension "$_domain_extension" + + _debug "Getting current records" + existing_items="" + results_retrieved=0 + while true; do + _openprovider_request "$(printf '%s.%s%s' "$_domain_name" "$_domain_extension" "$results_retrieved")" + + # Remove acme records from items + items="$response" + while true; do + item="$(echo "$items" | _egrep_o '.*<\/openXML>' | sed -n 's/.*\(.*<\/item>\).*/\1/p')" + _debug existing_items "$existing_items" + _debug results_retrieved "$results_retrieved" + _debug item "$item" + + if [ -z "$item" ]; then + break + fi + + tmpitem="$(echo "$item" | sed 's/\*/\\*/g')" + items="$(echo "$items" | sed "s|${tmpitem}||")" + + results_retrieved="$(_math "$results_retrieved" + 1)" + if ! echo "$item" | grep -v "$fulldomain"; then + _debug "acme record, skipping" "$item" + continue + fi + + new_item="$(echo "$item" | sed -n 's/.*.*\(\(.*\)\.'"$_domain_name"'\.'"$_domain_extension"'<\/name>.*\(.*<\/type>\).*\(.*<\/value>\).*\(.*<\/prio>\).*\(.*<\/ttl>\)\).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p')" + + if [ -z "$new_item" ]; then + # domain apex + new_item="$(echo "$item" | sed -n 's/.*.*\(\(.*\)'"$_domain_name"'\.'"$_domain_extension"'<\/name>.*\(.*<\/type>\).*\(.*<\/value>\).*\(.*<\/prio>\).*\(.*<\/ttl>\)\).*<\/item>.*/\2<\/name>\3\4\5\6<\/item>/p')" + fi + + if [ -z "$(echo "$new_item" | _egrep_o ".*(A|AAAA|CNAME|MX|SPF|SRV|TXT|TLSA|SSHFP|CAA|NS)<\/type>.*")" ]; then + _debug "not an allowed record type, skipping" "$new_item" + continue + fi + + existing_items="$existing_items$new_item" + done + + total="$(echo "$response" | _egrep_o '.*?<\/total>' | sed -n 's/.*\(.*\)<\/total>.*/\1/p')" + + _debug total "$total" + + if [ "$results_retrieved" -eq "$total" ]; then + break + fi + done + + _debug "Removing acme record" + _openprovider_request "$(printf '%s%smaster%s' "$_domain_name" "$_domain_extension" "$existing_items")" + + return 0 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _domain_name=domain +# _domain_extension=com +_get_root() { + domain=$1 + i=2 + + results_retrieved=0 + while true; do + h=$(echo "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + _openprovider_request "$(printf '%s%s' "$(echo "$h" | cut -d . -f 1)" "$results_retrieved")" + + items="$response" + while true; do + item="$(echo "$items" | _egrep_o '.*<\/openXML>' | sed -n 's/.*\(.*<\/domain>\).*/\1/p')" + _debug existing_items "$existing_items" + _debug results_retrieved "$results_retrieved" + _debug item "$item" + + if [ -z "$item" ]; then + break + fi + + tmpitem="$(echo "$item" | sed 's/\*/\\*/g')" + items="$(echo "$items" | sed "s|${tmpitem}||")" + + results_retrieved="$(_math "$results_retrieved" + 1)" + + _domain_name="$(echo "$item" | sed -n 's/.*.*\(.*\)<\/name>.*<\/domain>.*/\1/p')" + _domain_extension="$(echo "$item" | sed -n 's/.*.*\(.*\)<\/extension>.*<\/domain>.*/\1/p')" + _debug _domain_name "$_domain_name" + _debug _domain_extension "$_domain_extension" + if [ "$_domain_name.$_domain_extension" = "$h" ]; then + return 0 + fi + done + + total="$(echo "$response" | _egrep_o '.*?<\/total>' | sed -n 's/.*\(.*\)<\/total>.*/\1/p')" + + _debug total "$total" + + if [ "$results_retrieved" -eq "$total" ]; then + results_retrieved=0 + i="$(_math "$i" + 1)" + fi + done + return 1 +} + +_openprovider_request() { + request_xml=$1 + + xml_prefix='' + xml_content=$(printf '%s%s%s' "$OPENPROVIDER_USER" "$OPENPROVIDER_PASSWORDHASH" "$request_xml") + response="$(_post "$(echo "$xml_prefix$xml_content" | tr -d '\n')" "$OPENPROVIDER_API" "" "POST" "application/xml")" + _debug response "$response" + if ! _contains "$response" "0.*"; then + _err "API request failed." + return 1 + fi +} diff --git a/letsencrypt/dnsapi/dns_openstack.sh b/letsencrypt/dnsapi/dns_openstack.sh new file mode 100755 index 00000000..c43c4a45 --- /dev/null +++ b/letsencrypt/dnsapi/dns_openstack.sh @@ -0,0 +1,348 @@ +#!/bin/bash + +# OpenStack Designate API plugin +# +# This requires you to have OpenStackClient and python-desginateclient +# installed. +# +# You will require Keystone V3 credentials loaded into your environment, which +# could be either password or v3applicationcredential type. +# +# Author: Andy Botting + +######## Public functions ##################### + +# Usage: dns_openstack_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_openstack_add() { + fulldomain=$1 + txtvalue=$2 + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + _dns_openstack_credentials || return $? + _dns_openstack_check_setup || return $? + _dns_openstack_find_zone || return $? + _dns_openstack_get_recordset || return $? + _debug _recordset_id "$_recordset_id" + if [ -n "$_recordset_id" ]; then + _dns_openstack_get_records || return $? + _debug _records "$_records" + fi + _dns_openstack_create_recordset || return $? +} + +# Usage: dns_openstack_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +# Remove the txt record after validation. +dns_openstack_rm() { + fulldomain=$1 + txtvalue=$2 + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + _dns_openstack_credentials || return $? + _dns_openstack_check_setup || return $? + _dns_openstack_find_zone || return $? + _dns_openstack_get_recordset || return $? + _debug _recordset_id "$_recordset_id" + if [ -n "$_recordset_id" ]; then + _dns_openstack_get_records || return $? + _debug _records "$_records" + fi + _dns_openstack_delete_recordset || return $? +} + +#################### Private functions below ################################## + +_dns_openstack_create_recordset() { + + if [ -z "$_recordset_id" ]; then + _info "Creating a new recordset" + if ! _recordset_id=$(openstack recordset create -c id -f value --type TXT --record "$txtvalue" "$_zone_id" "$fulldomain."); then + _err "No recordset ID found after create" + return 1 + fi + else + _info "Updating existing recordset" + # Build new list of --record args for update + _record_args="--record $txtvalue" + for _rec in $_records; do + _record_args="$_record_args --record $_rec" + done + # shellcheck disable=SC2086 + if ! _recordset_id=$(openstack recordset set -c id -f value $_record_args "$_zone_id" "$fulldomain."); then + _err "Recordset update failed" + return 1 + fi + fi + + _max_retries=60 + _sleep_sec=5 + _retry_times=0 + while [ "$_retry_times" -lt "$_max_retries" ]; do + _retry_times=$(_math "$_retry_times" + 1) + _debug3 _retry_times "$_retry_times" + + _record_status=$(openstack recordset show -c status -f value "$_zone_id" "$_recordset_id") + _info "Recordset status is $_record_status" + if [ "$_record_status" = "ACTIVE" ]; then + return 0 + elif [ "$_record_status" = "ERROR" ]; then + return 1 + else + _sleep $_sleep_sec + fi + done + + _err "Recordset failed to become ACTIVE" + return 1 +} + +_dns_openstack_delete_recordset() { + + if [ "$_records" = "$txtvalue" ]; then + _info "Only one record found, deleting recordset" + if ! openstack recordset delete "$_zone_id" "$fulldomain." >/dev/null; then + _err "Failed to delete recordset" + return 1 + fi + else + _info "Found existing records, updating recordset" + # Build new list of --record args for update + _record_args="" + for _rec in $_records; do + if [ "$_rec" = "$txtvalue" ]; then + continue + fi + _record_args="$_record_args --record $_rec" + done + # shellcheck disable=SC2086 + if ! openstack recordset set -c id -f value $_record_args "$_zone_id" "$fulldomain." >/dev/null; then + _err "Recordset update failed" + return 1 + fi + fi +} + +_dns_openstack_get_root() { + # Take the full fqdn and strip away pieces until we get an exact zone name + # match. For example, _acme-challenge.something.domain.com might need to go + # into something.domain.com or domain.com + _zone_name=$1 + _zone_list=$2 + while [ "$_zone_name" != "" ]; do + _zone_name="$(echo "$_zone_name" | sed 's/[^.]*\.*//')" + echo "$_zone_list" | while read -r id name; do + if _startswith "$_zone_name." "$name"; then + echo "$id" + fi + done + done | _head_n 1 +} + +_dns_openstack_find_zone() { + if ! _zone_list="$(openstack zone list -c id -c name -f value)"; then + _err "Can't list zones. Check your OpenStack credentials" + return 1 + fi + _debug _zone_list "$_zone_list" + + if ! _zone_id="$(_dns_openstack_get_root "$fulldomain" "$_zone_list")"; then + _err "Can't find a matching zone. Check your OpenStack credentials" + return 1 + fi + _debug _zone_id "$_zone_id" +} + +_dns_openstack_get_records() { + if ! _records=$(openstack recordset show -c records -f value "$_zone_id" "$fulldomain."); then + _err "Failed to get records" + return 1 + fi + return 0 +} + +_dns_openstack_get_recordset() { + if ! _recordset_id=$(openstack recordset list -c id -f value --name "$fulldomain." "$_zone_id"); then + _err "Failed to get recordset" + return 1 + fi + return 0 +} + +_dns_openstack_check_setup() { + if ! _exists openstack; then + _err "OpenStack client not found" + return 1 + fi +} + +_dns_openstack_credentials() { + _debug "Check OpenStack credentials" + + # If we have OS_AUTH_URL already set in the environment, then assume we want + # to use those, otherwise use stored credentials + if [ -n "$OS_AUTH_URL" ]; then + _debug "OS_AUTH_URL env var found, using environment" + else + _debug "OS_AUTH_URL not found, loading stored credentials" + OS_AUTH_URL="${OS_AUTH_URL:-$(_readaccountconf_mutable OS_AUTH_URL)}" + OS_IDENTITY_API_VERSION="${OS_IDENTITY_API_VERSION:-$(_readaccountconf_mutable OS_IDENTITY_API_VERSION)}" + OS_AUTH_TYPE="${OS_AUTH_TYPE:-$(_readaccountconf_mutable OS_AUTH_TYPE)}" + OS_APPLICATION_CREDENTIAL_ID="${OS_APPLICATION_CREDENTIAL_ID:-$(_readaccountconf_mutable OS_APPLICATION_CREDENTIAL_ID)}" + OS_APPLICATION_CREDENTIAL_SECRET="${OS_APPLICATION_CREDENTIAL_SECRET:-$(_readaccountconf_mutable OS_APPLICATION_CREDENTIAL_SECRET)}" + OS_USERNAME="${OS_USERNAME:-$(_readaccountconf_mutable OS_USERNAME)}" + OS_PASSWORD="${OS_PASSWORD:-$(_readaccountconf_mutable OS_PASSWORD)}" + OS_PROJECT_NAME="${OS_PROJECT_NAME:-$(_readaccountconf_mutable OS_PROJECT_NAME)}" + OS_PROJECT_ID="${OS_PROJECT_ID:-$(_readaccountconf_mutable OS_PROJECT_ID)}" + OS_USER_DOMAIN_NAME="${OS_USER_DOMAIN_NAME:-$(_readaccountconf_mutable OS_USER_DOMAIN_NAME)}" + OS_USER_DOMAIN_ID="${OS_USER_DOMAIN_ID:-$(_readaccountconf_mutable OS_USER_DOMAIN_ID)}" + OS_PROJECT_DOMAIN_NAME="${OS_PROJECT_DOMAIN_NAME:-$(_readaccountconf_mutable OS_PROJECT_DOMAIN_NAME)}" + OS_PROJECT_DOMAIN_ID="${OS_PROJECT_DOMAIN_ID:-$(_readaccountconf_mutable OS_PROJECT_DOMAIN_ID)}" + fi + + # Check each var and either save or clear it depending on whether its set. + # The helps us clear out old vars in the case where a user may want + # to switch between password and app creds + _debug "OS_AUTH_URL" "$OS_AUTH_URL" + if [ -n "$OS_AUTH_URL" ]; then + export OS_AUTH_URL + _saveaccountconf_mutable OS_AUTH_URL "$OS_AUTH_URL" + else + unset OS_AUTH_URL + _clearaccountconf SAVED_OS_AUTH_URL + fi + + _debug "OS_IDENTITY_API_VERSION" "$OS_IDENTITY_API_VERSION" + if [ -n "$OS_IDENTITY_API_VERSION" ]; then + export OS_IDENTITY_API_VERSION + _saveaccountconf_mutable OS_IDENTITY_API_VERSION "$OS_IDENTITY_API_VERSION" + else + unset OS_IDENTITY_API_VERSION + _clearaccountconf SAVED_OS_IDENTITY_API_VERSION + fi + + _debug "OS_AUTH_TYPE" "$OS_AUTH_TYPE" + if [ -n "$OS_AUTH_TYPE" ]; then + export OS_AUTH_TYPE + _saveaccountconf_mutable OS_AUTH_TYPE "$OS_AUTH_TYPE" + else + unset OS_AUTH_TYPE + _clearaccountconf SAVED_OS_AUTH_TYPE + fi + + _debug "OS_APPLICATION_CREDENTIAL_ID" "$OS_APPLICATION_CREDENTIAL_ID" + if [ -n "$OS_APPLICATION_CREDENTIAL_ID" ]; then + export OS_APPLICATION_CREDENTIAL_ID + _saveaccountconf_mutable OS_APPLICATION_CREDENTIAL_ID "$OS_APPLICATION_CREDENTIAL_ID" + else + unset OS_APPLICATION_CREDENTIAL_ID + _clearaccountconf SAVED_OS_APPLICATION_CREDENTIAL_ID + fi + + _secure_debug "OS_APPLICATION_CREDENTIAL_SECRET" "$OS_APPLICATION_CREDENTIAL_SECRET" + if [ -n "$OS_APPLICATION_CREDENTIAL_SECRET" ]; then + export OS_APPLICATION_CREDENTIAL_SECRET + _saveaccountconf_mutable OS_APPLICATION_CREDENTIAL_SECRET "$OS_APPLICATION_CREDENTIAL_SECRET" + else + unset OS_APPLICATION_CREDENTIAL_SECRET + _clearaccountconf SAVED_OS_APPLICATION_CREDENTIAL_SECRET + fi + + _debug "OS_USERNAME" "$OS_USERNAME" + if [ -n "$OS_USERNAME" ]; then + export OS_USERNAME + _saveaccountconf_mutable OS_USERNAME "$OS_USERNAME" + else + unset OS_USERNAME + _clearaccountconf SAVED_OS_USERNAME + fi + + _secure_debug "OS_PASSWORD" "$OS_PASSWORD" + if [ -n "$OS_PASSWORD" ]; then + export OS_PASSWORD + _saveaccountconf_mutable OS_PASSWORD "$OS_PASSWORD" + else + unset OS_PASSWORD + _clearaccountconf SAVED_OS_PASSWORD + fi + + _debug "OS_PROJECT_NAME" "$OS_PROJECT_NAME" + if [ -n "$OS_PROJECT_NAME" ]; then + export OS_PROJECT_NAME + _saveaccountconf_mutable OS_PROJECT_NAME "$OS_PROJECT_NAME" + else + unset OS_PROJECT_NAME + _clearaccountconf SAVED_OS_PROJECT_NAME + fi + + _debug "OS_PROJECT_ID" "$OS_PROJECT_ID" + if [ -n "$OS_PROJECT_ID" ]; then + export OS_PROJECT_ID + _saveaccountconf_mutable OS_PROJECT_ID "$OS_PROJECT_ID" + else + unset OS_PROJECT_ID + _clearaccountconf SAVED_OS_PROJECT_ID + fi + + _debug "OS_USER_DOMAIN_NAME" "$OS_USER_DOMAIN_NAME" + if [ -n "$OS_USER_DOMAIN_NAME" ]; then + export OS_USER_DOMAIN_NAME + _saveaccountconf_mutable OS_USER_DOMAIN_NAME "$OS_USER_DOMAIN_NAME" + else + unset OS_USER_DOMAIN_NAME + _clearaccountconf SAVED_OS_USER_DOMAIN_NAME + fi + + _debug "OS_USER_DOMAIN_ID" "$OS_USER_DOMAIN_ID" + if [ -n "$OS_USER_DOMAIN_ID" ]; then + export OS_USER_DOMAIN_ID + _saveaccountconf_mutable OS_USER_DOMAIN_ID "$OS_USER_DOMAIN_ID" + else + unset OS_USER_DOMAIN_ID + _clearaccountconf SAVED_OS_USER_DOMAIN_ID + fi + + _debug "OS_PROJECT_DOMAIN_NAME" "$OS_PROJECT_DOMAIN_NAME" + if [ -n "$OS_PROJECT_DOMAIN_NAME" ]; then + export OS_PROJECT_DOMAIN_NAME + _saveaccountconf_mutable OS_PROJECT_DOMAIN_NAME "$OS_PROJECT_DOMAIN_NAME" + else + unset OS_PROJECT_DOMAIN_NAME + _clearaccountconf SAVED_OS_PROJECT_DOMAIN_NAME + fi + + _debug "OS_PROJECT_DOMAIN_ID" "$OS_PROJECT_DOMAIN_ID" + if [ -n "$OS_PROJECT_DOMAIN_ID" ]; then + export OS_PROJECT_DOMAIN_ID + _saveaccountconf_mutable OS_PROJECT_DOMAIN_ID "$OS_PROJECT_DOMAIN_ID" + else + unset OS_PROJECT_DOMAIN_ID + _clearaccountconf SAVED_OS_PROJECT_DOMAIN_ID + fi + + if [ "$OS_AUTH_TYPE" = "v3applicationcredential" ]; then + # Application Credential auth + if [ -z "$OS_APPLICATION_CREDENTIAL_ID" ] || [ -z "$OS_APPLICATION_CREDENTIAL_SECRET" ]; then + _err "When using OpenStack application credentials, OS_APPLICATION_CREDENTIAL_ID" + _err "and OS_APPLICATION_CREDENTIAL_SECRET must be set." + _err "Please check your credentials and try again." + return 1 + fi + else + # Password auth + if [ -z "$OS_USERNAME" ] || [ -z "$OS_PASSWORD" ]; then + _err "OpenStack username or password not found." + _err "Please check your credentials and try again." + return 1 + fi + + if [ -z "$OS_PROJECT_NAME" ] && [ -z "$OS_PROJECT_ID" ]; then + _err "When using password authentication, OS_PROJECT_NAME or" + _err "OS_PROJECT_ID must be set." + _err "Please check your credentials and try again." + return 1 + fi + fi + + return 0 +} diff --git a/letsencrypt/dnsapi/dns_opnsense.sh b/letsencrypt/dnsapi/dns_opnsense.sh new file mode 100755 index 00000000..84ba546c --- /dev/null +++ b/letsencrypt/dnsapi/dns_opnsense.sh @@ -0,0 +1,273 @@ +#!/bin/bash + +#OPNsense Bind API +#https://docs.opnsense.org/development/api.html +# +#OPNs_Host="opnsense.example.com" +#OPNs_Port="443" +# optional, defaults to 443 if unset +#OPNs_Key="qocfU9RSbt8vTIBcnW8bPqCrpfAHMDvj5OzadE7Str+rbjyCyk7u6yMrSCHtBXabgDDXx/dY0POUp7ZA" +#OPNs_Token="pZEQ+3ce8dDlfBBdg3N8EpqpF5I1MhFqdxX06le6Gl8YzyQvYCfCzNaFX9O9+IOSyAs7X71fwdRiZ+Lv" +#OPNs_Api_Insecure=0 +# optional, defaults to 0 if unset +# Set 1 for insecure and 0 for secure -> difference is whether ssl cert is checked for validity (0) or whether it is just accepted (1) + +######## Public functions ##################### +#Usage: add _acme-challenge.www.domain.com "123456789ABCDEF0000000000000000000000000000000000000" +#fulldomain +#txtvalue +OPNs_DefaultPort=443 +OPNs_DefaultApi_Insecure=0 + +dns_opnsense_add() { + fulldomain=$1 + txtvalue=$2 + + _opns_check_auth || return 1 + + if ! set_record "$fulldomain" "$txtvalue"; then + return 1 + fi + + return 0 +} + +#fulldomain +dns_opnsense_rm() { + fulldomain=$1 + txtvalue=$2 + + _opns_check_auth || return 1 + + if ! rm_record "$fulldomain" "$txtvalue"; then + return 1 + fi + + return 0 +} + +set_record() { + fulldomain=$1 + new_challenge=$2 + _info "Adding record $fulldomain with challenge: $new_challenge" + + _debug "Detect root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _domain "$_domain" + _debug _host "$_host" + _debug _domainid "$_domainid" + _return_str="" + _record_string="" + _build_record_string "$_domainid" "$_host" "$new_challenge" + _uuid="" + if _existingchallenge "$_domain" "$_host" "$new_challenge"; then + # Update + if _opns_rest "POST" "/record/setRecord/${_uuid}" "$_record_string"; then + _return_str="$response" + else + return 1 + fi + + else + #create + if _opns_rest "POST" "/record/addRecord" "$_record_string"; then + _return_str="$response" + else + return 1 + fi + fi + + if echo "$_return_str" | _egrep_o "\"result\":\"saved\"" >/dev/null; then + _opns_rest "POST" "/service/reconfigure" "{}" + _debug "Record created" + else + _err "Error creating record $_record_string" + return 1 + fi + + return 0 +} + +rm_record() { + fulldomain=$1 + new_challenge="$2" + _info "Remove record $fulldomain with challenge: $new_challenge" + + _debug "Detect root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _domain "$_domain" + _debug _host "$_host" + _debug _domainid "$_domainid" + _uuid="" + if _existingchallenge "$_domain" "$_host" "$new_challenge"; then + # Delete + if _opns_rest "POST" "/record/delRecord/${_uuid}" "\{\}"; then + if echo "$_return_str" | _egrep_o "\"result\":\"deleted\"" >/dev/null; then + _opns_rest "POST" "/service/reconfigure" "{}" + _debug "Record deleted" + else + _err "Error deleting record $_host from domain $fulldomain" + return 1 + fi + else + _err "Error deleting record $_host from domain $fulldomain" + return 1 + fi + else + _info "Record not found, nothing to remove" + fi + + return 0 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _domainid=domid +#_domain=domain.com +_get_root() { + domain=$1 + i=2 + p=1 + if _opns_rest "GET" "/domain/get"; then + _domain_response="$response" + else + return 1 + fi + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + #not valid + return 1 + fi + _debug h "$h" + id=$(echo "$_domain_response" | _egrep_o "\"[^\"]*\":{\"enabled\":\"1\",\"type\":{\"master\":{\"value\":\"master\",\"selected\":1},\"slave\":{\"value\":\"slave\",\"selected\":0}},\"masterip\":\"[^\"]*\"(,\"allownotifyslave\":{\"\":{[^}]*}},|,)\"domainname\":\"${h}\"" | cut -d ':' -f 1 | cut -d '"' -f 2) + + if [ -n "$id" ]; then + _debug id "$id" + _host=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="${h}" + _domainid="${id}" + return 0 + fi + p=$i + i=$(_math $i + 1) + done + _debug "$domain not found" + + return 1 +} + +_opns_rest() { + method=$1 + ep=$2 + data=$3 + #Percent encode user and token + key=$(echo "$OPNs_Key" | tr -d "\n\r" | _url_encode) + token=$(echo "$OPNs_Token" | tr -d "\n\r" | _url_encode) + + opnsense_url="https://${key}:${token}@${OPNs_Host}:${OPNs_Port:-$OPNs_DefaultPort}/api/bind${ep}" + export _H1="Content-Type: application/json" + _debug2 "Try to call api: https://${OPNs_Host}:${OPNs_Port:-$OPNs_DefaultPort}/api/bind${ep}" + if [ ! "$method" = "GET" ]; then + _debug data "$data" + export _H1="Content-Type: application/json" + response="$(_post "$data" "$opnsense_url" "" "$method")" + else + export _H1="" + response="$(_get "$opnsense_url")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + + return 0 +} + +_build_record_string() { + _record_string="{\"record\":{\"enabled\":\"1\",\"domain\":\"$1\",\"name\":\"$2\",\"type\":\"TXT\",\"value\":\"$3\"}}" +} + +_existingchallenge() { + if _opns_rest "GET" "/record/searchRecord"; then + _record_response="$response" + else + return 1 + fi + _uuid="" + _uuid=$(echo "$_record_response" | _egrep_o "\"uuid\":\"[^\"]*\",\"enabled\":\"[01]\",\"domain\":\"$1\",\"name\":\"$2\",\"type\":\"TXT\",\"value\":\"$3\"" | cut -d ':' -f 2 | cut -d '"' -f 2) + + if [ -n "$_uuid" ]; then + _debug uuid "$_uuid" + return 0 + fi + _debug "${2}.$1{1} record not found" + + return 1 +} + +_opns_check_auth() { + OPNs_Host="${OPNs_Host:-$(_readaccountconf_mutable OPNs_Host)}" + OPNs_Port="${OPNs_Port:-$(_readaccountconf_mutable OPNs_Port)}" + OPNs_Key="${OPNs_Key:-$(_readaccountconf_mutable OPNs_Key)}" + OPNs_Token="${OPNs_Token:-$(_readaccountconf_mutable OPNs_Token)}" + OPNs_Api_Insecure="${OPNs_Api_Insecure:-$(_readaccountconf_mutable OPNs_Api_Insecure)}" + + if [ -z "$OPNs_Host" ]; then + _err "You don't specify OPNsense address." + return 1 + else + _saveaccountconf_mutable OPNs_Host "$OPNs_Host" + fi + + if ! printf '%s' "$OPNs_Port" | grep '^[0-9]*$' >/dev/null; then + _err 'OPNs_Port specified but not numeric value' + return 1 + elif [ -z "$OPNs_Port" ]; then + _info "OPNSense port not specified. Defaulting to using port $OPNs_DefaultPort" + else + _saveaccountconf_mutable OPNs_Port "$OPNs_Port" + fi + + if ! printf '%s' "$OPNs_Api_Insecure" | grep '^[01]$' >/dev/null; then + _err 'OPNs_Api_Insecure specified but not 0/1 value' + return 1 + elif [ -n "$OPNs_Api_Insecure" ]; then + _saveaccountconf_mutable OPNs_Api_Insecure "$OPNs_Api_Insecure" + fi + export HTTPS_INSECURE="${OPNs_Api_Insecure:-$OPNs_DefaultApi_Insecure}" + + if [ -z "$OPNs_Key" ]; then + _err "you have not specified your OPNsense api key id." + _err "Please set OPNs_Key and try again." + return 1 + else + _saveaccountconf_mutable OPNs_Key "$OPNs_Key" + fi + + if [ -z "$OPNs_Token" ]; then + _err "you have not specified your OPNsense token." + _err "Please create OPNs_Token and try again." + return 1 + else + _saveaccountconf_mutable OPNs_Token "$OPNs_Token" + fi + + if ! _opns_rest "GET" "/general/get"; then + _err "Call to OPNsense API interface failed. Unable to access OPNsense API." + return 1 + fi + return 0 +} diff --git a/letsencrypt/dnsapi/dns_ovh.sh b/letsencrypt/dnsapi/dns_ovh.sh new file mode 100755 index 00000000..fac58210 --- /dev/null +++ b/letsencrypt/dnsapi/dns_ovh.sh @@ -0,0 +1,318 @@ +#!/bin/bash + +#Application Key +#OVH_AK="sdfsdfsdfljlbjkljlkjsdfoiwje" +# +#Application Secret +#OVH_AS="sdfsafsdfsdfdsfsdfsa" +# +#Consumer Key +#OVH_CK="sdfsdfsdfsdfsdfdsf" + +#OVH_END_POINT=ovh-eu + +#'ovh-eu' +OVH_EU='https://eu.api.ovh.com/1.0' + +#'ovh-ca': +OVH_CA='https://ca.api.ovh.com/1.0' + +#'kimsufi-eu' +KSF_EU='https://eu.api.kimsufi.com/1.0' + +#'kimsufi-ca' +KSF_CA='https://ca.api.kimsufi.com/1.0' + +#'soyoustart-eu' +SYS_EU='https://eu.api.soyoustart.com/1.0' + +#'soyoustart-ca' +SYS_CA='https://ca.api.soyoustart.com/1.0' + +#'runabove-ca' +RAV_CA='https://api.runabove.com/1.0' + +wiki="https://github.com/acmesh-official/acme.sh/wiki/How-to-use-OVH-domain-api" + +ovh_success="https://github.com/acmesh-official/acme.sh/wiki/OVH-Success" + +_ovh_get_api() { + _ogaep="$1" + + case "${_ogaep}" in + + ovh-eu | ovheu) + printf "%s" $OVH_EU + return + ;; + ovh-ca | ovhca) + printf "%s" $OVH_CA + return + ;; + kimsufi-eu | kimsufieu) + printf "%s" $KSF_EU + return + ;; + kimsufi-ca | kimsufica) + printf "%s" $KSF_CA + return + ;; + soyoustart-eu | soyoustarteu) + printf "%s" $SYS_EU + return + ;; + soyoustart-ca | soyoustartca) + printf "%s" $SYS_CA + return + ;; + runabove-ca | runaboveca) + printf "%s" $RAV_CA + return + ;; + + *) + + _err "Unknown parameter : $1" + return 1 + ;; + esac +} + +_initAuth() { + OVH_AK="${OVH_AK:-$(_readaccountconf_mutable OVH_AK)}" + OVH_AS="${OVH_AS:-$(_readaccountconf_mutable OVH_AS)}" + + if [ -z "$OVH_AK" ] || [ -z "$OVH_AS" ]; then + OVH_AK="" + OVH_AS="" + _err "You don't specify OVH application key and application secret yet." + _err "Please create you key and try again." + return 1 + fi + + if [ "$OVH_AK" != "$(_readaccountconf OVH_AK)" ]; then + _info "It seems that your ovh key is changed, let's clear consumer key first." + _clearaccountconf OVH_CK + fi + _saveaccountconf_mutable OVH_AK "$OVH_AK" + _saveaccountconf_mutable OVH_AS "$OVH_AS" + + OVH_END_POINT="${OVH_END_POINT:-$(_readaccountconf_mutable OVH_END_POINT)}" + if [ -z "$OVH_END_POINT" ]; then + OVH_END_POINT="ovh-eu" + fi + _info "Using OVH endpoint: $OVH_END_POINT" + if [ "$OVH_END_POINT" != "ovh-eu" ]; then + _saveaccountconf_mutable OVH_END_POINT "$OVH_END_POINT" + fi + + OVH_API="$(_ovh_get_api $OVH_END_POINT)" + _debug OVH_API "$OVH_API" + + OVH_CK="${OVH_CK:-$(_readaccountconf_mutable OVH_CK)}" + if [ -z "$OVH_CK" ]; then + _info "OVH consumer key is empty, Let's get one:" + if ! _ovh_authentication; then + _err "Can not get consumer key." + fi + #return and wait for retry. + return 1 + fi + + _info "Checking authentication" + + if ! _ovh_rest GET "domain" || _contains "$response" "INVALID_CREDENTIAL" || _contains "$response" "NOT_CREDENTIAL"; then + _err "The consumer key is invalid: $OVH_CK" + _err "Please retry to create a new one." + _clearaccountconf OVH_CK + return 1 + fi + _info "Consumer key is ok." + return 0 +} + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_ovh_add() { + fulldomain=$1 + txtvalue=$2 + + if ! _initAuth; then + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _info "Adding record" + if _ovh_rest POST "domain/zone/$_domain/record" "{\"fieldType\":\"TXT\",\"subDomain\":\"$_sub_domain\",\"target\":\"$txtvalue\",\"ttl\":60}"; then + if _contains "$response" "$txtvalue"; then + _ovh_rest POST "domain/zone/$_domain/refresh" + _debug "Refresh:$response" + _info "Added, sleep 10 seconds." + _sleep 10 + return 0 + fi + fi + _err "Add txt record error." + return 1 + +} + +#fulldomain +dns_ovh_rm() { + fulldomain=$1 + txtvalue=$2 + + if ! _initAuth; then + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + _debug "Getting txt records" + if ! _ovh_rest GET "domain/zone/$_domain/record?fieldType=TXT&subDomain=$_sub_domain"; then + return 1 + fi + + for rid in $(echo "$response" | tr '][,' ' '); do + _debug rid "$rid" + if ! _ovh_rest GET "domain/zone/$_domain/record/$rid"; then + return 1 + fi + if _contains "$response" "\"target\":\"$txtvalue\""; then + _debug "Found txt id:$rid" + if ! _ovh_rest DELETE "domain/zone/$_domain/record/$rid"; then + return 1 + fi + return 0 + fi + done + + return 1 +} + +#################### Private functions below ################################## + +_ovh_authentication() { + + _H1="X-Ovh-Application: $OVH_AK" + _H2="Content-type: application/json" + _H3="" + _H4="" + + _ovhdata='{"accessRules": [{"method": "GET","path": "/auth/time"},{"method": "GET","path": "/domain"},{"method": "GET","path": "/domain/zone/*"},{"method": "GET","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/record"},{"method": "POST","path": "/domain/zone/*/refresh"},{"method": "PUT","path": "/domain/zone/*/record/*"},{"method": "DELETE","path": "/domain/zone/*/record/*"}],"redirection":"'$ovh_success'"}' + + response="$(_post "$_ovhdata" "$OVH_API/auth/credential")" + _debug3 response "$response" + validationUrl="$(echo "$response" | _egrep_o "validationUrl\":\"[^\"]*\"" | _egrep_o "http.*\"" | tr -d '"')" + if [ -z "$validationUrl" ]; then + _err "Unable to get validationUrl" + return 1 + fi + _debug validationUrl "$validationUrl" + + consumerKey="$(echo "$response" | _egrep_o "consumerKey\":\"[^\"]*\"" | cut -d : -f 2 | tr -d '"')" + if [ -z "$consumerKey" ]; then + _err "Unable to get consumerKey" + return 1 + fi + _secure_debug consumerKey "$consumerKey" + + OVH_CK="$consumerKey" + _saveaccountconf OVH_CK "$OVH_CK" + + _info "Please open this link to do authentication: $(__green "$validationUrl")" + + _info "Here is a guide for you: $(__green "$wiki")" + _info "Please retry after the authentication is done." + +} + +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain=$1 + i=1 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _ovh_rest GET "domain/zone/$h"; then + return 1 + fi + + if ! _contains "$response" "This service does not exist" >/dev/null && ! _contains "$response" "NOT_GRANTED_CALL" >/dev/null; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_ovh_timestamp() { + _H1="" + _H2="" + _H3="" + _H4="" + _H5="" + _get "$OVH_API/auth/time" "" 30 +} + +_ovh_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + _ovh_url="$OVH_API/$ep" + _debug2 _ovh_url "$_ovh_url" + _ovh_t="$(_ovh_timestamp)" + _debug2 _ovh_t "$_ovh_t" + _ovh_p="$OVH_AS+$OVH_CK+$m+$_ovh_url+$data+$_ovh_t" + _secure_debug _ovh_p "$_ovh_p" + _ovh_hex="$(printf "%s" "$_ovh_p" | _digest sha1 hex)" + _debug2 _ovh_hex "$_ovh_hex" + + export _H1="X-Ovh-Application: $OVH_AK" + export _H2="X-Ovh-Signature: \$1\$$_ovh_hex" + _debug2 _H2 "$_H2" + export _H3="X-Ovh-Timestamp: $_ovh_t" + export _H4="X-Ovh-Consumer: $OVH_CK" + export _H5="Content-Type: application/json;charset=utf-8" + if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ] || [ "$m" = "DELETE" ]; then + _debug data "$data" + response="$(_post "$data" "$_ovh_url" "" "$m")" + else + response="$(_get "$_ovh_url")" + fi + + if [ "$?" != "0" ] || _contains "$response" "INVALID_CREDENTIAL"; then + _err "error $response" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_pdns.sh b/letsencrypt/dnsapi/dns_pdns.sh new file mode 100755 index 00000000..24c929df --- /dev/null +++ b/letsencrypt/dnsapi/dns_pdns.sh @@ -0,0 +1,232 @@ +#!/bin/bash + +#PowerDNS Embedded API +#https://doc.powerdns.com/md/httpapi/api_spec/ +# +#PDNS_Url="http://ns.example.com:8081" +#PDNS_ServerId="localhost" +#PDNS_Token="0123456789ABCDEF" +#PDNS_Ttl=60 + +DEFAULT_PDNS_TTL=60 + +######## Public functions ##################### +#Usage: add _acme-challenge.www.domain.com "123456789ABCDEF0000000000000000000000000000000000000" +#fulldomain +#txtvalue +dns_pdns_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$PDNS_Url" ]; then + PDNS_Url="" + _err "You don't specify PowerDNS address." + _err "Please set PDNS_Url and try again." + return 1 + fi + + if [ -z "$PDNS_ServerId" ]; then + PDNS_ServerId="" + _err "You don't specify PowerDNS server id." + _err "Please set you PDNS_ServerId and try again." + return 1 + fi + + if [ -z "$PDNS_Token" ]; then + PDNS_Token="" + _err "You don't specify PowerDNS token." + _err "Please create you PDNS_Token and try again." + return 1 + fi + + if [ -z "$PDNS_Ttl" ]; then + PDNS_Ttl="$DEFAULT_PDNS_TTL" + fi + + #save the api addr and key to the account conf file. + _saveaccountconf PDNS_Url "$PDNS_Url" + _saveaccountconf PDNS_ServerId "$PDNS_ServerId" + _saveaccountconf PDNS_Token "$PDNS_Token" + + if [ "$PDNS_Ttl" != "$DEFAULT_PDNS_TTL" ]; then + _saveaccountconf PDNS_Ttl "$PDNS_Ttl" + fi + + _debug "Detect root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain "$_domain" + + if ! set_record "$_domain" "$fulldomain" "$txtvalue"; then + return 1 + fi + + return 0 +} + +#fulldomain +dns_pdns_rm() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$PDNS_Ttl" ]; then + PDNS_Ttl="$DEFAULT_PDNS_TTL" + fi + + _debug "Detect root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _domain "$_domain" + + if ! rm_record "$_domain" "$fulldomain" "$txtvalue"; then + return 1 + fi + + return 0 +} + +set_record() { + _info "Adding record" + root=$1 + full=$2 + new_challenge=$3 + + _record_string="" + _build_record_string "$new_challenge" + _list_existingchallenges + for oldchallenge in $_existing_challenges; do + _build_record_string "$oldchallenge" + done + + if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [$_record_string]}]}"; then + _err "Set txt record error." + return 1 + fi + + if ! notify_slaves "$root"; then + return 1 + fi + + return 0 +} + +rm_record() { + _info "Remove record" + root=$1 + full=$2 + txtvalue=$3 + + #Enumerate existing acme challenges + _list_existingchallenges + + if _contains "$_existing_challenges" "$txtvalue"; then + #Delete all challenges (PowerDNS API does not allow to delete content) + if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"DELETE\", \"name\": \"$full.\", \"type\": \"TXT\"}]}"; then + _err "Delete txt record error." + return 1 + fi + _record_string="" + #If the only existing challenge was the challenge to delete: nothing to do + if ! [ "$_existing_challenges" = "$txtvalue" ]; then + for oldchallenge in $_existing_challenges; do + #Build up the challenges to re-add, ommitting the one what should be deleted + if ! [ "$oldchallenge" = "$txtvalue" ]; then + _build_record_string "$oldchallenge" + fi + done + #Recreate the existing challenges + if ! _pdns_rest "PATCH" "/api/v1/servers/$PDNS_ServerId/zones/$root" "{\"rrsets\": [{\"changetype\": \"REPLACE\", \"name\": \"$full.\", \"type\": \"TXT\", \"ttl\": $PDNS_Ttl, \"records\": [$_record_string]}]}"; then + _err "Set txt record error." + return 1 + fi + fi + if ! notify_slaves "$root"; then + return 1 + fi + else + _info "Record not found, nothing to remove" + fi + + return 0 +} + +notify_slaves() { + root=$1 + + if ! _pdns_rest "PUT" "/api/v1/servers/$PDNS_ServerId/zones/$root/notify"; then + _err "Notify slaves error." + return 1 + fi + + return 0 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _domain=domain.com +_get_root() { + domain=$1 + i=1 + + if _pdns_rest "GET" "/api/v1/servers/$PDNS_ServerId/zones"; then + _zones_response="$response" + fi + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + + if _contains "$_zones_response" "\"name\": \"$h.\""; then + _domain="$h." + if [ -z "$h" ]; then + _domain="=2E" + fi + return 0 + fi + + if [ -z "$h" ]; then + return 1 + fi + i=$(_math $i + 1) + done + _debug "$domain not found" + + return 1 +} + +_pdns_rest() { + method=$1 + ep=$2 + data=$3 + + export _H1="X-API-Key: $PDNS_Token" + + if [ ! "$method" = "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$PDNS_Url$ep" "" "$method")" + else + response="$(_get "$PDNS_Url$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + + return 0 +} + +_build_record_string() { + _record_string="${_record_string:+${_record_string}, }{\"content\": \"\\\"${1}\\\"\", \"disabled\": false}" +} + +_list_existingchallenges() { + _pdns_rest "GET" "/api/v1/servers/$PDNS_ServerId/zones/$root" + _existing_challenges=$(echo "$response" | _normalizeJson | _egrep_o "\"name\":\"${fulldomain}[^]]*}" | _egrep_o 'content\":\"\\"[^\\]*' | sed -n 's/^content":"\\"//p') +} diff --git a/letsencrypt/dnsapi/dns_pleskxml.sh b/letsencrypt/dnsapi/dns_pleskxml.sh new file mode 100644 index 00000000..0e2a3e07 --- /dev/null +++ b/letsencrypt/dnsapi/dns_pleskxml.sh @@ -0,0 +1,417 @@ +#!/bin/bash + +## Name: dns_pleskxml.sh +## Created by Stilez. +## Also uses some code from PR#1832 by @romanlum (https://github.com/acmesh-official/acme.sh/pull/1832/files) + +## This DNS-01 method uses the Plesk XML API described at: +## https://docs.plesk.com/en-US/12.5/api-rpc/about-xml-api.28709 +## and more specifically: https://docs.plesk.com/en-US/12.5/api-rpc/reference.28784 + +## Note: a DNS ID with host = empty string is OK for this API, see +## https://docs.plesk.com/en-US/obsidian/api-rpc/about-xml-api/reference/managing-dns/managing-dns-records/adding-dns-record.34798 +## For example, to add a TXT record to DNS alias domain "acme-alias.com" would be a valid Plesk action. +## So this API module can handle such a request, if needed. + +## For ACME v2 purposes, new TXT records are appended when added, and removing one TXT record will not affect any other TXT records. + +## The user credentials (username+password) and URL/URI for the Plesk XML API must be set by the user +## before this module is called (case sensitive): +## +## ``` +## export pleskxml_uri="https://address-of-my-plesk-server.net:8443/enterprise/control/agent.php" +## (or probably something similar) +## export pleskxml_user="my plesk username" +## export pleskxml_pass="my plesk password" +## ``` + +## Ok, let's issue a cert now: +## ``` +## acme.sh --issue --dns dns_pleskxml -d example.com -d www.example.com +## ``` +## +## The `pleskxml_uri`, `pleskxml_user` and `pleskxml_pass` will be saved in `~/.acme.sh/account.conf` and reused when needed. + +#################### INTERNAL VARIABLES + NEWLINE + API TEMPLATES ################################## + +pleskxml_init_checks_done=0 + +# Variable containing bare newline - not a style issue +# shellcheck disable=SC1004 +NEWLINE='\ +' + +pleskxml_tplt_get_domains="" +# Get a list of domains that PLESK can manage, so we can check root domain + host for acme.sh +# Also used to test credentials and URI. +# No params. + +pleskxml_tplt_get_dns_records="%s" +# Get all DNS records for a Plesk domain ID. +# PARAM = Plesk domain id to query + +pleskxml_tplt_add_txt_record="%sTXT%s%s" +# Add a TXT record to a domain. +# PARAMS = (1) Plesk internal domain ID, (2) "hostname" for the new record, eg '_acme_challenge', (3) TXT record value + +pleskxml_tplt_rmv_dns_record="%s" +# Delete a specific TXT record from a domain. +# PARAM = the Plesk internal ID for the DNS record to be deleted + +#################### Public functions ################################## + +#Usage: dns_pleskxml_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_pleskxml_add() { + fulldomain=$1 + txtvalue=$2 + + _info "Entering dns_pleskxml_add() to add TXT record '$txtvalue' to domain '$fulldomain'..." + + # Get credentials if not already checked, and confirm we can log in to Plesk XML API + if ! _credential_check; then + return 1 + fi + + # Get root and subdomain details, and Plesk domain ID + if ! _pleskxml_get_root_domain "$fulldomain"; then + return 1 + fi + + _debug 'Credentials OK, and domain identified. Calling Plesk XML API to add TXT record' + + # printf using template in a variable - not a style issue + # shellcheck disable=SC2059 + request="$(printf "$pleskxml_tplt_add_txt_record" "$root_domain_id" "$sub_domain_name" "$txtvalue")" + if ! _call_api "$request"; then + return 1 + fi + + # OK, we should have added a TXT record. Let's check and return success if so. + # All that should be left in the result, is one section, containing okNEW_DNS_RECORD_ID + + results="$(_api_response_split "$pleskxml_prettyprint_result" 'result' '')" + + if ! _value "$results" | grep 'ok' | grep '[0-9]\{1,\}' >/dev/null; then + # Error - doesn't contain expected string. Something's wrong. + _err 'Error when calling Plesk XML API.' + _err 'The result did not contain the expected XXXXX section, or contained other values as well.' + _err 'This is unexpected: something has gone wrong.' + _err 'The full response was:' + _err "$pleskxml_prettyprint_result" + return 1 + fi + + recid="$(_value "$results" | grep '[0-9]\{1,\}' | sed 's/^.*\([0-9]\{1,\}\)<\/id>.*$/\1/')" + + _info "Success. TXT record appears to be correctly added (Plesk record ID=$recid). Exiting dns_pleskxml_add()." + + return 0 +} + +#Usage: dns_pleskxml_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_pleskxml_rm() { + fulldomain=$1 + txtvalue=$2 + + _info "Entering dns_pleskxml_rm() to remove TXT record '$txtvalue' from domain '$fulldomain'..." + + # Get credentials if not already checked, and confirm we can log in to Plesk XML API + if ! _credential_check; then + return 1 + fi + + # Get root and subdomain details, and Plesk domain ID + if ! _pleskxml_get_root_domain "$fulldomain"; then + return 1 + fi + + _debug 'Credentials OK, and domain identified. Calling Plesk XML API to get list of TXT records and their IDs' + + # printf using template in a variable - not a style issue + # shellcheck disable=SC2059 + request="$(printf "$pleskxml_tplt_get_dns_records" "$root_domain_id")" + if ! _call_api "$request"; then + return 1 + fi + + # Reduce output to one line per DNS record, filtered for TXT records with a record ID only (which they should all have) + # Also strip out spaces between tags, redundant and group tags and any tags + reclist="$( + _api_response_split "$pleskxml_prettyprint_result" 'result' 'ok' | + sed 's# \{1,\}<\([a-zA-Z]\)#<\1#g;s###g;s#<[a-z][^/<>]*/>##g' | + grep "${root_domain_id}" | + grep '[0-9]\{1,\}' | + grep 'TXT' + )" + + if [ -z "$reclist" ]; then + _err "No TXT records found for root domain ${root_domain_name} (Plesk domain ID ${root_domain_id}). Exiting." + return 1 + fi + + _debug "Got list of DNS TXT records for root domain '$root_domain_name':" + _debug "$reclist" + + recid="$( + _value "$reclist" | + grep "${fulldomain}." | + grep "${txtvalue}" | + sed 's/^.*\([0-9]\{1,\}\)<\/id>.*$/\1/' + )" + + if ! _value "$recid" | grep '^[0-9]\{1,\}$' >/dev/null; then + _err "DNS records for root domain '${root_domain_name}' (Plesk ID ${root_domain_id}) + host '${sub_domain_name}' do not contain the TXT record '${txtvalue}'" + _err "Cannot delete TXT record. Exiting." + return 1 + fi + + _debug "Found Plesk record ID for target text string '${txtvalue}': ID=${recid}" + _debug 'Calling Plesk XML API to remove TXT record' + + # printf using template in a variable - not a style issue + # shellcheck disable=SC2059 + request="$(printf "$pleskxml_tplt_rmv_dns_record" "$recid")" + if ! _call_api "$request"; then + return 1 + fi + + # OK, we should have removed a TXT record. Let's check and return success if so. + # All that should be left in the result, is one section, containing okPLESK_DELETED_DNS_RECORD_ID + + results="$(_api_response_split "$pleskxml_prettyprint_result" 'result' '')" + + if ! _value "$results" | grep 'ok' | grep '[0-9]\{1,\}' >/dev/null; then + # Error - doesn't contain expected string. Something's wrong. + _err 'Error when calling Plesk XML API.' + _err 'The result did not contain the expected XXXXX section, or contained other values as well.' + _err 'This is unexpected: something has gone wrong.' + _err 'The full response was:' + _err "$pleskxml_prettyprint_result" + return 1 + fi + + _info "Success. TXT record appears to be correctly removed. Exiting dns_pleskxml_rm()." + return 0 +} + +#################### Private functions below (utility functions) ################################## + +# Outputs value of a variable without additional newlines etc +_value() { + printf '%s' "$1" +} + +# Outputs value of a variable (FQDN) and cuts it at 2 specified '.' delimiters, returning the text in between +# $1, $2 = where to cut +# $3 = FQDN +_valuecut() { + printf '%s' "$3" | cut -d . -f "${1}-${2}" +} + +# Counts '.' present in a domain name or other string +# $1 = domain name +_countdots() { + _value "$1" | tr -dc '.' | wc -c | sed 's/ //g' +} + +# Cleans up an API response, splits it "one line per item in the response" and greps for a string that in the context, identifies "useful" lines +# $1 - result string from API +# $2 - plain text tag to resplit on (usually "result" or "domain"). NOT REGEX +# $3 - basic regex to recognise useful return lines +# note: $3 matches via basic NOT extended regex (BRE), as extended regex capabilities not needed at the moment. +# Last line could change to instead, with suitable escaping of ['"/$], +# if future Plesk XML API changes ever require extended regex +_api_response_split() { + printf '%s' "$1" | + sed 's/^ +//;s/ +$//' | + tr -d '\n\r' | + sed "s/<\/\{0,1\}$2>/${NEWLINE}/g" | + grep "$3" +} + +#################### Private functions below (DNS functions) ################################## + +# Calls Plesk XML API, and checks results for obvious issues +_call_api() { + request="$1" + errtext='' + + _debug 'Entered _call_api(). Calling Plesk XML API with request:' + _debug "'$request'" + + export _H1="HTTP_AUTH_LOGIN: $pleskxml_user" + export _H2="HTTP_AUTH_PASSWD: $pleskxml_pass" + export _H3="content-Type: text/xml" + export _H4="HTTP_PRETTY_PRINT: true" + pleskxml_prettyprint_result="$(_post "${request}" "$pleskxml_uri" "" "POST")" + pleskxml_retcode="$?" + _debug 'The responses from the Plesk XML server were:' + _debug "retcode=$pleskxml_retcode. Literal response:" + _debug "'$pleskxml_prettyprint_result'" + + # Detect any that isn't "ok". None of the used calls should fail if the API is working correctly. + # Also detect if there simply aren't any status lines (null result?) and report that, as well. + + statuslines_count_total="$(echo "$pleskxml_prettyprint_result" | grep -c '^ *[^<]* *$')" + statuslines_count_okay="$(echo "$pleskxml_prettyprint_result" | grep -c '^ *ok *$')" + + if [ -z "$statuslines_count_total" ]; then + + # We have no status lines at all. Results are empty + errtext='The Plesk XML API unexpectedly returned an empty set of results for this call.' + + elif [ "$statuslines_count_okay" -ne "$statuslines_count_total" ]; then + + # We have some status lines that aren't "ok". Any available details are in API response fields "status" "errcode" and "errtext" + # Workaround for basic regex: + # - filter output to keep only lines like this: "SPACEStextSPACES" (shouldn't be necessary with prettyprint but guarantees subsequent code is ok) + # - then edit the 3 "useful" error tokens individually and remove closing tags on all lines + # - then filter again to remove all lines not edited (which will be the lines not starting A-Z) + errtext="$( + _value "$pleskxml_prettyprint_result" | + grep '^ *<[a-z]\{1,\}>[^<]*<\/[a-z]\{1,\}> *$' | + sed 's/^ */Status: /;s/^ */Error code: /;s/^ */Error text: /;s/<\/.*$//' | + grep '^[A-Z]' + )" + + fi + + if [ "$pleskxml_retcode" -ne 0 ] || [ "$errtext" != "" ]; then + # Call failed, for reasons either in the retcode or the response text... + + if [ "$pleskxml_retcode" -eq 0 ]; then + _err "The POST request was successfully sent to the Plesk server." + else + _err "The return code for the POST request was $pleskxml_retcode (non-zero = failure in submitting request to server)." + fi + + if [ "$errtext" != "" ]; then + _err 'The error responses received from the Plesk server were:' + _err "$errtext" + else + _err "No additional error messages were received back from the Plesk server" + fi + + _err "The Plesk XML API call failed." + return 1 + + fi + + _debug "Leaving _call_api(). Successful call." + + return 0 +} + +# Startup checks (credentials, URI) +_credential_check() { + _debug "Checking Plesk XML API login credentials and URI..." + + if [ "$pleskxml_init_checks_done" -eq 1 ]; then + _debug "Initial checks already done, no need to repeat. Skipped." + return 0 + fi + + pleskxml_user="${pleskxml_user:-$(_readaccountconf_mutable pleskxml_user)}" + pleskxml_pass="${pleskxml_pass:-$(_readaccountconf_mutable pleskxml_pass)}" + pleskxml_uri="${pleskxml_uri:-$(_readaccountconf_mutable pleskxml_uri)}" + + if [ -z "$pleskxml_user" ] || [ -z "$pleskxml_pass" ] || [ -z "$pleskxml_uri" ]; then + pleskxml_user="" + pleskxml_pass="" + pleskxml_uri="" + _err "You didn't specify one or more of the Plesk XML API username, password, or URI." + _err "Please create these and try again." + _err "Instructions are in the 'dns_pleskxml' plugin source code or in the acme.sh documentation." + return 1 + fi + + # Test the API is usable, by trying to read the list of managed domains... + _call_api "$pleskxml_tplt_get_domains" + if [ "$pleskxml_retcode" -ne 0 ]; then + _err 'Failed to access Plesk XML API.' + _err "Please check your login credentials and Plesk URI, and that the URI is reachable, and try again." + return 1 + fi + + _saveaccountconf_mutable pleskxml_uri "$pleskxml_uri" + _saveaccountconf_mutable pleskxml_user "$pleskxml_user" + _saveaccountconf_mutable pleskxml_pass "$pleskxml_pass" + + _debug "Test login to Plesk XML API successful. Login credentials and URI successfully saved to the acme.sh configuration file for future use." + + pleskxml_init_checks_done=1 + + return 0 +} + +# For a FQDN, identify the root domain managed by Plesk, its domain ID in Plesk, and the host if any. + +# IMPORTANT NOTE: a result with host = empty string is OK for this API, see +# https://docs.plesk.com/en-US/obsidian/api-rpc/about-xml-api/reference/managing-dns/managing-dns-records/adding-dns-record.34798 +# See notes at top of this file + +_pleskxml_get_root_domain() { + original_full_domain_name="$1" + + _debug "Identifying DNS root domain for '$original_full_domain_name' that is managed by the Plesk account." + + # test if the domain as provided is valid for splitting. + + if [ "$(_countdots "$original_full_domain_name")" -eq 0 ]; then + _err "Invalid domain. The ACME domain must contain at least two parts (aa.bb) to identify a domain and tld for the TXT record." + return 1 + fi + + _debug "Querying Plesk server for list of managed domains..." + + _call_api "$pleskxml_tplt_get_domains" + if [ "$pleskxml_retcode" -ne 0 ]; then + return 1 + fi + + # Generate a crude list of domains known to this Plesk account. + # We convert tags to so it'll flag on a hit with either or fields, + # for non-Western character sets. + # Output will be one line per known domain, containing 2 tages and a single tag + # We don't actually need to check for type, name, *and* id, but it guarantees only usable lines are returned. + + output="$(_api_response_split "$pleskxml_prettyprint_result" 'domain' 'domain' | sed 's///g;s/<\/ascii-name>/<\/name>/g' | grep '' | grep '')" + + _debug 'Domains managed by Plesk server are (ignore the hacked output):' + _debug "$output" + + # loop and test if domain, or any parent domain, is managed by Plesk + # Loop until we don't have any '.' in the string we're testing as a candidate Plesk-managed domain + + root_domain_name="$original_full_domain_name" + + while true; do + + _debug "Checking if '$root_domain_name' is managed by the Plesk server..." + + root_domain_id="$(_value "$output" | grep "$root_domain_name" | _head_n 1 | sed 's/^.*\([0-9]\{1,\}\)<\/id>.*$/\1/')" + + if [ -n "$root_domain_id" ]; then + # Found a match + # SEE IMPORTANT NOTE ABOVE - THIS FUNCTION CAN RETURN HOST='', AND THAT'S OK FOR PLESK XML API WHICH ALLOWS IT. + # SO WE HANDLE IT AND DON'T PREVENT IT + sub_domain_name="$(_value "$original_full_domain_name" | sed "s/\.\{0,1\}${root_domain_name}"'$//')" + _info "Success. Matched host '$original_full_domain_name' to: DOMAIN '${root_domain_name}' (Plesk ID '${root_domain_id}'), HOST '${sub_domain_name}'. Returning." + return 0 + fi + + # No match, try next parent up (if any)... + + root_domain_name="$(_valuecut 2 1000 "$root_domain_name")" + + if [ "$(_countdots "$root_domain_name")" -eq 0 ]; then + _debug "No match, and next parent would be a TLD..." + _err "Cannot find '$original_full_domain_name' or any parent domain of it, in Plesk." + _err "Are you sure that this domain is managed by this Plesk server?" + return 1 + fi + + _debug "No match, trying next parent up..." + + done +} diff --git a/letsencrypt/dnsapi/dns_pointhq.sh b/letsencrypt/dnsapi/dns_pointhq.sh new file mode 100644 index 00000000..d75c0355 --- /dev/null +++ b/letsencrypt/dnsapi/dns_pointhq.sh @@ -0,0 +1,164 @@ +#!/bin/bash + +# +#PointHQ_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# +#PointHQ_Email="xxxx@sss.com" + +PointHQ_Api="https://api.pointhq.com" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_pointhq_add() { + fulldomain=$1 + txtvalue=$2 + + PointHQ_Key="${PointHQ_Key:-$(_readaccountconf_mutable PointHQ_Key)}" + PointHQ_Email="${PointHQ_Email:-$(_readaccountconf_mutable PointHQ_Email)}" + if [ -z "$PointHQ_Key" ] || [ -z "$PointHQ_Email" ]; then + PointHQ_Key="" + PointHQ_Email="" + _err "You didn't specify a PointHQ API key and email yet." + _err "Please create the key and try again." + return 1 + fi + + if ! _contains "$PointHQ_Email" "@"; then + _err "It seems that the PointHQ_Email=$PointHQ_Email is not a valid email address." + _err "Please check and retry." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable PointHQ_Key "$PointHQ_Key" + _saveaccountconf_mutable PointHQ_Email "$PointHQ_Email" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _info "Adding record" + if _pointhq_rest POST "zones/$_domain/records" "{\"zone_record\": {\"name\":\"$_sub_domain\",\"record_type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":3600}}"; then + if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then + _info "Added, OK" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + return 1 +} + +#fulldomain txtvalue +dns_pointhq_rm() { + fulldomain=$1 + txtvalue=$2 + + PointHQ_Key="${PointHQ_Key:-$(_readaccountconf_mutable PointHQ_Key)}" + PointHQ_Email="${PointHQ_Email:-$(_readaccountconf_mutable PointHQ_Email)}" + if [ -z "$PointHQ_Key" ] || [ -z "$PointHQ_Email" ]; then + PointHQ_Key="" + PointHQ_Email="" + _err "You didn't specify a PointHQ API key and email yet." + _err "Please create the key and try again." + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _pointhq_rest GET "zones/${_domain}/records?record_type=TXT&name=$_sub_domain" + + if ! printf "%s" "$response" | grep "^\[" >/dev/null; then + _err "Error" + return 1 + fi + + if [ "$response" = "[]" ]; then + _info "No records to remove." + else + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[^,]*" | cut -d : -f 2 | tr -d \" | head -n 1) + _debug "record_id" "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if ! _pointhq_rest DELETE "zones/$_domain/records/$record_id"; then + _err "Delete record error." + return 1 + fi + _contains "$response" '"status":"OK"' + fi +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _pointhq_rest GET "zones"; then + return 1 + fi + + if _contains "$response" "\"name\":\"$h\"" >/dev/null; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_pointhq_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + _pointhq_auth=$(printf "%s:%s" "$PointHQ_Email" "$PointHQ_Key" | _base64) + + export _H1="Authorization: Basic $_pointhq_auth" + export _H2="Content-Type: application/json" + export _H3="Accept: application/json" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$PointHQ_Api/$ep" "" "$m")" + else + response="$(_get "$PointHQ_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_rackspace.sh b/letsencrypt/dnsapi/dns_rackspace.sh new file mode 100644 index 00000000..05c28c2f --- /dev/null +++ b/letsencrypt/dnsapi/dns_rackspace.sh @@ -0,0 +1,207 @@ +#!/bin/bash +# +# +#RACKSPACE_Username="" +# +#RACKSPACE_Apikey="" + +RACKSPACE_Endpoint="https://dns.api.rackspacecloud.com/v1.0" + +# 20190213 - The name & id fields swapped in the API response; fix sed +# 20190101 - Duplicating file for new pull request to dev branch +# Original - tcocca:rackspace_dnsapi https://github.com/acmesh-official/acme.sh/pull/1297 + +######## Public functions ##################### +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_rackspace_add() { + fulldomain="$1" + _debug fulldomain="$fulldomain" + txtvalue="$2" + _debug txtvalue="$txtvalue" + _rackspace_check_auth || return 1 + _rackspace_check_rootzone || return 1 + _info "Creating TXT record." + if ! _rackspace_rest POST "$RACKSPACE_Tenant/domains/$_domain_id/records" "{\"records\":[{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":300}]}"; then + return 1 + fi + _debug2 response "$response" + if ! _contains "$response" "$txtvalue" >/dev/null; then + _err "Could not add TXT record." + return 1 + fi + return 0 +} + +#fulldomain txtvalue +dns_rackspace_rm() { + fulldomain=$1 + _debug fulldomain="$fulldomain" + txtvalue=$2 + _debug txtvalue="$txtvalue" + _rackspace_check_auth || return 1 + _rackspace_check_rootzone || return 1 + _info "Checking for TXT record." + if ! _get_recordid "$_domain_id" "$fulldomain" "$txtvalue"; then + _err "Could not get TXT record id." + return 1 + fi + if [ "$_dns_record_id" = "" ]; then + _err "TXT record not found." + return 1 + fi + _info "Removing TXT record." + if ! _delete_txt_record "$_domain_id" "$_dns_record_id"; then + _err "Could not remove TXT record $_dns_record_id." + fi + return 0 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root_zone() { + domain="$1" + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + if ! _rackspace_rest GET "$RACKSPACE_Tenant/domains/search?name=$h"; then + return 1 + fi + _debug2 response "$response" + if _contains "$response" "\"name\":\"$h\"" >/dev/null; then + # Response looks like: + # {"ttl":300,"accountId":12345,"id":1111111,"name":"example.com","emailAddress": ... + _domain_id=$(echo "$response" | sed -n "s/^.*\"id\":\([^,]*\),\"name\":\"$h\",.*/\1/p") + _debug2 domain_id "$_domain_id" + if [ -n "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_get_recordid() { + domainid="$1" + fulldomain="$2" + txtvalue="$3" + if ! _rackspace_rest GET "$RACKSPACE_Tenant/domains/$domainid/records?name=$fulldomain&type=TXT"; then + return 1 + fi + _debug response "$response" + if ! _contains "$response" "$txtvalue"; then + _dns_record_id=0 + return 0 + fi + _dns_record_id=$(echo "$response" | tr '{' "\n" | grep "\"data\":\"$txtvalue\"" | sed -n 's/^.*"id":"\([^"]*\)".*/\1/p') + _debug _dns_record_id "$_dns_record_id" + return 0 +} + +_delete_txt_record() { + domainid="$1" + _dns_record_id="$2" + if ! _rackspace_rest DELETE "$RACKSPACE_Tenant/domains/$domainid/records?id=$_dns_record_id"; then + return 1 + fi + _debug response "$response" + if ! _contains "$response" "RUNNING"; then + return 1 + fi + return 0 +} + +_rackspace_rest() { + m="$1" + ep="$2" + data="$3" + _debug ep "$ep" + export _H1="Accept: application/json" + export _H2="X-Auth-Token: $RACKSPACE_Token" + export _H3="X-Project-Id: $RACKSPACE_Tenant" + export _H4="Content-Type: application/json" + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$RACKSPACE_Endpoint/$ep" "" "$m")" + retcode=$? + else + _info "Getting $RACKSPACE_Endpoint/$ep" + response="$(_get "$RACKSPACE_Endpoint/$ep")" + retcode=$? + fi + + if [ "$retcode" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} + +_rackspace_authorization() { + export _H1="Content-Type: application/json" + data="{\"auth\":{\"RAX-KSKEY:apiKeyCredentials\":{\"username\":\"$RACKSPACE_Username\",\"apiKey\":\"$RACKSPACE_Apikey\"}}}" + _debug data "$data" + response="$(_post "$data" "https://identity.api.rackspacecloud.com/v2.0/tokens" "" "POST")" + retcode=$? + _debug2 response "$response" + if [ "$retcode" != "0" ]; then + _err "Authentication failed." + return 1 + fi + if _contains "$response" "token"; then + RACKSPACE_Token="$(echo "$response" | _normalizeJson | sed -n 's/^.*"token":{.*,"id":"\([^"]*\)",".*/\1/p')" + RACKSPACE_Tenant="$(echo "$response" | _normalizeJson | sed -n 's/^.*"token":{.*,"id":"\([^"]*\)"}.*/\1/p')" + _debug RACKSPACE_Token "$RACKSPACE_Token" + _debug RACKSPACE_Tenant "$RACKSPACE_Tenant" + fi + return 0 +} + +_rackspace_check_auth() { + # retrieve the rackspace creds + RACKSPACE_Username="${RACKSPACE_Username:-$(_readaccountconf_mutable RACKSPACE_Username)}" + RACKSPACE_Apikey="${RACKSPACE_Apikey:-$(_readaccountconf_mutable RACKSPACE_Apikey)}" + # check their vals for null + if [ -z "$RACKSPACE_Username" ] || [ -z "$RACKSPACE_Apikey" ]; then + RACKSPACE_Username="" + RACKSPACE_Apikey="" + _err "You didn't specify a Rackspace username and api key." + _err "Please set those values and try again." + return 1 + fi + # save the username and api key to the account conf file. + _saveaccountconf_mutable RACKSPACE_Username "$RACKSPACE_Username" + _saveaccountconf_mutable RACKSPACE_Apikey "$RACKSPACE_Apikey" + if [ -z "$RACKSPACE_Token" ]; then + _info "Getting authorization token." + if ! _rackspace_authorization; then + _err "Can not get token." + fi + fi +} + +_rackspace_check_rootzone() { + _debug "First detect the root zone" + if ! _get_root_zone "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" +} diff --git a/letsencrypt/dnsapi/dns_rcode0.sh b/letsencrypt/dnsapi/dns_rcode0.sh new file mode 100755 index 00000000..4c5e6066 --- /dev/null +++ b/letsencrypt/dnsapi/dns_rcode0.sh @@ -0,0 +1,224 @@ +#!/bin/bash + +#Rcode0 API Integration +#https://my.rcodezero.at/api-doc +# +# log into https://my.rcodezero.at/enableapi and get your ACME API Token (the ACME API token has limited +# access to the REST calls needed for acme.sh only) +# +#RCODE0_URL="https://my.rcodezero.at" +#RCODE0_API_TOKEN="0123456789ABCDEF" +#RCODE0_TTL=60 + +DEFAULT_RCODE0_URL="https://my.rcodezero.at" +DEFAULT_RCODE0_TTL=60 + +######## Public functions ##################### +#Usage: add _acme-challenge.www.domain.com "123456789ABCDEF0000000000000000000000000000000000000" +#fulldomain +#txtvalue +dns_rcode0_add() { + fulldomain=$1 + txtvalue=$2 + + RCODE0_API_TOKEN="${RCODE0_API_TOKEN:-$(_readaccountconf_mutable RCODE0_API_TOKEN)}" + RCODE0_URL="${RCODE0_URL:-$(_readaccountconf_mutable RCODE0_URL)}" + RCODE0_TTL="${RCODE0_TTL:-$(_readaccountconf_mutable RCODE0_TTL)}" + + if [ -z "$RCODE0_URL" ]; then + RCODE0_URL="$DEFAULT_RCODE0_URL" + fi + + if [ -z "$RCODE0_API_TOKEN" ]; then + RCODE0_API_TOKEN="" + _err "Missing Rcode0 ACME API Token." + _err "Please login and create your token at httsp://my.rcodezero.at/enableapi and try again." + return 1 + fi + + if [ -z "$RCODE0_TTL" ]; then + RCODE0_TTL="$DEFAULT_RCODE0_TTL" + fi + + #save the token to the account conf file. + _saveaccountconf_mutable RCODE0_API_TOKEN "$RCODE0_API_TOKEN" + + if [ "$RCODE0_URL" != "$DEFAULT_RCODE0_URL" ]; then + _saveaccountconf_mutable RCODE0_URL "$RCODE0_URL" + fi + + if [ "$RCODE0_TTL" != "$DEFAULT_RCODE0_TTL" ]; then + _saveaccountconf_mutable RCODE0_TTL "$RCODE0_TTL" + fi + + _debug "Detect root zone" + if ! _get_root "$fulldomain"; then + _err "No 'MASTER' zone for $fulldomain found at RcodeZero Anycast." + return 1 + fi + _debug _domain "$_domain" + + _debug "Adding record" + + _record_string="" + _build_record_string "$txtvalue" + _list_existingchallenges + for oldchallenge in $_existing_challenges; do + _build_record_string "$oldchallenge" + done + + _debug "Challenges: $_existing_challenges" + + if [ -z "$_existing_challenges" ]; then + if ! _rcode0_rest "PATCH" "/api/v1/acme/zones/$_domain/rrsets" "[{\"changetype\": \"add\", \"name\": \"$fulldomain.\", \"type\": \"TXT\", \"ttl\": $RCODE0_TTL, \"records\": [$_record_string]}]"; then + _err "Add txt record error." + return 1 + fi + else + # try update in case a records exists (need for wildcard certs) + if ! _rcode0_rest "PATCH" "/api/v1/acme/zones/$_domain/rrsets" "[{\"changetype\": \"update\", \"name\": \"$fulldomain.\", \"type\": \"TXT\", \"ttl\": $RCODE0_TTL, \"records\": [$_record_string]}]"; then + _err "Set txt record error." + return 1 + fi + fi + + return 0 +} + +#fulldomain txtvalue +dns_rcode0_rm() { + fulldomain=$1 + txtvalue=$2 + + RCODE0_API_TOKEN="${RCODE0_API_TOKEN:-$(_readaccountconf_mutable RCODE0_API_TOKEN)}" + RCODE0_URL="${RCODE0_URL:-$(_readaccountconf_mutable RCODE0_URL)}" + RCODE0_TTL="${RCODE0_TTL:-$(_readaccountconf_mutable RCODE0_TTL)}" + + if [ -z "$RCODE0_URL" ]; then + RCODE0_URL="$DEFAULT_RCODE0_URL" + fi + + if [ -z "$RCODE0_API_TOKEN" ]; then + RCODE0_API_TOKEN="" + _err "Missing Rcode0 API Token." + _err "Please login and create your token at httsp://my.rcodezero.at/enableapi and try again." + return 1 + fi + + #save the api addr and key to the account conf file. + _saveaccountconf_mutable RCODE0_URL "$RCODE0_URL" + _saveaccountconf_mutable RCODE0_API_TOKEN "$RCODE0_API_TOKEN" + + if [ "$RCODE0_TTL" != "$DEFAULT_RCODE0_TTL" ]; then + _saveaccountconf_mutable RCODE0_TTL "$RCODE0_TTL" + fi + + if [ -z "$RCODE0_TTL" ]; then + RCODE0_TTL="$DEFAULT_RCODE0_TTL" + fi + + _debug "Detect root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug "Remove record" + + #Enumerate existing acme challenges + _list_existingchallenges + + if _contains "$_existing_challenges" "$txtvalue"; then + #Delete all challenges (PowerDNS API does not allow to delete content) + if ! _rcode0_rest "PATCH" "/api/v1/acme/zones/$_domain/rrsets" "[{\"changetype\": \"delete\", \"name\": \"$fulldomain.\", \"type\": \"TXT\"}]"; then + _err "Delete txt record error." + return 1 + fi + _record_string="" + #If the only existing challenge was the challenge to delete: nothing to do + if ! [ "$_existing_challenges" = "$txtvalue" ]; then + for oldchallenge in $_existing_challenges; do + #Build up the challenges to re-add, ommitting the one what should be deleted + if ! [ "$oldchallenge" = "$txtvalue" ]; then + _build_record_string "$oldchallenge" + fi + done + #Recreate the existing challenges + if ! _rcode0_rest "PATCH" "/api/v1/acme/zones/$_domain/rrsets" "[{\"changetype\": \"update\", \"name\": \"$fulldomain.\", \"type\": \"TXT\", \"ttl\": $RCODE0_TTL, \"records\": [$_record_string]}]"; then + _err "Set txt record error." + return 1 + fi + fi + else + _info "Record not found, nothing to remove" + fi + + return 0 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _domain=domain.com +_get_root() { + domain=$1 + i=1 + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + + _debug "try to find: $h" + if _rcode0_rest "GET" "/api/v1/acme/zones/$h"; then + if [ "$response" = "[\"found\"]" ]; then + _domain="$h" + if [ -z "$h" ]; then + _domain="=2E" + fi + return 0 + elif [ "$response" = "[\"not a master domain\"]" ]; then + return 1 + fi + fi + + if [ -z "$h" ]; then + return 1 + fi + i=$(_math $i + 1) + done + _debug "no matching domain for $domain found" + + return 1 +} + +_rcode0_rest() { + method=$1 + ep=$2 + data=$3 + + export _H1="Authorization: Bearer $RCODE0_API_TOKEN" + + if [ ! "$method" = "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$RCODE0_URL$ep" "" "$method")" + else + response="$(_get "$RCODE0_URL$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + + return 0 +} + +_build_record_string() { + _record_string="${_record_string:+${_record_string}, }{\"content\": \"\\\"${1}\\\"\", \"disabled\": false}" +} + +_list_existingchallenges() { + _rcode0_rest "GET" "/api/v1/acme/zones/$_domain/rrsets" + _existing_challenges=$(echo "$response" | _normalizeJson | _egrep_o "\"name\":\"${fulldomain}[^]]*}" | _egrep_o 'content\":\"\\"[^\\]*' | sed -n 's/^content":"\\"//p') + _debug2 "$_existing_challenges" +} diff --git a/letsencrypt/dnsapi/dns_regru.sh b/letsencrypt/dnsapi/dns_regru.sh new file mode 100644 index 00000000..8c935add --- /dev/null +++ b/letsencrypt/dnsapi/dns_regru.sh @@ -0,0 +1,126 @@ +#!/bin/bash + +# +# REGRU_API_Username="test" +# +# REGRU_API_Password="test" +# + +REGRU_API_URL="https://api.reg.ru/api/regru2" + +######## Public functions ##################### + +dns_regru_add() { + fulldomain=$1 + txtvalue=$2 + + REGRU_API_Username="${REGRU_API_Username:-$(_readaccountconf_mutable REGRU_API_Username)}" + REGRU_API_Password="${REGRU_API_Password:-$(_readaccountconf_mutable REGRU_API_Password)}" + if [ -z "$REGRU_API_Username" ] || [ -z "$REGRU_API_Password" ]; then + REGRU_API_Username="" + REGRU_API_Password="" + _err "You don't specify regru password or username." + return 1 + fi + + _saveaccountconf_mutable REGRU_API_Username "$REGRU_API_Username" + _saveaccountconf_mutable REGRU_API_Password "$REGRU_API_Password" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain "$_domain" + + _subdomain=$(echo "$fulldomain" | sed -r "s/.$_domain//") + _debug _subdomain "$_subdomain" + + _info "Adding TXT record to ${fulldomain}" + _regru_rest POST "zone/add_txt" "input_data={%22username%22:%22${REGRU_API_Username}%22,%22password%22:%22${REGRU_API_Password}%22,%22domains%22:[{%22dname%22:%22${_domain}%22}],%22subdomain%22:%22${_subdomain}%22,%22text%22:%22${txtvalue}%22,%22output_content_type%22:%22plain%22}&input_format=json" + + if ! _contains "${response}" 'error'; then + return 0 + fi + _err "Could not create resource record, check logs" + _err "${response}" + return 1 +} + +dns_regru_rm() { + fulldomain=$1 + txtvalue=$2 + + REGRU_API_Username="${REGRU_API_Username:-$(_readaccountconf_mutable REGRU_API_Username)}" + REGRU_API_Password="${REGRU_API_Password:-$(_readaccountconf_mutable REGRU_API_Password)}" + if [ -z "$REGRU_API_Username" ] || [ -z "$REGRU_API_Password" ]; then + REGRU_API_Username="" + REGRU_API_Password="" + _err "You don't specify regru password or username." + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain "$_domain" + + _subdomain=$(echo "$fulldomain" | sed -r "s/.$_domain//") + _debug _subdomain "$_subdomain" + + _info "Deleting resource record $fulldomain" + _regru_rest POST "zone/remove_record" "input_data={%22username%22:%22${REGRU_API_Username}%22,%22password%22:%22${REGRU_API_Password}%22,%22domains%22:[{%22dname%22:%22${_domain}%22}],%22subdomain%22:%22${_subdomain}%22,%22content%22:%22${txtvalue}%22,%22record_type%22:%22TXT%22,%22output_content_type%22:%22plain%22}&input_format=json" + + if ! _contains "${response}" 'error'; then + return 0 + fi + _err "Could not delete resource record, check logs" + _err "${response}" + return 1 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _domain=domain.com +_get_root() { + domain=$1 + + _regru_rest POST "service/get_list" "username=${REGRU_API_Username}&password=${REGRU_API_Password}&output_format=xml&servtype=domain" + domains_list=$(echo "${response}" | grep dname | sed -r "s/.*dname=\"([^\"]+)\".*/\\1/g") + + for ITEM in ${domains_list}; do + case "${domain}" in + *${ITEM}*) + _domain=${ITEM} + _debug _domain "${_domain}" + return 0 + ;; + esac + done + + return 1 +} + +#returns +# response +_regru_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Content-Type: application/x-www-form-urlencoded" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$REGRU_API_URL/$ep" "" "$m")" + else + response="$(_get "$REGRU_API_URL/$ep?$data")" + fi + + _debug response "${response}" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_schlundtech.sh b/letsencrypt/dnsapi/dns_schlundtech.sh new file mode 100644 index 00000000..23c9d3e9 --- /dev/null +++ b/letsencrypt/dnsapi/dns_schlundtech.sh @@ -0,0 +1,261 @@ +#!/bin/bash +# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*- + +# Schlundtech DNS API +# Author: mod242 +# Created: 2019-40-29 +# Completly based on the autoDNS xml api wrapper by auerswald@gmail.com +# +# export SCHLUNDTECH_USER="username" +# export SCHLUNDTECH_PASSWORD="password" +# +# Usage: +# acme.sh --issue --dns dns_schlundtech -d example.com + +SCHLUNDTECH_API="https://gateway.schlundtech.de" + +# Arguments: +# txtdomain +# txt +dns_schlundtech_add() { + fulldomain="$1" + txtvalue="$2" + + SCHLUNDTECH_USER="${SCHLUNDTECH_USER:-$(_readaccountconf_mutable SCHLUNDTECH_USER)}" + SCHLUNDTECH_PASSWORD="${SCHLUNDTECH_PASSWORD:-$(_readaccountconf_mutable SCHLUNDTECH_PASSWORD)}" + + if [ -z "$SCHLUNDTECH_USER" ] || [ -z "$SCHLUNDTECH_PASSWORD" ]; then + _err "You didn't specify schlundtech user and password." + return 1 + fi + + _saveaccountconf_mutable SCHLUNDTECH_USER "$SCHLUNDTECH_USER" + _saveaccountconf_mutable SCHLUNDTECH_PASSWORD "$SCHLUNDTECH_PASSWORD" + + _debug "First detect the root zone" + + if ! _get_autodns_zone "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _zone "$_zone" + _debug _system_ns "$_system_ns" + + _info "Adding TXT record" + + autodns_response="$(_autodns_zone_update "$_zone" "$_sub_domain" "$txtvalue" "$_system_ns")" + + if [ "$?" -eq "0" ]; then + _info "Added, OK" + return 0 + fi + + return 1 +} + +# Arguments: +# txtdomain +# txt +dns_schlundtech_rm() { + fulldomain="$1" + txtvalue="$2" + + SCHLUNDTECH_USER="${SCHLUNDTECH_USER:-$(_readaccountconf_mutable SCHLUNDTECH_USER)}" + SCHLUNDTECH_PASSWORD="${SCHLUNDTECH_PASSWORD:-$(_readaccountconf_mutable SCHLUNDTECH_PASSWORD)}" + + if [ -z "$SCHLUNDTECH_USER" ] || [ -z "$SCHLUNDTECH_PASSWORD" ]; then + _err "You didn't specify schlundtech user and password." + return 1 + fi + + _debug "First detect the root zone" + + if ! _get_autodns_zone "$fulldomain"; then + _err "zone not found" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _zone "$_zone" + _debug _system_ns "$_system_ns" + + _info "Delete TXT record" + + autodns_response="$(_autodns_zone_cleanup "$_zone" "$_sub_domain" "$txtvalue" "$_system_ns")" + + if [ "$?" -eq "0" ]; then + _info "Deleted, OK" + return 0 + fi + + return 1 +} + +#################### Private functions below ################################## + +# Arguments: +# fulldomain +# Returns: +# _sub_domain=_acme-challenge.www +# _zone=domain.com +# _system_ns +_get_autodns_zone() { + domain="$1" + + i=2 + p=1 + + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + + if [ -z "$h" ]; then + # not valid + return 1 + fi + + autodns_response="$(_autodns_zone_inquire "$h")" + + if [ "$?" -ne "0" ]; then + _err "invalid domain" + return 1 + fi + + if _contains "$autodns_response" "1" >/dev/null; then + _zone="$(echo "$autodns_response" | _egrep_o '[^<]*' | cut -d '>' -f 2 | cut -d '<' -f 1)" + _system_ns="$(echo "$autodns_response" | _egrep_o '[^<]*' | cut -d '>' -f 2 | cut -d '<' -f 1)" + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + return 0 + fi + + p=$i + i=$(_math "$i" + 1) + done + + return 1 +} + +_build_request_auth_xml() { + printf " + %s + %s + 10 + " "$SCHLUNDTECH_USER" "$SCHLUNDTECH_PASSWORD" +} + +# Arguments: +# zone +_build_zone_inquire_xml() { + printf " + + %s + + 0205 + + 1 + 1 + + + name + eq + %s + + + " "$(_build_request_auth_xml)" "$1" +} + +# Arguments: +# zone +# subdomain +# txtvalue +# system_ns +_build_zone_update_xml() { + printf " + + %s + + 0202001 + + + %s + 600 + TXT + %s + + + + %s + %s + + + " "$(_build_request_auth_xml)" "$2" "$3" "$1" "$4" +} + +# Arguments: +# zone +_autodns_zone_inquire() { + request_data="$(_build_zone_inquire_xml "$1")" + autodns_response="$(_autodns_api_call "$request_data")" + ret="$?" + + printf "%s" "$autodns_response" + return "$ret" +} + +# Arguments: +# zone +# subdomain +# txtvalue +# system_ns +_autodns_zone_update() { + request_data="$(_build_zone_update_xml "$1" "$2" "$3" "$4")" + autodns_response="$(_autodns_api_call "$request_data")" + ret="$?" + + printf "%s" "$autodns_response" + return "$ret" +} + +# Arguments: +# zone +# subdomain +# txtvalue +# system_ns +_autodns_zone_cleanup() { + request_data="$(_build_zone_update_xml "$1" "$2" "$3" "$4")" + # replace 'rr_add>' with 'rr_rem>' in request_data + request_data="$(printf -- "%s" "$request_data" | sed 's/rr_add>/rr_rem>/g')" + autodns_response="$(_autodns_api_call "$request_data")" + ret="$?" + + printf "%s" "$autodns_response" + return "$ret" +} + +# Arguments: +# request_data +_autodns_api_call() { + request_data="$1" + + _debug request_data "$request_data" + + autodns_response="$(_post "$request_data" "$SCHLUNDTECH_API")" + ret="$?" + + _debug autodns_response "$autodns_response" + + if [ "$ret" -ne "0" ]; then + _err "error" + return 1 + fi + + if _contains "$autodns_response" "success" >/dev/null; then + _info "success" + printf "%s" "$autodns_response" + return 0 + fi + + return 1 +} diff --git a/letsencrypt/dnsapi/dns_selectel.sh b/letsencrypt/dnsapi/dns_selectel.sh new file mode 100644 index 00000000..500c97c8 --- /dev/null +++ b/letsencrypt/dnsapi/dns_selectel.sh @@ -0,0 +1,161 @@ +#!/bin/bash + +# +#SL_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# + +SL_Api="https://api.selectel.ru/domains/v1" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_selectel_add() { + fulldomain=$1 + txtvalue=$2 + + SL_Key="${SL_Key:-$(_readaccountconf_mutable SL_Key)}" + + if [ -z "$SL_Key" ]; then + SL_Key="" + _err "You don't specify selectel.ru api key yet." + _err "Please create you key and try again." + return 1 + fi + + #save the api key to the account conf file. + _saveaccountconf_mutable SL_Key "$SL_Key" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _info "Adding record" + if _sl_rest POST "/$_domain_id/records/" "{\"type\": \"TXT\", \"ttl\": 60, \"name\": \"$fulldomain\", \"content\": \"$txtvalue\"}"; then + if _contains "$response" "$txtvalue" || _contains "$response" "record_already_exists"; then + _info "Added, OK" + return 0 + fi + fi + _err "Add txt record error." + return 1 +} + +#fulldomain txtvalue +dns_selectel_rm() { + fulldomain=$1 + txtvalue=$2 + + SL_Key="${SL_Key:-$(_readaccountconf_mutable SL_Key)}" + + if [ -z "$SL_Key" ]; then + SL_Key="" + _err "You don't specify slectel api key yet." + _err "Please create you key and try again." + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _sl_rest GET "/${_domain_id}/records/" + + if ! _contains "$response" "$txtvalue"; then + _err "Txt record not found" + return 1 + fi + + _record_seg="$(echo "$response" | _egrep_o "\"content\" *: *\"$txtvalue\"[^}]*}")" + _debug2 "_record_seg" "$_record_seg" + if [ -z "$_record_seg" ]; then + _err "can not find _record_seg" + return 1 + fi + + _record_id="$(echo "$_record_seg" | tr "," "\n" | tr "}" "\n" | tr -d " " | grep "\"id\"" | cut -d : -f 2)" + _debug2 "_record_id" "$_record_id" + if [ -z "$_record_id" ]; then + _err "can not find _record_id" + return 1 + fi + + if ! _sl_rest DELETE "/$_domain_id/records/$_record_id"; then + _err "Delete record error." + return 1 + fi + return 0 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + + if ! _sl_rest GET "/"; then + return 1 + fi + + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if _contains "$response" "\"name\": \"$h\","; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + _debug "Getting domain id for $h" + if ! _sl_rest GET "/$h"; then + return 1 + fi + _domain_id="$(echo "$response" | tr "," "\n" | tr "}" "\n" | tr -d " " | grep "\"id\":" | cut -d : -f 2)" + return 0 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_sl_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="X-Token: $SL_Key" + export _H2="Content-Type: application/json" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$SL_Api/$ep" "" "$m")" + else + response="$(_get "$SL_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_servercow.sh b/letsencrypt/dnsapi/dns_servercow.sh new file mode 100755 index 00000000..60284e0c --- /dev/null +++ b/letsencrypt/dnsapi/dns_servercow.sh @@ -0,0 +1,170 @@ +#!/bin/bash + +########## +# Custom servercow.de DNS API v1 for use with [acme.sh](https://github.com/acmesh-official/acme.sh) +# +# Usage: +# export SERVERCOW_API_Username=username +# export SERVERCOW_API_Password=password +# acme.sh --issue -d example.com --dns dns_servercow +# +# Issues: +# Any issues / questions / suggestions can be posted here: +# https://github.com/jhartlep/servercow-dns-api/issues +# +# Author: Jens Hartlep +########## + +SERVERCOW_API="https://api.servercow.de/dns/v1/domains" + +# Usage dns_servercow_add _acme-challenge.www.domain.com "abcdefghijklmnopqrstuvwxyz" +dns_servercow_add() { + fulldomain=$1 + txtvalue=$2 + + _info "Using servercow" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}" + SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}" + if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then + SERVERCOW_API_Username="" + SERVERCOW_API_Password="" + _err "You don't specify servercow api username and password yet." + _err "Please create your username and password and try again." + return 1 + fi + + # save the credentials to the account conf file + _saveaccountconf_mutable SERVERCOW_API_Username "$SERVERCOW_API_Username" + _saveaccountconf_mutable SERVERCOW_API_Password "$SERVERCOW_API_Password" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + if _servercow_api POST "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":20}"; then + if printf -- "%s" "$response" | grep "ok" >/dev/null; then + _info "Added, OK" + return 0 + else + _err "add txt record error." + return 1 + fi + fi + _err "add txt record error." + + return 1 +} + +# Usage fulldomain txtvalue +# Remove the txt record after validation +dns_servercow_rm() { + fulldomain=$1 + txtvalue=$2 + + _info "Using servercow" + _debug fulldomain "$fulldomain" + _debug txtvalue "$fulldomain" + + SERVERCOW_API_Username="${SERVERCOW_API_Username:-$(_readaccountconf_mutable SERVERCOW_API_Username)}" + SERVERCOW_API_Password="${SERVERCOW_API_Password:-$(_readaccountconf_mutable SERVERCOW_API_Password)}" + if [ -z "$SERVERCOW_API_Username" ] || [ -z "$SERVERCOW_API_Password" ]; then + SERVERCOW_API_Username="" + SERVERCOW_API_Password="" + _err "You don't specify servercow api username and password yet." + _err "Please create your username and password and try again." + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + if _servercow_api DELETE "$_domain" "{\"type\":\"TXT\",\"name\":\"$fulldomain\"}"; then + if printf -- "%s" "$response" | grep "ok" >/dev/null; then + _info "Deleted, OK" + _contains "$response" '"message":"ok"' + else + _err "delete txt record error." + return 1 + fi + fi + +} + +#################### Private functions below ################################## + +# _acme-challenge.www.domain.com +# returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + fulldomain=$1 + i=2 + p=1 + + while true; do + _domain=$(printf "%s" "$fulldomain" | cut -d . -f $i-100) + + _debug _domain "$_domain" + if [ -z "$_domain" ]; then + # not valid + return 1 + fi + + if ! _servercow_api GET "$_domain"; then + return 1 + fi + + if ! _contains "$response" '"error":"no such domain in user context"' >/dev/null; then + _sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-$p) + if [ -z "$_sub_domain" ]; then + # not valid + return 1 + fi + + return 0 + fi + + p=$i + i=$(_math "$i" + 1) + done + + return 1 +} + +_servercow_api() { + method=$1 + domain=$2 + data="$3" + + export _H1="Content-Type: application/json" + export _H2="X-Auth-Username: $SERVERCOW_API_Username" + export _H3="X-Auth-Password: $SERVERCOW_API_Password" + + if [ "$method" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$SERVERCOW_API/$domain" "" "$method")" + else + response="$(_get "$SERVERCOW_API/$domain")" + fi + + if [ "$?" != "0" ]; then + _err "error $domain" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_tele3.sh b/letsencrypt/dnsapi/dns_tele3.sh new file mode 100644 index 00000000..35d6c56e --- /dev/null +++ b/letsencrypt/dnsapi/dns_tele3.sh @@ -0,0 +1,69 @@ +#!/bin/bash +# +# tele3.cz DNS API +# +# Author: Roman Blizik +# Report Bugs here: https://github.com/par-pa/acme.sh +# +# -- +# export TELE3_Key="MS2I4uPPaI..." +# export TELE3_Secret="kjhOIHGJKHg" +# -- + +TELE3_API="https://www.tele3.cz/acme/" + +######## Public functions ##################### + +dns_tele3_add() { + _info "Using TELE3 DNS" + data="\"ope\":\"add\", \"domain\":\"$1\", \"value\":\"$2\"" + if ! _tele3_call; then + _err "Publish zone failed" + return 1 + fi + + _info "Zone published" +} + +dns_tele3_rm() { + _info "Using TELE3 DNS" + data="\"ope\":\"rm\", \"domain\":\"$1\", \"value\":\"$2\"" + if ! _tele3_call; then + _err "delete TXT record failed" + return 1 + fi + + _info "TXT record successfully deleted" +} + +#################### Private functions below ################################## + +_tele3_init() { + TELE3_Key="${TELE3_Key:-$(_readaccountconf_mutable TELE3_Key)}" + TELE3_Secret="${TELE3_Secret:-$(_readaccountconf_mutable TELE3_Secret)}" + if [ -z "$TELE3_Key" ] || [ -z "$TELE3_Secret" ]; then + TELE3_Key="" + TELE3_Secret="" + _err "You must export variables: TELE3_Key and TELE3_Secret" + return 1 + fi + + #save the config variables to the account conf file. + _saveaccountconf_mutable TELE3_Key "$TELE3_Key" + _saveaccountconf_mutable TELE3_Secret "$TELE3_Secret" +} + +_tele3_call() { + _tele3_init + data="{\"key\":\"$TELE3_Key\", \"secret\":\"$TELE3_Secret\", $data}" + + _debug data "$data" + + response="$(_post "$data" "$TELE3_API" "" "POST")" + _debug response "$response" + + if [ "$response" != "success" ]; then + _err "$response" + return 1 + fi +} diff --git a/letsencrypt/dnsapi/dns_transip.sh b/letsencrypt/dnsapi/dns_transip.sh new file mode 100644 index 00000000..6506a724 --- /dev/null +++ b/letsencrypt/dnsapi/dns_transip.sh @@ -0,0 +1,162 @@ +#!/bin/bash +TRANSIP_Api_Url="https://api.transip.nl/v6" +TRANSIP_Token_Read_Only="false" +TRANSIP_Token_Global_Key="false" +TRANSIP_Token_Expiration="30 minutes" +# You can't reuse a label token, so we leave this empty normally +TRANSIP_Token_Label="" + +######## Public functions ##################### +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_transip_add() { + fulldomain="$1" + _debug fulldomain="$fulldomain" + txtvalue="$2" + _debug txtvalue="$txtvalue" + _transip_setup "$fulldomain" || return 1 + _info "Creating TXT record." + if ! _transip_rest POST "domains/$_domain/dns" "{\"dnsEntry\":{\"name\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"expire\":300}}"; then + _err "Could not add TXT record." + return 1 + fi + return 0 +} + +dns_transip_rm() { + fulldomain=$1 + _debug fulldomain="$fulldomain" + txtvalue=$2 + _debug txtvalue="$txtvalue" + _transip_setup "$fulldomain" || return 1 + _info "Removing TXT record." + if ! _transip_rest DELETE "domains/$_domain/dns" "{\"dnsEntry\":{\"name\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"expire\":300}}"; then + _err "Could not remove TXT record $_sub_domain for $domain" + return 1 + fi + return 0 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + domain="$1" + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + + if [ -z "$h" ]; then + #not valid + return 1 + fi + + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="$h" + + if _transip_rest GET "domains/$h/dns" && _contains "$response" "dnsEntries"; then + return 0 + fi + + p=$i + i=$(_math "$i" + 1) + done + _err "Unable to parse this domain" + return 1 +} + +_transip_rest() { + m="$1" + ep="$2" + data="$3" + _debug ep "$ep" + export _H1="Accept: application/json" + export _H2="Authorization: Bearer $_token" + export _H4="Content-Type: application/json" + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$TRANSIP_Api_Url/$ep" "" "$m")" + retcode=$? + else + response="$(_get "$TRANSIP_Api_Url/$ep")" + retcode=$? + fi + + if [ "$retcode" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} + +_transip_get_token() { + nonce=$(echo "TRANSIP$(_time)" | _digest sha1 hex | cut -c 1-32) + _debug nonce "$nonce" + + data="{\"login\":\"${TRANSIP_Username}\",\"nonce\":\"${nonce}\",\"read_only\":\"${TRANSIP_Token_Read_Only}\",\"expiration_time\":\"${TRANSIP_Token_Expiration}\",\"label\":\"${TRANSIP_Token_Label}\",\"global_key\":\"${TRANSIP_Token_Global_Key}\"}" + _debug data "$data" + + #_signature=$(printf "%s" "$data" | openssl dgst -sha512 -sign "$TRANSIP_Key_File" | _base64) + _signature=$(printf "%s" "$data" | _sign "$TRANSIP_Key_File" "sha512") + _debug2 _signature "$_signature" + + export _H1="Signature: $_signature" + export _H2="Content-Type: application/json" + + response="$(_post "$data" "$TRANSIP_Api_Url/auth" "" "POST")" + retcode=$? + _debug2 response "$response" + if [ "$retcode" != "0" ]; then + _err "Authentication failed." + return 1 + fi + if _contains "$response" "token"; then + _token="$(echo "$response" | _normalizeJson | sed -n 's/^{"token":"\(.*\)"}/\1/p')" + _debug _token "$_token" + return 0 + fi + return 1 +} + +_transip_setup() { + fulldomain=$1 + + # retrieve the transip creds + TRANSIP_Username="${TRANSIP_Username:-$(_readaccountconf_mutable TRANSIP_Username)}" + TRANSIP_Key_File="${TRANSIP_Key_File:-$(_readaccountconf_mutable TRANSIP_Key_File)}" + # check their vals for null + if [ -z "$TRANSIP_Username" ] || [ -z "$TRANSIP_Key_File" ]; then + TRANSIP_Username="" + TRANSIP_Key_File="" + _err "You didn't specify a TransIP username and api key file location" + _err "Please set those values and try again." + return 1 + fi + # save the username and api key to the account conf file. + _saveaccountconf_mutable TRANSIP_Username "$TRANSIP_Username" + _saveaccountconf_mutable TRANSIP_Key_File "$TRANSIP_Key_File" + + if [ -f "$TRANSIP_Key_File" ]; then + if ! grep "BEGIN PRIVATE KEY" "$TRANSIP_Key_File" >/dev/null 2>&1; then + _err "Key file doesn't seem to be a valid key: ${TRANSIP_Key_File}" + return 1 + fi + else + _err "Can't read private key file: ${TRANSIP_Key_File}" + return 1 + fi + + if [ -z "$_token" ]; then + if ! _transip_get_token; then + _err "Can not get token." + return 1 + fi + fi + + _get_root "$fulldomain" || return 1 + + return 0 +} diff --git a/letsencrypt/dnsapi/dns_ultra.sh b/letsencrypt/dnsapi/dns_ultra.sh new file mode 100644 index 00000000..310b4a55 --- /dev/null +++ b/letsencrypt/dnsapi/dns_ultra.sh @@ -0,0 +1,164 @@ +#!/bin/bash + +# +# ULTRA_USR="your_user_goes_here" +# +# ULTRA_PWD="some_password_goes_here" + +ULTRA_API="https://restapi.ultradns.com/v2/" + +#Usage: add _acme-challenge.www.domain.com "some_long_string_of_characters_go_here_from_lets_encrypt" +dns_ultra_add() { + fulldomain=$1 + txtvalue=$2 + export txtvalue + ULTRA_USR="${ULTRA_USR:-$(_readaccountconf_mutable ULTRA_USR)}" + ULTRA_PWD="${ULTRA_PWD:-$(_readaccountconf_mutable ULTRA_PWD)}" + if [ -z "$ULTRA_USR" ] || [ -z "$ULTRA_PWD" ]; then + ULTRA_USR="" + ULTRA_PWD="" + _err "You didn't specify an UltraDNS username and password yet" + return 1 + fi + # save the username and password to the account conf file. + _saveaccountconf_mutable ULTRA_USR "$ULTRA_USR" + _saveaccountconf_mutable ULTRA_PWD "$ULTRA_PWD" + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "${_domain_id}" + _debug _sub_domain "${_sub_domain}" + _debug _domain "${_domain}" + _debug "Getting txt records" + _ultra_rest GET "zones/${_domain_id}/rrsets/TXT?q=value:${fulldomain}" + if printf "%s" "$response" | grep \"totalCount\" >/dev/null; then + _err "Error, it would appear that this record already exists. Please review existing TXT records for this domain." + return 1 + fi + + _info "Adding record" + if _ultra_rest POST "zones/$_domain_id/rrsets/TXT/${_sub_domain}" '{"ttl":300,"rdata":["'"${txtvalue}"'"]}'; then + if _contains "$response" "Successful"; then + _info "Added, OK" + return 0 + elif _contains "$response" "Resource Record of type 16 with these attributes already exists"; then + _info "Already exists, OK" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + +} + +dns_ultra_rm() { + fulldomain=$1 + txtvalue=$2 + export txtvalue + ULTRA_USR="${ULTRA_USR:-$(_readaccountconf_mutable ULTRA_USR)}" + ULTRA_PWD="${ULTRA_PWD:-$(_readaccountconf_mutable ULTRA_PWD)}" + if [ -z "$ULTRA_USR" ] || [ -z "$ULTRA_PWD" ]; then + ULTRA_USR="" + ULTRA_PWD="" + _err "You didn't specify an UltraDNS username and password yet" + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "${_domain_id}" + _debug _sub_domain "${_sub_domain}" + _debug _domain "${domain}" + + _debug "Getting TXT records" + _ultra_rest GET "zones/${_domain_id}/rrsets?q=kind:RECORDS+owner:${_sub_domain}" + + if ! printf "%s" "$response" | grep \"resultInfo\" >/dev/null; then + _err "There was an error in obtaining the resource records for ${_domain_id}" + return 1 + fi + + count=$(echo "$response" | _egrep_o "\"returnedCount\":[^,]*" | cut -d: -f2 | cut -d'}' -f1) + _debug count "${count}" + if [ "${count}" = "" ]; then + _info "Text record is not present, will not delete anything." + else + if ! _ultra_rest DELETE "zones/$_domain_id/rrsets/TXT/${_sub_domain}" '{"ttl":300,"rdata":["'"${txtvalue}"'"]}'; then + _err "Deleting the record did not succeed, please verify/check." + return 1 + fi + _contains "$response" "" + fi + +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + _debug response "$response" + if [ -z "$h" ]; then + #not valid + return 1 + fi + if ! _ultra_rest GET "zones"; then + return 1 + fi + if _contains "${response}" "${h}." >/dev/null; then + _domain_id=$(echo "$response" | _egrep_o "${h}") + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="${h}" + _debug sub_domain "${_sub_domain}" + _debug domain "${_domain}" + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_ultra_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + _debug TOKEN "${AUTH_TOKEN}" + + _ultra_login + export _H1="Content-Type: application/json" + export _H2="Authorization: Bearer ${AUTH_TOKEN}" + + if [ "$m" != "GET" ]; then + _debug data "${data}" + response="$(_post "${data}" "${ULTRA_API}"/"${ep}" "" "${m}")" + else + response="$(_get "$ULTRA_API/$ep")" + fi +} + +_ultra_login() { + export _H1="" + export _H2="" + AUTH_TOKEN=$(_post "grant_type=password&username=${ULTRA_USR}&password=${ULTRA_PWD}" "${ULTRA_API}authorization/token" | cut -d, -f3 | cut -d\" -f4) + export AUTH_TOKEN +} diff --git a/letsencrypt/dnsapi/dns_unoeuro.sh b/letsencrypt/dnsapi/dns_unoeuro.sh new file mode 100644 index 00000000..ae4500ce --- /dev/null +++ b/letsencrypt/dnsapi/dns_unoeuro.sh @@ -0,0 +1,179 @@ +#!/bin/bash + +# +#UNO_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# +#UNO_User="UExxxxxx" + +Uno_Api="https://api.simply.com/1" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_unoeuro_add() { + fulldomain=$1 + txtvalue=$2 + + UNO_Key="${UNO_Key:-$(_readaccountconf_mutable UNO_Key)}" + UNO_User="${UNO_User:-$(_readaccountconf_mutable UNO_User)}" + if [ -z "$UNO_Key" ] || [ -z "$UNO_User" ]; then + UNO_Key="" + UNO_User="" + _err "You haven't specified a UnoEuro api key and account yet." + _err "Please create your key and try again." + return 1 + fi + + #save the api key and email to the account conf file. + _saveaccountconf_mutable UNO_Key "$UNO_Key" + _saveaccountconf_mutable UNO_User "$UNO_User" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _uno_rest GET "my/products/$h/dns/records" + + if ! _contains "$response" "\"status\": 200" >/dev/null; then + _err "Error" + return 1 + fi + _info "Adding record" + + if _uno_rest POST "my/products/$h/dns/records" "{\"name\":\"$fulldomain\",\"type\":\"TXT\",\"data\":\"$txtvalue\",\"ttl\":120,\"priority\":0}"; then + if _contains "$response" "\"status\": 200" >/dev/null; then + _info "Added, OK" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi +} + +#fulldomain txtvalue +dns_unoeuro_rm() { + fulldomain=$1 + txtvalue=$2 + + UNO_Key="${UNO_Key:-$(_readaccountconf_mutable UNO_Key)}" + UNO_User="${UNO_User:-$(_readaccountconf_mutable UNO_User)}" + if [ -z "$UNO_Key" ] || [ -z "$UNO_User" ]; then + UNO_Key="" + UNO_User="" + _err "You haven't specified a UnoEuro api key and account yet." + _err "Please create your key and try again." + return 1 + fi + + if ! _contains "$UNO_User" "UE"; then + _err "It seems that the UNO_User=$UNO_User is not a valid username." + _err "Please check and retry." + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _uno_rest GET "my/products/$h/dns/records" + + if ! _contains "$response" "\"status\": 200"; then + _err "Error" + return 1 + fi + + if ! _contains "$response" "$_sub_domain"; then + _info "Don't need to remove." + else + for record_line_number in $(echo "$response" | grep -n "$_sub_domain" | cut -d : -f 1); do + record_line_number=$(_math "$record_line_number" - 1) + _debug "record_line_number" "$record_line_number" + record_id=$(echo "$response" | _head_n "$record_line_number" | _tail_n 1 1 | _egrep_o "[0-9]{1,}") + _debug "record_id" "$record_id" + + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + + if ! _uno_rest DELETE "my/products/$h/dns/records/$record_id"; then + _err "Delete record error." + return 1 + fi + _contains "$response" "\"status\": 200" + done + fi +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _uno_rest GET "my/products/$h/dns/records"; then + return 1 + fi + + if _contains "$response" "\"status\": 200"; then + _domain_id=$h + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_uno_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Content-Type: application/json" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$Uno_Api/$UNO_User/$UNO_Key/$ep" "" "$m")" + else + response="$(_get "$Uno_Api/$UNO_User/$UNO_Key/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_variomedia.sh b/letsencrypt/dnsapi/dns_variomedia.sh new file mode 100644 index 00000000..9d17630d --- /dev/null +++ b/letsencrypt/dnsapi/dns_variomedia.sh @@ -0,0 +1,147 @@ +#!/bin/bash + +# +#VARIOMEDIA_API_TOKEN=000011112222333344445555666677778888 + +VARIOMEDIA_API="https://api.variomedia.de" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_variomedia_add() { + fulldomain=$1 + txtvalue=$2 + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + VARIOMEDIA_API_TOKEN="${VARIOMEDIA_API_TOKEN:-$(_readaccountconf_mutable VARIOMEDIA_API_TOKEN)}" + if test -z "$VARIOMEDIA_API_TOKEN"; then + VARIOMEDIA_API_TOKEN="" + _err 'VARIOMEDIA_API_TOKEN was not exported' + return 1 + fi + + _saveaccountconf_mutable VARIOMEDIA_API_TOKEN "$VARIOMEDIA_API_TOKEN" + + _debug 'First detect the root zone' + if ! _get_root "$fulldomain"; then + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + if ! _variomedia_rest POST "dns-records" "{\"data\": {\"type\": \"dns-record\", \"attributes\": {\"record_type\": \"TXT\", \"name\": \"$_sub_domain\", \"domain\": \"$_domain\", \"data\": \"$txtvalue\", \"ttl\":300}}}"; then + _err "$response" + return 1 + fi + + _debug2 _response "$response" + return 0 +} + +#fulldomain txtvalue +dns_variomedia_rm() { + fulldomain=$1 + txtvalue=$2 + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + VARIOMEDIA_API_TOKEN="${VARIOMEDIA_API_TOKEN:-$(_readaccountconf_mutable VARIOMEDIA_API_TOKEN)}" + if test -z "$VARIOMEDIA_API_TOKEN"; then + VARIOMEDIA_API_TOKEN="" + _err 'VARIOMEDIA_API_TOKEN was not exported' + return 1 + fi + + _saveaccountconf_mutable VARIOMEDIA_API_TOKEN "$VARIOMEDIA_API_TOKEN" + + _debug 'First detect the root zone' + if ! _get_root "$fulldomain"; then + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug 'Getting txt records' + + if ! _variomedia_rest GET "dns-records?filter[domain]=$_domain"; then + _err 'Error' + return 1 + fi + + _record_id="$(echo "$response" | cut -d '[' -f2 | cut -d']' -f1 | sed 's/},[ \t]*{/\},§\{/g' | tr § '\n' | grep "$_sub_domain" | grep "$txtvalue" | sed 's/^{//;s/}[,]?$//' | tr , '\n' | tr -d '\"' | grep ^id | cut -d : -f2 | tr -d ' ')" + _debug _record_id "$_record_id" + if [ "$_record_id" ]; then + _info "Successfully retrieved the record id for ACME challenge." + else + _info "Empty record id, it seems no such record." + return 0 + fi + + if ! _variomedia_rest DELETE "/dns-records/$_record_id"; then + _err "$response" + return 1 + fi + + _debug2 _response "$response" + return 0 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +_get_root() { + fulldomain=$1 + i=1 + while true; do + h=$(printf "%s" "$fulldomain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + return 1 + fi + + if ! _variomedia_rest GET "domains/$h"; then + return 1 + fi + + if _startswith "$response" "\{\"data\":"; then + if _contains "$response" "\"id\":\"$h\""; then + _sub_domain="$(echo "$fulldomain" | sed "s/\\.$h\$//")" + _domain=$h + return 0 + fi + fi + i=$(_math "$i" + 1) + done + + _debug "root domain not found" + return 1 +} + +_variomedia_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + export _H1="Authorization: token $VARIOMEDIA_API_TOKEN" + export _H2="Content-Type: application/vnd.api+json" + export _H3="Accept: application/vnd.variomedia.v1+json" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$VARIOMEDIA_API/$ep" "" "$m")" + else + response="$(_get "$VARIOMEDIA_API/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "Error $ep" + return 1 + fi + + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_vscale.sh b/letsencrypt/dnsapi/dns_vscale.sh new file mode 100755 index 00000000..c628db7d --- /dev/null +++ b/letsencrypt/dnsapi/dns_vscale.sh @@ -0,0 +1,149 @@ +#!/bin/bash + +#This is the vscale.io api wrapper for acme.sh +# +#Author: Alex Loban +#Report Bugs here: https://github.com/LAV45/acme.sh + +#VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje" +VSCALE_API_URL="https://api.vscale.io/v1" + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_vscale_add() { + fulldomain=$1 + txtvalue=$2 + + if [ -z "$VSCALE_API_KEY" ]; then + VSCALE_API_KEY="" + _err "You didn't specify the VSCALE api key yet." + _err "Please create you key and try again." + return 1 + fi + + _saveaccountconf VSCALE_API_KEY "$VSCALE_API_KEY" + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _vscale_tmpl_json="{\"type\":\"TXT\",\"name\":\"$_sub_domain.$_domain\",\"content\":\"$txtvalue\"}" + + if _vscale_rest POST "domains/$_domain_id/records/" "$_vscale_tmpl_json"; then + response=$(printf "%s\n" "$response" | _egrep_o "{\"error\": \".+\"" | cut -d : -f 2) + if [ -z "$response" ]; then + _info "txt record updated success." + return 0 + fi + fi + + return 1 +} + +#fulldomain txtvalue +dns_vscale_rm() { + fulldomain=$1 + txtvalue=$2 + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "$_domain_id" + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug "Getting txt records" + _vscale_rest GET "domains/$_domain_id/records/" + + if [ -n "$response" ]; then + record_id=$(printf "%s\n" "$response" | _egrep_o "\"TXT\", \"id\": [0-9]+, \"name\": \"$_sub_domain.$_domain\"" | cut -d : -f 2 | tr -d ", \"name\"") + _debug record_id "$record_id" + if [ -z "$record_id" ]; then + _err "Can not get record id to remove." + return 1 + fi + if _vscale_rest DELETE "domains/$_domain_id/records/$record_id" && [ -z "$response" ]; then + _info "txt record deleted success." + return 0 + fi + _debug response "$response" + return 1 + fi + + return 1 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=12345 +_get_root() { + domain=$1 + i=2 + p=1 + + if _vscale_rest GET "domains/"; then + response="$(echo "$response" | tr -d "\n" | sed 's/{/\n&/g')" + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + hostedzone="$(echo "$response" | tr "{" "\n" | _egrep_o "\"name\":\s*\"$h\".*}")" + if [ "$hostedzone" ]; then + _domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ ) + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain=$h + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + fi + return 1 +} + +#method uri qstr data +_vscale_rest() { + mtd="$1" + ep="$2" + data="$3" + + _debug mtd "$mtd" + _debug ep "$ep" + + export _H1="Accept: application/json" + export _H2="Content-Type: application/json" + export _H3="X-Token: ${VSCALE_API_KEY}" + + if [ "$mtd" != "GET" ]; then + # both POST and DELETE. + _debug data "$data" + response="$(_post "$data" "$VSCALE_API_URL/$ep" "" "$mtd")" + else + response="$(_get "$VSCALE_API_URL/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_vultr.sh b/letsencrypt/dnsapi/dns_vultr.sh new file mode 100644 index 00000000..0dce2ca1 --- /dev/null +++ b/letsencrypt/dnsapi/dns_vultr.sh @@ -0,0 +1,161 @@ +#!/bin/bash + +# +#VULTR_API_KEY=000011112222333344445555666677778888 + +VULTR_Api="https://api.vultr.com/v1" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_vultr_add() { + fulldomain=$1 + txtvalue=$2 + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + VULTR_API_KEY="${VULTR_API_KEY:-$(_readaccountconf_mutable VULTR_API_KEY)}" + if test -z "$VULTR_API_KEY"; then + VULTR_API_KEY='' + _err 'VULTR_API_KEY was not exported' + return 1 + fi + + _saveaccountconf_mutable VULTR_API_KEY "$VULTR_API_KEY" + + _debug 'First detect the root zone' + if ! _get_root "$fulldomain"; then + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug 'Getting txt records' + _vultr_rest GET "dns/records?domain=$_domain" + + if printf "%s\n" "$response" | grep "\"type\":\"TXT\",\"name\":\"$fulldomain\"" >/dev/null; then + _err 'Error' + return 1 + fi + + if ! _vultr_rest POST 'dns/create_record' "domain=$_domain&name=$_sub_domain&data=\"$txtvalue\"&type=TXT"; then + _err "$response" + return 1 + fi + + _debug2 _response "$response" + return 0 +} + +#fulldomain txtvalue +dns_vultr_rm() { + fulldomain=$1 + txtvalue=$2 + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + VULTR_API_KEY="${VULTR_API_KEY:-$(_readaccountconf_mutable VULTR_API_KEY)}" + if test -z "$VULTR_API_KEY"; then + VULTR_API_KEY="" + _err 'VULTR_API_KEY was not exported' + return 1 + fi + + _saveaccountconf_mutable VULTR_API_KEY "$VULTR_API_KEY" + + _debug 'First detect the root zone' + if ! _get_root "$fulldomain"; then + return 1 + fi + _debug _sub_domain "$_sub_domain" + _debug _domain "$_domain" + + _debug 'Getting txt records' + _vultr_rest GET "dns/records?domain=$_domain" + + if printf "%s\n" "$response" | grep "\"type\":\"TXT\",\"name\":\"$fulldomain\"" >/dev/null; then + _err 'Error' + return 1 + fi + + _record_id="$(echo "$response" | tr '{}' '\n' | grep '"TXT"' | grep "$txtvalue" | tr ',' '\n' | grep -i 'RECORDID' | cut -d : -f 2)" + _debug _record_id "$_record_id" + if [ "$_record_id" ]; then + _info "Successfully retrieved the record id for ACME challenge." + else + _info "Empty record id, it seems no such record." + return 0 + fi + + if ! _vultr_rest POST 'dns/delete_record' "domain=$_domain&RECORDID=$_record_id"; then + _err "$response" + return 1 + fi + + _debug2 _response "$response" + return 0 +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=1 + while true; do + _domain=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$_domain" + if [ -z "$_domain" ]; then + return 1 + fi + + if ! _vultr_rest GET "dns/list"; then + return 1 + fi + + if printf "%s\n" "$response" | grep '^\[.*\]' >/dev/null; then + if _contains "$response" "\"domain\":\"$_domain\""; then + _sub_domain="$(echo "$fulldomain" | sed "s/\\.$_domain\$//")" + return 0 + else + _debug "Go to next level of $_domain" + fi + else + _err "$response" + return 1 + fi + i=$(_math "$i" + 1) + done + + return 1 +} + +_vultr_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + api_key_trimmed=$(echo $VULTR_API_KEY | tr -d '"') + + export _H1="Api-Key: $api_key_trimmed" + export _H2='Content-Type: application/x-www-form-urlencoded' + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$VULTR_Api/$ep" "" "$m")" + else + response="$(_get "$VULTR_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "Error $ep" + return 1 + fi + + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_world4you.sh b/letsencrypt/dnsapi/dns_world4you.sh new file mode 100644 index 00000000..be59e439 --- /dev/null +++ b/letsencrypt/dnsapi/dns_world4you.sh @@ -0,0 +1,191 @@ +#!/bin/bash + +# World4You - www.world4you.com +# Lorenz Stechauner, 2020 - https://www.github.com/NerLOR + +WORLD4YOU_API="https://my.world4you.com/en" +PAKETNR='' +TLD='' +RECORD='' + +################ Public functions ################ + +# Usage: dns_world4you_add +dns_world4you_add() { + fqdn="$1" + value="$2" + _info "Using world4you to add record" + _debug fulldomain "$fqdn" + _debug txtvalue "$value" + + _login + if [ "$?" != 0 ]; then + return 1 + fi + + export _H1="Cookie: W4YSESSID=$sessid" + form=$(_get "$WORLD4YOU_API/dashboard/paketuebersicht") + _get_paketnr "$fqdn" "$form" + paketnr="$PAKETNR" + if [ -z "$paketnr" ]; then + _err "Unable to parse paketnr" + return 3 + fi + _debug paketnr "$paketnr" + + export _H1="Cookie: W4YSESSID=$sessid" + form=$(_get "$WORLD4YOU_API/$paketnr/dns") + formiddp=$(echo "$form" | grep 'AddDnsRecordForm\[uniqueFormIdDP\]' | sed 's/^.*name="AddDnsRecordForm\[uniqueFormIdDP\]" value="\([^"]*\)".*$/\1/') + formidttl=$(echo "$form" | grep 'AddDnsRecordForm\[uniqueFormIdTTL\]' | sed 's/^.*name="AddDnsRecordForm\[uniqueFormIdTTL\]" value="\([^"]*\)".*$/\1/') + form_token=$(echo "$form" | grep 'AddDnsRecordForm\[_token\]' | sed 's/^.*name="AddDnsRecordForm\[_token\]" value="\([^"]*\)".*$/\1/') + if [ -z "$formiddp" ]; then + _err "Unable to parse form" + return 3 + fi + + _resethttp + export ACME_HTTP_NO_REDIRECTS=1 + body="AddDnsRecordForm[name]=$RECORD&AddDnsRecordForm[dnsType][type]=TXT&\ +AddDnsRecordForm[value]=$value&AddDnsRecordForm[aktivPaket]=$paketnr&AddDnsRecordForm[uniqueFormIdDP]=$formiddp&\ +AddDnsRecordForm[uniqueFormIdTTL]=$formidttl&AddDnsRecordForm[_token]=$form_token" + _info "Adding record..." + ret=$(_post "$body" "$WORLD4YOU_API/$paketnr/dns" '' POST 'application/x-www-form-urlencoded') + _resethttp + + if grep '302' >/dev/null <"$HTTP_HEADER"; then + res=$(_get "$WORLD4YOU_API/$paketnr/dns") + if _contains "$res" "successfully"; then + return 0 + else + msg=$(echo "$res" | tr '\n' '\t' | sed 's/.*

[^\t]*\t *\([^\t]*\)\t.*/\1/') + _err "Unable to add record: $msg" + return 1 + fi + else + _err "$(_head_n 1 <"$HTTP_HEADER")" + return 1 + fi +} + +# Usage: dns_world4you_rm +dns_world4you_rm() { + fqdn="$1" + value="$2" + _info "Using world4you to remove record" + _debug fulldomain "$fqdn" + _debug txtvalue "$value" + + _login + if [ "$?" != 0 ]; then + return 1 + fi + + export _H1="Cookie: W4YSESSID=$sessid" + form=$(_get "$WORLD4YOU_API/dashboard/paketuebersicht") + _get_paketnr "$fqdn" "$form" + paketnr="$PAKETNR" + if [ -z "$paketnr" ]; then + _err "Unable to parse paketnr" + return 3 + fi + _debug paketnr "$paketnr" + + form=$(_get "$WORLD4YOU_API/$paketnr/dns") + formiddp=$(echo "$form" | grep 'DeleteDnsRecordForm\[uniqueFormIdDP\]' | sed 's/^.*name="DeleteDnsRecordForm\[uniqueFormIdDP\]" value="\([^"]*\)".*$/\1/') + formidttl=$(echo "$form" | grep 'DeleteDnsRecordForm\[uniqueFormIdTTL\]' | sed 's/^.*name="DeleteDnsRecordForm\[uniqueFormIdTTL\]" value="\([^"]*\)".*$/\1/') + form_token=$(echo "$form" | grep 'DeleteDnsRecordForm\[_token\]' | sed 's/^.*name="DeleteDnsRecordForm\[_token\]" value="\([^"]*\)".*$/\1/') + if [ -z "$formiddp" ]; then + _err "Unable to parse form" + return 3 + fi + + recordid=$(printf "TXT:%s.:\"%s\"" "$fqdn" "$value" | _base64) + _debug recordid "$recordid" + + _resethttp + export ACME_HTTP_NO_REDIRECTS=1 + body="DeleteDnsRecordForm[recordId]=$recordid&DeleteDnsRecordForm[aktivPaket]=$paketnr&\ +DeleteDnsRecordForm[uniqueFormIdDP]=$formiddp&DeleteDnsRecordForm[uniqueFormIdTTL]=$formidttl&\ +DeleteDnsRecordForm[_token]=$form_token" + _info "Removing record..." + ret=$(_post "$body" "$WORLD4YOU_API/$paketnr/deleteRecord" '' POST 'application/x-www-form-urlencoded') + _resethttp + + if grep '302' >/dev/null <"$HTTP_HEADER"; then + res=$(_get "$WORLD4YOU_API/$paketnr/dns") + if _contains "$res" "successfully"; then + return 0 + else + msg=$(echo "$res" | tr '\n' '\t' | sed 's/.*

[^\t]*\t *\([^\t]*\)\t.*/\1/') + _err "Unable to remove record: $msg" + return 1 + fi + else + _err "$(_head_n 1 <"$HTTP_HEADER")" + return 1 + fi +} + +################ Private functions ################ + +# Usage: _login +_login() { + WORLD4YOU_USERNAME="${WORLD4YOU_USERNAME:-$(_readaccountconf_mutable WORLD4YOU_USERNAME)}" + WORLD4YOU_PASSWORD="${WORLD4YOU_PASSWORD:-$(_readaccountconf_mutable WORLD4YOU_PASSWORD)}" + + if [ -z "$WORLD4YOU_USERNAME" ] || [ -z "$WORLD4YOU_PASSWORD" ]; then + WORLD4YOU_USERNAME="" + WORLD4YOU_PASSWORD="" + _err "You didn't specify world4you username and password yet." + _err "Usage: export WORLD4YOU_USERNAME=" + _err "Usage: export WORLD4YOU_PASSWORD=" + return 1 + fi + + _saveaccountconf_mutable WORLD4YOU_USERNAME "$WORLD4YOU_USERNAME" + _saveaccountconf_mutable WORLD4YOU_PASSWORD "$WORLD4YOU_PASSWORD" + + _info "Logging in..." + + username="$WORLD4YOU_USERNAME" + password="$WORLD4YOU_PASSWORD" + csrf_token=$(_get "$WORLD4YOU_API/login" | grep '_csrf_token' | sed 's/^.*]*value=\"\([^"]*\)\".*$/\1/') + sessid=$(grep 'W4YSESSID' <"$HTTP_HEADER" | sed 's/^.*W4YSESSID=\([^;]*\);.*$/\1/') + + export _H1="Cookie: W4YSESSID=$sessid" + export _H2="X-Requested-With: XMLHttpRequest" + body="_username=$username&_password=$password&_csrf_token=$csrf_token" + ret=$(_post "$body" "$WORLD4YOU_API/login" '' POST 'application/x-www-form-urlencoded') + unset _H2 + _debug ret "$ret" + if _contains "$ret" "\"success\":true"; then + _info "Successfully logged in" + sessid=$(grep 'W4YSESSID' <"$HTTP_HEADER" | sed 's/^.*W4YSESSID=\([^;]*\);.*$/\1/') + else + _err "Unable to log in: $(echo "$ret" | sed 's/^.*"message":"\([^\"]*\)".*$/\1/')" + return 1 + fi +} + +# Usage _get_paketnr
+_get_paketnr() { + fqdn="$1" + form="$2" + + domains=$(echo "$form" | grep '^ *[A-Za-z0-9_\.-]*\.[A-Za-z0-9_-]*$' | sed 's/^\s*\(\S*\)$/\1/') + domain='' + for domain in $domains; do + if echo "$fqdn" | grep "$domain\$" >/dev/null; then + break + fi + domain='' + done + if [ -z "$domain" ]; then + return 1 + fi + + TLD="$domain" + RECORD=$(echo "$fqdn" | cut -c"1-$((${#fqdn} - ${#TLD} - 1))") + PAKETNR=$(echo "$form" | grep "data-textfilter=\" $domain " | _head_n 1 | sed 's/^.* \([0-9]*\) .*$/\1/') + return 0 +} diff --git a/letsencrypt/dnsapi/dns_yandex.sh b/letsencrypt/dnsapi/dns_yandex.sh new file mode 100755 index 00000000..caee633b --- /dev/null +++ b/letsencrypt/dnsapi/dns_yandex.sh @@ -0,0 +1,121 @@ +#!/bin/bash +# Author: non7top@gmail.com +# 07 Jul 2017 +# report bugs at https://github.com/non7top/acme.sh + +# Values to export: +# export PDD_Token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + +# Sometimes cloudflare / google doesn't pick new dns records fast enough. +# You can add --dnssleep XX to params as workaround. + +######## Public functions ##################### + +#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_yandex_add() { + fulldomain="${1}" + txtvalue="${2}" + _debug "Calling: dns_yandex_add() '${fulldomain}' '${txtvalue}'" + + _PDD_credentials || return 1 + + _PDD_get_domain || return 1 + _debug "Found suitable domain: $domain" + + _PDD_get_record_ids || return 1 + _debug "Record_ids: $record_ids" + + if [ -n "$record_ids" ]; then + _info "All existing $subdomain records from $domain will be removed at the very end." + fi + + data="domain=${domain}&type=TXT&subdomain=${subdomain}&ttl=300&content=${txtvalue}" + uri="https://pddimp.yandex.ru/api2/admin/dns/add" + result="$(_post "${data}" "${uri}" | _normalizeJson)" + _debug "Result: $result" + + if ! _contains "$result" '"success":"ok"'; then + if _contains "$result" '"success":"error"' && _contains "$result" '"error":"record_exists"'; then + _info "Record already exists." + else + _err "Can't add $subdomain to $domain." + return 1 + fi + fi +} + +#Usage: dns_myapi_rm _acme-challenge.www.domain.com +dns_yandex_rm() { + fulldomain="${1}" + _debug "Calling: dns_yandex_rm() '${fulldomain}'" + + _PDD_credentials || return 1 + + _PDD_get_domain "$fulldomain" || return 1 + _debug "Found suitable domain: $domain" + + _PDD_get_record_ids "${domain}" "${subdomain}" || return 1 + _debug "Record_ids: $record_ids" + + for record_id in $record_ids; do + data="domain=${domain}&record_id=${record_id}" + uri="https://pddimp.yandex.ru/api2/admin/dns/del" + result="$(_post "${data}" "${uri}" | _normalizeJson)" + _debug "Result: $result" + + if ! _contains "$result" '"success":"ok"'; then + _info "Can't remove $subdomain from $domain." + fi + done +} + +#################### Private functions below ################################## + +_PDD_get_domain() { + subdomain_start=1 + while true; do + domain_start=$(_math $subdomain_start + 1) + domain=$(echo "$fulldomain" | cut -d . -f "$domain_start"-) + subdomain=$(echo "$fulldomain" | cut -d . -f -"$subdomain_start") + + _debug "Checking domain $domain" + if [ -z "$domain" ]; then + return 1 + fi + + uri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=$domain" + result="$(_get "${uri}" | _normalizeJson)" + _debug "Result: $result" + + if _contains "$result" '"success":"ok"'; then + return 0 + fi + subdomain_start=$(_math $subdomain_start + 1) + done +} + +_PDD_credentials() { + if [ -z "${PDD_Token}" ]; then + PDD_Token="" + _err "You need to export PDD_Token=xxxxxxxxxxxxxxxxx." + _err "You can get it at https://pddimp.yandex.ru/api2/admin/get_token." + return 1 + else + _saveaccountconf PDD_Token "${PDD_Token}" + fi + export _H1="PddToken: $PDD_Token" +} + +_PDD_get_record_ids() { + _debug "Check existing records for $subdomain" + + uri="https://pddimp.yandex.ru/api2/admin/dns/list?domain=${domain}" + result="$(_get "${uri}" | _normalizeJson)" + _debug "Result: $result" + + if ! _contains "$result" '"success":"ok"'; then + return 1 + fi + + record_ids=$(echo "$result" | _egrep_o "{[^{]*\"subdomain\":\"${subdomain}\"[^}]*}" | sed -n -e 's#.*"record_id": \([0-9]*\).*#\1#p') +} diff --git a/letsencrypt/dnsapi/dns_zilore.sh b/letsencrypt/dnsapi/dns_zilore.sh new file mode 100644 index 00000000..c7232b79 --- /dev/null +++ b/letsencrypt/dnsapi/dns_zilore.sh @@ -0,0 +1,139 @@ +#!/bin/bash + +Zilore_API="https://api.zilore.com/dns/v1" +# Zilore_Key="YOUR-ZILORE-API-KEY" + +######## Public functions ##################### + +dns_zilore_add() { + fulldomain=$1 + txtvalue=$2 + + _info "Using Zilore" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + Zilore_Key="${Zilore_Key:-$(_readaccountconf_mutable Zilore_Key)}" + if [ -z "$Zilore_Key" ]; then + Zilore_Key="" + _err "Please define Zilore API key" + return 1 + fi + _saveaccountconf_mutable Zilore_Key "$Zilore_Key" + + if ! _get_root "$fulldomain"; then + _err "Unable to determine root domain" + return 1 + else + _debug _domain "$_domain" + fi + + if _zilore_rest POST "domains/$_domain/records?record_type=TXT&record_ttl=600&record_name=$fulldomain&record_value=\"$txtvalue\""; then + if _contains "$response" '"added"' >/dev/null; then + _info "Added TXT record, waiting for validation" + return 0 + else + _debug response "$response" + _err "Error while adding DNS records" + return 1 + fi + fi + + return 1 +} + +dns_zilore_rm() { + fulldomain=$1 + txtvalue=$2 + + _info "Using Zilore" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + + Zilore_Key="${Zilore_Key:-$(_readaccountconf_mutable Zilore_Key)}" + if [ -z "$Zilore_Key" ]; then + Zilore_Key="" + _err "Please define Zilore API key" + return 1 + fi + _saveaccountconf_mutable Zilore_Key "$Zilore_Key" + + if ! _get_root "$fulldomain"; then + _err "Unable to determine root domain" + return 1 + else + _debug _domain "$_domain" + fi + + _debug "Getting TXT records" + _zilore_rest GET "domains/${_domain}/records?search_text=$txtvalue&search_record_type=TXT" + _debug response "$response" + + if ! _contains "$response" '"ok"' >/dev/null; then + _err "Error while getting records list" + return 1 + else + _record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[^\"]+\"" | cut -d : -f 2 | tr -d \" | _head_n 1) + if [ -z "$_record_id" ]; then + _err "Cannot determine _record_id" + return 1 + else + _debug _record_id "$_record_id" + fi + if ! _zilore_rest DELETE "domains/${_domain}/records?record_id=$_record_id"; then + _err "Error while deleting chosen record" + return 1 + fi + _contains "$response" '"ok"' + fi +} + +#################### Private functions below ################################## + +_get_root() { + domain=$1 + i=2 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + #not valid + return 1 + fi + + if ! _zilore_rest GET "domains?search_text=$h"; then + return 1 + fi + + if _contains "$response" "\"$h\"" >/dev/null; then + _domain=$h + return 0 + else + _debug "$h not found" + fi + i=$(_math "$i" + 1) + done + return 1 +} + +_zilore_rest() { + method=$1 + param=$2 + data=$3 + + export _H1="X-Auth-Key: $Zilore_Key" + + if [ "$method" != "GET" ]; then + response="$(_post "$data" "$Zilore_API/$param" "" "$method")" + else + response="$(_get "$Zilore_API/$param")" + fi + + if [ "$?" != "0" ]; then + _err "error $param" + return 1 + fi + + _debug2 response "$response" + return 0 +} diff --git a/letsencrypt/dnsapi/dns_zone.sh b/letsencrypt/dnsapi/dns_zone.sh new file mode 100755 index 00000000..f27e4921 --- /dev/null +++ b/letsencrypt/dnsapi/dns_zone.sh @@ -0,0 +1,149 @@ +#!/bin/bash + +# Zone.ee dns API +# https://help.zone.eu/kb/zoneid-api-v2/ +# required ZONE_Username and ZONE_Key + +ZONE_Api="https://api.zone.eu/v2" +######## Public functions ##################### + +#Usage: dns_zone_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_zone_add() { + fulldomain=$1 + txtvalue=$2 + _info "Using zone.ee dns api" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + ZONE_Username="${ZONE_Username:-$(_readaccountconf_mutable ZONE_Username)}" + ZONE_Key="${ZONE_Key:-$(_readaccountconf_mutable ZONE_Key)}" + if [ -z "$ZONE_Username" ] || [ -z "$ZONE_Key" ]; then + ZONE_Username="" + ZONE_Key="" + _err "Zone api key and username must be present." + return 1 + fi + _saveaccountconf_mutable ZONE_Username "$ZONE_Username" + _saveaccountconf_mutable ZONE_Key "$ZONE_Key" + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug "Adding txt record" + + if _zone_rest POST "dns/${_domain}/txt" "{\"name\": \"$fulldomain\", \"destination\": \"$txtvalue\"}"; then + if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then + _info "Added, OK" + return 0 + else + _err "Adding txt record error." + return 1 + fi + else + _err "Adding txt record error." + fi +} + +#Usage: fulldomain txtvalue +#Remove the txt record after validation. +dns_zone_rm() { + fulldomain=$1 + txtvalue=$2 + _info "Using zone.ee dns api" + _debug fulldomain "$fulldomain" + _debug txtvalue "$txtvalue" + ZONE_Username="${ZONE_Username:-$(_readaccountconf_mutable ZONE_Username)}" + ZONE_Key="${ZONE_Key:-$(_readaccountconf_mutable ZONE_Key)}" + if [ -z "$ZONE_Username" ] || [ -z "$ZONE_Key" ]; then + ZONE_Username="" + ZONE_Key="" + _err "Zone api key and username must be present." + return 1 + fi + _saveaccountconf_mutable ZONE_Username "$ZONE_Username" + _saveaccountconf_mutable ZONE_Key "$ZONE_Key" + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + + _debug "Getting txt records" + _debug _domain "$_domain" + + _zone_rest GET "dns/${_domain}/txt" + + if printf "%s" "$response" | grep \"error\" >/dev/null; then + _err "Error" + return 1 + fi + + count=$(printf "%s\n" "$response" | _egrep_o "\"name\":\"$fulldomain\"" | wc -l) + _debug count "$count" + if [ "$count" = "0" ]; then + _info "Nothing to remove." + else + record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\"[^\"]*\",\"resource_url\":\"[^\"]*\",\"name\":\"$fulldomain\"," | cut -d : -f2 | cut -d , -f1 | tr -d \" | _head_n 1) + if [ -z "$record_id" ]; then + _err "No id found to remove." + return 1 + fi + if ! _zone_rest DELETE "dns/${_domain}/txt/$record_id"; then + _err "Record deleting error." + return 1 + fi + _info "Record deleted" + return 0 + fi + +} + +#################### Private functions below ################################## + +_zone_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + + realm="$(printf "%s" "$ZONE_Username:$ZONE_Key" | _base64)" + + export _H1="Authorization: Basic $realm" + export _H2="Content-Type: application/json" + + if [ "$m" != "GET" ]; then + _debug data "$data" + response="$(_post "$data" "$ZONE_Api/$ep" "" "$m")" + else + response="$(_get "$ZONE_Api/$ep")" + fi + + if [ "$?" != "0" ]; then + _err "error $ep" + return 1 + fi + _debug2 response "$response" + return 0 +} + +_get_root() { + domain=$1 + i=2 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + if [ -z "$h" ]; then + return 1 + fi + if ! _zone_rest GET "dns/$h"; then + return 1 + fi + if _contains "$response" "\"identificator\":\"$h\"" >/dev/null; then + _domain=$h + return 0 + fi + i=$(_math "$i" + 1) + done + return 0 +} diff --git a/letsencrypt/dnsapi/dns_zonomi.sh b/letsencrypt/dnsapi/dns_zonomi.sh new file mode 100644 index 00000000..d15bac9a --- /dev/null +++ b/letsencrypt/dnsapi/dns_zonomi.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +# +#ZM_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" +# +#https://zonomi.com dns api + +ZM_Api="https://zonomi.com/app/dns/dyndns.jsp" + +######## Public functions ##################### + +#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" +dns_zonomi_add() { + fulldomain=$1 + txtvalue=$2 + + ZM_Key="${ZM_Key:-$(_readaccountconf_mutable ZM_Key)}" + + if [ -z "$ZM_Key" ]; then + ZM_Key="" + _err "You don't specify zonomi api key yet." + _err "Please create your key and try again." + return 1 + fi + + #save the api key to the account conf file. + _saveaccountconf_mutable ZM_Key "$ZM_Key" + + _info "Get existing txt records for $fulldomain" + if ! _zm_request "action=QUERY&name=$fulldomain"; then + _err "error" + return 1 + fi + + if _contains "$response" "' | tr "<" "\n" | grep record | grep 'type="TXT"' | cut -d '"' -f 6); do + _debug2 t "$t" + _qstr="$_qstr&action[$_qindex]=SET&type[$_qindex]=TXT&name[$_qindex]=$fulldomain&value[$_qindex]=$t" + _qindex="$(_math "$_qindex" + 1)" + done + _zm_request "$_qstr" + else + _debug "Just add record" + _zm_request "action=SET&type=TXT&name=$fulldomain&value=$txtvalue" + fi + +} + +#fulldomain txtvalue +dns_zonomi_rm() { + fulldomain=$1 + txtvalue=$2 + + ZM_Key="${ZM_Key:-$(_readaccountconf_mutable ZM_Key)}" + if [ -z "$ZM_Key" ]; then + ZM_Key="" + _err "You don't specify zonomi api key yet." + _err "Please create your key and try again." + return 1 + fi + + _zm_request "action=DELETE&type=TXT&name=$fulldomain" + +} + +#################### Private functions below ################################## +#qstr +_zm_request() { + qstr="$1" + + _debug2 "qstr" "$qstr" + + _zm_url="$ZM_Api?api_key=$ZM_Key&$qstr" + _debug2 "_zm_url" "$_zm_url" + response="$(_get "$_zm_url")" + + if [ "$?" != "0" ]; then + return 1 + fi + _debug2 response "$response" + _contains "$response" "OK:" +} diff --git a/letsencrypt/ghost.realm.local/ghost.realm.local.conf b/letsencrypt/ghost.realm.local/ghost.realm.local.conf new file mode 100644 index 00000000..7bbd49e2 --- /dev/null +++ b/letsencrypt/ghost.realm.local/ghost.realm.local.conf @@ -0,0 +1,8 @@ +Le_Domain='ghost.realm.local' +Le_Alt='no' +Le_Webroot='/home/pi/ghost/system/nginx-root' +Le_PreHook='' +Le_PostHook='' +Le_RenewHook='' +Le_API='https://acme-v02.api.letsencrypt.org/directory' +Le_Keylength='' diff --git a/letsencrypt/ghost.realm.local/ghost.realm.local.csr b/letsencrypt/ghost.realm.local/ghost.realm.local.csr new file mode 100644 index 00000000..cd859254 --- /dev/null +++ b/letsencrypt/ghost.realm.local/ghost.realm.local.csr @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICnTCCAYUCAQAwHDEaMBgGA1UEAwwRZ2hvc3QucmVhbG0ubG9jYWwwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDzgbmwS8BJnqFziRl1bmyrsHX+G0R6 +YbEhu/Teh8AGBNQcauf/Prt1qZl6y62nHzSApE+oEYjHYtNDXSX1qTr2fyb+lM3P +6H/qVIagm4dJumc4XyrfFaI2l9fuQR2ClQ93K4/X70iB1bvsZAPdXoa7MoB1WjUF +B6PyH/dqr63PLne4Ko5N/yHRTWxXIXo7lRTYFQszGnAbAIxUPnmPZsWWisrCq3Cb ++9Od7dsUDI3L+JP74HiTS/pepOP8f/IeNf+Or9jwygeMDnFNBK/N/uQM68AlqNGA +yumPvtA1ady3Gmto+Wk/mSH0Vcc4kvhMv+yxX+meW7mGjAL1diCcJGJXAgMBAAGg +PDA6BgkqhkiG9w0BCQ4xLTArMAsGA1UdDwQEAwIF4DAcBgNVHREEFTATghFnaG9z +dC5yZWFsbS5sb2NhbDANBgkqhkiG9w0BAQsFAAOCAQEAC/khu0HxfO4zygcG5c5Q +20gzTgCwVCdLjydXeZ4ctRZMbvKlpsMK7bR/CHmM5PdyYqVJ4ygMkE3Aai4fwzDU +KmvviF+5ChvdDl+zLazHPAAoZa6I1eG1CPTj+uXgn09WuVuQNSCfShT4TKc+6/oW +kVi5jBd7YPwkKs6uZnR2Tv2S6S6HtyWJOzebLBPaFyHghF3VCnHJ7Hw7Wqw4YT6I +SNn4CPKs6gR66TPo1Hh2G6ZJ/aRRpHVLRWLu+rLgnITas827JhPKVUitHlH1PocS +SKG8QihWtoaA2YBSxH3+pIBH1ao2/Sl97CdXwwywTJ5GMHPz5PebN/B7UoSW9Gup +Yw== +-----END CERTIFICATE REQUEST----- diff --git a/letsencrypt/ghost.realm.local/ghost.realm.local.csr.conf b/letsencrypt/ghost.realm.local/ghost.realm.local.csr.conf new file mode 100644 index 00000000..deba00ac --- /dev/null +++ b/letsencrypt/ghost.realm.local/ghost.realm.local.csr.conf @@ -0,0 +1,8 @@ +[ req_distinguished_name ] +[ req ] +distinguished_name = req_distinguished_name +req_extensions = v3_req +[ v3_req ] + +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +subjectAltName=DNS:ghost.realm.local \ No newline at end of file diff --git a/letsencrypt/ghost.realm.local/ghost.realm.local.key b/letsencrypt/ghost.realm.local/ghost.realm.local.key new file mode 100644 index 00000000..417b7cd8 --- /dev/null +++ b/letsencrypt/ghost.realm.local/ghost.realm.local.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA84G5sEvASZ6hc4kZdW5sq7B1/htEemGxIbv03ofABgTUHGrn +/z67damZesutpx80gKRPqBGIx2LTQ10l9ak69n8m/pTNz+h/6lSGoJuHSbpnOF8q +3xWiNpfX7kEdgpUPdyuP1+9IgdW77GQD3V6GuzKAdVo1BQej8h/3aq+tzy53uCqO +Tf8h0U1sVyF6O5UU2BULMxpwGwCMVD55j2bFlorKwqtwm/vTne3bFAyNy/iT++B4 +k0v6XqTj/H/yHjX/jq/Y8MoHjA5xTQSvzf7kDOvAJajRgMrpj77QNWnctxpraPlp +P5kh9FXHOJL4TL/ssV/pnlu5howC9XYgnCRiVwIDAQABAoIBADLwunXFAw7jnoba +8XZ9iUJJggWMksC/WxzhgxJid6tKq0zemHXvG6w7tJ3ZqhRCFOusc/WG5YRAik2X +WO+RXYJfizrKyltqGghdcmR65MxpsFo8nm1Yyzx8e3GeMZw1rqyRcmAL8LEok02a +hqxyr+DNac4i9uB8frGSOmIZKlUizPYBTj6krqShCtVJpT3MXVqlqJ0ic//j+AjK +CSTBE/M3gkW4jJSbNgfBCKyADvVqQimD+i2jTH4cxUTjdhcSBV1WE/V0C/rJ6GLQ +9kOXbQ4hvAbBRwa4W+Tnh/ACPOUVDOTZf6VGKUx6BvKhuxtRc1yRxCAepL6dgJzJ +rmeO8PECgYEA+pFydfGPnSyzzx2yHqLnxGFWPZg4dbiaxV/PyLuuaGMEIFdAE5Hh +1dQsfkHQ/Uai2+a4FmRgsz/u/eTHztUqpNvYwuLNyt2HiAon93P8hcGlZS6yDknj +pj0wXlZhFzHkXbOhW9PiZ+iCffzLALNYqh0Z9x4ti3cnraH3t1cXqhsCgYEA+MkX +GJ+aGtHxWP0mtj48GZ9bl12BRUrCPqsykQgcb36sniXBcCN2chmKrndSPjjnfAk9 ++YMt3IxeheX2TIqoTqXt4ThfLK63QELy9SOQ5vKaYO5GiRsOM8z77LUhQMWFMCRw +IXXpngaI8WLBsrcoK/KffNQnqm7Nxc3LDui1LHUCgYEAtrwqII/Zr8OxIoRCqYse +wZ5HGcaQrnHCFd2JGJifWiuUD83xwhPrAlmpVS7ErmG8VekOKe5sg21F603U1iep +4O8gRwjHEoK62+CkQxgIere92mvSmQ8UAeGwC6ytRBAzvo5JSEHfZO4xdJZOqiUh +rXZpwEn25zYv7rYnhULz1C8CgYEAuAFDK9sfx6ZvsznJYBE3slvDCnkGG5HniSJm +DA7LuUsfsPiL0bzo5gsuH0vxcEP2Mi9Dvz/es7i+UJp9SK9lPIZNIr7m5c1zi/v4 +ZocfrTDSLc8OLGnuXzHFQpXVOmrcz3aj2Ju1ZkO/FYnNabk95QNWIqVnkQ7S8vH6 +tdQ36+ECgYAI7m191z1sT5hgxhZjf+TaqFxREZtnmtVmt3q7HC+hVINtHP+Bw/S9 +p6bgmImd41EXup3P4OnDUxDAXw41Adps3WX4P3eBt1MByP5s6jH4vtvLQhaQzHkR +uBRm10OxJuz2LO12fghOHNB/TG/0AiZxFqZCKw9eLfcNyNchmfzSlg== +-----END RSA PRIVATE KEY----- diff --git a/letsencrypt/http.header b/letsencrypt/http.header new file mode 100644 index 00000000..42f1077a --- /dev/null +++ b/letsencrypt/http.header @@ -0,0 +1,10 @@ +HTTP/2 400 +server: nginx +date: Wed, 20 Jan 2021 12:47:56 GMT +content-type: application/problem+json +content-length: 219 +boulder-requester: 110150126 +cache-control: public, max-age=0, no-cache +link: ;rel="index" +replay-nonce: 0004QJfxCF8Fchp7uXO_dbf5eAgaWVkgxWef7t_dVm05fGo + diff --git a/letsencrypt/notify/cqhttp.sh b/letsencrypt/notify/cqhttp.sh new file mode 100644 index 00000000..1c5d4b85 --- /dev/null +++ b/letsencrypt/notify/cqhttp.sh @@ -0,0 +1,64 @@ +#!/bin/bash + +#Support for CQHTTP api. Push notification on CoolQ +#CQHTTP_TOKEN="" Recommended to be not empty, QQ application token +#CQHTTP_USER="" Required, QQ receiver ID +#CQHTTP_APIROOT="" Required, CQHTTP Server URL (without slash suffix) +#CQHTTP_CUSTOM_MSGHEAD="" Optional, custom message header + +CQHTTP_APIPATH="/send_private_msg" + +cqhttp_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_statusCode" "$_statusCode" + + CQHTTP_TOKEN="${CQHTTP_TOKEN:-$(_readaccountconf_mutable CQHTTP_TOKEN)}" + if [ -z "$CQHTTP_TOKEN" ]; then + CQHTTP_TOKEN="" + _info "You didn't specify a CQHTTP application token yet, which is unsafe. Assuming it to be empty." + else + _saveaccountconf_mutable CQHTTP_TOKEN "$CQHTTP_TOKEN" + fi + + CQHTTP_USER="${CQHTTP_USER:-$(_readaccountconf_mutable CQHTTP_USER)}" + if [ -z "$CQHTTP_USER" ]; then + CQHTTP_USER="" + _err "You didn't specify a QQ user yet." + return 1 + fi + _saveaccountconf_mutable CQHTTP_USER "$CQHTTP_USER" + + CQHTTP_APIROOT="${CQHTTP_APIROOT:-$(_readaccountconf_mutable CQHTTP_APIROOT)}" + if [ -z "$CQHTTP_APIROOT" ]; then + CQHTTP_APIROOT="" + _err "You didn't specify the API root yet." + return 1 + fi + _saveaccountconf_mutable CQHTTP_APIROOT "$CQHTTP_APIROOT" + + CQHTTP_CUSTOM_MSGHEAD="${CQHTTP_CUSTOM_MSGHEAD:-$(_readaccountconf_mutable CQHTTP_CUSTOM_MSGHEAD)}" + if [ -z "$CQHTTP_CUSTOM_MSGHEAD" ]; then + CQHTTP_CUSTOM_MSGHEAD="A message from acme.sh:" + else + _saveaccountconf_mutable CQHTTP_CUSTOM_MSGHEAD "$CQHTTP_CUSTOM_MSGHEAD" + fi + + _access_token="$(printf "%s" "$CQHTTP_TOKEN" | _url_encode)" + _user_id="$(printf "%s" "$CQHTTP_USER" | _url_encode)" + _message="$(printf "$CQHTTP_CUSTOM_MSGHEAD %s\\n%s" "$_subject" "$_content" | _url_encode)" + + _finalUrl="$CQHTTP_APIROOT$CQHTTP_APIPATH?access_token=$_access_token&user_id=$_user_id&message=$_message" + response="$(_get "$_finalUrl")" + + if [ "$?" = "0" ] && _contains "$response" "\"retcode\":0,\"status\":\"ok\""; then + _info "QQ send success." + return 0 + fi + + _err "QQ send error." + _debug "URL" "$_finalUrl" + _debug "Response" "$response" + return 1 +} diff --git a/letsencrypt/notify/dingtalk.sh b/letsencrypt/notify/dingtalk.sh new file mode 100644 index 00000000..bc96a0e0 --- /dev/null +++ b/letsencrypt/notify/dingtalk.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +#Support dingtalk webhooks api + +#DINGTALK_WEBHOOK="xxxx" + +#optional +#DINGTALK_KEYWORD="yyyy" + +#DINGTALK_SIGNING_KEY="SEC08ffdbd403cbc3fc8a65xxxxxxxxxxxxxxxxxxxx" + +# subject content statusCode +dingtalk_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_subject" "$_subject" + _debug "_content" "$_content" + _debug "_statusCode" "$_statusCode" + + DINGTALK_WEBHOOK="${DINGTALK_WEBHOOK:-$(_readaccountconf_mutable DINGTALK_WEBHOOK)}" + if [ -z "$DINGTALK_WEBHOOK" ]; then + DINGTALK_WEBHOOK="" + _err "You didn't specify a dingtalk webhooks DINGTALK_WEBHOOK yet." + _err "You can get yours from https://dingtalk.com" + return 1 + fi + _saveaccountconf_mutable DINGTALK_WEBHOOK "$DINGTALK_WEBHOOK" + + DINGTALK_KEYWORD="${DINGTALK_KEYWORD:-$(_readaccountconf_mutable DINGTALK_KEYWORD)}" + if [ "$DINGTALK_KEYWORD" ]; then + _saveaccountconf_mutable DINGTALK_KEYWORD "$DINGTALK_KEYWORD" + fi + + # DINGTALK_SIGNING_KEY="${DINGTALK_SIGNING_KEY:-$(_readaccountconf_mutable DINGTALK_SIGNING_KEY)}" + # if [ -z "$DINGTALK_SIGNING_KEY" ]; then + # DINGTALK_SIGNING_KEY="value1" + # _info "The DINGTALK_SIGNING_KEY is not set, so use the default value1 as key." + # elif ! _hasfield "$_IFTTT_AVAIL_MSG_KEYS" "$DINGTALK_SIGNING_KEY"; then + # _err "The DINGTALK_SIGNING_KEY \"$DINGTALK_SIGNING_KEY\" is not available, should be one of $_IFTTT_AVAIL_MSG_KEYS" + # DINGTALK_SIGNING_KEY="" + # return 1 + # else + # _saveaccountconf_mutable DINGTALK_SIGNING_KEY "$DINGTALK_SIGNING_KEY" + # fi + + # if [ "$DINGTALK_SIGNING_KEY" = "$IFTTT_CONTENT_KEY" ]; then + # DINGTALK_SIGNING_KEY="" + # IFTTT_CONTENT_KEY="" + # _err "The DINGTALK_SIGNING_KEY must not be same as IFTTT_CONTENT_KEY." + # return 1 + # fi + + _content=$(echo "$_content" | _json_encode) + _subject=$(echo "$_subject" | _json_encode) + _data="{\"msgtype\": \"text\", \"text\": {\"content\": \"[$DINGTALK_KEYWORD]\n$_subject\n$_content\"}}" + + response="$(_post "$_data" "$DINGTALK_WEBHOOK" "" "POST" "application/json")" + + if [ "$?" = "0" ] && _contains "$response" "errmsg\":\"ok"; then + _info "dingtalk webhooks event fired success." + return 0 + fi + + _err "dingtalk webhooks event fired error." + _err "$response" + return 1 +} diff --git a/letsencrypt/notify/ifttt.sh b/letsencrypt/notify/ifttt.sh new file mode 100644 index 00000000..44515bea --- /dev/null +++ b/letsencrypt/notify/ifttt.sh @@ -0,0 +1,86 @@ +#!/bin/bash + +#Support ifttt.com webhooks api + +#IFTTT_API_KEY="xxxx" +#IFTTT_EVENT_NAME="yyyy" + +#IFTTT_SUBJECT_KEY="value1|value2|value3" #optional, use "value1" as default +#IFTTT_CONTENT_KEY="value1|value2|value3" #optional, use "value2" as default + +_IFTTT_AVAIL_MSG_KEYS="value1,value2,value3" + +# subject content statusCode +ifttt_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_subject" "$_subject" + _debug "_content" "$_content" + _debug "_statusCode" "$_statusCode" + + IFTTT_API_KEY="${IFTTT_API_KEY:-$(_readaccountconf_mutable IFTTT_API_KEY)}" + if [ -z "$IFTTT_API_KEY" ]; then + IFTTT_API_KEY="" + _err "You didn't specify a ifttt webhooks api key IFTTT_API_KEY yet." + _err "You can get yours from https://ifttt.com" + return 1 + fi + _saveaccountconf_mutable IFTTT_API_KEY "$IFTTT_API_KEY" + + IFTTT_EVENT_NAME="${IFTTT_EVENT_NAME:-$(_readaccountconf_mutable IFTTT_EVENT_NAME)}" + if [ -z "$IFTTT_EVENT_NAME" ]; then + IFTTT_EVENT_NAME="" + _err "You didn't specify a ifttt webhooks event name IFTTT_EVENT_NAME yet." + return 1 + fi + _saveaccountconf_mutable IFTTT_EVENT_NAME "$IFTTT_EVENT_NAME" + + IFTTT_SUBJECT_KEY="${IFTTT_SUBJECT_KEY:-$(_readaccountconf_mutable IFTTT_SUBJECT_KEY)}" + if [ -z "$IFTTT_SUBJECT_KEY" ]; then + IFTTT_SUBJECT_KEY="value1" + _info "The IFTTT_SUBJECT_KEY is not set, so use the default value1 as key." + elif ! _hasfield "$_IFTTT_AVAIL_MSG_KEYS" "$IFTTT_SUBJECT_KEY"; then + _err "The IFTTT_SUBJECT_KEY \"$IFTTT_SUBJECT_KEY\" is not available, should be one of $_IFTTT_AVAIL_MSG_KEYS" + IFTTT_SUBJECT_KEY="" + return 1 + else + _saveaccountconf_mutable IFTTT_SUBJECT_KEY "$IFTTT_SUBJECT_KEY" + fi + + IFTTT_CONTENT_KEY="${IFTTT_CONTENT_KEY:-$(_readaccountconf_mutable IFTTT_CONTENT_KEY)}" + if [ -z "$IFTTT_CONTENT_KEY" ]; then + IFTTT_CONTENT_KEY="value2" + _info "The IFTTT_CONTENT_KEY is not set, so use the default value2 as key." + elif ! _hasfield "$_IFTTT_AVAIL_MSG_KEYS" "$IFTTT_CONTENT_KEY"; then + _err "The IFTTT_CONTENT_KEY \"$IFTTT_CONTENT_KEY\" is not available, should be one of $_IFTTT_AVAIL_MSG_KEYS" + IFTTT_CONTENT_KEY="" + return 1 + else + _saveaccountconf_mutable IFTTT_CONTENT_KEY "$IFTTT_CONTENT_KEY" + fi + + if [ "$IFTTT_SUBJECT_KEY" = "$IFTTT_CONTENT_KEY" ]; then + IFTTT_SUBJECT_KEY="" + IFTTT_CONTENT_KEY="" + _err "The IFTTT_SUBJECT_KEY must not be same as IFTTT_CONTENT_KEY." + return 1 + fi + + IFTTT_API_URL="https://maker.ifttt.com/trigger/$IFTTT_EVENT_NAME/with/key/$IFTTT_API_KEY" + + _content=$(echo "$_content" | _json_encode) + _subject=$(echo "$_subject" | _json_encode) + _data="{\"$IFTTT_SUBJECT_KEY\": \"$_subject\", \"$IFTTT_CONTENT_KEY\": \"$_content\"}" + + response="$(_post "$_data" "$IFTTT_API_URL" "" "POST" "application/json")" + + if [ "$?" = "0" ] && _contains "$response" "Congratulations"; then + _info "IFTTT webhooks event fired success." + return 0 + fi + + _err "IFTTT webhooks event fired error." + _err "$response" + return 1 +} diff --git a/letsencrypt/notify/mail.sh b/letsencrypt/notify/mail.sh new file mode 100644 index 00000000..ae922aa9 --- /dev/null +++ b/letsencrypt/notify/mail.sh @@ -0,0 +1,143 @@ +#!/bin/bash + +#Support local mail app + +#MAIL_BIN="sendmail" +#MAIL_FROM="yyyy@gmail.com" +#MAIL_TO="yyyy@gmail.com" +#MAIL_NOVALIDATE="" +#MAIL_MSMTP_ACCOUNT="" + +mail_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_subject" "$_subject" + _debug "_content" "$_content" + _debug "_statusCode" "$_statusCode" + + MAIL_NOVALIDATE="${MAIL_NOVALIDATE:-$(_readaccountconf_mutable MAIL_NOVALIDATE)}" + if [ -n "$MAIL_NOVALIDATE" ]; then + _saveaccountconf_mutable MAIL_NOVALIDATE 1 + else + _clearaccountconf "MAIL_NOVALIDATE" + fi + + MAIL_BIN="${MAIL_BIN:-$(_readaccountconf_mutable MAIL_BIN)}" + if [ -n "$MAIL_BIN" ] && ! _exists "$MAIL_BIN"; then + _err "It seems that the command $MAIL_BIN is not in path." + return 1 + fi + _MAIL_BIN=$(_mail_bin) + if [ -n "$MAIL_BIN" ]; then + _saveaccountconf_mutable MAIL_BIN "$MAIL_BIN" + else + _clearaccountconf "MAIL_BIN" + fi + + MAIL_FROM="${MAIL_FROM:-$(_readaccountconf_mutable MAIL_FROM)}" + if [ -n "$MAIL_FROM" ]; then + if ! _mail_valid "$MAIL_FROM"; then + _err "It seems that the MAIL_FROM=$MAIL_FROM is not a valid email address." + return 1 + fi + + _saveaccountconf_mutable MAIL_FROM "$MAIL_FROM" + fi + + MAIL_TO="${MAIL_TO:-$(_readaccountconf_mutable MAIL_TO)}" + if [ -n "$MAIL_TO" ]; then + if ! _mail_valid "$MAIL_TO"; then + _err "It seems that the MAIL_TO=$MAIL_TO is not a valid email address." + return 1 + fi + + _saveaccountconf_mutable MAIL_TO "$MAIL_TO" + else + MAIL_TO="$(_readaccountconf ACCOUNT_EMAIL)" + if [ -z "$MAIL_TO" ]; then + _err "It seems that account email is empty." + return 1 + fi + fi + + contenttype="text/plain; charset=utf-8" + subject="=?UTF-8?B?$(echo "$_subject" | _base64)?=" + result=$({ _mail_body | eval "$(_mail_cmnd)"; } 2>&1) + + # shellcheck disable=SC2181 + if [ $? -ne 0 ]; then + _debug "mail send error." + _err "$result" + return 1 + fi + + _debug "mail send success." + return 0 +} + +_mail_bin() { + _MAIL_BIN="" + + for b in "$MAIL_BIN" sendmail ssmtp mutt mail msmtp; do + if _exists "$b"; then + _MAIL_BIN="$b" + break + fi + done + + if [ -z "$_MAIL_BIN" ]; then + _err "Please install sendmail, ssmtp, mutt, mail or msmtp first." + return 1 + fi + + echo "$_MAIL_BIN" +} + +_mail_cmnd() { + _MAIL_ARGS="" + + case $(basename "$_MAIL_BIN") in + sendmail) + if [ -n "$MAIL_FROM" ]; then + _MAIL_ARGS="-f '$MAIL_FROM'" + fi + ;; + mutt | mail) + _MAIL_ARGS="-s '$_subject'" + ;; + msmtp) + if [ -n "$MAIL_FROM" ]; then + _MAIL_ARGS="-f '$MAIL_FROM'" + fi + + if [ -n "$MAIL_MSMTP_ACCOUNT" ]; then + _MAIL_ARGS="$_MAIL_ARGS -a '$MAIL_MSMTP_ACCOUNT'" + fi + ;; + *) ;; + esac + + echo "'$_MAIL_BIN' $_MAIL_ARGS '$MAIL_TO'" +} + +_mail_body() { + case $(basename "$_MAIL_BIN") in + sendmail | ssmtp | msmtp) + if [ -n "$MAIL_FROM" ]; then + echo "From: $MAIL_FROM" + fi + + echo "To: $MAIL_TO" + echo "Subject: $subject" + echo "Content-Type: $contenttype" + echo + ;; + esac + + echo "$_content" +} + +_mail_valid() { + [ -n "$MAIL_NOVALIDATE" ] || _contains "$1" "@" +} diff --git a/letsencrypt/notify/mailgun.sh b/letsencrypt/notify/mailgun.sh new file mode 100644 index 00000000..dc2af9ef --- /dev/null +++ b/letsencrypt/notify/mailgun.sh @@ -0,0 +1,131 @@ +#!/bin/bash + +#Support mailgun.com api + +#MAILGUN_API_KEY="xxxx" +#MAILGUN_TO="yyyy@gmail.com" + +#MAILGUN_REGION="us|eu" #optional, use "us" as default +#MAILGUN_API_DOMAIN="xxxxxx.com" #optional, use the default sandbox domain +#MAILGUN_FROM="xxx@xxxxx.com" #optional, use the default sandbox account + +_MAILGUN_BASE_US="https://api.mailgun.net/v3" +_MAILGUN_BASE_EU="https://api.eu.mailgun.net/v3" + +_MAILGUN_BASE="$_MAILGUN_BASE_US" + +# subject content statusCode +mailgun_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_statusCode" "$_statusCode" + + MAILGUN_API_KEY="${MAILGUN_API_KEY:-$(_readaccountconf_mutable MAILGUN_API_KEY)}" + if [ -z "$MAILGUN_API_KEY" ]; then + MAILGUN_API_KEY="" + _err "You didn't specify a mailgun api key MAILGUN_API_KEY yet ." + _err "You can get yours from here https://mailgun.com" + return 1 + fi + _saveaccountconf_mutable MAILGUN_API_KEY "$MAILGUN_API_KEY" + + MAILGUN_REGION="${MAILGUN_REGION:-$(_readaccountconf_mutable MAILGUN_REGION)}" + if [ -z "$MAILGUN_REGION" ]; then + MAILGUN_REGION="" + _debug "The MAILGUN_REGION is not set, so use the default us region." + _MAILGUN_BASE="$_MAILGUN_BASE_US" + else + MAILGUN_REGION="$(echo "$MAILGUN_REGION" | _lower_case)" + _saveaccountconf_mutable MAILGUN_REGION "$MAILGUN_REGION" + if [ "$MAILGUN_REGION" = "us" ]; then + _MAILGUN_BASE="$_MAILGUN_BASE_US" + else + _MAILGUN_BASE="$_MAILGUN_BASE_EU" + fi + fi + _debug _MAILGUN_BASE "$_MAILGUN_BASE" + MAILGUN_TO="${MAILGUN_TO:-$(_readaccountconf_mutable MAILGUN_TO)}" + if [ -z "$MAILGUN_TO" ]; then + MAILGUN_TO="" + _err "You didn't specify an email to MAILGUN_TO receive messages." + return 1 + fi + _saveaccountconf_mutable MAILGUN_TO "$MAILGUN_TO" + + MAILGUN_API_DOMAIN="${MAILGUN_API_DOMAIN:-$(_readaccountconf_mutable MAILGUN_API_DOMAIN)}" + if [ -z "$MAILGUN_API_DOMAIN" ]; then + _info "The MAILGUN_API_DOMAIN is not set, try to get the default sending sandbox domain for you." + if ! _mailgun_rest GET "/domains"; then + _err "Can not get sandbox domain." + return 1 + fi + _sendboxDomain="$(echo "$response" | _egrep_o '"name": *"sandbox.*.mailgun.org"' | cut -d : -f 2 | tr -d '" ')" + _debug _sendboxDomain "$_sendboxDomain" + MAILGUN_API_DOMAIN="$_sendboxDomain" + if [ -z "$MAILGUN_API_DOMAIN" ]; then + _err "Can not get sandbox domain for MAILGUN_API_DOMAIN" + return 1 + fi + + _info "$(__green "When using sandbox domain, you must verify your email first.")" + #todo: add recepient + fi + if [ -z "$MAILGUN_API_DOMAIN" ]; then + _err "Can not get MAILGUN_API_DOMAIN" + return 1 + fi + _saveaccountconf_mutable MAILGUN_API_DOMAIN "$MAILGUN_API_DOMAIN" + + MAILGUN_FROM="${MAILGUN_FROM:-$(_readaccountconf_mutable MAILGUN_FROM)}" + if [ -z "$MAILGUN_FROM" ]; then + MAILGUN_FROM="$PROJECT_NAME@$MAILGUN_API_DOMAIN" + _info "The MAILGUN_FROM is not set, so use the default value: $MAILGUN_FROM" + else + _debug MAILGUN_FROM "$MAILGUN_FROM" + _saveaccountconf_mutable MAILGUN_FROM "$MAILGUN_FROM" + fi + + #send from url + _msg="/$MAILGUN_API_DOMAIN/messages?from=$(printf "%s" "$MAILGUN_FROM" | _url_encode)&to=$(printf "%s" "$MAILGUN_TO" | _url_encode)&subject=$(printf "%s" "$_subject" | _url_encode)&text=$(printf "%s" "$_content" | _url_encode)" + _debug "_msg" "$_msg" + _mailgun_rest POST "$_msg" + if _contains "$response" "Queued. Thank you."; then + _debug "mailgun send success." + return 0 + else + _err "mailgun send error" + _err "$response" + return 1 + fi + +} + +# method uri data +_mailgun_rest() { + _method="$1" + _mguri="$2" + _mgdata="$3" + _debug _mguri "$_mguri" + _mgurl="$_MAILGUN_BASE$_mguri" + _debug _mgurl "$_mgurl" + + _auth="$(printf "%s" "api:$MAILGUN_API_KEY" | _base64)" + export _H1="Authorization: Basic $_auth" + export _H2="Content-Type: application/json" + + if [ "$_method" = "GET" ]; then + response="$(_get "$_mgurl")" + else + _debug _mgdata "$_mgdata" + response="$(_post "$_mgdata" "$_mgurl" "" "$_method")" + fi + if [ "$?" != "0" ]; then + _err "Error: $_mguri" + _err "$response" + return 1 + fi + _debug2 response "$response" + return 0 + +} diff --git a/letsencrypt/notify/pop.sh b/letsencrypt/notify/pop.sh new file mode 100644 index 00000000..ffc4f18e --- /dev/null +++ b/letsencrypt/notify/pop.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# support pop + +pop_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_subject" "$_subject" + _debug "_content" "$_content" + _debug "_statusCode" "$_statusCode" + + _err "Not implemented yet." + return 1 +} diff --git a/letsencrypt/notify/postmark.sh b/letsencrypt/notify/postmark.sh new file mode 100644 index 00000000..b14ba327 --- /dev/null +++ b/letsencrypt/notify/postmark.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +#Support postmarkapp.com API (https://postmarkapp.com/developer/user-guide/sending-email/sending-with-api) + +#POSTMARK_TOKEN="" +#POSTMARK_TO="xxxx@xxx.com" +#POSTMARK_FROM="xxxx@cccc.com" + +postmark_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_statusCode" "$_statusCode" + + POSTMARK_TOKEN="${POSTMARK_TOKEN:-$(_readaccountconf_mutable POSTMARK_TOKEN)}" + if [ -z "$POSTMARK_TOKEN" ]; then + POSTMARK_TOKEN="" + _err "You didn't specify a POSTMARK api token POSTMARK_TOKEN yet ." + _err "You can get yours from here https://account.postmarkapp.com" + return 1 + fi + _saveaccountconf_mutable POSTMARK_TOKEN "$POSTMARK_TOKEN" + + POSTMARK_TO="${POSTMARK_TO:-$(_readaccountconf_mutable POSTMARK_TO)}" + if [ -z "$POSTMARK_TO" ]; then + POSTMARK_TO="" + _err "You didn't specify an email to POSTMARK_TO receive messages." + return 1 + fi + _saveaccountconf_mutable POSTMARK_TO "$POSTMARK_TO" + + POSTMARK_FROM="${POSTMARK_FROM:-$(_readaccountconf_mutable POSTMARK_FROM)}" + if [ -z "$POSTMARK_FROM" ]; then + POSTMARK_FROM="" + _err "You didn't specify an email from POSTMARK_FROM receive messages." + return 1 + fi + _saveaccountconf_mutable POSTMARK_FROM "$POSTMARK_FROM" + + export _H1="Accept: application/json" + export _H2="Content-Type: application/json" + export _H3="X-Postmark-Server-Token: $POSTMARK_TOKEN" + + _content="$(echo "$_content" | _json_encode)" + _data="{\"To\": \"$POSTMARK_TO\", \"From\": \"$POSTMARK_FROM\", \"Subject\": \"$_subject\", \"TextBody\": \"$_content\"}" + if _post "$_data" "https://api.postmarkapp.com/email"; then + # shellcheck disable=SC2154 + _message=$(printf "%s\n" "$response" | _lower_case | _egrep_o "\"message\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | head -n 1) + if [ "$_message" = "ok" ]; then + _info "postmark send success." + return 0 + fi + fi + _err "postmark send error." + _err "$response" + return 1 + +} diff --git a/letsencrypt/notify/pushover.sh b/letsencrypt/notify/pushover.sh new file mode 100644 index 00000000..499a806d --- /dev/null +++ b/letsencrypt/notify/pushover.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +#Support for pushover.net's api. Push notification platform for multiple platforms +#PUSHOVER_TOKEN="" Required, pushover application token +#PUSHOVER_USER="" Required, pushover userkey +#PUSHOVER_DEVICE="" Optional, Specific device or devices by hostnames, joining multiples with a comma (such as device=iphone,nexus5) +#PUSHOVER_PRIORITY="" Optional, Lowest Priority (-2), Low Priority (-1), Normal Priority (0), High Priority (1) + +PUSHOVER_URI="https://api.pushover.net/1/messages.json" + +pushover_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_statusCode" "$_statusCode" + + PUSHOVER_TOKEN="${PUSHOVER_TOKEN:-$(_readaccountconf_mutable PUSHOVER_TOKEN)}" + if [ -z "$PUSHOVER_TOKEN" ]; then + PUSHOVER_TOKEN="" + _err "You didn't specify a PushOver application token yet." + return 1 + fi + _saveaccountconf_mutable PUSHOVER_TOKEN "$PUSHOVER_TOKEN" + + PUSHOVER_USER="${PUSHOVER_USER:-$(_readaccountconf_mutable PUSHOVER_USER)}" + if [ -z "$PUSHOVER_USER" ]; then + PUSHOVER_USER="" + _err "You didn't specify a PushOver UserKey yet." + return 1 + fi + _saveaccountconf_mutable PUSHOVER_USER "$PUSHOVER_USER" + + PUSHOVER_DEVICE="${PUSHOVER_DEVICE:-$(_readaccountconf_mutable PUSHOVER_DEVICE)}" + if [ "$PUSHOVER_DEVICE" ]; then + _saveaccountconf_mutable PUSHOVER_DEVICE "$PUSHOVER_DEVICE" + fi + + PUSHOVER_PRIORITY="${PUSHOVER_PRIORITY:-$(_readaccountconf_mutable PUSHOVER_PRIORITY)}" + if [ "$PUSHOVER_PRIORITY" ]; then + _saveaccountconf_mutable PUSHOVER_PRIORITY "$PUSHOVER_PRIORITY" + fi + + PUSHOVER_SOUND="${PUSHOVER_SOUND:-$(_readaccountconf_mutable PUSHOVER_SOUND)}" + if [ "$PUSHOVER_SOUND" ]; then + _saveaccountconf_mutable PUSHOVER_SOUND "$PUSHOVER_SOUND" + fi + + export _H1="Content-Type: application/json" + _content="$(printf "*%s*\n" "$_content" | _json_encode)" + _subject="$(printf "*%s*\n" "$_subject" | _json_encode)" + _data="{\"token\": \"$PUSHOVER_TOKEN\",\"user\": \"$PUSHOVER_USER\",\"title\": \"$_subject\",\"message\": \"$_content\",\"sound\": \"$PUSHOVER_SOUND\", \"device\": \"$PUSHOVER_DEVICE\", \"priority\": \"$PUSHOVER_PRIORITY\"}" + + response="$(_post "$_data" "$PUSHOVER_URI")" + + if [ "$?" = "0" ] && _contains "$response" "{\"status\":1"; then + _info "PUSHOVER send success." + return 0 + fi + + _err "PUSHOVER send error." + _err "$response" + return 1 +} diff --git a/letsencrypt/notify/sendgrid.sh b/letsencrypt/notify/sendgrid.sh new file mode 100644 index 00000000..317be732 --- /dev/null +++ b/letsencrypt/notify/sendgrid.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +#Support SENDGRID.com api + +#SENDGRID_API_KEY="" +#SENDGRID_TO="xxxx@xxx.com" +#SENDGRID_FROM="xxxx@cccc.com" + +sendgrid_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_statusCode" "$_statusCode" + + SENDGRID_API_KEY="${SENDGRID_API_KEY:-$(_readaccountconf_mutable SENDGRID_API_KEY)}" + if [ -z "$SENDGRID_API_KEY" ]; then + SENDGRID_API_KEY="" + _err "You didn't specify a sendgrid api key SENDGRID_API_KEY yet ." + _err "You can get yours from here https://sendgrid.com" + return 1 + fi + _saveaccountconf_mutable SENDGRID_API_KEY "$SENDGRID_API_KEY" + + SENDGRID_TO="${SENDGRID_TO:-$(_readaccountconf_mutable SENDGRID_TO)}" + if [ -z "$SENDGRID_TO" ]; then + SENDGRID_TO="" + _err "You didn't specify an email to SENDGRID_TO receive messages." + return 1 + fi + _saveaccountconf_mutable SENDGRID_TO "$SENDGRID_TO" + + SENDGRID_FROM="${SENDGRID_FROM:-$(_readaccountconf_mutable SENDGRID_FROM)}" + if [ -z "$SENDGRID_FROM" ]; then + SENDGRID_FROM="" + _err "You didn't specify an email to SENDGRID_FROM receive messages." + return 1 + fi + _saveaccountconf_mutable SENDGRID_FROM "$SENDGRID_FROM" + + export _H1="Authorization: Bearer $SENDGRID_API_KEY" + export _H2="Content-Type: application/json" + + _content="$(echo "$_content" | _json_encode)" + _data="{\"personalizations\": [{\"to\": [{\"email\": \"$SENDGRID_TO\"}]}],\"from\": {\"email\": \"$SENDGRID_FROM\"},\"subject\": \"$_subject\",\"content\": [{\"type\": \"text/plain\", \"value\": \"$_content\"}]}" + response="$(_post "$_data" "https://api.sendgrid.com/v3/mail/send")" + + if [ "$?" = "0" ] && [ -z "$response" ]; then + _info "sendgrid send sccess." + return 0 + fi + + _err "sendgrid send error." + _err "$response" + return 1 + +} diff --git a/letsencrypt/notify/slack.sh b/letsencrypt/notify/slack.sh new file mode 100644 index 00000000..f867b799 --- /dev/null +++ b/letsencrypt/notify/slack.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +#Support Slack webhooks + +#SLACK_WEBHOOK_URL="" +#SLACK_CHANNEL="" +#SLACK_USERNAME="" + +slack_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_statusCode" "$_statusCode" + + SLACK_WEBHOOK_URL="${SLACK_WEBHOOK_URL:-$(_readaccountconf_mutable SLACK_WEBHOOK_URL)}" + if [ -z "$SLACK_WEBHOOK_URL" ]; then + SLACK_WEBHOOK_URL="" + _err "You didn't specify a Slack webhook url SLACK_WEBHOOK_URL yet." + return 1 + fi + _saveaccountconf_mutable SLACK_WEBHOOK_URL "$SLACK_WEBHOOK_URL" + + SLACK_CHANNEL="${SLACK_CHANNEL:-$(_readaccountconf_mutable SLACK_CHANNEL)}" + if [ -n "$SLACK_CHANNEL" ]; then + _saveaccountconf_mutable SLACK_CHANNEL "$SLACK_CHANNEL" + fi + + SLACK_USERNAME="${SLACK_USERNAME:-$(_readaccountconf_mutable SLACK_USERNAME)}" + if [ -n "$SLACK_USERNAME" ]; then + _saveaccountconf_mutable SLACK_USERNAME "$SLACK_USERNAME" + fi + + export _H1="Content-Type: application/json" + + _content="$(printf "*%s*\n%s" "$_subject" "$_content" | _json_encode)" + _data="{\"text\": \"$_content\", " + if [ -n "$SLACK_CHANNEL" ]; then + _data="$_data\"channel\": \"$SLACK_CHANNEL\", " + fi + if [ -n "$SLACK_USERNAME" ]; then + _data="$_data\"username\": \"$SLACK_USERNAME\", " + fi + _data="$_data\"mrkdwn\": \"true\"}" + + if _post "$_data" "$SLACK_WEBHOOK_URL"; then + # shellcheck disable=SC2154 + if [ "$response" = "ok" ]; then + _info "slack send success." + return 0 + fi + fi + _err "slack send error." + _err "$response" + return 1 +} diff --git a/letsencrypt/notify/smtp.sh b/letsencrypt/notify/smtp.sh new file mode 100644 index 00000000..b1a066bd --- /dev/null +++ b/letsencrypt/notify/smtp.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# support smtp + +smtp_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_subject" "$_subject" + _debug "_content" "$_content" + _debug "_statusCode" "$_statusCode" + + _err "Not implemented yet." + return 1 +} diff --git a/letsencrypt/notify/teams.sh b/letsencrypt/notify/teams.sh new file mode 100644 index 00000000..b4c57460 --- /dev/null +++ b/letsencrypt/notify/teams.sh @@ -0,0 +1,86 @@ +#!/bin/bash + +#Support Microsoft Teams webhooks + +#TEAMS_WEBHOOK_URL="" +#TEAMS_THEME_COLOR="" +#TEAMS_SUCCESS_COLOR="" +#TEAMS_ERROR_COLOR="" +#TEAMS_SKIP_COLOR="" + +teams_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_statusCode" "$_statusCode" + + _color_success="2cbe4e" # green + _color_danger="cb2431" # red + _color_muted="586069" # gray + + TEAMS_WEBHOOK_URL="${TEAMS_WEBHOOK_URL:-$(_readaccountconf_mutable TEAMS_WEBHOOK_URL)}" + if [ -z "$TEAMS_WEBHOOK_URL" ]; then + TEAMS_WEBHOOK_URL="" + _err "You didn't specify a Microsoft Teams webhook url TEAMS_WEBHOOK_URL yet." + return 1 + fi + _saveaccountconf_mutable TEAMS_WEBHOOK_URL "$TEAMS_WEBHOOK_URL" + + TEAMS_THEME_COLOR="${TEAMS_THEME_COLOR:-$(_readaccountconf_mutable TEAMS_THEME_COLOR)}" + if [ -n "$TEAMS_THEME_COLOR" ]; then + _saveaccountconf_mutable TEAMS_THEME_COLOR "$TEAMS_THEME_COLOR" + fi + + TEAMS_SUCCESS_COLOR="${TEAMS_SUCCESS_COLOR:-$(_readaccountconf_mutable TEAMS_SUCCESS_COLOR)}" + if [ -n "$TEAMS_SUCCESS_COLOR" ]; then + _saveaccountconf_mutable TEAMS_SUCCESS_COLOR "$TEAMS_SUCCESS_COLOR" + fi + + TEAMS_ERROR_COLOR="${TEAMS_ERROR_COLOR:-$(_readaccountconf_mutable TEAMS_ERROR_COLOR)}" + if [ -n "$TEAMS_ERROR_COLOR" ]; then + _saveaccountconf_mutable TEAMS_ERROR_COLOR "$TEAMS_ERROR_COLOR" + fi + + TEAMS_SKIP_COLOR="${TEAMS_SKIP_COLOR:-$(_readaccountconf_mutable TEAMS_SKIP_COLOR)}" + if [ -n "$TEAMS_SKIP_COLOR" ]; then + _saveaccountconf_mutable TEAMS_SKIP_COLOR "$TEAMS_SKIP_COLOR" + fi + + export _H1="Content-Type: application/json" + + _subject=$(echo "$_subject" | _json_encode) + _content=$(echo "$_content" | _json_encode) + + case "$_statusCode" in + 0) + _color="${TEAMS_SUCCESS_COLOR:-$_color_success}" + ;; + 1) + _color="${TEAMS_ERROR_COLOR:-$_color_danger}" + ;; + 2) + _color="${TEAMS_SKIP_COLOR:-$_color_muted}" + ;; + esac + + _color=$(echo "$_color" | tr -cd 'a-fA-F0-9') + if [ -z "$_color" ]; then + _color=$(echo "${TEAMS_THEME_COLOR:-$_color_muted}" | tr -cd 'a-fA-F0-9') + fi + + _data="{\"title\": \"$_subject\"," + if [ -n "$_color" ]; then + _data="$_data\"themeColor\": \"$_color\", " + fi + _data="$_data\"text\": \"$_content\"}" + + if response=$(_post "$_data" "$TEAMS_WEBHOOK_URL"); then + if ! _contains "$response" error; then + _info "teams send success." + return 0 + fi + fi + _err "teams send error." + _err "$response" + return 1 +} diff --git a/letsencrypt/notify/xmpp.sh b/letsencrypt/notify/xmpp.sh new file mode 100644 index 00000000..e013a1e4 --- /dev/null +++ b/letsencrypt/notify/xmpp.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +#Support xmpp via sendxmpp + +#XMPP_BIN="/usr/bin/sendxmpp" +#XMPP_BIN_ARGS="-n -t --tls-ca-path=/etc/ssl/certs" +#XMPP_TO="zzzz@example.com" + +xmpp_send() { + _subject="$1" + _content="$2" + _statusCode="$3" #0: success, 1: error 2($RENEW_SKIP): skipped + _debug "_subject" "$_subject" + _debug "_content" "$_content" + _debug "_statusCode" "$_statusCode" + + XMPP_BIN="${XMPP_BIN:-$(_readaccountconf_mutable XMPP_BIN)}" + if [ -n "$XMPP_BIN" ] && ! _exists "$XMPP_BIN"; then + _err "It seems that the command $XMPP_BIN is not in path." + return 1 + fi + _XMPP_BIN=$(_xmpp_bin) + if [ -n "$XMPP_BIN" ]; then + _saveaccountconf_mutable XMPP_BIN "$XMPP_BIN" + else + _clearaccountconf "XMPP_BIN" + fi + + XMPP_BIN_ARGS="${XMPP_BIN_ARGS:-$(_readaccountconf_mutable XMPP_BIN_ARGS)}" + if [ -n "$XMPP_BIN_ARGS" ]; then + _saveaccountconf_mutable XMPP_BIN_ARGS "$XMPP_BIN_ARGS" + else + _clearaccountconf "XMPP_BIN_ARGS" + fi + + XMPP_TO="${XMPP_TO:-$(_readaccountconf_mutable XMPP_TO)}" + if [ -n "$XMPP_TO" ]; then + if ! _xmpp_valid "$XMPP_TO"; then + _err "It seems that the XMPP_TO=$XMPP_TO is not a valid xmpp address." + return 1 + fi + + _saveaccountconf_mutable XMPP_TO "$XMPP_TO" + fi + + result=$({ _xmpp_message | eval "$(_xmpp_cmnd)"; } 2>&1) + + # shellcheck disable=SC2181 + if [ $? -ne 0 ]; then + _debug "xmpp send error." + _err "$result" + return 1 + fi + + _debug "xmpp send success." + return 0 +} + +_xmpp_bin() { + if [ -n "$XMPP_BIN" ]; then + _XMPP_BIN="$XMPP_BIN" + elif _exists "sendxmpp"; then + _XMPP_BIN="sendxmpp" + else + _err "Please install sendxmpp first." + return 1 + fi + + echo "$_XMPP_BIN" +} + +_xmpp_cmnd() { + case $(basename "$_XMPP_BIN") in + sendxmpp) + echo "'$_XMPP_BIN' '$XMPP_TO' $XMPP_BIN_ARGS" + ;; + *) + _err "Command $XMPP_BIN is not supported, use sendxmpp." + return 1 + ;; + esac +} + +_xmpp_message() { + echo "$_subject" +} + +_xmpp_valid() { + _contains "$1" "@" +} diff --git a/libaudit.conf b/libaudit.conf new file mode 100644 index 00000000..90855d72 --- /dev/null +++ b/libaudit.conf @@ -0,0 +1,7 @@ +# This is the configuration file for libaudit tunables. +# It is currently only used for the failure_action tunable. + +# failure_action can be: log, ignore, terminate +failure_action = ignore + + diff --git a/libnl-3/classid b/libnl-3/classid new file mode 100644 index 00000000..22032431 --- /dev/null +++ b/libnl-3/classid @@ -0,0 +1,45 @@ +############################################################################### +# +# ClassID <-> Name Translation Table +# +# This file can be used to assign names to classids for easier reference +# in all libnl tools. +# +# Format: +# # qdisc definition +# # class deifnition +# # class definition referencing an +# existing qdisc definition. +# +# Example: +# 1: top # top -> 1:0 +# top:1 interactive # interactive -> 1:1 +# top:2 www # www -> 1:2 +# top:3 bulk # bulk -> 1:3 +# 2:1 test_class # test_class -> 2:1 +# +# Illegal Example: +# 30:1 classD +# classD:2 invalidClass # classD refers to a class, not a qdisc +# +############################################################################### + +# + +# Reserved default classids +0:0 none +ffff:ffff root +ffff:fff1 ingress + +# +# List your classid definitions here: +# + + + +############################################################################### +# List of auto-generated classids +# +# DO NOT ADD CLASSID DEFINITIONS BELOW THIS LINE +# +# diff --git a/libnl-3/pktloc b/libnl-3/pktloc new file mode 100644 index 00000000..8559161b --- /dev/null +++ b/libnl-3/pktloc @@ -0,0 +1,76 @@ +# +# Location definitions for packet matching +# + +# name alignment offset mask shift +ip.version u8 net+0 0xF0 4 +ip.hdrlen u8 net+0 0x0F +ip.diffserv u8 net+1 +ip.length u16 net+2 +ip.id u16 net+4 +ip.flag.res u8 net+6 0xff 7 +ip.df u8 net+6 0x40 6 +ip.mf u8 net+6 0x20 5 +ip.offset u16 net+6 0x1FFF +ip.ttl u8 net+8 +ip.proto u8 net+9 +ip.chksum u16 net+10 +ip.src u32 net+12 +ip.dst u32 net+16 + +# if ip.ihl > 5 +ip.opts u32 net+20 + + +# +# IP version 6 +# +# name alignment offset mask shift +ip6.version u8 net+0 0xF0 4 +ip6.tc u16 net+0 0xFF0 4 +ip6.flowlabel u32 net+0 0xFFFFF +ip6.length u16 net+4 +ip6.nexthdr u8 net+6 +ip6.hoplimit u8 net+7 +ip6.src 16 net+8 +ip6.dst 16 net+24 + +# +# Transmission Control Protocol (TCP) +# +# name alignment offset mask shift +tcp.sport u16 tcp+0 +tcp.dport u16 tcp+2 +tcp.seq u32 tcp+4 +tcp.ack u32 tcp+8 + +# Data offset (4 bits) +tcp.off u8 tcp+12 0xF0 4 + +# Reserved [0 0 0] (3 bits) +tcp.reserved u8 tcp+12 0x04 1 + +# ECN [N C E] (3 bits) +tcp.ecn u16 tcp+12 0x01C00 6 + +# Individual TCP flags (0|1) (6 bits in total) +tcp.flag.urg u8 tcp+13 0x20 5 +tcp.flag.ack u8 tcp+13 0x10 4 +tcp.flag.psh u8 tcp+13 0x08 3 +tcp.flag.rst u8 tcp+13 0x04 2 +tcp.flag.syn u8 tcp+13 0x02 1 +tcp.flag.fin u8 tcp+13 0x01 + +tcp.win u16 tcp+14 +tcp.csum u16 tcp+16 +tcp.urg u16 tcp+18 +tcp.opts u32 tcp+20 + +# +# User Datagram Protocol (UDP) +# +# name alignment offset mask shift +udp.sport u16 tcp+0 +udp.dport u16 tcp+2 +udp.length u16 tcp+4 +udp.csum u16 tcp+6 diff --git a/lighttpd/external.conf b/lighttpd/external.conf new file mode 100644 index 00000000..e69de29b diff --git a/lighttpd/lighttpd.conf.orig b/lighttpd/lighttpd.conf.orig new file mode 100644 index 00000000..09022a31 --- /dev/null +++ b/lighttpd/lighttpd.conf.orig @@ -0,0 +1,51 @@ +server.modules = ( + "mod_indexfile", + "mod_access", + "mod_alias", + "mod_redirect", +) + +server.document-root = "/var/www/html" +server.upload-dirs = ( "/var/cache/lighttpd/uploads" ) +server.errorlog = "/var/log/lighttpd/error.log" +server.pid-file = "/var/run/lighttpd.pid" +server.username = "www-data" +server.groupname = "www-data" +server.port = 80 + +# strict parsing and normalization of URL for consistency and security +# https://redmine.lighttpd.net/projects/lighttpd/wiki/Server_http-parseoptsDetails +# (might need to explicitly set "url-path-2f-decode" = "disable" +# if a specific application is encoding URLs inside url-path) +server.http-parseopts = ( + "header-strict" => "enable",# default + "host-strict" => "enable",# default + "host-normalize" => "enable",# default + "url-normalize-unreserved"=> "enable",# recommended highly + "url-normalize-required" => "enable",# recommended + "url-ctrls-reject" => "enable",# recommended + "url-path-2f-decode" => "enable",# recommended highly (unless breaks app) + #"url-path-2f-reject" => "enable", + "url-path-dotseg-remove" => "enable",# recommended highly (unless breaks app) + #"url-path-dotseg-reject" => "enable", + #"url-query-20-plus" => "enable",# consistency in query string +) + +index-file.names = ( "index.php", "index.html" ) +url.access-deny = ( "~", ".inc" ) +static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" ) + +compress.cache-dir = "/var/cache/lighttpd/compress/" +compress.filetype = ( "application/javascript", "text/css", "text/html", "text/plain" ) + +# default listening port for IPv6 falls back to the IPv4 port +include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port +include_shell "/usr/share/lighttpd/create-mime.conf.pl" +include "/etc/lighttpd/conf-enabled/*.conf" + +#server.compat-module-load = "disable" +server.modules += ( + "mod_compress", + "mod_dirlisting", + "mod_staticfile", +) diff --git a/locale.alias b/locale.alias new file mode 100644 index 00000000..2b286dd0 --- /dev/null +++ b/locale.alias @@ -0,0 +1,82 @@ +# Locale name alias data base. +# Copyright (C) 1996-2018 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . + +# The format of this file is the same as for the corresponding file of +# the X Window System, which normally can be found in +# /usr/lib/X11/locale/locale.alias +# A single line contains two fields: an alias and a substitution value. +# All entries are case independent. + +# Note: This file is obsolete and is kept around for the time being for +# backward compatibility. Nobody should rely on the names defined here. +# Locales should always be specified by their full name. + +# Note: This file used to contain the following lines: +# bokmaal nb_NO.ISO-8859-1 +# franc,ais fr_FR.ISO-8859-1 +# except that the "aa" was actually the byte '\0xE5' (the Latin-1 +# encoding for U+00E5 LATIN SMALL LETTER A WITH RING ABOVE) and the +# "c," was actually the byte '\xE7' (the Latin-1 encoding for U+00E7 +# LATIN SMALL LETTER C WITH CEDILLA). These lines were removed +# because they caused 'locale -a' to output text encoded in Latin-1, +# which broke applications in UTF-8 locales. See: +# https://sourceware.org/bugzilla/show_bug.cgi?id=18412 + +bokmal nb_NO.ISO-8859-1 +catalan ca_ES.ISO-8859-1 +croatian hr_HR.ISO-8859-2 +czech cs_CZ.ISO-8859-2 +danish da_DK.ISO-8859-1 +dansk da_DK.ISO-8859-1 +deutsch de_DE.ISO-8859-1 +dutch nl_NL.ISO-8859-1 +eesti et_EE.ISO-8859-15 +estonian et_EE.ISO-8859-15 +finnish fi_FI.ISO-8859-1 +french fr_FR.ISO-8859-1 +galego gl_ES.ISO-8859-1 +galician gl_ES.ISO-8859-1 +german de_DE.ISO-8859-1 +greek el_GR.ISO-8859-7 +hebrew he_IL.ISO-8859-8 +hrvatski hr_HR.ISO-8859-2 +hungarian hu_HU.ISO-8859-2 +icelandic is_IS.ISO-8859-1 +italian it_IT.ISO-8859-1 +japanese ja_JP.eucJP +japanese.euc ja_JP.eucJP +ja_JP ja_JP.eucJP +ja_JP.ujis ja_JP.eucJP +japanese.sjis ja_JP.SJIS +korean ko_KR.eucKR +korean.euc ko_KR.eucKR +ko_KR ko_KR.eucKR +lithuanian lt_LT.ISO-8859-13 +no_NO nb_NO.ISO-8859-1 +no_NO.ISO-8859-1 nb_NO.ISO-8859-1 +norwegian nb_NO.ISO-8859-1 +nynorsk nn_NO.ISO-8859-1 +polish pl_PL.ISO-8859-2 +portuguese pt_PT.ISO-8859-1 +romanian ro_RO.ISO-8859-2 +russian ru_RU.KOI8-R +slovak sk_SK.ISO-8859-2 +slovene sl_SI.ISO-8859-2 +slovenian sl_SI.ISO-8859-2 +spanish es_ES.ISO-8859-1 +swedish sv_SE.ISO-8859-1 +thai th_TH.TIS-620 +turkish tr_TR.ISO-8859-9 diff --git a/locale.gen b/locale.gen new file mode 100644 index 00000000..f575e9fd --- /dev/null +++ b/locale.gen @@ -0,0 +1,501 @@ +# This file lists locales that you wish to have built. You can find a list +# of valid supported locales at /usr/share/i18n/SUPPORTED, and you can add +# user defined locales to /usr/local/share/i18n/SUPPORTED. If you change +# this file, you need to rerun locale-gen. +# + +# aa_DJ ISO-8859-1 +# aa_DJ.UTF-8 UTF-8 +# aa_ER UTF-8 +# aa_ER@saaho UTF-8 +# aa_ET UTF-8 +# af_ZA ISO-8859-1 +# af_ZA.UTF-8 UTF-8 +# agr_PE UTF-8 +# ak_GH UTF-8 +# am_ET UTF-8 +# an_ES ISO-8859-15 +# an_ES.UTF-8 UTF-8 +# anp_IN UTF-8 +# ar_AE ISO-8859-6 +# ar_AE.UTF-8 UTF-8 +# ar_BH ISO-8859-6 +# ar_BH.UTF-8 UTF-8 +# ar_DZ ISO-8859-6 +# ar_DZ.UTF-8 UTF-8 +# ar_EG ISO-8859-6 +# ar_EG.UTF-8 UTF-8 +# ar_IN UTF-8 +# ar_IQ ISO-8859-6 +# ar_IQ.UTF-8 UTF-8 +# ar_JO ISO-8859-6 +# ar_JO.UTF-8 UTF-8 +# ar_KW ISO-8859-6 +# ar_KW.UTF-8 UTF-8 +# ar_LB ISO-8859-6 +# ar_LB.UTF-8 UTF-8 +# ar_LY ISO-8859-6 +# ar_LY.UTF-8 UTF-8 +# ar_MA ISO-8859-6 +# ar_MA.UTF-8 UTF-8 +# ar_OM ISO-8859-6 +# ar_OM.UTF-8 UTF-8 +# ar_QA ISO-8859-6 +# ar_QA.UTF-8 UTF-8 +# ar_SA ISO-8859-6 +# ar_SA.UTF-8 UTF-8 +# ar_SD ISO-8859-6 +# ar_SD.UTF-8 UTF-8 +# ar_SS UTF-8 +# ar_SY ISO-8859-6 +# ar_SY.UTF-8 UTF-8 +# ar_TN ISO-8859-6 +# ar_TN.UTF-8 UTF-8 +# ar_YE ISO-8859-6 +# ar_YE.UTF-8 UTF-8 +# as_IN UTF-8 +# ast_ES ISO-8859-15 +# ast_ES.UTF-8 UTF-8 +# ayc_PE UTF-8 +# az_AZ UTF-8 +# az_IR UTF-8 +# be_BY CP1251 +# be_BY.UTF-8 UTF-8 +# be_BY@latin UTF-8 +# bem_ZM UTF-8 +# ber_DZ UTF-8 +# ber_MA UTF-8 +# bg_BG CP1251 +# bg_BG.UTF-8 UTF-8 +# bhb_IN.UTF-8 UTF-8 +# bho_IN UTF-8 +# bho_NP UTF-8 +# bi_VU UTF-8 +# bn_BD UTF-8 +# bn_IN UTF-8 +# bo_CN UTF-8 +# bo_IN UTF-8 +# br_FR ISO-8859-1 +# br_FR.UTF-8 UTF-8 +# br_FR@euro ISO-8859-15 +# brx_IN UTF-8 +# bs_BA ISO-8859-2 +# bs_BA.UTF-8 UTF-8 +# byn_ER UTF-8 +# ca_AD ISO-8859-15 +# ca_AD.UTF-8 UTF-8 +# ca_ES ISO-8859-1 +# ca_ES.UTF-8 UTF-8 +# ca_ES@euro ISO-8859-15 +# ca_ES@valencia UTF-8 +# ca_FR ISO-8859-15 +# ca_FR.UTF-8 UTF-8 +# ca_IT ISO-8859-15 +# ca_IT.UTF-8 UTF-8 +# ce_RU UTF-8 +# chr_US UTF-8 +# cmn_TW UTF-8 +# crh_UA UTF-8 +# cs_CZ ISO-8859-2 +# cs_CZ.UTF-8 UTF-8 +# csb_PL UTF-8 +# cv_RU UTF-8 +# cy_GB ISO-8859-14 +# cy_GB.UTF-8 UTF-8 +# da_DK ISO-8859-1 +# da_DK.UTF-8 UTF-8 +# de_AT ISO-8859-1 +# de_AT.UTF-8 UTF-8 +# de_AT@euro ISO-8859-15 +# de_BE ISO-8859-1 +# de_BE.UTF-8 UTF-8 +# de_BE@euro ISO-8859-15 +# de_CH ISO-8859-1 +# de_CH.UTF-8 UTF-8 +# de_DE ISO-8859-1 +# de_DE.UTF-8 UTF-8 +# de_DE@euro ISO-8859-15 +# de_IT ISO-8859-1 +# de_IT.UTF-8 UTF-8 +# de_LI.UTF-8 UTF-8 +# de_LU ISO-8859-1 +# de_LU.UTF-8 UTF-8 +# de_LU@euro ISO-8859-15 +# doi_IN UTF-8 +# dsb_DE UTF-8 +# dv_MV UTF-8 +# dz_BT UTF-8 +# el_CY ISO-8859-7 +# el_CY.UTF-8 UTF-8 +# el_GR ISO-8859-7 +# el_GR.UTF-8 UTF-8 +# el_GR@euro ISO-8859-7 +# en_AG UTF-8 +# en_AU ISO-8859-1 +# en_AU.UTF-8 UTF-8 +# en_BW ISO-8859-1 +# en_BW.UTF-8 UTF-8 +# en_CA ISO-8859-1 +# en_CA.UTF-8 UTF-8 +# en_DK ISO-8859-1 +# en_DK.ISO-8859-15 ISO-8859-15 +# en_DK.UTF-8 UTF-8 +# en_GB ISO-8859-1 +# en_GB.ISO-8859-15 ISO-8859-15 +en_GB.UTF-8 UTF-8 +# en_HK ISO-8859-1 +# en_HK.UTF-8 UTF-8 +# en_IE ISO-8859-1 +# en_IE.UTF-8 UTF-8 +# en_IE@euro ISO-8859-15 +# en_IL UTF-8 +# en_IN UTF-8 +# en_NG UTF-8 +# en_NZ ISO-8859-1 +# en_NZ.UTF-8 UTF-8 +# en_PH ISO-8859-1 +# en_PH.UTF-8 UTF-8 +# en_SC.UTF-8 UTF-8 +# en_SG ISO-8859-1 +# en_SG.UTF-8 UTF-8 +# en_US ISO-8859-1 +# en_US.ISO-8859-15 ISO-8859-15 +# en_US.UTF-8 UTF-8 +# en_ZA ISO-8859-1 +# en_ZA.UTF-8 UTF-8 +# en_ZM UTF-8 +# en_ZW ISO-8859-1 +# en_ZW.UTF-8 UTF-8 +# eo UTF-8 +# es_AR ISO-8859-1 +# es_AR.UTF-8 UTF-8 +# es_BO ISO-8859-1 +# es_BO.UTF-8 UTF-8 +# es_CL ISO-8859-1 +# es_CL.UTF-8 UTF-8 +# es_CO ISO-8859-1 +# es_CO.UTF-8 UTF-8 +# es_CR ISO-8859-1 +# es_CR.UTF-8 UTF-8 +# es_CU UTF-8 +# es_DO ISO-8859-1 +# es_DO.UTF-8 UTF-8 +# es_EC ISO-8859-1 +# es_EC.UTF-8 UTF-8 +# es_ES ISO-8859-1 +# es_ES.UTF-8 UTF-8 +# es_ES@euro ISO-8859-15 +# es_GT ISO-8859-1 +# es_GT.UTF-8 UTF-8 +# es_HN ISO-8859-1 +# es_HN.UTF-8 UTF-8 +# es_MX ISO-8859-1 +# es_MX.UTF-8 UTF-8 +# es_NI ISO-8859-1 +# es_NI.UTF-8 UTF-8 +# es_PA ISO-8859-1 +# es_PA.UTF-8 UTF-8 +# es_PE ISO-8859-1 +# es_PE.UTF-8 UTF-8 +# es_PR ISO-8859-1 +# es_PR.UTF-8 UTF-8 +# es_PY ISO-8859-1 +# es_PY.UTF-8 UTF-8 +# es_SV ISO-8859-1 +# es_SV.UTF-8 UTF-8 +# es_US ISO-8859-1 +# es_US.UTF-8 UTF-8 +# es_UY ISO-8859-1 +# es_UY.UTF-8 UTF-8 +# es_VE ISO-8859-1 +# es_VE.UTF-8 UTF-8 +# et_EE ISO-8859-1 +# et_EE.ISO-8859-15 ISO-8859-15 +# et_EE.UTF-8 UTF-8 +# eu_ES ISO-8859-1 +# eu_ES.UTF-8 UTF-8 +# eu_ES@euro ISO-8859-15 +# eu_FR ISO-8859-1 +# eu_FR.UTF-8 UTF-8 +# eu_FR@euro ISO-8859-15 +# fa_IR UTF-8 +# ff_SN UTF-8 +# fi_FI ISO-8859-1 +# fi_FI.UTF-8 UTF-8 +# fi_FI@euro ISO-8859-15 +# fil_PH UTF-8 +# fo_FO ISO-8859-1 +# fo_FO.UTF-8 UTF-8 +# fr_BE ISO-8859-1 +# fr_BE.UTF-8 UTF-8 +# fr_BE@euro ISO-8859-15 +# fr_CA ISO-8859-1 +# fr_CA.UTF-8 UTF-8 +# fr_CH ISO-8859-1 +# fr_CH.UTF-8 UTF-8 +# fr_FR ISO-8859-1 +# fr_FR.UTF-8 UTF-8 +# fr_FR@euro ISO-8859-15 +# fr_LU ISO-8859-1 +# fr_LU.UTF-8 UTF-8 +# fr_LU@euro ISO-8859-15 +# fur_IT UTF-8 +# fy_DE UTF-8 +# fy_NL UTF-8 +# ga_IE ISO-8859-1 +# ga_IE.UTF-8 UTF-8 +# ga_IE@euro ISO-8859-15 +# gd_GB ISO-8859-15 +# gd_GB.UTF-8 UTF-8 +# gez_ER UTF-8 +# gez_ER@abegede UTF-8 +# gez_ET UTF-8 +# gez_ET@abegede UTF-8 +# gl_ES ISO-8859-1 +# gl_ES.UTF-8 UTF-8 +# gl_ES@euro ISO-8859-15 +# gu_IN UTF-8 +# gv_GB ISO-8859-1 +# gv_GB.UTF-8 UTF-8 +# ha_NG UTF-8 +# hak_TW UTF-8 +# he_IL ISO-8859-8 +# he_IL.UTF-8 UTF-8 +# hi_IN UTF-8 +# hif_FJ UTF-8 +# hne_IN UTF-8 +# hr_HR ISO-8859-2 +# hr_HR.UTF-8 UTF-8 +# hsb_DE ISO-8859-2 +# hsb_DE.UTF-8 UTF-8 +# ht_HT UTF-8 +# hu_HU ISO-8859-2 +# hu_HU.UTF-8 UTF-8 +# hy_AM UTF-8 +# hy_AM.ARMSCII-8 ARMSCII-8 +# ia_FR UTF-8 +# id_ID ISO-8859-1 +# id_ID.UTF-8 UTF-8 +# ig_NG UTF-8 +# ik_CA UTF-8 +# is_IS ISO-8859-1 +# is_IS.UTF-8 UTF-8 +# it_CH ISO-8859-1 +# it_CH.UTF-8 UTF-8 +# it_IT ISO-8859-1 +# it_IT.UTF-8 UTF-8 +# it_IT@euro ISO-8859-15 +# iu_CA UTF-8 +# ja_JP.EUC-JP EUC-JP +# ja_JP.UTF-8 UTF-8 +# ka_GE GEORGIAN-PS +# ka_GE.UTF-8 UTF-8 +# kab_DZ UTF-8 +# kk_KZ PT154 +# kk_KZ.RK1048 RK1048 +# kk_KZ.UTF-8 UTF-8 +# kl_GL ISO-8859-1 +# kl_GL.UTF-8 UTF-8 +# km_KH UTF-8 +# kn_IN UTF-8 +# ko_KR.EUC-KR EUC-KR +# ko_KR.UTF-8 UTF-8 +# kok_IN UTF-8 +# ks_IN UTF-8 +# ks_IN@devanagari UTF-8 +# ku_TR ISO-8859-9 +# ku_TR.UTF-8 UTF-8 +# kw_GB ISO-8859-1 +# kw_GB.UTF-8 UTF-8 +# ky_KG UTF-8 +# lb_LU UTF-8 +# lg_UG ISO-8859-10 +# lg_UG.UTF-8 UTF-8 +# li_BE UTF-8 +# li_NL UTF-8 +# lij_IT UTF-8 +# ln_CD UTF-8 +# lo_LA UTF-8 +# lt_LT ISO-8859-13 +# lt_LT.UTF-8 UTF-8 +# lv_LV ISO-8859-13 +# lv_LV.UTF-8 UTF-8 +# lzh_TW UTF-8 +# mag_IN UTF-8 +# mai_IN UTF-8 +# mai_NP UTF-8 +# mfe_MU UTF-8 +# mg_MG ISO-8859-15 +# mg_MG.UTF-8 UTF-8 +# mhr_RU UTF-8 +# mi_NZ ISO-8859-13 +# mi_NZ.UTF-8 UTF-8 +# miq_NI UTF-8 +# mjw_IN UTF-8 +# mk_MK ISO-8859-5 +# mk_MK.UTF-8 UTF-8 +# ml_IN UTF-8 +# mn_MN UTF-8 +# mni_IN UTF-8 +# mr_IN UTF-8 +# ms_MY ISO-8859-1 +# ms_MY.UTF-8 UTF-8 +# mt_MT ISO-8859-3 +# mt_MT.UTF-8 UTF-8 +# my_MM UTF-8 +# nan_TW UTF-8 +# nan_TW@latin UTF-8 +# nb_NO ISO-8859-1 +# nb_NO.UTF-8 UTF-8 +# nds_DE UTF-8 +# nds_NL UTF-8 +# ne_NP UTF-8 +# nhn_MX UTF-8 +# niu_NU UTF-8 +# niu_NZ UTF-8 +# nl_AW UTF-8 +# nl_BE ISO-8859-1 +# nl_BE.UTF-8 UTF-8 +# nl_BE@euro ISO-8859-15 +# nl_NL ISO-8859-1 +# nl_NL.UTF-8 UTF-8 +# nl_NL@euro ISO-8859-15 +# nn_NO ISO-8859-1 +# nn_NO.UTF-8 UTF-8 +# nr_ZA UTF-8 +# nso_ZA UTF-8 +# oc_FR ISO-8859-1 +# oc_FR.UTF-8 UTF-8 +# om_ET UTF-8 +# om_KE ISO-8859-1 +# om_KE.UTF-8 UTF-8 +# or_IN UTF-8 +# os_RU UTF-8 +# pa_IN UTF-8 +# pa_PK UTF-8 +# pap_AW UTF-8 +# pap_CW UTF-8 +# pl_PL ISO-8859-2 +# pl_PL.UTF-8 UTF-8 +# ps_AF UTF-8 +# pt_BR ISO-8859-1 +# pt_BR.UTF-8 UTF-8 +# pt_PT ISO-8859-1 +# pt_PT.UTF-8 UTF-8 +# pt_PT@euro ISO-8859-15 +# quz_PE UTF-8 +# raj_IN UTF-8 +# ro_RO ISO-8859-2 +# ro_RO.UTF-8 UTF-8 +# ru_RU ISO-8859-5 +# ru_RU.CP1251 CP1251 +# ru_RU.KOI8-R KOI8-R +# ru_RU.UTF-8 UTF-8 +# ru_UA KOI8-U +# ru_UA.UTF-8 UTF-8 +# rw_RW UTF-8 +# sa_IN UTF-8 +# sah_RU UTF-8 +# sat_IN UTF-8 +# sc_IT UTF-8 +# sd_IN UTF-8 +# sd_IN@devanagari UTF-8 +# se_NO UTF-8 +# sgs_LT UTF-8 +# shn_MM UTF-8 +# shs_CA UTF-8 +# si_LK UTF-8 +# sid_ET UTF-8 +# sk_SK ISO-8859-2 +# sk_SK.UTF-8 UTF-8 +# sl_SI ISO-8859-2 +# sl_SI.UTF-8 UTF-8 +# sm_WS UTF-8 +# so_DJ ISO-8859-1 +# so_DJ.UTF-8 UTF-8 +# so_ET UTF-8 +# so_KE ISO-8859-1 +# so_KE.UTF-8 UTF-8 +# so_SO ISO-8859-1 +# so_SO.UTF-8 UTF-8 +# sq_AL ISO-8859-1 +# sq_AL.UTF-8 UTF-8 +# sq_MK UTF-8 +# sr_ME UTF-8 +# sr_RS UTF-8 +# sr_RS@latin UTF-8 +# ss_ZA UTF-8 +# st_ZA ISO-8859-1 +# st_ZA.UTF-8 UTF-8 +# sv_FI ISO-8859-1 +# sv_FI.UTF-8 UTF-8 +# sv_FI@euro ISO-8859-15 +# sv_SE ISO-8859-1 +# sv_SE.ISO-8859-15 ISO-8859-15 +# sv_SE.UTF-8 UTF-8 +# sw_KE UTF-8 +# sw_TZ UTF-8 +# szl_PL UTF-8 +# ta_IN UTF-8 +# ta_LK UTF-8 +# tcy_IN.UTF-8 UTF-8 +# te_IN UTF-8 +# tg_TJ KOI8-T +# tg_TJ.UTF-8 UTF-8 +# th_TH TIS-620 +# th_TH.UTF-8 UTF-8 +# the_NP UTF-8 +# ti_ER UTF-8 +# ti_ET UTF-8 +# tig_ER UTF-8 +# tk_TM UTF-8 +# tl_PH ISO-8859-1 +# tl_PH.UTF-8 UTF-8 +# tn_ZA UTF-8 +# to_TO UTF-8 +# tpi_PG UTF-8 +# tr_CY ISO-8859-9 +# tr_CY.UTF-8 UTF-8 +# tr_TR ISO-8859-9 +# tr_TR.UTF-8 UTF-8 +# ts_ZA UTF-8 +# tt_RU UTF-8 +# tt_RU@iqtelif UTF-8 +# ug_CN UTF-8 +# uk_UA KOI8-U +# uk_UA.UTF-8 UTF-8 +# unm_US UTF-8 +# ur_IN UTF-8 +# ur_PK UTF-8 +# uz_UZ ISO-8859-1 +# uz_UZ.UTF-8 UTF-8 +# uz_UZ@cyrillic UTF-8 +# ve_ZA UTF-8 +# vi_VN UTF-8 +# wa_BE ISO-8859-1 +# wa_BE.UTF-8 UTF-8 +# wa_BE@euro ISO-8859-15 +# wae_CH UTF-8 +# wal_ET UTF-8 +# wo_SN UTF-8 +# xh_ZA ISO-8859-1 +# xh_ZA.UTF-8 UTF-8 +# yi_US CP1255 +# yi_US.UTF-8 UTF-8 +# yo_NG UTF-8 +# yue_HK UTF-8 +# yuw_PG UTF-8 +# zh_CN GB2312 +# zh_CN.GB18030 GB18030 +# zh_CN.GBK GBK +# zh_CN.UTF-8 UTF-8 +# zh_HK BIG5-HKSCS +# zh_HK.UTF-8 UTF-8 +# zh_SG GB2312 +# zh_SG.GBK GBK +# zh_SG.UTF-8 UTF-8 +# zh_TW BIG5 +# zh_TW.EUC-TW EUC-TW +# zh_TW.UTF-8 UTF-8 +# zu_ZA ISO-8859-1 +# zu_ZA.UTF-8 UTF-8 diff --git a/localtime b/localtime new file mode 120000 index 00000000..622b45b1 --- /dev/null +++ b/localtime @@ -0,0 +1 @@ +/usr/share/zoneinfo/Europe/Berlin \ No newline at end of file diff --git a/logcheck/ignore.d.server/gpg-agent b/logcheck/ignore.d.server/gpg-agent new file mode 100644 index 00000000..a2f21307 --- /dev/null +++ b/logcheck/ignore.d.server/gpg-agent @@ -0,0 +1,11 @@ +^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[[[:digit:]]+\]: Listening on GnuPG cryptographic agent and passphrase cache\.$ +^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[[[:digit:]]+\]: Listening on GnuPG network certificate management daemon\.$ +^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[[[:digit:]]+\]: Listening on GnuPG cryptographic agent and passphrase cache \(restricted\)\.$ +^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[[[:digit:]]+\]: Listening on GnuPG cryptographic agent \(access for web browsers\)\.$ +^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[[[:digit:]]+\]: Listening on GnuPG cryptographic agent \(ssh-agent emulation\)\.$ +^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[[[:digit:]]+\]: Closed GnuPG network certificate management daemon\.$ +^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[[[:digit:]]+\]: Closed GnuPG cryptographic agent and passphrase cache\.$ +^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[[[:digit:]]+\]: Closed GnuPG cryptographic agent and passphrase cache \(restricted\)\.$ +^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[[[:digit:]]+\]: Closed GnuPG cryptographic agent \(ssh-agent emulation\)\.$ +^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ systemd\[[[:digit:]]+\]: Closed GnuPG cryptographic agent \(access for web browsers\)\.$ + diff --git a/logcheck/ignore.d.server/rng-tools b/logcheck/ignore.d.server/rng-tools new file mode 100644 index 00000000..8bfb6b87 --- /dev/null +++ b/logcheck/ignore.d.server/rng-tools @@ -0,0 +1,5 @@ +rngd\[[0-9]+\]: +stats: +rngd\[[0-9]+\]: .* starting up\.\.\. +rngd\[[0-9]+\]: +Exiting\.\.\. +rngd\[[0-9]+\]: +entropy feed to the kernel ready +rngd\[[0-9]+\]: +Activating Linux kernel 2.4 entropy accounting bug workaround diff --git a/logcheck/ignore.d.server/rsyslog b/logcheck/ignore.d.server/rsyslog new file mode 100644 index 00000000..171f20ee --- /dev/null +++ b/logcheck/ignore.d.server/rsyslog @@ -0,0 +1,5 @@ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ kernel: imklog [0-9.]+, log source = /proc/kmsg started.$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ kernel: Kernel logging \(proc\) stopped.$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ rsyslogd: \[origin software="rsyslogd" swVersion="[0-9.]+" x-pid="[0-9]+" x-info="http://www.rsyslog.com"\] start$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ rsyslogd: \[origin software="rsyslogd" swVersion="[0-9.]+" x-pid="[0-9]+" x-info="http://www.rsyslog.com"\] exiting on signal [0-9]+.$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ rsyslogd: \[origin software="rsyslogd" swVersion="[0-9.]+" x-pid="[0-9]+" x-info="http://www.rsyslog.com"\] rsyslogd was HUPed$ diff --git a/logcheck/violations.ignore.d/rng-tools b/logcheck/violations.ignore.d/rng-tools new file mode 100644 index 00000000..8bfb6b87 --- /dev/null +++ b/logcheck/violations.ignore.d/rng-tools @@ -0,0 +1,5 @@ +rngd\[[0-9]+\]: +stats: +rngd\[[0-9]+\]: .* starting up\.\.\. +rngd\[[0-9]+\]: +Exiting\.\.\. +rngd\[[0-9]+\]: +entropy feed to the kernel ready +rngd\[[0-9]+\]: +Activating Linux kernel 2.4 entropy accounting bug workaround diff --git a/login.defs b/login.defs new file mode 100644 index 00000000..4d917487 --- /dev/null +++ b/login.defs @@ -0,0 +1,340 @@ +# +# /etc/login.defs - Configuration control definitions for the login package. +# +# Three items must be defined: MAIL_DIR, ENV_SUPATH, and ENV_PATH. +# If unspecified, some arbitrary (and possibly incorrect) value will +# be assumed. All other items are optional - if not specified then +# the described action or option will be inhibited. +# +# Comment lines (lines beginning with "#") and blank lines are ignored. +# +# Modified for Linux. --marekm + +# REQUIRED for useradd/userdel/usermod +# Directory where mailboxes reside, _or_ name of file, relative to the +# home directory. If you _do_ define MAIL_DIR and MAIL_FILE, +# MAIL_DIR takes precedence. +# +# Essentially: +# - MAIL_DIR defines the location of users mail spool files +# (for mbox use) by appending the username to MAIL_DIR as defined +# below. +# - MAIL_FILE defines the location of the users mail spool files as the +# fully-qualified filename obtained by prepending the user home +# directory before $MAIL_FILE +# +# NOTE: This is no more used for setting up users MAIL environment variable +# which is, starting from shadow 4.0.12-1 in Debian, entirely the +# job of the pam_mail PAM modules +# See default PAM configuration files provided for +# login, su, etc. +# +# This is a temporary situation: setting these variables will soon +# move to /etc/default/useradd and the variables will then be +# no more supported +MAIL_DIR /var/mail +#MAIL_FILE .mail + +# +# Enable logging and display of /var/log/faillog login failure info. +# This option conflicts with the pam_tally PAM module. +# +FAILLOG_ENAB yes + +# +# Enable display of unknown usernames when login failures are recorded. +# +# WARNING: Unknown usernames may become world readable. +# See #290803 and #298773 for details about how this could become a security +# concern +LOG_UNKFAIL_ENAB no + +# +# Enable logging of successful logins +# +LOG_OK_LOGINS no + +# +# Enable "syslog" logging of su activity - in addition to sulog file logging. +# SYSLOG_SG_ENAB does the same for newgrp and sg. +# +SYSLOG_SU_ENAB yes +SYSLOG_SG_ENAB yes + +# +# If defined, all su activity is logged to this file. +# +#SULOG_FILE /var/log/sulog + +# +# If defined, file which maps tty line to TERM environment parameter. +# Each line of the file is in a format something like "vt100 tty01". +# +#TTYTYPE_FILE /etc/ttytype + +# +# If defined, login failures will be logged here in a utmp format +# last, when invoked as lastb, will read /var/log/btmp, so... +# +FTMP_FILE /var/log/btmp + +# +# If defined, the command name to display when running "su -". For +# example, if this is defined as "su" then a "ps" will display the +# command is "-su". If not defined, then "ps" would display the +# name of the shell actually being run, e.g. something like "-sh". +# +SU_NAME su + +# +# If defined, file which inhibits all the usual chatter during the login +# sequence. If a full pathname, then hushed mode will be enabled if the +# user's name or shell are found in the file. If not a full pathname, then +# hushed mode will be enabled if the file exists in the user's home directory. +# +HUSHLOGIN_FILE .hushlogin +#HUSHLOGIN_FILE /etc/hushlogins + +# +# *REQUIRED* The default PATH settings, for superuser and normal users. +# +# (they are minimal, add the rest in the shell startup files) +ENV_SUPATH PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +ENV_PATH PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games + +# +# Terminal permissions +# +# TTYGROUP Login tty will be assigned this group ownership. +# TTYPERM Login tty will be set to this permission. +# +# If you have a "write" program which is "setgid" to a special group +# which owns the terminals, define TTYGROUP to the group number and +# TTYPERM to 0620. Otherwise leave TTYGROUP commented out and assign +# TTYPERM to either 622 or 600. +# +# In Debian /usr/bin/bsd-write or similar programs are setgid tty +# However, the default and recommended value for TTYPERM is still 0600 +# to not allow anyone to write to anyone else console or terminal + +# Users can still allow other people to write them by issuing +# the "mesg y" command. + +TTYGROUP tty +TTYPERM 0600 + +# +# Login configuration initializations: +# +# ERASECHAR Terminal ERASE character ('\010' = backspace). +# KILLCHAR Terminal KILL character ('\025' = CTRL/U). +# UMASK Default "umask" value. +# +# The ERASECHAR and KILLCHAR are used only on System V machines. +# +# UMASK is the default umask value for pam_umask and is used by +# useradd and newusers to set the mode of the new home directories. +# 022 is the "historical" value in Debian for UMASK +# 027, or even 077, could be considered better for privacy +# There is no One True Answer here : each sysadmin must make up his/her +# mind. +# +# If USERGROUPS_ENAB is set to "yes", that will modify this UMASK default value +# for private user groups, i. e. the uid is the same as gid, and username is +# the same as the primary group name: for these, the user permissions will be +# used as group permissions, e. g. 022 will become 002. +# +# Prefix these values with "0" to get octal, "0x" to get hexadecimal. +# +ERASECHAR 0177 +KILLCHAR 025 +UMASK 022 + +# +# Password aging controls: +# +# PASS_MAX_DAYS Maximum number of days a password may be used. +# PASS_MIN_DAYS Minimum number of days allowed between password changes. +# PASS_WARN_AGE Number of days warning given before a password expires. +# +PASS_MAX_DAYS 99999 +PASS_MIN_DAYS 0 +PASS_WARN_AGE 7 + +# +# Min/max values for automatic uid selection in useradd +# +UID_MIN 1000 +UID_MAX 60000 +# System accounts +#SYS_UID_MIN 100 +#SYS_UID_MAX 999 + +# +# Min/max values for automatic gid selection in groupadd +# +GID_MIN 1000 +GID_MAX 60000 +# System accounts +#SYS_GID_MIN 100 +#SYS_GID_MAX 999 + +# +# Max number of login retries if password is bad. This will most likely be +# overriden by PAM, since the default pam_unix module has it's own built +# in of 3 retries. However, this is a safe fallback in case you are using +# an authentication module that does not enforce PAM_MAXTRIES. +# +LOGIN_RETRIES 5 + +# +# Max time in seconds for login +# +LOGIN_TIMEOUT 60 + +# +# Which fields may be changed by regular users using chfn - use +# any combination of letters "frwh" (full name, room number, work +# phone, home phone). If not defined, no changes are allowed. +# For backward compatibility, "yes" = "rwh" and "no" = "frwh". +# +CHFN_RESTRICT rwh + +# +# Should login be allowed if we can't cd to the home directory? +# Default in no. +# +DEFAULT_HOME yes + +# +# If defined, this command is run when removing a user. +# It should remove any at/cron/print jobs etc. owned by +# the user to be removed (passed as the first argument). +# +#USERDEL_CMD /usr/sbin/userdel_local + +# +# If set to yes, userdel will remove the user's group if it contains no +# more members, and useradd will create by default a group with the name +# of the user. +# +# Other former uses of this variable such as setting the umask when +# user==primary group are not used in PAM environments, such as Debian +# +USERGROUPS_ENAB yes + +# +# Instead of the real user shell, the program specified by this parameter +# will be launched, although its visible name (argv[0]) will be the shell's. +# The program may do whatever it wants (logging, additional authentification, +# banner, ...) before running the actual shell. +# +# FAKE_SHELL /bin/fakeshell + +# +# If defined, either full pathname of a file containing device names or +# a ":" delimited list of device names. Root logins will be allowed only +# upon these devices. +# +# This variable is used by login and su. +# +#CONSOLE /etc/consoles +#CONSOLE console:tty01:tty02:tty03:tty04 + +# +# List of groups to add to the user's supplementary group set +# when logging in on the console (as determined by the CONSOLE +# setting). Default is none. +# +# Use with caution - it is possible for users to gain permanent +# access to these groups, even when not logged in on the console. +# How to do it is left as an exercise for the reader... +# +# This variable is used by login and su. +# +#CONSOLE_GROUPS floppy:audio:cdrom + +# +# If set to "yes", new passwords will be encrypted using the MD5-based +# algorithm compatible with the one used by recent releases of FreeBSD. +# It supports passwords of unlimited length and longer salt strings. +# Set to "no" if you need to copy encrypted passwords to other systems +# which don't understand the new algorithm. Default is "no". +# +# This variable is deprecated. You should use ENCRYPT_METHOD. +# +#MD5_CRYPT_ENAB no + +# +# If set to MD5 , MD5-based algorithm will be used for encrypting password +# If set to SHA256, SHA256-based algorithm will be used for encrypting password +# If set to SHA512, SHA512-based algorithm will be used for encrypting password +# If set to DES, DES-based algorithm will be used for encrypting password (default) +# Overrides the MD5_CRYPT_ENAB option +# +# Note: It is recommended to use a value consistent with +# the PAM modules configuration. +# +ENCRYPT_METHOD SHA512 + +# +# Only used if ENCRYPT_METHOD is set to SHA256 or SHA512. +# +# Define the number of SHA rounds. +# With a lot of rounds, it is more difficult to brute forcing the password. +# But note also that it more CPU resources will be needed to authenticate +# users. +# +# If not specified, the libc will choose the default number of rounds (5000). +# The values must be inside the 1000-999999999 range. +# If only one of the MIN or MAX values is set, then this value will be used. +# If MIN > MAX, the highest value will be used. +# +# SHA_CRYPT_MIN_ROUNDS 5000 +# SHA_CRYPT_MAX_ROUNDS 5000 + +################# OBSOLETED BY PAM ############## +# # +# These options are now handled by PAM. Please # +# edit the appropriate file in /etc/pam.d/ to # +# enable the equivelants of them. +# +############### + +#MOTD_FILE +#DIALUPS_CHECK_ENAB +#LASTLOG_ENAB +#MAIL_CHECK_ENAB +#OBSCURE_CHECKS_ENAB +#PORTTIME_CHECKS_ENAB +#SU_WHEEL_ONLY +#CRACKLIB_DICTPATH +#PASS_CHANGE_TRIES +#PASS_ALWAYS_WARN +#ENVIRON_FILE +#NOLOGINS_FILE +#ISSUE_FILE +#PASS_MIN_LEN +#PASS_MAX_LEN +#ULIMIT +#ENV_HZ +#CHFN_AUTH +#CHSH_AUTH +#FAIL_DELAY + +################# OBSOLETED ####################### +# # +# These options are no more handled by shadow. # +# # +# Shadow utilities will display a warning if they # +# still appear. # +# # +################################################### + +# CLOSE_SESSIONS +# LOGIN_STRING +# NO_PASSWORD_CONSOLE +# QMAIL_DIR + + + diff --git a/logrotate.conf b/logrotate.conf new file mode 100644 index 00000000..21c38247 --- /dev/null +++ b/logrotate.conf @@ -0,0 +1,9 @@ +# THIS FILE IS AUTOMATICALLY DISTRIBUTED BY PUPPET. +# ANY CHANGES WILL BE OVERWRITTEN. + +create +rotate 4 +weekly + +# configurable file rotations +include /etc/logrotate.d diff --git a/logrotate.d/apt b/logrotate.d/apt new file mode 100644 index 00000000..706d3d8f --- /dev/null +++ b/logrotate.d/apt @@ -0,0 +1,14 @@ +# THIS FILE IS AUTOMATICALLY DISTRIBUTED BY PUPPET. ANY CHANGES WILL BE +# OVERWRITTEN. + +/var/log/apt/term.log /var/log/apt/history.log { + compress + delaycompress + missingok + notifempty + rotate 4 + weekly + postrotate + invoke-rc.d rsyslog rotate > /dev/null + endscript +} diff --git a/logrotate.d/btmp b/logrotate.d/btmp new file mode 100644 index 00000000..2258fb2f --- /dev/null +++ b/logrotate.d/btmp @@ -0,0 +1,9 @@ +# THIS FILE IS AUTOMATICALLY DISTRIBUTED BY PUPPET. ANY CHANGES WILL BE +# OVERWRITTEN. + +/var/log/btmp { + create 0600 root utmp + missingok + monthly + rotate 1 +} diff --git a/logrotate.d/dpkg b/logrotate.d/dpkg new file mode 100644 index 00000000..e46cda4f --- /dev/null +++ b/logrotate.d/dpkg @@ -0,0 +1,14 @@ +# THIS FILE IS AUTOMATICALLY DISTRIBUTED BY PUPPET. ANY CHANGES WILL BE +# OVERWRITTEN. + +/var/log/dpkg.log /var/log/alternatives.log { + compress + delaycompress + missingok + notifempty + rotate 4 + weekly + postrotate + invoke-rc.d rsyslog rotate > /dev/null + endscript +} diff --git a/logrotate.d/exim4-base b/logrotate.d/exim4-base new file mode 100644 index 00000000..ac31dd44 --- /dev/null +++ b/logrotate.d/exim4-base @@ -0,0 +1,9 @@ +/var/log/exim4/mainlog /var/log/exim4/rejectlog { + daily + missingok + rotate 10 + compress + delaycompress + notifempty + create 640 Debian-exim adm +} diff --git a/logrotate.d/exim4-paniclog b/logrotate.d/exim4-paniclog new file mode 100644 index 00000000..dd36d687 --- /dev/null +++ b/logrotate.d/exim4-paniclog @@ -0,0 +1,10 @@ +/var/log/exim4/paniclog { + size 10M + missingok + rotate 10 + compress + delaycompress + notifempty + create 640 Debian-exim adm +} + diff --git a/logrotate.d/mosquitto b/logrotate.d/mosquitto new file mode 100644 index 00000000..aa61c0b9 --- /dev/null +++ b/logrotate.d/mosquitto @@ -0,0 +1,14 @@ +/var/log/mosquitto/mosquitto.log { + rotate 7 + daily + compress + size 100k + nocreate + missingok + postrotate + if invoke-rc.d mosquitto status > /dev/null 2>&1; then \ + invoke-rc.d mosquitto reload > /dev/null 2>&1; \ + fi; + endscript +} + diff --git a/logrotate.d/nginx b/logrotate.d/nginx new file mode 100644 index 00000000..423c6ad1 --- /dev/null +++ b/logrotate.d/nginx @@ -0,0 +1,18 @@ +/var/log/nginx/*.log { + daily + missingok + rotate 14 + compress + delaycompress + notifempty + create 0640 www-data adm + sharedscripts + prerotate + if [ -d /etc/logrotate.d/httpd-prerotate ]; then \ + run-parts /etc/logrotate.d/httpd-prerotate; \ + fi \ + endscript + postrotate + invoke-rc.d nginx rotate >/dev/null 2>&1 + endscript +} diff --git a/logrotate.d/nodered b/logrotate.d/nodered new file mode 100644 index 00000000..a14cc691 --- /dev/null +++ b/logrotate.d/nodered @@ -0,0 +1,9 @@ +/var/log/nodered-install.log +{ + rotate 4 + weekly + missingok + notifempty + compress + delaycompress +} diff --git a/logrotate.d/php7.3-fpm b/logrotate.d/php7.3-fpm new file mode 100644 index 00000000..124db408 --- /dev/null +++ b/logrotate.d/php7.3-fpm @@ -0,0 +1,11 @@ +/var/log/php7.3-fpm.log { + rotate 12 + weekly + missingok + notifempty + compress + delaycompress + postrotate + /usr/lib/php/php7.3-fpm-reopenlogs + endscript +} diff --git a/logrotate.d/postgresql-common b/logrotate.d/postgresql-common new file mode 100644 index 00000000..0cbf10a5 --- /dev/null +++ b/logrotate.d/postgresql-common @@ -0,0 +1,10 @@ +/var/log/postgresql/*.log { + weekly + rotate 10 + copytruncate + delaycompress + compress + notifempty + missingok + su root root +} diff --git a/logrotate.d/rsyslog b/logrotate.d/rsyslog new file mode 100644 index 00000000..5db0681c --- /dev/null +++ b/logrotate.d/rsyslog @@ -0,0 +1,15 @@ +# THIS FILE IS AUTOMATICALLY DISTRIBUTED BY PUPPET. ANY CHANGES WILL BE +# OVERWRITTEN. + +/var/log/messages /var/log/debug /var/log/cron.log /var/log/lpr.log /var/log/user.log /var/log/auth.log /var/log/kern.log /var/log/daemon.log /var/log/mail.log /var/log/mail.err /var/log/mail.warn /var/log/mail.info { + compress + delaycompress + missingok + notifempty + rotate 4 + sharedscripts + weekly + postrotate + invoke-rc.d rsyslog rotate > /dev/null + endscript +} diff --git a/logrotate.d/syslog b/logrotate.d/syslog new file mode 100644 index 00000000..7f703f09 --- /dev/null +++ b/logrotate.d/syslog @@ -0,0 +1,14 @@ +# THIS FILE IS AUTOMATICALLY DISTRIBUTED BY PUPPET. ANY CHANGES WILL BE +# OVERWRITTEN. + +/var/log/syslog { + compress + daily + delaycompress + missingok + notifempty + rotate 7 + postrotate + invoke-rc.d rsyslog rotate > /dev/null + endscript +} diff --git a/logrotate.d/wtmp b/logrotate.d/wtmp new file mode 100644 index 00000000..664a832d --- /dev/null +++ b/logrotate.d/wtmp @@ -0,0 +1,9 @@ +# THIS FILE IS AUTOMATICALLY DISTRIBUTED BY PUPPET. ANY CHANGES WILL BE +# OVERWRITTEN. + +/var/log/wtmp { + create 0664 root utmp + missingok + monthly + rotate 1 +} diff --git a/machine-id b/machine-id new file mode 100644 index 00000000..b5e6fe20 --- /dev/null +++ b/machine-id @@ -0,0 +1 @@ +5fd92f790d6840e2b8fc4feb29678576 diff --git a/magic b/magic new file mode 100644 index 00000000..283a8639 --- /dev/null +++ b/magic @@ -0,0 +1,3 @@ +# Magic local data for file(1) command. +# Insert here your local magic data. Format is described in magic(5). + diff --git a/magic.mime b/magic.mime new file mode 100644 index 00000000..283a8639 --- /dev/null +++ b/magic.mime @@ -0,0 +1,3 @@ +# Magic local data for file(1) command. +# Insert here your local magic data. Format is described in magic(5). + diff --git a/mailcap b/mailcap new file mode 100644 index 00000000..b8f1b311 --- /dev/null +++ b/mailcap @@ -0,0 +1,66 @@ +############################################################################### +# +# MIME media types and programs that process those types +# +# Much of this file is generated automatically by the program "update-mime". +# Please see the "update-mime" man page for more information. +# +# Users can add their own rules if they wish by creating a ".mailcap" +# file in their home directory. Entries included there will take +# precedence over those listed here. +# +############################################################################### + + +############################################################################### +# +# User section follows: Any entries included in this section will take +# precedence over those created by "update-mime". DO NOT CHANGE the +# "User Section Begins" and "User Section Ends" lines, or anything outside +# of this section! +# + +# ----- User Section Begins ----- # +# ----- User Section Ends ----- # + +############################################################################### + +text/plain; less '%s'; needsterminal +application/x-troff-man; /usr/bin/man -X100 -l '%s'; test=test -n "$DISPLAY" -a -e /usr/bin/gxditview; description=Man page +text/troff; /usr/bin/man -X100 -l '%s'; test=test -n "$DISPLAY" -a -e /usr/bin/gxditview; description=Man page +application/x-troff-man; /usr/bin/man -l '%s'; needsterminal; description=Man page +text/troff; /usr/bin/man -l '%s'; needsterminal; description=Man page +text/html; /usr/bin/sensible-browser %s; description=HTML Text; nametemplate=%s.html +application/x-troff-man; /usr/bin/nroff -mandoc -Tutf8; copiousoutput; print=/usr/bin/nroff -mandoc -Tutf8 | print text/plain:- +text/troff; /usr/bin/nroff -mandoc -Tutf8; copiousoutput; print=/usr/bin/nroff -mandoc -Tutf8 | print text/plain:- +application/x-info; /usr/bin/info -f '%s'; needsterminal; description=GNU Info document +text/plain; more %s; needsterminal +text/english; vim %s; needsterminal +text/plain; vim %s; needsterminal +text/x-makefile; vim %s; needsterminal +text/x-c++hdr; vim %s; needsterminal +text/x-c++src; vim %s; needsterminal +text/x-chdr; vim %s; needsterminal +text/x-csrc; vim %s; needsterminal +text/x-java; vim %s; needsterminal +text/x-moc; vim %s; needsterminal +text/x-pascal; vim %s; needsterminal +text/x-tcl; vim %s; needsterminal +text/x-tex; vim %s; needsterminal +application/x-shellscript; vim %s; needsterminal +text/x-c; vim %s; needsterminal +text/x-c++; vim %s; needsterminal +text/plain; view %s; edit=vim %s; compose=vim %s; test=test -x /usr/bin/vim; needsterminal +application/zip; unzip -l %s; nametemplate=%s.zip; copiousoutput +text/plain; view %s; edit=vi %s; compose=vi %s; needsterminal +application/x-troff-man; /usr/bin/man -Tascii -l '%s' | col -b; copiousoutput; description=Man page +text/troff; /usr/bin/man -Tascii -l '%s' | col -b; copiousoutput; description=Man page +text/*; less '%s'; needsterminal +text/*; view %s; edit=vim %s; compose=vim %s; test=test -x /usr/bin/vim; needsterminal +application/x-info; /usr/bin/info --subnodes -o /dev/stdout -f '%s' 2>/dev/null; copiousoutput; description=GNU Info document +application/x-tar; /bin/tar tvf '%s'; print=/bin/tar tvf - | print text/plain:-; copiousoutput +application/x-gtar; /bin/tar tvf '%s'; print=/bin/tar tvf - | print text/plain:-; copiousoutput +application/x-ustar; /bin/tar tvf '%s'; print=/bin/tar tvf - | print text/plain:-; copiousoutput +text/*; more %s; needsterminal +text/*; view %s; edit=vi %s; compose=vi %s; needsterminal +application/vnd.debian.binary-package; /usr/lib/mime/debian-view %s; needsterminal; description=Debian GNU/Linux Package; nametemplate=%s.deb diff --git a/mailcap.order b/mailcap.order new file mode 100644 index 00000000..7f38c230 --- /dev/null +++ b/mailcap.order @@ -0,0 +1,10 @@ +############################################################################### +# +# Mailcap.order: This file allows a system-wide override of MIME program +# preferences. See the mailcap.order(5) man page for more information. +# +# After modifying this file, be sure to run /usr/sbin/update-mime (as root) +# to propagate the changes into the /etc/mailcap file. +# +################################################################################ + diff --git a/mailname b/mailname new file mode 100644 index 00000000..324b8054 --- /dev/null +++ b/mailname @@ -0,0 +1 @@ +serviceraspi.realm.local diff --git a/manpath.config b/manpath.config new file mode 100644 index 00000000..722a52d6 --- /dev/null +++ b/manpath.config @@ -0,0 +1,131 @@ +# manpath.config +# +# This file is used by the man-db package to configure the man and cat paths. +# It is also used to provide a manpath for those without one by examining +# their PATH environment variable. For details see the manpath(5) man page. +# +# Lines beginning with `#' are comments and are ignored. Any combination of +# tabs or spaces may be used as `whitespace' separators. +# +# There are three mappings allowed in this file: +# -------------------------------------------------------- +# MANDATORY_MANPATH manpath_element +# MANPATH_MAP path_element manpath_element +# MANDB_MAP global_manpath [relative_catpath] +#--------------------------------------------------------- +# every automatically generated MANPATH includes these fields +# +#MANDATORY_MANPATH /usr/src/pvm3/man +# +MANDATORY_MANPATH /usr/man +MANDATORY_MANPATH /usr/share/man +MANDATORY_MANPATH /usr/local/share/man +#--------------------------------------------------------- +# set up PATH to MANPATH mapping +# ie. what man tree holds man pages for what binary directory. +# +# *PATH* -> *MANPATH* +# +MANPATH_MAP /bin /usr/share/man +MANPATH_MAP /usr/bin /usr/share/man +MANPATH_MAP /sbin /usr/share/man +MANPATH_MAP /usr/sbin /usr/share/man +MANPATH_MAP /usr/local/bin /usr/local/man +MANPATH_MAP /usr/local/bin /usr/local/share/man +MANPATH_MAP /usr/local/sbin /usr/local/man +MANPATH_MAP /usr/local/sbin /usr/local/share/man +MANPATH_MAP /usr/X11R6/bin /usr/X11R6/man +MANPATH_MAP /usr/bin/X11 /usr/X11R6/man +MANPATH_MAP /usr/games /usr/share/man +MANPATH_MAP /opt/bin /opt/man +MANPATH_MAP /opt/sbin /opt/man +#--------------------------------------------------------- +# For a manpath element to be treated as a system manpath (as most of those +# above should normally be), it must be mentioned below. Each line may have +# an optional extra string indicating the catpath associated with the +# manpath. If no catpath string is used, the catpath will default to the +# given manpath. +# +# You *must* provide all system manpaths, including manpaths for alternate +# operating systems, locale specific manpaths, and combinations of both, if +# they exist, otherwise the permissions of the user running man/mandb will +# be used to manipulate the manual pages. Also, mandb will not initialise +# the database cache for any manpaths not mentioned below unless explicitly +# requested to do so. +# +# In a per-user configuration file, this directive only controls the +# location of catpaths and the creation of database caches; it has no effect +# on privileges. +# +# Any manpaths that are subdirectories of other manpaths must be mentioned +# *before* the containing manpath. E.g. /usr/man/preformat must be listed +# before /usr/man. +# +# *MANPATH* -> *CATPATH* +# +MANDB_MAP /usr/man /var/cache/man/fsstnd +MANDB_MAP /usr/share/man /var/cache/man +MANDB_MAP /usr/local/man /var/cache/man/oldlocal +MANDB_MAP /usr/local/share/man /var/cache/man/local +MANDB_MAP /usr/X11R6/man /var/cache/man/X11R6 +MANDB_MAP /opt/man /var/cache/man/opt +# +#--------------------------------------------------------- +# Program definitions. These are commented out by default as the value +# of the definition is already the default. To change: uncomment a +# definition and modify it. +# +#DEFINE pager pager +#DEFINE cat cat +#DEFINE tr tr '\255\267\264\327' '\055\157\047\170' +#DEFINE grep grep +#DEFINE troff groff -mandoc +#DEFINE nroff nroff -mandoc +#DEFINE eqn eqn +#DEFINE neqn neqn +#DEFINE tbl tbl +#DEFINE col col +#DEFINE vgrind vgrind +#DEFINE refer refer +#DEFINE grap grap +#DEFINE pic pic -S +# +#DEFINE compressor gzip -c7 +#--------------------------------------------------------- +# Misc definitions: same as program definitions above. +# +#DEFINE whatis_grep_flags -i +#DEFINE apropos_grep_flags -iEw +#DEFINE apropos_regex_grep_flags -iE +#--------------------------------------------------------- +# Section names. Manual sections will be searched in the order listed here; +# the default is 1, n, l, 8, 3, 0, 2, 5, 4, 9, 6, 7. Multiple SECTION +# directives may be given for clarity, and will be concatenated together in +# the expected way. +# If a particular extension is not in this list (say, 1mh), it will be +# displayed with the rest of the section it belongs to. The effect of this +# is that you only need to explicitly list extensions if you want to force a +# particular order. Sections with extensions should usually be adjacent to +# their main section (e.g. "1 1mh 8 ..."). +# +SECTION 1 n l 8 3 2 3posix 3pm 3perl 3am 5 4 9 6 7 +# +#--------------------------------------------------------- +# Range of terminal widths permitted when displaying cat pages. If the +# terminal falls outside this range, cat pages will not be created (if +# missing) or displayed. +# +#MINCATWIDTH 80 +#MAXCATWIDTH 80 +# +# If CATWIDTH is set to a non-zero number, cat pages will always be +# formatted for a terminal of the given width, regardless of the width of +# the terminal actually being used. This should generally be within the +# range set by MINCATWIDTH and MAXCATWIDTH. +# +#CATWIDTH 0 +# +#--------------------------------------------------------- +# Flags. +# NOCACHE keeps man from creating cat pages. +#NOCACHE diff --git a/mime.types b/mime.types new file mode 100644 index 00000000..6e3eabb8 --- /dev/null +++ b/mime.types @@ -0,0 +1,845 @@ +############################################################################### +# +# MIME media types and the extensions that represent them. +# +# The format of this file is a media type on the left and zero or more +# filename extensions on the right. Programs using this file will map +# files ending with those extensions to the associated type. +# +# This file is part of the "mime-support" package. Please report a bug using +# the "reportbug" command of the "reportbug" package if you would like new +# types or extensions to be added. +# +# The reason that all types are managed by the mime-support package instead +# allowing individual packages to install types in much the same way as they +# add entries in to the mailcap file is so these types can be referenced by +# other programs (such as a web server) even if the specific support package +# for that type is not installed. +# +# Users can add their own types if they wish by creating a ".mime.types" +# file in their home directory. Definitions included there will take +# precedence over those listed here. +# +############################################################################### + + +application/activemessage +application/andrew-inset ez +application/annodex anx +application/applefile +application/atom+xml atom +application/atomcat+xml atomcat +application/atomicmail +application/atomserv+xml atomsrv +application/batch-SMTP +application/bbolin lin +application/beep+xml +application/cals-1840 +application/commonground +application/cu-seeme cu +application/cybercash +application/davmount+xml davmount +application/dca-rft +application/dec-dx +application/dicom dcm +application/docbook+xml +application/dsptype tsp +application/dvcs +application/ecmascript es +application/edi-consent +application/edi-x12 +application/edifact +application/epub+zip epub +application/eshop +application/font-sfnt otf ttf +application/font-tdpfr pfr +application/font-woff woff +application/futuresplash spl +application/ghostview +application/gzip gz +application/hta hta +application/http +application/hyperstudio +application/iges +application/index +application/index.cmd +application/index.obj +application/index.response +application/index.vnd +application/iotp +application/ipp +application/isup +application/java-archive jar +application/java-serialized-object ser +application/java-vm class +application/javascript js +application/json json +application/m3g m3g +application/mac-binhex40 hqx +application/mac-compactpro cpt +application/macwriteii +application/marc +application/mathematica nb nbp +application/mbox mbox +application/ms-tnef +application/msaccess mdb +application/msword doc dot +application/mxf mxf +application/news-message-id +application/news-transmission +application/ocsp-request +application/ocsp-response +application/octet-stream bin deploy msu msp +application/oda oda +application/oebps-package+xml opf +application/ogg ogx +application/onenote one onetoc2 onetmp onepkg +application/parityfec +application/pdf pdf +application/pgp-encrypted pgp +application/pgp-keys key +application/pgp-signature sig +application/pics-rules prf +application/pkcs10 +application/pkcs7-mime +application/pkcs7-signature +application/pkix-cert +application/pkix-crl +application/pkixcmp +application/postscript ps ai eps epsi epsf eps2 eps3 +application/prs.alvestrand.titrax-sheet +application/prs.cww +application/prs.nprend +application/qsig +application/rar rar +application/rdf+xml rdf +application/remote-printing +application/riscos +application/rtf rtf +application/sdp +application/set-payment +application/set-payment-initiation +application/set-registration +application/set-registration-initiation +application/sgml +application/sgml-open-catalog +application/sieve +application/sla stl +application/slate +application/smil+xml smi smil +application/timestamp-query +application/timestamp-reply +application/vemmi +application/wasm wasm +application/whoispp-query +application/whoispp-response +application/wita +application/x400-bp +application/xhtml+xml xhtml xht +application/xml xml xsd +application/xml-dtd +application/xml-external-parsed-entity +application/xslt+xml xsl xslt +application/xspf+xml xspf +application/zip zip +application/vnd.3M.Post-it-Notes +application/vnd.accpac.simply.aso +application/vnd.accpac.simply.imp +application/vnd.acucobol +application/vnd.aether.imp +application/vnd.android.package-archive apk +application/vnd.anser-web-certificate-issue-initiation +application/vnd.anser-web-funds-transfer-initiation +application/vnd.audiograph +application/vnd.bmi +application/vnd.businessobjects +application/vnd.canon-cpdl +application/vnd.canon-lips +application/vnd.cinderella cdy +application/vnd.claymore +application/vnd.commerce-battelle +application/vnd.commonspace +application/vnd.comsocaller +application/vnd.contact.cmsg +application/vnd.cosmocaller +application/vnd.ctc-posml +application/vnd.cups-postscript +application/vnd.cups-raster +application/vnd.cups-raw +application/vnd.cybank +application/vnd.debian.binary-package deb ddeb udeb +application/vnd.dna +application/vnd.dpgraph +application/vnd.dxr +application/vnd.ecdis-update +application/vnd.ecowin.chart +application/vnd.ecowin.filerequest +application/vnd.ecowin.fileupdate +application/vnd.ecowin.series +application/vnd.ecowin.seriesrequest +application/vnd.ecowin.seriesupdate +application/vnd.enliven +application/vnd.epson.esf +application/vnd.epson.msf +application/vnd.epson.quickanime +application/vnd.epson.salt +application/vnd.epson.ssf +application/vnd.ericsson.quickcall +application/vnd.eudora.data +application/vnd.fdf +application/vnd.ffsns +application/vnd.flographit +application/vnd.font-fontforge-sfd sfd +application/vnd.framemaker +application/vnd.fsc.weblaunch +application/vnd.fujitsu.oasys +application/vnd.fujitsu.oasys2 +application/vnd.fujitsu.oasys3 +application/vnd.fujitsu.oasysgp +application/vnd.fujitsu.oasysprs +application/vnd.fujixerox.ddd +application/vnd.fujixerox.docuworks +application/vnd.fujixerox.docuworks.binder +application/vnd.fut-misnet +application/vnd.google-earth.kml+xml kml +application/vnd.google-earth.kmz kmz +application/vnd.grafeq +application/vnd.groove-account +application/vnd.groove-identity-message +application/vnd.groove-injector +application/vnd.groove-tool-message +application/vnd.groove-tool-template +application/vnd.groove-vcard +application/vnd.hhe.lesson-player +application/vnd.hp-HPGL +application/vnd.hp-PCL +application/vnd.hp-PCLXL +application/vnd.hp-hpid +application/vnd.hp-hps +application/vnd.httphone +application/vnd.hzn-3d-crossword +application/vnd.ibm.MiniPay +application/vnd.ibm.afplinedata +application/vnd.ibm.modcap +application/vnd.informix-visionary +application/vnd.intercon.formnet +application/vnd.intertrust.digibox +application/vnd.intertrust.nncp +application/vnd.intu.qbo +application/vnd.intu.qfx +application/vnd.irepository.package+xml +application/vnd.is-xpr +application/vnd.japannet-directory-service +application/vnd.japannet-jpnstore-wakeup +application/vnd.japannet-payment-wakeup +application/vnd.japannet-registration +application/vnd.japannet-registration-wakeup +application/vnd.japannet-setstore-wakeup +application/vnd.japannet-verification +application/vnd.japannet-verification-wakeup +application/vnd.koan +application/vnd.lotus-1-2-3 +application/vnd.lotus-approach +application/vnd.lotus-freelance +application/vnd.lotus-notes +application/vnd.lotus-organizer +application/vnd.lotus-screencam +application/vnd.lotus-wordpro +application/vnd.mcd +application/vnd.mediastation.cdkey +application/vnd.meridian-slingshot +application/vnd.mif +application/vnd.minisoft-hp3000-save +application/vnd.mitsubishi.misty-guard.trustweb +application/vnd.mobius.daf +application/vnd.mobius.dis +application/vnd.mobius.msl +application/vnd.mobius.plc +application/vnd.mobius.txf +application/vnd.motorola.flexsuite +application/vnd.motorola.flexsuite.adsi +application/vnd.motorola.flexsuite.fis +application/vnd.motorola.flexsuite.gotap +application/vnd.motorola.flexsuite.kmr +application/vnd.motorola.flexsuite.ttc +application/vnd.motorola.flexsuite.wem +application/vnd.mozilla.xul+xml xul +application/vnd.ms-artgalry +application/vnd.ms-asf +application/vnd.ms-excel xls xlb xlt +application/vnd.ms-excel.addin.macroEnabled.12 xlam +application/vnd.ms-excel.sheet.binary.macroEnabled.12 xlsb +application/vnd.ms-excel.sheet.macroEnabled.12 xlsm +application/vnd.ms-excel.template.macroEnabled.12 xltm +application/vnd.ms-fontobject eot +application/vnd.ms-lrm +application/vnd.ms-officetheme thmx +application/vnd.ms-pki.seccat cat +#application/vnd.ms-pki.stl stl +application/vnd.ms-powerpoint ppt pps +application/vnd.ms-powerpoint.addin.macroEnabled.12 ppam +application/vnd.ms-powerpoint.presentation.macroEnabled.12 pptm +application/vnd.ms-powerpoint.slide.macroEnabled.12 sldm +application/vnd.ms-powerpoint.slideshow.macroEnabled.12 ppsm +application/vnd.ms-powerpoint.template.macroEnabled.12 potm +application/vnd.ms-project +application/vnd.ms-tnef +application/vnd.ms-word.document.macroEnabled.12 docm +application/vnd.ms-word.template.macroEnabled.12 dotm +application/vnd.ms-works +application/vnd.mseq +application/vnd.msign +application/vnd.music-niff +application/vnd.musician +application/vnd.netfpx +application/vnd.noblenet-directory +application/vnd.noblenet-sealer +application/vnd.noblenet-web +application/vnd.novadigm.EDM +application/vnd.novadigm.EDX +application/vnd.novadigm.EXT +application/vnd.oasis.opendocument.chart odc +application/vnd.oasis.opendocument.database odb +application/vnd.oasis.opendocument.formula odf +application/vnd.oasis.opendocument.graphics odg +application/vnd.oasis.opendocument.graphics-template otg +application/vnd.oasis.opendocument.image odi +application/vnd.oasis.opendocument.presentation odp +application/vnd.oasis.opendocument.presentation-template otp +application/vnd.oasis.opendocument.spreadsheet ods +application/vnd.oasis.opendocument.spreadsheet-template ots +application/vnd.oasis.opendocument.text odt +application/vnd.oasis.opendocument.text-master odm +application/vnd.oasis.opendocument.text-template ott +application/vnd.oasis.opendocument.text-web oth +application/vnd.openxmlformats-officedocument.presentationml.presentation pptx +application/vnd.openxmlformats-officedocument.presentationml.slide sldx +application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx +application/vnd.openxmlformats-officedocument.presentationml.template potx +application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx +application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx +application/vnd.openxmlformats-officedocument.wordprocessingml.document docx +application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx +application/vnd.osa.netdeploy +application/vnd.palm +application/vnd.pg.format +application/vnd.pg.osasli +application/vnd.powerbuilder6 +application/vnd.powerbuilder6-s +application/vnd.powerbuilder7 +application/vnd.powerbuilder7-s +application/vnd.powerbuilder75 +application/vnd.powerbuilder75-s +application/vnd.previewsystems.box +application/vnd.publishare-delta-tree +application/vnd.pvi.ptid1 +application/vnd.pwg-xhtml-print+xml +application/vnd.rapid +application/vnd.rim.cod cod +application/vnd.s3sms +application/vnd.seemail +application/vnd.shana.informed.formdata +application/vnd.shana.informed.formtemplate +application/vnd.shana.informed.interchange +application/vnd.shana.informed.package +application/vnd.smaf mmf +application/vnd.sss-cod +application/vnd.sss-dtf +application/vnd.sss-ntf +application/vnd.stardivision.calc sdc +application/vnd.stardivision.chart sds +application/vnd.stardivision.draw sda +application/vnd.stardivision.impress sdd +application/vnd.stardivision.math sdf +application/vnd.stardivision.writer sdw +application/vnd.stardivision.writer-global sgl +application/vnd.street-stream +application/vnd.sun.xml.calc sxc +application/vnd.sun.xml.calc.template stc +application/vnd.sun.xml.draw sxd +application/vnd.sun.xml.draw.template std +application/vnd.sun.xml.impress sxi +application/vnd.sun.xml.impress.template sti +application/vnd.sun.xml.math sxm +application/vnd.sun.xml.writer sxw +application/vnd.sun.xml.writer.global sxg +application/vnd.sun.xml.writer.template stw +application/vnd.svd +application/vnd.swiftview-ics +application/vnd.symbian.install sis +application/vnd.tcpdump.pcap cap pcap +application/vnd.triscape.mxs +application/vnd.trueapp +application/vnd.truedoc +application/vnd.tve-trigger +application/vnd.ufdl +application/vnd.uplanet.alert +application/vnd.uplanet.alert-wbxml +application/vnd.uplanet.bearer-choice +application/vnd.uplanet.bearer-choice-wbxml +application/vnd.uplanet.cacheop +application/vnd.uplanet.cacheop-wbxml +application/vnd.uplanet.channel +application/vnd.uplanet.channel-wbxml +application/vnd.uplanet.list +application/vnd.uplanet.list-wbxml +application/vnd.uplanet.listcmd +application/vnd.uplanet.listcmd-wbxml +application/vnd.uplanet.signal +application/vnd.vcx +application/vnd.vectorworks +application/vnd.vidsoft.vidconference +application/vnd.visio vsd vst vsw vss +application/vnd.vividence.scriptfile +application/vnd.wap.sic +application/vnd.wap.slc +application/vnd.wap.wbxml wbxml +application/vnd.wap.wmlc wmlc +application/vnd.wap.wmlscriptc wmlsc +application/vnd.webturbo +application/vnd.wordperfect wpd +application/vnd.wordperfect5.1 wp5 +application/vnd.wrq-hp3000-labelled +application/vnd.wt.stf +application/vnd.xara +application/vnd.xfdl +application/vnd.yellowriver-custom-menu +application/zlib +application/x-123 wk +application/x-7z-compressed 7z +application/x-abiword abw +application/x-apple-diskimage dmg +application/x-bcpio bcpio +application/x-bittorrent torrent +application/x-cab cab +application/x-cbr cbr +application/x-cbz cbz +application/x-cdf cdf cda +application/x-cdlink vcd +application/x-chess-pgn pgn +application/x-comsol mph +application/x-core +application/x-cpio cpio +application/x-csh csh +application/x-debian-package deb udeb +application/x-director dcr dir dxr +application/x-dms dms +application/x-doom wad +application/x-dvi dvi +application/x-executable +application/x-font pfa pfb gsf +application/x-font-pcf pcf pcf.Z +application/x-freemind mm +application/x-futuresplash spl +application/x-ganttproject gan +application/x-gnumeric gnumeric +application/x-go-sgf sgf +application/x-graphing-calculator gcf +application/x-gtar gtar +application/x-gtar-compressed tgz taz +application/x-hdf hdf +#application/x-httpd-eruby rhtml +#application/x-httpd-php phtml pht php +#application/x-httpd-php-source phps +#application/x-httpd-php3 php3 +#application/x-httpd-php3-preprocessed php3p +#application/x-httpd-php4 php4 +#application/x-httpd-php5 php5 +application/x-hwp hwp +application/x-ica ica +application/x-info info +application/x-internet-signup ins isp +application/x-iphone iii +application/x-iso9660-image iso +application/x-jam jam +application/x-java-applet +application/x-java-bean +application/x-java-jnlp-file jnlp +application/x-jmol jmz +application/x-kchart chrt +application/x-kdelnk +application/x-killustrator kil +application/x-koan skp skd skt skm +application/x-kpresenter kpr kpt +application/x-kspread ksp +application/x-kword kwd kwt +application/x-latex latex +application/x-lha lha +application/x-lyx lyx +application/x-lzh lzh +application/x-lzx lzx +application/x-maker frm maker frame fm fb book fbdoc +application/x-mif mif +application/x-mpegURL m3u8 +application/x-ms-application application +application/x-ms-manifest manifest +application/x-ms-wmd wmd +application/x-ms-wmz wmz +application/x-msdos-program com exe bat dll +application/x-msi msi +application/x-netcdf nc +application/x-ns-proxy-autoconfig pac +application/x-nwc nwc +application/x-object o +application/x-oz-application oza +application/x-pkcs7-certreqresp p7r +application/x-pkcs7-crl crl +application/x-python-code pyc pyo +application/x-qgis qgs shp shx +application/x-quicktimeplayer qtl +application/x-rdp rdp +application/x-redhat-package-manager rpm +application/x-rss+xml rss +application/x-ruby rb +application/x-rx +application/x-scilab sci sce +application/x-scilab-xcos xcos +application/x-sh sh +application/x-shar shar +application/x-shellscript +application/x-shockwave-flash swf swfl +application/x-silverlight scr +application/x-sql sql +application/x-stuffit sit sitx +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-tar tar +application/x-tcl tcl +application/x-tex-gf gf +application/x-tex-pk pk +application/x-texinfo texinfo texi +application/x-trash ~ % bak old sik +application/x-troff t tr roff +application/x-troff-man man +application/x-troff-me me +application/x-troff-ms ms +application/x-ustar ustar +application/x-videolan +application/x-wais-source src +application/x-wingz wz +application/x-x509-ca-cert crt +application/x-xcf xcf +application/x-xfig fig +application/x-xpinstall xpi +application/x-xz xz + +audio/32kadpcm +audio/3gpp +audio/amr amr +audio/amr-wb awb +audio/annodex axa +audio/basic au snd +audio/csound csd orc sco +audio/flac flac +audio/g.722.1 +audio/l16 +audio/midi mid midi kar +audio/mp4a-latm +audio/mpa-robust +audio/mpeg mpga mpega mp2 mp3 m4a +audio/mpegurl m3u +audio/ogg oga ogg opus spx +audio/parityfec +audio/prs.sid sid +audio/telephone-event +audio/tone +audio/vnd.cisco.nse +audio/vnd.cns.anp1 +audio/vnd.cns.inf1 +audio/vnd.digital-winds +audio/vnd.everad.plj +audio/vnd.lucent.voice +audio/vnd.nortel.vbk +audio/vnd.nuera.ecelp4800 +audio/vnd.nuera.ecelp7470 +audio/vnd.nuera.ecelp9600 +audio/vnd.octel.sbc +audio/vnd.qcelp +audio/vnd.rhetorex.32kadpcm +audio/vnd.vmx.cvsd +audio/x-aiff aif aiff aifc +audio/x-gsm gsm +audio/x-mpegurl m3u +audio/x-ms-wma wma +audio/x-ms-wax wax +audio/x-pn-realaudio-plugin +audio/x-pn-realaudio ra rm ram +audio/x-realaudio ra +audio/x-scpls pls +audio/x-sd2 sd2 +audio/x-wav wav + +chemical/x-alchemy alc +chemical/x-cache cac cache +chemical/x-cache-csf csf +chemical/x-cactvs-binary cbin cascii ctab +chemical/x-cdx cdx +chemical/x-cerius cer +chemical/x-chem3d c3d +chemical/x-chemdraw chm +chemical/x-cif cif +chemical/x-cmdf cmdf +chemical/x-cml cml +chemical/x-compass cpa +chemical/x-crossfire bsd +chemical/x-csml csml csm +chemical/x-ctx ctx +chemical/x-cxf cxf cef +#chemical/x-daylight-smiles smi +chemical/x-embl-dl-nucleotide emb embl +chemical/x-galactic-spc spc +chemical/x-gamess-input inp gam gamin +chemical/x-gaussian-checkpoint fch fchk +chemical/x-gaussian-cube cub +chemical/x-gaussian-input gau gjc gjf +chemical/x-gaussian-log gal +chemical/x-gcg8-sequence gcg +chemical/x-genbank gen +chemical/x-hin hin +chemical/x-isostar istr ist +chemical/x-jcamp-dx jdx dx +chemical/x-kinemage kin +chemical/x-macmolecule mcm +chemical/x-macromodel-input mmd mmod +chemical/x-mdl-molfile mol +chemical/x-mdl-rdfile rd +chemical/x-mdl-rxnfile rxn +chemical/x-mdl-sdfile sd sdf +chemical/x-mdl-tgf tgf +#chemical/x-mif mif +chemical/x-mmcif mcif +chemical/x-mol2 mol2 +chemical/x-molconn-Z b +chemical/x-mopac-graph gpt +chemical/x-mopac-input mop mopcrt mpc zmt +chemical/x-mopac-out moo +chemical/x-mopac-vib mvb +chemical/x-ncbi-asn1 asn +chemical/x-ncbi-asn1-ascii prt ent +chemical/x-ncbi-asn1-binary val aso +chemical/x-ncbi-asn1-spec asn +chemical/x-pdb pdb ent +chemical/x-rosdal ros +chemical/x-swissprot sw +chemical/x-vamas-iso14976 vms +chemical/x-vmd vmd +chemical/x-xtel xtel +chemical/x-xyz xyz + +font/collection ttc +font/otf ttf otf +font/sfnt ttf otf +font/ttf ttf otf +font/woff woff +font/woff2 woff2 + +image/cgm +image/g3fax +image/gif gif +image/ief ief +image/jp2 jp2 jpg2 +image/jpeg jpeg jpg jpe +image/jpm jpm +image/jpx jpx jpf +image/naplps +image/pcx pcx +image/png png +image/prs.btif +image/prs.pti +image/svg+xml svg svgz +image/tiff tiff tif +image/vnd.cns.inf2 +image/vnd.djvu djvu djv +image/vnd.dwg +image/vnd.dxf +image/vnd.fastbidsheet +image/vnd.fpx +image/vnd.fst +image/vnd.fujixerox.edmics-mmr +image/vnd.fujixerox.edmics-rlc +image/vnd.microsoft.icon ico +image/vnd.mix +image/vnd.net-fpx +image/vnd.svf +image/vnd.wap.wbmp wbmp +image/vnd.xiff +image/x-canon-cr2 cr2 +image/x-canon-crw crw +image/x-cmu-raster ras +image/x-coreldraw cdr +image/x-coreldrawpattern pat +image/x-coreldrawtemplate cdt +image/x-corelphotopaint cpt +image/x-epson-erf erf +image/x-icon +image/x-jg art +image/x-jng jng +image/x-ms-bmp bmp +image/x-nikon-nef nef +image/x-olympus-orf orf +image/x-photoshop psd +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-rgb rgb +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd + +inode/chardevice +inode/blockdevice +inode/directory-locked +inode/directory +inode/fifo +inode/socket + +message/delivery-status +message/disposition-notification +message/external-body +message/http +message/s-http +message/news +message/partial +message/rfc822 eml + +model/iges igs iges +model/mesh msh mesh silo +model/vnd.dwf +model/vnd.flatland.3dml +model/vnd.gdl +model/vnd.gs-gdl +model/vnd.gtw +model/vnd.mts +model/vnd.vtu +model/vrml wrl vrml +model/x3d+vrml x3dv +model/x3d+xml x3d +model/x3d+binary x3db + +multipart/alternative +multipart/appledouble +multipart/byteranges +multipart/digest +multipart/encrypted +multipart/form-data +multipart/header-set +multipart/mixed +multipart/parallel +multipart/related +multipart/report +multipart/signed +multipart/voice-message + +text/cache-manifest appcache +text/calendar ics icz +text/css css +text/csv csv +text/directory +text/english +text/enriched +text/h323 323 +text/html html htm shtml +text/iuls uls +text/mathml mml +text/markdown md markdown +text/parityfec +text/plain asc txt text pot brf srt +text/prs.lines.tag +text/rfc822-headers +text/richtext rtx +text/rtf +text/scriptlet sct wsc +text/t140 +text/texmacs tm +text/tab-separated-values tsv +text/turtle ttl +text/uri-list +text/vcard vcf vcard +text/vnd.abc +text/vnd.curl +text/vnd.debian.copyright +text/vnd.DMClientScript +text/vnd.flatland.3dml +text/vnd.fly +text/vnd.fmi.flexstor +text/vnd.in3d.3dml +text/vnd.in3d.spot +text/vnd.IPTC.NewsML +text/vnd.IPTC.NITF +text/vnd.latex-z +text/vnd.motorola.reflex +text/vnd.ms-mediapackage +text/vnd.sun.j2me.app-descriptor jad +text/vnd.wap.si +text/vnd.wap.sl +text/vnd.wap.wml wml +text/vnd.wap.wmlscript wmls +text/x-bibtex bib +text/x-boo boo +text/x-c++hdr h++ hpp hxx hh +text/x-c++src c++ cpp cxx cc +text/x-chdr h +text/x-component htc +text/x-crontab +text/x-csh csh +text/x-csrc c +text/x-dsrc d +text/x-diff diff patch +text/x-haskell hs +text/x-java java +text/x-lilypond ly +text/x-literate-haskell lhs +text/x-makefile +text/x-moc moc +text/x-pascal p pas +text/x-pcs-gcd gcd +text/x-perl pl pm +text/x-python py +text/x-scala scala +text/x-server-parsed-html +text/x-setext etx +text/x-sfv sfv +text/x-sh sh +text/x-tcl tcl tk +text/x-tex tex ltx sty cls +text/x-vcalendar vcs + +video/3gpp 3gp +video/annodex axv +video/dl dl +video/dv dif dv +video/fli fli +video/gl gl +video/mpeg mpeg mpg mpe +video/MP2T ts +video/mp4 mp4 +video/quicktime qt mov +video/mp4v-es +video/ogg ogv +video/parityfec +video/pointer +video/webm webm +video/vnd.fvt +video/vnd.motorola.video +video/vnd.motorola.videop +video/vnd.mpegurl mxu +video/vnd.mts +video/vnd.nokia.interleaved-multimedia +video/vnd.vivo +video/x-flv flv +video/x-la-asf lsf lsx +video/x-mng mng +video/x-ms-asf asf asx +video/x-ms-wm wm +video/x-ms-wmv wmv +video/x-ms-wmx wmx +video/x-ms-wvx wvx +video/x-msvideo avi +video/x-sgi-movie movie +video/x-matroska mpv mkv + +x-conference/x-cooltalk ice + +x-epoc/x-sisx-app sisx +x-world/x-vrml vrm vrml wrl diff --git a/mke2fs.conf b/mke2fs.conf new file mode 100644 index 00000000..01e35cf8 --- /dev/null +++ b/mke2fs.conf @@ -0,0 +1,47 @@ +[defaults] + base_features = sparse_super,large_file,filetype,resize_inode,dir_index,ext_attr + default_mntopts = acl,user_xattr + enable_periodic_fsck = 0 + blocksize = 4096 + inode_size = 256 + inode_ratio = 16384 + +[fs_types] + ext3 = { + features = has_journal + } + ext4 = { + features = has_journal,extent,huge_file,flex_bg,metadata_csum,64bit,dir_nlink,extra_isize + inode_size = 256 + } + small = { + blocksize = 1024 + inode_size = 128 + inode_ratio = 4096 + } + floppy = { + blocksize = 1024 + inode_size = 128 + inode_ratio = 8192 + } + big = { + inode_ratio = 32768 + } + huge = { + inode_ratio = 65536 + } + news = { + inode_ratio = 4096 + } + largefile = { + inode_ratio = 1048576 + blocksize = -1 + } + largefile4 = { + inode_ratio = 4194304 + blocksize = -1 + } + hurd = { + blocksize = 4096 + inode_size = 128 + } diff --git a/modprobe.d/blacklist-8192cu.conf b/modprobe.d/blacklist-8192cu.conf new file mode 100644 index 00000000..b1e5f14c --- /dev/null +++ b/modprobe.d/blacklist-8192cu.conf @@ -0,0 +1 @@ +blacklist 8192cu diff --git a/modprobe.d/blacklist-rtl8xxxu.conf b/modprobe.d/blacklist-rtl8xxxu.conf new file mode 100644 index 00000000..519cd30e --- /dev/null +++ b/modprobe.d/blacklist-rtl8xxxu.conf @@ -0,0 +1 @@ +blacklist rtl8xxxu diff --git a/modprobe.d/dkms.conf b/modprobe.d/dkms.conf new file mode 100644 index 00000000..508b7f4c --- /dev/null +++ b/modprobe.d/dkms.conf @@ -0,0 +1,4 @@ +# modprobe information used for DKMS modules +# +# This is a stub file, should be edited when needed, +# used by default by DKMS. diff --git a/modules b/modules new file mode 100644 index 00000000..a88e208f --- /dev/null +++ b/modules @@ -0,0 +1,5 @@ +# /etc/modules: kernel modules to load at boot time. +# +# This file contains the names of kernel modules that should be loaded +# at boot time, one per line. Lines beginning with "#" are ignored. + diff --git a/modules-load.d/modules.conf b/modules-load.d/modules.conf new file mode 120000 index 00000000..464b823a --- /dev/null +++ b/modules-load.d/modules.conf @@ -0,0 +1 @@ +../modules \ No newline at end of file diff --git a/mosquitto/ca_certificates/README b/mosquitto/ca_certificates/README new file mode 100644 index 00000000..5c015fc9 --- /dev/null +++ b/mosquitto/ca_certificates/README @@ -0,0 +1 @@ +Place your SSL/TLS Certificate Authority certificates in this directory. diff --git a/mosquitto/certs/README b/mosquitto/certs/README new file mode 100644 index 00000000..3f24ca84 --- /dev/null +++ b/mosquitto/certs/README @@ -0,0 +1,3 @@ +Place your SSL/TLS server keys and certificates in this directory. + +This directory should only be readable by the mosquitto user. diff --git a/mosquitto/conf.d/README b/mosquitto/conf.d/README new file mode 100644 index 00000000..c2798f6b --- /dev/null +++ b/mosquitto/conf.d/README @@ -0,0 +1,2 @@ +Any files placed in this directory that have a .conf ending will be loaded as +config files by the broker. Use this to make your local config. diff --git a/mosquitto/mosquitto.conf b/mosquitto/mosquitto.conf new file mode 100644 index 00000000..cb4a0368 --- /dev/null +++ b/mosquitto/mosquitto.conf @@ -0,0 +1,13 @@ +# Place your local configuration in /etc/mosquitto/conf.d/ +# +# A full description of the configuration file is at +# /usr/share/doc/mosquitto/examples/mosquitto.conf.example + +pid_file /var/run/mosquitto.pid + +persistence true +persistence_location /var/lib/mosquitto/ + +log_dest file /var/log/mosquitto/mosquitto.log + +include_dir /etc/mosquitto/conf.d diff --git a/mysql/conf.d/mysql.cnf b/mysql/conf.d/mysql.cnf new file mode 100644 index 00000000..22b052d9 --- /dev/null +++ b/mysql/conf.d/mysql.cnf @@ -0,0 +1 @@ +[mysql] diff --git a/mysql/conf.d/mysqldump.cnf b/mysql/conf.d/mysqldump.cnf new file mode 100644 index 00000000..38310a9b --- /dev/null +++ b/mysql/conf.d/mysqldump.cnf @@ -0,0 +1,4 @@ +[mysqldump] +quick +quote-names +max_allowed_packet = 16M diff --git a/mysql/mariadb.cnf b/mysql/mariadb.cnf new file mode 100644 index 00000000..94d8f107 --- /dev/null +++ b/mysql/mariadb.cnf @@ -0,0 +1,23 @@ +# The MariaDB configuration file +# +# The MariaDB/MySQL tools read configuration files in the following order: +# 1. "/etc/mysql/mariadb.cnf" (this file) to set global defaults, +# 2. "/etc/mysql/conf.d/*.cnf" to set global options. +# 3. "/etc/mysql/mariadb.conf.d/*.cnf" to set MariaDB-only options. +# 4. "~/.my.cnf" to set user-specific options. +# +# If the same option is defined multiple times, the last one will apply. +# +# One can use all long options that the program supports. +# Run program with --help to get a list of available options and with +# --print-defaults to see which it would actually understand and use. + +# +# This group is read both both by the client and the server +# use it for options that affect everything +# +[client-server] + +# Import all .cnf files from configuration directory +!includedir /etc/mysql/conf.d/ +!includedir /etc/mysql/mariadb.conf.d/ diff --git a/mysql/my.cnf b/mysql/my.cnf new file mode 120000 index 00000000..18bea135 --- /dev/null +++ b/mysql/my.cnf @@ -0,0 +1 @@ +/etc/alternatives/my.cnf \ No newline at end of file diff --git a/mysql/my.cnf.fallback b/mysql/my.cnf.fallback new file mode 100644 index 00000000..92747d88 --- /dev/null +++ b/mysql/my.cnf.fallback @@ -0,0 +1,23 @@ +# +# The MySQL database server configuration file. +# +# You can copy this to one of: +# - "/etc/mysql/my.cnf" to set global options, +# - "~/.my.cnf" to set user-specific options. +# +# One can use all long options that the program supports. +# Run program with --help to get a list of available options and with +# --print-defaults to see which it would actually understand and use. +# +# For explanations see +# http://dev.mysql.com/doc/mysql/en/server-system-variables.html + +# This will be passed to all mysql clients +# It has been reported that passwords should be enclosed with ticks/quotes +# escpecially if they contain "#" chars... +# Remember to edit /etc/mysql/debian.cnf when changing the socket location. + +# Here is entries for some specific programs +# The following values assume you have at least 32M ram + +!includedir /etc/mysql/conf.d/ diff --git a/nanorc b/nanorc new file mode 100644 index 00000000..427801ab --- /dev/null +++ b/nanorc @@ -0,0 +1,272 @@ +## Sample initialization file for GNU nano. +## +## Please note that you must have configured nano with --enable-nanorc +## for this file to be read! Also note that this file should not be in +## DOS or Mac format, and that characters specially interpreted by the +## shell should not be escaped here. +## +## To make sure an option is disabled, use "unset