]> jfr.im git - solanum.git/blame - modules/m_scan.c
m_oper: receive ircd-seven-style opernames
[solanum.git] / modules / m_scan.c
CommitLineData
212380e3 1/*
a6f63a82 2 * Solanum: a slightly advanced ircd
212380e3
AC
3 * m_scan.c: Provides information about various targets on various topics
4 *
3fc0499e 5 * Copyright (c) 2006 Ariadne Conill <ariadne -at- dereferenced.org>
212380e3
AC
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * 1.Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 * 2.Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3.The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
28 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
212380e3
AC
30 */
31
32#include "stdinc.h"
33#include "class.h"
34#include "hook.h"
35#include "client.h"
36#include "hash.h"
212380e3 37#include "hash.h"
4562c604 38#include "match.h"
212380e3
AC
39#include "ircd.h"
40#include "numeric.h"
212380e3
AC
41#include "s_serv.h"
42#include "s_conf.h"
43#include "s_newconf.h"
44#include "s_user.h"
45#include "send.h"
46#include "msg.h"
47#include "parse.h"
48#include "modules.h"
77d3d2db 49#include "logger.h"
212380e3 50
3abc337f
AW
51static const char scan_desc[] =
52 "Provides the SCAN command to show users that have a mode set or cleared";
212380e3 53
3c7d6fcc
EM
54static void mo_scan(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
55static void scan_umodes(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
eeabf33a 56
212380e3 57struct Message scan_msgtab = {
7baa37a9 58 "SCAN", 0, 0, 0, 0,
212380e3
AC
59 {mg_ignore, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_scan, 2}}
60};
61
62mapi_clist_av1 scan_clist[] = { &scan_msgtab, NULL };
eeabf33a 63
3abc337f 64DECLARE_MODULE_AV2(scan, NULL, NULL, scan_clist, NULL, NULL, NULL, NULL, scan_desc);
212380e3 65
3c7d6fcc 66typedef void (*scan_handler)(struct MsgBuf *, struct Client *, struct Client *, int,
212380e3
AC
67 const char **);
68
69struct scan_cmd {
70 const char *name;
71 int operlevel;
72 scan_handler handler;
73} scan_cmds[] = {
74 {"UMODES", L_OPER, scan_umodes},
75 {NULL, 0, NULL}
76};
77
78static const char *empty_sockhost = "255.255.255.255";
79static const char *spoofed_sockhost = "0";
80
81/*
82 * m_scan
212380e3
AC
83 * parv[1] = options [or target]
84 * parv[2] = [target]
85 */
3c7d6fcc 86static void
428ca87b 87mo_scan(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc,
212380e3
AC
88 const char *parv[])
89{
90 struct scan_cmd *sptr;
91
92 for (sptr = scan_cmds; sptr->name != NULL; sptr++)
93 {
94 if (!irccmp(sptr->name, parv[1]))
95 {
3c7d6fcc
EM
96 if (!(sptr->operlevel == L_ADMIN && !IsOperAdmin(source_p)))
97 sptr->handler(msgbuf_p, client_p, source_p, parc, parv);
98
99 return;
212380e3
AC
100 }
101 }
102
103 sendto_one_notice(source_p, ":*** %s is not an implemented SCAN target",
104 parv[1]);
212380e3
AC
105}
106
3c7d6fcc 107static void
428ca87b 108scan_umodes(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc,
212380e3
AC
109 const char *parv[])
110{
111 unsigned int allowed_umodes = 0, disallowed_umodes = 0;
112 int what = MODE_ADD;
113 int mode;
3c7d6fcc 114 bool list_users = true;
0b5cf476 115 int list_max = 500;
212380e3
AC
116 int list_count = 0, count = 0;
117 const char *mask = NULL;
118 const char *c;
119 struct Client *target_p;
5b96d9a6
AC
120 rb_dlink_list *target_list = &lclient_list; /* local clients only by default */
121 rb_dlink_node *tn;
212380e3
AC
122 int i;
123 const char *sockhost;
124 char buf[512];
125
126 if (parc < 3)
127 {
128 if (MyClient(source_p))
129 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
130 me.name, source_p->name, "SCAN UMODES");
131
3c7d6fcc 132 return;
212380e3
AC
133 }
134
94a84cdd
JT
135 if (parv[2][0] != '+' && parv[2][0] != '-')
136 {
137 sendto_one_notice(source_p, ":SCAN UMODES: umodes parameter must start with '+' or '-'");
3c7d6fcc 138 return;
94a84cdd
JT
139 }
140
212380e3
AC
141 for (c = parv[2]; *c; c++)
142 {
143 switch(*c)
144 {
145 case '+':
146 what = MODE_ADD;
147 break;
148 case '-':
149 what = MODE_DEL;
150 break;
151 default:
152 if ((mode = user_modes[(unsigned char) *c]) != 0)
153 {
154 if (what == MODE_ADD)
155 allowed_umodes |= mode;
156 else
157 disallowed_umodes |= mode;
158 }
159 }
160 }
161
162 for (i = 3; i < parc; i++)
163 {
164 if (!irccmp(parv[i], "no-list"))
3c7d6fcc 165 list_users = false;
212380e3 166 else if (!irccmp(parv[i], "list"))
3c7d6fcc 167 list_users = true;
212380e3
AC
168 else if (!irccmp(parv[i], "global"))
169 target_list = &global_client_list;
170 else if (i < (parc - 1))
171 {
172 if (!irccmp(parv[i], "list-max"))
173 list_max = atoi(parv[++i]);
174 else if (!irccmp(parv[i], "mask"))
175 mask = parv[++i];
94a84cdd
JT
176 else
177 {
178 sendto_one_notice(source_p, ":SCAN UMODES: invalid parameters");
3c7d6fcc 179 return;
94a84cdd
JT
180 }
181 }
182 else
183 {
184 sendto_one_notice(source_p, ":SCAN UMODES: invalid parameters");
3c7d6fcc 185 return;
212380e3
AC
186 }
187 }
5f291021 188 if (target_list == &global_client_list && list_users)
212380e3
AC
189 {
190 if (IsOperSpy(source_p))
191 {
192 if (!ConfigFileEntry.operspy_dont_care_user_info)
193 {
f427c8b0 194 rb_strlcpy(buf, "UMODES", sizeof buf);
212380e3
AC
195 for (i = 2; i < parc; i++)
196 {
1f9de103
VY
197 rb_strlcat(buf, " ", sizeof buf);
198 rb_strlcat(buf, parv[i], sizeof buf);
212380e3
AC
199 }
200 report_operspy(source_p, "SCAN", buf);
201 }
202 }
203 else
204 {
205 sendto_one(source_p, form_str(ERR_NOPRIVS),
206 me.name, source_p->name, "oper_spy");
3c7d6fcc 207 return;
212380e3
AC
208 }
209 }
210
5b96d9a6 211 RB_DLINK_FOREACH(tn, target_list->head)
212380e3
AC
212 {
213 unsigned int working_umodes = 0;
214 char maskbuf[BUFSIZE];
215
216 target_p = tn->data;
217
218 if (!IsClient(target_p))
219 continue;
220
221 if(EmptyString(target_p->sockhost))
222 sockhost = empty_sockhost;
223 else if(!show_ip(source_p, target_p))
224 sockhost = spoofed_sockhost;
225 else
226 sockhost = target_p->sockhost;
227
228 working_umodes = target_p->umodes;
229
230 /* require that we have the allowed umodes... */
231 if ((working_umodes & allowed_umodes) != allowed_umodes)
232 continue;
233
234 /* require that we have NONE of the disallowed ones */
235 if ((working_umodes & disallowed_umodes) != 0)
236 continue;
237
238 if (mask != NULL)
239 {
5203cba5 240 snprintf(maskbuf, BUFSIZE, "%s!%s@%s",
212380e3
AC
241 target_p->name, target_p->username, target_p->host);
242
243 if (!match(mask, maskbuf))
244 continue;
245 }
246
247 if (list_users && (!list_max || (list_count < list_max)))
248 {
249 char modebuf[BUFSIZE];
250 char *m = modebuf;
251
252 *m++ = '+';
253
254 for (i = 0; i < 128; i++)
255 {
256 if (target_p->umodes & user_modes[i])
257 *m++ = (char) i;
258 }
259
260 *m++ = '\0';
261
262 list_count++;
263
264 sendto_one_numeric(source_p, RPL_SCANUMODES,
265 form_str(RPL_SCANUMODES),
266 target_p->name, target_p->username,
55abcbb2 267 target_p->host, sockhost,
212380e3
AC
268 target_p->servptr->name, modebuf,
269 target_p->info);
270 }
271 count++;
272 }
273
274 sendto_one_numeric(source_p, RPL_SCANMATCHED,
275 form_str(RPL_SCANMATCHED), count);
212380e3 276}