7bfa65176c7f81e008c9d35e7621463c30164a0e
[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 #include "nsswitch/nss.h"
28
29 NSS_STATUS winbindd_request(int req_type,
30                                  struct winbindd_request *request,
31                                  struct winbindd_response *response);
32
33 /* Copy of parse_domain_user from winbindd_util.c.  Parse a string of the
34    form DOMAIN/user into a domain and a user */
35
36 static BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
37 {
38         char *p = strchr(domuser,*lp_winbind_separator());
39
40         if (!p)
41                 return False;
42         
43         fstrcpy(user, p+1);
44         fstrcpy(domain, domuser);
45         domain[PTR_DIFF(p, domuser)] = 0;
46         strupper(domain);
47         return True;
48 }
49
50 /* Call winbindd to convert a name to a sid */
51
52 BOOL winbind_lookup_name(const char *name, DOM_SID *sid, 
53                          enum SID_NAME_USE *name_type)
54 {
55         struct winbindd_request request;
56         struct winbindd_response response;
57         NSS_STATUS result;
58         
59         if (!sid || !name_type)
60                 return False;
61
62         /*
63          * Don't do the lookup if the name has no separator.
64          */
65
66         if (!strchr(name, *lp_winbind_separator()))
67                 return False;
68
69         /* Send off request */
70
71         ZERO_STRUCT(request);
72         ZERO_STRUCT(response);
73
74         fstrcpy(request.data.name, name);
75
76         if ((result = winbindd_request(WINBINDD_LOOKUPNAME, &request, 
77                                        &response)) == NSS_STATUS_SUCCESS) {
78                 string_to_sid(sid, response.data.sid.sid);
79                 *name_type = (enum SID_NAME_USE)response.data.sid.type;
80         }
81
82         return result == NSS_STATUS_SUCCESS;
83 }
84
85 /* Call winbindd to convert sid to name */
86
87 BOOL winbind_lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, 
88                         enum SID_NAME_USE *name_type)
89 {
90         struct winbindd_request request;
91         struct winbindd_response response;
92         NSS_STATUS result;
93         fstring sid_str;
94         
95         /* Initialise request */
96
97         ZERO_STRUCT(request);
98         ZERO_STRUCT(response);
99
100         sid_to_string(sid_str, sid);
101         fstrcpy(request.data.sid, sid_str);
102         
103         /* Make request */
104
105         result = winbindd_request(WINBINDD_LOOKUPSID, &request, &response);
106
107         /* Copy out result */
108
109         if (result == NSS_STATUS_SUCCESS) {
110                 parse_domain_user(response.data.name.name, dom_name, name);
111                 *name_type = (enum SID_NAME_USE)response.data.name.type;
112
113                 DEBUG(10, ("winbind_lookup_sid: SUCCESS: SID %s -> %s %s\n", 
114                            sid_str, dom_name, name));
115         }
116
117         return (result == NSS_STATUS_SUCCESS);
118 }
119
120 /* Call winbindd to convert SID to uid */
121
122 BOOL winbind_sid_to_uid(uid_t *puid, DOM_SID *sid)
123 {
124         struct winbindd_request request;
125         struct winbindd_response response;
126         int result;
127         fstring sid_str;
128
129         if (!puid)
130                 return False;
131
132         /* Initialise request */
133
134         ZERO_STRUCT(request);
135         ZERO_STRUCT(response);
136
137         sid_to_string(sid_str, sid);
138         fstrcpy(request.data.sid, sid_str);
139         
140         /* Make request */
141
142         result = winbindd_request(WINBINDD_SID_TO_UID, &request, &response);
143
144         /* Copy out result */
145
146         if (result == NSS_STATUS_SUCCESS) {
147                 *puid = response.data.uid;
148         }
149
150         return (result == NSS_STATUS_SUCCESS);
151 }
152
153 /* Call winbindd to convert uid to sid */
154
155 BOOL winbind_uid_to_sid(DOM_SID *sid, uid_t uid)
156 {
157         struct winbindd_request request;
158         struct winbindd_response response;
159         int result;
160
161         if (!sid)
162                 return False;
163
164         /* Initialise request */
165
166         ZERO_STRUCT(request);
167         ZERO_STRUCT(response);
168
169         request.data.uid = uid;
170
171         /* Make request */
172
173         result = winbindd_request(WINBINDD_UID_TO_SID, &request, &response);
174
175         /* Copy out result */
176
177         if (result == NSS_STATUS_SUCCESS) {
178                 string_to_sid(sid, response.data.sid.sid);
179         } else {
180                 sid_copy(sid, &global_sid_NULL);
181         }
182
183         return (result == NSS_STATUS_SUCCESS);
184 }
185
186 /* Call winbindd to convert SID to gid */
187
188 BOOL winbind_sid_to_gid(gid_t *pgid, DOM_SID *sid)
189 {
190         struct winbindd_request request;
191         struct winbindd_response response;
192         int result;
193         fstring sid_str;
194
195         if (!pgid)
196                 return False;
197
198         /* Initialise request */
199
200         ZERO_STRUCT(request);
201         ZERO_STRUCT(response);
202
203         sid_to_string(sid_str, sid);
204         fstrcpy(request.data.sid, sid_str);
205         
206         /* Make request */
207
208         result = winbindd_request(WINBINDD_SID_TO_GID, &request, &response);
209
210         /* Copy out result */
211
212         if (result == NSS_STATUS_SUCCESS) {
213                 *pgid = response.data.gid;
214         }
215
216         return (result == NSS_STATUS_SUCCESS);
217 }
218
219 /* Call winbindd to convert gid to sid */
220
221 BOOL winbind_gid_to_sid(DOM_SID *sid, gid_t gid)
222 {
223         struct winbindd_request request;
224         struct winbindd_response response;
225         int result;
226
227         if (!sid)
228                 return False;
229
230         /* Initialise request */
231
232         ZERO_STRUCT(request);
233         ZERO_STRUCT(response);
234
235         request.data.gid = gid;
236
237         /* Make request */
238
239         result = winbindd_request(WINBINDD_GID_TO_SID, &request, &response);
240
241         /* Copy out result */
242
243         if (result == NSS_STATUS_SUCCESS) {
244                 string_to_sid(sid, response.data.sid.sid);
245         } else {
246                 sid_copy(sid, &global_sid_NULL);
247         }
248
249         return (result == NSS_STATUS_SUCCESS);
250 }
251
252 /* Fetch the list of groups a user is a member of from winbindd.  This is
253    used by winbind_initgroups and winbind_getgroups. */
254
255 static int wb_getgroups(const char *user, gid_t **groups)
256 {
257         struct winbindd_request request;
258         struct winbindd_response response;
259         int result;
260
261         /* Call winbindd */
262
263         fstrcpy(request.data.username, user);
264
265         ZERO_STRUCT(response);
266
267         result = winbindd_request(WINBINDD_GETGROUPS, &request, &response);
268
269         if (result == NSS_STATUS_SUCCESS) {
270                 
271                 /* Return group list.  Don't forget to free the group list
272                    when finished. */
273
274                 *groups = (gid_t *)response.extra_data;
275                 return response.data.num_entries;
276         }
277
278         return -1;
279 }
280
281 /* Call winbindd to initialise group membership.  This is necessary for
282    some systems (i.e RH5.2) that do not have an initgroups function as part
283    of the nss extension.  In RH5.2 this is implemented using getgrent()
284    which can be amazingly inefficient as well as having problems with
285    username case. */
286
287 int winbind_initgroups(char *user, gid_t gid)
288 {
289         gid_t *tgr, *groups = NULL;
290         int result;
291
292         /* Call normal initgroups if we are a local user */
293
294         if (!strchr(user, *lp_winbind_separator())) {
295                 return initgroups(user, gid);
296         }
297
298         result = wb_getgroups(user, &groups);
299
300         DEBUG(10,("winbind_getgroups: %s: result = %s\n", user, 
301                   result == -1 ? "FAIL" : "SUCCESS"));
302
303         if (result != -1) {
304                 int ngroups = result, i;
305                 BOOL is_member = False;
306
307                 /* Check to see if the passed gid is already in the list */
308
309                 for (i = 0; i < ngroups; i++) {
310                         if (groups[i] == gid) {
311                                 is_member = True;
312                         }
313                 }
314
315                 /* Add group to list if necessary */
316
317                 if (!is_member) {
318                         tgr = (gid_t *)Realloc(groups, sizeof(gid_t) * ngroups + 1);
319                         
320                         if (!tgr) {
321                                 errno = ENOMEM;
322                                 result = -1;
323                                 goto done;
324                         }
325                         else groups = tgr;
326
327                         groups[ngroups] = gid;
328                         ngroups++;
329                 }
330
331                 /* Set the groups */
332
333                 if (sys_setgroups(ngroups, groups) == -1) {
334                         errno = EPERM;
335                         result = -1;
336                         goto done;
337                 }
338
339         } else {
340                 
341                 /* The call failed.  Set errno to something so we don't get
342                    a bogus value from the last failed system call. */
343
344                 errno = EIO;
345         }
346
347         /* Free response data if necessary */
348
349  done:
350         SAFE_FREE(groups);
351
352         return result;
353 }
354
355 /* Return a list of groups the user is a member of.  This function is
356    useful for large systems where inverting the group database would be too
357    time consuming.  If size is zero, list is not modified and the total
358    number of groups for the user is returned. */
359
360 int winbind_getgroups(const char *user, int size, gid_t *list)
361 {
362         gid_t *groups = NULL;
363         int result, i;
364
365         /*
366          * Don't do the lookup if the name has no separator.
367          */
368
369         if (!strchr(user, *lp_winbind_separator()))
370                 return -1;
371
372         /* Fetch list of groups */
373
374         result = wb_getgroups(user, &groups);
375
376         if (size == 0)
377                 goto done;
378
379         if (result > size) {
380                 result = -1;
381                 errno = EINVAL; /* This is what getgroups() does */
382                 goto done;
383         }
384
385         /* Copy list of groups across */
386
387         for (i = 0; i < result; i++) {
388                 list[i] = groups[i];
389         }
390
391  done:
392         SAFE_FREE(groups);
393         return result;
394 }
395
396 /* Utility function. Convert a uid_t to a name if possible. */
397
398 BOOL winbind_uidtoname(fstring name, uid_t uid)
399 {
400         DOM_SID sid;
401         fstring dom_name;
402         fstring user_name;
403         enum SID_NAME_USE name_type;
404
405         if (!winbind_uid_to_sid(&sid, uid))
406                 return False;
407         if (!winbind_lookup_sid(&sid, dom_name, user_name, &name_type))
408                 return False;
409
410         if (name_type != SID_NAME_USER)
411                 return False;
412
413         slprintf(name, sizeof(fstring)-1, "%s%s%s", dom_name, 
414                  lp_winbind_separator(), user_name);
415
416         return True;
417 }
418
419 /* Utility function. Convert a gid_t to a name if possible. */
420
421 BOOL winbind_gidtoname(fstring name, gid_t gid)
422 {
423         DOM_SID sid;
424         fstring dom_name;
425         fstring group_name;
426         enum SID_NAME_USE name_type;
427
428         if (!winbind_gid_to_sid(&sid, gid))
429                 return False;
430         if (!winbind_lookup_sid(&sid, dom_name, group_name, &name_type))
431                 return False;
432
433         if (name_type != SID_NAME_DOM_GRP)
434                 return False;
435
436         slprintf(name, sizeof(fstring)-1, "%s%s%s", dom_name, 
437                  lp_winbind_separator(), group_name);
438
439         return True;
440 }
441
442 /* Utility function. Convert a name to a uid_t if possible. */
443
444 BOOL winbind_nametouid(uid_t *puid, const char *name)
445 {
446         DOM_SID sid;
447         enum SID_NAME_USE name_type;
448
449         if (!winbind_lookup_name(name, &sid, &name_type))
450                 return False;
451
452         if (name_type != SID_NAME_USER)
453                 return False;
454
455         return winbind_sid_to_uid(puid, &sid);
456 }
457
458 /* Utility function. Convert a name to a gid_t if possible. */
459
460 BOOL winbind_nametogid(gid_t *pgid, const char *gname)
461 {
462         DOM_SID g_sid;
463         enum SID_NAME_USE name_type;
464
465         if (!winbind_lookup_name(gname, &g_sid, &name_type))
466                 return False;
467
468         if (name_type != SID_NAME_DOM_GRP)
469                 return False;
470
471         return winbind_sid_to_gid(pgid, &g_sid);
472 }