Changes from APPLIANCE_HEAD:
[samba.git] / source3 / nsswitch / wb_client.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 2.0
4
5    winbind client code
6
7    Copyright (C) Tim Potter 2000
8    Copyright (C) Andrew Tridgell 2000
9    
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Library General Public
12    License as published by the Free Software Foundation; either
13    version 2 of the License, or (at your option) any later version.
14    
15    This library is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    Library General Public License for more details.
19    
20    You should have received a copy of the GNU Library General Public
21    License along with this library; if not, write to the
22    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23    Boston, MA  02111-1307, USA.   
24 */
25
26 #include "includes.h"
27
28 /* Call winbindd to convert a name to a sid */
29
30 BOOL winbind_lookup_name(char *name, DOM_SID *sid, enum SID_NAME_USE *name_type)
31 {
32         struct winbindd_request request;
33         struct winbindd_response response;
34         enum nss_status result;
35         
36         if (!sid || !name_type)
37                 return False;
38
39         /* Send off request */
40
41         ZERO_STRUCT(request);
42         ZERO_STRUCT(response);
43
44         fstrcpy(request.data.name, name);
45         if ((result = winbindd_request(WINBINDD_LOOKUPNAME, &request, 
46                                        &response)) == NSS_STATUS_SUCCESS) {
47                 string_to_sid(sid, response.data.sid.sid);
48                 *name_type = (enum SID_NAME_USE)response.data.sid.type;
49         }
50
51         return result == NSS_STATUS_SUCCESS;
52 }
53
54 /* Call winbindd to convert sid to name */
55
56 BOOL winbind_lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE *name_type)
57 {
58         struct winbindd_request request;
59         struct winbindd_response response;
60         enum nss_status result;
61         fstring sid_str;
62         
63         /* Initialise request */
64
65         ZERO_STRUCT(request);
66         ZERO_STRUCT(response);
67
68         sid_to_string(sid_str, sid);
69         fstrcpy(request.data.sid, sid_str);
70         
71         /* Make request */
72
73         result = winbindd_request(WINBINDD_LOOKUPSID, &request, &response);
74
75         /* Copy out result */
76
77         if (result == NSS_STATUS_SUCCESS) {
78                 parse_domain_user(response.data.name.name, dom_name, name);
79                 *name_type = (enum SID_NAME_USE)response.data.name.type;
80                 DEBUG(10,("winbind_lookup_sid: SUCCESS: SID %s -> %s %s\n", sid_str, dom_name, name ));
81         }
82
83         return (result == NSS_STATUS_SUCCESS);
84 }
85
86 /* Call winbindd to convert SID to uid */
87
88 BOOL winbind_sid_to_uid(uid_t *puid, DOM_SID *sid)
89 {
90         struct winbindd_request request;
91         struct winbindd_response response;
92         int result;
93         fstring sid_str;
94
95         if (!puid)
96                 return False;
97
98         /* Initialise request */
99
100         ZERO_STRUCT(request);
101         ZERO_STRUCT(response);
102
103         sid_to_string(sid_str, sid);
104         fstrcpy(request.data.sid, sid_str);
105         
106         /* Make request */
107
108         result = winbindd_request(WINBINDD_SID_TO_UID, &request, &response);
109
110         /* Copy out result */
111
112         if (result == NSS_STATUS_SUCCESS) {
113                 *puid = response.data.uid;
114         }
115
116         return (result == NSS_STATUS_SUCCESS);
117 }
118
119 /* Call winbindd to convert uid to sid */
120
121 BOOL winbind_uid_to_sid(DOM_SID *sid, uid_t uid)
122 {
123         struct winbindd_request request;
124         struct winbindd_response response;
125         int result;
126
127         if (!sid)
128                 return False;
129
130         /* Initialise request */
131
132         ZERO_STRUCT(request);
133         ZERO_STRUCT(response);
134
135         request.data.uid = uid;
136
137         /* Make request */
138
139         result = winbindd_request(WINBINDD_UID_TO_SID, &request, &response);
140
141         /* Copy out result */
142
143         if (result == NSS_STATUS_SUCCESS) {
144                 string_to_sid(sid, response.data.sid.sid);
145         } else {
146                 sid_copy(sid, &global_sid_NULL);
147         }
148
149         return (result == NSS_STATUS_SUCCESS);
150 }
151
152 /* Call winbindd to convert SID to gid */
153
154 BOOL winbind_sid_to_gid(gid_t *pgid, DOM_SID *sid)
155 {
156         struct winbindd_request request;
157         struct winbindd_response response;
158         int result;
159         fstring sid_str;
160
161         if (!pgid)
162                 return False;
163
164         /* Initialise request */
165
166         ZERO_STRUCT(request);
167         ZERO_STRUCT(response);
168
169         sid_to_string(sid_str, sid);
170         fstrcpy(request.data.sid, sid_str);
171         
172         /* Make request */
173
174         result = winbindd_request(WINBINDD_SID_TO_UID, &request, &response);
175
176         /* Copy out result */
177
178         if (result == NSS_STATUS_SUCCESS) {
179                 *pgid = response.data.gid;
180         }
181
182         return (result == NSS_STATUS_SUCCESS);
183 }
184
185 /* Call winbindd to convert gid to sid */
186
187 BOOL winbind_gid_to_sid(DOM_SID *sid, gid_t gid)
188 {
189         struct winbindd_request request;
190         struct winbindd_response response;
191         int result;
192
193         if (!sid)
194                 return False;
195
196         /* Initialise request */
197
198         ZERO_STRUCT(request);
199         ZERO_STRUCT(response);
200
201         request.data.gid = gid;
202
203         /* Make request */
204
205         result = winbindd_request(WINBINDD_GID_TO_SID, &request, &response);
206
207         /* Copy out result */
208
209         if (result == NSS_STATUS_SUCCESS) {
210                 string_to_sid(sid, response.data.sid.sid);
211         } else {
212                 sid_copy(sid, &global_sid_NULL);
213         }
214
215         return (result == NSS_STATUS_SUCCESS);
216 }
217
218 /* Fetch the list of groups a user is a member of from winbindd.  This is
219    used by winbind_initgroups and winbind_getgroups. */
220
221 static int wb_getgroups(char *user, gid_t **groups)
222 {
223         struct winbindd_request request;
224         struct winbindd_response response;
225         int result;
226
227         /* Call winbindd */
228
229         fstrcpy(request.data.username, user);
230
231         ZERO_STRUCT(response);
232
233         result = winbindd_request(WINBINDD_GETGROUPS, &request, &response);
234
235         if (result == NSS_STATUS_SUCCESS) {
236                 
237                 /* Return group list.  Don't forget to free the group list
238                    when finished. */
239
240                 *groups = (gid_t *)response.extra_data;
241                 return response.data.num_entries;
242         }
243
244         return -1;
245 }
246
247 /* Call winbindd to initialise group membership.  This is necessary for
248    some systems (i.e RH5.2) that do not have an initgroups function as part
249    of the nss extension.  In RH5.2 this is implemented using getgrent()
250    which can be amazingly inefficient as well as having problems with
251    username case. */
252
253 int winbind_initgroups(char *user, gid_t gid)
254 {
255         gid_t *groups = NULL;
256         int result;
257         char *sep;
258
259         /* Call normal initgroups if we are a local user */
260
261         sep = lp_winbind_separator();
262
263         if (!strchr(user, *sep)) {
264                 return initgroups(user, gid);
265         }
266
267         result = wb_getgroups(user, &groups);
268
269         DEBUG(10,("winbind_getgroups: %s: result = %s\n", user, 
270                   result == -1 ? "FAIL" : "SUCCESS"));
271
272         if (result != -1) {
273                 int ngroups = result, i;
274                 BOOL is_member = False;
275
276                 /* Check to see if the passed gid is already in the list */
277
278                 for (i = 0; i < ngroups; i++) {
279                         if (groups[i] == gid) {
280                                 is_member = True;
281                         }
282                 }
283
284                 /* Add group to list if necessary */
285
286                 if (!is_member) {
287                         groups = Realloc(groups, sizeof(gid_t) * ngroups + 1);
288                         
289                         if (!groups) {
290                                 errno = ENOMEM;
291                                 result = -1;
292                                 goto done;
293                         }
294
295                         groups[ngroups] = gid;
296                         ngroups++;
297                 }
298
299                 /* Set the groups */
300
301                 if (sys_setgroups(ngroups, groups) == -1) {
302                         errno = EPERM;
303                         result = -1;
304                         goto done;
305                 }
306
307         } else {
308                 
309                 /* The call failed.  Set errno to something so we don't get
310                    a bogus value from the last failed system call. */
311
312                 errno = EIO;
313         }
314
315         /* Free response data if necessary */
316
317  done:
318         safe_free(groups);
319
320         return result;
321 }
322
323 /* Return a list of groups the user is a member of.  This function is
324    useful for large systems where inverting the group database would be too
325    time consuming.  If size is zero, list is not modified and the total
326    number of groups for the user is returned. */
327
328 int winbind_getgroups(char *user, int size, gid_t *list)
329 {
330         gid_t *groups = NULL;
331         int result, i;
332
333         /* Fetch list of groups */
334
335         result = wb_getgroups(user, &groups);
336
337         if (size == 0) goto done;
338
339         if (result > size) {
340                 result = -1;
341                 errno = EINVAL; /* This is what getgroups() does */
342                 goto done;
343         }
344
345         /* Copy list of groups across */
346
347         for (i = 0; i < result; i++) {
348                 list[i] = groups[i];
349         }
350
351  done:
352         safe_free(groups);
353         return result;
354 }
355
356 /**********************************************************************************
357  Utility function. Convert a uid_t to a name if possible.
358 **********************************************************************************/
359
360 BOOL winbind_uidtoname(fstring name, uid_t uid)
361 {
362         DOM_SID sid;
363         fstring dom_name;
364         fstring user_name;
365         enum SID_NAME_USE name_type;
366
367         if (!winbind_uid_to_sid(&sid, uid))
368                 return False;
369         if (!winbind_lookup_sid(&sid, dom_name, user_name, &name_type))
370                 return False;
371
372         if (name_type != SID_NAME_USER)
373                 return False;
374
375         slprintf(name, sizeof(fstring)-1, "%s%s%s", dom_name, lp_winbind_separator(), user_name );
376         return True;
377 }
378
379 /**********************************************************************************
380  Utility function. Convert a gid_t to a name if possible.
381 **********************************************************************************/
382
383 BOOL winbind_gidtoname(fstring name, gid_t gid)
384 {
385         DOM_SID sid;
386         fstring dom_name;
387         fstring group_name;
388         enum SID_NAME_USE name_type;
389
390         if (!winbind_gid_to_sid(&sid, gid))
391                 return False;
392         if (!winbind_lookup_sid(&sid, dom_name, group_name, &name_type))
393                 return False;
394
395         if (name_type != SID_NAME_USER)
396                 return False;
397
398         slprintf(name, sizeof(fstring)-1, "%s%s%s", dom_name, lp_winbind_separator(), group_name );
399         return True;
400 }
401
402 /**********************************************************************************
403  Utility function. Convert a name to a uid_t if possible.
404 **********************************************************************************/
405
406 BOOL winbind_nametouid(uid_t *puid, char *name)
407 {
408         DOM_SID sid;
409         enum SID_NAME_USE name_type;
410
411         if (!winbind_lookup_name(name, &sid, &name_type)) {
412         return False;
413     }
414
415         if (name_type != SID_NAME_USER)
416                 return False;
417
418         return winbind_sid_to_uid(puid, &sid);
419 }
420
421 /**********************************************************************************
422  Utility function. Convert a name to a gid_t if possible.
423 **********************************************************************************/
424
425 BOOL winbind_nametogid(gid_t *pgid, char *gname)
426 {
427         DOM_SID g_sid;
428         enum SID_NAME_USE name_type;
429
430         if (!winbind_lookup_name(gname, &g_sid, &name_type)) {
431         return False;
432     }
433
434         if (name_type != SID_NAME_DOM_GRP)
435                 return False;
436
437         return winbind_sid_to_gid(pgid, &g_sid);
438 }