~vcs-imports/samba/main

« back to all changes in this revision

Viewing changes to source/nsswitch/wb_client.c

  • Committer: jerry
  • Date: 2006-07-14 21:48:39 UTC
  • Revision ID: vcs-imports@canonical.com-20060714214839-586d8c489a8fcead
gutting trunk to move to svn:externals

Show diffs side-by-side

added added

removed removed

Lines of Context:
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_response(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_response(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(TALLOC_CTX *mem_ctx, const DOM_SID *sid, 
68
 
                        const char **domain, const char **name,
69
 
                        enum SID_NAME_USE *name_type)
70
 
{
71
 
        struct winbindd_request request;
72
 
        struct winbindd_response response;
73
 
        NSS_STATUS result;
74
 
        
75
 
        /* Initialise request */
76
 
 
77
 
        ZERO_STRUCT(request);
78
 
        ZERO_STRUCT(response);
79
 
 
80
 
        fstrcpy(request.data.sid, sid_string_static(sid));
81
 
        
82
 
        /* Make request */
83
 
 
84
 
        result = winbindd_request_response(WINBINDD_LOOKUPSID, &request,
85
 
                                           &response);
86
 
 
87
 
        if (result != NSS_STATUS_SUCCESS) {
88
 
                return False;
89
 
        }
90
 
 
91
 
        /* Copy out result */
92
 
 
93
 
        if (domain != NULL) {
94
 
                *domain = talloc_strdup(mem_ctx, response.data.name.dom_name);
95
 
                if (*domain == NULL) {
96
 
                        DEBUG(0, ("talloc failed\n"));
97
 
                        return False;
98
 
                }
99
 
        }
100
 
        if (name != NULL) {
101
 
                *name = talloc_strdup(mem_ctx, response.data.name.name);
102
 
                if (*name == NULL) {
103
 
                        DEBUG(0, ("talloc failed\n"));
104
 
                        return False;
105
 
                }
106
 
        }
107
 
 
108
 
        *name_type = (enum SID_NAME_USE)response.data.name.type;
109
 
 
110
 
        DEBUG(10, ("winbind_lookup_sid: SUCCESS: SID %s -> %s %s\n", 
111
 
                   sid_string_static(sid), response.data.name.dom_name,
112
 
                   response.data.name.name));
113
 
        return True;
114
 
}
115
 
 
116
 
BOOL winbind_lookup_rids(TALLOC_CTX *mem_ctx,
117
 
                         const DOM_SID *domain_sid,
118
 
                         int num_rids, uint32 *rids,
119
 
                         const char **domain_name,
120
 
                         const char ***names, enum SID_NAME_USE **types)
121
 
{
122
 
        size_t i, buflen;
123
 
        ssize_t len;
124
 
        char *ridlist;
125
 
        char *p;
126
 
        struct winbindd_request request;
127
 
        struct winbindd_response response;
128
 
        NSS_STATUS result;
129
 
 
130
 
        if (num_rids == 0) {
131
 
                return False;
132
 
        }
133
 
 
134
 
        /* Initialise request */
135
 
 
136
 
        ZERO_STRUCT(request);
137
 
        ZERO_STRUCT(response);
138
 
 
139
 
        fstrcpy(request.data.sid, sid_string_static(domain_sid));
140
 
        
141
 
        len = 0;
142
 
        buflen = 0;
143
 
        ridlist = NULL;
144
 
 
145
 
        for (i=0; i<num_rids; i++) {
146
 
                sprintf_append(mem_ctx, &ridlist, &len, &buflen,
147
 
                               "%ld\n", rids[i]);
148
 
        }
149
 
 
150
 
        if ((num_rids != 0) && (ridlist == NULL)) {
151
 
                return False;
152
 
        }
153
 
 
154
 
        request.extra_data.data = ridlist;
155
 
        request.extra_len = strlen(ridlist)+1;
156
 
 
157
 
        result = winbindd_request_response(WINBINDD_LOOKUPRIDS,
158
 
                                           &request, &response);
159
 
 
160
 
        TALLOC_FREE(ridlist);
161
 
 
162
 
        if (result != NSS_STATUS_SUCCESS) {
163
 
                return False;
164
 
        }
165
 
 
166
 
        *domain_name = talloc_strdup(mem_ctx, response.data.domain_name);
167
 
 
168
 
        *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids);
169
 
        *types = TALLOC_ARRAY(mem_ctx, enum SID_NAME_USE, num_rids);
170
 
 
171
 
        if ((*names == NULL) || (*types == NULL)) {
172
 
                goto fail;
173
 
        }
174
 
 
175
 
        p = response.extra_data.data;
176
 
 
177
 
        for (i=0; i<num_rids; i++) {
178
 
                char *q;
179
 
 
180
 
                if (*p == '\0') {
181
 
                        DEBUG(10, ("Got invalid reply: %s\n",
182
 
                                   (char *)response.extra_data.data));
183
 
                        goto fail;
184
 
                }
185
 
                        
186
 
                (*types)[i] = (enum SID_NAME_USE)strtoul(p, &q, 10);
187
 
 
188
 
                if (*q != ' ') {
189
 
                        DEBUG(10, ("Got invalid reply: %s\n",
190
 
                                   (char *)response.extra_data.data));
191
 
                        goto fail;
192
 
                }
193
 
 
194
 
                p = q+1;
195
 
 
196
 
                q = strchr(p, '\n');
197
 
                if (q == NULL) {
198
 
                        DEBUG(10, ("Got invalid reply: %s\n",
199
 
                                   (char *)response.extra_data.data));
200
 
                        goto fail;
201
 
                }
202
 
 
203
 
                *q = '\0';
204
 
 
205
 
                (*names)[i] = talloc_strdup(*names, p);
206
 
 
207
 
                p = q+1;
208
 
        }
209
 
 
210
 
        if (*p != '\0') {
211
 
                DEBUG(10, ("Got invalid reply: %s\n",
212
 
                           (char *)response.extra_data.data));
213
 
                goto fail;
214
 
        }
215
 
 
216
 
        SAFE_FREE(response.extra_data.data);
217
 
 
218
 
        return True;
219
 
 
220
 
 fail:
221
 
        TALLOC_FREE(*names);
222
 
        TALLOC_FREE(*types);
223
 
        return False;
224
 
}
225
 
 
226
 
/* Call winbindd to convert SID to uid */
227
 
 
228
 
BOOL winbind_sid_to_uid(uid_t *puid, const DOM_SID *sid)
229
 
{
230
 
        struct winbindd_request request;
231
 
        struct winbindd_response response;
232
 
        int result;
233
 
        fstring sid_str;
234
 
 
235
 
        if (!puid)
236
 
                return False;
237
 
 
238
 
        /* Initialise request */
239
 
 
240
 
        ZERO_STRUCT(request);
241
 
        ZERO_STRUCT(response);
242
 
 
243
 
        sid_to_string(sid_str, sid);
244
 
        fstrcpy(request.data.sid, sid_str);
245
 
        
246
 
        /* Make request */
247
 
 
248
 
        result = winbindd_request_response(WINBINDD_SID_TO_UID, &request, &response);
249
 
 
250
 
        /* Copy out result */
251
 
 
252
 
        if (result == NSS_STATUS_SUCCESS) {
253
 
                *puid = response.data.uid;
254
 
        }
255
 
 
256
 
        return (result == NSS_STATUS_SUCCESS);
257
 
}
258
 
 
259
 
/* Call winbindd to convert uid to sid */
260
 
 
261
 
BOOL winbind_uid_to_sid(DOM_SID *sid, uid_t uid)
262
 
{
263
 
        struct winbindd_request request;
264
 
        struct winbindd_response response;
265
 
        int result;
266
 
 
267
 
        if (!sid)
268
 
                return False;
269
 
 
270
 
        /* Initialise request */
271
 
 
272
 
        ZERO_STRUCT(request);
273
 
        ZERO_STRUCT(response);
274
 
 
275
 
        request.data.uid = uid;
276
 
 
277
 
        /* Make request */
278
 
 
279
 
        result = winbindd_request_response(WINBINDD_UID_TO_SID, &request, &response);
280
 
 
281
 
        /* Copy out result */
282
 
 
283
 
        if (result == NSS_STATUS_SUCCESS) {
284
 
                if (!string_to_sid(sid, response.data.sid.sid))
285
 
                        return False;
286
 
        } else {
287
 
                sid_copy(sid, &global_sid_NULL);
288
 
        }
289
 
 
290
 
        return (result == NSS_STATUS_SUCCESS);
291
 
}
292
 
 
293
 
/* Call winbindd to convert SID to gid */
294
 
 
295
 
BOOL winbind_sid_to_gid(gid_t *pgid, const DOM_SID *sid)
296
 
{
297
 
        struct winbindd_request request;
298
 
        struct winbindd_response response;
299
 
        int result;
300
 
        fstring sid_str;
301
 
 
302
 
        if (!pgid)
303
 
                return False;
304
 
 
305
 
        /* Initialise request */
306
 
 
307
 
        ZERO_STRUCT(request);
308
 
        ZERO_STRUCT(response);
309
 
 
310
 
        sid_to_string(sid_str, sid);
311
 
        fstrcpy(request.data.sid, sid_str);
312
 
        
313
 
        /* Make request */
314
 
 
315
 
        result = winbindd_request_response(WINBINDD_SID_TO_GID, &request, &response);
316
 
 
317
 
        /* Copy out result */
318
 
 
319
 
        if (result == NSS_STATUS_SUCCESS) {
320
 
                *pgid = response.data.gid;
321
 
        }
322
 
 
323
 
        return (result == NSS_STATUS_SUCCESS);
324
 
}
325
 
 
326
 
/* Call winbindd to convert gid to sid */
327
 
 
328
 
BOOL winbind_gid_to_sid(DOM_SID *sid, gid_t gid)
329
 
{
330
 
        struct winbindd_request request;
331
 
        struct winbindd_response response;
332
 
        int result;
333
 
 
334
 
        if (!sid)
335
 
                return False;
336
 
 
337
 
        /* Initialise request */
338
 
 
339
 
        ZERO_STRUCT(request);
340
 
        ZERO_STRUCT(response);
341
 
 
342
 
        request.data.gid = gid;
343
 
 
344
 
        /* Make request */
345
 
 
346
 
        result = winbindd_request_response(WINBINDD_GID_TO_SID, &request, &response);
347
 
 
348
 
        /* Copy out result */
349
 
 
350
 
        if (result == NSS_STATUS_SUCCESS) {
351
 
                if (!string_to_sid(sid, response.data.sid.sid))
352
 
                        return False;
353
 
        } else {
354
 
                sid_copy(sid, &global_sid_NULL);
355
 
        }
356
 
 
357
 
        return (result == NSS_STATUS_SUCCESS);
358
 
}
359
 
 
360
 
BOOL winbind_allocate_uid(uid_t *uid)
361
 
{
362
 
        struct winbindd_request request;
363
 
        struct winbindd_response response;
364
 
        int result;
365
 
 
366
 
        /* Initialise request */
367
 
 
368
 
        ZERO_STRUCT(request);
369
 
        ZERO_STRUCT(response);
370
 
 
371
 
        /* Make request */
372
 
 
373
 
        result = winbindd_request_response(WINBINDD_ALLOCATE_UID,
374
 
                                           &request, &response);
375
 
 
376
 
        if (result != NSS_STATUS_SUCCESS)
377
 
                return False;
378
 
 
379
 
        /* Copy out result */
380
 
        *uid = response.data.uid;
381
 
 
382
 
        return True;
383
 
}
384
 
 
385
 
BOOL winbind_allocate_gid(gid_t *gid)
386
 
{
387
 
        struct winbindd_request request;
388
 
        struct winbindd_response response;
389
 
        int result;
390
 
 
391
 
        /* Initialise request */
392
 
 
393
 
        ZERO_STRUCT(request);
394
 
        ZERO_STRUCT(response);
395
 
 
396
 
        /* Make request */
397
 
 
398
 
        result = winbindd_request_response(WINBINDD_ALLOCATE_GID,
399
 
                                           &request, &response);
400
 
 
401
 
        if (result != NSS_STATUS_SUCCESS)
402
 
                return False;
403
 
 
404
 
        /* Copy out result */
405
 
        *gid = response.data.gid;
406
 
 
407
 
        return True;
408
 
}
409
 
 
410
 
/* Fetch the list of groups a user is a member of from winbindd.  This is
411
 
   used by winbind_getgroups. */
412
 
 
413
 
static int wb_getgroups(const char *user, gid_t **groups)
414
 
{
415
 
        struct winbindd_request request;
416
 
        struct winbindd_response response;
417
 
        int result;
418
 
 
419
 
        /* Call winbindd */
420
 
 
421
 
        ZERO_STRUCT(request);
422
 
        fstrcpy(request.data.username, user);
423
 
 
424
 
        ZERO_STRUCT(response);
425
 
 
426
 
        result = winbindd_request_response(WINBINDD_GETGROUPS, &request, &response);
427
 
 
428
 
        if (result == NSS_STATUS_SUCCESS) {
429
 
                
430
 
                /* Return group list.  Don't forget to free the group list
431
 
                   when finished. */
432
 
 
433
 
                *groups = (gid_t *)response.extra_data.data;
434
 
                return response.data.num_entries;
435
 
        }
436
 
 
437
 
        return -1;
438
 
}
439
 
 
440
 
/* Call winbindd to initialise group membership.  This is necessary for
441
 
   some systems (i.e RH5.2) that do not have an initgroups function as part
442
 
   of the nss extension.  In RH5.2 this is implemented using getgrent()
443
 
   which can be amazingly inefficient as well as having problems with
444
 
   username case. */
445
 
 
446
 
int winbind_initgroups(char *user, gid_t gid)
447
 
{
448
 
        gid_t *groups = NULL;
449
 
        int result;
450
 
 
451
 
        /* Call normal initgroups if we are a local user */
452
 
 
453
 
        if (!strchr(user, *lp_winbind_separator())) {
454
 
                return initgroups(user, gid);
455
 
        }
456
 
 
457
 
        result = wb_getgroups(user, &groups);
458
 
 
459
 
        DEBUG(10,("winbind_getgroups: %s: result = %s\n", user, 
460
 
                  result == -1 ? "FAIL" : "SUCCESS"));
461
 
 
462
 
        if (result != -1) {
463
 
                int ngroups = result, i;
464
 
                BOOL is_member = False;
465
 
 
466
 
                /* Check to see if the passed gid is already in the list */
467
 
 
468
 
                for (i = 0; i < ngroups; i++) {
469
 
                        if (groups[i] == gid) {
470
 
                                is_member = True;
471
 
                        }
472
 
                }
473
 
 
474
 
                /* Add group to list if necessary */
475
 
 
476
 
                if (!is_member) {
477
 
                        groups = SMB_REALLOC_ARRAY(groups, gid_t, ngroups + 1);
478
 
                        if (!groups) {
479
 
                                errno = ENOMEM;
480
 
                                result = -1;
481
 
                                goto done;
482
 
                        }
483
 
 
484
 
                        groups[ngroups] = gid;
485
 
                        ngroups++;
486
 
                }
487
 
 
488
 
                /* Set the groups */
489
 
 
490
 
                if (sys_setgroups(ngroups, groups) == -1) {
491
 
                        errno = EPERM;
492
 
                        result = -1;
493
 
                        goto done;
494
 
                }
495
 
 
496
 
        } else {
497
 
                
498
 
                /* The call failed.  Set errno to something so we don't get
499
 
                   a bogus value from the last failed system call. */
500
 
 
501
 
                errno = EIO;
502
 
        }
503
 
 
504
 
        /* Free response data if necessary */
505
 
 
506
 
 done:
507
 
        SAFE_FREE(groups);
508
 
 
509
 
        return result;
510
 
}
511
 
 
512
 
/* Return a list of groups the user is a member of.  This function is
513
 
   useful for large systems where inverting the group database would be too
514
 
   time consuming.  If size is zero, list is not modified and the total
515
 
   number of groups for the user is returned. */
516
 
 
517
 
int winbind_getgroups(const char *user, gid_t **list)
518
 
{
519
 
        /*
520
 
         * Don't do the lookup if the name has no separator _and_ we are not in
521
 
         * 'winbind use default domain' mode.
522
 
         */
523
 
 
524
 
        if (!(strchr(user, *lp_winbind_separator()) || lp_winbind_use_default_domain()))
525
 
                return -1;
526
 
 
527
 
        /* Fetch list of groups */
528
 
 
529
 
        return wb_getgroups(user, list);
530
 
}
531
 
 
532
 
/**********************************************************************
533
 
 simple wrapper function to see if winbindd is alive
534
 
**********************************************************************/
535
 
 
536
 
BOOL winbind_ping( void )
537
 
{
538
 
        NSS_STATUS result;
539
 
 
540
 
        result = winbindd_request_response(WINBINDD_PING, NULL, NULL);
541
 
 
542
 
        return result == NSS_STATUS_SUCCESS;
543
 
}
544
 
 
545
 
/**********************************************************************
546
 
 Is a domain trusted?
547
 
 
548
 
 result == NSS_STATUS_UNAVAIL: winbind not around
549
 
 result == NSS_STATUS_NOTFOUND: winbind around, but domain missing
550
 
 
551
 
 Due to a bad API NSS_STATUS_NOTFOUND is returned both when winbind_off and
552
 
 when winbind return WINBINDD_ERROR. So the semantics of this routine depends
553
 
 on winbind_on. Grepping for winbind_off I just found 3 places where winbind
554
 
 is turned off, and this does not conflict (as far as I have seen) with the
555
 
 callers of is_trusted_domains.
556
 
 
557
 
 I *hate* global variables....
558
 
 
559
 
 Volker
560
 
 
561
 
**********************************************************************/
562
 
 
563
 
NSS_STATUS wb_is_trusted_domain(const char *domain)
564
 
{
565
 
        struct winbindd_request request;
566
 
        struct winbindd_response response;
567
 
 
568
 
        /* Call winbindd */
569
 
 
570
 
        ZERO_STRUCT(request);
571
 
        ZERO_STRUCT(response);
572
 
 
573
 
        fstrcpy(request.domain_name, domain);
574
 
 
575
 
        return winbindd_request_response(WINBINDD_DOMAIN_INFO, &request, &response);
576
 
}