commit 4dd26c445b35b3e562ba22816710c2572764b637 Author: caelebfi Date: Wed Oct 27 14:28:05 2021 +0200 Initial commit 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 00000000..df670fd0 Binary files /dev/null and b/apt/trusted.gpg differ 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 00000000..8d002b7c Binary files /dev/null and b/console-setup/cached_Lat15-Fixed16.psf.gz differ 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 00000000..311fca37 Binary files /dev/null and b/console-setup/cached_UTF-8_del.kmap.gz differ diff --git a/console-setup/cached_setup_font.sh b/console-setup/cached_setup_font.sh new file mode 100755 index 00000000..cbb090ea --- /dev/null +++ b/console-setup/cached_setup_font.sh @@ -0,0 +1,19 @@ +#!/bin/sh + + + +if ls /dev/fb* >/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 00000000..029aa3c5 Binary files /dev/null and b/java-11-openjdk/security/public_suffix_list.dat differ diff --git a/java-11-openjdk/sound.properties b/java-11-openjdk/sound.properties new file mode 100644 index 00000000..68309d11 --- /dev/null +++ b/java-11-openjdk/sound.properties @@ -0,0 +1,39 @@ +############################################################ +# Sound Configuration File +############################################################ +# +# This properties file is used to specify default service +# providers for javax.sound.midi.MidiSystem and +# javax.sound.sampled.AudioSystem. +# +# The following keys are recognized by MidiSystem methods: +# +# javax.sound.midi.Receiver +# javax.sound.midi.Sequencer +# javax.sound.midi.Synthesizer +# javax.sound.midi.Transmitter +# +# The following keys are recognized by AudioSystem methods: +# +# javax.sound.sampled.Clip +# javax.sound.sampled.Port +# javax.sound.sampled.SourceDataLine +# javax.sound.sampled.TargetDataLine +# +# The values specify the full class name of the service +# provider, or the device name. +# +# See the class descriptions for details. +# +# Example 1: +# Use MyDeviceProvider as default for SourceDataLines: +# javax.sound.sampled.SourceDataLine=com.xyz.MyDeviceProvider +# +# Example 2: +# Specify the default Synthesizer by its name "InternalSynth". +# javax.sound.midi.Synthesizer=#InternalSynth +# +# Example 3: +# Specify the default Receiver by provider and name: +# javax.sound.midi.Receiver=com.sun.media.sound.MidiProvider#SunMIDI1 +# diff --git a/java-11-openjdk/swing.properties b/java-11-openjdk/swing.properties new file mode 100644 index 00000000..0f55df0c --- /dev/null +++ b/java-11-openjdk/swing.properties @@ -0,0 +1,2 @@ +# uncomment to set the default look and feel to GTK +#swing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel diff --git a/kernel/header_postinst.d/dkms b/kernel/header_postinst.d/dkms new file mode 100755 index 00000000..3752beef --- /dev/null +++ b/kernel/header_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/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