Initial import
[samba] / source / 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 = SMB_MALLOC_P(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 = SMB_STRDUP(grp->gr_name)) == NULL)
57                                 goto err;
58                 }
59                 if (grp->gr_passwd) {
60                         if ((gent->gr_passwd = SMB_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 = SMB_MALLOC_ARRAY(char *, num+1)) == 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] = SMB_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 = SMB_MALLOC_P(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 = SMB_MALLOC_P(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 = SMB_STRDUP(pwd->pw_name)) == NULL)
150                                 goto err;
151                 }
152                 if (pwd->pw_passwd) {
153                         if ((pent->pw_passwd = SMB_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_gecos = SMB_STRDUP(pwd->pw_gecos)) == NULL)
160                                 goto err;
161                 }
162                 if (pwd->pw_dir) {
163                         if ((pent->pw_dir = SMB_STRDUP(pwd->pw_dir)) == NULL)
164                                 goto err;
165                 }
166                 if (pwd->pw_shell) {
167                         if ((pent->pw_shell = SMB_STRDUP(pwd->pw_shell)) == NULL)
168                                 goto err;
169                 }
170
171                 pwd = getpwent();
172                 if (pwd) {
173                         pent->next = SMB_MALLOC_P(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 = SMB_MALLOC_P(struct sys_userlist);
227                 if (entry == NULL) {
228                         free_userlist(list_head);
229                         return NULL;
230                 }
231                 entry->unix_name = (char *)SMB_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  Splits passed user or group name to domain and user/group name parts
244  Returns True if name was splitted and False otherwise.
245 *****************************************************************/
246
247 static BOOL split_domain_and_name(const char *name, char *domain,
248                                   char* username)
249 {
250         char *p = strchr(name,*lp_winbind_separator());
251         
252         
253         /* Parse a string of the form DOMAIN/user into a domain and a user */
254         DEBUG(10,("split_domain_and_name: checking whether name |%s| local or "
255                   "not\n", name));
256         
257         if (p) {
258                 fstrcpy(username, p+1);
259                 fstrcpy(domain, name);
260                 domain[PTR_DIFF(p, name)] = 0;
261         } else if (lp_winbind_use_default_domain()) {
262                 fstrcpy(username, name);
263                 fstrcpy(domain, lp_workgroup());
264         } else {
265                 return False;
266         }
267
268         DEBUG(10,("split_domain_and_name: all is fine, domain is |%s| and "
269                   "name is |%s|\n", domain, username));
270         return True;
271 }
272
273 /****************************************************************
274  Get the list of UNIX users in a group.
275  We have to enumerate the /etc/group file as some UNIX getgrnam()
276  calls won't do that for us (notably Tru64 UNIX).
277 ****************************************************************/
278
279 struct sys_userlist *get_users_in_group(const char *gname)
280 {
281         struct sys_userlist *list_head = NULL;
282         struct group *gptr;
283         fstring domain;
284         fstring groupname;
285         DOM_SID sid;
286         enum SID_NAME_USE name_type;
287
288         /* No point using winbind if we can't split it in the
289            first place */
290         if (split_domain_and_name(gname, domain, groupname)) {
291
292                 /*
293                  * If we're doing this via winbindd, don't do the
294                  * entire group list enumeration as we know this is
295                  * pointless (and slow).
296                  */
297                 
298                 if (winbind_lookup_name(domain, groupname, &sid, &name_type) 
299                     && name_type == SID_NAME_DOM_GRP) {
300                         if ((gptr = (struct group *)getgrnam(gname)) == NULL)
301                                 return NULL;
302                         return add_members_to_userlist(list_head, gptr);
303                 }
304         }
305         
306 #if !defined(BROKEN_GETGRNAM)
307         if ((gptr = (struct group *)getgrnam(gname)) == NULL)
308                 return NULL;
309         return add_members_to_userlist(list_head, gptr);
310 #else
311         /* BROKEN_GETGRNAM - True64 */
312         setgrent();
313         while((gptr = getgrent()) != NULL) {
314                 if (strequal(gname, gptr->gr_name)) {
315                         list_head = add_members_to_userlist(list_head, gptr);
316                         if (list_head == NULL)
317                                 return NULL;
318                 }
319         }
320         endgrent();
321         return list_head;
322 #endif
323 }
324
325 /****************************************************************
326  Free list allocated above.
327 ****************************************************************/
328
329 void free_userlist(struct sys_userlist *list_head)
330 {
331         while (list_head) {
332                 struct sys_userlist *old_head = list_head;
333                 DLIST_REMOVE(list_head, list_head);
334                 SAFE_FREE(old_head->unix_name);
335                 SAFE_FREE(old_head);
336         }
337 }