This commit was generated by cvs2svn to compensate for changes in r30,
[samba.git] / source4 / lib / 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 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 #include "includes.h"
23
24
25 /****************************************************************
26  Returns a single linked list of group entries.
27  Use grent_free() to free it after use.
28 ****************************************************************/
29
30 struct sys_grent * getgrent_list(void)
31 {
32         struct sys_grent *glist;
33         struct sys_grent *gent;
34         struct group *grp;
35         
36         gent = (struct sys_grent *) malloc(sizeof(struct sys_grent));
37         if (gent == NULL) {
38                 DEBUG (0, ("Out of memory in getgrent_list!\n"));
39                 return NULL;
40         }
41         memset(gent, '\0', sizeof(struct sys_grent));
42         glist = gent;
43         
44         setgrent();
45         grp = getgrent();
46         if (grp == NULL) {
47                 endgrent();
48                 SAFE_FREE(glist);
49                 return NULL;
50         }
51
52         while (grp != NULL) {
53                 int i,num;
54                 
55                 if (grp->gr_name) {
56                         if ((gent->gr_name = strdup(grp->gr_name)) == NULL)
57                                 goto err;
58                 }
59                 if (grp->gr_passwd) {
60                         if ((gent->gr_passwd = strdup(grp->gr_passwd)) == NULL)
61                                 goto err;
62                 }
63                 gent->gr_gid = grp->gr_gid;
64                 
65                 /* number of strings in gr_mem */
66                 for (num = 0; grp->gr_mem[num]; num++)
67                         ;
68                 
69                 /* alloc space for gr_mem string pointers */
70                 if ((gent->gr_mem = (char **) malloc((num+1) * sizeof(char *))) == NULL)
71                         goto err;
72
73                 memset(gent->gr_mem, '\0', (num+1) * sizeof(char *));
74
75                 for (i=0; i < num; i++) {
76                         if ((gent->gr_mem[i] = strdup(grp->gr_mem[i])) == NULL)
77                                 goto err;
78                 }
79                 gent->gr_mem[num] = NULL;
80                 
81                 grp = getgrent();
82                 if (grp) {
83                         gent->next = (struct sys_grent *) malloc(sizeof(struct sys_grent));
84                         if (gent->next == NULL)
85                                 goto err;
86                         gent = gent->next;
87                         memset(gent, '\0', sizeof(struct sys_grent));
88                 }
89         }
90         
91         endgrent();
92         return glist;
93
94   err:
95
96         endgrent();
97         DEBUG(0, ("Out of memory in getgrent_list!\n"));
98         grent_free(glist);
99         return NULL;
100 }
101
102 /****************************************************************
103  Free the single linked list of group entries made by
104  getgrent_list()
105 ****************************************************************/
106
107 void grent_free (struct sys_grent *glist)
108 {
109         while (glist) {
110                 struct sys_grent *prev;
111                 
112                 SAFE_FREE(glist->gr_name);
113                 SAFE_FREE(glist->gr_passwd);
114                 if (glist->gr_mem) {
115                         int i;
116                         for (i = 0; glist->gr_mem[i]; i++)
117                                 SAFE_FREE(glist->gr_mem[i]);
118                         SAFE_FREE(glist->gr_mem);
119                 }
120                 prev = glist;
121                 glist = glist->next;
122                 SAFE_FREE(prev);
123         }
124 }
125
126 /****************************************************************
127  Returns a single linked list of passwd entries.
128  Use pwent_free() to free it after use.
129 ****************************************************************/
130
131 struct sys_pwent * getpwent_list(void)
132 {
133         struct sys_pwent *plist;
134         struct sys_pwent *pent;
135         struct passwd *pwd;
136         
137         pent = (struct sys_pwent *) malloc(sizeof(struct sys_pwent));
138         if (pent == NULL) {
139                 DEBUG (0, ("Out of memory in getpwent_list!\n"));
140                 return NULL;
141         }
142         plist = pent;
143         
144         setpwent();
145         pwd = getpwent();
146         while (pwd != NULL) {
147                 memset(pent, '\0', sizeof(struct sys_pwent));
148                 if (pwd->pw_name) {
149                         if ((pent->pw_name = strdup(pwd->pw_name)) == NULL)
150                                 goto err;
151                 }
152                 if (pwd->pw_passwd) {
153                         if ((pent->pw_passwd = strdup(pwd->pw_passwd)) == NULL)
154                                 goto err;
155                 }
156                 pent->pw_uid = pwd->pw_uid;
157                 pent->pw_gid = pwd->pw_gid;
158                 if (pwd->pw_gecos) {
159                         if ((pent->pw_name = strdup(pwd->pw_gecos)) == NULL)
160                                 goto err;
161                 }
162                 if (pwd->pw_dir) {
163                         if ((pent->pw_name = strdup(pwd->pw_dir)) == NULL)
164                                 goto err;
165                 }
166                 if (pwd->pw_shell) {
167                         if ((pent->pw_name = strdup(pwd->pw_shell)) == NULL)
168                                 goto err;
169                 }
170
171                 pwd = getpwent();
172                 if (pwd) {
173                         pent->next = (struct sys_pwent *) malloc(sizeof(struct sys_pwent));
174                         if (pent->next == NULL)
175                                 goto err;
176                         pent = pent->next;
177                 }
178         }
179         
180         endpwent();
181         return plist;
182
183   err:
184
185         endpwent();
186         DEBUG(0, ("Out of memory in getpwent_list!\n"));
187         pwent_free(plist);
188         return NULL;
189 }
190
191 /****************************************************************
192  Free the single linked list of passwd entries made by
193  getpwent_list()
194 ****************************************************************/
195
196 void pwent_free (struct sys_pwent *plist)
197 {
198         while (plist) {
199                 struct sys_pwent *prev;
200                 
201                 SAFE_FREE(plist->pw_name);
202                 SAFE_FREE(plist->pw_passwd);
203                 SAFE_FREE(plist->pw_gecos);
204                 SAFE_FREE(plist->pw_dir);
205                 SAFE_FREE(plist->pw_shell);
206
207                 prev = plist;
208                 plist = plist->next;
209                 SAFE_FREE(prev);
210         }
211 }
212
213 /****************************************************************
214  Add the individual group users onto the list.
215 ****************************************************************/
216
217 static struct sys_userlist *add_members_to_userlist(struct sys_userlist *list_head, const struct group *grp)
218 {
219         size_t num_users, i;
220
221         /* Count the number of users. */
222         for (num_users = 0; grp->gr_mem[num_users]; num_users++)
223                 ;
224
225         for (i = 0; i < num_users; i++) {
226                 struct sys_userlist *entry = (struct sys_userlist *)malloc(sizeof(*entry));
227                 if (entry == NULL) {
228                         free_userlist(list_head);
229                         return NULL;
230                 }
231                 entry->unix_name = (char *)strdup(grp->gr_mem[i]);
232                 if (entry->unix_name == NULL) {
233                         SAFE_FREE(entry);
234                         free_userlist(list_head);
235                         return NULL;
236                 }
237                 DLIST_ADD(list_head, entry);
238         }
239         return list_head;
240 }
241
242 /****************************************************************
243  Get the list of UNIX users in a group.
244  We have to enumerate the /etc/group file as some UNIX getgrnam()
245  calls won't do that for us (notably Tru64 UNIX).
246 ****************************************************************/
247
248 struct sys_userlist *get_users_in_group(const char *gname)
249 {
250         struct sys_userlist *list_head = NULL;
251         struct group *gptr;
252         fstring domain;
253         fstring groupname;
254         DOM_SID sid;
255         enum SID_NAME_USE name_type;
256
257         /* No point using winbind if we can't split it in the
258            first place */
259         if (split_domain_and_name(gname, domain, groupname)) {
260
261                 /*
262                  * If we're doing this via winbindd, don't do the
263                  * entire group list enumeration as we know this is
264                  * pointless (and slow).
265                  */
266                 
267                 if (winbind_lookup_name(domain, groupname, &sid, &name_type) 
268                     && name_type == SID_NAME_DOM_GRP) {
269                         if ((gptr = (struct group *)getgrnam(gname)) == NULL)
270                                 return NULL;
271                         return add_members_to_userlist(list_head, gptr);
272                 }
273         }
274         
275 #if !defined(BROKEN_GETGRNAM)
276         if ((gptr = (struct group *)getgrnam(gname)) == NULL)
277                 return NULL;
278         return add_members_to_userlist(list_head, gptr);
279 #else
280         /* BROKEN_GETGRNAM - True64 */
281         setgrent();
282         while((gptr = getgrent()) != NULL) {
283                 if (strequal(gname, gptr->gr_name)) {
284                         list_head = add_members_to_userlist(list_head, gptr);
285                         if (list_head == NULL)
286                                 return NULL;
287                 }
288         }
289         endgrent();
290         return list_head;
291 #endif
292 }
293
294 /****************************************************************
295  Free list allocated above.
296 ****************************************************************/
297
298 void free_userlist(struct sys_userlist *list_head)
299 {
300         while (list_head) {
301                 struct sys_userlist *old_head = list_head;
302                 DLIST_REMOVE(list_head, list_head);
303                 SAFE_FREE(old_head->unix_name);
304                 SAFE_FREE(old_head);
305         }
306 }