b949ea080851eef8a8b4e87a4108e4ab93e9bd8e
[samba.git] / source3 / 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, True);
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 ( !lookup_name( mem_ctx, name, LOOKUP_NAME_ALL, 
249                 NULL, NULL, sid, type ) )
250         {
251                 return NT_STATUS_NONE_MAPPED;
252         }
253
254         return NT_STATUS_OK;
255 }
256
257 /*
258   convert a domain SID to a user or group name
259 */
260 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
261                             TALLOC_CTX *mem_ctx,
262                             const DOM_SID *sid,
263                             char **domain_name,
264                             char **name,
265                             enum SID_NAME_USE *type)
266 {
267         const char *dom, *nam;
268
269         DEBUG(10, ("Converting SID %s\n", sid_string_static(sid)));
270
271         /* Paranoia check */
272         if (!sid_check_is_in_builtin(sid) &&
273             !sid_check_is_in_our_domain(sid)) {
274                 DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with "
275                           "passdb backend\n", sid_string_static(sid)));
276                 return NT_STATUS_NONE_MAPPED;
277         }
278
279         if (!lookup_sid(mem_ctx, sid, &dom, &nam, type)) {
280                 return NT_STATUS_NONE_MAPPED;
281         }
282
283         *domain_name = talloc_strdup(mem_ctx, dom);
284         *name = talloc_strdup(mem_ctx, nam);
285
286         return NT_STATUS_OK;
287 }
288
289 /* Lookup user information from a rid or username. */
290 static NTSTATUS query_user(struct winbindd_domain *domain, 
291                            TALLOC_CTX *mem_ctx, 
292                            const DOM_SID *user_sid,
293                            WINBIND_USERINFO *user_info)
294 {
295         return NT_STATUS_NO_SUCH_USER;
296 }
297
298 /* Lookup groups a user is a member of.  I wish Unix had a call like this! */
299 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
300                                   TALLOC_CTX *mem_ctx,
301                                   const DOM_SID *user_sid,
302                                   uint32 *num_groups, DOM_SID **user_gids)
303 {
304         NTSTATUS result;
305         DOM_SID *groups = NULL;
306         gid_t *gids = NULL;
307         size_t ngroups = 0;
308         struct samu *user;
309
310         if ( (user = samu_new(mem_ctx)) == NULL ) {
311                 return NT_STATUS_NO_MEMORY;
312         }
313
314         if ( !pdb_getsampwsid( user, user_sid ) ) {
315                 return NT_STATUS_NO_SUCH_USER;
316         }
317
318         result = pdb_enum_group_memberships( mem_ctx, user, &groups, &gids, &ngroups );
319
320         TALLOC_FREE( user );
321
322         *num_groups = (uint32)ngroups;
323         *user_gids = groups;
324
325         return result;
326 }
327
328 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
329                                    TALLOC_CTX *mem_ctx,
330                                    uint32 num_sids, const DOM_SID *sids,
331                                    uint32 *p_num_aliases, uint32 **rids)
332 {
333         NTSTATUS result;
334         size_t num_aliases = 0;
335
336         result = pdb_enum_alias_memberships(mem_ctx, &domain->sid,
337                                             sids, num_sids, rids, &num_aliases);
338
339         *p_num_aliases = num_aliases;
340         return result;
341 }
342
343 /* Lookup group membership given a rid.   */
344 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
345                                 TALLOC_CTX *mem_ctx,
346                                 const DOM_SID *group_sid, uint32 *num_names, 
347                                 DOM_SID **sid_mem, char ***names, 
348                                 uint32 **name_types)
349 {
350         size_t i, num_members, num_mapped;
351         uint32 *rids;
352         NTSTATUS result;
353         const DOM_SID **sids;
354         struct lsa_dom_info *lsa_domains;
355         struct lsa_name_info *lsa_names;
356
357         if (!sid_check_is_in_our_domain(group_sid)) {
358                 /* There's no groups, only aliases in BUILTIN */
359                 return NT_STATUS_NO_SUCH_GROUP;
360         }
361
362         result = pdb_enum_group_members(mem_ctx, group_sid, &rids,
363                                         &num_members);
364         if (!NT_STATUS_IS_OK(result)) {
365                 return result;
366         }
367
368         if (num_members == 0) {
369                 *num_names = 0;
370                 *sid_mem = NULL;
371                 *names = NULL;
372                 *name_types = NULL;
373                 return NT_STATUS_OK;
374         }
375
376         *sid_mem = TALLOC_ARRAY(mem_ctx, DOM_SID, num_members);
377         *names = TALLOC_ARRAY(mem_ctx, char *, num_members);
378         *name_types = TALLOC_ARRAY(mem_ctx, uint32, num_members);
379         sids = TALLOC_ARRAY(mem_ctx, const DOM_SID *, num_members);
380
381         if (((*sid_mem) == NULL) || ((*names) == NULL) ||
382             ((*name_types) == NULL) || (sids == NULL)) {
383                 return NT_STATUS_NO_MEMORY;
384         }
385
386         for (i=0; i<num_members; i++) {
387                 DOM_SID *sid = &((*sid_mem)[i]);
388                 sid_copy(sid, &domain->sid);
389                 sid_append_rid(sid, rids[i]);
390                 sids[i] = sid;
391         }
392
393         result = lookup_sids(mem_ctx, num_members, sids, 1,
394                              &lsa_domains, &lsa_names);
395         if (!NT_STATUS_IS_OK(result)) {
396                 return result;
397         }
398
399         num_mapped = 0;
400         for (i=0; i<num_members; i++) {
401                 if (lsa_names[i].type != SID_NAME_USER) {
402                         DEBUG(2, ("Got %s as group member -- ignoring\n",
403                                   sid_type_lookup(lsa_names[i].type)));
404                         continue;
405                 }
406                 (*names)[i] = talloc_steal((*names),
407                                            lsa_names[i].name);
408                 (*name_types)[i] = lsa_names[i].type;
409
410                 num_mapped += 1;
411         }
412
413         *num_names = num_mapped;
414
415         return NT_STATUS_OK;
416 }
417
418 /* find the sequence number for a domain */
419 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
420 {
421         BOOL result;
422         time_t seq_num;
423
424         result = pdb_get_seq_num(&seq_num);
425         if (!result) {
426                 *seq = 1;
427         }
428
429         *seq = (int) seq_num;
430         /* *seq = 1; */
431         return NT_STATUS_OK;
432 }
433
434 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
435                                TALLOC_CTX *mem_ctx,
436                                SAM_UNK_INFO_12 *policy)
437 {
438         /* actually we have that */
439         return NT_STATUS_NOT_IMPLEMENTED;
440 }
441
442 static NTSTATUS password_policy(struct winbindd_domain *domain,
443                                 TALLOC_CTX *mem_ctx,
444                                 SAM_UNK_INFO_1 *policy)
445 {
446         uint32 min_pass_len,pass_hist,password_properties;
447         time_t u_expire, u_min_age;
448         NTTIME nt_expire, nt_min_age;
449         uint32 account_policy_temp;
450
451         if ((policy = TALLOC_ZERO_P(mem_ctx, SAM_UNK_INFO_1)) == NULL) {
452                 return NT_STATUS_NO_MEMORY;
453         }
454
455         if (!pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &account_policy_temp)) {
456                 return NT_STATUS_ACCESS_DENIED;
457         }
458         min_pass_len = account_policy_temp;
459
460         if (!pdb_get_account_policy(AP_PASSWORD_HISTORY, &account_policy_temp)) {
461                 return NT_STATUS_ACCESS_DENIED;
462         }
463         pass_hist = account_policy_temp;
464
465         if (!pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, &account_policy_temp)) {
466                 return NT_STATUS_ACCESS_DENIED;
467         }
468         password_properties = account_policy_temp;
469         
470         if (!pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &account_policy_temp)) {
471                 return NT_STATUS_ACCESS_DENIED;
472         }
473         u_expire = account_policy_temp;
474
475         if (!pdb_get_account_policy(AP_MIN_PASSWORD_AGE, &account_policy_temp)) {
476                 return NT_STATUS_ACCESS_DENIED;
477         }
478         u_min_age = account_policy_temp;
479
480         unix_to_nt_time_abs(&nt_expire, u_expire);
481         unix_to_nt_time_abs(&nt_min_age, u_min_age);
482
483         init_unk_info1(policy, (uint16)min_pass_len, (uint16)pass_hist, 
484                        password_properties, nt_expire, nt_min_age);
485
486         return NT_STATUS_OK;
487 }
488
489 /* get a list of trusted domains */
490 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
491                                 TALLOC_CTX *mem_ctx,
492                                 uint32 *num_domains,
493                                 char ***names,
494                                 char ***alt_names,
495                                 DOM_SID **dom_sids)
496 {
497         NTSTATUS nt_status;
498         struct trustdom_info **domains;
499         int i;
500
501         *num_domains = 0;
502         *names = NULL;
503         *alt_names = NULL;
504         *dom_sids = NULL;
505
506         nt_status = secrets_trusted_domains(mem_ctx, num_domains,
507                                             &domains);
508         if (!NT_STATUS_IS_OK(nt_status)) {
509                 return nt_status;
510         }
511
512         *names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
513         *alt_names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
514         *dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
515
516         if ((*alt_names == NULL) || (*names == NULL) || (*dom_sids == NULL)) {
517                 return NT_STATUS_NO_MEMORY;
518         }
519
520         for (i=0; i<*num_domains; i++) {
521                 (*alt_names)[i] = NULL;
522                 (*names)[i] = talloc_steal((*names), domains[i]->name);
523                 sid_copy(&(*dom_sids)[i], &domains[i]->sid);
524         }
525
526         return NT_STATUS_OK;
527 }
528
529 /* the rpc backend methods are exposed via this structure */
530 struct winbindd_methods passdb_methods = {
531         False,
532         query_user_list,
533         enum_dom_groups,
534         enum_local_groups,
535         name_to_sid,
536         sid_to_name,
537         query_user,
538         lookup_usergroups,
539         lookup_useraliases,
540         lookup_groupmem,
541         sequence_number,
542         lockout_policy,
543         password_policy,
544         trusted_domains,
545 };