|
1 | 1 | // |
2 | 2 | // SMTPClientSession.cpp |
3 | 3 | // |
4 | | -// $Id: //poco/svn/Net/src/SMTPClientSession.cpp#3 $ |
| 4 | +// $Id: //poco/Main/Net/src/SMTPClientSession.cpp#10 $ |
5 | 5 | // |
6 | 6 | // Library: Net |
7 | 7 | // Package: Mail |
8 | 8 | // Module: SMTPClientSession |
9 | 9 | // |
10 | | -// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH. |
| 10 | +// Copyright (c) 2005-2008, Applied Informatics Software Engineering GmbH. |
11 | 11 | // and Contributors. |
12 | 12 | // |
13 | 13 | // Permission is hereby granted, free of charge, to any person or organization |
|
42 | 42 | #include "Poco/Net/SocketStream.h" |
43 | 43 | #include "Poco/Net/NetException.h" |
44 | 44 | #include "Poco/Environment.h" |
| 45 | +#include "Poco/Net/NetworkInterface.h" |
| 46 | +#include "Poco/HMACEngine.h" |
| 47 | +#include "Poco/MD5Engine.h" |
| 48 | +#include "Poco/DigestStream.h" |
| 49 | +#include "Poco/StreamCopier.h" |
| 50 | +#include "Poco/Base64Encoder.h" |
| 51 | +#include "Poco/Base64Decoder.h" |
| 52 | +#include <sstream> |
| 53 | +#include <fstream> |
| 54 | +#include <iostream> |
45 | 55 |
|
46 | 56 |
|
| 57 | +using Poco::DigestEngine; |
| 58 | +using Poco::HMACEngine; |
| 59 | +using Poco::MD5Engine; |
| 60 | +using Poco::DigestOutputStream; |
| 61 | +using Poco::StreamCopier; |
| 62 | +using Poco::Base64Encoder; |
| 63 | +using Poco::Base64Decoder; |
47 | 64 | using Poco::Environment; |
48 | 65 |
|
49 | 66 |
|
@@ -89,23 +106,137 @@ Poco::Timespan SMTPClientSession::getTimeout() const |
89 | 106 | } |
90 | 107 |
|
91 | 108 |
|
92 | | -void SMTPClientSession::login(const std::string& hostname) |
| 109 | +void SMTPClientSession::login(const std::string& hostname, std::string& response) |
93 | 110 | { |
94 | 111 | open(); |
95 | | - std::string response; |
96 | 112 | int status = sendCommand("EHLO", hostname, response); |
97 | 113 | if (isPermanentNegative(status)) |
98 | 114 | status = sendCommand("HELO", hostname, response); |
99 | 115 | if (!isPositiveCompletion(status)) throw SMTPException("Login failed", response); |
100 | 116 | } |
101 | 117 |
|
102 | 118 |
|
| 119 | +void SMTPClientSession::login(const std::string& hostname) |
| 120 | +{ |
| 121 | + std::string response; |
| 122 | + login(hostname, response); |
| 123 | +} |
| 124 | + |
| 125 | + |
103 | 126 | void SMTPClientSession::login() |
104 | 127 | { |
105 | 128 | login(Environment::nodeName()); |
106 | 129 | } |
107 | 130 |
|
108 | 131 |
|
| 132 | +void SMTPClientSession::loginUsingCRAM_MD5(const std::string& username, const std::string& password) |
| 133 | +{ |
| 134 | + int status = 0; |
| 135 | + std::string response; |
| 136 | + |
| 137 | + status = sendCommand("AUTH CRAM-MD5", response); |
| 138 | + if (!isPositiveIntermediate(status)) throw SMTPException("Cannot authenticate CRAM-MD5", response); |
| 139 | + std::string challengeBase64 = response.substr(4); |
| 140 | + |
| 141 | + std::istringstream istr(challengeBase64); |
| 142 | + Base64Decoder decoder(istr); |
| 143 | + std::string challenge; |
| 144 | + decoder >> challenge; |
| 145 | + |
| 146 | + HMACEngine<MD5Engine> hmac(password); |
| 147 | + hmac.update(challenge); |
| 148 | + |
| 149 | + const DigestEngine::Digest& digest = hmac.digest(); |
| 150 | + std::string digestString(DigestEngine::digestToHex(digest)); |
| 151 | + |
| 152 | + std::string challengeResponse = username + " " + digestString; |
| 153 | + |
| 154 | + std::ostringstream challengeResponseBase64; |
| 155 | + Base64Encoder encoder(challengeResponseBase64); |
| 156 | + encoder << challengeResponse; |
| 157 | + encoder.close(); |
| 158 | + |
| 159 | + status = sendCommand(challengeResponseBase64.str(), response); |
| 160 | + if (!isPositiveCompletion(status)) throw SMTPException("Login using CRAM-MD5 failed", response); |
| 161 | +} |
| 162 | + |
| 163 | + |
| 164 | +void SMTPClientSession::loginUsingLogin(const std::string& username, const std::string& password) |
| 165 | +{ |
| 166 | + int status = 0; |
| 167 | + std::string response; |
| 168 | + |
| 169 | + status = sendCommand("AUTH LOGIN", response); |
| 170 | + if (!isPositiveIntermediate(status)) throw SMTPException("Cannot authenticate LOGIN", response); |
| 171 | + |
| 172 | + std::ostringstream usernameBase64; |
| 173 | + Base64Encoder usernameEncoder(usernameBase64); |
| 174 | + usernameEncoder << username; |
| 175 | + usernameEncoder.close(); |
| 176 | + |
| 177 | + std::ostringstream passwordBase64; |
| 178 | + Base64Encoder passwordEncoder(passwordBase64); |
| 179 | + passwordEncoder << password; |
| 180 | + passwordEncoder.close(); |
| 181 | + |
| 182 | + //Server request for username/password not defined could be either |
| 183 | + //S: login: |
| 184 | + //C: user_login |
| 185 | + //S: password: |
| 186 | + //C: user_password |
| 187 | + //or |
| 188 | + //S: password: |
| 189 | + //C: user_password |
| 190 | + //S: login: |
| 191 | + //C: user_login |
| 192 | + if (response == "334 VXNlcm5hbWU6") // username first (md5("Username:")) |
| 193 | + { |
| 194 | + status = sendCommand(usernameBase64.str(), response); |
| 195 | + if (!isPositiveIntermediate(status)) throw SMTPException("Login using LOGIN user name failed", response); |
| 196 | + |
| 197 | + status = sendCommand(passwordBase64.str(), response); |
| 198 | + if (!isPositiveCompletion(status)) throw SMTPException("Login using LOGIN password failed", response); |
| 199 | + } |
| 200 | + else if (response == "334 UGFzc3dvcmQ6") // password first (md5("Password:")) |
| 201 | + { |
| 202 | + status = sendCommand(passwordBase64.str(), response); |
| 203 | + if (!isPositiveIntermediate(status)) throw SMTPException("Login using LOGIN password failed", response); |
| 204 | + |
| 205 | + status = sendCommand(usernameBase64.str(), response); |
| 206 | + if (!isPositiveCompletion(status)) throw SMTPException("Login using LOGIN user name failed", response); |
| 207 | + } |
| 208 | + |
| 209 | +} |
| 210 | + |
| 211 | + |
| 212 | +void SMTPClientSession::login(LoginMethod loginMethod, const std::string& username, const std::string& password) |
| 213 | +{ |
| 214 | + std::string response; |
| 215 | + login(Environment::nodeName(), response); |
| 216 | + |
| 217 | + if (loginMethod == AUTH_CRAM_MD5) |
| 218 | + { |
| 219 | + if (response.find("CRAM-MD5", 0) != std::string::npos) |
| 220 | + { |
| 221 | + loginUsingCRAM_MD5(username, password); |
| 222 | + } |
| 223 | + else throw SMTPException("The mail service does not support CRAM-MD5 authentication", response); |
| 224 | + } |
| 225 | + else if (loginMethod == AUTH_LOGIN) |
| 226 | + { |
| 227 | + if (response.find("LOGIN", 0) != std::string::npos) |
| 228 | + { |
| 229 | + loginUsingLogin(username, password); |
| 230 | + } |
| 231 | + else throw SMTPException("The mail service does not support LOGIN authentication", response); |
| 232 | + } |
| 233 | + else if (loginMethod != AUTH_NONE) |
| 234 | + { |
| 235 | + throw SMTPException("The autentication method is not supported"); |
| 236 | + } |
| 237 | +} |
| 238 | + |
| 239 | + |
109 | 240 | void SMTPClientSession::open() |
110 | 241 | { |
111 | 242 | if (!_isOpen) |
|
0 commit comments