static int m_ison(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; char *nick; char *p; char buf[IRCD_BUFSIZE]; int i; memset(buf, 0, sizeof(buf)); for(i = 1; i < parc; i++) { char *cs = LOCAL_COPY(parv[i]); for(nick = rb_strtok_r(cs, " ", &p); nick; nick = rb_strtok_r(NULL, " ", &p)) { target_p = find_named_client(nick); if(target_p != NULL) { rb_strlcat(buf, target_p->name, sizeof(buf)); rb_strlcat(buf, " ", sizeof(buf)); } } } sendto_one_numeric(source_p, s_RPL(RPL_ISON), buf); return 0; }
/* * m_ison added by Darren Reed 13/8/91 to act as an efficent user indicator * with respect to cpu/bandwidth used. Implemented for NOTIFY feature in * clients. Designed to reduce number of whois requests. Can process * nicknames in batches as long as the maximum buffer length. * * format: * ISON :nicklist */ static int m_ison(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; char *nick; char *p; char *current_insert_point, *current_insert_point2; int len; int i; int done = 0; current_insert_point2 = buf2; *buf2 = '\0'; rb_sprintf(buf, form_str(RPL_ISON), me.name, source_p->name); len = strlen(buf); current_insert_point = buf + len; /* rfc1489 is ambigious about how to handle ISON * this should handle both interpretations. */ for(i = 1; i < parc; i++) { char *cs = LOCAL_COPY(parv[i]); for(nick = rb_strtok_r(cs, " ", &p); nick; nick = rb_strtok_r(NULL, " ", &p)) { target_p = find_named_client(nick); if(target_p != NULL) { len = strlen(target_p->name); if((current_insert_point + (len + 5)) < (buf + sizeof(buf))) { memcpy(current_insert_point, target_p->name, len); current_insert_point += len; *current_insert_point++ = ' '; } else { done = 1; break; } } } if(done) break; } /* current_insert_point--; * Do NOT take out the trailing space, it breaks ircII * --Rodder */ *current_insert_point = '\0'; *current_insert_point2 = '\0'; sendto_one_buffer(source_p, buf); return 0; }
static int sasl_visible(struct Client *client_p) { struct Client *agent_p = NULL; if (ConfigFileEntry.sasl_service) agent_p = find_named_client(ConfigFileEntry.sasl_service); return agent_p != NULL && IsService(agent_p); }
static int m_authenticate(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *agent_p = NULL; struct Client *saslserv_p = NULL; /* They really should use CAP for their own sake. */ if(!IsCapable(source_p, CLICAP_SASL)) return 0; if (strlen(client_p->id) == 3) { exit_client(client_p, client_p, client_p, "Mixing client and server protocol"); return 0; } saslserv_p = find_named_client(ConfigFileEntry.sasl_service); if (saslserv_p == NULL || !IsService(saslserv_p)) { sendto_one(source_p, form_str(ERR_SASLABORTED), me.name, EmptyString(source_p->name) ? "*" : source_p->name); return 0; } if(source_p->localClient->sasl_complete) { *source_p->localClient->sasl_agent = '\0'; source_p->localClient->sasl_complete = 0; } if(strlen(parv[1]) > 400) { sendto_one(source_p, form_str(ERR_SASLTOOLONG), me.name, EmptyString(source_p->name) ? "*" : source_p->name); return 0; } if(!*source_p->id) { /* Allocate a UID. */ strcpy(source_p->id, generate_uid()); add_to_id_hash(source_p->id, source_p); } if(*source_p->localClient->sasl_agent) agent_p = find_id(source_p->localClient->sasl_agent); if(agent_p == NULL) { sendto_one(saslserv_p, ":%s ENCAP %s SASL %s %s H %s %s", me.id, saslserv_p->servptr->name, source_p->id, saslserv_p->id, source_p->host, source_p->sockhost); if (source_p->certfp != NULL) sendto_one(saslserv_p, ":%s ENCAP %s SASL %s %s S %s %s", me.id, saslserv_p->servptr->name, source_p->id, saslserv_p->id, parv[1], source_p->certfp); else sendto_one(saslserv_p, ":%s ENCAP %s SASL %s %s S %s", me.id, saslserv_p->servptr->name, source_p->id, saslserv_p->id, parv[1]); rb_strlcpy(source_p->localClient->sasl_agent, saslserv_p->id, IDLEN); } else sendto_one(agent_p, ":%s ENCAP %s SASL %s %s C %s", me.id, agent_p->servptr->name, source_p->id, agent_p->id, parv[1]); source_p->localClient->sasl_out++; return 0; }
static int ms_signon(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Client *target_p; int newts, sameuser; char login[NICKLEN+1]; if(!clean_nick(parv[1])) { ServerStats.is_kill++; sendto_realops_snomask(SNO_DEBUG, L_ALL, "Bad Nick from SIGNON: %s From: %s(via %s)", parv[1], source_p->servptr->name, client_p->name); /* if source_p has an id, kill_client_serv_butone() will * send a kill to client_p, otherwise do it here */ if (!has_id(source_p)) sendto_one(client_p, ":%s KILL %s :%s (Bad nickname from SIGNON)", get_id(&me, client_p), parv[1], me.name); kill_client_serv_butone(client_p, source_p, "%s (Bad nickname from SIGNON)", me.name); source_p->flags |= FLAGS_KILLED; exit_client(NULL, source_p, &me, "Bad nickname from SIGNON"); return 0; } if(!clean_username(parv[2]) || !clean_host(parv[3])) { ServerStats.is_kill++; sendto_realops_snomask(SNO_DEBUG, L_ALL, "Bad user@host from SIGNON: %s@%s From: %s(via %s)", parv[2], parv[3], source_p->servptr->name, client_p->name); /* if source_p has an id, kill_client_serv_butone() will * send a kill to client_p, otherwise do it here */ if (!has_id(source_p)) sendto_one(client_p, ":%s KILL %s :%s (Bad user@host from SIGNON)", get_id(&me, client_p), parv[1], me.name); kill_client_serv_butone(client_p, source_p, "%s (Bad user@host from SIGNON)", me.name); source_p->flags |= FLAGS_KILLED; exit_client(NULL, source_p, &me, "Bad user@host from SIGNON"); return 0; } newts = atol(parv[4]); if(!strcmp(parv[5], "0")) login[0] = '\0'; else if(*parv[5] != '*') { if (clean_nick(parv[5])) rb_strlcpy(login, parv[5], NICKLEN + 1); else return 0; } target_p = find_named_client(parv[1]); if(target_p != NULL && target_p != source_p) { /* In case of collision, follow NICK rules. */ /* XXX this is duplicated code and does not do SAVE */ if(IsUnknown(target_p)) exit_client(NULL, target_p, &me, "Overridden"); else { if(!newts || !target_p->tsinfo || (newts == target_p->tsinfo) || !source_p->user) { sendto_realops_snomask(SNO_GENERAL, L_ALL, "Nick change collision from SIGNON from %s to %s(%s <- %s)(both killed)", source_p->name, target_p->name, target_p->from->name, client_p->name); ServerStats.is_kill++; sendto_one_numeric(target_p, ERR_NICKCOLLISION, form_str(ERR_NICKCOLLISION), target_p->name); kill_client_serv_butone(NULL, source_p, "%s (Nick change collision)", me.name); ServerStats.is_kill++; kill_client_serv_butone(NULL, target_p, "%s (Nick change collision)", me.name); target_p->flags |= FLAGS_KILLED; exit_client(NULL, target_p, &me, "Nick collision(new)"); source_p->flags |= FLAGS_KILLED; exit_client(client_p, source_p, &me, "Nick collision(old)"); return 0; } else { sameuser = !irccmp(target_p->username, source_p->username) && !irccmp(target_p->host, source_p->host); if((sameuser && newts < target_p->tsinfo) || (!sameuser && newts > target_p->tsinfo)) { if(sameuser) sendto_realops_snomask(SNO_GENERAL, L_ALL, "Nick change collision from SIGNON from %s to %s(%s <- %s)(older killed)", source_p->name, target_p->name, target_p->from->name, client_p->name); else sendto_realops_snomask(SNO_GENERAL, L_ALL, "Nick change collision from SIGNON from %s to %s(%s <- %s)(newer killed)", source_p->name, target_p->name, target_p->from->name, client_p->name); ServerStats.is_kill++; sendto_one_numeric(target_p, ERR_NICKCOLLISION, form_str(ERR_NICKCOLLISION), target_p->name); /* kill the client issuing the nickchange */ kill_client_serv_butone(client_p, source_p, "%s (Nick change collision)", me.name); source_p->flags |= FLAGS_KILLED; if(sameuser) exit_client(client_p, source_p, &me, "Nick collision(old)"); else exit_client(client_p, source_p, &me, "Nick collision(new)"); return 0; } else { if(sameuser) sendto_realops_snomask(SNO_GENERAL, L_ALL, "Nick collision from SIGNON on %s(%s <- %s)(older killed)", target_p->name, target_p->from->name, client_p->name); else sendto_realops_snomask(SNO_GENERAL, L_ALL, "Nick collision from SIGNON on %s(%s <- %s)(newer killed)", target_p->name, target_p->from->name, client_p->name); sendto_one_numeric(target_p, ERR_NICKCOLLISION, form_str(ERR_NICKCOLLISION), target_p->name); /* kill the client who existed before hand */ kill_client_serv_butone(client_p, target_p, "%s (Nick collision)", me.name); ServerStats.is_kill++; target_p->flags |= FLAGS_KILLED; (void) exit_client(client_p, target_p, &me, "Nick collision"); } } } } send_signon(client_p, source_p, parv[1], parv[2], parv[3], newts, login); return 0; }
static void cap_req(struct Client *source_p, const char *arg) { char buf[BUFSIZE]; char pbuf[2][BUFSIZE]; struct clicap *cap; int buflen, plen; int i = 0; int capadd = 0, capdel = 0; int finished = 0, negate; if(!IsRegistered(source_p)) source_p->flags |= FLAGS_CLICAP; if(EmptyString(arg)) return; buflen = snprintf(buf, sizeof(buf), ":%s CAP %s ACK", me.name, EmptyString(source_p->name) ? "*" : source_p->name); pbuf[0][0] = '\0'; plen = 0; for(cap = clicap_find(arg, &negate, &finished); cap; cap = clicap_find(NULL, &negate, &finished)) { /* filled the first array, but cant send it in case the * request fails. one REQ should never fill more than two * buffers --fl */ if(buflen + plen + cap->namelen + 6 >= BUFSIZE) { pbuf[1][0] = '\0'; plen = 0; i = 1; } if(negate) { if(cap->flags & CLICAP_FLAGS_STICKY) { finished = 0; break; } strcat(pbuf[i], "-"); plen++; capdel |= cap->cap_serv; } else { if(cap->cap_required_serv && !((capadd & cap->cap_required_serv) == cap->cap_required_serv || IsCapable(source_p, cap->cap_required_serv))) { finished = 0; break; } if (cap->cap_serv == CLICAP_SASL) { struct Client *agent_p = NULL; if (!ConfigFileEntry.sasl_service) { finished = 0; break; } agent_p = find_named_client(ConfigFileEntry.sasl_service); if (agent_p == NULL || !IsService(agent_p)) { finished = 0; break; } } capadd |= cap->cap_serv; } if(cap->cap_cli) { strcat(pbuf[i], "~"); plen++; } strcat(pbuf[i], cap->name); if (!finished) { strcat(pbuf[i], " "); plen += (cap->namelen + 1); } } if(!finished) { sendto_one(source_p, ":%s CAP %s NAK :%s", me.name, EmptyString(source_p->name) ? "*" : source_p->name, arg); return; } if(i) { sendto_one(source_p, "%s * :%s", buf, pbuf[0]); sendto_one(source_p, "%s :%s", buf, pbuf[1]); } else sendto_one(source_p, "%s :%s", buf, pbuf[0]); source_p->localClient->caps |= capadd; source_p->localClient->caps &= ~capdel; }
/* clicap_generate() * Generates a list of capabilities. * * Inputs: client to send to, subcmd to send, * flags to match against: 0 to do none, -1 if client has no flags, * int to whether we are doing CAP CLEAR * Outputs: None */ static void clicap_generate(struct Client *source_p, const char *subcmd, int flags, int clear) { char buf[BUFSIZE]; char capbuf[BUFSIZE]; char *p; int buflen = 0; int curlen, mlen; size_t i; mlen = sprintf(buf, ":%s CAP %s %s", me.name, EmptyString(source_p->name) ? "*" : source_p->name, subcmd); p = capbuf; buflen = mlen; /* shortcut, nothing to do */ if(flags == -1) { sendto_one(source_p, "%s :", buf); return; } for(i = 0; i < CLICAP_LIST_LEN; i++) { if(flags) { if(!IsCapable(source_p, clicap_list[i].cap_serv)) continue; /* they are capable of this, check sticky */ else if(clear && clicap_list[i].flags & CLICAP_FLAGS_STICKY) continue; } if (clicap_list[i].cap_serv == CLICAP_SASL) { struct Client *agent_p = NULL; if (!ConfigFileEntry.sasl_service) continue; agent_p = find_named_client(ConfigFileEntry.sasl_service); if (agent_p == NULL || !IsService(agent_p)) continue; } /* \r\n\0, possible "-~=", space, " *" */ if(buflen + clicap_list[i].namelen >= BUFSIZE - 10) { /* remove our trailing space -- if buflen == mlen * here, we didnt even succeed in adding one. */ if(buflen != mlen) *(p - 1) = '\0'; else *p = '\0'; sendto_one(source_p, "%s * :%s", buf, capbuf); p = capbuf; buflen = mlen; } if(clear) { *p++ = '-'; buflen++; } curlen = sprintf(p, "%s ", clicap_list[i].name); p += curlen; buflen += curlen; } /* remove trailing space */ if(buflen != mlen) *(p - 1) = '\0'; else *p = '\0'; sendto_one(source_p, "%s :%s", buf, capbuf); }