/* 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 */