c728f9659c504c183f87c2fa07b512456d57fb88
[amitay/samba.git] / source3 / nsswitch / winbindd_ads.c
1 /* 
2    Unix SMB/Netbios implementation.
3
4    Winbind ADS backend functions
5
6    Copyright (C) Andrew Tridgell 2001
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "winbindd.h"
24
25 #ifdef HAVE_ADS
26
27 /* Query display info for a realm. This is the basic user list fn */
28 static NTSTATUS query_dispinfo(struct winbindd_domain *domain,
29                                TALLOC_CTX *mem_ctx,
30                                uint32 *start_ndx, uint32 *num_entries, 
31                                WINBIND_DISPINFO **info)
32 {
33         ADS_STRUCT *ads;
34         const char *attrs[] = {"sAMAccountName", "name", "objectSid", "primaryGroupID", 
35                                "userAccountControl", NULL};
36         int rc, i, count;
37         void *res;
38         void *msg;
39
40         DEBUG(3,("ads: query_dispinfo\n"));
41
42         if ((*start_ndx) != 0) {
43                 DEBUG(1,("ads backend start_ndx not implemented\n"));
44                 return NT_STATUS_NOT_IMPLEMENTED;
45         }
46
47         ads = ads_init(NULL, NULL, NULL);
48         if (!ads) {
49                 DEBUG(1,("ads_init failed\n"));
50                 return NT_STATUS_UNSUCCESSFUL;
51         }
52
53         rc = ads_connect(ads);
54         if (rc) {
55                 DEBUG(1,("query_dispinfo ads_connect: %s\n", ads_errstr(rc)));
56                 return NT_STATUS_UNSUCCESSFUL;
57         }
58
59         rc = ads_search(ads, &res, "(objectclass=user)", attrs);
60         if (rc) {
61                 DEBUG(1,("query_dispinfo ads_search: %s\n", ads_errstr(rc)));
62                 return NT_STATUS_UNSUCCESSFUL;
63         }
64
65         count = ads_count_replies(ads, res);
66         if (count == 0) {
67                 DEBUG(1,("query_dispinfo: No users found\n"));
68                 return NT_STATUS_UNSUCCESSFUL;
69         }
70
71         (*info) = talloc(mem_ctx, count * sizeof(**info));
72         if (!*info) return NT_STATUS_NO_MEMORY;
73
74         i = 0;
75
76         for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
77                 char *name, *gecos;
78                 DOM_SID sid;
79                 uint32 rid, group;
80                 uint32 account_control;
81
82                 if (!ads_pull_uint32(ads, msg, "userAccountControl", 
83                                      &account_control) ||
84                     !(account_control & UF_NORMAL_ACCOUNT)) continue;
85
86                 name = ads_pull_string(ads, mem_ctx, msg, "sAMAccountName");
87                 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
88                 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
89                         DEBUG(1,("No sid for %s !?\n", name));
90                         continue;
91                 }
92                 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
93                         DEBUG(1,("No primary group for %s !?\n", name));
94                         continue;
95                 }
96
97                 if (!sid_peek_rid(&sid, &rid)) {
98                         DEBUG(1,("No rid for %s !?\n", name));
99                         continue;
100                 }
101
102                 (*info)[i].acct_name = name;
103                 (*info)[i].full_name = gecos;
104                 (*info)[i].user_rid = rid;
105                 (*info)[i].group_rid = group;
106                 i++;
107         }
108
109         (*num_entries) = i;
110
111         ads_destroy(&ads);
112
113         return NT_STATUS_OK;
114 }
115
116 /* list all domain groups */
117 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
118                                 TALLOC_CTX *mem_ctx,
119                                 uint32 *start_ndx, uint32 *num_entries, 
120                                 struct acct_info **info)
121 {
122         ADS_STRUCT *ads;
123         const char *attrs[] = {"sAMAccountName", "name", "objectSid", 
124                                "sAMAccountType", NULL};
125         int rc, i, count;
126         void *res;
127         void *msg;
128
129         DEBUG(3,("ads: enum_dom_groups\n"));
130
131         if ((*start_ndx) != 0) {
132                 DEBUG(1,("ads backend start_ndx not implemented\n"));
133                 return NT_STATUS_NOT_IMPLEMENTED;
134         }
135
136         ads = ads_init(NULL, NULL, NULL);
137         if (!ads) {
138                 DEBUG(1,("ads_init failed\n"));
139                 return NT_STATUS_UNSUCCESSFUL;
140         }
141
142         rc = ads_connect(ads);
143         if (rc) {
144                 DEBUG(1,("query_dispinfo ads_connect: %s\n", ads_errstr(rc)));
145                 return NT_STATUS_UNSUCCESSFUL;
146         }
147
148         rc = ads_search(ads, &res, "(objectclass=group)", attrs);
149         if (rc) {
150                 DEBUG(1,("query_dispinfo ads_search: %s\n", ads_errstr(rc)));
151                 return NT_STATUS_UNSUCCESSFUL;
152         }
153
154         count = ads_count_replies(ads, res);
155         if (count == 0) {
156                 DEBUG(1,("query_dispinfo: No users found\n"));
157                 return NT_STATUS_UNSUCCESSFUL;
158         }
159
160         (*info) = talloc(mem_ctx, count * sizeof(**info));
161         if (!*info) return NT_STATUS_NO_MEMORY;
162
163         i = 0;
164
165         for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
166                 char *name, *gecos;
167                 DOM_SID sid;
168                 uint32 rid;
169                 uint32 account_type;
170
171                 if (!ads_pull_uint32(ads, msg, "sAMAccountType", 
172                                      &account_type) ||
173                     !(account_type & ATYPE_NORMAL_GROUP)) continue;
174
175                 name = ads_pull_string(ads, mem_ctx, msg, "sAMAccountName");
176                 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
177                 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
178                         DEBUG(1,("No sid for %s !?\n", name));
179                         continue;
180                 }
181
182                 if (!sid_peek_rid(&sid, &rid)) {
183                         DEBUG(1,("No rid for %s !?\n", name));
184                         continue;
185                 }
186
187                 fstrcpy((*info)[i].acct_name, name);
188                 fstrcpy((*info)[i].acct_desc, gecos);
189                 (*info)[i].rid = rid;
190                 i++;
191         }
192
193         (*num_entries) = i;
194
195         ads_destroy(&ads);
196
197         return NT_STATUS_OK;
198 }
199
200
201 /* the rpc backend methods are exposed via this structure */
202 struct winbindd_methods ads_methods = {
203         query_dispinfo,
204         enum_dom_groups
205 };
206
207 #endif