2 * ngIRCd -- The Next Generation IRC Daemon
3 * Copyright (c)2001-2013 Alexander Barton (alex@barton.de) and Contributors.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * Please read the file COPYING, README and AUTHORS for more information.
16 * IRC operator commands
27 #include "conn-func.h"
33 #include "irc-write.h"
41 * Handle invalid received OPER command.
42 * Log OPER attempt and send error message to client.
45 Bad_OperPass(CLIENT *Client, char *errtoken, char *errmsg)
47 Log(LOG_WARNING, "Got invalid OPER from \"%s\": \"%s\" -- %s!",
48 Client_Mask(Client), errtoken, errmsg);
49 /* Increase penalty to slow down possible brute force attacks */
50 IRC_SetPenalty(Client, 10);
51 return IRC_WriteStrClient(Client, ERR_PASSWDMISMATCH_MSG,
56 * Handler for the IRC "OPER" command.
58 * @param Client The client from which this command has been received.
59 * @param Req Request structure with prefix and all parameters.
60 * @return CONNECTED or DISCONNECTED.
63 IRC_OPER( CLIENT *Client, REQUEST *Req )
68 assert( Client != NULL );
69 assert( Req != NULL );
71 len = array_length(&Conf_Opers, sizeof(*op));
72 op = array_start(&Conf_Opers);
73 for (i = 0; i < len && strcmp(op[i].name, Req->argv[0]); i++)
76 return Bad_OperPass(Client, Req->argv[0], "not configured");
78 if (strcmp(op[i].pwd, Req->argv[1]) != 0)
79 return Bad_OperPass(Client, op[i].name, "bad password");
81 if (op[i].mask && (!Match(op[i].mask, Client_Mask(Client))))
82 return Bad_OperPass(Client, op[i].mask, "hostmask check failed");
84 if (!Client_HasMode(Client, 'o')) {
85 Client_ModeAdd(Client, 'o');
86 if (!IRC_WriteStrClient(Client, "MODE %s :+o",
89 IRC_WriteStrServersPrefix(NULL, Client, "MODE %s :+o",
93 Log(LOG_NOTICE|LOG_snotice,
94 "Got valid OPER for \"%s\" from \"%s\", user is an IRC operator now.",
95 Req->argv[0], Client_Mask(Client));
97 return IRC_WriteStrClient(Client, RPL_YOUREOPER_MSG, Client_ID(Client));
101 * Handler for the IRC "DIE" command.
103 * @param Client The client from which this command has been received.
104 * @param Req Request structure with prefix and all parameters.
105 * @return CONNECTED or DISCONNECTED.
108 IRC_DIE(CLIENT * Client, REQUEST * Req)
110 /* Shut down server */
115 assert(Client != NULL);
118 if (!Op_Check(Client, Req))
119 return Op_NoPrivileges(Client, Req);
121 /* Is a message given? */
125 cl = Conn_GetClient(c);
126 if (Client_Type(cl) == CLIENT_USER)
127 IRC_WriteStrClient(cl, "NOTICE %s :%s",
128 Client_ID(cl), Req->argv[0]);
133 Log(LOG_NOTICE | LOG_snotice, "Got DIE command from \"%s\" ...",
134 Client_Mask(Client));
135 NGIRCd_SignalQuit = true;
141 * Handler for the IRC "REHASH" command.
143 * @param Client The client from which this command has been received.
144 * @param Req Request structure with prefix and all parameters.
145 * @return CONNECTED or DISCONNECTED.
148 IRC_REHASH( CLIENT *Client, REQUEST *Req )
150 /* Reload configuration file */
152 assert( Client != NULL );
153 assert( Req != NULL );
155 if (!Op_Check(Client, Req))
156 return Op_NoPrivileges(Client, Req);
158 Log(LOG_NOTICE|LOG_snotice, "Got REHASH command from \"%s\" ...",
159 Client_Mask(Client));
160 IRC_WriteStrClient(Client, RPL_REHASHING_MSG, Client_ID(Client));
168 * Handler for the IRC "RESTART" command.
170 * @param Client The client from which this command has been received.
171 * @param Req Request structure with prefix and all parameters.
172 * @return CONNECTED or DISCONNECTED.
175 IRC_RESTART( CLIENT *Client, REQUEST *Req )
177 /* Restart IRC server (fork a new process) */
179 assert( Client != NULL );
180 assert( Req != NULL );
182 if (!Op_Check(Client, Req))
183 return Op_NoPrivileges(Client, Req);
185 Log(LOG_NOTICE|LOG_snotice, "Got RESTART command from \"%s\" ...",
186 Client_Mask(Client));
187 NGIRCd_SignalRestart = true;
193 * Handler for the IRC "CONNECT" command.
195 * @param Client The client from which this command has been received.
196 * @param Req Request structure with prefix and all parameters.
197 * @return CONNECTED or DISCONNECTED.
200 IRC_CONNECT(CLIENT * Client, REQUEST * Req)
202 CLIENT *from, *target;
204 assert(Client != NULL);
207 /* Bad number of parameters? */
208 if (Req->argc != 1 && Req->argc != 2 && Req->argc != 3 &&
209 Req->argc != 5 && Req->argc != 6)
210 return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
211 Client_ID(Client), Req->command);
213 /* Invalid port number? */
214 if ((Req->argc > 1) && atoi(Req->argv[1]) < 1)
215 return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
216 Client_ID(Client), Req->command);
218 if (Client_Type(Client) != CLIENT_SERVER
219 && !Client_HasMode(Client, 'o'))
220 return Op_NoPrivileges(Client, Req);
223 target = Client_ThisServer();
225 if (Req->argc == 3 || Req->argc == 6) {
226 /* This CONNECT has a target parameter */
227 if (Client_Type(Client) == CLIENT_SERVER && Req->prefix)
228 from = Client_Search(Req->prefix);
230 return IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
231 Client_ID(Client), Req->prefix);
233 target = (Req->argc == 3) ? Client_Search(Req->argv[2])
234 : Client_Search(Req->argv[5]);
235 if (! target || Client_Type(target) != CLIENT_SERVER)
236 return IRC_WriteErrClient(from, ERR_NOSUCHSERVER_MSG,
237 Client_ID(from), Req->argv[0]);
240 if (target != Client_ThisServer()) {
241 /* Forward CONNECT command ... */
243 IRC_WriteStrClientPrefix(target, from,
244 "CONNECT %s %s :%s", Req->argv[0],
245 Req->argv[1], Req->argv[2]);
247 IRC_WriteStrClientPrefix(target, from,
248 "CONNECT %s %s %s %s %s :%s", Req->argv[0],
249 Req->argv[1], Req->argv[2], Req->argv[3],
250 Req->argv[4], Req->argv[5]);
254 if (!Op_Check(from, Req))
255 return Op_NoPrivileges(Client, Req);
259 if (!Conf_EnablePassiveServer(Req->argv[0]))
260 return IRC_WriteErrClient(from, ERR_NOSUCHSERVER_MSG,
266 /* Connect configured server */
267 if (!Conf_EnableServer
268 (Req->argv[0], (UINT16) atoi(Req->argv[1])))
269 return IRC_WriteErrClient(from, ERR_NOSUCHSERVER_MSG,
276 (Req->argv[0], (UINT16) atoi(Req->argv[1]), Req->argv[2],
277 Req->argv[3], Req->argv[4]))
278 return IRC_WriteErrClient(from, ERR_NOSUCHSERVER_MSG,
283 Log(LOG_NOTICE | LOG_snotice,
284 "Got CONNECT command from \"%s\" for \"%s\".", Client_Mask(from),
286 IRC_SendWallops(Client_ThisServer(), Client_ThisServer(),
287 "Received CONNECT %s from %s",
288 Req->argv[0], Client_ID(from));
294 * Handler for the IRC "DISCONNECT" command.
296 * This command is not specified in the IRC RFCs, it is an extension
297 * of ngIRCd: it shuts down and disables a configured server connection.
299 * @param Client The client from which this command has been received.
300 * @param Req Request structure with prefix and all parameters.
301 * @return CONNECTED or DISCONNECTED.
304 IRC_DISCONNECT(CLIENT * Client, REQUEST * Req)
308 assert(Client != NULL);
311 if (!Op_Check(Client, Req))
312 return Op_NoPrivileges(Client, Req);
314 IRC_SendWallops(Client_ThisServer(), Client_ThisServer(),
315 "Received DISCONNECT %s from %s",
316 Req->argv[0], Client_ID(Client));
318 Log(LOG_NOTICE | LOG_snotice,
319 "Got DISCONNECT command from \"%s\" for \"%s\".",
320 Client_Mask(Client), Req->argv[0]);
322 /* Save ID of this connection */
323 my_conn = Client_Conn(Client);
325 /* Disconnect configured server */
326 if (!Conf_DisableServer(Req->argv[0]))
327 return IRC_WriteErrClient(Client, ERR_NOSUCHSERVER_MSG,
328 Client_ID(Client), Req->argv[0]);
330 /* Are we still connected or were we killed, too? */
331 if (Conn_GetClient(my_conn))
335 } /* IRC_DISCONNECT */
338 * Handler for the IRC "WALLOPS" command.
340 * @param Client The client from which this command has been received.
341 * @param Req Request structure with prefix and all parameters.
342 * @return CONNECTED or DISCONNECTED.
345 IRC_WALLOPS( CLIENT *Client, REQUEST *Req )
349 assert( Client != NULL );
350 assert( Req != NULL );
352 switch (Client_Type(Client)) {
354 if (!Op_Check(Client, Req))
355 return Op_NoPrivileges(Client, Req);
359 from = Client_Search(Req->prefix);
366 return IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
367 Client_ID(Client), Req->prefix);
369 IRC_SendWallops(Client, from, "%s", Req->argv[0]);
374 * Handle <?>LINE commands (GLINE, KLINE).
376 * @param Client The client from which this command has been received.
377 * @param Req Request structure with prefix and all parameters.
378 * @return CONNECTED or DISCONNECTED.
381 IRC_xLINE(CLIENT *Client, REQUEST *Req)
383 CLIENT *from, *c, *c_next;
384 char reason[COMMAND_LEN], class_c;
385 struct list_head *list;
389 assert(Client != NULL);
392 /* Bad number of parameters? */
393 if (Req->argc != 1 && Req->argc != 3)
394 return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
395 Client_ID(Client), Req->command);
397 from = Op_Check(Client, Req);
399 return Op_NoPrivileges(Client, Req);
401 switch(Req->command[0]) {
404 class = CLASS_GLINE; class_c = 'G';
408 class = CLASS_KLINE; class_c = 'K';
412 "IRC_xLINE() called for unknown line: %c!? Ignored.",
417 if (Req->argc == 1) {
418 /* Delete mask from list */
419 Class_DeleteMask(class, Req->argv[0]);
420 Log(LOG_NOTICE|LOG_snotice,
421 "\"%s\" deleted \"%s\" from %c-Line list.",
422 Client_Mask(from), Req->argv[0], class_c);
423 if (class == CLASS_GLINE) {
424 /* Inform other servers */
425 IRC_WriteStrServersPrefix(Client, from, "%s %s",
426 Req->command, Req->argv[0]);
430 /* Add new mask to list */
431 timeout = atol(Req->argv[1]);
433 timeout += time(NULL);
434 if (Class_AddMask(class, Req->argv[0],
437 Log(LOG_NOTICE|LOG_snotice,
438 "\"%s\" added \"%s\" to %c-Line list: \"%s\" (%ld seconds).",
439 Client_Mask(from), Req->argv[0], class_c,
440 Req->argv[2], atol(Req->argv[1]));
441 if (class == CLASS_GLINE) {
442 /* Inform other servers */
443 IRC_WriteStrServersPrefix(Client, from,
444 "%s %s %s :%s", Req->command,
445 Req->argv[0], Req->argv[1],
449 /* Check currently connected clients */
450 snprintf(reason, sizeof(reason), "%c-Line by \"%s\": \"%s\"",
451 class_c, Client_ID(from), Req->argv[2]);
452 list = Class_GetList(class);
455 c_next = Client_Next(c);
456 if ((class == CLASS_GLINE || Client_Conn(c) > NONE)
457 && Lists_Check(list, c))
458 IRC_KillClient(Client, NULL,
459 Client_ID(c), reason);