Registry server LDB backend: Don't make copies of the same type
[kai/samba.git] / lib / util / util_getent.c
1 /*
2    Unix SMB/CIFS implementation.
3    Samba utility functions
4    Copyright (C) Simo Sorce 2001
5    Copyright (C) Jeremy Allison 2001
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 3 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, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22
23
24 /****************************************************************
25  Returns a single linked list of group entries.
26  Use grent_free() to free it after use.
27 ****************************************************************/
28
29 struct sys_grent * getgrent_list(void)
30 {
31         struct sys_grent *glist;
32         struct sys_grent *gent;
33         struct group *grp;
34         
35         gent = malloc_p(struct sys_grent);
36         if (gent == NULL) {
37                 DEBUG (0, ("Out of memory in getgrent_list!\n"));
38                 return NULL;
39         }
40         memset(gent, '\0', sizeof(struct sys_grent));
41         glist = gent;
42         
43         setgrent();
44         grp = getgrent();
45         if (grp == NULL) {
46                 endgrent();
47                 SAFE_FREE(glist);
48                 return NULL;
49         }
50
51         while (grp != NULL) {
52                 int i,num;
53                 
54                 if (grp->gr_name) {
55                         if ((gent->gr_name = strdup(grp->gr_name)) == NULL)
56                                 goto err;
57                 }
58                 if (grp->gr_passwd) {
59                         if ((gent->gr_passwd = strdup(grp->gr_passwd)) == NULL)
60                                 goto err;
61                 }
62                 gent->gr_gid = grp->gr_gid;
63                 
64                 /* number of strings in gr_mem */
65                 for (num = 0; grp->gr_mem[num]; num++)
66                         ;
67                 
68                 /* alloc space for gr_mem string pointers */
69                 if ((gent->gr_mem = malloc_array_p(char *, num+1)) == NULL)
70                         goto err;
71
72                 memset(gent->gr_mem, '\0', (num+1) * sizeof(char *));
73
74                 for (i=0; i < num; i++) {
75                         if ((gent->gr_mem[i] = strdup(grp->gr_mem[i])) == NULL)
76                                 goto err;
77                 }
78                 gent->gr_mem[num] = NULL;
79                 
80                 grp = getgrent();
81                 if (grp) {
82                         gent->next = malloc_p(struct sys_grent);
83                         if (gent->next == NULL)
84                                 goto err;
85                         gent = gent->next;
86                         memset(gent, '\0', sizeof(struct sys_grent));
87                 }
88         }
89         
90         endgrent();
91         return glist;
92
93   err:
94
95         endgrent();
96         DEBUG(0, ("Out of memory in getgrent_list!\n"));
97         grent_free(glist);
98         return NULL;
99 }
100
101 /****************************************************************
102  Free the single linked list of group entries made by
103  getgrent_list()
104 ****************************************************************/
105
106 void grent_free (struct sys_grent *glist)
107 {
108         while (glist) {
109                 struct sys_grent *prev;
110                 
111                 SAFE_FREE(glist->gr_name);
112                 SAFE_FREE(glist->gr_passwd);
113                 if (glist->gr_mem) {
114                         int i;
115                         for (i = 0; glist->gr_mem[i]; i++)
116                                 SAFE_FREE(glist->gr_mem[i]);
117                         SAFE_FREE(glist->gr_mem);
118                 }
119                 prev = glist;
120                 glist = glist->next;
121                 SAFE_FREE(prev);
122         }
123 }
124
125 /****************************************************************
126  Returns a single linked list of passwd entries.
127  Use pwent_free() to free it after use.
128 ****************************************************************/
129
130 struct sys_pwent * getpwent_list(void)
131 {
132         struct sys_pwent *plist;
133         struct sys_pwent *pent;
134         struct passwd *pwd;
135         
136         pent = malloc_p(struct sys_pwent);
137         if (pent == NULL) {
138                 DEBUG (0, ("Out of memory in getpwent_list!\n"));
139                 return NULL;
140         }
141         plist = pent;
142         
143         setpwent();
144         pwd = getpwent();
145         while (pwd != NULL) {
146                 memset(pent, '\0', sizeof(struct sys_pwent));
147                 if (pwd->pw_name) {
148                         if ((pent->pw_name = strdup(pwd->pw_name)) == NULL)
149                                 goto err;
150                 }
151                 if (pwd->pw_passwd) {
152                         if ((pent->pw_passwd = strdup(pwd->pw_passwd)) == NULL)
153                                 goto err;
154                 }
155                 pent->pw_uid = pwd->pw_uid;
156                 pent->pw_gid = pwd->pw_gid;
157                 if (pwd->pw_gecos) {
158                         if ((pent->pw_name = strdup(pwd->pw_gecos)) == NULL)
159                                 goto err;
160                 }
161                 if (pwd->pw_dir) {
162                         if ((pent->pw_name = strdup(pwd->pw_dir)) == NULL)
163                                 goto err;
164                 }
165                 if (pwd->pw_shell) {
166                         if ((pent->pw_name = strdup(pwd->pw_shell)) == NULL)
167                                 goto err;
168                 }
169
170                 pwd = getpwent();
171                 if (pwd) {
172                         pent->next = malloc_p(struct sys_pwent);
173                         if (pent->next == NULL)
174                                 goto err;
175                         pent = pent->next;
176                 }
177         }
178         
179         endpwent();
180         return plist;
181
182   err:
183
184         endpwent();
185         DEBUG(0, ("Out of memory in getpwent_list!\n"));
186         pwent_free(plist);
187         return NULL;
188 }
189
190 /****************************************************************
191  Free the single linked list of passwd entries made by
192  getpwent_list()
193 ****************************************************************/
194
195 void pwent_free (struct sys_pwent *plist)
196 {
197         while (plist) {
198                 struct sys_pwent *prev;
199                 
200                 SAFE_FREE(plist->pw_name);
201                 SAFE_FREE(plist->pw_passwd);
202                 SAFE_FREE(plist->pw_gecos);
203                 SAFE_FREE(plist->pw_dir);
204                 SAFE_FREE(plist->pw_shell);
205
206                 prev = plist;
207                 plist = plist->next;
208                 SAFE_FREE(prev);
209         }
210 }
211
212 /****************************************************************
213  Add the individual group users onto the list.
214 ****************************************************************/
215
216 static struct sys_userlist *add_members_to_userlist(struct sys_userlist *list_head, const struct group *grp)
217 {
218         size_t num_users, i;
219
220         /* Count the number of users. */
221         for (num_users = 0; grp->gr_mem[num_users]; num_users++)
222                 ;
223
224         for (i = 0; i < num_users; i++) {
225                 struct sys_userlist *entry = malloc_p(struct sys_userlist);
226                 if (entry == NULL) {
227                         free_userlist(list_head);
228                         return NULL;
229                 }
230                 entry->unix_name = (char *)strdup(grp->gr_mem[i]);
231                 if (entry->unix_name == NULL) {
232                         SAFE_FREE(entry);
233                         free_userlist(list_head);
234                         return NULL;
235                 }
236                 DLIST_ADD(list_head, entry);
237         }
238         return list_head;
239 }
240
241 /****************************************************************
242  Get the list of UNIX users in a group.
243  We have to enumerate the /etc/group file as some UNIX getgrnam()
244  calls won't do that for us (notably Tru64 UNIX).
245 ****************************************************************/
246
247 struct sys_userlist *get_users_in_group(const char *gname)
248 {
249         struct sys_userlist *list_head = NULL;
250         struct group *gptr;
251
252 #if !defined(BROKEN_GETGRNAM)
253         if ((gptr = (struct group *)getgrnam(gname)) == NULL)
254                 return NULL;
255         return add_members_to_userlist(list_head, gptr);
256 #else
257         /* BROKEN_GETGRNAM - True64 */
258         setgrent();
259         while((gptr = getgrent()) != NULL) {
260                 if (strequal(gname, gptr->gr_name)) {
261                         list_head = add_members_to_userlist(list_head, gptr);
262                         if (list_head == NULL)
263                                 return NULL;
264                 }
265         }
266         endgrent();
267         return list_head;
268 #endif
269 }
270
271 /****************************************************************
272  Free list allocated above.
273 ****************************************************************/
274
275 void free_userlist(struct sys_userlist *list_head)
276 {
277         while (list_head) {
278                 struct sys_userlist *old_head = list_head;
279                 DLIST_REMOVE(list_head, list_head);
280                 SAFE_FREE(old_head->unix_name);
281                 SAFE_FREE(old_head);
282         }
283 }