/*
* ================================================== ===============
* Filename: vhosts.c
* Description: Vhosts manager module
* Author: AngryWolf <angrywolf@flashmail.com>
* Documentation: vhosts.txt (comes with the package)
* ================================================== ===============
*/
#include "config.h"
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "msg.h"
#include "channel.h"
#include <time.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <io.h>
#endif
#include <fcntl.h>
#include "h.h"
#ifdef STRIPBADWORDS
#include "badwords.h"
#endif
#ifdef _WIN32
#include "version.h"
#endif
typedef struct _conf_operflag OperFlag;
typedef struct _blocklist BlockList;
typedef struct _cmdinfo CmdInfo;
struct _conf_operflag
{
long flag;
char *name;
};
struct _blocklist
{
BlockList *prev, *next;
ConfigItem_vhost *vhost;
};
struct _cmdinfo
{
char *msg, *tok;
iFP func;
Command *cmd;
};
extern void sendto_one(aClient *to, char *pattern, ...);
extern void sendto_serv_butone_token(aClient *one, char *prefix, char *command, char *token, char *pattern, ...);
extern OperFlag *config_binary_flags_search(OperFlag *table, char *cmd, int size);
extern anAuthStruct AuthTypes[];
#define VHOST_DB "vhost.db"
#define VHOST_DB_VERSION 1001
#define IsParam(x) (parc > (x) && !BadPtr(parv[(x)]))
#define IsNotParam(x) (parc <= (x) || BadPtr(parv[(x)]))
#define ircfree(x) if (x) MyFree(x); x = NULL
#define ircstrdup(x,y) if (x) MyFree(x); if (!y) x = NULL; else x = strdup(y)
#define DelCommand(x) if (x) CommandDel(x); x = NULL
#define DelHook(x) if (x) HookDel(x); x = NULL
#define IsSkoAdmin(sptr) (IsAdmin(sptr) || IsNetAdmin(sptr) || IsSAdmin(sptr))
#define VF_VHOST 0x01
#define VF_USERHOST 0x02
#define VF_LOGIN 0x04
#define VF_PASSWORD 0x08
#define VF_SWHOIS 0x10
/* Helpful macros to make the code a bit more readable */
#define FromLoop(counter, list) \
for (counter = (ConfigItem_oper_from *) list; \
counter; counter = (ConfigItem_oper_from *) (counter)->next)
#define FromLoop2(counter, list, next) \
for (counter = (ConfigItem_oper_from *) list; \
counter; counter = (ConfigItem_oper_from *) next)
#define NewFrom \
(ConfigItem_oper_from *) MyMallocEx(sizeof(ConfigItem_oper_from))
static CMD_FUNC(m_addvhost);
static CMD_FUNC(m_addrvhost);
static CMD_FUNC(m_addgvhost);
static CMD_FUNC(m_delvhost);
static CMD_FUNC(m_delrvhost);
static CMD_FUNC(m_delgvhost);
static CMD_FUNC(m_modvhost);
static CMD_FUNC(m_modrvhost);
static CMD_FUNC(m_modgvhost);
static CMD_FUNC(m_confvhost);
static CMD_FUNC(m_confrvhost);
static Command *AddCommand(Module *module, char *msg, char *token, iFP func);
static int add_commands(Module *module);
static void del_commands();
#ifdef STATIC_LINKING
static int cb_config_rehash();
static int cb_rehash_complete();
#endif
static int save_vhosts();
static int load_vhosts();
static void free_extvhosts();
#ifdef STATIC_LINKING
Hook *HookConfRehash;
Hook *HookRehashDone;
#endif
BlockList *ExternalVhosts;
static char buf[1024];
static unsigned vhost_db_version = VHOST_DB_VERSION;
static CmdInfo VhostCommands[] =
{
{ "ADDVHOST", "VA", m_addvhost, NULL },
{ "ADDRVHOST", "VRA", m_addrvhost, NULL },
{ "ADDGVHOST", "VGA", m_addgvhost, NULL },
{ "DELVHOST", "VD", m_delvhost, NULL },
{ "DELRVHOST", "VRD", m_delrvhost, NULL },
{ "DELGVHOST", "VGD", m_delgvhost, NULL },
{ "MODVHOST", "VM", m_modvhost, NULL },
{ "MODRVHOST", "VRM", m_modrvhost, NULL },
{ "MODGVHOST", "VGM", m_modgvhost, NULL },
{ "CONFVHOST", "VC", m_confvhost, NULL },
{ "CONFRVHOST", "VRC", m_confrvhost, NULL },
{ NULL, NULL, NULL, NULL }
};
/* This MUST be alphabetized */
static OperFlag _VhostFields[] =
{
{ VF_LOGIN, "login" },
{ VF_PASSWORD, "password" },
{ VF_SWHOIS, "swhois" },
{ VF_USERHOST, "userhost" },
{ VF_VHOST, "vhost" },
};
ModuleHeader MOD_HEADER(vhosts)
= {
"vhosts",
"$Id: vhosts.c,v 2.4 2004/06/07 09:07:05 angrywolf Exp $",
"Vhosts manager",
"3.2-b8-1",
NULL
};
DLLFUNC int MOD_INIT(vhosts)(ModuleInfo *modinfo)
{
ExternalVhosts = NULL;
#ifdef STATIC_LINKING
HookConfRehash = HookAddEx(modinfo->handle, HOOKTYPE_REHASH, cb_config_rehash);
HookRehashDone = HookAddEx(modinfo->handle, HOOKTYPE_REHASH_COMPLETE, cb_rehash_complete);
#endif
return add_commands(modinfo->handle);
}
DLLFUNC int MOD_LOAD(vhosts)(int module_load)
{
load_vhosts();
return MOD_SUCCESS;
}
DLLFUNC int MOD_UNLOAD(vhosts)(int module_unload)
{
free_extvhosts();
del_commands();
#ifdef STATIC_LINKING
DelHook(HookRehashDone);
DelHook(HookConfRehash);
#endif
return MOD_SUCCESS;
}
#ifdef STATIC_LINKING
static int cb_config_rehash()
{
free_extvhosts();
return 0;
}
static int cb_rehash_complete()
{
load_vhosts();
return 0;
}
#endif
static Command *AddCommand(Module *module, char *msg, char *token, iFP func)
{
Command *cmd;
if (CommandExists(msg))
{
config_error("Command %s already exists", msg);
return NULL;
}
if (CommandExists(token))
{
config_error("Token %s already exists", token);
return NULL;
}
cmd = CommandAdd(module, msg, token, func, MAXPARA, 0);
#ifndef STATIC_LINKING
if (ModuleGetError(module) != MODERR_NOERROR || !cmd)
#else
if (!cmd)
#endif
{
#ifndef STATIC_LINKING
config_error("Error adding command %s: %s", msg,
ModuleGetErrorStr(module));
#else
config_error("Error adding command %s", msg);
#endif
return NULL;
}
return cmd;
}
static int add_commands(Module *module)
{
CmdInfo *p;
int ret = MOD_SUCCESS;
for (p = VhostCommands; p->msg; p++)
{
p->cmd = AddCommand(module, p->msg, p->tok, p->func);
if (!p->cmd)
ret = MOD_FAILED;
}
return ret;
}
static void del_commands()
{
CmdInfo *p;
for (p = VhostCommands; p->msg; p++)
{
DelCommand(p->cmd);
}
}
// ================================================== =======================
static void free_vhost(ConfigItem_vhost *vhost)
{
ListStruct *next;
ConfigItem_oper_from *from;
ircfree(vhost->login);
ircfree(vhost->virthost);
ircfree(vhost->virtuser);
ircfree(vhost->swhois);
Auth_DeleteAuthStruct(vhost->auth);
FromLoop2(from, vhost->from, next)
{
next = (ListStruct *) from->next;
DelListItem(from, vhost->from);
ircfree(from->name);
MyFree(from);
}
MyFree(vhost);
}
static void free_extvhosts()
{
BlockList *p;
ListStruct *next;
for (p = ExternalVhosts; p; p = (BlockList *) next)
{
next = (ListStruct *) p->next;
DelListItem(p, ExternalVhosts);
MyFree(p);
}
}
static BlockList *FindExternalVhost(ConfigItem_vhost *vhost)
{
BlockList *p;
for (p = ExternalVhosts; p; p = p->next)
if (p->vhost == vhost)
break;
return p;
}
static void AddExternalVhost(ConfigItem_vhost *vhost)
{
BlockList *p;
p = (BlockList *) MyMalloc(sizeof(BlockList));
p->vhost = vhost;
AddListItem(p, ExternalVhosts);
}
inline static void DelExternalVhost(BlockList *extvhost)
{
DelListItem(extvhost, ExternalVhosts);
MyFree(extvhost);
}
// ================================================== =======================
#define VF_TABLESIZE sizeof(_VhostFields)/sizeof(_VhostFields[0])
#ifndef _WIN32
#define OpenFile(fd, file, flags) fd = open(file, flags, S_IRUSR|S_IWUSR)
#else
#define OpenFile(fd, file, flags) fd = open(file, flags, S_IREAD|S_IWRITE)
#endif
#define R_SAFE(x) \
do { \
if ((x)) \
{ \
close(fd); \
if (vhost) \
free_vhost(vhost); \
config_error("Read error on %s", VHOST_DB); \
return -1; \
} \
} while (0)
#define RF_SAFE(x) \
do { \
if ((x)) \
{ \
close(fd); \
if (vhost) \
free_vhost(vhost); \
ircfree(from); \
config_error("Read error on %s", VHOST_DB); \
return -1; \
} \
} while (0)
#define W_SAFE(x) \
do { \
if ((x)) \
{ \
close(fd); \
config_error("Write error on %s", VHOST_DB); \
return -1; \
} \
} while (0)
static inline int read_data(int fd, void *buf, size_t count)
{
if ((size_t) read(fd, buf, count) < count)
return -1;
return 0;
}
static inline int write_data(int fd, void *buf, size_t count)
{
if ((size_t) write(fd, buf, count) < count)
return -1;
return 0;
}
static int write_str(int fd, char *x)
{
size_t count = x ? strlen(x) : 0;
if (write_data(fd, &count, sizeof count))
return -1;
if (count)
{
if (write_data(fd, x, sizeof(char) * count))
return -1;
}
return 0;
}
static int read_str(int fd, char **x)
{
size_t count;
if (read_data(fd, &count, sizeof count))
return -1;
if (!count)
{
*x = NULL;
return 0;
}
*x = (char *) MyMalloc(sizeof(char) * count + 1);
if (read_data(fd, *x, sizeof(char) * count))
{
MyFree(*x);
*x = NULL;
return -1;
}
(*x)[count] = 0;
return 0;
}
static int save_vhosts()
{
ConfigItem_vhost *vhost;
ConfigItem_oper_from *from;
int fd;
size_t count, fromcount;
OpenFile(fd, VHOST_DB, O_CREAT | O_WRONLY | O_TRUNC);
if (fd == -1)
{
config_status("error opening %s for writing: %s",
VHOST_DB, strerror(errno));
return -1;
}
W_SAFE(write_data(fd, &vhost_db_version, sizeof vhost_db_version));
count = 0;
for (vhost = conf_vhost; vhost; vhost = (ConfigItem_vhost *) vhost->next)
if (FindExternalVhost(vhost))
count++;
W_SAFE(write_data(fd, &count, sizeof count));
for (vhost = conf_vhost; vhost; vhost = (ConfigItem_vhost *) vhost->next)
{
if (!FindExternalVhost(vhost))
continue;
W_SAFE(write_str(fd, vhost->login));
W_SAFE(write_str(fd, vhost->virthost));
W_SAFE(write_str(fd, vhost->virtuser));
W_SAFE(write_str(fd, vhost->swhois));
W_SAFE(write_str(fd, vhost->auth->data));
W_SAFE(write_data(fd, &vhost->auth->type, sizeof vhost->auth->type));
fromcount = 0;
FromLoop(from, vhost->from)
fromcount++;
W_SAFE(write_data(fd, &fromcount, sizeof fromcount));
FromLoop(from, vhost->from)
W_SAFE(write_str(fd, from->name));
}
close(fd);
return 0;
}
static int load_vhosts()
{
ConfigItem_vhost *vhost = NULL;
ConfigItem_oper_from *from = NULL;
int fd;
size_t count, fromcount, i, j;
unsigned version;
OpenFile(fd, VHOST_DB, O_RDONLY);
if (fd == -1)
{
if (errno != ENOENT)
config_status("error opening %s for reading: %s",
VHOST_DB, strerror(errno));
return -1;
}
R_SAFE(read_data(fd, &version, sizeof version));
if (version != vhost_db_version)
{
config_status("File %s has a wrong database version (expected: %u, got: %u)",
VHOST_DB, vhost_db_version, version);
close(fd);
return -1;
}
R_SAFE(read_data(fd, &count, sizeof count));
for (i = 1; i <= count; i++)
{
from = NULL;
vhost = MyMallocEx(sizeof(ConfigItem_vhost));
vhost->auth = (anAuthStruct *) MyMallocEx(sizeof(anAuthStruct));
R_SAFE(read_str(fd, &vhost->login));
R_SAFE(read_str(fd, &vhost->virthost));
R_SAFE(read_str(fd, &vhost->virtuser));
R_SAFE(read_str(fd, &vhost->swhois));
R_SAFE(read_str(fd, &vhost->auth->data));
R_SAFE(read_data(fd, &vhost->auth->type, sizeof vhost->auth->type));
R_SAFE(read_data(fd, &fromcount, sizeof fromcount));
for (j = 1; j <= fromcount; j++)
{
from = NewFrom;
RF_SAFE(read_str(fd, &from->name));
AddListItem(from, vhost->from);
}
if (Find_vhost(vhost->login))
{
char *oldlogin = vhost->login;
config_status("Warning: can't add an external vhost block with login '%s', "
"an other one with the same login already exists; renaming the new one to '_%s'",
oldlogin, oldlogin);
vhost->login = (char *) MyMallocEx(strlen(oldlogin) + 2);
*vhost->login = '_';
strcat(vhost->login, oldlogin);
MyFree(oldlogin);
}
AddListItem(vhost, conf_vhost);
AddExternalVhost(vhost);
}
close(fd);
return 0;
}
// ================================================== =======================
/*
* Auth_CheckError2:
* makes sure password and authtype are valid
*/
static int Auth_CheckError2(aClient *sptr, char *password, short type)
{
#ifdef AUTHENABLE_SSL_CLIENTCERT
X509 *x509_filecert = NULL;
FILE *x509_f = NULL;
#endif
switch (type)
{
#ifdef AUTHENABLE_UNIXCRYPT
case AUTHTYPE_UNIXCRYPT:
/* If our data is like 1 or none, we just let em through .. */
if (strlen(password) < 2)
{
sendnotice(sptr, "*** AUTHTYPE_UNIXCRYPT: no salt (crypt strings will always be >2 in length)");
return 0;
}
break;
#endif
#ifdef AUTHENABLE_SSL_CLIENTCERT
case AUTHTYPE_SSL_CLIENTCERT:
if (!(x509_f = fopen(password, "r")))
{
sendnotice(sptr, "*** AUTHTYPE_SSL_CLIENTCERT: error opening file %s",
password);
return 0;
}
x509_filecert = PEM_read_X509(x509_f, NULL, NULL, NULL);
fclose(x509_f);
if (!x509_filecert)
{
sendnotice(sptr, "*** AUTHTYPE_SSL_CLIENTCERT: PEM_read_X509 errored in file %s (format error?)",
password);
return 0;
}
X509_free(x509_filecert);
break;
#endif
default: ;
}
return 1;
}
/*
* Auth_Convert2:
* converts password and authtype to anAuthStruct
*/
static anAuthStruct *Auth_Convert2(char *password, short type)
{
anAuthStruct *as;
as = (anAuthStruct *) MyMalloc(sizeof(anAuthStruct));
as->data = strdup(password);
as->type = type;
return as;
}
/*
* Auth_FindName:
* finds an authentication method name (used by /confvhost)
*/
static char *Auth_FindName(short type)
{
anAuthStruct *p;
for (p = AuthTypes; p->data; p++)
if (p->type == type)
break;
return p->data;
}
static anAuthStruct *Auth_DoAll(aClient *sptr, char *password, char *authtype)
{
short type;
char *encpass = NULL;
if ((type = Auth_FindType(authtype)) == -1)
{
sendnotice(sptr, "*** %s is not a supported authentication method",
authtype);
return NULL;
}
if (!Auth_CheckError2(sptr, password, type))
{
/* error message already sent */
return NULL;
}
if (type == AUTHTYPE_SSL_CLIENTCERT)
encpass = password;
else if (!(encpass = Auth_Make(type, password)))
{
sendnotice(sptr, "*** Authentication method %s failed", authtype);
return NULL;
}
return Auth_Convert2(encpass, type);
}
// ================================================== =======================
static u_int check_userhost(char **user, char **host, u_int needuser, u_int charscheck)
{
char *p;
*user = NULL;
if ((p = strchr(*host, '@')))
{
if (p == *host || !p[1])
return 0;
*p = 0;
*user = *host;
*host = p+1;
}
else if (needuser)
return 0;
if (charscheck)
{
if (*user)
{
if (**user != '~' && !isallowed(**user))
return 0;
for (p = *user + 1; *p; p++)
if (!isallowed(*p))
return 0;
}
if (!valid_host(*host))
return 0;
}
return 1;
}
/*
* is_valid_mask:
* checks whether a mask is in a correct user@host form
* returns NULL on error, otherwise a pointer to '@'.
*/
static char *is_valid_mask(char *mask)
{
char *p, *mid;
/* '@' */
if (!*mask || (!(mid = strchr(mask, '@'))))
return NULL;
if (mid == mask || !mid[1])
return NULL;
/* username */
if (*mask != '~' && *mask != '*' && *mask != '?' && !isallowed(*mask))
return NULL;
for (p = mask + 1; p < mid; p++)
if (*p != '*' && *p != '?' && !isallowed(*p))
return NULL;
/* hostname */
for (p = mid + 1; *p; p++)
if ((*p != '*') && (*p != '?') && (*p != '_') && (*p != '-')
&& (*p != '.') && (*p != ':') && !isalnum(*p))
return NULL;
return mid;
}
/*
* check_all_masks:
* Checks all user@host masks for validity in a string separated by
* spaces. Returns the first bad mask, or NULL if all masks are valid.
*/
static char *check_all_masks(char *userhosts)
{
char *m, *p = NULL;
char *str = strdup(userhosts);
for (m = strtoken(&p, str, " "); m; m = strtoken(&p, NULL, " "))
if (!is_valid_mask(m))
{
strcpy(buf, m);
ircfree(str);
return buf;
}
ircfree(str);
return NULL;
}
static void add_userhosts(ConfigItem_vhost *vhost, char *userhosts)
{
ConfigItem_oper_from *from;
char *str = strdup(userhosts);
char *tmp, *p = NULL;
for (tmp = strtoken(&p, str, " "); tmp; tmp = strtoken(&p, NULL, " "))
{
FromLoop(from, vhost->from)
if (!strcmp(from->name, tmp))
break;
if (from)
continue;
from = NewFrom;
from->name = strdup(tmp);
AddListItem(from, vhost->from);
}
ircfree(str);
}
static int check_target(aClient *cptr, aClient *sptr, char *command,
char *token, int global, int parc, char *parv[])
{
static char format[] = "%s %s %s %s %s %s %s %s";
int ret = 0;
/* parc > 1 */
format[(parc - 1) * 3 - 1] = 0;
if (global)
sendto_serv_butone_token(cptr, sptr->name, command, token,
format, parv[1], parv[2], parv[3], parv[4],
parv[5], parv[6], parv[7], parv[8]);
else
ret = hunt_server_token(cptr, sptr, command, token,
format, 1, parc, parv);
format[(parc - 1) * 3 - 1] = ' ';
return ret;
}
static unsigned has_privileges(aClient *sptr, int remote)
{
if (!IsPerson(sptr))
return 0;
if (!remote)
{
if (!IsSAdmin(sptr) && !IsNetAdmin(sptr))
return 0;
}
else
{
if (!IsSkoAdmin(sptr))
return 0;
}
return 1;
}
static char *make_vhost(char *user, char *host)
{
static char buf[BUFSIZE + 1];
if (user)
return make_user_host(user, host);
return strcpy(buf, host);
}
/*
** ADDVHOST/ADDGVHOST ADDRVHOST
** parv[0] = sender prefix sender prefix
** parv[1] = login server mask
** parv[2] = password login
** parv[3] = vhost (user@host) password
** parv[4] = userhosts vhost (user@host)
** parv[5] = userhosts
*/
static int add_vhost(aClient *sptr, char *login, char *password, char *host,
char *userhosts)
{
ConfigItem_vhost *vhost = NULL;
anAuthStruct *auth;
char *authtype, *user, *tmp;
if (Find_vhost(login))
{
sendnotice(sptr, "*** A vhost with login %s already exists", login);
return 0;
}
if (!check_userhost(&authtype, &password, 0, 0)) /* <== trick :) */
{
sendnotice(sptr, "*** Bad syntax for password");
return 0;
}
if (!check_userhost(&user, &host, 0, 1))
{
sendnotice(sptr, "*** Bad syntax for vhost or it has invalid characters");
return 0;
}
if (userhosts && (tmp = check_all_masks(userhosts)))
{
sendnotice(sptr, "*** Bad mask '%s'", tmp);
return 0;
}
if (!authtype)
authtype = "plain";
if (!(auth = Auth_DoAll(sptr, password, authtype)))
return 0;
vhost = MyMallocEx(sizeof(ConfigItem_vhost));
vhost->login = strdup(login);
vhost->virthost = strdup(host);
vhost->virtuser = user ? strdup(user) : NULL;
vhost->auth = auth;
add_userhosts(vhost, userhosts ? userhosts : "*@*");
AddListItem(vhost, conf_vhost);
AddExternalVhost(vhost);
save_vhosts();
tmp = make_vhost(user, host);
sendnotice(sptr, "*** Vhost %s added succesfully", tmp);
ircsprintf(buf, "*** [%s] Vhost %s added by %s (login: %s, userhosts: %s)",
me.name, tmp, sptr->name, login,
userhosts ? userhosts : "*@*");
sendto_snomask(SNO_EYES, "%s", buf);
sendto_serv_butone_token(NULL, me.name, MSG_SENDSNO, TOK_SENDSNO, "e :%s", buf);
return 0;
}
static CMD_FUNC(m_addvhost)
{
if (!has_privileges(sptr, 0))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return -1;
}
if (IsNotParam(3))
{
sendnotice(sptr, "*** Usage: /addvhost <login> [<auth-type>@]<password> [<user>@]<vhost> [:][<userhost masks>]");
sendnotice(sptr, "*** Examples: /addvhost newlogin newpass user@domain.com");
sendnotice(sptr, "*** /addvhost newlogin crypt@newpass new.domain.com :*@host1.* *@host2.*");
return 0;
}
add_vhost(sptr, parv[1], parv[2], parv[3],
IsParam(4) ? parv[4] : NULL);
return 0;
}
static CMD_FUNC(m_addrvhost)
{
if (!has_privileges(sptr, 1))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (IsNotParam(4))
{
sendnotice(sptr, "*** Usage: /addvhost <servermask> <login> [<auth-type>@]<password> [<user>@]<vhost> [:][<userhost masks>]");
sendnotice(sptr, "*** Examples: /addvhost irc.server.com newlogin newpass user@domain.com");
sendnotice(sptr, "*** /addvhost server2.* newlogin crypt@newpass new.domain.com :*@host1.* *@host2.*");
return 0;
}
if (check_target(cptr, sptr, "ADDRVHOST", "VRA", 0, parc,
parv) == HUNTED_ISME)
{
add_vhost(sptr, parv[2], parv[3], parv[4],
IsParam(5) ? parv[5] : NULL);
}
return 0;
}
static CMD_FUNC(m_addgvhost)
{
if (!has_privileges(sptr, 1))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (IsNotParam(3))
{
sendnotice(sptr, "*** Usage: /addgvhost <login> [<auth-type>@]<password> [<user>@]<vhost> [:][<userhost masks>]");
sendnotice(sptr, "*** Examples: /addgvhost newlogin newpass user@domain.com");
sendnotice(sptr, "*** /addgvhost newlogin crypt@newpass new.domain.com :*@host1.* *@host2.*");
return 0;
}
check_target(cptr, sptr, "ADDGVHOST", "VGA", 1, parc, parv);
add_vhost(sptr, parv[1], parv[2], parv[3],
IsParam(4) ? parv[4] : NULL);
return 0;
}
/*
** DELVHOST/DELGVHOST DELRVHOST
** parv[0] = sender prefix sender prefix
** parv[1] = login name server mask
** parv[2] = login name
*/
static int del_vhost(aClient *sptr, char *login)
{
ConfigItem_vhost *vhost;
BlockList *extvhost;
char *tmp;
if (!(vhost = Find_vhost(login)))
{
sendnotice(sptr, "*** Couldn't find a vhost with login name %s",
login);
return 0;
}
if (!(extvhost = FindExternalVhost(vhost)))
{
sendnotice(sptr, "*** No vhost is not present with login name %s in the external O:Line database",
login);
return 0;
}
tmp = make_vhost(vhost->virtuser, vhost->virthost);
DelListItem(vhost, conf_vhost);
DelExternalVhost(extvhost);
free_vhost(vhost);
save_vhosts();
sendnotice(sptr, "*** Vhost %s deleted succesfully", tmp);
ircsprintf(buf, "*** [%s] Vhost %s deleted by %s", me.name, tmp, sptr->name);
sendto_snomask(SNO_EYES, "%s", buf);
sendto_serv_butone_token(NULL, me.name, MSG_SENDSNO, TOK_SENDSNO, "e :%s", buf);
return 0;
}
static CMD_FUNC(m_delvhost)
{
if (!has_privileges(sptr, 0))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return -1;
}
if (IsNotParam(1))
{
sendnotice(sptr, "*** Usage: /delvhost <login>");
return 0;
}
del_vhost(sptr, parv[1]);
return 0;
}
static CMD_FUNC(m_delrvhost)
{
if (!has_privileges(sptr, 1))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return -1;
}
if (IsNotParam(2))
{
sendnotice(sptr, "*** Usage: /delrvhost <servermask> <login>");
return 0;
}
if (check_target(cptr, sptr, "DELRVHOST", "VRD", 0, parc,
parv) == HUNTED_ISME)
del_vhost(sptr, parv[2]);
return 0;
}
static CMD_FUNC(m_delgvhost)
{
if (!has_privileges(sptr, 1))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return -1;
}
if (IsNotParam(1))
{
sendnotice(sptr, "*** Usage: /delgvhost <login>");
return 0;
}
check_target(cptr, sptr, "DELGVHOST", "VGD", 1, parc, parv);
del_vhost(sptr, parv[1]);
return 0;
}
/*
** MODVHOST/MODGVHOST MODRVHOST
** parv[0] = sender prefix sender prefix
** parv[1] = login server mask
** parv[2] = option login
** parv[3] = value option
** parv[4] = encryption type value
** parv[5] = encryption type
*/
#define CHECKVALUE \
if (!value) \
{ \
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), \
me.name, sptr->name, cmd); \
return 0; \
}
static int mod_vhost(aClient *sptr, char *cmd, char *login, char *option,
char *value, char *enctype)
{
ConfigItem_vhost *vhost;
char *virthost;
OperFlag *vf;
if (!(vf = config_binary_flags_search(_VhostFields, option, VF_TABLESIZE)))
{
sendnotice(sptr, "*** Invalid option %s", option);
return 0;
}
if (!(vhost = Find_vhost(login)))
{
sendnotice(sptr, "*** Couldn't find a vhost with login name %s", login);
return 0;
}
if (!FindExternalVhost(vhost))
{
sendnotice(sptr, "*** No vhost is not present with login name %s in the external O:Line database",
login);
return 0;
}
virthost = make_vhost(vhost->virtuser, vhost->virthost);
switch (vf->flag)
{
/* login */
case VF_LOGIN:
{
CHECKVALUE
if (strchr(value, SPACE))
{
sendnotice(sptr, "*** Login names may not contain spaces");
return 0;
}
if (Find_vhost(value))
{
sendnotice(sptr, "*** A vhost with login name %s already exists",
value);
return 0;
}
ircfree(vhost->login);
vhost->login = strdup(value);
ircsprintf(buf, "%s changed the login name for vhost %s to %s",
sptr->name, virthost, value);
break;
}
/* swhois */
case VF_SWHOIS:
{
ircfree(vhost->swhois);
if (value)
{
vhost->swhois = strdup(value);
ircsprintf(buf, "%s changed the SWHOIS information of vhost %s to %s",
sptr->name, virthost, value);
}
else
ircsprintf(buf, "%s removed the SWHOIS information from vhost %s",
sptr->name, virthost);
break;
}
/* vhost */
case VF_VHOST:
{
char *user;
CHECKVALUE
if (strchr(value, SPACE))
{
sendnotice(sptr, "*** Vhosts may not contain spaces");
return 0;
}
if (!check_userhost(&user, &value, 0, 1))
{
sendnotice(sptr, "*** Bad syntax for vhost or it has invalid characters");
return 0;
}
ircfree(vhost->virtuser);
ircfree(vhost->virthost);
vhost->virtuser = user ? strdup(user) : NULL;
vhost->virthost = strdup(value);
ircsprintf(buf, "%s changed vhost %s to %s%s%s",
sptr->name, virthost,
user ? user : "", user ? "@" : "",
value);
break;
}
/* userhost */
case VF_USERHOST:
{
unsigned add = 1;
ConfigItem_oper_from *from;
CHECKVALUE
if (strchr(value, SPACE))
{
sendnotice(sptr, "*** Userhosts may not contain spaces");
return 0;
}
if (*value == '-')
{
add = 0;
value++;
}
else if (*value == '+')
value++;
if (!is_valid_mask(value))
{
sendnotice(sptr, "*** Bad mask '%s'", value);
return 0;
}
FromLoop(from, vhost->from)
if (!strcmp(from->name, value))
break;
if (add)
{
if (from)
{
sendnotice(sptr, "*** Mask %s already added",
value);
return 0;
}
from = NewFrom;
from->name = strdup(value);
AddListItem(from, vhost->from);
ircsprintf(buf, "%s added userhost '%s' for vhost %s",
sptr->name, value, virthost);
}
else /* del */
{
if (!from)
{
sendnotice(sptr, "*** Mask %s not found",
value);
return 0;
}
DelListItem(from, vhost->from);
ircfree(from->name);
MyFree(from);
/* add mask *@* if vhost->from is NULL */
if (!vhost->from)
{
from = NewFrom;
from->name = strdup("*@*");
AddListItem(from, vhost->from);
}
ircsprintf(buf, "%s removed userhost '%s' from vhost %s",
sptr->name, value, virthost);
}
break;
}
/* password */
case VF_PASSWORD:
{
anAuthStruct *auth;
char *authtype;
CHECKVALUE
if (enctype)
{
authtype = value;
value = enctype;
}
else
authtype = "plain";
if (strchr(value, SPACE))
{
sendnotice(sptr, "*** Passwords may not contain spaces");
return 0;
}
if (!(auth = Auth_DoAll(sptr, value, authtype)))
return 0;
Auth_DeleteAuthStruct(vhost->auth);
vhost->auth = auth;
ircsprintf(buf, "%s set a new password for vhost %s",
sptr->name, virthost);
break;
}
}
save_vhosts();
sendnotice(sptr, "*** Vhost %s modified succesfully", virthost);
sendto_snomask(SNO_EYES, "*** [%s] %s", me.name, buf);
sendto_serv_butone_token(NULL, me.name, MSG_SENDSNO, TOK_SENDSNO,
"e :*** [%s] %s", me.name, buf);
return 0;
}
static CMD_FUNC(m_modvhost)
{
if (!has_privileges(sptr, 0))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return -1;
}
if (IsNotParam(2))
{
sendnotice(sptr, "*** Usage: /modvhost <login> login|vhost <value>");
sendnotice(sptr, "*** /modvhost <login> swhois [:][<value>]");
sendnotice(sptr, "*** /modvhost <login> password [<auth method>] <password>");
sendnotice(sptr, "*** /modvhost <login> userhost +|-<mask>");
sendnotice(sptr, "*** Examples: /modvhost someone vhost someone@somewhere.com");
sendnotice(sptr, "*** /modvhost someone swhois :This is the new swhois info");
sendnotice(sptr, "*** /modvhost someone password crypt newpass");
return 0;
}
mod_vhost(sptr, "MODVHOST", parv[1], parv[2],
IsParam(3) ? parv[3] : NULL,
IsParam(4) ? parv[4] : NULL);
return 0;
}
static CMD_FUNC(m_modrvhost)
{
if (!has_privileges(sptr, 1))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (IsNotParam(3))
{
sendnotice(sptr, "*** Usage: /modvhost <servermask> <login> login|vhost <value>");
sendnotice(sptr, "*** /modvhost <servermask> <login> swhois [:][<value>]");
sendnotice(sptr, "*** /modvhost <servermask> <login> password [<auth method>] <password>");
sendnotice(sptr, "*** /modvhost <servermask> <login> userhost +|-<mask>");
sendnotice(sptr, "*** Examples: /modvhost server2.* someone vhost someone@somewhere.com");
sendnotice(sptr, "*** /modvhost irc.* someone swhois :This is the new swhois info");
sendnotice(sptr, "*** /modvhost server1.* someone password crypt newpass");
return 0;
}
if (check_target(cptr, sptr, "MODRVHOST", "VRM", 0, parc,
parv) == HUNTED_ISME)
{
mod_vhost(sptr, "MODRVHOST", parv[2], parv[3],
IsParam(4) ? parv[4] : NULL,
IsParam(5) ? parv[5] : NULL);
}
return 0;
}
static CMD_FUNC(m_modgvhost)
{
if (!has_privileges(sptr, 1))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (IsNotParam(2))
{
sendnotice(sptr, "*** Usage: /modvhost <login> login|vhost <value>");
sendnotice(sptr, "*** /modvhost <login> swhois [:][<value>]");
sendnotice(sptr, "*** /modvhost <login> password [<auth method>] <password>");
sendnotice(sptr, "*** /modvhost <login> userhost +|-<mask>");
sendnotice(sptr, "*** Examples: /modvhost someone vhost someone@somewhere.com");
sendnotice(sptr, "*** /modvhost someone swhois :This is the new swhois info");
sendnotice(sptr, "*** /modvhost someone password crypt newpass");
return 0;
}
check_target(cptr, sptr, "MODGVHOST", "VGM", 1, parc, parv);
mod_vhost(sptr, "MODGVHOST", parv[1], parv[2],
IsParam(3) ? parv[3] : NULL,
IsParam(4) ? parv[4] : NULL);
return 0;
}
/*
** CONFVHOST CONFRVHOST
** parv[0] = sender prefix sender prefix
** parv[1] = login name server mask
** parv[2] = login name
*/
#define MaxSize (sizeof(confstr) - strlen(confstr) - 1)
static int show_vhost(aClient *sptr, char *login)
{
static char confstr[BUFSIZE+1], tmp[BUFSIZE+1];
ConfigItem_vhost *vhost;
ConfigItem_oper_from *from;
char *authtype, *virthost;
if (!(vhost = Find_vhost(login)))
{
sendnotice(sptr, "*** Vhost %s does not exist", login);
return 0;
}
memset(&confstr, 0, sizeof confstr);
memset(&tmp, 0, sizeof tmp);
virthost = make_vhost(vhost->virtuser, vhost->virthost);
snprintf(confstr, sizeof confstr, "vhost { vhost %s; ",
virthost);
strncat(confstr, "from { ", MaxSize);
FromLoop(from, vhost->from)
{
snprintf(tmp, sizeof tmp, "userhost \"%s\"; ", from->name);
strncat(confstr, tmp, MaxSize);
}
strncat(confstr, "}; ", MaxSize);
snprintf(tmp, sizeof tmp, "login %s; password \"%s\" { %s; }; ",
vhost->login, vhost->auth->data,
(authtype = Auth_FindName(vhost->auth->type)) ?
authtype : "plain");
strncat(confstr, tmp, MaxSize);
if (vhost->swhois)
{
snprintf(tmp, sizeof tmp, "swhois \"%s\"; ", vhost->swhois);
strncat(confstr, tmp, MaxSize);
}
strncat(confstr, "};", MaxSize);
sendnotice(sptr, "*** %s", confstr);
return 0;
}
static CMD_FUNC(m_confvhost)
{
if (!has_privileges(sptr, 0))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return -1;
}
if (IsNotParam(1))
{
sendnotice(sptr, "*** Usage: /confvhost <login>");
return 0;
}
show_vhost(sptr, parv[1]);
return 0;
}
static CMD_FUNC(m_confrvhost)
{
if (!has_privileges(sptr, 1))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (IsNotParam(2))
{
sendnotice(sptr, "*** Usage: /confrvhost <servermask> <login>");
return 0;
}
if (check_target(cptr, sptr, "CONFRVHOST", "VRC", 0, parc,
parv) == HUNTED_ISME)
show_vhost(sptr, parv[2]);
return 0;
}