6bd6c34442f57e1f02d7a091f2ff3d369c944e9f
[samba.git] / source3 / groupdb / groupdb.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Password and authentication handling
5    Copyright (C) Jeremy Allison 1996-1998
6    Copyright (C) Luke Kenneth Casson Leighton 1996-1998
7       
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "nterr.h"
25
26 extern int DEBUGLEVEL;
27 extern DOM_SID global_sam_sid;
28
29 /*
30  * NOTE. All these functions are abstracted into a structure
31  * that points to the correct function for the selected database. JRA.
32  */
33
34 static struct groupdb_ops *gpdb_ops = NULL;
35
36 /***************************************************************
37  Initialise the group db operations.
38 ***************************************************************/
39
40 BOOL initialise_group_db(void)
41 {
42   if (gpdb_ops)
43   {
44     return True;
45   }
46
47 #ifdef WITH_NISPLUS
48   gpdb_ops =  nisplus_initialise_group_db();
49 #elif defined(WITH_LDAP)
50   gpdb_ops = ldap_initialise_group_db();
51 #elif defined(USE_SMBUNIX_DB)
52   gpdb_ops = unix_initialise_group_db();
53 #endif 
54
55   return (gpdb_ops != NULL);
56 }
57
58 /*
59  * Functions that return/manipulate a DOMAIN_GRP.
60  */
61
62 /************************************************************************
63  Utility function to search group database by gid: the DOMAIN_GRP
64  structure does not have a gid member, so we have to convert here
65  from gid to group rid.
66 *************************************************************************/
67 DOMAIN_GRP *iterate_getgroupgid(gid_t gid, DOMAIN_GRP_MEMBER **mem, int *num_mem)
68 {
69         DOM_NAME_MAP gmep;
70         uint32 rid;
71         if (!lookupsmbgrpgid(gid, &gmep))
72         {
73                 DEBUG(0,("iterate_getgroupgid: gid %d does not map to one of our Domain's Groups\n", gid));
74                 return NULL;
75         }
76
77         if (gmep.type != SID_NAME_DOM_GRP && gmep.type != SID_NAME_WKN_GRP)
78         {
79                 DEBUG(0,("iterate_getgroupgid: gid %d does not map to one of our Domain's Groups\n", gid));
80                 return NULL;
81         }
82
83         sid_split_rid(&gmep.sid, &rid);
84         if (!sid_equal(&gmep.sid, &global_sam_sid))
85         {
86                 DEBUG(0,("iterate_getgroupgid: gid %d does not map into our Domain SID\n", gid));
87                 return NULL;
88         }
89
90         return iterate_getgrouprid(rid, mem, num_mem);
91 }
92
93 /************************************************************************
94  Utility function to search group database by rid.  use this if your database
95  does not have search facilities.
96 *************************************************************************/
97 DOMAIN_GRP *iterate_getgrouprid(uint32 rid, DOMAIN_GRP_MEMBER **mem, int *num_mem)
98 {
99         DOMAIN_GRP *grp = NULL;
100         void *fp = NULL;
101
102         DEBUG(10, ("search by rid: 0x%x\n", rid));
103
104         /* Open the group database file - not for update. */
105         fp = startgroupent(False);
106
107         if (fp == NULL)
108         {
109                 DEBUG(0, ("unable to open group database.\n"));
110                 return NULL;
111         }
112
113         while ((grp = getgroupent(fp, mem, num_mem)) != NULL && grp->rid != rid)
114         {
115         }
116
117         if (grp != NULL)
118         {
119                 DEBUG(10, ("found group %s by rid: 0x%x\n", grp->name, rid));
120         }
121
122         endgroupent(fp);
123         return grp;
124 }
125
126 /************************************************************************
127  Utility function to search group database by name.  use this if your database
128  does not have search facilities.
129 *************************************************************************/
130 DOMAIN_GRP *iterate_getgroupntnam(const char *name, DOMAIN_GRP_MEMBER **mem, int *num_mem)
131 {
132         DOMAIN_GRP *grp = NULL;
133         void *fp = NULL;
134
135         DEBUG(10, ("search by name: %s\n", name));
136
137         /* Open the group database file - not for update. */
138         fp = startgroupent(False);
139
140         if (fp == NULL)
141         {
142                 DEBUG(0, ("unable to open group database.\n"));
143                 return NULL;
144         }
145
146         while ((grp = getgroupent(fp, mem, num_mem)) != NULL && !strequal(grp->name, name))
147         {
148         }
149
150         if (grp != NULL)
151         {
152                 DEBUG(10, ("found by name: %s\n", name));
153         }
154
155         endgroupent(fp);
156         return grp;
157 }
158
159 /*************************************************************************
160  Routine to return the next entry in the smbdomaingroup list.
161  *************************************************************************/
162 BOOL add_domain_group(DOMAIN_GRP **grps, int *num_grps, DOMAIN_GRP *grp)
163 {
164         if (grps == NULL || num_grps == NULL || grp == NULL)
165         {
166                 return False;
167         }
168
169         (*grps) = Realloc((*grps), ((*num_grps)+1) * sizeof(DOMAIN_GRP));
170         if ((*grps) == NULL)
171         {
172                 return False;
173         }
174
175         DEBUG(10,("adding group %s(%s)\n", grp->name, grp->comment));
176
177         fstrcpy((*grps)[(*num_grps)].name   , grp->name);
178         fstrcpy((*grps)[(*num_grps)].comment, grp->comment);
179         (*grps)[(*num_grps)].attr = grp->attr;
180         (*grps)[(*num_grps)].rid  = grp->rid ;
181
182         (*num_grps)++;
183
184         return True;
185 }
186
187 /*************************************************************************
188  checks to see if a user is a member of a domain group
189  *************************************************************************/
190 static BOOL user_is_member(const char *user_name, DOMAIN_GRP_MEMBER *mem, int num_mem)
191 {
192         int i;
193         for (i = 0; i < num_mem; i++)
194         {
195                 DEBUG(10,("searching against user %s...\n", mem[i].name));
196                 if (strequal(mem[i].name, user_name))
197                 {
198                         DEBUG(10,("searching for user %s: found\n", user_name));
199                         return True;
200                 }
201         }
202         DEBUG(10,("searching for user %s: not found\n", user_name));
203         return False;
204 }
205
206 /*************************************************************************
207  gets an array of groups that a user is in.  use this if your database
208  does not have search facilities
209  *************************************************************************/
210 BOOL iterate_getusergroupsnam(const char *user_name, DOMAIN_GRP **grps, int *num_grps)
211 {
212         DOMAIN_GRP *grp = NULL;
213         DOMAIN_GRP_MEMBER *mem = NULL;
214         int num_mem = 0;
215         void *fp = NULL;
216
217         DEBUG(10, ("search for usergroups by name: %s\n", user_name));
218
219         if (user_name == NULL || grps == NULL || num_grps == NULL)
220         {
221                 return False;
222         }
223
224         (*grps) = NULL;
225         (*num_grps) = 0;
226
227         /* Open the group database file - not for update. */
228         fp = startgroupent(False);
229
230         if (fp == NULL)
231         {
232                 DEBUG(0, ("unable to open group database.\n"));
233                 return False;
234         }
235
236         /* iterate through all groups.  search members for required user */
237         while ((grp = getgroupent(fp, &mem, &num_mem)) != NULL)
238         {
239                 DEBUG(5,("group name %s members: %d\n", grp->name, num_mem));
240                 if (num_mem != 0 && mem != NULL)
241                 {
242                         BOOL ret = True;
243                         if (user_is_member(user_name, mem, num_mem))
244                         {
245                                 ret = add_domain_group(grps, num_grps, grp);
246                         }
247
248                         free(mem);
249                         mem = NULL;
250                         num_mem = 0;
251
252                         if (!ret)
253                         {
254                                 (*num_grps) = 0;
255                                 break;
256                         }
257                 }
258         }
259
260         if ((*num_grps) != 0)
261         {
262                 DEBUG(10, ("found %d user groups:\n", (*num_grps)));
263         }
264
265         endgroupent(fp);
266         return True;
267 }
268
269 /*************************************************************************
270  gets an array of groups that a user is in.  use this if your database
271  does not have search facilities
272  *************************************************************************/
273 BOOL enumdomgroups(DOMAIN_GRP **grps, int *num_grps)
274 {
275         DOMAIN_GRP *grp = NULL;
276         void *fp = NULL;
277
278         DEBUG(10, ("enum user groups\n"));
279
280         if (grps == NULL || num_grps == NULL)
281         {
282                 return False;
283         }
284
285         (*grps) = NULL;
286         (*num_grps) = 0;
287
288         /* Open the group database file - not for update. */
289         fp = startgroupent(False);
290
291         if (fp == NULL)
292         {
293                 DEBUG(0, ("unable to open group database.\n"));
294                 return False;
295         }
296
297         /* iterate through all groups. */
298         while ((grp = getgroupent(fp, NULL, NULL)) != NULL)
299         {
300                 if (!add_domain_group(grps, num_grps, grp))
301                 {
302                         DEBUG(0,("unable to add group while enumerating\n"));
303                         return False;
304                 }
305         }
306
307         if ((*num_grps) != 0)
308         {
309                 DEBUG(10, ("found %d user groups:\n", (*num_grps)));
310         }
311
312         endgroupent(fp);
313         return True;
314 }
315
316 /***************************************************************
317  Start to enumerate the group database list. Returns a void pointer
318  to ensure no modification outside this module.
319 ****************************************************************/
320
321 void *startgroupent(BOOL update)
322 {
323   return gpdb_ops->startgroupent(update);
324 }
325
326 /***************************************************************
327  End enumeration of the group database list.
328 ****************************************************************/
329
330 void endgroupent(void *vp)
331 {
332   gpdb_ops->endgroupent(vp);
333 }
334
335 /*************************************************************************
336  Routine to return the next entry in the group database list.
337  *************************************************************************/
338
339 DOMAIN_GRP *getgroupent(void *vp, DOMAIN_GRP_MEMBER **mem, int *num_mem)
340 {
341         return gpdb_ops->getgroupent(vp, mem, num_mem);
342 }
343
344 /************************************************************************
345  Routine to add an entry to the group database file.
346 *************************************************************************/
347
348 BOOL add_group_entry(DOMAIN_GRP *newgrp)
349 {
350         return gpdb_ops->add_group_entry(newgrp);
351 }
352
353 /************************************************************************
354  Routine to search the group database file for an entry matching the groupname.
355  and then replace the entry.
356 ************************************************************************/
357
358 BOOL mod_group_entry(DOMAIN_GRP* grp)
359 {
360         return gpdb_ops->mod_group_entry(grp);
361 }
362
363 /************************************************************************
364  Routine to search group database by name.
365 *************************************************************************/
366
367 DOMAIN_GRP *getgroupntnam(const char *name, DOMAIN_GRP_MEMBER **mem, int *num_mem)
368 {
369         return gpdb_ops->getgroupntnam(name, mem, num_mem);
370 }
371
372 /************************************************************************
373  Routine to search group database by group rid.
374 *************************************************************************/
375
376 DOMAIN_GRP *getgrouprid(uint32 group_rid, DOMAIN_GRP_MEMBER **mem, int *num_mem)
377 {
378         return gpdb_ops->getgrouprid(group_rid, mem, num_mem);
379 }
380
381 /************************************************************************
382  Routine to search group database by gid.
383 *************************************************************************/
384
385 DOMAIN_GRP *getgroupgid(gid_t gid, DOMAIN_GRP_MEMBER **mem, int *num_mem)
386 {
387         return gpdb_ops->getgroupgid(gid, mem, num_mem);
388 }
389
390 /*************************************************************************
391  gets an array of groups that a user is in.
392  *************************************************************************/
393 BOOL getusergroupsntnam(const char *user_name, DOMAIN_GRP **grp, int *num_grps)
394 {
395         return gpdb_ops->getusergroupsntnam(user_name, grp, num_grps);
396 }
397
398 /*************************************************************
399  initialises a DOMAIN_GRP.
400  **************************************************************/
401
402 void gpdb_init_grp(DOMAIN_GRP *grp)
403 {
404         if (grp == NULL) return;
405         ZERO_STRUCTP(grp);
406 }
407
408 /*************************************************************************
409  turns a list of groups into a string.
410 *************************************************************************/
411 BOOL make_group_line(char *p, int max_len,
412                                 DOMAIN_GRP *grp,
413                                 DOMAIN_GRP_MEMBER **mem, int *num_mem)
414 {
415         int i;
416         int len;
417         len = slprintf(p, max_len-1, "%s:%s:%d:", grp->name, grp->comment, grp->rid);
418
419         if (len == -1)
420         {
421                 DEBUG(0,("make_group_line: cannot create entry\n"));
422                 return False;
423         }
424
425         p += len;
426         max_len -= len;
427
428         if (mem == NULL || num_mem == NULL)
429         {
430                 return True;
431         }
432
433         for (i = 0; i < (*num_mem); i++)
434         {
435                 len = strlen((*mem)[i].name);
436                 p = safe_strcpy(p, (*mem)[i].name, max_len); 
437
438                 if (p == NULL)
439                 {
440                         DEBUG(0, ("make_group_line: out of space for groups!\n"));
441                         return False;
442                 }
443
444                 max_len -= len;
445
446                 if (i != (*num_mem)-1)
447                 {
448                         *p = ',';
449                         p++;
450                         max_len--;
451                 }
452         }
453
454         return True;
455 }