Changes from APPLIANCE_HEAD:
[ira/wip.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,("wb_getgroups: %s: result = %s\n", user, result == -1 ?
270                   "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
308         /* Free response data if necessary */
309
310  done:
311         safe_free(groups);
312
313         return result;
314 }
315
316 /* Return a list of groups the user is a member of.  This function is
317    useful for large systems where inverting the group database would be too
318    time consuming.  If size is zero, list is not modified and the total
319    number of groups for the user is returned. */
320
321 int winbind_getgroups(char *user, int size, gid_t *list)
322 {
323         gid_t *groups = NULL;
324         int result, i;
325
326         /* Fetch list of groups */
327
328         result = wb_getgroups(user, &groups);
329
330         if (size == 0) goto done;
331
332         if (result > size) {
333                 result = -1;
334                 errno = EINVAL; /* This is what getgroups() does */
335                 goto done;
336         }
337
338         /* Copy list of groups across */
339
340         for (i = 0; i < result; i++) {
341                 list[i] = groups[i];
342         }
343
344  done:
345         safe_free(groups);
346         return result;
347 }
348
349 /**********************************************************************************
350  Utility function. Convert a uid_t to a name if possible.
351 **********************************************************************************/
352
353 BOOL winbind_uidtoname(fstring name, uid_t uid)
354 {
355         DOM_SID sid;
356         fstring dom_name;
357         fstring user_name;
358         enum SID_NAME_USE name_type;
359
360         if (!winbind_uid_to_sid(&sid, uid))
361                 return False;
362         if (!winbind_lookup_sid(&sid, dom_name, user_name, &name_type))
363                 return False;
364
365         if (name_type != SID_NAME_USER)
366                 return False;
367
368         slprintf(name, sizeof(fstring)-1, "%s%s%s", dom_name, lp_winbind_separator(), user_name );
369         return True;
370 }
371
372 /**********************************************************************************
373  Utility function. Convert a gid_t to a name if possible.
374 **********************************************************************************/
375
376 BOOL winbind_gidtoname(fstring name, gid_t gid)
377 {
378         DOM_SID sid;
379         fstring dom_name;
380         fstring group_name;
381         enum SID_NAME_USE name_type;
382
383         if (!winbind_gid_to_sid(&sid, gid))
384                 return False;
385         if (!winbind_lookup_sid(&sid, dom_name, group_name, &name_type))
386                 return False;
387
388         if (name_type != SID_NAME_USER)
389                 return False;
390
391         slprintf(name, sizeof(fstring)-1, "%s%s%s", dom_name, lp_winbind_separator(), group_name );
392         return True;
393 }
394
395 /**********************************************************************************
396  Utility function. Convert a name to a uid_t if possible.
397 **********************************************************************************/
398
399 BOOL winbind_nametouid(uid_t *puid, char *name)
400 {
401         DOM_SID sid;
402         enum SID_NAME_USE name_type;
403
404         if (!winbind_lookup_name(name, &sid, &name_type)) {
405         return False;
406     }
407
408         if (name_type != SID_NAME_USER)
409                 return False;
410
411         return winbind_sid_to_uid(puid, &sid);
412 }
413
414 /**********************************************************************************
415  Utility function. Convert a name to a gid_t if possible.
416 **********************************************************************************/
417
418 BOOL winbind_nametogid(gid_t *pgid, char *gname)
419 {
420         DOM_SID g_sid;
421         enum SID_NAME_USE name_type;
422
423         if (!winbind_lookup_name(gname, &g_sid, &name_type)) {
424         return False;
425     }
426
427         if (name_type != SID_NAME_DOM_GRP)
428                 return False;
429
430         return winbind_sid_to_gid(pgid, &g_sid);
431 }