r7415: * big change -- volker's new async winbindd from trunk
[Samba/gbeck.git] / source / nsswitch / winbindd_sid.c
blobf8fb5e93c2ec1aabdcfe004694b2663646f3f92b
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind daemon - sid related functions
6 Copyright (C) Tim Potter 2000
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "includes.h"
24 #include "winbindd.h"
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_WINBIND
29 /* Convert a string */
31 static void lookupsid_recv(void *private, BOOL success,
32 const char *dom_name, const char *name,
33 enum SID_NAME_USE type);
35 enum winbindd_result winbindd_lookupsid(struct winbindd_cli_state *state)
37 DOM_SID sid;
39 /* Ensure null termination */
40 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
42 DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid,
43 state->request.data.sid));
45 if (!string_to_sid(&sid, state->request.data.sid)) {
46 DEBUG(5, ("%s not a SID\n", state->request.data.sid));
47 return WINBINDD_ERROR;
50 winbindd_lookupsid_async(state->mem_ctx, &sid, lookupsid_recv, state);
51 return WINBINDD_PENDING;
54 static void lookupsid_recv(void *private, BOOL success,
55 const char *dom_name, const char *name,
56 enum SID_NAME_USE type)
58 struct winbindd_cli_state *state =
59 talloc_get_type_abort(private, struct winbindd_cli_state);
61 if (!success) {
62 DEBUG(5, ("lookupsid returned an error\n"));
63 state->response.result = WINBINDD_ERROR;
64 request_finished(state);
65 return;
68 fstrcpy(state->response.data.name.dom_name, dom_name);
69 fstrcpy(state->response.data.name.name, name);
70 state->response.data.name.type = type;
71 state->response.result = WINBINDD_OK;
72 request_finished(state);
75 /**
76 * Look up the SID for a qualified name.
77 **/
79 static void lookupname_recv(void *private, BOOL success,
80 const DOM_SID *sid, enum SID_NAME_USE type);
82 enum winbindd_result winbindd_lookupname(struct winbindd_cli_state *state)
84 char *name_domain, *name_user;
85 char *p;
87 /* Ensure null termination */
88 state->request.data.sid[sizeof(state->request.data.name.dom_name)-1]='\0';
90 /* Ensure null termination */
91 state->request.data.sid[sizeof(state->request.data.name.name)-1]='\0';
93 /* cope with the name being a fully qualified name */
94 p = strstr(state->request.data.name.name, lp_winbind_separator());
95 if (p) {
96 *p = 0;
97 name_domain = state->request.data.name.name;
98 name_user = p+1;
99 } else {
100 name_domain = state->request.data.name.dom_name;
101 name_user = state->request.data.name.name;
104 DEBUG(3, ("[%5lu]: lookupname %s%s%s\n", (unsigned long)state->pid,
105 name_domain, lp_winbind_separator(), name_user));
107 winbindd_lookupname_async(state->mem_ctx, name_domain, name_user,
108 lookupname_recv, state);
109 return WINBINDD_PENDING;
112 static void lookupname_recv(void *private, BOOL success,
113 const DOM_SID *sid, enum SID_NAME_USE type)
115 struct winbindd_cli_state *state =
116 talloc_get_type_abort(private, struct winbindd_cli_state);
118 if (!success) {
119 DEBUG(5, ("lookupname returned an error\n"));
120 state->response.result = WINBINDD_ERROR;
121 request_finished(state);
122 return;
125 sid_to_string(state->response.data.sid.sid, sid);
126 state->response.data.sid.type = type;
127 state->response.result = WINBINDD_OK;
128 request_finished(state);
129 return;
132 static struct winbindd_child static_idmap_child;
134 void init_idmap_child(void)
136 setup_domain_child(NULL, &static_idmap_child, "idmap");
139 struct winbindd_child *idmap_child(void)
141 return &static_idmap_child;
144 /* Convert a sid to a uid. We assume we only have one rid attached to the
145 sid. */
147 static void sid2uid_recv(void *private, BOOL success, uid_t uid);
149 enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state)
151 DOM_SID sid;
152 NTSTATUS result;
154 /* Ensure null termination */
155 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
157 DEBUG(3, ("[%5lu]: sid to uid %s\n", (unsigned long)state->pid,
158 state->request.data.sid));
160 if (idmap_proxyonly()) {
161 DEBUG(8, ("IDMAP proxy only\n"));
162 return WINBINDD_ERROR;
165 if (!string_to_sid(&sid, state->request.data.sid)) {
166 DEBUG(1, ("Could not get convert sid %s from string\n",
167 state->request.data.sid));
168 return WINBINDD_ERROR;
171 /* Query only the local tdb, everything else might possibly block */
173 result = idmap_sid_to_uid(&sid, &(state->response.data.uid),
174 ID_QUERY_ONLY|ID_CACHE_ONLY);
176 if (NT_STATUS_IS_OK(result)) {
177 return WINBINDD_OK;
180 winbindd_sid2uid_async(state->mem_ctx, &sid, sid2uid_recv, state);
181 return WINBINDD_PENDING;
184 static void sid2uid_recv(void *private, BOOL success, uid_t uid)
186 struct winbindd_cli_state *state =
187 talloc_get_type_abort(private, struct winbindd_cli_state);
189 if (!success) {
190 DEBUG(5, ("Could not convert sid %s\n",
191 state->request.data.sid));
192 state->response.result = WINBINDD_ERROR;
193 request_finished(state);
194 return;
197 state->response.result = WINBINDD_OK;
198 state->response.data.uid = uid;
199 request_finished(state);
202 /* Convert a sid to a gid. We assume we only have one rid attached to the
203 sid.*/
205 static void sid2gid_recv(void *private, BOOL success, gid_t gid);
207 enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state)
209 DOM_SID sid;
210 NTSTATUS result;
212 /* Ensure null termination */
213 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
215 DEBUG(3, ("[%5lu]: sid to gid %s\n", (unsigned long)state->pid,
216 state->request.data.sid));
218 if (idmap_proxyonly()) {
219 DEBUG(8, ("IDMAP proxy only\n"));
220 return WINBINDD_ERROR;
223 if (!string_to_sid(&sid, state->request.data.sid)) {
224 DEBUG(1, ("Could not get convert sid %s from string\n",
225 state->request.data.sid));
226 return WINBINDD_ERROR;
229 /* Query only the local tdb, everything else might possibly block */
231 result = idmap_sid_to_gid(&sid, &(state->response.data.gid),
232 ID_QUERY_ONLY|ID_CACHE_ONLY);
234 if (NT_STATUS_IS_OK(result)) {
235 return WINBINDD_OK;
238 winbindd_sid2gid_async(state->mem_ctx, &sid, sid2gid_recv, state);
239 return WINBINDD_PENDING;
242 static void sid2gid_recv(void *private, BOOL success, gid_t gid)
244 struct winbindd_cli_state *state =
245 talloc_get_type_abort(private, struct winbindd_cli_state);
247 if (!success) {
248 DEBUG(5, ("Could not convert sid %s\n",
249 state->request.data.sid));
250 state->response.result = WINBINDD_ERROR;
251 request_finished(state);
252 return;
255 state->response.result = WINBINDD_OK;
256 state->response.data.gid = gid;
257 request_finished(state);
260 /* Convert a uid to a sid */
262 struct uid2sid_state {
263 struct winbindd_cli_state *cli_state;
264 uid_t uid;
265 fstring name;
266 DOM_SID sid;
267 enum SID_NAME_USE type;
270 static void uid2sid_uid2name_recv(void *private, BOOL success,
271 const char *username);
272 static void uid2sid_lookupname_recv(void *private, BOOL success,
273 const DOM_SID *sid,
274 enum SID_NAME_USE type);
275 static void uid2sid_idmap_set_mapping_recv(void *private, BOOL success);
277 enum winbindd_result winbindd_uid_to_sid(struct winbindd_cli_state *state)
279 DOM_SID sid;
280 NTSTATUS status;
281 struct uid2sid_state *uid2sid_state;
283 DEBUG(3, ("[%5lu]: uid to sid %lu\n", (unsigned long)state->pid,
284 (unsigned long)state->request.data.uid));
286 if (idmap_proxyonly()) {
287 DEBUG(8, ("IDMAP proxy only\n"));
288 return WINBINDD_ERROR;
291 status = idmap_uid_to_sid(&sid, state->request.data.uid,
292 ID_QUERY_ONLY | ID_CACHE_ONLY);
294 if (NT_STATUS_IS_OK(status)) {
295 sid_to_string(state->response.data.sid.sid, &sid);
296 state->response.data.sid.type = SID_NAME_USER;
297 return WINBINDD_OK;
300 if (is_in_uid_range(state->request.data.uid)) {
301 /* This is winbind's, so we should better have succeeded
302 * above. */
303 return WINBINDD_ERROR;
306 /* The only chance that this is correct is that winbind trusted
307 * domains only = yes, and the user exists in nss and the domain. */
309 if (!lp_winbind_trusted_domains_only()) {
310 return WINBINDD_ERROR;
313 /* The only chance that this is correct is that winbind trusted
314 * domains only = yes, and the user exists in nss and the domain. */
316 uid2sid_state = TALLOC_ZERO_P(state->mem_ctx, struct uid2sid_state);
317 if (uid2sid_state == NULL) {
318 DEBUG(0, ("talloc failed\n"));
319 return WINBINDD_ERROR;
322 uid2sid_state->cli_state = state;
323 uid2sid_state->uid = state->request.data.uid;
325 winbindd_uid2name_async(state->mem_ctx, state->request.data.uid,
326 uid2sid_uid2name_recv, uid2sid_state);
327 return WINBINDD_PENDING;
330 static void uid2sid_uid2name_recv(void *private, BOOL success,
331 const char *username)
333 struct uid2sid_state *state =
334 talloc_get_type_abort(private, struct uid2sid_state);
336 DEBUG(10, ("uid2sid: uid %lu has name %s\n",
337 (unsigned long)state->uid, username));
339 fstrcpy(state->name, username);
341 if (!success) {
342 state->cli_state->response.result = WINBINDD_ERROR;
343 request_finished(state->cli_state);
344 return;
347 winbindd_lookupname_async(state->cli_state->mem_ctx,
348 find_our_domain()->name, username,
349 uid2sid_lookupname_recv, state);
352 static void uid2sid_lookupname_recv(void *private, BOOL success,
353 const DOM_SID *sid, enum SID_NAME_USE type)
355 struct uid2sid_state *state =
356 talloc_get_type_abort(private, struct uid2sid_state);
357 unid_t id;
359 if ((!success) || (type != SID_NAME_USER)) {
360 state->cli_state->response.result = WINBINDD_ERROR;
361 request_finished(state->cli_state);
362 return;
365 state->sid = *sid;
366 state->type = type;
368 id.uid = state->uid;
369 idmap_set_mapping_async(state->cli_state->mem_ctx, sid, id, ID_USERID,
370 uid2sid_idmap_set_mapping_recv, state );
373 static void uid2sid_idmap_set_mapping_recv(void *private, BOOL success)
375 struct uid2sid_state *state =
376 talloc_get_type_abort(private, struct uid2sid_state);
378 /* don't fail if we can't store it */
380 sid_to_string(state->cli_state->response.data.sid.sid, &state->sid);
381 state->cli_state->response.data.sid.type = state->type;
382 state->cli_state->response.result = WINBINDD_OK;
383 request_finished(state->cli_state);
386 /* Convert a gid to a sid */
388 struct gid2sid_state {
389 struct winbindd_cli_state *cli_state;
390 gid_t gid;
391 fstring name;
392 DOM_SID sid;
393 enum SID_NAME_USE type;
396 static void gid2sid_gid2name_recv(void *private, BOOL success,
397 const char *groupname);
398 static void gid2sid_lookupname_recv(void *private, BOOL success,
399 const DOM_SID *sid,
400 enum SID_NAME_USE type);
401 static void gid2sid_idmap_set_mapping_recv(void *private, BOOL success);
403 enum winbindd_result winbindd_gid_to_sid(struct winbindd_cli_state *state)
405 DOM_SID sid;
406 NTSTATUS status;
407 struct gid2sid_state *gid2sid_state;
409 DEBUG(3, ("[%5lu]: gid to sid %lu\n", (unsigned long)state->pid,
410 (unsigned long)state->request.data.gid));
412 if (idmap_proxyonly()) {
413 DEBUG(8, ("IDMAP proxy only\n"));
414 return WINBINDD_ERROR;
417 status = idmap_gid_to_sid(&sid, state->request.data.gid,
418 ID_QUERY_ONLY | ID_CACHE_ONLY);
420 if (NT_STATUS_IS_OK(status)) {
421 sid_to_string(state->response.data.sid.sid, &sid);
422 state->response.data.sid.type = SID_NAME_USER;
423 return WINBINDD_OK;
426 if (is_in_gid_range(state->request.data.gid)) {
427 /* This is winbind's, so we should better have succeeded
428 * above. */
429 return WINBINDD_ERROR;
432 /* The only chance that this is correct is that winbind trusted
433 * domains only = yes, and the user exists in nss and the domain. */
435 if (!lp_winbind_trusted_domains_only()) {
436 return WINBINDD_ERROR;
439 /* The only chance that this is correct is that winbind trusted
440 * domains only = yes, and the user exists in nss and the domain. */
442 gid2sid_state = TALLOC_ZERO_P(state->mem_ctx, struct gid2sid_state);
443 if (gid2sid_state == NULL) {
444 DEBUG(0, ("talloc failed\n"));
445 return WINBINDD_ERROR;
448 gid2sid_state->cli_state = state;
449 gid2sid_state->gid = state->request.data.gid;
451 winbindd_gid2name_async(state->mem_ctx, state->request.data.gid,
452 gid2sid_gid2name_recv, gid2sid_state);
453 return WINBINDD_PENDING;
456 static void gid2sid_gid2name_recv(void *private, BOOL success,
457 const char *username)
459 struct gid2sid_state *state =
460 talloc_get_type_abort(private, struct gid2sid_state);
462 DEBUG(10, ("gid2sid: gid %lu has name %s\n",
463 (unsigned long)state->gid, username));
465 fstrcpy(state->name, username);
467 if (!success) {
468 state->cli_state->response.result = WINBINDD_ERROR;
469 request_finished(state->cli_state);
470 return;
473 winbindd_lookupname_async(state->cli_state->mem_ctx,
474 find_our_domain()->name, username,
475 gid2sid_lookupname_recv, state);
478 static void gid2sid_lookupname_recv(void *private, BOOL success,
479 const DOM_SID *sid, enum SID_NAME_USE type)
481 struct gid2sid_state *state =
482 talloc_get_type_abort(private, struct gid2sid_state);
483 unid_t id;
485 if ((!success) ||
486 ((type != SID_NAME_DOM_GRP) && (type!=SID_NAME_ALIAS))) {
487 state->cli_state->response.result = WINBINDD_ERROR;
488 request_finished(state->cli_state);
489 return;
492 state->sid = *sid;
493 state->type = type;
495 id.gid = state->gid;
496 idmap_set_mapping_async(state->cli_state->mem_ctx, sid, id, ID_GROUPID,
497 gid2sid_idmap_set_mapping_recv, state );
500 static void gid2sid_idmap_set_mapping_recv(void *private, BOOL success)
502 struct gid2sid_state *state = private;
504 /* don't fail if we can't store it */
506 sid_to_string(state->cli_state->response.data.sid.sid, &state->sid);
507 state->cli_state->response.data.sid.type = state->type;
508 state->cli_state->response.result = WINBINDD_OK;
509 request_finished(state->cli_state);
512 enum winbindd_result winbindd_allocate_rid(struct winbindd_cli_state *state)
514 if ( !state->privileged ) {
515 DEBUG(2, ("winbindd_allocate_rid: non-privileged access "
516 "denied!\n"));
517 return WINBINDD_ERROR;
520 async_request(state->mem_ctx, idmap_child(),
521 &state->request, &state->response,
522 request_finished_cont, state);
523 return WINBINDD_PENDING;
526 enum winbindd_result winbindd_dual_allocate_rid(struct winbindd_domain *domain,
527 struct winbindd_cli_state *state)
529 /* We tell idmap to always allocate a user RID. There might be a good
530 * reason to keep RID allocation for users to even and groups to
531 * odd. This needs discussion I think. For now only allocate user
532 * rids. */
534 if (!NT_STATUS_IS_OK(idmap_allocate_rid(&state->response.data.rid,
535 USER_RID_TYPE)))
536 return WINBINDD_ERROR;
538 return WINBINDD_OK;
541 enum winbindd_result winbindd_allocate_rid_and_gid(struct winbindd_cli_state *state)
543 if ( !state->privileged ) {
544 DEBUG(2, ("winbindd_allocate_rid: non-privileged access "
545 "denied!\n"));
546 return WINBINDD_ERROR;
549 async_request(state->mem_ctx, idmap_child(),
550 &state->request, &state->response,
551 request_finished_cont, state);
552 return WINBINDD_PENDING;
555 enum winbindd_result winbindd_dual_allocate_rid_and_gid(struct winbindd_domain *domain,
556 struct winbindd_cli_state *state)
558 NTSTATUS result;
559 DOM_SID sid;
561 /* We tell idmap to always allocate a user RID. This is really
562 * historic and needs to be fixed. I *think* this has to do with the
563 * way winbind determines its free RID space. */
565 result = idmap_allocate_rid(&state->response.data.rid_and_gid.rid,
566 USER_RID_TYPE);
568 if (!NT_STATUS_IS_OK(result))
569 return WINBINDD_ERROR;
571 sid_copy(&sid, get_global_sam_sid());
572 sid_append_rid(&sid, state->response.data.rid_and_gid.rid);
574 result = idmap_sid_to_gid(&sid, &state->response.data.rid_and_gid.gid,
577 if (!NT_STATUS_IS_OK(result))
578 return WINBINDD_ERROR;
580 return WINBINDD_OK;