Ejemplo n.º 1
0
/*
 *  exit_client 
 * This is old "m_bye". Name  changed, because this is not a
 * protocol function, but a general server utility function.
 * 
 *      This function exits a client of *any* type (user, server, etc) 
 * from this server. Also, this generates all necessary prototol 
 * messages that this exit may cause. 
 * 
 *   1) If the client is a local client, then this implicitly exits
 * all other clients depending on this connection (e.g. remote
 * clients having 'from'-field that points to this. 
 * 
 *   2) If the client is a remote client, then only this is exited. 
 * 
 * For convenience, this function returns a suitable value for 
 * m_function return value: 
 * 
 *      FLUSH_BUFFER    if (cptr == sptr) 
 *      0 if (cptr != sptr)
 */
int 
exit_client(aClient *cptr, aClient *sptr, aClient *from, char *comment)
{
#ifdef  FNAME_USERLOG
    time_t on_for;
#endif
    
    if (MyConnect(sptr)) 
    {
        call_hooks(CHOOK_SIGNOFF, sptr);

        if (IsUnknown(sptr))
            Count.unknown--;
        if (IsAnOper(sptr)) 
            remove_from_list(&oper_list, sptr, NULL);
        if (sptr->flags & FLAGS_HAVERECVQ)
        {
            /* mark invalid, will be deleted in do_recvqs() */
            DLink *lp = find_dlink(recvq_clients, sptr);
            if (lp)
                lp->flags = -1;
        }
        if (IsClient(sptr))
            Count.local--;
        if (IsNegoServer(sptr))
            sendto_realops("Lost server %s during negotiation: %s", 
                           sptr->name, comment);
        
        if (IsServer(sptr)) 
        {
            Count.myserver--;
            if (IsULine(sptr))
                Count.myulined--;
            remove_from_list(&server_list, sptr, NULL);
            if (server_list == NULL) 
                server_was_split = YES;
        }
        sptr->flags |= FLAGS_CLOSING;
        if (IsPerson(sptr)) 
        {
            Link *lp, *next;
            LOpts *lopt = sptr->user->lopt;
            /* poof goes their watchlist! */
            hash_del_watch_list(sptr);
            /* if they have listopts, axe those, too */
            if(lopt != NULL) 
            {
                remove_from_list(&listing_clients, sptr, NULL);
                for (lp = lopt->yeslist; lp; lp = next) 
                {
                    next = lp->next;
                    MyFree(lp->value.cp);
                    free_link(lp);
                }
                for (lp = lopt->nolist; lp; lp = next) 
                {
                    next = lp->next;
                    MyFree(lp->value.cp);
                    free_link(lp);
                }
                                
                MyFree(sptr->user->lopt);
                sptr->user->lopt = NULL;
            }
            sendto_realops_lev(CCONN_LEV,
                               "Client exiting: %s (%s@%s) [%s] [%s]",
                               sptr->name, sptr->user->username,
                               sptr->user->host,
                               (sptr->flags & FLAGS_NORMALEX) ?
                               "Client Quit" : comment,
                               sptr->hostip);
        }
#ifdef FNAME_USERLOG
        on_for = timeofday - sptr->firsttime;
#endif
#if defined(USE_SYSLOG) && defined(SYSLOG_USERS)
        if (IsPerson(sptr))
            syslog(LOG_NOTICE, "%s (%3d:%02d:%02d): %s!%s@%s %d/%d\n",
                   myctime(sptr->firsttime),
                   on_for / 3600, (on_for % 3600) / 60,
                   on_for % 60, sptr->name,
                   sptr->user->username, sptr->user->host,
                   sptr->sendK, sptr->receiveK);
#endif
#if defined(FNAME_USERLOG)
        {
            char        linebuf[300];
            static int  logfile = -1;
            static long lasttime;
            
            /*
             * This conditional makes the logfile active only after it's
             * been created - thus logging can be turned off by removing
             * the file.
             * 
             * stop NFS hangs...most systems should be able to open a file in
             * 3 seconds. -avalon (curtesy of wumpus)
             * 
             * Keep the logfile open, syncing it every 10 seconds -Taner
             */
            if (IsPerson(sptr)) 
            {
                if (logfile == -1) 
                {
                    alarm(3);
                    logfile = open(FNAME_USERLOG, O_WRONLY | O_APPEND);
                    alarm(0);
                }
                ircsprintf(linebuf, "%s (%3d:%02d:%02d): %s!%s@%s %d/%d\n",
                           myctime(sptr->firsttime), on_for / 3600,
                           (on_for % 3600) / 60, on_for % 60,
                           sptr->name, sptr->user->username,
                           sptr->user->host, sptr->sendK, sptr->receiveK);
                alarm(3);
                write(logfile, linebuf, strlen(linebuf));
                alarm(0);
                /* Resync the file evey 10 seconds*/
                if (timeofday - lasttime > 10) 
                {
                    alarm(3);
                    close(logfile);
                    alarm(0);
                    logfile = -1;
                    lasttime = timeofday;
                }
            }
        }
#endif
        if (sptr->fd >= 0) 
        {
            if (cptr != NULL && sptr != cptr)
              sendto_one(&me, sptr, "ERROR :Closing Link: %s %s (%s)",
                           IsPerson(sptr) ? sptr->sockhost : "0.0.0.0", 
                           sptr->name, comment);
            else
              sendto_one(&me, sptr, "ERROR :Closing Link: %s (%s)",
                           IsPerson(sptr) ? sptr->sockhost : "0.0.0.0", 
                           comment);
        }
        /*
         * * Currently only server connections can have * depending
         * remote clients here, but it does no * harm to check for all
         * local clients. In * future some other clients than servers
         * might * have remotes too... *
         * 
         * Close the Client connection first and mark it * so that no
         * messages are attempted to send to it. *, The following *must*
         * make MyConnect(sptr) == FALSE!). * It also makes sptr->from ==
         * NULL, thus it's unnecessary * to test whether "sptr != acptr"
         * in the following loops.
         */
        if (IsServer(sptr)) 
        {
            sendto_ops("%s was connected for %lu seconds.  %lu/%lu "
                       "sendK/recvK.", sptr->name,
		       (long)(timeofday - sptr->firsttime),
                       sptr->sendK, sptr->receiveK);
#ifdef USE_SYSLOG
            syslog(LOG_NOTICE, "%s was connected for %lu seconds.  %lu/%lu "
                   "sendK/recvK.", sptr->name, 
                        (u_long) timeofday - sptr->firsttime,
                   sptr->sendK, sptr->receiveK);
#endif
            close_connection(sptr);
            sptr->sockerr = 0;
            sptr->flags |= FLAGS_DEADSOCKET;
        }
        else
        {
            close_connection(sptr);
            sptr->sockerr = 0;
            sptr->flags |= FLAGS_DEADSOCKET;
        }
                
    }
    exit_one_client(cptr, sptr, from, comment);
    return cptr == sptr ? FLUSH_BUFFER : 0;
}
Ejemplo n.º 2
0
int m_dkey(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
    if(!(IsNegoServer(sptr) && parc > 1))
    {
        if(IsPerson(sptr))
            return 0;
        return exit_client(sptr, sptr, sptr, "Not negotiating now");
    }
#ifdef HAVE_ENCRYPTION_ON
    if(mycmp(parv[1], "START") == 0)
    {
        char keybuf[1024];

        if(parc != 2)
            return exit_client(sptr, sptr, sptr, "DKEY START failure");

        if(sptr->serv->sessioninfo_in != NULL &&
           sptr->serv->sessioninfo_out != NULL)
            return exit_client(sptr, sptr, sptr, "DKEY START duplicate?!");

        sptr->serv->sessioninfo_in = dh_start_session();
        sptr->serv->sessioninfo_out = dh_start_session();

        sendto_realops("Initiating diffie-hellman key exchange with %s",
                       sptr->name);

        dh_get_s_public(keybuf, 1024, sptr->serv->sessioninfo_in);
        sendto_one(sptr, "DKEY PUB I %s", keybuf);

        dh_get_s_public(keybuf, 1024, sptr->serv->sessioninfo_out);
        sendto_one(sptr, "DKEY PUB O %s", keybuf);
        return 0;
    }

    if(mycmp(parv[1], "PUB") == 0)
    {
        unsigned char keybuf[1024];
        size_t keylen;

        if(parc != 4 || !sptr->serv->sessioninfo_in ||
           !sptr->serv->sessioninfo_out)
            return exit_client(sptr, sptr, sptr, "DKEY PUB failure");

        if(mycmp(parv[2], "O") == 0) /* their out is my in! */
        {
            if(!dh_generate_shared(sptr->serv->sessioninfo_in, parv[3]))
                return exit_client(sptr, sptr, sptr, "DKEY PUB O invalid");
            sptr->serv->dkey_flags |= DKEY_GOTOUT;
        }
        else if(mycmp(parv[2], "I") == 0) /* their out is my in! */
        {
            if(!dh_generate_shared(sptr->serv->sessioninfo_out, parv[3]))
                return exit_client(sptr, sptr, sptr, "DKEY PUB I invalid");
            sptr->serv->dkey_flags |= DKEY_GOTIN;
        }
        else
            return exit_client(sptr, sptr, sptr, "DKEY PUB bad option");

        if(DKEY_DONE(sptr->serv->dkey_flags))
        {
            sendto_one(sptr, "DKEY DONE");
            SetRC4OUT(sptr);

            keylen = 1024;
            if(!dh_get_s_shared(keybuf, &keylen, sptr->serv->sessioninfo_in))
                return exit_client(sptr, sptr, sptr,
                                   "Could not setup encrypted session");
            sptr->serv->rc4_in = rc4_initstate(keybuf, keylen);

            keylen = 1024;
            if(!dh_get_s_shared(keybuf, &keylen, sptr->serv->sessioninfo_out))
                return exit_client(sptr, sptr, sptr,
                                   "Could not setup encrypted session");
            sptr->serv->rc4_out = rc4_initstate(keybuf, keylen);

            dh_end_session(sptr->serv->sessioninfo_in);
            dh_end_session(sptr->serv->sessioninfo_out);

            sptr->serv->sessioninfo_in = sptr->serv->sessioninfo_out = NULL;
            return 0;
        }

        return 0;
    }


    if(mycmp(parv[1], "DONE") == 0)
    {
        if(!((sptr->serv->sessioninfo_in == NULL &&
              sptr->serv->sessioninfo_out == NULL) &&
             (sptr->serv->rc4_in != NULL && sptr->serv->rc4_out != NULL)))
            return exit_client(sptr, sptr, sptr, "DKEY DONE when not done!");
        SetRC4IN(sptr);
        sendto_realops("Diffie-Hellman exchange with %s complete, connection "
                       "encrypted.", sptr->name);
        sendto_one(sptr, "DKEY EXIT");
        return RC4_NEXT_BUFFER;
    }

    if(mycmp(parv[1], "EXIT") == 0)
    {
        if(!(IsRC4IN(sptr) && IsRC4OUT(sptr)))
            return exit_client(sptr, sptr, sptr, "DKEY EXIT when not in "
                               "proper stage");
        ClearNegoServer(sptr);
        return do_server_estab(sptr);
    }
#endif
    return 0;
}