fix bug 118; replace hard coded 'next[User|Group]Rid' attribute names
[Samba/ekacnet.git] / source / passdb / pdb_ldap.c
blob1c305a361c63d95e3d6b866104d8e4e70bd84258
1 /*
2 Unix SMB/CIFS mplementation.
3 LDAP protocol helper functions for SAMBA
4 Copyright (C) Jean François Micouleau 1998
5 Copyright (C) Gerald Carter 2001-2003
6 Copyright (C) Shahms King 2001
7 Copyright (C) Andrew Bartlett 2002
8 Copyright (C) Stefan (metze) Metzmacher 2002
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 /* TODO:
27 * persistent connections: if using NSS LDAP, many connections are made
28 * however, using only one within Samba would be nice
30 * Clean up SSL stuff, compile on OpenLDAP 1.x, 2.x, and Netscape SDK
32 * Other LDAP based login attributes: accountExpires, etc.
33 * (should be the domain of Samba proper, but the sam_password/SAM_ACCOUNT
34 * structures don't have fields for some of these attributes)
36 * SSL is done, but can't get the certificate based authentication to work
37 * against on my test platform (Linux 2.4, OpenLDAP 2.x)
40 /* NOTE: this will NOT work against an Active Directory server
41 * due to the fact that the two password fields cannot be retrieved
42 * from a server; recommend using security = domain in this situation
43 * and/or winbind
46 #include "includes.h"
48 #undef DBGC_CLASS
49 #define DBGC_CLASS DBGC_PASSDB
51 #include <lber.h>
52 #include <ldap.h>
54 #ifndef LDAP_OPT_SUCCESS
55 #define LDAP_OPT_SUCCESS 0
56 #endif
58 #ifndef SAM_ACCOUNT
59 #define SAM_ACCOUNT struct sam_passwd
60 #endif
62 struct ldapsam_privates {
63 /* Former statics */
64 LDAP *ldap_struct;
65 LDAPMessage *result;
66 LDAPMessage *entry;
67 int index;
69 time_t last_ping;
70 /* retrive-once info */
71 const char *uri;
72 const char *domain_name;
73 DOM_SID domain_sid;
75 /* configuration items */
76 int schema_ver;
78 BOOL permit_non_unix_accounts;
80 uint32 low_allocated_user_rid;
81 uint32 high_allocated_user_rid;
83 uint32 low_allocated_group_rid;
84 uint32 high_allocated_group_rid;
86 char *bind_dn;
87 char *bind_secret;
89 unsigned int num_failures;
92 #define LDAPSAM_DONT_PING_TIME 10 /* ping only all 10 seconds */
94 static struct ldapsam_privates *static_ldap_state;
96 /* specify schema versions between 2.2. and 3.0 */
98 #define SCHEMAVER_SAMBAACCOUNT 1
99 #define SCHEMAVER_SAMBASAMACCOUNT 2
101 /* objectclass names */
103 #define LDAP_OBJ_SAMBASAMACCOUNT "sambaSamAccount"
104 #define LDAP_OBJ_SAMBAACCOUNT "sambaAccount"
105 #define LDAP_OBJ_GROUPMAP "sambaGroupMapping"
106 #define LDAP_OBJ_DOMINFO "sambaDomain"
108 #define LDAP_OBJ_ACCOUNT "account"
109 #define LDAP_OBJ_POSIXACCOUNT "posixAccount"
110 #define LDAP_OBJ_POSIXGROUP "posixGroup"
112 /* some generic attributes that get reused a lot */
114 #define LDAP_ATTRIBUTE_SID "sambaSID"
116 /* attribute map table indexes */
118 #define LDAP_ATTR_LIST_END 0
119 #define LDAP_ATTR_UID 1
120 #define LDAP_ATTR_UIDNUMBER 2
121 #define LDAP_ATTR_GIDNUMBER 3
122 #define LDAP_ATTR_UNIX_HOME 4
123 #define LDAP_ATTR_PWD_LAST_SET 5
124 #define LDAP_ATTR_PWD_CAN_CHANGE 6
125 #define LDAP_ATTR_PWD_MUST_CHANGE 7
126 #define LDAP_ATTR_LOGON_TIME 8
127 #define LDAP_ATTR_LOGOFF_TIME 9
128 #define LDAP_ATTR_KICKOFF_TIME 10
129 #define LDAP_ATTR_CN 11
130 #define LDAP_ATTR_DISPLAY_NAME 12
131 #define LDAP_ATTR_HOME_PATH 13
132 #define LDAP_ATTR_LOGON_SCRIPT 14
133 #define LDAP_ATTR_PROFILE_PATH 15
134 #define LDAP_ATTR_DESC 16
135 #define LDAP_ATTR_USER_WKS 17
136 #define LDAP_ATTR_USER_SID 18
137 #define LDAP_ATTR_USER_RID 18
138 #define LDAP_ATTR_PRIMARY_GROUP_SID 19
139 #define LDAP_ATTR_PRIMARY_GROUP_RID 20
140 #define LDAP_ATTR_LMPW 21
141 #define LDAP_ATTR_NTPW 22
142 #define LDAP_ATTR_DOMAIN 23
143 #define LDAP_ATTR_OBJCLASS 24
144 #define LDAP_ATTR_ACB_INFO 25
145 #define LDAP_ATTR_NEXT_USERRID 26
146 #define LDAP_ATTR_NEXT_GROUPRID 27
147 #define LDAP_ATTR_DOM_SID 28
148 #define LDAP_ATTR_HOME_DRIVE 29
149 #define LDAP_ATTR_GROUP_SID 30
150 #define LDAP_ATTR_GROUP_TYPE 31
153 typedef struct _attrib_map_entry {
154 int attrib;
155 const char *name;
156 } ATTRIB_MAP_ENTRY;
159 /* attributes used by Samba 2.2 */
161 static ATTRIB_MAP_ENTRY attrib_map_v22[] = {
162 { LDAP_ATTR_UID, "uid" },
163 { LDAP_ATTR_UIDNUMBER, "uidNumber" },
164 { LDAP_ATTR_GIDNUMBER, "gidNumber" },
165 { LDAP_ATTR_UNIX_HOME, "homeDirectory" },
166 { LDAP_ATTR_PWD_LAST_SET, "pwdLastSet" },
167 { LDAP_ATTR_PWD_CAN_CHANGE, "pwdCanChange" },
168 { LDAP_ATTR_PWD_MUST_CHANGE, "pwdMustChange" },
169 { LDAP_ATTR_LOGON_TIME, "logonTime" },
170 { LDAP_ATTR_LOGOFF_TIME, "logoffTime" },
171 { LDAP_ATTR_KICKOFF_TIME, "kickoffTime" },
172 { LDAP_ATTR_CN, "cn" },
173 { LDAP_ATTR_DISPLAY_NAME, "displayName" },
174 { LDAP_ATTR_HOME_PATH, "smbHome" },
175 { LDAP_ATTR_HOME_DRIVE, "homeDrives" },
176 { LDAP_ATTR_LOGON_SCRIPT, "scriptPath" },
177 { LDAP_ATTR_PROFILE_PATH, "profilePath" },
178 { LDAP_ATTR_DESC, "description" },
179 { LDAP_ATTR_USER_WKS, "userWorkstations"},
180 { LDAP_ATTR_USER_RID, "rid" },
181 { LDAP_ATTR_PRIMARY_GROUP_RID, "primaryGroupID"},
182 { LDAP_ATTR_LMPW, "lmPassword" },
183 { LDAP_ATTR_NTPW, "ntPassword" },
184 { LDAP_ATTR_DOMAIN, "domain" },
185 { LDAP_ATTR_OBJCLASS, "objectClass" },
186 { LDAP_ATTR_ACB_INFO, "acctFlags" },
187 { LDAP_ATTR_LIST_END, NULL }
190 /* attributes used by Samba 3.0's sambaSamAccount */
192 static ATTRIB_MAP_ENTRY attrib_map_v30[] = {
193 { LDAP_ATTR_UID, "uid" },
194 { LDAP_ATTR_UIDNUMBER, "uidNumber" },
195 { LDAP_ATTR_GIDNUMBER, "gidNumber" },
196 { LDAP_ATTR_UNIX_HOME, "homeDirectory" },
197 { LDAP_ATTR_PWD_LAST_SET, "sambaPwdLastSet" },
198 { LDAP_ATTR_PWD_CAN_CHANGE, "sambaPwdCanChange" },
199 { LDAP_ATTR_PWD_MUST_CHANGE, "sambaPwdMustChange" },
200 { LDAP_ATTR_LOGON_TIME, "sambaLogonTime" },
201 { LDAP_ATTR_LOGOFF_TIME, "sambaLogoffTime" },
202 { LDAP_ATTR_KICKOFF_TIME, "sambaKickoffTime" },
203 { LDAP_ATTR_CN, "cn" },
204 { LDAP_ATTR_DISPLAY_NAME, "displayName" },
205 { LDAP_ATTR_HOME_DRIVE, "sambaHomeDrive" },
206 { LDAP_ATTR_HOME_PATH, "sambaHomePath" },
207 { LDAP_ATTR_LOGON_SCRIPT, "sambaLogonScript" },
208 { LDAP_ATTR_PROFILE_PATH, "sambaProfilePath" },
209 { LDAP_ATTR_DESC, "description" },
210 { LDAP_ATTR_USER_WKS, "sambaUserWorkstations" },
211 { LDAP_ATTR_USER_SID, "sambaSID" },
212 { LDAP_ATTR_PRIMARY_GROUP_SID, "sambaPrimaryGroupSID" },
213 { LDAP_ATTR_LMPW, "sambaLMPassword" },
214 { LDAP_ATTR_NTPW, "sambaNTPassword" },
215 { LDAP_ATTR_DOMAIN, "sambaDomainName" },
216 { LDAP_ATTR_OBJCLASS, "objectClass" },
217 { LDAP_ATTR_ACB_INFO, "sambaAcctFlags" },
218 { LDAP_ATTR_LIST_END, NULL }
221 /* attributes used for alalocating RIDs */
223 static ATTRIB_MAP_ENTRY dominfo_attr_list[] = {
224 { LDAP_ATTR_DOMAIN, "sambaDomainName" },
225 { LDAP_ATTR_NEXT_USERRID, "sambaNextUserRid" },
226 { LDAP_ATTR_NEXT_GROUPRID, "sambaNextGroupRid" },
227 { LDAP_ATTR_DOM_SID, "sambaSID" },
228 { LDAP_ATTR_LIST_END, NULL },
231 /* Samba 3.0 group mapping attributes */
233 static ATTRIB_MAP_ENTRY groupmap_attr_list[] = {
234 { LDAP_ATTR_GIDNUMBER, "gidNumber" },
235 { LDAP_ATTR_GROUP_SID, "sambaSID" },
236 { LDAP_ATTR_GROUP_TYPE, "sambaGroupType" },
237 { LDAP_ATTR_DESC, "description" },
238 { LDAP_ATTR_DISPLAY_NAME, "displayName" },
239 { LDAP_ATTR_CN, "cn" },
240 { LDAP_ATTR_LIST_END, NULL }
243 static ATTRIB_MAP_ENTRY groupmap_attr_list_to_delete[] = {
244 { LDAP_ATTR_GROUP_SID, "sambaSID" },
245 { LDAP_ATTR_GROUP_TYPE, "sambaGroupType" },
246 { LDAP_ATTR_DESC, "description" },
247 { LDAP_ATTR_DISPLAY_NAME, "displayName" },
248 { LDAP_ATTR_LIST_END, NULL }
251 /**********************************************************************
252 perform a simple table lookup and return the attribute name
253 **********************************************************************/
255 static const char* get_attr_key2string( ATTRIB_MAP_ENTRY table[], int key )
257 int i = 0;
259 while ( table[i].attrib != LDAP_ATTR_LIST_END ) {
260 if ( table[i].attrib == key )
261 return table[i].name;
262 i++;
265 return NULL;
268 /**********************************************************************
269 get the attribute name given a user schame version
270 **********************************************************************/
272 static const char* get_userattr_key2string( int schema_ver, int key )
274 switch ( schema_ver )
276 case SCHEMAVER_SAMBAACCOUNT:
277 return get_attr_key2string( attrib_map_v22, key );
279 case SCHEMAVER_SAMBASAMACCOUNT:
280 return get_attr_key2string( attrib_map_v30, key );
282 default:
283 DEBUG(0,("get_userattr_key2string: unknown schema version specified\n"));
284 break;
286 return NULL;
289 /**********************************************************************
290 Return the list of attribute names from a mapping table
291 **********************************************************************/
293 static char** get_attr_list( ATTRIB_MAP_ENTRY table[] )
295 char **names;
296 int i = 0;
298 while ( table[i].attrib != LDAP_ATTR_LIST_END )
299 i++;
300 i++;
302 names = (char**)malloc( sizeof(char*)*i );
303 if ( !names ) {
304 DEBUG(0,("get_attr_list: out of memory\n"));
305 return NULL;
308 i = 0;
309 while ( table[i].attrib != LDAP_ATTR_LIST_END ) {
310 names[i] = strdup( table[i].name );
311 i++;
313 names[i] = NULL;
315 return names;
318 /*********************************************************************
319 Cleanup
320 ********************************************************************/
322 static void free_attr_list( char **list )
324 int i = 0;
326 if ( !list )
327 return;
329 while ( list[i] )
330 SAFE_FREE( list[i] );
332 SAFE_FREE( list );
335 /**********************************************************************
336 return the list of attribute names given a user schema version
337 **********************************************************************/
339 static char** get_userattr_list( int schema_ver )
341 switch ( schema_ver )
343 case SCHEMAVER_SAMBAACCOUNT:
344 return get_attr_list( attrib_map_v22 );
346 case SCHEMAVER_SAMBASAMACCOUNT:
347 return get_attr_list( attrib_map_v30 );
348 default:
349 DEBUG(0,("get_userattr_list: unknown schema version specified!\n"));
350 break;
353 return NULL;
356 /*******************************************************************
357 find the ldap password
358 ******************************************************************/
359 static BOOL fetch_ldapsam_pw(char **dn, char** pw)
361 char *key = NULL;
362 size_t size;
364 *dn = smb_xstrdup(lp_ldap_admin_dn());
366 if (asprintf(&key, "%s/%s", SECRETS_LDAP_BIND_PW, *dn) < 0) {
367 SAFE_FREE(*dn);
368 DEBUG(0, ("fetch_ldapsam_pw: asprintf failed!\n"));
371 *pw=secrets_fetch(key, &size);
372 SAFE_FREE(key);
374 if (!size) {
375 /* Upgrade 2.2 style entry */
376 char *p;
377 char* old_style_key = strdup(*dn);
378 char *data;
379 fstring old_style_pw;
381 if (!old_style_key) {
382 DEBUG(0, ("fetch_ldapsam_pw: strdup failed!\n"));
383 return False;
386 for (p=old_style_key; *p; p++)
387 if (*p == ',') *p = '/';
389 data=secrets_fetch(old_style_key, &size);
390 if (!size && size < sizeof(old_style_pw)) {
391 DEBUG(0,("fetch_ldap_pw: neither ldap secret retrieved!\n"));
392 SAFE_FREE(old_style_key);
393 SAFE_FREE(*dn);
394 return False;
397 strncpy(old_style_pw, data, size);
398 old_style_pw[size] = 0;
400 SAFE_FREE(data);
402 if (!secrets_store_ldap_pw(*dn, old_style_pw)) {
403 DEBUG(0,("fetch_ldap_pw: ldap secret could not be upgraded!\n"));
404 SAFE_FREE(old_style_key);
405 SAFE_FREE(*dn);
406 return False;
408 if (!secrets_delete(old_style_key)) {
409 DEBUG(0,("fetch_ldap_pw: old ldap secret could not be deleted!\n"));
412 SAFE_FREE(old_style_key);
414 *pw = smb_xstrdup(old_style_pw);
417 return True;
420 /*******************************************************************
421 open a connection to the ldap server.
422 ******************************************************************/
423 static int ldapsam_open_connection (struct ldapsam_privates *ldap_state, LDAP ** ldap_struct)
425 int rc = LDAP_SUCCESS;
426 int version;
427 BOOL ldap_v3 = False;
429 #ifdef HAVE_LDAP_INITIALIZE
430 DEBUG(10, ("ldapsam_open_connection: %s\n", ldap_state->uri));
432 if ((rc = ldap_initialize(ldap_struct, ldap_state->uri)) != LDAP_SUCCESS) {
433 DEBUG(0, ("ldap_initialize: %s\n", ldap_err2string(rc)));
434 return rc;
437 #else
439 /* Parse the string manually */
442 int port = 0;
443 fstring protocol;
444 fstring host;
445 const char *p = ldap_state->uri;
446 SMB_ASSERT(sizeof(protocol)>10 && sizeof(host)>254);
448 /* skip leading "URL:" (if any) */
449 if ( strncasecmp( p, "URL:", 4 ) == 0 ) {
450 p += 4;
453 sscanf(p, "%10[^:]://%254s[^:]:%d", protocol, host, &port);
455 if (port == 0) {
456 if (strequal(protocol, "ldap")) {
457 port = LDAP_PORT;
458 } else if (strequal(protocol, "ldaps")) {
459 port = LDAPS_PORT;
460 } else {
461 DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
465 if ((*ldap_struct = ldap_init(host, port)) == NULL) {
466 DEBUG(0, ("ldap_init failed !\n"));
467 return LDAP_OPERATIONS_ERROR;
470 if (strequal(protocol, "ldaps")) {
471 #ifdef LDAP_OPT_X_TLS
472 int tls = LDAP_OPT_X_TLS_HARD;
473 if (ldap_set_option (*ldap_struct, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
475 DEBUG(0, ("Failed to setup a TLS session\n"));
478 DEBUG(3,("LDAPS option set...!\n"));
479 #else
480 DEBUG(0,("ldapsam_open_connection: Secure connection not supported by LDAP client libraries!\n"));
481 return LDAP_OPERATIONS_ERROR;
482 #endif
485 #endif
487 if (ldap_get_option(*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS)
489 if (version != LDAP_VERSION3)
491 version = LDAP_VERSION3;
492 if (ldap_set_option (*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS) {
493 ldap_v3 = True;
495 } else {
496 ldap_v3 = True;
500 if (lp_ldap_ssl() == LDAP_SSL_START_TLS) {
501 #ifdef LDAP_OPT_X_TLS
502 if (ldap_v3) {
503 if ((rc = ldap_start_tls_s (*ldap_struct, NULL, NULL)) != LDAP_SUCCESS)
505 DEBUG(0,("Failed to issue the StartTLS instruction: %s\n",
506 ldap_err2string(rc)));
507 return rc;
509 DEBUG (3, ("StartTLS issued: using a TLS connection\n"));
510 } else {
512 DEBUG(0, ("Need LDAPv3 for Start TLS\n"));
513 return LDAP_OPERATIONS_ERROR;
515 #else
516 DEBUG(0,("ldapsam_open_connection: StartTLS not supported by LDAP client libraries!\n"));
517 return LDAP_OPERATIONS_ERROR;
518 #endif
521 DEBUG(2, ("ldapsam_open_connection: connection opened\n"));
522 return rc;
526 /*******************************************************************
527 a rebind function for authenticated referrals
528 This version takes a void* that we can shove useful stuff in :-)
529 ******************************************************************/
530 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
531 #else
532 static int rebindproc_with_state (LDAP * ld, char **whop, char **credp,
533 int *methodp, int freeit, void *arg)
535 struct ldapsam_privates *ldap_state = arg;
537 /** @TODO Should we be doing something to check what servers we rebind to?
538 Could we get a referral to a machine that we don't want to give our
539 username and password to? */
541 if (freeit) {
542 SAFE_FREE(*whop);
543 memset(*credp, '\0', strlen(*credp));
544 SAFE_FREE(*credp);
545 } else {
546 DEBUG(5,("rebind_proc_with_state: Rebinding as \"%s\"\n",
547 ldap_state->bind_dn));
549 *whop = strdup(ldap_state->bind_dn);
550 if (!*whop) {
551 return LDAP_NO_MEMORY;
553 *credp = strdup(ldap_state->bind_secret);
554 if (!*credp) {
555 SAFE_FREE(*whop);
556 return LDAP_NO_MEMORY;
558 *methodp = LDAP_AUTH_SIMPLE;
560 return 0;
562 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
564 /*******************************************************************
565 a rebind function for authenticated referrals
566 This version takes a void* that we can shove useful stuff in :-)
567 and actually does the connection.
568 ******************************************************************/
569 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
570 static int rebindproc_connect_with_state (LDAP *ldap_struct,
571 LDAP_CONST char *url,
572 ber_tag_t request,
573 ber_int_t msgid, void *arg)
575 struct ldapsam_privates *ldap_state = arg;
576 int rc;
577 DEBUG(5,("rebindproc_connect_with_state: Rebinding as \"%s\"\n",
578 ldap_state->bind_dn));
580 /** @TODO Should we be doing something to check what servers we rebind to?
581 Could we get a referral to a machine that we don't want to give our
582 username and password to? */
584 rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
586 return rc;
588 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
590 /*******************************************************************
591 Add a rebind function for authenticated referrals
592 ******************************************************************/
593 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
594 #else
595 # if LDAP_SET_REBIND_PROC_ARGS == 2
596 static int rebindproc (LDAP *ldap_struct, char **whop, char **credp,
597 int *method, int freeit )
599 return rebindproc_with_state(ldap_struct, whop, credp,
600 method, freeit, static_ldap_state);
603 # endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
604 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
606 /*******************************************************************
607 a rebind function for authenticated referrals
608 this also does the connection, but no void*.
609 ******************************************************************/
610 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
611 # if LDAP_SET_REBIND_PROC_ARGS == 2
612 static int rebindproc_connect (LDAP * ld, LDAP_CONST char *url, int request,
613 ber_int_t msgid)
615 return rebindproc_connect_with_state(ld, url, (ber_tag_t)request, msgid,
616 static_ldap_state);
618 # endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
619 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
621 /*******************************************************************
622 connect to the ldap server under system privilege.
623 ******************************************************************/
624 static int ldapsam_connect_system(struct ldapsam_privates *ldap_state, LDAP * ldap_struct)
626 int rc;
627 char *ldap_dn;
628 char *ldap_secret;
630 /* The rebind proc needs this *HACK*. We are not multithreaded, so
631 this will work, but it's not nice. */
632 static_ldap_state = ldap_state;
634 /* get the password */
635 if (!fetch_ldapsam_pw(&ldap_dn, &ldap_secret))
637 DEBUG(0, ("ldap_connect_system: Failed to retrieve password from secrets.tdb\n"));
638 return LDAP_INVALID_CREDENTIALS;
641 ldap_state->bind_dn = ldap_dn;
642 ldap_state->bind_secret = ldap_secret;
644 /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite
645 (OpenLDAP) doesnt' seem to support it */
647 DEBUG(10,("ldap_connect_system: Binding to ldap server %s as \"%s\"\n",
648 ldap_state->uri, ldap_dn));
650 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
651 # if LDAP_SET_REBIND_PROC_ARGS == 2
652 ldap_set_rebind_proc(ldap_struct, &rebindproc_connect);
653 # endif
654 # if LDAP_SET_REBIND_PROC_ARGS == 3
655 ldap_set_rebind_proc(ldap_struct, &rebindproc_connect_with_state, (void *)ldap_state);
656 # endif
657 #else /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
658 # if LDAP_SET_REBIND_PROC_ARGS == 2
659 ldap_set_rebind_proc(ldap_struct, &rebindproc);
660 # endif
661 # if LDAP_SET_REBIND_PROC_ARGS == 3
662 ldap_set_rebind_proc(ldap_struct, &rebindproc_with_state, (void *)ldap_state);
663 # endif
664 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
666 rc = ldap_simple_bind_s(ldap_struct, ldap_dn, ldap_secret);
668 if (rc != LDAP_SUCCESS) {
669 char *ld_error = NULL;
670 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
671 &ld_error);
672 DEBUG(ldap_state->num_failures ? 2 : 0,
673 ("failed to bind to server with dn= %s Error: %s\n\t%s\n",
674 ldap_dn ? ld_error : "(unknown)", ldap_err2string(rc),
675 ld_error));
676 SAFE_FREE(ld_error);
677 ldap_state->num_failures++;
678 return rc;
681 ldap_state->num_failures = 0;
683 DEBUG(3, ("ldap_connect_system: succesful connection to the LDAP server\n"));
684 return rc;
687 /**********************************************************************
688 Connect to LDAP server
689 *********************************************************************/
690 static int ldapsam_open(struct ldapsam_privates *ldap_state)
692 int rc;
693 SMB_ASSERT(ldap_state);
695 #ifndef NO_LDAP_SECURITY
696 if (geteuid() != 0) {
697 DEBUG(0, ("ldapsam_open: cannot access LDAP when not root..\n"));
698 return LDAP_INSUFFICIENT_ACCESS;
700 #endif
702 if ((ldap_state->ldap_struct != NULL) && ((ldap_state->last_ping + LDAPSAM_DONT_PING_TIME) < time(NULL))) {
703 struct sockaddr_un addr;
704 socklen_t len = sizeof(addr);
705 int sd;
706 if (ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_DESC, &sd) == 0 &&
707 getpeername(sd, (struct sockaddr *) &addr, &len) < 0) {
708 /* the other end has died. reopen. */
709 ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL);
710 ldap_state->ldap_struct = NULL;
711 ldap_state->last_ping = (time_t)0;
712 } else {
713 ldap_state->last_ping = time(NULL);
717 if (ldap_state->ldap_struct != NULL) {
718 DEBUG(5,("ldapsam_open: already connected to the LDAP server\n"));
719 return LDAP_SUCCESS;
722 if ((rc = ldapsam_open_connection(ldap_state, &ldap_state->ldap_struct))) {
723 return rc;
726 if ((rc = ldapsam_connect_system(ldap_state, ldap_state->ldap_struct))) {
727 ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL);
728 ldap_state->ldap_struct = NULL;
729 return rc;
733 ldap_state->last_ping = time(NULL);
734 DEBUG(4,("The LDAP server is succesful connected\n"));
736 return LDAP_SUCCESS;
739 /**********************************************************************
740 Disconnect from LDAP server
741 *********************************************************************/
742 static NTSTATUS ldapsam_close(struct ldapsam_privates *ldap_state)
744 if (!ldap_state)
745 return NT_STATUS_INVALID_PARAMETER;
747 if (ldap_state->ldap_struct != NULL) {
748 ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL);
749 ldap_state->ldap_struct = NULL;
752 DEBUG(5,("The connection to the LDAP server was closed\n"));
753 /* maybe free the results here --metze */
755 return NT_STATUS_OK;
758 static int ldapsam_retry_open(struct ldapsam_privates *ldap_state, int *attempts)
760 int rc;
762 SMB_ASSERT(ldap_state && attempts);
764 if (*attempts != 0) {
765 unsigned int sleep_time;
766 uint8 rand_byte;
768 /* Sleep for a random timeout */
769 rand_byte = (char)(sys_random());
771 sleep_time = (((*attempts)*(*attempts))/2)*rand_byte*2;
772 /* we retry after (0.5, 1, 2, 3, 4.5, 6) seconds
773 on average.
775 DEBUG(3, ("Sleeping for %u milliseconds before reconnecting\n",
776 sleep_time));
777 msleep(sleep_time);
779 (*attempts)++;
781 if ((rc = ldapsam_open(ldap_state))) {
782 DEBUG(1,("Connection to LDAP Server failed for the %d try!\n",*attempts));
783 return rc;
786 return LDAP_SUCCESS;
790 /*********************************************************************
791 ********************************************************************/
793 static int ldapsam_search(struct ldapsam_privates *ldap_state,
794 const char *base, int scope, const char *filter,
795 char *attrs[], int attrsonly,
796 LDAPMessage **res)
798 int rc = LDAP_SERVER_DOWN;
799 int attempts = 0;
800 char *utf8_filter;
802 SMB_ASSERT(ldap_state);
804 if (push_utf8_allocate(&utf8_filter, filter) == (size_t)-1) {
805 return LDAP_NO_MEMORY;
808 while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
810 if ((rc = ldapsam_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
811 continue;
813 rc = ldap_search_s(ldap_state->ldap_struct, base, scope,
814 utf8_filter, attrs, attrsonly, res);
817 if (rc == LDAP_SERVER_DOWN) {
818 DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
819 ldapsam_close(ldap_state);
822 SAFE_FREE(utf8_filter);
823 return rc;
826 static int ldapsam_modify(struct ldapsam_privates *ldap_state, const char *dn, LDAPMod *attrs[])
828 int rc = LDAP_SERVER_DOWN;
829 int attempts = 0;
830 char *utf8_dn;
832 SMB_ASSERT(ldap_state);
834 if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
835 return LDAP_NO_MEMORY;
838 while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
840 if ((rc = ldapsam_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
841 continue;
843 rc = ldap_modify_s(ldap_state->ldap_struct, utf8_dn, attrs);
846 if (rc == LDAP_SERVER_DOWN) {
847 DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
848 ldapsam_close(ldap_state);
851 SAFE_FREE(utf8_dn);
852 return rc;
855 static int ldapsam_add(struct ldapsam_privates *ldap_state, const char *dn, LDAPMod *attrs[])
857 int rc = LDAP_SERVER_DOWN;
858 int attempts = 0;
859 char *utf8_dn;
861 SMB_ASSERT(ldap_state);
863 if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
864 return LDAP_NO_MEMORY;
867 while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
869 if ((rc = ldapsam_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
870 continue;
872 rc = ldap_add_s(ldap_state->ldap_struct, utf8_dn, attrs);
875 if (rc == LDAP_SERVER_DOWN) {
876 DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
877 ldapsam_close(ldap_state);
880 SAFE_FREE(utf8_dn);
881 return rc;
884 static int ldapsam_delete(struct ldapsam_privates *ldap_state, char *dn)
886 int rc = LDAP_SERVER_DOWN;
887 int attempts = 0;
888 char *utf8_dn;
890 SMB_ASSERT(ldap_state);
892 if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
893 return LDAP_NO_MEMORY;
896 while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
898 if ((rc = ldapsam_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
899 continue;
901 rc = ldap_delete_s(ldap_state->ldap_struct, utf8_dn);
904 if (rc == LDAP_SERVER_DOWN) {
905 DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
906 ldapsam_close(ldap_state);
909 SAFE_FREE(utf8_dn);
910 return rc;
913 #ifdef LDAP_EXOP_X_MODIFY_PASSWD
914 static int ldapsam_extended_operation(struct ldapsam_privates *ldap_state, LDAP_CONST char *reqoid, struct berval *reqdata, LDAPControl **serverctrls, LDAPControl **clientctrls, char **retoidp, struct berval **retdatap)
916 int rc = LDAP_SERVER_DOWN;
917 int attempts = 0;
919 if (!ldap_state)
920 return (-1);
922 while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
924 if ((rc = ldapsam_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
925 continue;
927 rc = ldap_extended_operation_s(ldap_state->ldap_struct, reqoid, reqdata, serverctrls, clientctrls, retoidp, retdatap);
930 if (rc == LDAP_SERVER_DOWN) {
931 DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
932 ldapsam_close(ldap_state);
935 return rc;
937 #endif
939 /*******************************************************************
940 run the search by name.
941 ******************************************************************/
942 static int ldapsam_search_suffix (struct ldapsam_privates *ldap_state, const char *filter,
943 char **search_attr, LDAPMessage ** result)
945 int scope = LDAP_SCOPE_SUBTREE;
946 int rc;
948 DEBUG(2, ("ldapsam_search_suffix: searching for:[%s]\n", filter));
950 rc = ldapsam_search(ldap_state, lp_ldap_suffix(), scope, filter, search_attr, 0, result);
952 if (rc != LDAP_SUCCESS) {
953 char *ld_error = NULL;
954 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
955 &ld_error);
956 DEBUG(0,("ldapsam_search_suffix: Problem during the LDAP search: %s (%s)\n",
957 ld_error?ld_error:"(unknown)", ldap_err2string (rc)));
958 DEBUG(3,("ldapsam_search_suffix: Query was: %s, %s\n", lp_ldap_suffix(),
959 filter));
960 SAFE_FREE(ld_error);
963 return rc;
966 /*******************************************************************
967 generate the LDAP search filter for the objectclass based on the
968 version of the schema we are using
969 ******************************************************************/
971 static const char* get_objclass_filter( int schema_ver )
973 static fstring objclass_filter;
975 switch( schema_ver )
977 case SCHEMAVER_SAMBAACCOUNT:
978 snprintf( objclass_filter, sizeof(objclass_filter)-1, "(objectclass=%s)", LDAP_OBJ_SAMBAACCOUNT );
979 break;
980 case SCHEMAVER_SAMBASAMACCOUNT:
981 snprintf( objclass_filter, sizeof(objclass_filter)-1, "(objectclass=%s)", LDAP_OBJ_SAMBASAMACCOUNT );
982 break;
983 default:
984 DEBUG(0,("ldapsam_search_suffix_by_name(): Invalid schema version specified!\n"));
985 break;
988 return objclass_filter;
991 /*******************************************************************
992 run the search by name.
993 ******************************************************************/
994 static int ldapsam_search_suffix_by_name (struct ldapsam_privates *ldap_state, const char *user,
995 LDAPMessage ** result, char **attr)
997 pstring filter;
998 char *escape_user = escape_ldap_string_alloc(user);
1000 if (!escape_user) {
1001 return LDAP_NO_MEMORY;
1005 * in the filter expression, replace %u with the real name
1006 * so in ldap filter, %u MUST exist :-)
1008 snprintf(filter, sizeof(filter)-1, "(&%s%s)", lp_ldap_filter(),
1009 get_objclass_filter(ldap_state->schema_ver));
1012 * have to use this here because $ is filtered out
1013 * in pstring_sub
1017 all_string_sub(filter, "%u", escape_user, sizeof(pstring));
1018 SAFE_FREE(escape_user);
1020 return ldapsam_search_suffix(ldap_state, filter, attr, result);
1023 /*******************************************************************
1024 run the search by rid.
1025 ******************************************************************/
1026 static int ldapsam_search_suffix_by_rid (struct ldapsam_privates *ldap_state,
1027 uint32 rid, LDAPMessage ** result,
1028 char **attr)
1030 pstring filter;
1031 int rc;
1033 /* check if the user rid exists, if not, try searching on the uid */
1035 snprintf(filter, sizeof(filter)-1, "(&(rid=%i)%s)", rid,
1036 get_objclass_filter(ldap_state->schema_ver));
1038 rc = ldapsam_search_suffix(ldap_state, filter, attr, result);
1040 return rc;
1043 /*******************************************************************
1044 run the search by SID.
1045 ******************************************************************/
1046 static int ldapsam_search_suffix_by_sid (struct ldapsam_privates *ldap_state,
1047 const DOM_SID *sid, LDAPMessage ** result,
1048 char **attr)
1050 pstring filter;
1051 int rc;
1052 fstring sid_string;
1054 /* check if the user rid exsists, if not, try searching on the uid */
1056 snprintf(filter, sizeof(filter)-1, "(&(%s=%s)%s)",
1057 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_SID),
1058 sid_to_string(sid_string, sid),
1059 get_objclass_filter(ldap_state->schema_ver));
1061 rc = ldapsam_search_suffix(ldap_state, filter, attr, result);
1063 return rc;
1066 /*******************************************************************
1067 search an attribute and return the first value found.
1068 ******************************************************************/
1069 static BOOL get_single_attribute (LDAP * ldap_struct, LDAPMessage * entry,
1070 const char *attribute, pstring value)
1072 char **values;
1074 if ( !attribute )
1075 return False;
1077 value[0] = '\0';
1079 if ((values = ldap_get_values (ldap_struct, entry, attribute)) == NULL) {
1080 DEBUG (10, ("get_single_attribute: [%s] = [<does not exist>]\n", attribute));
1082 return False;
1085 if (convert_string(CH_UTF8, CH_UNIX,values[0], -1, value, sizeof(pstring)) == (size_t)-1)
1087 DEBUG(1, ("get_single_attribute: string conversion of [%s] = [%s] failed!\n",
1088 attribute, values[0]));
1089 ldap_value_free(values);
1090 return False;
1093 ldap_value_free(values);
1094 #ifdef DEBUG_PASSWORDS
1095 DEBUG (100, ("get_single_attribute: [%s] = [%s]\n", attribute, value));
1096 #endif
1097 return True;
1100 /************************************************************************
1101 Routine to manage the LDAPMod structure array
1102 manage memory used by the array, by each struct, and values
1104 ************************************************************************/
1105 static void make_a_mod (LDAPMod *** modlist, int modop, const char *attribute, const char *value)
1107 LDAPMod **mods;
1108 int i;
1109 int j;
1111 mods = *modlist;
1113 /* sanity checks on the mod values */
1115 if (attribute == NULL || *attribute == '\0')
1116 return;
1117 #if 0 /* commented out after discussion with abartlet. Do not reenable.
1118 left here so other so re-add similar code --jerry */
1119 if (value == NULL || *value == '\0')
1120 return;
1121 #endif
1123 if (mods == NULL)
1125 mods = (LDAPMod **) malloc(sizeof(LDAPMod *));
1126 if (mods == NULL)
1128 DEBUG(0, ("make_a_mod: out of memory!\n"));
1129 return;
1131 mods[0] = NULL;
1134 for (i = 0; mods[i] != NULL; ++i) {
1135 if (mods[i]->mod_op == modop && !strcasecmp(mods[i]->mod_type, attribute))
1136 break;
1139 if (mods[i] == NULL)
1141 mods = (LDAPMod **) Realloc (mods, (i + 2) * sizeof (LDAPMod *));
1142 if (mods == NULL)
1144 DEBUG(0, ("make_a_mod: out of memory!\n"));
1145 return;
1147 mods[i] = (LDAPMod *) malloc(sizeof(LDAPMod));
1148 if (mods[i] == NULL)
1150 DEBUG(0, ("make_a_mod: out of memory!\n"));
1151 return;
1153 mods[i]->mod_op = modop;
1154 mods[i]->mod_values = NULL;
1155 mods[i]->mod_type = strdup(attribute);
1156 mods[i + 1] = NULL;
1159 if (value != NULL)
1161 char *utf8_value = NULL;
1163 j = 0;
1164 if (mods[i]->mod_values != NULL) {
1165 for (; mods[i]->mod_values[j] != NULL; j++);
1167 mods[i]->mod_values = (char **)Realloc(mods[i]->mod_values,
1168 (j + 2) * sizeof (char *));
1170 if (mods[i]->mod_values == NULL) {
1171 DEBUG (0, ("make_a_mod: Memory allocation failure!\n"));
1172 return;
1175 if (push_utf8_allocate(&utf8_value, value) == (size_t)-1) {
1176 DEBUG (0, ("make_a_mod: String conversion failure!\n"));
1177 return;
1180 mods[i]->mod_values[j] = utf8_value;
1182 mods[i]->mod_values[j + 1] = NULL;
1184 *modlist = mods;
1187 /**********************************************************************
1188 Set attribute to newval in LDAP, regardless of what value the
1189 attribute had in LDAP before.
1190 *********************************************************************/
1191 static void make_ldap_mod(LDAP *ldap_struct, LDAPMessage *existing,
1192 LDAPMod ***mods,
1193 const char *attribute, const char *newval)
1195 char **values = NULL;
1197 if (existing != NULL) {
1198 values = ldap_get_values(ldap_struct, existing, attribute);
1201 /* all of our string attributes are case insensitive */
1203 if ((values != NULL) && (values[0] != NULL) &&
1204 StrCaseCmp(values[0], newval) == 0)
1207 /* Believe it or not, but LDAP will deny a delete and
1208 an add at the same time if the values are the
1209 same... */
1211 ldap_value_free(values);
1212 return;
1215 /* Regardless of the real operation (add or modify)
1216 we add the new value here. We rely on deleting
1217 the old value, should it exist. */
1219 if ((newval != NULL) && (strlen(newval) > 0)) {
1220 make_a_mod(mods, LDAP_MOD_ADD, attribute, newval);
1223 if (values == NULL) {
1224 /* There has been no value before, so don't delete it.
1225 Here's a possible race: We might end up with
1226 duplicate attributes */
1227 return;
1230 /* By deleting exactly the value we found in the entry this
1231 should be race-free in the sense that the LDAP-Server will
1232 deny the complete operation if somebody changed the
1233 attribute behind our back. */
1235 make_a_mod(mods, LDAP_MOD_DELETE, attribute, values[0]);
1236 ldap_value_free(values);
1239 /*******************************************************************
1240 Delete complete object or objectclass and attrs from
1241 object found in search_result depending on lp_ldap_delete_dn
1242 ******************************************************************/
1243 static NTSTATUS ldapsam_delete_entry(struct ldapsam_privates *ldap_state,
1244 LDAPMessage *result,
1245 const char *objectclass,
1246 char **attrs)
1248 int rc;
1249 LDAPMessage *entry;
1250 LDAPMod **mods = NULL;
1251 char *name, *dn;
1252 BerElement *ptr = NULL;
1254 rc = ldap_count_entries(ldap_state->ldap_struct, result);
1256 if (rc != 1) {
1257 DEBUG(0, ("Entry must exist exactly once!\n"));
1258 return NT_STATUS_UNSUCCESSFUL;
1261 entry = ldap_first_entry(ldap_state->ldap_struct, result);
1262 dn = ldap_get_dn(ldap_state->ldap_struct, entry);
1264 if (lp_ldap_delete_dn()) {
1265 NTSTATUS ret = NT_STATUS_OK;
1266 rc = ldapsam_delete(ldap_state, dn);
1268 if (rc != LDAP_SUCCESS) {
1269 DEBUG(0, ("Could not delete object %s\n", dn));
1270 ret = NT_STATUS_UNSUCCESSFUL;
1272 ldap_memfree(dn);
1273 return ret;
1276 /* Ok, delete only the SAM attributes */
1278 for (name = ldap_first_attribute(ldap_state->ldap_struct, entry, &ptr);
1279 name != NULL;
1280 name = ldap_next_attribute(ldap_state->ldap_struct, entry, ptr))
1282 char **attrib;
1284 /* We are only allowed to delete the attributes that
1285 really exist. */
1287 for (attrib = attrs; *attrib != NULL; attrib++)
1289 if (StrCaseCmp(*attrib, name) == 0) {
1290 DEBUG(10, ("deleting attribute %s\n", name));
1291 make_a_mod(&mods, LDAP_MOD_DELETE, name, NULL);
1295 ldap_memfree(name);
1298 if (ptr != NULL) {
1299 ber_free(ptr, 0);
1302 make_a_mod(&mods, LDAP_MOD_DELETE, "objectClass", objectclass);
1304 rc = ldapsam_modify(ldap_state, dn, mods);
1305 ldap_mods_free(mods, 1);
1307 if (rc != LDAP_SUCCESS) {
1308 char *ld_error = NULL;
1309 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
1310 &ld_error);
1312 DEBUG(0, ("could not delete attributes for %s, error: %s (%s)\n",
1313 dn, ldap_err2string(rc), ld_error?ld_error:"unknown"));
1314 SAFE_FREE(ld_error);
1315 ldap_memfree(dn);
1316 return NT_STATUS_UNSUCCESSFUL;
1319 ldap_memfree(dn);
1320 return NT_STATUS_OK;
1323 /**********************************************************************
1324 Search for the domain info entry
1325 *********************************************************************/
1326 static int ldapsam_search_domain_info(struct ldapsam_privates *ldap_state,
1327 LDAPMessage ** result)
1329 pstring filter;
1330 int rc;
1331 char **attr_list;
1333 snprintf(filter, sizeof(filter)-1, "(&(objectClass=%s)(%s=%s))",
1334 LDAP_OBJ_DOMINFO,
1335 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
1336 ldap_state->domain_name);
1338 DEBUG(2, ("Searching for:[%s]\n", filter));
1341 attr_list = get_attr_list( dominfo_attr_list );
1342 rc = ldapsam_search_suffix(ldap_state, filter, attr_list , result);
1343 free_attr_list( attr_list );
1345 if (rc != LDAP_SUCCESS) {
1346 DEBUG(2,("Problem during LDAPsearch: %s\n", ldap_err2string (rc)));
1347 DEBUG(2,("Query was: %s, %s\n", lp_ldap_suffix(), filter));
1350 return rc;
1353 /**********************************************************************
1354 If this entry is is the 'allocated' range, extract the RID and return
1355 it, so we can find the 'next' rid to allocate.
1357 Do this, no matter what type of object holds the RID - be it a user,
1358 group or somthing else.
1359 *********************************************************************/
1360 static uint32 entry_to_rid(struct ldapsam_privates *ldap_state, LDAPMessage *entry, int rid_type)
1362 pstring sid_string;
1363 DOM_SID dom_sid;
1364 uint32 rid;
1366 if (!get_single_attribute(ldap_state->ldap_struct, entry,
1367 LDAP_ATTRIBUTE_SID, sid_string))
1369 return 0;
1372 if (!string_to_sid(&dom_sid, sid_string)) {
1373 return 0;
1376 if (!sid_peek_check_rid(&dom_sid, get_global_sam_sid(), &rid)) {
1377 /* not our domain, so we don't care */
1378 return 0;
1381 switch (rid_type) {
1382 case USER_RID_TYPE:
1383 if (rid >= ldap_state->low_allocated_user_rid &&
1384 rid <= ldap_state->high_allocated_user_rid) {
1385 return rid;
1387 break;
1388 case GROUP_RID_TYPE:
1389 if (rid >= ldap_state->low_allocated_group_rid &&
1390 rid <= ldap_state->high_allocated_group_rid) {
1391 return rid;
1393 break;
1395 return 0;
1399 /**********************************************************************
1400 Connect to LDAP server and find the next available 'allocated' RID.
1402 The search is done 'per type' as we allocate seperate pools for the
1403 EVEN and ODD (user and group) RIDs.
1405 This is only done once, so that we can fill out the sambaDomain.
1406 *********************************************************************/
1407 static uint32 search_next_allocated_rid(struct ldapsam_privates *ldap_state, int rid_type)
1409 int rc;
1410 LDAPMessage *result;
1411 LDAPMessage *entry;
1412 uint32 top_rid = 0;
1413 uint32 next_rid;
1414 uint32 count;
1415 uint32 rid;
1416 char *sid_attr[] = {LDAP_ATTRIBUTE_SID, NULL};
1417 fstring filter;
1419 snprintf( filter, sizeof(filter)-1, "(%s=*)", LDAP_ATTRIBUTE_SID );
1421 DEBUG(2, ("search_top_allocated_rid: searching for:[%s]\n", filter));
1423 rc = ldapsam_search_suffix(ldap_state, filter, sid_attr, &result);
1425 if (rc != LDAP_SUCCESS) {
1426 DEBUG(3, ("LDAP search failed! cannot find base for NUA RIDs: %s\n", ldap_err2string(rc)));
1427 DEBUGADD(3, ("Query was: %s, %s\n", lp_ldap_suffix(), filter));
1429 result = NULL;
1430 return 0;
1433 count = ldap_count_entries(ldap_state->ldap_struct, result);
1434 DEBUG(2, ("search_top_allocated_rid: %d entries in the base!\n", count));
1436 if (count == 0) {
1437 DEBUG(3, ("LDAP search returned no records, assuming no allocated RIDs present!: %s\n", ldap_err2string(rc)));
1438 DEBUGADD(3, ("Query was: %s, %s\n", lp_ldap_suffix(), filter));
1439 } else {
1440 entry = ldap_first_entry(ldap_state->ldap_struct,result);
1442 top_rid = entry_to_rid(ldap_state, entry, rid_type);
1444 while ((entry = ldap_next_entry(ldap_state->ldap_struct, entry))) {
1446 rid = entry_to_rid(ldap_state, entry, rid_type);
1447 if (((rid & ~RID_TYPE_MASK) == rid_type) && (rid > top_rid)) {
1448 top_rid = rid;
1453 switch (rid_type) {
1454 case USER_RID_TYPE:
1455 if (top_rid < ldap_state->low_allocated_user_rid) {
1456 return ldap_state->low_allocated_user_rid;
1458 break;
1459 case GROUP_RID_TYPE:
1460 if (top_rid < ldap_state->low_allocated_group_rid)
1461 return ldap_state->low_allocated_group_rid;
1462 break;
1465 next_rid = (top_rid & ~RID_TYPE_MASK) + rid_type + RID_MULTIPLIER;
1467 switch (rid_type) {
1468 case USER_RID_TYPE:
1469 if (next_rid > ldap_state->high_allocated_user_rid) {
1470 return 0;
1472 break;
1473 case GROUP_RID_TYPE:
1474 if (next_rid > ldap_state->high_allocated_group_rid) {
1475 return 0;
1477 break;
1479 return next_rid;
1482 /**********************************************************************
1483 Add the sambaDomain to LDAP, so we don't have to search for this stuff
1484 again. This is a once-add operation for now.
1486 TODO: Add other attributes, and allow modification.
1487 *********************************************************************/
1488 static NTSTATUS add_new_domain_info(struct ldapsam_privates *ldap_state)
1490 pstring tmp;
1491 pstring filter;
1492 LDAPMod **mods = NULL;
1493 int rc;
1494 int ldap_op;
1495 LDAPMessage *result = NULL;
1496 char *dn = NULL;
1497 int num_result;
1498 char **attr_list;
1500 uint32 next_allocated_user_rid;
1501 uint32 next_allocated_group_rid;
1503 next_allocated_user_rid = search_next_allocated_rid(ldap_state, USER_RID_TYPE);
1504 if (!next_allocated_user_rid) {
1505 return NT_STATUS_UNSUCCESSFUL;
1508 next_allocated_group_rid = search_next_allocated_rid(ldap_state, GROUP_RID_TYPE);
1509 if (!next_allocated_group_rid) {
1510 return NT_STATUS_UNSUCCESSFUL;
1513 slprintf (filter, sizeof (filter) - 1, "(&(%s=%s)(objectclass=%s))",
1514 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
1515 ldap_state->domain_name, LDAP_OBJ_DOMINFO);
1517 attr_list = get_attr_list( dominfo_attr_list );
1518 rc = ldapsam_search_suffix(ldap_state, filter, attr_list, &result);
1519 free_attr_list( attr_list );
1521 if (rc != LDAP_SUCCESS) {
1522 return NT_STATUS_UNSUCCESSFUL;
1525 num_result = ldap_count_entries(ldap_state->ldap_struct, result);
1527 if (num_result > 1) {
1528 DEBUG (0, ("More than domain with that name exists: bailing out!\n"));
1529 ldap_msgfree(result);
1530 return NT_STATUS_UNSUCCESSFUL;
1533 /* Check if we need to add an entry */
1534 DEBUG(3,("Adding new domain\n"));
1535 ldap_op = LDAP_MOD_ADD;
1536 asprintf (&dn, "%s=%s,%s", get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
1537 ldap_state->domain_name, lp_ldap_suffix());
1539 /* Free original search */
1540 ldap_msgfree(result);
1542 if (!dn)
1543 return NT_STATUS_NO_MEMORY;
1545 /* make the changes - the entry *must* not already have samba attributes */
1546 make_a_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
1547 ldap_state->domain_name);
1549 sid_to_string(tmp, &ldap_state->domain_sid);
1550 make_a_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID), tmp);
1552 snprintf(tmp, sizeof(tmp)-1, "%i", next_allocated_user_rid);
1553 make_a_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID), tmp);
1555 snprintf(tmp, sizeof(tmp)-1, "%i", next_allocated_group_rid);
1556 make_a_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID), tmp);
1558 make_a_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_DOMINFO);
1560 switch(ldap_op)
1562 case LDAP_MOD_ADD:
1563 rc = ldapsam_add(ldap_state, dn, mods);
1564 break;
1565 case LDAP_MOD_REPLACE:
1566 rc = ldapsam_modify(ldap_state, dn, mods);
1567 break;
1568 default:
1569 DEBUG(0,("Wrong LDAP operation type: %d!\n", ldap_op));
1570 return NT_STATUS_INVALID_PARAMETER;
1573 if (rc!=LDAP_SUCCESS) {
1574 char *ld_error = NULL;
1575 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
1576 &ld_error);
1577 DEBUG(1,
1578 ("failed to %s domain dn= %s with: %s\n\t%s\n",
1579 ldap_op == LDAP_MOD_ADD ? "add" : "modify",
1580 dn, ldap_err2string(rc),
1581 ld_error?ld_error:"unknown"));
1582 SAFE_FREE(ld_error);
1584 ldap_mods_free(mods,1);
1585 return NT_STATUS_UNSUCCESSFUL;
1588 DEBUG(2,("added: domain = %s in the LDAP database\n", ldap_state->domain_name));
1589 ldap_mods_free(mods, 1);
1590 return NT_STATUS_OK;
1593 /**********************************************************************
1594 Even if the sambaAccount attribute in LDAP tells us that this RID is
1595 safe to use, always check before use.
1596 *********************************************************************/
1597 static BOOL sid_in_use(struct ldapsam_privates *ldap_state,
1598 const DOM_SID *sid, int *error)
1600 fstring filter;
1601 fstring sid_string;
1602 LDAPMessage *result = NULL;
1603 int count;
1604 int rc;
1605 char *sid_attr[] = {LDAP_ATTRIBUTE_SID, NULL};
1607 slprintf(filter, sizeof(filter)-1, "(%s=%s)", LDAP_ATTRIBUTE_SID, sid_to_string(sid_string, sid));
1609 rc = ldapsam_search_suffix(ldap_state, filter, sid_attr, &result);
1611 if (rc != LDAP_SUCCESS) {
1612 char *ld_error = NULL;
1613 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
1614 DEBUG(2, ("Failed to check if sid %s is alredy in use: %s\n",
1615 sid_string, ld_error));
1616 SAFE_FREE(ld_error);
1618 *error = rc;
1619 return True;
1622 if ((count = ldap_count_entries(ldap_state->ldap_struct, result)) > 0) {
1623 DEBUG(3, ("Sid %s already in use - trying next RID\n",
1624 sid_string));
1625 ldap_msgfree(result);
1626 return True;
1629 ldap_msgfree(result);
1631 /* good, sid is not in use */
1632 return False;
1635 /**********************************************************************
1636 Set the new nextRid attribute, and return one we can use.
1638 This also checks that this RID is actually free - in case the admin
1639 manually stole it :-).
1640 *********************************************************************/
1641 static NTSTATUS ldapsam_next_rid(struct ldapsam_privates *ldap_state, uint32 *rid, int rid_type)
1643 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
1644 int rc;
1645 LDAPMessage *result = NULL;
1646 LDAPMessage *entry = NULL;
1647 char *dn;
1648 LDAPMod **mods = NULL;
1649 int count;
1650 fstring old_rid_string;
1651 fstring next_rid_string;
1652 uint32 next_rid;
1653 int attempts = 0;
1655 if ( ldap_state->schema_ver != SCHEMAVER_SAMBASAMACCOUNT ) {
1656 DEBUG(0, ("Allocated RIDs require the %s objectclass used by 'ldapsam'\n",
1657 LDAP_OBJ_SAMBASAMACCOUNT));
1658 return NT_STATUS_UNSUCCESSFUL;
1661 while (attempts < 10)
1663 char *ld_error;
1664 if (ldapsam_search_domain_info(ldap_state, &result)) {
1665 return ret;
1668 if (ldap_count_entries(ldap_state->ldap_struct, result) < 1) {
1669 DEBUG(3, ("Got no domain info entries for domain %s\n",
1670 ldap_state->domain_name));
1671 ldap_msgfree(result);
1672 if (NT_STATUS_IS_OK(ret = add_new_domain_info(ldap_state))) {
1673 continue;
1674 } else {
1675 DEBUG(0, ("Adding domain info failed with %s\n", nt_errstr(ret)));
1676 return ret;
1680 if ((count = ldap_count_entries(ldap_state->ldap_struct, result)) > 1) {
1681 DEBUG(0, ("Got too many (%d) domain info entries for domain %s\n",
1682 count, ldap_state->domain_name));
1683 ldap_msgfree(result);
1684 return ret;
1687 entry = ldap_first_entry(ldap_state->ldap_struct, result);
1688 if (!entry) {
1689 ldap_msgfree(result);
1690 return ret;
1693 if ((dn = ldap_get_dn(ldap_state->ldap_struct, entry)) == NULL) {
1694 DEBUG(0, ("Could not get domain info DN\n"));
1695 ldap_msgfree(result);
1696 return ret;
1699 /* yes, we keep 2 seperate counters, to avoid stomping on the two
1700 different sets of algorithmic RIDs */
1702 switch (rid_type) {
1703 case USER_RID_TYPE:
1704 if (!get_single_attribute(ldap_state->ldap_struct, entry,
1705 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
1706 old_rid_string))
1708 ldap_memfree(dn);
1709 ldap_msgfree(result);
1710 return ret;
1712 break;
1713 case GROUP_RID_TYPE:
1714 if (!get_single_attribute(ldap_state->ldap_struct, entry,
1715 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
1716 old_rid_string))
1718 ldap_memfree(dn);
1719 ldap_msgfree(result);
1720 return ret;
1722 break;
1725 /* This is the core of the whole routine. If we had
1726 scheme-style closures, there would be a *lot* less code
1727 duplication... */
1728 *rid = (uint32)atol(old_rid_string);
1729 next_rid = *rid+RID_MULTIPLIER;
1731 slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
1733 switch (rid_type) {
1734 case USER_RID_TYPE:
1735 if (next_rid > ldap_state->high_allocated_user_rid) {
1736 return NT_STATUS_UNSUCCESSFUL;
1739 /* Try to make the modification atomically by enforcing the
1740 old value in the delete mod. */
1741 make_ldap_mod(ldap_state->ldap_struct, entry, &mods,
1742 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID),
1743 next_rid_string);
1744 break;
1746 case GROUP_RID_TYPE:
1747 if (next_rid > ldap_state->high_allocated_group_rid) {
1748 return NT_STATUS_UNSUCCESSFUL;
1751 /* Try to make the modification atomically by enforcing the
1752 old value in the delete mod. */
1753 make_ldap_mod(ldap_state->ldap_struct, entry, &mods,
1754 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
1755 next_rid_string);
1756 break;
1759 if ((rc = ldap_modify_s(ldap_state->ldap_struct, dn, mods)) == LDAP_SUCCESS) {
1760 DOM_SID dom_sid;
1761 DOM_SID sid;
1762 pstring domain_sid_string;
1763 int error = 0;
1765 if (!get_single_attribute(ldap_state->ldap_struct, result,
1766 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID),
1767 domain_sid_string))
1769 ldap_mods_free(mods, 1);
1770 ldap_memfree(dn);
1771 ldap_msgfree(result);
1772 return ret;
1775 if (!string_to_sid(&dom_sid, domain_sid_string)) {
1776 ldap_mods_free(mods, 1);
1777 ldap_memfree(dn);
1778 ldap_msgfree(result);
1779 return ret;
1782 ldap_mods_free(mods, 1);
1783 mods = NULL;
1784 ldap_memfree(dn);
1785 ldap_msgfree(result);
1787 sid_copy(&sid, &dom_sid);
1788 sid_append_rid(&sid, *rid);
1790 /* check RID is not in use */
1791 if (sid_in_use(ldap_state, &sid, &error)) {
1792 if (error) {
1793 return ret;
1795 continue;
1798 return NT_STATUS_OK;
1801 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
1802 DEBUG(2, ("Failed to modify rid: %s\n", ld_error));
1803 SAFE_FREE(ld_error);
1805 ldap_mods_free(mods, 1);
1806 mods = NULL;
1808 ldap_memfree(dn);
1809 dn = NULL;
1811 ldap_msgfree(result);
1812 result = NULL;
1815 /* Sleep for a random timeout */
1816 unsigned sleeptime = (sys_random()*sys_getpid()*attempts);
1817 attempts += 1;
1819 sleeptime %= 100;
1820 msleep(sleeptime);
1824 DEBUG(0, ("Failed to set new RID\n"));
1825 return ret;
1828 /* New Interface is being implemented here */
1830 /**********************************************************************
1831 Initialize SAM_ACCOUNT from an LDAP query (unix attributes only)
1832 *********************************************************************/
1833 static BOOL get_unix_attributes (struct ldapsam_privates *ldap_state,
1834 SAM_ACCOUNT * sampass,
1835 LDAPMessage * entry,
1836 gid_t *gid)
1838 pstring homedir;
1839 pstring temp;
1840 char **ldap_values;
1841 char **values;
1843 if ((ldap_values = ldap_get_values (ldap_state->ldap_struct, entry, "objectClass")) == NULL) {
1844 DEBUG (1, ("get_unix_attributes: no objectClass! \n"));
1845 return False;
1848 for (values=ldap_values;*values;values++) {
1849 if (strcasecmp(*values, LDAP_OBJ_POSIXACCOUNT ) == 0) {
1850 break;
1854 if (!*values) { /*end of array, no posixAccount */
1855 DEBUG(10, ("user does not have %s attributes\n", LDAP_OBJ_POSIXACCOUNT));
1856 ldap_value_free(ldap_values);
1857 return False;
1859 ldap_value_free(ldap_values);
1861 if ( !get_single_attribute(ldap_state->ldap_struct, entry,
1862 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_UNIX_HOME), homedir) )
1864 return False;
1867 if ( !get_single_attribute(ldap_state->ldap_struct, entry,
1868 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_GIDNUMBER), temp) )
1870 return False;
1873 *gid = (gid_t)atol(temp);
1875 pdb_set_unix_homedir(sampass, homedir, PDB_SET);
1877 DEBUG(10, ("user has %s attributes\n", LDAP_OBJ_POSIXACCOUNT));
1879 return True;
1883 /**********************************************************************
1884 Initialize SAM_ACCOUNT from an LDAP query
1885 (Based on init_sam_from_buffer in pdb_tdb.c)
1886 *********************************************************************/
1887 static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
1888 SAM_ACCOUNT * sampass,
1889 LDAPMessage * entry)
1891 time_t logon_time,
1892 logoff_time,
1893 kickoff_time,
1894 pass_last_set_time,
1895 pass_can_change_time,
1896 pass_must_change_time;
1897 pstring username,
1898 domain,
1899 nt_username,
1900 fullname,
1901 homedir,
1902 dir_drive,
1903 logon_script,
1904 profile_path,
1905 acct_desc,
1906 munged_dial,
1907 workstations;
1908 uint32 user_rid;
1909 uint8 smblmpwd[LM_HASH_LEN],
1910 smbntpwd[NT_HASH_LEN];
1911 uint16 acct_ctrl = 0,
1912 logon_divs;
1913 uint32 hours_len;
1914 uint8 hours[MAX_HOURS_LEN];
1915 pstring temp;
1916 uid_t uid = -1;
1917 gid_t gid = getegid();
1920 * do a little initialization
1922 username[0] = '\0';
1923 domain[0] = '\0';
1924 nt_username[0] = '\0';
1925 fullname[0] = '\0';
1926 homedir[0] = '\0';
1927 dir_drive[0] = '\0';
1928 logon_script[0] = '\0';
1929 profile_path[0] = '\0';
1930 acct_desc[0] = '\0';
1931 munged_dial[0] = '\0';
1932 workstations[0] = '\0';
1935 if (sampass == NULL || ldap_state == NULL || entry == NULL) {
1936 DEBUG(0, ("init_sam_from_ldap: NULL parameters found!\n"));
1937 return False;
1940 if (ldap_state->ldap_struct == NULL) {
1941 DEBUG(0, ("init_sam_from_ldap: ldap_state->ldap_struct is NULL!\n"));
1942 return False;
1945 if (!get_single_attribute(ldap_state->ldap_struct, entry, "uid", username)) {
1946 DEBUG(1, ("No uid attribute found for this user!\n"));
1947 return False;
1950 DEBUG(2, ("Entry found for user: %s\n", username));
1952 pstrcpy(nt_username, username);
1954 pstrcpy(domain, ldap_state->domain_name);
1956 pdb_set_username(sampass, username, PDB_SET);
1958 pdb_set_domain(sampass, domain, PDB_DEFAULT);
1959 pdb_set_nt_username(sampass, nt_username, PDB_SET);
1961 /* deal with different attributes between the schema first */
1963 if ( ldap_state->schema_ver == SCHEMAVER_SAMBASAMACCOUNT )
1965 if (get_single_attribute(ldap_state->ldap_struct, entry,
1966 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_SID), temp))
1968 pdb_set_user_sid_from_string(sampass, temp, PDB_SET);
1971 if (get_single_attribute(ldap_state->ldap_struct, entry,
1972 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PRIMARY_GROUP_SID), temp))
1974 pdb_set_group_sid_from_string(sampass, temp, PDB_SET);
1976 else
1978 pdb_set_group_sid_from_rid(sampass, DOMAIN_GROUP_RID_USERS, PDB_DEFAULT);
1983 else
1985 if (get_single_attribute(ldap_state->ldap_struct, entry,
1986 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_RID), temp))
1988 user_rid = (uint32)atol(temp);
1989 pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
1992 if (!get_single_attribute(ldap_state->ldap_struct, entry,
1993 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PRIMARY_GROUP_RID), temp))
1995 pdb_set_group_sid_from_rid(sampass, DOMAIN_GROUP_RID_USERS, PDB_DEFAULT);
1996 } else {
1997 uint32 group_rid;
1999 group_rid = (uint32)atol(temp);
2001 /* for some reason, we often have 0 as a primary group RID.
2002 Make sure that we treat this just as a 'default' value */
2004 if ( group_rid > 0 )
2005 pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
2006 else
2007 pdb_set_group_sid_from_rid(sampass, DOMAIN_GROUP_RID_USERS, PDB_DEFAULT);
2011 if (pdb_get_init_flags(sampass,PDB_USERSID) == PDB_DEFAULT) {
2012 DEBUG(1, ("no %s or %s attribute found for this user %s\n",
2013 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_SID),
2014 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_RID),
2015 username));
2016 return False;
2021 * If so configured, try and get the values from LDAP
2024 if (lp_ldap_trust_ids() && (get_unix_attributes(ldap_state, sampass, entry, &gid)))
2026 if (pdb_get_init_flags(sampass,PDB_GROUPSID) == PDB_DEFAULT)
2028 GROUP_MAP map;
2029 /* call the mapping code here */
2030 if(pdb_getgrgid(&map, gid, MAPPING_WITHOUT_PRIV)) {
2031 pdb_set_group_sid(sampass, &map.sid, PDB_SET);
2033 else {
2034 pdb_set_group_sid_from_rid(sampass, pdb_gid_to_group_rid(gid), PDB_SET);
2039 if (!get_single_attribute(ldap_state->ldap_struct, entry,
2040 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_LAST_SET), temp))
2042 /* leave as default */
2043 } else {
2044 pass_last_set_time = (time_t) atol(temp);
2045 pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
2048 if (!get_single_attribute(ldap_state->ldap_struct, entry,
2049 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGON_TIME), temp))
2051 /* leave as default */
2052 } else {
2053 logon_time = (time_t) atol(temp);
2054 pdb_set_logon_time(sampass, logon_time, PDB_SET);
2057 if (!get_single_attribute(ldap_state->ldap_struct, entry,
2058 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGOFF_TIME), temp))
2060 /* leave as default */
2061 } else {
2062 logoff_time = (time_t) atol(temp);
2063 pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
2066 if (!get_single_attribute(ldap_state->ldap_struct, entry,
2067 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_KICKOFF_TIME), temp))
2069 /* leave as default */
2070 } else {
2071 kickoff_time = (time_t) atol(temp);
2072 pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
2075 if (!get_single_attribute(ldap_state->ldap_struct, entry,
2076 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_CAN_CHANGE), temp))
2078 /* leave as default */
2079 } else {
2080 pass_can_change_time = (time_t) atol(temp);
2081 pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
2084 if (!get_single_attribute(ldap_state->ldap_struct, entry,
2085 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_MUST_CHANGE), temp))
2087 /* leave as default */
2088 } else {
2089 pass_must_change_time = (time_t) atol(temp);
2090 pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
2093 /* recommend that 'gecos' and 'displayName' should refer to the same
2094 * attribute OID. userFullName depreciated, only used by Samba
2095 * primary rules of LDAP: don't make a new attribute when one is already defined
2096 * that fits your needs; using cn then displayName rather than 'userFullName'
2099 if (!get_single_attribute(ldap_state->ldap_struct, entry,
2100 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_DISPLAY_NAME), fullname))
2102 if (!get_single_attribute(ldap_state->ldap_struct, entry,
2103 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_CN), fullname))
2105 /* leave as default */
2106 } else {
2107 pdb_set_fullname(sampass, fullname, PDB_SET);
2109 } else {
2110 pdb_set_fullname(sampass, fullname, PDB_SET);
2113 if (!get_single_attribute(ldap_state->ldap_struct, entry,
2114 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_HOME_DRIVE), dir_drive))
2116 pdb_set_dir_drive(sampass, talloc_sub_specified(sampass->mem_ctx,
2117 lp_logon_drive(),
2118 username, domain,
2119 uid, gid),
2120 PDB_DEFAULT);
2121 } else {
2122 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
2125 if (!get_single_attribute(ldap_state->ldap_struct, entry,
2126 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_HOME_PATH), homedir))
2128 pdb_set_homedir(sampass, talloc_sub_specified(sampass->mem_ctx,
2129 lp_logon_home(),
2130 username, domain,
2131 uid, gid),
2132 PDB_DEFAULT);
2133 } else {
2134 pdb_set_homedir(sampass, homedir, PDB_SET);
2137 if (!get_single_attribute(ldap_state->ldap_struct, entry,
2138 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGON_SCRIPT), logon_script))
2140 pdb_set_logon_script(sampass, talloc_sub_specified(sampass->mem_ctx,
2141 lp_logon_script(),
2142 username, domain,
2143 uid, gid),
2144 PDB_DEFAULT);
2145 } else {
2146 pdb_set_logon_script(sampass, logon_script, PDB_SET);
2149 if (!get_single_attribute(ldap_state->ldap_struct, entry,
2150 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PROFILE_PATH), profile_path))
2152 pdb_set_profile_path(sampass, talloc_sub_specified(sampass->mem_ctx,
2153 lp_logon_path(),
2154 username, domain,
2155 uid, gid),
2156 PDB_DEFAULT);
2157 } else {
2158 pdb_set_profile_path(sampass, profile_path, PDB_SET);
2161 if (!get_single_attribute(ldap_state->ldap_struct, entry,
2162 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_DESC), acct_desc))
2164 /* leave as default */
2165 } else {
2166 pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
2169 if (!get_single_attribute(ldap_state->ldap_struct, entry,
2170 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_WKS), workstations))
2172 /* leave as default */;
2173 } else {
2174 pdb_set_workstations(sampass, workstations, PDB_SET);
2177 /* FIXME: hours stuff should be cleaner */
2179 logon_divs = 168;
2180 hours_len = 21;
2181 memset(hours, 0xff, hours_len);
2183 if (!get_single_attribute (ldap_state->ldap_struct, entry,
2184 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LMPW), temp))
2186 /* leave as default */
2187 } else {
2188 pdb_gethexpwd(temp, smblmpwd);
2189 memset((char *)temp, '\0', strlen(temp)+1);
2190 if (!pdb_set_lanman_passwd(sampass, smblmpwd, PDB_SET))
2191 return False;
2192 ZERO_STRUCT(smblmpwd);
2195 if (!get_single_attribute (ldap_state->ldap_struct, entry,
2196 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_NTPW), temp))
2198 /* leave as default */
2199 } else {
2200 pdb_gethexpwd(temp, smbntpwd);
2201 memset((char *)temp, '\0', strlen(temp)+1);
2202 if (!pdb_set_nt_passwd(sampass, smbntpwd, PDB_SET))
2203 return False;
2204 ZERO_STRUCT(smbntpwd);
2207 if (!get_single_attribute (ldap_state->ldap_struct, entry,
2208 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_ACB_INFO), temp))
2210 acct_ctrl |= ACB_NORMAL;
2211 } else {
2212 acct_ctrl = pdb_decode_acct_ctrl(temp);
2214 if (acct_ctrl == 0)
2215 acct_ctrl |= ACB_NORMAL;
2217 pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
2220 pdb_set_hours_len(sampass, hours_len, PDB_SET);
2221 pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
2223 pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
2225 /* pdb_set_unknown_3(sampass, unknown3, PDB_SET); */
2226 /* pdb_set_unknown_5(sampass, unknown5, PDB_SET); */
2227 /* pdb_set_unknown_6(sampass, unknown6, PDB_SET); */
2229 pdb_set_hours(sampass, hours, PDB_SET);
2231 return True;
2234 /**********************************************************************
2235 Initialize SAM_ACCOUNT from an LDAP query
2236 (Based on init_buffer_from_sam in pdb_tdb.c)
2237 *********************************************************************/
2238 static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state,
2239 LDAPMessage *existing,
2240 LDAPMod *** mods, SAM_ACCOUNT * sampass,
2241 BOOL (*need_update)(const SAM_ACCOUNT *,
2242 enum pdb_elements))
2244 pstring temp;
2245 uint32 rid;
2247 if (mods == NULL || sampass == NULL) {
2248 DEBUG(0, ("init_ldap_from_sam: NULL parameters found!\n"));
2249 return False;
2252 *mods = NULL;
2255 * took out adding "objectclass: sambaAccount"
2256 * do this on a per-mod basis
2258 if (need_update(sampass, PDB_USERNAME))
2259 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2260 "uid", pdb_get_username(sampass));
2262 DEBUG(2, ("Setting entry for user: %s\n", pdb_get_username(sampass)));
2264 if (pdb_get_init_flags(sampass, PDB_USERSID) == PDB_DEFAULT) {
2265 if (ldap_state->permit_non_unix_accounts) {
2266 if (!NT_STATUS_IS_OK(ldapsam_next_rid(ldap_state, &rid, USER_RID_TYPE))) {
2267 DEBUG(0, ("NO user RID specified on account %s, and "
2268 "finding next available NUA RID failed, "
2269 "cannot store!\n",
2270 pdb_get_username(sampass)));
2271 ldap_mods_free(*mods, 1);
2272 return False;
2274 } else {
2275 DEBUG(0, ("NO user RID specified on account %s, "
2276 "cannot store!\n", pdb_get_username(sampass)));
2277 ldap_mods_free(*mods, 1);
2278 return False;
2281 /* now that we have figured out the RID, always store it, as
2282 the schema requires it (either as a SID or a RID) */
2284 if (!pdb_set_user_sid_from_rid(sampass, rid, PDB_CHANGED)) {
2285 DEBUG(0, ("Could not store RID back onto SAM_ACCOUNT for user %s!\n",
2286 pdb_get_username(sampass)));
2287 ldap_mods_free(*mods, 1);
2288 return False;
2292 /* only update the RID if we actually need to */
2293 if (need_update(sampass, PDB_USERSID))
2295 fstring sid_string;
2296 fstring dom_sid_string;
2297 const DOM_SID *user_sid = pdb_get_user_sid(sampass);
2299 switch ( ldap_state->schema_ver )
2301 case SCHEMAVER_SAMBAACCOUNT:
2302 if (!sid_peek_check_rid(get_global_sam_sid(), user_sid, &rid)) {
2303 DEBUG(1, ("User's SID (%s) is not for this domain (%s), cannot add to LDAP!\n",
2304 sid_to_string(sid_string, user_sid),
2305 sid_to_string(dom_sid_string, get_global_sam_sid())));
2306 return False;
2308 slprintf(temp, sizeof(temp) - 1, "%i", rid);
2309 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2310 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_RID),
2311 temp);
2312 break;
2314 case SCHEMAVER_SAMBASAMACCOUNT:
2315 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2316 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_SID),
2317 sid_to_string(sid_string, user_sid));
2318 break;
2320 default:
2321 DEBUG(0,("init_ldap_from_sam: unknown schema version specified\n"));
2322 break;
2326 /* we don't need to store the primary group RID - so leaving it
2327 'free' to hang off the unix primary group makes life easier */
2329 if (need_update(sampass, PDB_GROUPSID))
2331 fstring sid_string;
2332 fstring dom_sid_string;
2333 const DOM_SID *group_sid = pdb_get_group_sid(sampass);
2335 switch ( ldap_state->schema_ver )
2337 case SCHEMAVER_SAMBAACCOUNT:
2338 if (!sid_peek_check_rid(get_global_sam_sid(), group_sid, &rid)) {
2339 DEBUG(1, ("User's Primary Group SID (%s) is not for this domain (%s), cannot add to LDAP!\n",
2340 sid_to_string(sid_string, group_sid),
2341 sid_to_string(dom_sid_string, get_global_sam_sid())));
2342 return False;
2345 slprintf(temp, sizeof(temp) - 1, "%i", rid);
2346 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2347 get_userattr_key2string(ldap_state->schema_ver,
2348 LDAP_ATTR_PRIMARY_GROUP_RID), temp);
2349 break;
2351 case SCHEMAVER_SAMBASAMACCOUNT:
2352 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2353 get_userattr_key2string(ldap_state->schema_ver,
2354 LDAP_ATTR_PRIMARY_GROUP_SID), sid_to_string(sid_string, group_sid));
2355 break;
2357 default:
2358 DEBUG(0,("init_ldap_from_sam: unknown schema version specified\n"));
2359 break;
2364 /* displayName, cn, and gecos should all be the same
2365 * most easily accomplished by giving them the same OID
2366 * gecos isn't set here b/c it should be handled by the
2367 * add-user script
2368 * We change displayName only and fall back to cn if
2369 * it does not exist.
2372 if (need_update(sampass, PDB_FULLNAME))
2373 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2374 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_DISPLAY_NAME),
2375 pdb_get_fullname(sampass));
2377 if (need_update(sampass, PDB_ACCTDESC))
2378 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2379 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_DESC),
2380 pdb_get_acct_desc(sampass));
2382 if (need_update(sampass, PDB_WORKSTATIONS))
2383 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2384 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_WKS),
2385 pdb_get_workstations(sampass));
2387 if (need_update(sampass, PDB_SMBHOME))
2388 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2389 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_HOME_PATH),
2390 pdb_get_homedir(sampass));
2392 if (need_update(sampass, PDB_DRIVE))
2393 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2394 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_HOME_DRIVE),
2395 pdb_get_dir_drive(sampass));
2397 if (need_update(sampass, PDB_LOGONSCRIPT))
2398 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2399 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGON_SCRIPT),
2400 pdb_get_logon_script(sampass));
2402 if (need_update(sampass, PDB_PROFILE))
2403 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2404 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PROFILE_PATH),
2405 pdb_get_profile_path(sampass));
2407 slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logon_time(sampass));
2408 if (need_update(sampass, PDB_LOGONTIME))
2409 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2410 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGON_TIME), temp);
2412 slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logoff_time(sampass));
2413 if (need_update(sampass, PDB_LOGOFFTIME))
2414 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2415 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGOFF_TIME), temp);
2417 slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_kickoff_time(sampass));
2418 if (need_update(sampass, PDB_KICKOFFTIME))
2419 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2420 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_KICKOFF_TIME), temp);
2422 slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_can_change_time(sampass));
2423 if (need_update(sampass, PDB_CANCHANGETIME))
2424 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2425 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_CAN_CHANGE), temp);
2427 slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_must_change_time(sampass));
2428 if (need_update(sampass, PDB_MUSTCHANGETIME))
2429 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2430 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_MUST_CHANGE), temp);
2432 if ((pdb_get_acct_ctrl(sampass)&(ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST))
2433 || (lp_ldap_passwd_sync()!=LDAP_PASSWD_SYNC_ONLY))
2436 pdb_sethexpwd(temp, pdb_get_lanman_passwd(sampass),
2437 pdb_get_acct_ctrl(sampass));
2439 if (need_update(sampass, PDB_LMPASSWD))
2440 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2441 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LMPW),
2442 temp);
2444 pdb_sethexpwd (temp, pdb_get_nt_passwd(sampass),
2445 pdb_get_acct_ctrl(sampass));
2447 if (need_update(sampass, PDB_NTPASSWD))
2448 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2449 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_NTPW),
2450 temp);
2452 slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_last_set_time(sampass));
2453 if (need_update(sampass, PDB_PASSLASTSET))
2454 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2455 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_LAST_SET),
2456 temp);
2459 /* FIXME: Hours stuff goes in LDAP */
2461 if (need_update(sampass, PDB_ACCTCTRL))
2462 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2463 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_ACB_INFO),
2464 pdb_encode_acct_ctrl (pdb_get_acct_ctrl(sampass), NEW_PW_FORMAT_SPACE_PADDED_LEN));
2466 return True;
2471 /**********************************************************************
2472 Connect to LDAP server for password enumeration
2473 *********************************************************************/
2474 static NTSTATUS ldapsam_setsampwent(struct pdb_methods *my_methods, BOOL update)
2476 struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2477 int rc;
2478 pstring filter;
2479 char **attr_list;
2481 snprintf( filter, sizeof(filter)-1, "(&%s%s)", lp_ldap_filter(),
2482 get_objclass_filter(ldap_state->schema_ver));
2483 all_string_sub(filter, "%u", "*", sizeof(pstring));
2485 attr_list = get_userattr_list(ldap_state->schema_ver);
2486 rc = ldapsam_search_suffix(ldap_state, filter, attr_list, &ldap_state->result);
2487 free_attr_list( attr_list );
2489 if (rc != LDAP_SUCCESS) {
2490 DEBUG(0, ("LDAP search failed: %s\n", ldap_err2string(rc)));
2491 DEBUG(3, ("Query was: %s, %s\n", lp_ldap_suffix(), filter));
2492 ldap_msgfree(ldap_state->result);
2493 ldap_state->result = NULL;
2494 return NT_STATUS_UNSUCCESSFUL;
2497 DEBUG(2, ("ldapsam_setsampwent: %d entries in the base!\n",
2498 ldap_count_entries(ldap_state->ldap_struct,
2499 ldap_state->result)));
2501 ldap_state->entry = ldap_first_entry(ldap_state->ldap_struct,
2502 ldap_state->result);
2503 ldap_state->index = 0;
2505 return NT_STATUS_OK;
2508 /**********************************************************************
2509 End enumeration of the LDAP password list
2510 *********************************************************************/
2511 static void ldapsam_endsampwent(struct pdb_methods *my_methods)
2513 struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2514 if (ldap_state->result) {
2515 ldap_msgfree(ldap_state->result);
2516 ldap_state->result = NULL;
2520 /**********************************************************************
2521 Get the next entry in the LDAP password database
2522 *********************************************************************/
2523 static NTSTATUS ldapsam_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUNT *user)
2525 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
2526 struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2527 BOOL bret = False;
2529 /* The rebind proc needs this *HACK*. We are not multithreaded, so
2530 this will work, but it's not nice. */
2531 static_ldap_state = ldap_state;
2533 while (!bret) {
2534 if (!ldap_state->entry)
2535 return ret;
2537 ldap_state->index++;
2538 bret = init_sam_from_ldap(ldap_state, user, ldap_state->entry);
2540 ldap_state->entry = ldap_next_entry(ldap_state->ldap_struct,
2541 ldap_state->entry);
2544 return NT_STATUS_OK;
2547 /**********************************************************************
2548 Get SAM_ACCOUNT entry from LDAP by username
2549 *********************************************************************/
2550 static NTSTATUS ldapsam_getsampwnam(struct pdb_methods *my_methods, SAM_ACCOUNT *user, const char *sname)
2552 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
2553 struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2554 LDAPMessage *result;
2555 LDAPMessage *entry;
2556 int count;
2557 char ** attr_list;
2558 int rc;
2560 attr_list = get_userattr_list( ldap_state->schema_ver );
2561 rc = ldapsam_search_suffix_by_name(ldap_state, sname, &result, attr_list);
2562 free_attr_list( attr_list );
2564 if ( rc != LDAP_SUCCESS )
2565 return NT_STATUS_NO_SUCH_USER;
2567 count = ldap_count_entries(ldap_state->ldap_struct, result);
2569 if (count < 1) {
2570 DEBUG(4,
2571 ("Unable to locate user [%s] count=%d\n", sname,
2572 count));
2573 return NT_STATUS_NO_SUCH_USER;
2574 } else if (count > 1) {
2575 DEBUG(1,
2576 ("Duplicate entries for this user [%s] Failing. count=%d\n", sname,
2577 count));
2578 return NT_STATUS_NO_SUCH_USER;
2581 entry = ldap_first_entry(ldap_state->ldap_struct, result);
2582 if (entry) {
2583 if (!init_sam_from_ldap(ldap_state, user, entry)) {
2584 DEBUG(1,("ldapsam_getsampwnam: init_sam_from_ldap failed for user '%s'!\n", sname));
2585 ldap_msgfree(result);
2586 return NT_STATUS_NO_SUCH_USER;
2588 ldap_msgfree(result);
2589 ret = NT_STATUS_OK;
2590 } else {
2591 ldap_msgfree(result);
2593 return ret;
2596 /**********************************************************************
2597 Get SAM_ACCOUNT entry from LDAP by SID
2598 *********************************************************************/
2599 static NTSTATUS ldapsam_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT * user, const DOM_SID *sid)
2601 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
2602 struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2603 LDAPMessage *result;
2604 LDAPMessage *entry;
2605 fstring sid_string;
2606 int count;
2607 int rc;
2608 char ** attr_list;
2610 switch ( ldap_state->schema_ver )
2612 case SCHEMAVER_SAMBASAMACCOUNT:
2613 attr_list = get_userattr_list(ldap_state->schema_ver);
2614 rc = ldapsam_search_suffix_by_sid(ldap_state, sid, &result, attr_list);
2615 free_attr_list( attr_list );
2617 if ( rc != LDAP_SUCCESS )
2618 return NT_STATUS_NO_SUCH_USER;
2619 break;
2621 case SCHEMAVER_SAMBAACCOUNT:
2623 uint32 rid;
2624 if (!sid_peek_check_rid(get_global_sam_sid(), sid, &rid)) {
2625 return NT_STATUS_NO_SUCH_USER;
2628 attr_list = get_userattr_list(ldap_state->schema_ver);
2629 rc = ldapsam_search_suffix_by_rid(ldap_state, rid, &result, attr_list );
2630 free_attr_list( attr_list );
2632 if ( rc != LDAP_SUCCESS )
2633 return NT_STATUS_NO_SUCH_USER;
2635 break;
2638 count = ldap_count_entries(ldap_state->ldap_struct, result);
2640 if (count < 1)
2642 DEBUG(4,
2643 ("Unable to locate SID [%s] count=%d\n", sid_to_string(sid_string, sid),
2644 count));
2645 return NT_STATUS_NO_SUCH_USER;
2647 else if (count > 1)
2649 DEBUG(1,
2650 ("More than one user with SID [%s]. Failing. count=%d\n", sid_to_string(sid_string, sid),
2651 count));
2652 return NT_STATUS_NO_SUCH_USER;
2655 entry = ldap_first_entry(ldap_state->ldap_struct, result);
2656 if (entry)
2658 if (!init_sam_from_ldap(ldap_state, user, entry)) {
2659 DEBUG(1,("ldapsam_getsampwrid: init_sam_from_ldap failed!\n"));
2660 ldap_msgfree(result);
2661 return NT_STATUS_NO_SUCH_USER;
2663 ldap_msgfree(result);
2664 ret = NT_STATUS_OK;
2665 } else {
2666 ldap_msgfree(result);
2668 return ret;
2671 /********************************************************************
2672 Do the actual modification - also change a plaittext passord if
2673 it it set.
2674 **********************************************************************/
2676 static NTSTATUS ldapsam_modify_entry(struct pdb_methods *my_methods,
2677 SAM_ACCOUNT *newpwd, char *dn,
2678 LDAPMod **mods, int ldap_op,
2679 BOOL (*need_update)(const SAM_ACCOUNT *,
2680 enum pdb_elements))
2682 struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2683 int rc;
2685 if (!my_methods || !newpwd || !dn) {
2686 return NT_STATUS_INVALID_PARAMETER;
2689 if (!mods) {
2690 DEBUG(5,("mods is empty: nothing to modify\n"));
2691 /* may be password change below however */
2692 } else {
2693 switch(ldap_op)
2695 case LDAP_MOD_ADD:
2696 make_a_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_ACCOUNT);
2697 rc = ldapsam_add(ldap_state, dn, mods);
2698 break;
2699 case LDAP_MOD_REPLACE:
2700 rc = ldapsam_modify(ldap_state, dn ,mods);
2701 break;
2702 default:
2703 DEBUG(0,("Wrong LDAP operation type: %d!\n", ldap_op));
2704 return NT_STATUS_INVALID_PARAMETER;
2707 if (rc!=LDAP_SUCCESS) {
2708 char *ld_error = NULL;
2709 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
2710 &ld_error);
2711 DEBUG(1,
2712 ("failed to %s user dn= %s with: %s\n\t%s\n",
2713 ldap_op == LDAP_MOD_ADD ? "add" : "modify",
2714 dn, ldap_err2string(rc),
2715 ld_error?ld_error:"unknown"));
2716 SAFE_FREE(ld_error);
2717 return NT_STATUS_UNSUCCESSFUL;
2721 #ifdef LDAP_EXOP_X_MODIFY_PASSWD
2722 if (!(pdb_get_acct_ctrl(newpwd)&(ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST)) &&
2723 (lp_ldap_passwd_sync() != LDAP_PASSWD_SYNC_OFF) &&
2724 need_update(newpwd, PDB_PLAINTEXT_PW) &&
2725 (pdb_get_plaintext_passwd(newpwd)!=NULL)) {
2726 BerElement *ber;
2727 struct berval *bv;
2728 char *retoid;
2729 struct berval *retdata;
2730 char *utf8_password;
2731 char *utf8_dn;
2733 if (push_utf8_allocate(&utf8_password, pdb_get_plaintext_passwd(newpwd)) == (size_t)-1) {
2734 return NT_STATUS_NO_MEMORY;
2737 if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
2738 return NT_STATUS_NO_MEMORY;
2741 if ((ber = ber_alloc_t(LBER_USE_DER))==NULL) {
2742 DEBUG(0,("ber_alloc_t returns NULL\n"));
2743 SAFE_FREE(utf8_password);
2744 return NT_STATUS_UNSUCCESSFUL;
2747 ber_printf (ber, "{");
2748 ber_printf (ber, "ts", LDAP_TAG_EXOP_X_MODIFY_PASSWD_ID, utf8_dn);
2749 ber_printf (ber, "ts", LDAP_TAG_EXOP_X_MODIFY_PASSWD_NEW, utf8_password);
2750 ber_printf (ber, "N}");
2752 if ((rc = ber_flatten (ber, &bv))<0) {
2753 DEBUG(0,("ber_flatten returns a value <0\n"));
2754 ber_free(ber,1);
2755 SAFE_FREE(utf8_dn);
2756 SAFE_FREE(utf8_password);
2757 return NT_STATUS_UNSUCCESSFUL;
2760 SAFE_FREE(utf8_dn);
2761 SAFE_FREE(utf8_password);
2762 ber_free(ber, 1);
2764 if ((rc = ldapsam_extended_operation(ldap_state, LDAP_EXOP_X_MODIFY_PASSWD,
2765 bv, NULL, NULL, &retoid, &retdata))!=LDAP_SUCCESS) {
2766 DEBUG(0,("LDAP Password could not be changed for user %s: %s\n",
2767 pdb_get_username(newpwd),ldap_err2string(rc)));
2768 } else {
2769 DEBUG(3,("LDAP Password changed for user %s\n",pdb_get_username(newpwd)));
2770 #ifdef DEBUG_PASSWORD
2771 DEBUG(100,("LDAP Password changed to %s\n",pdb_get_plaintext_passwd(newpwd)));
2772 #endif
2773 ber_bvfree(retdata);
2774 ber_memfree(retoid);
2776 ber_bvfree(bv);
2778 #else
2779 DEBUG(10,("LDAP PASSWORD SYNC is not supported!\n"));
2780 #endif /* LDAP_EXOP_X_MODIFY_PASSWD */
2781 return NT_STATUS_OK;
2784 /**********************************************************************
2785 Delete entry from LDAP for username
2786 *********************************************************************/
2787 static NTSTATUS ldapsam_delete_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT * sam_acct)
2789 struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2790 const char *sname;
2791 int rc;
2792 LDAPMessage *result;
2793 NTSTATUS ret;
2794 char **attr_list;
2795 fstring objclass;
2797 if (!sam_acct) {
2798 DEBUG(0, ("sam_acct was NULL!\n"));
2799 return NT_STATUS_INVALID_PARAMETER;
2802 sname = pdb_get_username(sam_acct);
2804 DEBUG (3, ("Deleting user %s from LDAP.\n", sname));
2806 attr_list= get_userattr_list( ldap_state->schema_ver );
2807 rc = ldapsam_search_suffix_by_name(ldap_state, sname, &result, attr_list);
2809 if (rc != LDAP_SUCCESS) {
2810 free_attr_list( attr_list );
2811 return NT_STATUS_NO_SUCH_USER;
2814 switch ( ldap_state->schema_ver )
2816 case SCHEMAVER_SAMBASAMACCOUNT:
2817 fstrcpy( objclass, LDAP_OBJ_SAMBASAMACCOUNT );
2818 break;
2820 case SCHEMAVER_SAMBAACCOUNT:
2821 fstrcpy( objclass, LDAP_OBJ_SAMBAACCOUNT );
2822 break;
2823 default:
2824 fstrcpy( objclass, "UNKNOWN" );
2825 DEBUG(0,("ldapsam_delete_sam_account: Unknown schema version specified!\n"));
2826 break;
2829 ret = ldapsam_delete_entry(ldap_state, result, objclass, attr_list );
2830 ldap_msgfree(result);
2831 free_attr_list( attr_list );
2833 return ret;
2836 /**********************************************************************
2837 Helper function to determine for update_sam_account whether
2838 we need LDAP modification.
2839 *********************************************************************/
2840 static BOOL element_is_changed(const SAM_ACCOUNT *sampass,
2841 enum pdb_elements element)
2843 return IS_SAM_CHANGED(sampass, element);
2846 /**********************************************************************
2847 Update SAM_ACCOUNT
2848 *********************************************************************/
2849 static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT * newpwd)
2851 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
2852 struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2853 int rc;
2854 char *dn;
2855 LDAPMessage *result;
2856 LDAPMessage *entry;
2857 LDAPMod **mods;
2858 char **attr_list;
2860 attr_list = get_userattr_list(ldap_state->schema_ver);
2861 rc = ldapsam_search_suffix_by_name(ldap_state, pdb_get_username(newpwd), &result, attr_list );
2862 free_attr_list( attr_list );
2863 if (rc != LDAP_SUCCESS)
2864 return NT_STATUS_UNSUCCESSFUL;
2866 if (ldap_count_entries(ldap_state->ldap_struct, result) == 0) {
2867 DEBUG(0, ("No user to modify!\n"));
2868 ldap_msgfree(result);
2869 return NT_STATUS_UNSUCCESSFUL;
2872 entry = ldap_first_entry(ldap_state->ldap_struct, result);
2873 dn = ldap_get_dn(ldap_state->ldap_struct, entry);
2875 if (!init_ldap_from_sam(ldap_state, entry, &mods, newpwd,
2876 element_is_changed)) {
2877 DEBUG(0, ("ldapsam_update_sam_account: init_ldap_from_sam failed!\n"));
2878 ldap_msgfree(result);
2879 return NT_STATUS_UNSUCCESSFUL;
2882 ldap_msgfree(result);
2884 if (mods == NULL) {
2885 DEBUG(4,("mods is empty: nothing to update for user: %s\n",
2886 pdb_get_username(newpwd)));
2887 ldap_mods_free(mods, 1);
2888 return NT_STATUS_OK;
2891 ret = ldapsam_modify_entry(my_methods,newpwd,dn,mods,LDAP_MOD_REPLACE, element_is_changed);
2892 ldap_mods_free(mods,1);
2894 if (!NT_STATUS_IS_OK(ret)) {
2895 char *ld_error = NULL;
2896 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
2897 &ld_error);
2898 DEBUG(0,("failed to modify user with uid = %s, error: %s (%s)\n",
2899 pdb_get_username(newpwd), ld_error?ld_error:"(unknwon)", ldap_err2string(rc)));
2900 SAFE_FREE(ld_error);
2901 return ret;
2904 DEBUG(2, ("successfully modified uid = %s in the LDAP database\n",
2905 pdb_get_username(newpwd)));
2906 return NT_STATUS_OK;
2909 /**********************************************************************
2910 Helper function to determine for update_sam_account whether
2911 we need LDAP modification.
2912 *********************************************************************/
2913 static BOOL element_is_set_or_changed(const SAM_ACCOUNT *sampass,
2914 enum pdb_elements element)
2916 return (IS_SAM_SET(sampass, element) ||
2917 IS_SAM_CHANGED(sampass, element));
2920 /**********************************************************************
2921 Add SAM_ACCOUNT to LDAP
2922 *********************************************************************/
2924 static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT * newpwd)
2926 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
2927 struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2928 int rc;
2929 LDAPMessage *result = NULL;
2930 LDAPMessage *entry = NULL;
2931 pstring dn;
2932 LDAPMod **mods = NULL;
2933 int ldap_op;
2934 uint32 num_result;
2935 char **attr_list;
2936 char *escape_user;
2937 const char *username = pdb_get_username(newpwd);
2938 pstring filter;
2940 if (!username || !*username) {
2941 DEBUG(0, ("Cannot add user without a username!\n"));
2942 return NT_STATUS_INVALID_PARAMETER;
2945 /* free this list after the second search or in case we exit on failure */
2947 attr_list = get_userattr_list(ldap_state->schema_ver);
2948 rc = ldapsam_search_suffix_by_name (ldap_state, username, &result, attr_list);
2950 if (rc != LDAP_SUCCESS) {
2951 free_attr_list( attr_list );
2952 return NT_STATUS_UNSUCCESSFUL;
2955 if (ldap_count_entries(ldap_state->ldap_struct, result) != 0) {
2956 DEBUG(0,("User '%s' already in the base, with samba attributes\n",
2957 username));
2958 ldap_msgfree(result);
2959 free_attr_list( attr_list );
2960 return NT_STATUS_UNSUCCESSFUL;
2962 ldap_msgfree(result);
2964 /* does the entry already exist but without a samba rttibutes?
2965 we don't really care what attributes are returned here */
2967 escape_user = escape_ldap_string_alloc( username );
2968 pstrcpy( filter, lp_ldap_filter() );
2969 all_string_sub( filter, "%u", escape_user, sizeof(filter) );
2970 SAFE_FREE( escape_user );
2972 rc = ldapsam_search_suffix(ldap_state, filter, attr_list, &result);
2973 free_attr_list( attr_list );
2975 if ( rc != LDAP_SUCCESS )
2976 return NT_STATUS_UNSUCCESSFUL;
2978 num_result = ldap_count_entries(ldap_state->ldap_struct, result);
2980 if (num_result > 1) {
2981 DEBUG (0, ("More than one user with that uid exists: bailing out!\n"));
2982 ldap_msgfree(result);
2983 return NT_STATUS_UNSUCCESSFUL;
2986 /* Check if we need to update an existing entry */
2987 if (num_result == 1) {
2988 char *tmp;
2990 DEBUG(3,("User exists without samba attributes: adding them\n"));
2991 ldap_op = LDAP_MOD_REPLACE;
2992 entry = ldap_first_entry (ldap_state->ldap_struct, result);
2993 tmp = ldap_get_dn (ldap_state->ldap_struct, entry);
2994 slprintf (dn, sizeof (dn) - 1, "%s", tmp);
2995 ldap_memfree (tmp);
2996 } else {
2997 /* Check if we need to add an entry */
2998 DEBUG(3,("Adding new user\n"));
2999 ldap_op = LDAP_MOD_ADD;
3000 if (username[strlen(username)-1] == '$') {
3001 slprintf (dn, sizeof (dn) - 1, "uid=%s,%s", username, lp_ldap_machine_suffix ());
3002 } else {
3003 slprintf (dn, sizeof (dn) - 1, "uid=%s,%s", username, lp_ldap_user_suffix ());
3007 if (!init_ldap_from_sam(ldap_state, entry, &mods, newpwd,
3008 element_is_set_or_changed)) {
3009 DEBUG(0, ("ldapsam_add_sam_account: init_ldap_from_sam failed!\n"));
3010 ldap_msgfree(result);
3011 return NT_STATUS_UNSUCCESSFUL;
3014 ldap_msgfree(result);
3016 if (mods == NULL) {
3017 DEBUG(0,("mods is empty: nothing to add for user: %s\n",pdb_get_username(newpwd)));
3018 return NT_STATUS_UNSUCCESSFUL;
3020 switch ( ldap_state->schema_ver )
3022 case SCHEMAVER_SAMBAACCOUNT:
3023 make_a_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_SAMBAACCOUNT);
3024 break;
3025 case SCHEMAVER_SAMBASAMACCOUNT:
3026 make_a_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_SAMBASAMACCOUNT);
3027 break;
3028 default:
3029 DEBUG(0,("ldapsam_add_sam_account: invalid schema version specified\n"));
3030 break;
3033 ret = ldapsam_modify_entry(my_methods,newpwd,dn,mods,ldap_op, element_is_set_or_changed);
3034 if (NT_STATUS_IS_ERR(ret)) {
3035 DEBUG(0,("failed to modify/add user with uid = %s (dn = %s)\n",
3036 pdb_get_username(newpwd),dn));
3037 ldap_mods_free(mods,1);
3038 return ret;
3041 DEBUG(2,("added: uid == %s in the LDAP database\n", pdb_get_username(newpwd)));
3042 ldap_mods_free(mods, 1);
3044 return NT_STATUS_OK;
3047 /**********************************************************************
3048 Housekeeping
3049 *********************************************************************/
3051 static void free_private_data(void **vp)
3053 struct ldapsam_privates **ldap_state = (struct ldapsam_privates **)vp;
3055 ldapsam_close(*ldap_state);
3057 if ((*ldap_state)->bind_secret) {
3058 memset((*ldap_state)->bind_secret, '\0', strlen((*ldap_state)->bind_secret));
3061 ldapsam_close(*ldap_state);
3063 SAFE_FREE((*ldap_state)->bind_dn);
3064 SAFE_FREE((*ldap_state)->bind_secret);
3066 *ldap_state = NULL;
3068 /* No need to free any further, as it is talloc()ed */
3071 /**********************************************************************
3072 *********************************************************************/
3074 static int ldapsam_search_one_group (struct ldapsam_privates *ldap_state,
3075 const char *filter,
3076 LDAPMessage ** result)
3078 int scope = LDAP_SCOPE_SUBTREE;
3079 int rc;
3080 char **attr_list;
3082 DEBUG(2, ("ldapsam_search_one_group: searching for:[%s]\n", filter));
3085 attr_list = get_attr_list(groupmap_attr_list);
3086 rc = ldapsam_search(ldap_state, lp_ldap_suffix (), scope,
3087 filter, attr_list, 0, result);
3088 free_attr_list( attr_list );
3090 if (rc != LDAP_SUCCESS) {
3091 char *ld_error = NULL;
3092 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
3093 &ld_error);
3094 DEBUG(0, ("ldapsam_search_one_group: "
3095 "Problem during the LDAP search: LDAP error: %s (%s)",
3096 ld_error?ld_error:"(unknown)", ldap_err2string(rc)));
3097 DEBUG(3, ("ldapsam_search_one_group: Query was: %s, %s\n",
3098 lp_ldap_suffix(), filter));
3099 SAFE_FREE(ld_error);
3102 return rc;
3105 /**********************************************************************
3106 *********************************************************************/
3108 static BOOL init_group_from_ldap(struct ldapsam_privates *ldap_state,
3109 GROUP_MAP *map, LDAPMessage *entry)
3111 pstring temp;
3113 if (ldap_state == NULL || map == NULL || entry == NULL ||
3114 ldap_state->ldap_struct == NULL)
3116 DEBUG(0, ("init_group_from_ldap: NULL parameters found!\n"));
3117 return False;
3120 if (!get_single_attribute(ldap_state->ldap_struct, entry,
3121 get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GIDNUMBER), temp))
3123 DEBUG(0, ("Mandatory attribute %s not found\n",
3124 get_attr_key2string( groupmap_attr_list, LDAP_ATTR_GIDNUMBER)));
3125 return False;
3127 DEBUG(2, ("Entry found for group: %s\n", temp));
3129 map->gid = (gid_t)atol(temp);
3131 if (!get_single_attribute(ldap_state->ldap_struct, entry,
3132 get_attr_key2string( groupmap_attr_list, LDAP_ATTR_GROUP_SID), temp))
3134 DEBUG(0, ("Mandatory attribute %s not found\n",
3135 get_attr_key2string( groupmap_attr_list, LDAP_ATTR_GROUP_SID)));
3136 return False;
3138 string_to_sid(&map->sid, temp);
3140 if (!get_single_attribute(ldap_state->ldap_struct, entry,
3141 get_attr_key2string( groupmap_attr_list, LDAP_ATTR_GROUP_TYPE), temp))
3143 DEBUG(0, ("Mandatory attribute %s not found\n",
3144 get_attr_key2string( groupmap_attr_list, LDAP_ATTR_GROUP_TYPE)));
3145 return False;
3147 map->sid_name_use = (uint32)atol(temp);
3149 if ((map->sid_name_use < SID_NAME_USER) ||
3150 (map->sid_name_use > SID_NAME_UNKNOWN)) {
3151 DEBUG(0, ("Unknown Group type: %d\n", map->sid_name_use));
3152 return False;
3155 if (!get_single_attribute(ldap_state->ldap_struct, entry,
3156 get_attr_key2string( groupmap_attr_list, LDAP_ATTR_DISPLAY_NAME), temp))
3158 temp[0] = '\0';
3159 if (!get_single_attribute(ldap_state->ldap_struct, entry,
3160 get_attr_key2string( groupmap_attr_list, LDAP_ATTR_CN), temp))
3162 DEBUG(0, ("Attributes cn not found either "
3163 "for gidNumber(%i)\n",map->gid));
3164 return False;
3167 fstrcpy(map->nt_name, temp);
3169 if (!get_single_attribute(ldap_state->ldap_struct, entry,
3170 get_attr_key2string( groupmap_attr_list, LDAP_ATTR_DESC), temp))
3172 temp[0] = '\0';
3174 fstrcpy(map->comment, temp);
3176 map->systemaccount = 0;
3177 init_privilege(&map->priv_set);
3179 return True;
3182 /**********************************************************************
3183 *********************************************************************/
3185 static BOOL init_ldap_from_group(LDAP *ldap_struct,
3186 LDAPMessage *existing,
3187 LDAPMod ***mods,
3188 const GROUP_MAP *map)
3190 pstring tmp;
3192 if (mods == NULL || map == NULL) {
3193 DEBUG(0, ("init_ldap_from_group: NULL parameters found!\n"));
3194 return False;
3197 *mods = NULL;
3199 sid_to_string(tmp, &map->sid);
3200 make_ldap_mod(ldap_struct, existing, mods,
3201 get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GROUP_SID), tmp);
3202 snprintf(tmp, sizeof(tmp)-1, "%i", map->sid_name_use);
3203 make_ldap_mod(ldap_struct, existing, mods,
3204 get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GROUP_TYPE), tmp);
3206 make_ldap_mod(ldap_struct, existing, mods,
3207 get_attr_key2string( groupmap_attr_list, LDAP_ATTR_DISPLAY_NAME), map->nt_name);
3208 make_ldap_mod(ldap_struct, existing, mods,
3209 get_attr_key2string( groupmap_attr_list, LDAP_ATTR_DESC), map->comment);
3211 return True;
3214 /**********************************************************************
3215 *********************************************************************/
3217 static NTSTATUS ldapsam_getgroup(struct pdb_methods *methods,
3218 const char *filter,
3219 GROUP_MAP *map)
3221 struct ldapsam_privates *ldap_state =
3222 (struct ldapsam_privates *)methods->private_data;
3223 LDAPMessage *result;
3224 LDAPMessage *entry;
3225 int count;
3227 if (ldapsam_search_one_group(ldap_state, filter, &result)
3228 != LDAP_SUCCESS) {
3229 return NT_STATUS_NO_SUCH_GROUP;
3232 count = ldap_count_entries(ldap_state->ldap_struct, result);
3234 if (count < 1) {
3235 DEBUG(4, ("Did not find group for filter %s\n", filter));
3236 return NT_STATUS_NO_SUCH_GROUP;
3239 if (count > 1) {
3240 DEBUG(1, ("Duplicate entries for filter %s: count=%d\n",
3241 filter, count));
3242 return NT_STATUS_NO_SUCH_GROUP;
3245 entry = ldap_first_entry(ldap_state->ldap_struct, result);
3247 if (!entry) {
3248 ldap_msgfree(result);
3249 return NT_STATUS_UNSUCCESSFUL;
3252 if (!init_group_from_ldap(ldap_state, map, entry)) {
3253 DEBUG(1, ("init_group_from_ldap failed for group filter %s\n",
3254 filter));
3255 ldap_msgfree(result);
3256 return NT_STATUS_NO_SUCH_GROUP;
3259 ldap_msgfree(result);
3260 return NT_STATUS_OK;
3263 /**********************************************************************
3264 *********************************************************************/
3266 static NTSTATUS ldapsam_getgrsid(struct pdb_methods *methods, GROUP_MAP *map,
3267 DOM_SID sid, BOOL with_priv)
3269 pstring filter;
3271 snprintf(filter, sizeof(filter)-1, "(&(objectClass=%s)(%s=%s))",
3272 LDAP_OBJ_GROUPMAP,
3273 get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GROUP_SID),
3274 sid_string_static(&sid));
3276 return ldapsam_getgroup(methods, filter, map);
3279 /**********************************************************************
3280 *********************************************************************/
3282 static NTSTATUS ldapsam_getgrgid(struct pdb_methods *methods, GROUP_MAP *map,
3283 gid_t gid, BOOL with_priv)
3285 pstring filter;
3287 snprintf(filter, sizeof(filter)-1, "(&(objectClass=%s)(%s=%d))",
3288 LDAP_OBJ_GROUPMAP,
3289 get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GIDNUMBER),
3290 gid);
3292 return ldapsam_getgroup(methods, filter, map);
3295 /**********************************************************************
3296 *********************************************************************/
3298 static NTSTATUS ldapsam_getgrnam(struct pdb_methods *methods, GROUP_MAP *map,
3299 char *name, BOOL with_priv)
3301 pstring filter;
3303 /* TODO: Escaping of name? */
3305 snprintf(filter, sizeof(filter)-1, "(&(objectClass=%s)(|(%s=%s)(%s=%s)))",
3306 LDAP_OBJ_GROUPMAP,
3307 get_attr_key2string(groupmap_attr_list, LDAP_ATTR_DISPLAY_NAME), name,
3308 get_attr_key2string(groupmap_attr_list, LDAP_ATTR_CN), name);
3310 return ldapsam_getgroup(methods, filter, map);
3313 /**********************************************************************
3314 *********************************************************************/
3316 static int ldapsam_search_one_group_by_gid(struct ldapsam_privates *ldap_state,
3317 gid_t gid,
3318 LDAPMessage **result)
3320 pstring filter;
3322 snprintf(filter, sizeof(filter)-1, "(&(objectClass=%s)(%s=%i))",
3323 LDAP_OBJ_POSIXGROUP,
3324 get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GIDNUMBER),
3325 gid);
3327 return ldapsam_search_one_group(ldap_state, filter, result);
3330 /**********************************************************************
3331 *********************************************************************/
3333 static NTSTATUS ldapsam_add_group_mapping_entry(struct pdb_methods *methods,
3334 GROUP_MAP *map)
3336 struct ldapsam_privates *ldap_state =
3337 (struct ldapsam_privates *)methods->private_data;
3338 LDAPMessage *result = NULL;
3339 LDAPMod **mods = NULL;
3341 char *tmp;
3342 pstring dn;
3343 LDAPMessage *entry;
3345 GROUP_MAP dummy;
3347 int rc;
3349 if (NT_STATUS_IS_OK(ldapsam_getgrgid(methods, &dummy,
3350 map->gid, False))) {
3351 DEBUG(0, ("Group %i already exists in LDAP\n", map->gid));
3352 return NT_STATUS_UNSUCCESSFUL;
3355 rc = ldapsam_search_one_group_by_gid(ldap_state, map->gid, &result);
3356 if (rc != LDAP_SUCCESS) {
3357 return NT_STATUS_UNSUCCESSFUL;
3360 if (ldap_count_entries(ldap_state->ldap_struct, result) != 1) {
3361 DEBUG(2, ("Group %i must exist exactly once in LDAP\n",
3362 map->gid));
3363 ldap_msgfree(result);
3364 return NT_STATUS_UNSUCCESSFUL;
3367 entry = ldap_first_entry(ldap_state->ldap_struct, result);
3368 tmp = ldap_get_dn(ldap_state->ldap_struct, entry);
3369 pstrcpy(dn, tmp);
3370 ldap_memfree(tmp);
3372 if (!init_ldap_from_group(ldap_state->ldap_struct,
3373 result, &mods, map)) {
3374 DEBUG(0, ("init_ldap_from_group failed!\n"));
3375 ldap_mods_free(mods, 1);
3376 ldap_msgfree(result);
3377 return NT_STATUS_UNSUCCESSFUL;
3380 ldap_msgfree(result);
3382 if (mods == NULL) {
3383 DEBUG(0, ("mods is empty\n"));
3384 return NT_STATUS_UNSUCCESSFUL;
3387 make_a_mod(&mods, LDAP_MOD_ADD, "objectClass",
3388 "sambaGroupMapping");
3390 rc = ldapsam_modify(ldap_state, dn, mods);
3391 ldap_mods_free(mods, 1);
3393 if (rc != LDAP_SUCCESS) {
3394 char *ld_error = NULL;
3395 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
3396 &ld_error);
3397 DEBUG(0, ("failed to add group %i error: %s (%s)\n", map->gid,
3398 ld_error ? ld_error : "(unknown)", ldap_err2string(rc)));
3399 SAFE_FREE(ld_error);
3400 return NT_STATUS_UNSUCCESSFUL;
3403 DEBUG(2, ("successfully modified group %i in LDAP\n", map->gid));
3404 return NT_STATUS_OK;
3407 /**********************************************************************
3408 *********************************************************************/
3410 static NTSTATUS ldapsam_update_group_mapping_entry(struct pdb_methods *methods,
3411 GROUP_MAP *map)
3413 struct ldapsam_privates *ldap_state =
3414 (struct ldapsam_privates *)methods->private_data;
3415 int rc;
3416 char *dn;
3417 LDAPMessage *result;
3418 LDAPMessage *entry;
3419 LDAPMod **mods;
3421 rc = ldapsam_search_one_group_by_gid(ldap_state, map->gid, &result);
3423 if (rc != LDAP_SUCCESS) {
3424 return NT_STATUS_UNSUCCESSFUL;
3427 if (ldap_count_entries(ldap_state->ldap_struct, result) == 0) {
3428 DEBUG(0, ("No group to modify!\n"));
3429 ldap_msgfree(result);
3430 return NT_STATUS_UNSUCCESSFUL;
3433 entry = ldap_first_entry(ldap_state->ldap_struct, result);
3434 dn = ldap_get_dn(ldap_state->ldap_struct, entry);
3436 if (!init_ldap_from_group(ldap_state->ldap_struct,
3437 result, &mods, map)) {
3438 DEBUG(0, ("init_ldap_from_group failed\n"));
3439 ldap_msgfree(result);
3440 return NT_STATUS_UNSUCCESSFUL;
3443 ldap_msgfree(result);
3445 if (mods == NULL) {
3446 DEBUG(4, ("mods is empty: nothing to do\n"));
3447 return NT_STATUS_UNSUCCESSFUL;
3450 rc = ldapsam_modify(ldap_state, dn, mods);
3452 ldap_mods_free(mods, 1);
3454 if (rc != LDAP_SUCCESS) {
3455 char *ld_error = NULL;
3456 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
3457 &ld_error);
3458 DEBUG(0, ("failed to modify group %i error: %s (%s)\n", map->gid,
3459 ld_error ? ld_error : "(unknown)", ldap_err2string(rc)));
3460 SAFE_FREE(ld_error);
3463 DEBUG(2, ("successfully modified group %i in LDAP\n", map->gid));
3464 return NT_STATUS_OK;
3467 /**********************************************************************
3468 *********************************************************************/
3470 static NTSTATUS ldapsam_delete_group_mapping_entry(struct pdb_methods *methods,
3471 DOM_SID sid)
3473 struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)methods->private_data;
3474 pstring sidstring, filter;
3475 LDAPMessage *result;
3476 int rc;
3477 NTSTATUS ret;
3478 char **attr_list;
3480 sid_to_string(sidstring, &sid);
3482 snprintf(filter, sizeof(filter)-1, "(&(objectClass=%s)(%s=%s))",
3483 LDAP_OBJ_GROUPMAP, LDAP_ATTRIBUTE_SID, sidstring);
3485 rc = ldapsam_search_one_group(ldap_state, filter, &result);
3487 if (rc != LDAP_SUCCESS) {
3488 return NT_STATUS_NO_SUCH_GROUP;
3491 attr_list = get_attr_list( groupmap_attr_list_to_delete );
3492 ret = ldapsam_delete_entry(ldap_state, result, LDAP_OBJ_GROUPMAP, attr_list);
3493 free_attr_list ( attr_list );
3495 ldap_msgfree(result);
3497 return ret;
3500 /**********************************************************************
3501 *********************************************************************/
3503 static NTSTATUS ldapsam_setsamgrent(struct pdb_methods *my_methods, BOOL update)
3505 struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
3506 fstring filter;
3507 int rc;
3508 char **attr_list;
3510 snprintf( filter, sizeof(filter)-1, "(objectclass=%s)", LDAP_OBJ_GROUPMAP);
3511 attr_list = get_attr_list( groupmap_attr_list );
3512 rc = ldapsam_search(ldap_state, lp_ldap_suffix(),
3513 LDAP_SCOPE_SUBTREE, filter,
3514 attr_list, 0, &ldap_state->result);
3515 free_attr_list( attr_list );
3517 if (rc != LDAP_SUCCESS) {
3518 DEBUG(0, ("LDAP search failed: %s\n", ldap_err2string(rc)));
3519 DEBUG(3, ("Query was: %s, %s\n", lp_ldap_suffix(), filter));
3520 ldap_msgfree(ldap_state->result);
3521 ldap_state->result = NULL;
3522 return NT_STATUS_UNSUCCESSFUL;
3525 DEBUG(2, ("ldapsam_setsampwent: %d entries in the base!\n",
3526 ldap_count_entries(ldap_state->ldap_struct,
3527 ldap_state->result)));
3529 ldap_state->entry = ldap_first_entry(ldap_state->ldap_struct, ldap_state->result);
3530 ldap_state->index = 0;
3532 return NT_STATUS_OK;
3535 /**********************************************************************
3536 *********************************************************************/
3538 static void ldapsam_endsamgrent(struct pdb_methods *my_methods)
3540 ldapsam_endsampwent(my_methods);
3543 /**********************************************************************
3544 *********************************************************************/
3546 static NTSTATUS ldapsam_getsamgrent(struct pdb_methods *my_methods,
3547 GROUP_MAP *map)
3549 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
3550 struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
3551 BOOL bret = False;
3553 /* The rebind proc needs this *HACK*. We are not multithreaded, so
3554 this will work, but it's not nice. */
3555 static_ldap_state = ldap_state;
3557 while (!bret) {
3558 if (!ldap_state->entry)
3559 return ret;
3561 ldap_state->index++;
3562 bret = init_group_from_ldap(ldap_state, map, ldap_state->entry);
3564 ldap_state->entry = ldap_next_entry(ldap_state->ldap_struct,
3565 ldap_state->entry);
3568 return NT_STATUS_OK;
3571 /**********************************************************************
3572 *********************************************************************/
3574 static NTSTATUS ldapsam_enum_group_mapping(struct pdb_methods *methods,
3575 enum SID_NAME_USE sid_name_use,
3576 GROUP_MAP **rmap, int *num_entries,
3577 BOOL unix_only, BOOL with_priv)
3579 GROUP_MAP map;
3580 GROUP_MAP *mapt;
3581 int entries = 0;
3582 NTSTATUS nt_status;
3584 *num_entries = 0;
3585 *rmap = NULL;
3587 if (!NT_STATUS_IS_OK(ldapsam_setsamgrent(methods, False))) {
3588 DEBUG(0, ("Unable to open passdb\n"));
3589 return NT_STATUS_ACCESS_DENIED;
3592 while (NT_STATUS_IS_OK(nt_status = ldapsam_getsamgrent(methods, &map))) {
3593 if (sid_name_use != SID_NAME_UNKNOWN &&
3594 sid_name_use != map.sid_name_use) {
3595 DEBUG(11,("enum_group_mapping: group %s is not of the requested type\n", map.nt_name));
3596 continue;
3598 if (unix_only==ENUM_ONLY_MAPPED && map.gid==-1) {
3599 DEBUG(11,("enum_group_mapping: group %s is non mapped\n", map.nt_name));
3600 continue;
3603 mapt=(GROUP_MAP *)Realloc((*rmap), (entries+1)*sizeof(GROUP_MAP));
3604 if (!mapt) {
3605 DEBUG(0,("enum_group_mapping: Unable to enlarge group map!\n"));
3606 SAFE_FREE(*rmap);
3607 return NT_STATUS_UNSUCCESSFUL;
3609 else
3610 (*rmap) = mapt;
3612 mapt[entries] = map;
3614 entries += 1;
3617 ldapsam_endsamgrent(methods);
3619 *num_entries = entries;
3621 return NT_STATUS_OK;
3624 /**********************************************************************
3625 *********************************************************************/
3627 static NTSTATUS pdb_init_ldapsam_common(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method,
3628 const char *location)
3630 NTSTATUS nt_status;
3631 struct ldapsam_privates *ldap_state;
3633 if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
3634 return nt_status;
3637 (*pdb_method)->name = "ldapsam";
3639 (*pdb_method)->setsampwent = ldapsam_setsampwent;
3640 (*pdb_method)->endsampwent = ldapsam_endsampwent;
3641 (*pdb_method)->getsampwent = ldapsam_getsampwent;
3642 (*pdb_method)->getsampwnam = ldapsam_getsampwnam;
3643 (*pdb_method)->getsampwsid = ldapsam_getsampwsid;
3644 (*pdb_method)->add_sam_account = ldapsam_add_sam_account;
3645 (*pdb_method)->update_sam_account = ldapsam_update_sam_account;
3646 (*pdb_method)->delete_sam_account = ldapsam_delete_sam_account;
3648 (*pdb_method)->getgrsid = ldapsam_getgrsid;
3649 (*pdb_method)->getgrgid = ldapsam_getgrgid;
3650 (*pdb_method)->getgrnam = ldapsam_getgrnam;
3651 (*pdb_method)->add_group_mapping_entry = ldapsam_add_group_mapping_entry;
3652 (*pdb_method)->update_group_mapping_entry = ldapsam_update_group_mapping_entry;
3653 (*pdb_method)->delete_group_mapping_entry = ldapsam_delete_group_mapping_entry;
3654 (*pdb_method)->enum_group_mapping = ldapsam_enum_group_mapping;
3656 /* TODO: Setup private data and free */
3658 ldap_state = talloc_zero(pdb_context->mem_ctx, sizeof(struct ldapsam_privates));
3660 if (!ldap_state) {
3661 DEBUG(0, ("talloc() failed for ldapsam private_data!\n"));
3662 return NT_STATUS_NO_MEMORY;
3665 if (location) {
3666 ldap_state->uri = talloc_strdup(pdb_context->mem_ctx, location);
3667 } else {
3668 ldap_state->uri = "ldap://localhost";
3671 ldap_state->domain_name = talloc_strdup(pdb_context->mem_ctx, get_global_sam_name());
3672 if (!ldap_state->domain_name) {
3673 return NT_STATUS_NO_MEMORY;
3676 sid_copy(&ldap_state->domain_sid, get_global_sam_sid());
3678 (*pdb_method)->private_data = ldap_state;
3680 (*pdb_method)->free_private_data = free_private_data;
3682 return NT_STATUS_OK;
3685 /**********************************************************************
3686 *********************************************************************/
3688 static NTSTATUS pdb_init_ldapsam_compat(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
3690 NTSTATUS nt_status;
3691 struct ldapsam_privates *ldap_state;
3693 if (!NT_STATUS_IS_OK(nt_status = pdb_init_ldapsam_common(pdb_context, pdb_method, location))) {
3694 return nt_status;
3697 (*pdb_method)->name = "ldapsam_compat";
3699 ldap_state = (*pdb_method)->private_data;
3700 ldap_state->schema_ver = SCHEMAVER_SAMBAACCOUNT;
3702 if (location) {
3703 ldap_state->uri = talloc_strdup(pdb_context->mem_ctx, location);
3704 } else {
3705 #ifndef WITH_LDAP_SAMCONFIG
3706 ldap_state->uri = "ldap://localhost";
3707 #else
3708 int ldap_port = lp_ldap_port();
3710 /* remap default port if not using SSL (ie clear or TLS) */
3711 if ( (lp_ldap_ssl() != LDAP_SSL_ON) && (ldap_port == 636) ) {
3712 ldap_port = 389;
3715 ldap_state->uri = talloc_asprintf(pdb_context->mem_ctx, "%s://%s:%d", lp_ldap_ssl() == LDAP_SSL_ON ? "ldaps" : "ldap", lp_ldap_server(), ldap_port);
3716 if (!ldap_state->uri) {
3717 return NT_STATUS_NO_MEMORY;
3719 #endif
3722 return NT_STATUS_OK;
3725 /**********************************************************************
3726 *********************************************************************/
3728 static NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
3730 NTSTATUS nt_status;
3731 struct ldapsam_privates *ldap_state;
3732 uint32 low_idmap_uid, high_idmap_uid;
3733 uint32 low_idmap_gid, high_idmap_gid;
3735 if (!NT_STATUS_IS_OK(nt_status = pdb_init_ldapsam_common(pdb_context, pdb_method, location))) {
3736 return nt_status;
3739 (*pdb_method)->name = "ldapsam";
3741 ldap_state = (*pdb_method)->private_data;
3742 ldap_state->schema_ver = SCHEMAVER_SAMBASAMACCOUNT;
3743 ldap_state->permit_non_unix_accounts = False;
3745 /* check for non-unix account ranges */
3747 if (lp_idmap_uid(&low_idmap_uid, &high_idmap_uid)
3748 && lp_idmap_gid(&low_idmap_gid, &high_idmap_gid))
3750 DEBUG(2, ("Enabling non-unix account ranges\n"));
3752 ldap_state->permit_non_unix_accounts = True;
3754 ldap_state->low_allocated_user_rid = fallback_pdb_uid_to_user_rid(low_idmap_uid);
3755 ldap_state->high_allocated_user_rid = fallback_pdb_uid_to_user_rid(high_idmap_uid);
3756 ldap_state->low_allocated_group_rid = pdb_gid_to_group_rid(low_idmap_gid);
3757 ldap_state->high_allocated_group_rid = pdb_gid_to_group_rid(high_idmap_gid);
3760 return NT_STATUS_OK;
3763 NTSTATUS pdb_ldap_init(void)
3765 NTSTATUS nt_status;
3766 if (!NT_STATUS_IS_OK(nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "ldapsam", pdb_init_ldapsam)))
3767 return nt_status;
3769 if (!NT_STATUS_IS_OK(nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "ldapsam_compat", pdb_init_ldapsam_compat)))
3770 return nt_status;
3772 return NT_STATUS_OK;