Initial import
[samba] / source / nsswitch / winbindd_passdb.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Winbind rpc backend functions
5
6    Copyright (C) Tim Potter 2000-2001,2003
7    Copyright (C) Simo Sorce 2003
8    Copyright (C) Volker Lendecke 2004
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "winbindd.h"
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_WINBIND
30
31 static void add_member(const char *domain, const char *user,
32            char **pp_members, size_t *p_num_members)
33 {
34         fstring name;
35
36         fill_domain_username(name, domain, user);
37         safe_strcat(name, ",", sizeof(name)-1);
38         string_append(pp_members, name);
39         *p_num_members += 1;
40 }
41
42 /**********************************************************************
43  Add member users resulting from sid. Expand if it is a domain group.
44 **********************************************************************/
45
46 static void add_expanded_sid(const DOM_SID *sid, char **pp_members, size_t *p_num_members)
47 {
48         DOM_SID dom_sid;
49         uint32 rid;
50         struct winbindd_domain *domain;
51         size_t i;
52
53         char *domain_name = NULL;
54         char *name = NULL;
55         enum SID_NAME_USE type;
56
57         uint32 num_names;
58         DOM_SID *sid_mem;
59         char **names;
60         uint32 *types;
61
62         NTSTATUS result;
63
64         TALLOC_CTX *mem_ctx = talloc_init("add_expanded_sid");
65
66         if (mem_ctx == NULL) {
67                 DEBUG(1, ("talloc_init failed\n"));
68                 return;
69         }
70
71         sid_copy(&dom_sid, sid);
72         sid_split_rid(&dom_sid, &rid);
73
74         domain = find_lookup_domain_from_sid(sid);
75
76         if (domain == NULL) {
77                 DEBUG(3, ("Could not find domain for sid %s\n",
78                           sid_string_static(sid)));
79                 goto done;
80         }
81
82         result = domain->methods->sid_to_name(domain, mem_ctx, sid,
83                                               &domain_name, &name, &type);
84
85         if (!NT_STATUS_IS_OK(result)) {
86                 DEBUG(3, ("sid_to_name failed for sid %s\n",
87                           sid_string_static(sid)));
88                 goto done;
89         }
90
91         DEBUG(10, ("Found name %s, type %d\n", name, type));
92
93         if (type == SID_NAME_USER) {
94                 add_member(domain_name, name, pp_members, p_num_members);
95                 goto done;
96         }
97
98         if (type != SID_NAME_DOM_GRP) {
99                 DEBUG(10, ("Alias member %s neither user nor group, ignore\n",
100                            name));
101                 goto done;
102         }
103
104         /* Expand the domain group, this must be done via the target domain */
105
106         domain = find_domain_from_sid(sid);
107
108         if (domain == NULL) {
109                 DEBUG(3, ("Could not find domain from SID %s\n",
110                           sid_string_static(sid)));
111                 goto done;
112         }
113
114         result = domain->methods->lookup_groupmem(domain, mem_ctx,
115                                                   sid, &num_names,
116                                                   &sid_mem, &names,
117                                                   &types);
118
119         if (!NT_STATUS_IS_OK(result)) {
120                 DEBUG(10, ("Could not lookup group members for %s: %s\n",
121                            name, nt_errstr(result)));
122                 goto done;
123         }
124
125         for (i=0; i<num_names; i++) {
126                 DEBUG(10, ("Adding group member SID %s\n",
127                            sid_string_static(&sid_mem[i])));
128
129                 if (types[i] != SID_NAME_USER) {
130                         DEBUG(1, ("Hmmm. Member %s of group %s is no user. "
131                                   "Ignoring.\n", names[i], name));
132                         continue;
133                 }
134
135                 add_member(domain->name, names[i], pp_members, p_num_members);
136         }
137
138  done:
139         talloc_destroy(mem_ctx);
140         return;
141 }
142
143 BOOL fill_passdb_alias_grmem(struct winbindd_domain *domain,
144                              DOM_SID *group_sid, 
145                              size_t *num_gr_mem, char **gr_mem, size_t *gr_mem_len)
146 {
147         DOM_SID *members;
148         size_t i, num_members;
149
150         *num_gr_mem = 0;
151         *gr_mem = NULL;
152         *gr_mem_len = 0;
153
154         if (!pdb_enum_aliasmem(group_sid, &members, &num_members))
155                 return True;
156
157         for (i=0; i<num_members; i++) {
158                 add_expanded_sid(&members[i], gr_mem, num_gr_mem);
159         }
160
161         SAFE_FREE(members);
162
163         if (*gr_mem != NULL) {
164                 size_t len;
165
166                 /* We have at least one member, strip off the last "," */
167                 len = strlen(*gr_mem);
168                 (*gr_mem)[len-1] = '\0';
169                 *gr_mem_len = len;
170         }
171
172         return True;
173 }
174
175 /* Query display info for a domain.  This returns enough information plus a
176    bit extra to give an overview of domain users for the User Manager
177    application. */
178 static NTSTATUS query_user_list(struct winbindd_domain *domain,
179                                TALLOC_CTX *mem_ctx,
180                                uint32 *num_entries, 
181                                WINBIND_USERINFO **info)
182 {
183         /* We don't have users */
184         *num_entries = 0;
185         *info = NULL;
186         return NT_STATUS_OK;
187 }
188
189 /* list all domain groups */
190 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
191                                 TALLOC_CTX *mem_ctx,
192                                 uint32 *num_entries, 
193                                 struct acct_info **info)
194 {
195         /* We don't have domain groups */
196         *num_entries = 0;
197         *info = NULL;
198         return NT_STATUS_OK;
199 }
200
201 /* List all domain groups */
202
203 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
204                                 TALLOC_CTX *mem_ctx,
205                                 uint32 *num_entries, 
206                                 struct acct_info **info)
207 {
208         struct pdb_search *search;
209         struct samr_displayentry *aliases;
210         int i;
211         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
212
213         search = pdb_search_aliases(&domain->sid);
214         if (search == NULL) goto done;
215
216         *num_entries = pdb_search_entries(search, 0, 0xffffffff, &aliases);
217         if (*num_entries == 0) goto done;
218
219         *info = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
220         if (*info == NULL) {
221                 result = NT_STATUS_NO_MEMORY;
222                 goto done;
223         }
224
225         for (i=0; i<*num_entries; i++) {
226                 fstrcpy((*info)[i].acct_name, aliases[i].account_name);
227                 fstrcpy((*info)[i].acct_desc, aliases[i].description);
228                 (*info)[i].rid = aliases[i].rid;
229         }
230
231         result = NT_STATUS_OK;
232  done:
233         pdb_search_destroy(search);
234         return result;
235 }
236
237 /* convert a single name to a sid in a domain */
238 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
239                             TALLOC_CTX *mem_ctx,
240                             const char *domain_name,
241                             const char *name,
242                             DOM_SID *sid,
243                             enum SID_NAME_USE *type)
244 {
245         DEBUG(10, ("Finding name %s\n", name));
246
247         if (!pdb_find_alias(name, sid))
248                 return NT_STATUS_NONE_MAPPED;
249
250         if (sid_check_is_in_builtin(sid))
251                 *type = SID_NAME_WKN_GRP;
252         else
253                 *type = SID_NAME_ALIAS;
254
255         return NT_STATUS_OK;
256 }
257
258 /*
259   convert a domain SID to a user or group name
260 */
261 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
262                             TALLOC_CTX *mem_ctx,
263                             const DOM_SID *sid,
264                             char **domain_name,
265                             char **name,
266                             enum SID_NAME_USE *type)
267 {
268         struct acct_info info;
269
270         DEBUG(10, ("Converting SID %s\n", sid_string_static(sid)));
271
272         if (!pdb_get_aliasinfo(sid, &info))
273                 return NT_STATUS_NONE_MAPPED;
274
275         *domain_name = talloc_strdup(mem_ctx, domain->name);
276         *name = talloc_strdup(mem_ctx, info.acct_name);
277         if (sid_check_is_in_builtin(sid))
278                 *type = SID_NAME_WKN_GRP;
279         else
280                 *type = SID_NAME_ALIAS;
281
282         return NT_STATUS_OK;
283 }
284
285 /* Lookup user information from a rid or username. */
286 static NTSTATUS query_user(struct winbindd_domain *domain, 
287                            TALLOC_CTX *mem_ctx, 
288                            const DOM_SID *user_sid,
289                            WINBIND_USERINFO *user_info)
290 {
291         return NT_STATUS_NO_SUCH_USER;
292 }
293
294 /* Lookup groups a user is a member of.  I wish Unix had a call like this! */
295 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
296                                   TALLOC_CTX *mem_ctx,
297                                   const DOM_SID *user_sid,
298                                   uint32 *num_groups, DOM_SID **user_gids)
299 {
300         return NT_STATUS_NO_SUCH_USER;
301 }
302
303 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
304                                    TALLOC_CTX *mem_ctx,
305                                    uint32 num_sids, const DOM_SID *sids,
306                                    uint32 *p_num_aliases, uint32 **rids)
307 {
308         BOOL result;
309         size_t num_aliases = 0;
310
311         result = pdb_enum_alias_memberships(mem_ctx, &domain->sid,
312                                             sids, num_sids, rids, &num_aliases);
313
314         *p_num_aliases = num_aliases;
315         return result ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
316 }
317
318 /* Lookup group membership given a rid.   */
319 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
320                                 TALLOC_CTX *mem_ctx,
321                                 const DOM_SID *group_sid, uint32 *num_names, 
322                                 DOM_SID **sid_mem, char ***names, 
323                                 uint32 **name_types)
324 {
325         return NT_STATUS_OK;
326 }
327
328 /* find the sequence number for a domain */
329 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
330 {
331         *seq = 1;
332         return NT_STATUS_OK;
333 }
334
335 /* get a list of trusted domains */
336 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
337                                 TALLOC_CTX *mem_ctx,
338                                 uint32 *num_domains,
339                                 char ***names,
340                                 char ***alt_names,
341                                 DOM_SID **dom_sids)
342 {
343         NTSTATUS nt_status;
344         int enum_ctx = 0;
345         int num_sec_domains;
346         TRUSTDOM **domains;
347         *num_domains = 0;
348         *names = NULL;
349         *alt_names = NULL;
350         *dom_sids = NULL;
351         do {
352                 int i;
353                 nt_status = secrets_get_trusted_domains(mem_ctx, &enum_ctx, 1,
354                                                         &num_sec_domains,
355                                                         &domains);
356                 *names = TALLOC_REALLOC_ARRAY(mem_ctx, *names, char *,
357                                         num_sec_domains + *num_domains);
358                 *alt_names = TALLOC_REALLOC_ARRAY(mem_ctx, *alt_names, char *,
359                                             num_sec_domains + *num_domains);
360                 *dom_sids = TALLOC_REALLOC_ARRAY(mem_ctx, *dom_sids, DOM_SID,
361                                            num_sec_domains + *num_domains);
362
363                 for (i=0; i< num_sec_domains; i++) {
364                         if (pull_ucs2_talloc(mem_ctx, &(*names)[*num_domains],
365                                              domains[i]->name) == -1) {
366                                 return NT_STATUS_NO_MEMORY;
367                         }
368                         (*alt_names)[*num_domains] = NULL;
369                         (*dom_sids)[*num_domains] = domains[i]->sid;
370                         (*num_domains)++;
371                 }
372
373         } while (NT_STATUS_EQUAL(nt_status, STATUS_MORE_ENTRIES));
374
375         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MORE_ENTRIES)) {
376                 return NT_STATUS_OK;
377         }
378         return nt_status;
379 }
380
381 /* the rpc backend methods are exposed via this structure */
382 struct winbindd_methods passdb_methods = {
383         False,
384         query_user_list,
385         enum_dom_groups,
386         enum_local_groups,
387         name_to_sid,
388         sid_to_name,
389         query_user,
390         lookup_usergroups,
391         lookup_useraliases,
392         lookup_groupmem,
393         sequence_number,
394         trusted_domains,
395 };