bool decode_pw_buffer(TALLOC_CTX *ctx, uint8 in_buffer[516], char **pp_new_pwrd, uint32 *new_pw_len, int string_flags) { int byte_len=0; *pp_new_pwrd = NULL; *new_pw_len = 0; /* the incoming buffer can be any alignment. */ string_flags |= STR_NOALIGN; /* Warning !!! : This function is called from some rpc call. The password IN the buffer may be a UNICODE string. The password IN new_pwrd is an ASCII string If you reuse that code somewhere else check first. */ /* The length of the new password is in the last 4 bytes of the data buffer. */ byte_len = IVAL(in_buffer, 512); #ifdef DEBUG_PASSWORD dump_data(100, in_buffer, 516); #endif /* Password cannot be longer than the size of the password buffer */ if ( (byte_len < 0) || (byte_len > 512)) { DEBUG(0, ("decode_pw_buffer: incorrect password length (%d).\n", byte_len)); DEBUG(0, ("decode_pw_buffer: check that 'encrypt passwords = yes'\n")); return false; } /* decode into the return buffer. */ *new_pw_len = pull_string_talloc(ctx, NULL, 0, pp_new_pwrd, &in_buffer[512 - byte_len], byte_len, string_flags); if (!*pp_new_pwrd || *new_pw_len == 0) { DEBUG(0, ("decode_pw_buffer: pull_string_talloc failed\n")); return false; } #ifdef DEBUG_PASSWORD DEBUG(100,("decode_pw_buffer: new_pwrd: ")); dump_data(100, (uint8 *)*pp_new_pwrd, *new_pw_len); DEBUG(100,("multibyte len:%d\n", *new_pw_len)); DEBUG(100,("original char len:%d\n", byte_len/2)); #endif return true; }
size_t clistr_pull_talloc(TALLOC_CTX *ctx, const char *base, uint16_t flags2, char **pp_dest, const void *src, int src_len, int flags) { return pull_string_talloc(ctx, base, flags2, pp_dest, src, src_len, flags); }
bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32_t stype, void (*fn)(const char *, uint32_t, const char *, void *), void *state) { char *rparam = NULL; char *rdata = NULL; char *rdata_end = NULL; unsigned int rdrcnt,rprcnt; char *p; char param[1024]; int uLevel = 1; size_t len; uint32_t func = RAP_NetServerEnum2; char *last_entry = NULL; int total_cnt = 0; int return_cnt = 0; int res; errno = 0; /* reset */ /* * This may take more than one transaction, so we should loop until * we no longer get a more data to process or we have all of the * items. */ do { /* send a SMBtrans command with api NetServerEnum */ p = param; SIVAL(p,0,func); /* api number */ p += 2; if (func == RAP_NetServerEnum3) { strlcpy(p,"WrLehDzz", sizeof(param)-PTR_DIFF(p,param)); } else { strlcpy(p,"WrLehDz", sizeof(param)-PTR_DIFF(p,param)); } p = skip_string(param, sizeof(param), p); strlcpy(p,"B16BBDz", sizeof(param)-PTR_DIFF(p,param)); p = skip_string(param, sizeof(param), p); SSVAL(p,0,uLevel); SSVAL(p,2,CLI_BUFFER_SIZE); p += 4; SIVAL(p,0,stype); p += 4; /* If we have more data, tell the server where * to continue from. */ len = push_ascii(p, workgroup, sizeof(param) - PTR_DIFF(p,param) - 1, STR_TERMINATE|STR_UPPER); if (len == 0) { SAFE_FREE(last_entry); return false; } p += len; if (func == RAP_NetServerEnum3) { len = push_ascii(p, last_entry ? last_entry : "", sizeof(param) - PTR_DIFF(p,param) - 1, STR_TERMINATE); if (len == 0) { SAFE_FREE(last_entry); return false; } p += len; } /* Next time through we need to use the continue api */ func = RAP_NetServerEnum3; if (!cli_api(cli, param, PTR_DIFF(p,param), 8, /* params, length, max */ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */ &rparam, &rprcnt, /* return params, return size */ &rdata, &rdrcnt)) { /* return data, return size */ /* break out of the loop on error */ res = -1; break; } rdata_end = rdata + rdrcnt; res = rparam ? SVAL(rparam,0) : -1; if (res == 0 || res == ERRmoredata || (res != -1 && cli_errno(cli) == 0)) { char *sname = NULL; int i, count; int converter=SVAL(rparam,2); /* Get the number of items returned in this buffer */ count = SVAL(rparam, 4); /* The next field contains the number of items left, * including those returned in this buffer. So the * first time through this should contain all of the * entries. */ if (total_cnt == 0) { total_cnt = SVAL(rparam, 6); } /* Keep track of how many we have read */ return_cnt += count; p = rdata; /* The last name in the previous NetServerEnum reply is * sent back to server in the NetServerEnum3 request * (last_entry). The next reply should repeat this entry * as the first element. We have no proof that this is * always true, but from traces that seems to be the * behavior from Window Servers. So first lets do a lot * of checking, just being paranoid. If the string * matches then we already saw this entry so skip it. * * NOTE: sv1_name field must be null terminated and has * a max size of 16 (NetBIOS Name). */ if (last_entry && count && p && (strncmp(last_entry, p, 16) == 0)) { count -= 1; /* Skip this entry */ return_cnt = -1; /* Not part of total, so don't count. */ p = rdata + 26; /* Skip the whole record */ } for (i = 0; i < count; i++, p += 26) { int comment_offset; const char *cmnt; const char *p1; char *s1, *s2; TALLOC_CTX *frame = talloc_stackframe(); uint32_t entry_stype; if (p + 26 > rdata_end) { TALLOC_FREE(frame); break; } sname = p; comment_offset = (IVAL(p,22) & 0xFFFF)-converter; cmnt = comment_offset?(rdata+comment_offset):""; if (comment_offset < 0 || comment_offset >= (int)rdrcnt) { TALLOC_FREE(frame); continue; } /* Work out the comment length. */ for (p1 = cmnt, len = 0; *p1 && p1 < rdata_end; len++) p1++; if (!*p1) { len++; } entry_stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY; pull_string_talloc(frame,rdata,0, &s1,sname,16,STR_ASCII); pull_string_talloc(frame,rdata,0, &s2,cmnt,len,STR_ASCII); if (!s1 || !s2) { TALLOC_FREE(frame); continue; } fn(s1, entry_stype, s2, state); TALLOC_FREE(frame); } /* We are done with the old last entry, so now we can free it */ if (last_entry) { SAFE_FREE(last_entry); /* This will set it to null */ } /* We always make a copy of the last entry if we have one */ if (sname) { last_entry = smb_xstrdup(sname); } /* If we have more data, but no last entry then error out */ if (!last_entry && (res == ERRmoredata)) { errno = EINVAL; res = 0; } } SAFE_FREE(rparam); SAFE_FREE(rdata); } while ((res == ERRmoredata) && (total_cnt > return_cnt)); SAFE_FREE(rparam); SAFE_FREE(rdata); SAFE_FREE(last_entry); if (res == -1) { errno = cli_errno(cli); } else { if (!return_cnt) { /* this is a very special case, when the domain master for the work group isn't part of the work group itself, there is something wild going on */ errno = ENOENT; } } return(return_cnt > 0); }
int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32_t, const char *, void *), void *state) { char *rparam = NULL; char *rdata = NULL; char *p; unsigned int rdrcnt,rprcnt; char param[1024]; int count = -1; /* now send a SMBtrans command with api RNetShareEnum */ p = param; SSVAL(p,0,0); /* api number */ p += 2; strlcpy(p,"WrLeh",sizeof(param)-PTR_DIFF(p,param)); p = skip_string(param,sizeof(param),p); strlcpy(p,"B13BWz",sizeof(param)-PTR_DIFF(p,param)); p = skip_string(param,sizeof(param),p); SSVAL(p,0,1); /* * Win2k needs a *smaller* buffer than 0xFFFF here - * it returns "out of server memory" with 0xFFFF !!! JRA. */ SSVAL(p,2,0xFFE0); p += 4; if (cli_api(cli, param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */ NULL, 0, 0xFFE0, /* data, length, maxlen - Win2k needs a small buffer here too ! */ &rparam, &rprcnt, /* return params, length */ &rdata, &rdrcnt)) /* return data, length */ { int res = rparam? SVAL(rparam,0) : -1; if (res == 0 || res == ERRmoredata) { int converter=SVAL(rparam,2); int i; char *rdata_end = rdata + rdrcnt; count=SVAL(rparam,4); p = rdata; for (i=0;i<count;i++,p+=20) { char *sname; int type; int comment_offset; const char *cmnt; const char *p1; char *s1, *s2; size_t len; TALLOC_CTX *frame = talloc_stackframe(); if (p + 20 > rdata_end) { TALLOC_FREE(frame); break; } sname = p; type = SVAL(p,14); comment_offset = (IVAL(p,16) & 0xFFFF) - converter; if (comment_offset < 0 || comment_offset > (int)rdrcnt) { TALLOC_FREE(frame); break; } cmnt = comment_offset?(rdata+comment_offset):""; /* Work out the comment length. */ for (p1 = cmnt, len = 0; *p1 && p1 < rdata_end; len++) p1++; if (!*p1) { len++; } pull_string_talloc(frame,rdata,0, &s1,sname,14,STR_ASCII); pull_string_talloc(frame,rdata,0, &s2,cmnt,len,STR_ASCII); if (!s1 || !s2) { TALLOC_FREE(frame); continue; } fn(s1, type, s2, state); TALLOC_FREE(frame); } } else { DEBUG(4,("NetShareEnum res=%d\n", res)); } } else { DEBUG(4,("NetShareEnum failed\n")); } SAFE_FREE(rparam); SAFE_FREE(rdata); return count; }
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; } }
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 param_len = 0; 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_t num_referrals; struct client_dfs_referral *referrals = NULL; NTSTATUS status; TALLOC_CTX *frame = talloc_stackframe(); *num_refs = 0; *refs = NULL; 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, smbXcli_conn_use_unicode(cli->conn), 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]; if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { DATA_BLOB in_input_buffer; DATA_BLOB in_output_buffer = data_blob_null; DATA_BLOB out_input_buffer = data_blob_null; DATA_BLOB out_output_buffer = data_blob_null; in_input_buffer.data = param; in_input_buffer.length = param_len; status = smb2cli_ioctl(cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon, UINT64_MAX, /* in_fid_persistent */ UINT64_MAX, /* in_fid_volatile */ FSCTL_DFS_GET_REFERRALS, 0, /* in_max_input_length */ &in_input_buffer, CLI_BUFFER_SIZE, /* in_max_output_length */ &in_output_buffer, SMB2_IOCTL_FLAG_IS_FSCTL, talloc_tos(), &out_input_buffer, &out_output_buffer); if (!NT_STATUS_IS_OK(status)) { goto out; } if (out_output_buffer.length < 4) { status = NT_STATUS_INVALID_NETWORK_RESPONSE; goto out; } recv_flags2 = FLAGS2_UNICODE_STRINGS; rdata = out_output_buffer.data; endp = (char *)rdata + out_output_buffer.length; } else { unsigned int data_len = 0; uint16_t setup[1]; SSVAL(setup, 0, TRANSACT2_GET_DFS_REFERRAL); 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_t ref_version; uint16_t ref_size; int i; uint16_t 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; } }
static NTSTATUS parse_object(TALLOC_CTX *mem_ctx, struct libnet_keytab_context *ctx, struct drsuapi_DsReplicaObjectListItemEx *cur) { NTSTATUS status = NT_STATUS_OK; uchar nt_passwd[16]; DATA_BLOB *blob; int i = 0; struct drsuapi_DsReplicaAttribute *attr; bool got_pwd = false; struct package_PrimaryKerberosCtr3 *pkb3 = NULL; struct package_PrimaryKerberosCtr4 *pkb4 = NULL; char *object_dn = NULL; char *upn = NULL; char **spn = NULL; uint32_t num_spns = 0; char *name = NULL; uint32_t kvno = 0; uint32_t uacc = 0; uint32_t sam_type = 0; uint32_t pwd_history_len = 0; uint8_t *pwd_history = NULL; ZERO_STRUCT(nt_passwd); object_dn = talloc_strdup(mem_ctx, cur->object.identifier->dn); if (!object_dn) { return NT_STATUS_NO_MEMORY; } DEBUG(3, ("parsing object '%s'\n", object_dn)); for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) { attr = &cur->object.attribute_ctr.attributes[i]; if (attr->attid == DRSUAPI_ATTID_servicePrincipalName) { uint32_t count; num_spns = attr->value_ctr.num_values; spn = talloc_array(mem_ctx, char *, num_spns); for (count = 0; count < num_spns; count++) { blob = attr->value_ctr.values[count].blob; pull_string_talloc(spn, NULL, 0, &spn[count], blob->data, blob->length, STR_UNICODE); } } if (attr->value_ctr.num_values != 1) { continue; } if (!attr->value_ctr.values[0].blob) { continue; } blob = attr->value_ctr.values[0].blob; switch (attr->attid) { case DRSUAPI_ATTID_unicodePwd: if (blob->length != 16) { break; } memcpy(&nt_passwd, blob->data, 16); got_pwd = true; /* pick the kvno from the meta_data version, * thanks, metze, for explaining this */ if (!cur->meta_data_ctr) { break; } if (cur->meta_data_ctr->count != cur->object.attribute_ctr.num_attributes) { break; } kvno = cur->meta_data_ctr->meta_data[i].version; break; case DRSUAPI_ATTID_ntPwdHistory: pwd_history_len = blob->length / 16; pwd_history = blob->data; break; case DRSUAPI_ATTID_userPrincipalName: pull_string_talloc(mem_ctx, NULL, 0, &upn, blob->data, blob->length, STR_UNICODE); break; case DRSUAPI_ATTID_sAMAccountName: pull_string_talloc(mem_ctx, NULL, 0, &name, blob->data, blob->length, STR_UNICODE); break; case DRSUAPI_ATTID_sAMAccountType: sam_type = IVAL(blob->data, 0); break; case DRSUAPI_ATTID_userAccountControl: uacc = IVAL(blob->data, 0); break; case DRSUAPI_ATTID_supplementalCredentials: status = parse_supplemental_credentials(mem_ctx, blob, &pkb3, &pkb4); if (!NT_STATUS_IS_OK(status)) { DEBUG(2, ("parsing of supplemental " "credentials failed: %s\n", nt_errstr(status))); } break; default: break; } }