Annotation of ircnowd/src/ngircd/irc-oper.c, Revision 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