diff --git a/.gitattributesdb b/.gitattributesdb index fed81d0..6c27bcb 100644 --- a/.gitattributesdb +++ b/.gitattributesdb @@ -1,9 +1,186 @@ # This is the gitattributesdb database file. # Do not manually edit this file - any changes will be overwritten. -LmdpdGhvb2tzL2dpdGF0dHJpYnV0ZXNkYg== 1757518619.432797732 1757518618.466836488 tadgy:users 0755 - - -LmdpdGhvb2tzL3Bvc3QtY2hlY2tvdXQ= 1757518719.301790744 1757518850.675522371 tadgy:users 0755 - - -LmdpdGhvb2tzL3Bvc3QtbWVyZ2U= 1757518766.485897550 1757518850.675522371 tadgy:users 0755 - - -LmdpdGhvb2tzL3ByZS1jb21taXQ= 1757518781.005315169 1757518850.675522371 tadgy:users 0755 - - -LmdpdG1vZHVsZXM= 1757518619.436797572 1757518619.438797492 tadgy:users 0644 - - -UkVBRE1FLm1k 1757518519.971788195 1757518530.954347573 tadgy:users 0644 - - +LmdpdGhvb2tzL2dpdGF0dHJpYnV0ZXNkYg== 1757608819.000000000 1757608819.000000000 root:root 0755 - - +LmdpdGhvb2tzL3Bvc3QtY2hlY2tvdXQ= 1757519106.000000000 1757519106.000000000 root:root 0755 - - +LmdpdGhvb2tzL3Bvc3QtbWVyZ2U= 1757519106.000000000 1757519106.000000000 root:root 0755 - - +LmdpdGhvb2tzL3ByZS1jb21taXQ= 1757519106.000000000 1757519106.000000000 root:root 0755 - - +LmdpdGlnbm9yZQ== 1762025173.020942279 1757593248.000000000 root:root 0644 - - +LmdpdG1vZHVsZXM= 1757607701.000000000 1757607701.000000000 root:root 0644 - - +ZXRjLy5naXRpZ25vcmU= 1762626742.156358716 1757611781.000000000 root:root 0644 - - +ZXRjL2FwYWNoZTIvLmdpdGlnbm9yZQ== 1766069108.043264156 1757775932.000000000 root:root 0644 - - +ZXRjL2FwYWNoZTIvYXBhY2hlMi5jb25m 1766155394.332589865 1757785514.000000000 root:root 0644 - - +ZXRjL2FwYWNoZTIvbW9kcy1lbmFibGVkL2FsaWFzLmxvYWQ= 1762021735.493652772 1762021735.493652772 root:root 0777 - - +ZXRjL2FwYWNoZTIvbW9kcy1lbmFibGVkL2FsbG93bWV0aG9kcy5sb2Fk 1766073519.503025374 1766073519.503025374 root:root 0777 - - +ZXRjL2FwYWNoZTIvbW9kcy1lbmFibGVkL2F1dGhuX2NvcmUubG9hZA== 1762021735.381654619 1762021735.381654619 root:root 0777 - - +ZXRjL2FwYWNoZTIvbW9kcy1lbmFibGVkL2F1dGhuX2ZpbGUubG9hZA== 1762021735.437653696 1762021735.437653696 root:root 0777 - - +ZXRjL2FwYWNoZTIvbW9kcy1lbmFibGVkL2F1dGh6X2NvcmUubG9hZA== 1762021735.349655147 1762021735.349655147 root:root 0777 - - +ZXRjL2FwYWNoZTIvbW9kcy1lbmFibGVkL2F1dGh6X2hvc3QubG9hZA== 1766070527.231989855 1766070527.231989855 root:root 0777 - - +ZXRjL2FwYWNoZTIvbW9kcy1lbmFibGVkL2F1dGh6X3VzZXIubG9hZA== 1762021735.469653168 1762021735.469653168 root:root 0777 - - +ZXRjL2FwYWNoZTIvbW9kcy1lbmFibGVkL2NnaWQubG9hZA== 1766080747.085077197 1766080747.085077197 root:root 0777 - - +ZXRjL2FwYWNoZTIvbW9kcy1lbmFibGVkL2RlZmxhdGUubG9hZA== 1762021735.721649011 1762021735.721649011 root:root 0777 - - +ZXRjL2FwYWNoZTIvbW9kcy1lbmFibGVkL2Rpci5sb2Fk 1762021735.525652244 1762021735.525652244 root:root 0777 - - +ZXRjL2FwYWNoZTIvbW9kcy1lbmFibGVkL2Vudi5sb2Fk 1762021735.577651386 1762021735.577651386 root:root 0777 - - +ZXRjL2FwYWNoZTIvbW9kcy1lbmFibGVkL2ZpbHRlci5sb2Fk 1762021735.689649539 1762021735.689649539 root:root 0777 - - +ZXRjL2FwYWNoZTIvbW9kcy1lbmFibGVkL2h0dHAyLmxvYWQ= 1766079814.224337175 1766079814.224337175 root:root 0777 - - +ZXRjL2FwYWNoZTIvbW9kcy1lbmFibGVkL2luY2x1ZGUubG9hZA== 1766070423.145696881 1766070423.145696881 root:root 0777 - - +ZXRjL2FwYWNoZTIvbW9kcy1lbmFibGVkL21pbWUubG9hZA== 1762021735.609650859 1762021735.609650859 root:root 0777 - - +ZXRjL2FwYWNoZTIvbW9kcy1lbmFibGVkL21pbWVfbWFnaWMubG9hZA== 1766077359.436502219 1766077359.436502219 root:root 0777 - - +ZXRjL2FwYWNoZTIvbW9kcy1lbmFibGVkL21wbV9ldmVudC5sb2Fk 1766077495.230282186 1766077495.230282186 root:root 0777 - - +ZXRjL2FwYWNoZTIvbW9kcy1lbmFibGVkL3Byb3h5LmxvYWQ= 1766080867.035115479 1766080867.035115479 root:root 0777 - - +ZXRjL2FwYWNoZTIvbW9kcy1lbmFibGVkL3Byb3h5X2ZjZ2kubG9hZA== 1766080921.386226594 1766080921.386226594 root:root 0777 - - +ZXRjL2FwYWNoZTIvbW9kcy1lbmFibGVkL3Jld3JpdGUubG9hZA== 1766081010.864763229 1766081010.864763229 root:root 0777 - - +ZXRjL2FwYWNoZTIvbW9kcy1lbmFibGVkL3NldGVudmlmLmxvYWQ= 1762021735.661650000 1762021735.661650000 root:root 0777 - - +ZXRjL2FwYWNoZTIvc2l0ZXMtYXZhaWxhYmxlLy5naXRpZ25vcmU= 1766069274.068541443 1766069263.648712326 root:root 0644 - - +ZXRjL2FwYWNoZTIvc2l0ZXMtYXZhaWxhYmxlL2NvcmUuc2xhY2t3YXJlLnVrLm5ldC5jb25m 1758817141.000000000 1757785113.000000000 root:root 0644 - - +ZXRjL2FwYWNoZTIvc2l0ZXMtZW5hYmxlZC8wMDAtY29yZS5zbGFja3dhcmUudWsubmV0LmNvbmY= 1762529451.292078041 1762529451.292078041 root:root 0777 - - +ZXRjL2FwdC8uZ2l0aWdub3Jl 1762532662.236312315 1762532566.409854495 root:root 0644 - - +ZXRjL2FwdC9wcmVmZXJlbmNlcy5kL3N1cnk= 1762021809.456432672 1762021809.456432672 root:root 0644 - - +ZXRjL2FwdC9zb3VyY2VzLmxpc3QuZC9mZC5saXN0 1762021706.378133066 1762021706.374133133 root:root 0644 - - +ZXRjL2FwdC9zb3VyY2VzLmxpc3QuZC9zdXJ5Lmxpc3Q= 1762021706.378133066 1762021706.378133066 root:root 0644 - - +ZXRjL2Nyb24uMTVtaW4vLmdpdGlnbm9yZQ== 1762535468.567176697 1762535289.358058790 root:root 0644 - - +ZXRjL2Nyb24uZC8uZ2l0aWdub3Jl 1762535453.203423781 1762535289.358058790 root:root 0644 - - +ZXRjL2Nyb24uZGFpbHkvLmdpdGlnbm9yZQ== 1762538383.748288196 1762535499.146684944 root:root 0644 - - +ZXRjL2Nyb24uZGFpbHkvMC1yb3RhdGUtbG9ncy1zeW1saW5rcw== 1762022637.182797762 1762022637.182797762 root:root 0777 - - +ZXRjL2Nyb24uZGFpbHkvMTAtZGVoeWRyYXRlZA== 1762022637.182797762 1762022637.182797762 root:root 0777 - - +ZXRjL2Nyb24uZGFpbHkvNS11cGRhdGUtcGFja2FnZXMtbGlzdA== 1762022637.182797762 1762022637.182797762 root:root 0777 - - +ZXRjL2Nyb24uZGFpbHkvNy13YXJuLWdpdC1zdGF0dXM= 1762022637.182797762 1762022637.182797762 root:root 0777 - - +ZXRjL2Nyb24uaG91cmx5Ly5naXRpZ25vcmU= 1762535518.534373147 1762535518.534373147 root:root 0644 - - +ZXRjL2Nyb24ubW9udGhseS8uZ2l0aWdub3Jl 1762535548.045898541 1762535548.045898541 root:root 0644 - - +ZXRjL2Nyb24ud2Vla2x5Ly5naXRpZ25vcmU= 1762628453.620630321 1762535530.470181196 root:root 0644 - - +ZXRjL2Nyb24ud2Vla2x5L2NsZWFuLXBocA== 1762628439.836853762 1762628439.836853762 root:root 0777 - - +ZXRjL2Nyb24ueWVhcmx5Ly5naXRpZ25vcmU= 1762535568.001577608 1762535568.001577608 root:root 0644 - - +ZXRjL2Nyb250YWI= 1762534976.223094581 1757593504.000000000 root:root 0600 - - +ZXRjL2RlZmF1bHQvLmdpdGlnbm9yZQ== 1762624179.585857684 1762624148.166366444 root:root 0644 - - +ZXRjL2RlZmF1bHQvcHJvbWV0aGV1cy1ub2RlLWV4cG9ydGVy 1771504260.677940581 1762023153.000000000 root:root 0644 - - +ZXRjL2RlZmF1bHQvcm90YXRlLWxvZ3Mtc3ltbGlua3M= 1758555243.000000000 1758552192.000000000 root:root 0644 - - +ZXRjL2RlZmF1bHQvdGVycmFmb3JtLWh0dHAtYmFja2VuZA== 1771507048.704791655 1757595391.000000000 root:root 0600 - - +ZXRjL2RlaHlkcmF0ZWQvLmdpdGlnbm9yZQ== 1758038054.000000000 1758038054.000000000 root:root 0644 - - +ZXRjL2RlaHlkcmF0ZWQvYWNjb3VudHMvLmdpdGlnbm9yZQ== 1757873230.000000000 1757873230.000000000 root:root 0644 - - +ZXRjL2RlaHlkcmF0ZWQvYWNjb3VudHMvYUhSMGNITTZMeTloWTIxbExYWXdNaTVoY0drdWJHVjBjMlZ1WTNKNWNIUXViM0puTDJScGNtVmpkRzl5ZVFvLnRhci5ncGc= 1761052714.000000000 1757873275.000000000 root:root 0644 - - +ZXRjL2RlaHlkcmF0ZWQvYXJjaGl2ZS8uZ2l0aWdub3Jl 1757874259.000000000 1757873451.000000000 root:root 0644 - - +ZXRjL2RlaHlkcmF0ZWQvY2VydHMvLmdpdGlnbm9yZQ== 1757874303.000000000 1757873537.000000000 root:root 0644 - - +ZXRjL2RlaHlkcmF0ZWQvY29uZmln 1758044465.000000000 1757862077.000000000 root:root 0644 - - +ZXRjL2RlaHlkcmF0ZWQvZG9tYWlucw== 1757862328.000000000 1757862077.000000000 root:root 0644 - - +ZXRjL2RlaHlkcmF0ZWQvZG9tYWlucy5kL19leGFtcGxlXw== 1757863238.000000000 1757862077.000000000 root:root 0644 - - +ZXRjL2RlaHlkcmF0ZWQvZG9tYWlucy5kL2NvcmUuc2xhY2t3YXJlLnVrLm5ldA== 1757863250.000000000 1757863250.000000000 root:root 0644 - - +ZXRjL2RlaHlkcmF0ZWQvaG9va3MvZGVmYXVsdA== 1758045829.000000000 1757862077.000000000 root:root 0755 - - +ZXRjL2Z1c2lvbmRpcmVjdG9yeS9mdXNpb25kaXJlY3RvcnktYXBhY2hlLmNvbmY= 1740415693.000000000 1762022137.000000000 root:root 0644 - - +ZXRjL2Z1c2lvbmRpcmVjdG9yeS9mdXNpb25kaXJlY3RvcnkuY29uZg== 1771459200.000000000 1771459200.000000000 root:root 0644 - - +ZXRjL2Z1c2lvbmRpcmVjdG9yeS9mdXNpb25kaXJlY3RvcnkuY29uZi5vcmln 1760207207.000000000 1760207207.000000000 root:root 0644 - - +ZXRjL2dyb3Vw 1762530431.632238190 1762530431.632238190 root:root 0644 - - +ZXRjL2dzaGFkb3cuZ3Bn 1762628156.813441524 1762447499.282711556 root:root 0644 - - +ZXRjL2hvc3RuYW1l 1757594311.000000000 1757594311.000000000 root:root 0644 - - +ZXRjL2hvc3Rz 1762446715.371577485 1757594362.000000000 root:root 0644 - - +ZXRjL2luaXQuZC8uZ2l0aWdub3Jl 1771459200.000000000 1771459200.000000000 root:root 0644 - - +ZXRjL2luaXQuZC90ZXJyYWZvcm0taHR0cC1iYWNrZW5k 1771459200.000000000 1771459200.000000000 root:root 0755 - - +ZXRjL2tyYjUuY29uZg== 1762447367.132883171 1583171707.000000000 root:root 0644 - - +ZXRjL2xkYXAvbGRhcC5jb25m 1758374529.000000000 1730112559.000000000 root:root 0644 - - +ZXRjL2xkYXAvc2NoZW1hLy5naXRpZ25vcmU= 1762628549.507075969 1762628549.507075969 root:root 0644 - - +ZXRjL2xkYXAvc2NoZW1hL3JmYzIzMDdiaXMuc2NoZW1h 1759835660.000000000 1759835660.000000000 root:root 0644 - - +ZXRjL2xvZ2luLmRlZnM= 1771509215.801996599 1745058028.000000000 root:root 0644 - - +ZXRjL21vdGQ= 1762625944.389278724 1756052400.000000000 root:root 0644 - - +ZXRjL21zbXRwLmFsaWFzZXM= 1758035451.000000000 1758035451.000000000 root:root 0644 - - +ZXRjL21zbXRwcmMuZ3Bn 1761052674.000000000 1758049424.000000000 root:root 0644 - - +ZXRjL25ldHdvcmsvLmdpdGlnbm9yZQ== 1757596572.000000000 1757596572.000000000 root:root 0644 - - +ZXRjL25ldHdvcmsvaW50ZXJmYWNlcw== 1762449437.502802342 1762449437.502802342 root:root 0644 - - +ZXRjL25ldHdvcmsvaW50ZXJmYWNlcy5kL2V0aDA= 1762449591.864258045 1762449559.040799058 root:root 0644 - - +ZXRjL25ldHdvcmsvaW50ZXJmYWNlcy5kL2V0aDE= 1762449602.376084790 1762449560.312778093 root:root 0644 - - +ZXRjL3Bhc3N3ZA== 1762449439.234773795 1762449439.234773795 root:root 0644 - - +ZXRjL3BocGxkYXBhZG1pbi8uZ2l0aWdub3Jl 1762628720.800299329 1762628701.308615289 root:root 0644 - - +ZXRjL3BocGxkYXBhZG1pbi9jb25maWcucGhwLmdwZw== 1761052640.000000000 1758539944.000000000 root:root 0644 - - +ZXRjL3BrZ2xpc3Q= 1766102401.840579350 1762560002.068536774 root:root 0644 - - +ZXRjL3BsYS9jb25maWcucGhwLmdwZw== 1771459200.000000000 1771459200.000000000 root:root 0644 - - +ZXRjL3B1c2hvdmVyLWNsaWVudC8uZ2l0aWdub3Jl 1762628624.365862525 1762448145.464092595 root:root 0644 - - +ZXRjL3B1c2hvdmVyLWNsaWVudC9kZWZhdWx0LmdwZw== 1762448163.991787320 1762448163.979787518 root:root 0644 - - +ZXRjL3Jlc29sdi5jb25m 1757611605.000000000 1757611605.000000000 root:root 0644 - - +ZXRjL3JzeXNsb2cuY29uZg== 1757785113.000000000 1757785113.000000000 root:root 0644 - - +ZXRjL3NhbWJhL3NtYi5jb25m 1762447904.392054475 1758208516.000000000 root:root 0644 - - +ZXRjL3NhbWJhL3NtYnVzZXJz 1758121825.000000000 1758121586.000000000 root:root 0644 - - +ZXRjL3NoYWRvdy5ncGc= 1762628180.969049967 1762447484.598952854 root:root 0644 - - +ZXRjL3NzaC8uZ2l0aWdub3Jl 1762628843.382312260 1757606957.000000000 root:root 0644 - - +ZXRjL3NzaC9zc2hfY29uZmln 1757606630.000000000 1757606630.000000000 root:root 0644 - - +ZXRjL3NzaC9zc2hkX2NvbmZpZw== 1758202229.000000000 1757606896.000000000 root:root 0644 - - +ZXRjL3NzaGd1YXJkL3NzaGd1YXJkLmNvbmY= 1758050700.000000000 1758050700.000000000 root:root 0644 - - +ZXRjL3NzaGd1YXJkL3doaXRlbGlzdA== 1758050235.000000000 1758050235.000000000 root:root 0644 - - +ZXRjL3N1ZG9lcnMuZC8uZ2l0aWdub3Jl 1762026765.566662574 1762026765.566662574 root:root 0644 - - +ZXRjL3N1ZG9lcnMuZC9kZWZhdWx0cw== 1757599359.000000000 1757599359.000000000 root:root 0640 - - +ZXRjL3N1ZG9lcnMuZC9yb290LWFjY2Vzcw== 1757600157.000000000 1757600157.000000000 root:root 0640 - - +aG9tZS8uZ2l0aWdub3Jl 1757762052.000000000 1757762052.000000000 root:root 0644 - - +aG9tZS9zeXNhZG1pbi8uYmFzaF9sb2dvdXQ= 1757582867.000000000 1757582867.000000000 sysadmin:users 0644 - - +aG9tZS9zeXNhZG1pbi8uYmFzaF9wcm9maWxl 1757861225.000000000 1757584711.000000000 sysadmin:users 0644 - - +aG9tZS9zeXNhZG1pbi8uYmFzaHJj 1758887092.000000000 1757586493.000000000 sysadmin:users 0644 - - +aG9tZS9zeXNhZG1pbi8uZ2l0Y29uZmln 1757582738.000000000 1757582738.000000000 sysadmin:users 0644 - - +aG9tZS9zeXNhZG1pbi8uZ2l0aWdub3Jl 1757600312.000000000 1757600312.000000000 sysadmin:users 0644 - - +aG9tZS9zeXNhZG1pbi8ubG9jYWwvc2hhcmUvbmFuby8uZ2l0aWdub3Jl 1757586210.000000000 1757586210.000000000 sysadmin:users 0644 - - +aG9tZS9zeXNhZG1pbi8ubmFub3Jj 1757585756.000000000 1757585756.000000000 sysadmin:users 0644 - - +aG9tZS9zeXNhZG1pbi8uc3NoLy5naXRpZ25vcmU= 1757593349.000000000 1757593349.000000000 sysadmin:users 0644 - - +aG9tZS9zeXNhZG1pbi8uc3NoL2F1dGhvcml6ZWRfa2V5cw== 1757763178.000000000 1757587611.000000000 sysadmin:users 0644 - - +b3B0L3NiaW4vY3JvbmpvYi1jbGVhbi1waHA= 1762538240.962584934 1758289390.000000000 root:root 0755 - - +b3B0L3NiaW4vY3JvbmpvYi1kZWh5ZHJhdGVk 1758033093.000000000 1757531685.000000000 root:root 0755 - - +b3B0L3NiaW4vY3JvbmpvYi1yb3RhdGUtbG9ncy1zeW1saW5rcw== 1758555302.000000000 1758224324.000000000 root:root 0755 - - +b3B0L3NiaW4vY3JvbmpvYi11cGRhdGUtcGFja2FnZXMtbGlzdA== 1757531121.000000000 1757531121.000000000 root:root 0755 - - +b3B0L3NiaW4vY3JvbmpvYi13YXJuLWdpdC1zdGF0dXM= 1758221607.000000000 1757591137.000000000 root:root 0755 - - +b3B0L3NiaW4vZGVoeWRyYXRlZA== 1757531557.000000000 1757531557.000000000 root:root 0755 - - +b3B0L3NiaW4vcHVzaG92ZXItY2xpZW50 1758224526.000000000 1758224526.000000000 root:root 0755 - - +b3B0L3NiaW4vdGVycmFmb3JtLWh0dHAtYmFja2VuZA== 1757590543.000000000 1757590543.000000000 root:root 0755 - - +cm9vdC8uYmFzaF9sb2dvdXQ= 1757582867.000000000 1757582867.000000000 root:root 0644 - - +cm9vdC8uYmFzaF9wcm9maWxl 1757584711.000000000 1757584711.000000000 root:root 0644 - - +cm9vdC8uYmFzaHJj 1758887027.000000000 1757586493.000000000 root:root 0644 - - +cm9vdC8uZ2l0Y29uZmln 1757582738.000000000 1757582738.000000000 root:root 0644 - - +cm9vdC8uZ2l0aWdub3Jl 1771509562.912369370 1757600312.000000000 root:root 0644 - - +cm9vdC8ubG9jYWwvc2hhcmUvbmFuby8uZ2l0aWdub3Jl 1757586210.000000000 1757586210.000000000 root:root 0644 - - +cm9vdC8ubmFub3Jj 1757585756.000000000 1757585756.000000000 root:root 0644 - - +cm9vdC8uc3NoLy5naXRpZ25vcmU= 1757593349.000000000 1757593349.000000000 root:root 0644 - - +cm9vdC8uc3NoL2F1dGhvcml6ZWRfa2V5cw== 1757587611.000000000 1757587611.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NsZWFuLWZk 1758994151.000000000 1758992264.000000000 root:root 0755 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC8wMF9iY21hdGguaW5p 1754432591.000000000 1754432591.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC8wMF9iejIuaW5p 1754432591.000000000 1754432591.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC8wMF9jdXJsLmluaQ== 1754432591.000000000 1754432591.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC8wMF9nZC5pbmk= 1758756479.000000000 1758756479.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC8wMF9nZXR0ZXh0LmluaQ== 1754432591.000000000 1754432591.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC8wMF9nbXAuaW5p 1754432591.000000000 1754432591.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC8wMF9pY29udi5pbmk= 1754432591.000000000 1754432591.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC8wMF9pbWFwLmluaQ== 1758756479.000000000 1758756479.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC8wMF9pbnRsLmluaQ== 1754432591.000000000 1754432591.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC8wMF9sZGFwLmluaQ== 1754432591.000000000 1754432591.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC8wMF9tYnN0cmluZy5pbmk= 1754432591.000000000 1754432591.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC8wMF9vcGNhY2hlLmluaQ== 1754432591.000000000 1754432591.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC8wMF9vcGVuc3NsLmluaQ== 1754432591.000000000 1754432591.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC8wMF9wb3NpeC5pbmk= 1754432591.000000000 1754432591.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC8wMF9zZXNzaW9uLmluaQ== 1754432591.000000000 1754432591.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC8wMF9zaW1wbGV4bWwuaW5p 1754432591.000000000 1754432591.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC8wMF9zb2RpdW0uaW5p 1758756479.000000000 1758756479.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC8wMF9zcWxpdGUzLmluaQ== 1754432591.000000000 1754432591.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC8wMF94bWwuaW5p 1754432591.000000000 1754432591.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC8wMF96aXAuaW5p 1754432591.000000000 1754432591.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC8wMV9waGFyLmluaQ== 1754432591.000000000 1754432591.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC85OV9wZG8uaW5p 1758566165.000000000 1758566165.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC85OV9wZG9fbXlzcWwuaW5p 1758566165.000000000 1758566165.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC85OV9wZ3NxbC5pbmk= 1758566165.000000000 1758566165.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC85OV9waGFyLmluaQ== 1758566165.000000000 1758566165.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC85OV9zZXNzaW9uLmluaQ== 1760206689.000000000 1758566165.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC85OV9zb2FwLmluaQ== 1758566165.000000000 1758566165.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC85OV9zcWxpdGUzLmluaQ== 1758566165.000000000 1758566165.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC85OV9zeXN2c2htLmluaQ== 1758566165.000000000 1758566165.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC85OV90aWR5LmluaQ== 1758566165.000000000 1758566165.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2NvbmYuZC9pbWFnaWNrLmluaQ== 1755096904.000000000 1755096904.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2R1bW15LWRlZmF1bHQtbXRh 1762020478.278412865 1762020215.034844513 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL2R1bW15LWRlZmF1bHQtbXRhXzAuMC4xX2FsbC5kZWI= 1762020499.466056182 1762020499.458056317 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL3BocC1mcG0uY29uZg== 1758566251.000000000 1758566184.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL3BocC1mcG0uZC93d3cuY29uZg== 1758566277.000000000 1758566199.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL3BocC5pbmk= 1759845481.000000000 1758566175.000000000 root:root 0644 - - +cm9vdC9zdHVmZi10by1rZWVwL3B1c2hvdmVyLWFsZXJ0LnN0YXJ0 1758225142.000000000 1758225089.000000000 root:root 0755 - - +cm9vdC9zdHVmZi10by1rZWVwL3B1c2hvdmVyLWFsZXJ0LnN0b3A= 1758225254.000000000 1758225155.000000000 root:root 0755 - - +dmFyLy5naXRpZ25vcmU= 1762537544.845782317 1758288560.000000000 root:root 0644 - - +dmFyL2xpYi8uZ2l0aWdub3Jl 1762025492.611669032 1758288764.000000000 root:root 0644 - - +dmFyL2xpYi90ZXJyYWZvcm0taHR0cC1iYWNrZW5kLy5naXRrZWVwZGly 1762024627.173956151 1762024627.173956151 root:root 0644 - - +dmFyL3RtcC8uZ2l0aWdub3Jl 1771459200.000000000 1771459200.000000000 root:root 0644 - - +dmFyL3RtcC9waHAtdXBsb2Fkcy8uZ2l0aWdub3Jl 1771459200.000000000 1771459200.000000000 root:root 0644 - - +ZXRjL3NoYWRvdw== 1762449439.206774257 1762449439.206774257 root:shadow 0640 - - +ZXRjL3NoYWRvdy0= 1762023813.000000000 1762023813.000000000 root:shadow 0640 - - +ZXRjL3N1ZG9lcnM= 1751262933.000000000 1751262933.000000000 root:root 0440 - - +ZXRjL3N1ZG9lcnMuZC9SRUFETUU= 1751262933.000000000 1751262933.000000000 root:root 0440 - - +ZXRjL3N1ZG9lcnMuZC9kZWZhdWx0cw== 1757599359.000000000 1757599359.000000000 root:root 0640 - - +ZXRjL3N1ZG9lcnMuZC9yb290LWFjY2Vzcw== 1757600157.000000000 1757600157.000000000 root:root 0640 - - +aG9tZS9zeXNhZG1pbg== 1758887092.000000000 1757761412.000000000 sysadmin:users 0711 - - diff --git a/.gitattributesdb-extra b/.gitattributesdb-extra new file mode 100644 index 0000000..1cdeeb2 --- /dev/null +++ b/.gitattributesdb-extra @@ -0,0 +1,7 @@ +ZXRjL2RvYXMuY29uZg== +ZXRjL2RvYXMuZA== +ZXRjL3NoYWRvdw== +ZXRjL3NoYWRvdy0= +ZXRjL3N1ZG9lcnM= +ZXRjL3N1ZG9lcnMuZC8q +aG9tZS9zeXNhZG1pbg== diff --git a/.githooks/gitattributesdb b/.githooks/gitattributesdb index aa17af4..6f956ff 160000 --- a/.githooks/gitattributesdb +++ b/.githooks/gitattributesdb @@ -1 +1 @@ -Subproject commit aa17af467452849b2204472c8c16d9d3757824af +Subproject commit 6f956ff56af0a65b6dd8f84aa845031c22998c61 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8d64849 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +*~ +*.save + +.*.swp + +/bin +/boot/ +/data/ +/dev/ +/lib +/lib64 +/media/ +/mnt/ +/proc/ +/run/ +/sbin +/srv/ +/sys/ +/tmp/ +/usr/ diff --git a/README.md b/README.md deleted file mode 100644 index 0dbacfc..0000000 --- a/README.md +++ /dev/null @@ -1,9 +0,0 @@ -README -====== -System configurations are stored in a seperate branch for each host or purpose. - -List available branches: - * git branch -avv - -Check out specific branch: - * git checkout diff --git a/etc/.gitignore b/etc/.gitignore new file mode 100644 index 0000000..34654b4 --- /dev/null +++ b/etc/.gitignore @@ -0,0 +1,119 @@ +/.pwd.lock +/.updated +/ImageMagick-7/ +/X11/ +/adduser.conf +/alternatives/ +/apparmor.d/ +/bash.bashrc +/bash_completion +/bash_completion.d/ +/bindresvport.blacklist +/binfmt.d/ +/ca-certificates/ +/ca-certificates.conf +/credstore/ +/credstore.encrypted/ +/certificates/ +/dbus-1/ +/debconf.conf +/debian_version +/deluser.conf +/depmod.d/ +/dhcpcd.conf +/dpkg/ +/environment +/ethertypes +/fonts/ +/freeipmi/ +/fstab +/gai.conf +/ghostscript/ +/gprofng.rc +/groff/ +/group- +/gshadow +/gshadow- +/gss/ +/gssapi_mech.conf +/host.conf +/hosts.* +/inputrc +/ipmi/ +/issue +/issue.net +/kernel/ +/ld.so.* +/libaudit.conf +/lighttpd/ +/locale.* +/localtime +/logcheck/ +/lynx/ +/machine-id +/magic +/magic.mime +/mail.rc +/mailcap +/mailcap.order +/manpath.config +/mime.types +/modprobe.d/ +/modules +/modules-load.d/ +/msmtprc +/mtab +/nanorc +/netconfig +/networks +/nftables.conf +/nsswitch.conf +/nvme/ +/opt/ +/os-release +/pam.conf +/pam.d/ +/paperspecs +/passwd- +/perl/ +/polkit-1/ +/profile +/profile.d/ +/protocols +/python3/ +/python3.13/ +/rc?.d/ +/rmt +/rpc +/runit/ +/security/ +/selinux/ +/sensors.d/ +/sensors3.conf +/services +/sgml/ +/shadow +/shadow- +/shells +/skel/ +/snmp/ +/ssl/ +/subgid +/subuid +/sudo.conf +/sudoers +/sudo_logsrvd.conf +/supercat/ +/sv/ +/sysctl.d/ +/terminfo/ +/tmpfiles.d/ +/ucf.conf +/udev/ +/ufw/ +/update-motd.d/ +/vconsole.conf +/vim/ +/xattr.conf +/xdg +/xml diff --git a/etc/apache2/.gitignore b/etc/apache2/.gitignore new file mode 100644 index 0000000..da02ca7 --- /dev/null +++ b/etc/apache2/.gitignore @@ -0,0 +1,5 @@ +/conf-*/ +/envvars +/magic +/mods-available/ +/ports.conf diff --git a/etc/apache2/apache2.conf b/etc/apache2/apache2.conf new file mode 100644 index 0000000..8f6332d --- /dev/null +++ b/etc/apache2/apache2.conf @@ -0,0 +1,238 @@ +# These modules are required for the basic configuration directives used in this file. +# They *must* be loaded to use this configuration with httpd. +LoadModule alias_module /usr/lib/apache2/modules/mod_alias.so +LoadModule allowmethods_module /usr/lib/apache2/modules/mod_allowmethods.so +LoadModule authz_host_module /usr/lib/apache2/modules/mod_authz_host.so +LoadModule dir_module /usr/lib/apache2/modules/mod_dir.so +LoadModule env_module /usr/lib/apache2/modules/mod_env.so +#LoadModule log_config_module /usr/lib/apache2/mod_log_config.so +LoadModule mime_module /usr/lib/apache2/modules/mod_mime.so +LoadModule mime_magic_module /usr/lib/apache2/modules/mod_mime_magic.so +LoadModule mpm_event_module /usr/lib/apache2/modules/mod_mpm_event.so +LoadModule setenvif_module /usr/lib/apache2/modules/mod_setenvif.so +#LoadModule unixd_module /usr/lib/apache2/mod_unixd.so + +# Load extra modules. +IncludeOptional /etc/apache2/mods-enabled/*.load + + +# IP addresses and ports to listen on. +Listen 5.101.171.215:80 +Listen [2a01:a500:2981:1::d7]:80 + + Listen 5.101.171.215:25443 + Listen [2a01:a500:2981:1::d7]:25443 + + + +# Main server configuration. +# Note: A DocumentRoot (and a Directory block granting access) is required in order for RedirectMatch to work in VirtualHosts. +DocumentRoot /var/www/html +ServerAdmin "sysadmin(at)slackware.uk" +ServerName core.slackware.uk.net +ServerSignature Email +ServerTokens Major +User www-data +Group www-data +DefaultRuntimeDir /var/run/apache2 +PidFile /var/run/apache2/apache2.pid +ScriptSock /var/run/apache2/cgid.sock +Mutex pthread + + +# Logging. +LogFormat "%h %l %u %t \"%r\" %>s %b" Common +LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" Combined +LogFormat "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" VHostCombined +CustomLog "|/usr/bin/logger -p local1.info -t httpd" VHostCombined env=!no_log +LogLevel warn allowmethods:crit authz_core:crit + + LogLevel include:crit + + + LogLevel ssl:crit + +ErrorLog syslog:local0 + + +# Resource limits for event MPM. +# MaxConnectionsPerChild: maximum number of requests a server process serves +# MaxRequestWorkers: maximum number of worker threads +# MaxSpareThreads: maximum number of worker threads which are kept spare +# MinSpareThreads: minimum number of worker threads which are kept spare +# StartServers: initial number of server processes to start +# ThreadLimit: maximum limit of threads for ThreadsPerChild setting +# ThreadsPerChild: constant number of worker threads in each server process +MaxConnectionsPerChild 10240 +MaxRequestWorkers 128 +MaxSpareThreads 16 +MinSpareThreads 2 +StartServers 1 +ThreadLimit 64 +ThreadsPerChild 32 + + +# Timeouts. +TimeOut 30 +GracefulShutDownTimeout 1 + + +# Browser handling. +BrowserMatch "^Dreamweaver-WebDAV-SCM1" redirect-carefully +BrowserMatch "Java/1\.0" force-response-1.0 +BrowserMatch "JDK/1\.0" force-response-1.0 +BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully +BrowserMatch "Mozilla/2" nokeepalive +BrowserMatch "MS FrontPage" redirect-carefully +BrowserMatch "MSIE [2-5]" nokeepalive downgrade-1.0 force-response-1.0 +BrowserMatch "RealPlayer 4\.0" force-response-1.0 +BrowserMatch "^WebDAVFS/1\.[012]" redirect-carefully +BrowserMatch "^WebDrive" redirect-carefully +BrowserMatch "^XML Spy" redirect-carefully +BrowserMatch "^gnome-vfs/1\.0" redirect-carefully +BrowserMatch "^gvfs/1" redirect-carefully +BrowserMatch "Konqueror/4" redirect-carefully + + +# HTTP2. + + Protocols h2 h2c http/1.1 + H2Push On + H2PushPriority application/javascript interleaved + H2PushPriority image/jpeg after 32 + H2PushPriority image/png after 32 + H2PushPriority text/css before + H2PushPriority * after + + + +# SSL configuration. + + SSLCipherSuite HIGH:!SSLv3:!TLS1:!aNULL:!MD5 + SSLHonorCipherOrder On + SSLOptions +FakeBasicAuth + SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1 + SSLRandomSeed startup builtin + SSLRandomSeed startup file:/dev/urandom 512 + SSLRandomSeed connect builtin + SSLRandomSeed connect file:/dev/urandom 512 + SSLSessionCache shmcb:${APACHE_RUN_DIR}/ssl_session_cache(512000) + SSLSessionCacheTimeout 300 + SSLSessionTickets Off + BrowserMatch "MSIE [2-5]" ssl-unclean-shutdown + + + +# PHP. + + DirectoryIndex index.php index.phtml + + + SetHandler proxy:unix:/run/php-fpm83/php-fpm.sock|fcgi://localhost/ + + + + +# Filters and Handlers. + + + AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript + AddOutputFilterByType DEFLATE application/x-javascript application/javascript application/ecmascript + AddOutputFilterByType DEFLATE application/rss+xml + AddOutputFilterByType DEFLATE application/wasm + AddOutputFilterByType DEFLATE application/xml + + + AddOutputFilter INCLUDES .shtml .html + + +#This isn't needed except where CGI scripts are placed outside of ScriptAlias dirs. ExecCGI is required in Options for the dir. +# +# AddHandler cgi-script .cgi .pl .py .sh +# + + +# Mime type mappings. +TypesConfig /etc/mime.types +AddEncoding x-compress .tz .z .Z +AddEncoding x-gzip .gz .tgz +AddEncoding x-bzip2 .bz2 .tbz +AddType application/octet-stream .deb .dpkg .flac .flp .img .lz .lzma .mkv .rpm .run .srpm .tlz .txz .vob .xz +AddType application/pkcs8 .key +AddType application/pkcs10 .csr +AddType application/pkix-crl .crl +AddType application/x-pem-file .pem +AddType application/x-x509-user-cert .crt +AddType text/html .shtml +AddType text/markdown .md +AddType text/plain .csh .diff .ksh .md5 .md5sum .meta .patch .pl .pm .py .rb .sh .sha .shasum .sha1 .sha1sum .sha256 .sha256sum .sha512 .sha512sum .slackbuild .tcl .url +MIMEMagicFile /etc/apache2/magic + + +# Lets Encrypt validation. +Alias /.well-known/acme-challenge/ /srv/dehydrated/ + + +# Access control. + + Require all denied + + + + Options SymLinksIfOwnerMatch + AllowOverride None + Require all denied + + + + Options None + AllowOverride None + Require all granted + + + + Options None + AllowOverride None + Require all granted + + + + Options Includes MultiViews SymLinksIfOwnerMatch + AllowOverride AuthConfig FileInfo Indexes Limit + + Require all granted + + AllowMethods GET POST OPTIONS + + DirectoryIndex index.html index.xhtml + + DirectoryIndex index.shtml + + + + + SSLOptions +StdEnvVars + + + + + + + Options ExecCGI Includes MultiViews SymLinksIfOwnerMatch + AllowOverride AuthConfig FileInfo Limit + + Require all granted + + AllowMethods GET POST OPTIONS + + DirectoryIndex disabled + + + SSLOptions +StdEnvVars + + + + + +# Include extra configurations. +IncludeOptional /etc/apache2/sites-enabled/*.conf diff --git a/etc/apache2/mods-enabled/alias.load b/etc/apache2/mods-enabled/alias.load new file mode 120000 index 0000000..13a943a --- /dev/null +++ b/etc/apache2/mods-enabled/alias.load @@ -0,0 +1 @@ +../mods-available/alias.load \ No newline at end of file diff --git a/etc/apache2/mods-enabled/allowmethods.load b/etc/apache2/mods-enabled/allowmethods.load new file mode 120000 index 0000000..ddeb6dc --- /dev/null +++ b/etc/apache2/mods-enabled/allowmethods.load @@ -0,0 +1 @@ +../mods-available/allowmethods.load \ No newline at end of file diff --git a/etc/apache2/mods-enabled/authn_core.load b/etc/apache2/mods-enabled/authn_core.load new file mode 120000 index 0000000..6ae9e0d --- /dev/null +++ b/etc/apache2/mods-enabled/authn_core.load @@ -0,0 +1 @@ +../mods-available/authn_core.load \ No newline at end of file diff --git a/etc/apache2/mods-enabled/authn_file.load b/etc/apache2/mods-enabled/authn_file.load new file mode 120000 index 0000000..ab54e91 --- /dev/null +++ b/etc/apache2/mods-enabled/authn_file.load @@ -0,0 +1 @@ +../mods-available/authn_file.load \ No newline at end of file diff --git a/etc/apache2/mods-enabled/authz_core.load b/etc/apache2/mods-enabled/authz_core.load new file mode 120000 index 0000000..ccfcf1e --- /dev/null +++ b/etc/apache2/mods-enabled/authz_core.load @@ -0,0 +1 @@ +../mods-available/authz_core.load \ No newline at end of file diff --git a/etc/apache2/mods-enabled/authz_host.load b/etc/apache2/mods-enabled/authz_host.load new file mode 120000 index 0000000..badc268 --- /dev/null +++ b/etc/apache2/mods-enabled/authz_host.load @@ -0,0 +1 @@ +../mods-available/authz_host.load \ No newline at end of file diff --git a/etc/apache2/mods-enabled/authz_user.load b/etc/apache2/mods-enabled/authz_user.load new file mode 120000 index 0000000..59914f2 --- /dev/null +++ b/etc/apache2/mods-enabled/authz_user.load @@ -0,0 +1 @@ +../mods-available/authz_user.load \ No newline at end of file diff --git a/etc/apache2/mods-enabled/cgid.load b/etc/apache2/mods-enabled/cgid.load new file mode 120000 index 0000000..61a606d --- /dev/null +++ b/etc/apache2/mods-enabled/cgid.load @@ -0,0 +1 @@ +../mods-available/cgid.load \ No newline at end of file diff --git a/etc/apache2/mods-enabled/deflate.load b/etc/apache2/mods-enabled/deflate.load new file mode 120000 index 0000000..f73768e --- /dev/null +++ b/etc/apache2/mods-enabled/deflate.load @@ -0,0 +1 @@ +../mods-available/deflate.load \ No newline at end of file diff --git a/etc/apache2/mods-enabled/dir.load b/etc/apache2/mods-enabled/dir.load new file mode 120000 index 0000000..84a580b --- /dev/null +++ b/etc/apache2/mods-enabled/dir.load @@ -0,0 +1 @@ +../mods-available/dir.load \ No newline at end of file diff --git a/etc/apache2/mods-enabled/env.load b/etc/apache2/mods-enabled/env.load new file mode 120000 index 0000000..ef85526 --- /dev/null +++ b/etc/apache2/mods-enabled/env.load @@ -0,0 +1 @@ +../mods-available/env.load \ No newline at end of file diff --git a/etc/apache2/mods-enabled/filter.load b/etc/apache2/mods-enabled/filter.load new file mode 120000 index 0000000..07ee625 --- /dev/null +++ b/etc/apache2/mods-enabled/filter.load @@ -0,0 +1 @@ +../mods-available/filter.load \ No newline at end of file diff --git a/etc/apache2/mods-enabled/http2.load b/etc/apache2/mods-enabled/http2.load new file mode 120000 index 0000000..ad40386 --- /dev/null +++ b/etc/apache2/mods-enabled/http2.load @@ -0,0 +1 @@ +../mods-available/http2.load \ No newline at end of file diff --git a/etc/apache2/mods-enabled/include.load b/etc/apache2/mods-enabled/include.load new file mode 120000 index 0000000..5473bf5 --- /dev/null +++ b/etc/apache2/mods-enabled/include.load @@ -0,0 +1 @@ +../mods-available/include.load \ No newline at end of file diff --git a/etc/apache2/mods-enabled/mime.load b/etc/apache2/mods-enabled/mime.load new file mode 120000 index 0000000..c2c01f7 --- /dev/null +++ b/etc/apache2/mods-enabled/mime.load @@ -0,0 +1 @@ +../mods-available/mime.load \ No newline at end of file diff --git a/etc/apache2/mods-enabled/mime_magic.load b/etc/apache2/mods-enabled/mime_magic.load new file mode 120000 index 0000000..fcc0e96 --- /dev/null +++ b/etc/apache2/mods-enabled/mime_magic.load @@ -0,0 +1 @@ +../mods-available/mime_magic.load \ No newline at end of file diff --git a/etc/apache2/mods-enabled/mpm_event.load b/etc/apache2/mods-enabled/mpm_event.load new file mode 120000 index 0000000..c1e41c1 --- /dev/null +++ b/etc/apache2/mods-enabled/mpm_event.load @@ -0,0 +1 @@ +../mods-available/mpm_event.load \ No newline at end of file diff --git a/etc/apache2/mods-enabled/proxy.load b/etc/apache2/mods-enabled/proxy.load new file mode 120000 index 0000000..2f5281a --- /dev/null +++ b/etc/apache2/mods-enabled/proxy.load @@ -0,0 +1 @@ +../mods-available/proxy.load \ No newline at end of file diff --git a/etc/apache2/mods-enabled/proxy_fcgi.load b/etc/apache2/mods-enabled/proxy_fcgi.load new file mode 120000 index 0000000..5f187b2 --- /dev/null +++ b/etc/apache2/mods-enabled/proxy_fcgi.load @@ -0,0 +1 @@ +../mods-available/proxy_fcgi.load \ No newline at end of file diff --git a/etc/apache2/mods-enabled/rewrite.load b/etc/apache2/mods-enabled/rewrite.load new file mode 120000 index 0000000..498351b --- /dev/null +++ b/etc/apache2/mods-enabled/rewrite.load @@ -0,0 +1 @@ +../mods-available/rewrite.load \ No newline at end of file diff --git a/etc/apache2/mods-enabled/setenvif.load b/etc/apache2/mods-enabled/setenvif.load new file mode 120000 index 0000000..6d36106 --- /dev/null +++ b/etc/apache2/mods-enabled/setenvif.load @@ -0,0 +1 @@ +../mods-available/setenvif.load \ No newline at end of file diff --git a/etc/apache2/sites-available/.gitignore b/etc/apache2/sites-available/.gitignore new file mode 100644 index 0000000..6e8cef5 --- /dev/null +++ b/etc/apache2/sites-available/.gitignore @@ -0,0 +1,2 @@ +/000-default.conf +/default-ssl.conf diff --git a/etc/apache2/sites-available/core.slackware.uk.net.conf b/etc/apache2/sites-available/core.slackware.uk.net.conf new file mode 100644 index 0000000..2b9c4a0 --- /dev/null +++ b/etc/apache2/sites-available/core.slackware.uk.net.conf @@ -0,0 +1,44 @@ + + Options FollowSymlinks + AllowOverride None + Require all granted + + + + # include /etc/fusiondirectory/fusiondirectory.secrets + + AllowOverride None + Require all granted + AddType application/wasm .wasm + + + + ServerName core.slackware.uk.net + + SetEnvIf REQUEST_URI ^/robots\.txt$ no_log + SetEnvIf REQUEST_URI ^/favicon\.ico$ no_log + SetEnvIf REQUEST_URI ^/\.well-known/.*$ no_log + + RedirectMatch 403 ^/(?!(\.well-known|httpd-errordocs)/)(.*) + + + + + ServerName core.slackware.uk.net + + SSLEngine On + SSLCertificateFile /etc/certificates/core.slackware.uk.net_cert.pem + SSLCertificateKeyFile /etc/certificates/core.slackware.uk.net_key.pem + SSLCertificateChainFile /etc/certificates/core.slackware.uk.net_chain.pem + + SetEnvIf REQUEST_URI ^/robots\.txt$ no_log + SetEnvIf REQUEST_URI ^/favicon\.ico$ no_log + + ScriptAlias /cgi-bin/ /data/sites/core.slackware.uk.net/cgi-bin/ + + DocumentRoot /data/sites/core.slackware.uk.net/html + + Alias /fd /srv/fusiondirectory/html + Alias /pla /srv/pla + + diff --git a/etc/apache2/sites-enabled/000-core.slackware.uk.net.conf b/etc/apache2/sites-enabled/000-core.slackware.uk.net.conf new file mode 120000 index 0000000..95be8ba --- /dev/null +++ b/etc/apache2/sites-enabled/000-core.slackware.uk.net.conf @@ -0,0 +1 @@ +../sites-available/core.slackware.uk.net.conf \ No newline at end of file diff --git a/etc/apt/.gitignore b/etc/apt/.gitignore new file mode 100644 index 0000000..1451072 --- /dev/null +++ b/etc/apt/.gitignore @@ -0,0 +1,5 @@ +/apt.conf.d/ +/auth.conf.d/ +/keyrings/ +/sources.list +/trusted.gpg.d/ diff --git a/etc/apt/preferences.d/sury b/etc/apt/preferences.d/sury new file mode 100644 index 0000000..af6fa36 --- /dev/null +++ b/etc/apt/preferences.d/sury @@ -0,0 +1,3 @@ +Package: * +Pin: release o=deb.sury.org +Pin-Priority: 1000 diff --git a/etc/apt/sources.list.d/fd.list b/etc/apt/sources.list.d/fd.list new file mode 100644 index 0000000..1b7dcbd --- /dev/null +++ b/etc/apt/sources.list.d/fd.list @@ -0,0 +1,4 @@ +deb [trusted=yes] https://public.fusiondirectory.org/debian/fusiondirectory-integrator/ bullseye main +deb [trusted=yes] https://public.fusiondirectory.org/debian/fusiondirectory-tools/ bullseye main +deb [trusted=yes] https://public.fusiondirectory.org/debian/fusiondirectory-external-libraries/ bullseye main +deb [trusted=yes] https://public.fusiondirectory.org/debian/bullseye-fusiondirectory-release/ bullseye main diff --git a/etc/apt/sources.list.d/sury.list b/etc/apt/sources.list.d/sury.list new file mode 100644 index 0000000..feb0f4f --- /dev/null +++ b/etc/apt/sources.list.d/sury.list @@ -0,0 +1 @@ +deb [trusted=yes] https://packages.sury.org/php/ trixie main diff --git a/etc/cron.15min/.gitignore b/etc/cron.15min/.gitignore new file mode 100644 index 0000000..a68d087 --- /dev/null +++ b/etc/cron.15min/.gitignore @@ -0,0 +1,2 @@ +/* +!/.gitignore diff --git a/etc/cron.d/.gitignore b/etc/cron.d/.gitignore new file mode 100644 index 0000000..a68d087 --- /dev/null +++ b/etc/cron.d/.gitignore @@ -0,0 +1,2 @@ +/* +!/.gitignore diff --git a/etc/cron.daily/.gitignore b/etc/cron.daily/.gitignore new file mode 100644 index 0000000..c77a4e1 --- /dev/null +++ b/etc/cron.daily/.gitignore @@ -0,0 +1,6 @@ +/* +!/.gitignore +!/0-rotate-logs-symlinks +!/5-update-packages-list +!/7-warn-git-status +!/10-dehydrated diff --git a/etc/cron.daily/0-rotate-logs-symlinks b/etc/cron.daily/0-rotate-logs-symlinks new file mode 120000 index 0000000..e26953b --- /dev/null +++ b/etc/cron.daily/0-rotate-logs-symlinks @@ -0,0 +1 @@ +/opt/sbin/cronjob-rotate-logs-symlinks \ No newline at end of file diff --git a/etc/cron.daily/10-dehydrated b/etc/cron.daily/10-dehydrated new file mode 120000 index 0000000..e19bc69 --- /dev/null +++ b/etc/cron.daily/10-dehydrated @@ -0,0 +1 @@ +/opt/sbin/cronjob-dehydrated \ No newline at end of file diff --git a/etc/cron.daily/5-update-packages-list b/etc/cron.daily/5-update-packages-list new file mode 120000 index 0000000..208cb6d --- /dev/null +++ b/etc/cron.daily/5-update-packages-list @@ -0,0 +1 @@ +/opt/sbin/cronjob-update-packages-list \ No newline at end of file diff --git a/etc/cron.daily/7-warn-git-status b/etc/cron.daily/7-warn-git-status new file mode 120000 index 0000000..d9e2cc4 --- /dev/null +++ b/etc/cron.daily/7-warn-git-status @@ -0,0 +1 @@ +/opt/sbin/cronjob-warn-git-status \ No newline at end of file diff --git a/etc/cron.hourly/.gitignore b/etc/cron.hourly/.gitignore new file mode 100644 index 0000000..a68d087 --- /dev/null +++ b/etc/cron.hourly/.gitignore @@ -0,0 +1,2 @@ +/* +!/.gitignore diff --git a/etc/cron.monthly/.gitignore b/etc/cron.monthly/.gitignore new file mode 100644 index 0000000..a68d087 --- /dev/null +++ b/etc/cron.monthly/.gitignore @@ -0,0 +1,2 @@ +/* +!/.gitignore diff --git a/etc/cron.weekly/.gitignore b/etc/cron.weekly/.gitignore new file mode 100644 index 0000000..7c262be --- /dev/null +++ b/etc/cron.weekly/.gitignore @@ -0,0 +1,3 @@ +/* +!/.gitignore +!/clean-php diff --git a/etc/cron.weekly/clean-php b/etc/cron.weekly/clean-php new file mode 120000 index 0000000..e164f2a --- /dev/null +++ b/etc/cron.weekly/clean-php @@ -0,0 +1 @@ +/opt/sbin/cronjob-clean-php \ No newline at end of file diff --git a/etc/cron.yearly/.gitignore b/etc/cron.yearly/.gitignore new file mode 100644 index 0000000..a68d087 --- /dev/null +++ b/etc/cron.yearly/.gitignore @@ -0,0 +1,2 @@ +/* +!/.gitignore diff --git a/etc/crontab b/etc/crontab new file mode 100644 index 0000000..c934f35 --- /dev/null +++ b/etc/crontab @@ -0,0 +1,8 @@ +# do daily/weekly/monthly maintenance +# min hour day month weekday user command +0,15,30,45 * * * * root cd / && [ -d /etc/cron.15min ] && run-parts --report /etc/cron.15min +0 * * * * root cd / && [ -d /etc/cron.hourly ] && run-parts --report /etc/cron.hourly +0 0 * * * root cd / && [ -d /etc/cron.daily ] && run-parts --report /etc/cron.daily +0 0 * * 6 root cd / && [ -d /etc/cron.weekly ] && run-parts --report /etc/cron.weekly +0 0 1 * * root cd / && [ -d /etc/cron.monthly ] && run-parts --report /etc/cron.monthly +0 0 1 1 * root cd / && [ -d /etc/cron.yearly ] && run-parts --report /etc/cron.yearly diff --git a/etc/default/.gitignore b/etc/default/.gitignore new file mode 100644 index 0000000..2a9e21a --- /dev/null +++ b/etc/default/.gitignore @@ -0,0 +1,10 @@ +/apache-htcacheclean +/cron +/dbus +/locale +/networking +/nss +/openipmi +/ssh +/useradd +/winbind diff --git a/etc/default/prometheus-node-exporter b/etc/default/prometheus-node-exporter new file mode 100644 index 0000000..1378629 --- /dev/null +++ b/etc/default/prometheus-node-exporter @@ -0,0 +1,5 @@ +# Set the command-line arguments to pass to the server. +# Due to shell escaping, to pass backslashes for regexes, you need to double +# them (\\d for \d). If running under systemd, you need to double them again +# (\\\\d to mean \d), and escape newlines too. +ARGS="--web.listen-address=5.101.171.215:9100" diff --git a/etc/default/rotate-logs-symlinks b/etc/default/rotate-logs-symlinks new file mode 100644 index 0000000..2312951 --- /dev/null +++ b/etc/default/rotate-logs-symlinks @@ -0,0 +1 @@ +CREATE_DIRS['core.slackware.uk.net']="fusiondirectory samba" diff --git a/etc/default/terraform-http-backend b/etc/default/terraform-http-backend new file mode 100644 index 0000000..e6cc2ce --- /dev/null +++ b/etc/default/terraform-http-backend @@ -0,0 +1,7 @@ +TF_USER="thb" +TF_IP="5.101.171.215" +TF_PORT="25480" +TF_STORAGE_DIR="/var/lib/terraform-http-backend" +TF_AUTH_ENABLED="true" +TF_USERNAME="sysadmin" +TF_PASSWORD="sunsa" diff --git a/etc/dehydrated/.gitignore b/etc/dehydrated/.gitignore new file mode 100644 index 0000000..ac15403 --- /dev/null +++ b/etc/dehydrated/.gitignore @@ -0,0 +1 @@ +/chains/ diff --git a/etc/dehydrated/accounts/.gitignore b/etc/dehydrated/accounts/.gitignore new file mode 100644 index 0000000..8e3c016 --- /dev/null +++ b/etc/dehydrated/accounts/.gitignore @@ -0,0 +1,2 @@ +/*/ +/*.tar diff --git a/etc/dehydrated/accounts/aHR0cHM6Ly9hY21lLXYwMi5hcGkubGV0c2VuY3J5cHQub3JnL2RpcmVjdG9yeQo.tar.gpg b/etc/dehydrated/accounts/aHR0cHM6Ly9hY21lLXYwMi5hcGkubGV0c2VuY3J5cHQub3JnL2RpcmVjdG9yeQo.tar.gpg new file mode 100644 index 0000000..983eedd Binary files /dev/null and b/etc/dehydrated/accounts/aHR0cHM6Ly9hY21lLXYwMi5hcGkubGV0c2VuY3J5cHQub3JnL2RpcmVjdG9yeQo.tar.gpg differ diff --git a/etc/dehydrated/archive/.gitignore b/etc/dehydrated/archive/.gitignore new file mode 100644 index 0000000..33662f5 --- /dev/null +++ b/etc/dehydrated/archive/.gitignore @@ -0,0 +1 @@ +/* diff --git a/etc/dehydrated/certs/.gitignore b/etc/dehydrated/certs/.gitignore new file mode 100644 index 0000000..33662f5 --- /dev/null +++ b/etc/dehydrated/certs/.gitignore @@ -0,0 +1 @@ +/* diff --git a/etc/dehydrated/config b/etc/dehydrated/config new file mode 100644 index 0000000..b43b3ad --- /dev/null +++ b/etc/dehydrated/config @@ -0,0 +1,147 @@ +# This is the main config file for dehydrated. +# This file is looked for in the following locations: +# $SCRIPTDIR/config (next to this script) +# /usr/local/etc/dehydrated/config +# /etc/dehydrated/config +# ${PWD}/config (in current working-directory) + +# Which user should dehydrated run as? This will be implictly enforced when running as root. +# Default: +#DEHYDRATED_USER="" + +# Which group should dehydrated run as? This will be implictly enforced when running as root. +# Default: +#DEHYDRATED_GROUP="" + +# Resolve names to addresses of IP version only, for curl. +# Supported values: 4, 6. +# Default: +#IP_VERSION="" + +# Path to certificate authority. +# Default: https://acme-v02.api.letsencrypt.org/directory +#CA="https://acme-v02.api.letsencrypt.org/directory" +# Use staging server for testing: +#CA="https://acme-staging-v02.api.letsencrypt.org/directory" + +# Path to old certificate authority. +# Set this value to your old CA when upgrading from ACMEv1 to ACMEv2 under a different endpoint. +# If dehydrated detects an account-key for the old CA it will automatically reuse that key +# instead of registering a new one. +# Default: https://acme-v01.api.letsencrypt.org/directory +#OLDCA="https://acme-v01.api.letsencrypt.org/directory" + +# Which challenge should be used? +# Supported values: http-01, dns-01, tls-alpn-01. +# Default: http-01 +#CHALLENGETYPE="http-01" + +# Path to a directory containing additional config files. +# This allows overriding the defaults found in the main configuration file. +# Additional config files in this directory must be named with a '.sh' ending. +# Default: +#CONFIG_D="" + +# Base directory for account key, generated certificates and list of domains. +# Default: $SCRIPTDIR +BASEDIR="/etc/dehydrated" + +# File containing the list of domains for which to request certificates. +# Default: $BASEDIR/domains.txt +DOMAINS_TXT="${BASEDIR}/domains" + +# Directory for per-domain configuration files. +# If not set, per-domain configurations are sourced from each certificates output directory. +# Default: +DOMAINS_D="${BASEDIR}/domains.d" + +# Output directory for generated certificates. +# Default: ${BASEDIR}/certs +#CERTDIR="${BASEDIR}/certs" + +# Output directory for alpn verification certificates. +# Default: ${BASEDIR}/alpn-certs +#ALPNCERTDIR="${BASEDIR}/alpn-certs" + +# Directory for account keys and registration information. +# Default: ${BASEDIR}/accounts +#ACCOUNTDIR="${BASEDIR}/accounts" + +# Output directory for challenge-tokens to be served by webserver, or deployed in $HOOK. +# Default: /var/www/dehydrated +WELLKNOWN="/srv/dehydrated" + +# Default keysize for private keys. +# Default: 4096 +#KEYSIZE="4096" + +# Path to openssl config file. +# To try and figure out the system default, leave this unset. +# Default: +#OPENSSL_CNF="" + +# Path to OpenSSL binary. +# Default: openssl +#OPENSSL="openssl" + +# Extra options passed to the curl binary. +# Default: +#CURL_OPTS="" + +# Program or function called at certain stages of processing. +# BASEDIR and WELLKNOWN variables are exported and can be used in an external program. +# Default: +HOOK="${BASEDIR}/hooks/default" + +# Chain clean_challenge|deploy_challenge arguments together into one hook call per certificate? +# Default: no +#HOOK_CHAIN="no" + +# Minimum days before expiration to automatically renew certificate. +# Default: 30 +#RENEW_DAYS="30" + +# Regenerate private keys instead of just signing new certificates on renewal? +# Default: yes +PRIVATE_KEY_RENEW="no" + +# Create an extra private key for rollover? +# Default: no +#PRIVATE_KEY_ROLLOVER="no" + +# Which public key algorithm should be used? +# Supported: rsa, prime256v1, secp384r1. +# Default: rsa +KEY_ALGO="secp384r1" + +# E-mail to use during the registration. +# Default: +CONTACT_EMAIL="sysadmin@slackware.uk" + +# Lockfile location, to prevent concurrent execution. +# Default: $BASEDIR/lock +LOCKFILE="/run/dehydrated.lock" + +# Option to add CSR-flag indicating OCSP stapling to be mandatory. +# Default: no +#OCSP_MUST_STAPLE="no" + +# Fetch OCSP responses. +# Default: no +#OCSP_FETCH="no" + +# OCSP refresh interval, in days. +# Default: 5 +#OCSP_DAYS="5" + +# Issuer chain cache directory. +# Default: $BASEDIR/chains +#CHAINCACHE="${BASEDIR}/chains" + +# Automatic cleanup? +# Default: no +AUTO_CLEANUP="yes" + +# ACME API version. +# Default: auto +#API=auto diff --git a/etc/dehydrated/domains b/etc/dehydrated/domains new file mode 100644 index 0000000..c9d26dd --- /dev/null +++ b/etc/dehydrated/domains @@ -0,0 +1,32 @@ +# Create certificate for 'example.org' with an alternative name of +# 'www.example.org'. It will be stored in the directory ${CERT_DIR}/example.org +#example.org www.example.org + +# Create certificate for 'example.com' with alternative names of +# 'www.example.com' & 'wiki.example.com'. It will be stored in the directory +# ${CERT_DIR}/example.com +#example.com www.example.com wiki.example.com + +# Using the alias 'certalias' create certificate for 'example.net' with +# alternate name 'www.example.net' and store it in the directory +# ${CERTDIR}/certalias +#example.net www.example.net > certalias + +# Using the alias 'service_example_com' create a wildcard certificate for +# '*.service.example.com' and store it in the directory +# ${CERTDIR}/service_example_com +# NOTE: It is NOT a certificate for 'service.example.com' +#*.service.example.com > service_example_com + +# Using the alias 'star_service_example_org' create a wildcard certificate for +# '*.service.example.org' with an alternative name of `service.example.org' +# and store it in the directory ${CERTDIR}/star_service_example_org +# NOTE: It is a certificate for 'service.example.org' +#*.service.example.org service.example.org > star_service_example_org + +# Create a certificate for 'service.example.net' with an alternative name of +# '*.service.example.net' (which is a wildcard domain) and store it in the +# directory ${CERTDIR}/service.example.net +#service.example.net *.service.example.net + +core.slackware.uk.net diff --git a/etc/dehydrated/domains.d/_example_ b/etc/dehydrated/domains.d/_example_ new file mode 100644 index 0000000..941659e --- /dev/null +++ b/etc/dehydrated/domains.d/_example_ @@ -0,0 +1,48 @@ +# The settings in this file can be used to override those in the global config file in /etc/dehydrated + +# Which challenge should be used? +# Supported values: http-01, dns-01, tls-alpn-01. +# Default: http-01 +#CHALLENGETYPE="http-01" + +# Default keysize for private keys. +# Default: 4096 +#KEYSIZE="4096" + +# Program or function called at certain stages of processing. +# BASEDIR and WELLKNOWN variables are exported and can be used in an external program. +# Default: +#HOOK="" + +# Chain clean_challenge|deploy_challenge arguments together into one hook call per certificate? +# Default: no +#HOOK_CHAIN="no" + +# Minimum days before expiration to automatically renew certificate. +# Default: 30 +#RENEW_DAYS="30" + +# Regenerate private keys instead of just signing new certificates on renewal? +# Default: yes +#PRIVATE_KEY_RENEW="yes" + +# Create an extra private key for rollover? +# Default: no +#PRIVATE_KEY_ROLLOVER="no" + +# Which public key algorithm should be used? +# Supported: rsa, prime256v1, secp384r1. +# Default: rsa +#KEY_ALGO="rsa" + +# Option to add CSR-flag indicating OCSP stapling to be mandatory. +# Default: no +#OCSP_MUST_STAPLE="no" + +# Fetch OCSP responses. +# Default: no +#OCSP_FETCH="no" + +# OCSP refresh interval, in days. +# Default: 5 +#OCSP_DAYS="5" diff --git a/etc/dehydrated/domains.d/core.slackware.uk.net b/etc/dehydrated/domains.d/core.slackware.uk.net new file mode 100644 index 0000000..941659e --- /dev/null +++ b/etc/dehydrated/domains.d/core.slackware.uk.net @@ -0,0 +1,48 @@ +# The settings in this file can be used to override those in the global config file in /etc/dehydrated + +# Which challenge should be used? +# Supported values: http-01, dns-01, tls-alpn-01. +# Default: http-01 +#CHALLENGETYPE="http-01" + +# Default keysize for private keys. +# Default: 4096 +#KEYSIZE="4096" + +# Program or function called at certain stages of processing. +# BASEDIR and WELLKNOWN variables are exported and can be used in an external program. +# Default: +#HOOK="" + +# Chain clean_challenge|deploy_challenge arguments together into one hook call per certificate? +# Default: no +#HOOK_CHAIN="no" + +# Minimum days before expiration to automatically renew certificate. +# Default: 30 +#RENEW_DAYS="30" + +# Regenerate private keys instead of just signing new certificates on renewal? +# Default: yes +#PRIVATE_KEY_RENEW="yes" + +# Create an extra private key for rollover? +# Default: no +#PRIVATE_KEY_ROLLOVER="no" + +# Which public key algorithm should be used? +# Supported: rsa, prime256v1, secp384r1. +# Default: rsa +#KEY_ALGO="rsa" + +# Option to add CSR-flag indicating OCSP stapling to be mandatory. +# Default: no +#OCSP_MUST_STAPLE="no" + +# Fetch OCSP responses. +# Default: no +#OCSP_FETCH="no" + +# OCSP refresh interval, in days. +# Default: 5 +#OCSP_DAYS="5" diff --git a/etc/dehydrated/hooks/default b/etc/dehydrated/hooks/default new file mode 100755 index 0000000..2c94e31 --- /dev/null +++ b/etc/dehydrated/hooks/default @@ -0,0 +1,436 @@ +#!/usr/bin/env bash +# This file contains the default hook functions for dehydrated - these functions will be used when there is no overriding certificate specific hooks file. +# All but startup_hook and ext_hook can be overridden by a hooks script on a per certificate basis. +# +# shellcheck disable=SC2034,SC2317 + +# Configuration. +# Where the copies of the current certificates/keys should be placed. Comment for no copying. +CERTSDIR="/etc/certificates" +# The syslog facility and tag to use. +FACILITY="local3" +TAG="dehydrated" +# Where from/to to send emails. +EMAIL_FROM="\"Server: ${HOSTNAME%%.*}\" " +EMAIL_TO=("Systems' Administrator ") + +# Get the system ID. +# shellcheck disable=SC2046 +declare SYSTEM_$(grep '^ID=' /etc/os-release 2>/dev/null) + +# Write a message to syslog, and send a copy via email. +notify() { + local LOG_PREFIX="${LOG_PREFIX:-Certificate renewal} $1" PRIORITY + + [[ -z "$1" ]] && return 1 + + # Select the syslog priority level. + case "$1" in + 'error') PRIORITY="err" ;; + 'warning') PRIORITY="warn" ;; + *) PRIORITY="info" ;; + esac + shift + + # Log the message to syslog + if [[ "$ID" == "alpine" ]]; then + # BusyBox logger on Alpine's is missing the --id option. + printf "%s\\n" "$LOG_PREFIX:" "$@" "EOX" | logger -p "$FACILITY.$PRIORITY" -t "$TAG" >/dev/null 2>&1 + else + printf "%s\\n" "$LOG_PREFIX:" "$@" "EOX" | logger --id="$$" -p "$FACILITY.$PRIORITY" -t "$TAG" >/dev/null 2>&1 + fi + + # Email the notification. + printf "%s\\n" "$@" | mail -r "$EMAIL_FROM" -s "$LOG_PREFIX" "${EMAIL_TO[@]}" >/dev/null 2>&1 + + return 0 +} + +# Service configurations (used at startup/shutdown). +services() { + local DAEMON ERR=0 LOG_PREFIX="Dehydrated configuration" PIDFILE RCFILE SANITY="$1" + + # Select the service configuration based on the distribution. + # RCFILE_ is required for any service. + # Either DAEMON_ or PIDFILE_, or both is required for any service. + if [[ "$SYSTEM_ID" == "slackware" ]]; then + # HTTP daemon selection. + if [[ -x "/etc/rc.d/rc.httpd" ]]; then + RCFILE_HTTPD="/etc/rc.d/rc.httpd" + DAEMON_HTTPD="httpd" + PIDFILE_HTTPD="/run/httpd.pid" + elif [[ -x "/etc/rc.d/rc.thttpd" ]]; then + RCFILE_HTTPD="/etc/rc.d/rc.thttpd" + DAEMON_HTTPD="thttpd" + PIDFILE_HTTPD="/run/thttpd.pid" + fi + # FTP daemon selection. + if [[ -x "/etc/rc.d/rc.proftpd" ]]; then + RCFILE_FTPD="/etc/rc.d/rc.proftpd" + DAEMON_FTPD="proftpd" + PIDFILE_FTPD="/run/proftpd.pid" + fi + # SMTP daemon selection. + if [[ -x "/etc/rc.d/rc.exim" ]]; then + RCFILE_SMTPD="/etc/rc.d/rc.exim" + DAEMON_SMTPD="exim" + PIDFILE_SMTPD="/run/exim.pid" + fi + elif [[ "$SYSTEM_ID" == "void" ]]; then + # HTTP daemon selection. + # thttpd on Void doesn't have a directly callable rc script, so can't be supported. + if [[ -x "/usr/sbin/apachectl" ]]; then + RCFILE_HTTPD="/usr/sbin/apachectl" + DAEMON_HTTPD="httpd" + PIDFILE_HTTPD="/run/httpd/httpd.pid" + fi + elif [[ "$SYSTEM_ID" == "alpine" ]]; then + # HTTP daemon selection. + if [[ -x "/etc/init.d/apache2" ]]; then + RCFILE_HTTPD="/etc/init.d/apache2" + DAEMON_HTTPD="httpd" + PIDFILE_HTTPD="/run/apache2/httpd.pid" + elif [[ -x "/etc/init.d/thttpd" ]]; then + RCFILE_HTTPD="/etc/init.d/thttpd" + DAEMON_HTTPD="thttpd" + PIDFILE_HTTPD="/run/thttpd.pid" + fi + # Samba daemon selection. + if [[ -x "/etc/init.d/samba" ]]; then +# FIXME: +# RCFILE_SAMBA="/etc/init.d/samba" + DAEMON_SAMBA="samba" + PIDFILE_SAMBA="/run/samba.pid" + fi + fi + + # Sanity check settings. + ((SANITY == 1)) && { + [[ -z "$RCFILE_HTTPD" ]] && notify "warning" "No configuration settings for an HTTP daemon - no start/restart of HTTP daemon is possible -- check configuration" + for RCFILE in "${!RCFILE_@}"; do + DAEMON="DAEMON_${RCFILE#RCFILE_}" + PIDFILE="PIDFILE_${RCFILE#RCFILE_}" + [[ -n "${!RCFILE}" ]] && [[ -z "${!DAEMON}" ]] && [[ -z "${!PIDFILE}" ]] && notify "error" "'$RCFILE' is set, but neither '$DAEMON' nor '$PIDFILE' is set - at least one setting is required -- aborting" && ERR=1 + done + } + + ((ERR == 1)) && return 1 + + return 0 +} + +deploy_challenge() { + local DOMAIN="$1" TOKEN_FILENAME="$2" TOKEN_VALUE="$3" + + # This hook is called once for every domain that needs to be + # validated, including any alternative names you may have listed. + # Parameters: + # DOMAIN - The domain name (CN or subject alternative name) being validated. + # TOKEN_FILENAME - The name of the file containing the token to be served for HTTP validation + # Should be served by your web server as /.well-known/acme-challenge/${TOKEN_FILENAME}. + # TOKEN_VALUE - The token value that needs to be served for validation. + # For DNS validation, this is what you want to put in the _acme-challenge TXT record. + # For HTTP validation it is the value that is expected be found in the $TOKEN_FILENAME file. + + # Simple example: Use nsupdate with local named + # printf 'server 127.0.0.1\nupdate add _acme-challenge.%s 300 IN TXT "%s"\nsend\n' "$DOMAIN" "$TOKEN_VALUE" | nsupdate -k /var/run/named/session.key + + return 0 +} + + +clean_challenge() { + local DOMAIN="$1" TOKEN_FILENAME="$2" TOKEN_VALUE="$3" + + # This hook is called after attempting to validate each domain, whether or not validation was successful. Here you can delete files or DNS records that are no longer needed. + # The parameters are the same as for deploy_challenge. + + # Simple example: Use nsupdate with local named + # printf 'server 127.0.0.1\nupdate delete _acme-challenge.%s TXT "%s"\nsend\n' "$DOMAIN" "$TOKEN_VALUE" | nsupdate -k /var/run/named/session.key + + return 0 +} + + +sync_cert() { + local KEYFILE="$1" CERTFILE="$2" FULLCHAINFILE="$3" CHAINFILE="$4" REQUESTFILE="$5" + + # This hook is called after the certificates have been created but before they are symlinked. + # This allows you to sync the files to disk to prevent creating a symlink to empty files on unexpected system crashes. + # This hook is not intended to be used for further processing of certificate files; see deploy_cert for that. + # Parameters: + # KEYFILE - The path of the file containing the private key. + # CERTFILE - The path of the file containing the signed certificate. + # FULLCHAINFILE - The path of the file containing the full certificate chain. + # CHAINFILE - The path of the file containing the intermediate certificate(s). + # REQUESTFILE - The path of the file containing the certificate signing request. + + # Simple example: sync the files before symlinking them + # sync "$KEYFILE" "$CERTFILE" "$FULLCHAINFILE" "$CHAINFILE" "$REQUESTFILE" + + return 0 +} + + +deploy_cert() { + local DOMAIN="$1" KEYFILE="$2" CERTFILE="$3" FULLCHAINFILE="$4" CHAINFILE="$5" TIMESTAMP="$6" + + # This hook is called once for each certificate that has been produced. + # Here you might, for instance, copy your new certificates to service-specific locations and reload the service. + # Parameters: + # DOMAIN - The primary domain name, i.e. the certificate common name (CN). + # KEYFILE - The path of the file containing the private key. + # CERTFILE - The path of the file containing the signed certificate. + # FULLCHAINFILE - The path of the file containing the full certificate chain. + # CHAINFILE - The path of the file containing the intermediate certificate(s). + # TIMESTAMP - Timestamp when the specified certificate was created. + + local FILE LOG_PREFIX="Certificate deployment" + + # Only copy the certificate if there's a CERTSDIR setting. + [[ -n "$CERTSDIR" ]] && { + # If any of the destination files are symlinks, bail out - we don't want to clobber something. + for FILE in "$CERTSDIR/${DOMAIN}_"{cert,key,chain,fullchain}.pem; do + [[ -e "$FILE" ]] && [[ -L "$FILE" ]] && { + notify "error" "Will not copy to symlink '$FILE' during '$DOMAIN' certificate deployment" + # Return 0 so that dehydrated doesn't stop - there may be some more certificates to renew. + return 0 + } + done + + # The first time through this will create the files readable by root only, but better to err on the side of caution. + # Subsequent runs will retain whatever permissions were set by the admin after the first run. + cmp "$CERTFILE" "$CERTSDIR/${DOMAIN}_cert.pem" >/dev/null 2>&1 || { + umask 066 + # shellcheck disable=SC2015 + cat "$CERTFILE" >"$CERTSDIR/${DOMAIN}_cert.pem" && cat "$KEYFILE" >"$CERTSDIR/${DOMAIN}_key.pem" && cat "$CHAINFILE" >"$CERTSDIR/${DOMAIN}_chain.pem" && cat "$FULLCHAINFILE" >"$CERTSDIR/${DOMAIN}_fullchain.pem" || { + notify "error" "Failed to copy certificates/key to '$CERTSDIR' during '$DOMAIN' certificate deployment" + # Return 0 so that dehydrated doesn't stop - there may be some more certificates to renew. + return 0 + } + } + + # Set a marker (used in the exit_hook function) to signal that services should be reloaded at the end of deployments. + touch /run/dehydrated-reload-marker || { + notify "warning" "Failed to create reload marker during '$DOMAIN' certificate deployment - reloading services manually may be required -- check server" + # Return 0 so that dehydrated doesn't stop - there may be some more certificates to renew. + return 0 + } + } + + # Notify the sysadmin of the sucessful renewal. + notify "information" "Sucessful renewal and deployment of certificate/key for '$DOMAIN'" + + return 0 +} + + +deploy_ocsp() { + local DOMAIN="$1" OCSPFILE="$2" TIMESTAMP="$3" + + # This hook is called once for each updated ocsp stapling file that has been produced. + # Here you might, for instance, copy your new ocsp stapling files to service-specific locations and reload the service. + # Parameters: + # DOMAIN - The primary domain name, i.e. the certificate common name (CN). + # OCSPFILE - The path of the ocsp stapling file. + # TIMESTAMP - Timestamp when the specified ocsp stapling file was created. + + # Simple example: Copy file to nginx config + # cp "$OCSPFILE" /etc/nginx/ssl/; chown -R nginx: /etc/nginx/ssl + # systemctl reload nginx + + return 0 +} + + +unchanged_cert() { + local DOMAIN="$1" KEYFILE="$2" CERTFILE="$3" FULLCHAINFILE="$4" CHAINFILE="$5" + + # This hook is called once for each certificate that is still valid and therefore wasn't reissued. + # Parameters: + # DOMAIN - The primary domain name, i.e. the certificate common name (CN). + # KEYFILE - The path of the file containing the private key. + # CERTFILE - The path of the file containing the signed certificate. + # FULLCHAINFILE - The path of the file containing the full certificate chain. + # CHAINFILE - The path of the file containing the intermediate certificate(s). + + return 0 +} + + +invalid_challenge() { + local DOMAIN="$1" RESPONSE="$2" + + # This hook is called if the challenge response has failed, so domain owners can be aware and act accordingly. + # Parameters: + # DOMAIN - The primary domain name, i.e. the certificate common name (CN). + # RESPONSE - The response that the verification server returned + + # Notify the sysadmin. + notify "error" "Validation of '$DOMAIN' failed:" "$RESPONSE" + + return 0 +} + + +request_failure() { + local STATUSCODE="$1" REASON="$2" REQTYPE="$3" HEADERS="$4" + + # This hook is called when an HTTP request fails (e.g., when the ACME server is busy, returns an error, etc). + # It will be called upon any response code that does not start with '2'. Useful to alert admins about problems with requests. + # Parameters: + # STATUSCODE - The HTML status code that originated the error. + # REASON - The specified reason for the error. + # REQTYPE - The kind of request that was made (GET, POST...) + + # Notify the sysadmin. + notify "error" "HTTP $REQTYPE request failed for '$DOMAIN' with code '$STATUSCODE'" "Reason: $REASON" "Headers:" "$HEADERS" + + return 0 +} + + +generate_csr() { + local DOMAIN="$1" CERTDIR="$2" ALTNAMES="$3" + + # This hook is called before any certificate signing operation takes place. + # It can be used to generate or fetch a certificate signing request with external tools. + # The output should be just the cerificate signing request formatted as PEM. + # Parameters: + # DOMAIN - The primary domain as specified in domains.txt. + # This does not need to match with the domains in the CSR, it's basically just the directory name. + # CERTDIR - Certificate output directory for this particular certificate. + # Can be used for storing additional files. + # ALTNAMES - All domain names for the current certificate as specified in domains.txt. + # Again, this doesn't need to match with the CSR, it's just there for convenience. + + # Simple example: Look for pre-generated CSRs + # if [ -e "$CERTDIR/pre-generated.csr" ]; then + # cat "$CERTDIR/pre-generated.csr" + # fi + + return 0 +} + + +startup_hook() { + # This hook is called before the cron command to do some initial tasks (e.g. starting a webserver). + + local LOG_PREFIX="Dehydrated startup" + + # Read services configuration (with sanity check) + services 1 || return 1 + + # Make sure the certificates directory exists. + [[ -n "$CERTSDIR" ]] && { + umask 022 + # shellcheck disable=SC2174 + mkdir -p -m 0755 "$CERTSDIR" 2>/dev/null || { + notify "error" "Failed to create certificate storage directory -- aborting" + return 1 + } + } + + # If an HTTP daemon rc script is available and the service is not already running, start it. + [[ -n "$RCFILE_HTTPD" ]] && { + pgrep -c ${PIDFILE_HTTPD:+-F "$PIDFILE_HTTPD"} "$DAEMON_HTTPD" >/dev/null 2>&1 || { + "$RCFILE_HTTPD" start >/dev/null 2>&1 + sleep 5 + if pgrep -c ${PIDFILE_HTTPD:+-F "$PIDFILE_HTTPD"} "$DAEMON_HTTPD" >/dev/null 2>&1; then + # Set a marker (used in exit_hook()) to signal that the HTTP daemon should be stopped at the end of deployments. + touch /run/dehydrated-http-daemon-stop-marker 2>/dev/null || notify "warning" "Failed to create HTTP daemon stop marker - HTTP daemon will be left running -- check server" + else + notify "error" "Failure of '$RCFILE_HTTPD' to start HTTP daemon -- aborting" + return 1 + fi + } + } + + # Add firewall rules to allow HTTP traffic so the nonce can be validated. + { iptables -N dehydrated && ip6tables -N dehydrated && iptables -I INPUT 1 -j dehydrated && ip6tables -I INPUT 1 -j dehydrated && iptables -I dehydrated 1 -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT && ip6tables -I dehydrated 1 -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT; } >/dev/null 2>&1 || { + notify "error" "Failed to insert firewall rules to allow nonce validation -- aborting" + return 1 + } + + return 0 +} + + +exit_hook() { + local ERROR="$1" + + # This hook is called at the end of the cron command and can be used to do some final (cleanup or other) tasks. + # Parameters: + # ERROR - Contains error message if dehydrated exits with error. + + local DAEMON ERR=0 LOG_PREFIX="Dehydrated shutdown" PIDFILE RCFILE TIMEOUT=30 + + # Read services configuration (without sanity check - this was already done at startup) + services 0 || return 1 + + # Delete firewall rules that was added to allow HTTP traffic. + iptables -C INPUT -j dehydrated >/dev/null 2>&1 && iptables -D INPUT -j dehydrated >/dev/null 2>&1 + ip6tables -C INPUT -j dehydrated >/dev/null 2>&1 && ip6tables -D INPUT -j dehydrated >/dev/null 2>&1 + iptables -F dehydrated >/dev/null 2>&1 + ip6tables -F dehydrated >/dev/null 2>&1 + iptables -X dehydrated >/dev/null 2>&1 + ip6tables -X dehydrated >/dev/null 2>&1 + + # If the reload marker was set, restart services. + [[ -e /run/dehydrated-reload-marker ]] && { + for RCFILE in "${!RCFILE_@}"; do + DAEMON="DAEMON_${RCFILE#RCFILE_}" + PIDFILE="PIDFILE_${RCFILE#RCFILE_}" + # If the HTTP daemon is going to be shut down, there's no need to restart it. + [[ "$RCFILE" == "RCFILE_HTTPD" ]] && [[ -e /run/dehydrated-http-daemon-stop-marker ]] && continue + # Restart the service. + "${!RCFILE}" restart >/dev/null 2>&1 || notify "warning" "Failed to restart service '${!DAEMON}' -- check server" + sleep "$TIMEOUT" + pgrep -c ${PIDFILE:+-F "${!PIDFILE}"} "${!DAEMON}" >/dev/null 2>&1 || { + notify "warning" "Service '${!DAEMON}' exited unexpectedly - trying to start again" + "${!RCFILE}" start >/dev/null 2>&1 || notify "warning" "Failed to start service '${!DAEMON}' -- check server" + sleep "$TIMEOUT" + pgrep -c ${PIDFILE:+-F "${!PIDFILE}"} "${!DAEMON}" >/dev/null 2>&1 || { + notify "warning" "Service '${!DAEMON}' failed to restart correctly -- check server" + ERR=1 + } + } + done + } + + # Remove the reload marker if all services restarted without issue. Keep the marker if any failed. + ((ERR == 0)) && { rm -f /run/dehydrated-reload-marker 2>/dev/null || notify "warning" "Failed to remove services reload marker -- check server"; } + + # If an HTTP daemon was started by dehydrated, stop it now. + ERR=0 + [[ -e /run/dehydrated-http-daemon-stop-marker ]] && { + pgrep -c ${PIDFILE_HTTPD:+-F "$PIDFILE_HTTPD"} "$DAEMON_HTTPD" >/dev/null 2>&1 && { + "$RCFILE_HTTPD" stop >/dev/null 2>&1 || notify "warning" "Failed to gracefully stop service '$DAEMON_HTTPD' -- check server" + sleep "$TIMEOUT" + pgrep -c ${PIDFILE_HTTPD:+-F "$PIDFILE_HTTPD"} "$DAEMON_HTTPD" >/dev/null 2>&1 && { + pkill -TERM ${PIDFILE_HTTPD:+-F "$PIDFILE_HTTPD"} "$DAEMON_HTTPD" >/dev/null 2>&1 || notify "warning" "Failed to -SIGTERM service '$DAEMON_HTTPD' -- check server" + sleep "$TIMEOUT" + pgrep -c ${PIDFILE_HTTPD:+-F "$PIDFILE_HTTPD"} "$DAEMON_HTTPD" >/dev/null 2>&1 && { + pkill -KILL ${PIDFILE_HTTPD:+-F "$PIDFILE_HTTPD"} "$DAEMON_HTTPD" >/dev/null 2>&1 || notify "warning" "Failed to -SIGKILL service '$DAEMON_HTTPD' -- check server" + sleep 5 + } + } + pgrep -c ${PIDFILE_HTTPD:+-F "$PIDFILE_HTTPD"} "$DAEMON_HTTPD" >/dev/null 2>&1 && notify "warning" "Failed to stop HTTP daemon that dehydrated started" && ERR=1 + } + } + + # If the HTTP daemon was stopped correctly, remove the stop marker. + ((ERR == 0)) && { rm -f /run/dehydrated-http-daemon-stop-marker 2>/dev/null || notify "warning" "Failed to remove HTTP daemon stop marker -- check server"; } + + return 0 +} + +# Run the correct function. +HANDLER="$1" +shift +if declare -pF "$HANDLER" >/dev/null 2>&1; then + "$HANDLER" "$@" + exit "$?" +else + exit 0 +fi diff --git a/etc/fusiondirectory/fusiondirectory-apache.conf b/etc/fusiondirectory/fusiondirectory-apache.conf new file mode 100644 index 0000000..9facd2a --- /dev/null +++ b/etc/fusiondirectory/fusiondirectory-apache.conf @@ -0,0 +1,8 @@ +# Include FusionDirectory to your web service +Alias /fusiondirectory /usr/share/fusiondirectory/html + + +# Remove the comment from the line below if you use fusiondirectory-configuration-manager --encrypt-passwords +# include /etc/fusiondirectory/fusiondirectory.secrets + + diff --git a/etc/fusiondirectory/fusiondirectory.conf b/etc/fusiondirectory/fusiondirectory.conf new file mode 100644 index 0000000..ca86517 --- /dev/null +++ b/etc/fusiondirectory/fusiondirectory.conf @@ -0,0 +1,8 @@ + + +
+ + + +
+
diff --git a/etc/fusiondirectory/fusiondirectory.conf.orig b/etc/fusiondirectory/fusiondirectory.conf.orig new file mode 100644 index 0000000..ca86517 --- /dev/null +++ b/etc/fusiondirectory/fusiondirectory.conf.orig @@ -0,0 +1,8 @@ + + +
+ + + +
+
diff --git a/etc/group b/etc/group new file mode 100644 index 0000000..164c458 --- /dev/null +++ b/etc/group @@ -0,0 +1,57 @@ +root:x:0: +daemon:x:1: +bin:x:2: +sys:x:3: +adm:x:4: +tty:x:5: +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: +fax:x:21: +voice:x:22: +cdrom:x:24: +floppy:x:25: +tape:x:26: +sudo:x:27: +audio:x:29: +dip:x:30: +www-data:x:33: +backup:x:34: +operator:x:37: +list:x:38: +irc:x:39: +src:x:40: +shadow:x:42: +utmp:x:43: +video:x:44: +sasl:x:45: +plugdev:x:46: +staff:x:50: +games:x:60: +users:x:100: +nogroup:x:65534: +systemd-journal:x:999: +systemd-network:x:998: +messagebus:x:997: +systemd-resolve:x:996: +input:x:995: +sgx:x:994: +clock:x:993: +kvm:x:992: +render:x:991: +_ssh:x:101: +polkitd:x:990: +ssl-cert:x:102: +sambashare:x:989: +winbindd_priv:x:988: +prometheus:x:103: +uuidd:x:104: +thb:x:500:thb +netdev:x:105: +crontab:x:987: diff --git a/etc/gshadow.gpg b/etc/gshadow.gpg new file mode 100644 index 0000000..55621e5 Binary files /dev/null and b/etc/gshadow.gpg differ diff --git a/etc/hostname b/etc/hostname new file mode 100644 index 0000000..1ab311b --- /dev/null +++ b/etc/hostname @@ -0,0 +1 @@ +core.slackware.uk.net diff --git a/etc/hosts b/etc/hosts new file mode 100644 index 0000000..c7ed8a2 --- /dev/null +++ b/etc/hosts @@ -0,0 +1,5 @@ +127.0.1.1 core core.slackware.uk.net +127.0.0.1 localhost localhost.localdomain +::1 localhost ip6-localhost ip6-loopback localhost.localdomain +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters diff --git a/etc/init.d/.gitignore b/etc/init.d/.gitignore new file mode 100644 index 0000000..e7df9d0 --- /dev/null +++ b/etc/init.d/.gitignore @@ -0,0 +1,3 @@ +/* +!/.gitignore +!/terraform-http-backend diff --git a/etc/init.d/terraform-http-backend b/etc/init.d/terraform-http-backend new file mode 100755 index 0000000..0bc5bb7 --- /dev/null +++ b/etc/init.d/terraform-http-backend @@ -0,0 +1,49 @@ +#!/bin/sh +# Start/stop terraform-http-backend. +# +### BEGIN INIT INFO +# Provides: terraform-http-backend +# Required-Start: $network +# Required-Stop: $network +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Terraform HTTP state backend daemon +# Description: Terraform HTTP state backend daemon +### END INIT INFO + +NAME=terraform-http-backend +DAEMON=/opt/sbin/$NAME +DESC="Terraform HTTP state backend" +SCRIPT=terraform-http-backend + +test -x $DAEMON || exit 0 + +[ -f /etc/default/terraform-http-backend ] && . /etc/default/terraform-http-backend +export TF_USER TF_IP TF_PORT TF_STORAGE_DIR TF_AUTH_ENABLED TF_USERNAME TF_PASSWORD + +. /lib/lsb/init-functions + +case "$1" in + (start) + log_daemon_msg "Starting $DESC" $NAME + /usr/bin/su "$TF_USER" -c "$DAEMON >/dev/null 2>&1 &" + log_end_msg $? + ;; + (stop) + log_daemon_msg "Stopping $DESC" $NAME + /usr/bin/killall -TERM $DAEMON + log_end_msg $? + ;; + (restart|force-reload) + $0 stop && sleep 1 && $0 start + ;; + (status) + status_of_proc $DAEMON $NAME && exit 0 || exit $? + ;; + (*) + echo "Usage: /etc/init.d/$SCRIPT {start|stop|restart|force-reload|status}" + exit 1 + ;; +esac + +exit 0 diff --git a/etc/krb5.conf b/etc/krb5.conf new file mode 100644 index 0000000..3b866e2 --- /dev/null +++ b/etc/krb5.conf @@ -0,0 +1,28 @@ +[logging] +# FIXME: +# default = FILE:/var/log/krb5libs +# kdc = FILE:/var/log/krb5kdc +# admin_server = FILE:/var/log/kadmind + +[libdefaults] +ccache_type = 4 +default_realm = SLACKWARE.UK.NET +dns_lookup_realm = false +dns_lookup_kdc = false +kdc_timesync = 1 +rdns = true +forwardable = true +proxiable = true +ticket_lifetime = 24h +renew_lifetime = 7d + +[realms] +SLACKWARE.UK.NET = { + default_domain = slackware.uk.net + admin_server = core.slackware.uk.net + kdc = core.slackware.uk.net +} + +[domain_realm] +.slackware.uk.net = SLACKWARE.UK.NET +core = SLACKWARE.UK.NET diff --git a/etc/ldap/ldap.conf b/etc/ldap/ldap.conf new file mode 100644 index 0000000..b46f0f5 --- /dev/null +++ b/etc/ldap/ldap.conf @@ -0,0 +1,10 @@ +# LDAP Defaults + +URI ldap://core.slackware.uk.net +BASE dc=slackware,dc=uk,dc=net +VERSION 3 + +TLS_CACERT /etc/certificates/LetsEncrypt-CompleteCertificateStore.pem +TLS_CERT /etc/certificates/core.slackware.uk.net_cert.pem +TLS_KEY /etc/certificates/core.slackware.uk.net_key.pem +TLS_PROTOCOL_MIN 3.3 diff --git a/etc/ldap/schema/.gitignore b/etc/ldap/schema/.gitignore new file mode 100644 index 0000000..6cf35c3 --- /dev/null +++ b/etc/ldap/schema/.gitignore @@ -0,0 +1 @@ +/fusiondirectory/ diff --git a/etc/ldap/schema/rfc2307bis.schema b/etc/ldap/schema/rfc2307bis.schema new file mode 100644 index 0000000..db34365 --- /dev/null +++ b/etc/ldap/schema/rfc2307bis.schema @@ -0,0 +1,288 @@ +# builtin +# +#attributetype ( 1.3.6.1.1.1.1.0 NAME 'uidNumber' +# DESC 'An integer uniquely identifying a user in an administrative domain' +# EQUALITY integerMatch +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 +# SINGLE-VALUE ) + +# builtin +# +#attributetype ( 1.3.6.1.1.1.1.1 NAME 'gidNumber' +# DESC 'An integer uniquely identifying a group in an +# administrative domain' +# EQUALITY integerMatch +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 +# SINGLE-VALUE ) + +attributetype ( 1.3.6.1.1.1.1.2 NAME 'gecos' + DESC 'The GECOS field; the common name' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.1.1.1.3 NAME 'homeDirectory' + DESC 'The absolute path to the home directory' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.1.1.1.4 NAME 'loginShell' + DESC 'The path to the login shell' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.1.1.1.5 NAME 'shadowLastChange' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.1.1.1.6 NAME 'shadowMin' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.1.1.1.7 NAME 'shadowMax' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.1.1.1.8 NAME 'shadowWarning' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.1.1.1.9 NAME 'shadowInactive' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.1.1.1.10 NAME 'shadowExpire' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.1.1.1.11 NAME 'shadowFlag' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.1.1.1.12 NAME 'memberUid' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.1.1.1.13 NAME 'memberNisNetgroup' + EQUALITY caseExactIA5Match + SUBSTR caseExactIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.1.1.1.14 NAME 'nisNetgroupTriple' + DESC 'Netgroup triple' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.1.1.1.15 NAME 'ipServicePort' + DESC 'Service port number' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.1.1.1.16 NAME 'ipServiceProtocol' + DESC 'Service protocol name' + SUP name ) + +attributetype ( 1.3.6.1.1.1.1.17 NAME 'ipProtocolNumber' + DESC 'IP protocol number' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.1.1.1.18 NAME 'oncRpcNumber' + DESC 'ONC RPC number' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) +attributetype ( 1.3.6.1.1.1.1.19 NAME 'ipHostNumber' + DESC 'IPv4 addresses as a dotted decimal omitting leading + zeros or IPv6 addresses as defined in RFC2373' + SUP name ) + +attributetype ( 1.3.6.1.1.1.1.20 NAME 'ipNetworkNumber' + DESC 'IP network as a dotted decimal, eg. 192.168, + omitting leading zeros' + SUP name + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.1.1.1.21 NAME 'ipNetmaskNumber' + DESC 'IP netmask as a dotted decimal, eg. 255.255.255.0, + omitting leading zeros' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.1.1.1.22 NAME 'macAddress' + DESC 'MAC address in maximal, colon separated hex + notation, eg. 00:00:92:90:ee:e2' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.1.1.1.23 NAME 'bootParameter' + DESC 'rpc.bootparamd parameter' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.1.1.1.24 NAME 'bootFile' + DESC 'Boot image name' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.1.1.1.26 NAME 'nisMapName' + DESC 'Name of a A generic NIS map' + SUP name ) + +attributetype ( 1.3.6.1.1.1.1.27 NAME 'nisMapEntry' + DESC 'A generic NIS entry' + EQUALITY caseExactIA5Match + SUBSTR caseExactIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.1.1.1.28 NAME 'nisPublicKey' + DESC 'NIS public key' + EQUALITY octetStringMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.1.1.1.29 NAME 'nisSecretKey' + DESC 'NIS secret key' + EQUALITY octetStringMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.1.1.1.30 NAME 'nisDomain' + DESC 'NIS domain' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26) + +attributetype ( 1.3.6.1.1.1.1.31 NAME 'automountMapName' + DESC 'automount Map Name' + EQUALITY caseExactIA5Match + SUBSTR caseExactIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.1.1.1.32 NAME 'automountKey' + DESC 'Automount Key value' + EQUALITY caseExactIA5Match + SUBSTR caseExactIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.1.1.1.33 NAME 'automountInformation' + DESC 'Automount information' + EQUALITY caseExactIA5Match + SUBSTR caseExactIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) + +objectclass ( 1.3.6.1.1.1.2.0 NAME 'posixAccount' SUP top AUXILIARY + DESC 'Abstraction of an account with POSIX attributes' + MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory ) + MAY ( userPassword $ loginShell $ gecos $ + description ) ) + +objectclass ( 1.3.6.1.1.1.2.1 NAME 'shadowAccount' SUP top AUXILIARY + DESC 'Additional attributes for shadow passwords' + MUST uid + MAY ( userPassword $ description $ + shadowLastChange $ shadowMin $ shadowMax $ + shadowWarning $ shadowInactive $ + shadowExpire $ shadowFlag ) ) + +objectclass ( 1.3.6.1.1.1.2.2 NAME 'posixGroup' SUP top AUXILIARY + DESC 'Abstraction of a group of accounts' + MUST gidNumber + MAY ( userPassword $ memberUid $ + description ) ) + +objectclass ( 1.3.6.1.1.1.2.3 NAME 'ipService' SUP top STRUCTURAL + DESC 'Abstraction an Internet Protocol service. + Maps an IP port and protocol (such as tcp or udp) + to one or more names; the distinguished value of + the cn attribute denotes the services canonical + name' + MUST ( cn $ ipServicePort $ ipServiceProtocol ) + MAY description ) + +objectclass ( 1.3.6.1.1.1.2.4 NAME 'ipProtocol' SUP top STRUCTURAL + DESC 'Abstraction of an IP protocol. Maps a protocol number + to one or more names. The distinguished value of the cn + attribute denotes the protocols canonical name' + MUST ( cn $ ipProtocolNumber ) + MAY description ) + +objectclass ( 1.3.6.1.1.1.2.5 NAME 'oncRpc' SUP top STRUCTURAL + DESC 'Abstraction of an Open Network Computing (ONC) + [RFC1057] Remote Procedure Call (RPC) binding. + This class maps an ONC RPC number to a name. + The distinguished value of the cn attribute denotes + the RPC services canonical name' + MUST ( cn $ oncRpcNumber ) + MAY description ) + +objectclass ( 1.3.6.1.1.1.2.6 NAME 'ipHost' SUP top AUXILIARY + DESC 'Abstraction of a host, an IP device. The distinguished + value of the cn attribute denotes the hosts canonical + name. Device SHOULD be used as a structural class' + MUST ( cn $ ipHostNumber ) + MAY ( userPassword $ l $ description $ manager ) ) + +objectclass ( 1.3.6.1.1.1.2.7 NAME 'ipNetwork' SUP top STRUCTURAL + DESC 'Abstraction of a network. The distinguished value of + the cn attribute denotes the networks canonical name' + MUST ipNetworkNumber + MAY ( cn $ ipNetmaskNumber $ l $ description $ manager ) ) + +objectclass ( 1.3.6.1.1.1.2.8 NAME 'nisNetgroup' SUP top STRUCTURAL + DESC 'Abstraction of a netgroup. May refer to other netgroups' + MUST cn + MAY ( nisNetgroupTriple $ memberNisNetgroup $ description ) ) + +objectclass ( 1.3.6.1.1.1.2.9 NAME 'nisMap' SUP top STRUCTURAL + DESC 'A generic abstraction of a NIS map' + MUST nisMapName + MAY description ) + +objectclass ( 1.3.6.1.1.1.2.10 NAME 'nisObject' SUP top STRUCTURAL + DESC 'An entry in a NIS map' + MUST ( cn $ nisMapEntry $ nisMapName ) + MAY description ) + +objectclass ( 1.3.6.1.1.1.2.11 NAME 'ieee802Device' SUP top AUXILIARY + DESC 'A device with a MAC address; device SHOULD be + used as a structural class' + MAY macAddress ) + +objectclass ( 1.3.6.1.1.1.2.12 NAME 'bootableDevice' SUP top AUXILIARY + DESC 'A device with boot parameters; device SHOULD be + used as a structural class' + MAY ( bootFile $ bootParameter ) ) + +objectclass ( 1.3.6.1.1.1.2.14 NAME 'nisKeyObject' SUP top AUXILIARY + DESC 'An object with a public and secret key' + MUST ( cn $ nisPublicKey $ nisSecretKey ) + MAY ( uidNumber $ description ) ) + +objectclass ( 1.3.6.1.1.1.2.15 NAME 'nisDomainObject' SUP top AUXILIARY + DESC 'Associates a NIS domain with a naming context' + MUST nisDomain ) + +objectclass ( 1.3.6.1.1.1.2.16 NAME 'automountMap' SUP top STRUCTURAL + MUST ( automountMapName ) + MAY description ) + +objectclass ( 1.3.6.1.1.1.2.17 NAME 'automount' SUP top STRUCTURAL + DESC 'Automount information' + MUST ( automountKey $ automountInformation ) + MAY description ) +## namedObject is needed for groups without members +objectclass ( 1.3.6.1.4.1.5322.13.1.1 NAME 'namedObject' SUP top + STRUCTURAL MAY cn ) + diff --git a/etc/login.defs b/etc/login.defs new file mode 100644 index 0000000..cef0fc7 --- /dev/null +++ b/etc/login.defs @@ -0,0 +1,192 @@ +# +# /etc/login.defs - Configuration control definitions for the shadow package. +# + +# 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 display of unknown usernames when login(1) 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 yes + +# +# If defined, file which maps tty line to TERM environment parameter. +# Each line of the file is in a format similar to "vt100 tty01". +# +#TTYTYPE_FILE /etc/ttytype + +# +# 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/bin:/usr/bin:/bin:/usr/local/games:/usr/games + +# +# Terminal permissions for terminals after login(1). +# These settings are ignored for remote and other logins. +# +# TTYGROUP Login tty will be assigned this group ownership. +# TTYPERM Login tty will be set to this permission. +# +#TTYGROUP tty +TTYPERM 0600 + +# +# Login configuration initializations: +# +# ERASECHAR Terminal ERASE character ('\010' = backspace). +# KILLCHAR Terminal KILL character ('\025' = CTRL/U). +# +# The ERASECHAR and KILLCHAR are used only on System V machines. +# +ERASECHAR 0177 +KILLCHAR 025 + +# HOME_MODE is used by useradd(8) and newusers(8) to set the mode for new +# home directories. +HOME_MODE 0700 + +# +# 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(8) +# +UID_MIN 1000 +UID_MAX 60000 +# System accounts +#SYS_UID_MIN 101 +#SYS_UID_MAX 999 +# Extra per user uids +SUB_UID_MIN 100000 +SUB_UID_MAX 600100000 +SUB_UID_COUNT 65536 + +# +# Min/max values for automatic gid selection in groupadd(8) +# +GID_MIN 1000 +GID_MAX 60000 +# System accounts +#SYS_GID_MIN 101 +#SYS_GID_MAX 999 +# Extra per user group ids +SUB_GID_MIN 100000 +SUB_GID_MAX 600100000 +SUB_GID_COUNT 65536 + +# +# Max number of login(1) 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 3 + +# +# Max time in seconds for login(1) +# +LOGIN_TIMEOUT 30 + +# +# Which fields may be changed by regular users using chfn(1) - 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 + +# +# 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 BCRYPT, BCRYPT-based algorithm will be used for encrypting password +# If set to YESCRYPT, YESCRYPT-based algorithm will be used for encrypting password +# If set to DES, DES-based algorithm will be used for encrypting password (default) +# MD5 and DES should not be used for new hashes, see crypt(5) for recommendations. +# Overrides the MD5_CRYPT_ENAB option +# +# Note: It is recommended to use a value consistent with +# the PAM modules configuration. +# +ENCRYPT_METHOD YESCRYPT + +# +# Should login be allowed if we can't cd to the home directory? +# Default is no. +# +DEFAULT_HOME yes + +# +# The pwck(8) utility emits a warning for any system account with a home +# directory that does not exist. Some system accounts intentionally do +# not have a home directory. Such accounts may have this string as +# their home directory in /etc/passwd to avoid a spurious warning. +# +NONEXISTENT /nonexistent + +# +# 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(8) will remove the user's group if it contains no more +# members, and useradd(8) will create by default a group with the name of the +# user. +# +# Other former uses of this variable are not used in PAM environments, such as +# Debian. +# +USERGROUPS_ENAB yes diff --git a/etc/motd b/etc/motd new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/etc/motd @@ -0,0 +1 @@ + diff --git a/etc/msmtp.aliases b/etc/msmtp.aliases new file mode 100644 index 0000000..ba7c32b --- /dev/null +++ b/etc/msmtp.aliases @@ -0,0 +1 @@ +default: sysadmin@slackware.uk diff --git a/etc/msmtprc.gpg b/etc/msmtprc.gpg new file mode 100644 index 0000000..8f86af5 --- /dev/null +++ b/etc/msmtprc.gpg @@ -0,0 +1,2 @@ +   +SH uo샜2Li60*>,QDI2fX~UBؕ4dwEpin `׎U7v:Or\F(,7g^j\Ⱥ^xߚ]ZJop${N,VOha~'eYꍣC"REϗ-/ݚH +c @ow^2^p|d+L1"Lx "0 ^q PISukJ>&zooҺRo8vg̤jq55SoT \ No newline at end of file diff --git a/etc/network/.gitignore b/etc/network/.gitignore new file mode 100644 index 0000000..bedda81 --- /dev/null +++ b/etc/network/.gitignore @@ -0,0 +1,6 @@ +/if-down.d/ +/if-post-down.d/ +/if-post-up.d/ +/if-pre-down.d/ +/if-pre-up.d/ +/if-up.d/ diff --git a/etc/network/interfaces b/etc/network/interfaces new file mode 100644 index 0000000..830d585 --- /dev/null +++ b/etc/network/interfaces @@ -0,0 +1,3 @@ +# interfaces(5) file used by ifup(8) and ifdown(8) +# Include files from /etc/network/interfaces.d: +source /etc/network/interfaces.d/* diff --git a/etc/network/interfaces.d/eth0 b/etc/network/interfaces.d/eth0 new file mode 100644 index 0000000..3e9a27d --- /dev/null +++ b/etc/network/interfaces.d/eth0 @@ -0,0 +1,9 @@ +auto eth0 +iface eth0 inet static + address 5.101.171.215/28 + gateway 5.101.171.209 + mtu 1500 +iface eth0 inet6 static + address 2a01:a500:2981:1::d7/64 + gateway 2a01:a500:2981:1:ff:ff:ff:ff + mtu 1500 diff --git a/etc/network/interfaces.d/eth1 b/etc/network/interfaces.d/eth1 new file mode 100644 index 0000000..37144f7 --- /dev/null +++ b/etc/network/interfaces.d/eth1 @@ -0,0 +1,4 @@ +auto eth1 +iface eth1 inet static + address 10.254.0.215/24 + mtu 1500 diff --git a/etc/passwd b/etc/passwd new file mode 100644 index 0000000..6937e4a --- /dev/null +++ b/etc/passwd @@ -0,0 +1,28 @@ +root:x:0:0:root:/root:/bin/bash +daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin +bin:x:2:2:bin:/bin:/usr/sbin/nologin +sys:x:3:3:sys:/dev:/usr/sbin/nologin +sync:x:4:65534:sync:/bin:/bin/sync +games:x:5:60:games:/usr/games:/usr/sbin/nologin +man:x:6:12:man:/var/cache/man:/usr/sbin/nologin +lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin +mail:x:8:8:mail:/var/mail:/usr/sbin/nologin +news:x:9:9:news:/var/spool/news:/usr/sbin/nologin +uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin +proxy:x:13:13:proxy:/bin:/usr/sbin/nologin +www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin +backup:x:34:34:backup:/var/backups:/usr/sbin/nologin +list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin +irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin +_apt:x:42:65534::/nonexistent:/usr/sbin/nologin +nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin +systemd-network:x:998:998:systemd Network Management:/:/usr/sbin/nologin +messagebus:x:997:997:System Message Bus:/nonexistent:/usr/sbin/nologin +systemd-resolve:x:996:996:systemd Resolver:/:/usr/sbin/nologin +polkitd:x:990:990:User for polkitd:/:/usr/sbin/nologin +sshd:x:989:65534:sshd user:/run/sshd:/usr/sbin/nologin +prometheus:x:100:103:Prometheus daemon:/var/lib/prometheus:/usr/sbin/nologin +uuidd:x:101:104::/run/uuidd:/usr/sbin/nologin +thb:x:500:500:terraform http backend:/var/lib/terraform-http-backend:/bin/bash +sysadmin:x:1000:100:Systems' Administrator:/home/sysadmin:/bin/bash +dhcpcd:x:102:65534:DHCP Client Daemon:/usr/lib/dhcpcd:/bin/false diff --git a/etc/phpldapadmin/.gitignore b/etc/phpldapadmin/.gitignore new file mode 100644 index 0000000..4be8e33 --- /dev/null +++ b/etc/phpldapadmin/.gitignore @@ -0,0 +1,3 @@ +/* +!/.gitignore +!/*.gpg diff --git a/etc/phpldapadmin/config.php.gpg b/etc/phpldapadmin/config.php.gpg new file mode 100644 index 0000000..6e5ba71 Binary files /dev/null and b/etc/phpldapadmin/config.php.gpg differ diff --git a/etc/pkglist b/etc/pkglist new file mode 100644 index 0000000..6ae8d51 --- /dev/null +++ b/etc/pkglist @@ -0,0 +1,581 @@ +adduser +apache2 +apache2-bin +apache2-data +apache2-utils +apt +attr +autoconf +automake +autopoint +autotools-dev +base-files +base-passwd +bash +bash-completion +bind9-host +bind9-libs +binutils +binutils-common +binutils-x86-64-linux-gnu +bsd-mailx +bsdextrautils +bsdutils +build-essential +bzip2 +ca-certificates +coreutils +cpp +cpp-14 +cpp-14-x86-64-linux-gnu +cpp-x86-64-linux-gnu +cron +cron-daemon-common +cronutils +curl +dash +dbus +dbus-bin +dbus-daemon +dbus-session-bus-common +dbus-system-bus-common +dbus-user-session +debconf +debhelper +debian-archive-keyring +debianutils +dehydrated +dh-autoreconf +dh-strip-nondeterminism +dhcpcd-base +dialog +diffutils +dirmngr +distro-info-data +dpkg +dpkg-dev +dummy-default-mta +dwz +equivs +fakeroot +file +findutils +fontconfig-config +fonts-dejavu-core +fonts-dejavu-mono +fonts-droid-fallback +fonts-noto-mono +fonts-urw-base35 +freeipmi-common +fusiondirectory +fusiondirectory-integrator +fusiondirectory-schema +fusiondirectory-smarty3-acl-render +fusiondirectory-theme-oxygen +fusiondirectory-tools +g++ +g++-14 +g++-14-x86-64-linux-gnu +g++-x86-64-linux-gnu +gcc +gcc-14 +gcc-14-base +gcc-14-x86-64-linux-gnu +gcc-x86-64-linux-gnu +gettext +gettext-base +ghostscript +git +git-man +gnupg +gnupg-l10n +gnupg-utils +gpg +gpg-agent +gpg-wks-client +gpgconf +gpgsm +gpgv +grep +groff-base +gsasl-common +gzip +hicolor-icon-theme +hostname +ifupdown +imagemagick-7-common +init +init-system-helpers +intltool-debian +ipmitool +iproute2 +iptables +iputils-ping +iso-codes +javascript-common +jq +kmod +krb5-config +krb5-locales +krb5-user +ldap-utils +less +libabsl20240722 +libacl1 +libalgorithm-diff-perl +libalgorithm-diff-xs-perl +libalgorithm-merge-perl +libaom3 +libapache2-mod-php8.4 +libapparmor1 +libapr1t64 +libaprutil1-dbd-sqlite3 +libaprutil1-ldap +libaprutil1t64 +libapt-pkg7.0 +libarchive-cpio-perl +libarchive-zip-perl +libargon2-1 +libasan8 +libassuan9 +libatomic1 +libattr1 +libaudit-common +libaudit1 +libavahi-client3 +libavahi-common-data +libavahi-common3 +libavif16 +libbinutils +libblkid1 +libbpf1 +libbrotli1 +libbsd0 +libbz2-1.0 +libc-bin +libc-client2007e +libc-dev-bin +libc-l10n +libc6 +libc6-dev +libcap-ng0 +libcap2 +libcap2-bin +libcbor0.10 +libcc1-0 +libcom-err2 +libcrypt-dev +libcrypt1 +libctf-nobfd0 +libctf0 +libcups2t64 +libcurl3t64-gnutls +libcurl4t64 +libdav1d7 +libdb5.3t64 +libdbus-1-3 +libde265-0 +libdebconfclient0 +libdebhelper-perl +libdeflate0 +libdialog15 +libdpkg-perl +libduktape207 +libedit2 +libelf1t64 +liberror-perl +libestr0 +libexpat1 +libfakeroot +libfastjson4 +libffi8 +libfftw3-double3 +libfido2-1 +libfile-fcntllock-perl +libfile-stripnondeterminism-perl +libfontconfig1 +libfontenc1 +libfreeipmi17 +libfreetype6 +libfstrm0 +libgav1-1 +libgcc-14-dev +libgcc-s1 +libgcrypt20 +libgd3 +libgdbm-compat4t64 +libgdbm6t64 +libglib2.0-0t64 +libglib2.0-data +libgmp10 +libgnutls30t64 +libgomp1 +libgpg-error-l10n +libgpg-error0 +libgpgme11t64 +libgpm2 +libgprofng0 +libgs-common +libgs10 +libgs10-common +libgsasl18 +libgssapi-krb5-2 +libgssglue1 +libgssrpc4t64 +libheif-plugin-aomenc +libheif-plugin-dav1d +libheif-plugin-libde265 +libheif-plugin-x265 +libheif1 +libhogweed6t64 +libhwasan0 +libice6 +libicu76 +libidn12 +libidn2-0 +libijs-0.35 +libimagequant0 +libio-pty-perl +libip4tc2 +libip6tc2 +libipc-run-perl +libisl23 +libitm1 +libjansson4 +libjbig0 +libjbig2dec0 +libjemalloc2 +libjpeg62-turbo +libjq1 +libjs-prototype +libjs-scriptaculous +libjson-c5 +libk5crypto3 +libkadm5clnt-mit12 +libkadm5srv-mit12 +libkdb5-10t64 +libkeyutils1 +libkmod2 +libkrb5-3 +libkrb5support0 +libksba8 +liblastlog2-2 +liblcms2-2 +libldap-common +libldap2 +libldb2 +liblerc4 +liblmdb0 +liblocale-gettext-perl +liblockfile-bin +liblockfile1 +liblognorm5 +liblqr-1-0 +liblsan0 +libltdl-dev +libltdl7 +liblua5.4-0 +liblz4-1 +liblzma5 +libmagic-mgc +libmagic1t64 +libmagickcore-7.q16-10 +libmagickwand-7.q16-10 +libmail-sendmail-perl +libmaxminddb0 +libmd0 +libmnl0 +libmount1 +libmpc3 +libmpfr6 +libncurses6 +libncursesw6 +libnetfilter-conntrack3 +libnettle8t64 +libnfnetlink0 +libnftables1 +libnftnl11 +libnghttp2-14 +libnghttp3-9 +libngtcp2-16 +libngtcp2-crypto-gnutls8 +libnpth0t64 +libnss-systemd +libnss-winbind +libntlm0 +libnuma1 +libnvme1t64 +libonig5 +libopenipmi0t64 +libopenjp2-7 +libp11-kit0 +libpam-cap +libpam-modules +libpam-modules-bin +libpam-runtime +libpam-systemd +libpam-winbind +libpam0g +libpaper-utils +libpaper2 +libpci3 +libpcre2-8-0 +libperl5.40 +libpipeline1 +libpng16-16t64 +libpolkit-agent-1-0 +libpolkit-gobject-1-0 +libpopt0 +libproc2-0 +libprotobuf-c1 +libpsl5t64 +libpython3-stdlib +libpython3.13 +libpython3.13-minimal +libpython3.13-stdlib +libquadmath0 +librav1e0.7 +libraw23t64 +libreadline8t64 +librtmp1 +libsasl2-2 +libsasl2-modules +libsasl2-modules-db +libseccomp2 +libsecret-1-0 +libsecret-common +libselinux1 +libsemanage-common +libsemanage2 +libsensors-config +libsensors5 +libsepol2 +libsframe1 +libsharpyuv0 +libsm6 +libsmartcols1 +libsnmp-base +libsnmp40t64 +libsodium23 +libsqlite3-0 +libss2 +libssh2-1t64 +libssl3t64 +libstdc++-14-dev +libstdc++6 +libsvtav1enc2 +libsys-hostname-long-perl +libsystemd-shared +libsystemd0 +libtalloc2 +libtasn1-6 +libtdb1 +libtevent0t64 +libtext-charwidth-perl +libtext-wrapi18n-perl +libtiff6 +libtime-duration-perl +libtimedate-perl +libtinfo6 +libtirpc-common +libtirpc3t64 +libtool +libtsan2 +libubsan1 +libuchardet0 +libudev1 +libunistring5 +liburcu8t64 +liburing2 +libuuid1 +libuv1t64 +libwbclient0 +libwebp7 +libwebpdemux2 +libwebpmux3 +libwrap0 +libwtmpdb0 +libx11-6 +libx11-data +libx265-215 +libxau6 +libxcb1 +libxdmcp6 +libxext6 +libxml2 +libxpm4 +libxslt1.1 +libxt6t64 +libxtables12 +libxxhash0 +libyaml-0-2 +libyuv0 +libzstd1 +linux-libc-dev +linux-sysctl-defaults +locales +locales-all +login +login.defs +logrotate +lsb-release +lynx +lynx-common +m4 +mailcap +make +man-db +manpages +manpages-dev +mawk +media-types +mlock +moreutils +mount +msmtp +nano +ncurses-base +ncurses-bin +ncurses-term +net-tools +netbase +nftables +nvme-cli +openipmi +openssh-client +openssh-server +openssh-sftp-server +openssl +openssl-provider-legacy +oxygen-icon-theme +passwd +patch +pci.ids +perl +perl-base +perl-modules-5.40 +php +php-bcmath +php-bz2 +php-cas +php-common +php-curl +php-fpdf +php-fpm +php-gd +php-gmp +php-intl +php-ldap +php-mbstring +php-sqlite3 +php-xml +php-yaml +php8.4 +php8.4-bcmath +php8.4-bz2 +php8.4-cli +php8.4-common +php8.4-curl +php8.4-fpm +php8.4-gd +php8.4-gmp +php8.4-imagick +php8.4-imap +php8.4-intl +php8.4-ldap +php8.4-mbstring +php8.4-opcache +php8.4-readline +php8.4-sqlite3 +php8.4-xml +php8.4-yaml +phpldapadmin +pinentry-curses +pkexec +po-debconf +polkitd +poppler-data +procps +prometheus-node-exporter +prometheus-node-exporter-collectors +psmisc +publicsuffix +python-apt-common +python3 +python3-anyio +python3-apt +python3-bcrypt +python3-certifi +python3-cffi-backend +python3-click +python3-cryptography +python3-decorator +python3-dnspython +python3-gpg +python3-h11 +python3-h2 +python3-hpack +python3-httpcore +python3-httpx +python3-hyperframe +python3-idna +python3-ldb +python3-linkify-it +python3-markdown +python3-markdown-it +python3-mdurl +python3-minimal +python3-prometheus-client +python3-pygments +python3-rich +python3-samba +python3-sniffio +python3-talloc +python3-tdb +python3-uc-micro +python3-yaml +python3.13 +python3.13-minimal +readline-common +rpcsvc-proto +rsyslog +runit-helper +samba +samba-ad-dc +samba-ad-provision +samba-common +samba-common-bin +samba-dsdb-modules +samba-libs +sed +sensible-utils +sgml-base +shared-mime-info +smarty-gettext +smarty3 +sqv +sshguard +ssl-cert +sudo +systemd +systemd-resolved +systemd-sysv +sysvinit-utils +tar +tdb-tools +tzdata +ucf +udev +util-linux +uuid-runtime +vim +vim-common +vim-runtime +winbind +x11-common +xdg-user-dirs +xfonts-encodings +xfonts-utils +xml-core +xz-utils +zlib1g diff --git a/etc/pla/config.php.gpg b/etc/pla/config.php.gpg new file mode 100644 index 0000000..6e5ba71 Binary files /dev/null and b/etc/pla/config.php.gpg differ diff --git a/etc/pushover-client/.gitignore b/etc/pushover-client/.gitignore new file mode 100644 index 0000000..4be8e33 --- /dev/null +++ b/etc/pushover-client/.gitignore @@ -0,0 +1,3 @@ +/* +!/.gitignore +!/*.gpg diff --git a/etc/pushover-client/default.gpg b/etc/pushover-client/default.gpg new file mode 100644 index 0000000..ce1eae4 --- /dev/null +++ b/etc/pushover-client/default.gpg @@ -0,0 +1,2 @@ +   +MYQ-қGR0JZ9S\P(rvғ \Sh05!N؝opĒu sKyޅI~ vh3>2=l"d2F8tMi<>"Qi31[,N3ʞ᱉ \ No newline at end of file diff --git a/etc/resolv.conf b/etc/resolv.conf new file mode 100644 index 0000000..ff531e2 --- /dev/null +++ b/etc/resolv.conf @@ -0,0 +1,6 @@ +options timeout:2 +options edns0 +search slackware.uk.net +nameserver 5.101.171.216 +nameserver 5.101.171.217 +nameserver 185.176.90.169 diff --git a/etc/rsyslog.conf b/etc/rsyslog.conf new file mode 100644 index 0000000..e3caae5 --- /dev/null +++ b/etc/rsyslog.conf @@ -0,0 +1,143 @@ +# Load modules. +module(load="imudp") +module(load="imtcp") +module(load="builtin:omfile" dirCreateMode="0750" dirOwnerNum="0" dirGroupNum="0" fileCreateMode="0640" fileOwnerNum="0" fileGroupNum="0" compression.driver="zstd") + + +# Global configuration. +global( + workDirectory="/var/lib/rsyslog" + #stdlog.channelspec="on" + maxMessageSize="16K" + senders.keepTrack="on" + senders.timeoutAfter="2419200" + senders.reportGoneAway="on" + senders.reportNew="on" +) + + +# Inputs. +input(type="imudp" port="25414" ruleset="syslog") +input(type="imudp" port="25415" ruleset="httplog") +input(type="imtcp" port="25414" ruleset="syslog") + + +# Rulesets. +ruleset(name="syslog") { + set $.host = tolower(field($hostname, ".", 1)); + set $.domain = tolower(re_extract($hostname, '[^.]+\\.(.*)', 0, 1, "unknown_domain")); + if ($app-name != "") then { + set $.proc = $app-name; + if ($procid != "" and $procid != "-") then { + set $.proc = '[' & $procid & ']'; + } + } else { + set $.proc = '-'; + } + if ($msgid != "") then { + set $.id = $msgid; + } else { + set $.id = '-'; + } + + template(name="LogLineSingleHost" type="string" string="%timereported:::date-utc,date-rfc3339% %$.host% %pri-text% %$.proc% %$.id% :%msg:::sp-if-no-1st-sp%%msg:::escape-cc,drop-last-lf%\n") + template(name="LogLineAllHosts" type="string" string="%timereported:::date-utc,date-rfc3339% %hostname% %pri-text% %$.proc% %$.id% :%msg:::sp-if-no-1st-sp%%msg:::escape-cc,drop-last-lf%\n") + +# FIXME: Log each facility to the AllHosts logs. Compression? + if prifilt("auth.*,authpriv.*") then { + action(type="omfile" file="/tmp/log/AllHosts/auth" template="LogLineAllHosts" zipLevel="6" asyncWriting="on" flushInterval="5" ioBufferSize="64k" ) + } else if ... then { + + + + template(name="LogFileeSingleHost" type="string" string="/tmp/logs/%$.host%/ +%timereported:::date-utc,date-rfc3339% %$.host% %pri-text% %$.proc% %$.id% :%msg:::sp-if-no-1st-sp%%msg:::escape-cc,drop-last-lf%\n") + + + + if prifilt("*.info") then { + action(type="omfile" file="/var/log/info.log") + } +} + + + + +#template(name="SyslogLineFormat" type="list") { +# property(name="timereported" dateFormat="rfc3339" caseConversion="lower") # Timestamp yyyy-MM-dd'T'HH:mm:ss.SSS'Z' +# constant(value=" ") +# property(name="hostname") # Hostname +# constant(value=" ") +# property(name="syslogfacility") # Facility +# constant(value=".") +# property(name="syslogpriority") # Log priority +# constant(value=" ") +# property(name="syslogtag") # Syslog tag +# constant(value=": ") +# property(name="msg") # Message content +# constant(value="\n") +#} + + + + +#template(name="LogHostFile" type="string" string="/mnt/Data/logs/%HOSTNAME:::escape-cc,secpath-replace%/ +#%TIMESTAMP:::date-utc,date-year%/%TIMESTAMP:::date-utc,date-month%/%TIMESTAMP:::date-utc,date-day%/ +# %syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n") + +#template(name="LogAllHostsFile" type="string" string="/mnt/Data/logs/AllHosts/ +#%TIMESTAMP:::date-utc,date-year%/%TIMESTAMP:::date-utc,date-month%/%TIMESTAMP:::date-utc,date-day%/ +# %syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n") + + + + +#VMWare: RFC 5424 + + + +# Parser. +#parser( +# name="FIXME" +# type="pmnormalize" +# rule=[ +# "rule=:<%pri:number%> %fromhost-ip:ipv4% %hostname:word% %syslogtag:char-to:\\x3a%: %msg:rest%", +# "rule=:<%pri:number%> %hostname:word% %fromhost-ip:ipv4% %syslogtag:char-to:\\x3a%: %msg:rest%" +# ] +#) + + +# Rules +#ruleset(name="outp" parser="custom.pmnormalize") { +# action(type="omfile" File="/tmp/output") +#} + + +# Outputs. +action(type="omfile" file="/tmp/messages" template="LogLineSingleHost") + + + +# Include additional configurations. +include(file="/etc/rsyslog.d/*.conf" mode="optional") + + + + +### Examples #### + +# Send all logs to remote syslog via UDP. +# An on-disk queue is created for this action. If the remote host is +# down, messages are spooled to disk and sent when it is up again. +#*.* action( +# type="omfwd" +# target="192.168.0.1" +# port="514" +# protocol="udp" +# queue.filename="fwdRule1" # unique name prefix for spool files +# queue.type="LinkedList" +# queue.maxDiskSpace="256m" +# queue.saveOnShutdown="on" +# action.resumeRetryCount="-1" +# action.resumeInterval="30" +#) diff --git a/etc/samba/smb.conf b/etc/samba/smb.conf new file mode 100644 index 0000000..7279919 --- /dev/null +++ b/etc/samba/smb.conf @@ -0,0 +1,45 @@ +[global] +realm = SLACKWARE.UK.NET +netbios name = CORE +workgroup = SLACKWAREUKNET +server string = "slackware.uk.net Domain Controller" +# FIXME: +# dns forwarder = 5.101.171.216 5.101.171.217 185.176.90.169 +dns forwarder = 216.119.155.58 185.176.90.169 +allow dns updates = no +tls cafile = /etc/ssl/certs/ca-certificates.crt +tls certfile = /etc/certificates/core.slackware.uk.net_cert.pem +tls keyfile = /etc/certificates/core.slackware.uk.net_key.pem +tls verify peer = ca_and_name_if_available +log level = 1 +logging = syslog:local5 +log file = /var/log/core.slackware.uk.net/today/samba/samba-debug +debug syslog format = always +debug hires timestamp = yes +enable core files = no +idmap config * : backend = tdb +# There are only 568 IDs mapped into the container by TrueNAS, so limit the number that can be used. +idmap config * : range = 10000-10500 +idmap_ldb:use rfc2307 = yes +password hash userPassword schemes = CryptSHA512 +server role = active directory domain controller +username map = /etc/samba/smbusers +vfs objects = dfs_samba4 posixacl acl_xattr +nfs4acl_xattr:encoding = nfs +nfs4acl_xattr:version = 41 +nfs4acl_xattr:xattr_name = user.nfs4_acl +nfs4acl_xattr:default acl style = windows +acl_xattr:security_acl_name = user.NTACL +acl_xattr:default acl style = windows + +# [homes] + +# [printers] + +[sysvol] +path = /var/lib/samba/sysvol +write list = @'Domain Admins@slackware.uk.net' + +[netlogon] +path = /var/lib/samba/sysvol/slackware.uk.net/scripts +write list = @'Domain Admins@slackware.uk.net' diff --git a/etc/samba/smbusers b/etc/samba/smbusers new file mode 100644 index 0000000..6f2443b --- /dev/null +++ b/etc/samba/smbusers @@ -0,0 +1 @@ +root = Administrator diff --git a/etc/shadow.gpg b/etc/shadow.gpg new file mode 100644 index 0000000..271a115 Binary files /dev/null and b/etc/shadow.gpg differ diff --git a/etc/ssh/.gitignore b/etc/ssh/.gitignore new file mode 100644 index 0000000..6adaf00 --- /dev/null +++ b/etc/ssh/.gitignore @@ -0,0 +1,4 @@ +/moduli +/sshd_config.d/ +/ssh_config.d/ +/ssh_host_*_key* diff --git a/etc/ssh/ssh_config b/etc/ssh/ssh_config new file mode 100644 index 0000000..fd5e900 --- /dev/null +++ b/etc/ssh/ssh_config @@ -0,0 +1,7 @@ +Include /etc/ssh/ssh_config.d/*.conf + +Host * + ControlPath ~/.ssh/%u@%l->%r@%h:%p + SendEnv LANG LC_* + VerifyHostKeyDNS yes + VisualHostKey yes diff --git a/etc/ssh/sshd_config b/etc/ssh/sshd_config new file mode 100644 index 0000000..b18599a --- /dev/null +++ b/etc/ssh/sshd_config @@ -0,0 +1,11 @@ +Include /etc/ssh/sshd_config.d/*.conf + +Port 25422 + +AcceptEnv LANG LC_* +LoginGraceTime 30 +MaxStartups 5 +PermitRootLogin prohibit-password +StreamLocalBindUnlink yes +Subsystem sftp internal-sftp +X11Forwarding no diff --git a/etc/sshguard/sshguard.conf b/etc/sshguard/sshguard.conf new file mode 100644 index 0000000..8dedc93 --- /dev/null +++ b/etc/sshguard/sshguard.conf @@ -0,0 +1,54 @@ +#!/bin/sh +# sshguard.conf -- SSHGuard configuration + +# Full path to backend executable (required, no default) +BACKEND="/usr/libexec/sshg-fw-iptables" + +# Space-separated list of log files to monitor. (optional, no default) +FILES="/var/log/core.slackware.uk.net/auth" + +# Shell command that provides logs on standard output. (optional, no default) +# Example 1: ssh and sendmail from systemd journal: +#LOGREADER="LANG=C /usr/bin/journalctl -afb -p info -n1 -t sshd -t sendmail -o cat" +# Example 2: ssh from os_log (macOS 10.12+) +#LOGREADER="/usr/bin/log stream --style syslog --predicate '(processImagePath contains \"sshd\")'" + +# Block attackers when their cumulative attack score exceeds THRESHOLD. +# Most attacks have a score of 10. (optional, default 30) +THRESHOLD=10 + +# Block attackers for initially BLOCK_TIME seconds after exceeding THRESHOLD. +# Subsequent blocks increase by a factor of 1.5. (optional, default 120) +BLOCK_TIME=86400 + +# Remember potential attackers for up to DETECTION_TIME seconds before +# resetting their score. (optional, default 1800) +DETECTION_TIME=28800 + +# Size of IPv6 subnet to block. Defaults to a single address, CIDR notation. (optional, default to 128) +IPV6_SUBNET=128 + +# Size of IPv4 subnet to block. Defaults to a single address, CIDR notation. (optional, default to 32) +IPV4_SUBNET=32 + +# Full path to PID file (optional, no default) +PID_FILE=/run/sshguard.pid + +# Colon-separated blacklist threshold and full path to blacklist file. +# (optional, no default) +BLACKLIST_FILE=10:/var/lib/sshguard/blacklist + +# IP addresses listed in the WHITELIST_FILE are considered to be +# friendlies and will never be blocked. +WHITELIST_FILE=/etc/sshguard.whitelist + +# If PARSER is unset, SSHGuard will use the installed sshg-parser as its +# parser. Setting PARSER overrides this, so that you can use your own parser. +#PARSER= + +# Run POST_PARSER as a filter after the parser. POST_PARSER must read as input +# and produce as output lines in the format used by sshg-parser. This example +# implements primitive whitelisting, preventing sshg-blocker from seeing +# attacks from 1.2.3.4. Unlike whitelisting, attacks filtered by POST_PARSER +# are not logged by SSHGuard. +#POST_PARSER="grep -v 1.2.3.4" diff --git a/etc/sshguard/whitelist b/etc/sshguard/whitelist new file mode 100644 index 0000000..77a0c3d --- /dev/null +++ b/etc/sshguard/whitelist @@ -0,0 +1,19 @@ +# Localhost. +127.0.0.1/8 +::1 + +# UK Servers +5.101.171.208/28 +2a01:a500:2981:1::/64 + +# Linode +172.236.16.105 +2600:3c13::2000:50ff:fef4:7f56 + +# Loveservers +185.176.90.169 +2a07:4580:b0d:57f::169 + +# Afterdark +afterdark.org.uk +2001:470:1f1c:58::/64 diff --git a/etc/sudoers.d/.gitignore b/etc/sudoers.d/.gitignore new file mode 100644 index 0000000..c3fea74 --- /dev/null +++ b/etc/sudoers.d/.gitignore @@ -0,0 +1 @@ +/README diff --git a/etc/sudoers.d/defaults b/etc/sudoers.d/defaults new file mode 100644 index 0000000..e34d298 --- /dev/null +++ b/etc/sudoers.d/defaults @@ -0,0 +1,2 @@ +## Set the password prompting timeout to 30 mins. +Defaults timestamp_timeout = 30 diff --git a/etc/sudoers.d/root-access b/etc/sudoers.d/root-access new file mode 100644 index 0000000..024d622 --- /dev/null +++ b/etc/sudoers.d/root-access @@ -0,0 +1,5 @@ +## Allow certain users access to root using their own passwords. +tadgy ALL=(root) ALL + +## Allow the 'sysadmin' user access to root without a password. +sysadmin ALL=(root) NOPASSWD: ALL diff --git a/home/.gitignore b/home/.gitignore new file mode 100644 index 0000000..31cdac1 --- /dev/null +++ b/home/.gitignore @@ -0,0 +1,2 @@ +/*/ +!/sysadmin/ diff --git a/home/sysadmin/.bash_logout b/home/sysadmin/.bash_logout new file mode 100644 index 0000000..df5d9a6 --- /dev/null +++ b/home/sysadmin/.bash_logout @@ -0,0 +1,14 @@ +#!/bin/bash - not strictly necessary, but helps nano with syntax highlighting. + +# Clear the screen/console on logout. +if (( SHLVL == 1 )); then + if [[ -x /usr/bin/clear_console ]]; then + /usr/bin/clear_console -q + elif [[ -x /usr/bin/clear ]]; then + /usr/bin/clear + elif [[ -x /usr/bin/tput ]]; then + /usr/bin/tput clear + else + echo -ne "\e[2J" + fi +fi diff --git a/home/sysadmin/.bash_profile b/home/sysadmin/.bash_profile new file mode 100644 index 0000000..0d22242 --- /dev/null +++ b/home/sysadmin/.bash_profile @@ -0,0 +1,21 @@ +#!/bin/bash - not strictly necessary, but helps nano with syntax highlighting. +# Bash shell environmental set up. + +export LANG="en_GB.UTF-8" +export LC_COLLATE="POSIX" # 'C' causes issues with some applications +export PATH="/opt/sbin:/opt/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" +hash less >/dev/null 2>&1 && export PAGER="less" +hash nano >/dev/null 2>&1 && export EDITOR="nano" && export VISUAL="$EDITOR" + +[[ "$TERM" == screen.* ]] && export TERM="${TERM#screen.}" + +[[ -d "$HOME/files/bin" ]] && export PATH="$HOME/files/bin:$PATH" +[[ -d "$HOME/.local/bin" ]] && export PATH="$HOME/.local/bin:$PATH" +[[ -d "$HOME/bin" ]] && export PATH="$HOME/bin:$PATH" + +for FILE in "$HOME"/.bash_profile.d/*; do + [[ -x "$FILE" ]] && source "$FILE" +done +unset FILE + +[[ -f "$HOME/.bashrc" ]] && . "$HOME/.bashrc" diff --git a/home/sysadmin/.bashrc b/home/sysadmin/.bashrc new file mode 100644 index 0000000..7fcb2ed --- /dev/null +++ b/home/sysadmin/.bashrc @@ -0,0 +1,54 @@ +#!/bin/bash - not strictly necessary, but helps nano with syntax highlighting. +# Bash specific configuration. + +__prompt_user_colour() { + # Determine the colour of the username in the prompt. + + if [[ "$(whoami)" == "root" ]]; then + printf "%s" "1;31m" # Bright Red. + elif [[ "$(whoami)" == "tadgy" ]]; then + printf "%s" "1;32m" # Bright Green. + else + printf "%s" "1;36m" # Bright Cyan. + fi + + return 0 +} + +shopt -s cdspell checkhash checkjobs checkwinsize cmdhist dirspell histappend no_empty_cmd_completion + +HISTCONTROL="ignoredups" +HISTFILE="$HOME/.bash_history-${HOSTNAME%%.*}" +HISTFILESIZE=1000000 +HISTIGNORE="bg:bg *:fg:fg *:jobs:exit:clear:history" +HISTSIZE=1000000 +HISTTIMEFORMAT="%d/%m/%y %H:%M:%S " +IGNOREEOF=0 +PROMPT_DIRTRIM=2 +PS1='[\[\033[$(__prompt_user_colour)\]\u\[\033[0m\]@\[\033[1;33m\]\h\[\033[0m\]] \[\033[1;34m\]\w\[\033[0m\] ->' + +history -a +history -r + +hash grep >/dev/null 2>&1 && { alias egrep='grep -E'; alias fgrep='grep -F'; } +hash ps grep >/dev/null 2>&1 && psgrep() { + if [[ -n "$1" ]]; then + # shellcheck disable=SC2009 + ps | command grep -E -- "(.*RSS.*|$1)" | command grep -F -v '(.*RSS.*|' + else + printf "%s: %s\\n" "Usage" "${FUNCNAME[0]} " >&2 + return 1 + fi +} +hash ls >/dev/null 2>&1 && alias ls='ls -Fv --color=always' +hash nc >/dev/null 2>&1 && alias pastebin='nc termbin.com 9999' + +[[ -z "$SSH_TTY" ]] && { + echo -ne "\e[2q" + echo -e "\e]12;#00FF00" +} + +for FILE in "$HOME"/.bashrc.d/*; do + [[ -x "$FILE" ]] && source "$FILE" +done +unset FILE diff --git a/home/sysadmin/.gitconfig b/home/sysadmin/.gitconfig new file mode 100644 index 0000000..7f9f4af --- /dev/null +++ b/home/sysadmin/.gitconfig @@ -0,0 +1,27 @@ +[user] + name = Darren 'Tadgy' Austin + email = darren@afterdark.org.uk +[color] + branch = auto + diff = auto + grep = auto + interactive = auto + showBranch = auto + status = auto + ui = auto +[credential] + username = tadgy + helper = cache --timeout 2592000 +[commit] + verbose = 1 +[push] + autoSetupRemote = true +[alias] + c = commit + co = checkout + d = diff + lsut = ls-files --others --exclude-standard --directory --error-unmatch -- ':/*' + p = push + s = status +[init] + defaultBranch = master diff --git a/home/sysadmin/.gitignore b/home/sysadmin/.gitignore new file mode 100644 index 0000000..589f81f --- /dev/null +++ b/home/sysadmin/.gitignore @@ -0,0 +1,8 @@ +/* +!/.* +!/.*/ +!/.*/** + +/.bash_history* +/.gnupg/ +/.nano_history diff --git a/home/sysadmin/.local/share/nano/.gitignore b/home/sysadmin/.local/share/nano/.gitignore new file mode 100644 index 0000000..4f77bdc --- /dev/null +++ b/home/sysadmin/.local/share/nano/.gitignore @@ -0,0 +1 @@ +/search_history diff --git a/home/sysadmin/.nanorc b/home/sysadmin/.nanorc new file mode 100644 index 0000000..1b0e0a0 --- /dev/null +++ b/home/sysadmin/.nanorc @@ -0,0 +1,125 @@ +## When soft line wrapping is enabled, make it wrap lines at blank characters. +set atblanks + +## Use auto-indentation. +set autoindent + +## When saving a file, create a backup file by adding a tilde (~). +# set backup + +## Automatically hard-wrap the current line when it becomes overlong. +# set breaklonglines + +## Do case-sensitive searches by default. +# set casesensitive + +## Do not use the line below the title bar. +# set emptyline + +## Set the line length for wrapping text and justifying paragraphs. +set fill -2 + +## Draw a vertical stripe at the given column +#set guidestripe 190 + +## Remember the used search/replace strings for the next session. +set historylog + +## Display a "scrollbar" on the righthand side of the edit window. +# set indicator + +## Scroll the buffer contents per half-screen instead of per line. +# set jumpyscrolling + +## Display line numbers to the left of the text area. +set linenumbers + +## Enable vim-style lock-files. +set locking + +## Use libmagic for syntax highlighting suggestions. +# set magic + +## Don't display the helpful shortcut lists at the bottom of the screen. +set nohelp + +## Don't add newlines to the ends of files. +# set nonewlines + +## Save the cursor position of files between editing sessions. +# set positionlog + +## Do quick statusbar blanking. +set quickblank + +## Do extended regular expression searches by default. +# set regexp + +## Make the Home key smarter. +set smarthome + +## Enable soft line wrapping (AKA full-line display). +set softwrap + +## Use this spelling checker instead of the internal one. +# set speller "aspell -x -c" + +## Show flags in the title bar. +set stateflags + +## When justifying text, trailing whitespace will automatically be removed. +set trimblanks + +## The two characters used to indicate the presence of tabs and spaces. +set whitespace »· + +## Detect word boundaries more accurately by treating punctuation +## characters as parts of words. +set wordbounds + +## Let an unmodified Backspace or Delete erase the marked region, without +## affecting the cut-buffer. +# set zap + + +## Paint the interface elements of nano. +set errorcolor brightwhite,red +set functioncolor magenta +set keycolor brightwhite +set numbercolor brightwhite,magenta +set promptcolor brightwhite,magenta +set scrollercolor brightwhite,magenta +set selectedcolor brightwhite,blue +set spotlightcolor black,yellow +set statuscolor brightwhite,magenta +set stripecolor ,magenta +set titlecolor brightwhite,magenta + + +## Include all existing syntax highlight definitions. +# include "/usr/share/nano/*.nanorc" + + +## Key bindings. +## The following five functions are not bound to any key by default. +## You may wish to choose different keys than the ones suggested here. +# bind ^S savefile main +# bind M-Q findprevious main +# bind M-W findnext main +# bind M-B cutwordleft main +# bind M-N cutwordright main +## Set this if your Backspace key sends Del most of the time. +# bind Del backspace all +# Unbind the ^J (justification) shortcut as it's annoying. +unbind ^J main +# Allow ^Z to suspend nano. +bind ^Z suspend main +# Allow marking using ^Space. +bind ^Space mark main +# Select buffers. +bind M-9 nextbuf main +bind M-0 prevbuf main +# Use anchors. +bind Ins anchor main +bind M-, prevanchor main +bind M-. nextanchor main diff --git a/home/sysadmin/.ssh/.gitignore b/home/sysadmin/.ssh/.gitignore new file mode 100644 index 0000000..73e51bd --- /dev/null +++ b/home/sysadmin/.ssh/.gitignore @@ -0,0 +1,2 @@ +/known_hosts +/known_hosts.old diff --git a/home/sysadmin/.ssh/authorized_keys b/home/sysadmin/.ssh/authorized_keys new file mode 100644 index 0000000..afec5cc --- /dev/null +++ b/home/sysadmin/.ssh/authorized_keys @@ -0,0 +1,2 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF6Gx1rYhHHsbFCG2rsIaunvunacO0vUQK9O50gfhz9c Slackware UK Systems' Administrator +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICsx4EY4vbDt0TXGZsW9UjOxj+s/mVeytJ7lW5rAu0gS Darren 'Tadgy' Austin diff --git a/opt/sbin/cronjob-clean-php b/opt/sbin/cronjob-clean-php new file mode 100755 index 0000000..b47cc39 --- /dev/null +++ b/opt/sbin/cronjob-clean-php @@ -0,0 +1,4 @@ +#!/bin/bash + +[[ -d /var/lib/php/sessions ]] && find /var/lib/php/sessions -mmin +1440 -type f -print0 | xargs -0 rm -f +[[ -d /var/tmp/php-uploads ]] && find /var/tmp/php-uploads -mmin +1440 -type f -print0 | xargs -0 rm -f diff --git a/opt/sbin/cronjob-dehydrated b/opt/sbin/cronjob-dehydrated new file mode 100755 index 0000000..4035bcf --- /dev/null +++ b/opt/sbin/cronjob-dehydrated @@ -0,0 +1,6 @@ +#!/bin/bash +# Run this job in the background. +( # Delay the run for 15 hours (from midnight) and then run at a random time within 3 hours after that. + sleep $(( 54000 + (RANDOM % 10800) )) + + /opt/sbin/dehydrated -c >/dev/null ) & diff --git a/opt/sbin/cronjob-rotate-logs-symlinks b/opt/sbin/cronjob-rotate-logs-symlinks new file mode 100755 index 0000000..49997ea --- /dev/null +++ b/opt/sbin/cronjob-rotate-logs-symlinks @@ -0,0 +1,56 @@ +#!/bin/bash + +# Default configuration. +LOGS_DIR="/var/log" +DIR_MODE="0750" +UMASK="027" + +# This array may be used in the defaults file. +declare -A CREATE_DIRS + +# Allow /etc/default/rotate-logs-symlinks to override default configuration. +[[ -e /etc/default/rotate-logs-symlinks ]] && { + # shellcheck disable=SC1091 + source /etc/default/rotate-logs-symlinks || { + printf "%s: %s\\n" "${0##*/}" "failed reading /etc/default/rotate-logs-symlinks" >&2 + exit 1 + } +} + +# Process the directories in the logs directory. +[[ -d "$LOGS_DIR" ]] && { + TODAY="$(printf "%(%Y/%m/%d)T")" + + umask "$UMASK" + + # Process all the directories in the logs directory. + for DIR in "$LOGS_DIR"/*/; do + cd "$DIR" 2>/dev/null || { + printf "%s: %s\\n" "${0##*/}" "failed to change directory to '$DIR'" >&2 + continue + } + + # Create a new logs directory for today. + # shellcheck disable=SC2174 + mkdir -p -m "$DIR_MODE" "$TODAY" 2>/dev/null || { + printf "%s: %s\\n" "${0##*/}" "failed to create directory '$DIR/$TODAY'" >&2 + continue + } + + # If configured to do so for this directory, create sub directories. + for CREATE_DIR in ${CREATE_DIRS[$(printf "$DIR" | awk -F / -e '{print $4}')]}; do + mkdir -p -m "$DIR_MODE" "$TODAY/$CREATE_DIR" 2>/dev/null || { + printf "%s: %s\\n" "${0##*/}" "failed to create directory '$DIR/$TODAY/$CREATE_DIR'" >&2 + continue + } + done + + # Create a 'today' symlink to the new days' directory. + ( cd "$DIR" 2>/dev/null && ln -sfn "$TODAY" "today" 2>/dev/null ) || { + printf "%s: %s\\n" "${0##*/}" "updating 'today' symlink failed" >&2 + continue + } + done +} + +exit 0 diff --git a/opt/sbin/cronjob-update-packages-list b/opt/sbin/cronjob-update-packages-list new file mode 100755 index 0000000..824965d --- /dev/null +++ b/opt/sbin/cronjob-update-packages-list @@ -0,0 +1,34 @@ +#!/bin/bash + +# Check for an /etc/os-release. +[[ ! -e /etc/os-release ]] && { + printf "%s: %s\\n" "${BASH_SOURCE[0]}" "No /etc/os-release to determine system." >&2 + exit 1 +} + +# Source system info. +. /etc/os-release + +# Create package list depending on system type. +case "$ID" in + 'alpine') + apk list -I | cut -d' ' -f1 | rev | cut -d- -f3- | rev >/etc/pkglist + ;; + 'debian'|'ubuntu') + dpkg-query --show --showformat='${Package}\n' >/etc/pkglist + ;; + 'slackware') + slackpkg -batch=on -default_answer=y generate-template "$(hostname --short)" >/dev/null + [[ -L /etc/pkglist ]] && rm -f /etc/pkglist + ls -1 /var/log/packages/ | rev | cut -d- -f4- | rev >/etc/pkglist + ;; + 'void') + xbps-query -l | awk '{ print $2 }' | rev | cut -d- -f2- | rev >/etc/pkglist + ;; + *) + printf "%s: %s\\n" "${BASH_SOURCE[0]}" "Unsupported system." >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/opt/sbin/cronjob-warn-git-status b/opt/sbin/cronjob-warn-git-status new file mode 100755 index 0000000..c09f931 --- /dev/null +++ b/opt/sbin/cronjob-warn-git-status @@ -0,0 +1,44 @@ +#!/bin/bash + +# Default configuration. +CHECK_DIRS=('/') +EMAIL_TO=('sysadmin@slackware.uk') +EMAIL_FROM="\"Server: ${HOSTNAME%%.*}\" " + +# Allow /etc/default/warn-git-status to override default configuration. +[[ -e /etc/default/warn-git-status ]] && { + source /etc/default/warn-git-status || { + printf "%s: %s\\n" "${0##*/}" "failed reading /etc/default/warn-git-status" >&2 + exit 1 + } +} + +OUTPUT_FILE="/tmp/${0##*/}-$$-$RANDOM" + +# Remove the OUTPUT_FILE when done. +trap 'rm -f "$OUTPUT_FILE"' EXIT + +# Loop through the list and process. +for DIR in "${CHECK_DIRS[@]}"; do + [[ ! -e "$DIR" ]] || [[ ! -d "$DIR" ]] && continue + TMP_OUTPUT="$(cd "$DIR" && [[ "$(git rev-parse --show-toplevel)" == "$PWD" ]] && git status | grep -E -ve "^(On branch|Your branch|No commits|nothing|$)" -e "\(use")" + [[ -n "$TMP_OUTPUT" ]] && printf "%s:\\n%s\\n\\n" "$DIR" "$TMP_OUTPUT" >>"$OUTPUT_FILE" + unset TMP_OUTPUT +done + +[[ ! -s "$OUTPUT_FILE" ]] && { + exit 0 +} + +# Send the message. +if [[ -n "${EMAIL_TO[*]}" ]]; then + mail -r "$EMAIL_FROM" -s "Git statuses" "${EMAIL_TO[@]}" <"$OUTPUT_FILE" >/dev/null 2>&1 || { + printf "%s: %s\\n" "${0##*/}" "mail command failed" >&2 + exit 1 + } +else + printf "%s: %s\\n" "${0##*/}" "no recipient configured for mail delivery" >&2 + exit 1 +fi + +exit 0 diff --git a/opt/sbin/dehydrated b/opt/sbin/dehydrated new file mode 100755 index 0000000..28c4711 --- /dev/null +++ b/opt/sbin/dehydrated @@ -0,0 +1,2539 @@ +#!/usr/bin/env bash + +# dehydrated by lukas2511 +# Source: https://dehydrated.io +# +# This script is licensed under The MIT License (see LICENSE for more information). + +set -e +set -u +set -o pipefail +[[ -n "${ZSH_VERSION:-}" ]] && set -o SH_WORD_SPLIT && set +o FUNCTION_ARGZERO && set -o NULL_GLOB && set -o noglob +[[ -z "${ZSH_VERSION:-}" ]] && shopt -s nullglob && set -f + +umask 077 # paranoid umask, we're creating private keys + +# Close weird external file descriptors +exec 3>&- +exec 4>&- + +VERSION="0.7.3" + +# Find directory in which this script is stored by traversing all symbolic links +SOURCE="${0}" +while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink + DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + SOURCE="$(readlink "$SOURCE")" + [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located +done +SCRIPTDIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + +BASEDIR="${SCRIPTDIR}" +ORIGARGS=("${@}") + +noglob_set() { + if [[ -n "${ZSH_VERSION:-}" ]]; then + set +o noglob + else + set +f + fi +} + +noglob_clear() { + if [[ -n "${ZSH_VERSION:-}" ]]; then + set -o noglob + else + set -f + fi +} + +# Generate json.sh path matching string +json_path() { + if [ ! "${1}" = "-p" ]; then + printf '"%s"' "${1}" + else + printf '%s' "${2}" + fi +} + +# Get string value from json dictionary +get_json_string_value() { + local filter + filter="$(printf 's/.*\[%s\][[:space:]]*"\([^"]*\)"/\\1/p' "$(json_path "${1:-}" "${2:-}")")" + sed -n "${filter}" +} + +# Get array values from json dictionary +get_json_array_values() { + grep -E '^\['"$(json_path "${1:-}" "${2:-}")"',[0-9]*\]' | sed -e 's/\[[^\]*\][[:space:]]*//g' -e 's/^"//' -e 's/"$//' +} + +# Get sub-dictionary from json +get_json_dict_value() { + local filter + filter="$(printf 's/.*\[%s\][[:space:]]*\(.*\)/\\1/p' "$(json_path "${1:-}" "${2:-}")")" + sed -n "${filter}" | jsonsh +} + +# Get integer value from json +get_json_int_value() { + local filter + filter="$(printf 's/.*\[%s\][[:space:]]*\([^"]*\)/\\1/p' "$(json_path "${1:-}" "${2:-}")")" + sed -n "${filter}" +} + +# Get boolean value from json +get_json_bool_value() { + local filter + filter="$(printf 's/.*\[%s\][[:space:]]*\([^"]*\)/\\1/p' "$(json_path "${1:-}" "${2:-}")")" + sed -n "${filter}" +} + +# JSON.sh JSON-parser +# Modified from https://github.com/dominictarr/JSON.sh +# Original Copyright (c) 2011 Dominic Tarr +# Licensed under The MIT License +jsonsh() { + + throw() { + echo "$*" >&2 + exit 1 + } + + awk_egrep () { + local pattern_string=$1 + + awk '{ + while ($0) { + start=match($0, pattern); + token=substr($0, start, RLENGTH); + print token; + $0=substr($0, start+RLENGTH); + } + }' pattern="$pattern_string" + } + + tokenize () { + local GREP + local ESCAPE + local CHAR + + if echo "test string" | grep -Eao --color=never "test" >/dev/null 2>&1 + then + GREP='grep -Eao --color=never' + else + GREP='grep -Eao' + fi + + # shellcheck disable=SC2196 + if echo "test string" | grep -Eao "test" >/dev/null 2>&1 + then + ESCAPE='(\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})' + CHAR='[^[:cntrl:]"\\]' + else + GREP=awk_egrep + ESCAPE='(\\\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})' + CHAR='[^[:cntrl:]"\\\\]' + fi + + local STRING="\"$CHAR*($ESCAPE$CHAR*)*\"" + local NUMBER='-?(0|[1-9][0-9]*)([.][0-9]*)?([eE][+-]?[0-9]*)?' + local KEYWORD='null|false|true' + local SPACE='[[:space:]]+' + + # Force zsh to expand $A into multiple words + local is_wordsplit_disabled + is_wordsplit_disabled="$(unsetopt 2>/dev/null | grep -c '^shwordsplit$' || true)" + if [ "${is_wordsplit_disabled}" != "0" ]; then setopt shwordsplit; fi + $GREP "$STRING|$NUMBER|$KEYWORD|$SPACE|." | grep -Ev "^$SPACE$" + if [ "${is_wordsplit_disabled}" != "0" ]; then unsetopt shwordsplit; fi + } + + parse_array () { + local index=0 + local ary='' + read -r token + case "$token" in + ']') ;; + *) + while : + do + parse_value "$1" "$index" + index=$((index+1)) + ary="$ary""$value" + read -r token + case "$token" in + ']') break ;; + ',') ary="$ary," ;; + *) throw "EXPECTED , or ] GOT ${token:-EOF}" ;; + esac + read -r token + done + ;; + esac + value=$(printf '[%s]' "$ary") || value= + : + } + + parse_object () { + local key + local obj='' + read -r token + case "$token" in + '}') ;; + *) + while : + do + case "$token" in + '"'*'"') key=$token ;; + *) throw "EXPECTED string GOT ${token:-EOF}" ;; + esac + read -r token + case "$token" in + ':') ;; + *) throw "EXPECTED : GOT ${token:-EOF}" ;; + esac + read -r token + parse_value "$1" "$key" + obj="$obj$key:$value" + read -r token + case "$token" in + '}') break ;; + ',') obj="$obj," ;; + *) throw "EXPECTED , or } GOT ${token:-EOF}" ;; + esac + read -r token + done + ;; + esac + value=$(printf '{%s}' "$obj") || value= + : + } + + parse_value () { + local jpath="${1:+$1,}${2:-}" + case "$token" in + '{') parse_object "$jpath" ;; + '[') parse_array "$jpath" ;; + # At this point, the only valid single-character tokens are digits. + ''|[!0-9]) throw "EXPECTED value GOT ${token:-EOF}" ;; + *) value="${token//\\\///}" + # replace solidus ("\/") in json strings with normalized value: "/" + ;; + esac + [ "$value" = '' ] && return + [ -z "$jpath" ] && return # do not print head + + printf "[%s]\t%s\n" "$jpath" "$value" + : + } + + parse () { + read -r token + parse_value + read -r token || true + case "$token" in + '') ;; + *) throw "EXPECTED EOF GOT $token" ;; + esac + } + + tokenize | parse +} + +# Convert IP addresses to their reverse dns variants. +# Used for ALPN certs as validation for IPs uses this in SNI since IPs aren't allowed there. +ip_to_ptr() { + ip="$(cat)" + if [[ "${ip}" =~ : ]]; then + printf "%sip6.arpa" "$(printf "%s" "${ip}" | awk -F: 'BEGIN {OFS=""; }{addCount = 9 - NF; for(i=1; i<=NF;i++){if(length($i) == 0){ for(j=1;j<=addCount;j++){$i = ($i "0000");} } else { $i = substr(("0000" $i), length($i)+5-4);}}; print}' | rev | sed -e "s/./&./g")" + else + printf "%s.in-addr.arpa" "$(printf "%s" "${ip}" | awk -F. '{print $4"."$3"." $2"."$1}')" + fi +} + +# Create (identifiable) temporary files +_mktemp() { + mktemp "${TMPDIR:-/tmp}/dehydrated-XXXXXX" +} + +# Check for script dependencies +check_dependencies() { + # look for required binaries + for binary in grep mktemp diff sed awk curl cut head tail hexdump; do + bin_path="$(command -v "${binary}" 2>/dev/null)" || _exiterr "This script requires ${binary}." + [[ -x "${bin_path}" ]] || _exiterr "${binary} found in PATH but it's not executable" + done + + # just execute some dummy and/or version commands to see if required tools are actually usable + "${OPENSSL}" version > /dev/null 2>&1 || _exiterr "This script requires an openssl binary." + _sed "" < /dev/null > /dev/null 2>&1 || _exiterr "This script requires sed with support for extended (modern) regular expressions." + + # curl returns with an error code in some ancient versions so we have to catch that + set +e + CURL_VERSION="$(curl -V 2>&1 | head -n1 | awk '{print $2}')" + set -e +} + +store_configvars() { + __KEY_ALGO="${KEY_ALGO}" + __OCSP_MUST_STAPLE="${OCSP_MUST_STAPLE}" + __OCSP_FETCH="${OCSP_FETCH}" + __OCSP_DAYS="${OCSP_DAYS}" + __PRIVATE_KEY_RENEW="${PRIVATE_KEY_RENEW}" + __PRIVATE_KEY_ROLLOVER="${PRIVATE_KEY_ROLLOVER}" + __KEYSIZE="${KEYSIZE}" + __CHALLENGETYPE="${CHALLENGETYPE}" + __HOOK="${HOOK}" + __PREFERRED_CHAIN="${PREFERRED_CHAIN}" + __WELLKNOWN="${WELLKNOWN}" + __HOOK_CHAIN="${HOOK_CHAIN}" + __OPENSSL_CNF="${OPENSSL_CNF}" + __RENEW_DAYS="${RENEW_DAYS}" + __IP_VERSION="${IP_VERSION}" + __ACME_PROFILE="${ACME_PROFILE}" + __ORDER_TIMEOUT=${ORDER_TIMEOUT} + __VALIDATION_TIMEOUT=${VALIDATION_TIMEOUT} + __KEEP_GOING=${KEEP_GOING} +} + +reset_configvars() { + KEY_ALGO="${__KEY_ALGO}" + OCSP_MUST_STAPLE="${__OCSP_MUST_STAPLE}" + OCSP_FETCH="${__OCSP_FETCH}" + OCSP_DAYS="${__OCSP_DAYS}" + PRIVATE_KEY_RENEW="${__PRIVATE_KEY_RENEW}" + PRIVATE_KEY_ROLLOVER="${__PRIVATE_KEY_ROLLOVER}" + KEYSIZE="${__KEYSIZE}" + CHALLENGETYPE="${__CHALLENGETYPE}" + HOOK="${__HOOK}" + PREFERRED_CHAIN="${__PREFERRED_CHAIN}" + WELLKNOWN="${__WELLKNOWN}" + HOOK_CHAIN="${__HOOK_CHAIN}" + OPENSSL_CNF="${__OPENSSL_CNF}" + RENEW_DAYS="${__RENEW_DAYS}" + IP_VERSION="${__IP_VERSION}" + ACME_PROFILE="${__ACME_PROFILE}" + ORDER_TIMEOUT=${__ORDER_TIMEOUT} + VALIDATION_TIMEOUT=${__VALIDATION_TIMEOUT} + KEEP_GOING="${__KEEP_GOING}" +} + +hookscript_bricker_hook() { + # Hook scripts should ignore any hooks they don't know. + # Calling a random hook to make this clear to the hook script authors... + if [[ -n "${HOOK}" ]]; then + "${HOOK}" "this_hookscript_is_broken__dehydrated_is_working_fine__please_ignore_unknown_hooks_in_your_script" || _exiterr "Please check your hook script, it should exit cleanly without doing anything on unknown/new hooks." + fi +} + +# verify configuration values +verify_config() { + [[ "${CHALLENGETYPE}" == "http-01" || "${CHALLENGETYPE}" == "dns-01" || "${CHALLENGETYPE}" == "tls-alpn-01" ]] || _exiterr "Unknown challenge type ${CHALLENGETYPE}... cannot continue." + if [[ "${COMMAND:-}" =~ sign_domains|sign_csr ]]; then + if [[ "${CHALLENGETYPE}" = "dns-01" ]] && [[ -z "${HOOK}" ]]; then + _exiterr "Challenge type dns-01 needs a hook script for deployment... cannot continue." + fi + if [[ "${CHALLENGETYPE}" = "http-01" ]] && [[ ! -d "${WELLKNOWN}" ]]; then + _exiterr "WELLKNOWN directory doesn't exist, please create ${WELLKNOWN} and set appropriate permissions." + fi + fi + [[ "${KEY_ALGO}" == "rsa" || "${KEY_ALGO}" == "prime256v1" || "${KEY_ALGO}" == "secp384r1" || "${KEY_ALGO}" == "secp521r1" ]] || _exiterr "Unknown public key algorithm ${KEY_ALGO}... cannot continue." + if [[ -n "${IP_VERSION}" ]]; then + [[ "${IP_VERSION}" = "4" || "${IP_VERSION}" = "6" ]] || _exiterr "Unknown IP version ${IP_VERSION}... cannot continue." + fi + [[ "${API}" == "auto" || "${API}" == "1" || "${API}" == "2" ]] || _exiterr "Unsupported API version defined in config: ${API}" + [[ "${OCSP_DAYS}" =~ ^[0-9]+$ ]] || _exiterr "OCSP_DAYS must be a number" + [[ "${ORDER_TIMEOUT}" =~ ^[0-9]+$ ]] || _exiterr "ORDER_TIMEOUT must be a number" + [[ "${VALIDATION_TIMEOUT}" =~ ^[0-9]+$ ]] || _exiterr "VALIDATION_TIMEOUT must be a number" +} + +# Setup default config values, search for and load configuration files +load_config() { + # Check for config in various locations + if [[ -z "${CONFIG:-}" ]]; then + for check_config in "/etc/dehydrated" "/usr/local/etc/dehydrated" "${PWD}" "${SCRIPTDIR}"; do + if [[ -f "${check_config}/config" ]]; then + BASEDIR="${check_config}" + CONFIG="${check_config}/config" + break + fi + done + fi + + # Preset + CA_ZEROSSL="https://acme.zerossl.com/v2/DV90" + CA_LETSENCRYPT="https://acme-v02.api.letsencrypt.org/directory" + CA_LETSENCRYPT_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_GOOGLE="https://dv.acme-v02.api.pki.goog/directory" + CA_GOOGLE_TEST="https://dv.acme-v02.test-api.pki.goog/directory" + + # Default values + CA="letsencrypt" + OLDCA= + CERTDIR= + ALPNCERTDIR= + ACCOUNTDIR= + ACCOUNT_KEYSIZE="4096" + ACCOUNT_KEY_ALGO=rsa + CHALLENGETYPE="http-01" + CONFIG_D= + CURL_OPTS= + DOMAINS_D= + DOMAINS_TXT= + HOOK= + PREFERRED_CHAIN= + HOOK_CHAIN="no" + RENEW_DAYS="32" + KEYSIZE="4096" + WELLKNOWN= + PRIVATE_KEY_RENEW="yes" + PRIVATE_KEY_ROLLOVER="no" + KEY_ALGO=secp384r1 + OPENSSL=openssl + OPENSSL_CNF= + CONTACT_EMAIL= + LOCKFILE= + OCSP_MUST_STAPLE="no" + OCSP_FETCH="no" + OCSP_DAYS=5 + IP_VERSION= + CHAINCACHE= + AUTO_CLEANUP="no" + AUTO_CLEANUP_DELETE="no" + DEHYDRATED_USER= + DEHYDRATED_GROUP= + API="auto" + ACME_PROFILE="" + ORDER_TIMEOUT=0 + VALIDATION_TIMEOUT=0 + KEEP_GOING="no" + + if [[ -z "${CONFIG:-}" ]]; then + echo "#" >&2 + echo "# !! WARNING !! No main config file found, using default config!" >&2 + echo "#" >&2 + elif [[ -f "${CONFIG}" ]]; then + echo "# INFO: Using main config file ${CONFIG}" + BASEDIR="$(dirname "${CONFIG}")" + # shellcheck disable=SC1090 + . "${CONFIG}" + else + _exiterr "Specified config file doesn't exist." + fi + + if [[ -n "${CONFIG_D}" ]]; then + if [[ ! -d "${CONFIG_D}" ]]; then + _exiterr "The path ${CONFIG_D} specified for CONFIG_D does not point to a directory." + fi + + # Allow globbing + noglob_set + + for check_config_d in "${CONFIG_D}"/*.sh; do + if [[ -f "${check_config_d}" ]] && [[ -r "${check_config_d}" ]]; then + echo "# INFO: Using additional config file ${check_config_d}" + # shellcheck disable=SC1090 + . "${check_config_d}" + else + _exiterr "Specified additional config ${check_config_d} is not readable or not a file at all." + fi + done + + # Disable globbing + noglob_clear + fi + + # Check for missing dependencies + check_dependencies + + has_sudo() { + command -v sudo > /dev/null 2>&1 || _exiterr "DEHYDRATED_USER set but sudo not available. Please install sudo." + } + + # Check if we are running & are allowed to run as root + if [[ -n "$DEHYDRATED_USER" ]]; then + command -v getent > /dev/null 2>&1 || _exiterr "DEHYDRATED_USER set but getent not available. Please install getent." + + TARGET_UID="$(getent passwd "${DEHYDRATED_USER}" | cut -d':' -f3)" || _exiterr "DEHYDRATED_USER ${DEHYDRATED_USER} is invalid" + if [[ -z "${DEHYDRATED_GROUP}" ]]; then + if [[ "${EUID}" != "${TARGET_UID}" ]]; then + echo "# INFO: Running $0 as ${DEHYDRATED_USER}" + has_sudo && exec sudo -u "${DEHYDRATED_USER}" "${0}" "${ORIGARGS[@]}" + fi + else + TARGET_GID="$(getent group "${DEHYDRATED_GROUP}" | cut -d':' -f3)" || _exiterr "DEHYDRATED_GROUP ${DEHYDRATED_GROUP} is invalid" + if [[ -z "${EGID:-}" ]]; then + command -v id > /dev/null 2>&1 || _exiterr "DEHYDRATED_GROUP set, don't know current gid and 'id' not available... Please provide 'id' binary." + EGID="$(id -g)" + fi + if [[ "${EUID}" != "${TARGET_UID}" ]] || [[ "${EGID}" != "${TARGET_GID}" ]]; then + echo "# INFO: Running $0 as ${DEHYDRATED_USER}/${DEHYDRATED_GROUP}" + has_sudo && exec sudo -u "${DEHYDRATED_USER}" -g "${DEHYDRATED_GROUP}" "${0}" "${ORIGARGS[@]}" + fi + fi + elif [[ -n "${DEHYDRATED_GROUP}" ]]; then + _exiterr "DEHYDRATED_GROUP can only be used in combination with DEHYDRATED_USER." + fi + + # Remove slash from end of BASEDIR. Mostly for cleaner outputs, doesn't change functionality. + [[ "$BASEDIR" != "/" ]] && BASEDIR="${BASEDIR%%/}" + + # Check BASEDIR and set default variables + [[ -d "${BASEDIR}" ]] || _exiterr "BASEDIR does not exist: ${BASEDIR}" + + # Check for ca cli parameter + if [ -n "${PARAM_CA:-}" ]; then + CA="${PARAM_CA}" + fi + + # Preset CAs + if [ "${CA}" = "letsencrypt" ]; then + CA="${CA_LETSENCRYPT}" + elif [ "${CA}" = "letsencrypt-test" ]; then + CA="${CA_LETSENCRYPT_TEST}" + elif [ "${CA}" = "zerossl" ]; then + CA="${CA_ZEROSSL}" + elif [ "${CA}" = "buypass" ]; then + CA="${CA_BUYPASS}" + elif [ "${CA}" = "buypass-test" ]; then + CA="${CA_BUYPASS_TEST}" + elif [ "${CA}" = "google" ]; then + CA="${CA_GOOGLE}" + elif [ "${CA}" = "google-test" ]; then + CA="${CA_GOOGLE_TEST}" + fi + + if [[ -z "${OLDCA}" ]] && [[ "${CA}" = "https://acme-v02.api.letsencrypt.org/directory" ]]; then + OLDCA="https://acme-v01.api.letsencrypt.org/directory" + fi + + # Create new account directory or symlink to account directory from old CA + # dev note: keep in mind that because of the use of 'echo' instead of 'printf' or + # similar there is a newline encoded in the directory name. not going to fix this + # since it's a non-issue and trying to fix existing installations would be too much + # trouble + CAHASH="$(echo "${CA}" | urlbase64)" + [[ -z "${ACCOUNTDIR}" ]] && ACCOUNTDIR="${BASEDIR}/accounts" + if [[ ! -e "${ACCOUNTDIR}/${CAHASH}" ]]; then + OLDCAHASH="$(echo "${OLDCA}" | urlbase64)" + mkdir -p "${ACCOUNTDIR}" + if [[ -n "${OLDCA}" ]] && [[ -e "${ACCOUNTDIR}/${OLDCAHASH}" ]]; then + echo "! Reusing account from ${OLDCA}" + ln -s "${OLDCAHASH}" "${ACCOUNTDIR}/${CAHASH}" + else + mkdir "${ACCOUNTDIR}/${CAHASH}" + fi + fi + + # shellcheck disable=SC1090 + [[ -f "${ACCOUNTDIR}/${CAHASH}/config" ]] && . "${ACCOUNTDIR}/${CAHASH}/config" + ACCOUNT_KEY="${ACCOUNTDIR}/${CAHASH}/account_key.pem" + ACCOUNT_KEY_JSON="${ACCOUNTDIR}/${CAHASH}/registration_info.json" + ACCOUNT_ID_JSON="${ACCOUNTDIR}/${CAHASH}/account_id.json" + ACCOUNT_DEACTIVATED="${ACCOUNTDIR}/${CAHASH}/deactivated" + + if [[ -f "${ACCOUNT_DEACTIVATED}" ]]; then + _exiterr "Account has been deactivated. Remove account and create a new one using --register." + fi + + if [[ -f "${BASEDIR}/private_key.pem" ]] && [[ ! -f "${ACCOUNT_KEY}" ]]; then + echo "! Moving private_key.pem to ${ACCOUNT_KEY}" + mv "${BASEDIR}/private_key.pem" "${ACCOUNT_KEY}" + fi + if [[ -f "${BASEDIR}/private_key.json" ]] && [[ ! -f "${ACCOUNT_KEY_JSON}" ]]; then + echo "! Moving private_key.json to ${ACCOUNT_KEY_JSON}" + mv "${BASEDIR}/private_key.json" "${ACCOUNT_KEY_JSON}" + fi + + [[ -z "${CERTDIR}" ]] && CERTDIR="${BASEDIR}/certs" + [[ -z "${ALPNCERTDIR}" ]] && ALPNCERTDIR="${BASEDIR}/alpn-certs" + [[ -z "${CHAINCACHE}" ]] && CHAINCACHE="${BASEDIR}/chains" + [[ -z "${DOMAINS_TXT}" ]] && DOMAINS_TXT="${BASEDIR}/domains.txt" + [[ -z "${WELLKNOWN}" ]] && WELLKNOWN="/var/www/dehydrated" + [[ -z "${LOCKFILE}" ]] && LOCKFILE="${BASEDIR}/lock" + [[ -z "${OPENSSL_CNF}" ]] && OPENSSL_CNF="$("${OPENSSL}" version -d | cut -d\" -f2)/openssl.cnf" + [[ -n "${PARAM_LOCKFILE_SUFFIX:-}" ]] && LOCKFILE="${LOCKFILE}-${PARAM_LOCKFILE_SUFFIX}" + [[ -n "${PARAM_NO_LOCK:-}" ]] && LOCKFILE="" + + [[ -n "${PARAM_HOOK:-}" ]] && HOOK="${PARAM_HOOK}" + [[ -n "${PARAM_DOMAINS_TXT:-}" ]] && DOMAINS_TXT="${PARAM_DOMAINS_TXT}" + [[ -n "${PARAM_PREFERRED_CHAIN:-}" ]] && PREFERRED_CHAIN="${PARAM_PREFERRED_CHAIN}" + [[ -n "${PARAM_CERTDIR:-}" ]] && CERTDIR="${PARAM_CERTDIR}" + [[ -n "${PARAM_ALPNCERTDIR:-}" ]] && ALPNCERTDIR="${PARAM_ALPNCERTDIR}" + [[ -n "${PARAM_CHALLENGETYPE:-}" ]] && CHALLENGETYPE="${PARAM_CHALLENGETYPE}" + [[ -n "${PARAM_KEY_ALGO:-}" ]] && KEY_ALGO="${PARAM_KEY_ALGO}" + [[ -n "${PARAM_OCSP_MUST_STAPLE:-}" ]] && OCSP_MUST_STAPLE="${PARAM_OCSP_MUST_STAPLE}" + [[ -n "${PARAM_IP_VERSION:-}" ]] && IP_VERSION="${PARAM_IP_VERSION}" + [[ -n "${PARAM_ACME_PROFILE:-}" ]] && ACME_PROFILE="${PARAM_ACME_PROFILE}" + [[ -n "${PARAM_ORDER_TIMEOUT:-}" ]] && ORDER_TIMEOUT="${PARAM_ORDER_TIMEOUT}" + [[ -n "${PARAM_VALIDATION_TIMEOUT:-}" ]] && VALIDATION_TIMEOUT="${PARAM_VALIDATION_TIMEOUT}" + [[ -n "${PARAM_KEEP_GOING:-}" ]] && KEEP_GOING="${PARAM_KEEP_GOING}" + + if [ "${PARAM_FORCE_VALIDATION:-no}" = "yes" ] && [ "${PARAM_FORCE:-no}" = "no" ]; then + _exiterr "Argument --force-validation can only be used in combination with --force (-x)" + fi + + if [ ! "${1:-}" = "noverify" ]; then + verify_config + fi + store_configvars +} + +# Initialize system +init_system() { + load_config + + # Lockfile handling (prevents concurrent access) + if [[ -n "${LOCKFILE}" ]]; then + LOCKDIR="$(dirname "${LOCKFILE}")" + [[ -w "${LOCKDIR}" ]] || _exiterr "Directory ${LOCKDIR} for LOCKFILE ${LOCKFILE} is not writable, aborting." + ( set -C; date > "${LOCKFILE}" ) 2>/dev/null || _exiterr "Lock file '${LOCKFILE}' present, aborting." + remove_lock() { rm -f "${LOCKFILE}"; } + trap 'remove_lock' EXIT + fi + + # Get CA URLs + CA_DIRECTORY="$(http_request get "${CA}" | jsonsh)" + + # Automatic discovery of API version + if [[ "${API}" = "auto" ]]; then + grep -q newOrder <<< "${CA_DIRECTORY}" && API=2 || API=1 + fi + + # shellcheck disable=SC2015 + if [[ "${API}" = "1" ]]; then + CA_NEW_CERT="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value new-cert)" && + CA_NEW_AUTHZ="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value new-authz)" && + CA_NEW_REG="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value new-reg)" && + CA_TERMS="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value terms-of-service)" && + CA_REQUIRES_EAB="false" && + CA_REVOKE_CERT="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value revoke-cert)" || + _exiterr "Problem retrieving ACME/CA-URLs, check if your configured CA points to the directory entrypoint." + # Since reg URI is missing from directory we will assume it is the same as CA_NEW_REG without the new part + CA_REG=${CA_NEW_REG/new-reg/reg} + + if [[ -n "${ACME_PROFILE}" ]]; then + _exiterr "ACME profiles are not supported in ACME v1." + fi + else + CA_NEW_ORDER="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value newOrder)" && + CA_NEW_NONCE="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value newNonce)" && + CA_NEW_ACCOUNT="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value newAccount)" && + CA_TERMS="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value -p '"meta","termsOfService"')" && + CA_REQUIRES_EAB="$(printf "%s" "${CA_DIRECTORY}" | get_json_bool_value -p '"meta","externalAccountRequired"' || echo false)" && + CA_REVOKE_CERT="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value revokeCert)" || + _exiterr "Problem retrieving ACME/CA-URLs, check if your configured CA points to the directory entrypoint." + + # Checking ACME profile + if [[ -n "${ACME_PROFILE}" ]]; then + # Extract available profiles from CA directory + declare -A available_profiles=() + while IFS=$'\t' read -r path value; do + if [[ "${value}" =~ ^\"([^\"]+)\"$ ]]; then + value=${BASH_REMATCH[1]} + fi + if [[ "${path}" =~ ^\[\"([^\"]+)\"\]$ ]]; then + available_profiles[${BASH_REMATCH[1]}]=$value + fi + done <<< "$(printf "%s" "${CA_DIRECTORY}" | get_json_dict_value -p '"meta","profiles"' 2>/dev/null)" + if [[ ${#available_profiles[@]} -eq 0 ]]; then + _exiterr "ACME profile not supported by this CA" + fi + + # Check if the requested profile is available + found_profile="no" + for profile in "${!available_profiles[@]}"; do + if [[ "${profile}" == "${ACME_PROFILE}" ]]; then + found_profile="yes" + break + fi + done + if [[ "${found_profile}" == "no" ]]; then + _exiterr "ACME profile '${ACME_PROFILE}' not found, available profiles:$(for key in "${!available_profiles[@]}"; do printf "\n %s: %s" "${key}" "${available_profiles[$key]}"; done)" + fi + fi + fi + + # Export some environment variables to be used in hook script + export WELLKNOWN BASEDIR CERTDIR ALPNCERTDIR CONFIG COMMAND + + # Checking for private key ... + register_new_key="no" + generated="false" + if [[ -n "${PARAM_ACCOUNT_KEY:-}" ]]; then + # a private key was specified from the command line so use it for this run + echo "Using private key ${PARAM_ACCOUNT_KEY} instead of account key" + ACCOUNT_KEY="${PARAM_ACCOUNT_KEY}" + ACCOUNT_KEY_JSON="${PARAM_ACCOUNT_KEY}.json" + ACCOUNT_ID_JSON="${PARAM_ACCOUNT_KEY}_id.json" + [ "${COMMAND:-}" = "register" ] && register_new_key="yes" + else + # Check if private account key exists, if it doesn't exist yet generate a new one (rsa key) + if [[ ! -e "${ACCOUNT_KEY}" ]]; then + if [[ ! "${PARAM_ACCEPT_TERMS:-}" = "yes" ]]; then + printf '\n' >&2 + printf 'To use dehydrated with this certificate authority you have to agree to their terms of service which you can find here: %s\n\n' "${CA_TERMS}" >&2 + printf 'To accept these terms of service run "%s --register --accept-terms".\n' "${0}" >&2 + exit 1 + fi + + echo "+ Generating account key..." + generated="true" + local tmp_account_key + tmp_account_key="$(_mktemp)" + if [[ ${API} -eq 1 && ! "${ACCOUNT_KEY_ALGO}" = "rsa" ]]; then + _exiterr "ACME API version 1 does not support EC account keys" + fi + case "${ACCOUNT_KEY_ALGO}" in + rsa) _openssl genrsa -out "${tmp_account_key}" "${ACCOUNT_KEYSIZE}";; + prime256v1|secp384r1|secp521r1) _openssl ecparam -genkey -name "${ACCOUNT_KEY_ALGO}" -out "${tmp_account_key}" -noout;; + esac + cat "${tmp_account_key}" > "${ACCOUNT_KEY}" + rm "${tmp_account_key}" + register_new_key="yes" + fi + fi + + if ("${OPENSSL}" rsa -in "${ACCOUNT_KEY}" -check 2>/dev/null > /dev/null); then + # Get public components from private key and calculate thumbprint + pubExponent64="$(printf '%x' "$("${OPENSSL}" rsa -in "${ACCOUNT_KEY}" -noout -text | awk '/publicExponent/ {print $2}')" | hex2bin | urlbase64)" + pubMod64="$("${OPENSSL}" rsa -in "${ACCOUNT_KEY}" -noout -modulus | cut -d'=' -f2 | hex2bin | urlbase64)" + + account_key_info="$(printf '{"e":"%s","kty":"RSA","n":"%s"}' "${pubExponent64}" "${pubMod64}")" + account_key_sigalgo=RS256 + elif ("${OPENSSL}" ec -in "${ACCOUNT_KEY}" -check 2>/dev/null > /dev/null); then + curve="$("${OPENSSL}" ec -in "${ACCOUNT_KEY}" -noout -text 2>/dev/null | grep 'NIST CURVE' | cut -d':' -f2 | tr -d ' ')" + pubkey="$("${OPENSSL}" ec -in "${ACCOUNT_KEY}" -noout -text 2>/dev/null | tr -d '\n ' | grep -Eo 'pub:.*ASN1' | _sed -e 's/^pub://' -e 's/ASN1$//' | tr -d ':')" + + if [ "${curve}" = "P-256" ]; then + account_key_sigalgo="ES256" + elif [ "${curve}" = "P-384" ]; then + account_key_sigalgo="ES384" + elif [ "${curve}" = "P-521" ]; then + account_key_sigalgo="ES512" + else + _exiterr "Unknown account key curve: ${curve}" + fi + + ec_x_offset=2 + ec_x_len=$((${#pubkey}/2 - 1)) + ec_x="${pubkey:$ec_x_offset:$ec_x_len}" + ec_x64="$(printf "%s" "${ec_x}" | hex2bin | urlbase64)" + + ec_y_offset=$((ec_x_offset+ec_x_len)) + ec_y_len=$((${#pubkey}-ec_y_offset)) + ec_y="${pubkey:$ec_y_offset:$ec_y_len}" + ec_y64="$(printf "%s" "${ec_y}" | hex2bin | urlbase64)" + + account_key_info="$(printf '{"crv":"%s","kty":"EC","x":"%s","y":"%s"}' "${curve}" "${ec_x64}" "${ec_y64}")" + else + _exiterr "Account key is not valid, cannot continue." + fi + thumbprint="$(printf '%s' "${account_key_info}" | "${OPENSSL}" dgst -sha256 -binary | urlbase64)" + + # If we generated a new private key in the step above we have to register it with the acme-server + if [[ "${register_new_key}" = "yes" ]]; then + echo "+ Registering account key with ACME server..." + FAILED=false + + if [[ ${API} -eq 1 && -z "${CA_NEW_REG}" ]] || [[ ${API} -eq 2 && -z "${CA_NEW_ACCOUNT}" ]]; then + echo "Certificate authority doesn't allow registrations." + FAILED=true + fi + + # ZeroSSL special sauce + if [[ "${CA}" = "${CA_ZEROSSL}" ]]; then + if [[ -z "${EAB_KID:-}" ]] || [[ -z "${EAB_HMAC_KEY:-}" ]]; then + if [[ -z "${CONTACT_EMAIL}" ]]; then + echo "ZeroSSL requires contact email to be set or EAB_KID/EAB_HMAC_KEY to be manually configured" + FAILED=true + else + zeroapi="$(curl -s "https://api.zerossl.com/acme/eab-credentials-email" -d "email=${CONTACT_EMAIL}" | jsonsh)" + EAB_KID="$(printf "%s" "${zeroapi}" | get_json_string_value eab_kid)" + EAB_HMAC_KEY="$(printf "%s" "${zeroapi}" | get_json_string_value eab_hmac_key)" + if [[ -z "${EAB_KID:-}" ]] || [[ -z "${EAB_HMAC_KEY:-}" ]]; then + echo "Unknown error retrieving ZeroSSL API credentials" + echo "${zeroapi}" + FAILED=true + fi + fi + fi + fi + + # Google special sauce + if [[ "${CA}" = "${CA_GOOGLE}" ]]; then + if [[ -z "${CONTACT_EMAIL}" ]] || [[ -z "${EAB_KID:-}" ]] || [[ -z "${EAB_HMAC_KEY:-}" ]]; then + echo "Google requires contact email, EAB_KID and EAB_HMAC_KEY to be manually configured (see https://cloud.google.com/certificate-manager/docs/public-ca-tutorial)" + FAILED=true + fi + fi + + # Check if external account is required + if [[ "${FAILED}" = "false" ]]; then + if [[ "${CA_REQUIRES_EAB}" = "true" ]]; then + if [[ -z "${EAB_KID:-}" ]] || [[ -z "${EAB_HMAC_KEY:-}" ]]; then + FAILED=true + echo "This CA requires an external account but no EAB_KID/EAB_HMAC_KEY has been configured" + fi + fi + fi + + # If an email for the contact has been provided then adding it to the registration request + if [[ "${FAILED}" = "false" ]]; then + if [[ ${API} -eq 1 ]]; then + if [[ -n "${CONTACT_EMAIL}" ]]; then + (signed_request "${CA_NEW_REG}" '{"resource": "new-reg", "contact":["mailto:'"${CONTACT_EMAIL}"'"], "agreement": "'"${CA_TERMS}"'"}' > "${ACCOUNT_KEY_JSON}") || FAILED=true + else + (signed_request "${CA_NEW_REG}" '{"resource": "new-reg", "agreement": "'"${CA_TERMS}"'"}' > "${ACCOUNT_KEY_JSON}") || FAILED=true + fi + else + if [[ -n "${EAB_KID:-}" ]] && [[ -n "${EAB_HMAC_KEY:-}" ]]; then + eab_url="${CA_NEW_ACCOUNT}" + eab_protected64="$(printf '{"alg":"HS256","kid":"%s","url":"%s"}' "${EAB_KID}" "${eab_url}" | urlbase64)" + eab_payload64="$(printf "%s" "${account_key_info}" | urlbase64)" + eab_key="$(printf "%s" "${EAB_HMAC_KEY}" | deurlbase64 | bin2hex)" + eab_signed64="$(printf '%s' "${eab_protected64}.${eab_payload64}" | "${OPENSSL}" dgst -binary -sha256 -mac HMAC -macopt "hexkey:${eab_key}" | urlbase64)" + + if [[ -n "${CONTACT_EMAIL}" ]]; then + regjson='{"contact":["mailto:'"${CONTACT_EMAIL}"'"], "termsOfServiceAgreed": true, "externalAccountBinding": {"protected": "'"${eab_protected64}"'", "payload": "'"${eab_payload64}"'", "signature": "'"${eab_signed64}"'"}}' + else + regjson='{"termsOfServiceAgreed": true, "externalAccountBinding": {"protected": "'"${eab_protected64}"'", "payload": "'"${eab_payload64}"'", "signature": "'"${eab_signed64}"'"}}' + fi + else + if [[ -n "${CONTACT_EMAIL}" ]]; then + regjson='{"contact":["mailto:'"${CONTACT_EMAIL}"'"], "termsOfServiceAgreed": true}' + else + regjson='{"termsOfServiceAgreed": true}' + fi + fi + (signed_request "${CA_NEW_ACCOUNT}" "${regjson}" > "${ACCOUNT_KEY_JSON}") || FAILED=true + fi + fi + + if [[ "${FAILED}" = "true" ]]; then + echo >&2 + echo >&2 + echo "Error registering account key. See message above for more information." >&2 + if [[ "${generated}" = "true" ]]; then + rm "${ACCOUNT_KEY}" + fi + rm -f "${ACCOUNT_KEY_JSON}" + exit 1 + fi + elif [[ "${COMMAND:-}" = "register" ]]; then + echo "+ Account already registered!" + exit 0 + fi + + # Read account information or request from CA if missing + if [[ -e "${ACCOUNT_KEY_JSON}" ]]; then + if [[ ${API} -eq 1 ]]; then + ACCOUNT_ID="$(jsonsh < "${ACCOUNT_KEY_JSON}" | get_json_int_value id)" + ACCOUNT_URL="${CA_REG}/${ACCOUNT_ID}" + else + if [[ -e "${ACCOUNT_ID_JSON}" ]]; then + ACCOUNT_URL="$(jsonsh < "${ACCOUNT_ID_JSON}" | get_json_string_value url)" + fi + # if account URL is not storred, fetch it from the CA + if [[ -z "${ACCOUNT_URL:-}" ]]; then + echo "+ Fetching account URL..." + ACCOUNT_URL="$(signed_request "${CA_NEW_ACCOUNT}" '{"onlyReturnExisting": true}' 4>&1 | grep -i ^Location: | cut -d':' -f2- | tr -d ' \t\r\n')" + if [[ -z "${ACCOUNT_URL}" ]]; then + _exiterr "Unknown error on fetching account information" + fi + echo '{"url":"'"${ACCOUNT_URL}"'"}' > "${ACCOUNT_ID_JSON}" # store the URL for next time + fi + fi + else + echo "Fetching missing account information from CA..." + if [[ ${API} -eq 1 ]]; then + _exiterr "This is not implemented for ACMEv1! Consider switching to ACMEv2 :)" + else + ACCOUNT_URL="$(signed_request "${CA_NEW_ACCOUNT}" '{"onlyReturnExisting": true}' 4>&1 | grep -i ^Location: | cut -d':' -f2- | tr -d ' \t\r\n')" + ACCOUNT_INFO="$(signed_request "${ACCOUNT_URL}" '{}')" + fi + echo "${ACCOUNT_INFO}" > "${ACCOUNT_KEY_JSON}" + fi +} + +# Different sed version for different os types... +_sed() { + if [[ "${OSTYPE}" = "Linux" || "${OSTYPE:0:5}" = "MINGW" ]]; then + sed -r "${@}" + else + sed -E "${@}" + fi +} + +# Print error message and exit with error +_exiterr() { + if [ -n "${1:-}" ]; then + echo "ERROR: ${1}" >&2 + fi + [[ "${skip_exit_hook:-no}" = "no" ]] && [[ -n "${HOOK:-}" ]] && ("${HOOK}" "exit_hook" "${1:-}" || echo 'exit_hook returned with non-zero exit code!' >&2) + exit 1 +} + +# Remove newlines and whitespace from json +clean_json() { + tr -d '\r\n' | _sed -e 's/ +/ /g' -e 's/\{ /{/g' -e 's/ \}/}/g' -e 's/\[ /[/g' -e 's/ \]/]/g' +} + +# Encode data as url-safe formatted base64 +urlbase64() { + # urlbase64: base64 encoded string with '+' replaced with '-' and '/' replaced with '_' + "${OPENSSL}" base64 -e | tr -d '\n\r' | _sed -e 's:=*$::g' -e 'y:+/:-_:' +} + +# Decode data from url-safe formatted base64 +deurlbase64() { + data="$(cat | tr -d ' \n\r')" + modlen=$((${#data} % 4)) + padding="" + if [[ "${modlen}" = "2" ]]; then padding="=="; + elif [[ "${modlen}" = "3" ]]; then padding="="; fi + printf "%s%s" "${data}" "${padding}" | tr -d '\n\r' | _sed -e 'y:-_:+/:' | "${OPENSSL}" base64 -d -A +} + +# Convert hex string to binary data +hex2bin() { + # Remove spaces, add leading zero, escape as hex string and parse with printf + # shellcheck disable=SC2059 + printf "%b" "$(cat | _sed -e 's/[[:space:]]//g' -e 's/^(.(.{2})*)$/0\1/' -e 's/(.{2})/\\x\1/g')" +} + +# Convert binary data to hex string +bin2hex() { + hexdump -v -e '/1 "%02x"' +} + +# OpenSSL writes to stderr/stdout even when there are no errors. So just +# display the output if the exit code was != 0 to simplify debugging. +_openssl() { + set +e + out="$("${OPENSSL}" "${@}" 2>&1)" + res=$? + set -e + if [[ ${res} -ne 0 ]]; then + echo " + ERROR: failed to run $* (Exitcode: ${res})" >&2 + echo >&2 + echo "Details:" >&2 + echo "${out}" >&2 + echo >&2 + exit "${res}" + fi +} + +# Send http(s) request with specified method +http_request() { + tempcont="$(_mktemp)" + tempheaders="$(_mktemp)" + + if [[ -n "${IP_VERSION:-}" ]]; then + ip_version="-${IP_VERSION}" + fi + + set +e + # shellcheck disable=SC2086 + if [[ "${1}" = "head" ]]; then + statuscode="$(curl ${ip_version:-} ${CURL_OPTS} -A "dehydrated/${VERSION} curl/${CURL_VERSION}" -s -w "%{http_code}" -o "${tempcont}" -H 'Cache-Control: no-cache' "${2}" -I)" + curlret="${?}" + touch "${tempheaders}" + elif [[ "${1}" = "get" ]]; then + statuscode="$(curl ${ip_version:-} ${CURL_OPTS} -A "dehydrated/${VERSION} curl/${CURL_VERSION}" -L -s -w "%{http_code}" -o "${tempcont}" -D "${tempheaders}" -H 'Cache-Control: no-cache' "${2}")" + curlret="${?}" + elif [[ "${1}" = "post" ]]; then + statuscode="$(curl ${ip_version:-} ${CURL_OPTS} -A "dehydrated/${VERSION} curl/${CURL_VERSION}" -s -w "%{http_code}" -o "${tempcont}" "${2}" -D "${tempheaders}" -H 'Cache-Control: no-cache' -H 'Content-Type: application/jose+json' -d "${3}")" + curlret="${?}" + else + set -e + _exiterr "Unknown request method: ${1}" + fi + set -e + + if [[ ! "${curlret}" = "0" ]]; then + _exiterr "Problem connecting to server (${1} for ${2}; curl returned with ${curlret})" + fi + + if [[ ! "${statuscode:0:1}" = "2" ]]; then + # check for existing registration warning + if [[ "${API}" = "1" ]] && [[ -n "${CA_NEW_REG:-}" ]] && [[ "${2}" = "${CA_NEW_REG:-}" ]] && [[ "${statuscode}" = "409" ]] && grep -q "Registration key is already in use" "${tempcont}"; then + # do nothing + : + # check for already-revoked warning + elif [[ -n "${CA_REVOKE_CERT:-}" ]] && [[ "${2}" = "${CA_REVOKE_CERT:-}" ]] && [[ "${statuscode}" = "409" ]]; then + grep -q "Certificate already revoked" "${tempcont}" && return + else + if grep -q "urn:ietf:params:acme:error:badNonce" "${tempcont}"; then + printf "badnonce %s" "$(grep -Eoi "^replay-nonce:.*$" "${tempheaders}" | sed 's/ //' | cut -d: -f2)" + return 0 + fi + echo " + ERROR: An error occurred while sending ${1}-request to ${2} (Status ${statuscode})" >&2 + echo >&2 + echo "Details:" >&2 + cat "${tempheaders}" >&2 + cat "${tempcont}" >&2 + echo >&2 + echo >&2 + + # An exclusive hook for the {1}-request error might be useful (e.g., for sending an e-mail to admins) + if [[ -n "${HOOK}" ]]; then + errtxt="$(cat "${tempcont}")" + errheaders="$(cat "${tempheaders}")" + "${HOOK}" "request_failure" "${statuscode}" "${errtxt}" "${1}" "${errheaders}" || _exiterr 'request_failure hook returned with non-zero exit code' + fi + + rm -f "${tempcont}" + rm -f "${tempheaders}" + + # remove temporary domains.txt file if used + [[ "${COMMAND:-}" = "sign_domains" && -n "${PARAM_DOMAIN:-}" && -n "${DOMAINS_TXT:-}" ]] && rm "${DOMAINS_TXT}" + _exiterr + fi + fi + + if { true >&4; } 2>/dev/null; then + cat "${tempheaders}" >&4 + fi + cat "${tempcont}" + rm -f "${tempcont}" + rm -f "${tempheaders}" +} + +# Send signed request +signed_request() { + # Encode payload as urlbase64 + payload64="$(printf '%s' "${2}" | urlbase64)" + + if [ -n "${3:-}" ]; then + nonce="$(printf "%s" "${3}" | tr -d ' \t\n\r')" + else + # Retrieve nonce from acme-server + if [[ ${API} -eq 1 ]]; then + nonce="$(http_request head "${CA}" | grep -i ^Replay-Nonce: | cut -d':' -f2- | tr -d ' \t\n\r')" + else + nonce="$(http_request head "${CA_NEW_NONCE}" | grep -i ^Replay-Nonce: | cut -d':' -f2- | tr -d ' \t\n\r')" + fi + fi + + if [[ ${API} -eq 1 ]]; then + # Build another header which also contains the previously received nonce and encode it as urlbase64 + protected='{"alg": "RS256", "jwk": {"e": "'"${pubExponent64}"'", "kty": "RSA", "n": "'"${pubMod64}"'"}, "nonce": "'"${nonce}"'"}' + protected64="$(printf '%s' "${protected}" | urlbase64)" + else + # Build another header which also contains the previously received nonce and url and encode it as urlbase64 + if [[ -n "${ACCOUNT_URL:-}" ]]; then + protected='{"alg": "'"${account_key_sigalgo}"'", "kid": "'"${ACCOUNT_URL}"'", "url": "'"${1}"'", "nonce": "'"${nonce}"'"}' + else + protected='{"alg": "'"${account_key_sigalgo}"'", "jwk": '"${account_key_info}"', "url": "'"${1}"'", "nonce": "'"${nonce}"'"}' + fi + protected64="$(printf '%s' "${protected}" | urlbase64)" + fi + + # Sign header with nonce and our payload with our private key and encode signature as urlbase64 + if [[ "${account_key_sigalgo}" = "RS256" ]]; then + signed64="$(printf '%s' "${protected64}.${payload64}" | "${OPENSSL}" dgst -sha256 -sign "${ACCOUNT_KEY}" | urlbase64)" + else + dgstparams="$(printf '%s' "${protected64}.${payload64}" | "${OPENSSL}" dgst -sha${account_key_sigalgo:2} -sign "${ACCOUNT_KEY}" | "${OPENSSL}" asn1parse -inform DER)" + dgst_parm_1="$(echo "$dgstparams" | head -n 2 | tail -n 1 | cut -d':' -f4)" + dgst_parm_2="$(echo "$dgstparams" | head -n 3 | tail -n 1 | cut -d':' -f4)" + + # zero-padding (doesn't seem to be necessary, but other clients are doing this as well... + case "${account_key_sigalgo}" in + "ES256") siglen=64;; + "ES384") siglen=96;; + "ES512") siglen=132;; + esac + while [[ ${#dgst_parm_1} -lt $siglen ]]; do dgst_parm_1="0${dgst_parm_1}"; done + while [[ ${#dgst_parm_2} -lt $siglen ]]; do dgst_parm_2="0${dgst_parm_2}"; done + + signed64="$(printf "%s%s" "${dgst_parm_1}" "${dgst_parm_2}" | hex2bin | urlbase64)" + fi + + if [[ ${API} -eq 1 ]]; then + # Build header with just our public key and algorithm information + header='{"alg": "RS256", "jwk": {"e": "'"${pubExponent64}"'", "kty": "RSA", "n": "'"${pubMod64}"'"}}' + + # Send header + extended header + payload + signature to the acme-server + data='{"header": '"${header}"', "protected": "'"${protected64}"'", "payload": "'"${payload64}"'", "signature": "'"${signed64}"'"}' + else + # Send extended header + payload + signature to the acme-server + data='{"protected": "'"${protected64}"'", "payload": "'"${payload64}"'", "signature": "'"${signed64}"'"}' + fi + + output="$(http_request post "${1}" "${data}")" + + if grep -qE "^badnonce " <<< "${output}"; then + echo " ! Request failed (badNonce), retrying request..." >&2 + signed_request "${1:-}" "${2:-}" "$(printf "%s" "${output}" | cut -d' ' -f2)" + else + printf "%s" "${output}" + fi +} + +# Extracts all subject names from a CSR +# Outputs either the CN, or the SANs, one per line +extract_altnames() { + csrfile="${1}" # path to CSR file + + if ! "${OPENSSL}" req -in "${csrfile}" -verify -noout >/dev/null; then + _exiterr "Certificate signing request isn't valid" + fi + + reqtext="$("${OPENSSL}" req -in "${csrfile}" -noout -text)" + if <<<"${reqtext}" grep -q '^[[:space:]]*X509v3 Subject Alternative Name:[[:space:]]*$'; then + # SANs used, extract these + altnames="$( <<<"${reqtext}" awk '/X509v3 Subject Alternative Name:/{print;getline;print;}' | tail -n1 )" + # split to one per line: + # shellcheck disable=SC1003 + altnames="$( <<<"${altnames}" _sed -e 's/^[[:space:]]*//; s/, /\'$'\n''/g' )" + # we can only get DNS/IP: ones signed + if grep -qEv '^(DNS|IP( Address)*|othername):' <<<"${altnames}"; then + _exiterr "Certificate signing request contains non-DNS/IP Subject Alternative Names" + fi + # strip away the DNS/IP: prefix + altnames="$( <<<"${altnames}" _sed -e 's/^(DNS:|IP( Address)*:|othername:)//' )" + printf "%s" "${altnames}" | tr '\n' ' ' + else + # No SANs, extract CN + altnames="$( <<<"${reqtext}" grep '^[[:space:]]*Subject:' | _sed -e 's/.*[ /]CN ?= ?([^ /,]*).*/\1/' )" + printf "%s" "${altnames}" + fi +} + +# Get last issuer CN in certificate chain +get_last_cn() { + <<<"${1}" _sed 'H;/-----BEGIN CERTIFICATE-----/h;$!d;x' | "${OPENSSL}" x509 -noout -issuer | head -n1 | _sed -e 's/.*[ /]CN ?= ?([^/,]*).*/\1/' +} + +# Create certificate for domain(s) and outputs it FD 3 +sign_csr() { + csrfile="${1}" # path to CSR file + + if { true >&3; } 2>/dev/null; then + : # fd 3 looks OK + else + _exiterr "sign_csr: FD 3 not open" + fi + + shift 1 || true + export altnames="${*}" + + if [[ ${API} -eq 1 ]]; then + if [[ -z "${CA_NEW_AUTHZ}" ]] || [[ -z "${CA_NEW_CERT}" ]]; then + _exiterr "Certificate authority doesn't allow certificate signing" + fi + elif [[ ${API} -eq 2 ]] && [[ -z "${CA_NEW_ORDER}" ]]; then + _exiterr "Certificate authority doesn't allow certificate signing" + fi + + if [[ -n "${ZSH_VERSION:-}" ]]; then + local -A challenge_names challenge_uris challenge_tokens authorizations keyauths deploy_args + else + local -a challenge_names challenge_uris challenge_tokens authorizations keyauths deploy_args + fi + + # Initial step: Find which authorizations we're dealing with + if [[ ${API} -eq 2 ]]; then + # Request new order and store authorization URIs + local challenge_identifiers="" + for altname in ${altnames}; do + if [[ "${altname}" =~ ^ip: ]]; then + challenge_identifiers+="$(printf '{"type": "ip", "value": "%s"}, ' "${altname:3}")" + else + challenge_identifiers+="$(printf '{"type": "dns", "value": "%s"}, ' "${altname}")" + fi + done + challenge_identifiers="[${challenge_identifiers%, }]" + + echo " + Requesting new certificate order from CA..." + local order_payload='{"identifiers": '"${challenge_identifiers}" + if [[ -n "${ACME_PROFILE}" ]]; then + order_payload="${order_payload}"',"profile":"'"${ACME_PROFILE}"'"' + fi + order_payload="${order_payload}"'}' + order_location="$(signed_request "${CA_NEW_ORDER}" "${order_payload}" 4>&1 | grep -i ^Location: | cut -d':' -f2- | tr -d ' \t\r\n')" + result="$(signed_request "${order_location}" "" | jsonsh)" + + order_authorizations="$(echo "${result}" | get_json_array_values authorizations)" + finalize="$(echo "${result}" | get_json_string_value finalize)" + + local idx=0 + for uri in ${order_authorizations}; do + authorizations[${idx}]="${uri}" + idx=$((idx+1)) + done + echo " + Received ${idx} authorizations URLs from the CA" + else + # Copy $altnames to $authorizations (just doing this to reduce duplicate code later on) + local idx=0 + for altname in ${altnames}; do + authorizations[${idx}]="${altname}" + idx=$((idx+1)) + done + fi + + # Check if authorizations are valid and gather challenge information for pending authorizations + local idx=0 + for authorization in ${authorizations[*]}; do + if [[ "${API}" -eq 2 ]]; then + # Receive authorization ($authorization is authz uri) + response="$(signed_request "$(echo "${authorization}" | _sed -e 's/\"(.*)".*/\1/')" "" | jsonsh)" + identifier="$(echo "${response}" | get_json_string_value -p '"identifier","value"')" + identifier_type="$(echo "${response}" | get_json_string_value -p '"identifier","type"')" + echo " + Handling authorization for ${identifier}" + else + # Request new authorization ($authorization is altname) + identifier="${authorization}" + echo " + Requesting authorization for ${identifier}..." + response="$(signed_request "${CA_NEW_AUTHZ}" '{"resource": "new-authz", "identifier": {"type": "dns", "value": "'"${identifier}"'"}}' | jsonsh)" + fi + + # Check if authorization has already been validated + if [ "$(echo "${response}" | get_json_string_value status)" = "valid" ]; then + if [ "${PARAM_FORCE_VALIDATION:-no}" = "yes" ]; then + echo " + A valid authorization has been found but will be ignored" + else + echo " + Found valid authorization for ${identifier}" + continue + fi + fi + + # Find challenge in authorization + challengeindex="$(echo "${response}" | grep -E '^\["challenges",[0-9]+,"type"\][[:space:]]+"'"${CHALLENGETYPE}"'"' | cut -d',' -f2 || true)" + + if [ -z "${challengeindex}" ]; then + allowed_validations="$(echo "${response}" | grep -E '^\["challenges",[0-9]+,"type"\]' | sed -e 's/\[[^\]*\][[:space:]]*//g' -e 's/^"//' -e 's/"$//' | tr '\n' ' ')" + _exiterr "Validating this certificate is not possible using ${CHALLENGETYPE}. Possible validation methods are: ${allowed_validations}" + fi + challenge="$(echo "${response}" | get_json_dict_value -p '"challenges",'"${challengeindex}")" + + # Gather challenge information + if [ "${identifier_type:-}" = "ip" ] && [ "${CHALLENGETYPE}" = "tls-alpn-01" ] ; then + challenge_names[${idx}]="$(echo "${identifier}" | ip_to_ptr)" + else + challenge_names[${idx}]="${identifier}" + fi + challenge_tokens[${idx}]="$(echo "${challenge}" | get_json_string_value token)" + + if [[ ${API} -eq 2 ]]; then + challenge_uris[${idx}]="$(echo "${challenge}" | get_json_string_value url)" + else + if [[ "$(echo "${challenge}" | get_json_string_value type)" = "urn:acme:error:unauthorized" ]]; then + _exiterr "Challenge unauthorized: $(echo "${challenge}" | get_json_string_value detail)" + fi + challenge_uris[${idx}]="$(echo "${challenge}" | get_json_dict_value validationRecord | get_json_string_value uri)" + fi + + # Prepare challenge tokens and deployment parameters + keyauth="${challenge_tokens[${idx}]}.${thumbprint}" + + case "${CHALLENGETYPE}" in + "http-01") + # Store challenge response in well-known location and make world-readable (so that a webserver can access it) + printf '%s' "${keyauth}" > "${WELLKNOWN}/${challenge_tokens[${idx}]}" + chmod a+r "${WELLKNOWN}/${challenge_tokens[${idx}]}" + keyauth_hook="${keyauth}" + ;; + "dns-01") + # Generate DNS entry content for dns-01 validation + keyauth_hook="$(printf '%s' "${keyauth}" | "${OPENSSL}" dgst -sha256 -binary | urlbase64)" + ;; + "tls-alpn-01") + keyauth_hook="$(printf '%s' "${keyauth}" | "${OPENSSL}" dgst -sha256 -c -hex | awk '{print $NF}')" + generate_alpn_certificate "${identifier}" "${identifier_type}" "${keyauth_hook}" + ;; + esac + + keyauths[${idx}]="${keyauth}" + if [ "${identifier_type:-}" = "ip" ] && [ "${CHALLENGETYPE}" = "tls-alpn-01" ]; then + deploy_args[${idx}]="$(echo "${identifier}" | ip_to_ptr) ${challenge_tokens[${idx}]} ${keyauth_hook}" + else + deploy_args[${idx}]="${identifier} ${challenge_tokens[${idx}]} ${keyauth_hook}" + fi + + idx=$((idx+1)) + done + local num_pending_challenges=${idx} + echo " + ${num_pending_challenges} pending challenge(s)" + + # Deploy challenge tokens + if [[ ${num_pending_challenges} -ne 0 ]]; then + echo " + Deploying challenge tokens..." + if [[ -n "${HOOK}" ]] && [[ "${HOOK_CHAIN}" = "yes" ]]; then + # shellcheck disable=SC2068 + "${HOOK}" "deploy_challenge" ${deploy_args[@]} || _exiterr 'deploy_challenge hook returned with non-zero exit code' + elif [[ -n "${HOOK}" ]]; then + # Run hook script to deploy the challenge token + local idx=0 + while [ ${idx} -lt ${num_pending_challenges} ]; do + # shellcheck disable=SC2086 + "${HOOK}" "deploy_challenge" ${deploy_args[${idx}]} || _exiterr 'deploy_challenge hook returned with non-zero exit code' + idx=$((idx+1)) + done + fi + fi + + # Validate pending challenges + local idx=0 + while [ ${idx} -lt ${num_pending_challenges} ]; do + echo " + Responding to challenge for ${challenge_names[${idx}]} authorization..." + + # Ask the acme-server to verify our challenge and wait until it is no longer pending + if [[ ${API} -eq 1 ]]; then + result="$(signed_request "${challenge_uris[${idx}]}" '{"resource": "challenge", "keyAuthorization": "'"${keyauths[${idx}]}"'"}' | jsonsh)" + else + result="$(signed_request "${challenge_uris[${idx}]}" '{}' | jsonsh)" + fi + + reqstatus="$(echo "${result}" | get_json_string_value status)" + + local waited=0 + while [[ "${reqstatus}" = "pending" ]] || [[ "${reqstatus}" = "processing" ]]; do + if [ ${VALIDATION_TIMEOUT} -gt 0 ] && [ ${waited} -gt ${VALIDATION_TIMEOUT} ]; then + _exiterr "Timed out waiting for processing of domain validation (still ${reqstatus})" + fi + echo " + Validation is ${reqstatus}..." + sleep 1 + waited=$((waited+1)) + if [[ "${API}" -eq 2 ]]; then + result="$(signed_request "${challenge_uris[${idx}]}" "" | jsonsh)" + else + result="$(http_request get "${challenge_uris[${idx}]}" | jsonsh)" + fi + reqstatus="$(echo "${result}" | get_json_string_value status)" + done + + [[ "${CHALLENGETYPE}" = "http-01" ]] && rm -f "${WELLKNOWN}/${challenge_tokens[${idx}]}" + [[ "${CHALLENGETYPE}" = "tls-alpn-01" ]] && rm -f "${ALPNCERTDIR}/${challenge_names[${idx}]}.crt.pem" "${ALPNCERTDIR}/${challenge_names[${idx}]}.key.pem" + + if [[ "${reqstatus}" = "valid" ]]; then + echo " + Challenge is valid!" + else + [[ -n "${HOOK}" ]] && ("${HOOK}" "invalid_challenge" "${altname}" "${result}" || _exiterr 'invalid_challenge hook returned with non-zero exit code') + break + fi + idx=$((idx+1)) + done + + if [[ ${num_pending_challenges} -ne 0 ]]; then + echo " + Cleaning challenge tokens..." + + # Clean challenge tokens using chained hook + # shellcheck disable=SC2068 + [[ -n "${HOOK}" ]] && [[ "${HOOK_CHAIN}" = "yes" ]] && ("${HOOK}" "clean_challenge" ${deploy_args[@]} || _exiterr 'clean_challenge hook returned with non-zero exit code') + + # Clean remaining challenge tokens if validation has failed + local idx=0 + while [ ${idx} -lt ${num_pending_challenges} ]; do + # Delete challenge file + [[ "${CHALLENGETYPE}" = "http-01" ]] && rm -f "${WELLKNOWN}/${challenge_tokens[${idx}]}" + # Delete alpn verification certificates + [[ "${CHALLENGETYPE}" = "tls-alpn-01" ]] && rm -f "${ALPNCERTDIR}/${challenge_names[${idx}]}.crt.pem" "${ALPNCERTDIR}/${challenge_names[${idx}]}.key.pem" + # Clean challenge token using non-chained hook + # shellcheck disable=SC2086 + [[ -n "${HOOK}" ]] && [[ "${HOOK_CHAIN}" != "yes" ]] && ("${HOOK}" "clean_challenge" ${deploy_args[${idx}]} || _exiterr 'clean_challenge hook returned with non-zero exit code') + idx=$((idx+1)) + done + + if [[ "${reqstatus}" != "valid" ]]; then + echo " + Challenge validation has failed :(" + _exiterr "Challenge is invalid! (returned: ${reqstatus}) (result: ${result})" + fi + fi + + # Finally request certificate from the acme-server and store it in cert-${timestamp}.pem and link from cert.pem + echo " + Requesting certificate..." + csr64="$("${OPENSSL}" req -in "${csrfile}" -config "${OPENSSL_CNF}" -outform DER | urlbase64)" + if [[ ${API} -eq 1 ]]; then + crt64="$(signed_request "${CA_NEW_CERT}" '{"resource": "new-cert", "csr": "'"${csr64}"'"}' | "${OPENSSL}" base64 -e)" + crt="$( printf -- '-----BEGIN CERTIFICATE-----\n%s\n-----END CERTIFICATE-----\n' "${crt64}" )" + else + result="$(signed_request "${finalize}" '{"csr": "'"${csr64}"'"}' | jsonsh)" + waited=0 + while :; do + orderstatus="$(echo "${result}" | get_json_string_value status)" + case "${orderstatus}" + in + "processing" | "pending") + if [ ${ORDER_TIMEOUT} -gt 0 ] && [ ${waited} -gt ${ORDER_TIMEOUT} ]; then + _exiterr "Timed out waiting for processing of order (still ${orderstatus})" + fi + echo " + Order is ${orderstatus}..." + sleep 2; + waited=$((waited+2)) + ;; + "valid") + break; + ;; + *) + _exiterr "Order has invalid/unknown status: ${orderstatus}" + ;; + esac + result="$(signed_request "${order_location}" "" | jsonsh)" + done + + resheaders="$(_mktemp)" + certificate="$(echo "${result}" | get_json_string_value certificate)" + crt="$(signed_request "${certificate}" "" 4>"${resheaders}")" + + if [ -n "${PREFERRED_CHAIN:-}" ]; then + foundaltchain=0 + altcn="$(get_last_cn "${crt}")" + altoptions="${altcn}" + if [ "${altcn}" = "${PREFERRED_CHAIN}" ]; then + foundaltchain=1 + fi + if [ "${foundaltchain}" = "0" ] && (grep -Ei '^link:' "${resheaders}" | grep -q -Ei 'rel="alternate"'); then + while read -r altcrturl; do + if [ "${foundaltchain}" = "0" ]; then + altcrt="$(signed_request "${altcrturl}" "")" + altcn="$(get_last_cn "${altcrt}")" + altoptions="${altoptions}, ${altcn}" + if [ "${altcn}" = "${PREFERRED_CHAIN}" ]; then + foundaltchain=1 + crt="${altcrt}" + fi + fi + done <<< "$(grep -Ei '^link:' "${resheaders}" | grep -Ei 'rel="alternate"' | cut -d'<' -f2 | cut -d'>' -f1)" + fi + if [ "${foundaltchain}" = "0" ]; then + _exiterr "Alternative chain with CN = ${PREFERRED_CHAIN} not found, available options: ${altoptions}" + fi + echo " + Using preferred chain with CN = ${altcn}" + fi + rm -f "${resheaders}" + fi + + # Try to load the certificate to detect corruption + echo " + Checking certificate..." + _openssl x509 -text <<<"${crt}" + + echo "${crt}" >&3 + + unset challenge_token + echo " + Done!" +} + +# grep issuer cert uri from certificate +get_issuer_cert_uri() { + certificate="${1}" + "${OPENSSL}" x509 -in "${certificate}" -noout -text | (grep 'CA Issuers - URI:' | cut -d':' -f2-) || true +} + +get_issuer_hash() { + certificate="${1}" + "${OPENSSL}" x509 -in "${certificate}" -noout -issuer_hash +} + +get_ocsp_url() { + certificate="${1}" + "${OPENSSL}" x509 -in "${certificate}" -noout -ocsp_uri +} + +# walk certificate chain, retrieving all intermediate certificates +walk_chain() { + local certificate + certificate="${1}" + + local issuer_cert_uri + issuer_cert_uri="${2:-}" + if [[ -z "${issuer_cert_uri}" ]]; then issuer_cert_uri="$(get_issuer_cert_uri "${certificate}")"; fi + if [[ -n "${issuer_cert_uri}" ]]; then + # create temporary files + local tmpcert + local tmpcert_raw + tmpcert_raw="$(_mktemp)" + tmpcert="$(_mktemp)" + + # download certificate + http_request get "${issuer_cert_uri}" > "${tmpcert_raw}" + + # PEM + if grep -q "BEGIN CERTIFICATE" "${tmpcert_raw}"; then mv "${tmpcert_raw}" "${tmpcert}" + # DER + elif "${OPENSSL}" x509 -in "${tmpcert_raw}" -inform DER -out "${tmpcert}" -outform PEM 2> /dev/null > /dev/null; then : + # PKCS7 + elif "${OPENSSL}" pkcs7 -in "${tmpcert_raw}" -inform DER -out "${tmpcert}" -outform PEM -print_certs 2> /dev/null > /dev/null; then : + # Unknown certificate type + else _exiterr "Unknown certificate type in chain" + fi + + local next_issuer_cert_uri + next_issuer_cert_uri="$(get_issuer_cert_uri "${tmpcert}")" + if [[ -n "${next_issuer_cert_uri}" ]]; then + printf "\n%s\n" "${issuer_cert_uri}" + cat "${tmpcert}" + walk_chain "${tmpcert}" "${next_issuer_cert_uri}" + fi + rm -f "${tmpcert}" "${tmpcert_raw}" + fi +} + +# Generate ALPN verification certificate +generate_alpn_certificate() { + local altname="${1}" + local identifier_type="${2}" + local acmevalidation="${3}" + + local alpncertdir="${ALPNCERTDIR}" + if [[ ! -e "${alpncertdir}" ]]; then + echo " + Creating new directory ${alpncertdir} ..." + mkdir -p "${alpncertdir}" || _exiterr "Unable to create directory ${alpncertdir}" + fi + + echo " + Generating ALPN certificate and key for ${1}..." + tmp_openssl_cnf="$(_mktemp)" + cat "${OPENSSL_CNF}" > "${tmp_openssl_cnf}" + if [[ "${identifier_type}" = "ip" ]]; then + printf "\n[SAN]\nsubjectAltName=IP:%s\n" "${altname}" >> "${tmp_openssl_cnf}" + else + printf "\n[SAN]\nsubjectAltName=DNS:%s\n" "${altname}" >> "${tmp_openssl_cnf}" + fi + printf "1.3.6.1.5.5.7.1.31=critical,DER:04:20:%s\n" "${acmevalidation}" >> "${tmp_openssl_cnf}" + SUBJ="/CN=${altname}/" + [[ "${OSTYPE:0:5}" = "MINGW" ]] && SUBJ="/${SUBJ}" + if [[ "${identifier_type}" = "ip" ]]; then + altname="$(echo "${altname}" | ip_to_ptr)" + fi + _openssl req -x509 -new -sha256 -nodes -newkey rsa:2048 -keyout "${alpncertdir}/${altname}.key.pem" -out "${alpncertdir}/${altname}.crt.pem" -subj "${SUBJ}" -extensions SAN -config "${tmp_openssl_cnf}" + chmod g+r "${alpncertdir}/${altname}.key.pem" "${alpncertdir}/${altname}.crt.pem" + rm -f "${tmp_openssl_cnf}" +} + +# Create certificate for domain(s) +sign_domain() { + local certdir="${1}" + shift + timestamp="${1}" + shift + domain="${1}" + altnames="${*}" + + export altnames + + echo " + Signing domains..." + if [[ ${API} -eq 1 ]]; then + if [[ -z "${CA_NEW_AUTHZ}" ]] || [[ -z "${CA_NEW_CERT}" ]]; then + _exiterr "Certificate authority doesn't allow certificate signing" + fi + elif [[ ${API} -eq 2 ]] && [[ -z "${CA_NEW_ORDER}" ]]; then + _exiterr "Certificate authority doesn't allow certificate signing" + fi + + local privkey="privkey.pem" + if [[ ! -e "${certdir}/cert-${timestamp}.csr" ]]; then + # generate a new private key if we need or want one + if [[ ! -r "${certdir}/privkey.pem" ]] || [[ "${PRIVATE_KEY_RENEW}" = "yes" ]]; then + echo " + Generating private key..." + privkey="privkey-${timestamp}.pem" + local tmp_privkey + tmp_privkey="$(_mktemp)" + case "${KEY_ALGO}" in + rsa) _openssl genrsa -out "${tmp_privkey}" "${KEYSIZE}";; + prime256v1|secp384r1) _openssl ecparam -genkey -name "${KEY_ALGO}" -out "${tmp_privkey}" -noout;; + esac + cat "${tmp_privkey}" > "${certdir}/privkey-${timestamp}.pem" + rm "${tmp_privkey}" + fi + # move rolloverkey into position (if any) + if [[ -r "${certdir}/privkey.pem" && -r "${certdir}/privkey.roll.pem" && "${PRIVATE_KEY_RENEW}" = "yes" && "${PRIVATE_KEY_ROLLOVER}" = "yes" ]]; then + echo " + Moving Rolloverkey into position.... " + mv "${certdir}/privkey.roll.pem" "${certdir}/privkey-tmp.pem" + mv "${certdir}/privkey-${timestamp}.pem" "${certdir}/privkey.roll.pem" + mv "${certdir}/privkey-tmp.pem" "${certdir}/privkey-${timestamp}.pem" + fi + # generate a new private rollover key if we need or want one + if [[ ! -r "${certdir}/privkey.roll.pem" && "${PRIVATE_KEY_ROLLOVER}" = "yes" && "${PRIVATE_KEY_RENEW}" = "yes" ]]; then + echo " + Generating private rollover key..." + case "${KEY_ALGO}" in + rsa) _openssl genrsa -out "${certdir}/privkey.roll.pem" "${KEYSIZE}";; + prime256v1|secp384r1) _openssl ecparam -genkey -name "${KEY_ALGO}" -out "${certdir}/privkey.roll.pem" -noout;; + esac + fi + # delete rolloverkeys if disabled + if [[ -r "${certdir}/privkey.roll.pem" && ! "${PRIVATE_KEY_ROLLOVER}" = "yes" ]]; then + echo " + Removing Rolloverkey (feature disabled)..." + rm -f "${certdir}/privkey.roll.pem" + fi + + # Generate signing request config and the actual signing request + echo " + Generating signing request..." + SAN="" + for altname in ${altnames}; do + if [[ "${altname}" =~ ^ip: ]]; then + SAN="${SAN}IP:${altname:3}, " + else + SAN="${SAN}DNS:${altname}, " + fi + done + if [[ "${domain}" =~ ^ip: ]]; then + SUBJ="/" + else + SUBJ="/CN=${domain}/" + fi + SAN="${SAN%%, }" + local tmp_openssl_cnf + tmp_openssl_cnf="$(_mktemp)" + cat "${OPENSSL_CNF}" > "${tmp_openssl_cnf}" + printf "\n[SAN]\nsubjectAltName=%s" "${SAN}" >> "${tmp_openssl_cnf}" + if [ "${OCSP_MUST_STAPLE}" = "yes" ]; then + printf "\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >> "${tmp_openssl_cnf}" + fi + if [[ "${OSTYPE:0:5}" = "MINGW" ]]; then + # The subject starts with a /, so MSYS will assume it's a path and convert + # it unless we escape it with another one: + SUBJ="/${SUBJ}" + fi + "${OPENSSL}" req -new -sha256 -key "${certdir}/${privkey}" -out "${certdir}/cert-${timestamp}.csr" -subj "${SUBJ}" -reqexts SAN -config "${tmp_openssl_cnf}" + rm -f "${tmp_openssl_cnf}" + fi + + crt_path="${certdir}/cert-${timestamp}.pem" + # shellcheck disable=SC2086 + sign_csr "${certdir}/cert-${timestamp}.csr" ${altnames} 3>"${crt_path}" + + # Create fullchain.pem + echo " + Creating fullchain.pem..." + if [[ ${API} -eq 1 ]]; then + cat "${crt_path}" > "${certdir}/fullchain-${timestamp}.pem" + local issuer_hash + issuer_hash="$(get_issuer_hash "${crt_path}")" + if [ -e "${CHAINCACHE}/${issuer_hash}.chain" ]; then + echo " + Using cached chain!" + cat "${CHAINCACHE}/${issuer_hash}.chain" > "${certdir}/chain-${timestamp}.pem" + else + echo " + Walking chain..." + local issuer_cert_uri + issuer_cert_uri="$(get_issuer_cert_uri "${crt_path}" || echo "unknown")" + (walk_chain "${crt_path}" > "${certdir}/chain-${timestamp}.pem") || _exiterr "Walking chain has failed, your certificate has been created and can be found at ${crt_path}, the corresponding private key at ${privkey}. If you want you can manually continue on creating and linking all necessary files. If this error occurs again you should manually generate the certificate chain and place it under ${CHAINCACHE}/${issuer_hash}.chain (see ${issuer_cert_uri})" + cat "${certdir}/chain-${timestamp}.pem" > "${CHAINCACHE}/${issuer_hash}.chain" + fi + cat "${certdir}/chain-${timestamp}.pem" >> "${certdir}/fullchain-${timestamp}.pem" + else + tmpcert="$(_mktemp)" + tmpchain="$(_mktemp)" + awk '{print >out}; /----END CERTIFICATE-----/{out=tmpchain}' out="${tmpcert}" tmpchain="${tmpchain}" "${certdir}/cert-${timestamp}.pem" + mv "${certdir}/cert-${timestamp}.pem" "${certdir}/fullchain-${timestamp}.pem" + cat "${tmpcert}" > "${certdir}/cert-${timestamp}.pem" + cat "${tmpchain}" > "${certdir}/chain-${timestamp}.pem" + rm "${tmpcert}" "${tmpchain}" + fi + + # Wait for hook script to sync the files before creating the symlinks + [[ -n "${HOOK}" ]] && ("${HOOK}" "sync_cert" "${certdir}/privkey-${timestamp}.pem" "${certdir}/cert-${timestamp}.pem" "${certdir}/fullchain-${timestamp}.pem" "${certdir}/chain-${timestamp}.pem" "${certdir}/cert-${timestamp}.csr" || _exiterr 'sync_cert hook returned with non-zero exit code') + + # Update symlinks + [[ "${privkey}" = "privkey.pem" ]] || ln -sf "privkey-${timestamp}.pem" "${certdir}/privkey.pem" + + ln -sf "chain-${timestamp}.pem" "${certdir}/chain.pem" + ln -sf "fullchain-${timestamp}.pem" "${certdir}/fullchain.pem" + ln -sf "cert-${timestamp}.csr" "${certdir}/cert.csr" + ln -sf "cert-${timestamp}.pem" "${certdir}/cert.pem" + + # Wait for hook script to clean the challenge and to deploy cert if used + [[ -n "${HOOK}" ]] && ("${HOOK}" "deploy_cert" "${domain}" "${certdir}/privkey.pem" "${certdir}/cert.pem" "${certdir}/fullchain.pem" "${certdir}/chain.pem" "${timestamp}" || _exiterr 'deploy_cert hook returned with non-zero exit code') + + unset challenge_token + echo " + Done!" +} + +# Update OCSP stapling file +update_ocsp_stapling() { + local certdir="${1}" + local update_ocsp="${2}" + local cert="${3}" + local chain="${4}" + + local ocsp_url="$(get_ocsp_url "${cert}")" + + if [[ -z "${ocsp_url}" ]]; then + echo " ! ERROR: OCSP stapling requested but no OCSP url found in certificate." >&2 + echo " ! Keep in mind that some CAs ended support for OCSP: https://letsencrypt.org/2024/12/05/ending-ocsp/" >&2 + return 1 + fi + + if [[ ! -e "${certdir}/ocsp.der" ]]; then + update_ocsp="yes" + elif ! ("${OPENSSL}" ocsp -no_nonce -issuer "${chain}" -verify_other "${chain}" -cert "${cert}" -respin "${certdir}/ocsp.der" -status_age $((OCSP_DAYS*24*3600)) 2>&1 | grep -q "${cert}: good"); then + update_ocsp="yes" + fi + + if [[ "${update_ocsp}" = "yes" ]]; then + echo " + Updating OCSP stapling file" + ocsp_timestamp="$(date +%s)" + if grep -qE "^(openssl (0|(1\.0))\.)|(libressl (1|2|3)\.)" <<< "$(${OPENSSL} version | awk '{print tolower($0)}')"; then + ocsp_log="$("${OPENSSL}" ocsp -no_nonce -issuer "${chain}" -verify_other "${chain}" -cert "${cert}" -respout "${certdir}/ocsp-${ocsp_timestamp}.der" -url "${ocsp_url}" -header "HOST" "$(echo "${ocsp_url}" | _sed -e 's/^http(s?):\/\///' -e 's/\/.*$//g')" 2>&1)" || _exiterr "Fetching of OCSP information failed. Please note that some CAs (e.g. LetsEncrypt) do no longer support OCSP. Error message: ${ocsp_log}" + else + ocsp_log="$("${OPENSSL}" ocsp -no_nonce -issuer "${chain}" -verify_other "${chain}" -cert "${cert}" -respout "${certdir}/ocsp-${ocsp_timestamp}.der" -url "${ocsp_url}" 2>&1)" || _exiterr "Fetching of OCSP information failed. Please note that some CAs (e.g. LetsEncrypt) do no longer support OCSP. Error message: ${ocsp_log}" + fi + ln -sf "ocsp-${ocsp_timestamp}.der" "${certdir}/ocsp.der" + [[ -n "${HOOK}" ]] && (altnames="${domain} ${morenames}" "${HOOK}" "deploy_ocsp" "${domain}" "${certdir}/ocsp.der" "${ocsp_timestamp}" || _exiterr 'deploy_ocsp hook returned with non-zero exit code') + else + echo " + OCSP stapling file is still valid (skipping update)" + fi +} + +# Usage: --version (-v) +# Description: Print version information +command_version() { + load_config noverify + + echo "Dehydrated by Lukas Schauer" + echo "https://dehydrated.io" + echo "" + echo "Dehydrated version: ${VERSION}" + revision="$(cd "${SCRIPTDIR}"; git rev-parse HEAD 2>/dev/null || echo "unknown")" + echo "GIT-Revision: ${revision}" + echo "" + # shellcheck disable=SC1091 + if [[ "${OSTYPE}" =~ (BSD|Darwin) ]]; then + echo "OS: $(uname -sr)" + elif [[ -e /etc/os-release ]]; then + ( . /etc/os-release && echo "OS: $PRETTY_NAME" ) + elif [[ -e /usr/lib/os-release ]]; then + ( . /usr/lib/os-release && echo "OS: $PRETTY_NAME" ) + else + echo "OS: $(grep -v '^$' /etc/issue | head -n1 | _sed 's/\\(r|n|l) .*//g')" + fi + echo "Used software:" + [[ -n "${BASH_VERSION:-}" ]] && echo " bash: ${BASH_VERSION}" + [[ -n "${ZSH_VERSION:-}" ]] && echo " zsh: ${ZSH_VERSION}" + echo " curl: ${CURL_VERSION}" + if [[ "${OSTYPE}" =~ (BSD|Darwin) ]]; then + echo " awk, sed, mktemp, grep, diff: BSD base system versions" + else + echo " awk: $(awk -W version 2>&1 | head -n1)" + echo " sed: $(sed --version 2>&1 | head -n1)" + echo " mktemp: $(mktemp --version 2>&1 | head -n1)" + echo " grep: $(grep --version 2>&1 | head -n1)" + echo " diff: $(diff --version 2>&1 | head -n1)" + fi + echo " openssl: $("${OPENSSL}" version 2>&1)" + + exit 0 +} + +# Usage: --display-terms +# Description: Display current terms of service +command_terms() { + init_system + echo "The current terms of service: $CA_TERMS" + echo "+ Done!" + exit 0 +} + +# Usage: --register +# Description: Register account key +command_register() { + init_system + echo "+ Done!" + exit 0 +} + +# Usage: --account +# Description: Update account contact information +command_account() { + init_system + FAILED=false + + NEW_ACCOUNT_KEY_JSON="$(_mktemp)" + + # Check if we have the registration url + if [[ -z "${ACCOUNT_URL}" ]]; then + _exiterr "Error retrieving registration url." + fi + + echo "+ Updating registration url: ${ACCOUNT_URL} contact information..." + if [[ ${API} -eq 1 ]]; then + # If an email for the contact has been provided then adding it to the registered account + if [[ -n "${CONTACT_EMAIL}" ]]; then + (signed_request "${ACCOUNT_URL}" '{"resource": "reg", "contact":["mailto:'"${CONTACT_EMAIL}"'"]}' > "${NEW_ACCOUNT_KEY_JSON}") || FAILED=true + else + (signed_request "${ACCOUNT_URL}" '{"resource": "reg", "contact":[]}' > "${NEW_ACCOUNT_KEY_JSON}") || FAILED=true + fi + else + # If an email for the contact has been provided then adding it to the registered account + if [[ -n "${CONTACT_EMAIL}" ]]; then + (signed_request "${ACCOUNT_URL}" '{"contact":["mailto:'"${CONTACT_EMAIL}"'"]}' > "${NEW_ACCOUNT_KEY_JSON}") || FAILED=true + else + (signed_request "${ACCOUNT_URL}" '{"contact":[]}' > "${NEW_ACCOUNT_KEY_JSON}") || FAILED=true + fi + fi + + if [[ "${FAILED}" = "true" ]]; then + rm "${NEW_ACCOUNT_KEY_JSON}" + _exiterr "Error updating account information. See message above for more information." + fi + if diff -q "${NEW_ACCOUNT_KEY_JSON}" "${ACCOUNT_KEY_JSON}" > /dev/null; then + echo "+ Account information was the same after the update" + rm "${NEW_ACCOUNT_KEY_JSON}" + else + ACCOUNT_KEY_JSON_BACKUP="${ACCOUNT_KEY_JSON%.*}-$(date +%s).json" + echo "+ Backup ${ACCOUNT_KEY_JSON} as ${ACCOUNT_KEY_JSON_BACKUP}" + cp -p "${ACCOUNT_KEY_JSON}" "${ACCOUNT_KEY_JSON_BACKUP}" + echo "+ Populate ${ACCOUNT_KEY_JSON}" + mv "${NEW_ACCOUNT_KEY_JSON}" "${ACCOUNT_KEY_JSON}" + fi + echo "+ Done!" + exit 0 +} + +# Parse contents of domains.txt and domains.txt.d +parse_domains_txt() { + # Allow globbing temporarily + noglob_set + local inputs=("${DOMAINS_TXT}" "${DOMAINS_TXT}.d"/*.txt) + noglob_clear + + cat "${inputs[@]}" | + tr -d '\r' | + awk '{print tolower($0)}' | + _sed -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*$//g' -e 's/[[:space:]]+/ /g' -e 's/([^ ])>/\1 >/g' -e 's/> />/g' | + (grep -vE '^(#|$)' || true) +} + +# Usage: --cron (-c) +# Description: Sign/renew non-existent/changed/expiring certificates. +command_sign_domains() { + init_system + hookscript_bricker_hook + + # Call startup hook + [[ -n "${HOOK}" ]] && ("${HOOK}" "startup_hook" || _exiterr 'startup_hook hook returned with non-zero exit code') + + if [ ! -d "${CHAINCACHE}" ]; then + echo " + Creating chain cache directory ${CHAINCACHE}" + mkdir "${CHAINCACHE}" + fi + + if [[ -n "${PARAM_DOMAIN:-}" ]]; then + DOMAINS_TXT="$(_mktemp)" + if [[ -n "${PARAM_ALIAS:-}" ]]; then + printf "%s > %s" "${PARAM_DOMAIN}" "${PARAM_ALIAS}" > "${DOMAINS_TXT}" + else + printf "%s" "${PARAM_DOMAIN}" > "${DOMAINS_TXT}" + fi + elif [[ -e "${DOMAINS_TXT}" ]]; then + if [[ ! -r "${DOMAINS_TXT}" ]]; then + _exiterr "domains.txt found but not readable" + fi + else + _exiterr "domains.txt not found and --domain not given" + fi + + # Generate certificates for all domains found in domains.txt. Check if existing certificate are about to expire + ORIGIFS="${IFS}" + IFS=$'\n' + for line in $(parse_domains_txt); do + reset_configvars + IFS="${ORIGIFS}" + alias="$(grep -Eo '>[^ ]+' <<< "${line}" || true)" + line="$(_sed -e 's/>[^ ]+[ ]*//g' <<< "${line}")" + aliascount="$(grep -Eo '>' <<< "${alias}" | awk 'END {print NR}' || true )" + [ "${aliascount}" -gt 1 ] && _exiterr "Only one alias per line is allowed in domains.txt!" + + domain="$(printf '%s\n' "${line}" | cut -d' ' -f1)" + morenames="$(printf '%s\n' "${line}" | cut -s -d' ' -f2-)" + [ "${aliascount}" -lt 1 ] && alias="${domain}" || alias="${alias#>}" + export alias + + if [[ -z "${morenames}" ]];then + echo "Processing ${domain}" + else + echo "Processing ${domain} with alternative names: ${morenames}" + fi + + if [ "${alias:0:2}" = "*." ]; then + _exiterr "Please define a valid alias for your ${domain} wildcard-certificate. See domains.txt-documentation for more details." + fi + + local certdir="${CERTDIR}/${alias}" + cert="${certdir}/cert.pem" + chain="${certdir}/chain.pem" + + force_renew="${PARAM_FORCE:-no}" + + timestamp="$(date +%s)" + + # If there is no existing certificate directory => make it + if [[ ! -e "${certdir}" ]]; then + echo " + Creating new directory ${certdir} ..." + mkdir -p "${certdir}" || _exiterr "Unable to create directory ${certdir}" + fi + + # read cert config + # for now this loads the certificate specific config in a subshell and parses a diff of set variables. + # we could just source the config file but i decided to go this way to protect people from accidentally overriding + # variables used internally by this script itself. + if [[ -n "${DOMAINS_D}" ]]; then + certconfig="${DOMAINS_D}/${alias}" + else + certconfig="${certdir}/config" + fi + + if [ -f "${certconfig}" ]; then + echo " + Using certificate specific config file!" + ORIGIFS="${IFS}" + IFS=$'\n' + for cfgline in $( + beforevars="$(_mktemp)" + aftervars="$(_mktemp)" + set > "${beforevars}" + # shellcheck disable=SC1090 + . "${certconfig}" + set > "${aftervars}" + diff -u "${beforevars}" "${aftervars}" | grep -E '^\+[^+]' + rm "${beforevars}" + rm "${aftervars}" + ); do + config_var="$(echo "${cfgline:1}" | cut -d'=' -f1)" + config_value="$(echo "${cfgline:1}" | cut -d'=' -f2- | tr -d "'")" + # All settings that are allowed here should also be stored and + # restored in store_configvars() and reset_configvars() + case "${config_var}" in + KEY_ALGO|OCSP_MUST_STAPLE|OCSP_FETCH|OCSP_DAYS|PRIVATE_KEY_RENEW|PRIVATE_KEY_ROLLOVER|KEYSIZE|CHALLENGETYPE|HOOK|PREFERRED_CHAIN|WELLKNOWN|HOOK_CHAIN|OPENSSL_CNF|RENEW_DAYS|ACME_PROFILE|ORDER_TIMEOUT|VALIDATION_TIMEOUT|KEEP_GOING) + echo " + ${config_var} = ${config_value}" + declare -- "${config_var}=${config_value}" + ;; + _) ;; + *) echo " ! Setting ${config_var} on a per-certificate base is not (yet) supported" >&2 + esac + done + IFS="${ORIGIFS}" + fi + verify_config + hookscript_bricker_hook + export WELLKNOWN CHALLENGETYPE KEY_ALGO PRIVATE_KEY_ROLLOVER + + skip="no" + + # Allow for external CSR generation + local csrfile="" + if [[ -n "${HOOK}" ]]; then + csr="$("${HOOK}" "generate_csr" "${domain}" "${certdir}" "${domain} ${morenames}")" || _exiterr 'generate_csr hook returned with non-zero exit code' + if grep -qE "\-----BEGIN (NEW )?CERTIFICATE REQUEST-----" <<< "${csr}"; then + csrfile="$(_mktemp)" + cat > "${csrfile}" <<< "${csr}" + altnames="$(extract_altnames "${csrfile}")" + domain="$(cut -d' ' -f1 <<< "${altnames}")" + morenames="$(cut -s -d' ' -f2- <<< "${altnames}")" + echo " + Using CSR from hook script (real names: ${altnames})" + else + csrfile="" + fi + fi + + # Check domain names of existing certificate + if [[ -e "${cert}" && "${force_renew}" = "no" ]]; then + printf " + Checking domain name(s) of existing cert..." + + certnames="$("${OPENSSL}" x509 -in "${cert}" -text -noout | grep -E '(DNS|IP( Address*)):' | _sed 's/(DNS|IP( Address)*)://g' | tr -d ' ' | tr ',' '\n' | sort -u | tr '\n' ' ' | _sed 's/ $//')" + givennames="$(echo "${domain}" "${morenames}"| tr ' ' '\n' | sort -u | tr '\n' ' ' | _sed 's/ip://g' | _sed 's/ $//' | _sed 's/^ //')" + + if [[ "${certnames}" = "${givennames}" ]]; then + echo " unchanged." + else + echo " changed!" + echo " + Domain name(s) are not matching!" + echo " + Names in old certificate: ${certnames}" + echo " + Configured names: ${givennames}" + echo " + Forcing renew." + force_renew="yes" + fi + fi + + # Check expire date of existing certificate + if [[ -e "${cert}" ]]; then + echo " + Checking expire date of existing cert..." + valid="$("${OPENSSL}" x509 -enddate -noout -in "${cert}" | cut -d= -f2- )" + + printf " + Valid till %s " "${valid}" + if ("${OPENSSL}" x509 -checkend $((RENEW_DAYS * 86400)) -noout -in "${cert}" > /dev/null 2>&1); then + printf "(Longer than %d days). " "${RENEW_DAYS}" + if [[ "${force_renew}" = "yes" ]]; then + echo "Ignoring because renew was forced!" + else + # Certificate-Names unchanged and cert is still valid + echo "Skipping renew!" + [[ -n "${HOOK}" ]] && ("${HOOK}" "unchanged_cert" "${domain}" "${certdir}/privkey.pem" "${certdir}/cert.pem" "${certdir}/fullchain.pem" "${certdir}/chain.pem" || _exiterr 'unchanged_cert hook returned with non-zero exit code') + skip="yes" + fi + else + echo "(Less than ${RENEW_DAYS} days). Renewing!" + fi + fi + + local update_ocsp + update_ocsp="no" + + # Sign certificate for this domain + if [[ ! "${skip}" = "yes" ]]; then + update_ocsp="yes" + if [[ -n "${csrfile}" ]]; then + cat "${csrfile}" > "${certdir}/cert-${timestamp}.csr" + rm "${csrfile}" + fi + # shellcheck disable=SC2086 + if [[ "${KEEP_GOING:-}" = "yes" ]]; then + skip_exit_hook=yes + sign_domain "${certdir}" "${timestamp}" "${domain}" ${morenames} & + wait $! || exit_with_errorcode=1 + skip_exit_hook=no + else + sign_domain "${certdir}" "${timestamp}" "${domain}" ${morenames} + fi + fi + + if [[ "${OCSP_FETCH}" = "yes" ]]; then + if [[ "${KEEP_GOING:-}" = "yes" ]]; then + skip_exit_hook=yes + update_ocsp_stapling "${certdir}" "${update_ocsp}" "${cert}" "${chain}" & + wait $! || exit_with_errorcode=1 + skip_exit_hook=no + else + update_ocsp_stapling "${certdir}" "${update_ocsp}" "${cert}" "${chain}" + fi + fi + done + reset_configvars + + # remove temporary domains.txt file if used + [[ -n "${PARAM_DOMAIN:-}" ]] && rm -f "${DOMAINS_TXT}" + + [[ -n "${HOOK}" ]] && ("${HOOK}" "exit_hook" || echo 'exit_hook returned with non-zero exit code!' >&2) + if [[ "${AUTO_CLEANUP}" == "yes" ]]; then + echo " + Running automatic cleanup" + PARAM_CLEANUPDELETE="${AUTO_CLEANUP_DELETE:-no}" command_cleanup noinit | _sed 's/^/ + /g' + fi + + exit "${exit_with_errorcode}" +} + +# Usage: --signcsr (-s) path/to/csr.pem +# Description: Sign a given CSR, output CRT on stdout (advanced usage) +command_sign_csr() { + init_system + + # redirect stdout to stderr + # leave stdout over at fd 3 to output the cert + exec 3>&1 1>&2 + + # load csr + local csrfile="${1}" + if [ ! -r "${csrfile}" ]; then + _exiterr "Could not read certificate signing request ${csrfile}" + fi + + # extract names + altnames="$(extract_altnames "${csrfile}")" + + # gen cert + certfile="$(_mktemp)" + # shellcheck disable=SC2086 + sign_csr "${csrfile}" ${altnames} 3> "${certfile}" + + # print cert + echo "# CERT #" >&3 + cat "${certfile}" >&3 + echo >&3 + + # print chain + if [ -n "${PARAM_FULL_CHAIN:-}" ]; then + # get and convert ca cert + chainfile="$(_mktemp)" + tmpchain="$(_mktemp)" + http_request get "$("${OPENSSL}" x509 -in "${certfile}" -noout -text | grep 'CA Issuers - URI:' | cut -d':' -f2-)" > "${tmpchain}" + if grep -q "BEGIN CERTIFICATE" "${tmpchain}"; then + mv "${tmpchain}" "${chainfile}" + else + "${OPENSSL}" x509 -in "${tmpchain}" -inform DER -out "${chainfile}" -outform PEM + rm "${tmpchain}" + fi + + echo "# CHAIN #" >&3 + cat "${chainfile}" >&3 + + rm "${chainfile}" + fi + + # cleanup + rm "${certfile}" + + exit 0 +} + +# Usage: --revoke (-r) path/to/cert.pem +# Description: Revoke specified certificate +command_revoke() { + init_system + + [[ -n "${CA_REVOKE_CERT}" ]] || _exiterr "Certificate authority doesn't allow certificate revocation." + + cert="${1}" + if [[ -L "${cert}" ]]; then + # follow symlink and use real certificate name (so we move the real file and not the symlink at the end) + local link_target + link_target="$(readlink -n "${cert}")" + if [[ "${link_target}" =~ ^/ ]]; then + cert="${link_target}" + else + cert="$(dirname "${cert}")/${link_target}" + fi + fi + [[ -f "${cert}" ]] || _exiterr "Could not find certificate ${cert}" + + echo "Revoking ${cert}" + + cert64="$("${OPENSSL}" x509 -in "${cert}" -inform PEM -outform DER | urlbase64)" + if [[ ${API} -eq 1 ]]; then + response="$(signed_request "${CA_REVOKE_CERT}" '{"resource": "revoke-cert", "certificate": "'"${cert64}"'"}' | clean_json)" + else + response="$(signed_request "${CA_REVOKE_CERT}" '{"certificate": "'"${cert64}"'"}' | clean_json)" + fi + # if there is a problem with our revoke request _request (via signed_request) will report this and "exit 1" out + # so if we are here, it is safe to assume the request was successful + echo " + Done." + echo " + Renaming certificate to ${cert}-revoked" + mv -f "${cert}" "${cert}-revoked" +} + +# Usage: --deactivate +# Description: Deactivate account +command_deactivate() { + init_system + + echo "Deactivating account ${ACCOUNT_URL}" + + if [[ ${API} -eq 1 ]]; then + echo "Deactivation for ACMEv1 is not implemented" + else + response="$(signed_request "${ACCOUNT_URL}" '{"status": "deactivated"}' | clean_json)" + deactstatus=$(echo "$response" | jsonsh | get_json_string_value "status") + if [[ "${deactstatus}" = "deactivated" ]]; then + touch "${ACCOUNT_DEACTIVATED}" + else + _exiterr "Account deactivation failed!" + fi + fi + + echo " + Done." +} + +# Usage: --cleanup (-gc) +# Description: Move unused certificate files to archive directory +command_cleanup() { + if [ ! "${1:-}" = "noinit" ]; then + load_config + fi + + if [[ ! "${PARAM_CLEANUPDELETE:-}" = "yes" ]]; then + # Create global archive directory if not existent + if [[ ! -e "${BASEDIR}/archive" ]]; then + mkdir "${BASEDIR}/archive" + fi + fi + + # Allow globbing + noglob_set + + # Loop over all certificate directories + for certdir in "${CERTDIR}/"*; do + # Skip if entry is not a folder + [[ -d "${certdir}" ]] || continue + + # Get certificate name + certname="$(basename "${certdir}")" + + # Create certificates archive directory if not existent + if [[ ! "${PARAM_CLEANUPDELETE:-}" = "yes" ]]; then + archivedir="${BASEDIR}/archive/${certname}" + if [[ ! -e "${archivedir}" ]]; then + mkdir "${archivedir}" + fi + fi + + # Loop over file-types (certificates, keys, signing-requests, ...) + for filetype in cert.csr cert.pem chain.pem fullchain.pem privkey.pem ocsp.der; do + # Delete all if symlink is broken + if [[ -r "${certdir}/${filetype}" ]]; then + # Look up current file in use + current="$(basename "$(readlink "${certdir}/${filetype}")")" + else + if [[ -h "${certdir}/${filetype}" ]]; then + echo "Removing broken symlink: ${certdir}/${filetype}" + rm -f "${certdir}/${filetype}" + fi + current="" + fi + + # Split filetype into name and extension + filebase="$(echo "${filetype}" | cut -d. -f1)" + fileext="$(echo "${filetype}" | cut -d. -f2)" + + # Loop over all files of this type + for file in "${certdir}/${filebase}-"*".${fileext}" "${certdir}/${filebase}-"*".${fileext}-revoked"; do + # Check if current file is in use, if unused move to archive directory + filename="$(basename "${file}")" + if [[ ! "${filename}" = "${current}" ]] && [[ -f "${certdir}/${filename}" ]]; then + if [[ "${PARAM_CLEANUPDELETE:-}" = "yes" ]]; then + echo "Deleting unused file: ${certname}/${filename}" + rm "${certdir}/${filename}" + else + echo "Moving unused file to archive directory: ${certname}/${filename}" + mv "${certdir}/${filename}" "${archivedir}/${filename}" + fi + fi + done + done + done + + exit "${exit_with_errorcode}" +} + +# Usage: --cleanup-delete (-gcd) +# Description: Deletes (!) unused certificate files +command_cleanupdelete() { + command_cleanup +} + + +# Usage: --help (-h) +# Description: Show help text +command_help() { + printf "Usage: %s [-h] [command [argument]] [parameter [argument]] [parameter [argument]] ...\n\n" "${0}" + printf "Default command: help\n\n" + echo "Commands:" + grep -e '^[[:space:]]*# Usage:' -e '^[[:space:]]*# Description:' -e '^command_.*()[[:space:]]*{' "${0}" | while read -r usage; read -r description; read -r command; do + if [[ ! "${usage}" =~ Usage ]] || [[ ! "${description}" =~ Description ]] || [[ ! "${command}" =~ ^command_ ]]; then + _exiterr "Error generating help text." + fi + printf " %-32s %s\n" "${usage##"# Usage: "}" "${description##"# Description: "}" + done + printf -- "\nParameters:\n" + grep -E -e '^[[:space:]]*# PARAM_Usage:' -e '^[[:space:]]*# PARAM_Description:' "${0}" | while read -r usage; read -r description; do + if [[ ! "${usage}" =~ Usage ]] || [[ ! "${description}" =~ Description ]]; then + _exiterr "Error generating help text." + fi + printf " %-32s %s\n" "${usage##"# PARAM_Usage: "}" "${description##"# PARAM_Description: "}" + done +} + +# Usage: --env (-e) +# Description: Output configuration variables for use in other scripts +command_env() { + echo "# dehydrated configuration" + load_config + typeset -p CA CERTDIR ALPNCERTDIR CHALLENGETYPE DOMAINS_D DOMAINS_TXT HOOK HOOK_CHAIN RENEW_DAYS ACCOUNT_KEY ACCOUNT_KEY_JSON ACCOUNT_ID_JSON KEYSIZE WELLKNOWN PRIVATE_KEY_RENEW OPENSSL_CNF CONTACT_EMAIL LOCKFILE +} + +# Main method (parses script arguments and calls command_* methods) +main() { + exit_with_errorcode=0 + skip_exit_hook=no + COMMAND="" + set_command() { + [[ -z "${COMMAND}" ]] || _exiterr "Only one command can be executed at a time. See help (-h) for more information." + COMMAND="${1}" + } + + check_parameters() { + if [[ -z "${1:-}" ]]; then + echo "The specified command requires additional parameters. See help:" >&2 + echo >&2 + command_help >&2 + exit 1 + elif [[ "${1:0:1}" = "-" ]]; then + _exiterr "Invalid argument: ${1}" + fi + } + + [[ -z "${*}" ]] && eval set -- "--help" + + while (( ${#} )); do + case "${1}" in + --help|-h) + command_help + exit 0 + ;; + + --env|-e) + set_command env + ;; + + --cron|-c) + set_command sign_domains + ;; + + --register) + set_command register + ;; + + --account) + set_command account + ;; + + # PARAM_Usage: --accept-terms + # PARAM_Description: Accept CAs terms of service + --accept-terms) + PARAM_ACCEPT_TERMS="yes" + ;; + + --display-terms) + set_command terms + ;; + + --signcsr|-s) + shift 1 + set_command sign_csr + check_parameters "${1:-}" + PARAM_CSR="${1}" + ;; + + --revoke|-r) + shift 1 + set_command revoke + check_parameters "${1:-}" + PARAM_REVOKECERT="${1}" + ;; + + --deactivate) + set_command deactivate + ;; + + --version|-v) + set_command version + ;; + + --cleanup|-gc) + set_command cleanup + ;; + + --cleanup-delete|-gcd) + set_command cleanupdelete + PARAM_CLEANUPDELETE="yes" + ;; + + # PARAM_Usage: --full-chain (-fc) + # PARAM_Description: Print full chain when using --signcsr + --full-chain|-fc) + PARAM_FULL_CHAIN="1" + ;; + + # PARAM_Usage: --ipv4 (-4) + # PARAM_Description: Resolve names to IPv4 addresses only + --ipv4|-4) + PARAM_IP_VERSION="4" + ;; + + # PARAM_Usage: --ipv6 (-6) + # PARAM_Description: Resolve names to IPv6 addresses only + --ipv6|-6) + PARAM_IP_VERSION="6" + ;; + + # PARAM_Usage: --domain (-d) domain.tld + # PARAM_Description: Use specified domain name(s) instead of domains.txt entry (one certificate!) + --domain|-d) + shift 1 + check_parameters "${1:-}" + if [[ -z "${PARAM_DOMAIN:-}" ]]; then + PARAM_DOMAIN="${1}" + else + PARAM_DOMAIN="${PARAM_DOMAIN} ${1}" + fi + ;; + + # PARAM_Usage: --ca url/preset + # PARAM_Description: Use specified CA URL or preset + --ca) + shift 1 + check_parameters "${1:-}" + [[ -n "${PARAM_CA:-}" ]] && _exiterr "CA can only be specified once!" + PARAM_CA="${1}" + ;; + + # PARAM_Usage: --alias certalias + # PARAM_Description: Use specified name for certificate directory (and per-certificate config) instead of the primary domain (only used if --domain is specified) + --alias) + shift 1 + check_parameters "${1:-}" + [[ -n "${PARAM_ALIAS:-}" ]] && _exiterr "Alias can only be specified once!" + PARAM_ALIAS="${1}" + ;; + + # PARAM_Usage: --keep-going (-g) + # PARAM_Description: Keep going after encountering an error while creating/renewing multiple certificates in cron mode + --keep-going|-g) + PARAM_KEEP_GOING="yes" + ;; + + # PARAM_Usage: --force (-x) + # PARAM_Description: Force certificate renewal even if it is not due to expire within RENEW_DAYS + --force|-x) + PARAM_FORCE="yes" + ;; + + # PARAM_Usage: --force-validation + # PARAM_Description: Force revalidation of domain names (used in combination with --force) + --force-validation) + PARAM_FORCE_VALIDATION="yes" + ;; + + # PARAM_Usage: --no-lock (-n) + # PARAM_Description: Don't use lockfile (potentially dangerous!) + --no-lock|-n) + PARAM_NO_LOCK="yes" + ;; + + # PARAM_Usage: --lock-suffix example.com + # PARAM_Description: Suffix lockfile name with a string (useful for with -d) + --lock-suffix) + shift 1 + check_parameters "${1:-}" + PARAM_LOCKFILE_SUFFIX="${1}" + ;; + + # PARAM_Usage: --ocsp + # PARAM_Description: Sets option in CSR indicating OCSP stapling to be mandatory + --ocsp) + PARAM_OCSP_MUST_STAPLE="yes" + ;; + + # PARAM_Usage: --privkey (-p) path/to/key.pem + # PARAM_Description: Use specified private key instead of account key (useful for revocation) + --privkey|-p) + shift 1 + check_parameters "${1:-}" + PARAM_ACCOUNT_KEY="${1}" + ;; + + # PARAM_Usage: --domains-txt path/to/domains.txt + # PARAM_Description: Use specified domains.txt instead of default/configured one + --domains-txt) + shift 1 + check_parameters "${1:-}" + PARAM_DOMAINS_TXT="${1}" + ;; + + # PARAM_Usage: --config (-f) path/to/config + # PARAM_Description: Use specified config file + --config|-f) + shift 1 + check_parameters "${1:-}" + CONFIG="${1}" + ;; + + # PARAM_Usage: --hook (-k) path/to/hook.sh + # PARAM_Description: Use specified script for hooks + --hook|-k) + shift 1 + check_parameters "${1:-}" + PARAM_HOOK="${1}" + ;; + + # PARAM_Usage: --preferred-chain issuer-cn + # PARAM_Description: Use alternative certificate chain identified by issuer CN + --preferred-chain) + shift 1 + check_parameters "${1:-}" + PARAM_PREFERRED_CHAIN="${1}" + ;; + + # PARAM_Usage: --out (-o) certs/directory + # PARAM_Description: Output certificates into the specified directory + --out|-o) + shift 1 + check_parameters "${1:-}" + PARAM_CERTDIR="${1}" + ;; + + # PARAM_Usage: --alpn alpn-certs/directory + # PARAM_Description: Output alpn verification certificates into the specified directory + --alpn) + shift 1 + check_parameters "${1:-}" + PARAM_ALPNCERTDIR="${1}" + ;; + + # PARAM_Usage: --challenge (-t) http-01|dns-01|tls-alpn-01 + # PARAM_Description: Which challenge should be used? Currently http-01, dns-01, and tls-alpn-01 are supported + --challenge|-t) + shift 1 + check_parameters "${1:-}" + PARAM_CHALLENGETYPE="${1}" + ;; + + # PARAM_Usage: --algo (-a) rsa|prime256v1|secp384r1 + # PARAM_Description: Which public key algorithm should be used? Supported: rsa, prime256v1 and secp384r1 + --algo|-a) + shift 1 + check_parameters "${1:-}" + PARAM_KEY_ALGO="${1}" + ;; + + # PARAM_Usage: --acme-profile profile_name + # PARAM_Description: Use specified ACME profile + --acme-profile) + shift 1 + check_parameters "${1:-}" + PARAM_ACME_PROFILE="${1}" + ;; + + # PARAM_Usage: --order-timeout seconds + # PARAM_Description: Amount of seconds to wait for processing of order until erroring out + --order-timeout) + shift 1 + check_parameters "${1:-}" + PARAM_ORDER_TIMEOUT=${1} + ;; + + # PARAM_Usage: --validation-timeout seconds + # PARAM_Description: Amount of seconds to wait for processing of domain validations until erroring out + --validation-timeout) + shift 1 + check_parameters "${1:-}" + PARAM_VALIDATION_TIMEOUT=${1} + ;; + + *) + echo "Unknown parameter detected: ${1}" >&2 + echo >&2 + command_help >&2 + exit 1 + ;; + esac + + shift 1 + done + + case "${COMMAND}" in + env) command_env;; + sign_domains) command_sign_domains;; + register) command_register;; + account) command_account;; + sign_csr) command_sign_csr "${PARAM_CSR}";; + revoke) command_revoke "${PARAM_REVOKECERT}";; + deactivate) command_deactivate;; + cleanup) command_cleanup;; + terms) command_terms;; + cleanupdelete) command_cleanupdelete;; + version) command_version;; + *) command_help; exit 1;; + esac + + exit "${exit_with_errorcode}" +} + +# Determine OS type +OSTYPE="$(uname)" + +if [[ ! "${DEHYDRATED_NOOP:-}" = "NOOP" ]]; then + # Run script + main "${@:-}" +fi + +# vi: expandtab sw=2 ts=2 diff --git a/opt/sbin/pushover-client b/opt/sbin/pushover-client new file mode 100755 index 0000000..1e86583 --- /dev/null +++ b/opt/sbin/pushover-client @@ -0,0 +1,701 @@ +#!/bin/bash +# Version: 0.1.0 +# Copyright (c) 2023: +# Darren 'Tadgy' Austin +# Licensed under the terms of the GNU General Public License version 3. +# +# A PushOver client to send alert messages. + +# Configuration. +CONFIG_API_URL="https://api.pushover.net/1/messages.json" +CONFIG_SOUNDS_API_URL="https://api.pushover.net/1/sounds.json" + +# Defaults. +DEFAULT_SYSTEM_DIR="/etc/pushover-client" +DEFAULT_USER_DIR="${HOME}/.pushover-client" +DEFAULT_CONFIG_FILE="default" +DEFAULT_EXPIRY="3600" +DEFAULT_RETRY="60" + +# Functions. +show_help() { + local SCRIPT="${0##*/}" + + #........1.........2.........3.........4.........5.........6.........7.........8 + cat <<-EOF + Usage: $SCRIPT [config file] [options] + Push notifications to your https://pushover.net registered devices. + + If [config_file] is specified it is used to read the default configuration. + If [config_file] is not specified, a custom user or system 'default' file will be + read to obtain the defaults. If no 'default' custom user or system config file + can be read, command line options are required for operation. + Command line [options] override any config file. + + Options: + -a, --attachment The picture to send with the alert. No default. + -A, --api-url The API URL to use for this submission. Default + is: $CONFIG_API_URL. + Quote if it contains shell special chars. + -c, --callback A URL which is accessed by API server when the + user acknowledges the alert. This option is + only used in priority 2 alerts. + Quote if it contains shell special chars. + -d, --devices A comma seperated list of the devices to receive + the alert. Default is to send to all devices. + -e, --expiry Set the expiration time for alerts sent with + priority 2. Default is 3600 (1 hour). The + maximum expiry time is 10800 (3 hours). + --examples Show extended example usage of this program. + -h, --help Show this help page. + -m, --message The plain text message to send. + Quote if it contains spaces. + This option or -M is required if a message is + not available from a config file. + -M, --html-message The HTML message to send. + Quote if it contains spaces. + This option or -m is required if a message is + not available from a config file. + --monospace Use a monospace font to display the message + given with -m. Default is to use regular font. + This option cannot be used with -M. + -p, --priority Set the priority of the message: + -2 Lowest priority - no alert/notification + will be generated. However, the app + badge or number will update on devices. + -1 Low priority - no alert sound is + emitted but a notification will appear. + During a user's configured quiet hours, + priority -1 is used for messages. + 0 Normal priority (the default) - an alert + sound and notification are generated. + 1 High priority - bypass the user's + configured quiet hours and generate an + alert and notification. + 2 Emergency - as priority 1, but the alert + and notification is repeated (subject to + the -r and -e options) until it is + acknowledged by the recipient. + -q, --quiet Do not print the API execution reply to stdout. + -r, --retry Set the retry interval for alerts sent with + priority 2. Default is 60 (1 minute). The + minimum retry time is 30 seconds. + -s, --subject The subject/title of the message. If unset, + the configured app name is used. + Quote if it contains spaces. + -S, --sound Set the alert sound to play with message: + none None/silent. + vibrate Vibrate only. + pushover Pushover (short, default). + bike Bike (short). + bugle Bugle (short). + cashregister Cash Register (short). + classical Classical (short). + cosmic Cosmic (short). + falling Falling (short). + gamelan Gamelan (short). + incoming Incoming (short). + intermission Intermission (short). + magic Magic (short). + mechanical Mechanical (short). + pianobar Piano Bar (short). + siren Siren (short). + spacealarm Space Alarm (short). + tugboat Tug Boat (short). + alien Alien Alarm (long). + climb Climb (long). + persistent Persistent (long). + echo Pushover Echo (long). + updown Up Down (long). + Or a sound uploaded to the user's account. + -t, --token The pushover.net API token/key for the specific + application. This option is required if not + available from a config file. + -T, --ttl The number of seconds the alert will live (or + be displayed) on a users device before being + automatically removed. The default is no ttl. + This option is ignored when alerts are sent with + priority (-p) 2. + --timestamp The number of seconds since the unix epoch to + use as the timestamp for the alert. + The default timestamp is the time the API + received the message. + -u, --user The pushover.net user key(s). If a single user + key is specified, that account's configuration + will be used for the alerts. If a comma + separated list (maximum 50) of user keys is + given, the alert is sent only to those users. + This option is required if not available from a + config file. + -U, --url Set the URL to send with the alert. + Quote if it contains shell special chars. + --url-title The title of the URL given with -U. Ignored + if -U is not used also. + Quote if it contains spaces. + Option processing ceases with "--". + + For example usage, use: $SCRIPT --examples + EOF +} + +show_examples() { + local SCRIPT="${0##*/}" + + #........1.........2.........3.........4.........5.........6.........7.........8 + cat <<-EOF + Basic usage is: $SCRIPT [config file] [options] + + [config file] configuration options are overridden by command line [options]. + All or part settings may be specified in the [config file], with the addition of + command line [options] to augment the [config file] settings. + [options] can be seen by running: $SCRIPT --help + + Command line examples: + Send a plain text message to all devices, showing all required [options]. + $SCRIPT -u -t -m "Test message" + + Same as the above, but do not show any response from the API server (an + appropriate error/return code is set). + $SCRIPT -q -u -t -m "Test message" + + Send a HTML message (which will be underlined) to all devices, showing all + required [options]. + $SCRIPT -u -t -M "Test message" + + Send a plain text message to all devices, with the addition of a subject/title + to the message. + $SCRIPT -u -t -s "Test subject" -m "..." + + Send a message to all devices, including a picture attachment. + $SCRIPT -u -t -a -m "..." + + Send a message to all devices, including a supplimentary URL with a title. + $SCRIPT -u -t -U "https://afterdark.org.uk" \\ + --url-title "Afterdark" -m "Check out the included URL!" + + Send a message to all devices, selecting an alternative sound alert. + $SCRIPT -u -t -s "magic" -m "..." + + Send a message to a specific list of devices. + $SCRIPT -u -t -d "iphone,ipad" -m "..." + + Send an emergency alert, repeated every minute for an 2 hours until it is + acknowledged by the user. + $SCRIPT -u -t -p 2 -r 60 -e 7200 -m "..." + + Read all configuration from path and use that for sending the + alert. If this path does not exist, search for a file matching the the + name in the user's private pushover directory (~/.pushover-client) + or the system wide pushover directory (/etc/pushover-client), in that order. + $SCRIPT + EOF +} + +# Pick out possible config file and '--' arguments of the command line. +ARGS=( "$@" ) +(( ${#ARGS[@]} >= 1 )) && FIRST_ARG="${ARGS[0]}" +(( ${#ARGS[@]} >= 2 )) && SECOND_ARG="${ARGS[1]}" + +# Get the config filename if it was given on the command line, or use the default. +[[ -z "$FIRST_ARG" ]] || [[ "$FIRST_ARG" =~ -[^-] ]] && FILENAME="$DEFAULT_CONFIG_FILE" && SKIP_CUSTOM=1 +[[ ! -v FILENAME ]] && [[ "$FIRST_ARG" != -* ]] && FILENAME="$FIRST_ARG" && unset "ARGS[0]" +[[ ! -v FILENAME ]] && [[ "$FIRST_ARG" == "--" ]] && [[ -n "$SECOND_ARG" ]] && FILENAME="$SECOND_ARG" && unset "ARGS[1]" + +# Find and validate the correct config filename. +if (( ${SKIP_CUSTOM:-0} == 1 )) && [[ -e "$DEFAULT_USER_DIR/$FILENAME" ]] && [[ ! -d "$DEFAULT_USER_DIR/$FILENAME" ]] && \ + [[ -r "$DEFAULT_USER_DIR/$FILENAME" ]]; then + FILENAME="$DEFAULT_USER_DIR/$FILENAME" +elif (( ${SKIP_CUSTOM:-0} == 1 )) && [[ -e "$DEFAULT_SYSTEM_DIR/$FILENAME" ]] && [[ ! -d "$DEFAULT_SYSTEM_DIR/$FILENAME" ]] && \ + [[ -r "$DEFAULT_SYSTEM_DIR/$FILENAME" ]]; then + FILENAME="$DEFAULT_SYSTEM_DIR/$FILENAME" +elif [[ "${FILENAME:0:1}" != "/" ]] && [[ -e "$FILENAME" ]] && [[ ! -d "$FILENAME" ]] && [[ -r "$FILENAME" ]]; then + : +elif [[ "${FILENAME:0:1}" != "/" ]] && [[ -e "$DEFAULT_USER_DIR/$FILENAME" ]] && [[ ! -d "$DEFAULT_USER_DIR/$FILENAME" ]] && \ + [[ -r "$DEFAULT_USER_DIR/$FILENAME" ]]; then + FILENAME="$DEFAULT_USER_DIR/$FILENAME" +elif [[ "${FILENAME:0:1}" != "/" ]] && [[ -e "$DEFAULT_SYSTEM_DIR/$FILENAME" ]] && [[ ! -d "$DEFAULT_SYSTEM_DIR/$FILENAME" ]] && \ + [[ -r "$DEFAULT_SYSTEM_DIR/$FILENAME" ]]; then + FILENAME="$DEFAULT_SYSTEM_DIR/$FILENAME" +elif [[ "${FILENAME:0:1}" == "/" ]] && [[ -e "$FILENAME" ]] && [[ ! -d "$FILENAME" ]] && [[ -r "$FILENAME" ]]; then + : +elif [[ -n "$FILENAME" ]]; then + printf "%s: '%s' %s\\n" "${0##*/}" "$FILENAME" "invalid config file name" >&2 + exit 1 +fi + +# Read the config file. +[[ -n "$FILENAME" ]] && { + eval "$(awk '!/^(#|$|[[:blank:]]*$)/ { print "CONFIG_"$0 }' "$FILENAME")" 2>/dev/null || { + printf "%s: %s '%s'\\n" "${0##*/}" "error in config file" "$FILENAME" >&2 + exit 1 + } +} + +# Parse command line options. +set -- "${ARGS[@]}" +while [[ -n "$1" ]]; do + case "$1" in + -a|-attachment|--attachment) + if [[ "$2" =~ ^[[:blank:]]*$ ]]; then + printf "%s: %s\\n" "${0##*/}" "attachment filename cannot be an empty value" >&2 + exit 1 + else + CONFIG_ATTACHMENT="$2" + fi + shift + ;; + -A|-api-url|--api-url) + # Setting is validated below. + CONFIG_API_URL="$2" + shift + ;; + -c|-callback|--callback) + if [[ "$2" =~ ^[[:blank:]]*$ ]]; then + printf "%s: %s\\n" "${0##*/}" "callback URL address cannot be empty" >&2 + exit 1 + else + CONFIG_CALLBACK_URL="$2" + fi + shift + ;; + -d|-devices|--devices) + if [[ "$2" =~ ^[[:blank:]]*$ ]]; then + printf "%s: %s\\n" "${0##*/}" "device list cannot be an empty value" >&2 + exit 1 + else + CONFIG_DEVICES="$2" + fi + shift + ;; + -e|-expiry|--expiry) + if [[ "$2" =~ ^[[:blank:]]*$ ]]; then + printf "%s: %s\\n" "${0##*/}" "expiry time cannot be an empty value" >&2 + exit 1 + else + CONFIG_EXPIRY="$2" + fi + shift + ;; + -examples|--examples) + show_examples + exit 0 + ;; + -h|-help|--help) + show_help + exit 0 + ;; + -m|-message|--message) + # Setting is validated below. + CONFIG_MESSAGE="$2" + shift + ;; + -M|-html-message|--html-message) + # Setting is validated below. + CONFIG_HTML_MESSAGE="$2" + shift + ;; + -monospace|--monospace) + # Setting is validated below. + CONFIG_MONOSPACE="1" + shift + ;; + -p|-priority|--priority) + if [[ "$2" =~ ^[[:blank:]]*$ ]]; then + printf "%s: %s\\n" "${0##*/}" "priority setting cannot be an empty value" >&2 + exit 1 + else + CONFIG_PRIORITY="$2" + fi + shift + ;; + -q|-quiet|--quiet) + CONFIG_QUIET=1 + shift + ;; + -r|-retry|--retry) + if [[ "$2" =~ ^[[:blank:]]*$ ]]; then + printf "%s: %s\\n" "${0##*/}" "retry time cannot be an empty value" >&2 + exit 1 + else + CONFIG_RETRY="$2" + fi + shift + ;; + -s|-subject|--subject) + if [[ "$2" =~ ^[[:blank:]]*$ ]]; then + printf "%s: %s\\n" "${0##*/}" "subject/title cannot be an empty value" >&2 + exit 1 + else + CONFIG_SUBJECT="$2" + fi + shift + ;; + -S|-sound|--sound) + if [[ "$2" =~ ^[[:blank:]]*$ ]]; then + printf "%s: %s\\n" "${0##*/}" "sound selection cannot be empty" >&2 + exit 1 + else + CONFIG_SOUND="$2" + fi + shift + ;; + -t|-token|--token) + if [[ "$2" =~ ^[[:blank:]]*$ ]]; then + printf "%s: %s\\n" "${0##*/}" "token key cannot be an empty value" >&2 + exit 1 + else + CONFIG_TOKEN="$2" + fi + shift + ;; + -T|-ttl|--ttl) + if [[ "$2" =~ ^[[:blank:]]*$ ]]; then + printf "%s: %s\\n" "${0##*/}" "ttl cannot be an empty value" >&2 + exit 1 + else + CONFIG_TTL="$2" + fi + shift + ;; + -timestamp|--timestamp) + if [[ "$2" =~ ^[[:blank:]]*$ ]]; then + printf "%s: %s\\n" "${0##*/}" "timestamp cannot be an empty value" >&2 + exit 1 + else + CONFIG_TIMESTAMP="$2" + fi + shift + ;; + -u|-user|--user) + # Setting is validated below. + CONFIG_USER_KEYS="$2" + shift + ;; + -U|-url|--url) + if [[ "$2" =~ ^[[:blank:]]*$ ]]; then + printf "%s: %s\\n" "${0##*/}" "URL address cannot be empty" >&2 + exit 1 + else + CONFIG_URL="$2" + fi + shift + ;; + -url-title|--url-title) + if [[ "$2" =~ ^[[:blank:]]*$ ]]; then + printf "%s: %s\\n" "${0##*/}" "URL title cannot be empty" >&2 + exit 1 + else + CONFIG_URL_TITLE="$2" + fi + shift + ;; + --) + shift + break + ;; + *) + printf "%s: %s: %s\\n" "${0##*/}" "invalid option" "$1" >&2 + printf "%s: %s %s\\n" "Try" "${0##*/}" "--help" >&2 + exit 1 + ;; + esac + shift +done + +# The options list should be empty if the correct syntax was used. +[[ -n "$1" ]] && { + printf "%s: %s\\n" "${0##*/}" "options cannot come after --" >&2 + exit 1 +} + +# Validate all the CONFIG_* settings. +[[ "$CONFIG_API_URL" =~ ^[[:blank:]]*$ ]] && { + printf "%s: %s\\n" "${0##*/}" "API URL (-A) cannot be an empty value" >&2 + exit 1 +} + +if [[ ! "$CONFIG_ATTACHMENT" =~ ^[[:blank:]]*$ ]]; then + if [[ ! -e "$CONFIG_ATTACHMENT" ]]; then + printf "%s: %s '%s' %s\\n" "${0##*/}" "attachment (-a)" "$CONFIG_ATTACHMENT" "does not exist" >&2 + exit 1 + elif [[ -d "$CONFIG_ATTACHMENT" ]]; then + printf "%s: %s '%s' %s\\n" "${0##*/}" "attachment (-a)" "$CONFIG_ATTACHMENT" "is a directory, not a file" >&2 + exit 1 + elif [[ ! -r "$CONFIG_ATTACHMENT" ]]; then + printf "%s: %s '%s' %s\\n" "${0##*/}" "attachment (-a)" "$CONFIG_ATTACHMENT" "is not readable by you" >&2 + exit 1 + elif (( $(stat --printf=%s "$CONFIG_ATTACHMENT") > 2621440 )); then + printf "%s: %s\\n" "${0##*/}" "attachment (-a) is too large (2.5MB maximum)" >&2 + exit 1 + fi +else + unset "CONFIG_ATTACHMENT" +fi + +if [[ ! "$CONFIG_CALLBACK_URL" =~ ^[[:blank:]]*$ ]]; then + (( ${#CONFIG_CALLBACK_URL} > 512 )) && { + printf "%s: %s\\n" "${0##*/}" "callback URL (-c) is too long (maximum 512 characters)" >&2 + exit 1 + } +else + unset "CONFIG_CALLBACK_URL" +fi + +if [[ ! "$CONFIG_DEVICES" =~ ^[[:blank:]]*$ ]]; then + while read -r -d , DEV; do + [[ -z "$DEV" ]] && continue + if (( "${#DEV}" > 25 )); then + printf "%s: %s\\n" "${0##*/}" "device IDs (-d) are 25 characters or less in length" >&2 + exit 1 + elif [[ ! "$DEV" =~ ^[[:alnum:]_-]*$ ]]; then + printf "%s: %s\\n" "${0##*/}" "device IDs (-d) can only be letters, numbers, _ and -" >&2 + exit 1 + else + if [[ -z "$LIST" ]]; then + LIST="$DEV" + else + LIST+=",$DEV" + fi + fi + done <<<"$CONFIG_DEVICES," # The , on the end is required. + CONFIG_DEVICES="$LIST" +else + unset "CONFIG_DEVICES" +fi + +if [[ ! "$CONFIG_EXPIRY" =~ ^[[:blank:]]*$ ]]; then + if [[ ! "$CONFIG_EXPIRY" =~ [[:digit:]] ]]; then + printf "%s: %s\\n" "${0##*/}" "expiry time (-e) must be a number" >&2 + exit 1 + elif (( CONFIG_EXPIRY < 30 )); then + printf "%s: %s\\n" "${0##*/}" "expiry time (-e) cannot be that short (30s minimum)" >&2 + exit 1 + elif (( CONFIG_EXPIRY > 10800 )); then + printf "%s: %s\\n" "${0##*/}" "expiry time (-e) cannot be that long (10800s/3h maximum)" >&2 + exit 1 + elif [[ -n "$CONFIG_RETRY" ]] && (( CONFIG_EXPIRY < CONFIG_RETRY )); then + printf "%s: %s\\n" "${0##*/}" "expiry time (-e) is less than retry time" >&2 + exit 1 + fi +else + unset "CONFIG_EXPIRY" +fi + +if [[ "$CONFIG_MONOSPACE" =~ ^[[:blank:]]*$ ]] || [[ "$CONFIG_MONOSPACE" =~ ^(false|0)$ ]]; then + CONFIG_MONOSPACE=0 +elif [[ "$CONFIG_MONOSPACE" =~ ^(true|1)$ ]]; then + CONFIG_MONOSPACE=1 +else + printf "%s: %s\\n" "${0##*/}" "monospace (--monospace) setting must be 'true', '1', 'false' or '0'" >&2 + exit 1 +fi + +if [[ ! "$CONFIG_MESSAGE" =~ ^[[:blank:]]*$ ]] && [[ ! "$CONFIG_HTML_MESSAGE" =~ ^[[:blank:]]*$ ]]; then + printf "%s: %s\\n" "${0##*/}" "cannot mix a plain text (-m) and HTML (-M) message setting" >&2 + exit 1 +elif [[ "$CONFIG_MESSAGE" =~ ^[[:blank:]]*$ ]] && [[ "$CONFIG_HTML_MESSAGE" =~ ^[[:blank:]]*$ ]]; then + printf "%s: %s\\n" "${0##*/}" "must set either a plain text (-m) or HTML (-M) message" >&2 + exit 1 +elif [[ ! "$CONFIG_HTML_MESSAGE" =~ ^[[:blank:]]*$ ]] && (( CONFIG_MONOSPACE == 1 )); then + printf "%s: %s\\n" "${0##*/}" "HTML messages (-M) cannot be used with a monospace font (--monospace)" >&2 + exit 1 +elif (( ${#CONFIG_MESSAGE} > 1024 )) || (( ${#CONFIG_HTML_MESSAGE} > 1024 )); then + printf "%s: %s\\n" "${0##*/}" "message (-m/-M) length is too long (maximum 1024 characters)" >&2 + exit 1 +fi + +if [[ ! "$CONFIG_PRIORITY" =~ ^[[:blank:]]*$ ]]; then + if [[ ! "$CONFIG_PRIORITY" =~ [[:digit:]] ]]; then + printf "%s: %s\\n" "${0##*/}" "priority (-p) setting must be a number" >&2 + exit 1 + elif (( CONFIG_PRIORITY < -2 )) || (( CONFIG_PRIORITY > 2 )); then + printf "%s: %s\\n" "${0##*/}" "priority (-p) setting must be in the range -2 - 2" >&2 + exit 1 + fi +else + unset "CONFIG_PRIORITY" +fi + +if [[ "$CONFIG_QUIET" =~ ^[[:blank:]]*$ ]] || [[ "$CONFIG_QUIET" =~ ^(false|0)$ ]]; then + CONFIG_QUIET=0 +elif [[ "$CONFIG_QUIET" =~ ^(true|1)$ ]]; then + CONFIG_QUIET=1 +else + printf "%s: %s\\n" "${0##*/}" "quiet (-q) setting must be 'true', '1', 'false' or '0'" >&2 + exit 1 +fi + +if [[ ! "$CONFIG_RETRY" =~ ^[[:blank:]]*$ ]]; then + if [[ ! "$CONFIG_RETRY" =~ [[:digit:]] ]]; then + printf "%s: %s\\n" "${0##*/}" "retry time (-r) must be a number" >&2 + exit 1 + elif (( CONFIG_RETRY < 30 )); then + printf "%s: %s\\n" "${0##*/}" "retry time (-r) cannot be that short (30s minimum)" >&2 + exit 1 + elif [[ -n "$CONFIG_EXPIRY" ]] && (( CONFIG_RETRY > CONFIG_EXPIRY )); then + printf "%s: %s\\n" "${0##*/}" "retry time (-r) exceeds expiry time" >&2 + exit 1 + fi +else + unset "CONFIG_RETRY" +fi + +if [[ ! "$CONFIG_SUBJECT" =~ ^[[:blank:]]*$ ]]; then + (( ${#CONFIG_SUBJECT} > 250 )) && { + printf "%s: %s\\n" "${0##*/}" "subject/title (-s) is too long (maximum 250 characters)" >&2 + exit 1 + } +else + unset "CONFIG_SUBJECT" +fi + +if [[ ! "$CONFIG_TOKEN" =~ ^[[:blank:]]*$ ]]; then + if (( "${#CONFIG_TOKEN}" != 30 )); then + printf "%s: %s\\n" "${0##*/}" "token key (-t) must be 30 characters in length" >&2 + exit 1 + elif [[ ! "$CONFIG_TOKEN" =~ ^[[:alnum:]]*$ ]]; then + printf "%s: %s\\n" "${0##*/}" "token key (-t) can only be letters and numbers" >&2 + exit 1 + fi +else + printf "%s: %s\\n" "${0##*/}" "token key (-t) cannot be an empty value" >&2 + exit 1 +fi + +if [[ ! "$CONFIG_SOUND" =~ ^[[:blank:]]*$ ]]; then + [[ ! "$CONFIG_SOUND" =~ ^(none|vibrate|pushover|bike|bugle|cashregister|classical|cosmic|falling|gamelan|incoming|intermission|magic|mechanical|pianobar|siren|spacealarm|tugboat|alien|climb|persistent|echo|updown)$ ]] && { + JSON="$(curl -s "$CONFIG_SOUNDS_API_URL?token=$CONFIG_TOKEN" 2>/dev/null)" + if [[ "$JSON" =~ \"status\":1, ]]; then + [[ ! "$JSON" =~ \"$CONFIG_SOUND\": ]] && { + printf "%s: %s\\n" "${0##*/}" "sound (-S) must be a built-in or user uploaded custom sound" >&2 + exit 1 + } + else + printf "%s: %s\\n" "${0##*/}" "failed to get list of custom sounds from API (invalid API token?)" >&2 + exit 1 + fi + } +else + unset "CONFIG_SOUND" +fi + +if [[ ! "$CONFIG_TTL" =~ ^[[:blank:]]*$ ]]; then + if [[ ! "$CONFIG_TTL" =~ [[:digit:]] ]]; then + printf "%s: %s\\n" "${0##*/}" "TTL (-T) must be a number" >&2 + exit 1 + elif (( CONFIG_TTL < 0 )); then + printf "%s: %s\\n" "${0##*/}" "TTL (-T) must be a positive number of seconds" >&2 + exit 1 + fi +else + unset "CONFIG_TTL" +fi + +if [[ ! "$CONFIG_TIMESTAMP" =~ ^[[:blank:]]*$ ]]; then + if [[ ! "$CONFIG_TIMESTAMP" =~ [[:digit:]] ]]; then + printf "%s: %s\\n" "${0##*/}" "timestamp (--timestamp) must be a number" >&2 + exit 1 + elif (( CONFIG_TIMESTAMP < 0 )); then + printf "%s: %s\\n" "${0##*/}" "timestamp (--timestamp) must be a positive number of seconds" >&2 + exit 1 + fi +else + unset "CONFIG_TIMESTAMP" +fi + +if [[ ! "$CONFIG_USER_KEYS" =~ ^[[:blank:]]*$ ]]; then + unset COUNT LIST + while read -r -d , KEY; do + [[ -z "$KEY" ]] && continue + if (( "${#KEY}" != 30 )); then + printf "%s: %s\\n" "${0##*/}" "user keys (-u) must be 30 characters in length" >&2 + exit 1 + elif [[ ! "$KEY" =~ ^[[:alnum:]]*$ ]]; then + printf "%s: %s\\n" "${0##*/}" "user keys (-u) can only be letters and numbers" >&2 + exit 1 + else + if [[ -z "$LIST" ]]; then + LIST="$KEY" + COUNT=1 + else + LIST+=",$KEY" + (( COUNT++ )) + fi + fi + done <<<"$CONFIG_USER_KEYS," # The , on the end is required. + (( COUNT > 50 )) && { + printf "%s: %s\\n" "${0##*/}" "too many user keys (-u) (maximum 50)" >&2 + exit 1 + } + CONFIG_USER_KEYS="$LIST" +else + printf "%s: %s\\n" "${0##*/}" "user keys (-u) cannot be an empty value" >&2 + exit 1 +fi + +if [[ ! "$CONFIG_URL" =~ ^[[:blank:]]*$ ]]; then + (( ${#CONFIG_URL} > 512 )) && { + printf "%s: %s\\n" "${0##*/}" "URL (-U) is too long (maximum 512 characters)" >&2 + exit 1 + } +else + unset "CONFIG_URL" +fi + +if [[ ! "$CONFIG_URL_TITLE" =~ ^[[:blank:]]*$ ]]; then + (( ${#CONFIG_URL_TITLE} > 100 )) && { + printf "%s: %s\\n" "${0##*/}" "URL title (--url-title) is too long (maximum 100 characters)" >&2 + exit 1 + } +else + unset "CONFIG_URL_TITLE" +fi + +# Build the curl command line. +COMMAND_LINE=('-s') +# Required API elements. +COMMAND_LINE+=('--form-string' user="$CONFIG_USER_KEYS") +COMMAND_LINE+=('--form-string' token="$CONFIG_TOKEN") +if [[ -v CONFIG_MESSAGE ]]; then + COMMAND_LINE+=('--form-string' message="$CONFIG_MESSAGE") + (( CONFIG_MONOSPACE == 1 )) && COMMAND_LINE+=('--form-string' 'monospace=1') +else + COMMAND_LINE+=('--form-string' message="$CONFIG_HTML_MESSAGE") + COMMAND_LINE+=('--form-string' 'html=1') +fi +# Optional API elements. +[[ -v CONFIG_ATTACHMENT ]] && COMMAND_LINE+=('--form' attachment="@$CONFIG_ATTACHMENT") +[[ -v CONFIG_DEVICES ]] && COMMAND_LINE+=('--form-string' device="$CONFIG_DEVICES") +[[ -v CONFIG_PRIORITY ]] && { + COMMAND_LINE+=('--form-string' priority="$CONFIG_PRIORITY") + (( CONFIG_PRIORITY == 2 )) && { + [[ -v CONFIG_CALLBACK_URL ]] && COMMAND_LINE+=('--form-string' callback="$CONFIG_CALLBACK_URL") + COMMAND_LINE+=('--form-string' expire="${CONFIG_EXPIRY:-$DEFAULT_EXPIRY}") + COMMAND_LINE+=('--form-string' retry="${CONFIG_RETRY:-$DEFAULT_RETRY}") + } +} +[[ -v CONFIG_SUBJECT ]] && COMMAND_LINE+=('--form-string' title="$CONFIG_SUBJECT") +[[ -v CONFIG_SOUND ]] && COMMAND_LINE+=('--form-string' sound="$CONFIG_SOUND") +[[ -v CONFIG_TTL ]] && COMMAND_LINE+=('--form-string' ttl="$CONFIG_TTL") +[[ -v CONFIG_TIMESTAMP ]] && COMMAND_LINE+=('--form-string' timestamp="$CONFIG_TIMESTAMP") +[[ -v CONFIG_URL ]] && COMMAND_LINE+=('--form-string' url="$CONFIG_URL") +[[ -v CONFIG_URL_TITLE ]] && COMMAND_LINE+=('--form-string' url_title="$CONFIG_URL_TITLE") + +# Make the call to the messaging API. +JSON="$(curl "${COMMAND_LINE[@]}" "$CONFIG_API_URL" 2>/dev/null)" || { + printf "%s: %s\\n" "${0##*/}" "API call failed" >&2 + exit 3 +} +if [[ "$JSON" =~ \"status\":1, ]]; then + (( CONFIG_QUIET == 0 )) && printf "%s\\n" "$JSON" +else + printf "%s: %s\\n" "${0##*/}" "API returned a non-success status code" >&2 + (( CONFIG_QUIET == 0 )) && printf "%s\\n" "$JSON" >&2 + exit 2 +fi + +# 0 = Request submitted OK. +# 1 = Usage error. +# 2 = Request status error from API +# 3 = Error accessing API +exit 0 diff --git a/opt/sbin/terraform-http-backend b/opt/sbin/terraform-http-backend new file mode 100755 index 0000000..0f3578a Binary files /dev/null and b/opt/sbin/terraform-http-backend differ diff --git a/root/.bash_logout b/root/.bash_logout new file mode 100644 index 0000000..df5d9a6 --- /dev/null +++ b/root/.bash_logout @@ -0,0 +1,14 @@ +#!/bin/bash - not strictly necessary, but helps nano with syntax highlighting. + +# Clear the screen/console on logout. +if (( SHLVL == 1 )); then + if [[ -x /usr/bin/clear_console ]]; then + /usr/bin/clear_console -q + elif [[ -x /usr/bin/clear ]]; then + /usr/bin/clear + elif [[ -x /usr/bin/tput ]]; then + /usr/bin/tput clear + else + echo -ne "\e[2J" + fi +fi diff --git a/root/.bash_profile b/root/.bash_profile new file mode 100644 index 0000000..bf68916 --- /dev/null +++ b/root/.bash_profile @@ -0,0 +1,19 @@ +#!/bin/bash - not strictly necessary, but helps nano with syntax highlighting. +# Bash shell environmental set up. + +export LANG="en_GB.UTF-8" +export LC_COLLATE="POSIX" # 'C' causes issues with some applications +export PATH="/opt/sbin:/opt/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" +hash less >/dev/null 2>&1 && export PAGER="less" +hash nano >/dev/null 2>&1 && export EDITOR="nano" && export VISUAL="$EDITOR" + +[[ -d "$HOME/files/bin" ]] && export PATH="$HOME/files/bin:$PATH" +[[ -d "$HOME/.local/bin" ]] && export PATH="$HOME/.local/bin:$PATH" +[[ -d "$HOME/bin" ]] && export PATH="$HOME/bin:$PATH" + +for FILE in "$HOME"/.bash_profile.d/*; do + [[ -x "$FILE" ]] && source "$FILE" +done +unset FILE + +[[ -f "$HOME/.bashrc" ]] && . "$HOME/.bashrc" diff --git a/root/.bashrc b/root/.bashrc new file mode 100644 index 0000000..7fcb2ed --- /dev/null +++ b/root/.bashrc @@ -0,0 +1,54 @@ +#!/bin/bash - not strictly necessary, but helps nano with syntax highlighting. +# Bash specific configuration. + +__prompt_user_colour() { + # Determine the colour of the username in the prompt. + + if [[ "$(whoami)" == "root" ]]; then + printf "%s" "1;31m" # Bright Red. + elif [[ "$(whoami)" == "tadgy" ]]; then + printf "%s" "1;32m" # Bright Green. + else + printf "%s" "1;36m" # Bright Cyan. + fi + + return 0 +} + +shopt -s cdspell checkhash checkjobs checkwinsize cmdhist dirspell histappend no_empty_cmd_completion + +HISTCONTROL="ignoredups" +HISTFILE="$HOME/.bash_history-${HOSTNAME%%.*}" +HISTFILESIZE=1000000 +HISTIGNORE="bg:bg *:fg:fg *:jobs:exit:clear:history" +HISTSIZE=1000000 +HISTTIMEFORMAT="%d/%m/%y %H:%M:%S " +IGNOREEOF=0 +PROMPT_DIRTRIM=2 +PS1='[\[\033[$(__prompt_user_colour)\]\u\[\033[0m\]@\[\033[1;33m\]\h\[\033[0m\]] \[\033[1;34m\]\w\[\033[0m\] ->' + +history -a +history -r + +hash grep >/dev/null 2>&1 && { alias egrep='grep -E'; alias fgrep='grep -F'; } +hash ps grep >/dev/null 2>&1 && psgrep() { + if [[ -n "$1" ]]; then + # shellcheck disable=SC2009 + ps | command grep -E -- "(.*RSS.*|$1)" | command grep -F -v '(.*RSS.*|' + else + printf "%s: %s\\n" "Usage" "${FUNCNAME[0]} " >&2 + return 1 + fi +} +hash ls >/dev/null 2>&1 && alias ls='ls -Fv --color=always' +hash nc >/dev/null 2>&1 && alias pastebin='nc termbin.com 9999' + +[[ -z "$SSH_TTY" ]] && { + echo -ne "\e[2q" + echo -e "\e]12;#00FF00" +} + +for FILE in "$HOME"/.bashrc.d/*; do + [[ -x "$FILE" ]] && source "$FILE" +done +unset FILE diff --git a/root/.gitconfig b/root/.gitconfig new file mode 100644 index 0000000..7f9f4af --- /dev/null +++ b/root/.gitconfig @@ -0,0 +1,27 @@ +[user] + name = Darren 'Tadgy' Austin + email = darren@afterdark.org.uk +[color] + branch = auto + diff = auto + grep = auto + interactive = auto + showBranch = auto + status = auto + ui = auto +[credential] + username = tadgy + helper = cache --timeout 2592000 +[commit] + verbose = 1 +[push] + autoSetupRemote = true +[alias] + c = commit + co = checkout + d = diff + lsut = ls-files --others --exclude-standard --directory --error-unmatch -- ':/*' + p = push + s = status +[init] + defaultBranch = master diff --git a/root/.gitignore b/root/.gitignore new file mode 100644 index 0000000..83fd8b0 --- /dev/null +++ b/root/.gitignore @@ -0,0 +1,12 @@ +/* +!/.* +!/.*/ +!/.*/** +!/stuff-to-keep/ + +/.bash_history* +/.composer/ +/.gnupg/ +/.lesshst +/.nano_history +/.profile diff --git a/root/.local/share/nano/.gitignore b/root/.local/share/nano/.gitignore new file mode 100644 index 0000000..4f77bdc --- /dev/null +++ b/root/.local/share/nano/.gitignore @@ -0,0 +1 @@ +/search_history diff --git a/root/.nanorc b/root/.nanorc new file mode 100644 index 0000000..1b0e0a0 --- /dev/null +++ b/root/.nanorc @@ -0,0 +1,125 @@ +## When soft line wrapping is enabled, make it wrap lines at blank characters. +set atblanks + +## Use auto-indentation. +set autoindent + +## When saving a file, create a backup file by adding a tilde (~). +# set backup + +## Automatically hard-wrap the current line when it becomes overlong. +# set breaklonglines + +## Do case-sensitive searches by default. +# set casesensitive + +## Do not use the line below the title bar. +# set emptyline + +## Set the line length for wrapping text and justifying paragraphs. +set fill -2 + +## Draw a vertical stripe at the given column +#set guidestripe 190 + +## Remember the used search/replace strings for the next session. +set historylog + +## Display a "scrollbar" on the righthand side of the edit window. +# set indicator + +## Scroll the buffer contents per half-screen instead of per line. +# set jumpyscrolling + +## Display line numbers to the left of the text area. +set linenumbers + +## Enable vim-style lock-files. +set locking + +## Use libmagic for syntax highlighting suggestions. +# set magic + +## Don't display the helpful shortcut lists at the bottom of the screen. +set nohelp + +## Don't add newlines to the ends of files. +# set nonewlines + +## Save the cursor position of files between editing sessions. +# set positionlog + +## Do quick statusbar blanking. +set quickblank + +## Do extended regular expression searches by default. +# set regexp + +## Make the Home key smarter. +set smarthome + +## Enable soft line wrapping (AKA full-line display). +set softwrap + +## Use this spelling checker instead of the internal one. +# set speller "aspell -x -c" + +## Show flags in the title bar. +set stateflags + +## When justifying text, trailing whitespace will automatically be removed. +set trimblanks + +## The two characters used to indicate the presence of tabs and spaces. +set whitespace »· + +## Detect word boundaries more accurately by treating punctuation +## characters as parts of words. +set wordbounds + +## Let an unmodified Backspace or Delete erase the marked region, without +## affecting the cut-buffer. +# set zap + + +## Paint the interface elements of nano. +set errorcolor brightwhite,red +set functioncolor magenta +set keycolor brightwhite +set numbercolor brightwhite,magenta +set promptcolor brightwhite,magenta +set scrollercolor brightwhite,magenta +set selectedcolor brightwhite,blue +set spotlightcolor black,yellow +set statuscolor brightwhite,magenta +set stripecolor ,magenta +set titlecolor brightwhite,magenta + + +## Include all existing syntax highlight definitions. +# include "/usr/share/nano/*.nanorc" + + +## Key bindings. +## The following five functions are not bound to any key by default. +## You may wish to choose different keys than the ones suggested here. +# bind ^S savefile main +# bind M-Q findprevious main +# bind M-W findnext main +# bind M-B cutwordleft main +# bind M-N cutwordright main +## Set this if your Backspace key sends Del most of the time. +# bind Del backspace all +# Unbind the ^J (justification) shortcut as it's annoying. +unbind ^J main +# Allow ^Z to suspend nano. +bind ^Z suspend main +# Allow marking using ^Space. +bind ^Space mark main +# Select buffers. +bind M-9 nextbuf main +bind M-0 prevbuf main +# Use anchors. +bind Ins anchor main +bind M-, prevanchor main +bind M-. nextanchor main diff --git a/root/.ssh/.gitignore b/root/.ssh/.gitignore new file mode 100644 index 0000000..73e51bd --- /dev/null +++ b/root/.ssh/.gitignore @@ -0,0 +1,2 @@ +/known_hosts +/known_hosts.old diff --git a/root/.ssh/authorized_keys b/root/.ssh/authorized_keys new file mode 100644 index 0000000..e54d97a --- /dev/null +++ b/root/.ssh/authorized_keys @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICsx4EY4vbDt0TXGZsW9UjOxj+s/mVeytJ7lW5rAu0gS Darren 'Tadgy' Austin diff --git a/root/stuff-to-keep/clean-fd b/root/stuff-to-keep/clean-fd new file mode 100755 index 0000000..c0a69d9 --- /dev/null +++ b/root/stuff-to-keep/clean-fd @@ -0,0 +1,5 @@ +#!/bin/bash + +rm -f /var/spool/fusiondirectory/* +rm -f /var/cache/fusiondirectory/{fai/*,fusiondirectory.auth,template/*,tmp/*} +rm -f /var/lib/php/sessions/* diff --git a/root/stuff-to-keep/conf.d/00_bcmath.ini b/root/stuff-to-keep/conf.d/00_bcmath.ini new file mode 100644 index 0000000..6813a0b --- /dev/null +++ b/root/stuff-to-keep/conf.d/00_bcmath.ini @@ -0,0 +1 @@ +extension=bcmath diff --git a/root/stuff-to-keep/conf.d/00_bz2.ini b/root/stuff-to-keep/conf.d/00_bz2.ini new file mode 100644 index 0000000..d0b5b0f --- /dev/null +++ b/root/stuff-to-keep/conf.d/00_bz2.ini @@ -0,0 +1 @@ +extension=bz2 diff --git a/root/stuff-to-keep/conf.d/00_curl.ini b/root/stuff-to-keep/conf.d/00_curl.ini new file mode 100644 index 0000000..89fa13d --- /dev/null +++ b/root/stuff-to-keep/conf.d/00_curl.ini @@ -0,0 +1 @@ +extension=curl diff --git a/root/stuff-to-keep/conf.d/00_gd.ini b/root/stuff-to-keep/conf.d/00_gd.ini new file mode 100644 index 0000000..bb35ed0 --- /dev/null +++ b/root/stuff-to-keep/conf.d/00_gd.ini @@ -0,0 +1 @@ +extension=gd diff --git a/root/stuff-to-keep/conf.d/00_gettext.ini b/root/stuff-to-keep/conf.d/00_gettext.ini new file mode 100644 index 0000000..549944c --- /dev/null +++ b/root/stuff-to-keep/conf.d/00_gettext.ini @@ -0,0 +1 @@ +extension=gettext diff --git a/root/stuff-to-keep/conf.d/00_gmp.ini b/root/stuff-to-keep/conf.d/00_gmp.ini new file mode 100644 index 0000000..1b2be41 --- /dev/null +++ b/root/stuff-to-keep/conf.d/00_gmp.ini @@ -0,0 +1 @@ +extension=gmp diff --git a/root/stuff-to-keep/conf.d/00_iconv.ini b/root/stuff-to-keep/conf.d/00_iconv.ini new file mode 100644 index 0000000..4711441 --- /dev/null +++ b/root/stuff-to-keep/conf.d/00_iconv.ini @@ -0,0 +1 @@ +extension=iconv diff --git a/root/stuff-to-keep/conf.d/00_imap.ini b/root/stuff-to-keep/conf.d/00_imap.ini new file mode 100644 index 0000000..d026b09 --- /dev/null +++ b/root/stuff-to-keep/conf.d/00_imap.ini @@ -0,0 +1 @@ +extension=imap diff --git a/root/stuff-to-keep/conf.d/00_intl.ini b/root/stuff-to-keep/conf.d/00_intl.ini new file mode 100644 index 0000000..63f20e8 --- /dev/null +++ b/root/stuff-to-keep/conf.d/00_intl.ini @@ -0,0 +1 @@ +extension=intl diff --git a/root/stuff-to-keep/conf.d/00_ldap.ini b/root/stuff-to-keep/conf.d/00_ldap.ini new file mode 100644 index 0000000..5d67d7d --- /dev/null +++ b/root/stuff-to-keep/conf.d/00_ldap.ini @@ -0,0 +1 @@ +extension=ldap diff --git a/root/stuff-to-keep/conf.d/00_mbstring.ini b/root/stuff-to-keep/conf.d/00_mbstring.ini new file mode 100644 index 0000000..0e3a392 --- /dev/null +++ b/root/stuff-to-keep/conf.d/00_mbstring.ini @@ -0,0 +1 @@ +extension=mbstring diff --git a/root/stuff-to-keep/conf.d/00_opcache.ini b/root/stuff-to-keep/conf.d/00_opcache.ini new file mode 100644 index 0000000..592cb59 --- /dev/null +++ b/root/stuff-to-keep/conf.d/00_opcache.ini @@ -0,0 +1 @@ +zend_extension=opcache diff --git a/root/stuff-to-keep/conf.d/00_openssl.ini b/root/stuff-to-keep/conf.d/00_openssl.ini new file mode 100644 index 0000000..355624b --- /dev/null +++ b/root/stuff-to-keep/conf.d/00_openssl.ini @@ -0,0 +1 @@ +extension=openssl diff --git a/root/stuff-to-keep/conf.d/00_posix.ini b/root/stuff-to-keep/conf.d/00_posix.ini new file mode 100644 index 0000000..e58281c --- /dev/null +++ b/root/stuff-to-keep/conf.d/00_posix.ini @@ -0,0 +1 @@ +extension=posix diff --git a/root/stuff-to-keep/conf.d/00_session.ini b/root/stuff-to-keep/conf.d/00_session.ini new file mode 100644 index 0000000..7482518 --- /dev/null +++ b/root/stuff-to-keep/conf.d/00_session.ini @@ -0,0 +1 @@ +extension=session diff --git a/root/stuff-to-keep/conf.d/00_simplexml.ini b/root/stuff-to-keep/conf.d/00_simplexml.ini new file mode 100644 index 0000000..c88c0ae --- /dev/null +++ b/root/stuff-to-keep/conf.d/00_simplexml.ini @@ -0,0 +1 @@ +extension=simplexml diff --git a/root/stuff-to-keep/conf.d/00_sodium.ini b/root/stuff-to-keep/conf.d/00_sodium.ini new file mode 100644 index 0000000..2932bf4 --- /dev/null +++ b/root/stuff-to-keep/conf.d/00_sodium.ini @@ -0,0 +1 @@ +extension=sodium diff --git a/root/stuff-to-keep/conf.d/00_sqlite3.ini b/root/stuff-to-keep/conf.d/00_sqlite3.ini new file mode 100644 index 0000000..7ee602b --- /dev/null +++ b/root/stuff-to-keep/conf.d/00_sqlite3.ini @@ -0,0 +1 @@ +extension=sqlite3 diff --git a/root/stuff-to-keep/conf.d/00_xml.ini b/root/stuff-to-keep/conf.d/00_xml.ini new file mode 100644 index 0000000..971783d --- /dev/null +++ b/root/stuff-to-keep/conf.d/00_xml.ini @@ -0,0 +1 @@ +extension=xml diff --git a/root/stuff-to-keep/conf.d/00_zip.ini b/root/stuff-to-keep/conf.d/00_zip.ini new file mode 100644 index 0000000..08a7894 --- /dev/null +++ b/root/stuff-to-keep/conf.d/00_zip.ini @@ -0,0 +1 @@ +extension=zip diff --git a/root/stuff-to-keep/conf.d/01_phar.ini b/root/stuff-to-keep/conf.d/01_phar.ini new file mode 100644 index 0000000..c535cef --- /dev/null +++ b/root/stuff-to-keep/conf.d/01_phar.ini @@ -0,0 +1 @@ +extension=phar diff --git a/root/stuff-to-keep/conf.d/99_pdo.ini b/root/stuff-to-keep/conf.d/99_pdo.ini new file mode 100644 index 0000000..1e03675 --- /dev/null +++ b/root/stuff-to-keep/conf.d/99_pdo.ini @@ -0,0 +1,6 @@ +[Pdo] +; Whether to pool ODBC connections. Can be one of "strict", "relaxed" or "off" +; http://php.net/pdo-odbc.connection-pooling +;pdo_odbc.connection_pooling=strict + +;pdo_odbc.db2_instance_name diff --git a/root/stuff-to-keep/conf.d/99_pdo_mysql.ini b/root/stuff-to-keep/conf.d/99_pdo_mysql.ini new file mode 100644 index 0000000..1598241 --- /dev/null +++ b/root/stuff-to-keep/conf.d/99_pdo_mysql.ini @@ -0,0 +1,4 @@ +[Pdo_mysql] +; Default socket name for local MySQL connects. If empty, uses the built-in +; MySQL defaults. +;pdo_mysql.default_socket= diff --git a/root/stuff-to-keep/conf.d/99_pgsql.ini b/root/stuff-to-keep/conf.d/99_pgsql.ini new file mode 100644 index 0000000..0b17fb5 --- /dev/null +++ b/root/stuff-to-keep/conf.d/99_pgsql.ini @@ -0,0 +1,27 @@ +[PostgreSQL] +; Allow or prevent persistent links. +; http://php.net/pgsql.allow-persistent +pgsql.allow_persistent = On + +; Detect broken persistent links always with pg_pconnect(). +; Auto reset feature requires a little overheads. +; http://php.net/pgsql.auto-reset-persistent +pgsql.auto_reset_persistent = Off + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/pgsql.max-persistent +pgsql.max_persistent = -1 + +; Maximum number of links (persistent+non persistent). -1 means no limit. +; http://php.net/pgsql.max-links +pgsql.max_links = -1 + +; Ignore PostgreSQL backends Notice message or not. +; Notice message logging require a little overheads. +; http://php.net/pgsql.ignore-notice +pgsql.ignore_notice = 0 + +; Log PostgreSQL backends Notice message or not. +; Unless pgsql.ignore_notice=0, module cannot log notice message. +; http://php.net/pgsql.log-notice +pgsql.log_notice = 0 diff --git a/root/stuff-to-keep/conf.d/99_phar.ini b/root/stuff-to-keep/conf.d/99_phar.ini new file mode 100644 index 0000000..e3fc161 --- /dev/null +++ b/root/stuff-to-keep/conf.d/99_phar.ini @@ -0,0 +1,8 @@ +[Phar] +; http://php.net/phar.readonly +;phar.readonly = On + +; http://php.net/phar.require-hash +;phar.require_hash = On + +;phar.cache_list = diff --git a/root/stuff-to-keep/conf.d/99_session.ini b/root/stuff-to-keep/conf.d/99_session.ini new file mode 100644 index 0000000..214fac5 --- /dev/null +++ b/root/stuff-to-keep/conf.d/99_session.ini @@ -0,0 +1,269 @@ +[Session] +; Handler used to store/retrieve data. +; http://php.net/session.save-handler +session.save_handler = files + +; Argument passed to save_handler. In the case of files, this is the path +; where data files are stored. Note: Windows users have to change this +; variable in order to use PHP's session functions. +; +; The path can be defined as: +; +; session.save_path = "N;/path" +; +; where N is an integer. Instead of storing all the session files in +; /path, what this will do is use subdirectories N-levels deep, and +; store the session data in those directories. This is useful if +; your OS has problems with many files in one directory, and is +; a more efficient layout for servers that handle many sessions. +; +; NOTE 1: PHP will not create this directory structure automatically. +; You can use the script in the ext/session dir for that purpose. +; NOTE 2: See the section on garbage collection below if you choose to +; use subdirectories for session storage +; +; The file storage module creates files using mode 600 by default. +; You can change that by using +; +; session.save_path = "N;MODE;/path" +; +; where MODE is the octal representation of the mode. Note that this +; does not overwrite the process's umask. +; http://php.net/session.save-path +session.save_path = "/var/lib/php/sessions" + +; Name of the session (used as cookie name). +; http://php.net/session.name +session.name = PHP_SESSION_ID + +; Initialize session on request startup. +; http://php.net/session.auto-start +;session.auto_start = 0 + +; Handler used to serialize data. php is the standard serializer of PHP. +; http://php.net/session.serialize-handler +session.serialize_handler = php_serialize + +; Defines the probability that the 'garbage collection' process is started on every +; session initialization. The probability is calculated by using gc_probability/gc_divisor, +; e.g. 1/100 means there is a 1% chance that the GC process starts on each request. +; Default Value: 1 +; Development Value: 1 +; Production Value: 1 +; http://php.net/session.gc-probability +;session.gc_probability = 1 + +; Defines the probability that the 'garbage collection' process is started on every +; session initialization. The probability is calculated by using gc_probability/gc_divisor, +; e.g. 1/100 means there is a 1% chance that the GC process starts on each request. +; For high volume production servers, using a value of 1000 is a more efficient approach. +; Default Value: 100 +; Development Value: 1000 +; Production Value: 1000 +; http://php.net/session.gc-divisor +;session.gc_divisor = 1000 + +; After this number of seconds, stored data will be seen as 'garbage' and +; cleaned up by the garbage collection process. +; http://php.net/session.gc-maxlifetime +session.gc_maxlifetime = 86400 + +; NOTE: If you are using the subdirectory option for storing session files +; (see session.save_path above), then garbage collection does *not* +; happen automatically. You will need to do your own garbage +; collection through a shell script, cron entry, or some other method. +; For example, the following script is the equivalent of setting +; session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes): +; find /path/to/sessions -cmin +24 -type f | xargs rm + +; Check HTTP Referer to invalidate externally stored URLs containing ids. +; HTTP_REFERER has to contain this substring for the session to be +; considered as valid. +; http://php.net/session.referer-check +;session.referer_check = + +; Gives a path to an external resource (file) which will be used as an +; additional entropy source in the session id creation process. +;session.entropy_file string = /dev/urandom + +; Whether to use strict session mode. +; Strict session mode does not accept an uninitialized session ID, and +; regenerates the session ID if the browser sends an uninitialized session ID. +; Strict mode protects applications from session fixation via a session adoption +; vulnerability. It is disabled by default for maximum compatibility, but +; enabling it is encouraged. +; https://wiki.php.net/rfc/strict_sessions +;session.use_strict_mode = 0 + +; Whether to use cookies. +; http://php.net/session.use-cookies +; session.use_cookies = 1 + +; This option forces PHP to fetch and use a cookie for storing and maintaining +; the session id. We encourage this operation as it's very helpful in combating +; session hijacking when not specifying and managing your own session id. It is +; not the be-all and end-all of session hijacking defense, but it's a good start. +; http://php.net/session.use-only-cookies +;session.use_only_cookies = 1 + +; Lifetime in seconds of cookie or, if 0, until browser is restarted. +; http://php.net/session.cookie-lifetime +;session.cookie_lifetime = 0 + +; The path for which the cookie is valid. +; http://php.net/session.cookie-path +;session.cookie_path = / + +; The domain for which the cookie is valid. +; http://php.net/session.cookie-domain +;session.cookie_domain = + +; http://php.net/session.cookie-secure +; session.cookie_secure = On + +; Whether or not to add the httpOnly flag to the cookie, which makes it +; inaccessible to browser scripting languages such as JavaScript. +; http://php.net/session.cookie-httponly +session.cookie_httponly = Off + +; Add SameSite attribute to cookie to help mitigate Cross-Site Request Forgery (CSRF/XSRF) +; Current valid values are "Strict", "Lax" or "None". When using "None", +; make sure to include the quotes, as `none` is interpreted like `false` in ini files. +; https://tools.ietf.org/html/draft-west-first-party-cookies-07 +; session.cookie_samesite = + +; Set to {nocache,private,public,} to determine HTTP caching aspects +; or leave this empty to avoid sending anti-caching headers. +; http://php.net/session.cache-limiter +;session.cache_limiter = nocache + +; Document expires after n minutes. +; http://php.net/session.cache-expire +;session.cache_expire = 180 + +; trans sid support is disabled by default. +; Use of trans sid may risk your users' security. +; Use this option with caution. +; - User may send URL contains active session ID +; to other person via. email/irc/etc. +; - URL that contains active session ID may be stored +; in publicly accessible computer. +; - User may access your site with the same session ID +; always using URL stored in browser's history or bookmarks. +; http://php.net/session.use-trans-sid +;session.use_trans_sid = 0 + +; The URL rewriter will look for URLs in a defined set of HTML tags. +;
is special; if you include them here, the rewriter will +; add a hidden field with the info which is otherwise appended +; to URLs. tag's action attribute URL will not be modified +; unless it is specified. +; Note that all valid entries require a "=", even if no value follows. +; Default Value: "a=href,area=href,frame=src,form=" +; Development Value: "a=href,area=href,frame=src,form=" +; Production Value: "a=href,area=href,frame=src,form=" +; http://php.net/url-rewriter.tags +;session.trans_sid_tags = "a=href,area=href,frame=src,form=" + +; URL rewriter does not rewrite absolute URLs by default. +; To enable rewrites for absolute paths, target hosts must be specified +; at RUNTIME. i.e. use ini_set() +; tags is special. PHP will check action attribute's URL regardless +; of session.trans_sid_tags setting. +; If no host is defined, HTTP_HOST will be used for allowed host. +; Example value: php.net,www.php.net,wiki.php.net +; Use "," for multiple hosts. No spaces are allowed. +; Default Value: "" +; Development Value: "" +; Production Value: "" +;session.trans_sid_hosts="" + +; Set session ID character length. This value could be between 22 to 256. +; Shorter length than default is supported only for compatibility reason. +; Users should use 32 or more chars. +; http://php.net/session.sid-length +; Default Value: 32 +; Development Value: 26 +; Production Value: 26 +session.sid_length = 64 + +; Define how many bits are stored in each character when converting +; the binary hash data to something readable. +; Possible values: +; 4 (4 bits: 0-9, a-f) +; 5 (5 bits: 0-9, a-v) +; 6 (6 bits: 0-9, a-z, A-Z, "-", ",") +; Default Value: 4 +; Development Value: 5 +; Production Value: 5 +; http://php.net/session.hash-bits-per-character +session.sid_bits_per_character = 6 + +; Define the hash algorithm used to generate the session IDs. +; Possible values: +; '0' MD5 (128 bits) +; '1' SHA-1 (160 bits) +; It is also possible to specify any of the algorithms provided by the hash +; extension (if it is available), like sha512 or whirlpool. +session.hash_function = 1 + +; Define how many bits are stored in each character when converting +; the binary hash data to something readable. +; Possible values: +; 4 (4 bits: 0-9, a-f) +; 5 (5 bits: 0-9, a-v) +; 6 (6 bits: 0-9, a-z, A-Z, "-", ",") +; Default Value: 4 +; Development Value: 5 +; Production Value: 5 +session.hash_bits_per_character = 6 + +; Enable upload progress tracking in $_SESSION +; Default Value: On +; Development Value: On +; Production Value: On +; http://php.net/session.upload-progress.enabled +;session.upload_progress.enabled = On + +; Cleanup the progress information as soon as all POST data has been read +; (i.e. upload completed). +; Default Value: On +; Development Value: On +; Production Value: On +; http://php.net/session.upload-progress.cleanup +;session.upload_progress.cleanup = 1 + +; A prefix used for the upload progress key in $_SESSION +; Default Value: "upload_progress_" +; Development Value: "upload_progress_" +; Production Value: "upload_progress_" +; http://php.net/session.upload-progress.prefix +;session.upload_progress.prefix = "upload_progress_" + +; The index name (concatenated with the prefix) in $_SESSION +; containing the upload progress information +; Default Value: "PHP_SESSION_UPLOAD_PROGRESS" +; Development Value: "PHP_SESSION_UPLOAD_PROGRESS" +; Production Value: "PHP_SESSION_UPLOAD_PROGRESS" +; http://php.net/session.upload-progress.name +;session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS" + +; How frequently the upload progress should be updated. +; Given either in percentages (per-file), or in bytes +; Default Value: "1%" +; Development Value: "1%" +; Production Value: "1%" +; http://php.net/session.upload-progress.freq +;session.upload_progress.freq = "1%" + +; The minimum delay between updates, in seconds +; Default Value: 1 +; Development Value: 1 +; Production Value: 1 +; http://php.net/session.upload-progress.min-freq +;session.upload_progress.min_freq = "1" + +; Only write session data when session data is changed. Enabled by default. +; http://php.net/session.lazy-write +;session.lazy_write = On +session.lazy_write = Off diff --git a/root/stuff-to-keep/conf.d/99_soap.ini b/root/stuff-to-keep/conf.d/99_soap.ini new file mode 100644 index 0000000..c048b3f --- /dev/null +++ b/root/stuff-to-keep/conf.d/99_soap.ini @@ -0,0 +1,16 @@ +[soap] +; Enables or disables WSDL caching feature. +; http://php.net/soap.wsdl-cache-enabled +soap.wsdl_cache_enabled=1 + +; Sets the directory name where SOAP extension will put cache files. +; http://php.net/soap.wsdl-cache-dir +soap.wsdl_cache_dir="/tmp" + +; (time to live) Sets the number of second while cached file will be used +; instead of original one. +; http://php.net/soap.wsdl-cache-ttl +soap.wsdl_cache_ttl=86400 + +; Sets the size of the cache limit. (Max. number of WSDL files to cache) +soap.wsdl_cache_limit = 5 diff --git a/root/stuff-to-keep/conf.d/99_sqlite3.ini b/root/stuff-to-keep/conf.d/99_sqlite3.ini new file mode 100644 index 0000000..1965589 --- /dev/null +++ b/root/stuff-to-keep/conf.d/99_sqlite3.ini @@ -0,0 +1,13 @@ +[sqlite3] +; Directory pointing to SQLite3 extensions +; http://php.net/sqlite3.extension-dir +;sqlite3.extension_dir = + +; SQLite defensive mode flag (only available from SQLite 3.26+) +; When the defensive flag is enabled, language features that allow ordinary +; SQL to deliberately corrupt the database file are disabled. This forbids +; writing directly to the schema, shadow tables (eg. FTS data tables), or +; the sqlite_dbpage virtual table. +; https://www.sqlite.org/c3ref/c_dbconfig_defensive.html +; (for older SQLite versions, this flag has no use) +;sqlite3.defensive = 1 diff --git a/root/stuff-to-keep/conf.d/99_sysvshm.ini b/root/stuff-to-keep/conf.d/99_sysvshm.ini new file mode 100644 index 0000000..03da3ab --- /dev/null +++ b/root/stuff-to-keep/conf.d/99_sysvshm.ini @@ -0,0 +1,3 @@ +[sysvshm] +; A default size of the shared memory segment +;sysvshm.init_mem = 10000 diff --git a/root/stuff-to-keep/conf.d/99_tidy.ini b/root/stuff-to-keep/conf.d/99_tidy.ini new file mode 100644 index 0000000..90c5f13 --- /dev/null +++ b/root/stuff-to-keep/conf.d/99_tidy.ini @@ -0,0 +1,10 @@ +[Tidy] +; The path to a default tidy configuration file to use when using tidy +; http://php.net/tidy.default-config +;tidy.default_config = /usr/local/lib/php/default.tcfg + +; Should tidy clean and repair output automatically? +; WARNING: Do not use this option if you are generating non-html content +; such as dynamic images +; http://php.net/tidy.clean-output +tidy.clean_output = Off diff --git a/root/stuff-to-keep/conf.d/imagick.ini b/root/stuff-to-keep/conf.d/imagick.ini new file mode 100644 index 0000000..76225ec --- /dev/null +++ b/root/stuff-to-keep/conf.d/imagick.ini @@ -0,0 +1 @@ +extension=imagick diff --git a/root/stuff-to-keep/dummy-default-mta b/root/stuff-to-keep/dummy-default-mta new file mode 100644 index 0000000..5e5fdb1 --- /dev/null +++ b/root/stuff-to-keep/dummy-default-mta @@ -0,0 +1,11 @@ +Section: misc +Priority: optional +Standards-Version: 3.9.2 +Package: dummy-default-mta +Version: 0.0.1 +Maintainer: Darren 'Tadgy' Austin +Recommends: bsd-mailx +Provides: default-mta +Architecture: all +Description: A dummy package to provide the 'default-mta' package + This is a dummy package. diff --git a/root/stuff-to-keep/dummy-default-mta_0.0.1_all.deb b/root/stuff-to-keep/dummy-default-mta_0.0.1_all.deb new file mode 100644 index 0000000..7467f38 Binary files /dev/null and b/root/stuff-to-keep/dummy-default-mta_0.0.1_all.deb differ diff --git a/root/stuff-to-keep/php-fpm.conf b/root/stuff-to-keep/php-fpm.conf new file mode 100644 index 0000000..f0b273f --- /dev/null +++ b/root/stuff-to-keep/php-fpm.conf @@ -0,0 +1,143 @@ +;;;;;;;;;;;;;;;;;;;;; +; FPM Configuration ; +;;;;;;;;;;;;;;;;;;;;; + +; All relative paths in this configuration file are relative to PHP's install +; prefix (/usr). This prefix can be dynamically changed by using the +; '-p' argument from the command line. + +;;;;;;;;;;;;;;;;;; +; Global Options ; +;;;;;;;;;;;;;;;;;; + +[global] +; Pid file +; Note: the default prefix is /var +; Default Value: none +pid = run/php-fpm.pid + +; Error log file +; If it's set to "syslog", log is sent to syslogd instead of being written +; into a local file. +; Note: the default prefix is /var +; Default Value: log/php-fpm.log +error_log = syslog + +; syslog_facility is used to specify what type of program is logging the +; message. This lets syslogd specify that messages from different facilities +; will be handled differently. +; See syslog(3) for possible values (ex daemon equiv LOG_DAEMON) +; Default Value: daemon +syslog.facility = local2 + +; syslog_ident is prepended to every message. If you have multiple FPM +; instances running on the same server, you can change the default value +; which must suit common needs. +; Default Value: php-fpm +syslog.ident = php-fpm + +; Log level +; Possible Values: alert, error, warning, notice, debug +; Default Value: notice +log_level = notice + +; Log limit on number of characters in the single line (log entry). If the +; line is over the limit, it is wrapped on multiple lines. The limit is for +; all logged characters including message prefix and suffix if present. However +; the new line character does not count into it as it is present only when +; logging to a file descriptor. It means the new line character is not present +; when logging to syslog. +; Default Value: 1024 +;log_limit = 4096 + +; Log buffering specifies if the log line is buffered which means that the +; line is written in a single write operation. If the value is false, then the +; data is written directly into the file descriptor. It is an experimental +; option that can potentionaly improve logging performance and memory usage +; for some heavy logging scenarios. This option is ignored if logging to syslog +; as it has to be always buffered. +; Default value: yes +;log_buffering = no + +; If this number of child processes exit with SIGSEGV or SIGBUS within the time +; interval set by emergency_restart_interval then FPM will restart. A value +; of '0' means 'Off'. +; Default Value: 0 +emergency_restart_threshold = 5 + +; Interval of time used by emergency_restart_interval to determine when +; a graceful restart will be initiated. This can be useful to work around +; accidental corruptions in an accelerator's shared memory. +; Available Units: s(econds), m(inutes), h(ours), or d(ays) +; Default Unit: seconds +; Default Value: 0 +emergency_restart_interval = 10 + +; Time limit for child processes to wait for a reaction on signals from master. +; Available units: s(econds), m(inutes), h(ours), or d(ays) +; Default Unit: seconds +; Default Value: 0 +;process_control_timeout = 0 + +; The maximum number of processes FPM will fork. This has been designed to control +; the global number of processes when using dynamic PM within a lot of pools. +; Use it with caution. +; Note: A value of 0 indicates no limit +; Default Value: 0 +process.max = 16 + +; Specify the nice(2) priority to apply to the master process (only if set) +; The value can vary from -19 (highest priority) to 20 (lowest priority) +; Note: - It will only work if the FPM master process is launched as root +; - The pool process will inherit the master process priority +; unless specified otherwise +; Default Value: no set +process.priority = 0 + +; Send FPM to background. Set to 'no' to keep FPM in foreground for debugging. +; Default Value: yes +;daemonize = yes + +; Set open file descriptor rlimit for the master process. +; Default Value: system defined value +;rlimit_files = 1024 + +; Set max core size rlimit for the master process. +; Possible Values: 'unlimited' or an integer greater or equal to 0 +; Default Value: system defined value +;rlimit_core = 0 + +; Specify the event mechanism FPM will use. The following is available: +; - select (any POSIX os) +; - poll (any POSIX os) +; - epoll (linux >= 2.5.44) +; - kqueue (FreeBSD >= 4.1, OpenBSD >= 2.9, NetBSD >= 2.0) +; - /dev/poll (Solaris >= 7) +; - port (Solaris >= 10) +; Default Value: not set (auto detection) +;events.mechanism = epoll + +; When FPM is built with systemd integration, specify the interval, +; in seconds, between health report notification to systemd. +; Set to 0 to disable. +; Available Units: s(econds), m(inutes), h(ours) +; Default Unit: seconds +; Default value: 10 +;systemd_interval = 10 + +;;;;;;;;;;;;;;;;;;;; +; Pool Definitions ; +;;;;;;;;;;;;;;;;;;;; + +; Multiple pools of child processes may be started with different listening +; ports and different management options. The name of the pool will be +; used in logs and stats. There is no limitation on the number of pools which +; FPM can handle. Your system will tell you anyway :) + +; Include one or more files. If glob(3) exists, it is used to include a bunch of +; files from a glob(3) pattern. This directive can be used everywhere in the +; file. +; Relative path can also be used. They will be prefixed by: +; - the global prefix if it's been set (-p argument) +; - /usr otherwise +include=/etc/php83/php-fpm.d/*.conf diff --git a/root/stuff-to-keep/php-fpm.d/www.conf b/root/stuff-to-keep/php-fpm.d/www.conf new file mode 100644 index 0000000..dfc4cef --- /dev/null +++ b/root/stuff-to-keep/php-fpm.d/www.conf @@ -0,0 +1,424 @@ +; Start a new pool named 'www'. +; the variable $pool can be used in any directive and will be replaced by the +; pool name ('www' here) +[www] + +; Per pool prefix +; It only applies on the following directives: +; - 'access.log' +; - 'slowlog' +; - 'listen' (unixsocket) +; - 'chroot' +; - 'chdir' +; - 'php_values' +; - 'php_admin_values' +; When not set, the global prefix (or /usr) applies instead. +; Note: This directive can also be relative to the global prefix. +; Default Value: none +;prefix = /path/to/pools/$pool + +; Unix user/group of processes +; Note: The user is mandatory. If the group is not set, the default user's group +; will be used. +user = nobody +group = nobody + +; The address on which to accept FastCGI requests. +; Valid syntaxes are: +; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on +; a specific port; +; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on +; a specific port; +; 'port' - to listen on a TCP socket to all addresses +; (IPv6 and IPv4-mapped) on a specific port; +; '/path/to/unix/socket' - to listen on a unix socket. +; Note: This value is mandatory. +;listen = 127.0.0.1:9000 +listen = /run/php-fpm83/php-fpm.sock + +; Set listen(2) backlog. +; Default Value: 511 (-1 on FreeBSD and OpenBSD) +;listen.backlog = 511 + +; Set permissions for unix socket, if one is used. In Linux, read/write +; permissions must be set in order to allow connections from a web server. Many +; BSD-derived systems allow connections regardless of permissions. +; Default Values: user and group are set as the running user +; mode is set to 0660 +listen.owner = nobody +listen.group = apache +listen.mode = 0660 +; When POSIX Access Control Lists are supported you can set them using +; these options, value is a comma separated list of user/group names. +; When set, listen.owner and listen.group are ignored +;listen.acl_users = +;listen.acl_groups = + +; List of addresses (IPv4/IPv6) of FastCGI clients which are allowed to connect. +; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original +; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address +; must be separated by a comma. If this value is left blank, connections will be +; accepted from any ip address. +; Default Value: any +; listen.allowed_clients = 127.0.0.1 + +; Specify the nice(2) priority to apply to the pool processes (only if set) +; The value can vary from -19 (highest priority) to 20 (lower priority) +; Note: - It will only work if the FPM master process is launched as root +; - The pool processes will inherit the master process priority +; unless it specified otherwise +; Default Value: no set +process.priority = 0 + +; Set the process dumpable flag (PR_SET_DUMPABLE prctl) even if the process user +; or group is differrent than the master process user. It allows to create process +; core dump and ptrace the process for the pool user. +; Default Value: no +; process.dumpable = yes + +; Choose how the process manager will control the number of child processes. +; Possible Values: +; static - a fixed number (pm.max_children) of child processes; +; dynamic - the number of child processes are set dynamically based on the +; following directives. With this process management, there will be +; always at least 1 children. +; pm.max_children - the maximum number of children that can +; be alive at the same time. +; pm.start_servers - the number of children created on startup. +; pm.min_spare_servers - the minimum number of children in 'idle' +; state (waiting to process). If the number +; of 'idle' processes is less than this +; number then some children will be created. +; pm.max_spare_servers - the maximum number of children in 'idle' +; state (waiting to process). If the number +; of 'idle' processes is greater than this +; number then some children will be killed. +; ondemand - no children are created at startup. Children will be forked when +; new requests will connect. The following parameter are used: +; pm.max_children - the maximum number of children that +; can be alive at the same time. +; pm.process_idle_timeout - The number of seconds after which +; an idle process will be killed. +; Note: This value is mandatory. +pm = dynamic + +; The number of child processes to be created when pm is set to 'static' and the +; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'. +; This value sets the limit on the number of simultaneous requests that will be +; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. +; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP +; CGI. The below defaults are based on a server without much resources. Don't +; forget to tweak pm.* to fit your needs. +; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand' +; Note: This value is mandatory. +pm.max_children = 8 + +; The number of child processes created on startup. +; Note: Used only when pm is set to 'dynamic' +; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 +pm.start_servers = 2 + +; The desired minimum number of idle server processes. +; Note: Used only when pm is set to 'dynamic' +; Note: Mandatory when pm is set to 'dynamic' +pm.min_spare_servers = 2 + +; The desired maximum number of idle server processes. +; Note: Used only when pm is set to 'dynamic' +; Note: Mandatory when pm is set to 'dynamic' +pm.max_spare_servers = 4 + +; The number of seconds after which an idle process will be killed. +; Note: Used only when pm is set to 'ondemand' +; Default Value: 10s +;pm.process_idle_timeout = 10s; + +; The number of requests each child process should execute before respawning. +; This can be useful to work around memory leaks in 3rd party libraries. For +; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS. +; Default Value: 0 +pm.max_requests = 5000 + +; The URI to view the FPM status page. If this value is not set, no URI will be +; recognized as a status page. It shows the following informations: +; pool - the name of the pool; +; process manager - static, dynamic or ondemand; +; start time - the date and time FPM has started; +; start since - number of seconds since FPM has started; +; accepted conn - the number of request accepted by the pool; +; listen queue - the number of request in the queue of pending +; connections (see backlog in listen(2)); +; max listen queue - the maximum number of requests in the queue +; of pending connections since FPM has started; +; listen queue len - the size of the socket queue of pending connections; +; idle processes - the number of idle processes; +; active processes - the number of active processes; +; total processes - the number of idle + active processes; +; max active processes - the maximum number of active processes since FPM +; has started; +; max children reached - number of times, the process limit has been reached, +; when pm tries to start more children (works only for +; pm 'dynamic' and 'ondemand'); +; Value are updated in real time. +; Example output: +; pool: www +; process manager: static +; start time: 01/Jul/2011:17:53:49 +0200 +; start since: 62636 +; accepted conn: 190460 +; listen queue: 0 +; max listen queue: 1 +; listen queue len: 42 +; idle processes: 4 +; active processes: 11 +; total processes: 15 +; max active processes: 12 +; max children reached: 0 +; +; By default the status page output is formatted as text/plain. Passing either +; 'html', 'xml' or 'json' in the query string will return the corresponding +; output syntax. Example: +; http://www.foo.bar/status +; http://www.foo.bar/status?json +; http://www.foo.bar/status?html +; http://www.foo.bar/status?xml +; +; By default the status page only outputs short status. Passing 'full' in the +; query string will also return status for each pool process. +; Example: +; http://www.foo.bar/status?full +; http://www.foo.bar/status?json&full +; http://www.foo.bar/status?html&full +; http://www.foo.bar/status?xml&full +; The Full status returns for each process: +; pid - the PID of the process; +; state - the state of the process (Idle, Running, ...); +; start time - the date and time the process has started; +; start since - the number of seconds since the process has started; +; requests - the number of requests the process has served; +; request duration - the duration in µs of the requests; +; request method - the request method (GET, POST, ...); +; request URI - the request URI with the query string; +; content length - the content length of the request (only with POST); +; user - the user (PHP_AUTH_USER) (or '-' if not set); +; script - the main script called (or '-' if not set); +; last request cpu - the %cpu the last request consumed +; it's always 0 if the process is not in Idle state +; because CPU calculation is done when the request +; processing has terminated; +; last request memory - the max amount of memory the last request consumed +; it's always 0 if the process is not in Idle state +; because memory calculation is done when the request +; processing has terminated; +; If the process is in Idle state, then informations are related to the +; last request the process has served. Otherwise informations are related to +; the current request being served. +; Example output: +; ************************ +; pid: 31330 +; state: Running +; start time: 01/Jul/2011:17:53:49 +0200 +; start since: 63087 +; requests: 12808 +; request duration: 1250261 +; request method: GET +; request URI: /test_mem.php?N=10000 +; content length: 0 +; user: - +; script: /home/fat/web/docs/php/test_mem.php +; last request cpu: 0.00 +; last request memory: 0 +; +; Note: There is a real-time FPM status monitoring sample web page available +; It's available in: /usr/share/fpm/status.html +; +; Note: The value must start with a leading slash (/). The value can be +; anything, but it may not be a good idea to use the .php extension or it +; may conflict with a real PHP file. +; Default Value: not set +;pm.status_path = /status + +; The ping URI to call the monitoring page of FPM. If this value is not set, no +; URI will be recognized as a ping page. This could be used to test from outside +; that FPM is alive and responding, or to +; - create a graph of FPM availability (rrd or such); +; - remove a server from a group if it is not responding (load balancing); +; - trigger alerts for the operating team (24/7). +; Note: The value must start with a leading slash (/). The value can be +; anything, but it may not be a good idea to use the .php extension or it +; may conflict with a real PHP file. +; Default Value: not set +;ping.path = /ping + +; This directive may be used to customize the response of a ping request. The +; response is formatted as text/plain with a 200 response code. +; Default Value: pong +;ping.response = pong + +; The access log file +; Default: not set +;access.log = log/$pool.access.log + +; The access log format. +; The following syntax is allowed +; %%: the '%' character +; %C: %CPU used by the request +; it can accept the following format: +; - %{user}C for user CPU only +; - %{system}C for system CPU only +; - %{total}C for user + system CPU (default) +; %d: time taken to serve the request +; it can accept the following format: +; - %{seconds}d (default) +; - %{miliseconds}d +; - %{mili}d +; - %{microseconds}d +; - %{micro}d +; %e: an environment variable (same as $_ENV or $_SERVER) +; it must be associated with embraces to specify the name of the env +; variable. Some exemples: +; - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e +; - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e +; %f: script filename +; %l: content-length of the request (for POST request only) +; %m: request method +; %M: peak of memory allocated by PHP +; it can accept the following format: +; - %{bytes}M (default) +; - %{kilobytes}M +; - %{kilo}M +; - %{megabytes}M +; - %{mega}M +; %n: pool name +; %o: output header +; it must be associated with embraces to specify the name of the header: +; - %{Content-Type}o +; - %{X-Powered-By}o +; - %{Transfert-Encoding}o +; - .... +; %p: PID of the child that serviced the request +; %P: PID of the parent of the child that serviced the request +; %q: the query string +; %Q: the '?' character if query string exists +; %r: the request URI (without the query string, see %q and %Q) +; %R: remote IP address +; %s: status (response code) +; %t: server time the request was received +; it can accept a strftime(3) format: +; %d/%b/%Y:%H:%M:%S %z (default) +; The strftime(3) format must be encapsuled in a %{}t tag +; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t +; %T: time the log has been written (the request has finished) +; it can accept a strftime(3) format: +; %d/%b/%Y:%H:%M:%S %z (default) +; The strftime(3) format must be encapsuled in a %{}t tag +; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t +; %u: remote user +; +; Default: "%R - %u %t \"%m %r\" %s" +;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%" + +; The log file for slow requests +; Default Value: not set +; Note: slowlog is mandatory if request_slowlog_timeout is set +;slowlog = log/$pool.log.slow + +; The timeout for serving a single request after which a PHP backtrace will be +; dumped to the 'slowlog' file. A value of '0s' means 'off'. +; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) +; Default Value: 0 +;request_slowlog_timeout = 0 + +; Depth of slow log stack trace. +; Default Value: 20 +;request_slowlog_trace_depth = 20 + +; The timeout for serving a single request after which the worker process will +; be killed. This option should be used when the 'max_execution_time' ini option +; does not stop script execution for some reason. A value of '0' means 'off'. +; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) +; Default Value: 0 +request_terminate_timeout = 60 + +; Set open file descriptor rlimit. +; Default Value: system defined value +;rlimit_files = 1024 + +; Set max core size rlimit. +; Possible Values: 'unlimited' or an integer greater or equal to 0 +; Default Value: system defined value +;rlimit_core = 0 + +; Chroot to this directory at the start. This value must be defined as an +; absolute path. When this value is not set, chroot is not used. +; Note: you can prefix with '$prefix' to chroot to the pool prefix or one +; of its subdirectories. If the pool prefix is not set, the global prefix +; will be used instead. +; Note: chrooting is a great security feature and should be used whenever +; possible. However, all PHP paths will be relative to the chroot +; (error_log, sessions.save_path, ...). +; Default Value: not set +;chroot = + +; Chdir to this directory at the start. +; Note: relative path can be used. +; Default Value: current directory or / when chroot +;chdir = /var/www + +; Redirect worker stdout and stderr into main error log. If not set, stdout and +; stderr will be redirected to /dev/null according to FastCGI specs. +; Note: on highloaded environement, this can cause some delay in the page +; process time (several ms). +; Default Value: no +;catch_workers_output = yes + +; Clear environment in FPM workers +; Prevents arbitrary environment variables from reaching FPM worker processes +; by clearing the environment in workers before env vars specified in this +; pool configuration are added. +; Setting to "no" will make all environment variables available to PHP code +; via getenv(), $_ENV and $_SERVER. +; Default Value: yes +;clear_env = no + +; Limits the extensions of the main script FPM will allow to parse. This can +; prevent configuration mistakes on the web server side. You should only limit +; FPM to .php extensions to prevent malicious users to use other extensions to +; execute php code. +; Note: set an empty value to allow all extensions. +; Default Value: .php +security.limit_extensions = .php .phar .phtml + +; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from +; the current environment. +; Default Value: clean env +;env[HOSTNAME] = $HOSTNAME +;env[PATH] = /usr/local/bin:/usr/bin:/bin +;env[TMP] = /tmp +;env[TMPDIR] = /tmp +;env[TEMP] = /tmp + +; Additional php.ini defines, specific to this pool of workers. These settings +; overwrite the values previously defined in the php.ini. The directives are the +; same as the PHP SAPI: +; php_value/php_flag - you can set classic ini defines which can +; be overwritten from PHP call 'ini_set'. +; php_admin_value/php_admin_flag - these directives won't be overwritten by +; PHP call 'ini_set' +; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no. + +; Defining 'extension' will load the corresponding shared extension from +; extension_dir. Defining 'disable_functions' or 'disable_classes' will not +; overwrite previously defined php.ini values, but will append the new value +; instead. + +; Note: path INI options can be relative and will be expanded with the prefix +; (pool, global or /usr) + +; Default Value: nothing is defined by default except the values in php.ini and +; specified at startup with the -d argument +;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com +;php_flag[display_errors] = off +;php_admin_value[error_log] = /var/log/fpm-php.www.log +;php_admin_flag[log_errors] = on +;php_admin_value[memory_limit] = 32M diff --git a/root/stuff-to-keep/php.ini b/root/stuff-to-keep/php.ini new file mode 100644 index 0000000..b81394b --- /dev/null +++ b/root/stuff-to-keep/php.ini @@ -0,0 +1,844 @@ +[PHP] +;;;;;;;;;;;;;;;;;;;; +; php.ini Options ; +;;;;;;;;;;;;;;;;;;;; +; Name for user-defined php.ini (.htaccess) files. Default is ".user.ini" +; To disable this feature set this option to an empty value +;user_ini.filename = ".user.ini" + +; TTL for user-defined php.ini files (time-to-live) in seconds. Default is 300 seconds (5 minutes) +;user_ini.cache_ttl = 300 + +;;;;;;;;;;;;;;;;;;;; +; Language Options ; +;;;;;;;;;;;;;;;;;;;; +; Enable the PHP scripting language engine under Apache. +; http://php.net/engine +engine = On + +; This directive determines whether or not PHP will recognize code between +; tags as PHP source which should be processed as such. It is +; generally recommended that should be used and that this feature +; should be disabled, as enabling it may result in issues when generating XML +; documents, however this remains supported for backward compatibility reasons. +; Note that this directive does not control the would work. +; http://php.net/syntax-highlighting +;highlight.string = #DD0000 +;highlight.comment = #FF9900 +;highlight.keyword = #007700 +;highlight.default = #0000BB +;highlight.html = #000000 + +; If enabled, the request will be allowed to complete even if the user aborts +; the request. Consider enabling it if executing long requests, which may end up +; being interrupted by the user or a browser timing out. PHP's default behavior +; is to disable this feature. +; http://php.net/ignore-user-abort +;ignore_user_abort = On + +; Determines the size of the realpath cache to be used by PHP. This value should +; be increased on systems where PHP opens many files to reflect the quantity of +; the file operations performed. +; Note: if open_basedir is set, the cache is disabled +; http://php.net/realpath-cache-size +;realpath_cache_size = 4096k + +; Duration of time, in seconds for which to cache realpath information for a given +; file or directory. For systems with rarely changing files, consider increasing this +; value. +; http://php.net/realpath-cache-ttl +;realpath_cache_ttl = 120 + +; Enables or disables the circular reference collector. +; http://php.net/zend.enable-gc +zend.enable_gc = On + +; If enabled, scripts may be written in encodings that are incompatible with +; the scanner. CP936, Big5, CP949 and Shift_JIS are the examples of such +; encodings. To use this feature, mbstring extension must be enabled. +; Default: Off +;zend.multibyte = Off + +; Allows to set the default encoding for the scripts. This value will be used +; unless "declare(encoding=...)" directive appears at the top of the script. +; Only affects if zend.multibyte is set. +; Default: "" +;zend.script_encoding = + +; Allows to include or exclude arguments from stack traces generated for exceptions. +; In production, it is recommended to turn this setting on to prohibit the output +; of sensitive information in stack traces +; Default: Off +zend.exception_ignore_args = On + +;;;;;;;;;;;;;;;;; +; Miscellaneous ; +;;;;;;;;;;;;;;;;; +; Decides whether PHP may expose the fact that it is installed on the server +; (e.g. by adding its signature to the Web server header). It is no security +; threat in any way, but it makes it possible to determine whether you use PHP +; on your server or not. +; http://php.net/expose-php +expose_php = Off + +;;;;;;;;;;;;;;;;;;; +; Resource Limits ; +;;;;;;;;;;;;;;;;;;; +; Maximum execution time of each script, in seconds +; http://php.net/max-execution-time +; Note: This directive is hardcoded to 0 for the CLI SAPI +max_execution_time = 45 + +; Maximum amount of time each script may spend parsing request data. It's a good +; idea to limit this time on productions servers in order to eliminate unexpectedly +; long running scripts. +; Note: This directive is hardcoded to -1 for the CLI SAPI +; Default Value: -1 (Unlimited) +; Development Value: 60 (60 seconds) +; Production Value: 60 (60 seconds) +; http://php.net/max-input-time +max_input_time = 30 + +; Maximum input variable nesting level +; http://php.net/max-input-nesting-level +;max_input_nesting_level = 64 + +; How many GET/POST/COOKIE input variables may be accepted +;max_input_vars = 1000 + +; Maximum amount of memory a script may consume +; http://php.net/memory-limit +memory_limit = 1073741824 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Error handling and logging ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; This directive informs PHP of which errors, warnings and notices you would like +; it to take action for. The recommended way of setting values for this +; directive is through the use of the error level constants and bitwise +; operators. The error level constants are below here for convenience as well as +; some common settings and their meanings. +; By default, PHP is set to take action on all errors, notices and warnings EXCEPT +; those related to E_NOTICE and E_STRICT, which together cover best practices and +; recommended coding standards in PHP. For performance reasons, this is the +; recommend error reporting setting. Your production server shouldn't be wasting +; resources complaining about best practices and coding standards. That's what +; development servers and development settings are for. +; Note: The php.ini-development file has this setting as E_ALL. This +; means it pretty much reports everything which is exactly what you want during +; development and early testing. +; +; Error Level Constants: +; E_ALL - All errors and warnings (includes E_STRICT as of PHP 5.4.0) +; E_ERROR - fatal run-time errors +; E_RECOVERABLE_ERROR - almost fatal run-time errors +; E_WARNING - run-time warnings (non-fatal errors) +; E_PARSE - compile-time parse errors +; E_NOTICE - run-time notices (these are warnings which often result +; from a bug in your code, but it's possible that it was +; intentional (e.g., using an uninitialized variable and +; relying on the fact it is automatically initialized to an +; empty string) +; E_STRICT - run-time notices, enable to have PHP suggest changes +; to your code which will ensure the best interoperability +; and forward compatibility of your code +; E_CORE_ERROR - fatal errors that occur during PHP's initial startup +; E_CORE_WARNING - warnings (non-fatal errors) that occur during PHP's +; initial startup +; E_COMPILE_ERROR - fatal compile-time errors +; E_COMPILE_WARNING - compile-time warnings (non-fatal errors) +; E_USER_ERROR - user-generated error message +; E_USER_WARNING - user-generated warning message +; E_USER_NOTICE - user-generated notice message +; E_DEPRECATED - warn about code that will not work in future versions +; of PHP +; E_USER_DEPRECATED - user-generated deprecation warnings +; +; Common Values: +; E_ALL (Show all errors, warnings and notices including coding standards.) +; E_ALL & ~E_NOTICE (Show all errors, except for notices) +; E_ALL & ~E_NOTICE & ~E_STRICT (Show all errors, except for notices and coding standards warnings.) +; E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR (Show only errors) +; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED +; Development Value: E_ALL +; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT +; http://php.net/error-reporting +error_reporting = ~E_DEPRECATED | ~E_USER_DEPRECATED | E_ERROR | E_RECOVERABLE_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR + +; This directive controls whether or not and where PHP will output errors, +; notices and warnings too. Error output is very useful during development, but +; it could be very dangerous in production environments. Depending on the code +; which is triggering the error, sensitive information could potentially leak +; out of your application such as database usernames and passwords or worse. +; For production environments, we recommend logging errors rather than +; sending them to STDOUT. +; Possible Values: +; Off = Do not display any errors +; stderr = Display errors to STDERR (affects only CGI/CLI binaries!) +; On or stdout = Display errors to STDOUT +; Default Value: On +; Development Value: On +; Production Value: Off +; http://php.net/display-errors +display_errors = On + +; The display of errors which occur during PHP's startup sequence are handled +; separately from display_errors. PHP's default behavior is to suppress those +; errors from clients. Turning the display of startup errors on can be useful in +; debugging configuration problems. We strongly recommend you +; set this to 'off' for production servers. +; Default Value: Off +; Development Value: On +; Production Value: Off +; http://php.net/display-startup-errors +display_startup_errors = On + +; Besides displaying errors, PHP can also log errors to locations such as a +; server-specific log, STDERR, or a location specified by the error_log +; directive found below. While errors should not be displayed on productions +; servers they should still be monitored and logging is a great way to do that. +; Default Value: Off +; Development Value: On +; Production Value: On +; http://php.net/log-errors +log_errors = On + +; Set maximum length of log_errors. In error_log information about the source is +; added. The default is 1024 and 0 allows to not apply any maximum length at all. +; http://php.net/log-errors-max-len +log_errors_max_len = 1024 + +; Do not log repeated messages. Repeated errors must occur in same file on same +; line unless ignore_repeated_source is set true. +; http://php.net/ignore-repeated-errors +ignore_repeated_errors = Off + +; Ignore source of message when ignoring repeated messages. When this setting +; is On you will not log errors with repeated messages from different files or +; source lines. +; http://php.net/ignore-repeated-source +ignore_repeated_source = Off + +; If this parameter is set to Off, then memory leaks will not be shown (on +; stdout or in the log). This is only effective in a debug compile, and if +; error reporting includes E_WARNING in the allowed list +; http://php.net/report-memleaks +report_memleaks = On + +; This setting is on by default. +;report_zend_debug = 0 + +; Store the last error/warning message in $php_errormsg (boolean). Setting this value +; to On can assist in debugging and is appropriate for development servers. It should +; however be disabled on production servers. +; This directive is DEPRECATED. +; Default Value: Off +; Development Value: Off +; Production Value: Off +; http://php.net/track-errors +;track_errors = Off + +; Turn off normal error reporting and emit XML-RPC error XML +; http://php.net/xmlrpc-errors +;xmlrpc_errors = 0 + +; An XML-RPC faultCode +;xmlrpc_error_number = 0 + +; When PHP displays or logs an error, it has the capability of formatting the +; error message as HTML for easier reading. This directive controls whether +; the error message is formatted as HTML or not. +; Note: This directive is hardcoded to Off for the CLI SAPI +; http://php.net/html-errors +;html_errors = On + +; If html_errors is set to On *and* docref_root is not empty, then PHP +; produces clickable error messages that direct to a page describing the error +; or function causing the error in detail. +; You can download a copy of the PHP manual from http://php.net/docs +; and change docref_root to the base URL of your local copy including the +; leading '/'. You must also specify the file extension being used including +; the dot. PHP's default behavior is to leave these settings empty, in which +; case no links to documentation are generated. +; Note: Never use this feature for production boxes. +; http://php.net/docref-root +; Examples +;docref_root = "/phpmanual/" + +; http://php.net/docref-ext +;docref_ext = .html + +; String to output before an error message. PHP's default behavior is to leave +; this setting blank. +; http://php.net/error-prepend-string +; Example: +;error_prepend_string = "" + +; String to output after an error message. PHP's default behavior is to leave +; this setting blank. +; http://php.net/error-append-string +; Example: +;error_append_string = "" + +; Log errors to specified file. PHP's default behavior is to leave this value +; empty. +; http://php.net/error-log +; Example: +;error_log = php_errors.log +; Log errors to syslog (Event Log on Windows). +error_log = syslog + +; The syslog ident is a string which is prepended to every message logged +; to syslog. Only used when error_log is set to syslog. +syslog.ident = php + +; The syslog facility is used to specify what type of program is logging +; the message. Only used when error_log is set to syslog. +syslog.facility = local2 + +; Set this to disable filtering control characters (the default). +; Some loggers only accept NVT-ASCII, others accept anything that's not +; control characters. If your logger accepts everything, then no filtering +; is needed at all. +; Allowed values are: +; ascii (all printable ASCII characters and NL) +; no-ctrl (all characters except control characters) +; all (all characters) +; raw (like "all", but messages are not split at newlines) +; http://php.net/syslog.filter +syslog.filter = ascii + +;windows.show_crt_warning +; Default value: 0 +; Development value: 0 +; Production value: 0 + +;;;;;;;;;;;;;;;;; +; Data Handling ; +;;;;;;;;;;;;;;;;; +; The separator used in PHP generated URLs to separate arguments. +; PHP's default setting is "&". +; http://php.net/arg-separator.output +; Example: +;arg_separator.output = "&" + +; List of separator(s) used by PHP to parse input URLs into variables. +; PHP's default setting is "&". +; NOTE: Every character in this directive is considered as separator! +; http://php.net/arg-separator.input +; Example: +;arg_separator.input = ";&" + +; This directive determines which super global arrays are registered when PHP +; starts up. G,P,C,E & S are abbreviations for the following respective super +; globals: GET, POST, COOKIE, ENV and SERVER. There is a performance penalty +; paid for the registration of these arrays and because ENV is not as commonly +; used as the others, ENV is not recommended on productions servers. You +; can still get access to the environment variables through getenv() should you +; need to. +; Default Value: "EGPCS" +; Development Value: "GPCS" +; Production Value: "GPCS"; +; http://php.net/variables-order +variables_order = "GPCS" + +; This directive determines which super global data (G,P & C) should be +; registered into the super global array REQUEST. If so, it also determines +; the order in which that data is registered. The values for this directive +; are specified in the same manner as the variables_order directive, +; EXCEPT one. Leaving this value empty will cause PHP to use the value set +; in the variables_order directive. It does not mean it will leave the super +; globals array REQUEST empty. +; Default Value: None +; Development Value: "GP" +; Production Value: "GP" +; http://php.net/request-order +request_order = "GP" + +; This directive determines whether PHP registers $argv & $argc each time it +; runs. $argv contains an array of all the arguments passed to PHP when a script +; is invoked. $argc contains an integer representing the number of arguments +; that were passed when the script was invoked. These arrays are extremely +; useful when running scripts from the command line. When this directive is +; enabled, registering these variables consumes CPU cycles and memory each time +; a script is executed. For performance reasons, this feature should be disabled +; on production servers. +; Note: This directive is hardcoded to On for the CLI SAPI +; Default Value: On +; Development Value: Off +; Production Value: Off +; http://php.net/register-argc-argv +register_argc_argv = Off + +; When enabled, the ENV, REQUEST and SERVER variables are created when they're +; first used (Just In Time) instead of when the script starts. If these +; variables are not used within a script, having this directive on will result +; in a performance gain. The PHP directive register_argc_argv must be disabled +; for this directive to have any effect. +; http://php.net/auto-globals-jit +auto_globals_jit = On + +; Whether PHP will read the POST data. +; This option is enabled by default. +; Most likely, you won't want to disable this option globally. It causes $_POST +; and $_FILES to always be empty; the only way you will be able to read the +; POST data will be through the php://input stream wrapper. This can be useful +; to proxy requests or to process the POST data in a memory efficient fashion. +; http://php.net/enable-post-data-reading +;enable_post_data_reading = Off + +; Maximum size of POST data that PHP will accept. +; Its value may be 0 to disable the limit. It is ignored if POST data reading +; is disabled through enable_post_data_reading. +; http://php.net/post-max-size +post_max_size = 8M + +; Automatically add files before PHP document. +; http://php.net/auto-prepend-file +auto_prepend_file = + +; Automatically add files after PHP document. +; http://php.net/auto-append-file +auto_append_file = + +; By default, PHP will output a media type using the Content-Type header. To +; disable this, simply set it to be empty. +; PHP's built-in default media type is set to text/html. +; http://php.net/default-mimetype +default_mimetype = "text/html" + +; PHP's default character set is set to UTF-8. +; http://php.net/default-charset +default_charset = "UTF-8" + +; PHP internal character encoding is set to empty. +; If empty, default_charset is used. +; http://php.net/internal-encoding +;internal_encoding = + +; PHP input character encoding is set to empty. +; If empty, default_charset is used. +; http://php.net/input-encoding +;input_encoding = + +; PHP output character encoding is set to empty. +; If empty, default_charset is used. +; See also output_buffer. +; http://php.net/output-encoding +;output_encoding = + +;;;;;;;;;;;;;;;;;;;;;;;;; +; Paths and Directories ; +;;;;;;;;;;;;;;;;;;;;;;;;; +; PHP's default setting for include_path is ".;/path/to/php/pear" +; http://php.net/include-path +;include_path = ".:/php/includes" + +; The root of the PHP pages, used only if nonempty. +; if PHP was not compiled with FORCE_REDIRECT, you SHOULD set doc_root +; if you are running php as a CGI under any web server (other than IIS) +; see documentation for security issues. The alternate is to use the +; cgi.force_redirect configuration below +; http://php.net/doc-root +;doc_root = + +; The directory under which PHP opens the script using /~username used only +; if nonempty. +; http://php.net/user-dir +;user_dir = + +; Directory in which the loadable extensions (modules) reside. +; http://php.net/extension-dir +;extension_dir = "./" + +; Directory where the temporary files should be placed. +; Defaults to the system default (see sys_get_temp_dir) +;sys_temp_dir = "/tmp" + +; Whether or not to enable the dl() function. The dl() function does NOT work +; properly in multithreaded servers, such as IIS or Zeus, and is automatically +; disabled on them. +; http://php.net/enable-dl +enable_dl = Off + +; cgi.force_redirect is necessary to provide security running PHP as a CGI under +; most web servers. Left undefined, PHP turns this on by default. You can +; turn it off here AT YOUR OWN RISK +; **You CAN safely turn this off for IIS, in fact, you MUST.** +; http://php.net/cgi.force-redirect +;cgi.force_redirect = 1 + +; if cgi.nph is enabled it will force cgi to always sent Status: 200 with +; every request. PHP's default behavior is to disable this feature. +;cgi.nph = 1 + +; if cgi.force_redirect is turned on, and you are not running under Apache or Netscape +; (iPlanet) web servers, you MAY need to set an environment variable name that PHP +; will look for to know it is OK to continue execution. Setting this variable MAY +; cause security issues, KNOW WHAT YOU ARE DOING FIRST. +; http://php.net/cgi.redirect-status-env +;cgi.redirect_status_env = + +; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's +; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok +; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting +; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting +; of zero causes PHP to behave as before. Default is 1. You should fix your scripts +; to use SCRIPT_FILENAME rather than PATH_TRANSLATED. +; http://php.net/cgi.fix-pathinfo +;cgi.fix_pathinfo=1 + +; if cgi.discard_path is enabled, the PHP CGI binary can safely be placed outside +; of the web tree and people will not be able to circumvent .htaccess security. +;cgi.discard_path=1 + +; FastCGI under IIS supports the ability to impersonate +; security tokens of the calling client. This allows IIS to define the +; security context that the request runs under. mod_fastcgi under Apache +; does not currently support this feature (03/17/2002) +; Set to 1 if running under IIS. Default is zero. +; http://php.net/fastcgi.impersonate +;fastcgi.impersonate = 1 + +; Disable logging through FastCGI connection. PHP's default behavior is to enable +; this feature. +;fastcgi.logging = 0 + +; cgi.rfc2616_headers configuration option tells PHP what type of headers to +; use when sending HTTP response code. If set to 0, PHP sends Status: header that +; is supported by Apache. When this option is set to 1, PHP will send +; RFC2616 compliant header. +; Default is zero. +; http://php.net/cgi.rfc2616-headers +;cgi.rfc2616_headers = 0 + +; cgi.check_shebang_line controls whether CGI PHP checks for line starting with #! +; (shebang) at the top of the running script. This line might be needed if the +; script support running both as stand-alone script and via PHP CGI<. PHP in CGI +; mode skips this line and ignores its content if this directive is turned on. +; http://php.net/cgi.check-shebang-line +;cgi.check_shebang_line=1 + +;;;;;;;;;;;;;;;; +; File Uploads ; +;;;;;;;;;;;;;;;; +; Whether to allow HTTP file uploads. +; http://php.net/file-uploads +file_uploads = On + +; Temporary directory for HTTP uploaded files (will use system default if not +; specified). +; http://php.net/upload-tmp-dir +upload_tmp_dir = /var/lib/php/uploads + +; Maximum allowed size for uploaded files. +; http://php.net/upload-max-filesize +upload_max_filesize = 20M + +; Maximum number of files that can be uploaded via a single request +max_file_uploads = 20 + +;;;;;;;;;;;;;;;;;; +; Fopen wrappers ; +;;;;;;;;;;;;;;;;;; +; Whether to allow the treatment of URLs (like http:// or ftp://) as files. +; http://php.net/allow-url-fopen +allow_url_fopen = On + +; Whether to allow include/require to open URLs (like http:// or ftp://) as files. +; http://php.net/allow-url-include +allow_url_include = Off + +; Define the anonymous ftp password (your email address). PHP's default setting +; for this is empty. +; http://php.net/from +;from="john@doe.com" + +; Define the User-Agent string. PHP's default setting for this is empty. +; http://php.net/user-agent +;user_agent="PHP" + +; Default timeout for socket based streams (seconds) +; http://php.net/default-socket-timeout +default_socket_timeout = 60 + +; If your scripts have to deal with files from Macintosh systems, +; or you are running on a Mac and need to deal with files from +; unix or win32 systems, setting this flag will cause PHP to +; automatically detect the EOL character in those files so that +; fgets() and file() will work regardless of the source of the file. +; http://php.net/auto-detect-line-endings +;auto_detect_line_endings = Off + +[Assertion] +; Switch whether to compile assertions at all (to have no overhead at run-time) +; -1: Do not compile at all +; 0: Jump over assertion at run-time +; 1: Execute assertions +; Changing from or to a negative value is only possible in php.ini! (For turning assertions on and off at run-time, see assert.active, when zend.assertions = 1) +; Default Value: 1 +; Development Value: 1 +; Production Value: -1 +; http://php.net/zend.assertions +zend.assertions = -1 + +; Assert(expr); active by default. +; http://php.net/assert.active +;assert.active = On + +; Throw an AssertionError on failed assertions +; http://php.net/assert.exception +;assert.exception = On + +; Issue a PHP warning for each failed assertion. (Overridden by assert.exception if active) +; http://php.net/assert.warning +;assert.warning = On + +; Don't bail out by default. +; http://php.net/assert.bail +;assert.bail = Off + +; User-function to be called if an assertion fails. +; http://php.net/assert.callback +;assert.callback = 0 + +; Eval the expression with current error_reporting(). Set to true if you want +; error_reporting(0) around the eval(). +; http://php.net/assert.quiet-eval +;assert.quiet_eval = 0 + +[browscap] +; http://php.net/browscap +;browscap = extra/browscap.ini + +[CLI Server] +; Whether the CLI web server uses ANSI color coding in its terminal output. +cli_server.color = On + +[Date] +; Defines the default timezone used by the date functions +; http://php.net/date.timezone +date.timezone = UTC + +; http://php.net/date.default-latitude +;date.default_latitude = 31.7667 + +; http://php.net/date.default-longitude +;date.default_longitude = 35.2333 + +; http://php.net/date.sunrise-zenith +;date.sunrise_zenith = 90.583333 + +; http://php.net/date.sunset-zenith +;date.sunset_zenith = 90.583333 + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Built-In Module Settings ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +[COM] +; path to a file containing GUIDs, IIDs or filenames of files with TypeLibs +; http://php.net/com.typelib-file +;com.typelib_file = + +; allow Distributed-COM calls +; http://php.net/com.allow-dcom +;com.allow_dcom = true + +; autoregister constants of a component's typlib on com_load() +; http://php.net/com.autoregister-typelib +;com.autoregister_typelib = true + +; register constants casesensitive +; http://php.net/com.autoregister-casesensitive +;com.autoregister_casesensitive = false + +; show warnings on duplicate constant registrations +; http://php.net/com.autoregister-verbose +;com.autoregister_verbose = true + +; The default character set code-page to use when passing strings to and from COM objects. +; Default: system ANSI code page +;com.code_page= + +[filter] +; http://php.net/filter.default +;filter.default = unsafe_raw + +; http://php.net/filter.default-flags +;filter.default_flags = + +[mail function] +; You may supply arguments as well (default: "sendmail -t -i"). +; http://php.net/sendmail-path +;sendmail_path = "/usr/sbin/sendmail -f 'noreply@slackware.uk' -t" + +; Force the addition of the specified parameters to be passed as extra parameters +; to the sendmail binary. These parameters will always replace the value of +; the 5th parameter to mail(). +;mail.force_extra_parameters = + +; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename +mail.add_x_header = Off + +; The path to a log file that will log all mail() calls. Log entries include +; the full path of the script, line number, To address and headers. +;mail.log = +; Log mail to syslog (Event Log on Windows). +;mail.log = syslog + +[Pcre] +; PCRE library backtracking limit. +; http://php.net/pcre.backtrack-limit +;pcre.backtrack_limit=100000 + +; PCRE library recursion limit. +; Please note that if you set this value to a high number you may consume all +; the available process stack and eventually crash PHP (due to reaching the +; stack size limit imposed by the Operating System). +; http://php.net/pcre.recursion-limit +;pcre.recursion_limit=100000 + +; Enables or disables JIT compilation of patterns. This requires the PCRE +; library to be compiled with JIT support. +;pcre.jit=1 diff --git a/root/stuff-to-keep/pushover-alert.start b/root/stuff-to-keep/pushover-alert.start new file mode 100755 index 0000000..3b1f2ac --- /dev/null +++ b/root/stuff-to-keep/pushover-alert.start @@ -0,0 +1,4 @@ +#!/bin/bash + +# Alert that this host is up. +( sleep 30; [[ -x /opt/sbin/pushover-client ]] && /opt/sbin/pushover-client -p -1 -m "Boot up: ${HOSTNAME%%.*}" ) & diff --git a/root/stuff-to-keep/pushover-alert.stop b/root/stuff-to-keep/pushover-alert.stop new file mode 100755 index 0000000..ebfff6a --- /dev/null +++ b/root/stuff-to-keep/pushover-alert.stop @@ -0,0 +1,4 @@ +#!/bin/bash + +# Alert that this host is going down. +[[ -x /opt/sbin/pushover-client ]] && /opt/sbin/pushover-client -p -1 -m "Shut down: ${HOSTNAME%%.*}" & diff --git a/var/.gitignore b/var/.gitignore new file mode 100644 index 0000000..9ba0da3 --- /dev/null +++ b/var/.gitignore @@ -0,0 +1,11 @@ +/.updated +/backups/ +/cache/ +/local/ +/lock +/log/ +/mail/ +/opt/ +/run +/spool/ +/www/ diff --git a/var/lib/.gitignore b/var/lib/.gitignore new file mode 100644 index 0000000..f73ab66 --- /dev/null +++ b/var/lib/.gitignore @@ -0,0 +1,27 @@ +/apache2/ +/apt/ +/dbus/ +/dpkg/ +/ghostscript/ +/git/ +/libuuid/ +/logrotate/ +/man-db/ +/misc/ +/pam/ +/php/ +/private/ +/prometheus/ +/python/ +/samba/ +/sgml-base/ +/shells.state +/smartmontools/ +/snmp/ +/sudo/ +/systemd/ +/ucf/ +/vim/ +/wtmpdb/ +/xfonts/ +/xml-core/ diff --git a/var/lib/terraform-http-backend/.gitkeepdir b/var/lib/terraform-http-backend/.gitkeepdir new file mode 100644 index 0000000..e69de29 diff --git a/var/tmp/.gitignore b/var/tmp/.gitignore new file mode 100644 index 0000000..24f9531 --- /dev/null +++ b/var/tmp/.gitignore @@ -0,0 +1,3 @@ +/* +!/.gitignore +!/php-uploads/ diff --git a/var/tmp/php-uploads/.gitignore b/var/tmp/php-uploads/.gitignore new file mode 100644 index 0000000..a68d087 --- /dev/null +++ b/var/tmp/php-uploads/.gitignore @@ -0,0 +1,2 @@ +/* +!/.gitignore