r7243: Don't look at gencache.tdb for the trusted domains if winbind is around.
[kai/samba-autobuild/.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/winbind_nss.h"
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_WINBIND
30
31 NSS_STATUS winbindd_request(int req_type,
32                                  struct winbindd_request *request,
33                                  struct winbindd_response *response);
34
35 /* Call winbindd to convert a name to a sid */
36
37 BOOL winbind_lookup_name(const char *dom_name, const char *name, DOM_SID *sid, 
38                          enum SID_NAME_USE *name_type)
39 {
40         struct winbindd_request request;
41         struct winbindd_response response;
42         NSS_STATUS result;
43         
44         if (!sid || !name_type)
45                 return False;
46
47         /* Send off request */
48
49         ZERO_STRUCT(request);
50         ZERO_STRUCT(response);
51
52         fstrcpy(request.data.name.dom_name, dom_name);
53         fstrcpy(request.data.name.name, name);
54
55         if ((result = winbindd_request(WINBINDD_LOOKUPNAME, &request, 
56                                        &response)) == NSS_STATUS_SUCCESS) {
57                 if (!string_to_sid(sid, response.data.sid.sid))
58                         return False;
59                 *name_type = (enum SID_NAME_USE)response.data.sid.type;
60         }
61
62         return result == NSS_STATUS_SUCCESS;
63 }
64
65 /* Call winbindd to convert sid to name */
66
67 BOOL winbind_lookup_sid(const DOM_SID *sid, 
68                         fstring dom_name, fstring name, 
69                         enum SID_NAME_USE *name_type)
70 {
71         struct winbindd_request request;
72         struct winbindd_response response;
73         NSS_STATUS result;
74         fstring sid_str;
75         
76         /* Initialise request */
77
78         ZERO_STRUCT(request);
79         ZERO_STRUCT(response);
80
81         sid_to_string(sid_str, sid);
82         fstrcpy(request.data.sid, sid_str);
83         
84         /* Make request */
85
86         result = winbindd_request(WINBINDD_LOOKUPSID, &request, &response);
87
88         /* Copy out result */
89
90         if (result == NSS_STATUS_SUCCESS) {
91                 fstrcpy(dom_name, response.data.name.dom_name);
92                 fstrcpy(name, response.data.name.name);
93                 *name_type = (enum SID_NAME_USE)response.data.name.type;
94
95                 DEBUG(10, ("winbind_lookup_sid: SUCCESS: SID %s -> %s %s\n", 
96                            sid_str, dom_name, name));
97         }
98
99         return (result == NSS_STATUS_SUCCESS);
100 }
101
102 /* Call winbindd to convert SID to uid */
103
104 BOOL winbind_sid_to_uid(uid_t *puid, const DOM_SID *sid)
105 {
106         struct winbindd_request request;
107         struct winbindd_response response;
108         int result;
109         fstring sid_str;
110
111         if (!puid)
112                 return False;
113
114         /* Initialise request */
115
116         ZERO_STRUCT(request);
117         ZERO_STRUCT(response);
118
119         sid_to_string(sid_str, sid);
120         fstrcpy(request.data.sid, sid_str);
121         
122         /* Make request */
123
124         result = winbindd_request(WINBINDD_SID_TO_UID, &request, &response);
125
126         /* Copy out result */
127
128         if (result == NSS_STATUS_SUCCESS) {
129                 *puid = response.data.uid;
130         }
131
132         return (result == NSS_STATUS_SUCCESS);
133 }
134
135 /* Call winbindd to convert uid to sid */
136
137 BOOL winbind_uid_to_sid(DOM_SID *sid, uid_t uid)
138 {
139         struct winbindd_request request;
140         struct winbindd_response response;
141         int result;
142
143         if (!sid)
144                 return False;
145
146         /* Initialise request */
147
148         ZERO_STRUCT(request);
149         ZERO_STRUCT(response);
150
151         request.data.uid = uid;
152
153         /* Make request */
154
155         result = winbindd_request(WINBINDD_UID_TO_SID, &request, &response);
156
157         /* Copy out result */
158
159         if (result == NSS_STATUS_SUCCESS) {
160                 if (!string_to_sid(sid, response.data.sid.sid))
161                         return False;
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                 if (!string_to_sid(sid, response.data.sid.sid))
228                         return False;
229         } else {
230                 sid_copy(sid, &global_sid_NULL);
231         }
232
233         return (result == NSS_STATUS_SUCCESS);
234 }
235
236 BOOL winbind_allocate_rid(uint32 *rid)
237 {
238         struct winbindd_request request;
239         struct winbindd_response response;
240         int result;
241
242         /* Initialise request */
243
244         ZERO_STRUCT(request);
245         ZERO_STRUCT(response);
246
247         /* Make request */
248
249         result = winbindd_request(WINBINDD_ALLOCATE_RID, &request, &response);
250
251         if (result != NSS_STATUS_SUCCESS)
252                 return False;
253
254         /* Copy out result */
255         *rid = response.data.rid;
256
257         return True;
258 }
259
260 /* Fetch the list of groups a user is a member of from winbindd.  This is
261    used by winbind_getgroups. */
262
263 static int wb_getgroups(const char *user, gid_t **groups)
264 {
265         struct winbindd_request request;
266         struct winbindd_response response;
267         int result;
268
269         /* Call winbindd */
270
271         ZERO_STRUCT(request);
272         fstrcpy(request.data.username, user);
273
274         ZERO_STRUCT(response);
275
276         result = winbindd_request(WINBINDD_GETGROUPS, &request, &response);
277
278         if (result == NSS_STATUS_SUCCESS) {
279                 
280                 /* Return group list.  Don't forget to free the group list
281                    when finished. */
282
283                 *groups = (gid_t *)response.extra_data;
284                 return response.data.num_entries;
285         }
286
287         return -1;
288 }
289
290 /* Call winbindd to initialise group membership.  This is necessary for
291    some systems (i.e RH5.2) that do not have an initgroups function as part
292    of the nss extension.  In RH5.2 this is implemented using getgrent()
293    which can be amazingly inefficient as well as having problems with
294    username case. */
295
296 int winbind_initgroups(char *user, gid_t gid)
297 {
298         gid_t *tgr, *groups = NULL;
299         int result;
300
301         /* Call normal initgroups if we are a local user */
302
303         if (!strchr(user, *lp_winbind_separator())) {
304                 return initgroups(user, gid);
305         }
306
307         result = wb_getgroups(user, &groups);
308
309         DEBUG(10,("winbind_getgroups: %s: result = %s\n", user, 
310                   result == -1 ? "FAIL" : "SUCCESS"));
311
312         if (result != -1) {
313                 int ngroups = result, i;
314                 BOOL is_member = False;
315
316                 /* Check to see if the passed gid is already in the list */
317
318                 for (i = 0; i < ngroups; i++) {
319                         if (groups[i] == gid) {
320                                 is_member = True;
321                         }
322                 }
323
324                 /* Add group to list if necessary */
325
326                 if (!is_member) {
327                         tgr = SMB_REALLOC_ARRAY(groups, gid_t, ngroups + 1);
328                         
329                         if (!tgr) {
330                                 errno = ENOMEM;
331                                 result = -1;
332                                 goto done;
333                         }
334                         else groups = tgr;
335
336                         groups[ngroups] = gid;
337                         ngroups++;
338                 }
339
340                 /* Set the groups */
341
342                 if (sys_setgroups(ngroups, groups) == -1) {
343                         errno = EPERM;
344                         result = -1;
345                         goto done;
346                 }
347
348         } else {
349                 
350                 /* The call failed.  Set errno to something so we don't get
351                    a bogus value from the last failed system call. */
352
353                 errno = EIO;
354         }
355
356         /* Free response data if necessary */
357
358  done:
359         SAFE_FREE(groups);
360
361         return result;
362 }
363
364 /* Return a list of groups the user is a member of.  This function is
365    useful for large systems where inverting the group database would be too
366    time consuming.  If size is zero, list is not modified and the total
367    number of groups for the user is returned. */
368
369 int winbind_getgroups(const char *user, gid_t **list)
370 {
371         /*
372          * Don't do the lookup if the name has no separator _and_ we are not in
373          * 'winbind use default domain' mode.
374          */
375
376         if (!(strchr(user, *lp_winbind_separator()) || lp_winbind_use_default_domain()))
377                 return -1;
378
379         /* Fetch list of groups */
380
381         return wb_getgroups(user, list);
382 }
383
384 /**********************************************************************
385  simple wrapper function to see if winbindd is alive
386 **********************************************************************/
387
388 BOOL winbind_ping( void )
389 {
390         NSS_STATUS result;
391
392         result = winbindd_request(WINBINDD_PING, NULL, NULL);
393
394         return result == NSS_STATUS_SUCCESS;
395 }
396
397 /**********************************************************************
398  Is a domain trusted?
399
400  result == NSS_STATUS_UNAVAIL: winbind not around
401  result == NSS_STATUS_NOTFOUND: winbind around, but domain missing
402
403  Due to a bad API NSS_STATUS_NOTFOUND is returned both when winbind_off and
404  when winbind return WINBINDD_ERROR. So the semantics of this routine depends
405  on winbind_on. Grepping for winbind_off I just found 3 places where winbind
406  is turned off, and this does not conflict (as far as I have seen) with the
407  callers of is_trusted_domains.
408
409  I *hate* global variables....
410
411  Volker
412
413 **********************************************************************/
414
415 NSS_STATUS wb_is_trusted_domain(const char *domain)
416 {
417         struct winbindd_request request;
418         struct winbindd_response response;
419
420         /* Call winbindd */
421
422         ZERO_STRUCT(request);
423         ZERO_STRUCT(response);
424
425         fstrcpy(request.domain_name, domain);
426
427         return winbindd_request(WINBINDD_DOMAIN_INFO, &request, &response);
428 }