/** * 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; }
ZPolicyObj * smtp_policy_sanitize_address(SmtpProxy *self, ZPolicyObj *args) { gchar *address; gchar *final_end; GString *sanitized_address; ZPolicyObj *res = NULL; z_proxy_enter(self); if (!z_policy_var_parse_tuple(args, "s", &address)) { z_policy_raise_exception_obj(z_policy_exc_value_error, "Invalid arguments"); z_proxy_leave(self); return NULL; } sanitized_address = g_string_new(""); if (!smtp_sanitize_address(self, sanitized_address, address, TRUE, &final_end)) { z_policy_raise_exception_obj(z_policy_exc_value_error, "Invalid address"); goto exit; } res = z_policy_var_build("s", sanitized_address->str); exit: g_string_free(sanitized_address, TRUE); z_proxy_leave(self); return res; }
/** * z_transfer2_read_source: * @self: ZTransfer2 instance * @endpoint: endpoint to fetch data from * @buf: store fetched information into this buffer * @error: error details are stored here * * This function is called to fetch data from the specified endpoint. When * it is a proxy-connected stream then the proxy provided callbacks are * used to fetch information, otherwise z_stream_read is called directly. **/ static GIOStatus z_transfer2_read_source(ZTransfer2 *self, gint endpoint, ZTransfer2Buffer *buf, GError **error) { ZStream *from = z_transfer2_get_stream(self, endpoint); GIOStatus res = G_IO_STATUS_NORMAL; GError *local_error = NULL; gsize read_len; z_proxy_enter(self->owner); if (endpoint & ZT2E_STACKED) { res = z_stream_read(from, &buf->buf[buf->end], buf->size - buf->end, &read_len, &local_error); } else if (endpoint == ZT2E_SOURCE) { res = z_transfer2_src_read(self, self->endpoints[endpoint], &buf->buf[buf->end], buf->size - buf->end, &read_len, &local_error); } if (res == G_IO_STATUS_NORMAL) { buf->end += read_len; } if (local_error) g_propagate_error(error, local_error); z_proxy_leave(self->owner); return res; }
/** * anypy_set_content_hint: * @self: AnyPyProxy instance * @args: Python args argument * * sets verdict for the parent proxy * args is (verdict,description) **/ static ZPolicyObj * anypy_set_content_hint(AnyPyProxy * self, ZPolicyObj *args) { gint64 length; z_proxy_enter(self); if (!z_policy_var_parse_tuple(args, "L", &length)) { z_policy_raise_exception_obj(z_policy_exc_value_error, "Invalid arguments."); z_proxy_leave(self); return NULL; } if (self->super.parent_proxy) { ZProxyStackIface *iface; iface = z_proxy_find_iface(self->super.parent_proxy, Z_CLASS(ZProxyStackIface)); if (iface) { z_proxy_stack_iface_set_content_hint(iface, length); z_object_unref(&iface->super); } } z_proxy_return(self, z_policy_none_ref()); }
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; }
/** * z_transfer2_write_dest: * @self: ZTransfer2 instance * @endpoint: endpoint to send data to * @buf: send data from this buffer * @error: error details are stored here * * This function is called to send data to the specified endpoint. When * it is a proxy-connected stream then the proxy provided callbacks are * used to send information, otherwise z_stream_write is called directly. **/ static GIOStatus z_transfer2_write_dest(ZTransfer2 *self, gint endpoint, ZTransfer2Buffer *buf, GError **error) { ZStream *to = z_transfer2_get_stream(self, endpoint); GError *local_error = NULL; GIOStatus res = G_IO_STATUS_NORMAL; gsize bytes_written; z_proxy_enter(self->owner); if (!z_transfer2_buffer_empty(buf)) { if (endpoint & ZT2E_STACKED) res = z_stream_write(to, &buf->buf[buf->ofs], buf->end - buf->ofs, &bytes_written, &local_error); else res = z_transfer2_dst_write(self, to, &buf->buf[buf->ofs], buf->end - buf->ofs, &bytes_written, &local_error); switch (res) { case G_IO_STATUS_NORMAL: buf->ofs += bytes_written; if (!z_transfer2_buffer_empty(buf)) { res = G_IO_STATUS_AGAIN; } default: break; } } if (local_error) g_propagate_error(error, local_error); z_proxy_leave(self->owner); return res; }
/** * anypy_config_set_defaults: * @self: AnyPyProxy instance * * This function initializes various attributes exported to the Python layer * for possible modification. **/ static void anypy_config_set_defaults(AnyPyProxy *self) { z_proxy_enter(self); self->max_line_length[EP_CLIENT] = 4096; self->max_line_length[EP_SERVER] = 4096; z_proxy_leave(self); }
void ftp_policy_feature_hash_handle_insert(struct _FtpProxy *self, GHashTable *features) { z_proxy_enter(self); z_policy_lock(self->super.thread); g_hash_table_foreach(self->policy_features, ftp_policy_feature_hash_foreach_cb, features); z_policy_unlock(self->super.thread); z_proxy_leave(self); }
/** * 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 gboolean z_proxy_stack_fds(ZProxy *self, gint client_fd, gint server_fd, gint control_fd, ZStackedProxy **stacked, guint32 flags) { ZStream *client_upstream, *server_upstream, *control_stream = NULL; z_proxy_enter(self); client_upstream = z_stream_fd_new(client_fd, ""); server_upstream = z_stream_fd_new(server_fd, ""); if (control_fd != -1) control_stream = z_stream_fd_new(control_fd, ""); *stacked = z_stacked_proxy_new(client_upstream, server_upstream, control_stream, self, NULL, flags); z_proxy_leave(self); return TRUE; }
/** * z_transfer2_eof: * @self: ZTransfer2 instance * * This function is called when transfer encounters an EOF one of the * endpoints. It updates self->status end also terminates the poll loop * by setting ZT2S_FINISHED when the transfer supposedly finished. **/ static void z_transfer2_eof(ZTransfer2 *self, gint endpoint) { guint32 eof_status = endpoint == ZT2E_SOURCE ? ZT2S_EOF_SOURCE : ZT2S_EOF_DEST; z_proxy_enter(self->owner); if (!z_transfer2_get_status(self, eof_status)) { if (self->stacked) { if (endpoint == ZT2E_SOURCE) { z_stream_set_nonblock(z_transfer2_get_stream(self, ZT2E_SOURCE), FALSE); z_transfer2_src_shutdown(self, z_transfer2_get_stream(self, ZT2E_SOURCE), NULL); z_stream_set_nonblock(z_transfer2_get_stream(self, ZT2E_SOURCE), TRUE); z_stream_shutdown(z_transfer2_get_stream(self, ZT2E_DOWN_SOURCE), SHUT_WR, NULL); } else { z_stream_set_nonblock(z_transfer2_get_stream(self, ZT2E_DOWN_DEST), FALSE); z_stream_shutdown(z_transfer2_get_stream(self, ZT2E_DOWN_DEST), SHUT_RD, NULL); z_stream_set_nonblock(z_transfer2_get_stream(self, ZT2E_DOWN_DEST), TRUE); z_transfer2_dst_shutdown(self, z_transfer2_get_stream(self, ZT2E_DEST), NULL); } } else { z_stream_set_nonblock(z_transfer2_get_stream(self, ZT2E_SOURCE), FALSE); z_stream_set_nonblock(z_transfer2_get_stream(self, ZT2E_DEST), FALSE); z_transfer2_src_shutdown(self, z_transfer2_get_stream(self, ZT2E_SOURCE), NULL); z_transfer2_dst_shutdown(self, z_transfer2_get_stream(self, ZT2E_DEST), NULL); z_stream_set_nonblock(z_transfer2_get_stream(self, ZT2E_DEST), TRUE); z_stream_set_nonblock(z_transfer2_get_stream(self, ZT2E_SOURCE), TRUE); eof_status = ZT2S_EOF_SOURCE+ZT2S_EOF_DEST; } z_transfer2_update_status(self, eof_status, TRUE); } if ((self->status & (ZT2S_EOF_SOURCE+ZT2S_EOF_DEST)) == (ZT2S_EOF_SOURCE+ZT2S_EOF_DEST)) { z_transfer2_update_status(self, ZT2S_FINISHED, TRUE); } z_proxy_leave(self->owner); }
void plug_config_set_defaults(PlugProxy *self) { z_proxy_enter(self); self->session_data.copy_to_server = TRUE; self->session_data.copy_to_client = TRUE; self->session_data.timeout = 600000; self->session_data.buffer_size = PLUG_DEFAULT_BUFSIZE; self->session_data.packet_stats = plug_packet_stat_event; self->session_data.finish = plug_finish; self->session_data.timeout_cb = plug_timeout; if (self->super.parent_proxy) self->session_data.shutdown_soft = TRUE; z_proxy_leave(self); }
/** * z_transfer2_update_cond: * @self: ZTransfer2 instance * * This function is called after a chunk of data was transferred to update * the stream read/write conditions. It works based on the bits * stored in self->status. **/ static void z_transfer2_update_cond(ZTransfer2 *self) { gint i; z_proxy_enter(self->owner); for (i = 0; i <= ZT2E_MAX; i++) { if ((i & ZT2E_STACKED) == 0 || self->stacked) { z_stream_set_cond(z_transfer2_get_stream(self, i), G_IO_IN, FALSE); z_stream_set_cond(z_transfer2_get_stream(self, i), G_IO_OUT, FALSE); } } if (self->stacked) { if (!z_transfer2_get_status(self, ZT2S_EOF_SOURCE)) { if (z_transfer2_buffer_empty(&self->buffers[0]) && !z_transfer2_get_status(self, ZT2S_PROXY_OUT)) z_stream_set_cond(z_transfer2_get_stream(self, ZT2E_SOURCE), G_IO_IN, TRUE); else z_stream_set_cond(z_transfer2_get_stream(self, ZT2E_DOWN_SOURCE), G_IO_OUT, TRUE); } if (!z_transfer2_get_status(self, ZT2S_EOF_DEST)) { if (z_transfer2_buffer_empty(&self->buffers[1])) z_stream_set_cond(z_transfer2_get_stream(self, ZT2E_DOWN_DEST), G_IO_IN, TRUE); else z_stream_set_cond(z_transfer2_get_stream(self, ZT2E_DEST), G_IO_OUT, TRUE); } } else { /* no stacking */ if (!z_transfer2_get_status(self, ZT2S_EOF_SOURCE)) { if ((z_transfer2_buffer_empty(&self->buffers[0]) || z_transfer2_get_status(self, ZT2S_EOF_DEST) != 0) && !z_transfer2_get_status(self, ZT2S_PROXY_OUT)) z_stream_set_cond(z_transfer2_get_stream(self, ZT2E_SOURCE), G_IO_IN, TRUE); else z_stream_set_cond(z_transfer2_get_stream(self, ZT2E_DEST), G_IO_OUT, TRUE); } } z_proxy_leave(self->owner); }
static void anypy_main(ZProxy * s) { AnyPyProxy *self = Z_CAST(s, AnyPyProxy); ZPolicyObj *res; gboolean called; z_proxy_enter(self); if (!z_proxy_connect_server(&self->super, NULL, 0) || !anypy_stream_init(self)) { z_proxy_leave(self); return; } z_policy_lock(self->super.thread); res = z_policy_call(self->super.handler, "proxyThread", NULL, &called, self->super.session_id); z_policy_var_unref(res); z_policy_unlock(self->super.thread); z_proxy_return(self); }
/** * 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 void anypy_register_vars(AnyPyProxy *self) { z_proxy_enter(self); /* method for setting the proxy verdict. It should be used before the first write */ z_proxy_var_new(&self->super, "set_verdict", Z_VAR_TYPE_METHOD | Z_VAR_GET, self,anypy_set_verdict); /* method for setting the content hint. It should be used before the first write */ z_proxy_var_new(&self->super, "set_content_hint", Z_VAR_TYPE_METHOD | Z_VAR_GET, self, anypy_set_content_hint); /* size of line buffer of the client stream */ z_proxy_var_new(&self->super, "client_max_line_length", Z_VAR_TYPE_INT | Z_VAR_GET | Z_VAR_SET_CONFIG | Z_VAR_GET_CONFIG, &self->max_line_length[EP_CLIENT]); /* size of line buffer of the server stream */ z_proxy_var_new(&self->super, "server_max_line_length", Z_VAR_TYPE_INT | Z_VAR_GET | Z_VAR_SET_CONFIG | Z_VAR_GET_CONFIG, &self->max_line_length[EP_SERVER]); z_proxy_leave(self); }
/** * 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; }
guint Pop3AnswerParseNum_One(Pop3Proxy *self) { long int arg; gchar *err; gchar newline[self->max_reply_length]; z_proxy_enter(self); if (!strcmp(self->response->str, "-ERR")) z_proxy_return(self, POP3_RSP_ACCEPT); arg = strtol(self->response_param->str, &err, 10); if ( err == self->response_param->str ) { /*LOG This message indicates that the numerical parameter of the response is missing and Zorp aborts the connection. */ z_proxy_log(self, POP3_RESPONSE, 3, "The required numerical parameter of the response is missing; req='%s', rsp_prm='%s'", self->command->str, self->response_param->str); z_proxy_return(self, POP3_RSP_ABORT); } if (errno == ERANGE) { /*LOG This message indicates that the numerical parameter of the response is not in the given range and Zorp aborts the connection. */ z_proxy_log(self, POP3_RESPONSE, 3, "The numerical parameter of the response is not in the given range; req='%s', rsp_prm='%s'", self->command->str, self->response_param->str); z_proxy_return(self, POP3_RSP_ABORT); } if (arg < 0) { /*LOG This message indicates that the numerical parameter of the response is a negative number which is invalid and Zorp aborts the connection. */ z_proxy_log(self, POP3_RESPONSE, 3, "The numerical parameter of the response is a negative number; req='%s', rsp_prm='%s'", self->command->str, self->response_param->str); z_proxy_return(self, POP3_RSP_ABORT); } if (*err != 0) { /*LOG This message indicates that the numerical parameter of the response contains junk characters after the number but Zorp ignores and truncates the junk. */ z_proxy_log(self, POP3_RESPONSE, 4, "The numerical parameter of the response contains junk after the number; req='%s', rsp_prm='%s'", self->command->str, self->response_param->str); } g_snprintf(newline, sizeof(newline), "%ld", arg); g_string_assign(self->response_param, newline); z_proxy_leave(self); return POP3_RSP_ACCEPT; }
/** * z_transfer2_copy_data: * @self: ZTransfer2 instance * @ep_from: source endpoint * @ep_to: destination endpoint * @error: error details are stored here * * This function is the central copy-loop of ZTransfer2 and is called by I/O * callbacks assigned to various streams. It copies data while: * 1) data is available (e.g. G_IO_STATUS_NORMAL is returned) * 2) have not copied MAX_READ_AT_A_TIME chunks yet * 3) data can be flushed to destination (e.g. G_IO_STATUS_NORMAL is returned) * * when any of the conditions become FALSE, z_transfer2_copy_data returns, * but the operation can simply be restarted by calling it again. * Information stored in internal buffers are automatically reused in the * next invocation. * * This function also updates the timeout timer to indicate that some I/O * has happened, thus the timeout callback does not need to be called. **/ static GIOStatus z_transfer2_copy_data(ZTransfer2 *self, gint ep_from, gint ep_to, GError **error) { GError *local_error = NULL; ZTransfer2Buffer *buf = &self->buffers[ep_from & ~ZT2E_STACKED]; gint pkt_count = 0; GIOStatus res = G_IO_STATUS_NORMAL; gboolean leave_while = FALSE; z_proxy_enter(self->owner); if (self->timeout_source) z_timeout_source_set_timeout(self->timeout_source, self->timeout); while (pkt_count < MAX_READ_AT_A_TIME && !leave_while) { if (!z_transfer2_get_status(self, ZT2S_COPYING_TAIL)) { res = z_transfer2_write_dest(self, ep_to, buf, &local_error); if (res == G_IO_STATUS_NORMAL) { if (!z_transfer2_buffer_empty(buf)) break; } else if (res == G_IO_STATUS_AGAIN) { break; } else { z_transfer2_update_status(self, ZT2S_FAILED, TRUE); if (self->flags & ZT2F_COMPLETE_COPY) { z_transfer2_update_status(self, ZT2S_COPYING_TAIL, TRUE); } else { z_transfer2_update_status(self, ZT2S_FINISHED, TRUE); } break; } } else { buf->ofs = buf->end = 0; } if (z_transfer2_buffer_empty(buf)) { buf->ofs = buf->end = 0; } while (pkt_count < MAX_READ_AT_A_TIME && !z_transfer2_buffer_full(buf)) { guint eof_status = ep_from == ZT2E_SOURCE ? ZT2S_SOFT_EOF_SOURCE : ZT2S_SOFT_EOF_DEST; if (!z_transfer2_get_status(self, eof_status)) { res = z_transfer2_read_source(self, ep_from, buf, &local_error); if (res == G_IO_STATUS_NORMAL) { ; } else if (res == G_IO_STATUS_AGAIN) { leave_while = TRUE; break; } else if (res == G_IO_STATUS_EOF) { if (z_transfer2_buffer_empty(buf)) { z_transfer2_eof(self, ep_from); leave_while = TRUE; break; } else { z_transfer2_update_status(self, eof_status, TRUE); break; } } else { z_transfer2_update_status(self, ZT2S_FINISHED + ZT2S_ABORTED, TRUE); z_transfer2_eof(self, ep_from); leave_while = TRUE; break; } pkt_count++; } else { if (z_transfer2_buffer_empty(buf)) { z_transfer2_eof(self, ep_from); leave_while = TRUE; } break; } } } z_transfer2_update_cond(self); if (local_error) g_propagate_error(error, local_error); z_proxy_leave(self->owner); return 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; }
/** * 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); }