static struct ConfItem * find_password_aconf(char *name, struct Client *source_p) { struct ConfItem *aconf; if ((aconf = find_conf_exact(name, source_p->username, source_p->host, CONF_OPERATOR)) != NULL) return (aconf); else if ((aconf = find_conf_exact(name, source_p->username, source_p->localClient->sockhost, CONF_OPERATOR)) != NULL) return (aconf); return (NULL); }
static struct ConfItem * find_password_aconf(char *name, struct Client *source_p) { struct ConfItem *aconf; if(!(aconf = find_conf_exact(name, source_p->username, source_p->host, CONF_OPERATOR)) && !(aconf = find_conf_exact(name, source_p->username, source_p->localClient->sockhost, CONF_OPERATOR))) { return 0; } return (aconf); }
/* * 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; dlink_node *ptr; struct ConfItem *aconf, *oconf; if(!(source_p->user) || !source_p->localClient) return; /* 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]); SendMessageFile(source_p, &ConfigFileEntry.opermotd); return; } if(*parv[1] == '+') { /* Ignore it if we aren't expecting this... -A1kmm */ if(!source_p->user->response) return; if(irccmp(source_p->user->response, ++parv[1])) { sendto_one(source_p, form_str(ERR_PASSWDMISMATCH), me.name, source_p->name); log_foper(source_p, source_p->user->auth_oper); if(ConfigFileEntry.failed_oper_notice) sendto_realops_flags(UMODE_ALL, L_ALL, "Failed OPER attempt by %s (%s@%s)", source_p->name, source_p->username, source_p->host); return; } if((aconf = find_conf_by_name(source_p->user->auth_oper, CONF_OPERATOR)) == NULL) { sendto_one(source_p, form_str(ERR_NOOPERHOST), me.name, parv[0]); log_foper(source_p, source_p->user->auth_oper); if(ConfigFileEntry.failed_oper_notice) sendto_realops_flags(UMODE_ALL, L_ALL, "Failed CHALLENGE attempt - host mismatch by %s (%s@%s)", source_p->name, source_p->username, source_p->host); return; } ptr = source_p->localClient->confs.head; oconf = ptr->data; detach_conf(source_p, oconf); if(attach_conf(source_p, aconf) != 0) { sendto_one(source_p, ":%s NOTICE %s :Can't attach conf!", me.name, source_p->name); sendto_realops_flags(UMODE_ALL, L_ALL, "Failed CHALLENGE attempt by %s (%s@%s) can't attach conf!", source_p->name, source_p->username, source_p->host); log_foper(source_p, source_p->user->auth_oper); attach_conf(source_p, oconf); return; } oper_up(source_p, aconf); ilog(L_TRACE, "OPER %s by %s!%s@%s", source_p->user->auth_oper, source_p->name, source_p->username, source_p->host); log_oper(source_p, source_p->user->auth_oper); MyFree(source_p->user->response); MyFree(source_p->user->auth_oper); source_p->user->response = NULL; source_p->user->auth_oper = NULL; return; } MyFree(source_p->user->response); MyFree(source_p->user->auth_oper); source_p->user->response = NULL; source_p->user->auth_oper = NULL; if(!(aconf = find_conf_exact(parv[1], source_p->username, source_p->host, CONF_OPERATOR)) && !(aconf = find_conf_exact(parv[1], source_p->username, source_p->localClient->sockhost, CONF_OPERATOR))) { sendto_one(source_p, form_str(ERR_NOOPERHOST), me.name, parv[0]); log_foper(source_p, parv[1]); if(ConfigFileEntry.failed_oper_notice) sendto_realops_flags(UMODE_ALL, L_ALL, "Failed CHALLENGE attempt - host mismatch by %s (%s@%s)", source_p->name, source_p->username, source_p->host); return; } if(!aconf->rsa_public_key) { 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->user->response), aconf->rsa_public_key)) { sendto_one(source_p, form_str(RPL_RSACHALLENGE), me.name, parv[0], challenge); } DupString(source_p->user->auth_oper, aconf->name); MyFree(challenge); return; }
/* * 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); }
int m_challenge(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { #ifdef USE_SSL struct ConfItem *aconf; RSA *rsa_public_key; BIO *file = NULL; char *challenge = NULL; char *name; char *tmpname; char chan[CHANNELLEN-1]; char* join[2]; int nl; struct Flags old_mode = cli_flags(sptr); if (!MyUser(sptr)) return 0; if (parc < 2) return need_more_params(sptr, "CHALLENGE"); if (parc > 2) { /* This is a remote OPER Request */ struct Client *srv; if (!string_has_wildcards(parv[1])) srv = FindServer(parv[1]); else srv = find_match_server(parv[1]); if (!feature_bool(FEAT_REMOTE_OPER)) return send_reply(sptr, ERR_NOOPERHOST); if (!srv) return send_reply(sptr, ERR_NOOPERHOST); if (IsMe(srv)) { parv[1] = parv[2]; } else { sendcmdto_one(sptr, CMD_CHALLENGE, srv, "%C %s", srv, parv[2]); return 0; } } /* if theyre an oper, reprint oper motd and ignore */ if (IsOper(sptr)) { send_reply(sptr, RPL_YOUREOPER); if (feature_bool(FEAT_OPERMOTD)) m_opermotd(sptr, sptr, 1, parv); } if (*parv[1] == '+') { /* Ignore it if we aren't expecting this... -A1kmm */ if (cli_user(sptr)->response == NULL) return 0; if (ircd_strcmp(cli_user(sptr)->response, ++parv[1])) { send_reply(sptr, ERR_PASSWDMISMATCH); sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (Password Incorrect)", parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr)); tmpname = strdup(cli_user(sptr)->auth_oper); failed_challenge_notice(sptr, tmpname, "challenge failed"); return 0; } name = strdup(cli_user(sptr)->auth_oper); aconf = find_conf_exact(cli_user(sptr)->auth_oper, cli_user(sptr)->realusername, MyUser(sptr) ? cli_sockhost(sptr) : cli_user(sptr)->realhost, CONF_OPS); if (!aconf) aconf = find_conf_exact(cli_user(sptr)->auth_oper, cli_user(sptr)->realusername, ircd_ntoa((const char*) &(cli_ip(sptr))), CONF_OPS); if (!aconf) aconf = find_conf_cidr(cli_user(sptr)->auth_oper, cli_user(sptr)->realusername, cli_ip(sptr), CONF_OPS); if (!aconf) { send_reply(sptr, ERR_NOOPERHOST); sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (No O:line)", parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr)); return 0; } if (CONF_LOCOP == aconf->status) { ClearOper(sptr); SetLocOp(sptr); } else { /* * prevent someone from being both oper and local oper */ ClearLocOp(sptr); if (!feature_bool(FEAT_OPERFLAGS) || !(aconf->port & OFLAG_ADMIN)) { /* Global Oper */ SetOper(sptr); ClearAdmin(sptr); } else { /* Admin */ SetOper(sptr); OSetGlobal(sptr); SetAdmin(sptr); } ++UserStats.opers; } cli_handler(cptr) = OPER_HANDLER; if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_WHOIS)) { OSetWhois(sptr); } if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_IDLE)) { OSetIdle(sptr); } if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_XTRAOP)) { OSetXtraop(sptr); } if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_HIDECHANS)) { OSetHideChans(sptr); } SetFlag(sptr, FLAG_WALLOP); SetFlag(sptr, FLAG_SERVNOTICE); SetFlag(sptr, FLAG_DEBUG); if (!IsAdmin(sptr)) cli_oflags(sptr) = aconf->port; set_snomask(sptr, SNO_OPERDEFAULT, SNO_ADD); client_set_privs(sptr, aconf); cli_max_sendq(sptr) = 0; /* Get the sendq from the oper's class */ send_umode_out(cptr, sptr, &old_mode, HasPriv(sptr, PRIV_PROPAGATE)); send_reply(sptr, RPL_YOUREOPER); if (IsAdmin(sptr)) { sendto_allops(&me, SNO_OLDSNO, "%s (%s@%s) is now an IRC Administrator", parv[0], cli_user(sptr)->username, cli_sockhost(sptr)); /* Autojoin admins to admin channel and oper channel (if enabled) */ if (feature_bool(FEAT_AUTOJOIN_ADMIN)) { if (feature_bool(FEAT_AUTOJOIN_ADMIN_NOTICE)) sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, feature_str(FEAT_AUTOJOIN_ADMIN_NOTICE_VALUE)); ircd_strncpy(chan, feature_str(FEAT_AUTOJOIN_ADMIN_CHANNEL), CHANNELLEN-1); join[0] = cli_name(sptr); join[1] = chan; m_join(sptr, sptr, 2, join); } if (feature_bool(FEAT_AUTOJOIN_OPER) && IsOper(sptr)) { if (feature_bool(FEAT_AUTOJOIN_OPER_NOTICE)) sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, feature_str(FEAT_AUTOJOIN_OPER_NOTICE_VALUE)); ircd_strncpy(chan, feature_str(FEAT_AUTOJOIN_OPER_CHANNEL), CHANNELLEN-1); join[0] = cli_name(sptr); join[1] = chan; m_join(sptr, sptr, 2, join); } } else { sendto_allops(&me, SNO_OLDSNO, "%s (%s@%s) is now an IRC Operator (%c)", parv[0], cli_user(sptr)->username, cli_sockhost(sptr), IsOper(sptr) ? 'O' : 'o'); if (feature_bool(FEAT_AUTOJOIN_OPER) && IsOper(sptr)) { if (feature_bool(FEAT_AUTOJOIN_OPER_NOTICE)) sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, feature_str(FEAT_AUTOJOIN_OPER_NOTICE_VALUE)); ircd_strncpy(chan, feature_str(FEAT_AUTOJOIN_OPER_CHANNEL), CHANNELLEN-1); join[0] = cli_name(sptr); join[1] = chan; m_join(sptr, sptr, 2, join); } } if (feature_bool(FEAT_OPERMOTD)) m_opermotd(sptr, sptr, 1, parv); log_write(LS_OPER, L_INFO, 0, "OPER (%s) by (%#C)", name, sptr); ircd_snprintf(0, cli_user(sptr)->response, BUFSIZE+1, "%s", ""); return 0; } ircd_snprintf(0, cli_user(sptr)->response, BUFSIZE+1, "%s", ""); ircd_snprintf(0, cli_user(sptr)->auth_oper, NICKLEN+1, "%s", ""); aconf = find_conf_exact(parv[1], cli_user(sptr)->realusername, cli_user(sptr)->realhost, CONF_OPS); if (!aconf) aconf = find_conf_exact(parv[1], cli_user(sptr)->realusername, ircd_ntoa((const char*) &(cli_ip(sptr))), CONF_OPS); if (!aconf) aconf = find_conf_cidr(parv[1], cli_user(sptr)->realusername, cli_ip(sptr), CONF_OPS); if (aconf == NULL) { send_reply(sptr, ERR_NOOPERHOST); failed_challenge_notice(sptr, parv[1], "No o:line"); sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (No O:line)", parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr)); return 0; } if (!(aconf->port & OFLAG_RSA)) { send_reply(sptr, RPL_NO_CHALL); return 0; } if (!verify_sslclifp(sptr, aconf)) { sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (SSL Fingerprint Missmatch)", parv[0], cli_user(sptr)->realusername, cli_user(sptr)->realhost); send_reply(sptr, ERR_SSLCLIFP); return 0; } if ((file = BIO_new_file(aconf->passwd, "r")) == NULL) { send_reply(sptr, RPL_NO_KEY); return 0; } rsa_public_key = (RSA *)PEM_read_bio_RSA_PUBKEY(file, NULL, 0, NULL); if (rsa_public_key == NULL) return send_reply(sptr, RPL_INVALID_KEY); if (!generate_challenge(&challenge, rsa_public_key, sptr)) { Debug((DEBUG_DEBUG, "generating challenge sum (%s)", challenge)); send_reply(sptr, RPL_RSACHALLENGE, challenge); ircd_snprintf(0, cli_user(sptr)->auth_oper, NICKLEN + 1, "%s", aconf->name); } nl = BIO_set_close(file, BIO_CLOSE); BIO_free(file); return 1; #else return 1; #endif }
int ms_challenge(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { #ifdef USE_SSL struct ConfItem *aconf; RSA *rsa_public_key; BIO *file = NULL; char *challenge = NULL; char *name; char *tmpname; char chan[CHANNELLEN-1]; char* join[2]; int nl; struct Client *acptr = NULL; char *privbuf; if (!IsServer(cptr)) return 0; /* if theyre an oper, reprint oper motd and ignore */ if (IsOper(sptr)) { send_reply(sptr, RPL_YOUREOPER); if (feature_bool(FEAT_OPERMOTD)) m_opermotd(sptr, sptr, 1, parv); } if (parc < 3) { return send_reply(sptr, ERR_NOOPERHOST); } if (!(acptr = FindNServer(parv[1]))) { return send_reply(sptr, ERR_NOOPERHOST); } else if (!IsMe(acptr)) { sendcmdto_one(sptr, CMD_CHALLENGE, acptr, "%C %s %s", acptr, parv[2], parv[3]); return 0; } if (*parv[2] == '+') { /* Ignore it if we aren't expecting this... -A1kmm */ if (cli_user(sptr)->response == NULL) return 0; if (ircd_strcmp(cli_user(sptr)->response, ++parv[2])) { send_reply(sptr, ERR_PASSWDMISMATCH); sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (Password Incorrect)", parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr)); tmpname = strdup(cli_user(sptr)->auth_oper); failed_challenge_notice(sptr, tmpname, "challenge failed"); return 0; } name = strdup(cli_user(sptr)->auth_oper); aconf = find_conf_exact(cli_user(sptr)->auth_oper, cli_user(sptr)->realusername, MyUser(sptr) ? cli_sockhost(sptr) : cli_user(sptr)->realhost, CONF_OPS); if (!aconf) aconf = find_conf_exact(cli_user(sptr)->auth_oper, cli_user(sptr)->realusername, ircd_ntoa((const char*) &(cli_ip(sptr))), CONF_OPS); if (!aconf) aconf = find_conf_cidr(cli_user(sptr)->auth_oper, cli_user(sptr)->realusername, cli_ip(sptr), CONF_OPS); if (!aconf) { send_reply(sptr, ERR_NOOPERHOST); sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (No O:line)", parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr)); return 0; } if (CONF_LOCOP == aconf->status) { ClearOper(sptr); SetLocOp(sptr); } else { /* This must be called before client_set_privs() */ SetRemoteOper(sptr); if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_WHOIS)) { OSetWhois(sptr); } if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_IDLE)) { OSetIdle(sptr); } if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_XTRAOP)) { OSetXtraop(sptr); } if (!feature_bool(FEAT_OPERFLAGS) || (aconf->port & OFLAG_HIDECHANS)) { OSetHideChans(sptr); } /* prevent someone from being both oper and local oper */ ClearLocOp(sptr); if (!feature_bool(FEAT_OPERFLAGS) || !(aconf->port & OFLAG_ADMIN)) { /* Global Oper */ ClearAdmin(sptr); OSetGlobal(sptr); SetOper(sptr); } else { /* Admin */ OSetGlobal(sptr); OSetAdmin(sptr); SetOper(sptr); SetAdmin(sptr); } /* Tell client_set_privs to send privileges to the user */ client_set_privs(sptr, aconf); ClearOper(sptr); ClearAdmin(sptr); ClearRemoteOper(sptr); privbuf = client_print_privs(sptr); sendcmdto_one(&me, CMD_PRIVS, sptr, "%C %s", sptr, privbuf); } sendcmdto_one(&me, CMD_MODE, sptr, "%s %s", cli_name(sptr), (OIsAdmin(sptr)) ? "+aoiwsg" : "+oiwsg"); send_reply(sptr, RPL_YOUREOPER); if (OIsAdmin(sptr)) { sendto_allops(&me, SNO_OLDSNO, "%s (%s@%s) is now an IRC Administrator", parv[0], cli_user(sptr)->username, cli_sockhost(sptr)); /* Autojoin admins to admin channel and oper channel (if enabled) */ if (feature_bool(FEAT_AUTOJOIN_ADMIN)) { if (feature_bool(FEAT_AUTOJOIN_ADMIN_NOTICE)) sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, feature_str(FEAT_AUTOJOIN_ADMIN_NOTICE_VALUE)); ircd_strncpy(chan, feature_str(FEAT_AUTOJOIN_ADMIN_CHANNEL), CHANNELLEN-1); join[0] = cli_name(sptr); join[1] = chan; m_join(sptr, sptr, 2, join); } if (feature_bool(FEAT_AUTOJOIN_OPER) && OIsGlobal(sptr)) { if (feature_bool(FEAT_AUTOJOIN_OPER_NOTICE)) sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, feature_str(FEAT_AUTOJOIN_OPER_NOTICE_VALUE)); ircd_strncpy(chan, feature_str(FEAT_AUTOJOIN_OPER_CHANNEL), CHANNELLEN-1); join[0] = cli_name(sptr); join[1] = chan; m_join(sptr, sptr, 2, join); } } else { sendto_allops(&me, SNO_OLDSNO, "%s (%s@%s) is now an IRC Operator (%c)", parv[0], cli_user(sptr)->username, cli_sockhost(sptr), OIsGlobal(sptr) ? 'O' : 'o'); if (feature_bool(FEAT_AUTOJOIN_OPER) && OIsGlobal(sptr)) { if (feature_bool(FEAT_AUTOJOIN_OPER_NOTICE)) sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, feature_str(FEAT_AUTOJOIN_OPER_NOTICE_VALUE)); ircd_strncpy(chan, feature_str(FEAT_AUTOJOIN_OPER_CHANNEL), CHANNELLEN-1); join[0] = cli_name(sptr); join[1] = chan; m_join(sptr, sptr, 2, join); } } if (feature_bool(FEAT_OPERMOTD)) m_opermotd(sptr, sptr, 1, parv); log_write(LS_OPER, L_INFO, 0, "OPER (%s) by (%#C)", name, sptr); ircd_snprintf(0, cli_user(sptr)->response, BUFSIZE+1, "%s", ""); return 0; } ircd_snprintf(0, cli_user(sptr)->response, BUFSIZE+1, "%s", ""); ircd_snprintf(0, cli_user(sptr)->auth_oper, NICKLEN+1, "%s", ""); aconf = find_conf_exact(parv[2], cli_user(sptr)->realusername, cli_user(sptr)->realhost, CONF_OPS); if (!aconf) aconf = find_conf_exact(parv[2], cli_user(sptr)->realusername, ircd_ntoa((const char*) &(cli_ip(sptr))), CONF_OPS); if (!aconf) aconf = find_conf_cidr(parv[2], cli_user(sptr)->realusername, cli_ip(sptr), CONF_OPS); if (aconf == NULL) { send_reply(sptr, ERR_NOOPERHOST); failed_challenge_notice(sptr, parv[2], "No o:line"); sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (No O:line)", parv[0], cli_user(sptr)->realusername, cli_sockhost(sptr)); return 0; } if (!(aconf->port & OFLAG_REMOTE)) { send_reply(sptr, ERR_NOOPERHOST); sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (Remote Oper)", parv[0], cli_user(sptr)->realusername, cli_user(sptr)->realhost); return 0; } if (!(aconf->port & OFLAG_RSA)) { send_reply(sptr, RPL_NO_CHALL); return 0; } if (!verify_sslclifp(sptr, aconf)) { sendto_allops(&me, SNO_OLDREALOP, "Failed OPER attempt by %s (%s@%s) (SSL Fingerprint Missmatch)", parv[0], cli_user(sptr)->realusername, cli_user(sptr)->realhost); send_reply(sptr, ERR_SSLCLIFP); return 0; } if ((file = BIO_new_file(aconf->passwd, "r")) == NULL) { send_reply(sptr, RPL_NO_KEY); return 0; } rsa_public_key = (RSA *)PEM_read_bio_RSA_PUBKEY(file, NULL, 0, NULL); if (rsa_public_key == NULL) return send_reply(sptr, RPL_INVALID_KEY); if (!generate_challenge(&challenge, rsa_public_key, sptr)) { Debug((DEBUG_DEBUG, "generating challenge sum (%s)", challenge)); send_reply(sptr, RPL_RSACHALLENGE, challenge); ircd_snprintf(0, cli_user(sptr)->auth_oper, NICKLEN + 1, "%s", aconf->name); } nl = BIO_set_close(file, BIO_CLOSE); BIO_free(file); return 1; #else return 1; #endif }
/* * m_oper - generic message handler */ int m_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct ConfItem* aconf; char* name; char* password; assert(0 != cptr); assert(cptr == sptr); name = parc > 1 ? parv[1] : 0; password = parc > 2 ? parv[2] : 0; if (EmptyString(name) || EmptyString(password)) return need_more_params(sptr, "OPER"); aconf = find_conf_exact(name, sptr, CONF_OPERATOR); if (!aconf || IsIllegal(aconf)) { send_reply(sptr, ERR_NOOPERHOST); sendto_opmask_butone(0, SNO_OLDREALOP, "Failed staff authentication attempt by %s (%s@%s)", parv[0], cli_user(sptr)->username, cli_sockhost(sptr)); return 0; } assert(0 != (aconf->status & CONF_OPERATOR)); if (oper_password_match(password, aconf->passwd)) { struct Flags old_mode = cli_flags(sptr); if (ACR_OK != attach_conf(sptr, aconf)) { send_reply(sptr, ERR_NOOPERHOST); sendto_opmask_butone(0, SNO_OLDREALOP, "Failed staff authentication attempt by %s " "(%s@%s)", parv[0], cli_user(sptr)->username, cli_sockhost(sptr)); return 0; } SetLocOp(sptr); client_set_privs(sptr, aconf); if (HasPriv(sptr, PRIV_PROPAGATE)) { ClearLocOp(sptr); SetOper(sptr); ++UserStats.opers; } cli_handler(cptr) = OPER_HANDLER; SetFlag(sptr, FLAG_WALLOP); SetFlag(sptr, FLAG_SERVNOTICE); SetFlag(sptr, FLAG_DEBUG); set_snomask(sptr, SNO_OPERDEFAULT, SNO_ADD); cli_max_sendq(sptr) = 0; /* Get the sendq from the oper's class */ send_umode_out(cptr, sptr, &old_mode, HasPriv(sptr, PRIV_PROPAGATE)); send_reply(sptr, RPL_YOUREOPER); sendto_opmask_butone(0, SNO_OLDSNO, "%s (%s@%s) has authenticated as staff", parv[0], cli_user(sptr)->username, cli_sockhost(sptr)); log_write(LS_OPER, L_INFO, 0, "OPER (%s) by (%#C)", name, sptr); } else { send_reply(sptr, ERR_PASSWDMISMATCH); sendto_opmask_butone(0, SNO_OLDREALOP, "Failed staff authentication attempt by %s (%s@%s)", parv[0], cli_user(sptr)->username, cli_sockhost(sptr)); } return 0; }
/* * 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 */ }
/** Attempt to send a sequence of bytes to the connection. * As a side effect, updates \a cptr's FLAG_BLOCKED setting * and sendB/sendK fields. * @param cptr Client that should receive data. * @param buf Message buffer to send to client. * @return Negative on connection-fatal error; otherwise * number of bytes sent. */ unsigned int deliver_it(struct Client *cptr, struct MsgQ *buf) { unsigned int bytes_written = 0; unsigned int bytes_count = 0; assert(0 != cptr); #if defined(USE_SSL) switch (client_sendv(cptr, buf, &bytes_count, &bytes_written)) { #else switch (os_sendv_nonb(cli_fd(cptr), buf, &bytes_count, &bytes_written)) { #endif case IO_SUCCESS: ClrFlag(cptr, FLAG_BLOCKED); cli_sendB(cptr) += bytes_written; cli_sendB(&me) += bytes_written; /* A partial write implies that future writes will block. */ if (bytes_written < bytes_count) SetFlag(cptr, FLAG_BLOCKED); break; case IO_BLOCKED: SetFlag(cptr, FLAG_BLOCKED); break; case IO_FAILURE: cli_error(cptr) = errno; SetFlag(cptr, FLAG_DEADSOCKET); break; } return bytes_written; } /** Complete non-blocking connect()-sequence. Check access and * terminate connection, if trouble detected. * @param cptr Client to which we have connected, with all ConfItem structs attached. * @return Zero on failure (caller should exit_client()), non-zero on success. */ static int completed_connection(struct Client* cptr) { struct ConfItem *aconf; time_t newts; struct Client *acptr; int i; #if defined(USE_SSL) char *sslfp; int r; #endif assert(0 != cptr); /* * get the socket status from the fd first to check if * connection actually succeeded */ if ((cli_error(cptr) = os_get_sockerr(cli_fd(cptr)))) { const char* msg = strerror(cli_error(cptr)); if (!msg) msg = "Unknown error"; sendto_opmask(0, SNO_OLDSNO, "Connection failed to %s: %s", cli_name(cptr), msg); return 0; } if (!(aconf = find_conf_byname(cli_confs(cptr), cli_name(cptr), CONF_SERVER))) { sendto_opmask(0, SNO_OLDSNO, "Lost Server Line for %s", cli_name(cptr)); return 0; } #if defined(USE_SSL) if (aconf->flags & CONF_SSL) { r = ssl_connect(&(cli_socket(cptr))); if (r == -1) { sendto_opmask(0, SNO_OLDSNO, "Connection failed to %s: SSL error", cli_name(cptr)); return 0; } else if (r == 0) return 1; sslfp = ssl_get_fingerprint(cli_socket(cptr).s_ssl); if (sslfp) ircd_strncpy(cli_sslclifp(cptr), sslfp, BUFSIZE+1); SetSSL(cptr); } #endif if (s_state(&(cli_socket(cptr))) == SS_CONNECTING) socket_state(&(cli_socket(cptr)), SS_CONNECTED); if (!EmptyString(aconf->passwd)) sendrawto_one(cptr, MSG_PASS " :%s", aconf->passwd); /* * Create a unique timestamp */ newts = TStime(); for (i = HighestFd; i > -1; --i) { if ((acptr = LocalClientArray[i]) && (IsServer(acptr) || IsHandshake(acptr))) { if (cli_serv(acptr)->timestamp >= newts) newts = cli_serv(acptr)->timestamp + 1; } } assert(0 != cli_serv(cptr)); cli_serv(cptr)->timestamp = newts; SetHandshake(cptr); /* * Make us timeout after twice the timeout for DNS look ups */ cli_lasttime(cptr) = CurrentTime; ClearPingSent(cptr); /* TODO: NEGOCIACION envia_config_req(cptr); */ sendrawto_one(cptr, MSG_SERVER " %s 1 %Tu %Tu J%s %s%s +%s6 :%s", cli_name(&me), cli_serv(&me)->timestamp, newts, MAJOR_PROTOCOL, NumServCap(&me), feature_bool(FEAT_HUB) ? "h" : "", cli_info(&me)); #if defined(DDB) ddb_burst(cptr); #endif return (IsDead(cptr)) ? 0 : 1; } /** Close the physical connection. Side effects: MyConnect(cptr) * becomes false and cptr->from becomes NULL. * @param cptr Client to disconnect. */ void close_connection(struct Client *cptr) { struct ConfItem* aconf; if (IsServer(cptr)) { ServerStats->is_sv++; ServerStats->is_sbs += cli_sendB(cptr); ServerStats->is_sbr += cli_receiveB(cptr); ServerStats->is_sti += CurrentTime - cli_firsttime(cptr); /* * If the connection has been up for a long amount of time, schedule * a 'quick' reconnect, else reset the next-connect cycle. */ if ((aconf = find_conf_exact(cli_name(cptr), cptr, CONF_SERVER))) { /* * 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->hold = CurrentTime; aconf->hold += ((aconf->hold - cli_since(cptr) > feature_int(FEAT_HANGONGOODLINK)) ? feature_int(FEAT_HANGONRETRYDELAY) : ConfConFreq(aconf)); /* if (nextconnect > aconf->hold) */ /* nextconnect = aconf->hold; */ } } else if (IsUser(cptr)) { ServerStats->is_cl++; ServerStats->is_cbs += cli_sendB(cptr); ServerStats->is_cbr += cli_receiveB(cptr); ServerStats->is_cti += CurrentTime - cli_firsttime(cptr); } else ServerStats->is_ni++; #if defined(USE_ZLIB) /* * Siempre es una conexion nuestra */ if (cli_connect(cptr)->zlib_negociation & ZLIB_IN) { inflateEnd(cli_connect(cptr)->comp_in); MyFree(cli_connect(cptr)->comp_in); } if (cli_connect(cptr)->zlib_negociation & ZLIB_OUT) { deflateEnd(cli_connect(cptr)->comp_out); MyFree(cli_connect(cptr)->comp_out); } #endif if (-1 < cli_fd(cptr)) { flush_connections(cptr); LocalClientArray[cli_fd(cptr)] = 0; close(cli_fd(cptr)); socket_del(&(cli_socket(cptr))); /* queue a socket delete */ cli_fd(cptr) = -1; cli_freeflag(cptr) &= ~FREEFLAG_SOCKET; } SetFlag(cptr, FLAG_DEADSOCKET); MsgQClear(&(cli_sendQ(cptr))); client_drop_sendq(cli_connect(cptr)); DBufClear(&(cli_recvQ(cptr))); memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr))); set_snomask(cptr, 0, SNO_SET); det_confs_butmask(cptr, 0); if (cli_listener(cptr)) { release_listener(cli_listener(cptr)); cli_listener(cptr) = 0; } for ( ; HighestFd > 0; --HighestFd) { if (LocalClientArray[HighestFd]) break; } } /** Close all unregistered connections. * @param source Oper who requested the close. * @return Number of closed connections. */ int net_close_unregistered_connections(struct Client* source) { int i; struct Client* cptr; int count = 0; assert(0 != source); for (i = HighestFd; i > 0; --i) { if ((cptr = LocalClientArray[i]) && !IsRegistered(cptr)) { send_reply(source, RPL_CLOSING, get_client_name(source, HIDE_IP)); exit_client(source, cptr, &me, "Oper Closing"); ++count; } } return count; }
int can_oper(struct Client *cptr, struct Client *sptr, char *name, char *password, struct ConfItem **_aconf) { struct ConfItem *aconf; aconf = find_conf_exact(name, sptr, CONF_OPERATOR); if (!aconf || IsIllegal(aconf)) { send_reply(sptr, ERR_NOOPERHOST); sendto_opmask_butone_global(&me, SNO_OLDREALOP, "Failed %sOPER attempt by %s (%s@%s) " "(no operator block)", (!MyUser(sptr) ? "remote " : ""), cli_name(sptr), cli_user(sptr)->username, cli_user(sptr)->realhost); return 0; } assert(0 != (aconf->status & CONF_OPERATOR)); if (!MyUser(sptr)) { if (FlagHas(&aconf->privs, PRIV_REMOTE)) { } else if (aconf->conn_class && FlagHas(&aconf->conn_class->privs, PRIV_REMOTE)) { } else { send_reply(sptr, ERR_NOOPERHOST); sendto_opmask_butone_global(&me, SNO_OLDREALOP, "Failed %sOPER attempt by %s (%s@%s) " "(no remote oper priv)", (!MyUser(sptr) ? "remote " : ""), cli_name(sptr), cli_user(sptr)->username, cli_user(sptr)->realhost); return 0; } } if (!verify_sslclifp(sptr, aconf)) { send_reply(sptr, ERR_SSLCLIFP); sendto_opmask_butone_global(&me, SNO_OLDREALOP, "Failed %sOPER attempt by %s " "(%s@%s) (SSL fingerprint mismatch)", (!MyUser(sptr) ? "remote " : ""), cli_name(sptr), cli_user(sptr)->username, cli_user(sptr)->realhost); return 0; } if (oper_password_match(password, aconf->passwd)) { if (MyUser(sptr)) { int attach_result = attach_conf(sptr, aconf); if ((ACR_OK != attach_result) && (ACR_ALREADY_AUTHORIZED != attach_result)) { send_reply(sptr, ERR_NOOPERHOST); sendto_opmask_butone_global(&me, SNO_OLDREALOP, "Failed %sOPER attempt by %s " "(%s@%s) (no operator block)", (!MyUser(sptr) ? "remote " : ""), cli_name(sptr), cli_user(sptr)->username, cli_user(sptr)->realhost); return 0; } } *_aconf = aconf; return -1; } else { send_reply(sptr, ERR_PASSWDMISMATCH); sendto_opmask_butone_global(&me, SNO_OLDREALOP, "Failed %sOPER attempt by %s (%s@%s) " "(password mis-match)", (!MyUser(sptr) ? "remote " : ""), cli_name(sptr), cli_user(sptr)->username, cli_user(sptr)->realhost); return 0; } }
/** Close the physical connection. Side effects: MyConnect(cptr) * becomes false and cptr->from becomes NULL. * @param cptr Client to disconnect. */ void close_connection(struct Client *cptr) { struct ConfItem* aconf; if (IsServer(cptr)) { ServerStats->is_sv++; ServerStats->is_sbs += cli_sendB(cptr); ServerStats->is_sbr += cli_receiveB(cptr); ServerStats->is_sti += CurrentTime - cli_firsttime(cptr); /* * If the connection has been up for a long amount of time, schedule * a 'quick' reconnect, else reset the next-connect cycle. */ if ((aconf = find_conf_exact(cli_name(cptr), cptr, CONF_SERVER))) { /* * 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->hold = CurrentTime; aconf->hold += ((aconf->hold - cli_since(cptr) > feature_int(FEAT_HANGONGOODLINK)) ? feature_int(FEAT_HANGONRETRYDELAY) : ConfConFreq(aconf)); /* if (nextconnect > aconf->hold) */ /* nextconnect = aconf->hold; */ } } else if (IsUser(cptr)) { ServerStats->is_cl++; ServerStats->is_cbs += cli_sendB(cptr); ServerStats->is_cbr += cli_receiveB(cptr); ServerStats->is_cti += CurrentTime - cli_firsttime(cptr); } else ServerStats->is_ni++; if (-1 < cli_fd(cptr)) { flush_connections(cptr); LocalClientArray[cli_fd(cptr)] = 0; close(cli_fd(cptr)); socket_del(&(cli_socket(cptr))); /* queue a socket delete */ cli_fd(cptr) = -1; } SetFlag(cptr, FLAG_DEADSOCKET); MsgQClear(&(cli_sendQ(cptr))); client_drop_sendq(cli_connect(cptr)); DBufClear(&(cli_recvQ(cptr))); memset(cli_passwd(cptr), 0, sizeof(cli_passwd(cptr))); set_snomask(cptr, 0, SNO_SET); det_confs_butmask(cptr, 0); if (cli_listener(cptr)) { release_listener(cli_listener(cptr)); cli_listener(cptr) = 0; } for ( ; HighestFd > 0; --HighestFd) { if (LocalClientArray[HighestFd]) break; } }