6169c89b3b9a9674ba87c953d62a2bd11888bbe4
[samba.git] / source3 / 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, int 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         pstr_sprintf(id_str, "%lu", ((id_type & ID_USERID) ? (unsigned long)id.uid :
75                                                  (unsigned long)id.gid));       
76         
77         smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDMAP_ENTRY );
78
79         smbldap_make_mod( ldap_state.smbldap_state->ldap_struct, 
80                           entry, &mods, type, id_str );
81
82         smbldap_make_mod( ldap_state.smbldap_state->ldap_struct,
83                           entry, &mods,  
84                           get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID), 
85                           sid_string );
86
87         /* There may well be nothing at all to do */
88
89         if (mods) {
90                 smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SID_ENTRY );
91                 rc = smbldap_add(ldap_state.smbldap_state, dn, mods);
92                 ldap_mods_free( mods, True );   
93         } else {
94                 rc = LDAP_SUCCESS;
95         }
96
97         if (rc != LDAP_SUCCESS) {
98                 char *ld_error = NULL;
99                 ldap_get_option(ldap_state.smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
100                                 &ld_error);
101                 DEBUG(0,("ldap_set_mapping_internals: Failed to %s mapping from %s to %lu [%s]\n",
102                          (ldap_op == LDAP_MOD_ADD) ? "add" : "replace",
103                          sid_string, (unsigned long)((id_type & ID_USERID) ? id.uid : id.gid), type));
104                 DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n", 
105                         ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
106                 return NT_STATUS_UNSUCCESSFUL;
107         }
108                 
109         DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to %lu [%s]\n",
110                 sid_string, ((id_type & ID_USERID) ? (unsigned long)id.uid : 
111                              (unsigned long)id.gid), type));
112
113         return NT_STATUS_OK;
114 }
115
116 /*****************************************************************************
117  Allocate a new uid or gid
118 *****************************************************************************/
119
120 static NTSTATUS ldap_allocate_id(unid_t *id, int id_type)
121 {
122         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
123         int rc = LDAP_SERVER_DOWN;
124         int count = 0;
125         LDAPMessage *result = NULL;
126         LDAPMessage *entry = NULL;
127         pstring id_str, new_id_str;
128         LDAPMod **mods = NULL;
129         const char *type;
130         char *dn = NULL;
131         const char **attr_list;
132         pstring filter;
133         uid_t   luid, huid;
134         gid_t   lgid, hgid;
135
136
137         type = (id_type & ID_USERID) ?
138                 get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER ) : 
139                 get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
140
141         pstr_sprintf(filter, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
142
143         attr_list = get_attr_list( NULL, idpool_attr_list );
144
145         rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(),
146                                LDAP_SCOPE_SUBTREE, filter,
147                                attr_list, 0, &result);
148         TALLOC_FREE( attr_list );
149          
150         if (rc != LDAP_SUCCESS) {
151                 DEBUG(0,("ldap_allocate_id: %s object not found\n", LDAP_OBJ_IDPOOL));
152                 goto out;
153         }
154         
155         count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
156         if (count != 1) {
157                 DEBUG(0,("ldap_allocate_id: single %s object not found\n", LDAP_OBJ_IDPOOL));
158                 goto out;
159         }
160
161         dn = smbldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
162         if (!dn) {
163                 goto out;
164         }
165         entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
166
167         if (!smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, type, id_str)) {
168                 DEBUG(0,("ldap_allocate_id: %s attribute not found\n",
169                          type));
170                 goto out;
171         }
172
173         /* this must succeed or else we wouldn't have initialized */
174                 
175         lp_idmap_uid( &luid, &huid);
176         lp_idmap_gid( &lgid, &hgid);
177         
178         /* make sure we still have room to grow */
179         
180         if (id_type & ID_USERID) {
181                 id->uid = strtoul(id_str, NULL, 10);
182                 if (id->uid > huid ) {
183                         DEBUG(0,("ldap_allocate_id: Cannot allocate uid above %lu!\n", 
184                                  (unsigned long)huid));
185                         goto out;
186                 }
187         }
188         else { 
189                 id->gid = strtoul(id_str, NULL, 10);
190                 if (id->gid > hgid ) {
191                         DEBUG(0,("ldap_allocate_id: Cannot allocate gid above %lu!\n", 
192                                  (unsigned long)hgid));
193                         goto out;
194                 }
195         }
196         
197         pstr_sprintf(new_id_str, "%lu", 
198                  ((id_type & ID_USERID) ? (unsigned long)id->uid : 
199                   (unsigned long)id->gid) + 1);
200                  
201         smbldap_set_mod( &mods, LDAP_MOD_DELETE, type, id_str );                 
202         smbldap_set_mod( &mods, LDAP_MOD_ADD, type, new_id_str );
203
204         if (mods == NULL) {
205                 DEBUG(0,("ldap_allocate_id: smbldap_set_mod() failed.\n"));
206                 goto out;               
207         }
208
209         rc = smbldap_modify(ldap_state.smbldap_state, dn, mods);
210
211         ldap_mods_free( mods, True );
212         if (rc != LDAP_SUCCESS) {
213                 DEBUG(1,("ldap_allocate_id: Failed to allocate new %s.  ldap_modify() failed.\n",
214                         type));
215                 goto out;
216         }
217         
218         ret = NT_STATUS_OK;
219 out:
220         SAFE_FREE(dn);
221         if (result != NULL)
222                 ldap_msgfree(result);
223
224         return ret;
225 }
226
227 /*****************************************************************************
228  get a sid from an id
229 *****************************************************************************/
230
231 static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
232 {
233         LDAPMessage *result = NULL;
234         LDAPMessage *entry = NULL;
235         pstring sid_str;
236         pstring filter;
237         pstring suffix;
238         const char *type;
239         int rc;
240         int count;
241         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
242         const char **attr_list;
243
244         if ( id_type & ID_USERID ) 
245                 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER );
246         else 
247                 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
248
249         pstrcpy( suffix, lp_ldap_idmap_suffix() );
250         pstr_sprintf(filter, "(&(objectClass=%s)(%s=%lu))",
251                 LDAP_OBJ_IDMAP_ENTRY, type,  
252                 ((id_type & ID_USERID) ? (unsigned long)id.uid : (unsigned long)id.gid));
253                 
254         attr_list = get_attr_list( NULL, sidmap_attr_list );
255         rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE, 
256                 filter, attr_list, 0, &result);
257
258         if (rc != LDAP_SUCCESS) {
259                 DEBUG(3,("ldap_get_isd_from_id: Failure looking up entry (%s)\n",
260                         ldap_err2string(rc) ));
261                 goto out;
262         }
263                            
264         count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
265
266         if (count != 1) {
267                 DEBUG(0,("ldap_get_sid_from_id: mapping not found for %s: %lu\n", 
268                         type, ((id_type & ID_USERID) ? (unsigned long)id.uid : 
269                                (unsigned long)id.gid)));
270                 goto out;
271         }
272         
273         entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
274         
275         if ( !smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, LDAP_ATTRIBUTE_SID, sid_str) )
276                 goto out;
277            
278         if (!string_to_sid(sid, sid_str))
279                 goto out;
280
281         ret = NT_STATUS_OK;
282 out:
283         TALLOC_FREE( attr_list );        
284
285         if (result)
286                 ldap_msgfree(result);
287
288         return ret;
289 }
290
291 /***********************************************************************
292  Get an id from a sid 
293 ***********************************************************************/
294
295 static NTSTATUS ldap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid)
296 {
297         LDAPMessage *result = NULL;
298         LDAPMessage *entry = NULL;
299         pstring sid_str;
300         pstring filter;
301         pstring id_str;
302         const char *suffix;     
303         const char *type;
304         int rc;
305         int count;
306         const char **attr_list;
307         char *dn = NULL;
308         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
309
310         sid_to_string(sid_str, sid);
311
312         DEBUG(8,("ldap_get_id_from_sid: %s (%s)\n", sid_str,
313                 (*id_type & ID_GROUPID ? "group" : "user") ));
314
315         suffix = lp_ldap_idmap_suffix();
316         pstr_sprintf(filter, "(&(objectClass=%s)(%s=%s))", 
317                 LDAP_OBJ_IDMAP_ENTRY, LDAP_ATTRIBUTE_SID, sid_str);
318                         
319         if ( *id_type & ID_GROUPID ) 
320                 type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER );
321         else 
322                 type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER );
323
324         /* do the search and check for errors */
325
326         attr_list = get_attr_list( NULL, sidmap_attr_list );
327         rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE, 
328                 filter, attr_list, 0, &result);
329                         
330         if (rc != LDAP_SUCCESS) {
331                 DEBUG(3,("ldap_get_id_from_sid: Failure looking up idmap entry (%s)\n",
332                         ldap_err2string(rc) ));
333                 goto out;
334         }
335                         
336         /* check for the number of entries returned */
337
338         count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
339            
340         if ( count > 1 ) {
341                 DEBUG(0, ("ldap_get_id_from_sid: (2nd) search %s returned [%d] entries!\n",
342                         filter, count));
343                 goto out;
344         }
345         
346         /* try to allocate a new id if we still haven't found one */
347
348         if ( !count ) {
349                 int i;
350
351                 if (*id_type & ID_QUERY_ONLY) {
352                         DEBUG(5,("ldap_get_id_from_sid: No matching entry found and QUERY_ONLY flag set\n"));
353                         goto out;
354                 }
355
356                 DEBUG(8,("ldap_get_id_from_sid: Allocating new id\n"));
357                 
358                 for (i = 0; i < LDAP_MAX_ALLOC_ID; i++) {
359                         ret = ldap_allocate_id(id, *id_type);
360                         if ( NT_STATUS_IS_OK(ret) )
361                                 break;
362                 }
363                 
364                 if ( !NT_STATUS_IS_OK(ret) ) {
365                         DEBUG(0,("ldap_allocate_id: cannot acquire id lock!\n"));
366                         goto out;
367                 }
368
369                 DEBUG(10,("ldap_get_id_from_sid: Allocated new %cid [%ul]\n",
370                         (*id_type & ID_GROUPID ? 'g' : 'u'), (uint32)id->uid ));
371         
372                 ret = ldap_set_mapping(sid, *id, *id_type);
373
374                 /* all done */
375
376                 goto out;
377         }
378
379         DEBUG(10,("ldap_get_id_from_sid: success\n"));
380
381         entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
382         
383         dn = smbldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
384         if (!dn)
385                 goto out;
386
387         DEBUG(10, ("Found mapping entry at dn=%s, looking for %s\n", dn, type));
388                 
389         if ( smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, type, id_str) ) {
390                 if ( (*id_type & ID_USERID) )
391                         id->uid = strtoul(id_str, NULL, 10);
392                 else
393                         id->gid = strtoul(id_str, NULL, 10);
394                 
395                 ret = NT_STATUS_OK;
396                 goto out;
397         }
398         
399 out:
400         TALLOC_FREE( attr_list );
401         if (result)
402                 ldap_msgfree(result);
403         SAFE_FREE(dn);
404         
405         return ret;
406 }
407
408 /**********************************************************************
409  Verify the sambaUnixIdPool entry in the directiry.  
410 **********************************************************************/
411
412 static NTSTATUS verify_idpool( void )
413 {
414         fstring filter;
415         int rc;
416         const char **attr_list;
417         LDAPMessage *result = NULL;
418         LDAPMod **mods = NULL;
419         int count;
420         
421         fstr_sprintf( filter, "(objectclass=%s)", LDAP_OBJ_IDPOOL );
422         
423         attr_list = get_attr_list( NULL, idpool_attr_list );
424         rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), 
425                 LDAP_SCOPE_SUBTREE, filter, attr_list, 0, &result);
426         TALLOC_FREE( attr_list );
427
428         if (rc != LDAP_SUCCESS)
429                 return NT_STATUS_UNSUCCESSFUL;
430
431         count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
432
433         ldap_msgfree(result);
434
435         if ( count > 1 ) {
436                 DEBUG(0,("ldap_idmap_init: multiple entries returned from %s (base == %s)\n",
437                         filter, lp_ldap_idmap_suffix() ));
438                 return NT_STATUS_UNSUCCESSFUL;
439         }
440         else if (count == 0) {
441                 uid_t   luid, huid;
442                 gid_t   lgid, hgid;
443                 fstring uid_str, gid_str;
444                 
445                 if ( !lp_idmap_uid(&luid, &huid) || !lp_idmap_gid( &lgid, &hgid ) ) {
446                         DEBUG(0,("ldap_idmap_init: idmap uid/gid parameters not specified\n"));
447                         return NT_STATUS_UNSUCCESSFUL;
448                 }
449                 
450                 fstr_sprintf( uid_str, "%lu", (unsigned long)luid );
451                 fstr_sprintf( gid_str, "%lu", (unsigned long)lgid );
452
453                 smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDPOOL );
454                 smbldap_set_mod( &mods, LDAP_MOD_ADD, 
455                         get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER), uid_str );
456                 smbldap_set_mod( &mods, LDAP_MOD_ADD,
457                         get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER), gid_str );
458                 if (mods) {
459                         rc = smbldap_modify(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), mods);
460                         ldap_mods_free( mods, True );
461                 } else {
462                         return NT_STATUS_UNSUCCESSFUL;
463                 }
464         }
465
466         return ( rc==LDAP_SUCCESS ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
467 }
468
469 /*****************************************************************************
470  Initialise idmap database. 
471 *****************************************************************************/
472
473 static NTSTATUS ldap_idmap_init( char *params )
474 {
475         NTSTATUS nt_status;
476
477         ldap_state.mem_ctx = talloc_init("idmap_ldap");
478         if (!ldap_state.mem_ctx) {
479                 return NT_STATUS_NO_MEMORY;
480         }
481
482         /* assume location is the only parameter */
483         if (!NT_STATUS_IS_OK(nt_status = 
484                              smbldap_init(ldap_state.mem_ctx, params, 
485                                           &ldap_state.smbldap_state))) {
486                 talloc_destroy(ldap_state.mem_ctx);
487                 return nt_status;
488         }
489
490         /* see if the idmap suffix and sub entries exists */
491         
492         nt_status = verify_idpool();    
493         if ( !NT_STATUS_IS_OK(nt_status) )
494                 return nt_status;
495                 
496         return NT_STATUS_OK;
497 }
498
499 /*****************************************************************************
500  End the LDAP session
501 *****************************************************************************/
502
503 static NTSTATUS ldap_idmap_close(void)
504 {
505
506         smbldap_free_struct(&(ldap_state).smbldap_state);
507         talloc_destroy(ldap_state.mem_ctx);
508         
509         DEBUG(5,("The connection to the LDAP server was closed\n"));
510         /* maybe free the results here --metze */
511         
512         return NT_STATUS_OK;
513 }
514
515
516 /* This function doesn't make as much sense in an LDAP world since the calling
517    node doesn't really control the ID ranges */
518 static void ldap_idmap_status(void)
519 {
520         DEBUG(0, ("LDAP IDMAP Status not available\n"));
521 }
522
523 static struct idmap_methods ldap_methods = {
524         ldap_idmap_init,
525         ldap_allocate_id,
526         ldap_get_sid_from_id,
527         ldap_get_id_from_sid,
528         ldap_set_mapping,
529         ldap_idmap_close,
530         ldap_idmap_status
531
532 };
533
534 NTSTATUS idmap_ldap_init(void)
535 {
536         return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap", &ldap_methods);
537 }