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