📄 pdb_ldap.c
字号:
/* Unix SMB/CIFS implementation. LDAP protocol helper functions for SAMBA Copyright (C) Jean François Micouleau 1998 Copyright (C) Gerald Carter 2001-2003 Copyright (C) Shahms King 2001 Copyright (C) Andrew Bartlett 2002-2003 Copyright (C) Stefan (metze) Metzmacher 2002-2003 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. *//* TODO:* persistent connections: if using NSS LDAP, many connections are made* however, using only one within Samba would be nice* * Clean up SSL stuff, compile on OpenLDAP 1.x, 2.x, and Netscape SDK** Other LDAP based login attributes: accountExpires, etc.* (should be the domain of Samba proper, but the sam_password/SAM_ACCOUNT* structures don't have fields for some of these attributes)** SSL is done, but can't get the certificate based authentication to work* against on my test platform (Linux 2.4, OpenLDAP 2.x)*//* NOTE: this will NOT work against an Active Directory server* due to the fact that the two password fields cannot be retrieved* from a server; recommend using security = domain in this situation* and/or winbind*/#include "includes.h"#undef DBGC_CLASS#define DBGC_CLASS DBGC_PASSDB#include <lber.h>#include <ldap.h>/* * Work around versions of the LDAP client libs that don't have the OIDs * defined, or have them defined under the old name. * This functionality is really a factor of the server, not the client * */#if defined(LDAP_EXOP_X_MODIFY_PASSWD) && !defined(LDAP_EXOP_MODIFY_PASSWD)#define LDAP_EXOP_MODIFY_PASSWD LDAP_EXOP_X_MODIFY_PASSWD#elif !defined(LDAP_EXOP_MODIFY_PASSWD)#define LDAP_EXOP_MODIFY_PASSWD "1.3.6.1.4.1.4203.1.11.1"#endif#if defined(LDAP_EXOP_X_MODIFY_PASSWD_ID) && !defined(LDAP_EXOP_MODIFY_PASSWD_ID)#define LDAP_TAG_EXOP_MODIFY_PASSWD_ID LDAP_EXOP_X_MODIFY_PASSWD_ID#elif !defined(LDAP_EXOP_MODIFY_PASSWD_ID)#define LDAP_TAG_EXOP_MODIFY_PASSWD_ID ((ber_tag_t) 0x80U)#endif#if defined(LDAP_EXOP_X_MODIFY_PASSWD_NEW) && !defined(LDAP_EXOP_MODIFY_PASSWD_NEW)#define LDAP_TAG_EXOP_MODIFY_PASSWD_NEW LDAP_EXOP_X_MODIFY_PASSWD_NEW#elif !defined(LDAP_EXOP_MODIFY_PASSWD_NEW)#define LDAP_TAG_EXOP_MODIFY_PASSWD_NEW ((ber_tag_t) 0x82U)#endif#ifndef SAM_ACCOUNT#define SAM_ACCOUNT struct sam_passwd#endif#include "smbldap.h"/********************************************************************** Free a LDAPMessage (one is stored on the SAM_ACCOUNT). **********************************************************************/ void private_data_free_fn(void **result) { ldap_msgfree(*result); *result = NULL;}/********************************************************************** Get the attribute name given a user schame version. **********************************************************************/ static const char* get_userattr_key2string( int schema_ver, int key ){ switch ( schema_ver ) { case SCHEMAVER_SAMBAACCOUNT: return get_attr_key2string( attrib_map_v22, key ); case SCHEMAVER_SAMBASAMACCOUNT: return get_attr_key2string( attrib_map_v30, key ); default: DEBUG(0,("get_userattr_key2string: unknown schema version specified\n")); break; } return NULL;}/********************************************************************** Return the list of attribute names given a user schema version.**********************************************************************/const char** get_userattr_list( int schema_ver ){ switch ( schema_ver ) { case SCHEMAVER_SAMBAACCOUNT: return get_attr_list( attrib_map_v22 ); case SCHEMAVER_SAMBASAMACCOUNT: return get_attr_list( attrib_map_v30 ); default: DEBUG(0,("get_userattr_list: unknown schema version specified!\n")); break; } return NULL;}/************************************************************************** Return the list of attribute names to delete given a user schema version.**************************************************************************/static const char** get_userattr_delete_list( int schema_ver ){ switch ( schema_ver ) { case SCHEMAVER_SAMBAACCOUNT: return get_attr_list( attrib_map_to_delete_v22 ); case SCHEMAVER_SAMBASAMACCOUNT: return get_attr_list( attrib_map_to_delete_v30 ); default: DEBUG(0,("get_userattr_delete_list: unknown schema version specified!\n")); break; } return NULL;}/******************************************************************* Generate the LDAP search filter for the objectclass based on the version of the schema we are using.******************************************************************/static const char* get_objclass_filter( int schema_ver ){ static fstring objclass_filter; switch( schema_ver ) { case SCHEMAVER_SAMBAACCOUNT: fstr_sprintf( objclass_filter, "(objectclass=%s)", LDAP_OBJ_SAMBAACCOUNT ); break; case SCHEMAVER_SAMBASAMACCOUNT: fstr_sprintf( objclass_filter, "(objectclass=%s)", LDAP_OBJ_SAMBASAMACCOUNT ); break; default: DEBUG(0,("get_objclass_filter: Invalid schema version specified!\n")); break; } return objclass_filter; }/***************************************************************** Scan a sequence number off OpenLDAP's syncrepl contextCSN******************************************************************/static NTSTATUS ldapsam_get_seq_num(struct pdb_methods *my_methods, time_t *seq_num){ struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data; NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL; LDAPMessage *msg = NULL; LDAPMessage *entry = NULL; TALLOC_CTX *mem_ctx; char **values = NULL; int rc, num_result, num_values, rid; pstring suffix; fstring tok; const char *p; const char **attrs; /* Unfortunatly there is no proper way to detect syncrepl-support in * smbldap_connect_system(). The syncrepl OIDs are submitted for publication * but do not show up in the root-DSE yet. Neither we can query the * subschema-context for the syncProviderSubentry or syncConsumerSubentry * objectclass. Currently we require lp_ldap_suffix() to show up as * namingContext. - Guenther */ if (!lp_parm_bool(-1, "ldapsam", "syncrepl_seqnum", False)) { return ntstatus; } if (!seq_num) { DEBUG(3,("ldapsam_get_seq_num: no sequence_number\n")); return ntstatus; } if (!smbldap_has_naming_context(ldap_state->smbldap_state, lp_ldap_suffix())) { DEBUG(3,("ldapsam_get_seq_num: DIT not configured to hold %s " "as top-level namingContext\n", lp_ldap_suffix())); return ntstatus; } mem_ctx = talloc_init("ldapsam_get_seq_num"); if (mem_ctx == NULL) return NT_STATUS_NO_MEMORY; attrs = TALLOC_ARRAY(mem_ctx, const char *, 2); /* if we got a syncrepl-rid (up to three digits long) we speak with a consumer */ rid = lp_parm_int(-1, "ldapsam", "syncrepl_rid", -1); if (rid > 0) { /* consumer syncreplCookie: */ /* csn=20050126161620Z#0000001#00#00000 */ attrs[0] = talloc_strdup(mem_ctx, "syncreplCookie"); attrs[1] = NULL; pstr_sprintf( suffix, "cn=syncrepl%d,%s", rid, lp_ldap_suffix()); } else { /* provider contextCSN */ /* 20050126161620Z#000009#00#000000 */ attrs[0] = talloc_strdup(mem_ctx, "contextCSN"); attrs[1] = NULL; pstr_sprintf( suffix, "cn=ldapsync,%s", lp_ldap_suffix()); } rc = smbldap_search(ldap_state->smbldap_state, suffix, LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0, &msg); if (rc != LDAP_SUCCESS) { char *ld_error = NULL; ldap_get_option(ldap_state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error); DEBUG(0,("ldapsam_get_seq_num: Failed search for suffix: %s, error: %s (%s)\n", suffix,ldap_err2string(rc), ld_error?ld_error:"unknown")); SAFE_FREE(ld_error); goto done; } num_result = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, msg); if (num_result != 1) { DEBUG(3,("ldapsam_get_seq_num: Expected one entry, got %d\n", num_result)); goto done; } entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, msg); if (entry == NULL) { DEBUG(3,("ldapsam_get_seq_num: Could not retrieve entry\n")); goto done; } values = ldap_get_values(ldap_state->smbldap_state->ldap_struct, entry, attrs[0]); if (values == NULL) { DEBUG(3,("ldapsam_get_seq_num: no values\n")); goto done; } num_values = ldap_count_values(values); if (num_values == 0) { DEBUG(3,("ldapsam_get_seq_num: not a single value\n")); goto done; } p = values[0]; if (!next_token(&p, tok, "#", sizeof(tok))) { DEBUG(0,("ldapsam_get_seq_num: failed to parse sequence number\n")); goto done; } p = tok; if (!strncmp(p, "csn=", strlen("csn="))) p += strlen("csn="); DEBUG(10,("ldapsam_get_seq_num: got %s: %s\n", attrs[0], p)); *seq_num = generalized_to_unix_time(p); /* very basic sanity check */ if (*seq_num <= 0) { DEBUG(3,("ldapsam_get_seq_num: invalid sequence number: %d\n", (int)*seq_num)); goto done; } ntstatus = NT_STATUS_OK; done: if (values != NULL) ldap_value_free(values); if (msg != NULL) ldap_msgfree(msg); if (mem_ctx) talloc_destroy(mem_ctx); return ntstatus;}/******************************************************************* Run the search by name.******************************************************************/int ldapsam_search_suffix_by_name(struct ldapsam_privates *ldap_state, const char *user, LDAPMessage ** result, const char **attr){ pstring filter; char *escape_user = escape_ldap_string_alloc(user); if (!escape_user) { return LDAP_NO_MEMORY; } /* * in the filter expression, replace %u with the real name * so in ldap filter, %u MUST exist :-) */ pstr_sprintf(filter, "(&%s%s)", "(uid=%u)", get_objclass_filter(ldap_state->schema_ver)); /* * have to use this here because $ is filtered out * in pstring_sub */ all_string_sub(filter, "%u", escape_user, sizeof(pstring)); SAFE_FREE(escape_user); return smbldap_search_suffix(ldap_state->smbldap_state, filter, attr, result);}/******************************************************************* Run the search by rid.******************************************************************/static int ldapsam_search_suffix_by_rid (struct ldapsam_privates *ldap_state, uint32 rid, LDAPMessage ** result, const char **attr){ pstring filter; int rc; pstr_sprintf(filter, "(&(rid=%i)%s)", rid, get_objclass_filter(ldap_state->schema_ver)); rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, attr, result); return rc;}/******************************************************************* Run the search by SID.******************************************************************/static int ldapsam_search_suffix_by_sid (struct ldapsam_privates *ldap_state, const DOM_SID *sid, LDAPMessage ** result, const char **attr){ pstring filter; int rc; fstring sid_string; pstr_sprintf(filter, "(&(%s=%s)%s)", get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_SID), sid_to_string(sid_string, sid), get_objclass_filter(ldap_state->schema_ver)); rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, attr, result); return rc;}/******************************************************************* Delete complete object or objectclass and attrs from object found in search_result depending on lp_ldap_delete_dn******************************************************************/static NTSTATUS ldapsam_delete_entry(struct ldapsam_privates *ldap_state, LDAPMessage *result, const char *objectclass, const char **attrs)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -