import HEAD into svn+ssh://svn.samba.org/home/svn/samba/trunk
[metze/old/v3-2-winbind-ndr.git] / source / nsswitch / wb_client.c
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
31 extern DOM_SID global_sid_NULL;                         /* NULL sid */
32
33 NSS_STATUS winbindd_request(int req_type,
34                                  struct winbindd_request *request,
35                                  struct winbindd_response *response);
36
37 /* Call winbindd to convert a name to a sid */
38
39 BOOL winbind_lookup_name(const char *dom_name, const char *name, DOM_SID *sid, 
40                          enum SID_NAME_USE *name_type)
41 {
42         struct winbindd_request request;
43         struct winbindd_response response;
44         NSS_STATUS result;
45         
46         if (!sid || !name_type)
47                 return False;
48
49         /* Send off request */
50
51         ZERO_STRUCT(request);
52         ZERO_STRUCT(response);
53
54         fstrcpy(request.data.name.dom_name, dom_name);
55         fstrcpy(request.data.name.name, name);
56
57         if ((result = winbindd_request(WINBINDD_LOOKUPNAME, &request, 
58                                        &response)) == NSS_STATUS_SUCCESS) {
59                 if (!string_to_sid(sid, response.data.sid.sid))
60                         return False;
61                 *name_type = (enum SID_NAME_USE)response.data.sid.type;
62         }
63
64         return result == NSS_STATUS_SUCCESS;
65 }
66
67 /* Call winbindd to convert sid to name */
68
69 BOOL winbind_lookup_sid(const DOM_SID *sid, 
70                         fstring dom_name, fstring name, 
71                         enum SID_NAME_USE *name_type)
72 {
73         struct winbindd_request request;
74         struct winbindd_response response;
75         NSS_STATUS result;
76         fstring sid_str;
77         
78         /* Initialise request */
79
80         ZERO_STRUCT(request);
81         ZERO_STRUCT(response);
82
83         sid_to_string(sid_str, sid);
84         fstrcpy(request.data.sid, sid_str);
85         
86         /* Make request */
87
88         result = winbindd_request(WINBINDD_LOOKUPSID, &request, &response);
89
90         /* Copy out result */
91
92         if (result == NSS_STATUS_SUCCESS) {
93                 fstrcpy(dom_name, response.data.name.dom_name);
94                 fstrcpy(name, response.data.name.name);
95                 *name_type = (enum SID_NAME_USE)response.data.name.type;
96
97                 DEBUG(10, ("winbind_lookup_sid: SUCCESS: SID %s -> %s %s\n", 
98                            sid_str, dom_name, name));
99         }
100
101         return (result == NSS_STATUS_SUCCESS);
102 }
103
104 /* Call winbindd to convert SID to uid */
105
106 BOOL winbind_sid_to_uid(uid_t *puid, const DOM_SID *sid)
107 {
108         struct winbindd_request request;
109         struct winbindd_response response;
110         int result;
111         fstring sid_str;
112
113         if (!puid)
114                 return False;
115
116         /* Initialise request */
117
118         ZERO_STRUCT(request);
119         ZERO_STRUCT(response);
120
121         sid_to_string(sid_str, sid);
122         fstrcpy(request.data.sid, sid_str);
123         
124         /* Make request */
125
126         result = winbindd_request(WINBINDD_SID_TO_UID, &request, &response);
127
128         /* Copy out result */
129
130         if (result == NSS_STATUS_SUCCESS) {
131                 *puid = response.data.uid;
132         }
133
134         return (result == NSS_STATUS_SUCCESS);
135 }
136
137 /* Call winbindd to convert uid to sid */
138
139 BOOL winbind_uid_to_sid(DOM_SID *sid, uid_t uid)
140 {
141         struct winbindd_request request;
142         struct winbindd_response response;
143         int result;
144
145         if (!sid)
146                 return False;
147
148         /* Initialise request */
149
150         ZERO_STRUCT(request);
151         ZERO_STRUCT(response);
152
153         request.data.uid = uid;
154
155         /* Make request */
156
157         result = winbindd_request(WINBINDD_UID_TO_SID, &request, &response);
158
159         /* Copy out result */
160
161         if (result == NSS_STATUS_SUCCESS) {
162                 if (!string_to_sid(sid, response.data.sid.sid))
163                         return False;
164         } else {
165                 sid_copy(sid, &global_sid_NULL);
166         }
167
168         return (result == NSS_STATUS_SUCCESS);
169 }
170
171 /* Call winbindd to convert SID to gid */
172
173 BOOL winbind_sid_to_gid(gid_t *pgid, const DOM_SID *sid)
174 {
175         struct winbindd_request request;
176         struct winbindd_response response;
177         int result;
178         fstring sid_str;
179
180         if (!pgid)
181                 return False;
182
183         /* Initialise request */
184
185         ZERO_STRUCT(request);
186         ZERO_STRUCT(response);
187
188         sid_to_string(sid_str, sid);
189         fstrcpy(request.data.sid, sid_str);
190         
191         /* Make request */
192
193         result = winbindd_request(WINBINDD_SID_TO_GID, &request, &response);
194
195         /* Copy out result */
196
197         if (result == NSS_STATUS_SUCCESS) {
198                 *pgid = response.data.gid;
199         }
200
201         return (result == NSS_STATUS_SUCCESS);
202 }
203
204 /* Call winbindd to convert gid to sid */
205
206 BOOL winbind_gid_to_sid(DOM_SID *sid, gid_t gid)
207 {
208         struct winbindd_request request;
209         struct winbindd_response response;
210         int result;
211
212         if (!sid)
213                 return False;
214
215         /* Initialise request */
216
217         ZERO_STRUCT(request);
218         ZERO_STRUCT(response);
219
220         request.data.gid = gid;
221
222         /* Make request */
223
224         result = winbindd_request(WINBINDD_GID_TO_SID, &request, &response);
225
226         /* Copy out result */
227
228         if (result == NSS_STATUS_SUCCESS) {
229                 if (!string_to_sid(sid, response.data.sid.sid))
230                         return False;
231         } else {
232                 sid_copy(sid, &global_sid_NULL);
233         }
234
235         return (result == NSS_STATUS_SUCCESS);
236 }
237
238 BOOL winbind_allocate_rid(uint32 *rid)
239 {
240         struct winbindd_request request;
241         struct winbindd_response response;
242         int result;
243
244         /* Initialise request */
245
246         ZERO_STRUCT(request);
247         ZERO_STRUCT(response);
248
249         /* Make request */
250
251         result = winbindd_request(WINBINDD_ALLOCATE_RID, &request, &response);
252
253         if (result != NSS_STATUS_SUCCESS)
254                 return False;
255
256         /* Copy out result */
257         *rid = response.data.rid;
258
259         return True;
260 }
261
262 /* Fetch the list of groups a user is a member of from winbindd.  This is
263    used by winbind_getgroups. */
264
265 static int wb_getgroups(const char *user, gid_t **groups)
266 {
267         struct winbindd_request request;
268         struct winbindd_response response;
269         int result;
270
271         /* Call winbindd */
272
273         fstrcpy(request.data.username, user);
274
275         ZERO_STRUCT(response);
276
277         result = winbindd_request(WINBINDD_GETGROUPS, &request, &response);
278
279         if (result == NSS_STATUS_SUCCESS) {
280                 
281                 /* Return group list.  Don't forget to free the group list
282                    when finished. */
283
284                 *groups = (gid_t *)response.extra_data;
285                 return response.data.num_entries;
286         }
287
288         return -1;
289 }
290
291 /* Call winbindd to initialise group membership.  This is necessary for
292    some systems (i.e RH5.2) that do not have an initgroups function as part
293    of the nss extension.  In RH5.2 this is implemented using getgrent()
294    which can be amazingly inefficient as well as having problems with
295    username case. */
296
297 int winbind_initgroups(char *user, gid_t gid)
298 {
299         gid_t *tgr, *groups = NULL;
300         int result;
301
302         /* Call normal initgroups if we are a local user */
303
304         if (!strchr(user, *lp_winbind_separator())) {
305                 return initgroups(user, gid);
306         }
307
308         result = wb_getgroups(user, &groups);
309
310         DEBUG(10,("winbind_getgroups: %s: result = %s\n", user, 
311                   result == -1 ? "FAIL" : "SUCCESS"));
312
313         if (result != -1) {
314                 int ngroups = result, i;
315                 BOOL is_member = False;
316
317                 /* Check to see if the passed gid is already in the list */
318
319                 for (i = 0; i < ngroups; i++) {
320                         if (groups[i] == gid) {
321                                 is_member = True;
322                         }
323                 }
324
325                 /* Add group to list if necessary */
326
327                 if (!is_member) {
328                         tgr = (gid_t *)Realloc(groups, sizeof(gid_t) * ngroups + 1);
329                         
330                         if (!tgr) {
331                                 errno = ENOMEM;
332                                 result = -1;
333                                 goto done;
334                         }
335                         else groups = tgr;
336
337                         groups[ngroups] = gid;
338                         ngroups++;
339                 }
340
341                 /* Set the groups */
342
343                 if (sys_setgroups(ngroups, groups) == -1) {
344                         errno = EPERM;
345                         result = -1;
346                         goto done;
347                 }
348
349         } else {
350                 
351                 /* The call failed.  Set errno to something so we don't get
352                    a bogus value from the last failed system call. */
353
354                 errno = EIO;
355         }
356
357         /* Free response data if necessary */
358
359  done:
360         SAFE_FREE(groups);
361
362         return result;
363 }
364
365 /* Return a list of groups the user is a member of.  This function is
366    useful for large systems where inverting the group database would be too
367    time consuming.  If size is zero, list is not modified and the total
368    number of groups for the user is returned. */
369
370 int winbind_getgroups(const char *user, gid_t **list)
371 {
372         /*
373          * Don't do the lookup if the name has no separator _and_ we are not in
374          * 'winbind use default domain' mode.
375          */
376
377         if (!(strchr(user, *lp_winbind_separator()) || lp_winbind_use_default_domain()))
378                 return -1;
379
380         /* Fetch list of groups */
381
382         return wb_getgroups(user, list);
383 }
384
385 /**********************************************************************
386  simple wrapper function to see if winbindd is alive
387 **********************************************************************/
388
389 BOOL winbind_ping( void )
390 {
391         NSS_STATUS result;
392
393         result = winbindd_request(WINBINDD_PING, NULL, NULL);
394
395         return result == NSS_STATUS_SUCCESS;
396 }
397
398 /**********************************************************************
399  Ask winbindd to create a local user
400 **********************************************************************/
401
402 BOOL winbind_create_user( const char *name, uint32 *rid )
403 {
404         struct winbindd_request request;
405         struct winbindd_response response;
406         NSS_STATUS result;
407         
408         if ( !lp_winbind_enable_local_accounts() )
409                 return False;
410         
411         if ( !name )
412                 return False;
413                 
414         DEBUG(10,("winbind_create_user: %s\n", name));
415         
416         ZERO_STRUCT(request);
417         ZERO_STRUCT(response);
418         
419         /* see if the caller wants a new RID returned */
420         
421         if ( rid ) 
422                 request.flags = WBFLAG_ALLOCATE_RID;
423
424         fstrcpy( request.data.acct_mgt.username, name );
425         fstrcpy( request.data.acct_mgt.groupname, "" );
426         
427         result = winbindd_request( WINBINDD_CREATE_USER, &request, &response);
428         
429         if ( rid )
430                 *rid = response.data.rid;
431         
432         return result == NSS_STATUS_SUCCESS;
433 }
434
435 /**********************************************************************
436  Ask winbindd to create a local group
437 **********************************************************************/
438
439 BOOL winbind_create_group( const char *name, uint32 *rid )
440 {
441         struct winbindd_request request;
442         struct winbindd_response response;
443         NSS_STATUS result;
444         
445         if ( !lp_winbind_enable_local_accounts() )
446                 return False;
447                 
448         if ( !name )
449                 return False;
450                 
451         DEBUG(10,("winbind_create_group: %s\n", name));
452
453         ZERO_STRUCT(request);
454         ZERO_STRUCT(response);
455         
456         /* see if the caller wants a new RID returned */
457         
458         if ( rid ) 
459                 request.flags = WBFLAG_ALLOCATE_RID;
460                 
461         fstrcpy( request.data.acct_mgt.groupname, name );
462         
463         
464         result = winbindd_request( WINBINDD_CREATE_GROUP, &request, &response);
465         
466         if ( rid )
467                 *rid = response.data.rid;
468         
469         return result == NSS_STATUS_SUCCESS;
470 }
471
472 /**********************************************************************
473  Ask winbindd to add a user to a local group
474 **********************************************************************/
475
476 BOOL winbind_add_user_to_group( const char *user, const char *group )
477 {
478         struct winbindd_request request;
479         struct winbindd_response response;
480         NSS_STATUS result;
481         
482         if ( !lp_winbind_enable_local_accounts() )
483                 return False;
484                 
485         if ( !user || !group )
486                 return False;
487                 
488         ZERO_STRUCT(request);
489         ZERO_STRUCT(response);
490         
491         DEBUG(10,("winbind_add_user_to_group: user(%s), group(%s) \n", 
492                 user, group));
493                 
494         fstrcpy( request.data.acct_mgt.username, user );
495         fstrcpy( request.data.acct_mgt.groupname, group );
496         
497         result = winbindd_request( WINBINDD_ADD_USER_TO_GROUP, &request, &response);
498         
499         return result == NSS_STATUS_SUCCESS;
500 }
501
502 /**********************************************************************
503  Ask winbindd to remove a user to a local group
504 **********************************************************************/
505
506 BOOL winbind_remove_user_from_group( const char *user, const char *group )
507 {
508         struct winbindd_request request;
509         struct winbindd_response response;
510         NSS_STATUS result;
511         
512         if ( !lp_winbind_enable_local_accounts() )
513                 return False;
514                 
515         if ( !user || !group )
516                 return False;
517                 
518         ZERO_STRUCT(request);
519         ZERO_STRUCT(response);
520         
521         DEBUG(10,("winbind_remove_user_from_group: user(%s), group(%s) \n", 
522                 user, group));
523                 
524         ZERO_STRUCT(response);
525         
526         fstrcpy( request.data.acct_mgt.username, user );
527         fstrcpy( request.data.acct_mgt.groupname, group );
528         
529         result = winbindd_request( WINBINDD_REMOVE_USER_FROM_GROUP, &request, &response);
530         
531         return result == NSS_STATUS_SUCCESS;
532 }
533
534 /**********************************************************************
535  Ask winbindd to set the primary group for a user local user
536 **********************************************************************/
537
538 BOOL winbind_set_user_primary_group( const char *user, const char *group )
539 {
540         struct winbindd_request request;
541         struct winbindd_response response;
542         NSS_STATUS result;
543         
544         if ( !lp_winbind_enable_local_accounts() )
545                 return False;
546                 
547         if ( !user || !group )
548                 return False;
549                 
550         ZERO_STRUCT(request);
551         ZERO_STRUCT(response);
552         
553         DEBUG(10,("winbind_set_user_primary_group: user(%s), group(%s) \n", 
554                 user, group));
555
556         fstrcpy( request.data.acct_mgt.username, user );
557         fstrcpy( request.data.acct_mgt.groupname, group );
558         
559         result = winbindd_request( WINBINDD_SET_USER_PRIMARY_GROUP, &request, &response);
560         
561         return result == NSS_STATUS_SUCCESS;
562 }
563
564
565 /**********************************************************************
566  Ask winbindd to remove a user from its lists of accounts
567 **********************************************************************/
568
569 BOOL winbind_delete_user( const char *user )
570 {
571         struct winbindd_request request;
572         struct winbindd_response response;
573         NSS_STATUS result;
574         
575         if ( !lp_winbind_enable_local_accounts() )
576                 return False;
577                 
578         if ( !user )
579                 return False;
580                 
581         ZERO_STRUCT(request);
582         ZERO_STRUCT(response);
583         
584         DEBUG(10,("winbind_delete_user: user (%s)\n", user));
585
586         fstrcpy( request.data.acct_mgt.username, user );
587         
588         result = winbindd_request( WINBINDD_DELETE_USER, &request, &response);
589         
590         return result == NSS_STATUS_SUCCESS;
591 }
592
593 /**********************************************************************
594  Ask winbindd to remove a group from its lists of accounts
595 **********************************************************************/
596
597 BOOL winbind_delete_group( const char *group )
598 {
599         struct winbindd_request request;
600         struct winbindd_response response;
601         NSS_STATUS result;
602         
603         if ( !lp_winbind_enable_local_accounts() )
604                 return False;
605                 
606         if ( !group )
607                 return False;
608                 
609         ZERO_STRUCT(request);
610         ZERO_STRUCT(response);
611         
612         DEBUG(10,("winbind_delete_group: group (%s)\n", group));
613
614         fstrcpy( request.data.acct_mgt.groupname, group );
615         
616         result = winbindd_request( WINBINDD_DELETE_GROUP, &request, &response);
617         
618         return result == NSS_STATUS_SUCCESS;
619 }
620
621 /***********************************************************************/
622 /* Call winbindd to convert SID to uid. Do not allocate */
623
624 BOOL winbind_sid_to_uid_query(uid_t *puid, const DOM_SID *sid)
625 {
626         struct winbindd_request request;
627         struct winbindd_response response;
628         int result;
629         fstring sid_str;
630
631         if (!puid)
632                 return False;
633
634         /* Initialise request */
635
636         ZERO_STRUCT(request);
637         ZERO_STRUCT(response);
638
639         sid_to_string(sid_str, sid);
640         fstrcpy(request.data.sid, sid_str);
641
642         request.flags = WBFLAG_QUERY_ONLY;
643         
644         /* Make request */
645
646         result = winbindd_request(WINBINDD_SID_TO_UID, &request, &response);
647
648         /* Copy out result */
649
650         if (result == NSS_STATUS_SUCCESS) {
651                 *puid = response.data.uid;
652         }
653
654         return (result == NSS_STATUS_SUCCESS);
655 }
656
657 /* Call winbindd to convert SID to gid.  Do not allocate */
658
659 BOOL winbind_sid_to_gid_query(gid_t *pgid, const DOM_SID *sid)
660 {
661         struct winbindd_request request;
662         struct winbindd_response response;
663         int result;
664         fstring sid_str;
665
666         if (!pgid)
667                 return False;
668
669         /* Initialise request */
670
671         ZERO_STRUCT(request);
672         ZERO_STRUCT(response);
673
674         sid_to_string(sid_str, sid);
675         fstrcpy(request.data.sid, sid_str);
676         
677         request.flags = WBFLAG_QUERY_ONLY;
678
679         /* Make request */
680
681         result = winbindd_request(WINBINDD_SID_TO_GID, &request, &response);
682
683         /* Copy out result */
684
685         if (result == NSS_STATUS_SUCCESS) {
686                 *pgid = response.data.gid;
687         }
688
689         return (result == NSS_STATUS_SUCCESS);
690 }
691
692 /***********************************************************************/
693