2685e98555c757ee952c2f688417ee80c0d8fa12
[samba] / source / 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.sid[sizeof(state->request.data.name.dom_name)-1]='\0';
87
88         /* Ensure null termination */
89         state->request.data.sid[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 static struct winbindd_child static_idmap_child;
128
129 void init_idmap_child(void)
130 {
131         setup_domain_child(NULL, &static_idmap_child, "idmap");
132 }
133
134 struct winbindd_child *idmap_child(void)
135 {
136         return &static_idmap_child;
137 }
138
139 /* Convert a sid to a uid.  We assume we only have one rid attached to the
140    sid. */
141
142 static void sid2uid_recv(void *private_data, BOOL success, uid_t uid);
143
144 void winbindd_sid_to_uid(struct winbindd_cli_state *state)
145 {
146         DOM_SID sid;
147         NTSTATUS result;
148
149         /* Ensure null termination */
150         state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
151
152         DEBUG(3, ("[%5lu]: sid to uid %s\n", (unsigned long)state->pid,
153                   state->request.data.sid));
154
155         if (idmap_proxyonly()) {
156                 DEBUG(8, ("IDMAP proxy only\n"));
157                 request_error(state);
158                 return;
159         }
160
161         if (!string_to_sid(&sid, state->request.data.sid)) {
162                 DEBUG(1, ("Could not get convert sid %s from string\n",
163                           state->request.data.sid));
164                 request_error(state);
165                 return;
166         }
167
168         /* Query only the local tdb, everything else might possibly block */
169
170         result = idmap_sid_to_uid(&sid, &(state->response.data.uid),
171                                   ID_QUERY_ONLY|ID_CACHE_ONLY);
172
173         if (NT_STATUS_IS_OK(result)) {
174                 request_ok(state);
175                 return;
176         }
177
178         winbindd_sid2uid_async(state->mem_ctx, &sid, sid2uid_recv, state);
179 }
180
181 static void sid2uid_recv(void *private_data, BOOL success, uid_t uid)
182 {
183         struct winbindd_cli_state *state =
184                 talloc_get_type_abort(private_data, struct winbindd_cli_state);
185
186         if (!success) {
187                 DEBUG(5, ("Could not convert sid %s\n",
188                           state->request.data.sid));
189                 request_error(state);
190                 return;
191         }
192
193         state->response.data.uid = uid;
194         request_ok(state);
195 }
196
197 /* Convert a sid to a gid.  We assume we only have one rid attached to the
198    sid.*/
199
200 static void sid2gid_recv(void *private_data, BOOL success, gid_t gid);
201
202 void winbindd_sid_to_gid(struct winbindd_cli_state *state)
203 {
204         DOM_SID sid;
205         NTSTATUS result;
206
207         /* Ensure null termination */
208         state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
209
210         DEBUG(3, ("[%5lu]: sid to gid %s\n", (unsigned long)state->pid,
211                   state->request.data.sid));
212
213         if (idmap_proxyonly()) {
214                 DEBUG(8, ("IDMAP proxy only\n"));
215                 request_error(state);
216                 return;
217         }
218
219         if (!string_to_sid(&sid, state->request.data.sid)) {
220                 DEBUG(1, ("Could not get convert sid %s from string\n",
221                           state->request.data.sid));
222                 request_error(state);
223                 return;
224         }
225
226         /* Query only the local tdb, everything else might possibly block */
227
228         result = idmap_sid_to_gid(&sid, &(state->response.data.gid),
229                                   ID_QUERY_ONLY|ID_CACHE_ONLY);
230
231         if (NT_STATUS_IS_OK(result)) {
232                 request_ok(state);
233                 return;
234         }
235
236         winbindd_sid2gid_async(state->mem_ctx, &sid, sid2gid_recv, state);
237 }
238
239 static void sid2gid_recv(void *private_data, BOOL success, gid_t gid)
240 {
241         struct winbindd_cli_state *state =
242                 talloc_get_type_abort(private_data, struct winbindd_cli_state);
243
244         if (!success) {
245                 DEBUG(5, ("Could not convert sid %s\n",
246                           state->request.data.sid));
247                 request_error(state);
248                 return;
249         }
250
251         state->response.data.gid = gid;
252         request_ok(state);
253 }
254
255 /* Convert a uid to a sid */
256
257 struct uid2sid_state {
258         struct winbindd_cli_state *cli_state;
259         uid_t uid;
260         fstring name;
261         DOM_SID sid;
262         enum SID_NAME_USE type;
263 };
264
265 static void uid2sid_uid2name_recv(void *private_data, BOOL success,
266                                   const char *username);
267 static void uid2sid_lookupname_recv(void *private_data, BOOL success,
268                                     const DOM_SID *sid,
269                                     enum SID_NAME_USE type);
270 static void uid2sid_idmap_set_mapping_recv(void *private_data, BOOL success);
271
272 void winbindd_uid_to_sid(struct winbindd_cli_state *state)
273 {
274         DOM_SID sid;
275         NTSTATUS status;
276         struct uid2sid_state *uid2sid_state;
277
278         DEBUG(3, ("[%5lu]: uid to sid %lu\n", (unsigned long)state->pid, 
279                   (unsigned long)state->request.data.uid));
280
281         if (idmap_proxyonly()) {
282                 DEBUG(8, ("IDMAP proxy only\n"));
283                 request_error(state);
284                 return;
285         }
286
287         status = idmap_uid_to_sid(&sid, state->request.data.uid,
288                                   ID_QUERY_ONLY | ID_CACHE_ONLY);
289
290         if (NT_STATUS_IS_OK(status)) {
291                 sid_to_string(state->response.data.sid.sid, &sid);
292                 state->response.data.sid.type = SID_NAME_USER;
293                 request_ok(state);
294                 return;
295         }
296
297         if (is_in_uid_range(state->request.data.uid)) {
298                 /* This is winbind's, so we should better have succeeded
299                  * above. */
300                 request_error(state);
301                 return;
302         }
303
304         /* The only chance that this is correct is that winbind trusted
305          * domains only = yes, and the user exists in nss and the domain. */
306
307         if (!lp_winbind_trusted_domains_only()) {
308                 request_error(state);
309                 return;
310         }
311
312         /* The only chance that this is correct is that winbind trusted
313          * domains only = yes, and the user exists in nss and the domain. */
314
315         uid2sid_state = TALLOC_ZERO_P(state->mem_ctx, struct uid2sid_state);
316         if (uid2sid_state == NULL) {
317                 DEBUG(0, ("talloc failed\n"));
318                 request_error(state);
319                 return;
320         }
321
322         uid2sid_state->cli_state = state;
323         uid2sid_state->uid = state->request.data.uid;
324
325         winbindd_uid2name_async(state->mem_ctx, state->request.data.uid,
326                                 uid2sid_uid2name_recv, uid2sid_state);
327 }
328
329 static void uid2sid_uid2name_recv(void *private_data, BOOL success,
330                                   const char *username)
331 {
332         struct uid2sid_state *state =
333                 talloc_get_type_abort(private_data, struct uid2sid_state);
334
335         DEBUG(10, ("uid2sid: uid %lu has name %s\n",
336                    (unsigned long)state->uid, username));
337
338         fstrcpy(state->name, username);
339
340         if (!success) {
341                 request_error(state->cli_state);
342                 return;
343         }
344
345         winbindd_lookupname_async(state->cli_state->mem_ctx,
346                                   find_our_domain()->name, username,
347                                   uid2sid_lookupname_recv, state);
348 }
349
350 static void uid2sid_lookupname_recv(void *private_data, BOOL success,
351                                     const DOM_SID *sid, enum SID_NAME_USE type)
352 {
353         struct uid2sid_state *state =
354                 talloc_get_type_abort(private_data, struct uid2sid_state);
355         unid_t id;
356
357         if ((!success) || (type != SID_NAME_USER)) {
358                 request_error(state->cli_state);
359                 return;
360         }
361
362         state->sid = *sid;
363         state->type = type;
364
365         id.uid = state->uid;
366         idmap_set_mapping_async(state->cli_state->mem_ctx, sid, id, ID_USERID,
367                                 uid2sid_idmap_set_mapping_recv, state );
368 }
369
370 static void uid2sid_idmap_set_mapping_recv(void *private_data, BOOL success)
371 {
372         struct uid2sid_state *state =
373                 talloc_get_type_abort(private_data, struct uid2sid_state);
374
375         /* don't fail if we can't store it */
376
377         sid_to_string(state->cli_state->response.data.sid.sid, &state->sid);
378         state->cli_state->response.data.sid.type = state->type;
379         request_ok(state->cli_state);
380 }
381
382 /* Convert a gid to a sid */
383
384 struct gid2sid_state {
385         struct winbindd_cli_state *cli_state;
386         gid_t gid;
387         fstring name;
388         DOM_SID sid;
389         enum SID_NAME_USE type;
390 };
391
392 static void gid2sid_gid2name_recv(void *private_data, BOOL success,
393                                   const char *groupname);
394 static void gid2sid_lookupname_recv(void *private_data, BOOL success,
395                                     const DOM_SID *sid,
396                                     enum SID_NAME_USE type);
397 static void gid2sid_idmap_set_mapping_recv(void *private_data, BOOL success);
398
399 void winbindd_gid_to_sid(struct winbindd_cli_state *state)
400 {
401         DOM_SID sid;
402         NTSTATUS status;
403         struct gid2sid_state *gid2sid_state;
404
405         DEBUG(3, ("[%5lu]: gid to sid %lu\n", (unsigned long)state->pid, 
406                   (unsigned long)state->request.data.gid));
407
408         if (idmap_proxyonly()) {
409                 DEBUG(8, ("IDMAP proxy only\n"));
410                 request_error(state);
411                 return;
412         }
413
414         status = idmap_gid_to_sid(&sid, state->request.data.gid,
415                                   ID_QUERY_ONLY | ID_CACHE_ONLY);
416
417         if (NT_STATUS_IS_OK(status)) {
418                 sid_to_string(state->response.data.sid.sid, &sid);
419                 state->response.data.sid.type = SID_NAME_USER;
420                 request_ok(state);
421                 return;
422         }
423
424         if (is_in_gid_range(state->request.data.gid)) {
425                 /* This is winbind's, so we should better have succeeded
426                  * above. */
427                 request_error(state);
428                 return;
429         }
430
431         /* The only chance that this is correct is that winbind trusted
432          * domains only = yes, and the user exists in nss and the domain. */
433
434         if (!lp_winbind_trusted_domains_only()) {
435                 request_error(state);
436                 return;
437         }
438
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. */
441
442         gid2sid_state = TALLOC_ZERO_P(state->mem_ctx, struct gid2sid_state);
443         if (gid2sid_state == NULL) {
444                 DEBUG(0, ("talloc failed\n"));
445                 request_error(state);
446                 return;
447         }
448
449         gid2sid_state->cli_state = state;
450         gid2sid_state->gid = state->request.data.gid;
451
452         winbindd_gid2name_async(state->mem_ctx, state->request.data.gid,
453                                 gid2sid_gid2name_recv, gid2sid_state);
454 }
455
456 static void gid2sid_gid2name_recv(void *private_data, BOOL success,
457                                   const char *username)
458 {
459         struct gid2sid_state *state =
460                 talloc_get_type_abort(private_data, struct gid2sid_state);
461
462         DEBUG(10, ("gid2sid: gid %lu has name %s\n",
463                    (unsigned long)state->gid, username));
464
465         fstrcpy(state->name, username);
466
467         if (!success) {
468                 request_error(state->cli_state);
469                 return;
470         }
471
472         winbindd_lookupname_async(state->cli_state->mem_ctx,
473                                   find_our_domain()->name, username,
474                                   gid2sid_lookupname_recv, state);
475 }
476
477 static void gid2sid_lookupname_recv(void *private_data, BOOL success,
478                                     const DOM_SID *sid, enum SID_NAME_USE type)
479 {
480         struct gid2sid_state *state =
481                 talloc_get_type_abort(private_data, struct gid2sid_state);
482         unid_t id;
483
484         if ((!success) ||
485             ((type != SID_NAME_DOM_GRP) && (type!=SID_NAME_ALIAS))) {
486                 request_error(state->cli_state);
487                 return;
488         }
489
490         state->sid = *sid;
491         state->type = type;
492
493         id.gid = state->gid;
494         idmap_set_mapping_async(state->cli_state->mem_ctx, sid, id, ID_GROUPID,
495                                 gid2sid_idmap_set_mapping_recv, state );
496 }
497
498 static void gid2sid_idmap_set_mapping_recv(void *private_data, BOOL success)
499 {
500         struct gid2sid_state *state = private_data;
501
502         /* don't fail if we can't store it */
503
504         sid_to_string(state->cli_state->response.data.sid.sid, &state->sid);
505         state->cli_state->response.data.sid.type = state->type;
506         request_ok(state->cli_state);
507 }
508
509 void winbindd_allocate_rid(struct winbindd_cli_state *state)
510 {
511         if ( !state->privileged ) {
512                 DEBUG(2, ("winbindd_allocate_rid: non-privileged access "
513                           "denied!\n"));
514                 request_error(state);
515                 return;
516         }
517
518         sendto_child(state, idmap_child());
519 }
520
521 enum winbindd_result winbindd_dual_allocate_rid(struct winbindd_domain *domain,
522                                                 struct winbindd_cli_state *state)
523 {
524         /* We tell idmap to always allocate a user RID. There might be a good
525          * reason to keep RID allocation for users to even and groups to
526          * odd. This needs discussion I think. For now only allocate user
527          * rids. */
528
529         if (!NT_STATUS_IS_OK(idmap_allocate_rid(&state->response.data.rid,
530                                                 USER_RID_TYPE)))
531                 return WINBINDD_ERROR;
532
533         return WINBINDD_OK;
534 }
535
536 void winbindd_allocate_rid_and_gid(struct winbindd_cli_state *state)
537 {
538         if ( !state->privileged ) {
539                 DEBUG(2, ("winbindd_allocate_rid: non-privileged access "
540                           "denied!\n"));
541                 request_error(state);
542                 return;
543         }
544
545         sendto_child(state, idmap_child());
546 }
547
548 enum winbindd_result winbindd_dual_allocate_rid_and_gid(struct winbindd_domain *domain,
549                                                         struct winbindd_cli_state *state)
550 {
551         NTSTATUS result;
552         DOM_SID sid;
553
554         /* We tell idmap to always allocate a user RID. This is really
555          * historic and needs to be fixed. I *think* this has to do with the
556          * way winbind determines its free RID space. */
557
558         result = idmap_allocate_rid(&state->response.data.rid_and_gid.rid,
559                                     USER_RID_TYPE);
560
561         if (!NT_STATUS_IS_OK(result))
562                 return WINBINDD_ERROR;
563
564         sid_copy(&sid, get_global_sam_sid());
565         sid_append_rid(&sid, state->response.data.rid_and_gid.rid);
566
567         result = idmap_sid_to_gid(&sid, &state->response.data.rid_and_gid.gid,
568                                   0);
569
570         if (!NT_STATUS_IS_OK(result))
571                 return WINBINDD_ERROR;
572
573         return WINBINDD_OK;
574 }