- Install to ~/.local/bin/winamp-mpris - Use ~/.local/state/winamp-mpris/bridge.log for logging - Use $XDG_RUNTIME_DIR/winamp-mpris.pid for PID management - Add detailed user notification for 401 Unauthorized errors - Add install.sh for automated, standard-compliant setup - Include Winamp Web Interface source code and installer in repository
313 lines
7.8 KiB
C++
313 lines
7.8 KiB
C++
/* --- SECURITY.CPP ---
|
|
/
|
|
/ Written by Phil Himsworth, 2001-2002.
|
|
/
|
|
/*/
|
|
|
|
#include <windows.h>
|
|
#include <wincrypt.h>
|
|
#include <mmsystem.h>
|
|
|
|
#include "types.h"
|
|
#include "main.h"
|
|
#include "html.h"
|
|
#include "plugin.h"
|
|
|
|
extern char password[], username[];
|
|
extern int securepassword;
|
|
|
|
extern winampGeneralPurposePlugin plugin;
|
|
|
|
|
|
|
|
// Base64 character array
|
|
// 0 1 2 3 4 5 6
|
|
// 01234567890123456789012345678901234567890123456789012345678901234
|
|
char bchars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+*";
|
|
char achars[256];
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// Calculates MD5 of a string
|
|
bool MD5(char * input, char * output, int output_len)
|
|
{
|
|
//MessageBox(NULL,input,"MD5 input",MB_TOPMOST | MB_OK);
|
|
HCRYPTPROV hProv = 0;
|
|
HCRYPTHASH Hash;
|
|
|
|
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
|
|
{
|
|
LPVOID lpMsgBuf;
|
|
FormatMessage(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL,
|
|
GetLastError(),
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
|
(LPTSTR) &lpMsgBuf,
|
|
0,
|
|
NULL
|
|
);
|
|
// Process any inserts in lpMsgBuf.
|
|
// ...
|
|
// Display the string.
|
|
MessageBox( NULL, (LPCTSTR)lpMsgBuf, "MD5 AcquireContext Error", MB_OK | MB_ICONINFORMATION );
|
|
// Free the buffer.
|
|
LocalFree( lpMsgBuf );
|
|
|
|
return false;
|
|
}
|
|
|
|
CryptCreateHash(hProv,CALG_MD5, 0, 0, &Hash);
|
|
|
|
int input_len = lstrlen(input);
|
|
|
|
BYTE md5raw[2048];
|
|
int md5raw_len = 2048;
|
|
CryptHashData(Hash,(unsigned char*)input,input_len, 0); // md5 of "<time>:<password>"
|
|
CryptGetHashParam(Hash, HP_HASHVAL, md5raw,(DWORD*)&md5raw_len,0);
|
|
|
|
wsprintf(output,""); // Make output a terminated string
|
|
|
|
char temp[4];
|
|
//wsprintf(temp,"%d",md5raw_len);
|
|
//MessageBox(NULL,temp,"gen_httpSrv md5raw_len",MB_OK);
|
|
|
|
for (int i=0;i<md5raw_len;i++)
|
|
{
|
|
wsprintf(temp,"%2.2x", md5raw[i]);
|
|
lstrcat(output,temp);
|
|
}
|
|
|
|
//MessageBox(NULL,output,"gen_httpSrv debug MD5", MB_OK);
|
|
|
|
|
|
|
|
|
|
CryptReleaseContext(hProv,0);
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// Sends a 401 for Basic authentication
|
|
int SendBasic401(connection * conn, char * realm)
|
|
{
|
|
prints(conn,"HTTP/1.0 401 Unauthorized\nWWW-Authenticate: Basic realm=\"");
|
|
prints(conn,realm);
|
|
prints(conn,"\"\n");
|
|
prints(conn,"Content-Type: text/html\n\n<html>\n<head>\n<title>Login Failed</title>\n");
|
|
Style(conn);
|
|
CloseHeader(conn);
|
|
OpenPageBody(conn);
|
|
prints(conn,"<h1>Login Failed</h1>\n<p><b>Winamp Web Interface could not log you in.</b></p>\n<p><a href=\"/main\">Back to main page</a></p>");
|
|
CloseBody(conn);
|
|
conn->http.responsecode = 401;
|
|
return ST_CLOSE;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// Finds a substring in another string. Probably should be in strings.cpp...
|
|
char * FindSubString(char * buffer,char * target)
|
|
{
|
|
//MessageBox(NULL,buffer,"gen_httpSrv FindSubString",MB_OK);
|
|
int len = lstrlen(buffer) - lstrlen(target);
|
|
for (int i=0;i<=len;i++)
|
|
{
|
|
if (StartString(target,buffer+i))
|
|
return (char*)(buffer+i);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// Finds auth headers in a request
|
|
void FindBasicAuth(connection * conn, char * buffer)
|
|
{
|
|
//int ptr;
|
|
//MessageBox(NULL,buffer,"gen_httpSrv FindBasicAuth: buffer",MB_OK);
|
|
char * chptr = FindSubString(buffer,"Authorization:"); // Look for auth
|
|
if (!chptr)
|
|
{ // Not found
|
|
chptr = FindSubString(buffer,"Authorisation:"); // Misspellings?
|
|
if (!chptr) // Still no; fail
|
|
{
|
|
//MessageBox(NULL,"No Auth","gen_httpSrv debug FindBasicAuth",MB_OK);
|
|
conn->http.auth = CheckCredentials(conn,"anon","");
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Authorisation section found
|
|
//MessageBox(NULL,chptr,"gen_httpSrv debug",MB_OK);
|
|
|
|
char temp[100];
|
|
|
|
|
|
char * cl_user;
|
|
char * cl_pass;
|
|
|
|
chptr = GetAString(chptr,(char*)&temp); // chptr now points at Authorisation, so get it
|
|
chptr = GetAString(chptr,(char*)&temp); // get auth mode - 'basic'
|
|
chptr = GetAString(chptr,(char*)&temp); // get user/pass string
|
|
|
|
char userpass[100];
|
|
FromBase64((char*)&temp,(char*)&userpass);
|
|
|
|
int i=0;
|
|
while(userpass[i] != ':')
|
|
{
|
|
if (userpass[i] == 0)
|
|
{
|
|
conn->http.auth = CheckCredentials(conn,"anon","");
|
|
return;
|
|
}
|
|
i++;
|
|
}
|
|
userpass[i] = 0;
|
|
cl_pass = &userpass[i+1];
|
|
cl_user = (char*)&userpass;
|
|
|
|
|
|
//wsprintf(temp,"User: %s\nPassword: %s",cl_user,cl_pass);
|
|
//MessageBox(NULL,temp,"user/password",MB_TOPMOST | MB_OK);
|
|
//MessageBox(NULL,temp,"gen_httpSrv debug base64 from client",MB_OK);
|
|
|
|
conn->http.auth = CheckCredentials(conn, cl_user, cl_pass);
|
|
|
|
|
|
}
|
|
// --------------------------------------------------------------------------------
|
|
// Converts a string to Base64
|
|
void ToBase64(char * instr, char * outstr)
|
|
{
|
|
//MessageBox(NULL,instr,"instr",MB_OK);
|
|
|
|
int i=0;
|
|
int o=0;
|
|
int j = lstrlen(instr);
|
|
|
|
bool done = false;
|
|
|
|
while(instr[i] != 0 && done == false)
|
|
{
|
|
outstr[o] = bchars[(instr[i] & 0xFC) / 4];
|
|
outstr[o+1] = bchars[((instr[i] & 0x03) * 16) + ((instr[i+1] & 0xF0) / 16)];
|
|
if (instr[i+1] == 0)
|
|
{
|
|
outstr[o+2] = '=';
|
|
outstr[o+3] = '=';
|
|
done = true;
|
|
}
|
|
else
|
|
{
|
|
outstr[o+2] = bchars[((instr[i+1] & 0x0F) * 4) + ((instr[i+2] & 0xC0) /64)];
|
|
if (instr[i+2] == 0)
|
|
{
|
|
outstr[o+3] = '=';
|
|
done = true;
|
|
}
|
|
else
|
|
outstr[o+3] = bchars[(instr[i+2] & 0x3F)];
|
|
}
|
|
|
|
o += 4;
|
|
i += 3;
|
|
}
|
|
|
|
outstr[o] = 0;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// Converts a Base64 string to plaintext
|
|
void FromBase64(char * instr,char * outstr)
|
|
{
|
|
int i=0;
|
|
int o=0;
|
|
int j=lstrlen(instr);
|
|
|
|
for (int n=0;n<j;n++) // reduce ascii codes to numbers
|
|
{
|
|
if (instr[n] != '=')
|
|
instr[n] = achars[instr[n]];
|
|
else
|
|
instr[n] = (char)255;
|
|
}
|
|
|
|
while(instr[i] != 0)
|
|
{
|
|
outstr[o] = ((instr[i] & 0x3F) * 4) + ((instr[i+1] & 0x30) / 16);
|
|
|
|
if (instr[i+2] == (char)255)
|
|
outstr[o+1] = 0;
|
|
else
|
|
{
|
|
outstr[o+1] = ((instr[i+1] & 0x0F) * 16) + ((instr[i+2] & 0x3C) / 4);
|
|
|
|
if (instr[i+3] == (char)255)
|
|
outstr[o+2] = 0;
|
|
else
|
|
outstr[o+2] = ((instr[i+2] & 0x03) * 64) + (instr[i+3] & 0x3F);
|
|
}
|
|
|
|
i += 4;
|
|
o += 3;
|
|
}
|
|
outstr[o] = 0;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// Checks credentials with those in ini file
|
|
int CheckCredentials(connection * conn, char * user, char * pass)
|
|
{
|
|
|
|
char ini_file[MAX_PATH], *p;
|
|
GetModuleFileName(plugin.hDllInstance,ini_file,sizeof(ini_file));
|
|
p=ini_file+lstrlen(ini_file);
|
|
while (p >= ini_file && *p != '\\') p--;
|
|
if (++p >= ini_file) *p = 0;
|
|
lstrcat(ini_file,"gen_httpsrv.ini");
|
|
|
|
if (StrComp(user,"anon"))
|
|
return GetUserAccess(ini_file,user);
|
|
|
|
char password[40];
|
|
|
|
GetPrivateProfileString("Users",user,"",(char*)&password,40,ini_file);
|
|
|
|
char md5pass[40];
|
|
if (securepassword == 1)
|
|
MD5(pass,(char*)&md5pass,40);
|
|
else
|
|
ToBase64(pass,md5pass);
|
|
|
|
//if (password[0] == 0)
|
|
// return AUTH_ANON;
|
|
|
|
//char temp[150];
|
|
//wsprintf(temp,"file: %s\nrecv: %s",password,md5pass);
|
|
//MessageBox(NULL,temp,"auth",MB_OK | MB_TOPMOST);
|
|
|
|
if (StrComp(password,md5pass))
|
|
{
|
|
wsprintf(conn->http.user,user);
|
|
return GetUserAccess(ini_file, user);
|
|
}
|
|
else
|
|
return AUTH_ANON;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// Gets access rights from the ini file
|
|
int GetUserAccess(char * ini_file,char * user)
|
|
{
|
|
char useraccesskey[30];
|
|
wsprintf(useraccesskey, "#%s_access", user);
|
|
return GetPrivateProfileInt("Users",useraccesskey,AUTH_ANON,ini_file);
|
|
}
|