84a7e76e78fe8077f98ef5690bff4eb1092fbad8
[samba.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 3 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 lsa_SidType 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 lsa_SidType 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 lsa_SidType 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, WINBINDD_LOOKUPNAME, 
107                                   state);
108 }
109
110 static void lookupname_recv(void *private_data, BOOL success,
111                             const DOM_SID *sid, enum lsa_SidType type)
112 {
113         struct winbindd_cli_state *state =
114                 talloc_get_type_abort(private_data, struct winbindd_cli_state);
115
116         if (!success) {
117                 DEBUG(5, ("lookupname returned an error\n"));
118                 request_error(state);
119                 return;
120         }
121
122         sid_to_string(state->response.data.sid.sid, sid);
123         state->response.data.sid.type = type;
124         request_ok(state);
125         return;
126 }
127
128 void winbindd_lookuprids(struct winbindd_cli_state *state)
129 {
130         struct winbindd_domain *domain;
131         DOM_SID domain_sid;
132         
133         /* Ensure null termination */
134         state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
135
136         DEBUG(10, ("lookup_rids: %s\n", state->request.data.sid));
137
138         if (!string_to_sid(&domain_sid, state->request.data.sid)) {
139                 DEBUG(5, ("Could not convert %s to SID\n",
140                           state->request.data.sid));
141                 request_error(state);
142                 return;
143         }
144
145         domain = find_lookup_domain_from_sid(&domain_sid);
146         if (domain == NULL) {
147                 DEBUG(10, ("Could not find domain for name %s\n",
148                            state->request.domain_name));
149                 request_error(state);
150                 return;
151         }
152
153         sendto_domain(state, domain);
154 }
155
156 static struct winbindd_child static_idmap_child;
157
158 void init_idmap_child(void)
159 {
160         setup_domain_child(NULL, &static_idmap_child, "idmap");
161 }
162
163 struct winbindd_child *idmap_child(void)
164 {
165         return &static_idmap_child;
166 }
167
168 /* Convert a sid to a uid.  We assume we only have one rid attached to the
169    sid. */
170
171 static void sid2uid_recv(void *private_data, BOOL success, uid_t uid)
172 {
173         struct winbindd_cli_state *state =
174                 talloc_get_type_abort(private_data, struct winbindd_cli_state);
175
176         if (!success) {
177                 DEBUG(5, ("Could not convert sid %s\n",
178                           state->request.data.sid));
179                 request_error(state);
180                 return;
181         }
182
183         state->response.data.uid = uid;
184         request_ok(state);
185 }
186
187 static void sid2uid_lookupsid_recv( void *private_data, BOOL success, 
188                                     const char *domain_name, 
189                                     const char *name, 
190                                     enum lsa_SidType type)
191 {
192         struct winbindd_cli_state *state =
193                 talloc_get_type_abort(private_data, struct winbindd_cli_state);
194         DOM_SID sid;
195
196         if (!success) {
197                 DEBUG(5, ("sid2uid_lookupsid_recv Could not convert get sid type for %s\n",
198                           state->request.data.sid));
199                 request_error(state);
200                 return;
201         }
202
203         if ( (type!=SID_NAME_USER) && (type!=SID_NAME_COMPUTER) ) {
204                 DEBUG(5,("sid2uid_lookupsid_recv: Sid %s is not a user or a computer.\n", 
205                          state->request.data.sid));
206                 request_error(state);
207                 return;         
208         }
209
210         if (!string_to_sid(&sid, state->request.data.sid)) {
211                 DEBUG(1, ("sid2uid_lookupsid_recv: Could not get convert sid %s from string\n",
212                           state->request.data.sid));
213                 request_error(state);
214                 return;
215         }
216         
217         /* always use the async interface (may block) */
218         winbindd_sid2uid_async(state->mem_ctx, &sid, sid2uid_recv, state);
219 }
220
221 void winbindd_sid_to_uid(struct winbindd_cli_state *state)
222 {
223         DOM_SID sid;
224
225         /* Ensure null termination */
226         state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
227
228         DEBUG(3, ("[%5lu]: sid to uid %s\n", (unsigned long)state->pid,
229                   state->request.data.sid));
230
231         if (!string_to_sid(&sid, state->request.data.sid)) {
232                 DEBUG(1, ("Could not get convert sid %s from string\n",
233                           state->request.data.sid));
234                 request_error(state);
235                 return;
236         }
237
238         /* Validate the SID as a user.  Hopefully this will hit cache.
239            Needed to prevent DoS by exhausting the uid allocation
240            range from random SIDs. */
241
242         winbindd_lookupsid_async( state->mem_ctx, &sid, sid2uid_lookupsid_recv, state );
243 }
244
245 /* Convert a sid to a gid.  We assume we only have one rid attached to the
246    sid.*/
247
248 static void sid2gid_recv(void *private_data, BOOL success, gid_t gid)
249 {
250         struct winbindd_cli_state *state =
251                 talloc_get_type_abort(private_data, struct winbindd_cli_state);
252
253         if (!success) {
254                 DEBUG(5, ("Could not convert sid %s\n",
255                           state->request.data.sid));
256                 request_error(state);
257                 return;
258         }
259
260         state->response.data.gid = gid;
261         request_ok(state);
262 }
263
264 static void sid2gid_lookupsid_recv( void *private_data, BOOL success, 
265                                     const char *domain_name, 
266                                     const char *name, 
267                                     enum lsa_SidType type)
268 {
269         struct winbindd_cli_state *state =
270                 talloc_get_type_abort(private_data, struct winbindd_cli_state);
271         DOM_SID sid;
272
273         if (!success) {
274                 DEBUG(5, ("sid2gid_lookupsid_recv: Could not get sid type for %s\n",
275                           state->request.data.sid));
276                 request_error(state);
277                 return;
278         }
279
280         if ( (type!=SID_NAME_DOM_GRP) &&
281              (type!=SID_NAME_ALIAS) && 
282              (type!=SID_NAME_WKN_GRP) ) 
283         {
284                 DEBUG(5,("sid2gid_lookupsid_recv: Sid %s is not a group.\n", 
285                          state->request.data.sid));
286                 request_error(state);
287                 return;         
288         }
289
290         if (!string_to_sid(&sid, state->request.data.sid)) {
291                 DEBUG(1, ("sid2gid_lookupsid_recv: Could not get convert sid %s from string\n",
292                           state->request.data.sid));
293                 request_error(state);
294                 return;
295         }
296         
297         /* always use the async interface (may block) */
298         winbindd_sid2gid_async(state->mem_ctx, &sid, sid2gid_recv, state);
299 }
300
301 void winbindd_sid_to_gid(struct winbindd_cli_state *state)
302 {
303         DOM_SID sid;
304
305         /* Ensure null termination */
306         state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
307
308         DEBUG(3, ("[%5lu]: sid to gid %s\n", (unsigned long)state->pid,
309                   state->request.data.sid));
310
311         if (!string_to_sid(&sid, state->request.data.sid)) {
312                 DEBUG(1, ("Could not get convert sid %s from string\n",
313                           state->request.data.sid));
314                 request_error(state);
315                 return;
316         }
317
318         /* Validate the SID as a group.  Hopefully this will hit cache.
319            Needed to prevent DoS by exhausting the uid allocation
320            range from random SIDs. */
321
322         winbindd_lookupsid_async( state->mem_ctx, &sid, sid2gid_lookupsid_recv, state );        
323 }
324
325 static void sids2xids_recv(void *private_data, BOOL success, void *data, int len)
326 {
327         struct winbindd_cli_state *state =
328                 talloc_get_type_abort(private_data, struct winbindd_cli_state);
329
330         if (!success) {
331                 DEBUG(5, ("Could not convert sids to xids\n"));
332                 request_error(state);
333                 return;
334         }
335
336         state->response.extra_data.data = data;
337         state->response.length = sizeof(state->response) + len;
338         request_ok(state);
339 }
340
341 void winbindd_sids_to_unixids(struct winbindd_cli_state *state)
342 {
343         DEBUG(3, ("[%5lu]: sids to xids\n", (unsigned long)state->pid));
344
345         winbindd_sids2xids_async(state->mem_ctx,
346                         state->request.extra_data.data,
347                         state->request.extra_len,
348                         sids2xids_recv, state);
349 }
350
351 static void set_mapping_recv(void *private_data, BOOL success)
352 {
353         struct winbindd_cli_state *state =
354                 talloc_get_type_abort(private_data, struct winbindd_cli_state);
355
356         if (!success) {
357                 DEBUG(5, ("Could not set sid mapping\n"));
358                 request_error(state);
359                 return;
360         }
361
362         request_ok(state);
363 }
364
365 void winbindd_set_mapping(struct winbindd_cli_state *state)
366 {
367         struct id_map map;
368         DOM_SID sid;
369
370         DEBUG(3, ("[%5lu]: set id map\n", (unsigned long)state->pid));
371
372         if ( ! state->privileged) {
373                 DEBUG(0, ("Only root is allowed to set mappings!\n"));
374                 request_error(state);
375                 return;
376         }
377
378         if (!string_to_sid(&sid, state->request.data.dual_idmapset.sid)) {
379                 DEBUG(1, ("Could not get convert sid %s from string\n",
380                           state->request.data.sid));
381                 request_error(state);
382                 return;
383         }
384
385         map.sid = &sid;
386         map.xid.id = state->request.data.dual_idmapset.id;
387         map.xid.type = state->request.data.dual_idmapset.type;
388
389         winbindd_set_mapping_async(state->mem_ctx, &map,
390                         set_mapping_recv, state);
391 }
392
393 static void set_hwm_recv(void *private_data, BOOL success)
394 {
395         struct winbindd_cli_state *state =
396                 talloc_get_type_abort(private_data, struct winbindd_cli_state);
397
398         if (!success) {
399                 DEBUG(5, ("Could not set sid mapping\n"));
400                 request_error(state);
401                 return;
402         }
403
404         request_ok(state);
405 }
406
407 void winbindd_set_hwm(struct winbindd_cli_state *state)
408 {
409         struct unixid xid;
410
411         DEBUG(3, ("[%5lu]: set hwm\n", (unsigned long)state->pid));
412
413         if ( ! state->privileged) {
414                 DEBUG(0, ("Only root is allowed to set mappings!\n"));
415                 request_error(state);
416                 return;
417         }
418
419         xid.id = state->request.data.dual_idmapset.id;
420         xid.type = state->request.data.dual_idmapset.type;
421
422         winbindd_set_hwm_async(state->mem_ctx, &xid, set_hwm_recv, state);
423 }
424
425 /* Convert a uid to a sid */
426
427 static void uid2sid_recv(void *private_data, BOOL success, const char *sid)
428 {
429         struct winbindd_cli_state *state =
430                 (struct winbindd_cli_state *)private_data;
431
432         if (success) {
433                 DEBUG(10,("uid2sid: uid %lu has sid %s\n",
434                           (unsigned long)(state->request.data.uid), sid));
435                 fstrcpy(state->response.data.sid.sid, sid);
436                 state->response.data.sid.type = SID_NAME_USER;
437                 request_ok(state);
438                 return;
439         }
440
441         request_error(state);
442         return;
443 }
444
445 void winbindd_uid_to_sid(struct winbindd_cli_state *state)
446 {
447         DEBUG(3, ("[%5lu]: uid to sid %lu\n", (unsigned long)state->pid, 
448                   (unsigned long)state->request.data.uid));
449
450         /* always go via the async interface (may block) */
451         winbindd_uid2sid_async(state->mem_ctx, state->request.data.uid, uid2sid_recv, state);
452 }
453
454 /* Convert a gid to a sid */
455
456 static void gid2sid_recv(void *private_data, BOOL success, const char *sid)
457 {
458         struct winbindd_cli_state *state =
459                 (struct winbindd_cli_state *)private_data;
460
461         if (success) {
462                 DEBUG(10,("gid2sid: gid %lu has sid %s\n",
463                           (unsigned long)(state->request.data.gid), sid));
464                 fstrcpy(state->response.data.sid.sid, sid);
465                 state->response.data.sid.type = SID_NAME_DOM_GRP;
466                 request_ok(state);
467                 return;
468         }
469
470         request_error(state);
471         return;
472 }
473
474
475 void winbindd_gid_to_sid(struct winbindd_cli_state *state)
476 {
477         DEBUG(3, ("[%5lu]: gid to sid %lu\n", (unsigned long)state->pid, 
478                   (unsigned long)state->request.data.gid));
479
480         /* always use async calls (may block) */
481         winbindd_gid2sid_async(state->mem_ctx, state->request.data.gid, gid2sid_recv, state);
482 }
483
484 void winbindd_allocate_uid(struct winbindd_cli_state *state)
485 {
486         if ( !state->privileged ) {
487                 DEBUG(2, ("winbindd_allocate_uid: non-privileged access "
488                           "denied!\n"));
489                 request_error(state);
490                 return;
491         }
492
493         sendto_child(state, idmap_child());
494 }
495
496 enum winbindd_result winbindd_dual_allocate_uid(struct winbindd_domain *domain,
497                                                 struct winbindd_cli_state *state)
498 {
499         struct unixid xid;
500
501         if (!NT_STATUS_IS_OK(idmap_allocate_uid(&xid))) {
502                 return WINBINDD_ERROR;
503         }
504         state->response.data.uid = xid.id;
505         return WINBINDD_OK;
506 }
507
508 void winbindd_allocate_gid(struct winbindd_cli_state *state)
509 {
510         if ( !state->privileged ) {
511                 DEBUG(2, ("winbindd_allocate_gid: non-privileged access "
512                           "denied!\n"));
513                 request_error(state);
514                 return;
515         }
516
517         sendto_child(state, idmap_child());
518 }
519
520 enum winbindd_result winbindd_dual_allocate_gid(struct winbindd_domain *domain,
521                                                 struct winbindd_cli_state *state)
522 {
523         struct unixid xid;
524
525         if (!NT_STATUS_IS_OK(idmap_allocate_gid(&xid))) {
526                 return WINBINDD_ERROR;
527         }
528         state->response.data.gid = xid.id;
529         return WINBINDD_OK;
530 }
531
532 static void dump_maps_recv(void *private_data, BOOL success)
533 {
534         struct winbindd_cli_state *state =
535                 talloc_get_type_abort(private_data, struct winbindd_cli_state);
536
537         if (!success) {
538                 DEBUG(5, ("Could not dump maps\n"));
539                 request_error(state);
540                 return;
541         }
542
543         request_ok(state);
544 }
545
546 void winbindd_dump_maps(struct winbindd_cli_state *state)
547 {
548         if ( ! state->privileged) {
549                 DEBUG(0, ("Only root is allowed to ask for an idmap dump!\n"));
550                 request_error(state);
551                 return;
552         }
553
554         DEBUG(3, ("[%5lu]: dump maps\n", (unsigned long)state->pid));
555
556         winbindd_dump_maps_async(state->mem_ctx,
557                         state->request.extra_data.data,
558                         state->request.extra_len,
559                         dump_maps_recv, state);
560 }
561