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