46caa1087c8828da29fc8b9cb66fc4b7ff3ff15d
[sfrench/samba-autobuild/.git] / source3 / 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 3 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 License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "nsswitch/winbind_nss.h"
25
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_WINBIND
28
29 NSS_STATUS winbindd_request_response(int req_type,
30                                  struct winbindd_request *request,
31                                  struct winbindd_response *response);
32
33 /* Call winbindd to convert a name to a sid */
34
35 BOOL winbind_lookup_name(const char *dom_name, const char *name, DOM_SID *sid, 
36                          enum lsa_SidType *name_type)
37 {
38         struct winbindd_request request;
39         struct winbindd_response response;
40         NSS_STATUS result;
41         
42         if (!sid || !name_type)
43                 return False;
44
45         /* Send off request */
46
47         ZERO_STRUCT(request);
48         ZERO_STRUCT(response);
49
50         fstrcpy(request.data.name.dom_name, dom_name);
51         fstrcpy(request.data.name.name, name);
52
53         if ((result = winbindd_request_response(WINBINDD_LOOKUPNAME, &request, 
54                                        &response)) == NSS_STATUS_SUCCESS) {
55                 if (!string_to_sid(sid, response.data.sid.sid))
56                         return False;
57                 *name_type = (enum lsa_SidType)response.data.sid.type;
58         }
59
60         return result == NSS_STATUS_SUCCESS;
61 }
62
63 /* Call winbindd to convert sid to name */
64
65 BOOL winbind_lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid, 
66                         const char **domain, const char **name,
67                         enum lsa_SidType *name_type)
68 {
69         struct winbindd_request request;
70         struct winbindd_response response;
71         NSS_STATUS result;
72         
73         /* Initialise request */
74
75         ZERO_STRUCT(request);
76         ZERO_STRUCT(response);
77
78         fstrcpy(request.data.sid, sid_string_static(sid));
79         
80         /* Make request */
81
82         result = winbindd_request_response(WINBINDD_LOOKUPSID, &request,
83                                            &response);
84
85         if (result != NSS_STATUS_SUCCESS) {
86                 return False;
87         }
88
89         /* Copy out result */
90
91         if (domain != NULL) {
92                 *domain = talloc_strdup(mem_ctx, response.data.name.dom_name);
93                 if (*domain == NULL) {
94                         DEBUG(0, ("talloc failed\n"));
95                         return False;
96                 }
97         }
98         if (name != NULL) {
99                 *name = talloc_strdup(mem_ctx, response.data.name.name);
100                 if (*name == NULL) {
101                         DEBUG(0, ("talloc failed\n"));
102                         return False;
103                 }
104         }
105
106         *name_type = (enum lsa_SidType)response.data.name.type;
107
108         DEBUG(10, ("winbind_lookup_sid: SUCCESS: SID %s -> %s %s\n", 
109                    sid_string_static(sid), response.data.name.dom_name,
110                    response.data.name.name));
111         return True;
112 }
113
114 BOOL winbind_lookup_rids(TALLOC_CTX *mem_ctx,
115                          const DOM_SID *domain_sid,
116                          int num_rids, uint32 *rids,
117                          const char **domain_name,
118                          const char ***names, enum lsa_SidType **types)
119 {
120         size_t i, buflen;
121         ssize_t len;
122         char *ridlist;
123         char *p;
124         struct winbindd_request request;
125         struct winbindd_response response;
126         NSS_STATUS result;
127
128         if (num_rids == 0) {
129                 return False;
130         }
131
132         /* Initialise request */
133
134         ZERO_STRUCT(request);
135         ZERO_STRUCT(response);
136
137         fstrcpy(request.data.sid, sid_string_static(domain_sid));
138         
139         len = 0;
140         buflen = 0;
141         ridlist = NULL;
142
143         for (i=0; i<num_rids; i++) {
144                 sprintf_append(mem_ctx, &ridlist, &len, &buflen,
145                                "%ld\n", rids[i]);
146         }
147
148         if ((num_rids != 0) && (ridlist == NULL)) {
149                 return False;
150         }
151
152         request.extra_data.data = ridlist;
153         request.extra_len = strlen(ridlist)+1;
154
155         result = winbindd_request_response(WINBINDD_LOOKUPRIDS,
156                                            &request, &response);
157
158         TALLOC_FREE(ridlist);
159
160         if (result != NSS_STATUS_SUCCESS) {
161                 return False;
162         }
163
164         *domain_name = talloc_strdup(mem_ctx, response.data.domain_name);
165
166         if (num_rids) {
167                 *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids);
168                 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
169
170                 if ((*names == NULL) || (*types == NULL)) {
171                         goto fail;
172                 }
173         } else {
174                 *names = NULL;
175                 *types = NULL;
176         }
177
178         p = (char *)response.extra_data.data;
179
180         for (i=0; i<num_rids; i++) {
181                 char *q;
182
183                 if (*p == '\0') {
184                         DEBUG(10, ("Got invalid reply: %s\n",
185                                    (char *)response.extra_data.data));
186                         goto fail;
187                 }
188                         
189                 (*types)[i] = (enum lsa_SidType)strtoul(p, &q, 10);
190
191                 if (*q != ' ') {
192                         DEBUG(10, ("Got invalid reply: %s\n",
193                                    (char *)response.extra_data.data));
194                         goto fail;
195                 }
196
197                 p = q+1;
198
199                 q = strchr(p, '\n');
200                 if (q == NULL) {
201                         DEBUG(10, ("Got invalid reply: %s\n",
202                                    (char *)response.extra_data.data));
203                         goto fail;
204                 }
205
206                 *q = '\0';
207
208                 (*names)[i] = talloc_strdup(*names, p);
209
210                 p = q+1;
211         }
212
213         if (*p != '\0') {
214                 DEBUG(10, ("Got invalid reply: %s\n",
215                            (char *)response.extra_data.data));
216                 goto fail;
217         }
218
219         SAFE_FREE(response.extra_data.data);
220
221         return True;
222
223  fail:
224         TALLOC_FREE(*names);
225         TALLOC_FREE(*types);
226         return False;
227 }
228
229 /* Call winbindd to convert SID to uid */
230
231 BOOL winbind_sid_to_uid(uid_t *puid, const DOM_SID *sid)
232 {
233         struct winbindd_request request;
234         struct winbindd_response response;
235         int result;
236         fstring sid_str;
237
238         if (!puid)
239                 return False;
240
241         /* Initialise request */
242
243         ZERO_STRUCT(request);
244         ZERO_STRUCT(response);
245
246         sid_to_string(sid_str, sid);
247         fstrcpy(request.data.sid, sid_str);
248         
249         /* Make request */
250
251         result = winbindd_request_response(WINBINDD_SID_TO_UID, &request, &response);
252
253         /* Copy out result */
254
255         if (result == NSS_STATUS_SUCCESS) {
256                 *puid = response.data.uid;
257         }
258
259         return (result == NSS_STATUS_SUCCESS);
260 }
261
262 /* Call winbindd to convert uid to sid */
263
264 BOOL winbind_uid_to_sid(DOM_SID *sid, uid_t uid)
265 {
266         struct winbindd_request request;
267         struct winbindd_response response;
268         int result;
269
270         if (!sid)
271                 return False;
272
273         /* Initialise request */
274
275         ZERO_STRUCT(request);
276         ZERO_STRUCT(response);
277
278         request.data.uid = uid;
279
280         /* Make request */
281
282         result = winbindd_request_response(WINBINDD_UID_TO_SID, &request, &response);
283
284         /* Copy out result */
285
286         if (result == NSS_STATUS_SUCCESS) {
287                 if (!string_to_sid(sid, response.data.sid.sid))
288                         return False;
289         } else {
290                 sid_copy(sid, &global_sid_NULL);
291         }
292
293         return (result == NSS_STATUS_SUCCESS);
294 }
295
296 /* Call winbindd to convert SID to gid */
297
298 BOOL winbind_sid_to_gid(gid_t *pgid, const DOM_SID *sid)
299 {
300         struct winbindd_request request;
301         struct winbindd_response response;
302         int result;
303         fstring sid_str;
304
305         if (!pgid)
306                 return False;
307
308         /* Initialise request */
309
310         ZERO_STRUCT(request);
311         ZERO_STRUCT(response);
312
313         sid_to_string(sid_str, sid);
314         fstrcpy(request.data.sid, sid_str);
315         
316         /* Make request */
317
318         result = winbindd_request_response(WINBINDD_SID_TO_GID, &request, &response);
319
320         /* Copy out result */
321
322         if (result == NSS_STATUS_SUCCESS) {
323                 *pgid = response.data.gid;
324         }
325
326         return (result == NSS_STATUS_SUCCESS);
327 }
328
329 /* Call winbindd to convert gid to sid */
330
331 BOOL winbind_gid_to_sid(DOM_SID *sid, gid_t gid)
332 {
333         struct winbindd_request request;
334         struct winbindd_response response;
335         int result;
336
337         if (!sid)
338                 return False;
339
340         /* Initialise request */
341
342         ZERO_STRUCT(request);
343         ZERO_STRUCT(response);
344
345         request.data.gid = gid;
346
347         /* Make request */
348
349         result = winbindd_request_response(WINBINDD_GID_TO_SID, &request, &response);
350
351         /* Copy out result */
352
353         if (result == NSS_STATUS_SUCCESS) {
354                 if (!string_to_sid(sid, response.data.sid.sid))
355                         return False;
356         } else {
357                 sid_copy(sid, &global_sid_NULL);
358         }
359
360         return (result == NSS_STATUS_SUCCESS);
361 }
362
363 /* Call winbindd to convert SID to uid */
364
365 BOOL winbind_sids_to_unixids(struct id_map *ids, int num_ids)
366 {
367         struct winbindd_request request;
368         struct winbindd_response response;
369         int result;
370         DOM_SID *sids;
371         int i;
372
373         /* Initialise request */
374
375         ZERO_STRUCT(request);
376         ZERO_STRUCT(response);
377
378         request.extra_len = num_ids * sizeof(DOM_SID);
379
380         sids = (DOM_SID *)SMB_MALLOC(request.extra_len);
381         for (i = 0; i < num_ids; i++) {
382                 sid_copy(&sids[i], ids[i].sid);
383         }
384
385         request.extra_data.data = (char *)sids;
386         
387         /* Make request */
388
389         result = winbindd_request_response(WINBINDD_SIDS_TO_XIDS, &request, &response);
390
391         /* Copy out result */
392
393         if (result == NSS_STATUS_SUCCESS) {
394                 struct unixid *wid = (struct unixid *)response.extra_data.data;
395                 
396                 for (i = 0; i < num_ids; i++) {
397                         if (wid[i].type == -1) {
398                                 ids[i].status = ID_UNMAPPED;
399                         } else {
400                                 ids[i].status = ID_MAPPED;
401                                 ids[i].xid.type = wid[i].type;
402                                 ids[i].xid.id = wid[i].id;
403                         }
404                 }
405         }
406
407         SAFE_FREE(request.extra_data.data);
408         SAFE_FREE(response.extra_data.data);
409
410         return (result == NSS_STATUS_SUCCESS);
411 }
412
413 BOOL winbind_idmap_dump_maps(TALLOC_CTX *memctx, const char *file)
414 {
415         struct winbindd_request request;
416         struct winbindd_response response;
417         int result;
418
419         ZERO_STRUCT(request);
420         ZERO_STRUCT(response);
421
422         request.extra_data.data = SMB_STRDUP(file);
423         request.extra_len = strlen(request.extra_data.data) + 1;
424
425         result = winbindd_request_response(WINBINDD_DUMP_MAPS, &request, &response);
426
427         SAFE_FREE(request.extra_data.data);
428         return (result == NSS_STATUS_SUCCESS);
429 }
430
431 BOOL winbind_allocate_uid(uid_t *uid)
432 {
433         struct winbindd_request request;
434         struct winbindd_response response;
435         int result;
436
437         /* Initialise request */
438
439         ZERO_STRUCT(request);
440         ZERO_STRUCT(response);
441
442         /* Make request */
443
444         result = winbindd_request_response(WINBINDD_ALLOCATE_UID,
445                                            &request, &response);
446
447         if (result != NSS_STATUS_SUCCESS)
448                 return False;
449
450         /* Copy out result */
451         *uid = response.data.uid;
452
453         return True;
454 }
455
456 BOOL winbind_allocate_gid(gid_t *gid)
457 {
458         struct winbindd_request request;
459         struct winbindd_response response;
460         int result;
461
462         /* Initialise request */
463
464         ZERO_STRUCT(request);
465         ZERO_STRUCT(response);
466
467         /* Make request */
468
469         result = winbindd_request_response(WINBINDD_ALLOCATE_GID,
470                                            &request, &response);
471
472         if (result != NSS_STATUS_SUCCESS)
473                 return False;
474
475         /* Copy out result */
476         *gid = response.data.gid;
477
478         return True;
479 }
480
481 BOOL winbind_set_mapping(const struct id_map *map)
482 {
483         struct winbindd_request request;
484         struct winbindd_response response;
485         int result;
486
487         /* Initialise request */
488
489         ZERO_STRUCT(request);
490         ZERO_STRUCT(response);
491
492         /* Make request */
493
494         request.data.dual_idmapset.id = map->xid.id;
495         request.data.dual_idmapset.type = map->xid.type;
496         sid_to_string(request.data.dual_idmapset.sid, map->sid);
497
498         result = winbindd_request_response(WINBINDD_SET_MAPPING, &request, &response);
499
500         return (result == NSS_STATUS_SUCCESS);
501 }
502
503 BOOL winbind_set_uid_hwm(unsigned long id)
504 {
505         struct winbindd_request request;
506         struct winbindd_response response;
507         int result;
508
509         /* Initialise request */
510
511         ZERO_STRUCT(request);
512         ZERO_STRUCT(response);
513
514         /* Make request */
515
516         request.data.dual_idmapset.id = id;
517         request.data.dual_idmapset.type = ID_TYPE_UID;
518
519         result = winbindd_request_response(WINBINDD_SET_HWM, &request, &response);
520
521         return (result == NSS_STATUS_SUCCESS);
522 }
523
524 BOOL winbind_set_gid_hwm(unsigned long id)
525 {
526         struct winbindd_request request;
527         struct winbindd_response response;
528         int result;
529
530         /* Initialise request */
531
532         ZERO_STRUCT(request);
533         ZERO_STRUCT(response);
534
535         /* Make request */
536
537         request.data.dual_idmapset.id = id;
538         request.data.dual_idmapset.type = ID_TYPE_GID;
539
540         result = winbindd_request_response(WINBINDD_SET_HWM, &request, &response);
541
542         return (result == NSS_STATUS_SUCCESS);
543 }
544
545 /**********************************************************************
546  simple wrapper function to see if winbindd is alive
547 **********************************************************************/
548
549 BOOL winbind_ping( void )
550 {
551         NSS_STATUS result;
552
553         result = winbindd_request_response(WINBINDD_PING, NULL, NULL);
554
555         return result == NSS_STATUS_SUCCESS;
556 }
557
558 /**********************************************************************
559  Is a domain trusted?
560
561  result == NSS_STATUS_UNAVAIL: winbind not around
562  result == NSS_STATUS_NOTFOUND: winbind around, but domain missing
563
564  Due to a bad API NSS_STATUS_NOTFOUND is returned both when winbind_off and
565  when winbind return WINBINDD_ERROR. So the semantics of this routine depends
566  on winbind_on. Grepping for winbind_off I just found 3 places where winbind
567  is turned off, and this does not conflict (as far as I have seen) with the
568  callers of is_trusted_domains.
569
570  I *hate* global variables....
571
572  Volker
573
574 **********************************************************************/
575
576 NSS_STATUS wb_is_trusted_domain(const char *domain)
577 {
578         struct winbindd_request request;
579         struct winbindd_response response;
580
581         /* Call winbindd */
582
583         ZERO_STRUCT(request);
584         ZERO_STRUCT(response);
585
586         fstrcpy(request.domain_name, domain);
587
588         return winbindd_request_response(WINBINDD_DOMAIN_INFO, &request, &response);
589 }