/* Send req and get response */ int http_transaction(http_t *client, http_trans_t *trans) { int rc = 0; ASSERT(client); ASSERT(trans); if (!client->initialized) return RC_HTTP_OBJECT_NOT_INITIALIZED; trans->rsp_len = 0; do { #ifdef ENABLE_SSL if (client->ssl_enabled) { TRY(ssl_send(client, trans->p_req, trans->req_len)); TRY(ssl_recv(client, trans->p_rsp, trans->max_rsp_len, &trans->rsp_len)); } else #endif { TRY(tcp_send(&client->tcp, trans->p_req, trans->req_len)); TRY(tcp_recv(&client->tcp, trans->p_rsp, trans->max_rsp_len, &trans->rsp_len)); } } while (0); trans->p_rsp[trans->rsp_len] = 0; http_response_parse(trans); return rc; }
/* * Send data in buf to the socket in socket_fd. * Return value: * Returns the number of bytes sent, or -1 on failure. */ size_t socket_send(struct socket_in *s, const char *buf) { size_t bytes = 0; #ifdef OPENSSL_ENABLED if(s->ssl != NULL) bytes = ssl_send(s, buf); else #endif /* OPENSSL_ENABLED */ { int temp_bytes; size_t len = strlen(buf); do { if((temp_bytes = send(s->fd, buf+bytes, len-bytes, 0)) == -1) return -1; bytes += temp_bytes; } while(bytes < len); } return(bytes); }
/* ** Send content over the wire. */ void transport_send(Blob *toSend){ char *z = blob_buffer(toSend); int n = blob_size(toSend); transport.nSent += n; if( g.urlIsSsh ){ int sent; sent = fwrite(z, 1, n, sshOut); fflush(sshOut); /* printf("sent %d of %d bytes\n", sent, n); fflush(stdout); */ }else if( g.urlIsHttps ){ #ifdef FOSSIL_ENABLE_SSL int sent; while( n>0 ){ sent = ssl_send(0, z, n); /* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */ if( sent<=0 ) break; n -= sent; } #endif }else if( g.urlIsFile ){ fwrite(z, 1, n, transport.pFile); }else{ int sent; while( n>0 ){ sent = socket_send(0, z, n); /* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */ if( sent<=0 ) break; n -= sent; } } }
/* * Sends AES-CBC-128 bit encrypted file to the receiver * SSL *conn -> The SSL connection of the recipient * const char *fname -> The name of the file to send * const unsigned char *key -> The already instantiated AES Key for decryption * const unsigned char *iv -> The initialization vector for CBC that was * received from the sender * returns the total amount of bytes sent and encrypted */ ssize_t crypto_send_file(SSL *conn, const char *fname, const unsigned char *key, const unsigned char *iv) { int len, ciph_len=0, first=0; ssize_t total = 0; unsigned char plaintxt[BUFFSIZE]; unsigned char ciphtxt[BUFFSIZE]; FILE *file; if((file = fopen(fname, "rb")) == nullptr) return FILE_NOT_FOUND; EVP_CIPHER_CTX cntx; EVP_CipherInit(&cntx, EVP_aes_128_cbc(), key, iv, ENCRYPT); memcpy(plaintxt, iv, IV_LEN); while ((len = (int)fread(plaintxt+(first?0:16), sizeof(char), sizeof(ciphtxt)-(first?0:16)-1, file)) > 0) { EVP_CipherUpdate(&cntx, ciphtxt+1,&ciph_len,plaintxt,len+(first?0:16)); ssl_send(conn, (char *)ciphtxt, (size_t)ciph_len+1); /* Last transmission of the file */ if(len < BUFFSIZE-1) { if(!first && len < BUFFSIZE-16-1) break; } first++; } ERRCHK(len, ==, -1, "send() failed"); EVP_CipherFinal(&cntx, ciphtxt+1, &ciph_len); ssl_send(conn, (char *)ciphtxt, (size_t)ciph_len+1); SENDFIN(conn); ERRCHK(len, ==, -1, "send() failed"); EVP_CIPHER_CTX_cleanup(&cntx); fclose(file); return total; seterrhandle(err); EVP_CIPHER_CTX_cleanup(&cntx); die_with_err(errmsg); return 1; }
/* * Sends Plain Text file to the receiver * SSL *conn -> The SSL connection of the recipient * const char *fname -> The name of the file to send * returns the total amount of bytes sent and encrypted */ ssize_t ssl_send_file(SSL *conn, const char *fname) { ssize_t len, total = 0; unsigned char buf[BUFFSIZE]; buf[0] = 'T'; FILE *file; if((file = fopen(fname, "rb")) == nullptr) return FILE_NOT_FOUND; while ((len = (int)fread(buf+1, sizeof(char), sizeof(buf)-1, file)) > 0) { total += (len = ssl_send(conn, (char *)buf, (size_t)len+1))-1; if (len < 0) break; } SENDACK(conn); fclose(file); if(len < 0) { perror("ssl_send() failed"); return -1; } return total; }
static ssize_t ssl_stream_file(IOBuf *iob, int fd, off_t len) { ssize_t sent = 0; off_t total = 0; ssize_t amt = 0; ssize_t tosend = 0; int conn_fd = IOBuf_fd(iob); char buff[1024]; for(total = 0; fdwait(conn_fd, 'w') == 0 && total < len; total += tosend) { tosend = pread(fd, buff, sizeof(buff), total); check_debug(tosend > 0, "Came up short in reading file %d\n", fd); // We do this in case the file somehow lengthened on us. In general, // it shouldn't happen. if(tosend + total > len) tosend = len - total; sent = 0; while(sent < tosend) { amt = ssl_send(iob, buff, tosend); check_debug(amt > 0, "ssl_send failed in ssl_stream_file with " "return code %zd", amt); sent += amt; } check(Register_write(iob->fd, sent) != -1, "Failed to record write, must have died."); } check(total <= len, "Wrote way too much, wrote %d but size was %zd", (int)total, len); check(total == len, "Sent other than expected, sent: %d, but expected: %zd", (int)total, len); return total; error: return -1; }
/* Send req and get response */ int http_transaction(http_t *client, http_trans_t *trans) { int rc = 0; ASSERT(client); ASSERT(trans); if (!client->initialized) return RC_HTTP_OBJECT_NOT_INITIALIZED; trans->rsp_len = 0; do { TRY(ssl_send(client, trans->req, trans->req_len)); TRY(ssl_recv(client, trans->rsp, trans->max_rsp_len, &trans->rsp_len)); } while (0); trans->rsp[trans->rsp_len] = 0; http_response_parse(trans); return rc; }
/** Send a char buffer to the client. Traffic throttling is handled here. */ static int send_to_client(t_session *session, const char *buffer, int size) { /* HELP!! No socket open. */ if (session->socket_open == false) { return -1; } else if ((buffer == NULL) || (size <= 0)) { return 0; } int bytes_sent = 0, total_sent = 0, can_send, rest; time_t new_time; if (session->directory != NULL) { if (session->directory->session_speed > 0) { session->throttle = session->directory->session_speed; } } do { rest = size - total_sent; if (session->throttle > 0) { do { new_time = time(NULL); if (session->throttle_timer < new_time) { session->bytecounter = 0; session->throttle_timer = new_time; } can_send = session->throttle - session->bytecounter; if (can_send <= 0) { usleep(10000); } } while (can_send <= 0); if (can_send > rest) { can_send = rest; } } else { can_send = rest; } #ifdef HAVE_SSL if (session->binding->use_ssl) { if ((bytes_sent = ssl_send(session->ssl_data, (char*)(buffer + total_sent), can_send)) <= 0) { bytes_sent = -1; } } else #endif if ((bytes_sent = send(session->client_socket, (char*)(buffer + total_sent), can_send, 0)) <= 0) { bytes_sent = -1; } /* Handle read result */ if (bytes_sent == -1) { if (errno != EINTR) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { log_error(session, "send timeout"); } else if ((errno != EPIPE) && (errno != ECONNRESET)) { log_error(session, "socket error"); } close_socket(session); session->keep_alive = false; return -1; } } else { total_sent += bytes_sent; session->bytecounter += bytes_sent; } } while (total_sent < size); return 0; }
void cmd (void) { SECURITY_ATTRIBUTES sa; PROCESS_INFORMATION pi; STARTUPINFO si; OVERLAPPED lap; HANDLE in[2], out[2]; DWORD p, e; sa.nLength = sizeof (SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; evt[stdout_evt = evt_cnt++] = CreateEvent (NULL, TRUE, TRUE, NULL); if (CreatePipe (&in[R_PIPE], &in[W_PIPE], &sa, 0)) { out[R_PIPE] = CreateNamedPipe ("\\\\.\\pipe\\0", PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 0, 0, 0, &sa); if (out[R_PIPE] != INVALID_HANDLE_VALUE) { out[W_PIPE] = CreateFile ("\\\\.\\pipe\\0", GENERIC_WRITE, 0, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); if (out[W_PIPE] != INVALID_HANDLE_VALUE) { ZeroMemory (&si, sizeof (si)); ZeroMemory (&pi, sizeof (pi)); SetHandleInformation (in[W_PIPE], HANDLE_FLAG_INHERIT, 0); SetHandleInformation (out[R_PIPE], HANDLE_FLAG_INHERIT, 0); si.cb = sizeof (si); si.hStdInput = in[R_PIPE]; si.hStdError = out[W_PIPE]; si.hStdOutput = out[W_PIPE]; si.dwFlags = STARTF_USESTDHANDLES; if (CreateProcess (NULL, "cmd", NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { evt[proc_evt = evt_cnt++] = pi.hProcess; ZeroMemory (&lap, sizeof (lap)); lap.hEvent = evt[stdout_evt]; p=0; do { e=wait_evt(); if (e==ctrl_evt) { printf (" [ CTRL+C received\n"); break; } if (e==proc_evt) { printf (" [ cmd.exe terminated\n"); break; } if (e == -1) break; // is this socket event? if (e == sck_evt) { if (ReadDecrypt () != SEC_E_OK) break; WriteFile (in[W_PIPE], pbDataIn, cbDataIn, &cbDataIn, 0); p--; // we're ready to read again. } else // data from cmd.exe? if (e == stdout_evt) { if (p==0) // still waiting for previous read to complete? { if (!ReadFile (out[R_PIPE], pbDataOut, cbBufferLen, &cbDataOut, &lap)) { if (GetLastError() != ERROR_IO_PENDING) { // problem... break; } else { p++; } } else { p++; } } else { if (!GetOverlappedResult (out[R_PIPE], &lap, &cbDataOut, FALSE)) { // problem... break; } if (cbDataOut != 0) { if (ssl_send() != SEC_E_OK) break; p--; } } } } while (1); TerminateProcess (pi.hProcess, 0); CloseHandle (pi.hThread); CloseHandle (pi.hProcess); evt_cnt--; } CloseHandle (out[W_PIPE]); } CloseHandle (out[R_PIPE]); } CloseHandle (in[W_PIPE]); CloseHandle (in[R_PIPE]); } CloseHandle (evt[stdout_evt]); evt_cnt--; }
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; }
/* Send a char buffer to the client. Traffic throttling is handled here. */ static int send_to_client(t_session *session, const char *buffer, int size) { int bytes_sent = 0, total_sent = 0, can_send, rest; time_t new_time; /* Send buffer to browser. */ if (session->socket_open == false) { return -1; } else if ((buffer == NULL) || (size <= 0)) { return 0; } if (session->directory != NULL) { if (session->directory->session_speed > 0) { session->throttle = session->directory->session_speed; } } do { rest = size - total_sent; if (session->throttle > 0) { do { new_time = time(NULL); if (session->throttle_timer < new_time) { session->bytecounter = 0; session->throttle_timer = new_time; } can_send = session->throttle - session->bytecounter; if (can_send <= 0) { usleep(10000); } } while (can_send <= 0); if (can_send > rest) { can_send = rest; } } else { can_send = rest; } #ifdef ENABLE_SSL if (session->binding->use_ssl) { if ((bytes_sent = ssl_send(&(session->ssl_context), (char*)(buffer + total_sent), can_send)) <= 0) { bytes_sent = -1; } } else #endif if ((bytes_sent = send(session->client_socket, (char*)(buffer + total_sent), can_send, 0)) <= 0) { bytes_sent = -1; } /* Handle read result */ if (bytes_sent == -1) { if (errno != EINTR) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { log_error(session, "send timeout"); } else if ((errno != EPIPE) && (errno != ECONNRESET)) { log_error(session, "error while sending response"); } close_socket(session); session->keep_alive = false; session->error_cause = ec_SOCKET_WRITE_ERROR; return -1; } } else { total_sent += bytes_sent; session->bytecounter += bytes_sent; } } while (total_sent < size); #ifdef ENABLE_TOMAHAWK increment_transfer(TRANSFER_SEND, total_sent); #endif return 0; }