| 1 | /********** |
| 2 | This library is free software; you can redistribute it and/or modify it under |
| 3 | the terms of the GNU Lesser General Public License as published by the |
| 4 | Free Software Foundation; either version 3 of the License, or (at your |
| 5 | option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.) |
| 6 | |
| 7 | This library is distributed in the hope that it will be useful, but WITHOUT |
| 8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for |
| 10 | more details. |
| 11 | |
| 12 | You should have received a copy of the GNU Lesser General Public License |
| 13 | along with this library; if not, write to the Free Software Foundation, Inc., |
| 14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| 15 | **********/ |
| 16 | // "liveMedia" |
| 17 | // Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved. |
| 18 | // A class used for digest authentication. |
| 19 | // Implementation |
| 20 | |
| 21 | #include "DigestAuthentication.hh" |
| 22 | #include "ourMD5.hh" |
| 23 | #include <strDup.hh> |
| 24 | #include <GroupsockHelper.hh> // for gettimeofday() |
| 25 | #include <stdio.h> |
| 26 | #include <stdlib.h> |
| 27 | #include <string.h> |
| 28 | |
| 29 | Authenticator::Authenticator() { |
| 30 | assign(NULL, NULL, NULL, NULL, False); |
| 31 | } |
| 32 | |
| 33 | Authenticator::Authenticator(char const* username, char const* password, Boolean passwordIsMD5) { |
| 34 | assign(NULL, NULL, username, password, passwordIsMD5); |
| 35 | } |
| 36 | |
| 37 | Authenticator::Authenticator(const Authenticator& orig) { |
| 38 | assign(orig.realm(), orig.nonce(), orig.username(), orig.password(), orig.fPasswordIsMD5); |
| 39 | } |
| 40 | |
| 41 | Authenticator& Authenticator::operator=(const Authenticator& rightSide) { |
| 42 | if (&rightSide != this) { |
| 43 | reset(); |
| 44 | assign(rightSide.realm(), rightSide.nonce(), |
| 45 | rightSide.username(), rightSide.password(), rightSide.fPasswordIsMD5); |
| 46 | } |
| 47 | |
| 48 | return *this; |
| 49 | } |
| 50 | |
| 51 | Boolean Authenticator::operator<(const Authenticator* rightSide) { |
| 52 | // Returns True if "rightSide" is 'newer' than us: |
| 53 | if (rightSide != NULL && rightSide != this && |
| 54 | (rightSide->realm() != NULL || rightSide->nonce() != NULL || |
| 55 | username() == NULL || password() == NULL || |
| 56 | strcmp(rightSide->username(), username()) != 0 || |
| 57 | strcmp(rightSide->password(), password()) != 0)) { |
| 58 | return True; |
| 59 | } |
| 60 | |
| 61 | return False; |
| 62 | } |
| 63 | |
| 64 | Authenticator::~Authenticator() { |
| 65 | reset(); |
| 66 | } |
| 67 | |
| 68 | void Authenticator::reset() { |
| 69 | resetRealmAndNonce(); |
| 70 | resetUsernameAndPassword(); |
| 71 | } |
| 72 | |
| 73 | void Authenticator::setRealmAndNonce(char const* realm, char const* nonce) { |
| 74 | resetRealmAndNonce(); |
| 75 | assignRealmAndNonce(realm, nonce); |
| 76 | } |
| 77 | |
| 78 | void Authenticator::setRealmAndRandomNonce(char const* realm) { |
| 79 | resetRealmAndNonce(); |
| 80 | |
| 81 | // Construct data to seed the random nonce: |
| 82 | struct { |
| 83 | struct timeval timestamp; |
| 84 | unsigned counter; |
| 85 | } seedData; |
| 86 | gettimeofday(&seedData.timestamp, NULL); |
| 87 | static unsigned counter = 0; |
| 88 | seedData.counter = ++counter; |
| 89 | |
| 90 | // Use MD5 to compute a 'random' nonce from this seed data: |
| 91 | char nonceBuf[33]; |
| 92 | our_MD5Data((unsigned char*)(&seedData), sizeof seedData, nonceBuf); |
| 93 | |
| 94 | assignRealmAndNonce(realm, nonceBuf); |
| 95 | } |
| 96 | |
| 97 | void Authenticator::setUsernameAndPassword(char const* username, |
| 98 | char const* password, |
| 99 | Boolean passwordIsMD5) { |
| 100 | resetUsernameAndPassword(); |
| 101 | assignUsernameAndPassword(username, password, passwordIsMD5); |
| 102 | } |
| 103 | |
| 104 | char const* Authenticator::computeDigestResponse(char const* cmd, |
| 105 | char const* url) const { |
| 106 | // The "response" field is computed as: |
| 107 | // md5(md5(<username>:<realm>:<password>):<nonce>:md5(<cmd>:<url>)) |
| 108 | // or, if "fPasswordIsMD5" is True: |
| 109 | // md5(<password>:<nonce>:md5(<cmd>:<url>)) |
| 110 | char ha1Buf[33]; |
| 111 | if (fPasswordIsMD5) { |
| 112 | strncpy(ha1Buf, password(), 32); |
| 113 | ha1Buf[32] = '\0'; // just in case |
| 114 | } else { |
| 115 | unsigned const ha1DataLen = strlen(username()) + 1 |
| 116 | + strlen(realm()) + 1 + strlen(password()); |
| 117 | unsigned char* ha1Data = new unsigned char[ha1DataLen+1]; |
| 118 | sprintf((char*)ha1Data, "%s:%s:%s" , username(), realm(), password()); |
| 119 | our_MD5Data(ha1Data, ha1DataLen, ha1Buf); |
| 120 | delete[] ha1Data; |
| 121 | } |
| 122 | |
| 123 | unsigned const ha2DataLen = strlen(cmd) + 1 + strlen(url); |
| 124 | unsigned char* ha2Data = new unsigned char[ha2DataLen+1]; |
| 125 | sprintf((char*)ha2Data, "%s:%s" , cmd, url); |
| 126 | char ha2Buf[33]; |
| 127 | our_MD5Data(ha2Data, ha2DataLen, ha2Buf); |
| 128 | delete[] ha2Data; |
| 129 | |
| 130 | unsigned const digestDataLen |
| 131 | = 32 + 1 + strlen(nonce()) + 1 + 32; |
| 132 | unsigned char* digestData = new unsigned char[digestDataLen+1]; |
| 133 | sprintf((char*)digestData, "%s:%s:%s" , |
| 134 | ha1Buf, nonce(), ha2Buf); |
| 135 | char const* result = our_MD5Data(digestData, digestDataLen, NULL); |
| 136 | delete[] digestData; |
| 137 | return result; |
| 138 | } |
| 139 | |
| 140 | void Authenticator::reclaimDigestResponse(char const* responseStr) const { |
| 141 | delete[](char*)responseStr; |
| 142 | } |
| 143 | |
| 144 | void Authenticator::resetRealmAndNonce() { |
| 145 | delete[] fRealm; fRealm = NULL; |
| 146 | delete[] fNonce; fNonce = NULL; |
| 147 | } |
| 148 | |
| 149 | void Authenticator::resetUsernameAndPassword() { |
| 150 | delete[] fUsername; fUsername = NULL; |
| 151 | delete[] fPassword; fPassword = NULL; |
| 152 | fPasswordIsMD5 = False; |
| 153 | } |
| 154 | |
| 155 | void Authenticator::assignRealmAndNonce(char const* realm, char const* nonce) { |
| 156 | fRealm = strDup(realm); |
| 157 | fNonce = strDup(nonce); |
| 158 | } |
| 159 | |
| 160 | void Authenticator::assignUsernameAndPassword(char const* username, char const* password, Boolean passwordIsMD5) { |
| 161 | if (username == NULL) username = "" ; |
| 162 | if (password == NULL) password = "" ; |
| 163 | |
| 164 | fUsername = strDup(username); |
| 165 | fPassword = strDup(password); |
| 166 | fPasswordIsMD5 = passwordIsMD5; |
| 167 | } |
| 168 | |
| 169 | void Authenticator::assign(char const* realm, char const* nonce, |
| 170 | char const* username, char const* password, Boolean passwordIsMD5) { |
| 171 | assignRealmAndNonce(realm, nonce); |
| 172 | assignUsernameAndPassword(username, password, passwordIsMD5); |
| 173 | } |
| 174 | |