From ef2e26c91b80556af033d3335e55f5dfa6fff31d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 13 Aug 2003 01:53:07 +0000 Subject: first public release of samba4 code (This used to be commit b0510b5428b3461aeb9bbe3cc95f62fc73e2b97f) --- source4/sam/sam_ads.c | 1378 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1378 insertions(+) create mode 100755 source4/sam/sam_ads.c (limited to 'source4/sam/sam_ads.c') diff --git a/source4/sam/sam_ads.c b/source4/sam/sam_ads.c new file mode 100755 index 0000000000..13e0369004 --- /dev/null +++ b/source4/sam/sam_ads.c @@ -0,0 +1,1378 @@ +/* + Unix SMB/CIFS implementation. + Active Directory SAM backend, for simulate a W2K DC in mixed mode. + + Copyright (C) Stefan (metze) Metzmacher 2002 + Copyright (C) Andrew Bartlett 2002 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + + +#ifdef HAVE_LDAP + +static int sam_ads_debug_level = DBGC_SAM; + +#undef DBGC_CLASS +#define DBGC_CLASS sam_ads_debug_level + +#ifndef FIXME +#define FIXME( body ) { DEBUG(0,("FIXME: "));\ + DEBUGADD(0,(body));} +#endif + +#define ADS_STATUS_OK ADS_ERROR(0) +#define ADS_STATUS_UNSUCCESSFUL ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL) +#define ADS_STATUS_NOT_IMPLEMENTED ADS_ERROR_NT(NT_STATUS_NOT_IMPLEMENTED) + + +#define ADS_SUBTREE_BUILTIN "CN=Builtin," +#define ADS_SUBTREE_COMPUTERS "CN=Computers," +#define ADS_SUBTREE_DC "CN=Domain Controllers," +#define ADS_SUBTREE_USERS "CN=Users," +#define ADS_ROOT_TREE "" +/* Here are private module structs and functions */ + +typedef struct sam_ads_privates { + ADS_STRUCT *ads_struct; + TALLOC_CTX *mem_ctx; + BOOL bind_plaintext; + char *ads_bind_dn; + char *ads_bind_pw; + char *ldap_uri; + /* did we need something more? */ +}SAM_ADS_PRIVATES; + + +/* get only these LDAP attributes, witch we really need for an account */ +const char *account_attrs[] = { "objectSid", + "objectGUID", + "sAMAccountType", + "sAMAcountName", + "userPrincipalName", + "accountExpires", + "badPasswordTime", + "badPwdCount", + "lastLogoff", + "lastLogon", + "userWorkstations", + "dBCSPwd", + "unicodePwd", + "pwdLastSet", + "userAccountControl", + "profilePath", + "homeDrive", + "scriptPath", + "homeDirectory", + "cn", + "primaryGroupID",/* 513 */ + "nsNPAllowDialIn",/* TRUE */ + "userParameters",/* Dial Back number ...*/ + "codePage",/* 0 */ + "countryCode",/* 0 */ + "adminCount",/* 1 or 0 */ + "logonCount",/* 0 */ + "managedObjects", + "memberOf",/* dn */ + "instanceType",/* 4 */ + "name", /* sync with cn */ + "description", + /* "nTSecurityDescriptor", */ + NULL}; + +/* get only these LDAP attributes, witch we really need for a group */ +const char *group_attrs[] = {"objectSid", + /* "objectGUID", */ + "sAMAccountType", + "sAMAcountName", + "groupType", + /* "member", */ + "description", + "name", /* sync with cn */ + /* "nTSecurityDescriptor", */ + NULL}; + + +/*************************************************** + return our ads connection. We keep the connection + open to make things faster +****************************************************/ +static ADS_STATUS sam_ads_cached_connection(SAM_ADS_PRIVATES *privates) +{ + ADS_STRUCT *ads_struct; + ADS_STATUS ads_status; + + if (!privates->ads_struct) { + privates->ads_struct = ads_init_simple(); + ads_struct = privates->ads_struct; + ads_struct->server.ldap_uri = smb_xstrdup(privates->ldap_uri); + if ((!privates->ads_bind_dn) || (!*privates->ads_bind_dn)) { + ads_struct->auth.flags |= ADS_AUTH_ANON_BIND; + } else { + ads_struct->auth.user_name + = smb_xstrdup(privates->ads_bind_dn); + if (privates->ads_bind_pw) { + ads_struct->auth.password + = smb_xstrdup(privates->ads_bind_pw); + } + } + if (privates->bind_plaintext) { + ads_struct->auth.flags |= ADS_AUTH_SIMPLE_BIND; + } + } else { + ads_struct = privates->ads_struct; + } + + if (ads_struct->ld != NULL) { + /* connection has been opened. ping server. */ + struct sockaddr_un addr; + socklen_t len; + int sd; + if (ldap_get_option(ads_struct->ld, LDAP_OPT_DESC, &sd) == 0 && + getpeername(sd, (struct sockaddr *) &addr, &len) < 0) { + /* the other end has died. reopen. */ + ldap_unbind_ext(ads_struct->ld, NULL, NULL); + ads_struct->ld = NULL; + } + } + + if (ads_struct->ld != NULL) { + DEBUG(5,("sam_ads_cached_connection: allready connected to the LDAP server\n")); + return ADS_SUCCESS; + } + + ads_status = ads_connect(ads_struct); + + ads_status = ads_server_info(ads_struct); + if (!ADS_ERR_OK(ads_status)) { + DEBUG(0,("Can't set server info: %s\n",ads_errstr(ads_status))); + /* return ads_status; */ FIXME("for now we only warn!\n"); + } + + DEBUG(2, ("sam_ads_cached_connection: succesful connection to the LDAP server\n")); + return ADS_SUCCESS; +} + +static ADS_STATUS sam_ads_do_search(SAM_ADS_PRIVATES *privates, const char *bind_path, int scope, const char *exp, const char **attrs, void **res) +{ + ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); + + ads_status = sam_ads_cached_connection(privates); + if (!ADS_ERR_OK(ads_status)) + return ads_status; + + return ads_do_search_retry(privates->ads_struct, bind_path, scope, exp, attrs, res); +} + + +/********************************************* +here we have to check the update serial number + - this is the core of the ldap cache +*********************************************/ +static ADS_STATUS sam_ads_usn_is_valid(SAM_ADS_PRIVATES *privates, uint32 usn_in, uint32 *usn_out) +{ + ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); + + SAM_ASSERT(privates && privates->ads_struct && usn_out); + + ads_status = ads_USN(privates->ads_struct, usn_out); + if (!ADS_ERR_OK(ads_status)) + return ads_status; + + if (*usn_out == usn_in) + return ADS_SUCCESS; + + return ads_status; +} + +/*********************************************** +Initialize SAM_ACCOUNT_HANDLE from an ADS query +************************************************/ +/* not ready :-( */ +static ADS_STATUS ads_entry2sam_account_handle(SAM_ADS_PRIVATES *privates, SAM_ACCOUNT_HANDLE *account ,void *msg) +{ + ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_NO_SUCH_USER); + NTSTATUS nt_status = NT_STATUS_NO_SUCH_USER; + ADS_STRUCT *ads_struct = privates->ads_struct; + TALLOC_CTX *mem_ctx = account->mem_ctx; + char *tmp_str = NULL; + + SAM_ASSERT(privates && ads_struct && account && mem_ctx && msg); + + FIXME("should we really use ads_pull_username()(or ads_pull_string())?\n"); + if ((account->private.account_name = ads_pull_username(ads_struct, mem_ctx, msg))==NULL) { + DEBUG(0,("ads_pull_username failed\n")); + return ADS_ERROR_NT(NT_STATUS_NO_SUCH_USER); + } + + if ((account->private.full_name = ads_pull_string(ads_struct, mem_ctx, msg,"name"))==NULL) { + DEBUG(3,("ads_pull_string for 'name' failed - skip\n")); + } + + if ((account->private.acct_desc = ads_pull_string(ads_struct, mem_ctx, msg,"description"))!=NULL) { + DEBUG(3,("ads_pull_string for 'acct_desc' failed - skip\n")); + } + + if ((account->private.home_dir = ads_pull_string(ads_struct, mem_ctx, msg,"homeDirectory"))!=NULL) { + DEBUG(3,("ads_pull_string for 'homeDirectory' failed - skip\n")); + } + + if ((account->private.dir_drive = ads_pull_string(ads_struct, mem_ctx, msg,"homeDrive"))!=NULL) { + DEBUG(3,("ads_pull_string for 'homeDrive' failed - skip\n")); + } + + if ((account->private.profile_path = ads_pull_string(ads_struct, mem_ctx, msg,"profilePath"))!=NULL) { + DEBUG(3,("ads_pull_string for 'profilePath' failed - skip\n")); + } + + if ((account->private.logon_script = ads_pull_string(ads_struct, mem_ctx, msg,"scriptPath"))!=NULL) { + DEBUG(3,("ads_pull_string for 'scriptPath' failed - skip\n")); + } + + FIXME("check 'nsNPAllowDialIn' for munged_dial!\n"); + if ((account->private.munged_dial = ads_pull_string(ads_struct, mem_ctx, msg,"userParameters"))!=NULL) { + DEBUG(3,("ads_pull_string for 'userParameters' failed - skip\n")); + } + + if ((account->private.unix_home_dir = ads_pull_string(ads_struct, mem_ctx, msg,"msSFUHomeDrirectory"))!=NULL) { + DEBUG(3,("ads_pull_string for 'msSFUHomeDrirectory' failed - skip\n")); + } + +#if 0 + FIXME("use function intern mem_ctx for pwdLastSet\n"); + if ((tmp_str = ads_pull_string(ads_struct, mem_ctx, msg,"pwdLastSet"))!=NULL) { + DEBUG(3,("ads_pull_string for 'pwdLastSet' failed - skip\n")); + } else { + account->private.pass_last_set_time = ads_parse_nttime(tmp_str); + tmp_str = NULL; + + } +#endif + +#if 0 +typedef struct sam_account_handle { + TALLOC_CTX *mem_ctx; + uint32 access_granted; + const struct sam_methods *current_sam_methods; /* sam_methods creating this handle */ + void (*free_fn)(struct sam_account_handle **); + struct sam_account_data { + uint32 init_flag; + NTTIME logon_time; /* logon time */ + NTTIME logoff_time; /* logoff time */ + NTTIME kickoff_time; /* kickoff time */ + NTTIME pass_last_set_time; /* password last set time */ + NTTIME pass_can_change_time; /* password can change time */ + NTTIME pass_must_change_time; /* password must change time */ + char * account_name; /* account_name string */ + SAM_DOMAIN_HANDLE * domain; /* domain of account */ + char *full_name; /* account's full name string */ + char *unix_home_dir; /* UNIX home directory string */ + char *home_dir; /* home directory string */ + char *dir_drive; /* home directory drive string */ + char *logon_script; /* logon script string */ + char *profile_path; /* profile path string */ + char *acct_desc; /* account description string */ + char *workstations; /* login from workstations string */ + char *unknown_str; /* don't know what this is, yet. */ + char *munged_dial; /* munged path name and dial-back tel number */ + DOM_SID account_sid; /* Primary Account SID */ + DOM_SID group_sid; /* Primary Group SID */ + DATA_BLOB lm_pw; /* .data is Null if no password */ + DATA_BLOB nt_pw; /* .data is Null if no password */ + char *plaintext_pw; /* if Null not available */ + uint16 acct_ctrl; /* account info (ACB_xxxx bit-mask) */ + uint32 unknown_1; /* 0x00ff ffff */ + uint16 logon_divs; /* 168 - number of hours in a week */ + uint32 hours_len; /* normally 21 bytes */ + uint8 hours[MAX_HOURS_LEN]; + uint32 unknown_2; /* 0x0002 0000 */ + uint32 unknown_3; /* 0x0000 04ec */ + } private; +} SAM_ACCOUNT_HANDLE; +#endif + + return ads_status; +} + + +/*********************************************** +Initialize SAM_GROUP_ENUM from an ads entry +************************************************/ +/* not ready :-( */ +static ADS_STATUS ads_entry2sam_group_enum(SAM_ADS_PRIVATES *privates, TALLOC_CTX *mem_ctx, SAM_GROUP_ENUM **group_enum,const void *entry) +{ + ADS_STATUS ads_status = ADS_STATUS_UNSUCCESSFUL; + ADS_STRUCT *ads_struct = privates->ads_struct; + SAM_GROUP_ENUM __group_enum; + SAM_GROUP_ENUM *_group_enum = &__group_enum; + + SAM_ASSERT(privates && ads_struct && mem_ctx && group_enum && entry); + + *group_enum = _group_enum; + + DEBUG(3,("sam_ads: ads_entry2sam_account_handle\n")); + + if (!ads_pull_sid(ads_struct, &entry, "objectSid", &(_group_enum->sid))) { + DEBUG(0,("No sid for!?\n")); + return ADS_STATUS_UNSUCCESSFUL; + } + + if (!(_group_enum->group_name = ads_pull_string(ads_struct, mem_ctx, &entry, "sAMAccountName"))) { + DEBUG(0,("No groupname found")); + return ADS_STATUS_UNSUCCESSFUL; + } + + if (!(_group_enum->group_desc = ads_pull_string(ads_struct, mem_ctx, &entry, "desciption"))) { + DEBUG(0,("No description found")); + return ADS_STATUS_UNSUCCESSFUL; + } + + DEBUG(0,("sAMAccountName: %s\ndescription: %s\nobjectSid: %s\n", + _group_enum->group_name, + _group_enum->group_desc, + sid_string_static(&(_group_enum->sid)) + )); + + return ads_status; +} + +static ADS_STATUS sam_ads_access_check(SAM_ADS_PRIVATES *privates, const SEC_DESC *sd, const NT_USER_TOKEN *access_token, uint32 access_desired, uint32 *acc_granted) +{ + ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED); + NTSTATUS nt_status; + uint32 my_acc_granted; + + SAM_ASSERT(privates && sd && access_token); + /* acc_granted can be set to NULL */ + + /* the steps you need are: + 1. get_sec_desc for sid + 2. se_map_generic(accessdesired, generic_mapping) + 3. se_access_check() */ + + if (!se_access_check(sd, access_token, access_desired, (acc_granted)?acc_granted:&my_acc_granted, &nt_status)) { + DEBUG(3,("sam_ads_access_check: ACCESS DENIED\n")); + ads_status = ADS_ERROR_NT(nt_status); + return ads_status; + } + ads_status = ADS_ERROR_NT(nt_status); + return ads_status; +} + +static ADS_STATUS sam_ads_get_tree_sec_desc(SAM_ADS_PRIVATES *privates, const char *subtree, SEC_DESC **sd) +{ + ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER); + ADS_STRUCT *ads_struct = privates->ads_struct; + TALLOC_CTX *mem_ctx = privates->mem_ctx; + char *search_path; + void *sec_desc_res; + void *sec_desc_msg; + const char *sec_desc_attrs[] = {"nTSecurityDescriptor",NULL}; + + SAM_ASSERT(privates && ads_struct && mem_ctx && sd); + *sd = NULL; + + if (subtree) { + asprintf(&search_path, "%s%s",subtree,ads_struct->config.bind_path); + } else { + asprintf(&search_path, "%s",""); + } + ads_status = sam_ads_do_search(privates, search_path, LDAP_SCOPE_BASE, "(objectClass=*)", sec_desc_attrs, &sec_desc_res); + SAFE_FREE(search_path); + if (!ADS_ERR_OK(ads_status)) + return ads_status; + + if ((sec_desc_msg = ads_first_entry(ads_struct, sec_desc_res))==NULL) { + ads_status = ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER); + return ads_status; + } + + if (!ads_pull_sd(ads_struct, mem_ctx, sec_desc_msg, sec_desc_attrs[0], sd)) { + *sd = NULL; + ads_status = ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER); + return ads_status; + } + + return ads_status; +} + +static ADS_STATUS sam_ads_account_policy_get(SAM_ADS_PRIVATES *privates, int field, uint32 *value) +{ + ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER); + ADS_STRUCT *ads_struct = privates->ads_struct; + void *ap_res; + void *ap_msg; + const char *ap_attrs[] = {"minPwdLength",/* AP_MIN_PASSWORD_LEN */ + "pwdHistoryLength",/* AP_PASSWORD_HISTORY */ + "AP_USER_MUST_LOGON_TO_CHG_PASS",/* AP_USER_MUST_LOGON_TO_CHG_PASS */ + "maxPwdAge",/* AP_MAX_PASSWORD_AGE */ + "minPwdAge",/* AP_MIN_PASSWORD_AGE */ + "lockoutDuration",/* AP_LOCK_ACCOUNT_DURATION */ + "AP_RESET_COUNT_TIME",/* AP_RESET_COUNT_TIME */ + "AP_BAD_ATTEMPT_LOCKOUT",/* AP_BAD_ATTEMPT_LOCKOUT */ + "AP_TIME_TO_LOGOUT",/* AP_TIME_TO_LOGOUT */ + NULL}; + /*lockOutObservationWindow + lockoutThreshold $ pwdProperties*/ + static uint32 ap[9]; + static uint32 ap_usn = 0; + uint32 tmp_usn = 0; + + SAM_ASSERT(privates && ads_struct && value); + + FIXME("We need to decode all account_policy attributes!\n"); + + ads_status = sam_ads_usn_is_valid(privates,ap_usn,&tmp_usn); + if (!ADS_ERR_OK(ads_status)) { + ads_status = sam_ads_do_search(privates, ads_struct->config.bind_path, LDAP_SCOPE_BASE, "(objectClass=*)", ap_attrs, &ap_res); + if (!ADS_ERR_OK(ads_status)) + return ads_status; + + if (ads_count_replies(ads_struct, ap_res) != 1) { + ads_msgfree(ads_struct, ap_res); + return ADS_ERROR(LDAP_NO_RESULTS_RETURNED); + } + + if (!(ap_msg = ads_first_entry(ads_struct, ap_res))) { + ads_msgfree(ads_struct, ap_res); + return ADS_ERROR(LDAP_NO_RESULTS_RETURNED); + } + + if (!ads_pull_uint32(ads_struct, ap_msg, ap_attrs[0], &ap[0])) { + /* AP_MIN_PASSWORD_LEN */ + ap[0] = MINPASSWDLENGTH;/* 5 chars minimum */ + } + if (!ads_pull_uint32(ads_struct, ap_msg, ap_attrs[1], &ap[1])) { + /* AP_PASSWORD_HISTORY */ + ap[1] = 0;/* don't keep any old password */ + } + if (!ads_pull_uint32(ads_struct, ap_msg, ap_attrs[2], &ap[2])) { + /* AP_USER_MUST_LOGON_TO_CHG_PASS */ + ap[2] = 0;/* don't force user to logon */ + } + if (!ads_pull_uint32(ads_struct, ap_msg, ap_attrs[3], &ap[3])) { + /* AP_MAX_PASSWORD_AGE */ + ap[3] = MAX_PASSWORD_AGE;/* 21 days */ + } + if (!ads_pull_uint32(ads_struct, ap_msg, ap_attrs[4], &ap[4])) { + /* AP_MIN_PASSWORD_AGE */ + ap[4] = 0;/* 0 days */ + } + if (!ads_pull_uint32(ads_struct, ap_msg, ap_attrs[5], &ap[5])) { + /* AP_LOCK_ACCOUNT_DURATION */ + ap[5] = 0;/* lockout for 0 minutes */ + } + if (!ads_pull_uint32(ads_struct, ap_msg, ap_attrs[6], &ap[6])) { + /* AP_RESET_COUNT_TIME */ + ap[6] = 0;/* reset immediatly */ + } + if (!ads_pull_uint32(ads_struct, ap_msg, ap_attrs[7], &ap[7])) { + /* AP_BAD_ATTEMPT_LOCKOUT */ + ap[7] = 0;/* don't lockout */ + } + if (!ads_pull_uint32(ads_struct, ap_msg, ap_attrs[8], &ap[8])) { + /* AP_TIME_TO_LOGOUT */ + ap[8] = -1;/* don't force logout */ + } + + ads_msgfree(ads_struct, ap_res); + ap_usn = tmp_usn; + } + + switch(field) { + case AP_MIN_PASSWORD_LEN: + *value = ap[0]; + ads_status = ADS_ERROR_NT(NT_STATUS_OK); + break; + case AP_PASSWORD_HISTORY: + *value = ap[1]; + ads_status = ADS_ERROR_NT(NT_STATUS_OK); + break; + case AP_USER_MUST_LOGON_TO_CHG_PASS: + *value = ap[2]; + ads_status = ADS_ERROR_NT(NT_STATUS_OK); + break; + case AP_MAX_PASSWORD_AGE: + *value = ap[3]; + ads_status = ADS_ERROR_NT(NT_STATUS_OK); + break; + case AP_MIN_PASSWORD_AGE: + *value = ap[4]; + ads_status = ADS_ERROR_NT(NT_STATUS_OK); + break; + case AP_LOCK_ACCOUNT_DURATION: + *value = ap[5]; + ads_status = ADS_ERROR_NT(NT_STATUS_OK); + break; + case AP_RESET_COUNT_TIME: + *value = ap[6]; + ads_status = ADS_ERROR_NT(NT_STATUS_OK); + break; + case AP_BAD_ATTEMPT_LOCKOUT: + *value = ap[7]; + ads_status = ADS_ERROR_NT(NT_STATUS_OK); + break; + case AP_TIME_TO_LOGOUT: + *value = ap[8]; + ads_status = ADS_ERROR_NT(NT_STATUS_OK); + break; + default: *value = 0; break; + } + + return ads_status; +} + + +/********************************** +Now the functions off the SAM API +***********************************/ + +/* General API */ +static NTSTATUS sam_ads_get_sec_desc(const SAM_METHODS *sam_method, const NT_USER_TOKEN *access_token, + const DOM_SID *sid, SEC_DESC **sd) +{ + ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); + SAM_ADS_PRIVATES *privates = (struct sam_ads_privates *)sam_method->private_data; + ADS_STRUCT *ads_struct = privates->ads_struct; + TALLOC_CTX *mem_ctx; + char *sidstr,*filter; + void *sec_desc_res; + void *sec_desc_msg; + const char *sec_desc_attrs[] = {"nTSecurityDescriptor",NULL}; + fstring sid_str; + SEC_DESC *my_sd; + + SAM_ASSERT(sam_method && access_token && sid && sd); + + ads_status = sam_ads_get_tree_sec_desc(privates, ADS_ROOT_TREE, &my_sd); + if (!ADS_ERR_OK(ads_status)) + return ads_ntstatus(ads_status); + + ads_status = sam_ads_access_check(privates, my_sd, access_token, GENERIC_RIGHTS_DOMAIN_READ, NULL); + + if (!ADS_ERR_OK(ads_status)) + return ads_ntstatus(ads_status); + + sidstr = sid_binstring(sid); + if (asprintf(&filter, "(objectSid=%s)", sidstr) == -1) { + SAFE_FREE(sidstr); + return NT_STATUS_NO_MEMORY; + } + + SAFE_FREE(sidstr); + + ads_status = sam_ads_do_search(privates,ads_struct->config.bind_path, + LDAP_SCOPE_SUBTREE, filter, sec_desc_attrs, + &sec_desc_res); + SAFE_FREE(filter); + + if (!ADS_ERR_OK(ads_status)) { + return ads_ntstatus(ads_status); + } + + if (!(mem_ctx = talloc_init("sec_desc parse in sam_ads"))) { + DEBUG(1, ("talloc_init() failed for sec_desc parse context in sam_ads")); + ads_msgfree(ads_struct, sec_desc_res); + return NT_STATUS_NO_MEMORY; + } + + if (ads_count_replies(ads_struct, sec_desc_res) != 1) { + DEBUG(1,("sam_ads_get_sec_desc: duplicate or 0 results for sid %s\n", + sid_to_string(sid_str, sid))); + talloc_destroy(mem_ctx); + ads_msgfree(ads_struct, sec_desc_res); + return NT_STATUS_UNSUCCESSFUL; + } + + if (!(sec_desc_msg = ads_first_entry(ads_struct, sec_desc_res))) { + talloc_destroy(mem_ctx); + ads_msgfree(ads_struct, sec_desc_res); + return NT_STATUS_INVALID_PARAMETER; + } + + if (!ads_pull_sd(ads_struct, mem_ctx, sec_desc_msg, sec_desc_attrs[0], sd)) { + ads_status = ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER); + talloc_destroy(mem_ctx); + ads_msgfree(ads_struct, sec_desc_res); + return ads_ntstatus(ads_status); + } + + /* now, were we allowed to see the SD we just got? */ + + ads_msgfree(ads_struct, sec_desc_res); + talloc_destroy(mem_ctx); + return ads_ntstatus(ads_status); +} + +static NTSTATUS sam_ads_set_sec_desc(const SAM_METHODS *sam_method, const NT_USER_TOKEN *access_token, + const DOM_SID *sid, const SEC_DESC *sd) +{ + ADS_STATUS ads_status = ADS_STATUS_NOT_IMPLEMENTED; + DEBUG(0,("sam_ads: %s was called!\n",FUNCTION_MACRO)); + SAM_ASSERT(sam_method); + return ads_ntstatus(ads_status); +} + + +static NTSTATUS sam_ads_lookup_sid(const SAM_METHODS *sam_method, const NT_USER_TOKEN *access_token, + TALLOC_CTX *mem_ctx, const DOM_SID *sid, char **name, + enum SID_NAME_USE *type) +{ + ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); + SAM_ADS_PRIVATES *privates = (struct sam_ads_privates *)sam_method->private_data; + ADS_STRUCT *ads_struct = privates->ads_struct; + SEC_DESC *my_sd; + + SAM_ASSERT(sam_method && access_token && mem_ctx && sid && name && type); + + ads_status = sam_ads_get_tree_sec_desc(privates, ADS_ROOT_TREE, &my_sd); + if (!ADS_ERR_OK(ads_status)) + return ads_ntstatus(ads_status); + + ads_status = sam_ads_access_check(privates, my_sd, access_token, GENERIC_RIGHTS_DOMAIN_READ, NULL); + if (!ADS_ERR_OK(ads_status)) + return ads_ntstatus(ads_status); + + return ads_sid_to_name(ads_struct, mem_ctx, sid, name, type); +} + +static NTSTATUS sam_ads_lookup_name(const SAM_METHODS *sam_method, const NT_USER_TOKEN *access_token, + const char *name, DOM_SID *sid, enum SID_NAME_USE *type) +{ + ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); + SAM_ADS_PRIVATES *privates = (struct sam_ads_privates *)sam_method->private_data; + ADS_STRUCT *ads_struct = privates->ads_struct; + SEC_DESC *my_sd; + + SAM_ASSERT(sam_method && access_token && name && sid && type); + + ads_status = sam_ads_get_tree_sec_desc(privates, ADS_ROOT_TREE, &my_sd); + if (!ADS_ERR_OK(ads_status)) + return ads_ntstatus(ads_status); + + ads_status = sam_ads_access_check(privates, my_sd, access_token, GENERIC_RIGHTS_DOMAIN_READ, NULL); + if (!ADS_ERR_OK(ads_status)) + return ads_ntstatus(ads_status); + + return ads_name_to_sid(ads_struct, name, sid, type); +} + + +/* Domain API */ + +static NTSTATUS sam_ads_update_domain(const SAM_METHODS *sam_method, const SAM_DOMAIN_HANDLE *domain) +{ + ADS_STATUS ads_status = ADS_STATUS_NOT_IMPLEMENTED; + DEBUG(0,("sam_ads: %s was called!\n",FUNCTION_MACRO)); + SAM_ASSERT(sam_method); + return ads_ntstatus(ads_status); +} + +static NTSTATUS sam_ads_get_domain_handle(const SAM_METHODS *sam_method, const NT_USER_TOKEN *access_token, + const uint32 access_desired, SAM_DOMAIN_HANDLE **domain) +{ + ADS_STATUS ads_status = ADS_STATUS_NOT_IMPLEMENTED; + SAM_ADS_PRIVATES *privates = (struct sam_ads_privates *)sam_method->private_data; + TALLOC_CTX *mem_ctx = privates->mem_ctx; /*Fix me is this right??? */ + SAM_DOMAIN_HANDLE *dom_handle = NULL; + SEC_DESC *sd; + uint32 acc_granted; + uint32 tmp_value; + + DEBUG(5,("sam_ads_get_domain_handle: %d\n",__LINE__)); + + SAM_ASSERT(sam_method && access_token && domain); + + (*domain) = NULL; + + if ((dom_handle = talloc(mem_ctx, sizeof(SAM_DOMAIN_HANDLE))) == NULL) { + DEBUG(0,("failed to talloc dom_handle\n")); + ads_status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); + return ads_ntstatus(ads_status); + } + + ZERO_STRUCTP(dom_handle); + + dom_handle->mem_ctx = mem_ctx; /*Fix me is this right??? */ + dom_handle->free_fn = NULL; + dom_handle->current_sam_methods = sam_method; + + /* check if access can be granted as requested */ + + ads_status = sam_ads_get_tree_sec_desc(privates, ADS_ROOT_TREE, &sd); + if (!ADS_ERR_OK(ads_status)) + return ads_ntstatus(ads_status); + + ads_status = sam_ads_access_check(privates, sd, access_token, access_desired, &acc_granted); + if (!ADS_ERR_OK(ads_status)) + return ads_ntstatus(ads_status); + + dom_handle->access_granted = acc_granted; + + /* fill all the values of dom_handle */ + sid_copy(&dom_handle->private.sid, &sam_method->domain_sid); + dom_handle->private.name = smb_xstrdup(sam_method->domain_name); + dom_handle->private.servername = "WHOKNOWS"; /* what is the servername */ + + /*Fix me: sam_ads_account_policy_get() return ADS_STATUS! */ + ads_status = sam_ads_account_policy_get(privates, AP_MAX_PASSWORD_AGE, &tmp_value); + if (!ADS_ERR_OK(ads_status)) { + DEBUG(4,("sam_ads_account_policy_get failed for max password age. Useing default\n")); + tmp_value = MAX_PASSWORD_AGE; + } + unix_to_nt_time_abs(&dom_handle->private.max_passwordage,tmp_value); + + ads_status = sam_ads_account_policy_get(privates, AP_MIN_PASSWORD_AGE, &tmp_value); + if (!ADS_ERR_OK(ads_status)) { + DEBUG(4,("sam_ads_account_policy_get failed for min password age. Useing default\n")); + tmp_value = 0; + } + unix_to_nt_time_abs(&dom_handle->private.min_passwordage, tmp_value); + + ads_status = sam_ads_account_policy_get(privates, AP_LOCK_ACCOUNT_DURATION, &tmp_value); + if (!ADS_ERR_OK(ads_status)) { + DEBUG(4,("sam_ads_account_policy_get failed for lockout duration. Useing default\n")); + tmp_value = 0; + } + unix_to_nt_time_abs(&dom_handle->private.lockout_duration, tmp_value); + + ads_status = sam_ads_account_policy_get(privates, AP_RESET_COUNT_TIME, &tmp_value); + if (!ADS_ERR_OK(ads_status)) { + DEBUG(4,("sam_ads_account_policy_get failed for time till locout count is reset. Useing default\n")); + tmp_value = 0; + } + unix_to_nt_time_abs(&dom_handle->private.reset_count, tmp_value); + + ads_status = sam_ads_account_policy_get(privates, AP_MIN_PASSWORD_LEN, &tmp_value); + if (!ADS_ERR_OK(ads_status)) { + DEBUG(4,("sam_ads_account_policy_get failed for min password length. Useing default\n")); + tmp_value = 0; + } + dom_handle->private.min_passwordlength = (uint16)tmp_value; + + ads_status = sam_ads_account_policy_get(privates, AP_PASSWORD_HISTORY, &tmp_value); + if (!ADS_ERR_OK(ads_status)) { + DEBUG(4,("sam_ads_account_policy_get failed password history. Useing default\n")); + tmp_value = 0; + } + dom_handle->private.password_history = (uint16)tmp_value; + + ads_status = sam_ads_account_policy_get(privates, AP_BAD_ATTEMPT_LOCKOUT, &tmp_value); + if (!ADS_ERR_OK(ads_status)) { + DEBUG(4,("sam_ads_account_policy_get failed for bad attempts till lockout. Useing default\n")); + tmp_value = 0; + } + dom_handle->private.lockout_count = (uint16)tmp_value; + + ads_status = sam_ads_account_policy_get(privates, AP_TIME_TO_LOGOUT, &tmp_value); + if (!ADS_ERR_OK(ads_status)) { + DEBUG(4,("sam_ads_account_policy_get failed for force logout. Useing default\n")); + tmp_value = -1; + } + + ads_status = sam_ads_account_policy_get(privates, AP_USER_MUST_LOGON_TO_CHG_PASS, &tmp_value); + if (!ADS_ERR_OK(ads_status)) { + DEBUG(4,("sam_ads_account_policy_get failed for user must login to change password. Useing default\n")); + tmp_value = 0; + } + + /* should the real values of num_accounts, num_groups and num_aliases be retreved? + * I think it is to expensive to bother + */ + dom_handle->private.num_accounts = 3; + dom_handle->private.num_groups = 4; + dom_handle->private.num_aliases = 5; + + *domain = dom_handle; + + ads_status = ADS_ERROR_NT(NT_STATUS_OK); + return ads_ntstatus(ads_status); +} + +/* Account API */ +static NTSTATUS sam_ads_create_account(const SAM_METHODS *sam_method, + const NT_USER_TOKEN *access_token, uint32 access_desired, + const char *account_name, uint16 acct_ctrl, SAM_ACCOUNT_HANDLE **account) +{ + ADS_STATUS ads_status = ADS_STATUS_NOT_IMPLEMENTED; + SAM_ADS_PRIVATES *privates = (struct sam_ads_privates *)sam_method->private_data; + SEC_DESC *sd = NULL; + uint32 acc_granted; + + SAM_ASSERT(sam_method && privates && access_token && account_name && account); + + ads_status = sam_ads_get_tree_sec_desc(privates, ADS_SUBTREE_USERS, &sd); + if (!ADS_ERR_OK(ads_status)) + return ads_ntstatus(ads_status); + + ads_status = sam_ads_access_check(privates, sd, access_token, access_desired, &acc_granted); + if (!ADS_ERR_OK(ads_status)) + return ads_ntstatus(ads_status); + + ads_status = ADS_ERROR_NT(sam_init_account(account)); + if (!ADS_ERR_OK(ads_status)) + return ads_ntstatus(ads_status); + + (*account)->access_granted = acc_granted; + + return ads_ntstatus(ads_status); +} + +static NTSTATUS sam_ads_add_account(const SAM_METHODS *sam_method, const SAM_ACCOUNT_HANDLE *account) +{ + ADS_STATUS ads_status = ADS_ERROR(LDAP_NO_MEMORY); + SAM_ADS_PRIVATES *privates = (struct sam_ads_privates *)sam_method->private_data; + ADS_STRUCT *ads_struct = privates->ads_struct; + TALLOC_CTX *mem_ctx = privates->mem_ctx; + ADS_MODLIST mods; + uint16 acct_ctrl; + char *new_dn; + SEC_DESC *sd; + uint32 acc_granted; + + SAM_ASSERT(sam_method && account); + + ads_status = ADS_ERROR_NT(sam_get_account_acct_ctrl(account,&acct_ctrl)); + if (!ADS_ERR_OK(ads_status)) + goto done; + + if ((acct_ctrl & ACB_WSTRUST)||(acct_ctrl & ACB_SVRTRUST)) { + /* Computer account */ + char *name,*controlstr; + char *hostname,*host_upn,*host_spn; + const char *objectClass[] = {"top", "person", "organizationalPerson", + "user", "computer", NULL}; + + ads_status = ADS_ERROR_NT(sam_get_account_name(account,&name)); + if (!ADS_ERR_OK(ads_status)) + goto done; + + if (!(host_upn = talloc_asprintf(mem_ctx, "%s@%s", name, ads_struct->config.realm))) { + ads_status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); + goto done; + } + + if (!(new_dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Computers,%s", hostname, + ads_struct->config.bind_path))) { + ads_status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); + goto done; + } + + if (!(controlstr = talloc_asprintf(mem_ctx, "%u", ads_acb2uf(acct_ctrl)))) { + ads_status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); + goto done; + } + + if (!(mods = ads_init_mods(mem_ctx))) { + ads_status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); + goto done; + } + + ads_status = ads_mod_str(mem_ctx, &mods, "cn", hostname); + if (!ADS_ERR_OK(ads_status)) + goto done; + ads_status = ads_mod_strlist(mem_ctx, &mods, "objectClass", objectClass); + if (!ADS_ERR_OK(ads_status)) + goto done; + ads_status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", host_upn); + if (!ADS_ERR_OK(ads_status)) + goto done; + ads_status = ads_mod_str(mem_ctx, &mods, "displayName", hostname); + if (!ADS_ERR_OK(ads_status)) + goto done; + ads_status = ads_mod_str(mem_ctx, &mods, "sAMAccountName", name); + if (!ADS_ERR_OK(ads_status)) + goto done; + ads_status = ads_mod_str(mem_ctx, &mods, "userAccountControl", controlstr); + if (!ADS_ERR_OK(ads_status)) + goto done; + + ads_status = ads_mod_str(mem_ctx, &mods, "servicePrincipalName", host_spn); + if (!ADS_ERR_OK(ads_status)) + goto done; + ads_status = ads_mod_str(mem_ctx, &mods, "dNSHostName", hostname); + if (!ADS_ERR_OK(ads_status)) + goto done; + ads_status = ads_mod_str(mem_ctx, &mods, "userAccountControl", controlstr); + if (!ADS_ERR_OK(ads_status)) + goto done; + /* ads_status = ads_mod_str(mem_ctx, &mods, "operatingSystem", "Samba"); + if (!ADS_ERR_OK(ads_status)) + goto done; + *//* ads_status = ads_mod_str(mem_ctx, &mods, "operatingSystemVersion", VERSION); + if (!ADS_ERR_OK(ads_status)) + goto done; + */ + /* End Computer account */ + } else { + /* User account*/ + char *upn, *controlstr; + char *name, *fullname; + const char *objectClass[] = {"top", "person", "organizationalPerson", + "user", NULL}; + + ads_status = ADS_ERROR_NT(sam_get_account_name(account,&name)); + if (!ADS_ERR_OK(ads_status)) + goto done; + + ads_status = ADS_ERROR_NT(sam_get_account_fullname(account,&fullname)); + if (!ADS_ERR_OK(ads_status)) + goto done; + + if (!(upn = talloc_asprintf(mem_ctx, "%s@%s", name, ads_struct->config.realm))) { + ads_status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); + goto done; + } + + if (!(new_dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Users,%s", fullname, + ads_struct->config.bind_path))) { + ads_status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); + goto done; + } + + if (!(controlstr = talloc_asprintf(mem_ctx, "%u", ads_acb2uf(acct_ctrl)))) { + ads_status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); + goto done; + } + + if (!(mods = ads_init_mods(mem_ctx))) { + ads_status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); + goto done; + } + + ads_status = ads_mod_str(mem_ctx, &mods, "cn", fullname); + if (!ADS_ERR_OK(ads_status)) + goto done; + ads_status = ads_mod_strlist(mem_ctx, &mods, "objectClass", objectClass); + if (!ADS_ERR_OK(ads_status)) + goto done; + ads_status = ads_mod_str(mem_ctx, &mods, "userPrincipalName", upn); + if (!ADS_ERR_OK(ads_status)) + goto done; + ads_status = ads_mod_str(mem_ctx, &mods, "displayName", fullname); + if (!ADS_ERR_OK(ads_status)) + goto done; + ads_status = ads_mod_str(mem_ctx, &mods, "sAMAccountName", name); + if (!ADS_ERR_OK(ads_status)) + goto done; + ads_status = ads_mod_str(mem_ctx, &mods, "userAccountControl", controlstr); + if (!ADS_ERR_OK(ads_status)) + goto done; + }/* End User account */ + + /* Finally at the account */ + ads_status = ads_gen_add(ads_struct, new_dn, mods); + +done: + return ads_ntstatus(ads_status); +} + +static NTSTATUS sam_ads_update_account(const SAM_METHODS *sam_method, const SAM_ACCOUNT_HANDLE *account) +{ + ADS_STATUS ads_status = ADS_STATUS_NOT_IMPLEMENTED; + DEBUG(0,("sam_ads: %s was called!\n",FUNCTION_MACRO)); + SAM_ASSERT(sam_method); + return ads_ntstatus(ads_status); +} + +static NTSTATUS sam_ads_delete_account(const SAM_METHODS *sam_method, const SAM_ACCOUNT_HANDLE *account) +{ + ADS_STATUS ads_status = ADS_STATUS_NOT_IMPLEMENTED; + DEBUG(0,("sam_ads: %s was called!\n",FUNCTION_MACRO)); + SAM_ASSERT(sam_method); + + + + return ads_ntstatus(ads_status); +} + +static NTSTATUS sam_ads_enum_accounts(const SAM_METHODS *sam_method, const NT_USER_TOKEN *access_token, uint16 acct_ctrl, uint32 *account_count, SAM_ACCOUNT_ENUM **accounts) +{ + ADS_STATUS ads_status = ADS_STATUS_NOT_IMPLEMENTED; + DEBUG(0,("sam_ads: %s was called!\n",FUNCTION_MACRO)); + SAM_ASSERT(sam_method); + return ads_ntstatus(ads_status); +} + +#if 0 +static NTSTATUS sam_ads_get_account_by_sid(const SAM_METHODS *sam_method, const NT_USER_TOKEN *access_token, const uint32 access_desired, const DOM_SID *account_sid, SAM_ACCOUNT_HANDLE **account) +{ + ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); + SAM_ADS_PRIVATES *privates = (struct sam_ads_privates *)sam_method->private_data; + ADS_STRUCT *ads_struct = privates->ads_struct; + TALLOC_CTX *mem_ctx = privates->mem_ctx; + SEC_DESC *sd = NULL; + uint32 acc_granted; + + SAM_ASSERT(sam_method && privates && ads_struct && access_token && account_sid && account); + + ads_status = ADS_ERROR_NT(sam_ads_get_sec_desc(sam_method, access_token, account_sid, &my_sd)); + if (!ADS_ERR_OK(ads_status)) + return ads_ntstatus(ads_status); + + ads_status = sam_ads_access_check(privates, sd, access_token, access_desired, &acc_granted); + if (!ADS_ERR_OK(ads_status)) + return ads_ntstatus(ads_status); + + ads_status = ADS_ERROR_NT(sam_init_account(account)); + if (!ADS_ERR_OK(ads_status)) + return ads_ntstatus(ads_status); + + (*account)->access_granted = acc_granted; + + return ads_ntstatus(ads_status); +} +#else +static NTSTATUS sam_ads_get_account_by_sid(const SAM_METHODS *sam_method, const NT_USER_TOKEN *access_token, const uint32 access_desired, const DOM_SID *account_sid, SAM_ACCOUNT_HANDLE **account) +{ + ADS_STATUS ads_status = ADS_STATUS_NOT_IMPLEMENTED; + DEBUG(0,("sam_ads: %s was called!\n",FUNCTION_MACRO)); + SAM_ASSERT(sam_method); + return ads_ntstatus(ads_status); +} +#endif + +#if 0 +static NTSTATUS sam_ads_get_account_by_name(const SAM_METHODS *sam_method, const NT_USER_TOKEN *access_token, const uint32 access_desired, const char *account_name, SAM_ACCOUNT_HANDLE **account) +{ + ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); + SAM_ADS_PRIVATES *privates = (struct sam_ads_privates *)sam_method->private_data; + ADS_STRUCT *ads_struct = privates->ads_struct; + TALLOC_CTX *mem_ctx = privates->mem_ctx; + SEC_DESC *sd = NULL; + uint32 acc_granted; + + SAM_ASSERT(sam_method && privates && ads_struct && access_token && account_name && account); + + ads_status = sam_ads_get_tree_sec_desc(privates, ADS_ROOT_TREE, &sd); + if (!ADS_ERR_OK(ads_status)) + return ads_ntstatus(ads_status); + + ads_status = sam_ads_access_check(privates, sd, access_token, access_desired, &acc_granted); + if (!ADS_ERR_OK(ads_status)) + return ads_ntstatus(ads_status); + + ads_status = ADS_ERROR_NT(sam_init_account(account)); + if (!ADS_ERR_OK(ads_status)) + return ads_ntstatus(ads_status); + + (*account)->access_granted = acc_granted; + + return ads_ntstatus(ads_status); +} +#else +static NTSTATUS sam_ads_get_account_by_name(const SAM_METHODS *sam_method, const NT_USER_TOKEN *access_token, const uint32 access_desired, const char *account_name, SAM_ACCOUNT_HANDLE **account) +{ + ADS_STATUS ads_status = ADS_STATUS_NOT_IMPLEMENTED; + DEBUG(0,("sam_ads: %s was called!\n",FUNCTION_MACRO)); + SAM_ASSERT(sam_method); + return ads_ntstatus(ads_status); +} +#endif + +/* Group API */ +static NTSTATUS sam_ads_create_group(const SAM_METHODS *sam_method, const NT_USER_TOKEN *access_token, uint32 access_desired, const char *group_name, uint16 group_ctrl, SAM_GROUP_HANDLE **group) +{ + ADS_STATUS ads_status = ADS_STATUS_NOT_IMPLEMENTED; + DEBUG(0,("sam_ads: %s was called!\n",FUNCTION_MACRO)); + SAM_ASSERT(sam_method); + return ads_ntstatus(ads_status); +} + +static NTSTATUS sam_ads_add_group(const SAM_METHODS *sam_method, const SAM_GROUP_HANDLE *group) +{ + ADS_STATUS ads_status = ADS_STATUS_NOT_IMPLEMENTED; + DEBUG(0,("sam_ads: %s was called!\n",FUNCTION_MACRO)); + SAM_ASSERT(sam_method); + return ads_ntstatus(ads_status); +} + +static NTSTATUS sam_ads_update_group(const SAM_METHODS *sam_method, const SAM_GROUP_HANDLE *group) +{ + ADS_STATUS ads_status = ADS_STATUS_NOT_IMPLEMENTED; + DEBUG(0,("sam_ads: %s was called!\n",FUNCTION_MACRO)); + SAM_ASSERT(sam_method); + return ads_ntstatus(ads_status); +} + +static NTSTATUS sam_ads_delete_group(const SAM_METHODS *sam_method, const SAM_GROUP_HANDLE *group) +{ + ADS_STATUS ads_status = ADS_STATUS_NOT_IMPLEMENTED; + DEBUG(0,("sam_ads: %s was called!\n",FUNCTION_MACRO)); + SAM_ASSERT(sam_method); + return ads_ntstatus(ads_status); +} + +static NTSTATUS sam_ads_enum_groups(const SAM_METHODS *sam_method, const NT_USER_TOKEN *access_token, const uint16 group_ctrl, uint32 *groups_count, SAM_GROUP_ENUM **groups) +{ + ADS_STATUS ads_status = ADS_STATUS_NOT_IMPLEMENTED; + SAM_ADS_PRIVATES *privates = (struct sam_ads_privates *)sam_method->private_data; + ADS_STRUCT *ads_struct = privates->ads_struct; + TALLOC_CTX *mem_ctx = privates->mem_ctx; + void *res = NULL; + void *msg = NULL; + char *filter = NULL; + int i = 0; + + /* get only these LDAP attributes, witch we really need for a group */ + const char *group_enum_attrs[] = {"objectSid", + "description", + "sAMAcountName", + NULL}; + + SAM_ASSERT(sam_method && access_token && groups_count && groups); + + *groups_count = 0; + + DEBUG(3,("ads: enum_dom_groups\n")); + + FIXME("get only group from the wanted Type!\n"); + asprintf(&filter, "(&(objectClass=group)(groupType=%s))", "*"); + ads_status = sam_ads_do_search(privates, ads_struct->config.bind_path, LDAP_SCOPE_SUBTREE, filter, group_enum_attrs, &res); + if (!ADS_ERR_OK(ads_status)) { + DEBUG(1,("enum_groups ads_search: %s\n", ads_errstr(ads_status))); + } + + *groups_count = ads_count_replies(ads_struct, res); + if (*groups_count == 0) { + DEBUG(1,("enum_groups: No groups found\n")); + } + + (*groups) = talloc_zero(mem_ctx, (*groups_count) * sizeof(**groups)); + if (!*groups) { + ads_status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); + } + + for (msg = ads_first_entry(ads_struct, res); msg; msg = ads_next_entry(ads_struct, msg)) { + uint32 grouptype; + + if (!ads_pull_uint32(ads_struct, msg, "groupType", &grouptype)) { + ; + } else { + (*groups)->group_ctrl = ads_gtype2gcb(grouptype); + } + + if (!((*groups)->group_name = ads_pull_string(ads_struct, mem_ctx, msg, "sAMAccountName"))) { + ; + } + + if (!((*groups)->group_desc = ads_pull_string(ads_struct, mem_ctx, msg, "description"))) { + ; + } + + if (!ads_pull_sid(ads_struct, msg, "objectSid", &((*groups)->sid))) { + DEBUG(1,("No sid for group %s !?\n", (*groups)->group_name)); + continue; + } + + i++; + } + + (*groups_count) = i; + + ads_status = ADS_ERROR_NT(NT_STATUS_OK); + + DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*groups_count))); + + if (res) ads_msgfree(ads_struct, res); + + return ads_ntstatus(ads_status); +} + +static NTSTATUS sam_ads_get_group_by_sid(const SAM_METHODS *sam_method, const NT_USER_TOKEN *access_token, const uint32 access_desired, const DOM_SID *groupsid, SAM_GROUP_HANDLE **group) +{ + ADS_STATUS ads_status = ADS_STATUS_NOT_IMPLEMENTED; + DEBUG(0,("sam_ads: %s was called!\n",FUNCTION_MACRO)); + SAM_ASSERT(sam_method); + return ads_ntstatus(ads_status); +} + +static NTSTATUS sam_ads_get_group_by_name(const SAM_METHODS *sam_method, const NT_USER_TOKEN *access_token, const uint32 access_desired, const char *name, SAM_GROUP_HANDLE **group) +{ + ADS_STATUS ads_status = ADS_STATUS_NOT_IMPLEMENTED; + DEBUG(0,("sam_ads: %s was called!\n",FUNCTION_MACRO)); + SAM_ASSERT(sam_method); + return ads_ntstatus(ads_status); +} + +static NTSTATUS sam_ads_add_member_to_group(const SAM_METHODS *sam_method, const SAM_GROUP_HANDLE *group, const SAM_GROUP_MEMBER *member) +{ + ADS_STATUS ads_status = ADS_STATUS_NOT_IMPLEMENTED; + DEBUG(0,("sam_ads: %s was called!\n",FUNCTION_MACRO)); + SAM_ASSERT(sam_method); + return ads_ntstatus(ads_status); +} + +static NTSTATUS sam_ads_delete_member_from_group(const SAM_METHODS *sam_method, const SAM_GROUP_HANDLE *group, const SAM_GROUP_MEMBER *member) +{ + ADS_STATUS ads_status = ADS_STATUS_NOT_IMPLEMENTED; + DEBUG(0,("sam_ads: %s was called!\n",FUNCTION_MACRO)); + SAM_ASSERT(sam_method); + return ads_ntstatus(ads_status); +} + +static NTSTATUS sam_ads_enum_groupmembers(const SAM_METHODS *sam_method, const SAM_GROUP_HANDLE *group, uint32 *members_count, SAM_GROUP_MEMBER **members) +{ + ADS_STATUS ads_status = ADS_STATUS_NOT_IMPLEMENTED; + DEBUG(0,("sam_ads: %s was called!\n",FUNCTION_MACRO)); + SAM_ASSERT(sam_method); + return ads_ntstatus(ads_status); +} + +static NTSTATUS sam_ads_get_groups_of_sid(const SAM_METHODS *sam_method, const NT_USER_TOKEN *access_token, const DOM_SID **sids, const uint16 group_ctrl, uint32 *group_count, SAM_GROUP_ENUM **groups) +{ + ADS_STATUS ads_status = ADS_STATUS_NOT_IMPLEMENTED; + DEBUG(0,("sam_ads: %s was called!\n",FUNCTION_MACRO)); + SAM_ASSERT(sam_method); + return ads_ntstatus(ads_status); +} + +/********************************** +Free our private data +***********************************/ +static void sam_ads_free_private_data(void **vp) +{ + SAM_ADS_PRIVATES **sam_ads_state = (SAM_ADS_PRIVATES **)vp; + + if ((*sam_ads_state)->ads_struct->ld) { + ldap_unbind((*sam_ads_state)->ads_struct->ld); + } + + ads_destroy(&((*sam_ads_state)->ads_struct)); + + talloc_destroy((*sam_ads_state)->mem_ctx); + FIXME("maybe we must free some other stuff here\n"); + + *sam_ads_state = NULL; +} + + + +/***************************************************** +Init the ADS SAM backend +******************************************************/ +NTSTATUS sam_init_ads(SAM_METHODS *sam_method, const char *module_params) +{ + ADS_STATUS ads_status; + SAM_ADS_PRIVATES *sam_ads_state; + TALLOC_CTX *mem_ctx; + + SAM_ASSERT(sam_method && sam_method->parent); + + mem_ctx = sam_method->parent->mem_ctx; + + /* Here the SAM API functions of the sam_ads module */ + + /* General API */ + + sam_method->sam_get_sec_desc = sam_ads_get_sec_desc; + sam_method->sam_set_sec_desc = sam_ads_set_sec_desc; + + sam_method->sam_lookup_sid = sam_ads_lookup_sid; + sam_method->sam_lookup_name = sam_ads_lookup_name; + + /* Domain API */ + + sam_method->sam_update_domain = sam_ads_update_domain; + sam_method->sam_get_domain_handle = sam_ads_get_domain_handle; + + /* Account API */ + + sam_method->sam_create_account = sam_ads_create_account; + sam_method->sam_add_account = sam_ads_add_account; + sam_method->sam_update_account = sam_ads_update_account; + sam_method->sam_delete_account = sam_ads_delete_account; + sam_method->sam_enum_accounts = sam_ads_enum_accounts; + + sam_method->sam_get_account_by_sid = sam_ads_get_account_by_sid; + sam_method->sam_get_account_by_name = sam_ads_get_account_by_name; + + /* Group API */ + + sam_method->sam_create_group = sam_ads_create_group; + sam_method->sam_add_group = sam_ads_add_group; + sam_method->sam_update_group = sam_ads_update_group; + sam_method->sam_delete_group = sam_ads_delete_group; + sam_method->sam_enum_groups = sam_ads_enum_groups; + sam_method->sam_get_group_by_sid = sam_ads_get_group_by_sid; + sam_method->sam_get_group_by_name = sam_ads_get_group_by_name; + + sam_method->sam_add_member_to_group = sam_ads_add_member_to_group; + sam_method->sam_delete_member_from_group = sam_ads_delete_member_from_group; + sam_method->sam_enum_groupmembers = sam_ads_enum_groupmembers; + + sam_method->sam_get_groups_of_sid = sam_ads_get_groups_of_sid; + + sam_ads_state = talloc_zero(mem_ctx, sizeof(SAM_ADS_PRIVATES)); + if (!sam_ads_state) { + DEBUG(0, ("talloc() failed for sam_ads private_data!\n")); + return NT_STATUS_NO_MEMORY; + } + + if (!(sam_ads_state->mem_ctx = talloc_init("sam_ads_method"))) { + DEBUG(0, ("talloc_init() failed for sam_ads_state->mem_ctx\n")); + return NT_STATUS_NO_MEMORY; + } + + sam_ads_state->ads_bind_dn = talloc_strdup(sam_ads_state->mem_ctx, lp_parm_string(NULL,"sam_ads","bind as")); + sam_ads_state->ads_bind_pw = talloc_strdup(sam_ads_state->mem_ctx, lp_parm_string(NULL,"sam_ads","bind pw")); + + sam_ads_state->bind_plaintext = strequal(lp_parm_string(NULL, "sam_ads", "plaintext bind"), "yes"); + + if (!sam_ads_state->ads_bind_dn || !sam_ads_state->ads_bind_pw) { + DEBUG(0, ("talloc_strdup() failed for bind dn or password\n")); + return NT_STATUS_NO_MEMORY; + } + + /* Maybe we should not check the result here? Server down on startup? */ + + if (module_params && *module_params) { + sam_ads_state->ldap_uri = talloc_strdup(sam_ads_state->mem_ctx, module_params); + if (!sam_ads_state->ldap_uri) { + DEBUG(0, ("talloc_strdup() failed for bind dn or password\n")); + return NT_STATUS_NO_MEMORY; + } + } else { + sam_ads_state->ldap_uri = "ldapi://"; + } + + ads_status = sam_ads_cached_connection(sam_ads_state); + if (!ADS_ERR_OK(ads_status)) { + return ads_ntstatus(ads_status); + } + + sam_method->private_data = sam_ads_state; + sam_method->free_private_data = sam_ads_free_private_data; + + sam_ads_debug_level = debug_add_class("sam_ads"); + if (sam_ads_debug_level == -1) { + sam_ads_debug_level = DBGC_ALL; + DEBUG(0, ("sam_ads: Couldn't register custom debugging class!\n")); + } else DEBUG(2, ("sam_ads: Debug class number of 'sam_ads': %d\n", sam_ads_debug_level)); + + DEBUG(5, ("Initializing sam_ads\n")); + if (module_params) + DEBUG(10, ("Module Parameters for Domain %s[%s]: %s\n", sam_method->domain_name, sam_method->domain_name, module_params)); + return NT_STATUS_OK; +} + +#else /* HAVE_LDAP */ +void sam_ads_dummy(void) +{ + DEBUG(0,("sam_ads: not supported!\n")); +} +#endif /* HAVE_LDAP */ -- cgit