a1c71becf03d47700d6c34140441e2e3bcdb8352
[tprouty/samba.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         ZERO_STRUCT(request);
274         fstrcpy(request.data.username, user);
275
276         ZERO_STRUCT(response);
277
278         result = winbindd_request(WINBINDD_GETGROUPS, &request, &response);
279
280         if (result == NSS_STATUS_SUCCESS) {
281                 
282                 /* Return group list.  Don't forget to free the group list
283                    when finished. */
284
285                 *groups = (gid_t *)response.extra_data;
286                 return response.data.num_entries;
287         }
288
289         return -1;
290 }
291
292 /* Call winbindd to initialise group membership.  This is necessary for
293    some systems (i.e RH5.2) that do not have an initgroups function as part
294    of the nss extension.  In RH5.2 this is implemented using getgrent()
295    which can be amazingly inefficient as well as having problems with
296    username case. */
297
298 int winbind_initgroups(char *user, gid_t gid)
299 {
300         gid_t *tgr, *groups = NULL;
301         int result;
302
303         /* Call normal initgroups if we are a local user */
304
305         if (!strchr(user, *lp_winbind_separator())) {
306                 return initgroups(user, gid);
307         }
308
309         result = wb_getgroups(user, &groups);
310
311         DEBUG(10,("winbind_getgroups: %s: result = %s\n", user, 
312                   result == -1 ? "FAIL" : "SUCCESS"));
313
314         if (result != -1) {
315                 int ngroups = result, i;
316                 BOOL is_member = False;
317
318                 /* Check to see if the passed gid is already in the list */
319
320                 for (i = 0; i < ngroups; i++) {
321                         if (groups[i] == gid) {
322                                 is_member = True;
323                         }
324                 }
325
326                 /* Add group to list if necessary */
327
328                 if (!is_member) {
329                         tgr = (gid_t *)Realloc(groups, sizeof(gid_t) * ngroups + 1);
330                         
331                         if (!tgr) {
332                                 errno = ENOMEM;
333                                 result = -1;
334                                 goto done;
335                         }
336                         else groups = tgr;
337
338                         groups[ngroups] = gid;
339                         ngroups++;
340                 }
341
342                 /* Set the groups */
343
344                 if (sys_setgroups(ngroups, groups) == -1) {
345                         errno = EPERM;
346                         result = -1;
347                         goto done;
348                 }
349
350         } else {
351                 
352                 /* The call failed.  Set errno to something so we don't get
353                    a bogus value from the last failed system call. */
354
355                 errno = EIO;
356         }
357
358         /* Free response data if necessary */
359
360  done:
361         SAFE_FREE(groups);
362
363         return result;
364 }
365
366 /* Return a list of groups the user is a member of.  This function is
367    useful for large systems where inverting the group database would be too
368    time consuming.  If size is zero, list is not modified and the total
369    number of groups for the user is returned. */
370
371 int winbind_getgroups(const char *user, gid_t **list)
372 {
373         /*
374          * Don't do the lookup if the name has no separator _and_ we are not in
375          * 'winbind use default domain' mode.
376          */
377
378         if (!(strchr(user, *lp_winbind_separator()) || lp_winbind_use_default_domain()))
379                 return -1;
380
381         /* Fetch list of groups */
382
383         return wb_getgroups(user, list);
384 }
385
386 /**********************************************************************
387  simple wrapper function to see if winbindd is alive
388 **********************************************************************/
389
390 BOOL winbind_ping( void )
391 {
392         NSS_STATUS result;
393
394         result = winbindd_request(WINBINDD_PING, NULL, NULL);
395
396         return result == NSS_STATUS_SUCCESS;
397 }
398
399 /**********************************************************************
400  Ask winbindd to create a local user
401 **********************************************************************/
402
403 BOOL winbind_create_user( const char *name, uint32 *rid )
404 {
405         struct winbindd_request request;
406         struct winbindd_response response;
407         NSS_STATUS result;
408         
409         if ( !lp_winbind_enable_local_accounts() )
410                 return False;
411         
412         if ( !name )
413                 return False;
414                 
415         DEBUG(10,("winbind_create_user: %s\n", name));
416         
417         ZERO_STRUCT(request);
418         ZERO_STRUCT(response);
419         
420         /* see if the caller wants a new RID returned */
421         
422         if ( rid ) 
423                 request.flags = WBFLAG_ALLOCATE_RID;
424
425         fstrcpy( request.data.acct_mgt.username, name );
426         fstrcpy( request.data.acct_mgt.groupname, "" );
427         
428         result = winbindd_request( WINBINDD_CREATE_USER, &request, &response);
429         
430         if ( rid )
431                 *rid = response.data.rid;
432         
433         return result == NSS_STATUS_SUCCESS;
434 }
435
436 /**********************************************************************
437  Ask winbindd to create a local group
438 **********************************************************************/
439
440 BOOL winbind_create_group( const char *name, uint32 *rid )
441 {
442         struct winbindd_request request;
443         struct winbindd_response response;
444         NSS_STATUS result;
445         
446         if ( !lp_winbind_enable_local_accounts() )
447                 return False;
448                 
449         if ( !name )
450                 return False;
451                 
452         DEBUG(10,("winbind_create_group: %s\n", name));
453
454         ZERO_STRUCT(request);
455         ZERO_STRUCT(response);
456         
457         /* see if the caller wants a new RID returned */
458         
459         if ( rid ) 
460                 request.flags = WBFLAG_ALLOCATE_RID;
461                 
462         fstrcpy( request.data.acct_mgt.groupname, name );
463         
464         
465         result = winbindd_request( WINBINDD_CREATE_GROUP, &request, &response);
466         
467         if ( rid )
468                 *rid = response.data.rid;
469         
470         return result == NSS_STATUS_SUCCESS;
471 }
472
473 /**********************************************************************
474  Ask winbindd to add a user to a local group
475 **********************************************************************/
476
477 BOOL winbind_add_user_to_group( const char *user, const char *group )
478 {
479         struct winbindd_request request;
480         struct winbindd_response response;
481         NSS_STATUS result;
482         
483         if ( !lp_winbind_enable_local_accounts() )
484                 return False;
485                 
486         if ( !user || !group )
487                 return False;
488                 
489         ZERO_STRUCT(request);
490         ZERO_STRUCT(response);
491         
492         DEBUG(10,("winbind_add_user_to_group: user(%s), group(%s) \n", 
493                 user, group));
494                 
495         fstrcpy( request.data.acct_mgt.username, user );
496         fstrcpy( request.data.acct_mgt.groupname, group );
497         
498         result = winbindd_request( WINBINDD_ADD_USER_TO_GROUP, &request, &response);
499         
500         return result == NSS_STATUS_SUCCESS;
501 }
502
503 /**********************************************************************
504  Ask winbindd to remove a user to a local group
505 **********************************************************************/
506
507 BOOL winbind_remove_user_from_group( const char *user, const char *group )
508 {
509         struct winbindd_request request;
510         struct winbindd_response response;
511         NSS_STATUS result;
512         
513         if ( !lp_winbind_enable_local_accounts() )
514                 return False;
515                 
516         if ( !user || !group )
517                 return False;
518                 
519         ZERO_STRUCT(request);
520         ZERO_STRUCT(response);
521         
522         DEBUG(10,("winbind_remove_user_from_group: user(%s), group(%s) \n", 
523                 user, group));
524                 
525         ZERO_STRUCT(response);
526         
527         fstrcpy( request.data.acct_mgt.username, user );
528         fstrcpy( request.data.acct_mgt.groupname, group );
529         
530         result = winbindd_request( WINBINDD_REMOVE_USER_FROM_GROUP, &request, &response);
531         
532         return result == NSS_STATUS_SUCCESS;
533 }
534
535 /**********************************************************************
536  Ask winbindd to set the primary group for a user local user
537 **********************************************************************/
538
539 BOOL winbind_set_user_primary_group( const char *user, const char *group )
540 {
541         struct winbindd_request request;
542         struct winbindd_response response;
543         NSS_STATUS result;
544         
545         if ( !lp_winbind_enable_local_accounts() )
546                 return False;
547                 
548         if ( !user || !group )
549                 return False;
550                 
551         ZERO_STRUCT(request);
552         ZERO_STRUCT(response);
553         
554         DEBUG(10,("winbind_set_user_primary_group: user(%s), group(%s) \n", 
555                 user, group));
556
557         fstrcpy( request.data.acct_mgt.username, user );
558         fstrcpy( request.data.acct_mgt.groupname, group );
559         
560         result = winbindd_request( WINBINDD_SET_USER_PRIMARY_GROUP, &request, &response);
561         
562         return result == NSS_STATUS_SUCCESS;
563 }
564
565
566 /**********************************************************************
567  Ask winbindd to remove a user from its lists of accounts
568 **********************************************************************/
569
570 BOOL winbind_delete_user( const char *user )
571 {
572         struct winbindd_request request;
573         struct winbindd_response response;
574         NSS_STATUS result;
575         
576         if ( !lp_winbind_enable_local_accounts() )
577                 return False;
578                 
579         if ( !user )
580                 return False;
581                 
582         ZERO_STRUCT(request);
583         ZERO_STRUCT(response);
584         
585         DEBUG(10,("winbind_delete_user: user (%s)\n", user));
586
587         fstrcpy( request.data.acct_mgt.username, user );
588         
589         result = winbindd_request( WINBINDD_DELETE_USER, &request, &response);
590         
591         return result == NSS_STATUS_SUCCESS;
592 }
593
594 /**********************************************************************
595  Ask winbindd to remove a group from its lists of accounts
596 **********************************************************************/
597
598 BOOL winbind_delete_group( const char *group )
599 {
600         struct winbindd_request request;
601         struct winbindd_response response;
602         NSS_STATUS result;
603         
604         if ( !lp_winbind_enable_local_accounts() )
605                 return False;
606                 
607         if ( !group )
608                 return False;
609                 
610         ZERO_STRUCT(request);
611         ZERO_STRUCT(response);
612         
613         DEBUG(10,("winbind_delete_group: group (%s)\n", group));
614
615         fstrcpy( request.data.acct_mgt.groupname, group );
616         
617         result = winbindd_request( WINBINDD_DELETE_GROUP, &request, &response);
618         
619         return result == NSS_STATUS_SUCCESS;
620 }
621
622 /***********************************************************************/
623 #if 0   /* not needed currently since winbindd_acct was added -- jerry */
624
625 /* Call winbindd to convert SID to uid. Do not allocate */
626
627 BOOL winbind_sid_to_uid_query(uid_t *puid, const DOM_SID *sid)
628 {
629         struct winbindd_request request;
630         struct winbindd_response response;
631         int result;
632         fstring sid_str;
633
634         if (!puid)
635                 return False;
636
637         /* Initialise request */
638
639         ZERO_STRUCT(request);
640         ZERO_STRUCT(response);
641
642         sid_to_string(sid_str, sid);
643         fstrcpy(request.data.sid, sid_str);
644
645         request.flags = WBFLAG_QUERY_ONLY;
646         
647         /* Make request */
648
649         result = winbindd_request(WINBINDD_SID_TO_UID, &request, &response);
650
651         /* Copy out result */
652
653         if (result == NSS_STATUS_SUCCESS) {
654                 *puid = response.data.uid;
655         }
656
657         return (result == NSS_STATUS_SUCCESS);
658 }
659
660 /* Call winbindd to convert SID to gid.  Do not allocate */
661
662 BOOL winbind_sid_to_gid_query(gid_t *pgid, const DOM_SID *sid)
663 {
664         struct winbindd_request request;
665         struct winbindd_response response;
666         int result;
667         fstring sid_str;
668
669         if (!pgid)
670                 return False;
671
672         /* Initialise request */
673
674         ZERO_STRUCT(request);
675         ZERO_STRUCT(response);
676
677         sid_to_string(sid_str, sid);
678         fstrcpy(request.data.sid, sid_str);
679         
680         request.flags = WBFLAG_QUERY_ONLY;
681
682         /* Make request */
683
684         result = winbindd_request(WINBINDD_SID_TO_GID, &request, &response);
685
686         /* Copy out result */
687
688         if (result == NSS_STATUS_SUCCESS) {
689                 *pgid = response.data.gid;
690         }
691
692         return (result == NSS_STATUS_SUCCESS);
693 }
694
695 #endif  /* JERRY */
696
697 /***********************************************************************/
698