diff --git a/root/backup-openvpn-2025-10-06/openvpn/server/backup-old/ca.crt b/root/backup-openvpn-2025-10-06/openvpn/server/backup-old/ca.crt new file mode 100644 index 0000000000..12fab8279f --- /dev/null +++ b/root/backup-openvpn-2025-10-06/openvpn/server/backup-old/ca.crt @@ -0,0 +1,27 @@ + +-----BEGIN CERTIFICATE----- +MIIEVjCCAj6gAwIBAgIQY5WTY8JOcIJxWRi/w9ftVjANBgkqhkiG9w0BAQsFADBP +MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy +Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa +Fw0yNzAzMTIyMzU5NTlaMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF +bmNyeXB0MQswCQYDVQQDEwJFODB2MBAGByqGSM49AgEGBSuBBAAiA2IABNFl8l7c +S7QMApzSsvru6WyrOq44ofTUOTIzxULUzDMMNMchIJBwXOhiLxxxs0LXeb5GDcHb +R6EToMffgSZjO9SNHfY9gjMy9vQr5/WWOrQTZxh7az6NSNnq3u2ubT6HTKOB+DCB +9TAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMB +MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFI8NE6L2Ln7RUGwzGDhdWY4j +cpHKMB8GA1UdIwQYMBaAFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEB +BCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzATBgNVHSAE +DDAKMAgGBmeBDAECATAnBgNVHR8EIDAeMBygGqAYhhZodHRwOi8veDEuYy5sZW5j +ci5vcmcvMA0GCSqGSIb3DQEBCwUAA4ICAQBnE0hGINKsCYWi0Xx1ygxD5qihEjZ0 +RI3tTZz1wuATH3ZwYPIp97kWEayanD1j0cDhIYzy4CkDo2jB8D5t0a6zZWzlr98d +AQFNh8uKJkIHdLShy+nUyeZxc5bNeMp1Lu0gSzE4McqfmNMvIpeiwWSYO9w82Ob8 +otvXcO2JUYi3svHIWRm3+707DUbL51XMcY2iZdlCq4Wa9nbuk3WTU4gr6LY8MzVA +aDQG2+4U3eJ6qUF10bBnR1uuVyDYs9RhrwucRVnfuDj29CMLTsplM5f5wSV5hUpm +Uwp/vV7M4w4aGunt74koX71n4EdagCsL/Yk5+mAQU0+tue0JOfAV/R6t1k+Xk9s2 +HMQFeoxppfzAVC04FdG9M+AC2JWxmFSt6BCuh3CEey3fE52Qrj9YM75rtvIjsm/1 +Hl+u//Wqxnu1ZQ4jpa+VpuZiGOlWrqSP9eogdOhCGisnyewWJwRQOqK16wiGyZeR +xs/Bekw65vwSIaVkBruPiTfMOo0Zh4gVa8/qJgMbJbyrwwG97z/PRgmLKCDl8z3d +tA0Z7qq7fta0Gl24uyuB05dqI5J1LvAzKuWdIjT1tP8qCoxSE/xpix8hX2dt3h+/ +jujUgFPFZ0EVZ0xSyBNRF3MboGZnYXFUxpNjTWPKpagDHJQmqrAcDmWJnMsFY3jS +u1igv3OefnWjSQ== +-----END CERTIFICATE----- diff --git a/root/backup-openvpn-2025-10-06/openvpn/server/backup-old/ca.srl b/root/backup-openvpn-2025-10-06/openvpn/server/backup-old/ca.srl new file mode 100644 index 0000000000..b84bf098fc --- /dev/null +++ b/root/backup-openvpn-2025-10-06/openvpn/server/backup-old/ca.srl @@ -0,0 +1 @@ +469A1D60BE8EC6EE44EE81E5AB9A24B61EE78435 diff --git a/root/backup-openvpn-2025-10-06/openvpn/server/backup-old/server.crt b/root/backup-openvpn-2025-10-06/openvpn/server/backup-old/server.crt new file mode 100644 index 0000000000..71b04efa84 --- /dev/null +++ b/root/backup-openvpn-2025-10-06/openvpn/server/backup-old/server.crt @@ -0,0 +1,48 @@ +-----BEGIN CERTIFICATE----- +MIIDjDCCAxOgAwIBAgISBaCPzr8fq0guKTRH/42qANiyMAoGCCqGSM49BAMDMDIx +CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJF +ODAeFw0yNTEwMDUxODE2MDJaFw0yNjAxMDMxODE2MDFaMBsxGTAXBgNVBAMTEHZw +bi5jdXRlbWVsaS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATGjXe/B1Wn +r9hwoS4V/SxMjZ/Qx+rc4/WlexgH+66Zdegjz8zXmtaT93MtGzgNwffrk2mBM2hA +mgxXy882Rf/bo4ICHjCCAhowDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsG +AQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSTABfK7Ti6 +PkMxWyGqVs7R9P/TBzAfBgNVHSMEGDAWgBSPDROi9i5+0VBsMxg4XVmOI3KRyjAy +BggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly9lOC5pLmxlbmNyLm9y +Zy8wGwYDVR0RBBQwEoIQdnBuLmN1dGVtZWxpLmNvbTATBgNVHSAEDDAKMAgGBmeB +DAECATAtBgNVHR8EJjAkMCKgIKAehhxodHRwOi8vZTguYy5sZW5jci5vcmcvNTEu +Y3JsMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHYAyzj3FYl8hKFEX1vB3fvJbvKa +Wc1HCmkFhbDLFMMUWOcAAAGZtcwKrAAABAMARzBFAiEA7yYWyd69ruhzbs8ZCw7+ +b4QIlienyATFcwff4xORX6UCID4QAzDQpuwI23OMhGo1+86KuosHgwy+G9XIjj1r +UddAAHYAlpdkv1VYl633Q4doNwhCd+nwOtX2pPM2bkakPw/KqcYAAAGZtcwKzAAA +BAMARzBFAiEA/5t3AApTDxXCp/bJxn2Wr06vZM8LO0LwwZU4kiCUndcCIGQ65r6G +KvmXqhfg02PEwcFojo03NDrbw/7IgZaitpzTMAoGCCqGSM49BAMDA2cAMGQCME2k +UBz+sr0WJnAPZHzx7pxIg99SQVagGQQDPnUhciQeDiAf++dpm2slhzhdPj9vuwIw +aP8e5wJ6uz2an96g6o+h0h4hrcrJtYmzORZSGuCxGpywFa190l6Ck1I7WX5Z6CWX +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIEVjCCAj6gAwIBAgIQY5WTY8JOcIJxWRi/w9ftVjANBgkqhkiG9w0BAQsFADBP +MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy +Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa +Fw0yNzAzMTIyMzU5NTlaMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF +bmNyeXB0MQswCQYDVQQDEwJFODB2MBAGByqGSM49AgEGBSuBBAAiA2IABNFl8l7c +S7QMApzSsvru6WyrOq44ofTUOTIzxULUzDMMNMchIJBwXOhiLxxxs0LXeb5GDcHb +R6EToMffgSZjO9SNHfY9gjMy9vQr5/WWOrQTZxh7az6NSNnq3u2ubT6HTKOB+DCB +9TAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMB +MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFI8NE6L2Ln7RUGwzGDhdWY4j +cpHKMB8GA1UdIwQYMBaAFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEB +BCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzATBgNVHSAE +DDAKMAgGBmeBDAECATAnBgNVHR8EIDAeMBygGqAYhhZodHRwOi8veDEuYy5sZW5j +ci5vcmcvMA0GCSqGSIb3DQEBCwUAA4ICAQBnE0hGINKsCYWi0Xx1ygxD5qihEjZ0 +RI3tTZz1wuATH3ZwYPIp97kWEayanD1j0cDhIYzy4CkDo2jB8D5t0a6zZWzlr98d +AQFNh8uKJkIHdLShy+nUyeZxc5bNeMp1Lu0gSzE4McqfmNMvIpeiwWSYO9w82Ob8 +otvXcO2JUYi3svHIWRm3+707DUbL51XMcY2iZdlCq4Wa9nbuk3WTU4gr6LY8MzVA +aDQG2+4U3eJ6qUF10bBnR1uuVyDYs9RhrwucRVnfuDj29CMLTsplM5f5wSV5hUpm +Uwp/vV7M4w4aGunt74koX71n4EdagCsL/Yk5+mAQU0+tue0JOfAV/R6t1k+Xk9s2 +HMQFeoxppfzAVC04FdG9M+AC2JWxmFSt6BCuh3CEey3fE52Qrj9YM75rtvIjsm/1 +Hl+u//Wqxnu1ZQ4jpa+VpuZiGOlWrqSP9eogdOhCGisnyewWJwRQOqK16wiGyZeR +xs/Bekw65vwSIaVkBruPiTfMOo0Zh4gVa8/qJgMbJbyrwwG97z/PRgmLKCDl8z3d +tA0Z7qq7fta0Gl24uyuB05dqI5J1LvAzKuWdIjT1tP8qCoxSE/xpix8hX2dt3h+/ +jujUgFPFZ0EVZ0xSyBNRF3MboGZnYXFUxpNjTWPKpagDHJQmqrAcDmWJnMsFY3jS +u1igv3OefnWjSQ== +-----END CERTIFICATE----- diff --git a/root/backup-openvpn-2025-10-06/openvpn/server/backup-old/server.key b/root/backup-openvpn-2025-10-06/openvpn/server/backup-old/server.key new file mode 100644 index 0000000000..a8ef7038c8 --- /dev/null +++ b/root/backup-openvpn-2025-10-06/openvpn/server/backup-old/server.key @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIPPZ7Syd1F/ed42DRSegOQ8rLr/66oUHQdJ4FkfG8rlJoAoGCCqGSM49 +AwEHoUQDQgAExo13vwdVp6/YcKEuFf0sTI2f0Mfq3OP1pXsYB/uumXXoI8/M15rW +k/dzLRs4DcH365NpgTNoQJoMV8vPNkX/2w== +-----END EC PRIVATE KEY----- diff --git a/root/backup-openvpn-2025-10-06/openvpn/server/ca.crt b/root/backup-openvpn-2025-10-06/openvpn/server/ca.crt new file mode 100644 index 0000000000..3c4cba1f6d --- /dev/null +++ b/root/backup-openvpn-2025-10-06/openvpn/server/ca.crt @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIFrzCCA5egAwIBAgIUHWB3I2jCGo3mj9sazsfh2jEhWEUwDQYJKoZIhvcNAQEL +BQAwZzELMAkGA1UEBhMCREUxGzAZBgNVBAgMEkJhZGVuLVd1ZXJ0dGVtYmVyZzES +MBAGA1UEBwwJS2FybHNydWhlMREwDwYDVQQKDAhjdXRlbWVsaTEUMBIGA1UEAwwL +Y3V0ZW1lbGktQ0EwHhcNMjUxMDA1MTk0NTA0WhcNMzUxMDAzMTk0NTA0WjBnMQsw +CQYDVQQGEwJERTEbMBkGA1UECAwSQmFkZW4tV3VlcnR0ZW1iZXJnMRIwEAYDVQQH +DAlLYXJsc3J1aGUxETAPBgNVBAoMCGN1dGVtZWxpMRQwEgYDVQQDDAtjdXRlbWVs +aS1DQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALB3LVR4VTeqb8BN +oJkIuLZ4zD8EFPRV1pGXExKRSAx/g6m+IIYG/KaVCgVYlOF5DPC7g2yEdoMppRrd +xtgW41e2idKAw6dJBnrDTmcb/hEq+BEAy2ScZGXAZxIp0kBfjucjDPEy43DTwIy3 +TsnikS8aiplltRhWNN29RFlKnxqUoAjITsQYK3diCuZ3cji1V9vfo5ptcujY1Oy5 +jZ8PxmhVId2WnIGXwggqeQJwNGF9jXfF0Ov5aGgxY5tBFh8yPdpnPSXey4l+kg3B +3TNqJI98LTgViNucVHiYMGbnzv7Vn0AcJerISsJoim4IwcNIATW67jRusqM1t52R +KXcJUwVUhhCpJVFDhK6U1VbHomqnC+KEbFausOlc+G/flzbAcqu8FfV3ZQKe3qhS +oGjHe2M8kwOFFxi/xbQvXQjNdrL8lBS0XjOUXaQKtzzMCLr2EysaPlmRqq01RKZa +Cwg+Rol45T5TN07OS6ajPl/JVtgaXALx6l8BzgIH5+oF+lUGTi1l7pdqTsEbm8co +WoCl0LUjNrKy5Jg6HXDYZGKmX9u1JnNP3PX37gIu4Y6V5AIr/Sm64Y2ZGBgiAJYv +us3W0rTnBjlm399CJ4vorXbS5lygmFTUV7x4ob8xxz+HwzmrhN1jGcUjJbNjPbit +7GC+bzUQ/2TJ2tLi68bMuFzJ8qoDAgMBAAGjUzBRMB0GA1UdDgQWBBQpYKteJSe+ +O4ZgaGp2qjqlChwQXjAfBgNVHSMEGDAWgBQpYKteJSe+O4ZgaGp2qjqlChwQXjAP +BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQBilXrgYCHr4bhC0l5m +lCHj7V7nm5PUFoiJa8WuaNF14t1j7OdJ3Kx4xq7Vu8wD+3hTx+jrZ6Uw1753eQVX +mzB/UDyuCeP7EbqoWdh3zQj0NqBTm6BI+98BGpl6D2b3EG2XNFKpDb6JEAqrm+OB +iCqDT3HcI/djf7NmJrJ3Wk8nijLrzYvtYWaVRxu6wzxBBlhYxggiCjQ+6Uih3nYX +Jru7dO4hIPHtHOA39a1Cfcs5UQCy//vSQbeokMi1TH9WFYHO+Dci0naCOh9GWJeI +B9X+Q3NqdSyscZB5mNE3u9HjL9khrM6+eKTqFxp/DoJRn8/sq6ttF50YT+vx69LO +tv0JZXAQo8rdaIsO/pW4G1CQjtlwcIm3VyU8QOFi6F5i/xbwS/dEDSXxFEAzh2Mt +/h45jtXpzzRui8+g4dGW8kkvKlmSIH6QiWUIFiIj/CdDXoLuZaDSuXLRb06RSx9e +KJYVFia20uOAs+/F3KQc/hITCvIbXVtzj8j/XcilJcqGrI5Ge3DH11z0hWj+W9yW +vSEfgqoVucflY3wdijWjfI8zC4m5kaoWBQWdJJ2gXljlGkSIOo7lPUFPF9srIrdE +4ZndGOHpKj6af1ha9q4VrDUhVjYWq1lAHv1YIyLaDohhJW+iYkfqLKxyv4ymeRNV +3iLy3uGqXt9Us3Su6P4i0/U9OA== +-----END CERTIFICATE----- diff --git a/root/backup-openvpn-2025-10-06/openvpn/server/ca.key b/root/backup-openvpn-2025-10-06/openvpn/server/ca.key new file mode 100644 index 0000000000..5034e3d95f --- /dev/null +++ b/root/backup-openvpn-2025-10-06/openvpn/server/ca.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +BhqbyO9FaDlBLp6TBkdXWjVJegfd +-----END PRIVATE KEY----- diff --git a/root/backup-openvpn-2025-10-06/openvpn/server/ca.srl b/root/backup-openvpn-2025-10-06/openvpn/server/ca.srl new file mode 100644 index 0000000000..2d29d0bf12 --- /dev/null +++ b/root/backup-openvpn-2025-10-06/openvpn/server/ca.srl @@ -0,0 +1 @@ +7996B8D142923ACFC89F3B8510B2D4AD9B17F983 diff --git a/root/backup-openvpn-2025-10-06/openvpn/server/clients/arch.crt b/root/backup-openvpn-2025-10-06/openvpn/server/clients/arch.crt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/root/backup-openvpn-2025-10-06/openvpn/server/clients/arch.csr b/root/backup-openvpn-2025-10-06/openvpn/server/clients/arch.csr new file mode 100644 index 0000000000..3ef92bde7a --- /dev/null +++ b/root/backup-openvpn-2025-10-06/openvpn/server/clients/arch.csr @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICVDCCATwCAQAwDzENMAsGA1UEAwwEYXJjaDCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAOj+4UR6NJF+6NhsFfZ5r9eN3ny9+hiiv/UEgJVvEQOhpRV6 +x2E8LYiMYfdMCuVjgXwvG4lE9lHI0w+Mmjm+dhMtjwJdTD14SL2g7xuG9nD27Hby +CvdPqwnagPjwzMs518aIsh0lNgVVwdzQF6J/lP3KcFZ9jF6qwz3OHUXbrDRK7LY0 +YOQ63ntWUZ8HOHmnmfoKwhe2iMoMs5YRUEkSqagQY0pawg8IF7ks4Pu8MajRs/Ks +2tRgulBfRevPD6j4DEemkV+q4chfeJNMDeJoVGzOM3IBW16kUhOCKX8Z2w2Cvu/v +h73PbPNLNq2y37tNnLtKAVCp/CyANFJ0pZ0XOjkCAwEAAaAAMA0GCSqGSIb3DQEB +CwUAA4IBAQCt7w0W3cmL0IOTWtXAmn+wkuGWY1x3m57PhbkiKSHh4Tb1H69TrLwn +QnR3Phd0HEaR3HwSuBfodcGI38PnyrB0KGiQ87W5qZWvfMNWZxan/cmXpDzFwQ3A +UOBrzmJf8+jz9zOQNAChi+vuJf/46bWnP1P2Rq6AKMzFcm86CtjQWP8KrOIwovO8 +bvPHwrc/qKv3Z0TmF/gs4KRK4nLHgGd4VA3p2FVa2Aqb2AxQwvEaYITn3kMhT2Lp +4/BmWCnN9QmwXd4KHMTslOkm0l8HalnFQB+rkvDYRDf6frgDkY5dt8kSNGxz5fEp +Pk2Yt5TVyp7O3bXqFjyqVyTSd3owTZ1c +-----END CERTIFICATE REQUEST----- diff --git a/root/backup-openvpn-2025-10-06/openvpn/server/clients/arch.key b/root/backup-openvpn-2025-10-06/openvpn/server/clients/arch.key new file mode 100644 index 0000000000..4e731d26ae --- /dev/null +++ b/root/backup-openvpn-2025-10-06/openvpn/server/clients/arch.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDo/uFEejSRfujY +bBX2ea/Xjd58vfoYor/1BICVbxEDoaUVesdhPC2IjGH3TArlY4F8LxuJRPZRyNMP +jJo5vnYTLY8CXUw9eEi9oO8bhvZw9ux28gr3T6sJ2oD48MzLOdfGiLIdJTYFVcHc +0Beif5T9ynBWfYxeqsM9zh1F26w0Suy2NGDkOt57VlGfBzh5p5n6CsIXtojKDLOW +EVBJEqmoEGNKWsIPCBe5LOD7vDGo0bPyrNrUYLpQX0Xrzw+o+AxHppFfquHIX3iT +TA3iaFRszjNyAVtepFITgil/GdsNgr7v74e9z2zzSzatst+7TZy7SgFQqfwsgDRS +dKWdFzo5AgMBAAECggEAJ/u5T6WDCObU8XLW8AWg4eZEJHb7iKfBNjxQDpTRQCTI +rh90QKDxlWm11BjWE9hYG6X/3TYa6R0D7zqrKrafD5p1XKwDDddq8DPCZKBsASW2 +nZDaxecDjHzVPiMgmc1y1GyX2D2PACpfytNhAu9O86B+V7FS2doHCD+rMVZJvm07 +R1+s9nEPCt7ogZ5g2YFRHDN6UyaBW8QsbtfpIvNZTt3L7RNvWLemV4Uuk+0AVL29 +PoJ5KOgi9bEs2M+kylk9wKYpDkqN79EU7AUh0TBpgsKeroLFrze8j7gPy7encc09 +iZ6Faf6dWtcyAf269PXEtOgGC6kabwzWtGGrGBT2EwKBgQD7YJFbunCH8CjVw+os +zyg/2PlyBEGWpfu27WCz9en0OXhMz681dywsTs7d4BwS/JVExi9j0pLW+YUmfFej +PGrNgXW404WzHCQv6xCttc9E1xtfFrSuHUbmqTcYaX462XoX5O8ASO5k/H/b8h3k +kBSBAFs3zEfM9+3mVBvZZZTwxwKBgQDtR8Z/3NFq6Azj+LrzYYREI9qi6ASoVpZZ +RLJ6Rmx0sK7a7HPLO4XC/DT4CAw8ixG+R5hvSxIH8gts/9mhcDooxs6wUMoGLlS9 +B2DnUe9N0FrabmjozXiDHLQ36T6jAQqRd5ntABVSACMkWTsGPRBZGCP5IeLe7e7O +ZH9BeQ18/wKBgHMQ1hjF8+LV1Otc3aGbRdJMEIrXVeqOmfU3HY/i3i+z6tRGMO5p +WagCfwDjKBas1esASQsJhbuvxfpC6p7G9iCRxQBQmp/NHudsU1sgoPri+B2DuDsH +HcBR7u1WxLhNemzbl2dq+uzxA9n7LyHDrg8KybZ15Nv3FUfcck8GB7JbAoGBAIoq +62l1GfTYnvj401P5it1qy1tlI6Eqmm3s1MjizTC92XPdkCfdxywdVHLBrO5sRK66 +XgcgfaVmykR0TzP0d8layuxcfudOf0V7UHAig+iZ1O2wsSIu02f1hPOxvCmK566B +KH6bN88CCXSXCQm+8RAQQJJHqyYJAq/oUTm81Z/dAoGAb0xfGRw86gLiBsk6Ygyb +MU+1JKfcWllFZTfaBs6B0jfYyLeS3QrRUIxPRVumarbXAvsblDxCqGfjuiLhoyvi +wS41hkC2suGdp3wZ/yZQU7jHeuRc+Xv2AzzK+M8DkfhP6BjO7c0jiAKOXzKTRPf/ +rT6C5zF2vSThx0tQE1iB5VI= +-----END PRIVATE KEY----- diff --git a/root/backup-openvpn-2025-10-06/openvpn/server/clients/emy-laptop.crt b/root/backup-openvpn-2025-10-06/openvpn/server/clients/emy-laptop.crt new file mode 100644 index 0000000000..930311e96f --- /dev/null +++ b/root/backup-openvpn-2025-10-06/openvpn/server/clients/emy-laptop.crt @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEAzCCAesCFHmWuNFCkjrPyJ87hRCy1K2bF/mDMA0GCSqGSIb3DQEBCwUAMGcx +CzAJBgNVBAYTAkRFMRswGQYDVQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxEjAQBgNV +BAcMCUthcmxzcnVoZTERMA8GA1UECgwIY3V0ZW1lbGkxFDASBgNVBAMMC2N1dGVt +ZWxpLUNBMB4XDTI1MTAwNTE5NDUyMVoXDTI2MTAwNTE5NDUyMVowFTETMBEGA1UE +AwwKZW15LWxhcHRvcDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK0+ +NLS9tmwHuh7rRNhiSYnFtNT7x2paUmLHU4oFFb2goJw4NkdzBgKUGI60Tkal84zJ +ZVEcoEXB8PU2doDaiTBprjjEMqY4K3P3+mop6zDIB7U3ssYw/Nz2C3mSuQ81zrbT +l2o8fghoJvzOnnzehyIWG/LuoXzDZC/j4djePRq2qywjedPGPoU/YhsW/pyWTz76 +eANxBvkix2M7WWEAp4YYW4vrDQymWXev39MI7xMChBgHpe0jiW6bJsxt6pw6kXdp +1vR+5ARLHvMl6Rs9gatS3CHcEkPX4LRdRPboi8xiJ7D0fbkOSH5d+hERKCPId68s +SaWtUz8bpq/s0Iz4fPUCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAomnv8eskjl/P +ZGy97nMxyeqoASspP4/nhSnLpPhXmpnnWBDM2YQzzAU//ABoOfPE4WnmJCeH2ZGQ +TZ9nn5M1VpkR8fJtC6j7lnRb4pKNGqpcfipZhKDGwYIMiRncscUejA3S1xhskerV +K9MyMp+4KTT+tgawTeOeFimymk2CcUS/000szXLgsdA01RMJ3oZMzLJMEeIbY6CI +r6ULNgWgqyz36KDBOJxzHMzTYZUGTQblkSCJq3pFcK9Y5g7dpHbJ4VqyPbV8AJA7 +FW8C6aOuiCQoQhPrTZZP2+bhlsNtEAIhceatSPjdYZNUPiM44Qkw69fOm5IjglHT +gSV1bt8Ng8T7Fuds5bWFW6huza/Y1VcbCDdsLxCbu4A4FeTIB77vqBOo1/O3hRh1 +zhhQ+o6cEL+srJkao3U114XlHsrj5IfvH+epst3JeifH2FRvxJVu8qxy2tr4yFRO +8jvFSP69bwbIL2MMcKF/K0shD/tUmhesdLhHvKsoDi6qHu+YbFfdzJNsplzf2wTA +Itm83Dq0yAukmDslfTCUcq8XoSGRq4okqjHZBcvzXgBe9eA0D8blMqNd0oV+81hu +pJm7QOUYycZG0PRR+tp7lPASjVkEFpBEHTstnkobRwrHshGVVMj8TPpe61bt8gXJ +Q6TBXSSLcCP1zdIFu12jGK14hbHx+ew= +-----END CERTIFICATE----- diff --git a/root/backup-openvpn-2025-10-06/openvpn/server/clients/emy-laptop.csr b/root/backup-openvpn-2025-10-06/openvpn/server/clients/emy-laptop.csr new file mode 100644 index 0000000000..4ece227317 --- /dev/null +++ b/root/backup-openvpn-2025-10-06/openvpn/server/clients/emy-laptop.csr @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICWjCCAUICAQAwFTETMBEGA1UEAwwKZW15LWxhcHRvcDCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAK0+NLS9tmwHuh7rRNhiSYnFtNT7x2paUmLHU4oF +Fb2goJw4NkdzBgKUGI60Tkal84zJZVEcoEXB8PU2doDaiTBprjjEMqY4K3P3+mop +6zDIB7U3ssYw/Nz2C3mSuQ81zrbTl2o8fghoJvzOnnzehyIWG/LuoXzDZC/j4dje +PRq2qywjedPGPoU/YhsW/pyWTz76eANxBvkix2M7WWEAp4YYW4vrDQymWXev39MI +7xMChBgHpe0jiW6bJsxt6pw6kXdp1vR+5ARLHvMl6Rs9gatS3CHcEkPX4LRdRPbo +i8xiJ7D0fbkOSH5d+hERKCPId68sSaWtUz8bpq/s0Iz4fPUCAwEAAaAAMA0GCSqG +SIb3DQEBCwUAA4IBAQApu9ntmZSxGTAPQhANLYe5LbW0jtxLuiySHPN3TrR3Xi6q +wLyL3fUEfJHR3QK8SQ+2f54tNfWrRQl39UwWBma6J/hftK3ROWFDwiUvKazKg62N +xLvF4HfcEM0aE/HMKVnNgtfErmwXLr9LfNcyfhzMW0Gl4lpofQzYj0KP2SCfvMVt +DYK6jIfO/AuBg8DsK3s2HCD+UU8xFgVvq2RWuS2K148S2MWGEBiOHjLouQc4ohGv +TfaiXaTTGwEJsDHaaOCfLyvNN9D2fK/uIL2x6q3rpi+qXwOAKVFwrEKd5ne7LSBI +QpjTWj68ViQ9Ntxz7yyl+b9VGlP6kaCdGAYJBRpk +-----END CERTIFICATE REQUEST----- diff --git a/root/backup-openvpn-2025-10-06/openvpn/server/clients/emy-laptop.key b/root/backup-openvpn-2025-10-06/openvpn/server/clients/emy-laptop.key new file mode 100644 index 0000000000..e2466cea78 --- /dev/null +++ b/root/backup-openvpn-2025-10-06/openvpn/server/clients/emy-laptop.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCtPjS0vbZsB7oe +60TYYkmJxbTU+8dqWlJix1OKBRW9oKCcODZHcwYClBiOtE5GpfOMyWVRHKBFwfD1 +NnaA2okwaa44xDKmOCtz9/pqKeswyAe1N7LGMPzc9gt5krkPNc6205dqPH4IaCb8 +zp583ociFhvy7qF8w2Qv4+HY3j0atqssI3nTxj6FP2IbFv6clk8++ngDcQb5Isdj +O1lhAKeGGFuL6w0Mpll3r9/TCO8TAoQYB6XtI4lumybMbeqcOpF3adb0fuQESx7z +JekbPYGrUtwh3BJD1+C0XUT26IvMYiew9H25Dkh+XfoRESgjyHevLEmlrVM/G6av +7NCM+Hz1AgMBAAECggEAGLHrVXBNlqyrTUkAMVAhZ3A1TL7vOCvT3pzHPb9nz/Yb +rukcY6bzzl5J+d2d4tg5FXKH7L4F4qu4q1uuHMQKFkqaOSFOjv8mwoswuP1stzFs +V9qusy28fcrc6+GMW6yx4MHcrZod5RjjpdnWIbqezK8WINT/VAeOOn1jbkSPtUTk +lMODzlmcoDkwn0RuGO/l2R0f6c+njFLdHNpz81hf8i2qBIP4F453eBJNAvQOCrz9 +LkjfcsgcOLdUmrPme7P//f8LZJFkBQSwSLNM+Wf8SRUZKZcFmSLR6jpDLQoongfJ +A5R+nenJ3MvEQHerTSse6+J2e7rix5cmm30Ngud5aQKBgQDeWIw+F2QsDy2QL50V +67YpHM80g+VL3HSy0j38DYRiL3NsRCGFfSuxuKm009AH34dqtofAWo+hJQS7Nnkk +aahyC88gp18zpaynsaD2oNVpnc2Mm/lf3Q+egNAJymG+zVlQX86UDxFSyo4qBsiG +za3gumF/r1lRgIjJ4wOnLxLuQwKBgQDHdwU2wJB3XTFPd+pxjzmENUUMnIzYNvnI +gMdpxc1nTZynUJyEVwNsblsIfU1flrTsBWxyp0B2+vPwN0q7k3R7HH2Sae4uy+Id +qhndW75eEOF88EJpLQ9QQgQDPGJBICBhD/820e5HIOLpTKf/2qsqhZttHXojU94p +Ls3XNqDgZwKBgHlaSMjGyYSGkC6m3gyNxrEvqSOXbTl3TDYhK3V7ByrzjQKlOMp7 +o7JvACjShjMV2/nxP6xLgSLJaoinVXz7MdV0/opq7znoDZDFEP4qj/ACEaLRqkyZ +AaJX2bPOQoT53OpSMBR9GM5gATGM3Ds+3MzPzND8qjoidgYCIgdIWQOzAoGBAKpf +JRrxO/RYq4e/W4cH2Q7uGT5+cWc0/gGezbWw+JNmHYpkNmxrjkcNs7/6lx4wsfRv +ZYRBC7UVAUuLTtANUQ7e9PscdA+QomDILDOA64eZT6DR70e67zuUR60j5KDP+hgt ++8YtZiNnGapAibbmZhF58Zov9WU7e6Udj0BmLt+9AoGACO6ND2F5T7JXoY+0t3Rf +tTYQO/R2M7jj4+HhoBbk0bLQ4eYNzw6net/zMpTq7GPQqmtWmO7geVwOxswhNPq+ +1ynnqYCSo1eYjUkRSVQ5YJFlAM6wtwdYq/lEbZh0cn7RVfSNUb4lrRFtNCa7XZmE +PTVb/YZQ53URA/bNcxo0eM4= +-----END PRIVATE KEY----- diff --git a/root/backup-openvpn-2025-10-06/openvpn/server/clients/emy-laptop.ovpn b/root/backup-openvpn-2025-10-06/openvpn/server/clients/emy-laptop.ovpn new file mode 100644 index 0000000000..c95395d281 --- /dev/null +++ b/root/backup-openvpn-2025-10-06/openvpn/server/clients/emy-laptop.ovpn @@ -0,0 +1,102 @@ +client +dev tun +proto udp +remote vpn.cutemeli.com 1194 +resolv-retry infinite +nobind +persist-key +persist-tun +remote-cert-tls server +cipher AES-256-GCM +verb 3 + +-----BEGIN CERTIFICATE----- +MIIFrzCCA5egAwIBAgIUHWB3I2jCGo3mj9sazsfh2jEhWEUwDQYJKoZIhvcNAQEL +BQAwZzELMAkGA1UEBhMCREUxGzAZBgNVBAgMEkJhZGVuLVd1ZXJ0dGVtYmVyZzES +MBAGA1UEBwwJS2FybHNydWhlMREwDwYDVQQKDAhjdXRlbWVsaTEUMBIGA1UEAwwL +Y3V0ZW1lbGktQ0EwHhcNMjUxMDA1MTk0NTA0WhcNMzUxMDAzMTk0NTA0WjBnMQsw +CQYDVQQGEwJERTEbMBkGA1UECAwSQmFkZW4tV3VlcnR0ZW1iZXJnMRIwEAYDVQQH +DAlLYXJsc3J1aGUxETAPBgNVBAoMCGN1dGVtZWxpMRQwEgYDVQQDDAtjdXRlbWVs +aS1DQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALB3LVR4VTeqb8BN +oJkIuLZ4zD8EFPRV1pGXExKRSAx/g6m+IIYG/KaVCgVYlOF5DPC7g2yEdoMppRrd +xtgW41e2idKAw6dJBnrDTmcb/hEq+BEAy2ScZGXAZxIp0kBfjucjDPEy43DTwIy3 +TsnikS8aiplltRhWNN29RFlKnxqUoAjITsQYK3diCuZ3cji1V9vfo5ptcujY1Oy5 +jZ8PxmhVId2WnIGXwggqeQJwNGF9jXfF0Ov5aGgxY5tBFh8yPdpnPSXey4l+kg3B +3TNqJI98LTgViNucVHiYMGbnzv7Vn0AcJerISsJoim4IwcNIATW67jRusqM1t52R +KXcJUwVUhhCpJVFDhK6U1VbHomqnC+KEbFausOlc+G/flzbAcqu8FfV3ZQKe3qhS +oGjHe2M8kwOFFxi/xbQvXQjNdrL8lBS0XjOUXaQKtzzMCLr2EysaPlmRqq01RKZa +Cwg+Rol45T5TN07OS6ajPl/JVtgaXALx6l8BzgIH5+oF+lUGTi1l7pdqTsEbm8co +WoCl0LUjNrKy5Jg6HXDYZGKmX9u1JnNP3PX37gIu4Y6V5AIr/Sm64Y2ZGBgiAJYv +us3W0rTnBjlm399CJ4vorXbS5lygmFTUV7x4ob8xxz+HwzmrhN1jGcUjJbNjPbit +7GC+bzUQ/2TJ2tLi68bMuFzJ8qoDAgMBAAGjUzBRMB0GA1UdDgQWBBQpYKteJSe+ +O4ZgaGp2qjqlChwQXjAfBgNVHSMEGDAWgBQpYKteJSe+O4ZgaGp2qjqlChwQXjAP +BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQBilXrgYCHr4bhC0l5m +lCHj7V7nm5PUFoiJa8WuaNF14t1j7OdJ3Kx4xq7Vu8wD+3hTx+jrZ6Uw1753eQVX +mzB/UDyuCeP7EbqoWdh3zQj0NqBTm6BI+98BGpl6D2b3EG2XNFKpDb6JEAqrm+OB +iCqDT3HcI/djf7NmJrJ3Wk8nijLrzYvtYWaVRxu6wzxBBlhYxggiCjQ+6Uih3nYX +Jru7dO4hIPHtHOA39a1Cfcs5UQCy//vSQbeokMi1TH9WFYHO+Dci0naCOh9GWJeI +B9X+Q3NqdSyscZB5mNE3u9HjL9khrM6+eKTqFxp/DoJRn8/sq6ttF50YT+vx69LO +tv0JZXAQo8rdaIsO/pW4G1CQjtlwcIm3VyU8QOFi6F5i/xbwS/dEDSXxFEAzh2Mt +/h45jtXpzzRui8+g4dGW8kkvKlmSIH6QiWUIFiIj/CdDXoLuZaDSuXLRb06RSx9e +KJYVFia20uOAs+/F3KQc/hITCvIbXVtzj8j/XcilJcqGrI5Ge3DH11z0hWj+W9yW +vSEfgqoVucflY3wdijWjfI8zC4m5kaoWBQWdJJ2gXljlGkSIOo7lPUFPF9srIrdE +4ZndGOHpKj6af1ha9q4VrDUhVjYWq1lAHv1YIyLaDohhJW+iYkfqLKxyv4ymeRNV +3iLy3uGqXt9Us3Su6P4i0/U9OA== +-----END CERTIFICATE----- + + +-----BEGIN CERTIFICATE----- +MIIEAzCCAesCFHmWuNFCkjrPyJ87hRCy1K2bF/mDMA0GCSqGSIb3DQEBCwUAMGcx +CzAJBgNVBAYTAkRFMRswGQYDVQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxEjAQBgNV +BAcMCUthcmxzcnVoZTERMA8GA1UECgwIY3V0ZW1lbGkxFDASBgNVBAMMC2N1dGVt +ZWxpLUNBMB4XDTI1MTAwNTE5NDUyMVoXDTI2MTAwNTE5NDUyMVowFTETMBEGA1UE +AwwKZW15LWxhcHRvcDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK0+ +NLS9tmwHuh7rRNhiSYnFtNT7x2paUmLHU4oFFb2goJw4NkdzBgKUGI60Tkal84zJ +ZVEcoEXB8PU2doDaiTBprjjEMqY4K3P3+mop6zDIB7U3ssYw/Nz2C3mSuQ81zrbT +l2o8fghoJvzOnnzehyIWG/LuoXzDZC/j4djePRq2qywjedPGPoU/YhsW/pyWTz76 +eANxBvkix2M7WWEAp4YYW4vrDQymWXev39MI7xMChBgHpe0jiW6bJsxt6pw6kXdp +1vR+5ARLHvMl6Rs9gatS3CHcEkPX4LRdRPboi8xiJ7D0fbkOSH5d+hERKCPId68s +SaWtUz8bpq/s0Iz4fPUCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAomnv8eskjl/P +ZGy97nMxyeqoASspP4/nhSnLpPhXmpnnWBDM2YQzzAU//ABoOfPE4WnmJCeH2ZGQ +TZ9nn5M1VpkR8fJtC6j7lnRb4pKNGqpcfipZhKDGwYIMiRncscUejA3S1xhskerV +K9MyMp+4KTT+tgawTeOeFimymk2CcUS/000szXLgsdA01RMJ3oZMzLJMEeIbY6CI +r6ULNgWgqyz36KDBOJxzHMzTYZUGTQblkSCJq3pFcK9Y5g7dpHbJ4VqyPbV8AJA7 +FW8C6aOuiCQoQhPrTZZP2+bhlsNtEAIhceatSPjdYZNUPiM44Qkw69fOm5IjglHT +gSV1bt8Ng8T7Fuds5bWFW6huza/Y1VcbCDdsLxCbu4A4FeTIB77vqBOo1/O3hRh1 +zhhQ+o6cEL+srJkao3U114XlHsrj5IfvH+epst3JeifH2FRvxJVu8qxy2tr4yFRO +8jvFSP69bwbIL2MMcKF/K0shD/tUmhesdLhHvKsoDi6qHu+YbFfdzJNsplzf2wTA +Itm83Dq0yAukmDslfTCUcq8XoSGRq4okqjHZBcvzXgBe9eA0D8blMqNd0oV+81hu +pJm7QOUYycZG0PRR+tp7lPASjVkEFpBEHTstnkobRwrHshGVVMj8TPpe61bt8gXJ +Q6TBXSSLcCP1zdIFu12jGK14hbHx+ew= +-----END CERTIFICATE----- + + +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCtPjS0vbZsB7oe +60TYYkmJxbTU+8dqWlJix1OKBRW9oKCcODZHcwYClBiOtE5GpfOMyWVRHKBFwfD1 +NnaA2okwaa44xDKmOCtz9/pqKeswyAe1N7LGMPzc9gt5krkPNc6205dqPH4IaCb8 +zp583ociFhvy7qF8w2Qv4+HY3j0atqssI3nTxj6FP2IbFv6clk8++ngDcQb5Isdj +O1lhAKeGGFuL6w0Mpll3r9/TCO8TAoQYB6XtI4lumybMbeqcOpF3adb0fuQESx7z +JekbPYGrUtwh3BJD1+C0XUT26IvMYiew9H25Dkh+XfoRESgjyHevLEmlrVM/G6av +7NCM+Hz1AgMBAAECggEAGLHrVXBNlqyrTUkAMVAhZ3A1TL7vOCvT3pzHPb9nz/Yb +rukcY6bzzl5J+d2d4tg5FXKH7L4F4qu4q1uuHMQKFkqaOSFOjv8mwoswuP1stzFs +V9qusy28fcrc6+GMW6yx4MHcrZod5RjjpdnWIbqezK8WINT/VAeOOn1jbkSPtUTk +lMODzlmcoDkwn0RuGO/l2R0f6c+njFLdHNpz81hf8i2qBIP4F453eBJNAvQOCrz9 +LkjfcsgcOLdUmrPme7P//f8LZJFkBQSwSLNM+Wf8SRUZKZcFmSLR6jpDLQoongfJ +A5R+nenJ3MvEQHerTSse6+J2e7rix5cmm30Ngud5aQKBgQDeWIw+F2QsDy2QL50V +67YpHM80g+VL3HSy0j38DYRiL3NsRCGFfSuxuKm009AH34dqtofAWo+hJQS7Nnkk +aahyC88gp18zpaynsaD2oNVpnc2Mm/lf3Q+egNAJymG+zVlQX86UDxFSyo4qBsiG +za3gumF/r1lRgIjJ4wOnLxLuQwKBgQDHdwU2wJB3XTFPd+pxjzmENUUMnIzYNvnI +gMdpxc1nTZynUJyEVwNsblsIfU1flrTsBWxyp0B2+vPwN0q7k3R7HH2Sae4uy+Id +qhndW75eEOF88EJpLQ9QQgQDPGJBICBhD/820e5HIOLpTKf/2qsqhZttHXojU94p +Ls3XNqDgZwKBgHlaSMjGyYSGkC6m3gyNxrEvqSOXbTl3TDYhK3V7ByrzjQKlOMp7 +o7JvACjShjMV2/nxP6xLgSLJaoinVXz7MdV0/opq7znoDZDFEP4qj/ACEaLRqkyZ +AaJX2bPOQoT53OpSMBR9GM5gATGM3Ds+3MzPzND8qjoidgYCIgdIWQOzAoGBAKpf +JRrxO/RYq4e/W4cH2Q7uGT5+cWc0/gGezbWw+JNmHYpkNmxrjkcNs7/6lx4wsfRv +ZYRBC7UVAUuLTtANUQ7e9PscdA+QomDILDOA64eZT6DR70e67zuUR60j5KDP+hgt ++8YtZiNnGapAibbmZhF58Zov9WU7e6Udj0BmLt+9AoGACO6ND2F5T7JXoY+0t3Rf +tTYQO/R2M7jj4+HhoBbk0bLQ4eYNzw6net/zMpTq7GPQqmtWmO7geVwOxswhNPq+ +1ynnqYCSo1eYjUkRSVQ5YJFlAM6wtwdYq/lEbZh0cn7RVfSNUb4lrRFtNCa7XZmE +PTVb/YZQ53URA/bNcxo0eM4= +-----END PRIVATE KEY----- + diff --git a/root/backup-openvpn-2025-10-06/openvpn/server/ipp.txt b/root/backup-openvpn-2025-10-06/openvpn/server/ipp.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/root/backup-openvpn-2025-10-06/openvpn/server/server.conf b/root/backup-openvpn-2025-10-06/openvpn/server/server.conf new file mode 100644 index 0000000000..e597824a01 --- /dev/null +++ b/root/backup-openvpn-2025-10-06/openvpn/server/server.conf @@ -0,0 +1,30 @@ +port 443 +proto udp +dev tun + +ca /etc/openvpn/server/ca.crt +cert /etc/openvpn/server/server.crt +key /etc/openvpn/server/server.key +dh none +tls-crypt /etc/openvpn/server/ta.key + +topology subnet +server 10.10.0.0 255.255.255.0 + +ifconfig-pool-persist ipp.txt + +# Clients durchs VPN leiten +push "redirect-gateway def1 bypass-dhcp" +push "dhcp-option DNS 1.1.1.1" +push "dhcp-option DNS 8.8.8.8" + +keepalive 10 120 +cipher AES-256-GCM +user nobody +group nogroup +persist-key +persist-tun +verb 3 + +explicit-exit-notify 1 + diff --git a/root/backup-openvpn-2025-10-06/openvpn/server/server.crt b/root/backup-openvpn-2025-10-06/openvpn/server/server.crt new file mode 100644 index 0000000000..1d70fa2d13 --- /dev/null +++ b/root/backup-openvpn-2025-10-06/openvpn/server/server.crt @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIFCTCCAvECFHmWuNFCkjrPyJ87hRCy1K2bF/mCMA0GCSqGSIb3DQEBCwUAMGcx +CzAJBgNVBAYTAkRFMRswGQYDVQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxEjAQBgNV +BAcMCUthcmxzcnVoZTERMA8GA1UECgwIY3V0ZW1lbGkxFDASBgNVBAMMC2N1dGVt +ZWxpLUNBMB4XDTI1MTAwNTE5NDUxMloXDTI4MDEwODE5NDUxMlowGzEZMBcGA1UE +AwwQdnBuLmN1dGVtZWxpLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBAKLCeWvZl9hgbhWEx70NE6T2al5QlJ/5TQQc626lO9Oh9X4xwjtB1CDxATja +i8QQymQNtNti2uHVUG3XgPzmjZiQcvjgp7PB6yoD75B8fqn2i8wvabTCeISTtBkY +jyVTI18KY/3zJ7KvADl37xu8+ChUY+tcFmRaa7DNNAX4amFdyhgCBCb9g+Gitw+d +IBIwyQkZVwkjhh8JwNmz9LFY20WuJfVhODWBQX8BsbnoySLUhFlUENSCEGsICmsG +Rl0rzHSP6f17GAFXwMbpuxWJ4pK0943AsatDy3THfSW1FX/vYnUFgfTSY+eXzJ3G +CLUIDAmg48UjFY+JtM55hh2r6cM+AoZO7XHUXycQEhRzlT3yphlNY40arZZeGIV/ +lXc3exAGkEhRZygBi0dqb8hOXoB3sOiGGrd4d1X/gEnZJkdnQBWyR9pb7SJ42IPp +c3Y7zJ3RutShoKlp1RDlLeA+gSbgHv+147TPbq0LgC0AMoxaxOxrs4VqSExGB5Wl +APdti/byxphwH1S3RSQW44MBLgTtRFSFZjCBtkSGOd9KavxE4c5V6Bh/uZ+ikZEZ +nW3ZR2ku43oNX/FQ2gjN/KC1m/f9nO/Lp4np8Z0JayiyeoHw6LhIT4a9hQhzbKYK +BXrfXaxAxD8f1bTNDU7RjQqcCjnlDwR9IDodh9YNr8RuuWgjAgMBAAEwDQYJKoZI +hvcNAQELBQADggIBABzRE0Rl2P0Sr+jejmA7Aq3f5AvYchhfuf+4YSsKgmb32URT +c9ZgP0IX1w6pSnARfikyuYPjX2+S4Nz5J/ccv6WlWs3sfjVU1mcO1uhZ1IGh1ysu +b9MiPRDbUG1BkJoIiNZXoRaiQUFlMyDmOmD7u/YVde33xWKSw81Io6YgqNU2rnBc +DE8lJl+gSuegrtI+T0hRw9LZWNtE5acE8Hgw/900G5UEC3SmgZ1QuL2HpUCpajS7 +/KmfyjPEBir+j7xD/3VPdcID7ddwISESb7MyuwFYNO0cLqzKbLLnttp6wkwFfWfY +JuUzeSheBgV8Uf+2jBRItqz15jLLSMKiYUwLyx/qY2Zh6EEEWx18jRw1w36JopRx +45TsnopIHZqfT+05ngJv5fa2oeXvWHG3Q3AgysstJ3/355KOoiF9m/KCFwjrbUAs +pqfVrQ0+dEAe2WLz1KI//Ij/buK05/xQJHUK9zhIMTa91NFGhUGXxEkzQgiWNAxy +uaTAOTx6SWKIKdXHuHrwHXzdZHT9cAWtS2N9E4VXRGfTbzYjb96/n6DL3jP1U737 +5MOvQySBsD9aLN31GLGLWuuYVX9j/hRc4UgCQ0ulmagoeSaMcUMbOnCpKWceXMII +6o8eHGNQNu4SDI2U0365LYbJ14D0rOfJHTX8w9HNdrrX+8VMxRD8LTpKi5Sj +-----END CERTIFICATE----- diff --git a/root/backup-openvpn-2025-10-06/openvpn/server/server.csr b/root/backup-openvpn-2025-10-06/openvpn/server/server.csr new file mode 100644 index 0000000000..920b96ca15 --- /dev/null +++ b/root/backup-openvpn-2025-10-06/openvpn/server/server.csr @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIEYDCCAkgCAQAwGzEZMBcGA1UEAwwQdnBuLmN1dGVtZWxpLmNvbTCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAKLCeWvZl9hgbhWEx70NE6T2al5QlJ/5 +TQQc626lO9Oh9X4xwjtB1CDxATjai8QQymQNtNti2uHVUG3XgPzmjZiQcvjgp7PB +6yoD75B8fqn2i8wvabTCeISTtBkYjyVTI18KY/3zJ7KvADl37xu8+ChUY+tcFmRa +a7DNNAX4amFdyhgCBCb9g+Gitw+dIBIwyQkZVwkjhh8JwNmz9LFY20WuJfVhODWB +QX8BsbnoySLUhFlUENSCEGsICmsGRl0rzHSP6f17GAFXwMbpuxWJ4pK0943AsatD +y3THfSW1FX/vYnUFgfTSY+eXzJ3GCLUIDAmg48UjFY+JtM55hh2r6cM+AoZO7XHU +XycQEhRzlT3yphlNY40arZZeGIV/lXc3exAGkEhRZygBi0dqb8hOXoB3sOiGGrd4 +d1X/gEnZJkdnQBWyR9pb7SJ42IPpc3Y7zJ3RutShoKlp1RDlLeA+gSbgHv+147TP +bq0LgC0AMoxaxOxrs4VqSExGB5WlAPdti/byxphwH1S3RSQW44MBLgTtRFSFZjCB +tkSGOd9KavxE4c5V6Bh/uZ+ikZEZnW3ZR2ku43oNX/FQ2gjN/KC1m/f9nO/Lp4np +8Z0JayiyeoHw6LhIT4a9hQhzbKYKBXrfXaxAxD8f1bTNDU7RjQqcCjnlDwR9IDod +h9YNr8RuuWgjAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAgEAEo/rutNW17Kg1nzK +6rAbRoDfBEKTDh/2HshM0bmxP4uI3K0BMNZO8xm/ubSACK9cS45E/aOrf5R7E2JJ +rC/wNZygeT60u0ZvJoYIIcfqN/u5xEXSeicFdrkJYZfnPsY9xHzMlykvsf8zejCC +lwW9mFSOkzhw4KqsKHPNMSmNJ1bFFpDIUgUZbkislHbZR94xwuauGKgg7K87SI2D +6LR0w+Cdq2j7kumyuOT5sha0XWBMGejWASzUkL7eTlgEbVlmlmnLUpl1eall8kD9 +R/k1QRt1Q3BkNWGC4u2oo7jNaAII0VUMwQ/nHg60jC+Jy1A0fk644E/5PX1SIfhg +0cubYpyw2OvTaIGwuuWVGQi0RmMl7qDkcrRWSPGFNB7eooNh+VdHwjfUoYf+CIPu +XqE3fKZ1aCjTUOj0KNRv8TX2qYjfXFLGK2H7xzLc4dZOv7uhO4SzgFttDgdFHFYn +AFYp15j5lJ20b5wQY94XkKwJuxSxePyTC0xI21SNE4WiukB57IgHEv3dWf8Sep77 +zwAE0Z9se2jpm1jL8TpmIvpuQlxUGVWwrApqKHYPHdDk95M+ngCxU1Cs3E+IYCL6 +37tmAouG8hUXHWwxSCiwnQn8ON87xFzrB8etLkNZP8KqCJH5KT9u0nQ2isluW8mu +S17rCg8cF1uvimm125r9i1TmChk= +-----END CERTIFICATE REQUEST----- diff --git a/root/backup-openvpn-2025-10-06/openvpn/server/server.key b/root/backup-openvpn-2025-10-06/openvpn/server/server.key new file mode 100644 index 0000000000..e93b1505d9 --- /dev/null +++ b/root/backup-openvpn-2025-10-06/openvpn/server/server.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +t5P4bKIAhk7T5F/aa0t7EDKVdEOpqb8= +-----END PRIVATE KEY----- diff --git a/root/backup-openvpn-2025-10-06/openvpn/server/ta.key b/root/backup-openvpn-2025-10-06/openvpn/server/ta.key new file mode 100644 index 0000000000..3484258fab --- /dev/null +++ b/root/backup-openvpn-2025-10-06/openvpn/server/ta.key @@ -0,0 +1,21 @@ +# +# 2048 bit OpenVPN static key +# +-----BEGIN OpenVPN Static key V1----- +f49f89fbd5c3686a2298bb67510f0d45 +303fb9be418ff0caa897f57cf4dc04e2 +64a02ed2d49d61234a62ea0588bb8d24 +f5a7b445816c57cb0f7a9bd4f3a20f95 +e99be06e20034ced2441664d835f1c03 +d841c4cd4de17854efb545d65ce595f8 +cd83a19881eb2ff0dabc61a6ab2bae2a +177c900336b94a2f464cf9d2272a9ca8 +a7a0ae83c8cb3ed585171a23ac3966f7 +3aeba4cf8f0745f84c1fe13866d7bc32 +47d426db823a73c1753c91a88bf47e3e +117afe9cb4003fe7579c8e8d4a05a89d +34b2d2f2c562a5b347ef69035628aaf9 +e0b3017f6b71435bf7d9377a73e96cf6 +26a99924aad5076f54a82132905a2e24 +825cf81526395d9431bb3f1d6b3b10c0 +-----END OpenVPN Static key V1----- diff --git a/root/backup-openvpn-2025-10-06/openvpn/update-resolv-conf b/root/backup-openvpn-2025-10-06/openvpn/update-resolv-conf new file mode 100755 index 0000000000..61b15d9a3c --- /dev/null +++ b/root/backup-openvpn-2025-10-06/openvpn/update-resolv-conf @@ -0,0 +1,63 @@ +#!/bin/bash +# +# Parses DHCP options from openvpn to update resolv.conf +# To use set as 'up' and 'down' script in your openvpn *.conf: +# up /etc/openvpn/update-resolv-conf +# down /etc/openvpn/update-resolv-conf +# +# Used snippets of resolvconf script by Thomas Hood and Chris Hanson. +# Licensed under the GNU GPL. See /usr/share/common-licenses/GPL. +# +# Example envs set from openvpn: +# +# foreign_option_1='dhcp-option DNS 193.43.27.132' +# foreign_option_2='dhcp-option DNS 193.43.27.133' +# foreign_option_3='dhcp-option DOMAIN be.bnc.ch' +# + +if [ ! -x /sbin/resolvconf ] ; then + logger "[OpenVPN:update-resolve-conf] missing binary /sbin/resolvconf"; + exit 0; +fi + +[ "$script_type" ] || exit 0 +[ "$dev" ] || exit 0 + +split_into_parts() +{ + part1="$1" + part2="$2" + part3="$3" +} + +case "$script_type" in + up) + NMSRVRS="" + SRCHS="" + foreign_options=$(printf '%s\n' ${!foreign_option_*} | sort -t _ -k 3 -g) + for optionvarname in ${foreign_options} ; do + option="${!optionvarname}" + echo "$option" + split_into_parts $option + if [ "$part1" = "dhcp-option" ] ; then + if [ "$part2" = "DNS" ] ; then + NMSRVRS="${NMSRVRS:+$NMSRVRS }$part3" + elif [ "$part2" = "DOMAIN" ] ; then + SRCHS="${SRCHS:+$SRCHS }$part3" + fi + fi + done + R="" + [ "$SRCHS" ] && R="search $SRCHS +" + for NS in $NMSRVRS ; do + R="${R}nameserver $NS +" + done + echo -n "$R" | /sbin/resolvconf -a "${dev}.openvpn" + ;; + down) + /sbin/resolvconf -d "${dev}.openvpn" + ;; +esac + diff --git a/root/emy-laptop.csr b/root/emy-laptop.csr new file mode 100644 index 0000000000..ef3de9a417 --- /dev/null +++ b/root/emy-laptop.csr @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICWjCCAUICAQAwFTETMBEGA1UEAwwKZW15LWxhcHRvcDCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAOIcxSL0pn2Aiv/Ox7MbT6eiaaDuTuobvYa1BH1z +wv5qgmg3gTmQf95fqQ5cYvqtFYFO05iaF77aI5n5gAB3QnxlNL2iEqhxvRZYMxRM +NTrKEotomzHfVd86Ef1Ihbxgf+sGGVwUPIl3ArArzuSSRdmXPqWXP4XsFSBlJxsI +eMSjlVdsZIVMz2pgskPn3tm2m3b/rTN81qwWQgLCig6swQ6uZbsX9T/L2b03UN06 +HeBmjssQ9wObaLCFPkQaGnkLc9rFWxdlcPxq0ga8a8QiZf96X+qGXg3z09FklgVr +QXBkwAuoxU/VMiiZEnDqL3Vudq+VNf9Nh3FzM0t+FdJnAT0CAwEAAaAAMA0GCSqG +SIb3DQEBCwUAA4IBAQB6Ml2Fm/xoHz+WXXv+rJ/F8z7sJCTRJQWF+yNvs8wEJPMj +DovxxIjsmyvhvnW5+K+HhJWMvp+fjeK3g7A0WEQfzO4QuC/n/Ouy017hp1cdUSHw +C1LQr31Z/BhGRoxbHOKfPq75sG7oPTkhnK1shAkmxi8iI+M0/3UAHZoppIdymFCc +zgVKFy11h/7J/ZQNlwRWI5GIs2Pu+cQfTH+gjnhSKJHqXX1RcVf8dp5kTn4iK1kV +8EnoRWVm8T6llujjMCoro11xzOvR8PtvfMH6f6h1idBr3Pnok4wEXrD3avSD6pQv +zaJw2RQqDus0jYTCJSAlJesTUwhpzYLADxT5/1+f +-----END CERTIFICATE REQUEST----- diff --git a/root/emy-laptop.key b/root/emy-laptop.key new file mode 100644 index 0000000000..f82330630a --- /dev/null +++ b/root/emy-laptop.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDiHMUi9KZ9gIr/ +zsezG0+nommg7k7qG72GtQR9c8L+aoJoN4E5kH/eX6kOXGL6rRWBTtOYmhe+2iOZ ++YAAd0J8ZTS9ohKocb0WWDMUTDU6yhKLaJsx31XfOhH9SIW8YH/rBhlcFDyJdwKw +K87kkkXZlz6llz+F7BUgZScbCHjEo5VXbGSFTM9qYLJD597Ztpt2/60zfNasFkIC +wooOrMEOrmW7F/U/y9m9N1DdOh3gZo7LEPcDm2iwhT5EGhp5C3PaxVsXZXD8atIG +vGvEImX/el/qhl4N89PRZJYFa0FwZMALqMVP1TIomRJw6i91bnavlTX/TYdxczNL +fhXSZwE9AgMBAAECggEANlBf4F4xMftzKDCFEtZwI13ljqU/6odgVt/bpMDuaYuv +KJaQoYG+3W1QICV8FygFfuqu9DyrkIo4vA9NOo9rNpNfAGBSqAiuOZRVLL6DmMwa +eUdW5Dt4FqeN07Acg9wQTiXIaLBpvEGMsUHMsGYchkCI6WDz/tjvWDlEE//Mdrs7 +FSR7k2befFaV1+qUIWtY9ZiyWV0FUo+7C3yBekkeFg+DeL33oQr2ci2QWLfQpkOJ +YuQkoUhjdibiBgzFMBSihS69SyV5GUFC47a79zsda1yMtPd/MhfebtitlZSDgMLN +RwxVEyINFmCYZlhkezFmcQJilxfDwuMMrxrioXBIdwKBgQD06jO6v2WxXdzVt+hv +zYSXLIq6lL7t9mtr3o/yqYVKHTbfQZSXUmF8yXiFoPD0iPdclLBngMo28e7jAuRt +0qnPpBycbTqF1dKpcS3tIE9V7jUQLz+yn7ijXVWaOQeciEeYyb7tZS3RJKXESwh6 +iLrU1pXyF8RfEYWrP0Lif033VwKBgQDsWLTE3fBCH0OAuZ8MwwrcS8u+2ZZCi88O +xwRmjGA4V0N6qhy9yCqiNV6IQ+Kwwnlbdh9kNQ+9s0N5za6C5oEU82eVoVEjQhIg +jSOgv9u8Zr4oxKnz8KpUWw/+MVtK3HMDumL1anoaT4gpFJMPTkpHTcy45DysUd1T +UyW/WVPTiwKBgD8db9FLa7CGqNdmun69btLqhqHInV+DpnE4/M2jRBcyaiakpt9M +OpVG8kk1jYLnHR/9rWwu822vcUmNQELRDDPXbgwd1fwRe2VxJk26itdxOLmAA6FL +qfBnqBzDX6PGNvU34H0bGvCPyixIzdmODN+2oROvbkq1oEXeWqU1+2inAoGBAM/J +xVP3k81uUxiPGUhNCfVYJg7qmXJ0HFxvmGzYKZgfEFJ90LsBiooFxdCjbl/c+njw +xvSAuhAb1Mz3id/H6+CRhpZEt2L6KZm4vIQNaZCf+7s3+/tdsUJstQjUN+D/I5c5 +fNsq+6K6HYmQbyJbwG4j9kLvVnBhoOYrCdrLHCm1AoGAIdXToZIuTavVq/Vv1Xl5 +xFv5S5d1AAi5yVLRCzVJR4M0jfd45QQLlj08y/75ze2j0XXO085aW3mn+JK+0h3L +gNfNIp9J3eLalJ966Vt4I2rEnFq0Dm/0OX6snhfk4sPq8me35IZzc9CJqGguerEq ++ktF1bRNlQ73kDn2AfTR5xQ= +-----END PRIVATE KEY----- diff --git a/root/monitoring/docker-compose.yml b/root/monitoring/docker-compose.yml new file mode 100644 index 0000000000..7ab70d1108 --- /dev/null +++ b/root/monitoring/docker-compose.yml @@ -0,0 +1,15 @@ +version: "3.8" + +services: + uptime-kuma: + image: louislam/uptime-kuma:latest + container_name: uptime-kuma + restart: unless-stopped + volumes: + - /root/monitoring/uptime-kuma:/app/data + ports: + - "127.0.0.1:3001:3001" # nur lokal, reverse proxy via nginx empfohlen + extra_hosts: + - "proxmox.cutemeli.com:10.10.0.1" + - "share.cutemeli.com:10.10.0.1" + - "monitor.cutemeli.com:10.10.0.1" diff --git a/root/monitoring/host-health.sh b/root/monitoring/host-health.sh new file mode 100755 index 0000000000..3c2b299d9b --- /dev/null +++ b/root/monitoring/host-health.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ==== KONFIG ==== +PUSH_URL="http://127.0.0.1:3001/api/push/O2EhJUkH4n" +LOG_FILE="/var/log/host-health.log" + +CURL="/usr/bin/curl" +SYSTEMCTL="/bin/systemctl" +DATESTAMP="$(date -Is)" + +# Warn- und Kritisch-Schwellen +CPU_WARN=5.0 # Load > 5 Warnung +CPU_CRIT=10.0 # Load > 10 kritisch +RAM_WARN=85 # >85% RAM Warnung +RAM_CRIT=95 # >95% RAM kritisch +DISK_WARN=80 # >80% Disk Warnung +DISK_CRIT=95 # >95% Disk kritisch + +# ==== MESSWERTE ==== +CPU_LOAD="$(awk '{print $1}' /proc/loadavg)" +RAM_PCT="$(free | awk '/Mem:/ {printf "%.0f", ($3/$2)*100}')" +DISK_PCT="$(df -P / | awk 'NR==2 {gsub("%","",$5); print $5}')" + +# Ping zur Default-Gateway oder extern (hier Google DNS) +PING_MS="$(ping -c1 -W1 8.8.8.8 | awk -F'time=' '/time=/{print $2}' | cut -d' ' -f1 || echo "NaN")" + +# Dienste-Status +svc_ok () { $SYSTEMCTL is-active --quiet "$1" && echo OK || echo FAIL; } +NGINX_STATUS="$(svc_ok nginx)" +DOCKER_STATUS="$(svc_ok docker)" +WG_STATUS="$(svc_ok wg-quick@wg0)" +PVEVM_STATUS="$(svc_ok proxmox-vm)" + +# ==== STATUS LOGIK ==== +STATUS="up" +MSG="" + +# CPU Check +if (( $(echo "$CPU_LOAD > $CPU_CRIT" | bc -l) )); then + STATUS="down"; MSG+="CPU:CRIT(${CPU_LOAD}) " +elif (( $(echo "$CPU_LOAD > $CPU_WARN" | bc -l) )); then + MSG+="CPU:WARN(${CPU_LOAD}) " +else + MSG+="CPU:${CPU_LOAD} " +fi + +# RAM Check +if [ "$RAM_PCT" -ge "$RAM_CRIT" ]; then + STATUS="down"; MSG+="RAM:CRIT(${RAM_PCT}%) " +elif [ "$RAM_PCT" -ge "$RAM_WARN" ]; then + MSG+="RAM:WARN(${RAM_PCT}%) " +else + MSG+="RAM:${RAM_PCT}% " +fi + +# Disk Check +if [ "$DISK_PCT" -ge "$DISK_CRIT" ]; then + STATUS="down"; MSG+="DISK:CRIT(${DISK_PCT}%) " +elif [ "$DISK_PCT" -ge "$DISK_WARN" ]; then + MSG+="DISK:WARN(${DISK_PCT}%) " +else + MSG+="DISK:${DISK_PCT}% " +fi + +# Dienste Check +for svc in NGINX:$NGINX_STATUS DOCKER:$DOCKER_STATUS WG:$WG_STATUS PVEVM:$PVEVM_STATUS; do + name="${svc%%:*}"; val="${svc##*:}" + if [ "$val" != "OK" ]; then + STATUS="down"; MSG+="$name:FAIL " + else + MSG+="$name:OK " + fi +done + +# Ping (nur Info) +MSG+="PING:${PING_MS}ms" + +# ==== PUSH ==== +HTTP_CODE="$($CURL -sS -o /tmp/kuma_push.out -w "%{http_code}" \ + --get \ + --data-urlencode "status=${STATUS}" \ + --data-urlencode "msg=${MSG}" \ + --data-urlencode "ping=${PING_MS}" \ + "${PUSH_URL}")" || true + +# Logging +echo "${DATESTAMP} status=${STATUS} msg='${MSG}' http=${HTTP_CODE}" >> "$LOG_FILE" + +if [[ "$HTTP_CODE" != "200" ]]; then + echo "${DATESTAMP} ERROR: Kuma Push HTTP ${HTTP_CODE}" >> "$LOG_FILE" + exit 1 +fi diff --git a/root/monitoring/uptime-kuma/error.log b/root/monitoring/uptime-kuma/error.log new file mode 100644 index 0000000000..f354807548 --- /dev/null +++ b/root/monitoring/uptime-kuma/error.log @@ -0,0 +1,4 @@ +[2025-10-02 16:37:39] [Error: insert into `heartbeat` (`down_count`, `duration`, `important`, `monitor_id`, `msg`, `status`, `time`) values (0, 0, true, 7, 'queryA ETIMEOUT 217.154.245.77', 0, '2025-10-02 14:37:16.510') - SQLITE_CONSTRAINT: FOREIGN KEY constraint failed] { + errno: 19, + code: 'SQLITE_CONSTRAINT' +} diff --git a/root/monitoring/uptime-kuma/kuma.db b/root/monitoring/uptime-kuma/kuma.db new file mode 100755 index 0000000000..3abd2f46b9 Binary files /dev/null and b/root/monitoring/uptime-kuma/kuma.db differ diff --git a/root/parallels/PHP74_17/php74-ubt24.04-x86_64.inf3 b/root/parallels/PHP74_17/php74-ubt24.04-x86_64.inf3 new file mode 100644 index 0000000000..f2d4834cfb --- /dev/null +++ b/root/parallels/PHP74_17/php74-ubt24.04-x86_64.inf3 @@ -0,0 +1,47 @@ + + + -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v2.0.22 (GNU/Linux) mQGiBFXAUiARBAC9lDsyU9L2dZRyhOp27adDZ99+tfPq9L0aX1xmZvpF+rO6FEa1 HCEi1blRq/icL784esCEuEe/k6eGeqKgOv6E05ZG9txvP/vhUofFJX6vAHsiScKN QXwZQQqM2Fz3oPqeN/7zOE/dfASrTC8fET7J7+d+KNOOnDSSxIG9XJbGTwCg0BCd 2vNB4CduMm2oyTVNGcWXmCMEAIFJALIEEeNlevXvBxBPv86DB3eFdLUgYJNlwIfJ aDCFr9plRNb6O/MMGPFPsp113r4E+o1M8bW5RBfZgnxXH+6Xi3i/kMBh9GtovAv+ qe4lMJQ+t7cFDedvsgsmigq7cl0cmSwe00zhYzT4t3lEg5F3l543Wwxk/kwQj2wp t5cCA/9rAUUCZ4ewdO74tiuF5nmTb+lHNvIq4EKXacgA5gsVVMTw/SH8G0m0z+YH 3xJuVJaO18+6OrdCjGzmzJ78k8j6z1fuAZVWWaUK+XtjP6mn/ZsjwvrIGMxrbJ85 B/v+j4W7MOjIHmD37PScSibK56ItlQHjd2y0S6jy+e4UFIOnA7QbUGxlc2sgVGVh bSA8aW5mb0BwbGVzay5jb20+iGAEExECACAFAlXAUiACGwMGCwkIBwMCBBUCCAME FgIDAQIeAQIXgAAKCRC9EaaqkUvfflh7AKCDstpjOFDR1FarF2BU/sA6+rFteQCg xHjO3vh+i2QiTnGlBhOUlCxuNFq5Ag0EVcBSJxAIAID5a6RrDkEIkaAc6u+BJJsp Rychg18z+IdHPUrBABEeT7vCmH5KISP1bdhur8vgeDdFanhLjTjC7mYJ5OJnb3ZM nl/L8B5uz/RQ8i7Sv/buwr69h/llVElkeOyx2SkkIdsHLPNXuxydZfADfz5B5Zjx R7IVepDxEeA755rCQd3alAwk6lA0Iy+LCdCaNIGpzzC6j7goLeGE1tAoG3J0Lvja xXGgTmqHHhImGjc875wngrDRo4yDu6Tfwi6b0RCfbkm6wgEWGvDwzSXz1+7iWRAC kyagGrZPOqKJiKBfj+hVMnflB3EFZd2j5hfWl35U4j18U6v6JkxKIn0DvD5+cz8A BAsH/RVWit+s/zXJbxd9U07EPbVS+ujZrhannBgV6xpMuGWDbl1QcMWXoQXU0zK4 Gr44UmHbe3h1F38GeMzELjfMYi8XAMvOQkC5i8Clv9jHJwfHxt8wcA/tE4kPtRNx KhDhh3i2sZTg123h0EpEOlMvrVoboFyH8K7BN+KdEl3YtWgmbM9zhOO8R7LFGQ6m VxxL4BlX7QNZ9cpDQ5sNTiPu4pij++oFoSaquXZKGXOO3KvTBQHHceps+w1cpYXv EGzNjxvTvPmBYXZAVlu8dOInDMfl8wwctAmHXxPeh0kTGRlZT4QHJs1pJVgNuQbP pjqmxx1SGEnYmE/TNDP+J1F7GISISQQYEQIACQUCVcBSJwIbDAAKCRC9EaaqkUvf fmn2AJ9q31HpLe/9sHWQHAL/ul6qeSNIJwCeK2hBWeBcx0iC/ISo8T/EX8KTCcw= =NB3w -----END PGP PUBLIC KEY BLOCK----- + + + plesk-php74 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/PHP74_17/release.inf3 b/root/parallels/PHP74_17/release.inf3 new file mode 100644 index 0000000000..1315112a7d --- /dev/null +++ b/root/parallels/PHP74_17/release.inf3 @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/PHP80_17/php80-ubt24.04-x86_64.inf3 b/root/parallels/PHP80_17/php80-ubt24.04-x86_64.inf3 new file mode 100644 index 0000000000..d786c45d72 --- /dev/null +++ b/root/parallels/PHP80_17/php80-ubt24.04-x86_64.inf3 @@ -0,0 +1,45 @@ + + + -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v2.0.22 (GNU/Linux) mQGiBFXAUiARBAC9lDsyU9L2dZRyhOp27adDZ99+tfPq9L0aX1xmZvpF+rO6FEa1 HCEi1blRq/icL784esCEuEe/k6eGeqKgOv6E05ZG9txvP/vhUofFJX6vAHsiScKN QXwZQQqM2Fz3oPqeN/7zOE/dfASrTC8fET7J7+d+KNOOnDSSxIG9XJbGTwCg0BCd 2vNB4CduMm2oyTVNGcWXmCMEAIFJALIEEeNlevXvBxBPv86DB3eFdLUgYJNlwIfJ aDCFr9plRNb6O/MMGPFPsp113r4E+o1M8bW5RBfZgnxXH+6Xi3i/kMBh9GtovAv+ qe4lMJQ+t7cFDedvsgsmigq7cl0cmSwe00zhYzT4t3lEg5F3l543Wwxk/kwQj2wp t5cCA/9rAUUCZ4ewdO74tiuF5nmTb+lHNvIq4EKXacgA5gsVVMTw/SH8G0m0z+YH 3xJuVJaO18+6OrdCjGzmzJ78k8j6z1fuAZVWWaUK+XtjP6mn/ZsjwvrIGMxrbJ85 B/v+j4W7MOjIHmD37PScSibK56ItlQHjd2y0S6jy+e4UFIOnA7QbUGxlc2sgVGVh bSA8aW5mb0BwbGVzay5jb20+iGAEExECACAFAlXAUiACGwMGCwkIBwMCBBUCCAME FgIDAQIeAQIXgAAKCRC9EaaqkUvfflh7AKCDstpjOFDR1FarF2BU/sA6+rFteQCg xHjO3vh+i2QiTnGlBhOUlCxuNFq5Ag0EVcBSJxAIAID5a6RrDkEIkaAc6u+BJJsp Rychg18z+IdHPUrBABEeT7vCmH5KISP1bdhur8vgeDdFanhLjTjC7mYJ5OJnb3ZM nl/L8B5uz/RQ8i7Sv/buwr69h/llVElkeOyx2SkkIdsHLPNXuxydZfADfz5B5Zjx R7IVepDxEeA755rCQd3alAwk6lA0Iy+LCdCaNIGpzzC6j7goLeGE1tAoG3J0Lvja xXGgTmqHHhImGjc875wngrDRo4yDu6Tfwi6b0RCfbkm6wgEWGvDwzSXz1+7iWRAC kyagGrZPOqKJiKBfj+hVMnflB3EFZd2j5hfWl35U4j18U6v6JkxKIn0DvD5+cz8A BAsH/RVWit+s/zXJbxd9U07EPbVS+ujZrhannBgV6xpMuGWDbl1QcMWXoQXU0zK4 Gr44UmHbe3h1F38GeMzELjfMYi8XAMvOQkC5i8Clv9jHJwfHxt8wcA/tE4kPtRNx KhDhh3i2sZTg123h0EpEOlMvrVoboFyH8K7BN+KdEl3YtWgmbM9zhOO8R7LFGQ6m VxxL4BlX7QNZ9cpDQ5sNTiPu4pij++oFoSaquXZKGXOO3KvTBQHHceps+w1cpYXv EGzNjxvTvPmBYXZAVlu8dOInDMfl8wwctAmHXxPeh0kTGRlZT4QHJs1pJVgNuQbP pjqmxx1SGEnYmE/TNDP+J1F7GISISQQYEQIACQUCVcBSJwIbDAAKCRC9EaaqkUvf fmn2AJ9q31HpLe/9sHWQHAL/ul6qeSNIJwCeK2hBWeBcx0iC/ISo8T/EX8KTCcw= =NB3w -----END PGP PUBLIC KEY BLOCK----- + + + plesk-php80 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/PHP80_17/release.inf3 b/root/parallels/PHP80_17/release.inf3 new file mode 100644 index 0000000000..f30f04f5df --- /dev/null +++ b/root/parallels/PHP80_17/release.inf3 @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/PHP81_17/php81-ubt24.04-x86_64.inf3 b/root/parallels/PHP81_17/php81-ubt24.04-x86_64.inf3 new file mode 100644 index 0000000000..ba77ec0d5d --- /dev/null +++ b/root/parallels/PHP81_17/php81-ubt24.04-x86_64.inf3 @@ -0,0 +1,45 @@ + + + -----BEGIN PGP PUBLIC KEY BLOCK----- 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 VNnMRY8n =Hv0N -----END PGP PUBLIC KEY BLOCK----- + + + plesk-php81 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/PHP81_17/release.inf3 b/root/parallels/PHP81_17/release.inf3 new file mode 100644 index 0000000000..c57c3e1627 --- /dev/null +++ b/root/parallels/PHP81_17/release.inf3 @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/PHP82_17/php82-ubt24.04-x86_64.inf3 b/root/parallels/PHP82_17/php82-ubt24.04-x86_64.inf3 new file mode 100644 index 0000000000..48f33d21d5 --- /dev/null +++ b/root/parallels/PHP82_17/php82-ubt24.04-x86_64.inf3 @@ -0,0 +1,45 @@ + + + -----BEGIN PGP PUBLIC KEY BLOCK----- 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 VNnMRY8n =Hv0N -----END PGP PUBLIC KEY BLOCK----- + + + plesk-php82 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/PHP82_17/release.inf3 b/root/parallels/PHP82_17/release.inf3 new file mode 100644 index 0000000000..ba928876f6 --- /dev/null +++ b/root/parallels/PHP82_17/release.inf3 @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/PHP83_17/php83-ubt24.04-x86_64.inf3 b/root/parallels/PHP83_17/php83-ubt24.04-x86_64.inf3 new file mode 100644 index 0000000000..a152443126 --- /dev/null +++ b/root/parallels/PHP83_17/php83-ubt24.04-x86_64.inf3 @@ -0,0 +1,45 @@ + + + -----BEGIN PGP PUBLIC KEY BLOCK----- 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 VNnMRY8n =Hv0N -----END PGP PUBLIC KEY BLOCK----- + + + plesk-php83 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/PHP83_17/release.inf3 b/root/parallels/PHP83_17/release.inf3 new file mode 100644 index 0000000000..a176334f51 --- /dev/null +++ b/root/parallels/PHP83_17/release.inf3 @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/PHP84_17/php84-ubt24.04-x86_64.inf3 b/root/parallels/PHP84_17/php84-ubt24.04-x86_64.inf3 new file mode 100644 index 0000000000..82faba849b --- /dev/null +++ b/root/parallels/PHP84_17/php84-ubt24.04-x86_64.inf3 @@ -0,0 +1,45 @@ + + + -----BEGIN PGP PUBLIC KEY BLOCK----- mQGNBGfIt/cBDADGVazaP3jWndhBaSljtWGtGqrRjNVnsu5YPtOsmOgQ0x7VZQft C/LpT5QnOVip5DBfAUBbxLzZ0C6/YP4+7yJRcAbecuFEwln02AeiE7tzQu8P8cvC V4VTTKcdWzEhKMaoSS1tiIKGVGPuQcYwAvhY5pcrFgMypYOOsLjZtR0oOrmqpMlC x2JMmD6gwGONzNv3EungSV8QVE7sgyttmuCUR2QlbCJQjNWpkgvstNxXRvWiuvrK gGNVdd14r5juOv3PA2TwWsEFUR8hfK7eqtDYo8BS9HigUkjI35B/CWxi55mgAXDq Xdwtc79dWGvnCruFmTVp6W3kTEwPXC0SphHAqE4r8+HoKX3fMXb7oddqwYXUCOuS z7xan1KctOe/c5Y9EbERjBLdr4sJrOkJv91PBuL7Scz33o7lHKCXrvuVQmLhRvT1 rG2D6/Ya/WaFFWI8z8MqINZgMtwzmcow/xapj8c6e1lgOblQ0j1qiiptQTuIoC49 JgZTFr3A6mcYOrEAEQEAAbQbUGxlc2sgVGVhbSA8aW5mb0BwbGVzay5jb20+iQHO BBMBCgA4FiEEbBkTJQiO2DphjsDC6SmQRc5VDlcFAmfIt/cCGwMFCwkIBwIGFQoJ CAsCBBYCAwECHgECF4AACgkQ6SmQRc5VDld7pwv9FrqzISuXHelFotpDXcqPqcWQ W97mi4dkyo9dY+UBFXqprPaC9+mM9HW7a+lZSgWdxc+CY2MrbcIXfdnaJmJWJGqc dvW122hjQRe7ClrwRAL06HDj5yhMHqhFPUbb8a+PoKb1d8vRQHHrLpUhcpwhsLr5 aZFZop3NKN3ktPQiqoMPAHBuG4Aag6puG9BZS4jBvTJXvD9JAd7wQkxvPW/BJvBK ILlOrs/6UTdgIDNv8qlUt77vS1s6RpGVJXRhjj9J1f6Lfg2xJZMO0fLqOxgUjSrG jV1r6tnS6pxi0onXJsSmMEli4wsZpnotr35Vwu9Eekb6KTq5K05YJxnqi6G2qFY7 nRpXSvfjYJ+MDP3a3fhryqfFd6lQdnuNv4XMBRnwr6VJNzsRg/xkYlPkDZ2dbXVl AwUTIX6Uw6F8ToUE8v/KGNHEiLycCv2Szk/nLawr3aLCfijgxTaP+RzUUb44ex/k nm6at9hCZbNknBGcMPXb6Y6MTSOQKhmpR4n+a4KluQGNBGfIt/cBDACtcVnLn1ye JFEhPja0IJE4AxmVLGGWHKLBLGqyoONwAi9LA/+kfTL0MhhM4Ib8dmg4N7HfTROd HvhjlsRLnqBoTuPyz8Jh1oxkmM3gYGAR10GulqNNXLWNVdqJjtfRKLGZr5MhsCdb i7tKA42/hWqqKVmCGEkc5IOl0kd8qvCPM/vqFvHYBxF5Ov5aUhSTwQBVbrcsU1Qc K491VjCk1Fw1BpV3sj0pYs2MPaR0k3A3pMLG6oMI900wt/wiZMjNSyFCxhEYFrLR t7qkuLcN+LZ94USiowPP04QxaDj5mFnQ+O0n4UAKRJ9/uHGbhCFuej1/DkB9urP0 SGbte51v2KisuWG/nBkg119gQeXKLIGNC5aE2TTQBTaEBL09teDeQMg8TbQlu6v/ AIFpgrwckmvAk6afaWpAZ0GTNZ0DQL1wD6m8E8T4JFcVIQ+C1IzKu6OE7KKMzyjg crI9HMLpGSEOzRfR334nSYsWFS88XW6msltMNWn3jNSLOQ+1Xf+RN3cAEQEAAYkB tQQYAQoAIBYhBGwZEyUIjtg6YY7AwukpkEXOVQ5XBQJnyLf3AhsMAAoJEOkpkEXO VQ5XoooL91q50qxg/09vV1GldlFBF1eFEUsSVwOYoGKtsRzebWEdGc8Ze4Cks5fq CQipKjPC1kmShocshFBYKDRChiXk+b/djK0U1aEaRZYP/ro953yfXVnV68WeoiJ4 EIH9qXMzDcMn58fVEvz9EYyk8b3VcBru+0TgCvWrNVJBd7DF8YJXs2rSAfhu5Sdf P4uL9hhhF1TWPJjFG3L4gW8Ah9vgmaU9uQhIP3e3ANWxOtEhjhnnO8noJCxELKeS tTve7EYpscuixfOXPwmY3zJATXLt/+QJAcnGasFcTkw/XFvGOOZJ/7mx+GUhD23D AjsA3ozjL3FLS/v7A4rYEUc/dClX3lMKwEK7ZVNtmtt1WsbuHX/Py/R5XhyA3V1W JOwV1Mgnmu8BS62JcWY6oB0mhc3uGd6Tgs1ZkeisnBsi0Oi4YQ8Ms0v1NZHXgwtL JbRkcLFAL8rErnC0728220B+2Aik4DHZZI0M7Fre7QPWiU9a1R7AUCxsgQfEum5m VNnMRY8n =Hv0N -----END PGP PUBLIC KEY BLOCK----- + + + plesk-php84 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/PHP84_17/release.inf3 b/root/parallels/PHP84_17/release.inf3 new file mode 100644 index 0000000000..0568050498 --- /dev/null +++ b/root/parallels/PHP84_17/release.inf3 @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/PHP85_17/php85-ubt24.04-x86_64.inf3 b/root/parallels/PHP85_17/php85-ubt24.04-x86_64.inf3 new file mode 100644 index 0000000000..8702480824 --- /dev/null +++ b/root/parallels/PHP85_17/php85-ubt24.04-x86_64.inf3 @@ -0,0 +1,44 @@ + + + -----BEGIN PGP PUBLIC KEY BLOCK----- mQGNBGfIt/cBDADGVazaP3jWndhBaSljtWGtGqrRjNVnsu5YPtOsmOgQ0x7VZQft C/LpT5QnOVip5DBfAUBbxLzZ0C6/YP4+7yJRcAbecuFEwln02AeiE7tzQu8P8cvC V4VTTKcdWzEhKMaoSS1tiIKGVGPuQcYwAvhY5pcrFgMypYOOsLjZtR0oOrmqpMlC x2JMmD6gwGONzNv3EungSV8QVE7sgyttmuCUR2QlbCJQjNWpkgvstNxXRvWiuvrK gGNVdd14r5juOv3PA2TwWsEFUR8hfK7eqtDYo8BS9HigUkjI35B/CWxi55mgAXDq Xdwtc79dWGvnCruFmTVp6W3kTEwPXC0SphHAqE4r8+HoKX3fMXb7oddqwYXUCOuS z7xan1KctOe/c5Y9EbERjBLdr4sJrOkJv91PBuL7Scz33o7lHKCXrvuVQmLhRvT1 rG2D6/Ya/WaFFWI8z8MqINZgMtwzmcow/xapj8c6e1lgOblQ0j1qiiptQTuIoC49 JgZTFr3A6mcYOrEAEQEAAbQbUGxlc2sgVGVhbSA8aW5mb0BwbGVzay5jb20+iQHO BBMBCgA4FiEEbBkTJQiO2DphjsDC6SmQRc5VDlcFAmfIt/cCGwMFCwkIBwIGFQoJ CAsCBBYCAwECHgECF4AACgkQ6SmQRc5VDld7pwv9FrqzISuXHelFotpDXcqPqcWQ W97mi4dkyo9dY+UBFXqprPaC9+mM9HW7a+lZSgWdxc+CY2MrbcIXfdnaJmJWJGqc dvW122hjQRe7ClrwRAL06HDj5yhMHqhFPUbb8a+PoKb1d8vRQHHrLpUhcpwhsLr5 aZFZop3NKN3ktPQiqoMPAHBuG4Aag6puG9BZS4jBvTJXvD9JAd7wQkxvPW/BJvBK ILlOrs/6UTdgIDNv8qlUt77vS1s6RpGVJXRhjj9J1f6Lfg2xJZMO0fLqOxgUjSrG jV1r6tnS6pxi0onXJsSmMEli4wsZpnotr35Vwu9Eekb6KTq5K05YJxnqi6G2qFY7 nRpXSvfjYJ+MDP3a3fhryqfFd6lQdnuNv4XMBRnwr6VJNzsRg/xkYlPkDZ2dbXVl AwUTIX6Uw6F8ToUE8v/KGNHEiLycCv2Szk/nLawr3aLCfijgxTaP+RzUUb44ex/k nm6at9hCZbNknBGcMPXb6Y6MTSOQKhmpR4n+a4KluQGNBGfIt/cBDACtcVnLn1ye JFEhPja0IJE4AxmVLGGWHKLBLGqyoONwAi9LA/+kfTL0MhhM4Ib8dmg4N7HfTROd HvhjlsRLnqBoTuPyz8Jh1oxkmM3gYGAR10GulqNNXLWNVdqJjtfRKLGZr5MhsCdb i7tKA42/hWqqKVmCGEkc5IOl0kd8qvCPM/vqFvHYBxF5Ov5aUhSTwQBVbrcsU1Qc K491VjCk1Fw1BpV3sj0pYs2MPaR0k3A3pMLG6oMI900wt/wiZMjNSyFCxhEYFrLR t7qkuLcN+LZ94USiowPP04QxaDj5mFnQ+O0n4UAKRJ9/uHGbhCFuej1/DkB9urP0 SGbte51v2KisuWG/nBkg119gQeXKLIGNC5aE2TTQBTaEBL09teDeQMg8TbQlu6v/ AIFpgrwckmvAk6afaWpAZ0GTNZ0DQL1wD6m8E8T4JFcVIQ+C1IzKu6OE7KKMzyjg crI9HMLpGSEOzRfR334nSYsWFS88XW6msltMNWn3jNSLOQ+1Xf+RN3cAEQEAAYkB tQQYAQoAIBYhBGwZEyUIjtg6YY7AwukpkEXOVQ5XBQJnyLf3AhsMAAoJEOkpkEXO VQ5XoooL91q50qxg/09vV1GldlFBF1eFEUsSVwOYoGKtsRzebWEdGc8Ze4Cks5fq CQipKjPC1kmShocshFBYKDRChiXk+b/djK0U1aEaRZYP/ro953yfXVnV68WeoiJ4 EIH9qXMzDcMn58fVEvz9EYyk8b3VcBru+0TgCvWrNVJBd7DF8YJXs2rSAfhu5Sdf P4uL9hhhF1TWPJjFG3L4gW8Ah9vgmaU9uQhIP3e3ANWxOtEhjhnnO8noJCxELKeS tTve7EYpscuixfOXPwmY3zJATXLt/+QJAcnGasFcTkw/XFvGOOZJ/7mx+GUhD23D AjsA3ozjL3FLS/v7A4rYEUc/dClX3lMKwEK7ZVNtmtt1WsbuHX/Py/R5XhyA3V1W JOwV1Mgnmu8BS62JcWY6oB0mhc3uGd6Tgs1ZkeisnBsi0Oi4YQ8Ms0v1NZHXgwtL JbRkcLFAL8rErnC0728220B+2Aik4DHZZI0M7Fre7QPWiU9a1R7AUCxsgQfEum5m VNnMRY8n =Hv0N -----END PGP PUBLIC KEY BLOCK----- + + + plesk-php85 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/PHP85_17/release.inf3 b/root/parallels/PHP85_17/release.inf3 new file mode 100644 index 0000000000..f33e86f120 --- /dev/null +++ b/root/parallels/PHP85_17/release.inf3 @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/apache.inf3 b/root/parallels/apache.inf3 new file mode 100644 index 0000000000..f7091b2669 --- /dev/null +++ b/root/parallels/apache.inf3 @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/billing.inf3 b/root/parallels/billing.inf3 new file mode 100644 index 0000000000..19e1e2730b --- /dev/null +++ b/root/parallels/billing.inf3 @@ -0,0 +1,1396 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/mysql.inf3 b/root/parallels/mysql.inf3 new file mode 100644 index 0000000000..40a8a814f7 --- /dev/null +++ b/root/parallels/mysql.inf3 @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/nginx.inf3 b/root/parallels/nginx.inf3 new file mode 100644 index 0000000000..553bdc5c9a --- /dev/null +++ b/root/parallels/nginx.inf3 @@ -0,0 +1,419 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/php52.inf3 b/root/parallels/php52.inf3 new file mode 100644 index 0000000000..7d793d752f --- /dev/null +++ b/root/parallels/php52.inf3 @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/php53.inf3 b/root/parallels/php53.inf3 new file mode 100644 index 0000000000..4feb25d441 --- /dev/null +++ b/root/parallels/php53.inf3 @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/php54.inf3 b/root/parallels/php54.inf3 new file mode 100644 index 0000000000..cedf26e643 --- /dev/null +++ b/root/parallels/php54.inf3 @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/php55.inf3 b/root/parallels/php55.inf3 new file mode 100644 index 0000000000..40f7262b40 --- /dev/null +++ b/root/parallels/php55.inf3 @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/php56.inf3 b/root/parallels/php56.inf3 new file mode 100644 index 0000000000..36b8dbf6f0 --- /dev/null +++ b/root/parallels/php56.inf3 @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/php70.inf3 b/root/parallels/php70.inf3 new file mode 100644 index 0000000000..1d73090db0 --- /dev/null +++ b/root/parallels/php70.inf3 @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/php71.inf3 b/root/parallels/php71.inf3 new file mode 100644 index 0000000000..d356bdab82 --- /dev/null +++ b/root/parallels/php71.inf3 @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/php72.inf3 b/root/parallels/php72.inf3 new file mode 100644 index 0000000000..5cb7c10d3a --- /dev/null +++ b/root/parallels/php72.inf3 @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/php73.inf3 b/root/parallels/php73.inf3 new file mode 100644 index 0000000000..6eca461f6c --- /dev/null +++ b/root/parallels/php73.inf3 @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/php74.inf3 b/root/parallels/php74.inf3 new file mode 100644 index 0000000000..433403b955 --- /dev/null +++ b/root/parallels/php74.inf3 @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + diff --git a/root/parallels/php80.inf3 b/root/parallels/php80.inf3 new file mode 100644 index 0000000000..344acca646 --- /dev/null +++ b/root/parallels/php80.inf3 @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/root/parallels/php81.inf3 b/root/parallels/php81.inf3 new file mode 100644 index 0000000000..078e2cff73 --- /dev/null +++ b/root/parallels/php81.inf3 @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/root/parallels/php82.inf3 b/root/parallels/php82.inf3 new file mode 100644 index 0000000000..a0a62fe64d --- /dev/null +++ b/root/parallels/php82.inf3 @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/root/parallels/php83.inf3 b/root/parallels/php83.inf3 new file mode 100644 index 0000000000..fdfe9d84d0 --- /dev/null +++ b/root/parallels/php83.inf3 @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/root/parallels/plesk.inf3 b/root/parallels/plesk.inf3 new file mode 100644 index 0000000000..84a51bd23a --- /dev/null +++ b/root/parallels/plesk.inf3 @@ -0,0 +1,2791 @@ + + + + + + + + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.5.0 + + + 2.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.5.0 + + + 2.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.5.0 + + + 2.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.5.0 + + + 2.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.5.0 + + + 2.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.5.0 + + + 2.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.5.0 + + + 2.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.5.0 + + + 2.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.5.0 + + + 2.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.5.0 + + + 2.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.5.0 + + + 2.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.5.0 + + + 2.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.1.0 + + + 2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.1.0 + + + 2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.1.0 + + + 2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pmm.inf3 b/root/parallels/pmm.inf3 new file mode 100644 index 0000000000..c7c475b2ef --- /dev/null +++ b/root/parallels/pmm.inf3 @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.64_15680/release.inf3 b/root/parallels/pool/PSA_18.0.64_15680/release.inf3 new file mode 100644 index 0000000000..556189cd0b --- /dev/null +++ b/root/parallels/pool/PSA_18.0.64_15680/release.inf3 @@ -0,0 +1,34 @@ + + + + + + + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.65_15919/release.inf3 b/root/parallels/pool/PSA_18.0.65_15919/release.inf3 new file mode 100644 index 0000000000..ab20c611ba --- /dev/null +++ b/root/parallels/pool/PSA_18.0.65_15919/release.inf3 @@ -0,0 +1,34 @@ + + + + + + + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.66_16134/release.inf3 b/root/parallels/pool/PSA_18.0.66_16134/release.inf3 new file mode 100644 index 0000000000..d96c745d10 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.66_16134/release.inf3 @@ -0,0 +1,34 @@ + + + + + + + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.67_16409/release.inf3 b/root/parallels/pool/PSA_18.0.67_16409/release.inf3 new file mode 100644 index 0000000000..2d4ac12030 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.67_16409/release.inf3 @@ -0,0 +1,35 @@ + + + + + + + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.68_16616/release.inf3 b/root/parallels/pool/PSA_18.0.68_16616/release.inf3 new file mode 100644 index 0000000000..da76ca53df --- /dev/null +++ b/root/parallels/pool/PSA_18.0.68_16616/release.inf3 @@ -0,0 +1,35 @@ + + + + + + + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.69_17010/release.inf3 b/root/parallels/pool/PSA_18.0.69_17010/release.inf3 new file mode 100644 index 0000000000..bf8edd5d8f --- /dev/null +++ b/root/parallels/pool/PSA_18.0.69_17010/release.inf3 @@ -0,0 +1,33 @@ + + + + + + + + + psa + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.70_17357/release.inf3 b/root/parallels/pool/PSA_18.0.70_17357/release.inf3 new file mode 100644 index 0000000000..f735ca4357 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.70_17357/release.inf3 @@ -0,0 +1,33 @@ + + + + + + + + + psa + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.71_17351/release.inf3 b/root/parallels/pool/PSA_18.0.71_17351/release.inf3 new file mode 100644 index 0000000000..8419c3264e --- /dev/null +++ b/root/parallels/pool/PSA_18.0.71_17351/release.inf3 @@ -0,0 +1,35 @@ + + + + + + + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.72_17583/examiners/congratulations.sh b/root/parallels/pool/PSA_18.0.72_17583/examiners/congratulations.sh new file mode 100755 index 0000000000..907c5ba782 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.72_17583/examiners/congratulations.sh @@ -0,0 +1,50 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +out() +{ + echo -e "\t$*" >&2 +} + +print_urls() +{ + plesk login 2>/dev/null | sed -e $'s|^|\t * |' >&2 +} + +print_congratulations() +{ + local mode="$1" # 'install' or 'upgrade' + local process= + [ "$mode" = "install" ] && process="installation" || process="upgrade" + + out + out " Congratulations!" + out + out "The $process has been finished. Plesk is now running on your server." + out + if [ "$mode" = "install" ]; then + out "To complete the configuration process, browse either of URLs:" + print_urls + out + fi + out "Use the username 'admin' to log in. To log in as 'admin', use the 'plesk login' command." + out "You can also log in as 'root' using your 'root' password." + out + out "Use the 'plesk' command to manage the server. Run 'plesk help' for more info." + out + out "Use the following commands to start and stop the Plesk web interface:" + out "'systemctl start psa.service' and 'systemctl stop psa.service' respectively." + out + if [ "$mode" = "install" ]; then + out "If you would like to migrate your subscriptions from other hosting panel" + out "or older Plesk version to this server, please check out our assistance" + out "options: https://www.plesk.com/professional-services/" + out + fi +} + +unset GREP_OPTIONS + +print_congratulations "$1" +# Force showing text when used as AI post-examiner +exit 1 diff --git a/root/parallels/pool/PSA_18.0.72_17583/examiners/disk_space_check.sh b/root/parallels/pool/PSA_18.0.72_17583/examiners/disk_space_check.sh new file mode 100755 index 0000000000..b6238e41a0 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.72_17583/examiners/disk_space_check.sh @@ -0,0 +1,532 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ -z "$PLESK_INSTALLER_DEBUG" ] || set -x +[ -z "$PLESK_INSTALLER_STRICT_MODE" ] || set -e + +export LC_ALL=C +unset GREP_OPTIONS + +RET_SUCCESS=0 +RET_WARN=1 +RET_FATAL=2 + +is_function_defined() +{ + local fn="$1" + case "$(type $fn 2>/dev/null)" in + *function*) + return 0 + ;; + esac + return 1 +} + +# @params are tags in format "key=value" +# Report body (human readable information) is read from stdin +# and copied to stderr. +make_error_report() +{ + local report_file="${PLESK_INSTALLER_ERROR_REPORT:-}" + + local python_bin= + for bin in "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2" "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3"; do + if [ -x "$bin" ]; then + python_bin="$bin" + break + fi + done + + if [ -n "$report_file" -a -x "$python_bin" ]; then + "$python_bin" -c 'import sys, json +report_file = sys.argv[1] +error = sys.stdin.read() + +sys.stderr.write(error) + +data = { + "error": error, +} + +for tag in sys.argv[2:]: + k, v = tag.split("=", 1) + data[k] = v + +with open(report_file, "a") as f: + json.dump(data, f) + f.write("\n") +' "$report_file" "date=$(date --utc --iso-8601=ns)" "$@" + else + cat - >&2 + fi +} + +detect_platform() +{ + . /etc/os-release + os_name="$ID" + os_version="${VERSION_ID%%.*}" + os_arch="$(uname -m)" + if [ -e /etc/debian_version ]; then + case "$os_arch" in + x86_64) pkg_arch="amd64" ;; + aarch64) pkg_arch="arm64" ;; + esac + if [ -n "$VERSION_CODENAME" ]; then + os_codename="$VERSION_CODENAME" + else + case "$os_name$os_version" in + debian10) os_codename="buster" ;; + debian11) os_codename="bullseye" ;; + debian12) os_codename="bookworm" ;; + ubuntu18) os_codename="bionic" ;; + ubuntu20) os_codename="focal" ;; + ubuntu22) os_codename="jammy" ;; + ubuntu24) os_codename="noble" ;; + esac + fi + fi + + case "$os_name$os_version" in + rhel7|centos7|cloudlinux7|virtuozzo7) + package_manager="yum" + ;; + rhel*|centos*|cloudlinux*|almalinux*|rocky*) + package_manager="dnf" + ;; + debian*|ubuntu*) + package_manager="apt" + ;; + esac + + if [ "$os_name" = "ubuntu" -o "$os_name" = "debian" ]; then + PRODUCT_ROOT_D="/opt/psa" + else + PRODUCT_ROOT_D="/usr/local/psa" + fi +} + +has_os_impl_function() +{ + local prefix="$1" + local fn="${prefix}_${os_name}${os_version}" + is_function_defined "$fn" +} + +call_os_impl_function() +{ + local prefix="$1" + shift + local fn="${prefix}_${os_name}${os_version}" + "$fn" "$@" +} + +skip_checker_on_flag() +{ + local name="$1" + local flag="$2" + + if [ -f "$flag" ]; then + echo "$name was skipped due to flag file." >&2 + exit $RET_SUCCESS + fi +} + +skip_checker_on_env() +{ + local name="$1" + local env="$2" + + if [ -n "$env" ]; then + echo "$name was skipped due to environment variable." >&2 + exit $RET_SUCCESS + fi +} + +checker_main() +{ + local fnprefix="$1" + shift + + detect_platform + # try to execute checker only if all attributes are detected + [ -n "$os_name" -a -n "$os_version" ] || return $RET_SUCCESS + + for checker in "${fnprefix}_${os_name}${os_version}" "${fnprefix}_${os_name}" "${fnprefix}"; do + if is_function_defined "$checker"; then + local rc=$RET_SUCCESS + "$checker" "$@" || rc=$? + [ "$(( $rc & $RET_FATAL ))" = "0" ] || return $RET_FATAL + [ "$(( $rc & $RET_WARN ))" = "0" ] || return $RET_WARN + return $rc + fi + done + return $RET_SUCCESS +} + +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +# If env variable PLESK_INSTALLER_ERROR_REPORT=path_to_file is specified then in case of error +# disk_space_check.sh writes single line json report into it with the following fields: +# - "stage": "diskspacecheck" +# - "level": "error" +# - "errtype": "notenoughdiskspace" +# - "volume": volume with not enough diskspace (e.g. "/") +# - "required": required diskspace on the volume, human readable (e.g. "600 MB") +# - "available": available diskspace on the volume, human readable (e.g. "255 MB") +# - "needtofree": amount of diskspace which should be freed on the volume, human readable (e.g. "345 MB") +# - "date": time of error occurance ("2020-03-24T06:59:43,127545441+0000") +# - "error": human readable error message ("There is not enough disk space available in the / directory.") + +# Required values below for Full installation are in MB. See 'du -cs -BM /*' and 'df -Pm'. + +required_disk_space_cloudlinux7() +{ + case "$1" in + /opt) echo 900 ;; + /usr) echo 4400 ;; + /var) echo 600 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_cloudlinux8() +{ + case "$1" in + /opt) echo 1200 ;; + /usr) echo 4400 ;; + /var) echo 700 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_centos7() +{ + case "$1" in + /opt) echo 900 ;; + /usr) echo 4100 ;; + /var) echo 600 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_centos8() +{ + case "$1" in + /opt) echo 900 ;; + /usr) echo 4500 ;; + /var) echo 800 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_virtuozzo7() +{ + required_disk_space_centos7 "$1" +} + +required_disk_space_rhel7() +{ + required_disk_space_centos7 "$1" +} + +required_disk_space_rhel8() +{ + required_disk_space_centos8 "$1" +} + +required_disk_space_almalinux8() +{ + required_disk_space_centos8 "$1" +} + +required_disk_space_rocky8() +{ + required_disk_space_centos8 "$1" +} + +required_disk_space_rhel9() +{ + case "$1" in + /opt) echo 500 ;; + /usr) echo 4000 ;; + /var) echo 800 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_almalinux9() +{ + required_disk_space_rhel9 "$1" +} + +required_disk_space_almalinux10() +{ + required_disk_space_almalinux9 "$1" +} + +required_disk_space_cloudlinux9() +{ + required_disk_space_rhel9 "$1" +} + +required_disk_space_debian10() +{ + case "$1" in + /opt) echo 1800 ;; + /usr) echo 2300 ;; + /var) echo 1700 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_debian11() +{ + case "$1" in + /opt) echo 1500 ;; + /usr) echo 3100 ;; + /var) echo 1800 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_debian12() +{ + case "$1" in + /opt) echo 2700 ;; + /usr) echo 2500 ;; + /var) echo 2200 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_ubuntu18() +{ + case "$1" in + /opt) echo 900 ;; + /usr) echo 1800 ;; + /var) echo 600 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_ubuntu20() +{ + case "$1" in + /opt) echo 1800 ;; + /usr) echo 2900 ;; + /var) echo 1600 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_ubuntu22() +{ + case "$1" in + /opt) echo 1800 ;; + /usr) echo 3900 ;; + /var) echo 1900 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_ubuntu24() +{ + case "$1" in + /opt) echo 3200 ;; + /usr) echo 1800 ;; + /var) echo 2400 ;; + /tmp) echo 100 ;; + esac +} + +required_update_upgrade_disk_space() +{ + case "$1" in + /opt) echo 100 ;; + /usr) echo 300 ;; + /var) echo 600 ;; + /tmp) echo 100 ;; + esac +} + +clean_tmp() +{ + local volume="$1" + local path="/tmp" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'systemd-tmpfiles --clean --prefix $path'" + systemd-tmpfiles --clean --prefix "$path" 2>&1 +} + +clean_yum() +{ + local volume="$1" + local path="/var/cache/yum" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'yum clean all'" + yum clean all 2>&1 + + # The command above doesn't clean untracked repos (missing in configuration), clean if left > 2 Mb + [ "`du -sm "$path" | awk '{ print $1 }'`" -gt 2 ] || return 0 + echo "Cleaning $path via 'rm -rf $path/*'" + rm -rf "$path"/* 2>&1 +} + +clean_dnf() +{ + local volume="$1" + local path="/var/cache/dnf" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'dnf clean all'" + dnf clean all 2>&1 +} + +clean_apt() +{ + local volume="$1" + local path="/var/cache/apt" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'apt-get clean'" + apt-get clean 2>&1 +} + +clean_journal() +{ + local volume="$1" + local path="/var/log/journal" + is_path_on_volume "$path" "$volume" || return 0 + + # Note that --rotate may cause more space to be freed, but may also cause more space to be used + echo "Cleaning $path via 'journalctl --vacuum-time 1d'" + journalctl --vacuum-time 1d 2>&1 +} + +clean_ext_packages() +{ + local volume="$1" + local path="$PRODUCT_ROOT_D/var/modules-packages" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'rm -rf $path/*'" + rm -rf "$path"/* 2>&1 +} + +# @param $1 target directory +mount_point() +{ + df -Pm $1 | awk 'NR==2 { print $6 }' +} + +# @param $1 target directory +available_disk_space() +{ + df -Pm $1 | awk 'NR==2 { print $4 }' +} + +is_path_on_volume() +{ + local path="$1" + local volume="$2" + [ -d "$path" ] && [ "`mount_point "$path"`" = "$volume" ] +} + +# @param $1 target directory +# @param $2 mode (install/upgrade/update) +req_disk_space() +{ + if [ "$2" != "install" ]; then + required_update_upgrade_disk_space "$1" + return + fi + + has_os_impl_function "required_disk_space" || { + echo "There are no requirements defined for $os_name$os_version." >&2 + echo "Disk space check cannot be performed." >&2 + exit $RET_WARN + } + call_os_impl_function "required_disk_space" "$1" +} + +human_readable_size() +{ + echo "$1" | awk ' + function human(x) { + s = "MGTEPYZ"; + while (x >= 1000 && length(s) > 1) { + x /= 1024; s = substr(s, 2); + } + # 0.05 below will make sure the value is rounded up + return sprintf("%.1f %sB", x + 0.05, substr(s, 1, 1)); + } + { print human($1); }' +} + +# @param $1 target directory +# @param $2 required disk space +# @param $3 check only flag (don't emit errors) +check_available_disk_space() +{ + local volume="$1" + local required="$2" + local check_only="${3:-}" + local available="$(available_disk_space "$volume")" + if [ "$available" -lt "$required" ]; then + local needtofree + needtofree="`human_readable_size $((required - available))`" + [ -n "$check_only" ] || + make_error_report 'stage=diskspacecheck' 'level=error' 'errtype=notenoughdiskspace' \ + "volume=$volume" "required=$required MB" "available=$available MB" "needtofree=$needtofree" \ + <<-EOL + There is not enough disk space available in the $1 directory. + You need to free up $needtofree. + EOL + return "$RET_FATAL" + fi +} + +# @param $1 target directory +# @param $2 required disk space +clean_and_check_available_disk_space() +{ + if [ -n "$PLESK_INSTALLER_FORCE_CLEAN_DISK_SPACE" ] || ! check_available_disk_space "$@" --check-only; then + clean_disk_space "$1" + check_available_disk_space "$@" + fi +} + +# Cleans up disk space on the volume +clean_disk_space() +{ + local volume="$1" + for cleanup_func in clean_tmp clean_yum clean_dnf clean_apt clean_journal clean_ext_packages; do + "$cleanup_func" "$volume" + done +} + +# @param $1 mode (install/upgrade/update) +clean_and_check_disk_space() +{ + local mode="$1" + local shared=0 + + for target_directory in /opt /usr /var /tmp; do + local required=$(req_disk_space "$target_directory" "$mode") + [ -n "$required" ] || return "$RET_WARN" + + if is_path_on_volume "$target_directory" "/"; then + shared="$((shared + required))" + else + clean_and_check_available_disk_space "$target_directory" "$required" || return $? + fi + done + + clean_and_check_available_disk_space "/" "$shared" || return $? +} + +checker_main 'clean_and_check_disk_space' "$1" diff --git a/root/parallels/pool/PSA_18.0.72_17583/examiners/package_manager_check.sh b/root/parallels/pool/PSA_18.0.72_17583/examiners/package_manager_check.sh new file mode 100755 index 0000000000..b089061d97 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.72_17583/examiners/package_manager_check.sh @@ -0,0 +1,224 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ -z "$PLESK_INSTALLER_DEBUG" ] || set -x +[ -z "$PLESK_INSTALLER_STRICT_MODE" ] || set -e + +export LC_ALL=C +unset GREP_OPTIONS + +RET_SUCCESS=0 +RET_WARN=1 +RET_FATAL=2 + +is_function_defined() +{ + local fn="$1" + case "$(type $fn 2>/dev/null)" in + *function*) + return 0 + ;; + esac + return 1 +} + +# @params are tags in format "key=value" +# Report body (human readable information) is read from stdin +# and copied to stderr. +make_error_report() +{ + local report_file="${PLESK_INSTALLER_ERROR_REPORT:-}" + + local python_bin= + for bin in "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2" "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3"; do + if [ -x "$bin" ]; then + python_bin="$bin" + break + fi + done + + if [ -n "$report_file" -a -x "$python_bin" ]; then + "$python_bin" -c 'import sys, json +report_file = sys.argv[1] +error = sys.stdin.read() + +sys.stderr.write(error) + +data = { + "error": error, +} + +for tag in sys.argv[2:]: + k, v = tag.split("=", 1) + data[k] = v + +with open(report_file, "a") as f: + json.dump(data, f) + f.write("\n") +' "$report_file" "date=$(date --utc --iso-8601=ns)" "$@" + else + cat - >&2 + fi +} + +detect_platform() +{ + . /etc/os-release + os_name="$ID" + os_version="${VERSION_ID%%.*}" + os_arch="$(uname -m)" + if [ -e /etc/debian_version ]; then + case "$os_arch" in + x86_64) pkg_arch="amd64" ;; + aarch64) pkg_arch="arm64" ;; + esac + if [ -n "$VERSION_CODENAME" ]; then + os_codename="$VERSION_CODENAME" + else + case "$os_name$os_version" in + debian10) os_codename="buster" ;; + debian11) os_codename="bullseye" ;; + debian12) os_codename="bookworm" ;; + ubuntu18) os_codename="bionic" ;; + ubuntu20) os_codename="focal" ;; + ubuntu22) os_codename="jammy" ;; + ubuntu24) os_codename="noble" ;; + esac + fi + fi + + case "$os_name$os_version" in + rhel7|centos7|cloudlinux7|virtuozzo7) + package_manager="yum" + ;; + rhel*|centos*|cloudlinux*|almalinux*|rocky*) + package_manager="dnf" + ;; + debian*|ubuntu*) + package_manager="apt" + ;; + esac + + if [ "$os_name" = "ubuntu" -o "$os_name" = "debian" ]; then + PRODUCT_ROOT_D="/opt/psa" + else + PRODUCT_ROOT_D="/usr/local/psa" + fi +} + +has_os_impl_function() +{ + local prefix="$1" + local fn="${prefix}_${os_name}${os_version}" + is_function_defined "$fn" +} + +call_os_impl_function() +{ + local prefix="$1" + shift + local fn="${prefix}_${os_name}${os_version}" + "$fn" "$@" +} + +skip_checker_on_flag() +{ + local name="$1" + local flag="$2" + + if [ -f "$flag" ]; then + echo "$name was skipped due to flag file." >&2 + exit $RET_SUCCESS + fi +} + +skip_checker_on_env() +{ + local name="$1" + local env="$2" + + if [ -n "$env" ]; then + echo "$name was skipped due to environment variable." >&2 + exit $RET_SUCCESS + fi +} + +checker_main() +{ + local fnprefix="$1" + shift + + detect_platform + # try to execute checker only if all attributes are detected + [ -n "$os_name" -a -n "$os_version" ] || return $RET_SUCCESS + + for checker in "${fnprefix}_${os_name}${os_version}" "${fnprefix}_${os_name}" "${fnprefix}"; do + if is_function_defined "$checker"; then + local rc=$RET_SUCCESS + "$checker" "$@" || rc=$? + [ "$(( $rc & $RET_FATAL ))" = "0" ] || return $RET_FATAL + [ "$(( $rc & $RET_WARN ))" = "0" ] || return $RET_WARN + return $rc + fi + done + return $RET_SUCCESS +} + +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +check_package_manager_deb_based() +{ + local output= + output="`dpkg --audit 2>&1`" || output="$output"$'\n'"'dpkg --audit' finished with error code $?." + + if [ -n "$output" ]; then + make_error_report 'stage=packagemanagercheck' 'level=error' 'errtype=brokenpackages' <<-EOL + The system package manager reports the following problems: + + $output + + To continue with the installation, you need to resolve these issues + using the procedure below: + + 1. Make sure you have a full server snapshot. Although the + following steps are usually safe, they can still cause + data loss or irreversible changes. + 2. Run 'dpkg --configure -a'. This command can fix some of the + issues. However, it may fail. Regardless if it fails or not, + proceed with the following steps. + 3. Run 'PLESK_INSTALLER_SKIP_PACKAGE_MANAGER_CHECK=1 plesk installer update --skip-cleanup'. + Instead of 'update', you may need to use the command you used + previously (for example, 'upgrade' or 'install'). + 4. The next step depends on the outcome of the previous one: + - If step 3 was completed with the "You already have the latest + version of product(s) and all the selected components installed. + Installation will not continue." message, + run 'plesk repair installation'. + - If step 3 failed, run 'dpkg --audit'. This command can show you + packages that need to be reinstalled. To reinstall them, run + 'apt-get install --reinstall '. + 5. Run 'plesk installer update' to revert temporary changes and + validate that the issues are resolved. If the command fails or + triggers this check again, contact Plesk support. + + For more information, see + https://support.plesk.com/hc/en-us/articles/12871173047447-Plesk-update-on-Debian-Ubuntu-fails-dpkg-was-interrupted-you-must-manually-run-dpkg-configure-a-to-correct-the-problem + EOL + return "$RET_FATAL" + fi +} + +check_package_manager_debian() +{ + check_package_manager_deb_based +} + +check_package_manager_ubuntu() +{ + check_package_manager_deb_based +} + +skip_checker_on_env "Package manager check" "$PLESK_INSTALLER_SKIP_PACKAGE_MANAGER_CHECK" +skip_checker_on_flag "Package manager check" "/tmp/plesk-installer-skip-package-manager-check.flag" +checker_main 'check_package_manager' "$@" diff --git a/root/parallels/pool/PSA_18.0.72_17583/examiners/php_launcher.sh b/root/parallels/pool/PSA_18.0.72_17583/examiners/php_launcher.sh new file mode 100755 index 0000000000..70ebd0f0c6 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.72_17583/examiners/php_launcher.sh @@ -0,0 +1,38 @@ +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +die() +{ + echo $* + exit 1 +} + +[ -n "$1" ] || die "Usage: $0 php_script [args...]" + +[ "X${PLESK_INSTALLER_DEBUG}" = "X" ] || set -x +[ "X${PLESK_INSTALLER_STRICT_MODE}" = "X" ] || set -e + +php_bin= + +lookup() +{ + [ -z "$php_bin" ] || return + + local paths="$1" + local name="$2" + + for path in $paths; do + if [ -x "$path/$name" ]; then + php_bin="$path/$name" + break + fi + done +} + +lookup "/usr/local/psa/admin/bin /opt/psa/admin/bin" "php" +lookup "/usr/local/psa/bin /opt/psa/bin" "sw-engine-pleskrun" + +[ -n "$php_bin" ] || \ + die "Unable to locate the sw-engine PHP interpreter to execute the script. Make sure that Parallels Plesk Panel is installed on this server." + +exec "${php_bin}" "$@" diff --git a/root/parallels/pool/PSA_18.0.72_17583/examiners/py_launcher.sh b/root/parallels/pool/PSA_18.0.72_17583/examiners/py_launcher.sh new file mode 100755 index 0000000000..96dc215391 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.72_17583/examiners/py_launcher.sh @@ -0,0 +1,30 @@ +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +die() +{ + echo "$*" + exit 1 +} + +[ -f "$1" ] || die "Usage: $0 PEX [args...]" + +[ "X${PLESK_INSTALLER_DEBUG}" = "X" ] || set -x +[ "X${PLESK_INSTALLER_STRICT_MODE}" = "X" ] || set -e + +find_python_bin() +{ + local bin + for bin in "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3" "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2"; do + [ -x "$bin" ] || continue + python_bin="$bin" + return 0 + done + + return 1 +} + +find_python_bin || + die "Unable to locate Python interpreter to execute the script." + +exec "$python_bin" "$@" diff --git a/root/parallels/pool/PSA_18.0.72_17583/examiners/repository_check.sh b/root/parallels/pool/PSA_18.0.72_17583/examiners/repository_check.sh new file mode 100755 index 0000000000..090f121ea1 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.72_17583/examiners/repository_check.sh @@ -0,0 +1,782 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ -z "$PLESK_INSTALLER_DEBUG" ] || set -x +[ -z "$PLESK_INSTALLER_STRICT_MODE" ] || set -e + +export LC_ALL=C +unset GREP_OPTIONS + +RET_SUCCESS=0 +RET_WARN=1 +RET_FATAL=2 + +is_function_defined() +{ + local fn="$1" + case "$(type $fn 2>/dev/null)" in + *function*) + return 0 + ;; + esac + return 1 +} + +# @params are tags in format "key=value" +# Report body (human readable information) is read from stdin +# and copied to stderr. +make_error_report() +{ + local report_file="${PLESK_INSTALLER_ERROR_REPORT:-}" + + local python_bin= + for bin in "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2" "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3"; do + if [ -x "$bin" ]; then + python_bin="$bin" + break + fi + done + + if [ -n "$report_file" -a -x "$python_bin" ]; then + "$python_bin" -c 'import sys, json +report_file = sys.argv[1] +error = sys.stdin.read() + +sys.stderr.write(error) + +data = { + "error": error, +} + +for tag in sys.argv[2:]: + k, v = tag.split("=", 1) + data[k] = v + +with open(report_file, "a") as f: + json.dump(data, f) + f.write("\n") +' "$report_file" "date=$(date --utc --iso-8601=ns)" "$@" + else + cat - >&2 + fi +} + +detect_platform() +{ + . /etc/os-release + os_name="$ID" + os_version="${VERSION_ID%%.*}" + os_arch="$(uname -m)" + if [ -e /etc/debian_version ]; then + case "$os_arch" in + x86_64) pkg_arch="amd64" ;; + aarch64) pkg_arch="arm64" ;; + esac + if [ -n "$VERSION_CODENAME" ]; then + os_codename="$VERSION_CODENAME" + else + case "$os_name$os_version" in + debian10) os_codename="buster" ;; + debian11) os_codename="bullseye" ;; + debian12) os_codename="bookworm" ;; + ubuntu18) os_codename="bionic" ;; + ubuntu20) os_codename="focal" ;; + ubuntu22) os_codename="jammy" ;; + ubuntu24) os_codename="noble" ;; + esac + fi + fi + + case "$os_name$os_version" in + rhel7|centos7|cloudlinux7|virtuozzo7) + package_manager="yum" + ;; + rhel*|centos*|cloudlinux*|almalinux*|rocky*) + package_manager="dnf" + ;; + debian*|ubuntu*) + package_manager="apt" + ;; + esac + + if [ "$os_name" = "ubuntu" -o "$os_name" = "debian" ]; then + PRODUCT_ROOT_D="/opt/psa" + else + PRODUCT_ROOT_D="/usr/local/psa" + fi +} + +has_os_impl_function() +{ + local prefix="$1" + local fn="${prefix}_${os_name}${os_version}" + is_function_defined "$fn" +} + +call_os_impl_function() +{ + local prefix="$1" + shift + local fn="${prefix}_${os_name}${os_version}" + "$fn" "$@" +} + +skip_checker_on_flag() +{ + local name="$1" + local flag="$2" + + if [ -f "$flag" ]; then + echo "$name was skipped due to flag file." >&2 + exit $RET_SUCCESS + fi +} + +skip_checker_on_env() +{ + local name="$1" + local env="$2" + + if [ -n "$env" ]; then + echo "$name was skipped due to environment variable." >&2 + exit $RET_SUCCESS + fi +} + +checker_main() +{ + local fnprefix="$1" + shift + + detect_platform + # try to execute checker only if all attributes are detected + [ -n "$os_name" -a -n "$os_version" ] || return $RET_SUCCESS + + for checker in "${fnprefix}_${os_name}${os_version}" "${fnprefix}_${os_name}" "${fnprefix}"; do + if is_function_defined "$checker"; then + local rc=$RET_SUCCESS + "$checker" "$@" || rc=$? + [ "$(( $rc & $RET_FATAL ))" = "0" ] || return $RET_FATAL + [ "$(( $rc & $RET_WARN ))" = "0" ] || return $RET_WARN + return $rc + fi + done + return $RET_SUCCESS +} + +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +# If env variable PLESK_INSTALLER_ERROR_REPORT=path_to_file is specified then in case of error +# repository_check.sh writes single line json report into it with the following fields: +# - "stage": "repositorycheck" +# - "level": "error" +# - "errtype" is one of the following: +# * "reponotcached" - repository is not cached (mostly due to unavailability). +# * "reponotenabled" - required repository is not enabled. +# * "reponotsupported" - unsupported repository is enabled. +# * "configmanagernotinstalled" - dnf config-manager is disabled. +# - "repo": repository name. +# - "date": time of error occurance ("2020-03-24T06:59:43,127545441+0000") +# - "error": human readable error message. + +report_no_repo() +{ + local repo="$1" + + make_error_report 'stage=repositorycheck' 'level=error' 'errtype=reponotenabled' "repo=$repo" <<-EOL + Plesk installation requires '$repo' OS repository to be enabled. + Make sure it is available and enabled, then try again. + EOL +} + +report_no_repo_cache() +{ + local repo="$1" + + make_error_report 'stage=repositorycheck' 'level=error' 'errtype=reponotcached' "repo=$repo" <<-EOL + Unable to create $package_manager cache for '$repo' OS repository. + Make sure the repository is available, otherwise either disable it or fix its configuration, then try again. + EOL +} + +report_unsupported_repo() +{ + local repo="$1" + + make_error_report 'stage=repositorycheck' 'level=error' 'errtype=reponotsupported' "repo=$repo" <<-EOL + Plesk installation doesn't support '$repo' OS repository. + Make sure it is disabled, then try again. + EOL +} + +report_rh_no_config_manager() +{ + local target + case "$package_manager" in + yum) + target="yum-utils package" + ;; + dnf) + target="config-manager dnf plugin" + ;; + esac + + make_error_report 'stage=repositorycheck' 'level=error' 'errtype=configmanagernotinstalled' <<-EOL + Failed to install $target. + Make sure repositories configuration of $package_manager package manager is correct + (use '$package_manager repolist --verbose' to get its actual state), then try again. + EOL +} + +check_rh_broken_repos() +{ + local rh_enabled_repos rh_available_repos + + # 1. `yum repolist` and `dnf repolist` list all repos + # which were enabled before last cache creation + # even if cache for them was not created. + # If some repo is misconfigured and cache was created with `skip_if_unavailable=1` + # then such repo will be listed anyway despite on cache state. + # If some repo was enabled after last cache creation + # then `repolist --cacheonly` will fail. + # 2. `yum repolist --verbose` and `dnf repoinfo` list only repos + # which were successfully cached before. + # These commands fail if at least one repo is not available + # and the 'skip_if_unavailable' flag is not set. + case "$package_manager" in + yum) + rh_enabled_repos="$( + { + yum repolist enabled --cacheonly -q 2>/dev/null \ + || yum repolist enabled -q --setopt='*.skip_if_unavailable=1' + } | sed -n -e '1d' -e 's/^\*\?!\?\([^/[:space:]]\+\).*/\1/p' + )" || return $RET_FATAL + + rh_available_repos="$( + yum repolist enabled --verbose --cacheonly -q --setopt='*.skip_if_unavailable=1' \ + | sed -n -e 's/^Repo-id\s*:\s*\([^/[:space:]]\+\).*/\1/p' + )" || return $RET_FATAL + ;; + dnf) + rh_enabled_repos="$( + { + dnf repolist --enabled --cacheonly -q 2>/dev/null \ + || dnf repolist --enabled -q --setopt='*.skip_if_unavailable=1' + } | sed -n -e '1d' -e 's/^!\?\(\S\+\).*/\1/p' + )" || return $RET_FATAL + + rh_available_repos="$( \ + dnf repoinfo --enabled --cacheonly -q --setopt='*.skip_if_unavailable=1' \ + | sed -n -e 's|^Repo-id\s*:\s*\(\S\+\)\s*$|\1|p' + )" || return $RET_FATAL + ;; + esac + + local rh_enabled_repos_f="$(mktemp /tmp/plesk-installer.preupgrade_checker.XXXXXX)" + echo "$rh_enabled_repos" | sort > "$rh_enabled_repos_f" + local rh_available_repos_f="$(mktemp /tmp/plesk-installer.preupgrade_checker.XXXXXX)" + echo "$rh_available_repos" | sort > "$rh_available_repos_f" + + local repo rc=0 + for repo in $(comm -23 "$rh_enabled_repos_f" "$rh_available_repos_f"); do + report_no_repo_cache "$repo" + rc=$RET_WARN + done + + rm -f "$rh_enabled_repos_f" "$rh_available_repos_f" + + return $rc +} + +has_rh_enabled_repo() +{ + local repo="$1" + + # Try to get list of repos from cache first. + # If some repo was enabled after last cache creation + # or some repo is unavailable the query from cache will fail. + # Try to fetch actual metadata in this case. + case "$package_manager" in + yum) + # Repo-id may end with OS version and/or architecture + # if baseurl of the repo refers to $releasever and/or $basearch variables + # eg 'epel/7/x86_64', 'epel/7', 'epel/x86_64' + { + yum repolist enabled --verbose --cacheonly -q 2>/dev/null \ + || yum repolist enabled --verbose -q --setopt='*.skip_if_unavailable=1' + } | grep -E -q "^Repo-id\s*: $repo(/.+)?\s*$" + ;; + dnf) + # note: --noplugins may cause failure and empty output on RedHat + { + dnf repoinfo --enabled --cacheonly -q 2>/dev/null \ + || dnf repoinfo --enabled -q --setopt='*.skip_if_unavailable=1' + } | grep -E -q "^Repo-id\s*: $repo\s*$" + ;; + esac +} + +has_rh_config_manager() +{ + case "$package_manager" in + yum) yum-config-manager --help >/dev/null 2>&1 ;; + dnf) dnf config-manager --help >/dev/null 2>&1 ;; + esac +} + +install_rh_config_manager() +{ + case "$package_manager" in + yum) yum install --disablerepo 'PLESK_*' -q -y 'yum-utils' --setopt='*.skip_if_unavailable=1' ;; + dnf) dnf install --disablerepo 'PLESK_*' -q -y 'dnf-command(config-manager)' --setopt='*.skip_if_unavailable=1' ;; + esac +} + +check_rh_config_manager() +{ + if ! has_rh_config_manager && ! install_rh_config_manager; then + report_rh_no_config_manager + return $RET_FATAL + fi +} + +enable_rh_repo() +{ + case "$package_manager" in + yum) yum-config-manager --enable "$@" && has_rh_enabled_repo "$@" ;; + dnf) dnf config-manager --set-enabled "$@" && has_rh_enabled_repo "$@" ;; + esac +} + +enable_sm_repo() +{ + ! has_rh_enabled_repo "$@" || return 0 + subscription-manager repos --enable "$@" || return $? + # On RedHat 8 above command may return 0 on failure with "Repositories disabled by configuration." + has_rh_enabled_repo "$@" +} + +check_epel() +{ + ! enable_rh_repo "epel" || return 0 + + # try to install epel-release from centos/extras or plesk/thirdparty repo + # and then try to update it to last version shipped by epel itself + # to make package upgradable with pum + "$package_manager" install --disablerepo 'PLESK_*' -q -y 'epel-release' --setopt='*.skip_if_unavailable=1' 2>/dev/null \ + || "$package_manager" install --disablerepo='*' --enablerepo 'PLESK_18_*-thirdparty' -q -y 'epel-release' \ + || "$package_manager" install -q -y "https://dl.fedoraproject.org/pub/epel/epel-release-latest-$os_version.noarch.rpm" \ + && "$package_manager" update -q -y 'epel-release' --setopt='*.skip_if_unavailable=1' 2>/dev/null + + # Ensure any other EPEL repos have cache for subsequent check for broken repos (AL9) + local epel_repos="$( + [ "$package_manager" != "dnf" ] || { + dnf repolist --enabled --cacheonly -q 2>/dev/null || + dnf repolist --enabled -q --setopt='*.skip_if_unavailable=1' + } | sed -n -e '1d' -e 's/^!\?\(epel\S\+\).*/\1/p' + )" + for repo in $epel_repos; do + "$package_manager" makecache --repo "$repo" -q + done + + ! has_rh_enabled_repo "epel" || return 0 + + report_no_repo "epel" + return $RET_FATAL +} + +check_codeready() +{ + local repo_rhel="codeready-builder-for-rhel-$os_version-$os_arch-rpms" + local repo_rhui="codeready-builder-for-rhel-$os_version-rhui-rpms" + local repo_rhui_alt="codeready-builder-for-rhel-$os_version-$os_arch-rhui-rpms" + local repo_rhui_alt2="rhui-codeready-builder-for-rhel-$os_version-$os_arch-rhui-rpms" + + ! enable_sm_repo "$repo_rhel" || return 0 + ! enable_rh_repo "$repo_rhui" || return 0 + ! enable_rh_repo "$repo_rhui_alt" || return 0 + ! enable_rh_repo "$repo_rhui_alt2" || return 0 + + report_no_repo "$repo_rhel" + return $RET_FATAL +} + +check_optional() +{ + local repo_rhel="rhel-$os_version-server-optional-rpms" + local repo_rhui="rhel-$os_version-server-rhui-optional-rpms" + + ! enable_sm_repo "$repo_rhel" || return 0 + ! enable_rh_repo "$repo_rhui" || return 0 + + report_no_repo "$repo_rhel" + return $RET_FATAL +} + +check_repos_rhel9() +{ + check_rh_config_manager || return $? + + local rc=0 + + check_epel || rc="$(( $rc | $? ))" + check_codeready || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + return $rc +} + +check_repos_almalinux9() +{ + check_rh_config_manager || return $? + + local rc=0 + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + # powertools is renamed to crb since AlmaLinux 9 + ! enable_rh_repo "crb" || return $rc + + report_no_repo "crb" + return $RET_FATAL +} + +check_repos_cloudlinux9() +{ + check_repos_almalinux9 "$@" +} + +check_repos_almalinux10() +{ + check_repos_almalinux9 "$@" +} + +check_repos_centos8() +{ + check_rh_config_manager || return $? + + local rc=0 + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + # names of repos are lowercased since 8.3 + ! enable_rh_repo "powertools" || return $rc + ! enable_rh_repo "PowerTools" || return $rc + + report_no_repo "powertools" + return $RET_FATAL +} + +check_repos_cloudlinux8() +{ + check_rh_config_manager || return $? + + local rc=0 + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + # names of repos are changed since 8.5 + ! enable_rh_repo "powertools" || return $rc + ! enable_rh_repo "cloudlinux-PowerTools" || return $rc + + report_no_repo "powertools" + return $RET_FATAL +} + +check_repos_rhel8() +{ + check_rh_config_manager || return $? + + local rc=0 + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + [ "$1" = "install" ] || return $rc + + check_codeready || rc="$(( $rc | $? ))" + + return $rc +} + +check_repos_almalinux8() +{ + check_repos_centos8 "$@" +} + +check_repos_rocky8() +{ + check_repos_centos8 "$@" +} + +check_repos_rhel7() +{ + check_rh_config_manager || return $? + + local rc=0 + + check_epel || rc="$(( $rc | $? ))" + check_optional || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + return $rc +} + +check_repos_centos7_based() +{ + check_rh_config_manager || return $? + + local rc=0 + + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + return $rc +} + +sed_escape() +{ + # Note: this is not a full implementation + echo -n "$1" | sed -e 's|\.|\\.|g' +} + +switch_eol_centos_repos() +{ + local old_mirrorlist_host="mirrorlist.centos.org" + local old_host="mirror.centos.org" + local new_host="vault.centos.org" + + grep -qFw "$old_host" /etc/yum.repos.d/CentOS-*.repo 2>/dev/null || return 0 + local backup="`mktemp -d "/tmp/yum.repos.d-$(date --rfc-3339=date)-XXXXXX"`" + ! [ -d "$backup" ] || cp -raT /etc/yum.repos.d "$backup" || : + + sed -i \ + -e "s|^\s*\(mirrorlist\b[^/]*//`sed_escape "$old_mirrorlist_host"`/.*\)$|#\1|" \ + -e "s|^#*\s*baseurl\b\([^/]*\)//`sed_escape "$old_host"`/\(.*\)$|baseurl\1//$new_host/\2|" \ + /etc/yum.repos.d/CentOS-*.repo + echo "YUM package manager repositories were backed up to '$backup' and switched from $old_host to $new_host ." >&2 +} + +check_repos_centos7() +{ + switch_eol_centos_repos + + check_repos_centos7_based "$@" +} + +check_repos_cloudlinux7() +{ + check_repos_centos7_based "$@" +} + +check_repos_virtuozzo7() +{ + check_repos_centos7_based "$@" +} + +find_apt_repo() +{ + local repo="$1" + + local dist_tag= + ! [ "$os_name" = "ubuntu" ] || dist_tag="a" + ! [ "$os_name" = "debian" ] || dist_tag="n" + + if [ -z "$_apt_cache_policy" ]; then + # extract info of each available release as a string which consists of 'tag=value' + # filter out releases with priority less or equal to 100 + _apt_cache_policy="$( + apt-cache policy \ + | grep "b=$pkg_arch" \ + | grep -Eo '([a-z]=[^,]+,?)*' \ + )" + fi + + local l="$(echo "$repo" | cut -f1 -d'/')" + local d="$(echo "$repo" | cut -f2 -d'/')" + local c="$(echo "$repo" | cut -f3 -d'/')" + + # try to find releases by distribution and component + echo "$_apt_cache_policy" \ + | grep -E "(^|,)l=$l(,|$)" \ + | grep -E "(^|,)$dist_tag=$d(,|$)" \ + | grep -E "(^|,)c=$c(,|$)" \ + | while IFS="$(printf '\n')" read rel && [ -n "$rel" ]; do + l="$(echo "$rel" | grep -Eo "(^|,)l=[^,]+" | cut -f2 -d"=")" + d="$(echo "$rel" | grep -Eo "(^|,)$dist_tag=[^,]+" | cut -f2 -d"=")" + c="$(echo "$rel" | grep -Eo "(^|,)c=[^,]+" | cut -f2 -d"=")" + echo "$l/$d/$c" + done +} + +apt_install_packages() +{ + DEBIAN_FRONTEND=noninteractive LANG=C PATH=/usr/sbin:/usr/bin:/sbin:/bin \ + apt-get -qq --assume-yes -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold -o APT::Install-Recommends=no \ + install "$@" +} + +# Takes a list of suites and disables them in APT sources. +# Multiline deb822 format is supported. +disable_apt_suites_deb822() +{ + local python3=/usr/bin/python3 + + "$python3" -c 'import aptsources.sourceslist' 2>/dev/null || + apt_install_packages python3-apt + + "$python3" -c ' +import sys + +from aptsources.sourceslist import SourcesList + + +suites_to_disable=set(sys.argv[1:]) + +sources_list = SourcesList(deb822=True) + +sources_changed = False +for src in sources_list: + if src.invalid: + continue + suites = getattr(src, "suites", ()) + if not suites: + continue + new_suites = [s for s in suites if s not in suites_to_disable] + if len(new_suites) != len(suites): + sources_changed = True + if len(new_suites) == 0: + src.disabled = True + else: + src.suites = new_suites + +if sources_changed: + sources_list.save() +' "$@" + + # Since we have changed the repositories list, we should re-read _apt_cache_policy on a next call + # of the find_apt_repo function. Hence we have to reset the value of the variable + _apt_cache_policy="" +} + +disable_apt_repo() +{ + local repos_to_disable="$(find_apt_repo "$1" | cut -d '/' -f 2,3 | sort | uniq)" + if [ -z "$repos_to_disable" ]; then + return 0 + fi + + echo "$repos_to_disable" \ + | while IFS= read -r repo_to_disable && [ -n "$repo_to_disable" ]; do + local distrib=${repo_to_disable%%/*} + local component=${repo_to_disable##*/} + find /etc/apt -name "*.list" -exec \ + sed -i -e "/^\s*#/! s/.*\s$distrib\s\+$component\b/# &/" {} + + done + + # Since we have changed the repositories list, we should re-read _apt_cache_policy on a next call + # of the find_apt_repo function. Hence we have to reset the value of the variable + _apt_cache_policy="" + + return 0 +} + +check_required_apt_repo() +{ + local repo="$1" + [ -z "$(find_apt_repo "$repo")" ] || return 0 + report_no_repo "$repo" + return $RET_FATAL +} + +check_unsupported_apt_repos_ubuntu() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + + local repos="$( + find_apt_repo "Ubuntu/[^,]+/[^,]+" | grep -v "Ubuntu/$os_codename.*/.*" + find_apt_repo "Debian[^,]*/[^,]+/[^,]+" + )" + [ -n "$repos" ] || return 0 + + echo "$repos" | while IFS="$(printf '\n')" read repo; do + report_unsupported_repo "$repo" + done + + [ "$mode" = "install" ] || return $RET_WARN + return $RET_FATAL +} + +check_repos_ubuntu18() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + local rc=0 + + check_required_apt_repo "Ubuntu/$os_codename/main" || rc="$(( $rc | $? ))" + check_required_apt_repo "Ubuntu/$os_codename/universe" || rc="$(( $rc | $? ))" + check_required_apt_repo "Ubuntu/$os_codename-updates/main" || rc="$(( $rc | $? ))" + check_required_apt_repo "Ubuntu/$os_codename-updates/universe" || rc="$(( $rc | $? ))" + check_unsupported_apt_repos_ubuntu "$mode" || rc="$(( $rc | $? ))" + + return $rc +} + + +check_repos_ubuntu() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + local rc=0 + + check_required_apt_repo "Ubuntu/$os_codename/main" || rc="$(( $rc | $? ))" + check_required_apt_repo "Ubuntu/$os_codename/universe" || rc="$(( $rc | $? ))" + check_unsupported_apt_repos_ubuntu "$mode" || rc="$(( $rc | $? ))" + + return $rc +} + +check_unsupported_apt_repos_debian() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + + local repos="$( + find_apt_repo "Debian Backports/$os_codename-backports/[^,]+" + find_apt_repo "Debian[^,]*/[^,]+/[^,]+" | grep -v "Debian.*/$os_codename.*/.*" + find_apt_repo "Ubuntu/[^,]+/[^,]+" + )" + [ -n "$repos" ] || return 0 + + echo "$repos" | while IFS="$(printf '\n')" read repo; do + report_unsupported_repo "$repo" + done + + [ "$mode" = "install" ] || return $RET_WARN + return $RET_FATAL +} + +check_repos_debian() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + local rc=0 + + if [ "$os_name" = "debian" -a "$os_version" -ge 12 ]; then + disable_apt_suites_deb822 "$os_codename-backports" + else + disable_apt_repo "Debian Backports/$os_codename-backports/[^,]+" + fi + + check_required_apt_repo "Debian/$os_codename/main" || rc="$(( $rc | $? ))" + check_unsupported_apt_repos_debian "$mode" || rc="$(( $rc | $? ))" + + return $rc +} + +# --- + +skip_checker_on_flag "Repository check" "/tmp/plesk-installer-skip-repository-check.flag" + +checker_main 'check_repos' "$1" diff --git a/root/parallels/pool/PSA_18.0.72_17583/examiners/save-installation-info.php b/root/parallels/pool/PSA_18.0.72_17583/examiners/save-installation-info.php new file mode 100644 index 0000000000..748049f4fd --- /dev/null +++ b/root/parallels/pool/PSA_18.0.72_17583/examiners/save-installation-info.php @@ -0,0 +1,61 @@ +allowed_commands = [ + [ + CU_OPT_LONG => 'save', + CU_OPT_PARAM => false, + CU_OPT_DESC => 'Save info about Plesk installation', + ], + ]; + + $this->allowed_options = [ + [ + CU_OPT_LONG => 'mode', + CU_OPT_PARAM => true, + ], + [ + CU_OPT_LONG => 'preset', + CU_OPT_PARAM => true, + ], + [ + CU_OPT_LONG => 'arguments', + CU_OPT_PARAM => true, + ], + ]; + } + + protected function _saveCommand($mode, $preset, $arguments) + { + put_param('installation_mode', $this->getMode($mode)); + put_param('installation_preset', $preset); + put_param('installation_arguments', $arguments); + put_param('installation_finish', time()); + } + + private function getMode($mode) + { + if (!$this->os->isUnix()) { + return $mode; + } + if (empty(getenv('PLESK_ONE_CLICK_INSTALLER'))) { + return $mode; + } + return 'ONE_CLICK'; + } +} + +$app = new InstallationInfo(); +$app->runFromCli(); diff --git a/root/parallels/pool/PSA_18.0.72_17583/examiners/sh_cmd.sh b/root/parallels/pool/PSA_18.0.72_17583/examiners/sh_cmd.sh new file mode 100755 index 0000000000..ed95d0acbb --- /dev/null +++ b/root/parallels/pool/PSA_18.0.72_17583/examiners/sh_cmd.sh @@ -0,0 +1,7 @@ +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ "X${PLESK_INSTALLER_DEBUG}" = "X" ] || set -x +[ "X${PLESK_INSTALLER_STRICT_MODE}" = "X" ] || set -e + +exec "$@" diff --git a/root/parallels/pool/PSA_18.0.72_17583/examiners/tune_memory_swap.sh b/root/parallels/pool/PSA_18.0.72_17583/examiners/tune_memory_swap.sh new file mode 100755 index 0000000000..daea81631e --- /dev/null +++ b/root/parallels/pool/PSA_18.0.72_17583/examiners/tune_memory_swap.sh @@ -0,0 +1,287 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ -z "$PLESK_INSTALLER_DEBUG" ] || set -x +[ -z "$PLESK_INSTALLER_STRICT_MODE" ] || set -e + +export LC_ALL=C +unset GREP_OPTIONS + +RET_SUCCESS=0 +RET_WARN=1 +RET_FATAL=2 + +is_function_defined() +{ + local fn="$1" + case "$(type $fn 2>/dev/null)" in + *function*) + return 0 + ;; + esac + return 1 +} + +detect_platform() +{ + . /etc/os-release + os_name="$ID" + os_version="${VERSION_ID%%.*}" + os_arch="$(uname -m)" + if [ -e /etc/debian_version ]; then + case "$os_arch" in + x86_64) pkg_arch="amd64" ;; + aarch64) pkg_arch="arm64" ;; + esac + if [ -n "$VERSION_CODENAME" ]; then + os_codename="$VERSION_CODENAME" + else + case "$os_name$os_version" in + debian10) os_codename="buster" ;; + debian11) os_codename="bullseye" ;; + debian12) os_codename="bookworm" ;; + ubuntu18) os_codename="bionic" ;; + ubuntu20) os_codename="focal" ;; + ubuntu22) os_codename="jammy" ;; + ubuntu24) os_codename="noble" ;; + esac + fi + fi + + case "$os_name$os_version" in + rhel7|centos7|cloudlinux7|virtuozzo7) + package_manager="yum" + ;; + rhel*|centos*|cloudlinux*|almalinux*|rocky*) + package_manager="dnf" + ;; + debian*|ubuntu*) + package_manager="apt" + ;; + esac + + if [ "$os_name" = "ubuntu" -o "$os_name" = "debian" ]; then + PRODUCT_ROOT_D="/opt/psa" + else + PRODUCT_ROOT_D="/usr/local/psa" + fi +} + +checker_main() +{ + local fnprefix="$1" + shift + + detect_platform + # try to execute checker only if all attributes are detected + [ -n "$os_name" -a -n "$os_version" ] || return $RET_SUCCESS + + for checker in "${fnprefix}_${os_name}${os_version}" "${fnprefix}_${os_name}" "${fnprefix}"; do + if is_function_defined "$checker"; then + local rc=$RET_SUCCESS + "$checker" "$@" || rc=$? + [ "$(( $rc & $RET_FATAL ))" = "0" ] || return $RET_FATAL + [ "$(( $rc & $RET_WARN ))" = "0" ] || return $RET_WARN + return $rc + fi + done + return $RET_SUCCESS +} + +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +# echo message to product log and console (always visible) +pp_echo() +{ + if [ -n "$product_log" ] ; then + echo "$@" >> "$product_log" 2>&1 + fi + echo "$@" >&2 +} + +detect_vz() +{ + [ -z "$PLESK_VZ_RESULT" ] || return $PLESK_VZ_RESULT + + PLESK_VZ_RESULT=1 + PLESK_VZ=0 + PLESK_VE_HW_NODE=0 + PLESK_VZ_TYPE= + + local issue_file="/etc/issue" + local vzcheck_file="/proc/self/status" + [ -f "$vzcheck_file" ] || return 1 + + local env_id=`sed -ne 's|^envID\:[[:space:]]*\([[:digit:]]\+\)$|\1|p' "$vzcheck_file"` + [ -n "$env_id" ] || return 1 + if [ "$env_id" = "0" ]; then + # Either VZ/OpenVZ HW node or unjailed CloudLinux + PLESK_VE_HW_NODE=1 + return 1 + fi + + if grep -q "CloudLinux" "$issue_file" >/dev/null 2>&1 ; then + return 1 + fi + + if [ -f "/proc/vz/veredir" ]; then + PLESK_VZ_TYPE="vz" + elif [ -d "/proc/vz" ]; then + PLESK_VZ_TYPE="openvz" + fi + + PLESK_VZ=1 + PLESK_VZ_RESULT=0 + return 0 +} + +# detects lxc and docker containers +detect_lxc() +{ + [ -z "$PLESK_LXC_RESULT" ] || return $PLESK_LXC_RESULT + PLESK_LXC_RESULT=1 + PLESK_LXC=0 + if { [ -f /proc/1/cgroup ] && grep -q 'docker\|lxc' /proc/1/cgroup; } || \ + { [ -f /proc/1/environ ] && cat /proc/1/environ | tr \\0 \\n | grep -q "container=lxc"; }; + then + PLESK_LXC_RESULT=0 + PLESK_LXC=1 + fi + return "$PLESK_LXC_RESULT" +} +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. +# vim:ft=sh + +set_file_swap_params() +{ + local pleskswaprc='/etc/pleskswaprc' + [ ! -f "$pleskswaprc" ] || . /etc/pleskswaprc + [ -n "$PLESK_SWAP_PATH" ] || PLESK_SWAP_PATH='/pleskswap' + [ -n "$PLESK_SWAP_SIZE" ] || PLESK_SWAP_SIZE='1G' + [ -n "$PLESK_REQUIRED_MEMORY" ] || PLESK_REQUIRED_MEMORY='1G' + + FSTAB='/etc/fstab' +} + +file_swap_is_required() +{ + local total_mem_mib=$(LC_ALL=C LANG=C free -m -t | awk '/^Total:/ { print $2 }') + local required_mem_mib="`units2units $PLESK_REQUIRED_MEMORY M`" + [ "$total_mem_mib" -lt "$required_mem_mib" ] || return 1 + pp_echo "Total amount of memory is less than minimal required size (${total_mem_mib}M < ${required_mem_mib}M)" + return 0 +} + +file_swap_is_switched_off() +{ + case "${PLESK_SWAP:-}" in + 0|false|disable) + pp_echo "Swapfile creation is disabled: envirinment vaiable \$PLESK_SWAP='$PLESK_SWAP'." + return 0 + ;; + esac + + if [ -f "/etc/pleskswapdisable" ]; then + pp_echo "Swapfile creation is disabled: file '/etc/pleskswapdisable' is present." + return 0 + fi + + detect_vz + if [ "$PLESK_VZ" = "1" ]; then + pp_echo "Swapfile creation is disabled: installation into Virtuozzo container." + return 0 + fi + + detect_lxc + if [ "$PLESK_LXC" = "1" ]; then + pp_echo "Swapfile creation is disabled: installation into Docker/LXC container." + return 0 + fi + + return 1 +} + +file_swap_enable() +{ + if file_swap_status; then + echo "Error: Plesk swapfile is already enabled." >&2 + return 1 + fi + + local swap_size_mb="`units2units $PLESK_SWAP_SIZE M`" + + pp_echo "===> Enable swapfile in $PLESK_SWAP_PATH" + dd if=/dev/zero of="$PLESK_SWAP_PATH" bs=1M count="$swap_size_mb" status=none || return 1 + chmod 0600 "$PLESK_SWAP_PATH" || return 1 + mkswap "$PLESK_SWAP_PATH" || return 1 + if ! grep -qw "^$PLESK_SWAP_PATH" "${FSTAB}"; then + cp -f "${FSTAB}" "${FSTAB}.saved_by_plesk" + echo "$PLESK_SWAP_PATH none swap sw 0 0" >> "${FSTAB}" + fi + if swapon "$PLESK_SWAP_PATH"; then + rm -f "${FSTAB}.saved_by_plesk" + return 0 + else + [ ! -f "${FSTAB}.saved_by_plesk" ] || mv -f "${FSTAB}.saved_by_plesk" "${FSTAB}" + return 1 + fi +} + +file_swap_status() +{ + [ -f "$PLESK_SWAP_PATH" ] || return 1 + grep -qw "^$PLESK_SWAP_PATH" "${FSTAB}" || return 1 + return 0 +} + +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +units2units() { + local bytes + local n="${1%%[^0-9]*}" + case "${1,,}" in + *[0-9]) bytes="$1" ;; + *k|*kib) bytes="$(( $n * 1024 ** 1 ))" ;; + *m|*mib) bytes="$(( $n * 1024 ** 2 ))" ;; + *g|*gib) bytes="$(( $n * 1024 ** 3 ))" ;; + *t|*tib) bytes="$(( $n * 1024 ** 4 ))" ;; + *kb) bytes="$(( $n * 1000 ** 1 ))" ;; + *mb) bytes="$(( $n * 1000 ** 2 ))" ;; + *gb) bytes="$(( $n * 1000 ** 3 ))" ;; + *tb) bytes="$(( $n * 1000 ** 4 ))" ;; + *) echo "units2units: incorrect value '$1'" >&2; exit 1 ;; + esac + case "${2,,}" in + k|kib) echo $(( $bytes / 1024 ** 1 )) ;; + m|mib) echo $(( $bytes / 1024 ** 2 )) ;; + g|gib) echo $(( $bytes / 1024 ** 3 )) ;; + t|tib) echo $(( $bytes / 1024 ** 4 )) ;; + kb) echo $(( $bytes / 1000 ** 1 )) ;; + mb) echo $(( $bytes / 1000 ** 2 )) ;; + gb) echo $(( $bytes / 1000 ** 3 )) ;; + tb) echo $(( $bytes / 1000 ** 4 )) ;; + "") echo $bytes ;; + *) echo "Unknown unit: $2" >&2; exit 1 ;; + esac +} + +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +tune_memory_swap() +{ + local mode="$1" + [ "$mode" = 'install' ] || return 0 # clean install only + set_file_swap_params + file_swap_is_required || return 0 + ! file_swap_is_switched_off || return 0 # disabled by admin + ! file_swap_status || return 0 # already enabled + if ! file_swap_enable; then + pp_echo "Failed to enable swapfile. Installation may fail or freeze due to insufficient memory." + return "$RET_WARN" + fi +} + +product_log= +product_problems_log= +checker_main 'tune_memory_swap' "$1" diff --git a/root/parallels/pool/PSA_18.0.72_17583/plesk-18.0.72-ubt24.04-x86_64.inf3 b/root/parallels/pool/PSA_18.0.72_17583/plesk-18.0.72-ubt24.04-x86_64.inf3 new file mode 100644 index 0000000000..41a00736ae --- /dev/null +++ b/root/parallels/pool/PSA_18.0.72_17583/plesk-18.0.72-ubt24.04-x86_64.inf3 @@ -0,0 +1,927 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -----BEGIN PGP PUBLIC KEY BLOCK----- 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 VNnMRY8n =Hv0N -----END PGP PUBLIC KEY BLOCK----- + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + + + + + mysqlgroup + l10n + proftpd + webservers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + imapservers + + + + + + + + + + + + + + + + + + + imapservers + + + + + + + + + + + + + + mailman + spamassassin + drweb + sophos + courier + dovecot + + + + + + + + + + + + + + + + + + + + + + mailservers + + + + + + + + + + + + + + + + + + + + mailservers + + + + + + + + + + + + + + + + + + panel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + webservers + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + + + + + + + + + + + + + + + + php7.4 + + + + + + + + + + + + + + + + + + + + + + + + + + php8.3 + + + + + + + + + + + webservers + + + + + + + + webservers + + + + + + + + + + + + + + + + + + panel + + + + + + + + + + + + + panel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + panel + + + + + + + + + + + + + + + + + + + + panel + + + + + + + panel + + + + + + + + panel + + + + + + + panel + passenger + + + + + + ruby + + + + + + + panel + + + + + + panel + + + + + + panel + passenger + + + + + + + + + + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + panel + roundcube + postfix + dovecot + mod_fcgid + proftpd + webalizer + awstats + webservers + nginx + mysqlgroup + l10n + bind + wp-toolkit + advisor + git + xovi + imunify360 + fail2ban + modsecurity + sslit + letsencrypt + repair-kit + composer + monitoring + log-browser + ssh-terminal + site-import + sitejet + ntp-timesync + php8.3 + php8.4 + mfa + configurations-troubleshooter + + + panel + roundcube + postfix + dovecot + mod_fcgid + proftpd + webalizer + awstats + webservers + nginx + mysqlgroup + l10n + bind + wp-toolkit + advisor + git + xovi + imunify360 + fail2ban + modsecurity + sslit + letsencrypt + repair-kit + composer + monitoring + log-browser + ssh-terminal + site-import + sitejet + ntp-timesync + php8.1 + php8.2 + php8.3 + php8.4 + mfa + configurations-troubleshooter + resctrl + drweb + postgresql + spamassassin + ruby + gems-pre + nodejs + pmm + psa-firewall + watchdog + passenger + phpgroup + sophos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.72_17583/release.inf3 b/root/parallels/pool/PSA_18.0.72_17583/release.inf3 new file mode 100644 index 0000000000..7cf5f49dae --- /dev/null +++ b/root/parallels/pool/PSA_18.0.72_17583/release.inf3 @@ -0,0 +1,35 @@ + + + + + + + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.73_17652/release.inf3 b/root/parallels/pool/PSA_18.0.73_17652/release.inf3 new file mode 100644 index 0000000000..4fb000283d --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17652/release.inf3 @@ -0,0 +1,36 @@ + + + + + + + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.73_17686/release.inf3 b/root/parallels/pool/PSA_18.0.73_17686/release.inf3 new file mode 100644 index 0000000000..4fb000283d --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17686/release.inf3 @@ -0,0 +1,36 @@ + + + + + + + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.73_17695/release.inf3 b/root/parallels/pool/PSA_18.0.73_17695/release.inf3 new file mode 100644 index 0000000000..4fb000283d --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17695/release.inf3 @@ -0,0 +1,36 @@ + + + + + + + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.73_17725/examiners/check_broken_timezone.sh b/root/parallels/pool/PSA_18.0.73_17725/examiners/check_broken_timezone.sh new file mode 100755 index 0000000000..ee862642be --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17725/examiners/check_broken_timezone.sh @@ -0,0 +1,255 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ -z "$PLESK_INSTALLER_DEBUG" ] || set -x +[ -z "$PLESK_INSTALLER_STRICT_MODE" ] || set -e + +export LC_ALL=C +unset GREP_OPTIONS + +RET_SUCCESS=0 +RET_WARN=1 +RET_FATAL=2 + +is_function_defined() +{ + local fn="$1" + case "$(type $fn 2>/dev/null)" in + *function*) + return 0 + ;; + esac + return 1 +} + +# @params are tags in format "key=value" +# Report body (human readable information) is read from stdin +# and copied to stderr. +make_error_report() +{ + local report_file="${PLESK_INSTALLER_ERROR_REPORT:-}" + + local python_bin= + for bin in "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2" "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3"; do + if [ -x "$bin" ]; then + python_bin="$bin" + break + fi + done + + if [ -n "$report_file" -a -x "$python_bin" ]; then + "$python_bin" -c 'import sys, json +report_file = sys.argv[1] +error = sys.stdin.read() + +sys.stderr.write(error) + +data = { + "error": error, +} + +for tag in sys.argv[2:]: + k, v = tag.split("=", 1) + data[k] = v + +with open(report_file, "a") as f: + json.dump(data, f) + f.write("\n") +' "$report_file" "date=$(date --utc --iso-8601=ns)" "$@" + else + cat - >&2 + fi +} + +detect_platform() +{ + . /etc/os-release + os_name="$ID" + os_version="${VERSION_ID%%.*}" + os_arch="$(uname -m)" + if [ -e /etc/debian_version ]; then + case "$os_arch" in + x86_64) pkg_arch="amd64" ;; + aarch64) pkg_arch="arm64" ;; + esac + if [ -n "$VERSION_CODENAME" ]; then + os_codename="$VERSION_CODENAME" + else + case "$os_name$os_version" in + debian10) os_codename="buster" ;; + debian11) os_codename="bullseye" ;; + debian12) os_codename="bookworm" ;; + ubuntu18) os_codename="bionic" ;; + ubuntu20) os_codename="focal" ;; + ubuntu22) os_codename="jammy" ;; + ubuntu24) os_codename="noble" ;; + esac + fi + fi + + case "$os_name$os_version" in + rhel7|centos7|cloudlinux7|virtuozzo7) + package_manager="yum" + ;; + rhel*|centos*|cloudlinux*|almalinux*|rocky*) + package_manager="dnf" + ;; + debian*|ubuntu*) + package_manager="apt" + ;; + esac + + if [ "$os_name" = "ubuntu" -o "$os_name" = "debian" ]; then + PRODUCT_ROOT_D="/opt/psa" + else + PRODUCT_ROOT_D="/usr/local/psa" + fi +} + +has_os_impl_function() +{ + local prefix="$1" + local fn="${prefix}_${os_name}${os_version}" + is_function_defined "$fn" +} + +call_os_impl_function() +{ + local prefix="$1" + shift + local fn="${prefix}_${os_name}${os_version}" + "$fn" "$@" +} + +skip_checker_on_flag() +{ + local name="$1" + local flag="$2" + + if [ -f "$flag" ]; then + echo "$name was skipped due to flag file." >&2 + exit $RET_SUCCESS + fi +} + +skip_checker_on_env() +{ + local name="$1" + local env="$2" + + if [ -n "$env" ]; then + echo "$name was skipped due to environment variable." >&2 + exit $RET_SUCCESS + fi +} + +checker_main() +{ + local fnprefix="$1" + shift + + detect_platform + # try to execute checker only if all attributes are detected + [ -n "$os_name" -a -n "$os_version" ] || return $RET_SUCCESS + + for checker in "${fnprefix}_${os_name}${os_version}" "${fnprefix}_${os_name}" "${fnprefix}"; do + if is_function_defined "$checker"; then + local rc=$RET_SUCCESS + "$checker" "$@" || rc=$? + [ "$(( $rc & $RET_FATAL ))" = "0" ] || return $RET_FATAL + [ "$(( $rc & $RET_WARN ))" = "0" ] || return $RET_WARN + return $rc + fi + done + return $RET_SUCCESS +} + +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +# If env variable PLESK_INSTALLER_ERROR_REPORT=path_to_file is specified then in case of error +# check-broken-tz.sh writes single line json report into it with the following fields: +# - "stage": "timezonefix" +# - "level": "error" +# - "errtype": "failure" +# - "date": time of error occurance ("2024-07-24T06:59:43,127545441+0000") +# - "error": human readable error message + +report_dpkg_configure_fail() +{ + local pkgname="$1" + make_error_report 'stage=timezonefix' 'level=error' 'errtype=dpkgconfigurefailed' <<-EOL + Could not configure the packages ( $pkgname ). See https://support.plesk.com/hc/en-us/articles/24721507961623-Plesk-provides-error-on-update-Package-tzdata-is-not-configured-yet for more details. + EOL +} + +report_get_tz_fail() +{ + make_error_report 'stage=timezonefix' 'level=error' 'errtype=gettzfailed' <<-EOL + Could not get the system timezone. See https://support.plesk.com/hc/en-us/articles/24721507961623-Plesk-provides-error-on-update-Package-tzdata-is-not-configured-yet for more details. + EOL +} + +report_set_tz_fail() +{ + local tz="$1" + + make_error_report 'stage=timezonefix' 'level=error' 'errtype=settzfailed' <<-EOL + Could not set the system timezone ( $tz ). See https://support.plesk.com/hc/en-us/articles/24721507961623-Plesk-provides-error-on-update-Package-tzdata-is-not-configured-yet for more details. + EOL +} + +get_current_tz() +{ + [ -L /etc/localtime ] || return 1 + + local tz + tz="$(readlink -m /etc/localtime)" || return 1 + [ -f "$tz" ] || return 1 + case "$tz" in + /usr/share/zoneinfo/*) ;; + *) return 1;; + esac + tz="${tz#/usr/share/zoneinfo/}" + [ -n "$tz" ] || return 1 + + echo -n "${tz}" +} + +check_timezone_ubuntu() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + + # PPP-65676: Plesk update fails on ubuntu if timezone is CET + if dpkg-query --showformat='${db:Status-Status}\n' --show 'tzdata' | grep -wq 'half-configured'; then + local origtz + origtz=$(get_current_tz) + if [ $? != 0 ]; then + report_get_tz_fail + return $RET_WARN + fi + if ! timedatectl set-timezone 'Etc/UTC'; then + timedatectl set-timezone "$origtz" + report_set_tz_fail 'Etc/UTC' + return $RET_WARN + fi + if ! dpkg --configure 'tzdata'; then + timedatectl set-timezone "$origtz" + report_dpkg_configure_fail 'tzdata' + return $RET_WARN + fi + if ! timedatectl set-timezone "$origtz"; then + report_set_tz_fail "$origtz" + return $RET_WARN + fi + fi + + return 0 +} + +# --- + +skip_checker_on_flag "Broken timezone check" "/tmp/plesk-installer-skip-check-broken-timezone.flag" + +checker_main 'check_timezone' "$1" diff --git a/root/parallels/pool/PSA_18.0.73_17725/examiners/congratulations.sh b/root/parallels/pool/PSA_18.0.73_17725/examiners/congratulations.sh new file mode 100755 index 0000000000..907c5ba782 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17725/examiners/congratulations.sh @@ -0,0 +1,50 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +out() +{ + echo -e "\t$*" >&2 +} + +print_urls() +{ + plesk login 2>/dev/null | sed -e $'s|^|\t * |' >&2 +} + +print_congratulations() +{ + local mode="$1" # 'install' or 'upgrade' + local process= + [ "$mode" = "install" ] && process="installation" || process="upgrade" + + out + out " Congratulations!" + out + out "The $process has been finished. Plesk is now running on your server." + out + if [ "$mode" = "install" ]; then + out "To complete the configuration process, browse either of URLs:" + print_urls + out + fi + out "Use the username 'admin' to log in. To log in as 'admin', use the 'plesk login' command." + out "You can also log in as 'root' using your 'root' password." + out + out "Use the 'plesk' command to manage the server. Run 'plesk help' for more info." + out + out "Use the following commands to start and stop the Plesk web interface:" + out "'systemctl start psa.service' and 'systemctl stop psa.service' respectively." + out + if [ "$mode" = "install" ]; then + out "If you would like to migrate your subscriptions from other hosting panel" + out "or older Plesk version to this server, please check out our assistance" + out "options: https://www.plesk.com/professional-services/" + out + fi +} + +unset GREP_OPTIONS + +print_congratulations "$1" +# Force showing text when used as AI post-examiner +exit 1 diff --git a/root/parallels/pool/PSA_18.0.73_17725/examiners/disk_space_check.sh b/root/parallels/pool/PSA_18.0.73_17725/examiners/disk_space_check.sh new file mode 100755 index 0000000000..1fdfb44037 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17725/examiners/disk_space_check.sh @@ -0,0 +1,542 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ -z "$PLESK_INSTALLER_DEBUG" ] || set -x +[ -z "$PLESK_INSTALLER_STRICT_MODE" ] || set -e + +export LC_ALL=C +unset GREP_OPTIONS + +RET_SUCCESS=0 +RET_WARN=1 +RET_FATAL=2 + +is_function_defined() +{ + local fn="$1" + case "$(type $fn 2>/dev/null)" in + *function*) + return 0 + ;; + esac + return 1 +} + +# @params are tags in format "key=value" +# Report body (human readable information) is read from stdin +# and copied to stderr. +make_error_report() +{ + local report_file="${PLESK_INSTALLER_ERROR_REPORT:-}" + + local python_bin= + for bin in "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2" "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3"; do + if [ -x "$bin" ]; then + python_bin="$bin" + break + fi + done + + if [ -n "$report_file" -a -x "$python_bin" ]; then + "$python_bin" -c 'import sys, json +report_file = sys.argv[1] +error = sys.stdin.read() + +sys.stderr.write(error) + +data = { + "error": error, +} + +for tag in sys.argv[2:]: + k, v = tag.split("=", 1) + data[k] = v + +with open(report_file, "a") as f: + json.dump(data, f) + f.write("\n") +' "$report_file" "date=$(date --utc --iso-8601=ns)" "$@" + else + cat - >&2 + fi +} + +detect_platform() +{ + . /etc/os-release + os_name="$ID" + os_version="${VERSION_ID%%.*}" + os_arch="$(uname -m)" + if [ -e /etc/debian_version ]; then + case "$os_arch" in + x86_64) pkg_arch="amd64" ;; + aarch64) pkg_arch="arm64" ;; + esac + if [ -n "$VERSION_CODENAME" ]; then + os_codename="$VERSION_CODENAME" + else + case "$os_name$os_version" in + debian10) os_codename="buster" ;; + debian11) os_codename="bullseye" ;; + debian12) os_codename="bookworm" ;; + ubuntu18) os_codename="bionic" ;; + ubuntu20) os_codename="focal" ;; + ubuntu22) os_codename="jammy" ;; + ubuntu24) os_codename="noble" ;; + esac + fi + fi + + case "$os_name$os_version" in + rhel7|centos7|cloudlinux7|virtuozzo7) + package_manager="yum" + ;; + rhel*|centos*|cloudlinux*|almalinux*|rocky*) + package_manager="dnf" + ;; + debian*|ubuntu*) + package_manager="apt" + ;; + esac + + if [ "$os_name" = "ubuntu" -o "$os_name" = "debian" ]; then + PRODUCT_ROOT_D="/opt/psa" + else + PRODUCT_ROOT_D="/usr/local/psa" + fi +} + +has_os_impl_function() +{ + local prefix="$1" + local fn="${prefix}_${os_name}${os_version}" + is_function_defined "$fn" +} + +call_os_impl_function() +{ + local prefix="$1" + shift + local fn="${prefix}_${os_name}${os_version}" + "$fn" "$@" +} + +skip_checker_on_flag() +{ + local name="$1" + local flag="$2" + + if [ -f "$flag" ]; then + echo "$name was skipped due to flag file." >&2 + exit $RET_SUCCESS + fi +} + +skip_checker_on_env() +{ + local name="$1" + local env="$2" + + if [ -n "$env" ]; then + echo "$name was skipped due to environment variable." >&2 + exit $RET_SUCCESS + fi +} + +checker_main() +{ + local fnprefix="$1" + shift + + detect_platform + # try to execute checker only if all attributes are detected + [ -n "$os_name" -a -n "$os_version" ] || return $RET_SUCCESS + + for checker in "${fnprefix}_${os_name}${os_version}" "${fnprefix}_${os_name}" "${fnprefix}"; do + if is_function_defined "$checker"; then + local rc=$RET_SUCCESS + "$checker" "$@" || rc=$? + [ "$(( $rc & $RET_FATAL ))" = "0" ] || return $RET_FATAL + [ "$(( $rc & $RET_WARN ))" = "0" ] || return $RET_WARN + return $rc + fi + done + return $RET_SUCCESS +} + +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +# If env variable PLESK_INSTALLER_ERROR_REPORT=path_to_file is specified then in case of error +# disk_space_check.sh writes single line json report into it with the following fields: +# - "stage": "diskspacecheck" +# - "level": "error" +# - "errtype": "notenoughdiskspace" +# - "volume": volume with not enough diskspace (e.g. "/") +# - "required": required diskspace on the volume, human readable (e.g. "600 MB") +# - "available": available diskspace on the volume, human readable (e.g. "255 MB") +# - "needtofree": amount of diskspace which should be freed on the volume, human readable (e.g. "345 MB") +# - "date": time of error occurance ("2020-03-24T06:59:43,127545441+0000") +# - "error": human readable error message ("There is not enough disk space available in the / directory.") + +# Required values below for Full installation are in MB. See 'du -cs -BM /*' and 'df -Pm'. + +required_disk_space_cloudlinux7() +{ + case "$1" in + /opt) echo 900 ;; + /usr) echo 4400 ;; + /var) echo 600 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_cloudlinux8() +{ + case "$1" in + /opt) echo 1200 ;; + /usr) echo 4400 ;; + /var) echo 700 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_centos7() +{ + case "$1" in + /opt) echo 900 ;; + /usr) echo 4100 ;; + /var) echo 600 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_centos8() +{ + case "$1" in + /opt) echo 900 ;; + /usr) echo 4500 ;; + /var) echo 800 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_virtuozzo7() +{ + required_disk_space_centos7 "$1" +} + +required_disk_space_rhel7() +{ + required_disk_space_centos7 "$1" +} + +required_disk_space_rhel8() +{ + required_disk_space_centos8 "$1" +} + +required_disk_space_almalinux8() +{ + required_disk_space_centos8 "$1" +} + +required_disk_space_rocky8() +{ + required_disk_space_centos8 "$1" +} + +required_disk_space_rhel9() +{ + case "$1" in + /opt) echo 500 ;; + /usr) echo 4000 ;; + /var) echo 800 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_almalinux9() +{ + required_disk_space_rhel9 "$1" +} + +required_disk_space_almalinux10() +{ + required_disk_space_almalinux9 "$1" +} + +required_disk_space_cloudlinux9() +{ + required_disk_space_rhel9 "$1" +} + +required_disk_space_debian10() +{ + case "$1" in + /opt) echo 1800 ;; + /usr) echo 2300 ;; + /var) echo 1700 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_debian11() +{ + case "$1" in + /opt) echo 1500 ;; + /usr) echo 3100 ;; + /var) echo 1800 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_debian12() +{ + case "$1" in + /opt) echo 2700 ;; + /usr) echo 2500 ;; + /var) echo 2200 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_debian13() +{ + case "$1" in + /opt) echo 2700 ;; + /usr) echo 2500 ;; + /var) echo 2200 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_ubuntu18() +{ + case "$1" in + /opt) echo 900 ;; + /usr) echo 1800 ;; + /var) echo 600 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_ubuntu20() +{ + case "$1" in + /opt) echo 1800 ;; + /usr) echo 2900 ;; + /var) echo 1600 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_ubuntu22() +{ + case "$1" in + /opt) echo 1800 ;; + /usr) echo 3900 ;; + /var) echo 1900 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_ubuntu24() +{ + case "$1" in + /opt) echo 3200 ;; + /usr) echo 1800 ;; + /var) echo 2400 ;; + /tmp) echo 100 ;; + esac +} + +required_update_upgrade_disk_space() +{ + case "$1" in + /opt) echo 100 ;; + /usr) echo 300 ;; + /var) echo 600 ;; + /tmp) echo 100 ;; + esac +} + +clean_tmp() +{ + local volume="$1" + local path="/tmp" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'systemd-tmpfiles --clean --prefix $path'" + systemd-tmpfiles --clean --prefix "$path" 2>&1 +} + +clean_yum() +{ + local volume="$1" + local path="/var/cache/yum" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'yum clean all'" + yum clean all 2>&1 + + # The command above doesn't clean untracked repos (missing in configuration), clean if left > 2 Mb + [ "`du -sm "$path" | awk '{ print $1 }'`" -gt 2 ] || return 0 + echo "Cleaning $path via 'rm -rf $path/*'" + rm -rf "$path"/* 2>&1 +} + +clean_dnf() +{ + local volume="$1" + local path="/var/cache/dnf" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'dnf clean all'" + dnf clean all 2>&1 +} + +clean_apt() +{ + local volume="$1" + local path="/var/cache/apt" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'apt-get clean'" + apt-get clean 2>&1 +} + +clean_journal() +{ + local volume="$1" + local path="/var/log/journal" + is_path_on_volume "$path" "$volume" || return 0 + + # Note that --rotate may cause more space to be freed, but may also cause more space to be used + echo "Cleaning $path via 'journalctl --vacuum-time 1d'" + journalctl --vacuum-time 1d 2>&1 +} + +clean_ext_packages() +{ + local volume="$1" + local path="$PRODUCT_ROOT_D/var/modules-packages" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'rm -rf $path/*'" + rm -rf "$path"/* 2>&1 +} + +# @param $1 target directory +mount_point() +{ + df -Pm $1 | awk 'NR==2 { print $6 }' +} + +# @param $1 target directory +available_disk_space() +{ + df -Pm $1 | awk 'NR==2 { print $4 }' +} + +is_path_on_volume() +{ + local path="$1" + local volume="$2" + [ -d "$path" ] && [ "`mount_point "$path"`" = "$volume" ] +} + +# @param $1 target directory +# @param $2 mode (install/upgrade/update) +req_disk_space() +{ + if [ "$2" != "install" ]; then + required_update_upgrade_disk_space "$1" + return + fi + + has_os_impl_function "required_disk_space" || { + echo "There are no requirements defined for $os_name$os_version." >&2 + echo "Disk space check cannot be performed." >&2 + exit $RET_WARN + } + call_os_impl_function "required_disk_space" "$1" +} + +human_readable_size() +{ + echo "$1" | awk ' + function human(x) { + s = "MGTEPYZ"; + while (x >= 1000 && length(s) > 1) { + x /= 1024; s = substr(s, 2); + } + # 0.05 below will make sure the value is rounded up + return sprintf("%.1f %sB", x + 0.05, substr(s, 1, 1)); + } + { print human($1); }' +} + +# @param $1 target directory +# @param $2 required disk space +# @param $3 check only flag (don't emit errors) +check_available_disk_space() +{ + local volume="$1" + local required="$2" + local check_only="${3:-}" + local available="$(available_disk_space "$volume")" + if [ "$available" -lt "$required" ]; then + local needtofree + needtofree="`human_readable_size $((required - available))`" + [ -n "$check_only" ] || + make_error_report 'stage=diskspacecheck' 'level=error' 'errtype=notenoughdiskspace' \ + "volume=$volume" "required=$required MB" "available=$available MB" "needtofree=$needtofree" \ + <<-EOL + There is not enough disk space available in the $1 directory. + You need to free up $needtofree. + EOL + return "$RET_FATAL" + fi +} + +# @param $1 target directory +# @param $2 required disk space +clean_and_check_available_disk_space() +{ + if [ -n "$PLESK_INSTALLER_FORCE_CLEAN_DISK_SPACE" ] || ! check_available_disk_space "$@" --check-only; then + clean_disk_space "$1" + check_available_disk_space "$@" + fi +} + +# Cleans up disk space on the volume +clean_disk_space() +{ + local volume="$1" + for cleanup_func in clean_tmp clean_yum clean_dnf clean_apt clean_journal clean_ext_packages; do + "$cleanup_func" "$volume" + done +} + +# @param $1 mode (install/upgrade/update) +clean_and_check_disk_space() +{ + local mode="$1" + local shared=0 + + for target_directory in /opt /usr /var /tmp; do + local required=$(req_disk_space "$target_directory" "$mode") + [ -n "$required" ] || return "$RET_WARN" + + if is_path_on_volume "$target_directory" "/"; then + shared="$((shared + required))" + else + clean_and_check_available_disk_space "$target_directory" "$required" || return $? + fi + done + + clean_and_check_available_disk_space "/" "$shared" || return $? +} + +checker_main 'clean_and_check_disk_space' "$1" diff --git a/root/parallels/pool/PSA_18.0.73_17725/examiners/license_key_check.php b/root/parallels/pool/PSA_18.0.73_17725/examiners/license_key_check.php new file mode 100644 index 0000000000..917e44709f --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17725/examiners/license_key_check.php @@ -0,0 +1,111 @@ += 10.0.0 */ +if (!is_array($vers)) { + $vers = [$vers]; +} + +$match = false; +foreach ($vers as $ver) { + if (!is_array($ver)) { + $match |= strtok($ver, ".") == strtok($targetVersion, "."); + } else { + $match |= ("any" == $ver[0] || version_compare($ver[0], $targetVersion) <= 0) && + ("any" == $ver[1] || version_compare($ver[1], $targetVersion) >= 0); + } +} + +if ($match) { + fwrite(STDERR, "You do not need to upgrade the current license key.\n"); + fwrite(STDOUT, "License upgrade check to $targetVersion can be skipped.\n"); + fwrite(STDOUT, "Plesk versions compatible with the license key: " . preg_replace('/\n\s*/', '', var_export($vers, true)) . "\n"); + finish(0); +} + +if (!function_exists('ka_is_key_upgrade_available')) { + // Plesk 17.0 + fwrite(STDERR, "Cannot check whether Plesk license key upgrade is available.\n"); + finish(1, false); +} + +$si = getServerInfo(); +$result = ka_is_key_upgrade_available($prod, $targetVersion, $si); + +$isConfused = false; +switch ($result['code']) { + case RESULT_LICENSE_OK: + fwrite(STDERR, "The licensing server accepted the key upgrade request.\n"); + fwrite(STDERR, "License upgrade to $targetVersion is available.\n"); + fwrite(STDERR, "Response from the licensing server: {$result['message']}\n"); + finish(0); + case RESULT_NETWORK_PROBLEM: + fwrite(STDERR, "Unable to connect to the licensing server to check if license upgrade is available.\n"); + fwrite(STDERR, "Error message: {$result['message']}\n"); + finish(2, false); + case RESULT_LICENSE_PROBLEM: + fwrite(STDERR, "Warning: Your Plesk license key cannot be upgraded.\n"); + fwrite(STDERR, "Response from the licensing server: {$result['message']}\n"); + finish(2); + default: + $isConfused = true; + // fall-through + case RESULT_ERROR: + // This includes "Software Update Service (SUS) is not found for the given license key" case, but also many others. + fwrite(STDERR, "Failed to check whether a new license key is available.\n"); + fwrite(STDERR, "Error message: {$result['message']}\n"); + if ($isConfused) { + fwrite(STDERR, "Error code: {$result['code']}\n"); + } + finish(2, !$isConfused); +} diff --git a/root/parallels/pool/PSA_18.0.73_17725/examiners/package_manager_check.sh b/root/parallels/pool/PSA_18.0.73_17725/examiners/package_manager_check.sh new file mode 100755 index 0000000000..b089061d97 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17725/examiners/package_manager_check.sh @@ -0,0 +1,224 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ -z "$PLESK_INSTALLER_DEBUG" ] || set -x +[ -z "$PLESK_INSTALLER_STRICT_MODE" ] || set -e + +export LC_ALL=C +unset GREP_OPTIONS + +RET_SUCCESS=0 +RET_WARN=1 +RET_FATAL=2 + +is_function_defined() +{ + local fn="$1" + case "$(type $fn 2>/dev/null)" in + *function*) + return 0 + ;; + esac + return 1 +} + +# @params are tags in format "key=value" +# Report body (human readable information) is read from stdin +# and copied to stderr. +make_error_report() +{ + local report_file="${PLESK_INSTALLER_ERROR_REPORT:-}" + + local python_bin= + for bin in "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2" "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3"; do + if [ -x "$bin" ]; then + python_bin="$bin" + break + fi + done + + if [ -n "$report_file" -a -x "$python_bin" ]; then + "$python_bin" -c 'import sys, json +report_file = sys.argv[1] +error = sys.stdin.read() + +sys.stderr.write(error) + +data = { + "error": error, +} + +for tag in sys.argv[2:]: + k, v = tag.split("=", 1) + data[k] = v + +with open(report_file, "a") as f: + json.dump(data, f) + f.write("\n") +' "$report_file" "date=$(date --utc --iso-8601=ns)" "$@" + else + cat - >&2 + fi +} + +detect_platform() +{ + . /etc/os-release + os_name="$ID" + os_version="${VERSION_ID%%.*}" + os_arch="$(uname -m)" + if [ -e /etc/debian_version ]; then + case "$os_arch" in + x86_64) pkg_arch="amd64" ;; + aarch64) pkg_arch="arm64" ;; + esac + if [ -n "$VERSION_CODENAME" ]; then + os_codename="$VERSION_CODENAME" + else + case "$os_name$os_version" in + debian10) os_codename="buster" ;; + debian11) os_codename="bullseye" ;; + debian12) os_codename="bookworm" ;; + ubuntu18) os_codename="bionic" ;; + ubuntu20) os_codename="focal" ;; + ubuntu22) os_codename="jammy" ;; + ubuntu24) os_codename="noble" ;; + esac + fi + fi + + case "$os_name$os_version" in + rhel7|centos7|cloudlinux7|virtuozzo7) + package_manager="yum" + ;; + rhel*|centos*|cloudlinux*|almalinux*|rocky*) + package_manager="dnf" + ;; + debian*|ubuntu*) + package_manager="apt" + ;; + esac + + if [ "$os_name" = "ubuntu" -o "$os_name" = "debian" ]; then + PRODUCT_ROOT_D="/opt/psa" + else + PRODUCT_ROOT_D="/usr/local/psa" + fi +} + +has_os_impl_function() +{ + local prefix="$1" + local fn="${prefix}_${os_name}${os_version}" + is_function_defined "$fn" +} + +call_os_impl_function() +{ + local prefix="$1" + shift + local fn="${prefix}_${os_name}${os_version}" + "$fn" "$@" +} + +skip_checker_on_flag() +{ + local name="$1" + local flag="$2" + + if [ -f "$flag" ]; then + echo "$name was skipped due to flag file." >&2 + exit $RET_SUCCESS + fi +} + +skip_checker_on_env() +{ + local name="$1" + local env="$2" + + if [ -n "$env" ]; then + echo "$name was skipped due to environment variable." >&2 + exit $RET_SUCCESS + fi +} + +checker_main() +{ + local fnprefix="$1" + shift + + detect_platform + # try to execute checker only if all attributes are detected + [ -n "$os_name" -a -n "$os_version" ] || return $RET_SUCCESS + + for checker in "${fnprefix}_${os_name}${os_version}" "${fnprefix}_${os_name}" "${fnprefix}"; do + if is_function_defined "$checker"; then + local rc=$RET_SUCCESS + "$checker" "$@" || rc=$? + [ "$(( $rc & $RET_FATAL ))" = "0" ] || return $RET_FATAL + [ "$(( $rc & $RET_WARN ))" = "0" ] || return $RET_WARN + return $rc + fi + done + return $RET_SUCCESS +} + +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +check_package_manager_deb_based() +{ + local output= + output="`dpkg --audit 2>&1`" || output="$output"$'\n'"'dpkg --audit' finished with error code $?." + + if [ -n "$output" ]; then + make_error_report 'stage=packagemanagercheck' 'level=error' 'errtype=brokenpackages' <<-EOL + The system package manager reports the following problems: + + $output + + To continue with the installation, you need to resolve these issues + using the procedure below: + + 1. Make sure you have a full server snapshot. Although the + following steps are usually safe, they can still cause + data loss or irreversible changes. + 2. Run 'dpkg --configure -a'. This command can fix some of the + issues. However, it may fail. Regardless if it fails or not, + proceed with the following steps. + 3. Run 'PLESK_INSTALLER_SKIP_PACKAGE_MANAGER_CHECK=1 plesk installer update --skip-cleanup'. + Instead of 'update', you may need to use the command you used + previously (for example, 'upgrade' or 'install'). + 4. The next step depends on the outcome of the previous one: + - If step 3 was completed with the "You already have the latest + version of product(s) and all the selected components installed. + Installation will not continue." message, + run 'plesk repair installation'. + - If step 3 failed, run 'dpkg --audit'. This command can show you + packages that need to be reinstalled. To reinstall them, run + 'apt-get install --reinstall '. + 5. Run 'plesk installer update' to revert temporary changes and + validate that the issues are resolved. If the command fails or + triggers this check again, contact Plesk support. + + For more information, see + https://support.plesk.com/hc/en-us/articles/12871173047447-Plesk-update-on-Debian-Ubuntu-fails-dpkg-was-interrupted-you-must-manually-run-dpkg-configure-a-to-correct-the-problem + EOL + return "$RET_FATAL" + fi +} + +check_package_manager_debian() +{ + check_package_manager_deb_based +} + +check_package_manager_ubuntu() +{ + check_package_manager_deb_based +} + +skip_checker_on_env "Package manager check" "$PLESK_INSTALLER_SKIP_PACKAGE_MANAGER_CHECK" +skip_checker_on_flag "Package manager check" "/tmp/plesk-installer-skip-package-manager-check.flag" +checker_main 'check_package_manager' "$@" diff --git a/root/parallels/pool/PSA_18.0.73_17725/examiners/panel_preupgrade_checker.php b/root/parallels/pool/PSA_18.0.73_17725/examiners/panel_preupgrade_checker.php new file mode 100644 index 0000000000..181534e61e --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17725/examiners/panel_preupgrade_checker.php @@ -0,0 +1,2401 @@ +_checkMainIP(); //:INFO: Checking for main IP address https://support.plesk.com/hc/articles/12377857361687 + $this->_checkMySQLDatabaseUserRoot(); //:INFO: Plesk user "root" for MySQL database servers have not access to phpMyAdmin https://support.plesk.com/hc/articles/12378148229399 + $this->_checkProftpdIPv6(); //:INFO: #94489 FTP service proftpd cannot be started by xinetd if IPv6 is disabled https://support.plesk.com/hc/articles/12377796102807 + $this->_checkSwCollectdIntervalSetting(); //:INFO: #105405 https://support.plesk.com/hc/articles/213362569 + $this->_checkApacheStatus(); + $this->_checkImmutableBitOnPleskFiles(); //:INFO: #128414 https://support.plesk.com/hc/articles/12377589682327 + $this->_checkAbilityToChmodInDumpd(); //:INFO: ERROR while trying to backup MySQL database. https://support.plesk.com/hc/en-us/articles/12377010033943 + $this->_checkIpcollectionReference(); //:INFO: #72751 https://support.plesk.com/hc/articles/12377666752279 + $this->_checkApsApplicationContext(); //:INFO: Broken contexts of the APS applications can lead to errors at building Apache web server configuration https://support.plesk.com/hc/articles/12377671820311 + $this->_checkApsTablesInnoDB(); + $this->_checkCustomWebServerConfigTemplates(); //:INFO: #PPPM-1195 https://support.plesk.com/hc/articles/12377740416151 + $this->_checkMixedCaseDomainIssues(); //:INFO: #PPPM-4284 https://support.plesk.com/hc/en-us/articles/12377171904151 + + if (PleskOS::isDebLike()) { + $this->_checkSymLinkToOptPsa(); //:INFO: Check that symbolic link /usr/local/psa actually exists on Debian-like OSes https://support.plesk.com/hc/articles/12377511731991 + } + + if (Util::isVz()) { + $this->_checkShmPagesLimit(); //:INFO: PSA service does not start. Unable to allocate shared memory segment. https://support.plesk.com/hc/articles/12377744827927 + + if (PleskOS::isRedHatLike()) { + $this->_checkMailDriversConflict(); //:INFO: #PPPM-955 https://support.plesk.com/hc/articles/12378148767895 + } + } + } + + $this->_checkForCryptPasswords(); + $this->_checkMysqlServersTable(); //:INFO: Checking existing table mysql.servers + $this->_checkPleskTCPPorts(); //:INFO: Check the availability of Plesk TCP ports https://support.plesk.com/hc/articles/12377821243159 + + if (Util::isWindows()) { + $this->_checkPhprcSystemVariable(); //:INFO: #PPPM-294 Checking for PHPRC system variable + $this->_unknownISAPIfilters(); //:INFO: Checking for unknown ISAPI filters and show warning https://support.plesk.com/hc/articles/213913765 + $this->_checkMSVCR(); //:INFO: Just warning about possible issues related to Microsoft Visual C++ Redistributable Packages https://support.plesk.com/hc/articles/115000201014 + $this->_checkIisFcgiDllVersion(); //:INFO: Check iisfcgi.dll file version https://support.plesk.com/hc/articles/12378148258199 + $this->_checkCDONTSmailrootFolder(); //:INFO: After upgrade Plesk change permissions on folder of Collaboration Data Objects (CDO) for NTS (CDONTS) to default, https://support.plesk.com/hc/articles/12377887661335 + $this->_checkNullClientLogin(); //:INFO: #118963 https://support.plesk.com/hc/articles/12378122202391 + $this->checkDomainControllerLocation(); //:INFO: https://support.plesk.com/hc/articles/12377107094167 + } + } + + //:INFO: PSA service does not start. Unable to allocate shared memory segment. https://support.plesk.com/hc/articles/12377744827927 + function _checkShmPagesLimit() + { + $log = Log::getInstance("Checking for limit shmpages", true); + $ubc = Util::getUserBeanCounters(); + if ((int)$ubc['shmpages']['limit'] < 40960) { + $log->emergency("Virtuozzo Container set the \"shmpages\" limit to {$ubc['shmpages']['limit']}, which is too low. This may cause the sw-engine service not to start. To resolve this issue, refer to the article at https://support.plesk.com/hc/articles/12377744827927"); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: #PPPM-294 + function _checkPhprcSystemVariable() + { + $log = Log::getInstance("Checking for PHPRC system variable", true); + + $phprc = getenv('PHPRC'); + + if ($phprc) { + $log->emergency('The environment variable PHPRC is present in the system. This variable may lead to upgrade failure. Please delete this variable from the system environment.'); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: ERROR while trying to backup MySQL database. https://support.plesk.com/hc/en-us/articles/12377010033943 + function _checkAbilityToChmodInDumpd() + { + $log = Log::getInstance("Checking the possibility to change the permissions of files in the DUMP_D directory", true); + + $dump_d = Util::getSettingFromPsaConf('DUMP_D'); + if (is_null($dump_d)) { + $log->warning('Unable to obtain the path to the directory defined by the DUMP_D parameter. Check that the DUMP_D parameter is set in the /etc/psa/psa.conf file.'); + $log->resultWarning(); + return; + } + + $file = $dump_d . '/pre_upgrade_test_checkAbilityToChmodInDumpd'; + + if (false === file_put_contents($file, 'test')) { + $log->emergency('Unable to write in the ' . $dump_d . ' directory. The upgrade procedure will fail. Check that the folder exists and you have write permissions for it, and repeat upgrading. '); + $log->resultWarning(); + return; + } else { + $result = @chmod($file, 0600); + unlink($file); + if (!$result) { + $log->emergency( + 'Unable to change the permissions of files in the ' . $dump_d . ' directory. ' + . 'The upgrade procedure will fail. Please refer to https://support.plesk.com/hc/articles/12377010033943 for details.' + ); + $log->resultError(); + return; + } + } + $log->resultOk(); + } + + //:INFO: #128414 https://support.plesk.com/hc/articles/12377589682327 + function _checkImmutableBitOnPleskFiles() + { + $log = Log::getInstance("Checking Panel files for the immutable bit attribute"); + + $cmd = 'lsattr -R /usr/local/psa/ 2>/dev/null |awk \'{split($1, a, ""); if (a[5] == "i") {print;}}\''; + $output = Util::exec($cmd, $code); + $files = explode('\n', $output); + + if (!empty($output)) { + $log->info('The immutable bit attribute of the following Panel files can interrupt the upgrade procedure:'); + foreach ($files as $file) { + $log->info($file); + } + $log->emergency('Files with the immutable bit attribute were found. Please check https://support.plesk.com/hc/articles/12377589682327 for details.'); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: #PPPM-1195 https://support.plesk.com/hc/articles/12377740416151 + function _checkCustomWebServerConfigTemplates() + { + $log = Log::getInstance("Checking for custom web server configuration templates"); + $pleskDir = Util::getSettingFromPsaConf('PRODUCT_ROOT_D'); + $customTemplatesPath = $pleskDir . '/admin/conf/templates/custom'; + + if (is_dir($customTemplatesPath)) { + $log->warning("Directory {$customTemplatesPath} for custom web server configuration templates was found. Custom templates might be incompatible with a new Plesk version, and this might lead to failure to generate web server configuration files. Remove the directory to get rid of this warning. " + . "Please check https://support.plesk.com/hc/articles/12377740416151 for details."); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: #PPPM-955 https://support.plesk.com/hc/articles/12378148767895 + function _checkMailDriversConflict() + { + $log = Log::getInstance("Checking for a Plesk mail drivers conflict"); + + if (((true === PackageManager::isInstalled('psa-mail-pc-driver') || true === PackageManager::isInstalled('plesk-mail-pc-driver')) + && true === PackageManager::isInstalled('psa-qmail')) + || ((true === PackageManager::isInstalled('psa-mail-pc-driver') || true === PackageManager::isInstalled('plesk-mail-pc-driver')) + && true === PackageManager::isInstalled('psa-qmail-rblsmtpd'))) { + $log->warning("Plesk upgrade by EZ templates failed if psa-mail-pc-driver and psa-qmail or psa-qmail-rblsmtpd packages are installed. " + . "Please check https://support.plesk.com/hc/articles/12378148767895 for details."); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: #118963 https://support.plesk.com/hc/articles/12378122202391 + function _checkNullClientLogin() + { + $log = Log::getInstance("Checking for accounts with empty user names"); + + $mysql = PleskDb::getInstance(); + $sql = "SELECT domains.id, domains.name, clients.login FROM domains LEFT JOIN clients ON clients.id=domains.cl_id WHERE clients.login is NULL"; + $nullLogins = $mysql->fetchAll($sql); + + if (!empty($nullLogins)) { + $log->warning('There are accounts with empty user names. This problem can cause the backup or migration operation to fail. Please see https://support.plesk.com/hc/articles/12378122202391 for the solution.'); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: #105405 https://support.plesk.com/hc/articles/213362569 + function _checkSwCollectdIntervalSetting() + { + $log = Log::getInstance("Checking the 'Interval' parameter in the sw-collectd configuration file"); + + $collectd_config = '/etc/sw-collectd/collectd.conf'; + if (file_exists($collectd_config)) { + if (!is_file($collectd_config) || !is_readable($collectd_config)) + return; + + $config_content = Util::readfileToArray($collectd_config); + if ($config_content) { + foreach ($config_content as $line) { + if (preg_match('/Interval\s*\d+$/', $line, $match)) { + if (preg_match('/Interval\s*10$/', $line, $match)) { + $log->warning('If you leave the default value of the "Interval" parameter in the ' . $collectd_config . ', sw-collectd may heavily load the system. Please see https://support.plesk.com/hc/articles/213362569 for details.'); + $log->resultWarning(); + return; + } + $log->resultOk(); + return; + } + } + $log->warning('If you leave the default value of the "Interval" parameter in the ' . $collectd_config . ', sw-collectd may heavily load the system. Please see https://support.plesk.com/hc/articles/213362569 for details.'); + $log->resultWarning(); + return; + } + } + } + + private function _checkApacheStatus() + { + $log = Log::getInstance("Checking Apache status"); + + $apacheCtl = file_exists('/usr/sbin/apache2ctl') ? '/usr/sbin/apache2ctl' : '/usr/sbin/apachectl'; + + if (!is_executable($apacheCtl)) { + return; + } + + $resultCode = 0; + Util::Exec("$apacheCtl -t 2>/dev/null", $resultCode); + + if (0 !== $resultCode) { + $log->error("The Apache configuration is broken. Run '$apacheCtl -t' to see the detailed info."); + $log->resultError(); + return; + } + + $log->resultOk(); + } + + //:INFO: #72751 https://support.plesk.com/hc/articles/12377666752279 + function _checkIpcollectionReference() + { + $log = Log::getInstance("Checking consistency of the IP addresses list in the Panel database"); + + $mysql = PleskDb::getInstance(); + $sql = "SELECT 1 FROM ip_pool, clients, IpAddressesCollections, domains, DomainServices, IP_Addresses WHERE DomainServices.ipCollectionId = IpAddressesCollections.ipCollectionId AND domains.id=DomainServices.dom_id AND clients.id=domains.cl_id AND ipAddressId NOT IN (select id from IP_Addresses) AND IP_Addresses.id = ip_pool.ip_address_id AND pool_id = ip_pool.id GROUP BY pool_id"; + $brokenIps = $mysql->fetchAll($sql); + $sql = "select 1 from DomainServices, domains, clients, ip_pool where ipCollectionId not in (select IpAddressesCollections.ipCollectionId from IpAddressesCollections) and domains.id=DomainServices.dom_id and clients.id = domains.cl_id and ip_pool.id = clients.pool_id and DomainServices.type='web' group by ipCollectionId"; + $brokenCollections = $mysql->fetchAll($sql); + + if (!empty($brokenIps) || !empty($brokenCollections)) { + $log->warning('Some database entries related to Panel IP addresses are corrupted. Please see https://support.plesk.com/hc/articles/12377666752279 for the solution.'); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: Broken contexts of the APS applications can lead to errors at building Apache web server configuration https://support.plesk.com/hc/articles/12377671820311 + function _checkApsApplicationContext() + { + $log = Log::getInstance("Checking installed APS applications"); + $mysql = PleskDb::getInstance(); + $sql = "SELECT * FROM apsContexts WHERE (pleskType = 'hosting' OR pleskType = 'subdomain') AND subscriptionId = 0"; + $brokenContexts = $mysql->fetchAll($sql); + + if (!empty($brokenContexts)) { + $log->warning('Some database entries related to the installed APS applications are corrupted. Please see https://support.plesk.com/hc/articles/12377671820311 for the solution.'); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: #94489 FTP service proftpd cannot be started by xinetd if IPv6 is disabled https://support.plesk.com/hc/articles/12377796102807 + function _checkProftpdIPv6() + { + $log = Log::getInstance("Checking proftpd settings"); + + $inet6 = '/proc/net/if_inet6'; + if (!file_exists($inet6) || !@file_get_contents($inet6)) { + $proftpd_config = '/etc/xinetd.d/ftp_psa'; + if (!is_file($proftpd_config) || !is_readable($proftpd_config)) + return null; + + $config_content = Util::readfileToArray($proftpd_config); + if ($config_content) { + for ($i=0; $i<=count($config_content)-1; $i++) { + if (preg_match('/flags.+IPv6$/', $config_content[$i], $match)) { + $log->warning('The proftpd FTP service will fail to start in case the support for IPv6 is disabled on the server. Please check https://support.plesk.com/hc/articles/12377796102807 for details.'); + $log->resultWarning(); + return; + } + } + } + } + $log->resultOk(); + } + + //:INFO: Check the availability of Plesk Panel TCP ports + function _checkPleskTCPPorts() + { + $log = Log::getInstance('Checking the availability of Plesk Panel TCP ports'); + + $plesk_ports = array('8880' => 'Plesk Panel non-secure HTTP port', '8443' => 'Plesk Panel secure HTTPS port'); + + $mysql = PleskDb::getInstance(); + $sql = "select ip_address from IP_Addresses"; + $ip_addresses = $mysql->fetchAll($sql); + $warning = false; + if (count($ip_addresses)>0) { + if (Util::isLinux()) { + $ipv4 = Util::getIPv4ListOnLinux(); + $ipv6 = Util::getIPv6ListOnLinux(); + if ($ipv6) { + $ipsInSystem = array_merge($ipv4, $ipv6); + } else { + $ipsInSystem = $ipv4; + } + } else { + $ipsInSystem = Util::getIPListOnWindows(); + } + foreach ($ip_addresses as $ip) { + foreach ($plesk_ports as $port => $description) { + if (PleskValidator::validateIPv4($ip['ip_address']) && in_array($ip['ip_address'], $ipsInSystem)) { + $fp = @fsockopen($ip['ip_address'], $port, $errno, $errstr, 1); + } elseif (PleskValidator::validateIPv6($ip['ip_address']) && in_array($ip['ip_address'], $ipsInSystem)) { + $fp = @fsockopen('[' . $ip['ip_address'] . ']', $port, $errno, $errstr, 1); + } else { + $log->warning('IP address registered in Plesk is invalid or broken: ' . $ip['ip_address']); + $log->resultWarning(); + return; + } + if (!$fp) { + // $errno 110 means "timed out", 111 means "refused" + $log->info('Unable to connect to IP address ' . $ip['ip_address'] . ' on ' . $description . ' ' . $port . ': ' . $errstr); + $warning = true; + } + } + } + } + if ($warning) { + $log->warning('Unable to connect to some Plesk ports. Please see ' . LOG_PATH . ' for details. Find the full list of the required open ports at https://support.plesk.com/hc/articles/12377821243159 '); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: Plesk user "root" for MySQL database servers have not access to phpMyAdmin https://support.plesk.com/hc/articles/12378148229399 + function _checkMySQLDatabaseUserRoot() + { + $log = Log::getInstance('Checking existence of Plesk user "root" for MariaDB/MySQL database servers'); + + $psaroot = Util::getSettingFromPsaConf('PRODUCT_ROOT_D'); + + if (PleskVersion::is_below_17_9()) { + $phpMyAdminConfFile = $psaroot . '/admin/htdocs/domains/databases/phpMyAdmin/libraries/config.default.php'; + } else { + $phpMyAdminConfFile = $psaroot . '/phpMyAdmin/libraries/config.default.php'; + } + + if (file_exists($phpMyAdminConfFile)) { + $phpMyAdminConfFileContent = file_get_contents($phpMyAdminConfFile); + if (!preg_match("/\[\'AllowRoot\'\]\s*=\s*true\s*\;/", $phpMyAdminConfFileContent)) { + $mysql = PleskDb::getInstance(); + $sql = "select login, data_bases.name as db_name, displayName as domain_name from db_users, data_bases, domains where db_users.db_id = data_bases.id and data_bases.dom_id = domains.id and data_bases.type = 'mysql' and login = 'root'"; + $dbusers = $mysql->fetchAll($sql); + + foreach ($dbusers as $user) { + $log->warning('The database user "' . $user['login'] . '" (database "' . $user['db_name'] . '" at "' . $user['domain_name'] . '") has no access to phpMyAdmin. Please check https://support.plesk.com/hc/articles/12378148229399 for more details.'); + $log->resultWarning(); + return; + } + } + } + + $log->resultOk(); + } + + //:INFO: After upgrade Plesk change permissions on folder of Collaboration Data Objects (CDO) for NTS (CDONTS) to default, https://support.plesk.com/hc/articles/12377887661335 + function _checkCDONTSmailrootFolder() + { + $log = Log::getInstance('Checking for CDONTS mailroot folder'); + + $mailroot = Util::getSystemDisk() . 'inetpub\mailroot\pickup'; + + if (is_dir($mailroot)) { + $log->warning('After upgrade you have to add write permissions to psacln group on folder ' . $mailroot . '. Please, check https://support.plesk.com/hc/articles/12377887661335 for more details.'); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: Check iisfcgi.dll file version https://support.plesk.com/hc/articles/12378148258199 + function _checkIisFcgiDllVersion() + { + $log = Log::getInstance("Checking the iisfcgi.dll file version"); + + $windir = Util::getSystemRoot(); + $iisfcgi = $windir . '\system32\inetsrv\iisfcgi.dll'; + if (file_exists($iisfcgi)) { + $version = Util::getFileVersion($iisfcgi); + if (version_compare($version, '7.5.0', '>') + && version_compare($version, '7.5.7600.16632', '<')) { + $log->warning('File iisfcgi.dll version ' . $version . ' is outdated. Please, check article https://support.plesk.com/hc/articles/12378148258199 for details'); + return; + } + } + $log->resultOk(); + } + + //:INFO: Checking for main IP address https://support.plesk.com/hc/articles/12377857361687 + function _checkMainIP() + { + $log = Log::getInstance("Checking for main IP address"); + + $mysql = PleskDb::getInstance(); + $sql = 'select * from IP_Addresses'; + $ips = $mysql->fetchAll($sql); + $mainexists = false; + foreach ($ips as $ip) { + if (isset($ip['main'])) { + if ($ip['main'] == 'true') { + $mainexists = true; + } + } else { + $log->info('No field "main" in table IP_Addresses.'); + $log->resultOk(); + return; + } + } + + if (!$mainexists) { + $warn = 'Unable to find "main" IP address in psa database. Please, check https://support.plesk.com/hc/articles/12377857361687 for more details.'; + $log->warning($warn); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: Checking existing table mysql.servers https://support.plesk.com/hc/articles/12377850098455 + function _checkMysqlServersTable() + { + $log = Log::getInstance('Checking table "servers" in database "mysql"'); + + $mySQLServerVersion = Util::getMySQLServerVersion(); + if (version_compare($mySQLServerVersion, '5.1.0', '>=')) { + $credentials = Util::getDefaultClientMySQLServerCredentials(); + + if (preg_match('/AES-128-CBC/', $credentials['admin_password'])) { + $log->info('The administrator\'s password for the default MariaDB/MySQL server is encrypted.'); + return; + } + + $mysql = new DbClientMysql($credentials['host'], $credentials['admin_login'], $credentials['admin_password'] , 'information_schema', $credentials['port']); + if (!$mysql->hasErrors()) { + $sql = 'SELECT * FROM information_schema.TABLES WHERE TABLE_SCHEMA="mysql" and TABLE_NAME="servers"'; + $servers = $mysql->fetchAll($sql); + if (empty($servers)) { + $warn = 'The table "servers" in the database "mysql" does not exist. Please check https://support.plesk.com/hc/articles/12377850098455 for details.'; + $log->warning($warn); + $log->resultWarning(); + return; + } + } + } + $log->resultOk(); + } + + //:INFO: Check that there is symbolic link /usr/local/psa on /opt/psa on Debian-like Oses https://support.plesk.com/hc/articles/12377511731991 + function _checkSymLinkToOptPsa() + { + $log = Log::getInstance('Checking symbolic link /usr/local/psa on /opt/psa'); + + $link = @realpath('/usr/local/psa/version'); + if (!preg_match('/\/opt\/psa\/version/', $link, $macthes)) { + $warn = "The symbolic link /usr/local/psa does not exist or has wrong destination. Read article https://support.plesk.com/hc/articles/12377511731991 to fix the issue."; + $log->warning($warn); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: Checking for unknown ISAPI filters and show warning https://support.plesk.com/hc/articles/213913765 + function _unknownISAPIfilters() + { + $log = Log::getInstance('Detecting installed ISAPI filters'); + + if (Util::isUnknownISAPIfilters()) { + $warn = 'Please read carefully article https://support.plesk.com/hc/articles/213913765, for avoiding possible problems caused by unknown ISAPI filters.'; + $log->warning($warn); + $log->resultWarning(); + + return; + } + $log->resultOk(); + } + + //:INFO: Warning about possible issues related to Microsoft Visual C++ Redistributable Packages ?https://support.plesk.com/hc/articles/115000201014 + function _checkMSVCR() + { + $log = Log::getInstance('Microsoft Visual C++ Redistributable Packages'); + + $warn = 'Please read carefully article https://support.plesk.com/hc/articles/115000201014, for avoiding possible problems caused by Microsoft Visual C++ Redistributable Packages.'; + $log->info($warn); + + return; + } + + function _checkForCryptPasswords() + { + //:INFO: Prevent potential problem with E: Couldn't configure pre-depend plesk-core for psa-firewall, probably a dependency cycle. + $log = Log::getInstance('Detecting if encrypted passwords are used'); + + $db = PleskDb::getInstance(); + $sql = "SELECT COUNT(*) AS cnt FROM accounts WHERE type='crypt' AND password not like '$%';"; + $r = $db->fetchAll($sql); + + if ($r[0]['cnt'] != '0') + { + $warn = 'There are ' . $r[0]['cnt'] . ' accounts with passwords encrypted using a deprecated algorithm. Please refer to https://support.plesk.com/hc/articles/12377596588311 for the instructions about how to change the password type to plain.'; + + $log->warning($warn); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + function _checkApsTablesInnoDB() + { + $log = Log::getInstance('Checking if apsc database tables have InnoDB engine'); + + $db = PleskDb::getInstance(); + $apsDatabase = $db->fetchOne("select val from misc where param = 'aps_database'"); + $sql = "SELECT TABLE_NAME FROM information_schema.TABLES where TABLE_SCHEMA = '$apsDatabase' and ENGINE = 'MyISAM'"; + $myISAMTables = $db->fetchAll($sql); + if (!empty($myISAMTables)) { + $myISAMTablesList = implode(', ', array_map('reset', $myISAMTables)); + $warn = 'The are tables in apsc database with MyISAM engine: ' . $myISAMTablesList . '. It would be updated to InnoDB engine.'; + $log->warning($warn); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + function _checkMixedCaseDomainIssues() + { + $log = Log::getInstance("Checking for domains with mixed case names", true); + $db = PleskDb::getInstance(); + + + $domains = $db->fetchAll("select id, name, displayName from domains"); + $problemDomains = array(); + foreach ($domains as $domain) { + if (strtolower($domain['name']) == $domain['name']) { + continue; + } + $problemDomains[] = $domain; + } + if (count($problemDomains)) { + $msg = "Found one or more domains with mixed case names. Such domains may have trouble working with the \"FPM application server by Apache\" handler.\n" . + implode("\n", array_map(function($row) { + return "{$row['id']}\t{$row['displayName']}\t{$row['name']}"; + }, $problemDomains)) . "\n" . + "A manual fix can be applied to resolve the issue. Read https://support.plesk.com/hc/en-us/articles/12377171904151 for details."; + $log->warning($msg); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + private function checkDomainControllerLocation() + { + $log = Log::getInstance("Checking for Active Directory Domain Controller and Plesk on the same server", true); + $cmd = '"' . rtrim(Util::getPleskRootPath(), '\\') . '\admin\bin\serverconf.exe" --list'; + $output = Util::exec($cmd, $code); + if (preg_match("/IS_DOMAIN_CONTROLLER:\s*true/", $output)) { + $log->warning('Active Directory Domain Controller and Plesk are on the same server. Read https://support.plesk.com/hc/articles/12377107094167 for details.'); + $log->resultWarning(); + } else { + $log->resultOk(); + } + } +} + +class Plesk175Requirements +{ + public function validate() + { + if (PleskInstallation::isInstalled() && PleskVersion::is_below_17_5() && Util::isLinux()) { + //:INFO: Check that DUMP_TMP_D is not inside of (or equal to) DUMP_D + $this->_checkDumpTmpD(); + } + } + + public function _checkDumpTmpD() + { + $log = Log::getInstance('Checking the DUMP_TMP_D directory'); + + $dumpD = Util::getSettingFromPsaConf('DUMP_D'); + if (is_null($dumpD)) { + $log->warning('Unable to obtain the path to the directory defined by the DUMP_D parameter. Check that the DUMP_D parameter is set in the /etc/psa/psa.conf file.'); + $log->resultWarning(); + return; + } + $dumpTmpD = Util::getSettingFromPsaConf('DUMP_TMP_D'); + if (is_null($dumpTmpD)) { + $log->warning('Unable to obtain the path to the directory defined by the DUMP_TMP_D parameter. Check that the DUMP_TMP_D parameter is set in the /etc/psa/psa.conf file.'); + $log->resultWarning(); + return; + } + + if (strpos(rtrim($dumpTmpD, '/') . '/', rtrim($dumpD, '/') . '/') === 0) { + $log->error(sprintf('The directory DUMP_TMP_D = %s should not be inside of (or equal to) the directory DUMP_D = %s. Fix these parameters in the /etc/psa/psa.conf file.', $dumpTmpD, $dumpD)); + $log->resultError(); + } + + $log->resultOk(); + } +} + +class Plesk178Requirements +{ + public function validate() + { + if (PleskInstallation::isInstalled() && Util::isWindows() && PleskVersion::is_below_17_9()) { + $this->_checkPleskVhostsDir(); + } + + if (PleskVersion::is_below_17_8()) { + $this->checkTomcat(); + $this->checkMultiServer(); + } + } + + private function checkTomcat() + { + if (Util::isWindows()) { + $tomcatRegBase = '\\PLESK\\PSA Config\\Config\\Packages\\tomcat\\tomcat'; + /* Supported versions on windows are tomcat5 and tomcat7 */ + $key = '/v InstallDir'; + $isInstalled = Util::regQuery($tomcatRegBase . '7', $key, true) || Util::regQuery($tomcatRegBase . '5', $key, true); + } else { + $isInstalled = PackageManager::isInstalled('psa-tomcat-configurator'); + } + + if ($isInstalled + || (PleskDb::getInstance()->fetchOne('show tables like \'WebApps\'') + && PleskDb::getInstance()->fetchOne('select count(*) from WebApps')) + ) { + $log = Log::getInstance('Checking Apache Tomcat installation'); + $message = <<warning($message); + } + } + + private function checkMultiServer() + { + if (!PleskModule::isMultiServer()) { + return; + } + + $log = Log::getInstance('Checking Plesk Multi Server installation'); + $message = <<emergency($message); + $log->resultError(); + } + + private function _checkPleskVhostsDir() + { + $log = Log::getInstance('Checking mount volume for HTTPD_VHOSTS_D directory'); + + $vhostsDir = rtrim(Util::regPleskQuery('HTTPD_VHOSTS_D'), "\\"); + Util::exec("mountvol \"{$vhostsDir}\" /L", $code); + if ($code == 0) { + $msg = "A disk volume is mounted to the {$vhostsDir} directory." . + " It will be unmounted during the Plesk upgrade." . + " As a result, all hosted websites will become unavailable." . + " Make sure to remount the volume to the {$vhostsDir} directory after the upgrade."; + $log->emergency($msg); + $log->resultError(); + return; + } + + $log->resultOk(); + } +} + +class Plesk18Requirements +{ + public function validate() + { + if (PleskInstallation::isInstalled()) { + if (Util::isLinux() && PleskOS::isRedHatLike()) { + $this->_checkYumDuplicates(); + } + $this->checkPdUsersLoginCollation(); + $this->checkDomainsGuidCollation(); + $this->checkClientsGuidCollation(); + $this->checkModSecurityModules(); + $this->checkIsFirewallPackageConfigured(); + $this->checkDefaultDnsServerComponent(); + } + } + + private function checkModSecurityModules() + { + /* Issue actual for Plesk for Windows below 18.0.32 (ModSecurity 2.9.3 and below) */ + if (!Util::isWindows() || PleskVersion::is_18_0_32_or_above()) { + return; + } + + $log = Log::getInstance('Checking the status of ModSecurity IIS modules'); + $modules = Util::exec(Util::getSystemRoot() . '\system32\inetsrv\AppCmd.exe list module', $code); + if ($code) { + $log->warning('Unable to get the list of IIS modules.'); + } else { + if (strpos($modules, 'ModSecurity IIS (32bits)') === false && strpos($modules, 'ModSecurity IIS (64bits)') === false) { + $log->error('Either 32-bit or 64-bit ModSecurity IIS module is absent.'); + $log->resultError(); + } + } + } + + // INFO: PPP-46440 checking package duplicates https://support.plesk.com/hc/articles/12377586286615 + private function _checkYumDuplicates() + { + $log = Log::getInstance('Checking for RPM packages duplicates'); + if (!file_exists("/usr/bin/package-cleanup")) + { + $log->info("package-cleanup is not found. Check for duplicates was skipped"); + return; + } + + $output = Util::exec("/usr/bin/package-cleanup --cacheonly -q --dupes", $code); + if ($code != 0) + { + // some repos may have no cache at this point or may be broken at all + // retry with cache recreation and skipping broken repos + $output = Util::exec("/usr/bin/package-cleanup -q --dupes --setopt='*.skip_if_unavailable=1'", $code); + } + if ($code != 0) + { + $message = "Unable to detect package duplicates: /usr/bin/package-cleanup --dupes returns $code." . + "Output is:\n$output"; + $log->warning($message); + $log->resultWarning(); + return; + } + + if (empty($output)) { + return; + } + + $message = "Your package system contains duplicated packages, which can lead to broken Plesk update:\n\n" . + "$output\n\n" . + "Please check https://support.plesk.com/hc/articles/12377586286615 for more details."; + + $log->error($message); + $log->resultError(); + } + + private function checkPdUsersLoginCollation() + { + $log = Log::getInstance('Checking for Protected Directory Users with duplicates in login field.'); + $duplicates = PleskDb::getInstance()->fetchAll( + 'SELECT pd_id, LOWER(login) AS login_ci, COUNT(*) AS duplicates FROM pd_users' . + ' GROUP BY pd_id, login_ci' . + ' HAVING duplicates > 1' + ); + if (!empty($duplicates)) { + $log->error( + "Duplicate logins of Protected Directory Users were found in the database:\n\n" . + implode("\n", array_column($duplicates, 'login_ci')) . "\n\n" . + "Please check https://support.plesk.com/hc/en-us/articles/360014743900 for more details." + ); + $log->resultError(); + } + } + + private function checkDomainsGuidCollation() + { + $log = Log::getInstance('Checking "domains" table with duplicates in guid field.'); + $duplicates = PleskDb::getInstance()->fetchAll( + 'SELECT guid, COUNT(*) AS duplicates FROM domains' + . ' GROUP BY guid' + . ' HAVING duplicates > 1' + ); + + if (!empty($duplicates)) { + $log->error( + "Duplicate guid were found in the 'domains' table:\n\n" . + implode("\n", array_column($duplicates, 'guid')) . "\n\n" + . "Please check https://support.plesk.com/hc/en-us/articles/12377018323351 for more details." + ); + $log->resultError(); + } + } + + private function checkClientsGuidCollation() + { + $log = Log::getInstance('Checking "clients" table with duplicates in guid field.'); + $duplicates = PleskDb::getInstance()->fetchAll( + 'SELECT guid, COUNT(*) AS duplicates FROM clients' + . ' GROUP BY guid' + . ' HAVING duplicates > 1' + ); + + if (!empty($duplicates)) { + $log->error( + "Duplicate guid were found in the 'clients' table:\n\n" . + implode("\n", array_column($duplicates, 'guid')) . "\n\n" + . "Please check https://support.plesk.com/hc/en-us/articles/360016801679 for more details." + ); + $log->resultError(); + } + } + + private function checkIsFirewallPackageConfigured() + { + if (!Util::isLinux()) { + return; + } + + $log = Log::getInstance("Checking if any rules are configured in the Firewall extension"); + $db = PleskDb::getInstance(); + if ($db->fetchOne("SHOW TABLES LIKE 'module_firewall_rules'") + && $db->fetchOne("SELECT COUNT(*) FROM module_firewall_rules") + ) { + $message = "Plesk Firewall no longer stores its configuration in Plesk database since " + . "Plesk Obsidian 18.0.52. Since you're upgrading to the latest version late, " + . "if you wish to retain the Plesk Firewall extension and its configuration, " + . "you need to follow additional steps after the upgrade. Please check " + . "https://support.plesk.com/hc/en-us/articles/16198248236311 for more details."; + $log->warning($message); + } + } + + private function checkDefaultDnsServerComponent() + { + if (Util::isLinux()) { + return; + } + + $path = '\\PLESK\\PSA Config\\Config\\Packages\\dnsserver'; + $key = '/ve'; + + if ('bind' === Util::regQuery($path, $key, true)) { + $log = Log::getInstance("Checking default DNS server component"); + $message = <<emergency($message); + $log->resultError(); + } + } +} + +class PleskModule +{ + public static function isInstalledWatchdog() + { + return PleskModule::_isInstalled('watchdog'); + } + + public static function isInstalledFileServer() + { + return PleskModule::_isInstalled('fileserver'); + } + + public static function isInstalledFirewall() + { + return PleskModule::_isInstalled('firewall'); + } + + public static function isInstalledVpn() + { + return PleskModule::_isInstalled('vpn'); + } + + public static function isMultiServer() + { + return PleskModule::_isInstalled('plesk-multi-server') || + PleskModule::_isInstalled('plesk-multi-server-node'); + } + + protected static function _isInstalled($module) + { + $sql = "SELECT * FROM Modules WHERE name = '{$module}'"; + + $pleskDb = PleskDb::getInstance(); + $row = $pleskDb->fetchRow($sql); + + return (empty($row) ? false : true); + } +} + +class PleskInstallation +{ + public static function validate() + { + if (!self::isInstalled()) { + $log = Log::getInstance('Checking for Plesk installation'); + $log->step('Plesk installation is not found. You will have no problems with upgrade, go on and install ' + . PleskVersion::getLatestPleskVersionAsString() . ' (https://www.plesk.com/)'); + return; + } + self::detectVersion(); + } + + public static function isInstalled() + { + $rootPath = Util::getPleskRootPath(); + if (empty($rootPath) || !file_exists($rootPath)) { + return false; + } + return true; + } + + private static function detectVersion() + { + $log = Log::getInstance('Installed Plesk version/build: ' . PleskVersion::getVersionAndBuild(), false); + + $currentVersion = PleskVersion::getVersion(); + if (version_compare($currentVersion, PLESK_VERSION, 'eq')) { + $err = 'You have already installed the latest version ' . PleskVersion::getLatestPleskVersionAsString() . '. '; + $err .= 'Tool must be launched prior to upgrade to ' . PleskVersion::getLatestPleskVersionAsString() . ' for the purpose of getting a report on potential problems with the upgrade.'; + $log->info($err); + exit(0); + } + + if (!PleskVersion::isUpgradeSupportedVersion()) { + $err = 'Unable to find Plesk 17.x. '; + $err .= 'Tool must be launched prior to upgrade to ' . PleskVersion::getLatestPleskVersionAsString() . ' for the purpose of getting a report on potential problems with the upgrade.'; + fatal($err); + } + } +} + +class PleskVersion +{ + const PLESK_17_MIN_VERSION = '13.0.0'; /* historically it has been started as 13.0 */ + + const PLESK_17_MAX_VERSION = '17.9.13'; + + const PLESK_18_MIN_VERSION = '18.0.14'; + + public static function is17x_or_above() + { + return version_compare(self::getVersion(), self::PLESK_17_MIN_VERSION, '>='); + } + + public static function is_below_17_5() + { + return version_compare(self::getVersion(), '17.5.0', '<'); + } + + public static function is_below_17_8() + { + return version_compare(self::getVersion(), '17.8.0', '<'); + } + + public static function is_below_17_9() + { + return version_compare(self::getVersion(), '17.9.0', '<'); + } + + public static function is_18_0_32_or_above() + { + return version_compare(self::getVersion(), '18.0.32', '>='); + } + + public static function getVersion() + { + $version = self::getVersionAndBuild(); + if (!preg_match('/([0-9]+[.][0-9]+[.][0-9]+)/', $version, $matches)) { + fatal("Incorrect Plesk version format. Current version: {$version}"); + } + return $matches[1]; + } + + public static function getVersionAndBuild() + { + $versionPath = Util::getPleskRootPath().'/version'; + if (!file_exists($versionPath)) { + fatal("Plesk version file is not exists $versionPath"); + } + $version = file_get_contents($versionPath); + $version = trim($version); + return $version; + } + + public static function getLatestPleskVersionAsString() + { + return 'Plesk ' . PLESK_VERSION; + } + + public static function isUpgradeSupportedVersion() + { + return self::is17x_or_above(); + } +} + +class Log +{ + private $errors; + private $warnings; + private $emergency; + private $logfile; + private $step; + private $step_header; + + /** @var array */ + private $errorsContent = []; + + /** @var array */ + private $warningsContent = []; + + public static function getInstance($step_msg = '', $step_number = true) + { + static $_instance = null; + if (is_null($_instance)) { + $_instance = new Log(); + } + if ($step_msg) { + $_instance->step($step_msg, $step_number); + } + + return $_instance; + } + + private function __construct() + { + $this->log_init(); + @unlink($this->logfile); + } + + private function log_init() + { + $this->step = 0; + $this->errors = 0; + $this->warnings = 0; + $this->emergency = 0; + $this->logfile = LOG_PATH; + $this->step_header = "Unknown step is running"; + } + + public function getErrors() + { + return $this->errors; + } + + public function getWarnings() + { + return $this->warnings; + } + + public function getEmergency() + { + return $this->emergency; + } + + public function fatal($msg) + { + $this->errors++; + + $this->errorsContent[] = $msg; + $content = $this->get_log_string($msg, 'FATAL_ERROR'); + fwrite(STDERR, $content); + $this->write($content); + } + + public function error($msg) + { + $this->errors++; + + $this->errorsContent[] = $msg; + $content = $this->get_log_string($msg, 'ERROR'); + fwrite(STDERR, $content); + $this->write($content); + } + + public function warning($msg) + { + $this->warnings++; + + $this->warningsContent[] = $msg; + $content = $this->get_log_string($msg, 'WARNING'); + fwrite(STDERR, $content); + $this->write($content); + } + + public function emergency($msg) + { + $this->emergency++; + + $this->errorsContent[] = $msg; + $content = $this->get_log_string($msg, 'EMERGENCY'); + fwrite(STDERR, $content); + $this->write($content); + } + + public function step($msg, $useNumber=false) + { + $this->step_header = $msg; + + echo PHP_EOL; + $this->write(PHP_EOL); + + if ($useNumber) { + $msg = "STEP " . $this->step . ": {$msg}..."; + $this->step++; + } else { + $msg = "{$msg}..."; + } + + $this->info($msg); + } + + public function resultOk() + { + $this->info('Result: OK'); + } + + public function resultWarning() + { + $this->info('Result: WARNING'); + } + + public function resultError() + { + $this->info('Result: ERROR'); + } + + public function info($msg) + { + $content = $this->get_log_string($msg, 'INFO'); + echo $content; + $this->write($content); + } + + public function debug($msg) + { + $this->write($this->get_log_string($msg, 'DEBUG')); + } + + public function dumpStatistics() + { + $errors = $this->errors + $this->emergency; + $str = "Errors found: $errors; Warnings found: {$this->warnings}"; + echo PHP_EOL . $str . PHP_EOL . PHP_EOL; + } + + private function get_log_string($msg, $type) + { + if (getenv('VZ_UPGRADE_SCRIPT')) { + switch ($type) { + case 'FATAL_ERROR': + case 'ERROR': + case 'WARNING': + case 'EMERGENCY': + $content = "[{$type}]: {$this->step_header} DESC: {$msg}" . PHP_EOL; + break; + default: + $content = "[{$type}]: {$msg}" . PHP_EOL; + } + } else if (getenv('AUTOINSTALLER_VERSION')) { + $content = "{$type}: {$msg}" . PHP_EOL; + } else { + $date = date('Y-m-d h:i:s'); + $content = "[{$date}][{$type}] {$msg}" . PHP_EOL; + } + + return $content; + } + + public function write($content, $file = null, $mode='a+') + { + $logfile = $file ? $file : $this->logfile; + $fp = fopen($logfile, $mode); + fwrite($fp, $content); + fclose($fp); + } + + private function getJsonFileName() + { + return (Util::isWindows() ? + rtrim(Util::regPleskQuery('PRODUCT_DATA_D'), "\\") : + Util::getSettingFromPsaConf('PRODUCT_ROOT_D') + ) . '/var/' . LOG_JSON; + } + + public function writeJsonFile() + { + $data = [ + 'version' => PRE_UPGRADE_SCRIPT_VERSION, + 'errorsFound' => $this->errors + $this->emergency, + 'errors' => $this->errorsContent, + 'warningsFound' => $this->warnings, + 'warnings' => $this->warningsContent, + ]; + file_put_contents($this->getJsonFileName(), json_encode($data)); + } +} + +class PleskDb +{ + var $_db = null; + + public function __construct($dbParams) + { + switch($dbParams['db_type']) { + case 'mysql': + $this->_db = new DbMysql( + $dbParams['host'], $dbParams['login'], $dbParams['passwd'], $dbParams['db'], $dbParams['port'] + ); + break; + + case 'jet': + $this->_db = new DbJet($dbParams['db']); + break; + + case 'mssql': + $this->_db = new DbMsSql( + $dbParams['host'], $dbParams['login'], $dbParams['passwd'], $dbParams['db'], $dbParams['port'] + ); + break; + + default: + fatal("{$dbParams['db_type']} is not implemented yet"); + break; + } + } + + public static function getInstance() + { + global $options; + static $_instance = array(); + + $dbParams['db_type']= Util::getPleskDbType(); + $dbParams['db'] = Util::getPleskDbName(); + $dbParams['port'] = Util::getPleskDbPort(); + $dbParams['login'] = Util::getPleskDbLogin(); + $dbParams['passwd'] = Util::getPleskDbPassword($options->getDbPasswd()); + $dbParams['host'] = Util::getPleskDbHost(); + + $dbId = md5(implode("\n", $dbParams)); + + $_instance[$dbId] = new PleskDb($dbParams); + + return $_instance[$dbId]; + } + + function fetchOne($sql) + { + if (DEBUG) { + $log = Log::getInstance(); + $log->info($sql); + } + return $this->_db->fetchOne($sql); + } + + function fetchRow($sql) + { + $res = $this->fetchAll($sql); + if (is_array($res) && isset($res[0])) { + return $res[0]; + } + return array(); + } + + function fetchAll($sql) + { + if (DEBUG) { + $log = Log::getInstance(); + $log->info($sql); + } + return $this->_db->fetchAll($sql); + } +} + +class DbMysql +{ + var $_dbHandler; + + public function __construct($host, $user, $passwd, $database, $port) + { + if ( extension_loaded('mysql') ) { + $this->_dbHandler = @mysql_connect("{$host}:{$port}", $user, $passwd); + if (!is_resource($this->_dbHandler)) { + $mysqlError = mysql_error(); + if (stristr($mysqlError, 'access denied for user')) { + $errMsg = 'Given is incorrect. ' . $mysqlError; + } else { + $errMsg = 'Unable to connect database. The reason of problem: ' . $mysqlError . PHP_EOL; + } + $this->_logError($errMsg); + } + @mysql_select_db($database, $this->_dbHandler); + } else if ( extension_loaded('mysqli') ) { + + // forbid using MYSQLI_REPORT_STRICT to handle mysqli errors via error codes + mysqli_report(MYSQLI_REPORT_ERROR); + + $this->_dbHandler = @mysqli_connect($host, $user, $passwd, $database, $port); + if (!$this->_dbHandler) { + $mysqlError = mysqli_connect_error(); + if (stristr($mysqlError, 'access denied for user')) { + $errMsg = 'Given is incorrect. ' . $mysqlError; + } else { + $errMsg = 'Unable to connect database. The reason of problem: ' . $mysqlError . PHP_EOL; + } + $this->_logError($errMsg); + } + } else { + fatal("No MariaDB/MySQL extension is available"); + } + } + + function fetchAll($sql) + { + if ( extension_loaded('mysql') ) { + $res = mysql_query($sql, $this->_dbHandler); + if (!is_resource($res)) { + $this->_logError('Unable to execute query. Error: ' . mysql_error($this->_dbHandler)); + } + $rowset = array(); + while ($row = mysql_fetch_assoc($res)) { + $rowset[] = $row; + } + return $rowset; + } else if ( extension_loaded('mysqli') ) { + $res = $this->_dbHandler->query($sql); + if ($res === false) { + $this->_logError('Unable to execute query. Error: ' . mysqli_error($this->_dbHandler)); + } + $rowset = array(); + while ($row = mysqli_fetch_assoc($res)) { + $rowset[] = $row; + } + return $rowset; + } else { + fatal("No MariaDB/MySQL extension is available"); + } + } + + function fetchOne($sql) + { + if ( extension_loaded('mysql') ) { + $res = mysql_query($sql, $this->_dbHandler); + if (!is_resource($res)) { + $this->_logError('Unable to execute query. Error: ' . mysql_error($this->_dbHandler)); + } + $row = mysql_fetch_row($res); + return isset($row[0]) ? $row[0] : null; + } else if ( extension_loaded('mysqli') ) { + $res = $this->_dbHandler->query($sql); + if ($res === false) { + $this->_logError('Unable to execute query. Error: ' . mysqli_error($this->_dbHandler)); + } + $row = mysqli_fetch_row($res); + return isset($row[0]) ? $row[0] : null; + } else { + fatal("No MariaDB/MySQL extension is available"); + } + } + + function query($sql) + { + if ( extension_loaded('mysql') ) { + $res = mysql_query($sql, $this->_dbHandler); + if ($res === false ) { + $this->_logError('Unable to execute query. Error: ' . mysql_error($this->_dbHandler) ); + } + return $res; + } else if ( extension_loaded('mysqli') ) { + $res = $this->_dbHandler->query($sql); + if ($res === false ) { + $this->_logError('Unable to execute query. Error: ' . mysqli_error($this->_dbHandler) ); + } + return $res; + } else { + fatal("No MariaDB/MySQL extension is available"); + } + } + + function _logError($message) + { + fatal("[MYSQL ERROR] $message"); + } +} + +class DbClientMysql extends DbMysql +{ + var $errors = array(); + + function _logError($message) + { + $message = "[MYSQL ERROR] $message"; + $log = Log::getInstance(); + $log->warning($message); + $this->errors[] = $message; + } + + function hasErrors() { + return count($this->errors) > 0; + } +} + +class DbJet +{ + var $_dbHandler = null; + + public function __construct($dbPath) + { + $dsn = "Provider='Microsoft.Jet.OLEDB.4.0';Data Source={$dbPath}"; + $this->_dbHandler = new COM("ADODB.Connection", NULL, CP_UTF8); + if (!$this->_dbHandler) { + $this->_logError('Unable to init ADODB.Connection'); + } + + $this->_dbHandler->open($dsn); + } + + function fetchAll($sql) + { + $result_id = $this->_dbHandler->execute($sql); + if (!$result_id) { + $this->_logError('Unable to execute sql query ' . $sql); + } + if ($result_id->BOF && !$result_id->EOF) { + $result_id->MoveFirst(); + } + if ($result_id->EOF) { + return array(); + } + + $rowset = array(); + while(!$result_id->EOF) { + $row = array(); + for ($i=0;$i<$result_id->Fields->count;$i++) { + $field = $result_id->Fields($i); + $row[$field->Name] = (string)$field->value; + } + $result_id->MoveNext(); + $rowset[] = $row; + } + return $rowset; + } + + function fetchOne($sql) + { + $result_id = $this->_dbHandler->execute($sql); + if (!$result_id) { + $this->_logError('Unable to execute sql query ' . $sql); + } + if ($result_id->BOF && !$result_id->EOF) { + $result_id->MoveFirst(); + } + if ($result_id->EOF) { + return null; + } + $field = $result_id->Fields(0); + $result = $field->value; + + return (string)$result; + } + + function _logError($message) + { + fatal("[JET ERROR] $message"); + } +} + +class DbMsSql extends DbJet +{ + public function __construct($host, $user, $passwd, $database, $port) + { + $dsn = "Provider=SQLOLEDB.1;Initial Catalog={$database};Data Source={$host}"; + $this->_dbHandler = new COM("ADODB.Connection", NULL, CP_UTF8); + if (!$this->_dbHandler) { + $this->_logError('Unable to init ADODB.Connection'); + } + $this->_dbHandler->open($dsn, $user, $passwd); + } + + function _logError($message) + { + fatal("[MSSQL ERROR] $message"); + } +} + +class Util +{ + const DSN_INI_PATH_UNIX = '/etc/psa/private/dsn.ini'; + + /** @var array */ + private static $_dsnIni; + + public static function isWindows() + { + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + return true; + } + return false; + } + + public static function isLinux() + { + return !Util::isWindows(); + } + + public static function isVz() + { + $vz = false; + if (Util::isLinux()) { + if (file_exists('/proc/vz/veredir')) { + $vz = true; + } + } else { + $reg = 'REG QUERY "HKLM\SOFTWARE\SWsoft\Virtuozzo" 2>nul'; + Util::exec($reg, $code); + if ($code==0) { + $vz = true; + } + } + return $vz; + } + + public static function getArch() + { + global $arch; + if (!empty($arch)) + return $arch; + + $arch = 'i386'; + if (Util::isLinux()) { + $cmd = 'uname -m'; + $x86_64 = 'x86_64'; + $output = Util::exec($cmd, $code); + if (!empty($output) && stristr($output, $x86_64)) { + $arch = 'x86_64'; + } + } else { + $arch = 'x86_64'; + } + return $arch; + } + + public static function getHostname() + { + if (Util::isLinux()) { + $cmd = 'hostname -f'; + } else { + $cmd = 'hostname'; + } + $hostname = Util::exec($cmd, $code); + + if (empty($hostname)) { + $err = 'Command: ' . $cmd . ' returns: ' . $hostname . "\n"; + $err .= 'Hostname is not defined and configured. Unable to get hostname. Server should have properly configured hostname and it should be resolved locally.'; + fatal($err); + } + + return $hostname; + } + + public static function getIPList($lo=false) + { + if (Util::isLinux()) { + $ipList = Util::getIPv4ListOnLinux(); + foreach ($ipList as $key => $ip) { + if (!$lo && substr($ip, 0, 3) == '127') { + unset($ipList[$key]); + continue; + } + trim($ip); + } + $ipList = array_values($ipList); + } else { + $cmd = 'hostname'; + $hostname = Util::exec($cmd, $code); + $ip = gethostbyname($hostname); + $res = ($ip != $hostname) ? true : false; + if (!$res) { + fatal('Unable to retrieve IP address'); + } + $ipList = array(trim($ip)); + } + return $ipList; + } + + public static function getIPv6ListOnLinux() + { + return Util::grepCommandOutput(array( + array('bin' => 'ip', 'command' => '%PATH% addr list', 'regexp' => '#inet6 ([^ /]+)#'), + array('bin' => 'ifconfig', 'command' => '%PATH% -a', 'regexp' => '#inet6 (?:addr: ?)?([A-F0-9:]+)#i'), + )); + } + + public static function getIPv4ListOnLinux() + { + $commands = array( + array('bin' => 'ip', 'command' => '%PATH% addr list', 'regexp' => '#inet ([^ /]+)#'), + array('bin' => 'ifconfig', 'command' => '%PATH% -a', 'regexp' => '#inet (?:addr: ?)?([\d\.]+)#'), + ); + if (!($list = Util::grepCommandOutput($commands))) { + fatal('Unable to get IP address'); + } + return $list; + } + + public static function grepCommandOutput($cmds) + { + foreach ($cmds as $cmd) { + if ($fullPath = Util::lookupCommand($cmd['bin'])) { + $output = Util::exec(str_replace("%PATH%", $fullPath, $cmd['command']), $code); + if (preg_match_all($cmd['regexp'], $output, $matches)) { + return $matches[1]; + } + } + } + return false; + } + + public static function getIPListOnWindows() + { + $cmd = 'wmic.exe path win32_NetworkAdapterConfiguration get IPaddress'; + $output = Util::exec($cmd, $code); + if (!preg_match_all('/"(.*?)"/', $output, $matches)) { + fatal('Unable to get IP address'); + } + return $matches[1]; + } + + public static function getPleskRootPath() + { + global $_pleskRootPath; + if (empty($_pleskRootPath)) { + if (Util::isLinux()) { + if (PleskOS::isDebLike()) { + $_pleskRootPath = '/opt/psa'; + } else { + $_pleskRootPath = '/usr/local/psa'; + } + } + if (Util::isWindows()) { + $_pleskRootPath = Util::regPleskQuery('PRODUCT_ROOT_D', true); + } + } + return $_pleskRootPath; + } + + public static function getPleskDbName() + { + $dbName = 'psa'; + if (Util::isWindows()) { + $dbName = Util::regPleskQuery('mySQLDBName'); + } else { + $dsnDbname = Util::_getDsnConfigValue('dbname'); + if ($dsnDbname) { + $dbName = $dsnDbname; + } + } + return $dbName; + } + + public static function getPleskDbLogin() + { + $dbLogin = 'admin'; + if (Util::isWindows()) { + $dbLogin = Util::regPleskQuery('PLESK_DATABASE_LOGIN'); + } else { + $dsnLogin = Util::_getDsnConfigValue('username'); + if ($dsnLogin) { + $dbLogin = $dsnLogin; + } + } + return $dbLogin; + } + + public static function getPleskDbPassword($dbPassword) + { + if (Util::isLinux()) { + $dsnPassword = Util::_getDsnConfigValue('password'); + if ($dsnPassword) { + $dbPassword = $dsnPassword; + } + } + return $dbPassword; + } + + public static function getPleskDbType() + { + $dbType = 'mysql'; + if (Util::isWindows()) { + $dbType = strtolower(Util::regPleskQuery('PLESK_DATABASE_PROVIDER_NAME')); + } + return $dbType; + } + + public static function getPleskDbHost() + { + $dbHost = 'localhost'; + if (Util::isWindows()) { + $dbProvider = strtolower(Util::regPleskQuery('PLESK_DATABASE_PROVIDER_NAME')); + if ($dbProvider == 'mysql' || $dbProvider == 'mssql') { + $dbHost = Util::regPleskQuery('MySQL_DB_HOST'); + } + } else { + $dsnHost = Util::_getDsnConfigValue('host'); + if ($dsnHost) { + $dbHost = $dsnHost; + } + } + return $dbHost; + } + + public static function getPleskDbPort() + { + $dbPort = '3306'; + if (Util::isWindows()) { + $dbPort = Util::regPleskQuery('MYSQL_PORT'); + } else { + $dsnPort = Util::_getDsnConfigValue('port'); + if ($dsnPort) { + $dbPort = $dsnPort; + } + } + return $dbPort; + } + + private static function _getDsnConfigValue($param) + { + if (Util::isWindows()) { + return null; + } + + if (is_null(self::$_dsnIni)) { + if (!is_file(self::DSN_INI_PATH_UNIX)) { + self::$_dsnIni = false; + return null; + } + self::$_dsnIni = parse_ini_file(self::DSN_INI_PATH_UNIX, true); + } + + if (!self::$_dsnIni) { + return null; + } + if (!array_key_exists('plesk', self::$_dsnIni)) { + return null; + } + if (!array_key_exists($param, self::$_dsnIni['plesk'])) { + return null; + } + return self::$_dsnIni['plesk'][$param]; + } + + public static function regPleskQuery($key, $returnResult=false) + { + $reg = 'REG QUERY "HKLM\SOFTWARE\Wow6432Node\Plesk\Psa Config\Config" /v '.$key; + $output = Util::exec($reg, $code); + + if ($code) { + $log = Log::getInstance(); + $log->info($reg); + $log->info($output); + if ($returnResult) { + return false; + } else { + fatal("Unable to get '$key' from registry"); + } + } + + if (!preg_match("/\w+\s+REG_SZ\s+(.*)/i", trim($output), $matches)) { + fatal('Unable to macth registry value by key '.$key.'. Output: ' . trim($output)); + } + + return $matches[1]; + } + + public static function regQuery($path, $key, $returnResult = false) + { + $reg = 'REG QUERY "HKLM\SOFTWARE\Wow6432Node' . $path . '" '.$key; + $output = Util::exec($reg, $code); + + if ($code) { + $log = Log::getInstance(); + $log->info($reg); + $log->info($output); + if ($returnResult) { + return false; + } else { + fatal("Unable to get '$key' from registry"); + } + } + + if (!preg_match("/\s+REG_SZ(\s+)?(.*)/i", trim($output), $matches)) { + fatal('Unable to match registry value by key '.$key.'. Output: ' . trim($output)); + } + + return $matches[2]; + } + + public static function lookupCommand($cmd, $exit = false, $path = '/bin:/usr/bin:/usr/local/bin:/usr/sbin:/sbin:/usr/local/sbin') + { + $dirs = explode(':', $path); + foreach ($dirs as $dir) { + $util = $dir . '/' . $cmd; + if (is_executable($util)) { + return $util; + } + } + if ($exit) { + fatal("{$cmd}: command not found"); + } + return false; + } + + public static function getSystemDisk() + { + $cmd = 'echo %SYSTEMROOT%'; + $output = Util::exec($cmd, $code); + return substr($output, 0, 3); + } + + public static function getSystemRoot() + { + $cmd = 'echo %SYSTEMROOT%'; + $output = Util::exec($cmd, $code); + return $output; + } + + public static function getFileVersion($file) + { + $fso = new COM("Scripting.FileSystemObject"); + $version = $fso->GetFileVersion($file); + $fso = null; + return $version; + } + + public static function isUnknownISAPIfilters() + { + if (PleskVersion::is17x_or_above()) { + return false; + } + + $log = Log::getInstance(); + + $isUnknownISAPI = false; + $knownISAPI = array ("ASP\\.Net.*", "sitepreview", "COMPRESSION", "jakarta"); + + foreach ($knownISAPI as &$value) { + $value = strtoupper($value); + } + $cmd='cscript ' . Util::getSystemDisk() . 'inetpub\AdminScripts\adsutil.vbs ENUM W3SVC/FILTERS'; + $output = Util::exec($cmd, $code); + + if ($code!=0) { + $log->info("Unable to get ISAPI filters. Error: " . $output); + return false; + } + if (!preg_match_all('/FILTERS\/(.*)]/', trim($output), $matches)) { + $log->info($output); + $log->info("Unable to get ISAPI filters from output: " . $output); + return false; + } + foreach ($matches[1] as $ISAPI) { + $valid = false; + foreach ($knownISAPI as $knownPattern) { + if (preg_match("/$knownPattern/i", $ISAPI)) { + $valid = true; + break; + } + } + if (! $valid ) { + $log->warning("Unknown ISAPI filter detected in IIS: " . $ISAPI); + $isUnknownISAPI = true; + } + } + + return $isUnknownISAPI; + } + + /** + * @return string + */ + public static function getMySQLServerVersion() + { + $credentials = Util::getDefaultClientMySQLServerCredentials(); + + if (preg_match('/AES-128-CBC/', $credentials['admin_password'])) { + Log::getInstance()->info('The administrator\'s password for the default MariaDB/MySQL server is encrypted.'); + + return ''; + } + + $mysql = new DbClientMysql( + $credentials['host'], + $credentials['admin_login'], + $credentials['admin_password'], + 'information_schema', + $credentials['port'] + ); + + if (!$mysql->hasErrors()) { + $sql = 'select version()'; + $mySQLversion = $mysql->fetchOne($sql); + if (!preg_match("/(\d{1,})\.(\d{1,})\.(\d{1,})/", trim($mySQLversion), $matches)) { + fatal('Unable to match MariaDB/MySQL server version.'); + } + + return $matches[0]; + } + + return ''; + } + + public static function getDefaultClientMySQLServerCredentials() + { + $db = PleskDb::getInstance(); + $sql = "SELECT val FROM misc WHERE param='default_server_mysql'"; + $defaultServerMysqlId = $db->fetchOne($sql); + if ($defaultServerMysqlId) { + $where = "id={$defaultServerMysqlId}"; + } else { + $where = "type='mysql' AND host='localhost'"; + } + $sql = "SELECT ds.host, ds.port, ds.admin_login, ds.admin_password FROM DatabaseServers ds WHERE {$where}"; + $clientDBServerCredentials = $db->fetchAll($sql)[0]; + if ($clientDBServerCredentials['host'] === 'localhost' && Util::isLinux()) { + $clientDBServerCredentials['admin_password'] = Util::retrieveAdminMySQLDbPassword(); + } + if (empty($clientDBServerCredentials['port'])) { + $clientDBServerCredentials['port'] = self::getPleskDbPort(); + } + + return $clientDBServerCredentials; + } + + public static function retrieveAdminMySQLDbPassword() + { + return Util::isLinux() + ? trim( Util::readfile("/etc/psa/.psa.shadow") ) + : null; + } + + public static function exec($cmd, &$code) + { + $log = Log::getInstance(); + + if (!$cmd) { + $log->info('Unable to execute a blank command. Please see ' . LOG_PATH . ' for details.'); + + $debugBacktrace = ""; + foreach (debug_backtrace() as $i => $obj) { + $debugBacktrace .= "#{$i} {$obj['file']}:{$obj['line']} {$obj['function']} ()\n"; + } + $log->debug("Unable to execute a blank command. The stack trace:\n{$debugBacktrace}"); + $code = 1; + return ''; + } + exec($cmd, $output, $code); + return trim(implode("\n", $output)); + } + + public static function readfile($file) + { + if (!is_file($file) || !is_readable($file)) { + return null; + } + $lines = file($file); + return $lines === false + ? null + : trim(implode("\n", $lines)); + } + + public static function readfileToArray($file) + { + if (!is_file($file) || !is_readable($file)) { + return null; + } + $lines = file($file); + return $lines === false + ? null + : $lines; + } + + public static function getSettingFromPsaConf($setting) + { + $file = '/etc/psa/psa.conf'; + if (!is_file($file) || !is_readable($file)) + return null; + $lines = file($file); + if ($lines === false) + return null; + foreach ($lines as $line) { + if (preg_match("/^{$setting}\s.*/", $line, $match_setting)) { + if (preg_match("/[\s].*/i", $match_setting[0], $match_value)) { + $value = trim($match_value[0]); + return $value; + } + } + } + return null; + } + + public static function getPhpIni() + { + if (Util::isLinux()) { + // Debian/Ubuntu /etc/php5/apache2/php.ini /etc/php5/conf.d/ + // SuSE /etc/php5/apache2/php.ini /etc/php5/conf.d/ + // CentOS 4/5 /etc/php.ini /etc/php.d + if (PleskOS::isRedHatLike()) { + $phpini = Util::readfileToArray('/etc/php.ini'); + } else { + $phpini = Util::readfileToArray('/etc/php5/apache2/php.ini'); + } + } + + return $phpini; + } + + public static function getUserBeanCounters() + { + if (!Util::isLinux()) { + + return false; + } + $user_beancounters = array(); + $ubRaw = Util::readfileToArray('/proc/user_beancounters'); + + if (!$ubRaw) { + + return false; + } + for ($i=2; $i<=count($ubRaw)-1; $i++) { + + if (preg_match('/^.+?:?.+?\b(\w+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/', $ubRaw[$i], $limit_name)) { + + $user_beancounters[trim($limit_name[1])] = array( + 'held' => (int)$limit_name[2], + 'maxheld' => (int)$limit_name[3], + 'barrier' => (int)$limit_name[4], + 'limit' => (int)$limit_name[5], + 'failcnt' => (int)$limit_name[6] + ); + } + } + + return $user_beancounters; + } +} + +class PackageManager +{ + public static function buildListCmdLine($glob) + { + if (PleskOS::isRedHatLike()) { + $cmd = "rpm -qa --queryformat '%{NAME} %{VERSION}-%{RELEASE} %{ARCH}\\n'"; + } elseif (PleskOS::isDebLike()) { + $cmd = "dpkg-query --show --showformat '\${Package} \${Version} \${Architecture}\\n'"; + } else { + return false; + } + + if (!empty($glob)) { + $cmd .= " '" . $glob . "' 2>/dev/null"; + } + + return $cmd; + } + + /* + * Fetches a list of installed packages that match given criteria. + * string $glob - Glob (wildcard) pattern for coarse-grained packages selection from system package management backend. Empty $glob will fetch everything. + * string $regexp - Package name regular expression for a fine-grained filtering of the results. + * returns array of hashes with keys 'name', 'version' and 'arch', or false on error. + */ + public static function listInstalled($glob, $regexp = null) + { + $cmd = PackageManager::buildListCmdLine($glob); + if (!$cmd) { + return array(); + } + + $output = Util::exec($cmd, $code); + if ($code != 0) { + return false; + } + + $packages = array(); + $lines = explode("\n", $output); + foreach ($lines as $line) { + @list($pkgName, $pkgVersion, $pkgArch) = explode(" ", $line); + if (empty($pkgName) || empty($pkgVersion) || empty($pkgArch)) + continue; + if (!empty($regexp) && !preg_match($regexp, $pkgName)) + continue; + $packages[] = array( + 'name' => $pkgName, + 'version' => $pkgVersion, + 'arch' => $pkgArch + ); + } + + return $packages; + } + + public static function isInstalled($glob, $regexp = null) + { + $packages = PackageManager::listInstalled($glob, $regexp); + return !empty($packages); + } +} + +class Package +{ + function getManager($field, $package) + { + $redhat = 'rpm -q --queryformat \'%{' . $field . '}\n\' ' . $package; + $debian = 'dpkg-query --show --showformat=\'${' . $field . '}\n\' '. $package . ' 2> /dev/null'; + + if (PleskOS::isRedHatLike()) { + $manager = $redhat; + } elseif (PleskOS::isDebLike()) { + $manager = $debian; + } else { + return false; + } + + return $manager; + } + + /* DPKG doesn't supports ${Release} + * + */ + + function getRelease($package) + { + $manager = Package::getManager('Release', $package); + + if (!$manager) { + return false; + } + + $release = Util::exec($manager, $code); + if (!$code === 0) { + return false; + } + return $release; + } + + function getVersion($package) + { + $manager = Package::getManager('Version', $package); + + if (!$manager) { + return false; + } + + $version = Util::exec($manager, $code); + if (!$code === 0) { + return false; + } + return $version; + } + +} + +class PleskOS +{ + public static function isDebLike() + { + return is_file("/etc/debian_version"); + } + + public static function isRedHatLike() + { + return is_file("/etc/redhat-release"); + } + + public static function catEtcIssue() + { + $cmd = 'cat /etc/issue'; + $output = Util::exec($cmd, $code); + + return $output; + } + + public static function detectSystem() + { + $log = Log::getInstance('Detect system configuration'); + $log->info('OS: ' . (Util::isLinux() ? PleskOS::catEtcIssue() : 'Windows')); + $log->info('Arch: ' . Util::getArch()); + } +} + +class PleskValidator +{ + public static function validateIPv4($value) + { + $ip2long = ip2long($value); + if ($ip2long === false) { + return false; + } + + return $value == long2ip($ip2long); + } + + public static function validateIPv6($value) + { + if (strlen($value) < 3) { + return $value == '::'; + } + + if (strpos($value, '.')) { + $lastcolon = strrpos($value, ':'); + if (!($lastcolon && PleskValidator::validateIPv4(substr($value, $lastcolon + 1)))) { + return false; + } + + $value = substr($value, 0, $lastcolon) . ':0:0'; + } + + if (strpos($value, '::') === false) { + return preg_match('/\A(?:[a-f0-9]{1,4}:){7}[a-f0-9]{1,4}\z/i', $value); + } + + $colonCount = substr_count($value, ':'); + if ($colonCount < 8) { + return preg_match('/\A(?::|(?:[a-f0-9]{1,4}:)+):(?:(?:[a-f0-9]{1,4}:)*[a-f0-9]{1,4})?\z/i', $value); + } + + // special case with ending or starting double colon + if ($colonCount == 8) { + return preg_match('/\A(?:::)?(?:[a-f0-9]{1,4}:){6}[a-f0-9]{1,4}(?:::)?\z/i', $value); + } + + return false; + } +} + +class CheckRequirements +{ + function validate() + { + if (!PleskInstallation::isInstalled()) { + //:INFO: skip chking mysql extension if plesk is not installed + return; + } + + $reqExts = array(); + foreach ($reqExts as $name) { + $status = extension_loaded($name); + if (!$status) { + $this->_fail("PHP extension {$name} is not installed"); + } + } + } + + function _fail($errMsg) + { + echo '===Checking requirements===' . PHP_EOL; + echo PHP_EOL . 'Error: ' . $errMsg . PHP_EOL; + exit(1); + } +} + +class GetOpt +{ + var $_argv; + var $_adminDbPasswd; + + public function __construct() + { + $this->_argv = $_SERVER['argv']; + if (empty($this->_argv[1]) && Util::isLinux()) { + $this->_adminDbPasswd = Util::retrieveAdminMySQLDbPassword(); + } else { + $this->_adminDbPasswd = $this->_argv[1]; + } + } + + public function validate() + { + if (empty($this->_adminDbPasswd) && PleskInstallation::isInstalled()) { + echo 'Please specify Plesk database password'; + $this->_helpUsage(); + } + } + + public function getDbPasswd() + { + return $this->_adminDbPasswd; + } + + public function _helpUsage() + { + echo PHP_EOL . "Usage: {$this->_argv[0]} " . PHP_EOL; + exit(1); + } +} + +function fatal($msg) +{ + $log = Log::getInstance(); + $log->fatal($msg); + exit(1); +} + +$log = Log::getInstance(); + +//:INFO: Validate options +$options = new GetOpt(); +$options->validate(); + +//:INFO: Validate PHP requirements, need to make sure that PHP extensions are installed +$checkRequirements = new CheckRequirements(); +$checkRequirements->validate(); + +//:INFO: Validate Plesk installation +PleskInstallation::validate(); + +//:INFO: Detect system +$pleskOs = new PleskOS(); +$pleskOs->detectSystem(); + +//:INFO: Need to make sure that given db password is valid +if (PleskInstallation::isInstalled()) { + $log->step('Validating the database password'); + $pleskDb = PleskDb::getInstance(); + $log->resultOk(); +} + +//:INFO: Dump script version +$log->step('Pre-Upgrade analyzer version: ' . PRE_UPGRADE_SCRIPT_VERSION); + +//:INFO: Validate known OS specific issues with recommendation to avoid bugs in Plesk +$pleskKnownIssues = new Plesk17KnownIssues(); +$pleskKnownIssues->validate(); + +$plesk175Requirements = new Plesk175Requirements(); +$plesk175Requirements->validate(); + +$plesk178Requirements = new Plesk178Requirements(); +$plesk178Requirements->validate(); + +$plesk18Requirements = new Plesk18Requirements(); +$plesk18Requirements->validate(); + +$log->dumpStatistics(); +$log->writeJsonFile(); + +if ($log->getEmergency() > 0) { + exit(2); +} + +if ($log->getErrors() > 0 || $log->getWarnings() > 0) { + exit(1); +} +// vim:set et ts=4 sts=4 sw=4: diff --git a/root/parallels/pool/PSA_18.0.73_17725/examiners/php_launcher.sh b/root/parallels/pool/PSA_18.0.73_17725/examiners/php_launcher.sh new file mode 100755 index 0000000000..70ebd0f0c6 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17725/examiners/php_launcher.sh @@ -0,0 +1,38 @@ +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +die() +{ + echo $* + exit 1 +} + +[ -n "$1" ] || die "Usage: $0 php_script [args...]" + +[ "X${PLESK_INSTALLER_DEBUG}" = "X" ] || set -x +[ "X${PLESK_INSTALLER_STRICT_MODE}" = "X" ] || set -e + +php_bin= + +lookup() +{ + [ -z "$php_bin" ] || return + + local paths="$1" + local name="$2" + + for path in $paths; do + if [ -x "$path/$name" ]; then + php_bin="$path/$name" + break + fi + done +} + +lookup "/usr/local/psa/admin/bin /opt/psa/admin/bin" "php" +lookup "/usr/local/psa/bin /opt/psa/bin" "sw-engine-pleskrun" + +[ -n "$php_bin" ] || \ + die "Unable to locate the sw-engine PHP interpreter to execute the script. Make sure that Parallels Plesk Panel is installed on this server." + +exec "${php_bin}" "$@" diff --git a/root/parallels/pool/PSA_18.0.73_17725/examiners/plesk_preupgrade_checker.log b/root/parallels/pool/PSA_18.0.73_17725/examiners/plesk_preupgrade_checker.log new file mode 100644 index 0000000000..ad2a8ba715 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17725/examiners/plesk_preupgrade_checker.log @@ -0,0 +1,68 @@ + +INFO: Installed Plesk version/build: 18.0.72 Ubuntu 24.04 1800250915.05... + +INFO: STEP 0: Detect system configuration... +INFO: OS: Ubuntu 24.04.3 LTS \n \l +INFO: Arch: x86_64 + +INFO: Validating the database password... +INFO: Result: OK + +INFO: Pre-Upgrade analyzer version: 18.0.73.0... + +INFO: STEP 1: Checking for main IP address... +INFO: Result: OK + +INFO: STEP 2: Checking existence of Plesk user "root" for MariaDB/MySQL database servers... +INFO: Result: OK + +INFO: STEP 3: Checking proftpd settings... +INFO: Result: OK + +INFO: STEP 4: Checking the 'Interval' parameter in the sw-collectd configuration file... +INFO: Result: OK + +INFO: STEP 5: Checking Apache status... +INFO: Result: OK + +INFO: STEP 6: Checking Panel files for the immutable bit attribute... +INFO: Result: OK + +INFO: STEP 7: Checking the possibility to change the permissions of files in the DUMP_D directory... +INFO: Result: OK + +INFO: STEP 8: Checking consistency of the IP addresses list in the Panel database... +INFO: Result: OK + +INFO: STEP 9: Checking installed APS applications... +INFO: Result: OK + +INFO: STEP 10: Checking if apsc database tables have InnoDB engine... +INFO: Result: OK + +INFO: STEP 11: Checking for custom web server configuration templates... +INFO: Result: OK + +INFO: STEP 12: Checking for domains with mixed case names... +INFO: Result: OK + +INFO: STEP 13: Checking symbolic link /usr/local/psa on /opt/psa... +INFO: Result: OK + +INFO: STEP 14: Detecting if encrypted passwords are used... +INFO: Result: OK + +INFO: STEP 15: Checking table "servers" in database "mysql"... +INFO: The administrator's password for the default MariaDB/MySQL server is encrypted. +INFO: Result: OK + +INFO: STEP 16: Checking the availability of Plesk Panel TCP ports... +INFO: Result: OK + +INFO: STEP 17: Checking for Protected Directory Users with duplicates in login field.... + +INFO: STEP 18: Checking "domains" table with duplicates in guid field.... + +INFO: STEP 19: Checking "clients" table with duplicates in guid field.... + +INFO: STEP 20: Checking if any rules are configured in the Firewall extension... diff --git a/root/parallels/pool/PSA_18.0.73_17725/examiners/py_launcher.sh b/root/parallels/pool/PSA_18.0.73_17725/examiners/py_launcher.sh new file mode 100755 index 0000000000..96dc215391 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17725/examiners/py_launcher.sh @@ -0,0 +1,30 @@ +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +die() +{ + echo "$*" + exit 1 +} + +[ -f "$1" ] || die "Usage: $0 PEX [args...]" + +[ "X${PLESK_INSTALLER_DEBUG}" = "X" ] || set -x +[ "X${PLESK_INSTALLER_STRICT_MODE}" = "X" ] || set -e + +find_python_bin() +{ + local bin + for bin in "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3" "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2"; do + [ -x "$bin" ] || continue + python_bin="$bin" + return 0 + done + + return 1 +} + +find_python_bin || + die "Unable to locate Python interpreter to execute the script." + +exec "$python_bin" "$@" diff --git a/root/parallels/pool/PSA_18.0.73_17725/examiners/repository_check.sh b/root/parallels/pool/PSA_18.0.73_17725/examiners/repository_check.sh new file mode 100755 index 0000000000..090f121ea1 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17725/examiners/repository_check.sh @@ -0,0 +1,782 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ -z "$PLESK_INSTALLER_DEBUG" ] || set -x +[ -z "$PLESK_INSTALLER_STRICT_MODE" ] || set -e + +export LC_ALL=C +unset GREP_OPTIONS + +RET_SUCCESS=0 +RET_WARN=1 +RET_FATAL=2 + +is_function_defined() +{ + local fn="$1" + case "$(type $fn 2>/dev/null)" in + *function*) + return 0 + ;; + esac + return 1 +} + +# @params are tags in format "key=value" +# Report body (human readable information) is read from stdin +# and copied to stderr. +make_error_report() +{ + local report_file="${PLESK_INSTALLER_ERROR_REPORT:-}" + + local python_bin= + for bin in "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2" "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3"; do + if [ -x "$bin" ]; then + python_bin="$bin" + break + fi + done + + if [ -n "$report_file" -a -x "$python_bin" ]; then + "$python_bin" -c 'import sys, json +report_file = sys.argv[1] +error = sys.stdin.read() + +sys.stderr.write(error) + +data = { + "error": error, +} + +for tag in sys.argv[2:]: + k, v = tag.split("=", 1) + data[k] = v + +with open(report_file, "a") as f: + json.dump(data, f) + f.write("\n") +' "$report_file" "date=$(date --utc --iso-8601=ns)" "$@" + else + cat - >&2 + fi +} + +detect_platform() +{ + . /etc/os-release + os_name="$ID" + os_version="${VERSION_ID%%.*}" + os_arch="$(uname -m)" + if [ -e /etc/debian_version ]; then + case "$os_arch" in + x86_64) pkg_arch="amd64" ;; + aarch64) pkg_arch="arm64" ;; + esac + if [ -n "$VERSION_CODENAME" ]; then + os_codename="$VERSION_CODENAME" + else + case "$os_name$os_version" in + debian10) os_codename="buster" ;; + debian11) os_codename="bullseye" ;; + debian12) os_codename="bookworm" ;; + ubuntu18) os_codename="bionic" ;; + ubuntu20) os_codename="focal" ;; + ubuntu22) os_codename="jammy" ;; + ubuntu24) os_codename="noble" ;; + esac + fi + fi + + case "$os_name$os_version" in + rhel7|centos7|cloudlinux7|virtuozzo7) + package_manager="yum" + ;; + rhel*|centos*|cloudlinux*|almalinux*|rocky*) + package_manager="dnf" + ;; + debian*|ubuntu*) + package_manager="apt" + ;; + esac + + if [ "$os_name" = "ubuntu" -o "$os_name" = "debian" ]; then + PRODUCT_ROOT_D="/opt/psa" + else + PRODUCT_ROOT_D="/usr/local/psa" + fi +} + +has_os_impl_function() +{ + local prefix="$1" + local fn="${prefix}_${os_name}${os_version}" + is_function_defined "$fn" +} + +call_os_impl_function() +{ + local prefix="$1" + shift + local fn="${prefix}_${os_name}${os_version}" + "$fn" "$@" +} + +skip_checker_on_flag() +{ + local name="$1" + local flag="$2" + + if [ -f "$flag" ]; then + echo "$name was skipped due to flag file." >&2 + exit $RET_SUCCESS + fi +} + +skip_checker_on_env() +{ + local name="$1" + local env="$2" + + if [ -n "$env" ]; then + echo "$name was skipped due to environment variable." >&2 + exit $RET_SUCCESS + fi +} + +checker_main() +{ + local fnprefix="$1" + shift + + detect_platform + # try to execute checker only if all attributes are detected + [ -n "$os_name" -a -n "$os_version" ] || return $RET_SUCCESS + + for checker in "${fnprefix}_${os_name}${os_version}" "${fnprefix}_${os_name}" "${fnprefix}"; do + if is_function_defined "$checker"; then + local rc=$RET_SUCCESS + "$checker" "$@" || rc=$? + [ "$(( $rc & $RET_FATAL ))" = "0" ] || return $RET_FATAL + [ "$(( $rc & $RET_WARN ))" = "0" ] || return $RET_WARN + return $rc + fi + done + return $RET_SUCCESS +} + +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +# If env variable PLESK_INSTALLER_ERROR_REPORT=path_to_file is specified then in case of error +# repository_check.sh writes single line json report into it with the following fields: +# - "stage": "repositorycheck" +# - "level": "error" +# - "errtype" is one of the following: +# * "reponotcached" - repository is not cached (mostly due to unavailability). +# * "reponotenabled" - required repository is not enabled. +# * "reponotsupported" - unsupported repository is enabled. +# * "configmanagernotinstalled" - dnf config-manager is disabled. +# - "repo": repository name. +# - "date": time of error occurance ("2020-03-24T06:59:43,127545441+0000") +# - "error": human readable error message. + +report_no_repo() +{ + local repo="$1" + + make_error_report 'stage=repositorycheck' 'level=error' 'errtype=reponotenabled' "repo=$repo" <<-EOL + Plesk installation requires '$repo' OS repository to be enabled. + Make sure it is available and enabled, then try again. + EOL +} + +report_no_repo_cache() +{ + local repo="$1" + + make_error_report 'stage=repositorycheck' 'level=error' 'errtype=reponotcached' "repo=$repo" <<-EOL + Unable to create $package_manager cache for '$repo' OS repository. + Make sure the repository is available, otherwise either disable it or fix its configuration, then try again. + EOL +} + +report_unsupported_repo() +{ + local repo="$1" + + make_error_report 'stage=repositorycheck' 'level=error' 'errtype=reponotsupported' "repo=$repo" <<-EOL + Plesk installation doesn't support '$repo' OS repository. + Make sure it is disabled, then try again. + EOL +} + +report_rh_no_config_manager() +{ + local target + case "$package_manager" in + yum) + target="yum-utils package" + ;; + dnf) + target="config-manager dnf plugin" + ;; + esac + + make_error_report 'stage=repositorycheck' 'level=error' 'errtype=configmanagernotinstalled' <<-EOL + Failed to install $target. + Make sure repositories configuration of $package_manager package manager is correct + (use '$package_manager repolist --verbose' to get its actual state), then try again. + EOL +} + +check_rh_broken_repos() +{ + local rh_enabled_repos rh_available_repos + + # 1. `yum repolist` and `dnf repolist` list all repos + # which were enabled before last cache creation + # even if cache for them was not created. + # If some repo is misconfigured and cache was created with `skip_if_unavailable=1` + # then such repo will be listed anyway despite on cache state. + # If some repo was enabled after last cache creation + # then `repolist --cacheonly` will fail. + # 2. `yum repolist --verbose` and `dnf repoinfo` list only repos + # which were successfully cached before. + # These commands fail if at least one repo is not available + # and the 'skip_if_unavailable' flag is not set. + case "$package_manager" in + yum) + rh_enabled_repos="$( + { + yum repolist enabled --cacheonly -q 2>/dev/null \ + || yum repolist enabled -q --setopt='*.skip_if_unavailable=1' + } | sed -n -e '1d' -e 's/^\*\?!\?\([^/[:space:]]\+\).*/\1/p' + )" || return $RET_FATAL + + rh_available_repos="$( + yum repolist enabled --verbose --cacheonly -q --setopt='*.skip_if_unavailable=1' \ + | sed -n -e 's/^Repo-id\s*:\s*\([^/[:space:]]\+\).*/\1/p' + )" || return $RET_FATAL + ;; + dnf) + rh_enabled_repos="$( + { + dnf repolist --enabled --cacheonly -q 2>/dev/null \ + || dnf repolist --enabled -q --setopt='*.skip_if_unavailable=1' + } | sed -n -e '1d' -e 's/^!\?\(\S\+\).*/\1/p' + )" || return $RET_FATAL + + rh_available_repos="$( \ + dnf repoinfo --enabled --cacheonly -q --setopt='*.skip_if_unavailable=1' \ + | sed -n -e 's|^Repo-id\s*:\s*\(\S\+\)\s*$|\1|p' + )" || return $RET_FATAL + ;; + esac + + local rh_enabled_repos_f="$(mktemp /tmp/plesk-installer.preupgrade_checker.XXXXXX)" + echo "$rh_enabled_repos" | sort > "$rh_enabled_repos_f" + local rh_available_repos_f="$(mktemp /tmp/plesk-installer.preupgrade_checker.XXXXXX)" + echo "$rh_available_repos" | sort > "$rh_available_repos_f" + + local repo rc=0 + for repo in $(comm -23 "$rh_enabled_repos_f" "$rh_available_repos_f"); do + report_no_repo_cache "$repo" + rc=$RET_WARN + done + + rm -f "$rh_enabled_repos_f" "$rh_available_repos_f" + + return $rc +} + +has_rh_enabled_repo() +{ + local repo="$1" + + # Try to get list of repos from cache first. + # If some repo was enabled after last cache creation + # or some repo is unavailable the query from cache will fail. + # Try to fetch actual metadata in this case. + case "$package_manager" in + yum) + # Repo-id may end with OS version and/or architecture + # if baseurl of the repo refers to $releasever and/or $basearch variables + # eg 'epel/7/x86_64', 'epel/7', 'epel/x86_64' + { + yum repolist enabled --verbose --cacheonly -q 2>/dev/null \ + || yum repolist enabled --verbose -q --setopt='*.skip_if_unavailable=1' + } | grep -E -q "^Repo-id\s*: $repo(/.+)?\s*$" + ;; + dnf) + # note: --noplugins may cause failure and empty output on RedHat + { + dnf repoinfo --enabled --cacheonly -q 2>/dev/null \ + || dnf repoinfo --enabled -q --setopt='*.skip_if_unavailable=1' + } | grep -E -q "^Repo-id\s*: $repo\s*$" + ;; + esac +} + +has_rh_config_manager() +{ + case "$package_manager" in + yum) yum-config-manager --help >/dev/null 2>&1 ;; + dnf) dnf config-manager --help >/dev/null 2>&1 ;; + esac +} + +install_rh_config_manager() +{ + case "$package_manager" in + yum) yum install --disablerepo 'PLESK_*' -q -y 'yum-utils' --setopt='*.skip_if_unavailable=1' ;; + dnf) dnf install --disablerepo 'PLESK_*' -q -y 'dnf-command(config-manager)' --setopt='*.skip_if_unavailable=1' ;; + esac +} + +check_rh_config_manager() +{ + if ! has_rh_config_manager && ! install_rh_config_manager; then + report_rh_no_config_manager + return $RET_FATAL + fi +} + +enable_rh_repo() +{ + case "$package_manager" in + yum) yum-config-manager --enable "$@" && has_rh_enabled_repo "$@" ;; + dnf) dnf config-manager --set-enabled "$@" && has_rh_enabled_repo "$@" ;; + esac +} + +enable_sm_repo() +{ + ! has_rh_enabled_repo "$@" || return 0 + subscription-manager repos --enable "$@" || return $? + # On RedHat 8 above command may return 0 on failure with "Repositories disabled by configuration." + has_rh_enabled_repo "$@" +} + +check_epel() +{ + ! enable_rh_repo "epel" || return 0 + + # try to install epel-release from centos/extras or plesk/thirdparty repo + # and then try to update it to last version shipped by epel itself + # to make package upgradable with pum + "$package_manager" install --disablerepo 'PLESK_*' -q -y 'epel-release' --setopt='*.skip_if_unavailable=1' 2>/dev/null \ + || "$package_manager" install --disablerepo='*' --enablerepo 'PLESK_18_*-thirdparty' -q -y 'epel-release' \ + || "$package_manager" install -q -y "https://dl.fedoraproject.org/pub/epel/epel-release-latest-$os_version.noarch.rpm" \ + && "$package_manager" update -q -y 'epel-release' --setopt='*.skip_if_unavailable=1' 2>/dev/null + + # Ensure any other EPEL repos have cache for subsequent check for broken repos (AL9) + local epel_repos="$( + [ "$package_manager" != "dnf" ] || { + dnf repolist --enabled --cacheonly -q 2>/dev/null || + dnf repolist --enabled -q --setopt='*.skip_if_unavailable=1' + } | sed -n -e '1d' -e 's/^!\?\(epel\S\+\).*/\1/p' + )" + for repo in $epel_repos; do + "$package_manager" makecache --repo "$repo" -q + done + + ! has_rh_enabled_repo "epel" || return 0 + + report_no_repo "epel" + return $RET_FATAL +} + +check_codeready() +{ + local repo_rhel="codeready-builder-for-rhel-$os_version-$os_arch-rpms" + local repo_rhui="codeready-builder-for-rhel-$os_version-rhui-rpms" + local repo_rhui_alt="codeready-builder-for-rhel-$os_version-$os_arch-rhui-rpms" + local repo_rhui_alt2="rhui-codeready-builder-for-rhel-$os_version-$os_arch-rhui-rpms" + + ! enable_sm_repo "$repo_rhel" || return 0 + ! enable_rh_repo "$repo_rhui" || return 0 + ! enable_rh_repo "$repo_rhui_alt" || return 0 + ! enable_rh_repo "$repo_rhui_alt2" || return 0 + + report_no_repo "$repo_rhel" + return $RET_FATAL +} + +check_optional() +{ + local repo_rhel="rhel-$os_version-server-optional-rpms" + local repo_rhui="rhel-$os_version-server-rhui-optional-rpms" + + ! enable_sm_repo "$repo_rhel" || return 0 + ! enable_rh_repo "$repo_rhui" || return 0 + + report_no_repo "$repo_rhel" + return $RET_FATAL +} + +check_repos_rhel9() +{ + check_rh_config_manager || return $? + + local rc=0 + + check_epel || rc="$(( $rc | $? ))" + check_codeready || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + return $rc +} + +check_repos_almalinux9() +{ + check_rh_config_manager || return $? + + local rc=0 + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + # powertools is renamed to crb since AlmaLinux 9 + ! enable_rh_repo "crb" || return $rc + + report_no_repo "crb" + return $RET_FATAL +} + +check_repos_cloudlinux9() +{ + check_repos_almalinux9 "$@" +} + +check_repos_almalinux10() +{ + check_repos_almalinux9 "$@" +} + +check_repos_centos8() +{ + check_rh_config_manager || return $? + + local rc=0 + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + # names of repos are lowercased since 8.3 + ! enable_rh_repo "powertools" || return $rc + ! enable_rh_repo "PowerTools" || return $rc + + report_no_repo "powertools" + return $RET_FATAL +} + +check_repos_cloudlinux8() +{ + check_rh_config_manager || return $? + + local rc=0 + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + # names of repos are changed since 8.5 + ! enable_rh_repo "powertools" || return $rc + ! enable_rh_repo "cloudlinux-PowerTools" || return $rc + + report_no_repo "powertools" + return $RET_FATAL +} + +check_repos_rhel8() +{ + check_rh_config_manager || return $? + + local rc=0 + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + [ "$1" = "install" ] || return $rc + + check_codeready || rc="$(( $rc | $? ))" + + return $rc +} + +check_repos_almalinux8() +{ + check_repos_centos8 "$@" +} + +check_repos_rocky8() +{ + check_repos_centos8 "$@" +} + +check_repos_rhel7() +{ + check_rh_config_manager || return $? + + local rc=0 + + check_epel || rc="$(( $rc | $? ))" + check_optional || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + return $rc +} + +check_repos_centos7_based() +{ + check_rh_config_manager || return $? + + local rc=0 + + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + return $rc +} + +sed_escape() +{ + # Note: this is not a full implementation + echo -n "$1" | sed -e 's|\.|\\.|g' +} + +switch_eol_centos_repos() +{ + local old_mirrorlist_host="mirrorlist.centos.org" + local old_host="mirror.centos.org" + local new_host="vault.centos.org" + + grep -qFw "$old_host" /etc/yum.repos.d/CentOS-*.repo 2>/dev/null || return 0 + local backup="`mktemp -d "/tmp/yum.repos.d-$(date --rfc-3339=date)-XXXXXX"`" + ! [ -d "$backup" ] || cp -raT /etc/yum.repos.d "$backup" || : + + sed -i \ + -e "s|^\s*\(mirrorlist\b[^/]*//`sed_escape "$old_mirrorlist_host"`/.*\)$|#\1|" \ + -e "s|^#*\s*baseurl\b\([^/]*\)//`sed_escape "$old_host"`/\(.*\)$|baseurl\1//$new_host/\2|" \ + /etc/yum.repos.d/CentOS-*.repo + echo "YUM package manager repositories were backed up to '$backup' and switched from $old_host to $new_host ." >&2 +} + +check_repos_centos7() +{ + switch_eol_centos_repos + + check_repos_centos7_based "$@" +} + +check_repos_cloudlinux7() +{ + check_repos_centos7_based "$@" +} + +check_repos_virtuozzo7() +{ + check_repos_centos7_based "$@" +} + +find_apt_repo() +{ + local repo="$1" + + local dist_tag= + ! [ "$os_name" = "ubuntu" ] || dist_tag="a" + ! [ "$os_name" = "debian" ] || dist_tag="n" + + if [ -z "$_apt_cache_policy" ]; then + # extract info of each available release as a string which consists of 'tag=value' + # filter out releases with priority less or equal to 100 + _apt_cache_policy="$( + apt-cache policy \ + | grep "b=$pkg_arch" \ + | grep -Eo '([a-z]=[^,]+,?)*' \ + )" + fi + + local l="$(echo "$repo" | cut -f1 -d'/')" + local d="$(echo "$repo" | cut -f2 -d'/')" + local c="$(echo "$repo" | cut -f3 -d'/')" + + # try to find releases by distribution and component + echo "$_apt_cache_policy" \ + | grep -E "(^|,)l=$l(,|$)" \ + | grep -E "(^|,)$dist_tag=$d(,|$)" \ + | grep -E "(^|,)c=$c(,|$)" \ + | while IFS="$(printf '\n')" read rel && [ -n "$rel" ]; do + l="$(echo "$rel" | grep -Eo "(^|,)l=[^,]+" | cut -f2 -d"=")" + d="$(echo "$rel" | grep -Eo "(^|,)$dist_tag=[^,]+" | cut -f2 -d"=")" + c="$(echo "$rel" | grep -Eo "(^|,)c=[^,]+" | cut -f2 -d"=")" + echo "$l/$d/$c" + done +} + +apt_install_packages() +{ + DEBIAN_FRONTEND=noninteractive LANG=C PATH=/usr/sbin:/usr/bin:/sbin:/bin \ + apt-get -qq --assume-yes -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold -o APT::Install-Recommends=no \ + install "$@" +} + +# Takes a list of suites and disables them in APT sources. +# Multiline deb822 format is supported. +disable_apt_suites_deb822() +{ + local python3=/usr/bin/python3 + + "$python3" -c 'import aptsources.sourceslist' 2>/dev/null || + apt_install_packages python3-apt + + "$python3" -c ' +import sys + +from aptsources.sourceslist import SourcesList + + +suites_to_disable=set(sys.argv[1:]) + +sources_list = SourcesList(deb822=True) + +sources_changed = False +for src in sources_list: + if src.invalid: + continue + suites = getattr(src, "suites", ()) + if not suites: + continue + new_suites = [s for s in suites if s not in suites_to_disable] + if len(new_suites) != len(suites): + sources_changed = True + if len(new_suites) == 0: + src.disabled = True + else: + src.suites = new_suites + +if sources_changed: + sources_list.save() +' "$@" + + # Since we have changed the repositories list, we should re-read _apt_cache_policy on a next call + # of the find_apt_repo function. Hence we have to reset the value of the variable + _apt_cache_policy="" +} + +disable_apt_repo() +{ + local repos_to_disable="$(find_apt_repo "$1" | cut -d '/' -f 2,3 | sort | uniq)" + if [ -z "$repos_to_disable" ]; then + return 0 + fi + + echo "$repos_to_disable" \ + | while IFS= read -r repo_to_disable && [ -n "$repo_to_disable" ]; do + local distrib=${repo_to_disable%%/*} + local component=${repo_to_disable##*/} + find /etc/apt -name "*.list" -exec \ + sed -i -e "/^\s*#/! s/.*\s$distrib\s\+$component\b/# &/" {} + + done + + # Since we have changed the repositories list, we should re-read _apt_cache_policy on a next call + # of the find_apt_repo function. Hence we have to reset the value of the variable + _apt_cache_policy="" + + return 0 +} + +check_required_apt_repo() +{ + local repo="$1" + [ -z "$(find_apt_repo "$repo")" ] || return 0 + report_no_repo "$repo" + return $RET_FATAL +} + +check_unsupported_apt_repos_ubuntu() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + + local repos="$( + find_apt_repo "Ubuntu/[^,]+/[^,]+" | grep -v "Ubuntu/$os_codename.*/.*" + find_apt_repo "Debian[^,]*/[^,]+/[^,]+" + )" + [ -n "$repos" ] || return 0 + + echo "$repos" | while IFS="$(printf '\n')" read repo; do + report_unsupported_repo "$repo" + done + + [ "$mode" = "install" ] || return $RET_WARN + return $RET_FATAL +} + +check_repos_ubuntu18() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + local rc=0 + + check_required_apt_repo "Ubuntu/$os_codename/main" || rc="$(( $rc | $? ))" + check_required_apt_repo "Ubuntu/$os_codename/universe" || rc="$(( $rc | $? ))" + check_required_apt_repo "Ubuntu/$os_codename-updates/main" || rc="$(( $rc | $? ))" + check_required_apt_repo "Ubuntu/$os_codename-updates/universe" || rc="$(( $rc | $? ))" + check_unsupported_apt_repos_ubuntu "$mode" || rc="$(( $rc | $? ))" + + return $rc +} + + +check_repos_ubuntu() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + local rc=0 + + check_required_apt_repo "Ubuntu/$os_codename/main" || rc="$(( $rc | $? ))" + check_required_apt_repo "Ubuntu/$os_codename/universe" || rc="$(( $rc | $? ))" + check_unsupported_apt_repos_ubuntu "$mode" || rc="$(( $rc | $? ))" + + return $rc +} + +check_unsupported_apt_repos_debian() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + + local repos="$( + find_apt_repo "Debian Backports/$os_codename-backports/[^,]+" + find_apt_repo "Debian[^,]*/[^,]+/[^,]+" | grep -v "Debian.*/$os_codename.*/.*" + find_apt_repo "Ubuntu/[^,]+/[^,]+" + )" + [ -n "$repos" ] || return 0 + + echo "$repos" | while IFS="$(printf '\n')" read repo; do + report_unsupported_repo "$repo" + done + + [ "$mode" = "install" ] || return $RET_WARN + return $RET_FATAL +} + +check_repos_debian() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + local rc=0 + + if [ "$os_name" = "debian" -a "$os_version" -ge 12 ]; then + disable_apt_suites_deb822 "$os_codename-backports" + else + disable_apt_repo "Debian Backports/$os_codename-backports/[^,]+" + fi + + check_required_apt_repo "Debian/$os_codename/main" || rc="$(( $rc | $? ))" + check_unsupported_apt_repos_debian "$mode" || rc="$(( $rc | $? ))" + + return $rc +} + +# --- + +skip_checker_on_flag "Repository check" "/tmp/plesk-installer-skip-repository-check.flag" + +checker_main 'check_repos' "$1" diff --git a/root/parallels/pool/PSA_18.0.73_17725/examiners/sh_cmd.sh b/root/parallels/pool/PSA_18.0.73_17725/examiners/sh_cmd.sh new file mode 100755 index 0000000000..ed95d0acbb --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17725/examiners/sh_cmd.sh @@ -0,0 +1,7 @@ +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ "X${PLESK_INSTALLER_DEBUG}" = "X" ] || set -x +[ "X${PLESK_INSTALLER_STRICT_MODE}" = "X" ] || set -e + +exec "$@" diff --git a/root/parallels/pool/PSA_18.0.73_17725/plesk-18.0.73-ubt24.04-x86_64.inf3 b/root/parallels/pool/PSA_18.0.73_17725/plesk-18.0.73-ubt24.04-x86_64.inf3 new file mode 100644 index 0000000000..30083b61b3 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17725/plesk-18.0.73-ubt24.04-x86_64.inf3 @@ -0,0 +1,927 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -----BEGIN PGP PUBLIC KEY BLOCK----- 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 VNnMRY8n =Hv0N -----END PGP PUBLIC KEY BLOCK----- + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + + + + + mysqlgroup + l10n + proftpd + webservers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + imapservers + + + + + + + + + + + + + + + + + + + imapservers + + + + + + + + + + + + + + mailman + spamassassin + drweb + sophos + courier + dovecot + + + + + + + + + + + + + + + + + + + + + + mailservers + + + + + + + + + + + + + + + + + + + + mailservers + + + + + + + + + + + + + + + + + + panel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + webservers + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + + + + + + + + + + + + + + + + php7.4 + + + + + + + + + + + + + + + + + + + + + + + + + + php8.3 + + + + + + + + + + + webservers + + + + + + + + webservers + + + + + + + + + + + + + + + + + + panel + + + + + + + + + + + + + panel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + panel + + + + + + + + + + + + + + + + + + + + panel + + + + + + + panel + + + + + + + + panel + + + + + + + panel + passenger + + + + + + ruby + + + + + + + panel + + + + + + panel + + + + + + panel + passenger + + + + + + + + + + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + panel + roundcube + postfix + dovecot + mod_fcgid + proftpd + webalizer + awstats + webservers + nginx + mysqlgroup + l10n + bind + wp-toolkit + advisor + git + xovi + imunify360 + fail2ban + modsecurity + sslit + letsencrypt + repair-kit + composer + monitoring + log-browser + ssh-terminal + site-import + sitejet + ntp-timesync + php8.3 + php8.4 + mfa + configurations-troubleshooter + + + panel + roundcube + postfix + dovecot + mod_fcgid + proftpd + webalizer + awstats + webservers + nginx + mysqlgroup + l10n + bind + wp-toolkit + advisor + git + xovi + imunify360 + fail2ban + modsecurity + sslit + letsencrypt + repair-kit + composer + monitoring + log-browser + ssh-terminal + site-import + sitejet + ntp-timesync + php8.1 + php8.2 + php8.3 + php8.4 + mfa + configurations-troubleshooter + resctrl + drweb + postgresql + spamassassin + ruby + gems-pre + nodejs + pmm + psa-firewall + watchdog + passenger + phpgroup + sophos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.73_17725/release.inf3 b/root/parallels/pool/PSA_18.0.73_17725/release.inf3 new file mode 100644 index 0000000000..4fb000283d --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17725/release.inf3 @@ -0,0 +1,36 @@ + + + + + + + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.73_17940/examiners/check_broken_timezone.sh b/root/parallels/pool/PSA_18.0.73_17940/examiners/check_broken_timezone.sh new file mode 100755 index 0000000000..ee862642be --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17940/examiners/check_broken_timezone.sh @@ -0,0 +1,255 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ -z "$PLESK_INSTALLER_DEBUG" ] || set -x +[ -z "$PLESK_INSTALLER_STRICT_MODE" ] || set -e + +export LC_ALL=C +unset GREP_OPTIONS + +RET_SUCCESS=0 +RET_WARN=1 +RET_FATAL=2 + +is_function_defined() +{ + local fn="$1" + case "$(type $fn 2>/dev/null)" in + *function*) + return 0 + ;; + esac + return 1 +} + +# @params are tags in format "key=value" +# Report body (human readable information) is read from stdin +# and copied to stderr. +make_error_report() +{ + local report_file="${PLESK_INSTALLER_ERROR_REPORT:-}" + + local python_bin= + for bin in "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2" "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3"; do + if [ -x "$bin" ]; then + python_bin="$bin" + break + fi + done + + if [ -n "$report_file" -a -x "$python_bin" ]; then + "$python_bin" -c 'import sys, json +report_file = sys.argv[1] +error = sys.stdin.read() + +sys.stderr.write(error) + +data = { + "error": error, +} + +for tag in sys.argv[2:]: + k, v = tag.split("=", 1) + data[k] = v + +with open(report_file, "a") as f: + json.dump(data, f) + f.write("\n") +' "$report_file" "date=$(date --utc --iso-8601=ns)" "$@" + else + cat - >&2 + fi +} + +detect_platform() +{ + . /etc/os-release + os_name="$ID" + os_version="${VERSION_ID%%.*}" + os_arch="$(uname -m)" + if [ -e /etc/debian_version ]; then + case "$os_arch" in + x86_64) pkg_arch="amd64" ;; + aarch64) pkg_arch="arm64" ;; + esac + if [ -n "$VERSION_CODENAME" ]; then + os_codename="$VERSION_CODENAME" + else + case "$os_name$os_version" in + debian10) os_codename="buster" ;; + debian11) os_codename="bullseye" ;; + debian12) os_codename="bookworm" ;; + ubuntu18) os_codename="bionic" ;; + ubuntu20) os_codename="focal" ;; + ubuntu22) os_codename="jammy" ;; + ubuntu24) os_codename="noble" ;; + esac + fi + fi + + case "$os_name$os_version" in + rhel7|centos7|cloudlinux7|virtuozzo7) + package_manager="yum" + ;; + rhel*|centos*|cloudlinux*|almalinux*|rocky*) + package_manager="dnf" + ;; + debian*|ubuntu*) + package_manager="apt" + ;; + esac + + if [ "$os_name" = "ubuntu" -o "$os_name" = "debian" ]; then + PRODUCT_ROOT_D="/opt/psa" + else + PRODUCT_ROOT_D="/usr/local/psa" + fi +} + +has_os_impl_function() +{ + local prefix="$1" + local fn="${prefix}_${os_name}${os_version}" + is_function_defined "$fn" +} + +call_os_impl_function() +{ + local prefix="$1" + shift + local fn="${prefix}_${os_name}${os_version}" + "$fn" "$@" +} + +skip_checker_on_flag() +{ + local name="$1" + local flag="$2" + + if [ -f "$flag" ]; then + echo "$name was skipped due to flag file." >&2 + exit $RET_SUCCESS + fi +} + +skip_checker_on_env() +{ + local name="$1" + local env="$2" + + if [ -n "$env" ]; then + echo "$name was skipped due to environment variable." >&2 + exit $RET_SUCCESS + fi +} + +checker_main() +{ + local fnprefix="$1" + shift + + detect_platform + # try to execute checker only if all attributes are detected + [ -n "$os_name" -a -n "$os_version" ] || return $RET_SUCCESS + + for checker in "${fnprefix}_${os_name}${os_version}" "${fnprefix}_${os_name}" "${fnprefix}"; do + if is_function_defined "$checker"; then + local rc=$RET_SUCCESS + "$checker" "$@" || rc=$? + [ "$(( $rc & $RET_FATAL ))" = "0" ] || return $RET_FATAL + [ "$(( $rc & $RET_WARN ))" = "0" ] || return $RET_WARN + return $rc + fi + done + return $RET_SUCCESS +} + +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +# If env variable PLESK_INSTALLER_ERROR_REPORT=path_to_file is specified then in case of error +# check-broken-tz.sh writes single line json report into it with the following fields: +# - "stage": "timezonefix" +# - "level": "error" +# - "errtype": "failure" +# - "date": time of error occurance ("2024-07-24T06:59:43,127545441+0000") +# - "error": human readable error message + +report_dpkg_configure_fail() +{ + local pkgname="$1" + make_error_report 'stage=timezonefix' 'level=error' 'errtype=dpkgconfigurefailed' <<-EOL + Could not configure the packages ( $pkgname ). See https://support.plesk.com/hc/en-us/articles/24721507961623-Plesk-provides-error-on-update-Package-tzdata-is-not-configured-yet for more details. + EOL +} + +report_get_tz_fail() +{ + make_error_report 'stage=timezonefix' 'level=error' 'errtype=gettzfailed' <<-EOL + Could not get the system timezone. See https://support.plesk.com/hc/en-us/articles/24721507961623-Plesk-provides-error-on-update-Package-tzdata-is-not-configured-yet for more details. + EOL +} + +report_set_tz_fail() +{ + local tz="$1" + + make_error_report 'stage=timezonefix' 'level=error' 'errtype=settzfailed' <<-EOL + Could not set the system timezone ( $tz ). See https://support.plesk.com/hc/en-us/articles/24721507961623-Plesk-provides-error-on-update-Package-tzdata-is-not-configured-yet for more details. + EOL +} + +get_current_tz() +{ + [ -L /etc/localtime ] || return 1 + + local tz + tz="$(readlink -m /etc/localtime)" || return 1 + [ -f "$tz" ] || return 1 + case "$tz" in + /usr/share/zoneinfo/*) ;; + *) return 1;; + esac + tz="${tz#/usr/share/zoneinfo/}" + [ -n "$tz" ] || return 1 + + echo -n "${tz}" +} + +check_timezone_ubuntu() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + + # PPP-65676: Plesk update fails on ubuntu if timezone is CET + if dpkg-query --showformat='${db:Status-Status}\n' --show 'tzdata' | grep -wq 'half-configured'; then + local origtz + origtz=$(get_current_tz) + if [ $? != 0 ]; then + report_get_tz_fail + return $RET_WARN + fi + if ! timedatectl set-timezone 'Etc/UTC'; then + timedatectl set-timezone "$origtz" + report_set_tz_fail 'Etc/UTC' + return $RET_WARN + fi + if ! dpkg --configure 'tzdata'; then + timedatectl set-timezone "$origtz" + report_dpkg_configure_fail 'tzdata' + return $RET_WARN + fi + if ! timedatectl set-timezone "$origtz"; then + report_set_tz_fail "$origtz" + return $RET_WARN + fi + fi + + return 0 +} + +# --- + +skip_checker_on_flag "Broken timezone check" "/tmp/plesk-installer-skip-check-broken-timezone.flag" + +checker_main 'check_timezone' "$1" diff --git a/root/parallels/pool/PSA_18.0.73_17940/examiners/disk_space_check.sh b/root/parallels/pool/PSA_18.0.73_17940/examiners/disk_space_check.sh new file mode 100755 index 0000000000..1fdfb44037 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17940/examiners/disk_space_check.sh @@ -0,0 +1,542 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ -z "$PLESK_INSTALLER_DEBUG" ] || set -x +[ -z "$PLESK_INSTALLER_STRICT_MODE" ] || set -e + +export LC_ALL=C +unset GREP_OPTIONS + +RET_SUCCESS=0 +RET_WARN=1 +RET_FATAL=2 + +is_function_defined() +{ + local fn="$1" + case "$(type $fn 2>/dev/null)" in + *function*) + return 0 + ;; + esac + return 1 +} + +# @params are tags in format "key=value" +# Report body (human readable information) is read from stdin +# and copied to stderr. +make_error_report() +{ + local report_file="${PLESK_INSTALLER_ERROR_REPORT:-}" + + local python_bin= + for bin in "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2" "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3"; do + if [ -x "$bin" ]; then + python_bin="$bin" + break + fi + done + + if [ -n "$report_file" -a -x "$python_bin" ]; then + "$python_bin" -c 'import sys, json +report_file = sys.argv[1] +error = sys.stdin.read() + +sys.stderr.write(error) + +data = { + "error": error, +} + +for tag in sys.argv[2:]: + k, v = tag.split("=", 1) + data[k] = v + +with open(report_file, "a") as f: + json.dump(data, f) + f.write("\n") +' "$report_file" "date=$(date --utc --iso-8601=ns)" "$@" + else + cat - >&2 + fi +} + +detect_platform() +{ + . /etc/os-release + os_name="$ID" + os_version="${VERSION_ID%%.*}" + os_arch="$(uname -m)" + if [ -e /etc/debian_version ]; then + case "$os_arch" in + x86_64) pkg_arch="amd64" ;; + aarch64) pkg_arch="arm64" ;; + esac + if [ -n "$VERSION_CODENAME" ]; then + os_codename="$VERSION_CODENAME" + else + case "$os_name$os_version" in + debian10) os_codename="buster" ;; + debian11) os_codename="bullseye" ;; + debian12) os_codename="bookworm" ;; + ubuntu18) os_codename="bionic" ;; + ubuntu20) os_codename="focal" ;; + ubuntu22) os_codename="jammy" ;; + ubuntu24) os_codename="noble" ;; + esac + fi + fi + + case "$os_name$os_version" in + rhel7|centos7|cloudlinux7|virtuozzo7) + package_manager="yum" + ;; + rhel*|centos*|cloudlinux*|almalinux*|rocky*) + package_manager="dnf" + ;; + debian*|ubuntu*) + package_manager="apt" + ;; + esac + + if [ "$os_name" = "ubuntu" -o "$os_name" = "debian" ]; then + PRODUCT_ROOT_D="/opt/psa" + else + PRODUCT_ROOT_D="/usr/local/psa" + fi +} + +has_os_impl_function() +{ + local prefix="$1" + local fn="${prefix}_${os_name}${os_version}" + is_function_defined "$fn" +} + +call_os_impl_function() +{ + local prefix="$1" + shift + local fn="${prefix}_${os_name}${os_version}" + "$fn" "$@" +} + +skip_checker_on_flag() +{ + local name="$1" + local flag="$2" + + if [ -f "$flag" ]; then + echo "$name was skipped due to flag file." >&2 + exit $RET_SUCCESS + fi +} + +skip_checker_on_env() +{ + local name="$1" + local env="$2" + + if [ -n "$env" ]; then + echo "$name was skipped due to environment variable." >&2 + exit $RET_SUCCESS + fi +} + +checker_main() +{ + local fnprefix="$1" + shift + + detect_platform + # try to execute checker only if all attributes are detected + [ -n "$os_name" -a -n "$os_version" ] || return $RET_SUCCESS + + for checker in "${fnprefix}_${os_name}${os_version}" "${fnprefix}_${os_name}" "${fnprefix}"; do + if is_function_defined "$checker"; then + local rc=$RET_SUCCESS + "$checker" "$@" || rc=$? + [ "$(( $rc & $RET_FATAL ))" = "0" ] || return $RET_FATAL + [ "$(( $rc & $RET_WARN ))" = "0" ] || return $RET_WARN + return $rc + fi + done + return $RET_SUCCESS +} + +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +# If env variable PLESK_INSTALLER_ERROR_REPORT=path_to_file is specified then in case of error +# disk_space_check.sh writes single line json report into it with the following fields: +# - "stage": "diskspacecheck" +# - "level": "error" +# - "errtype": "notenoughdiskspace" +# - "volume": volume with not enough diskspace (e.g. "/") +# - "required": required diskspace on the volume, human readable (e.g. "600 MB") +# - "available": available diskspace on the volume, human readable (e.g. "255 MB") +# - "needtofree": amount of diskspace which should be freed on the volume, human readable (e.g. "345 MB") +# - "date": time of error occurance ("2020-03-24T06:59:43,127545441+0000") +# - "error": human readable error message ("There is not enough disk space available in the / directory.") + +# Required values below for Full installation are in MB. See 'du -cs -BM /*' and 'df -Pm'. + +required_disk_space_cloudlinux7() +{ + case "$1" in + /opt) echo 900 ;; + /usr) echo 4400 ;; + /var) echo 600 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_cloudlinux8() +{ + case "$1" in + /opt) echo 1200 ;; + /usr) echo 4400 ;; + /var) echo 700 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_centos7() +{ + case "$1" in + /opt) echo 900 ;; + /usr) echo 4100 ;; + /var) echo 600 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_centos8() +{ + case "$1" in + /opt) echo 900 ;; + /usr) echo 4500 ;; + /var) echo 800 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_virtuozzo7() +{ + required_disk_space_centos7 "$1" +} + +required_disk_space_rhel7() +{ + required_disk_space_centos7 "$1" +} + +required_disk_space_rhel8() +{ + required_disk_space_centos8 "$1" +} + +required_disk_space_almalinux8() +{ + required_disk_space_centos8 "$1" +} + +required_disk_space_rocky8() +{ + required_disk_space_centos8 "$1" +} + +required_disk_space_rhel9() +{ + case "$1" in + /opt) echo 500 ;; + /usr) echo 4000 ;; + /var) echo 800 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_almalinux9() +{ + required_disk_space_rhel9 "$1" +} + +required_disk_space_almalinux10() +{ + required_disk_space_almalinux9 "$1" +} + +required_disk_space_cloudlinux9() +{ + required_disk_space_rhel9 "$1" +} + +required_disk_space_debian10() +{ + case "$1" in + /opt) echo 1800 ;; + /usr) echo 2300 ;; + /var) echo 1700 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_debian11() +{ + case "$1" in + /opt) echo 1500 ;; + /usr) echo 3100 ;; + /var) echo 1800 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_debian12() +{ + case "$1" in + /opt) echo 2700 ;; + /usr) echo 2500 ;; + /var) echo 2200 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_debian13() +{ + case "$1" in + /opt) echo 2700 ;; + /usr) echo 2500 ;; + /var) echo 2200 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_ubuntu18() +{ + case "$1" in + /opt) echo 900 ;; + /usr) echo 1800 ;; + /var) echo 600 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_ubuntu20() +{ + case "$1" in + /opt) echo 1800 ;; + /usr) echo 2900 ;; + /var) echo 1600 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_ubuntu22() +{ + case "$1" in + /opt) echo 1800 ;; + /usr) echo 3900 ;; + /var) echo 1900 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_ubuntu24() +{ + case "$1" in + /opt) echo 3200 ;; + /usr) echo 1800 ;; + /var) echo 2400 ;; + /tmp) echo 100 ;; + esac +} + +required_update_upgrade_disk_space() +{ + case "$1" in + /opt) echo 100 ;; + /usr) echo 300 ;; + /var) echo 600 ;; + /tmp) echo 100 ;; + esac +} + +clean_tmp() +{ + local volume="$1" + local path="/tmp" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'systemd-tmpfiles --clean --prefix $path'" + systemd-tmpfiles --clean --prefix "$path" 2>&1 +} + +clean_yum() +{ + local volume="$1" + local path="/var/cache/yum" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'yum clean all'" + yum clean all 2>&1 + + # The command above doesn't clean untracked repos (missing in configuration), clean if left > 2 Mb + [ "`du -sm "$path" | awk '{ print $1 }'`" -gt 2 ] || return 0 + echo "Cleaning $path via 'rm -rf $path/*'" + rm -rf "$path"/* 2>&1 +} + +clean_dnf() +{ + local volume="$1" + local path="/var/cache/dnf" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'dnf clean all'" + dnf clean all 2>&1 +} + +clean_apt() +{ + local volume="$1" + local path="/var/cache/apt" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'apt-get clean'" + apt-get clean 2>&1 +} + +clean_journal() +{ + local volume="$1" + local path="/var/log/journal" + is_path_on_volume "$path" "$volume" || return 0 + + # Note that --rotate may cause more space to be freed, but may also cause more space to be used + echo "Cleaning $path via 'journalctl --vacuum-time 1d'" + journalctl --vacuum-time 1d 2>&1 +} + +clean_ext_packages() +{ + local volume="$1" + local path="$PRODUCT_ROOT_D/var/modules-packages" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'rm -rf $path/*'" + rm -rf "$path"/* 2>&1 +} + +# @param $1 target directory +mount_point() +{ + df -Pm $1 | awk 'NR==2 { print $6 }' +} + +# @param $1 target directory +available_disk_space() +{ + df -Pm $1 | awk 'NR==2 { print $4 }' +} + +is_path_on_volume() +{ + local path="$1" + local volume="$2" + [ -d "$path" ] && [ "`mount_point "$path"`" = "$volume" ] +} + +# @param $1 target directory +# @param $2 mode (install/upgrade/update) +req_disk_space() +{ + if [ "$2" != "install" ]; then + required_update_upgrade_disk_space "$1" + return + fi + + has_os_impl_function "required_disk_space" || { + echo "There are no requirements defined for $os_name$os_version." >&2 + echo "Disk space check cannot be performed." >&2 + exit $RET_WARN + } + call_os_impl_function "required_disk_space" "$1" +} + +human_readable_size() +{ + echo "$1" | awk ' + function human(x) { + s = "MGTEPYZ"; + while (x >= 1000 && length(s) > 1) { + x /= 1024; s = substr(s, 2); + } + # 0.05 below will make sure the value is rounded up + return sprintf("%.1f %sB", x + 0.05, substr(s, 1, 1)); + } + { print human($1); }' +} + +# @param $1 target directory +# @param $2 required disk space +# @param $3 check only flag (don't emit errors) +check_available_disk_space() +{ + local volume="$1" + local required="$2" + local check_only="${3:-}" + local available="$(available_disk_space "$volume")" + if [ "$available" -lt "$required" ]; then + local needtofree + needtofree="`human_readable_size $((required - available))`" + [ -n "$check_only" ] || + make_error_report 'stage=diskspacecheck' 'level=error' 'errtype=notenoughdiskspace' \ + "volume=$volume" "required=$required MB" "available=$available MB" "needtofree=$needtofree" \ + <<-EOL + There is not enough disk space available in the $1 directory. + You need to free up $needtofree. + EOL + return "$RET_FATAL" + fi +} + +# @param $1 target directory +# @param $2 required disk space +clean_and_check_available_disk_space() +{ + if [ -n "$PLESK_INSTALLER_FORCE_CLEAN_DISK_SPACE" ] || ! check_available_disk_space "$@" --check-only; then + clean_disk_space "$1" + check_available_disk_space "$@" + fi +} + +# Cleans up disk space on the volume +clean_disk_space() +{ + local volume="$1" + for cleanup_func in clean_tmp clean_yum clean_dnf clean_apt clean_journal clean_ext_packages; do + "$cleanup_func" "$volume" + done +} + +# @param $1 mode (install/upgrade/update) +clean_and_check_disk_space() +{ + local mode="$1" + local shared=0 + + for target_directory in /opt /usr /var /tmp; do + local required=$(req_disk_space "$target_directory" "$mode") + [ -n "$required" ] || return "$RET_WARN" + + if is_path_on_volume "$target_directory" "/"; then + shared="$((shared + required))" + else + clean_and_check_available_disk_space "$target_directory" "$required" || return $? + fi + done + + clean_and_check_available_disk_space "/" "$shared" || return $? +} + +checker_main 'clean_and_check_disk_space' "$1" diff --git a/root/parallels/pool/PSA_18.0.73_17940/examiners/license_key_check.php b/root/parallels/pool/PSA_18.0.73_17940/examiners/license_key_check.php new file mode 100644 index 0000000000..917e44709f --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17940/examiners/license_key_check.php @@ -0,0 +1,111 @@ += 10.0.0 */ +if (!is_array($vers)) { + $vers = [$vers]; +} + +$match = false; +foreach ($vers as $ver) { + if (!is_array($ver)) { + $match |= strtok($ver, ".") == strtok($targetVersion, "."); + } else { + $match |= ("any" == $ver[0] || version_compare($ver[0], $targetVersion) <= 0) && + ("any" == $ver[1] || version_compare($ver[1], $targetVersion) >= 0); + } +} + +if ($match) { + fwrite(STDERR, "You do not need to upgrade the current license key.\n"); + fwrite(STDOUT, "License upgrade check to $targetVersion can be skipped.\n"); + fwrite(STDOUT, "Plesk versions compatible with the license key: " . preg_replace('/\n\s*/', '', var_export($vers, true)) . "\n"); + finish(0); +} + +if (!function_exists('ka_is_key_upgrade_available')) { + // Plesk 17.0 + fwrite(STDERR, "Cannot check whether Plesk license key upgrade is available.\n"); + finish(1, false); +} + +$si = getServerInfo(); +$result = ka_is_key_upgrade_available($prod, $targetVersion, $si); + +$isConfused = false; +switch ($result['code']) { + case RESULT_LICENSE_OK: + fwrite(STDERR, "The licensing server accepted the key upgrade request.\n"); + fwrite(STDERR, "License upgrade to $targetVersion is available.\n"); + fwrite(STDERR, "Response from the licensing server: {$result['message']}\n"); + finish(0); + case RESULT_NETWORK_PROBLEM: + fwrite(STDERR, "Unable to connect to the licensing server to check if license upgrade is available.\n"); + fwrite(STDERR, "Error message: {$result['message']}\n"); + finish(2, false); + case RESULT_LICENSE_PROBLEM: + fwrite(STDERR, "Warning: Your Plesk license key cannot be upgraded.\n"); + fwrite(STDERR, "Response from the licensing server: {$result['message']}\n"); + finish(2); + default: + $isConfused = true; + // fall-through + case RESULT_ERROR: + // This includes "Software Update Service (SUS) is not found for the given license key" case, but also many others. + fwrite(STDERR, "Failed to check whether a new license key is available.\n"); + fwrite(STDERR, "Error message: {$result['message']}\n"); + if ($isConfused) { + fwrite(STDERR, "Error code: {$result['code']}\n"); + } + finish(2, !$isConfused); +} diff --git a/root/parallels/pool/PSA_18.0.73_17940/examiners/package_manager_check.sh b/root/parallels/pool/PSA_18.0.73_17940/examiners/package_manager_check.sh new file mode 100755 index 0000000000..b089061d97 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17940/examiners/package_manager_check.sh @@ -0,0 +1,224 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ -z "$PLESK_INSTALLER_DEBUG" ] || set -x +[ -z "$PLESK_INSTALLER_STRICT_MODE" ] || set -e + +export LC_ALL=C +unset GREP_OPTIONS + +RET_SUCCESS=0 +RET_WARN=1 +RET_FATAL=2 + +is_function_defined() +{ + local fn="$1" + case "$(type $fn 2>/dev/null)" in + *function*) + return 0 + ;; + esac + return 1 +} + +# @params are tags in format "key=value" +# Report body (human readable information) is read from stdin +# and copied to stderr. +make_error_report() +{ + local report_file="${PLESK_INSTALLER_ERROR_REPORT:-}" + + local python_bin= + for bin in "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2" "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3"; do + if [ -x "$bin" ]; then + python_bin="$bin" + break + fi + done + + if [ -n "$report_file" -a -x "$python_bin" ]; then + "$python_bin" -c 'import sys, json +report_file = sys.argv[1] +error = sys.stdin.read() + +sys.stderr.write(error) + +data = { + "error": error, +} + +for tag in sys.argv[2:]: + k, v = tag.split("=", 1) + data[k] = v + +with open(report_file, "a") as f: + json.dump(data, f) + f.write("\n") +' "$report_file" "date=$(date --utc --iso-8601=ns)" "$@" + else + cat - >&2 + fi +} + +detect_platform() +{ + . /etc/os-release + os_name="$ID" + os_version="${VERSION_ID%%.*}" + os_arch="$(uname -m)" + if [ -e /etc/debian_version ]; then + case "$os_arch" in + x86_64) pkg_arch="amd64" ;; + aarch64) pkg_arch="arm64" ;; + esac + if [ -n "$VERSION_CODENAME" ]; then + os_codename="$VERSION_CODENAME" + else + case "$os_name$os_version" in + debian10) os_codename="buster" ;; + debian11) os_codename="bullseye" ;; + debian12) os_codename="bookworm" ;; + ubuntu18) os_codename="bionic" ;; + ubuntu20) os_codename="focal" ;; + ubuntu22) os_codename="jammy" ;; + ubuntu24) os_codename="noble" ;; + esac + fi + fi + + case "$os_name$os_version" in + rhel7|centos7|cloudlinux7|virtuozzo7) + package_manager="yum" + ;; + rhel*|centos*|cloudlinux*|almalinux*|rocky*) + package_manager="dnf" + ;; + debian*|ubuntu*) + package_manager="apt" + ;; + esac + + if [ "$os_name" = "ubuntu" -o "$os_name" = "debian" ]; then + PRODUCT_ROOT_D="/opt/psa" + else + PRODUCT_ROOT_D="/usr/local/psa" + fi +} + +has_os_impl_function() +{ + local prefix="$1" + local fn="${prefix}_${os_name}${os_version}" + is_function_defined "$fn" +} + +call_os_impl_function() +{ + local prefix="$1" + shift + local fn="${prefix}_${os_name}${os_version}" + "$fn" "$@" +} + +skip_checker_on_flag() +{ + local name="$1" + local flag="$2" + + if [ -f "$flag" ]; then + echo "$name was skipped due to flag file." >&2 + exit $RET_SUCCESS + fi +} + +skip_checker_on_env() +{ + local name="$1" + local env="$2" + + if [ -n "$env" ]; then + echo "$name was skipped due to environment variable." >&2 + exit $RET_SUCCESS + fi +} + +checker_main() +{ + local fnprefix="$1" + shift + + detect_platform + # try to execute checker only if all attributes are detected + [ -n "$os_name" -a -n "$os_version" ] || return $RET_SUCCESS + + for checker in "${fnprefix}_${os_name}${os_version}" "${fnprefix}_${os_name}" "${fnprefix}"; do + if is_function_defined "$checker"; then + local rc=$RET_SUCCESS + "$checker" "$@" || rc=$? + [ "$(( $rc & $RET_FATAL ))" = "0" ] || return $RET_FATAL + [ "$(( $rc & $RET_WARN ))" = "0" ] || return $RET_WARN + return $rc + fi + done + return $RET_SUCCESS +} + +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +check_package_manager_deb_based() +{ + local output= + output="`dpkg --audit 2>&1`" || output="$output"$'\n'"'dpkg --audit' finished with error code $?." + + if [ -n "$output" ]; then + make_error_report 'stage=packagemanagercheck' 'level=error' 'errtype=brokenpackages' <<-EOL + The system package manager reports the following problems: + + $output + + To continue with the installation, you need to resolve these issues + using the procedure below: + + 1. Make sure you have a full server snapshot. Although the + following steps are usually safe, they can still cause + data loss or irreversible changes. + 2. Run 'dpkg --configure -a'. This command can fix some of the + issues. However, it may fail. Regardless if it fails or not, + proceed with the following steps. + 3. Run 'PLESK_INSTALLER_SKIP_PACKAGE_MANAGER_CHECK=1 plesk installer update --skip-cleanup'. + Instead of 'update', you may need to use the command you used + previously (for example, 'upgrade' or 'install'). + 4. The next step depends on the outcome of the previous one: + - If step 3 was completed with the "You already have the latest + version of product(s) and all the selected components installed. + Installation will not continue." message, + run 'plesk repair installation'. + - If step 3 failed, run 'dpkg --audit'. This command can show you + packages that need to be reinstalled. To reinstall them, run + 'apt-get install --reinstall '. + 5. Run 'plesk installer update' to revert temporary changes and + validate that the issues are resolved. If the command fails or + triggers this check again, contact Plesk support. + + For more information, see + https://support.plesk.com/hc/en-us/articles/12871173047447-Plesk-update-on-Debian-Ubuntu-fails-dpkg-was-interrupted-you-must-manually-run-dpkg-configure-a-to-correct-the-problem + EOL + return "$RET_FATAL" + fi +} + +check_package_manager_debian() +{ + check_package_manager_deb_based +} + +check_package_manager_ubuntu() +{ + check_package_manager_deb_based +} + +skip_checker_on_env "Package manager check" "$PLESK_INSTALLER_SKIP_PACKAGE_MANAGER_CHECK" +skip_checker_on_flag "Package manager check" "/tmp/plesk-installer-skip-package-manager-check.flag" +checker_main 'check_package_manager' "$@" diff --git a/root/parallels/pool/PSA_18.0.73_17940/examiners/panel_preupgrade_checker.php b/root/parallels/pool/PSA_18.0.73_17940/examiners/panel_preupgrade_checker.php new file mode 100644 index 0000000000..181534e61e --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17940/examiners/panel_preupgrade_checker.php @@ -0,0 +1,2401 @@ +_checkMainIP(); //:INFO: Checking for main IP address https://support.plesk.com/hc/articles/12377857361687 + $this->_checkMySQLDatabaseUserRoot(); //:INFO: Plesk user "root" for MySQL database servers have not access to phpMyAdmin https://support.plesk.com/hc/articles/12378148229399 + $this->_checkProftpdIPv6(); //:INFO: #94489 FTP service proftpd cannot be started by xinetd if IPv6 is disabled https://support.plesk.com/hc/articles/12377796102807 + $this->_checkSwCollectdIntervalSetting(); //:INFO: #105405 https://support.plesk.com/hc/articles/213362569 + $this->_checkApacheStatus(); + $this->_checkImmutableBitOnPleskFiles(); //:INFO: #128414 https://support.plesk.com/hc/articles/12377589682327 + $this->_checkAbilityToChmodInDumpd(); //:INFO: ERROR while trying to backup MySQL database. https://support.plesk.com/hc/en-us/articles/12377010033943 + $this->_checkIpcollectionReference(); //:INFO: #72751 https://support.plesk.com/hc/articles/12377666752279 + $this->_checkApsApplicationContext(); //:INFO: Broken contexts of the APS applications can lead to errors at building Apache web server configuration https://support.plesk.com/hc/articles/12377671820311 + $this->_checkApsTablesInnoDB(); + $this->_checkCustomWebServerConfigTemplates(); //:INFO: #PPPM-1195 https://support.plesk.com/hc/articles/12377740416151 + $this->_checkMixedCaseDomainIssues(); //:INFO: #PPPM-4284 https://support.plesk.com/hc/en-us/articles/12377171904151 + + if (PleskOS::isDebLike()) { + $this->_checkSymLinkToOptPsa(); //:INFO: Check that symbolic link /usr/local/psa actually exists on Debian-like OSes https://support.plesk.com/hc/articles/12377511731991 + } + + if (Util::isVz()) { + $this->_checkShmPagesLimit(); //:INFO: PSA service does not start. Unable to allocate shared memory segment. https://support.plesk.com/hc/articles/12377744827927 + + if (PleskOS::isRedHatLike()) { + $this->_checkMailDriversConflict(); //:INFO: #PPPM-955 https://support.plesk.com/hc/articles/12378148767895 + } + } + } + + $this->_checkForCryptPasswords(); + $this->_checkMysqlServersTable(); //:INFO: Checking existing table mysql.servers + $this->_checkPleskTCPPorts(); //:INFO: Check the availability of Plesk TCP ports https://support.plesk.com/hc/articles/12377821243159 + + if (Util::isWindows()) { + $this->_checkPhprcSystemVariable(); //:INFO: #PPPM-294 Checking for PHPRC system variable + $this->_unknownISAPIfilters(); //:INFO: Checking for unknown ISAPI filters and show warning https://support.plesk.com/hc/articles/213913765 + $this->_checkMSVCR(); //:INFO: Just warning about possible issues related to Microsoft Visual C++ Redistributable Packages https://support.plesk.com/hc/articles/115000201014 + $this->_checkIisFcgiDllVersion(); //:INFO: Check iisfcgi.dll file version https://support.plesk.com/hc/articles/12378148258199 + $this->_checkCDONTSmailrootFolder(); //:INFO: After upgrade Plesk change permissions on folder of Collaboration Data Objects (CDO) for NTS (CDONTS) to default, https://support.plesk.com/hc/articles/12377887661335 + $this->_checkNullClientLogin(); //:INFO: #118963 https://support.plesk.com/hc/articles/12378122202391 + $this->checkDomainControllerLocation(); //:INFO: https://support.plesk.com/hc/articles/12377107094167 + } + } + + //:INFO: PSA service does not start. Unable to allocate shared memory segment. https://support.plesk.com/hc/articles/12377744827927 + function _checkShmPagesLimit() + { + $log = Log::getInstance("Checking for limit shmpages", true); + $ubc = Util::getUserBeanCounters(); + if ((int)$ubc['shmpages']['limit'] < 40960) { + $log->emergency("Virtuozzo Container set the \"shmpages\" limit to {$ubc['shmpages']['limit']}, which is too low. This may cause the sw-engine service not to start. To resolve this issue, refer to the article at https://support.plesk.com/hc/articles/12377744827927"); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: #PPPM-294 + function _checkPhprcSystemVariable() + { + $log = Log::getInstance("Checking for PHPRC system variable", true); + + $phprc = getenv('PHPRC'); + + if ($phprc) { + $log->emergency('The environment variable PHPRC is present in the system. This variable may lead to upgrade failure. Please delete this variable from the system environment.'); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: ERROR while trying to backup MySQL database. https://support.plesk.com/hc/en-us/articles/12377010033943 + function _checkAbilityToChmodInDumpd() + { + $log = Log::getInstance("Checking the possibility to change the permissions of files in the DUMP_D directory", true); + + $dump_d = Util::getSettingFromPsaConf('DUMP_D'); + if (is_null($dump_d)) { + $log->warning('Unable to obtain the path to the directory defined by the DUMP_D parameter. Check that the DUMP_D parameter is set in the /etc/psa/psa.conf file.'); + $log->resultWarning(); + return; + } + + $file = $dump_d . '/pre_upgrade_test_checkAbilityToChmodInDumpd'; + + if (false === file_put_contents($file, 'test')) { + $log->emergency('Unable to write in the ' . $dump_d . ' directory. The upgrade procedure will fail. Check that the folder exists and you have write permissions for it, and repeat upgrading. '); + $log->resultWarning(); + return; + } else { + $result = @chmod($file, 0600); + unlink($file); + if (!$result) { + $log->emergency( + 'Unable to change the permissions of files in the ' . $dump_d . ' directory. ' + . 'The upgrade procedure will fail. Please refer to https://support.plesk.com/hc/articles/12377010033943 for details.' + ); + $log->resultError(); + return; + } + } + $log->resultOk(); + } + + //:INFO: #128414 https://support.plesk.com/hc/articles/12377589682327 + function _checkImmutableBitOnPleskFiles() + { + $log = Log::getInstance("Checking Panel files for the immutable bit attribute"); + + $cmd = 'lsattr -R /usr/local/psa/ 2>/dev/null |awk \'{split($1, a, ""); if (a[5] == "i") {print;}}\''; + $output = Util::exec($cmd, $code); + $files = explode('\n', $output); + + if (!empty($output)) { + $log->info('The immutable bit attribute of the following Panel files can interrupt the upgrade procedure:'); + foreach ($files as $file) { + $log->info($file); + } + $log->emergency('Files with the immutable bit attribute were found. Please check https://support.plesk.com/hc/articles/12377589682327 for details.'); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: #PPPM-1195 https://support.plesk.com/hc/articles/12377740416151 + function _checkCustomWebServerConfigTemplates() + { + $log = Log::getInstance("Checking for custom web server configuration templates"); + $pleskDir = Util::getSettingFromPsaConf('PRODUCT_ROOT_D'); + $customTemplatesPath = $pleskDir . '/admin/conf/templates/custom'; + + if (is_dir($customTemplatesPath)) { + $log->warning("Directory {$customTemplatesPath} for custom web server configuration templates was found. Custom templates might be incompatible with a new Plesk version, and this might lead to failure to generate web server configuration files. Remove the directory to get rid of this warning. " + . "Please check https://support.plesk.com/hc/articles/12377740416151 for details."); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: #PPPM-955 https://support.plesk.com/hc/articles/12378148767895 + function _checkMailDriversConflict() + { + $log = Log::getInstance("Checking for a Plesk mail drivers conflict"); + + if (((true === PackageManager::isInstalled('psa-mail-pc-driver') || true === PackageManager::isInstalled('plesk-mail-pc-driver')) + && true === PackageManager::isInstalled('psa-qmail')) + || ((true === PackageManager::isInstalled('psa-mail-pc-driver') || true === PackageManager::isInstalled('plesk-mail-pc-driver')) + && true === PackageManager::isInstalled('psa-qmail-rblsmtpd'))) { + $log->warning("Plesk upgrade by EZ templates failed if psa-mail-pc-driver and psa-qmail or psa-qmail-rblsmtpd packages are installed. " + . "Please check https://support.plesk.com/hc/articles/12378148767895 for details."); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: #118963 https://support.plesk.com/hc/articles/12378122202391 + function _checkNullClientLogin() + { + $log = Log::getInstance("Checking for accounts with empty user names"); + + $mysql = PleskDb::getInstance(); + $sql = "SELECT domains.id, domains.name, clients.login FROM domains LEFT JOIN clients ON clients.id=domains.cl_id WHERE clients.login is NULL"; + $nullLogins = $mysql->fetchAll($sql); + + if (!empty($nullLogins)) { + $log->warning('There are accounts with empty user names. This problem can cause the backup or migration operation to fail. Please see https://support.plesk.com/hc/articles/12378122202391 for the solution.'); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: #105405 https://support.plesk.com/hc/articles/213362569 + function _checkSwCollectdIntervalSetting() + { + $log = Log::getInstance("Checking the 'Interval' parameter in the sw-collectd configuration file"); + + $collectd_config = '/etc/sw-collectd/collectd.conf'; + if (file_exists($collectd_config)) { + if (!is_file($collectd_config) || !is_readable($collectd_config)) + return; + + $config_content = Util::readfileToArray($collectd_config); + if ($config_content) { + foreach ($config_content as $line) { + if (preg_match('/Interval\s*\d+$/', $line, $match)) { + if (preg_match('/Interval\s*10$/', $line, $match)) { + $log->warning('If you leave the default value of the "Interval" parameter in the ' . $collectd_config . ', sw-collectd may heavily load the system. Please see https://support.plesk.com/hc/articles/213362569 for details.'); + $log->resultWarning(); + return; + } + $log->resultOk(); + return; + } + } + $log->warning('If you leave the default value of the "Interval" parameter in the ' . $collectd_config . ', sw-collectd may heavily load the system. Please see https://support.plesk.com/hc/articles/213362569 for details.'); + $log->resultWarning(); + return; + } + } + } + + private function _checkApacheStatus() + { + $log = Log::getInstance("Checking Apache status"); + + $apacheCtl = file_exists('/usr/sbin/apache2ctl') ? '/usr/sbin/apache2ctl' : '/usr/sbin/apachectl'; + + if (!is_executable($apacheCtl)) { + return; + } + + $resultCode = 0; + Util::Exec("$apacheCtl -t 2>/dev/null", $resultCode); + + if (0 !== $resultCode) { + $log->error("The Apache configuration is broken. Run '$apacheCtl -t' to see the detailed info."); + $log->resultError(); + return; + } + + $log->resultOk(); + } + + //:INFO: #72751 https://support.plesk.com/hc/articles/12377666752279 + function _checkIpcollectionReference() + { + $log = Log::getInstance("Checking consistency of the IP addresses list in the Panel database"); + + $mysql = PleskDb::getInstance(); + $sql = "SELECT 1 FROM ip_pool, clients, IpAddressesCollections, domains, DomainServices, IP_Addresses WHERE DomainServices.ipCollectionId = IpAddressesCollections.ipCollectionId AND domains.id=DomainServices.dom_id AND clients.id=domains.cl_id AND ipAddressId NOT IN (select id from IP_Addresses) AND IP_Addresses.id = ip_pool.ip_address_id AND pool_id = ip_pool.id GROUP BY pool_id"; + $brokenIps = $mysql->fetchAll($sql); + $sql = "select 1 from DomainServices, domains, clients, ip_pool where ipCollectionId not in (select IpAddressesCollections.ipCollectionId from IpAddressesCollections) and domains.id=DomainServices.dom_id and clients.id = domains.cl_id and ip_pool.id = clients.pool_id and DomainServices.type='web' group by ipCollectionId"; + $brokenCollections = $mysql->fetchAll($sql); + + if (!empty($brokenIps) || !empty($brokenCollections)) { + $log->warning('Some database entries related to Panel IP addresses are corrupted. Please see https://support.plesk.com/hc/articles/12377666752279 for the solution.'); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: Broken contexts of the APS applications can lead to errors at building Apache web server configuration https://support.plesk.com/hc/articles/12377671820311 + function _checkApsApplicationContext() + { + $log = Log::getInstance("Checking installed APS applications"); + $mysql = PleskDb::getInstance(); + $sql = "SELECT * FROM apsContexts WHERE (pleskType = 'hosting' OR pleskType = 'subdomain') AND subscriptionId = 0"; + $brokenContexts = $mysql->fetchAll($sql); + + if (!empty($brokenContexts)) { + $log->warning('Some database entries related to the installed APS applications are corrupted. Please see https://support.plesk.com/hc/articles/12377671820311 for the solution.'); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: #94489 FTP service proftpd cannot be started by xinetd if IPv6 is disabled https://support.plesk.com/hc/articles/12377796102807 + function _checkProftpdIPv6() + { + $log = Log::getInstance("Checking proftpd settings"); + + $inet6 = '/proc/net/if_inet6'; + if (!file_exists($inet6) || !@file_get_contents($inet6)) { + $proftpd_config = '/etc/xinetd.d/ftp_psa'; + if (!is_file($proftpd_config) || !is_readable($proftpd_config)) + return null; + + $config_content = Util::readfileToArray($proftpd_config); + if ($config_content) { + for ($i=0; $i<=count($config_content)-1; $i++) { + if (preg_match('/flags.+IPv6$/', $config_content[$i], $match)) { + $log->warning('The proftpd FTP service will fail to start in case the support for IPv6 is disabled on the server. Please check https://support.plesk.com/hc/articles/12377796102807 for details.'); + $log->resultWarning(); + return; + } + } + } + } + $log->resultOk(); + } + + //:INFO: Check the availability of Plesk Panel TCP ports + function _checkPleskTCPPorts() + { + $log = Log::getInstance('Checking the availability of Plesk Panel TCP ports'); + + $plesk_ports = array('8880' => 'Plesk Panel non-secure HTTP port', '8443' => 'Plesk Panel secure HTTPS port'); + + $mysql = PleskDb::getInstance(); + $sql = "select ip_address from IP_Addresses"; + $ip_addresses = $mysql->fetchAll($sql); + $warning = false; + if (count($ip_addresses)>0) { + if (Util::isLinux()) { + $ipv4 = Util::getIPv4ListOnLinux(); + $ipv6 = Util::getIPv6ListOnLinux(); + if ($ipv6) { + $ipsInSystem = array_merge($ipv4, $ipv6); + } else { + $ipsInSystem = $ipv4; + } + } else { + $ipsInSystem = Util::getIPListOnWindows(); + } + foreach ($ip_addresses as $ip) { + foreach ($plesk_ports as $port => $description) { + if (PleskValidator::validateIPv4($ip['ip_address']) && in_array($ip['ip_address'], $ipsInSystem)) { + $fp = @fsockopen($ip['ip_address'], $port, $errno, $errstr, 1); + } elseif (PleskValidator::validateIPv6($ip['ip_address']) && in_array($ip['ip_address'], $ipsInSystem)) { + $fp = @fsockopen('[' . $ip['ip_address'] . ']', $port, $errno, $errstr, 1); + } else { + $log->warning('IP address registered in Plesk is invalid or broken: ' . $ip['ip_address']); + $log->resultWarning(); + return; + } + if (!$fp) { + // $errno 110 means "timed out", 111 means "refused" + $log->info('Unable to connect to IP address ' . $ip['ip_address'] . ' on ' . $description . ' ' . $port . ': ' . $errstr); + $warning = true; + } + } + } + } + if ($warning) { + $log->warning('Unable to connect to some Plesk ports. Please see ' . LOG_PATH . ' for details. Find the full list of the required open ports at https://support.plesk.com/hc/articles/12377821243159 '); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: Plesk user "root" for MySQL database servers have not access to phpMyAdmin https://support.plesk.com/hc/articles/12378148229399 + function _checkMySQLDatabaseUserRoot() + { + $log = Log::getInstance('Checking existence of Plesk user "root" for MariaDB/MySQL database servers'); + + $psaroot = Util::getSettingFromPsaConf('PRODUCT_ROOT_D'); + + if (PleskVersion::is_below_17_9()) { + $phpMyAdminConfFile = $psaroot . '/admin/htdocs/domains/databases/phpMyAdmin/libraries/config.default.php'; + } else { + $phpMyAdminConfFile = $psaroot . '/phpMyAdmin/libraries/config.default.php'; + } + + if (file_exists($phpMyAdminConfFile)) { + $phpMyAdminConfFileContent = file_get_contents($phpMyAdminConfFile); + if (!preg_match("/\[\'AllowRoot\'\]\s*=\s*true\s*\;/", $phpMyAdminConfFileContent)) { + $mysql = PleskDb::getInstance(); + $sql = "select login, data_bases.name as db_name, displayName as domain_name from db_users, data_bases, domains where db_users.db_id = data_bases.id and data_bases.dom_id = domains.id and data_bases.type = 'mysql' and login = 'root'"; + $dbusers = $mysql->fetchAll($sql); + + foreach ($dbusers as $user) { + $log->warning('The database user "' . $user['login'] . '" (database "' . $user['db_name'] . '" at "' . $user['domain_name'] . '") has no access to phpMyAdmin. Please check https://support.plesk.com/hc/articles/12378148229399 for more details.'); + $log->resultWarning(); + return; + } + } + } + + $log->resultOk(); + } + + //:INFO: After upgrade Plesk change permissions on folder of Collaboration Data Objects (CDO) for NTS (CDONTS) to default, https://support.plesk.com/hc/articles/12377887661335 + function _checkCDONTSmailrootFolder() + { + $log = Log::getInstance('Checking for CDONTS mailroot folder'); + + $mailroot = Util::getSystemDisk() . 'inetpub\mailroot\pickup'; + + if (is_dir($mailroot)) { + $log->warning('After upgrade you have to add write permissions to psacln group on folder ' . $mailroot . '. Please, check https://support.plesk.com/hc/articles/12377887661335 for more details.'); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: Check iisfcgi.dll file version https://support.plesk.com/hc/articles/12378148258199 + function _checkIisFcgiDllVersion() + { + $log = Log::getInstance("Checking the iisfcgi.dll file version"); + + $windir = Util::getSystemRoot(); + $iisfcgi = $windir . '\system32\inetsrv\iisfcgi.dll'; + if (file_exists($iisfcgi)) { + $version = Util::getFileVersion($iisfcgi); + if (version_compare($version, '7.5.0', '>') + && version_compare($version, '7.5.7600.16632', '<')) { + $log->warning('File iisfcgi.dll version ' . $version . ' is outdated. Please, check article https://support.plesk.com/hc/articles/12378148258199 for details'); + return; + } + } + $log->resultOk(); + } + + //:INFO: Checking for main IP address https://support.plesk.com/hc/articles/12377857361687 + function _checkMainIP() + { + $log = Log::getInstance("Checking for main IP address"); + + $mysql = PleskDb::getInstance(); + $sql = 'select * from IP_Addresses'; + $ips = $mysql->fetchAll($sql); + $mainexists = false; + foreach ($ips as $ip) { + if (isset($ip['main'])) { + if ($ip['main'] == 'true') { + $mainexists = true; + } + } else { + $log->info('No field "main" in table IP_Addresses.'); + $log->resultOk(); + return; + } + } + + if (!$mainexists) { + $warn = 'Unable to find "main" IP address in psa database. Please, check https://support.plesk.com/hc/articles/12377857361687 for more details.'; + $log->warning($warn); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: Checking existing table mysql.servers https://support.plesk.com/hc/articles/12377850098455 + function _checkMysqlServersTable() + { + $log = Log::getInstance('Checking table "servers" in database "mysql"'); + + $mySQLServerVersion = Util::getMySQLServerVersion(); + if (version_compare($mySQLServerVersion, '5.1.0', '>=')) { + $credentials = Util::getDefaultClientMySQLServerCredentials(); + + if (preg_match('/AES-128-CBC/', $credentials['admin_password'])) { + $log->info('The administrator\'s password for the default MariaDB/MySQL server is encrypted.'); + return; + } + + $mysql = new DbClientMysql($credentials['host'], $credentials['admin_login'], $credentials['admin_password'] , 'information_schema', $credentials['port']); + if (!$mysql->hasErrors()) { + $sql = 'SELECT * FROM information_schema.TABLES WHERE TABLE_SCHEMA="mysql" and TABLE_NAME="servers"'; + $servers = $mysql->fetchAll($sql); + if (empty($servers)) { + $warn = 'The table "servers" in the database "mysql" does not exist. Please check https://support.plesk.com/hc/articles/12377850098455 for details.'; + $log->warning($warn); + $log->resultWarning(); + return; + } + } + } + $log->resultOk(); + } + + //:INFO: Check that there is symbolic link /usr/local/psa on /opt/psa on Debian-like Oses https://support.plesk.com/hc/articles/12377511731991 + function _checkSymLinkToOptPsa() + { + $log = Log::getInstance('Checking symbolic link /usr/local/psa on /opt/psa'); + + $link = @realpath('/usr/local/psa/version'); + if (!preg_match('/\/opt\/psa\/version/', $link, $macthes)) { + $warn = "The symbolic link /usr/local/psa does not exist or has wrong destination. Read article https://support.plesk.com/hc/articles/12377511731991 to fix the issue."; + $log->warning($warn); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: Checking for unknown ISAPI filters and show warning https://support.plesk.com/hc/articles/213913765 + function _unknownISAPIfilters() + { + $log = Log::getInstance('Detecting installed ISAPI filters'); + + if (Util::isUnknownISAPIfilters()) { + $warn = 'Please read carefully article https://support.plesk.com/hc/articles/213913765, for avoiding possible problems caused by unknown ISAPI filters.'; + $log->warning($warn); + $log->resultWarning(); + + return; + } + $log->resultOk(); + } + + //:INFO: Warning about possible issues related to Microsoft Visual C++ Redistributable Packages ?https://support.plesk.com/hc/articles/115000201014 + function _checkMSVCR() + { + $log = Log::getInstance('Microsoft Visual C++ Redistributable Packages'); + + $warn = 'Please read carefully article https://support.plesk.com/hc/articles/115000201014, for avoiding possible problems caused by Microsoft Visual C++ Redistributable Packages.'; + $log->info($warn); + + return; + } + + function _checkForCryptPasswords() + { + //:INFO: Prevent potential problem with E: Couldn't configure pre-depend plesk-core for psa-firewall, probably a dependency cycle. + $log = Log::getInstance('Detecting if encrypted passwords are used'); + + $db = PleskDb::getInstance(); + $sql = "SELECT COUNT(*) AS cnt FROM accounts WHERE type='crypt' AND password not like '$%';"; + $r = $db->fetchAll($sql); + + if ($r[0]['cnt'] != '0') + { + $warn = 'There are ' . $r[0]['cnt'] . ' accounts with passwords encrypted using a deprecated algorithm. Please refer to https://support.plesk.com/hc/articles/12377596588311 for the instructions about how to change the password type to plain.'; + + $log->warning($warn); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + function _checkApsTablesInnoDB() + { + $log = Log::getInstance('Checking if apsc database tables have InnoDB engine'); + + $db = PleskDb::getInstance(); + $apsDatabase = $db->fetchOne("select val from misc where param = 'aps_database'"); + $sql = "SELECT TABLE_NAME FROM information_schema.TABLES where TABLE_SCHEMA = '$apsDatabase' and ENGINE = 'MyISAM'"; + $myISAMTables = $db->fetchAll($sql); + if (!empty($myISAMTables)) { + $myISAMTablesList = implode(', ', array_map('reset', $myISAMTables)); + $warn = 'The are tables in apsc database with MyISAM engine: ' . $myISAMTablesList . '. It would be updated to InnoDB engine.'; + $log->warning($warn); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + function _checkMixedCaseDomainIssues() + { + $log = Log::getInstance("Checking for domains with mixed case names", true); + $db = PleskDb::getInstance(); + + + $domains = $db->fetchAll("select id, name, displayName from domains"); + $problemDomains = array(); + foreach ($domains as $domain) { + if (strtolower($domain['name']) == $domain['name']) { + continue; + } + $problemDomains[] = $domain; + } + if (count($problemDomains)) { + $msg = "Found one or more domains with mixed case names. Such domains may have trouble working with the \"FPM application server by Apache\" handler.\n" . + implode("\n", array_map(function($row) { + return "{$row['id']}\t{$row['displayName']}\t{$row['name']}"; + }, $problemDomains)) . "\n" . + "A manual fix can be applied to resolve the issue. Read https://support.plesk.com/hc/en-us/articles/12377171904151 for details."; + $log->warning($msg); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + private function checkDomainControllerLocation() + { + $log = Log::getInstance("Checking for Active Directory Domain Controller and Plesk on the same server", true); + $cmd = '"' . rtrim(Util::getPleskRootPath(), '\\') . '\admin\bin\serverconf.exe" --list'; + $output = Util::exec($cmd, $code); + if (preg_match("/IS_DOMAIN_CONTROLLER:\s*true/", $output)) { + $log->warning('Active Directory Domain Controller and Plesk are on the same server. Read https://support.plesk.com/hc/articles/12377107094167 for details.'); + $log->resultWarning(); + } else { + $log->resultOk(); + } + } +} + +class Plesk175Requirements +{ + public function validate() + { + if (PleskInstallation::isInstalled() && PleskVersion::is_below_17_5() && Util::isLinux()) { + //:INFO: Check that DUMP_TMP_D is not inside of (or equal to) DUMP_D + $this->_checkDumpTmpD(); + } + } + + public function _checkDumpTmpD() + { + $log = Log::getInstance('Checking the DUMP_TMP_D directory'); + + $dumpD = Util::getSettingFromPsaConf('DUMP_D'); + if (is_null($dumpD)) { + $log->warning('Unable to obtain the path to the directory defined by the DUMP_D parameter. Check that the DUMP_D parameter is set in the /etc/psa/psa.conf file.'); + $log->resultWarning(); + return; + } + $dumpTmpD = Util::getSettingFromPsaConf('DUMP_TMP_D'); + if (is_null($dumpTmpD)) { + $log->warning('Unable to obtain the path to the directory defined by the DUMP_TMP_D parameter. Check that the DUMP_TMP_D parameter is set in the /etc/psa/psa.conf file.'); + $log->resultWarning(); + return; + } + + if (strpos(rtrim($dumpTmpD, '/') . '/', rtrim($dumpD, '/') . '/') === 0) { + $log->error(sprintf('The directory DUMP_TMP_D = %s should not be inside of (or equal to) the directory DUMP_D = %s. Fix these parameters in the /etc/psa/psa.conf file.', $dumpTmpD, $dumpD)); + $log->resultError(); + } + + $log->resultOk(); + } +} + +class Plesk178Requirements +{ + public function validate() + { + if (PleskInstallation::isInstalled() && Util::isWindows() && PleskVersion::is_below_17_9()) { + $this->_checkPleskVhostsDir(); + } + + if (PleskVersion::is_below_17_8()) { + $this->checkTomcat(); + $this->checkMultiServer(); + } + } + + private function checkTomcat() + { + if (Util::isWindows()) { + $tomcatRegBase = '\\PLESK\\PSA Config\\Config\\Packages\\tomcat\\tomcat'; + /* Supported versions on windows are tomcat5 and tomcat7 */ + $key = '/v InstallDir'; + $isInstalled = Util::regQuery($tomcatRegBase . '7', $key, true) || Util::regQuery($tomcatRegBase . '5', $key, true); + } else { + $isInstalled = PackageManager::isInstalled('psa-tomcat-configurator'); + } + + if ($isInstalled + || (PleskDb::getInstance()->fetchOne('show tables like \'WebApps\'') + && PleskDb::getInstance()->fetchOne('select count(*) from WebApps')) + ) { + $log = Log::getInstance('Checking Apache Tomcat installation'); + $message = <<warning($message); + } + } + + private function checkMultiServer() + { + if (!PleskModule::isMultiServer()) { + return; + } + + $log = Log::getInstance('Checking Plesk Multi Server installation'); + $message = <<emergency($message); + $log->resultError(); + } + + private function _checkPleskVhostsDir() + { + $log = Log::getInstance('Checking mount volume for HTTPD_VHOSTS_D directory'); + + $vhostsDir = rtrim(Util::regPleskQuery('HTTPD_VHOSTS_D'), "\\"); + Util::exec("mountvol \"{$vhostsDir}\" /L", $code); + if ($code == 0) { + $msg = "A disk volume is mounted to the {$vhostsDir} directory." . + " It will be unmounted during the Plesk upgrade." . + " As a result, all hosted websites will become unavailable." . + " Make sure to remount the volume to the {$vhostsDir} directory after the upgrade."; + $log->emergency($msg); + $log->resultError(); + return; + } + + $log->resultOk(); + } +} + +class Plesk18Requirements +{ + public function validate() + { + if (PleskInstallation::isInstalled()) { + if (Util::isLinux() && PleskOS::isRedHatLike()) { + $this->_checkYumDuplicates(); + } + $this->checkPdUsersLoginCollation(); + $this->checkDomainsGuidCollation(); + $this->checkClientsGuidCollation(); + $this->checkModSecurityModules(); + $this->checkIsFirewallPackageConfigured(); + $this->checkDefaultDnsServerComponent(); + } + } + + private function checkModSecurityModules() + { + /* Issue actual for Plesk for Windows below 18.0.32 (ModSecurity 2.9.3 and below) */ + if (!Util::isWindows() || PleskVersion::is_18_0_32_or_above()) { + return; + } + + $log = Log::getInstance('Checking the status of ModSecurity IIS modules'); + $modules = Util::exec(Util::getSystemRoot() . '\system32\inetsrv\AppCmd.exe list module', $code); + if ($code) { + $log->warning('Unable to get the list of IIS modules.'); + } else { + if (strpos($modules, 'ModSecurity IIS (32bits)') === false && strpos($modules, 'ModSecurity IIS (64bits)') === false) { + $log->error('Either 32-bit or 64-bit ModSecurity IIS module is absent.'); + $log->resultError(); + } + } + } + + // INFO: PPP-46440 checking package duplicates https://support.plesk.com/hc/articles/12377586286615 + private function _checkYumDuplicates() + { + $log = Log::getInstance('Checking for RPM packages duplicates'); + if (!file_exists("/usr/bin/package-cleanup")) + { + $log->info("package-cleanup is not found. Check for duplicates was skipped"); + return; + } + + $output = Util::exec("/usr/bin/package-cleanup --cacheonly -q --dupes", $code); + if ($code != 0) + { + // some repos may have no cache at this point or may be broken at all + // retry with cache recreation and skipping broken repos + $output = Util::exec("/usr/bin/package-cleanup -q --dupes --setopt='*.skip_if_unavailable=1'", $code); + } + if ($code != 0) + { + $message = "Unable to detect package duplicates: /usr/bin/package-cleanup --dupes returns $code." . + "Output is:\n$output"; + $log->warning($message); + $log->resultWarning(); + return; + } + + if (empty($output)) { + return; + } + + $message = "Your package system contains duplicated packages, which can lead to broken Plesk update:\n\n" . + "$output\n\n" . + "Please check https://support.plesk.com/hc/articles/12377586286615 for more details."; + + $log->error($message); + $log->resultError(); + } + + private function checkPdUsersLoginCollation() + { + $log = Log::getInstance('Checking for Protected Directory Users with duplicates in login field.'); + $duplicates = PleskDb::getInstance()->fetchAll( + 'SELECT pd_id, LOWER(login) AS login_ci, COUNT(*) AS duplicates FROM pd_users' . + ' GROUP BY pd_id, login_ci' . + ' HAVING duplicates > 1' + ); + if (!empty($duplicates)) { + $log->error( + "Duplicate logins of Protected Directory Users were found in the database:\n\n" . + implode("\n", array_column($duplicates, 'login_ci')) . "\n\n" . + "Please check https://support.plesk.com/hc/en-us/articles/360014743900 for more details." + ); + $log->resultError(); + } + } + + private function checkDomainsGuidCollation() + { + $log = Log::getInstance('Checking "domains" table with duplicates in guid field.'); + $duplicates = PleskDb::getInstance()->fetchAll( + 'SELECT guid, COUNT(*) AS duplicates FROM domains' + . ' GROUP BY guid' + . ' HAVING duplicates > 1' + ); + + if (!empty($duplicates)) { + $log->error( + "Duplicate guid were found in the 'domains' table:\n\n" . + implode("\n", array_column($duplicates, 'guid')) . "\n\n" + . "Please check https://support.plesk.com/hc/en-us/articles/12377018323351 for more details." + ); + $log->resultError(); + } + } + + private function checkClientsGuidCollation() + { + $log = Log::getInstance('Checking "clients" table with duplicates in guid field.'); + $duplicates = PleskDb::getInstance()->fetchAll( + 'SELECT guid, COUNT(*) AS duplicates FROM clients' + . ' GROUP BY guid' + . ' HAVING duplicates > 1' + ); + + if (!empty($duplicates)) { + $log->error( + "Duplicate guid were found in the 'clients' table:\n\n" . + implode("\n", array_column($duplicates, 'guid')) . "\n\n" + . "Please check https://support.plesk.com/hc/en-us/articles/360016801679 for more details." + ); + $log->resultError(); + } + } + + private function checkIsFirewallPackageConfigured() + { + if (!Util::isLinux()) { + return; + } + + $log = Log::getInstance("Checking if any rules are configured in the Firewall extension"); + $db = PleskDb::getInstance(); + if ($db->fetchOne("SHOW TABLES LIKE 'module_firewall_rules'") + && $db->fetchOne("SELECT COUNT(*) FROM module_firewall_rules") + ) { + $message = "Plesk Firewall no longer stores its configuration in Plesk database since " + . "Plesk Obsidian 18.0.52. Since you're upgrading to the latest version late, " + . "if you wish to retain the Plesk Firewall extension and its configuration, " + . "you need to follow additional steps after the upgrade. Please check " + . "https://support.plesk.com/hc/en-us/articles/16198248236311 for more details."; + $log->warning($message); + } + } + + private function checkDefaultDnsServerComponent() + { + if (Util::isLinux()) { + return; + } + + $path = '\\PLESK\\PSA Config\\Config\\Packages\\dnsserver'; + $key = '/ve'; + + if ('bind' === Util::regQuery($path, $key, true)) { + $log = Log::getInstance("Checking default DNS server component"); + $message = <<emergency($message); + $log->resultError(); + } + } +} + +class PleskModule +{ + public static function isInstalledWatchdog() + { + return PleskModule::_isInstalled('watchdog'); + } + + public static function isInstalledFileServer() + { + return PleskModule::_isInstalled('fileserver'); + } + + public static function isInstalledFirewall() + { + return PleskModule::_isInstalled('firewall'); + } + + public static function isInstalledVpn() + { + return PleskModule::_isInstalled('vpn'); + } + + public static function isMultiServer() + { + return PleskModule::_isInstalled('plesk-multi-server') || + PleskModule::_isInstalled('plesk-multi-server-node'); + } + + protected static function _isInstalled($module) + { + $sql = "SELECT * FROM Modules WHERE name = '{$module}'"; + + $pleskDb = PleskDb::getInstance(); + $row = $pleskDb->fetchRow($sql); + + return (empty($row) ? false : true); + } +} + +class PleskInstallation +{ + public static function validate() + { + if (!self::isInstalled()) { + $log = Log::getInstance('Checking for Plesk installation'); + $log->step('Plesk installation is not found. You will have no problems with upgrade, go on and install ' + . PleskVersion::getLatestPleskVersionAsString() . ' (https://www.plesk.com/)'); + return; + } + self::detectVersion(); + } + + public static function isInstalled() + { + $rootPath = Util::getPleskRootPath(); + if (empty($rootPath) || !file_exists($rootPath)) { + return false; + } + return true; + } + + private static function detectVersion() + { + $log = Log::getInstance('Installed Plesk version/build: ' . PleskVersion::getVersionAndBuild(), false); + + $currentVersion = PleskVersion::getVersion(); + if (version_compare($currentVersion, PLESK_VERSION, 'eq')) { + $err = 'You have already installed the latest version ' . PleskVersion::getLatestPleskVersionAsString() . '. '; + $err .= 'Tool must be launched prior to upgrade to ' . PleskVersion::getLatestPleskVersionAsString() . ' for the purpose of getting a report on potential problems with the upgrade.'; + $log->info($err); + exit(0); + } + + if (!PleskVersion::isUpgradeSupportedVersion()) { + $err = 'Unable to find Plesk 17.x. '; + $err .= 'Tool must be launched prior to upgrade to ' . PleskVersion::getLatestPleskVersionAsString() . ' for the purpose of getting a report on potential problems with the upgrade.'; + fatal($err); + } + } +} + +class PleskVersion +{ + const PLESK_17_MIN_VERSION = '13.0.0'; /* historically it has been started as 13.0 */ + + const PLESK_17_MAX_VERSION = '17.9.13'; + + const PLESK_18_MIN_VERSION = '18.0.14'; + + public static function is17x_or_above() + { + return version_compare(self::getVersion(), self::PLESK_17_MIN_VERSION, '>='); + } + + public static function is_below_17_5() + { + return version_compare(self::getVersion(), '17.5.0', '<'); + } + + public static function is_below_17_8() + { + return version_compare(self::getVersion(), '17.8.0', '<'); + } + + public static function is_below_17_9() + { + return version_compare(self::getVersion(), '17.9.0', '<'); + } + + public static function is_18_0_32_or_above() + { + return version_compare(self::getVersion(), '18.0.32', '>='); + } + + public static function getVersion() + { + $version = self::getVersionAndBuild(); + if (!preg_match('/([0-9]+[.][0-9]+[.][0-9]+)/', $version, $matches)) { + fatal("Incorrect Plesk version format. Current version: {$version}"); + } + return $matches[1]; + } + + public static function getVersionAndBuild() + { + $versionPath = Util::getPleskRootPath().'/version'; + if (!file_exists($versionPath)) { + fatal("Plesk version file is not exists $versionPath"); + } + $version = file_get_contents($versionPath); + $version = trim($version); + return $version; + } + + public static function getLatestPleskVersionAsString() + { + return 'Plesk ' . PLESK_VERSION; + } + + public static function isUpgradeSupportedVersion() + { + return self::is17x_or_above(); + } +} + +class Log +{ + private $errors; + private $warnings; + private $emergency; + private $logfile; + private $step; + private $step_header; + + /** @var array */ + private $errorsContent = []; + + /** @var array */ + private $warningsContent = []; + + public static function getInstance($step_msg = '', $step_number = true) + { + static $_instance = null; + if (is_null($_instance)) { + $_instance = new Log(); + } + if ($step_msg) { + $_instance->step($step_msg, $step_number); + } + + return $_instance; + } + + private function __construct() + { + $this->log_init(); + @unlink($this->logfile); + } + + private function log_init() + { + $this->step = 0; + $this->errors = 0; + $this->warnings = 0; + $this->emergency = 0; + $this->logfile = LOG_PATH; + $this->step_header = "Unknown step is running"; + } + + public function getErrors() + { + return $this->errors; + } + + public function getWarnings() + { + return $this->warnings; + } + + public function getEmergency() + { + return $this->emergency; + } + + public function fatal($msg) + { + $this->errors++; + + $this->errorsContent[] = $msg; + $content = $this->get_log_string($msg, 'FATAL_ERROR'); + fwrite(STDERR, $content); + $this->write($content); + } + + public function error($msg) + { + $this->errors++; + + $this->errorsContent[] = $msg; + $content = $this->get_log_string($msg, 'ERROR'); + fwrite(STDERR, $content); + $this->write($content); + } + + public function warning($msg) + { + $this->warnings++; + + $this->warningsContent[] = $msg; + $content = $this->get_log_string($msg, 'WARNING'); + fwrite(STDERR, $content); + $this->write($content); + } + + public function emergency($msg) + { + $this->emergency++; + + $this->errorsContent[] = $msg; + $content = $this->get_log_string($msg, 'EMERGENCY'); + fwrite(STDERR, $content); + $this->write($content); + } + + public function step($msg, $useNumber=false) + { + $this->step_header = $msg; + + echo PHP_EOL; + $this->write(PHP_EOL); + + if ($useNumber) { + $msg = "STEP " . $this->step . ": {$msg}..."; + $this->step++; + } else { + $msg = "{$msg}..."; + } + + $this->info($msg); + } + + public function resultOk() + { + $this->info('Result: OK'); + } + + public function resultWarning() + { + $this->info('Result: WARNING'); + } + + public function resultError() + { + $this->info('Result: ERROR'); + } + + public function info($msg) + { + $content = $this->get_log_string($msg, 'INFO'); + echo $content; + $this->write($content); + } + + public function debug($msg) + { + $this->write($this->get_log_string($msg, 'DEBUG')); + } + + public function dumpStatistics() + { + $errors = $this->errors + $this->emergency; + $str = "Errors found: $errors; Warnings found: {$this->warnings}"; + echo PHP_EOL . $str . PHP_EOL . PHP_EOL; + } + + private function get_log_string($msg, $type) + { + if (getenv('VZ_UPGRADE_SCRIPT')) { + switch ($type) { + case 'FATAL_ERROR': + case 'ERROR': + case 'WARNING': + case 'EMERGENCY': + $content = "[{$type}]: {$this->step_header} DESC: {$msg}" . PHP_EOL; + break; + default: + $content = "[{$type}]: {$msg}" . PHP_EOL; + } + } else if (getenv('AUTOINSTALLER_VERSION')) { + $content = "{$type}: {$msg}" . PHP_EOL; + } else { + $date = date('Y-m-d h:i:s'); + $content = "[{$date}][{$type}] {$msg}" . PHP_EOL; + } + + return $content; + } + + public function write($content, $file = null, $mode='a+') + { + $logfile = $file ? $file : $this->logfile; + $fp = fopen($logfile, $mode); + fwrite($fp, $content); + fclose($fp); + } + + private function getJsonFileName() + { + return (Util::isWindows() ? + rtrim(Util::regPleskQuery('PRODUCT_DATA_D'), "\\") : + Util::getSettingFromPsaConf('PRODUCT_ROOT_D') + ) . '/var/' . LOG_JSON; + } + + public function writeJsonFile() + { + $data = [ + 'version' => PRE_UPGRADE_SCRIPT_VERSION, + 'errorsFound' => $this->errors + $this->emergency, + 'errors' => $this->errorsContent, + 'warningsFound' => $this->warnings, + 'warnings' => $this->warningsContent, + ]; + file_put_contents($this->getJsonFileName(), json_encode($data)); + } +} + +class PleskDb +{ + var $_db = null; + + public function __construct($dbParams) + { + switch($dbParams['db_type']) { + case 'mysql': + $this->_db = new DbMysql( + $dbParams['host'], $dbParams['login'], $dbParams['passwd'], $dbParams['db'], $dbParams['port'] + ); + break; + + case 'jet': + $this->_db = new DbJet($dbParams['db']); + break; + + case 'mssql': + $this->_db = new DbMsSql( + $dbParams['host'], $dbParams['login'], $dbParams['passwd'], $dbParams['db'], $dbParams['port'] + ); + break; + + default: + fatal("{$dbParams['db_type']} is not implemented yet"); + break; + } + } + + public static function getInstance() + { + global $options; + static $_instance = array(); + + $dbParams['db_type']= Util::getPleskDbType(); + $dbParams['db'] = Util::getPleskDbName(); + $dbParams['port'] = Util::getPleskDbPort(); + $dbParams['login'] = Util::getPleskDbLogin(); + $dbParams['passwd'] = Util::getPleskDbPassword($options->getDbPasswd()); + $dbParams['host'] = Util::getPleskDbHost(); + + $dbId = md5(implode("\n", $dbParams)); + + $_instance[$dbId] = new PleskDb($dbParams); + + return $_instance[$dbId]; + } + + function fetchOne($sql) + { + if (DEBUG) { + $log = Log::getInstance(); + $log->info($sql); + } + return $this->_db->fetchOne($sql); + } + + function fetchRow($sql) + { + $res = $this->fetchAll($sql); + if (is_array($res) && isset($res[0])) { + return $res[0]; + } + return array(); + } + + function fetchAll($sql) + { + if (DEBUG) { + $log = Log::getInstance(); + $log->info($sql); + } + return $this->_db->fetchAll($sql); + } +} + +class DbMysql +{ + var $_dbHandler; + + public function __construct($host, $user, $passwd, $database, $port) + { + if ( extension_loaded('mysql') ) { + $this->_dbHandler = @mysql_connect("{$host}:{$port}", $user, $passwd); + if (!is_resource($this->_dbHandler)) { + $mysqlError = mysql_error(); + if (stristr($mysqlError, 'access denied for user')) { + $errMsg = 'Given is incorrect. ' . $mysqlError; + } else { + $errMsg = 'Unable to connect database. The reason of problem: ' . $mysqlError . PHP_EOL; + } + $this->_logError($errMsg); + } + @mysql_select_db($database, $this->_dbHandler); + } else if ( extension_loaded('mysqli') ) { + + // forbid using MYSQLI_REPORT_STRICT to handle mysqli errors via error codes + mysqli_report(MYSQLI_REPORT_ERROR); + + $this->_dbHandler = @mysqli_connect($host, $user, $passwd, $database, $port); + if (!$this->_dbHandler) { + $mysqlError = mysqli_connect_error(); + if (stristr($mysqlError, 'access denied for user')) { + $errMsg = 'Given is incorrect. ' . $mysqlError; + } else { + $errMsg = 'Unable to connect database. The reason of problem: ' . $mysqlError . PHP_EOL; + } + $this->_logError($errMsg); + } + } else { + fatal("No MariaDB/MySQL extension is available"); + } + } + + function fetchAll($sql) + { + if ( extension_loaded('mysql') ) { + $res = mysql_query($sql, $this->_dbHandler); + if (!is_resource($res)) { + $this->_logError('Unable to execute query. Error: ' . mysql_error($this->_dbHandler)); + } + $rowset = array(); + while ($row = mysql_fetch_assoc($res)) { + $rowset[] = $row; + } + return $rowset; + } else if ( extension_loaded('mysqli') ) { + $res = $this->_dbHandler->query($sql); + if ($res === false) { + $this->_logError('Unable to execute query. Error: ' . mysqli_error($this->_dbHandler)); + } + $rowset = array(); + while ($row = mysqli_fetch_assoc($res)) { + $rowset[] = $row; + } + return $rowset; + } else { + fatal("No MariaDB/MySQL extension is available"); + } + } + + function fetchOne($sql) + { + if ( extension_loaded('mysql') ) { + $res = mysql_query($sql, $this->_dbHandler); + if (!is_resource($res)) { + $this->_logError('Unable to execute query. Error: ' . mysql_error($this->_dbHandler)); + } + $row = mysql_fetch_row($res); + return isset($row[0]) ? $row[0] : null; + } else if ( extension_loaded('mysqli') ) { + $res = $this->_dbHandler->query($sql); + if ($res === false) { + $this->_logError('Unable to execute query. Error: ' . mysqli_error($this->_dbHandler)); + } + $row = mysqli_fetch_row($res); + return isset($row[0]) ? $row[0] : null; + } else { + fatal("No MariaDB/MySQL extension is available"); + } + } + + function query($sql) + { + if ( extension_loaded('mysql') ) { + $res = mysql_query($sql, $this->_dbHandler); + if ($res === false ) { + $this->_logError('Unable to execute query. Error: ' . mysql_error($this->_dbHandler) ); + } + return $res; + } else if ( extension_loaded('mysqli') ) { + $res = $this->_dbHandler->query($sql); + if ($res === false ) { + $this->_logError('Unable to execute query. Error: ' . mysqli_error($this->_dbHandler) ); + } + return $res; + } else { + fatal("No MariaDB/MySQL extension is available"); + } + } + + function _logError($message) + { + fatal("[MYSQL ERROR] $message"); + } +} + +class DbClientMysql extends DbMysql +{ + var $errors = array(); + + function _logError($message) + { + $message = "[MYSQL ERROR] $message"; + $log = Log::getInstance(); + $log->warning($message); + $this->errors[] = $message; + } + + function hasErrors() { + return count($this->errors) > 0; + } +} + +class DbJet +{ + var $_dbHandler = null; + + public function __construct($dbPath) + { + $dsn = "Provider='Microsoft.Jet.OLEDB.4.0';Data Source={$dbPath}"; + $this->_dbHandler = new COM("ADODB.Connection", NULL, CP_UTF8); + if (!$this->_dbHandler) { + $this->_logError('Unable to init ADODB.Connection'); + } + + $this->_dbHandler->open($dsn); + } + + function fetchAll($sql) + { + $result_id = $this->_dbHandler->execute($sql); + if (!$result_id) { + $this->_logError('Unable to execute sql query ' . $sql); + } + if ($result_id->BOF && !$result_id->EOF) { + $result_id->MoveFirst(); + } + if ($result_id->EOF) { + return array(); + } + + $rowset = array(); + while(!$result_id->EOF) { + $row = array(); + for ($i=0;$i<$result_id->Fields->count;$i++) { + $field = $result_id->Fields($i); + $row[$field->Name] = (string)$field->value; + } + $result_id->MoveNext(); + $rowset[] = $row; + } + return $rowset; + } + + function fetchOne($sql) + { + $result_id = $this->_dbHandler->execute($sql); + if (!$result_id) { + $this->_logError('Unable to execute sql query ' . $sql); + } + if ($result_id->BOF && !$result_id->EOF) { + $result_id->MoveFirst(); + } + if ($result_id->EOF) { + return null; + } + $field = $result_id->Fields(0); + $result = $field->value; + + return (string)$result; + } + + function _logError($message) + { + fatal("[JET ERROR] $message"); + } +} + +class DbMsSql extends DbJet +{ + public function __construct($host, $user, $passwd, $database, $port) + { + $dsn = "Provider=SQLOLEDB.1;Initial Catalog={$database};Data Source={$host}"; + $this->_dbHandler = new COM("ADODB.Connection", NULL, CP_UTF8); + if (!$this->_dbHandler) { + $this->_logError('Unable to init ADODB.Connection'); + } + $this->_dbHandler->open($dsn, $user, $passwd); + } + + function _logError($message) + { + fatal("[MSSQL ERROR] $message"); + } +} + +class Util +{ + const DSN_INI_PATH_UNIX = '/etc/psa/private/dsn.ini'; + + /** @var array */ + private static $_dsnIni; + + public static function isWindows() + { + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + return true; + } + return false; + } + + public static function isLinux() + { + return !Util::isWindows(); + } + + public static function isVz() + { + $vz = false; + if (Util::isLinux()) { + if (file_exists('/proc/vz/veredir')) { + $vz = true; + } + } else { + $reg = 'REG QUERY "HKLM\SOFTWARE\SWsoft\Virtuozzo" 2>nul'; + Util::exec($reg, $code); + if ($code==0) { + $vz = true; + } + } + return $vz; + } + + public static function getArch() + { + global $arch; + if (!empty($arch)) + return $arch; + + $arch = 'i386'; + if (Util::isLinux()) { + $cmd = 'uname -m'; + $x86_64 = 'x86_64'; + $output = Util::exec($cmd, $code); + if (!empty($output) && stristr($output, $x86_64)) { + $arch = 'x86_64'; + } + } else { + $arch = 'x86_64'; + } + return $arch; + } + + public static function getHostname() + { + if (Util::isLinux()) { + $cmd = 'hostname -f'; + } else { + $cmd = 'hostname'; + } + $hostname = Util::exec($cmd, $code); + + if (empty($hostname)) { + $err = 'Command: ' . $cmd . ' returns: ' . $hostname . "\n"; + $err .= 'Hostname is not defined and configured. Unable to get hostname. Server should have properly configured hostname and it should be resolved locally.'; + fatal($err); + } + + return $hostname; + } + + public static function getIPList($lo=false) + { + if (Util::isLinux()) { + $ipList = Util::getIPv4ListOnLinux(); + foreach ($ipList as $key => $ip) { + if (!$lo && substr($ip, 0, 3) == '127') { + unset($ipList[$key]); + continue; + } + trim($ip); + } + $ipList = array_values($ipList); + } else { + $cmd = 'hostname'; + $hostname = Util::exec($cmd, $code); + $ip = gethostbyname($hostname); + $res = ($ip != $hostname) ? true : false; + if (!$res) { + fatal('Unable to retrieve IP address'); + } + $ipList = array(trim($ip)); + } + return $ipList; + } + + public static function getIPv6ListOnLinux() + { + return Util::grepCommandOutput(array( + array('bin' => 'ip', 'command' => '%PATH% addr list', 'regexp' => '#inet6 ([^ /]+)#'), + array('bin' => 'ifconfig', 'command' => '%PATH% -a', 'regexp' => '#inet6 (?:addr: ?)?([A-F0-9:]+)#i'), + )); + } + + public static function getIPv4ListOnLinux() + { + $commands = array( + array('bin' => 'ip', 'command' => '%PATH% addr list', 'regexp' => '#inet ([^ /]+)#'), + array('bin' => 'ifconfig', 'command' => '%PATH% -a', 'regexp' => '#inet (?:addr: ?)?([\d\.]+)#'), + ); + if (!($list = Util::grepCommandOutput($commands))) { + fatal('Unable to get IP address'); + } + return $list; + } + + public static function grepCommandOutput($cmds) + { + foreach ($cmds as $cmd) { + if ($fullPath = Util::lookupCommand($cmd['bin'])) { + $output = Util::exec(str_replace("%PATH%", $fullPath, $cmd['command']), $code); + if (preg_match_all($cmd['regexp'], $output, $matches)) { + return $matches[1]; + } + } + } + return false; + } + + public static function getIPListOnWindows() + { + $cmd = 'wmic.exe path win32_NetworkAdapterConfiguration get IPaddress'; + $output = Util::exec($cmd, $code); + if (!preg_match_all('/"(.*?)"/', $output, $matches)) { + fatal('Unable to get IP address'); + } + return $matches[1]; + } + + public static function getPleskRootPath() + { + global $_pleskRootPath; + if (empty($_pleskRootPath)) { + if (Util::isLinux()) { + if (PleskOS::isDebLike()) { + $_pleskRootPath = '/opt/psa'; + } else { + $_pleskRootPath = '/usr/local/psa'; + } + } + if (Util::isWindows()) { + $_pleskRootPath = Util::regPleskQuery('PRODUCT_ROOT_D', true); + } + } + return $_pleskRootPath; + } + + public static function getPleskDbName() + { + $dbName = 'psa'; + if (Util::isWindows()) { + $dbName = Util::regPleskQuery('mySQLDBName'); + } else { + $dsnDbname = Util::_getDsnConfigValue('dbname'); + if ($dsnDbname) { + $dbName = $dsnDbname; + } + } + return $dbName; + } + + public static function getPleskDbLogin() + { + $dbLogin = 'admin'; + if (Util::isWindows()) { + $dbLogin = Util::regPleskQuery('PLESK_DATABASE_LOGIN'); + } else { + $dsnLogin = Util::_getDsnConfigValue('username'); + if ($dsnLogin) { + $dbLogin = $dsnLogin; + } + } + return $dbLogin; + } + + public static function getPleskDbPassword($dbPassword) + { + if (Util::isLinux()) { + $dsnPassword = Util::_getDsnConfigValue('password'); + if ($dsnPassword) { + $dbPassword = $dsnPassword; + } + } + return $dbPassword; + } + + public static function getPleskDbType() + { + $dbType = 'mysql'; + if (Util::isWindows()) { + $dbType = strtolower(Util::regPleskQuery('PLESK_DATABASE_PROVIDER_NAME')); + } + return $dbType; + } + + public static function getPleskDbHost() + { + $dbHost = 'localhost'; + if (Util::isWindows()) { + $dbProvider = strtolower(Util::regPleskQuery('PLESK_DATABASE_PROVIDER_NAME')); + if ($dbProvider == 'mysql' || $dbProvider == 'mssql') { + $dbHost = Util::regPleskQuery('MySQL_DB_HOST'); + } + } else { + $dsnHost = Util::_getDsnConfigValue('host'); + if ($dsnHost) { + $dbHost = $dsnHost; + } + } + return $dbHost; + } + + public static function getPleskDbPort() + { + $dbPort = '3306'; + if (Util::isWindows()) { + $dbPort = Util::regPleskQuery('MYSQL_PORT'); + } else { + $dsnPort = Util::_getDsnConfigValue('port'); + if ($dsnPort) { + $dbPort = $dsnPort; + } + } + return $dbPort; + } + + private static function _getDsnConfigValue($param) + { + if (Util::isWindows()) { + return null; + } + + if (is_null(self::$_dsnIni)) { + if (!is_file(self::DSN_INI_PATH_UNIX)) { + self::$_dsnIni = false; + return null; + } + self::$_dsnIni = parse_ini_file(self::DSN_INI_PATH_UNIX, true); + } + + if (!self::$_dsnIni) { + return null; + } + if (!array_key_exists('plesk', self::$_dsnIni)) { + return null; + } + if (!array_key_exists($param, self::$_dsnIni['plesk'])) { + return null; + } + return self::$_dsnIni['plesk'][$param]; + } + + public static function regPleskQuery($key, $returnResult=false) + { + $reg = 'REG QUERY "HKLM\SOFTWARE\Wow6432Node\Plesk\Psa Config\Config" /v '.$key; + $output = Util::exec($reg, $code); + + if ($code) { + $log = Log::getInstance(); + $log->info($reg); + $log->info($output); + if ($returnResult) { + return false; + } else { + fatal("Unable to get '$key' from registry"); + } + } + + if (!preg_match("/\w+\s+REG_SZ\s+(.*)/i", trim($output), $matches)) { + fatal('Unable to macth registry value by key '.$key.'. Output: ' . trim($output)); + } + + return $matches[1]; + } + + public static function regQuery($path, $key, $returnResult = false) + { + $reg = 'REG QUERY "HKLM\SOFTWARE\Wow6432Node' . $path . '" '.$key; + $output = Util::exec($reg, $code); + + if ($code) { + $log = Log::getInstance(); + $log->info($reg); + $log->info($output); + if ($returnResult) { + return false; + } else { + fatal("Unable to get '$key' from registry"); + } + } + + if (!preg_match("/\s+REG_SZ(\s+)?(.*)/i", trim($output), $matches)) { + fatal('Unable to match registry value by key '.$key.'. Output: ' . trim($output)); + } + + return $matches[2]; + } + + public static function lookupCommand($cmd, $exit = false, $path = '/bin:/usr/bin:/usr/local/bin:/usr/sbin:/sbin:/usr/local/sbin') + { + $dirs = explode(':', $path); + foreach ($dirs as $dir) { + $util = $dir . '/' . $cmd; + if (is_executable($util)) { + return $util; + } + } + if ($exit) { + fatal("{$cmd}: command not found"); + } + return false; + } + + public static function getSystemDisk() + { + $cmd = 'echo %SYSTEMROOT%'; + $output = Util::exec($cmd, $code); + return substr($output, 0, 3); + } + + public static function getSystemRoot() + { + $cmd = 'echo %SYSTEMROOT%'; + $output = Util::exec($cmd, $code); + return $output; + } + + public static function getFileVersion($file) + { + $fso = new COM("Scripting.FileSystemObject"); + $version = $fso->GetFileVersion($file); + $fso = null; + return $version; + } + + public static function isUnknownISAPIfilters() + { + if (PleskVersion::is17x_or_above()) { + return false; + } + + $log = Log::getInstance(); + + $isUnknownISAPI = false; + $knownISAPI = array ("ASP\\.Net.*", "sitepreview", "COMPRESSION", "jakarta"); + + foreach ($knownISAPI as &$value) { + $value = strtoupper($value); + } + $cmd='cscript ' . Util::getSystemDisk() . 'inetpub\AdminScripts\adsutil.vbs ENUM W3SVC/FILTERS'; + $output = Util::exec($cmd, $code); + + if ($code!=0) { + $log->info("Unable to get ISAPI filters. Error: " . $output); + return false; + } + if (!preg_match_all('/FILTERS\/(.*)]/', trim($output), $matches)) { + $log->info($output); + $log->info("Unable to get ISAPI filters from output: " . $output); + return false; + } + foreach ($matches[1] as $ISAPI) { + $valid = false; + foreach ($knownISAPI as $knownPattern) { + if (preg_match("/$knownPattern/i", $ISAPI)) { + $valid = true; + break; + } + } + if (! $valid ) { + $log->warning("Unknown ISAPI filter detected in IIS: " . $ISAPI); + $isUnknownISAPI = true; + } + } + + return $isUnknownISAPI; + } + + /** + * @return string + */ + public static function getMySQLServerVersion() + { + $credentials = Util::getDefaultClientMySQLServerCredentials(); + + if (preg_match('/AES-128-CBC/', $credentials['admin_password'])) { + Log::getInstance()->info('The administrator\'s password for the default MariaDB/MySQL server is encrypted.'); + + return ''; + } + + $mysql = new DbClientMysql( + $credentials['host'], + $credentials['admin_login'], + $credentials['admin_password'], + 'information_schema', + $credentials['port'] + ); + + if (!$mysql->hasErrors()) { + $sql = 'select version()'; + $mySQLversion = $mysql->fetchOne($sql); + if (!preg_match("/(\d{1,})\.(\d{1,})\.(\d{1,})/", trim($mySQLversion), $matches)) { + fatal('Unable to match MariaDB/MySQL server version.'); + } + + return $matches[0]; + } + + return ''; + } + + public static function getDefaultClientMySQLServerCredentials() + { + $db = PleskDb::getInstance(); + $sql = "SELECT val FROM misc WHERE param='default_server_mysql'"; + $defaultServerMysqlId = $db->fetchOne($sql); + if ($defaultServerMysqlId) { + $where = "id={$defaultServerMysqlId}"; + } else { + $where = "type='mysql' AND host='localhost'"; + } + $sql = "SELECT ds.host, ds.port, ds.admin_login, ds.admin_password FROM DatabaseServers ds WHERE {$where}"; + $clientDBServerCredentials = $db->fetchAll($sql)[0]; + if ($clientDBServerCredentials['host'] === 'localhost' && Util::isLinux()) { + $clientDBServerCredentials['admin_password'] = Util::retrieveAdminMySQLDbPassword(); + } + if (empty($clientDBServerCredentials['port'])) { + $clientDBServerCredentials['port'] = self::getPleskDbPort(); + } + + return $clientDBServerCredentials; + } + + public static function retrieveAdminMySQLDbPassword() + { + return Util::isLinux() + ? trim( Util::readfile("/etc/psa/.psa.shadow") ) + : null; + } + + public static function exec($cmd, &$code) + { + $log = Log::getInstance(); + + if (!$cmd) { + $log->info('Unable to execute a blank command. Please see ' . LOG_PATH . ' for details.'); + + $debugBacktrace = ""; + foreach (debug_backtrace() as $i => $obj) { + $debugBacktrace .= "#{$i} {$obj['file']}:{$obj['line']} {$obj['function']} ()\n"; + } + $log->debug("Unable to execute a blank command. The stack trace:\n{$debugBacktrace}"); + $code = 1; + return ''; + } + exec($cmd, $output, $code); + return trim(implode("\n", $output)); + } + + public static function readfile($file) + { + if (!is_file($file) || !is_readable($file)) { + return null; + } + $lines = file($file); + return $lines === false + ? null + : trim(implode("\n", $lines)); + } + + public static function readfileToArray($file) + { + if (!is_file($file) || !is_readable($file)) { + return null; + } + $lines = file($file); + return $lines === false + ? null + : $lines; + } + + public static function getSettingFromPsaConf($setting) + { + $file = '/etc/psa/psa.conf'; + if (!is_file($file) || !is_readable($file)) + return null; + $lines = file($file); + if ($lines === false) + return null; + foreach ($lines as $line) { + if (preg_match("/^{$setting}\s.*/", $line, $match_setting)) { + if (preg_match("/[\s].*/i", $match_setting[0], $match_value)) { + $value = trim($match_value[0]); + return $value; + } + } + } + return null; + } + + public static function getPhpIni() + { + if (Util::isLinux()) { + // Debian/Ubuntu /etc/php5/apache2/php.ini /etc/php5/conf.d/ + // SuSE /etc/php5/apache2/php.ini /etc/php5/conf.d/ + // CentOS 4/5 /etc/php.ini /etc/php.d + if (PleskOS::isRedHatLike()) { + $phpini = Util::readfileToArray('/etc/php.ini'); + } else { + $phpini = Util::readfileToArray('/etc/php5/apache2/php.ini'); + } + } + + return $phpini; + } + + public static function getUserBeanCounters() + { + if (!Util::isLinux()) { + + return false; + } + $user_beancounters = array(); + $ubRaw = Util::readfileToArray('/proc/user_beancounters'); + + if (!$ubRaw) { + + return false; + } + for ($i=2; $i<=count($ubRaw)-1; $i++) { + + if (preg_match('/^.+?:?.+?\b(\w+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/', $ubRaw[$i], $limit_name)) { + + $user_beancounters[trim($limit_name[1])] = array( + 'held' => (int)$limit_name[2], + 'maxheld' => (int)$limit_name[3], + 'barrier' => (int)$limit_name[4], + 'limit' => (int)$limit_name[5], + 'failcnt' => (int)$limit_name[6] + ); + } + } + + return $user_beancounters; + } +} + +class PackageManager +{ + public static function buildListCmdLine($glob) + { + if (PleskOS::isRedHatLike()) { + $cmd = "rpm -qa --queryformat '%{NAME} %{VERSION}-%{RELEASE} %{ARCH}\\n'"; + } elseif (PleskOS::isDebLike()) { + $cmd = "dpkg-query --show --showformat '\${Package} \${Version} \${Architecture}\\n'"; + } else { + return false; + } + + if (!empty($glob)) { + $cmd .= " '" . $glob . "' 2>/dev/null"; + } + + return $cmd; + } + + /* + * Fetches a list of installed packages that match given criteria. + * string $glob - Glob (wildcard) pattern for coarse-grained packages selection from system package management backend. Empty $glob will fetch everything. + * string $regexp - Package name regular expression for a fine-grained filtering of the results. + * returns array of hashes with keys 'name', 'version' and 'arch', or false on error. + */ + public static function listInstalled($glob, $regexp = null) + { + $cmd = PackageManager::buildListCmdLine($glob); + if (!$cmd) { + return array(); + } + + $output = Util::exec($cmd, $code); + if ($code != 0) { + return false; + } + + $packages = array(); + $lines = explode("\n", $output); + foreach ($lines as $line) { + @list($pkgName, $pkgVersion, $pkgArch) = explode(" ", $line); + if (empty($pkgName) || empty($pkgVersion) || empty($pkgArch)) + continue; + if (!empty($regexp) && !preg_match($regexp, $pkgName)) + continue; + $packages[] = array( + 'name' => $pkgName, + 'version' => $pkgVersion, + 'arch' => $pkgArch + ); + } + + return $packages; + } + + public static function isInstalled($glob, $regexp = null) + { + $packages = PackageManager::listInstalled($glob, $regexp); + return !empty($packages); + } +} + +class Package +{ + function getManager($field, $package) + { + $redhat = 'rpm -q --queryformat \'%{' . $field . '}\n\' ' . $package; + $debian = 'dpkg-query --show --showformat=\'${' . $field . '}\n\' '. $package . ' 2> /dev/null'; + + if (PleskOS::isRedHatLike()) { + $manager = $redhat; + } elseif (PleskOS::isDebLike()) { + $manager = $debian; + } else { + return false; + } + + return $manager; + } + + /* DPKG doesn't supports ${Release} + * + */ + + function getRelease($package) + { + $manager = Package::getManager('Release', $package); + + if (!$manager) { + return false; + } + + $release = Util::exec($manager, $code); + if (!$code === 0) { + return false; + } + return $release; + } + + function getVersion($package) + { + $manager = Package::getManager('Version', $package); + + if (!$manager) { + return false; + } + + $version = Util::exec($manager, $code); + if (!$code === 0) { + return false; + } + return $version; + } + +} + +class PleskOS +{ + public static function isDebLike() + { + return is_file("/etc/debian_version"); + } + + public static function isRedHatLike() + { + return is_file("/etc/redhat-release"); + } + + public static function catEtcIssue() + { + $cmd = 'cat /etc/issue'; + $output = Util::exec($cmd, $code); + + return $output; + } + + public static function detectSystem() + { + $log = Log::getInstance('Detect system configuration'); + $log->info('OS: ' . (Util::isLinux() ? PleskOS::catEtcIssue() : 'Windows')); + $log->info('Arch: ' . Util::getArch()); + } +} + +class PleskValidator +{ + public static function validateIPv4($value) + { + $ip2long = ip2long($value); + if ($ip2long === false) { + return false; + } + + return $value == long2ip($ip2long); + } + + public static function validateIPv6($value) + { + if (strlen($value) < 3) { + return $value == '::'; + } + + if (strpos($value, '.')) { + $lastcolon = strrpos($value, ':'); + if (!($lastcolon && PleskValidator::validateIPv4(substr($value, $lastcolon + 1)))) { + return false; + } + + $value = substr($value, 0, $lastcolon) . ':0:0'; + } + + if (strpos($value, '::') === false) { + return preg_match('/\A(?:[a-f0-9]{1,4}:){7}[a-f0-9]{1,4}\z/i', $value); + } + + $colonCount = substr_count($value, ':'); + if ($colonCount < 8) { + return preg_match('/\A(?::|(?:[a-f0-9]{1,4}:)+):(?:(?:[a-f0-9]{1,4}:)*[a-f0-9]{1,4})?\z/i', $value); + } + + // special case with ending or starting double colon + if ($colonCount == 8) { + return preg_match('/\A(?:::)?(?:[a-f0-9]{1,4}:){6}[a-f0-9]{1,4}(?:::)?\z/i', $value); + } + + return false; + } +} + +class CheckRequirements +{ + function validate() + { + if (!PleskInstallation::isInstalled()) { + //:INFO: skip chking mysql extension if plesk is not installed + return; + } + + $reqExts = array(); + foreach ($reqExts as $name) { + $status = extension_loaded($name); + if (!$status) { + $this->_fail("PHP extension {$name} is not installed"); + } + } + } + + function _fail($errMsg) + { + echo '===Checking requirements===' . PHP_EOL; + echo PHP_EOL . 'Error: ' . $errMsg . PHP_EOL; + exit(1); + } +} + +class GetOpt +{ + var $_argv; + var $_adminDbPasswd; + + public function __construct() + { + $this->_argv = $_SERVER['argv']; + if (empty($this->_argv[1]) && Util::isLinux()) { + $this->_adminDbPasswd = Util::retrieveAdminMySQLDbPassword(); + } else { + $this->_adminDbPasswd = $this->_argv[1]; + } + } + + public function validate() + { + if (empty($this->_adminDbPasswd) && PleskInstallation::isInstalled()) { + echo 'Please specify Plesk database password'; + $this->_helpUsage(); + } + } + + public function getDbPasswd() + { + return $this->_adminDbPasswd; + } + + public function _helpUsage() + { + echo PHP_EOL . "Usage: {$this->_argv[0]} " . PHP_EOL; + exit(1); + } +} + +function fatal($msg) +{ + $log = Log::getInstance(); + $log->fatal($msg); + exit(1); +} + +$log = Log::getInstance(); + +//:INFO: Validate options +$options = new GetOpt(); +$options->validate(); + +//:INFO: Validate PHP requirements, need to make sure that PHP extensions are installed +$checkRequirements = new CheckRequirements(); +$checkRequirements->validate(); + +//:INFO: Validate Plesk installation +PleskInstallation::validate(); + +//:INFO: Detect system +$pleskOs = new PleskOS(); +$pleskOs->detectSystem(); + +//:INFO: Need to make sure that given db password is valid +if (PleskInstallation::isInstalled()) { + $log->step('Validating the database password'); + $pleskDb = PleskDb::getInstance(); + $log->resultOk(); +} + +//:INFO: Dump script version +$log->step('Pre-Upgrade analyzer version: ' . PRE_UPGRADE_SCRIPT_VERSION); + +//:INFO: Validate known OS specific issues with recommendation to avoid bugs in Plesk +$pleskKnownIssues = new Plesk17KnownIssues(); +$pleskKnownIssues->validate(); + +$plesk175Requirements = new Plesk175Requirements(); +$plesk175Requirements->validate(); + +$plesk178Requirements = new Plesk178Requirements(); +$plesk178Requirements->validate(); + +$plesk18Requirements = new Plesk18Requirements(); +$plesk18Requirements->validate(); + +$log->dumpStatistics(); +$log->writeJsonFile(); + +if ($log->getEmergency() > 0) { + exit(2); +} + +if ($log->getErrors() > 0 || $log->getWarnings() > 0) { + exit(1); +} +// vim:set et ts=4 sts=4 sw=4: diff --git a/root/parallels/pool/PSA_18.0.73_17940/examiners/php_launcher.sh b/root/parallels/pool/PSA_18.0.73_17940/examiners/php_launcher.sh new file mode 100755 index 0000000000..70ebd0f0c6 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17940/examiners/php_launcher.sh @@ -0,0 +1,38 @@ +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +die() +{ + echo $* + exit 1 +} + +[ -n "$1" ] || die "Usage: $0 php_script [args...]" + +[ "X${PLESK_INSTALLER_DEBUG}" = "X" ] || set -x +[ "X${PLESK_INSTALLER_STRICT_MODE}" = "X" ] || set -e + +php_bin= + +lookup() +{ + [ -z "$php_bin" ] || return + + local paths="$1" + local name="$2" + + for path in $paths; do + if [ -x "$path/$name" ]; then + php_bin="$path/$name" + break + fi + done +} + +lookup "/usr/local/psa/admin/bin /opt/psa/admin/bin" "php" +lookup "/usr/local/psa/bin /opt/psa/bin" "sw-engine-pleskrun" + +[ -n "$php_bin" ] || \ + die "Unable to locate the sw-engine PHP interpreter to execute the script. Make sure that Parallels Plesk Panel is installed on this server." + +exec "${php_bin}" "$@" diff --git a/root/parallels/pool/PSA_18.0.73_17940/examiners/plesk_preupgrade_checker.log b/root/parallels/pool/PSA_18.0.73_17940/examiners/plesk_preupgrade_checker.log new file mode 100644 index 0000000000..854d0e8647 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17940/examiners/plesk_preupgrade_checker.log @@ -0,0 +1,3 @@ + +INFO: Installed Plesk version/build: 18.0.73 Ubuntu 24.04 1800251009.17... +INFO: You have already installed the latest version Plesk 18.0.73. Tool must be launched prior to upgrade to Plesk 18.0.73 for the purpose of getting a report on potential problems with the upgrade. diff --git a/root/parallels/pool/PSA_18.0.73_17940/examiners/py_launcher.sh b/root/parallels/pool/PSA_18.0.73_17940/examiners/py_launcher.sh new file mode 100755 index 0000000000..96dc215391 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17940/examiners/py_launcher.sh @@ -0,0 +1,30 @@ +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +die() +{ + echo "$*" + exit 1 +} + +[ -f "$1" ] || die "Usage: $0 PEX [args...]" + +[ "X${PLESK_INSTALLER_DEBUG}" = "X" ] || set -x +[ "X${PLESK_INSTALLER_STRICT_MODE}" = "X" ] || set -e + +find_python_bin() +{ + local bin + for bin in "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3" "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2"; do + [ -x "$bin" ] || continue + python_bin="$bin" + return 0 + done + + return 1 +} + +find_python_bin || + die "Unable to locate Python interpreter to execute the script." + +exec "$python_bin" "$@" diff --git a/root/parallels/pool/PSA_18.0.73_17940/examiners/repository_check.sh b/root/parallels/pool/PSA_18.0.73_17940/examiners/repository_check.sh new file mode 100755 index 0000000000..090f121ea1 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17940/examiners/repository_check.sh @@ -0,0 +1,782 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ -z "$PLESK_INSTALLER_DEBUG" ] || set -x +[ -z "$PLESK_INSTALLER_STRICT_MODE" ] || set -e + +export LC_ALL=C +unset GREP_OPTIONS + +RET_SUCCESS=0 +RET_WARN=1 +RET_FATAL=2 + +is_function_defined() +{ + local fn="$1" + case "$(type $fn 2>/dev/null)" in + *function*) + return 0 + ;; + esac + return 1 +} + +# @params are tags in format "key=value" +# Report body (human readable information) is read from stdin +# and copied to stderr. +make_error_report() +{ + local report_file="${PLESK_INSTALLER_ERROR_REPORT:-}" + + local python_bin= + for bin in "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2" "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3"; do + if [ -x "$bin" ]; then + python_bin="$bin" + break + fi + done + + if [ -n "$report_file" -a -x "$python_bin" ]; then + "$python_bin" -c 'import sys, json +report_file = sys.argv[1] +error = sys.stdin.read() + +sys.stderr.write(error) + +data = { + "error": error, +} + +for tag in sys.argv[2:]: + k, v = tag.split("=", 1) + data[k] = v + +with open(report_file, "a") as f: + json.dump(data, f) + f.write("\n") +' "$report_file" "date=$(date --utc --iso-8601=ns)" "$@" + else + cat - >&2 + fi +} + +detect_platform() +{ + . /etc/os-release + os_name="$ID" + os_version="${VERSION_ID%%.*}" + os_arch="$(uname -m)" + if [ -e /etc/debian_version ]; then + case "$os_arch" in + x86_64) pkg_arch="amd64" ;; + aarch64) pkg_arch="arm64" ;; + esac + if [ -n "$VERSION_CODENAME" ]; then + os_codename="$VERSION_CODENAME" + else + case "$os_name$os_version" in + debian10) os_codename="buster" ;; + debian11) os_codename="bullseye" ;; + debian12) os_codename="bookworm" ;; + ubuntu18) os_codename="bionic" ;; + ubuntu20) os_codename="focal" ;; + ubuntu22) os_codename="jammy" ;; + ubuntu24) os_codename="noble" ;; + esac + fi + fi + + case "$os_name$os_version" in + rhel7|centos7|cloudlinux7|virtuozzo7) + package_manager="yum" + ;; + rhel*|centos*|cloudlinux*|almalinux*|rocky*) + package_manager="dnf" + ;; + debian*|ubuntu*) + package_manager="apt" + ;; + esac + + if [ "$os_name" = "ubuntu" -o "$os_name" = "debian" ]; then + PRODUCT_ROOT_D="/opt/psa" + else + PRODUCT_ROOT_D="/usr/local/psa" + fi +} + +has_os_impl_function() +{ + local prefix="$1" + local fn="${prefix}_${os_name}${os_version}" + is_function_defined "$fn" +} + +call_os_impl_function() +{ + local prefix="$1" + shift + local fn="${prefix}_${os_name}${os_version}" + "$fn" "$@" +} + +skip_checker_on_flag() +{ + local name="$1" + local flag="$2" + + if [ -f "$flag" ]; then + echo "$name was skipped due to flag file." >&2 + exit $RET_SUCCESS + fi +} + +skip_checker_on_env() +{ + local name="$1" + local env="$2" + + if [ -n "$env" ]; then + echo "$name was skipped due to environment variable." >&2 + exit $RET_SUCCESS + fi +} + +checker_main() +{ + local fnprefix="$1" + shift + + detect_platform + # try to execute checker only if all attributes are detected + [ -n "$os_name" -a -n "$os_version" ] || return $RET_SUCCESS + + for checker in "${fnprefix}_${os_name}${os_version}" "${fnprefix}_${os_name}" "${fnprefix}"; do + if is_function_defined "$checker"; then + local rc=$RET_SUCCESS + "$checker" "$@" || rc=$? + [ "$(( $rc & $RET_FATAL ))" = "0" ] || return $RET_FATAL + [ "$(( $rc & $RET_WARN ))" = "0" ] || return $RET_WARN + return $rc + fi + done + return $RET_SUCCESS +} + +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +# If env variable PLESK_INSTALLER_ERROR_REPORT=path_to_file is specified then in case of error +# repository_check.sh writes single line json report into it with the following fields: +# - "stage": "repositorycheck" +# - "level": "error" +# - "errtype" is one of the following: +# * "reponotcached" - repository is not cached (mostly due to unavailability). +# * "reponotenabled" - required repository is not enabled. +# * "reponotsupported" - unsupported repository is enabled. +# * "configmanagernotinstalled" - dnf config-manager is disabled. +# - "repo": repository name. +# - "date": time of error occurance ("2020-03-24T06:59:43,127545441+0000") +# - "error": human readable error message. + +report_no_repo() +{ + local repo="$1" + + make_error_report 'stage=repositorycheck' 'level=error' 'errtype=reponotenabled' "repo=$repo" <<-EOL + Plesk installation requires '$repo' OS repository to be enabled. + Make sure it is available and enabled, then try again. + EOL +} + +report_no_repo_cache() +{ + local repo="$1" + + make_error_report 'stage=repositorycheck' 'level=error' 'errtype=reponotcached' "repo=$repo" <<-EOL + Unable to create $package_manager cache for '$repo' OS repository. + Make sure the repository is available, otherwise either disable it or fix its configuration, then try again. + EOL +} + +report_unsupported_repo() +{ + local repo="$1" + + make_error_report 'stage=repositorycheck' 'level=error' 'errtype=reponotsupported' "repo=$repo" <<-EOL + Plesk installation doesn't support '$repo' OS repository. + Make sure it is disabled, then try again. + EOL +} + +report_rh_no_config_manager() +{ + local target + case "$package_manager" in + yum) + target="yum-utils package" + ;; + dnf) + target="config-manager dnf plugin" + ;; + esac + + make_error_report 'stage=repositorycheck' 'level=error' 'errtype=configmanagernotinstalled' <<-EOL + Failed to install $target. + Make sure repositories configuration of $package_manager package manager is correct + (use '$package_manager repolist --verbose' to get its actual state), then try again. + EOL +} + +check_rh_broken_repos() +{ + local rh_enabled_repos rh_available_repos + + # 1. `yum repolist` and `dnf repolist` list all repos + # which were enabled before last cache creation + # even if cache for them was not created. + # If some repo is misconfigured and cache was created with `skip_if_unavailable=1` + # then such repo will be listed anyway despite on cache state. + # If some repo was enabled after last cache creation + # then `repolist --cacheonly` will fail. + # 2. `yum repolist --verbose` and `dnf repoinfo` list only repos + # which were successfully cached before. + # These commands fail if at least one repo is not available + # and the 'skip_if_unavailable' flag is not set. + case "$package_manager" in + yum) + rh_enabled_repos="$( + { + yum repolist enabled --cacheonly -q 2>/dev/null \ + || yum repolist enabled -q --setopt='*.skip_if_unavailable=1' + } | sed -n -e '1d' -e 's/^\*\?!\?\([^/[:space:]]\+\).*/\1/p' + )" || return $RET_FATAL + + rh_available_repos="$( + yum repolist enabled --verbose --cacheonly -q --setopt='*.skip_if_unavailable=1' \ + | sed -n -e 's/^Repo-id\s*:\s*\([^/[:space:]]\+\).*/\1/p' + )" || return $RET_FATAL + ;; + dnf) + rh_enabled_repos="$( + { + dnf repolist --enabled --cacheonly -q 2>/dev/null \ + || dnf repolist --enabled -q --setopt='*.skip_if_unavailable=1' + } | sed -n -e '1d' -e 's/^!\?\(\S\+\).*/\1/p' + )" || return $RET_FATAL + + rh_available_repos="$( \ + dnf repoinfo --enabled --cacheonly -q --setopt='*.skip_if_unavailable=1' \ + | sed -n -e 's|^Repo-id\s*:\s*\(\S\+\)\s*$|\1|p' + )" || return $RET_FATAL + ;; + esac + + local rh_enabled_repos_f="$(mktemp /tmp/plesk-installer.preupgrade_checker.XXXXXX)" + echo "$rh_enabled_repos" | sort > "$rh_enabled_repos_f" + local rh_available_repos_f="$(mktemp /tmp/plesk-installer.preupgrade_checker.XXXXXX)" + echo "$rh_available_repos" | sort > "$rh_available_repos_f" + + local repo rc=0 + for repo in $(comm -23 "$rh_enabled_repos_f" "$rh_available_repos_f"); do + report_no_repo_cache "$repo" + rc=$RET_WARN + done + + rm -f "$rh_enabled_repos_f" "$rh_available_repos_f" + + return $rc +} + +has_rh_enabled_repo() +{ + local repo="$1" + + # Try to get list of repos from cache first. + # If some repo was enabled after last cache creation + # or some repo is unavailable the query from cache will fail. + # Try to fetch actual metadata in this case. + case "$package_manager" in + yum) + # Repo-id may end with OS version and/or architecture + # if baseurl of the repo refers to $releasever and/or $basearch variables + # eg 'epel/7/x86_64', 'epel/7', 'epel/x86_64' + { + yum repolist enabled --verbose --cacheonly -q 2>/dev/null \ + || yum repolist enabled --verbose -q --setopt='*.skip_if_unavailable=1' + } | grep -E -q "^Repo-id\s*: $repo(/.+)?\s*$" + ;; + dnf) + # note: --noplugins may cause failure and empty output on RedHat + { + dnf repoinfo --enabled --cacheonly -q 2>/dev/null \ + || dnf repoinfo --enabled -q --setopt='*.skip_if_unavailable=1' + } | grep -E -q "^Repo-id\s*: $repo\s*$" + ;; + esac +} + +has_rh_config_manager() +{ + case "$package_manager" in + yum) yum-config-manager --help >/dev/null 2>&1 ;; + dnf) dnf config-manager --help >/dev/null 2>&1 ;; + esac +} + +install_rh_config_manager() +{ + case "$package_manager" in + yum) yum install --disablerepo 'PLESK_*' -q -y 'yum-utils' --setopt='*.skip_if_unavailable=1' ;; + dnf) dnf install --disablerepo 'PLESK_*' -q -y 'dnf-command(config-manager)' --setopt='*.skip_if_unavailable=1' ;; + esac +} + +check_rh_config_manager() +{ + if ! has_rh_config_manager && ! install_rh_config_manager; then + report_rh_no_config_manager + return $RET_FATAL + fi +} + +enable_rh_repo() +{ + case "$package_manager" in + yum) yum-config-manager --enable "$@" && has_rh_enabled_repo "$@" ;; + dnf) dnf config-manager --set-enabled "$@" && has_rh_enabled_repo "$@" ;; + esac +} + +enable_sm_repo() +{ + ! has_rh_enabled_repo "$@" || return 0 + subscription-manager repos --enable "$@" || return $? + # On RedHat 8 above command may return 0 on failure with "Repositories disabled by configuration." + has_rh_enabled_repo "$@" +} + +check_epel() +{ + ! enable_rh_repo "epel" || return 0 + + # try to install epel-release from centos/extras or plesk/thirdparty repo + # and then try to update it to last version shipped by epel itself + # to make package upgradable with pum + "$package_manager" install --disablerepo 'PLESK_*' -q -y 'epel-release' --setopt='*.skip_if_unavailable=1' 2>/dev/null \ + || "$package_manager" install --disablerepo='*' --enablerepo 'PLESK_18_*-thirdparty' -q -y 'epel-release' \ + || "$package_manager" install -q -y "https://dl.fedoraproject.org/pub/epel/epel-release-latest-$os_version.noarch.rpm" \ + && "$package_manager" update -q -y 'epel-release' --setopt='*.skip_if_unavailable=1' 2>/dev/null + + # Ensure any other EPEL repos have cache for subsequent check for broken repos (AL9) + local epel_repos="$( + [ "$package_manager" != "dnf" ] || { + dnf repolist --enabled --cacheonly -q 2>/dev/null || + dnf repolist --enabled -q --setopt='*.skip_if_unavailable=1' + } | sed -n -e '1d' -e 's/^!\?\(epel\S\+\).*/\1/p' + )" + for repo in $epel_repos; do + "$package_manager" makecache --repo "$repo" -q + done + + ! has_rh_enabled_repo "epel" || return 0 + + report_no_repo "epel" + return $RET_FATAL +} + +check_codeready() +{ + local repo_rhel="codeready-builder-for-rhel-$os_version-$os_arch-rpms" + local repo_rhui="codeready-builder-for-rhel-$os_version-rhui-rpms" + local repo_rhui_alt="codeready-builder-for-rhel-$os_version-$os_arch-rhui-rpms" + local repo_rhui_alt2="rhui-codeready-builder-for-rhel-$os_version-$os_arch-rhui-rpms" + + ! enable_sm_repo "$repo_rhel" || return 0 + ! enable_rh_repo "$repo_rhui" || return 0 + ! enable_rh_repo "$repo_rhui_alt" || return 0 + ! enable_rh_repo "$repo_rhui_alt2" || return 0 + + report_no_repo "$repo_rhel" + return $RET_FATAL +} + +check_optional() +{ + local repo_rhel="rhel-$os_version-server-optional-rpms" + local repo_rhui="rhel-$os_version-server-rhui-optional-rpms" + + ! enable_sm_repo "$repo_rhel" || return 0 + ! enable_rh_repo "$repo_rhui" || return 0 + + report_no_repo "$repo_rhel" + return $RET_FATAL +} + +check_repos_rhel9() +{ + check_rh_config_manager || return $? + + local rc=0 + + check_epel || rc="$(( $rc | $? ))" + check_codeready || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + return $rc +} + +check_repos_almalinux9() +{ + check_rh_config_manager || return $? + + local rc=0 + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + # powertools is renamed to crb since AlmaLinux 9 + ! enable_rh_repo "crb" || return $rc + + report_no_repo "crb" + return $RET_FATAL +} + +check_repos_cloudlinux9() +{ + check_repos_almalinux9 "$@" +} + +check_repos_almalinux10() +{ + check_repos_almalinux9 "$@" +} + +check_repos_centos8() +{ + check_rh_config_manager || return $? + + local rc=0 + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + # names of repos are lowercased since 8.3 + ! enable_rh_repo "powertools" || return $rc + ! enable_rh_repo "PowerTools" || return $rc + + report_no_repo "powertools" + return $RET_FATAL +} + +check_repos_cloudlinux8() +{ + check_rh_config_manager || return $? + + local rc=0 + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + # names of repos are changed since 8.5 + ! enable_rh_repo "powertools" || return $rc + ! enable_rh_repo "cloudlinux-PowerTools" || return $rc + + report_no_repo "powertools" + return $RET_FATAL +} + +check_repos_rhel8() +{ + check_rh_config_manager || return $? + + local rc=0 + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + [ "$1" = "install" ] || return $rc + + check_codeready || rc="$(( $rc | $? ))" + + return $rc +} + +check_repos_almalinux8() +{ + check_repos_centos8 "$@" +} + +check_repos_rocky8() +{ + check_repos_centos8 "$@" +} + +check_repos_rhel7() +{ + check_rh_config_manager || return $? + + local rc=0 + + check_epel || rc="$(( $rc | $? ))" + check_optional || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + return $rc +} + +check_repos_centos7_based() +{ + check_rh_config_manager || return $? + + local rc=0 + + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + return $rc +} + +sed_escape() +{ + # Note: this is not a full implementation + echo -n "$1" | sed -e 's|\.|\\.|g' +} + +switch_eol_centos_repos() +{ + local old_mirrorlist_host="mirrorlist.centos.org" + local old_host="mirror.centos.org" + local new_host="vault.centos.org" + + grep -qFw "$old_host" /etc/yum.repos.d/CentOS-*.repo 2>/dev/null || return 0 + local backup="`mktemp -d "/tmp/yum.repos.d-$(date --rfc-3339=date)-XXXXXX"`" + ! [ -d "$backup" ] || cp -raT /etc/yum.repos.d "$backup" || : + + sed -i \ + -e "s|^\s*\(mirrorlist\b[^/]*//`sed_escape "$old_mirrorlist_host"`/.*\)$|#\1|" \ + -e "s|^#*\s*baseurl\b\([^/]*\)//`sed_escape "$old_host"`/\(.*\)$|baseurl\1//$new_host/\2|" \ + /etc/yum.repos.d/CentOS-*.repo + echo "YUM package manager repositories were backed up to '$backup' and switched from $old_host to $new_host ." >&2 +} + +check_repos_centos7() +{ + switch_eol_centos_repos + + check_repos_centos7_based "$@" +} + +check_repos_cloudlinux7() +{ + check_repos_centos7_based "$@" +} + +check_repos_virtuozzo7() +{ + check_repos_centos7_based "$@" +} + +find_apt_repo() +{ + local repo="$1" + + local dist_tag= + ! [ "$os_name" = "ubuntu" ] || dist_tag="a" + ! [ "$os_name" = "debian" ] || dist_tag="n" + + if [ -z "$_apt_cache_policy" ]; then + # extract info of each available release as a string which consists of 'tag=value' + # filter out releases with priority less or equal to 100 + _apt_cache_policy="$( + apt-cache policy \ + | grep "b=$pkg_arch" \ + | grep -Eo '([a-z]=[^,]+,?)*' \ + )" + fi + + local l="$(echo "$repo" | cut -f1 -d'/')" + local d="$(echo "$repo" | cut -f2 -d'/')" + local c="$(echo "$repo" | cut -f3 -d'/')" + + # try to find releases by distribution and component + echo "$_apt_cache_policy" \ + | grep -E "(^|,)l=$l(,|$)" \ + | grep -E "(^|,)$dist_tag=$d(,|$)" \ + | grep -E "(^|,)c=$c(,|$)" \ + | while IFS="$(printf '\n')" read rel && [ -n "$rel" ]; do + l="$(echo "$rel" | grep -Eo "(^|,)l=[^,]+" | cut -f2 -d"=")" + d="$(echo "$rel" | grep -Eo "(^|,)$dist_tag=[^,]+" | cut -f2 -d"=")" + c="$(echo "$rel" | grep -Eo "(^|,)c=[^,]+" | cut -f2 -d"=")" + echo "$l/$d/$c" + done +} + +apt_install_packages() +{ + DEBIAN_FRONTEND=noninteractive LANG=C PATH=/usr/sbin:/usr/bin:/sbin:/bin \ + apt-get -qq --assume-yes -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold -o APT::Install-Recommends=no \ + install "$@" +} + +# Takes a list of suites and disables them in APT sources. +# Multiline deb822 format is supported. +disable_apt_suites_deb822() +{ + local python3=/usr/bin/python3 + + "$python3" -c 'import aptsources.sourceslist' 2>/dev/null || + apt_install_packages python3-apt + + "$python3" -c ' +import sys + +from aptsources.sourceslist import SourcesList + + +suites_to_disable=set(sys.argv[1:]) + +sources_list = SourcesList(deb822=True) + +sources_changed = False +for src in sources_list: + if src.invalid: + continue + suites = getattr(src, "suites", ()) + if not suites: + continue + new_suites = [s for s in suites if s not in suites_to_disable] + if len(new_suites) != len(suites): + sources_changed = True + if len(new_suites) == 0: + src.disabled = True + else: + src.suites = new_suites + +if sources_changed: + sources_list.save() +' "$@" + + # Since we have changed the repositories list, we should re-read _apt_cache_policy on a next call + # of the find_apt_repo function. Hence we have to reset the value of the variable + _apt_cache_policy="" +} + +disable_apt_repo() +{ + local repos_to_disable="$(find_apt_repo "$1" | cut -d '/' -f 2,3 | sort | uniq)" + if [ -z "$repos_to_disable" ]; then + return 0 + fi + + echo "$repos_to_disable" \ + | while IFS= read -r repo_to_disable && [ -n "$repo_to_disable" ]; do + local distrib=${repo_to_disable%%/*} + local component=${repo_to_disable##*/} + find /etc/apt -name "*.list" -exec \ + sed -i -e "/^\s*#/! s/.*\s$distrib\s\+$component\b/# &/" {} + + done + + # Since we have changed the repositories list, we should re-read _apt_cache_policy on a next call + # of the find_apt_repo function. Hence we have to reset the value of the variable + _apt_cache_policy="" + + return 0 +} + +check_required_apt_repo() +{ + local repo="$1" + [ -z "$(find_apt_repo "$repo")" ] || return 0 + report_no_repo "$repo" + return $RET_FATAL +} + +check_unsupported_apt_repos_ubuntu() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + + local repos="$( + find_apt_repo "Ubuntu/[^,]+/[^,]+" | grep -v "Ubuntu/$os_codename.*/.*" + find_apt_repo "Debian[^,]*/[^,]+/[^,]+" + )" + [ -n "$repos" ] || return 0 + + echo "$repos" | while IFS="$(printf '\n')" read repo; do + report_unsupported_repo "$repo" + done + + [ "$mode" = "install" ] || return $RET_WARN + return $RET_FATAL +} + +check_repos_ubuntu18() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + local rc=0 + + check_required_apt_repo "Ubuntu/$os_codename/main" || rc="$(( $rc | $? ))" + check_required_apt_repo "Ubuntu/$os_codename/universe" || rc="$(( $rc | $? ))" + check_required_apt_repo "Ubuntu/$os_codename-updates/main" || rc="$(( $rc | $? ))" + check_required_apt_repo "Ubuntu/$os_codename-updates/universe" || rc="$(( $rc | $? ))" + check_unsupported_apt_repos_ubuntu "$mode" || rc="$(( $rc | $? ))" + + return $rc +} + + +check_repos_ubuntu() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + local rc=0 + + check_required_apt_repo "Ubuntu/$os_codename/main" || rc="$(( $rc | $? ))" + check_required_apt_repo "Ubuntu/$os_codename/universe" || rc="$(( $rc | $? ))" + check_unsupported_apt_repos_ubuntu "$mode" || rc="$(( $rc | $? ))" + + return $rc +} + +check_unsupported_apt_repos_debian() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + + local repos="$( + find_apt_repo "Debian Backports/$os_codename-backports/[^,]+" + find_apt_repo "Debian[^,]*/[^,]+/[^,]+" | grep -v "Debian.*/$os_codename.*/.*" + find_apt_repo "Ubuntu/[^,]+/[^,]+" + )" + [ -n "$repos" ] || return 0 + + echo "$repos" | while IFS="$(printf '\n')" read repo; do + report_unsupported_repo "$repo" + done + + [ "$mode" = "install" ] || return $RET_WARN + return $RET_FATAL +} + +check_repos_debian() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + local rc=0 + + if [ "$os_name" = "debian" -a "$os_version" -ge 12 ]; then + disable_apt_suites_deb822 "$os_codename-backports" + else + disable_apt_repo "Debian Backports/$os_codename-backports/[^,]+" + fi + + check_required_apt_repo "Debian/$os_codename/main" || rc="$(( $rc | $? ))" + check_unsupported_apt_repos_debian "$mode" || rc="$(( $rc | $? ))" + + return $rc +} + +# --- + +skip_checker_on_flag "Repository check" "/tmp/plesk-installer-skip-repository-check.flag" + +checker_main 'check_repos' "$1" diff --git a/root/parallels/pool/PSA_18.0.73_17940/examiners/sh_cmd.sh b/root/parallels/pool/PSA_18.0.73_17940/examiners/sh_cmd.sh new file mode 100755 index 0000000000..ed95d0acbb --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17940/examiners/sh_cmd.sh @@ -0,0 +1,7 @@ +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ "X${PLESK_INSTALLER_DEBUG}" = "X" ] || set -x +[ "X${PLESK_INSTALLER_STRICT_MODE}" = "X" ] || set -e + +exec "$@" diff --git a/root/parallels/pool/PSA_18.0.73_17940/plesk-18.0.73-ubt24.04-x86_64.inf3 b/root/parallels/pool/PSA_18.0.73_17940/plesk-18.0.73-ubt24.04-x86_64.inf3 new file mode 100644 index 0000000000..120ba03792 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17940/plesk-18.0.73-ubt24.04-x86_64.inf3 @@ -0,0 +1,927 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -----BEGIN PGP PUBLIC KEY BLOCK----- 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 VNnMRY8n =Hv0N -----END PGP PUBLIC KEY BLOCK----- + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + + + + + mysqlgroup + l10n + proftpd + webservers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + imapservers + + + + + + + + + + + + + + + + + + + imapservers + + + + + + + + + + + + + + mailman + spamassassin + drweb + sophos + courier + dovecot + + + + + + + + + + + + + + + + + + + + + + mailservers + + + + + + + + + + + + + + + + + + + + mailservers + + + + + + + + + + + + + + + + + + panel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + webservers + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + + + + + + + + + + + + + + + + php7.4 + + + + + + + + + + + + + + + + + + + + + + + + + + php8.3 + + + + + + + + + + + webservers + + + + + + + + webservers + + + + + + + + + + + + + + + + + + panel + + + + + + + + + + + + + panel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + panel + + + + + + + + + + + + + + + + + + + + panel + + + + + + + panel + + + + + + + + panel + + + + + + + panel + passenger + + + + + + ruby + + + + + + + panel + + + + + + panel + + + + + + panel + passenger + + + + + + + + + + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + panel + roundcube + postfix + dovecot + mod_fcgid + proftpd + webalizer + awstats + webservers + nginx + mysqlgroup + l10n + bind + wp-toolkit + advisor + git + xovi + imunify360 + fail2ban + modsecurity + sslit + letsencrypt + repair-kit + composer + monitoring + log-browser + ssh-terminal + site-import + sitejet + ntp-timesync + php8.3 + php8.4 + mfa + configurations-troubleshooter + + + panel + roundcube + postfix + dovecot + mod_fcgid + proftpd + webalizer + awstats + webservers + nginx + mysqlgroup + l10n + bind + wp-toolkit + advisor + git + xovi + imunify360 + fail2ban + modsecurity + sslit + letsencrypt + repair-kit + composer + monitoring + log-browser + ssh-terminal + site-import + sitejet + ntp-timesync + php8.1 + php8.2 + php8.3 + php8.4 + mfa + configurations-troubleshooter + resctrl + drweb + postgresql + spamassassin + ruby + gems-pre + nodejs + pmm + psa-firewall + watchdog + passenger + phpgroup + sophos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.73_17940/release.inf3 b/root/parallels/pool/PSA_18.0.73_17940/release.inf3 new file mode 100644 index 0000000000..4fb000283d --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17940/release.inf3 @@ -0,0 +1,36 @@ + + + + + + + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.73_17971/examiners/check_broken_timezone.sh b/root/parallels/pool/PSA_18.0.73_17971/examiners/check_broken_timezone.sh new file mode 100755 index 0000000000..ee862642be --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17971/examiners/check_broken_timezone.sh @@ -0,0 +1,255 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ -z "$PLESK_INSTALLER_DEBUG" ] || set -x +[ -z "$PLESK_INSTALLER_STRICT_MODE" ] || set -e + +export LC_ALL=C +unset GREP_OPTIONS + +RET_SUCCESS=0 +RET_WARN=1 +RET_FATAL=2 + +is_function_defined() +{ + local fn="$1" + case "$(type $fn 2>/dev/null)" in + *function*) + return 0 + ;; + esac + return 1 +} + +# @params are tags in format "key=value" +# Report body (human readable information) is read from stdin +# and copied to stderr. +make_error_report() +{ + local report_file="${PLESK_INSTALLER_ERROR_REPORT:-}" + + local python_bin= + for bin in "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2" "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3"; do + if [ -x "$bin" ]; then + python_bin="$bin" + break + fi + done + + if [ -n "$report_file" -a -x "$python_bin" ]; then + "$python_bin" -c 'import sys, json +report_file = sys.argv[1] +error = sys.stdin.read() + +sys.stderr.write(error) + +data = { + "error": error, +} + +for tag in sys.argv[2:]: + k, v = tag.split("=", 1) + data[k] = v + +with open(report_file, "a") as f: + json.dump(data, f) + f.write("\n") +' "$report_file" "date=$(date --utc --iso-8601=ns)" "$@" + else + cat - >&2 + fi +} + +detect_platform() +{ + . /etc/os-release + os_name="$ID" + os_version="${VERSION_ID%%.*}" + os_arch="$(uname -m)" + if [ -e /etc/debian_version ]; then + case "$os_arch" in + x86_64) pkg_arch="amd64" ;; + aarch64) pkg_arch="arm64" ;; + esac + if [ -n "$VERSION_CODENAME" ]; then + os_codename="$VERSION_CODENAME" + else + case "$os_name$os_version" in + debian10) os_codename="buster" ;; + debian11) os_codename="bullseye" ;; + debian12) os_codename="bookworm" ;; + ubuntu18) os_codename="bionic" ;; + ubuntu20) os_codename="focal" ;; + ubuntu22) os_codename="jammy" ;; + ubuntu24) os_codename="noble" ;; + esac + fi + fi + + case "$os_name$os_version" in + rhel7|centos7|cloudlinux7|virtuozzo7) + package_manager="yum" + ;; + rhel*|centos*|cloudlinux*|almalinux*|rocky*) + package_manager="dnf" + ;; + debian*|ubuntu*) + package_manager="apt" + ;; + esac + + if [ "$os_name" = "ubuntu" -o "$os_name" = "debian" ]; then + PRODUCT_ROOT_D="/opt/psa" + else + PRODUCT_ROOT_D="/usr/local/psa" + fi +} + +has_os_impl_function() +{ + local prefix="$1" + local fn="${prefix}_${os_name}${os_version}" + is_function_defined "$fn" +} + +call_os_impl_function() +{ + local prefix="$1" + shift + local fn="${prefix}_${os_name}${os_version}" + "$fn" "$@" +} + +skip_checker_on_flag() +{ + local name="$1" + local flag="$2" + + if [ -f "$flag" ]; then + echo "$name was skipped due to flag file." >&2 + exit $RET_SUCCESS + fi +} + +skip_checker_on_env() +{ + local name="$1" + local env="$2" + + if [ -n "$env" ]; then + echo "$name was skipped due to environment variable." >&2 + exit $RET_SUCCESS + fi +} + +checker_main() +{ + local fnprefix="$1" + shift + + detect_platform + # try to execute checker only if all attributes are detected + [ -n "$os_name" -a -n "$os_version" ] || return $RET_SUCCESS + + for checker in "${fnprefix}_${os_name}${os_version}" "${fnprefix}_${os_name}" "${fnprefix}"; do + if is_function_defined "$checker"; then + local rc=$RET_SUCCESS + "$checker" "$@" || rc=$? + [ "$(( $rc & $RET_FATAL ))" = "0" ] || return $RET_FATAL + [ "$(( $rc & $RET_WARN ))" = "0" ] || return $RET_WARN + return $rc + fi + done + return $RET_SUCCESS +} + +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +# If env variable PLESK_INSTALLER_ERROR_REPORT=path_to_file is specified then in case of error +# check-broken-tz.sh writes single line json report into it with the following fields: +# - "stage": "timezonefix" +# - "level": "error" +# - "errtype": "failure" +# - "date": time of error occurance ("2024-07-24T06:59:43,127545441+0000") +# - "error": human readable error message + +report_dpkg_configure_fail() +{ + local pkgname="$1" + make_error_report 'stage=timezonefix' 'level=error' 'errtype=dpkgconfigurefailed' <<-EOL + Could not configure the packages ( $pkgname ). See https://support.plesk.com/hc/en-us/articles/24721507961623-Plesk-provides-error-on-update-Package-tzdata-is-not-configured-yet for more details. + EOL +} + +report_get_tz_fail() +{ + make_error_report 'stage=timezonefix' 'level=error' 'errtype=gettzfailed' <<-EOL + Could not get the system timezone. See https://support.plesk.com/hc/en-us/articles/24721507961623-Plesk-provides-error-on-update-Package-tzdata-is-not-configured-yet for more details. + EOL +} + +report_set_tz_fail() +{ + local tz="$1" + + make_error_report 'stage=timezonefix' 'level=error' 'errtype=settzfailed' <<-EOL + Could not set the system timezone ( $tz ). See https://support.plesk.com/hc/en-us/articles/24721507961623-Plesk-provides-error-on-update-Package-tzdata-is-not-configured-yet for more details. + EOL +} + +get_current_tz() +{ + [ -L /etc/localtime ] || return 1 + + local tz + tz="$(readlink -m /etc/localtime)" || return 1 + [ -f "$tz" ] || return 1 + case "$tz" in + /usr/share/zoneinfo/*) ;; + *) return 1;; + esac + tz="${tz#/usr/share/zoneinfo/}" + [ -n "$tz" ] || return 1 + + echo -n "${tz}" +} + +check_timezone_ubuntu() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + + # PPP-65676: Plesk update fails on ubuntu if timezone is CET + if dpkg-query --showformat='${db:Status-Status}\n' --show 'tzdata' | grep -wq 'half-configured'; then + local origtz + origtz=$(get_current_tz) + if [ $? != 0 ]; then + report_get_tz_fail + return $RET_WARN + fi + if ! timedatectl set-timezone 'Etc/UTC'; then + timedatectl set-timezone "$origtz" + report_set_tz_fail 'Etc/UTC' + return $RET_WARN + fi + if ! dpkg --configure 'tzdata'; then + timedatectl set-timezone "$origtz" + report_dpkg_configure_fail 'tzdata' + return $RET_WARN + fi + if ! timedatectl set-timezone "$origtz"; then + report_set_tz_fail "$origtz" + return $RET_WARN + fi + fi + + return 0 +} + +# --- + +skip_checker_on_flag "Broken timezone check" "/tmp/plesk-installer-skip-check-broken-timezone.flag" + +checker_main 'check_timezone' "$1" diff --git a/root/parallels/pool/PSA_18.0.73_17971/examiners/disk_space_check.sh b/root/parallels/pool/PSA_18.0.73_17971/examiners/disk_space_check.sh new file mode 100755 index 0000000000..1fdfb44037 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17971/examiners/disk_space_check.sh @@ -0,0 +1,542 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ -z "$PLESK_INSTALLER_DEBUG" ] || set -x +[ -z "$PLESK_INSTALLER_STRICT_MODE" ] || set -e + +export LC_ALL=C +unset GREP_OPTIONS + +RET_SUCCESS=0 +RET_WARN=1 +RET_FATAL=2 + +is_function_defined() +{ + local fn="$1" + case "$(type $fn 2>/dev/null)" in + *function*) + return 0 + ;; + esac + return 1 +} + +# @params are tags in format "key=value" +# Report body (human readable information) is read from stdin +# and copied to stderr. +make_error_report() +{ + local report_file="${PLESK_INSTALLER_ERROR_REPORT:-}" + + local python_bin= + for bin in "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2" "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3"; do + if [ -x "$bin" ]; then + python_bin="$bin" + break + fi + done + + if [ -n "$report_file" -a -x "$python_bin" ]; then + "$python_bin" -c 'import sys, json +report_file = sys.argv[1] +error = sys.stdin.read() + +sys.stderr.write(error) + +data = { + "error": error, +} + +for tag in sys.argv[2:]: + k, v = tag.split("=", 1) + data[k] = v + +with open(report_file, "a") as f: + json.dump(data, f) + f.write("\n") +' "$report_file" "date=$(date --utc --iso-8601=ns)" "$@" + else + cat - >&2 + fi +} + +detect_platform() +{ + . /etc/os-release + os_name="$ID" + os_version="${VERSION_ID%%.*}" + os_arch="$(uname -m)" + if [ -e /etc/debian_version ]; then + case "$os_arch" in + x86_64) pkg_arch="amd64" ;; + aarch64) pkg_arch="arm64" ;; + esac + if [ -n "$VERSION_CODENAME" ]; then + os_codename="$VERSION_CODENAME" + else + case "$os_name$os_version" in + debian10) os_codename="buster" ;; + debian11) os_codename="bullseye" ;; + debian12) os_codename="bookworm" ;; + ubuntu18) os_codename="bionic" ;; + ubuntu20) os_codename="focal" ;; + ubuntu22) os_codename="jammy" ;; + ubuntu24) os_codename="noble" ;; + esac + fi + fi + + case "$os_name$os_version" in + rhel7|centos7|cloudlinux7|virtuozzo7) + package_manager="yum" + ;; + rhel*|centos*|cloudlinux*|almalinux*|rocky*) + package_manager="dnf" + ;; + debian*|ubuntu*) + package_manager="apt" + ;; + esac + + if [ "$os_name" = "ubuntu" -o "$os_name" = "debian" ]; then + PRODUCT_ROOT_D="/opt/psa" + else + PRODUCT_ROOT_D="/usr/local/psa" + fi +} + +has_os_impl_function() +{ + local prefix="$1" + local fn="${prefix}_${os_name}${os_version}" + is_function_defined "$fn" +} + +call_os_impl_function() +{ + local prefix="$1" + shift + local fn="${prefix}_${os_name}${os_version}" + "$fn" "$@" +} + +skip_checker_on_flag() +{ + local name="$1" + local flag="$2" + + if [ -f "$flag" ]; then + echo "$name was skipped due to flag file." >&2 + exit $RET_SUCCESS + fi +} + +skip_checker_on_env() +{ + local name="$1" + local env="$2" + + if [ -n "$env" ]; then + echo "$name was skipped due to environment variable." >&2 + exit $RET_SUCCESS + fi +} + +checker_main() +{ + local fnprefix="$1" + shift + + detect_platform + # try to execute checker only if all attributes are detected + [ -n "$os_name" -a -n "$os_version" ] || return $RET_SUCCESS + + for checker in "${fnprefix}_${os_name}${os_version}" "${fnprefix}_${os_name}" "${fnprefix}"; do + if is_function_defined "$checker"; then + local rc=$RET_SUCCESS + "$checker" "$@" || rc=$? + [ "$(( $rc & $RET_FATAL ))" = "0" ] || return $RET_FATAL + [ "$(( $rc & $RET_WARN ))" = "0" ] || return $RET_WARN + return $rc + fi + done + return $RET_SUCCESS +} + +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +# If env variable PLESK_INSTALLER_ERROR_REPORT=path_to_file is specified then in case of error +# disk_space_check.sh writes single line json report into it with the following fields: +# - "stage": "diskspacecheck" +# - "level": "error" +# - "errtype": "notenoughdiskspace" +# - "volume": volume with not enough diskspace (e.g. "/") +# - "required": required diskspace on the volume, human readable (e.g. "600 MB") +# - "available": available diskspace on the volume, human readable (e.g. "255 MB") +# - "needtofree": amount of diskspace which should be freed on the volume, human readable (e.g. "345 MB") +# - "date": time of error occurance ("2020-03-24T06:59:43,127545441+0000") +# - "error": human readable error message ("There is not enough disk space available in the / directory.") + +# Required values below for Full installation are in MB. See 'du -cs -BM /*' and 'df -Pm'. + +required_disk_space_cloudlinux7() +{ + case "$1" in + /opt) echo 900 ;; + /usr) echo 4400 ;; + /var) echo 600 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_cloudlinux8() +{ + case "$1" in + /opt) echo 1200 ;; + /usr) echo 4400 ;; + /var) echo 700 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_centos7() +{ + case "$1" in + /opt) echo 900 ;; + /usr) echo 4100 ;; + /var) echo 600 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_centos8() +{ + case "$1" in + /opt) echo 900 ;; + /usr) echo 4500 ;; + /var) echo 800 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_virtuozzo7() +{ + required_disk_space_centos7 "$1" +} + +required_disk_space_rhel7() +{ + required_disk_space_centos7 "$1" +} + +required_disk_space_rhel8() +{ + required_disk_space_centos8 "$1" +} + +required_disk_space_almalinux8() +{ + required_disk_space_centos8 "$1" +} + +required_disk_space_rocky8() +{ + required_disk_space_centos8 "$1" +} + +required_disk_space_rhel9() +{ + case "$1" in + /opt) echo 500 ;; + /usr) echo 4000 ;; + /var) echo 800 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_almalinux9() +{ + required_disk_space_rhel9 "$1" +} + +required_disk_space_almalinux10() +{ + required_disk_space_almalinux9 "$1" +} + +required_disk_space_cloudlinux9() +{ + required_disk_space_rhel9 "$1" +} + +required_disk_space_debian10() +{ + case "$1" in + /opt) echo 1800 ;; + /usr) echo 2300 ;; + /var) echo 1700 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_debian11() +{ + case "$1" in + /opt) echo 1500 ;; + /usr) echo 3100 ;; + /var) echo 1800 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_debian12() +{ + case "$1" in + /opt) echo 2700 ;; + /usr) echo 2500 ;; + /var) echo 2200 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_debian13() +{ + case "$1" in + /opt) echo 2700 ;; + /usr) echo 2500 ;; + /var) echo 2200 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_ubuntu18() +{ + case "$1" in + /opt) echo 900 ;; + /usr) echo 1800 ;; + /var) echo 600 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_ubuntu20() +{ + case "$1" in + /opt) echo 1800 ;; + /usr) echo 2900 ;; + /var) echo 1600 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_ubuntu22() +{ + case "$1" in + /opt) echo 1800 ;; + /usr) echo 3900 ;; + /var) echo 1900 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_ubuntu24() +{ + case "$1" in + /opt) echo 3200 ;; + /usr) echo 1800 ;; + /var) echo 2400 ;; + /tmp) echo 100 ;; + esac +} + +required_update_upgrade_disk_space() +{ + case "$1" in + /opt) echo 100 ;; + /usr) echo 300 ;; + /var) echo 600 ;; + /tmp) echo 100 ;; + esac +} + +clean_tmp() +{ + local volume="$1" + local path="/tmp" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'systemd-tmpfiles --clean --prefix $path'" + systemd-tmpfiles --clean --prefix "$path" 2>&1 +} + +clean_yum() +{ + local volume="$1" + local path="/var/cache/yum" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'yum clean all'" + yum clean all 2>&1 + + # The command above doesn't clean untracked repos (missing in configuration), clean if left > 2 Mb + [ "`du -sm "$path" | awk '{ print $1 }'`" -gt 2 ] || return 0 + echo "Cleaning $path via 'rm -rf $path/*'" + rm -rf "$path"/* 2>&1 +} + +clean_dnf() +{ + local volume="$1" + local path="/var/cache/dnf" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'dnf clean all'" + dnf clean all 2>&1 +} + +clean_apt() +{ + local volume="$1" + local path="/var/cache/apt" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'apt-get clean'" + apt-get clean 2>&1 +} + +clean_journal() +{ + local volume="$1" + local path="/var/log/journal" + is_path_on_volume "$path" "$volume" || return 0 + + # Note that --rotate may cause more space to be freed, but may also cause more space to be used + echo "Cleaning $path via 'journalctl --vacuum-time 1d'" + journalctl --vacuum-time 1d 2>&1 +} + +clean_ext_packages() +{ + local volume="$1" + local path="$PRODUCT_ROOT_D/var/modules-packages" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'rm -rf $path/*'" + rm -rf "$path"/* 2>&1 +} + +# @param $1 target directory +mount_point() +{ + df -Pm $1 | awk 'NR==2 { print $6 }' +} + +# @param $1 target directory +available_disk_space() +{ + df -Pm $1 | awk 'NR==2 { print $4 }' +} + +is_path_on_volume() +{ + local path="$1" + local volume="$2" + [ -d "$path" ] && [ "`mount_point "$path"`" = "$volume" ] +} + +# @param $1 target directory +# @param $2 mode (install/upgrade/update) +req_disk_space() +{ + if [ "$2" != "install" ]; then + required_update_upgrade_disk_space "$1" + return + fi + + has_os_impl_function "required_disk_space" || { + echo "There are no requirements defined for $os_name$os_version." >&2 + echo "Disk space check cannot be performed." >&2 + exit $RET_WARN + } + call_os_impl_function "required_disk_space" "$1" +} + +human_readable_size() +{ + echo "$1" | awk ' + function human(x) { + s = "MGTEPYZ"; + while (x >= 1000 && length(s) > 1) { + x /= 1024; s = substr(s, 2); + } + # 0.05 below will make sure the value is rounded up + return sprintf("%.1f %sB", x + 0.05, substr(s, 1, 1)); + } + { print human($1); }' +} + +# @param $1 target directory +# @param $2 required disk space +# @param $3 check only flag (don't emit errors) +check_available_disk_space() +{ + local volume="$1" + local required="$2" + local check_only="${3:-}" + local available="$(available_disk_space "$volume")" + if [ "$available" -lt "$required" ]; then + local needtofree + needtofree="`human_readable_size $((required - available))`" + [ -n "$check_only" ] || + make_error_report 'stage=diskspacecheck' 'level=error' 'errtype=notenoughdiskspace' \ + "volume=$volume" "required=$required MB" "available=$available MB" "needtofree=$needtofree" \ + <<-EOL + There is not enough disk space available in the $1 directory. + You need to free up $needtofree. + EOL + return "$RET_FATAL" + fi +} + +# @param $1 target directory +# @param $2 required disk space +clean_and_check_available_disk_space() +{ + if [ -n "$PLESK_INSTALLER_FORCE_CLEAN_DISK_SPACE" ] || ! check_available_disk_space "$@" --check-only; then + clean_disk_space "$1" + check_available_disk_space "$@" + fi +} + +# Cleans up disk space on the volume +clean_disk_space() +{ + local volume="$1" + for cleanup_func in clean_tmp clean_yum clean_dnf clean_apt clean_journal clean_ext_packages; do + "$cleanup_func" "$volume" + done +} + +# @param $1 mode (install/upgrade/update) +clean_and_check_disk_space() +{ + local mode="$1" + local shared=0 + + for target_directory in /opt /usr /var /tmp; do + local required=$(req_disk_space "$target_directory" "$mode") + [ -n "$required" ] || return "$RET_WARN" + + if is_path_on_volume "$target_directory" "/"; then + shared="$((shared + required))" + else + clean_and_check_available_disk_space "$target_directory" "$required" || return $? + fi + done + + clean_and_check_available_disk_space "/" "$shared" || return $? +} + +checker_main 'clean_and_check_disk_space' "$1" diff --git a/root/parallels/pool/PSA_18.0.73_17971/examiners/license_key_check.php b/root/parallels/pool/PSA_18.0.73_17971/examiners/license_key_check.php new file mode 100644 index 0000000000..917e44709f --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17971/examiners/license_key_check.php @@ -0,0 +1,111 @@ += 10.0.0 */ +if (!is_array($vers)) { + $vers = [$vers]; +} + +$match = false; +foreach ($vers as $ver) { + if (!is_array($ver)) { + $match |= strtok($ver, ".") == strtok($targetVersion, "."); + } else { + $match |= ("any" == $ver[0] || version_compare($ver[0], $targetVersion) <= 0) && + ("any" == $ver[1] || version_compare($ver[1], $targetVersion) >= 0); + } +} + +if ($match) { + fwrite(STDERR, "You do not need to upgrade the current license key.\n"); + fwrite(STDOUT, "License upgrade check to $targetVersion can be skipped.\n"); + fwrite(STDOUT, "Plesk versions compatible with the license key: " . preg_replace('/\n\s*/', '', var_export($vers, true)) . "\n"); + finish(0); +} + +if (!function_exists('ka_is_key_upgrade_available')) { + // Plesk 17.0 + fwrite(STDERR, "Cannot check whether Plesk license key upgrade is available.\n"); + finish(1, false); +} + +$si = getServerInfo(); +$result = ka_is_key_upgrade_available($prod, $targetVersion, $si); + +$isConfused = false; +switch ($result['code']) { + case RESULT_LICENSE_OK: + fwrite(STDERR, "The licensing server accepted the key upgrade request.\n"); + fwrite(STDERR, "License upgrade to $targetVersion is available.\n"); + fwrite(STDERR, "Response from the licensing server: {$result['message']}\n"); + finish(0); + case RESULT_NETWORK_PROBLEM: + fwrite(STDERR, "Unable to connect to the licensing server to check if license upgrade is available.\n"); + fwrite(STDERR, "Error message: {$result['message']}\n"); + finish(2, false); + case RESULT_LICENSE_PROBLEM: + fwrite(STDERR, "Warning: Your Plesk license key cannot be upgraded.\n"); + fwrite(STDERR, "Response from the licensing server: {$result['message']}\n"); + finish(2); + default: + $isConfused = true; + // fall-through + case RESULT_ERROR: + // This includes "Software Update Service (SUS) is not found for the given license key" case, but also many others. + fwrite(STDERR, "Failed to check whether a new license key is available.\n"); + fwrite(STDERR, "Error message: {$result['message']}\n"); + if ($isConfused) { + fwrite(STDERR, "Error code: {$result['code']}\n"); + } + finish(2, !$isConfused); +} diff --git a/root/parallels/pool/PSA_18.0.73_17971/examiners/package_manager_check.sh b/root/parallels/pool/PSA_18.0.73_17971/examiners/package_manager_check.sh new file mode 100755 index 0000000000..b089061d97 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17971/examiners/package_manager_check.sh @@ -0,0 +1,224 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ -z "$PLESK_INSTALLER_DEBUG" ] || set -x +[ -z "$PLESK_INSTALLER_STRICT_MODE" ] || set -e + +export LC_ALL=C +unset GREP_OPTIONS + +RET_SUCCESS=0 +RET_WARN=1 +RET_FATAL=2 + +is_function_defined() +{ + local fn="$1" + case "$(type $fn 2>/dev/null)" in + *function*) + return 0 + ;; + esac + return 1 +} + +# @params are tags in format "key=value" +# Report body (human readable information) is read from stdin +# and copied to stderr. +make_error_report() +{ + local report_file="${PLESK_INSTALLER_ERROR_REPORT:-}" + + local python_bin= + for bin in "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2" "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3"; do + if [ -x "$bin" ]; then + python_bin="$bin" + break + fi + done + + if [ -n "$report_file" -a -x "$python_bin" ]; then + "$python_bin" -c 'import sys, json +report_file = sys.argv[1] +error = sys.stdin.read() + +sys.stderr.write(error) + +data = { + "error": error, +} + +for tag in sys.argv[2:]: + k, v = tag.split("=", 1) + data[k] = v + +with open(report_file, "a") as f: + json.dump(data, f) + f.write("\n") +' "$report_file" "date=$(date --utc --iso-8601=ns)" "$@" + else + cat - >&2 + fi +} + +detect_platform() +{ + . /etc/os-release + os_name="$ID" + os_version="${VERSION_ID%%.*}" + os_arch="$(uname -m)" + if [ -e /etc/debian_version ]; then + case "$os_arch" in + x86_64) pkg_arch="amd64" ;; + aarch64) pkg_arch="arm64" ;; + esac + if [ -n "$VERSION_CODENAME" ]; then + os_codename="$VERSION_CODENAME" + else + case "$os_name$os_version" in + debian10) os_codename="buster" ;; + debian11) os_codename="bullseye" ;; + debian12) os_codename="bookworm" ;; + ubuntu18) os_codename="bionic" ;; + ubuntu20) os_codename="focal" ;; + ubuntu22) os_codename="jammy" ;; + ubuntu24) os_codename="noble" ;; + esac + fi + fi + + case "$os_name$os_version" in + rhel7|centos7|cloudlinux7|virtuozzo7) + package_manager="yum" + ;; + rhel*|centos*|cloudlinux*|almalinux*|rocky*) + package_manager="dnf" + ;; + debian*|ubuntu*) + package_manager="apt" + ;; + esac + + if [ "$os_name" = "ubuntu" -o "$os_name" = "debian" ]; then + PRODUCT_ROOT_D="/opt/psa" + else + PRODUCT_ROOT_D="/usr/local/psa" + fi +} + +has_os_impl_function() +{ + local prefix="$1" + local fn="${prefix}_${os_name}${os_version}" + is_function_defined "$fn" +} + +call_os_impl_function() +{ + local prefix="$1" + shift + local fn="${prefix}_${os_name}${os_version}" + "$fn" "$@" +} + +skip_checker_on_flag() +{ + local name="$1" + local flag="$2" + + if [ -f "$flag" ]; then + echo "$name was skipped due to flag file." >&2 + exit $RET_SUCCESS + fi +} + +skip_checker_on_env() +{ + local name="$1" + local env="$2" + + if [ -n "$env" ]; then + echo "$name was skipped due to environment variable." >&2 + exit $RET_SUCCESS + fi +} + +checker_main() +{ + local fnprefix="$1" + shift + + detect_platform + # try to execute checker only if all attributes are detected + [ -n "$os_name" -a -n "$os_version" ] || return $RET_SUCCESS + + for checker in "${fnprefix}_${os_name}${os_version}" "${fnprefix}_${os_name}" "${fnprefix}"; do + if is_function_defined "$checker"; then + local rc=$RET_SUCCESS + "$checker" "$@" || rc=$? + [ "$(( $rc & $RET_FATAL ))" = "0" ] || return $RET_FATAL + [ "$(( $rc & $RET_WARN ))" = "0" ] || return $RET_WARN + return $rc + fi + done + return $RET_SUCCESS +} + +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +check_package_manager_deb_based() +{ + local output= + output="`dpkg --audit 2>&1`" || output="$output"$'\n'"'dpkg --audit' finished with error code $?." + + if [ -n "$output" ]; then + make_error_report 'stage=packagemanagercheck' 'level=error' 'errtype=brokenpackages' <<-EOL + The system package manager reports the following problems: + + $output + + To continue with the installation, you need to resolve these issues + using the procedure below: + + 1. Make sure you have a full server snapshot. Although the + following steps are usually safe, they can still cause + data loss or irreversible changes. + 2. Run 'dpkg --configure -a'. This command can fix some of the + issues. However, it may fail. Regardless if it fails or not, + proceed with the following steps. + 3. Run 'PLESK_INSTALLER_SKIP_PACKAGE_MANAGER_CHECK=1 plesk installer update --skip-cleanup'. + Instead of 'update', you may need to use the command you used + previously (for example, 'upgrade' or 'install'). + 4. The next step depends on the outcome of the previous one: + - If step 3 was completed with the "You already have the latest + version of product(s) and all the selected components installed. + Installation will not continue." message, + run 'plesk repair installation'. + - If step 3 failed, run 'dpkg --audit'. This command can show you + packages that need to be reinstalled. To reinstall them, run + 'apt-get install --reinstall '. + 5. Run 'plesk installer update' to revert temporary changes and + validate that the issues are resolved. If the command fails or + triggers this check again, contact Plesk support. + + For more information, see + https://support.plesk.com/hc/en-us/articles/12871173047447-Plesk-update-on-Debian-Ubuntu-fails-dpkg-was-interrupted-you-must-manually-run-dpkg-configure-a-to-correct-the-problem + EOL + return "$RET_FATAL" + fi +} + +check_package_manager_debian() +{ + check_package_manager_deb_based +} + +check_package_manager_ubuntu() +{ + check_package_manager_deb_based +} + +skip_checker_on_env "Package manager check" "$PLESK_INSTALLER_SKIP_PACKAGE_MANAGER_CHECK" +skip_checker_on_flag "Package manager check" "/tmp/plesk-installer-skip-package-manager-check.flag" +checker_main 'check_package_manager' "$@" diff --git a/root/parallels/pool/PSA_18.0.73_17971/examiners/panel_preupgrade_checker.php b/root/parallels/pool/PSA_18.0.73_17971/examiners/panel_preupgrade_checker.php new file mode 100644 index 0000000000..181534e61e --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17971/examiners/panel_preupgrade_checker.php @@ -0,0 +1,2401 @@ +_checkMainIP(); //:INFO: Checking for main IP address https://support.plesk.com/hc/articles/12377857361687 + $this->_checkMySQLDatabaseUserRoot(); //:INFO: Plesk user "root" for MySQL database servers have not access to phpMyAdmin https://support.plesk.com/hc/articles/12378148229399 + $this->_checkProftpdIPv6(); //:INFO: #94489 FTP service proftpd cannot be started by xinetd if IPv6 is disabled https://support.plesk.com/hc/articles/12377796102807 + $this->_checkSwCollectdIntervalSetting(); //:INFO: #105405 https://support.plesk.com/hc/articles/213362569 + $this->_checkApacheStatus(); + $this->_checkImmutableBitOnPleskFiles(); //:INFO: #128414 https://support.plesk.com/hc/articles/12377589682327 + $this->_checkAbilityToChmodInDumpd(); //:INFO: ERROR while trying to backup MySQL database. https://support.plesk.com/hc/en-us/articles/12377010033943 + $this->_checkIpcollectionReference(); //:INFO: #72751 https://support.plesk.com/hc/articles/12377666752279 + $this->_checkApsApplicationContext(); //:INFO: Broken contexts of the APS applications can lead to errors at building Apache web server configuration https://support.plesk.com/hc/articles/12377671820311 + $this->_checkApsTablesInnoDB(); + $this->_checkCustomWebServerConfigTemplates(); //:INFO: #PPPM-1195 https://support.plesk.com/hc/articles/12377740416151 + $this->_checkMixedCaseDomainIssues(); //:INFO: #PPPM-4284 https://support.plesk.com/hc/en-us/articles/12377171904151 + + if (PleskOS::isDebLike()) { + $this->_checkSymLinkToOptPsa(); //:INFO: Check that symbolic link /usr/local/psa actually exists on Debian-like OSes https://support.plesk.com/hc/articles/12377511731991 + } + + if (Util::isVz()) { + $this->_checkShmPagesLimit(); //:INFO: PSA service does not start. Unable to allocate shared memory segment. https://support.plesk.com/hc/articles/12377744827927 + + if (PleskOS::isRedHatLike()) { + $this->_checkMailDriversConflict(); //:INFO: #PPPM-955 https://support.plesk.com/hc/articles/12378148767895 + } + } + } + + $this->_checkForCryptPasswords(); + $this->_checkMysqlServersTable(); //:INFO: Checking existing table mysql.servers + $this->_checkPleskTCPPorts(); //:INFO: Check the availability of Plesk TCP ports https://support.plesk.com/hc/articles/12377821243159 + + if (Util::isWindows()) { + $this->_checkPhprcSystemVariable(); //:INFO: #PPPM-294 Checking for PHPRC system variable + $this->_unknownISAPIfilters(); //:INFO: Checking for unknown ISAPI filters and show warning https://support.plesk.com/hc/articles/213913765 + $this->_checkMSVCR(); //:INFO: Just warning about possible issues related to Microsoft Visual C++ Redistributable Packages https://support.plesk.com/hc/articles/115000201014 + $this->_checkIisFcgiDllVersion(); //:INFO: Check iisfcgi.dll file version https://support.plesk.com/hc/articles/12378148258199 + $this->_checkCDONTSmailrootFolder(); //:INFO: After upgrade Plesk change permissions on folder of Collaboration Data Objects (CDO) for NTS (CDONTS) to default, https://support.plesk.com/hc/articles/12377887661335 + $this->_checkNullClientLogin(); //:INFO: #118963 https://support.plesk.com/hc/articles/12378122202391 + $this->checkDomainControllerLocation(); //:INFO: https://support.plesk.com/hc/articles/12377107094167 + } + } + + //:INFO: PSA service does not start. Unable to allocate shared memory segment. https://support.plesk.com/hc/articles/12377744827927 + function _checkShmPagesLimit() + { + $log = Log::getInstance("Checking for limit shmpages", true); + $ubc = Util::getUserBeanCounters(); + if ((int)$ubc['shmpages']['limit'] < 40960) { + $log->emergency("Virtuozzo Container set the \"shmpages\" limit to {$ubc['shmpages']['limit']}, which is too low. This may cause the sw-engine service not to start. To resolve this issue, refer to the article at https://support.plesk.com/hc/articles/12377744827927"); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: #PPPM-294 + function _checkPhprcSystemVariable() + { + $log = Log::getInstance("Checking for PHPRC system variable", true); + + $phprc = getenv('PHPRC'); + + if ($phprc) { + $log->emergency('The environment variable PHPRC is present in the system. This variable may lead to upgrade failure. Please delete this variable from the system environment.'); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: ERROR while trying to backup MySQL database. https://support.plesk.com/hc/en-us/articles/12377010033943 + function _checkAbilityToChmodInDumpd() + { + $log = Log::getInstance("Checking the possibility to change the permissions of files in the DUMP_D directory", true); + + $dump_d = Util::getSettingFromPsaConf('DUMP_D'); + if (is_null($dump_d)) { + $log->warning('Unable to obtain the path to the directory defined by the DUMP_D parameter. Check that the DUMP_D parameter is set in the /etc/psa/psa.conf file.'); + $log->resultWarning(); + return; + } + + $file = $dump_d . '/pre_upgrade_test_checkAbilityToChmodInDumpd'; + + if (false === file_put_contents($file, 'test')) { + $log->emergency('Unable to write in the ' . $dump_d . ' directory. The upgrade procedure will fail. Check that the folder exists and you have write permissions for it, and repeat upgrading. '); + $log->resultWarning(); + return; + } else { + $result = @chmod($file, 0600); + unlink($file); + if (!$result) { + $log->emergency( + 'Unable to change the permissions of files in the ' . $dump_d . ' directory. ' + . 'The upgrade procedure will fail. Please refer to https://support.plesk.com/hc/articles/12377010033943 for details.' + ); + $log->resultError(); + return; + } + } + $log->resultOk(); + } + + //:INFO: #128414 https://support.plesk.com/hc/articles/12377589682327 + function _checkImmutableBitOnPleskFiles() + { + $log = Log::getInstance("Checking Panel files for the immutable bit attribute"); + + $cmd = 'lsattr -R /usr/local/psa/ 2>/dev/null |awk \'{split($1, a, ""); if (a[5] == "i") {print;}}\''; + $output = Util::exec($cmd, $code); + $files = explode('\n', $output); + + if (!empty($output)) { + $log->info('The immutable bit attribute of the following Panel files can interrupt the upgrade procedure:'); + foreach ($files as $file) { + $log->info($file); + } + $log->emergency('Files with the immutable bit attribute were found. Please check https://support.plesk.com/hc/articles/12377589682327 for details.'); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: #PPPM-1195 https://support.plesk.com/hc/articles/12377740416151 + function _checkCustomWebServerConfigTemplates() + { + $log = Log::getInstance("Checking for custom web server configuration templates"); + $pleskDir = Util::getSettingFromPsaConf('PRODUCT_ROOT_D'); + $customTemplatesPath = $pleskDir . '/admin/conf/templates/custom'; + + if (is_dir($customTemplatesPath)) { + $log->warning("Directory {$customTemplatesPath} for custom web server configuration templates was found. Custom templates might be incompatible with a new Plesk version, and this might lead to failure to generate web server configuration files. Remove the directory to get rid of this warning. " + . "Please check https://support.plesk.com/hc/articles/12377740416151 for details."); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: #PPPM-955 https://support.plesk.com/hc/articles/12378148767895 + function _checkMailDriversConflict() + { + $log = Log::getInstance("Checking for a Plesk mail drivers conflict"); + + if (((true === PackageManager::isInstalled('psa-mail-pc-driver') || true === PackageManager::isInstalled('plesk-mail-pc-driver')) + && true === PackageManager::isInstalled('psa-qmail')) + || ((true === PackageManager::isInstalled('psa-mail-pc-driver') || true === PackageManager::isInstalled('plesk-mail-pc-driver')) + && true === PackageManager::isInstalled('psa-qmail-rblsmtpd'))) { + $log->warning("Plesk upgrade by EZ templates failed if psa-mail-pc-driver and psa-qmail or psa-qmail-rblsmtpd packages are installed. " + . "Please check https://support.plesk.com/hc/articles/12378148767895 for details."); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: #118963 https://support.plesk.com/hc/articles/12378122202391 + function _checkNullClientLogin() + { + $log = Log::getInstance("Checking for accounts with empty user names"); + + $mysql = PleskDb::getInstance(); + $sql = "SELECT domains.id, domains.name, clients.login FROM domains LEFT JOIN clients ON clients.id=domains.cl_id WHERE clients.login is NULL"; + $nullLogins = $mysql->fetchAll($sql); + + if (!empty($nullLogins)) { + $log->warning('There are accounts with empty user names. This problem can cause the backup or migration operation to fail. Please see https://support.plesk.com/hc/articles/12378122202391 for the solution.'); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: #105405 https://support.plesk.com/hc/articles/213362569 + function _checkSwCollectdIntervalSetting() + { + $log = Log::getInstance("Checking the 'Interval' parameter in the sw-collectd configuration file"); + + $collectd_config = '/etc/sw-collectd/collectd.conf'; + if (file_exists($collectd_config)) { + if (!is_file($collectd_config) || !is_readable($collectd_config)) + return; + + $config_content = Util::readfileToArray($collectd_config); + if ($config_content) { + foreach ($config_content as $line) { + if (preg_match('/Interval\s*\d+$/', $line, $match)) { + if (preg_match('/Interval\s*10$/', $line, $match)) { + $log->warning('If you leave the default value of the "Interval" parameter in the ' . $collectd_config . ', sw-collectd may heavily load the system. Please see https://support.plesk.com/hc/articles/213362569 for details.'); + $log->resultWarning(); + return; + } + $log->resultOk(); + return; + } + } + $log->warning('If you leave the default value of the "Interval" parameter in the ' . $collectd_config . ', sw-collectd may heavily load the system. Please see https://support.plesk.com/hc/articles/213362569 for details.'); + $log->resultWarning(); + return; + } + } + } + + private function _checkApacheStatus() + { + $log = Log::getInstance("Checking Apache status"); + + $apacheCtl = file_exists('/usr/sbin/apache2ctl') ? '/usr/sbin/apache2ctl' : '/usr/sbin/apachectl'; + + if (!is_executable($apacheCtl)) { + return; + } + + $resultCode = 0; + Util::Exec("$apacheCtl -t 2>/dev/null", $resultCode); + + if (0 !== $resultCode) { + $log->error("The Apache configuration is broken. Run '$apacheCtl -t' to see the detailed info."); + $log->resultError(); + return; + } + + $log->resultOk(); + } + + //:INFO: #72751 https://support.plesk.com/hc/articles/12377666752279 + function _checkIpcollectionReference() + { + $log = Log::getInstance("Checking consistency of the IP addresses list in the Panel database"); + + $mysql = PleskDb::getInstance(); + $sql = "SELECT 1 FROM ip_pool, clients, IpAddressesCollections, domains, DomainServices, IP_Addresses WHERE DomainServices.ipCollectionId = IpAddressesCollections.ipCollectionId AND domains.id=DomainServices.dom_id AND clients.id=domains.cl_id AND ipAddressId NOT IN (select id from IP_Addresses) AND IP_Addresses.id = ip_pool.ip_address_id AND pool_id = ip_pool.id GROUP BY pool_id"; + $brokenIps = $mysql->fetchAll($sql); + $sql = "select 1 from DomainServices, domains, clients, ip_pool where ipCollectionId not in (select IpAddressesCollections.ipCollectionId from IpAddressesCollections) and domains.id=DomainServices.dom_id and clients.id = domains.cl_id and ip_pool.id = clients.pool_id and DomainServices.type='web' group by ipCollectionId"; + $brokenCollections = $mysql->fetchAll($sql); + + if (!empty($brokenIps) || !empty($brokenCollections)) { + $log->warning('Some database entries related to Panel IP addresses are corrupted. Please see https://support.plesk.com/hc/articles/12377666752279 for the solution.'); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: Broken contexts of the APS applications can lead to errors at building Apache web server configuration https://support.plesk.com/hc/articles/12377671820311 + function _checkApsApplicationContext() + { + $log = Log::getInstance("Checking installed APS applications"); + $mysql = PleskDb::getInstance(); + $sql = "SELECT * FROM apsContexts WHERE (pleskType = 'hosting' OR pleskType = 'subdomain') AND subscriptionId = 0"; + $brokenContexts = $mysql->fetchAll($sql); + + if (!empty($brokenContexts)) { + $log->warning('Some database entries related to the installed APS applications are corrupted. Please see https://support.plesk.com/hc/articles/12377671820311 for the solution.'); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: #94489 FTP service proftpd cannot be started by xinetd if IPv6 is disabled https://support.plesk.com/hc/articles/12377796102807 + function _checkProftpdIPv6() + { + $log = Log::getInstance("Checking proftpd settings"); + + $inet6 = '/proc/net/if_inet6'; + if (!file_exists($inet6) || !@file_get_contents($inet6)) { + $proftpd_config = '/etc/xinetd.d/ftp_psa'; + if (!is_file($proftpd_config) || !is_readable($proftpd_config)) + return null; + + $config_content = Util::readfileToArray($proftpd_config); + if ($config_content) { + for ($i=0; $i<=count($config_content)-1; $i++) { + if (preg_match('/flags.+IPv6$/', $config_content[$i], $match)) { + $log->warning('The proftpd FTP service will fail to start in case the support for IPv6 is disabled on the server. Please check https://support.plesk.com/hc/articles/12377796102807 for details.'); + $log->resultWarning(); + return; + } + } + } + } + $log->resultOk(); + } + + //:INFO: Check the availability of Plesk Panel TCP ports + function _checkPleskTCPPorts() + { + $log = Log::getInstance('Checking the availability of Plesk Panel TCP ports'); + + $plesk_ports = array('8880' => 'Plesk Panel non-secure HTTP port', '8443' => 'Plesk Panel secure HTTPS port'); + + $mysql = PleskDb::getInstance(); + $sql = "select ip_address from IP_Addresses"; + $ip_addresses = $mysql->fetchAll($sql); + $warning = false; + if (count($ip_addresses)>0) { + if (Util::isLinux()) { + $ipv4 = Util::getIPv4ListOnLinux(); + $ipv6 = Util::getIPv6ListOnLinux(); + if ($ipv6) { + $ipsInSystem = array_merge($ipv4, $ipv6); + } else { + $ipsInSystem = $ipv4; + } + } else { + $ipsInSystem = Util::getIPListOnWindows(); + } + foreach ($ip_addresses as $ip) { + foreach ($plesk_ports as $port => $description) { + if (PleskValidator::validateIPv4($ip['ip_address']) && in_array($ip['ip_address'], $ipsInSystem)) { + $fp = @fsockopen($ip['ip_address'], $port, $errno, $errstr, 1); + } elseif (PleskValidator::validateIPv6($ip['ip_address']) && in_array($ip['ip_address'], $ipsInSystem)) { + $fp = @fsockopen('[' . $ip['ip_address'] . ']', $port, $errno, $errstr, 1); + } else { + $log->warning('IP address registered in Plesk is invalid or broken: ' . $ip['ip_address']); + $log->resultWarning(); + return; + } + if (!$fp) { + // $errno 110 means "timed out", 111 means "refused" + $log->info('Unable to connect to IP address ' . $ip['ip_address'] . ' on ' . $description . ' ' . $port . ': ' . $errstr); + $warning = true; + } + } + } + } + if ($warning) { + $log->warning('Unable to connect to some Plesk ports. Please see ' . LOG_PATH . ' for details. Find the full list of the required open ports at https://support.plesk.com/hc/articles/12377821243159 '); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: Plesk user "root" for MySQL database servers have not access to phpMyAdmin https://support.plesk.com/hc/articles/12378148229399 + function _checkMySQLDatabaseUserRoot() + { + $log = Log::getInstance('Checking existence of Plesk user "root" for MariaDB/MySQL database servers'); + + $psaroot = Util::getSettingFromPsaConf('PRODUCT_ROOT_D'); + + if (PleskVersion::is_below_17_9()) { + $phpMyAdminConfFile = $psaroot . '/admin/htdocs/domains/databases/phpMyAdmin/libraries/config.default.php'; + } else { + $phpMyAdminConfFile = $psaroot . '/phpMyAdmin/libraries/config.default.php'; + } + + if (file_exists($phpMyAdminConfFile)) { + $phpMyAdminConfFileContent = file_get_contents($phpMyAdminConfFile); + if (!preg_match("/\[\'AllowRoot\'\]\s*=\s*true\s*\;/", $phpMyAdminConfFileContent)) { + $mysql = PleskDb::getInstance(); + $sql = "select login, data_bases.name as db_name, displayName as domain_name from db_users, data_bases, domains where db_users.db_id = data_bases.id and data_bases.dom_id = domains.id and data_bases.type = 'mysql' and login = 'root'"; + $dbusers = $mysql->fetchAll($sql); + + foreach ($dbusers as $user) { + $log->warning('The database user "' . $user['login'] . '" (database "' . $user['db_name'] . '" at "' . $user['domain_name'] . '") has no access to phpMyAdmin. Please check https://support.plesk.com/hc/articles/12378148229399 for more details.'); + $log->resultWarning(); + return; + } + } + } + + $log->resultOk(); + } + + //:INFO: After upgrade Plesk change permissions on folder of Collaboration Data Objects (CDO) for NTS (CDONTS) to default, https://support.plesk.com/hc/articles/12377887661335 + function _checkCDONTSmailrootFolder() + { + $log = Log::getInstance('Checking for CDONTS mailroot folder'); + + $mailroot = Util::getSystemDisk() . 'inetpub\mailroot\pickup'; + + if (is_dir($mailroot)) { + $log->warning('After upgrade you have to add write permissions to psacln group on folder ' . $mailroot . '. Please, check https://support.plesk.com/hc/articles/12377887661335 for more details.'); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: Check iisfcgi.dll file version https://support.plesk.com/hc/articles/12378148258199 + function _checkIisFcgiDllVersion() + { + $log = Log::getInstance("Checking the iisfcgi.dll file version"); + + $windir = Util::getSystemRoot(); + $iisfcgi = $windir . '\system32\inetsrv\iisfcgi.dll'; + if (file_exists($iisfcgi)) { + $version = Util::getFileVersion($iisfcgi); + if (version_compare($version, '7.5.0', '>') + && version_compare($version, '7.5.7600.16632', '<')) { + $log->warning('File iisfcgi.dll version ' . $version . ' is outdated. Please, check article https://support.plesk.com/hc/articles/12378148258199 for details'); + return; + } + } + $log->resultOk(); + } + + //:INFO: Checking for main IP address https://support.plesk.com/hc/articles/12377857361687 + function _checkMainIP() + { + $log = Log::getInstance("Checking for main IP address"); + + $mysql = PleskDb::getInstance(); + $sql = 'select * from IP_Addresses'; + $ips = $mysql->fetchAll($sql); + $mainexists = false; + foreach ($ips as $ip) { + if (isset($ip['main'])) { + if ($ip['main'] == 'true') { + $mainexists = true; + } + } else { + $log->info('No field "main" in table IP_Addresses.'); + $log->resultOk(); + return; + } + } + + if (!$mainexists) { + $warn = 'Unable to find "main" IP address in psa database. Please, check https://support.plesk.com/hc/articles/12377857361687 for more details.'; + $log->warning($warn); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: Checking existing table mysql.servers https://support.plesk.com/hc/articles/12377850098455 + function _checkMysqlServersTable() + { + $log = Log::getInstance('Checking table "servers" in database "mysql"'); + + $mySQLServerVersion = Util::getMySQLServerVersion(); + if (version_compare($mySQLServerVersion, '5.1.0', '>=')) { + $credentials = Util::getDefaultClientMySQLServerCredentials(); + + if (preg_match('/AES-128-CBC/', $credentials['admin_password'])) { + $log->info('The administrator\'s password for the default MariaDB/MySQL server is encrypted.'); + return; + } + + $mysql = new DbClientMysql($credentials['host'], $credentials['admin_login'], $credentials['admin_password'] , 'information_schema', $credentials['port']); + if (!$mysql->hasErrors()) { + $sql = 'SELECT * FROM information_schema.TABLES WHERE TABLE_SCHEMA="mysql" and TABLE_NAME="servers"'; + $servers = $mysql->fetchAll($sql); + if (empty($servers)) { + $warn = 'The table "servers" in the database "mysql" does not exist. Please check https://support.plesk.com/hc/articles/12377850098455 for details.'; + $log->warning($warn); + $log->resultWarning(); + return; + } + } + } + $log->resultOk(); + } + + //:INFO: Check that there is symbolic link /usr/local/psa on /opt/psa on Debian-like Oses https://support.plesk.com/hc/articles/12377511731991 + function _checkSymLinkToOptPsa() + { + $log = Log::getInstance('Checking symbolic link /usr/local/psa on /opt/psa'); + + $link = @realpath('/usr/local/psa/version'); + if (!preg_match('/\/opt\/psa\/version/', $link, $macthes)) { + $warn = "The symbolic link /usr/local/psa does not exist or has wrong destination. Read article https://support.plesk.com/hc/articles/12377511731991 to fix the issue."; + $log->warning($warn); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: Checking for unknown ISAPI filters and show warning https://support.plesk.com/hc/articles/213913765 + function _unknownISAPIfilters() + { + $log = Log::getInstance('Detecting installed ISAPI filters'); + + if (Util::isUnknownISAPIfilters()) { + $warn = 'Please read carefully article https://support.plesk.com/hc/articles/213913765, for avoiding possible problems caused by unknown ISAPI filters.'; + $log->warning($warn); + $log->resultWarning(); + + return; + } + $log->resultOk(); + } + + //:INFO: Warning about possible issues related to Microsoft Visual C++ Redistributable Packages ?https://support.plesk.com/hc/articles/115000201014 + function _checkMSVCR() + { + $log = Log::getInstance('Microsoft Visual C++ Redistributable Packages'); + + $warn = 'Please read carefully article https://support.plesk.com/hc/articles/115000201014, for avoiding possible problems caused by Microsoft Visual C++ Redistributable Packages.'; + $log->info($warn); + + return; + } + + function _checkForCryptPasswords() + { + //:INFO: Prevent potential problem with E: Couldn't configure pre-depend plesk-core for psa-firewall, probably a dependency cycle. + $log = Log::getInstance('Detecting if encrypted passwords are used'); + + $db = PleskDb::getInstance(); + $sql = "SELECT COUNT(*) AS cnt FROM accounts WHERE type='crypt' AND password not like '$%';"; + $r = $db->fetchAll($sql); + + if ($r[0]['cnt'] != '0') + { + $warn = 'There are ' . $r[0]['cnt'] . ' accounts with passwords encrypted using a deprecated algorithm. Please refer to https://support.plesk.com/hc/articles/12377596588311 for the instructions about how to change the password type to plain.'; + + $log->warning($warn); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + function _checkApsTablesInnoDB() + { + $log = Log::getInstance('Checking if apsc database tables have InnoDB engine'); + + $db = PleskDb::getInstance(); + $apsDatabase = $db->fetchOne("select val from misc where param = 'aps_database'"); + $sql = "SELECT TABLE_NAME FROM information_schema.TABLES where TABLE_SCHEMA = '$apsDatabase' and ENGINE = 'MyISAM'"; + $myISAMTables = $db->fetchAll($sql); + if (!empty($myISAMTables)) { + $myISAMTablesList = implode(', ', array_map('reset', $myISAMTables)); + $warn = 'The are tables in apsc database with MyISAM engine: ' . $myISAMTablesList . '. It would be updated to InnoDB engine.'; + $log->warning($warn); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + function _checkMixedCaseDomainIssues() + { + $log = Log::getInstance("Checking for domains with mixed case names", true); + $db = PleskDb::getInstance(); + + + $domains = $db->fetchAll("select id, name, displayName from domains"); + $problemDomains = array(); + foreach ($domains as $domain) { + if (strtolower($domain['name']) == $domain['name']) { + continue; + } + $problemDomains[] = $domain; + } + if (count($problemDomains)) { + $msg = "Found one or more domains with mixed case names. Such domains may have trouble working with the \"FPM application server by Apache\" handler.\n" . + implode("\n", array_map(function($row) { + return "{$row['id']}\t{$row['displayName']}\t{$row['name']}"; + }, $problemDomains)) . "\n" . + "A manual fix can be applied to resolve the issue. Read https://support.plesk.com/hc/en-us/articles/12377171904151 for details."; + $log->warning($msg); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + private function checkDomainControllerLocation() + { + $log = Log::getInstance("Checking for Active Directory Domain Controller and Plesk on the same server", true); + $cmd = '"' . rtrim(Util::getPleskRootPath(), '\\') . '\admin\bin\serverconf.exe" --list'; + $output = Util::exec($cmd, $code); + if (preg_match("/IS_DOMAIN_CONTROLLER:\s*true/", $output)) { + $log->warning('Active Directory Domain Controller and Plesk are on the same server. Read https://support.plesk.com/hc/articles/12377107094167 for details.'); + $log->resultWarning(); + } else { + $log->resultOk(); + } + } +} + +class Plesk175Requirements +{ + public function validate() + { + if (PleskInstallation::isInstalled() && PleskVersion::is_below_17_5() && Util::isLinux()) { + //:INFO: Check that DUMP_TMP_D is not inside of (or equal to) DUMP_D + $this->_checkDumpTmpD(); + } + } + + public function _checkDumpTmpD() + { + $log = Log::getInstance('Checking the DUMP_TMP_D directory'); + + $dumpD = Util::getSettingFromPsaConf('DUMP_D'); + if (is_null($dumpD)) { + $log->warning('Unable to obtain the path to the directory defined by the DUMP_D parameter. Check that the DUMP_D parameter is set in the /etc/psa/psa.conf file.'); + $log->resultWarning(); + return; + } + $dumpTmpD = Util::getSettingFromPsaConf('DUMP_TMP_D'); + if (is_null($dumpTmpD)) { + $log->warning('Unable to obtain the path to the directory defined by the DUMP_TMP_D parameter. Check that the DUMP_TMP_D parameter is set in the /etc/psa/psa.conf file.'); + $log->resultWarning(); + return; + } + + if (strpos(rtrim($dumpTmpD, '/') . '/', rtrim($dumpD, '/') . '/') === 0) { + $log->error(sprintf('The directory DUMP_TMP_D = %s should not be inside of (or equal to) the directory DUMP_D = %s. Fix these parameters in the /etc/psa/psa.conf file.', $dumpTmpD, $dumpD)); + $log->resultError(); + } + + $log->resultOk(); + } +} + +class Plesk178Requirements +{ + public function validate() + { + if (PleskInstallation::isInstalled() && Util::isWindows() && PleskVersion::is_below_17_9()) { + $this->_checkPleskVhostsDir(); + } + + if (PleskVersion::is_below_17_8()) { + $this->checkTomcat(); + $this->checkMultiServer(); + } + } + + private function checkTomcat() + { + if (Util::isWindows()) { + $tomcatRegBase = '\\PLESK\\PSA Config\\Config\\Packages\\tomcat\\tomcat'; + /* Supported versions on windows are tomcat5 and tomcat7 */ + $key = '/v InstallDir'; + $isInstalled = Util::regQuery($tomcatRegBase . '7', $key, true) || Util::regQuery($tomcatRegBase . '5', $key, true); + } else { + $isInstalled = PackageManager::isInstalled('psa-tomcat-configurator'); + } + + if ($isInstalled + || (PleskDb::getInstance()->fetchOne('show tables like \'WebApps\'') + && PleskDb::getInstance()->fetchOne('select count(*) from WebApps')) + ) { + $log = Log::getInstance('Checking Apache Tomcat installation'); + $message = <<warning($message); + } + } + + private function checkMultiServer() + { + if (!PleskModule::isMultiServer()) { + return; + } + + $log = Log::getInstance('Checking Plesk Multi Server installation'); + $message = <<emergency($message); + $log->resultError(); + } + + private function _checkPleskVhostsDir() + { + $log = Log::getInstance('Checking mount volume for HTTPD_VHOSTS_D directory'); + + $vhostsDir = rtrim(Util::regPleskQuery('HTTPD_VHOSTS_D'), "\\"); + Util::exec("mountvol \"{$vhostsDir}\" /L", $code); + if ($code == 0) { + $msg = "A disk volume is mounted to the {$vhostsDir} directory." . + " It will be unmounted during the Plesk upgrade." . + " As a result, all hosted websites will become unavailable." . + " Make sure to remount the volume to the {$vhostsDir} directory after the upgrade."; + $log->emergency($msg); + $log->resultError(); + return; + } + + $log->resultOk(); + } +} + +class Plesk18Requirements +{ + public function validate() + { + if (PleskInstallation::isInstalled()) { + if (Util::isLinux() && PleskOS::isRedHatLike()) { + $this->_checkYumDuplicates(); + } + $this->checkPdUsersLoginCollation(); + $this->checkDomainsGuidCollation(); + $this->checkClientsGuidCollation(); + $this->checkModSecurityModules(); + $this->checkIsFirewallPackageConfigured(); + $this->checkDefaultDnsServerComponent(); + } + } + + private function checkModSecurityModules() + { + /* Issue actual for Plesk for Windows below 18.0.32 (ModSecurity 2.9.3 and below) */ + if (!Util::isWindows() || PleskVersion::is_18_0_32_or_above()) { + return; + } + + $log = Log::getInstance('Checking the status of ModSecurity IIS modules'); + $modules = Util::exec(Util::getSystemRoot() . '\system32\inetsrv\AppCmd.exe list module', $code); + if ($code) { + $log->warning('Unable to get the list of IIS modules.'); + } else { + if (strpos($modules, 'ModSecurity IIS (32bits)') === false && strpos($modules, 'ModSecurity IIS (64bits)') === false) { + $log->error('Either 32-bit or 64-bit ModSecurity IIS module is absent.'); + $log->resultError(); + } + } + } + + // INFO: PPP-46440 checking package duplicates https://support.plesk.com/hc/articles/12377586286615 + private function _checkYumDuplicates() + { + $log = Log::getInstance('Checking for RPM packages duplicates'); + if (!file_exists("/usr/bin/package-cleanup")) + { + $log->info("package-cleanup is not found. Check for duplicates was skipped"); + return; + } + + $output = Util::exec("/usr/bin/package-cleanup --cacheonly -q --dupes", $code); + if ($code != 0) + { + // some repos may have no cache at this point or may be broken at all + // retry with cache recreation and skipping broken repos + $output = Util::exec("/usr/bin/package-cleanup -q --dupes --setopt='*.skip_if_unavailable=1'", $code); + } + if ($code != 0) + { + $message = "Unable to detect package duplicates: /usr/bin/package-cleanup --dupes returns $code." . + "Output is:\n$output"; + $log->warning($message); + $log->resultWarning(); + return; + } + + if (empty($output)) { + return; + } + + $message = "Your package system contains duplicated packages, which can lead to broken Plesk update:\n\n" . + "$output\n\n" . + "Please check https://support.plesk.com/hc/articles/12377586286615 for more details."; + + $log->error($message); + $log->resultError(); + } + + private function checkPdUsersLoginCollation() + { + $log = Log::getInstance('Checking for Protected Directory Users with duplicates in login field.'); + $duplicates = PleskDb::getInstance()->fetchAll( + 'SELECT pd_id, LOWER(login) AS login_ci, COUNT(*) AS duplicates FROM pd_users' . + ' GROUP BY pd_id, login_ci' . + ' HAVING duplicates > 1' + ); + if (!empty($duplicates)) { + $log->error( + "Duplicate logins of Protected Directory Users were found in the database:\n\n" . + implode("\n", array_column($duplicates, 'login_ci')) . "\n\n" . + "Please check https://support.plesk.com/hc/en-us/articles/360014743900 for more details." + ); + $log->resultError(); + } + } + + private function checkDomainsGuidCollation() + { + $log = Log::getInstance('Checking "domains" table with duplicates in guid field.'); + $duplicates = PleskDb::getInstance()->fetchAll( + 'SELECT guid, COUNT(*) AS duplicates FROM domains' + . ' GROUP BY guid' + . ' HAVING duplicates > 1' + ); + + if (!empty($duplicates)) { + $log->error( + "Duplicate guid were found in the 'domains' table:\n\n" . + implode("\n", array_column($duplicates, 'guid')) . "\n\n" + . "Please check https://support.plesk.com/hc/en-us/articles/12377018323351 for more details." + ); + $log->resultError(); + } + } + + private function checkClientsGuidCollation() + { + $log = Log::getInstance('Checking "clients" table with duplicates in guid field.'); + $duplicates = PleskDb::getInstance()->fetchAll( + 'SELECT guid, COUNT(*) AS duplicates FROM clients' + . ' GROUP BY guid' + . ' HAVING duplicates > 1' + ); + + if (!empty($duplicates)) { + $log->error( + "Duplicate guid were found in the 'clients' table:\n\n" . + implode("\n", array_column($duplicates, 'guid')) . "\n\n" + . "Please check https://support.plesk.com/hc/en-us/articles/360016801679 for more details." + ); + $log->resultError(); + } + } + + private function checkIsFirewallPackageConfigured() + { + if (!Util::isLinux()) { + return; + } + + $log = Log::getInstance("Checking if any rules are configured in the Firewall extension"); + $db = PleskDb::getInstance(); + if ($db->fetchOne("SHOW TABLES LIKE 'module_firewall_rules'") + && $db->fetchOne("SELECT COUNT(*) FROM module_firewall_rules") + ) { + $message = "Plesk Firewall no longer stores its configuration in Plesk database since " + . "Plesk Obsidian 18.0.52. Since you're upgrading to the latest version late, " + . "if you wish to retain the Plesk Firewall extension and its configuration, " + . "you need to follow additional steps after the upgrade. Please check " + . "https://support.plesk.com/hc/en-us/articles/16198248236311 for more details."; + $log->warning($message); + } + } + + private function checkDefaultDnsServerComponent() + { + if (Util::isLinux()) { + return; + } + + $path = '\\PLESK\\PSA Config\\Config\\Packages\\dnsserver'; + $key = '/ve'; + + if ('bind' === Util::regQuery($path, $key, true)) { + $log = Log::getInstance("Checking default DNS server component"); + $message = <<emergency($message); + $log->resultError(); + } + } +} + +class PleskModule +{ + public static function isInstalledWatchdog() + { + return PleskModule::_isInstalled('watchdog'); + } + + public static function isInstalledFileServer() + { + return PleskModule::_isInstalled('fileserver'); + } + + public static function isInstalledFirewall() + { + return PleskModule::_isInstalled('firewall'); + } + + public static function isInstalledVpn() + { + return PleskModule::_isInstalled('vpn'); + } + + public static function isMultiServer() + { + return PleskModule::_isInstalled('plesk-multi-server') || + PleskModule::_isInstalled('plesk-multi-server-node'); + } + + protected static function _isInstalled($module) + { + $sql = "SELECT * FROM Modules WHERE name = '{$module}'"; + + $pleskDb = PleskDb::getInstance(); + $row = $pleskDb->fetchRow($sql); + + return (empty($row) ? false : true); + } +} + +class PleskInstallation +{ + public static function validate() + { + if (!self::isInstalled()) { + $log = Log::getInstance('Checking for Plesk installation'); + $log->step('Plesk installation is not found. You will have no problems with upgrade, go on and install ' + . PleskVersion::getLatestPleskVersionAsString() . ' (https://www.plesk.com/)'); + return; + } + self::detectVersion(); + } + + public static function isInstalled() + { + $rootPath = Util::getPleskRootPath(); + if (empty($rootPath) || !file_exists($rootPath)) { + return false; + } + return true; + } + + private static function detectVersion() + { + $log = Log::getInstance('Installed Plesk version/build: ' . PleskVersion::getVersionAndBuild(), false); + + $currentVersion = PleskVersion::getVersion(); + if (version_compare($currentVersion, PLESK_VERSION, 'eq')) { + $err = 'You have already installed the latest version ' . PleskVersion::getLatestPleskVersionAsString() . '. '; + $err .= 'Tool must be launched prior to upgrade to ' . PleskVersion::getLatestPleskVersionAsString() . ' for the purpose of getting a report on potential problems with the upgrade.'; + $log->info($err); + exit(0); + } + + if (!PleskVersion::isUpgradeSupportedVersion()) { + $err = 'Unable to find Plesk 17.x. '; + $err .= 'Tool must be launched prior to upgrade to ' . PleskVersion::getLatestPleskVersionAsString() . ' for the purpose of getting a report on potential problems with the upgrade.'; + fatal($err); + } + } +} + +class PleskVersion +{ + const PLESK_17_MIN_VERSION = '13.0.0'; /* historically it has been started as 13.0 */ + + const PLESK_17_MAX_VERSION = '17.9.13'; + + const PLESK_18_MIN_VERSION = '18.0.14'; + + public static function is17x_or_above() + { + return version_compare(self::getVersion(), self::PLESK_17_MIN_VERSION, '>='); + } + + public static function is_below_17_5() + { + return version_compare(self::getVersion(), '17.5.0', '<'); + } + + public static function is_below_17_8() + { + return version_compare(self::getVersion(), '17.8.0', '<'); + } + + public static function is_below_17_9() + { + return version_compare(self::getVersion(), '17.9.0', '<'); + } + + public static function is_18_0_32_or_above() + { + return version_compare(self::getVersion(), '18.0.32', '>='); + } + + public static function getVersion() + { + $version = self::getVersionAndBuild(); + if (!preg_match('/([0-9]+[.][0-9]+[.][0-9]+)/', $version, $matches)) { + fatal("Incorrect Plesk version format. Current version: {$version}"); + } + return $matches[1]; + } + + public static function getVersionAndBuild() + { + $versionPath = Util::getPleskRootPath().'/version'; + if (!file_exists($versionPath)) { + fatal("Plesk version file is not exists $versionPath"); + } + $version = file_get_contents($versionPath); + $version = trim($version); + return $version; + } + + public static function getLatestPleskVersionAsString() + { + return 'Plesk ' . PLESK_VERSION; + } + + public static function isUpgradeSupportedVersion() + { + return self::is17x_or_above(); + } +} + +class Log +{ + private $errors; + private $warnings; + private $emergency; + private $logfile; + private $step; + private $step_header; + + /** @var array */ + private $errorsContent = []; + + /** @var array */ + private $warningsContent = []; + + public static function getInstance($step_msg = '', $step_number = true) + { + static $_instance = null; + if (is_null($_instance)) { + $_instance = new Log(); + } + if ($step_msg) { + $_instance->step($step_msg, $step_number); + } + + return $_instance; + } + + private function __construct() + { + $this->log_init(); + @unlink($this->logfile); + } + + private function log_init() + { + $this->step = 0; + $this->errors = 0; + $this->warnings = 0; + $this->emergency = 0; + $this->logfile = LOG_PATH; + $this->step_header = "Unknown step is running"; + } + + public function getErrors() + { + return $this->errors; + } + + public function getWarnings() + { + return $this->warnings; + } + + public function getEmergency() + { + return $this->emergency; + } + + public function fatal($msg) + { + $this->errors++; + + $this->errorsContent[] = $msg; + $content = $this->get_log_string($msg, 'FATAL_ERROR'); + fwrite(STDERR, $content); + $this->write($content); + } + + public function error($msg) + { + $this->errors++; + + $this->errorsContent[] = $msg; + $content = $this->get_log_string($msg, 'ERROR'); + fwrite(STDERR, $content); + $this->write($content); + } + + public function warning($msg) + { + $this->warnings++; + + $this->warningsContent[] = $msg; + $content = $this->get_log_string($msg, 'WARNING'); + fwrite(STDERR, $content); + $this->write($content); + } + + public function emergency($msg) + { + $this->emergency++; + + $this->errorsContent[] = $msg; + $content = $this->get_log_string($msg, 'EMERGENCY'); + fwrite(STDERR, $content); + $this->write($content); + } + + public function step($msg, $useNumber=false) + { + $this->step_header = $msg; + + echo PHP_EOL; + $this->write(PHP_EOL); + + if ($useNumber) { + $msg = "STEP " . $this->step . ": {$msg}..."; + $this->step++; + } else { + $msg = "{$msg}..."; + } + + $this->info($msg); + } + + public function resultOk() + { + $this->info('Result: OK'); + } + + public function resultWarning() + { + $this->info('Result: WARNING'); + } + + public function resultError() + { + $this->info('Result: ERROR'); + } + + public function info($msg) + { + $content = $this->get_log_string($msg, 'INFO'); + echo $content; + $this->write($content); + } + + public function debug($msg) + { + $this->write($this->get_log_string($msg, 'DEBUG')); + } + + public function dumpStatistics() + { + $errors = $this->errors + $this->emergency; + $str = "Errors found: $errors; Warnings found: {$this->warnings}"; + echo PHP_EOL . $str . PHP_EOL . PHP_EOL; + } + + private function get_log_string($msg, $type) + { + if (getenv('VZ_UPGRADE_SCRIPT')) { + switch ($type) { + case 'FATAL_ERROR': + case 'ERROR': + case 'WARNING': + case 'EMERGENCY': + $content = "[{$type}]: {$this->step_header} DESC: {$msg}" . PHP_EOL; + break; + default: + $content = "[{$type}]: {$msg}" . PHP_EOL; + } + } else if (getenv('AUTOINSTALLER_VERSION')) { + $content = "{$type}: {$msg}" . PHP_EOL; + } else { + $date = date('Y-m-d h:i:s'); + $content = "[{$date}][{$type}] {$msg}" . PHP_EOL; + } + + return $content; + } + + public function write($content, $file = null, $mode='a+') + { + $logfile = $file ? $file : $this->logfile; + $fp = fopen($logfile, $mode); + fwrite($fp, $content); + fclose($fp); + } + + private function getJsonFileName() + { + return (Util::isWindows() ? + rtrim(Util::regPleskQuery('PRODUCT_DATA_D'), "\\") : + Util::getSettingFromPsaConf('PRODUCT_ROOT_D') + ) . '/var/' . LOG_JSON; + } + + public function writeJsonFile() + { + $data = [ + 'version' => PRE_UPGRADE_SCRIPT_VERSION, + 'errorsFound' => $this->errors + $this->emergency, + 'errors' => $this->errorsContent, + 'warningsFound' => $this->warnings, + 'warnings' => $this->warningsContent, + ]; + file_put_contents($this->getJsonFileName(), json_encode($data)); + } +} + +class PleskDb +{ + var $_db = null; + + public function __construct($dbParams) + { + switch($dbParams['db_type']) { + case 'mysql': + $this->_db = new DbMysql( + $dbParams['host'], $dbParams['login'], $dbParams['passwd'], $dbParams['db'], $dbParams['port'] + ); + break; + + case 'jet': + $this->_db = new DbJet($dbParams['db']); + break; + + case 'mssql': + $this->_db = new DbMsSql( + $dbParams['host'], $dbParams['login'], $dbParams['passwd'], $dbParams['db'], $dbParams['port'] + ); + break; + + default: + fatal("{$dbParams['db_type']} is not implemented yet"); + break; + } + } + + public static function getInstance() + { + global $options; + static $_instance = array(); + + $dbParams['db_type']= Util::getPleskDbType(); + $dbParams['db'] = Util::getPleskDbName(); + $dbParams['port'] = Util::getPleskDbPort(); + $dbParams['login'] = Util::getPleskDbLogin(); + $dbParams['passwd'] = Util::getPleskDbPassword($options->getDbPasswd()); + $dbParams['host'] = Util::getPleskDbHost(); + + $dbId = md5(implode("\n", $dbParams)); + + $_instance[$dbId] = new PleskDb($dbParams); + + return $_instance[$dbId]; + } + + function fetchOne($sql) + { + if (DEBUG) { + $log = Log::getInstance(); + $log->info($sql); + } + return $this->_db->fetchOne($sql); + } + + function fetchRow($sql) + { + $res = $this->fetchAll($sql); + if (is_array($res) && isset($res[0])) { + return $res[0]; + } + return array(); + } + + function fetchAll($sql) + { + if (DEBUG) { + $log = Log::getInstance(); + $log->info($sql); + } + return $this->_db->fetchAll($sql); + } +} + +class DbMysql +{ + var $_dbHandler; + + public function __construct($host, $user, $passwd, $database, $port) + { + if ( extension_loaded('mysql') ) { + $this->_dbHandler = @mysql_connect("{$host}:{$port}", $user, $passwd); + if (!is_resource($this->_dbHandler)) { + $mysqlError = mysql_error(); + if (stristr($mysqlError, 'access denied for user')) { + $errMsg = 'Given is incorrect. ' . $mysqlError; + } else { + $errMsg = 'Unable to connect database. The reason of problem: ' . $mysqlError . PHP_EOL; + } + $this->_logError($errMsg); + } + @mysql_select_db($database, $this->_dbHandler); + } else if ( extension_loaded('mysqli') ) { + + // forbid using MYSQLI_REPORT_STRICT to handle mysqli errors via error codes + mysqli_report(MYSQLI_REPORT_ERROR); + + $this->_dbHandler = @mysqli_connect($host, $user, $passwd, $database, $port); + if (!$this->_dbHandler) { + $mysqlError = mysqli_connect_error(); + if (stristr($mysqlError, 'access denied for user')) { + $errMsg = 'Given is incorrect. ' . $mysqlError; + } else { + $errMsg = 'Unable to connect database. The reason of problem: ' . $mysqlError . PHP_EOL; + } + $this->_logError($errMsg); + } + } else { + fatal("No MariaDB/MySQL extension is available"); + } + } + + function fetchAll($sql) + { + if ( extension_loaded('mysql') ) { + $res = mysql_query($sql, $this->_dbHandler); + if (!is_resource($res)) { + $this->_logError('Unable to execute query. Error: ' . mysql_error($this->_dbHandler)); + } + $rowset = array(); + while ($row = mysql_fetch_assoc($res)) { + $rowset[] = $row; + } + return $rowset; + } else if ( extension_loaded('mysqli') ) { + $res = $this->_dbHandler->query($sql); + if ($res === false) { + $this->_logError('Unable to execute query. Error: ' . mysqli_error($this->_dbHandler)); + } + $rowset = array(); + while ($row = mysqli_fetch_assoc($res)) { + $rowset[] = $row; + } + return $rowset; + } else { + fatal("No MariaDB/MySQL extension is available"); + } + } + + function fetchOne($sql) + { + if ( extension_loaded('mysql') ) { + $res = mysql_query($sql, $this->_dbHandler); + if (!is_resource($res)) { + $this->_logError('Unable to execute query. Error: ' . mysql_error($this->_dbHandler)); + } + $row = mysql_fetch_row($res); + return isset($row[0]) ? $row[0] : null; + } else if ( extension_loaded('mysqli') ) { + $res = $this->_dbHandler->query($sql); + if ($res === false) { + $this->_logError('Unable to execute query. Error: ' . mysqli_error($this->_dbHandler)); + } + $row = mysqli_fetch_row($res); + return isset($row[0]) ? $row[0] : null; + } else { + fatal("No MariaDB/MySQL extension is available"); + } + } + + function query($sql) + { + if ( extension_loaded('mysql') ) { + $res = mysql_query($sql, $this->_dbHandler); + if ($res === false ) { + $this->_logError('Unable to execute query. Error: ' . mysql_error($this->_dbHandler) ); + } + return $res; + } else if ( extension_loaded('mysqli') ) { + $res = $this->_dbHandler->query($sql); + if ($res === false ) { + $this->_logError('Unable to execute query. Error: ' . mysqli_error($this->_dbHandler) ); + } + return $res; + } else { + fatal("No MariaDB/MySQL extension is available"); + } + } + + function _logError($message) + { + fatal("[MYSQL ERROR] $message"); + } +} + +class DbClientMysql extends DbMysql +{ + var $errors = array(); + + function _logError($message) + { + $message = "[MYSQL ERROR] $message"; + $log = Log::getInstance(); + $log->warning($message); + $this->errors[] = $message; + } + + function hasErrors() { + return count($this->errors) > 0; + } +} + +class DbJet +{ + var $_dbHandler = null; + + public function __construct($dbPath) + { + $dsn = "Provider='Microsoft.Jet.OLEDB.4.0';Data Source={$dbPath}"; + $this->_dbHandler = new COM("ADODB.Connection", NULL, CP_UTF8); + if (!$this->_dbHandler) { + $this->_logError('Unable to init ADODB.Connection'); + } + + $this->_dbHandler->open($dsn); + } + + function fetchAll($sql) + { + $result_id = $this->_dbHandler->execute($sql); + if (!$result_id) { + $this->_logError('Unable to execute sql query ' . $sql); + } + if ($result_id->BOF && !$result_id->EOF) { + $result_id->MoveFirst(); + } + if ($result_id->EOF) { + return array(); + } + + $rowset = array(); + while(!$result_id->EOF) { + $row = array(); + for ($i=0;$i<$result_id->Fields->count;$i++) { + $field = $result_id->Fields($i); + $row[$field->Name] = (string)$field->value; + } + $result_id->MoveNext(); + $rowset[] = $row; + } + return $rowset; + } + + function fetchOne($sql) + { + $result_id = $this->_dbHandler->execute($sql); + if (!$result_id) { + $this->_logError('Unable to execute sql query ' . $sql); + } + if ($result_id->BOF && !$result_id->EOF) { + $result_id->MoveFirst(); + } + if ($result_id->EOF) { + return null; + } + $field = $result_id->Fields(0); + $result = $field->value; + + return (string)$result; + } + + function _logError($message) + { + fatal("[JET ERROR] $message"); + } +} + +class DbMsSql extends DbJet +{ + public function __construct($host, $user, $passwd, $database, $port) + { + $dsn = "Provider=SQLOLEDB.1;Initial Catalog={$database};Data Source={$host}"; + $this->_dbHandler = new COM("ADODB.Connection", NULL, CP_UTF8); + if (!$this->_dbHandler) { + $this->_logError('Unable to init ADODB.Connection'); + } + $this->_dbHandler->open($dsn, $user, $passwd); + } + + function _logError($message) + { + fatal("[MSSQL ERROR] $message"); + } +} + +class Util +{ + const DSN_INI_PATH_UNIX = '/etc/psa/private/dsn.ini'; + + /** @var array */ + private static $_dsnIni; + + public static function isWindows() + { + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + return true; + } + return false; + } + + public static function isLinux() + { + return !Util::isWindows(); + } + + public static function isVz() + { + $vz = false; + if (Util::isLinux()) { + if (file_exists('/proc/vz/veredir')) { + $vz = true; + } + } else { + $reg = 'REG QUERY "HKLM\SOFTWARE\SWsoft\Virtuozzo" 2>nul'; + Util::exec($reg, $code); + if ($code==0) { + $vz = true; + } + } + return $vz; + } + + public static function getArch() + { + global $arch; + if (!empty($arch)) + return $arch; + + $arch = 'i386'; + if (Util::isLinux()) { + $cmd = 'uname -m'; + $x86_64 = 'x86_64'; + $output = Util::exec($cmd, $code); + if (!empty($output) && stristr($output, $x86_64)) { + $arch = 'x86_64'; + } + } else { + $arch = 'x86_64'; + } + return $arch; + } + + public static function getHostname() + { + if (Util::isLinux()) { + $cmd = 'hostname -f'; + } else { + $cmd = 'hostname'; + } + $hostname = Util::exec($cmd, $code); + + if (empty($hostname)) { + $err = 'Command: ' . $cmd . ' returns: ' . $hostname . "\n"; + $err .= 'Hostname is not defined and configured. Unable to get hostname. Server should have properly configured hostname and it should be resolved locally.'; + fatal($err); + } + + return $hostname; + } + + public static function getIPList($lo=false) + { + if (Util::isLinux()) { + $ipList = Util::getIPv4ListOnLinux(); + foreach ($ipList as $key => $ip) { + if (!$lo && substr($ip, 0, 3) == '127') { + unset($ipList[$key]); + continue; + } + trim($ip); + } + $ipList = array_values($ipList); + } else { + $cmd = 'hostname'; + $hostname = Util::exec($cmd, $code); + $ip = gethostbyname($hostname); + $res = ($ip != $hostname) ? true : false; + if (!$res) { + fatal('Unable to retrieve IP address'); + } + $ipList = array(trim($ip)); + } + return $ipList; + } + + public static function getIPv6ListOnLinux() + { + return Util::grepCommandOutput(array( + array('bin' => 'ip', 'command' => '%PATH% addr list', 'regexp' => '#inet6 ([^ /]+)#'), + array('bin' => 'ifconfig', 'command' => '%PATH% -a', 'regexp' => '#inet6 (?:addr: ?)?([A-F0-9:]+)#i'), + )); + } + + public static function getIPv4ListOnLinux() + { + $commands = array( + array('bin' => 'ip', 'command' => '%PATH% addr list', 'regexp' => '#inet ([^ /]+)#'), + array('bin' => 'ifconfig', 'command' => '%PATH% -a', 'regexp' => '#inet (?:addr: ?)?([\d\.]+)#'), + ); + if (!($list = Util::grepCommandOutput($commands))) { + fatal('Unable to get IP address'); + } + return $list; + } + + public static function grepCommandOutput($cmds) + { + foreach ($cmds as $cmd) { + if ($fullPath = Util::lookupCommand($cmd['bin'])) { + $output = Util::exec(str_replace("%PATH%", $fullPath, $cmd['command']), $code); + if (preg_match_all($cmd['regexp'], $output, $matches)) { + return $matches[1]; + } + } + } + return false; + } + + public static function getIPListOnWindows() + { + $cmd = 'wmic.exe path win32_NetworkAdapterConfiguration get IPaddress'; + $output = Util::exec($cmd, $code); + if (!preg_match_all('/"(.*?)"/', $output, $matches)) { + fatal('Unable to get IP address'); + } + return $matches[1]; + } + + public static function getPleskRootPath() + { + global $_pleskRootPath; + if (empty($_pleskRootPath)) { + if (Util::isLinux()) { + if (PleskOS::isDebLike()) { + $_pleskRootPath = '/opt/psa'; + } else { + $_pleskRootPath = '/usr/local/psa'; + } + } + if (Util::isWindows()) { + $_pleskRootPath = Util::regPleskQuery('PRODUCT_ROOT_D', true); + } + } + return $_pleskRootPath; + } + + public static function getPleskDbName() + { + $dbName = 'psa'; + if (Util::isWindows()) { + $dbName = Util::regPleskQuery('mySQLDBName'); + } else { + $dsnDbname = Util::_getDsnConfigValue('dbname'); + if ($dsnDbname) { + $dbName = $dsnDbname; + } + } + return $dbName; + } + + public static function getPleskDbLogin() + { + $dbLogin = 'admin'; + if (Util::isWindows()) { + $dbLogin = Util::regPleskQuery('PLESK_DATABASE_LOGIN'); + } else { + $dsnLogin = Util::_getDsnConfigValue('username'); + if ($dsnLogin) { + $dbLogin = $dsnLogin; + } + } + return $dbLogin; + } + + public static function getPleskDbPassword($dbPassword) + { + if (Util::isLinux()) { + $dsnPassword = Util::_getDsnConfigValue('password'); + if ($dsnPassword) { + $dbPassword = $dsnPassword; + } + } + return $dbPassword; + } + + public static function getPleskDbType() + { + $dbType = 'mysql'; + if (Util::isWindows()) { + $dbType = strtolower(Util::regPleskQuery('PLESK_DATABASE_PROVIDER_NAME')); + } + return $dbType; + } + + public static function getPleskDbHost() + { + $dbHost = 'localhost'; + if (Util::isWindows()) { + $dbProvider = strtolower(Util::regPleskQuery('PLESK_DATABASE_PROVIDER_NAME')); + if ($dbProvider == 'mysql' || $dbProvider == 'mssql') { + $dbHost = Util::regPleskQuery('MySQL_DB_HOST'); + } + } else { + $dsnHost = Util::_getDsnConfigValue('host'); + if ($dsnHost) { + $dbHost = $dsnHost; + } + } + return $dbHost; + } + + public static function getPleskDbPort() + { + $dbPort = '3306'; + if (Util::isWindows()) { + $dbPort = Util::regPleskQuery('MYSQL_PORT'); + } else { + $dsnPort = Util::_getDsnConfigValue('port'); + if ($dsnPort) { + $dbPort = $dsnPort; + } + } + return $dbPort; + } + + private static function _getDsnConfigValue($param) + { + if (Util::isWindows()) { + return null; + } + + if (is_null(self::$_dsnIni)) { + if (!is_file(self::DSN_INI_PATH_UNIX)) { + self::$_dsnIni = false; + return null; + } + self::$_dsnIni = parse_ini_file(self::DSN_INI_PATH_UNIX, true); + } + + if (!self::$_dsnIni) { + return null; + } + if (!array_key_exists('plesk', self::$_dsnIni)) { + return null; + } + if (!array_key_exists($param, self::$_dsnIni['plesk'])) { + return null; + } + return self::$_dsnIni['plesk'][$param]; + } + + public static function regPleskQuery($key, $returnResult=false) + { + $reg = 'REG QUERY "HKLM\SOFTWARE\Wow6432Node\Plesk\Psa Config\Config" /v '.$key; + $output = Util::exec($reg, $code); + + if ($code) { + $log = Log::getInstance(); + $log->info($reg); + $log->info($output); + if ($returnResult) { + return false; + } else { + fatal("Unable to get '$key' from registry"); + } + } + + if (!preg_match("/\w+\s+REG_SZ\s+(.*)/i", trim($output), $matches)) { + fatal('Unable to macth registry value by key '.$key.'. Output: ' . trim($output)); + } + + return $matches[1]; + } + + public static function regQuery($path, $key, $returnResult = false) + { + $reg = 'REG QUERY "HKLM\SOFTWARE\Wow6432Node' . $path . '" '.$key; + $output = Util::exec($reg, $code); + + if ($code) { + $log = Log::getInstance(); + $log->info($reg); + $log->info($output); + if ($returnResult) { + return false; + } else { + fatal("Unable to get '$key' from registry"); + } + } + + if (!preg_match("/\s+REG_SZ(\s+)?(.*)/i", trim($output), $matches)) { + fatal('Unable to match registry value by key '.$key.'. Output: ' . trim($output)); + } + + return $matches[2]; + } + + public static function lookupCommand($cmd, $exit = false, $path = '/bin:/usr/bin:/usr/local/bin:/usr/sbin:/sbin:/usr/local/sbin') + { + $dirs = explode(':', $path); + foreach ($dirs as $dir) { + $util = $dir . '/' . $cmd; + if (is_executable($util)) { + return $util; + } + } + if ($exit) { + fatal("{$cmd}: command not found"); + } + return false; + } + + public static function getSystemDisk() + { + $cmd = 'echo %SYSTEMROOT%'; + $output = Util::exec($cmd, $code); + return substr($output, 0, 3); + } + + public static function getSystemRoot() + { + $cmd = 'echo %SYSTEMROOT%'; + $output = Util::exec($cmd, $code); + return $output; + } + + public static function getFileVersion($file) + { + $fso = new COM("Scripting.FileSystemObject"); + $version = $fso->GetFileVersion($file); + $fso = null; + return $version; + } + + public static function isUnknownISAPIfilters() + { + if (PleskVersion::is17x_or_above()) { + return false; + } + + $log = Log::getInstance(); + + $isUnknownISAPI = false; + $knownISAPI = array ("ASP\\.Net.*", "sitepreview", "COMPRESSION", "jakarta"); + + foreach ($knownISAPI as &$value) { + $value = strtoupper($value); + } + $cmd='cscript ' . Util::getSystemDisk() . 'inetpub\AdminScripts\adsutil.vbs ENUM W3SVC/FILTERS'; + $output = Util::exec($cmd, $code); + + if ($code!=0) { + $log->info("Unable to get ISAPI filters. Error: " . $output); + return false; + } + if (!preg_match_all('/FILTERS\/(.*)]/', trim($output), $matches)) { + $log->info($output); + $log->info("Unable to get ISAPI filters from output: " . $output); + return false; + } + foreach ($matches[1] as $ISAPI) { + $valid = false; + foreach ($knownISAPI as $knownPattern) { + if (preg_match("/$knownPattern/i", $ISAPI)) { + $valid = true; + break; + } + } + if (! $valid ) { + $log->warning("Unknown ISAPI filter detected in IIS: " . $ISAPI); + $isUnknownISAPI = true; + } + } + + return $isUnknownISAPI; + } + + /** + * @return string + */ + public static function getMySQLServerVersion() + { + $credentials = Util::getDefaultClientMySQLServerCredentials(); + + if (preg_match('/AES-128-CBC/', $credentials['admin_password'])) { + Log::getInstance()->info('The administrator\'s password for the default MariaDB/MySQL server is encrypted.'); + + return ''; + } + + $mysql = new DbClientMysql( + $credentials['host'], + $credentials['admin_login'], + $credentials['admin_password'], + 'information_schema', + $credentials['port'] + ); + + if (!$mysql->hasErrors()) { + $sql = 'select version()'; + $mySQLversion = $mysql->fetchOne($sql); + if (!preg_match("/(\d{1,})\.(\d{1,})\.(\d{1,})/", trim($mySQLversion), $matches)) { + fatal('Unable to match MariaDB/MySQL server version.'); + } + + return $matches[0]; + } + + return ''; + } + + public static function getDefaultClientMySQLServerCredentials() + { + $db = PleskDb::getInstance(); + $sql = "SELECT val FROM misc WHERE param='default_server_mysql'"; + $defaultServerMysqlId = $db->fetchOne($sql); + if ($defaultServerMysqlId) { + $where = "id={$defaultServerMysqlId}"; + } else { + $where = "type='mysql' AND host='localhost'"; + } + $sql = "SELECT ds.host, ds.port, ds.admin_login, ds.admin_password FROM DatabaseServers ds WHERE {$where}"; + $clientDBServerCredentials = $db->fetchAll($sql)[0]; + if ($clientDBServerCredentials['host'] === 'localhost' && Util::isLinux()) { + $clientDBServerCredentials['admin_password'] = Util::retrieveAdminMySQLDbPassword(); + } + if (empty($clientDBServerCredentials['port'])) { + $clientDBServerCredentials['port'] = self::getPleskDbPort(); + } + + return $clientDBServerCredentials; + } + + public static function retrieveAdminMySQLDbPassword() + { + return Util::isLinux() + ? trim( Util::readfile("/etc/psa/.psa.shadow") ) + : null; + } + + public static function exec($cmd, &$code) + { + $log = Log::getInstance(); + + if (!$cmd) { + $log->info('Unable to execute a blank command. Please see ' . LOG_PATH . ' for details.'); + + $debugBacktrace = ""; + foreach (debug_backtrace() as $i => $obj) { + $debugBacktrace .= "#{$i} {$obj['file']}:{$obj['line']} {$obj['function']} ()\n"; + } + $log->debug("Unable to execute a blank command. The stack trace:\n{$debugBacktrace}"); + $code = 1; + return ''; + } + exec($cmd, $output, $code); + return trim(implode("\n", $output)); + } + + public static function readfile($file) + { + if (!is_file($file) || !is_readable($file)) { + return null; + } + $lines = file($file); + return $lines === false + ? null + : trim(implode("\n", $lines)); + } + + public static function readfileToArray($file) + { + if (!is_file($file) || !is_readable($file)) { + return null; + } + $lines = file($file); + return $lines === false + ? null + : $lines; + } + + public static function getSettingFromPsaConf($setting) + { + $file = '/etc/psa/psa.conf'; + if (!is_file($file) || !is_readable($file)) + return null; + $lines = file($file); + if ($lines === false) + return null; + foreach ($lines as $line) { + if (preg_match("/^{$setting}\s.*/", $line, $match_setting)) { + if (preg_match("/[\s].*/i", $match_setting[0], $match_value)) { + $value = trim($match_value[0]); + return $value; + } + } + } + return null; + } + + public static function getPhpIni() + { + if (Util::isLinux()) { + // Debian/Ubuntu /etc/php5/apache2/php.ini /etc/php5/conf.d/ + // SuSE /etc/php5/apache2/php.ini /etc/php5/conf.d/ + // CentOS 4/5 /etc/php.ini /etc/php.d + if (PleskOS::isRedHatLike()) { + $phpini = Util::readfileToArray('/etc/php.ini'); + } else { + $phpini = Util::readfileToArray('/etc/php5/apache2/php.ini'); + } + } + + return $phpini; + } + + public static function getUserBeanCounters() + { + if (!Util::isLinux()) { + + return false; + } + $user_beancounters = array(); + $ubRaw = Util::readfileToArray('/proc/user_beancounters'); + + if (!$ubRaw) { + + return false; + } + for ($i=2; $i<=count($ubRaw)-1; $i++) { + + if (preg_match('/^.+?:?.+?\b(\w+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/', $ubRaw[$i], $limit_name)) { + + $user_beancounters[trim($limit_name[1])] = array( + 'held' => (int)$limit_name[2], + 'maxheld' => (int)$limit_name[3], + 'barrier' => (int)$limit_name[4], + 'limit' => (int)$limit_name[5], + 'failcnt' => (int)$limit_name[6] + ); + } + } + + return $user_beancounters; + } +} + +class PackageManager +{ + public static function buildListCmdLine($glob) + { + if (PleskOS::isRedHatLike()) { + $cmd = "rpm -qa --queryformat '%{NAME} %{VERSION}-%{RELEASE} %{ARCH}\\n'"; + } elseif (PleskOS::isDebLike()) { + $cmd = "dpkg-query --show --showformat '\${Package} \${Version} \${Architecture}\\n'"; + } else { + return false; + } + + if (!empty($glob)) { + $cmd .= " '" . $glob . "' 2>/dev/null"; + } + + return $cmd; + } + + /* + * Fetches a list of installed packages that match given criteria. + * string $glob - Glob (wildcard) pattern for coarse-grained packages selection from system package management backend. Empty $glob will fetch everything. + * string $regexp - Package name regular expression for a fine-grained filtering of the results. + * returns array of hashes with keys 'name', 'version' and 'arch', or false on error. + */ + public static function listInstalled($glob, $regexp = null) + { + $cmd = PackageManager::buildListCmdLine($glob); + if (!$cmd) { + return array(); + } + + $output = Util::exec($cmd, $code); + if ($code != 0) { + return false; + } + + $packages = array(); + $lines = explode("\n", $output); + foreach ($lines as $line) { + @list($pkgName, $pkgVersion, $pkgArch) = explode(" ", $line); + if (empty($pkgName) || empty($pkgVersion) || empty($pkgArch)) + continue; + if (!empty($regexp) && !preg_match($regexp, $pkgName)) + continue; + $packages[] = array( + 'name' => $pkgName, + 'version' => $pkgVersion, + 'arch' => $pkgArch + ); + } + + return $packages; + } + + public static function isInstalled($glob, $regexp = null) + { + $packages = PackageManager::listInstalled($glob, $regexp); + return !empty($packages); + } +} + +class Package +{ + function getManager($field, $package) + { + $redhat = 'rpm -q --queryformat \'%{' . $field . '}\n\' ' . $package; + $debian = 'dpkg-query --show --showformat=\'${' . $field . '}\n\' '. $package . ' 2> /dev/null'; + + if (PleskOS::isRedHatLike()) { + $manager = $redhat; + } elseif (PleskOS::isDebLike()) { + $manager = $debian; + } else { + return false; + } + + return $manager; + } + + /* DPKG doesn't supports ${Release} + * + */ + + function getRelease($package) + { + $manager = Package::getManager('Release', $package); + + if (!$manager) { + return false; + } + + $release = Util::exec($manager, $code); + if (!$code === 0) { + return false; + } + return $release; + } + + function getVersion($package) + { + $manager = Package::getManager('Version', $package); + + if (!$manager) { + return false; + } + + $version = Util::exec($manager, $code); + if (!$code === 0) { + return false; + } + return $version; + } + +} + +class PleskOS +{ + public static function isDebLike() + { + return is_file("/etc/debian_version"); + } + + public static function isRedHatLike() + { + return is_file("/etc/redhat-release"); + } + + public static function catEtcIssue() + { + $cmd = 'cat /etc/issue'; + $output = Util::exec($cmd, $code); + + return $output; + } + + public static function detectSystem() + { + $log = Log::getInstance('Detect system configuration'); + $log->info('OS: ' . (Util::isLinux() ? PleskOS::catEtcIssue() : 'Windows')); + $log->info('Arch: ' . Util::getArch()); + } +} + +class PleskValidator +{ + public static function validateIPv4($value) + { + $ip2long = ip2long($value); + if ($ip2long === false) { + return false; + } + + return $value == long2ip($ip2long); + } + + public static function validateIPv6($value) + { + if (strlen($value) < 3) { + return $value == '::'; + } + + if (strpos($value, '.')) { + $lastcolon = strrpos($value, ':'); + if (!($lastcolon && PleskValidator::validateIPv4(substr($value, $lastcolon + 1)))) { + return false; + } + + $value = substr($value, 0, $lastcolon) . ':0:0'; + } + + if (strpos($value, '::') === false) { + return preg_match('/\A(?:[a-f0-9]{1,4}:){7}[a-f0-9]{1,4}\z/i', $value); + } + + $colonCount = substr_count($value, ':'); + if ($colonCount < 8) { + return preg_match('/\A(?::|(?:[a-f0-9]{1,4}:)+):(?:(?:[a-f0-9]{1,4}:)*[a-f0-9]{1,4})?\z/i', $value); + } + + // special case with ending or starting double colon + if ($colonCount == 8) { + return preg_match('/\A(?:::)?(?:[a-f0-9]{1,4}:){6}[a-f0-9]{1,4}(?:::)?\z/i', $value); + } + + return false; + } +} + +class CheckRequirements +{ + function validate() + { + if (!PleskInstallation::isInstalled()) { + //:INFO: skip chking mysql extension if plesk is not installed + return; + } + + $reqExts = array(); + foreach ($reqExts as $name) { + $status = extension_loaded($name); + if (!$status) { + $this->_fail("PHP extension {$name} is not installed"); + } + } + } + + function _fail($errMsg) + { + echo '===Checking requirements===' . PHP_EOL; + echo PHP_EOL . 'Error: ' . $errMsg . PHP_EOL; + exit(1); + } +} + +class GetOpt +{ + var $_argv; + var $_adminDbPasswd; + + public function __construct() + { + $this->_argv = $_SERVER['argv']; + if (empty($this->_argv[1]) && Util::isLinux()) { + $this->_adminDbPasswd = Util::retrieveAdminMySQLDbPassword(); + } else { + $this->_adminDbPasswd = $this->_argv[1]; + } + } + + public function validate() + { + if (empty($this->_adminDbPasswd) && PleskInstallation::isInstalled()) { + echo 'Please specify Plesk database password'; + $this->_helpUsage(); + } + } + + public function getDbPasswd() + { + return $this->_adminDbPasswd; + } + + public function _helpUsage() + { + echo PHP_EOL . "Usage: {$this->_argv[0]} " . PHP_EOL; + exit(1); + } +} + +function fatal($msg) +{ + $log = Log::getInstance(); + $log->fatal($msg); + exit(1); +} + +$log = Log::getInstance(); + +//:INFO: Validate options +$options = new GetOpt(); +$options->validate(); + +//:INFO: Validate PHP requirements, need to make sure that PHP extensions are installed +$checkRequirements = new CheckRequirements(); +$checkRequirements->validate(); + +//:INFO: Validate Plesk installation +PleskInstallation::validate(); + +//:INFO: Detect system +$pleskOs = new PleskOS(); +$pleskOs->detectSystem(); + +//:INFO: Need to make sure that given db password is valid +if (PleskInstallation::isInstalled()) { + $log->step('Validating the database password'); + $pleskDb = PleskDb::getInstance(); + $log->resultOk(); +} + +//:INFO: Dump script version +$log->step('Pre-Upgrade analyzer version: ' . PRE_UPGRADE_SCRIPT_VERSION); + +//:INFO: Validate known OS specific issues with recommendation to avoid bugs in Plesk +$pleskKnownIssues = new Plesk17KnownIssues(); +$pleskKnownIssues->validate(); + +$plesk175Requirements = new Plesk175Requirements(); +$plesk175Requirements->validate(); + +$plesk178Requirements = new Plesk178Requirements(); +$plesk178Requirements->validate(); + +$plesk18Requirements = new Plesk18Requirements(); +$plesk18Requirements->validate(); + +$log->dumpStatistics(); +$log->writeJsonFile(); + +if ($log->getEmergency() > 0) { + exit(2); +} + +if ($log->getErrors() > 0 || $log->getWarnings() > 0) { + exit(1); +} +// vim:set et ts=4 sts=4 sw=4: diff --git a/root/parallels/pool/PSA_18.0.73_17971/examiners/php_launcher.sh b/root/parallels/pool/PSA_18.0.73_17971/examiners/php_launcher.sh new file mode 100755 index 0000000000..70ebd0f0c6 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17971/examiners/php_launcher.sh @@ -0,0 +1,38 @@ +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +die() +{ + echo $* + exit 1 +} + +[ -n "$1" ] || die "Usage: $0 php_script [args...]" + +[ "X${PLESK_INSTALLER_DEBUG}" = "X" ] || set -x +[ "X${PLESK_INSTALLER_STRICT_MODE}" = "X" ] || set -e + +php_bin= + +lookup() +{ + [ -z "$php_bin" ] || return + + local paths="$1" + local name="$2" + + for path in $paths; do + if [ -x "$path/$name" ]; then + php_bin="$path/$name" + break + fi + done +} + +lookup "/usr/local/psa/admin/bin /opt/psa/admin/bin" "php" +lookup "/usr/local/psa/bin /opt/psa/bin" "sw-engine-pleskrun" + +[ -n "$php_bin" ] || \ + die "Unable to locate the sw-engine PHP interpreter to execute the script. Make sure that Parallels Plesk Panel is installed on this server." + +exec "${php_bin}" "$@" diff --git a/root/parallels/pool/PSA_18.0.73_17971/examiners/plesk_preupgrade_checker.log b/root/parallels/pool/PSA_18.0.73_17971/examiners/plesk_preupgrade_checker.log new file mode 100644 index 0000000000..7cadbf4cf5 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17971/examiners/plesk_preupgrade_checker.log @@ -0,0 +1,3 @@ + +INFO: Installed Plesk version/build: 18.0.73 Ubuntu 24.04 1800251117.15... +INFO: You have already installed the latest version Plesk 18.0.73. Tool must be launched prior to upgrade to Plesk 18.0.73 for the purpose of getting a report on potential problems with the upgrade. diff --git a/root/parallels/pool/PSA_18.0.73_17971/examiners/py_launcher.sh b/root/parallels/pool/PSA_18.0.73_17971/examiners/py_launcher.sh new file mode 100755 index 0000000000..96dc215391 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17971/examiners/py_launcher.sh @@ -0,0 +1,30 @@ +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +die() +{ + echo "$*" + exit 1 +} + +[ -f "$1" ] || die "Usage: $0 PEX [args...]" + +[ "X${PLESK_INSTALLER_DEBUG}" = "X" ] || set -x +[ "X${PLESK_INSTALLER_STRICT_MODE}" = "X" ] || set -e + +find_python_bin() +{ + local bin + for bin in "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3" "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2"; do + [ -x "$bin" ] || continue + python_bin="$bin" + return 0 + done + + return 1 +} + +find_python_bin || + die "Unable to locate Python interpreter to execute the script." + +exec "$python_bin" "$@" diff --git a/root/parallels/pool/PSA_18.0.73_17971/examiners/repository_check.sh b/root/parallels/pool/PSA_18.0.73_17971/examiners/repository_check.sh new file mode 100755 index 0000000000..090f121ea1 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17971/examiners/repository_check.sh @@ -0,0 +1,782 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ -z "$PLESK_INSTALLER_DEBUG" ] || set -x +[ -z "$PLESK_INSTALLER_STRICT_MODE" ] || set -e + +export LC_ALL=C +unset GREP_OPTIONS + +RET_SUCCESS=0 +RET_WARN=1 +RET_FATAL=2 + +is_function_defined() +{ + local fn="$1" + case "$(type $fn 2>/dev/null)" in + *function*) + return 0 + ;; + esac + return 1 +} + +# @params are tags in format "key=value" +# Report body (human readable information) is read from stdin +# and copied to stderr. +make_error_report() +{ + local report_file="${PLESK_INSTALLER_ERROR_REPORT:-}" + + local python_bin= + for bin in "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2" "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3"; do + if [ -x "$bin" ]; then + python_bin="$bin" + break + fi + done + + if [ -n "$report_file" -a -x "$python_bin" ]; then + "$python_bin" -c 'import sys, json +report_file = sys.argv[1] +error = sys.stdin.read() + +sys.stderr.write(error) + +data = { + "error": error, +} + +for tag in sys.argv[2:]: + k, v = tag.split("=", 1) + data[k] = v + +with open(report_file, "a") as f: + json.dump(data, f) + f.write("\n") +' "$report_file" "date=$(date --utc --iso-8601=ns)" "$@" + else + cat - >&2 + fi +} + +detect_platform() +{ + . /etc/os-release + os_name="$ID" + os_version="${VERSION_ID%%.*}" + os_arch="$(uname -m)" + if [ -e /etc/debian_version ]; then + case "$os_arch" in + x86_64) pkg_arch="amd64" ;; + aarch64) pkg_arch="arm64" ;; + esac + if [ -n "$VERSION_CODENAME" ]; then + os_codename="$VERSION_CODENAME" + else + case "$os_name$os_version" in + debian10) os_codename="buster" ;; + debian11) os_codename="bullseye" ;; + debian12) os_codename="bookworm" ;; + ubuntu18) os_codename="bionic" ;; + ubuntu20) os_codename="focal" ;; + ubuntu22) os_codename="jammy" ;; + ubuntu24) os_codename="noble" ;; + esac + fi + fi + + case "$os_name$os_version" in + rhel7|centos7|cloudlinux7|virtuozzo7) + package_manager="yum" + ;; + rhel*|centos*|cloudlinux*|almalinux*|rocky*) + package_manager="dnf" + ;; + debian*|ubuntu*) + package_manager="apt" + ;; + esac + + if [ "$os_name" = "ubuntu" -o "$os_name" = "debian" ]; then + PRODUCT_ROOT_D="/opt/psa" + else + PRODUCT_ROOT_D="/usr/local/psa" + fi +} + +has_os_impl_function() +{ + local prefix="$1" + local fn="${prefix}_${os_name}${os_version}" + is_function_defined "$fn" +} + +call_os_impl_function() +{ + local prefix="$1" + shift + local fn="${prefix}_${os_name}${os_version}" + "$fn" "$@" +} + +skip_checker_on_flag() +{ + local name="$1" + local flag="$2" + + if [ -f "$flag" ]; then + echo "$name was skipped due to flag file." >&2 + exit $RET_SUCCESS + fi +} + +skip_checker_on_env() +{ + local name="$1" + local env="$2" + + if [ -n "$env" ]; then + echo "$name was skipped due to environment variable." >&2 + exit $RET_SUCCESS + fi +} + +checker_main() +{ + local fnprefix="$1" + shift + + detect_platform + # try to execute checker only if all attributes are detected + [ -n "$os_name" -a -n "$os_version" ] || return $RET_SUCCESS + + for checker in "${fnprefix}_${os_name}${os_version}" "${fnprefix}_${os_name}" "${fnprefix}"; do + if is_function_defined "$checker"; then + local rc=$RET_SUCCESS + "$checker" "$@" || rc=$? + [ "$(( $rc & $RET_FATAL ))" = "0" ] || return $RET_FATAL + [ "$(( $rc & $RET_WARN ))" = "0" ] || return $RET_WARN + return $rc + fi + done + return $RET_SUCCESS +} + +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +# If env variable PLESK_INSTALLER_ERROR_REPORT=path_to_file is specified then in case of error +# repository_check.sh writes single line json report into it with the following fields: +# - "stage": "repositorycheck" +# - "level": "error" +# - "errtype" is one of the following: +# * "reponotcached" - repository is not cached (mostly due to unavailability). +# * "reponotenabled" - required repository is not enabled. +# * "reponotsupported" - unsupported repository is enabled. +# * "configmanagernotinstalled" - dnf config-manager is disabled. +# - "repo": repository name. +# - "date": time of error occurance ("2020-03-24T06:59:43,127545441+0000") +# - "error": human readable error message. + +report_no_repo() +{ + local repo="$1" + + make_error_report 'stage=repositorycheck' 'level=error' 'errtype=reponotenabled' "repo=$repo" <<-EOL + Plesk installation requires '$repo' OS repository to be enabled. + Make sure it is available and enabled, then try again. + EOL +} + +report_no_repo_cache() +{ + local repo="$1" + + make_error_report 'stage=repositorycheck' 'level=error' 'errtype=reponotcached' "repo=$repo" <<-EOL + Unable to create $package_manager cache for '$repo' OS repository. + Make sure the repository is available, otherwise either disable it or fix its configuration, then try again. + EOL +} + +report_unsupported_repo() +{ + local repo="$1" + + make_error_report 'stage=repositorycheck' 'level=error' 'errtype=reponotsupported' "repo=$repo" <<-EOL + Plesk installation doesn't support '$repo' OS repository. + Make sure it is disabled, then try again. + EOL +} + +report_rh_no_config_manager() +{ + local target + case "$package_manager" in + yum) + target="yum-utils package" + ;; + dnf) + target="config-manager dnf plugin" + ;; + esac + + make_error_report 'stage=repositorycheck' 'level=error' 'errtype=configmanagernotinstalled' <<-EOL + Failed to install $target. + Make sure repositories configuration of $package_manager package manager is correct + (use '$package_manager repolist --verbose' to get its actual state), then try again. + EOL +} + +check_rh_broken_repos() +{ + local rh_enabled_repos rh_available_repos + + # 1. `yum repolist` and `dnf repolist` list all repos + # which were enabled before last cache creation + # even if cache for them was not created. + # If some repo is misconfigured and cache was created with `skip_if_unavailable=1` + # then such repo will be listed anyway despite on cache state. + # If some repo was enabled after last cache creation + # then `repolist --cacheonly` will fail. + # 2. `yum repolist --verbose` and `dnf repoinfo` list only repos + # which were successfully cached before. + # These commands fail if at least one repo is not available + # and the 'skip_if_unavailable' flag is not set. + case "$package_manager" in + yum) + rh_enabled_repos="$( + { + yum repolist enabled --cacheonly -q 2>/dev/null \ + || yum repolist enabled -q --setopt='*.skip_if_unavailable=1' + } | sed -n -e '1d' -e 's/^\*\?!\?\([^/[:space:]]\+\).*/\1/p' + )" || return $RET_FATAL + + rh_available_repos="$( + yum repolist enabled --verbose --cacheonly -q --setopt='*.skip_if_unavailable=1' \ + | sed -n -e 's/^Repo-id\s*:\s*\([^/[:space:]]\+\).*/\1/p' + )" || return $RET_FATAL + ;; + dnf) + rh_enabled_repos="$( + { + dnf repolist --enabled --cacheonly -q 2>/dev/null \ + || dnf repolist --enabled -q --setopt='*.skip_if_unavailable=1' + } | sed -n -e '1d' -e 's/^!\?\(\S\+\).*/\1/p' + )" || return $RET_FATAL + + rh_available_repos="$( \ + dnf repoinfo --enabled --cacheonly -q --setopt='*.skip_if_unavailable=1' \ + | sed -n -e 's|^Repo-id\s*:\s*\(\S\+\)\s*$|\1|p' + )" || return $RET_FATAL + ;; + esac + + local rh_enabled_repos_f="$(mktemp /tmp/plesk-installer.preupgrade_checker.XXXXXX)" + echo "$rh_enabled_repos" | sort > "$rh_enabled_repos_f" + local rh_available_repos_f="$(mktemp /tmp/plesk-installer.preupgrade_checker.XXXXXX)" + echo "$rh_available_repos" | sort > "$rh_available_repos_f" + + local repo rc=0 + for repo in $(comm -23 "$rh_enabled_repos_f" "$rh_available_repos_f"); do + report_no_repo_cache "$repo" + rc=$RET_WARN + done + + rm -f "$rh_enabled_repos_f" "$rh_available_repos_f" + + return $rc +} + +has_rh_enabled_repo() +{ + local repo="$1" + + # Try to get list of repos from cache first. + # If some repo was enabled after last cache creation + # or some repo is unavailable the query from cache will fail. + # Try to fetch actual metadata in this case. + case "$package_manager" in + yum) + # Repo-id may end with OS version and/or architecture + # if baseurl of the repo refers to $releasever and/or $basearch variables + # eg 'epel/7/x86_64', 'epel/7', 'epel/x86_64' + { + yum repolist enabled --verbose --cacheonly -q 2>/dev/null \ + || yum repolist enabled --verbose -q --setopt='*.skip_if_unavailable=1' + } | grep -E -q "^Repo-id\s*: $repo(/.+)?\s*$" + ;; + dnf) + # note: --noplugins may cause failure and empty output on RedHat + { + dnf repoinfo --enabled --cacheonly -q 2>/dev/null \ + || dnf repoinfo --enabled -q --setopt='*.skip_if_unavailable=1' + } | grep -E -q "^Repo-id\s*: $repo\s*$" + ;; + esac +} + +has_rh_config_manager() +{ + case "$package_manager" in + yum) yum-config-manager --help >/dev/null 2>&1 ;; + dnf) dnf config-manager --help >/dev/null 2>&1 ;; + esac +} + +install_rh_config_manager() +{ + case "$package_manager" in + yum) yum install --disablerepo 'PLESK_*' -q -y 'yum-utils' --setopt='*.skip_if_unavailable=1' ;; + dnf) dnf install --disablerepo 'PLESK_*' -q -y 'dnf-command(config-manager)' --setopt='*.skip_if_unavailable=1' ;; + esac +} + +check_rh_config_manager() +{ + if ! has_rh_config_manager && ! install_rh_config_manager; then + report_rh_no_config_manager + return $RET_FATAL + fi +} + +enable_rh_repo() +{ + case "$package_manager" in + yum) yum-config-manager --enable "$@" && has_rh_enabled_repo "$@" ;; + dnf) dnf config-manager --set-enabled "$@" && has_rh_enabled_repo "$@" ;; + esac +} + +enable_sm_repo() +{ + ! has_rh_enabled_repo "$@" || return 0 + subscription-manager repos --enable "$@" || return $? + # On RedHat 8 above command may return 0 on failure with "Repositories disabled by configuration." + has_rh_enabled_repo "$@" +} + +check_epel() +{ + ! enable_rh_repo "epel" || return 0 + + # try to install epel-release from centos/extras or plesk/thirdparty repo + # and then try to update it to last version shipped by epel itself + # to make package upgradable with pum + "$package_manager" install --disablerepo 'PLESK_*' -q -y 'epel-release' --setopt='*.skip_if_unavailable=1' 2>/dev/null \ + || "$package_manager" install --disablerepo='*' --enablerepo 'PLESK_18_*-thirdparty' -q -y 'epel-release' \ + || "$package_manager" install -q -y "https://dl.fedoraproject.org/pub/epel/epel-release-latest-$os_version.noarch.rpm" \ + && "$package_manager" update -q -y 'epel-release' --setopt='*.skip_if_unavailable=1' 2>/dev/null + + # Ensure any other EPEL repos have cache for subsequent check for broken repos (AL9) + local epel_repos="$( + [ "$package_manager" != "dnf" ] || { + dnf repolist --enabled --cacheonly -q 2>/dev/null || + dnf repolist --enabled -q --setopt='*.skip_if_unavailable=1' + } | sed -n -e '1d' -e 's/^!\?\(epel\S\+\).*/\1/p' + )" + for repo in $epel_repos; do + "$package_manager" makecache --repo "$repo" -q + done + + ! has_rh_enabled_repo "epel" || return 0 + + report_no_repo "epel" + return $RET_FATAL +} + +check_codeready() +{ + local repo_rhel="codeready-builder-for-rhel-$os_version-$os_arch-rpms" + local repo_rhui="codeready-builder-for-rhel-$os_version-rhui-rpms" + local repo_rhui_alt="codeready-builder-for-rhel-$os_version-$os_arch-rhui-rpms" + local repo_rhui_alt2="rhui-codeready-builder-for-rhel-$os_version-$os_arch-rhui-rpms" + + ! enable_sm_repo "$repo_rhel" || return 0 + ! enable_rh_repo "$repo_rhui" || return 0 + ! enable_rh_repo "$repo_rhui_alt" || return 0 + ! enable_rh_repo "$repo_rhui_alt2" || return 0 + + report_no_repo "$repo_rhel" + return $RET_FATAL +} + +check_optional() +{ + local repo_rhel="rhel-$os_version-server-optional-rpms" + local repo_rhui="rhel-$os_version-server-rhui-optional-rpms" + + ! enable_sm_repo "$repo_rhel" || return 0 + ! enable_rh_repo "$repo_rhui" || return 0 + + report_no_repo "$repo_rhel" + return $RET_FATAL +} + +check_repos_rhel9() +{ + check_rh_config_manager || return $? + + local rc=0 + + check_epel || rc="$(( $rc | $? ))" + check_codeready || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + return $rc +} + +check_repos_almalinux9() +{ + check_rh_config_manager || return $? + + local rc=0 + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + # powertools is renamed to crb since AlmaLinux 9 + ! enable_rh_repo "crb" || return $rc + + report_no_repo "crb" + return $RET_FATAL +} + +check_repos_cloudlinux9() +{ + check_repos_almalinux9 "$@" +} + +check_repos_almalinux10() +{ + check_repos_almalinux9 "$@" +} + +check_repos_centos8() +{ + check_rh_config_manager || return $? + + local rc=0 + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + # names of repos are lowercased since 8.3 + ! enable_rh_repo "powertools" || return $rc + ! enable_rh_repo "PowerTools" || return $rc + + report_no_repo "powertools" + return $RET_FATAL +} + +check_repos_cloudlinux8() +{ + check_rh_config_manager || return $? + + local rc=0 + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + # names of repos are changed since 8.5 + ! enable_rh_repo "powertools" || return $rc + ! enable_rh_repo "cloudlinux-PowerTools" || return $rc + + report_no_repo "powertools" + return $RET_FATAL +} + +check_repos_rhel8() +{ + check_rh_config_manager || return $? + + local rc=0 + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + [ "$1" = "install" ] || return $rc + + check_codeready || rc="$(( $rc | $? ))" + + return $rc +} + +check_repos_almalinux8() +{ + check_repos_centos8 "$@" +} + +check_repos_rocky8() +{ + check_repos_centos8 "$@" +} + +check_repos_rhel7() +{ + check_rh_config_manager || return $? + + local rc=0 + + check_epel || rc="$(( $rc | $? ))" + check_optional || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + return $rc +} + +check_repos_centos7_based() +{ + check_rh_config_manager || return $? + + local rc=0 + + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + return $rc +} + +sed_escape() +{ + # Note: this is not a full implementation + echo -n "$1" | sed -e 's|\.|\\.|g' +} + +switch_eol_centos_repos() +{ + local old_mirrorlist_host="mirrorlist.centos.org" + local old_host="mirror.centos.org" + local new_host="vault.centos.org" + + grep -qFw "$old_host" /etc/yum.repos.d/CentOS-*.repo 2>/dev/null || return 0 + local backup="`mktemp -d "/tmp/yum.repos.d-$(date --rfc-3339=date)-XXXXXX"`" + ! [ -d "$backup" ] || cp -raT /etc/yum.repos.d "$backup" || : + + sed -i \ + -e "s|^\s*\(mirrorlist\b[^/]*//`sed_escape "$old_mirrorlist_host"`/.*\)$|#\1|" \ + -e "s|^#*\s*baseurl\b\([^/]*\)//`sed_escape "$old_host"`/\(.*\)$|baseurl\1//$new_host/\2|" \ + /etc/yum.repos.d/CentOS-*.repo + echo "YUM package manager repositories were backed up to '$backup' and switched from $old_host to $new_host ." >&2 +} + +check_repos_centos7() +{ + switch_eol_centos_repos + + check_repos_centos7_based "$@" +} + +check_repos_cloudlinux7() +{ + check_repos_centos7_based "$@" +} + +check_repos_virtuozzo7() +{ + check_repos_centos7_based "$@" +} + +find_apt_repo() +{ + local repo="$1" + + local dist_tag= + ! [ "$os_name" = "ubuntu" ] || dist_tag="a" + ! [ "$os_name" = "debian" ] || dist_tag="n" + + if [ -z "$_apt_cache_policy" ]; then + # extract info of each available release as a string which consists of 'tag=value' + # filter out releases with priority less or equal to 100 + _apt_cache_policy="$( + apt-cache policy \ + | grep "b=$pkg_arch" \ + | grep -Eo '([a-z]=[^,]+,?)*' \ + )" + fi + + local l="$(echo "$repo" | cut -f1 -d'/')" + local d="$(echo "$repo" | cut -f2 -d'/')" + local c="$(echo "$repo" | cut -f3 -d'/')" + + # try to find releases by distribution and component + echo "$_apt_cache_policy" \ + | grep -E "(^|,)l=$l(,|$)" \ + | grep -E "(^|,)$dist_tag=$d(,|$)" \ + | grep -E "(^|,)c=$c(,|$)" \ + | while IFS="$(printf '\n')" read rel && [ -n "$rel" ]; do + l="$(echo "$rel" | grep -Eo "(^|,)l=[^,]+" | cut -f2 -d"=")" + d="$(echo "$rel" | grep -Eo "(^|,)$dist_tag=[^,]+" | cut -f2 -d"=")" + c="$(echo "$rel" | grep -Eo "(^|,)c=[^,]+" | cut -f2 -d"=")" + echo "$l/$d/$c" + done +} + +apt_install_packages() +{ + DEBIAN_FRONTEND=noninteractive LANG=C PATH=/usr/sbin:/usr/bin:/sbin:/bin \ + apt-get -qq --assume-yes -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold -o APT::Install-Recommends=no \ + install "$@" +} + +# Takes a list of suites and disables them in APT sources. +# Multiline deb822 format is supported. +disable_apt_suites_deb822() +{ + local python3=/usr/bin/python3 + + "$python3" -c 'import aptsources.sourceslist' 2>/dev/null || + apt_install_packages python3-apt + + "$python3" -c ' +import sys + +from aptsources.sourceslist import SourcesList + + +suites_to_disable=set(sys.argv[1:]) + +sources_list = SourcesList(deb822=True) + +sources_changed = False +for src in sources_list: + if src.invalid: + continue + suites = getattr(src, "suites", ()) + if not suites: + continue + new_suites = [s for s in suites if s not in suites_to_disable] + if len(new_suites) != len(suites): + sources_changed = True + if len(new_suites) == 0: + src.disabled = True + else: + src.suites = new_suites + +if sources_changed: + sources_list.save() +' "$@" + + # Since we have changed the repositories list, we should re-read _apt_cache_policy on a next call + # of the find_apt_repo function. Hence we have to reset the value of the variable + _apt_cache_policy="" +} + +disable_apt_repo() +{ + local repos_to_disable="$(find_apt_repo "$1" | cut -d '/' -f 2,3 | sort | uniq)" + if [ -z "$repos_to_disable" ]; then + return 0 + fi + + echo "$repos_to_disable" \ + | while IFS= read -r repo_to_disable && [ -n "$repo_to_disable" ]; do + local distrib=${repo_to_disable%%/*} + local component=${repo_to_disable##*/} + find /etc/apt -name "*.list" -exec \ + sed -i -e "/^\s*#/! s/.*\s$distrib\s\+$component\b/# &/" {} + + done + + # Since we have changed the repositories list, we should re-read _apt_cache_policy on a next call + # of the find_apt_repo function. Hence we have to reset the value of the variable + _apt_cache_policy="" + + return 0 +} + +check_required_apt_repo() +{ + local repo="$1" + [ -z "$(find_apt_repo "$repo")" ] || return 0 + report_no_repo "$repo" + return $RET_FATAL +} + +check_unsupported_apt_repos_ubuntu() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + + local repos="$( + find_apt_repo "Ubuntu/[^,]+/[^,]+" | grep -v "Ubuntu/$os_codename.*/.*" + find_apt_repo "Debian[^,]*/[^,]+/[^,]+" + )" + [ -n "$repos" ] || return 0 + + echo "$repos" | while IFS="$(printf '\n')" read repo; do + report_unsupported_repo "$repo" + done + + [ "$mode" = "install" ] || return $RET_WARN + return $RET_FATAL +} + +check_repos_ubuntu18() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + local rc=0 + + check_required_apt_repo "Ubuntu/$os_codename/main" || rc="$(( $rc | $? ))" + check_required_apt_repo "Ubuntu/$os_codename/universe" || rc="$(( $rc | $? ))" + check_required_apt_repo "Ubuntu/$os_codename-updates/main" || rc="$(( $rc | $? ))" + check_required_apt_repo "Ubuntu/$os_codename-updates/universe" || rc="$(( $rc | $? ))" + check_unsupported_apt_repos_ubuntu "$mode" || rc="$(( $rc | $? ))" + + return $rc +} + + +check_repos_ubuntu() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + local rc=0 + + check_required_apt_repo "Ubuntu/$os_codename/main" || rc="$(( $rc | $? ))" + check_required_apt_repo "Ubuntu/$os_codename/universe" || rc="$(( $rc | $? ))" + check_unsupported_apt_repos_ubuntu "$mode" || rc="$(( $rc | $? ))" + + return $rc +} + +check_unsupported_apt_repos_debian() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + + local repos="$( + find_apt_repo "Debian Backports/$os_codename-backports/[^,]+" + find_apt_repo "Debian[^,]*/[^,]+/[^,]+" | grep -v "Debian.*/$os_codename.*/.*" + find_apt_repo "Ubuntu/[^,]+/[^,]+" + )" + [ -n "$repos" ] || return 0 + + echo "$repos" | while IFS="$(printf '\n')" read repo; do + report_unsupported_repo "$repo" + done + + [ "$mode" = "install" ] || return $RET_WARN + return $RET_FATAL +} + +check_repos_debian() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + local rc=0 + + if [ "$os_name" = "debian" -a "$os_version" -ge 12 ]; then + disable_apt_suites_deb822 "$os_codename-backports" + else + disable_apt_repo "Debian Backports/$os_codename-backports/[^,]+" + fi + + check_required_apt_repo "Debian/$os_codename/main" || rc="$(( $rc | $? ))" + check_unsupported_apt_repos_debian "$mode" || rc="$(( $rc | $? ))" + + return $rc +} + +# --- + +skip_checker_on_flag "Repository check" "/tmp/plesk-installer-skip-repository-check.flag" + +checker_main 'check_repos' "$1" diff --git a/root/parallels/pool/PSA_18.0.73_17971/examiners/sh_cmd.sh b/root/parallels/pool/PSA_18.0.73_17971/examiners/sh_cmd.sh new file mode 100755 index 0000000000..ed95d0acbb --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17971/examiners/sh_cmd.sh @@ -0,0 +1,7 @@ +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ "X${PLESK_INSTALLER_DEBUG}" = "X" ] || set -x +[ "X${PLESK_INSTALLER_STRICT_MODE}" = "X" ] || set -e + +exec "$@" diff --git a/root/parallels/pool/PSA_18.0.73_17971/plesk-18.0.73-ubt24.04-x86_64.inf3 b/root/parallels/pool/PSA_18.0.73_17971/plesk-18.0.73-ubt24.04-x86_64.inf3 new file mode 100644 index 0000000000..3d5e3de915 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17971/plesk-18.0.73-ubt24.04-x86_64.inf3 @@ -0,0 +1,927 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -----BEGIN PGP PUBLIC KEY BLOCK----- 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 VNnMRY8n =Hv0N -----END PGP PUBLIC KEY BLOCK----- + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + + + + + mysqlgroup + l10n + proftpd + webservers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + imapservers + + + + + + + + + + + + + + + + + + + imapservers + + + + + + + + + + + + + + mailman + spamassassin + drweb + sophos + courier + dovecot + + + + + + + + + + + + + + + + + + + + + + mailservers + + + + + + + + + + + + + + + + + + + + mailservers + + + + + + + + + + + + + + + + + + panel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + webservers + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + + + + + + + + + + + + + + + + php7.4 + + + + + + + + + + + + + + + + + + + + + + + + + + php8.3 + + + + + + + + + + + webservers + + + + + + + + webservers + + + + + + + + + + + + + + + + + + panel + + + + + + + + + + + + + panel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + panel + + + + + + + + + + + + + + + + + + + + panel + + + + + + + panel + + + + + + + + panel + + + + + + + panel + passenger + + + + + + ruby + + + + + + + panel + + + + + + panel + + + + + + panel + passenger + + + + + + + + + + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + panel + roundcube + postfix + dovecot + mod_fcgid + proftpd + webalizer + awstats + webservers + nginx + mysqlgroup + l10n + bind + wp-toolkit + advisor + git + xovi + imunify360 + fail2ban + modsecurity + sslit + letsencrypt + repair-kit + composer + monitoring + log-browser + ssh-terminal + site-import + sitejet + ntp-timesync + php8.3 + php8.4 + mfa + configurations-troubleshooter + + + panel + roundcube + postfix + dovecot + mod_fcgid + proftpd + webalizer + awstats + webservers + nginx + mysqlgroup + l10n + bind + wp-toolkit + advisor + git + xovi + imunify360 + fail2ban + modsecurity + sslit + letsencrypt + repair-kit + composer + monitoring + log-browser + ssh-terminal + site-import + sitejet + ntp-timesync + php8.1 + php8.2 + php8.3 + php8.4 + mfa + configurations-troubleshooter + resctrl + drweb + postgresql + spamassassin + ruby + gems-pre + nodejs + pmm + psa-firewall + watchdog + passenger + phpgroup + sophos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.73_17971/release.inf3 b/root/parallels/pool/PSA_18.0.73_17971/release.inf3 new file mode 100644 index 0000000000..4fb000283d --- /dev/null +++ b/root/parallels/pool/PSA_18.0.73_17971/release.inf3 @@ -0,0 +1,36 @@ + + + + + + + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.74_17897/release.inf3 b/root/parallels/pool/PSA_18.0.74_17897/release.inf3 new file mode 100644 index 0000000000..bcac0846cb --- /dev/null +++ b/root/parallels/pool/PSA_18.0.74_17897/release.inf3 @@ -0,0 +1,36 @@ + + + + + + + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.74_17941/release.inf3 b/root/parallels/pool/PSA_18.0.74_17941/release.inf3 new file mode 100644 index 0000000000..bcac0846cb --- /dev/null +++ b/root/parallels/pool/PSA_18.0.74_17941/release.inf3 @@ -0,0 +1,36 @@ + + + + + + + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.74_17968/release.inf3 b/root/parallels/pool/PSA_18.0.74_17968/release.inf3 new file mode 100644 index 0000000000..bcac0846cb --- /dev/null +++ b/root/parallels/pool/PSA_18.0.74_17968/release.inf3 @@ -0,0 +1,36 @@ + + + + + + + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.74_18022/examiners/check_broken_timezone.sh b/root/parallels/pool/PSA_18.0.74_18022/examiners/check_broken_timezone.sh new file mode 100755 index 0000000000..ee862642be --- /dev/null +++ b/root/parallels/pool/PSA_18.0.74_18022/examiners/check_broken_timezone.sh @@ -0,0 +1,255 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ -z "$PLESK_INSTALLER_DEBUG" ] || set -x +[ -z "$PLESK_INSTALLER_STRICT_MODE" ] || set -e + +export LC_ALL=C +unset GREP_OPTIONS + +RET_SUCCESS=0 +RET_WARN=1 +RET_FATAL=2 + +is_function_defined() +{ + local fn="$1" + case "$(type $fn 2>/dev/null)" in + *function*) + return 0 + ;; + esac + return 1 +} + +# @params are tags in format "key=value" +# Report body (human readable information) is read from stdin +# and copied to stderr. +make_error_report() +{ + local report_file="${PLESK_INSTALLER_ERROR_REPORT:-}" + + local python_bin= + for bin in "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2" "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3"; do + if [ -x "$bin" ]; then + python_bin="$bin" + break + fi + done + + if [ -n "$report_file" -a -x "$python_bin" ]; then + "$python_bin" -c 'import sys, json +report_file = sys.argv[1] +error = sys.stdin.read() + +sys.stderr.write(error) + +data = { + "error": error, +} + +for tag in sys.argv[2:]: + k, v = tag.split("=", 1) + data[k] = v + +with open(report_file, "a") as f: + json.dump(data, f) + f.write("\n") +' "$report_file" "date=$(date --utc --iso-8601=ns)" "$@" + else + cat - >&2 + fi +} + +detect_platform() +{ + . /etc/os-release + os_name="$ID" + os_version="${VERSION_ID%%.*}" + os_arch="$(uname -m)" + if [ -e /etc/debian_version ]; then + case "$os_arch" in + x86_64) pkg_arch="amd64" ;; + aarch64) pkg_arch="arm64" ;; + esac + if [ -n "$VERSION_CODENAME" ]; then + os_codename="$VERSION_CODENAME" + else + case "$os_name$os_version" in + debian10) os_codename="buster" ;; + debian11) os_codename="bullseye" ;; + debian12) os_codename="bookworm" ;; + ubuntu18) os_codename="bionic" ;; + ubuntu20) os_codename="focal" ;; + ubuntu22) os_codename="jammy" ;; + ubuntu24) os_codename="noble" ;; + esac + fi + fi + + case "$os_name$os_version" in + rhel7|centos7|cloudlinux7|virtuozzo7) + package_manager="yum" + ;; + rhel*|centos*|cloudlinux*|almalinux*|rocky*) + package_manager="dnf" + ;; + debian*|ubuntu*) + package_manager="apt" + ;; + esac + + if [ "$os_name" = "ubuntu" -o "$os_name" = "debian" ]; then + PRODUCT_ROOT_D="/opt/psa" + else + PRODUCT_ROOT_D="/usr/local/psa" + fi +} + +has_os_impl_function() +{ + local prefix="$1" + local fn="${prefix}_${os_name}${os_version}" + is_function_defined "$fn" +} + +call_os_impl_function() +{ + local prefix="$1" + shift + local fn="${prefix}_${os_name}${os_version}" + "$fn" "$@" +} + +skip_checker_on_flag() +{ + local name="$1" + local flag="$2" + + if [ -f "$flag" ]; then + echo "$name was skipped due to flag file." >&2 + exit $RET_SUCCESS + fi +} + +skip_checker_on_env() +{ + local name="$1" + local env="$2" + + if [ -n "$env" ]; then + echo "$name was skipped due to environment variable." >&2 + exit $RET_SUCCESS + fi +} + +checker_main() +{ + local fnprefix="$1" + shift + + detect_platform + # try to execute checker only if all attributes are detected + [ -n "$os_name" -a -n "$os_version" ] || return $RET_SUCCESS + + for checker in "${fnprefix}_${os_name}${os_version}" "${fnprefix}_${os_name}" "${fnprefix}"; do + if is_function_defined "$checker"; then + local rc=$RET_SUCCESS + "$checker" "$@" || rc=$? + [ "$(( $rc & $RET_FATAL ))" = "0" ] || return $RET_FATAL + [ "$(( $rc & $RET_WARN ))" = "0" ] || return $RET_WARN + return $rc + fi + done + return $RET_SUCCESS +} + +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +# If env variable PLESK_INSTALLER_ERROR_REPORT=path_to_file is specified then in case of error +# check-broken-tz.sh writes single line json report into it with the following fields: +# - "stage": "timezonefix" +# - "level": "error" +# - "errtype": "failure" +# - "date": time of error occurance ("2024-07-24T06:59:43,127545441+0000") +# - "error": human readable error message + +report_dpkg_configure_fail() +{ + local pkgname="$1" + make_error_report 'stage=timezonefix' 'level=error' 'errtype=dpkgconfigurefailed' <<-EOL + Could not configure the packages ( $pkgname ). See https://support.plesk.com/hc/en-us/articles/24721507961623-Plesk-provides-error-on-update-Package-tzdata-is-not-configured-yet for more details. + EOL +} + +report_get_tz_fail() +{ + make_error_report 'stage=timezonefix' 'level=error' 'errtype=gettzfailed' <<-EOL + Could not get the system timezone. See https://support.plesk.com/hc/en-us/articles/24721507961623-Plesk-provides-error-on-update-Package-tzdata-is-not-configured-yet for more details. + EOL +} + +report_set_tz_fail() +{ + local tz="$1" + + make_error_report 'stage=timezonefix' 'level=error' 'errtype=settzfailed' <<-EOL + Could not set the system timezone ( $tz ). See https://support.plesk.com/hc/en-us/articles/24721507961623-Plesk-provides-error-on-update-Package-tzdata-is-not-configured-yet for more details. + EOL +} + +get_current_tz() +{ + [ -L /etc/localtime ] || return 1 + + local tz + tz="$(readlink -m /etc/localtime)" || return 1 + [ -f "$tz" ] || return 1 + case "$tz" in + /usr/share/zoneinfo/*) ;; + *) return 1;; + esac + tz="${tz#/usr/share/zoneinfo/}" + [ -n "$tz" ] || return 1 + + echo -n "${tz}" +} + +check_timezone_ubuntu() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + + # PPP-65676: Plesk update fails on ubuntu if timezone is CET + if dpkg-query --showformat='${db:Status-Status}\n' --show 'tzdata' | grep -wq 'half-configured'; then + local origtz + origtz=$(get_current_tz) + if [ $? != 0 ]; then + report_get_tz_fail + return $RET_WARN + fi + if ! timedatectl set-timezone 'Etc/UTC'; then + timedatectl set-timezone "$origtz" + report_set_tz_fail 'Etc/UTC' + return $RET_WARN + fi + if ! dpkg --configure 'tzdata'; then + timedatectl set-timezone "$origtz" + report_dpkg_configure_fail 'tzdata' + return $RET_WARN + fi + if ! timedatectl set-timezone "$origtz"; then + report_set_tz_fail "$origtz" + return $RET_WARN + fi + fi + + return 0 +} + +# --- + +skip_checker_on_flag "Broken timezone check" "/tmp/plesk-installer-skip-check-broken-timezone.flag" + +checker_main 'check_timezone' "$1" diff --git a/root/parallels/pool/PSA_18.0.74_18022/examiners/congratulations.sh b/root/parallels/pool/PSA_18.0.74_18022/examiners/congratulations.sh new file mode 100755 index 0000000000..907c5ba782 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.74_18022/examiners/congratulations.sh @@ -0,0 +1,50 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +out() +{ + echo -e "\t$*" >&2 +} + +print_urls() +{ + plesk login 2>/dev/null | sed -e $'s|^|\t * |' >&2 +} + +print_congratulations() +{ + local mode="$1" # 'install' or 'upgrade' + local process= + [ "$mode" = "install" ] && process="installation" || process="upgrade" + + out + out " Congratulations!" + out + out "The $process has been finished. Plesk is now running on your server." + out + if [ "$mode" = "install" ]; then + out "To complete the configuration process, browse either of URLs:" + print_urls + out + fi + out "Use the username 'admin' to log in. To log in as 'admin', use the 'plesk login' command." + out "You can also log in as 'root' using your 'root' password." + out + out "Use the 'plesk' command to manage the server. Run 'plesk help' for more info." + out + out "Use the following commands to start and stop the Plesk web interface:" + out "'systemctl start psa.service' and 'systemctl stop psa.service' respectively." + out + if [ "$mode" = "install" ]; then + out "If you would like to migrate your subscriptions from other hosting panel" + out "or older Plesk version to this server, please check out our assistance" + out "options: https://www.plesk.com/professional-services/" + out + fi +} + +unset GREP_OPTIONS + +print_congratulations "$1" +# Force showing text when used as AI post-examiner +exit 1 diff --git a/root/parallels/pool/PSA_18.0.74_18022/examiners/disk_space_check.sh b/root/parallels/pool/PSA_18.0.74_18022/examiners/disk_space_check.sh new file mode 100755 index 0000000000..1fdfb44037 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.74_18022/examiners/disk_space_check.sh @@ -0,0 +1,542 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ -z "$PLESK_INSTALLER_DEBUG" ] || set -x +[ -z "$PLESK_INSTALLER_STRICT_MODE" ] || set -e + +export LC_ALL=C +unset GREP_OPTIONS + +RET_SUCCESS=0 +RET_WARN=1 +RET_FATAL=2 + +is_function_defined() +{ + local fn="$1" + case "$(type $fn 2>/dev/null)" in + *function*) + return 0 + ;; + esac + return 1 +} + +# @params are tags in format "key=value" +# Report body (human readable information) is read from stdin +# and copied to stderr. +make_error_report() +{ + local report_file="${PLESK_INSTALLER_ERROR_REPORT:-}" + + local python_bin= + for bin in "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2" "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3"; do + if [ -x "$bin" ]; then + python_bin="$bin" + break + fi + done + + if [ -n "$report_file" -a -x "$python_bin" ]; then + "$python_bin" -c 'import sys, json +report_file = sys.argv[1] +error = sys.stdin.read() + +sys.stderr.write(error) + +data = { + "error": error, +} + +for tag in sys.argv[2:]: + k, v = tag.split("=", 1) + data[k] = v + +with open(report_file, "a") as f: + json.dump(data, f) + f.write("\n") +' "$report_file" "date=$(date --utc --iso-8601=ns)" "$@" + else + cat - >&2 + fi +} + +detect_platform() +{ + . /etc/os-release + os_name="$ID" + os_version="${VERSION_ID%%.*}" + os_arch="$(uname -m)" + if [ -e /etc/debian_version ]; then + case "$os_arch" in + x86_64) pkg_arch="amd64" ;; + aarch64) pkg_arch="arm64" ;; + esac + if [ -n "$VERSION_CODENAME" ]; then + os_codename="$VERSION_CODENAME" + else + case "$os_name$os_version" in + debian10) os_codename="buster" ;; + debian11) os_codename="bullseye" ;; + debian12) os_codename="bookworm" ;; + ubuntu18) os_codename="bionic" ;; + ubuntu20) os_codename="focal" ;; + ubuntu22) os_codename="jammy" ;; + ubuntu24) os_codename="noble" ;; + esac + fi + fi + + case "$os_name$os_version" in + rhel7|centos7|cloudlinux7|virtuozzo7) + package_manager="yum" + ;; + rhel*|centos*|cloudlinux*|almalinux*|rocky*) + package_manager="dnf" + ;; + debian*|ubuntu*) + package_manager="apt" + ;; + esac + + if [ "$os_name" = "ubuntu" -o "$os_name" = "debian" ]; then + PRODUCT_ROOT_D="/opt/psa" + else + PRODUCT_ROOT_D="/usr/local/psa" + fi +} + +has_os_impl_function() +{ + local prefix="$1" + local fn="${prefix}_${os_name}${os_version}" + is_function_defined "$fn" +} + +call_os_impl_function() +{ + local prefix="$1" + shift + local fn="${prefix}_${os_name}${os_version}" + "$fn" "$@" +} + +skip_checker_on_flag() +{ + local name="$1" + local flag="$2" + + if [ -f "$flag" ]; then + echo "$name was skipped due to flag file." >&2 + exit $RET_SUCCESS + fi +} + +skip_checker_on_env() +{ + local name="$1" + local env="$2" + + if [ -n "$env" ]; then + echo "$name was skipped due to environment variable." >&2 + exit $RET_SUCCESS + fi +} + +checker_main() +{ + local fnprefix="$1" + shift + + detect_platform + # try to execute checker only if all attributes are detected + [ -n "$os_name" -a -n "$os_version" ] || return $RET_SUCCESS + + for checker in "${fnprefix}_${os_name}${os_version}" "${fnprefix}_${os_name}" "${fnprefix}"; do + if is_function_defined "$checker"; then + local rc=$RET_SUCCESS + "$checker" "$@" || rc=$? + [ "$(( $rc & $RET_FATAL ))" = "0" ] || return $RET_FATAL + [ "$(( $rc & $RET_WARN ))" = "0" ] || return $RET_WARN + return $rc + fi + done + return $RET_SUCCESS +} + +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +# If env variable PLESK_INSTALLER_ERROR_REPORT=path_to_file is specified then in case of error +# disk_space_check.sh writes single line json report into it with the following fields: +# - "stage": "diskspacecheck" +# - "level": "error" +# - "errtype": "notenoughdiskspace" +# - "volume": volume with not enough diskspace (e.g. "/") +# - "required": required diskspace on the volume, human readable (e.g. "600 MB") +# - "available": available diskspace on the volume, human readable (e.g. "255 MB") +# - "needtofree": amount of diskspace which should be freed on the volume, human readable (e.g. "345 MB") +# - "date": time of error occurance ("2020-03-24T06:59:43,127545441+0000") +# - "error": human readable error message ("There is not enough disk space available in the / directory.") + +# Required values below for Full installation are in MB. See 'du -cs -BM /*' and 'df -Pm'. + +required_disk_space_cloudlinux7() +{ + case "$1" in + /opt) echo 900 ;; + /usr) echo 4400 ;; + /var) echo 600 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_cloudlinux8() +{ + case "$1" in + /opt) echo 1200 ;; + /usr) echo 4400 ;; + /var) echo 700 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_centos7() +{ + case "$1" in + /opt) echo 900 ;; + /usr) echo 4100 ;; + /var) echo 600 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_centos8() +{ + case "$1" in + /opt) echo 900 ;; + /usr) echo 4500 ;; + /var) echo 800 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_virtuozzo7() +{ + required_disk_space_centos7 "$1" +} + +required_disk_space_rhel7() +{ + required_disk_space_centos7 "$1" +} + +required_disk_space_rhel8() +{ + required_disk_space_centos8 "$1" +} + +required_disk_space_almalinux8() +{ + required_disk_space_centos8 "$1" +} + +required_disk_space_rocky8() +{ + required_disk_space_centos8 "$1" +} + +required_disk_space_rhel9() +{ + case "$1" in + /opt) echo 500 ;; + /usr) echo 4000 ;; + /var) echo 800 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_almalinux9() +{ + required_disk_space_rhel9 "$1" +} + +required_disk_space_almalinux10() +{ + required_disk_space_almalinux9 "$1" +} + +required_disk_space_cloudlinux9() +{ + required_disk_space_rhel9 "$1" +} + +required_disk_space_debian10() +{ + case "$1" in + /opt) echo 1800 ;; + /usr) echo 2300 ;; + /var) echo 1700 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_debian11() +{ + case "$1" in + /opt) echo 1500 ;; + /usr) echo 3100 ;; + /var) echo 1800 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_debian12() +{ + case "$1" in + /opt) echo 2700 ;; + /usr) echo 2500 ;; + /var) echo 2200 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_debian13() +{ + case "$1" in + /opt) echo 2700 ;; + /usr) echo 2500 ;; + /var) echo 2200 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_ubuntu18() +{ + case "$1" in + /opt) echo 900 ;; + /usr) echo 1800 ;; + /var) echo 600 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_ubuntu20() +{ + case "$1" in + /opt) echo 1800 ;; + /usr) echo 2900 ;; + /var) echo 1600 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_ubuntu22() +{ + case "$1" in + /opt) echo 1800 ;; + /usr) echo 3900 ;; + /var) echo 1900 ;; + /tmp) echo 100 ;; + esac +} + +required_disk_space_ubuntu24() +{ + case "$1" in + /opt) echo 3200 ;; + /usr) echo 1800 ;; + /var) echo 2400 ;; + /tmp) echo 100 ;; + esac +} + +required_update_upgrade_disk_space() +{ + case "$1" in + /opt) echo 100 ;; + /usr) echo 300 ;; + /var) echo 600 ;; + /tmp) echo 100 ;; + esac +} + +clean_tmp() +{ + local volume="$1" + local path="/tmp" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'systemd-tmpfiles --clean --prefix $path'" + systemd-tmpfiles --clean --prefix "$path" 2>&1 +} + +clean_yum() +{ + local volume="$1" + local path="/var/cache/yum" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'yum clean all'" + yum clean all 2>&1 + + # The command above doesn't clean untracked repos (missing in configuration), clean if left > 2 Mb + [ "`du -sm "$path" | awk '{ print $1 }'`" -gt 2 ] || return 0 + echo "Cleaning $path via 'rm -rf $path/*'" + rm -rf "$path"/* 2>&1 +} + +clean_dnf() +{ + local volume="$1" + local path="/var/cache/dnf" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'dnf clean all'" + dnf clean all 2>&1 +} + +clean_apt() +{ + local volume="$1" + local path="/var/cache/apt" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'apt-get clean'" + apt-get clean 2>&1 +} + +clean_journal() +{ + local volume="$1" + local path="/var/log/journal" + is_path_on_volume "$path" "$volume" || return 0 + + # Note that --rotate may cause more space to be freed, but may also cause more space to be used + echo "Cleaning $path via 'journalctl --vacuum-time 1d'" + journalctl --vacuum-time 1d 2>&1 +} + +clean_ext_packages() +{ + local volume="$1" + local path="$PRODUCT_ROOT_D/var/modules-packages" + is_path_on_volume "$path" "$volume" || return 0 + + echo "Cleaning $path via 'rm -rf $path/*'" + rm -rf "$path"/* 2>&1 +} + +# @param $1 target directory +mount_point() +{ + df -Pm $1 | awk 'NR==2 { print $6 }' +} + +# @param $1 target directory +available_disk_space() +{ + df -Pm $1 | awk 'NR==2 { print $4 }' +} + +is_path_on_volume() +{ + local path="$1" + local volume="$2" + [ -d "$path" ] && [ "`mount_point "$path"`" = "$volume" ] +} + +# @param $1 target directory +# @param $2 mode (install/upgrade/update) +req_disk_space() +{ + if [ "$2" != "install" ]; then + required_update_upgrade_disk_space "$1" + return + fi + + has_os_impl_function "required_disk_space" || { + echo "There are no requirements defined for $os_name$os_version." >&2 + echo "Disk space check cannot be performed." >&2 + exit $RET_WARN + } + call_os_impl_function "required_disk_space" "$1" +} + +human_readable_size() +{ + echo "$1" | awk ' + function human(x) { + s = "MGTEPYZ"; + while (x >= 1000 && length(s) > 1) { + x /= 1024; s = substr(s, 2); + } + # 0.05 below will make sure the value is rounded up + return sprintf("%.1f %sB", x + 0.05, substr(s, 1, 1)); + } + { print human($1); }' +} + +# @param $1 target directory +# @param $2 required disk space +# @param $3 check only flag (don't emit errors) +check_available_disk_space() +{ + local volume="$1" + local required="$2" + local check_only="${3:-}" + local available="$(available_disk_space "$volume")" + if [ "$available" -lt "$required" ]; then + local needtofree + needtofree="`human_readable_size $((required - available))`" + [ -n "$check_only" ] || + make_error_report 'stage=diskspacecheck' 'level=error' 'errtype=notenoughdiskspace' \ + "volume=$volume" "required=$required MB" "available=$available MB" "needtofree=$needtofree" \ + <<-EOL + There is not enough disk space available in the $1 directory. + You need to free up $needtofree. + EOL + return "$RET_FATAL" + fi +} + +# @param $1 target directory +# @param $2 required disk space +clean_and_check_available_disk_space() +{ + if [ -n "$PLESK_INSTALLER_FORCE_CLEAN_DISK_SPACE" ] || ! check_available_disk_space "$@" --check-only; then + clean_disk_space "$1" + check_available_disk_space "$@" + fi +} + +# Cleans up disk space on the volume +clean_disk_space() +{ + local volume="$1" + for cleanup_func in clean_tmp clean_yum clean_dnf clean_apt clean_journal clean_ext_packages; do + "$cleanup_func" "$volume" + done +} + +# @param $1 mode (install/upgrade/update) +clean_and_check_disk_space() +{ + local mode="$1" + local shared=0 + + for target_directory in /opt /usr /var /tmp; do + local required=$(req_disk_space "$target_directory" "$mode") + [ -n "$required" ] || return "$RET_WARN" + + if is_path_on_volume "$target_directory" "/"; then + shared="$((shared + required))" + else + clean_and_check_available_disk_space "$target_directory" "$required" || return $? + fi + done + + clean_and_check_available_disk_space "/" "$shared" || return $? +} + +checker_main 'clean_and_check_disk_space' "$1" diff --git a/root/parallels/pool/PSA_18.0.74_18022/examiners/license_key_check.php b/root/parallels/pool/PSA_18.0.74_18022/examiners/license_key_check.php new file mode 100644 index 0000000000..465fdbe9b8 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.74_18022/examiners/license_key_check.php @@ -0,0 +1,111 @@ += 10.0.0 */ +if (!is_array($vers)) { + $vers = [$vers]; +} + +$match = false; +foreach ($vers as $ver) { + if (!is_array($ver)) { + $match |= strtok($ver, ".") == strtok($targetVersion, "."); + } else { + $match |= ("any" == $ver[0] || version_compare($ver[0], $targetVersion) <= 0) && + ("any" == $ver[1] || version_compare($ver[1], $targetVersion) >= 0); + } +} + +if ($match) { + fwrite(STDERR, "You do not need to upgrade the current license key.\n"); + fwrite(STDOUT, "License upgrade check to $targetVersion can be skipped.\n"); + fwrite(STDOUT, "Plesk versions compatible with the license key: " . preg_replace('/\n\s*/', '', var_export($vers, true)) . "\n"); + finish(0); +} + +if (!function_exists('ka_is_key_upgrade_available')) { + // Plesk 17.0 + fwrite(STDERR, "Cannot check whether Plesk license key upgrade is available.\n"); + finish(1, false); +} + +$si = getServerInfo(); +$result = ka_is_key_upgrade_available($prod, $targetVersion, $si); + +$isConfused = false; +switch ($result['code']) { + case RESULT_LICENSE_OK: + fwrite(STDERR, "The licensing server accepted the key upgrade request.\n"); + fwrite(STDERR, "License upgrade to $targetVersion is available.\n"); + fwrite(STDERR, "Response from the licensing server: {$result['message']}\n"); + finish(0); + case RESULT_NETWORK_PROBLEM: + fwrite(STDERR, "Unable to connect to the licensing server to check if license upgrade is available.\n"); + fwrite(STDERR, "Error message: {$result['message']}\n"); + finish(2, false); + case RESULT_LICENSE_PROBLEM: + fwrite(STDERR, "Warning: Your Plesk license key cannot be upgraded.\n"); + fwrite(STDERR, "Response from the licensing server: {$result['message']}\n"); + finish(2); + default: + $isConfused = true; + // fall-through + case RESULT_ERROR: + // This includes "Software Update Service (SUS) is not found for the given license key" case, but also many others. + fwrite(STDERR, "Failed to check whether a new license key is available.\n"); + fwrite(STDERR, "Error message: {$result['message']}\n"); + if ($isConfused) { + fwrite(STDERR, "Error code: {$result['code']}\n"); + } + finish(2, !$isConfused); +} diff --git a/root/parallels/pool/PSA_18.0.74_18022/examiners/package_manager_check.sh b/root/parallels/pool/PSA_18.0.74_18022/examiners/package_manager_check.sh new file mode 100755 index 0000000000..b089061d97 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.74_18022/examiners/package_manager_check.sh @@ -0,0 +1,224 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ -z "$PLESK_INSTALLER_DEBUG" ] || set -x +[ -z "$PLESK_INSTALLER_STRICT_MODE" ] || set -e + +export LC_ALL=C +unset GREP_OPTIONS + +RET_SUCCESS=0 +RET_WARN=1 +RET_FATAL=2 + +is_function_defined() +{ + local fn="$1" + case "$(type $fn 2>/dev/null)" in + *function*) + return 0 + ;; + esac + return 1 +} + +# @params are tags in format "key=value" +# Report body (human readable information) is read from stdin +# and copied to stderr. +make_error_report() +{ + local report_file="${PLESK_INSTALLER_ERROR_REPORT:-}" + + local python_bin= + for bin in "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2" "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3"; do + if [ -x "$bin" ]; then + python_bin="$bin" + break + fi + done + + if [ -n "$report_file" -a -x "$python_bin" ]; then + "$python_bin" -c 'import sys, json +report_file = sys.argv[1] +error = sys.stdin.read() + +sys.stderr.write(error) + +data = { + "error": error, +} + +for tag in sys.argv[2:]: + k, v = tag.split("=", 1) + data[k] = v + +with open(report_file, "a") as f: + json.dump(data, f) + f.write("\n") +' "$report_file" "date=$(date --utc --iso-8601=ns)" "$@" + else + cat - >&2 + fi +} + +detect_platform() +{ + . /etc/os-release + os_name="$ID" + os_version="${VERSION_ID%%.*}" + os_arch="$(uname -m)" + if [ -e /etc/debian_version ]; then + case "$os_arch" in + x86_64) pkg_arch="amd64" ;; + aarch64) pkg_arch="arm64" ;; + esac + if [ -n "$VERSION_CODENAME" ]; then + os_codename="$VERSION_CODENAME" + else + case "$os_name$os_version" in + debian10) os_codename="buster" ;; + debian11) os_codename="bullseye" ;; + debian12) os_codename="bookworm" ;; + ubuntu18) os_codename="bionic" ;; + ubuntu20) os_codename="focal" ;; + ubuntu22) os_codename="jammy" ;; + ubuntu24) os_codename="noble" ;; + esac + fi + fi + + case "$os_name$os_version" in + rhel7|centos7|cloudlinux7|virtuozzo7) + package_manager="yum" + ;; + rhel*|centos*|cloudlinux*|almalinux*|rocky*) + package_manager="dnf" + ;; + debian*|ubuntu*) + package_manager="apt" + ;; + esac + + if [ "$os_name" = "ubuntu" -o "$os_name" = "debian" ]; then + PRODUCT_ROOT_D="/opt/psa" + else + PRODUCT_ROOT_D="/usr/local/psa" + fi +} + +has_os_impl_function() +{ + local prefix="$1" + local fn="${prefix}_${os_name}${os_version}" + is_function_defined "$fn" +} + +call_os_impl_function() +{ + local prefix="$1" + shift + local fn="${prefix}_${os_name}${os_version}" + "$fn" "$@" +} + +skip_checker_on_flag() +{ + local name="$1" + local flag="$2" + + if [ -f "$flag" ]; then + echo "$name was skipped due to flag file." >&2 + exit $RET_SUCCESS + fi +} + +skip_checker_on_env() +{ + local name="$1" + local env="$2" + + if [ -n "$env" ]; then + echo "$name was skipped due to environment variable." >&2 + exit $RET_SUCCESS + fi +} + +checker_main() +{ + local fnprefix="$1" + shift + + detect_platform + # try to execute checker only if all attributes are detected + [ -n "$os_name" -a -n "$os_version" ] || return $RET_SUCCESS + + for checker in "${fnprefix}_${os_name}${os_version}" "${fnprefix}_${os_name}" "${fnprefix}"; do + if is_function_defined "$checker"; then + local rc=$RET_SUCCESS + "$checker" "$@" || rc=$? + [ "$(( $rc & $RET_FATAL ))" = "0" ] || return $RET_FATAL + [ "$(( $rc & $RET_WARN ))" = "0" ] || return $RET_WARN + return $rc + fi + done + return $RET_SUCCESS +} + +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +check_package_manager_deb_based() +{ + local output= + output="`dpkg --audit 2>&1`" || output="$output"$'\n'"'dpkg --audit' finished with error code $?." + + if [ -n "$output" ]; then + make_error_report 'stage=packagemanagercheck' 'level=error' 'errtype=brokenpackages' <<-EOL + The system package manager reports the following problems: + + $output + + To continue with the installation, you need to resolve these issues + using the procedure below: + + 1. Make sure you have a full server snapshot. Although the + following steps are usually safe, they can still cause + data loss or irreversible changes. + 2. Run 'dpkg --configure -a'. This command can fix some of the + issues. However, it may fail. Regardless if it fails or not, + proceed with the following steps. + 3. Run 'PLESK_INSTALLER_SKIP_PACKAGE_MANAGER_CHECK=1 plesk installer update --skip-cleanup'. + Instead of 'update', you may need to use the command you used + previously (for example, 'upgrade' or 'install'). + 4. The next step depends on the outcome of the previous one: + - If step 3 was completed with the "You already have the latest + version of product(s) and all the selected components installed. + Installation will not continue." message, + run 'plesk repair installation'. + - If step 3 failed, run 'dpkg --audit'. This command can show you + packages that need to be reinstalled. To reinstall them, run + 'apt-get install --reinstall '. + 5. Run 'plesk installer update' to revert temporary changes and + validate that the issues are resolved. If the command fails or + triggers this check again, contact Plesk support. + + For more information, see + https://support.plesk.com/hc/en-us/articles/12871173047447-Plesk-update-on-Debian-Ubuntu-fails-dpkg-was-interrupted-you-must-manually-run-dpkg-configure-a-to-correct-the-problem + EOL + return "$RET_FATAL" + fi +} + +check_package_manager_debian() +{ + check_package_manager_deb_based +} + +check_package_manager_ubuntu() +{ + check_package_manager_deb_based +} + +skip_checker_on_env "Package manager check" "$PLESK_INSTALLER_SKIP_PACKAGE_MANAGER_CHECK" +skip_checker_on_flag "Package manager check" "/tmp/plesk-installer-skip-package-manager-check.flag" +checker_main 'check_package_manager' "$@" diff --git a/root/parallels/pool/PSA_18.0.74_18022/examiners/panel_preupgrade_checker.php b/root/parallels/pool/PSA_18.0.74_18022/examiners/panel_preupgrade_checker.php new file mode 100644 index 0000000000..ce983f8614 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.74_18022/examiners/panel_preupgrade_checker.php @@ -0,0 +1,2441 @@ +_checkMainIP(); //:INFO: Checking for main IP address https://support.plesk.com/hc/articles/12377857361687 + $this->_checkMySQLDatabaseUserRoot(); //:INFO: Plesk user "root" for MySQL database servers have not access to phpMyAdmin https://support.plesk.com/hc/articles/12378148229399 + $this->_checkProftpdIPv6(); //:INFO: #94489 FTP service proftpd cannot be started by xinetd if IPv6 is disabled https://support.plesk.com/hc/articles/12377796102807 + $this->_checkSwCollectdIntervalSetting(); //:INFO: #105405 https://support.plesk.com/hc/articles/213362569 + $this->_checkApacheStatus(); + $this->_checkImmutableBitOnPleskFiles(); //:INFO: #128414 https://support.plesk.com/hc/articles/12377589682327 + $this->_checkAbilityToChmodInDumpd(); //:INFO: ERROR while trying to backup MySQL database. https://support.plesk.com/hc/en-us/articles/12377010033943 + $this->_checkIpcollectionReference(); //:INFO: #72751 https://support.plesk.com/hc/articles/12377666752279 + $this->_checkApsApplicationContext(); //:INFO: Broken contexts of the APS applications can lead to errors at building Apache web server configuration https://support.plesk.com/hc/articles/12377671820311 + $this->_checkApsTablesInnoDB(); + $this->_checkCustomWebServerConfigTemplates(); //:INFO: #PPPM-1195 https://support.plesk.com/hc/articles/12377740416151 + $this->_checkMixedCaseDomainIssues(); //:INFO: #PPPM-4284 https://support.plesk.com/hc/en-us/articles/12377171904151 + + if (PleskOS::isDebLike()) { + $this->_checkSymLinkToOptPsa(); //:INFO: Check that symbolic link /usr/local/psa actually exists on Debian-like OSes https://support.plesk.com/hc/articles/12377511731991 + } + + if (Util::isVz()) { + $this->_checkShmPagesLimit(); //:INFO: PSA service does not start. Unable to allocate shared memory segment. https://support.plesk.com/hc/articles/12377744827927 + + if (PleskOS::isRedHatLike()) { + $this->_checkMailDriversConflict(); //:INFO: #PPPM-955 https://support.plesk.com/hc/articles/12378148767895 + } + } + } + + $this->_checkForCryptPasswords(); + $this->_checkMysqlServersTable(); //:INFO: Checking existing table mysql.servers + $this->_checkPleskTCPPorts(); //:INFO: Check the availability of Plesk TCP ports https://support.plesk.com/hc/articles/12377821243159 + + if (Util::isWindows()) { + $this->_checkPhprcSystemVariable(); //:INFO: #PPPM-294 Checking for PHPRC system variable + $this->_unknownISAPIfilters(); //:INFO: Checking for unknown ISAPI filters and show warning https://support.plesk.com/hc/articles/213913765 + $this->_checkMSVCR(); //:INFO: Just warning about possible issues related to Microsoft Visual C++ Redistributable Packages https://support.plesk.com/hc/articles/115000201014 + $this->_checkIisFcgiDllVersion(); //:INFO: Check iisfcgi.dll file version https://support.plesk.com/hc/articles/12378148258199 + $this->_checkCDONTSmailrootFolder(); //:INFO: After upgrade Plesk change permissions on folder of Collaboration Data Objects (CDO) for NTS (CDONTS) to default, https://support.plesk.com/hc/articles/12377887661335 + $this->_checkNullClientLogin(); //:INFO: #118963 https://support.plesk.com/hc/articles/12378122202391 + $this->checkDomainControllerLocation(); //:INFO: https://support.plesk.com/hc/articles/12377107094167 + } + } + + //:INFO: PSA service does not start. Unable to allocate shared memory segment. https://support.plesk.com/hc/articles/12377744827927 + function _checkShmPagesLimit() + { + $log = Log::getInstance("Checking for limit shmpages", true); + $ubc = Util::getUserBeanCounters(); + if ((int)$ubc['shmpages']['limit'] < 40960) { + $log->emergency("Virtuozzo Container set the \"shmpages\" limit to {$ubc['shmpages']['limit']}, which is too low. This may cause the sw-engine service not to start. To resolve this issue, refer to the article at https://support.plesk.com/hc/articles/12377744827927"); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: #PPPM-294 + function _checkPhprcSystemVariable() + { + $log = Log::getInstance("Checking for PHPRC system variable", true); + + $phprc = getenv('PHPRC'); + + if ($phprc) { + $log->emergency('The environment variable PHPRC is present in the system. This variable may lead to upgrade failure. Please delete this variable from the system environment.'); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: ERROR while trying to backup MySQL database. https://support.plesk.com/hc/en-us/articles/12377010033943 + function _checkAbilityToChmodInDumpd() + { + $log = Log::getInstance("Checking the possibility to change the permissions of files in the DUMP_D directory", true); + + $dump_d = Util::getSettingFromPsaConf('DUMP_D'); + if (is_null($dump_d)) { + $log->warning('Unable to obtain the path to the directory defined by the DUMP_D parameter. Check that the DUMP_D parameter is set in the /etc/psa/psa.conf file.'); + $log->resultWarning(); + return; + } + + $file = $dump_d . '/pre_upgrade_test_checkAbilityToChmodInDumpd'; + + if (false === file_put_contents($file, 'test')) { + $log->emergency('Unable to write in the ' . $dump_d . ' directory. The upgrade procedure will fail. Check that the folder exists and you have write permissions for it, and repeat upgrading. '); + $log->resultWarning(); + return; + } else { + $result = @chmod($file, 0600); + unlink($file); + if (!$result) { + $log->emergency( + 'Unable to change the permissions of files in the ' . $dump_d . ' directory. ' + . 'The upgrade procedure will fail. Please refer to https://support.plesk.com/hc/articles/12377010033943 for details.' + ); + $log->resultError(); + return; + } + } + $log->resultOk(); + } + + //:INFO: #128414 https://support.plesk.com/hc/articles/12377589682327 + function _checkImmutableBitOnPleskFiles() + { + $log = Log::getInstance("Checking Panel files for the immutable bit attribute"); + + $cmd = 'lsattr -R /usr/local/psa/ 2>/dev/null |awk \'{split($1, a, ""); if (a[5] == "i") {print;}}\''; + $output = Util::exec($cmd, $code); + $files = explode('\n', $output); + + if (!empty($output)) { + $log->info('The immutable bit attribute of the following Panel files can interrupt the upgrade procedure:'); + foreach ($files as $file) { + $log->info($file); + } + $log->emergency('Files with the immutable bit attribute were found. Please check https://support.plesk.com/hc/articles/12377589682327 for details.'); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: #PPPM-1195 https://support.plesk.com/hc/articles/12377740416151 + function _checkCustomWebServerConfigTemplates() + { + $log = Log::getInstance("Checking for custom web server configuration templates"); + $pleskDir = Util::getSettingFromPsaConf('PRODUCT_ROOT_D'); + $customTemplatesPath = $pleskDir . '/admin/conf/templates/custom'; + + if (is_dir($customTemplatesPath)) { + $log->warning("Directory {$customTemplatesPath} for custom web server configuration templates was found. Custom templates might be incompatible with a new Plesk version, and this might lead to failure to generate web server configuration files. Remove the directory to get rid of this warning. " + . "Please check https://support.plesk.com/hc/articles/12377740416151 for details."); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: #PPPM-955 https://support.plesk.com/hc/articles/12378148767895 + function _checkMailDriversConflict() + { + $log = Log::getInstance("Checking for a Plesk mail drivers conflict"); + + if (((true === PackageManager::isInstalled('psa-mail-pc-driver') || true === PackageManager::isInstalled('plesk-mail-pc-driver')) + && true === PackageManager::isInstalled('psa-qmail')) + || ((true === PackageManager::isInstalled('psa-mail-pc-driver') || true === PackageManager::isInstalled('plesk-mail-pc-driver')) + && true === PackageManager::isInstalled('psa-qmail-rblsmtpd'))) { + $log->warning("Plesk upgrade by EZ templates failed if psa-mail-pc-driver and psa-qmail or psa-qmail-rblsmtpd packages are installed. " + . "Please check https://support.plesk.com/hc/articles/12378148767895 for details."); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: #118963 https://support.plesk.com/hc/articles/12378122202391 + function _checkNullClientLogin() + { + $log = Log::getInstance("Checking for accounts with empty user names"); + + $mysql = PleskDb::getInstance(); + $sql = "SELECT domains.id, domains.name, clients.login FROM domains LEFT JOIN clients ON clients.id=domains.cl_id WHERE clients.login is NULL"; + $nullLogins = $mysql->fetchAll($sql); + + if (!empty($nullLogins)) { + $log->warning('There are accounts with empty user names. This problem can cause the backup or migration operation to fail. Please see https://support.plesk.com/hc/articles/12378122202391 for the solution.'); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: #105405 https://support.plesk.com/hc/articles/213362569 + function _checkSwCollectdIntervalSetting() + { + $log = Log::getInstance("Checking the 'Interval' parameter in the sw-collectd configuration file"); + + $collectd_config = '/etc/sw-collectd/collectd.conf'; + if (file_exists($collectd_config)) { + if (!is_file($collectd_config) || !is_readable($collectd_config)) + return; + + $config_content = Util::readfileToArray($collectd_config); + if ($config_content) { + foreach ($config_content as $line) { + if (preg_match('/Interval\s*\d+$/', $line, $match)) { + if (preg_match('/Interval\s*10$/', $line, $match)) { + $log->warning('If you leave the default value of the "Interval" parameter in the ' . $collectd_config . ', sw-collectd may heavily load the system. Please see https://support.plesk.com/hc/articles/213362569 for details.'); + $log->resultWarning(); + return; + } + $log->resultOk(); + return; + } + } + $log->warning('If you leave the default value of the "Interval" parameter in the ' . $collectd_config . ', sw-collectd may heavily load the system. Please see https://support.plesk.com/hc/articles/213362569 for details.'); + $log->resultWarning(); + return; + } + } + } + + private function _checkApacheStatus() + { + $log = Log::getInstance("Checking Apache status"); + + $apacheCtl = file_exists('/usr/sbin/apache2ctl') ? '/usr/sbin/apache2ctl' : '/usr/sbin/apachectl'; + + if (!is_executable($apacheCtl)) { + return; + } + + $resultCode = 0; + Util::Exec("$apacheCtl -t 2>/dev/null", $resultCode); + + if (0 !== $resultCode) { + $log->error("The Apache configuration is broken. Run '$apacheCtl -t' to see the detailed info."); + $log->resultError(); + return; + } + + $log->resultOk(); + } + + //:INFO: #72751 https://support.plesk.com/hc/articles/12377666752279 + function _checkIpcollectionReference() + { + $log = Log::getInstance("Checking consistency of the IP addresses list in the Panel database"); + + $mysql = PleskDb::getInstance(); + $sql = "SELECT 1 FROM ip_pool, clients, IpAddressesCollections, domains, DomainServices, IP_Addresses WHERE DomainServices.ipCollectionId = IpAddressesCollections.ipCollectionId AND domains.id=DomainServices.dom_id AND clients.id=domains.cl_id AND ipAddressId NOT IN (select id from IP_Addresses) AND IP_Addresses.id = ip_pool.ip_address_id AND pool_id = ip_pool.id GROUP BY pool_id"; + $brokenIps = $mysql->fetchAll($sql); + $sql = "select 1 from DomainServices, domains, clients, ip_pool where ipCollectionId not in (select IpAddressesCollections.ipCollectionId from IpAddressesCollections) and domains.id=DomainServices.dom_id and clients.id = domains.cl_id and ip_pool.id = clients.pool_id and DomainServices.type='web' group by ipCollectionId"; + $brokenCollections = $mysql->fetchAll($sql); + + if (!empty($brokenIps) || !empty($brokenCollections)) { + $log->warning('Some database entries related to Panel IP addresses are corrupted. Please see https://support.plesk.com/hc/articles/12377666752279 for the solution.'); + $log->resultWarning(); + return; + } + + $log->resultOk(); + } + + //:INFO: Broken contexts of the APS applications can lead to errors at building Apache web server configuration https://support.plesk.com/hc/articles/12377671820311 + function _checkApsApplicationContext() + { + $log = Log::getInstance("Checking installed APS applications"); + $mysql = PleskDb::getInstance(); + $sql = "SELECT * FROM apsContexts WHERE (pleskType = 'hosting' OR pleskType = 'subdomain') AND subscriptionId = 0"; + $brokenContexts = $mysql->fetchAll($sql); + + if (!empty($brokenContexts)) { + $log->warning('Some database entries related to the installed APS applications are corrupted. Please see https://support.plesk.com/hc/articles/12377671820311 for the solution.'); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: #94489 FTP service proftpd cannot be started by xinetd if IPv6 is disabled https://support.plesk.com/hc/articles/12377796102807 + function _checkProftpdIPv6() + { + $log = Log::getInstance("Checking proftpd settings"); + + $inet6 = '/proc/net/if_inet6'; + if (!file_exists($inet6) || !@file_get_contents($inet6)) { + $proftpd_config = '/etc/xinetd.d/ftp_psa'; + if (!is_file($proftpd_config) || !is_readable($proftpd_config)) + return null; + + $config_content = Util::readfileToArray($proftpd_config); + if ($config_content) { + for ($i=0; $i<=count($config_content)-1; $i++) { + if (preg_match('/flags.+IPv6$/', $config_content[$i], $match)) { + $log->warning('The proftpd FTP service will fail to start in case the support for IPv6 is disabled on the server. Please check https://support.plesk.com/hc/articles/12377796102807 for details.'); + $log->resultWarning(); + return; + } + } + } + } + $log->resultOk(); + } + + //:INFO: Check the availability of Plesk Panel TCP ports + function _checkPleskTCPPorts() + { + $log = Log::getInstance('Checking the availability of Plesk Panel TCP ports'); + + $plesk_ports = array('8880' => 'Plesk Panel non-secure HTTP port', '8443' => 'Plesk Panel secure HTTPS port'); + + $mysql = PleskDb::getInstance(); + $sql = "select ip_address from IP_Addresses"; + $ip_addresses = $mysql->fetchAll($sql); + $warning = false; + if (count($ip_addresses)>0) { + if (Util::isLinux()) { + $ipv4 = Util::getIPv4ListOnLinux(); + $ipv6 = Util::getIPv6ListOnLinux(); + if ($ipv6) { + $ipsInSystem = array_merge($ipv4, $ipv6); + } else { + $ipsInSystem = $ipv4; + } + } else { + $ipsInSystem = Util::getIPListOnWindows(); + } + foreach ($ip_addresses as $ip) { + foreach ($plesk_ports as $port => $description) { + if (PleskValidator::validateIPv4($ip['ip_address']) && in_array($ip['ip_address'], $ipsInSystem)) { + $fp = @fsockopen($ip['ip_address'], $port, $errno, $errstr, 1); + } elseif (PleskValidator::validateIPv6($ip['ip_address']) && in_array($ip['ip_address'], $ipsInSystem)) { + $fp = @fsockopen('[' . $ip['ip_address'] . ']', $port, $errno, $errstr, 1); + } else { + $log->warning('IP address registered in Plesk is invalid or broken: ' . $ip['ip_address']); + $log->resultWarning(); + return; + } + if (!$fp) { + // $errno 110 means "timed out", 111 means "refused" + $log->info('Unable to connect to IP address ' . $ip['ip_address'] . ' on ' . $description . ' ' . $port . ': ' . $errstr); + $warning = true; + } + } + } + } + if ($warning) { + $log->warning('Unable to connect to some Plesk ports. Please see ' . LOG_PATH . ' for details. Find the full list of the required open ports at https://support.plesk.com/hc/articles/12377821243159 '); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: Plesk user "root" for MySQL database servers have not access to phpMyAdmin https://support.plesk.com/hc/articles/12378148229399 + function _checkMySQLDatabaseUserRoot() + { + $log = Log::getInstance('Checking existence of Plesk user "root" for MariaDB/MySQL database servers'); + + $psaroot = Util::getSettingFromPsaConf('PRODUCT_ROOT_D'); + + if (PleskVersion::is_below_17_9()) { + $phpMyAdminConfFile = $psaroot . '/admin/htdocs/domains/databases/phpMyAdmin/libraries/config.default.php'; + } else { + $phpMyAdminConfFile = $psaroot . '/phpMyAdmin/libraries/config.default.php'; + } + + if (file_exists($phpMyAdminConfFile)) { + $phpMyAdminConfFileContent = file_get_contents($phpMyAdminConfFile); + if (!preg_match("/\[\'AllowRoot\'\]\s*=\s*true\s*\;/", $phpMyAdminConfFileContent)) { + $mysql = PleskDb::getInstance(); + $sql = "select login, data_bases.name as db_name, displayName as domain_name from db_users, data_bases, domains where db_users.db_id = data_bases.id and data_bases.dom_id = domains.id and data_bases.type = 'mysql' and login = 'root'"; + $dbusers = $mysql->fetchAll($sql); + + foreach ($dbusers as $user) { + $log->warning('The database user "' . $user['login'] . '" (database "' . $user['db_name'] . '" at "' . $user['domain_name'] . '") has no access to phpMyAdmin. Please check https://support.plesk.com/hc/articles/12378148229399 for more details.'); + $log->resultWarning(); + return; + } + } + } + + $log->resultOk(); + } + + //:INFO: After upgrade Plesk change permissions on folder of Collaboration Data Objects (CDO) for NTS (CDONTS) to default, https://support.plesk.com/hc/articles/12377887661335 + function _checkCDONTSmailrootFolder() + { + $log = Log::getInstance('Checking for CDONTS mailroot folder'); + + $mailroot = Util::getSystemDisk() . 'inetpub\mailroot\pickup'; + + if (is_dir($mailroot)) { + $log->warning('After upgrade you have to add write permissions to psacln group on folder ' . $mailroot . '. Please, check https://support.plesk.com/hc/articles/12377887661335 for more details.'); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: Check iisfcgi.dll file version https://support.plesk.com/hc/articles/12378148258199 + function _checkIisFcgiDllVersion() + { + $log = Log::getInstance("Checking the iisfcgi.dll file version"); + + $windir = Util::getSystemRoot(); + $iisfcgi = $windir . '\system32\inetsrv\iisfcgi.dll'; + if (file_exists($iisfcgi)) { + $version = Util::getFileVersion($iisfcgi); + if (version_compare($version, '7.5.0', '>') + && version_compare($version, '7.5.7600.16632', '<')) { + $log->warning('File iisfcgi.dll version ' . $version . ' is outdated. Please, check article https://support.plesk.com/hc/articles/12378148258199 for details'); + return; + } + } + $log->resultOk(); + } + + //:INFO: Checking for main IP address https://support.plesk.com/hc/articles/12377857361687 + function _checkMainIP() + { + $log = Log::getInstance("Checking for main IP address"); + + $mysql = PleskDb::getInstance(); + $sql = 'select * from IP_Addresses'; + $ips = $mysql->fetchAll($sql); + $mainexists = false; + foreach ($ips as $ip) { + if (isset($ip['main'])) { + if ($ip['main'] == 'true') { + $mainexists = true; + } + } else { + $log->info('No field "main" in table IP_Addresses.'); + $log->resultOk(); + return; + } + } + + if (!$mainexists) { + $warn = 'Unable to find "main" IP address in psa database. Please, check https://support.plesk.com/hc/articles/12377857361687 for more details.'; + $log->warning($warn); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: Checking existing table mysql.servers https://support.plesk.com/hc/articles/12377850098455 + function _checkMysqlServersTable() + { + $log = Log::getInstance('Checking table "servers" in database "mysql"'); + + $mySQLServerVersion = Util::getMySQLServerVersion(); + if (version_compare($mySQLServerVersion, '5.1.0', '>=')) { + $credentials = Util::getDefaultClientMySQLServerCredentials(); + + if (preg_match('/AES-128-CBC/', $credentials['admin_password'])) { + $log->info('The administrator\'s password for the default MariaDB/MySQL server is encrypted.'); + return; + } + + $mysql = new DbClientMysql($credentials['host'], $credentials['admin_login'], $credentials['admin_password'] , 'information_schema', $credentials['port']); + if (!$mysql->hasErrors()) { + $sql = 'SELECT * FROM information_schema.TABLES WHERE TABLE_SCHEMA="mysql" and TABLE_NAME="servers"'; + $servers = $mysql->fetchAll($sql); + if (empty($servers)) { + $warn = 'The table "servers" in the database "mysql" does not exist. Please check https://support.plesk.com/hc/articles/12377850098455 for details.'; + $log->warning($warn); + $log->resultWarning(); + return; + } + } + } + $log->resultOk(); + } + + //:INFO: Check that there is symbolic link /usr/local/psa on /opt/psa on Debian-like Oses https://support.plesk.com/hc/articles/12377511731991 + function _checkSymLinkToOptPsa() + { + $log = Log::getInstance('Checking symbolic link /usr/local/psa on /opt/psa'); + + $link = @realpath('/usr/local/psa/version'); + if (!preg_match('/\/opt\/psa\/version/', $link, $macthes)) { + $warn = "The symbolic link /usr/local/psa does not exist or has wrong destination. Read article https://support.plesk.com/hc/articles/12377511731991 to fix the issue."; + $log->warning($warn); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + //:INFO: Checking for unknown ISAPI filters and show warning https://support.plesk.com/hc/articles/213913765 + function _unknownISAPIfilters() + { + $log = Log::getInstance('Detecting installed ISAPI filters'); + + if (Util::isUnknownISAPIfilters()) { + $warn = 'Please read carefully article https://support.plesk.com/hc/articles/213913765, for avoiding possible problems caused by unknown ISAPI filters.'; + $log->warning($warn); + $log->resultWarning(); + + return; + } + $log->resultOk(); + } + + //:INFO: Warning about possible issues related to Microsoft Visual C++ Redistributable Packages ?https://support.plesk.com/hc/articles/115000201014 + function _checkMSVCR() + { + $log = Log::getInstance('Microsoft Visual C++ Redistributable Packages'); + + $warn = 'Please read carefully article https://support.plesk.com/hc/articles/115000201014, for avoiding possible problems caused by Microsoft Visual C++ Redistributable Packages.'; + $log->info($warn); + + return; + } + + function _checkForCryptPasswords() + { + //:INFO: Prevent potential problem with E: Couldn't configure pre-depend plesk-core for psa-firewall, probably a dependency cycle. + $log = Log::getInstance('Detecting if encrypted passwords are used'); + + $db = PleskDb::getInstance(); + $sql = "SELECT COUNT(*) AS cnt FROM accounts WHERE type='crypt' AND password not like '$%';"; + $r = $db->fetchAll($sql); + + if ($r[0]['cnt'] != '0') + { + $warn = 'There are ' . $r[0]['cnt'] . ' accounts with passwords encrypted using a deprecated algorithm. Please refer to https://support.plesk.com/hc/articles/12377596588311 for the instructions about how to change the password type to plain.'; + + $log->warning($warn); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + function _checkApsTablesInnoDB() + { + $log = Log::getInstance('Checking if apsc database tables have InnoDB engine'); + + $db = PleskDb::getInstance(); + $apsDatabase = $db->fetchOne("select val from misc where param = 'aps_database'"); + $sql = "SELECT TABLE_NAME FROM information_schema.TABLES where TABLE_SCHEMA = '$apsDatabase' and ENGINE = 'MyISAM'"; + $myISAMTables = $db->fetchAll($sql); + if (!empty($myISAMTables)) { + $myISAMTablesList = implode(', ', array_map('reset', $myISAMTables)); + $warn = 'The are tables in apsc database with MyISAM engine: ' . $myISAMTablesList . '. It would be updated to InnoDB engine.'; + $log->warning($warn); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + function _checkMixedCaseDomainIssues() + { + $log = Log::getInstance("Checking for domains with mixed case names", true); + $db = PleskDb::getInstance(); + + + $domains = $db->fetchAll("select id, name, displayName from domains"); + $problemDomains = array(); + foreach ($domains as $domain) { + if (strtolower($domain['name']) == $domain['name']) { + continue; + } + $problemDomains[] = $domain; + } + if (count($problemDomains)) { + $msg = "Found one or more domains with mixed case names. Such domains may have trouble working with the \"FPM application server by Apache\" handler.\n" . + implode("\n", array_map(function($row) { + return "{$row['id']}\t{$row['displayName']}\t{$row['name']}"; + }, $problemDomains)) . "\n" . + "A manual fix can be applied to resolve the issue. Read https://support.plesk.com/hc/en-us/articles/12377171904151 for details."; + $log->warning($msg); + $log->resultWarning(); + return; + } + $log->resultOk(); + } + + private function checkDomainControllerLocation() + { + $log = Log::getInstance("Checking for Active Directory Domain Controller and Plesk on the same server", true); + $cmd = '"' . rtrim(Util::getPleskRootPath(), '\\') . '\admin\bin\serverconf.exe" --list'; + $output = Util::exec($cmd, $code); + if (preg_match("/IS_DOMAIN_CONTROLLER:\s*true/", $output)) { + $log->warning('Active Directory Domain Controller and Plesk are on the same server. Read https://support.plesk.com/hc/articles/12377107094167 for details.'); + $log->resultWarning(); + } else { + $log->resultOk(); + } + } +} + +class Plesk175Requirements +{ + public function validate() + { + if (PleskInstallation::isInstalled() && PleskVersion::is_below_17_5() && Util::isLinux()) { + //:INFO: Check that DUMP_TMP_D is not inside of (or equal to) DUMP_D + $this->_checkDumpTmpD(); + } + } + + public function _checkDumpTmpD() + { + $log = Log::getInstance('Checking the DUMP_TMP_D directory'); + + $dumpD = Util::getSettingFromPsaConf('DUMP_D'); + if (is_null($dumpD)) { + $log->warning('Unable to obtain the path to the directory defined by the DUMP_D parameter. Check that the DUMP_D parameter is set in the /etc/psa/psa.conf file.'); + $log->resultWarning(); + return; + } + $dumpTmpD = Util::getSettingFromPsaConf('DUMP_TMP_D'); + if (is_null($dumpTmpD)) { + $log->warning('Unable to obtain the path to the directory defined by the DUMP_TMP_D parameter. Check that the DUMP_TMP_D parameter is set in the /etc/psa/psa.conf file.'); + $log->resultWarning(); + return; + } + + if (strpos(rtrim($dumpTmpD, '/') . '/', rtrim($dumpD, '/') . '/') === 0) { + $log->error(sprintf('The directory DUMP_TMP_D = %s should not be inside of (or equal to) the directory DUMP_D = %s. Fix these parameters in the /etc/psa/psa.conf file.', $dumpTmpD, $dumpD)); + $log->resultError(); + } + + $log->resultOk(); + } +} + +class Plesk178Requirements +{ + public function validate() + { + if (PleskInstallation::isInstalled() && Util::isWindows() && PleskVersion::is_below_17_9()) { + $this->_checkPleskVhostsDir(); + } + + if (PleskVersion::is_below_17_8()) { + $this->checkTomcat(); + $this->checkMultiServer(); + } + } + + private function checkTomcat() + { + if (Util::isWindows()) { + $tomcatRegBase = '\\PLESK\\PSA Config\\Config\\Packages\\tomcat\\tomcat'; + /* Supported versions on windows are tomcat5 and tomcat7 */ + $key = '/v InstallDir'; + $isInstalled = Util::regQuery($tomcatRegBase . '7', $key, true) || Util::regQuery($tomcatRegBase . '5', $key, true); + } else { + $isInstalled = PackageManager::isInstalled('psa-tomcat-configurator'); + } + + if ($isInstalled + || (PleskDb::getInstance()->fetchOne('show tables like \'WebApps\'') + && PleskDb::getInstance()->fetchOne('select count(*) from WebApps')) + ) { + $log = Log::getInstance('Checking Apache Tomcat installation'); + $message = <<warning($message); + } + } + + private function checkMultiServer() + { + if (!PleskModule::isMultiServer()) { + return; + } + + $log = Log::getInstance('Checking Plesk Multi Server installation'); + $message = <<emergency($message); + $log->resultError(); + } + + private function _checkPleskVhostsDir() + { + $log = Log::getInstance('Checking mount volume for HTTPD_VHOSTS_D directory'); + + $vhostsDir = rtrim(Util::regPleskQuery('HTTPD_VHOSTS_D'), "\\"); + Util::exec("mountvol \"{$vhostsDir}\" /L", $code); + if ($code == 0) { + $msg = "A disk volume is mounted to the {$vhostsDir} directory." . + " It will be unmounted during the Plesk upgrade." . + " As a result, all hosted websites will become unavailable." . + " Make sure to remount the volume to the {$vhostsDir} directory after the upgrade."; + $log->emergency($msg); + $log->resultError(); + return; + } + + $log->resultOk(); + } +} + +class Plesk18Requirements +{ + public function validate() + { + if (PleskInstallation::isInstalled()) { + if (Util::isLinux() && PleskOS::isRedHatLike()) { + $this->_checkYumDuplicates(); + } + $this->checkPdUsersLoginCollation(); + $this->checkDomainsGuidCollation(); + $this->checkClientsGuidCollation(); + $this->checkModSecurityModules(); + $this->checkIsFirewallPackageConfigured(); + $this->checkDefaultDnsServerComponent(); + } + } + + private function checkModSecurityModules() + { + /* Issue actual for Plesk for Windows below 18.0.32 (ModSecurity 2.9.3 and below) */ + if (!Util::isWindows() || PleskVersion::is_18_0_32_or_above()) { + return; + } + + $log = Log::getInstance('Checking the status of ModSecurity IIS modules'); + $modules = Util::exec(Util::getSystemRoot() . '\system32\inetsrv\AppCmd.exe list module', $code); + if ($code) { + $log->warning('Unable to get the list of IIS modules.'); + } else { + if (strpos($modules, 'ModSecurity IIS (32bits)') === false && strpos($modules, 'ModSecurity IIS (64bits)') === false) { + $log->error('Either 32-bit or 64-bit ModSecurity IIS module is absent.'); + $log->resultError(); + } + } + } + + // INFO: PPP-46440 checking package duplicates https://support.plesk.com/hc/articles/12377586286615 + private function _checkYumDuplicates() + { + $log = Log::getInstance('Checking for RPM packages duplicates'); + if (!file_exists("/usr/bin/package-cleanup")) + { + $log->info("package-cleanup is not found. Check for duplicates was skipped"); + return; + } + + $output = Util::exec("/usr/bin/package-cleanup --cacheonly -q --dupes", $code); + if ($code != 0) + { + // some repos may have no cache at this point or may be broken at all + // retry with cache recreation and skipping broken repos + $output = Util::exec("/usr/bin/package-cleanup -q --dupes --setopt='*.skip_if_unavailable=1'", $code); + } + if ($code != 0) + { + $message = "Unable to detect package duplicates: /usr/bin/package-cleanup --dupes returns $code." . + "Output is:\n$output"; + $log->warning($message); + $log->resultWarning(); + return; + } + + if (empty($output)) { + return; + } + + $message = "Your package system contains duplicated packages, which can lead to broken Plesk update:\n\n" . + "$output\n\n" . + "Please check https://support.plesk.com/hc/articles/12377586286615 for more details."; + + $log->error($message); + $log->resultError(); + } + + private function checkPdUsersLoginCollation() + { + $log = Log::getInstance('Checking for Protected Directory Users with duplicates in login field.'); + $duplicates = PleskDb::getInstance()->fetchAll( + 'SELECT pd_id, LOWER(login) AS login_ci, COUNT(*) AS duplicates FROM pd_users' . + ' GROUP BY pd_id, login_ci' . + ' HAVING duplicates > 1' + ); + if (!empty($duplicates)) { + $log->error( + "Duplicate logins of Protected Directory Users were found in the database:\n\n" . + implode("\n", array_column($duplicates, 'login_ci')) . "\n\n" . + "Please check https://support.plesk.com/hc/en-us/articles/360014743900 for more details." + ); + $log->resultError(); + } + } + + private function checkDomainsGuidCollation() + { + $log = Log::getInstance('Checking "domains" table with duplicates in guid field.'); + $duplicates = PleskDb::getInstance()->fetchAll( + 'SELECT guid, COUNT(*) AS duplicates FROM domains' + . ' GROUP BY guid' + . ' HAVING duplicates > 1' + ); + + if (!empty($duplicates)) { + $log->error( + "Duplicate guid were found in the 'domains' table:\n\n" . + implode("\n", array_column($duplicates, 'guid')) . "\n\n" + . "Please check https://support.plesk.com/hc/en-us/articles/12377018323351 for more details." + ); + $log->resultError(); + } + } + + private function checkClientsGuidCollation() + { + $log = Log::getInstance('Checking "clients" table with duplicates in guid field.'); + $duplicates = PleskDb::getInstance()->fetchAll( + 'SELECT guid, COUNT(*) AS duplicates FROM clients' + . ' GROUP BY guid' + . ' HAVING duplicates > 1' + ); + + if (!empty($duplicates)) { + $log->error( + "Duplicate guid were found in the 'clients' table:\n\n" . + implode("\n", array_column($duplicates, 'guid')) . "\n\n" + . "Please check https://support.plesk.com/hc/en-us/articles/360016801679 for more details." + ); + $log->resultError(); + } + } + + private function checkIsFirewallPackageConfigured() + { + if (!Util::isLinux()) { + return; + } + + $log = Log::getInstance("Checking if any rules are configured in the Firewall extension"); + $db = PleskDb::getInstance(); + if ($db->fetchOne("SHOW TABLES LIKE 'module_firewall_rules'") + && $db->fetchOne("SELECT COUNT(*) FROM module_firewall_rules") + ) { + $message = "Plesk Firewall no longer stores its configuration in Plesk database since " + . "Plesk Obsidian 18.0.52. Since you're upgrading to the latest version late, " + . "if you wish to retain the Plesk Firewall extension and its configuration, " + . "you need to follow additional steps after the upgrade. Please check " + . "https://support.plesk.com/hc/en-us/articles/16198248236311 for more details."; + $log->warning($message); + } + } + + private function checkDefaultDnsServerComponent() + { + if (Util::isLinux()) { + return; + } + + $path = '\\PLESK\\PSA Config\\Config\\Packages\\dnsserver'; + $key = '/ve'; + + if ('bind' === Util::regQuery($path, $key, true)) { + $log = Log::getInstance("Checking default DNS server component"); + $message = <<emergency($message); + $log->resultError(); + } + } +} + +class PleskModule +{ + public static function isInstalledWatchdog() + { + return PleskModule::_isInstalled('watchdog'); + } + + public static function isInstalledFileServer() + { + return PleskModule::_isInstalled('fileserver'); + } + + public static function isInstalledFirewall() + { + return PleskModule::_isInstalled('firewall'); + } + + public static function isInstalledVpn() + { + return PleskModule::_isInstalled('vpn'); + } + + public static function isMultiServer() + { + return PleskModule::_isInstalled('plesk-multi-server') || + PleskModule::_isInstalled('plesk-multi-server-node'); + } + + protected static function _isInstalled($module) + { + $sql = "SELECT * FROM Modules WHERE name = '{$module}'"; + + $pleskDb = PleskDb::getInstance(); + $row = $pleskDb->fetchRow($sql); + + return (empty($row) ? false : true); + } +} + +class PleskInstallation +{ + public static function validate() + { + if (!self::isInstalled()) { + $log = Log::getInstance('Checking for Plesk installation'); + $log->step('Plesk installation is not found. You will have no problems with upgrade, go on and install ' + . PleskVersion::getLatestPleskVersionAsString() . ' (https://www.plesk.com/)'); + return; + } + self::detectVersion(); + } + + public static function isInstalled() + { + $rootPath = Util::getPleskRootPath(); + if (empty($rootPath) || !file_exists($rootPath)) { + return false; + } + return true; + } + + private static function detectVersion() + { + $log = Log::getInstance('Installed Plesk version/build: ' . PleskVersion::getVersionAndBuild(), false); + + $currentVersion = PleskVersion::getVersion(); + if (version_compare($currentVersion, PLESK_VERSION, 'eq')) { + $err = 'You have already installed the latest version ' . PleskVersion::getLatestPleskVersionAsString() . '. '; + $err .= 'Tool must be launched prior to upgrade to ' . PleskVersion::getLatestPleskVersionAsString() . ' for the purpose of getting a report on potential problems with the upgrade.'; + $log->info($err); + exit(0); + } + + if (!PleskVersion::isUpgradeSupportedVersion()) { + $err = 'Unable to find Plesk 17.x. '; + $err .= 'Tool must be launched prior to upgrade to ' . PleskVersion::getLatestPleskVersionAsString() . ' for the purpose of getting a report on potential problems with the upgrade.'; + fatal($err); + } + } +} + +class PleskVersion +{ + const PLESK_17_MIN_VERSION = '13.0.0'; /* historically it has been started as 13.0 */ + + const PLESK_17_MAX_VERSION = '17.9.13'; + + const PLESK_18_MIN_VERSION = '18.0.14'; + + public static function is17x_or_above() + { + return version_compare(self::getVersion(), self::PLESK_17_MIN_VERSION, '>='); + } + + public static function is_below_17_5() + { + return version_compare(self::getVersion(), '17.5.0', '<'); + } + + public static function is_below_17_8() + { + return version_compare(self::getVersion(), '17.8.0', '<'); + } + + public static function is_below_17_9() + { + return version_compare(self::getVersion(), '17.9.0', '<'); + } + + public static function is_18_0_32_or_above() + { + return version_compare(self::getVersion(), '18.0.32', '>='); + } + + public static function getVersion() + { + $version = self::getVersionAndBuild(); + if (!preg_match('/([0-9]+[.][0-9]+[.][0-9]+)/', $version, $matches)) { + fatal("Incorrect Plesk version format. Current version: {$version}"); + } + return $matches[1]; + } + + public static function getVersionAndBuild() + { + $versionPath = Util::getPleskRootPath().'/version'; + if (!file_exists($versionPath)) { + fatal("Plesk version file is not exists $versionPath"); + } + $version = file_get_contents($versionPath); + $version = trim($version); + return $version; + } + + public static function getLatestPleskVersionAsString() + { + return 'Plesk ' . PLESK_VERSION; + } + + public static function isUpgradeSupportedVersion() + { + return self::is17x_or_above(); + } +} + +class Log +{ + private $errors; + private $warnings; + private $emergency; + private $logfile; + private $step; + private $step_header; + + /** @var array */ + private $errorsContent = []; + + /** @var array */ + private $warningsContent = []; + + public static function getInstance($step_msg = '', $step_number = true) + { + static $_instance = null; + if (is_null($_instance)) { + $_instance = new Log(); + } + if ($step_msg) { + $_instance->step($step_msg, $step_number); + } + + return $_instance; + } + + private function __construct() + { + $this->log_init(); + @unlink($this->logfile); + } + + private function log_init() + { + $this->step = 0; + $this->errors = 0; + $this->warnings = 0; + $this->emergency = 0; + $this->logfile = LOG_PATH; + $this->step_header = "Unknown step is running"; + } + + public function getErrors() + { + return $this->errors; + } + + public function getWarnings() + { + return $this->warnings; + } + + public function getEmergency() + { + return $this->emergency; + } + + public function fatal($msg) + { + $this->errors++; + + $this->errorsContent[] = $msg; + $content = $this->get_log_string($msg, 'FATAL_ERROR'); + fwrite(STDERR, $content); + $this->write($content); + } + + public function error($msg) + { + $this->errors++; + + $this->errorsContent[] = $msg; + $content = $this->get_log_string($msg, 'ERROR'); + fwrite(STDERR, $content); + $this->write($content); + } + + public function warning($msg) + { + $this->warnings++; + + $this->warningsContent[] = $msg; + $content = $this->get_log_string($msg, 'WARNING'); + fwrite(STDERR, $content); + $this->write($content); + } + + public function emergency($msg) + { + $this->emergency++; + + $this->errorsContent[] = $msg; + $content = $this->get_log_string($msg, 'EMERGENCY'); + fwrite(STDERR, $content); + $this->write($content); + } + + public function step($msg, $useNumber=false) + { + $this->step_header = $msg; + + echo PHP_EOL; + $this->write(PHP_EOL); + + if ($useNumber) { + $msg = "STEP " . $this->step . ": {$msg}..."; + $this->step++; + } else { + $msg = "{$msg}..."; + } + + $this->info($msg); + } + + public function resultOk() + { + $this->info('Result: OK'); + } + + public function resultWarning() + { + $this->info('Result: WARNING'); + } + + public function resultError() + { + $this->info('Result: ERROR'); + } + + public function info($msg) + { + $content = $this->get_log_string($msg, 'INFO'); + echo $content; + $this->write($content); + } + + public function debug($msg) + { + $this->write($this->get_log_string($msg, 'DEBUG')); + } + + public function dumpStatistics() + { + $errors = $this->errors + $this->emergency; + $str = "Errors found: $errors; Warnings found: {$this->warnings}"; + echo PHP_EOL . $str . PHP_EOL . PHP_EOL; + } + + private function get_log_string($msg, $type) + { + if (getenv('VZ_UPGRADE_SCRIPT')) { + switch ($type) { + case 'FATAL_ERROR': + case 'ERROR': + case 'WARNING': + case 'EMERGENCY': + $content = "[{$type}]: {$this->step_header} DESC: {$msg}" . PHP_EOL; + break; + default: + $content = "[{$type}]: {$msg}" . PHP_EOL; + } + } else if (getenv('AUTOINSTALLER_VERSION')) { + $content = "{$type}: {$msg}" . PHP_EOL; + } else { + $date = date('Y-m-d h:i:s'); + $content = "[{$date}][{$type}] {$msg}" . PHP_EOL; + } + + return $content; + } + + public function write($content, $file = null, $mode='a+') + { + $logfile = $file ? $file : $this->logfile; + $fp = fopen($logfile, $mode); + fwrite($fp, $content); + fclose($fp); + } + + private function getJsonFileName() + { + return (Util::isWindows() ? + rtrim(Util::regPleskQuery('PRODUCT_DATA_D'), "\\") : + Util::getSettingFromPsaConf('PRODUCT_ROOT_D') + ) . '/var/' . LOG_JSON; + } + + public function writeJsonFile() + { + $data = [ + 'version' => PRE_UPGRADE_SCRIPT_VERSION, + 'errorsFound' => $this->errors + $this->emergency, + 'errors' => $this->errorsContent, + 'warningsFound' => $this->warnings, + 'warnings' => $this->warningsContent, + ]; + file_put_contents($this->getJsonFileName(), json_encode($data)); + } +} + +class PleskDb +{ + var $_db = null; + + public function __construct($dbParams) + { + switch($dbParams['db_type']) { + case 'mysql': + $this->_db = new DbMysql( + $dbParams['host'], $dbParams['login'], $dbParams['passwd'], $dbParams['db'], $dbParams['port'] + ); + break; + + case 'jet': + $this->_db = new DbJet($dbParams['db']); + break; + + case 'mssql': + $this->_db = new DbMsSql( + $dbParams['host'], $dbParams['login'], $dbParams['passwd'], $dbParams['db'], $dbParams['port'] + ); + break; + + default: + fatal("{$dbParams['db_type']} is not implemented yet"); + break; + } + } + + public static function getInstance() + { + global $options; + static $_instance = array(); + + $dbParams['db_type']= Util::getPleskDbType(); + $dbParams['db'] = Util::getPleskDbName(); + $dbParams['port'] = Util::getPleskDbPort(); + $dbParams['login'] = Util::getPleskDbLogin(); + $dbParams['passwd'] = Util::getPleskDbPassword($options->getDbPasswd()); + $dbParams['host'] = Util::getPleskDbHost(); + + $dbId = md5(implode("\n", $dbParams)); + + $_instance[$dbId] = new PleskDb($dbParams); + + return $_instance[$dbId]; + } + + function fetchOne($sql) + { + if (DEBUG) { + $log = Log::getInstance(); + $log->info($sql); + } + return $this->_db->fetchOne($sql); + } + + function fetchRow($sql) + { + $res = $this->fetchAll($sql); + if (is_array($res) && isset($res[0])) { + return $res[0]; + } + return array(); + } + + function fetchAll($sql) + { + if (DEBUG) { + $log = Log::getInstance(); + $log->info($sql); + } + return $this->_db->fetchAll($sql); + } +} + +class DbMysql +{ + var $_dbHandler; + + public function __construct($host, $user, $passwd, $database, $port) + { + if ( extension_loaded('mysql') ) { + $this->_dbHandler = @mysql_connect("{$host}:{$port}", $user, $passwd); + if (!is_resource($this->_dbHandler)) { + $mysqlError = mysql_error(); + if (stristr($mysqlError, 'access denied for user')) { + $errMsg = 'Given is incorrect. ' . $mysqlError; + } else { + $errMsg = 'Unable to connect database. The reason of problem: ' . $mysqlError . PHP_EOL; + } + $this->_logError($errMsg); + } + @mysql_select_db($database, $this->_dbHandler); + } else if ( extension_loaded('mysqli') ) { + + // forbid using MYSQLI_REPORT_STRICT to handle mysqli errors via error codes + mysqli_report(MYSQLI_REPORT_ERROR); + + $this->_dbHandler = @mysqli_connect($host, $user, $passwd, $database, $port); + if (!$this->_dbHandler) { + $mysqlError = mysqli_connect_error(); + if (stristr($mysqlError, 'access denied for user')) { + $errMsg = 'Given is incorrect. ' . $mysqlError; + } else { + $errMsg = 'Unable to connect database. The reason of problem: ' . $mysqlError . PHP_EOL; + } + $this->_logError($errMsg); + } + } else { + fatal("No MariaDB/MySQL extension is available"); + } + } + + function fetchAll($sql) + { + if ( extension_loaded('mysql') ) { + $res = mysql_query($sql, $this->_dbHandler); + if (!is_resource($res)) { + $this->_logError('Unable to execute query. Error: ' . mysql_error($this->_dbHandler)); + } + $rowset = array(); + while ($row = mysql_fetch_assoc($res)) { + $rowset[] = $row; + } + return $rowset; + } else if ( extension_loaded('mysqli') ) { + $res = $this->_dbHandler->query($sql); + if ($res === false) { + $this->_logError('Unable to execute query. Error: ' . mysqli_error($this->_dbHandler)); + } + $rowset = array(); + while ($row = mysqli_fetch_assoc($res)) { + $rowset[] = $row; + } + return $rowset; + } else { + fatal("No MariaDB/MySQL extension is available"); + } + } + + function fetchOne($sql) + { + if ( extension_loaded('mysql') ) { + $res = mysql_query($sql, $this->_dbHandler); + if (!is_resource($res)) { + $this->_logError('Unable to execute query. Error: ' . mysql_error($this->_dbHandler)); + } + $row = mysql_fetch_row($res); + return isset($row[0]) ? $row[0] : null; + } else if ( extension_loaded('mysqli') ) { + $res = $this->_dbHandler->query($sql); + if ($res === false) { + $this->_logError('Unable to execute query. Error: ' . mysqli_error($this->_dbHandler)); + } + $row = mysqli_fetch_row($res); + return isset($row[0]) ? $row[0] : null; + } else { + fatal("No MariaDB/MySQL extension is available"); + } + } + + function query($sql) + { + if ( extension_loaded('mysql') ) { + $res = mysql_query($sql, $this->_dbHandler); + if ($res === false ) { + $this->_logError('Unable to execute query. Error: ' . mysql_error($this->_dbHandler) ); + } + return $res; + } else if ( extension_loaded('mysqli') ) { + $res = $this->_dbHandler->query($sql); + if ($res === false ) { + $this->_logError('Unable to execute query. Error: ' . mysqli_error($this->_dbHandler) ); + } + return $res; + } else { + fatal("No MariaDB/MySQL extension is available"); + } + } + + function _logError($message) + { + fatal("[MYSQL ERROR] $message"); + } +} + +class DbClientMysql extends DbMysql +{ + var $errors = array(); + + function _logError($message) + { + $message = "[MYSQL ERROR] $message"; + $log = Log::getInstance(); + $log->warning($message); + $this->errors[] = $message; + } + + function hasErrors() { + return count($this->errors) > 0; + } +} + +class DbJet +{ + var $_dbHandler = null; + + public function __construct($dbPath) + { + $dsn = "Provider='Microsoft.Jet.OLEDB.4.0';Data Source={$dbPath}"; + $this->_dbHandler = new COM("ADODB.Connection", NULL, CP_UTF8); + if (!$this->_dbHandler) { + $this->_logError('Unable to init ADODB.Connection'); + } + + $this->_dbHandler->open($dsn); + } + + function fetchAll($sql) + { + $result_id = $this->_dbHandler->execute($sql); + if (!$result_id) { + $this->_logError('Unable to execute sql query ' . $sql); + } + if ($result_id->BOF && !$result_id->EOF) { + $result_id->MoveFirst(); + } + if ($result_id->EOF) { + return array(); + } + + $rowset = array(); + while(!$result_id->EOF) { + $row = array(); + for ($i=0;$i<$result_id->Fields->count;$i++) { + $field = $result_id->Fields($i); + $row[$field->Name] = (string)$field->value; + } + $result_id->MoveNext(); + $rowset[] = $row; + } + return $rowset; + } + + function fetchOne($sql) + { + $result_id = $this->_dbHandler->execute($sql); + if (!$result_id) { + $this->_logError('Unable to execute sql query ' . $sql); + } + if ($result_id->BOF && !$result_id->EOF) { + $result_id->MoveFirst(); + } + if ($result_id->EOF) { + return null; + } + $field = $result_id->Fields(0); + $result = $field->value; + + return (string)$result; + } + + function _logError($message) + { + fatal("[JET ERROR] $message"); + } +} + +class DbMsSql extends DbJet +{ + public function __construct($host, $user, $passwd, $database, $port) + { + $dsn = "Provider=SQLOLEDB.1;Initial Catalog={$database};Data Source={$host}"; + $this->_dbHandler = new COM("ADODB.Connection", NULL, CP_UTF8); + if (!$this->_dbHandler) { + $this->_logError('Unable to init ADODB.Connection'); + } + $this->_dbHandler->open($dsn, $user, $passwd); + } + + function _logError($message) + { + fatal("[MSSQL ERROR] $message"); + } +} + +class IpParser +{ + public static function getIpListFromIpconfigOutput($output) + { + $ips = []; + foreach ($output as $line) { + $line = trim($line); + + // IPv4 + if (preg_match('/\b(\d{1,3}\.){3}\d{1,3}\b/', $line, $m)) { + // no mask + if (!preg_match('/^255\.255\.255\.\d{1,3}$/', $m[0])) { + $ips[] = $m[0]; + } + } + + // IPv6 + if (preg_match('/\b([0-9a-f]{0,4}:){2,7}[0-9a-f]{0,4}\b/i', $line, $m)) { + // no local + if (stripos($m[0], 'fe80') !== 0) { + $ips[] = $m[0]; + } + } + } + return $ips; + } +} + +class Util +{ + const DSN_INI_PATH_UNIX = '/etc/psa/private/dsn.ini'; + + /** @var array */ + private static $_dsnIni; + + public static function isWindows() + { + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + return true; + } + return false; + } + + public static function isLinux() + { + return !Util::isWindows(); + } + + public static function isVz() + { + $vz = false; + if (Util::isLinux()) { + if (file_exists('/proc/vz/veredir')) { + $vz = true; + } + } else { + $reg = 'REG QUERY "HKLM\SOFTWARE\SWsoft\Virtuozzo" 2>nul'; + Util::exec($reg, $code); + if ($code==0) { + $vz = true; + } + } + return $vz; + } + + public static function getArch() + { + global $arch; + if (!empty($arch)) + return $arch; + + $arch = 'i386'; + if (Util::isLinux()) { + $cmd = 'uname -m'; + $x86_64 = 'x86_64'; + $output = Util::exec($cmd, $code); + if (!empty($output) && stristr($output, $x86_64)) { + $arch = 'x86_64'; + } + } else { + $arch = 'x86_64'; + } + return $arch; + } + + public static function getHostname() + { + if (Util::isLinux()) { + $cmd = 'hostname -f'; + } else { + $cmd = 'hostname'; + } + $hostname = Util::exec($cmd, $code); + + if (empty($hostname)) { + $err = 'Command: ' . $cmd . ' returns: ' . $hostname . "\n"; + $err .= 'Hostname is not defined and configured. Unable to get hostname. Server should have properly configured hostname and it should be resolved locally.'; + fatal($err); + } + + return $hostname; + } + + public static function getIPList($lo=false) + { + if (Util::isLinux()) { + $ipList = Util::getIPv4ListOnLinux(); + foreach ($ipList as $key => $ip) { + if (!$lo && substr($ip, 0, 3) == '127') { + unset($ipList[$key]); + continue; + } + trim($ip); + } + $ipList = array_values($ipList); + } else { + $cmd = 'hostname'; + $hostname = Util::exec($cmd, $code); + $ip = gethostbyname($hostname); + $res = ($ip != $hostname) ? true : false; + if (!$res) { + fatal('Unable to retrieve IP address'); + } + $ipList = array(trim($ip)); + } + return $ipList; + } + + public static function getIPv6ListOnLinux() + { + return Util::grepCommandOutput(array( + array('bin' => 'ip', 'command' => '%PATH% addr list', 'regexp' => '#inet6 ([^ /]+)#'), + array('bin' => 'ifconfig', 'command' => '%PATH% -a', 'regexp' => '#inet6 (?:addr: ?)?([A-F0-9:]+)#i'), + )); + } + + public static function getIPv4ListOnLinux() + { + $commands = array( + array('bin' => 'ip', 'command' => '%PATH% addr list', 'regexp' => '#inet ([^ /]+)#'), + array('bin' => 'ifconfig', 'command' => '%PATH% -a', 'regexp' => '#inet (?:addr: ?)?([\d\.]+)#'), + ); + if (!($list = Util::grepCommandOutput($commands))) { + fatal('Unable to get IP address'); + } + return $list; + } + + public static function grepCommandOutput($cmds) + { + foreach ($cmds as $cmd) { + if ($fullPath = Util::lookupCommand($cmd['bin'])) { + $output = Util::exec(str_replace("%PATH%", $fullPath, $cmd['command']), $code); + if (preg_match_all($cmd['regexp'], $output, $matches)) { + return $matches[1]; + } + } + } + return false; + } + + public static function getIPListOnWindows() + { + $lastLine = exec('ipconfig', $output, $code); + if (false === $lastLine) { + $error = error_get_last(); + $message = isset($error['message']) ? $error['message'] : 'Unknown error'; + fatal("Unable to get IP address: {$message}"); + } + if ($code === 0 && $ips = IpParser::getIpListFromIpconfigOutput($output)) { + return $ips; + } + fatal("Unable to get IP address"); + } + + public static function getPleskRootPath() + { + global $_pleskRootPath; + if (empty($_pleskRootPath)) { + if (Util::isLinux()) { + if (PleskOS::isDebLike()) { + $_pleskRootPath = '/opt/psa'; + } else { + $_pleskRootPath = '/usr/local/psa'; + } + } + if (Util::isWindows()) { + $_pleskRootPath = Util::regPleskQuery('PRODUCT_ROOT_D', true); + } + } + return $_pleskRootPath; + } + + public static function getPleskDbName() + { + $dbName = 'psa'; + if (Util::isWindows()) { + $dbName = Util::regPleskQuery('mySQLDBName'); + } else { + $dsnDbname = Util::_getDsnConfigValue('dbname'); + if ($dsnDbname) { + $dbName = $dsnDbname; + } + } + return $dbName; + } + + public static function getPleskDbLogin() + { + $dbLogin = 'admin'; + if (Util::isWindows()) { + $dbLogin = Util::regPleskQuery('PLESK_DATABASE_LOGIN'); + } else { + $dsnLogin = Util::_getDsnConfigValue('username'); + if ($dsnLogin) { + $dbLogin = $dsnLogin; + } + } + return $dbLogin; + } + + public static function getPleskDbPassword($dbPassword) + { + if (Util::isLinux()) { + $dsnPassword = Util::_getDsnConfigValue('password'); + if ($dsnPassword) { + $dbPassword = $dsnPassword; + } + } + return $dbPassword; + } + + public static function getPleskDbType() + { + $dbType = 'mysql'; + if (Util::isWindows()) { + $dbType = strtolower(Util::regPleskQuery('PLESK_DATABASE_PROVIDER_NAME')); + } + return $dbType; + } + + public static function getPleskDbHost() + { + $dbHost = 'localhost'; + if (Util::isWindows()) { + $dbProvider = strtolower(Util::regPleskQuery('PLESK_DATABASE_PROVIDER_NAME')); + if ($dbProvider == 'mysql' || $dbProvider == 'mssql') { + $dbHost = Util::regPleskQuery('MySQL_DB_HOST'); + } + } else { + $dsnHost = Util::_getDsnConfigValue('host'); + if ($dsnHost) { + $dbHost = $dsnHost; + } + } + return $dbHost; + } + + public static function getPleskDbPort() + { + $dbPort = '3306'; + if (Util::isWindows()) { + $dbPort = Util::regPleskQuery('MYSQL_PORT'); + } else { + $dsnPort = Util::_getDsnConfigValue('port'); + if ($dsnPort) { + $dbPort = $dsnPort; + } + } + return $dbPort; + } + + private static function _getDsnConfigValue($param) + { + if (Util::isWindows()) { + return null; + } + + if (is_null(self::$_dsnIni)) { + if (!is_file(self::DSN_INI_PATH_UNIX)) { + self::$_dsnIni = false; + return null; + } + self::$_dsnIni = parse_ini_file(self::DSN_INI_PATH_UNIX, true); + } + + if (!self::$_dsnIni) { + return null; + } + if (!array_key_exists('plesk', self::$_dsnIni)) { + return null; + } + if (!array_key_exists($param, self::$_dsnIni['plesk'])) { + return null; + } + return self::$_dsnIni['plesk'][$param]; + } + + public static function regPleskQuery($key, $returnResult=false) + { + $reg = 'REG QUERY "HKLM\SOFTWARE\Wow6432Node\Plesk\Psa Config\Config" /v '.$key; + $output = Util::exec($reg, $code); + + if ($code) { + $log = Log::getInstance(); + $log->info($reg); + $log->info($output); + if ($returnResult) { + return false; + } else { + fatal("Unable to get '$key' from registry"); + } + } + + if (!preg_match("/\w+\s+REG_SZ\s+(.*)/i", trim($output), $matches)) { + fatal('Unable to macth registry value by key '.$key.'. Output: ' . trim($output)); + } + + return $matches[1]; + } + + public static function regQuery($path, $key, $returnResult = false) + { + $reg = 'REG QUERY "HKLM\SOFTWARE\Wow6432Node' . $path . '" '.$key; + $output = Util::exec($reg, $code); + + if ($code) { + $log = Log::getInstance(); + $log->info($reg); + $log->info($output); + if ($returnResult) { + return false; + } else { + fatal("Unable to get '$key' from registry"); + } + } + + if (!preg_match("/\s+REG_SZ(\s+)?(.*)/i", trim($output), $matches)) { + fatal('Unable to match registry value by key '.$key.'. Output: ' . trim($output)); + } + + return $matches[2]; + } + + public static function lookupCommand($cmd, $exit = false, $path = '/bin:/usr/bin:/usr/local/bin:/usr/sbin:/sbin:/usr/local/sbin') + { + $dirs = explode(':', $path); + foreach ($dirs as $dir) { + $util = $dir . '/' . $cmd; + if (is_executable($util)) { + return $util; + } + } + if ($exit) { + fatal("{$cmd}: command not found"); + } + return false; + } + + public static function getSystemDisk() + { + $cmd = 'echo %SYSTEMROOT%'; + $output = Util::exec($cmd, $code); + return substr($output, 0, 3); + } + + public static function getSystemRoot() + { + $cmd = 'echo %SYSTEMROOT%'; + $output = Util::exec($cmd, $code); + return $output; + } + + public static function getFileVersion($file) + { + $fso = new COM("Scripting.FileSystemObject"); + $version = $fso->GetFileVersion($file); + $fso = null; + return $version; + } + + public static function isUnknownISAPIfilters() + { + if (PleskVersion::is17x_or_above()) { + return false; + } + + $log = Log::getInstance(); + + $isUnknownISAPI = false; + $knownISAPI = array ("ASP\\.Net.*", "sitepreview", "COMPRESSION", "jakarta"); + + foreach ($knownISAPI as &$value) { + $value = strtoupper($value); + } + $cmd='cscript ' . Util::getSystemDisk() . 'inetpub\AdminScripts\adsutil.vbs ENUM W3SVC/FILTERS'; + $output = Util::exec($cmd, $code); + + if ($code!=0) { + $log->info("Unable to get ISAPI filters. Error: " . $output); + return false; + } + if (!preg_match_all('/FILTERS\/(.*)]/', trim($output), $matches)) { + $log->info($output); + $log->info("Unable to get ISAPI filters from output: " . $output); + return false; + } + foreach ($matches[1] as $ISAPI) { + $valid = false; + foreach ($knownISAPI as $knownPattern) { + if (preg_match("/$knownPattern/i", $ISAPI)) { + $valid = true; + break; + } + } + if (! $valid ) { + $log->warning("Unknown ISAPI filter detected in IIS: " . $ISAPI); + $isUnknownISAPI = true; + } + } + + return $isUnknownISAPI; + } + + /** + * @return string + */ + public static function getMySQLServerVersion() + { + $credentials = Util::getDefaultClientMySQLServerCredentials(); + + if (preg_match('/AES-128-CBC/', $credentials['admin_password'])) { + Log::getInstance()->info('The administrator\'s password for the default MariaDB/MySQL server is encrypted.'); + + return ''; + } + + $mysql = new DbClientMysql( + $credentials['host'], + $credentials['admin_login'], + $credentials['admin_password'], + 'information_schema', + $credentials['port'] + ); + + if (!$mysql->hasErrors()) { + $sql = 'select version()'; + $mySQLversion = $mysql->fetchOne($sql); + if (!preg_match("/(\d{1,})\.(\d{1,})\.(\d{1,})/", trim($mySQLversion), $matches)) { + fatal('Unable to match MariaDB/MySQL server version.'); + } + + return $matches[0]; + } + + return ''; + } + + public static function getDefaultClientMySQLServerCredentials() + { + $db = PleskDb::getInstance(); + $sql = "SELECT val FROM misc WHERE param='default_server_mysql'"; + $defaultServerMysqlId = $db->fetchOne($sql); + if ($defaultServerMysqlId) { + $where = "id={$defaultServerMysqlId}"; + } else { + $where = "type='mysql' AND host='localhost'"; + } + $sql = "SELECT ds.host, ds.port, ds.admin_login, ds.admin_password FROM DatabaseServers ds WHERE {$where}"; + $clientDBServerCredentials = $db->fetchAll($sql)[0]; + if ($clientDBServerCredentials['host'] === 'localhost' && Util::isLinux()) { + $clientDBServerCredentials['admin_password'] = Util::retrieveAdminMySQLDbPassword(); + } + if (empty($clientDBServerCredentials['port'])) { + $clientDBServerCredentials['port'] = self::getPleskDbPort(); + } + + return $clientDBServerCredentials; + } + + public static function retrieveAdminMySQLDbPassword() + { + return Util::isLinux() + ? trim( Util::readfile("/etc/psa/.psa.shadow") ) + : null; + } + + public static function exec($cmd, &$code) + { + $log = Log::getInstance(); + + if (!$cmd) { + $log->info('Unable to execute a blank command. Please see ' . LOG_PATH . ' for details.'); + + $debugBacktrace = ""; + foreach (debug_backtrace() as $i => $obj) { + $debugBacktrace .= "#{$i} {$obj['file']}:{$obj['line']} {$obj['function']} ()\n"; + } + $log->debug("Unable to execute a blank command. The stack trace:\n{$debugBacktrace}"); + $code = 1; + return ''; + } + exec($cmd, $output, $code); + return trim(implode("\n", $output)); + } + + public static function readfile($file) + { + if (!is_file($file) || !is_readable($file)) { + return null; + } + $lines = file($file); + return $lines === false + ? null + : trim(implode("\n", $lines)); + } + + public static function readfileToArray($file) + { + if (!is_file($file) || !is_readable($file)) { + return null; + } + $lines = file($file); + return $lines === false + ? null + : $lines; + } + + public static function getSettingFromPsaConf($setting) + { + $file = '/etc/psa/psa.conf'; + if (!is_file($file) || !is_readable($file)) + return null; + $lines = file($file); + if ($lines === false) + return null; + foreach ($lines as $line) { + if (preg_match("/^{$setting}\s.*/", $line, $match_setting)) { + if (preg_match("/[\s].*/i", $match_setting[0], $match_value)) { + $value = trim($match_value[0]); + return $value; + } + } + } + return null; + } + + public static function getPhpIni() + { + if (Util::isLinux()) { + // Debian/Ubuntu /etc/php5/apache2/php.ini /etc/php5/conf.d/ + // SuSE /etc/php5/apache2/php.ini /etc/php5/conf.d/ + // CentOS 4/5 /etc/php.ini /etc/php.d + if (PleskOS::isRedHatLike()) { + $phpini = Util::readfileToArray('/etc/php.ini'); + } else { + $phpini = Util::readfileToArray('/etc/php5/apache2/php.ini'); + } + } + + return $phpini; + } + + public static function getUserBeanCounters() + { + if (!Util::isLinux()) { + + return false; + } + $user_beancounters = array(); + $ubRaw = Util::readfileToArray('/proc/user_beancounters'); + + if (!$ubRaw) { + + return false; + } + for ($i=2; $i<=count($ubRaw)-1; $i++) { + + if (preg_match('/^.+?:?.+?\b(\w+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/', $ubRaw[$i], $limit_name)) { + + $user_beancounters[trim($limit_name[1])] = array( + 'held' => (int)$limit_name[2], + 'maxheld' => (int)$limit_name[3], + 'barrier' => (int)$limit_name[4], + 'limit' => (int)$limit_name[5], + 'failcnt' => (int)$limit_name[6] + ); + } + } + + return $user_beancounters; + } +} + +class PackageManager +{ + public static function buildListCmdLine($glob) + { + if (PleskOS::isRedHatLike()) { + $cmd = "rpm -qa --queryformat '%{NAME} %{VERSION}-%{RELEASE} %{ARCH}\\n'"; + } elseif (PleskOS::isDebLike()) { + $cmd = "dpkg-query --show --showformat '\${Package} \${Version} \${Architecture}\\n'"; + } else { + return false; + } + + if (!empty($glob)) { + $cmd .= " '" . $glob . "' 2>/dev/null"; + } + + return $cmd; + } + + /* + * Fetches a list of installed packages that match given criteria. + * string $glob - Glob (wildcard) pattern for coarse-grained packages selection from system package management backend. Empty $glob will fetch everything. + * string $regexp - Package name regular expression for a fine-grained filtering of the results. + * returns array of hashes with keys 'name', 'version' and 'arch', or false on error. + */ + public static function listInstalled($glob, $regexp = null) + { + $cmd = PackageManager::buildListCmdLine($glob); + if (!$cmd) { + return array(); + } + + $output = Util::exec($cmd, $code); + if ($code != 0) { + return false; + } + + $packages = array(); + $lines = explode("\n", $output); + foreach ($lines as $line) { + @list($pkgName, $pkgVersion, $pkgArch) = explode(" ", $line); + if (empty($pkgName) || empty($pkgVersion) || empty($pkgArch)) + continue; + if (!empty($regexp) && !preg_match($regexp, $pkgName)) + continue; + $packages[] = array( + 'name' => $pkgName, + 'version' => $pkgVersion, + 'arch' => $pkgArch + ); + } + + return $packages; + } + + public static function isInstalled($glob, $regexp = null) + { + $packages = PackageManager::listInstalled($glob, $regexp); + return !empty($packages); + } +} + +class Package +{ + function getManager($field, $package) + { + $redhat = 'rpm -q --queryformat \'%{' . $field . '}\n\' ' . $package; + $debian = 'dpkg-query --show --showformat=\'${' . $field . '}\n\' '. $package . ' 2> /dev/null'; + + if (PleskOS::isRedHatLike()) { + $manager = $redhat; + } elseif (PleskOS::isDebLike()) { + $manager = $debian; + } else { + return false; + } + + return $manager; + } + + /* DPKG doesn't supports ${Release} + * + */ + + function getRelease($package) + { + $manager = Package::getManager('Release', $package); + + if (!$manager) { + return false; + } + + $release = Util::exec($manager, $code); + if (!$code === 0) { + return false; + } + return $release; + } + + function getVersion($package) + { + $manager = Package::getManager('Version', $package); + + if (!$manager) { + return false; + } + + $version = Util::exec($manager, $code); + if (!$code === 0) { + return false; + } + return $version; + } + +} + +class PleskOS +{ + public static function isDebLike() + { + return is_file("/etc/debian_version"); + } + + public static function isRedHatLike() + { + return is_file("/etc/redhat-release"); + } + + public static function catEtcIssue() + { + $cmd = 'cat /etc/issue'; + $output = Util::exec($cmd, $code); + + return $output; + } + + public static function detectSystem() + { + $log = Log::getInstance('Detect system configuration'); + $log->info('OS: ' . (Util::isLinux() ? PleskOS::catEtcIssue() : 'Windows')); + $log->info('Arch: ' . Util::getArch()); + } +} + +class PleskValidator +{ + public static function validateIPv4($value) + { + $ip2long = ip2long($value); + if ($ip2long === false) { + return false; + } + + return $value == long2ip($ip2long); + } + + public static function validateIPv6($value) + { + if (strlen($value) < 3) { + return $value == '::'; + } + + if (strpos($value, '.')) { + $lastcolon = strrpos($value, ':'); + if (!($lastcolon && PleskValidator::validateIPv4(substr($value, $lastcolon + 1)))) { + return false; + } + + $value = substr($value, 0, $lastcolon) . ':0:0'; + } + + if (strpos($value, '::') === false) { + return preg_match('/\A(?:[a-f0-9]{1,4}:){7}[a-f0-9]{1,4}\z/i', $value); + } + + $colonCount = substr_count($value, ':'); + if ($colonCount < 8) { + return preg_match('/\A(?::|(?:[a-f0-9]{1,4}:)+):(?:(?:[a-f0-9]{1,4}:)*[a-f0-9]{1,4})?\z/i', $value); + } + + // special case with ending or starting double colon + if ($colonCount == 8) { + return preg_match('/\A(?:::)?(?:[a-f0-9]{1,4}:){6}[a-f0-9]{1,4}(?:::)?\z/i', $value); + } + + return false; + } +} + +class CheckRequirements +{ + function validate() + { + if (!PleskInstallation::isInstalled()) { + //:INFO: skip chking mysql extension if plesk is not installed + return; + } + + $reqExts = array(); + foreach ($reqExts as $name) { + $status = extension_loaded($name); + if (!$status) { + $this->_fail("PHP extension {$name} is not installed"); + } + } + } + + function _fail($errMsg) + { + echo '===Checking requirements===' . PHP_EOL; + echo PHP_EOL . 'Error: ' . $errMsg . PHP_EOL; + exit(1); + } +} + +class GetOpt +{ + var $_argv; + var $_adminDbPasswd; + + public function __construct() + { + $this->_argv = $_SERVER['argv']; + if (empty($this->_argv[1]) && Util::isLinux()) { + $this->_adminDbPasswd = Util::retrieveAdminMySQLDbPassword(); + } else { + $this->_adminDbPasswd = $this->_argv[1]; + } + } + + public function validate() + { + if (empty($this->_adminDbPasswd) && PleskInstallation::isInstalled()) { + echo 'Please specify Plesk database password'; + $this->_helpUsage(); + } + } + + public function getDbPasswd() + { + return $this->_adminDbPasswd; + } + + public function _helpUsage() + { + echo PHP_EOL . "Usage: {$this->_argv[0]} " . PHP_EOL; + exit(1); + } +} + +function fatal($msg) +{ + $log = Log::getInstance(); + $log->fatal($msg); + exit(1); +} + +function main() +{ + $log = Log::getInstance(); + + global $options; + //:INFO: Validate options + $options = new GetOpt(); + $options->validate(); + + //:INFO: Validate PHP requirements, need to make sure that PHP extensions are installed + $checkRequirements = new CheckRequirements(); + $checkRequirements->validate(); + + //:INFO: Validate Plesk installation + PleskInstallation::validate(); + + //:INFO: Detect system + $pleskOs = new PleskOS(); + $pleskOs->detectSystem(); + + //:INFO: Need to make sure that given db password is valid + if (PleskInstallation::isInstalled()) { + $log->step('Validating the database password'); + $pleskDb = PleskDb::getInstance(); + $log->resultOk(); + } + + //:INFO: Dump script version + $log->step('Pre-Upgrade analyzer version: ' . PRE_UPGRADE_SCRIPT_VERSION); + + //:INFO: Validate known OS specific issues with recommendation to avoid bugs in Plesk + $pleskKnownIssues = new Plesk17KnownIssues(); + $pleskKnownIssues->validate(); + + $plesk175Requirements = new Plesk175Requirements(); + $plesk175Requirements->validate(); + + $plesk178Requirements = new Plesk178Requirements(); + $plesk178Requirements->validate(); + + $plesk18Requirements = new Plesk18Requirements(); + $plesk18Requirements->validate(); + + $log->dumpStatistics(); + $log->writeJsonFile(); + + if ($log->getEmergency() > 0) { + exit(2); + } + + if ($log->getErrors() > 0 || $log->getWarnings() > 0) { + exit(1); + } +} + +if (!defined('UNIT_TEST_MODE')) { + main(); +} +// vim:set et ts=4 sts=4 sw=4: diff --git a/root/parallels/pool/PSA_18.0.74_18022/examiners/php_launcher.sh b/root/parallels/pool/PSA_18.0.74_18022/examiners/php_launcher.sh new file mode 100755 index 0000000000..70ebd0f0c6 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.74_18022/examiners/php_launcher.sh @@ -0,0 +1,38 @@ +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +die() +{ + echo $* + exit 1 +} + +[ -n "$1" ] || die "Usage: $0 php_script [args...]" + +[ "X${PLESK_INSTALLER_DEBUG}" = "X" ] || set -x +[ "X${PLESK_INSTALLER_STRICT_MODE}" = "X" ] || set -e + +php_bin= + +lookup() +{ + [ -z "$php_bin" ] || return + + local paths="$1" + local name="$2" + + for path in $paths; do + if [ -x "$path/$name" ]; then + php_bin="$path/$name" + break + fi + done +} + +lookup "/usr/local/psa/admin/bin /opt/psa/admin/bin" "php" +lookup "/usr/local/psa/bin /opt/psa/bin" "sw-engine-pleskrun" + +[ -n "$php_bin" ] || \ + die "Unable to locate the sw-engine PHP interpreter to execute the script. Make sure that Parallels Plesk Panel is installed on this server." + +exec "${php_bin}" "$@" diff --git a/root/parallels/pool/PSA_18.0.74_18022/examiners/plesk_preupgrade_checker.log b/root/parallels/pool/PSA_18.0.74_18022/examiners/plesk_preupgrade_checker.log new file mode 100644 index 0000000000..b8325f8371 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.74_18022/examiners/plesk_preupgrade_checker.log @@ -0,0 +1,68 @@ + +INFO: Installed Plesk version/build: 18.0.73 Ubuntu 24.04 1800251124.20... + +INFO: STEP 0: Detect system configuration... +INFO: OS: Ubuntu 24.04.3 LTS \n \l +INFO: Arch: x86_64 + +INFO: Validating the database password... +INFO: Result: OK + +INFO: Pre-Upgrade analyzer version: 18.0.74.0... + +INFO: STEP 1: Checking for main IP address... +INFO: Result: OK + +INFO: STEP 2: Checking existence of Plesk user "root" for MariaDB/MySQL database servers... +INFO: Result: OK + +INFO: STEP 3: Checking proftpd settings... +INFO: Result: OK + +INFO: STEP 4: Checking the 'Interval' parameter in the sw-collectd configuration file... +INFO: Result: OK + +INFO: STEP 5: Checking Apache status... +INFO: Result: OK + +INFO: STEP 6: Checking Panel files for the immutable bit attribute... +INFO: Result: OK + +INFO: STEP 7: Checking the possibility to change the permissions of files in the DUMP_D directory... +INFO: Result: OK + +INFO: STEP 8: Checking consistency of the IP addresses list in the Panel database... +INFO: Result: OK + +INFO: STEP 9: Checking installed APS applications... +INFO: Result: OK + +INFO: STEP 10: Checking if apsc database tables have InnoDB engine... +INFO: Result: OK + +INFO: STEP 11: Checking for custom web server configuration templates... +INFO: Result: OK + +INFO: STEP 12: Checking for domains with mixed case names... +INFO: Result: OK + +INFO: STEP 13: Checking symbolic link /usr/local/psa on /opt/psa... +INFO: Result: OK + +INFO: STEP 14: Detecting if encrypted passwords are used... +INFO: Result: OK + +INFO: STEP 15: Checking table "servers" in database "mysql"... +INFO: The administrator's password for the default MariaDB/MySQL server is encrypted. +INFO: Result: OK + +INFO: STEP 16: Checking the availability of Plesk Panel TCP ports... +INFO: Result: OK + +INFO: STEP 17: Checking for Protected Directory Users with duplicates in login field.... + +INFO: STEP 18: Checking "domains" table with duplicates in guid field.... + +INFO: STEP 19: Checking "clients" table with duplicates in guid field.... + +INFO: STEP 20: Checking if any rules are configured in the Firewall extension... diff --git a/root/parallels/pool/PSA_18.0.74_18022/examiners/py_launcher.sh b/root/parallels/pool/PSA_18.0.74_18022/examiners/py_launcher.sh new file mode 100755 index 0000000000..96dc215391 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.74_18022/examiners/py_launcher.sh @@ -0,0 +1,30 @@ +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +die() +{ + echo "$*" + exit 1 +} + +[ -f "$1" ] || die "Usage: $0 PEX [args...]" + +[ "X${PLESK_INSTALLER_DEBUG}" = "X" ] || set -x +[ "X${PLESK_INSTALLER_STRICT_MODE}" = "X" ] || set -e + +find_python_bin() +{ + local bin + for bin in "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3" "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2"; do + [ -x "$bin" ] || continue + python_bin="$bin" + return 0 + done + + return 1 +} + +find_python_bin || + die "Unable to locate Python interpreter to execute the script." + +exec "$python_bin" "$@" diff --git a/root/parallels/pool/PSA_18.0.74_18022/examiners/repository_check.sh b/root/parallels/pool/PSA_18.0.74_18022/examiners/repository_check.sh new file mode 100755 index 0000000000..090f121ea1 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.74_18022/examiners/repository_check.sh @@ -0,0 +1,782 @@ +#!/bin/bash +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ -z "$PLESK_INSTALLER_DEBUG" ] || set -x +[ -z "$PLESK_INSTALLER_STRICT_MODE" ] || set -e + +export LC_ALL=C +unset GREP_OPTIONS + +RET_SUCCESS=0 +RET_WARN=1 +RET_FATAL=2 + +is_function_defined() +{ + local fn="$1" + case "$(type $fn 2>/dev/null)" in + *function*) + return 0 + ;; + esac + return 1 +} + +# @params are tags in format "key=value" +# Report body (human readable information) is read from stdin +# and copied to stderr. +make_error_report() +{ + local report_file="${PLESK_INSTALLER_ERROR_REPORT:-}" + + local python_bin= + for bin in "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2" "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3"; do + if [ -x "$bin" ]; then + python_bin="$bin" + break + fi + done + + if [ -n "$report_file" -a -x "$python_bin" ]; then + "$python_bin" -c 'import sys, json +report_file = sys.argv[1] +error = sys.stdin.read() + +sys.stderr.write(error) + +data = { + "error": error, +} + +for tag in sys.argv[2:]: + k, v = tag.split("=", 1) + data[k] = v + +with open(report_file, "a") as f: + json.dump(data, f) + f.write("\n") +' "$report_file" "date=$(date --utc --iso-8601=ns)" "$@" + else + cat - >&2 + fi +} + +detect_platform() +{ + . /etc/os-release + os_name="$ID" + os_version="${VERSION_ID%%.*}" + os_arch="$(uname -m)" + if [ -e /etc/debian_version ]; then + case "$os_arch" in + x86_64) pkg_arch="amd64" ;; + aarch64) pkg_arch="arm64" ;; + esac + if [ -n "$VERSION_CODENAME" ]; then + os_codename="$VERSION_CODENAME" + else + case "$os_name$os_version" in + debian10) os_codename="buster" ;; + debian11) os_codename="bullseye" ;; + debian12) os_codename="bookworm" ;; + ubuntu18) os_codename="bionic" ;; + ubuntu20) os_codename="focal" ;; + ubuntu22) os_codename="jammy" ;; + ubuntu24) os_codename="noble" ;; + esac + fi + fi + + case "$os_name$os_version" in + rhel7|centos7|cloudlinux7|virtuozzo7) + package_manager="yum" + ;; + rhel*|centos*|cloudlinux*|almalinux*|rocky*) + package_manager="dnf" + ;; + debian*|ubuntu*) + package_manager="apt" + ;; + esac + + if [ "$os_name" = "ubuntu" -o "$os_name" = "debian" ]; then + PRODUCT_ROOT_D="/opt/psa" + else + PRODUCT_ROOT_D="/usr/local/psa" + fi +} + +has_os_impl_function() +{ + local prefix="$1" + local fn="${prefix}_${os_name}${os_version}" + is_function_defined "$fn" +} + +call_os_impl_function() +{ + local prefix="$1" + shift + local fn="${prefix}_${os_name}${os_version}" + "$fn" "$@" +} + +skip_checker_on_flag() +{ + local name="$1" + local flag="$2" + + if [ -f "$flag" ]; then + echo "$name was skipped due to flag file." >&2 + exit $RET_SUCCESS + fi +} + +skip_checker_on_env() +{ + local name="$1" + local env="$2" + + if [ -n "$env" ]; then + echo "$name was skipped due to environment variable." >&2 + exit $RET_SUCCESS + fi +} + +checker_main() +{ + local fnprefix="$1" + shift + + detect_platform + # try to execute checker only if all attributes are detected + [ -n "$os_name" -a -n "$os_version" ] || return $RET_SUCCESS + + for checker in "${fnprefix}_${os_name}${os_version}" "${fnprefix}_${os_name}" "${fnprefix}"; do + if is_function_defined "$checker"; then + local rc=$RET_SUCCESS + "$checker" "$@" || rc=$? + [ "$(( $rc & $RET_FATAL ))" = "0" ] || return $RET_FATAL + [ "$(( $rc & $RET_WARN ))" = "0" ] || return $RET_WARN + return $rc + fi + done + return $RET_SUCCESS +} + +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +# If env variable PLESK_INSTALLER_ERROR_REPORT=path_to_file is specified then in case of error +# repository_check.sh writes single line json report into it with the following fields: +# - "stage": "repositorycheck" +# - "level": "error" +# - "errtype" is one of the following: +# * "reponotcached" - repository is not cached (mostly due to unavailability). +# * "reponotenabled" - required repository is not enabled. +# * "reponotsupported" - unsupported repository is enabled. +# * "configmanagernotinstalled" - dnf config-manager is disabled. +# - "repo": repository name. +# - "date": time of error occurance ("2020-03-24T06:59:43,127545441+0000") +# - "error": human readable error message. + +report_no_repo() +{ + local repo="$1" + + make_error_report 'stage=repositorycheck' 'level=error' 'errtype=reponotenabled' "repo=$repo" <<-EOL + Plesk installation requires '$repo' OS repository to be enabled. + Make sure it is available and enabled, then try again. + EOL +} + +report_no_repo_cache() +{ + local repo="$1" + + make_error_report 'stage=repositorycheck' 'level=error' 'errtype=reponotcached' "repo=$repo" <<-EOL + Unable to create $package_manager cache for '$repo' OS repository. + Make sure the repository is available, otherwise either disable it or fix its configuration, then try again. + EOL +} + +report_unsupported_repo() +{ + local repo="$1" + + make_error_report 'stage=repositorycheck' 'level=error' 'errtype=reponotsupported' "repo=$repo" <<-EOL + Plesk installation doesn't support '$repo' OS repository. + Make sure it is disabled, then try again. + EOL +} + +report_rh_no_config_manager() +{ + local target + case "$package_manager" in + yum) + target="yum-utils package" + ;; + dnf) + target="config-manager dnf plugin" + ;; + esac + + make_error_report 'stage=repositorycheck' 'level=error' 'errtype=configmanagernotinstalled' <<-EOL + Failed to install $target. + Make sure repositories configuration of $package_manager package manager is correct + (use '$package_manager repolist --verbose' to get its actual state), then try again. + EOL +} + +check_rh_broken_repos() +{ + local rh_enabled_repos rh_available_repos + + # 1. `yum repolist` and `dnf repolist` list all repos + # which were enabled before last cache creation + # even if cache for them was not created. + # If some repo is misconfigured and cache was created with `skip_if_unavailable=1` + # then such repo will be listed anyway despite on cache state. + # If some repo was enabled after last cache creation + # then `repolist --cacheonly` will fail. + # 2. `yum repolist --verbose` and `dnf repoinfo` list only repos + # which were successfully cached before. + # These commands fail if at least one repo is not available + # and the 'skip_if_unavailable' flag is not set. + case "$package_manager" in + yum) + rh_enabled_repos="$( + { + yum repolist enabled --cacheonly -q 2>/dev/null \ + || yum repolist enabled -q --setopt='*.skip_if_unavailable=1' + } | sed -n -e '1d' -e 's/^\*\?!\?\([^/[:space:]]\+\).*/\1/p' + )" || return $RET_FATAL + + rh_available_repos="$( + yum repolist enabled --verbose --cacheonly -q --setopt='*.skip_if_unavailable=1' \ + | sed -n -e 's/^Repo-id\s*:\s*\([^/[:space:]]\+\).*/\1/p' + )" || return $RET_FATAL + ;; + dnf) + rh_enabled_repos="$( + { + dnf repolist --enabled --cacheonly -q 2>/dev/null \ + || dnf repolist --enabled -q --setopt='*.skip_if_unavailable=1' + } | sed -n -e '1d' -e 's/^!\?\(\S\+\).*/\1/p' + )" || return $RET_FATAL + + rh_available_repos="$( \ + dnf repoinfo --enabled --cacheonly -q --setopt='*.skip_if_unavailable=1' \ + | sed -n -e 's|^Repo-id\s*:\s*\(\S\+\)\s*$|\1|p' + )" || return $RET_FATAL + ;; + esac + + local rh_enabled_repos_f="$(mktemp /tmp/plesk-installer.preupgrade_checker.XXXXXX)" + echo "$rh_enabled_repos" | sort > "$rh_enabled_repos_f" + local rh_available_repos_f="$(mktemp /tmp/plesk-installer.preupgrade_checker.XXXXXX)" + echo "$rh_available_repos" | sort > "$rh_available_repos_f" + + local repo rc=0 + for repo in $(comm -23 "$rh_enabled_repos_f" "$rh_available_repos_f"); do + report_no_repo_cache "$repo" + rc=$RET_WARN + done + + rm -f "$rh_enabled_repos_f" "$rh_available_repos_f" + + return $rc +} + +has_rh_enabled_repo() +{ + local repo="$1" + + # Try to get list of repos from cache first. + # If some repo was enabled after last cache creation + # or some repo is unavailable the query from cache will fail. + # Try to fetch actual metadata in this case. + case "$package_manager" in + yum) + # Repo-id may end with OS version and/or architecture + # if baseurl of the repo refers to $releasever and/or $basearch variables + # eg 'epel/7/x86_64', 'epel/7', 'epel/x86_64' + { + yum repolist enabled --verbose --cacheonly -q 2>/dev/null \ + || yum repolist enabled --verbose -q --setopt='*.skip_if_unavailable=1' + } | grep -E -q "^Repo-id\s*: $repo(/.+)?\s*$" + ;; + dnf) + # note: --noplugins may cause failure and empty output on RedHat + { + dnf repoinfo --enabled --cacheonly -q 2>/dev/null \ + || dnf repoinfo --enabled -q --setopt='*.skip_if_unavailable=1' + } | grep -E -q "^Repo-id\s*: $repo\s*$" + ;; + esac +} + +has_rh_config_manager() +{ + case "$package_manager" in + yum) yum-config-manager --help >/dev/null 2>&1 ;; + dnf) dnf config-manager --help >/dev/null 2>&1 ;; + esac +} + +install_rh_config_manager() +{ + case "$package_manager" in + yum) yum install --disablerepo 'PLESK_*' -q -y 'yum-utils' --setopt='*.skip_if_unavailable=1' ;; + dnf) dnf install --disablerepo 'PLESK_*' -q -y 'dnf-command(config-manager)' --setopt='*.skip_if_unavailable=1' ;; + esac +} + +check_rh_config_manager() +{ + if ! has_rh_config_manager && ! install_rh_config_manager; then + report_rh_no_config_manager + return $RET_FATAL + fi +} + +enable_rh_repo() +{ + case "$package_manager" in + yum) yum-config-manager --enable "$@" && has_rh_enabled_repo "$@" ;; + dnf) dnf config-manager --set-enabled "$@" && has_rh_enabled_repo "$@" ;; + esac +} + +enable_sm_repo() +{ + ! has_rh_enabled_repo "$@" || return 0 + subscription-manager repos --enable "$@" || return $? + # On RedHat 8 above command may return 0 on failure with "Repositories disabled by configuration." + has_rh_enabled_repo "$@" +} + +check_epel() +{ + ! enable_rh_repo "epel" || return 0 + + # try to install epel-release from centos/extras or plesk/thirdparty repo + # and then try to update it to last version shipped by epel itself + # to make package upgradable with pum + "$package_manager" install --disablerepo 'PLESK_*' -q -y 'epel-release' --setopt='*.skip_if_unavailable=1' 2>/dev/null \ + || "$package_manager" install --disablerepo='*' --enablerepo 'PLESK_18_*-thirdparty' -q -y 'epel-release' \ + || "$package_manager" install -q -y "https://dl.fedoraproject.org/pub/epel/epel-release-latest-$os_version.noarch.rpm" \ + && "$package_manager" update -q -y 'epel-release' --setopt='*.skip_if_unavailable=1' 2>/dev/null + + # Ensure any other EPEL repos have cache for subsequent check for broken repos (AL9) + local epel_repos="$( + [ "$package_manager" != "dnf" ] || { + dnf repolist --enabled --cacheonly -q 2>/dev/null || + dnf repolist --enabled -q --setopt='*.skip_if_unavailable=1' + } | sed -n -e '1d' -e 's/^!\?\(epel\S\+\).*/\1/p' + )" + for repo in $epel_repos; do + "$package_manager" makecache --repo "$repo" -q + done + + ! has_rh_enabled_repo "epel" || return 0 + + report_no_repo "epel" + return $RET_FATAL +} + +check_codeready() +{ + local repo_rhel="codeready-builder-for-rhel-$os_version-$os_arch-rpms" + local repo_rhui="codeready-builder-for-rhel-$os_version-rhui-rpms" + local repo_rhui_alt="codeready-builder-for-rhel-$os_version-$os_arch-rhui-rpms" + local repo_rhui_alt2="rhui-codeready-builder-for-rhel-$os_version-$os_arch-rhui-rpms" + + ! enable_sm_repo "$repo_rhel" || return 0 + ! enable_rh_repo "$repo_rhui" || return 0 + ! enable_rh_repo "$repo_rhui_alt" || return 0 + ! enable_rh_repo "$repo_rhui_alt2" || return 0 + + report_no_repo "$repo_rhel" + return $RET_FATAL +} + +check_optional() +{ + local repo_rhel="rhel-$os_version-server-optional-rpms" + local repo_rhui="rhel-$os_version-server-rhui-optional-rpms" + + ! enable_sm_repo "$repo_rhel" || return 0 + ! enable_rh_repo "$repo_rhui" || return 0 + + report_no_repo "$repo_rhel" + return $RET_FATAL +} + +check_repos_rhel9() +{ + check_rh_config_manager || return $? + + local rc=0 + + check_epel || rc="$(( $rc | $? ))" + check_codeready || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + return $rc +} + +check_repos_almalinux9() +{ + check_rh_config_manager || return $? + + local rc=0 + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + # powertools is renamed to crb since AlmaLinux 9 + ! enable_rh_repo "crb" || return $rc + + report_no_repo "crb" + return $RET_FATAL +} + +check_repos_cloudlinux9() +{ + check_repos_almalinux9 "$@" +} + +check_repos_almalinux10() +{ + check_repos_almalinux9 "$@" +} + +check_repos_centos8() +{ + check_rh_config_manager || return $? + + local rc=0 + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + # names of repos are lowercased since 8.3 + ! enable_rh_repo "powertools" || return $rc + ! enable_rh_repo "PowerTools" || return $rc + + report_no_repo "powertools" + return $RET_FATAL +} + +check_repos_cloudlinux8() +{ + check_rh_config_manager || return $? + + local rc=0 + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + # names of repos are changed since 8.5 + ! enable_rh_repo "powertools" || return $rc + ! enable_rh_repo "cloudlinux-PowerTools" || return $rc + + report_no_repo "powertools" + return $RET_FATAL +} + +check_repos_rhel8() +{ + check_rh_config_manager || return $? + + local rc=0 + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + [ "$1" = "install" ] || return $rc + + check_codeready || rc="$(( $rc | $? ))" + + return $rc +} + +check_repos_almalinux8() +{ + check_repos_centos8 "$@" +} + +check_repos_rocky8() +{ + check_repos_centos8 "$@" +} + +check_repos_rhel7() +{ + check_rh_config_manager || return $? + + local rc=0 + + check_epel || rc="$(( $rc | $? ))" + check_optional || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + return $rc +} + +check_repos_centos7_based() +{ + check_rh_config_manager || return $? + + local rc=0 + + check_epel || rc="$(( $rc | $? ))" + check_rh_broken_repos || rc="$(( $rc | $? ))" + + return $rc +} + +sed_escape() +{ + # Note: this is not a full implementation + echo -n "$1" | sed -e 's|\.|\\.|g' +} + +switch_eol_centos_repos() +{ + local old_mirrorlist_host="mirrorlist.centos.org" + local old_host="mirror.centos.org" + local new_host="vault.centos.org" + + grep -qFw "$old_host" /etc/yum.repos.d/CentOS-*.repo 2>/dev/null || return 0 + local backup="`mktemp -d "/tmp/yum.repos.d-$(date --rfc-3339=date)-XXXXXX"`" + ! [ -d "$backup" ] || cp -raT /etc/yum.repos.d "$backup" || : + + sed -i \ + -e "s|^\s*\(mirrorlist\b[^/]*//`sed_escape "$old_mirrorlist_host"`/.*\)$|#\1|" \ + -e "s|^#*\s*baseurl\b\([^/]*\)//`sed_escape "$old_host"`/\(.*\)$|baseurl\1//$new_host/\2|" \ + /etc/yum.repos.d/CentOS-*.repo + echo "YUM package manager repositories were backed up to '$backup' and switched from $old_host to $new_host ." >&2 +} + +check_repos_centos7() +{ + switch_eol_centos_repos + + check_repos_centos7_based "$@" +} + +check_repos_cloudlinux7() +{ + check_repos_centos7_based "$@" +} + +check_repos_virtuozzo7() +{ + check_repos_centos7_based "$@" +} + +find_apt_repo() +{ + local repo="$1" + + local dist_tag= + ! [ "$os_name" = "ubuntu" ] || dist_tag="a" + ! [ "$os_name" = "debian" ] || dist_tag="n" + + if [ -z "$_apt_cache_policy" ]; then + # extract info of each available release as a string which consists of 'tag=value' + # filter out releases with priority less or equal to 100 + _apt_cache_policy="$( + apt-cache policy \ + | grep "b=$pkg_arch" \ + | grep -Eo '([a-z]=[^,]+,?)*' \ + )" + fi + + local l="$(echo "$repo" | cut -f1 -d'/')" + local d="$(echo "$repo" | cut -f2 -d'/')" + local c="$(echo "$repo" | cut -f3 -d'/')" + + # try to find releases by distribution and component + echo "$_apt_cache_policy" \ + | grep -E "(^|,)l=$l(,|$)" \ + | grep -E "(^|,)$dist_tag=$d(,|$)" \ + | grep -E "(^|,)c=$c(,|$)" \ + | while IFS="$(printf '\n')" read rel && [ -n "$rel" ]; do + l="$(echo "$rel" | grep -Eo "(^|,)l=[^,]+" | cut -f2 -d"=")" + d="$(echo "$rel" | grep -Eo "(^|,)$dist_tag=[^,]+" | cut -f2 -d"=")" + c="$(echo "$rel" | grep -Eo "(^|,)c=[^,]+" | cut -f2 -d"=")" + echo "$l/$d/$c" + done +} + +apt_install_packages() +{ + DEBIAN_FRONTEND=noninteractive LANG=C PATH=/usr/sbin:/usr/bin:/sbin:/bin \ + apt-get -qq --assume-yes -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold -o APT::Install-Recommends=no \ + install "$@" +} + +# Takes a list of suites and disables them in APT sources. +# Multiline deb822 format is supported. +disable_apt_suites_deb822() +{ + local python3=/usr/bin/python3 + + "$python3" -c 'import aptsources.sourceslist' 2>/dev/null || + apt_install_packages python3-apt + + "$python3" -c ' +import sys + +from aptsources.sourceslist import SourcesList + + +suites_to_disable=set(sys.argv[1:]) + +sources_list = SourcesList(deb822=True) + +sources_changed = False +for src in sources_list: + if src.invalid: + continue + suites = getattr(src, "suites", ()) + if not suites: + continue + new_suites = [s for s in suites if s not in suites_to_disable] + if len(new_suites) != len(suites): + sources_changed = True + if len(new_suites) == 0: + src.disabled = True + else: + src.suites = new_suites + +if sources_changed: + sources_list.save() +' "$@" + + # Since we have changed the repositories list, we should re-read _apt_cache_policy on a next call + # of the find_apt_repo function. Hence we have to reset the value of the variable + _apt_cache_policy="" +} + +disable_apt_repo() +{ + local repos_to_disable="$(find_apt_repo "$1" | cut -d '/' -f 2,3 | sort | uniq)" + if [ -z "$repos_to_disable" ]; then + return 0 + fi + + echo "$repos_to_disable" \ + | while IFS= read -r repo_to_disable && [ -n "$repo_to_disable" ]; do + local distrib=${repo_to_disable%%/*} + local component=${repo_to_disable##*/} + find /etc/apt -name "*.list" -exec \ + sed -i -e "/^\s*#/! s/.*\s$distrib\s\+$component\b/# &/" {} + + done + + # Since we have changed the repositories list, we should re-read _apt_cache_policy on a next call + # of the find_apt_repo function. Hence we have to reset the value of the variable + _apt_cache_policy="" + + return 0 +} + +check_required_apt_repo() +{ + local repo="$1" + [ -z "$(find_apt_repo "$repo")" ] || return 0 + report_no_repo "$repo" + return $RET_FATAL +} + +check_unsupported_apt_repos_ubuntu() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + + local repos="$( + find_apt_repo "Ubuntu/[^,]+/[^,]+" | grep -v "Ubuntu/$os_codename.*/.*" + find_apt_repo "Debian[^,]*/[^,]+/[^,]+" + )" + [ -n "$repos" ] || return 0 + + echo "$repos" | while IFS="$(printf '\n')" read repo; do + report_unsupported_repo "$repo" + done + + [ "$mode" = "install" ] || return $RET_WARN + return $RET_FATAL +} + +check_repos_ubuntu18() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + local rc=0 + + check_required_apt_repo "Ubuntu/$os_codename/main" || rc="$(( $rc | $? ))" + check_required_apt_repo "Ubuntu/$os_codename/universe" || rc="$(( $rc | $? ))" + check_required_apt_repo "Ubuntu/$os_codename-updates/main" || rc="$(( $rc | $? ))" + check_required_apt_repo "Ubuntu/$os_codename-updates/universe" || rc="$(( $rc | $? ))" + check_unsupported_apt_repos_ubuntu "$mode" || rc="$(( $rc | $? ))" + + return $rc +} + + +check_repos_ubuntu() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + local rc=0 + + check_required_apt_repo "Ubuntu/$os_codename/main" || rc="$(( $rc | $? ))" + check_required_apt_repo "Ubuntu/$os_codename/universe" || rc="$(( $rc | $? ))" + check_unsupported_apt_repos_ubuntu "$mode" || rc="$(( $rc | $? ))" + + return $rc +} + +check_unsupported_apt_repos_debian() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + + local repos="$( + find_apt_repo "Debian Backports/$os_codename-backports/[^,]+" + find_apt_repo "Debian[^,]*/[^,]+/[^,]+" | grep -v "Debian.*/$os_codename.*/.*" + find_apt_repo "Ubuntu/[^,]+/[^,]+" + )" + [ -n "$repos" ] || return 0 + + echo "$repos" | while IFS="$(printf '\n')" read repo; do + report_unsupported_repo "$repo" + done + + [ "$mode" = "install" ] || return $RET_WARN + return $RET_FATAL +} + +check_repos_debian() +{ + [ -n "$os_codename" ] || return 0 + local mode="$1" + local rc=0 + + if [ "$os_name" = "debian" -a "$os_version" -ge 12 ]; then + disable_apt_suites_deb822 "$os_codename-backports" + else + disable_apt_repo "Debian Backports/$os_codename-backports/[^,]+" + fi + + check_required_apt_repo "Debian/$os_codename/main" || rc="$(( $rc | $? ))" + check_unsupported_apt_repos_debian "$mode" || rc="$(( $rc | $? ))" + + return $rc +} + +# --- + +skip_checker_on_flag "Repository check" "/tmp/plesk-installer-skip-repository-check.flag" + +checker_main 'check_repos' "$1" diff --git a/root/parallels/pool/PSA_18.0.74_18022/examiners/sh_cmd.sh b/root/parallels/pool/PSA_18.0.74_18022/examiners/sh_cmd.sh new file mode 100755 index 0000000000..ed95d0acbb --- /dev/null +++ b/root/parallels/pool/PSA_18.0.74_18022/examiners/sh_cmd.sh @@ -0,0 +1,7 @@ +#!/bin/sh +### Copyright 1999-2025. WebPros International GmbH. All rights reserved. + +[ "X${PLESK_INSTALLER_DEBUG}" = "X" ] || set -x +[ "X${PLESK_INSTALLER_STRICT_MODE}" = "X" ] || set -e + +exec "$@" diff --git a/root/parallels/pool/PSA_18.0.74_18022/plesk-18.0.74-ubt24.04-x86_64.inf3 b/root/parallels/pool/PSA_18.0.74_18022/plesk-18.0.74-ubt24.04-x86_64.inf3 new file mode 100644 index 0000000000..88d52d32e8 --- /dev/null +++ b/root/parallels/pool/PSA_18.0.74_18022/plesk-18.0.74-ubt24.04-x86_64.inf3 @@ -0,0 +1,928 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -----BEGIN PGP PUBLIC KEY BLOCK----- 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 VNnMRY8n =Hv0N -----END PGP PUBLIC KEY BLOCK----- + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + + + + + mysqlgroup + l10n + proftpd + webservers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + imapservers + + + + + + + + + + + + + + + + + + + imapservers + + + + + + + + + + + + + + mailman + spamassassin + drweb + sophos + courier + dovecot + + + + + + + + + + + + + + + + + + + + + + mailservers + + + + + + + + + + + + + + + + + + + + mailservers + + + + + + + + + + + + + + + + + + panel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + webservers + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + + + + + + + + + + + + + + + + php7.4 + + + + + + + + + + + + + + + + + + + + + + + + + + php8.3 + + + + + + + + + + + webservers + + + + + + + + webservers + + + + + + + + + + + + + + + + + + panel + + + + + + + + + + + + + panel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + panel + + + + + + + + + + + + + + + + + + + + panel + + + + + + + panel + + + + + + + + panel + + + + + + + panel + passenger + + + + + + ruby + + + + + + + panel + + + + + + panel + + + + + + panel + passenger + + + + + + + + + + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + + + panel + + + + panel + roundcube + postfix + dovecot + mod_fcgid + proftpd + webalizer + awstats + webservers + nginx + mysqlgroup + l10n + bind + wp-toolkit + advisor + git + xovi + imunify360 + fail2ban + modsecurity + sslit + letsencrypt + repair-kit + composer + monitoring + log-browser + ssh-terminal + site-import + sitejet + ntp-timesync + php8.3 + php8.4 + mfa + configurations-troubleshooter + + + panel + roundcube + postfix + dovecot + mod_fcgid + proftpd + webalizer + awstats + webservers + nginx + mysqlgroup + l10n + bind + wp-toolkit + advisor + git + xovi + imunify360 + fail2ban + modsecurity + sslit + letsencrypt + repair-kit + composer + monitoring + log-browser + ssh-terminal + site-import + sitejet + ntp-timesync + php8.1 + php8.2 + php8.3 + php8.4 + mfa + configurations-troubleshooter + resctrl + drweb + postgresql + spamassassin + ruby + gems-pre + nodejs + pmm + psa-firewall + watchdog + passenger + phpgroup + sophos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/PSA_18.0.74_18022/release.inf3 b/root/parallels/pool/PSA_18.0.74_18022/release.inf3 new file mode 100644 index 0000000000..bcac0846cb --- /dev/null +++ b/root/parallels/pool/PSA_18.0.74_18022/release.inf3 @@ -0,0 +1,36 @@ + + + + + + + + + psa + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/WPB_18.0.55_74/release.inf3 b/root/parallels/pool/WPB_18.0.55_74/release.inf3 new file mode 100644 index 0000000000..94de1181b8 --- /dev/null +++ b/root/parallels/pool/WPB_18.0.55_74/release.inf3 @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/WPB_18.0.59_78/release.inf3 b/root/parallels/pool/WPB_18.0.59_78/release.inf3 new file mode 100644 index 0000000000..2ca3d25c6f --- /dev/null +++ b/root/parallels/pool/WPB_18.0.59_78/release.inf3 @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/WPB_18.0.69_87/release.inf3 b/root/parallels/pool/WPB_18.0.69_87/release.inf3 new file mode 100644 index 0000000000..a3ef0137bb --- /dev/null +++ b/root/parallels/pool/WPB_18.0.69_87/release.inf3 @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/WPB_18.0.69_87/sitebuilder-18.0.69-deball-all.inf3 b/root/parallels/pool/WPB_18.0.69_87/sitebuilder-18.0.69-deball-all.inf3 new file mode 100644 index 0000000000..3b4244abb6 --- /dev/null +++ b/root/parallels/pool/WPB_18.0.69_87/sitebuilder-18.0.69-deball-all.inf3 @@ -0,0 +1,28 @@ + + + -----BEGIN PGP PUBLIC KEY BLOCK----- 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 VNnMRY8n =Hv0N -----END PGP PUBLIC KEY BLOCK----- + + + pp-sitebuilder + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/WPB_18.0.69_88/release.inf3 b/root/parallels/pool/WPB_18.0.69_88/release.inf3 new file mode 100644 index 0000000000..e545568925 --- /dev/null +++ b/root/parallels/pool/WPB_18.0.69_88/release.inf3 @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pool/WPB_18.0.69_88/sitebuilder-18.0.69-deball-all.inf3 b/root/parallels/pool/WPB_18.0.69_88/sitebuilder-18.0.69-deball-all.inf3 new file mode 100644 index 0000000000..3efbc63385 --- /dev/null +++ b/root/parallels/pool/WPB_18.0.69_88/sitebuilder-18.0.69-deball-all.inf3 @@ -0,0 +1,28 @@ + + + -----BEGIN PGP PUBLIC KEY BLOCK----- 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 VNnMRY8n =Hv0N -----END PGP PUBLIC KEY BLOCK----- + + + pp-sitebuilder + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/pp-sitebuilder.inf3 b/root/parallels/pp-sitebuilder.inf3 new file mode 100644 index 0000000000..f51b0c544f --- /dev/null +++ b/root/parallels/pp-sitebuilder.inf3 @@ -0,0 +1,712 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/products.inf3 b/root/parallels/products.inf3 new file mode 100644 index 0000000000..c85f4eba4b --- /dev/null +++ b/root/parallels/products.inf3 @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/report-update b/root/parallels/report-update new file mode 100644 index 0000000000..fc90b069d0 Binary files /dev/null and b/root/parallels/report-update differ diff --git a/root/parallels/setemplates.inf3 b/root/parallels/setemplates.inf3 new file mode 100644 index 0000000000..8b38e9106b --- /dev/null +++ b/root/parallels/setemplates.inf3 @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/parallels/sitebuilder.inf3 b/root/parallels/sitebuilder.inf3 new file mode 100644 index 0000000000..9da3099163 --- /dev/null +++ b/root/parallels/sitebuilder.inf3 @@ -0,0 +1,163 @@ + + + + + sitebuilder + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Internal Server Error - git.cutemeli.com 500 Internal Server Error Gitea Version: 1.25.2
Gitea Version: 1.25.2