/* ** m_oper ** parv[0] = sender prefix ** parv[1] = oper name ** parv[2] = oper password */ static void m_oper(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct ConfItem *conf; struct AccessItem *aconf=NULL; const char *name = parv[1]; const char *password = parv[2]; if (EmptyString(password)) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "OPER"); return; } /* end the grace period */ if (!IsFloodDone(source_p)) flood_endgrace(source_p); if ((conf = find_password_conf(name,source_p)) == NULL) { sendto_one(source_p, form_str(ERR_NOOPERHOST), me.name, source_p->name); conf = find_exact_name_conf(OPER_TYPE, name, NULL, NULL); failed_oper_notice(source_p, name, (conf != NULL) ? "host mismatch" : "no oper {} block"); log_failed_oper(source_p, name); return; } aconf = (struct AccessItem *)map_to_conf(conf); if (match_oper_password(password, aconf)) { if (attach_conf(source_p, conf) != 0) { sendto_one(source_p, ":%s NOTICE %s :Can't attach conf!", me.name, source_p->name); failed_oper_notice(source_p, name, "can't attach conf!"); log_failed_oper(source_p, name); return; } oper_up(source_p); ilog(L_TRACE, "OPER %s by %s!%s@%s", name, source_p->name, source_p->username, source_p->host); log_oper(source_p, name); } else { sendto_one(source_p, form_str(ERR_PASSWDMISMATCH), me.name, parv[0]); failed_oper_notice(source_p, name, "password mismatch"); log_failed_oper(source_p, name); } }
/* * m_challenge - generate RSA challenge for wouldbe oper * parv[0] = sender prefix * parv[1] = operator to challenge for, or +response * */ static void m_challenge(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { char *challenge = NULL; struct ConfItem *conf = NULL; struct AccessItem *aconf = NULL; /* if theyre an oper, reprint oper motd and ignore */ if(IsOper(source_p)) { sendto_one(source_p, form_str(RPL_YOUREOPER), me.name, parv[0]); send_message_file(source_p, &ConfigFileEntry.opermotd); return; } if(*parv[1] == '+') { /* Ignore it if we aren't expecting this... -A1kmm */ if(source_p->localClient->response == NULL) return; if(svsnoop) { sendto_one(source_p, ":%s NOTICE %s :*** This server is in NOOP mode, you cannot /oper", me.name, source_p->name); failed_challenge_notice(source_p, source_p->localClient->auth_oper, "This server is in NOOP mode"); log_oper_action(LOG_FAILED_OPER_TYPE, source_p, "%s\n", source_p->localClient->auth_oper); return; } if(irccmp(source_p->localClient->response, ++parv[1])) { sendto_one(source_p, form_str(ERR_PASSWDMISMATCH), me.name, source_p->name); failed_challenge_notice(source_p, source_p->localClient->auth_oper, "challenge failed"); return; } conf = find_exact_name_conf(OPER_TYPE, source_p->localClient->auth_oper, source_p->username, source_p->host); if(conf == NULL) conf = find_exact_name_conf(OPER_TYPE, source_p->localClient->auth_oper, source_p->username, source_p->realhost); if(conf == NULL) conf = find_exact_name_conf(OPER_TYPE, source_p->localClient->auth_oper, source_p->username, source_p->sockhost); if(conf == NULL) { sendto_one(source_p, form_str(ERR_NOOPERHOST), me.name, parv[0]); log_oper_action(LOG_FAILED_OPER_TYPE, source_p, "%s\n", source_p->localClient->auth_oper); return; } if(attach_conf(source_p, conf) != 0) { sendto_one(source_p, ":%s NOTICE %s :Can't attach conf!", me.name, source_p->name); failed_challenge_notice(source_p, conf->name, "can't attach conf!"); log_oper_action(LOG_FAILED_OPER_TYPE, source_p, "%s\n", source_p->localClient->auth_oper); return; } oper_up(source_p); ilog(L_TRACE, "OPER %s by %s!%s@%s", source_p->localClient->auth_oper, source_p->name, source_p->username, source_p->realhost); log_oper_action(LOG_OPER_TYPE, source_p, "%s\n", source_p->localClient->auth_oper); MyFree(source_p->localClient->response); MyFree(source_p->localClient->auth_oper); source_p->localClient->response = NULL; source_p->localClient->auth_oper = NULL; return; } MyFree(source_p->localClient->response); MyFree(source_p->localClient->auth_oper); source_p->localClient->response = NULL; source_p->localClient->auth_oper = NULL; if((conf = find_conf_exact(OPER_TYPE, parv[1], source_p->username, source_p->host)) != NULL) aconf = map_to_conf(conf); else if((conf = find_conf_exact(OPER_TYPE, parv[1], source_p->username, source_p->realhost)) != NULL) aconf = map_to_conf(conf); else if((conf = find_conf_exact(OPER_TYPE, parv[1], source_p->username, source_p->sockhost)) != NULL) aconf = map_to_conf(conf); if(aconf == NULL) { sendto_one(source_p, form_str(ERR_NOOPERHOST), me.name, parv[0]); conf = find_exact_name_conf(OPER_TYPE, parv[1], NULL, NULL); failed_challenge_notice(source_p, parv[1], (conf != NULL) ? "host mismatch" : "no oper {} block"); log_oper_action(LOG_FAILED_OPER_TYPE, source_p, "%s\n", parv[1]); return; } if(aconf->rsa_public_key == NULL) { sendto_one(source_p, ":%s NOTICE %s :I'm sorry, PK authentication " "is not enabled for your oper{} block.", me.name, parv[0]); return; } if(!generate_challenge(&challenge, &(source_p->localClient->response), aconf->rsa_public_key)) sendto_one(source_p, form_str(RPL_RSACHALLENGE), me.name, parv[0], challenge); DupString(source_p->localClient->auth_oper, conf->name); MyFree(challenge); }
/* * ms_connect - CONNECT command handler * * Added by Jto 11 Feb 1989 * * m_connect * parv[0] = sender prefix * parv[1] = servername * parv[2] = port number * parv[3] = remote server */ static void ms_connect(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { int port; int tmpport; struct ConfItem *conf = NULL; struct AccessItem *aconf = NULL; struct Client *target_p; if (hunt_server(client_p, source_p, ":%s CONNECT %s %s :%s", 3, parc, parv) != HUNTED_ISME) return; if (*parv[1] == '\0') { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "CONNECT"); return; } if ((target_p = find_server(parv[1]))) { sendto_one(source_p, ":%s NOTICE %s :Connect: Server %s already exists from %s.", me.name, source_p->name, parv[1], target_p->from->name); return; } /* * try to find the name, then host, if both fail notify ops and bail */ if ((conf = find_matching_name_conf(SERVER_TYPE, parv[1], NULL, NULL, 0)) != NULL) aconf = (struct AccessItem *)map_to_conf(conf); else if ((conf = find_matching_name_conf(SERVER_TYPE, NULL, NULL, parv[1], 0)) != NULL) aconf = (struct AccessItem *)map_to_conf(conf); if (aconf == NULL) { sendto_one(source_p, ":%s NOTICE %s :Connect: Host %s not listed in ircd.conf", me.name, source_p->name, parv[1]); return; } assert(aconf != NULL); /* Get port number from user, if given. If not specified, * use the default form configuration structure. If missing * from there, then use the precompiled default. */ tmpport = port = aconf->port; if (parc > 2 && !EmptyString(parv[2])) { port = atoi(parv[2]); /* if someone sends port 0, and we have a config port.. use it */ if (port == 0 && aconf->port) port = aconf->port; else if (port <= 0) { sendto_one(source_p, ":%s NOTICE %s :Connect: Illegal port number", me.name, source_p->name); return; } } else if (port <= 0 && (port = PORTNUM) <= 0) { sendto_one(source_p, ":%s NOTICE %s :Connect: missing port number", me.name, source_p->name); return; } if (find_servconn_in_progress(conf->name)) { sendto_one(source_p, ":%s NOTICE %s :Connect: a connection to %s " "is already in progress.", me.name, source_p->name, conf->name); return; } /* * Notify all operators about remote connect requests */ sendto_wallops_flags(UMODE_WALLOP, &me, "Remote CONNECT %s %d from %s", parv[1], port, source_p->name); sendto_server(NULL, NULL, NULL, NOCAPS, NOCAPS, NOFLAGS, ":%s WALLOPS :Remote CONNECT %s %d from %s", me.name, parv[1], port, source_p->name); ilog(L_TRACE, "CONNECT From %s : %s %d", source_p->name, parv[1], port); aconf->port = port; /* at this point we should be calling connect_server with a valid * C:line and a valid port in the C:line */ if (serv_connect(aconf, source_p)) sendto_one(source_p, ":%s NOTICE %s :*** Connecting to %s.%d", me.name, source_p->name, conf->name, aconf->port); else sendto_one(source_p, ":%s NOTICE %s :*** Couldn't connect to %s.%d", me.name, source_p->name, conf->name, aconf->port); /* client is either connecting with all the data it needs or has been * destroyed */ aconf->port = tmpport; }
/* * mo_connect - CONNECT command handler * * Added by Jto 11 Feb 1989 * * m_connect * parv[0] = sender prefix * parv[1] = servername * parv[2] = port number * parv[3] = remote server */ static void mo_connect(struct Client* client_p, struct Client* source_p, int parc, char* parv[]) { int port; int tmpport; struct ConfItem *conf = NULL; struct AccessItem *aconf = NULL; struct Client *target_p; /* always privileged with handlers */ if (MyConnect(source_p) && !IsOperRemote(source_p) && parc > 3) { sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "connect"); return; } if (hunt_server(client_p, source_p, ":%s CONNECT %s %s :%s", 3, parc, parv) != HUNTED_ISME) return; if (*parv[1] == '\0') { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "CONNECT"); return; } if ((target_p = find_server(parv[1]))) { sendto_one(source_p, ":%s NOTICE %s :Connect: Server %s already exists from %s.", me.name, source_p->name, parv[1], target_p->from->name); return; } /* * try to find the name, then host, if both fail notify ops and bail */ if ((conf = find_matching_name_conf(SERVER_TYPE, parv[1], NULL, NULL, 0)) != NULL) aconf = (struct AccessItem *)map_to_conf(conf); else if ((conf = find_matching_name_conf(SERVER_TYPE, NULL, NULL, parv[1], 0)) != NULL) aconf = (struct AccessItem *)map_to_conf(conf); if (conf == NULL) { sendto_one(source_p, ":%s NOTICE %s :Connect: Host %s not listed in ircd.conf", me.name, source_p->name, parv[1]); return; } /* Get port number from user, if given. If not specified, * use the default form configuration structure. If missing * from there, then use the precompiled default. */ tmpport = port = aconf->port; if (parc > 2 && !EmptyString(parv[2])) { if ((port = atoi(parv[2])) <= 0) { sendto_one(source_p, ":%s NOTICE %s :Connect: Illegal port number", me.name, source_p->name); return; } } else if (port <= 0 && (port = PORTNUM) <= 0) { sendto_one(source_p, ":%s NOTICE %s :Connect: missing port number", me.name, source_p->name); return; } if (find_servconn_in_progress(conf->name)) { sendto_one(source_p, ":%s NOTICE %s :Connect: a connection to %s " "is already in progress.", me.name, source_p->name, conf->name); return; } /* * Notify all operators about remote connect requests */ ilog(L_TRACE, "CONNECT From %s : %s %s", source_p->name, parv[1], parv[2] ? parv[2] : ""); aconf->port = port; /* at this point we should be calling connect_server with a valid * C:line and a valid port in the C:line */ if (serv_connect(aconf, source_p)) { if (!ConfigServerHide.hide_server_ips && IsAdmin(source_p)) sendto_one(source_p, ":%s NOTICE %s :*** Connecting to %s[%s].%d", me.name, source_p->name, aconf->host, conf->name, aconf->port); else sendto_one(source_p, ":%s NOTICE %s :*** Connecting to %s.%d", me.name, source_p->name, conf->name, aconf->port); } else { sendto_one(source_p, ":%s NOTICE %s :*** Couldn't connect to %s.%d", me.name, source_p->name, conf->name, aconf->port); } /* client is either connecting with all the data it needs or has been * destroyed */ aconf->port = tmpport; }
/* parse_csv_file() * * inputs - FILE pointer * - type of conf to parse * output - none * side effects - */ void parse_csv_file(FBFILE *file, ConfType conf_type) { struct ConfItem *conf; struct AccessItem *aconf; struct MatchItem *match_item; struct MatchItem *nresv; struct ResvChannel *cresv; char *name_field=NULL; char *user_field=NULL; char *reason_field=NULL; char *oper_reason=NULL; char *host_field=NULL; char *duration_field=NULL; char *temp=NULL; char line[IRCD_BUFSIZE]; char *p; while (fbgets(line, sizeof(line), file) != NULL) { duration_field = NULL; if ((p = strchr(line, '\n')) != NULL) *p = '\0'; if ((line[0] == '\0') || (line[0] == '#')) continue; switch(conf_type) { case KLINE_TYPE: parse_csv_line(line, &user_field, &host_field, &reason_field, &oper_reason, &temp, &temp, &temp, &duration_field, NULL); conf = make_conf_item(KLINE_TYPE); aconf = map_to_conf(conf); if (host_field != NULL) DupString(aconf->host, host_field); if (reason_field != NULL) DupString(aconf->reason, reason_field); if (oper_reason != NULL) DupString(aconf->oper_reason, oper_reason); if (user_field != NULL) DupString(aconf->user, user_field); if (duration_field != NULL) aconf->hold = atoi(duration_field); if (aconf->host != NULL) { if(duration_field == NULL) add_conf_by_address(CONF_KILL, aconf); else add_temp_line(conf); } break; case RKLINE_TYPE: { const char *errptr = NULL; pcre *exp_user = NULL, *exp_host = NULL; parse_csv_line(line, &user_field, &host_field, &reason_field, &oper_reason, &temp, &temp, &temp, &duration_field, NULL); if (host_field == NULL || user_field == NULL) break; if (!(exp_user = ircd_pcre_compile(user_field, &errptr)) || !(exp_host = ircd_pcre_compile(host_field, &errptr))) { sendto_realops_flags(UMODE_ALL, L_ALL, "Failed to add regular expression based K-Line: %s", errptr); break; } conf = make_conf_item(RKLINE_TYPE); aconf = map_to_conf(conf); aconf->regexuser = exp_user; aconf->regexhost = exp_host; DupString(aconf->user, user_field); DupString(aconf->host, host_field); if (reason_field != NULL) DupString(aconf->reason, reason_field); else DupString(aconf->reason, "No reason"); if (oper_reason != NULL) DupString(aconf->oper_reason, oper_reason); if(duration_field != NULL) { aconf->hold = atoi(duration_field); add_temp_line(conf); } } break; case DLINE_TYPE: parse_csv_line(line, &host_field, &reason_field, &temp, &temp, &temp, &temp, &duration_field, NULL); conf = make_conf_item(DLINE_TYPE); aconf = (struct AccessItem *)map_to_conf(conf); if (host_field != NULL) DupString(aconf->host, host_field); if (reason_field != NULL) DupString(aconf->reason, reason_field); if(duration_field != NULL) { aconf->hold = atoi(duration_field); add_temp_line(conf); } else conf_add_d_conf(aconf); break; case XLINE_TYPE: parse_csv_line(line, &name_field, &reason_field, &oper_reason, &temp, &temp, &temp, &temp, &duration_field, NULL); conf = make_conf_item(XLINE_TYPE); match_item = (struct MatchItem *)map_to_conf(conf); if (name_field != NULL) DupString(conf->name, name_field); if (reason_field != NULL) DupString(match_item->reason, reason_field); if(duration_field != NULL) { match_item->hold = atoi(duration_field); add_temp_line(conf); } break; case RXLINE_TYPE: { const char *errptr = NULL; pcre *exp_p = NULL; parse_csv_line(line, &name_field, &reason_field, &oper_reason, &temp, &temp, &temp, &temp, &duration_field, NULL); if (name_field == NULL) break; if (!(exp_p = ircd_pcre_compile(name_field, &errptr))) { sendto_realops_flags(UMODE_ALL, L_ALL, "Failed to add regular expression based X-Line: %s", errptr); break; } conf = make_conf_item(RXLINE_TYPE); conf->regexpname = exp_p; match_item = map_to_conf(conf); DupString(conf->name, name_field); if (reason_field != NULL) DupString(match_item->reason, reason_field); else DupString(match_item->reason, "No reason"); if(duration_field != NULL) { match_item->hold = atoi(duration_field); add_temp_line(conf); } } break; case CRESV_TYPE: parse_csv_line(line, &name_field, &reason_field, &duration_field, NULL); conf = create_channel_resv(name_field, reason_field, 0); if(duration_field != NULL) { cresv = map_to_conf(conf); cresv->hold = atoi(duration_field); add_temp_line(conf); } break; case NRESV_TYPE: parse_csv_line(line, &name_field, &reason_field, &duration_field, NULL); conf = create_nick_resv(name_field, reason_field, 0); if(duration_field != NULL) { nresv = map_to_conf(conf); nresv->hold = atoi(duration_field); add_temp_line(conf); } break; case GLINE_TYPE: case GDENY_TYPE: case CONF_TYPE: case OPER_TYPE: case CLIENT_TYPE: case SERVER_TYPE: case CLUSTER_TYPE: case HUB_TYPE: case LEAF_TYPE: case ULINE_TYPE: case EXEMPTDLINE_TYPE: case CLASS_TYPE: break; } } }
/* * close_connection * Close the physical connection. This function must make * MyConnect(client_p) == FALSE, and set client_p->from == NULL. */ void close_connection(struct Client *client_p) { struct ConfItem *conf; struct AccessItem *aconf; struct ClassItem *aclass; assert(NULL != client_p); if (!IsDead(client_p)) { /* attempt to flush any pending dbufs. Evil, but .. -- adrian */ /* there is still a chance that we might send data to this socket * even if it is marked as blocked (COMM_SELECT_READ handler is called * before COMM_SELECT_WRITE). Let's try, nothing to lose.. -adx */ ClearSendqBlocked(client_p); send_queued_write(client_p); } if (IsServer(client_p)) { ++ServerStats.is_sv; ServerStats.is_sbs += client_p->localClient->send.bytes; ServerStats.is_sbr += client_p->localClient->recv.bytes; ServerStats.is_sti += CurrentTime - client_p->firsttime; /* XXX Does this even make any sense at all anymore? * scheduling a 'quick' reconnect could cause a pile of * nick collides under TSora protocol... -db */ /* * If the connection has been up for a long amount of time, schedule * a 'quick' reconnect, else reset the next-connect cycle. */ if ((conf = find_conf_exact(SERVER_TYPE, client_p->name, client_p->username, client_p->host))) { /* * Reschedule a faster reconnect, if this was a automatically * connected configuration entry. (Note that if we have had * a rehash in between, the status has been changed to * CONF_ILLEGAL). But only do this if it was a "good" link. */ aconf = (struct AccessItem *)map_to_conf(conf); aclass = (struct ClassItem *)map_to_conf(aconf->class_ptr); aconf->hold = time(NULL); aconf->hold += (aconf->hold - client_p->since > HANGONGOODLINK) ? HANGONRETRYDELAY : ConFreq(aclass); if (nextconnect > aconf->hold) nextconnect = aconf->hold; } } else if (IsClient(client_p)) { ++ServerStats.is_cl; ServerStats.is_cbs += client_p->localClient->send.bytes; ServerStats.is_cbr += client_p->localClient->recv.bytes; ServerStats.is_cti += CurrentTime - client_p->firsttime; } else ++ServerStats.is_ni; #ifdef HAVE_LIBCRYPTO if (client_p->localClient->fd.ssl) { SSL_set_shutdown(client_p->localClient->fd.ssl, SSL_RECEIVED_SHUTDOWN); if (!SSL_shutdown(client_p->localClient->fd.ssl)) SSL_shutdown(client_p->localClient->fd.ssl); } #endif if (client_p->localClient->fd.flags.open) fd_close(&client_p->localClient->fd); if (HasServlink(client_p)) { if (client_p->localClient->ctrlfd.flags.open) fd_close(&client_p->localClient->ctrlfd); } dbuf_clear(&client_p->localClient->buf_sendq); dbuf_clear(&client_p->localClient->buf_recvq); MyFree(client_p->localClient->passwd); detach_conf(client_p, CONF_TYPE); client_p->from = NULL; /* ...this should catch them! >:) --msa */ }
static void remove_resv(struct Client *source_p, const char *name) { struct ConfItem *conf = NULL; int services = 0; if(IsServices(source_p)) services = 1; if(IsChanPrefix(*name)) { struct ResvChannel *resv_p; if(resv_channel_list.head == NULL || !(resv_p = hash_find_resv(name))) { if(!services) sendto_one(source_p, ":%s NOTICE %s :A RESV does not exist for channel: %s", me.name, source_p->name, name); return; } if(resv_p->conf) { if(!services) sendto_one(source_p, ":%s NOTICE %s :The RESV for channel: %s is in ircd.conf and must be removed by hand.", me.name, source_p->name, name); return; } delete_channel_resv(resv_p); remove_conf_line(CRESV_TYPE, source_p, name, NULL); if(!services) { sendto_one(source_p, ":%s NOTICE %s :The RESV has been removed on channel: %s", me.name, source_p->name, name); sendto_realops_flags(UMODE_ALL, L_ALL, "%s has removed the RESV for channel: %s", get_oper_name(source_p), name); } } else { struct MatchItem *resv_p = NULL; if((conf = find_exact_name_conf(NRESV_TYPE, name, NULL, NULL, NULL)) == NULL) { if(!services) sendto_one(source_p, ":%s NOTICE %s :A RESV does not exist for nick: %s", me.name, source_p->name, name); return; } resv_p = map_to_conf(conf); if(resv_p->action) { if(!services) sendto_one(source_p, ":%s NOTICE %s :The RESV for nick: %s is in ircd.conf and must be removed by hand.", me.name, source_p->name, name); return; } delete_conf_item(conf); remove_conf_line(NRESV_TYPE, source_p, name, NULL); if(!services) { sendto_one(source_p, ":%s NOTICE %s :The RESV has been removed on nick: %s", me.name, source_p->name, name); sendto_realops_flags(UMODE_ALL, L_ALL, "%s has removed the RESV for nick: %s", get_oper_name(source_p), name); } } }
/* write_conf_line() * * inputs - pointer to struct AccessItem * - string current_date (small date) * - time_t cur_time * output - NONE * side effects - This function takes care of * finding right conf file, writing * the right lines to this file, * notifying the oper that their kline/dline etc. is in place * notifying the opers on the server about the k/d etc. line * * - Dianora */ void write_conf_line(struct Client *source_p, struct ConfItem *conf, const char *current_date, time_t cur_time, time_t duration) { FBFILE *out; const char *filename, *from, *to; struct AccessItem *aconf; struct MatchItem *xconf; struct ResvChannel *cresv_p=NULL; struct MatchItem *nresv_p=NULL; ConfType type; type = conf->type; filename = get_conf_name(type); if (!MyConnect(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p)) { from = me.id; to = source_p->id; } else { from = me.name; to = source_p->name; } if ((out = fbopen(filename, "a")) == NULL) { sendto_realops_flags(UMODE_ALL, L_ALL, "*** Problem opening %s ", filename); return; } switch(type) { case KLINE_TYPE: aconf = (struct AccessItem *)map_to_conf(conf); if(duration == 0) { sendto_realops_flags(UMODE_ALL, L_ALL, "%s added K-Line for [%s@%s] [%s]", get_oper_name(source_p), aconf->user, aconf->host, aconf->reason); sendto_one(source_p, ":%s NOTICE %s :Added K-Line [%s@%s]", from, to, aconf->user, aconf->host); ilog(L_TRACE, "%s added K-Line for [%s@%s] [%s]", source_p->name, aconf->user, aconf->host, aconf->reason); log_oper_action(LOG_KLINE_TYPE, source_p, "[%s@%s] [%s]\n", aconf->user, aconf->host, aconf->reason); write_csv_line(out, "%s%s%s%s%s%s%d", aconf->user, aconf->host, aconf->reason, aconf->oper_reason, current_date, get_oper_name(source_p), cur_time); } else { sendto_realops_flags(UMODE_ALL, L_ALL, "%s added temporary %d min. K-Line for [%s@%s] [%s]", get_oper_name(source_p), duration/60, aconf->user, aconf->host, aconf->reason); sendto_one(source_p, ":%s NOTICE %s :Added temporary %d min. K-Line [%s@%s]", from, to, duration/60, aconf->user, aconf->host); ilog(L_TRACE, "%s added temporary %ld min. K-Line for [%s@%s] [%s]", source_p->name, duration/60, aconf->user, aconf->host, aconf->reason); log_oper_action(LOG_TEMP_KLINE_TYPE, source_p, "[%s@%s] [%s]\n", aconf->user, aconf->host, aconf->reason); write_csv_line(out, "%s%s%s%s%s%s%d%d", aconf->user, aconf->host, aconf->reason, aconf->oper_reason, current_date, get_oper_name(source_p), cur_time, aconf->hold); } break; case RKLINE_TYPE: aconf = map_to_conf(conf); if(duration == 0) { sendto_realops_flags(UMODE_ALL, L_ALL, "%s added RK-Line for [%s@%s] [%s]", get_oper_name(source_p), aconf->user, aconf->host, aconf->reason); sendto_one(source_p, ":%s NOTICE %s :Added RK-Line [%s@%s]", from, to, aconf->user, aconf->host); ilog(L_TRACE, "%s added K-Line for [%s@%s] [%s]", source_p->name, aconf->user, aconf->host, aconf->reason); log_oper_action(LOG_RKLINE_TYPE, source_p, "[%s@%s] [%s]\n", aconf->user, aconf->host, aconf->reason); write_csv_line(out, "%s%s%s%s%s%s%d", aconf->user, aconf->host, aconf->reason, aconf->oper_reason, current_date, get_oper_name(source_p), cur_time); } else { sendto_realops_flags(UMODE_ALL, L_ALL, "%s added temporary %d min. RK-Line for [%s@%s] [%s]", get_oper_name(source_p), duration/60, aconf->user, aconf->host, aconf->reason); sendto_one(source_p, ":%s NOTICE %s :Added temporary %d min. RK-Line [%s@%s]", from, to, duration/60, aconf->user, aconf->host); ilog(L_TRACE, "%s added temporary %ld min. RK-Line for [%s@%s] [%s]", source_p->name, duration/60, aconf->user, aconf->host, aconf->reason); log_oper_action(LOG_TEMP_RKLINE_TYPE, source_p, "[%s@%s] [%s]\n", aconf->user, aconf->host, aconf->reason); write_csv_line(out, "%s%s%s%s%s%s%d%d", aconf->user, aconf->host, aconf->reason, aconf->oper_reason, current_date, get_oper_name(source_p), cur_time, aconf->hold); } break; case DLINE_TYPE: aconf = (struct AccessItem *)map_to_conf(conf); if(duration == 0) { sendto_realops_flags(UMODE_ALL, L_ALL, "%s added D-Line for [%s] [%s]", get_oper_name(source_p), aconf->host, aconf->reason); sendto_one(source_p, ":%s NOTICE %s :Added D-Line [%s] to %s", from, to, aconf->host, filename); ilog(L_TRACE, "%s added D-Line for [%s] [%s]", get_oper_name(source_p), aconf->host, aconf->reason); log_oper_action(LOG_DLINE_TYPE, source_p, "[%s] [%s]\n", aconf->host, aconf->reason); write_csv_line(out, "%s%s%s%s%s%d", aconf->host, aconf->reason, aconf->oper_reason, current_date, get_oper_name(source_p), cur_time); } else { sendto_realops_flags(UMODE_ALL, L_ALL, "%s added temporary %d min. D-Line for [%s] [%s]", get_oper_name(source_p), duration/60, aconf->host, aconf->reason); sendto_one(source_p, ":%s NOTICE %s :Added temporary %d min. D-Line [%s]", from, to, duration/60, aconf->host); ilog(L_TRACE, "%s added temporary %d min. D-Line for [%s] [%s]", source_p->name, (int)duration/60, aconf->host, aconf->reason); log_oper_action(LOG_TEMP_DLINE_TYPE, source_p, "[%s@%s] [%s]\n", aconf->user, aconf->host, aconf->reason); write_csv_line(out, "%s%s%s%s%s%d%d", aconf->host, aconf->reason, aconf->oper_reason, current_date, get_oper_name(source_p), cur_time, aconf->hold); } break; case XLINE_TYPE: xconf = (struct MatchItem *)map_to_conf(conf); if(duration == 0) { sendto_realops_flags(UMODE_ALL, L_ALL, "%s added X-Line for [%s] [%s]", get_oper_name(source_p), conf->name, xconf->reason); sendto_one(source_p, ":%s NOTICE %s :Added X-Line [%s] [%d] [%s] to %s", from, to, conf->name, xconf->action, xconf->reason, filename); ilog(L_TRACE, "%s added X-Line for [%s] [%s]", get_oper_name(source_p), conf->name, xconf->reason); write_csv_line(out, "%s%s%s%s%s%d", conf->name, xconf->reason, xconf->oper_reason, current_date, get_oper_name(source_p), cur_time); } else { sendto_realops_flags(UMODE_ALL, L_ALL, "%s added temporary %d min. X-Line for [%s] [%s]", get_oper_name(source_p), (int)duration/60, conf->name, xconf->reason); sendto_one(source_p, ":%s NOTICE %s :Added temporary %d min. X-Line [%s]", MyConnect(source_p) ? me.name : ID_or_name(&me, source_p->from), source_p->name, (int)duration/60, conf->name); ilog(L_TRACE, "%s added temporary %d min. X-Line for [%s] [%s]", source_p->name, (int)duration/60, conf->name, xconf->reason); write_csv_line(out, "%s%s%s%s%s%d%d", conf->name, xconf->reason, xconf->oper_reason, current_date, get_oper_name(source_p), cur_time, xconf->hold); } break; case RXLINE_TYPE: xconf = (struct MatchItem *)map_to_conf(conf); if(duration == 0) { sendto_realops_flags(UMODE_ALL, L_ALL, "%s added RX-Line for [%s] [%s]", get_oper_name(source_p), conf->name, xconf->reason); sendto_one(source_p, ":%s NOTICE %s :Added RX-Line [%s] [%s] to %s", from, to, conf->name, xconf->reason, filename); ilog(L_TRACE, "%s added X-Line for [%s] [%s]", get_oper_name(source_p), conf->name, xconf->reason); write_csv_line(out, "%s%s%s%s%s%d", conf->name, xconf->reason, xconf->oper_reason, current_date, get_oper_name(source_p), cur_time); } else { sendto_realops_flags(UMODE_ALL, L_ALL, "%s added temporary %d min. RX-Line for [%s] [%s]", get_oper_name(source_p), (int)duration/60, conf->name, xconf->reason); sendto_one(source_p, ":%s NOTICE %s :Added temporary %d min. RX-Line [%s]", from, to, (int)duration/60, conf->name); ilog(L_TRACE, "%s added temporary %d min. RX-Line for [%s] [%s]", source_p->name, (int)duration/60, conf->name, xconf->reason); write_csv_line(out, "%s%s%s%s%s%d%d", conf->name, xconf->reason, xconf->oper_reason, current_date, get_oper_name(source_p), cur_time, xconf->hold); } break; case CRESV_TYPE: cresv_p = (struct ResvChannel *)map_to_conf(conf); if(duration == 0) write_csv_line(out, "%s%s", cresv_p->name, cresv_p->reason); else write_csv_line(out, "%s%s%d", cresv_p->name, cresv_p->reason, cresv_p->hold); break; case NRESV_TYPE: nresv_p = (struct MatchItem *)map_to_conf(conf); if(duration == 0) write_csv_line(out, "%s%s", conf->name, nresv_p->reason); else write_csv_line(out, "%s%s%d", conf->name, nresv_p->reason, nresv_p->hold); break; default: fbclose(out); return; } fbclose(out); }
/* parse_resv() * * inputs - source_p, NULL supported * - thing to resv * - time_t if tkline * - reason * outputs - none * side effects - parse resv, create if valid */ static void parse_resv(struct Client *source_p, char *name, int tkline_time, char *reason) { struct ConfItem *conf = NULL; int services = 0; if(IsServices(source_p)) services = 1; if(IsChanPrefix(*name)) { struct ResvChannel *resv_p; if((conf = create_channel_resv(name, reason, 0)) == NULL) { if(!services) sendto_one(source_p, ":%s NOTICE %s :A RESV has already been placed on channel: %s", me.name, source_p->name, name); return; } resv_p = map_to_conf(conf); if(tkline_time != 0) { if(!services) { sendto_one(source_p, ":%s NOTICE %s :A %d minute %s RESV has been placed on channel: %s", me.name, source_p->name, tkline_time / 60, (MyClient(source_p) ? "local" : "remote"), name); sendto_realops_flags(UMODE_ALL, L_ALL, "%s has placed a %d minute %s RESV on channel: %s [%s]", get_oper_name(source_p), tkline_time / 60, (MyClient(source_p) ? "local" : "remote"), resv_p->name, resv_p->reason); } ilog(L_TRACE, "%s added temporary %d min. RESV for [%s] [%s]", source_p->name, (int) tkline_time / 60, conf->name, resv_p->reason); resv_p->hold = CurrentTime + tkline_time; add_temp_line(conf); } else { if(!services) { sendto_one(source_p, ":%s NOTICE %s :A %s RESV has been placed on channel %s", me.name, source_p->name, (MyClient(source_p) ? "local" : "remote"), name); sendto_realops_flags(UMODE_ALL, L_ALL, "%s has placed a %s RESV on channel %s : [%s]", get_oper_name(source_p), (MyClient(source_p) ? "local" : "remote"), resv_p->name, resv_p->reason); } write_conf_line(source_p, conf, NULL /* not used */ , 0 /* not used */ ); } } else { struct MatchItem *resv_p = NULL; if(!valid_wild_card_simple(name) && !IsServices(source_p)) { sendto_one(source_p, ":%s NOTICE %s :Please include at least %d non-wildcard characters with the resv", me.name, source_p->name, ConfigFileEntry.min_nonwildcard_simple); return; } if(!IsAdmin(source_p) && !IsServices(source_p) && strpbrk(name, "*?#")) { sendto_one(source_p, ":%s NOTICE %s :You must be an admin to perform a " "wildcard RESV", me.name, source_p->name); return; } if((conf = create_nick_resv(name, reason, 0)) == NULL) { if(!services) sendto_one(source_p, ":%s NOTICE %s :A RESV has already been placed on nick %s", me.name, source_p->name, name); return; } resv_p = map_to_conf(conf); if(tkline_time != 0) { if(!services) { sendto_one(source_p, ":%s NOTICE %s :A %d minute %s RESV has been placed on nick %s : [%s]", me.name, source_p->name, tkline_time / 60, (MyClient(source_p) ? "local" : "remote"), conf->name, resv_p->reason); sendto_realops_flags(UMODE_ALL, L_ALL, "%s has placed a %d minute %s RESV on nick %s : [%s]", get_oper_name(source_p), tkline_time / 60, (MyClient(source_p) ? "local" : "remote"), conf->name, resv_p->reason); } ilog(L_TRACE, "%s added temporary %d min. RESV for [%s] [%s]", source_p->name, (int) tkline_time / 60, conf->name, resv_p->reason); resv_p->hold = CurrentTime + tkline_time; add_temp_line(conf); } else { if(!services) { sendto_one(source_p, ":%s NOTICE %s :A %s RESV has been placed on nick %s : [%s]", me.name, source_p->name, (MyClient(source_p) ? "local" : "remote"), conf->name, resv_p->reason); sendto_realops_flags(UMODE_ALL, L_ALL, "%s has placed a %s RESV on nick %s : [%s]", get_oper_name(source_p), (MyClient(source_p) ? "local" : "remote"), conf->name, resv_p->reason); } write_conf_line(source_p, conf, NULL /* not used */ , 0 /* not used */ ); } } }
/* * cryptlink_serv - CRYPTLINK SERV message handler * parv[0] == CRYPTLINK * parv[1] == SERV * parv[2] == server name * parv[3] == keyphrase * parv[4] == :server info (M-line) */ static void cryptlink_serv(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { char info[REALLEN + 1]; char *name; struct Client *target_p; char *key = client_p->localClient->out_key; unsigned char *b64_key; struct ConfItem *conf; struct AccessItem *aconf; char *encrypted; const char *p; int enc_len; /* if (client_p->name[0] != 0) return; */ if ((parc < 5) || (*parv[4] == '\0')) { cryptlink_error(client_p, "SERV", "Invalid params", "CRYPTLINK SERV - Invalid params"); return; } if ((name = parse_cryptserv_args(client_p, parv, parc, info, key)) == NULL) { cryptlink_error(client_p, "SERV", "Invalid params", "CRYPTLINK SERV - Invalid params"); return; } /* CRYPTLINK SERV support => TS support */ client_p->tsinfo = TS_DOESTS; if (bogus_host(name)) { exit_client(client_p, client_p, "Bogus server name"); return; } /* Now we just have to call check_server and everything should be * checked for us... -A1kmm. */ switch (check_server(name, client_p, CHECK_SERVER_CRYPTLINK)) { case -1: if (ConfigFileEntry.warn_no_nline) { cryptlink_error(client_p, "SERV", "Unauthorized server connection attempt: No entry for server", NULL); } exit_client(client_p, client_p, "Invalid server name"); return; break; case -2: cryptlink_error(client_p, "SERV", "Unauthorized server connection attempt: CRYPTLINK not " "enabled on remote server", "CRYPTLINK not enabled"); return; break; case -3: cryptlink_error(client_p, "SERV", "Unauthorized server connection attempt: Invalid host", "Invalid host"); return; break; } if ((target_p = find_server(name))) { /* * This link is trying feed me a server that I already have * access through another path -- multiple paths not accepted * currently, kill this link immediately!! * * Rather than KILL the link which introduced it, KILL the * youngest of the two links. -avalon * * Definitely don't do that here. This is from an unregistered * connect - A1kmm. */ cryptlink_error(client_p, "SERV", "Attempt to re-introduce existing server", "Server Exists"); return; } if (ServerInfo.hub && IsCapable(client_p, CAP_LL)) { if (IsCapable(client_p, CAP_HUB)) { ClearCap(client_p,CAP_LL); sendto_realops_flags(UMODE_ALL, L_ALL, "*** LazyLinks to a hub from a hub, that's a no-no."); } else { client_p->localClient->serverMask = nextFreeMask(); if(!client_p->localClient->serverMask) { sendto_realops_flags(UMODE_ALL, L_ALL, "serverMask is full!"); /* try and negotiate a non LL connect */ ClearCap(client_p,CAP_LL); } } } else if (IsCapable(client_p, CAP_LL)) { if (!IsCapable(client_p, CAP_HUB)) { ClearCap(client_p,CAP_LL); sendto_realops_flags(UMODE_ALL, L_ALL, "*** LazyLinks to a leaf from a leaf, that's a no-no."); } } conf = find_conf_name(&client_p->localClient->confs, name, SERVER_TYPE); if (conf == NULL) { cryptlink_error(client_p, "AUTH", "Lost C-line for server", "Lost C-line" ); return; } /* * if we are connecting (Handshake), we already have the name from the * connect {} block in client_p->name */ strlcpy(client_p->name, name, sizeof(client_p->name)); p = info; if (!strncmp(info, "(H)", 3)) { SetHidden(client_p); if ((p = strchr(info, ' ')) != NULL) { p++; if (*p == '\0') p = "(Unknown Location)"; } else p = "(Unknown Location)"; } strlcpy(client_p->info, p, sizeof(client_p->info)); client_p->hopcount = 0; aconf = (struct AccessItem *)map_to_conf(conf); if (!(client_p->localClient->out_cipher || (client_p->localClient->out_cipher = check_cipher(client_p, aconf)))) { cryptlink_error(client_p, "AUTH", "Couldn't find compatible cipher", "Couldn't find compatible cipher"); return; } encrypted = MyMalloc(RSA_size(ServerInfo.rsa_private_key)); enc_len = RSA_public_encrypt(client_p->localClient->out_cipher->keylen, (unsigned char *)key, (unsigned char *)encrypted, aconf->rsa_public_key, RSA_PKCS1_PADDING); if (enc_len <= 0) { report_crypto_errors(); MyFree(encrypted); cryptlink_error(client_p, "AUTH", "Couldn't encrypt data", "Couldn't encrypt data"); return; } base64_block(&b64_key, encrypted, enc_len); MyFree(encrypted); if (!IsWaitAuth(client_p)) { cryptlink_init(client_p, conf, NULL); } sendto_one(client_p, "CRYPTLINK AUTH %s %s", client_p->localClient->out_cipher->name, b64_key); /* needed for old servers that can't shove data back into slink */ send_queued_write(client_p); SetCryptOut(client_p); MyFree(b64_key); }
/* * cryptlink_auth - CRYPTLINK AUTH message handler * parv[1] = secret key */ static void cryptlink_auth(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct EncCapability *ecap; struct ConfItem *conf; struct AccessItem *aconf; int enc_len; int len; unsigned char *enc; unsigned char *key; if (parc < 4) { cryptlink_error(client_p, "AUTH", "Invalid params", "CRYPTLINK AUTH - Invalid params"); return; } if (!IsWaitAuth(client_p)) return; for (ecap = CipherTable; ecap->name; ecap++) { if ((!irccmp(ecap->name, parv[2])) && (IsCapableEnc(client_p, ecap->cap))) { client_p->localClient->in_cipher = ecap; break; } } if (client_p->localClient->in_cipher == NULL) { cryptlink_error(client_p, "AUTH", "Invalid cipher", "Invalid cipher"); return; } if (!(enc_len = unbase64_block(&enc, parv[3], strlen(parv[3])))) { cryptlink_error(client_p, "AUTH", "Could not base64 decode response", "Malformed CRYPTLINK AUTH reply"); return; } if (verify_private_key() == -1) { sendto_realops_flags(UMODE_ALL, L_ADMIN, "verify_private_key() returned -1. Check log for information."); } key = MyMalloc(RSA_size(ServerInfo.rsa_private_key)); len = RSA_private_decrypt(enc_len, (unsigned char *)enc,(unsigned char *)key, ServerInfo.rsa_private_key, RSA_PKCS1_PADDING); if (len < client_p->localClient->in_cipher->keylen) { report_crypto_errors(); if (len < 0) { cryptlink_error(client_p, "AUTH", "Decryption failed", "Malformed CRYPTLINK AUTH reply"); } else { cryptlink_error(client_p, "AUTH", "Not enough random data sent", "Malformed CRYPTLINK AUTH reply"); } MyFree(enc); MyFree(key); return; } if (memcmp(key, client_p->localClient->in_key, client_p->localClient->in_cipher->keylen) != 0) { cryptlink_error(client_p, "AUTH", "Unauthorized server connection attempt", "Malformed CRYPTLINK AUTH reply"); return; } conf = find_conf_name(&client_p->localClient->confs, client_p->name, SERVER_TYPE); if (conf == NULL) { cryptlink_error(client_p, "AUTH", "Lost C-line for server", "Lost C-line"); return; } aconf = (struct AccessItem *)map_to_conf(conf); if (!(client_p->localClient->out_cipher || (client_p->localClient->out_cipher = check_cipher(client_p, aconf)))) { cryptlink_error(client_p, "AUTH", "Couldn't find compatible cipher", "Couldn't find compatible cipher"); return; } /* set hopcount */ client_p->hopcount = 1; SetCryptIn(client_p); ClearWaitAuth(client_p); server_estab(client_p); }
static void remove_resv (struct Client *source_p, char *name, int cluster) { struct ConfItem *conf; if (IsChanPrefix (*name)) { struct ResvChannel *resv_p; if (resv_channel_list.head == NULL || !(resv_p = hash_find_resv (name))) { if (!cluster) sendto_one (source_p, ":%s NOTICE %s :A RESV does not exist for channel: %s", me.name, source_p->name, name); return; } else if (resv_p->conf) { if (!cluster) sendto_one (source_p, ":%s NOTICE %s :The RESV for channel: %s is in ircd.conf and must be removed by hand.", me.name, source_p->name, name); return; } else { delete_channel_resv (resv_p); (void) remove_conf_line (CRESV_TYPE, source_p, name, NULL); if (!cluster) sendto_one (source_p, ":%s NOTICE %s :The RESV has been removed on channel: %s", me.name, source_p->name, name); sendto_realops_flags (UMODE_ALL, L_ALL, "%s has removed the RESV for channel: %s", get_oper_name (source_p), name); } } else if (clean_resv_nick (name)) { struct MatchItem *resv_p; conf = find_matching_name_conf (NRESV_TYPE, name, NULL, NULL, 0); if (conf == NULL) { if (!cluster) sendto_one (source_p, ":%s NOTICE %s :A RESV does not exist for nick: %s", me.name, source_p->name, name); return; } resv_p = (struct MatchItem *) map_to_conf (conf); if (resv_p->action) { if (!cluster) sendto_one (source_p, ":%s NOTICE %s :The RESV for nick: %s is in ircd.conf and must be removed by hand.", me.name, source_p->name, name); return; } else { delete_conf_item (conf); (void) remove_conf_line (NRESV_TYPE, source_p, name, NULL); if (!cluster) sendto_one (source_p, ":%s NOTICE %s :The RESV has been removed on nick: %s", me.name, source_p->name, name); sendto_realops_flags (UMODE_ALL, L_ALL, "%s has removed the RESV for nick: %s", get_oper_name (source_p), name); } } }
/* parse_resv() * * inputs - source_p, NULL supported * - thing to resv * - reason * outputs - none * side effects - parse resv, create if valid */ static void parse_resv (struct Client *source_p, char *name, char *reason, int cluster) { struct ConfItem *conf; if (IsChanPrefix (*name)) { struct ResvChannel *resv_p; if ((conf = create_channel_resv (name, reason, 0)) == NULL) { if (!cluster) sendto_one (source_p, ":%s NOTICE %s :A RESV has already been placed on channel: %s", me.name, source_p->name, name); return; } resv_p = (struct ResvChannel *) map_to_conf (conf); if (!cluster) sendto_one (source_p, ":%s NOTICE %s :A %s RESV has been placed on channel: %s", me.name, source_p->name, (MyClient (source_p) ? "local" : "remote"), name); sendto_realops_flags (UMODE_ALL, L_ALL, "%s has placed a %s RESV on channel: %s [%s]", get_oper_name (source_p), (MyClient (source_p) ? "local" : "remote"), resv_p->name, resv_p->reason); write_conf_line (source_p, conf, NULL /* not used */ , 0 /* not used */ ); } else if (clean_resv_nick (name)) { struct MatchItem *resv_p; if ((strchr (name, '*') || strchr (name, '?')) && !IsAdmin (source_p)) { if (!cluster) sendto_one (source_p, ":%s NOTICE %s :You must be an admin to perform a wildcard RESV", me.name, source_p->name); return; } if ((conf = create_nick_resv (name, reason, 0)) == NULL) { if (!cluster) sendto_one (source_p, ":%s NOTICE %s :A RESV has already been placed on nick: %s", me.name, source_p->name, name); return; } resv_p = (struct MatchItem *) map_to_conf (conf); if (!cluster) sendto_one (source_p, ":%s NOTICE %s :A %s RESV has been placed on nick: %s [%s]", me.name, source_p->name, (MyClient (source_p) ? "local" : "remote"), conf->name, resv_p->reason); sendto_realops_flags (UMODE_ALL, L_ALL, "%s has placed a %s RESV on nick: %s [%s]", get_oper_name (source_p), (MyClient (source_p) ? "local" : "remote"), conf->name, resv_p->reason); write_conf_line (source_p, conf, NULL /* not used */ , 0 /* not used */ ); } else if (!cluster) sendto_one (source_p, ":%s NOTICE %s :You have specified an invalid resv: [%s]", me.name, source_p->name, name); }