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