/* Decode question. */ Boolean ssh_dns_packet_decode_question(SshDNSPacket packet, const unsigned char *packet_buffer, size_t packet_length, size_t *offset_ptr, SshDNSQuestion question) { SshUInt16 qtype, qclass; size_t len; if (!ssh_dns_packet_decode_name(packet, packet_buffer, packet_length, offset_ptr, &question->qname)) return FALSE; len = ssh_decode_array(packet_buffer + *offset_ptr, packet_length - *offset_ptr, SSH_DECODE_UINT16(&qtype), SSH_DECODE_UINT16(&qclass), SSH_FORMAT_END); if (len == 0) { SSH_DEBUG(SSH_D_NETGARB, ("Error decoding question")); return FALSE; } *offset_ptr += len; question->qtype = qtype; question->qclass = qclass; return TRUE; }
Boolean ssh_channel_tcp_forward_cancel(const char *type, const unsigned char *data, size_t len, void *context) { SshCommon common = (SshCommon)context; char *address_to_bind; SshUInt32 port; char port_string[20]; SshRemoteTcpForward fwd, *fwdp; SshChannelTypeTcpForward ct; SSH_DEBUG(5, ("remote TCP/IP cancel request received")); ct = ssh_channel_ftcp_ct(common); /* Don't allow a server to send remote forwarding requests to the client. */ if (common->client) { ssh_warning("Remote TCP/IP forwarding cancel from server denied."); return FALSE; } /* Parse the request. */ if (ssh_decode_array(data, len, SSH_FORMAT_UINT32_STR, &address_to_bind, NULL, SSH_FORMAT_UINT32, &port, SSH_FORMAT_END) != len) { SSH_DEBUG(0, ("bad data")); return FALSE; } /* Convert port number to a string. */ snprintf(port_string, sizeof(port_string), "%ld", (unsigned long) port); for (fwdp = &ct->remote_forwards; *fwdp; fwdp = &fwd->next) { fwd = *fwdp; if (strcmp(port_string, fwd->port) == 0 && strcmp(address_to_bind, fwd->address_to_bind) == 0) { ssh_tcp_destroy_listener(fwd->listener); ssh_xfree(fwd->address_to_bind); ssh_xfree(fwd->port); *fwdp = fwd->next; ssh_xfree(fwd); ssh_xfree(address_to_bind); return TRUE; } } SSH_DEBUG(1, ("port %s address_to_bind %s not found", port_string, address_to_bind)); ssh_xfree(address_to_bind); return FALSE; }
void test_random_decode(void) { unsigned char buf[16]; size_t i, j; for(j = 0; j < 100; j++) { for (i = 0; i < sizeof(buf); i++) buf[i] = rand(); ssh_decode_array(buf, sizeof(buf), SSH_DECODE_UINT32_STR(NULL, NULL), SSH_FORMAT_END); ssh_decode_array(buf, sizeof(buf), SSH_DECODE_UINT32(NULL), SSH_FORMAT_END); ssh_decode_array(buf, sizeof(buf), SSH_DECODE_CHAR(NULL), SSH_FORMAT_END); ssh_decode_array(buf, sizeof(buf), SSH_DECODE_BOOLEAN(NULL), SSH_FORMAT_END); ssh_decode_array(buf, sizeof(buf), SSH_DECODE_DATA(NULL, 0), SSH_FORMAT_END); } }
void test_empty_decode(void) { if (ssh_decode_array((const unsigned char *) "", 0, SSH_DECODE_UINT32_STR(NULL, NULL), SSH_FORMAT_END) != 0) ssh_fatal("test_empty_decode failed"); if (ssh_decode_array((const unsigned char *) "", 0, SSH_DECODE_UINT32(NULL), SSH_FORMAT_END) != 0) ssh_fatal("test_empty_decode failed"); if (ssh_decode_array((const unsigned char *) "", 0, SSH_DECODE_CHAR(NULL), SSH_FORMAT_END) != 0) ssh_fatal("test_empty_decode failed"); if (ssh_decode_array((const unsigned char *) "", 0, SSH_DECODE_BOOLEAN(NULL), SSH_FORMAT_END) != 0) ssh_fatal("test_empty_decode failed"); if (ssh_decode_array((const unsigned char *) "", 0, SSH_DECODE_DATA(NULL, 0), SSH_FORMAT_END) != 0) ssh_fatal("test_empty_decode failed"); }
/* * Parse methods array. This doesn't do anything with SOCKS4. */ SocksError ssh_socks_server_parse_methods(SshBuffer buffer, SocksInfo *socksinfo) { size_t ret = 0L, len; unsigned int version, num_methods; unsigned char *data; data = ssh_buffer_ptr(buffer); len = ssh_buffer_len(buffer); if (len < 1) return SSH_SOCKS_TRY_AGAIN; version = *data; if (version == 4) goto return_success; if (len < 2) return SSH_SOCKS_TRY_AGAIN; ret = ssh_decode_array(data, len, SSH_DECODE_CHAR(&version), SSH_DECODE_CHAR(&num_methods), SSH_FORMAT_END); if (ret == 0) { SSH_DEBUG(2, ("Decoding methods buffer failed.")); return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } if (len < num_methods + 2) return SSH_SOCKS_TRY_AGAIN; ssh_buffer_consume(buffer, num_methods + 2); return_success: if (socksinfo) { *socksinfo = ssh_calloc(1, sizeof(**socksinfo)); if (*socksinfo == NULL) { SSH_DEBUG(2, ("Couldn't allocate SshSocksInfo.")); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } (*socksinfo)->socks_version_number = version; } return SSH_SOCKS_SUCCESS; }
void decode_case_char(SshEncodingFormat fmt, unsigned char value) { unsigned int ch; size_t bytes; bytes = ssh_buffer_len(buffer); if (bytes != ssh_decode_array(ssh_buffer_ptr(buffer), ssh_buffer_len(buffer), fmt, NULL, SSH_FORMAT_END)) ssh_fatal("decode_case_char: NULL decode bad len"); if (bytes != ssh_decode_buffer(buffer, fmt, &ch, SSH_FORMAT_END)) ssh_fatal("decode_case_char: bad returned len"); if (ch != value) ssh_fatal("decode_case_char: bad value"); if (ssh_buffer_len(buffer) > 0) ssh_fatal("decode_case_char: data left"); }
void decode_case_bool(SshEncodingFormat fmt, Boolean value) { Boolean boo; size_t bytes; bytes = ssh_buffer_len(buffer); if (bytes != ssh_decode_array(ssh_buffer_ptr(buffer), ssh_buffer_len(buffer), fmt, NULL, SSH_FORMAT_END)) ssh_fatal("decode_case_bool: NULL decode bad len"); if (bytes != ssh_decode_buffer(buffer, fmt, &boo, SSH_FORMAT_END)) ssh_fatal("decode_case_bool: bad returned len"); if (boo != value) ssh_fatal("decode_case_bool: bad value"); if (ssh_buffer_len(buffer) > 0) ssh_fatal("decode_case_bool: data left"); }
void decode_case_data(SshEncodingFormat fmt, const char *value, size_t valuelen) { char buf[1024]; size_t bytes; SSH_ASSERT(valuelen < sizeof(buf)); bytes = ssh_buffer_len(buffer); if (bytes != ssh_decode_array(ssh_buffer_ptr(buffer), ssh_buffer_len(buffer), fmt, NULL, valuelen, SSH_FORMAT_END)) ssh_fatal("decode_case_data: NULL decode bad len"); if (bytes != ssh_decode_buffer(buffer, fmt, buf, valuelen, SSH_FORMAT_END)) ssh_fatal("decode_case_data: bad returned len"); if (memcmp(buf, value, valuelen) != 0) ssh_fatal("decode_case_data: bad value"); if (ssh_buffer_len(buffer) > 0) ssh_fatal("decode_case_data: data left"); }
void decode_case_str(SshEncodingFormat fmt, const char *value, size_t valuelen) { unsigned char *cp; size_t len, bytes; bytes = ssh_buffer_len(buffer); if (bytes != ssh_decode_array(ssh_buffer_ptr(buffer), ssh_buffer_len(buffer), fmt, NULL, NULL, SSH_FORMAT_END)) ssh_fatal("decode_case_str: NULL decode bad len"); if (bytes != ssh_decode_buffer(buffer, fmt, &cp, &len, SSH_FORMAT_END)) ssh_fatal("decode_case_str: bad returned len"); if (len != valuelen || memcmp(cp, value, len) != 0) ssh_fatal("decode_case_str: bad cmp"); if (ssh_buffer_len(buffer) > 0) ssh_fatal("decode_case_str: data left"); if (cp[len] != 0) ssh_fatal("decode_case_str: not null terminated"); ssh_xfree(cp); }
void ssh_engine_from_ipm_set_debug(SshEngine engine, const unsigned char *data, size_t len) { char *s; /* Decode the packet. */ if (ssh_decode_array(data, len, SSH_FORMAT_UINT32_STR, &s, NULL, SSH_FORMAT_END) != len) { SSH_DEBUG_HEXDUMP(0, ("Bad set debug from policy manager"), data, len); return; } /* Set debug level according to the stringl. */ ssh_debug_set_level_string(s); SSH_DEBUG(1, ("Engine debug level set to %s", s)); ssh_free(s); }
Boolean ssh_virtual_adapter_param_decode(SshVirtualAdapterParams params, const unsigned char *data, size_t len) { unsigned char *dns; size_t dns_len; unsigned char *wins; size_t wins_len; unsigned char *win_domain; size_t win_domain_len; SshUInt32 netbios_node_type; SshUInt32 i; size_t decode_len; SSH_ASSERT(params != NULL); SSH_ASSERT(data != NULL); SSH_ASSERT(len > 0); memset(params, 0, sizeof(*params)); if (ssh_decode_array(data, len, SSH_DECODE_UINT32(¶ms->mtu), SSH_DECODE_UINT32(¶ms->dns_ip_count), SSH_DECODE_UINT32_STR_NOCOPY(&dns, &dns_len), SSH_DECODE_UINT32(¶ms->wins_ip_count), SSH_DECODE_UINT32_STR_NOCOPY(&wins, &wins_len), SSH_DECODE_UINT32_STR_NOCOPY( &win_domain, &win_domain_len), SSH_DECODE_UINT32(&netbios_node_type), SSH_FORMAT_END) != len) return FALSE; /* DNS. */ if (params->dns_ip_count) { params->dns_ip = ssh_calloc(params->dns_ip_count, sizeof(*params->dns_ip)); if (params->dns_ip == NULL) goto error; for (i = 0; i < params->dns_ip_count; i++) { decode_len = ssh_decode_ipaddr_array(dns, dns_len, ¶ms->dns_ip[i]); if (decode_len == 0) goto error; dns += decode_len; dns_len -= decode_len; } } /* WINS. */ if (params->wins_ip_count) { params->wins_ip = ssh_calloc(params->wins_ip_count, sizeof(*params->wins_ip)); if (params->wins_ip == NULL) goto error; for (i = 0; i < params->wins_ip_count; i++) { decode_len = ssh_decode_ipaddr_array(wins, wins_len, ¶ms->wins_ip[i]); if (decode_len == 0) goto error; wins += decode_len; wins_len -= decode_len; } } if (win_domain_len) { params->win_domain = ssh_memdup(win_domain, win_domain_len); if (params->win_domain == NULL) goto error; } params->netbios_node_type = (SshUInt8) netbios_node_type; return TRUE; error: ssh_free(params->dns_ip); ssh_free(params->wins_ip); ssh_free(params->win_domain); memset(params, 0, sizeof(*params)); return FALSE; }
void ssh_channel_ftcp_open_request(const char *type, int channel_id, const unsigned char *data, size_t len, SshConnOpenCompletionProc completion, void *completion_context, void *context) { SshCommon common = (SshCommon)context; SshUInt32 port, originator_port; char *address_to_bind, *originator_ip; char port_string[20]; SshRemoteTcpForward fwd; SshChannelTcpFwdConnect c; SshChannelTypeTcpForward ct; SSH_DEBUG(5, ("open request for remote forwarded TCP/IP channel")); ct = ssh_channel_ftcp_ct(common); if (ssh_decode_array(data, len, SSH_FORMAT_UINT32_STR, &address_to_bind, NULL, SSH_FORMAT_UINT32, &port, SSH_FORMAT_UINT32_STR, &originator_ip, NULL, SSH_FORMAT_UINT32, &originator_port, SSH_FORMAT_END) != len) { /* XXX should disconnect? */ SSH_DEBUG(0, ("bad data")); (*completion)(SSH_OPEN_RESOURCE_SHORTAGE, NULL, FALSE, FALSE, 0, NULL, 0, NULL, NULL, NULL, completion_context); return; } snprintf(port_string, sizeof(port_string), "%ld", (long) port); ssh_debug("Received remote TCP/IP forward connect for port %s from %s:%ld", port_string, originator_ip, (long)originator_port); for (fwd = ct->remote_forwards; fwd; fwd = fwd->next) if (strcmp(fwd->address_to_bind, address_to_bind) == 0 && strcmp(fwd->port, port_string) == 0) { c = ssh_xcalloc(1, sizeof(*c)); c->fwd = fwd; c->channel_id = channel_id; c->completion = completion; c->completion_context = completion_context; ssh_tcp_connect_with_socks(fwd->connect_to_host, fwd->connect_to_port, NULL, 1, ssh_channel_ftcp_open_connected, (void *)c); ssh_xfree(address_to_bind); ssh_xfree(originator_ip); return; } ssh_warning("Received remote TCP/IP connect for non-forwarded port %s from %s:%ld", port_string, originator_ip, (long)originator_port); ssh_xfree(address_to_bind); ssh_xfree(originator_ip); (*completion)(SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, NULL, FALSE, FALSE, 0, NULL, 0, NULL, NULL, NULL, completion_context); }
/* Decode packet. This returns NULL if there is memory error or parse error, otherwise it will return the decoded packet. */ SshDNSPacket ssh_dns_packet_decode(const unsigned char *packet_buffer, size_t packet_length) { SshUInt16 question_count, answer_count, authority_count, additional_count; SshUInt16 id, flags; SshDNSPacket packet; size_t len; int i; len = ssh_decode_array(packet_buffer, packet_length, SSH_DECODE_UINT16(&id), SSH_DECODE_UINT16(&flags), SSH_DECODE_UINT16(&question_count), SSH_DECODE_UINT16(&answer_count), SSH_DECODE_UINT16(&authority_count), SSH_DECODE_UINT16(&additional_count), SSH_FORMAT_END); if (len == 0) { SSH_DEBUG(SSH_D_NETGARB, ("Error decoding dns packet")); return NULL; } packet = ssh_dns_packet_allocate(question_count, answer_count, authority_count, additional_count); if (packet == NULL) return NULL; packet->id = id; packet->flags = flags & SSH_DNS_FLAG_MASK; packet->op_code = (flags >> 11) & 0xf; packet->response_code = flags & 0xf; for (i = 0; i < question_count; i++) { if (!ssh_dns_packet_decode_question(packet, packet_buffer, packet_length, &len, &(packet->question_array[i]))) goto error; } for (i = 0; i < answer_count; i++) { if (!ssh_dns_packet_decode_record(packet, packet_buffer, packet_length, &len, &(packet->answer_array[i]))) goto error; } for (i = 0; i < authority_count; i++) { if (!ssh_dns_packet_decode_record(packet, packet_buffer, packet_length, &len, &(packet->authority_array[i]))) goto error; } for (i = 0; i < additional_count; i++) { if (!ssh_dns_packet_decode_record(packet, packet_buffer, packet_length, &len, &(packet->additional_array[i]))) goto error; } if (packet_length > len) { SSH_DEBUG(SSH_D_NETGARB, ("Dns packet contains %d bytes of extra data", packet_length - len)); } return packet; error: ssh_dns_packet_free(packet); return NULL; }
/* Decode record. */ Boolean ssh_dns_packet_decode_record(SshDNSPacket packet, const unsigned char *packet_buffer, size_t packet_length, size_t *offset_ptr, SshDNSRecord record) { SshUInt16 type, dns_class, rdlength; size_t len, len2, new_rdlength, offset, offset2; if (!ssh_dns_packet_decode_name(packet, packet_buffer, packet_length, offset_ptr, &record->name)) return FALSE; len = ssh_decode_array(packet_buffer + *offset_ptr, packet_length - *offset_ptr, SSH_DECODE_UINT16(&type), SSH_DECODE_UINT16(&dns_class), SSH_DECODE_UINT32(&record->ttl), SSH_DECODE_UINT16(&rdlength), SSH_FORMAT_END); if (len == 0) { SSH_DEBUG(SSH_D_NETGARB, ("Error decoding record")); return FALSE; } if (*offset_ptr + len + rdlength > packet_length) { SSH_DEBUG(SSH_D_NETGARB, ("Data length in record exceeds packet size")); return FALSE; } record->type = type; record->dns_class = dns_class; *offset_ptr += len; switch (record->type) { /* One compressed name. Copy rest. */ case SSH_DNS_RESOURCE_NS: case SSH_DNS_RESOURCE_MD: case SSH_DNS_RESOURCE_MF: case SSH_DNS_RESOURCE_CNAME: case SSH_DNS_RESOURCE_MB: case SSH_DNS_RESOURCE_MG: case SSH_DNS_RESOURCE_MR: case SSH_DNS_RESOURCE_PTR: case SSH_DNS_RESOURCE_NSAP_PTR: case SSH_DNS_RESOURCE_NXT: case SSH_DNS_RESOURCE_DNAME: /* Do not compress, but do decompress. */ case SSH_DNS_RESOURCE_NSEC: /* Do not compress, but do decompress. */ offset = *offset_ptr; len = ssh_dns_packet_decode_name_len(packet_buffer, packet_length, offset_ptr); if (len == 0) return FALSE; new_rdlength = len + rdlength - (*offset_ptr - offset); record->rdata = ssh_obstack_alloc(packet->obstack, new_rdlength); ssh_dns_packet_decode_name_copy(packet_buffer, packet_length, offset, record->rdata); memcpy(record->rdata + len, packet_buffer + *offset_ptr, new_rdlength - len); *offset_ptr += new_rdlength - len; break; /* Two domain name addresses, copy rest. */ case SSH_DNS_RESOURCE_SOA: case SSH_DNS_RESOURCE_MINFO: case SSH_DNS_RESOURCE_RP: offset = *offset_ptr; len = ssh_dns_packet_decode_name_len(packet_buffer, packet_length, offset_ptr); if (len == 0) return FALSE; offset2 = *offset_ptr; len2 = ssh_dns_packet_decode_name_len(packet_buffer, packet_length, offset_ptr); if (len2 == 0) return FALSE; new_rdlength = len + len2 + rdlength - (*offset_ptr - offset); record->rdata = ssh_obstack_alloc(packet->obstack, new_rdlength); ssh_dns_packet_decode_name_copy(packet_buffer, packet_length, offset, record->rdata); ssh_dns_packet_decode_name_copy(packet_buffer, packet_length, offset2, record->rdata + len); memcpy(record->rdata + len + len2, packet_buffer + *offset_ptr, new_rdlength - len - len2); *offset_ptr += new_rdlength - len - len2; break; /* 16-bit number and dns name. */ case SSH_DNS_RESOURCE_MX: case SSH_DNS_RESOURCE_AFSDB: case SSH_DNS_RESOURCE_RT: case SSH_DNS_RESOURCE_KX: /* Do not compress, but do decompress. */ len2 = 2; copy_name_copy: offset = *offset_ptr; *offset_ptr += len2; len = ssh_dns_packet_decode_name_len(packet_buffer, packet_length, offset_ptr); if (len == 0) return FALSE; new_rdlength = len2 + len + rdlength - (*offset_ptr - offset); record->rdata = ssh_obstack_alloc(packet->obstack, new_rdlength); memcpy(record->rdata, packet_buffer + offset, len2); ssh_dns_packet_decode_name_copy(packet_buffer, packet_length, offset + len2, record->rdata + len2); memcpy(record->rdata + len2 + len, packet_buffer + *offset_ptr, new_rdlength - len2 - len); *offset_ptr += new_rdlength - len2 - len; break; /* Copy 9 bytes, then decompress signers name, and then copy rest. */ case SSH_DNS_RESOURCE_SIG: case SSH_DNS_RESOURCE_RRSIG: /* Docompress, must not compress */ len2 = 9; goto copy_name_copy; /* 16-bit number and 2 dns names. */ case SSH_DNS_RESOURCE_PX: offset = *offset_ptr; *offset_ptr += 2; len = ssh_dns_packet_decode_name_len(packet_buffer, packet_length, offset_ptr); if (len == 0) return FALSE; offset2 = *offset_ptr; len2 = ssh_dns_packet_decode_name_len(packet_buffer, packet_length, offset_ptr); if (len2 == 0) return FALSE; new_rdlength = len + len2 + rdlength - (*offset_ptr - offset); record->rdata = ssh_obstack_alloc(packet->obstack, new_rdlength); memcpy(record->rdata, packet_buffer + offset, 2); ssh_dns_packet_decode_name_copy(packet_buffer, packet_length, offset + 2, record->rdata + 2); ssh_dns_packet_decode_name_copy(packet_buffer, packet_length, offset2, record->rdata + len + 2); memcpy(record->rdata + 2 + len + len2, packet_buffer + *offset_ptr, new_rdlength - 2 - len - len2); *offset_ptr += new_rdlength - 2 - len - len2; break; /* 3 16-bit numbers and dns name. */ case SSH_DNS_RESOURCE_SRV: /* Do not compress, but do decompress */ len2 = 6; goto copy_name_copy; /* Special handling. */ case SSH_DNS_RESOURCE_OPT: /* The special OPT handling is to parse the data and then copy it. i.e. we will fall through to the next case. */ packet->response_code |= ((record->ttl & 0xff000000) >> 24) << 4; /* We leave rest of the special stuff (i.e. senders UDP payload size version, extra flags, etc in the class, ttl etc fields, and there might be some attribute value pairs also). */ /* Just copy data. */ case SSH_DNS_RESOURCE_A: case SSH_DNS_RESOURCE_NULL: case SSH_DNS_RESOURCE_WKS: case SSH_DNS_RESOURCE_HINFO: case SSH_DNS_RESOURCE_TXT: case SSH_DNS_RESOURCE_X25: case SSH_DNS_RESOURCE_ISDN: case SSH_DNS_RESOURCE_NSAP: case SSH_DNS_RESOURCE_KEY: case SSH_DNS_RESOURCE_GPOS: case SSH_DNS_RESOURCE_AAAA: case SSH_DNS_RESOURCE_LOC: case SSH_DNS_RESOURCE_NAPTR: /* Contains name, and rfc2168 says it is compressed, but rfc2915 says that will not be compressed. */ case SSH_DNS_RESOURCE_CERT: case SSH_DNS_RESOURCE_A6: /* Contains name, but MUST NOT be compr. */ case SSH_DNS_RESOURCE_APL: case SSH_DNS_RESOURCE_DS: case SSH_DNS_RESOURCE_SSHFP: case SSH_DNS_RESOURCE_DNSKEY: case SSH_DNS_QUERY_TKEY: case SSH_DNS_QUERY_TSIG: /* Unknown, just copy. */ case SSH_DNS_RESOURCE_EID: case SSH_DNS_RESOURCE_NIMLOC: case SSH_DNS_RESOURCE_ATMA: case SSH_DNS_RESOURCE_SINK: case SSH_DNS_RESOURCE_UINFO: case SSH_DNS_RESOURCE_UID: case SSH_DNS_RESOURCE_GID: case SSH_DNS_RESOURCE_UNSPEC: /* Query typedef values which do not appear in resource records, copy */ case SSH_DNS_QUERY_IXFR: case SSH_DNS_QUERY_AXFR: case SSH_DNS_QUERY_MAILB: case SSH_DNS_QUERY_MAILA: case SSH_DNS_QUERY_ANY: default: record->rdata = ssh_obstack_memdup(packet->obstack, packet_buffer + *offset_ptr, rdlength); *offset_ptr += rdlength; new_rdlength = rdlength; break; } record->rdlength = new_rdlength; return TRUE; }
static void receive_virtual_adapter_packet_cb(SshInterceptor interceptor, const unsigned char *data, size_t len) { SshUInt32 flags; SshUInt32 ifnum_in, ifnum_out; SshUInt32 protocol; const unsigned char *packet, *internal; size_t packet_len, internal_len; SshInterceptorVirtualAdapter va; SshInterceptorPacket pp; if (ssh_decode_array(data, len, SSH_FORMAT_UINT32, &flags, SSH_FORMAT_UINT32, &ifnum_in, SSH_FORMAT_UINT32, &ifnum_out, SSH_FORMAT_UINT32, &protocol, SSH_FORMAT_UINT32_STR_NOCOPY, &packet, &packet_len, SSH_FORMAT_UINT32_STR_NOCOPY, &internal, &internal_len, SSH_FORMAT_END) != len) { SSH_DEBUG_HEXDUMP(SSH_D_ERROR, ("bad virtual adapter receive message"), data, len); return; } /* Find the virtual adapter of this receive operation. */ ssh_mutex_lock(interceptor->mutex); for (va = interceptor->virtual_adapters; va; va = va->next) if (va->adapter_ifnum == ifnum_in) break; ssh_mutex_unlock(interceptor->mutex); if (va == NULL) { SSH_DEBUG(SSH_D_ERROR, ("virtual adapter receive for unknown adapter %d", (int) ifnum_in)); return; } if (va->packet_cb == NULL_FNPTR) return; /* Assert that the interface numbers fit into SshInterceptorIfnum. */ SSH_ASSERT(ifnum_in <= SSH_INTERCEPTOR_MAX_IFNUM); SSH_ASSERT(ifnum_out <= SSH_INTERCEPTOR_MAX_IFNUM); /* Allocate a packet object. */ pp = ssh_interceptor_packet_alloc(interceptor, SSH_PACKET_FROMADAPTER, protocol, (SshInterceptorIfnum) ifnum_in, (SshInterceptorIfnum) ifnum_out, packet_len); if (pp == NULL) { SSH_DEBUG(SSH_D_ERROR, ("could not allocate packet for virtual adapter receive")); return; } if (!ssh_interceptor_packet_import_internal_data(pp, internal, internal_len)) { SSH_DEBUG(SSH_D_ERROR, ("import failed")); return; } pp->flags = flags; if (!ssh_interceptor_packet_copyin(pp, 0, packet, packet_len)) { SSH_DEBUG(SSH_D_ERROR, ("copyin failed, dropping packet")); return; } SSH_DEBUG(SSH_D_NICETOKNOW, ("received packet callback for virtual adapter %d from forwarder.", (int) ifnum_in)); /* Pass the packet to the user-supplied packet callback. */ (*va->packet_cb)(interceptor, pp, va->adapter_context); }
static void receive_virtual_adapter_status_cb(SshInterceptor interceptor, const unsigned char *data, size_t len) { SshUInt32 operation_id; SshUInt32 error; SshUInt32 adapter_ifnum; char *adapter_name; SshUInt32 adapter_state; SshInterceptorVirtualAdapterOp op; SshInterceptorVirtualAdapter va; void *adapter_context; if (ssh_decode_array(data, len, SSH_FORMAT_UINT32, &operation_id, SSH_FORMAT_UINT32, &error, SSH_FORMAT_UINT32, &adapter_ifnum, SSH_FORMAT_UINT32_STR_NOCOPY, &adapter_name, NULL, SSH_FORMAT_UINT32, &adapter_state, SSH_FORMAT_END) != len) { SSH_DEBUG_HEXDUMP(SSH_D_ERROR, ("bad virtual adapter status message"), data, len); return; } /* Lookup the pending operation. */ op = lookup_virtual_adapter_op(interceptor, operation_id); if (op == NULL) { SSH_DEBUG(SSH_D_ERROR, ("unknown virtual adapter operation ID %d", (int) operation_id)); return; } /* Handle attach operations separately. */ if (op->attach) { receive_virtual_adapter_attach_cb(interceptor, error, adapter_ifnum, adapter_name, adapter_state, op); return; } /* Is the operation aborted? */ if (op->aborted) { /* Free the operation context. */ free_virtual_adapter_op(interceptor, op); return; } /* Lookup virtual adapter. */ ssh_mutex_lock(interceptor->mutex); for (va = interceptor->virtual_adapters; va; va = va->next) if (va->adapter_ifnum == adapter_ifnum) break; ssh_mutex_unlock(interceptor->mutex); /* Take adapter context from virtual adapter, if it was found. */ if (va == NULL) adapter_context = op->adapter_context; else adapter_context = va->adapter_context; SSH_DEBUG(SSH_D_NICETOKNOW, ("received status callback for virtual adapter %d from forwarder, " "error %d", (int) adapter_ifnum, (int) error)); /* Call the completion function. */ if (op->status_cb) (*op->status_cb)((SshVirtualAdapterError) error, (SshInterceptorIfnum) adapter_ifnum, adapter_name, (SshVirtualAdapterState) adapter_state, adapter_context, op->context); /* Free operation context if there will be no more status callbacks to this operation. */ if (error != SSH_VIRTUAL_ADAPTER_ERROR_OK_MORE) { /* Unregister operation handle and free operation context. */ ssh_operation_unregister(op->handle); free_virtual_adapter_op(interceptor, op); } }
/* * Parse incoming socks connection from buffer. Consume the request * packet data from buffer. If everything is ok it allocates SocksInfo * strcture and store the request fields in it (sets * socks_version_number, command_code, ip, port, username). Returns * SSH_SOCKS_SUCCESS, SSH_SOCKS_TRY_AGAIN, or SSH_SOCKS_ERROR_*. If * anything other than SSH_SOCKS_SUCCESS is returned the socksinfo is * set to NULL. Use ssh_socks_free to free socksinfo data. */ SocksError ssh_socks_server_parse_open(SshBuffer buffer, SocksInfo *socksinfo) { unsigned char *data, *ip; unsigned long i, port; unsigned int version, cmd, ip_addr_len, atyp; unsigned char *username = NULL; size_t ret, len, bytes = 0; *socksinfo = NULL; len = ssh_buffer_len(buffer); data = ssh_buffer_ptr(buffer); if (len < 1) return SSH_SOCKS_TRY_AGAIN; version = data[0]; bytes++; if (version != 4 && version != 5) { SSH_DEBUG(2, ("Server gave us version %d.", version)); return SSH_SOCKS_ERROR_UNSUPPORTED_SOCKS_VERSION; } if (version == 4) { /* Check if enough data for header and name */ if (len < SOCKS4_COMMAND_SIZE + 1) { return SSH_SOCKS_TRY_AGAIN; } /* Find the end of username */ for (i = SOCKS4_COMMAND_SIZE; i < len; i++) { if (data[i] == '\0') break; } /* End of username not found, return either error or try_again */ if (i == len || data[i] != '\0') { if (len > SOCKS4_COMMAND_SIZE + SOCKS4_MAX_NAME_LEN) { return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } return SSH_SOCKS_TRY_AGAIN; } cmd = data[1]; port = SSH_GET_16BIT(&data[2]); ip_addr_len = 4; ip = ssh_memdup(&data[4], ip_addr_len); atyp = SSH_SOCKS5_ATYP_IPV4; if (ip == NULL) { SSH_DEBUG(2, ("Failed to allocate IP-address buffer.")); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } username = ssh_strdup((char *)(data + SOCKS4_COMMAND_SIZE)); bytes = SOCKS4_COMMAND_SIZE + strlen((char *) data + SOCKS4_COMMAND_SIZE) + 1; } else { unsigned char port_buf[2]; if (len - bytes < 3) return SSH_SOCKS_TRY_AGAIN; ret = ssh_decode_array(data + bytes, len - bytes, SSH_DECODE_CHAR(&cmd), SSH_DECODE_CHAR(NULL), /* RSV */ SSH_DECODE_CHAR(&atyp), SSH_FORMAT_END); if (ret <= 0) { SSH_DEBUG(2, ("Failed to decode command packet.")); return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } bytes += ret; if (atyp == SSH_SOCKS5_ATYP_IPV4) { SSH_DEBUG(4, ("SOCKS5 received address type IPV4.")); ip_addr_len = 4; } else if (atyp == SSH_SOCKS5_ATYP_IPV6) { SSH_DEBUG(4, ("SOCKS5 received address type IPV6.")); ip_addr_len = 16; } else if (atyp == SSH_SOCKS5_ATYP_FQDN) { if (len - bytes < 1) return SSH_SOCKS_TRY_AGAIN; ip_addr_len = *(data + bytes); if (ip_addr_len <= 0 || ip_addr_len >= 255) { SSH_DEBUG(2, ("Invalid FQDN address len %d.", ip_addr_len)); return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } SSH_DEBUG(4, ("SOCKS5 received address type FQDN, len %d.", ip_addr_len)); bytes++; } else { SSH_DEBUG(2, ("Invalid address type %d.", atyp)); return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } /* ip addr len + port */ if (len - bytes < ip_addr_len + 2) return SSH_SOCKS_TRY_AGAIN; ip = ssh_calloc(ip_addr_len + 1, sizeof(unsigned char)); if (ip == NULL) { SSH_DEBUG(2, ("Failed to allocate IP-address buffer.")); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } ret = ssh_decode_array(data + bytes, len - bytes, SSH_DECODE_DATA(ip, ip_addr_len), SSH_DECODE_DATA(port_buf, 2), SSH_FORMAT_END); if (ret <= 0) { SSH_DEBUG(2, ("Failed to decode command packet.")); ssh_free(ip); return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } port = SSH_GET_16BIT(port_buf); bytes += ret; } if ((*socksinfo = ssh_calloc(1, sizeof(struct SocksInfoRec))) == NULL) { SSH_DEBUG(2, ("Failed to allocate SocksInfo.")); ssh_free(ip); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } if (atyp == SSH_SOCKS5_ATYP_FQDN) { (*socksinfo)->ip = ip; } else { SshIpAddrStruct ip_addr; unsigned char buf[SSH_IP_ADDR_STRING_SIZE]; SSH_IP_DECODE(&ip_addr, ip, ip_addr_len); ssh_ipaddr_print(&ip_addr, buf, sizeof(buf)); (*socksinfo)->ip = ssh_memdup(buf, ssh_ustrlen(buf)); ssh_free(ip); if ((*socksinfo)->ip == NULL) { SSH_DEBUG(2, ("Failed to allocate final IP-addr buf.")); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } } (*socksinfo)->socks_version_number = version; (*socksinfo)->command_code = cmd; ssh_dsprintf(&(*socksinfo)->port, "%lu", port); (*socksinfo)->username = username; ssh_buffer_consume(buffer, bytes); SSH_DEBUG(5, ("Decoded %zd bytes.", bytes)); return SSH_SOCKS_SUCCESS; }
/* * Parse socks reply packet. Consume the reply packet data from buffer. * If the request was not granted (returns SSH_SOCKS_FAILED_*) the socket can * be immediately closed down (there will not be any additional data from the * socks server. * If the request is granted allocate socksinfo structure and store information * from request packet to there (sets socks_version_number, command_code, ip, * and port fields). * Use ssh_socks_free to free socksinfo data. */ SocksError ssh_socks_client_parse_reply(SshBuffer buffer, SocksInfo *socksinfo) { unsigned char *data, *ip_ptr, *port_ptr; unsigned char *username =NULL; unsigned long len, port, version; size_t bytes = 0; unsigned int cmd, atyp, ip_addr_len; if (socksinfo) *socksinfo = NULL; len = ssh_buffer_len(buffer); data = ssh_buffer_ptr(buffer); /* Check if enough data for version. */ if (len < 1) return SSH_SOCKS_TRY_AGAIN; version = data[0]; /* SOCKS4 replys have version number '0'. Go figure. */ if (version == 0) version = 4; bytes++; if (version != 4 && version != 5) { SSH_DEBUG(2, ("Server gave us version %ld.", version)); return SSH_SOCKS_ERROR_UNSUPPORTED_SOCKS_VERSION; } if (version == 4) { /* A SOCKS4 command reply is exactly 8 bytes long. */ if (len < 8) return SSH_SOCKS_TRY_AGAIN; SSH_DEBUG(2, ("Doing SOCKS4.")); bytes = 8; if (data[1] != SSH_SOCKS4_REPLY_GRANTED) { SocksError error = SSH_SOCKS_ERROR_PROTOCOL_ERROR; switch (data[1]) { case SSH_SOCKS4_REPLY_FAILED_REQUEST: error = SSH_SOCKS_FAILED_REQUEST; break; case SSH_SOCKS4_REPLY_FAILED_IDENTD: error = SSH_SOCKS_FAILED_IDENTD; break; case SSH_SOCKS4_REPLY_FAILED_USERNAME: error = SSH_SOCKS_FAILED_USERNAME; break; default: error = SSH_SOCKS_ERROR_PROTOCOL_ERROR; break; } ssh_buffer_consume(buffer, bytes); return error; } cmd = data[1]; port_ptr = &data[2]; ip_ptr = &data[4]; ip_addr_len = 4; atyp = SSH_SOCKS5_ATYP_IPV4; username = (unsigned char *)&data[8]; } else { size_t ret = 0L; /* SOCKS5. */ if (len - bytes < 3) return SSH_SOCKS_TRY_AGAIN; ret = ssh_decode_array(data + bytes, len - bytes, SSH_DECODE_CHAR(&cmd), SSH_DECODE_CHAR(NULL), /* RSV */ SSH_DECODE_CHAR(&atyp), SSH_FORMAT_END); if (ret == 0) { SSH_DEBUG(2, ("Decoding reply packet failed.")); return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } bytes += ret; if (atyp == SSH_SOCKS5_ATYP_IPV4) { ip_addr_len = 4; } else if (atyp == SSH_SOCKS5_ATYP_IPV6) { ip_addr_len = 16; } else if (atyp == SSH_SOCKS5_ATYP_FQDN) { if (len - bytes < 1) return SSH_SOCKS_TRY_AGAIN; ret = ssh_decode_array(data + bytes, len - bytes, SSH_DECODE_CHAR(&ip_addr_len), SSH_FORMAT_END); if (ret == 0) { SSH_DEBUG(2, ("Decoding FQDN hostname len failed.")); return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } bytes += ret; } else { SSH_DEBUG(2, ("Invalid address type %d.", atyp)); return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } /* ip addr len + port (2 bytes) */ if (len - bytes < ip_addr_len + 2) return SSH_SOCKS_TRY_AGAIN; ip_ptr = data + bytes; if (ret == 0) { SSH_DEBUG(2, ("Decoding reply packet failed.")); return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } bytes += ip_addr_len; port_ptr = data + bytes; bytes += 2; SSH_DEBUG(2, ("Doing SOCKS5.")); if (cmd != SSH_SOCKS5_REPLY_SUCCESS) { SSH_DEBUG(2, ("Got reply %d from server.", cmd)); if (cmd < SSH_SOCKS5_REPLY_SUCCESS || cmd > SSH_SOCKS5_REPLY_ATYP_NOT_SUPPORTED) return SSH_SOCKS_ERROR_PROTOCOL_ERROR; return SSH_SOCKS_FAILED_REQUEST; } } if (socksinfo) { SshIpAddrStruct ip_addr; if ((*socksinfo = ssh_calloc(1, sizeof(SocksInfoStruct))) == NULL) { SSH_DEBUG(2, ("Couldn't allocate SocksInfo.")); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } memset(&ip_addr, 0, sizeof(ip_addr)); (*socksinfo)->socks_version_number = version; (*socksinfo)->command_code = cmd; port = SSH_GET_16BIT(port_ptr); ssh_dsprintf(&(*socksinfo)->port, "%lu", port); if (username) (*socksinfo)->username = ssh_strdup(username); else (*socksinfo)->username = NULL; if (atyp == SSH_SOCKS5_ATYP_FQDN) { (*socksinfo)->ip = ssh_calloc(ip_addr_len + 1, sizeof(char)); if ((*socksinfo)->ip) memmove((*socksinfo)->ip, ip_ptr, ip_addr_len); } else { unsigned char buf[SSH_IP_ADDR_STRING_SIZE]; SSH_IP_DECODE(&ip_addr, ip_ptr, ip_addr_len); ssh_ipaddr_print(&ip_addr, buf, sizeof(buf) - 1); (*socksinfo)->ip = ssh_strdup(buf); } } SSH_DEBUG(2, ("Decoded %zd bytes.", bytes)); ssh_buffer_consume(buffer, bytes); return SSH_SOCKS_SUCCESS; }
void ssh_channel_dtcp_open_request(const char *type, int channel_id, const unsigned char *data, size_t len, SshConnOpenCompletionProc completion, void *completion_context, void *context) { SshCommon common = (SshCommon)context; char *connect_to_host, connect_to_port[20], *originator_ip; SshUInt32 port, originator_port; SshDirectTcp tcp; SSH_DEBUG(5, ("direct TCP/IP channel open request")); /* Parse packet data. */ if (ssh_decode_array(data, len, SSH_FORMAT_UINT32_STR, &connect_to_host, NULL, SSH_FORMAT_UINT32, &port, SSH_FORMAT_UINT32_STR, &originator_ip, NULL, SSH_FORMAT_UINT32, &originator_port, SSH_FORMAT_END) != len) { /* XXX disconnect? */ SSH_DEBUG(0, ("bad data")); (*completion)(SSH_OPEN_RESOURCE_SHORTAGE, NULL, FALSE, FALSE, 0, NULL, 0, NULL, NULL, NULL, completion_context); return; } /* We do not currently allow direct connections from server to client. */ if (common->client) { ssh_warning("Direct TCP/IP connection request from server " "to %s:%ld denied.", connect_to_host, (long)port); /* Free dynamically allocated data. */ ssh_xfree(originator_ip); ssh_xfree(connect_to_host); (*completion)(SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, NULL, FALSE, FALSE, 0, NULL, 0, NULL, NULL, NULL, completion_context); return; } /* Convert port number to string. */ snprintf(connect_to_port, sizeof(connect_to_port), "%ld", (long) port); ssh_debug("Direct TCP/IP connect to %s:%s from %s:%ld", connect_to_host, connect_to_port, originator_ip, (long)originator_port); /* Save data for callback. */ tcp = ssh_xcalloc(1, sizeof(*tcp)); tcp->common = common; tcp->channel_id = channel_id; tcp->completion = completion; tcp->completion_context = completion_context; /* Connect to the given host/port. */ ssh_tcp_connect_with_socks(connect_to_host, connect_to_port, NULL, 1, ssh_channel_dtcp_connected, (void *)tcp); /* Free dynamically allocated data. */ ssh_xfree(originator_ip); ssh_xfree(connect_to_host); }
Boolean ssh_channel_remote_tcp_forward_request(const char *type, const unsigned char *data, size_t len, void *context) { SshCommon common = (SshCommon)context; char *address_to_bind; SshUInt32 port; char port_string[20]; SshRemoteTcpForward fwd; SshChannelTypeTcpForward ct; SSH_DEBUG(5, ("remote TCP/IP forwarding request received")); ssh_log_event(common->config->log_facility, SSH_LOG_INFORMATIONAL, "Remote TCP/IP forwarding request received from host \"%s\", "\ "by authenticated user \"%s\".", common->remote_host, ssh_user_name(common->user_data)); ct = ssh_channel_ftcp_ct(common); /* Don't allow a server to send remote forwarding requests to the client. */ if (common->client) { ssh_warning("Remote TCP/IP forwarding request from server denied."); return FALSE; } /* Parse the request. */ if (ssh_decode_array(data, len, SSH_FORMAT_UINT32_STR, &address_to_bind, NULL, SSH_FORMAT_UINT32, &port, SSH_FORMAT_END) != len) { SSH_DEBUG(0, ("bad data")); return FALSE; } /* Convert port number to a string. */ snprintf(port_string, sizeof(port_string), "%ld", (unsigned long) port); /* If user is not logged in as a privileged user, don't allow forwarding of privileged ports. */ if (port < 1024) { if (ssh_user_uid(common->user_data)) { SSH_TRACE(2, ("User \"%s\" not root, tried to forward " \ "privileged port %ld.", ssh_user_name(common->user_data), (unsigned long) port)); ssh_log_event(common->config->log_facility, SSH_LOG_WARNING, "User \"%s\" not root, tried to forward " \ "privileged port %ld.", ssh_user_name(common->user_data), (unsigned long) port); return FALSE; } else { ssh_log_event(common->config->log_facility, SSH_LOG_NOTICE, "Privileged user \"%s\" forwarding a privileged port.", ssh_user_name(common->user_data)); } } if (port >= 65536) { SSH_TRACE(2, ("User \"%s\" tried to forward " \ "port above 65535 (%ld).", ssh_user_name(common->user_data), (unsigned long) port)); ssh_log_event(common->config->log_facility, SSH_LOG_WARNING, "User \"%s\" tried to forward " \ "port above 65535 (%ld).", ssh_user_name(common->user_data), (unsigned long) port); return FALSE; } /* Create a socket listener. */ fwd = ssh_xcalloc(1, sizeof(*fwd)); fwd->listener = ssh_tcp_make_listener(address_to_bind, port_string, ssh_channel_ftcp_incoming_connection, (void *)fwd); if (fwd->listener == NULL) { ssh_debug("Creating remote listener for %s:%s failed.", address_to_bind, port_string); ssh_log_event(common->config->log_facility, SSH_LOG_NOTICE, "Creating remote listener for %s:%s failed.", address_to_bind, port_string); ssh_xfree(address_to_bind); ssh_xfree(fwd); return FALSE; } /* Fill the remaining fields. */ fwd->common = common; fwd->address_to_bind = address_to_bind; fwd->port = ssh_xstrdup(port_string); fwd->connect_to_host = NULL; fwd->connect_to_port = NULL; /* Add to list of forwardings. */ fwd->next = ct->remote_forwards; ct->remote_forwards = fwd; ssh_log_event(common->config->log_facility, SSH_LOG_INFORMATIONAL, "Port %ld set up for remote forwarding.", (unsigned long) port); return TRUE; }
void ssh_acc_device_modexp_op_done(SshCryptoStatus status, const unsigned char *data, size_t data_len, void *context) { SshAccDeviceModExpContext ctx = context; ctx->sub_op = NULL; if (status == SSH_CRYPTO_OK) { /* No array decoding is needed. */ (*ctx->callback)(SSH_CRYPTO_OK, data, data_len, ctx->context); ssh_acc_device_modexp_op_free(ctx); return; } else { unsigned char *b, *e, *m, *ret; size_t b_len, e_len, mod_len, ret_len; /* The accelerated operation has failed, instead perform the operation in software. */ SSH_DEBUG(SSH_D_FAIL, ("Accelerated modexp operation has failed, " "now performing the operation in software")); /* Decode the data buffer to extract the original parameters */ if (ssh_decode_array(ctx->data, ctx->data_len, SSH_DECODE_UINT32_STR_NOCOPY(&b, &b_len), SSH_DECODE_UINT32_STR_NOCOPY(&e, &e_len), SSH_DECODE_UINT32_STR_NOCOPY(&m, &mod_len), SSH_FORMAT_END) != ctx->data_len) { (*ctx->callback)(SSH_CRYPTO_NO_MEMORY, NULL, 0, ctx->context); ssh_acc_device_modexp_op_free(ctx); return; } ret_len = mod_len; if ((ret = ssh_calloc(1, ret_len)) == NULL) { (*ctx->callback)(SSH_CRYPTO_NO_MEMORY, NULL, 0, ctx->context); ssh_acc_device_modexp_op_free(ctx); return; } if (modexp_op_buf(ret, ret_len, b, b_len, e, e_len, m, mod_len)) { (*ctx->callback)(SSH_CRYPTO_OK, ret, ret_len, ctx->context); } else { (*ctx->callback)(SSH_CRYPTO_OPERATION_FAILED, NULL, 0, ctx->context); } ssh_acc_device_modexp_op_free(ctx); ssh_free(ret); return; } }
void signer_received_packet(SshPacketType type, const unsigned char *data, size_t len, void *context) { /* Received. */ unsigned int msg_byte; /* This is unsigned int because SSH_FORMAT_CHAR expects uint; caused a rather nasty bug during development (I used SshUInt8, which wasn't long enough => ssh_decode_array blew the stack).*/ char *userauth_str, *hostbased_str, *recv_pubkey_alg, *recv_hostname; char *recv_username; unsigned char *recv_pubkeyblob; size_t recv_pubkeyblob_len; /* Dug up by us. */ char *pubkey_alg, *hostname, *username; unsigned char *pubkeyblob; size_t pubkeyblob_len; size_t hostname_len; /* Internal stuff*/ SshSigner signer = (SshSigner) context; char hostkeyfile[512]; char *comment; SshPrivateKey privkey; size_t sig_len, length_return; unsigned char *signature_buffer; SshCryptoStatus result; SshUser real_user; SSH_TRACE(2, ("Packet received.")); switch(type) { case SSH_AUTH_HOSTBASED_PACKET: /* Check packet out, and if it's ok, sign it and send signature to ssh2. */ #ifdef HEXDUMPS SSH_DEBUG_HEXDUMP(3, ("packet:"), \ data, len); #endif /* HEXDUMPS */ if (ssh_decode_array(data, len, /* session id */ SSH_FORMAT_UINT32_STR, NULL, NULL, /* SSH_MSG_USERAUTH_REQUEST (must be checked)*/ SSH_FORMAT_CHAR, &msg_byte, /* user name */ SSH_FORMAT_UINT32_STR, NULL, NULL, /* service "ssh-userauth" (must be checked)*/ SSH_FORMAT_UINT32_STR, &userauth_str, NULL, /* "hostbased" (must be checked)*/ SSH_FORMAT_UINT32_STR, &hostbased_str, NULL, /* public key algorithm for hostkey (must be checked)*/ SSH_FORMAT_UINT32_STR, &recv_pubkey_alg, NULL, /* public hostkey and certificates (must be checked)*/ SSH_FORMAT_UINT32_STR, &recv_pubkeyblob, &recv_pubkeyblob_len, /* client host name (must be checked)*/ SSH_FORMAT_UINT32_STR, &recv_hostname, NULL, /* user name on client host (must be checked) */ SSH_FORMAT_UINT32_STR, &recv_username, NULL, SSH_FORMAT_END) != len || len == 0) { /* There was an error. */ SSH_TRACE(0, ("Invalid packet.")); goto error; } /* Get pubkeyblob, pubkeyblob_len, pubkey_alg, hostname and username. */ /* Dig up hosts publickey. */ if(signer->config->public_host_key_file[0] != '/') { snprintf(hostkeyfile, sizeof(hostkeyfile), "%s/%s", SSH_SERVER_DIR, signer->config->public_host_key_file); } else { snprintf(hostkeyfile, sizeof(hostkeyfile), "%s", signer->config->public_host_key_file); } SSH_TRACE(2, ("place to look for public key: %s", hostkeyfile)); /* This pubkey*-stuff is for the client _host's_ public hostkey. */ /* Getting pubkeyblob, pubkeyblob_len */ SSH_DEBUG(4, ("Reading pubkey-blob from %s...", hostkeyfile)); if (ssh2_key_blob_read(signer->effective_user_data, hostkeyfile, NULL, &pubkeyblob, &pubkeyblob_len, NULL) != SSH_KEY_MAGIC_PUBLIC) { SSH_TRACE(1, ("Reading public key failed.")); goto error; } SSH_DEBUG(4, ("done.")); if ((pubkey_alg = ssh_pubkeyblob_type(pubkeyblob, pubkeyblob_len)) == NULL) { SSH_TRACE(1, ("Couldn't figure out public key algorithm.")); goto error; } /* Getting hostname. */ hostname = ssh_xmalloc(MAXHOSTNAMELEN + 1); ssh_tcp_get_host_name(hostname, MAXHOSTNAMELEN + 1); hostname_len = strlen(hostname); /* Sanity check */ SSH_ASSERT(hostname_len + 2 < MAXHOSTNAMELEN); /* We want FQDN. */ hostname[hostname_len] = '.'; hostname[hostname_len + 1] = '\0'; /* Getting username. */ real_user = ssh_user_initialize(NULL, FALSE); username = ssh_xstrdup(ssh_user_name(real_user)); ssh_user_free(real_user, FALSE); /* Check all parameters. */ if (msg_byte != SSH_MSG_USERAUTH_REQUEST) { SSH_TRACE(1, ("Invalid packet.")); SSH_DEBUG(1, ("msg_byte != SSH_MSG_USERAUTH_REQUEST " \ "(msg_byte = %d)", msg_byte)); goto error; } if (strcmp(userauth_str, SSH_USERAUTH_SERVICE) != 0) { SSH_TRACE(1, ("Invalid packet.")); SSH_DEBUG(1, ("userauth_str != \"ssh-userauth\" (it was '%s')", \ userauth_str)); goto error; } if (strcmp(hostbased_str, SSH_AUTH_HOSTBASED) != 0) { SSH_TRACE(1, ("Invalid packet.")); SSH_DEBUG(1, ("hostbased_str != \"hostbased\" (it was '%s')", \ hostbased_str)); goto error; } /* XXX has to be change when adding support for multiple hostkeys */ if (strcmp(recv_pubkey_alg, pubkey_alg) != 0) { SSH_TRACE(1, ("Invalid packet.")); SSH_DEBUG(1, ("Client gave us invalid pubkey-algorithms for our " \ "hostkey.")); goto error; } if (recv_pubkeyblob_len == pubkeyblob_len) { if (memcmp(recv_pubkeyblob, pubkeyblob, pubkeyblob_len) != 0) { SSH_TRACE(1, ("Invalid packet.")); SSH_DEBUG(1, ("client gave us wrong (or corrupted) " \ "public key.")); #ifdef HEXDUMPS SSH_DEBUG_HEXDUMP(3, ("client gave us:"), \ recv_pubkeyblob, pubkeyblob_len); SSH_DEBUG_HEXDUMP(3, ("our pubkey:"), \ recv_pubkeyblob, pubkeyblob_len); #endif /* HEXDUMPS */ goto error; } } else { SSH_TRACE(1, ("Invalid packet.")); SSH_DEBUG(1, ("Client gave us wrong (or corrupted) public key. " \ "Lengths differ (received: %d ; ours: %d)", \ recv_pubkeyblob_len, pubkeyblob_len)); goto error; } if (strcmp(recv_hostname, hostname) != 0) { SSH_TRACE(1, ("Invalid packet.")); SSH_DEBUG(1, ("Wethinks the client gave us the wrong hostname. " \ "(client's opinion: '%s' ours: '%s'", \ recv_hostname, hostname)); goto error; } if (strcmp(recv_username, username) != 0) { SSH_TRACE(1, ("Invalid packet.")); SSH_DEBUG(1, ("Client definitely gave us the wrong user name. " \ "(it says: '%s' we know: '%s')", recv_username, \ username)); goto error; } /* Sign the packet and send it to client. */ /* If we've gotten this far, the packet is ok, and it can be signed. */ SSH_TRACE(0, ("Received packet ok.")); if(signer->config->public_host_key_file[0] != '/') { snprintf(hostkeyfile, sizeof(hostkeyfile), "%s/%s", SSH_SERVER_DIR, signer->config->host_key_file); } else { snprintf(hostkeyfile, sizeof(hostkeyfile), "%s", signer->config->host_key_file); } SSH_TRACE(2, ("place to look for private key: %s", hostkeyfile)); if ((privkey = ssh_privkey_read(signer->effective_user_data, hostkeyfile, "", &comment, NULL)) == NULL) ssh_fatal("ssh_privkey_read from %s failed.", hostkeyfile); /* Check how big a chunk our private key can sign (this is purely a sanity check, as both of our signature schemas do their own hashing) */ sig_len = ssh_private_key_max_signature_input_len(privkey); SSH_TRACE(2, ("max input length for signing: %d", sig_len)); if (sig_len == 0) { SSH_TRACE(0, ("private key not capable of signing! " \ "(definitely an error)")); goto error; } else if (sig_len != -1 && sig_len < len) { SSH_TRACE(0, ("private key can't sign our data. (too much " \ "data (data_len %d, max input len for signing " \ "%d))", len, sig_len)); goto error; } /* Now check how much we much buffer we must allocate for the signature. */ sig_len = ssh_private_key_max_signature_output_len(privkey); SSH_TRACE(2, ("max output length for signature: %d", sig_len)); signature_buffer = ssh_xcalloc(sig_len, sizeof(unsigned char)); /* Do the actual signing. */ #ifdef HEXDUMPS SSH_DEBUG_HEXDUMP(5, ("Signing following data"), data + 4, len - 4); #endif /* HEXDUMPS */ if ((result = ssh_private_key_sign(privkey, data, len, signature_buffer, sig_len, &length_return, signer->random_state)) != SSH_CRYPTO_OK) { SSH_TRACE(0, ("ssh_private_key_sign() returned %d.", result)); goto error; } #ifdef HEXDUMPS SSH_DEBUG_HEXDUMP(5, ("Signature"), signature_buffer, length_return); #endif /* HEXDUMPS */ /* Send it to client. */ signer->packet_payload = signature_buffer; signer->packet_payload_len = length_return; signer->packet_waiting = TRUE; if (ssh_packet_wrapper_can_send(signer->wrapper)) signer_can_send(signer); /* XXX free dynamically allocated data. */ ssh_xfree(username); break; case SSH_AUTH_HOSTBASED_SIGNATURE: /* We shouldn't get this type of packet. This is an error.*/ SSH_TRACE(0, ("client sent us SSH_AUTH_HOSTBASED_SIGNATURE. This " \ "is an error.")); goto error; break; case SSH_AUTH_HOSTBASED_ERROR: /* We shouldn't be getting this either. This is an error. */ SSH_TRACE(0, ("client sent us SSH_AUTH_HOSTBASED_SIGNATURE_ERROR. " \ "This is an error. (This message can be sent by " \ "ssh-signer2 only)")); goto error; break; } return; /* We come here after errors. */ error: /* Send error message to ssh2, and wait for ssh2 to send EOF. */ ssh_packet_wrapper_send_encode(signer->wrapper, SSH_AUTH_HOSTBASED_ERROR, SSH_FORMAT_END); /* Init a 5 second timeout. If ssh2 hasn't disconnected at that time, close stream.*/ ssh_register_timeout(5L, 0L, signer_destroy_timeout, signer); return; }
void server_received_packet(SshCrossPacketType type, const unsigned char *data, size_t len, void *context) { char *service; switch (type) { case SSH_CROSS_PACKET: #ifdef DEBUG ssh_debug("server_received_packet: PACKET"); #endif break; case SSH_CROSS_DISCONNECT: #ifdef DEBUG ssh_debug("server_received_packet: DISCONNECT"); #endif /* XXX destroy? */ break; case SSH_CROSS_DEBUG: #ifdef DEBUG ssh_debug("server_received_packet: DEBUG"); #endif break; case SSH_CROSS_STARTUP: #ifdef DEBUG ssh_debug("server_received_packet: STARTUP"); #endif break; case SSH_CROSS_ALGORITHMS: #ifdef DEBUG ssh_debug("server_received_packet: ALGORITHMS"); #endif break; case SSH_CROSS_AUTHENTICATED: #ifdef DEBUG ssh_debug("server_received_packet: AUTHENTICATED"); #endif break; case SSH_CROSS_SERVICE_REQUEST: #ifdef DEBUG ssh_debug("server_received_packet: SERVICE_REQUEST"); #endif if (ssh_decode_array(data, len, SSH_FORMAT_UINT32_STR, &service, NULL, SSH_FORMAT_END) == 0) ssh_fatal("server_received_packet: bad service request"); if (strcmp(service, "TEST") == 0) ssh_cross_down_send(server_down, SSH_CROSS_SERVICE_ACCEPT, NULL, 0); else ssh_cross_down_send_disconnect(server_down, TRUE, SSH_DISCONNECT_SERVICE_NOT_AVAILABLE, "Service not available"); ssh_xfree(service); break; default: ssh_fatal("server_received_packet: type %d", (int)type); } }