r22589: Make TALLOC_ARRAY consistent across all uses.
[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 /* Query display info for a domain.  This returns enough information plus a
32    bit extra to give an overview of domain users for the User Manager
33    application. */
34 static NTSTATUS query_user_list(struct winbindd_domain *domain,
35                                TALLOC_CTX *mem_ctx,
36                                uint32 *num_entries, 
37                                WINBIND_USERINFO **info)
38 {
39         /* We don't have users */
40         *num_entries = 0;
41         *info = NULL;
42         return NT_STATUS_OK;
43 }
44
45 /* list all domain groups */
46 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
47                                 TALLOC_CTX *mem_ctx,
48                                 uint32 *num_entries, 
49                                 struct acct_info **info)
50 {
51         /* We don't have domain groups */
52         *num_entries = 0;
53         *info = NULL;
54         return NT_STATUS_OK;
55 }
56
57 /* List all domain groups */
58
59 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
60                                 TALLOC_CTX *mem_ctx,
61                                 uint32 *num_entries, 
62                                 struct acct_info **info)
63 {
64         struct pdb_search *search;
65         struct samr_displayentry *aliases;
66         int i;
67         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
68
69         search = pdb_search_aliases(&domain->sid);
70         if (search == NULL) goto done;
71
72         *num_entries = pdb_search_entries(search, 0, 0xffffffff, &aliases);
73         if (*num_entries == 0) goto done;
74
75         *info = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
76         if (*info == NULL) {
77                 result = NT_STATUS_NO_MEMORY;
78                 goto done;
79         }
80
81         for (i=0; i<*num_entries; i++) {
82                 fstrcpy((*info)[i].acct_name, aliases[i].account_name);
83                 fstrcpy((*info)[i].acct_desc, aliases[i].description);
84                 (*info)[i].rid = aliases[i].rid;
85         }
86
87         result = NT_STATUS_OK;
88  done:
89         pdb_search_destroy(search);
90         return result;
91 }
92
93 /* convert a single name to a sid in a domain */
94 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
95                             TALLOC_CTX *mem_ctx,
96                             const char *domain_name,
97                             const char *name,
98                             DOM_SID *sid,
99                             enum lsa_SidType *type)
100 {
101         DEBUG(10, ("Finding name %s\n", name));
102
103         if ( !lookup_name( mem_ctx, name, LOOKUP_NAME_ALL, 
104                 NULL, NULL, sid, type ) )
105         {
106                 return NT_STATUS_NONE_MAPPED;
107         }
108
109         return NT_STATUS_OK;
110 }
111
112 /*
113   convert a domain SID to a user or group name
114 */
115 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
116                             TALLOC_CTX *mem_ctx,
117                             const DOM_SID *sid,
118                             char **domain_name,
119                             char **name,
120                             enum lsa_SidType *type)
121 {
122         const char *dom, *nam;
123
124         DEBUG(10, ("Converting SID %s\n", sid_string_static(sid)));
125
126         /* Paranoia check */
127         if (!sid_check_is_in_builtin(sid) &&
128             !sid_check_is_in_our_domain(sid)) {
129                 DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with "
130                           "passdb backend\n", sid_string_static(sid)));
131                 return NT_STATUS_NONE_MAPPED;
132         }
133
134         if (!lookup_sid(mem_ctx, sid, &dom, &nam, type)) {
135                 return NT_STATUS_NONE_MAPPED;
136         }
137
138         *domain_name = talloc_strdup(mem_ctx, dom);
139         *name = talloc_strdup(mem_ctx, nam);
140
141         return NT_STATUS_OK;
142 }
143
144 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
145                               TALLOC_CTX *mem_ctx,
146                               const DOM_SID *sid,
147                               uint32 *rids,
148                               size_t num_rids,
149                               char **domain_name,
150                               char ***names,
151                               enum lsa_SidType **types)
152 {
153         return NT_STATUS_UNSUCCESSFUL;
154 }
155
156 /* Lookup user information from a rid or username. */
157 static NTSTATUS query_user(struct winbindd_domain *domain, 
158                            TALLOC_CTX *mem_ctx, 
159                            const DOM_SID *user_sid,
160                            WINBIND_USERINFO *user_info)
161 {
162         return NT_STATUS_NO_SUCH_USER;
163 }
164
165 /* Lookup groups a user is a member of.  I wish Unix had a call like this! */
166 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
167                                   TALLOC_CTX *mem_ctx,
168                                   const DOM_SID *user_sid,
169                                   uint32 *num_groups, DOM_SID **user_gids)
170 {
171         NTSTATUS result;
172         DOM_SID *groups = NULL;
173         gid_t *gids = NULL;
174         size_t ngroups = 0;
175         struct samu *user;
176
177         if ( (user = samu_new(mem_ctx)) == NULL ) {
178                 return NT_STATUS_NO_MEMORY;
179         }
180
181         if ( !pdb_getsampwsid( user, user_sid ) ) {
182                 return NT_STATUS_NO_SUCH_USER;
183         }
184
185         result = pdb_enum_group_memberships( mem_ctx, user, &groups, &gids, &ngroups );
186
187         TALLOC_FREE( user );
188
189         *num_groups = (uint32)ngroups;
190         *user_gids = groups;
191
192         return result;
193 }
194
195 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
196                                    TALLOC_CTX *mem_ctx,
197                                    uint32 num_sids, const DOM_SID *sids,
198                                    uint32 *p_num_aliases, uint32 **rids)
199 {
200         NTSTATUS result;
201         size_t num_aliases = 0;
202
203         result = pdb_enum_alias_memberships(mem_ctx, &domain->sid,
204                                             sids, num_sids, rids, &num_aliases);
205
206         *p_num_aliases = num_aliases;
207         return result;
208 }
209
210 /* Lookup group membership given a rid.   */
211 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
212                                 TALLOC_CTX *mem_ctx,
213                                 const DOM_SID *group_sid, uint32 *num_names, 
214                                 DOM_SID **sid_mem, char ***names, 
215                                 uint32 **name_types)
216 {
217         size_t i, num_members, num_mapped;
218         uint32 *rids;
219         NTSTATUS result;
220         const DOM_SID **sids;
221         struct lsa_dom_info *lsa_domains;
222         struct lsa_name_info *lsa_names;
223         TALLOC_CTX *tmp_ctx;
224
225         if (!sid_check_is_in_our_domain(group_sid)) {
226                 /* There's no groups, only aliases in BUILTIN */
227                 return NT_STATUS_NO_SUCH_GROUP;
228         }
229
230         if (!(tmp_ctx = talloc_init("lookup_groupmem"))) {
231                 return NT_STATUS_NO_MEMORY;
232         }
233
234         result = pdb_enum_group_members(tmp_ctx, group_sid, &rids,
235                                         &num_members);
236         if (!NT_STATUS_IS_OK(result)) {
237                 TALLOC_FREE(tmp_ctx);
238                 return result;
239         }
240
241         if (num_members == 0) {
242                 *num_names = 0;
243                 *sid_mem = NULL;
244                 *names = NULL;
245                 *name_types = NULL;
246                 TALLOC_FREE(tmp_ctx);
247                 return NT_STATUS_OK;
248         }
249
250         *sid_mem = TALLOC_ARRAY(mem_ctx, DOM_SID, num_members);
251         *names = TALLOC_ARRAY(mem_ctx, char *, num_members);
252         *name_types = TALLOC_ARRAY(mem_ctx, uint32, num_members);
253         sids = TALLOC_ARRAY(tmp_ctx, const DOM_SID *, num_members);
254
255         if (((*sid_mem) == NULL) || ((*names) == NULL) ||
256             ((*name_types) == NULL) || (sids == NULL)) {
257                 TALLOC_FREE(tmp_ctx);
258                 return NT_STATUS_NO_MEMORY;
259         }
260
261         /*
262          * Prepare an array of sid pointers for the lookup_sids calling
263          * convention.
264          */
265
266         for (i=0; i<num_members; i++) {
267                 DOM_SID *sid = &((*sid_mem)[i]);
268                 if (!sid_compose(sid, &domain->sid, rids[i])) {
269                         TALLOC_FREE(tmp_ctx);
270                         return NT_STATUS_INTERNAL_ERROR;
271                 }
272                 sids[i] = sid;
273         }
274
275         result = lookup_sids(tmp_ctx, num_members, sids, 1,
276                              &lsa_domains, &lsa_names);
277         if (!NT_STATUS_IS_OK(result)) {
278                 TALLOC_FREE(tmp_ctx);
279                 return result;
280         }
281
282         num_mapped = 0;
283         for (i=0; i<num_members; i++) {
284                 if (lsa_names[i].type != SID_NAME_USER) {
285                         DEBUG(2, ("Got %s as group member -- ignoring\n",
286                                   sid_type_lookup(lsa_names[i].type)));
287                         continue;
288                 }
289                 if (!((*names)[i] = talloc_strdup((*names),
290                                                   lsa_names[i].name))) {
291                         TALLOC_FREE(tmp_ctx);
292                         return NT_STATUS_NO_MEMORY;
293                 }
294
295                 (*name_types)[i] = lsa_names[i].type;
296
297                 num_mapped += 1;
298         }
299
300         *num_names = num_mapped;
301
302         TALLOC_FREE(tmp_ctx);
303         return NT_STATUS_OK;
304 }
305
306 /* find the sequence number for a domain */
307 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
308 {
309         BOOL result;
310         time_t seq_num;
311
312         result = pdb_get_seq_num(&seq_num);
313         if (!result) {
314                 *seq = 1;
315         }
316
317         *seq = (int) seq_num;
318         /* *seq = 1; */
319         return NT_STATUS_OK;
320 }
321
322 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
323                                TALLOC_CTX *mem_ctx,
324                                SAM_UNK_INFO_12 *policy)
325 {
326         /* actually we have that */
327         return NT_STATUS_NOT_IMPLEMENTED;
328 }
329
330 static NTSTATUS password_policy(struct winbindd_domain *domain,
331                                 TALLOC_CTX *mem_ctx,
332                                 SAM_UNK_INFO_1 *policy)
333 {
334         uint32 min_pass_len,pass_hist,password_properties;
335         time_t u_expire, u_min_age;
336         NTTIME nt_expire, nt_min_age;
337         uint32 account_policy_temp;
338
339         if ((policy = TALLOC_ZERO_P(mem_ctx, SAM_UNK_INFO_1)) == NULL) {
340                 return NT_STATUS_NO_MEMORY;
341         }
342
343         if (!pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &account_policy_temp)) {
344                 return NT_STATUS_ACCESS_DENIED;
345         }
346         min_pass_len = account_policy_temp;
347
348         if (!pdb_get_account_policy(AP_PASSWORD_HISTORY, &account_policy_temp)) {
349                 return NT_STATUS_ACCESS_DENIED;
350         }
351         pass_hist = account_policy_temp;
352
353         if (!pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, &account_policy_temp)) {
354                 return NT_STATUS_ACCESS_DENIED;
355         }
356         password_properties = account_policy_temp;
357         
358         if (!pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &account_policy_temp)) {
359                 return NT_STATUS_ACCESS_DENIED;
360         }
361         u_expire = account_policy_temp;
362
363         if (!pdb_get_account_policy(AP_MIN_PASSWORD_AGE, &account_policy_temp)) {
364                 return NT_STATUS_ACCESS_DENIED;
365         }
366         u_min_age = account_policy_temp;
367
368         unix_to_nt_time_abs(&nt_expire, u_expire);
369         unix_to_nt_time_abs(&nt_min_age, u_min_age);
370
371         init_unk_info1(policy, (uint16)min_pass_len, (uint16)pass_hist, 
372                        password_properties, nt_expire, nt_min_age);
373
374         return NT_STATUS_OK;
375 }
376
377 /* get a list of trusted domains */
378 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
379                                 TALLOC_CTX *mem_ctx,
380                                 uint32 *num_domains,
381                                 char ***names,
382                                 char ***alt_names,
383                                 DOM_SID **dom_sids)
384 {
385         NTSTATUS nt_status;
386         struct trustdom_info **domains;
387         int i;
388         TALLOC_CTX *tmp_ctx;
389
390         *num_domains = 0;
391         *names = NULL;
392         *alt_names = NULL;
393         *dom_sids = NULL;
394
395         if (!(tmp_ctx = talloc_init("trusted_domains"))) {
396                 return NT_STATUS_NO_MEMORY;
397         }
398
399         nt_status = pdb_enum_trusteddoms(tmp_ctx, num_domains, &domains);
400         if (!NT_STATUS_IS_OK(nt_status)) {
401                 TALLOC_FREE(tmp_ctx);
402                 return nt_status;
403         }
404
405         if (*num_domains) {
406                 *names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
407                 *alt_names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
408                 *dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
409
410                 if ((*alt_names == NULL) || (*names == NULL) || (*dom_sids == NULL)) {
411                         TALLOC_FREE(tmp_ctx);
412                         return NT_STATUS_NO_MEMORY;
413                 }
414         } else {
415                 *names = NULL;
416                 *alt_names = NULL;
417                 *dom_sids = NULL;
418         }
419
420         for (i=0; i<*num_domains; i++) {
421                 (*alt_names)[i] = NULL;
422                 if (!((*names)[i] = talloc_strdup((*names),
423                                                   domains[i]->name))) {
424                         TALLOC_FREE(tmp_ctx);
425                         return NT_STATUS_NO_MEMORY;
426                 }
427                 sid_copy(&(*dom_sids)[i], &domains[i]->sid);
428         }
429
430         TALLOC_FREE(tmp_ctx);
431         return NT_STATUS_OK;
432 }
433
434 /* the rpc backend methods are exposed via this structure */
435 struct winbindd_methods passdb_methods = {
436         False,
437         query_user_list,
438         enum_dom_groups,
439         enum_local_groups,
440         name_to_sid,
441         sid_to_name,
442         rids_to_names,
443         query_user,
444         lookup_usergroups,
445         lookup_useraliases,
446         lookup_groupmem,
447         sequence_number,
448         lockout_policy,
449         password_policy,
450         trusted_domains,
451 };