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