Files
winamp-mpris/Wawi Source/security.cpp
ergosteur 22492dbee9 Implement XDG compliance, logging, and improved 401 error handling
- 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
2026-04-08 18:29:40 -04:00

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);
}