r17605: Some C++ warnings
[abartlet/samba.git/.git] / source3 / nsswitch / winbindd_sid.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Winbind daemon - sid related functions
5
6    Copyright (C) Tim Potter 2000
7    
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.
12    
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.
17    
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.
21 */
22
23 #include "includes.h"
24 #include "winbindd.h"
25
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_WINBIND
28
29 /* Convert a string  */
30
31 static void lookupsid_recv(void *private_data, BOOL success,
32                            const char *dom_name, const char *name,
33                            enum SID_NAME_USE type);
34
35 void winbindd_lookupsid(struct winbindd_cli_state *state)
36 {
37         DOM_SID sid;
38
39         /* Ensure null termination */
40         state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
41
42         DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid, 
43                   state->request.data.sid));
44
45         if (!string_to_sid(&sid, state->request.data.sid)) {
46                 DEBUG(5, ("%s not a SID\n", state->request.data.sid));
47                 request_error(state);
48                 return;
49         }
50
51         winbindd_lookupsid_async(state->mem_ctx, &sid, lookupsid_recv, state);
52 }
53
54 static void lookupsid_recv(void *private_data, BOOL success,
55                            const char *dom_name, const char *name,
56                            enum SID_NAME_USE type)
57 {
58         struct winbindd_cli_state *state =
59                 talloc_get_type_abort(private_data, struct winbindd_cli_state);
60
61         if (!success) {
62                 DEBUG(5, ("lookupsid returned an error\n"));
63                 request_error(state);
64                 return;
65         }
66
67         fstrcpy(state->response.data.name.dom_name, dom_name);
68         fstrcpy(state->response.data.name.name, name);
69         state->response.data.name.type = type;
70         request_ok(state);
71 }
72
73 /**
74  * Look up the SID for a qualified name.  
75  **/
76
77 static void lookupname_recv(void *private_data, BOOL success,
78                             const DOM_SID *sid, enum SID_NAME_USE type);
79
80 void winbindd_lookupname(struct winbindd_cli_state *state)
81 {
82         char *name_domain, *name_user;
83         char *p;
84
85         /* Ensure null termination */
86         state->request.data.name.dom_name[sizeof(state->request.data.name.dom_name)-1]='\0';
87
88         /* Ensure null termination */
89         state->request.data.name.name[sizeof(state->request.data.name.name)-1]='\0';
90
91         /* cope with the name being a fully qualified name */
92         p = strstr(state->request.data.name.name, lp_winbind_separator());
93         if (p) {
94                 *p = 0;
95                 name_domain = state->request.data.name.name;
96                 name_user = p+1;
97         } else {
98                 name_domain = state->request.data.name.dom_name;
99                 name_user = state->request.data.name.name;
100         }
101
102         DEBUG(3, ("[%5lu]: lookupname %s%s%s\n", (unsigned long)state->pid,
103                   name_domain, lp_winbind_separator(), name_user));
104
105         winbindd_lookupname_async(state->mem_ctx, name_domain, name_user,
106                                   lookupname_recv, state);
107 }
108
109 static void lookupname_recv(void *private_data, BOOL success,
110                             const DOM_SID *sid, enum SID_NAME_USE type)
111 {
112         struct winbindd_cli_state *state =
113                 talloc_get_type_abort(private_data, struct winbindd_cli_state);
114
115         if (!success) {
116                 DEBUG(5, ("lookupname returned an error\n"));
117                 request_error(state);
118                 return;
119         }
120
121         sid_to_string(state->response.data.sid.sid, sid);
122         state->response.data.sid.type = type;
123         request_ok(state);
124         return;
125 }
126
127 void winbindd_lookuprids(struct winbindd_cli_state *state)
128 {
129         struct winbindd_domain *domain;
130         DOM_SID domain_sid;
131         
132         /* Ensure null termination */
133         state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
134
135         DEBUG(10, ("lookup_rids: %s\n", state->request.data.sid));
136
137         if (!string_to_sid(&domain_sid, state->request.data.sid)) {
138                 DEBUG(5, ("Could not convert %s to SID\n",
139                           state->request.data.sid));
140                 request_error(state);
141                 return;
142         }
143
144         domain = find_lookup_domain_from_sid(&domain_sid);
145         if (domain == NULL) {
146                 DEBUG(10, ("Could not find domain for name %s\n",
147                            state->request.domain_name));
148                 request_error(state);
149                 return;
150         }
151
152         sendto_domain(state, domain);
153 }
154
155 static struct winbindd_child static_idmap_child;
156
157 void init_idmap_child(void)
158 {
159         setup_domain_child(NULL, &static_idmap_child, "idmap");
160 }
161
162 struct winbindd_child *idmap_child(void)
163 {
164         return &static_idmap_child;
165 }
166
167 /* Convert a sid to a uid.  We assume we only have one rid attached to the
168    sid. */
169
170 static void sid2uid_recv(void *private_data, BOOL success, uid_t uid);
171
172 void winbindd_sid_to_uid(struct winbindd_cli_state *state)
173 {
174         DOM_SID sid;
175         NTSTATUS result;
176
177         /* Ensure null termination */
178         state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
179
180         DEBUG(3, ("[%5lu]: sid to uid %s\n", (unsigned long)state->pid,
181                   state->request.data.sid));
182
183         if (idmap_proxyonly()) {
184                 DEBUG(8, ("IDMAP proxy only\n"));
185                 request_error(state);
186                 return;
187         }
188
189         if (!string_to_sid(&sid, state->request.data.sid)) {
190                 DEBUG(1, ("Could not get convert sid %s from string\n",
191                           state->request.data.sid));
192                 request_error(state);
193                 return;
194         }
195
196         /* Query only the local tdb, everything else might possibly block */
197
198         result = idmap_sid_to_uid(&sid, &state->response.data.uid,
199                                   IDMAP_FLAG_QUERY_ONLY|IDMAP_FLAG_CACHE_ONLY);
200
201         if (NT_STATUS_IS_OK(result)) {
202                 request_ok(state);
203                 return;
204         }
205
206         winbindd_sid2uid_async(state->mem_ctx, &sid, sid2uid_recv, state);
207 }
208
209 static void sid2uid_recv(void *private_data, BOOL success, uid_t uid)
210 {
211         struct winbindd_cli_state *state =
212                 talloc_get_type_abort(private_data, struct winbindd_cli_state);
213
214         if (!success) {
215                 DEBUG(5, ("Could not convert sid %s\n",
216                           state->request.data.sid));
217                 request_error(state);
218                 return;
219         }
220
221         state->response.data.uid = uid;
222         request_ok(state);
223 }
224
225 /* Convert a sid to a gid.  We assume we only have one rid attached to the
226    sid.*/
227
228 static void sid2gid_recv(void *private_data, BOOL success, gid_t gid);
229
230 void winbindd_sid_to_gid(struct winbindd_cli_state *state)
231 {
232         DOM_SID sid;
233         NTSTATUS result;
234
235         /* Ensure null termination */
236         state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
237
238         DEBUG(3, ("[%5lu]: sid to gid %s\n", (unsigned long)state->pid,
239                   state->request.data.sid));
240
241         if (idmap_proxyonly()) {
242                 DEBUG(8, ("IDMAP proxy only\n"));
243                 request_error(state);
244                 return;
245         }
246
247         if (!string_to_sid(&sid, state->request.data.sid)) {
248                 DEBUG(1, ("Could not get convert sid %s from string\n",
249                           state->request.data.sid));
250                 request_error(state);
251                 return;
252         }
253
254         /* Query only the local tdb, everything else might possibly block */
255
256         result = idmap_sid_to_gid(&sid, &state->response.data.gid,
257                                   IDMAP_FLAG_QUERY_ONLY|IDMAP_FLAG_CACHE_ONLY);
258
259         if (NT_STATUS_IS_OK(result)) {
260                 request_ok(state);
261                 return;
262         }
263
264         winbindd_sid2gid_async(state->mem_ctx, &sid, sid2gid_recv, state);
265 }
266
267 static void sid2gid_recv(void *private_data, BOOL success, gid_t gid)
268 {
269         struct winbindd_cli_state *state =
270                 talloc_get_type_abort(private_data, struct winbindd_cli_state);
271
272         if (!success) {
273                 DEBUG(5, ("Could not convert sid %s\n",
274                           state->request.data.sid));
275                 request_error(state);
276                 return;
277         }
278
279         state->response.data.gid = gid;
280         request_ok(state);
281 }
282
283 /* Convert a uid to a sid */
284
285 struct uid2sid_state {
286         struct winbindd_cli_state *cli_state;
287         uid_t uid;
288         fstring name;
289         DOM_SID sid;
290         enum SID_NAME_USE type;
291 };
292
293 static void uid2sid_uid2name_recv(void *private_data, BOOL success,
294                                   const char *username);
295 static void uid2sid_lookupname_recv(void *private_data, BOOL success,
296                                     const DOM_SID *sid,
297                                     enum SID_NAME_USE type);
298 static void uid2sid_idmap_set_mapping_recv(void *private_data, BOOL success);
299
300 static void uid2sid_recv(void *private_data, BOOL success, const char *sid);
301
302 void winbindd_uid_to_sid(struct winbindd_cli_state *state)
303 {
304         DOM_SID sid;
305         NTSTATUS status;
306
307         DEBUG(3, ("[%5lu]: uid to sid %lu\n", (unsigned long)state->pid, 
308                   (unsigned long)state->request.data.uid));
309
310         if (idmap_proxyonly()) {
311                 DEBUG(8, ("IDMAP proxy only\n"));
312                 request_error(state);
313                 return;
314         }
315
316         status = idmap_uid_to_sid(&sid, state->request.data.uid,
317                                   IDMAP_FLAG_QUERY_ONLY|IDMAP_FLAG_CACHE_ONLY);
318
319         if (NT_STATUS_IS_OK(status)) {
320                 sid_to_string(state->response.data.sid.sid, &sid);
321                 state->response.data.sid.type = SID_NAME_USER;
322                 request_ok(state);
323                 return;
324         }
325
326         winbindd_uid2sid_async(state->mem_ctx, state->request.data.uid, uid2sid_recv, state);
327 }
328
329 static void uid2sid_recv(void *private_data, BOOL success, const char *sid)
330 {
331         struct winbindd_cli_state *state =
332                 (struct winbindd_cli_state *)private_data;
333         struct uid2sid_state *uid2sid_state;
334
335         if (success) {
336                 DEBUG(10,("uid2sid: uid %lu has sid %s\n",
337                           (unsigned long)(state->request.data.uid), sid));
338                 fstrcpy(state->response.data.sid.sid, sid);
339                 state->response.data.sid.type = SID_NAME_USER;
340                 request_ok(state);
341                 return;
342         }
343
344         /* preexisitng mapping not found go on */
345
346         if (is_in_uid_range(state->request.data.uid)) {
347                 /* This is winbind's, so we should better have succeeded
348                  * above. */
349                 request_error(state);
350                 return;
351         }
352
353         /* The only chance that this is correct is that winbind trusted
354          * domains only = yes, and the user exists in nss and the domain. */
355
356         if (!lp_winbind_trusted_domains_only()) {
357                 request_error(state);
358                 return;
359         }
360
361         uid2sid_state = TALLOC_ZERO_P(state->mem_ctx, struct uid2sid_state);
362         if (uid2sid_state == NULL) {
363                 DEBUG(0, ("talloc failed\n"));
364                 request_error(state);
365                 return;
366         }
367
368         uid2sid_state->cli_state = state;
369         uid2sid_state->uid = state->request.data.uid;
370
371         winbindd_uid2name_async(state->mem_ctx, state->request.data.uid,
372                                 uid2sid_uid2name_recv, uid2sid_state);
373 }
374
375 static void uid2sid_uid2name_recv(void *private_data, BOOL success,
376                                   const char *username)
377 {
378         struct uid2sid_state *state =
379                 talloc_get_type_abort(private_data, struct uid2sid_state);
380
381         DEBUG(10, ("uid2sid: uid %lu has name %s\n",
382                    (unsigned long)state->uid, username));
383
384         fstrcpy(state->name, username);
385
386         if (!success) {
387                 request_error(state->cli_state);
388                 return;
389         }
390
391         winbindd_lookupname_async(state->cli_state->mem_ctx,
392                                   find_our_domain()->name, username,
393                                   uid2sid_lookupname_recv, state);
394 }
395
396 static void uid2sid_lookupname_recv(void *private_data, BOOL success,
397                                     const DOM_SID *sid, enum SID_NAME_USE type)
398 {
399         struct uid2sid_state *state =
400                 talloc_get_type_abort(private_data, struct uid2sid_state);
401         unid_t id;
402
403         if ((!success) || (type != SID_NAME_USER)) {
404                 request_error(state->cli_state);
405                 return;
406         }
407
408         state->sid = *sid;
409         state->type = type;
410
411         id.uid = state->uid;
412         idmap_set_mapping_async(state->cli_state->mem_ctx, sid, id, ID_USERID,
413                                 uid2sid_idmap_set_mapping_recv, state );
414 }
415
416 static void uid2sid_idmap_set_mapping_recv(void *private_data, BOOL success)
417 {
418         struct uid2sid_state *state =
419                 talloc_get_type_abort(private_data, struct uid2sid_state);
420
421         /* don't fail if we can't store it */
422
423         sid_to_string(state->cli_state->response.data.sid.sid, &state->sid);
424         state->cli_state->response.data.sid.type = state->type;
425         request_ok(state->cli_state);
426 }
427
428 /* Convert a gid to a sid */
429
430 struct gid2sid_state {
431         struct winbindd_cli_state *cli_state;
432         gid_t gid;
433         fstring name;
434         DOM_SID sid;
435         enum SID_NAME_USE type;
436 };
437
438 static void gid2sid_gid2name_recv(void *private_data, BOOL success,
439                                   const char *groupname);
440 static void gid2sid_lookupname_recv(void *private_data, BOOL success,
441                                     const DOM_SID *sid,
442                                     enum SID_NAME_USE type);
443 static void gid2sid_idmap_set_mapping_recv(void *private_data, BOOL success);
444
445 static void gid2sid_recv(void *private_data, BOOL success, const char *sid);
446
447 void winbindd_gid_to_sid(struct winbindd_cli_state *state)
448 {
449         DOM_SID sid;
450         NTSTATUS status;
451
452         DEBUG(3, ("[%5lu]: gid to sid %lu\n", (unsigned long)state->pid, 
453                   (unsigned long)state->request.data.gid));
454
455         if (idmap_proxyonly()) {
456                 DEBUG(8, ("IDMAP proxy only\n"));
457                 request_error(state);
458                 return;
459         }
460
461         status = idmap_gid_to_sid(&sid, state->request.data.gid,
462                                   IDMAP_FLAG_QUERY_ONLY|IDMAP_FLAG_CACHE_ONLY);
463
464         if (NT_STATUS_IS_OK(status)) {
465                 sid_to_string(state->response.data.sid.sid, &sid);
466                 state->response.data.sid.type = SID_NAME_DOM_GRP;
467                 request_ok(state);
468                 return;
469         }
470
471         winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, gid2sid_recv, state);
472 }
473
474 static void gid2sid_recv(void *private_data, BOOL success, const char *sid)
475 {
476         struct winbindd_cli_state *state =
477                 (struct winbindd_cli_state *)private_data;
478         struct gid2sid_state *gid2sid_state;
479
480         if (success) {
481                 DEBUG(10,("gid2sid: gid %lu has sid %s\n",
482                           (unsigned long)(state->request.data.gid), sid));
483                 fstrcpy(state->response.data.sid.sid, sid);
484                 state->response.data.sid.type = SID_NAME_DOM_GRP;
485                 request_ok(state);
486                 return;
487         }
488
489         /* preexisitng mapping not found go on */
490
491         if (is_in_gid_range(state->request.data.gid)) {
492                 /* This is winbind's, so we should better have succeeded
493                  * above. */
494                 request_error(state);
495                 return;
496         }
497
498         /* The only chance that this is correct is that winbind trusted
499          * domains only = yes, and the user exists in nss and the domain. */
500
501         if (!lp_winbind_trusted_domains_only()) {
502                 request_error(state);
503                 return;
504         }
505
506         /* The only chance that this is correct is that winbind trusted
507          * domains only = yes, and the user exists in nss and the domain. */
508
509         gid2sid_state = TALLOC_ZERO_P(state->mem_ctx, struct gid2sid_state);
510         if (gid2sid_state == NULL) {
511                 DEBUG(0, ("talloc failed\n"));
512                 request_error(state);
513                 return;
514         }
515
516         gid2sid_state->cli_state = state;
517         gid2sid_state->gid = state->request.data.gid;
518
519         winbindd_gid2name_async(state->mem_ctx, state->request.data.gid,
520                                 gid2sid_gid2name_recv, gid2sid_state);
521 }
522
523 static void gid2sid_gid2name_recv(void *private_data, BOOL success,
524                                   const char *username)
525 {
526         struct gid2sid_state *state =
527                 talloc_get_type_abort(private_data, struct gid2sid_state);
528
529         DEBUG(10, ("gid2sid: gid %lu has name %s\n",
530                    (unsigned long)state->gid, username));
531
532         fstrcpy(state->name, username);
533
534         if (!success) {
535                 request_error(state->cli_state);
536                 return;
537         }
538
539         winbindd_lookupname_async(state->cli_state->mem_ctx,
540                                   find_our_domain()->name, username,
541                                   gid2sid_lookupname_recv, state);
542 }
543
544 static void gid2sid_lookupname_recv(void *private_data, BOOL success,
545                                     const DOM_SID *sid, enum SID_NAME_USE type)
546 {
547         struct gid2sid_state *state =
548                 talloc_get_type_abort(private_data, struct gid2sid_state);
549         unid_t id;
550
551         if ((!success) ||
552             ((type != SID_NAME_DOM_GRP) && (type!=SID_NAME_ALIAS))) {
553                 request_error(state->cli_state);
554                 return;
555         }
556
557         state->sid = *sid;
558         state->type = type;
559
560         id.gid = state->gid;
561         idmap_set_mapping_async(state->cli_state->mem_ctx, sid, id, ID_GROUPID,
562                                 gid2sid_idmap_set_mapping_recv, state );
563 }
564
565 static void gid2sid_idmap_set_mapping_recv(void *private_data, BOOL success)
566 {
567         struct gid2sid_state *state =
568                 (struct gid2sid_state *)private_data;
569
570         /* don't fail if we can't store it */
571
572         sid_to_string(state->cli_state->response.data.sid.sid, &state->sid);
573         state->cli_state->response.data.sid.type = state->type;
574         request_ok(state->cli_state);
575 }
576
577 void winbindd_allocate_uid(struct winbindd_cli_state *state)
578 {
579         if ( !state->privileged ) {
580                 DEBUG(2, ("winbindd_allocate_uid: non-privileged access "
581                           "denied!\n"));
582                 request_error(state);
583                 return;
584         }
585
586         sendto_child(state, idmap_child());
587 }
588
589 enum winbindd_result winbindd_dual_allocate_uid(struct winbindd_domain *domain,
590                                                 struct winbindd_cli_state *state)
591 {
592         union unid_t id;
593
594         if (!NT_STATUS_IS_OK(idmap_allocate_id(&id, ID_USERID))) {
595                 return WINBINDD_ERROR;
596         }
597         state->response.data.uid = id.uid;
598         return WINBINDD_OK;
599 }
600
601 void winbindd_allocate_gid(struct winbindd_cli_state *state)
602 {
603         if ( !state->privileged ) {
604                 DEBUG(2, ("winbindd_allocate_gid: non-privileged access "
605                           "denied!\n"));
606                 request_error(state);
607                 return;
608         }
609
610         sendto_child(state, idmap_child());
611 }
612
613 enum winbindd_result winbindd_dual_allocate_gid(struct winbindd_domain *domain,
614                                                 struct winbindd_cli_state *state)
615 {
616         union unid_t id;
617
618         if (!NT_STATUS_IS_OK(idmap_allocate_id(&id, ID_GROUPID))) {
619                 return WINBINDD_ERROR;
620         }
621         state->response.data.gid = id.gid;
622         return WINBINDD_OK;
623 }
624