/* * 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; }
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; }