void crash_report_header(FILE *reportfd, char *coredump) { char buf[512]; time_t t; fprintf(reportfd, "== UNREALIRCD CRASH REPORT ==\n" "\n" "SYSTEM INFORMATION:\n"); fprintf(reportfd, "UnrealIRCd version: %s\n", VERSIONONLY); #if defined(__VERSION__) fprintf(reportfd, " Compiler: %s\n", __VERSION__); #endif fprintf(reportfd, " Operating System: %s\n", MYOSNAME); fprintf(reportfd, "Using core file: %s\n", coredump); t = get_file_time(coredump); if (t != 0) { fprintf(reportfd, "Crash date/time: %s\n", myctime(t) ? myctime(t) : "???"); fprintf(reportfd, " Crash secs ago: %ld\n", (long)(time(NULL) - t)); } else { fprintf(reportfd, "Crash date/time: UNKNOWN\n"); fprintf(reportfd, " Crash secs ago: UNKNOWN\n"); } fprintf(reportfd, "\n"); }
static int whowas_do(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct Whowas *temp; int cur = 0; int max = -1, found = 0; char *p, *nick; if(parc < 2 || BadPtr(parv[1])) { sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]); return 0; } if(parc > 2) max = atoi(parv[2]); if(parc > 3) if(hunt_server(client_p, source_p, ":%s WHOWAS %s %s :%s", 3, parc, parv)) return 0; if((p = strchr(parv[1], ','))) *p = '\0'; nick = parv[1]; temp = WHOWASHASH[hash_whowas_name(nick)]; found = 0; for (; temp; temp = temp->next) { if(!irccmp(nick, temp->name)) { sendto_one(source_p, form_str(RPL_WHOWASUSER), me.name, parv[0], temp->name, temp->username, (IsOperAdmin(source_p))? temp->hostname : temp->rhostname, temp->realname); if(ConfigServerHide.hide_servers && !IsOper(source_p)) sendto_one(source_p, form_str(RPL_WHOISSERVER), me.name, parv[0], temp->name, ServerInfo.network_name, myctime(temp->logoff)); else sendto_one(source_p, form_str(RPL_WHOISSERVER), me.name, parv[0], temp->name, temp->servername, myctime(temp->logoff)); cur++; found++; } if(max > 0 && cur >= max) break; } if(!found) sendto_one(source_p, form_str(ERR_WASNOSUCHNICK), me.name, parv[0], nick); sendto_one(source_p, form_str(RPL_ENDOFWHOWAS), me.name, parv[0], parv[1]); return 0; }
/* log_user_exit() * * inputs - pointer to connecting client * output - NONE * side effects - Current exiting client is logged to * either SYSLOG or to file. */ void log_user_exit(struct Client *source_p) { time_t on_for = CurrentTime - source_p->firsttime; #ifdef SYSLOG_USERS if (IsPerson(source_p)) { ilog(L_INFO, "%s (%3ld:%02ld:%02ld): %s!%s@%s %ld/%ld\n", myctime(source_p->firsttime), (signed long) on_for / 3600, (signed long) (on_for % 3600)/60, (signed long) on_for % 60, source_p->name, source_p->username, source_p->host, source_p->localClient->sendK, source_p->localClient->receiveK); } #else { char linebuf[BUFSIZ]; /* * This conditional makes the logfile active only after * it's been created - thus logging can be turned off by * removing the file. * -Taner */ if (IsPerson(source_p)) { if (user_log_fb == NULL) { if ((ConfigLoggingEntry.userlog[0] != '\0') && (user_log_fb = fbopen(ConfigLoggingEntry.userlog, "r")) != NULL) { fbclose(user_log_fb); user_log_fb = fbopen(ConfigLoggingEntry.userlog, "a"); } } if (user_log_fb != NULL) { size_t nbytes = ircsprintf(linebuf, "%s (%3ld:%02ld:%02ld): %s!%s@%s %d/%d\n", myctime(source_p->firsttime), (signed long) on_for / 3600, (signed long) (on_for % 3600)/60, (signed long) on_for % 60, source_p->name, source_p->username, source_p->host, source_p->localClient->sendK, source_p->localClient->receiveK); fbputs(linebuf, user_log_fb, nbytes); } } } #endif }
void vsendto_log(int flags, char *pattern, va_list va) { char logbuf[4096]; logbuf[0] = '>'; vsprintf(logbuf + 1, pattern, va); #if defined(USE_SYSLOG) if (flags < 10) syslog(flags, "%s", logbuf + 1); #endif strcat(logbuf, "\n"); #if defined(ISERV_DEBUG) && defined(DEBUGLVL) if ((flags <= (DEBUGLVL + 9)) && (flags > LOG_DEBUG) && debug) { fprintf(debug, "[%s] %s", logstrings[flags], logbuf + 1); fflush(debug); } #endif if (iservlog && (flags < LOG_DEBUG)) { fprintf(iservlog, "[%s][%s]: %s", myctime(time(NULL)), logstrings[flags], logbuf+1); fflush(iservlog); } }
/* log_failed_oper() * * inputs - pointer to client that failed to oper up * - oper name * output - none * side effects - ffailed_operlog is written to, if its present */ void log_failed_oper(struct Client *source_p, const char *name) { if (ConfigLoggingEntry.failed_operlog[0] == '\0') return; if (IsPerson(source_p)) { FBFILE *oper_fb; if ((oper_fb = fbopen(ConfigLoggingEntry.failed_operlog, "r")) != NULL) { fbclose(oper_fb); oper_fb = fbopen(ConfigLoggingEntry.failed_operlog, "a"); } if (oper_fb != NULL) { char linebuf[BUFSIZE]; size_t nbytes = ircsprintf(linebuf, "%s FAILED OPER (%s) by (%s!%s@%s)\n", myctime(CurrentTime), name, source_p->name, source_p->username, source_p->host); fbputs(linebuf, oper_fb, nbytes); fbclose(oper_fb); } } }
/* * mo_info - oper message handler * * parv[0] = sender prefix * parv[1] = servername */ int mo_info(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { const char **text = infotext; if (hunt_server_cmd(sptr, CMD_INFO, cptr, 1, ":%C", 1, parc, parv) == HUNTED_ISME) { while (text[212]) { if (!IsOper(sptr)) send_reply(sptr, RPL_INFO, *text); text++; } if (IsOper(sptr) && (NULL != parv[1])) { while (*text) send_reply(sptr, RPL_INFO, *text++); send_reply(sptr, RPL_INFO, ""); } send_reply(sptr, SND_EXPLICIT | RPL_INFO, ":Birth Date: %s, compile # %s", creation, generation); send_reply(sptr, SND_EXPLICIT | RPL_INFO, ":On-line since %s", myctime(cli_firsttime(&me))); send_reply(sptr, RPL_ENDOFINFO); } return 0; }
/* send_birthdate_online_time() * * inputs - client pointer to send to * output - NONE * side effects - birthdate and online time are sent */ static void send_birthdate_online_time(struct Client *source_p) { sendto_one_numeric(source_p, &me, RPL_INFO|SND_EXPLICIT, ":On-line since %s", myctime(me.connection->firsttime)); }
void checkServer(struct Client *sptr, struct Client *acptr) { char outbuf[BUFSIZE]; /* Header */ send_reply(sptr, RPL_DATASTR, " "); send_reply(sptr, RPL_CHKHEAD, "server", acptr->cli_name); send_reply(sptr, RPL_DATASTR, " "); ircd_snprintf(0, outbuf, sizeof(outbuf), " Connected at:: %s (%Tu)", myctime(acptr->cli_serv->timestamp), acptr->cli_serv->timestamp); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " Server name:: %s", acptr->cli_name); send_reply(sptr, RPL_DATASTR, outbuf); if (cli_sslclifp(acptr) && (strlen(cli_sslclifp(acptr)) > 0)) { ircd_snprintf(0, outbuf, sizeof(outbuf), "SSL Fingerprint:: %s", cli_sslclifp(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); } ircd_snprintf(0, outbuf, sizeof(outbuf), " Numeric:: %s --> %d", NumServ(acptr), base64toint(acptr->cli_yxx)); send_reply(sptr, RPL_DATASTR, outbuf); ircd_snprintf(0, outbuf, sizeof(outbuf), " Users:: %d / %d", (acptr == &me) ? UserStats.local_clients : cli_serv(acptr)->clients, base64toint(cli_serv(acptr)->nn_capacity)); send_reply(sptr, RPL_DATASTR, outbuf); if (IsBurst(acptr)) send_reply(sptr, RPL_DATASTR, " Status:: Bursting"); else if (IsBurstAck(acptr)) send_reply(sptr, RPL_DATASTR, " Status:: Awaiting EOB Ack"); else if (IsService(acptr)) send_reply(sptr, RPL_DATASTR, " Status:: Network Service"); else if (IsHub(acptr)) send_reply(sptr, RPL_DATASTR, " Status:: Network Hub"); ircd_snprintf(0, outbuf, sizeof(outbuf), " Class:: %s", get_client_class(acptr)); send_reply(sptr, RPL_DATASTR, outbuf); if (feature_bool(FEAT_CHECK_EXTENDED)) { int dlinkc = 0; struct DLink* slink = NULL; send_reply(sptr, RPL_DATASTR, " "); send_reply(sptr, RPL_DATASTR, "Downlinks::"); for (slink = cli_serv(acptr)->down; slink; slink = slink->next) { ircd_snprintf(0, outbuf, sizeof(outbuf), "[%d] - %s%s", ++dlinkc, IsBurst(slink->value.cptr) ? "*" : IsBurstAck(slink->value.cptr) ? "!" : IsService(slink->value.cptr) ? "=" : IsHub(slink->value.cptr) ? "+" : " ", cli_name(slink->value.cptr)); send_reply(sptr, RPL_DATASTR, outbuf); } if (!dlinkc) send_reply(sptr, RPL_DATASTR, "<none>"); } /* Send 'END OF CHECK' message */ send_reply(sptr, RPL_ENDOFCHECK, " "); }
/* ** m_whowas ** parv[0] = sender prefix ** parv[1] = nickname queried */ DLLFUNC CMD_FUNC(m_whowas) { aWhowas *temp; int cur = 0; int max = -1, found = 0; char *p, *nick; if (parc < 2) { sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]); return 0; } if (parc > 2) max = atoi(parv[2]); if (parc > 3) if (hunt_server_token(cptr, sptr, MSG_WHOWAS, TOK_WHOWAS, "%s %s :%s", 3, parc, parv)) return 0; if (!MyConnect(sptr) && (max > 20)) max = 20; p = (char *)strchr(parv[1], ','); if (p) *p = '\0'; nick = parv[1]; temp = WHOWASHASH[hash_whowas_name(nick)]; found = 0; for (; temp; temp = temp->next) { if (!mycmp(nick, temp->name)) { sendto_one(sptr, rpl_str(RPL_WHOWASUSER), me.name, parv[0], temp->name, temp->username, (IsOper(sptr) ? temp->hostname : (*temp->virthost != '\0') ? temp->virthost : temp->hostname), temp->realname); if (!((Find_uline(temp->servername)) && !IsOper(sptr) && HIDE_ULINES)) sendto_one(sptr, rpl_str(RPL_WHOISSERVER), me.name, parv[0], temp->name, temp->servername, myctime(temp->logoff)); cur++; found++; } if (max > 0 && cur >= max) break; } if (!found) sendto_one(sptr, err_str(ERR_WASNOSUCHNICK), me.name, parv[0], nick); sendto_one(sptr, rpl_str(RPL_ENDOFWHOWAS), me.name, parv[0], parv[1]); return 0; }
/* * m_whowas - generic message handler * * parv[0] = sender prefix * parv[1] = nickname queried * parv[2] = maximum returned items (optional, default is unlimited) * parv[3] = remote server target (Opers only, max returned items 20) */ int m_whowas(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Whowas *temp; int cur = 0; int max = -1, found = 0; char *p, *nick, *s; if (parc < 2) { send_reply(sptr, ERR_NONICKNAMEGIVEN); return 0; } if (parc > 2) max = atoi(parv[2]); if (parc > 3) if (hunt_server_cmd(sptr, CMD_WHOWAS, cptr, 1, "%s %s :%C", 3, parc, parv)) return 0; parv[1] = canonize(parv[1]); if (!MyConnect(sptr) && (max > 20)) max = 20; /* Set max replies at 20 */ for (s = parv[1]; (nick = ircd_strtok(&p, s, ",")); s = 0) { /* Search through bucket, finding all nicknames that match */ found = 0; for (temp = whowashash[hash_whowas_name(nick)]; temp; temp = temp->hnext) { if (0 == ircd_strcmp(nick, temp->name)) { send_reply(sptr, RPL_WHOWASUSER, temp->name, temp->username, temp->hostname, temp->realname); if (IsAnOper(sptr) && temp->realhost) send_reply(sptr, RPL_WHOISACTUALLY, temp->name, temp->username, temp->realhost, "<untracked>"); send_reply(sptr, RPL_WHOISSERVER, temp->name, (feature_bool(FEAT_HIS_WHOIS_SERVERNAME) && !IsOper(sptr)) ? feature_str(FEAT_HIS_SERVERNAME) : temp->servername, myctime(temp->logoff)); if (temp->away) send_reply(sptr, RPL_AWAY, temp->name, temp->away); cur++; found++; } if (max >= 0 && cur >= max) break; } if (!found) send_reply(sptr, ERR_WASNOSUCHNICK, nick); /* To keep parv[1] intact for ENDOFWHOWAS */ if (p) p[-1] = ','; } send_reply(sptr, RPL_ENDOFWHOWAS, parv[1]); return 0; }
void longt(Armember *bp) { char *cp; pmode(strtoul(bp->hdr.mode, 0, 8)); Bprint(&bout, "%3ld/%1ld", atol(bp->hdr.uid), atol(bp->hdr.gid)); Bprint(&bout, "%7ld", bp->size); cp = myctime(bp->date); Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24); }
/* * send_birthdate_online_time * * inputs - client pointer to send to * output - none * side effects - birthdate and online time are sent */ static void send_birthdate_online_time(struct Client *source_p) { sendto_one(source_p, ":%s %d %s :Birth Date: %s, compile # %s", get_id(&me, source_p), RPL_INFO, get_id(source_p, source_p), creation, generation); sendto_one(source_p, ":%s %d %s :On-line since %s", get_id(&me, source_p), RPL_INFO, get_id(source_p, source_p), myctime(startup_time)); }
static void measure(int fd) { time_t start_time; int last_state; time_t last_time; int curr_state; time_t curr_time = 0; time_t time_diff; time_t active_time = 0; time_t sleep_time = 0; time_t unknown_time = 0; time_t total_time = 0; int changes = 0; float tmp; printf("Starting measurements\n"); last_state = check_powermode(fd); start_time = last_time = time(0); printf(" System is in state %s\n\n", state_name(last_state)); while(!endit) { sleep(1); curr_state = check_powermode(fd); if (curr_state != last_state || endit) { changes++; curr_time = time(0); time_diff = curr_time - last_time; if (last_state == 1) active_time += time_diff; else if (last_state == 0) sleep_time += time_diff; else unknown_time += time_diff; last_state = curr_state; last_time = curr_time; printf("%s: State-change to %s\n", myctime(curr_time), state_name(curr_state)); } } changes--; /* Compensate for SIGINT */ total_time = time(0) - start_time; printf("\nTotal running time: %lus\n", curr_time - start_time); printf(" State changed %d times\n", changes); tmp = (float)sleep_time / (float)total_time * 100; printf(" Time in sleep state: %lus (%.2f%%)\n", sleep_time, tmp); tmp = (float)active_time / (float)total_time * 100; printf(" Time in active state: %lus (%.2f%%)\n", active_time, tmp); tmp = (float)unknown_time / (float)total_time * 100; printf(" Time in unknown state: %lus (%.2f%%)\n", unknown_time, tmp); }
/* irc logs.. */ void ircd_log(int flags, char *format, ...) { va_list ap; ConfigItem_log *logs; char buf[2048], timebuf[128]; int fd; struct stat fstats; va_start(ap, format); ircvsprintf(buf, format, ap); snprintf(timebuf, sizeof timebuf, "[%s] - ", myctime(TStime())); RunHook3(HOOKTYPE_LOG, flags, timebuf, buf); strlcat(buf, "\n", sizeof buf); for (logs = conf_log; logs; logs = (ConfigItem_log *) logs->next) { #ifdef HAVE_SYSLOG if (!stricmp(logs->file, "syslog") && logs->flags & flags) { #ifdef HAVE_VSYSLOG vsyslog(LOG_INFO, format, ap); #else /* %s just to be safe */ syslog(LOG_INFO, "%s", buf); #endif continue; } #endif if (logs->flags & flags) { if (stat(logs->file, &fstats) != -1 && logs->maxsize && fstats.st_size >= logs->maxsize) { #ifndef _WIN32 fd = open(logs->file, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR); #else fd = open(logs->file, O_CREAT|O_WRONLY|O_TRUNC, S_IREAD|S_IWRITE); #endif if (fd == -1) continue; write(fd, "Max file size reached, starting new log file\n", 45); } else { #ifndef _WIN32 fd = open(logs->file, O_CREAT|O_APPEND|O_WRONLY, S_IRUSR|S_IWUSR); #else fd = open(logs->file, O_CREAT|O_APPEND|O_WRONLY, S_IREAD|S_IWRITE); #endif if (fd == -1) continue; } write(fd, timebuf, strlen(timebuf)); write(fd, buf, strlen(buf)); close(fd); } } va_end(ap); }
/* send_birthdate_online_time() * * inputs - client pointer to send to * output - NONE * side effects - birthdate and online time are sent */ static void send_birthdate_online_time(struct Client *source_p) { if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p)) { sendto_one(source_p, ":%s %d %s :Birth Date: %s, compile # %s", me.id, RPL_INFO, source_p->id, creation, generation); sendto_one(source_p, ":%s %d %s :On-line since %s", me.id, RPL_INFO, source_p->id, myctime(me.firsttime)); } else { sendto_one(source_p, ":%s %d %s :Birth Date: %s, compile # %s", me.name, RPL_INFO, source_p->name, creation, generation); sendto_one(source_p, ":%s %d %s :On-line since %s", me.name, RPL_INFO, source_p->name, myctime(me.firsttime)); } }
void checkChannel(struct Client *sptr, struct Channel *chptr) { char outbuf[TOPICLEN + MODEBUFLEN + 64], modebuf[MODEBUFLEN], parabuf[MODEBUFLEN]; /* Header */ send_reply(sptr, RPL_DATASTR, " "); send_reply(sptr, RPL_CHKHEAD, "channel", chptr->chname); send_reply(sptr, RPL_DATASTR, " "); /* Creation Time */ ircd_snprintf(sptr, outbuf, sizeof(outbuf), " Creation time:: %s", myctime(chptr->creationtime)); send_reply(sptr, RPL_DATASTR, outbuf); /* Topic */ if (strlen(chptr->topic) <= 0) send_reply(sptr, RPL_DATASTR, " Topic:: <none>"); else { ircd_snprintf(sptr, outbuf, sizeof(outbuf), " Topic:: %s", chptr->topic); send_reply(sptr, RPL_DATASTR, outbuf); /* ..set by */ ircd_snprintf(sptr, outbuf, sizeof(outbuf), " Set by:: %s", chptr->topic_nick); send_reply(sptr, RPL_DATASTR, outbuf); } /* Channel Modes */ strcpy(outbuf, "Channel mode(s):: "); modebuf[0] = '\0'; parabuf[0] = '\0'; channel_modes(sptr, modebuf, parabuf, sizeof(modebuf), chptr); if(modebuf[1] == '\0') strcat(outbuf, "<none>"); else if(*parabuf) { strcat(outbuf, modebuf); strcat(outbuf, " "); strcat(outbuf, parabuf); } else strcat(outbuf, modebuf); send_reply(sptr, RPL_DATASTR, outbuf); /* Don't send 'END OF CHECK' message, it's sent in checkUsers, which is called after this. */ }
int write_chat_record(struct command *cmdline,char *ip) { struct tm *tml; tml=myctime(); char buf[1024]; pthread_mutex_lock(&chatrecord_mutex); sprintf(buf, "[%d-%d-%d %d:%d:%d][%s][%s][%s]:\n%s\n", tml->tm_year,tml->tm_mon,tml->tm_mday,tml->tm_hour,tml->tm_min,tml->tm_sec, ip, cmdline->source, cmdline->dest, cmdline->data); fwrite(buf,sizeof(char),strlen(buf),fp); sync(); pthread_mutex_unlock(&chatrecord_mutex); return 0; }
void vsendto_log(int flags, int slflag, char *pattern, va_list va) { char logbuf[4096]; logbuf[0] = '>'; vsprintf(logbuf+1, pattern, va); #if defined(USE_SYSLOG) if (slflag) syslog(slflag, "%s", logbuf+1); #endif strcat(logbuf, "\n"); #if defined(IAUTH_DEBUG) if ((flags & ALOG_DALL) && (flags & debuglevel) && debug) { fprintf(debug, "%s", logbuf+1); fflush(debug); } #endif if (authlog && (flags & ALOG_FLOG)) { fprintf(authlog, "%s: %s", myctime(time(NULL)), logbuf+1); fflush(authlog); } if (flags & ALOG_IRCD) { write(0, logbuf, strlen(logbuf)); #if defined(IAUTH_DEBUG) if ((ALOG_DSPY & debuglevel) && debug) { fprintf(debug, "To ircd: %s", logbuf+1); fflush(debug); } #endif } }
void m_info_send(aClient *sptr) { char **text = unrealinfo; sendto_one(sptr, ":%s %d %s :=-=-=-= %s =-=-=-=", me.name, RPL_INFO, sptr->name, IRCDTOTALVERSION); while (*text) sendto_one(sptr, ":%s %d %s :| %s", me.name, RPL_INFO, sptr->name, *text++); sendto_one(sptr, ":%s %d %s :|", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :|", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :| Credits - Type /Credits", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :| DALnet Credits - Type /DalInfo", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :|", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :| This is an UnrealIRCd-style server", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :| If you find any bugs, please report them at:", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :| http://bugs.unrealircd.org/", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :| UnrealIRCd Homepage: http://www.unrealircd.com", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=", me.name, RPL_INFO, sptr->name); sendto_one(sptr, ":%s %d %s :Birth Date: %s, compile # %s", me.name, RPL_INFO, sptr->name, creation, generation); sendto_one(sptr, ":%s %d %s :On-line since %s", me.name, RPL_INFO, sptr->name, myctime(me.firsttime)); sendto_one(sptr, ":%s %d %s :ReleaseID (%s)", me.name, RPL_INFO, sptr->name, buildid); sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, sptr->name); }
/* ** m_whowas ** parv[0] = sender prefix ** parv[1] = nickname queried */ int m_whowas(aClient *cptr, aClient *sptr, int parc, char *parv[]) { Reg aName *wp, *wp2 = NULL; Reg int j = 0; Reg anUser *up = NULL; int max = -1; char *p = NULL, *nick, *s; if (parc < 2) { sendto_one(sptr, replies[ERR_NONICKNAMEGIVEN], ME, BadTo(parv[0])); return 1; } if (parc > 2) max = atoi(parv[2]); if (parc > 3) if (hunt_server(cptr,sptr,":%s WHOWAS %s %s :%s", 3,parc,parv)) return 3; parv[1] = canonize(parv[1]); if (!MyConnect(sptr)) max = MIN(max, 20); for (s = parv[1]; (nick = strtoken(&p, s, ",")); s = NULL) { wp = wp2 = &was[(ww_index ? ww_index : ww_size) - 1]; j = 0; do { if (mycmp(nick, wp->ww_nick) == 0) { up = wp->ww_user; sendto_one(sptr, replies[RPL_WHOWASUSER], ME, BadTo(parv[0]), wp->ww_nick, up->username, up->host, wp->ww_info); sendto_one(sptr, replies[RPL_WHOISSERVER], ME, BadTo(parv[0]), wp->ww_nick, up->server, myctime(wp->ww_logout)); j++; } if (max > 0 && j >= max) break; if (wp == was) wp = &was[ww_size - 1]; else wp--; } while (wp != wp2); if (up == NULL) { if (strlen(nick) > (size_t) NICKLEN) nick[NICKLEN] = '\0'; sendto_one(sptr, replies[ERR_WASNOSUCHNICK], ME, BadTo(parv[0]), nick); } else up = NULL; if (p) p[-1] = ','; } sendto_one(sptr, replies[RPL_ENDOFWHOWAS], ME, BadTo(parv[0]), parv[1]); return 2; }
/* irc logs.. */ void ircd_log(int flags, char *format, ...) { static int last_log_file_warning = 0; static char recursion_trap=0; va_list ap; ConfigItem_log *logs; char buf[2048], timebuf[128]; struct stat fstats; int written = 0, write_failure = 0; int n; /* Trap infinite recursions to avoid crash if log file is unavailable, * this will also avoid calling ircd_log from anything else called */ if (recursion_trap == 1) return; recursion_trap = 1; va_start(ap, format); ircvsnprintf(buf, sizeof(buf), format, ap); va_end(ap); snprintf(timebuf, sizeof(timebuf), "[%s] - ", myctime(TStime())); RunHook3(HOOKTYPE_LOG, flags, timebuf, buf); strlcat(buf, "\n", sizeof(buf)); if (!loop.ircd_forked && (flags & LOG_ERROR)) fprintf(stderr, "%s", buf); for (logs = conf_log; logs; logs = (ConfigItem_log *) logs->next) { #ifdef HAVE_SYSLOG if (!stricmp(logs->file, "syslog") && logs->flags & flags) { syslog(LOG_INFO, "%s", buf); written++; continue; } #endif if (logs->flags & flags) { if (stat(logs->file, &fstats) != -1 && logs->maxsize && fstats.st_size >= logs->maxsize) { char oldlog[512]; if (logs->logfd != -1) { write(logs->logfd, "Max file size reached, starting new log file\n", 45); fd_close(logs->logfd); } /* Rename log file to xxxxxx.old */ snprintf(oldlog, sizeof(oldlog), "%s.old", logs->file); rename(logs->file, oldlog); logs->logfd = fd_fileopen(logs->file, O_CREAT|O_WRONLY|O_TRUNC); if (logs->logfd == -1) continue; } else if (logs->logfd == -1) { #ifndef _WIN32 logs->logfd = fd_fileopen(logs->file, O_CREAT|O_APPEND|O_WRONLY); #else logs->logfd = fd_fileopen(logs->file, O_CREAT|O_APPEND|O_WRONLY); #endif if (logs->logfd == -1) { if (!loop.ircd_booted) { config_status("WARNING: Unable to write to '%s': %s", logs->file, strerror(ERRNO)); } else { if (last_log_file_warning + 300 < TStime()) { config_status("WARNING: Unable to write to '%s': %s. This warning will not re-appear for at least 5 minutes.", logs->file, strerror(ERRNO)); last_log_file_warning = TStime(); } } write_failure = 1; continue; } } /* this shouldn't happen, but lets not waste unnecessary syscalls... */ if (logs->logfd == -1) continue; write(logs->logfd, timebuf, strlen(timebuf)); n = write(logs->logfd, buf, strlen(buf)); if (n == strlen(buf)) { written++; } else { if (!loop.ircd_booted) { config_status("WARNING: Unable to write to '%s': %s", logs->file, strerror(ERRNO)); } else { if (last_log_file_warning + 300 < TStime()) { config_status("WARNING: Unable to write to '%s': %s. This warning will not re-appear for at least 5 minutes.", logs->file, strerror(ERRNO)); last_log_file_warning = TStime(); } } write_failure = 1; } #ifndef _WIN32 fsync(logs->logfd); #endif } } recursion_trap = 0; }
/* irc logs.. */ void ircd_log(int flags, char *format, ...) { static int last_log_file_warning = 0; va_list ap; ConfigItem_log *logs; char buf[2048], timebuf[128]; struct stat fstats; int written = 0, write_failure = 0; va_start(ap, format); ircvsnprintf(buf, sizeof(buf), format, ap); va_end(ap); snprintf(timebuf, sizeof(timebuf), "[%s] - ", myctime(TStime())); RunHook3(HOOKTYPE_LOG, flags, timebuf, buf); strlcat(buf, "\n", sizeof(buf)); for (logs = conf_log; logs; logs = (ConfigItem_log *) logs->next) { #ifdef HAVE_SYSLOG if (!stricmp(logs->file, "syslog") && logs->flags & flags) { syslog(LOG_INFO, "%s", buf); written++; continue; } #endif if (logs->flags & flags) { if (stat(logs->file, &fstats) != -1 && logs->maxsize && fstats.st_size >= logs->maxsize) { if (logs->logfd != -1) fd_close(logs->logfd); logs->logfd = fd_fileopen(logs->file, O_CREAT|O_WRONLY|O_TRUNC); if (logs->logfd == -1) continue; if (write(logs->logfd, "Max file size reached, starting new log file\n", 45) < 0) { write_failure = 1; continue; } } else if (logs->logfd == -1) { logs->logfd = fd_fileopen(logs->file, O_CREAT|O_APPEND|O_WRONLY); if (logs->logfd == -1) { if (!loop.ircd_booted) { config_status("WARNING: Unable to write to '%s': %s", logs->file, strerror(ERRNO)); } else { if (last_log_file_warning + 300 < TStime()) { config_status("WARNING: Unable to write to '%s': %s. This warning will not re-appear for at least 5 minutes.", logs->file, strerror(ERRNO)); last_log_file_warning = TStime(); } } write_failure = 1; continue; } } /* this shouldn't happen, but lets not waste unnecessary syscalls... */ if (logs->logfd == -1) continue; if (write(logs->logfd, timebuf, strlen(timebuf)) < 0) { if (!loop.ircd_booted) { config_status("WARNING: Unable to write to '%s': %s", logs->file, strerror(ERRNO)); } else { if (last_log_file_warning + 300 < TStime()) { config_status("WARNING: Unable to write to '%s': %s. This warning will not re-appear for at least 5 minutes.", logs->file, strerror(ERRNO)); last_log_file_warning = TStime(); } } write_failure = 1; } if (write(logs->logfd, buf, strlen(buf)) == strlen(buf)) { written++; } else { if (!loop.ircd_booted) { config_status("WARNING: Unable to write to '%s': %s", logs->file, strerror(ERRNO)); } else { if (last_log_file_warning + 300 < TStime()) { config_status("WARNING: Unable to write to '%s': %s. This warning will not re-appear for at least 5 minutes.", logs->file, strerror(ERRNO)); last_log_file_warning = TStime(); } } write_failure = 1; } fsync(logs->logfd); } } /* If nothing got written at all AND we had a write failure AND we are booting, then exit. * Note that we can't just fail when nothing got written, as we might have been called for * 'tkl' for example, which might not be in our log block. */ if (!written && write_failure && !loop.ircd_booted) { config_status("ERROR: Unable to write to any log file. Please check your log { } blocks and file permissions!"); exit(9); } }
/* * try_connections * * Scan through configuration and try new connections. * Returns the calendar time when the next call to this * function should be made latest. (No harm done if this * is called earlier or later...) */ static time_t try_connections(time_t currenttime) { aConfItem *aconf, **pconf, *con_conf = (aConfItem *) NULL; aClient *cptr; aClass *cltmp; int connecting, confrq, con_class = 0; time_t next = 0; connecting = FALSE; Debug((DEBUG_NOTICE, "Connection check at : %s", myctime(currenttime))); for (aconf = conf; aconf; aconf = aconf->next) { /* Also when already connecting! (update holdtimes) --SRB */ if (!(aconf->status & CONF_CONNECT_SERVER) || aconf->port <= 0) continue; cltmp = Class (aconf); /* * * Skip this entry if the use of it is still on hold until * future. Otherwise handle this entry (and set it on hold * until next time). Will reset only hold times, if already * made one successfull connection... [this algorithm is a bit * fuzzy... -- msa >;) ] */ if ((aconf->hold > currenttime)) { if ((next > aconf->hold) || (next == 0)) next = aconf->hold; continue; } confrq = get_con_freq(cltmp); aconf->hold = currenttime + confrq; /* Found a CONNECT config with port specified, scan clients * and see if this server is already connected? */ cptr = find_name(aconf->name, (aClient *) NULL); if (!cptr && (Links(cltmp) < MaxLinks(cltmp)) && (!connecting || (Class (cltmp) > con_class))) { con_class = Class (cltmp); con_conf = aconf; /* We connect only one at time... */ connecting = TRUE; } if ((next > aconf->hold) || (next == 0)) next = aconf->hold; } if (connecting) { if (con_conf->next) /* are we already last? */ { for (pconf = &conf; (aconf = *pconf); pconf = &(aconf->next)) /* * put the current one at the end and make sure we try all * connections */ if (aconf == con_conf) *pconf = aconf->next; (*pconf = con_conf)->next = 0; } if (connect_server(con_conf, (aClient *) NULL, (struct hostent *) NULL) == 0) sendto_gnotice("from %s: Connection to %s activated.", me.name, con_conf->name); } Debug((DEBUG_NOTICE, "Next connection check : %s", myctime(next))); return (next); }
static time_t check_pings(time_t currenttime) { aClient *cptr; aConfItem *aconf = (aConfItem *) NULL; int killflag, zkillflag, ping = 0, i; time_t oldest = 0; /* timeout removed, see EXPLANATION below */ char *reason, *ktype, fbuf[512]; char *errtxt = "No response from %s, closing link"; for (i = 0; i <= highest_fd; i++) { if (!(cptr = local[i]) || IsMe(cptr) || IsLog(cptr)) continue; /* Note: No need to notify opers here. It's * already done when "FLAGS_DEADSOCKET" is set. */ if (cptr->flags & FLAGS_DEADSOCKET) { (void) exit_client(cptr, cptr, &me, (cptr->flags & FLAGS_SENDQEX) ? "SendQ exceeded" : "Dead socket"); i--; continue; } killflag = NO; zkillflag = NO; if (rehashed) { if (zline_in_progress) { if (IsPerson(cptr)) { if ((aconf = find_zkill(cptr))) zkillflag = YES; } } else { if(IsPerson(cptr)) { if((aconf = find_kill(cptr))) killflag = YES; } } } /* Added a bit of code here to differentiate * between K and Z-lines. -ThemBones */ if (zkillflag || killflag) { ktype = zkillflag ? "Z-lined" : ((aconf->status == CONF_KILL) ? "K-lined" : "Autokilled"); if (killflag) { sendto_ops("%s active for %s", (aconf->status == CONF_KILL) ? "K-line" : "Autokill", get_client_name(cptr, FALSE)); reason = aconf->passwd ? aconf->passwd : ktype; } else { /* its a Z line */ sendto_ops("Z-line active for %s", get_client_name(cptr, FALSE)); reason = aconf->passwd ? aconf->passwd : "Z-lined"; } sendto_one(cptr, err_str(ERR_YOUREBANNEDCREEP), me.name, cptr->name, ktype); ircsprintf(fbuf, "%s: %s", ktype, reason); (void) exit_client(cptr, cptr, &me, fbuf); i--; /* subtract out this fd so we check it again.. */ continue; } if (IsRegistered(cptr)) ping = cptr->pingval; else ping = CONNECTTIMEOUT; /* * Ok, so goto's are ugly and can be avoided here but this code * is already indented enough so I think its justified. -avalon * * justified by what? laziness? <g> * If the client pingtime is fine (ie, not larger than the client ping) * skip over all the checks below. - lucas */ if (ping < (currenttime - cptr->lasttime)) { /* * If the server hasnt talked to us in 2*ping seconds and it has * a ping time, then close its connection. If the client is a * user and a KILL line was found to be active, close this * connection too. */ if (((cptr->flags & FLAGS_PINGSENT) && ((currenttime - cptr->lasttime) >= (2 * ping))) || ((!IsRegistered(cptr) && (currenttime - cptr->since) >= ping))) { if (!IsRegistered(cptr) && (DoingDNS(cptr) || DoingAuth(cptr))) { if (cptr->authfd >= 0) { (void) close(cptr->authfd); cptr->authfd = -1; cptr->count = 0; *cptr->buffer = '\0'; } #ifdef SHOW_HEADERS if (DoingDNS(cptr)) ssl_send(cptr, REPORT_FAIL_DNS, R_fail_dns, 0); if (DoingAuth(cptr)) ssl_send(cptr, REPORT_FAIL_ID, R_fail_id, 0); #endif Debug((DEBUG_NOTICE, "DNS/AUTH timeout %s", get_client_name(cptr, TRUE))); del_queries((char *) cptr); ClearAuth(cptr); ClearDNS(cptr); SetAccess(cptr); cptr->since = currenttime; continue; } if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr)) { ircsprintf(fbuf, "from %s: %s", me.name, errtxt); sendto_gnotice(fbuf, get_client_name(cptr, HIDEME)); ircsprintf(fbuf, ":%s GNOTICE :%s", me.name, errtxt); sendto_serv_butone(cptr, fbuf, get_client_name(cptr, HIDEME)); } (void) exit_client(cptr, cptr, &me, "Ping timeout"); i--; /* subtract out this fd so we check it again.. */ continue; } /* don't send pings during a burst, as we send them already. */ else if (!(cptr->flags & (FLAGS_PINGSENT|FLAGS_BURST))) { /* * if we havent PINGed the connection and we havent heard from * it in a while, PING it to make sure it is still alive. */ cptr->flags |= FLAGS_PINGSENT; /* * not nice but does the job */ cptr->lasttime = currenttime - ping; sendto_one(cptr, "PING :%s", me.name); } } /* see EXPLANATION below * * timeout = cptr->lasttime + ping; * while (timeout <= currenttime) * timeout += ping; * if (timeout < oldest || !oldest) * oldest = timeout; */ /* * Check UNKNOWN connections - if they have been in this state * for > 100s, close them. */ if (IsUnknown(cptr)) if (cptr->firsttime ? ((timeofday - cptr->firsttime) > 100) : 0) (void) exit_client(cptr, cptr, &me, "Connection Timed Out"); } rehashed = 0; zline_in_progress = 0; /* EXPLANATION * on a server with a large volume of clients, at any given point * there may be a client which needs to be pinged the next second, * or even right away (a second may have passed while running * check_pings). Preserving CPU time is more important than * pinging clients out at exact times, IMO. Therefore, I am going to make * check_pings always return currenttime + 9. This means that it may take * a user up to 9 seconds more than pingfreq to timeout. Oh well. * Plus, the number is 9 to 'stagger' our check_pings calls out over * time, to avoid doing it and the other tasks ircd does at the same time * all the time (which are usually done on intervals of 5 seconds or so). * - lucas * * if (!oldest || oldest < currenttime) * oldest = currenttime + PINGFREQUENCY; */ oldest = currenttime + 9; Debug((DEBUG_NOTICE, "Next check_ping() call at: %s, %d %d %d", myctime(oldest), ping, oldest, currenttime)); return oldest; }
/* ** try_connections ** ** Scan through configuration and try new connections. ** Returns the calendar time when the next call to this ** function should be made latest. (No harm done if this ** is called earlier or later...) */ static time_t try_connections(time_t currenttime) { Reg aConfItem *aconf; Reg aClient *cptr; aConfItem **pconf; int confrq; time_t next = 0; aClass *cltmp; aConfItem *con_conf = NULL; int allheld = 1; #ifdef DISABLE_DOUBLE_CONNECTS int i; #endif if ((bootopt & BOOT_STANDALONE)) return 0; Debug((DEBUG_NOTICE,"Connection check at : %s", myctime(currenttime))); for (aconf = conf; aconf; aconf = aconf->next ) { /* not a C-line */ if (!(aconf->status & (CONF_CONNECT_SERVER|CONF_ZCONNECT_SERVER))) continue; /* not a candidate for AC */ if (aconf->port <= 0) continue; cltmp = Class(aconf); /* not a candidate for AC */ if (MaxLinks(cltmp) == 0) continue; /* minimize next to lowest hold time of all AC-able C-lines */ if (next > aconf->hold || next == 0) next = aconf->hold; /* skip conf if the use of it is on hold until future. */ if (aconf->hold > currenttime) continue; /* at least one candidate not held for future, good */ allheld = 0; /* see if another link in this conf is allowed */ if (Links(cltmp) >= MaxLinks(cltmp)) continue; /* next possible check after connfreq secs for this C-line */ confrq = get_con_freq(cltmp); aconf->hold = currenttime + confrq; /* is this server already connected? */ cptr = find_name(aconf->name, (aClient *)NULL); if (!cptr) cptr = find_mask(aconf->name, (aClient *)NULL); /* matching client already exists, no AC to it */ if (cptr) continue; /* no such server, check D-lines */ if (find_denied(aconf->name, Class(cltmp))) continue; #ifdef DISABLE_DOUBLE_CONNECTS /* Much better would be traversing only unknown ** connections, but this requires another global ** variable, adding and removing from there in ** proper places etc. Some day. --B. */ for (i = highest_fd; i >= 0; i--) { if (!(cptr = local[i]) || cptr->status > STAT_UNKNOWN) { continue; } /* an unknown traveller we have */ if ( #ifndef INET6 cptr->ip.s_addr == aconf->ipnum.s_addr #else !memcmp(cptr->ip.s6_addr, aconf->ipnum.s6_addr, 16) #endif ) { /* IP the same. Coincidence? Maybe. ** Do not cause havoc with double connect. */ break; } cptr = NULL; } if (cptr) { sendto_flag(SCH_SERVER, "AC to %s postponed", aconf->name); continue; } #endif /* we have a candidate! */ /* choose the best. */ if (!con_conf || (con_conf->pref > aconf->pref && aconf->pref >= 0) || (con_conf->pref == -1 && Class(cltmp) > ConfClass(con_conf))) { con_conf = aconf; } /* above is my doubt: if we always choose best connection ** and it always fails connecting, we may never try another, ** even "worse"; what shall we do? --Beeth */ } if (con_conf) { if (con_conf->next) /* are we already last? */ { for (pconf = &conf; (aconf = *pconf); pconf = &(aconf->next)) /* put the current one at the end and * make sure we try all connections */ if (aconf == con_conf) *pconf = aconf->next; (*pconf = con_conf)->next = 0; } /* "Penalty" for being the best, so in next call of * try_connections() other servers have chance. --B. */ con_conf->hold += get_con_freq(Class(con_conf)); if (!iconf.aconnect) { sendto_flag(SCH_NOTICE, "Connection to %s deferred. Autoconnect " "administratively disabled", con_conf->name); } else if (connect_server(con_conf, (aClient *)NULL, (struct hostent *)NULL) == 0) { sendto_flag(SCH_NOTICE, "Connection to %s[%s] activated.", con_conf->name, con_conf->host); } } else if (allheld == 0) /* disable AC only when some C: got checked */ { /* No suitable conf for AC was found, so why bother checking ** again? If some server quits, it'd get reenabled --B. */ next = 0; } Debug((DEBUG_NOTICE,"Next connection check : %s", myctime(next))); return (next); }
/* ** m_whowas ** parv[0] = sender prefix ** parv[1] = nickname queried */ int m_whowas(aClient *cptr, aClient *sptr, int parc, char *parv[]) { aWhowas *temp; int cur = 0; int max = -1, found = 0; char *p, *nick; /* char *s; */ static time_t last_used=0L; if (parc < 2) { sendto_one(sptr, form_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]); return 0; } if (parc > 2) max = atoi(parv[2]); if (parc > 3) if (hunt_server(cptr,sptr,":%s WHOWAS %s %s :%s", 3,parc,parv)) return 0; if(!IsAnOper(sptr) && !MyConnect(sptr)) /* pace non local requests */ { if((last_used + WHOIS_WAIT) > CurrentTime) { return 0; } else { last_used = CurrentTime; } } if (!MyConnect(sptr) && (max > 20)) max = 20; /* for (s = parv[1]; (nick = strtoken(&p, s, ",")); s = NULL) */ p = strchr(parv[1],','); if(p) *p = '\0'; nick = parv[1]; temp = WHOWASHASH[hash_whowas_name(nick)]; found = 0; for(;temp;temp=temp->next) { if (!irccmp(nick, temp->name)) { sendto_one(sptr, form_str(RPL_WHOWASUSER), me.name, parv[0], temp->name, temp->username, temp->hostname, temp->realname); sendto_one(sptr, form_str(RPL_WHOISSERVER), me.name, parv[0], temp->name, #ifdef SERVERHIDE IsAnOper(sptr) ? temp->servername : NETWORK_NAME, #else temp->servername, #endif myctime(temp->logoff)); cur++; found++; } if (max > 0 && cur >= max) break; } if (!found) sendto_one(sptr, form_str(ERR_WASNOSUCHNICK), me.name, parv[0], nick); sendto_one(sptr, form_str(RPL_ENDOFWHOWAS), me.name, parv[0], parv[1]); return 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; }
int main() { buffer bin; buffer bout; struct prioq_elt pe; int fdoldmbox; int fdnewmbox; int fd; int match; int fdlock; umask(077); mbox = env_get("MAIL"); if (!mbox) strerr_die2x(111,FATL,"MAIL not set"); mboxtmp = env_get("MAILTMP"); if (!mboxtmp) strerr_die2x(111,FATL,"MAILTMP not set"); if (maildir_chdir() == -1) strerr_die1(111,FATAL,&maildir_chdir_err); maildir_clean(&filenames); if (maildir_scan(&pq,&filenames,1,1) == -1) strerr_die1(111,FATAL,&maildir_scan_err); if (!prioq_min(&pq,&pe)) _exit(0); /* nothing new */ fdlock = open_append(mbox); if (fdlock == -1) strerr_die4sys(111,FATL,"unable to lock ",mbox,": "); if (lock_ex(fdlock) == -1) strerr_die4sys(111,FATL,"unable to lock ",mbox,": "); fdoldmbox = open_read(mbox); if (fdoldmbox == -1) strerr_die4sys(111,FATL,"unable to read ",mbox,": "); fdnewmbox = open_trunc(mboxtmp); if (fdnewmbox == -1) strerr_die4sys(111,FATL,"unable to create ",mboxtmp,": "); buffer_init(&bin,read,fdoldmbox,inbuf,sizeof(inbuf)); buffer_init(&bout,write,fdnewmbox,outbuf,sizeof(outbuf)); switch(buffer_copy(&bout,&bin)) { case -2: strerr_die4sys(111,FATL,"unable to read ",mbox,": "); case -3: strerr_die4sys(111,FATL,"unable to write to ",mboxtmp,": "); } while (prioq_min(&pq,&pe)) { prioq_delmin(&pq); if (!prioq_insert(&pq2,&pe)) die_nomem(); fd = open_read(filenames.s + pe.id); if (fd == -1) strerr_die4sys(111,FATL,"unable to read $MAILDIR/",filenames.s + pe.id,": "); buffer_init(&bin,read,fd,inbuf,sizeof(inbuf)); if (getln(&bin,&line,&match,'\n') != 0) strerr_die4sys(111,FATL,"unable to read $MAILDIR/",filenames.s + pe.id,": "); if (!stralloc_copys(&ufline,"From XXX ")) die_nomem(); if (match) if (stralloc_starts(&line,"Return-Path: <")) { if (line.s[14] == '>') { if (!stralloc_copys(&ufline,"From MAILER-DAEMON ")) die_nomem(); } else { int i; if (!stralloc_ready(&ufline,line.len)) die_nomem(); if (!stralloc_copys(&ufline,"From ")) die_nomem(); for (i = 14;i < line.len - 2;++i) if ((line.s[i] == ' ') || (line.s[i] == '\t')) ufline.s[ufline.len++] = '-'; else { ufline.s[ufline.len++] = line.s[i]; if (!stralloc_cats(&ufline," ")) die_nomem(); } } } if (!stralloc_cats(&ufline,myctime(pe.dt))) die_nomem(); if (buffer_put(&bout,ufline.s,ufline.len) == -1) strerr_die4sys(111,FATAL,"unable to write to ",mboxtmp,": "); while (match && line.len) { if (gfrom(line.s,line.len)) if (buffer_puts(&bout,">") == -1) strerr_die4sys(111,FATL,"unable to write to ",mboxtmp,": "); if (buffer_put(&bout,line.s,line.len) == -1) strerr_die4sys(111,FATL,"unable to write to ",mboxtmp,": "); if (!match) { if (buffer_puts(&bout,"\n") == -1) strerr_die4sys(111,FATL,"unable to write to ",mboxtmp,": "); break; } if (getln(&bin,&line,&match,'\n') != 0) strerr_die4sys(111,FATL,"unable to read $MAILDIR/",filenames.s + pe.id,": "); } if (buffer_puts(&bout,"\n")) strerr_die4sys(111,FATL,"unable to write to ",mboxtmp,": "); close(fd); } if (buffer_flush(&bout) == -1) strerr_die4sys(111,FATL,"unable to write to ",mboxtmp,": "); if (fsync(fdnewmbox) == -1) strerr_die4sys(111,FATL,"unable to write to ",mboxtmp,": "); if (close(fdnewmbox) == -1) /* NFS dorks */ strerr_die4sys(111,FATL,"unable to write to ",mboxtmp,": "); if (rename(mboxtmp,mbox) == -1) strerr_die6(111,FATL,"unable to move ",mboxtmp," to ",mbox,": ",&strerr_sys); while (prioq_min(&pq2,&pe)) { prioq_delmin(&pq2); if (unlink(filenames.s + pe.id) == -1) strerr_warn4(WARNING,"$MAILDIR/",filenames.s + pe.id," will be delivered twice; unable to unlink: ",&strerr_sys); } return(0); }
static time_t check_pings(time_t currenttime) { #ifdef TIMEDKLINES static time_t lkill = 0; #endif Reg aClient *cptr; Reg int kflag = 0; aClient *bysptr = NULL; int ping = 0, i; time_t oldest = 0, timeout; char *reason = NULL; for (i = highest_fd; i >= 0; i--) { if (!(cptr = local[i]) || IsListener(cptr)) continue; #ifdef TIMEDKLINES kflag = 0; reason = NULL; /* ** Once per TIMEDKLINES seconds. ** (1 minute is minimum resolution in K-line field) */ if ((currenttime - lkill > TIMEDKLINES) && IsPerson(cptr) && !IsKlineExempt(cptr)) { kflag = find_kill(cptr, 1, &reason); } #endif ping = IsRegistered(cptr) ? cptr->ping : ACCEPTTIMEOUT; Debug((DEBUG_DEBUG, "c(%s) %d p %d k %d a %d", cptr->name, cptr->status, ping, kflag, currenttime - cptr->lasttime)); /* * Ok, so goto's are ugly and can be avoided here but this code * is already indented enough so I think its justified. -avalon */ if (!kflag && IsRegistered(cptr) && (ping >= currenttime - cptr->lasttime)) goto ping_timeout; /* * If the server hasnt talked to us in 2*ping seconds * and it has a ping time, then close its connection. * If the client is a user and a KILL line was found * to be active, close this connection too. */ if (kflag || ((currenttime - cptr->lasttime) >= (2 * ping) && (cptr->flags & FLAGS_PINGSENT)) || (!IsRegistered(cptr) && (currenttime - cptr->firsttime) >= ping)) { if (!IsRegistered(cptr) && (DoingDNS(cptr) || DoingAuth(cptr) || DoingXAuth(cptr))) { if (cptr->authfd >= 0) { (void)close(cptr->authfd); cptr->authfd = -1; cptr->count = 0; *cptr->buffer = '\0'; } Debug((DEBUG_NOTICE, "%s/%c%s timeout %s", (DoingDNS(cptr)) ? "DNS" : "dns", (DoingXAuth(cptr)) ? "X" : "x", (DoingAuth(cptr)) ? "AUTH" : "auth", get_client_name(cptr,TRUE))); del_queries((char *)cptr); ClearAuth(cptr); #if defined(USE_IAUTH) if (DoingDNS(cptr) || DoingXAuth(cptr)) { if (DoingDNS(cptr) && (iauth_options & XOPT_EXTWAIT)) { /* iauth wants more time */ sendto_iauth("%d d", cptr->fd); ClearDNS(cptr); cptr->lasttime = currenttime; continue; } if (DoingXAuth(cptr) && (iauth_options & XOPT_NOTIMEOUT)) { cptr->exitc = EXITC_AUTHTOUT; sendto_iauth("%d T", cptr->fd); exit_client(cptr, cptr, &me, "Authentication Timeout"); continue; } sendto_iauth("%d T", cptr->fd); SetDoneXAuth(cptr); } #endif ClearDNS(cptr); ClearXAuth(cptr); ClearWXAuth(cptr); cptr->firsttime = currenttime; cptr->lasttime = currenttime; continue; } if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr)) { if (cptr->serv && cptr->serv->byuid[0]) { bysptr = find_uid(cptr->serv->byuid, NULL); } /* we are interested only in *remote* opers */ if (bysptr && !MyConnect(bysptr)) { sendto_one(bysptr, ":%s NOTICE %s :" "No response from %s, closing" " link", ME, bysptr->name, get_client_name(cptr, FALSE)); } sendto_flag(SCH_NOTICE, "No response from %s closing link", get_client_name(cptr, FALSE)); } /* * this is used for KILL lines with time restrictions * on them - send a message to the user being killed * first. */ if (kflag && IsPerson(cptr)) { char buf[100]; sendto_flag(SCH_NOTICE, "Kill line active for %s", get_client_name(cptr, FALSE)); cptr->exitc = EXITC_KLINE; if (!BadPtr(reason)) sprintf(buf, "Kill line active: %.80s", reason); (void)exit_client(cptr, cptr, &me, (reason) ? buf : "Kill line active"); } else { cptr->exitc = EXITC_PING; (void)exit_client(cptr, cptr, &me, "Ping timeout"); } continue; } else if (IsRegistered(cptr) && (cptr->flags & FLAGS_PINGSENT) == 0) { /* * if we havent PINGed the connection and we havent * heard from it in a while, PING it to make sure * it is still alive. */ cptr->flags |= FLAGS_PINGSENT; /* not nice but does the job */ cptr->lasttime = currenttime - ping; sendto_one(cptr, "PING :%s", me.name); } ping_timeout: timeout = cptr->lasttime + ping; while (timeout <= currenttime) timeout += ping; if (timeout < oldest || !oldest) oldest = timeout; } #ifdef TIMEDKLINES if (currenttime - lkill > 60) lkill = currenttime; #endif if (!oldest || oldest < currenttime) oldest = currenttime + PINGFREQUENCY; if (oldest < currenttime + 30) oldest += 30; Debug((DEBUG_NOTICE,"Next check_ping() call at: %s, %d %d %d", myctime(oldest), ping, oldest, currenttime)); return (oldest); }
int m_info(aClient *cptr, aClient *sptr, int parc, char *parv[]) { char **text = infotext; static time_t last_used=0L; Info *infoptr; if(IsServer(sptr)) return 0; if (hunt_server(cptr,sptr,":%s INFO :%s",1,parc,parv) == HUNTED_ISME) { sendto_ops_imodes(IMODE_SPY, "info requested by %s (%s@%s) [%s]", sptr->name, sptr->username, sptr->host, sptr->user->server); if (!IsAnOper(sptr)) { /* reject non local requests */ if (!MyConnect(sptr)) return 0; if ((last_used + PACE_WAIT) > CurrentTime) { /* safe enough to give this on a local connect only */ sendto_one(sptr,form_str(RPL_LOAD2HI),me.name,parv[0]); return 0; } else last_used = CurrentTime; } /* if (!IsAnOper(sptr)) */ while (*text) sendto_one(sptr, form_str(RPL_INFO), me.name, parv[0], *text++); /* * Now send them a list of all our configuration options * (mostly from config.h) */ if (IsAnOper(sptr)) { sendto_one(sptr, form_str(RPL_INFO), me.name, parv[0], "Compile-time configuration options:"); for (infoptr = MyInformation; infoptr->name; infoptr++) { if (infoptr->intvalue) sendto_one(sptr, ":%s %d %s :%-30s %-5d [%-30s]", me.name, RPL_INFO, parv[0], infoptr->name, infoptr->intvalue, infoptr->desc); else sendto_one(sptr, ":%s %d %s :%-30s %-5s [%-30s]", me.name, RPL_INFO, parv[0], infoptr->name, infoptr->strvalue, infoptr->desc); } sendto_one(sptr, form_str(RPL_INFO), me.name, parv[0], ""); sendto_one(sptr, ":%s %d %s :Running binary [%s]", me.name, RPL_INFO, parv[0], ircdpath); #ifndef SERVERHIDE sendto_one(sptr, ":%s %d %s :Compiled on [%s]", me.name, RPL_INFO, parv[0], platform); #endif #ifdef HLC sendto_one(sptr, form_str(RPL_INFO), me.name, parv[0], ""); sendto_one(sptr, ":%s NOTICE %s :HLC - Current: %lu, Last received at: %lu, Lag: %lu", me.name, sptr->name, CurrentTime, receivedat, CurrentTime - receivedat); if (CurrentTime - receivedat >= LAGLIMIT) sendto_one(sptr, ":%s NOTICE %s :HLC - Rejecting all client connections", me.name, sptr->name); #endif } /* if (IsAnOper(sptr)) */ sendto_one(sptr, form_str(RPL_INFO), me.name, parv[0], ""); sendto_one(sptr, ":%s %d %s :Birth Date: %s, compile # %s", me.name, RPL_INFO, parv[0], creation, generation); sendto_one(sptr, ":%s %d %s :On-line since %s", me.name, RPL_INFO, parv[0], myctime(me.firsttime)); sendto_one(sptr, form_str(RPL_ENDOFINFO), me.name, parv[0]); } /* if (hunt_server(cptr,sptr,":%s INFO :%s",1,parc,parv) == HUNTED_ISME) */ return 0; } /* m_info() */