static bool test_QueryServiceConfig2W(struct torture_context *tctx, struct dcerpc_pipe *p) { struct svcctl_QueryServiceConfig2W r; struct policy_handle h, s; NTSTATUS status; uint32_t info_level = SERVICE_CONFIG_DESCRIPTION; uint8_t *buffer; uint32_t offered = 0; uint32_t needed = 0; if (!test_OpenSCManager(p, tctx, &h)) return false; if (!test_OpenService(p, tctx, &h, TORTURE_DEFAULT_SERVICE, &s)) return false; buffer = talloc(tctx, uint8_t); r.in.handle = &s; r.in.info_level = info_level; r.in.offered = offered; r.out.buffer = buffer; r.out.needed = &needed; status = dcerpc_svcctl_QueryServiceConfig2W(p, tctx, &r); torture_assert_ntstatus_ok(tctx, status, "QueryServiceConfig2W failed!"); if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) { r.in.offered = needed; buffer = talloc_array(tctx, uint8_t, needed); r.out.buffer = buffer; status = dcerpc_svcctl_QueryServiceConfig2W(p, tctx, &r); torture_assert_ntstatus_ok(tctx, status, "QueryServiceConfig2W failed!"); torture_assert_werr_ok(tctx, r.out.result, "QueryServiceConfig2W failed!"); } r.in.info_level = SERVICE_CONFIG_FAILURE_ACTIONS; r.in.offered = offered; r.out.buffer = buffer; r.out.needed = &needed; status = dcerpc_svcctl_QueryServiceConfig2W(p, tctx, &r); torture_assert_ntstatus_ok(tctx, status, "QueryServiceConfig2W failed!"); if (W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) { r.in.offered = needed; buffer = talloc_array(tctx, uint8_t, needed); r.out.buffer = buffer; status = dcerpc_svcctl_QueryServiceConfig2W(p, tctx, &r); torture_assert_ntstatus_ok(tctx, status, "QueryServiceConfig2W failed!"); torture_assert_werr_ok(tctx, r.out.result, "QueryServiceConfig2W failed!"); } if (!test_CloseServiceHandle(p, tctx, &s)) return false; if (!test_CloseServiceHandle(p, tctx, &h)) return false; return true; }
static NTSTATUS cmd_eventlog_readlog(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { NTSTATUS status = NT_STATUS_OK; NTSTATUS result = NT_STATUS_OK; struct policy_handle handle; struct dcerpc_binding_handle *b = cli->binding_handle; uint32_t flags = EVENTLOG_BACKWARDS_READ | EVENTLOG_SEQUENTIAL_READ; uint32_t offset = 0; uint32_t number_of_bytes = 0; uint8_t *data = NULL; uint32_t sent_size = 0; uint32_t real_size = 0; if (argc < 2 || argc > 4) { printf("Usage: %s logname [offset] [number_of_bytes]\n", argv[0]); return NT_STATUS_OK; } if (argc >= 3) { offset = atoi(argv[2]); } if (argc >= 4) { number_of_bytes = atoi(argv[3]); data = talloc_array(mem_ctx, uint8_t, number_of_bytes); if (!data) { goto done; } } status = get_eventlog_handle(cli, mem_ctx, argv[1], &handle); if (!NT_STATUS_IS_OK(status)) { return status; } do { enum ndr_err_code ndr_err; DATA_BLOB blob; struct EVENTLOGRECORD r; uint32_t size = 0; uint32_t pos = 0; status = dcerpc_eventlog_ReadEventLogW(b, mem_ctx, &handle, flags, offset, number_of_bytes, data, &sent_size, &real_size, &result); if (!NT_STATUS_IS_OK(status)) { return status; } if (NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL) && real_size > 0 ) { number_of_bytes = real_size; data = talloc_array(mem_ctx, uint8_t, real_size); if (!data) { goto done; } status = dcerpc_eventlog_ReadEventLogW(b, mem_ctx, &handle, flags, offset, number_of_bytes, data, &sent_size, &real_size, &result); if (!NT_STATUS_IS_OK(status)) { return status; } } if (!NT_STATUS_EQUAL(result, NT_STATUS_END_OF_FILE) && !NT_STATUS_IS_OK(result)) { goto done; } number_of_bytes = 0; size = IVAL(data, pos); while (size > 0) { blob = data_blob_const(data + pos, size); /* dump_data(0, blob.data, blob.length); */ ndr_err = ndr_pull_struct_blob_all(&blob, mem_ctx, &r, (ndr_pull_flags_fn_t)ndr_pull_EVENTLOGRECORD); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); goto done; } NDR_PRINT_DEBUG(EVENTLOGRECORD, &r); pos += size; if (pos + 4 > sent_size) { break; } size = IVAL(data, pos); } offset++; } while (NT_STATUS_IS_OK(result)); done: dcerpc_eventlog_CloseEventLog(b, mem_ctx, &handle, &result); return status; }
static NTSTATUS rpc_service_list_internal(struct net_context *c, const DOM_SID *domain_sid, const char *domain_name, struct cli_state *cli, struct rpc_pipe_client *pipe_hnd, TALLOC_CTX *mem_ctx, int argc, const char **argv ) { struct policy_handle hSCM; struct ENUM_SERVICE_STATUSW *services = NULL; WERROR result = WERR_GENERAL_FAILURE; NTSTATUS status; int i; uint8_t *buffer = NULL; uint32_t buf_size = 0; uint32_t bytes_needed = 0; uint32_t num_services = 0; uint32_t resume_handle = 0; if (argc != 0 ) { d_printf(_("Usage: net rpc service list\n")); return NT_STATUS_OK; } status = rpccli_svcctl_OpenSCManagerW(pipe_hnd, mem_ctx, pipe_hnd->srv_name_slash, NULL, SC_RIGHT_MGR_ENUMERATE_SERVICE, &hSCM, &result); if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) { d_fprintf(stderr, _("Failed to open Service Control Manager. [%s]\n"), win_errstr(result)); return werror_to_ntstatus(result); } do { status = rpccli_svcctl_EnumServicesStatusW(pipe_hnd, mem_ctx, &hSCM, SERVICE_TYPE_WIN32, SERVICE_STATE_ALL, buffer, buf_size, &bytes_needed, &num_services, &resume_handle, &result); if (NT_STATUS_IS_ERR(status)) { d_fprintf(stderr, _("Failed to enumerate services. [%s]\n"), win_errstr(result)); break; } if (W_ERROR_EQUAL(result, WERR_MORE_DATA) && bytes_needed > 0) { buffer = talloc_array(mem_ctx, uint8_t, bytes_needed); buf_size = bytes_needed; continue; } if ( num_services == 0 ) { d_printf(_("No services returned\n")); break; } { enum ndr_err_code ndr_err; DATA_BLOB blob; struct ndr_pull *ndr; blob.length = buf_size; blob.data = talloc_steal(mem_ctx, buffer); services = talloc_array(mem_ctx, struct ENUM_SERVICE_STATUSW, num_services); if (!services) { status = NT_STATUS_NO_MEMORY; break; } ndr = ndr_pull_init_blob(&blob, mem_ctx, NULL); if (ndr == NULL) { status = NT_STATUS_NO_MEMORY; break; } ndr_err = ndr_pull_ENUM_SERVICE_STATUSW_array( ndr, num_services, services); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); break; } for ( i=0; i<num_services; i++ ) { d_printf("%-20s \"%s\"\n", services[i].service_name, services[i].display_name); } } } while (W_ERROR_EQUAL(result, WERR_MORE_DATA)); rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hSCM, NULL); return status; }
/* * Frame the Dirty data that needs to be send to the client in an * EAP-Request. We always embed the TLS-length in all EAP-TLS * packets that we send, for easy reference purpose. Handle * fragmentation and sending the next fragment etc. */ int eaptls_request(EAP_DS *eap_ds, tls_session_t *ssn) { EAPTLS_PACKET reply; unsigned int size; unsigned int nlen; unsigned int lbit = 0; /* This value determines whether we set (L)ength flag for EVERY packet we send and add corresponding "TLS Message Length" field. length_flag = true; This means we include L flag and "TLS Msg Len" in EVERY packet we send out. length_flag = false; This means we include L flag and "TLS Msg Len" **ONLY** in First packet of a fragment series. We do not use it anywhere else. Having L flag in every packet is prefered. */ if (ssn->length_flag) { lbit = 4; } if (ssn->fragment == 0) { ssn->tls_msg_len = ssn->dirty_out.used; } reply.code = FR_TLS_REQUEST; reply.flags = ssn->peap_flag; /* Send data, NOT more than the FRAGMENT size */ if (ssn->dirty_out.used > ssn->offset) { size = ssn->offset; reply.flags = SET_MORE_FRAGMENTS(reply.flags); /* Length MUST be included if it is the First Fragment */ if (ssn->fragment == 0) { lbit = 4; } ssn->fragment = 1; } else { size = ssn->dirty_out.used; ssn->fragment = 0; } reply.dlen = lbit + size; reply.length = TLS_HEADER_LEN + 1/*flags*/ + reply.dlen; reply.data = talloc_array(eap_ds, uint8_t, reply.length); if (!reply.data) return 0; if (lbit) { nlen = htonl(ssn->tls_msg_len); memcpy(reply.data, &nlen, lbit); reply.flags = SET_LENGTH_INCLUDED(reply.flags); } (ssn->record_minus)(&ssn->dirty_out, reply.data + lbit, size); eaptls_compose(eap_ds, &reply); talloc_free(reply.data); reply.data = NULL; return 1; }
/* * Receives a packet, assuming that the RADIUS_PACKET structure * has been filled out already. * * This ASSUMES that the packet is allocated && fields * initialized. * * This ASSUMES that the socket is marked as O_NONBLOCK, which * the function above does set, if your system supports it. * * Calling this function MAY change sockfd, * if src_ipaddr.af == AF_UNSPEC. */ int fr_tcp_read_packet(RADIUS_PACKET *packet, int flags) { ssize_t len; /* * No data allocated. Read the 4-byte header into * a temporary buffer. */ if (!packet->data) { int packet_len; len = recv(packet->sockfd, packet->vector + packet->data_len, 4 - packet->data_len, 0); if (len == 0) return -2; /* clean close */ #ifdef ECONNRESET if ((len < 0) && (errno == ECONNRESET)) { /* forced */ return -2; } #endif if (len < 0) { fr_strerror_printf("Error receiving packet: %s", fr_syserror(errno)); return -1; } packet->data_len += len; if (packet->data_len < 4) { /* want more data */ return 0; } packet_len = (packet->vector[2] << 8) | packet->vector[3]; if (packet_len < AUTH_HDR_LEN) { fr_strerror_printf("Discarding packet: Smaller than RFC minimum of 20 bytes"); return -1; } /* * If the packet is too big, then the socket is bad. */ if (packet_len > MAX_PACKET_LEN) { fr_strerror_printf("Discarding packet: Larger than RFC limitation of 4096 bytes"); return -1; } packet->data = talloc_array(packet, uint8_t, packet_len); if (!packet->data) { fr_strerror_printf("Out of memory"); return -1; } packet->data_len = packet_len; packet->partial = 4; memcpy(packet->data, packet->vector, 4); } /* * Try to read more data. */ len = recv(packet->sockfd, packet->data + packet->partial, packet->data_len - packet->partial, 0); if (len == 0) return -2; /* clean close */ #ifdef ECONNRESET if ((len < 0) && (errno == ECONNRESET)) { /* forced */ return -2; } #endif if (len < 0) { fr_strerror_printf("Error receiving packet: %s", fr_syserror(errno)); return -1; } packet->partial += len; if (packet->partial < packet->data_len) { return 0; } /* * See if it's a well-formed RADIUS packet. */ if (!rad_packet_ok(packet, flags, NULL)) { return -1; } /* * Explicitly set the VP list to empty. */ packet->vps = NULL; if (fr_debug_flag) { char ip_buf[128], buffer[256]; if (packet->src_ipaddr.af != AF_UNSPEC) { inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, ip_buf, sizeof(ip_buf)); snprintf(buffer, sizeof(buffer), "host %s port %d", ip_buf, packet->src_port); } else { snprintf(buffer, sizeof(buffer), "socket %d", packet->sockfd); } if ((packet->code > 0) && (packet->code < FR_MAX_PACKET_CODE)) { DEBUG("rad_recv: %s packet from %s", fr_packet_codes[packet->code], buffer); } else { DEBUG("rad_recv: Packet from %s code=%d", buffer, packet->code); } DEBUG(", id=%d, length=%zu\n", packet->id, packet->data_len); } return 1; /* done reading the packet */ }
static int sendrecv_eap(RADIUS_PACKET *rep) { RADIUS_PACKET *req = NULL; VALUE_PAIR *vp, *vpnext; int tried_eap_md5 = 0; if (!rep) return -1; /* * Keep a copy of the the User-Password attribute. */ if ((vp = pairfind(rep->vps, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) != NULL) { strlcpy(password, vp->vp_strvalue, sizeof(password)); } else if ((vp = pairfind(rep->vps, PW_USER_PASSWORD, 0, TAG_ANY)) != NULL) { strlcpy(password, vp->vp_strvalue, sizeof(password)); /* * Otherwise keep a copy of the CHAP-Password attribute. */ } else if ((vp = pairfind(rep->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) != NULL) { strlcpy(password, vp->vp_strvalue, sizeof(password)); } else { *password = '******'; } again: rep->id++; /* * if there are EAP types, encode them into an EAP-Message * */ map_eap_methods(rep); /* * Fix up Digest-Attributes issues */ for (vp = rep->vps; vp != NULL; vp = vp->next) { switch (vp->da->attr) { default: break; case PW_DIGEST_REALM: case PW_DIGEST_NONCE: case PW_DIGEST_METHOD: case PW_DIGEST_URI: case PW_DIGEST_QOP: case PW_DIGEST_ALGORITHM: case PW_DIGEST_BODY_DIGEST: case PW_DIGEST_CNONCE: case PW_DIGEST_NONCE_COUNT: case PW_DIGEST_USER_NAME: /* overlapping! */ { DICT_ATTR const *da; uint8_t *p, *q; p = talloc_array(vp, uint8_t, vp->length + 2); memcpy(p + 2, vp->vp_octets, vp->length); p[0] = vp->da->attr - PW_DIGEST_REALM + 1; vp->length += 2; p[1] = vp->length; da = dict_attrbyvalue(PW_DIGEST_ATTRIBUTES, 0); vp->da = da; /* * Re-do pairmemsteal ourselves, * because we play games with * vp->da, and pairmemsteal goes * to GREAT lengths to sanitize * and fix and change and * double-check the various * fields. */ memcpy(&q, &vp->vp_octets, sizeof(q)); talloc_free(q); vp->vp_octets = talloc_steal(vp, p); vp->type = VT_DATA; VERIFY_VP(vp); } break; } } /* * If we've already sent a packet, free up the old * one, and ensure that the next packet has a unique * ID and authentication vector. */ if (rep->data) { talloc_free(rep->data); rep->data = NULL; } fr_md5_calc(rep->vector, rep->vector, sizeof(rep->vector)); if (*password != '\0') { if ((vp = pairfind(rep->vps, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) != NULL) { pairstrcpy(vp, password); } else if ((vp = pairfind(rep->vps, PW_USER_PASSWORD, 0, TAG_ANY)) != NULL) { pairstrcpy(vp, password); } else if ((vp = pairfind(rep->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) != NULL) { pairstrcpy(vp, password); uint8_t *p; p = talloc_zero_array(vp, uint8_t, 17); rad_chap_encode(rep, p, rep->id, vp); pairmemsteal(vp, p); } } /* there WAS a password */ /* send the response, wait for the next request */ send_packet(rep, &req); if (!req) return -1; /* okay got back the packet, go and decode the EAP-Message. */ unmap_eap_methods(req); debug_packet(req, R_RECV); /* now look for the code type. */ for (vp = req->vps; vp != NULL; vp = vpnext) { vpnext = vp->next; switch (vp->da->attr) { default: break; case ATTRIBUTE_EAP_BASE+PW_EAP_MD5: if(respond_eap_md5(req, rep) && tried_eap_md5 < 3) { tried_eap_md5++; goto again; } break; case ATTRIBUTE_EAP_BASE+PW_EAP_SIM: if(respond_eap_sim(req, rep)) { goto again; } break; } } return 1; }
int proxy_tls_recv(rad_listen_t *listener) { int rcode; size_t length; listen_socket_t *sock = listener->data; char buffer[256]; RADIUS_PACKET *packet; uint8_t *data; /* * Get the maximum size of data to receive. */ if (!sock->data) sock->data = talloc_array(sock, uint8_t, sock->ssn->offset); data = sock->data; DEBUG3("Proxy SSL socket has data to read"); PTHREAD_MUTEX_LOCK(&sock->mutex); redo: rcode = SSL_read(sock->ssn->ssl, data, 4); if (rcode <= 0) { int err = SSL_get_error(sock->ssn->ssl, rcode); switch (err) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: goto redo; case SSL_ERROR_ZERO_RETURN: /* remote end sent close_notify, send one back */ SSL_shutdown(sock->ssn->ssl); case SSL_ERROR_SYSCALL: do_close: PTHREAD_MUTEX_UNLOCK(&sock->mutex); tls_socket_close(listener); return 0; default: while ((err = ERR_get_error())) { DEBUG("proxy recv says %s", ERR_error_string(err, NULL)); } goto do_close; } } length = (data[2] << 8) | data[3]; DEBUG3("Proxy received header saying we have a packet of %u bytes", (unsigned int) length); if (length > sock->ssn->offset) { INFO("Received packet will be too large! Set \"fragment_size=%u\"", (data[2] << 8) | data[3]); goto do_close; } rcode = SSL_read(sock->ssn->ssl, data + 4, length); if (rcode <= 0) { switch (SSL_get_error(sock->ssn->ssl, rcode)) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: break; case SSL_ERROR_ZERO_RETURN: /* remote end sent close_notify, send one back */ SSL_shutdown(sock->ssn->ssl); goto do_close; default: goto do_close; } } PTHREAD_MUTEX_UNLOCK(&sock->mutex); packet = rad_alloc(NULL, 0); packet->sockfd = listener->fd; packet->src_ipaddr = sock->other_ipaddr; packet->src_port = sock->other_port; packet->dst_ipaddr = sock->my_ipaddr; packet->dst_port = sock->my_port; packet->code = data[0]; packet->id = data[1]; packet->data_len = length; packet->data = talloc_array(packet, uint8_t, packet->data_len); memcpy(packet->data, data, packet->data_len); memcpy(packet->vector, packet->data + 4, 16); /* * FIXME: Client MIB updates? */ switch(packet->code) { case PW_CODE_AUTHENTICATION_ACK: case PW_CODE_ACCESS_CHALLENGE: case PW_CODE_AUTHENTICATION_REJECT: break; #ifdef WITH_ACCOUNTING case PW_CODE_ACCOUNTING_RESPONSE: break; #endif default: /* * FIXME: Update MIB for packet types? */ ERROR("Invalid packet code %d sent to a proxy port " "from home server %s port %d - ID %d : IGNORED", packet->code, ip_ntoh(&packet->src_ipaddr, buffer, sizeof(buffer)), packet->src_port, packet->id); rad_free(&packet); return 0; } if (!request_proxy_reply(packet)) { rad_free(&packet); return 0; } return 1; }
static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, UNUSED void *thread, REQUEST *request) { #ifdef WITH_DHCP int rcode; VALUE_PAIR *vp; rlm_soh_t const *inst = instance; if (!inst->dhcp) return RLM_MODULE_NOOP; vp = fr_pair_find_by_da(request->packet->vps, attr_dhcp_vendor, TAG_ANY); if (vp) { /* * vendor-specific options contain * * vendor opt 220/0xdc - SoH payload, or null byte to probe, or string * "NAP" to indicate server-side support for SoH in OFFERs * * vendor opt 222/0xde - SoH correlation ID as utf-16 string, yuck... */ uint8_t vopt, vlen; uint8_t const *data; data = vp->vp_octets; while (data < vp->vp_octets + vp->vp_length) { vopt = *data++; vlen = *data++; switch (vopt) { case 220: if (vlen <= 1) { uint8_t *p; RDEBUG2("SoH adding NAP marker to DHCP reply"); /* client probe; send "NAP" in the reply */ vp = fr_pair_afrom_da(request->reply, attr_dhcp_vendor); p = talloc_array(vp, uint8_t, 5); p[0] = 220; p[1] = 3; p[4] = 'N'; p[3] = 'A'; p[2] = 'P'; fr_pair_value_memsteal(vp, p); fr_pair_add(&request->reply->vps, vp); } else { RDEBUG2("SoH decoding NAP from DHCP request"); /* SoH payload */ rcode = soh_verify(request, data, vlen); if (rcode < 0) { return RLM_MODULE_FAIL; } } break; default: /* nothing to do */ break; } data += vlen; } return RLM_MODULE_OK; } #endif return RLM_MODULE_NOOP; }
struct hbin_data_block *get_hbin_data_block(TALLOC_CTX *mem_ctx, FILE *fd, long int offset, long int parent_off) { struct hbin_data_block *block; long int cur_offset; block = talloc_zero(mem_ctx, struct hbin_data_block); /* [SYN] Set index to data block */ cur_offset = offset+0x1000; /* [SYN] Seek to data block */ fseek(fd, cur_offset, SEEK_SET); #if DODEBUG > 2 printf("Debug: Parsing block at cur_offset 0x%lx, parent 0x%lx\n", (long)cur_offset, (long) parent_off+0x1000); #endif if (!fread(block, 4, 1, fd)) { printf("Error: short read while reading hbin data record size at 0x%lx\n", (long)cur_offset); return NULL; } if (block->size > 0) { if (parent_off > 0) { /* [SYN] Positive block->size means unused. Time to barf. */ printf("Error: Referencing unused block (0x%lx) with size 0x%lx from 0x%lx\n", (long)cur_offset, (long)block->size, (long)parent_off); return NULL; } else { block->size = -block->size; return block; } } if (block->size == 0) { printf("Error: hbin data record size is NULL at 0x%lx\n", (long)cur_offset); return NULL; } block->size = -block->size; /* [SYN] Check block->size, do not allocate it if bigger */ if (block->size > 32768) { printf("Warning: hbin data record size (0x%lx) is quite large at 0x%lx\n", (long)block->size, (long)cur_offset); printf("Warning: NOT ALLOCATING THIS BLOCK."); return NULL; } /* [SYN] Allocate memory and read the record into memory */ if ((block->data = talloc_array(block, uint8_t, block->size)) == NULL) { printf("Failed to allocate %ld bytes at record 0x%lx\n", (long)block->size, (long)cur_offset); return NULL; } if (!fread(block->data, block->size, 1, fd)) { printf("Error: Failed to read hbin data record at 0x%lx\n", (long)cur_offset); return NULL; } return block; }
/* * Initiate the EAP-MD5 session by sending a challenge to the peer. */ static int mod_session_init(UNUSED void *instance, eap_handler_t *handler) { int i; MD5_PACKET *reply; REQUEST *request = handler->request; /* * Allocate an EAP-MD5 packet. */ reply = talloc(handler, MD5_PACKET); if (!reply) { return 0; } /* * Fill it with data. */ reply->code = PW_MD5_CHALLENGE; reply->length = 1 + MD5_CHALLENGE_LEN; /* one byte of value size */ reply->value_size = MD5_CHALLENGE_LEN; /* * Allocate user data. */ reply->value = talloc_array(reply, uint8_t, reply->value_size); if (!reply->value) { talloc_free(reply); return 0; } /* * Get a random challenge. */ for (i = 0; i < reply->value_size; i++) { reply->value[i] = fr_rand(); } RDEBUG2("Issuing MD5 Challenge"); /* * Keep track of the challenge. */ handler->opaque = talloc_array(handler, uint8_t, reply->value_size); rad_assert(handler->opaque != NULL); memcpy(handler->opaque, reply->value, reply->value_size); handler->free_opaque = NULL; /* * Compose the EAP-MD5 packet out of the data structure, * and free it. */ eapmd5_compose(handler->eap_ds, reply); /* * We don't need to authorize the user at this point. * * We also don't need to keep the challenge, as it's * stored in 'handler->eap_ds', which will be given back * to us... */ handler->stage = PROCESS; return 1; }
/** * Decode Attribute OID based on MS documentation * See MS-DRSR.pdf - 5.16.4 * * On success returns decoded OID and * corresponding prefix_map index (if requested) */ bool drs_util_oid_from_attid(struct torture_context *tctx, const struct drsuapi_DsReplicaOIDMapping_Ctr *prefix_map, uint32_t attid, const char **_oid, int *map_idx) { int i; uint32_t hi_word, lo_word; DATA_BLOB bin_oid = {NULL, 0}; char *oid; struct drsuapi_DsReplicaOIDMapping *map_entry = NULL; TALLOC_CTX *mem_ctx = talloc_named(tctx, 0, "util_drsuapi_oid_from_attid"); /* crack attid value */ hi_word = attid >> 16; lo_word = attid & 0xFFFF; /* check last entry in the prefix map is the special one */ map_entry = &prefix_map->mappings[prefix_map->num_mappings-1]; torture_assert(tctx, (map_entry->id_prefix == 0) && (*map_entry->oid.binary_oid == 0xFF), "Last entry in Prefix Map is not the special one!"); /* locate corresponding prefixMap entry */ map_entry = NULL; for (i = 0; i < prefix_map->num_mappings - 1; i++) { if (hi_word == prefix_map->mappings[i].id_prefix) { map_entry = &prefix_map->mappings[i]; if (map_idx) *map_idx = i; break; } } torture_assert(tctx, map_entry, "Unable to locate corresponding Prefix Map entry"); /* copy partial oid making enough room */ bin_oid.length = map_entry->oid.length + 2; bin_oid.data = talloc_array(mem_ctx, uint8_t, bin_oid.length); torture_assert(tctx, bin_oid.data, "Not enough memory"); memcpy(bin_oid.data, map_entry->oid.binary_oid, map_entry->oid.length); if (lo_word < 128) { bin_oid.length = bin_oid.length - 1; bin_oid.data[bin_oid.length-1] = lo_word; } else { if (lo_word >= 32768) { lo_word -= 32768; } bin_oid.data[bin_oid.length-2] = ((lo_word / 128) % 128) + 128; // (0x80 | ((lo_word>>7) & 0x7f)) bin_oid.data[bin_oid.length-1] = lo_word % 128; // lo_word & 0x7f } torture_assert(tctx, ber_read_OID_String(tctx, bin_oid, &oid), "Failed to decode binary OID"); talloc_free(mem_ctx); *_oid = oid; return true; }
static bool lcp2_init(struct ipalloc_state *ipalloc_state, uint32_t **lcp2_imbalances, bool **rebalance_candidates) { int i, numnodes; struct public_ip_list *t; numnodes = ipalloc_state->num; *rebalance_candidates = talloc_array(ipalloc_state, bool, numnodes); if (*rebalance_candidates == NULL) { DEBUG(DEBUG_ERR, (__location__ " out of memory\n")); return false; } *lcp2_imbalances = talloc_array(ipalloc_state, uint32_t, numnodes); if (*lcp2_imbalances == NULL) { DEBUG(DEBUG_ERR, (__location__ " out of memory\n")); return false; } for (i=0; i<numnodes; i++) { (*lcp2_imbalances)[i] = lcp2_imbalance(ipalloc_state->all_ips, i); /* First step: assume all nodes are candidates */ (*rebalance_candidates)[i] = true; } /* 2nd step: if a node has IPs assigned then it must have been * healthy before, so we remove it from consideration. This * is overkill but is all we have because we don't maintain * state between takeover runs. An alternative would be to * keep state and invalidate it every time the recovery master * changes. */ for (t = ipalloc_state->all_ips; t != NULL; t = t->next) { if (t->pnn != -1) { (*rebalance_candidates)[t->pnn] = false; } } /* 3rd step: if a node is forced to re-balance then we allow failback onto the node */ if (ipalloc_state->force_rebalance_nodes == NULL) { return true; } for (i = 0; i < talloc_array_length(ipalloc_state->force_rebalance_nodes); i++) { uint32_t pnn = ipalloc_state->force_rebalance_nodes[i]; if (pnn >= numnodes) { DEBUG(DEBUG_ERR, (__location__ "unknown node %u\n", pnn)); continue; } DEBUG(DEBUG_NOTICE, ("Forcing rebalancing of IPs to node %u\n", pnn)); (*rebalance_candidates)[pnn] = true; } return true; }
static bool test_EnumDependentServicesW(struct torture_context *tctx, struct dcerpc_pipe *p) { struct svcctl_EnumDependentServicesW r; struct policy_handle h, s; uint32_t needed; uint32_t services_returned; uint32_t i; uint32_t states[] = { SERVICE_STATE_ACTIVE, SERVICE_STATE_INACTIVE, SERVICE_STATE_ALL }; if (!test_OpenSCManager(p, tctx, &h)) return false; if (!test_OpenService(p, tctx, &h, TORTURE_DEFAULT_SERVICE, &s)) return false; r.in.service = &s; r.in.offered = 0; r.in.state = 0; r.out.service_status = NULL; r.out.services_returned = &services_returned; r.out.needed = &needed; torture_assert_ntstatus_ok(tctx, dcerpc_svcctl_EnumDependentServicesW(p, tctx, &r), "EnumDependentServicesW failed!"); torture_assert_werr_equal(tctx, r.out.result, WERR_INVALID_PARAM, "EnumDependentServicesW failed!"); for (i=0; i<ARRAY_SIZE(states); i++) { r.in.state = states[i]; torture_assert_ntstatus_ok(tctx, dcerpc_svcctl_EnumDependentServicesW(p, tctx, &r), "EnumDependentServicesW failed!"); if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) { r.in.offered = needed; r.out.service_status = talloc_array(tctx, uint8_t, needed); torture_assert_ntstatus_ok(tctx, dcerpc_svcctl_EnumDependentServicesW(p, tctx, &r), "EnumDependentServicesW failed!"); } torture_assert_werr_ok(tctx, r.out.result, "EnumDependentServicesW failed"); } if (!test_CloseServiceHandle(p, tctx, &s)) return false; if (!test_CloseServiceHandle(p, tctx, &h)) return false; return true; }
static bool test_EnumServicesStatus(struct torture_context *tctx, struct dcerpc_pipe *p) { struct svcctl_EnumServicesStatusW r; struct policy_handle h; int i; NTSTATUS status; uint32_t resume_handle = 0; struct ENUM_SERVICE_STATUSW *service = NULL; uint32_t needed = 0; uint32_t services_returned = 0; if (!test_OpenSCManager(p, tctx, &h)) return false; r.in.handle = &h; r.in.type = SERVICE_TYPE_WIN32; r.in.state = SERVICE_STATE_ALL; r.in.offered = 0; r.in.resume_handle = &resume_handle; r.out.service = NULL; r.out.resume_handle = &resume_handle; r.out.services_returned = &services_returned; r.out.needed = &needed; status = dcerpc_svcctl_EnumServicesStatusW(p, tctx, &r); torture_assert_ntstatus_ok(tctx, status, "EnumServicesStatus failed!"); if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) { r.in.offered = needed; r.out.service = talloc_array(tctx, uint8_t, needed); status = dcerpc_svcctl_EnumServicesStatusW(p, tctx, &r); torture_assert_ntstatus_ok(tctx, status, "EnumServicesStatus failed!"); torture_assert_werr_ok(tctx, r.out.result, "EnumServicesStatus failed"); } if (services_returned > 0) { enum ndr_err_code ndr_err; DATA_BLOB blob; struct ndr_pull *ndr; blob.length = r.in.offered; blob.data = talloc_steal(tctx, r.out.service); ndr = ndr_pull_init_blob(&blob, tctx, lp_iconv_convenience(tctx->lp_ctx)); service = talloc_array(tctx, struct ENUM_SERVICE_STATUSW, services_returned); if (!service) { return false; } ndr_err = ndr_pull_ENUM_SERVICE_STATUSW_array( ndr, services_returned, service); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return false; } } for(i = 0; i < services_returned; i++) { torture_assert(tctx, service[i].service_name, "Service without name returned!"); printf("%-20s \"%s\", Type: %d, State: %d\n", service[i].service_name, service[i].display_name, service[i].status.type, service[i].status.state); } if (!test_CloseServiceHandle(p, tctx, &h)) return false; return true; }
/** \details Opens a specific message and retrieves a MAPI object that can be used to get or set message properties. This function opens a specific message defined by a combination of object store, folder ID, and message ID and which read/write access is defined by ulFlags. \param obj_store the store to read from \param id_folder the folder ID \param id_message the message ID \param obj_message the resulting message object \param ulFlags Possible ulFlags values: - 0x0: read only access - 0x1: ReadWrite - 0x3: Create - 0x4: OpenSoftDeleted \return MAPI_E_SUCCESS on success, otherwise MAPI error. \note Developers may also call GetLastError() to retrieve the last MAPI error code. Possible MAPI error codes are: - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized - MAPI_E_INVALID_PARAMETER: obj_store is undefined - MAPI_E_CALL_FAILED: A network problem was encountered during the transaction \sa MAPIInitialize, GetLastError */ _PUBLIC_ enum MAPISTATUS OpenMessage(mapi_object_t *obj_store, mapi_id_t id_folder, mapi_id_t id_message, mapi_object_t *obj_message, uint8_t ulFlags) { struct mapi_context *mapi_ctx; struct mapi_request *mapi_request; struct mapi_response *mapi_response; struct EcDoRpc_MAPI_REQ *mapi_req; struct OpenMessage_req request; struct OpenMessage_repl *reply; struct mapi_session *session; mapi_object_message_t *message; struct SPropValue lpProp; const char *tstring; NTSTATUS status; enum MAPISTATUS retval; uint32_t size = 0; TALLOC_CTX *mem_ctx; uint32_t i = 0; uint8_t logon_id; /* Sanity checks */ OPENCHANGE_RETVAL_IF(!obj_store, MAPI_E_INVALID_PARAMETER, NULL); session = mapi_object_get_session(obj_store); OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL); mapi_ctx = session->mapi_ctx; OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL); if ((retval = mapi_object_get_logon_id(obj_store, &logon_id)) != MAPI_E_SUCCESS) return retval; mem_ctx = talloc_named(session, 0, "OpenMessage"); /* Fill the OpenMessage operation */ request.handle_idx = 0x1; request.CodePageId = 0xfff; request.FolderId = id_folder; request.OpenModeFlags = (enum OpenMessage_OpenModeFlags)ulFlags; request.MessageId = id_message; size = sizeof (uint8_t) + sizeof(uint16_t) + sizeof(mapi_id_t) + sizeof(uint8_t) + sizeof(mapi_id_t); /* Fill the MAPI_REQ request */ mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ); mapi_req->opnum = op_MAPI_OpenMessage; mapi_req->logon_id = logon_id; mapi_req->handle_idx = 0; mapi_req->u.mapi_OpenMessage = request; size += 5; /* Fill the mapi_request structure */ mapi_request = talloc_zero(mem_ctx, struct mapi_request); mapi_request->mapi_len = size + sizeof (uint32_t) * 2; mapi_request->length = size; mapi_request->mapi_req = mapi_req; mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2); mapi_request->handles[0] = mapi_object_get_handle(obj_store); mapi_request->handles[1] = 0xffffffff; status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response); OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx); OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx); retval = mapi_response->mapi_repl->error_code; OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx); OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response); /* Set object session and handle */ mapi_object_set_session(obj_message, session); mapi_object_set_handle(obj_message, mapi_response->handles[1]); mapi_object_set_logon_id(obj_message, logon_id); /* Store OpenMessage reply data */ reply = &mapi_response->mapi_repl->u.mapi_OpenMessage; message = talloc_zero((TALLOC_CTX *)session, mapi_object_message_t); tstring = get_TypedString(&reply->SubjectPrefix); if (tstring) { message->SubjectPrefix = talloc_strdup((TALLOC_CTX *)message, tstring); } tstring = get_TypedString(&reply->NormalizedSubject); if (tstring) { message->NormalizedSubject = talloc_strdup((TALLOC_CTX *)message, tstring); } message->cValues = reply->RecipientColumns.cValues; message->SRowSet.cRows = reply->RowCount; message->SRowSet.aRow = talloc_array((TALLOC_CTX *)message, struct SRow, reply->RowCount + 1); message->SPropTagArray.cValues = reply->RecipientColumns.cValues; message->SPropTagArray.aulPropTag = talloc_steal(message, reply->RecipientColumns.aulPropTag); for (i = 0; i < reply->RowCount; i++) { emsmdb_get_SRow((TALLOC_CTX *)message, &(message->SRowSet.aRow[i]), &message->SPropTagArray, reply->RecipientRows[i].RecipientRow.prop_count, &reply->RecipientRows[i].RecipientRow.prop_values, reply->RecipientRows[i].RecipientRow.layout, 1); lpProp.ulPropTag = PR_RECIPIENT_TYPE; lpProp.value.l = reply->RecipientRows[i].RecipientType; SRow_addprop(&(message->SRowSet.aRow[i]), lpProp); lpProp.ulPropTag = PR_INTERNET_CPID; lpProp.value.l = reply->RecipientRows[i].CodePageId; SRow_addprop(&(message->SRowSet.aRow[i]), lpProp); } /* add SPropTagArray elements we automatically append to SRow */ SPropTagArray_add((TALLOC_CTX *)message, &message->SPropTagArray, PR_RECIPIENT_TYPE); SPropTagArray_add((TALLOC_CTX *)message, &message->SPropTagArray, PR_INTERNET_CPID); obj_message->private_data = (void *) message; talloc_free(mapi_response); talloc_free(mem_ctx); return MAPI_E_SUCCESS; }
int eap_crypto_tls_session_id(TALLOC_CTX *ctx, #if OPENSSL_VERSION_NUMBER < 0x10101000L UNUSED #endif REQUEST *request, SSL *ssl, uint8_t **out, uint8_t eap_type, #if OPENSSL_VERSION_NUMBER < 0x10100000L UNUSED #endif char const *prf_label, #if OPENSSL_VERSION_NUMBER < 0x10101000L UNUSED #endif size_t prf_label_len) { uint8_t *buff = NULL, *p; *out = NULL; #if OPENSSL_VERSION_NUMBER >= 0x10100000L if (!prf_label) goto random_based_session_id; switch (SSL_SESSION_get_protocol_version(SSL_get_session(ssl))) { case SSL2_VERSION: /* Should never happen */ case SSL3_VERSION: /* Should never happen */ return - 1; case TLS1_VERSION: /* No Method ID */ case TLS1_1_VERSION: /* No Method ID */ case TLS1_2_VERSION: /* No Method ID */ random_based_session_id: #endif MEM(buff = p = talloc_array(ctx, uint8_t, sizeof(eap_type) + (2 * SSL3_RANDOM_SIZE))); *p++ = eap_type; SSL_get_client_random(ssl, p, SSL3_RANDOM_SIZE); p += SSL3_RANDOM_SIZE; SSL_get_server_random(ssl, p, SSL3_RANDOM_SIZE); #if OPENSSL_VERSION_NUMBER >= 0x10101000L break; /* * Session-Id = <EAP-Type> || Method-Id * Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id", "", 64) */ case TLS1_3_VERSION: default: { MEM(buff = p = talloc_array(ctx, uint8_t, sizeof(eap_type) + 64)); *p++ = eap_type; if (SSL_export_keying_material(ssl, p, 64, prf_label, prf_label_len, NULL, 0, 0) != 1) { tls_log_error(request, "Failed generating TLS session ID"); return -1; } } break; #endif #if OPENSSL_VERSION_NUMBER >= 0x10100000L } #endif *out = buff; return 0; }
static struct bkrp_BackupKey *createRestoreGUIDStruct(struct torture_context *tctx, struct dcerpc_pipe *p, int version, DATA_BLOB *out, bool norevert, bool broken_version, bool broken_user, bool broken_magic_secret, bool broken_magic_access, bool broken_hash_access, bool broken_cert_guid) { struct dcerpc_binding_handle *b = p->binding_handle; struct bkrp_client_side_wrapped data; DATA_BLOB *xs; DATA_BLOB *sec; DATA_BLOB *enc_sec; DATA_BLOB *enc_xs; DATA_BLOB *blob2; DATA_BLOB enc_sec_reverted; DATA_BLOB des3_key; DATA_BLOB aes_key; DATA_BLOB iv; DATA_BLOB out_blob; struct GUID *guid, *g; int t; uint32_t size; enum ndr_err_code ndr_err; NTSTATUS status; const char *user; struct bkrp_BackupKey *r = createRetreiveBackupKeyGUIDStruct(tctx, p, version, &out_blob); if (r == NULL) { return NULL; } if (broken_user) { /* we take a fake user*/ user = "******"; } else { user = cli_credentials_get_username(cmdline_credentials); } torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Get GUID"); /* * We have to set it outside of the function createRetreiveBackupKeyGUIDStruct * the len of the blob, this is due to the fact that they don't have the * same size (one is 32bits the other 64bits) */ out_blob.length = *r->out.data_out_len; sec = create_unencryptedsecret(tctx, broken_magic_secret, version); if (sec == NULL) { return NULL; } xs = create_access_check(tctx, p, tctx, user, broken_hash_access, version); if (xs == NULL) { return NULL; } if (broken_magic_access){ /* The start of the access_check structure contains the * GUID of the certificate */ xs->data[0]++; } enc_sec = encrypt_blob_pk(tctx, tctx, out_blob.data, out_blob.length, sec); if (!enc_sec) { return NULL; } enc_sec_reverted.data = talloc_array(tctx, uint8_t, enc_sec->length); if (enc_sec_reverted.data == NULL) { return NULL; } enc_sec_reverted.length = enc_sec->length; /* * We DO NOT revert the array on purpose it's in order to check that * when the server is not able to decrypt then it answer the correct error */ if (norevert) { for(t=0; t< enc_sec->length; t++) { enc_sec_reverted.data[t] = ((uint8_t*)enc_sec->data)[t]; } } else { for(t=0; t< enc_sec->length; t++) { enc_sec_reverted.data[t] = ((uint8_t*)enc_sec->data)[enc_sec->length - t -1]; } } size = sec->length; if (version ==2) { const AlgorithmIdentifier *alg = hx509_crypto_des_rsdi_ede3_cbc(); iv.data = sec->data+(size - 8); iv.length = 8; des3_key.data = sec->data+(size - 32); des3_key.length = 24; enc_xs = encrypt_blob(tctx, tctx, &des3_key, &iv, xs, alg); } if (version == 3) { const AlgorithmIdentifier *alg = hx509_crypto_aes256_cbc(); iv.data = sec->data+(size-16); iv.length = 16; aes_key.data = sec->data+(size-48); aes_key.length = 32; enc_xs = encrypt_blob(tctx, tctx, &aes_key, &iv, xs, alg); } if (!enc_xs) { return NULL; } /* To cope with the fact that heimdal do padding at the end for the moment */ enc_xs->length = xs->length; guid = get_cert_guid(tctx, tctx, out_blob.data, out_blob.length); if (guid == NULL) { return NULL; } if (broken_version) { data.version = 1; } else { data.version = version; } data.guid = *guid; data.encrypted_secret = enc_sec_reverted.data; data.access_check = enc_xs->data; data.encrypted_secret_len = enc_sec->length; data.access_check_len = enc_xs->length; /* We want the blob to persist after this function so we don't * allocate it in the stack */ blob2 = talloc(tctx, DATA_BLOB); if (blob2 == NULL) { return NULL; } ndr_err = ndr_push_struct_blob(blob2, tctx, &data, (ndr_push_flags_fn_t)ndr_push_bkrp_client_side_wrapped); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return NULL; } if (broken_cert_guid) { blob2->data[12]++; } ZERO_STRUCT(*r); g = talloc(tctx, struct GUID); if (g == NULL) { return NULL; } status = GUID_from_string(BACKUPKEY_RESTORE_GUID, g); if (!NT_STATUS_IS_OK(status)) { return NULL; } r->in.guidActionAgent = g; r->in.data_in = blob2->data; r->in.data_in_len = blob2->length; r->in.param = 0; r->out.data_out = &(out->data); r->out.data_out_len = talloc(r, uint32_t); return r; }
static bool smb_raw_query_posix_whoami(void *mem_ctx, struct torture_context *torture, struct smbcli_state *cli, struct smb_whoami *whoami, unsigned max_data) { struct smb_trans2 tp; NTSTATUS status; size_t offset; int i; uint16_t setup = TRANSACT2_QFSINFO; uint16_t info_level; ZERO_STRUCTP(whoami); tp.in.max_setup = 0; tp.in.flags = 0; tp.in.timeout = 0; tp.in.setup_count = 1; tp.in.max_param = 10; tp.in.max_data = (uint16_t)max_data; tp.in.setup = &setup; tp.in.trans_name = NULL; SSVAL(&info_level, 0, SMB_QFS_POSIX_WHOAMI); tp.in.params = data_blob_talloc(mem_ctx, &info_level, 2); tp.in.data = data_blob_talloc(mem_ctx, NULL, 0); status = smb_raw_trans2(cli->tree, mem_ctx, &tp); torture_assert_ntstatus_equal(torture, status, NT_STATUS_OK, "doing SMB_QFS_POSIX_WHOAMI"); /* Make sure we got back all the required fields. */ torture_assert(torture, tp.out.params.length == 0, "trans2 params should be empty"); torture_assert(torture, tp.out.data.length >= WHOAMI_REQUIRED_SIZE, "checking for required response fields"); whoami->mapping_flags = IVAL(tp.out.data.data, 0); whoami->mapping_mask = IVAL(tp.out.data.data, 4); whoami->server_uid = BVAL(tp.out.data.data, 8); whoami->server_gid = BVAL(tp.out.data.data, 16); whoami->num_gids = IVAL(tp.out.data.data, 24); whoami->num_sids = IVAL(tp.out.data.data, 28); whoami->num_sid_bytes = IVAL(tp.out.data.data, 32); whoami->reserved = IVAL(tp.out.data.data, 36); /* The GID list and SID list are optional, depending on the count * and length fields. */ if (whoami->num_sids != 0) { torture_assert(torture, whoami->num_sid_bytes != 0, "SID count does not match byte count"); } printf("\tmapping_flags=0x%08x mapping_mask=0x%08x\n", whoami->mapping_flags, whoami->mapping_mask); printf("\tserver UID=%llu GID=%llu\n", (unsigned long long)whoami->server_uid, (unsigned long long)whoami->server_gid); printf("\t%u GIDs, %u SIDs, %u SID bytes\n", whoami->num_gids, whoami->num_sids, whoami->num_sid_bytes); offset = WHOAMI_REQUIRED_SIZE; torture_assert_int_equal(torture, whoami->reserved, 0, "invalid reserved field"); if (tp.out.data.length == offset) { /* No SIDs or GIDs returned */ torture_assert_int_equal(torture, whoami->num_gids, 0, "invalid GID count"); torture_assert_int_equal(torture, whoami->num_sids, 0, "invalid SID count"); torture_assert_int_equal(torture, whoami->num_sid_bytes, 0, "invalid SID byte count"); return true; } if (whoami->num_gids != 0) { int remain = tp.out.data.length - offset; int gid_bytes = whoami->num_gids * 8; if (whoami->num_sids == 0) { torture_assert_int_equal(torture, remain, gid_bytes, "GID count does not match data length"); } else { torture_assert(torture, remain > gid_bytes, "invalid GID count"); } whoami->gid_list = talloc_array(mem_ctx, uint64_t, whoami->num_gids); torture_assert(torture, whoami->gid_list != NULL, "out of memory"); torture_comment(torture, "\tGIDs:\n"); for (i = 0; i < whoami->num_gids; ++i) { whoami->gid_list[i] = BVAL(tp.out.data.data, offset); offset += 8; torture_comment(torture, "\t\t%u\n", (unsigned int)whoami->gid_list[i]); } } /* Check if there should be data left for the SID list. */ if (tp.out.data.length == offset) { torture_assert_int_equal(torture, whoami->num_sids, 0, "invalid SID count"); return true; } /* All the remaining bytes must be the SID list. */ torture_assert_int_equal(torture, whoami->num_sid_bytes, (tp.out.data.length - offset), "invalid SID byte count"); if (whoami->num_sids != 0) { whoami->sid_list = talloc_array(mem_ctx, struct dom_sid *, whoami->num_sids); torture_assert(torture, whoami->sid_list != NULL, "out of memory"); torture_comment(torture, "\tSIDs:\n"); for (i = 0; i < whoami->num_sids; ++i) { if (!whoami_sid_parse(mem_ctx, torture, &tp.out.data, &offset, &whoami->sid_list[i])) { return false; } torture_comment(torture, "\t\t%s\n", dom_sid_string(torture, whoami->sid_list[i])); } }
static int tls_socket_recv(rad_listen_t *listener) { int doing_init = false; ssize_t rcode; RADIUS_PACKET *packet; REQUEST *request; listen_socket_t *sock = listener->data; fr_tls_status_t status; RADCLIENT *client = sock->client; if (!sock->packet) { sock->packet = rad_alloc(NULL, 0); if (!sock->packet) return 0; sock->packet->sockfd = listener->fd; sock->packet->src_ipaddr = sock->other_ipaddr; sock->packet->src_port = sock->other_port; sock->packet->dst_ipaddr = sock->my_ipaddr; sock->packet->dst_port = sock->my_port; if (sock->request) { (void) talloc_steal(sock->request, sock->packet); sock->request->packet = sock->packet; } } /* * Allocate a REQUEST for debugging. */ if (!sock->request) { sock->request = request = request_alloc(NULL); if (!sock->request) { ERROR("Out of memory"); return 0; } rad_assert(request->packet == NULL); rad_assert(sock->packet != NULL); request->packet = sock->packet; request->component = "<core>"; request->component = "<tls-connect>"; /* * Not sure if we should do this on every packet... */ request->reply = rad_alloc(request, 0); if (!request->reply) return 0; request->options = RAD_REQUEST_OPTION_DEBUG2; rad_assert(sock->ssn == NULL); sock->ssn = tls_new_session(listener->tls, sock->request, listener->tls->require_client_cert); if (!sock->ssn) { request_free(&sock->request); sock->packet = NULL; return 0; } (void) talloc_steal(sock, sock->ssn); SSL_set_ex_data(sock->ssn->ssl, FR_TLS_EX_INDEX_REQUEST, (void *)request); SSL_set_ex_data(sock->ssn->ssl, FR_TLS_EX_INDEX_CERTS, (void *)&request->packet->vps); doing_init = true; } rad_assert(sock->request != NULL); rad_assert(sock->request->packet != NULL); rad_assert(sock->packet != NULL); rad_assert(sock->ssn != NULL); request = sock->request; RDEBUG3("Reading from socket %d", request->packet->sockfd); PTHREAD_MUTEX_LOCK(&sock->mutex); rcode = read(request->packet->sockfd, sock->ssn->dirty_in.data, sizeof(sock->ssn->dirty_in.data)); if ((rcode < 0) && (errno == ECONNRESET)) { do_close: PTHREAD_MUTEX_UNLOCK(&sock->mutex); tls_socket_close(listener); return 0; } if (rcode < 0) { RDEBUG("Error reading TLS socket: %s", fr_syserror(errno)); goto do_close; } /* * Normal socket close. */ if (rcode == 0) goto do_close; sock->ssn->dirty_in.used = rcode; dump_hex("READ FROM SSL", sock->ssn->dirty_in.data, sock->ssn->dirty_in.used); /* * Catch attempts to use non-SSL. */ if (doing_init && (sock->ssn->dirty_in.data[0] != handshake)) { RDEBUG("Non-TLS data sent to TLS socket: closing"); goto do_close; } /* * Skip ahead to reading application data. */ if (SSL_is_init_finished(sock->ssn->ssl)) goto app; if (!tls_handshake_recv(request, sock->ssn)) { RDEBUG("FAILED in TLS handshake receive"); goto do_close; } if (sock->ssn->dirty_out.used > 0) { tls_socket_write(listener, request); PTHREAD_MUTEX_UNLOCK(&sock->mutex); return 0; } app: /* * FIXME: Run the packet through a virtual server in * order to see if we like the certificate presented by * the client. */ status = tls_application_data(sock->ssn, request); RDEBUG("Application data status %d", status); if (status == FR_TLS_MORE_FRAGMENTS) { PTHREAD_MUTEX_UNLOCK(&sock->mutex); return 0; } if (sock->ssn->clean_out.used == 0) { PTHREAD_MUTEX_UNLOCK(&sock->mutex); return 0; } dump_hex("TUNNELED DATA", sock->ssn->clean_out.data, sock->ssn->clean_out.used); /* * If the packet is a complete RADIUS packet, return it to * the caller. Otherwise... */ if ((sock->ssn->clean_out.used < 20) || (((sock->ssn->clean_out.data[2] << 8) | sock->ssn->clean_out.data[3]) != (int) sock->ssn->clean_out.used)) { RDEBUG("Received bad packet: Length %d contents %d", sock->ssn->clean_out.used, (sock->ssn->clean_out.data[2] << 8) | sock->ssn->clean_out.data[3]); goto do_close; } packet = sock->packet; packet->data = talloc_array(packet, uint8_t, sock->ssn->clean_out.used); packet->data_len = sock->ssn->clean_out.used; sock->ssn->record_minus(&sock->ssn->clean_out, packet->data, packet->data_len); packet->vps = NULL; PTHREAD_MUTEX_UNLOCK(&sock->mutex); if (!rad_packet_ok(packet, 0)) { RDEBUG("Received bad packet: %s", fr_strerror()); tls_socket_close(listener); return 0; /* do_close unlocks the mutex */ } /* * Copied from src/lib/radius.c, rad_recv(); */ if (fr_debug_flag) { char host_ipaddr[128]; if ((packet->code > 0) && (packet->code < FR_MAX_PACKET_CODE)) { RDEBUG("tls_recv: %s packet from host %s port %d, id=%d, length=%d", fr_packet_codes[packet->code], inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, host_ipaddr, sizeof(host_ipaddr)), packet->src_port, packet->id, (int) packet->data_len); } else { RDEBUG("tls_recv: Packet from host %s port %d code=%d, id=%d, length=%d", inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, host_ipaddr, sizeof(host_ipaddr)), packet->src_port, packet->code, packet->id, (int) packet->data_len); } } FR_STATS_INC(auth, total_requests); return 1; }
NTSTATUS cli_dfs_get_referral(TALLOC_CTX *ctx, struct cli_state *cli, const char *path, struct client_dfs_referral **refs, size_t *num_refs, size_t *consumed) { unsigned int data_len = 0; unsigned int param_len = 0; uint16_t setup[1]; uint16_t recv_flags2; uint8_t *param = NULL; uint8_t *rdata = NULL; char *p; char *endp; smb_ucs2_t *path_ucs; char *consumed_path = NULL; uint16_t consumed_ucs; uint16 num_referrals; struct client_dfs_referral *referrals = NULL; NTSTATUS status; TALLOC_CTX *frame = talloc_stackframe(); *num_refs = 0; *refs = NULL; SSVAL(setup, 0, TRANSACT2_GET_DFS_REFERRAL); param = talloc_array(talloc_tos(), uint8_t, 2); if (!param) { status = NT_STATUS_NO_MEMORY; goto out; } SSVAL(param, 0, 0x03); /* max referral level */ param = trans2_bytes_push_str(param, cli_ucs2(cli), path, strlen(path)+1, NULL); if (!param) { status = NT_STATUS_NO_MEMORY; goto out; } param_len = talloc_get_size(param); path_ucs = (smb_ucs2_t *)¶m[2]; status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, 0xffff, 0, 0, setup, 1, 0, param, param_len, 2, NULL, 0, CLI_BUFFER_SIZE, &recv_flags2, NULL, 0, NULL, /* rsetup */ NULL, 0, NULL, &rdata, 4, &data_len); if (!NT_STATUS_IS_OK(status)) { goto out; } endp = (char *)rdata + data_len; consumed_ucs = SVAL(rdata, 0); num_referrals = SVAL(rdata, 2); /* consumed_ucs is the number of bytes * of the UCS2 path consumed not counting any * terminating null. We need to convert * back to unix charset and count again * to get the number of bytes consumed from * the incoming path. */ errno = 0; if (pull_string_talloc(talloc_tos(), NULL, 0, &consumed_path, path_ucs, consumed_ucs, STR_UNICODE) == 0) { if (errno != 0) { status = map_nt_error_from_unix(errno); } else { status = NT_STATUS_INVALID_NETWORK_RESPONSE; } goto out; } if (consumed_path == NULL) { status = map_nt_error_from_unix(errno); goto out; } *consumed = strlen(consumed_path); if (num_referrals != 0) { uint16 ref_version; uint16 ref_size; int i; uint16 node_offset; referrals = talloc_array(ctx, struct client_dfs_referral, num_referrals); if (!referrals) { status = NT_STATUS_NO_MEMORY; goto out; } /* start at the referrals array */ p = (char *)rdata+8; for (i=0; i<num_referrals && p < endp; i++) { if (p + 18 > endp) { goto out; } ref_version = SVAL(p, 0); ref_size = SVAL(p, 2); node_offset = SVAL(p, 16); if (ref_version != 3) { p += ref_size; continue; } referrals[i].proximity = SVAL(p, 8); referrals[i].ttl = SVAL(p, 10); if (p + node_offset > endp) { status = NT_STATUS_INVALID_NETWORK_RESPONSE; goto out; } clistr_pull_talloc(referrals, (const char *)rdata, recv_flags2, &referrals[i].dfspath, p+node_offset, PTR_DIFF(endp, p+node_offset), STR_TERMINATE|STR_UNICODE); if (!referrals[i].dfspath) { status = map_nt_error_from_unix(errno); goto out; } p += ref_size; } if (i < num_referrals) { status = NT_STATUS_INVALID_NETWORK_RESPONSE; goto out; } }
_PUBLIC_ enum MAPISTATUS EcDoRpc_RopMoveCopyMessages(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, struct EcDoRpc_MAPI_REQ *mapi_req, struct EcDoRpc_MAPI_REPL *mapi_repl, uint32_t *handles, uint16_t *size) { enum MAPISTATUS retval; uint32_t handle; uint32_t contextID; struct mapi_handles *rec = NULL; void *private_data = NULL; struct emsmdbp_object *destination_object; struct emsmdbp_object *source_object; uint64_t *targetMIDs; uint32_t i; bool mapistore = false; OC_DEBUG(4, "exchange_emsmdb: [OXCFOLD] RopMoveCopyMessages (0x33)\n"); /* Sanity checks */ OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL); mapi_repl->opnum = mapi_req->opnum; mapi_repl->error_code = MAPI_E_SUCCESS; mapi_repl->handle_idx = mapi_req->handle_idx; mapi_repl->u.mapi_MoveCopyMessages.PartialCompletion = 0; /* Get the destionation information */ handle = handles[mapi_req->u.mapi_MoveCopyMessages.handle_idx]; retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &rec); if (retval) { mapi_repl->error_code = MAPI_E_INVALID_OBJECT; OC_DEBUG(5, " handle (%x) not found: %x\n", handle, mapi_req->handle_idx); goto end; } retval = mapi_handles_get_private_data(rec, &private_data); /* object is our destination folder */ destination_object = private_data; if (!destination_object) { mapi_repl->error_code = MAPI_E_INVALID_OBJECT; OC_DEBUG(5, " object (%x) not found: %x\n", handle, mapi_req->handle_idx); goto end; } /* Get the source folder information */ handle = handles[mapi_req->handle_idx]; retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &rec); if (retval) { mapi_repl->error_code = MAPI_E_INVALID_OBJECT; OC_DEBUG(5, " handle (%x) not found: %x\n", handle, mapi_req->handle_idx); goto end; } retval = mapi_handles_get_private_data(rec, &private_data); source_object = private_data; if (!source_object) { mapi_repl->error_code = MAPI_E_INVALID_OBJECT; OC_DEBUG(5, " object (%x) not found: %x\n", handle, mapi_req->u.mapi_MoveCopyMessages.handle_idx); goto end; } contextID = emsmdbp_get_contextID(destination_object); mapistore = emsmdbp_is_mapistore(source_object); if (mapistore) { /* We prepare a set of new MIDs for the backend */ targetMIDs = talloc_array(NULL, uint64_t, mapi_req->u.mapi_MoveCopyMessages.count); for (i = 0; i < mapi_req->u.mapi_MoveCopyMessages.count; i++) { mapistore_indexing_get_new_folderID(emsmdbp_ctx->mstore_ctx, &targetMIDs[i]); } /* We invoke the backend method */ mapistore_folder_move_copy_messages(emsmdbp_ctx->mstore_ctx, contextID, destination_object->backend_object, source_object->backend_object, mem_ctx, mapi_req->u.mapi_MoveCopyMessages.count, mapi_req->u.mapi_MoveCopyMessages.message_id, targetMIDs, NULL, NULL, mapi_req->u.mapi_MoveCopyMessages.WantCopy); talloc_free(targetMIDs); /* /\* The backend might do this for us. In any case, we try to add it ourselves *\/ */ /* mapistore_indexing_record_add_mid(emsmdbp_ctx->mstore_ctx, contextID, targetMID); */ } else { OC_DEBUG(0, "mapistore support not implemented yet - shouldn't occur\n"); mapi_repl->error_code = MAPI_E_NO_SUPPORT; } end: *size += libmapiserver_RopMoveCopyMessages_size(mapi_repl); return MAPI_E_SUCCESS; }
NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req) { struct smbXsrv_connection *xconn = req->xconn; NTSTATUS status; const uint8_t *inbody; const uint8_t *indyn = NULL; DATA_BLOB outbody; DATA_BLOB outdyn; DATA_BLOB negprot_spnego_blob; uint16_t security_offset; DATA_BLOB security_buffer; size_t expected_dyn_size = 0; size_t c; uint16_t security_mode; uint16_t dialect_count; uint16_t in_security_mode; uint32_t in_capabilities; DATA_BLOB in_guid_blob; struct GUID in_guid; struct smb2_negotiate_contexts in_c = { .num_contexts = 0, }; struct smb2_negotiate_context *in_preauth = NULL; struct smb2_negotiate_context *in_cipher = NULL; struct smb2_negotiate_contexts out_c = { .num_contexts = 0, }; DATA_BLOB out_negotiate_context_blob = data_blob_null; uint32_t out_negotiate_context_offset = 0; uint16_t out_negotiate_context_count = 0; uint16_t dialect = 0; uint32_t capabilities; DATA_BLOB out_guid_blob; struct GUID out_guid; enum protocol_types protocol = PROTOCOL_NONE; uint32_t max_limit; uint32_t max_trans = lp_smb2_max_trans(); uint32_t max_read = lp_smb2_max_read(); uint32_t max_write = lp_smb2_max_write(); NTTIME now = timeval_to_nttime(&req->request_time); bool signing_required = true; bool ok; status = smbd_smb2_request_verify_sizes(req, 0x24); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } inbody = SMBD_SMB2_IN_BODY_PTR(req); dialect_count = SVAL(inbody, 0x02); in_security_mode = SVAL(inbody, 0x04); in_capabilities = IVAL(inbody, 0x08); in_guid_blob = data_blob_const(inbody + 0x0C, 16); if (dialect_count == 0) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } status = GUID_from_ndr_blob(&in_guid_blob, &in_guid); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } expected_dyn_size = dialect_count * 2; if (SMBD_SMB2_IN_DYN_LEN(req) < expected_dyn_size) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } indyn = SMBD_SMB2_IN_DYN_PTR(req); protocol = smbd_smb2_protocol_dialect_match(indyn, dialect_count, &dialect); for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) { if (lp_server_max_protocol() < PROTOCOL_SMB2_10) { break; } dialect = SVAL(indyn, c*2); if (dialect == SMB2_DIALECT_REVISION_2FF) { if (xconn->smb2.allow_2ff) { xconn->smb2.allow_2ff = false; protocol = PROTOCOL_SMB2_10; break; } } } if (protocol == PROTOCOL_NONE) { return smbd_smb2_request_error(req, NT_STATUS_NOT_SUPPORTED); } if (protocol >= PROTOCOL_SMB3_10) { uint32_t in_negotiate_context_offset = 0; uint16_t in_negotiate_context_count = 0; DATA_BLOB in_negotiate_context_blob = data_blob_null; size_t ofs; in_negotiate_context_offset = IVAL(inbody, 0x1C); in_negotiate_context_count = SVAL(inbody, 0x20); ofs = SMB2_HDR_BODY; ofs += SMBD_SMB2_IN_BODY_LEN(req); ofs += expected_dyn_size; if ((ofs % 8) != 0) { ofs += 8 - (ofs % 8); } if (in_negotiate_context_offset != ofs) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } ofs -= SMB2_HDR_BODY; ofs -= SMBD_SMB2_IN_BODY_LEN(req); if (SMBD_SMB2_IN_DYN_LEN(req) < ofs) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } in_negotiate_context_blob = data_blob_const(indyn, SMBD_SMB2_IN_DYN_LEN(req)); in_negotiate_context_blob.data += ofs; in_negotiate_context_blob.length -= ofs; status = smb2_negotiate_context_parse(req, in_negotiate_context_blob, &in_c); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } if (in_negotiate_context_count != in_c.num_contexts) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } } if ((dialect != SMB2_DIALECT_REVISION_2FF) && (protocol >= PROTOCOL_SMB2_10) && !GUID_all_zero(&in_guid)) { ok = remote_arch_cache_update(&in_guid); if (!ok) { return smbd_smb2_request_error( req, NT_STATUS_UNSUCCESSFUL); } } switch (get_remote_arch()) { case RA_VISTA: case RA_SAMBA: case RA_CIFSFS: case RA_OSX: break; default: set_remote_arch(RA_VISTA); break; } fstr_sprintf(remote_proto, "SMB%X_%02X", (dialect >> 8) & 0xFF, dialect & 0xFF); reload_services(req->sconn, conn_snum_used, true); DEBUG(3,("Selected protocol %s\n", remote_proto)); in_preauth = smb2_negotiate_context_find(&in_c, SMB2_PREAUTH_INTEGRITY_CAPABILITIES); if (protocol >= PROTOCOL_SMB3_10 && in_preauth == NULL) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } in_cipher = smb2_negotiate_context_find(&in_c, SMB2_ENCRYPTION_CAPABILITIES); /* negprot_spnego() returns a the server guid in the first 16 bytes */ negprot_spnego_blob = negprot_spnego(req, xconn); if (negprot_spnego_blob.data == NULL) { return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); } if (negprot_spnego_blob.length < 16) { return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR); } security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED; /* * We use xconn->smb1.signing_state as that's already present * and used lpcfg_server_signing_allowed() to get the correct * defaults, e.g. signing_required for an ad_dc. */ signing_required = smb_signing_is_mandatory(xconn->smb1.signing_state); if (signing_required) { security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED; } capabilities = 0; if (lp_host_msdfs()) { capabilities |= SMB2_CAP_DFS; } if (protocol >= PROTOCOL_SMB2_10 && lp_smb2_leases() && lp_oplocks(GLOBAL_SECTION_SNUM) && !lp_kernel_oplocks(GLOBAL_SECTION_SNUM)) { capabilities |= SMB2_CAP_LEASING; } if ((protocol >= PROTOCOL_SMB2_24) && (lp_smb_encrypt(-1) != SMB_SIGNING_OFF) && (in_capabilities & SMB2_CAP_ENCRYPTION)) { capabilities |= SMB2_CAP_ENCRYPTION; } /* * 0x10000 (65536) is the maximum allowed message size * for SMB 2.0 */ max_limit = 0x10000; if (protocol >= PROTOCOL_SMB2_10) { int p = 0; if (tsocket_address_is_inet(req->sconn->local_address, "ip")) { p = tsocket_address_inet_port(req->sconn->local_address); } /* largeMTU is not supported over NBT (tcp port 139) */ if (p != NBT_SMB_PORT) { capabilities |= SMB2_CAP_LARGE_MTU; xconn->smb2.credits.multicredit = true; /* * We allow up to almost 16MB. * * The maximum PDU size is 0xFFFFFF (16776960) * and we need some space for the header. */ max_limit = 0xFFFF00; } } /* * the defaults are 8MB, but we'll limit this to max_limit based on * the dialect (64kb for SMB 2.0, 8MB for SMB >= 2.1 with LargeMTU) * * user configured values exceeding the limits will be overwritten, * only smaller values will be accepted */ max_trans = MIN(max_limit, lp_smb2_max_trans()); max_read = MIN(max_limit, lp_smb2_max_read()); max_write = MIN(max_limit, lp_smb2_max_write()); if (in_preauth != NULL) { size_t needed = 4; uint16_t hash_count; uint16_t salt_length; uint16_t selected_preauth = 0; const uint8_t *p; uint8_t buf[38]; DATA_BLOB b; size_t i; if (in_preauth->data.length < needed) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } hash_count = SVAL(in_preauth->data.data, 0); salt_length = SVAL(in_preauth->data.data, 2); if (hash_count == 0) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } p = in_preauth->data.data + needed; needed += hash_count * 2; needed += salt_length; if (in_preauth->data.length < needed) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } for (i=0; i < hash_count; i++) { uint16_t v; v = SVAL(p, 0); p += 2; if (v == SMB2_PREAUTH_INTEGRITY_SHA512) { selected_preauth = v; break; } } if (selected_preauth == 0) { return smbd_smb2_request_error(req, NT_STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP); } SSVAL(buf, 0, 1); /* HashAlgorithmCount */ SSVAL(buf, 2, 32); /* SaltLength */ SSVAL(buf, 4, selected_preauth); generate_random_buffer(buf + 6, 32); b = data_blob_const(buf, sizeof(buf)); status = smb2_negotiate_context_add(req, &out_c, SMB2_PREAUTH_INTEGRITY_CAPABILITIES, b); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } req->preauth = &req->xconn->smb2.preauth; } if (in_cipher != NULL) { size_t needed = 2; uint16_t cipher_count; const uint8_t *p; uint8_t buf[4]; DATA_BLOB b; size_t i; bool aes_128_ccm_supported = false; bool aes_128_gcm_supported = false; capabilities &= ~SMB2_CAP_ENCRYPTION; if (in_cipher->data.length < needed) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } cipher_count = SVAL(in_cipher->data.data, 0); if (cipher_count == 0) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } p = in_cipher->data.data + needed; needed += cipher_count * 2; if (in_cipher->data.length < needed) { return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } for (i=0; i < cipher_count; i++) { uint16_t v; v = SVAL(p, 0); p += 2; if (v == SMB2_ENCRYPTION_AES128_GCM) { aes_128_gcm_supported = true; } if (v == SMB2_ENCRYPTION_AES128_CCM) { aes_128_ccm_supported = true; } } /* * For now we preferr CCM because our implementation * is faster than GCM, see bug #11451. */ if (aes_128_ccm_supported) { xconn->smb2.server.cipher = SMB2_ENCRYPTION_AES128_CCM; } else if (aes_128_gcm_supported) { xconn->smb2.server.cipher = SMB2_ENCRYPTION_AES128_GCM; } SSVAL(buf, 0, 1); /* ChiperCount */ SSVAL(buf, 2, xconn->smb2.server.cipher); b = data_blob_const(buf, sizeof(buf)); status = smb2_negotiate_context_add(req, &out_c, SMB2_ENCRYPTION_CAPABILITIES, b); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } } if (capabilities & SMB2_CAP_ENCRYPTION) { xconn->smb2.server.cipher = SMB2_ENCRYPTION_AES128_CCM; } if (protocol >= PROTOCOL_SMB2_22 && xconn->client->server_multi_channel_enabled) { if (in_capabilities & SMB2_CAP_MULTI_CHANNEL) { capabilities |= SMB2_CAP_MULTI_CHANNEL; } } security_offset = SMB2_HDR_BODY + 0x40; #if 1 /* Try SPNEGO auth... */ security_buffer = data_blob_const(negprot_spnego_blob.data + 16, negprot_spnego_blob.length - 16); #else /* for now we want raw NTLMSSP */ security_buffer = data_blob_const(NULL, 0); #endif if (out_c.num_contexts != 0) { status = smb2_negotiate_context_push(req, &out_negotiate_context_blob, out_c); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } } if (out_negotiate_context_blob.length != 0) { static const uint8_t zeros[8]; size_t pad = 0; size_t ofs; outdyn = data_blob_dup_talloc(req, security_buffer); if (outdyn.length != security_buffer.length) { return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); } ofs = security_offset + security_buffer.length; if ((ofs % 8) != 0) { pad = 8 - (ofs % 8); } ofs += pad; ok = data_blob_append(req, &outdyn, zeros, pad); if (!ok) { return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); } ok = data_blob_append(req, &outdyn, out_negotiate_context_blob.data, out_negotiate_context_blob.length); if (!ok) { return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); } out_negotiate_context_offset = ofs; out_negotiate_context_count = out_c.num_contexts; } else { outdyn = security_buffer; } out_guid_blob = data_blob_const(negprot_spnego_blob.data, 16); status = GUID_from_ndr_blob(&out_guid_blob, &out_guid); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } outbody = smbd_smb2_generate_outbody(req, 0x40); if (outbody.data == NULL) { return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); } SSVAL(outbody.data, 0x00, 0x40 + 1); /* struct size */ SSVAL(outbody.data, 0x02, security_mode); /* security mode */ SSVAL(outbody.data, 0x04, dialect); /* dialect revision */ SSVAL(outbody.data, 0x06, out_negotiate_context_count); /* reserved/NegotiateContextCount */ memcpy(outbody.data + 0x08, out_guid_blob.data, 16); /* server guid */ SIVAL(outbody.data, 0x18, capabilities); /* capabilities */ SIVAL(outbody.data, 0x1C, max_trans); /* max transact size */ SIVAL(outbody.data, 0x20, max_read); /* max read size */ SIVAL(outbody.data, 0x24, max_write); /* max write size */ SBVAL(outbody.data, 0x28, now); /* system time */ SBVAL(outbody.data, 0x30, 0); /* server start time */ SSVAL(outbody.data, 0x38, security_offset); /* security buffer offset */ SSVAL(outbody.data, 0x3A, security_buffer.length); /* security buffer length */ SIVAL(outbody.data, 0x3C, out_negotiate_context_offset); /* reserved/NegotiateContextOffset */ req->sconn->using_smb2 = true; if (dialect != SMB2_DIALECT_REVISION_2FF) { struct smbXsrv_client_global0 *global0 = NULL; status = smbXsrv_connection_init_tables(xconn, protocol); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } xconn->smb2.client.capabilities = in_capabilities; xconn->smb2.client.security_mode = in_security_mode; xconn->smb2.client.guid = in_guid; xconn->smb2.client.num_dialects = dialect_count; xconn->smb2.client.dialects = talloc_array(xconn, uint16_t, dialect_count); if (xconn->smb2.client.dialects == NULL) { return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); } for (c=0; c < dialect_count; c++) { xconn->smb2.client.dialects[c] = SVAL(indyn, c*2); } xconn->smb2.server.capabilities = capabilities; xconn->smb2.server.security_mode = security_mode; xconn->smb2.server.guid = out_guid; xconn->smb2.server.dialect = dialect; xconn->smb2.server.max_trans = max_trans; xconn->smb2.server.max_read = max_read; xconn->smb2.server.max_write = max_write; if (xconn->protocol < PROTOCOL_SMB2_10) { /* * SMB2_02 doesn't support client guids */ return smbd_smb2_request_done(req, outbody, &outdyn); } if (!xconn->client->server_multi_channel_enabled) { /* * Only deal with the client guid database * if multi-channel is enabled. */ return smbd_smb2_request_done(req, outbody, &outdyn); } if (xconn->smb2.client.guid_verified) { /* * The connection was passed from another * smbd process. */ return smbd_smb2_request_done(req, outbody, &outdyn); } status = smb2srv_client_lookup_global(xconn->client, xconn->smb2.client.guid, req, &global0); /* * TODO: check for races... */ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECTID_NOT_FOUND)) { /* * This stores the new client information in * smbXsrv_client_global.tdb */ xconn->client->global->client_guid = xconn->smb2.client.guid; status = smbXsrv_client_update(xconn->client); if (!NT_STATUS_IS_OK(status)) { return status; } xconn->smb2.client.guid_verified = true; } else if (NT_STATUS_IS_OK(status)) { status = smb2srv_client_connection_pass(req, global0); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } smbd_server_connection_terminate(xconn, "passed connection"); return NT_STATUS_OBJECTID_EXISTS; } else { return smbd_smb2_request_error(req, status); } } return smbd_smb2_request_done(req, outbody, &outdyn); }
/* * EAPTLS_PACKET * code = EAP-code * id = EAP-id * length = code + id + length + flags + tlsdata * = 1 + 1 + 2 + 1 + X * length = EAP-length - 1(EAP-Type = 1 octet) * flags = EAP-typedata[0] (1 octet) * dlen = EAP-typedata[1-4] (4 octets), if L flag set * = length - 5(code+id+length+flags), otherwise * data = EAP-typedata[5-n], if L flag set * = EAP-typedata[1-n], otherwise * packet = EAP-typedata (complete typedata) * * Points to consider during EAP-TLS data extraction * 1. In the received packet, No data will be present incase of ACK-NAK * 2. Incase if more fragments need to be received then ACK after retreiving this fragment. * * RFC 2716 Section 4.2. PPP EAP TLS Request Packet * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Code | Identifier | Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Type | Flags | TLS Message Length * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | TLS Message Length | TLS Data... * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * The Length field is two octets and indicates the length of the EAP * packet including the Code, Identifir, Length, Type, and TLS data * fields. */ static EAPTLS_PACKET *eaptls_extract(REQUEST *request, EAP_DS *eap_ds, fr_tls_status_t status) { EAPTLS_PACKET *tlspacket; uint32_t data_len = 0; uint32_t len = 0; uint8_t *data = NULL; if (status == FR_TLS_INVALID) return NULL; /* * The main EAP code & eaptls_verify() take care of * ensuring that the packet is OK, and that we can * extract the various fields we want. * * e.g. a TLS packet with zero data is allowed as an ACK, * but we will never see it here, as we will simply * send another fragment, instead of trying to extract * the data. * * MUST have TLS type octet, followed by flags, followed * by data. */ assert(eap_ds->response->length > 2); tlspacket = talloc(eap_ds, EAPTLS_PACKET); if (!tlspacket) return NULL; /* * Code & id for EAPTLS & EAP are same * but eaptls_length = eap_length - 1(EAP-Type = 1 octet) * * length = code + id + length + type + tlsdata * = 1 + 1 + 2 + 1 + X */ tlspacket->code = eap_ds->response->code; tlspacket->id = eap_ds->response->id; tlspacket->length = eap_ds->response->length - 1; /* EAP type */ tlspacket->flags = eap_ds->response->type.data[0]; /* * A quick sanity check of the flags. If we've been told * that there's a length, and there isn't one, then stop. */ if (TLS_LENGTH_INCLUDED(tlspacket->flags) && (tlspacket->length < 5)) { /* flags + TLS message length */ RDEBUG("Invalid EAP-TLS packet received. (Length bit is set, but no length was found.)"); talloc_free(tlspacket); return NULL; } /* * If the final TLS packet is larger than we can handle, die * now. * * Likewise, if the EAP packet says N bytes, and the TLS * packet says there's fewer bytes, it's a problem. * * FIXME: Try to ensure that the claimed length is * consistent across multiple TLS fragments. */ if (TLS_LENGTH_INCLUDED(tlspacket->flags)) { memcpy(&data_len, &eap_ds->response->type.data[1], 4); data_len = ntohl(data_len); if (data_len > MAX_RECORD_SIZE) { RDEBUG("The EAP-TLS packet will contain more data than we can process"); talloc_free(tlspacket); return NULL; } #if 0 DEBUG2(" TLS: %d %d\n", data_len, tlspacket->length); if (data_len < tlspacket->length) { RDEBUG("EAP-TLS packet claims to be smaller than the encapsulating EAP packet"); talloc_free(tlspacket); return NULL; } #endif } switch (status) { /* * The TLS Message Length field is four octets, and * provides the total length of the TLS message or set of * messages that is being fragmented; this simplifies * buffer allocation. * * Dynamic allocation of buffers as & when we know the * length should solve the problem. */ case FR_TLS_FIRST_FRAGMENT: case FR_TLS_LENGTH_INCLUDED: case FR_TLS_MORE_FRAGMENTS_WITH_LENGTH: if (tlspacket->length < 5) { /* flags + TLS message length */ RDEBUG("Invalid EAP-TLS packet received. (Expected length, got none.)"); talloc_free(tlspacket); return NULL; } /* * Extract all the TLS fragments from the * previous eap_ds Start appending this * fragment to the above ds */ memcpy(&data_len, &eap_ds->response->type.data[1], sizeof(uint32_t)); data_len = ntohl(data_len); data = (eap_ds->response->type.data + 5/*flags+TLS-Length*/); len = eap_ds->response->type.length - 5/*flags+TLS-Length*/; /* * Hmm... this should be an error, too. */ if (data_len > len) { data_len = len; } break; /* * Data length is implicit, from the EAP header. */ case FR_TLS_MORE_FRAGMENTS: case FR_TLS_OK: data_len = eap_ds->response->type.length - 1/*flags*/; data = eap_ds->response->type.data + 1/*flags*/; break; default: RDEBUG("Invalid EAP-TLS packet received"); talloc_free(tlspacket); return NULL; } tlspacket->dlen = data_len; if (data_len) { tlspacket->data = talloc_array(tlspacket, uint8_t, data_len); if (!tlspacket->data) { talloc_free(tlspacket); return NULL; } memcpy(tlspacket->data, data, data_len); } return tlspacket; }
static int mod_process(void *arg, eap_handler_t *handler) { pwd_session_t *session; pwd_hdr *hdr; pwd_id_packet_t *packet; eap_packet_t *response; REQUEST *request, *fake; VALUE_PAIR *pw, *vp; EAP_DS *eap_ds; size_t in_len; int ret = 0; eap_pwd_t *inst = (eap_pwd_t *)arg; uint16_t offset; uint8_t exch, *in, *ptr, msk[MSK_EMSK_LEN], emsk[MSK_EMSK_LEN]; uint8_t peer_confirm[SHA256_DIGEST_LENGTH]; if (((eap_ds = handler->eap_ds) == NULL) || !inst) return 0; session = (pwd_session_t *)handler->opaque; request = handler->request; response = handler->eap_ds->response; hdr = (pwd_hdr *)response->type.data; /* * The header must be at least one byte. */ if (!hdr || (response->type.length < sizeof(pwd_hdr))) { RDEBUG("Packet with insufficient data"); return 0; } in = hdr->data; in_len = response->type.length - sizeof(pwd_hdr); /* * see if we're fragmenting, if so continue until we're done */ if (session->out_pos) { if (in_len) RDEBUG2("pwd got something more than an ACK for a fragment"); return send_pwd_request(session, eap_ds); } /* * the first fragment will have a total length, make a * buffer to hold all the fragments */ if (EAP_PWD_GET_LENGTH_BIT(hdr)) { if (session->in) { RDEBUG2("pwd already alloced buffer for fragments"); return 0; } if (in_len < 2) { RDEBUG("Invalid packet: length bit set, but no length field"); return 0; } session->in_len = ntohs(in[0] * 256 | in[1]); if ((session->in = talloc_zero_array(session, uint8_t, session->in_len)) == NULL) { RDEBUG2("pwd cannot allocate %zd buffer to hold fragments", session->in_len); return 0; } memset(session->in, 0, session->in_len); session->in_pos = 0; in += sizeof(uint16_t); in_len -= sizeof(uint16_t); } /* * all fragments, including the 1st will have the M(ore) bit set, * buffer those fragments! */ if (EAP_PWD_GET_MORE_BIT(hdr)) { rad_assert(session->in != NULL); if ((session->in_pos + in_len) > session->in_len) { RDEBUG2("Fragment overflows packet."); return 0; } memcpy(session->in + session->in_pos, in, in_len); session->in_pos += in_len; /* * send back an ACK for this fragment */ exch = EAP_PWD_GET_EXCHANGE(hdr); eap_ds->request->code = PW_EAP_REQUEST; eap_ds->request->type.num = PW_EAP_PWD; eap_ds->request->type.length = sizeof(pwd_hdr); if ((eap_ds->request->type.data = talloc_array(eap_ds->request, uint8_t, sizeof(pwd_hdr))) == NULL) { return 0; } hdr = (pwd_hdr *)eap_ds->request->type.data; EAP_PWD_SET_EXCHANGE(hdr, exch); return 1; } if (session->in) { /* * the last fragment... */ if ((session->in_pos + in_len) > session->in_len) { RDEBUG2("pwd will not overflow a fragment buffer. Nope, not prudent"); return 0; } memcpy(session->in + session->in_pos, in, in_len); in = session->in; in_len = session->in_len; } switch (session->state) { case PWD_STATE_ID_REQ: { BIGNUM *x = NULL, *y = NULL; if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_ID) { RDEBUG2("pwd exchange is incorrect: not ID"); return 0; } packet = (pwd_id_packet_t *) in; if (in_len < sizeof(*packet)) { RDEBUG("Packet is too small (%zd < %zd).", in_len, sizeof(*packet)); return 0; } if ((packet->prf != EAP_PWD_DEF_PRF) || (packet->random_function != EAP_PWD_DEF_RAND_FUN) || (packet->prep != EAP_PWD_PREP_NONE) || (CRYPTO_memcmp(packet->token, &session->token, 4)) || (packet->group_num != ntohs(session->group_num))) { RDEBUG2("pwd id response is invalid"); return 0; } /* * we've agreed on the ciphersuite, record it... */ ptr = (uint8_t *)&session->ciphersuite; memcpy(ptr, (char *)&packet->group_num, sizeof(uint16_t)); ptr += sizeof(uint16_t); *ptr = EAP_PWD_DEF_RAND_FUN; ptr += sizeof(uint8_t); *ptr = EAP_PWD_DEF_PRF; session->peer_id_len = in_len - sizeof(pwd_id_packet_t); if (session->peer_id_len >= sizeof(session->peer_id)) { RDEBUG2("pwd id response is malformed"); return 0; } memcpy(session->peer_id, packet->identity, session->peer_id_len); session->peer_id[session->peer_id_len] = '\0'; /* * make fake request to get the password for the usable ID */ if ((fake = request_alloc_fake(handler->request)) == NULL) { RDEBUG("pwd unable to create fake request!"); return 0; } fake->username = fr_pair_afrom_num(fake->packet, PW_USER_NAME, 0); if (!fake->username) { RDEBUG("Failed creating pair for peer id"); talloc_free(fake); return 0; } fr_pair_value_bstrncpy(fake->username, session->peer_id, session->peer_id_len); fr_pair_add(&fake->packet->vps, fake->username); if ((vp = fr_pair_find_by_num(request->config, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) { fake->server = vp->vp_strvalue; } else if (inst->virtual_server) { fake->server = inst->virtual_server; } /* else fake->server == request->server */ RDEBUG("Sending tunneled request"); rdebug_pair_list(L_DBG_LVL_1, request, fake->packet->vps, NULL); if (fake->server) { RDEBUG("server %s {", fake->server); } else { RDEBUG("server {"); } /* * Call authorization recursively, which will * get the password. */ RINDENT(); process_authorize(0, fake); REXDENT(); /* * Note that we don't do *anything* with the reply * attributes. */ if (fake->server) { RDEBUG("} # server %s", fake->server); } else { RDEBUG("}"); } RDEBUG("Got tunneled reply code %d", fake->reply->code); rdebug_pair_list(L_DBG_LVL_1, request, fake->reply->vps, NULL); if ((pw = fr_pair_find_by_num(fake->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) == NULL) { DEBUG2("failed to find password for %s to do pwd authentication", session->peer_id); talloc_free(fake); return 0; } if (compute_password_element(session, session->group_num, pw->data.strvalue, strlen(pw->data.strvalue), inst->server_id, strlen(inst->server_id), session->peer_id, strlen(session->peer_id), &session->token)) { DEBUG2("failed to obtain password element"); talloc_free(fake); return 0; } TALLOC_FREE(fake); /* * compute our scalar and element */ if (compute_scalar_element(session, inst->bnctx)) { DEBUG2("failed to compute server's scalar and element"); return 0; } MEM(x = BN_new()); MEM(y = BN_new()); /* * element is a point, get both coordinates: x and y */ if (!EC_POINT_get_affine_coordinates_GFp(session->group, session->my_element, x, y, inst->bnctx)) { DEBUG2("server point assignment failed"); BN_clear_free(x); BN_clear_free(y); return 0; } /* * construct request */ session->out_len = BN_num_bytes(session->order) + (2 * BN_num_bytes(session->prime)); if ((session->out = talloc_array(session, uint8_t, session->out_len)) == NULL) { return 0; } memset(session->out, 0, session->out_len); ptr = session->out; offset = BN_num_bytes(session->prime) - BN_num_bytes(x); BN_bn2bin(x, ptr + offset); BN_clear_free(x); ptr += BN_num_bytes(session->prime); offset = BN_num_bytes(session->prime) - BN_num_bytes(y); BN_bn2bin(y, ptr + offset); BN_clear_free(y); ptr += BN_num_bytes(session->prime); offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar); BN_bn2bin(session->my_scalar, ptr + offset); session->state = PWD_STATE_COMMIT; ret = send_pwd_request(session, eap_ds); } break; case PWD_STATE_COMMIT: if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_COMMIT) { RDEBUG2("pwd exchange is incorrect: not commit!"); return 0; } /* * process the peer's commit and generate the shared key, k */ if (process_peer_commit(session, in, in_len, inst->bnctx)) { RDEBUG2("failed to process peer's commit"); return 0; } /* * compute our confirm blob */ if (compute_server_confirm(session, session->my_confirm, inst->bnctx)) { ERROR("rlm_eap_pwd: failed to compute confirm!"); return 0; } /* * construct a response...which is just our confirm blob */ session->out_len = SHA256_DIGEST_LENGTH; if ((session->out = talloc_array(session, uint8_t, session->out_len)) == NULL) { return 0; } memset(session->out, 0, session->out_len); memcpy(session->out, session->my_confirm, SHA256_DIGEST_LENGTH); session->state = PWD_STATE_CONFIRM; ret = send_pwd_request(session, eap_ds); break; case PWD_STATE_CONFIRM: if (in_len < SHA256_DIGEST_LENGTH) { RDEBUG("Peer confirm is too short (%zd < %d)", in_len, SHA256_DIGEST_LENGTH); return 0; } if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_CONFIRM) { RDEBUG2("pwd exchange is incorrect: not commit!"); return 0; } if (compute_peer_confirm(session, peer_confirm, inst->bnctx)) { RDEBUG2("pwd exchange cannot compute peer's confirm"); return 0; } if (CRYPTO_memcmp(peer_confirm, in, SHA256_DIGEST_LENGTH)) { RDEBUG2("pwd exchange fails: peer confirm is incorrect!"); return 0; } if (compute_keys(session, peer_confirm, msk, emsk)) { RDEBUG2("pwd exchange cannot generate (E)MSK!"); return 0; } eap_ds->request->code = PW_EAP_SUCCESS; /* * return the MSK (in halves) */ eap_add_reply(handler->request, "MS-MPPE-Recv-Key", msk, MPPE_KEY_LEN); eap_add_reply(handler->request, "MS-MPPE-Send-Key", msk + MPPE_KEY_LEN, MPPE_KEY_LEN); ret = 1; break; default: RDEBUG2("unknown PWD state"); return 0; } /* * we processed the buffered fragments, get rid of them */ if (session->in) { talloc_free(session->in); session->in = NULL; } return ret; }
static NTSTATUS cmd_eventlog_loginfo(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { NTSTATUS status, result; struct policy_handle handle; uint8_t *buffer = NULL; uint32_t buf_size = 0; uint32_t bytes_needed = 0; struct dcerpc_binding_handle *b = cli->binding_handle; if (argc != 2) { printf("Usage: %s logname\n", argv[0]); return NT_STATUS_OK; } status = get_eventlog_handle(cli, mem_ctx, argv[1], &handle); if (!NT_STATUS_IS_OK(status)) { return status; } status = dcerpc_eventlog_GetLogInformation(b, mem_ctx, &handle, 0, /* level */ buffer, buf_size, &bytes_needed, &result); if (!NT_STATUS_IS_OK(status)) { goto done; } if (!NT_STATUS_IS_OK(result) && !NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)) { goto done; } buf_size = bytes_needed; buffer = talloc_array(mem_ctx, uint8_t, bytes_needed); if (!buffer) { status = NT_STATUS_NO_MEMORY; goto done; } status = dcerpc_eventlog_GetLogInformation(b, mem_ctx, &handle, 0, /* level */ buffer, buf_size, &bytes_needed, &result); if (!NT_STATUS_IS_OK(status)) { goto done; } if (!NT_STATUS_IS_OK(result)) { status = result; goto done; } done: dcerpc_eventlog_CloseEventLog(b, mem_ctx, &handle, &result); return status; }
/** Authenticate a previously sent challenge * */ static int mod_process(void *instance, eap_handler_t *handler) { uint8_t *in; uint8_t *out = NULL; uint8_t *ikemsg; u_int32_t len; uint8_t *sikemsg = NULL; //out message u_int32_t slen = 0; u_int32_t olen = 0; struct ikev2_ctx *i2 = (struct ikev2_ctx*)instance; struct EAPHeader *hdr; struct IKEv2Data *ikev2_data; struct IKEv2Session *session; INFO(IKEv2_LOG_PREFIX "authenticate" ); rad_assert(handler->request != NULL); rad_assert(handler->stage == PROCESS); EAP_DS *eap_ds=handler->eap_ds; if (!eap_ds || !eap_ds->response || (eap_ds->response->code != PW_IKEV2_RESPONSE) || eap_ds->response->type.num != PW_EAP_IKEV2 || !eap_ds->response->type.data) { ERROR(IKEv2_LOG_PREFIX "corrupted data"); return -1; } in = talloc_array(eap_ds, uint8_t, eap_ds->response->length); if (in){ ERROR(IKEv2_LOG_PREFIX "alloc error"); return -1; } rad_assert(in != NULL); hdr = (struct EAPHeader *)in; hdr->Code = eap_ds->response->code; hdr->Id = eap_ds->response->id; hdr->Length = htons(eap_ds->response->length); hdr->Type = eap_ds->response->type.num; memcpy(in + 5, eap_ds->response->type.data, eap_ds->response->length - 5); ikev2_data = (struct IKEv2Data*)handler->opaque; session = ikev2_data->session; session->timestamp = time(NULL); if (!session->fragdata) session->sendfrag = false; if (session->sendfrag && !ParseFragmentAck(in, session)){ session->eapMsgID = eap_ds->response->id + 1; olen = CreateIKEv2Message(i2, NULL, 0, false, hdr->Id, session, (uint8_t **)&out); talloc_free(in); if (compose_rad_message(out,olen,handler->eap_ds)) { free(out); return 0; } free(out); return 1; } session->eapMsgID = eap_ds->response->id + 1; if (ParseIKEv2Message(in, &ikemsg, &len, session)){ if (ikemsg != NULL) free(ikemsg); handler->eap_ds->request->code=PW_EAP_FAILURE; INFO(IKEv2_LOG_PREFIX "Discarded packet"); return 1; } /* Send fragment ack */ if (!ikemsg || !len) { if (session->SK_ready) session->include_integ = 1; olen = CreateFragmentAck(in, &out, session); // confirm fragment TALLOC_FREE(in); if (compose_rad_message(out,olen,handler->eap_ds)) { free(out); return 0; } free(out); return 1; } TALLOC_FREE(in); if (IKEv2ProcessMsg(i2, ikemsg, &sikemsg, &slen, session) != IKEv2_RET_OK) { INFO(IKEv2_LOG_PREFIX "EAP_STATE_DISCARD"); //session->State = EAP_STATE_DISCARD; free(out); return 1; } free(ikemsg); /* If there is there is something to send */ if (slen != 0){ olen = CreateIKEv2Message(i2, sikemsg, slen, false, 0, session, &out); if (session->fragdata) session->sendfrag = true; } else { if (session->Status == IKEv2_SST_FAILED ) { INFO(IKEv2_LOG_PREFIX "FAILED"); olen = CreateResultMessage( false, session, &out ); } if(session->Status == IKEv2_SST_ESTABLISHED) { INFO(IKEv2_LOG_PREFIX "SUCCESS"); olen = CreateResultMessage(true, session, &out); session->fFastReconnect = i2->enableFastReconnect; GenEapKeys(session ,EAP_IKEv2_KEY_LEN); set_mppe_keys(handler); } // keep sessions in memory, only reference cleared ikev2_data->session = NULL; } if ((olen > 0) && (out != NULL)){ if (compose_rad_message(out, olen, handler->eap_ds)){ free(out); return 0; } } free(out); return 1; }
/** Send the challenge itself * * Challenges will come from one of three places eventually: * * 1 from attributes like PW_EAP_SIM_RANDx * (these might be retrived from a database) * * 2 from internally implemented SIM authenticators * (a simple one based upon XOR will be provided) * * 3 from some kind of SS7 interface. * * For now, they only come from attributes. * It might be that the best way to do 2/3 will be with a different * module to generate/calculate things. * */ static int eap_sim_sendchallenge(eap_handler_t *handler) { REQUEST *request = handler->request; eap_sim_state_t *ess; VALUE_PAIR **invps, **outvps, *newvp; RADIUS_PACKET *packet; uint8_t *p; ess = (eap_sim_state_t *)handler->opaque; rad_assert(handler->request != NULL); rad_assert(handler->request->reply); /* * Invps is the data from the client but this is for non-protocol data here. * We should already have consumed any client originated data. */ invps = &handler->request->packet->vps; /* * Outvps is the data to the client */ packet = handler->request->reply; outvps = &packet->vps; if (RDEBUG_ENABLED2) { RDEBUG2("EAP-SIM decoded packet"); rdebug_pair_list(L_DBG_LVL_2, request, *invps, NULL); } /* * Okay, we got the challenges! Put them into an attribute. */ newvp = paircreate(packet, PW_EAP_SIM_RAND, 0); newvp->length = 2 + (EAPSIM_RAND_SIZE * 3); newvp->vp_octets = p = talloc_array(newvp, uint8_t, newvp->length); memset(p, 0, 2); /* clear reserved bytes */ p += 2; memcpy(p, ess->keys.rand[0], EAPSIM_RAND_SIZE); p += EAPSIM_RAND_SIZE; memcpy(p, ess->keys.rand[1], EAPSIM_RAND_SIZE); p += EAPSIM_RAND_SIZE; memcpy(p, ess->keys.rand[2], EAPSIM_RAND_SIZE); pairadd(outvps, newvp); /* * Set the EAP_ID - new value */ newvp = paircreate(packet, PW_EAP_ID, 0); newvp->vp_integer = ess->sim_id++; pairreplace(outvps, newvp); /* * Make a copy of the identity */ ess->keys.identitylen = strlen(handler->identity); memcpy(ess->keys.identity, handler->identity, ess->keys.identitylen); /* * Use the SIM identity, if available */ newvp = pairfind(*invps, PW_EAP_SIM_IDENTITY, 0, TAG_ANY); if (newvp && newvp->length > 2) { uint16_t len; memcpy(&len, newvp->vp_octets, sizeof(uint16_t)); len = ntohs(len); if (len <= newvp->length - 2 && len <= MAX_STRING_LEN) { ess->keys.identitylen = len; memcpy(ess->keys.identity, newvp->vp_octets + 2, ess->keys.identitylen); } } /* * All set, calculate keys! */ eapsim_calculate_keys(&ess->keys); #ifdef EAP_SIM_DEBUG_PRF eapsim_dump_mk(&ess->keys); #endif /* * Need to include an AT_MAC attribute so that it will get * calculated. The NONCE_MT and the MAC are both 16 bytes, so * We store the NONCE_MT in the MAC for the encoder, which * will pull it out before it does the operation. */ newvp = paircreate(packet, PW_EAP_SIM_MAC, 0); pairmemcpy(newvp, ess->keys.nonce_mt, 16); pairreplace(outvps, newvp); newvp = paircreate(packet, PW_EAP_SIM_KEY, 0); pairmemcpy(newvp, ess->keys.K_aut, 16); pairreplace(outvps, newvp); /* the SUBTYPE, set to challenge. */ newvp = paircreate(packet, PW_EAP_SIM_SUBTYPE, 0); newvp->vp_integer = EAPSIM_CHALLENGE; pairreplace(outvps, newvp); return 1; }
/** \details Retrieve the message properties for an already open message. This function is very similar to OpenMessage, but works on an already open message object. \param obj_message the message object to retrieve the properties for. \return MAPI_E_SUCCESS on success, otherwise MAPI error. \note Developers may also call GetLastError() to retrieve the last MAPI error code. Possible MAPI error codes are: - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized - MAPI_E_INVALID_PARAMETER: obj_store is undefined - MAPI_E_CALL_FAILED: A network problem was encountered during the transaction \sa OpenMessage */ _PUBLIC_ enum MAPISTATUS ReloadCachedInformation(mapi_object_t *obj_message) { struct mapi_context *mapi_ctx; struct mapi_request *mapi_request; struct mapi_response *mapi_response; struct EcDoRpc_MAPI_REQ *mapi_req; struct ReloadCachedInformation_req request; struct ReloadCachedInformation_repl *reply; struct mapi_session *session; mapi_object_message_t *message; struct SPropValue lpProp; NTSTATUS status; enum MAPISTATUS retval; uint32_t size = 0; TALLOC_CTX *mem_ctx; uint32_t i = 0; uint8_t logon_id; /* Sanity checks */ OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_INVALID_PARAMETER, NULL); session = mapi_object_get_session(obj_message); OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL); mapi_ctx = session->mapi_ctx; OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL); if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS) return retval; mem_ctx = talloc_named(session, 0, "ReloadCachedInformation"); /* Fill the ReloadCachedInformation operation */ request.Reserved = 0x0000; size += sizeof (uint16_t); /* Fill the MAPI_REQ request */ mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ); mapi_req->opnum = op_MAPI_ReloadCachedInformation; mapi_req->logon_id = logon_id; mapi_req->handle_idx = 0; mapi_req->u.mapi_ReloadCachedInformation = request; size += 5; /* Fill the mapi_request structure */ mapi_request = talloc_zero(mem_ctx, struct mapi_request); mapi_request->mapi_len = size + sizeof (uint32_t); mapi_request->length = size; mapi_request->mapi_req = mapi_req; mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1); mapi_request->handles[0] = mapi_object_get_handle(obj_message); status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response); OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx); OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx); retval = mapi_response->mapi_repl->error_code; OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx); OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response); /* Store ReloadCachedInformation reply data */ reply = &mapi_response->mapi_repl->u.mapi_ReloadCachedInformation; message = talloc_zero((TALLOC_CTX *)session, mapi_object_message_t); message->cValues = reply->RecipientColumns.cValues; message->SRowSet.cRows = reply->RowCount; message->SRowSet.aRow = talloc_array((TALLOC_CTX *)message, struct SRow, reply->RowCount + 1); message->SPropTagArray.cValues = reply->RecipientColumns.cValues; message->SPropTagArray.aulPropTag = talloc_steal(message, reply->RecipientColumns.aulPropTag); for (i = 0; i < reply->RowCount; i++) { emsmdb_get_SRow((TALLOC_CTX *)message, &(message->SRowSet.aRow[i]), &message->SPropTagArray, reply->RecipientRows[i].RecipientRow.prop_count, &reply->RecipientRows[i].RecipientRow.prop_values, reply->RecipientRows[i].RecipientRow.layout, 1); lpProp.ulPropTag = PR_RECIPIENT_TYPE; lpProp.value.l = reply->RecipientRows[i].RecipientType; SRow_addprop(&(message->SRowSet.aRow[i]), lpProp); lpProp.ulPropTag = PR_INTERNET_CPID; lpProp.value.l = reply->RecipientRows[i].CodePageId; SRow_addprop(&(message->SRowSet.aRow[i]), lpProp); } /* add SPropTagArray elements we automatically append to SRow */ SPropTagArray_add((TALLOC_CTX *)message, &message->SPropTagArray, PR_RECIPIENT_TYPE); SPropTagArray_add((TALLOC_CTX *)message, &message->SPropTagArray, PR_INTERNET_CPID); talloc_free(obj_message->private_data); obj_message->private_data = (void *) message; talloc_free(mapi_response); talloc_free(mem_ctx); errno = 0; return MAPI_E_SUCCESS; }
static int mod_authenticate (void *arg, eap_handler_t *handler) { pwd_session_t *pwd_session; pwd_hdr *hdr; pwd_id_packet *id; eap_packet_t *response; REQUEST *request, *fake; VALUE_PAIR *pw, *vp; EAP_DS *eap_ds; int len, ret = 0; eap_pwd_t *inst = (eap_pwd_t *)arg; uint16_t offset; uint8_t exch, *buf, *ptr, msk[MSK_EMSK_LEN], emsk[MSK_EMSK_LEN]; uint8_t peer_confirm[SHA256_DIGEST_LENGTH]; BIGNUM *x = NULL, *y = NULL; if ((!handler) || ((eap_ds = handler->eap_ds) == NULL) || (!inst)) { return 0; } pwd_session = (pwd_session_t *)handler->opaque; request = handler->request; response = handler->eap_ds->response; hdr = (pwd_hdr *)response->type.data; buf = hdr->data; len = response->type.length - sizeof(pwd_hdr); /* * see if we're fragmenting, if so continue until we're done */ if (pwd_session->out_buf_pos) { if (len) { RDEBUG2("pwd got something more than an ACK for a fragment"); } return send_pwd_request(pwd_session, eap_ds); } /* * the first fragment will have a total length, make a * buffer to hold all the fragments */ if (EAP_PWD_GET_LENGTH_BIT(hdr)) { if (pwd_session->in_buf) { RDEBUG2("pwd already alloced buffer for fragments"); return 0; } pwd_session->in_buf_len = ntohs(buf[0] * 256 | buf[1]); if ((pwd_session->in_buf = talloc_zero_array(pwd_session, uint8_t, pwd_session->in_buf_len)) == NULL) { RDEBUG2("pwd cannot allocate %d buffer to hold fragments", pwd_session->in_buf_len); return 0; } memset(pwd_session->in_buf, 0, pwd_session->in_buf_len); pwd_session->in_buf_pos = 0; buf += sizeof(uint16_t); len -= sizeof(uint16_t); } /* * all fragments, including the 1st will have the M(ore) bit set, * buffer those fragments! */ if (EAP_PWD_GET_MORE_BIT(hdr)) { rad_assert(pwd_session->in_buf != NULL); if ((pwd_session->in_buf_pos + len) > pwd_session->in_buf_len) { RDEBUG2("pwd will not overflow a fragment buffer. Nope, not prudent."); return 0; } memcpy(pwd_session->in_buf + pwd_session->in_buf_pos, buf, len); pwd_session->in_buf_pos += len; /* * send back an ACK for this fragment */ exch = EAP_PWD_GET_EXCHANGE(hdr); eap_ds->request->code = PW_EAP_REQUEST; eap_ds->request->type.num = PW_EAP_PWD; eap_ds->request->type.length = sizeof(pwd_hdr); if ((eap_ds->request->type.data = talloc_array(eap_ds->request, uint8_t, sizeof(pwd_hdr))) == NULL) { return 0; } hdr = (pwd_hdr *)eap_ds->request->type.data; EAP_PWD_SET_EXCHANGE(hdr, exch); return 1; } if (pwd_session->in_buf) { /* * the last fragment... */ if ((pwd_session->in_buf_pos + len) > pwd_session->in_buf_len) { RDEBUG2("pwd will not overflow a fragment buffer. Nope, not prudent."); return 0; } memcpy(pwd_session->in_buf + pwd_session->in_buf_pos, buf, len); buf = pwd_session->in_buf; len = pwd_session->in_buf_len; } switch (pwd_session->state) { case PWD_STATE_ID_REQ: if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_ID) { RDEBUG2("pwd exchange is incorrect: not ID"); return 0; } id = (pwd_id_packet *)buf; if ((id->prf != EAP_PWD_DEF_PRF) || (id->random_function != EAP_PWD_DEF_RAND_FUN) || (id->prep != EAP_PWD_PREP_NONE) || (memcmp(id->token, (char *)&pwd_session->token, 4)) || (id->group_num != ntohs(pwd_session->group_num))) { RDEBUG2("pwd id response is invalid"); return 0; } /* * we've agreed on the ciphersuite, record it... */ ptr = (uint8_t *)&pwd_session->ciphersuite; memcpy(ptr, (char *)&id->group_num, sizeof(uint16_t)); ptr += sizeof(uint16_t); *ptr = EAP_PWD_DEF_RAND_FUN; ptr += sizeof(uint8_t); *ptr = EAP_PWD_DEF_PRF; pwd_session->peer_id_len = len - sizeof(pwd_id_packet); if (pwd_session->peer_id_len >= sizeof(pwd_session->peer_id)) { RDEBUG2("pwd id response is malformed"); return 0; } memcpy(pwd_session->peer_id, id->identity, pwd_session->peer_id_len); pwd_session->peer_id[pwd_session->peer_id_len] = '\0'; /* * make fake request to get the password for the usable ID */ if ((fake = request_alloc_fake(handler->request)) == NULL) { RDEBUG("pwd unable to create fake request!"); return 0; } fake->username = pairmake_packet("User-Name", "", T_OP_EQ); if (!fake->username) { RDEBUG("pwd unanable to create value pair for username!"); request_free(&fake); return 0; } memcpy(fake->username->vp_strvalue, pwd_session->peer_id, pwd_session->peer_id_len); fake->username->length = pwd_session->peer_id_len; fake->username->vp_strvalue[fake->username->length] = 0; if ((vp = pairfind(request->config_items, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) { fake->server = vp->vp_strvalue; } else if (inst->conf->virtual_server) { fake->server = inst->conf->virtual_server; } /* else fake->server == request->server */ if ((debug_flag > 0) && fr_log_fp) { RDEBUG("Sending tunneled request"); debug_pair_list(fake->packet->vps); fprintf(fr_log_fp, "server %s {\n", (!fake->server) ? "" : fake->server); } /* * Call authorization recursively, which will * get the password. */ process_authorize(0, fake); /* * Note that we don't do *anything* with the reply * attributes. */ if ((debug_flag > 0) && fr_log_fp) { fprintf(fr_log_fp, "} # server %s\n", (!fake->server) ? "" : fake->server); RDEBUG("Got tunneled reply code %d", fake->reply->code); debug_pair_list(fake->reply->vps); } if ((pw = pairfind(fake->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) == NULL) { DEBUG2("failed to find password for %s to do pwd authentication", pwd_session->peer_id); request_free(&fake); return 0; } if (compute_password_element(pwd_session, pwd_session->group_num, pw->data.strvalue, strlen(pw->data.strvalue), inst->conf->server_id, strlen(inst->conf->server_id), pwd_session->peer_id, strlen(pwd_session->peer_id), &pwd_session->token)) { DEBUG2("failed to obtain password element :-("); request_free(&fake); return 0; } request_free(&fake); /* * compute our scalar and element */ if (compute_scalar_element(pwd_session, inst->bnctx)) { DEBUG2("failed to compute server's scalar and element"); return 0; } if (((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) { DEBUG2("server point allocation failed"); return 0; } /* * element is a point, get both coordinates: x and y */ if (!EC_POINT_get_affine_coordinates_GFp(pwd_session->group, pwd_session->my_element, x, y, inst->bnctx)) { DEBUG2("server point assignment failed"); BN_free(x); BN_free(y); return 0; } /* * construct request */ pwd_session->out_buf_len = BN_num_bytes(pwd_session->order) + (2 * BN_num_bytes(pwd_session->prime)); if ((pwd_session->out_buf = talloc_array(pwd_session, uint8_t, pwd_session->out_buf_len)) == NULL) { return 0; } memset(pwd_session->out_buf, 0, pwd_session->out_buf_len); ptr = pwd_session->out_buf; offset = BN_num_bytes(pwd_session->prime) - BN_num_bytes(x); BN_bn2bin(x, ptr + offset); ptr += BN_num_bytes(pwd_session->prime); offset = BN_num_bytes(pwd_session->prime) - BN_num_bytes(y); BN_bn2bin(y, ptr + offset); ptr += BN_num_bytes(pwd_session->prime); offset = BN_num_bytes(pwd_session->order) - BN_num_bytes(pwd_session->my_scalar); BN_bn2bin(pwd_session->my_scalar, ptr + offset); pwd_session->state = PWD_STATE_COMMIT; ret = send_pwd_request(pwd_session, eap_ds); break; case PWD_STATE_COMMIT: if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_COMMIT) { RDEBUG2("pwd exchange is incorrect: not commit!"); return 0; } /* * process the peer's commit and generate the shared key, k */ if (process_peer_commit(pwd_session, buf, inst->bnctx)) { RDEBUG2("failed to process peer's commit"); return 0; } /* * compute our confirm blob */ if (compute_server_confirm(pwd_session, pwd_session->my_confirm, inst->bnctx)) { ERROR("rlm_eap_pwd: failed to compute confirm!"); return 0; } /* * construct a response...which is just our confirm blob */ pwd_session->out_buf_len = SHA256_DIGEST_LENGTH; if ((pwd_session->out_buf = talloc_array(pwd_session, uint8_t, pwd_session->out_buf_len)) == NULL) { return 0; } memset(pwd_session->out_buf, 0, pwd_session->out_buf_len); memcpy(pwd_session->out_buf, pwd_session->my_confirm, SHA256_DIGEST_LENGTH); pwd_session->state = PWD_STATE_CONFIRM; ret = send_pwd_request(pwd_session, eap_ds); break; case PWD_STATE_CONFIRM: if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_CONFIRM) { RDEBUG2("pwd exchange is incorrect: not commit!"); return 0; } if (compute_peer_confirm(pwd_session, peer_confirm, inst->bnctx)) { RDEBUG2("pwd exchange cannot compute peer's confirm"); return 0; } if (memcmp(peer_confirm, buf, SHA256_DIGEST_LENGTH)) { RDEBUG2("pwd exchange fails: peer confirm is incorrect!"); return 0; } if (compute_keys(pwd_session, peer_confirm, msk, emsk)) { RDEBUG2("pwd exchange cannot generate (E)MSK!"); return 0; } eap_ds->request->code = PW_EAP_SUCCESS; /* * return the MSK (in halves) */ eap_add_reply(handler->request, "MS-MPPE-Recv-Key", msk, MPPE_KEY_LEN); eap_add_reply(handler->request, "MS-MPPE-Send-Key", msk+MPPE_KEY_LEN, MPPE_KEY_LEN); ret = 1; break; default: RDEBUG2("unknown PWD state"); return 0; } /* * we processed the buffered fragments, get rid of them */ if (pwd_session->in_buf) { talloc_free(pwd_session->in_buf); pwd_session->in_buf = NULL; } return ret; }
/* copy a file. Caller is supposed to have already ensured that the operation is allowed. The destination file must not exist. */ NTSTATUS pvfs_copy_file(struct pvfs_state *pvfs, struct pvfs_filename *name1, struct pvfs_filename *name2) { int fd1, fd2; mode_t mode; NTSTATUS status; size_t buf_size = 0x10000; uint8_t *buf = talloc_array(name2, uint8_t, buf_size); if (buf == NULL) { return NT_STATUS_NO_MEMORY; } fd1 = pvfs_sys_open(pvfs, name1->full_name, O_RDONLY, 0); if (fd1 == -1) { talloc_free(buf); return pvfs_map_errno(pvfs, errno); } fd2 = pvfs_sys_open(pvfs, name2->full_name, O_CREAT|O_EXCL|O_WRONLY, 0); if (fd2 == -1) { close(fd1); talloc_free(buf); return pvfs_map_errno(pvfs, errno); } while (1) { ssize_t ret2, ret = read(fd1, buf, buf_size); if (ret == -1 && (errno == EINTR || errno == EAGAIN)) { continue; } if (ret <= 0) break; ret2 = write(fd2, buf, ret); if (ret2 == -1 && (errno == EINTR || errno == EAGAIN)) { continue; } if (ret2 != ret) { close(fd1); close(fd2); talloc_free(buf); pvfs_sys_unlink(pvfs, name2->full_name); if (ret2 == -1) { return pvfs_map_errno(pvfs, errno); } return NT_STATUS_DISK_FULL; } } talloc_free(buf); close(fd1); mode = pvfs_fileperms(pvfs, name1->dos.attrib); if (pvfs_sys_fchmod(pvfs, fd2, mode) == -1) { status = pvfs_map_errno(pvfs, errno); close(fd2); pvfs_sys_unlink(pvfs, name2->full_name); return status; } name2->st.st_mode = mode; name2->dos = name1->dos; status = pvfs_dosattrib_save(pvfs, name2, fd2); if (!NT_STATUS_IS_OK(status)) { close(fd2); pvfs_sys_unlink(pvfs, name2->full_name); return status; } close(fd2); return NT_STATUS_OK; }