]> jfr.im git - solanum.git/blob - modules/m_scan.c
Replace RPL_WHOISTEXT(337) with RPL_WHOISSPECIAL(320) (#419)
[solanum.git] / modules / m_scan.c
1 /*
2 * Solanum: a slightly advanced ircd
3 * m_scan.c: Provides information about various targets on various topics
4 *
5 * Copyright (c) 2006 Ariadne Conill <ariadne -at- dereferenced.org>
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.
30 */
31
32 #include "stdinc.h"
33 #include "class.h"
34 #include "hook.h"
35 #include "client.h"
36 #include "hash.h"
37 #include "hash.h"
38 #include "match.h"
39 #include "ircd.h"
40 #include "numeric.h"
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"
49 #include "logger.h"
50
51 static const char scan_desc[] =
52 "Provides the SCAN command to show users that have a mode set or cleared";
53
54 static void mo_scan(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
55 static void scan_umodes(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
56
57 struct Message scan_msgtab = {
58 "SCAN", 0, 0, 0, 0,
59 {mg_ignore, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_scan, 2}}
60 };
61
62 mapi_clist_av1 scan_clist[] = { &scan_msgtab, NULL };
63
64 DECLARE_MODULE_AV2(scan, NULL, NULL, scan_clist, NULL, NULL, NULL, NULL, scan_desc);
65
66 typedef void (*scan_handler)(struct MsgBuf *, struct Client *, struct Client *, int,
67 const char **);
68
69 struct 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
78 static const char *empty_sockhost = "255.255.255.255";
79 static const char *spoofed_sockhost = "0";
80
81 /*
82 * m_scan
83 * parv[1] = options [or target]
84 * parv[2] = [target]
85 */
86 static void
87 mo_scan(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc,
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 {
96 if (!(sptr->operlevel == L_ADMIN && !IsOperAdmin(source_p)))
97 sptr->handler(msgbuf_p, client_p, source_p, parc, parv);
98
99 return;
100 }
101 }
102
103 sendto_one_notice(source_p, ":*** %s is not an implemented SCAN target",
104 parv[1]);
105 }
106
107 static void
108 scan_umodes(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc,
109 const char *parv[])
110 {
111 unsigned int allowed_umodes = 0, disallowed_umodes = 0;
112 int what = MODE_ADD;
113 int mode;
114 bool list_users = true;
115 int list_max = 500;
116 int list_count = 0, count = 0;
117 const char *mask = NULL;
118 const char *c;
119 struct Client *target_p;
120 rb_dlink_list *target_list = &lclient_list; /* local clients only by default */
121 rb_dlink_node *tn;
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
132 return;
133 }
134
135 if (parv[2][0] != '+' && parv[2][0] != '-')
136 {
137 sendto_one_notice(source_p, ":SCAN UMODES: umodes parameter must start with '+' or '-'");
138 return;
139 }
140
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"))
165 list_users = false;
166 else if (!irccmp(parv[i], "list"))
167 list_users = true;
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];
176 else
177 {
178 sendto_one_notice(source_p, ":SCAN UMODES: invalid parameters");
179 return;
180 }
181 }
182 else
183 {
184 sendto_one_notice(source_p, ":SCAN UMODES: invalid parameters");
185 return;
186 }
187 }
188 if (target_list == &global_client_list && list_users)
189 {
190 if (IsOperSpy(source_p))
191 {
192 if (!ConfigFileEntry.operspy_dont_care_user_info)
193 {
194 rb_strlcpy(buf, "UMODES", sizeof buf);
195 for (i = 2; i < parc; i++)
196 {
197 rb_strlcat(buf, " ", sizeof buf);
198 rb_strlcat(buf, parv[i], sizeof buf);
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");
207 return;
208 }
209 }
210
211 RB_DLINK_FOREACH(tn, target_list->head)
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 {
240 snprintf(maskbuf, sizeof maskbuf, "%s!%s@%s",
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,
267 target_p->host, sockhost,
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);
276 }