import HEAD into svn+ssh://svn.samba.org/home/svn/samba/trunk
[metze/old/v3-2-winbind-ndr.git] / examples / nss / nss_winbind.c
1 /* 
2    nss sample code for extended winbindd functionality
3
4    Copyright (C) Andrew Tridgell (tridge@samba.org)   
5
6    you are free to use this code in any way you see fit, including
7    without restriction, using this code in your own products. You do
8    not need to give any attribution.
9 */
10
11 #define _GNU_SOURCE
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <nss.h>
16 #include <dlfcn.h>
17 #include <errno.h>
18 #include <string.h>
19 #include <sys/types.h>
20
21 #include "nss_winbind.h"
22
23 /*
24   find a function in the nss library
25 */
26 static void *find_fn(struct nss_state *nss, const char *name)
27 {
28         void *res;
29         char *s = NULL;
30
31         asprintf(&s, "_nss_%s_%s", nss->nss_name, name);
32         if (!s) {
33                 errno = ENOMEM;
34                 return NULL;
35         }
36         res = dlsym(nss->dl_handle, s);
37         free(s);
38         if (!res) {
39                 errno = ENOENT;
40                 return NULL;
41         }
42         return res;
43 }
44
45 /*
46   establish a link to the nss library
47   Return 0 on success and -1 on error
48 */
49 int nss_open(struct nss_state *nss, const char *nss_path)
50 {
51         char *p;
52         p = strrchr(nss_path, '_');
53         if (!p) {
54                 errno = EINVAL;
55                 return -1;
56         }
57
58         nss->nss_name = strdup(p+1);
59         p = strchr(nss->nss_name, '.');
60         if (p) *p = 0;
61
62         nss->dl_handle = dlopen(nss_path, RTLD_LAZY);
63         if (!nss->dl_handle) {
64                 free(nss->nss_name);
65                 return -1;
66         }
67
68         return 0;
69 }
70
71 /*
72   close and cleanup a nss state
73 */
74 void nss_close(struct nss_state *nss)
75 {
76         free(nss->nss_name);
77         dlclose(nss->dl_handle);
78 }
79
80 /*
81   make a getpwnam call. 
82   Return 0 on success and -1 on error
83 */
84 int nss_getpwent(struct nss_state *nss, struct passwd *pwd)
85 {
86         enum nss_status (*_nss_getpwent_r)(struct passwd *, char *, 
87                                            size_t , int *);
88         enum nss_status status;
89         int nss_errno = 0;
90
91         _nss_getpwent_r = find_fn(nss, "getpwent_r");
92
93         if (!_nss_getpwent_r) {
94                 return -1;
95         }
96
97         status = _nss_getpwent_r(pwd, nss->pwnam_buf, sizeof(nss->pwnam_buf),
98                                  &nss_errno);
99         if (status == NSS_STATUS_NOTFOUND) {
100                 errno = ENOENT;
101                 return -1;
102         }
103         if (status != NSS_STATUS_SUCCESS) {
104                 errno = nss_errno;
105                 return -1;
106         }
107
108         return 0;
109 }
110
111 /*
112   make a setpwent call. 
113   Return 0 on success and -1 on error
114 */
115 int nss_setpwent(struct nss_state *nss)
116 {
117         enum nss_status (*_nss_setpwent)(void) = find_fn(nss, "setpwent");
118         enum nss_status status;
119         if (!_nss_setpwent) {
120                 return -1;
121         }
122         status = _nss_setpwent();
123         if (status != NSS_STATUS_SUCCESS) {
124                 errno = EINVAL;
125                 return -1;
126         }
127         return 0;
128 }
129
130 /*
131   make a endpwent call. 
132   Return 0 on success and -1 on error
133 */
134 int nss_endpwent(struct nss_state *nss)
135 {
136         enum nss_status (*_nss_endpwent)(void) = find_fn(nss, "endpwent");
137         enum nss_status status;
138         if (!_nss_endpwent) {
139                 return -1;
140         }
141         status = _nss_endpwent();
142         if (status != NSS_STATUS_SUCCESS) {
143                 errno = EINVAL;
144                 return -1;
145         }
146         return 0;
147 }
148
149
150 /*
151   convert a name to a SID
152   caller frees
153   Return 0 on success and -1 on error
154 */
155 int nss_nametosid(struct nss_state *nss, const char *name, char **sid)
156 {
157         enum nss_status (*_nss_nametosid)(const char *, char **, char *,
158                                           size_t, int *);
159         enum nss_status status;
160         int nss_errno = 0;
161         char buf[200];
162
163         _nss_nametosid = find_fn(nss, "nametosid");
164
165         if (!_nss_nametosid) {
166                 return -1;
167         }
168
169         status = _nss_nametosid(name, sid, buf, sizeof(buf), &nss_errno);
170         if (status == NSS_STATUS_NOTFOUND) {
171                 errno = ENOENT;
172                 return -1;
173         }
174         if (status != NSS_STATUS_SUCCESS) {
175                 errno = nss_errno;
176                 return -1;
177         }
178
179         *sid = strdup(*sid);
180
181         return 0;
182 }
183
184 /*
185   convert a SID to a name
186   caller frees
187   Return 0 on success and -1 on error
188 */
189 int nss_sidtoname(struct nss_state *nss, const char *sid, char **name)
190 {
191         enum nss_status (*_nss_sidtoname)(const char *, char **, char *,
192                                           size_t, int *);
193         enum nss_status status;
194         int nss_errno = 0;
195         char buf[200];
196
197         _nss_sidtoname = find_fn(nss, "sidtoname");
198
199         if (!_nss_sidtoname) {
200                 return -1;
201         }
202
203         status = _nss_sidtoname(sid, name, buf, sizeof(buf), &nss_errno);
204         if (status == NSS_STATUS_NOTFOUND) {
205                 errno = ENOENT;
206                 return -1;
207         }
208         if (status != NSS_STATUS_SUCCESS) {
209                 errno = nss_errno;
210                 return -1;
211         }
212
213         *name = strdup(*name);
214
215         return 0;
216 }
217
218 /*
219   return a list of group SIDs for a user SID
220   the returned list is NULL terminated
221   Return 0 on success and -1 on error
222 */
223 int nss_getusersids(struct nss_state *nss, const char *user_sid, char ***sids)
224 {
225         enum nss_status (*_nss_getusersids)(const char *, char **, int *,
226                                             char *, size_t, int *);
227         enum nss_status status;
228         int nss_errno = 0;
229         char *s;
230         int i, num_groups = 0;
231         unsigned bufsize = 10;
232         char *buf;
233
234         _nss_getusersids = find_fn(nss, "getusersids");
235
236         if (!_nss_getusersids) {
237                 return -1;
238         }
239
240 again:
241         buf = malloc(bufsize);
242         if (!buf) {
243                 errno = ENOMEM;
244                 return -1;
245         }
246
247         status = _nss_getusersids(user_sid, &s, &num_groups, buf, bufsize,
248                                   &nss_errno);
249
250         if (status == NSS_STATUS_NOTFOUND) {
251                 errno = ENOENT;
252                 free(buf);
253                 return -1;
254         }
255         
256         if (status == NSS_STATUS_TRYAGAIN) {
257                 bufsize *= 2;
258                 free(buf);
259                 goto again;
260         }
261
262         if (status != NSS_STATUS_SUCCESS) {
263                 free(buf);
264                 errno = nss_errno;
265                 return -1;
266         }
267
268         if (num_groups == 0) {
269                 free(buf);
270                 return 0;
271         }
272
273         *sids = (char **)malloc(sizeof(char *) * (num_groups+1));
274         if (! *sids) {
275                 errno = ENOMEM;
276                 free(buf);
277                 return -1;
278         }
279
280         for (i=0;i<num_groups;i++) {
281                 (*sids)[i] = strdup(s);
282                 s += strlen(s) + 1;
283         }
284         (*sids)[i] = NULL;
285
286         free(buf);
287
288         return 0;
289 }
290
291 /*
292   convert a sid to a uid
293   Return 0 on success and -1 on error
294 */
295 int nss_sidtouid(struct nss_state *nss, const char *sid, uid_t *uid)
296 {
297         enum nss_status (*_nss_sidtouid)(const char*, uid_t *, int*);
298
299         enum nss_status status;
300         int nss_errno = 0;
301
302         _nss_sidtouid = find_fn(nss, "sidtouid");
303
304         if (!_nss_sidtouid) {
305                 return -1;
306         }
307
308         status = _nss_sidtouid(sid, uid, &nss_errno);
309
310         if (status == NSS_STATUS_NOTFOUND) {
311                 errno = ENOENT;
312                 return -1;
313         }
314
315         if (status != NSS_STATUS_SUCCESS) {
316                 errno = nss_errno;
317                 return -1;
318         }
319
320         return 0;
321 }
322
323 /*
324   convert a sid to a gid
325   Return 0 on success and -1 on error
326 */
327 int nss_sidtogid(struct nss_state *nss, const char *sid, gid_t *gid)
328 {
329         enum nss_status (*_nss_sidtogid)(const char*, gid_t *, int*);
330
331         enum nss_status status;
332         int nss_errno = 0;
333
334         _nss_sidtogid = find_fn(nss, "sidtogid");
335
336         if (!_nss_sidtogid) {
337                 return -1;
338         }
339
340         status = _nss_sidtogid(sid, gid, &nss_errno);
341
342         if (status == NSS_STATUS_NOTFOUND) {
343                 errno = ENOENT;
344                 return -1;
345         }
346
347         if (status != NSS_STATUS_SUCCESS) {
348                 errno = nss_errno;
349                 return -1;
350         }
351
352         return 0;
353 }
354
355 /*
356   convert a uid to a sid
357   caller frees
358   Return 0 on success and -1 on error
359 */
360 int nss_uidtosid(struct nss_state *nss, uid_t uid, char **sid)
361 {
362         enum nss_status (*_nss_uidtosid)(uid_t, char **, char *,
363                                          size_t, int *);
364         enum nss_status status;
365         int nss_errno = 0;
366         char buf[200];
367
368         _nss_uidtosid = find_fn(nss, "uidtosid");
369
370         if (!_nss_uidtosid) {
371                 return -1;
372         }
373
374         status = _nss_uidtosid(uid, sid, buf, sizeof(buf), &nss_errno);
375         if (status == NSS_STATUS_NOTFOUND) {
376                 errno = ENOENT;
377                 return -1;
378         }
379         if (status != NSS_STATUS_SUCCESS) {
380                 errno = nss_errno;
381                 return -1;
382         }
383
384         *sid = strdup(*sid);
385
386         return 0;
387 }
388
389 /*
390   convert a gid to a sid
391   caller frees
392   Return 0 on success and -1 on error
393 */
394 int nss_gidtosid(struct nss_state *nss, gid_t gid, char **sid)
395 {
396         enum nss_status (*_nss_gidtosid)(gid_t, char **, char *,
397                                          size_t, int *);
398         enum nss_status status;
399         int nss_errno = 0;
400         char buf[200];
401
402         _nss_gidtosid = find_fn(nss, "gidtosid");
403
404         if (!_nss_gidtosid) {
405                 return -1;
406         }
407
408         status = _nss_gidtosid(gid, sid, buf, sizeof(buf), &nss_errno);
409         if (status == NSS_STATUS_NOTFOUND) {
410                 errno = ENOENT;
411                 return -1;
412         }
413         if (status != NSS_STATUS_SUCCESS) {
414                 errno = nss_errno;
415                 return -1;
416         }
417
418         *sid = strdup(*sid);
419
420         return 0;
421 }
422