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