96a85a4f3a0a8e569d6785c3e4ba245f724e3b2a
[samba.git] / 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 (!NT_STATUS_IS_OK(pdb_enum_aliasmem(group_sid, &members,
155                                                &num_members)))
156                 return True;
157
158         for (i=0; i<num_members; i++) {
159                 add_expanded_sid(&members[i], gr_mem, num_gr_mem);
160         }
161
162         SAFE_FREE(members);
163
164         if (*gr_mem != NULL) {
165                 size_t len;
166
167                 /* We have at least one member, strip off the last "," */
168                 len = strlen(*gr_mem);
169                 (*gr_mem)[len-1] = '\0';
170                 *gr_mem_len = len;
171         }
172
173         return True;
174 }
175
176 /* Query display info for a domain.  This returns enough information plus a
177    bit extra to give an overview of domain users for the User Manager
178    application. */
179 static NTSTATUS query_user_list(struct winbindd_domain *domain,
180                                TALLOC_CTX *mem_ctx,
181                                uint32 *num_entries, 
182                                WINBIND_USERINFO **info)
183 {
184         /* We don't have users */
185         *num_entries = 0;
186         *info = NULL;
187         return NT_STATUS_OK;
188 }
189
190 /* list all domain groups */
191 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
192                                 TALLOC_CTX *mem_ctx,
193                                 uint32 *num_entries, 
194                                 struct acct_info **info)
195 {
196         /* We don't have domain groups */
197         *num_entries = 0;
198         *info = NULL;
199         return NT_STATUS_OK;
200 }
201
202 /* List all domain groups */
203
204 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
205                                 TALLOC_CTX *mem_ctx,
206                                 uint32 *num_entries, 
207                                 struct acct_info **info)
208 {
209         struct pdb_search *search;
210         struct samr_displayentry *aliases;
211         int i;
212         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
213
214         search = pdb_search_aliases(&domain->sid);
215         if (search == NULL) goto done;
216
217         *num_entries = pdb_search_entries(search, 0, 0xffffffff, &aliases);
218         if (*num_entries == 0) goto done;
219
220         *info = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
221         if (*info == NULL) {
222                 result = NT_STATUS_NO_MEMORY;
223                 goto done;
224         }
225
226         for (i=0; i<*num_entries; i++) {
227                 fstrcpy((*info)[i].acct_name, aliases[i].account_name);
228                 fstrcpy((*info)[i].acct_desc, aliases[i].description);
229                 (*info)[i].rid = aliases[i].rid;
230         }
231
232         result = NT_STATUS_OK;
233  done:
234         pdb_search_destroy(search);
235         return result;
236 }
237
238 /* convert a single name to a sid in a domain */
239 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
240                             TALLOC_CTX *mem_ctx,
241                             const char *domain_name,
242                             const char *name,
243                             DOM_SID *sid,
244                             enum SID_NAME_USE *type)
245 {
246         DEBUG(10, ("Finding name %s\n", name));
247
248         if (!pdb_find_alias(name, sid))
249                 return NT_STATUS_NONE_MAPPED;
250
251         if (sid_check_is_in_builtin(sid))
252                 *type = SID_NAME_WKN_GRP;
253         else
254                 *type = SID_NAME_ALIAS;
255
256         return NT_STATUS_OK;
257 }
258
259 /*
260   convert a domain SID to a user or group name
261 */
262 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
263                             TALLOC_CTX *mem_ctx,
264                             const DOM_SID *sid,
265                             char **domain_name,
266                             char **name,
267                             enum SID_NAME_USE *type)
268 {
269         const char *dom, *nam;
270
271         DEBUG(10, ("Converting SID %s\n", sid_string_static(sid)));
272
273         /* Paranoia check */
274         if (!sid_check_is_in_builtin(sid) &&
275             !sid_check_is_in_our_domain(sid)) {
276                 DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with "
277                           "passdb backend\n", sid_string_static(sid)));
278                 return NT_STATUS_NONE_MAPPED;
279         }
280
281         if (!lookup_sid(mem_ctx, sid, &dom, &nam, type)) {
282                 return NT_STATUS_NONE_MAPPED;
283         }
284
285         *domain_name = talloc_strdup(mem_ctx, dom);
286         *name = talloc_strdup(mem_ctx, nam);
287
288         return NT_STATUS_OK;
289 }
290
291 /* Lookup user information from a rid or username. */
292 static NTSTATUS query_user(struct winbindd_domain *domain, 
293                            TALLOC_CTX *mem_ctx, 
294                            const DOM_SID *user_sid,
295                            WINBIND_USERINFO *user_info)
296 {
297         return NT_STATUS_NO_SUCH_USER;
298 }
299
300 /* Lookup groups a user is a member of.  I wish Unix had a call like this! */
301 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
302                                   TALLOC_CTX *mem_ctx,
303                                   const DOM_SID *user_sid,
304                                   uint32 *num_groups, DOM_SID **user_gids)
305 {
306         return NT_STATUS_NO_SUCH_USER;
307 }
308
309 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
310                                    TALLOC_CTX *mem_ctx,
311                                    uint32 num_sids, const DOM_SID *sids,
312                                    uint32 *p_num_aliases, uint32 **rids)
313 {
314         NTSTATUS result;
315         size_t num_aliases = 0;
316
317         result = pdb_enum_alias_memberships(mem_ctx, &domain->sid,
318                                             sids, num_sids, rids, &num_aliases);
319
320         *p_num_aliases = num_aliases;
321         return result;
322 }
323
324 /* Lookup group membership given a rid.   */
325 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
326                                 TALLOC_CTX *mem_ctx,
327                                 const DOM_SID *group_sid, uint32 *num_names, 
328                                 DOM_SID **sid_mem, char ***names, 
329                                 uint32 **name_types)
330 {
331         size_t i, num_members, num_mapped;
332         uint32 *rids;
333         NTSTATUS result;
334         const DOM_SID **sids;
335         struct lsa_dom_info *lsa_domains;
336         struct lsa_name_info *lsa_names;
337
338         if (!sid_check_is_in_our_domain(group_sid)) {
339                 /* There's no groups, only aliases in BUILTIN */
340                 return NT_STATUS_NO_SUCH_GROUP;
341         }
342
343         result = pdb_enum_group_members(mem_ctx, group_sid, &rids,
344                                         &num_members);
345         if (!NT_STATUS_IS_OK(result)) {
346                 return result;
347         }
348
349         if (num_members == 0) {
350                 *num_names = 0;
351                 *sid_mem = NULL;
352                 *names = NULL;
353                 *name_types = NULL;
354                 return NT_STATUS_OK;
355         }
356
357         *sid_mem = TALLOC_ARRAY(mem_ctx, DOM_SID, num_members);
358         *names = TALLOC_ARRAY(mem_ctx, char *, num_members);
359         *name_types = TALLOC_ARRAY(mem_ctx, uint32, num_members);
360         sids = TALLOC_ARRAY(mem_ctx, const DOM_SID *, num_members);
361
362         if (((*sid_mem) == NULL) || ((*names) == NULL) ||
363             ((*name_types) == NULL) || (sids == NULL)) {
364                 return NT_STATUS_NO_MEMORY;
365         }
366
367         for (i=0; i<num_members; i++) {
368                 DOM_SID *sid = &((*sid_mem)[i]);
369                 sid_copy(sid, &domain->sid);
370                 sid_append_rid(sid, rids[i]);
371                 sids[i] = sid;
372         }
373
374         result = lookup_sids(mem_ctx, num_members, sids, 1,
375                              &lsa_domains, &lsa_names);
376         if (!NT_STATUS_IS_OK(result)) {
377                 return result;
378         }
379
380         num_mapped = 0;
381         for (i=0; i<num_members; i++) {
382                 if (lsa_names[i].type != SID_NAME_USER) {
383                         DEBUG(2, ("Got %s as group member -- ignoring\n",
384                                   sid_type_lookup(lsa_names[i].type)));
385                         continue;
386                 }
387                 (*names)[i] = talloc_steal((*names),
388                                            lsa_names[i].name);
389                 (*name_types)[i] = lsa_names[i].type;
390
391                 num_mapped += 1;
392         }
393
394         *num_names = num_mapped;
395
396         return NT_STATUS_OK;
397 }
398
399 /* find the sequence number for a domain */
400 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
401 {
402         BOOL result;
403         time_t seq_num;
404
405         result = pdb_get_seq_num(&seq_num);
406         if (!result) {
407                 *seq = 1;
408         }
409
410         *seq = (int) seq_num;
411         /* *seq = 1; */
412         return NT_STATUS_OK;
413 }
414
415 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
416                                TALLOC_CTX *mem_ctx,
417                                SAM_UNK_INFO_12 *lockout_policy)
418 {
419         /* actually we have that */
420         return NT_STATUS_NOT_IMPLEMENTED;
421 }
422
423 static NTSTATUS password_policy(struct winbindd_domain *domain,
424                                 TALLOC_CTX *mem_ctx,
425                                 SAM_UNK_INFO_1 *password_policy)
426 {
427         /* actually we have that */
428         return NT_STATUS_NOT_IMPLEMENTED;
429 }
430
431 /* get a list of trusted domains */
432 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
433                                 TALLOC_CTX *mem_ctx,
434                                 uint32 *num_domains,
435                                 char ***names,
436                                 char ***alt_names,
437                                 DOM_SID **dom_sids)
438 {
439         NTSTATUS nt_status;
440         struct trustdom_info **domains;
441         int i;
442
443         *num_domains = 0;
444         *names = NULL;
445         *alt_names = NULL;
446         *dom_sids = NULL;
447
448         nt_status = secrets_trusted_domains(mem_ctx, num_domains,
449                                             &domains);
450         if (!NT_STATUS_IS_OK(nt_status)) {
451                 return nt_status;
452         }
453
454         *names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
455         *alt_names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
456         *dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
457
458         if ((*alt_names == NULL) || (*names == NULL) || (*dom_sids == NULL)) {
459                 return NT_STATUS_NO_MEMORY;
460         }
461
462         for (i=0; i<*num_domains; i++) {
463                 (*alt_names)[i] = NULL;
464                 (*names)[i] = talloc_steal((*names), domains[i]->name);
465                 sid_copy(&(*dom_sids)[i], &domains[i]->sid);
466         }
467
468         return NT_STATUS_OK;
469 }
470
471 /* the rpc backend methods are exposed via this structure */
472 struct winbindd_methods passdb_methods = {
473         False,
474         query_user_list,
475         enum_dom_groups,
476         enum_local_groups,
477         name_to_sid,
478         sid_to_name,
479         query_user,
480         lookup_usergroups,
481         lookup_useraliases,
482         lookup_groupmem,
483         sequence_number,
484         lockout_policy,
485         password_policy,
486         trusted_domains,
487 };