/* ** 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; }
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); }
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; }
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); }
/* ** 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 */ }
/* * 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 */ }
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*/); }
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 */ }