Import from http://svn.freenode.net/ircd-seven/private/beu/seven (r196).
[seven-1.x.git] / modules / m_grant.c
blobd884b4f862a178bef6618b12db66636995a5f3a8
1 /*
2 * Copyright (C) 2006 Jilles Tjoelker
3 * Copyright (C) 2006 Stephen Bennett <spb@gentoo.org>
5 * $Id$
6 */
8 #include "stdinc.h"
9 #include "modules.h"
10 #include "client.h"
11 #include "ircd.h"
12 #include "send.h"
13 #include "s_user.h"
14 #include "s_serv.h"
15 #include "s_conf.h"
16 #include "s_newconf.h"
18 static int mo_grant(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
19 static int me_grant(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
21 static int do_grant(struct Client *source_p, struct Client *target_p, int addflags, int removeflags, int dooper,
22 int dodeoper, int add_snomask, int remove_snomask);
24 struct Message grant_msgtab = {
25 "GRANT", 0, 0, 0, MFLG_SLOW,
26 { mg_ignore, mg_not_oper, mg_ignore, mg_ignore, {me_grant, 5}, {mo_grant, 3}}
29 mapi_clist_av1 grant_clist[] = { &grant_msgtab, NULL };
31 DECLARE_MODULE_AV1(grant, NULL, NULL, grant_clist, NULL, NULL, "$Revision$");
33 /* copied from src/newconf.c */
34 struct mode_table
36 const char *name;
37 int mode;
40 extern struct mode_table flag_table[];
42 static int
43 mo_grant(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
45 struct Client *target_p;
46 int addflags = 0, removeflags = 0;
47 int dooper = 0, dodeoper = 0;
48 int i, j;
49 int dir;
50 const char *p;
51 char *q;
52 int add_snomask = 0, remove_snomask = 0;
53 char oper_flag_changes[32], snomask_changes[64];
55 if(!IsOperGrant(source_p))
57 sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "grant");
58 return 0;
61 target_p = find_named_person(parv[1]);
62 if (target_p == NULL)
64 sendto_one_numeric(source_p, ERR_NOSUCHNICK,
65 form_str(ERR_NOSUCHNICK), parv[1]);
66 return 0;
69 for (i = 2; i < parc; i++)
71 p = parv[i];
72 if (*p == '-')
73 dir = MODE_DEL, p++;
74 else if (*p == '+')
75 dir = MODE_ADD, p++;
76 else
77 dir = MODE_ADD;
78 if (!irccmp(p, "oper"))
80 if (dir == MODE_ADD)
81 dooper = 1, dodeoper = 0;
82 else
83 dodeoper = 1, dooper = 0;
84 continue;
86 if (!irccmp(p, "snomask"))
88 add_snomask = parse_snobuf_to_mask(0, parv[++i]);
89 remove_snomask = ~parse_snobuf_to_mask(~0, parv[i]);
90 continue;
93 for (j = 0; flag_table[j].name != NULL; j++)
95 if (!irccmp(p, flag_table[j].name))
97 if (dir == MODE_ADD)
98 addflags |= flag_table[j].mode, removeflags &= ~flag_table[j].mode;
99 else
100 removeflags |= flag_table[j].mode, addflags &= ~flag_table[j].mode;
101 break;
104 if (flag_table[j].name == NULL)
106 sendto_one_notice(source_p, ":Unknown GRANT keyword '%s'", p);
107 return 0;
110 if (((addflags | removeflags) & source_p->operflags) != (addflags | removeflags))
112 sendto_one_notice(source_p, ":You may not change flags you do not have access to");
113 return 0;
116 if (MyClient(target_p))
118 do_grant(source_p, target_p, addflags, removeflags, dooper, dodeoper,
119 add_snomask, remove_snomask);
121 else
123 q = oper_flag_changes;
125 for (i = 0; oper_flagtable[i].flag; ++i)
127 if (addflags & oper_flagtable[i].flag)
128 *q++ = oper_flagtable[i].has;
129 else if (removeflags & oper_flagtable[i].flag)
130 *q++ = oper_flagtable[i].hasnt;
132 if(q == oper_flag_changes)
133 *q++ = '.';
134 *q++ = '\0';
136 strlcpy(snomask_changes, construct_snobuf_changes(add_snomask, remove_snomask), sizeof(snomask_changes));
138 sendto_one(target_p, ":%s ENCAP %s GRANT %s %s %d %d %s",
139 get_id(source_p, target_p), target_p->servptr->name,
140 get_id(target_p, target_p), oper_flag_changes, dooper, dodeoper,
141 snomask_changes);
144 return 0;
147 static int me_grant(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
149 struct Client *target_p;
150 int addflags = 0, removeflags = 0, dooper = 0, dodeoper = 0, add_snomask = 0, remove_snomask = 0;
151 int i = 0;
152 const char *p;
154 target_p = find_person(parv[1]);
155 if (target_p == NULL)
157 sendto_one_numeric(source_p, ERR_NOSUCHNICK,
158 form_str(ERR_NOSUCHNICK), parv[1]);
159 return 0;
162 if(!find_shared_conf(source_p->username, source_p->host,
163 source_p->user->server, SHARED_GRANT))
165 sendto_one(source_p, ":%s NOTICE %s :*** You don't have an appropriate shared"
166 "block to grant privilege on this server.", me.name, source_p->name);
167 return 0;
170 p = parv[2];
172 for (i = 0; oper_flagtable[i].flag; ++i)
174 if (*p == oper_flagtable[i].has)
175 addflags |= oper_flagtable[i].flag;
176 else if (*p == oper_flagtable[i].hasnt)
177 removeflags |= oper_flagtable[i].flag;
178 else if (*p == '\0' || *p == '.')
179 break;
180 else
181 continue;
182 ++p;
185 dooper = atoi(parv[3]);
186 dodeoper = atoi(parv[4]);
188 add_snomask = parse_snobuf_to_mask(0, parv[5]);
189 remove_snomask = ~parse_snobuf_to_mask(~0, parv[5]);
191 do_grant(source_p, target_p, addflags, removeflags, dooper, dodeoper, add_snomask, remove_snomask);
193 return 0;
197 static int do_grant(struct Client *source_p, struct Client *target_p, int addflags, int removeflags, int dooper,
198 int dodeoper, int add_snomask, int remove_snomask)
200 const char *newparv[4];
201 struct oper_conf oper;
202 int changes = 0;
203 int orig_snomask = target_p->allowed_snomask;
204 char desc[512];
205 int j;
207 if (dodeoper)
209 if (!IsOper(target_p))
210 sendto_one_notice(source_p, ":%s is not an oper",
211 target_p->name);
212 else
214 newparv[0] = target_p->name;
215 newparv[1] = target_p->name;
216 newparv[2] = "-o";
217 newparv[3] = NULL;
218 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
219 "%s is deopering %s",
220 get_oper_name(source_p),
221 get_client_name(target_p, HIDE_IP));
222 sendto_one_notice(target_p, ":%s is deopering you",
223 source_p->name);
224 user_mode(target_p, target_p, 3, newparv);
225 sendto_one_notice(source_p, ":Deopered %s",
226 target_p->name);
227 changes++;
230 else if (dooper)
232 if (IsOper(target_p))
233 sendto_one_notice(source_p, ":%s is already an oper",
234 target_p->name);
235 else
237 desc[0] = '\0';
238 for (j = 0; flag_table[j].name != NULL; j++)
240 if ((addflags & flag_table[j].mode) == flag_table[j].mode)
242 if (desc[0] != '\0')
243 strlcat(desc, " ", sizeof desc);
244 strlcat(desc, "+", sizeof desc);
245 strlcat(desc, flag_table[j].name, sizeof desc);
248 if (desc[0] == '\0')
249 strlcpy(desc, "<none>", sizeof desc);
250 oper.name = "<grant>";
251 oper.username = "";
252 oper.host = "";
253 oper.passwd = "";
254 oper.flags = addflags;
255 oper.umodes = 0;
256 oper.snomask = 0;
257 oper.allowed_snomask = add_snomask;
258 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
259 "%s is opering %s with flags %s and snomask %s",
260 get_oper_name(source_p),
261 get_client_name(target_p, HIDE_IP),
262 desc,
263 construct_snobuf(oper.allowed_snomask));
264 sendto_one_notice(target_p, ":%s is opering you",
265 source_p->name);
266 oper_up(target_p, &oper);
267 sendto_one_notice(source_p, ":Opered %s with flags %s and snomask %s",
268 target_p->name, desc, construct_snobuf(oper.allowed_snomask));
269 changes++;
272 removeflags &= target_p->operflags;
273 addflags &= ~target_p->operflags;
274 remove_snomask &= target_p->allowed_snomask;
275 add_snomask &= ~target_p->allowed_snomask;
276 if ((addflags | removeflags | add_snomask | remove_snomask) != 0)
278 if (!IsOper(target_p))
280 sendto_one_notice(source_p, ":%s is not an oper",
281 target_p->name);
283 else
285 target_p->operflags |= addflags;
286 target_p->operflags &= ~removeflags;
287 target_p->allowed_snomask |= add_snomask;
288 target_p->allowed_snomask &= ~remove_snomask;
289 desc[0] = '\0';
290 for (j = 0; flag_table[j].name != NULL; j++)
292 if ((addflags & flag_table[j].mode) == flag_table[j].mode)
294 if (desc[0] != '\0')
295 strlcat(desc, " ", sizeof desc);
296 strlcat(desc, "+", sizeof desc);
297 strlcat(desc, flag_table[j].name, sizeof desc);
299 else if ((removeflags & flag_table[j].mode) == flag_table[j].mode)
301 if (desc[0] != '\0')
302 strlcat(desc, " ", sizeof desc);
303 strlcat(desc, "-", sizeof desc);
304 strlcat(desc, flag_table[j].name, sizeof desc);
307 if(desc[0] == '\0')
308 strlcpy(desc, "<none>", sizeof desc);
309 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
310 "%s is changing oper flags on %s (%s, snomask %s)",
311 get_oper_name(source_p),
312 get_client_name(target_p, HIDE_IP),
313 desc,
314 construct_snobuf_changes(target_p->allowed_snomask & ~orig_snomask,
315 orig_snomask & ~target_p->allowed_snomask));
316 sendto_one_notice(target_p, ":%s is changing oper flags on you: %s, snomask %s",
317 source_p->name, desc, construct_snobuf_changes(target_p->allowed_snomask & ~orig_snomask,
318 orig_snomask & ~target_p->allowed_snomask));
319 sendto_one_notice(source_p, ":Changed oper flags on %s: %s, snomask %s",
320 target_p->name, desc, construct_snobuf_changes(target_p->allowed_snomask & ~orig_snomask,
321 orig_snomask & ~target_p->allowed_snomask));
323 sendto_server(source_p, NULL, CAP_TS6, NOCAPS, ":%s ENCAP * OPER %s",
324 get_id(target_p, target_p), get_oper_privs(target_p->operflags));
326 sendto_server(source_p, NULL, NOCAPS, CAP_TS6, ":%s ENCAP * OPER %s",
327 target_p->name, get_oper_privs(target_p->operflags));
329 /* fix up any umodes/snomasks they may not have
330 * anymore */
331 newparv[0] = target_p->name;
332 newparv[1] = target_p->name;
333 newparv[2] = "+";
334 newparv[3] = NULL;
335 user_mode(target_p, target_p, 3, newparv);
336 changes++;
339 if (!changes)
340 sendto_one_notice(source_p, ":Oper flags on %s unchanged",
341 target_p->name);
343 return 0;