Exemplo n.º 1
0
/*! \brief SVSNICK command handler
 *
 * \param source_p Pointer to allocated Client struct from which the message
 *                 originally comes from.  This can be a local or remote client.
 * \param parc     Integer holding the number of supplied arguments.
 * \param parv     Argument vector where parv[0] .. parv[parc-1] are non-NULL
 *                 pointers.
 * \note Valid arguments for this command are:
 *      - parv[0] = command
 *      - parv[1] = old nickname
 *      - parv[2] = new nickname
 *      - parv[3] = timestamp
 */
static int
ms_svsnick(struct Client *source_p, int parc, char *parv[])
{
  struct Client *target_p = NULL, *exists_p = NULL;

  if (!HasFlag(source_p, FLAGS_SERVICE) || !valid_nickname(parv[2], 1))
    return 0;

  if ((target_p = find_person(source_p, parv[1])) == NULL)
    return 0;

  if (!MyConnect(target_p))
  {
    if (target_p->from == source_p->from)
    {
      sendto_realops_flags(UMODE_DEBUG, L_ALL, SEND_NOTICE,
                           "Received wrong-direction SVSNICK "
                           "for %s (behind %s) from %s",
                           target_p->name, source_p->from->name,
                           get_client_name(source_p, HIDE_IP));
      return 0;
    }

    sendto_one(target_p, ":%s SVSNICK %s %s %s", source_p->id,
               target_p->id, parv[2], parv[3]);
    return 0;
  }

  if ((exists_p = hash_find_client(parv[2])))
  {
    if (target_p == exists_p)
    {
      if (!strcmp(target_p->name, parv[2]))
        return 0;
    }
    else if (IsUnknown(exists_p))
      exit_client(exists_p, "SVSNICK Override");
    else
    {
      exit_client(target_p, "SVSNICK Collide");
      return 0;
    }
  }

  target_p->tsinfo = strtoimax(parv[3], NULL, 10);
  clear_ban_cache_client(target_p);
  watch_check_hash(target_p, RPL_LOGOFF);

  if (HasUMode(target_p, UMODE_REGISTERED))
  {
    const unsigned int oldmodes = target_p->umodes;
    char modebuf[IRCD_BUFSIZE] = "";

    DelUMode(target_p, UMODE_REGISTERED);
    send_umode(target_p, target_p, oldmodes, modebuf);
  }

  sendto_common_channels_local(target_p, 1, 0, 0, ":%s!%s@%s NICK :%s",
                               target_p->name, target_p->username,
                               target_p->host, parv[2]);

  whowas_add_history(target_p, 1);

  sendto_server(NULL, 0, 0, ":%s NICK %s :%ju",
                target_p->id, parv[2], target_p->tsinfo);
  hash_del_client(target_p);
  strlcpy(target_p->name, parv[2], sizeof(target_p->name));
  hash_add_client(target_p);

  watch_check_hash(target_p, RPL_LOGON);

  fd_note(&target_p->connection->fd, "Nick: %s", target_p->name);
  return 0;
}
Exemplo n.º 2
0
static int
m_server_estab(aClient *cptr)
{
    aConnect *aconn;
    aClient *acptr;

    char       *inpath, *host, *s, *encr;

    inpath = get_client_name(cptr, HIDEME);  /* "refresh" inpath with host  */
    host = cptr->name;

    if (!(aconn = cptr->serv->aconn))
    {
        ircstp->is_ref++;
        sendto_one(cptr, "ERROR :Lost Connect block");
        sendto_ops_lev(ADMIN_LEV, "Lost Connect block for server %s",
                           get_client_name(cptr, TRUE));
        return exit_client(cptr, cptr, cptr, "Lost Connect block");
    }

    encr = cptr->passwd;
    if (*aconn->apasswd && !StrEq(aconn->apasswd, encr))
    {
        ircstp->is_ref++;
        sendto_one(cptr, "ERROR :Wrong link password");
        sendto_ops("Link %s dropped, wrong password", inpath);
        return exit_client(cptr, cptr, cptr, "Bad Password");
    }
    memset(cptr->passwd, '\0', sizeof(cptr->passwd));

    if ((acptr = find_client(host, NULL)))
    {
        /* Don't complain about juped servers */
        if(!IsULine(acptr) || find_aUserver(acptr->name))
        {
            sendto_gnotice("from %s: Link %s dropped, server already exists",
                           me.name, inpath);
            sendto_serv_butone(cptr, ":%s GNOTICE :Link %s dropped, server already"
                               " exists", me.name, inpath);
        }
        return exit_client(cptr, cptr, cptr, "Server Exists");
    }

    if(!(confopts & FLAGS_HUB))
    {
        int i;
        for (i = 0; i <= highest_fd; i++)
            if (local[i] && IsServer(local[i]))
            {
                ircstp->is_ref++;
                sendto_one(cptr, "ERROR :I'm a leaf not a hub");
                return exit_client(cptr, cptr, cptr, "I'm a leaf");
            }
    }

    /* aconf->port is a CAPAB field, kind-of. kludge. mm, mm. */
    /* no longer! this should still get better though */
    if((aconn->flags & CONN_ZIP))
        SetZipCapable(cptr);
    if((aconn->flags & CONN_DKEY))
        SetWantDKEY(cptr);
    if (IsUnknown(cptr))
    {
        if (aconn->cpasswd[0])
            sendto_one(cptr, "PASS %s :TS", aconn->cpasswd);

        /* Pass my info to the new server */

#ifdef HAVE_ENCRYPTION_ON
        if(!WantDKEY(cptr))
            sendto_one(cptr, "CAPAB SSJOIN NOQUIT BURST UNCONNECT ZIP "
                       "NICKIP NICKIPSTR TSMODE");
        else
            sendto_one(cptr, "CAPAB SSJOIN NOQUIT BURST UNCONNECT DKEY "
                       "ZIP NICKIP NICKIPSTR TSMODE");
#else
        sendto_one(cptr, "CAPAB SSJOIN NOQUIT BURST UNCONNECT ZIP NICKIP NICKIPSTR TSMODE");
#endif

        sendto_one(cptr, "SERVER %s 1 :%s",
                   my_name_for_link(me.name, aconn),
                   (me.info[0]) ? (me.info) : "IRCers United");
    }
    else 
    {
        s = (char *) strchr(aconn->host, '@');
        *s = '\0';      /* should never be NULL -- wanna bet? -Dianora */

        Debug((DEBUG_INFO, "Check Usernames [%s]vs[%s]", aconn->host,
               cptr->username));
        if (match(aconn->host, cptr->username))
        {
            *s = '@';
            ircstp->is_ref++;
            sendto_ops("Username mismatch [%s]v[%s] : %s",
                       aconn->host, cptr->username,
                       get_client_name(cptr, HIDEME));
            sendto_one(cptr, "ERROR :No Username Match");
            return exit_client(cptr, cptr, cptr, "Bad User");
        }
        *s = '@';
    }

    /* send routing notice, this should never happen anymore */
    if (!DoesTS(cptr))
    {
        sendto_gnotice("from %s: Warning: %s linked, non-TS server",
                       me.name, get_client_name(cptr, HIDEME));
        sendto_serv_butone(cptr,
                           ":%s GNOTICE :Warning: %s linked, non-TS server",
                           me.name, get_client_name(cptr, HIDEME));
    }

    sendto_one(cptr, "SVINFO %d %d 0 :%ld", TS_CURRENT, TS_MIN,
               (ts_val) timeofday);

    /* sendto one(cptr, "CAPAB ...."); moved to after PASS but before SERVER
     * now in two places.. up above and in s_bsd.c. - lucas
     * This is to make sure we pass on our capabilities before we establish
     * a server connection
     */

    /*
     * *WARNING*
     *   In the following code in place of plain
     * server's name we send what is returned by
     * get_client_name which may add the "sockhost" after the name.
     * It's *very* *important* that there is a SPACE between
     * the name and sockhost (if present). The receiving server
     * will start the information field from this first blank and
     * thus puts the sockhost into info. ...a bit tricky, but
     * you have been warned, besides code is more neat this way...
     * --msa
     */

    cptr->serv->up = me.name;
    cptr->serv->aconn = aconn;

    throttle_remove(cipntoa(cptr));

#ifdef HAVE_ENCRYPTION_ON
    if(!CanDoDKEY(cptr) || !WantDKEY(cptr))
        return do_server_estab(cptr);
    else
    {
        SetNegoServer(cptr); /* VERY IMPORTANT THAT THIS IS HERE */
        sendto_one(cptr, "DKEY START");
    }
#else
    return do_server_estab(cptr);
#endif

    return 0;
}
Exemplo n.º 3
0
static int
do_server_estab(aClient *cptr)
{
    aClient *acptr;
    aConnect *aconn;
    aChannel *chptr;
    int i;
    /* "refresh" inpath with host  */
    char *inpath = get_client_name(cptr, HIDEME);

    SetServer(cptr);

    Count.unknown--;
    Count.server++;
    Count.myserver++;

    if(IsZipCapable(cptr) && DoZipThis(cptr))
    {
        sendto_one(cptr, "SVINFO ZIP");
        SetZipOut(cptr);
        cptr->serv->zip_out = zip_create_output_session();
    }

#ifdef MAXBUFFERS
    /* let's try to bump up server sock_opts... -Taner */
    reset_sock_opts(cptr->fd, 1);
#endif

    /* adds to server list */
    add_to_list(&server_list, cptr);

    set_effective_class(cptr);

    /* Check one more time for good measure... is it there? */
    if ((acptr = find_name(cptr->name, NULL)))
    {
        char        nbuf[HOSTLEN * 2 + USERLEN + 5];
        aClient *bcptr;

        /*
         * While negotiating stuff, another copy of this server appeared.
         *
         * Rather than KILL the link which introduced it, KILL the
         * youngest of the two links. -avalon
         */

        bcptr = (cptr->firsttime > acptr->from->firsttime) ? cptr :
            acptr->from;
        sendto_one(bcptr, "ERROR :Server %s already exists", cptr->name);
        if (bcptr == cptr)
        {
            sendto_gnotice("from %s: Link %s cancelled, server %s already "
                           "exists (final phase)", me.name,
                           get_client_name(bcptr, HIDEME), cptr->name);
            sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, "
                                "server %s already exists (final phase)",
                                me.name, get_client_name(bcptr, HIDEME),
                                cptr->name);
            return exit_client(bcptr, bcptr, &me,
                               "Server Exists (final phase)");
        }
        /* inform all those who care (set +n) -epi */

        strcpy(nbuf, get_client_name(bcptr, HIDEME));
        sendto_gnotice("from %s: Link %s cancelled, server %s reintroduced "
                       "by %s (final phase)", me.name, nbuf, cptr->name,
                       get_client_name(cptr, HIDEME));
        sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, server %s "
                           "reintroduced by %s (final phase)", me.name, nbuf,
                           cptr->name, get_client_name(cptr, HIDEME));
        exit_client(bcptr, bcptr, &me, "Server Exists (final phase)");
    }

    /* error, error, error! if a server is U:'d, and it connects to us,
     * we need to figure that out! So, do it here. - lucas
     */

    if (find_aUserver(cptr->name))
    {
        Count.myulined++;
        cptr->flags |= FLAGS_ULINE;

        /* If the server has special u:line flags, let's set them.. */
        cptr->serv->uflags = cptr->serv->aconn->uflags;
    }

    fakelinkserver_update(cptr->name, cptr->info);

    sendto_gnotice("from %s: Link with %s established, states:%s%s%s%s",
                   me.name, inpath, ZipOut(cptr) ? " Output-compressed" : "",
                   RC4EncLink(cptr) ? " encrypted" : "",
                   IsULine(cptr) ? " ULined" : "",
                   DoesTS(cptr) ? " TS" : " Non-TS");

    /*
     * Notify everyone of the fact that this has just linked: the entire
     * network should get two of these, one explaining the link between
     * me->serv and the other between serv->me
     */

    sendto_serv_butone(NULL, ":%s GNOTICE :Link with %s established: %s",
                       me.name, inpath,
                       DoesTS(cptr) ? "TS link" : "Non-TS link!");

    add_to_client_hash_table(cptr->name, cptr);

    /* add it to scache */

    find_or_add(cptr->name);

    /*
     * Old sendto_serv_but_one() call removed because we now need to
     * send different names to different servers (domain name
     * matching) Send new server to other servers.
     */
    for (i = 0; i <= highest_fd; i++)
    {
        if (!(acptr = local[i]) || !IsServer(acptr) || acptr == cptr ||
            IsMe(acptr))
            continue;
        if ((aconn = acptr->serv->aconn) &&
            !match(my_name_for_link(me.name, aconn), cptr->name))
            continue;
        sendto_one(acptr, ":%s SERVER %s 2 :%s", me.name, cptr->name,
                   cptr->info);
    }

    /*
     * Pass on my client information to the new server
     *
     * First, pass only servers (idea is that if the link gets
     * cancelled beacause the server was already there, there are no
     * NICK's to be cancelled...). Of course, if cancellation occurs,
     * all this info is sent anyway, and I guess the link dies when a
     * read is attempted...? --msa
     *
     * Note: Link cancellation to occur at this point means that at
     * least two servers from my fragment are building up connection
     * this other fragment at the same time, it's a race condition,
     * not the normal way of operation...
     *
     * ALSO NOTE: using the get_client_name for server names-- see
     * previous *WARNING*!!! (Also, original inpath is
     * destroyed...)
     */

    aconn = cptr->serv->aconn;
    for (acptr = &me; acptr; acptr = acptr->prev)
    {
        if (acptr->from == cptr)
            continue;
        if (IsServer(acptr))
        {
            if (match(my_name_for_link(me.name, aconn), acptr->name) == 0)
                continue;
            sendto_one(cptr, ":%s SERVER %s %d :%s",
                       acptr->serv->up, acptr->name,
                       acptr->hopcount + 1, acptr->info);
        }
    }

    /* send out our SQLINES and SGLINES too */
    send_simbans(cptr, SBAN_CHAN|SBAN_NETWORK);
    send_simbans(cptr, SBAN_NICK|SBAN_NETWORK);
    send_simbans(cptr, SBAN_GCOS|SBAN_NETWORK);

    /* Send out fake server list and other 'fake' stuff */
    fakeserver_sendserver(cptr);

    /* Send UHM (user host-masking) type */
    if(confopts & FLAGS_HUB)
        sendto_one(cptr, "SVSUHM %d", uhm_type);

    /* send clone list */
    clones_send(cptr);

    /* Bursts are about to start.. send a BURST */
    if (IsBurst(cptr))
        sendto_one(cptr, "BURST");

    /*
     * * Send it in the shortened format with the TS, if it's a TS
     * server; walk the list of channels, sending all the nicks that
     * haven't been sent yet for each channel, then send the channel
     * itself -- it's less obvious than sending all nicks first, but
     * on the receiving side memory will be allocated more nicely
     * saving a few seconds in the handling of a split -orabidoo
     */
    {
        chanMember       *cm;
        static char nickissent = 1;

        nickissent = 3 - nickissent;
        /*
         * flag used for each nick to check if we've sent it yet - must
         * be different each time and !=0, so we alternate between 1 and
         * 2 -orabidoo
         */
        for (chptr = channel; chptr; chptr = chptr->nextch)
        {
            for (cm = chptr->members; cm; cm = cm->next)
            {
                acptr = cm->cptr;
                if (acptr->nicksent != nickissent)
                {
                    acptr->nicksent = nickissent;
                    if (acptr->from != cptr)
                        sendnick_TS(cptr, acptr);
                }
            }
            send_channel_modes(cptr, chptr);
        }
        /* also send out those that are not on any channel */
        for (acptr = &me; acptr; acptr = acptr->prev)
            if (acptr->nicksent != nickissent)
            {
                acptr->nicksent = nickissent;
                if (acptr->from != cptr)
                    sendnick_TS(cptr, acptr);
            }
    }

    if(confopts & FLAGS_HUB)
        fakelusers_sendlock(cptr);

    if(ZipOut(cptr))
    {
        unsigned long inb, outb;
        double rat;

        zip_out_get_stats(cptr->serv->zip_out, &inb, &outb, &rat);

        if(inb)
        {
            sendto_gnotice("from %s: Connect burst to %s: %lu bytes normal, "
                           "%lu compressed (%3.2f%%)", me.name,
                           get_client_name(cptr, HIDEME), inb, outb, rat);
            sendto_serv_butone(cptr, ":%s GNOTICE :Connect burst to %s: %lu "
                               "bytes normal, %lu compressed (%3.2f%%)",
                               me.name, get_client_name(cptr, HIDEME), inb,
                               outb, rat);
        }
    }

    /* stuff a PING at the end of this burst so we can figure out when
       the other side has finished processing it. */
    cptr->flags |= FLAGS_BURST|FLAGS_PINGSENT;
    if (IsBurst(cptr)) cptr->flags |= FLAGS_SOBSENT;
    sendto_one(cptr, "PING :%s", me.name);

    return 0;
}
Exemplo n.º 4
0
int parse(aClient *cptr, char *buffer, char *bufend)
{
    aClient *from = cptr;
    char *ch, *s;
    int i, numeric = 0, paramcount;
    struct Message *mptr;

#ifdef DUMP_DEBUG
    if(dumpfp!=NULL) 
    {
	fprintf(dumpfp, "<- %s: %s\n", (cptr->name ? cptr->name : "*"),
		buffer);
	fflush(dumpfp);
    }
#endif
    Debug((DEBUG_DEBUG, "Parsing %s: %s", get_client_name(cptr, TRUE),
	   buffer));
    
    if (IsDead(cptr))
	return -1;
    
    s = sender;
    *s = '\0';
    
    for (ch = buffer; *ch == ' '; ch++);	/* skip spaces */
    
    para[0] = from->name;
    if (*ch == ':') 
    {
	/*
	 * Copy the prefix to 'sender' assuming it terminates with
	 * SPACE (or NULL, which is an error, though).
	 */
	
	for (++ch; *ch && *ch != ' '; ++ch)
	    if (s < (sender + HOSTLEN))
		*s++ = *ch;		
	*s = '\0';
	
	/*
	 * Actually, only messages coming from servers can have the
	 * prefix--prefix silently ignored, if coming from a user
	 * client...
	 * 
	 * ...sigh, the current release "v2.2PL1" generates also null
	 * prefixes, at least to NOTIFY messages (e.g. it puts
	 * "sptr->nickname" as prefix from server structures where it's
	 * null--the following will handle this case as "no prefix" at
	 * all --msa  (": NOTICE nick ...")
	 */
	
	if (*sender && IsServer(cptr)) 
	{
	    from = find_client(sender, (aClient *) NULL);

	    /*
	     * okay, this doesn't seem to do much here.
	     * from->name _MUST_ be equal to sender. 
	     * That's what find_client does.
	     * find_client will find servers too, and since we don't use server
	     * masking, the find server call is useless (and very wasteful).
	     * now, there HAS to be a from and from->name and
	     * sender have to be the same
	     * for us to get to the next if. but the next if
	     * starts out with if(!from)
	     * so this is UNREACHABLE CODE! AGH! - lucas
	     *
	     *  if (!from || mycmp(from->name, sender))
	     *     from = find_server(sender, (aClient *) NULL);
	     *  else if (!from && strchr(sender, '@'))
	     *     from = find_nickserv(sender, (aClient *) NULL);
	     */

	    para[0] = sender;
	    /*
	     * Hmm! If the client corresponding to the prefix is not
	     * found--what is the correct action??? Now, I will ignore the
	     * message (old IRC just let it through as if the prefix just
	     * wasn't there...) --msa
	     */
	    if (!from) 
	    {
		Debug((DEBUG_ERROR, "Unknown prefix (%s)(%s) from (%s)",
		       sender, buffer, cptr->name));

		ircstp->is_unpf++;
		remove_unknown(cptr, sender, buffer);
		 
		return -1;
	    }

	    if (from->from != cptr) 
	    {
		ircstp->is_wrdi++;
		Debug((DEBUG_ERROR, "Message (%s) coming from (%s)",
		       buffer, cptr->name));
		
		return cancel_clients(cptr, from, buffer);
	    }
	}
	while (*ch == ' ')
	    ch++;
    }

    if (*ch == '\0') 
    {
	ircstp->is_empt++;
	Debug((DEBUG_NOTICE, "Empty message from host %s:%s",
	       cptr->name, from->name));
	return (-1);
    }
    /*
     * Extract the command code from the packet.  Point s to the end
     * of the command code and calculate the length using pointer
     * arithmetic.  Note: only need length for numerics and *all*
     * numerics must have parameters and thus a space after the command
     * code. -avalon
     * 
     * ummm???? - Dianora
     */

    /* check for numeric */
    if (*(ch + 3) == ' ' && IsDigit(*ch) && IsDigit(*(ch + 1)) &&
	IsDigit(*(ch + 2))) 
    {
	mptr = (struct Message *) NULL;
	numeric = (*ch - '0') * 100 + (*(ch + 1) - '0') *
	    10 + (*(ch + 2) - '0');
	paramcount = MAXPARA;
	ircstp->is_num++;
	s = ch + 3;
	*s++ = '\0';
    }
    else 
    {
	s = strchr(ch, ' ');
	
	if (s)
	    *s++ = '\0';
	
        char *t = ch;
        for (; *t; *t++) *t = ToUpper(*t);
#ifndef USE_NEW_COMMAND_SYSTEM
	mptr = tree_parse(ch);
#else
        HASH_FIND_STR(msgtab, ch, mptr);
#endif
	
	if (!mptr || !mptr->cmd) 
	{
	    /*
	     * only send error messages to things that actually sent
	     * buffers to us and only people, too.
	     */
	    if (buffer[0] != '\0') 
	    {
		if (IsPerson(from))
		  sendto_one(&me, from, ":%s %d %s %s :Unknown command",
			       me.name, ERR_UNKNOWNCOMMAND, from->name, ch);
		Debug((DEBUG_ERROR, "Unknown (%s) from %s",
		       ch, get_client_name(cptr, TRUE)));
	    }
	    ircstp->is_unco++;
	    return -1;
	}
	
	paramcount = mptr->parameters;
	i = bufend - ((s) ? s : ch);
	mptr->bytes += i;
	/*
	 * Allow only 1 msg per 2 seconds (on average) to prevent
	 * dumping. to keep the response rate up, bursts of up to 5 msgs
	 * are allowed -SRB Opers can send 1 msg per second, burst of ~20
	 * -Taner
	 */
	if (!IsServer(cptr) || (*(int **)(&cptr->cb) == NULL)) 
	{
        if (!NoMsgThrottle(cptr))
        {
#ifdef NO_OPER_FLOOD
            if (IsAnOper(cptr))
                /* "randomly" (weighted) increase the since */
                cptr->since += (cptr->receiveM % 10) ? 1 : 0;
            else
#endif
                cptr->since += (2 + i / 120);
        }
    }
    }
    /*
     * Must the following loop really be so devious? On surface it
     * splits the message to parameters from blank spaces. But, if
     * paramcount has been reached, the rest of the message goes into
     * this last parameter (about same effect as ":" has...) --msa
     */

    /* Note initially true: s==NULL || *(s-1) == '\0' !! */
    
    i = 1;
    if (s) 
    {
	if (paramcount > MAXPARA)
	    paramcount = MAXPARA;
	for (;;) 
	{
	    while (*s == ' ')
		*s++ = '\0';
	    
	    if (*s == '\0')
		break;
	    if (*s == ':') 
	    {
		/* The rest is a single parameter */
		para[i++] = s + 1;
		break;
	    }
	    para[i++] = s;
	    if (i >= paramcount)
            {
                if(paramcount == MAXPARA && strchr(s, ' '))
                {
                   sendto_realops_lev(DEBUG_LEV, "Overflowed MAXPARA on %s from %s",
			   mptr ? mptr->cmd : "numeric",
			   get_client_name(cptr, (IsServer(cptr) ? HIDEME : FALSE)));
                }
		break;
            }
	    
	    while(*s && *s != ' ')
		s++;
	}
    }
    
    para[i] = NULL;
    if (mptr == (struct Message *) NULL)
	return (do_numeric(numeric, cptr, from, i, para));
    
    mptr->count++;
    
    /* patch to avoid server flooding from unregistered connects */
    
    if (!IsRegistered(cptr) && !(mptr->flags & MF_UNREG)) {
      sendto_one(&me, from, err_str(ERR_NOTREGISTERED), me.name,
                   *para[0] ? para[0] : "*", ch);
        return -1;
    }
    
    if (IsRegisteredUser(cptr) && (mptr->flags & MF_RIDLE))
	from->user->last = timeofday;

    if (mptr->flags & MF_ALIAS)
         return mptr->func(cptr, from, i, para, &aliastab[mptr->aliasidx]);

    return (*mptr->func) (cptr, from, i, para);
}
Exemplo n.º 5
0
/*
 * Restore files
 */
int restore_cmd(UAContext *ua, const char *cmd)
{
   RESTORE_CTX rx;                    /* restore context */
   POOL_MEM buf;
   JOBRES *job;
   int i;
   JCR *jcr = ua->jcr;
   char *escaped_bsr_name = NULL;
   char *escaped_where_name = NULL;
   char *strip_prefix, *add_prefix, *add_suffix, *regexp;
   strip_prefix = add_prefix = add_suffix = regexp = NULL;

   memset(&rx, 0, sizeof(rx));
   rx.path = get_pool_memory(PM_FNAME);
   rx.fname = get_pool_memory(PM_FNAME);
   rx.JobIds = get_pool_memory(PM_FNAME);
   rx.JobIds[0] = 0;
   rx.BaseJobIds = get_pool_memory(PM_FNAME);
   rx.query = get_pool_memory(PM_FNAME);
   rx.bsr = new_bsr();

   i = find_arg_with_value(ua, "comment");
   if (i >= 0) {
      rx.comment = ua->argv[i];
      if (!is_comment_legal(ua, rx.comment)) {
         goto bail_out;
      }
   }

   i = find_arg_with_value(ua, "backupformat");
   if (i >= 0) {
      rx.backup_format = ua->argv[i];
   }

   i = find_arg_with_value(ua, "where");
   if (i >= 0) {
      rx.where = ua->argv[i];
   }

   i = find_arg_with_value(ua, "replace");
   if (i >= 0) {
      rx.replace = ua->argv[i];
   }

   i = find_arg_with_value(ua, "pluginoptions");
   if (i >= 0) {
      rx.plugin_options = ua->argv[i];
   }

   i = find_arg_with_value(ua, "strip_prefix");
   if (i >= 0) {
      strip_prefix = ua->argv[i];
   }

   i = find_arg_with_value(ua, "add_prefix");
   if (i >= 0) {
      add_prefix = ua->argv[i];
   }

   i = find_arg_with_value(ua, "add_suffix");
   if (i >= 0) {
      add_suffix = ua->argv[i];
   }

   i = find_arg_with_value(ua, "regexwhere");
   if (i >= 0) {
      rx.RegexWhere = ua->argv[i];
   }

   if (strip_prefix || add_suffix || add_prefix) {
      int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
      regexp = (char *)bmalloc(len * sizeof(char));

      bregexp_build_where(regexp, len, strip_prefix, add_prefix, add_suffix);
      rx.RegexWhere = regexp;
   }

   /* TODO: add acl for regexwhere ? */

   if (rx.RegexWhere) {
      if (!acl_access_ok(ua, Where_ACL, rx.RegexWhere, true)) {
         ua->error_msg(_("\"RegexWhere\" specification not authorized.\n"));
         goto bail_out;
      }
   }

   if (rx.where) {
      if (!acl_access_ok(ua, Where_ACL, rx.where, true)) {
         ua->error_msg(_("\"where\" specification not authorized.\n"));
         goto bail_out;
      }
   }

   if (!open_client_db(ua, true)) {
      goto bail_out;
   }

   /* Ensure there is at least one Restore Job */
   LockRes();
   foreach_res(job, R_JOB) {
      if (job->JobType == JT_RESTORE) {
         if (!rx.restore_job) {
            rx.restore_job = job;
         }
         rx.restore_jobs++;
      }
   }
   UnlockRes();
   if (!rx.restore_jobs) {
      ua->error_msg(_(
         "No Restore Job Resource found in bareos-dir.conf.\n"
         "You must create at least one before running this command.\n"));
      goto bail_out;
   }

   /*
    * Request user to select JobIds or files by various different methods
    *  last 20 jobs, where File saved, most recent backup, ...
    *  In the end, a list of files are pumped into
    *  add_findex()
    */
   switch (user_select_jobids_or_files(ua, &rx)) {
   case 0:                            /* error */
      goto bail_out;
   case 1:                            /* selected by jobid */
      get_and_display_basejobs(ua, &rx);
      if (!build_directory_tree(ua, &rx)) {
         ua->send_msg(_("Restore not done.\n"));
         goto bail_out;
      }
      break;
   case 2:                            /* selected by filename, no tree needed */
      break;
   }

   if (rx.bsr->JobId) {
      char ed1[50];
      if (!complete_bsr(ua, rx.bsr)) {   /* find Vol, SessId, SessTime from JobIds */
         ua->error_msg(_("Unable to construct a valid BSR. Cannot continue.\n"));
         goto bail_out;
      }
      if (!(rx.selected_files = write_bsr_file(ua, rx))) {
         ua->warning_msg(_("No files selected to be restored.\n"));
         goto bail_out;
      }
      display_bsr_info(ua, rx);          /* display vols needed, etc */

      if (rx.selected_files==1) {
         ua->info_msg(_("\n1 file selected to be restored.\n\n"));
      } else {
         ua->info_msg(_("\n%s files selected to be restored.\n\n"),
            edit_uint64_with_commas(rx.selected_files, ed1));
      }
   } else {
      ua->warning_msg(_("No files selected to be restored.\n"));
      goto bail_out;
   }

   if (rx.restore_jobs == 1) {
      job = rx.restore_job;
   } else {
      job = get_restore_job(ua);
   }
   if (!job) {
      goto bail_out;
   }

   get_client_name(ua, &rx);
   if (!rx.ClientName) {
      ua->error_msg(_("No Client resource found!\n"));
      goto bail_out;
   }
   get_restore_client_name(ua, rx);

   escaped_bsr_name = escape_filename(jcr->RestoreBootstrap);

   Mmsg(ua->cmd,
        "run job=\"%s\" client=\"%s\" restoreclient=\"%s\" storage=\"%s\""
        " bootstrap=\"%s\" files=%u catalog=\"%s\"",
        job->name(), rx.ClientName, rx.RestoreClientName,
        rx.store?rx.store->name():"",
        escaped_bsr_name ? escaped_bsr_name : jcr->RestoreBootstrap,
        rx.selected_files, ua->catalog->name());

   /*
    * Build run command
    */
   if (rx.backup_format) {
      Mmsg(buf, " backupformat=%s", rx.backup_format);
      pm_strcat(ua->cmd, buf);
   }

   pm_strcpy(buf, "");
   if (rx.RegexWhere) {
      escaped_where_name = escape_filename(rx.RegexWhere);
      Mmsg(buf, " regexwhere=\"%s\"",
           escaped_where_name ? escaped_where_name : rx.RegexWhere);

   } else if (rx.where) {
      escaped_where_name = escape_filename(rx.where);
      Mmsg(buf," where=\"%s\"",
           escaped_where_name ? escaped_where_name : rx.where);
   }
   pm_strcat(ua->cmd, buf);

   if (rx.replace) {
      Mmsg(buf, " replace=%s", rx.replace);
      pm_strcat(ua->cmd, buf);
   }

   if (rx.plugin_options) {
      Mmsg(buf, " pluginoptions=%s", rx.plugin_options);
      pm_strcat(ua->cmd, buf);
   }

   if (rx.comment) {
      Mmsg(buf, " comment=\"%s\"", rx.comment);
      pm_strcat(ua->cmd, buf);
   }

   if (escaped_bsr_name != NULL) {
      bfree(escaped_bsr_name);
   }

   if (escaped_where_name != NULL) {
      bfree(escaped_where_name);
   }

   if (regexp) {
      bfree(regexp);
   }

   if (find_arg(ua, NT_("yes")) > 0) {
      pm_strcat(ua->cmd, " yes");    /* pass it on to the run command */
   }

   Dmsg1(200, "Submitting: %s\n", ua->cmd);

   /*
    * Transfer jobids to jcr to for picking up restore objects
    */
   jcr->JobIds = rx.JobIds;
   rx.JobIds = NULL;

   parse_ua_args(ua);
   run_cmd(ua, ua->cmd);
   free_rx(&rx);
   garbage_collect_memory();       /* release unused memory */
   return 1;

bail_out:
   if (escaped_bsr_name != NULL) {
      bfree(escaped_bsr_name);
   }

   if (escaped_where_name != NULL) {
      bfree(escaped_where_name);
   }

   if (regexp) {
      bfree(regexp);
   }

   free_rx(&rx);
   garbage_collect_memory();       /* release unused memory */
   return 0;
}
Exemplo n.º 6
0
/** Parse a line of data from a server.
 * @param[in] cptr Client that sent the data.
 * @param[in] buffer Start of input line.
 * @param[in] bufend End of input line.
 * @return 0 on success, -1 on parse error, or CPTR_KILLED if message
 * handler returns it.
 */
int parse_server(struct Client *cptr, char *buffer, char *bufend)
{
  struct Client*  from = cptr;
  char*           ch = buffer;
  char*           s;
  int             len;
  int             i;
  int             numeric = 0;
  int             paramcount;
  struct Message* mptr;

  Debug((DEBUG_DEBUG, "Server Parsing: %s", buffer));

  if (IsDead(cptr))
    return 0;

  para[0] = cli_name(from);

  /*
   * A server ALWAYS sends a prefix. When it starts with a ':' it's the
   * protocol 9 prefix: a nick or a server name. Otherwise it's a numeric
   * nick or server
   */
  if (*ch == ':')
  {
    /* Let para[0] point to the name of the sender */
    para[0] = ch + 1;
    if (!(ch = strchr(ch, ' ')))
      return -1;
    *ch++ = '\0';

    /* And let `from' point to its client structure,
       opps.. a server is _also_ a client --Nem */
    from = FindClient(para[0]);

    /*
     * If the client corresponding to the
     * prefix is not found. We must ignore it,
     * it is simply a lagged message traveling
     * upstream a SQUIT that removed the client
     * --Run
     */
    if (from == NULL)
    {
      Debug((DEBUG_NOTICE, "Unknown prefix (%s)(%s) from (%s)",
          para[0], buffer, cli_name(cptr)));
      ++ServerStats->is_unpf;
      while (*ch == ' ')
        ch++;
      /*
       * However, the only thing that MUST be
       * allowed to travel upstream against an
       * squit, is an SQUIT itself (the timestamp
       * protects us from being used wrong)
       */
      if (ch[1] == 'Q')
      {
        para[0] = cli_name(cptr);
        from = cptr;
      }
      else
        return 0;
    }
    else if (cli_from(from) != cptr)
    {
      ++ServerStats->is_wrdi;
      Debug((DEBUG_NOTICE, "Fake direction: Message (%s) coming from (%s)",
          buffer, cli_name(cptr)));
      return 0;
    }
  }
  else
  {
    char numeric_prefix[6];
    int  i;
    for (i = 0; i < 5; ++i)
    {
      if ('\0' == ch[i] || ' ' == (numeric_prefix[i] = ch[i]))
      {
        break;
      }
    }
    numeric_prefix[i] = '\0';

    /*
     * We got a numeric nick as prefix
     * 1 or 2 character prefixes are from servers
     * 3 or 5 chars are from clients
     */
    if (0 == i)
    {
      protocol_violation(cptr,"Missing Prefix");
      from = cptr;
    }
    else if (' ' == ch[1] || ' ' == ch[2])
      from = FindNServer(numeric_prefix);
    else
      from = findNUser(numeric_prefix);

    do
    {
      ++ch;
    }
    while (*ch != ' ' && *ch);

    /*
     * If the client corresponding to the
     * prefix is not found. We must ignore it,
     * it is simply a lagged message traveling
     * upstream a SQUIT that removed the client
     * --Run
     * There turned out to be other reasons that
     * a prefix is unknown, needing an upstream
     * KILL.  Also, next to an SQUIT we better
     * allow a KILL to pass too.
     * --Run
     */
    if (from == NULL)
    {
      ServerStats->is_unpf++;
      while (*ch == ' ')
        ch++;
      if (*ch == 'N' && (ch[1] == ' ' || ch[1] == 'I'))
        /* Only sent a KILL for a nick change */
      {
        struct Client *server;
        /* Kill the unknown numeric prefix upstream if
         * it's server still exists: */
        if ((server = FindNServer(numeric_prefix)) && cli_from(server) == cptr)
	  sendcmdto_one(&me, CMD_KILL, cptr, "%s :%s (Unknown numeric nick)",
			numeric_prefix, cli_name(&me));
      }
      /*
       * Things that must be allowed to travel
       * upstream against an squit:
       */
      if (ch[1] == 'Q' || (*ch == 'D' && ch[1] == ' ') ||
          (*ch == 'K' && ch[2] == 'L'))
        from = cptr;
      else
        return 0;
    }

    /* Let para[0] point to the name of the sender */
    para[0] = cli_name(from);

    if (cli_from(from) != cptr)
    {
      ServerStats->is_wrdi++;
      Debug((DEBUG_NOTICE, "Fake direction: Message (%s) coming from (%s)",
          buffer, cli_name(cptr)));
      return 0;
    }
  }

  while (*ch == ' ')
    ch++;
  if (*ch == '\0')
  {
    ServerStats->is_empt++;
    Debug((DEBUG_NOTICE, "Empty message from host %s:%s",
        cli_name(cptr), cli_name(from)));
    return (-1);
  }

  /*
   * Extract the command code from the packet.   Point s to the end
   * of the command code and calculate the length using pointer
   * arithmetic.  Note: only need length for numerics and *all*
   * numerics must have parameters and thus a space after the command
   * code. -avalon
   */
  s = strchr(ch, ' ');          /* s -> End of the command code */
  len = (s) ? (s - ch) : 0;
  if (len == 3 && IsDigit(*ch))
  {
    numeric = (*ch - '0') * 100 + (*(ch + 1) - '0') * 10 + (*(ch + 2) - '0');
    paramcount = 2; /* destination, and the rest of it */
    ServerStats->is_num++;
    mptr = NULL;                /* Init. to avoid stupid compiler warning :/ */
  }
  else
  {
    if (s)
      *s++ = '\0';

    /* Version      Receive         Send
     * 2.9          Long            Long
     * 2.10.0       Tkn/Long        Long
     * 2.10.10      Tkn/Long        Tkn
     * 2.10.20      Tkn             Tkn
     *
     * Clients/unreg servers always receive/
     * send long commands   -record
     *
     * And for the record, this trie parser really does not care. - Dianora
     */

    mptr = msg_tree_parse(ch, &tok_tree);

    if (mptr == NULL)
    {
      mptr = msg_tree_parse(ch, &msg_tree);
    }

    if (mptr == NULL)
    {
      /*
       * Note: Give error message *only* to recognized
       * persons. It's a nightmare situation to have
       * two programs sending "Unknown command"'s or
       * equivalent to each other at full blast....
       * If it has got to person state, it at least
       * seems to be well behaving. Perhaps this message
       * should never be generated, though...   --msa
       * Hm, when is the buffer empty -- if a command
       * code has been found ?? -Armin
       */
#ifdef DEBUGMODE
      if (buffer[0] != '\0')
      {
        Debug((DEBUG_ERROR, "Unknown (%s) from %s",
              ch, get_client_name(cptr, HIDE_IP)));
      }
#endif
      ServerStats->is_unco++;
      return (-1);
    }

    paramcount = mptr->parameters;
    i = bufend - ((s) ? s : ch);
    mptr->bytes += i;
  }
  /*
   * Must the following loop really be so devious? On
   * surface it splits the message to parameters from
   * blank spaces. But, if paramcount has been reached,
   * the rest of the message goes into this last parameter
   * (about same effect as ":" has...) --msa
   */

  /* Note initially true: s==NULL || *(s-1) == '\0' !! */

  i = 0;
  if (s)
  {
    if (paramcount > MAXPARA)
      paramcount = MAXPARA;
    for (;;)
    {
      /*
       * Never "FRANCE " again!! ;-) Clean
       * out *all* blanks.. --msa
       */
      while (*s == ' ')
        *s++ = '\0';

      if (*s == '\0')
        break;
      if (*s == ':')
      {
        /*
         * The rest is single parameter--can
         * include blanks also.
         */
	if (numeric)
	  para[++i] = s; /* preserve the colon to make do_numeric happy */
	else
	  para[++i] = s + 1;
        break;
      }
      para[++i] = s;
      if (i >= paramcount)
        break;
      for (; *s != ' ' && *s; s++);
    }
  }
  para[++i] = NULL;
  if (numeric)
    return (do_numeric(numeric, (*buffer != ':'), cptr, from, i, para));
  mptr->count++;

  return (*mptr->handlers[cli_handler(cptr)]) (cptr, from, i, para);
}
Exemplo n.º 7
0
/*
 * m_squit - SQUIT message handler
 *      parv[0] = sender prefix
 *      parv[1] = server name
 *      parv[2] = comment
 */
int m_squit(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
  struct ConfItem* aconf;
  char*            server;
  struct Client*   acptr;
  char  *comment = (parc > 2 && parv[2]) ? parv[2] : cptr->name;

  if (!(IsServer(sptr) || HasUmode(sptr,UMODE_REMOTE)))
    {
      if (SeesOperMessages(sptr))
	sendto_one(sptr,":%s NOTICE %s :You have no R umode", me.name, parv[0]);
      else
	sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]);
      return 0;
    }

  if (parc > 1)
    {
      server = parv[1];
      /*
      ** To accomodate host masking, a squit for a masked server
      ** name is expanded if the incoming mask is the same as
      ** the server name for that link to the name of link.
      */
      while ((*server == '*') && IsServer(cptr))
        {
          aconf = cptr->serv->nline;
          if (!aconf)
            break;
          if (!irccmp(server, my_name_for_link(me.name, aconf)))
            server = cptr->name;
          break; /* WARNING is normal here */
          /* NOTREACHED */
        }
      /*
      ** The following allows wild cards in SQUIT. Only useful
      ** when the command is issued by an oper.
      */
      for (acptr = GlobalClientList; (acptr = next_client(acptr, server));
           acptr = acptr->next)
        if (IsServer(acptr) || IsMe(acptr))
          break;
      if (acptr && IsMe(acptr))
        {
          acptr = cptr;
          server = cptr->name;
        }
    }
  else
    {
      /*
      ** This is actually protocol error. But, well, closing
      ** the link is very proper answer to that...
      **
      ** Closing the client's connection probably wouldn't do much
      ** good.. any oper out there should know that the proper way
      ** to disconnect is /QUIT :)
      **
      ** its still valid if its not a local client, its then
      ** a protocol error for sure -Dianora
      */
      if(MyClient(sptr))
        {
          sendto_one(sptr, form_str(ERR_NEEDMOREPARAMS),
               me.name, parv[0], "SQUIT");
          return 0;
        }
      else
        {
          server = cptr->host;
          acptr = cptr;
        }
    }

  /*
  ** SQUIT semantics is tricky, be careful...
  **
  ** The old (irc2.2PL1 and earlier) code just cleans away the
  ** server client from the links (because it is never true
  ** "cptr == acptr".
  **
  ** This logic here works the same way until "SQUIT host" hits
  ** the server having the target "host" as local link. Then it
  ** will do a real cleanup spewing SQUIT's and QUIT's to all
  ** directions, also to the link from which the orinal SQUIT
  ** came, generating one unnecessary "SQUIT host" back to that
  ** link.
  **
  ** One may think that this could be implemented like
  ** "hunt_server" (e.g. just pass on "SQUIT" without doing
  ** nothing until the server having the link as local is
  ** reached). Unfortunately this wouldn't work in the real life,
  ** because either target may be unreachable or may not comply
  ** with the request. In either case it would leave target in
  ** links--no command to clear it away. So, it's better just
  ** clean out while going forward, just to be sure.
  **
  ** ...of course, even better cleanout would be to QUIT/SQUIT
  ** dependant users/servers already on the way out, but
  ** currently there is not enough information about remote
  ** clients to do this...   --msa
  */
  if (!acptr)
    {
      sendto_one(sptr, form_str(ERR_NOSUCHSERVER),
                 me.name, parv[0], server);
      return 0;
    }

  if (MyClient(sptr) && !HasUmode(sptr,UMODE_REMOTE) && !MyConnect(acptr))
    {
      sendto_one(sptr,":%s NOTICE %s :You have no R umode",me.name,parv[0]);
      return 0;
    }

  /*
  **  Notify all opers, if my local link is remotely squitted
  */
  if (MyConnect(acptr) && IsServer(cptr))
    {
      sendto_ops_flag(UMODE_AUSPEX,
		      "%s received SQUIT %s from %s (%s)",
		      me.name, server, get_client_name(sptr,FALSE), comment);
      logprintf(L_TRACE, "SQUIT From %s : %s (%s)", parv[0], server, comment);
    }
  else if (MyConnect(acptr))
    sendto_ops_flag(UMODE_SERVNOTICE, "Received SQUIT %s from %s (%s)",
			   acptr->name, get_client_name(sptr,FALSE), comment);
  
  return exit_client(cptr, acptr, sptr, comment);
}
Exemplo n.º 8
0
int ssl_handshake(struct Client *cptr) {

  char *str;
  int err;

      cptr->ssl = (struct SSL*) SSL_new (ctx);
//      cptr->use_ssl=1;


      CHK_NULL (cptr->ssl);
      SSL_set_fd ((SSL *)cptr->ssl, cptr->fd);
      set_non_blocking(cptr->fd);
      err = ircd_SSL_accept (cptr, cptr->fd);
      if ((err)==-1) {
        irclog(L_ERROR,"Lost connection to %s:Error in SSL_accept()", 
                     get_client_name(cptr, TRUE));
	SSL_shutdown((SSL *)cptr->ssl);
	SSL_free((SSL *)cptr->ssl);
	cptr->ssl = NULL;
        return 0;
      }

      /* Get the cipher - opt */
      SetSecure(cptr);
      
      irclog (L_DEBUG, "SSL connection using %s", SSL_get_cipher ((SSL *)cptr->ssl));

      /* Get client's certificate (note: beware of dynamic
       * allocation) - opt */

      cptr->client_cert = (struct X509*)SSL_get_peer_certificate ((SSL *)cptr->ssl);

      if (cptr->client_cert != NULL)
      {
        irclog (L_DEBUG,"Client certificate:");

        str = X509_NAME_oneline (X509_get_subject_name ((X509*)cptr->client_cert), 0, 0);
        CHK_NULL (str);
        irclog (L_DEBUG, "\t subject: %s", str);
        // Bejvavalo
 	//       Free (str);
	free(str);
	
        str = X509_NAME_oneline (X509_get_issuer_name ((X509*)cptr->client_cert), 0, 0);
        CHK_NULL (str);
        irclog (L_DEBUG, "\t issuer: %s", str);
        // Bejvavalo
        // Free (str);
	free(str);
	
        /* We could do all sorts of certificate
         * verification stuff here before
         *        deallocating the certificate. */

        X509_free ((X509*)cptr->client_cert);
      }
      else
        irclog (L_DEBUG, "Client does not have certificate.");

      return 1;

}
Exemplo n.º 9
0
/**
 * Exits a client of *any* type (user, server, etc)
 * from this server. Also, this generates all necessary prototol
 * messages that this exit may cause.
 *
 * This function implicitly exits all other clients depending on
 * this connection.
 *
 * For convenience, this function returns a suitable value for
 * m_function return value:
 *
 *   CPTR_KILLED     if (cptr == bcptr)
 *   0                if (cptr != bcptr)
 *
 * This function can be called in two ways:
 * 1) From before or in parse(), exiting the 'cptr', in which case it was
 *    invoked as exit_client(cptr, cptr, &me,...), causing it to always
 *    return CPTR_KILLED.
 * 2) Via parse from a m_function call, in which case it was invoked as
 *    exit_client(cptr, acptr, sptr, ...). Here 'sptr' is known; the client
 *    that generated the message in a way that we can assume he already
 *    did remove acptr from memory himself (or in other cases we don't mind
 *    because he will be delinked.) Or invoked as:
 *    exit_client(cptr, acptr/sptr, &me, ...) when WE decide this one should
 *    be removed.
 * In general: No generated SQUIT or QUIT should be sent to source link
 * sptr->from. And CPTR_KILLED should be returned if cptr got removed (too).
 *
 * --Run
 * @param cptr Connection currently being handled by read_message.
 * @param victim Client being killed.
 * @param killer Client that made the decision to remove \a victim.
 * @param comment Reason for the exit.
 * @return CPTR_KILLED if cptr == bcptr, else 0.
 */
int exit_client(struct Client *cptr,
    struct Client* victim,
    struct Client* killer,
    const char* comment)
{
  struct Client* acptr = 0;
  struct DLink *dlp;
  time_t on_for;

  char comment1[HOSTLEN + HOSTLEN + 2];
  assert(killer);
  if (MyConnect(victim))
  {
    SetFlag(victim, FLAG_CLOSING);

    if (feature_bool(FEAT_CONNEXIT_NOTICES) && IsUser(victim))
      sendto_opmask_butone(0, SNO_CONNEXIT,
                           "Client exiting: %s (%s@%s) [%s] [%s] <%s%s>",
                           cli_name(victim), cli_user(victim)->username,
                           cli_user(victim)->host, comment,
                           ircd_ntoa(&cli_ip(victim)),
                           NumNick(victim) /* two %s's */);
    update_load();

    on_for = CurrentTime - cli_firsttime(victim);

    if (IsUser(victim) || IsUserPort(victim))
      auth_send_exit(victim);

    if (IsUser(victim))
      log_write(LS_USER, L_TRACE, 0, "%Tu %i %s@%s %s %s %s%s %s :%s",
		cli_firsttime(victim), on_for,
		cli_user(victim)->username, cli_sockhost(victim),
                ircd_ntoa(&cli_ip(victim)),
                IsAccount(victim) ? cli_username(victim) : "0",
                NumNick(victim), /* two %s's */
                cli_name(victim), cli_info(victim));

    if (victim != cli_from(killer)  /* The source knows already */
        && IsClient(victim))    /* Not a Ping struct or Log file */
    {
      if (IsServer(victim) || IsHandshake(victim))
	sendcmdto_one(killer, CMD_SQUIT, victim, "%s 0 :%s", cli_name(&me), comment);
      else if (!IsConnecting(victim)) {
        if (!IsDead(victim)) {
	  if (IsServer(victim))
	    sendcmdto_one(killer, CMD_ERROR, victim,
			  ":Closing Link: %s by %s (%s)", cli_name(victim),
			  cli_name(killer), comment);
	  else
	    sendrawto_one(victim, MSG_ERROR " :Closing Link: %s by %s (%s)",
			  cli_name(victim),
                          cli_name(IsServer(killer) ? &his : killer),
			  comment);
	}
      }
      if ((IsServer(victim) || IsHandshake(victim) || IsConnecting(victim)) &&
          (killer == &me || (IsServer(killer) &&
          (strncmp(comment, "Leaf-only link", 14) ||
          strncmp(comment, "Non-Hub link", 12)))))
      {
        /*
         * Note: check user == user needed to make sure we have the same
         * client
         */
        if (cli_serv(victim)->user && *(cli_serv(victim))->by &&
            (acptr = findNUser(cli_serv(victim)->by))) {
          if (cli_user(acptr) == cli_serv(victim)->user) {
	    sendcmdto_one(&me, CMD_NOTICE, acptr,
			  "%C :Link with %s canceled: %s", acptr,
			  cli_name(victim), comment);
          }
          else {
            /*
             * not right client, set by to empty string
             */
            acptr = 0;
            *(cli_serv(victim))->by = '\0';
          }
        }
        if (killer == &me)
	  sendto_opmask_butone(acptr, SNO_OLDSNO, "Link with %s canceled: %s",
			       cli_name(victim), comment);
      }
    }
    /*
     *  Close the Client connection first.
     */
    close_connection(victim);
  }

  if (IsServer(victim))
  {
    if (feature_bool(FEAT_HIS_NETSPLIT))
      strcpy(comment1, "*.net *.split");
    else
    {
      strcpy(comment1, cli_name(cli_serv(victim)->up));
      strcat(comment1, " ");
      strcat(comment1, cli_name(victim));
    }

    if (IsUser(killer))
      sendto_opmask_butone(killer, SNO_OLDSNO, "%s SQUIT by %s [%s]:",
			   (cli_user(killer)->server == victim ||
			    cli_user(killer)->server == cli_serv(victim)->up) ?
			   "Local" : "Remote",
			   get_client_name(killer, HIDE_IP),
			   cli_name(cli_user(killer)->server));
    else if (killer != &me && cli_serv(victim)->up != killer)
      sendto_opmask_butone(0, SNO_OLDSNO, "Received SQUIT %s from %s :",
			   cli_name(victim), IsServer(killer) ? cli_name(killer) :
			   get_client_name(killer, HIDE_IP));
    sendto_opmask_butone(0, SNO_NETWORK, "Net break: %C %C (%s)",
			 cli_serv(victim)->up, victim, comment);
  }

  /*
   * First generate the needed protocol for the other server links
   * except the source:
   */
  for (dlp = cli_serv(&me)->down; dlp; dlp = dlp->next) {
    if (dlp->value.cptr != cli_from(killer) && dlp->value.cptr != victim)
    {
      if (IsServer(victim))
	sendcmdto_one(killer, CMD_SQUIT, dlp->value.cptr, "%s %Tu :%s",
		      cli_name(victim), cli_serv(victim)->timestamp, comment);
      else if (IsUser(victim) && !HasFlag(victim, FLAG_KILLED))
	sendcmdto_one(victim, CMD_QUIT, dlp->value.cptr, ":%s", comment);
    }
  }
  /* Then remove the client structures */
  if (IsServer(victim))
    exit_downlinks(victim, killer, comment1);
  exit_one_client(victim, comment);

  /*
   *  cptr can only have been killed if it was cptr itself that got killed here,
   *  because cptr can never have been a dependent of victim    --Run
   */
  return (cptr == victim) ? CPTR_KILLED : 0;
}
Exemplo n.º 10
0
/*
 * Check_pings_list()
 *
 * inputs	- pointer to list to check
 * output	- NONE
 * side effects	- 
 */
static void
check_pings_list(dlink_list *list)
{
  char         scratch[32];	/* way too generous but... */
  struct Client *client_p;          /* current local client_p being examined */
  int           ping = 0;       /* ping time value from client */
  dlink_node    *ptr, *next_ptr;

  for (ptr = list->head; ptr; ptr = next_ptr)
    {
      next_ptr = ptr->next;
      client_p = ptr->data;

      /*
      ** Note: No need to notify opers here. It's
      ** already done when "FLAGS_DEADSOCKET" is set.
      */
      if (client_p->flags & FLAGS_DEADSOCKET)
        {
	  /* Ignore it, its been exited already */
          continue; 
        }
      if (IsPerson(client_p))
        {
          if(!IsExemptKline(client_p) &&
             GlobalSetOptions.idletime && 
             !IsOper(client_p) &&
             !IsIdlelined(client_p) && 
             ((CurrentTime - client_p->user->last) > GlobalSetOptions.idletime))
            {
              struct ConfItem *aconf;

              aconf = make_conf();
              aconf->status = CONF_KILL;

              DupString(aconf->host, client_p->host);
              DupString(aconf->passwd, "idle exceeder");
              DupString(aconf->name, client_p->username);
              aconf->port = 0;
              aconf->hold = CurrentTime + 60;
              add_temp_kline(aconf);
              sendto_realops_flags(FLAGS_ALL, L_ALL,
			   "Idle time limit exceeded for %s - temp k-lining",
				   get_client_name(client_p, HIDE_IP));


	      (void)exit_client(client_p, client_p, &me, aconf->passwd);
              continue;
            }
        }

      if (!IsRegistered(client_p))
        ping = CONNECTTIMEOUT;
      else
        ping = get_client_ping(client_p);

      if (ping < (CurrentTime - client_p->lasttime))
        {
          /*
           * If the client/server hasnt talked to us in 2*ping seconds
           * and it has a ping time, then close its connection.
           */
          if (((CurrentTime - client_p->lasttime) >= (2 * ping) &&
               (client_p->flags & FLAGS_PINGSENT)))
            {
              if (IsServer(client_p) || IsConnecting(client_p) ||
                  IsHandshake(client_p))
                {
                  sendto_realops_flags(FLAGS_ALL, L_ADMIN,
				       "No response from %s, closing link",
				       get_client_name(client_p, HIDE_IP));
                  sendto_realops_flags(FLAGS_ALL, L_OPER,
                                       "No response from %s, closing link",
                                       get_client_name(client_p, MASK_IP));
                  ilog(L_NOTICE, "No response from %s, closing link",
                      get_client_name(client_p, HIDE_IP));
                }
	      (void)ircsprintf(scratch,
			       "Ping timeout: %d seconds",
			       (int)(CurrentTime - client_p->lasttime));
	      
	      (void)exit_client(client_p, client_p, &me, scratch);
              continue;
            }
          else if ((client_p->flags & FLAGS_PINGSENT) == 0)
            {
              /*
               * if we havent PINGed the connection and we havent
               * heard from it in a while, PING it to make sure
               * it is still alive.
               */
              client_p->flags |= FLAGS_PINGSENT;
              /* not nice but does the job */
              client_p->lasttime = CurrentTime - ping;
              sendto_one(client_p, "PING :%s", me.name);
            }
        }
      /* ping_timeout: */

    }
}
Exemplo n.º 11
0
/*
 * check_klines
 * inputs	- NONE
 * output	- NONE
 * side effects - Check all connections for a pending kline against the
 * 		  client, exit the client if a kline matches.
 */
void 
check_klines(void)
{               
  struct Client *client_p;          /* current local client_p being examined */
  struct ConfItem     *aconf = (struct ConfItem *)NULL;
  char          *reason;                /* pointer to reason string */
  dlink_node    *ptr, *next_ptr;
 
  for (ptr = lclient_list.head; ptr; ptr = next_ptr)
    {
      next_ptr = ptr->next;
      client_p = ptr->data;
      
      if (IsMe(client_p))
	continue;
	
      /* if there is a returned struct ConfItem then kill it */
      if ((aconf = find_dline(&client_p->localClient->ip,
			      client_p->localClient->aftype)))
	{
	  if (aconf->status & CONF_EXEMPTDLINE)
	    continue;
	    
	  sendto_realops_flags(FLAGS_ALL, L_ALL,"DLINE active for %s",
			       get_client_name(client_p, HIDE_IP));
			       
	  if (ConfigFileEntry.kline_with_connection_closed &&
	      ConfigFileEntry.kline_with_reason)
	  {
	    reason = "Connection closed";

	    if(IsPerson(client_p))
  	      sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP),
  	                 me.name, client_p->name,
	 	         aconf->passwd ? aconf->passwd : "D-lined");
            else
	      sendto_one(client_p, "NOTICE DLINE :*** You have been D-lined");
	  }
	  else
	  {
	    if(ConfigFileEntry.kline_with_connection_closed)
	      reason = "Connection closed";
	    else if(ConfigFileEntry.kline_with_reason && aconf->passwd)
	      reason = aconf->passwd;
	    else
	      reason = "D-lined";

            if(IsPerson(client_p))
	      sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP),
	                 me.name, client_p->name, reason);
            else
	      sendto_one(client_p, "NOTICE DLINE :*** You have been D-lined");
	  }
	    
	  (void)exit_client(client_p, client_p, &me, reason);
	  continue; /* and go examine next fd/client_p */
	}

      if (IsPerson(client_p))
	{
	  if (ConfigFileEntry.glines &&
	      (aconf = find_gkill(client_p, client_p->username)))
	    {
	      if (IsExemptKline(client_p))
		{
		  sendto_realops_flags(FLAGS_ALL, L_ALL,
				       "GLINE over-ruled for %s, client is kline_exempt",
				       get_client_name(client_p, HIDE_IP));
		  continue;
		}
	      
	      if (IsExemptGline(client_p))
		{
		  sendto_realops_flags(FLAGS_ALL, L_ALL,
				       "GLINE over-ruled for %s, client is gline_exempt",
				       get_client_name(client_p, HIDE_IP));
		  continue;
		}
       
	      sendto_realops_flags(FLAGS_ALL, L_ALL, "GLINE active for %s",
				   get_client_name(client_p, HIDE_IP));
			    
	      if(ConfigFileEntry.kline_with_connection_closed &&
	         ConfigFileEntry.kline_with_reason)
 	      {
		  reason = "Connection closed";

		  sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP),
		             me.name, client_p->name,
			     aconf->passwd ? aconf->passwd : "G-lined");
	      } 
	      else 
	      {
	        if(ConfigFileEntry.kline_with_connection_closed)
		  reason = "Connection closed";
		else if(ConfigFileEntry.kline_with_reason && aconf->passwd)
		  reason = aconf->passwd;
		else
		  reason = "G-lined";

		sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP),
		           me.name, client_p->name, reason);
	      }
	
	      (void)exit_client(client_p, client_p, &me, reason);
	      /* and go examine next fd/client_p */    
	      continue;
	    } 
	  else if((aconf = find_kill(client_p))) 
	    {
	      /* if there is a returned struct ConfItem.. then kill it */
	      if (IsExemptKline(client_p))
		{
		  sendto_realops_flags(FLAGS_ALL, L_ALL,
				       "KLINE over-ruled for %s, client is kline_exempt",
				       get_client_name(client_p, HIDE_IP));
		  continue;
		}

	      sendto_realops_flags(FLAGS_ALL, L_ALL, "KLINE active for %s",
				   get_client_name(client_p, HIDE_IP));

              if(ConfigFileEntry.kline_with_connection_closed &&
	          ConfigFileEntry.kline_with_reason)
	      {
	        reason = "Connection closed";

		sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP),
		           me.name, client_p->name, 
			   aconf->passwd ? aconf->passwd : "K-lined");
              }
	      else
	      {
	        if(ConfigFileEntry.kline_with_connection_closed)
		  reason = "Connection closed";
		else if(ConfigFileEntry.kline_with_reason && aconf->passwd)
		  reason = aconf->passwd;
		else
		  reason = "K-lined";

		sendto_one(client_p, form_str(ERR_YOUREBANNEDCREEP),
		           me.name, client_p->name, reason);
              }
	      
	      (void)exit_client(client_p, client_p, &me, reason);
	      continue; 
	    }
	}
    }
 
  /* also check the unknowns list for new dlines */
  for (ptr = unknown_list.head; ptr; ptr = next_ptr)
  {
    next_ptr = ptr->next;
    client_p = ptr->data;

    if((aconf = find_dline(&client_p->localClient->ip,
                           client_p->localClient->aftype)))
    {
      if(aconf->status & CONF_EXEMPTDLINE)
        continue;

      sendto_one(client_p, "NOTICE DLINE :*** You have been D-lined");
      exit_client(client_p, client_p, &me, "D-lined");
    }
  }

}
Exemplo n.º 12
0
/*
 * m_svinfo - SVINFO message handler
 *      parv[0] = sender prefix
 *      parv[1] = TS_CURRENT for the server
 *      parv[2] = TS_MIN for the server
 *      parv[3] = server is standalone or connected to non-TS only
 *      parv[4] = server's idea of UTC time
 */
int m_svinfo(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
  time_t deltat;
  time_t theirtime;

  if (MyConnect(sptr) && IsUnknown(sptr))
    return exit_client(sptr, sptr, sptr, "Need SERVER before SVINFO");

  if (!IsServer(sptr) || !MyConnect(sptr) || parc < 5)
    return 0;

  if (TS_CURRENT < atoi(parv[2]) || atoi(parv[1]) < TS_MIN)
    {
      /*
       * a server with the wrong TS version connected; since we're
       * TS_ONLY we can't fall back to the non-TS protocol so
       * we drop the link  -orabidoo
       */
#ifdef HIDE_SERVERS_IPS
      sendto_realops("Link %s dropped, wrong TS protocol version (%s,%s)",
      		 get_client_name(sptr, MASK_IP), parv[1], parv[2]);
#else		 
      sendto_realops("Link %s dropped, wrong TS protocol version (%s,%s)",
                 get_client_name(sptr, TRUE), parv[1], parv[2]);
#endif		 
      return exit_client(sptr, sptr, sptr, "Incompatible TS version");
    }

  sptr->serv->tsversion = atoi(parv[1]);
  
  /*
   * since we're here, might as well set CurrentTime while we're at it
   */
  CurrentTime = time(0);
  theirtime = atol(parv[4]);
  deltat = abs(theirtime - CurrentTime);

  if (deltat > TS_MAX_DELTA)
    {
#ifdef HIDE_SERVERS_IPS
      sendto_realops(
       "Link %s dropped, excessive TS delta (my TS=%d, their TS=%d, delta=%d)",
       		 get_client_name(sptr, MASK_IP), CurrentTime, theirtime,deltat);
#else		 
      sendto_realops(
       "Link %s dropped, excessive TS delta (my TS=%d, their TS=%d, delta=%d)",
                 get_client_name(sptr, TRUE), CurrentTime, theirtime,deltat);
#endif		 
      return exit_client(sptr, sptr, sptr, "Excessive TS delta");
    }

  if (deltat > TS_WARN_DELTA)
    { 
#ifdef HIDE_SERVERS_IPS
      sendto_realops(
      		 "Link %s notable TS delta (my TS=%d, their TS=%d, delta=%d)",
		 get_client_name(sptr, MASK_IP), CurrentTime, theirtime, deltat);
#else		 
      sendto_realops(
                 "Link %s notable TS delta (my TS=%d, their TS=%d, delta=%d)",
                 get_client_name(sptr, TRUE), CurrentTime, theirtime, deltat);
#endif		 
    }

  return 0;
}
Exemplo n.º 13
0
/*
** m_ltrace - LimitedTRACE... like m_trace() but doesn't return TRACEUSER, TRACEUNKNOWN, or TRACECLASS
**      parv[0] = sender prefix
**      parv[1] = servername
*/
int     m_ltrace(struct Client *cptr,
                struct Client *sptr,
                int parc,
                char *parv[])
{
  int   i;
  struct Client       *acptr = NULL;
  char  *tname;
  int   doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS];
  int   cnt = 0, wilds, dow;
  static time_t now;
  
  if (check_registered(sptr))
    return 0;

#ifdef SERVERHIDE
  if (!IsAnOper(sptr))
    return 0;
#endif

  if (parc > 2)
    if (hunt_server(cptr, sptr, ":%s LTRACE %s :%s",
                    2, parc, parv))
      return 0;
  
  if (parc > 1)
    tname = parv[1];
  else
    tname = me.name;

  switch (hunt_server(cptr, sptr, ":%s LTRACE :%s", 1, parc, parv))
    {
    case HUNTED_PASS: /* note: gets here only if parv[1] exists */
      {
        struct Client *ac2ptr;
        
        ac2ptr = next_client(GlobalClientList, tname);
        if (ac2ptr)
          sendto_one(sptr, form_str(RPL_TRACELINK), me.name, parv[0],
                     ircd_version, debugmode, tname, ac2ptr->from->name);
        else
          sendto_one(sptr, form_str(RPL_TRACELINK), me.name, parv[0],
                     ircd_version, debugmode, tname, "ac2ptr_is_NULL!!");
        return 0;
      }
    case HUNTED_ISME:
      break;
    default:
      return 0;
    }


  if(MyClient(sptr))
    sendto_realops_flags(FLAGS_SPY, "ltrace requested by %s (%s@%s) [%s]",
                       sptr->name, sptr->username, sptr->host,
                       sptr->user->server);


  doall = (parv[1] && (parc > 1)) ? match(tname, me.name): TRUE;
  wilds = !parv[1] || strchr(tname, '*') || strchr(tname, '?');
  dow = wilds || doall;

  if(!IsAnOper(sptr) || !dow) /* non-oper traces must be full nicks */
                              /* lets also do this for opers tracing nicks */
    { 
      const char* name;
      const char* ip;
      int         c_class;

      acptr = hash_find_client(tname,(struct Client *)NULL);
      if(!acptr || !IsPerson(acptr))
        { 
          /* this should only be reached if the matching
             target is this server */
          sendto_one(sptr, form_str(RPL_ENDOFTRACE),me.name,
                     parv[0], tname);
          return 0;
        }
      name = get_client_name(acptr, FALSE);
      ip = inetntoa((char*) &acptr->ip);

      c_class = get_client_class(acptr);

      if (IsAnOper(acptr))
        { 
          sendto_one(sptr, form_str(RPL_TRACEOPERATOR),
                     me.name, parv[0], c_class,
                     name,
                     IsAnOper(sptr)?ip:(IsIPHidden(acptr)?"255.255.255.255":ip),
                     now - acptr->lasttime,
                     (acptr->user)?(now - acptr->user->last):0);
        }
      sendto_one(sptr, form_str(RPL_ENDOFTRACE),me.name,
                 parv[0], tname);
      return 0;
    }
  
  for (i = 0; i < MAXCONNECTIONS; i++)
    link_s[i] = 0, link_u[i] = 0;
                        
  if (dow && LIFESUX && !IsOper(sptr))
    {
      sendto_one(sptr,form_str(RPL_LOAD2HI),me.name,parv[0]);
      return 0;
    }

  /*
   * Count up all the servers and clients in a downlink.
   */
  if (doall) {
    for (acptr = GlobalClientList; acptr; acptr = acptr->next) {
      if (IsServer(acptr)) 
        ++link_s[acptr->from->fd];
    }
  }

  /* report all direct connections */
  now = time(NULL);
  for (i = 0; i <= highest_fd; i++)
    {
      const char* name;
      const char* ip;
      int         c_class;
      
      if (!(acptr = local[i])) /* Local Connection? */
        continue;
      if (IsInvisible(acptr) && dow &&
          !(MyConnect(sptr) && IsAnOper(sptr)) &&
          !IsAnOper(acptr) && (acptr != sptr))
        continue;
      if (!doall && wilds && !match(tname, acptr->name))
        continue;
      if (!dow && irccmp(tname, acptr->name))
        continue;
      name = get_client_name(acptr, FALSE);
      ip = inetntoa((const char*) &acptr->ip);

      c_class = get_client_class(acptr);
      
      switch(acptr->status)
        {
        case STAT_HANDSHAKE:
#ifdef HIDE_SERVERS_IPS
	  name=get_client_name(acptr, MASK_IP);
#endif	  
          sendto_one(sptr, form_str(RPL_TRACEHANDSHAKE), me.name,
                     parv[0], c_class, name);
          cnt++;
          break;
	case STAT_CONNECTING:
#ifdef HIDE_SERVERS_IPS
          name=get_client_name(acptr, MASK_IP);
#endif
	  sendto_one(sptr, form_str(RPL_TRACECONNECTING), me.name, 
	             parv[0], c_class, name);
	  cnt++;
	  break;
        case STAT_ME:
          break;
        case STAT_CLIENT:
          /* Well, most servers don't have a LOT of OPERs... let's show them too */
          if ((IsAnOper(sptr) &&
              (MyClient(sptr) || !(dow && IsInvisible(acptr))))
              || !dow || IsAnOper(acptr))
            {
              if (IsAnOper(acptr))
                sendto_one(sptr,
                           form_str(RPL_TRACEOPERATOR),
                           me.name, parv[0], c_class,
                           name, 
                           IsAnOper(sptr)?ip:(IsIPHidden(acptr)?"255.255.255.255":ip), 
                           now - acptr->lasttime,
                           (acptr->user)?(now - acptr->user->last):0);
              cnt++;
            }
          break;
        case STAT_SERVER:
#if 0
          if (acptr->serv->user)
            sendto_one(sptr, form_str(RPL_TRACESERVER),
                       me.name, parv[0], c_class, link_s[i],
                       link_u[i], name, acptr->serv->by,
                       acptr->serv->user->username,
                       acptr->serv->user->host, now - acptr->lasttime);
          else
#endif
#ifdef HIDE_SERVERS_IPS
	    name=get_client_name(acptr, MASK_IP);
#endif	    
            sendto_one(sptr, form_str(RPL_TRACESERVER),
                       me.name, parv[0], c_class, link_s[i],
                       link_u[i], name, *(acptr->serv->by) ?
                       acptr->serv->by : "*", "*",
                       me.name, now - acptr->lasttime);
          cnt++;
          break;
        default: /* ...we actually shouldn't come here... --msa */
          sendto_one(sptr, form_str(RPL_TRACENEWTYPE), me.name,
                     parv[0], name);
          cnt++;
          break;
        }
    }
  /*
   * Add these lines to summarize the above which can get rather long
   * and messy when done remotely - Avalon
   */
  if (!IsAnOper(sptr) || !cnt)
    {
      if (cnt)
          return 0;
      /* let the user have some idea that its at the end of the
       * trace
       */
      sendto_one(sptr, form_str(RPL_TRACESERVER),
                 me.name, parv[0], 0, link_s[me.fd],
                 link_u[me.fd], me.name, "*", "*", me.name);
      sendto_one(sptr, form_str(RPL_ENDOFTRACE),me.name,
                 parv[0],tname);
      return 0;
    }
  sendto_one(sptr, form_str(RPL_ENDOFTRACE),me.name, parv[0],tname);
  return 0;
}
Exemplo n.º 14
0
static	time_t	check_pings(time_t currenttime)
{		
  register	aClient	*cptr;		/* current local cptr being examined */
  aConfItem 	*aconf = (aConfItem *)NULL;
  int		ping = 0;		/* ping time value from client */
  int		i;			/* used to index through fd/cptr's */
  time_t	oldest = 0;		/* next ping time */
  time_t	timeout;		/* found necessary ping time */
  char *reason;				/* pointer to reason string */
  int die_index=0;			/* index into list */
  char ping_time_out_buffer[64];	/* blech that should be a define */

					/* of dying clients */
  dying_clients[0] = (aClient *)NULL;	/* mark first one empty */

  /*
   * I re-wrote the way klines are handled. Instead of rescanning
   * the local[] array and calling exit_client() right away, I
   * mark the client thats dying by placing a pointer to its aClient
   * into dying_clients[]. When I have examined all in local[],
   * I then examine the dying_clients[] for aClient's to exit.
   * This saves the rescan on k-lines, also greatly simplifies the code,
   *
   * Jan 28, 1998
   * -Dianora
   */

   for (i = 0; i <= highest_fd; i++)
    {
      if (!(cptr = local[i]) || IsMe(cptr) || IsLog(cptr))
	continue;		/* and go examine next fd/cptr */
      /*
      ** Note: No need to notify opers here. It's
      ** already done when "FLAGS_DEADSOCKET" is set.
      */
      if (cptr->flags & FLAGS_DEADSOCKET)
	{
	  /* N.B. EVERY single time dying_clients[] is set
	   * it must be followed by an immediate continue,
	   * to prevent this cptr from being marked again for exit.
	   * If you don't, you could cause exit_client() to be called twice
	   * for the same cptr. i.e. bad news
	   * -Dianora
	   */

	  dying_clients[die_index] = cptr;
	  dying_clients_reason[die_index++] =
	    ((cptr->flags & FLAGS_SENDQEX) ?
	     "SendQ exceeded" : "Dead socket");
	  dying_clients[die_index] = (aClient *)NULL;
	  continue;		/* and go examine next fd/cptr */
	}

      if (rehashed)
	{
	  if(dline_in_progress)
	    {
	      if(IsPerson(cptr))
		{
		  if( (aconf = find_dkill(cptr)) ) /* if there is a returned 
						      aConfItem then kill it */
		    {
		      sendto_ops("D-line active for %s",
				 get_client_name(cptr, FALSE));

		      dying_clients[die_index] = cptr;
#ifdef KLINE_WITH_REASON
		      reason = aconf->passwd ? aconf->passwd : "D-lined";
		      dying_clients_reason[die_index++] = reason;
#else
		      dying_clients_reason[die_index++] = "D-lined";
#endif
		      dying_clients[die_index] = (aClient *)NULL;
		      sendto_one(cptr, err_str(ERR_YOUREBANNEDCREEP),
				 me.name, cptr->name, reason);
		      continue;		/* and go examine next fd/cptr */
		    }
		}
	    }
	  else
	    {
	      if(IsPerson(cptr))
		{
#ifdef GLINES
		  if( (aconf = find_gkill(cptr)) )
		    {
		      sendto_ops("G-line active for %s",
				 get_client_name(cptr, FALSE));

		      dying_clients[die_index] = cptr;
#ifdef KLINE_WITH_REASON
		      reason = aconf->passwd ? aconf->passwd : "G-lined";
		      dying_clients_reason[die_index++] = reason;
#else
		      dying_clients_reason[die_index++] = "G-lined";
#endif
		      dying_clients[die_index] = (aClient *)NULL;
		      sendto_one(cptr, err_str(ERR_YOUREBANNEDCREEP),
				 me.name, cptr->name, reason);
		      continue;		/* and go examine next fd/cptr */
		    }
		  else
#endif
		  if((aconf = find_kill(cptr)))	/* if there is a returned
						   aConfItem.. then kill it */
		    {
		      sendto_ops("K-line active for %s",
				 get_client_name(cptr, FALSE));
		      dying_clients[die_index] = cptr;

#ifdef KLINE_WITH_REASON
#ifdef K_COMMENT_ONLY
		      reason = aconf->passwd ? aconf->passwd : "K-lined";
#else
		      reason = (BadPtr(aconf->passwd) || 
				!is_comment(aconf->passwd)) ?
			"K-lined" : aconf->passwd;
#endif
		      dying_clients_reason[die_index++] = reason;
#else
		      dying_clients_reason[die_index++] = "K-lined";
#endif
		      dying_clients[die_index] = (aClient *)NULL;
		      sendto_one(cptr, err_str(ERR_YOUREBANNEDCREEP),
				 me.name, cptr->name, reason);
		      continue;		/* and go examine next fd/cptr */
		    }
		}
	    }
	}

#ifdef IDLE_CHECK
      if (IsPerson(cptr))
	{
	  if( !IsElined(cptr) && ((timeofday - cptr->user->last) > idle_time))
	    {
	      aConfItem *aconf;

	      dying_clients[die_index] = cptr;
	      dying_clients_reason[die_index++] = "idle exceeder";
	      dying_clients[die_index] = (aClient *)NULL;

	      aconf = make_conf();
	      aconf->status = CONF_KILL;
	      DupString(aconf->host, cptr->user->host);
	      DupString(aconf->passwd, "idle exceeder" );
	      DupString(aconf->name, cptr->user->username);
	      aconf->port = 0;
	      aconf->hold = timeofday + 60;
	      add_temp_kline(aconf);
	      sendto_ops("Idle exceeder %s temp k-lining",
			 get_client_name(cptr,FALSE));
	      continue;		/* and go examine next fd/cptr */
	    }
	}
#endif

#ifdef REJECT_HOLD
      if (IsRejectHeld(cptr))
	{
	  if( timeofday > (cptr->firsttime + REJECT_HOLD_TIME) )
	    {
	      dying_clients[die_index] = cptr;
	      dying_clients_reason[die_index++] = "reject held client";
	      dying_clients[die_index] = (aClient *)NULL;
	      continue;		/* and go examine next fd/cptr */
	    }
	}
#endif

#if defined(R_LINES) && defined(R_LINES_OFTEN)
      /*
       * this is used for KILL lines with time restrictions
       * on them - send a message to the user being killed
       * first.
       * *** Moved up above  -taner ***
       *
       * Moved here, no more rflag -Dianora 
       */
      if (IsPerson(cptr) && find_restrict(cptr))
	{
	  sendto_ops("Restricting %s, closing link.",
		     get_client_name(cptr,FALSE));

	  dying_clients[die_index] = cptr;
	  dying_clients_reason[die_index++] = "you have been R-lined";
	  dying_clients[die_index] = (aClient *)NULL;
	  continue;			/* and go examine next fd/cptr */
	}
#endif

      if (!IsRegistered(cptr))
	ping = CONNECTTIMEOUT;
      else
	ping = get_client_ping(cptr);

      /*
       * Ok, so goto's are ugly and can be avoided here but this code
       * is already indented enough so I think its justified. -avalon
       */
       /*  if (!rflag &&
	       (ping >= currenttime - cptr->lasttime))
	      goto ping_timeout; */

      /*
       * *sigh* I think not -Dianora
       */

      if (ping < (currenttime - cptr->lasttime))
	{

	  /*
	   * If the server hasnt talked to us in 2*ping seconds
	   * and it has a ping time, then close its connection.
	   * If the client is a user and a KILL line was found
	   * to be active, close this connection too.
	   */
	  if (((currenttime - cptr->lasttime) >= (2 * ping) &&
	       (cptr->flags & FLAGS_PINGSENT)) ||
	      ((!IsRegistered(cptr) && (currenttime - cptr->since) >= ping)))
	    {
	      if (!IsRegistered(cptr) &&
		  (DoingDNS(cptr) || DoingAuth(cptr)))
		{
		  if (cptr->authfd >= 0)
		    {
		      (void)close(cptr->authfd);
		      cptr->authfd = -1;
		      cptr->count = 0;
		      *cptr->buffer = '\0';
		    }
#ifdef SHOW_HEADERS
		  if (DoingDNS(cptr))
		    send(cptr->fd, REPORT_FAIL_DNS, R_fail_dns, 0);
		  else
		    send(cptr->fd, REPORT_FAIL_ID, R_fail_id, 0);
#endif
		  Debug((DEBUG_NOTICE,"DNS/AUTH timeout %s",
			 get_client_name(cptr,TRUE)));
		  del_queries((char *)cptr);
		  ClearAuth(cptr);
		  ClearDNS(cptr);
		  SetAccess(cptr);
		  cptr->since = currenttime;
		  continue;
		}
	      if (IsServer(cptr) || IsConnecting(cptr) ||
		  IsHandshake(cptr))
		{
		  sendto_ops("No response from %s, closing link",
			     get_client_name(cptr, FALSE));
		}
	      /*
	       * this is used for KILL lines with time restrictions
	       * on them - send a messgae to the user being killed
	       * first.
	       * *** Moved up above  -taner ***
	       */
	      cptr->flags2 |= FLAGS2_PING_TIMEOUT;
	      dying_clients[die_index++] = cptr;
	      /* the reason is taken care of at exit time */
      /*      dying_clients_reason[die_index++] = "Ping timeout"; */
	      dying_clients[die_index] = (aClient *)NULL;
	      
	      /*
	       * need to start loop over because the close can
	       * affect the ordering of the local[] array.- avalon
	       *
	       ** Not if you do it right - Dianora
	       */

	      continue;
	    }
	  else if ((cptr->flags & FLAGS_PINGSENT) == 0)
	    {
	      /*
	       * if we havent PINGed the connection and we havent
	       * heard from it in a while, PING it to make sure
	       * it is still alive.
	       */
	      cptr->flags |= FLAGS_PINGSENT;
	      /* not nice but does the job */
	      cptr->lasttime = currenttime - ping;
	      sendto_one(cptr, "PING :%s", me.name);
	    }
	}
      /* ping_timeout: */
      timeout = cptr->lasttime + ping;
      while (timeout <= currenttime)
	timeout += ping;
      if (timeout < oldest || !oldest)
	oldest = timeout;

      /*
       * Check UNKNOWN connections - if they have been in this state
       * for > 100s, close them.
       */

      if (IsUnknown(cptr))
	{
	  if (cptr->firsttime ? ((timeofday - cptr->firsttime) > 100) : 0)
	    {
	      dying_clients[die_index] = cptr;
	      dying_clients_reason[die_index++] = "Connection Timed Out";
	      dying_clients[die_index] = (aClient *)NULL;
	      continue;
	    }
	}
    }

  /* Now exit clients marked for exit above.
   * it doesn't matter if local[] gets re-arranged now
   *
   * -Dianora
   */

  for(die_index = 0; (cptr = dying_clients[die_index]); die_index++)
    {
      if(cptr->flags2 & FLAGS2_PING_TIMEOUT)
	{
	  (void)ircsprintf(ping_time_out_buffer,
			    "Ping timeout: %d seconds",
			    currenttime - cptr->lasttime);
	  (void)exit_client(cptr, cptr, &me, ping_time_out_buffer );
	}
      else
	(void)exit_client(cptr, cptr, &me, dying_clients_reason[die_index]);
    }

  rehashed = 0;
  dline_in_progress = 0;

  if (!oldest || oldest < currenttime)
    oldest = currenttime + PINGFREQUENCY;
  Debug((DEBUG_NOTICE,"Next check_ping() call at: %s, %d %d %d",
	 myctime(oldest), ping, oldest, currenttime));
  
  return (oldest);
}
Exemplo n.º 15
0
static
void do_trace(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
    int i;
    struct Client *acptr;
    struct Client *acptr2;
    const struct ConnectionClass* cl;
    char* tname;
    int doall;
    int *link_s;
    int *link_u;
    int cnt = 0;
    int wilds;
    int dow;

    if (parc < 2 || BadPtr(parv[1]))
    {
        /* just "TRACE" without parameters. Must be from local client */
        parc = 1;
        acptr = &me;
        tname = cli_name(&me);
        i = HUNTED_ISME;
    }
    else if (parc < 3 || BadPtr(parv[2]))
    {
        /* No target specified. Make one before propagating. */
        parc = 2;
        tname = parv[1];
        if ((acptr = find_match_server(parv[1])) ||
                ((acptr = FindClient(parv[1])) && !MyUser(acptr)))
        {
            if (IsUser(acptr))
                parv[2] = cli_name(cli_user(acptr)->server);
            else
                parv[2] = cli_name(acptr);
            parc = 3;
            parv[3] = 0;
            if ((i = hunt_server_cmd(sptr, CMD_TRACE, cptr, IsServer(acptr),
                                     "%s :%C", 2, parc, parv)) == HUNTED_NOSUCH)
                return;
        }
        else
            i = HUNTED_ISME;
    } else {
        /* Got "TRACE <tname> :<target>" */
        parc = 3;
        if (MyUser(sptr) || Protocol(cptr) < 10)
            acptr = find_match_server(parv[2]);
        else
            acptr = FindNServer(parv[2]);
        if ((i = hunt_server_cmd(sptr, CMD_TRACE, cptr, 0, "%s :%C", 2, parc,
                                 parv)) == HUNTED_NOSUCH)
            return;
        tname = parv[1];
    }

    if (i == HUNTED_PASS) {
        if (!acptr)
            acptr = next_client(GlobalClientList, tname);
        else
            acptr = cli_from(acptr);
        send_reply(sptr, RPL_TRACELINK,
                   version, debugmode, tname,
                   acptr ? cli_name(cli_from(acptr)) : "<No_match>");
        return;
    }

    doall = (parv[1] && (parc > 1)) ? !match(tname, cli_name(&me)) : 1;
    wilds = !parv[1] || strchr(tname, '*') || strchr(tname, '?');
    dow = wilds || doall;

    /* Don't give (long) remote listings to lusers */
    if (dow && !MyConnect(sptr) && !IsAnOper(sptr)) {
        send_reply(sptr, RPL_TRACEEND);
        return;
    }

    link_s = MyCalloc(2 * maxconnections, sizeof(link_s[0]));
    link_u = link_s + maxconnections;

    if (doall) {
        for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) {
            if (IsUser(acptr))
                link_u[cli_fd(cli_from(acptr))]++;
            else if (IsServer(acptr))
                link_s[cli_fd(cli_from(acptr))]++;
        }
    }

    /* report all direct connections */

    for (i = 0; i <= HighestFd; i++) {
        const char *conClass;

        if (!(acptr = LocalClientArray[i])) /* Local Connection? */
            continue;
        if (IsInvisible(acptr) && dow && !(MyConnect(sptr) && IsOper(sptr)) &&
                !IsAnOper(acptr) && (acptr != sptr))
            continue;
        if (!doall && wilds && match(tname, cli_name(acptr)))
            continue;
        if (!dow && 0 != ircd_strcmp(tname, cli_name(acptr)))
            continue;

        conClass = get_client_class(acptr);

        switch (cli_status(acptr)) {
        case STAT_CONNECTING:
            send_reply(sptr, RPL_TRACECONNECTING, conClass, cli_name(acptr));
            cnt++;
            break;
        case STAT_HANDSHAKE:
            send_reply(sptr, RPL_TRACEHANDSHAKE, conClass, cli_name(acptr));
            cnt++;
            break;
        case STAT_ME:
            break;
        case STAT_UNKNOWN:
        case STAT_UNKNOWN_USER:
            send_reply(sptr, RPL_TRACEUNKNOWN, conClass,
                       get_client_name(acptr, HIDE_IP));
            cnt++;
            break;
        case STAT_UNKNOWN_SERVER:
            send_reply(sptr, RPL_TRACEUNKNOWN, conClass, "Unknown Server");
            cnt++;
            break;
        case STAT_USER:
            /* Only opers see users if there is a wildcard
               but anyone can see all the opers. */
            if ((IsAnOper(sptr) && (MyUser(sptr) ||
                                    !(dow && IsInvisible(acptr)))) || !dow || IsAnOper(acptr)) {
                if (IsAnOper(acptr))
                    send_reply(sptr, RPL_TRACEOPERATOR, conClass,
                               get_client_name(acptr, SHOW_IP),
                               CurrentTime - cli_lasttime(acptr));
                else
                    send_reply(sptr, RPL_TRACEUSER, conClass,
                               get_client_name(acptr, SHOW_IP),
                               CurrentTime - cli_lasttime(acptr));
                cnt++;
            }
            break;
        /*
         * Connection is a server
         *
         * Serv <class> <nS> <nC> <name> <ConnBy> <last> <age>
         *
         * class        Class the server is in
         * nS           Number of servers reached via this link
         * nC           Number of clients reached via this link
         * name         Name of the server linked
         * ConnBy       Who established this link
         * last         Seconds since we got something from this link
         * age          Seconds this link has been alive
         *
         * Additional comments etc......        -Cym-<*****@*****.**>
         */

        case STAT_SERVER:
            if (cli_serv(acptr)->user) {
                if (!cli_serv(acptr)->by[0]
                        || !(acptr2 = findNUser(cli_serv(acptr)->by))
                        || (cli_user(acptr2) != cli_serv(acptr)->user))
                    acptr2 = NULL;
                send_reply(sptr, RPL_TRACESERVER, conClass, link_s[i],
                           link_u[i], cli_name(acptr),
                           acptr2 ? cli_name(acptr2) : "*",
                           cli_serv(acptr)->user->username,
                           cli_serv(acptr)->user->host,
                           CurrentTime - cli_lasttime(acptr),
                           CurrentTime - cli_serv(acptr)->timestamp);
            } else
                send_reply(sptr, RPL_TRACESERVER, conClass, link_s[i],
                           link_u[i], cli_name(acptr),
                           (*(cli_serv(acptr))->by) ?  cli_serv(acptr)->by : "*", "*",
                           cli_name(&me), CurrentTime - cli_lasttime(acptr),
                           CurrentTime - cli_serv(acptr)->timestamp);
            cnt++;
            break;
        default:                  /* We actually shouldn't come here, -msa */
            send_reply(sptr, RPL_TRACENEWTYPE, get_client_name(acptr, HIDE_IP));
            cnt++;
            break;
        }
    }
    /*
     * Add these lines to summarize the above which can get rather long
     * and messy when done remotely - Avalon
     */
    if (IsAnOper(sptr) && doall) {
        for (cl = get_class_list(); cl; cl = cl->next) {
            if (Links(cl) > 1)
                send_reply(sptr, RPL_TRACECLASS, ConClass(cl), Links(cl) - 1);
        }
    }
    send_reply(sptr, RPL_TRACEEND);
    MyFree(link_s);
}
Exemplo n.º 16
0
/*
 * start_auth
 *
 * Flag the client to show that an attempt to contact the ident server on
 * the client's host.  The connect and subsequently the socket are all put
 * into 'non-blocking' mode.  Should the connect or any later phase of the
 * identifing process fail, it is aborted and the user is given a username
 * of "unknown".
 */
void	start_auth(aClient *cptr)
{
#ifndef	NO_IDENT
	struct	SOCKADDR_IN	us, them;

	SOCK_LEN_TYPE ulen, tlen;

# if defined(USE_IAUTH)
	if ((iauth_options & XOPT_REQUIRED) && adfd < 0)
		return;
# endif
	Debug((DEBUG_NOTICE,"start_auth(%x) fd %d status %d",
		cptr, cptr->fd, cptr->status));
	if ((cptr->authfd = socket(AFINET, SOCK_STREAM, 0)) == -1)
	    {
# ifdef	USE_SYSLOG
		syslog(LOG_ERR, "Unable to create auth socket for %s:%m",
			get_client_name(cptr,TRUE));
# endif
		Debug((DEBUG_ERROR, "Unable to create auth socket for %s:%s",
			get_client_name(cptr, TRUE),
			strerror(get_sockerr(cptr))));
		ircstp->is_abad++;
		return;
	    }
	if (cptr->authfd >= (MAXCONNECTIONS - 2))
	    {
		sendto_flag(SCH_ERROR, "Can't allocate fd for auth on %s",
			   get_client_name(cptr, TRUE));
		(void)close(cptr->authfd);
		return;
	    }

	set_non_blocking(cptr->authfd, cptr);

	/* get remote host peer - so that we get right interface -- jrg */
	tlen = ulen = sizeof(us);
	if (getpeername(cptr->fd, (struct sockaddr *)&them, &tlen) < 0)
	    {
		/* we probably don't need this error message -kalt */
		report_error("getpeername for auth request %s:%s", cptr);
		close(cptr->authfd);
		cptr->authfd = -1;
		return;
	    }
	them.SIN_FAMILY = AFINET;

	/* We must bind the local end to the interface that they connected
	   to: The local system might have more than one network address,
	   and RFC931 check only sends port numbers: server takes IP addresses
	   from query socket -- jrg */
	(void)getsockname(cptr->fd, (struct sockaddr *)&us, &ulen);
	us.SIN_FAMILY = AFINET;
# if defined(USE_IAUTH)
	if (adfd >= 0)
	    {
		char abuf[BUFSIZ];
#  ifdef INET6
		sprintf(abuf, "%d C %s %u ", cptr->fd,
			inetntop(AF_INET6, (char *)&them.sin6_addr, ipv6string,
				 sizeof(ipv6string)), ntohs(them.SIN_PORT));
		sprintf(abuf+strlen(abuf), "%s %u",
			inetntop(AF_INET6, (char *)&us.sin6_addr, ipv6string,
				 sizeof(ipv6string)), ntohs(us.SIN_PORT));
#  else
		sprintf(abuf, "%d C %s %u ", cptr->fd,
			inetntoa((char *)&them.sin_addr),ntohs(them.SIN_PORT));
		sprintf(abuf+strlen(abuf), "%s %u",
			inetntoa((char *)&us.sin_addr), ntohs(us.SIN_PORT));
#  endif
		if (sendto_iauth(abuf) == 0)
		    {
			close(cptr->authfd);
			cptr->authfd = -1;
			cptr->flags |= FLAGS_XAUTH;
			return;
		    }
	    }
# endif
# ifdef INET6
	Debug((DEBUG_NOTICE,"auth(%x) from %s %x %x",
	       cptr, inet_ntop(AF_INET6, (char *)&us.sin6_addr, ipv6string,
			       sizeof(ipv6string)), us.sin6_addr.s6_addr[14],
	       us.sin6_addr.s6_addr[15]));
# else
	Debug((DEBUG_NOTICE,"auth(%x) from %s",
	       cptr, inetntoa((char *)&us.sin_addr)));
# endif
	them.SIN_PORT = htons(113);
	us.SIN_PORT = htons(0);  /* bind assigns us a port */
	if (bind(cptr->authfd, (struct SOCKADDR *)&us, ulen) >= 0)
	    {
		(void)getsockname(cptr->fd, (struct SOCKADDR *)&us, &ulen);
# ifdef INET6
		Debug((DEBUG_NOTICE,"auth(%x) to %s",
			cptr, inet_ntop(AF_INET6, (char *)&them.sin6_addr,
					ipv6string, sizeof(ipv6string))));
# else
		Debug((DEBUG_NOTICE,"auth(%x) to %s",
			cptr, inetntoa((char *)&them.sin_addr)));
# endif
		(void)alarm((unsigned)4);
		if (connect(cptr->authfd, (struct SOCKADDR *)&them,
			    tlen) == -1 && errno != EINPROGRESS)
		    {
# ifdef INET6
			Debug((DEBUG_ERROR,
				"auth(%x) connect failed to %s - %d", cptr,
				inet_ntop(AF_INET6, (char *)&them.sin6_addr,
					  ipv6string, sizeof(ipv6string)), errno));
# else
			Debug((DEBUG_ERROR,
				"auth(%x) connect failed to %s - %d", cptr,
				inetntoa((char *)&them.sin_addr), errno));
# endif
			ircstp->is_abad++;
			/*
			 * No error report from this...
			 */
			(void)alarm((unsigned)0);
			(void)close(cptr->authfd);
			cptr->authfd = -1;
			return;
		    }
		(void)alarm((unsigned)0);
	    }
	else
	    {
		report_error("binding stream socket for auth request %s:%s",
			     cptr);
# ifdef INET6
		Debug((DEBUG_ERROR,"auth(%x) bind failed on %s port %d - %d",
		      cptr, inet_ntop(AF_INET6, (char *)&us.sin6_addr,
		      ipv6string, sizeof(ipv6string)),
		      ntohs(us.SIN_PORT), errno));
# else
		Debug((DEBUG_ERROR,"auth(%x) bind failed on %s port %d - %d",
		      cptr, inetntoa((char *)&us.sin_addr),
		      ntohs(us.SIN_PORT), errno));
# endif
	    }

	cptr->flags |= (FLAGS_WRAUTH|FLAGS_AUTH);
	if (cptr->authfd > highest_fd)
		highest_fd = cptr->authfd;
#endif
	return;
}
Exemplo n.º 17
0
/** Parse a line of data from a user.
 * NOTE: parse_*() should not be called recursively by any other
 * functions!
 * @param[in] cptr Client that sent the data.
 * @param[in] buffer Start of input line.
 * @param[in] bufend End of input line.
 * @return 0 on success, -1 on parse error, or CPTR_KILLED if message
 * handler returns it.
 */
int
parse_client(struct Client *cptr, char *buffer, char *bufend)
{
  struct Client*  from = cptr;
  char*           ch;
  char*           s;
  int             i;
  int             paramcount;
  int             isshun = 0;
  int             lagmin = -1;
  int             lagfactor = -1;
  struct Message* mptr;
  MessageHandler  handler = 0;

  Debug((DEBUG_DEBUG, "Client Parsing: %s", buffer));

  if (IsDead(cptr))
    return 0;

  para[0] = cli_name(from);
  for (ch = buffer; *ch == ' '; ch++);  /* Eat leading spaces */
  if (*ch == ':')               /* Is any client doing this ? */
  {
    for (++ch; *ch && *ch != ' '; ++ch)
      ; /* Ignore sender prefix from client */
    while (*ch == ' ')
      ch++;                     /* Advance to command */
  }
  if (*ch == '\0')
  {
    ServerStats->is_empt++;
    Debug((DEBUG_NOTICE, "Empty message from host %s:%s",
        cli_name(cptr), cli_name(from)));
    return (-1);
  }

  if ((s = strchr(ch, ' ')))
    *s++ = '\0';

  expire_shuns();
  if (IsRegistered(cptr)) {
    if (cli_user(cptr)->username && cli_user(cptr)->host) {
      if (shun_lookup(cptr, 0))
        isshun = 1;
    }
  }

  if ((mptr = msg_tree_parse(ch, &msg_tree)) == NULL)
  {
    /*
     * Note: Give error message *only* to recognized
     * persons. It's a nightmare situation to have
     * two programs sending "Unknown command"'s or
     * equivalent to each other at full blast....
     * If it has got to person state, it at least
     * seems to be well behaving. Perhaps this message
     * should never be generated, though...  --msa
     * Hm, when is the buffer empty -- if a command
     * code has been found ?? -Armin
     */
    if (buffer[0] != '\0' && !isshun)
    {
      if (IsUser(from))
	send_reply(from, ERR_UNKNOWNCOMMAND, ch);
      Debug((DEBUG_ERROR, "Unknown (%s) from %s",
            ch, get_client_name(cptr, HIDE_IP)));
    }
    ServerStats->is_unco++;
    return (-1);
  }

  if (isshun && !(mptr->flags & MFLG_NOSHUN))
    return 0;

  paramcount = mptr->parameters;
  i = bufend - ((s) ? s : ch);
  mptr->bytes += i;
  lagmin = get_lag_min(cptr);
  lagfactor = get_lag_factor(cptr);
  if (lagmin < 0)
    lagmin = 2;
  if (lagfactor < 0)
    lagfactor = 120;
  if (((mptr->flags & MFLG_SLOW) || !IsAnOper(cptr)) && lagfactor > 0)
    cli_since(cptr) += (lagmin + i / lagfactor);
  /*
   * Allow only 1 msg per 2 seconds
   * (on average) to prevent dumping.
   * to keep the response rate up,
   * bursts of up to 5 msgs are allowed
   * -SRB
   */

  /*
   * Must the following loop really be so devious? On
   * surface it splits the message to parameters from
   * blank spaces. But, if paramcount has been reached,
   * the rest of the message goes into this last parameter
   * (about same effect as ":" has...) --msa
   */

  /* Note initially true: s==NULL || *(s-1) == '\0' !! */

  if (mptr->flags & MFLG_EXTRA) {
    /* This is a horrid kludge to avoid changing the command handler
     * argument list. */
    para[1] = (char*)mptr->extra;
    i = 1;
  } else {
    i = 0;
  }
  if (s)
  {
    if (paramcount > MAXPARA)
      paramcount = MAXPARA;
    for (;;)
    {
      /*
       * Never "FRANCE " again!! ;-) Clean
       * out *all* blanks.. --msa
       */
      while (*s == ' ')
        *s++ = '\0';

      if (*s == '\0')
        break;
      if (*s == ':')
      {
        /*
         * The rest is single parameter--can
         * include blanks also.
         */
        para[++i] = s + 1;
        break;
      }
      para[++i] = s;
      if (i >= paramcount)
        break;
      for (; *s != ' ' && *s; s++);
    }
  }
  para[++i] = NULL;
  ++mptr->count;

  handler = mptr->handlers[cli_handler(cptr)];
  assert(0 != handler);

  if (!feature_bool(FEAT_IDLE_FROM_MSG) && IsUser(cptr) &&
      handler != m_ping && handler != m_ignore)
    cli_user(from)->last = CurrentTime;

  return (*handler) (cptr, from, i, para);
}
Exemplo n.º 18
0
/*
** exit_client
**	This is old "m_bye". Name  changed, because this is not a
**	protocol function, but a general server utility function.
**
**	This function exits a client of *any* type (user, server, etc)
**	from this server. Also, this generates all necessary prototol
**	messages that this exit may cause.
**
**   1) If the client is a local client, then this implicitly
**	exits all other clients depending on this connection (e.g.
**	remote clients having 'from'-field that points to this.
**
**   2) If the client is a remote client, then only this is exited.
**
** For convenience, this function returns a suitable value for
** m_funtion return value:
**
**	FLUSH_BUFFER	if (cptr == sptr)
**	0		if (cptr != sptr)
**
**	Parameters:
**
**	aClient *cptr
** 		The local client originating the exit or NULL, if this
** 		exit is generated by this server for internal reasons.
** 		This will not get any of the generated messages.
**	aClient *sptr
**		Client exiting
**	aClient *from
**		Client firing off this Exit, never NULL!
**	char	*comment
**		Reason for the exit
*/
int	exit_client(aClient *cptr, aClient *sptr, aClient *from,
		const char *comment)
{
	char	comment1[HOSTLEN + HOSTLEN + 2];

	if (MyConnect(sptr))
	{
		if (sptr->flags & FLAGS_KILLED)
		{
			sendto_flag(SCH_NOTICE, "Killed: %s.",
				    get_client_name(sptr, TRUE));
			sptr->exitc = EXITC_KILL;
		}

		sptr->flags |= FLAGS_CLOSING;
#if (defined(FNAME_USERLOG) || defined(FNAME_CONNLOG) \
     || defined(USE_SERVICES)) \
    || (defined(USE_SYSLOG) && (defined(SYSLOG_USERS) || defined(SYSLOG_CONN)))
		if (IsPerson(sptr))
		{
# if defined(FNAME_USERLOG) || defined(USE_SERVICES) || \
	(defined(USE_SYSLOG) && defined(SYSLOG_USERS))
			sendto_flog(sptr, EXITC_REG, sptr->user->username,
				    sptr->user->host);
# endif
# if defined(CLIENTS_CHANNEL) && (CLIENTS_CHANNEL_LEVEL & CCL_QUIT)
			sendto_flag(SCH_CLIENT, "%s %s %s %s QUIT %c"
#  if (CLIENTS_CHANNEL_LEVEL & CCL_QUITINFO)
				" :%s"
#  endif
				, sptr->user->uid, sptr->name,
				sptr->user->username, sptr->user->host,
				sptr->exitc
#  if (CLIENTS_CHANNEL_LEVEL & CCL_QUITINFO)
				, comment
#  endif
				);
# endif
		}
		else if (!IsService(sptr))
		{
# if defined(FNAME_CONNLOG) || defined(USE_SERVICES) || \
	(defined(USE_SYSLOG) && defined(SYSLOG_CONN))
			if (sptr->exitc == '\0' || sptr->exitc == EXITC_REG)
			{
				sptr->exitc = EXITC_UNDEF;
			}
			sendto_flog(sptr, sptr->exitc,
				    sptr->user && sptr->user->username ?
				    sptr->user->username : "",
#ifdef UNIXPORT
				    (IsUnixSocket(sptr)) ? me.sockhost :
#endif
				    ((sptr->hostp) ? sptr->hostp->h_name :
				     sptr->sockhost));
# endif
		}
#endif
		if (MyConnect(sptr))
		{
			if (IsPerson(sptr))
			{
				istat.is_myclnt--;
			}
			else if (IsServer(sptr))
			{
				istat.is_myserv--;
			}
			else if (IsService(sptr))
			{
				istat.is_myservice--;
			}
			else
			{
				istat.is_unknown--;
			}

			if (istat.is_myclnt % CLCHNO == 0 &&
				istat.is_myclnt != istat.is_l_myclnt)
			{
				sendto_flag(SCH_NOTICE,
					"Local %screase from %d to %d clients "
					"in %d seconds",
					istat.is_myclnt>istat.is_l_myclnt?"in":"de",
					istat.is_l_myclnt, istat.is_myclnt,
					timeofday - istat.is_l_myclnt_t);
				istat.is_l_myclnt_t = timeofday;
				istat.is_l_myclnt = istat.is_myclnt;
			}
			/* Send SQUIT message to 2.11 servers to tell them
			 * the squit reason for rebroadcast on the other side
			 * - jv
			 */
			if (IsServer(sptr))
			{
				sendto_one(sptr, ":%s SQUIT %s :%s",
					me.serv->sid, sptr->serv->sid,
					comment);
			}

			if (cptr != NULL && sptr != cptr)
			{
				sendto_one(sptr, "ERROR :Closing Link: "
					"%s %s (%s)",
					get_client_name(sptr,FALSE),
					cptr->name, comment);
			}
			else
			{
				sendto_one(sptr, "ERROR :Closing Link: %s (%s)",
					get_client_name(sptr,FALSE), comment);
			}

			if (sptr->auth != sptr->username)
			{
				istat.is_authmem -= strlen(sptr->auth) + 1;
				istat.is_auth -= 1;
				MyFree(sptr->auth);
				sptr->auth = sptr->username;
			}
		}
		/*
		** Currently only server connections can have
		** depending remote clients here, but it does no
		** harm to check for all local clients. In
		** future some other clients than servers might
		** have remotes too...
		** now, I think it harms big client servers... - krys
		**
		** Close the Client connection first and mark it
		** so that no messages are attempted to send to it.
		** (The following *must* make MyConnect(sptr) == FALSE!).
		** It also makes sptr->from == NULL, thus it's unnecessary
		** to test whether "sptr != acptr" in the following loops.
		*/
		close_connection(sptr);

	} /* if (MyConnect(sptr) */

 	if (IsServer(sptr))
 	{
		/* Remove all dependent servers and clients. */
		if (!IsMasked(sptr))
		{
			sprintf(comment1, "%s %s", sptr->serv->up->name,
				sptr->name);
		}
		else
		{
			/* It was a masked server, the squit reason should
			** give the right quit reason for clients. */
			strncpyzt(comment1, comment, sizeof(comment1));
		}
		/* cptr != sptr means non-local server */
		if (cptr != sptr && 
			nextconnect == 0 && find_conf_name(sptr->name,
			(CONF_CONNECT_SERVER|CONF_ZCONNECT_SERVER)))
		{
			/* try AC */
			nextconnect = timeofday + HANGONRETRYDELAY;
		}
		exit_server(sptr, sptr, from, comment, comment1);
		check_split();
		if ((cptr == sptr))
		{
			/* It serves no purpose. --B.
			sendto_flag(SCH_SERVER, "Sending SQUIT %s (%s)",
				cptr->name, comment);
			*/
			return FLUSH_BUFFER;
		}
		return 0;
 	}
	
	/*
	** Try to guess from comment if the client is exiting
	** normally (KILL or issued QUIT), or if it is splitting
	** It requires comment for splitting users to be
	** "server.some.where splitting.some.where"
	*/
	comment1[0] = '\0';
	if ((sptr->flags & FLAGS_KILLED) == 0)
	{
		if (comment[0] == '"')
		{
			/* definitely user quit, see m_quit */
			sptr->flags |= FLAGS_QUIT;
		}
		else
		{
		        const char *c = comment;
			int i = 0;
			while (*c && *c != ' ')
				if (*c++ == '.')
					i++;
			if (*c++ && i)
			{
			        i = 0;
				while (*c && *c != ' ')
					if (*c++ == '.')
						i++;
				if (!i || *c)
					sptr->flags |= FLAGS_QUIT;
			}
			else
			{
				sptr->flags |= FLAGS_QUIT;
			}
		}

		if (sptr == cptr && !(sptr->flags & FLAGS_QUIT))
		{
			/*
			** This will avoid nick delay to be abused by
			** letting local users put a comment looking
			** like a server split.
			*/
			strncpyzt(comment1, comment, HOSTLEN + HOSTLEN);
			strcat(comment1, " ");
			sptr->flags |= FLAGS_QUIT;
		}
	}
	
	exit_one_client(cptr, sptr, from, (*comment1) ? comment1 : comment);
	/* XXX: we probably should not call it every client exit */
	/* checking every server quit should suffice --B. */
	/* check_split(); */
	return cptr == sptr ? FLUSH_BUFFER : 0;
    }
Exemplo n.º 19
0
int m_chall(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
  static char blank[] = "";
  char* salt = parc > 4 ? parv[4] : blank;
  char* chall = parc > 3 ? parv[3] : blank;
  char* remote_host = parc > 2 ? parv[2] : blank;
  char* host = parc > 1 ? parv[1] : blank;
  struct ConfItem *n_conf, *c_conf;
  struct Client* acptr;

  if (IsPerson(sptr))
    {
      if (IsServer(cptr))
        {
          sendto_ops_flag(UMODE_SERVNOTICE,"CHALL command from remote user %s -- %s is a hacked server",
				 get_client_name(sptr,HIDE_IP),
				 get_client_name(cptr,HIDE_IP));
        }
      else
        {
          sendto_one(sptr, form_str(ERR_UNKNOWNCOMMAND),
                     me.name, parv[0], "CHALL");
        }
      return 0;
    }

  /* If we know this, we shouldn't be getting a chall */
  if (IsPerson(cptr) || IsServer(cptr)) 
    return 0;

  /* What are they trying to auth against, is it me? */
  if (irccmp(remote_host, me.name) != 0)
    {
      sendto_one(cptr, "ERROR :I am %s, not %s", me.name, remote_host);
      sendto_ops_flag(UMODE_SERVCONNECT, "Server claiming to be %s challenged thinking I was %s, rejected", host, remote_host);
      return exit_client(cptr, cptr, &me, "Sorry, wrong number");
    }

  if ((acptr = find_server(host)))
    {
      sendto_one(cptr,"ERROR :Server %s already exists", host);
      if (!(acptr->from->caps & CAP_SERVICES)) /* If it's connected to services, it's actually a server jupe. Silently ignore. */
	sendto_ops_flag(UMODE_EXTERNAL, "Challenge for %s rejected, server already exists",
			host);
      return exit_client(cptr, cptr, &me, "Server already exists");
    }

  sendto_ops_flag(UMODE_SERVCONNECT, "CHALL received, trying to use N:line for %s", host);

  if (parc < 5)
    {
      sendto_one(cptr, "ERROR: Invalid challenge");
      sendto_ops_flag(UMODE_SERVCONNECT, "Invalid CHALL from remote host for %s", host);
      return 0;
    }

  /* See if we got c and n lines. */
  if (!(n_conf = find_conf_by_name(host, CONF_NOCONNECT_SERVER))) {
    sendto_ops_flag(UMODE_SERVCONNECT, "Challenge rejected. No N line for server %s", host);
    logprintf(L_NOTICE, "Challenge rejected. No N line for server %s", host);
    sendto_one(cptr, "ERROR :Access denied. No N line"); 
    return exit_client(cptr, cptr, cptr, "Access denied. No N line");    
  } 

  if (!(c_conf = find_conf_by_name(host, CONF_CONNECT_SERVER))) {
    sendto_ops_flag(UMODE_SERVCONNECT, "Challenge rejected. No C line for server %s", host);
    logprintf(L_NOTICE, "Challenge rejected. No C line for server %s", host);
    sendto_one(cptr, "ERROR :Access denied. No C line");
    return exit_client(cptr, cptr, cptr, "Access denied. No C line");    
  }
  
  /* Check if the ip matches the c/n IPs */
#ifdef IPV6
  if((memcmp((char*)cptr->ip.S_ADDR, (char*)c_conf->ipnum.S_ADDR, sizeof(struct IN_ADDR) != 0)) ||
        (memcmp((char*)cptr->ip.S_ADDR, (char*)n_conf->ipnum.S_ADDR,  sizeof(struct IN_ADDR)) != 0))
  {
#else
  if ( (cptr->ip.s_addr != c_conf->ipnum.s_addr) || (cptr->ip.s_addr != n_conf->ipnum.s_addr)) {
#endif
    sendto_ops_flag(UMODE_SERVCONNECT, "Challenge rejected. C/N line IP doesn't match connection");
    logprintf(L_NOTICE, "Challenge rejected. C/N line IP doesn't match connection");
    sendto_one(cptr, "ERROR :Access denied. C/N line don't match you"); 
    return exit_client(cptr, cptr, cptr, "Access denied. C/N line don't match");        
  }
  
  /* Ok, it got c/n lines and correct ip, lets challenge it back */
  if (!Challenged(cptr))
    cr_sendchallenge(cptr, n_conf);

  /* And send a response. */
  cr_sendresponse(cptr, c_conf, chall, salt);

  /* check for TS as in m_pass */
  if (parc > 5)
    {
      if (0 == irccmp(parv[5], "TS"))
        cptr->tsinfo = TS_DOESTS;
    }
  return 0;
}
Exemplo n.º 20
0
/*
** Exit one client, local or remote. Assuming all dependants have
** been already removed, and socket closed for local client.
*/
static	void	exit_one_client(aClient *cptr, aClient *sptr, aClient *from,
	const char *comment)
{
	Reg	aClient *acptr;
	Reg	int	i;
	Reg	Link	*lp;
	invLink		*ilp;

	/*
	**  For a server or user quitting, propagage the information to
	**  other servers (except to the one where is came from (cptr))
	*/
	if (IsMe(sptr))
	{
		sendto_flag(SCH_ERROR,
			    "ERROR: tried to exit me! : %s", comment);
		return;	/* ...must *never* exit self!! */
	}
	else if (IsServer(sptr))
	{
		/*
		** Old sendto_serv_but_one() call removed because we now
		** need to send different names to different servers
		** (domain name matching)
		*/
		if (!IsMasked(sptr))
		{
			istat.is_serv--;
		}
		if (!IsBursting(sptr))
		{
			istat.is_eobservers--;
		}
	 	for (i = fdas.highest; i >= 0; i--)
		{
			if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr) ||
			    acptr == cptr || IsMe(acptr))
			{
				continue;
			}
			if (!(sptr->flags & FLAGS_SQUIT))
			{
				/* Make sure we only send the last SQUIT
				** to a 2.11. */
				continue;
			}
			if ((acptr->flags & FLAGS_HIDDEN) &&
				!IsMasked(sptr))
			{
				/* We need a special SQUIT reason, so
				** the remote server can send the
				** right quit message. */
				sendto_one(acptr, ":%s SQUIT %s :%s %s",
					sptr->serv->up->serv->sid,
					sptr->serv->sid,
					sptr->serv->up->name,
					sptr->name);
			}
			else
			{
				sendto_one(acptr, ":%s SQUIT %s :%s",
					sptr->serv->up->serv->sid,
					sptr->serv->sid, comment);
			}
		}
#ifdef	USE_SERVICES
		check_services_butone(SERVICE_WANT_SQUIT, sptr->serv, sptr,
				      ":%s SQUIT %s :%s", from->name,
				      sptr->name, comment);
#endif
		del_from_sid_hash_table(sptr->serv);
		remove_server_from_tree(sptr);
		/* remove server from svrtop */
		unregister_server(sptr);
	}
	else if (!IsPerson(sptr) && !IsService(sptr))
	{
				    /* ...this test is *dubious*, would need
				    ** some thougth.. but for now it plugs a
				    ** nasty hole in the server... --msa
				    */
		; /* Nothing */
	}
	else if (sptr->name[0] && !IsService(sptr)) /* clean with QUIT... */
	{
		/*
		** If this exit is generated from "m_kill", then there
		** is no sense in sending the QUIT--KILL's have been
		** sent instead.
		*/
		if ((sptr->flags & FLAGS_KILLED) == 0)
		{
			if ((sptr->flags & FLAGS_SPLIT) == 0)
			{
				sendto_serv_butone(cptr, ":%s QUIT :%s",
						   sptr->user->uid, comment);
#ifdef	USE_SERVICES
				check_services_butone(SERVICE_WANT_QUIT|
						      SERVICE_WANT_RQUIT, 
						      (sptr->user) ?
						      sptr->user->servp
						      : NULL, cptr,
						      ":%s QUIT :%s",
						      sptr->name, comment);
#endif
			}
			else
			{
				if (sptr->flags & FLAGS_HIDDEN)
					/* joys of hostmasking */
					for (i = fdas.highest; i >= 0; i--)
					{
						if (!(acptr =local[fdas.fd[i]])
						    || acptr == cptr
						    || IsMe(acptr))
							continue;
						if (acptr->flags & FLAGS_HIDDEN)
							sendto_one(acptr,
								":%s QUIT :%s",
								sptr->user->uid,
								comment);
					}
#ifdef	USE_SERVICES
				check_services_butone(SERVICE_WANT_QUIT, 
					      (sptr->user) ? sptr->user->servp
						      : NULL, cptr,
						      ":%s QUIT :%s",
						      sptr->name, comment);
#endif
			}
		}
#ifdef USE_SERVICES
		else
		{
			/* Send QUIT to services which desire such as well.
			** Services with both _QUIT and _KILL will get both
			** for now --jv
			*/
			check_services_butone(SERVICE_WANT_QUIT, 
					     (sptr->user) ? sptr->user->servp
						      : NULL, cptr,
						      ":%s QUIT :%s",
						      sptr->name, comment);

		}
#endif
		/*
		** If a person is on a channel, send a QUIT notice
		** to every client (person) on the same channel (so
		** that the client can show the "**signoff" message).
		** (Note: The notice is to the local clients *only*)
		*/
		if (sptr->user)
		{
			if (IsInvisible(sptr))
			{
				istat.is_user[1]--;
				sptr->user->servp->usercnt[1]--;
			}
			else
			{
				istat.is_user[0]--;
				sptr->user->servp->usercnt[0]--;
			}
			if (IsAnOper(sptr))
			{
				sptr->user->servp->usercnt[2]--;
				istat.is_oper--;
			}
			sendto_common_channels(sptr, ":%s QUIT :%s",
						sptr->name, comment);

			if (!(acptr = cptr ? cptr : sptr->from))
				acptr = sptr;
			while ((lp = sptr->user->channel))
			{
				/*
				** Mark channels from where remote chop left,
				** this will eventually lock the channel.
				** close_connection() has already been called,
				** it makes MyConnect == False - krys
				*/
				if (sptr != cptr)
				{
					if (*lp->value.chptr->chname == '!')
					{
						if (!(sptr->flags &FLAGS_QUIT))
							lp->value.chptr->history = timeofday + LDELAYCHASETIMELIMIT;
					}
					else if (
#ifndef BETTER_CDELAY
						 !(sptr->flags & FLAGS_QUIT) &&
#endif
						 is_chan_op(sptr, lp->value.chptr))
					{
						lp->value.chptr->history = timeofday + DELAYCHASETIMELIMIT;
					}
				}
				if (IsAnonymous(lp->value.chptr) &&
				    !IsQuiet(lp->value.chptr))
				{
					sendto_channel_butserv(lp->value.chptr, sptr, ":%s PART %s :None", sptr->name, lp->value.chptr->chname);
				}
				remove_user_from_channel(sptr,lp->value.chptr);
			}

			/* Clean up invitefield */
			while ((ilp = sptr->user->invited))
			{
				del_invite(sptr, ilp->chptr);
				/* again, this is all that is needed */
			}

			/* remove from uid hash table */
			if (sptr->user)
			{
				del_from_uid_hash_table(sptr->user->uid, sptr);
			}

			/* Add user to history */
#ifndef BETTER_NDELAY
			add_history(sptr, (sptr->flags & FLAGS_QUIT) ?
				    &me : NULL);
#else
			add_history(sptr, (sptr == cptr) ? &me : NULL);
#endif
			off_history(sptr);
#ifdef USE_HOSTHASH
			del_from_hostname_hash_table(sptr->user->host,
						     sptr->user);
#endif
#ifdef USE_IPHASH
			del_from_ip_hash_table(sptr->user->sip, sptr->user);
#endif
		    }
	    }
	else if (sptr->name[0] && IsService(sptr))
	    {
		/*
		** If this exit is generated from "m_kill", then there
		** is no sense in sending the QUIT--KILL's have been
		** sent instead.
		*/
		if ((sptr->flags & FLAGS_KILLED) == 0)
		{
			/*
			** A service quitting is annoying, It has to be sent
			** to connected servers depending on 
			** sptr->service->dist
			*/
			for (i = fdas.highest; i >= 0; i--)
			    {
				if (!(acptr = local[fdas.fd[i]])
				    || !IsServer(acptr) || acptr == cptr
				    || IsMe(acptr))
				{
					continue;
				}
				if (match(sptr->service->dist, acptr->name) && 
					match(sptr->service->dist, acptr->serv->sid))
				{
					continue;
				}
				sendto_one(acptr, ":%s QUIT :%s", sptr->name,
					   comment);
			}
		}
#ifdef	USE_SERVICES
		check_services_butone(SERVICE_WANT_SERVICE, NULL, NULL,
				      ":%s QUIT :%s", sptr->name, comment);
#endif
		/* MyConnect(sptr) is always FALSE here */
		if (cptr == sptr)
		{
			sendto_flag(SCH_NOTICE, "Service %s disconnected",
				    get_client_name(sptr, TRUE));
		}
		sendto_flag(SCH_SERVICE, "Received QUIT %s from %s (%s)",
			    sptr->name, from->name, comment);
		istat.is_service--;
	    }

	/* Remove sptr from the client list */
	if (del_from_client_hash_table(sptr->name, sptr) != 1)
	{
		Debug((DEBUG_ERROR, "%#x !in tab %s[%s] %#x %#x %#x %d %d %#x",
			sptr, sptr->name,
			sptr->from ? sptr->from->sockhost : "??host",
			sptr->from, sptr->next, sptr->prev, sptr->fd,
			sptr->status, sptr->user));
	}
	remove_client_from_list(sptr);
	return;
}
Exemplo n.º 21
0
/*
 * ms_svinfo - SVINFO message handler
 *      parv[0] = sender prefix
 *      parv[1] = TS_CURRENT for the server
 *      parv[2] = TS_MIN for the server
 *      parv[3] = server is standalone or connected to non-TS only
 *      parv[4] = server's idea of UTC time
 */
static void
ms_svinfo(struct Client *client_p, struct Client *source_p,
	  int parc, char *parv[])
{
  time_t deltat;
  time_t theirtime;

  if (MyConnect(source_p) && IsUnknown(source_p))
  {
    exit_client(source_p, source_p, source_p, "Need SERVER before SVINFO");
    return;
  }

  if (!IsServer(source_p) || !MyConnect(source_p) || parc < 5)
    return;

  if (TS_CURRENT < atoi(parv[2]) || atoi(parv[1]) < TS_MIN)
    {
      /*
       * a server with the wrong TS version connected; since we're
       * TS_ONLY we can't fall back to the non-TS protocol so
       * we drop the link  -orabidoo
       */
      sendto_realops_flags(UMODE_ALL, L_ADMIN,
            "Link %s dropped, wrong TS protocol version (%s,%s)",
            get_client_name(source_p, SHOW_IP), parv[1], parv[2]);
      sendto_realops_flags(UMODE_ALL, L_OPER,
                 "Link %s dropped, wrong TS protocol version (%s,%s)",
                 get_client_name(source_p, MASK_IP), parv[1], parv[2]);
      exit_client(source_p, source_p, source_p, "Incompatible TS version");
      return;
    }

  /*
   * since we're here, might as well set CurrentTime while we're at it
   */
  set_time(); 
  theirtime = atol(parv[4]);
  deltat = abs(theirtime - CurrentTime);

  if (deltat > ConfigFileEntry.ts_max_delta)
    {
      sendto_realops_flags(UMODE_ALL, L_ADMIN,
          "Link %s dropped, excessive TS delta (my TS=%lu, their TS=%lu, delta=%d)",
          get_client_name(source_p, SHOW_IP),
          (unsigned long) CurrentTime,
          (unsigned long) theirtime,
          (int) deltat);
      sendto_realops_flags(UMODE_ALL, L_OPER,
          "Link %s dropped, excessive TS delta (my TS=%lu, their TS=%lu, delta=%d)",
           get_client_name(source_p, MASK_IP),
           (unsigned long) CurrentTime,
           (unsigned long) theirtime,
           (int) deltat);
      ilog(L_NOTICE,
          "Link %s dropped, excessive TS delta (my TS=%lu, their TS=%lu, delta=%d)",
          get_client_name(source_p, SHOW_IP),
          (unsigned long) CurrentTime,
          (unsigned long) theirtime,
          (int) deltat);
      exit_client(source_p, source_p, source_p, "Excessive TS delta");
      return;
    }

  if (deltat > ConfigFileEntry.ts_warn_delta)
    { 
      sendto_realops_flags(UMODE_ALL, L_ALL,
                "Link %s notable TS delta (my TS=%lu, their TS=%lu, delta=%d)",
                source_p->name,
                (unsigned long) CurrentTime,
                (unsigned long) theirtime,
                (int) deltat);
    }
}
Exemplo n.º 22
0
static      time_t
check_pings(time_t currenttime)
{
aClient 	*cptr;
aConfItem 	*aconf = (aConfItem *) NULL;
int     	 killflag, zkillflag, ping = 0, i;
time_t      	 oldest = 0; /* timeout removed, see EXPLANATION below */
char       	*reason, *ktype, fbuf[512];
char 		*errtxt = "No response from %s, closing link";


   for (i = 0; i <= highest_fd; i++) 
   {
      if (!(cptr = local[i]) || IsMe(cptr) || IsLog(cptr))
	 continue;

       /* Note: No need to notify opers here. It's 
	* already done when "FLAGS_DEADSOCKET" is set.
        */

      if (cptr->flags & FLAGS_DEADSOCKET) 
      {
	 (void) exit_client(cptr, cptr, &me, (cptr->flags & FLAGS_SENDQEX) ?
			    "SendQ exceeded" : "Dead socket");
	 i--;
	 continue;
      }

      killflag = NO;
      zkillflag = NO;

      if (rehashed) 
      {
	 if (zline_in_progress) 
	 {
	    if (IsPerson(cptr)) 
	    {
	       if ((aconf = find_zkill(cptr)))	
		  zkillflag = YES;
	    }
	 }
	 else 
	 {
	    if(IsPerson(cptr)) 
	    {
	       if((aconf = find_kill(cptr)))	
		  killflag = YES;	
	    }
	 }
      }

      /* Added a bit of code here to differentiate 
       * between K and Z-lines. -ThemBones
       */

      if (zkillflag || killflag)
      {
         ktype = zkillflag ? "Z-lined" : 
            ((aconf->status == CONF_KILL) ? "K-lined" : "Autokilled");

	 if (killflag) 
         {
	    sendto_ops("%s active for %s",
                       (aconf->status == CONF_KILL) ? "K-line" : "Autokill",
		       get_client_name(cptr, FALSE));
	    reason = aconf->passwd ? aconf->passwd : ktype;
	 }
	 else 
         {			/* its a Z line */
	    sendto_ops("Z-line active for %s",
		       get_client_name(cptr, FALSE));
	    reason = aconf->passwd ? aconf->passwd : "Z-lined";
	 }

	 sendto_one(cptr, err_str(ERR_YOUREBANNEDCREEP),
		    me.name, cptr->name, ktype);

         ircsprintf(fbuf, "%s: %s", ktype, reason);
	 (void) exit_client(cptr, cptr, &me, fbuf);
	 i--;			/* subtract out this fd so we check it again.. */			
	 continue;
      }

      if (IsRegistered(cptr))
	 ping = cptr->pingval;
      else
	 ping = CONNECTTIMEOUT;

      /*
       * Ok, so goto's are ugly and can be avoided here but this code
       * is already indented enough so I think its justified. -avalon
       *
       * justified by what? laziness? <g>
       * If the client pingtime is fine (ie, not larger than the client ping) 
       * skip over all the checks below. - lucas
       */

      if (ping < (currenttime - cptr->lasttime))
      {
         /*
          * If the server hasnt talked to us in 2*ping seconds and it has
          * a ping time, then close its connection. If the client is a
          * user and a KILL line was found to be active, close this
          * connection too.
          */
         if (((cptr->flags & FLAGS_PINGSENT) && ((currenttime - cptr->lasttime) >= (2 * ping))) ||
             ((!IsRegistered(cptr) && (currenttime - cptr->since) >= ping))) 
         {
	    if (!IsRegistered(cptr) && (DoingDNS(cptr) || DoingAuth(cptr))) 
            {
	       if (cptr->authfd >= 0) 
	       {
	          (void) close(cptr->authfd);
	          cptr->authfd = -1;
	          cptr->count = 0;
	          *cptr->buffer = '\0';
	       }
#ifdef SHOW_HEADERS
	       if (DoingDNS(cptr))
	          ssl_send(cptr, REPORT_FAIL_DNS, R_fail_dns, 0);
	       if (DoingAuth(cptr))
	          ssl_send(cptr, REPORT_FAIL_ID, R_fail_id, 0);
#endif
	       Debug((DEBUG_NOTICE, "DNS/AUTH timeout %s",
	 	      get_client_name(cptr, TRUE)));
	       del_queries((char *) cptr);
	       ClearAuth(cptr);
	       ClearDNS(cptr);
	       SetAccess(cptr);
	       cptr->since = currenttime;
	       continue;
	    }

	    if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr)) 
	    {
	       ircsprintf(fbuf, "from %s: %s", me.name, errtxt);
	       sendto_gnotice(fbuf, get_client_name(cptr, HIDEME));
	       ircsprintf(fbuf, ":%s GNOTICE :%s", me.name, errtxt);                                
	       sendto_serv_butone(cptr, fbuf, get_client_name(cptr, HIDEME));
	    }

	    (void) exit_client(cptr, cptr, &me, "Ping timeout");
	    i--;			/* subtract out this fd so we check it again.. */			
	    continue;
         } /* don't send pings during a burst, as we send them already. */

         else if (!(cptr->flags & (FLAGS_PINGSENT|FLAGS_BURST))) {
	    /*
	     * if we havent PINGed the connection and we havent heard from
	     * it in a while, PING it to make sure it is still alive.
	     */
	    cptr->flags |= FLAGS_PINGSENT;
	    /*
	     * not nice but does the job 
	     */
	    cptr->lasttime = currenttime - ping;
	    sendto_one(cptr, "PING :%s", me.name);
         }
      }

      /* see EXPLANATION below
       *
       * timeout = cptr->lasttime + ping;
       * while (timeout <= currenttime)
       *  timeout += ping;
       * if (timeout < oldest || !oldest)
       *   oldest = timeout;
       */

      /*
       * Check UNKNOWN connections - if they have been in this state
       * for > 100s, close them.
       */
      if (IsUnknown(cptr))
	 if (cptr->firsttime ? ((timeofday - cptr->firsttime) > 100) : 0) 
	    (void) exit_client(cptr, cptr, &me, "Connection Timed Out");
   }

   rehashed = 0;
   zline_in_progress = 0;

   /* EXPLANATION
    * on a server with a large volume of clients, at any given point
    * there may be a client which needs to be pinged the next second,
    * or even right away (a second may have passed while running
    * check_pings). Preserving CPU time is more important than
    * pinging clients out at exact times, IMO. Therefore, I am going to make
    * check_pings always return currenttime + 9. This means that it may take
    * a user up to 9 seconds more than pingfreq to timeout. Oh well.
    * Plus, the number is 9 to 'stagger' our check_pings calls out over
    * time, to avoid doing it and the other tasks ircd does at the same time
    * all the time (which are usually done on intervals of 5 seconds or so). 
    * - lucas
    *
    *  if (!oldest || oldest < currenttime)
    *     oldest = currenttime + PINGFREQUENCY;
    */

   oldest = currenttime + 9;

   Debug((DEBUG_NOTICE, "Next check_ping() call at: %s, %d %d %d",
	  myctime(oldest), ping, oldest, currenttime));

   return oldest;
}
Exemplo n.º 23
0
/*
 * The first step in the restore process is for the user to
 *  select a list of JobIds from which he will subsequently
 *  select which files are to be restored.
 *
 *  Returns:  2  if filename list made
 *            1  if jobid list made
 *            0  on error
 */
static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
{
   char *p;
   char date[MAX_TIME_LENGTH];
   bool have_date = false;
   /* Include current second if using current time */
   utime_t now = time(NULL) + 1;
   JobId_t JobId;
   JOB_DBR jr = { (JobId_t)-1 };
   bool done = false;
   int i, j;
   const char *list[] = {
      _("List last 20 Jobs run"),
      _("List Jobs where a given File is saved"),
      _("Enter list of comma separated JobIds to select"),
      _("Enter SQL list command"),
      _("Select the most recent backup for a client"),
      _("Select backup for a client before a specified time"),
      _("Enter a list of files to restore"),
      _("Enter a list of files to restore before a specified time"),
      _("Find the JobIds of the most recent backup for a client"),
      _("Find the JobIds for a backup for a client before a specified time"),
      _("Enter a list of directories to restore for found JobIds"),
      _("Select full restore to a specified Job date"),
      _("Cancel"),
      NULL
   };

   const char *kw[] = {
       /*
        * These keywords are handled in a for loop
        */
      "jobid",         /* 0 */
      "current",       /* 1 */
      "before",        /* 2 */
      "file",          /* 3 */
      "directory",     /* 4 */
      "select",        /* 5 */
      "pool",          /* 6 */
      "all",           /* 7 */

      /*
       * The keyword below are handled by individual arg lookups
       */
      "client",        /* 8 */
      "storage",       /* 9 */
      "fileset",       /* 10 */
      "where",         /* 11 */
      "yes",           /* 12 */
      "bootstrap",     /* 13 */
      "done",          /* 14 */
      "strip_prefix",  /* 15 */
      "add_prefix",    /* 16 */
      "add_suffix",    /* 17 */
      "regexwhere",    /* 18 */
      "restoreclient", /* 19 */
      "copies",        /* 20 */
      "comment",       /* 21 */
      "restorejob",    /* 22 */
      "replace",       /* 23 */
      "pluginoptions", /* 24 */
      NULL
   };

   rx->JobIds[0] = 0;

   for (i = 1; i<ua->argc; i++) {        /* loop through arguments */
      bool found_kw = false;
      for (j = 0; kw[j]; j++) {          /* loop through keywords */
         if (bstrcasecmp(kw[j], ua->argk[i])) {
            found_kw = true;
            break;
         }
      }
      if (!found_kw) {
         ua->error_msg(_("Unknown keyword: %s\n"), ua->argk[i]);
         return 0;
      }
      /* Found keyword in kw[] list, process it */
      switch (j) {
      case 0:                            /* jobid */
         if (!has_value(ua, i)) {
            return 0;
         }
         if (*rx->JobIds != 0) {
            pm_strcat(rx->JobIds, ",");
         }
         pm_strcat(rx->JobIds, ua->argv[i]);
         done = true;
         break;
      case 1:                            /* current */
         /*
          * Note, we add one second here just to include any job
          *  that may have finished within the current second,
          *  which happens a lot in scripting small jobs.
          */
         bstrutime(date, sizeof(date), now);
         have_date = true;
         break;
      case 2:                            /* before */
         if (have_date || !has_value(ua, i)) {
            return 0;
         }
         if (str_to_utime(ua->argv[i]) == 0) {
            ua->error_msg(_("Improper date format: %s\n"), ua->argv[i]);
            return 0;
         }
         bstrncpy(date, ua->argv[i], sizeof(date));
         have_date = true;
         break;
      case 3:                            /* file */
      case 4:                            /* dir */
         if (!has_value(ua, i)) {
            return 0;
         }
         if (!have_date) {
            bstrutime(date, sizeof(date), now);
         }
         if (!get_client_name(ua, rx)) {
            return 0;
         }
         pm_strcpy(ua->cmd, ua->argv[i]);
         insert_one_file_or_dir(ua, rx, date, j==4);
         return 2;
      case 5:                            /* select */
         if (!have_date) {
            bstrutime(date, sizeof(date), now);
         }
         if (!select_backups_before_date(ua, rx, date)) {
            return 0;
         }
         done = true;
         break;
      case 6:                            /* pool specified */
         if (!has_value(ua, i)) {
            return 0;
         }
         rx->pool = (POOLRES *)GetResWithName(R_POOL, ua->argv[i]);
         if (!rx->pool) {
            ua->error_msg(_("Error: Pool resource \"%s\" does not exist.\n"), ua->argv[i]);
            return 0;
         }
         if (!acl_access_ok(ua, Pool_ACL, ua->argv[i], true)) {
            rx->pool = NULL;
            ua->error_msg(_("Error: Pool resource \"%s\" access not allowed.\n"), ua->argv[i]);
            return 0;
         }
         break;
      case 7:                         /* all specified */
         rx->all = true;
         break;
      default:
         /*
          * All keywords 7 or greater are ignored or handled by a select prompt
          */
         break;
      }
   }

   if (!done) {
      ua->send_msg(_("\nFirst you select one or more JobIds that contain files\n"
                  "to be restored. You will be presented several methods\n"
                  "of specifying the JobIds. Then you will be allowed to\n"
                  "select which files from those JobIds are to be restored.\n\n"));
   }

   /* If choice not already made above, prompt */
   for ( ; !done; ) {
      char *fname;
      int len;
      bool gui_save;
      db_list_ctx jobids;

      start_prompt(ua, _("To select the JobIds, you have the following choices:\n"));
      for (int i=0; list[i]; i++) {
         add_prompt(ua, list[i]);
      }
      done = true;
      switch (do_prompt(ua, "", _("Select item: "), NULL, 0)) {
      case -1:                        /* error or cancel */
         return 0;
      case 0:                         /* list last 20 Jobs run */
         if (!acl_access_ok(ua, Command_ACL, NT_("sqlquery"), true)) {
            ua->error_msg(_("SQL query not authorized.\n"));
            return 0;
         }
         gui_save = ua->jcr->gui;
         ua->jcr->gui = true;
         db_list_sql_query(ua->jcr, ua->db, uar_list_jobs, prtit, ua, true, HORZ_LIST);
         ua->jcr->gui = gui_save;
         done = false;
         break;
      case 1:                         /* list where a file is saved */
         if (!get_client_name(ua, rx)) {
            return 0;
         }
         if (!get_cmd(ua, _("Enter Filename (no path):"))) {
            return 0;
         }
         len = strlen(ua->cmd);
         fname = (char *)malloc(len * 2 + 1);
         db_escape_string(ua->jcr, ua->db, fname, ua->cmd, len);
         Mmsg(rx->query, uar_file[db_get_type_index(ua->db)], rx->ClientName, fname);
         free(fname);
         gui_save = ua->jcr->gui;
         ua->jcr->gui = true;
         db_list_sql_query(ua->jcr, ua->db, rx->query, prtit, ua, true, HORZ_LIST);
         ua->jcr->gui = gui_save;
         done = false;
         break;
      case 2:                         /* enter a list of JobIds */
         if (!get_cmd(ua, _("Enter JobId(s), comma separated, to restore: "))) {
            return 0;
         }
         pm_strcpy(rx->JobIds, ua->cmd);
         break;
      case 3:                         /* Enter an SQL list command */
         if (!acl_access_ok(ua, Command_ACL, NT_("sqlquery"), true)) {
            ua->error_msg(_("SQL query not authorized.\n"));
            return 0;
         }
         if (!get_cmd(ua, _("Enter SQL list command: "))) {
            return 0;
         }
         gui_save = ua->jcr->gui;
         ua->jcr->gui = true;
         db_list_sql_query(ua->jcr, ua->db, ua->cmd, prtit, ua, true, HORZ_LIST);
         ua->jcr->gui = gui_save;
         done = false;
         break;
      case 4:                         /* Select the most recent backups */
         if (!have_date) {
            bstrutime(date, sizeof(date), now);
         }
         if (!select_backups_before_date(ua, rx, date)) {
            return 0;
         }
         break;
      case 5:                         /* select backup at specified time */
         if (!have_date) {
            if (!get_date(ua, date, sizeof(date))) {
               return 0;
            }
         }
         if (!select_backups_before_date(ua, rx, date)) {
            return 0;
         }
         break;
      case 6:                         /* Enter files */
         if (!have_date) {
            bstrutime(date, sizeof(date), now);
         }
         if (!get_client_name(ua, rx)) {
            return 0;
         }
         ua->send_msg(_("Enter file names with paths, or < to enter a filename\n"
                        "containing a list of file names with paths, and terminate\n"
                        "them with a blank line.\n"));
         for ( ;; ) {
            if (!get_cmd(ua, _("Enter full filename: "))) {
               return 0;
            }
            len = strlen(ua->cmd);
            if (len == 0) {
               break;
            }
            insert_one_file_or_dir(ua, rx, date, false);
         }
         return 2;
       case 7:                        /* enter files backed up before specified time */
         if (!have_date) {
            if (!get_date(ua, date, sizeof(date))) {
               return 0;
            }
         }
         if (!get_client_name(ua, rx)) {
            return 0;
         }
         ua->send_msg(_("Enter file names with paths, or < to enter a filename\n"
                        "containing a list of file names with paths, and terminate\n"
                        "them with a blank line.\n"));
         for ( ;; ) {
            if (!get_cmd(ua, _("Enter full filename: "))) {
               return 0;
            }
            len = strlen(ua->cmd);
            if (len == 0) {
               break;
            }
            insert_one_file_or_dir(ua, rx, date, false);
         }
         return 2;

      case 8:                         /* Find JobIds for current backup */
         if (!have_date) {
            bstrutime(date, sizeof(date), now);
         }
         if (!select_backups_before_date(ua, rx, date)) {
            return 0;
         }
         done = false;
         break;

      case 9:                         /* Find JobIds for give date */
         if (!have_date) {
            if (!get_date(ua, date, sizeof(date))) {
               return 0;
            }
         }
         if (!select_backups_before_date(ua, rx, date)) {
            return 0;
         }
         done = false;
         break;

      case 10:                        /* Enter directories */
         if (*rx->JobIds != 0) {
            ua->send_msg(_("You have already selected the following JobIds: %s\n"),
               rx->JobIds);
         } else if (get_cmd(ua, _("Enter JobId(s), comma separated, to restore: "))) {
            if (*rx->JobIds != 0 && *ua->cmd) {
               pm_strcat(rx->JobIds, ",");
            }
            pm_strcat(rx->JobIds, ua->cmd);
         }
         if (*rx->JobIds == 0 || *rx->JobIds == '.') {
            *rx->JobIds = 0;
            return 0;                 /* nothing entered, return */
         }
         if (!have_date) {
            bstrutime(date, sizeof(date), now);
         }
         if (!get_client_name(ua, rx)) {
            return 0;
         }
         ua->send_msg(_("Enter full directory names or start the name\n"
                        "with a < to indicate it is a filename containing a list\n"
                        "of directories and terminate them with a blank line.\n"));
         for ( ;; ) {
            if (!get_cmd(ua, _("Enter directory name: "))) {
               return 0;
            }
            len = strlen(ua->cmd);
            if (len == 0) {
               break;
            }
            /* Add trailing slash to end of directory names */
            if (ua->cmd[0] != '<' && !IsPathSeparator(ua->cmd[len-1])) {
               strcat(ua->cmd, "/");
            }
            insert_one_file_or_dir(ua, rx, date, true);
         }
         return 2;

      case 11:                        /* Choose a jobid and select jobs */
         if (!get_cmd(ua, _("Enter JobId to get the state to restore: ")) ||
             !is_an_integer(ua->cmd))
         {
            return 0;
         }

         memset(&jr, 0, sizeof(jr));
         jr.JobId = str_to_int64(ua->cmd);
         if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
            ua->error_msg(_("Unable to get Job record for JobId=%s: ERR=%s\n"),
                          ua->cmd, db_strerror(ua->db));
            return 0;
         }
         ua->send_msg(_("Selecting jobs to build the Full state at %s\n"),
                      jr.cStartTime);
         jr.JobLevel = L_INCREMENTAL; /* Take Full+Diff+Incr */
         if (!db_accurate_get_jobids(ua->jcr, ua->db, &jr, &jobids)) {
            return 0;
         }
         pm_strcpy(rx->JobIds, jobids.list);
         Dmsg1(30, "Item 12: jobids = %s\n", rx->JobIds);
         break;
      case 12:                        /* Cancel or quit */
         return 0;
      }
   }

   memset(&jr, 0, sizeof(jr));
   POOLMEM *JobIds = get_pool_memory(PM_FNAME);
   *JobIds = 0;
   rx->TotalFiles = 0;
   /*
    * Find total number of files to be restored, and filter the JobId
    *  list to contain only ones permitted by the ACL conditions.
    */
   for (p=rx->JobIds; ; ) {
      char ed1[50];
      int status = get_next_jobid_from_list(&p, &JobId);
      if (status < 0) {
         ua->error_msg(_("Invalid JobId in list.\n"));
         free_pool_memory(JobIds);
         return 0;
      }
      if (status == 0) {
         break;
      }
      if (jr.JobId == JobId) {
         continue;                    /* duplicate of last JobId */
      }
      memset(&jr, 0, sizeof(jr));
      jr.JobId = JobId;
      if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
         ua->error_msg(_("Unable to get Job record for JobId=%s: ERR=%s\n"),
            edit_int64(JobId, ed1), db_strerror(ua->db));
         free_pool_memory(JobIds);
         return 0;
      }
      if (!acl_access_ok(ua, Job_ACL, jr.Name, true)) {
         ua->error_msg(_("Access to JobId=%s (Job \"%s\") not authorized. Not selected.\n"),
            edit_int64(JobId, ed1), jr.Name);
         continue;
      }
      if (*JobIds != 0) {
         pm_strcat(JobIds, ",");
      }
      pm_strcat(JobIds, edit_int64(JobId, ed1));
      rx->TotalFiles += jr.JobFiles;
   }
   free_pool_memory(rx->JobIds);
   rx->JobIds = JobIds;               /* Set ACL filtered list */
   if (*rx->JobIds == 0) {
      ua->warning_msg(_("No Jobs selected.\n"));
      return 0;
   }

   if (strchr(rx->JobIds,',')) {
      ua->info_msg(_("You have selected the following JobIds: %s\n"), rx->JobIds);
   } else {
      ua->info_msg(_("You have selected the following JobId: %s\n"), rx->JobIds);
   }
   return 1;
}
Exemplo n.º 24
0
/** Handle a CONNECT message from a server.
 *
 * \a parv has the following elements:
 * \li \a parv[1] is the server that should initiate the connection
 * \li \a parv[2] is the port number to connect on (zero for the default)
 * \li \a parv[3] is the server to connect to
 *
 * See @ref m_functions for discussion of the arguments.
 * @param[in] cptr Client that sent us the message.
 * @param[in] sptr Original source of message.
 * @param[in] parc Number of arguments.
 * @param[in] parv Argument vector.
 */
int ms_connect(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  unsigned short   port;
  unsigned short   tmpport;
  const char*      rule;
  struct ConfItem* aconf;
  struct Client*   acptr;
  struct Jupe*     ajupe;

  assert(0 != cptr);
  assert(0 != sptr);

  if (!IsPrivileged(sptr))
    return send_reply(sptr, ERR_NOPRIVILEGES);

  if (parc < 4) {
    /*
     * this is coming from a server which should have already
     * checked it's args, if we don't have parc == 4, something
     * isn't right.
     */
    protocol_violation(sptr, "Too few parameters to connect");
    return need_more_params(sptr, "CONNECT");
  }

  if (hunt_server_cmd(sptr, CMD_CONNECT, cptr, 1, "%s %s :%C", 3, parc, parv)
      != HUNTED_ISME)
    return 0;

  /*
   * need to find the conf entry first so we can use the server name from
   * the conf entry instead of parv[1] to find out if the server is already
   * present below. --Bleep
   */
  if (0 == (aconf = conf_find_server(parv[1]))) {
    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Host %s not listed "
		  "in ircd.conf", sptr, parv[1]);
    return 0;
  }
  /*
   * use aconf->name to look up the server
   */
  if ((acptr = FindServer(aconf->name))) {
    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Server %s already "
		  "exists from %s", sptr, parv[1], cli_name(cli_from(acptr)));
    return 0;
  }
  /*
   * Evaluate connection rules...  If no rules found, allow the
   * connect.   Otherwise stop with the first true rule (ie: rules
   * are ored together.  Oper connects are effected only by D
   * lines (CRULEALL) not d lines (CRULEAUTO).
   */
  if ((rule = conf_eval_crule(aconf->name, CRULE_ALL))) {
    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Disallowed by rule: %s", sptr, rule);
    return 0;
  }
  /*
   * Check to see if the server is juped; if it is, disallow the connect
   */
  if ((ajupe = jupe_find(aconf->name)) && JupeIsActive(ajupe)) {
    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Connect: Server %s is juped: %s",
		  sptr, JupeServer(ajupe), JupeReason(ajupe));
    return 0;
  }

  /*
   * Allow opers to /connect foo.* 0 bah.* to connect foo and bah
   * using the conf's configured port
   */
  port = atoi(parv[2]);
  /*
   * save the old port
   */
  tmpport = aconf->address.port;
  if (port)
    aconf->address.port = port;
  else
    port = aconf->address.port;

  /*
   * Notify all operators about remote connect requests
   */
  sendwallto_group(&me, WALL_WALLOPS, 0,
                   "Remote CONNECT %s %s from %s", parv[1],
                   parv[2] ? parv[2] : "",
                   get_client_name(sptr, HIDE_IP));
  log_write(LS_NETWORK, L_INFO, 0, "CONNECT From %C : %s %s", sptr, parv[1],
	    parv[2] ? parv[2] : "");

  if (connect_server(aconf, sptr)) {
    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :*** Connecting to %s.", sptr,
		  aconf->name);
  }
  else {
    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :*** Connection to %s failed",
		  sptr, aconf->name);
  }
  aconf->address.port = tmpport;
  return 0;
}
Exemplo n.º 25
0
/*
** m_kill
**	parv[0] = sender prefix
**	parv[1] = kill victim(s) - comma separated list
**	parv[2] = kill path
*/
DLLFUNC int  m_kill(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
	aClient *acptr;
	anUser *auser;
	char inpath[HOSTLEN * 2 + USERLEN + 5];
	char *oinpath = get_client_name(cptr, FALSE);
	char *user, *path, *killer, *nick, *p, *s;
	int  chasing = 0, kcount = 0;



	if (parc < 2 || *parv[1] == '\0')
	{
		sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
		    me.name, parv[0], "KILL");
		return 0;
	}

	user = parv[1];
	path = parv[2];		/* Either defined or NULL (parc >= 2!!) */

	strlcpy(inpath, oinpath, sizeof inpath);

#ifndef ROXnet
	if (IsServer(cptr) && (s = (char *)index(inpath, '.')) != NULL)
		*s = '\0';	/* Truncate at first "." */
#endif

	if (!IsPrivileged(cptr))
	{
		sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
		return 0;
	}
	if (IsAnOper(cptr))
	{
		if (BadPtr(path))
		{
			sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
			    me.name, parv[0], "KILL");
			return 0;
		}
		if (strlen(path) > (size_t)TOPICLEN)
			path[TOPICLEN] = '\0';
	}

	if (MyClient(sptr))
		user = (char *)canonize(user);

	for (p = NULL, nick = strtoken(&p, user, ","); nick;
	    nick = strtoken(&p, NULL, ","))
	{

		chasing = 0;

		if (!(acptr = find_client(nick, NULL)))
		{
			/*
			   ** If the user has recently changed nick, we automaticly
			   ** rewrite the KILL for this new nickname--this keeps
			   ** servers in synch when nick change and kill collide
			 */
			if (!(acptr =
			    get_history(nick, (long)KILLCHASETIMELIMIT)))
			{
				sendto_one(sptr, err_str(ERR_NOSUCHNICK),
				    me.name, parv[0], nick);
				continue;
			}
			sendto_one(sptr,
			    ":%s %s %s :*** KILL changed from %s to %s",
			    me.name, IsWebTV(sptr) ? "PRIVMSG" : "NOTICE", parv[0], nick, acptr->name);
			chasing = 1;
		}
		if ((!MyConnect(acptr) && MyClient(cptr) && !OPCanGKill(cptr))
		    || (MyConnect(acptr) && MyClient(cptr)
		    && !OPCanLKill(cptr)))
		{
			sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name,
			    parv[0]);
			continue;
		}
		if (IsServer(acptr) || IsMe(acptr))
		{
			sendto_one(sptr, err_str(ERR_CANTKILLSERVER),
			    me.name, parv[0]);
			continue;
		}
		if (!IsPerson(acptr))
		{
			/* Nick exists but user is not registered yet: IOTW "doesn't exist". -- Syzop */
			sendto_one(sptr, err_str(ERR_NOSUCHNICK),
			    me.name, parv[0], nick);
			continue;
		}

		if (IsServices(acptr) && !(IsNetAdmin(sptr) || IsULine(sptr)))
		{
			sendto_one(sptr, err_str(ERR_KILLDENY), me.name,
			    parv[0], parv[1]);
			return 0;
		}
		/* From here on, the kill is probably going to be successful. */

		kcount++;

		if (!IsServer(sptr) && (kcount > MAXKILLS))
		{
			sendto_one(sptr,
			    ":%s %s %s :*** Too many targets, kill list was truncated. Maximum is %d.",
			    me.name, IsWebTV(sptr) ? "PRIVMSG" : "NOTICE", parv[0], MAXKILLS);
			break;
		}
		if (!IsServer(cptr))
		{
			/*
			   ** The kill originates from this server, initialize path.
			   ** (In which case the 'path' may contain user suplied
			   ** explanation ...or some nasty comment, sigh... >;-)
			   **
			   **   ...!operhost!oper
			   **   ...!operhost!oper (comment)
			 */
			strlcpy(inpath, GetHost(cptr), sizeof inpath);
			if (kcount < 2) {	/* Only check the path the first time
					   around, or it gets appended to itself. */
				if (!BadPtr(path))
				{
					(void)ircsprintf(buf, "%s%s (%s)",
					    cptr->name,
					    IsOper(sptr) ? "" : "(L)", path);
					path = buf;
				}
				else
					path = cptr->name;
			}
		}
		else if (BadPtr(path))
			path = "*no-path*";	/* Bogus server sending??? */
		/*
		   ** Notify all *local* opers about the KILL (this includes the one
		   ** originating the kill, if from this server--the special numeric
		   ** reply message is not generated anymore).
		   **
		   ** Note: "acptr->name" is used instead of "user" because we may
		   **    have changed the target because of the nickname change.
		 */

		auser = acptr->user;

		sendto_snomask_normal(SNO_KILLS,
		    "*** Notice -- Received KILL message for %s!%s@%s from %s Path: %s!%s",
		    acptr->name, auser->username,
		    IsHidden(acptr) ? auser->virthost : auser->realhost,
		    parv[0], inpath, path);
#if defined(USE_SYSLOG) && defined(SYSLOG_KILL)
		if (IsOper(sptr))
			syslog(LOG_DEBUG, "KILL From %s For %s Path %s!%s",
			    parv[0], acptr->name, inpath, path);
#endif
		/*
		 * By otherguy
		*/
                ircd_log
                    (LOG_KILL, "KILL (%s) by  %s(%s!%s)",
                           make_nick_user_host
                     (acptr->name, acptr->user->username, GetHost(acptr)),
                            parv[0],
                            inpath,
                            path);
		/*
		   ** And pass on the message to other servers. Note, that if KILL
		   ** was changed, the message has to be sent to all links, also
		   ** back.
		   ** Suicide kills are NOT passed on --SRB
		 */
		if (!MyConnect(acptr) || !MyConnect(sptr) || !IsAnOper(sptr))
		{
			sendto_serv_butone(cptr, ":%s KILL %s :%s!%s",
			    parv[0], acptr->name, inpath, path);
			if (chasing && IsServer(cptr))
				sendto_one(cptr, ":%s KILL %s :%s!%s",
				    me.name, acptr->name, inpath, path);
			acptr->flags |= FLAGS_KILLED;
		}

		/*
		   ** Tell the victim she/he has been zapped, but *only* if
		   ** the victim is on current server--no sense in sending the
		   ** notification chasing the above kill, it won't get far
		   ** anyway (as this user don't exist there any more either)
		 */
		if (MyConnect(acptr))
			sendto_prefix_one(acptr, sptr, ":%s KILL %s :%s!%s",
			    parv[0], acptr->name, inpath, path);
		/*
		   ** Set FLAGS_KILLED. This prevents exit_one_client from sending
		   ** the unnecessary QUIT for this. (This flag should never be
		   ** set in any other place)
		 */
		if (MyConnect(acptr) && MyConnect(sptr) && IsAnOper(sptr))

			(void)ircsprintf(buf2, "[%s] Local kill by %s (%s)",
			    me.name, sptr->name,
			    BadPtr(parv[2]) ? sptr->name : parv[2]);
		else
		{
			if ((killer = index(path, ' ')))
			{
				while ((killer >= path) && *killer && *killer != '!')
					killer--;
				if (!*killer)
					killer = path;
				else
					killer++;
			}
			else
				killer = path;
			(void)ircsprintf(buf2, "Killed (%s)", killer);
		}

		if (MyClient(sptr))
			RunHook3(HOOKTYPE_LOCAL_KILL, sptr, acptr, parv[2]);
		if (exit_client(cptr, acptr, sptr, buf2) == FLUSH_BUFFER)
			return FLUSH_BUFFER;
	}
	return 0;
}
Exemplo n.º 26
0
DLLFUNC CMD_FUNC(m_names)
{
	int uhnames = (MyConnect(sptr) && SupportUHNAMES(sptr)); // cache UHNAMES support
	int bufLen = NICKLEN + (!uhnames ? 0 : (1 + USERLEN + 1 + HOSTLEN));
	int  mlen = strlen(me.name) + bufLen + 7;
	aChannel *chptr;
	aClient *acptr;
	int  member;
	Member *cm;
	int  idx, flag = 1, spos;
	char *s, *para = parv[1];
	char nuhBuffer[NICKLEN+USERLEN+HOSTLEN+3];


	if (parc < 2 || !MyConnect(sptr))
	{
		sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name,
		    parv[0], "*");
		return 0;
	}

	for (s = para; *s; s++)
	{
		if (*s == ',')
		{
			if (strlen(para) > TRUNCATED_NAMES)
				para[TRUNCATED_NAMES] = '\0';
			sendto_realops("names abuser %s %s",
			    get_client_name(sptr, FALSE), para);
			sendto_one(sptr, err_str(ERR_TOOMANYTARGETS),
			    me.name, sptr->name, "NAMES");
			return 0;
		}
	}

	chptr = find_channel(para, (aChannel *)NULL);

	if (!chptr || (!ShowChannel(sptr, chptr) && !OPCanSeeSecret(sptr)))
	{
		sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name,
		    parv[0], para);
		return 0;
	}

	/* cache whether this user is a member of this channel or not */
	member = IsMember(sptr, chptr);

	if (PubChannel(chptr))
		buf[0] = '=';
	else if (SecretChannel(chptr))
		buf[0] = '@';
	else
		buf[0] = '*';

	idx = 1;
	buf[idx++] = ' ';
	for (s = chptr->chname; *s; s++)
		buf[idx++] = *s;
	buf[idx++] = ' ';
	buf[idx++] = ':';

	/* If we go through the following loop and never add anything,
	   we need this to be empty, otherwise spurious things from the
	   LAST /names call get stuck in there.. - lucas */
	buf[idx] = '\0';

	spos = idx;		/* starting point in buffer for names! */

	for (cm = chptr->members; cm; cm = cm->next)
	{
		acptr = cm->cptr;
		if (IsInvisible(acptr) && !member && !IsNetAdmin(sptr))
			continue;
		if (chptr->mode.mode & MODE_AUDITORIUM)
			if (!is_chan_op(sptr, chptr)
			    && !is_chanprot(sptr, chptr)
			    && !is_chanowner(sptr, chptr))
				if (!(cm->
				    flags & (CHFL_CHANOP | CHFL_CHANPROT |
				    CHFL_CHANOWNER)) && acptr != sptr)
					continue;

		if (!SupportNAMESX(sptr))
		{
			/* Standard NAMES reply */
#ifdef PREFIX_AQ
			if (cm->flags & CHFL_CHANOWNER)
				buf[idx++] = '~';
			else if (cm->flags & CHFL_CHANPROT)
				buf[idx++] = '&';
			else
#endif
			if (cm->flags & CHFL_CHANOP)
				buf[idx++] = '@';
			else if (cm->flags & CHFL_HALFOP)
				buf[idx++] = '%';
			else if (cm->flags & CHFL_VOICE)
				buf[idx++] = '+';
		} else {
			/* NAMES reply with all rights included (NAMESX) */
#ifdef PREFIX_AQ
			if (cm->flags & CHFL_CHANOWNER)
				buf[idx++] = '~';
			if (cm->flags & CHFL_CHANPROT)
				buf[idx++] = '&';
#endif
			if (cm->flags & CHFL_CHANOP)
				buf[idx++] = '@';
			if (cm->flags & CHFL_HALFOP)
				buf[idx++] = '%';
			if (cm->flags & CHFL_VOICE)
				buf[idx++] = '+';
		}

		if (!uhnames) {
			s = acptr->name;
		} else {
			strlcpy(nuhBuffer,
			        make_nick_user_host(acptr->name, acptr->user->username, GetHost(acptr)),
				bufLen + 1);
			s = nuhBuffer;
		}
		/* 's' is intialized above to point to either acptr->name (normal),
		 * or to nuhBuffer (for UHNAMES).
		 */
		for (; *s; s++)
			buf[idx++] = *s;
		buf[idx++] = ' ';
		buf[idx] = '\0';
		flag = 1;
		if (mlen + idx + bufLen > BUFSIZE - 7)
		{
			sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name,
			    parv[0], buf);
			idx = spos;
			flag = 0;
		}
	}

	if (flag)
		sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);

	sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0], para);

	return 0;

}
Exemplo n.º 27
0
/*
 *  m_server
 *       parv[0] = sender prefix
 *       parv[1] = servername
 *       parv[2] = serverinfo/hopcount
 *       parv[3] = serverinfo
 */
int m_server(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
    int     i;
    char        info[REALLEN + 1], *host;
    aClient    *acptr, *bcptr;
    aConnect   *aconn;
    int         hop;
    char        nbuf[HOSTLEN * 2 + USERLEN + 5]; /* same size as in s_misc.c */

    info[0] = '\0';

    if (parc < 2 || *parv[1] == '\0')
    {
        sendto_one(cptr, "ERROR :No servername");
        return 0;
    }

    hop = 0;
    host = parv[1];
    if (parc > 3 && atoi(parv[2]))
    {
        hop = atoi(parv[2]);
        strncpyzt(info, parv[3], REALLEN + 1);
    }
    else if (parc > 2)
    {
        strncpyzt(info, parv[2], REALLEN + 1);
        if ((parc > 3) && ((i = strlen(info)) < (REALLEN - 2)))
        {
            strcat(info, " ");
            strncat(info, parv[3], REALLEN - i - 2);
            info[REALLEN] = '\0';
        }
    }
    /*
     * July 5, 1997
     * Rewritten to throw away server cruft from users,
     * combined the hostname validity test with cleanup of host name,
     * so a cleaned up hostname can be returned as an error if
     * necessary. - Dianora
     */

    /* yes, the if(strlen) below is really needed!! */
    if (strlen(host) > HOSTLEN)
        host[HOSTLEN] = '\0';

    if (IsPerson(cptr))
    {
        /* A local link that has been identified as a USER tries
         * something fishy... ;-)
         */
        sendto_one(cptr, err_str(ERR_UNKNOWNCOMMAND),
                   me.name, parv[0], "SERVER");

        return 0;
    }
    else
        /* hostile servername check */
    {
        /*
         * Lets check for bogus names and clean them up we don't bother
         * cleaning up ones from users, becasuse we will never see them
         * any more - Dianora
         */

        int bogus_server = 0;
        int found_dot = 0;
        char clean_host[(2 * HOSTLEN) + 1];
        char *s;
        char *d;
        int n;

        s = host;
        d = clean_host;
        n = (2 * HOSTLEN) - 2;

        while (*s && n > 0)
        {
            if ((unsigned char) *s < (unsigned char) ' ')
                /* Is it a control character? */
            {
                bogus_server = 1;
                *d++ = '^';
                *d++ = (char) ((unsigned char) *s + 0x40);
                /* turn it into a printable */
                n -= 2;
            }
            else if ((unsigned char) *s > (unsigned char) '~')
            {
                bogus_server = 1;
                *d++ = '.';
                n--;
            }
            else
            {
                if (*s == '.')
                    found_dot = 1;
                *d++ = *s;
                n--;
            }
            s++;
        }
        *d = '\0';

        if ((!found_dot) || bogus_server)
        {
            sendto_one(sptr, "ERROR :Bogus server name (%s)",
                       clean_host);
            return exit_client(cptr, cptr, cptr, "Bogus server name");
        }
    }

    /* new connection */
    if (IsUnknown(cptr) || IsHandshake(cptr))
    {
        strncpyzt(cptr->name, host, sizeof(cptr->name));
        strncpyzt(cptr->info, info[0] ? info : me.name, REALLEN + 1);
        cptr->hopcount = hop;

        switch (check_server_init(cptr))
        {
            case 0:
                return m_server_estab(cptr);
            case 1:
                sendto_ops("Access check for %s in progress",
                           get_client_name(cptr, HIDEME));
                return 1;
            default:
                ircstp->is_ref++;
                sendto_ops_lev(ADMIN_LEV, "Link %s dropped, no Connect block",
                           get_client_name(cptr, TRUE));
                return exit_client(cptr, cptr, cptr, "No Connect block");
        }
    }
    
    /* already linked server */
    if (!IsServer(cptr))
        return 0;

    if ((acptr = find_name(host, NULL)))
    {
        /*
         * * This link is trying feed me a server that I already have
         * access through another path -- multiple paths not accepted
         * currently, kill this link immediately!!
         *
         * Rather than KILL the link which introduced it, KILL the
         * youngest of the two links. -avalon
         */

        bcptr = (cptr->firsttime > acptr->from->firsttime) ? cptr :
            acptr->from;
        sendto_one(bcptr, "ERROR :Server %s already exists", host);
        if (bcptr == cptr)
        {
            /* Don't complain for servers that are juped */
            /* (don't complain if the server that already exists is U: lined,
                unless I actually have a .conf U: line for it */
            if(!IsULine(acptr) || find_aUserver(acptr->name))
            {
                sendto_gnotice("from %s: Link %s cancelled, server %s already "
                               "exists", me.name, get_client_name(bcptr, HIDEME),
                               host);
                sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, "
                                   "server %s already exists", me.name,
                                   get_client_name(bcptr, HIDEME), host);
            }
            return exit_client(bcptr, bcptr, &me, "Server Exists");
        }
        /* inform all those who care (set +n) -epi */
        strcpy(nbuf, get_client_name(bcptr, HIDEME));
        sendto_gnotice("from %s: Link %s cancelled, server %s reintroduced "
                       "by %s", me.name, nbuf, host,
                       get_client_name(cptr, HIDEME));
        sendto_serv_butone(bcptr, ":%s GNOTICE :Link %s cancelled, server %s "
                           "reintroduced by %s", me.name, nbuf, host,
                           get_client_name(cptr, HIDEME));
        exit_client(bcptr, bcptr, &me, "Server Exists");
    }
    /*
     * The following if statement would be nice to remove since user
     * nicks never have '.' in them and servers must always have '.' in
     * them. There should never be a server/nick name collision, but it
     * is possible a capricious server admin could deliberately do
     * something strange.
     *
     * -Dianora
     */

    if ((acptr = find_client(host, NULL)) && acptr != cptr)
    {
        /*
         * * Server trying to use the same name as a person. Would
         * cause a fair bit of confusion. Enough to make it hellish for
         * a while and servers to send stuff to the wrong place.
         */
        sendto_one(cptr, "ERROR :Nickname %s already exists!", host);
        strcpy(nbuf, get_client_name(cptr, HIDEME));
        sendto_gnotice("from %s: Link %s cancelled, servername/nick collision",
                       me.name, nbuf);
        sendto_serv_butone(cptr, ":%s GNOTICE :Link %s cancelled, "
                           "servername/nick collision", me.name, nbuf);
        return exit_client(cptr, cptr, cptr, "Nick as Server");
    }

    if (IsServer(cptr))
    {
        /*
         * * Server is informing about a new server behind this link.
         * Create REMOTE server structure, add it to list and propagate
         * word to my other server links...
         */
        if (parc == 1 || info[0] == '\0')
        {
            sendto_one(cptr, "ERROR :No server info specified for %s", host);
            return 0;
        }
        /*
         * * See if the newly found server is behind a guaranteed leaf
         * (L-line). If so, close the link.
         *
         * Depreciated.  Kinda redundant with Hlines. -epi
         */
        if (!(cptr->serv->aconn->flags & CONN_HUB))
        {
            aconn = cptr->serv->aconn;
            sendto_gnotice("from %s: Non-Hub link %s introduced %s",
                           me.name, get_client_name(cptr, HIDEME), host);
            sendto_serv_butone(cptr,":%s GNOTICE :Non-Hub link %s introduced "
                               "%s", me.name, get_client_name(cptr, HIDEME),
                               host);
            sendto_one(cptr, "ERROR :You're not a hub (introducing %s)",
                       host);
            return exit_client(cptr, cptr, cptr, "Too many servers");
        }

        acptr = make_client(cptr, sptr);
        make_server(acptr);
        acptr->hopcount = hop;
        strncpyzt(acptr->name, host, sizeof(acptr->name));
        strncpyzt(acptr->info, info, REALLEN + 1);
        acptr->serv->up = find_or_add(parv[0]);

        fakelinkserver_update(acptr->name, acptr->info);
        SetServer(acptr);

        /*
         * if this server is behind a U-lined server, make it U-lined as
         * well. - lucas
         */

        if (IsULine(sptr) || find_aUserver(acptr->name))
        {
            acptr->flags |= FLAGS_ULINE;
            sendto_realops_lev(DEBUG_LEV, "%s introducing super server %s",
                               cptr->name, acptr->name);
        }

        Count.server++;

        add_client_to_list(acptr);
        add_to_client_hash_table(acptr->name, acptr);
        /*
         * Old sendto_serv_but_one() call removed because we now need
         * to send different names to different servers (domain name matching)
         */
        for (i = 0; i <= highest_fd; i++)
        {
            if (!(bcptr = local[i]) || !IsServer(bcptr) || bcptr == cptr ||
                IsMe(bcptr))
                continue;
            if (!(aconn = bcptr->serv->aconn))
            {
                sendto_gnotice("from %s: Lost Connect block for %s on %s."
                               " Closing", me.name,
                               get_client_name(cptr, HIDEME), host);
                sendto_serv_butone(cptr, ":%s GNOTICE :Lost Connect block for"
                                   " %s on %s. Closing", me.name,
                                   get_client_name(cptr, HIDEME), host);
                return exit_client(cptr, cptr, cptr, "Lost Connect block");
            }
            if (match(my_name_for_link(me.name, aconn), acptr->name) == 0)
                continue;
            sendto_one(bcptr, ":%s SERVER %s %d :%s",
                       parv[0], acptr->name, hop + 1, acptr->info);
        }
        return 0;
    }

    return 0;
}
Exemplo n.º 28
0
/*
** m_user
**	parv[0] = sender prefix
**	parv[1] = username (login name, account)
**	parv[2] = client host name (used only from other servers)
**	parv[3] = server host name (used only from other servers)
**	parv[4] = users real name info
**
** NOTE: Be advised that multiple USER messages are possible,
**       hence, always check if a certain struct is already allocated... -- Syzop
*/
DLLFUNC CMD_FUNC(m_user)
{
#define	UFLAGS	(UMODE_INVISIBLE|UMODE_WALLOP|UMODE_SERVNOTICE)
	char *username, *host, *server, *realname, *umodex = NULL, *virthost =
	    NULL, *ip = NULL;
	u_int32_t sstamp = 0;
	anUser *user;
	aClient *acptr;

	if (IsServer(cptr) && !IsUnknown(sptr))
		return 0;

	if (MyConnect(sptr) && (sptr->listener->umodes & LISTENER_SERVERSONLY))
	{
		return exit_client(cptr, sptr, sptr,
		    "This port is for servers only");
	}

	if (parc > 2 && (username = (char *)index(parv[1], '@')))
		*username = '******';
	if (parc < 5 || *parv[1] == '\0' || *parv[2] == '\0' ||
	    *parv[3] == '\0' || *parv[4] == '\0')
	{
		sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
		    me.name, parv[0], "USER");
		if (IsServer(cptr))
			sendto_ops("bad USER param count for %s from %s",
			    parv[0], get_client_name(cptr, FALSE));
		else
			return 0;
	}


	/* Copy parameters into better documenting variables */

	username = (parc < 2 || BadPtr(parv[1])) ? "<bad-boy>" : parv[1];
	host = (parc < 3 || BadPtr(parv[2])) ? "<nohost>" : parv[2];
	server = (parc < 4 || BadPtr(parv[3])) ? "<noserver>" : parv[3];

	/* This we can remove as soon as all servers have upgraded. */

	if (parc == 6 && IsServer(cptr))
	{
		if (isdigit(*parv[4]))
			sstamp = strtoul(parv[4], NULL, 10);
		realname = (BadPtr(parv[5])) ? "<bad-realname>" : parv[5];
		umodex = NULL;
	}
	else if (parc == 8 && IsServer(cptr))
	{
		if (isdigit(*parv[4]))
			sstamp = strtoul(parv[4], NULL, 10);
		realname = (BadPtr(parv[7])) ? "<bad-realname>" : parv[7];
		umodex = parv[5];
		virthost = parv[6];
	}
	else if (parc == 9 && IsServer(cptr))
	{
		if (isdigit(*parv[4]))
			sstamp = strtoul(parv[4], NULL, 10);
		realname = (BadPtr(parv[8])) ? "<bad-realname>" : parv[8];
		umodex = parv[5];
		virthost = parv[6];
		ip = parv[7];
	}
	else
	{
		realname = (BadPtr(parv[4])) ? "<bad-realname>" : parv[4];
	}
	user = make_user(sptr);

	if (!MyConnect(sptr))
	{
		if (sptr->srvptr == NULL)
			sendto_ops("WARNING, User %s introduced as being "
			    "on non-existant server %s.", sptr->name, server);
		if (SupportNS(cptr))
		{
			acptr = (aClient *)find_server_b64_or_real(server);
			if (acptr)
				user->server = find_or_add(acptr->name);
			else
				user->server = find_or_add(server);
		}
		else
			user->server = find_or_add(server);
		strlcpy(user->realhost, host, sizeof(user->realhost));
		goto user_finish;
	}

	if (!IsUnknown(sptr))
	{
		sendto_one(sptr, err_str(ERR_ALREADYREGISTRED),
		    me.name, parv[0]);
		return 0;
	}

	if (!IsServer(cptr))
	{
		sptr->umodes |= CONN_MODES;
		if (CONNECT_SNOMASK)
		{
			sptr->umodes |= UMODE_SERVNOTICE;
			create_snomask(sptr, user, CONNECT_SNOMASK);
		}
	}

	/* Set it temporarely to at least something trusted,
	 * this was copying user supplied data directly into user->realhost
	 * which seemed bad. Not to say this is much better ;p. -- Syzop
	 */
	strncpyzt(user->realhost, Inet_ia2p(&sptr->ip), sizeof(user->realhost));
	if (!user->ip_str)
		user->ip_str = strdup(Inet_ia2p(&sptr->ip));
	user->server = me_hash;
      user_finish:
	user->servicestamp = sstamp;
	strlcpy(sptr->info, realname, sizeof(sptr->info));
	if (sptr->name[0] && (IsServer(cptr) ? 1 : IsNotSpoof(sptr)))
		/* NICK and no-spoof already received, now we have USER... */
	{
		if (USE_BAN_VERSION && MyConnect(sptr))
			sendto_one(sptr, ":IRC!IRC@%s PRIVMSG %s :\1VERSION\1",
				me.name, sptr->name);
		if (strlen(username) > USERLEN)
			username[USERLEN] = '\0'; /* cut-off */
		return(
		    register_user(cptr, sptr, sptr->name, username, umodex,
		    virthost,ip));
	}
	else
		strncpyzt(sptr->user->username, username, USERLEN + 1);

	return 0;
}
Exemplo n.º 29
0
/*
 * parse a buffer.
 *
 * NOTE: parse() should not be called recusively by any other functions!
 */
int parse(aClient *cptr, char *pbuffer, char *bufend)
{
  aClient *from = cptr;
  char  *ch;
  char  *s;
  char  parsebuf[2048];
  int   i;
  char* numeric = 0;
  int   paramcount;
  struct Message *mptr;

  Debug((DEBUG_DEBUG, "Parsing %s: %s",
         get_client_name(cptr, TRUE), pbuffer));

  if (IsDead(cptr))
    return -1;

        if (MyClient(cptr) && cptr->codepage) {
                char *trans = codepage_to_unicode(pbuffer, cptr->codepage - 1);
                if (trans != pbuffer) {
                        strncpy(parsebuf, trans, sizeof(parsebuf));
                        pbuffer = parsebuf;
                        bufend = parsebuf + strlen(parsebuf) - 1;
                }
        }

  s = sender;
  *s = '\0';

  for (ch = pbuffer; *ch == ' '; ch++)   /* skip spaces */
    /* null statement */ ;

  para[0] = from->name;
  if (*ch == ':')
    {
      ch++;

      /*
      ** Copy the prefix to 'sender' assuming it terminates
      ** with SPACE (or NULL, which is an error, though).
      */
      for (i = 0; *ch && *ch != ' '; i++ )
	{
	  if (i < (sizeof(sender)-1))
	    *s++ = *ch; /* leave room for NULL */
	  ch++;
	}
      *s = '\0';
      i = 0;

      /*
      ** Actually, only messages coming from servers can have
      ** the prefix--prefix silently ignored, if coming from
      ** a user client...
      **
      ** ...sigh, the current release "v2.2PL1" generates also
      ** null prefixes, at least to NOTIFY messages (e.g. it
      ** puts "sptr->nickname" as prefix from server structures
      ** where it's null--the following will handle this case
      ** as "no prefix" at all --msa  (": NOTICE nick ...")
      */
      if (*sender && IsServer(cptr))
        {
          from = find_client(sender, (aClient *) NULL);
          if (!from || !match(from->name, sender))
            from = find_server(sender);

          para[0] = sender;
          
          /* Hmm! If the client corresponding to the
           * prefix is not found--what is the correct
           * action??? Now, I will ignore the message
           * (old IRC just let it through as if the
           * prefix just wasn't there...) --msa
           */
          if (!from)
            {
              Debug((DEBUG_ERROR, "Unknown prefix (%s)(%s) from (%s)",
                     sender, pbuffer, cptr->name));
              ServerStats->is_unpf++;

              remove_unknown(cptr, sender, pbuffer);

              return -1;
            }
          if (from->from != cptr)
            {
              ServerStats->is_wrdi++;
              Debug((DEBUG_ERROR, "Message (%s) coming from (%s)",
                     pbuffer, cptr->name));

              return cancel_clients(cptr, from, pbuffer);
            }
        }
      while (*ch == ' ')
        ch++;
    }

  if (*ch == '\0')
    {
      ServerStats->is_empt++;
      Debug((DEBUG_NOTICE, "Empty message from host %s:%s",
             cptr->name, from->name));
      return(-1);
    }

  /*
  ** Extract the command code from the packet.  Point s to the end
  ** of the command code and calculate the length using pointer
  ** arithmetic.  Note: only need length for numerics and *all*
  ** numerics must have parameters and thus a space after the command
  ** code. -avalon
  *
  * ummm???? - Dianora
  */
  
  /* Lets log any message we receive except nickserv/chanserv and
     privmsgs/notices - Lamego
  */
  if(debug_opt)
    {
      if(strncasecmp(ch,"PRIVMSG",7)==0 || strncasecmp(ch,"NOTICE",6)==0)
        irclog(L_NOTICE,"Recv: (%s) PRIVMSG/NOTICE ...", from->name);
      else if(strncasecmp(ch,"NICKSERV",8)==0 || strncasecmp(ch,"CHANSERV",8)==0)
        irclog(L_NOTICE,"Recv: (%s) NICKSERV/CHANSERV ...", from->name);
      else
        irclog(L_NOTICE,"Recv: (%s) %s", from->name, ch);
    }
  if( *(ch + 3) == ' ' && /* ok, lets see if its a possible numeric.. */
      IsDigit(*ch) && IsDigit(*(ch + 1)) && IsDigit(*(ch + 2)) )
    {
      mptr = (struct Message *)NULL;
      numeric = ch;
      paramcount = MAXPARA;
      ServerStats->is_num++;
      s = ch + 3;       /* I know this is ' ' from above if */
      *s++ = '\0';      /* blow away the ' ', and point s to next part */
    }
  else
    {
      s = strchr(ch, ' ');      /* moved from above,now need it here */
      if (s)
        *s++ = '\0';

      mptr = tree_parse(ch);

      if (!mptr || !mptr->cmd)
        {
          /*
          ** Note: Give error message *only* to recognized
          ** persons. It's a nightmare situation to have
          ** two programs sending "Unknown command"'s or
          ** equivalent to each other at full blast....
          ** If it has got to person state, it at least
          ** seems to be well behaving. Perhaps this message
          ** should never be generated, though...  --msa
          ** Hm, when is the buffer empty -- if a command
          ** code has been found ?? -Armin
          */
          if (pbuffer[0] != '\0')
            {
              if (IsPerson(from))
                sendto_one(from,
                           ":%s %d %s %s :Unknown command",
                           me.name, ERR_UNKNOWNCOMMAND,
                           from->name, ch);
              Debug((DEBUG_ERROR,"Unknown (%s) from %s",
                     ch, get_client_name(cptr, TRUE)));
            }
          ServerStats->is_unco++;
          return(-1);
        }

      paramcount = mptr->parameters;
      i = bufend - ((s) ? s : ch);
      mptr->bytes += i;

#ifdef FLOOD_DELAY
      /* Allow only 1 msg per 2 seconds
       * (on average) to prevent dumping.
       * to keep the response rate up,
       * bursts of up to 5 msgs are allowed
       * -SRB
       * Opers can send 1 msg per second, burst of ~20
       * -Taner
       */
      if ((mptr->flags & 1) && !(IsServer(cptr)) && !IsFloodEx(cptr) )
        {
#ifdef NO_OPER_FLOOD
#ifndef TRUE_NO_OPER_FLOOD
/* note: both have to be defined for the real no-flood */
          if (IsAnOper(cptr))
            /* "randomly" (weighted) increase the since */
            cptr->since += (cptr->receiveM % 5) ? 1 : 0;
          else
#else
          if (!IsAnOper(cptr))
#endif
#endif
            cptr->since += (2 + i / 120);
        }
#endif /* FLOOD_DELAY */            
    }

  /*
  ** Must the following loop really be so devious? On
  ** surface it splits the message to parameters from
  ** blank spaces. But, if paramcount has been reached,
  ** the rest of the message goes into this last parameter
  ** (about same effect as ":" has...) --msa
  */

  /* Note initially true: s==NULL || *(s-1) == '\0' !! */

  /* ZZZ hmmmmmmmm whats this then? */
#if 0
  if (me.user)
    para[0] = sender;
#endif

  i = 1;

  if (s)
    {
      if (paramcount > MAXPARA)
        paramcount = MAXPARA;

      for (;;)
        {
	  while(*s == ' ')	/* tabs are not considered space */
	    *s++ = '\0';

          if(!*s)
            break;

          if (*s == ':')
            {
              /*
              ** The rest is single parameter--can
              ** include blanks also.
              */
              para[i++] = s + 1;
              break;
            }
	  else
	    {
	      para[i++] = s;
              if (i >= paramcount)
                {
                  break;
                }
              /* scan for end of string, either ' ' or '\0' */
              while (IsNonEOS(*s))
                s++;
	    }
        }
    }

  para[i] = NULL;
  if (mptr == (struct Message *)NULL)
    return (do_numeric(numeric, cptr, from, i, para));

  mptr->count++;

  /* patch to avoid server flooding from unregistered connects */
  /* check allow_unregistered_use flag I've set up instead of function
     comparing *yech* - Dianora */

  if ((!IsRegistered(cptr) || (hvc_enabled && cptr->hvc)) && !mptr->allow_unregistered_use)
    {
      /* if its from a possible server connection
       * ignore it.. more than likely its a header thats sneaked through
       */

      if(IsHandshake(cptr) || IsConnecting(cptr) || IsServer(cptr))
        return -1;

      sendto_one(from,
                 ":%s %d %s %s :Register first.",
                 me.name, ERR_NOTREGISTERED,
                 BadPtr(from->name) ? "*" : from->name, ch);
      return -1;
    }

  /* Again, instead of function address comparing, see if
   * this function resets idle time as given from mptr
   * if IDLE_FROM_MSG is undefined, the sense of the flag is reversed.
   * i.e. if the flag is 0, then reset idle time, otherwise don't reset it.
   *
   * - Dianora
   */

#ifdef IDLE_FROM_MSG
  if (IsRegisteredUser(cptr) && mptr->reset_idle)
    from->user->last = CurrentTime;
#else
  if (IsRegisteredUser(cptr) && !mptr->reset_idle)
    from->user->last = CurrentTime;
#endif
  
  /* don't allow other commands while a list is blocked. since we treat
     them specially with respect to sendq. */
  if ((IsDoingList(cptr)) && (*mptr->func != m_list))
      return -1;
  return (*mptr->func)(cptr, from, i, para);
}
Exemplo n.º 30
0
/*
 * m_notice - generic message handler
 */
int m_notice(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  char*           name;
  char*           server;
  int             ret = 0;
  int             i;
  int             j;
  int             fd = 0;
  int             count;
  char            *clean;
  char*           vector[MAXTARGETS];
  char*           temp; /* added by Vadtec 02/25/2008 */
  char*           parv_temp; /* added by Vadtec 02/26/2008 */
  int             found_g = 0; /* added by Vadtec 02/26/2008 */
  int             sent = 0; /* added by Vadtec 03/13/2008 */
  struct Client*  acptr; /* added by Vadtec 02/26/2008 */
  struct Channel* chptr; /* added by Vadtec 02/27/2008 */
  int             isdcc = 0;

  assert(0 != cptr);
  assert(cptr == sptr);

  ClrFlag(sptr, FLAG_TS8);

  if (parc < 2 || EmptyString(parv[1]))
    return send_reply(sptr, ERR_NORECIPIENT, MSG_NOTICE);

  if (parc < 3 || EmptyString(parv[parc - 1]))
    return send_reply(sptr, ERR_NOTEXTTOSEND);

  if (parv[1][0] == '@' && IsChannelPrefix(parv[1][1])) {
    parv[1]++;                        /* Get rid of '@' */
    return m_wallchops(cptr, sptr, parc, parv);
  }

  count = unique_name_vector(parv[1], ',', vector, MAXTARGETS);

  /* Check here to make sure that the client is ours so we dont respond to NOTICES from other server's users. - Vadtec 02/25/2008 */
  /* Also, check to make sure that the notice is actually destined for the *server* and not another user. That way we don't process
     some user saying "what version do you use" to another user via notice. - Vadtec 03/13/2008 */
  if (feature_bool(FEAT_CTCP_VERSIONING) && MyConnect(sptr) && !strcmp(parv[1], cli_name(&me))) {
    /*
     Added by Vadtec 02/25/2008.
     This is so that we can do version checking (and banning) of connecting clients.
     Rules: Only one really. CTCP VERSION is not part of the RFC and therefore clients are not required to respond to
     a request for their version.
     NOTE: If we are lucky enough to have _GNU_SOURCE, we will use it over the standard strstr because its case insensetive.
           This should help against clients that like to send lower case CTCPs from slipping through as easily with only one
           function call.
    */
    for (fd = HighestFd; fd >= 0 && !sent; --fd) { /* Added the "sent" check here so that if we have already sent the notice
                                                      we don't needlessly loop through *all* the users - Vadtec 03/13/2008 */
      if ((acptr = LocalClientArray[fd])) {
        if (!cli_user(acptr))
          continue;

        #ifdef _GNU_SOURCE
        if ((temp = strcasestr(parv[2], "\x01VERSION"))) { /* added \x01 to the string so that it will *only* respond to CTCP version
                                                              replies. Seems redundant, but we dont want the users doing
                                                              /notice <server> version (and getting away with it) - Vadtec 03/13/2008 */
          temp = strchrnul(parv[2], ' '); /* Moved this here to take advantage of strchrnul - added by Vadtec 03/13/2008 */
        #else
        if ((temp = strstr(parv[2], "\x01VERSION")) || (temp = strstr(parv[2], "\x01version"))) { /* See above comment about \x01 - Vadtec */
          temp = strchr(parv[2], ' '); /* Moved this here to take advantage of strchrnul - added by Vadtec 03/13/2008 */
          if (temp == 0)
            temp = parv[2] + strlen(parv[2]); /* This does the same thing as strchrnul - Vadtec */
        #endif
          parv_temp = parv[2];
          j = 0;
          while (j <= (temp - parv[2])) { parv_temp++; j++; }

          clean = normalizeBuffer(parv_temp);
          doCleanBuffer((char *) clean);

          ircd_strncpy(cli_version(sptr), normalizeBuffer(clean), VERSIONLEN);
          sendcmdto_serv_butone(&me, CMD_MARK, cptr, "%s %s :%s", cli_name(sptr), MARK_CVERSION, cli_version(sptr));

          /* Moved here to solve duplicate MARK's if any of the CTCP_* conditions were false 05/13/2009 */
          sent = 1;

          if (feature_bool(FEAT_CTCP_VERSIONING_CHAN)) {
            sprintf(temp, "%s has version \002%s\002", cli_name(sptr), cli_version(sptr));
            /* Announce to channel. */
            if ((chptr = FindChannel(feature_str(FEAT_CTCP_VERSIONING_CHANNAME)))) {
              if (feature_bool(FEAT_CTCP_VERSIONING_USEMSG))
                sendcmdto_channel_butone(&me, CMD_PRIVATE, chptr, cptr, SKIP_DEAF | SKIP_BURST, '\0', "%H :%s", chptr, temp);
              else
                sendcmdto_channel_butone(&me, CMD_NOTICE, chptr, cptr, SKIP_DEAF | SKIP_BURST, '\0', "%H :%s", chptr, temp);
              /* Removed sent=1 from here because it caused the MARK above to be sent
                 more then once if any of the conditions leading here are false 05/13/2009 */
            }
          }

          if (feature_bool(FEAT_CTCP_VERSIONING_KILL)) {
            if ((found_g = find_kill(acptr))) {
              sendto_opmask_butone(0, found_g == -2 ? SNO_GLINE : SNO_OPERKILL,
                                   found_g == -2 ? "G-line active for %s%s" :
                                   "K-line active for %s%s",
                                   IsUnknown(sptr) ? "Unregistered Client ":"",
                                   get_client_name(sptr, SHOW_IP));
              return exit_client_msg(cptr, acptr, &me, "Banned Client: %s", cli_version(acptr));
            }
          }
          else
            return 0;
        }
      }
    }
  }

  for (i = 0; i < count; ++i) {
    name = vector[i];
    if (IsChannelPrefix(*name)) {
      ret = find_fline(cptr, sptr, parv[parc-1], WFFLAG_CHANNOTICE, name);
      if (ret != 0) {
        if (ret == 2)
          return CPTR_KILLED;
        else
          return 0;
      }
    } else {
      #ifdef _GNU_SOURCE
      if ((temp = strcasestr(parv[2], "\001DCC"))) {
        temp = strchrnul(parv[2], ' ');
      #else
      if ((temp = strstr(parv[2], "\001DCC")) || (temp = strstr(parv[2], "\001dcc"))) {
        temp = strchr(parv[2], ' ');
      #endif
        isdcc = 1;
        ret = find_fline(cptr, sptr, parv[parc-1], WFFLAG_DCC, name);
        if (ret != 0) {
          if (ret == 2)
            return CPTR_KILLED;
          else
            return 0;
        }
      }

      if (!isdcc) {
        ret = find_fline(cptr, sptr, parv[parc-1], WFFLAG_NOTICE, name);
        if (ret != 0) {
          if (ret == 2)
            return CPTR_KILLED;
          else
            return 0;
        }
      }
    }
  }
  i = 0;

  for (i = 0; i < count; ++i) {
    name = vector[i];
    /*
     * channel msg?
     */
    if (IsChannelPrefix(*name)) {
      relay_channel_notice(sptr, name, parv[parc - 1], count);
    }
    /*
     * we have to check for the '@' at least once no matter what we do
     * handle it first so we don't have to do it twice
     */
    else if ((server = strchr(name, '@')))
      relay_directed_notice(sptr, name, server, parv[parc - 1]);
    else 
      relay_private_notice(sptr, name, parv[parc - 1]);
  }
  return 0;
}

/*
 * ms_notice - server message handler
 */
int ms_notice(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  char* name;
  char* server;

  ClrFlag(sptr, FLAG_TS8);

  if (parc < 3) {
    /*
     * we can't deliver it, sending an error back is pointless
     */
    return protocol_violation(sptr,"Not enough params for NOTICE");
  }
  name = parv[1];
  /*
   * channel msg?
   */
  if (IsChannelPrefix(*name)) {
    server_relay_channel_notice(sptr, name, parv[parc - 1]);
  }
  /*
   * coming from another server, we have to check this here
   */
  else if ('$' == *name && IsOper(sptr)) {
    server_relay_masked_notice(sptr, name, parv[parc - 1]);
  }
  else if ((server = strchr(name, '@'))) {
    /*
     * XXX - can't get away with not doing everything
     * relay_directed_notice has to do
     */
    relay_directed_notice(sptr, name, server, parv[parc - 1]);
  }
  else {
    server_relay_private_notice(sptr, name, parv[parc - 1]);
  }
  return 0;
}

/*
 * mo_notice - oper message handler
 */
int mo_notice(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  char*           name;
  char*           server;
  int             i;
  int             count;
  char*           vector[MAXTARGETS];
  assert(0 != cptr);
  assert(cptr == sptr);

  ClrFlag(sptr, FLAG_TS8);

  if (parc < 2 || EmptyString(parv[1]))
    return send_reply(sptr, ERR_NORECIPIENT, MSG_NOTICE);

  if (parc < 3 || EmptyString(parv[parc - 1]))
    return send_reply(sptr, ERR_NOTEXTTOSEND);

  if (parv[1][0] == '@' && IsChannelPrefix(parv[1][1])) {
    parv[1]++;                        /* Get rid of '@' */
    return m_wallchops(cptr, sptr, parc, parv);
  }

  count = unique_name_vector(parv[1], ',', vector, MAXTARGETS);

  for (i = 0; i < count; ++i) {
    name = vector[i];
    /*
     * channel msg?
     */
    if (IsChannelPrefix(*name))
      relay_channel_notice(sptr, name, parv[parc - 1], count);

    else if (*name == '$')
      relay_masked_notice(sptr, name, parv[parc - 1]);

    else if ((server = strchr(name, '@')))
      relay_directed_notice(sptr, name, server, parv[parc - 1]);

    else 
      relay_private_notice(sptr, name, parv[parc - 1]);
  }
  return 0;
}