Esempio n. 1
0
/*
 ** send_queued_write
 **      This is called when there is a chance that some output would
 **      be possible. This attempts to empty the send queue as far as
 **      possible, and then if any data is left, a write is rescheduled.
 */
void
send_queued_write(struct Client *to)
{
  int retlen;
#ifndef NDEBUG
  struct hook_io_data hdata;
#endif
  struct dbuf_block *first;
  
  /*
   ** Once socket is marked dead, we cannot start writing to it,
   ** even if the error is removed...
   */
  if (IsDead(to) || IsSendqBlocked(to))
    return;  /* no use calling send() now */

  /* Next, lets try to write some data */
  if (dbuf_length(&to->localClient->buf_sendq))
  {
#ifndef NDEBUG
    hdata.connection = to;
#endif
    do {
      first = to->localClient->buf_sendq.blocks.head->data;
#ifdef HAVE_LIBCRYPTO
      if(IsSSL(to))
      {
        retlen = safe_SSL_write(to, first->data, first->size);
        printf("safe_ssl_write: writing: %s\n", first->data);
        printf("safe_ssl_write: %d written\n", retlen);
        if (retlen <= 0)
         break;
      }
      else
#endif
      if ((retlen = send(to->localClient->fd, first->data,
                         first->size, 0)) <= 0)
        break;

#ifndef NDEBUG
      hdata.data = ((struct dbuf_block *)
                    to->localClient->buf_sendq.blocks.head->data)->data;
      hdata.len = retlen;
      hook_call_event("iosend", &hdata);
#endif
      dbuf_delete(&to->localClient->buf_sendq, retlen);

      /* We have some data written .. update counters */
      to->localClient->sendB += retlen;
      me.localClient->sendB += retlen;
      if (to->localClient->sendB > 1023)
      { 
        to->localClient->sendK += (to->localClient->sendB >> 10);
        to->localClient->sendB &= 0x03ff;        /* 2^10 = 1024, 3ff = 1023 */
      }
      else if (me.localClient->sendB > 1023)
      { 
        me.localClient->sendK += (me.localClient->sendB >> 10);
        me.localClient->sendB &= 0x03ff;
      }
Esempio n. 2
0
bool CListener::Listen() {
    if (!m_uPort || m_pListener) {
        errno = EINVAL;
        return false;
    }

    m_pListener = new CRealListener(*this);

    bool bSSL = false;
#ifdef HAVE_LIBSSL
    if (IsSSL()) {
        bSSL = true;
        m_pListener->SetPemLocation(CZNC::Get().GetPemLocation());
        m_pListener->SetKeyLocation(CZNC::Get().GetKeyLocation());
        m_pListener->SetDHParamLocation(CZNC::Get().GetDHParamLocation());
    }
#endif

    // If e.g. getaddrinfo() fails, the following might not set errno.
    // Make sure there is a consistent error message, not something random
    // which might even be "Error: Success".
    errno = EINVAL;
    return CZNC::Get().GetManager().ListenHost(m_uPort, "_LISTENER",
                                               m_sBindHost, bSSL, SOMAXCONN,
                                               m_pListener, 0, m_eAddr);
}
Esempio n. 3
0
static int
mr_starttls(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
#ifdef HAVE_LIBCRYPTO
	ssl_ctl_t *ctl;
	rb_fde_t *F[2];

	if (!MyConnect(client_p))
		return 0;

	if (IsSSL(client_p))
	{
		sendto_one_numeric(client_p, ERR_STARTTLS, form_str(ERR_STARTTLS), "Nested TLS handshake not allowed");
		return 1;
	}

	if (!ssl_ok || !get_ssld_count())
	{
		sendto_one_numeric(client_p, ERR_STARTTLS, form_str(ERR_STARTTLS), "TLS is not configured");
		return 1;
	}

	if (rb_socketpair(AF_UNIX, SOCK_STREAM, 0, &F[0], &F[1], "STARTTLS ssld session") == -1)
	{
		ilog_error("error creating SSL/TLS socketpair for ssld slave");
		sendto_one_numeric(client_p, ERR_STARTTLS, form_str(ERR_STARTTLS), "Unable to create SSL/TLS socketpair for ssld offload slave");
		return 1;
	}

	s_assert(client_p->localClient != NULL);

	/* clear out any remaining plaintext lines */
	rb_linebuf_donebuf(&client_p->localClient->buf_recvq);

	sendto_one_numeric(client_p, RPL_STARTTLS, form_str(RPL_STARTTLS));
	send_queued(client_p);

	ctl = start_ssld_accept(client_p->localClient->F, F[1], rb_get_fd(F[0]));
	if (ctl != NULL)
	{
		client_p->localClient->F = F[0];
		client_p->localClient->ssl_ctl = ctl;
		SetSSL(client_p);
	}
	else
		return 1;

#else
	sendto_one_numeric(client_p, ERR_STARTTLS, form_str(ERR_STARTTLS), "TLS is not configured");
#endif
	return 0;
}
Esempio n. 4
0
bool CListener::Listen() {
	if (!m_uPort || m_pListener) {
		return false;
	}

	m_pListener = new CRealListener(this);

	bool bSSL = false;
#ifdef HAVE_LIBSSL
	if (IsSSL()) {
		bSSL = true;
		m_pListener->SetPemLocation(CZNC::Get().GetPemLocation());
	}
#endif

	return CZNC::Get().GetManager().ListenHost(m_uPort, "_LISTENER", m_sBindHost, bSSL, SOMAXCONN,
			m_pListener, 0, m_eAddr);
}
Esempio n. 5
0
/*
** deliver_it
**	Attempt to send a sequence of bytes to the connection.
**	Returns
**
**	< 0	Some fatal error occurred, (but not EWOULDBLOCK).
**		This return is a request to close the socket and
**		clean up the link.
**
**	>= 0	No real error occurred, returns the number of
**		bytes actually transferred. EWOULDBLOCK and other
**		possibly similar conditions should be mapped to
**		zero return. Upper level routine will have to
**		decide what to do with those unwritten bytes...
**
**	*NOTE*	alarm calls have been preserved, so this should
**		work equally well whether blocking or non-blocking
**		mode is used...
**
**	*NOTE*	I nuked 'em.  At the load of current ircd servers
**		you can't run with stuff that blocks. And we don't.
*/
int  deliver_it(aClient *cptr, char *str, int len)
{
    int  retval;

    if (IsDead(cptr) || (!IsServer(cptr) && !IsPerson(cptr)
                         && !IsHandshake(cptr)
#ifdef USE_SSL
                         && !IsSSLHandshake(cptr)
#endif

                         && !IsUnknown(cptr)))
    {
        str[len] = '\0';
        sendto_ops
        ("* * * DEBUG ERROR * * * !!! Calling deliver_it() for %s, status %d %s, with message: %s",
         cptr->name, cptr->status, IsDead(cptr) ? "DEAD" : "", str);
        return -1;
    }

#ifdef USE_SSL
    if (IsSSL(cptr) && cptr->ssl != NULL)
    {
        retval = SSL_write(cptr->ssl, str, len);

        if (retval < 0)
        {
            switch (SSL_get_error(cptr->ssl, retval))
            {
            case SSL_ERROR_WANT_READ:
                /* retry later */
                return 0;
            case SSL_ERROR_WANT_WRITE:
                SET_ERRNO(P_EWOULDBLOCK);
                break;
            case SSL_ERROR_SYSCALL:
                break;
            case SSL_ERROR_SSL:
                if (ERRNO == P_EAGAIN)
                    break;
            default:
                return 0;
            }
        }
    }
    else
#endif
        retval = send(cptr->fd, str, len, 0);
    /*
       ** Convert WOULDBLOCK to a return of "0 bytes moved". This
       ** should occur only if socket was non-blocking. Note, that
       ** all is Ok, if the 'write' just returns '0' instead of an
       ** error and errno=EWOULDBLOCK.
       **
       ** ...now, would this work on VMS too? --msa
     */
    if (retval < 0 && (errno == EWOULDBLOCK || errno == EAGAIN ||
                       errno == ENOBUFS))
        retval = 0;

    if (retval > 0)
    {
        cptr->sendB += retval;
        me.sendB += retval;
        if (cptr->sendB > 1023)
        {
            cptr->sendK += (cptr->sendB >> 10);
            cptr->sendB &= 0x03ff;	/* 2^10 = 1024, 3ff = 1023 */
        }
Esempio n. 6
0
/*
 * deliver_it 
 *
 * Attempt to send a sequence of bytes to the connection. 
 * Returns 
 *  < 0     Some fatal error occurred, (but not EWOULDBLOCK). 
 *    his return is a request to close the socket and clean up the link.
 *  >= 0    No real error occurred, returns the number of bytes actually
 *    transferred. EWOULDBLOCK and other similar conditions should be mapped
 *    to zero return.
 *    Upper level routine will have to decide what to do with
 *    those unwritten bytes... 
 * *NOTE*  alarm calls have been preserved, so this should work equally 
 *  well whether blocking or non-blocking mode is used...
 */
int
deliver_it (aClient * client_p, char *str, int len)
{
  int retval;
  aClient *acpt = client_p->acpt;
#ifdef	DEBUGMODE
  writecalls++;
#endif
#ifdef USE_SSL
  if (IsSSL (client_p) && client_p->ssl)
    retval = safe_SSL_write (client_p, str, len);
  else
#endif
    retval = send (client_p->fd, str, len, 0);

  /*
   * Convert WOULDBLOCK to a return of "0 bytes moved". This 
   * should occur only if socket was non-blocking. Note, that all is
   * Ok, if the 'write' just returns '0' instead of an error and
   * errno=EWOULDBLOCK. 
   */
  if (retval < 0 &&
#ifdef _WIN32
      (WSAGetLastError () == WSAEWOULDBLOCK ||
       WSAGetLastError () == WSAENOBUFS)
#else
      (errno == EWOULDBLOCK || errno == EAGAIN || errno == ENOBUFS)
#endif
    )
  {
    retval = 0;
    client_p->flags |= FLAGS_BLOCKED;
    set_fd_flags (client_p->fd, FDF_WANTWRITE);
    return (retval);            /* Just get out now... */
  }
  else if (retval > 0)
  {
    if (client_p->flags & FLAGS_BLOCKED)
    {
      client_p->flags &= ~FLAGS_BLOCKED;
      unset_fd_flags (client_p->fd, FDF_WANTWRITE);
    }
  }

#ifdef DEBUGMODE
  if (retval < 0)
  {
    writeb[0]++;
    Debug ((DEBUG_ERROR, "write error (%s) to %s",
            strerror (errno), client_p->name));
  }
  else if (retval == 0)
    writeb[1]++;
  else if (retval < 16)
    writeb[2]++;
  else if (retval < 32)
    writeb[3]++;
  else if (retval < 64)
    writeb[4]++;
  else if (retval < 128)
    writeb[5]++;
  else if (retval < 256)
    writeb[6]++;
  else if (retval < 512)
    writeb[7]++;
  else if (retval < 1024)
    writeb[8]++;
  else
    writeb[9]++;
#endif
  if (retval > 0)
  {
    client_p->sendB += retval;
    me.sendB += retval;
    if (client_p->sendB > 1023)
    {
      client_p->sendK += (client_p->sendB >> 10);
      client_p->sendB &= 0x03ff;        /* 2^10 = 1024, 3ff = 1023 */
    }
Esempio n. 7
0
TPS_PUBLIC PSHttpResponse *HttpConnection::getResponse(int index, const char *servlet, const char *body) {
    char *host_port;
    char uri[800];
    char *nickname;
    const char *httpprotocol;

    ConnectionInfo *failoverList = GetFailoverList();
    int len = failoverList->ConnectionInfo::GetHostPortListLen(); 
    if (index >= len) {
      index = len - 1; // use the last one
    }
    host_port= (failoverList->GetHostPortList())[index];

    if (IsSSL()) {
        httpprotocol = "https";
    } else {
        httpprotocol = "http";
    }

    PR_snprintf((char *)uri, 800,
      "%s://%s/%s",
      httpprotocol, host_port, servlet);

    RA::Debug("HttpConnection::getResponse", "Send request to host %s servlet %s", host_port, servlet);

    RA::Debug(LL_PER_PDU, "HttpConnection::getResponse", "uri=%s", uri);
    RA::Debug(LL_PER_PDU, "HttpConnection::getResponse", "host_port=%s", host_port);

    char *pPort = NULL;
    char *pPortActual = NULL;


    char hostName[512];

    /*
     * Isolate the host name, account for IPV6 numeric addresses.
     *
     */

    if(host_port)
        strncpy(hostName,host_port,512);

    pPort = hostName;
    while(1)  {
        pPort = strchr(pPort, ':');
        if (pPort) {
            pPortActual = pPort;
            pPort++;
        } else
            break;
    }

    if(pPortActual)
        *pPortActual = '\0';


    /*
    *  Rifle through the values for the host
    */

    PRAddrInfo *ai;
    void *iter;
    PRNetAddr addr;
    int family = PR_AF_INET;

    ai = PR_GetAddrInfoByName(hostName, PR_AF_UNSPEC, PR_AI_ADDRCONFIG);
    if (ai) {
        printf("%s\n", PR_GetCanonNameFromAddrInfo(ai));
        iter = NULL;
        while ((iter = PR_EnumerateAddrInfo(iter, ai, 0, &addr)) != NULL) {
            char buf[512];
            PR_NetAddrToString(&addr, buf, sizeof buf);
            RA::Debug( LL_PER_PDU,
                       "HttpConnection::getResponse: ",
                           "Sending addr -- Msg='%s'\n",
                           buf );
            family = PR_NetAddrFamily(&addr);
            RA::Debug( LL_PER_PDU,
                       "HttpConnection::getResponse: ",
                           "Sending family -- Msg='%d'\n",
                           family );
            break;
        }
        PR_FreeAddrInfo(ai);
        
    }

    PSHttpServer httpserver(host_port, family);
    nickname = GetClientNickname();
    if (IsSSL())
       httpserver.setSSL(PR_TRUE);
    else
       httpserver.setSSL(PR_FALSE);

    PSHttpRequest httprequest(&httpserver, uri, HTTP11, 0);
    if (IsSSL()) {
        httprequest.setSSL(PR_TRUE);
        if (nickname != NULL) {
            httprequest.setCertNickName(nickname);
        } else {
            return NULL;
        }
    } else
        httprequest.setSSL(PR_FALSE);

    httprequest.setMethod("POST");

    if (body != NULL) {
        httprequest.setBody( strlen(body), body);
    }

    httprequest.addHeader( "Content-Type", "application/x-www-form-urlencoded" );
    if (m_headers != NULL) {
        for (int i=0; i<m_headers->Size(); i++) {
            char *name = m_headers->GetNameAt(i);
            httprequest.addHeader(name, m_headers->GetValue(name));
        }
    }

    if (IsKeepAlive())
        httprequest.addHeader( "Connection", "keep-alive" );

    HttpEngine httpEngine;
    return httpEngine.makeRequest(httprequest, httpserver, (PRIntervalTime)GetTimeout(),
      PR_FALSE /*expectChunked*/);
}
Esempio n. 8
0
void do_join(struct Client *cptr, struct Client *sptr, struct JoinBuf *join,
             struct JoinBuf *create, char *chan, char *key, int level)
{
  struct Channel *chptr;
  struct Gline *gline;

  /* BADCHANed channel */
  if ((gline = gline_find(chan, GLINE_BADCHAN | GLINE_EXACT)) &&
      GlineIsActive(gline) && !IsAnOper(sptr)) {
    send_reply(sptr, ERR_BANNEDFROMCHAN, chan);
    return;
  }

  /* Bouncy +L joins */
  if (level > feature_int(FEAT_MAX_BOUNCE)) {
    sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :*** Couldn't join %s ! - Redirection (+L) setting was too bouncy", sptr, chan);
    return;
  }

  if (!(chptr = FindChannel(chan))) {
    if (((chan[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS))
        || strlen(chan) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) {
      send_reply(sptr, ERR_NOSUCHCHANNEL, chan);
      return;
    }

    if (feature_bool(FEAT_CHANNEL_CREATE_IRCOPONLY) && !IsAnOper(sptr) && !IsChannelService(sptr)) {
      send_reply(sptr, ERR_NOSUCHCHANNEL, chan);
      return;
    }

    if (!(chptr = get_channel(sptr, chan, CGT_CREATE)))
      return;

    /* Try to add the new channel as a recent target for the user. */
    if (check_target_limit(sptr, chptr, chptr->chname, 0)) {
      chptr->members = 0;
      destruct_channel(chptr);
      return;
    }

    joinbuf_join(create, chptr, CHFL_CHANOP | CHFL_CHANNEL_MANAGER);
  } else if (find_member_link(chptr, sptr)) {
    return; /* already on channel */
  } else if (check_target_limit(sptr, chptr, chptr->chname, 0)) {
    return;
  } else {
    int flags = CHFL_DEOPPED;
    int err = 0;
    int excepted = 0;
    int exceptkli = 0;
    struct Ban *ban = NULL;

    if (*chptr->mode.redir && (*chptr->mode.redir != '\0')) {
      if (chptr->users >= chptr->mode.limit) {
        if (IsNoLink(sptr))
          send_reply(sptr, ERR_LINKCHAN, chptr->chname, chptr->mode.redir);
        else if (!IsChannelName(chptr->mode.redir) || !strIsIrcCh(chptr->mode.redir))
          send_reply(sptr, ERR_NOSUCHCHANNEL, chptr->mode.redir);
        else {
          send_reply(sptr, ERR_LINKSET, chptr->chname, chptr->chname, chptr->mode.redir);
          do_join(cptr, sptr, join, create, chptr->mode.redir, key, level+1);
        }
        return;
      }
    }

    if (find_ban(sptr, chptr->exceptlist, EBAN_EXCEPTLIST, 0)) {
      if (feature_bool(FEAT_CHMODE_e_CHMODEEXCEPTION))
        exceptkli = 1;
      excepted = 1;
    }

    /* Check Apass/Upass -- since we only ever look at a single
     * "key" per channel now, this hampers brute force attacks. */
    if (feature_bool(FEAT_CHMODE_Z_STRICT) && (chptr->mode.exmode & EXMODE_SSLONLY) && !IsSSL(sptr))
      err = ERR_SSLONLYCHAN;
    else if (key && !strcmp(key, chptr->mode.apass))
      flags = CHFL_CHANOP | CHFL_CHANNEL_MANAGER;
    else if (key && !strcmp(key, chptr->mode.upass))
      flags = CHFL_CHANOP;
    else if (chptr->users == 0 && !chptr->mode.apass[0] && !(chptr->mode.exmode & EXMODE_PERSIST)) {
      /* Joining a zombie channel (zannel): give ops and increment TS. */
      flags = CHFL_CHANOP;
      chptr->creationtime++;
    } else if (IsXtraOp(sptr)) {
      /* XtraOp bypasses all other checks. */
    } else if ((chptr->mode.exmode & EXMODE_SSLONLY) && !IsSSL(sptr))
      err = ERR_SSLONLYCHAN;
    else if (IsInvited(sptr, chptr)) {
      /* Invites bypass these other checks. */
    } else if (*chptr->mode.key && (!key || strcmp(key, chptr->mode.key)) && !exceptkli)
      err = ERR_BADCHANNELKEY;
    else if (*chptr->mode.key && feature_bool(FEAT_FLEXIBLEKEYS) && (key && !strcmp(key, chptr->mode.key))) {
      /* Assume key checked by previous condition was found to be correct
         and allow join because FEAT_FLEXIBLEKEYS was enabled */
    } else if ((chptr->mode.mode & MODE_INVITEONLY) && !exceptkli)
      err = ERR_INVITEONLYCHAN;
    else if (chptr->mode.limit && (chptr->users >= chptr->mode.limit) && !exceptkli)
      err = ERR_CHANNELISFULL;
    else if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
      err = ERR_NEEDREGGEDNICK;
    else if ((chptr->mode.exmode & EXMODE_ADMINONLY) && !IsAdmin(sptr))
      err = ERR_ADMINONLYCHAN;
    else if ((chptr->mode.exmode & EXMODE_OPERONLY) && !IsAnOper(sptr))
      err = ERR_OPERONLYCHAN;
    else if ((ban = find_ban(sptr, chptr->banlist, EBAN_NONE, 0)) && !excepted)
      err = ERR_BANNEDFROMCHAN;

    /* An oper with WALK_LCHAN privilege can join a local channel
     * he otherwise could not join by using "OVERRIDE" as the key.
     * This will generate a HACK(4) notice, but fails if the oper
     * could normally join the channel. */
    if (IsLocalChannel(chptr->chname)
        && HasPriv(sptr, PRIV_WALK_LCHAN)
        && !(flags & CHFL_CHANOP)
        && key && !strcmp(key, "OVERRIDE"))
    {
      switch (err) {
      case 0:
        if (strcmp(chptr->mode.key, "OVERRIDE")
            && strcmp(chptr->mode.apass, "OVERRIDE")
            && strcmp(chptr->mode.upass, "OVERRIDE")) {
          send_reply(sptr, ERR_DONTCHEAT, chptr->chname);
          return;
        }
        break;
      case ERR_INVITEONLYCHAN: err = 'i'; break;
      case ERR_CHANNELISFULL:  err = 'l'; break;
      case ERR_BANNEDFROMCHAN: err = 'b'; break;
      case ERR_BADCHANNELKEY:  err = 'k'; break;
      case ERR_NEEDREGGEDNICK: err = 'r'; break;
      case ERR_ADMINONLYCHAN:  err = 'a'; break;
      case ERR_OPERONLYCHAN:   err = 'O'; break;
      case ERR_SSLONLYCHAN:    err = 'Z'; break;
      default: err = '?'; break;
      }
      /* send accountability notice */
      if (err)
        sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H "
                             "(overriding +%c)", sptr, chptr, err);
      err = 0;
    }

    /* Is there some reason the user may not join? */
    if (err) {
      switch(err) {
        case ERR_NEEDREGGEDNICK:
          send_reply(sptr,
                     ERR_NEEDREGGEDNICK,
                     chptr->chname,
                     feature_str(FEAT_URLREG));
          break;
        default:
          send_reply(sptr, err, chptr->chname);
          break;
      }
      return;
    }

    joinbuf_join(join, chptr, flags);
    if (flags & CHFL_CHANOP) {
      struct ModeBuf mbuf;
      /* Always let the server op him: this is needed on a net with older servers
         because they 'destruct' channels immediately when they become empty without
         sending out a DESTRUCT message. As a result, they would always bounce a mode
         (as HACK(2)) when the user ops himself.
         (There is also no particularly good reason to have the user op himself.)
      */
      modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER);
      modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr,
                          chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL);
      modebuf_flush(&mbuf);
    }
  }

  del_invite(sptr, chptr);

  if (chptr->topic[0]) {
    send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic);
    send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick,
               chptr->topic_time);
  }

  do_names(sptr, chptr, NAMES_ALL|NAMES_EON); /* send /names list */
}