Finally committing my LDAP changes.
[samba.git] / source3 / groupdb / groupldap.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 2.0.
4    LDAP domain group database for SAMBA
5    Copyright (C) Matthew Chapman 1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20    
21 */
22
23 #include "includes.h"
24
25 #ifdef WITH_LDAP
26
27 #include <lber.h>
28 #include <ldap.h>
29
30 extern int DEBUGLEVEL;
31 extern DOM_SID global_sam_sid;
32
33 /* Internal state */
34 extern LDAP *ldap_struct;
35 extern LDAPMessage *ldap_results;
36 extern LDAPMessage *ldap_entry;
37
38 /* Static structure filled for requests */
39 static DOMAIN_GRP domgrp;
40
41
42 /***************************************************************
43   Get group and membership information.
44  ****************************************************************/
45
46 static DOMAIN_GRP *ldapgroup_getgrp(DOMAIN_GRP *group,
47                              DOMAIN_GRP_MEMBER **members, int *num_membs)
48 {
49         fstring temp;
50         char **values;
51         DOMAIN_GRP_MEMBER *memblist;
52         char *value, *sep;
53         int i;
54
55         if(!ldap_entry)
56                 return NULL;
57
58         if(!ldap_get_attribute("cn", group->name)) {
59                 DEBUG(0, ("Missing cn\n"));
60                 return NULL; }
61
62         DEBUG(2,("Retrieving group [%s]\n", group->name));
63
64         if(ldap_get_attribute("rid", temp)) {
65                 group->rid = strtol(temp, NULL, 16);
66         } else {
67                 DEBUG(0, ("Missing rid\n"));
68                 return NULL;
69         }
70
71         if(!ldap_get_attribute("description", group->comment))
72                 group->comment[0] = 0;
73
74         group->attr = 0x7;
75
76         if(!members || !num_membs) {
77                 ldap_entry = ldap_next_entry(ldap_struct, ldap_entry);
78                 return group;
79         }
80
81         if(values = ldap_get_values(ldap_struct, ldap_entry, "member")) {
82
83                 *num_membs = i = ldap_count_values(values);
84                 *members = memblist = malloc(i * sizeof(DOMAIN_GRP_MEMBER));
85
86                 do {
87                         value = values[--i];
88                 
89                         if(!(sep = strchr(value, ','))) {
90                                 DEBUG(0, ("Malformed group member\n"));
91                                 return NULL;
92                         }
93                         *(sep++) = 0;
94                         fstrcpy(memblist[i].name, value);   
95
96                         if(!(value = strchr(sep, ','))) {
97                                 DEBUG(0, ("Malformed group member\n"));
98                                 return NULL;
99                         }
100                         memblist[i].rid = strtol(sep, &value, 16);
101
102                         if((memblist[i].sid_use = atoi(value+1))
103                                         >= SID_NAME_UNKNOWN)
104                                 DEBUG(0, ("Invalid SID use in group"));
105
106                         memblist[i].attr = 0x7;
107
108                 } while(i > 0);
109
110                 ldap_value_free(values);
111
112         } else {
113                 *num_membs = 0;
114                 *members = NULL;
115         }
116
117         ldap_entry = ldap_next_entry(ldap_struct, ldap_entry);
118         return group;
119 }
120
121
122 /************************************************************************
123   Queues the necessary modifications to save a DOMAIN_GRP structure
124  ************************************************************************/
125
126 static void ldapgroup_grpmods(DOMAIN_GRP *group, LDAPMod ***mods,
127                               int operation)
128 {
129         fstring temp;
130
131         *mods = NULL;
132
133         if(operation == LDAP_MOD_ADD) { /* immutable attributes */
134                 ldap_make_mod(mods, LDAP_MOD_ADD, "objectClass", "sambaGroup");
135                 ldap_make_mod(mods, LDAP_MOD_ADD, "cn", group->name);
136
137                 slprintf(temp, sizeof(temp)-1, "%x", group->rid);
138                 ldap_make_mod(mods, LDAP_MOD_ADD, "rid", temp);
139         }
140
141         ldap_make_mod(mods, operation, "description", group->comment);
142 }
143
144
145 /************************************************************************
146   Create a group member entry
147  ************************************************************************/
148
149 static BOOL ldapgroup_memmods(uint32 user_rid, LDAPMod ***mods, int operation)
150 {
151         pstring member;
152         fstring name;
153         DOM_SID sid;
154         uint8 type;
155
156         sid_copy(&sid, &global_sam_sid);
157         sid_append_rid(&sid, user_rid);
158         if (lookup_sid(&sid, name, &type))
159                 return (False);
160
161         slprintf(member, sizeof(member)-1, "%s,%x,%d", name, user_rid, type);
162
163         *mods = NULL;
164         ldap_make_mod(mods, operation, "member", member);
165         return True;
166 }
167
168
169 /***************************************************************
170   Begin/end domain group enumeration.
171  ****************************************************************/
172
173 static void *ldapgroup_enumfirst(BOOL update)
174 {
175         int server_role = lp_server_role();
176
177         if (server_role == ROLE_DOMAIN_NONE ||
178                         server_role == ROLE_DOMAIN_MEMBER)
179                 return NULL;
180
181         if (!ldap_connect())
182                 return NULL;
183
184         ldap_search_for("objectclass=sambaGroup");
185
186         return ldap_struct;
187 }
188
189 static void ldapgroup_enumclose(void *vp)
190 {
191         ldap_disconnect();
192 }
193
194
195 /*************************************************************************
196   Save/restore the current position in a query
197  *************************************************************************/
198
199 static SMB_BIG_UINT ldapgroup_getdbpos(void *vp)
200 {
201         return (SMB_BIG_UINT)((ulong)ldap_entry);
202 }
203
204 static BOOL ldapgroup_setdbpos(void *vp, SMB_BIG_UINT tok)
205 {
206         ldap_entry = (LDAPMessage *)((ulong)tok);
207         return (True);
208 }
209
210
211 /*************************************************************************
212   Return information about domain groups and their members.
213  *************************************************************************/
214
215 static DOMAIN_GRP *ldapgroup_getgrpbynam(const char *name,
216                DOMAIN_GRP_MEMBER **members, int *num_membs)
217 {
218         fstring filter;
219         DOMAIN_GRP *ret;
220
221         if(!ldap_connect())
222                 return (False);
223
224         slprintf(filter, sizeof(filter)-1,
225                  "(&(cn=%s)(objectClass=sambaGroup))", name);
226         ldap_search_for(filter);
227
228         ret = ldapgroup_getgrp(&domgrp, members, num_membs);
229
230         ldap_disconnect();
231         return ret;
232 }
233
234 static DOMAIN_GRP *ldapgroup_getgrpbygid(gid_t grp_id,
235                DOMAIN_GRP_MEMBER **members, int *num_membs)
236 {
237         fstring filter;
238         DOMAIN_GRP *ret;
239
240         if(!ldap_connect())
241                 return (False);
242
243         slprintf(filter, sizeof(filter)-1,
244                  "(&(gidNumber=%d)(objectClass=sambaGroup))", grp_id);
245         ldap_search_for(filter);
246
247         ret = ldapgroup_getgrp(&domgrp, members, num_membs);
248
249         ldap_disconnect();
250         return ret;
251 }
252
253 static DOMAIN_GRP *ldapgroup_getgrpbyrid(uint32 grp_rid,
254                DOMAIN_GRP_MEMBER **members, int *num_membs)
255 {
256         fstring filter;
257         DOMAIN_GRP *ret;
258
259         if(!ldap_connect())
260                 return (False);
261
262         slprintf(filter, sizeof(filter)-1,
263                  "(&(rid=%x)(objectClass=sambaGroup))", grp_rid);
264         ldap_search_for(filter);
265
266         ret = ldapgroup_getgrp(&domgrp, members, num_membs);
267
268         ldap_disconnect();
269         return ret;
270 }
271
272 static DOMAIN_GRP *ldapgroup_getcurrentgrp(void *vp,
273                DOMAIN_GRP_MEMBER **members, int *num_membs)
274 {
275         return ldapgroup_getgrp(&domgrp, members, num_membs);
276 }
277
278
279 /*************************************************************************
280   Add/modify/delete domain groups.
281  *************************************************************************/
282
283 static BOOL ldapgroup_addgrp(DOMAIN_GRP *group)
284 {
285         LDAPMod **mods;
286
287         if (!ldap_allocaterid(&group->rid))
288         {
289             DEBUG(0,("RID generation failed\n"));
290             return (False);
291         }
292
293         ldapgroup_grpmods(group, &mods, LDAP_MOD_ADD); 
294         return ldap_makemods("cn", group->name, mods, True);
295 }
296
297 static BOOL ldapgroup_modgrp(DOMAIN_GRP *group)
298 {
299         LDAPMod **mods;
300
301         ldapgroup_grpmods(group, &mods, LDAP_MOD_REPLACE);
302         return ldap_makemods("cn", group->name, mods, False);
303 }
304
305 static BOOL ldapgroup_delgrp(uint32 grp_rid)
306 {
307         fstring filter;
308         char *dn;
309         int err;
310
311         if (!ldap_connect())
312                 return (False);
313
314         slprintf(filter, sizeof(filter)-1,
315                  "(&(rid=%x)(objectClass=sambaGroup))", grp_rid);
316         ldap_search_for(filter);
317
318         if (!ldap_entry || !(dn = ldap_get_dn(ldap_struct, ldap_entry)))
319         {
320                 ldap_disconnect();
321                 return (False);
322         }
323
324         err = ldap_delete_s(ldap_struct, dn);
325         free(dn);
326         ldap_disconnect();
327
328         if (err != LDAP_SUCCESS)
329         {
330                 DEBUG(0, ("delete: %s\n", ldap_err2string(err)));
331                 return (False);
332         }
333
334         return True;
335 }
336
337
338 /*************************************************************************
339   Add users to/remove users from groups.
340  *************************************************************************/
341
342 static BOOL ldapgroup_addmem(uint32 grp_rid, uint32 user_rid)
343 {
344         LDAPMod **mods;
345         fstring rid_str;
346
347         slprintf(rid_str, sizeof(rid_str)-1, "%x", grp_rid);
348
349         if(!ldapgroup_memmods(user_rid, &mods, LDAP_MOD_ADD))
350                 return (False);
351
352         return ldap_makemods("rid", rid_str, mods, False);
353 }
354
355 static BOOL ldapgroup_delmem(uint32 grp_rid, uint32 user_rid)
356 {
357         LDAPMod **mods;
358         fstring rid_str;
359
360         slprintf(rid_str, sizeof(rid_str)-1, "%x", grp_rid);
361
362         if(!ldapgroup_memmods(user_rid, &mods, LDAP_MOD_DELETE))
363                 return (False);
364
365         return ldap_makemods("rid", rid_str, mods, False);
366 }
367
368
369 /*************************************************************************
370   Return domain groups that a user is in.
371  *************************************************************************/
372
373 static BOOL ldapgroup_getusergroups(const char *name, DOMAIN_GRP **groups,
374                                     int *num_grps)
375 {
376         DOMAIN_GRP *grouplist;
377         fstring filter;
378         int i;
379
380         if(!ldap_connect())
381                 return (False);
382
383         slprintf(filter, sizeof(pstring)-1,
384                  "(&(member=%s,*)(objectclass=sambaGroup))", name);
385         ldap_search_for(filter);
386
387         *num_grps = i = ldap_count_entries(ldap_struct, ldap_results);
388
389         if(!i) {
390                 *groups = NULL;
391                 ldap_disconnect();
392                 return (True);
393         }
394
395         *groups = grouplist = malloc(i * sizeof(DOMAIN_GRP));
396         do {
397                 i--;
398         } while(ldapgroup_getgrp(&grouplist[i], NULL, NULL) && (i > 0));
399
400         ldap_disconnect();
401         return (True);
402 }
403
404
405 static struct groupdb_ops ldapgroup_ops =
406 {
407         ldapgroup_enumfirst,
408         ldapgroup_enumclose,
409         ldapgroup_getdbpos,
410         ldapgroup_setdbpos,
411
412         ldapgroup_getgrpbynam,
413         ldapgroup_getgrpbygid,
414         ldapgroup_getgrpbyrid,
415         ldapgroup_getcurrentgrp,
416
417         ldapgroup_addgrp,
418         ldapgroup_modgrp,
419         ldapgroup_delgrp,
420
421         ldapgroup_addmem,
422         ldapgroup_delmem,
423
424         ldapgroup_getusergroups
425 };
426
427 struct groupdb_ops *ldap_initialise_group_db(void)
428 {
429         return &ldapgroup_ops;
430 }
431
432 #else
433  void groupldap_dummy_function(void);
434  void groupldap_dummy_function(void) { } /* stop some compilers complaining */
435 #endif
436