[BACK]Return to irc-oper.c CVS log [TXT][DIR] Up to [local] / ircnowd / src / ngircd

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