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 
Authenticator()29 Authenticator::Authenticator() {
30   assign(NULL, NULL, NULL, NULL, False);
31 }
32 
Authenticator(char const * username,char const * password,Boolean passwordIsMD5)33 Authenticator::Authenticator(char const* username, char const* password, Boolean passwordIsMD5) {
34   assign(NULL, NULL, username, password, passwordIsMD5);
35 }
36 
Authenticator(const Authenticator & orig)37 Authenticator::Authenticator(const Authenticator& orig) {
38   assign(orig.realm(), orig.nonce(), orig.username(), orig.password(), orig.fPasswordIsMD5);
39 }
40 
operator =(const Authenticator & rightSide)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 
operator <(const Authenticator * rightSide)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 
~Authenticator()64 Authenticator::~Authenticator() {
65   reset();
66 }
67 
reset()68 void Authenticator::reset() {
69   resetRealmAndNonce();
70   resetUsernameAndPassword();
71 }
72 
setRealmAndNonce(char const * realm,char const * nonce)73 void Authenticator::setRealmAndNonce(char const* realm, char const* nonce) {
74   resetRealmAndNonce();
75   assignRealmAndNonce(realm, nonce);
76 }
77 
setRealmAndRandomNonce(char const * realm)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 
setUsernameAndPassword(char const * username,char const * password,Boolean passwordIsMD5)97 void Authenticator::setUsernameAndPassword(char const* username,
98 					   char const* password,
99 					   Boolean passwordIsMD5) {
100   resetUsernameAndPassword();
101   assignUsernameAndPassword(username, password, passwordIsMD5);
102 }
103 
computeDigestResponse(char const * cmd,char const * url) const104 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 
reclaimDigestResponse(char const * responseStr) const140 void Authenticator::reclaimDigestResponse(char const* responseStr) const {
141   delete[](char*)responseStr;
142 }
143 
resetRealmAndNonce()144 void Authenticator::resetRealmAndNonce() {
145   delete[] fRealm; fRealm = NULL;
146   delete[] fNonce; fNonce = NULL;
147 }
148 
resetUsernameAndPassword()149 void Authenticator::resetUsernameAndPassword() {
150   delete[] fUsername; fUsername = NULL;
151   delete[] fPassword; fPassword = NULL;
152   fPasswordIsMD5 = False;
153 }
154 
assignRealmAndNonce(char const * realm,char const * nonce)155 void Authenticator::assignRealmAndNonce(char const* realm, char const* nonce) {
156   fRealm = strDup(realm);
157   fNonce = strDup(nonce);
158 }
159 
assignUsernameAndPassword(char const * username,char const * password,Boolean passwordIsMD5)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 
assign(char const * realm,char const * nonce,char const * username,char const * password,Boolean passwordIsMD5)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