static DATA_BLOB NTLMv2_generate_client_data(TALLOC_CTX *mem_ctx, const DATA_BLOB *names_blob) { uint8_t client_chal[8]; DATA_BLOB response = data_blob(NULL, 0); uint8_t long_date[8]; NTTIME nttime; unix_to_nt_time(&nttime, time(NULL)); generate_random_buffer(client_chal, sizeof(client_chal)); push_nttime(long_date, 0, nttime); /* See http://www.ubiqx.org/cifs/SMB.html#SMB.8.5 */ /* Deliberately ignore return here.. */ (void)msrpc_gen(mem_ctx, &response, "ddbbdb", 0x00000101, /* Header */ 0, /* 'Reserved' */ long_date, 8, /* Timestamp */ client_chal, 8, /* client challenge */ 0, /* Unknown */ names_blob->data, names_blob->length); /* End of name list */ return response; }
/* return filesystem attribute info */ static NTSTATUS svfs_fsattr(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_fsattr *fs) { struct stat st; struct svfs_private *p = ntvfs->private_data; if (fs->generic.level != RAW_FSATTR_GENERIC) { return ntvfs_map_fsattr(ntvfs, req, fs); } if (stat(p->connectpath, &st) == -1) { return map_nt_error_from_unix(errno); } unix_to_nt_time(&fs->generic.out.create_time, st.st_ctime); fs->generic.out.fs_attr = FILE_CASE_PRESERVED_NAMES | FILE_CASE_SENSITIVE_SEARCH | FILE_PERSISTENT_ACLS; fs->generic.out.max_file_component_length = 255; fs->generic.out.serial_number = 1; fs->generic.out.fs_type = talloc_strdup(req, "NTFS"); fs->generic.out.volume_name = talloc_strdup(req, lp_servicename(req->tcon->service)); return NT_STATUS_OK; }
/* construct msDS-User-Account-Control-Computed attr */ static int construct_msds_user_account_control_computed(struct ldb_module *module, struct ldb_message *msg, enum ldb_scope scope, struct ldb_request *parent) { uint32_t userAccountControl; uint32_t msDS_User_Account_Control_Computed = 0; struct ldb_context *ldb = ldb_module_get_ctx(module); NTTIME now; struct ldb_dn *nc_root; int ret; ret = dsdb_find_nc_root(ldb, msg, msg->dn, &nc_root); if (ret != 0) { ldb_asprintf_errstring(ldb, "Failed to find NC root of DN: %s: %s", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb_module_get_ctx(module))); return ret; } if (ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) != 0) { /* Only calculate this on our default NC */ return 0; } /* Test account expire time */ unix_to_nt_time(&now, time(NULL)); userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0); if (!(userAccountControl & _UF_TRUST_ACCOUNTS)) { int64_t lockoutTime = ldb_msg_find_attr_as_int64(msg, "lockoutTime", 0); if (lockoutTime != 0) { int64_t lockoutDuration = samdb_search_int64(ldb, msg, 0, nc_root, "lockoutDuration", NULL); if (lockoutDuration >= 0) { msDS_User_Account_Control_Computed |= UF_LOCKOUT; } else if (lockoutTime - lockoutDuration >= now) { msDS_User_Account_Control_Computed |= UF_LOCKOUT; } } } if (!(userAccountControl & _UF_NO_EXPIRY_ACCOUNTS)) { NTTIME must_change_time = get_msds_user_password_expiry_time_computed(module, msg, nc_root); /* check for expired password */ if (must_change_time < now) { msDS_User_Account_Control_Computed |= UF_PASSWORD_EXPIRED; } } return samdb_msg_add_int64(ldb, msg->elements, msg, "msDS-User-Account-Control-Computed", msDS_User_Account_Control_Computed); }
static PyObject *py_unix2nttime(PyObject *self, PyObject *args) { time_t t; NTTIME nt; if (!PyArg_ParseTuple(args, "I", &t)) return NULL; unix_to_nt_time(&nt, t); return PyInt_FromLong((uint64_t)nt); }
static WERROR dsdb_syntax_NTTIME_ldb_to_drsuapi(struct ldb_context *ldb, const struct dsdb_schema *schema, const struct dsdb_attribute *attr, const struct ldb_message_element *in, TALLOC_CTX *mem_ctx, struct drsuapi_DsReplicaAttribute *out) { uint32_t i; DATA_BLOB *blobs; if (attr->attributeID_id == 0xFFFFFFFF) { return WERR_FOOBAR; } out->attid = attr->attributeID_id; out->value_ctr.num_values = in->num_values; out->value_ctr.values = talloc_array(mem_ctx, struct drsuapi_DsAttributeValue, in->num_values); W_ERROR_HAVE_NO_MEMORY(out->value_ctr.values); blobs = talloc_array(mem_ctx, DATA_BLOB, in->num_values); W_ERROR_HAVE_NO_MEMORY(blobs); for (i=0; i < in->num_values; i++) { NTTIME v; time_t t; out->value_ctr.values[i].blob = &blobs[i]; blobs[i] = data_blob_talloc(blobs, NULL, 8); W_ERROR_HAVE_NO_MEMORY(blobs[i].data); t = ldb_string_to_time((const char *)in->values[i].data); unix_to_nt_time(&v, t); v /= 10000000; SBVAL(blobs[i].data, 0, v); } return WERR_OK; }
/* return filesystem space info */ static NTSTATUS svfs_fsinfo(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_fsinfo *fs) { struct svfs_private *p = ntvfs->private_data; struct stat st; if (fs->generic.level != RAW_QFS_GENERIC) { return ntvfs_map_fsinfo(ntvfs, req, fs); } if (sys_fsusage(p->connectpath, &fs->generic.out.blocks_free, &fs->generic.out.blocks_total) == -1) { return map_nt_error_from_unix(errno); } fs->generic.out.block_size = 512; if (stat(p->connectpath, &st) != 0) { return NT_STATUS_DISK_CORRUPT_ERROR; } fs->generic.out.fs_id = st.st_ino; unix_to_nt_time(&fs->generic.out.create_time, st.st_ctime); fs->generic.out.serial_number = st.st_ino; fs->generic.out.fs_attr = 0; fs->generic.out.max_file_component_length = 255; fs->generic.out.device_type = 0; fs->generic.out.device_characteristics = 0; fs->generic.out.quota_soft = 0; fs->generic.out.quota_hard = 0; fs->generic.out.quota_flags = 0; fs->generic.out.volume_name = talloc_strdup(req, ntvfs->ctx->config->name); fs->generic.out.fs_type = ntvfs->ctx->fs_type; return NT_STATUS_OK; }
uint32_t _fss_GetShareMapping(struct pipes_struct *p, struct fss_GetShareMapping *r) { NTSTATUS status; struct fss_sc_set *sc_set; struct fss_sc *sc; struct fss_sc_smap *sc_smap; char *share; struct fssagent_share_mapping_1 *sm_out; TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx); if (tmp_ctx == NULL) { return HRES_ERROR_V(HRES_E_OUTOFMEMORY); } if (!fss_permitted(p)) { talloc_free(tmp_ctx); return HRES_ERROR_V(HRES_E_ACCESSDENIED); } sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId); if (sc_set == NULL) { talloc_free(tmp_ctx); return HRES_ERROR_V(HRES_E_INVALIDARG); } /* * If ShadowCopySet.Status is not "Exposed", the server SHOULD<9> fail * the call with FSRVP_E_BAD_STATE. * <9> If ShadowCopySet.Status is "Started", "Added", * "CreationInProgress", or "Committed", Windows Server 2012 FSRVP * servers return an error value of 0x80042311. */ if ((sc_set->state == FSS_SC_STARTED) || (sc_set->state == FSS_SC_ADDED) || (sc_set->state == FSS_SC_CREATING) || (sc_set->state == FSS_SC_COMMITED)) { talloc_free(tmp_ctx); return 0x80042311; /* documented magic value */ } sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId); if (sc == NULL) { talloc_free(tmp_ctx); return HRES_ERROR_V(HRES_E_INVALIDARG); } status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share); if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return fss_ntstatus_map(status); } sc_smap = sc_smap_lookup(sc->smaps, share); if (sc_smap == NULL) { talloc_free(tmp_ctx); return HRES_ERROR_V(HRES_E_INVALIDARG); } if (r->in.Level != 1) { talloc_free(tmp_ctx); return HRES_ERROR_V(HRES_E_INVALIDARG); } sm_out = talloc_zero(p->mem_ctx, struct fssagent_share_mapping_1); if (sm_out == NULL) { talloc_free(tmp_ctx); return HRES_ERROR_V(HRES_E_OUTOFMEMORY); } sm_out->ShadowCopySetId = sc_set->id; sm_out->ShadowCopyId = sc->id; sm_out->ShareNameUNC = talloc_asprintf(sm_out, "\\\\%s\\%s", lp_netbios_name(), sc_smap->share_name); if (sm_out->ShareNameUNC == NULL) { talloc_free(sm_out); talloc_free(tmp_ctx); return HRES_ERROR_V(HRES_E_OUTOFMEMORY); } sm_out->ShadowCopyShareName = sc_smap->sc_share_name; unix_to_nt_time(&sm_out->tstamp, sc->create_ts); r->out.ShareMapping->ShareMapping1 = sm_out; talloc_free(tmp_ctx); /* reset msg sequence timer */ TALLOC_FREE(fss_global.seq_tmr); fss_seq_tout_set(fss_global.mem_ctx, 1800, sc_set, &fss_global.seq_tmr); return 0; }
NTSTATUS samu_to_SamInfo3(TALLOC_CTX *mem_ctx, struct samu *samu, const char *login_server, struct netr_SamInfo3 **_info3, struct extra_auth_info *extra) { struct netr_SamInfo3 *info3; const struct dom_sid *user_sid; const struct dom_sid *group_sid; struct dom_sid domain_sid; struct dom_sid *group_sids; uint32_t num_group_sids = 0; const char *tmp; gid_t *gids; NTSTATUS status; bool ok; user_sid = pdb_get_user_sid(samu); group_sid = pdb_get_group_sid(samu); if (!user_sid || !group_sid) { DEBUG(1, ("Sam account is missing sids!\n")); return NT_STATUS_UNSUCCESSFUL; } info3 = talloc_zero(mem_ctx, struct netr_SamInfo3); if (!info3) { return NT_STATUS_NO_MEMORY; } ZERO_STRUCT(domain_sid); /* check if this is a "Unix Users" domain user, * we need to handle it in a special way if that's the case */ if (sid_check_is_in_unix_users(user_sid)) { /* in info3 you can only set rids for the user and the * primary group, and the domain sid must be that of * the sam domain. * * Store a completely bogus value here. * The real SID is stored in the extra sids. * Other code will know to look there if (-1) is found */ info3->base.rid = (uint32_t)(-1); sid_copy(&extra->user_sid, user_sid); DEBUG(10, ("Unix User found in struct samu. Rid marked as " "special and sid (%s) saved as extra sid\n", sid_string_dbg(user_sid))); } else { sid_copy(&domain_sid, user_sid); sid_split_rid(&domain_sid, &info3->base.rid); } if (is_null_sid(&domain_sid)) { sid_copy(&domain_sid, get_global_sam_sid()); } /* check if this is a "Unix Groups" domain group, * if so we need special handling */ if (sid_check_is_in_unix_groups(group_sid)) { /* in info3 you can only set rids for the user and the * primary group, and the domain sid must be that of * the sam domain. * * Store a completely bogus value here. * The real SID is stored in the extra sids. * Other code will know to look there if (-1) is found */ info3->base.primary_gid = (uint32_t)(-1); sid_copy(&extra->pgid_sid, group_sid); DEBUG(10, ("Unix Group found in struct samu. Rid marked as " "special and sid (%s) saved as extra sid\n", sid_string_dbg(group_sid))); } else { ok = sid_peek_check_rid(&domain_sid, group_sid, &info3->base.primary_gid); if (!ok) { DEBUG(1, ("The primary group domain sid(%s) does not " "match the domain sid(%s) for %s(%s)\n", sid_string_dbg(group_sid), sid_string_dbg(&domain_sid), pdb_get_username(samu), sid_string_dbg(user_sid))); TALLOC_FREE(info3); return NT_STATUS_UNSUCCESSFUL; } } unix_to_nt_time(&info3->base.last_logon, pdb_get_logon_time(samu)); unix_to_nt_time(&info3->base.last_logoff, get_time_t_max()); unix_to_nt_time(&info3->base.acct_expiry, get_time_t_max()); unix_to_nt_time(&info3->base.last_password_change, pdb_get_pass_last_set_time(samu)); unix_to_nt_time(&info3->base.allow_password_change, pdb_get_pass_can_change_time(samu)); unix_to_nt_time(&info3->base.force_password_change, pdb_get_pass_must_change_time(samu)); tmp = pdb_get_username(samu); if (tmp) { info3->base.account_name.string = talloc_strdup(info3, tmp); RET_NOMEM(info3->base.account_name.string); } tmp = pdb_get_fullname(samu); if (tmp) { info3->base.full_name.string = talloc_strdup(info3, tmp); RET_NOMEM(info3->base.full_name.string); } tmp = pdb_get_logon_script(samu); if (tmp) { info3->base.logon_script.string = talloc_strdup(info3, tmp); RET_NOMEM(info3->base.logon_script.string); } tmp = pdb_get_profile_path(samu); if (tmp) { info3->base.profile_path.string = talloc_strdup(info3, tmp); RET_NOMEM(info3->base.profile_path.string); } tmp = pdb_get_homedir(samu); if (tmp) { info3->base.home_directory.string = talloc_strdup(info3, tmp); RET_NOMEM(info3->base.home_directory.string); } tmp = pdb_get_dir_drive(samu); if (tmp) { info3->base.home_drive.string = talloc_strdup(info3, tmp); RET_NOMEM(info3->base.home_drive.string); } info3->base.logon_count = pdb_get_logon_count(samu); info3->base.bad_password_count = pdb_get_bad_password_count(samu); info3->base.domain.string = talloc_strdup(info3, pdb_get_domain(samu)); RET_NOMEM(info3->base.domain.string); info3->base.domain_sid = dom_sid_dup(info3, &domain_sid); RET_NOMEM(info3->base.domain_sid); status = pdb_enum_group_memberships(mem_ctx, samu, &group_sids, &gids, &num_group_sids); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to get groups from sam account.\n")); TALLOC_FREE(info3); return status; } if (num_group_sids) { status = group_sids_to_info3(info3, group_sids, num_group_sids); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(info3); return status; } } /* We don't need sids and gids after the conversion */ TALLOC_FREE(group_sids); TALLOC_FREE(gids); num_group_sids = 0; /* FIXME: should we add other flags ? */ info3->base.user_flags = NETLOGON_EXTRA_SIDS; if (login_server) { info3->base.logon_server.string = talloc_strdup(info3, login_server); RET_NOMEM(info3->base.logon_server.string); } info3->base.acct_flags = pdb_get_acct_ctrl(samu); *_info3 = info3; return NT_STATUS_OK; }
/* add or modify a rdataset */ _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, void *dbdata, void *version) { struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data); struct dnsp_DnssrvRpcRecord *rec; struct ldb_dn *dn; isc_result_t result; struct ldb_result *res; const char *attrs[] = { "dnsRecord", NULL }; int ret, i; struct ldb_message_element *el; enum ndr_err_code ndr_err; NTTIME t; if (state->transaction_token != (void*)version) { state->log(ISC_LOG_INFO, "samba_dlz: bad transaction version"); return ISC_R_FAILURE; } rec = talloc_zero(state, struct dnsp_DnssrvRpcRecord); if (rec == NULL) { return ISC_R_NOMEMORY; } unix_to_nt_time(&t, time(NULL)); t /= 10*1000*1000; /* convert to seconds (NT time is in 100ns units) */ t /= 3600; /* convert to hours */ rec->rank = DNS_RANK_ZONE; rec->dwSerial = state->soa_serial; rec->dwTimeStamp = (uint32_t)t; if (!b9_parse(state, rdatastr, rec)) { state->log(ISC_LOG_INFO, "samba_dlz: failed to parse rdataset '%s'", rdatastr); talloc_free(rec); return ISC_R_FAILURE; } /* find the DN of the record */ result = b9_find_name_dn(state, name, rec, &dn); if (result != ISC_R_SUCCESS) { talloc_free(rec); return result; } /* get any existing records */ ret = ldb_search(state->samdb, rec, &res, dn, LDB_SCOPE_BASE, attrs, "objectClass=dnsNode"); if (ret == LDB_ERR_NO_SUCH_OBJECT) { result = b9_add_record(state, name, dn, rec); talloc_free(rec); if (result == ISC_R_SUCCESS) { state->log(ISC_LOG_ERROR, "samba_dlz: added %s %s", name, rdatastr); } return result; } /* there are existing records. We need to see if this will * replace a record or add to it */ el = ldb_msg_find_element(res->msgs[0], "dnsRecord"); if (el == NULL) { state->log(ISC_LOG_ERROR, "samba_dlz: no dnsRecord attribute for %s", ldb_dn_get_linearized(dn)); talloc_free(rec); return ISC_R_FAILURE; } for (i=0; i<el->num_values; i++) { struct dnsp_DnssrvRpcRecord rec2; ndr_err = ndr_pull_struct_blob(&el->values[i], rec, &rec2, (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s", ldb_dn_get_linearized(dn)); talloc_free(rec); return ISC_R_FAILURE; } if (b9_record_match(state, rec, &rec2)) { break; } } if (i == el->num_values) { /* adding a new value */ el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values+1); if (el->values == NULL) { talloc_free(rec); return ISC_R_NOMEMORY; } el->num_values++; }
/* fill in the dos file attributes for a file */ NTSTATUS pvfs_fill_dos_info(struct pvfs_state *pvfs, struct pvfs_filename *name, unsigned int flags, int fd) { NTSTATUS status; DATA_BLOB lkey; NTTIME write_time; /* make directories appear as size 0 with 1 link */ if (S_ISDIR(name->st.st_mode)) { name->st.st_size = 0; name->st.st_nlink = 1; } else if (name->stream_id == 0) { name->stream_name = NULL; } /* for now just use the simple samba mapping */ unix_to_nt_time(&name->dos.create_time, name->st.st_ctime); unix_to_nt_time(&name->dos.access_time, name->st.st_atime); unix_to_nt_time(&name->dos.write_time, name->st.st_mtime); unix_to_nt_time(&name->dos.change_time, name->st.st_ctime); #ifdef HAVE_STAT_TV_NSEC name->dos.create_time += name->st.st_ctim.tv_nsec / 100; name->dos.access_time += name->st.st_atim.tv_nsec / 100; name->dos.write_time += name->st.st_mtim.tv_nsec / 100; name->dos.change_time += name->st.st_ctim.tv_nsec / 100; #endif name->dos.attrib = dos_mode_from_stat(pvfs, &name->st); name->dos.alloc_size = pvfs_round_alloc_size(pvfs, name->st.st_size); name->dos.nlink = name->st.st_nlink; name->dos.ea_size = 4; /* TODO: Fill this in without hitting the stream bad in pvfs_doseas_load() */ if (pvfs->ntvfs->ctx->protocol >= PROTOCOL_SMB2_02) { /* SMB2 represents a null EA with zero bytes */ name->dos.ea_size = 0; } name->dos.file_id = (((uint64_t)name->st.st_dev)<<32) | name->st.st_ino; name->dos.flags = 0; status = pvfs_dosattrib_load(pvfs, name, fd); NT_STATUS_NOT_OK_RETURN(status); if (flags & PVFS_RESOLVE_NO_OPENDB) { return NT_STATUS_OK; } status = pvfs_locking_key(name, name, &lkey); NT_STATUS_NOT_OK_RETURN(status); status = odb_get_file_infos(pvfs->odb_context, &lkey, NULL, &write_time); data_blob_free(&lkey); if (!NT_STATUS_IS_OK(status)) { DEBUG(1,("WARNING: odb_get_file_infos: %s\n", nt_errstr(status))); return status; } if (!null_time(write_time)) { name->dos.write_time = write_time; } return NT_STATUS_OK; }
/* basic testing of all RAW_SFILEINFO_* calls for each call we test that it succeeds, and where possible test for consistency between the calls. */ static bool torture_raw_sfileinfo_base(struct torture_context *torture, struct smbcli_state *cli) { bool ret = true; int fnum = -1; char *fnum_fname; char *fnum_fname_new; char *path_fname; char *path_fname_new; union smb_fileinfo finfo1, finfo2; union smb_setfileinfo sfinfo; NTSTATUS status, status2; const char *call_name; time_t basetime = (time(NULL) - 86400) & ~1; bool check_fnum; int n = time(NULL) % 100; asprintf(&path_fname, BASEDIR "\\fname_test_%d.txt", n); asprintf(&path_fname_new, BASEDIR "\\fname_test_new_%d.txt", n); asprintf(&fnum_fname, BASEDIR "\\fnum_test_%d.txt", n); asprintf(&fnum_fname_new, BASEDIR "\\fnum_test_new_%d.txt", n); if (!torture_setup_dir(cli, BASEDIR)) { return false; } #define RECREATE_FILE(fname) do { \ if (fnum != -1) smbcli_close(cli->tree, fnum); \ fnum = create_complex_file(cli, torture, fname); \ if (fnum == -1) { \ printf("(%s) ERROR: open of %s failed (%s)\n", \ __location__, fname, smbcli_errstr(cli->tree)); \ ret = false; \ goto done; \ }} while (0) #define RECREATE_BOTH do { \ RECREATE_FILE(path_fname); \ smbcli_close(cli->tree, fnum); \ RECREATE_FILE(fnum_fname); \ } while (0) RECREATE_BOTH; #define CHECK_CALL_FNUM(call, rightstatus) do { \ check_fnum = true; \ call_name = #call; \ sfinfo.generic.level = RAW_SFILEINFO_ ## call; \ sfinfo.generic.in.file.fnum = fnum; \ status = smb_raw_setfileinfo(cli->tree, &sfinfo); \ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) { \ torture_warning(torture, \ "(%s) %s - %s", __location__, #call, \ nt_errstr(status)); \ } else if (!NT_STATUS_EQUAL(status, rightstatus)) { \ printf("(%s) %s - %s (should be %s)\n", __location__, #call, \ nt_errstr(status), nt_errstr(rightstatus)); \ ret = false; \ } \ finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \ finfo1.generic.in.file.fnum = fnum; \ status2 = smb_raw_fileinfo(cli->tree, torture, &finfo1); \ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) { \ torture_warning(torture, \ "(%s) %s - %s", __location__, #call, \ nt_errstr(status)); \ } else if (!NT_STATUS_IS_OK(status2)) { \ printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status)); \ ret = false; \ }} while (0) #define CHECK_CALL_PATH(call, rightstatus) do { \ check_fnum = false; \ call_name = #call; \ sfinfo.generic.level = RAW_SFILEINFO_ ## call; \ sfinfo.generic.in.file.path = path_fname; \ status = smb_raw_setpathinfo(cli->tree, &sfinfo); \ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { \ sfinfo.generic.in.file.path = path_fname_new; \ status = smb_raw_setpathinfo(cli->tree, &sfinfo); \ } \ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) { \ torture_warning(torture, \ "(%s) %s - %s", __location__, #call, \ nt_errstr(status)); \ } else if (!NT_STATUS_EQUAL(status, rightstatus)) { \ printf("(%s) %s - %s (should be %s)\n", __location__, #call, \ nt_errstr(status), nt_errstr(rightstatus)); \ ret = false; \ } \ finfo1.generic.level = RAW_FILEINFO_ALL_INFO; \ finfo1.generic.in.file.path = path_fname; \ status2 = smb_raw_pathinfo(cli->tree, torture, &finfo1); \ if (NT_STATUS_EQUAL(status2, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { \ finfo1.generic.in.file.path = path_fname_new; \ status2 = smb_raw_pathinfo(cli->tree, torture, &finfo1); \ } \ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) { \ torture_warning(torture, \ "(%s) %s - %s", __location__, #call, \ nt_errstr(status)); \ } else if (!NT_STATUS_IS_OK(status2)) { \ printf("(%s) %s pathinfo - %s\n", __location__, #call, nt_errstr(status2)); \ ret = false; \ }} while (0) #define CHECK1(call) \ do { if (NT_STATUS_IS_OK(status)) { \ finfo2.generic.level = RAW_FILEINFO_ ## call; \ if (check_fnum) { \ finfo2.generic.in.file.fnum = fnum; \ status2 = smb_raw_fileinfo(cli->tree, torture, &finfo2); \ } else { \ finfo2.generic.in.file.path = path_fname; \ status2 = smb_raw_pathinfo(cli->tree, torture, &finfo2); \ if (NT_STATUS_EQUAL(status2, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { \ finfo2.generic.in.file.path = path_fname_new; \ status2 = smb_raw_pathinfo(cli->tree, torture, &finfo2); \ } \ } \ if (!NT_STATUS_IS_OK(status2)) { \ printf("%s - %s\n", #call, nt_errstr(status2)); \ ret = false; \ } \ }} while (0) #define CHECK_VALUE(call, stype, field, value) do { \ CHECK1(call); \ if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && finfo2.stype.out.field != value) { \ printf("(%s) %s - %s/%s should be 0x%x - 0x%x\n", __location__, \ call_name, #stype, #field, \ (unsigned int)value, (unsigned int)finfo2.stype.out.field); \ dump_all_info(torture, &finfo1); \ ret = false; \ }} while (0) #define CHECK_TIME(call, stype, field, value) do { \ CHECK1(call); \ if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && nt_time_to_unix(finfo2.stype.out.field) != value) { \ printf("(%s) %s - %s/%s should be 0x%x - 0x%x\n", __location__, \ call_name, #stype, #field, \ (unsigned int)value, \ (unsigned int)nt_time_to_unix(finfo2.stype.out.field)); \ printf("\t%s", timestring(torture, value)); \ printf("\t%s\n", nt_time_string(torture, finfo2.stype.out.field)); \ dump_all_info(torture, &finfo1); \ ret = false; \ }} while (0) #define CHECK_STR(call, stype, field, value) do { \ CHECK1(call); \ if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && strcmp(finfo2.stype.out.field, value) != 0) { \ printf("(%s) %s - %s/%s should be '%s' - '%s'\n", __location__, \ call_name, #stype, #field, \ value, \ finfo2.stype.out.field); \ dump_all_info(torture, &finfo1); \ ret = false; \ }} while (0) #define CHECK_STATUS(status, correct) do { \ if (!NT_STATUS_EQUAL(status, correct)) { \ printf("(%s) Incorrect status %s - should be %s\n", \ __location__, nt_errstr(status), nt_errstr(correct)); \ ret = false; \ goto done; \ }} while (0) printf("Test setattr\n"); sfinfo.setattr.in.attrib = FILE_ATTRIBUTE_READONLY; sfinfo.setattr.in.write_time = basetime; CHECK_CALL_PATH(SETATTR, NT_STATUS_OK); CHECK_VALUE (ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_READONLY); CHECK_TIME (ALL_INFO, all_info, write_time, basetime); printf("setting to NORMAL doesn't do anything\n"); sfinfo.setattr.in.attrib = FILE_ATTRIBUTE_NORMAL; sfinfo.setattr.in.write_time = 0; CHECK_CALL_PATH(SETATTR, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_READONLY); CHECK_TIME (ALL_INFO, all_info, write_time, basetime); printf("a zero write_time means don't change\n"); sfinfo.setattr.in.attrib = 0; sfinfo.setattr.in.write_time = 0; CHECK_CALL_PATH(SETATTR, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL); CHECK_TIME (ALL_INFO, all_info, write_time, basetime); printf("Test setattre\n"); sfinfo.setattre.in.create_time = basetime + 20; sfinfo.setattre.in.access_time = basetime + 30; sfinfo.setattre.in.write_time = basetime + 40; CHECK_CALL_FNUM(SETATTRE, NT_STATUS_OK); CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 20); CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 30); CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 40); sfinfo.setattre.in.create_time = 0; sfinfo.setattre.in.access_time = 0; sfinfo.setattre.in.write_time = 0; CHECK_CALL_FNUM(SETATTRE, NT_STATUS_OK); CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 20); CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 30); CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 40); printf("Test standard level\n"); sfinfo.standard.in.create_time = basetime + 100; sfinfo.standard.in.access_time = basetime + 200; sfinfo.standard.in.write_time = basetime + 300; CHECK_CALL_FNUM(STANDARD, NT_STATUS_OK); CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100); CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200); CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300); printf("Test basic_info level\n"); basetime += 86400; unix_to_nt_time(&sfinfo.basic_info.in.create_time, basetime + 100); unix_to_nt_time(&sfinfo.basic_info.in.access_time, basetime + 200); unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime + 300); unix_to_nt_time(&sfinfo.basic_info.in.change_time, basetime + 400); sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY; CHECK_CALL_FNUM(BASIC_INFO, NT_STATUS_OK); CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100); CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200); CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300); CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400); CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_READONLY); printf("a zero time means don't change\n"); unix_to_nt_time(&sfinfo.basic_info.in.create_time, 0); unix_to_nt_time(&sfinfo.basic_info.in.access_time, 0); unix_to_nt_time(&sfinfo.basic_info.in.write_time, 0); unix_to_nt_time(&sfinfo.basic_info.in.change_time, 0); sfinfo.basic_info.in.attrib = 0; CHECK_CALL_FNUM(BASIC_INFO, NT_STATUS_OK); CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100); CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200); CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300); CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400); CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_READONLY); printf("Test basic_information level\n"); basetime += 86400; unix_to_nt_time(&sfinfo.basic_info.in.create_time, basetime + 100); unix_to_nt_time(&sfinfo.basic_info.in.access_time, basetime + 200); unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime + 300); unix_to_nt_time(&sfinfo.basic_info.in.change_time, basetime + 400); sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL; CHECK_CALL_FNUM(BASIC_INFORMATION, NT_STATUS_OK); CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100); CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200); CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300); CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400); CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL); CHECK_CALL_PATH(BASIC_INFORMATION, NT_STATUS_OK); CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100); CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200); CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300); CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400); CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL); torture_comment(torture, "try to change a file to a directory\n"); sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_DIRECTORY; CHECK_CALL_FNUM(BASIC_INFO, NT_STATUS_INVALID_PARAMETER); printf("a zero time means don't change\n"); unix_to_nt_time(&sfinfo.basic_info.in.create_time, 0); unix_to_nt_time(&sfinfo.basic_info.in.access_time, 0); unix_to_nt_time(&sfinfo.basic_info.in.write_time, 0); unix_to_nt_time(&sfinfo.basic_info.in.change_time, 0); sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL; CHECK_CALL_FNUM(BASIC_INFORMATION, NT_STATUS_OK); CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100); CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200); CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300); CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400); CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL); CHECK_CALL_PATH(BASIC_INFORMATION, NT_STATUS_OK); CHECK_TIME(ALL_INFO, all_info, create_time, basetime + 100); CHECK_TIME(ALL_INFO, all_info, access_time, basetime + 200); CHECK_TIME(ALL_INFO, all_info, write_time, basetime + 300); /* interesting - w2k3 leaves change_time as current time for 0 change time in setpathinfo CHECK_TIME(ALL_INFO, all_info, change_time, basetime + 400); */ CHECK_VALUE(ALL_INFO, all_info, attrib, FILE_ATTRIBUTE_NORMAL); printf("Test disposition_info level\n"); sfinfo.disposition_info.in.delete_on_close = 1; CHECK_CALL_FNUM(DISPOSITION_INFO, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, delete_pending, 1); CHECK_VALUE(ALL_INFO, all_info, nlink, 0); sfinfo.disposition_info.in.delete_on_close = 0; CHECK_CALL_FNUM(DISPOSITION_INFO, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, delete_pending, 0); CHECK_VALUE(ALL_INFO, all_info, nlink, 1); printf("Test disposition_information level\n"); sfinfo.disposition_info.in.delete_on_close = 1; CHECK_CALL_FNUM(DISPOSITION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, delete_pending, 1); CHECK_VALUE(ALL_INFO, all_info, nlink, 0); /* this would delete the file! */ /* CHECK_CALL_PATH(DISPOSITION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, delete_pending, 1); CHECK_VALUE(ALL_INFO, all_info, nlink, 0); */ sfinfo.disposition_info.in.delete_on_close = 0; CHECK_CALL_FNUM(DISPOSITION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, delete_pending, 0); CHECK_VALUE(ALL_INFO, all_info, nlink, 1); CHECK_CALL_PATH(DISPOSITION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, delete_pending, 0); CHECK_VALUE(ALL_INFO, all_info, nlink, 1); printf("Test allocation_info level\n"); sfinfo.allocation_info.in.alloc_size = 0; CHECK_CALL_FNUM(ALLOCATION_INFO, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, size, 0); CHECK_VALUE(ALL_INFO, all_info, alloc_size, 0); sfinfo.allocation_info.in.alloc_size = 4096; CHECK_CALL_FNUM(ALLOCATION_INFO, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, alloc_size, 4096); CHECK_VALUE(ALL_INFO, all_info, size, 0); RECREATE_BOTH; sfinfo.allocation_info.in.alloc_size = 0; CHECK_CALL_FNUM(ALLOCATION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, size, 0); CHECK_VALUE(ALL_INFO, all_info, alloc_size, 0); CHECK_CALL_PATH(ALLOCATION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, size, 0); CHECK_VALUE(ALL_INFO, all_info, alloc_size, 0); sfinfo.allocation_info.in.alloc_size = 4096; CHECK_CALL_FNUM(ALLOCATION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, alloc_size, 4096); CHECK_VALUE(ALL_INFO, all_info, size, 0); /* setting the allocation size up via setpathinfo seems to be broken in w2k3 */ CHECK_CALL_PATH(ALLOCATION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, alloc_size, 0); CHECK_VALUE(ALL_INFO, all_info, size, 0); printf("Test end_of_file_info level\n"); sfinfo.end_of_file_info.in.size = 37; CHECK_CALL_FNUM(END_OF_FILE_INFO, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, size, 37); sfinfo.end_of_file_info.in.size = 7; CHECK_CALL_FNUM(END_OF_FILE_INFO, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, size, 7); sfinfo.end_of_file_info.in.size = 37; CHECK_CALL_FNUM(END_OF_FILE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, size, 37); CHECK_CALL_PATH(END_OF_FILE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, size, 37); sfinfo.end_of_file_info.in.size = 7; CHECK_CALL_FNUM(END_OF_FILE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, size, 7); CHECK_CALL_PATH(END_OF_FILE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(ALL_INFO, all_info, size, 7); printf("Test position_information level\n"); sfinfo.position_information.in.position = 123456; CHECK_CALL_FNUM(POSITION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(POSITION_INFORMATION, position_information, position, 123456); CHECK_CALL_PATH(POSITION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(POSITION_INFORMATION, position_information, position, 0); printf("Test mode_information level\n"); sfinfo.mode_information.in.mode = 2; CHECK_CALL_FNUM(MODE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 2); CHECK_CALL_PATH(MODE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 0); sfinfo.mode_information.in.mode = 1; CHECK_CALL_FNUM(MODE_INFORMATION, NT_STATUS_INVALID_PARAMETER); CHECK_CALL_PATH(MODE_INFORMATION, NT_STATUS_INVALID_PARAMETER); sfinfo.mode_information.in.mode = 0; CHECK_CALL_FNUM(MODE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 0); CHECK_CALL_PATH(MODE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 0); #if 0 printf("Test unix_basic level\n"); CHECK_CALL_FNUM(UNIX_BASIC, NT_STATUS_OK); CHECK_CALL_PATH(UNIX_BASIC, NT_STATUS_OK); printf("Test unix_link level\n"); CHECK_CALL_FNUM(UNIX_LINK, NT_STATUS_OK); CHECK_CALL_PATH(UNIX_LINK, NT_STATUS_OK); #endif done: smb_raw_exit(cli->session); smbcli_close(cli->tree, fnum); if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fnum_fname))) { printf("Failed to delete %s - %s\n", fnum_fname, smbcli_errstr(cli->tree)); } if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, path_fname))) { printf("Failed to delete %s - %s\n", path_fname, smbcli_errstr(cli->tree)); } return ret; }
/* list files in a directory matching a wildcard pattern */ static NTSTATUS svfs_search_first(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_search_first *io, void *search_private, bool (*callback)(void *, const union smb_search_data *)) { struct svfs_dir *dir; int i; struct svfs_private *p = ntvfs->private_data; struct search_state *search; union smb_search_data file; unsigned int max_count; if (io->generic.level != RAW_SEARCH_TRANS2) { return NT_STATUS_NOT_SUPPORTED; } if (io->generic.data_level != RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO) { return NT_STATUS_NOT_SUPPORTED; } search = talloc_zero(p, struct search_state); if (!search) { return NT_STATUS_NO_MEMORY; } max_count = io->t2ffirst.in.max_count; dir = svfs_list(ntvfs, req, io->t2ffirst.in.pattern); if (!dir) { return NT_STATUS_FOOBAR; } search->handle = p->next_search_handle; search->dir = dir; if (dir->count < max_count) { max_count = dir->count; } for (i=0; i < max_count;i++) { ZERO_STRUCT(file); unix_to_nt_time(&file.both_directory_info.create_time, dir->files[i].st.st_ctime); unix_to_nt_time(&file.both_directory_info.access_time, dir->files[i].st.st_atime); unix_to_nt_time(&file.both_directory_info.write_time, dir->files[i].st.st_mtime); unix_to_nt_time(&file.both_directory_info.change_time, dir->files[i].st.st_mtime); file.both_directory_info.name.s = dir->files[i].name; file.both_directory_info.short_name.s = dir->files[i].name; file.both_directory_info.size = dir->files[i].st.st_size; file.both_directory_info.attrib = svfs_unix_to_dos_attrib(dir->files[i].st.st_mode); if (!callback(search_private, &file)) { break; } } search->current_index = i; io->t2ffirst.out.count = i; io->t2ffirst.out.handle = search->handle; io->t2ffirst.out.end_of_search = (i == dir->count) ? 1 : 0; /* work out if we are going to keep the search state */ if ((io->t2ffirst.in.flags & FLAG_TRANS2_FIND_CLOSE) || ((io->t2ffirst.in.flags & FLAG_TRANS2_FIND_CLOSE_IF_END) && (i == dir->count))) { talloc_free(search); } else { p->next_search_handle++; DLIST_ADD(p->search, search); } return NT_STATUS_OK; }
/* approximately map a struct stat to a generic fileinfo struct */ static NTSTATUS svfs_map_fileinfo(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_fileinfo *info, struct stat *st, const char *unix_path) { struct svfs_dir *dir = NULL; char *pattern = NULL; int i; const char *s, *short_name; s = strrchr(unix_path, '/'); if (s) { short_name = s+1; } else { short_name = ""; } asprintf(&pattern, "%s:*", unix_path); if (pattern) { dir = svfs_list_unix(req, req, pattern); } unix_to_nt_time(&info->generic.out.create_time, st->st_ctime); unix_to_nt_time(&info->generic.out.access_time, st->st_atime); unix_to_nt_time(&info->generic.out.write_time, st->st_mtime); unix_to_nt_time(&info->generic.out.change_time, st->st_mtime); info->generic.out.alloc_size = st->st_size; info->generic.out.size = st->st_size; info->generic.out.attrib = svfs_unix_to_dos_attrib(st->st_mode); info->generic.out.alloc_size = st->st_blksize * st->st_blocks; info->generic.out.nlink = st->st_nlink; info->generic.out.directory = S_ISDIR(st->st_mode) ? 1 : 0; info->generic.out.file_id = svfs_file_id(st); /* REWRITE: TODO stuff in here */ info->generic.out.delete_pending = 0; info->generic.out.ea_size = 0; info->generic.out.num_eas = 0; info->generic.out.fname.s = talloc_strdup(req, short_name); info->generic.out.alt_fname.s = talloc_strdup(req, short_name); info->generic.out.compressed_size = 0; info->generic.out.format = 0; info->generic.out.unit_shift = 0; info->generic.out.chunk_shift = 0; info->generic.out.cluster_shift = 0; info->generic.out.access_flags = 0; info->generic.out.position = 0; info->generic.out.mode = 0; info->generic.out.alignment_requirement = 0; info->generic.out.reparse_tag = 0; info->generic.out.num_streams = 0; /* setup a single data stream */ info->generic.out.num_streams = 1 + (dir?dir->count:0); info->generic.out.streams = talloc_array(req, struct stream_struct, info->generic.out.num_streams); if (!info->generic.out.streams) { return NT_STATUS_NO_MEMORY; } info->generic.out.streams[0].size = st->st_size; info->generic.out.streams[0].alloc_size = st->st_size; info->generic.out.streams[0].stream_name.s = talloc_strdup(req,"::$DATA"); for (i=0;dir && i<dir->count;i++) { s = strchr(dir->files[i].name, ':'); info->generic.out.streams[1+i].size = dir->files[i].st.st_size; info->generic.out.streams[1+i].alloc_size = dir->files[i].st.st_size; info->generic.out.streams[1+i].stream_name.s = s?s:dir->files[i].name; } return NT_STATUS_OK; }
/**************************************************************************** Do a specific test for a SAM_ACCOUNT being valid for this connection (ie not disabled, expired and the like). ****************************************************************************/ _PUBLIC_ NTSTATUS authsam_account_ok(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx, uint32_t logon_parameters, struct ldb_dn *domain_dn, struct ldb_message *msg, const char *logon_workstation, const char *name_for_logs, bool allow_domain_trust, bool password_change) { uint16_t acct_flags; const char *workstation_list; NTTIME acct_expiry; NTTIME must_change_time; NTTIME now; DEBUG(4,("authsam_account_ok: Checking SMB password for user %s\n", name_for_logs)); acct_flags = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, domain_dn); acct_expiry = samdb_result_account_expires(msg); /* Check for when we must change this password, taking the * userAccountControl flags into account */ must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx, domain_dn, msg); workstation_list = ldb_msg_find_attr_as_string(msg, "userWorkstations", NULL); /* Quit if the account was disabled. */ if (acct_flags & ACB_DISABLED) { DEBUG(2,("authsam_account_ok: Account for user '%s' was disabled.\n", name_for_logs)); return NT_STATUS_ACCOUNT_DISABLED; } /* Quit if the account was locked out. */ if (acct_flags & ACB_AUTOLOCK) { DEBUG(2,("authsam_account_ok: Account for user %s was locked out.\n", name_for_logs)); return NT_STATUS_ACCOUNT_LOCKED_OUT; } /* Test account expire time */ unix_to_nt_time(&now, time(NULL)); if (now > acct_expiry) { DEBUG(2,("authsam_account_ok: Account for user '%s' has expired.\n", name_for_logs)); DEBUG(3,("authsam_account_ok: Account expired at '%s'.\n", nt_time_string(mem_ctx, acct_expiry))); return NT_STATUS_ACCOUNT_EXPIRED; } /* check for immediate expiry "must change at next logon" (but not if this is a password change request) */ if ((must_change_time == 0) && !password_change) { DEBUG(2,("sam_account_ok: Account for user '%s' password must change!.\n", name_for_logs)); return NT_STATUS_PASSWORD_MUST_CHANGE; } /* check for expired password (but not if this is a password change request) */ if ((must_change_time < now) && !password_change) { DEBUG(2,("sam_account_ok: Account for user '%s' password expired!.\n", name_for_logs)); DEBUG(2,("sam_account_ok: Password expired at '%s' unix time.\n", nt_time_string(mem_ctx, must_change_time))); return NT_STATUS_PASSWORD_EXPIRED; } /* Test workstation. Workstation list is comma separated. */ if (logon_workstation && workstation_list && *workstation_list) { bool invalid_ws = true; int i; const char **workstations = (const char **)str_list_make(mem_ctx, workstation_list, ","); for (i = 0; workstations && workstations[i]; i++) { DEBUG(10,("sam_account_ok: checking for workstation match '%s' and '%s'\n", workstations[i], logon_workstation)); if (strequal(workstations[i], logon_workstation)) { invalid_ws = false; break; } } talloc_free(workstations); if (invalid_ws) { return NT_STATUS_INVALID_WORKSTATION; } } if (!logon_hours_ok(msg, name_for_logs)) { return NT_STATUS_INVALID_LOGON_HOURS; } if (!allow_domain_trust) { if (acct_flags & ACB_DOMTRUST) { DEBUG(2,("sam_account_ok: Domain trust account %s denied by server\n", name_for_logs)); return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT; } } if (!(logon_parameters & MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT)) { if (acct_flags & ACB_SVRTRUST) { DEBUG(2,("sam_account_ok: Server trust account %s denied by server\n", name_for_logs)); return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT; } } if (!(logon_parameters & MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT)) { /* TODO: this fails with current solaris client. We need to work with Gordon to work out why */ if (acct_flags & ACB_WSTRUST) { DEBUG(4,("sam_account_ok: Wksta trust account %s denied by server\n", name_for_logs)); return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT; } } return NT_STATUS_OK; }
/** * @brief Decode a blob containing a NDR envoded PAC structure * * @param mem_ctx - The memory context * @param pac_data_blob - The data blob containing the NDR encoded data * @param context - The Kerberos Context * @param service_keyblock - The Service Key used to verify the checksum * @param client_principal - The client principal * @param tgs_authtime - The ticket timestamp * @param pac_data_out - [out] The decoded PAC * * @return - A NTSTATUS error code */ NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx, DATA_BLOB pac_data_blob, krb5_context context, const krb5_keyblock *krbtgt_keyblock, const krb5_keyblock *service_keyblock, krb5_const_principal client_principal, time_t tgs_authtime, struct PAC_DATA **pac_data_out) { NTSTATUS status; enum ndr_err_code ndr_err; krb5_error_code ret; DATA_BLOB modified_pac_blob; NTTIME tgs_authtime_nttime; krb5_principal client_principal_pac = NULL; int i; struct PAC_SIGNATURE_DATA *srv_sig_ptr = NULL; struct PAC_SIGNATURE_DATA *kdc_sig_ptr = NULL; struct PAC_SIGNATURE_DATA *srv_sig_wipe = NULL; struct PAC_SIGNATURE_DATA *kdc_sig_wipe = NULL; struct PAC_LOGON_NAME *logon_name = NULL; struct PAC_LOGON_INFO *logon_info = NULL; struct PAC_DATA *pac_data = NULL; struct PAC_DATA_RAW *pac_data_raw = NULL; DATA_BLOB *srv_sig_blob = NULL; DATA_BLOB *kdc_sig_blob = NULL; bool bool_ret; *pac_data_out = NULL; pac_data = talloc(mem_ctx, struct PAC_DATA); pac_data_raw = talloc(mem_ctx, struct PAC_DATA_RAW); kdc_sig_wipe = talloc(mem_ctx, struct PAC_SIGNATURE_DATA); srv_sig_wipe = talloc(mem_ctx, struct PAC_SIGNATURE_DATA); if (!pac_data_raw || !pac_data || !kdc_sig_wipe || !srv_sig_wipe) { return NT_STATUS_NO_MEMORY; } ndr_err = ndr_pull_struct_blob(&pac_data_blob, pac_data, pac_data, (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't parse the PAC: %s\n", nt_errstr(status))); return status; } if (pac_data->num_buffers < 4) { /* we need logon_ingo, service_key and kdc_key */ DEBUG(0,("less than 4 PAC buffers\n")); return NT_STATUS_INVALID_PARAMETER; } ndr_err = ndr_pull_struct_blob( &pac_data_blob, pac_data_raw, pac_data_raw, (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA_RAW); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't parse the PAC: %s\n", nt_errstr(status))); return status; } if (pac_data_raw->num_buffers < 4) { /* we need logon_ingo, service_key and kdc_key */ DEBUG(0,("less than 4 PAC buffers\n")); return NT_STATUS_INVALID_PARAMETER; } if (pac_data->num_buffers != pac_data_raw->num_buffers) { /* we need logon_ingo, service_key and kdc_key */ DEBUG(0, ("misparse! PAC_DATA has %d buffers while " "PAC_DATA_RAW has %d\n", pac_data->num_buffers, pac_data_raw->num_buffers)); return NT_STATUS_INVALID_PARAMETER; } for (i=0; i < pac_data->num_buffers; i++) { struct PAC_BUFFER *data_buf = &pac_data->buffers[i]; struct PAC_BUFFER_RAW *raw_buf = &pac_data_raw->buffers[i]; if (data_buf->type != raw_buf->type) { DEBUG(0, ("misparse! PAC_DATA buffer %d has type " "%d while PAC_DATA_RAW has %d\n", i, data_buf->type, raw_buf->type)); return NT_STATUS_INVALID_PARAMETER; } switch (data_buf->type) { case PAC_TYPE_LOGON_INFO: if (!data_buf->info) { break; } logon_info = data_buf->info->logon_info.info; break; case PAC_TYPE_SRV_CHECKSUM: if (!data_buf->info) { break; } srv_sig_ptr = &data_buf->info->srv_cksum; srv_sig_blob = &raw_buf->info->remaining; break; case PAC_TYPE_KDC_CHECKSUM: if (!data_buf->info) { break; } kdc_sig_ptr = &data_buf->info->kdc_cksum; kdc_sig_blob = &raw_buf->info->remaining; break; case PAC_TYPE_LOGON_NAME: logon_name = &data_buf->info->logon_name; break; default: break; } } if (!logon_info) { DEBUG(0,("PAC no logon_info\n")); return NT_STATUS_INVALID_PARAMETER; } if (!logon_name) { DEBUG(0,("PAC no logon_name\n")); return NT_STATUS_INVALID_PARAMETER; } if (!srv_sig_ptr || !srv_sig_blob) { DEBUG(0,("PAC no srv_key\n")); return NT_STATUS_INVALID_PARAMETER; } if (!kdc_sig_ptr || !kdc_sig_blob) { DEBUG(0,("PAC no kdc_key\n")); return NT_STATUS_INVALID_PARAMETER; } /* Find and zero out the signatures, * as required by the signing algorithm */ /* We find the data blobs above, * now we parse them to get at the exact portion we should zero */ ndr_err = ndr_pull_struct_blob( kdc_sig_blob, kdc_sig_wipe, kdc_sig_wipe, (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't parse the KDC signature: %s\n", nt_errstr(status))); return status; } ndr_err = ndr_pull_struct_blob( srv_sig_blob, srv_sig_wipe, srv_sig_wipe, (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't parse the SRV signature: %s\n", nt_errstr(status))); return status; } /* Now zero the decoded structure */ memset(kdc_sig_wipe->signature.data, '\0', kdc_sig_wipe->signature.length); memset(srv_sig_wipe->signature.data, '\0', srv_sig_wipe->signature.length); /* and reencode, back into the same place it came from */ ndr_err = ndr_push_struct_blob( kdc_sig_blob, pac_data_raw, kdc_sig_wipe, (ndr_push_flags_fn_t)ndr_push_PAC_SIGNATURE_DATA); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't repack the KDC signature: %s\n", nt_errstr(status))); return status; } ndr_err = ndr_push_struct_blob( srv_sig_blob, pac_data_raw, srv_sig_wipe, (ndr_push_flags_fn_t)ndr_push_PAC_SIGNATURE_DATA); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't repack the SRV signature: %s\n", nt_errstr(status))); return status; } /* push out the whole structure, but now with zero'ed signatures */ ndr_err = ndr_push_struct_blob( &modified_pac_blob, pac_data_raw, pac_data_raw, (ndr_push_flags_fn_t)ndr_push_PAC_DATA_RAW); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't repack the RAW PAC: %s\n", nt_errstr(status))); return status; } if (service_keyblock) { /* verify by service_key */ ret = check_pac_checksum(mem_ctx, modified_pac_blob, srv_sig_ptr, context, service_keyblock); if (ret) { DEBUG(1, ("PAC Decode: Failed to verify the service " "signature: %s\n", error_message(ret))); return NT_STATUS_ACCESS_DENIED; } if (krbtgt_keyblock) { /* verify the service key checksum by krbtgt_key */ ret = check_pac_checksum(mem_ctx, srv_sig_ptr->signature, kdc_sig_ptr, context, krbtgt_keyblock); if (ret) { DEBUG(1, ("PAC Decode: Failed to verify the KDC signature: %s\n", smb_get_krb5_error_message(context, ret, mem_ctx))); return NT_STATUS_ACCESS_DENIED; } } } if (tgs_authtime) { /* Convert to NT time, so as not to loose accuracy in comparison */ unix_to_nt_time(&tgs_authtime_nttime, tgs_authtime); if (tgs_authtime_nttime != logon_name->logon_time) { DEBUG(2, ("PAC Decode: " "Logon time mismatch between ticket and PAC!\n")); DEBUG(2, ("PAC Decode: PAC: %s\n", nt_time_string(mem_ctx, logon_name->logon_time))); DEBUG(2, ("PAC Decode: Ticket: %s\n", nt_time_string(mem_ctx, tgs_authtime_nttime))); return NT_STATUS_ACCESS_DENIED; } } if (client_principal) { ret = smb_krb5_parse_name_norealm(context, logon_name->account_name, &client_principal_pac); if (ret) { DEBUG(2, ("Could not parse name from PAC: [%s]:%s\n", logon_name->account_name, error_message(ret))); return NT_STATUS_INVALID_PARAMETER; } bool_ret = smb_krb5_principal_compare_any_realm(context, client_principal, client_principal_pac); krb5_free_principal(context, client_principal_pac); if (!bool_ret) { DEBUG(2, ("Name in PAC [%s] does not match principal name " "in ticket\n", logon_name->account_name)); return NT_STATUS_ACCESS_DENIED; } } DEBUG(3,("Found account name from PAC: %s [%s]\n", logon_info->info3.base.account_name.string, logon_info->info3.base.full_name.string)); DEBUG(10,("Successfully validated Kerberos PAC\n")); if (DEBUGLEVEL >= 10) { const char *s; s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_DATA, pac_data); if (s) { DEBUGADD(10,("%s\n", s)); } } *pac_data_out = pac_data; return NT_STATUS_OK; }
NTSTATUS samu_to_SamInfo3(TALLOC_CTX *mem_ctx, struct samu *samu, const char *login_server, struct netr_SamInfo3 **_info3, struct extra_auth_info *extra) { struct netr_SamInfo3 *info3; const struct dom_sid *user_sid; const struct dom_sid *group_sid; struct dom_sid domain_sid; struct dom_sid *group_sids; uint32_t num_group_sids = 0; const char *tmp; gid_t *gids; NTSTATUS status; user_sid = pdb_get_user_sid(samu); group_sid = pdb_get_group_sid(samu); if (!user_sid || !group_sid) { DEBUG(1, ("Sam account is missing sids!\n")); return NT_STATUS_UNSUCCESSFUL; } info3 = talloc_zero(mem_ctx, struct netr_SamInfo3); if (!info3) { return NT_STATUS_NO_MEMORY; } ZERO_STRUCT(domain_sid); status = SamInfo3_handle_sids(pdb_get_username(samu), user_sid, group_sid, info3, &domain_sid, extra); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(info3); return status; } unix_to_nt_time(&info3->base.logon_time, pdb_get_logon_time(samu)); unix_to_nt_time(&info3->base.logoff_time, get_time_t_max()); unix_to_nt_time(&info3->base.kickoff_time, get_time_t_max()); unix_to_nt_time(&info3->base.last_password_change, pdb_get_pass_last_set_time(samu)); unix_to_nt_time(&info3->base.allow_password_change, pdb_get_pass_can_change_time(samu)); unix_to_nt_time(&info3->base.force_password_change, pdb_get_pass_must_change_time(samu)); tmp = pdb_get_username(samu); if (tmp) { info3->base.account_name.string = talloc_strdup(info3, tmp); RET_NOMEM(info3->base.account_name.string); } tmp = pdb_get_fullname(samu); if (tmp) { info3->base.full_name.string = talloc_strdup(info3, tmp); RET_NOMEM(info3->base.full_name.string); } tmp = pdb_get_logon_script(samu); if (tmp) { info3->base.logon_script.string = talloc_strdup(info3, tmp); RET_NOMEM(info3->base.logon_script.string); } tmp = pdb_get_profile_path(samu); if (tmp) { info3->base.profile_path.string = talloc_strdup(info3, tmp); RET_NOMEM(info3->base.profile_path.string); } tmp = pdb_get_homedir(samu); if (tmp) { info3->base.home_directory.string = talloc_strdup(info3, tmp); RET_NOMEM(info3->base.home_directory.string); } tmp = pdb_get_dir_drive(samu); if (tmp) { info3->base.home_drive.string = talloc_strdup(info3, tmp); RET_NOMEM(info3->base.home_drive.string); } info3->base.logon_count = pdb_get_logon_count(samu); info3->base.bad_password_count = pdb_get_bad_password_count(samu); info3->base.logon_domain.string = talloc_strdup(info3, pdb_get_domain(samu)); RET_NOMEM(info3->base.logon_domain.string); info3->base.domain_sid = dom_sid_dup(info3, &domain_sid); RET_NOMEM(info3->base.domain_sid); status = pdb_enum_group_memberships(mem_ctx, samu, &group_sids, &gids, &num_group_sids); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to get groups from sam account.\n")); TALLOC_FREE(info3); return status; } if (num_group_sids) { status = group_sids_to_info3(info3, group_sids, num_group_sids); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(info3); return status; } } /* We don't need sids and gids after the conversion */ TALLOC_FREE(group_sids); TALLOC_FREE(gids); num_group_sids = 0; /* FIXME: should we add other flags ? */ info3->base.user_flags = NETLOGON_EXTRA_SIDS; if (login_server) { info3->base.logon_server.string = talloc_strdup(info3, login_server); RET_NOMEM(info3->base.logon_server.string); } info3->base.acct_flags = pdb_get_acct_ctrl(samu); *_info3 = info3; return NT_STATUS_OK; }
NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, struct PAC_DATA **pac_data_out, DATA_BLOB blob, krb5_context context, const krb5_keyblock *krbtgt_keyblock, const krb5_keyblock *service_keyblock, krb5_const_principal client_principal, time_t tgs_authtime, krb5_error_code *k5ret) { krb5_error_code ret; NTSTATUS status; enum ndr_err_code ndr_err; struct PAC_SIGNATURE_DATA *srv_sig_ptr = NULL; struct PAC_SIGNATURE_DATA *kdc_sig_ptr = NULL; struct PAC_SIGNATURE_DATA *srv_sig_wipe = NULL; struct PAC_SIGNATURE_DATA *kdc_sig_wipe = NULL; struct PAC_LOGON_INFO *logon_info = NULL; struct PAC_LOGON_NAME *logon_name = NULL; struct PAC_DATA *pac_data; struct PAC_DATA_RAW *pac_data_raw; DATA_BLOB *srv_sig_blob = NULL; DATA_BLOB *kdc_sig_blob = NULL; DATA_BLOB modified_pac_blob; NTTIME tgs_authtime_nttime; krb5_principal client_principal_pac; int i; krb5_clear_error_message(context); if (k5ret) { *k5ret = KRB5_PARSE_MALFORMED; } pac_data = talloc(mem_ctx, struct PAC_DATA); pac_data_raw = talloc(mem_ctx, struct PAC_DATA_RAW); kdc_sig_wipe = talloc(mem_ctx, struct PAC_SIGNATURE_DATA); srv_sig_wipe = talloc(mem_ctx, struct PAC_SIGNATURE_DATA); if (!pac_data_raw || !pac_data || !kdc_sig_wipe || !srv_sig_wipe) { if (k5ret) { *k5ret = ENOMEM; } return NT_STATUS_NO_MEMORY; } ndr_err = ndr_pull_struct_blob(&blob, pac_data, iconv_convenience, pac_data, (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't parse the PAC: %s\n", nt_errstr(status))); return status; } if (pac_data->num_buffers < 4) { /* we need logon_ingo, service_key and kdc_key */ DEBUG(0,("less than 4 PAC buffers\n")); return NT_STATUS_INVALID_PARAMETER; } ndr_err = ndr_pull_struct_blob(&blob, pac_data_raw, iconv_convenience, pac_data_raw, (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA_RAW); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't parse the PAC: %s\n", nt_errstr(status))); return status; } if (pac_data_raw->num_buffers < 4) { /* we need logon_ingo, service_key and kdc_key */ DEBUG(0,("less than 4 PAC buffers\n")); return NT_STATUS_INVALID_PARAMETER; } if (pac_data->num_buffers != pac_data_raw->num_buffers) { /* we need logon_ingo, service_key and kdc_key */ DEBUG(0,("misparse! PAC_DATA has %d buffers while PAC_DATA_RAW has %d\n", pac_data->num_buffers, pac_data_raw->num_buffers)); return NT_STATUS_INVALID_PARAMETER; } for (i=0; i < pac_data->num_buffers; i++) { if (pac_data->buffers[i].type != pac_data_raw->buffers[i].type) { DEBUG(0,("misparse! PAC_DATA buffer %d has type %d while PAC_DATA_RAW has %d\n", i, pac_data->buffers[i].type, pac_data->buffers[i].type)); return NT_STATUS_INVALID_PARAMETER; } switch (pac_data->buffers[i].type) { case PAC_TYPE_LOGON_INFO: if (!pac_data->buffers[i].info) { break; } logon_info = pac_data->buffers[i].info->logon_info.info; break; case PAC_TYPE_SRV_CHECKSUM: if (!pac_data->buffers[i].info) { break; } srv_sig_ptr = &pac_data->buffers[i].info->srv_cksum; srv_sig_blob = &pac_data_raw->buffers[i].info->remaining; break; case PAC_TYPE_KDC_CHECKSUM: if (!pac_data->buffers[i].info) { break; } kdc_sig_ptr = &pac_data->buffers[i].info->kdc_cksum; kdc_sig_blob = &pac_data_raw->buffers[i].info->remaining; break; case PAC_TYPE_LOGON_NAME: logon_name = &pac_data->buffers[i].info->logon_name; break; default: break; } } if (!logon_info) { DEBUG(0,("PAC no logon_info\n")); return NT_STATUS_INVALID_PARAMETER; } if (!logon_name) { DEBUG(0,("PAC no logon_name\n")); return NT_STATUS_INVALID_PARAMETER; } if (!srv_sig_ptr || !srv_sig_blob) { DEBUG(0,("PAC no srv_key\n")); return NT_STATUS_INVALID_PARAMETER; } if (!kdc_sig_ptr || !kdc_sig_blob) { DEBUG(0,("PAC no kdc_key\n")); return NT_STATUS_INVALID_PARAMETER; } /* Find and zero out the signatures, as required by the signing algorithm */ /* We find the data blobs above, now we parse them to get at the exact portion we should zero */ ndr_err = ndr_pull_struct_blob(kdc_sig_blob, kdc_sig_wipe, iconv_convenience, kdc_sig_wipe, (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't parse the KDC signature: %s\n", nt_errstr(status))); return status; } ndr_err = ndr_pull_struct_blob(srv_sig_blob, srv_sig_wipe, iconv_convenience, srv_sig_wipe, (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't parse the SRV signature: %s\n", nt_errstr(status))); return status; } /* Now zero the decoded structure */ memset(kdc_sig_wipe->signature.data, '\0', kdc_sig_wipe->signature.length); memset(srv_sig_wipe->signature.data, '\0', srv_sig_wipe->signature.length); /* and reencode, back into the same place it came from */ ndr_err = ndr_push_struct_blob(kdc_sig_blob, pac_data_raw, iconv_convenience, kdc_sig_wipe, (ndr_push_flags_fn_t)ndr_push_PAC_SIGNATURE_DATA); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't repack the KDC signature: %s\n", nt_errstr(status))); return status; } ndr_err = ndr_push_struct_blob(srv_sig_blob, pac_data_raw, iconv_convenience, srv_sig_wipe, (ndr_push_flags_fn_t)ndr_push_PAC_SIGNATURE_DATA); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't repack the SRV signature: %s\n", nt_errstr(status))); return status; } /* push out the whole structure, but now with zero'ed signatures */ ndr_err = ndr_push_struct_blob(&modified_pac_blob, pac_data_raw, iconv_convenience, pac_data_raw, (ndr_push_flags_fn_t)ndr_push_PAC_DATA_RAW); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); DEBUG(0,("can't repack the RAW PAC: %s\n", nt_errstr(status))); return status; } /* verify by service_key */ ret = check_pac_checksum(mem_ctx, modified_pac_blob, srv_sig_ptr, context, service_keyblock); if (ret) { DEBUG(1, ("PAC Decode: Failed to verify the service signature: %s\n", smb_get_krb5_error_message(context, ret, mem_ctx))); if (k5ret) { *k5ret = ret; } return NT_STATUS_ACCESS_DENIED; } if (krbtgt_keyblock) { ret = check_pac_checksum(mem_ctx, srv_sig_ptr->signature, kdc_sig_ptr, context, krbtgt_keyblock); if (ret) { DEBUG(1, ("PAC Decode: Failed to verify the KDC signature: %s\n", smb_get_krb5_error_message(context, ret, mem_ctx))); if (k5ret) { *k5ret = ret; } return NT_STATUS_ACCESS_DENIED; } } /* Convert to NT time, so as not to loose accuracy in comparison */ unix_to_nt_time(&tgs_authtime_nttime, tgs_authtime); if (tgs_authtime_nttime != logon_name->logon_time) { DEBUG(2, ("PAC Decode: Logon time mismatch between ticket and PAC!\n")); DEBUG(2, ("PAC Decode: PAC: %s\n", nt_time_string(mem_ctx, logon_name->logon_time))); DEBUG(2, ("PAC Decode: Ticket: %s\n", nt_time_string(mem_ctx, tgs_authtime_nttime))); return NT_STATUS_ACCESS_DENIED; } ret = krb5_parse_name_flags(context, logon_name->account_name, KRB5_PRINCIPAL_PARSE_NO_REALM, &client_principal_pac); if (ret) { DEBUG(2, ("Could not parse name from incoming PAC: [%s]: %s\n", logon_name->account_name, smb_get_krb5_error_message(context, ret, mem_ctx))); if (k5ret) { *k5ret = ret; } return NT_STATUS_INVALID_PARAMETER; } if (!krb5_principal_compare_any_realm(context, client_principal, client_principal_pac)) { DEBUG(2, ("Name in PAC [%s] does not match principal name in ticket\n", logon_name->account_name)); return NT_STATUS_ACCESS_DENIED; } #if 0 if (strcasecmp(logon_info->info3.base.account_name.string, "Administrator")== 0) { file_save("tmp_pac_data-admin.dat",blob.data,blob.length); } #endif DEBUG(3,("Found account name from PAC: %s [%s]\n", logon_info->info3.base.account_name.string, logon_info->info3.base.full_name.string)); *pac_data_out = pac_data; return NT_STATUS_OK; }
/* basic testing of all SMB2 setinfo calls for each call we test that it succeeds, and where possible test for consistency between the calls. */ bool torture_smb2_setinfo(struct torture_context *tctx) { struct smb2_tree *tree; bool ret = true; struct smb2_handle handle; char *fname; union smb_fileinfo finfo2; union smb_setfileinfo sfinfo; struct security_ace ace; struct security_descriptor *sd; struct dom_sid *test_sid; NTSTATUS status, status2=NT_STATUS_OK; const char *call_name; time_t basetime = (time(NULL) - 86400) & ~1; int n = time(NULL) % 100; struct ea_struct ea; ZERO_STRUCT(handle); fname = talloc_asprintf(tctx, BASEDIR "fnum_test_%d.txt", n); if (!torture_smb2_connection(tctx, &tree)) { return false; } #define RECREATE_FILE(fname) do { \ smb2_util_close(tree, handle); \ status = smb2_create_complex_file(tree, fname, &handle); \ if (!NT_STATUS_IS_OK(status)) { \ torture_result(tctx, TORTURE_FAIL, "(%s) ERROR: open of %s failed (%s)\n", \ __location__, fname, nt_errstr(status)); \ ret = false; \ goto done; \ }} while (0) #define RECREATE_BOTH do { \ RECREATE_FILE(fname); \ } while (0) RECREATE_BOTH; #define CHECK_CALL(call, rightstatus) do { \ call_name = #call; \ sfinfo.generic.level = RAW_SFILEINFO_ ## call; \ sfinfo.generic.in.file.handle = handle; \ status = smb2_setinfo_file(tree, &sfinfo); \ if (!NT_STATUS_EQUAL(status, rightstatus)) { \ torture_result(tctx, TORTURE_FAIL, "(%s) %s - %s (should be %s)\n", __location__, #call, \ nt_errstr(status), nt_errstr(rightstatus)); \ ret = false; \ goto done; \ } \ } while (0) #define CHECK1(call) \ do { if (NT_STATUS_IS_OK(status)) { \ finfo2.generic.level = RAW_FILEINFO_ ## call; \ finfo2.generic.in.file.handle = handle; \ status2 = smb2_getinfo_file(tree, tctx, &finfo2); \ if (!NT_STATUS_IS_OK(status2)) { \ torture_result(tctx, TORTURE_FAIL, "(%s) %s - %s\n", __location__, #call, nt_errstr(status2)); \ ret = false; \ goto done; \ } \ }} while (0) #define CHECK_VALUE(call, stype, field, value) do { \ CHECK1(call); \ if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && finfo2.stype.out.field != value) { \ torture_result(tctx, TORTURE_FAIL, "(%s) %s - %s/%s should be 0x%x - 0x%x\n", __location__, \ call_name, #stype, #field, \ (unsigned int)value, (unsigned int)finfo2.stype.out.field); \ torture_smb2_all_info(tree, handle); \ ret = false; \ goto done; \ }} while (0) #define CHECK_TIME(call, stype, field, value) do { \ CHECK1(call); \ if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && nt_time_to_unix(finfo2.stype.out.field) != value) { \ torture_result(tctx, TORTURE_FAIL, "(%s) %s - %s/%s should be 0x%x - 0x%x\n", __location__, \ call_name, #stype, #field, \ (unsigned int)value, \ (unsigned int)nt_time_to_unix(finfo2.stype.out.field)); \ torture_warning(tctx, "\t%s", timestring(tctx, value)); \ torture_warning(tctx, "\t%s\n", nt_time_string(tctx, finfo2.stype.out.field)); \ torture_smb2_all_info(tree, handle); \ ret = false; \ goto done; \ }} while (0) #define CHECK_STATUS(status, correct) do { \ if (!NT_STATUS_EQUAL(status, correct)) { \ torture_result(tctx, TORTURE_FAIL, "(%s) Incorrect status %s - should be %s\n", \ __location__, nt_errstr(status), nt_errstr(correct)); \ ret = false; \ goto done; \ }} while (0) torture_smb2_all_info(tree, handle); torture_comment(tctx, "Test basic_information level\n"); basetime += 86400; unix_to_nt_time(&sfinfo.basic_info.in.create_time, basetime + 100); unix_to_nt_time(&sfinfo.basic_info.in.access_time, basetime + 200); unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime + 300); unix_to_nt_time(&sfinfo.basic_info.in.change_time, basetime + 400); sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY; CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK); CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, create_time, basetime + 100); CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, access_time, basetime + 200); CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, write_time, basetime + 300); CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, change_time, basetime + 400); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_READONLY); torture_comment(tctx, "a zero time means don't change\n"); unix_to_nt_time(&sfinfo.basic_info.in.create_time, 0); unix_to_nt_time(&sfinfo.basic_info.in.access_time, 0); unix_to_nt_time(&sfinfo.basic_info.in.write_time, 0); unix_to_nt_time(&sfinfo.basic_info.in.change_time, 0); sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL; CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK); CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, create_time, basetime + 100); CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, access_time, basetime + 200); CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, write_time, basetime + 300); CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, change_time, basetime + 400); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_NORMAL); torture_comment(tctx, "change the attribute\n"); sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_HIDDEN; CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_HIDDEN); torture_comment(tctx, "zero attrib means don't change\n"); sfinfo.basic_info.in.attrib = 0; CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_HIDDEN); torture_comment(tctx, "can't change a file to a directory\n"); sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_DIRECTORY; CHECK_CALL(BASIC_INFORMATION, NT_STATUS_INVALID_PARAMETER); torture_comment(tctx, "restore attribute\n"); sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL; CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_NORMAL); torture_comment(tctx, "Test disposition_information level\n"); sfinfo.disposition_info.in.delete_on_close = 1; CHECK_CALL(DISPOSITION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, delete_pending, 1); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, nlink, 0); sfinfo.disposition_info.in.delete_on_close = 0; CHECK_CALL(DISPOSITION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, delete_pending, 0); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, nlink, 1); torture_comment(tctx, "Test allocation_information level\n"); sfinfo.allocation_info.in.alloc_size = 0; CHECK_CALL(ALLOCATION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 0); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, alloc_size, 0); sfinfo.allocation_info.in.alloc_size = 4096; CHECK_CALL(ALLOCATION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, alloc_size, 4096); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 0); torture_comment(tctx, "Test end_of_file_info level\n"); sfinfo.end_of_file_info.in.size = 37; CHECK_CALL(END_OF_FILE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 37); sfinfo.end_of_file_info.in.size = 7; CHECK_CALL(END_OF_FILE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 7); torture_comment(tctx, "Test position_information level\n"); sfinfo.position_information.in.position = 123456; CHECK_CALL(POSITION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(POSITION_INFORMATION, position_information, position, 123456); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, position, 123456); torture_comment(tctx, "Test mode_information level\n"); sfinfo.mode_information.in.mode = 2; CHECK_CALL(MODE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 2); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, mode, 2); sfinfo.mode_information.in.mode = 1; CHECK_CALL(MODE_INFORMATION, NT_STATUS_INVALID_PARAMETER); sfinfo.mode_information.in.mode = 0; CHECK_CALL(MODE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 0); torture_comment(tctx, "Test sec_desc level\n"); ZERO_STRUCT(finfo2); finfo2.query_secdesc.in.secinfo_flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL; CHECK1(SEC_DESC); sd = finfo2.query_secdesc.out.sd; test_sid = dom_sid_parse_talloc(tctx, SID_NT_AUTHENTICATED_USERS); ZERO_STRUCT(ace); ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED; ace.flags = 0; ace.access_mask = SEC_STD_ALL; ace.trustee = *test_sid; status = security_descriptor_dacl_add(sd, &ace); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "add a new ACE to the DACL\n"); sfinfo.set_secdesc.in.secinfo_flags = finfo2.query_secdesc.in.secinfo_flags; sfinfo.set_secdesc.in.sd = sd; CHECK_CALL(SEC_DESC, NT_STATUS_OK); FAIL_UNLESS(smb2_util_verify_sd(tctx, tree, handle, sd)); torture_comment(tctx, "remove it again\n"); status = security_descriptor_dacl_del(sd, test_sid); CHECK_STATUS(status, NT_STATUS_OK); sfinfo.set_secdesc.in.secinfo_flags = finfo2.query_secdesc.in.secinfo_flags; sfinfo.set_secdesc.in.sd = sd; CHECK_CALL(SEC_DESC, NT_STATUS_OK); FAIL_UNLESS(smb2_util_verify_sd(tctx, tree, handle, sd)); torture_comment(tctx, "Check zero length EA's behavior\n"); /* Set a new EA. */ sfinfo.full_ea_information.in.eas.num_eas = 1; ea.flags = 0; ea.name.private_length = 6; ea.name.s = "NewEA"; ea.value = data_blob_string_const("testme"); sfinfo.full_ea_information.in.eas.eas = &ea; CHECK_CALL(FULL_EA_INFORMATION, NT_STATUS_OK); /* Does it still exist ? */ finfo2.generic.level = RAW_FILEINFO_SMB2_ALL_EAS; finfo2.generic.in.file.handle = handle; finfo2.all_eas.in.continue_flags = 1; status2 = smb2_getinfo_file(tree, tctx, &finfo2); if (!NT_STATUS_IS_OK(status2)) { torture_result(tctx, TORTURE_FAIL, "(%s) %s - %s\n", __location__, "SMB2_ALL_EAS", nt_errstr(status2)); ret = false; goto done; } /* Note on Windows EA name is returned capitalized. */ if (!find_returned_ea(&finfo2, "NewEA", "testme")) { torture_result(tctx, TORTURE_FAIL, "(%s) Missing EA 'NewEA'\n", __location__); ret = false; } /* Now zero it out (should delete it) */ sfinfo.full_ea_information.in.eas.num_eas = 1; ea.flags = 0; ea.name.private_length = 6; ea.name.s = "NewEA"; ea.value = data_blob_null; sfinfo.full_ea_information.in.eas.eas = &ea; CHECK_CALL(FULL_EA_INFORMATION, NT_STATUS_OK); /* Does it still exist ? */ finfo2.generic.level = RAW_FILEINFO_SMB2_ALL_EAS; finfo2.generic.in.file.handle = handle; finfo2.all_eas.in.continue_flags = 1; status2 = smb2_getinfo_file(tree, tctx, &finfo2); if (!NT_STATUS_IS_OK(status2)) { torture_result(tctx, TORTURE_FAIL, "(%s) %s - %s\n", __location__, "SMB2_ALL_EAS", nt_errstr(status2)); ret = false; goto done; } if (find_returned_ea(&finfo2, "NewEA", NULL)) { torture_result(tctx, TORTURE_FAIL, "(%s) EA 'NewEA' should be deleted\n", __location__); ret = false; } /* Set a zero length EA. */ sfinfo.full_ea_information.in.eas.num_eas = 1; ea.flags = 0; ea.name.private_length = 6; ea.name.s = "ZeroEA"; ea.value = data_blob_null; sfinfo.full_ea_information.in.eas.eas = &ea; CHECK_CALL(FULL_EA_INFORMATION, NT_STATUS_OK); /* Does it still exist ? */ finfo2.generic.level = RAW_FILEINFO_SMB2_ALL_EAS; finfo2.generic.in.file.handle = handle; finfo2.all_eas.in.continue_flags = 1; status2 = smb2_getinfo_file(tree, tctx, &finfo2); if (!NT_STATUS_IS_OK(status2)) { torture_result(tctx, TORTURE_FAIL, "(%s) %s - %s\n", __location__, "SMB2_ALL_EAS", nt_errstr(status2)); ret = false; goto done; } /* Over SMB2 ZeroEA should not exist. */ if (!find_returned_ea(&finfo2, "EAONE", "VALUE1")) { torture_result(tctx, TORTURE_FAIL, "(%s) Missing EA 'EAONE'\n", __location__); ret = false; } if (!find_returned_ea(&finfo2, "SECONDEA", "ValueTwo")) { torture_result(tctx, TORTURE_FAIL, "(%s) Missing EA 'SECONDEA'\n", __location__); ret = false; } if (find_returned_ea(&finfo2, "ZeroEA", NULL)) { torture_result(tctx, TORTURE_FAIL, "(%s) Found null EA 'ZeroEA'\n", __location__); ret = false; } done: status = smb2_util_close(tree, handle); if (NT_STATUS_IS_ERR(status)) { torture_warning(tctx, "Failed to delete %s - %s\n", fname, nt_errstr(status)); } smb2_util_unlink(tree, fname); return ret; }
/* open a file */ static NTSTATUS svfs_open(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_open *io) { struct svfs_private *p = ntvfs->private_data; char *unix_path; struct stat st; int fd, flags; struct svfs_file *f; int create_flags, rdwr_flags; bool readonly; NTSTATUS status; struct ntvfs_handle *handle; if (io->generic.level != RAW_OPEN_GENERIC) { return ntvfs_map_open(ntvfs, req, io); } readonly = share_bool_option(ntvfs->ctx->config, SHARE_READONLY, SHARE_READONLY_DEFAULT); if (readonly) { create_flags = 0; rdwr_flags = O_RDONLY; } else { create_flags = O_CREAT; rdwr_flags = O_RDWR; } unix_path = svfs_unix_path(ntvfs, req, io->ntcreatex.in.fname); switch (io->generic.in.open_disposition) { case NTCREATEX_DISP_SUPERSEDE: case NTCREATEX_DISP_OVERWRITE_IF: flags = create_flags | O_TRUNC; break; case NTCREATEX_DISP_OPEN: case NTCREATEX_DISP_OVERWRITE: flags = 0; break; case NTCREATEX_DISP_CREATE: flags = create_flags | O_EXCL; break; case NTCREATEX_DISP_OPEN_IF: flags = create_flags; break; default: flags = 0; break; } flags |= rdwr_flags; if (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) { flags = O_RDONLY | O_DIRECTORY; if (readonly) { goto do_open; } switch (io->generic.in.open_disposition) { case NTCREATEX_DISP_CREATE: if (mkdir(unix_path, 0755) == -1) { DEBUG(9,("svfs_open: mkdir %s errno=%d\n", unix_path, errno)); return map_nt_error_from_unix(errno); } break; case NTCREATEX_DISP_OPEN_IF: if (mkdir(unix_path, 0755) == -1 && errno != EEXIST) { DEBUG(9,("svfs_open: mkdir %s errno=%d\n", unix_path, errno)); return map_nt_error_from_unix(errno); } break; } } do_open: fd = open(unix_path, flags, 0644); if (fd == -1) { return map_nt_error_from_unix(errno); } if (fstat(fd, &st) == -1) { DEBUG(9,("svfs_open: fstat errno=%d\n", errno)); close(fd); return map_nt_error_from_unix(errno); } status = ntvfs_handle_new(ntvfs, req, &handle); NT_STATUS_NOT_OK_RETURN(status); f = talloc(handle, struct svfs_file); NT_STATUS_HAVE_NO_MEMORY(f); f->fd = fd; f->name = talloc_strdup(f, unix_path); NT_STATUS_HAVE_NO_MEMORY(f->name); DLIST_ADD(p->open_files, f); status = ntvfs_handle_set_backend_data(handle, ntvfs, f); NT_STATUS_NOT_OK_RETURN(status); ZERO_STRUCT(io->generic.out); unix_to_nt_time(&io->generic.out.create_time, st.st_ctime); unix_to_nt_time(&io->generic.out.access_time, st.st_atime); unix_to_nt_time(&io->generic.out.write_time, st.st_mtime); unix_to_nt_time(&io->generic.out.change_time, st.st_mtime); io->generic.out.file.ntvfs = handle; io->generic.out.alloc_size = st.st_size; io->generic.out.size = st.st_size; io->generic.out.attrib = svfs_unix_to_dos_attrib(st.st_mode); io->generic.out.is_directory = S_ISDIR(st.st_mode) ? 1 : 0; return NT_STATUS_OK; }
krb5_error_code kerberos_create_pac(TALLOC_CTX *mem_ctx, struct auth_user_info_dc *user_info_dc, krb5_context context, const krb5_keyblock *krbtgt_keyblock, const krb5_keyblock *service_keyblock, krb5_principal client_principal, time_t tgs_authtime, DATA_BLOB *pac) { NTSTATUS nt_status; krb5_error_code ret; struct PAC_DATA *pac_data = talloc(mem_ctx, struct PAC_DATA); struct netr_SamInfo3 *sam3; union PAC_INFO *u_LOGON_INFO; struct PAC_LOGON_INFO *LOGON_INFO; union PAC_INFO *u_LOGON_NAME; struct PAC_LOGON_NAME *LOGON_NAME; union PAC_INFO *u_KDC_CHECKSUM; union PAC_INFO *u_SRV_CHECKSUM; char *name; enum { PAC_BUF_LOGON_INFO = 0, PAC_BUF_LOGON_NAME = 1, PAC_BUF_SRV_CHECKSUM = 2, PAC_BUF_KDC_CHECKSUM = 3, PAC_BUF_NUM_BUFFERS = 4 }; if (!pac_data) { return ENOMEM; } pac_data->num_buffers = PAC_BUF_NUM_BUFFERS; pac_data->version = 0; pac_data->buffers = talloc_array(pac_data, struct PAC_BUFFER, pac_data->num_buffers); if (!pac_data->buffers) { talloc_free(pac_data); return ENOMEM; } /* LOGON_INFO */ u_LOGON_INFO = talloc_zero(pac_data->buffers, union PAC_INFO); if (!u_LOGON_INFO) { talloc_free(pac_data); return ENOMEM; } pac_data->buffers[PAC_BUF_LOGON_INFO].type = PAC_TYPE_LOGON_INFO; pac_data->buffers[PAC_BUF_LOGON_INFO].info = u_LOGON_INFO; /* LOGON_NAME */ u_LOGON_NAME = talloc_zero(pac_data->buffers, union PAC_INFO); if (!u_LOGON_NAME) { talloc_free(pac_data); return ENOMEM; } pac_data->buffers[PAC_BUF_LOGON_NAME].type = PAC_TYPE_LOGON_NAME; pac_data->buffers[PAC_BUF_LOGON_NAME].info = u_LOGON_NAME; LOGON_NAME = &u_LOGON_NAME->logon_name; /* SRV_CHECKSUM */ u_SRV_CHECKSUM = talloc_zero(pac_data->buffers, union PAC_INFO); if (!u_SRV_CHECKSUM) { talloc_free(pac_data); return ENOMEM; } pac_data->buffers[PAC_BUF_SRV_CHECKSUM].type = PAC_TYPE_SRV_CHECKSUM; pac_data->buffers[PAC_BUF_SRV_CHECKSUM].info = u_SRV_CHECKSUM; /* KDC_CHECKSUM */ u_KDC_CHECKSUM = talloc_zero(pac_data->buffers, union PAC_INFO); if (!u_KDC_CHECKSUM) { talloc_free(pac_data); return ENOMEM; } pac_data->buffers[PAC_BUF_KDC_CHECKSUM].type = PAC_TYPE_KDC_CHECKSUM; pac_data->buffers[PAC_BUF_KDC_CHECKSUM].info = u_KDC_CHECKSUM; /* now the real work begins... */ LOGON_INFO = talloc_zero(u_LOGON_INFO, struct PAC_LOGON_INFO); if (!LOGON_INFO) { talloc_free(pac_data); return ENOMEM; } nt_status = auth_convert_user_info_dc_saminfo3(LOGON_INFO, user_info_dc, &sam3); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("Getting Samba info failed: %s\n", nt_errstr(nt_status))); talloc_free(pac_data); return EINVAL; } u_LOGON_INFO->logon_info.info = LOGON_INFO; LOGON_INFO->info3 = *sam3; ret = krb5_unparse_name_flags(context, client_principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM | KRB5_PRINCIPAL_UNPARSE_DISPLAY, &name); if (ret) { return ret; } LOGON_NAME->account_name = talloc_strdup(LOGON_NAME, name); free(name); /* this logon_time field is absolutely critical. This is what caused all our PAC troubles :-) */ unix_to_nt_time(&LOGON_NAME->logon_time, tgs_authtime); ret = kerberos_encode_pac(mem_ctx, pac_data, context, krbtgt_keyblock, service_keyblock, pac); talloc_free(pac_data); return ret; }
NTSTATUS serverinfo_to_SamInfo3(struct auth_serversupplied_info *server_info, uint8_t pipe_session_key[16], struct netr_SamInfo3 *sam3) { struct samu *sampw; DOM_GID *gids = NULL; const DOM_SID *user_sid = NULL; const DOM_SID *group_sid = NULL; DOM_SID domain_sid; uint32 user_rid, group_rid; NTSTATUS status; int num_gids = 0; const char *my_name; struct netr_UserSessionKey user_session_key; struct netr_LMSessionKey lm_session_key; NTTIME last_logon, last_logoff, acct_expiry, last_password_change; NTTIME allow_password_change, force_password_change; struct samr_RidWithAttributeArray groups; int i; struct dom_sid2 *sid = NULL; ZERO_STRUCT(user_session_key); ZERO_STRUCT(lm_session_key); sampw = server_info->sam_account; user_sid = pdb_get_user_sid(sampw); group_sid = pdb_get_group_sid(sampw); if ((user_sid == NULL) || (group_sid == NULL)) { DEBUG(1, ("_netr_LogonSamLogon: User without group or user SID\n")); return NT_STATUS_UNSUCCESSFUL; } sid_copy(&domain_sid, user_sid); sid_split_rid(&domain_sid, &user_rid); sid = sid_dup_talloc(sam3, &domain_sid); if (!sid) { return NT_STATUS_NO_MEMORY; } if (!sid_peek_check_rid(&domain_sid, group_sid, &group_rid)) { DEBUG(1, ("_netr_LogonSamLogon: user %s\\%s has user sid " "%s\n but group sid %s.\n" "The conflicting domain portions are not " "supported for NETLOGON calls\n", pdb_get_domain(sampw), pdb_get_username(sampw), sid_string_dbg(user_sid), sid_string_dbg(group_sid))); return NT_STATUS_UNSUCCESSFUL; } if(server_info->login_server) { my_name = server_info->login_server; } else { my_name = global_myname(); } status = nt_token_to_group_list(sam3, &domain_sid, server_info->num_sids, server_info->sids, &num_gids, &gids); if (!NT_STATUS_IS_OK(status)) { return status; } if (server_info->user_session_key.length) { memcpy(user_session_key.key, server_info->user_session_key.data, MIN(sizeof(user_session_key.key), server_info->user_session_key.length)); SamOEMhash(user_session_key.key, pipe_session_key, 16); } if (server_info->lm_session_key.length) { memcpy(lm_session_key.key, server_info->lm_session_key.data, MIN(sizeof(lm_session_key.key), server_info->lm_session_key.length)); SamOEMhash(lm_session_key.key, pipe_session_key, 8); } groups.count = num_gids; groups.rids = TALLOC_ARRAY(sam3, struct samr_RidWithAttribute, groups.count); if (!groups.rids) { return NT_STATUS_NO_MEMORY; } for (i=0; i < groups.count; i++) { groups.rids[i].rid = gids[i].g_rid; groups.rids[i].attributes = gids[i].attr; } unix_to_nt_time(&last_logon, pdb_get_logon_time(sampw)); unix_to_nt_time(&last_logoff, get_time_t_max()); unix_to_nt_time(&acct_expiry, get_time_t_max()); unix_to_nt_time(&last_password_change, pdb_get_pass_last_set_time(sampw)); unix_to_nt_time(&allow_password_change, pdb_get_pass_can_change_time(sampw)); unix_to_nt_time(&force_password_change, pdb_get_pass_must_change_time(sampw)); init_netr_SamInfo3(sam3, last_logon, last_logoff, acct_expiry, last_password_change, allow_password_change, force_password_change, talloc_strdup(sam3, pdb_get_username(sampw)), talloc_strdup(sam3, pdb_get_fullname(sampw)), talloc_strdup(sam3, pdb_get_logon_script(sampw)), talloc_strdup(sam3, pdb_get_profile_path(sampw)), talloc_strdup(sam3, pdb_get_homedir(sampw)), talloc_strdup(sam3, pdb_get_dir_drive(sampw)), 0, /* logon_count */ 0, /* bad_password_count */ user_rid, group_rid, groups, NETLOGON_EXTRA_SIDS, user_session_key, my_name, talloc_strdup(sam3, pdb_get_domain(sampw)), sid, lm_session_key, pdb_get_acct_ctrl(sampw), 0, /* sidcount */ NULL); /* struct netr_SidAttr *sids */ ZERO_STRUCT(user_session_key); ZERO_STRUCT(lm_session_key); return NT_STATUS_OK; }
/* basic testing of all SMB2 setinfo calls for each call we test that it succeeds, and where possible test for consistency between the calls. */ BOOL torture_smb2_setinfo(struct torture_context *torture) { struct smb2_tree *tree; BOOL ret = True; TALLOC_CTX *mem_ctx = talloc_new(NULL); struct smb2_handle handle; char *fname; char *fname_new; union smb_fileinfo finfo2; union smb_setfileinfo sfinfo; struct security_ace ace; struct security_descriptor *sd; struct dom_sid *test_sid; NTSTATUS status, status2=NT_STATUS_OK; const char *call_name; time_t basetime = (time(NULL) - 86400) & ~1; int n = time(NULL) % 100; ZERO_STRUCT(handle); fname = talloc_asprintf(mem_ctx, BASEDIR "fnum_test_%d.txt", n); fname_new = talloc_asprintf(mem_ctx, BASEDIR "fnum_test_new_%d.txt", n); if (!torture_smb2_connection(mem_ctx, &tree)) { return False; } #define RECREATE_FILE(fname) do { \ smb2_util_close(tree, handle); \ status = smb2_create_complex_file(tree, fname, &handle); \ if (!NT_STATUS_IS_OK(status)) { \ printf("(%s) ERROR: open of %s failed (%s)\n", \ __location__, fname, nt_errstr(status)); \ ret = False; \ goto done; \ }} while (0) #define RECREATE_BOTH do { \ RECREATE_FILE(fname); \ } while (0) RECREATE_BOTH; #define CHECK_CALL(call, rightstatus) do { \ call_name = #call; \ sfinfo.generic.level = RAW_SFILEINFO_ ## call; \ sfinfo.generic.in.file.handle = handle; \ status = smb2_setinfo_file(tree, &sfinfo); \ if (!NT_STATUS_EQUAL(status, rightstatus)) { \ printf("(%s) %s - %s (should be %s)\n", __location__, #call, \ nt_errstr(status), nt_errstr(rightstatus)); \ ret = False; \ goto done; \ } \ } while (0) #define CHECK1(call) \ do { if (NT_STATUS_IS_OK(status)) { \ finfo2.generic.level = RAW_FILEINFO_ ## call; \ finfo2.generic.in.file.handle = handle; \ status2 = smb2_getinfo_file(tree, mem_ctx, &finfo2); \ if (!NT_STATUS_IS_OK(status2)) { \ printf("(%s) %s - %s\n", __location__, #call, nt_errstr(status2)); \ ret = False; \ goto done; \ } \ }} while (0) #define CHECK_VALUE(call, stype, field, value) do { \ CHECK1(call); \ if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && finfo2.stype.out.field != value) { \ printf("(%s) %s - %s/%s should be 0x%x - 0x%x\n", __location__, \ call_name, #stype, #field, \ (uint_t)value, (uint_t)finfo2.stype.out.field); \ torture_smb2_all_info(tree, handle); \ ret = False; \ goto done; \ }} while (0) #define CHECK_TIME(call, stype, field, value) do { \ CHECK1(call); \ if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(status2) && nt_time_to_unix(finfo2.stype.out.field) != value) { \ printf("(%s) %s - %s/%s should be 0x%x - 0x%x\n", __location__, \ call_name, #stype, #field, \ (uint_t)value, \ (uint_t)nt_time_to_unix(finfo2.stype.out.field)); \ printf("\t%s", timestring(mem_ctx, value)); \ printf("\t%s\n", nt_time_string(mem_ctx, finfo2.stype.out.field)); \ torture_smb2_all_info(tree, handle); \ ret = False; \ goto done; \ }} while (0) #define CHECK_STATUS(status, correct) do { \ if (!NT_STATUS_EQUAL(status, correct)) { \ printf("(%s) Incorrect status %s - should be %s\n", \ __location__, nt_errstr(status), nt_errstr(correct)); \ ret = False; \ goto done; \ }} while (0) torture_smb2_all_info(tree, handle); printf("test basic_information level\n"); basetime += 86400; unix_to_nt_time(&sfinfo.basic_info.in.create_time, basetime + 100); unix_to_nt_time(&sfinfo.basic_info.in.access_time, basetime + 200); unix_to_nt_time(&sfinfo.basic_info.in.write_time, basetime + 300); unix_to_nt_time(&sfinfo.basic_info.in.change_time, basetime + 400); sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_READONLY; CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK); CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, create_time, basetime + 100); CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, access_time, basetime + 200); CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, write_time, basetime + 300); CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, change_time, basetime + 400); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_READONLY); printf("a zero time means don't change\n"); unix_to_nt_time(&sfinfo.basic_info.in.create_time, 0); unix_to_nt_time(&sfinfo.basic_info.in.access_time, 0); unix_to_nt_time(&sfinfo.basic_info.in.write_time, 0); unix_to_nt_time(&sfinfo.basic_info.in.change_time, 0); sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL; CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK); CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, create_time, basetime + 100); CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, access_time, basetime + 200); CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, write_time, basetime + 300); CHECK_TIME(SMB2_ALL_INFORMATION, all_info2, change_time, basetime + 400); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_NORMAL); printf("change the attribute\n"); sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_HIDDEN; CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_HIDDEN); printf("zero attrib means don't change\n"); sfinfo.basic_info.in.attrib = 0; CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_HIDDEN); printf("restore attribute\n"); sfinfo.basic_info.in.attrib = FILE_ATTRIBUTE_NORMAL; CHECK_CALL(BASIC_INFORMATION, NT_STATUS_OK); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, attrib, FILE_ATTRIBUTE_NORMAL); printf("test disposition_information level\n"); sfinfo.disposition_info.in.delete_on_close = 1; CHECK_CALL(DISPOSITION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, delete_pending, 1); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, nlink, 0); sfinfo.disposition_info.in.delete_on_close = 0; CHECK_CALL(DISPOSITION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, delete_pending, 0); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, nlink, 1); printf("test allocation_information level\n"); sfinfo.allocation_info.in.alloc_size = 0; CHECK_CALL(ALLOCATION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 0); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, alloc_size, 0); sfinfo.allocation_info.in.alloc_size = 4096; CHECK_CALL(ALLOCATION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, alloc_size, 4096); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 0); printf("test end_of_file_info level\n"); sfinfo.end_of_file_info.in.size = 37; CHECK_CALL(END_OF_FILE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 37); sfinfo.end_of_file_info.in.size = 7; CHECK_CALL(END_OF_FILE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, size, 7); printf("test position_information level\n"); sfinfo.position_information.in.position = 123456; CHECK_CALL(POSITION_INFORMATION, NT_STATUS_OK); CHECK_VALUE(POSITION_INFORMATION, position_information, position, 123456); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, position, 123456); printf("test mode_information level\n"); sfinfo.mode_information.in.mode = 2; CHECK_CALL(MODE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 2); CHECK_VALUE(SMB2_ALL_INFORMATION, all_info2, mode, 2); sfinfo.mode_information.in.mode = 1; CHECK_CALL(MODE_INFORMATION, NT_STATUS_INVALID_PARAMETER); sfinfo.mode_information.in.mode = 0; CHECK_CALL(MODE_INFORMATION, NT_STATUS_OK); CHECK_VALUE(MODE_INFORMATION, mode_information, mode, 0); printf("test sec_desc level\n"); ZERO_STRUCT(finfo2); finfo2.query_secdesc.in.secinfo_flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL; CHECK1(SEC_DESC); sd = finfo2.query_secdesc.out.sd; test_sid = dom_sid_parse_talloc(mem_ctx, "S-1-5-32-1234-5432"); ZERO_STRUCT(ace); ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED; ace.flags = 0; ace.access_mask = SEC_STD_ALL; ace.trustee = *test_sid; status = security_descriptor_dacl_add(sd, &ace); CHECK_STATUS(status, NT_STATUS_OK); printf("add a new ACE to the DACL\n"); sfinfo.set_secdesc.in.secinfo_flags = finfo2.query_secdesc.in.secinfo_flags; sfinfo.set_secdesc.in.sd = sd; CHECK_CALL(SEC_DESC, NT_STATUS_OK); CHECK1(SEC_DESC); if (!security_acl_equal(finfo2.query_secdesc.out.sd->dacl, sd->dacl)) { printf("%s: security descriptors don't match!\n", __location__); printf("got:\n"); NDR_PRINT_DEBUG(security_descriptor, finfo2.query_secdesc.out.sd); printf("expected:\n"); NDR_PRINT_DEBUG(security_descriptor, sd); ret = False; } printf("remove it again\n"); status = security_descriptor_dacl_del(sd, test_sid); CHECK_STATUS(status, NT_STATUS_OK); sfinfo.set_secdesc.in.secinfo_flags = finfo2.query_secdesc.in.secinfo_flags; sfinfo.set_secdesc.in.sd = sd; CHECK_CALL(SEC_DESC, NT_STATUS_OK); CHECK1(SEC_DESC); if (!security_acl_equal(finfo2.query_secdesc.out.sd->dacl, sd->dacl)) { printf("%s: security descriptors don't match!\n", __location__); printf("got:\n"); NDR_PRINT_DEBUG(security_descriptor, finfo2.query_secdesc.out.sd); printf("expected:\n"); NDR_PRINT_DEBUG(security_descriptor, sd); ret = False; } done: status = smb2_util_close(tree, handle); if (NT_STATUS_IS_ERR(status)) { printf("Failed to delete %s - %s\n", fname, nt_errstr(status)); } smb2_util_unlink(tree, fname); talloc_free(mem_ctx); return ret; }
/* continue a search */ static NTSTATUS svfs_search_next(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_search_next *io, void *search_private, bool (*callback)(void *, const union smb_search_data *)) { struct svfs_dir *dir; int i; struct svfs_private *p = ntvfs->private_data; struct search_state *search; union smb_search_data file; unsigned int max_count; if (io->generic.level != RAW_SEARCH_TRANS2) { return NT_STATUS_NOT_SUPPORTED; } if (io->generic.data_level != RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO) { return NT_STATUS_NOT_SUPPORTED; } for (search=p->search; search; search = search->next) { if (search->handle == io->t2fnext.in.handle) break; } if (!search) { /* we didn't find the search handle */ return NT_STATUS_FOOBAR; } dir = search->dir; /* the client might be asking for something other than just continuing with the search */ if (!(io->t2fnext.in.flags & FLAG_TRANS2_FIND_CONTINUE) && (io->t2fnext.in.flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) && io->t2fnext.in.last_name && *io->t2fnext.in.last_name) { /* look backwards first */ for (i=search->current_index; i > 0; i--) { if (strcmp(io->t2fnext.in.last_name, dir->files[i-1].name) == 0) { search->current_index = i; goto found; } } /* then look forwards */ for (i=search->current_index+1; i <= dir->count; i++) { if (strcmp(io->t2fnext.in.last_name, dir->files[i-1].name) == 0) { search->current_index = i; goto found; } } } found: max_count = search->current_index + io->t2fnext.in.max_count; if (max_count > dir->count) { max_count = dir->count; } for (i = search->current_index; i < max_count;i++) { ZERO_STRUCT(file); unix_to_nt_time(&file.both_directory_info.create_time, dir->files[i].st.st_ctime); unix_to_nt_time(&file.both_directory_info.access_time, dir->files[i].st.st_atime); unix_to_nt_time(&file.both_directory_info.write_time, dir->files[i].st.st_mtime); unix_to_nt_time(&file.both_directory_info.change_time, dir->files[i].st.st_mtime); file.both_directory_info.name.s = dir->files[i].name; file.both_directory_info.short_name.s = dir->files[i].name; file.both_directory_info.size = dir->files[i].st.st_size; file.both_directory_info.attrib = svfs_unix_to_dos_attrib(dir->files[i].st.st_mode); if (!callback(search_private, &file)) { break; } } io->t2fnext.out.count = i - search->current_index; io->t2fnext.out.end_of_search = (i == dir->count) ? 1 : 0; search->current_index = i; /* work out if we are going to keep the search state */ if ((io->t2fnext.in.flags & FLAG_TRANS2_FIND_CLOSE) || ((io->t2fnext.in.flags & FLAG_TRANS2_FIND_CLOSE_IF_END) && (i == dir->count))) { DLIST_REMOVE(p->search, search); talloc_free(search); } return NT_STATUS_OK; }
struct netr_SamInfo3 *wbcAuthUserInfo_to_netr_SamInfo3(TALLOC_CTX *mem_ctx, const struct wbcAuthUserInfo *info) { struct netr_SamInfo3 *info3; struct dom_sid user_sid; struct dom_sid group_sid; struct dom_sid domain_sid; NTSTATUS status; bool ok; memcpy(&user_sid, &info->sids[0].sid, sizeof(user_sid)); memcpy(&group_sid, &info->sids[1].sid, sizeof(group_sid)); info3 = talloc_zero(mem_ctx, struct netr_SamInfo3); if (!info3) return NULL; unix_to_nt_time(&info3->base.logon_time, info->logon_time); unix_to_nt_time(&info3->base.logoff_time, info->logoff_time); unix_to_nt_time(&info3->base.kickoff_time, info->kickoff_time); unix_to_nt_time(&info3->base.last_password_change, info->pass_last_set_time); unix_to_nt_time(&info3->base.allow_password_change, info->pass_can_change_time); unix_to_nt_time(&info3->base.force_password_change, info->pass_must_change_time); if (info->account_name) { info3->base.account_name.string = talloc_strdup(info3, info->account_name); RET_NOMEM(info3->base.account_name.string); } if (info->full_name) { info3->base.full_name.string = talloc_strdup(info3, info->full_name); RET_NOMEM(info3->base.full_name.string); } if (info->logon_script) { info3->base.logon_script.string = talloc_strdup(info3, info->logon_script); RET_NOMEM(info3->base.logon_script.string); } if (info->profile_path) { info3->base.profile_path.string = talloc_strdup(info3, info->profile_path); RET_NOMEM(info3->base.profile_path.string); } if (info->home_directory) { info3->base.home_directory.string = talloc_strdup(info3, info->home_directory); RET_NOMEM(info3->base.home_directory.string); } if (info->home_drive) { info3->base.home_drive.string = talloc_strdup(info3, info->home_drive); RET_NOMEM(info3->base.home_drive.string); } info3->base.logon_count = info->logon_count; info3->base.bad_password_count = info->bad_password_count; sid_copy(&domain_sid, &user_sid); sid_split_rid(&domain_sid, &info3->base.rid); ok = sid_peek_check_rid(&domain_sid, &group_sid, &info3->base.primary_gid); if (!ok) { DEBUG(1, ("The primary group sid domain does not" "match user sid domain for user: %s\n", info->account_name)); TALLOC_FREE(info3); return NULL; } status = wbcsids_to_samr_RidWithAttributeArray(info3, &info3->base.groups, &domain_sid, &info->sids[1], info->num_sids - 1); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(info3); return NULL; } status = wbcsids_to_netr_SidAttrArray(&domain_sid, &info->sids[1], info->num_sids - 1, info3, &info3->sids, &info3->sidcount); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(info3); return NULL; } info3->base.user_flags = info->user_flags; memcpy(info3->base.key.key, info->user_session_key, 16); if (info->logon_server) { info3->base.logon_server.string = talloc_strdup(info3, info->logon_server); RET_NOMEM(info3->base.logon_server.string); } if (info->domain_name) { info3->base.logon_domain.string = talloc_strdup(info3, info->domain_name); RET_NOMEM(info3->base.logon_domain.string); } info3->base.domain_sid = dom_sid_dup(info3, &domain_sid); RET_NOMEM(info3->base.domain_sid); memcpy(info3->base.LMSessKey.key, info->lm_session_key, 8); info3->base.acct_flags = info->acct_flags; return info3; }