Annotation of ircnowd/src/ngircd/irc-oper.c, Revision 1.1.1.1
1.1 tomglok 1: /*
2: * ngIRCd -- The Next Generation IRC Daemon
3: * Copyright (c)2001-2015 Alexander Barton (alex@barton.de) and Contributors.
4: *
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.
10: */
11:
12: #include "portab.h"
13:
14: /**
15: * @file
16: * IRC operator commands
17: */
18:
19: #include <assert.h>
20: #include <stdio.h>
21: #include <stdlib.h>
22: #include <string.h>
23: #include <signal.h>
24: #include <time.h>
25:
26: #include "ngircd.h"
27: #include "conn-func.h"
28: #include "conf.h"
29: #include "channel.h"
30: #include "class.h"
31: #include "parse.h"
32: #include "irc.h"
33: #include "irc-macros.h"
34: #include "irc-write.h"
35: #include "lists.h"
36: #include "log.h"
37: #include "match.h"
38: #include "messages.h"
39: #include "op.h"
40:
41: #include "irc-oper.h"
42:
43: /**
44: * Handle invalid received OPER command.
45: * Log OPER attempt and send error message to client.
46: */
47: static bool
48: Bad_OperPass(CLIENT *Client, char *errtoken, char *errmsg)
49: {
50: Log(LOG_ERR|LOG_snotice, "Got invalid OPER from \"%s\": \"%s\" -- %s!",
51: Client_Mask(Client), errtoken, errmsg);
52: /* Increase penalty to slow down possible brute force attacks */
53: IRC_SetPenalty(Client, 10);
54: return IRC_WriteStrClient(Client, ERR_PASSWDMISMATCH_MSG,
55: Client_ID(Client));
56: } /* Bad_OperPass */
57:
58: /**
59: * Handler for the IRC "OPER" command.
60: *
61: * @param Client The client from which this command has been received.
62: * @param Req Request structure with prefix and all parameters.
63: * @return CONNECTED or DISCONNECTED.
64: */
65: GLOBAL bool
66: IRC_OPER( CLIENT *Client, REQUEST *Req )
67: {
68: struct Conf_Oper *op;
69: size_t len, i;
70:
71: assert( Client != NULL );
72: assert( Req != NULL );
73:
74: len = array_length(&Conf_Opers, sizeof(*op));
75: op = array_start(&Conf_Opers);
76: for (i = 0; i < len && strcmp(op[i].name, Req->argv[0]); i++)
77: ;
78: if (i >= len)
79: return Bad_OperPass(Client, Req->argv[0], "not configured");
80:
81: if (strcmp(op[i].pwd, Req->argv[1]) != 0)
82: return Bad_OperPass(Client, op[i].name, "bad password");
83:
84: if (op[i].mask && (!Match(op[i].mask, Client_Mask(Client))))
85: return Bad_OperPass(Client, op[i].mask, "hostmask check failed");
86:
87: if (!Client_HasMode(Client, 'o')) {
88: Client_ModeAdd(Client, 'o');
89: if (!IRC_WriteStrClient(Client, "MODE %s :+o",
90: Client_ID(Client)))
91: return DISCONNECTED;
92: IRC_WriteStrServersPrefix(NULL, Client, "MODE %s :+o",
93: Client_ID(Client));
94: }
95:
96: Log(LOG_NOTICE|LOG_snotice,
97: "Got valid OPER for \"%s\" from \"%s\", user is an IRC operator now.",
98: Req->argv[0], Client_Mask(Client));
99:
100: return IRC_WriteStrClient(Client, RPL_YOUREOPER_MSG, Client_ID(Client));
101: } /* IRC_OPER */
102:
103: /**
104: * Handler for the IRC "DIE" command.
105: *
106: * @param Client The client from which this command has been received.
107: * @param Req Request structure with prefix and all parameters.
108: * @return CONNECTED or DISCONNECTED.
109: */
110: GLOBAL bool
111: IRC_DIE(CLIENT * Client, REQUEST * Req)
112: {
113: /* Shut down server */
114:
115: CONN_ID c;
116: CLIENT *cl;
117:
118: assert(Client != NULL);
119: assert(Req != NULL);
120:
121: if (!Op_Check(Client, Req))
122: return Op_NoPrivileges(Client, Req);
123:
124: /* Is a message given? */
125: if (Req->argc > 0) {
126: c = Conn_First();
127: while (c != NONE) {
128: cl = Conn_GetClient(c);
129: if (Client_Type(cl) == CLIENT_USER)
130: IRC_WriteStrClient(cl, "NOTICE %s :%s",
131: Client_ID(cl), Req->argv[0]);
132: c = Conn_Next(c);
133: }
134: }
135:
136: Log(LOG_NOTICE | LOG_snotice, "Got DIE command from \"%s\" ...",
137: Client_Mask(Client));
138: NGIRCd_SignalQuit = true;
139:
140: return CONNECTED;
141: } /* IRC_DIE */
142:
143: /**
144: * Handler for the IRC "REHASH" command.
145: *
146: * @param Client The client from which this command has been received.
147: * @param Req Request structure with prefix and all parameters.
148: * @return CONNECTED or DISCONNECTED.
149: */
150: GLOBAL bool
151: IRC_REHASH( CLIENT *Client, REQUEST *Req )
152: {
153: /* Reload configuration file */
154:
155: assert( Client != NULL );
156: assert( Req != NULL );
157:
158: if (!Op_Check(Client, Req))
159: return Op_NoPrivileges(Client, Req);
160:
161: Log(LOG_NOTICE|LOG_snotice, "Got REHASH command from \"%s\" ...",
162: Client_Mask(Client));
163: IRC_WriteStrClient(Client, RPL_REHASHING_MSG, Client_ID(Client));
164:
165: raise(SIGHUP);
166:
167: return CONNECTED;
168: } /* IRC_REHASH */
169:
170: /**
171: * Handler for the IRC "RESTART" command.
172: *
173: * @param Client The client from which this command has been received.
174: * @param Req Request structure with prefix and all parameters.
175: * @return CONNECTED or DISCONNECTED.
176: */
177: GLOBAL bool
178: IRC_RESTART( CLIENT *Client, REQUEST *Req )
179: {
180: /* Restart IRC server (fork a new process) */
181:
182: assert( Client != NULL );
183: assert( Req != NULL );
184:
185: if (!Op_Check(Client, Req))
186: return Op_NoPrivileges(Client, Req);
187:
188: Log(LOG_NOTICE|LOG_snotice, "Got RESTART command from \"%s\" ...",
189: Client_Mask(Client));
190: NGIRCd_SignalRestart = true;
191:
192: return CONNECTED;
193: } /* IRC_RESTART */
194:
195: /**
196: * Handler for the IRC "CONNECT" command.
197: *
198: * @param Client The client from which this command has been received.
199: * @param Req Request structure with prefix and all parameters.
200: * @return CONNECTED or DISCONNECTED.
201: */
202: GLOBAL bool
203: IRC_CONNECT(CLIENT * Client, REQUEST * Req)
204: {
205: CLIENT *from, *target;
206:
207: assert(Client != NULL);
208: assert(Req != NULL);
209:
210: /* Bad number of parameters? */
211: if (Req->argc != 1 && Req->argc != 2 && Req->argc != 3 &&
212: Req->argc != 5 && Req->argc != 6)
213: return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
214: Client_ID(Client), Req->command);
215:
216: /* Invalid port number? */
217: if ((Req->argc > 1) && atoi(Req->argv[1]) < 1)
218: return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
219: Client_ID(Client), Req->command);
220:
221: if (Client_Type(Client) != CLIENT_SERVER
222: && !Client_HasMode(Client, 'o'))
223: return Op_NoPrivileges(Client, Req);
224:
225: from = Client;
226: target = Client_ThisServer();
227:
228: if (Req->argc == 3 || Req->argc == 6) {
229: /* This CONNECT has a target parameter */
230: if (Client_Type(Client) == CLIENT_SERVER && Req->prefix)
231: from = Client_Search(Req->prefix);
232: if (! from)
233: return IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
234: Client_ID(Client), Req->prefix);
235:
236: target = (Req->argc == 3) ? Client_Search(Req->argv[2])
237: : Client_Search(Req->argv[5]);
238: if (! target || Client_Type(target) != CLIENT_SERVER)
239: return IRC_WriteErrClient(from, ERR_NOSUCHSERVER_MSG,
240: Client_ID(from), Req->argv[0]);
241: }
242:
243: if (target != Client_ThisServer()) {
244: /* Forward CONNECT command ... */
245: if (Req->argc == 3)
246: IRC_WriteStrClientPrefix(target, from,
247: "CONNECT %s %s :%s", Req->argv[0],
248: Req->argv[1], Req->argv[2]);
249: else
250: IRC_WriteStrClientPrefix(target, from,
251: "CONNECT %s %s %s %s %s :%s", Req->argv[0],
252: Req->argv[1], Req->argv[2], Req->argv[3],
253: Req->argv[4], Req->argv[5]);
254: return CONNECTED;
255: }
256:
257: if (!Op_Check(from, Req))
258: return Op_NoPrivileges(Client, Req);
259:
260: switch (Req->argc) {
261: case 1:
262: if (!Conf_EnablePassiveServer(Req->argv[0]))
263: return IRC_WriteErrClient(from, ERR_NOSUCHSERVER_MSG,
264: Client_ID(from),
265: Req->argv[0]);
266: break;
267: case 2:
268: case 3:
269: /* Connect configured server */
270: if (!Conf_EnableServer
271: (Req->argv[0], (UINT16) atoi(Req->argv[1])))
272: return IRC_WriteErrClient(from, ERR_NOSUCHSERVER_MSG,
273: Client_ID(from),
274: Req->argv[0]);
275: break;
276: default:
277: /* Add server */
278: if (!Conf_AddServer
279: (Req->argv[0], (UINT16) atoi(Req->argv[1]), Req->argv[2],
280: Req->argv[3], Req->argv[4]))
281: return IRC_WriteErrClient(from, ERR_NOSUCHSERVER_MSG,
282: Client_ID(from),
283: Req->argv[0]);
284: }
285:
286: Log(LOG_NOTICE | LOG_snotice,
287: "Got CONNECT command from \"%s\" for \"%s\".", Client_Mask(from),
288: Req->argv[0]);
289: IRC_SendWallops(Client_ThisServer(), Client_ThisServer(),
290: "Received CONNECT %s from %s",
291: Req->argv[0], Client_ID(from));
292:
293: return CONNECTED;
294: } /* IRC_CONNECT */
295:
296: /**
297: * Handler for the IRC "DISCONNECT" command.
298: *
299: * This command is not specified in the IRC RFCs, it is an extension
300: * of ngIRCd: it shuts down and disables a configured server connection.
301: *
302: * @param Client The client from which this command has been received.
303: * @param Req Request structure with prefix and all parameters.
304: * @return CONNECTED or DISCONNECTED.
305: */
306: GLOBAL bool
307: IRC_DISCONNECT(CLIENT * Client, REQUEST * Req)
308: {
309: CONN_ID my_conn;
310:
311: assert(Client != NULL);
312: assert(Req != NULL);
313:
314: if (!Op_Check(Client, Req))
315: return Op_NoPrivileges(Client, Req);
316:
317: IRC_SendWallops(Client_ThisServer(), Client_ThisServer(),
318: "Received DISCONNECT %s from %s",
319: Req->argv[0], Client_ID(Client));
320:
321: Log(LOG_NOTICE | LOG_snotice,
322: "Got DISCONNECT command from \"%s\" for \"%s\".",
323: Client_Mask(Client), Req->argv[0]);
324:
325: /* Save ID of this connection */
326: my_conn = Client_Conn(Client);
327:
328: /* Disconnect configured server */
329: if (!Conf_DisableServer(Req->argv[0]))
330: return IRC_WriteErrClient(Client, ERR_NOSUCHSERVER_MSG,
331: Client_ID(Client), Req->argv[0]);
332:
333: /* Are we still connected or were we killed, too? */
334: if (Conn_GetClient(my_conn))
335: return CONNECTED;
336: else
337: return DISCONNECTED;
338: } /* IRC_DISCONNECT */
339:
340: /**
341: * Handler for the IRC "WALLOPS" command.
342: *
343: * @param Client The client from which this command has been received.
344: * @param Req Request structure with prefix and all parameters.
345: * @return CONNECTED or DISCONNECTED.
346: */
347: GLOBAL bool
348: IRC_WALLOPS( CLIENT *Client, REQUEST *Req )
349: {
350: CLIENT *from;
351:
352: assert( Client != NULL );
353: assert( Req != NULL );
354:
355: switch (Client_Type(Client)) {
356: case CLIENT_USER:
357: if (!Op_Check(Client, Req))
358: return Op_NoPrivileges(Client, Req);
359: from = Client;
360: break;
361: case CLIENT_SERVER:
362: _IRC_REQUIRE_PREFIX_OR_RETURN_(Client, Req)
363: from = Client_Search(Req->prefix);
364: break;
365: default:
366: return CONNECTED;
367: }
368:
369: if (!from)
370: return IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
371: Client_ID(Client), Req->prefix);
372:
373: IRC_SendWallops(Client, from, "%s", Req->argv[0]);
374: return CONNECTED;
375: } /* IRC_WALLOPS */
376:
377: /**
378: * Handle <?>LINE commands (GLINE, KLINE).
379: *
380: * @param Client The client from which this command has been received.
381: * @param Req Request structure with prefix and all parameters.
382: * @return CONNECTED or DISCONNECTED.
383: */
384: GLOBAL bool
385: IRC_xLINE(CLIENT *Client, REQUEST *Req)
386: {
387: CLIENT *from, *c, *c_next;
388: char reason[COMMAND_LEN], class_c;
389: struct list_head *list;
390: time_t timeout;
391: int class;
392:
393: assert(Client != NULL);
394: assert(Req != NULL);
395:
396: /* Bad number of parameters? */
397: if (Req->argc != 1 && Req->argc != 3)
398: return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
399: Client_ID(Client), Req->command);
400:
401: if (!Conf_AllowRemoteOper && Client_Type(Client) == CLIENT_SERVER) {
402: /* Explicitely forbid remote servers to modify "x-lines" when
403: * the "AllowRemoteOper" configuration option isn't set, even
404: * when the command seems to originate from the remote server
405: * itself: this prevents GLINE's to become set during server
406: * handshake in this case (what wouldn't be possible during
407: * regular runtime when a remote IRC Op sends the command). */
408: from = NULL;
409: } else
410: from = Op_Check(Client, Req);
411: if (!from)
412: return Op_NoPrivileges(Client, Req);
413:
414: switch(Req->command[0]) {
415: case 'g':
416: case 'G':
417: class = CLASS_GLINE; class_c = 'G';
418: break;
419: case 'k':
420: case 'K':
421: class = CLASS_KLINE; class_c = 'K';
422: break;
423: default:
424: Log(LOG_CRIT,
425: "IRC_xLINE() called for unknown line: %c!? Ignored.",
426: Req->command[0]);
427: return CONNECTED;
428: }
429:
430: if (Req->argc == 1) {
431: /* Delete mask from list */
432: Class_DeleteMask(class, Req->argv[0]);
433: Log(LOG_NOTICE|LOG_snotice,
434: "\"%s\" deleted \"%s\" from %c-Line list.",
435: Client_Mask(from), Req->argv[0], class_c);
436: if (class == CLASS_GLINE) {
437: /* Inform other servers */
438: IRC_WriteStrServersPrefix(Client, from, "%s %s",
439: Req->command, Req->argv[0]);
440:
441: }
442: } else {
443: /* Add new mask to list */
444: timeout = atol(Req->argv[1]);
445: if (timeout > 0)
446: timeout += time(NULL);
447: if (Class_AddMask(class, Req->argv[0],
448: timeout,
449: Req->argv[2])) {
450: if (Client_Type(from) != CLIENT_SERVER)
451: Log(LOG_NOTICE|LOG_snotice,
452: "\"%s\" added \"%s\" to %c-Line list: \"%s\" (%ld seconds).",
453: Client_Mask(from), Req->argv[0], class_c,
454: Req->argv[2], atol(Req->argv[1]));
455: if (class == CLASS_GLINE) {
456: /* Inform other servers */
457: IRC_WriteStrServersPrefix(Client, from,
458: "%s %s %s :%s", Req->command,
459: Req->argv[0], Req->argv[1],
460: Req->argv[2]);
461: }
462:
463: /* Check currently connected clients */
464: snprintf(reason, sizeof(reason), "%c-Line by \"%s\": \"%s\"",
465: class_c, Client_ID(from), Req->argv[2]);
466: list = Class_GetList(class);
467: c = Client_First();
468: while (c) {
469: c_next = Client_Next(c);
470: if ((class == CLASS_GLINE || Client_Conn(c) > NONE)
471: && Lists_Check(list, c))
472: IRC_KillClient(Client, NULL,
473: Client_ID(c), reason);
474: c = c_next;
475: }
476: }
477: }
478:
479: return CONNECTED;
480: }
481:
482: /* -eof- */
CVSweb