| slug@0 | 1 | /*
|
| slug@0 | 2 | * IRC - Internet Relay Chat, ircd/s_user.c (formerly ircd/s_msg.c)
|
| slug@0 | 3 | * Copyright (C) 1990 Jarkko Oikarinen and
|
| slug@0 | 4 | * University of Oulu, Computing Center
|
| slug@0 | 5 | *
|
| slug@0 | 6 | * See file AUTHORS in IRC package for additional names of
|
| slug@0 | 7 | * the programmers.
|
| slug@0 | 8 | *
|
| slug@0 | 9 | * This program is free software; you can redistribute it and/or modify
|
| slug@0 | 10 | * it under the terms of the GNU General Public License as published by
|
| slug@0 | 11 | * the Free Software Foundation; either version 1, or (at your option)
|
| slug@0 | 12 | * any later version.
|
| slug@0 | 13 | *
|
| slug@0 | 14 | * This program is distributed in the hope that it will be useful,
|
| slug@0 | 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| slug@0 | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| slug@0 | 17 | * GNU General Public License for more details.
|
| slug@0 | 18 | *
|
| slug@0 | 19 | * You should have received a copy of the GNU General Public License
|
| slug@0 | 20 | * along with this program; if not, write to the Free Software
|
| slug@0 | 21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
| slug@0 | 22 | */
|
| slug@0 | 23 | /** @file
|
| slug@0 | 24 | * @brief Miscellaneous user-related helper functions.
|
| paul@126 | 25 | * @version $Id: s_user.c,v 1.99.2.11 2007/08/21 01:13:15 entrope Exp $
|
| slug@0 | 26 | */
|
| slug@0 | 27 | #include "config.h"
|
| slug@0 | 28 |
|
| slug@0 | 29 | #include "s_user.h"
|
| slug@0 | 30 | #include "IPcheck.h"
|
| slug@0 | 31 | #include "channel.h"
|
| slug@0 | 32 | #include "class.h"
|
| slug@0 | 33 | #include "client.h"
|
| slug@0 | 34 | #include "hash.h"
|
| slug@0 | 35 | #include "ircd.h"
|
| slug@0 | 36 | #include "ircd_alloc.h"
|
| slug@0 | 37 | #include "ircd_chattr.h"
|
| slug@0 | 38 | #include "ircd_features.h"
|
| slug@0 | 39 | #include "ircd_log.h"
|
| slug@0 | 40 | #include "ircd_reply.h"
|
| slug@0 | 41 | #include "ircd_snprintf.h"
|
| slug@0 | 42 | #include "ircd_string.h"
|
| slug@0 | 43 | #include "list.h"
|
| slug@0 | 44 | #include "match.h"
|
| slug@0 | 45 | #include "motd.h"
|
| slug@0 | 46 | #include "msg.h"
|
| slug@0 | 47 | #include "msgq.h"
|
| slug@0 | 48 | #include "numeric.h"
|
| slug@0 | 49 | #include "numnicks.h"
|
| slug@0 | 50 | #include "parse.h"
|
| slug@0 | 51 | #include "querycmds.h"
|
| slug@0 | 52 | #include "random.h"
|
| paul@33 | 53 | #include "s_auth.h"
|
| slug@0 | 54 | #include "s_bsd.h"
|
| slug@0 | 55 | #include "s_conf.h"
|
| slug@0 | 56 | #include "s_debug.h"
|
| slug@0 | 57 | #include "s_misc.h"
|
| slug@0 | 58 | #include "s_serv.h" /* max_client_count */
|
| slug@0 | 59 | #include "send.h"
|
| slug@0 | 60 | #include "struct.h"
|
| slug@0 | 61 | #include "supported.h"
|
| slug@0 | 62 | #include "sys.h"
|
| slug@0 | 63 | #include "userload.h"
|
| slug@0 | 64 | #include "version.h"
|
| slug@0 | 65 | #include "whowas.h"
|
| slug@0 | 66 |
|
| slug@0 | 67 | #include "handlers.h" /* m_motd and m_lusers */
|
| slug@0 | 68 |
|
| slug@0 | 69 | /* #include <assert.h> -- Now using assert in ircd_log.h */
|
| slug@0 | 70 | #include <fcntl.h>
|
| slug@0 | 71 | #include <stdio.h>
|
| slug@0 | 72 | #include <stdlib.h>
|
| slug@0 | 73 | #include <string.h>
|
| slug@0 | 74 | #include <sys/stat.h>
|
| slug@0 | 75 |
|
| paul@30 | 76 | static char *IsVhost(char *hostmask, int oper);
|
| paul@30 | 77 | static char *IsVhostPass(char *hostmask);
|
| paul@30 | 78 |
|
| slug@0 | 79 | /** Count of allocated User structures. */
|
| slug@0 | 80 | static int userCount = 0;
|
| slug@0 | 81 |
|
| slug@0 | 82 | /** Makes sure that \a cptr has a User information block.
|
| slug@0 | 83 | * If cli_user(cptr) != NULL, does nothing.
|
| slug@0 | 84 | * @param[in] cptr Client to attach User struct to.
|
| slug@0 | 85 | * @return User struct associated with \a cptr.
|
| slug@0 | 86 | */
|
| slug@0 | 87 | struct User *make_user(struct Client *cptr)
|
| slug@0 | 88 | {
|
| slug@0 | 89 | assert(0 != cptr);
|
| slug@0 | 90 |
|
| slug@0 | 91 | if (!cli_user(cptr)) {
|
| slug@0 | 92 | cli_user(cptr) = (struct User*) MyMalloc(sizeof(struct User));
|
| slug@0 | 93 | assert(0 != cli_user(cptr));
|
| slug@0 | 94 |
|
| slug@0 | 95 | /* All variables are 0 by default */
|
| slug@0 | 96 | memset(cli_user(cptr), 0, sizeof(struct User));
|
| slug@0 | 97 | ++userCount;
|
| slug@0 | 98 | cli_user(cptr)->refcnt = 1;
|
| slug@0 | 99 | }
|
| slug@0 | 100 | return cli_user(cptr);
|
| slug@0 | 101 | }
|
| slug@0 | 102 |
|
| slug@0 | 103 | /** Dereference \a user.
|
| slug@0 | 104 | * User structures are reference-counted; if the refcount of \a user
|
| slug@0 | 105 | * becomes zero, free it.
|
| slug@0 | 106 | * @param[in] user User to dereference.
|
| slug@0 | 107 | */
|
| slug@0 | 108 | void free_user(struct User* user)
|
| slug@0 | 109 | {
|
| slug@0 | 110 | assert(0 != user);
|
| slug@0 | 111 | assert(0 < user->refcnt);
|
| slug@0 | 112 |
|
| slug@0 | 113 | if (--user->refcnt == 0) {
|
| slug@0 | 114 | if (user->away)
|
| slug@0 | 115 | MyFree(user->away);
|
| paul@80 | 116 | if (user->opername)
|
| paul@80 | 117 | MyFree(user->opername);
|
| slug@0 | 118 | /*
|
| slug@0 | 119 | * sanity check
|
| slug@0 | 120 | */
|
| slug@0 | 121 | assert(0 == user->joined);
|
| slug@0 | 122 | assert(0 == user->invited);
|
| slug@0 | 123 | assert(0 == user->channel);
|
| slug@0 | 124 |
|
| slug@0 | 125 | MyFree(user);
|
| paul@115 | 126 | assert(userCount>0);
|
| slug@0 | 127 | --userCount;
|
| slug@0 | 128 | }
|
| slug@0 | 129 | }
|
| slug@0 | 130 |
|
| slug@0 | 131 | /** Find number of User structs allocated and memory used by them.
|
| slug@0 | 132 | * @param[out] count_out Receives number of User structs allocated.
|
| slug@0 | 133 | * @param[out] bytes_out Receives number of bytes used by User structs.
|
| slug@0 | 134 | */
|
| slug@0 | 135 | void user_count_memory(size_t* count_out, size_t* bytes_out)
|
| slug@0 | 136 | {
|
| slug@0 | 137 | assert(0 != count_out);
|
| slug@0 | 138 | assert(0 != bytes_out);
|
| slug@0 | 139 | *count_out = userCount;
|
| slug@0 | 140 | *bytes_out = userCount * sizeof(struct User);
|
| slug@0 | 141 | }
|
| slug@0 | 142 |
|
| slug@0 | 143 |
|
| slug@0 | 144 | /** Find the next client (starting at \a next) with a name that matches \a ch.
|
| slug@0 | 145 | * Normal usage loop is:
|
| slug@0 | 146 | * for (x = client; x = next_client(x,mask); x = x->next)
|
| slug@0 | 147 | * HandleMatchingClient;
|
| slug@0 | 148 | *
|
| slug@0 | 149 | * @param[in] next First client to check.
|
| slug@0 | 150 | * @param[in] ch Name mask to check against.
|
| slug@0 | 151 | * @return Next matching client found, or NULL if none.
|
| slug@0 | 152 | */
|
| slug@0 | 153 | struct Client *next_client(struct Client *next, const char* ch)
|
| slug@0 | 154 | {
|
| slug@0 | 155 | struct Client *tmp = next;
|
| slug@0 | 156 |
|
| slug@0 | 157 | if (!tmp)
|
| slug@0 | 158 | return NULL;
|
| slug@0 | 159 |
|
| slug@0 | 160 | next = FindClient(ch);
|
| slug@0 | 161 | next = next ? next : tmp;
|
| slug@0 | 162 | if (cli_prev(tmp) == next)
|
| slug@0 | 163 | return NULL;
|
| slug@0 | 164 | if (next != tmp)
|
| slug@0 | 165 | return next;
|
| slug@0 | 166 | for (; next; next = cli_next(next))
|
| slug@0 | 167 | if (!match(ch, cli_name(next)))
|
| slug@0 | 168 | break;
|
| slug@0 | 169 | return next;
|
| slug@0 | 170 | }
|
| slug@0 | 171 |
|
| slug@0 | 172 | /** Find the destination server for a command, and forward it if that is not us.
|
| slug@0 | 173 | *
|
| slug@0 | 174 | * \a server may be a nickname, server name, server mask (if \a from
|
| slug@0 | 175 | * is a local user) or server numnick (if \a is a server or remote
|
| slug@0 | 176 | * user).
|
| slug@0 | 177 | *
|
| slug@0 | 178 | * @param[in] from Client that sent the command to us.
|
| slug@0 | 179 | * @param[in] cmd Long-form command text.
|
| slug@0 | 180 | * @param[in] tok Token-form command text.
|
| slug@0 | 181 | * @param[in] one Client that originated the command (ignored).
|
| slug@0 | 182 | * @param[in] MustBeOper If non-zero and \a from is not an operator, return HUNTED_NOSUCH.
|
| slug@0 | 183 | * @param[in] pattern Format string of arguments to command.
|
| slug@0 | 184 | * @param[in] server Index of target name or mask in \a parv.
|
| slug@0 | 185 | * @param[in] parc Number of valid elements in \a parv (must be less than 9).
|
| slug@0 | 186 | * @param[in] parv Array of arguments to command.
|
| slug@0 | 187 | * @return One of HUNTED_ISME, HUNTED_NOSUCH or HUNTED_PASS.
|
| slug@0 | 188 | */
|
| slug@0 | 189 | int hunt_server_cmd(struct Client *from, const char *cmd, const char *tok,
|
| slug@0 | 190 | struct Client *one, int MustBeOper, const char *pattern,
|
| slug@0 | 191 | int server, int parc, char *parv[])
|
| slug@0 | 192 | {
|
| slug@0 | 193 | struct Client *acptr;
|
| slug@0 | 194 | char *to;
|
| slug@0 | 195 |
|
| slug@0 | 196 | /* Assume it's me, if no server or an unregistered client */
|
| slug@0 | 197 | if (parc <= server || EmptyString((to = parv[server])) || IsUnknown(from))
|
| slug@0 | 198 | return (HUNTED_ISME);
|
| slug@0 | 199 |
|
| paul@114 | 200 | if (MustBeOper && (!IsPrivileged(from) || (IsAnOper(from) && !HasPriv(from, PRIV_SERVERINFO))))
|
| slug@0 | 201 | {
|
| slug@0 | 202 | send_reply(from, ERR_NOPRIVILEGES);
|
| slug@0 | 203 | return HUNTED_NOSUCH;
|
| slug@0 | 204 | }
|
| slug@0 | 205 |
|
| slug@0 | 206 | /* Make sure it's a server */
|
| slug@0 | 207 | if (MyUser(from)) {
|
| slug@0 | 208 | /* Make sure it's a server */
|
| slug@0 | 209 | if (!strchr(to, '*')) {
|
| slug@0 | 210 | if (0 == (acptr = FindClient(to))) {
|
| slug@0 | 211 | send_reply(from, ERR_NOSUCHSERVER, to);
|
| slug@0 | 212 | return HUNTED_NOSUCH;
|
| slug@0 | 213 | }
|
| slug@0 | 214 |
|
| slug@0 | 215 | if (cli_user(acptr))
|
| slug@0 | 216 | acptr = cli_user(acptr)->server;
|
| slug@0 | 217 | } else if (!(acptr = find_match_server(to))) {
|
| slug@0 | 218 | send_reply(from, ERR_NOSUCHSERVER, to);
|
| slug@0 | 219 | return (HUNTED_NOSUCH);
|
| slug@0 | 220 | }
|
| slug@0 | 221 | } else if (!(acptr = FindNServer(to))) {
|
| slug@0 | 222 | send_reply(from, SND_EXPLICIT | ERR_NOSUCHSERVER, "* :Server has disconnected");
|
| slug@0 | 223 | return (HUNTED_NOSUCH); /* Server broke off in the meantime */
|
| slug@0 | 224 | }
|
| slug@0 | 225 |
|
| slug@0 | 226 | if (IsMe(acptr))
|
| slug@0 | 227 | return (HUNTED_ISME);
|
| slug@0 | 228 |
|
| slug@0 | 229 | if (MustBeOper && !IsPrivileged(from)) {
|
| slug@0 | 230 | send_reply(from, ERR_NOPRIVILEGES);
|
| slug@0 | 231 | return HUNTED_NOSUCH;
|
| slug@0 | 232 | }
|
| slug@0 | 233 |
|
| slug@0 | 234 | /* assert(!IsServer(from)); */
|
| slug@0 | 235 |
|
| slug@0 | 236 | parv[server] = (char *) acptr; /* HACK! HACK! HACK! ARGH! */
|
| slug@0 | 237 |
|
| slug@0 | 238 | sendcmdto_one(from, cmd, tok, acptr, pattern, parv[1], parv[2], parv[3],
|
| slug@0 | 239 | parv[4], parv[5], parv[6], parv[7], parv[8]);
|
| slug@0 | 240 |
|
| slug@0 | 241 | return (HUNTED_PASS);
|
| slug@0 | 242 | }
|
| slug@0 | 243 |
|
| slug@0 | 244 | /** Find the destination server for a command, and forward it (as a
|
| slug@0 | 245 | * high-priority command) if that is not us.
|
| slug@0 | 246 | *
|
| slug@0 | 247 | * \a server may be a nickname, server name, server mask (if \a from
|
| slug@0 | 248 | * is a local user) or server numnick (if \a is a server or remote
|
| slug@0 | 249 | * user).
|
| slug@0 | 250 | * Unlike hunt_server_cmd(), this appends the message to the
|
| slug@0 | 251 | * high-priority message queue for the destination server.
|
| slug@0 | 252 | *
|
| slug@0 | 253 | * @param[in] from Client that sent the command to us.
|
| slug@0 | 254 | * @param[in] cmd Long-form command text.
|
| slug@0 | 255 | * @param[in] tok Token-form command text.
|
| slug@0 | 256 | * @param[in] one Client that originated the command (ignored).
|
| slug@0 | 257 | * @param[in] MustBeOper If non-zero and \a from is not an operator, return HUNTED_NOSUCH.
|
| slug@0 | 258 | * @param[in] pattern Format string of arguments to command.
|
| slug@0 | 259 | * @param[in] server Index of target name or mask in \a parv.
|
| slug@0 | 260 | * @param[in] parc Number of valid elements in \a parv (must be less than 9).
|
| slug@0 | 261 | * @param[in] parv Array of arguments to command.
|
| slug@0 | 262 | * @return One of HUNTED_ISME, HUNTED_NOSUCH or HUNTED_PASS.
|
| slug@0 | 263 | */
|
| slug@0 | 264 | int hunt_server_prio_cmd(struct Client *from, const char *cmd, const char *tok,
|
| slug@0 | 265 | struct Client *one, int MustBeOper,
|
| slug@0 | 266 | const char *pattern, int server, int parc,
|
| slug@0 | 267 | char *parv[])
|
| slug@0 | 268 | {
|
| slug@0 | 269 | struct Client *acptr;
|
| slug@0 | 270 | char *to;
|
| slug@0 | 271 |
|
| slug@0 | 272 | /* Assume it's me, if no server or an unregistered client */
|
| slug@0 | 273 | if (parc <= server || EmptyString((to = parv[server])) || IsUnknown(from))
|
| slug@0 | 274 | return (HUNTED_ISME);
|
| slug@0 | 275 |
|
| slug@0 | 276 | /* Make sure it's a server */
|
| slug@0 | 277 | if (MyUser(from)) {
|
| slug@0 | 278 | /* Make sure it's a server */
|
| slug@0 | 279 | if (!strchr(to, '*')) {
|
| slug@0 | 280 | if (0 == (acptr = FindClient(to))) {
|
| slug@0 | 281 | send_reply(from, ERR_NOSUCHSERVER, to);
|
| slug@0 | 282 | return HUNTED_NOSUCH;
|
| slug@0 | 283 | }
|
| slug@0 | 284 |
|
| slug@0 | 285 | if (cli_user(acptr))
|
| slug@0 | 286 | acptr = cli_user(acptr)->server;
|
| slug@0 | 287 | } else if (!(acptr = find_match_server(to))) {
|
| slug@0 | 288 | send_reply(from, ERR_NOSUCHSERVER, to);
|
| slug@0 | 289 | return (HUNTED_NOSUCH);
|
| slug@0 | 290 | }
|
| slug@0 | 291 | } else if (!(acptr = FindNServer(to)))
|
| slug@0 | 292 | return (HUNTED_NOSUCH); /* Server broke off in the meantime */
|
| slug@0 | 293 |
|
| slug@0 | 294 | if (IsMe(acptr))
|
| slug@0 | 295 | return (HUNTED_ISME);
|
| slug@0 | 296 |
|
| slug@0 | 297 | if (MustBeOper && !IsPrivileged(from)) {
|
| slug@0 | 298 | send_reply(from, ERR_NOPRIVILEGES);
|
| slug@0 | 299 | return HUNTED_NOSUCH;
|
| slug@0 | 300 | }
|
| slug@0 | 301 |
|
| slug@0 | 302 | /* assert(!IsServer(from)); SETTIME to particular destinations permitted */
|
| slug@0 | 303 |
|
| slug@0 | 304 | parv[server] = (char *) acptr; /* HACK! HACK! HACK! ARGH! */
|
| slug@0 | 305 |
|
| slug@0 | 306 | sendcmdto_prio_one(from, cmd, tok, acptr, pattern, parv[1], parv[2], parv[3],
|
| slug@0 | 307 | parv[4], parv[5], parv[6], parv[7], parv[8]);
|
| slug@0 | 308 |
|
| slug@0 | 309 | return (HUNTED_PASS);
|
| slug@0 | 310 | }
|
| slug@0 | 311 |
|
| slug@0 | 312 |
|
| slug@0 | 313 | /*
|
| slug@0 | 314 | * register_user
|
| slug@0 | 315 | *
|
| slug@0 | 316 | * This function is called when both NICK and USER messages
|
| slug@0 | 317 | * have been accepted for the client, in whatever order. Only
|
| slug@0 | 318 | * after this the USER message is propagated.
|
| slug@0 | 319 | *
|
| slug@0 | 320 | * NICK's must be propagated at once when received, although
|
| slug@0 | 321 | * it would be better to delay them too until full info is
|
| slug@0 | 322 | * available. Doing it is not so simple though, would have
|
| slug@0 | 323 | * to implement the following:
|
| slug@0 | 324 | *
|
| slug@0 | 325 | * 1) user telnets in and gives only "NICK foobar" and waits
|
| slug@0 | 326 | * 2) another user far away logs in normally with the nick
|
| slug@0 | 327 | * "foobar" (quite legal, as this server didn't propagate it).
|
| slug@0 | 328 | * 3) now this server gets nick "foobar" from outside, but
|
| slug@0 | 329 | * has already the same defined locally. Current server
|
| slug@0 | 330 | * would just issue "KILL foobar" to clean out dups. But,
|
| slug@0 | 331 | * this is not fair. It should actually request another
|
| slug@0 | 332 | * nick from local user or kill him/her...
|
| slug@0 | 333 | */
|
| slug@0 | 334 | /** Finish registering a user who has sent both NICK and USER.
|
| slug@0 | 335 | * For local connections, possibly check IAuth; make sure there is a
|
| slug@0 | 336 | * matching Client config block; clean the username field; check
|
| slug@0 | 337 | * K/k-lines; check for "hacked" looking usernames; assign a numnick;
|
| slug@0 | 338 | * and send greeting (WELCOME, ISUPPORT, MOTD, etc).
|
| slug@0 | 339 | * For all connections, update the invisible user and operator counts;
|
| slug@0 | 340 | * run IPcheck against their address; and forward the NICK.
|
| slug@0 | 341 | *
|
| slug@0 | 342 | * @param[in] cptr Client who introduced the user.
|
| slug@0 | 343 | * @param[in,out] sptr Client who has been fully introduced.
|
| slug@0 | 344 | * @return Zero or CPTR_KILLED.
|
| slug@0 | 345 | */
|
| paul@33 | 346 | int register_user(struct Client *cptr, struct Client *sptr)
|
| slug@0 | 347 | {
|
| slug@0 | 348 | char* parv[4];
|
| slug@0 | 349 | char* tmpstr;
|
| slug@0 | 350 | struct User* user = cli_user(sptr);
|
| slug@0 | 351 | char ip_base64[25];
|
| chris@144 | 352 | int ipv6andopername[] = {FLAG_IPV6,FLAG_OPERNAME};
|
| slug@0 | 353 |
|
| slug@0 | 354 | user->last = CurrentTime;
|
| slug@0 | 355 | parv[0] = cli_name(sptr);
|
| slug@0 | 356 | parv[1] = parv[2] = NULL;
|
| slug@0 | 357 |
|
| slug@0 | 358 | if (MyConnect(sptr))
|
| slug@0 | 359 | {
|
| paul@33 | 360 | assert(cptr == sptr);
|
| slug@0 | 361 |
|
| slug@0 | 362 | Count_unknownbecomesclient(sptr, UserStats);
|
| slug@0 | 363 |
|
| paul@30 | 364 | if (MyConnect(sptr) && feature_bool(FEAT_AUTOINVISIBLE))
|
| paul@30 | 365 | SetInvisible(sptr);
|
| paul@30 | 366 |
|
| paul@30 | 367 | if(MyConnect(sptr) && feature_bool(FEAT_SETHOST_AUTO)) {
|
| paul@30 | 368 | if (conf_check_slines(sptr)) {
|
| paul@30 | 369 | send_reply(sptr, RPL_USINGSLINE);
|
| paul@30 | 370 | SetSetHost(sptr);
|
| paul@30 | 371 | }
|
| paul@30 | 372 | }
|
| paul@30 | 373 |
|
| slug@0 | 374 | SetUser(sptr);
|
| slug@0 | 375 | cli_handler(sptr) = CLIENT_HANDLER;
|
| slug@0 | 376 | SetLocalNumNick(sptr);
|
| slug@0 | 377 | send_reply(sptr,
|
| slug@0 | 378 | RPL_WELCOME,
|
| slug@0 | 379 | feature_str(FEAT_NETWORK),
|
| slug@0 | 380 | feature_str(FEAT_PROVIDER) ? " via " : "",
|
| slug@0 | 381 | feature_str(FEAT_PROVIDER) ? feature_str(FEAT_PROVIDER) : "",
|
| paul@33 | 382 | cli_name(sptr));
|
| slug@0 | 383 | /*
|
| slug@0 | 384 | * This is a duplicate of the NOTICE but see below...
|
| slug@0 | 385 | */
|
| slug@0 | 386 | send_reply(sptr, RPL_YOURHOST, cli_name(&me), version);
|
| slug@0 | 387 | send_reply(sptr, RPL_CREATED, creation);
|
| slug@0 | 388 | send_reply(sptr, RPL_MYINFO, cli_name(&me), version, infousermodes,
|
| slug@0 | 389 | infochanmodes, infochanmodeswithparams);
|
| slug@0 | 390 | send_supported(sptr);
|
| slug@0 | 391 | m_lusers(sptr, sptr, 1, parv);
|
| slug@0 | 392 | update_load();
|
| slug@0 | 393 | motd_signon(sptr);
|
| slug@0 | 394 | if (cli_snomask(sptr) & SNO_NOISY)
|
| slug@0 | 395 | set_snomask(sptr, cli_snomask(sptr) & SNO_NOISY, SNO_ADD);
|
| slug@0 | 396 | if (feature_bool(FEAT_CONNEXIT_NOTICES))
|
| slug@0 | 397 | sendto_opmask_butone(0, SNO_CONNEXIT,
|
| slug@0 | 398 | "Client connecting: %s (%s@%s) [%s] {%s} [%s] <%s%s>",
|
| slug@0 | 399 | cli_name(sptr), user->username, user->host,
|
| slug@0 | 400 | cli_sock_ip(sptr), get_client_class(sptr),
|
| slug@0 | 401 | cli_info(sptr), NumNick(cptr) /* two %s's */);
|
| slug@0 | 402 |
|
| slug@0 | 403 | IPcheck_connect_succeeded(sptr);
|
| slug@0 | 404 | /*
|
| slug@0 | 405 | * Set user's initial modes
|
| slug@0 | 406 | */
|
| slug@0 | 407 | tmpstr = (char*)client_get_default_umode(sptr);
|
| paul@115 | 408 | if (tmpstr) {
|
| paul@121 | 409 | char *umodev[] = { NULL, NULL, NULL, NULL };
|
| paul@121 | 410 | umodev[2] = tmpstr;
|
| paul@115 | 411 | set_user_mode(cptr, sptr, 1, umodev, ALLOWMODES_ANY);
|
| slug@0 | 412 | }
|
| paul@115 | 413 |
|
| slug@0 | 414 | }
|
| slug@0 | 415 | else {
|
| paul@33 | 416 | struct Client *acptr = user->server;
|
| slug@0 | 417 |
|
| slug@0 | 418 | if (cli_from(acptr) != cli_from(sptr))
|
| slug@0 | 419 | {
|
| slug@0 | 420 | sendcmdto_one(&me, CMD_KILL, cptr, "%C :%s (%s != %s[%s])",
|
| slug@0 | 421 | sptr, cli_name(&me), cli_name(user->server), cli_name(cli_from(acptr)),
|
| slug@0 | 422 | cli_sockhost(cli_from(acptr)));
|
| slug@0 | 423 | SetFlag(sptr, FLAG_KILLED);
|
| slug@0 | 424 | return exit_client(cptr, sptr, &me, "NICK server wrong direction");
|
| slug@0 | 425 | }
|
| slug@0 | 426 | else if (HasFlag(acptr, FLAG_TS8))
|
| slug@0 | 427 | SetFlag(sptr, FLAG_TS8);
|
| slug@0 | 428 |
|
| slug@0 | 429 | /*
|
| slug@0 | 430 | * Check to see if this user is being propagated
|
| slug@0 | 431 | * as part of a net.burst, or is using protocol 9.
|
| slug@0 | 432 | * FIXME: This can be sped up - its stupid to check it for
|
| slug@0 | 433 | * every NICK message in a burst again --Run.
|
| slug@0 | 434 | */
|
| slug@0 | 435 | for (; acptr != &me; acptr = cli_serv(acptr)->up)
|
| slug@0 | 436 | {
|
| slug@0 | 437 | if (IsBurst(acptr) || Protocol(acptr) < 10)
|
| slug@0 | 438 | break;
|
| slug@0 | 439 | }
|
| slug@0 | 440 | if (!IPcheck_remote_connect(sptr, (acptr != &me)))
|
| slug@0 | 441 | {
|
| slug@0 | 442 | /*
|
| slug@0 | 443 | * We ran out of bits to count this
|
| slug@0 | 444 | */
|
| slug@0 | 445 | sendcmdto_one(&me, CMD_KILL, sptr, "%C :%s (Too many connections from your host -- Ghost)",
|
| slug@0 | 446 | sptr, cli_name(&me));
|
| slug@0 | 447 | return exit_client(cptr, sptr, &me,"Too many connections from your host -- throttled");
|
| slug@0 | 448 | }
|
| paul@30 | 449 |
|
| paul@30 | 450 | if(MyConnect(sptr) && feature_bool(FEAT_SETHOST_AUTO)) {
|
| paul@30 | 451 | if (conf_check_slines(sptr)) {
|
| paul@30 | 452 | send_reply(sptr, RPL_USINGSLINE);
|
| paul@30 | 453 | SetSetHost(sptr);
|
| paul@30 | 454 | }
|
| paul@30 | 455 | }
|
| paul@30 | 456 |
|
| slug@0 | 457 | SetUser(sptr);
|
| slug@0 | 458 | }
|
| slug@0 | 459 |
|
| paul@101 | 460 | /* If they get both +x and an account during registration, hide
|
| paul@101 | 461 | * their hostmask here. Calling hide_hostmask() from IAuth's
|
| paul@101 | 462 | * account assignment causes a numeric reply during registration.
|
| paul@101 | 463 | */
|
| paul@101 | 464 | if (HasHiddenHost(sptr))
|
| paul@101 | 465 | hide_hostmask(sptr, FLAG_HIDDENHOST);
|
| paul@126 | 466 | if (IsInvisible(sptr))
|
| paul@126 | 467 | ++UserStats.inv_clients;
|
| paul@126 | 468 | if (IsOper(sptr))
|
| paul@126 | 469 | ++UserStats.opers;
|
| slug@0 | 470 |
|
| paul@80 | 471 | tmpstr = umode_str(sptr, 0);
|
| paul@80 | 472 |
|
| paul@80 | 473 | /* Do not send oper name and send full IP address to IPv6-grokking servers. */
|
| slug@0 | 474 | sendcmdto_flag_serv_butone(user->server, CMD_NICK, cptr,
|
| paul@80 | 475 | FLAG_IPV6, FLAG_OPERNAME,
|
| slug@0 | 476 | "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
|
| paul@33 | 477 | cli_name(sptr), cli_hopcount(sptr) + 1,
|
| paul@33 | 478 | cli_lastnick(sptr),
|
| paul@30 | 479 | user->realusername, user->realhost,
|
| slug@0 | 480 | *tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
|
| slug@0 | 481 | iptobase64(ip_base64, &cli_ip(sptr), sizeof(ip_base64), 1),
|
| slug@0 | 482 | NumNick(sptr), cli_info(sptr));
|
| paul@80 | 483 | /* Do not send oper name and send fake IPv6 addresses to pre-IPv6 servers. */
|
| paul@80 | 484 | sendcmdto_flagarray_serv_butone(user->server, CMD_NICK, cptr,
|
| paul@80 | 485 | NULL, 0, ipv6andopername, 2,
|
| slug@0 | 486 | "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
|
| paul@33 | 487 | cli_name(sptr), cli_hopcount(sptr) + 1,
|
| paul@33 | 488 | cli_lastnick(sptr),
|
| paul@80 | 489 | user->realusername, user->realhost,
|
| paul@80 | 490 | *tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
|
| paul@80 | 491 | iptobase64(ip_base64, &cli_ip(sptr), sizeof(ip_base64), 0),
|
| paul@80 | 492 | NumNick(sptr), cli_info(sptr));
|
| paul@80 | 493 |
|
| paul@80 | 494 | tmpstr = umode_str(sptr, 1);
|
| paul@80 | 495 | /* Send oper name and full IP address to IPv6-grokking servers. */
|
| paul@80 | 496 | sendcmdto_flagarray_serv_butone(user->server, CMD_NICK, cptr,
|
| paul@80 | 497 | ipv6andopername, 2, NULL, 0,
|
| paul@80 | 498 | "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
|
| paul@80 | 499 | cli_name(sptr), cli_hopcount(sptr) + 1,
|
| paul@80 | 500 | cli_lastnick(sptr),
|
| paul@80 | 501 | user->realusername, user->realhost,
|
| paul@80 | 502 | *tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
|
| paul@80 | 503 | iptobase64(ip_base64, &cli_ip(sptr), sizeof(ip_base64), 1),
|
| paul@80 | 504 | NumNick(sptr), cli_info(sptr));
|
| paul@80 | 505 | /* Send oper name and fake IPv6 addresses to pre-IPv6 servers. */
|
| slug@0 | 506 | sendcmdto_flag_serv_butone(user->server, CMD_NICK, cptr,
|
| paul@80 | 507 | FLAG_OPERNAME, FLAG_IPV6,
|
| slug@0 | 508 | "%s %d %Tu %s %s %s%s%s%s %s%s :%s",
|
| paul@33 | 509 | cli_name(sptr), cli_hopcount(sptr) + 1,
|
| paul@33 | 510 | cli_lastnick(sptr),
|
| paul@30 | 511 | user->realusername, user->realhost,
|
| slug@0 | 512 | *tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
|
| slug@0 | 513 | iptobase64(ip_base64, &cli_ip(sptr), sizeof(ip_base64), 0),
|
| slug@0 | 514 | NumNick(sptr), cli_info(sptr));
|
| slug@0 | 515 |
|
| slug@0 | 516 | /* Send user mode to client */
|
| slug@0 | 517 | if (MyUser(sptr))
|
| slug@0 | 518 | {
|
| slug@0 | 519 | static struct Flags flags; /* automatically initialized to zeros */
|
| paul@31 | 520 | /* To avoid sending +r to the client due to auth-on-connect, set
|
| paul@31 | 521 | * the "old" FLAG_ACCOUNT bit to match the client's value.
|
| paul@31 | 522 | */
|
| paul@31 | 523 | if (IsAccount(cptr))
|
| paul@31 | 524 | FlagSet(&flags, FLAG_ACCOUNT);
|
| paul@31 | 525 | else
|
| paul@31 | 526 | FlagClr(&flags, FLAG_ACCOUNT);
|
| paul@126 | 527 | client_set_privs(sptr, NULL);
|
| paul@80 | 528 | send_umode(cptr, sptr, &flags, ALL_UMODES, 0);
|
| slug@0 | 529 | if ((cli_snomask(sptr) != SNO_DEFAULT) && HasFlag(sptr, FLAG_SERVNOTICE))
|
| slug@0 | 530 | send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr));
|
| slug@0 | 531 | }
|
| slug@0 | 532 | return 0;
|
| slug@0 | 533 | }
|
| slug@0 | 534 |
|
| slug@0 | 535 | /** List of user mode characters. */
|
| slug@0 | 536 | static const struct UserMode {
|
| slug@0 | 537 | unsigned int flag; /**< User mode constant. */
|
| slug@0 | 538 | char c; /**< Character corresponding to the mode. */
|
| slug@0 | 539 | } userModeList[] = {
|
| slug@0 | 540 | { FLAG_OPER, 'o' },
|
| slug@0 | 541 | { FLAG_LOCOP, 'O' },
|
| slug@0 | 542 | { FLAG_INVISIBLE, 'i' },
|
| slug@0 | 543 | { FLAG_WALLOP, 'w' },
|
| slug@0 | 544 | { FLAG_SERVNOTICE, 's' },
|
| slug@0 | 545 | { FLAG_DEAF, 'd' },
|
| slug@0 | 546 | { FLAG_CHSERV, 'k' },
|
| slug@0 | 547 | { FLAG_DEBUG, 'g' },
|
| slug@0 | 548 | { FLAG_ACCOUNT, 'r' },
|
| paul@30 | 549 | { FLAG_HIDDENHOST, 'x' },
|
| paul@30 | 550 | { FLAG_ACCOUNTONLY, 'R' },
|
| paul@30 | 551 | { FLAG_XTRAOP, 'X' },
|
| paul@30 | 552 | { FLAG_NOCHAN, 'n' },
|
| paul@30 | 553 | { FLAG_NOIDLE, 'I' },
|
| paul@30 | 554 | { FLAG_SETHOST, 'h' },
|
| paul@30 | 555 | { FLAG_PARANOID, 'P' }
|
| slug@0 | 556 | };
|
| slug@0 | 557 |
|
| slug@0 | 558 | /** Length of #userModeList. */
|
| slug@0 | 559 | #define USERMODELIST_SIZE sizeof(userModeList) / sizeof(struct UserMode)
|
| slug@0 | 560 |
|
| slug@0 | 561 | /*
|
| slug@0 | 562 | * XXX - find a way to get rid of this
|
| slug@0 | 563 | */
|
| slug@0 | 564 | /** Nasty global buffer used for communications with umode_str() and others. */
|
| slug@0 | 565 | static char umodeBuf[BUFSIZE];
|
| slug@0 | 566 |
|
| slug@0 | 567 | /** Try to set a user's nickname.
|
| slug@0 | 568 | * If \a sptr is a server, the client is being introduced for the first time.
|
| slug@0 | 569 | * @param[in] cptr Client to set nickname.
|
| slug@0 | 570 | * @param[in] sptr Client sending the NICK.
|
| slug@0 | 571 | * @param[in] nick New nickname.
|
| slug@0 | 572 | * @param[in] parc Number of arguments to NICK.
|
| slug@0 | 573 | * @param[in] parv Argument list to NICK.
|
| slug@0 | 574 | * @return CPTR_KILLED if \a cptr was killed, else 0.
|
| slug@0 | 575 | */
|
| slug@0 | 576 | int set_nick_name(struct Client* cptr, struct Client* sptr,
|
| slug@0 | 577 | const char* nick, int parc, char* parv[])
|
| slug@0 | 578 | {
|
| slug@0 | 579 | if (IsServer(sptr)) {
|
| slug@0 | 580 | /*
|
| slug@0 | 581 | * A server introducing a new client, change source
|
| slug@0 | 582 | */
|
| slug@0 | 583 | struct Client* new_client = make_client(cptr, STAT_UNKNOWN);
|
| slug@0 | 584 | assert(0 != new_client);
|
| slug@0 | 585 |
|
| slug@0 | 586 | cli_hopcount(new_client) = atoi(parv[2]);
|
| slug@0 | 587 | cli_lastnick(new_client) = atoi(parv[3]);
|
| paul@115 | 588 |
|
| slug@0 | 589 | /*
|
| slug@0 | 590 | * Set new nick name.
|
| slug@0 | 591 | */
|
| slug@0 | 592 | strcpy(cli_name(new_client), nick);
|
| slug@0 | 593 | cli_user(new_client) = make_user(new_client);
|
| slug@0 | 594 | cli_user(new_client)->server = sptr;
|
| slug@0 | 595 | SetRemoteNumNick(new_client, parv[parc - 2]);
|
| slug@0 | 596 | /*
|
| slug@0 | 597 | * IP# of remote client
|
| slug@0 | 598 | */
|
| slug@0 | 599 | base64toip(parv[parc - 3], &cli_ip(new_client));
|
| slug@0 | 600 |
|
| slug@0 | 601 | add_client_to_list(new_client);
|
| slug@0 | 602 | hAddClient(new_client);
|
| slug@0 | 603 |
|
| slug@0 | 604 | cli_serv(sptr)->ghost = 0; /* :server NICK means end of net.burst */
|
| slug@0 | 605 | ircd_strncpy(cli_username(new_client), parv[4], USERLEN);
|
| paul@33 | 606 | ircd_strncpy(cli_user(new_client)->username, parv[4], USERLEN);
|
| paul@30 | 607 | ircd_strncpy(cli_user(new_client)->realusername, parv[4], USERLEN);
|
| slug@0 | 608 | ircd_strncpy(cli_user(new_client)->host, parv[5], HOSTLEN);
|
| slug@0 | 609 | ircd_strncpy(cli_user(new_client)->realhost, parv[5], HOSTLEN);
|
| slug@0 | 610 | ircd_strncpy(cli_info(new_client), parv[parc - 1], REALLEN);
|
| paul@115 | 611 |
|
| paul@115 | 612 | Count_newremoteclient(UserStats, sptr);
|
| paul@115 | 613 |
|
| paul@115 | 614 | if (parc > 7 && *parv[6] == '+') {
|
| paul@115 | 615 | /* (parc-4) -3 for the ip, numeric nick, realname */
|
| paul@115 | 616 | set_user_mode(cptr, new_client, parc-7, parv+4, ALLOWMODES_ANY);
|
| slug@0 | 617 | }
|
| slug@0 | 618 |
|
| paul@33 | 619 | return register_user(cptr, new_client);
|
| slug@0 | 620 | }
|
| slug@0 | 621 | else if ((cli_name(sptr))[0]) {
|
| slug@0 | 622 | /*
|
| slug@0 | 623 | * Client changing its nick
|
| slug@0 | 624 | *
|
| slug@0 | 625 | * If the client belongs to me, then check to see
|
| slug@0 | 626 | * if client is on any channels where it is currently
|
| slug@0 | 627 | * banned. If so, do not allow the nick change to occur.
|
| slug@0 | 628 | */
|
| slug@0 | 629 | if (MyUser(sptr)) {
|
| slug@0 | 630 | const char* channel_name;
|
| slug@0 | 631 | struct Membership *member;
|
| paul@30 | 632 | if ((channel_name = find_no_nickchange_channel(sptr)) && !IsXtraOp(sptr)) {
|
| slug@0 | 633 | return send_reply(cptr, ERR_BANNICKCHANGE, channel_name);
|
| slug@0 | 634 | }
|
| slug@0 | 635 | /*
|
| slug@0 | 636 | * Refuse nick change if the last nick change was less
|
| slug@0 | 637 | * then 30 seconds ago. This is intended to get rid of
|
| slug@0 | 638 | * clone bots doing NICK FLOOD. -SeKs
|
| slug@0 | 639 | * If someone didn't change their nick for more then 60 seconds
|
| slug@0 | 640 | * however, allow to do two nick changes immediately after another
|
| slug@0 | 641 | * before limiting the nick flood. -Run
|
| slug@0 | 642 | */
|
| slug@0 | 643 | if (CurrentTime < cli_nextnick(cptr))
|
| slug@0 | 644 | {
|
| slug@0 | 645 | cli_nextnick(cptr) += 2;
|
| slug@0 | 646 | send_reply(cptr, ERR_NICKTOOFAST, parv[1],
|
| slug@0 | 647 | cli_nextnick(cptr) - CurrentTime);
|
| slug@0 | 648 | /* Send error message */
|
| slug@0 | 649 | sendcmdto_one(cptr, CMD_NICK, cptr, "%s", cli_name(cptr));
|
| slug@0 | 650 | /* bounce NICK to user */
|
| slug@0 | 651 | return 0; /* ignore nick change! */
|
| slug@0 | 652 | }
|
| slug@0 | 653 | else {
|
| slug@0 | 654 | /* Limit total to 1 change per NICK_DELAY seconds: */
|
| slug@0 | 655 | cli_nextnick(cptr) += NICK_DELAY;
|
| slug@0 | 656 | /* However allow _maximal_ 1 extra consecutive nick change: */
|
| slug@0 | 657 | if (cli_nextnick(cptr) < CurrentTime)
|
| slug@0 | 658 | cli_nextnick(cptr) = CurrentTime;
|
| slug@0 | 659 | }
|
| slug@0 | 660 | /* Invalidate all bans against the user so we check them again */
|
| slug@0 | 661 | for (member = (cli_user(cptr))->channel; member;
|
| slug@0 | 662 | member = member->next_channel)
|
| slug@0 | 663 | ClearBanValid(member);
|
| slug@0 | 664 | }
|
| slug@0 | 665 | /*
|
| slug@0 | 666 | * Also set 'lastnick' to current time, if changed.
|
| slug@0 | 667 | */
|
| slug@0 | 668 | if (0 != ircd_strcmp(parv[0], nick))
|
| slug@0 | 669 | cli_lastnick(sptr) = (sptr == cptr) ? TStime() : atoi(parv[2]);
|
| slug@0 | 670 |
|
| slug@0 | 671 | /*
|
| slug@0 | 672 | * Client just changing his/her nick. If he/she is
|
| slug@0 | 673 | * on a channel, send note of change to all clients
|
| slug@0 | 674 | * on that channel. Propagate notice to other servers.
|
| slug@0 | 675 | */
|
| slug@0 | 676 | if (IsUser(sptr)) {
|
| slug@0 | 677 | sendcmdto_common_channels_butone(sptr, CMD_NICK, NULL, ":%s", nick);
|
| slug@0 | 678 | add_history(sptr, 1);
|
| slug@0 | 679 | sendcmdto_serv_butone(sptr, CMD_NICK, cptr, "%s %Tu", nick,
|
| slug@0 | 680 | cli_lastnick(sptr));
|
| slug@0 | 681 | }
|
| slug@0 | 682 | else
|
| slug@0 | 683 | sendcmdto_one(sptr, CMD_NICK, sptr, ":%s", nick);
|
| slug@0 | 684 |
|
| slug@0 | 685 | if ((cli_name(sptr))[0])
|
| slug@0 | 686 | hRemClient(sptr);
|
| slug@0 | 687 | strcpy(cli_name(sptr), nick);
|
| slug@0 | 688 | hAddClient(sptr);
|
| slug@0 | 689 | }
|
| slug@0 | 690 | else {
|
| slug@0 | 691 | /* Local client setting NICK the first time */
|
| slug@0 | 692 | strcpy(cli_name(sptr), nick);
|
| slug@0 | 693 | hAddClient(sptr);
|
| paul@33 | 694 | return auth_set_nick(cli_auth(sptr), nick);
|
| slug@0 | 695 | }
|
| slug@0 | 696 | return 0;
|
| slug@0 | 697 | }
|
| slug@0 | 698 |
|
| slug@0 | 699 | /** Calculate the hash value for a target.
|
| slug@0 | 700 | * @param[in] target Pointer to target, cast to unsigned int.
|
| slug@0 | 701 | * @return Hash value constructed from the pointer.
|
| slug@0 | 702 | */
|
| slug@0 | 703 | static unsigned char hash_target(unsigned int target)
|
| slug@0 | 704 | {
|
| slug@0 | 705 | return (unsigned char) (target >> 16) ^ (target >> 8);
|
| slug@0 | 706 | }
|
| slug@0 | 707 |
|
| slug@0 | 708 | /** Records \a target as a recent target for \a sptr.
|
| slug@0 | 709 | * @param[in] sptr User who has sent to a new target.
|
| slug@0 | 710 | * @param[in] target Target to add.
|
| slug@0 | 711 | */
|
| slug@0 | 712 | void
|
| slug@0 | 713 | add_target(struct Client *sptr, void *target)
|
| slug@0 | 714 | {
|
| slug@0 | 715 | /* Ok, this shouldn't work esp on alpha
|
| slug@0 | 716 | */
|
| slug@0 | 717 | unsigned char hash = hash_target((unsigned long) target);
|
| slug@0 | 718 | unsigned char* targets;
|
| slug@0 | 719 | int i;
|
| slug@0 | 720 | assert(0 != sptr);
|
| slug@0 | 721 | assert(cli_local(sptr));
|
| slug@0 | 722 |
|
| slug@0 | 723 | targets = cli_targets(sptr);
|
| slug@0 | 724 |
|
| slug@0 | 725 | /*
|
| slug@0 | 726 | * Already in table?
|
| slug@0 | 727 | */
|
| slug@0 | 728 | for (i = 0; i < MAXTARGETS; ++i) {
|
| slug@0 | 729 | if (targets[i] == hash)
|
| slug@0 | 730 | return;
|
| slug@0 | 731 | }
|
| slug@0 | 732 | /*
|
| slug@0 | 733 | * New target
|
| slug@0 | 734 | */
|
| slug@0 | 735 | memmove(&targets[RESERVEDTARGETS + 1],
|
| slug@0 | 736 | &targets[RESERVEDTARGETS], MAXTARGETS - RESERVEDTARGETS - 1);
|
| slug@0 | 737 | targets[RESERVEDTARGETS] = hash;
|
| slug@0 | 738 | }
|
| slug@0 | 739 |
|
| slug@0 | 740 | /** Check whether \a sptr can send to or join \a target yet.
|
| slug@0 | 741 | * @param[in] sptr User trying to join a channel or send a message.
|
| slug@0 | 742 | * @param[in] target Target of the join or message.
|
| slug@0 | 743 | * @param[in] name Name of the target.
|
| slug@0 | 744 | * @param[in] created If non-zero, trying to join a new channel.
|
| slug@0 | 745 | * @return Non-zero if too many target changes; zero if okay to send.
|
| slug@0 | 746 | */
|
| slug@0 | 747 | int check_target_limit(struct Client *sptr, void *target, const char *name,
|
| slug@0 | 748 | int created)
|
| slug@0 | 749 | {
|
| slug@0 | 750 | unsigned char hash = hash_target((unsigned long) target);
|
| slug@0 | 751 | int i;
|
| slug@0 | 752 | unsigned char* targets;
|
| slug@0 | 753 |
|
| slug@0 | 754 | assert(0 != sptr);
|
| slug@0 | 755 | assert(cli_local(sptr));
|
| slug@0 | 756 | targets = cli_targets(sptr);
|
| slug@0 | 757 |
|
| slug@0 | 758 | /* If user is invited to channel, give him/her a free target */
|
| slug@0 | 759 | if (IsChannelName(name) && IsInvited(sptr, target))
|
| slug@0 | 760 | return 0;
|
| slug@0 | 761 |
|
| paul@30 | 762 | /* opers always have a free target */
|
| paul@30 | 763 | if (IsAnOper(sptr))
|
| paul@30 | 764 | return 0;
|
| paul@30 | 765 |
|
| slug@0 | 766 | /*
|
| slug@0 | 767 | * Same target as last time?
|
| slug@0 | 768 | */
|
| slug@0 | 769 | if (targets[0] == hash)
|
| slug@0 | 770 | return 0;
|
| slug@0 | 771 | for (i = 1; i < MAXTARGETS; ++i) {
|
| slug@0 | 772 | if (targets[i] == hash) {
|
| slug@0 | 773 | memmove(&targets[1], &targets[0], i);
|
| slug@0 | 774 | targets[0] = hash;
|
| slug@0 | 775 | return 0;
|
| slug@0 | 776 | }
|
| slug@0 | 777 | }
|
| slug@0 | 778 | /*
|
| slug@0 | 779 | * New target
|
| slug@0 | 780 | */
|
| slug@0 | 781 | if (!created) {
|
| slug@0 | 782 | if (CurrentTime < cli_nexttarget(sptr)) {
|
| slug@0 | 783 | if (cli_nexttarget(sptr) - CurrentTime < TARGET_DELAY + 8) {
|
| slug@0 | 784 | /*
|
| slug@0 | 785 | * No server flooding
|
| slug@0 | 786 | */
|
| slug@0 | 787 | cli_nexttarget(sptr) += 2;
|
| slug@0 | 788 | send_reply(sptr, ERR_TARGETTOOFAST, name,
|
| slug@0 | 789 | cli_nexttarget(sptr) - CurrentTime);
|
| slug@0 | 790 | }
|
| slug@0 | 791 | return 1;
|
| slug@0 | 792 | }
|
| slug@0 | 793 | else {
|
| slug@0 | 794 | cli_nexttarget(sptr) += TARGET_DELAY;
|
| slug@0 | 795 | if (cli_nexttarget(sptr) < CurrentTime - (TARGET_DELAY * (MAXTARGETS - 1)))
|
| slug@0 | 796 | cli_nexttarget(sptr) = CurrentTime - (TARGET_DELAY * (MAXTARGETS - 1));
|
| slug@0 | 797 | }
|
| slug@0 | 798 | }
|
| slug@0 | 799 | memmove(&targets[1], &targets[0], MAXTARGETS - 1);
|
| slug@0 | 800 | targets[0] = hash;
|
| slug@0 | 801 | return 0;
|
| slug@0 | 802 | }
|
| slug@0 | 803 |
|
| slug@0 | 804 | /** Allows a channel operator to avoid target change checks when
|
| slug@0 | 805 | * sending messages to users on their channel.
|
| slug@0 | 806 | * @param[in] source User sending the message.
|
| slug@0 | 807 | * @param[in] nick Destination of the message.
|
| slug@0 | 808 | * @param[in] channel Name of channel being sent to.
|
| slug@0 | 809 | * @param[in] text Message to send.
|
| slug@0 | 810 | * @param[in] is_notice If non-zero, use CNOTICE instead of CPRIVMSG.
|
| slug@0 | 811 | */
|
| slug@0 | 812 | /* Added 971023 by Run. */
|
| slug@0 | 813 | int whisper(struct Client* source, const char* nick, const char* channel,
|
| slug@0 | 814 | const char* text, int is_notice)
|
| slug@0 | 815 | {
|
| slug@0 | 816 | struct Client* dest;
|
| slug@0 | 817 | struct Channel* chptr;
|
| slug@0 | 818 | struct Membership* membership;
|
| slug@0 | 819 |
|
| slug@0 | 820 | assert(0 != source);
|
| slug@0 | 821 | assert(0 != nick);
|
| slug@0 | 822 | assert(0 != channel);
|
| slug@0 | 823 | assert(MyUser(source));
|
| slug@0 | 824 |
|
| slug@0 | 825 | if (!(dest = FindUser(nick))) {
|
| slug@0 | 826 | return send_reply(source, ERR_NOSUCHNICK, nick);
|
| slug@0 | 827 | }
|
| slug@0 | 828 | if (!(chptr = FindChannel(channel))) {
|
| slug@0 | 829 | return send_reply(source, ERR_NOSUCHCHANNEL, channel);
|
| slug@0 | 830 | }
|
| slug@0 | 831 | /*
|
| slug@0 | 832 | * compare both users channel lists, instead of the channels user list
|
| slug@0 | 833 | * since the link is the same, this should be a little faster for channels
|
| slug@0 | 834 | * with a lot of users
|
| slug@0 | 835 | */
|
| slug@0 | 836 | for (membership = cli_user(source)->channel; membership; membership = membership->next_channel) {
|
| slug@0 | 837 | if (chptr == membership->channel)
|
| slug@0 | 838 | break;
|
| slug@0 | 839 | }
|
| slug@0 | 840 | if (0 == membership) {
|
| slug@0 | 841 | return send_reply(source, ERR_NOTONCHANNEL, chptr->chname);
|
| slug@0 | 842 | }
|
| slug@0 | 843 | if (!IsVoicedOrOpped(membership)) {
|
| slug@0 | 844 | return send_reply(source, ERR_VOICENEEDED, chptr->chname);
|
| slug@0 | 845 | }
|
| slug@0 | 846 | /*
|
| slug@0 | 847 | * lookup channel in destination
|
| slug@0 | 848 | */
|
| slug@0 | 849 | assert(0 != cli_user(dest));
|
| slug@0 | 850 | for (membership = cli_user(dest)->channel; membership; membership = membership->next_channel) {
|
| slug@0 | 851 | if (chptr == membership->channel)
|
| slug@0 | 852 | break;
|
| slug@0 | 853 | }
|
| slug@0 | 854 | if (0 == membership || IsZombie(membership)) {
|
| slug@0 | 855 | return send_reply(source, ERR_USERNOTINCHANNEL, cli_name(dest), chptr->chname);
|
| slug@0 | 856 | }
|
| slug@0 | 857 | if (is_silenced(source, dest))
|
| slug@0 | 858 | return 0;
|
| paul@103 | 859 |
|
| paul@103 | 860 | if (IsAccountOnly(dest) && !IsAccount(source) && !IsOper(source)) {
|
| paul@103 | 861 | if(!is_notice)
|
| paul@103 | 862 | send_reply(source, ERR_ACCOUNTONLY, cli_name(source), feature_str(FEAT_URLREG));
|
| paul@103 | 863 | return 0;
|
| paul@103 | 864 | }
|
| slug@0 | 865 |
|
| slug@0 | 866 | if (is_notice)
|
| slug@0 | 867 | sendcmdto_one(source, CMD_NOTICE, dest, "%C :%s", dest, text);
|
| slug@0 | 868 | else
|
| paul@121 | 869 | {
|
| paul@121 | 870 | if (cli_user(dest)->away)
|
| paul@121 | 871 | send_reply(source, RPL_AWAY, cli_name(dest), cli_user(dest)->away);
|
| slug@0 | 872 | sendcmdto_one(source, CMD_PRIVATE, dest, "%C :%s", dest, text);
|
| paul@121 | 873 | }
|
| slug@0 | 874 | return 0;
|
| slug@0 | 875 | }
|
| slug@0 | 876 |
|
| slug@0 | 877 |
|
| slug@0 | 878 | /** Send a user mode change for \a cptr to neighboring servers.
|
| slug@0 | 879 | * @param[in] cptr User whose mode is changing.
|
| slug@0 | 880 | * @param[in] sptr Client who sent us the mode change message.
|
| slug@0 | 881 | * @param[in] old Prior set of user flags.
|
| slug@0 | 882 | * @param[in] prop If non-zero, also include FLAG_OPER.
|
| slug@0 | 883 | */
|
| slug@0 | 884 | void send_umode_out(struct Client *cptr, struct Client *sptr,
|
| slug@0 | 885 | struct Flags *old, int prop)
|
| slug@0 | 886 | {
|
| slug@0 | 887 | int i;
|
| slug@0 | 888 | struct Client *acptr;
|
| slug@0 | 889 |
|
| paul@80 | 890 | send_umode(NULL, sptr, old, prop ? SEND_UMODES : SEND_UMODES_BUT_OPER, 0);
|
| slug@0 | 891 |
|
| slug@0 | 892 | for (i = HighestFd; i >= 0; i--)
|
| slug@0 | 893 | {
|
| slug@0 | 894 | if ((acptr = LocalClientArray[i]) && IsServer(acptr) &&
|
| paul@80 | 895 | (acptr != cptr) && (acptr != sptr) && !IsSendOperName(acptr) && *umodeBuf)
|
| paul@80 | 896 | sendcmdto_one(sptr, CMD_MODE, acptr, "%s %s", cli_name(sptr), umodeBuf);
|
| slug@0 | 897 | }
|
| paul@80 | 898 |
|
| paul@80 | 899 | send_umode(NULL, sptr, old, prop ? SEND_UMODES : SEND_UMODES_BUT_OPER, 1);
|
| paul@80 | 900 |
|
| paul@80 | 901 | for (i = HighestFd; i >= 0; i--)
|
| paul@80 | 902 | {
|
| paul@80 | 903 | if ((acptr = LocalClientArray[i]) && IsServer(acptr) &&
|
| paul@80 | 904 | (acptr != cptr) && (acptr != sptr) && IsSendOperName(acptr) && *umodeBuf)
|
| paul@80 | 905 | sendcmdto_one(sptr, CMD_MODE, acptr, "%s %s", cli_name(sptr), umodeBuf);
|
| paul@80 | 906 | }
|
| paul@80 | 907 |
|
| slug@0 | 908 | if (cptr && MyUser(cptr))
|
| paul@80 | 909 | send_umode(cptr, sptr, old, ALL_UMODES, 0);
|
| slug@0 | 910 | }
|
| slug@0 | 911 |
|
| slug@0 | 912 |
|
| slug@0 | 913 | /** Call \a fmt for each Client named in \a names.
|
| slug@0 | 914 | * @param[in] sptr Client requesting information.
|
| slug@0 | 915 | * @param[in] names Space-delimited list of nicknames.
|
| slug@0 | 916 | * @param[in] rpl Base reply string for messages.
|
| slug@0 | 917 | * @param[in] fmt Formatting callback function.
|
| slug@0 | 918 | */
|
| slug@0 | 919 | void send_user_info(struct Client* sptr, char* names, int rpl, InfoFormatter fmt)
|
| slug@0 | 920 | {
|
| slug@0 | 921 | char* name;
|
| slug@0 | 922 | char* p = 0;
|
| slug@0 | 923 | int arg_count = 0;
|
| slug@0 | 924 | int users_found = 0;
|
| slug@0 | 925 | struct Client* acptr;
|
| slug@0 | 926 | struct MsgBuf* mb;
|
| slug@0 | 927 |
|
| slug@0 | 928 | assert(0 != sptr);
|
| slug@0 | 929 | assert(0 != names);
|
| slug@0 | 930 | assert(0 != fmt);
|
| slug@0 | 931 |
|
| slug@0 | 932 | mb = msgq_make(sptr, rpl_str(rpl), cli_name(&me), cli_name(sptr));
|
| slug@0 | 933 |
|
| slug@0 | 934 | for (name = ircd_strtok(&p, names, " "); name; name = ircd_strtok(&p, 0, " ")) {
|
| slug@0 | 935 | if ((acptr = FindUser(name))) {
|
| slug@0 | 936 | if (users_found++)
|
| slug@0 | 937 | msgq_append(0, mb, " ");
|
| slug@0 | 938 | (*fmt)(acptr, sptr, mb);
|
| slug@0 | 939 | }
|
| slug@0 | 940 | if (5 == ++arg_count)
|
| slug@0 | 941 | break;
|
| slug@0 | 942 | }
|
| slug@0 | 943 | send_buffer(sptr, mb, 0);
|
| slug@0 | 944 | msgq_clean(mb);
|
| slug@0 | 945 | }
|
| slug@0 | 946 |
|
| slug@0 | 947 | /** Set \a flag on \a cptr and possibly hide the client's hostmask.
|
| slug@0 | 948 | * @param[in,out] cptr User who is getting a new flag.
|
| slug@0 | 949 | * @param[in] flag Some flag that affects host-hiding (FLAG_HIDDENHOST, FLAG_ACCOUNT).
|
| slug@0 | 950 | * @return Zero.
|
| slug@0 | 951 | */
|
| slug@0 | 952 | int
|
| slug@0 | 953 | hide_hostmask(struct Client *cptr, unsigned int flag)
|
| slug@0 | 954 | {
|
| slug@0 | 955 | struct Membership *chan;
|
| slug@0 | 956 |
|
| slug@0 | 957 | switch (flag) {
|
| slug@0 | 958 | case FLAG_HIDDENHOST:
|
| slug@0 | 959 | /* Local users cannot set +x unless FEAT_HOST_HIDING is true. */
|
| slug@0 | 960 | if (MyConnect(cptr) && !feature_bool(FEAT_HOST_HIDING))
|
| slug@0 | 961 | return 0;
|
| slug@0 | 962 | break;
|
| slug@0 | 963 | case FLAG_ACCOUNT:
|
| slug@0 | 964 | /* Invalidate all bans against the user so we check them again */
|
| slug@0 | 965 | for (chan = (cli_user(cptr))->channel; chan;
|
| slug@0 | 966 | chan = chan->next_channel)
|
| slug@0 | 967 | ClearBanValid(chan);
|
| slug@0 | 968 | break;
|
| slug@0 | 969 | default:
|
| slug@0 | 970 | return 0;
|
| slug@0 | 971 | }
|
| slug@0 | 972 |
|
| slug@0 | 973 | SetFlag(cptr, flag);
|
| paul@50 | 974 | if (!HasFlag(cptr, FLAG_HIDDENHOST) || !HasFlag(cptr, FLAG_ACCOUNT) || HasSetHost(cptr))
|
| slug@0 | 975 | return 0;
|
| slug@0 | 976 |
|
| slug@0 | 977 | sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Registered");
|
| slug@0 | 978 | ircd_snprintf(0, cli_user(cptr)->host, HOSTLEN, "%s.%s",
|
| slug@0 | 979 | cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
|
| slug@0 | 980 |
|
| slug@0 | 981 | /* ok, the client is now fully hidden, so let them know -- hikari */
|
| slug@0 | 982 | if (MyConnect(cptr))
|
| slug@0 | 983 | send_reply(cptr, RPL_HOSTHIDDEN, cli_user(cptr)->host);
|
| slug@0 | 984 |
|
| slug@0 | 985 | /*
|
| slug@0 | 986 | * Go through all channels the client was on, rejoin him
|
| slug@0 | 987 | * and set the modes, if any
|
| slug@0 | 988 | */
|
| slug@0 | 989 | for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel)
|
| slug@0 | 990 | {
|
| slug@0 | 991 | if (IsZombie(chan))
|
| slug@0 | 992 | continue;
|
| slug@0 | 993 | /* Send a JOIN unless the user's join has been delayed. */
|
| slug@0 | 994 | if (!IsDelayedJoin(chan))
|
| slug@0 | 995 | sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr, 0,
|
| slug@0 | 996 | "%H", chan->channel);
|
| slug@0 | 997 | if (IsChanOp(chan) && HasVoice(chan))
|
| slug@0 | 998 | sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, cptr, 0,
|
| slug@0 | 999 | "%H +ov %C %C", chan->channel, cptr,
|
| slug@0 | 1000 | cptr);
|
| slug@0 | 1001 | else if (IsChanOp(chan) || HasVoice(chan))
|
| slug@0 | 1002 | sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, cptr, 0,
|
| slug@0 | 1003 | "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', cptr);
|
| slug@0 | 1004 | }
|
| slug@0 | 1005 | return 0;
|
| slug@0 | 1006 | }
|
| slug@0 | 1007 |
|
| paul@30 | 1008 | /*
|
| paul@30 | 1009 | * set_hostmask() - derived from hide_hostmask()
|
| paul@30 | 1010 | *
|
| paul@30 | 1011 | */
|
| paul@30 | 1012 | int set_hostmask(struct Client *cptr, char *hostmask, char *password)
|
| paul@30 | 1013 | {
|
| paul@30 | 1014 | int restore = 0;
|
| paul@30 | 1015 | int freeform = 0;
|
| paul@30 | 1016 | char *host, *new_vhost, *vhost_pass;
|
| paul@30 | 1017 | char hiddenhost[USERLEN + HOSTLEN + 2];
|
| paul@30 | 1018 | struct Membership *chan;
|
| paul@30 | 1019 |
|
| paul@30 | 1020 | Debug((DEBUG_INFO, "set_hostmask() %C, %s, %s", cptr, hostmask, password));
|
| paul@30 | 1021 |
|
| paul@30 | 1022 | /* sethost enabled? */
|
| paul@30 | 1023 | if (MyConnect(cptr) && !feature_bool(FEAT_SETHOST)) {
|
| paul@30 | 1024 | send_reply(cptr, ERR_DISABLED, "SETHOST");
|
| paul@30 | 1025 | return 0;
|
| paul@30 | 1026 | }
|
| paul@30 | 1027 |
|
| paul@30 | 1028 | /* sethost enabled for users? */
|
| paul@30 | 1029 | if (MyConnect(cptr) && !IsAnOper(cptr) && !feature_bool(FEAT_SETHOST_USER)) {
|
| paul@30 | 1030 | send_reply(cptr, ERR_NOPRIVILEGES);
|
| paul@30 | 1031 | return 0;
|
| paul@30 | 1032 | }
|
| paul@30 | 1033 |
|
| paul@30 | 1034 | /* MODE_DEL: restore original hostmask */
|
| paul@30 | 1035 | if (EmptyString(hostmask)) {
|
| paul@138 | 1036 | /* is already sethost'ed? and only opers can remove a sethost */
|
| paul@138 | 1037 | if (IsSetHost(cptr) && IsAnOper(cptr)) {
|
| paul@30 | 1038 | restore = 1;
|
| paul@30 | 1039 | sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
|
| paul@30 | 1040 | /* If they are +rx, we need to return to their +x host, not their "real" host */
|
| paul@30 | 1041 | if (HasHiddenHost(cptr))
|
| paul@30 | 1042 | ircd_snprintf(0, cli_user(cptr)->host, HOSTLEN, "%s.%s",
|
| paul@30 | 1043 | cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
|
| paul@30 | 1044 | else
|
| paul@30 | 1045 | strncpy(cli_user(cptr)->host, cli_user(cptr)->realhost, HOSTLEN);
|
| paul@30 | 1046 | strncpy(cli_user(cptr)->username, cli_user(cptr)->realusername, USERLEN);
|
| paul@30 | 1047 | /* log it */
|
| paul@30 | 1048 | if (MyConnect(cptr))
|
| paul@30 | 1049 | log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE,
|
| paul@30 | 1050 | "SETHOST (%s@%s) by (%#R): restoring real hostmask",
|
| paul@30 | 1051 | cli_user(cptr)->username, cli_user(cptr)->host, cptr);
|
| paul@30 | 1052 | } else
|
| paul@30 | 1053 | return 0;
|
| paul@30 | 1054 | /* MODE_ADD: set a new hostmask */
|
| paul@30 | 1055 | } else {
|
| paul@30 | 1056 | /* chop up ident and host.cc */
|
| paul@103 | 1057 | if ((host = strrchr(hostmask, '@'))) { /* oper can specifiy ident@host.cc */
|
| paul@30 | 1058 | *host++ = '\0';
|
| paul@103 | 1059 | if ( MyConnect(cptr) && (0 == strcmp(host, cli_user(cptr)->host)) && (0 == strcmp(hostmask, cli_user(cptr)->username))) {
|
| paul@103 | 1060 | ircd_snprintf(0, hiddenhost, HOSTLEN + USERLEN + 2, "%s@%s",
|
| paul@103 | 1061 | cli_user(cptr)->username, cli_user(cptr)->host);
|
| paul@103 | 1062 | send_reply(cptr, RPL_HOSTHIDDEN, hiddenhost);
|
| paul@103 | 1063 | return 0;
|
| paul@103 | 1064 | }
|
| paul@103 | 1065 | } else { /* user can only specifiy host.cc [password] */
|
| paul@30 | 1066 | host = hostmask;
|
| paul@103 | 1067 | if ( MyConnect(cptr) && (0 == strcmp(host, cli_user(cptr)->host))) {
|
| paul@103 | 1068 | ircd_snprintf(0, hiddenhost, HOSTLEN + USERLEN + 2, "%s@%s",
|
| paul@103 | 1069 | cli_user(cptr)->username, cli_user(cptr)->host);
|
| paul@103 | 1070 | send_reply(cptr, RPL_HOSTHIDDEN, hiddenhost);
|
| paul@103 | 1071 | return 0;
|
| paul@103 | 1072 | }
|
| paul@103 | 1073 | }
|
| paul@30 | 1074 | /*
|
| paul@30 | 1075 | * Oper sethost
|
| paul@30 | 1076 | */
|
| paul@30 | 1077 | if (MyConnect(cptr)) {
|
| paul@30 | 1078 | if (IsAnOper(cptr)) {
|
| paul@30 | 1079 | if ((new_vhost = IsVhost(host, 1)) == NULL) {
|
| paul@52 | 1080 | if (!HasPriv(cptr, PRIV_FREEFORM)) {
|
| paul@30 | 1081 | send_reply(cptr, ERR_HOSTUNAVAIL, hostmask);
|
| paul@30 | 1082 | log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE,
|
| paul@30 | 1083 | "SETHOST (%s@%s) by (%#R): no such s-line",
|
| paul@30 | 1084 | (host != hostmask) ? hostmask : cli_user(cptr)->username, host, cptr);
|
| paul@30 | 1085 | return 0;
|
| paul@30 | 1086 | } else /* freeform active, log and go */
|
| paul@30 | 1087 | freeform = 1;
|
| paul@30 | 1088 | }
|
| paul@30 | 1089 | sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
|
| paul@30 | 1090 | /* set the new ident and host */
|
| paul@30 | 1091 | if (host != hostmask) /* oper only specified host.cc */
|
| paul@30 | 1092 | strncpy(cli_user(cptr)->username, hostmask, USERLEN);
|
| paul@30 | 1093 | strncpy(cli_user(cptr)->host, host, HOSTLEN);
|
| paul@30 | 1094 | /* log it */
|
| paul@30 | 1095 | log_write(LS_SETHOST, (freeform) ? L_NOTICE : L_INFO,
|
| paul@30 | 1096 | (freeform) ? 0 : LOG_NOSNOTICE, "SETHOST (%s@%s) by (%#R)%s",
|
| paul@30 | 1097 | cli_user(cptr)->username, cli_user(cptr)->host, cptr,
|
| paul@30 | 1098 | (freeform) ? ": using freeform" : "");
|
| paul@30 | 1099 | /*
|
| paul@30 | 1100 | * plain user sethost, handled here
|
| paul@30 | 1101 | */
|
| paul@30 | 1102 | } else {
|
| paul@30 | 1103 | /* empty password? */
|
| paul@30 | 1104 | if (EmptyString(password)) {
|
| paul@30 | 1105 | send_reply(cptr, ERR_NEEDMOREPARAMS, "MODE");
|
| paul@30 | 1106 | return 0;
|
| paul@30 | 1107 | }
|
| paul@30 | 1108 | /* no such s-line */
|
| paul@30 | 1109 | if ((new_vhost = IsVhost(host, 0)) == NULL) {
|
| paul@30 | 1110 | send_reply(cptr, ERR_HOSTUNAVAIL, hostmask);
|
| paul@30 | 1111 | log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE, "SETHOST (%s@%s %s) by (%#R): no such s-line",
|
| paul@30 | 1112 | cli_user(cptr)->username, host, password, cptr);
|
| paul@30 | 1113 | return 0;
|
| paul@30 | 1114 | }
|
| paul@30 | 1115 | /* no password */
|
| paul@30 | 1116 | if ((vhost_pass = IsVhostPass(new_vhost)) == NULL) {
|
| paul@30 | 1117 | send_reply(cptr, ERR_PASSWDMISMATCH);
|
| paul@30 | 1118 | log_write(LS_SETHOST, L_INFO, 0, "SETHOST (%s@%s %s) by (%#R): trying to use an oper s-line",
|
| paul@30 | 1119 | cli_user(cptr)->username, host, password, cptr);
|
| paul@30 | 1120 | return 0;
|
| paul@30 | 1121 | }
|
| paul@30 | 1122 | /* incorrect password */
|
| paul@30 | 1123 | if (strCasediff(vhost_pass, password)) {
|
| paul@30 | 1124 | send_reply(cptr, ERR_PASSWDMISMATCH);
|
| paul@30 | 1125 | log_write(LS_SETHOST, L_NOTICE, 0, "SETHOST (%s@%s %s) by (%#R): incorrect password",
|
| paul@30 | 1126 | cli_user(cptr)->username, host, password, cptr);
|
| paul@30 | 1127 | return 0;
|
| paul@30 | 1128 | }
|
| paul@30 | 1129 | sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
|
| paul@30 | 1130 | /* set the new host */
|
| paul@30 | 1131 | strncpy(cli_user(cptr)->host, new_vhost, HOSTLEN);
|
| paul@30 | 1132 | /* log it */
|
| paul@30 | 1133 | log_write(LS_SETHOST, L_INFO, LOG_NOSNOTICE, "SETHOST (%s@%s) by (%#R)",
|
| paul@30 | 1134 | cli_user(cptr)->username, cli_user(cptr)->host, cptr);
|
| paul@30 | 1135 | }
|
| paul@30 | 1136 | } else { /* remote user */
|
| paul@30 | 1137 | sendcmdto_common_channels_butone(cptr, CMD_QUIT, cptr, ":Host change");
|
| paul@30 | 1138 | if (host != hostmask) /* oper only specified host.cc */
|
| paul@30 | 1139 | strncpy(cli_user(cptr)->username, hostmask, USERLEN);
|
| paul@30 | 1140 | strncpy(cli_user(cptr)->host, host, HOSTLEN);
|
| paul@30 | 1141 | }
|
| paul@30 | 1142 | }
|
| paul@30 | 1143 |
|
| paul@30 | 1144 | if (restore)
|
| paul@30 | 1145 | ClearSetHost(cptr);
|
| paul@30 | 1146 | else
|
| paul@30 | 1147 | SetSetHost(cptr);
|
| paul@30 | 1148 |
|
| paul@30 | 1149 | if (MyConnect(cptr)) {
|
| paul@30 | 1150 | ircd_snprintf(0, hiddenhost, HOSTLEN + USERLEN + 2, "%s@%s",
|
| paul@30 | 1151 | cli_user(cptr)->username, cli_user(cptr)->host);
|
| paul@30 | 1152 | send_reply(cptr, RPL_HOSTHIDDEN, hiddenhost);
|
| paul@30 | 1153 | }
|
| paul@30 | 1154 |
|
| paul@30 | 1155 | #if 0
|
| paul@30 | 1156 | /* Code copied from hide_hostmask(). This is the old (pre-delayedjoin)
|
| paul@30 | 1157 | * version. Switch this in if you're not using the delayed join patch. */
|
| paul@30 | 1158 | /*
|
| paul@30 | 1159 | * Go through all channels the client was on, rejoin him
|
| paul@30 | 1160 | * and set the modes, if any
|
| paul@30 | 1161 | */
|
| paul@30 | 1162 | for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) {
|
| paul@30 | 1163 | if (IsZombie(chan))
|
| paul@30 | 1164 | continue;
|
| paul@30 | 1165 | sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr,
|
| paul@30 | 1166 | "%H", chan->channel);
|
| paul@30 | 1167 | if (IsChanOp(chan) && HasVoice(chan)) {
|
| paul@30 | 1168 | sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr,
|
| paul@30 | 1169 | "%H +ov %C %C", chan->channel, cptr, cptr);
|
| paul@30 | 1170 | } else if (IsChanOp(chan) || HasVoice(chan)) {
|
| paul@30 | 1171 | sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr,
|
| paul@30 | 1172 | "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', cptr);
|
| paul@30 | 1173 | }
|
| paul@30 | 1174 | }
|
| paul@30 | 1175 | #endif
|
| paul@30 | 1176 |
|
| paul@30 | 1177 | /*
|
| paul@30 | 1178 | * Go through all channels the client was on, rejoin him
|
| paul@30 | 1179 | * and set the modes, if any
|
| paul@30 | 1180 | */
|
| paul@30 | 1181 | for (chan = cli_user(cptr)->channel; chan; chan = chan->next_channel) {
|
| paul@30 | 1182 | if (IsZombie(chan))
|
| paul@30 | 1183 | continue;
|
| paul@30 | 1184 | /* If this channel has delayed joins and the user has no modes, just set
|
| paul@30 | 1185 | * the delayed join flag rather than showing the join, even if the user
|
| paul@30 | 1186 | * was visible before */
|
| paul@30 | 1187 | if (!IsChanOp(chan) && !HasVoice(chan)
|
| paul@30 | 1188 | && (chan->channel->mode.mode & MODE_DELJOINS)) {
|
| paul@30 | 1189 | SetDelayedJoin(chan);
|
| paul@30 | 1190 | } else {
|
| paul@30 | 1191 | sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr, 0,
|
| paul@30 | 1192 | "%H", chan->channel);
|
| paul@30 | 1193 | }
|
| paul@30 | 1194 | if (IsChanOp(chan) && HasVoice(chan)) {
|
| paul@75 | 1195 | sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, cptr, 0,
|
| paul@30 | 1196 | "%H +ov %C %C", chan->channel, cptr, cptr);
|
| paul@30 | 1197 | } else if (IsChanOp(chan) || HasVoice(chan)) {
|
| paul@75 | 1198 | sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, cptr, 0,
|
| paul@30 | 1199 | "%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', cptr);
|
| paul@30 | 1200 | }
|
| paul@30 | 1201 | }
|
| paul@30 | 1202 | return 1;
|
| paul@30 | 1203 | }
|
| paul@30 | 1204 |
|
| slug@0 | 1205 | /** Set a user's mode. This function checks that \a cptr is trying to
|
| slug@0 | 1206 | * set his own mode, prevents local users from setting inappropriate
|
| slug@0 | 1207 | * modes through this function, and applies any other side effects of
|
| slug@0 | 1208 | * a successful mode change.
|
| slug@0 | 1209 | *
|
| slug@0 | 1210 | * @param[in,out] cptr User setting someone's mode.
|
| slug@0 | 1211 | * @param[in] sptr Client who sent the mode change message.
|
| slug@0 | 1212 | * @param[in] parc Number of parameters in \a parv.
|
| slug@0 | 1213 | * @param[in] parv Parameters to MODE.
|
| paul@115 | 1214 | * @param[in] allow_modes ALLOWMODES_ANY for any mode, ALLOWMODES_DEFAULT for
|
| paul@115 | 1215 | * only permitting legitimate default user modes.
|
| slug@0 | 1216 | * @return Zero.
|
| slug@0 | 1217 | */
|
| paul@115 | 1218 | int set_user_mode(struct Client *cptr, struct Client *sptr, int parc,
|
| paul@115 | 1219 | char *parv[], int allow_modes)
|
| slug@0 | 1220 | {
|
| slug@0 | 1221 | char** p;
|
| slug@0 | 1222 | char* m;
|
| slug@0 | 1223 | int what;
|
| slug@0 | 1224 | int i;
|
| slug@0 | 1225 | struct Flags setflags;
|
| slug@0 | 1226 | unsigned int tmpmask = 0;
|
| slug@0 | 1227 | int snomask_given = 0;
|
| slug@0 | 1228 | char buf[BUFSIZE];
|
| paul@117 | 1229 | char *hostmask, *password;
|
| slug@0 | 1230 | int prop = 0;
|
| slug@0 | 1231 | int do_host_hiding = 0;
|
| paul@30 | 1232 | int do_set_host = 0;
|
| paul@80 | 1233 | size_t opernamelen;
|
| paul@116 | 1234 | char *opername = 0;
|
| paul@115 | 1235 | char* account = NULL;
|
| slug@0 | 1236 |
|
| paul@30 | 1237 | hostmask = password = NULL;
|
| slug@0 | 1238 | what = MODE_ADD;
|
| slug@0 | 1239 |
|
| slug@0 | 1240 | if (parc < 3)
|
| slug@0 | 1241 | {
|
| slug@0 | 1242 | m = buf;
|
| slug@0 | 1243 | *m++ = '+';
|
| slug@0 | 1244 | for (i = 0; i < USERMODELIST_SIZE; i++)
|
| slug@0 | 1245 | {
|
| slug@0 | 1246 | if (HasFlag(sptr, userModeList[i].flag) &&
|
| paul@30 | 1247 | ((userModeList[i].flag != FLAG_ACCOUNT) &&
|
| paul@30 | 1248 | (userModeList[i].flag != FLAG_SETHOST)))
|
| slug@0 | 1249 | *m++ = userModeList[i].c;
|
| slug@0 | 1250 | }
|
| slug@0 | 1251 | *m = '\0';
|
| slug@0 | 1252 | send_reply(sptr, RPL_UMODEIS, buf);
|
| slug@0 | 1253 | if (HasFlag(sptr, FLAG_SERVNOTICE) && MyConnect(sptr)
|
| slug@0 | 1254 | && cli_snomask(sptr) !=
|
| slug@0 | 1255 | (unsigned int)(IsOper(sptr) ? SNO_OPERDEFAULT : SNO_DEFAULT))
|
| slug@0 | 1256 | send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr));
|
| slug@0 | 1257 | return 0;
|
| slug@0 | 1258 | }
|
| slug@0 | 1259 |
|
| slug@0 | 1260 | /*
|
| slug@0 | 1261 | * find flags already set for user
|
| slug@0 | 1262 | * why not just copy them?
|
| slug@0 | 1263 | */
|
| slug@0 | 1264 | setflags = cli_flags(sptr);
|
| slug@0 | 1265 |
|
| slug@0 | 1266 | if (MyConnect(sptr))
|
| slug@0 | 1267 | tmpmask = cli_snomask(sptr);
|
| slug@0 | 1268 |
|
| slug@0 | 1269 | /*
|
| slug@0 | 1270 | * parse mode change string(s)
|
| slug@0 | 1271 | */
|
| paul@115 | 1272 | for (p = &parv[2]; *p && p<&parv[parc]; p++) { /* p is changed in loop too */
|
| slug@0 | 1273 | for (m = *p; *m; m++) {
|
| slug@0 | 1274 | switch (*m) {
|
| slug@0 | 1275 | case '+':
|
| slug@0 | 1276 | what = MODE_ADD;
|
| slug@0 | 1277 | break;
|
| slug@0 | 1278 | case '-':
|
| slug@0 | 1279 | what = MODE_DEL;
|
| slug@0 | 1280 | break;
|
| slug@0 | 1281 | case 's':
|
| slug@0 | 1282 | if (*(p + 1) && is_snomask(*(p + 1))) {
|
| slug@0 | 1283 | snomask_given = 1;
|
| slug@0 | 1284 | tmpmask = umode_make_snomask(tmpmask, *++p, what);
|
| slug@0 | 1285 | tmpmask &= (IsAnOper(sptr) ? SNO_ALL : SNO_USER);
|
| slug@0 | 1286 | }
|
| slug@0 | 1287 | else
|
| slug@0 | 1288 | tmpmask = (what == MODE_ADD) ?
|
| slug@0 | 1289 | (IsAnOper(sptr) ? SNO_OPERDEFAULT : SNO_DEFAULT) : 0;
|
| slug@0 | 1290 | if (tmpmask)
|
| slug@0 | 1291 | SetServNotice(sptr);
|
| slug@0 | 1292 | else
|
| slug@0 | 1293 | ClearServNotice(sptr);
|
| slug@0 | 1294 | break;
|
| slug@0 | 1295 | case 'w':
|
| slug@0 | 1296 | if (what == MODE_ADD)
|
| slug@0 | 1297 | SetWallops(sptr);
|
| slug@0 | 1298 | else
|
| slug@0 | 1299 | ClearWallops(sptr);
|
| slug@0 | 1300 | break;
|
| slug@0 | 1301 | case 'o':
|
| paul@80 | 1302 | if (what == MODE_ADD) {
|
| slug@0 | 1303 | SetOper(sptr);
|
| paul@80 | 1304 | if (IsServer(cptr) && IsSendOperName(cptr)) {
|
| paul@80 | 1305 | if (*(p + 1)) {
|
| paul@80 | 1306 | opername = *++p;
|
| paul@80 | 1307 | if (cli_user(sptr)->opername)
|
| paul@80 | 1308 | MyFree(cli_user(sptr)->opername);
|
| paul@80 | 1309 | if ((opername[0] == NOOPERNAMECHARACTER) && (opername[1] == '\0')) {
|
| paul@80 | 1310 | cli_user(sptr)->opername = NULL;
|
| paul@80 | 1311 | } else {
|
| paul@80 | 1312 | opernamelen = strlen(opername);
|
| paul@80 | 1313 | if (opernamelen > ACCOUNTLEN) {
|
| paul@80 | 1314 | protocol_violation(cptr, "Received opername (%s) longer than %d for %s; ignoring.", opername, ACCOUNTLEN, cli_name(sptr));
|
| paul@80 | 1315 | cli_user(sptr)->opername = NULL;
|
| paul@80 | 1316 | } else {
|
| paul@80 | 1317 | cli_user(sptr)->opername = (char*) MyMalloc(opernamelen + 1);
|
| paul@80 | 1318 | assert(0 != cli_user(sptr)->opername);
|
| paul@80 | 1319 | ircd_strncpy(cli_user(sptr)->opername,opername,ACCOUNTLEN);
|
| paul@80 | 1320 | }
|
| paul@80 | 1321 | }
|
| paul@80 | 1322 | }
|
| paul@80 | 1323 | }
|
| paul@80 | 1324 | } else {
|
| slug@0 | 1325 | ClrFlag(sptr, FLAG_OPER);
|
| slug@0 | 1326 | ClrFlag(sptr, FLAG_LOCOP);
|
| slug@0 | 1327 | if (MyConnect(sptr))
|
| slug@0 | 1328 | {
|
| slug@0 | 1329 | tmpmask = cli_snomask(sptr) & ~SNO_OPER;
|
| slug@0 | 1330 | cli_handler(sptr) = CLIENT_HANDLER;
|
| slug@0 | 1331 | }
|
| slug@0 | 1332 | }
|
| slug@0 | 1333 | break;
|
| slug@0 | 1334 | case 'O':
|
| slug@0 | 1335 | if (what == MODE_ADD)
|
| slug@0 | 1336 | SetLocOp(sptr);
|
| slug@0 | 1337 | else
|
| slug@0 | 1338 | {
|
| slug@0 | 1339 | ClrFlag(sptr, FLAG_OPER);
|
| slug@0 | 1340 | ClrFlag(sptr, FLAG_LOCOP);
|
| slug@0 | 1341 | if (MyConnect(sptr))
|
| slug@0 | 1342 | {
|
| slug@0 | 1343 | tmpmask = cli_snomask(sptr) & ~SNO_OPER;
|
| slug@0 | 1344 | cli_handler(sptr) = CLIENT_HANDLER;
|
| slug@0 | 1345 | }
|
| slug@0 | 1346 | }
|
| slug@0 | 1347 | break;
|
| slug@0 | 1348 | case 'i':
|
| slug@0 | 1349 | if (what == MODE_ADD)
|
| slug@0 | 1350 | SetInvisible(sptr);
|
| slug@0 | 1351 | else
|
| paul@30 | 1352 | if (!feature_bool(FEAT_AUTOINVISIBLE) || IsOper(sptr)) /* Don't allow non-opers to -i if FEAT_AUTOINVISIBLE is set */
|
| paul@30 | 1353 | ClearInvisible(sptr);
|
| slug@0 | 1354 | break;
|
| slug@0 | 1355 | case 'd':
|
| slug@0 | 1356 | if (what == MODE_ADD)
|
| slug@0 | 1357 | SetDeaf(sptr);
|
| slug@0 | 1358 | else
|
| slug@0 | 1359 | ClearDeaf(sptr);
|
| slug@0 | 1360 | break;
|
| slug@0 | 1361 | case 'k':
|
| slug@0 | 1362 | if (what == MODE_ADD)
|
| slug@0 | 1363 | SetChannelService(sptr);
|
| slug@0 | 1364 | else
|
| slug@0 | 1365 | ClearChannelService(sptr);
|
| slug@0 | 1366 | break;
|
| paul@30 | 1367 | case 'X':
|
| paul@30 | 1368 | if (what == MODE_ADD)
|
| paul@30 | 1369 | SetXtraOp(sptr);
|
| paul@30 | 1370 | else
|
| paul@30 | 1371 | ClearXtraOp(sptr);
|
| paul@30 | 1372 | break;
|
| paul@30 | 1373 | case 'n':
|
| paul@30 | 1374 | if (what == MODE_ADD)
|
| paul@30 | 1375 | SetNoChan(sptr);
|
| paul@30 | 1376 | else
|
| paul@30 | 1377 | ClearNoChan(sptr);
|
| paul@30 | 1378 | break;
|
| paul@30 | 1379 | case 'I':
|
| paul@30 | 1380 | if (what == MODE_ADD)
|
| paul@30 | 1381 | SetNoIdle(sptr);
|
| paul@30 | 1382 | else
|
| paul@30 | 1383 | ClearNoIdle(sptr);
|
| paul@30 | 1384 | break;
|
| slug@0 | 1385 | case 'g':
|
| slug@0 | 1386 | if (what == MODE_ADD)
|
| slug@0 | 1387 | SetDebug(sptr);
|
| slug@0 | 1388 | else
|
| slug@0 | 1389 | ClearDebug(sptr);
|
| slug@0 | 1390 | break;
|
| slug@0 | 1391 | case 'x':
|
| slug@0 | 1392 | if (what == MODE_ADD)
|
| paul@30 | 1393 | do_host_hiding = 1;
|
| paul@30 | 1394 | break;
|
| paul@30 | 1395 | case 'h':
|
| paul@30 | 1396 | if (what == MODE_ADD) {
|
| paul@30 | 1397 | if (*(p + 1) && is_hostmask(*(p + 1))) {
|
| paul@30 | 1398 | do_set_host = 1;
|
| paul@30 | 1399 | hostmask = *++p;
|
| paul@30 | 1400 | /* DON'T step p onto the trailing NULL in the parameter array! - splidge */
|
| paul@30 | 1401 | if (*(p+1))
|
| paul@30 | 1402 | password = *++p;
|
| paul@30 | 1403 | else
|
| paul@30 | 1404 | password = NULL;
|
| paul@30 | 1405 | } else {
|
| paul@30 | 1406 | if (!*(p+1))
|
| paul@30 | 1407 | send_reply(sptr, ERR_NEEDMOREPARAMS, "SETHOST");
|
| paul@30 | 1408 | else {
|
| paul@30 | 1409 | send_reply(sptr, ERR_BADHOSTMASK, *(p+1));
|
| paul@30 | 1410 | p++; /* Swallow the arg anyway */
|
| paul@30 | 1411 | }
|
| paul@30 | 1412 | }
|
| paul@30 | 1413 | } else { /* MODE_DEL */
|
| paul@30 | 1414 | do_set_host = 1;
|
| paul@30 | 1415 | hostmask = NULL;
|
| paul@30 | 1416 | password = NULL;
|
| paul@30 | 1417 | }
|
| paul@30 | 1418 | break;
|
| paul@30 | 1419 | case 'R':
|
| paul@30 | 1420 | if (what == MODE_ADD)
|
| paul@30 | 1421 | SetAccountOnly(sptr);
|
| paul@30 | 1422 | else
|
| paul@30 | 1423 | ClearAccountOnly(sptr);
|
| paul@30 | 1424 | break;
|
| paul@30 | 1425 | case 'P':
|
| paul@30 | 1426 | if (what == MODE_ADD)
|
| paul@30 | 1427 | SetParanoid(sptr);
|
| paul@30 | 1428 | else
|
| paul@30 | 1429 | ClearParanoid(sptr);
|
| slug@0 | 1430 | break;
|
| paul@115 | 1431 | case 'r':
|
| chris@147 | 1432 | if ((what == MODE_ADD) && *(p + 1)) {
|
| paul@115 | 1433 | account = *(++p);
|
| paul@115 | 1434 | SetAccount(sptr);
|
| paul@115 | 1435 | }
|
| paul@115 | 1436 | /* There is no -r */
|
| paul@115 | 1437 | break;
|
| slug@0 | 1438 | default:
|
| slug@0 | 1439 | send_reply(sptr, ERR_UMODEUNKNOWNFLAG, *m);
|
| slug@0 | 1440 | break;
|
| slug@0 | 1441 | }
|
| slug@0 | 1442 | }
|
| slug@0 | 1443 | }
|
| slug@0 | 1444 | /*
|
| slug@0 | 1445 | * Evaluate rules for new user mode
|
| slug@0 | 1446 | * Stop users making themselves operators too easily:
|
| slug@0 | 1447 | */
|
| slug@0 | 1448 | if (!IsServer(cptr))
|
| slug@0 | 1449 | {
|
| slug@0 | 1450 | if (!FlagHas(&setflags, FLAG_OPER) && IsOper(sptr))
|
| slug@0 | 1451 | ClearOper(sptr);
|
| slug@0 | 1452 | if (!FlagHas(&setflags, FLAG_LOCOP) && IsLocOp(sptr))
|
| slug@0 | 1453 | ClearLocOp(sptr);
|
| paul@115 | 1454 | if (!FlagHas(&setflags, FLAG_ACCOUNT) && IsAccount(sptr))
|
| paul@115 | 1455 | ClrFlag(sptr, FLAG_ACCOUNT);
|
| slug@0 | 1456 | /*
|
| slug@0 | 1457 | * new umode; servers can set it, local users cannot;
|
| slug@0 | 1458 | * prevents users from /kick'ing or /mode -o'ing
|
| slug@0 | 1459 | */
|
| paul@52 | 1460 | if (!FlagHas(&setflags, FLAG_CHSERV) && !(IsOper(sptr) && HasPriv(sptr, PRIV_CHANSERV)))
|
| slug@0 | 1461 | ClearChannelService(sptr);
|
| paul@52 | 1462 | if (!FlagHas(&setflags, FLAG_XTRAOP) && !(IsOper(sptr) && HasPriv(sptr, PRIV_XTRA_OPER)))
|
| paul@30 | 1463 | ClearXtraOp(sptr);
|
| paul@30 | 1464 | if (!FlagHas(&setflags, FLAG_NOCHAN) && !(IsOper(sptr) || feature_bool(FEAT_USER_HIDECHANS)))
|
| paul@30 | 1465 | ClearNoChan(sptr);
|
| paul@52 | 1466 | if (!FlagHas(&setflags, FLAG_NOIDLE) && !((IsOper(sptr) && HasPriv(sptr, PRIV_NOIDLE)) || feature_bool(FEAT_USER_HIDEIDLETIME)))
|
| paul@30 | 1467 | ClearNoIdle(sptr);
|
| paul@52 | 1468 | if (!FlagHas(&setflags, FLAG_PARANOID) && !(IsOper(sptr) && HasPriv(sptr, PRIV_PARANOID)))
|
| paul@30 | 1469 | ClearParanoid(sptr);
|
| paul@30 | 1470 |
|
| slug@0 | 1471 | /*
|
| slug@0 | 1472 | * only send wallops to opers
|
| slug@0 | 1473 | */
|
| slug@0 | 1474 | if (feature_bool(FEAT_WALLOPS_OPER_ONLY) && !IsAnOper(sptr) &&
|
| slug@0 | 1475 | !FlagHas(&setflags, FLAG_WALLOP))
|
| slug@0 | 1476 | ClearWallops(sptr);
|
| slug@0 | 1477 | if (feature_bool(FEAT_HIS_SNOTICES_OPER_ONLY) && MyConnect(sptr) &&
|
| slug@0 | 1478 | !IsAnOper(sptr) && !FlagHas(&setflags, FLAG_SERVNOTICE))
|
| slug@0 | 1479 | {
|
| slug@0 | 1480 | ClearServNotice(sptr);
|
| slug@0 | 1481 | set_snomask(sptr, 0, SNO_SET);
|
| slug@0 | 1482 | }
|
| slug@0 | 1483 | if (feature_bool(FEAT_HIS_DEBUG_OPER_ONLY) &&
|
| slug@0 | 1484 | !IsAnOper(sptr) && !FlagHas(&setflags, FLAG_DEBUG))
|
| slug@0 | 1485 | ClearDebug(sptr);
|
| slug@0 | 1486 | }
|
| slug@0 | 1487 | if (MyConnect(sptr))
|
| slug@0 | 1488 | {
|
| slug@0 | 1489 | if ((FlagHas(&setflags, FLAG_OPER) || FlagHas(&setflags, FLAG_LOCOP)) &&
|
| slug@0 | 1490 | !IsAnOper(sptr))
|
| slug@0 | 1491 | det_confs_butmask(sptr, CONF_CLIENT & ~CONF_OPERATOR);
|
| slug@0 | 1492 |
|
| slug@0 | 1493 | if (SendServNotice(sptr))
|
| slug@0 | 1494 | {
|
| slug@0 | 1495 | if (tmpmask != cli_snomask(sptr))
|
| slug@0 | 1496 | set_snomask(sptr, tmpmask, SNO_SET);
|
| slug@0 | 1497 | if (cli_snomask(sptr) && snomask_given)
|
| slug@0 | 1498 | send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr));
|
| slug@0 | 1499 | }
|
| slug@0 | 1500 | else
|
| slug@0 | 1501 | set_snomask(sptr, 0, SNO_SET);
|
| slug@0 | 1502 | }
|
| slug@0 | 1503 | /*
|
| slug@0 | 1504 | * Compare new flags with old flags and send string which
|
| slug@0 | 1505 | * will cause servers to update correctly.
|
| slug@0 | 1506 | */
|
| paul@115 | 1507 | if (!FlagHas(&setflags, FLAG_ACCOUNT) && IsAccount(sptr)) {
|
| paul@115 | 1508 | int len = ACCOUNTLEN;
|
| paul@116 | 1509 | char *pts, *ts;
|
| paul@115 | 1510 | if ((ts = strchr(account, ':'))) {
|
| paul@115 | 1511 | len = (ts++) - account;
|
| paul@115 | 1512 | cli_user(sptr)->acc_create = atoi(ts);
|
| paul@116 | 1513 | if ((pts = strchr(ts, ':')))
|
| paul@117 | 1514 | cli_user(sptr)->acc_id = strtoul(pts + 1, NULL, 10);
|
| paul@116 | 1515 | Debug((DEBUG_DEBUG, "Received timestamped account in user mode; "
|
| paul@116 | 1516 | "account \"%s\", timestamp %Tu, id %lu", account,
|
| paul@116 | 1517 | cli_user(sptr)->acc_create,
|
| paul@117 | 1518 | cli_user(sptr)->acc_id));
|
| paul@115 | 1519 | }
|
| paul@115 | 1520 | ircd_strncpy(cli_user(sptr)->account, account, len);
|
| paul@115 | 1521 | }
|
| paul@115 | 1522 | if (!FlagHas(&setflags, FLAG_HIDDENHOST) && do_host_hiding && allow_modes != ALLOWMODES_DEFAULT)
|
| slug@0 | 1523 | hide_hostmask(sptr, FLAG_HIDDENHOST);
|
| paul@30 | 1524 | if (do_set_host) {
|
| paul@30 | 1525 | /* We clear the flag in the old mask, so that the +h will be sent */
|
| paul@30 | 1526 | /* Only do this if we're SETTING +h and it succeeded */
|
| paul@30 | 1527 | if (set_hostmask(sptr, hostmask, password) && hostmask)
|
| paul@30 | 1528 | FlagClr(&setflags, FLAG_SETHOST);
|
| paul@30 | 1529 | }
|
| paul@126 | 1530 |
|
| paul@126 | 1531 | if (IsRegistered(sptr)) {
|
| paul@126 | 1532 | if (!FlagHas(&setflags, FLAG_OPER) && IsOper(sptr)) {
|
| paul@126 | 1533 | /* user now oper */
|
| paul@126 | 1534 | ++UserStats.opers;
|
| paul@126 | 1535 | client_set_privs(sptr, NULL); /* may set propagate privilege */
|
| paul@126 | 1536 | }
|
| paul@126 | 1537 | /* remember propagate privilege setting */
|
| paul@126 | 1538 | if (HasPriv(sptr, PRIV_PROPAGATE)) {
|
| paul@126 | 1539 | prop = 1;
|
| paul@126 | 1540 | }
|
| paul@126 | 1541 | if (FlagHas(&setflags, FLAG_OPER) && !IsOper(sptr)) {
|
| paul@126 | 1542 | /* user no longer oper */
|
| paul@126 | 1543 | assert(UserStats.opers > 0);
|
| paul@126 | 1544 | --UserStats.opers;
|
| paul@126 | 1545 | client_set_privs(sptr, NULL); /* will clear propagate privilege */
|
| paul@127 | 1546 | if (cli_user(sptr)->opername) {
|
| paul@127 | 1547 | MyFree(cli_user(sptr)->opername);
|
| paul@127 | 1548 | cli_user(sptr)->opername = NULL;
|
| paul@127 | 1549 | }
|
| paul@126 | 1550 | }
|
| paul@126 | 1551 | if (FlagHas(&setflags, FLAG_INVISIBLE) && !IsInvisible(sptr)) {
|
| paul@126 | 1552 | assert(UserStats.inv_clients > 0);
|
| paul@126 | 1553 | --UserStats.inv_clients;
|
| paul@126 | 1554 | }
|
| paul@126 | 1555 | if (!FlagHas(&setflags, FLAG_INVISIBLE) && IsInvisible(sptr)) {
|
| paul@126 | 1556 | ++UserStats.inv_clients;
|
| paul@126 | 1557 | }
|
| paul@126 | 1558 | assert(UserStats.opers <= UserStats.clients + UserStats.unknowns);
|
| paul@126 | 1559 | assert(UserStats.inv_clients <= UserStats.clients + UserStats.unknowns);
|
| paul@101 | 1560 | send_umode_out(cptr, sptr, &setflags, prop);
|
| paul@126 | 1561 | }
|
| slug@0 | 1562 |
|
| slug@0 | 1563 | return 0;
|
| slug@0 | 1564 | }
|
| slug@0 | 1565 |
|
| slug@0 | 1566 | /** Build a mode string to describe modes for \a cptr.
|
| slug@0 | 1567 | * @param[in] cptr Some user.
|
| slug@0 | 1568 | * @return Pointer to a static buffer.
|
| slug@0 | 1569 | */
|
| paul@80 | 1570 | char *umode_str(struct Client *cptr, int opernames)
|
| slug@0 | 1571 | {
|
| slug@0 | 1572 | /* Maximum string size: "owidgrx\0" */
|
| slug@0 | 1573 | char *m = umodeBuf;
|
| slug@0 | 1574 | int i;
|
| slug@0 | 1575 | struct Flags c_flags = cli_flags(cptr);
|
| slug@0 | 1576 |
|
| slug@0 | 1577 | if (!HasPriv(cptr, PRIV_PROPAGATE))
|
| slug@0 | 1578 | FlagClr(&c_flags, FLAG_OPER);
|
| slug@0 | 1579 |
|
| slug@0 | 1580 | for (i = 0; i < USERMODELIST_SIZE; ++i)
|
| slug@0 | 1581 | {
|
| slug@0 | 1582 | if (FlagHas(&c_flags, userModeList[i].flag) &&
|
| slug@0 | 1583 | userModeList[i].flag >= FLAG_GLOBAL_UMODES)
|
| slug@0 | 1584 | *m++ = userModeList[i].c;
|
| slug@0 | 1585 | }
|
| slug@0 | 1586 |
|
| paul@80 | 1587 | if (opernames && IsOper(cptr))
|
| paul@80 | 1588 | {
|
| paul@80 | 1589 | *m++ = ' ';
|
| paul@80 | 1590 | if (cli_user(cptr)->opername) {
|
| paul@80 | 1591 | char* t = cli_user(cptr)->opername;
|
| paul@80 | 1592 | while ((*m++ = *t++))
|
| paul@80 | 1593 | ; /* Empty loop */
|
| paul@81 | 1594 | m--; /* Step back over the '\0' */
|
| paul@80 | 1595 | } else {
|
| paul@80 | 1596 | *m++ = NOOPERNAMECHARACTER;
|
| paul@80 | 1597 | }
|
| paul@80 | 1598 | }
|
| paul@80 | 1599 |
|
| slug@0 | 1600 | if (IsAccount(cptr))
|
| slug@0 | 1601 | {
|
| slug@0 | 1602 | char* t = cli_user(cptr)->account;
|
| slug@0 | 1603 |
|
| slug@0 | 1604 | *m++ = ' ';
|
| slug@0 | 1605 | while ((*m++ = *t++))
|
| slug@0 | 1606 | ; /* Empty loop */
|
| slug@0 | 1607 |
|
| slug@0 | 1608 | if (cli_user(cptr)->acc_create) {
|
| cruicky@83 | 1609 | char nbuf[30];
|
| slug@0 | 1610 | Debug((DEBUG_DEBUG, "Sending timestamped account in user mode for "
|
| slug@0 | 1611 | "account \"%s\"; timestamp %Tu", cli_user(cptr)->account,
|
| slug@0 | 1612 | cli_user(cptr)->acc_create));
|
| paul@38 | 1613 | if(cli_user(cptr)->acc_id) {
|
| paul@38 | 1614 | ircd_snprintf(0, t = nbuf, sizeof(nbuf), ":%Tu:%lu",
|
| paul@38 | 1615 | cli_user(cptr)->acc_create, cli_user(cptr)->acc_id);
|
| paul@38 | 1616 | } else {
|
| paul@38 | 1617 | ircd_snprintf(0, t = nbuf, sizeof(nbuf), ":%Tu",
|
| paul@38 | 1618 | cli_user(cptr)->acc_create);
|
| paul@38 | 1619 | }
|
| slug@0 | 1620 | m--; /* back up over previous nul-termination */
|
| slug@0 | 1621 | while ((*m++ = *t++))
|
| slug@0 | 1622 | ; /* Empty loop */
|
| slug@0 | 1623 | }
|
| paul@30 | 1624 | m--; /* Step back over the '\0' */
|
| slug@0 | 1625 | }
|
| slug@0 | 1626 |
|
| paul@30 | 1627 | if (IsSetHost(cptr)) {
|
| paul@30 | 1628 | *m++ = ' ';
|
| paul@30 | 1629 | ircd_snprintf(0, m, USERLEN + HOSTLEN + 2, "%s@%s", cli_user(cptr)->username,
|
| paul@30 | 1630 | cli_user(cptr)->host);
|
| paul@30 | 1631 | } else
|
| paul@30 | 1632 | *m = '\0';
|
| slug@0 | 1633 | return umodeBuf; /* Note: static buffer, gets
|
| slug@0 | 1634 | overwritten by send_umode() */
|
| slug@0 | 1635 | }
|
| slug@0 | 1636 |
|
| slug@0 | 1637 | /** Send a mode change string for \a sptr to \a cptr.
|
| slug@0 | 1638 | * @param[in] cptr Destination of mode change message.
|
| slug@0 | 1639 | * @param[in] sptr User whose mode has changed.
|
| slug@0 | 1640 | * @param[in] old Pre-change set of modes for \a sptr.
|
| slug@0 | 1641 | * @param[in] sendset One of ALL_UMODES, SEND_UMODES_BUT_OPER,
|
| slug@0 | 1642 | * SEND_UMODES, to select which changed user modes to send.
|
| slug@0 | 1643 | */
|
| slug@0 | 1644 | void send_umode(struct Client *cptr, struct Client *sptr, struct Flags *old,
|
| paul@80 | 1645 | int sendset, int opernames)
|
| slug@0 | 1646 | {
|
| slug@0 | 1647 | int i;
|
| slug@0 | 1648 | int flag;
|
| paul@30 | 1649 | int needhost = 0;
|
| paul@80 | 1650 | int needoper = 0;
|
| slug@0 | 1651 | char *m;
|
| slug@0 | 1652 | int what = MODE_NULL;
|
| slug@0 | 1653 |
|
| slug@0 | 1654 | /*
|
| slug@0 | 1655 | * Build a string in umodeBuf to represent the change in the user's
|
| slug@0 | 1656 | * mode between the new (cli_flags(sptr)) and 'old', but skipping
|
| slug@0 | 1657 | * the modes indicated by sendset.
|
| slug@0 | 1658 | */
|
| slug@0 | 1659 | m = umodeBuf;
|
| slug@0 | 1660 | *m = '\0';
|
| slug@0 | 1661 | for (i = 0; i < USERMODELIST_SIZE; ++i)
|
| slug@0 | 1662 | {
|
| slug@0 | 1663 | flag = userModeList[i].flag;
|
| slug@0 | 1664 | if (FlagHas(old, flag)
|
| slug@0 | 1665 | == HasFlag(sptr, flag))
|
| slug@0 | 1666 | continue;
|
| slug@0 | 1667 | switch (sendset)
|
| slug@0 | 1668 | {
|
| slug@0 | 1669 | case ALL_UMODES:
|
| slug@0 | 1670 | break;
|
| slug@0 | 1671 | case SEND_UMODES_BUT_OPER:
|
| slug@0 | 1672 | if (flag == FLAG_OPER)
|
| slug@0 | 1673 | continue;
|
| slug@0 | 1674 | /* and fall through */
|
| slug@0 | 1675 | case SEND_UMODES:
|
| slug@0 | 1676 | if (flag < FLAG_GLOBAL_UMODES)
|
| slug@0 | 1677 | continue;
|
| slug@0 | 1678 | break;
|
| slug@0 | 1679 | }
|
| paul@80 | 1680 | /* Special case for OPER.. */
|
| paul@80 | 1681 | if (flag == FLAG_OPER) {
|
| paul@80 | 1682 | /* If we're setting +o, add the opername later */
|
| paul@80 | 1683 | if (!FlagHas(old, flag))
|
| paul@80 | 1684 | needoper++;
|
| paul@80 | 1685 | }
|
| paul@30 | 1686 | /* Special case for SETHOST.. */
|
| paul@30 | 1687 | if (flag == FLAG_SETHOST) {
|
| paul@30 | 1688 | /* Don't send to users */
|
| paul@30 | 1689 | if (cptr && MyUser(cptr))
|
| paul@30 | 1690 | continue;
|
| paul@30 | 1691 |
|
| paul@30 | 1692 | /* If we're setting +h, add the parameter later */
|
| paul@30 | 1693 | if (!FlagHas(old, flag))
|
| paul@30 | 1694 | needhost++;
|
| paul@30 | 1695 | }
|
| slug@0 | 1696 | if (FlagHas(old, flag))
|
| slug@0 | 1697 | {
|
| slug@0 | 1698 | if (what == MODE_DEL)
|
| slug@0 | 1699 | *m++ = userModeList[i].c;
|
| slug@0 | 1700 | else
|
| slug@0 | 1701 | {
|
| slug@0 | 1702 | what = MODE_DEL;
|
| slug@0 | 1703 | *m++ = '-';
|
| slug@0 | 1704 | *m++ = userModeList[i].c;
|
| slug@0 | 1705 | }
|
| slug@0 | 1706 | }
|
| slug@0 | 1707 | else /* !FlagHas(old, flag) */
|
| slug@0 | 1708 | {
|
| slug@0 | 1709 | if (what == MODE_ADD)
|
| slug@0 | 1710 | *m++ = userModeList[i].c;
|
| slug@0 | 1711 | else
|
| slug@0 | 1712 | {
|
| slug@0 | 1713 | what = MODE_ADD;
|
| slug@0 | 1714 | *m++ = '+';
|
| slug@0 | 1715 | *m++ = userModeList[i].c;
|
| slug@0 | 1716 | }
|
| slug@0 | 1717 | }
|
| slug@0 | 1718 | }
|
| paul@80 | 1719 | if (opernames && needoper) {
|
| paul@80 | 1720 | *m++ = ' ';
|
| paul@80 | 1721 | if (cli_user(sptr)->opername) {
|
| paul@80 | 1722 | char* t = cli_user(sptr)->opername;
|
| paul@80 | 1723 | while ((*m++ = *t++))
|
| paul@80 | 1724 | ; /* Empty loop */
|
| cruicky@84 | 1725 | m--; /* Step back over the '\0' */
|
| paul@80 | 1726 | } else {
|
| paul@80 | 1727 | *m++ = NOOPERNAMECHARACTER;
|
| paul@80 | 1728 | }
|
| paul@80 | 1729 | }
|
| paul@30 | 1730 | if (needhost) {
|
| paul@30 | 1731 | *m++ = ' ';
|
| paul@30 | 1732 | ircd_snprintf(0, m, USERLEN + HOSTLEN + 1, "%s@%s", cli_user(sptr)->username,
|
| paul@30 | 1733 | cli_user(sptr)->host);
|
| paul@30 | 1734 | } else
|
| paul@30 | 1735 | *m = '\0';
|
| slug@0 | 1736 | if (*umodeBuf && cptr)
|
| paul@30 | 1737 | sendcmdto_one(sptr, CMD_MODE, cptr, "%s %s", cli_name(sptr), umodeBuf);
|
| slug@0 | 1738 | }
|
| slug@0 | 1739 |
|
| slug@0 | 1740 | /**
|
| slug@0 | 1741 | * Check to see if this resembles a sno_mask. It is if 1) there is
|
| slug@0 | 1742 | * at least one digit and 2) The first digit occurs before the first
|
| slug@0 | 1743 | * alphabetic character.
|
| slug@0 | 1744 | * @param[in] word Word to check for sno_mask-ness.
|
| slug@0 | 1745 | * @return Non-zero if \a word looks like a server notice mask; zero if not.
|
| slug@0 | 1746 | */
|
| slug@0 | 1747 | int is_snomask(char *word)
|
| slug@0 | 1748 | {
|
| slug@0 | 1749 | if (word)
|
| slug@0 | 1750 | {
|
| slug@0 | 1751 | for (; *word; word++)
|
| slug@0 | 1752 | if (IsDigit(*word))
|
| slug@0 | 1753 | return 1;
|
| slug@0 | 1754 | else if (IsAlpha(*word))
|
| slug@0 | 1755 | return 0;
|
| slug@0 | 1756 | }
|
| slug@0 | 1757 | return 0;
|
| slug@0 | 1758 | }
|
| slug@0 | 1759 |
|
| paul@30 | 1760 | /*
|
| paul@30 | 1761 | * Check to see if it resembles a valid hostmask.
|
| paul@30 | 1762 | */
|
| paul@30 | 1763 | int is_hostmask(char *word)
|
| paul@30 | 1764 | {
|
| paul@30 | 1765 | int i = 0;
|
| paul@30 | 1766 | char *host;
|
| paul@30 | 1767 |
|
| paul@30 | 1768 | Debug((DEBUG_INFO, "is_hostmask() %s", word));
|
| paul@30 | 1769 |
|
| paul@30 | 1770 | if (strlen(word) > (HOSTLEN + USERLEN + 1) || strlen(word) <= 0)
|
| paul@30 | 1771 | return 0;
|
| paul@30 | 1772 |
|
| paul@30 | 1773 | /* if a host is specified, make sure it's valid */
|
| paul@30 | 1774 | host = strrchr(word, '@');
|
| paul@30 | 1775 | if (host) {
|
| paul@30 | 1776 | if (strlen(++host) < 1)
|
| paul@30 | 1777 | return 0;
|
| paul@30 | 1778 | if (strlen(host) > HOSTLEN)
|
| paul@30 | 1779 | return 0;
|
| paul@30 | 1780 | }
|
| paul@30 | 1781 |
|
| paul@30 | 1782 | if (word) {
|
| paul@30 | 1783 | if ('@' == *word) /* no leading @'s */
|
| paul@30 | 1784 | return 0;
|
| paul@30 | 1785 |
|
| paul@30 | 1786 | if ('#' == *word) { /* numeric index given? */
|
| paul@30 | 1787 | for (word++; *word; word++) {
|
| paul@30 | 1788 | if (!IsDigit(*word))
|
| paul@30 | 1789 | return 0;
|
| paul@30 | 1790 | }
|
| paul@30 | 1791 | return 1;
|
| paul@30 | 1792 | }
|
| paul@30 | 1793 |
|
| paul@30 | 1794 | /* normal hostmask, account for at most one '@' */
|
| paul@30 | 1795 | for (; *word; word++) {
|
| paul@30 | 1796 | if ('@' == *word) {
|
| paul@30 | 1797 | i++;
|
| paul@30 | 1798 | continue;
|
| paul@30 | 1799 | }
|
| paul@30 | 1800 | if (!IsHostChar(*word))
|
| paul@30 | 1801 | return 0;
|
| paul@30 | 1802 | }
|
| paul@30 | 1803 | return (1 < i) ? 0 : 1; /* no more than on '@' */
|
| paul@30 | 1804 | }
|
| paul@30 | 1805 | return 0;
|
| paul@30 | 1806 | }
|
| paul@30 | 1807 |
|
| paul@30 | 1808 | /*
|
| paul@30 | 1809 | * IsVhost() - Check if given host is a valid spoofhost
|
| paul@30 | 1810 | * (ie: configured thru a S:line)
|
| paul@30 | 1811 | */
|
| paul@30 | 1812 | static char *IsVhost(char *hostmask, int oper)
|
| paul@30 | 1813 | {
|
| paul@30 | 1814 | unsigned int i = 0, y = 0;
|
| paul@30 | 1815 | struct sline *sconf;
|
| paul@30 | 1816 |
|
| paul@30 | 1817 | Debug((DEBUG_INFO, "IsVhost() %s", hostmask));
|
| paul@30 | 1818 |
|
| paul@30 | 1819 | if (EmptyString(hostmask))
|
| paul@30 | 1820 | return NULL;
|
| paul@30 | 1821 |
|
| paul@30 | 1822 | /* spoofhost specified as index, ie: #27 */
|
| paul@30 | 1823 | if ('#' == hostmask[0]) {
|
| paul@30 | 1824 | y = atoi(hostmask + 1);
|
| paul@30 | 1825 | for (i = 0, sconf = GlobalSList; sconf; sconf = sconf->next) {
|
| paul@30 | 1826 | if (!oper && EmptyString(sconf->passwd))
|
| paul@30 | 1827 | continue;
|
| paul@30 | 1828 | if (y == ++i)
|
| paul@30 | 1829 | return sconf->spoofhost;
|
| paul@30 | 1830 | }
|
| paul@30 | 1831 | return NULL;
|
| paul@30 | 1832 | }
|
| paul@30 | 1833 |
|
| paul@30 | 1834 | /* spoofhost specified as host, ie: host.cc */
|
| paul@30 | 1835 | for (sconf = GlobalSList; sconf; sconf = sconf->next)
|
| paul@30 | 1836 | if (strCasediff(hostmask, sconf->spoofhost) == 0)
|
| paul@30 | 1837 | return sconf->spoofhost;
|
| paul@30 | 1838 |
|
| paul@30 | 1839 | return NULL;
|
| paul@30 | 1840 | }
|
| paul@30 | 1841 |
|
| paul@30 | 1842 | /*
|
| paul@30 | 1843 | * IsVhostPass() - Check if given spoofhost has a password
|
| paul@30 | 1844 | * associated with it, and if, return the password (cleartext)
|
| paul@30 | 1845 | */
|
| paul@30 | 1846 | static char *IsVhostPass(char *hostmask)
|
| paul@30 | 1847 | {
|
| paul@30 | 1848 | struct sline *sconf;
|
| paul@30 | 1849 |
|
| paul@30 | 1850 | Debug((DEBUG_INFO, "IsVhostPass() %s", hostmask));
|
| paul@30 | 1851 |
|
| paul@30 | 1852 | if (EmptyString(hostmask))
|
| paul@30 | 1853 | return NULL;
|
| paul@30 | 1854 |
|
| paul@30 | 1855 | for (sconf = GlobalSList; sconf; sconf = sconf->next)
|
| paul@30 | 1856 | if (strCasediff(hostmask, sconf->spoofhost) == 0) {
|
| paul@30 | 1857 | Debug((DEBUG_INFO, "sconf->passwd %s", sconf->passwd));
|
| paul@30 | 1858 | return EmptyString(sconf->passwd) ? NULL : sconf->passwd;
|
| paul@30 | 1859 | }
|
| paul@30 | 1860 |
|
| paul@30 | 1861 | return NULL;
|
| paul@30 | 1862 | }
|
| paul@30 | 1863 |
|
| slug@0 | 1864 | /** Update snomask \a oldmask according to \a arg and \a what.
|
| slug@0 | 1865 | * @param[in] oldmask Original user mask.
|
| slug@0 | 1866 | * @param[in] arg Update string (either a number or '+'/'-' followed by a number).
|
| slug@0 | 1867 | * @param[in] what MODE_ADD if adding the mask.
|
| slug@0 | 1868 | * @return New value of service notice mask.
|
| slug@0 | 1869 | */
|
| slug@0 | 1870 | unsigned int umode_make_snomask(unsigned int oldmask, char *arg, int what)
|
| slug@0 | 1871 | {
|
| slug@0 | 1872 | unsigned int sno_what;
|
| slug@0 | 1873 | unsigned int newmask;
|
| slug@0 | 1874 | if (*arg == '+')
|
| slug@0 | 1875 | {
|
| slug@0 | 1876 | arg++;
|
| slug@0 | 1877 | if (what == MODE_ADD)
|
| slug@0 | 1878 | sno_what = SNO_ADD;
|
| slug@0 | 1879 | else
|
| slug@0 | 1880 | sno_what = SNO_DEL;
|
| slug@0 | 1881 | }
|
| slug@0 | 1882 | else if (*arg == '-')
|
| slug@0 | 1883 | {
|
| slug@0 | 1884 | arg++;
|
| slug@0 | 1885 | if (what == MODE_ADD)
|
| slug@0 | 1886 | sno_what = SNO_DEL;
|
| slug@0 | 1887 | else
|
| slug@0 | 1888 | sno_what = SNO_ADD;
|
| slug@0 | 1889 | }
|
| slug@0 | 1890 | else
|
| slug@0 | 1891 | sno_what = (what == MODE_ADD) ? SNO_SET : SNO_DEL;
|
| slug@0 | 1892 | /* pity we don't have strtoul everywhere */
|
| slug@0 | 1893 | newmask = (unsigned int)atoi(arg);
|
| slug@0 | 1894 | if (sno_what == SNO_DEL)
|
| slug@0 | 1895 | newmask = oldmask & ~newmask;
|
| slug@0 | 1896 | else if (sno_what == SNO_ADD)
|
| slug@0 | 1897 | newmask |= oldmask;
|
| slug@0 | 1898 | return newmask;
|
| slug@0 | 1899 | }
|
| slug@0 | 1900 |
|
| slug@0 | 1901 | /** Remove \a cptr from the singly linked list \a list.
|
| slug@0 | 1902 | * @param[in] cptr Client to remove from list.
|
| slug@0 | 1903 | * @param[in,out] list Pointer to head of list containing \a cptr.
|
| slug@0 | 1904 | */
|
| slug@0 | 1905 | static void delfrom_list(struct Client *cptr, struct SLink **list)
|
| slug@0 | 1906 | {
|
| slug@0 | 1907 | struct SLink* tmp;
|
| slug@0 | 1908 | struct SLink* prv = NULL;
|
| slug@0 | 1909 |
|
| slug@0 | 1910 | for (tmp = *list; tmp; tmp = tmp->next) {
|
| slug@0 | 1911 | if (tmp->value.cptr == cptr) {
|
| slug@0 | 1912 | if (prv)
|
| slug@0 | 1913 | prv->next = tmp->next;
|
| slug@0 | 1914 | else
|
| slug@0 | 1915 | *list = tmp->next;
|
| slug@0 | 1916 | free_link(tmp);
|
| slug@0 | 1917 | break;
|
| slug@0 | 1918 | }
|
| slug@0 | 1919 | prv = tmp;
|
| slug@0 | 1920 | }
|
| slug@0 | 1921 | }
|
| slug@0 | 1922 |
|
| slug@0 | 1923 | /** Set \a cptr's server notice mask, according to \a what.
|
| slug@0 | 1924 | * @param[in,out] cptr Client whose snomask is updating.
|
| slug@0 | 1925 | * @param[in] newmask Base value for new snomask.
|
| slug@0 | 1926 | * @param[in] what One of SNO_ADD, SNO_DEL, SNO_SET, to choose operation.
|
| slug@0 | 1927 | */
|
| slug@0 | 1928 | void set_snomask(struct Client *cptr, unsigned int newmask, int what)
|
| slug@0 | 1929 | {
|
| slug@0 | 1930 | unsigned int oldmask, diffmask; /* unsigned please */
|
| slug@0 | 1931 | int i;
|
| slug@0 | 1932 | struct SLink *tmp;
|
| slug@0 | 1933 |
|
| slug@0 | 1934 | oldmask = cli_snomask(cptr);
|
| slug@0 | 1935 |
|
| slug@0 | 1936 | if (what == SNO_ADD)
|
| slug@0 | 1937 | newmask |= oldmask;
|
| slug@0 | 1938 | else if (what == SNO_DEL)
|
| slug@0 | 1939 | newmask = oldmask & ~newmask;
|
| slug@0 | 1940 | else if (what != SNO_SET) /* absolute set, no math needed */
|
| slug@0 | 1941 | sendto_opmask_butone(0, SNO_OLDSNO, "setsnomask called with %d ?!", what);
|
| slug@0 | 1942 |
|
| slug@0 | 1943 | newmask &= (IsAnOper(cptr) ? SNO_ALL : SNO_USER);
|
| slug@0 | 1944 |
|
| slug@0 | 1945 | diffmask = oldmask ^ newmask;
|
| slug@0 | 1946 |
|
| slug@0 | 1947 | for (i = 0; diffmask >> i; i++) {
|
| slug@0 | 1948 | if (((diffmask >> i) & 1))
|
| slug@0 | 1949 | {
|
| slug@0 | 1950 | if (((newmask >> i) & 1))
|
| slug@0 | 1951 | {
|
| slug@0 | 1952 | tmp = make_link();
|
| slug@0 | 1953 | tmp->next = opsarray[i];
|
| slug@0 | 1954 | tmp->value.cptr = cptr;
|
| slug@0 | 1955 | opsarray[i] = tmp;
|
| slug@0 | 1956 | }
|
| slug@0 | 1957 | else
|
| slug@0 | 1958 | /* not real portable :( */
|
| slug@0 | 1959 | delfrom_list(cptr, &opsarray[i]);
|
| slug@0 | 1960 | }
|
| slug@0 | 1961 | }
|
| slug@0 | 1962 | cli_snomask(cptr) = newmask;
|
| slug@0 | 1963 | }
|
| slug@0 | 1964 |
|
| slug@0 | 1965 | /** Check whether \a sptr is allowed to send a message to \a acptr.
|
| slug@0 | 1966 | * If \a sptr is a remote user, it means some server has an outdated
|
| slug@0 | 1967 | * SILENCE list for \a acptr, so send the missing SILENCE mask(s) back
|
| slug@0 | 1968 | * in the direction of \a sptr. Skip the check if \a sptr is a server.
|
| slug@0 | 1969 | * @param[in] sptr Client trying to send a message.
|
| slug@0 | 1970 | * @param[in] acptr Destination of message.
|
| slug@0 | 1971 | * @return Non-zero if \a sptr is SILENCEd by \a acptr, zero if not.
|
| slug@0 | 1972 | */
|
| slug@0 | 1973 | int is_silenced(struct Client *sptr, struct Client *acptr)
|
| slug@0 | 1974 | {
|
| slug@0 | 1975 | struct Ban *found;
|
| slug@0 | 1976 | struct User *user;
|
| slug@0 | 1977 | size_t buf_used, slen;
|
| slug@0 | 1978 | char buf[BUFSIZE];
|
| slug@0 | 1979 |
|
| slug@0 | 1980 | if (IsServer(sptr) || !(user = cli_user(acptr))
|
| slug@0 | 1981 | || !(found = find_ban(sptr, user->silence)))
|
| slug@0 | 1982 | return 0;
|
| slug@0 | 1983 | assert(!(found->flags & BAN_EXCEPTION));
|
| slug@0 | 1984 | if (!MyConnect(sptr)) {
|
| slug@0 | 1985 | /* Buffer positive silence to send back. */
|
| slug@0 | 1986 | buf_used = strlen(found->banstr);
|
| slug@0 | 1987 | memcpy(buf, found->banstr, buf_used);
|
| slug@0 | 1988 | /* Add exceptions to buffer. */
|
| slug@0 | 1989 | for (found = user->silence; found; found = found->next) {
|
| slug@0 | 1990 | if (!(found->flags & BAN_EXCEPTION))
|
| slug@0 | 1991 | continue;
|
| slug@0 | 1992 | slen = strlen(found->banstr);
|
| slug@0 | 1993 | if (buf_used + slen + 4 > 400) {
|
| slug@0 | 1994 | buf[buf_used] = '\0';
|
| slug@0 | 1995 | sendcmdto_one(acptr, CMD_SILENCE, cli_from(sptr), "%C %s", sptr, buf);
|
| slug@0 | 1996 | buf_used = 0;
|
| slug@0 | 1997 | }
|
| slug@0 | 1998 | if (buf_used)
|
| slug@0 | 1999 | buf[buf_used++] = ',';
|
| slug@0 | 2000 | buf[buf_used++] = '+';
|
| slug@0 | 2001 | buf[buf_used++] = '~';
|
| slug@0 | 2002 | memcpy(buf + buf_used, found->banstr, slen);
|
| slug@0 | 2003 | buf_used += slen;
|
| slug@0 | 2004 | }
|
| slug@0 | 2005 | /* Flush silence buffer. */
|
| slug@0 | 2006 | if (buf_used) {
|
| slug@0 | 2007 | buf[buf_used] = '\0';
|
| slug@0 | 2008 | sendcmdto_one(acptr, CMD_SILENCE, cli_from(sptr), "%C %s", sptr, buf);
|
| slug@0 | 2009 | buf_used = 0;
|
| slug@0 | 2010 | }
|
| slug@0 | 2011 | }
|
| slug@0 | 2012 | return 1;
|
| slug@0 | 2013 | }
|
| slug@0 | 2014 |
|
| slug@0 | 2015 | /** Send RPL_ISUPPORT lines to \a cptr.
|
| slug@0 | 2016 | * @param[in] cptr Client to send ISUPPORT to.
|
| slug@0 | 2017 | * @return Zero.
|
| slug@0 | 2018 | */
|
| slug@0 | 2019 | int
|
| slug@0 | 2020 | send_supported(struct Client *cptr)
|
| slug@0 | 2021 | {
|
| slug@0 | 2022 | char featurebuf[512];
|
| slug@0 | 2023 |
|
| slug@0 | 2024 | ircd_snprintf(0, featurebuf, sizeof(featurebuf), FEATURES1, FEATURESVALUES1);
|
| slug@0 | 2025 | send_reply(cptr, RPL_ISUPPORT, featurebuf);
|
| slug@0 | 2026 | ircd_snprintf(0, featurebuf, sizeof(featurebuf), FEATURES2, FEATURESVALUES2);
|
| slug@0 | 2027 | send_reply(cptr, RPL_ISUPPORT, featurebuf);
|
| slug@0 | 2028 |
|
| slug@0 | 2029 | return 0; /* convenience return, if it's ever needed */
|
| slug@0 | 2030 | }
|
| paul@115 | 2031 |
|
| paul@115 | 2032 | /* vim: shiftwidth=2
|
| paul@115 | 2033 | */
|