commit
b9da417b4e
14 changed files with 129 additions and 55 deletions
|
@ -670,6 +670,13 @@ and most error messages are suppressed.
|
|||
Servers may not send '$$', '$#' and opers@server notices. Older servers may
|
||||
not allow servers to send to specific statuses on a channel.
|
||||
|
||||
OPER
|
||||
source: user
|
||||
parameters: opername, privset
|
||||
|
||||
Sets the source user's oper name and privset. Sent after the +o mode change, or
|
||||
during burst, to inform other servers of an oper's privileges.
|
||||
|
||||
OPERSPY
|
||||
encap only
|
||||
encap target: *
|
||||
|
@ -1222,7 +1229,6 @@ MODRESTART
|
|||
MODUNLOAD
|
||||
MONITOR
|
||||
NAMES
|
||||
OPER
|
||||
POST
|
||||
PUT
|
||||
RESTART
|
||||
|
|
|
@ -42,7 +42,7 @@ static int eb_oper(const char *data, struct Client *client_p,
|
|||
if (data != NULL)
|
||||
{
|
||||
struct PrivilegeSet *set = privilegeset_get(data);
|
||||
if (set != NULL && client_p->localClient->privset == set)
|
||||
if (set != NULL && client_p->user->privset == set)
|
||||
return EXTBAN_MATCH;
|
||||
|
||||
/* $o:admin or whatever */
|
||||
|
|
|
@ -79,6 +79,9 @@ struct User
|
|||
char *away; /* pointer to away message */
|
||||
int refcnt; /* Number of times this block is referenced */
|
||||
|
||||
char *opername; /* name of operator{} block being used or tried (challenge) */
|
||||
struct PrivilegeSet *privset;
|
||||
|
||||
char suser[NICKLEN+1];
|
||||
};
|
||||
|
||||
|
@ -225,7 +228,6 @@ struct LocalUser
|
|||
*/
|
||||
char *passwd;
|
||||
char *auth_user;
|
||||
char *opername; /* name of operator{} block being used or tried (challenge) */
|
||||
char *challenge;
|
||||
char *fullcaps;
|
||||
char *cipher_string;
|
||||
|
@ -282,8 +284,6 @@ struct LocalUser
|
|||
uint16_t cork_count; /* used for corking/uncorking connections */
|
||||
struct ev_entry *event; /* used for associated events */
|
||||
|
||||
struct PrivilegeSet *privset; /* privset... */
|
||||
|
||||
char sasl_agent[IDLEN];
|
||||
unsigned char sasl_out;
|
||||
unsigned char sasl_complete;
|
||||
|
|
|
@ -146,7 +146,7 @@ extern void cluster_generic(struct Client *, const char *, int cltype,
|
|||
#define IsOperConfEncrypted(x) ((x)->flags & OPER_ENCRYPTED)
|
||||
#define IsOperConfNeedSSL(x) ((x)->flags & OPER_NEEDSSL)
|
||||
|
||||
#define HasPrivilege(x, y) ((x)->localClient != NULL && (x)->localClient->privset != NULL && privilegeset_in_set((x)->localClient->privset, (y)))
|
||||
#define HasPrivilege(x, y) ((x)->user != NULL && (x)->user->privset != NULL && privilegeset_in_set((x)->user->privset, (y)))
|
||||
|
||||
#define IsOperGlobalKill(x) (HasPrivilege((x), "oper:global_kill"))
|
||||
#define IsOperLocalKill(x) (HasPrivilege((x), "oper:local_kill"))
|
||||
|
|
|
@ -300,10 +300,7 @@ free_local_client(struct Client *client_p)
|
|||
rb_free(client_p->localClient->auth_user);
|
||||
rb_free(client_p->localClient->challenge);
|
||||
rb_free(client_p->localClient->fullcaps);
|
||||
rb_free(client_p->localClient->opername);
|
||||
rb_free(client_p->localClient->mangledhost);
|
||||
if (client_p->localClient->privset)
|
||||
privilegeset_unref(client_p->localClient->privset);
|
||||
|
||||
if (IsSSL(client_p))
|
||||
ssld_decrement_clicount(client_p->localClient->ssl_ctl);
|
||||
|
@ -1920,6 +1917,9 @@ free_user(struct User *user, struct Client *client_p)
|
|||
{
|
||||
if(user->away)
|
||||
rb_free((char *) user->away);
|
||||
rb_free(user->opername);
|
||||
if (user->privset)
|
||||
privilegeset_unref(user->privset);
|
||||
/*
|
||||
* sanity check
|
||||
*/
|
||||
|
|
|
@ -1267,7 +1267,7 @@ get_oper_name(struct Client *client_p)
|
|||
{
|
||||
snprintf(buffer, sizeof(buffer), "%s!%s@%s{%s}",
|
||||
client_p->name, client_p->username,
|
||||
client_p->host, client_p->localClient->opername);
|
||||
client_p->host, client_p->user->opername);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
|
|
@ -669,6 +669,12 @@ burst_TS6(struct Client *client_p)
|
|||
use_id(target_p),
|
||||
target_p->user->away);
|
||||
|
||||
if(IsOper(target_p) && target_p->user && target_p->user->opername && target_p->user->privset)
|
||||
sendto_one(client_p, ":%s OPER %s %s",
|
||||
use_id(target_p),
|
||||
target_p->user->opername,
|
||||
target_p->user->privset->name);
|
||||
|
||||
hclientinfo.target = target_p;
|
||||
call_hook(h_burst_client, &hclientinfo);
|
||||
}
|
||||
|
|
|
@ -1121,12 +1121,19 @@ user_mode(struct Client *client_p, struct Client *source_p, int parc, const char
|
|||
}
|
||||
source_p->flags &= ~OPER_FLAGS;
|
||||
|
||||
rb_free(source_p->localClient->opername);
|
||||
source_p->localClient->opername = NULL;
|
||||
|
||||
rb_dlinkFindDestroy(source_p, &local_oper_list);
|
||||
privilegeset_unref(source_p->localClient->privset);
|
||||
source_p->localClient->privset = NULL;
|
||||
}
|
||||
|
||||
if(source_p->user->opername != NULL)
|
||||
{
|
||||
rb_free(source_p->user->opername);
|
||||
source_p->user->opername = NULL;
|
||||
}
|
||||
|
||||
if(source_p->user->privset != NULL)
|
||||
{
|
||||
privilegeset_unref(source_p->user->privset);
|
||||
source_p->user->privset = NULL;
|
||||
}
|
||||
|
||||
rb_dlinkFindDestroy(source_p, &oper_list);
|
||||
|
@ -1413,8 +1420,8 @@ oper_up(struct Client *source_p, struct oper_conf *oper_p)
|
|||
SetExemptKline(source_p);
|
||||
|
||||
source_p->flags |= oper_p->flags;
|
||||
source_p->localClient->opername = rb_strdup(oper_p->name);
|
||||
source_p->localClient->privset = privilegeset_ref(oper_p->privset);
|
||||
source_p->user->opername = rb_strdup(oper_p->name);
|
||||
source_p->user->privset = privilegeset_ref(oper_p->privset);
|
||||
|
||||
rb_dlinkAddAlloc(source_p, &local_oper_list);
|
||||
rb_dlinkAddAlloc(source_p, &oper_list);
|
||||
|
@ -1433,6 +1440,8 @@ oper_up(struct Client *source_p, struct oper_conf *oper_p)
|
|||
sendto_realops_snomask(SNO_GENERAL, L_ALL,
|
||||
"%s (%s!%s@%s) is now an operator", oper_p->name, source_p->name,
|
||||
source_p->username, source_p->host);
|
||||
sendto_server(NULL, NULL, CAP_TS6, NOCAPS, ":%s OPER %s %s",
|
||||
use_id(source_p), oper_p->name, oper_p->privset->name);
|
||||
if(!(old & UMODE_INVISIBLE) && IsInvisible(source_p))
|
||||
++Count.invisi;
|
||||
if((old & UMODE_INVISIBLE) && !IsInvisible(source_p))
|
||||
|
|
|
@ -93,9 +93,9 @@ cleanup_challenge(struct Client *target_p)
|
|||
return;
|
||||
|
||||
rb_free(target_p->localClient->challenge);
|
||||
rb_free(target_p->localClient->opername);
|
||||
rb_free(target_p->user->opername);
|
||||
target_p->localClient->challenge = NULL;
|
||||
target_p->localClient->opername = NULL;
|
||||
target_p->user->opername = NULL;
|
||||
target_p->localClient->chal_time = 0;
|
||||
}
|
||||
|
||||
|
@ -131,7 +131,7 @@ m_challenge(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *sou
|
|||
{
|
||||
sendto_one(source_p, form_str(ERR_PASSWDMISMATCH), me.name, source_p->name);
|
||||
ilog(L_FOPER, "EXPIRED CHALLENGE (%s) by (%s!%s@%s) (%s)",
|
||||
source_p->localClient->opername, source_p->name,
|
||||
source_p->user->opername, source_p->name,
|
||||
source_p->username, source_p->host, source_p->sockhost);
|
||||
|
||||
if(ConfigFileEntry.failed_oper_notice)
|
||||
|
@ -151,7 +151,7 @@ m_challenge(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *sou
|
|||
{
|
||||
sendto_one(source_p, form_str(ERR_PASSWDMISMATCH), me.name, source_p->name);
|
||||
ilog(L_FOPER, "FAILED CHALLENGE (%s) by (%s!%s@%s) (%s)",
|
||||
source_p->localClient->opername, source_p->name,
|
||||
source_p->user->opername, source_p->name,
|
||||
source_p->username, source_p->host, source_p->sockhost);
|
||||
|
||||
if(ConfigFileEntry.failed_oper_notice)
|
||||
|
@ -169,13 +169,13 @@ m_challenge(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *sou
|
|||
|
||||
oper_p = find_oper_conf(source_p->username, source_p->orighost,
|
||||
source_p->sockhost,
|
||||
source_p->localClient->opername);
|
||||
source_p->user->opername);
|
||||
|
||||
if(oper_p == NULL)
|
||||
{
|
||||
sendto_one_numeric(source_p, ERR_NOOPERHOST, form_str(ERR_NOOPERHOST));
|
||||
ilog(L_FOPER, "FAILED OPER (%s) by (%s!%s@%s) (%s)",
|
||||
source_p->localClient->opername, source_p->name,
|
||||
source_p->user->opername, source_p->name,
|
||||
source_p->username, source_p->host,
|
||||
source_p->sockhost);
|
||||
|
||||
|
@ -192,7 +192,7 @@ m_challenge(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *sou
|
|||
oper_up(source_p, oper_p);
|
||||
|
||||
ilog(L_OPERED, "OPER %s by %s!%s@%s (%s)",
|
||||
source_p->localClient->opername, source_p->name,
|
||||
source_p->user->opername, source_p->name,
|
||||
source_p->username, source_p->host, source_p->sockhost);
|
||||
return;
|
||||
}
|
||||
|
@ -274,7 +274,7 @@ m_challenge(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *sou
|
|||
sendto_one(source_p, form_str(RPL_ENDOFRSACHALLENGE2),
|
||||
me.name, source_p->name);
|
||||
rb_free(challenge);
|
||||
source_p->localClient->opername = rb_strdup(oper_p->name);
|
||||
source_p->user->opername = rb_strdup(oper_p->name);
|
||||
}
|
||||
else
|
||||
sendto_one_notice(source_p, ":Failed to generate challenge.");
|
||||
|
|
|
@ -61,7 +61,7 @@ void set_privset(struct Client *const source,
|
|||
return;
|
||||
}
|
||||
|
||||
if(IsOper(target) && target->localClient->privset == privset)
|
||||
if(IsOper(target) && target->user->privset == privset)
|
||||
{
|
||||
sendto_one_notice(source, ":%s already has role of %s.", target->name, privset_name);
|
||||
return;
|
||||
|
@ -71,7 +71,7 @@ void set_privset(struct Client *const source,
|
|||
{
|
||||
sendto_one_notice(target, ":%s has changed your role to %s.", source->name, privset_name);
|
||||
sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "%s has changed %s's role to %s.", get_oper_name(source), target->name, privset_name);
|
||||
target->localClient->privset = privset;
|
||||
target->user->privset = privset;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "s_newconf.h"
|
||||
#include "logger.h"
|
||||
#include "s_user.h"
|
||||
#include "s_serv.h"
|
||||
#include "send.h"
|
||||
#include "msg.h"
|
||||
#include "parse.h"
|
||||
|
@ -41,12 +42,13 @@
|
|||
static const char oper_desc[] = "Provides the OPER command to become an IRC operator";
|
||||
|
||||
static void m_oper(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
|
||||
static void mc_oper(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
|
||||
|
||||
static bool match_oper_password(const char *password, struct oper_conf *oper_p);
|
||||
|
||||
struct Message oper_msgtab = {
|
||||
"OPER", 0, 0, 0, 0,
|
||||
{mg_unreg, {m_oper, 3}, mg_ignore, mg_ignore, mg_ignore, {m_oper, 3}}
|
||||
{mg_unreg, {m_oper, 3}, {mc_oper, 3}, mg_ignore, mg_ignore, {m_oper, 3}}
|
||||
};
|
||||
|
||||
mapi_clist_av1 oper_clist[] = { &oper_msgtab, NULL };
|
||||
|
@ -161,6 +163,35 @@ m_oper(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* mc_oper - server-to-server OPER propagation
|
||||
* parv[1] = opername
|
||||
* parv[2] = privset
|
||||
*/
|
||||
static void
|
||||
mc_oper(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
|
||||
{
|
||||
struct PrivilegeSet *privset;
|
||||
sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s OPER %s %s", use_id(source_p), parv[1], parv[2]);
|
||||
|
||||
privset = privilegeset_get(parv[2]);
|
||||
if(privset == NULL)
|
||||
{
|
||||
/* if we don't have a matching privset, we'll create an empty one and
|
||||
* mark it illegal, so it gets picked up on a rehash later */
|
||||
sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Received OPER for %s with unknown privset %s", source_p->name, parv[2]);
|
||||
privset = privilegeset_set_new(parv[2], "", 0);
|
||||
privset->status |= CONF_ILLEGAL;
|
||||
}
|
||||
|
||||
privset = privilegeset_ref(privset);
|
||||
if (source_p->user->privset != NULL)
|
||||
privilegeset_unref(source_p->user->privset);
|
||||
|
||||
source_p->user->privset = privset;
|
||||
source_p->user->opername = rb_strdup(parv[1]);
|
||||
}
|
||||
|
||||
/*
|
||||
* match_oper_password
|
||||
*
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "modules.h"
|
||||
#include "s_conf.h"
|
||||
#include "s_newconf.h"
|
||||
#include "hash.h"
|
||||
|
||||
static const char privs_desc[] = "Provides the PRIVS command to inspect an operator's privileges";
|
||||
|
||||
|
@ -86,21 +87,24 @@ static void show_privs(struct Client *source_p, struct Client *target_p)
|
|||
struct mode_table *p;
|
||||
|
||||
buf[0] = '\0';
|
||||
if (target_p->localClient->privset)
|
||||
rb_strlcat(buf, target_p->localClient->privset->privs, sizeof buf);
|
||||
if (target_p->user->privset)
|
||||
rb_strlcat(buf, target_p->user->privset->privs, sizeof buf);
|
||||
if (IsOper(target_p))
|
||||
{
|
||||
if (buf[0] != '\0')
|
||||
rb_strlcat(buf, " ", sizeof buf);
|
||||
rb_strlcat(buf, "operator:", sizeof buf);
|
||||
rb_strlcat(buf, target_p->localClient->opername, sizeof buf);
|
||||
if (target_p->user->opername)
|
||||
{
|
||||
if (buf[0] != '\0')
|
||||
rb_strlcat(buf, " ", sizeof buf);
|
||||
rb_strlcat(buf, "operator:", sizeof buf);
|
||||
rb_strlcat(buf, target_p->user->opername, sizeof buf);
|
||||
}
|
||||
|
||||
if (target_p->localClient->privset)
|
||||
if (target_p->user->privset)
|
||||
{
|
||||
if (buf[0] != '\0')
|
||||
rb_strlcat(buf, " ", sizeof buf);
|
||||
rb_strlcat(buf, "privset:", sizeof buf);
|
||||
rb_strlcat(buf, target_p->localClient->privset->name, sizeof buf);
|
||||
rb_strlcat(buf, target_p->user->privset->name, sizeof buf);
|
||||
}
|
||||
}
|
||||
p = &auth_client_table[0];
|
||||
|
@ -126,8 +130,9 @@ me_privs(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
|
|||
if (!IsOper(source_p) || parc < 2 || EmptyString(parv[1]))
|
||||
return;
|
||||
|
||||
/* we cannot show privs for remote clients */
|
||||
if((target_p = find_person(parv[1])) && MyClient(target_p))
|
||||
target_p = find_person(parv[1]);
|
||||
|
||||
if (target_p != NULL)
|
||||
show_privs(source_p, target_p);
|
||||
}
|
||||
|
||||
|
@ -135,13 +140,24 @@ static void
|
|||
mo_privs(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
|
||||
{
|
||||
struct Client *target_p;
|
||||
struct Client *server_p;
|
||||
|
||||
if (parc < 2 || EmptyString(parv[1]))
|
||||
target_p = source_p;
|
||||
{
|
||||
server_p = target_p = source_p;
|
||||
}
|
||||
else
|
||||
{
|
||||
target_p = find_named_person(parv[1]);
|
||||
if (target_p == NULL)
|
||||
if (parc >= 3)
|
||||
{
|
||||
server_p = find_named_client(parv[1]);
|
||||
target_p = find_named_person(parv[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
server_p = target_p = find_named_person(parv[1]);
|
||||
}
|
||||
if (server_p == NULL || target_p == NULL)
|
||||
{
|
||||
sendto_one_numeric(source_p, ERR_NOSUCHNICK,
|
||||
form_str(ERR_NOSUCHNICK), parv[1]);
|
||||
|
@ -149,12 +165,15 @@ mo_privs(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
|
|||
}
|
||||
}
|
||||
|
||||
if (MyClient(target_p))
|
||||
if (!IsServer(server_p))
|
||||
server_p = server_p->servptr;
|
||||
|
||||
if (IsMe(server_p))
|
||||
show_privs(source_p, target_p);
|
||||
else
|
||||
sendto_one(target_p, ":%s ENCAP %s PRIVS %s",
|
||||
get_id(source_p, target_p),
|
||||
target_p->servptr->name,
|
||||
sendto_one(server_p, ":%s ENCAP %s PRIVS %s",
|
||||
get_id(source_p, server_p),
|
||||
server_p->name,
|
||||
use_id(target_p));
|
||||
}
|
||||
|
||||
|
|
|
@ -318,11 +318,14 @@ single_whois(struct Client *source_p, struct Client *target_p, int operspy)
|
|||
GlobalSetOptions.operstring));
|
||||
}
|
||||
|
||||
if(MyClient(target_p) && !EmptyString(target_p->localClient->opername) && IsOper(target_p) && IsOper(source_p))
|
||||
if(!EmptyString(target_p->user->opername) && IsOper(target_p) && IsOper(source_p))
|
||||
{
|
||||
char buf[512];
|
||||
const char *privset = "(missing)";
|
||||
if (target_p->user->privset != NULL)
|
||||
privset = target_p->user->privset->name;
|
||||
snprintf(buf, sizeof(buf), "is opered as %s, privset %s",
|
||||
target_p->localClient->opername, target_p->localClient->privset->name);
|
||||
target_p->user->opername, privset);
|
||||
sendto_one_numeric(source_p, RPL_WHOISSPECIAL, form_str(RPL_WHOISSPECIAL),
|
||||
target_p->name, buf);
|
||||
}
|
||||
|
|
|
@ -3898,8 +3898,8 @@ static void sendto_realops_snomask1(void)
|
|||
oper3->snomask = SNO_BOTS | SNO_SKILL;
|
||||
oper4->snomask = SNO_GENERAL | SNO_REJ;
|
||||
|
||||
oper3->localClient->privset = privilegeset_get("admin");
|
||||
oper4->localClient->privset = privilegeset_get("admin");
|
||||
oper3->user->privset = privilegeset_get("admin");
|
||||
oper4->user->privset = privilegeset_get("admin");
|
||||
|
||||
server->localClient->caps = CAP_ENCAP | CAP_TS6;
|
||||
server2->localClient->caps = 0;
|
||||
|
@ -4125,8 +4125,8 @@ static void sendto_realops_snomask1__tags(void)
|
|||
oper3->snomask = SNO_BOTS | SNO_SKILL;
|
||||
oper4->snomask = SNO_GENERAL | SNO_REJ;
|
||||
|
||||
oper3->localClient->privset = privilegeset_get("admin");
|
||||
oper4->localClient->privset = privilegeset_get("admin");
|
||||
oper3->user->privset = privilegeset_get("admin");
|
||||
oper4->user->privset = privilegeset_get("admin");
|
||||
|
||||
server->localClient->caps = CAP_ENCAP | CAP_TS6;
|
||||
server2->localClient->caps = 0;
|
||||
|
@ -4340,8 +4340,8 @@ static void sendto_realops_snomask_from1(void)
|
|||
oper3->snomask = SNO_BOTS | SNO_SKILL;
|
||||
oper4->snomask = SNO_GENERAL | SNO_REJ;
|
||||
|
||||
oper3->localClient->privset = privilegeset_get("admin");
|
||||
oper4->localClient->privset = privilegeset_get("admin");
|
||||
oper3->user->privset = privilegeset_get("admin");
|
||||
oper4->user->privset = privilegeset_get("admin");
|
||||
|
||||
sendto_realops_snomask_from(SNO_BOTS, L_ALL, &me, "Hello %s!", "World");
|
||||
is_client_sendq(":" TEST_ME_NAME " NOTICE * :*** Notice -- Hello World!" CRLF, oper1, "Matches mask; " MSG);
|
||||
|
@ -4460,8 +4460,8 @@ static void sendto_realops_snomask_from1__tags(void)
|
|||
oper3->snomask = SNO_BOTS | SNO_SKILL;
|
||||
oper4->snomask = SNO_GENERAL | SNO_REJ;
|
||||
|
||||
oper3->localClient->privset = privilegeset_get("admin");
|
||||
oper4->localClient->privset = privilegeset_get("admin");
|
||||
oper3->user->privset = privilegeset_get("admin");
|
||||
oper4->user->privset = privilegeset_get("admin");
|
||||
|
||||
sendto_realops_snomask_from(SNO_BOTS, L_ALL, &me, "Hello %s!", "World");
|
||||
is_client_sendq("@time=" ADVENTURE_TIME " :" TEST_ME_NAME " NOTICE * :*** Notice -- Hello World!" CRLF, oper1, "Matches mask; " MSG);
|
||||
|
|
Loading…
Reference in a new issue