function Authenticate(&$headers, $proxy, &$proxy_authorization, &$user, &$password, &$realm, &$workstation) { if ($proxy) { $authenticate_header = "proxy-authenticate"; $authorization_header = "Proxy-Authorization"; $authenticate_status = "407"; $authentication_mechanism = $this->proxy_authentication_mechanism; } else { $authenticate_header = "www-authenticate"; $authorization_header = "Authorization"; $authenticate_status = "401"; $authentication_mechanism = $this->authentication_mechanism; } if (isset($headers[$authenticate_header])) { if (function_exists("class_exists") && !class_exists("sasl_client_class", 0)) { return $this->SetError("the SASL client class needs to be loaded to be able to authenticate" . ($proxy ? " with the proxy server" : "") . " and access this site"); } if (GetType($headers[$authenticate_header]) == "array") { $authenticate = $headers[$authenticate_header]; } else { $authenticate = array($headers[$authenticate_header]); } for ($response = "", $mechanisms = array(), $m = 0; $m < count($authenticate); $m++) { $mechanism = $this->Tokenize($authenticate[$m], " "); $response = $this->Tokenize(""); if (strlen($authentication_mechanism)) { if (!strcmp($authentication_mechanism, $mechanism)) { $mechanisms[] = $mechanism; break; } } else { $mechanisms[] = $mechanism; } } $sasl = new sasl_client_class(); if (isset($user)) { $sasl->SetCredential("user", $user); } if (isset($password)) { $sasl->SetCredential("password", $password); } if (isset($realm)) { $sasl->SetCredential("realm", $realm); } if (isset($workstation)) { $sasl->SetCredential("workstation", $workstation); } $sasl->SetCredential("uri", $this->request_uri); $sasl->SetCredential("method", $this->request_method); $sasl->SetCredential("session", $this->session); do { $status = $sasl->Start($mechanisms, $message, $interactions); } while ($status == SASL_INTERACT); switch ($status) { case SASL_CONTINUE: break; case SASL_NOMECH: return $this->SetError(($proxy ? "proxy " : "") . "authentication error: " . (strlen($authentication_mechanism) ? "authentication mechanism " . $authentication_mechanism . " may not be used: " : "") . $sasl->error); default: return $this->SetError("Could not start the SASL " . ($proxy ? "proxy " : "") . "authentication client: " . $sasl->error); } if ($proxy >= 0) { for (;;) { if (strlen($error = $this->ReadReplyBody($body, $this->file_buffer_length))) { return $error; } if (strlen($body) == 0) { break; } } } $authorization_value = $sasl->mechanism . (isset($message) ? " " . ($sasl->encode_response ? base64_encode($message) : $message) : ""); $request_arguments = $this->request_arguments; $arguments = $request_arguments; $arguments["Headers"][$authorization_header] = $authorization_value; if (!$proxy && strlen($proxy_authorization)) { $arguments["Headers"]["Proxy-Authorization"] = $proxy_authorization; } if (strlen($error = $this->Close()) || strlen($error = $this->Open($arguments))) { return $this->SetError($error); } $authenticated = 0; if (isset($message)) { if ($proxy < 0) { if (strlen($error = $this->ConnectFromProxy($arguments, $headers))) { return $this->SetError($error); } } else { if (strlen($error = $this->SendRequest($arguments)) || strlen($error = $this->ReadReplyHeadersResponse($headers))) { return $this->SetError($error); } } if (!isset($headers[$authenticate_header])) { $authenticate = array(); } elseif (GetType($headers[$authenticate_header]) == "array") { $authenticate = $headers[$authenticate_header]; } else { $authenticate = array($headers[$authenticate_header]); } for ($mechanism = 0; $mechanism < count($authenticate); $mechanism++) { if (!strcmp($this->Tokenize($authenticate[$mechanism], " "), $sasl->mechanism)) { $response = $this->Tokenize(""); break; } } switch ($this->response_status) { case $authenticate_status: break; case "301": case "302": case "303": case "307": if ($proxy >= 0) { return $this->Redirect($headers); } default: if (intval($this->response_status / 100) == 2) { if ($proxy) { $proxy_authorization = $authorization_value; } $authenticated = 1; break; } if ($proxy && !strcmp($this->response_status, "401")) { $proxy_authorization = $authorization_value; $authenticated = 1; break; } return $this->SetError(($proxy ? "proxy " : "") . "authentication error: " . $this->response_status . " " . $this->response_message); } } for (; !$authenticated;) { do { $status = $sasl->Step($response, $message, $interactions); } while ($status == SASL_INTERACT); switch ($status) { case SASL_CONTINUE: $authorization_value = $sasl->mechanism . (isset($message) ? " " . ($sasl->encode_response ? base64_encode($message) : $message) : ""); $arguments = $request_arguments; $arguments["Headers"][$authorization_header] = $authorization_value; if (!$proxy && strlen($proxy_authorization)) { $arguments["Headers"]["Proxy-Authorization"] = $proxy_authorization; } if ($proxy < 0) { if (strlen($error = $this->ConnectFromProxy($arguments, $headers))) { return $this->SetError($error); } } else { if (strlen($error = $this->SendRequest($arguments)) || strlen($error = $this->ReadReplyHeadersResponse($headers))) { return $this->SetError($error); } } switch ($this->response_status) { case $authenticate_status: if (GetType($headers[$authenticate_header]) == "array") { $authenticate = $headers[$authenticate_header]; } else { $authenticate = array($headers[$authenticate_header]); } for ($response = "", $mechanism = 0; $mechanism < count($authenticate); $mechanism++) { if (!strcmp($this->Tokenize($authenticate[$mechanism], " "), $sasl->mechanism)) { $response = $this->Tokenize(""); break; } } if ($proxy >= 0) { for (;;) { if (strlen($error = $this->ReadReplyBody($body, $this->file_buffer_length))) { return $error; } if (strlen($body) == 0) { break; } } } $this->state = "Connected"; break; case "301": case "302": case "303": case "307": if ($proxy >= 0) { return $this->Redirect($headers); } default: if (intval($this->response_status / 100) == 2) { if ($proxy) { $proxy_authorization = $authorization_value; } $authenticated = 1; break; } if ($proxy && !strcmp($this->response_status, "401")) { $proxy_authorization = $authorization_value; $authenticated = 1; break; } return $this->SetError(($proxy ? "proxy " : "") . "authentication error: " . $this->response_status . " " . $this->response_message); } break; default: return $this->SetError("Could not process the SASL " . ($proxy ? "proxy " : "") . "authentication step: " . $sasl->error); } } } return ""; }
function SASLAuthenticate($mechanisms, $credentials, &$authenticated, &$mechanism) { $authenticated = 0; if (!function_exists("class_exists") || !class_exists("sasl_client_class")) { $this->error = "it is not possible to authenticate using the specified mechanism because the SASL library class is not loaded"; return 0; } $sasl = new sasl_client_class(); $sasl->SetCredential("user", $credentials["user"]); $sasl->SetCredential("password", $credentials["password"]); if (isset($credentials["realm"])) { $sasl->SetCredential("realm", $credentials["realm"]); } if (isset($credentials["workstation"])) { $sasl->SetCredential("workstation", $credentials["workstation"]); } if (isset($credentials["mode"])) { $sasl->SetCredential("mode", $credentials["mode"]); } do { $status = $sasl->Start($mechanisms, $message, $interactions); } while ($status == SASL_INTERACT); switch ($status) { case SASL_CONTINUE: break; case SASL_NOMECH: if (strlen($this->authentication_mechanism)) { $this->error = "authenticated mechanism " . $this->authentication_mechanism . " may not be used: " . $sasl->error; return 0; } break; default: $this->error = "Could not start the SASL authentication client: " . $sasl->error; return 0; } if (strlen($mechanism = $sasl->mechanism)) { if ($this->PutLine("AUTH " . $sasl->mechanism . (isset($message) ? " " . base64_encode($message) : "")) == 0) { $this->error = "Could not send the AUTH command"; return 0; } if (!$this->VerifyResultLines(array("235", "334"), $responses)) { return 0; } switch ($this->result_code) { case "235": $response = ""; $authenticated = 1; break; case "334": $response = base64_decode($responses[0]); break; default: $this->error = "Authentication error: " . $responses[0]; return 0; } for (; !$authenticated;) { do { $status = $sasl->Step($response, $message, $interactions); } while ($status == SASL_INTERACT); switch ($status) { case SASL_CONTINUE: if ($this->PutLine(base64_encode($message)) == 0) { $this->error = "Could not send the authentication step message"; return 0; } if (!$this->VerifyResultLines(array("235", "334"), $responses)) { return 0; } switch ($this->result_code) { case "235": $response = ""; $authenticated = 1; break; case "334": $response = base64_decode($responses[0]); break; default: $this->error = "Authentication error: " . $responses[0]; return 0; } break; default: $this->error = "Could not process the SASL authentication step: " . $sasl->error; return 0; } } } return 1; }
function Login($user, $password, $apop = 0) { if ($this->state != "AUTHORIZATION") { return $this->SetError("connection is not in AUTHORIZATION state"); } if ($apop) { if (!strcmp($this->greeting, "")) { return $this->SetError("Server does not seem to support APOP authentication"); } if ($this->PutLine("APOP {$user} " . md5("<" . $this->greeting . ">" . $password)) == 0) { return $this->SetError("Could not send the APOP command"); } $response = $this->GetLine(); if (GetType($response) != "string") { return $this->SetError("Could not get APOP login command response"); } if ($this->Tokenize($response, " ") != "+OK") { return $this->SetError("APOP login failed: " . $this->Tokenize("\r\n")); } } else { $authenticated = 0; if (strcmp($this->authentication_mechanism, "USER") && function_exists("class_exists") && class_exists("sasl_client_class")) { if (strlen($this->authentication_mechanism)) { $mechanisms = array($this->authentication_mechanism); } else { $mechanisms = array(); if ($this->PutLine("CAPA") == 0) { return $this->SetError("Could not send the CAPA command"); } $response = $this->GetLine(); if (GetType($response) != "string") { return $this->SetError("Could not get CAPA command response"); } if (!strcmp($this->Tokenize($response, " "), "+OK")) { for (;;) { $response = $this->GetLine(); if (GetType($response) != "string") { return $this->SetError("Could not retrieve the supported authentication methods"); } switch ($this->Tokenize($response, " ")) { case ".": break 2; case "SASL": for ($method = 1; strlen($mechanism = $this->Tokenize(" ")); $method++) { $mechanisms[] = $mechanism; } break; } } } } $sasl = new sasl_client_class(); $sasl->SetCredential("user", $user); $sasl->SetCredential("password", $password); if (strlen($this->realm)) { $sasl->SetCredential("realm", $this->realm); } if (strlen($this->workstation)) { $sasl->SetCredential("workstation", $this->workstation); } do { $status = $sasl->Start($mechanisms, $message, $interactions); } while ($status == SASL_INTERACT); switch ($status) { case SASL_CONTINUE: break; case SASL_NOMECH: if (strlen($this->authentication_mechanism)) { return $this->SetError("authenticated mechanism " . $this->authentication_mechanism . " may not be used: " . $sasl->error); } break; default: return $this->SetError("Could not start the SASL authentication client: " . $sasl->error); } if (strlen($sasl->mechanism)) { if ($this->PutLine("AUTH " . $sasl->mechanism . (isset($message) ? " " . base64_encode($message) : "")) == 0) { return "Could not send the AUTH command"; } $response = $this->GetLine(); if (GetType($response) != "string") { return "Could not get AUTH command response"; } switch ($this->Tokenize($response, " ")) { case "+OK": $response = ""; break; case "+": $response = base64_decode($this->Tokenize("\r\n")); break; default: return $this->SetError("Authentication error: " . $this->Tokenize("\r\n")); } for (; !$authenticated;) { do { $status = $sasl->Step($response, $message, $interactions); } while ($status == SASL_INTERACT); switch ($status) { case SASL_CONTINUE: if ($this->PutLine(base64_encode($message)) == 0) { return "Could not send message authentication step message"; } $response = $this->GetLine(); if (GetType($response) != "string") { return "Could not get authentication step message response"; } switch ($this->Tokenize($response, " ")) { case "+OK": $authenticated = 1; break; case "+": $response = base64_decode($this->Tokenize("\r\n")); break; default: return $this->SetError("Authentication error: " . $this->Tokenize("\r\n")); } break; default: return $this->SetError("Could not process the SASL authentication step: " . $sasl->error); } } } } if (!$authenticated) { if ($this->PutLine("USER {$user}") == 0) { return $this->SetError("Could not send the USER command"); } $response = $this->GetLine(); if (GetType($response) != "string") { return $this->SetError("Could not get user login entry response"); } if ($this->Tokenize($response, " ") != "+OK") { return $this->SetError("User error: " . $this->Tokenize("\r\n")); } if ($this->PutLine("PASS {$password}") == 0) { return $this->SetError("Could not send the PASS command"); } $response = $this->GetLine(); if (GetType($response) != "string") { return $this->SetError("Could not get login password entry response"); } if ($this->Tokenize($response, " ") != "+OK") { return $this->SetError("Password error: " . $this->Tokenize("\r\n")); } } } $this->state = "TRANSACTION"; return ""; }