void aes_ccm_128_init(struct aes_ccm_128_context *ctx, const uint8_t K[AES_BLOCK_SIZE], const uint8_t N[AES_CCM_128_NONCE_SIZE], size_t a_total, size_t m_total) { uint8_t B_0[AES_BLOCK_SIZE]; ZERO_STRUCTP(ctx); AES_set_encrypt_key(K, 128, &ctx->aes_key); memcpy(ctx->nonce, N, AES_CCM_128_NONCE_SIZE); ctx->a_remain = a_total; ctx->m_remain = m_total; /* * prepare B_0 */ B_0[0] = L_; B_0[0] += 8 * M_; if (a_total > 0) { B_0[0] += 64; } memcpy(&B_0[1], ctx->nonce, AES_CCM_128_NONCE_SIZE); RSIVAL(B_0, (AES_BLOCK_SIZE - AES_CCM_128_L), m_total); /* * prepare X_1 */ AES_encrypt(B_0, ctx->X_i, &ctx->aes_key); /* * prepare B_1 */ if (a_total >= UINT32_MAX) { RSSVAL(ctx->B_i, 0, 0xFFFF); RSBVAL(ctx->B_i, 2, (uint64_t)a_total); ctx->B_i_ofs = 10; } else if (a_total >= 0xFF00) { RSSVAL(ctx->B_i, 0, 0xFFFE); RSIVAL(ctx->B_i, 2, a_total); ctx->B_i_ofs = 6; } else if (a_total > 0) { RSSVAL(ctx->B_i, 0, a_total); ctx->B_i_ofs = 2; } ctx->S_i_ofs = AES_BLOCK_SIZE; }
static void dbg_rw_punival(BOOL charmode, const char *name, int depth, prs_struct *ps, char *in_buf, char *out_buf, int len) { int i; if (UNMARSHALLING(ps)) { if (ps->bigendian_data) { for (i = 0; i < len; i++) SSVAL(out_buf,2*i,RSVAL(in_buf, 2*i)); } else { for (i = 0; i < len; i++) SSVAL(out_buf, 2*i, SVAL(in_buf, 2*i)); } } else { if (ps->bigendian_data) { for (i = 0; i < len; i++) RSSVAL(in_buf, 2*i, SVAL(out_buf,2*i)); } else { for (i = 0; i < len; i++) SSVAL(in_buf, 2*i, SVAL(out_buf,2*i)); } } DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name)); if (charmode) print_asc(5, (unsigned char*)out_buf, 2*len); else { for (i = 0; i < len; i++) DEBUG(5,("%04x ", out_buf[i])); } DEBUG(5,("\n")); }
void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v) { if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) { SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v); } else { RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v); } }
/* this function is due to be replaced */ void initrpcreply(char *inbuf, char *q) { uint32 callid; SCVAL(q, 0, 5); q++; /* RPC version 5 */ SCVAL(q, 0, 0); q++; /* minor version 0 */ SCVAL(q, 0, 2); q++; /* RPC response packet */ SCVAL(q, 0, 3); q++; /* first frag + last frag */ RSIVAL(q, 0, 0x10000000); q += 4; /* packed data representation */ RSSVAL(q, 0, 0); q += 2; /* fragment length, fill in later */ SSVAL(q, 0, 0); q += 2; /* authentication length */ callid = RIVAL(inbuf, 12); RSIVAL(q, 0, callid); q += 4; /* call identifier - match incoming RPC */ SIVAL(q, 0, 0x18); q += 4; /* allocation hint (no idea) */ SSVAL(q, 0, 0); q += 2; /* presentation context identifier */ SCVAL(q, 0, 0); q++; /* cancel count */ SCVAL(q, 0, 0); q++; /* reserved */ }
/* send a WACK reply */ void nbtd_wack_reply(struct nbt_name_socket *nbtsock, struct nbt_name_packet *request_packet, struct socket_address *src, uint32_t ttl) { struct nbt_name_packet *packet; struct nbt_name *name = &request_packet->questions[0].name; struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, struct nbtd_interface); struct nbtd_server *nbtsrv = iface->nbtsrv; packet = talloc_zero(nbtsock, struct nbt_name_packet); if (packet == NULL) return; packet->name_trn_id = request_packet->name_trn_id; packet->ancount = 1; packet->operation = NBT_FLAG_REPLY | NBT_OPCODE_WACK | NBT_FLAG_AUTHORITIVE; packet->answers = talloc_array(packet, struct nbt_res_rec, 1); if (packet->answers == NULL) goto failed; packet->answers[0].name = *name; packet->answers[0].rr_type = NBT_QTYPE_NETBIOS; packet->answers[0].rr_class = NBT_QCLASS_IP; packet->answers[0].ttl = ttl; packet->answers[0].rdata.data.length = 2; packet->answers[0].rdata.data.data = talloc_size(packet, 2); if (packet->answers[0].rdata.data.data == NULL) goto failed; RSSVAL(packet->answers[0].rdata.data.data, 0, request_packet->operation); DEBUG(7,("Sending WACK reply for %s to %s:%d\n", nbt_name_string(packet, name), src->addr, src->port)); nbtsrv->stats.total_sent++; nbt_name_reply_send(nbtsock, src, packet); failed: talloc_free(packet); }
BOOL prs_uint16s(BOOL charmode, const char *name, prs_struct *ps, int depth, uint16 *data16s, int len) { int i; char *q = prs_mem_get(ps, len * sizeof(uint16)); if (q == NULL) return False; if (UNMARSHALLING(ps)) { if (ps->bigendian_data) { for (i = 0; i < len; i++) data16s[i] = RSVAL(q, 2*i); } else { for (i = 0; i < len; i++) data16s[i] = SVAL(q, 2*i); } } else { if (ps->bigendian_data) { for (i = 0; i < len; i++) RSSVAL(q, 2*i, data16s[i]); } else { for (i = 0; i < len; i++) SSVAL(q, 2*i, data16s[i]); } } DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name)); if (charmode) print_asc(5, (unsigned char*)data16s, 2*len); else { for (i = 0; i < len; i++) DEBUG(5,("%04x ", data16s[i])); } DEBUG(5,("\n")); ps->data_offset += (len * sizeof(uint16)); return True; }
int buffer_add_uint16(xrtp_buffer_t * buf, uint16 word){ if(buf->len_data + sizeof(uint16) > buf->len){ return OS_EREFUSE; } if(buf->byte_order == BIGEND_ORDER) { buffer_log(("buffer_add_uint16: Add BE(%u) to buf[%d]@%d\n", word, buf->pos, (int)(buf->data))); RSSVAL(buf->data, buf->len_data, word); } else { buffer_log(("buffer_add_uint16: Add LE(%u) to buf[%d]@%d\n", word, buf->pos, (int)(buf->data))); SSVAL(buf->data, buf->len_data, word); } buf->len_data += sizeof(uint16); buf->pos += sizeof(uint16); return OS_OK; }
/* Return true if there is a valid error packet formed in the error_blob */ static bool kpasswdd_make_error_reply(struct kdc_server *kdc, TALLOC_CTX *mem_ctx, uint16_t result_code, const char *error_string, DATA_BLOB *error_blob) { char *error_string_utf8; size_t len; DEBUG(result_code ? 3 : 10, ("kpasswdd: %s\n", error_string)); if (!push_utf8_talloc(mem_ctx, &error_string_utf8, error_string, &len)) { return false; } *error_blob = data_blob_talloc(mem_ctx, NULL, 2 + len + 1); if (!error_blob->data) { return false; } RSSVAL(error_blob->data, 0, result_code); memcpy(error_blob->data + 2, error_string_utf8, len + 1); return true; }
BOOL prs_uint16(const char *name, prs_struct *ps, int depth, uint16 *data16) { char *q = prs_mem_get(ps, sizeof(uint16)); if (q == NULL) return False; if (UNMARSHALLING(ps)) { if (ps->bigendian_data) *data16 = RSVAL(q,0); else *data16 = SVAL(q,0); } else { if (ps->bigendian_data) RSSVAL(q,0,*data16); else SSVAL(q,0,*data16); } DEBUG(5,("%s%04x %s: %04x\n", tab_depth(depth), ps->data_offset, name, *data16)); ps->data_offset += sizeof(uint16); return True; }
static krb5_error_code build_kpasswd_request(uint16 pversion, krb5_context context, krb5_auth_context auth_context, krb5_data *ap_req, const char *princ, const char *passwd, bool use_tcp, krb5_data *packet) { krb5_error_code ret; krb5_data cipherpw; krb5_data encoded_setpw; krb5_replay_data replay; char *p, *msg_start; DATA_BLOB setpw; unsigned int msg_length; ret = krb5_auth_con_setflags(context, auth_context,KRB5_AUTH_CONTEXT_DO_SEQUENCE); if (ret) { DEBUG(1,("krb5_auth_con_setflags failed (%s)\n", error_message(ret))); return ret; } /* handle protocol differences in chpw and setpw */ if (pversion == KRB5_KPASSWD_VERS_CHANGEPW) setpw = data_blob(passwd, strlen(passwd)); else if (pversion == KRB5_KPASSWD_VERS_SETPW || pversion == KRB5_KPASSWD_VERS_SETPW_ALT) setpw = encode_krb5_setpw(princ, passwd); else return EINVAL; if (setpw.data == NULL || setpw.length == 0) { return EINVAL; } encoded_setpw.data = (char *)setpw.data; encoded_setpw.length = setpw.length; ret = krb5_mk_priv(context, auth_context, &encoded_setpw, &cipherpw, &replay); data_blob_free(&setpw); /*from 'encode_krb5_setpw(...)' */ if (ret) { DEBUG(1,("krb5_mk_priv failed (%s)\n", error_message(ret))); return ret; } packet->data = (char *)SMB_MALLOC(ap_req->length + cipherpw.length + (use_tcp ? 10 : 6 )); if (!packet->data) return -1; /* see the RFC for details */ msg_start = p = ((char *)packet->data) + (use_tcp ? 4 : 0); p += 2; RSSVAL(p, 0, pversion); p += 2; RSSVAL(p, 0, ap_req->length); p += 2; memcpy(p, ap_req->data, ap_req->length); p += ap_req->length; memcpy(p, cipherpw.data, cipherpw.length); p += cipherpw.length; packet->length = PTR_DIFF(p,packet->data); msg_length = PTR_DIFF(p,msg_start); if (use_tcp) { RSIVAL(packet->data, 0, msg_length); } RSSVAL(msg_start, 0, msg_length); free(cipherpw.data); /* from 'krb5_mk_priv(...)' */ return 0; }
bool kpasswdd_process(struct kdc_server *kdc, TALLOC_CTX *mem_ctx, DATA_BLOB *input, DATA_BLOB *reply, struct tsocket_address *peer_addr, struct tsocket_address *my_addr, int datagram_reply) { bool ret; const uint16_t header_len = 6; uint16_t len; uint16_t ap_req_len; uint16_t krb_priv_len; uint16_t version; NTSTATUS nt_status; DATA_BLOB ap_req, krb_priv_req; DATA_BLOB krb_priv_rep = data_blob(NULL, 0); DATA_BLOB ap_rep = data_blob(NULL, 0); DATA_BLOB kpasswd_req, kpasswd_rep; struct cli_credentials *server_credentials; struct gensec_security *gensec_security; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); char *keytab_name; if (!tmp_ctx) { return false; } /* Be parinoid. We need to ensure we don't just let the * caller lead us into a buffer overflow */ if (input->length <= header_len) { talloc_free(tmp_ctx); return false; } len = RSVAL(input->data, 0); if (input->length != len) { talloc_free(tmp_ctx); return false; } /* There are two different versions of this protocol so far, * plus others in the standards pipe. Fortunetly they all * take a very similar framing */ version = RSVAL(input->data, 2); ap_req_len = RSVAL(input->data, 4); if ((ap_req_len >= len) || (ap_req_len + header_len) >= len) { talloc_free(tmp_ctx); return false; } krb_priv_len = len - ap_req_len; ap_req = data_blob_const(&input->data[header_len], ap_req_len); krb_priv_req = data_blob_const(&input->data[header_len + ap_req_len], krb_priv_len); server_credentials = cli_credentials_init(tmp_ctx); if (!server_credentials) { DEBUG(1, ("Failed to init server credentials\n")); return false; } /* We want the credentials subsystem to use the krb5 context * we already have, rather than a new context */ cli_credentials_set_krb5_context(server_credentials, kdc->smb_krb5_context); cli_credentials_set_conf(server_credentials, kdc->task->lp_ctx); keytab_name = talloc_asprintf(server_credentials, "HDB:samba4&%p", kdc->base_ctx); cli_credentials_set_username(server_credentials, "kadmin/changepw", CRED_SPECIFIED); ret = cli_credentials_set_keytab_name(server_credentials, kdc->task->event_ctx, kdc->task->lp_ctx, keytab_name, CRED_SPECIFIED); if (ret != 0) { ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, KRB5_KPASSWD_HARDERROR, talloc_asprintf(mem_ctx, "Failed to obtain server credentials for kadmin/changepw: %s\n", nt_errstr(nt_status)), &krb_priv_rep); ap_rep.length = 0; if (ret) { goto reply; } talloc_free(tmp_ctx); return ret; } /* We don't strictly need to call this wrapper, and could call * gensec_server_start directly, as we have no need for NTLM * and we have a PAC, but this ensures that the wrapper can be * safely extended for other helpful things in future */ nt_status = samba_server_gensec_start(tmp_ctx, kdc->task->event_ctx, kdc->task->msg_ctx, kdc->task->lp_ctx, server_credentials, "kpasswd", &gensec_security); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(tmp_ctx); return false; } /* The kerberos PRIV packets include these addresses. MIT * clients check that they are present */ #if 0 /* Skip this part for now, it breaks with a NetAPP filer and * in any case where the client address is behind NAT. If * older MIT clients need this, we might have to insert more * complex code */ nt_status = gensec_set_local_address(gensec_security, peer_addr); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(tmp_ctx); return false; } #endif nt_status = gensec_set_local_address(gensec_security, my_addr); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(tmp_ctx); return false; } /* We want the GENSEC wrap calls to generate PRIV tokens */ gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL); nt_status = gensec_start_mech_by_name(gensec_security, "krb5"); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(tmp_ctx); return false; } /* Accept the AP-REQ and generate teh AP-REP we need for the reply */ nt_status = gensec_update(gensec_security, tmp_ctx, ap_req, &ap_rep); if (!NT_STATUS_IS_OK(nt_status) && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, KRB5_KPASSWD_HARDERROR, talloc_asprintf(mem_ctx, "gensec_update failed: %s", nt_errstr(nt_status)), &krb_priv_rep); ap_rep.length = 0; if (ret) { goto reply; } talloc_free(tmp_ctx); return ret; } /* Extract the data from the KRB-PRIV half of the message */ nt_status = gensec_unwrap(gensec_security, tmp_ctx, &krb_priv_req, &kpasswd_req); if (!NT_STATUS_IS_OK(nt_status)) { ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, KRB5_KPASSWD_HARDERROR, talloc_asprintf(mem_ctx, "gensec_unwrap failed: %s", nt_errstr(nt_status)), &krb_priv_rep); ap_rep.length = 0; if (ret) { goto reply; } talloc_free(tmp_ctx); return ret; } /* Figure out something to do with it (probably changing a password...) */ ret = kpasswd_process_request(kdc, tmp_ctx, gensec_security, version, &kpasswd_req, &kpasswd_rep); if (!ret) { /* Argh! */ return false; } /* And wrap up the reply: This ensures that the error message * or success can be verified by the client */ nt_status = gensec_wrap(gensec_security, tmp_ctx, &kpasswd_rep, &krb_priv_rep); if (!NT_STATUS_IS_OK(nt_status)) { ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, KRB5_KPASSWD_HARDERROR, talloc_asprintf(mem_ctx, "gensec_wrap failed: %s", nt_errstr(nt_status)), &krb_priv_rep); ap_rep.length = 0; if (ret) { goto reply; } talloc_free(tmp_ctx); return ret; } reply: *reply = data_blob_talloc(mem_ctx, NULL, krb_priv_rep.length + ap_rep.length + header_len); if (!reply->data) { return false; } RSSVAL(reply->data, 0, reply->length); RSSVAL(reply->data, 2, 1); /* This is a version 1 reply, MS change/set or otherwise */ RSSVAL(reply->data, 4, ap_rep.length); memcpy(reply->data + header_len, ap_rep.data, ap_rep.length); memcpy(reply->data + header_len + ap_rep.length, krb_priv_rep.data, krb_priv_rep.length); talloc_free(tmp_ctx); return ret; }
WERROR dns_verify_tsig(struct dns_server *dns, TALLOC_CTX *mem_ctx, struct dns_request_state *state, struct dns_name_packet *packet, DATA_BLOB *in) { WERROR werror; NTSTATUS status; enum ndr_err_code ndr_err; bool found_tsig = false; uint16_t i, arcount = 0; DATA_BLOB tsig_blob, fake_tsig_blob, sig; uint8_t *buffer = NULL; size_t buffer_len = 0, packet_len = 0; struct dns_server_tkey *tkey = NULL; struct dns_fake_tsig_rec *check_rec = talloc_zero(mem_ctx, struct dns_fake_tsig_rec); /* Find the first TSIG record in the additional records */ for (i=0; i < packet->arcount; i++) { if (packet->additional[i].rr_type == DNS_QTYPE_TSIG) { found_tsig = true; break; } } if (!found_tsig) { return WERR_OK; } /* The TSIG record needs to be the last additional record */ if (found_tsig && i + 1 != packet->arcount) { DEBUG(1, ("TSIG record not the last additional record!\n")); return DNS_ERR(FORMAT_ERROR); } /* We got a TSIG, so we need to sign our reply */ state->sign = true; state->tsig = talloc_zero(state->mem_ctx, struct dns_res_rec); if (state->tsig == NULL) { return WERR_NOT_ENOUGH_MEMORY; } werror = dns_copy_tsig(state->tsig, &packet->additional[i], state->tsig); if (!W_ERROR_IS_OK(werror)) { return werror; } packet->arcount--; tkey = dns_find_tkey(dns->tkeys, state->tsig->name); if (tkey == NULL) { /* * We must save the name for use in the TSIG error * response and have no choice here but to save the * keyname from the TSIG request. */ state->key_name = talloc_strdup(state->mem_ctx, state->tsig->name); if (state->key_name == NULL) { return WERR_NOT_ENOUGH_MEMORY; } state->tsig_error = DNS_RCODE_BADKEY; return DNS_ERR(NOTAUTH); } /* * Remember the keyname that found an existing tkey, used * later to fetch the key with dns_find_tkey() when signing * and adding a TSIG record with MAC. */ state->key_name = talloc_strdup(state->mem_ctx, tkey->name); if (state->key_name == NULL) { return WERR_NOT_ENOUGH_MEMORY; } /* FIXME: check TSIG here */ if (check_rec == NULL) { return WERR_NOT_ENOUGH_MEMORY; } /* first build and verify check packet */ check_rec->name = talloc_strdup(check_rec, tkey->name); if (check_rec->name == NULL) { return WERR_NOT_ENOUGH_MEMORY; } check_rec->rr_class = DNS_QCLASS_ANY; check_rec->ttl = 0; check_rec->algorithm_name = talloc_strdup(check_rec, tkey->algorithm); if (check_rec->algorithm_name == NULL) { return WERR_NOT_ENOUGH_MEMORY; } check_rec->time_prefix = 0; check_rec->time = state->tsig->rdata.tsig_record.time; check_rec->fudge = state->tsig->rdata.tsig_record.fudge; check_rec->error = 0; check_rec->other_size = 0; check_rec->other_data = NULL; ndr_err = ndr_push_struct_blob(&tsig_blob, mem_ctx, state->tsig, (ndr_push_flags_fn_t)ndr_push_dns_res_rec); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { DEBUG(1, ("Failed to push packet: %s!\n", ndr_errstr(ndr_err))); return DNS_ERR(SERVER_FAILURE); } ndr_err = ndr_push_struct_blob(&fake_tsig_blob, mem_ctx, check_rec, (ndr_push_flags_fn_t)ndr_push_dns_fake_tsig_rec); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { DEBUG(1, ("Failed to push packet: %s!\n", ndr_errstr(ndr_err))); return DNS_ERR(SERVER_FAILURE); } /* we need to work some magic here. we need to keep the input packet * exactly like we got it, but we need to cut off the tsig record */ packet_len = in->length - tsig_blob.length; buffer_len = packet_len + fake_tsig_blob.length; buffer = talloc_zero_array(mem_ctx, uint8_t, buffer_len); if (buffer == NULL) { return WERR_NOT_ENOUGH_MEMORY; } memcpy(buffer, in->data, packet_len); memcpy(buffer + packet_len, fake_tsig_blob.data, fake_tsig_blob.length); sig.length = state->tsig->rdata.tsig_record.mac_size; sig.data = talloc_memdup(mem_ctx, state->tsig->rdata.tsig_record.mac, sig.length); if (sig.data == NULL) { return WERR_NOT_ENOUGH_MEMORY; } /* Now we also need to count down the additional record counter */ arcount = RSVAL(buffer, 10); RSSVAL(buffer, 10, arcount-1); status = gensec_check_packet(tkey->gensec, buffer, buffer_len, buffer, buffer_len, &sig); if (NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, status)) { state->tsig_error = DNS_RCODE_BADSIG; return DNS_ERR(NOTAUTH); } if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Verifying tsig failed: %s\n", nt_errstr(status))); return ntstatus_to_werror(status); } state->authenticated = true; return WERR_OK; }