sync 3.0 branch with head
[tprouty/samba.git] / source / nsswitch / wb_client.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    winbind client code
5
6    Copyright (C) Tim Potter 2000
7    Copyright (C) Andrew Tridgell 2000
8    
9    This library is free software; you can redistribute it and/or
10    modify it under the terms of the GNU Library General Public
11    License as published by the Free Software Foundation; either
12    version 2 of the License, or (at your option) any later version.
13    
14    This library is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    Library General Public License for more details.
18    
19    You should have received a copy of the GNU Library General Public
20    License along with this library; if not, write to the
21    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22    Boston, MA  02111-1307, USA.   
23 */
24
25 #include "includes.h"
26 #include "nsswitch/nss.h"
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_WINBIND
30
31 extern DOM_SID global_sid_NULL;                         /* NULL sid */
32
33 NSS_STATUS winbindd_request(int req_type,
34                                  struct winbindd_request *request,
35                                  struct winbindd_response *response);
36
37 /* Call winbindd to convert a name to a sid */
38
39 BOOL winbind_lookup_name(const char *dom_name, const char *name, DOM_SID *sid, 
40                          enum SID_NAME_USE *name_type)
41 {
42         struct winbindd_request request;
43         struct winbindd_response response;
44         NSS_STATUS result;
45         
46         if (!sid || !name_type)
47                 return False;
48
49         /* Send off request */
50
51         ZERO_STRUCT(request);
52         ZERO_STRUCT(response);
53
54         fstrcpy(request.data.name.dom_name, dom_name);
55         fstrcpy(request.data.name.name, name);
56
57         if ((result = winbindd_request(WINBINDD_LOOKUPNAME, &request, 
58                                        &response)) == NSS_STATUS_SUCCESS) {
59                 string_to_sid(sid, response.data.sid.sid);
60                 *name_type = (enum SID_NAME_USE)response.data.sid.type;
61         }
62
63         return result == NSS_STATUS_SUCCESS;
64 }
65
66 /* Call winbindd to convert sid to name */
67
68 BOOL winbind_lookup_sid(const DOM_SID *sid, 
69                         fstring dom_name, fstring name, 
70                         enum SID_NAME_USE *name_type)
71 {
72         struct winbindd_request request;
73         struct winbindd_response response;
74         NSS_STATUS result;
75         fstring sid_str;
76         
77         /* Initialise request */
78
79         ZERO_STRUCT(request);
80         ZERO_STRUCT(response);
81
82         sid_to_string(sid_str, sid);
83         fstrcpy(request.data.sid, sid_str);
84         
85         /* Make request */
86
87         result = winbindd_request(WINBINDD_LOOKUPSID, &request, &response);
88
89         /* Copy out result */
90
91         if (result == NSS_STATUS_SUCCESS) {
92                 fstrcpy(dom_name, response.data.name.dom_name);
93                 fstrcpy(name, response.data.name.name);
94                 *name_type = (enum SID_NAME_USE)response.data.name.type;
95
96                 DEBUG(10, ("winbind_lookup_sid: SUCCESS: SID %s -> %s %s\n", 
97                            sid_str, dom_name, name));
98         }
99
100         return (result == NSS_STATUS_SUCCESS);
101 }
102
103 /* Call winbindd to convert SID to uid */
104
105 BOOL winbind_sid_to_uid(uid_t *puid, const DOM_SID *sid)
106 {
107         struct winbindd_request request;
108         struct winbindd_response response;
109         int result;
110         fstring sid_str;
111
112         if (!puid)
113                 return False;
114
115         /* Initialise request */
116
117         ZERO_STRUCT(request);
118         ZERO_STRUCT(response);
119
120         sid_to_string(sid_str, sid);
121         fstrcpy(request.data.sid, sid_str);
122         
123         /* Make request */
124
125         result = winbindd_request(WINBINDD_SID_TO_UID, &request, &response);
126
127         /* Copy out result */
128
129         if (result == NSS_STATUS_SUCCESS) {
130                 *puid = response.data.uid;
131         }
132
133         return (result == NSS_STATUS_SUCCESS);
134 }
135
136 /* Call winbindd to convert uid to sid */
137
138 BOOL winbind_uid_to_sid(DOM_SID *sid, uid_t uid)
139 {
140         struct winbindd_request request;
141         struct winbindd_response response;
142         int result;
143
144         if (!sid)
145                 return False;
146
147         /* Initialise request */
148
149         ZERO_STRUCT(request);
150         ZERO_STRUCT(response);
151
152         request.data.uid = uid;
153
154         /* Make request */
155
156         result = winbindd_request(WINBINDD_UID_TO_SID, &request, &response);
157
158         /* Copy out result */
159
160         if (result == NSS_STATUS_SUCCESS) {
161                 string_to_sid(sid, response.data.sid.sid);
162         } else {
163                 sid_copy(sid, &global_sid_NULL);
164         }
165
166         return (result == NSS_STATUS_SUCCESS);
167 }
168
169 /* Call winbindd to convert SID to gid */
170
171 BOOL winbind_sid_to_gid(gid_t *pgid, const DOM_SID *sid)
172 {
173         struct winbindd_request request;
174         struct winbindd_response response;
175         int result;
176         fstring sid_str;
177
178         if (!pgid)
179                 return False;
180
181         /* Initialise request */
182
183         ZERO_STRUCT(request);
184         ZERO_STRUCT(response);
185
186         sid_to_string(sid_str, sid);
187         fstrcpy(request.data.sid, sid_str);
188         
189         /* Make request */
190
191         result = winbindd_request(WINBINDD_SID_TO_GID, &request, &response);
192
193         /* Copy out result */
194
195         if (result == NSS_STATUS_SUCCESS) {
196                 *pgid = response.data.gid;
197         }
198
199         return (result == NSS_STATUS_SUCCESS);
200 }
201
202 /* Call winbindd to convert gid to sid */
203
204 BOOL winbind_gid_to_sid(DOM_SID *sid, gid_t gid)
205 {
206         struct winbindd_request request;
207         struct winbindd_response response;
208         int result;
209
210         if (!sid)
211                 return False;
212
213         /* Initialise request */
214
215         ZERO_STRUCT(request);
216         ZERO_STRUCT(response);
217
218         request.data.gid = gid;
219
220         /* Make request */
221
222         result = winbindd_request(WINBINDD_GID_TO_SID, &request, &response);
223
224         /* Copy out result */
225
226         if (result == NSS_STATUS_SUCCESS) {
227                 string_to_sid(sid, response.data.sid.sid);
228         } else {
229                 sid_copy(sid, &global_sid_NULL);
230         }
231
232         return (result == NSS_STATUS_SUCCESS);
233 }
234
235 /* Fetch the list of groups a user is a member of from winbindd.  This is
236    used by winbind_getgroups. */
237
238 static int wb_getgroups(const char *user, gid_t **groups)
239 {
240         struct winbindd_request request;
241         struct winbindd_response response;
242         int result;
243
244         /* Call winbindd */
245
246         fstrcpy(request.data.username, user);
247
248         ZERO_STRUCT(response);
249
250         result = winbindd_request(WINBINDD_GETGROUPS, &request, &response);
251
252         if (result == NSS_STATUS_SUCCESS) {
253                 
254                 /* Return group list.  Don't forget to free the group list
255                    when finished. */
256
257                 *groups = (gid_t *)response.extra_data;
258                 return response.data.num_entries;
259         }
260
261         return -1;
262 }
263
264 /* Return a list of groups the user is a member of.  This function is
265    useful for large systems where inverting the group database would be too
266    time consuming.  If size is zero, list is not modified and the total
267    number of groups for the user is returned. */
268
269 int winbind_getgroups(const char *user, int size, gid_t *list)
270 {
271         gid_t *groups = NULL;
272         int result, i;
273
274         /*
275          * Don't do the lookup if the name has no separator _and_ we are not in
276          * 'winbind use default domain' mode.
277          */
278
279         if (!(strchr(user, *lp_winbind_separator()) || lp_winbind_use_default_domain()))
280                 return -1;
281
282         /* Fetch list of groups */
283
284         result = wb_getgroups(user, &groups);
285
286         if (size == 0)
287                 goto done;
288
289         if (result > size) {
290                 result = -1;
291                 errno = EINVAL; /* This is what getgroups() does */
292                 goto done;
293         }
294
295         /* Copy list of groups across */
296
297         for (i = 0; i < result; i++) {
298                 list[i] = groups[i];
299         }
300
301  done:
302         SAFE_FREE(groups);
303         return result;
304 }