mirror of
https://github.com/EnergyMech/energymech.git
synced 2025-12-17 15:36:50 +00:00
450 lines
7.9 KiB
C
450 lines
7.9 KiB
C
|
|
/*
|
||
|
|
|
||
|
|
EnergyMech, IRC bot software
|
||
|
|
Copyright (c) 2001-2004 proton
|
||
|
|
|
||
|
|
This program is free software; you can redistribute it and/or modify
|
||
|
|
it under the terms of the GNU General Public License as published by
|
||
|
|
the Free Software Foundation; either version 2 of the License, or
|
||
|
|
(at your option) any later version.
|
||
|
|
|
||
|
|
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, write to the Free Software
|
||
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
|
|
|
||
|
|
*/
|
||
|
|
#define AUTH_C
|
||
|
|
#include "config.h"
|
||
|
|
|
||
|
|
#include "defines.h"
|
||
|
|
#include "structs.h"
|
||
|
|
#include "global.h"
|
||
|
|
#include "h.h"
|
||
|
|
#include "text.h"
|
||
|
|
#include "mcmd.h"
|
||
|
|
|
||
|
|
#ifndef MD5CRYPT
|
||
|
|
|
||
|
|
/*
|
||
|
|
* simple password encryption
|
||
|
|
*/
|
||
|
|
|
||
|
|
char pctab[] =
|
||
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuwvxuz0123456789+-";
|
||
|
|
|
||
|
|
#define CIPHER(a1,a2,a3,a4,b1,b2,b3,b4) \
|
||
|
|
{ \
|
||
|
|
a2 = a2 ^ a1; \
|
||
|
|
b2 = b2 ^ b1; \
|
||
|
|
a3 = a2 ^ a1; \
|
||
|
|
b3 = b2 ^ b1; \
|
||
|
|
b3 >>= 2; \
|
||
|
|
b3 |= ((a3 & 3) << 30); \
|
||
|
|
a3 >>= 2; \
|
||
|
|
a2 = a3 ^ a2; \
|
||
|
|
b2 = b3 ^ b2; \
|
||
|
|
a4 = ~a4 ^ a2; \
|
||
|
|
b4 = -b4 ^ b2; \
|
||
|
|
a2 = a4 ^ ~a2; \
|
||
|
|
b2 = b4 ^ -b2; \
|
||
|
|
b1 >>= 1; \
|
||
|
|
b1 |= ((a1 & 1) << 31); \
|
||
|
|
a1 >>= 1; \
|
||
|
|
}
|
||
|
|
|
||
|
|
char *cipher(char *arg)
|
||
|
|
{
|
||
|
|
static char res[40];
|
||
|
|
ulong B1a,B2a,B3a,B4a;
|
||
|
|
ulong B1b,B2b,B3b,B4b;
|
||
|
|
uchar *ptr;
|
||
|
|
ulong R1;
|
||
|
|
int i;
|
||
|
|
|
||
|
|
if (!arg || !*arg)
|
||
|
|
return(NULL);
|
||
|
|
|
||
|
|
B1a = B2a = B3a = B4a = 0;
|
||
|
|
B1b = B2b = B3b = B4b = 0;
|
||
|
|
ptr = arg;
|
||
|
|
|
||
|
|
while(*ptr)
|
||
|
|
{
|
||
|
|
R1 = *ptr;
|
||
|
|
for(i=0;i<8;i++)
|
||
|
|
{
|
||
|
|
if (R1 & 1)
|
||
|
|
{
|
||
|
|
B1a |= 0x80008000;
|
||
|
|
B1b |= 0x80008000;
|
||
|
|
}
|
||
|
|
R1 >>= 1;
|
||
|
|
CIPHER(B1a,B2a,B3a,B4a,B1b,B2b,B3b,B4b);
|
||
|
|
}
|
||
|
|
ptr++;
|
||
|
|
}
|
||
|
|
while((B1a) || (B1b))
|
||
|
|
{
|
||
|
|
CIPHER(B1a,B2a,B3a,B4a,B1b,B2b,B3b,B4b);
|
||
|
|
}
|
||
|
|
|
||
|
|
for(i=0;i<10;i++)
|
||
|
|
{
|
||
|
|
res[i] = pctab[(B4b & 0x3f)];
|
||
|
|
B4b >>= 6;
|
||
|
|
B4b |= ((B4a & 0x3f) << 26);
|
||
|
|
B4a >>= 6;
|
||
|
|
}
|
||
|
|
res[i] = 0;
|
||
|
|
return(res);
|
||
|
|
}
|
||
|
|
|
||
|
|
char *makepass(char *plain)
|
||
|
|
{
|
||
|
|
return(cipher(plain));
|
||
|
|
}
|
||
|
|
|
||
|
|
int passmatch(char *plain, char *encoded)
|
||
|
|
{
|
||
|
|
return(!Strcmp(cipher(plain),encoded));
|
||
|
|
}
|
||
|
|
|
||
|
|
#else /* MD5CRYPT */
|
||
|
|
|
||
|
|
/*
|
||
|
|
* use MD5 to hash passwords
|
||
|
|
*/
|
||
|
|
|
||
|
|
char *CRYPT_FUNC(const char *, const char *);
|
||
|
|
|
||
|
|
char *makepass(char *plain)
|
||
|
|
{
|
||
|
|
char salt[8];
|
||
|
|
|
||
|
|
sprintf(salt,"$1$%04x",(rand() >> 16));
|
||
|
|
return(CRYPT_FUNC(plain,salt));
|
||
|
|
}
|
||
|
|
|
||
|
|
int passmatch(char *plain, char *encoded)
|
||
|
|
{
|
||
|
|
char *enc;
|
||
|
|
|
||
|
|
if (matches("$1$????$*",encoded))
|
||
|
|
return(FALSE);
|
||
|
|
enc = CRYPT_FUNC(plain,encoded);
|
||
|
|
return(!Strcmp(enc,encoded));
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif /* MD5CRYPT */
|
||
|
|
|
||
|
|
/*
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
void delete_auth(char *userhost)
|
||
|
|
{
|
||
|
|
Auth *auth,**pp;
|
||
|
|
|
||
|
|
pp = ¤t->authlist;
|
||
|
|
while(*pp)
|
||
|
|
{
|
||
|
|
if (!Strcasecmp(userhost,(*pp)->nuh))
|
||
|
|
{
|
||
|
|
auth = *pp;
|
||
|
|
*pp = auth->next;
|
||
|
|
Free((char**)&auth);
|
||
|
|
/*
|
||
|
|
* dont return yet, there might be more auths
|
||
|
|
*/
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
pp = &(*pp)->next;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void remove_auth(Auth *auth)
|
||
|
|
{
|
||
|
|
Auth **pp;
|
||
|
|
|
||
|
|
pp = ¤t->authlist;
|
||
|
|
while(*pp)
|
||
|
|
{
|
||
|
|
if (*pp == auth)
|
||
|
|
{
|
||
|
|
*pp = auth->next;
|
||
|
|
Free((char**)&auth);
|
||
|
|
/*
|
||
|
|
* when removing a DCC/telnet auth the connection should also be removed
|
||
|
|
*/
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
pp = &(*pp)->next;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
* register nick-changes in auths
|
||
|
|
*/
|
||
|
|
void change_authnick(char *nuh, char *newnuh)
|
||
|
|
{
|
||
|
|
Auth *auth,*oldauth,**pp;
|
||
|
|
char *n1,*n2;
|
||
|
|
|
||
|
|
pp = ¤t->authlist;
|
||
|
|
while(*pp)
|
||
|
|
{
|
||
|
|
auth = *pp;
|
||
|
|
if (!nickcmp(nuh,auth->nuh))
|
||
|
|
{
|
||
|
|
for(n1=nuh;*n1 != '!';n1++);
|
||
|
|
for(n2=newnuh;*n2 != '!';n2++);
|
||
|
|
if ((n1 - nuh) >= (n2 - newnuh))
|
||
|
|
{
|
||
|
|
#ifdef DEBUG
|
||
|
|
debug("(change_authnick) auth->nuh = `%s'; was `%s' (Strcpy) (L1 = %i, L2 = %i)\n",
|
||
|
|
newnuh,nuh,(int)(n1 - nuh),(int)(n2 - newnuh));
|
||
|
|
#endif /* DEBUG */
|
||
|
|
Strcpy(auth->nuh,newnuh);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
#ifdef DEBUG
|
||
|
|
debug("(change_authnick) auth->nuh = `%s'; was `%s' (re-alloc)\n",newnuh,nuh);
|
||
|
|
#endif /* DEBUG */
|
||
|
|
/*
|
||
|
|
* de-link the old auth record
|
||
|
|
*/
|
||
|
|
oldauth = auth;
|
||
|
|
*pp = auth->next;
|
||
|
|
|
||
|
|
set_mallocdoer(change_authnick);
|
||
|
|
auth = (Auth*)Calloc(sizeof(Auth) + strlen(newnuh));
|
||
|
|
auth->user = oldauth->user;
|
||
|
|
auth->active = now;
|
||
|
|
auth->next = current->authlist;
|
||
|
|
current->authlist = auth;
|
||
|
|
Strcpy(auth->nuh,newnuh);
|
||
|
|
Free((char**)&oldauth);
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
pp = &(*pp)->next;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
LS User *au_user;
|
||
|
|
LS char *au_userhost;
|
||
|
|
LS char *au_channel;
|
||
|
|
LS int au_access;
|
||
|
|
|
||
|
|
__attr(CORE_SEG, __regparm (1) )
|
||
|
|
void aucheck(User *user)
|
||
|
|
{
|
||
|
|
Strp *ump;
|
||
|
|
|
||
|
|
if (au_channel)
|
||
|
|
{
|
||
|
|
for(ump=user->chan;ump;ump=ump->next)
|
||
|
|
{
|
||
|
|
if (*ump->p == '*' || !Strcasecmp(au_channel,ump->p))
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
if (!ump)
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
for(ump=user->mask;ump;ump=ump->next)
|
||
|
|
{
|
||
|
|
if (!matches(ump->p,au_userhost))
|
||
|
|
{
|
||
|
|
if (au_access < user->x.x.access)
|
||
|
|
{
|
||
|
|
au_access = user->x.x.access;
|
||
|
|
au_user = user;
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
User *get_authuser(char *userhost, char *channel)
|
||
|
|
{
|
||
|
|
User *user;
|
||
|
|
Auth *auth;
|
||
|
|
|
||
|
|
au_user = NULL;
|
||
|
|
au_userhost = userhost;
|
||
|
|
au_channel = channel;
|
||
|
|
au_access = 0;
|
||
|
|
|
||
|
|
/*
|
||
|
|
* people who are authenticated
|
||
|
|
*/
|
||
|
|
for(auth=current->authlist;auth;auth=auth->next)
|
||
|
|
{
|
||
|
|
if (au_access < auth->user->x.x.access)
|
||
|
|
{
|
||
|
|
if (!Strcasecmp(userhost,auth->nuh))
|
||
|
|
{
|
||
|
|
aucheck(auth->user);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (current->setting[TOG_ENFPASS].int_var)
|
||
|
|
return(au_user);
|
||
|
|
/*
|
||
|
|
* people who dont need a password
|
||
|
|
*/
|
||
|
|
for(user=current->userlist;user;user=user->next)
|
||
|
|
{
|
||
|
|
if (!user->pass && (au_access < user->x.x.access))
|
||
|
|
{
|
||
|
|
aucheck(user);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return(au_user);
|
||
|
|
}
|
||
|
|
|
||
|
|
int get_authaccess(char *userhost, char *channel)
|
||
|
|
{
|
||
|
|
User *user;
|
||
|
|
Strp *ump;
|
||
|
|
|
||
|
|
if (userhost == CoreUser.name)
|
||
|
|
return(100);
|
||
|
|
if (CurrentDCC && CurrentDCC->user->name == userhost)
|
||
|
|
{
|
||
|
|
user = CurrentDCC->user;
|
||
|
|
if (!channel)
|
||
|
|
return(user->x.x.access);
|
||
|
|
for(ump=user->chan;ump;ump=ump->next)
|
||
|
|
{
|
||
|
|
if (*ump->p == '*' || !Strcasecmp(ump->p,channel))
|
||
|
|
return(user->x.x.access);
|
||
|
|
}
|
||
|
|
return(0);
|
||
|
|
}
|
||
|
|
if (is_bot(userhost))
|
||
|
|
return(BOTLEVEL);
|
||
|
|
|
||
|
|
get_authuser(userhost,channel);
|
||
|
|
return(au_access);
|
||
|
|
}
|
||
|
|
|
||
|
|
int make_auth(const char *userhost, const User *user)
|
||
|
|
{
|
||
|
|
Auth *auth;
|
||
|
|
Chan *chan;
|
||
|
|
ChanUser *cu;
|
||
|
|
|
||
|
|
for(auth=current->authlist;auth;auth=auth->next)
|
||
|
|
{
|
||
|
|
if ((auth->user == user) && !Strcasecmp(auth->nuh,userhost))
|
||
|
|
return(TRUE);
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef DEBUG
|
||
|
|
debug("(make_auth) %s = %s\n",userhost,user->name);
|
||
|
|
#endif /* DEBUG */
|
||
|
|
/*
|
||
|
|
* there is no matching auth for this user, we add one
|
||
|
|
*/
|
||
|
|
set_mallocdoer(make_auth);
|
||
|
|
auth = (Auth*)Calloc(sizeof(Auth) + strlen(userhost));
|
||
|
|
auth->user = (User*)user;
|
||
|
|
auth->active = now;
|
||
|
|
Strcpy(auth->nuh,userhost);
|
||
|
|
|
||
|
|
auth->next = current->authlist;
|
||
|
|
current->authlist = auth;
|
||
|
|
|
||
|
|
for(chan=current->chanlist;chan;chan=chan->next)
|
||
|
|
{
|
||
|
|
if (!chan->bot_is_op)
|
||
|
|
continue;
|
||
|
|
if (!chan->setting[TOG_AOP].int_var)
|
||
|
|
continue;
|
||
|
|
if ((cu = find_chanuser(chan,userhost)) == NULL)
|
||
|
|
continue;
|
||
|
|
if (cu->user && cu->user->x.x.aop)
|
||
|
|
{
|
||
|
|
send_mode(chan,120,QM_CHANUSER,'+','o',(void*)cu);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return(FALSE);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
*
|
||
|
|
* authentication commands
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Usage: VERIFY <password>
|
||
|
|
*/
|
||
|
|
void do_auth(COMMAND_ARGS)
|
||
|
|
{
|
||
|
|
#ifdef BOTNET
|
||
|
|
char *checksum;
|
||
|
|
#endif /* BOTNET */
|
||
|
|
Strp *ump;
|
||
|
|
User *user;
|
||
|
|
char *pass;
|
||
|
|
int hostmatch;
|
||
|
|
|
||
|
|
if ((pass = chop(&rest)) == NULL)
|
||
|
|
return;
|
||
|
|
|
||
|
|
/*
|
||
|
|
* chop chop
|
||
|
|
*/
|
||
|
|
if (strlen(pass) > MAXPASSCHARS)
|
||
|
|
pass[MAXPASSCHARS] = 0;
|
||
|
|
|
||
|
|
hostmatch = FALSE;
|
||
|
|
/*
|
||
|
|
* find a matching password
|
||
|
|
*/
|
||
|
|
for(user=current->userlist;user;user=user->next)
|
||
|
|
{
|
||
|
|
for(ump=user->mask;ump;ump=ump->next)
|
||
|
|
{
|
||
|
|
if (!matches(ump->p,from))
|
||
|
|
{
|
||
|
|
if (user->pass && passmatch(pass,user->pass))
|
||
|
|
goto listcheck;
|
||
|
|
hostmatch = TRUE;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
* if there was a matching host, they get a message...
|
||
|
|
*/
|
||
|
|
if (hostmatch)
|
||
|
|
to_user(from,TEXT_PASS_INCORRECT);
|
||
|
|
return;
|
||
|
|
|
||
|
|
listcheck:
|
||
|
|
#ifdef BOTNET
|
||
|
|
checksum = "";
|
||
|
|
if (user->pass)
|
||
|
|
{
|
||
|
|
sprintf(gsockdata,"%s %s %s",from,user->name,user->pass);
|
||
|
|
checksum = makepass(gsockdata);
|
||
|
|
}
|
||
|
|
botnet_relay(NULL,"PA%s %s %s\n",user->name,from,checksum);
|
||
|
|
#endif /* BOTNET */
|
||
|
|
if (make_auth(from,user))
|
||
|
|
{
|
||
|
|
to_user(from,"You have already been authorized");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
to_user(from,"You are now officially immortal");
|
||
|
|
}
|