idmap rewrite
[kai/samba.git] / source3 / winbindd / 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) Gerald Carter          2003
9    Copyright (C) Simo Sorce             2003-2007
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 3 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, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "winbindd.h"
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_IDMAP
30
31 #include <lber.h>
32 #include <ldap.h>
33
34 #include "smbldap.h"
35
36 static char *idmap_fetch_secret(const char *backend, bool alloc,
37                                 const char *domain, const char *identity)
38 {
39         char *tmp, *ret;
40         int r;
41
42         if (alloc) {
43                 r = asprintf(&tmp, "IDMAP_ALLOC_%s", backend);
44         } else {
45                 r = asprintf(&tmp, "IDMAP_%s_%s", backend, domain);
46         }
47
48         if (r < 0)
49                 return NULL;
50
51         strupper_m(tmp); /* make sure the key is case insensitive */
52         ret = secrets_fetch_generic(tmp, identity);
53
54         SAFE_FREE(tmp);
55
56         return ret;
57 }
58
59 struct idmap_ldap_context {
60         struct smbldap_state *smbldap_state;
61         char *url;
62         char *suffix;
63         char *user_dn;
64         uint32_t filter_low_id, filter_high_id;         /* Filter range */
65         bool anon;
66 };
67
68 struct idmap_ldap_alloc_context {
69         struct smbldap_state *smbldap_state;
70         char *url;
71         char *suffix;
72         char *user_dn;
73         uid_t low_uid, high_uid;      /* Range of uids */
74         gid_t low_gid, high_gid;      /* Range of gids */
75
76 };
77
78 #define CHECK_ALLOC_DONE(mem) do { \
79         if (!mem) { \
80                 DEBUG(0, ("Out of memory!\n")); \
81                 ret = NT_STATUS_NO_MEMORY; \
82                 goto done; \
83         } } while (0)
84
85 /**********************************************************************
86  IDMAP ALLOC TDB BACKEND
87 **********************************************************************/
88
89 static struct idmap_ldap_alloc_context *idmap_alloc_ldap;
90
91 /*********************************************************************
92  ********************************************************************/
93
94 static NTSTATUS get_credentials( TALLOC_CTX *mem_ctx,
95                                  struct smbldap_state *ldap_state,
96                                  const char *config_option,
97                                  struct idmap_domain *dom,
98                                  char **dn )
99 {
100         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
101         char *secret = NULL;
102         const char *tmp = NULL;
103         char *user_dn = NULL;
104         bool anon = False;
105
106         /* assume anonymous if we don't have a specified user */
107
108         tmp = lp_parm_const_string(-1, config_option, "ldap_user_dn", NULL);
109
110         if ( tmp ) {
111                 if (!dom) {
112                         /* only the alloc backend can pass in a NULL dom */
113                         secret = idmap_fetch_secret("ldap", True,
114                                                     NULL, tmp);
115                 } else {
116                         secret = idmap_fetch_secret("ldap", False,
117                                                     dom->name, tmp);
118                 }
119
120                 if (!secret) {
121                         DEBUG(0, ("get_credentials: Unable to fetch "
122                                   "auth credentials for %s in %s\n",
123                                   tmp, (dom==NULL)?"ALLOC":dom->name));
124                         ret = NT_STATUS_ACCESS_DENIED;
125                         goto done;
126                 }
127                 *dn = talloc_strdup(mem_ctx, tmp);
128                 CHECK_ALLOC_DONE(*dn);
129         } else {
130                 if (!fetch_ldap_pw(&user_dn, &secret)) {
131                         DEBUG(2, ("get_credentials: Failed to lookup ldap "
132                                   "bind creds. Using anonymous connection.\n"));
133                         anon = True;
134                 } else {
135                         *dn = talloc_strdup(mem_ctx, user_dn);
136                         SAFE_FREE( user_dn );
137                         CHECK_ALLOC_DONE(*dn);
138                 }
139         }
140
141         smbldap_set_creds(ldap_state, anon, *dn, secret);
142         ret = NT_STATUS_OK;
143
144 done:
145         SAFE_FREE(secret);
146
147         return ret;
148 }
149
150
151 /**********************************************************************
152  Verify the sambaUnixIdPool entry in the directory.
153 **********************************************************************/
154
155 static NTSTATUS verify_idpool(void)
156 {
157         NTSTATUS ret;
158         TALLOC_CTX *ctx;
159         LDAPMessage *result = NULL;
160         LDAPMod **mods = NULL;
161         const char **attr_list;
162         char *filter;
163         int count;
164         int rc;
165
166         if ( ! idmap_alloc_ldap) {
167                 return NT_STATUS_UNSUCCESSFUL;
168         }
169
170         ctx = talloc_new(idmap_alloc_ldap);
171         if ( ! ctx) {
172                 DEBUG(0, ("Out of memory!\n"));
173                 return NT_STATUS_NO_MEMORY;
174         }
175
176         filter = talloc_asprintf(ctx, "(objectclass=%s)", LDAP_OBJ_IDPOOL);
177         CHECK_ALLOC_DONE(filter);
178
179         attr_list = get_attr_list(ctx, idpool_attr_list);
180         CHECK_ALLOC_DONE(attr_list);
181
182         rc = smbldap_search(idmap_alloc_ldap->smbldap_state,
183                                 idmap_alloc_ldap->suffix,
184                                 LDAP_SCOPE_SUBTREE,
185                                 filter,
186                                 attr_list,
187                                 0,
188                                 &result);
189
190         if (rc != LDAP_SUCCESS) {
191                 DEBUG(1, ("Unable to verify the idpool, "
192                           "cannot continue initialization!\n"));
193                 return NT_STATUS_UNSUCCESSFUL;
194         }
195
196         count = ldap_count_entries(idmap_alloc_ldap->smbldap_state->ldap_struct,
197                                    result);
198
199         ldap_msgfree(result);
200
201         if ( count > 1 ) {
202                 DEBUG(0,("Multiple entries returned from %s (base == %s)\n",
203                         filter, idmap_alloc_ldap->suffix));
204                 ret = NT_STATUS_UNSUCCESSFUL;
205                 goto done;
206         }
207         else if (count == 0) {
208                 char *uid_str, *gid_str;
209
210                 uid_str = talloc_asprintf(ctx, "%lu",
211                                 (unsigned long)idmap_alloc_ldap->low_uid);
212                 gid_str = talloc_asprintf(ctx, "%lu",
213                                 (unsigned long)idmap_alloc_ldap->low_gid);
214
215                 smbldap_set_mod(&mods, LDAP_MOD_ADD,
216                                 "objectClass", LDAP_OBJ_IDPOOL);
217                 smbldap_set_mod(&mods, LDAP_MOD_ADD,
218                                 get_attr_key2string(idpool_attr_list,
219                                                     LDAP_ATTR_UIDNUMBER),
220                                 uid_str);
221                 smbldap_set_mod(&mods, LDAP_MOD_ADD,
222                                 get_attr_key2string(idpool_attr_list,
223                                                     LDAP_ATTR_GIDNUMBER),
224                                 gid_str);
225                 if (mods) {
226                         rc = smbldap_modify(idmap_alloc_ldap->smbldap_state,
227                                                 idmap_alloc_ldap->suffix,
228                                                 mods);
229                         ldap_mods_free(mods, True);
230                 } else {
231                         ret = NT_STATUS_UNSUCCESSFUL;
232                         goto done;
233                 }
234         }
235
236         ret = (rc == LDAP_SUCCESS)?NT_STATUS_OK:NT_STATUS_UNSUCCESSFUL;
237 done:
238         talloc_free(ctx);
239         return ret;
240 }
241
242 /*****************************************************************************
243  Initialise idmap database.
244 *****************************************************************************/
245
246 static NTSTATUS idmap_ldap_alloc_init(const char *params)
247 {
248         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
249         const char *range;
250         const char *tmp;
251         uid_t low_uid = 0;
252         uid_t high_uid = 0;
253         gid_t low_gid = 0;
254         gid_t high_gid = 0;
255
256         /* Only do init if we are online */
257         if (idmap_is_offline()) {
258                 return NT_STATUS_FILE_IS_OFFLINE;
259         }
260
261         idmap_alloc_ldap = TALLOC_ZERO_P(NULL, struct idmap_ldap_alloc_context);
262         CHECK_ALLOC_DONE( idmap_alloc_ldap );
263
264         /* load ranges */
265
266         idmap_alloc_ldap->low_uid = 0;
267         idmap_alloc_ldap->high_uid = 0;
268         idmap_alloc_ldap->low_gid = 0;
269         idmap_alloc_ldap->high_gid = 0;
270
271         range = lp_parm_const_string(-1, "idmap alloc config", "range", NULL);
272         if (range && range[0]) {
273                 unsigned low_id, high_id;
274
275                 if (sscanf(range, "%u - %u", &low_id, &high_id) == 2) {
276                         if (low_id < high_id) {
277                                 idmap_alloc_ldap->low_gid = low_id;
278                                 idmap_alloc_ldap->low_uid = low_id;
279                                 idmap_alloc_ldap->high_gid = high_id;
280                                 idmap_alloc_ldap->high_uid = high_id;
281                         } else {
282                                 DEBUG(1, ("ERROR: invalid idmap alloc range "
283                                           "[%s]", range));
284                         }
285                 } else {
286                         DEBUG(1, ("ERROR: invalid syntax for idmap alloc "
287                                   "config:range [%s]", range));
288                 }
289         }
290
291         if (lp_idmap_uid(&low_uid, &high_uid)) {
292                 idmap_alloc_ldap->low_uid = low_uid;
293                 idmap_alloc_ldap->high_uid = high_uid;
294         }
295
296         if (lp_idmap_gid(&low_gid, &high_gid)) {
297                 idmap_alloc_ldap->low_gid = low_gid;
298                 idmap_alloc_ldap->high_gid= high_gid;
299         }
300
301         if (idmap_alloc_ldap->high_uid <= idmap_alloc_ldap->low_uid) {
302                 DEBUG(1, ("idmap uid range missing or invalid\n"));
303                 DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
304                 ret = NT_STATUS_UNSUCCESSFUL;
305                 goto done;
306         }
307
308         if (idmap_alloc_ldap->high_gid <= idmap_alloc_ldap->low_gid) {
309                 DEBUG(1, ("idmap gid range missing or invalid\n"));
310                 DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
311                 ret = NT_STATUS_UNSUCCESSFUL;
312                 goto done;
313         }
314
315         if (params && *params) {
316                 /* assume location is the only parameter */
317                 idmap_alloc_ldap->url = talloc_strdup(idmap_alloc_ldap, params);
318         } else {
319                 tmp = lp_parm_const_string(-1, "idmap alloc config",
320                                            "ldap_url", NULL);
321
322                 if ( ! tmp) {
323                         DEBUG(1, ("ERROR: missing idmap ldap url\n"));
324                         ret = NT_STATUS_UNSUCCESSFUL;
325                         goto done;
326                 }
327
328                 idmap_alloc_ldap->url = talloc_strdup(idmap_alloc_ldap, tmp);
329         }
330         CHECK_ALLOC_DONE( idmap_alloc_ldap->url );
331
332         tmp = lp_parm_const_string(-1, "idmap alloc config",
333                                    "ldap_base_dn", NULL);
334         if ( ! tmp || ! *tmp) {
335                 tmp = lp_ldap_idmap_suffix();
336                 if ( ! tmp) {
337                         DEBUG(1, ("ERROR: missing idmap ldap suffix\n"));
338                         ret = NT_STATUS_UNSUCCESSFUL;
339                         goto done;
340                 }
341         }
342
343         idmap_alloc_ldap->suffix = talloc_strdup(idmap_alloc_ldap, tmp);
344         CHECK_ALLOC_DONE( idmap_alloc_ldap->suffix );
345
346         ret = smbldap_init(idmap_alloc_ldap, winbind_event_context(),
347                            idmap_alloc_ldap->url,
348                            &idmap_alloc_ldap->smbldap_state);
349         if (!NT_STATUS_IS_OK(ret)) {
350                 DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n",
351                           idmap_alloc_ldap->url));
352                 goto done;
353         }
354
355         ret = get_credentials( idmap_alloc_ldap,
356                                idmap_alloc_ldap->smbldap_state,
357                                "idmap alloc config", NULL,
358                                &idmap_alloc_ldap->user_dn );
359         if ( !NT_STATUS_IS_OK(ret) ) {
360                 DEBUG(1,("idmap_ldap_alloc_init: Failed to get connection "
361                          "credentials (%s)\n", nt_errstr(ret)));
362                 goto done;
363         }
364
365         /* see if the idmap suffix and sub entries exists */
366
367         ret = verify_idpool();
368
369  done:
370         if ( !NT_STATUS_IS_OK( ret ) )
371                 TALLOC_FREE( idmap_alloc_ldap );
372
373         return ret;
374 }
375
376 /********************************
377  Allocate a new uid or gid
378 ********************************/
379
380 static NTSTATUS idmap_ldap_allocate_id(struct unixid *xid)
381 {
382         TALLOC_CTX *ctx;
383         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
384         int rc = LDAP_SERVER_DOWN;
385         int count = 0;
386         LDAPMessage *result = NULL;
387         LDAPMessage *entry = NULL;
388         LDAPMod **mods = NULL;
389         char *id_str;
390         char *new_id_str;
391         char *filter = NULL;
392         const char *dn = NULL;
393         const char **attr_list;
394         const char *type;
395
396         /* Only do query if we are online */
397         if (idmap_is_offline()) {
398                 return NT_STATUS_FILE_IS_OFFLINE;
399         }
400
401         if ( ! idmap_alloc_ldap) {
402                 return NT_STATUS_UNSUCCESSFUL;
403         }
404
405         ctx = talloc_new(idmap_alloc_ldap);
406         if ( ! ctx) {
407                 DEBUG(0, ("Out of memory!\n"));
408                 return NT_STATUS_NO_MEMORY;
409         }
410
411         /* get type */
412         switch (xid->type) {
413
414         case ID_TYPE_UID:
415                 type = get_attr_key2string(idpool_attr_list,
416                                            LDAP_ATTR_UIDNUMBER);
417                 break;
418
419         case ID_TYPE_GID:
420                 type = get_attr_key2string(idpool_attr_list,
421                                            LDAP_ATTR_GIDNUMBER);
422                 break;
423
424         default:
425                 DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type));
426                 return NT_STATUS_INVALID_PARAMETER;
427         }
428
429         filter = talloc_asprintf(ctx, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
430         CHECK_ALLOC_DONE(filter);
431
432         attr_list = get_attr_list(ctx, idpool_attr_list);
433         CHECK_ALLOC_DONE(attr_list);
434
435         DEBUG(10, ("Search of the id pool (filter: %s)\n", filter));
436
437         rc = smbldap_search(idmap_alloc_ldap->smbldap_state,
438                                 idmap_alloc_ldap->suffix,
439                                LDAP_SCOPE_SUBTREE, filter,
440                                attr_list, 0, &result);
441
442         if (rc != LDAP_SUCCESS) {
443                 DEBUG(0,("%s object not found\n", LDAP_OBJ_IDPOOL));
444                 goto done;
445         }
446
447         talloc_autofree_ldapmsg(ctx, result);
448
449         count = ldap_count_entries(idmap_alloc_ldap->smbldap_state->ldap_struct,
450                                    result);
451         if (count != 1) {
452                 DEBUG(0,("Single %s object not found\n", LDAP_OBJ_IDPOOL));
453                 goto done;
454         }
455
456         entry = ldap_first_entry(idmap_alloc_ldap->smbldap_state->ldap_struct,
457                                  result);
458
459         dn = smbldap_talloc_dn(ctx,
460                                idmap_alloc_ldap->smbldap_state->ldap_struct,
461                                entry);
462         if ( ! dn) {
463                 goto done;
464         }
465
466         if ( ! (id_str = smbldap_talloc_single_attribute(idmap_alloc_ldap->smbldap_state->ldap_struct,
467                                 entry, type, ctx))) {
468                 DEBUG(0,("%s attribute not found\n", type));
469                 goto done;
470         }
471         if ( ! id_str) {
472                 DEBUG(0,("Out of memory\n"));
473                 ret = NT_STATUS_NO_MEMORY;
474                 goto done;
475         }
476
477         xid->id = strtoul(id_str, NULL, 10);
478
479         /* make sure we still have room to grow */
480
481         switch (xid->type) {
482         case ID_TYPE_UID:
483                 if (xid->id > idmap_alloc_ldap->high_uid) {
484                         DEBUG(0,("Cannot allocate uid above %lu!\n",
485                                  (unsigned long)idmap_alloc_ldap->high_uid));
486                         goto done;
487                 }
488                 break;
489
490         case ID_TYPE_GID:
491                 if (xid->id > idmap_alloc_ldap->high_gid) {
492                         DEBUG(0,("Cannot allocate gid above %lu!\n",
493                                  (unsigned long)idmap_alloc_ldap->high_uid));
494                         goto done;
495                 }
496                 break;
497
498         default:
499                 /* impossible */
500                 goto done;
501         }
502
503         new_id_str = talloc_asprintf(ctx, "%lu", (unsigned long)xid->id + 1);
504         if ( ! new_id_str) {
505                 DEBUG(0,("Out of memory\n"));
506                 ret = NT_STATUS_NO_MEMORY;
507                 goto done;
508         }
509
510         smbldap_set_mod(&mods, LDAP_MOD_DELETE, type, id_str);
511         smbldap_set_mod(&mods, LDAP_MOD_ADD, type, new_id_str);
512
513         if (mods == NULL) {
514                 DEBUG(0,("smbldap_set_mod() failed.\n"));
515                 goto done;
516         }
517
518         DEBUG(10, ("Try to atomically increment the id (%s -> %s)\n",
519                    id_str, new_id_str));
520
521         rc = smbldap_modify(idmap_alloc_ldap->smbldap_state, dn, mods);
522
523         ldap_mods_free(mods, True);
524
525         if (rc != LDAP_SUCCESS) {
526                 DEBUG(1,("Failed to allocate new %s. "
527                          "smbldap_modify() failed.\n", type));
528                 goto done;
529         }
530
531         ret = NT_STATUS_OK;
532
533 done:
534         talloc_free(ctx);
535         return ret;
536 }
537
538 /**********************************
539  Get current highest id.
540 **********************************/
541
542 static NTSTATUS idmap_ldap_get_hwm(struct unixid *xid)
543 {
544         TALLOC_CTX *memctx;
545         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
546         int rc = LDAP_SERVER_DOWN;
547         int count = 0;
548         LDAPMessage *result = NULL;
549         LDAPMessage *entry = NULL;
550         char *id_str;
551         char *filter = NULL;
552         const char **attr_list;
553         const char *type;
554
555         /* Only do query if we are online */
556         if (idmap_is_offline()) {
557                 return NT_STATUS_FILE_IS_OFFLINE;
558         }
559
560         if ( ! idmap_alloc_ldap) {
561                 return NT_STATUS_UNSUCCESSFUL;
562         }
563
564         memctx = talloc_new(idmap_alloc_ldap);
565         if ( ! memctx) {
566                 DEBUG(0, ("Out of memory!\n"));
567                 return NT_STATUS_NO_MEMORY;
568         }
569
570         /* get type */
571         switch (xid->type) {
572
573         case ID_TYPE_UID:
574                 type = get_attr_key2string(idpool_attr_list,
575                                            LDAP_ATTR_UIDNUMBER);
576                 break;
577
578         case ID_TYPE_GID:
579                 type = get_attr_key2string(idpool_attr_list,
580                                            LDAP_ATTR_GIDNUMBER);
581                 break;
582
583         default:
584                 DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type));
585                 return NT_STATUS_INVALID_PARAMETER;
586         }
587
588         filter = talloc_asprintf(memctx, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
589         CHECK_ALLOC_DONE(filter);
590
591         attr_list = get_attr_list(memctx, idpool_attr_list);
592         CHECK_ALLOC_DONE(attr_list);
593
594         rc = smbldap_search(idmap_alloc_ldap->smbldap_state,
595                                 idmap_alloc_ldap->suffix,
596                                LDAP_SCOPE_SUBTREE, filter,
597                                attr_list, 0, &result);
598
599         if (rc != LDAP_SUCCESS) {
600                 DEBUG(0,("%s object not found\n", LDAP_OBJ_IDPOOL));
601                 goto done;
602         }
603
604         talloc_autofree_ldapmsg(memctx, result);
605
606         count = ldap_count_entries(idmap_alloc_ldap->smbldap_state->ldap_struct,
607                                    result);
608         if (count != 1) {
609                 DEBUG(0,("Single %s object not found\n", LDAP_OBJ_IDPOOL));
610                 goto done;
611         }
612
613         entry = ldap_first_entry(idmap_alloc_ldap->smbldap_state->ldap_struct,
614                                  result);
615
616         id_str = smbldap_talloc_single_attribute(idmap_alloc_ldap->smbldap_state->ldap_struct,
617                         entry, type, memctx);
618         if ( ! id_str) {
619                 DEBUG(0,("%s attribute not found\n", type));
620                 goto done;
621         }
622         if ( ! id_str) {
623                 DEBUG(0,("Out of memory\n"));
624                 ret = NT_STATUS_NO_MEMORY;
625                 goto done;
626         }
627
628         xid->id = strtoul(id_str, NULL, 10);
629
630         ret = NT_STATUS_OK;
631 done:
632         talloc_free(memctx);
633         return ret;
634 }
635 /**********************************
636  Set highest id.
637 **********************************/
638
639 static NTSTATUS idmap_ldap_set_hwm(struct unixid *xid)
640 {
641         TALLOC_CTX *ctx;
642         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
643         int rc = LDAP_SERVER_DOWN;
644         int count = 0;
645         LDAPMessage *result = NULL;
646         LDAPMessage *entry = NULL;
647         LDAPMod **mods = NULL;
648         char *new_id_str;
649         char *filter = NULL;
650         const char *dn = NULL;
651         const char **attr_list;
652         const char *type;
653
654         /* Only do query if we are online */
655         if (idmap_is_offline()) {
656                 return NT_STATUS_FILE_IS_OFFLINE;
657         }
658
659         if ( ! idmap_alloc_ldap) {
660                 return NT_STATUS_UNSUCCESSFUL;
661         }
662
663         ctx = talloc_new(idmap_alloc_ldap);
664         if ( ! ctx) {
665                 DEBUG(0, ("Out of memory!\n"));
666                 return NT_STATUS_NO_MEMORY;
667         }
668
669         /* get type */
670         switch (xid->type) {
671
672         case ID_TYPE_UID:
673                 type = get_attr_key2string(idpool_attr_list,
674                                            LDAP_ATTR_UIDNUMBER);
675                 break;
676
677         case ID_TYPE_GID:
678                 type = get_attr_key2string(idpool_attr_list,
679                                            LDAP_ATTR_GIDNUMBER);
680                 break;
681
682         default:
683                 DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type));
684                 return NT_STATUS_INVALID_PARAMETER;
685         }
686
687         filter = talloc_asprintf(ctx, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
688         CHECK_ALLOC_DONE(filter);
689
690         attr_list = get_attr_list(ctx, idpool_attr_list);
691         CHECK_ALLOC_DONE(attr_list);
692
693         rc = smbldap_search(idmap_alloc_ldap->smbldap_state,
694                                 idmap_alloc_ldap->suffix,
695                                LDAP_SCOPE_SUBTREE, filter,
696                                attr_list, 0, &result);
697
698         if (rc != LDAP_SUCCESS) {
699                 DEBUG(0,("%s object not found\n", LDAP_OBJ_IDPOOL));
700                 goto done;
701         }
702
703         talloc_autofree_ldapmsg(ctx, result);
704
705         count = ldap_count_entries(idmap_alloc_ldap->smbldap_state->ldap_struct,
706                                    result);
707         if (count != 1) {
708                 DEBUG(0,("Single %s object not found\n", LDAP_OBJ_IDPOOL));
709                 goto done;
710         }
711
712         entry = ldap_first_entry(idmap_alloc_ldap->smbldap_state->ldap_struct,
713                                  result);
714
715         dn = smbldap_talloc_dn(ctx,
716                                 idmap_alloc_ldap->smbldap_state->ldap_struct,
717                                 entry);
718         if ( ! dn) {
719                 goto done;
720         }
721
722         new_id_str = talloc_asprintf(ctx, "%lu", (unsigned long)xid->id);
723         if ( ! new_id_str) {
724                 DEBUG(0,("Out of memory\n"));
725                 ret = NT_STATUS_NO_MEMORY;
726                 goto done;
727         }
728
729         smbldap_set_mod(&mods, LDAP_MOD_REPLACE, type, new_id_str);
730
731         if (mods == NULL) {
732                 DEBUG(0,("smbldap_set_mod() failed.\n"));
733                 goto done;
734         }
735
736         rc = smbldap_modify(idmap_alloc_ldap->smbldap_state, dn, mods);
737
738         ldap_mods_free(mods, True);
739
740         if (rc != LDAP_SUCCESS) {
741                 DEBUG(1,("Failed to allocate new %s. "
742                          "smbldap_modify() failed.\n", type));
743                 goto done;
744         }
745
746         ret = NT_STATUS_OK;
747
748 done:
749         talloc_free(ctx);
750         return ret;
751 }
752
753 /**********************************
754  Close idmap ldap alloc
755 **********************************/
756
757 static NTSTATUS idmap_ldap_alloc_close(void)
758 {
759         if (idmap_alloc_ldap) {
760                 smbldap_free_struct(&idmap_alloc_ldap->smbldap_state);
761                 DEBUG(5,("The connection to the LDAP server was closed\n"));
762                 /* maybe free the results here --metze */
763                 TALLOC_FREE(idmap_alloc_ldap);
764         }
765         return NT_STATUS_OK;
766 }
767
768
769 /**********************************************************************
770  IDMAP MAPPING LDAP BACKEND
771 **********************************************************************/
772
773 static int idmap_ldap_close_destructor(struct idmap_ldap_context *ctx)
774 {
775         smbldap_free_struct(&ctx->smbldap_state);
776         DEBUG(5,("The connection to the LDAP server was closed\n"));
777         /* maybe free the results here --metze */
778
779         return 0;
780 }
781
782 /********************************
783  Initialise idmap database.
784 ********************************/
785
786 static NTSTATUS idmap_ldap_db_init(struct idmap_domain *dom,
787                                    const char *params)
788 {
789         NTSTATUS ret;
790         struct idmap_ldap_context *ctx = NULL;
791         char *config_option = NULL;
792         const char *range = NULL;
793         const char *tmp = NULL;
794
795         /* Only do init if we are online */
796         if (idmap_is_offline()) {
797                 return NT_STATUS_FILE_IS_OFFLINE;
798         }
799
800         ctx = TALLOC_ZERO_P(dom, struct idmap_ldap_context);
801         if ( ! ctx) {
802                 DEBUG(0, ("Out of memory!\n"));
803                 return NT_STATUS_NO_MEMORY;
804         }
805
806         config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
807         if ( ! config_option) {
808                 DEBUG(0, ("Out of memory!\n"));
809                 ret = NT_STATUS_NO_MEMORY;
810                 goto done;
811         }
812
813         /* load ranges */
814         range = lp_parm_const_string(-1, config_option, "range", NULL);
815         if (range && range[0]) {
816                 if ((sscanf(range, "%u - %u", &ctx->filter_low_id,
817                                                 &ctx->filter_high_id) != 2) ||
818                     (ctx->filter_low_id > ctx->filter_high_id)) {
819                         DEBUG(1, ("ERROR: invalid filter range [%s]", range));
820                         ctx->filter_low_id = 0;
821                         ctx->filter_high_id = 0;
822                 }
823         }
824
825         if (params != NULL) {
826                 /* assume location is the only parameter */
827                 ctx->url = talloc_strdup(ctx, params);
828         } else {
829                 tmp = lp_parm_const_string(-1, config_option, "ldap_url", NULL);
830
831                 if ( ! tmp) {
832                         DEBUG(1, ("ERROR: missing idmap ldap url\n"));
833                         ret = NT_STATUS_UNSUCCESSFUL;
834                         goto done;
835                 }
836
837                 ctx->url = talloc_strdup(ctx, tmp);
838         }
839         CHECK_ALLOC_DONE(ctx->url);
840
841         tmp = lp_parm_const_string(-1, config_option, "ldap_base_dn", NULL);
842         if ( ! tmp || ! *tmp) {
843                 tmp = lp_ldap_idmap_suffix();
844                 if ( ! tmp) {
845                         DEBUG(1, ("ERROR: missing idmap ldap suffix\n"));
846                         ret = NT_STATUS_UNSUCCESSFUL;
847                         goto done;
848                 }
849         }
850
851         ctx->suffix = talloc_strdup(ctx, tmp);
852         CHECK_ALLOC_DONE(ctx->suffix);
853
854         ret = smbldap_init(ctx, winbind_event_context(), ctx->url,
855                            &ctx->smbldap_state);
856         if (!NT_STATUS_IS_OK(ret)) {
857                 DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n", ctx->url));
858                 goto done;
859         }
860
861         ret = get_credentials( ctx, ctx->smbldap_state, config_option,
862                                dom, &ctx->user_dn );
863         if ( !NT_STATUS_IS_OK(ret) ) {
864                 DEBUG(1,("idmap_ldap_db_init: Failed to get connection "
865                          "credentials (%s)\n", nt_errstr(ret)));
866                 goto done;
867         }
868
869         /* set the destructor on the context, so that resource are properly
870            freed if the contexts is released */
871
872         talloc_set_destructor(ctx, idmap_ldap_close_destructor);
873
874         dom->private_data = ctx;
875
876         talloc_free(config_option);
877         return NT_STATUS_OK;
878
879 /*failed */
880 done:
881         talloc_free(ctx);
882         return ret;
883 }
884
885 /* max number of ids requested per batch query */
886 #define IDMAP_LDAP_MAX_IDS 30
887
888 /**********************************
889  lookup a set of unix ids.
890 **********************************/
891
892 /* this function searches up to IDMAP_LDAP_MAX_IDS entries
893  * in maps for a match */
894 static struct id_map *find_map_by_id(struct id_map **maps,
895                                      enum id_type type,
896                                      uint32_t id)
897 {
898         int i;
899
900         for (i = 0; i < IDMAP_LDAP_MAX_IDS; i++) {
901                 if (maps[i] == NULL) { /* end of the run */
902                         return NULL;
903                 }
904                 if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) {
905                         return maps[i];
906                 }
907         }
908
909         return NULL;
910 }
911
912 static NTSTATUS idmap_ldap_unixids_to_sids(struct idmap_domain *dom,
913                                            struct id_map **ids)
914 {
915         NTSTATUS ret;
916         TALLOC_CTX *memctx;
917         struct idmap_ldap_context *ctx;
918         LDAPMessage *result = NULL;
919         const char *uidNumber;
920         const char *gidNumber;
921         const char **attr_list;
922         char *filter = NULL;
923         bool multi = False;
924         int idx = 0;
925         int bidx = 0;
926         int count;
927         int rc;
928         int i;
929
930         /* Only do query if we are online */
931         if (idmap_is_offline()) {
932                 return NT_STATUS_FILE_IS_OFFLINE;
933         }
934
935         ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
936
937         memctx = talloc_new(ctx);
938         if ( ! memctx) {
939                 DEBUG(0, ("Out of memory!\n"));
940                 return NT_STATUS_NO_MEMORY;
941         }
942
943         uidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER);
944         gidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER);
945
946         attr_list = get_attr_list(memctx, sidmap_attr_list);
947
948         if ( ! ids[1]) {
949                 /* if we are requested just one mapping use the simple filter */
950
951                 filter = talloc_asprintf(memctx, "(&(objectClass=%s)(%s=%lu))",
952                                 LDAP_OBJ_IDMAP_ENTRY,
953                                 (ids[0]->xid.type==ID_TYPE_UID)?uidNumber:gidNumber,
954                                 (unsigned long)ids[0]->xid.id);
955                 CHECK_ALLOC_DONE(filter);
956                 DEBUG(10, ("Filter: [%s]\n", filter));
957         } else {
958                 /* multiple mappings */
959                 multi = True;
960         }
961
962 again:
963         if (multi) {
964
965                 talloc_free(filter);
966                 filter = talloc_asprintf(memctx,
967                                          "(&(objectClass=%s)(|",
968                                          LDAP_OBJ_IDMAP_ENTRY);
969                 CHECK_ALLOC_DONE(filter);
970
971                 bidx = idx;
972                 for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
973                         filter = talloc_asprintf_append_buffer(filter, "(%s=%lu)",
974                                         (ids[idx]->xid.type==ID_TYPE_UID)?uidNumber:gidNumber,
975                                         (unsigned long)ids[idx]->xid.id);
976                         CHECK_ALLOC_DONE(filter);
977                 }
978                 filter = talloc_asprintf_append_buffer(filter, "))");
979                 CHECK_ALLOC_DONE(filter);
980                 DEBUG(10, ("Filter: [%s]\n", filter));
981         } else {
982                 bidx = 0;
983                 idx = 1;
984         }
985
986         rc = smbldap_search(ctx->smbldap_state, ctx->suffix, LDAP_SCOPE_SUBTREE,
987                 filter, attr_list, 0, &result);
988
989         if (rc != LDAP_SUCCESS) {
990                 DEBUG(3,("Failure looking up ids (%s)\n", ldap_err2string(rc)));
991                 ret = NT_STATUS_UNSUCCESSFUL;
992                 goto done;
993         }
994
995         count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result);
996
997         if (count == 0) {
998                 DEBUG(10, ("NO SIDs found\n"));
999         }
1000
1001         for (i = 0; i < count; i++) {
1002                 LDAPMessage *entry = NULL;
1003                 char *sidstr = NULL;
1004                 char *tmp = NULL;
1005                 enum id_type type;
1006                 struct id_map *map;
1007                 uint32_t id;
1008
1009                 if (i == 0) { /* first entry */
1010                         entry = ldap_first_entry(ctx->smbldap_state->ldap_struct,
1011                                                  result);
1012                 } else { /* following ones */
1013                         entry = ldap_next_entry(ctx->smbldap_state->ldap_struct,
1014                                                 entry);
1015                 }
1016                 if ( ! entry) {
1017                         DEBUG(2, ("ERROR: Unable to fetch ldap entries "
1018                                   "from results\n"));
1019                         break;
1020                 }
1021
1022                 /* first check if the SID is present */
1023                 sidstr = smbldap_talloc_single_attribute(
1024                                 ctx->smbldap_state->ldap_struct,
1025                                 entry, LDAP_ATTRIBUTE_SID, memctx);
1026                 if ( ! sidstr) { /* no sid, skip entry */
1027                         DEBUG(2, ("WARNING SID not found on entry\n"));
1028                         continue;
1029                 }
1030
1031                 /* now try to see if it is a uid, if not try with a gid
1032                  * (gid is more common, but in case both uidNumber and
1033                  * gidNumber are returned the SID is mapped to the uid
1034                  *not the gid) */
1035                 type = ID_TYPE_UID;
1036                 tmp = smbldap_talloc_single_attribute(
1037                                 ctx->smbldap_state->ldap_struct,
1038                                 entry, uidNumber, memctx);
1039                 if ( ! tmp) {
1040                         type = ID_TYPE_GID;
1041                         tmp = smbldap_talloc_single_attribute(
1042                                         ctx->smbldap_state->ldap_struct,
1043                                         entry, gidNumber, memctx);
1044                 }
1045                 if ( ! tmp) { /* wow very strange entry, how did it match ? */
1046                         DEBUG(5, ("Unprobable match on (%s), no uidNumber, "
1047                                   "nor gidNumber returned\n", sidstr));
1048                         TALLOC_FREE(sidstr);
1049                         continue;
1050                 }
1051
1052                 id = strtoul(tmp, NULL, 10);
1053                 if ((id == 0) ||
1054                     (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
1055                     (ctx->filter_high_id && (id > ctx->filter_high_id))) {
1056                         DEBUG(5, ("Requested id (%u) out of range (%u - %u). "
1057                                   "Filtered!\n", id,
1058                                   ctx->filter_low_id, ctx->filter_high_id));
1059                         TALLOC_FREE(sidstr);
1060                         TALLOC_FREE(tmp);
1061                         continue;
1062                 }
1063                 TALLOC_FREE(tmp);
1064
1065                 map = find_map_by_id(&ids[bidx], type, id);
1066                 if (!map) {
1067                         DEBUG(2, ("WARNING: couldn't match sid (%s) "
1068                                   "with requested ids\n", sidstr));
1069                         TALLOC_FREE(sidstr);
1070                         continue;
1071                 }
1072
1073                 if ( ! string_to_sid(map->sid, sidstr)) {
1074                         DEBUG(2, ("ERROR: Invalid SID on entry\n"));
1075                         TALLOC_FREE(sidstr);
1076                         continue;
1077                 }
1078                 TALLOC_FREE(sidstr);
1079
1080                 /* mapped */
1081                 map->status = ID_MAPPED;
1082
1083                 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
1084                            (unsigned long)map->xid.id, map->xid.type));
1085         }
1086
1087         /* free the ldap results */
1088         if (result) {
1089                 ldap_msgfree(result);
1090                 result = NULL;
1091         }
1092
1093         if (multi && ids[idx]) { /* still some values to map */
1094                 goto again;
1095         }
1096
1097         ret = NT_STATUS_OK;
1098
1099         /* mark all unknwon/expired ones as unmapped */
1100         for (i = 0; ids[i]; i++) {
1101                 if (ids[i]->status != ID_MAPPED)
1102                         ids[i]->status = ID_UNMAPPED;
1103         }
1104
1105 done:
1106         talloc_free(memctx);
1107         return ret;
1108 }
1109
1110 /**********************************
1111  lookup a set of sids.
1112 **********************************/
1113
1114 /* this function searches up to IDMAP_LDAP_MAX_IDS entries
1115  * in maps for a match */
1116 static struct id_map *find_map_by_sid(struct id_map **maps, DOM_SID *sid)
1117 {
1118         int i;
1119
1120         for (i = 0; i < IDMAP_LDAP_MAX_IDS; i++) {
1121                 if (maps[i] == NULL) { /* end of the run */
1122                         return NULL;
1123                 }
1124                 if (sid_equal(maps[i]->sid, sid)) {
1125                         return maps[i];
1126                 }
1127         }
1128
1129         return NULL;
1130 }
1131
1132 static NTSTATUS idmap_ldap_sids_to_unixids(struct idmap_domain *dom,
1133                                            struct id_map **ids)
1134 {
1135         LDAPMessage *entry = NULL;
1136         NTSTATUS ret;
1137         TALLOC_CTX *memctx;
1138         struct idmap_ldap_context *ctx;
1139         LDAPMessage *result = NULL;
1140         const char *uidNumber;
1141         const char *gidNumber;
1142         const char **attr_list;
1143         char *filter = NULL;
1144         bool multi = False;
1145         int idx = 0;
1146         int bidx = 0;
1147         int count;
1148         int rc;
1149         int i;
1150
1151         /* Only do query if we are online */
1152         if (idmap_is_offline()) {
1153                 return NT_STATUS_FILE_IS_OFFLINE;
1154         }
1155
1156         ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
1157
1158         memctx = talloc_new(ctx);
1159         if ( ! memctx) {
1160                 DEBUG(0, ("Out of memory!\n"));
1161                 return NT_STATUS_NO_MEMORY;
1162         }
1163
1164         uidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER);
1165         gidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER);
1166
1167         attr_list = get_attr_list(memctx, sidmap_attr_list);
1168
1169         if ( ! ids[1]) {
1170                 /* if we are requested just one mapping use the simple filter */
1171
1172                 filter = talloc_asprintf(memctx, "(&(objectClass=%s)(%s=%s))",
1173                                 LDAP_OBJ_IDMAP_ENTRY,
1174                                 LDAP_ATTRIBUTE_SID,
1175                                 sid_string_talloc(memctx, ids[0]->sid));
1176                 CHECK_ALLOC_DONE(filter);
1177                 DEBUG(10, ("Filter: [%s]\n", filter));
1178         } else {
1179                 /* multiple mappings */
1180                 multi = True;
1181         }
1182
1183 again:
1184         if (multi) {
1185
1186                 TALLOC_FREE(filter);
1187                 filter = talloc_asprintf(memctx,
1188                                          "(&(objectClass=%s)(|",
1189                                          LDAP_OBJ_IDMAP_ENTRY);
1190                 CHECK_ALLOC_DONE(filter);
1191
1192                 bidx = idx;
1193                 for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
1194                         filter = talloc_asprintf_append_buffer(filter, "(%s=%s)",
1195                                         LDAP_ATTRIBUTE_SID,
1196                                         sid_string_talloc(memctx,
1197                                                           ids[idx]->sid));
1198                         CHECK_ALLOC_DONE(filter);
1199                 }
1200                 filter = talloc_asprintf_append_buffer(filter, "))");
1201                 CHECK_ALLOC_DONE(filter);
1202                 DEBUG(10, ("Filter: [%s]", filter));
1203         } else {
1204                 bidx = 0;
1205                 idx = 1;
1206         }
1207
1208         rc = smbldap_search(ctx->smbldap_state, ctx->suffix, LDAP_SCOPE_SUBTREE,
1209                 filter, attr_list, 0, &result);
1210
1211         if (rc != LDAP_SUCCESS) {
1212                 DEBUG(3,("Failure looking up sids (%s)\n",
1213                          ldap_err2string(rc)));
1214                 ret = NT_STATUS_UNSUCCESSFUL;
1215                 goto done;
1216         }
1217
1218         count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result);
1219
1220         if (count == 0) {
1221                 DEBUG(10, ("NO SIDs found\n"));
1222         }
1223
1224         for (i = 0; i < count; i++) {
1225                 char *sidstr = NULL;
1226                 char *tmp = NULL;
1227                 enum id_type type;
1228                 struct id_map *map;
1229                 DOM_SID sid;
1230                 uint32_t id;
1231
1232                 if (i == 0) { /* first entry */
1233                         entry = ldap_first_entry(ctx->smbldap_state->ldap_struct,
1234                                                  result);
1235                 } else { /* following ones */
1236                         entry = ldap_next_entry(ctx->smbldap_state->ldap_struct,
1237                                                 entry);
1238                 }
1239                 if ( ! entry) {
1240                         DEBUG(2, ("ERROR: Unable to fetch ldap entries "
1241                                   "from results\n"));
1242                         break;
1243                 }
1244
1245                 /* first check if the SID is present */
1246                 sidstr = smbldap_talloc_single_attribute(
1247                                 ctx->smbldap_state->ldap_struct,
1248                                 entry, LDAP_ATTRIBUTE_SID, memctx);
1249                 if ( ! sidstr) { /* no sid ??, skip entry */
1250                         DEBUG(2, ("WARNING SID not found on entry\n"));
1251                         continue;
1252                 }
1253
1254                 if ( ! string_to_sid(&sid, sidstr)) {
1255                         DEBUG(2, ("ERROR: Invalid SID on entry\n"));
1256                         TALLOC_FREE(sidstr);
1257                         continue;
1258                 }
1259
1260                 map = find_map_by_sid(&ids[bidx], &sid);
1261                 if (!map) {
1262                         DEBUG(2, ("WARNING: couldn't find entry sid (%s) "
1263                                   "in ids", sidstr));
1264                         TALLOC_FREE(sidstr);
1265                         continue;
1266                 }
1267
1268                 TALLOC_FREE(sidstr);
1269
1270                 /* now try to see if it is a uid, if not try with a gid
1271                  * (gid is more common, but in case both uidNumber and
1272                  * gidNumber are returned the SID is mapped to the uid
1273                  * not the gid) */
1274                 type = ID_TYPE_UID;
1275                 tmp = smbldap_talloc_single_attribute(
1276                                 ctx->smbldap_state->ldap_struct,
1277                                 entry, uidNumber, memctx);
1278                 if ( ! tmp) {
1279                         type = ID_TYPE_GID;
1280                         tmp = smbldap_talloc_single_attribute(
1281                                         ctx->smbldap_state->ldap_struct,
1282                                         entry, gidNumber, memctx);
1283                 }
1284                 if ( ! tmp) { /* no ids ?? */
1285                         DEBUG(5, ("no uidNumber, "
1286                                   "nor gidNumber attributes found\n"));
1287                         continue;
1288                 }
1289
1290                 id = strtoul(tmp, NULL, 10);
1291                 if ((id == 0) ||
1292                     (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
1293                     (ctx->filter_high_id && (id > ctx->filter_high_id))) {
1294                         DEBUG(5, ("Requested id (%u) out of range (%u - %u). "
1295                                   "Filtered!\n", id,
1296                                   ctx->filter_low_id, ctx->filter_high_id));
1297                         TALLOC_FREE(tmp);
1298                         continue;
1299                 }
1300                 TALLOC_FREE(tmp);
1301
1302                 /* mapped */
1303                 map->xid.type = type;
1304                 map->xid.id = id;
1305                 map->status = ID_MAPPED;
1306
1307                 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
1308                            (unsigned long)map->xid.id, map->xid.type));
1309         }
1310
1311         /* free the ldap results */
1312         if (result) {
1313                 ldap_msgfree(result);
1314                 result = NULL;
1315         }
1316
1317         if (multi && ids[idx]) { /* still some values to map */
1318                 goto again;
1319         }
1320
1321         ret = NT_STATUS_OK;
1322
1323         /* mark all unknwon/expired ones as unmapped */
1324         for (i = 0; ids[i]; i++) {
1325                 if (ids[i]->status != ID_MAPPED)
1326                         ids[i]->status = ID_UNMAPPED;
1327         }
1328
1329 done:
1330         talloc_free(memctx);
1331         return ret;
1332 }
1333
1334 /**********************************
1335  set a mapping.
1336 **********************************/
1337
1338 /* TODO: change this:  This function cannot be called to modify a mapping,
1339  * only set a new one */
1340
1341 static NTSTATUS idmap_ldap_set_mapping(struct idmap_domain *dom,
1342                                        const struct id_map *map)
1343 {
1344         NTSTATUS ret;
1345         TALLOC_CTX *memctx;
1346         struct idmap_ldap_context *ctx;
1347         LDAPMessage *entry = NULL;
1348         LDAPMod **mods = NULL;
1349         const char *type;
1350         char *id_str;
1351         char *sid;
1352         char *dn;
1353         int rc = -1;
1354
1355         /* Only do query if we are online */
1356         if (idmap_is_offline()) {
1357                 return NT_STATUS_FILE_IS_OFFLINE;
1358         }
1359
1360         ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
1361
1362         switch(map->xid.type) {
1363         case ID_TYPE_UID:
1364                 type = get_attr_key2string(sidmap_attr_list,
1365                                            LDAP_ATTR_UIDNUMBER);
1366                 break;
1367
1368         case ID_TYPE_GID:
1369                 type = get_attr_key2string(sidmap_attr_list,
1370                                            LDAP_ATTR_GIDNUMBER);
1371                 break;
1372
1373         default:
1374                 return NT_STATUS_INVALID_PARAMETER;
1375         }
1376
1377         memctx = talloc_new(ctx);
1378         if ( ! memctx) {
1379                 DEBUG(0, ("Out of memory!\n"));
1380                 return NT_STATUS_NO_MEMORY;
1381         }
1382
1383         id_str = talloc_asprintf(memctx, "%lu", (unsigned long)map->xid.id);
1384         CHECK_ALLOC_DONE(id_str);
1385
1386         sid = talloc_strdup(memctx, sid_string_talloc(memctx, map->sid));
1387         CHECK_ALLOC_DONE(sid);
1388
1389         dn = talloc_asprintf(memctx, "%s=%s,%s",
1390                         get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
1391                         sid,
1392                         ctx->suffix);
1393         CHECK_ALLOC_DONE(dn);
1394
1395         smbldap_set_mod(&mods, LDAP_MOD_ADD,
1396                         "objectClass", LDAP_OBJ_IDMAP_ENTRY);
1397
1398         smbldap_make_mod(ctx->smbldap_state->ldap_struct,
1399                          entry, &mods, type, id_str);
1400
1401         smbldap_make_mod(ctx->smbldap_state->ldap_struct, entry, &mods,
1402                          get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
1403                          sid);
1404
1405         if ( ! mods) {
1406                 DEBUG(2, ("ERROR: No mods?\n"));
1407                 ret = NT_STATUS_UNSUCCESSFUL;
1408                 goto done;
1409         }
1410
1411         /* TODO: remove conflicting mappings! */
1412
1413         smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SID_ENTRY);
1414
1415         DEBUG(10, ("Set DN %s (%s -> %s)\n", dn, sid, id_str));
1416
1417         rc = smbldap_add(ctx->smbldap_state, dn, mods);
1418         ldap_mods_free(mods, True);
1419
1420         if (rc != LDAP_SUCCESS) {
1421                 char *ld_error = NULL;
1422                 ldap_get_option(ctx->smbldap_state->ldap_struct,
1423                                 LDAP_OPT_ERROR_STRING, &ld_error);
1424                 DEBUG(0,("ldap_set_mapping_internals: Failed to add %s to %lu "
1425                          "mapping [%s]\n", sid,
1426                          (unsigned long)map->xid.id, type));
1427                 DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n",
1428                         ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
1429                 if (ld_error) {
1430                         ldap_memfree(ld_error);
1431                 }
1432                 ret = NT_STATUS_UNSUCCESSFUL;
1433                 goto done;
1434         }
1435
1436         DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to "
1437                   "%lu [%s]\n", sid, (unsigned long)map->xid.id, type));
1438
1439         ret = NT_STATUS_OK;
1440
1441 done:
1442         talloc_free(memctx);
1443         return ret;
1444 }
1445
1446 /**********************************
1447  Close the idmap ldap instance
1448 **********************************/
1449
1450 static NTSTATUS idmap_ldap_close(struct idmap_domain *dom)
1451 {
1452         struct idmap_ldap_context *ctx;
1453
1454         if (dom->private_data) {
1455                 ctx = talloc_get_type(dom->private_data,
1456                                       struct idmap_ldap_context);
1457
1458                 talloc_free(ctx);
1459                 dom->private_data = NULL;
1460         }
1461
1462         return NT_STATUS_OK;
1463 }
1464
1465 static struct idmap_methods idmap_ldap_methods = {
1466
1467         .init = idmap_ldap_db_init,
1468         .unixids_to_sids = idmap_ldap_unixids_to_sids,
1469         .sids_to_unixids = idmap_ldap_sids_to_unixids,
1470         .set_mapping = idmap_ldap_set_mapping,
1471         .close_fn = idmap_ldap_close
1472 };
1473
1474 static struct idmap_alloc_methods idmap_ldap_alloc_methods = {
1475
1476         .init = idmap_ldap_alloc_init,
1477         .allocate_id = idmap_ldap_allocate_id,
1478         .get_id_hwm = idmap_ldap_get_hwm,
1479         .set_id_hwm = idmap_ldap_set_hwm,
1480         .close_fn = idmap_ldap_alloc_close,
1481         /* .dump_data = TODO */
1482 };
1483
1484 NTSTATUS idmap_alloc_ldap_init(void)
1485 {
1486         return smb_register_idmap_alloc(SMB_IDMAP_INTERFACE_VERSION, "ldap",
1487                                         &idmap_ldap_alloc_methods);
1488 }
1489
1490 NTSTATUS idmap_ldap_init(void)
1491 {
1492         NTSTATUS ret;
1493
1494         /* FIXME: bad hack to actually register also the alloc_ldap module
1495          * without changining configure.in */
1496         ret = idmap_alloc_ldap_init();
1497         if (! NT_STATUS_IS_OK(ret)) {
1498                 return ret;
1499         }
1500         return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap",
1501                                   &idmap_ldap_methods);
1502 }
1503