Sync trunk -> 3.0 for 3.0.24 code. Still need
[metze/old/v3-2-winbind-ndr.git] / source / sam / idmap_ldap.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    idmap LDAP backend
5
6    Copyright (C) Tim Potter             2000
7    Copyright (C) Jim McDonough <jmcd@us.ibm.com>        2003
8    Copyright (C) Simo Sorce             2003
9    Copyright (C) Gerald Carter          2003
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 2 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26 #include "includes.h"
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_IDMAP
30
31
32 #include <lber.h>
33 #include <ldap.h>
34
35 #include "smbldap.h"
36
37 struct ldap_idmap_state {
38         struct smbldap_state *smbldap_state;
39         TALLOC_CTX *mem_ctx;
40 };
41
42 static struct ldap_idmap_state ldap_state;
43
44 /* number tries while allocating new id */
45 #define LDAP_MAX_ALLOC_ID 128
46
47
48 /***********************************************************************
49  This function cannot be called to modify a mapping, only set a new one
50 ***********************************************************************/
51
52 static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, enum idmap_type id_type)
53 {
54         pstring dn;
55         pstring id_str;
56         fstring type;
57         LDAPMod **mods = NULL;
58         int rc = -1;
59         int ldap_op;
60         fstring sid_string;
61         LDAPMessage *entry = NULL;
62
63         sid_to_string( sid_string, sid );
64
65         ldap_op = LDAP_MOD_ADD;
66         pstr_sprintf(dn, "%s=%s,%s", get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID),
67                  sid_string, lp_ldap_idmap_suffix());
68
69         if ( id_type == ID_USERID ) {
70                 fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER ) );
71         } else {
72                 fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER ) );
73         }
74
75         pstr_sprintf(id_str, "%lu", ((id_type == ID_USERID) ? (unsigned long)id.uid :
76                                                  (unsigned long)id.gid));       
77         
78         smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDMAP_ENTRY );
79
80         smbldap_make_mod( ldap_state.smbldap_state->ldap_struct, 
81                           entry, &mods, type, id_str );
82
83         smbldap_make_mod( ldap_state.smbldap_state->ldap_struct,
84                           entry, &mods,  
85                           get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID), 
86                           sid_string );
87
88         /* There may well be nothing at all to do */
89
90         if (mods) {
91                 smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SID_ENTRY );
92                 rc = smbldap_add(ldap_state.smbldap_state, dn, mods);
93                 ldap_mods_free( mods, True );   
94         } else {
95                 rc = LDAP_SUCCESS;
96         }
97
98         if (rc != LDAP_SUCCESS) {
99                 char *ld_error = NULL;
100                 ldap_get_option(ldap_state.smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
101                                 &ld_error);
102                 DEBUG(0,("ldap_set_mapping_internals: Failed to %s mapping from %s to %lu [%s]\n",
103                          (ldap_op == LDAP_MOD_ADD) ? "add" : "replace",
104                          sid_string, (unsigned long)((id_type & ID_USERID) ? id.uid : id.gid), type));
105                 DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n", 
106                         ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
107                 return NT_STATUS_UNSUCCESSFUL;
108         }
109                 
110         DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to %lu [%s]\n",
111                 sid_string, ((id_type & ID_USERID) ? (unsigned long)id.uid : 
112                              (unsigned long)id.gid), type));
113
114         return NT_STATUS_OK;
115 }
116
117 /*****************************************************************************
118  Allocate a new uid or gid
119 *****************************************************************************/
120
121 static NTSTATUS ldap_allocate_id(unid_t *id, enum idmap_type id_type)
122 {
123         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
124         int rc = LDAP_SERVER_DOWN;
125         int count = 0;
126         LDAPMessage *result = NULL;
127         LDAPMessage *entry = NULL;
128         pstring id_str, new_id_str;
129         LDAPMod **mods = NULL;
130         const char *type;
131         char *dn = NULL;
132         const char **attr_list;
133         pstring filter;
134         uid_t   luid, huid;
135         gid_t   lgid, hgid;
136
137         if (id_type != ID_USERID && id_type != ID_GROUPID) {
138                 return NT_STATUS_INVALID_PARAMETER;
139         }
140
141         type = (id_type == ID_USERID) ?
142                 get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER ) : 
143                 get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
144
145         pstr_sprintf(filter, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
146
147         attr_list = get_attr_list( NULL, idpool_attr_list );
148
149         rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(),
150                                LDAP_SCOPE_SUBTREE, filter,
151                                attr_list, 0, &result);
152         TALLOC_FREE( attr_list );
153          
154         if (rc != LDAP_SUCCESS) {
155                 DEBUG(0,("ldap_allocate_id: %s object not found\n", LDAP_OBJ_IDPOOL));
156                 goto out;
157         }
158         
159         count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
160         if (count != 1) {
161                 DEBUG(0,("ldap_allocate_id: single %s object not found\n", LDAP_OBJ_IDPOOL));
162                 goto out;
163         }
164
165         dn = smbldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
166         if (!dn) {
167                 goto out;
168         }
169         entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
170
171         if (!smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, type, id_str)) {
172                 DEBUG(0,("ldap_allocate_id: %s attribute not found\n",
173                          type));
174                 goto out;
175         }
176
177         /* this must succeed or else we wouldn't have initialized */
178                 
179         lp_idmap_uid( &luid, &huid);
180         lp_idmap_gid( &lgid, &hgid);
181         
182         /* make sure we still have room to grow */
183         
184         if (id_type == ID_USERID) {
185                 id->uid = strtoul(id_str, NULL, 10);
186                 if (id->uid > huid ) {
187                         DEBUG(0,("ldap_allocate_id: Cannot allocate uid above %lu!\n", 
188                                  (unsigned long)huid));
189                         goto out;
190                 }
191         } else { 
192                 id->gid = strtoul(id_str, NULL, 10);
193                 if (id->gid > hgid ) {
194                         DEBUG(0,("ldap_allocate_id: Cannot allocate gid above %lu!\n", 
195                                  (unsigned long)hgid));
196                         goto out;
197                 }
198         }
199         
200         pstr_sprintf(new_id_str, "%lu", 
201                  ((id_type == ID_USERID) ? (unsigned long)id->uid : 
202                   (unsigned long)id->gid) + 1);
203                  
204         smbldap_set_mod( &mods, LDAP_MOD_DELETE, type, id_str );                 
205         smbldap_set_mod( &mods, LDAP_MOD_ADD, type, new_id_str );
206
207         if (mods == NULL) {
208                 DEBUG(0,("ldap_allocate_id: smbldap_set_mod() failed.\n"));
209                 goto out;               
210         }
211
212         rc = smbldap_modify(ldap_state.smbldap_state, dn, mods);
213
214         ldap_mods_free( mods, True );
215         if (rc != LDAP_SUCCESS) {
216                 DEBUG(1,("ldap_allocate_id: Failed to allocate new %s.  ldap_modify() failed.\n",
217                         type));
218                 goto out;
219         }
220         
221         ret = NT_STATUS_OK;
222 out:
223         SAFE_FREE(dn);
224         if (result != NULL)
225                 ldap_msgfree(result);
226
227         return ret;
228 }
229
230 /*****************************************************************************
231  get a sid from an id
232 *****************************************************************************/
233
234 static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, enum idmap_type id_type, int flags)
235 {
236         LDAPMessage *result = NULL;
237         LDAPMessage *entry = NULL;
238         pstring sid_str;
239         pstring filter;
240         pstring suffix;
241         const char *type;
242         int rc;
243         int count;
244         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
245         const char **attr_list;
246
247         if ( id_type == ID_USERID ) 
248                 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER );
249         else 
250                 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
251
252         pstrcpy( suffix, lp_ldap_idmap_suffix() );
253         pstr_sprintf(filter, "(&(objectClass=%s)(%s=%lu))",
254                 LDAP_OBJ_IDMAP_ENTRY, type,  
255                 ((id_type & ID_USERID) ? (unsigned long)id.uid : (unsigned long)id.gid));
256                 
257         attr_list = get_attr_list( NULL, sidmap_attr_list );
258         rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE, 
259                 filter, attr_list, 0, &result);
260
261         if (rc != LDAP_SUCCESS) {
262                 DEBUG(3,("ldap_get_isd_from_id: Failure looking up entry (%s)\n",
263                         ldap_err2string(rc) ));
264                 goto out;
265         }
266                            
267         count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
268
269         if (count != 1) {
270                 DEBUG(0,("ldap_get_sid_from_id: mapping not found for %s: %lu\n", 
271                         type, ((id_type & ID_USERID) ? (unsigned long)id.uid : 
272                                (unsigned long)id.gid)));
273                 goto out;
274         }
275         
276         entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
277         
278         if ( !smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, LDAP_ATTRIBUTE_SID, sid_str) )
279                 goto out;
280            
281         if (!string_to_sid(sid, sid_str))
282                 goto out;
283
284         ret = NT_STATUS_OK;
285 out:
286         TALLOC_FREE( attr_list );        
287
288         if (result)
289                 ldap_msgfree(result);
290
291         return ret;
292 }
293
294 /***********************************************************************
295  Get an id from a sid - urg. This is assuming the *output* parameter id_type
296  has been initialized with the correct needed type - ID_USERID or ID_GROUPID.
297  This *sucks* and is bad design and needs fixing. JRA.
298 ***********************************************************************/
299
300 static NTSTATUS ldap_get_id_from_sid(unid_t *id, enum idmap_type *id_type, const DOM_SID *sid, int flags)
301 {
302         LDAPMessage *result = NULL;
303         LDAPMessage *entry = NULL;
304         pstring sid_str;
305         pstring filter;
306         pstring id_str;
307         const char *suffix;     
308         const char *type;
309         int rc;
310         int count;
311         const char **attr_list;
312         char *dn = NULL;
313         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
314
315         sid_to_string(sid_str, sid);
316
317         DEBUG(8,("ldap_get_id_from_sid: %s (%s)\n", sid_str,
318                 (*id_type & ID_GROUPID ? "group" : "user") ));
319
320         suffix = lp_ldap_idmap_suffix();
321         pstr_sprintf(filter, "(&(objectClass=%s)(%s=%s))", 
322                 LDAP_OBJ_IDMAP_ENTRY, LDAP_ATTRIBUTE_SID, sid_str);
323                         
324         if ( *id_type == ID_GROUPID ) 
325                 type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER );
326         else 
327                 type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER );
328
329         /* do the search and check for errors */
330
331         attr_list = get_attr_list( NULL, sidmap_attr_list );
332         rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE, 
333                 filter, attr_list, 0, &result);
334                         
335         if (rc != LDAP_SUCCESS) {
336                 DEBUG(3,("ldap_get_id_from_sid: Failure looking up idmap entry (%s)\n",
337                         ldap_err2string(rc) ));
338                 goto out;
339         }
340                         
341         /* check for the number of entries returned */
342
343         count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
344            
345         if ( count > 1 ) {
346                 DEBUG(0, ("ldap_get_id_from_sid: (2nd) search %s returned [%d] entries!\n",
347                         filter, count));
348                 goto out;
349         }
350         
351         /* try to allocate a new id if we still haven't found one */
352
353         if ( !count ) {
354                 int i;
355
356                 if (flags & IDMAP_FLAG_QUERY_ONLY) {
357                         DEBUG(5,("ldap_get_id_from_sid: No matching entry found and QUERY_ONLY flag set\n"));
358                         goto out;
359                 }
360
361                 DEBUG(8,("ldap_get_id_from_sid: Allocating new id\n"));
362                 
363                 for (i = 0; i < LDAP_MAX_ALLOC_ID; i++) {
364                         ret = ldap_allocate_id(id, *id_type);
365                         if ( NT_STATUS_IS_OK(ret) )
366                                 break;
367                 }
368                 
369                 if ( !NT_STATUS_IS_OK(ret) ) {
370                         DEBUG(0,("ldap_allocate_id: cannot acquire id lock!\n"));
371                         goto out;
372                 }
373
374                 DEBUG(10,("ldap_get_id_from_sid: Allocated new %cid [%ul]\n",
375                         (*id_type & ID_GROUPID ? 'g' : 'u'), (uint32)id->uid ));
376         
377                 ret = ldap_set_mapping(sid, *id, *id_type);
378
379                 /* all done */
380
381                 goto out;
382         }
383
384         DEBUG(10,("ldap_get_id_from_sid: success\n"));
385
386         entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
387         
388         dn = smbldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
389         if (!dn)
390                 goto out;
391
392         DEBUG(10, ("Found mapping entry at dn=%s, looking for %s\n", dn, type));
393                 
394         if ( smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, type, id_str) ) {
395                 if ( (*id_type == ID_USERID) )
396                         id->uid = strtoul(id_str, NULL, 10);
397                 else
398                         id->gid = strtoul(id_str, NULL, 10);
399                 
400                 ret = NT_STATUS_OK;
401                 goto out;
402         }
403         
404 out:
405         TALLOC_FREE( attr_list );
406         if (result)
407                 ldap_msgfree(result);
408         SAFE_FREE(dn);
409         
410         return ret;
411 }
412
413 /**********************************************************************
414  Verify the sambaUnixIdPool entry in the directiry.  
415 **********************************************************************/
416
417 static NTSTATUS verify_idpool( void )
418 {
419         fstring filter;
420         int rc;
421         const char **attr_list;
422         LDAPMessage *result = NULL;
423         LDAPMod **mods = NULL;
424         int count;
425         
426         fstr_sprintf( filter, "(objectclass=%s)", LDAP_OBJ_IDPOOL );
427         
428         attr_list = get_attr_list( NULL, idpool_attr_list );
429         rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), 
430                 LDAP_SCOPE_SUBTREE, filter, attr_list, 0, &result);
431         TALLOC_FREE( attr_list );
432
433         if (rc != LDAP_SUCCESS)
434                 return NT_STATUS_UNSUCCESSFUL;
435
436         count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
437
438         ldap_msgfree(result);
439
440         if ( count > 1 ) {
441                 DEBUG(0,("ldap_idmap_init: multiple entries returned from %s (base == %s)\n",
442                         filter, lp_ldap_idmap_suffix() ));
443                 return NT_STATUS_UNSUCCESSFUL;
444         }
445         else if (count == 0) {
446                 uid_t   luid, huid;
447                 gid_t   lgid, hgid;
448                 fstring uid_str, gid_str;
449                 
450                 if ( !lp_idmap_uid(&luid, &huid) || !lp_idmap_gid( &lgid, &hgid ) ) {
451                         DEBUG(0,("ldap_idmap_init: idmap uid/gid parameters not specified\n"));
452                         return NT_STATUS_UNSUCCESSFUL;
453                 }
454                 
455                 fstr_sprintf( uid_str, "%lu", (unsigned long)luid );
456                 fstr_sprintf( gid_str, "%lu", (unsigned long)lgid );
457
458                 smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDPOOL );
459                 smbldap_set_mod( &mods, LDAP_MOD_ADD, 
460                         get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER), uid_str );
461                 smbldap_set_mod( &mods, LDAP_MOD_ADD,
462                         get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER), gid_str );
463                 if (mods) {
464                         rc = smbldap_modify(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), mods);
465                         ldap_mods_free( mods, True );
466                 } else {
467                         return NT_STATUS_UNSUCCESSFUL;
468                 }
469         }
470
471         return ( rc==LDAP_SUCCESS ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
472 }
473
474 /*****************************************************************************
475  Initialise idmap database. 
476 *****************************************************************************/
477
478 static NTSTATUS ldap_idmap_init( const char *params )
479 {
480         NTSTATUS nt_status;
481
482         ldap_state.mem_ctx = talloc_init("idmap_ldap");
483         if (!ldap_state.mem_ctx) {
484                 return NT_STATUS_NO_MEMORY;
485         }
486
487         /* assume location is the only parameter */
488         if (!NT_STATUS_IS_OK(nt_status = 
489                              smbldap_init(ldap_state.mem_ctx, params, 
490                                           &ldap_state.smbldap_state))) {
491                 talloc_destroy(ldap_state.mem_ctx);
492                 return nt_status;
493         }
494
495         /* see if the idmap suffix and sub entries exists */
496         
497         nt_status = verify_idpool();    
498         if ( !NT_STATUS_IS_OK(nt_status) )
499                 return nt_status;
500                 
501         return NT_STATUS_OK;
502 }
503
504 /*****************************************************************************
505  End the LDAP session
506 *****************************************************************************/
507
508 static NTSTATUS ldap_idmap_close(void)
509 {
510
511         smbldap_free_struct(&(ldap_state).smbldap_state);
512         talloc_destroy(ldap_state.mem_ctx);
513         
514         DEBUG(5,("The connection to the LDAP server was closed\n"));
515         /* maybe free the results here --metze */
516         
517         return NT_STATUS_OK;
518 }
519
520
521 /* This function doesn't make as much sense in an LDAP world since the calling
522    node doesn't really control the ID ranges */
523 static void ldap_idmap_status(void)
524 {
525         DEBUG(0, ("LDAP IDMAP Status not available\n"));
526 }
527
528 static struct idmap_methods ldap_methods = {
529         ldap_idmap_init,
530         ldap_allocate_id,
531         ldap_get_sid_from_id,
532         ldap_get_id_from_sid,
533         ldap_set_mapping,
534         ldap_idmap_close,
535         ldap_idmap_status
536
537 };
538
539 NTSTATUS idmap_ldap_init(void)
540 {
541         return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap", &ldap_methods);
542 }