/** * z_proxy_stack_prepare_streams: * @self: ZProxy instance * @downpair: * @uppair: * **/ static gboolean z_proxy_stack_prepare_streams(ZProxy *self, gint *downpair, gint *uppair) { z_proxy_enter(self); if (socketpair(AF_UNIX, SOCK_STREAM, 0, downpair) == -1) { /*LOG This message indicates that stacking a child proxy failed, because creating an AF_UNIX domain socketpair failed on the client side. */ z_proxy_log(self, CORE_ERROR, 1, "Error creating client socketpair for stacked proxy; error='%s'", g_strerror(errno)); z_proxy_leave(self); return FALSE; } else if (socketpair(AF_UNIX, SOCK_STREAM, 0, uppair) == -1) { close(downpair[0]); close(downpair[1]); /*LOG This message indicates that stacking a child proxy failed, because creating an AF_UNIX domain socketpair failed on the server side. */ z_proxy_log(self, CORE_ERROR, 1, "Error creating server socketpair for stacked proxy; error='%s'", g_strerror(errno)); z_proxy_leave(self); return FALSE; } z_proxy_leave(self); return TRUE; }
static gboolean z_proxy_ssl_host_iface_check_wildcard(ZProxy *s, const gchar *host_name, const gchar *pattern) { gchar **pattern_parts, **hostname_parts; gboolean success = FALSE; gint i; z_proxy_log(s, CORE_DEBUG, 6, "Checking certificate subject; host='%s', pattern='%s'", host_name, pattern); pattern_parts = g_strsplit(pattern, ".", 0); hostname_parts = g_strsplit(host_name, ".", 0); for (i = 0; pattern_parts[i]; i++) { if (!hostname_parts[i]) { /* number of dot separated entries is not the same in the hostname and the pattern spec */ goto exit; } if (!g_pattern_match_simple(pattern_parts[i], hostname_parts[i])) goto exit; } if (!hostname_parts[i]) /* if hostname_parts doesn't continue beyond pattern_parts */ success = TRUE; exit: g_strfreev(pattern_parts); g_strfreev(hostname_parts); if (!success) { z_proxy_log(s, CORE_VIOLATION, 2, "Certificate subject does not match; host='%s', pattern='%s'", host_name, pattern); } return success; }
/** * telnet_process_command: * @self: * @ep: * * * * Returns: * */ static guint telnet_process_command(TelnetProxy *self, guint ep) { ZPolicyObj *res = NULL; guint option_needed; gchar cmd_str[5]; guint ret_status; z_proxy_enter(self); /* * allow commands defined in RFC 854 * these are important, and must be implemented */ /* NOTE: this triggers a warning in gcc as the second part of the * condition is always TRUE as guchar is always less-or-equal than 255, * this is true, but I leave the condition intact as in the possible case * command is changed to int the condition might be perfectly valid */ if (self->command[ep] >= 240) z_proxy_return(self, TELNET_CHECK_OK); /* * allow negotiated commands * these were allowed during a negotiation */ g_snprintf(cmd_str, sizeof(cmd_str), "%hhu", self->command[ep]); z_policy_lock(self->super.thread); res = g_hash_table_lookup(self->negotiation, cmd_str); if (res != NULL) { if (!z_policy_var_parse(res, "i", &option_needed)) { z_proxy_log(self, TELNET_POLICY, 2, "Value in negotiation table bad; command='%d'", self->command[ep]); z_policy_unlock(self->super.thread); z_proxy_return(self, TELNET_CHECK_REJECT); } z_proxy_trace(self, "Changed needed negotiated option; command='%s', option='%d'", cmd_str, option_needed); } else { option_needed = self->command[ep]; } z_policy_unlock(self->super.thread); ret_status = TELNET_CHECK_REJECT; if (option_needed == 255) { ret_status = TELNET_CHECK_OK; } else if (option_needed > 255) { z_proxy_log(self, TELNET_POLICY, 2, "Value in negotation table out of range; command='%d', value='%d'", self->command[ep], option_needed); } else { z_proxy_trace(self, "Option state check; option='%d', state='%d:%d'", option_needed, self->options[option_needed][ep], self->options[option_needed][OTHER_EP(ep)]); if (self->options[option_needed][ep] & (SENT_WILL | GOT_DO)) ret_status = TELNET_CHECK_OK; } /* reject everything else */ z_proxy_return(self, ret_status); }
/** * finger_query_policy: * @self: FingerProxy instance * * Check the policy about the current request. **/ static gboolean finger_query_policy(FingerProxy *self) { char *errmsg = "Policy violation, request denied.\r\n"; gsize bytes_written; gint res; z_proxy_enter(self); z_policy_lock(self->super.thread); res = z_policy_event(self->super.handler, "fingerRequest", z_policy_var_build("(ss)", self->username->str, self->hostnames->str), self->super.session_id); switch (res) { case FINGER_REQ_UNSPEC: case FINGER_REQ_REJECT: case FINGER_REQ_ABORT: /*LOG This message is about administrator decision to reject the finger session. */ z_proxy_log(self, FINGER_POLICY, 2, "Policy violation, abort session;"); z_stream_write(self->super.endpoints[EP_CLIENT], errmsg, strlen(errmsg), &bytes_written, NULL); /* fallthrough */ case FINGER_REQ_DROP: if (res == ZV_DROP) { /*LOG This message is about administrator decision to drop finger session. */ z_proxy_log(self, FINGER_POLICY, 2, "Policy violation, drop session;"); } z_policy_unlock(self->super.thread); z_proxy_return(self, FALSE); case FINGER_REQ_ACCEPT: default: break; } z_policy_unlock(self->super.thread); z_proxy_return(self, TRUE); }
/** * http_ftp_login: * @self: HttpProxy instance * @user: username to log in with * @passwd: password for @user * * Log in to the FTP server using credentials in @user and @passwd. **/ static gboolean http_ftp_login(HttpProxy *self, const gchar *user, const gchar *passwd) { gchar response_msg[1024]; gint status; if (!http_ftp_communicate(self, "USER", user, &status, response_msg, sizeof(response_msg))) return FALSE; if (status == 230) { /* no password required */ return TRUE; } else if (status != 331) { /* no password required */ g_string_sprintf(self->error_info, "Unhandled status code returned to login request (%d, %s)", status, response_msg); /*LOG This message indicates that the FTP server returned an unknown status code in response to our login request. */ z_proxy_log(self, HTTP_ERROR, 4, "FTP server returned an unhandled status code for the login request; ftp_status='%d'", status); return FALSE; } if (!http_ftp_communicate(self, "PASS", passwd, &status, response_msg, sizeof(response_msg))) return FALSE; if (status == 230) { /* logged in */ return TRUE; } else { g_string_sprintf(self->error_info, "Error logging in (%d, %s)", status, response_msg); /*LOG This message indicates that the FTP refused our authentication attempt. */ z_proxy_log(self, HTTP_ERROR, 4, "Error logging in; user='******', ftp_status='%d', ftp_response='%s'", user, status, response_msg); return FALSE; } }
guint Pop3ParseAPOP(Pop3Proxy *self) { gchar username[self->max_username_length + 1]; guint i; gchar *buf = self->command_param->str; z_proxy_enter(self); for (i = 0; i < self->max_username_length && buf[i] != 0 && buf[i] != ' '; i++) username[i] = buf[i]; username[i] = 0; if (buf[i] != ' ') { /*LOG This message indicates that the username parameter is too long or the digest missing after the username and Zorp rejects the request. */ z_proxy_log(self, POP3_REQUEST, 3, "The username parameter is too long or the digest parameter is missing; req='APOP', req_prm='%s'", self->command_param->str); z_proxy_return(self, POP3_REQ_REJECT); } g_string_assign(self->username, username); while (buf[i] == 32) i++; buf = &buf[i]; for (i = 0; i < 32 && buf[i] != 0 && ((buf[i] >= '0' && buf[i] <= '9') || (buf[i] >= 'a' && buf[i] <= 'f') || (buf[i] >= 'A' && buf[i] <= 'F')); i++) ; if (i < 32) { /*LOG This message indicates that the MD5 digest parameter of the request is invalid and Zorp rejects the request. */ z_proxy_log(self, POP3_REQUEST, 3, "Error parsing the MD5 digest; req='APOP', req_prm='%s'", self->command_param->str); z_proxy_return(self, POP3_REQ_REJECT); } z_proxy_return(self, POP3_REQ_ACCEPT); }
guint ftp_policy_feature_hash_search(struct _FtpProxy *self, const gchar *feature) { ZPolicyObj *res; guint verdict; gboolean valid; z_proxy_enter(self); res = g_hash_table_lookup(self->policy_features, feature); if (!res) res = g_hash_table_lookup(self->policy_features, "*"); if (!res) { /*LOG This message indicates that the policy does not contain any setting for the given feature and Zorp drops the feature. Check the 'features' attribute. */ z_proxy_log(self, FTP_POLICY, 5, "Policy does not contain this feature, dropping; feature='%s'", feature); z_proxy_return(self, FTP_FEATURE_DROP); } z_policy_lock(self->super.thread); valid = ftp_hash_get_type(res, &verdict); z_policy_unlock(self->super.thread); if (!valid) { /*LOG This message indicates that the policy type is invalid for the given feature and thus Zorp drops the feature. */ z_proxy_log(self, FTP_POLICY, 1, "Policy value invalid; feature='%s'", feature); z_proxy_return(self, FTP_FEATURE_DROP); } z_proxy_return(self, verdict); }
/** * z_transfer2_timeout: * @user_data: ZTransfer2 instance passed as a generic pointer * * This function is a timeout-callback registered to terminate the * transfer loop when a specified time elapses. **/ static gboolean z_transfer2_timeout(gpointer user_data) { ZTransfer2 *self = Z_CAST(user_data, ZTransfer2); z_proxy_enter(self->owner); /*LOG This message indicates the data transfer timed out. */ z_proxy_log(self->owner, CORE_ERROR, 3, "Data transfer timed out; timeout='%ld'", self->timeout); z_transfer2_update_status(self, ZT2S_TIMEDOUT+ZT2S_FAILED+ZT2S_FINISHED, TRUE); z_proxy_leave(self->owner); return FALSE; }
static inline void z_transfer2_update_status(ZTransfer2 *self, guint32 status_bit, gint enable) { guint32 old_mask = self->status & ZT2S_EOF_BITS; if (enable) self->status |= status_bit; else self->status &= ~status_bit; /*LOG This message reports that the data-transfer to or from some endpoint is closed. */ z_proxy_log(self->owner, CORE_DEBUG, 7, "Eofmask is updated; old_mask='%04x', eof_mask='%04x'", old_mask, self->status & ZT2S_EOF_BITS); }
guint Pop3ParseNoarg(Pop3Proxy *self) { z_proxy_enter(self); if (self->command_param->len > 0) /*LOG This message indicates that the request must not have any parameter and Zorp is going to drop the parameter. */ z_proxy_log(self, POP3_REQUEST, 4, "Dropping request parameter, no parameter allowed; req='%s', req_prm='%s'", self->command->str, self->command_param->str); g_string_assign(self->command_param, ""); z_proxy_return(self, POP3_REQ_ACCEPT); }
static gboolean anypy_stream_init(AnyPyProxy *self) { z_proxy_enter(self); if (!self->super.endpoints[EP_CLIENT] || !self->super.endpoints[EP_SERVER]) { z_proxy_log(self, ANYPY_ERROR, 2, "Server side not yet connected, unable to init streams;"); z_proxy_leave(self); return FALSE; } self->super.endpoints[EP_CLIENT] = z_stream_push(self->super.endpoints[EP_CLIENT], z_stream_line_new(NULL, self->max_line_length[EP_CLIENT], ZRL_EOL_CRLF)); self->super.endpoints[EP_SERVER] = z_stream_push(self->super.endpoints[EP_SERVER], z_stream_line_new(NULL, self->max_line_length[EP_SERVER], ZRL_EOL_CRLF)); z_proxy_leave(self); return TRUE; }
/** * telnet_process_opneg: * @self: * @ep: * * * * Returns: * */ static guint telnet_process_opneg(TelnetProxy *self, guint ep) { guint res; z_proxy_enter(self); /* * ask policy if option is enabled */ res = telnet_policy_option(self); if (res == TELNET_CHECK_OK) { switch (self->command[ep]) { case TELNET_CMD_WILL: /* set flag which means this side has sent a WILL */ self->options[self->opneg_option[ep]][ep] |= SENT_WILL; break; case TELNET_CMD_WONT: /* set flag which means this side has sent a WONT */ self->options[self->opneg_option[ep]][ep] &= ~GOT_DO; break; case TELNET_CMD_DO: /* set the other side's flag, indicating that * its WILL was accepted by the other side */ self->options[self->opneg_option[ep]][OTHER_EP(ep)] |= GOT_DO; break; case TELNET_CMD_DONT: /* clear the other side's WILL flag, indicating that * its WILL was refused */ self->options[self->opneg_option[ep]][OTHER_EP(ep)] &= ~SENT_WILL; break; default: z_proxy_log(self, TELNET_VIOLATION, 2, "Unknown command; command='%d'", self->command[ep]); break; } } z_proxy_return(self, res); }
/** * z_transfer2_timed_progress: * @user_data: ZTransfer2 instance passed as a generic pointer * * This function is the timeout callback registered to be called when the * interval specified by the timeout_progress variable elapses. This is * used for example to generate NOOPs in SMTP while transfer is downloading * data to the virus checking proxy. **/ static gboolean z_transfer2_timed_progress(gpointer user_data) { ZTransfer2 *self = Z_CAST(user_data, ZTransfer2); z_proxy_enter(self->owner); if (!z_transfer2_progress(self)) { /*LOG This message indicates that the data-transfer is interrupted by a timed progress callback and Zorp is closing the date-transfer channels. */ z_proxy_log(self->owner, CORE_ERROR, 3, "Data transfer interrupted by progress;"); z_transfer2_update_status(self, ZT2S_FAILED+ZT2S_FINISHED, TRUE); } z_timeout_source_set_timeout(self->progress_source, self->progress_interval); z_proxy_leave(self->owner); return TRUE; }
static gboolean z_proxy_stack_tuple(ZProxy *self, ZPolicyObj *tuple, ZStackedProxy **stacked, ZPolicyDict *stack_info_dict) { guint stack_method; ZPolicyObj *arg = NULL; gboolean success = FALSE; if (!z_policy_tuple_get_verdict(tuple, &stack_method) || z_policy_seq_length(tuple) < 2) goto invalid_tuple; arg = z_policy_seq_getitem(tuple, 1); switch (stack_method) { case Z_STACK_PROXY: if (z_policy_seq_length(tuple) != 2) goto invalid_tuple; success = z_proxy_stack_proxy(self, arg, stacked, stack_info_dict); break; case Z_STACK_PROGRAM: if (!z_policy_str_check(arg)) goto invalid_tuple; success = z_proxy_stack_program(self, z_policy_str_as_string(arg), stacked); break; default: break; } exit: if (arg) z_policy_var_unref(arg); return success; invalid_tuple: z_proxy_log(self, CORE_POLICY, 1, "Invalid stack tuple;"); success = FALSE; goto exit; }
guint Pop3ParsePASS(Pop3Proxy *self) { gchar password[self->max_password_length + 1]; z_proxy_enter(self); if (self->command_param->len <= self->max_password_length) { g_strlcpy(password, self->command_param->str, self->max_password_length + 1); g_string_assign(self->password, password); z_proxy_return(self, POP3_REQ_ACCEPT); } /*LOG This message indicates that the password parameter of the request is too long and Zorp rejects the request. Check the 'max_password_length' attribute. */ z_proxy_log(self, POP3_POLICY, 2, "Password is too long; max_password_length='%d', password_length='%d'", self->max_password_length, (gint) self->command_param->len); z_proxy_return(self, POP3_REQ_REJECT); }
guint Pop3ParseUSER(Pop3Proxy *self) { gchar username[self->max_username_length + 1]; z_proxy_enter(self); if (self->command_param->len <= self->max_username_length) { g_strlcpy(username, self->command_param->str, self->max_username_length + 1); g_string_assign(self->username, username); z_proxy_return(self, POP3_REQ_ACCEPT); } /*LOG This message indicates that the username parameter of the request is too long and Zorp rejects the request. Check the 'max_username_length' attribute. */ z_proxy_log(self, POP3_POLICY, 2, "Username is too long; max_username_length='%d', username_length='%" G_GSIZE_FORMAT "', username='******'", self->max_username_length, self->command_param->len, self->command_param->str); z_proxy_return(self, POP3_REQ_REJECT); }
/** * telnet_check_suboption: * @self: * @ep: * * * * Returns: * */ static guint telnet_check_suboption(TelnetProxy *self, guint ep) { guint res; TelnetOptionFunction check_func; ZIOBuffer *sbuf = &self->suboptions[ep]; gchar buf[TELNET_BUFFER_SIZE + 1]; guint i, j; z_proxy_enter(self); /* check if allowed in this session */ if (!(self->options[self->opneg_option[ep]][OTHER_EP(ep)] & (SENT_WILL | GOT_DO)) && !(self->options[self->opneg_option[ep]][ep] & (SENT_WILL | GOT_DO))) { z_proxy_log(self, TELNET_VIOLATION, 3, "Option not allowed in the session; option='%d'", self->opneg_option[ep]); z_proxy_return(self, TELNET_CHECK_ABORT); } /* check if valid */ if ((check_func = self->telnet_options[self->opneg_option[ep]]) == NULL) { /* option has no suboption check function */ /* copy suboption negotiation buffer into policy_value */ for (j = 0, i = sbuf->ofs; i < sbuf->end; j++, i++) buf[j] = sbuf->buf[i]; g_string_assign(self->policy_name, ""); g_string_assign(self->policy_value, buf); /* call policy check */ res = telnet_policy_suboption(self, (guchar) buf[0], "", buf); } else { /* call check function, and check function calls policy */ res = check_func(self, ep); } z_proxy_return(self, res); }
/** * z_proxy_stack_proxy: * @self: proxy instance * @proxy_class: a Python class to be instantiated as the child proxy * * This function is called to start a child proxy. **/ gboolean z_proxy_stack_proxy(ZProxy *self, ZPolicyObj *proxy_class, ZStackedProxy **stacked, ZPolicyDict *stack_info) { int downpair[2], uppair[2]; ZPolicyObj *res, *client_stream, *server_stream, *stack_info_obj; ZStream *tmpstream; ZStream *client_upstream, *server_upstream; z_proxy_enter(self); if (proxy_class == z_policy_none) { z_policy_var_unref(proxy_class); z_proxy_leave(self); return FALSE; } if (!z_proxy_stack_prepare_streams(self, downpair, uppair)) { z_policy_var_unref(proxy_class); z_proxy_leave(self); return FALSE; } /*LOG This message reports that Zorp is about to stack a proxy class with the given fds as communication channels. */ z_proxy_log(self, CORE_DEBUG, 6, "Stacking subproxy; client='%d:%d', server='%d:%d'", downpair[0], downpair[1], uppair[0], uppair[1]); tmpstream = z_stream_fd_new(downpair[1], ""); client_stream = z_policy_stream_new(tmpstream); z_stream_unref(tmpstream); tmpstream = z_stream_fd_new(uppair[1], ""); server_stream = z_policy_stream_new(tmpstream); z_stream_unref(tmpstream); if (stack_info) { stack_info_obj = z_policy_struct_new(stack_info, Z_PST_SHARED); } else { Py_XINCREF(Py_None); stack_info_obj = Py_None; } res = z_policy_call(self->handler, "stackProxy", z_policy_var_build("(OOOO)", client_stream, server_stream, proxy_class, stack_info_obj), NULL, self->session_id); z_policy_var_unref(client_stream); z_policy_var_unref(server_stream); z_policy_var_unref(stack_info_obj); if (!res || res == z_policy_none || !z_policy_proxy_check(res)) { z_proxy_log(self, CORE_ERROR, 3, "Error stacking subproxy;"); close(downpair[0]); close(downpair[1]); close(uppair[0]); close(uppair[1]); z_policy_var_unref(res); z_proxy_leave(self); return FALSE; } client_upstream = z_stream_fd_new(downpair[0], ""); server_upstream = z_stream_fd_new(uppair[0], ""); *stacked = z_stacked_proxy_new(client_upstream, server_upstream, NULL, self, z_policy_proxy_get_proxy(res), 0); z_policy_var_unref(res); z_proxy_leave(self); return TRUE; }
/** * z_proxy_stack_program: * @self: proxy instance * @program: path to program to execute * * This function is called to start a program as a filtering child proxy. **/ static gboolean z_proxy_stack_program(ZProxy *self, const gchar *program, ZStackedProxy **stacked) { int downpair[2], uppair[2], controlpair[2]; pid_t pid; z_proxy_enter(self); if (!z_proxy_stack_prepare_streams(self, downpair, uppair)) { z_proxy_leave(self); return FALSE; } if (socketpair(AF_UNIX, SOCK_STREAM, 0, controlpair) < 0) { close(downpair[0]); close(downpair[1]); close(uppair[0]); close(uppair[1]); close(controlpair[0]); close(controlpair[1]); /*LOG This message indicates that stacking a child proxy failed, because creating an AF_UNIX domain socketpair failed for the control channel. */ z_proxy_log(self, CORE_ERROR, 1, "Error creating control socketpair for stacked proxy; error='%s'", g_strerror(errno)); z_proxy_leave(self); return FALSE; } /*LOG This message reports that Zorp is about to stack a program with the given fds as communication channels. */ z_proxy_log(self, CORE_DEBUG, 6, "Stacking program; client='%d:%d', server='%d:%d', control='%d:%d', program='%s'", downpair[0], downpair[1], uppair[0], uppair[1], controlpair[0], controlpair[1], program); pid = fork(); if (pid == 0) { int i; /* child */ dup2(downpair[1], 0); dup2(uppair[1], 1); /* standard error is inherited */ dup2(controlpair[1], 3); for (i = 4; i < sysconf(_SC_OPEN_MAX); i++) close(i); execl("/bin/sh", "/bin/sh", "-c", program, NULL); fprintf(stderr, "Error starting program; program='%s', error='%s'", program, strerror(errno)); exit(127); } else if (pid < 0) { z_proxy_log(self, CORE_ERROR, 2, "Program stacking failed, fork returned error; program='%s', error='%s'", program, g_strerror(errno)); close(downpair[0]); close(downpair[1]); close(uppair[0]); close(uppair[1]); close(controlpair[0]); close(controlpair[1]); z_proxy_leave(self); return FALSE; } close(downpair[1]); close(uppair[1]); close(controlpair[1]); if (!z_proxy_stack_fds(self, downpair[0], uppair[0], controlpair[0], stacked, 0)) { z_proxy_leave(self); return FALSE; } z_proxy_leave(self); return TRUE; }
gboolean pop3_data_transfer(Pop3Proxy *owner) { Pop3Transfer *t; GString *preamble; gboolean success; gchar buf[256]; z_proxy_enter(owner); preamble = g_string_new(owner->response->str); if (owner->response_param->len) { g_string_append_c(preamble, ' '); g_string_append(preamble, owner->response_param->str); } g_string_append(preamble, "\r\n"); t = Z_CAST(z_dot_transfer_new(Z_CLASS(Pop3Transfer), &owner->super, owner->poll, owner->super.endpoints[EP_SERVER], owner->super.endpoints[EP_CLIENT], owner->buffer_length, owner->timeout, ZT2F_COMPLETE_COPY | ZT2F_PROXY_STREAMS_POLLED, preamble), Pop3Transfer); z_transfer2_set_content_format(&t->super.super, "email"); z_stream_line_set_nul_nonfatal(owner->super.endpoints[EP_SERVER], TRUE); if (owner->policy_enable_longline) z_stream_line_set_split(owner->super.endpoints[EP_SERVER], TRUE); success = z_transfer2_simple_run(&t->super.super); z_stream_line_set_split(owner->super.endpoints[EP_SERVER], FALSE); z_stream_line_set_nul_nonfatal(owner->super.endpoints[EP_SERVER], FALSE); if (t->super.dst_write_state == DOT_DW_PREAMBLE) { /* nothing was written to destination */ switch (z_transfer2_get_stack_decision(&t->super.super)) { case ZV_REJECT: /*LOG This message indicates that the stacked proxy rejected the content and Zorp rejects the response. */ z_proxy_log(owner, POP3_ERROR, 2, "Stacked proxy rejected contents; info='%s'", z_transfer2_get_stack_info(&t->super.super)); g_snprintf(buf, sizeof(buf), "Content rejected (%s)", z_transfer2_get_stack_info(&t->super.super)); if (owner->reject_by_mail) pop3_error_msg(owner, buf); else pop3_response_reject(owner, buf); break; case ZV_ERROR: g_snprintf(buf, sizeof(buf), "Error occurred while transferring data (%s)", z_transfer2_get_stack_info(&t->super.super)); pop3_response_reject(owner, buf); owner->pop3_state = POP3_STATE_QUIT; break; default: pop3_response_write(owner); pop3_write_client(owner, ".\r\n"); break; } } else { pop3_write_client(owner, ".\r\n"); } if (owner->from) { g_string_free(owner->from, TRUE); owner->from = NULL; } if (owner->to) { g_string_free(owner->to, TRUE); owner->to = NULL; } if (owner->subject) { g_string_free(owner->subject, TRUE); owner->subject = NULL; } z_object_unref(&t->super.super.super); z_proxy_return(owner, success); }
/** * finger_send_request: * @self: FingerProxy instance * * Construct and send a request to the server based on the state * stored by finger_fetch_request(). **/ static gboolean finger_send_request(FingerProxy *self) { gchar request[self->username->len + self->hostnames->len + 6]; gsize bytes_written; z_proxy_enter(self); if (self->long_req) { if (self->username->len > 0) { if (self->hostnames->len > 0) g_snprintf(request, sizeof(request), "/W %s%s\r\n", self->username->str, self->hostnames->str); else g_snprintf(request, sizeof(request), "/W %s\r\n", self->username->str); } else { if (self->hostnames->len > 0) g_snprintf(request, sizeof(request), "/W %s\r\n", self->hostnames->str); else g_snprintf(request, sizeof(request), "/W\r\n"); } } else { if (self->username->len > 0) { if (self->hostnames->len > 0) g_snprintf(request, sizeof(request), "%s%s\r\n", self->username->str, self->hostnames->str); else g_snprintf(request, sizeof(request), "%s\r\n", self->username->str); } else { if (self->hostnames->len > 0) g_snprintf(request, sizeof(request), "%s\r\n", self->hostnames->str); else g_snprintf(request, sizeof(request), "\r\n"); } } if (z_stream_write(self->super.endpoints[EP_SERVER], request, strlen(request), &bytes_written, NULL) != G_IO_STATUS_NORMAL) { /*LOG This message appear when some error found in server side. */ z_proxy_log(self, FINGER_ERROR, 1, "Error write request;"); z_proxy_return(self, FALSE); } z_proxy_return(self, TRUE); }
static GIOStatus http_transfer_src_read(ZTransfer2 *s, ZStream *stream, gchar *buf, gsize count, gsize *bytes_read, GError **err) { HttpTransfer *self = Z_CAST(s, HttpTransfer); HttpProxy *owner = Z_CAST(s->owner, HttpProxy); GError *local_error = NULL; gsize br; GIOStatus res = G_IO_STATUS_NORMAL; if (self->src_read_state == HTTP_SR_INITIAL) self->src_read_state = HTTP_SR_PUSH_HEADERS; if (self->src_read_state >= HTTP_SR_PUSH_HEADERS && self->src_read_state <= HTTP_SR_PUSH_HEADERS_MAX) { if (self->push_mime_headers && self->stacked_preamble->len > 0) { gint move; *bytes_read = 0; move = MIN(count, self->stacked_preamble->len - self->stacked_preamble_ofs); memmove(buf, self->stacked_preamble->str + self->stacked_preamble_ofs, move); self->stacked_preamble_ofs += move; *bytes_read = move; if (self->stacked_preamble_ofs == self->stacked_preamble->len) { z_transfer2_set_proxy_out(s, FALSE); self->src_read_state = HTTP_SR_READ_INITIAL; } return G_IO_STATUS_NORMAL; } else { self->src_read_state = HTTP_SR_READ_INITIAL; } } *bytes_read = 0; if (self->src_chunked) { /* read as a chunked stream */ switch (self->src_read_state) { case HTTP_SR_READ_INITIAL: self->src_whole_length = 0; self->src_read_state = HTTP_SR_READ_CHUNK_LENGTH; z_stream_line_set_poll_partial(stream, FALSE); /* fallthrough */ case HTTP_SR_READ_CHUNK_LENGTH: { gchar line_buf[32], *line; gsize line_length; guint32 chunk_length; gchar *end; res = z_stream_line_get(stream, &line, &line_length, NULL); if (res == G_IO_STATUS_NORMAL) { /* a complete line was read, check if it is a valid chunk length */ if (line_length >= sizeof(line_buf) - 1) { /*LOG This message indicates that the chunk length line is too long. It is likely caused by a buggy client or server. */ z_proxy_log(self->super.owner, HTTP_VIOLATION, 1, "Chunk length line too long; line='%.*s'", (gint) line_length, line); res = G_IO_STATUS_ERROR; break; } /* we already checked that line_buf is large enough */ memcpy(line_buf, line, line_length); line_buf[line_length] = 0; chunk_length = strtoul(line_buf, &end, 16); if (end == line_buf) { /* hmm... invalid chunk length */ /*LOG This message indicates that the chunk length is invalid. It is likely caused by a buggy client or server. */ z_proxy_log(self->super.owner, HTTP_VIOLATION, 1, "Invalid chunk length; line='%s'", line_buf); res = G_IO_STATUS_ERROR; break; } /* * NOTE: the string pointed by end is NUL terminated, thus * we will not overflow our buffer */ while (*end == ' ') end++; if (*end == ';') { /* ignore and strip chunk extensions */ *end = 0; } if (*end) { /* hmm... invalid chunk length */ /*LOG This message indicates that the chunk length is invalid. It is likely caused by a buggy client or server. */ z_proxy_log(self->super.owner, HTTP_VIOLATION, 1, "Invalid chunk length; line='%s'", line_buf); res = G_IO_STATUS_ERROR; break; } if ((owner->max_chunk_length && chunk_length > owner->max_chunk_length) || (chunk_length & 0x80000000)) { /*LOG This message indicates that the length of the chunk is larger than allowed or is a negative number. Check the 'max_chunk_length' attribute. */ z_proxy_log(self->super.owner, HTTP_POLICY, 2, "Chunk too large; length='%d', max_chunk_length='%d'", chunk_length, owner->max_chunk_length); res = G_IO_STATUS_ERROR; break; } if (owner->max_body_length && (guint) self->src_whole_length + chunk_length > owner->max_body_length) { /* this chunk would be over body_length limit */ chunk_length = owner->max_body_length - self->src_whole_length; self->src_chunk_left = chunk_length; self->force_nonpersistent_mode = TRUE; self->src_chunk_truncated = TRUE; } self->src_chunk_left = chunk_length; self->src_last_chunk = chunk_length == 0; self->src_read_state = HTTP_SR_READ_CHUNK; z_stream_line_set_poll_partial(stream, TRUE); /* fall through */ } else break; } case HTTP_SR_READ_CHUNK: if (!self->src_last_chunk) { res = z_stream_read(stream, buf, MIN(self->src_chunk_left, count), &br, &local_error); if (res == G_IO_STATUS_NORMAL) { self->src_whole_length += br; self->src_chunk_left -= br; *bytes_read = br; } else if (res == G_IO_STATUS_EOF) { /* unexpected eof */ /*LOG This message indicates that Zorp unexpectedly got EOF during chunk encoded data transfer. It is likely a caused by a buggy client or server. */ z_proxy_log(self->super.owner, HTTP_VIOLATION, 1, "Unexpected EOF while dechunking stream;"); res = G_IO_STATUS_ERROR; break; } if (self->src_chunk_left == 0) { self->src_read_state = HTTP_SR_READ_FOOTER; z_stream_line_set_poll_partial(stream, FALSE); } break; } else { self->src_read_state = HTTP_SR_READ_FOOTER; z_stream_line_set_poll_partial(stream, FALSE); /* fallthrough */ } case HTTP_SR_READ_FOOTER: { gchar *line; gsize line_length; if (!self->src_chunk_truncated) { res = z_stream_line_get(stream, &line, &line_length, NULL); } else { res = G_IO_STATUS_EOF; } if (res == G_IO_STATUS_NORMAL) { if (line_length != 0) { /*LOG This message indicates that the chunk footer contains data. It is likely caused by a buggy client or server. */ z_proxy_log(self->super.owner, HTTP_VIOLATION, 1, "Chunk footer is not an empty line;"); res = G_IO_STATUS_ERROR; break; } if (self->src_last_chunk) { res = G_IO_STATUS_EOF; } else { self->src_read_state = HTTP_SR_READ_CHUNK_LENGTH; z_stream_line_set_poll_partial(stream, TRUE); /* come back later */ res = G_IO_STATUS_AGAIN; } break; } break; } } } else { /* copy until EOF or self->content_length bytes */ if (self->content_length == HTTP_LENGTH_NONE) { res = G_IO_STATUS_EOF; } else { if (self->src_read_state == HTTP_SR_INITIAL) { self->src_whole_length = 0; self->src_read_state = HTTP_SR_READ_ENTITY; } if (self->content_length == HTTP_LENGTH_UNKNOWN) { if (owner->max_body_length && self->src_whole_length + count >= owner->max_body_length) { count = owner->max_body_length - self->src_whole_length; } if (count == 0) { self->force_nonpersistent_mode = TRUE; res = G_IO_STATUS_EOF; } else res = z_stream_read(stream, buf, count, &br, &local_error); } else { /* for specified content-length, max_body_length has already been processed, and content_length contains the number of bytes to be transferred, but maximum max_body_length */ if (self->content_length >= 0 && (guint64) self->content_length == self->src_whole_length) res = G_IO_STATUS_EOF; else res = z_stream_read(stream, buf, MIN(count, self->content_length - self->src_whole_length), &br, &local_error); } if (res == G_IO_STATUS_NORMAL) { self->src_whole_length += br; *bytes_read = br; } } } if (local_error) g_propagate_error(err, local_error); return res; }
/** * finger_fetch_request: * @self: FingerProxy instance * * Read and process a request. **/ static gboolean finger_fetch_request(FingerProxy *self) { gchar *p, *line; gint left, hop_count; gsize line_length; gint res; gboolean fetch_user = TRUE; guint hostlen = 0; z_proxy_enter(self); res = z_stream_line_get(self->super.endpoints[EP_CLIENT], &line, &line_length, NULL); if (res != G_IO_STATUS_NORMAL) { /*LOG This message is appears when zorp cannot read finger request */ z_proxy_log(self, FINGER_ERROR, 1, "Error reading request;"); z_proxy_return(self, FALSE); } /*LOG This message is say about read finger request */ z_proxy_log(self, FINGER_REQUEST, 6, "Request details; req='%.*s'", (gint) line_length, line); p = line; left = line_length; self->long_req = FALSE; while (*p == ' ' && left) { p++; left--; } if (*p == '/') { p++; left--; if (*p == 'W') { self->long_req = TRUE; p++; left--; } else { /*LOG This message appear when zorp cannot parse request */ z_proxy_log(self, FINGER_VIOLATION, 1, "Parse error, dropping request; req='%.*s'", (gint) line_length, line); z_proxy_return(self, FALSE); } } while (*p == ' ' && left) { p++; left--; } hop_count = 0; g_string_truncate(self->username, 0); g_string_truncate(self->hostnames, 0); while (*p && left) { if (*p == '@') { if (self->max_hop_count != -1) { hop_count++; if (hop_count > self->max_hop_count) break; } fetch_user = FALSE; hostlen = 0; } if (self->strict_username_check && !(isalnum(*p) || *p == '_' || *p == '@' || *p == '.' || *p == '-')) { /*LOG This message say that zorp found an invalid character in finger request. */ z_proxy_log(self, FINGER_VIOLATION, 1, "Invalid character, dropping request; line='%.*s'", (gint) line_length, line); z_proxy_return(self, FALSE); } if (fetch_user) { g_string_append_c(self->username, *p); if (self->username->len > self->max_username_length) { /*LOG This message is about too long username found in the request. */ z_proxy_log(self, FINGER_VIOLATION, 1, "Username too long, dropping request; line='%.*s'", (gint) line_length, line); z_proxy_return(self, FALSE); } } else { g_string_append_c(self->hostnames, *p); if (hostlen > self->max_hostname_length) { /*LOG This message is appear when a too long hostname found in the request horname chain. */ z_proxy_log(self, FINGER_VIOLATION, 1, "One hostname is too long in hostname chain, dropping request; req='%.*s'", (gint) line_length, line); z_proxy_return(self, FALSE); } hostlen++; } p++; left--; } z_proxy_return(self, TRUE); }
/** * telnet_process_buf: * @self: * @buf: * @dbuf: * @odbuf: * @ep: * * * * Returns: * */ static gboolean telnet_process_buf(TelnetProxy *self, ZIOBuffer *buf, ZIOBufferDyn *dbuf, ZIOBufferDyn *odbuf, guint ep) { guint ptr; guint res; guchar byte; ZIOBuffer *sbuf = &self->suboptions[ep]; ZIOBuffer tbuf; z_proxy_enter(self); z_proxy_trace(self, "telnet_process_buf called side='%s'", WHICH_EP(ep)); dbuf->ofs = dbuf->end = 0; ptr = buf->ofs; while (ptr < buf->end) { z_proxy_log(self, TELNET_DEBUG, 7, "Processing buffer; state='%d'", self->state[ep]); switch (self->state[ep]) { case TELNET_DATA: while (ptr < buf->end && buf->buf[ptr] != TELNET_IAC) ptr++; /* if not in urgent mode, write out data */ res = telnet_copy_buf(dbuf, buf, ptr - buf->ofs); if (!res) { z_proxy_log(self, TELNET_ERROR, 3, "Output buffer full; side='%s'", WHICH_EP(OTHER_EP(ep))); z_proxy_return(self, FALSE); } else if (ptr >= buf->end) buf->ofs = ptr; /* set buffer offset pointer as if data was written */ if (ptr < buf->end) { self->state[ep] = TELNET_GOT_IAC; ptr++; } break; case TELNET_GOT_IAC: self->command[ep] = buf->buf[ptr++]; /* telnet option negotiation */ if (self->command[ep] == TELNET_CMD_WILL || self->command[ep] == TELNET_CMD_WONT || self->command[ep] == TELNET_CMD_DO || self->command[ep] == TELNET_CMD_DONT) { self->state[ep] = TELNET_GOT_OPNEG; } /* telnet suboption negotiation */ else if (self->command[ep] == TELNET_CMD_SB) { self->state[ep] = TELNET_GOT_SB; } /* telnet datamark */ else if (self->command[ep] == TELNET_CMD_DATAMARK) { self->state[ep] = TELNET_DATA; } /* invalid commands in this state, drop them */ else if (self->command[ep] == TELNET_CMD_SE) { self->state[ep] = TELNET_DATA; z_proxy_log(self, TELNET_VIOLATION, 2, "Illegal command in stream; command='%d'", self->command[ep]); } /* else send it to the other side */ else { res = telnet_process_command(self, ep); self->state[ep] = TELNET_DATA; if (res == TELNET_CHECK_OK) { res = telnet_copy_buf(dbuf, buf, ptr - buf->ofs); if (!res) { z_proxy_log(self, TELNET_ERROR, 3, "Output buffer full; side='%s'", WHICH_EP(OTHER_EP(ep))); z_proxy_return(self, FALSE); } } else { buf->ofs = ptr; z_proxy_log(self, TELNET_VIOLATION, 2, "Illegal command; command='%d'", self->command[ep]); } } z_proxy_log(self, TELNET_DEBUG, 6, "Processing command; state='TELNET_GOT_IAC', cmd='%d'", self->command[ep]); break; case TELNET_GOT_OPNEG: /* get option number from buffer */ self->opneg_option[ep] = buf->buf[ptr++]; z_proxy_log(self, TELNET_DEBUG, 6, "Processing option negotiation; state='TELNET_GOT_OPNEG', option='%d'", self->opneg_option[ep]); /* check if valid and allowed */ res = telnet_process_opneg(self, ep); switch (res) { case TELNET_CHECK_OK: res = telnet_copy_buf(dbuf, buf, ptr - buf->ofs); if (!res) { z_proxy_log(self, TELNET_ERROR, 3, "Output buffer full; side='%s'", WHICH_EP(OTHER_EP(ep))); z_proxy_return(self, FALSE); } break; case TELNET_CHECK_REJECT: /* create a temporary buffer */ tbuf.ofs = 0; tbuf.end = 3; tbuf.buf[0] = buf->buf[buf->ofs]; tbuf.buf[1] = buf->buf[buf->ofs + 1]; tbuf.buf[2] = buf->buf[buf->ofs + 2]; switch (buf->buf[buf->ofs + 1]) { case TELNET_CMD_WILL: tbuf.buf[tbuf.ofs + 1] = TELNET_CMD_DONT; buf->buf[buf->ofs + 1] = TELNET_CMD_WONT; z_proxy_log(self, TELNET_DEBUG, 6, "WILL rejected;"); break; case TELNET_CMD_WONT: tbuf.buf[tbuf.ofs + 1] = TELNET_CMD_DONT; z_proxy_log(self, TELNET_DEBUG, 6, "WONT passed through;"); break; case TELNET_CMD_DO: tbuf.buf[tbuf.ofs + 1] = TELNET_CMD_WONT; buf->buf[buf->ofs + 1] = TELNET_CMD_DONT; z_proxy_log(self, TELNET_DEBUG, 6, "DO rejected;"); break; case TELNET_CMD_DONT: tbuf.buf[tbuf.ofs + 1] = TELNET_CMD_WONT; z_proxy_log(self, TELNET_DEBUG, 6, "DONT passed through;"); break; } res = telnet_copy_buf(odbuf, &tbuf, tbuf.end); if (res) res = telnet_copy_buf(dbuf, buf, ptr - buf->ofs); if (!res) { z_proxy_log(self, TELNET_DEBUG, 6, "Output buffer full; side='%s'", WHICH_EP(ep)); z_proxy_return(self, FALSE); } break; case TELNET_CHECK_ABORT: z_proxy_log(self, TELNET_POLICY, 2, "Session aborted during option negotiation;"); z_proxy_return(self, FALSE); case TELNET_CHECK_DROP: default: z_proxy_log(self, TELNET_POLICY, 3, "Option negotiation sequence dropped;"); break; } /* next state */ self->state[ep] = TELNET_DATA; break; case TELNET_GOT_SB: /* get option number from buffer */ self->opneg_option[ep] = buf->buf[ptr++]; z_proxy_log(self, TELNET_DEBUG, 6, "Processing suboptions; state='TELNET_GOT_SB', option='%d'", self->opneg_option[ep]); /* initialize suboption buffer */ self->suboptions[ep].ofs = 0; self->suboptions[ep].end = 0; self->state[ep] = TELNET_IN_SB; break; case TELNET_IN_SB: /* while not end of buffer and no IAC found */ while (ptr < buf->end && buf->buf[ptr] != TELNET_IAC) { /* if the suboption buffer is already full */ if (sbuf->end == TELNET_SUBOPTION_SIZE) { z_proxy_log(self, TELNET_DEBUG, 6, "Suboption buffer full; side='%s'", WHICH_EP(ep)); z_proxy_return(self, FALSE); } /* copy byte to suboption buffer */ sbuf->buf[sbuf->end++] = buf->buf[ptr++]; } /* if IAC found, next state is TELNET_GOT_SB_IAC */ if (ptr < buf->end) { self->state[ep] = TELNET_GOT_SB_IAC; ptr++; } else { self->state[ep] = TELNET_DATA; } break; case TELNET_GOT_SB_IAC: /* if suboption negotiation end found */ if ((byte = buf->buf[ptr++]) == TELNET_CMD_SE) { res = telnet_check_suboption(self, ep); if (res == TELNET_CHECK_OK) { res = telnet_copy_buf(dbuf, buf, 3); if (res) telnet_copy_buf(dbuf, sbuf, sbuf->end - sbuf->ofs); buf->ofs = ptr - 2; if (res) telnet_copy_buf(dbuf, buf, 2); if (!res) { z_proxy_log(self, TELNET_VIOLATION, 6, "Output buffer full; side='%s'", WHICH_EP(OTHER_EP(ep))); z_proxy_leave(self); return FALSE; } } else { z_proxy_log(self, TELNET_POLICY, 3, "Suboption denied by policy;"); } /* data comes... */ buf->ofs = ptr; self->state[ep] = TELNET_DATA; } /* otherwise it was just suboption data */ else { /* check if there's room for two bytes in suboption buffer */ if (sbuf->end + 2 > TELNET_SUBOPTION_SIZE) { z_proxy_log(self, TELNET_ERROR, 3, "Suboption buffer full; side='%s'", WHICH_EP(ep)); z_proxy_return(self, FALSE); } /* put two bytes in the buffer */ sbuf->buf[sbuf->end++] = TELNET_IAC; sbuf->buf[sbuf->end++] = byte; /* suboption negotiation data follows... */ self->state[ep] = TELNET_IN_SB; } break; default: z_proxy_log(self, TELNET_ERROR, 2, "Internal error, unknown state;"); z_proxy_return(self, FALSE); } } z_proxy_return(self, TRUE); }
/** * finger_copy_response: * @self: FingerProxy instance * * Copy server's response to the client. * **/ static gboolean finger_copy_response(FingerProxy *self) { gsize bytes_written; gint res = G_IO_STATUS_ERROR; z_proxy_enter(self); if (self->response_header->len && z_stream_write(self->super.endpoints[EP_CLIENT], self->response_header->str, self->response_header->len, &bytes_written, NULL) != G_IO_STATUS_NORMAL) { /*LOG This message appear when some error found in client side when writting the header. */ z_proxy_log(self, FINGER_ERROR, 1, "Error write request;"); z_proxy_return(self, FALSE); } while (1) { gchar *line; gsize line_len; gchar *response; if (!z_proxy_loop_iteration(&self->super)) break; res = z_stream_line_get(self->super.endpoints[EP_SERVER], &line, &line_len, NULL); if (res != G_IO_STATUS_NORMAL) /* EOF or read error */ break; response = alloca(line_len + 3); memcpy(response, line, line_len); strcpy(response + line_len, "\r\n"); if (z_stream_write(self->super.endpoints[EP_CLIENT], response, line_len + 2, &bytes_written, NULL) != G_IO_STATUS_NORMAL) { /*LOG This message appear when some error found in client side when writting the response. */ z_proxy_log(self, FINGER_ERROR, 1, "Error write request;"); z_proxy_return(self, FALSE); } } if (res != G_IO_STATUS_ERROR && self->response_footer->len && z_stream_write(self->super.endpoints[EP_CLIENT], self->response_footer->str, self->response_footer->len, &bytes_written, NULL) != G_IO_STATUS_NORMAL) { /*LOG This message appear when some error found in client side when writting the footer. */ z_proxy_log(self, FINGER_ERROR, 1, "Error write request;"); z_proxy_return(self, FALSE); } z_proxy_return(self, TRUE); }
/** * telnet_forward: * @self: * @from: * @to: * @ep: * * * * Returns: * */ static gboolean telnet_forward(TelnetProxy *self, ZStream *from, ZStream *to, guint ep) { ZIOBuffer *buf = &self->read_buffers[ep]; ZIOBufferDyn *dbuf = &self->write_buffers[OTHER_EP(ep)]; ZIOBufferDyn *odbuf = &self->write_buffers[ep]; guint maxiter = 5; GIOStatus res; gboolean rc; z_proxy_enter(self); from->want_read = FALSE; /* write any pending data in output buffer */ to->want_write = FALSE; res = telnet_stream_write(self, dbuf, OTHER_EP(ep)); if (res != G_IO_STATUS_NORMAL) z_proxy_return(self, res == G_IO_STATUS_AGAIN); /* read and write */ while (maxiter) { maxiter--; if (buf->ofs != buf->end) memmove(buf->buf, buf->buf + buf->ofs, buf->end - buf->ofs); buf->end -= buf->ofs; buf->ofs = 0; res = telnet_stream_read(self, buf, ep); if (res == G_IO_STATUS_NORMAL) { /* process buffer */ rc = telnet_process_buf(self, buf, dbuf, odbuf, ep); if (!rc) z_proxy_return(self, FALSE); /* write output buffer */ if (!from->want_write) { res = telnet_stream_write(self, odbuf, ep); if (res != G_IO_STATUS_NORMAL && res != G_IO_STATUS_AGAIN) z_proxy_return(self, FALSE); } res = telnet_stream_write(self, dbuf, OTHER_EP(ep)); if (res == G_IO_STATUS_AGAIN) break; else if (res != G_IO_STATUS_NORMAL) z_proxy_return(self, FALSE); } else if (res == G_IO_STATUS_AGAIN) { break; } else if (res == G_IO_STATUS_EOF) { z_proxy_log(self, TELNET_DEBUG, 6, "Connection closed by peer; side='%s'", WHICH_EP(ep)); z_proxy_return(self, FALSE); } else if (res == G_IO_STATUS_ERROR) { z_proxy_return(self, FALSE); } } /* check if output buffer is empty */ if (dbuf->ofs == dbuf->end) from->want_read = TRUE; z_proxy_return(self, TRUE); }
/** * finger_main: * @s: FingerProxy instance * * main proxy routine. **/ static void finger_main(ZProxy *s) { FingerProxy *self = Z_CAST(s, FingerProxy); z_proxy_enter(self); if (!finger_init_client_stream(self)) z_proxy_return(self); /*LOG This debug message is about proxy state when start to fetching request */ z_proxy_log(self, FINGER_DEBUG, 6, "fetching request;"); if (!finger_fetch_request(self)) { char *errmsg = "Finger protocol or disallowed protocol element, request denied.\r\n"; gsize bytes_written; z_stream_write(self->super.endpoints[EP_CLIENT], errmsg, strlen(errmsg), &bytes_written, NULL); z_proxy_return(self); } /*LOG This debug message is about proxy state when finger fetched request and asking policy about it */ z_proxy_log(self, FINGER_DEBUG, 6, "asking policy;"); if (!finger_query_policy(self)) z_proxy_return(self); /*LOG This debug message is about proxy state when finger start connect to server. */ z_proxy_log(self, FINGER_DEBUG, 6, "connecting server;"); /* this sets the server side endpoint if successful */ if (!z_proxy_connect_server(&self->super, NULL, 0)) z_proxy_return(self); if (!finger_init_server_stream(self)) z_proxy_return(self); /*LOG This debug message is about proxy state when finger start send the request to server. */ z_proxy_log(self, FINGER_DEBUG, 6, "sending request;"); if (!finger_send_request(self)) z_proxy_return(self); /*LOG This debug message is about proxy state when finger start to copy server answer to client. */ z_proxy_log(self, FINGER_DEBUG, 6, "copying response;"); if (!finger_copy_response(self)) z_proxy_return(self); /*LOG This debug message is about proxy state when finger stop it's work. */ z_proxy_log(self, FINGER_DEBUG, 6, "everything is done;"); z_proxy_return(self); }
/** * telnet_policy_suboption: * @self: * @command: * @name: * @value: * * * * Returns: * */ guint telnet_policy_suboption(TelnetProxy *self, guchar command, gchar *name, gchar *value) { guint res; ZPolicyObj *pol_res; ZPolicyObj *tmp; ZPolicyObj *command_where = NULL; guint command_do; gchar lookup_str[2][10]; gchar *keys[2]; gboolean type_found; z_proxy_enter(self); z_proxy_log(self, TELNET_DEBUG, 8, "Policy suboption negotiation check;"); g_snprintf(lookup_str[0], sizeof(lookup_str[0]), "%d", self->opneg_option[self->ep]); g_snprintf(lookup_str[1], sizeof(lookup_str[1]), "%d", command); keys[0] = lookup_str[0]; keys[1] = lookup_str[1]; tmp = z_dim_hash_table_search(self->telnet_policy, 2, keys); if (!tmp) { z_proxy_log(self, TELNET_POLICY, 1, "Option not found in policy hash, dropping; command=`%s', option=`%s'", lookup_str[1], lookup_str[0]); z_proxy_return(self, TELNET_CHECK_DROP); } z_policy_lock(self->super.thread); type_found = telnet_hash_get_type(tmp, &command_do); z_policy_unlock(self->super.thread); if (!type_found) { z_proxy_log(self, TELNET_POLICY, 2, "Policy type invalid!"); z_proxy_return(self, TELNET_CHECK_ABORT); } switch (command_do) { case TELNET_OPTION_DROP: z_proxy_log(self, TELNET_POLICY, 6, "Policy denied suboption; command=`%s', option=`%s'", lookup_str[1], lookup_str[0]); res = TELNET_CHECK_DROP; break; case TELNET_OPTION_ACCEPT: z_proxy_log(self, TELNET_POLICY, 6, "Policy accepted suboption; command=`%s', option=`%s'", lookup_str[1], lookup_str[0]); res = TELNET_CHECK_OK; break; case TELNET_OPTION_POLICY: z_policy_lock(self->super.thread); if (!z_policy_var_parse(tmp, "(iO)", &command_do, &command_where)) { z_proxy_log(self, TELNET_POLICY, 2, "Cannot parse policy line for option; command=`%s', option=`%s'", lookup_str[1], lookup_str[0]); res = TELNET_CHECK_ABORT; } else { /* call Python method with appropriate parameters */ switch (self->opneg_option[self->ep]) { case TELNET_OPTION_TERMINAL_TYPE: case TELNET_OPTION_TERMINAL_SPEED: case TELNET_OPTION_X_DISPLAY_LOCATION: case TELNET_OPTION_ENVIRONMENT: case TELNET_OPTION_NAWS: pol_res = z_policy_call_object(command_where, z_policy_var_build("(iss)", &self->opneg_option[self->ep], name, value), self->super.session_id); break; default: pol_res = z_policy_call_object(command_where, z_policy_var_build("(i)", &self->opneg_option[self->ep]), self->super.session_id); break; } if (pol_res == NULL) { z_proxy_log(self, TELNET_POLICY, 2, "Error in policy calling; command=`%s', option=`%s'", lookup_str[1], lookup_str[0]); res = TELNET_CHECK_ABORT; } else if (!z_policy_var_parse(pol_res, "i", &res)) { z_proxy_log(self, TELNET_POLICY, 2, "Can't parse return verdict; command=`%s', option=`%s'", lookup_str[1], lookup_str[0]); res = TELNET_CHECK_ABORT; } else { switch (res) { case ZV_ACCEPT: z_proxy_log(self, TELNET_POLICY, 6, "Policy function accepted suboption; command=`%s', option=`%s'", lookup_str[1], lookup_str[0]); res = TELNET_CHECK_OK; break; case ZV_UNSPEC: case ZV_REJECT: case ZV_DROP: z_proxy_log(self, TELNET_POLICY, 3, "Policy function denied suboption; command=`%s', option=`%s'", lookup_str[1], lookup_str[0]); res = TELNET_CHECK_DROP; break; case ZV_ABORT: default: z_proxy_log(self, TELNET_POLICY, 3, "Policy function aborted suboption; command=`%s', option=`%s'", lookup_str[1], lookup_str[0]); res = TELNET_CHECK_ABORT; break; } } } z_policy_unlock(self->super.thread); break; case TELNET_OPTION_ABORT: default: z_proxy_log(self, TELNET_POLICY, 3, "Policy aborted session; command=`%s', option=`%s'", lookup_str[1], lookup_str[0]); res = TELNET_CHECK_ABORT; break; } z_proxy_return(self, res); }
/** * http_ftp_fetch_response: * @self: HttpProxy instance * @status: returned FTP status code * @msg: returned FTP message * @msglen: size of the @msg buffer * * This function is called to fetch a response from the FTP server. Line * continuations are supported however only the first line will be returned * in @msg. **/ static gboolean http_ftp_fetch_response(HttpProxy *self, gint *status, gchar *msg, gsize msglen) { gchar *line; gsize length; gboolean continuation = TRUE, first = TRUE; gint mul, value, i; msg[0] = 0; while (continuation) { if (z_stream_line_get(self->super.endpoints[EP_SERVER], &line, &length, NULL) != G_IO_STATUS_NORMAL) return FALSE; if (length < 4) { /*LOG This message indicates that the response given by the FTP server was too short, not even the mandatory status code was included. */ z_proxy_log(self, HTTP_VIOLATION, 2, "Invalid FTP response, line too short; line='%.*s'", (gint)length, line); return FALSE; } value = 0; mul = 100; for (i = 0; i < 3; i++) { if (!isdigit(line[i])) { /*LOG This message indicates that the FTP server gave an invalid response, the status code returned by the server was not numeric. */ z_proxy_log(self, HTTP_VIOLATION, 2, "Invalid FTP response, response code not numeric; line='%.*s'", (gint)length, line); return FALSE; } value = value + mul * (line[i] - '0'); mul = mul / 10; } if (first) { gint copy = MIN(msglen - 1, length - 4 + 1); *status = value; memcpy(msg, &line[4], copy); msg[copy] = 0; } else if (*status != value) { /*LOG This message indicates that the FTP server gave an invalid response as the status code changed from the one which was present on the first line. */ z_proxy_log(self, HTTP_VIOLATION, 2, "Invalid FTP response, continuation line contains different status code; ftp_status='%d', line='%.*s'", *status, (gint)length, line); return FALSE; } continuation = line[3] == '-'; } return TRUE; }
/** * telnet_policy_option: * @self: * * * * Returns: * */ guint telnet_policy_option(TelnetProxy *self) { guint res; ZPolicyObj *pol_res; ZPolicyObj *tmp; ZPolicyObj *command_where = NULL; guint command_do; gchar lookup_str[10]; gchar *keys[1]; gboolean type_found; z_proxy_enter(self); z_proxy_log(self, TELNET_DEBUG, 8, "Policy option negotiation check; option='%d'", self->opneg_option[self->ep]); g_snprintf(lookup_str, sizeof(lookup_str), "%d", self->opneg_option[self->ep]); keys[0] = lookup_str; tmp = z_dim_hash_table_search(self->telnet_policy, 1, keys); if (!tmp) { z_proxy_log(self, TELNET_POLICY, 2, "Option not found in policy; option='%s'", lookup_str); z_proxy_return(self, TELNET_CHECK_DROP); } z_policy_lock(self->super.thread); type_found = telnet_hash_get_type(tmp, &command_do); z_policy_unlock(self->super.thread); if (!type_found ) { z_proxy_log(self, TELNET_POLICY, 2, "Policy type invalid; option='%s'", lookup_str); z_proxy_return(self, TELNET_CHECK_ABORT); } switch (command_do) { case TELNET_OPTION_DROP: z_proxy_log(self, TELNET_POLICY, 3, "Policy denied option; option='%s'", lookup_str); res = TELNET_CHECK_DROP; break; case TELNET_OPTION_ACCEPT: z_proxy_log(self, TELNET_POLICY, 6, "Policy accepted option; option='%s'", lookup_str); res = TELNET_CHECK_OK; break; case TELNET_OPTION_POLICY: z_policy_lock(self->super.thread); if (!z_policy_var_parse(tmp, "(iO)", &command_do, &command_where)) { z_proxy_log(self, TELNET_POLICY, 2, "Cannot parse policy line; option='%s'", lookup_str); res = TELNET_CHECK_ABORT; } else { pol_res = z_policy_call_object(command_where, z_policy_var_build("(i)", &self->opneg_option[self->ep]), self->super.session_id); if (pol_res == NULL) { z_proxy_log(self, TELNET_POLICY, 2, "Error in policy calling; option='%s'", lookup_str); res = TELNET_CHECK_ABORT; } else if (!z_policy_var_parse(pol_res, "i", &res)) { z_proxy_log(self, TELNET_POLICY, 1, "Can't parse return verdict; option='%s'", lookup_str); res = TELNET_CHECK_ABORT; } else { switch (res) { case ZV_ACCEPT: z_proxy_log(self, TELNET_POLICY, 6, "Policy function accepted option; option='%s'", lookup_str); res = TELNET_CHECK_OK; break; case ZV_UNSPEC: case ZV_DROP: z_proxy_log(self, TELNET_POLICY, 3, "Policy function drop option; option='%s'", lookup_str); res = TELNET_CHECK_DROP; break; case TELNET_OPTION_REJECT: z_proxy_log(self, TELNET_POLICY, 3, "Policy function reject option; option='%s'", lookup_str); res = TELNET_CHECK_REJECT; break; case ZV_ABORT: default: z_proxy_log(self, TELNET_POLICY, 1, "Policy function aborted session; option='%s'", lookup_str); res = TELNET_CHECK_ABORT; break; } } } z_policy_unlock(self->super.thread); break; case TELNET_OPTION_REJECT: z_proxy_log(self, TELNET_POLICY, 3, "Policy rejected option; option='%s'", lookup_str); res = TELNET_CHECK_REJECT; break; case TELNET_OPTION_ABORT: default: z_proxy_log(self, TELNET_POLICY, 3, "Policy aborted session; option='%s'", lookup_str); res = TELNET_CHECK_ABORT; break; } z_proxy_return(self, res); }