1fd1e025b6d2a77de6c4e6f7b8bcb904c92e4c96
[samba.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 Lesser 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 Lesser 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 (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         *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids);
167         *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
168
169         if ((*names == NULL) || (*types == NULL)) {
170                 goto fail;
171         }
172
173         p = (char *)response.extra_data.data;
174
175         for (i=0; i<num_rids; i++) {
176                 char *q;
177
178                 if (*p == '\0') {
179                         DEBUG(10, ("Got invalid reply: %s\n",
180                                    (char *)response.extra_data.data));
181                         goto fail;
182                 }
183                         
184                 (*types)[i] = (enum lsa_SidType)strtoul(p, &q, 10);
185
186                 if (*q != ' ') {
187                         DEBUG(10, ("Got invalid reply: %s\n",
188                                    (char *)response.extra_data.data));
189                         goto fail;
190                 }
191
192                 p = q+1;
193
194                 q = strchr(p, '\n');
195                 if (q == NULL) {
196                         DEBUG(10, ("Got invalid reply: %s\n",
197                                    (char *)response.extra_data.data));
198                         goto fail;
199                 }
200
201                 *q = '\0';
202
203                 (*names)[i] = talloc_strdup(*names, p);
204
205                 p = q+1;
206         }
207
208         if (*p != '\0') {
209                 DEBUG(10, ("Got invalid reply: %s\n",
210                            (char *)response.extra_data.data));
211                 goto fail;
212         }
213
214         SAFE_FREE(response.extra_data.data);
215
216         return True;
217
218  fail:
219         TALLOC_FREE(*names);
220         TALLOC_FREE(*types);
221         return False;
222 }
223
224 /* Call winbindd to convert SID to uid */
225
226 bool winbind_sid_to_uid(uid_t *puid, const DOM_SID *sid)
227 {
228         struct winbindd_request request;
229         struct winbindd_response response;
230         int result;
231         fstring sid_str;
232
233         if (!puid)
234                 return False;
235
236         /* Initialise request */
237
238         ZERO_STRUCT(request);
239         ZERO_STRUCT(response);
240
241         sid_to_string(sid_str, sid);
242         fstrcpy(request.data.sid, sid_str);
243         
244         /* Make request */
245
246         result = winbindd_request_response(WINBINDD_SID_TO_UID, &request, &response);
247
248         /* Copy out result */
249
250         if (result == NSS_STATUS_SUCCESS) {
251                 *puid = response.data.uid;
252         }
253
254         return (result == NSS_STATUS_SUCCESS);
255 }
256
257 /* Call winbindd to convert uid to sid */
258
259 bool winbind_uid_to_sid(DOM_SID *sid, uid_t uid)
260 {
261         struct winbindd_request request;
262         struct winbindd_response response;
263         int result;
264
265         if (!sid)
266                 return False;
267
268         /* Initialise request */
269
270         ZERO_STRUCT(request);
271         ZERO_STRUCT(response);
272
273         request.data.uid = uid;
274
275         /* Make request */
276
277         result = winbindd_request_response(WINBINDD_UID_TO_SID, &request, &response);
278
279         /* Copy out result */
280
281         if (result == NSS_STATUS_SUCCESS) {
282                 if (!string_to_sid(sid, response.data.sid.sid))
283                         return False;
284         } else {
285                 sid_copy(sid, &global_sid_NULL);
286         }
287
288         return (result == NSS_STATUS_SUCCESS);
289 }
290
291 /* Call winbindd to convert SID to gid */
292
293 bool winbind_sid_to_gid(gid_t *pgid, const DOM_SID *sid)
294 {
295         struct winbindd_request request;
296         struct winbindd_response response;
297         int result;
298         fstring sid_str;
299
300         if (!pgid)
301                 return False;
302
303         /* Initialise request */
304
305         ZERO_STRUCT(request);
306         ZERO_STRUCT(response);
307
308         sid_to_string(sid_str, sid);
309         fstrcpy(request.data.sid, sid_str);
310         
311         /* Make request */
312
313         result = winbindd_request_response(WINBINDD_SID_TO_GID, &request, &response);
314
315         /* Copy out result */
316
317         if (result == NSS_STATUS_SUCCESS) {
318                 *pgid = response.data.gid;
319         }
320
321         return (result == NSS_STATUS_SUCCESS);
322 }
323
324 /* Call winbindd to convert gid to sid */
325
326 bool winbind_gid_to_sid(DOM_SID *sid, gid_t gid)
327 {
328         struct winbindd_request request;
329         struct winbindd_response response;
330         int result;
331
332         if (!sid)
333                 return False;
334
335         /* Initialise request */
336
337         ZERO_STRUCT(request);
338         ZERO_STRUCT(response);
339
340         request.data.gid = gid;
341
342         /* Make request */
343
344         result = winbindd_request_response(WINBINDD_GID_TO_SID, &request, &response);
345
346         /* Copy out result */
347
348         if (result == NSS_STATUS_SUCCESS) {
349                 if (!string_to_sid(sid, response.data.sid.sid))
350                         return False;
351         } else {
352                 sid_copy(sid, &global_sid_NULL);
353         }
354
355         return (result == NSS_STATUS_SUCCESS);
356 }
357
358 /* Call winbindd to convert SID to uid */
359
360 bool winbind_sids_to_unixids(struct id_map *ids, int num_ids)
361 {
362         struct winbindd_request request;
363         struct winbindd_response response;
364         int result;
365         DOM_SID *sids;
366         int i;
367
368         /* Initialise request */
369
370         ZERO_STRUCT(request);
371         ZERO_STRUCT(response);
372
373         request.extra_len = num_ids * sizeof(DOM_SID);
374
375         sids = (DOM_SID *)SMB_MALLOC(request.extra_len);
376         for (i = 0; i < num_ids; i++) {
377                 sid_copy(&sids[i], ids[i].sid);
378         }
379
380         request.extra_data.data = (char *)sids;
381         
382         /* Make request */
383
384         result = winbindd_request_response(WINBINDD_SIDS_TO_XIDS, &request, &response);
385
386         /* Copy out result */
387
388         if (result == NSS_STATUS_SUCCESS) {
389                 struct unixid *wid = (struct unixid *)response.extra_data.data;
390                 
391                 for (i = 0; i < num_ids; i++) {
392                         if (wid[i].type == -1) {
393                                 ids[i].status = ID_UNMAPPED;
394                         } else {
395                                 ids[i].status = ID_MAPPED;
396                                 ids[i].xid.type = wid[i].type;
397                                 ids[i].xid.id = wid[i].id;
398                         }
399                 }
400         }
401
402         SAFE_FREE(request.extra_data.data);
403         SAFE_FREE(response.extra_data.data);
404
405         return (result == NSS_STATUS_SUCCESS);
406 }
407
408 bool winbind_allocate_uid(uid_t *uid)
409 {
410         struct winbindd_request request;
411         struct winbindd_response response;
412         int result;
413
414         /* Initialise request */
415
416         ZERO_STRUCT(request);
417         ZERO_STRUCT(response);
418
419         /* Make request */
420
421         result = winbindd_request_response(WINBINDD_ALLOCATE_UID,
422                                            &request, &response);
423
424         if (result != NSS_STATUS_SUCCESS)
425                 return False;
426
427         /* Copy out result */
428         *uid = response.data.uid;
429
430         return True;
431 }
432
433 bool winbind_allocate_gid(gid_t *gid)
434 {
435         struct winbindd_request request;
436         struct winbindd_response response;
437         int result;
438
439         /* Initialise request */
440
441         ZERO_STRUCT(request);
442         ZERO_STRUCT(response);
443
444         /* Make request */
445
446         result = winbindd_request_response(WINBINDD_ALLOCATE_GID,
447                                            &request, &response);
448
449         if (result != NSS_STATUS_SUCCESS)
450                 return False;
451
452         /* Copy out result */
453         *gid = response.data.gid;
454
455         return True;
456 }
457
458 bool winbind_set_mapping(const struct id_map *map)
459 {
460         struct winbindd_request request;
461         struct winbindd_response response;
462         int result;
463
464         /* Initialise request */
465
466         ZERO_STRUCT(request);
467         ZERO_STRUCT(response);
468
469         /* Make request */
470
471         request.data.dual_idmapset.id = map->xid.id;
472         request.data.dual_idmapset.type = map->xid.type;
473         sid_to_string(request.data.dual_idmapset.sid, map->sid);
474
475         result = winbindd_request_response(WINBINDD_SET_MAPPING, &request, &response);
476
477         return (result == NSS_STATUS_SUCCESS);
478 }
479
480 bool winbind_set_uid_hwm(unsigned long id)
481 {
482         struct winbindd_request request;
483         struct winbindd_response response;
484         int result;
485
486         /* Initialise request */
487
488         ZERO_STRUCT(request);
489         ZERO_STRUCT(response);
490
491         /* Make request */
492
493         request.data.dual_idmapset.id = id;
494         request.data.dual_idmapset.type = ID_TYPE_UID;
495
496         result = winbindd_request_response(WINBINDD_SET_HWM, &request, &response);
497
498         return (result == NSS_STATUS_SUCCESS);
499 }
500
501 bool winbind_set_gid_hwm(unsigned long id)
502 {
503         struct winbindd_request request;
504         struct winbindd_response response;
505         int result;
506
507         /* Initialise request */
508
509         ZERO_STRUCT(request);
510         ZERO_STRUCT(response);
511
512         /* Make request */
513
514         request.data.dual_idmapset.id = id;
515         request.data.dual_idmapset.type = ID_TYPE_GID;
516
517         result = winbindd_request_response(WINBINDD_SET_HWM, &request, &response);
518
519         return (result == NSS_STATUS_SUCCESS);
520 }
521
522 /**********************************************************************
523  simple wrapper function to see if winbindd is alive
524 **********************************************************************/
525
526 bool winbind_ping( void )
527 {
528         NSS_STATUS result;
529
530         result = winbindd_request_response(WINBINDD_PING, NULL, NULL);
531
532         return result == NSS_STATUS_SUCCESS;
533 }
534
535 /**********************************************************************
536  Is a domain trusted?
537
538  result == NSS_STATUS_UNAVAIL: winbind not around
539  result == NSS_STATUS_NOTFOUND: winbind around, but domain missing
540
541  Due to a bad API NSS_STATUS_NOTFOUND is returned both when winbind_off and
542  when winbind return WINBINDD_ERROR. So the semantics of this routine depends
543  on winbind_on. Grepping for winbind_off I just found 3 places where winbind
544  is turned off, and this does not conflict (as far as I have seen) with the
545  callers of is_trusted_domains.
546
547  I *hate* global variables....
548
549  Volker
550
551 **********************************************************************/
552
553 NSS_STATUS wb_is_trusted_domain(const char *domain)
554 {
555         struct winbindd_request request;
556         struct winbindd_response response;
557
558         /* Call winbindd */
559
560         ZERO_STRUCT(request);
561         ZERO_STRUCT(response);
562
563         fstrcpy(request.domain_name, domain);
564
565         return winbindd_request_response(WINBINDD_DOMAIN_INFO, &request, &response);
566 }