/*
* passlog.cpp - basic log formats implementation
* $Id: passlog.cpp,v 1.4 2004/06/05 15:15:17 rdenisc Exp $
*/
/***********************************************************************
* Copyright (C) 2002-2003 Remi Denis-Courmont. *
* This program is free software; you can redistribute and/or modify *
* it under the terms of the GNU General Public License as published *
* by the Free Software Foundation; version 2 of the license. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, you can get it from: *
* http://www.gnu.org/copyleft/gpl.html *
***********************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "passlog.h"
#include <ctype.h> // isspace()
#include <stdio.h> // sscanf()
#include <string.h> // strchr()
/*
* Returns a pointer to the first non 'white' (space or tab) char in a string.
* CRASHES if str si NULL.
*/
static const char *
eat_white (const char *str)
{
while (isspace (*str))
str++;
return str;
}
/*
* Performs a case-insensitive comparaison of the first word of two strings.
* Returns true if different, 0 if equal.
* CRASHES if any param is NULL.
*/
static int
wordcasecmp (const char *w1, const char *w2)
{
w1 = eat_white (w1);
w2 = eat_white (w2);
do
{
char c1 = *w1++, c2 = *w2++;
if (isspace (c1) || !c1)
return !(isspace (c2) || !c2);
if (tolower (c1) != tolower (c2))
return 1;
}
while (1);
return 1; // dead code
}
/*
* Performs base64 decoding.
*/
#define BASE64_SKIP -3
#define BASE64_EOF -2
#define BASE64_ERR -1
static char
base64_reduce (char c)
{
if ((c >= 'A') && (c <= 'Z'))
return c - 'A';
if ((c >= 'a') && (c <= 'z'))
return c - 'a' + 26;
if ((c >= '0') && (c <= '9'))
return c - '0' + 52;
switch (c)
{
case '+':
return 62;
case '/':
return 63;
case '=':
return BASE64_EOF;
case '\n':
case '\r':
case ' ':
return BASE64_SKIP;
}
return BASE64_ERR;
}
/*
* Decodes Base64-encoded source to target.
* Returns 0 on success, -1 on I/O error, -2 if source is not Base64-encoded.
*/
static int
unbase64 (unsigned char *dec, const unsigned char *enc, size_t maxlen)
{
for (size_t len = 0; len < maxlen; len += 3)
{
unsigned char in[4];
unsigned avail = 4;
for (int i = 0; (i < 4) && (avail == 4); i++)
{
// reads one byte
int buf = *enc;
if (buf == 0)
buf = BASE64_EOF; // end of encoded string
else
enc++;
// decodes a 6-bits value from an octet
buf = base64_reduce (buf);
switch (buf)
{
case BASE64_SKIP: /* skips CR/LF/SP */
break;
case BASE64_ERR: /* invalid base64 char */
return -1;
case BASE64_EOF: /* end of string */
avail = i;
break;
default:
in[i] = (unsigned char)buf;
}
}
if (maxlen <= (len + ((avail > 0) ? (avail - 1) : 0)))
return -1; // output buffer too short
switch (avail)
{
case 4:
dec[len + 2] = (in[2] << 6) | (in[3] >> 0);
case 3:
dec[len + 1] = (in[1] << 4) | (in[2] >> 2);
case 2:
dec[len] = (in[0] << 2) | (in[1] >> 4);
}
if (avail < 4)
return 0;
}
return 0;
}
/*** PasswordDataLog class implementation ***/
int PasswordDataLog::WriteServerLine (const char *, int length, int)
{
#if 0
if (!oob)
{
/*switch (proto_class)
{
case undefined:
case unknown:
case HTTP_like:
case POP_like:
case FTP_like:
}*/
}
#endif
return length;
}
/*
* There is of course still a clever way to escape password capture
* by sending an overly long quantity of spaces between PASS and your actual
* password, or by getting your password split into two parts by the
* line-bufferization engine.
*/
int PasswordDataLog::WriteClientLine (const char *data, int length, int oob)
{
if (!oob)
{
// FTP/SMTP/NNTP/POP1/POP3:
if (!wordcasecmp ("USER", data))
sscanf (data, "%*s %127s", username);
else
if (!wordcasecmp ("PASS", data))
{
if ((sscanf (data, "%*s %127s", password) == 1)
&& *username)
fprintf (out, "UNKNOWN: %s:%s\n", username,
password);
}
else
// POP2 (but not SMTP!!):
if (!wordcasecmp ("HELO", data))
{
if (sscanf (data, "%*s %127s %127s", username,
password) == 2)
fprintf (out, "UNKNOWN: %s:%s\n", username,
password);
}
else
// HTTP Basic authentication
if (!wordcasecmp ("Authorization:", data)
|| !wordcasecmp ("Proxy-Authorization:", data))
{
unsigned char buf_enc[345];
char buf_dec[256];
if (sscanf (data, "%*s Basic %511s\n", buf_enc) == 1)
{
unbase64 ((unsigned char*)buf_dec, buf_enc,
sizeof (buf_dec));
char *lim = strchr (buf_dec, ':');
if (lim != NULL)
{
*lim = 0;
lim++;
fprintf (out, "UNKNOWN: %s:%s\n",
buf_dec, lim);
}
}
}
}
return length;
}
DataLog *PasswordLogMaker (void)
{
return new PasswordDataLog;
}
syntax highlighted by Code2HTML, v. 0.9.1