BUG 848: don't create winbind local users/groups that already exist in the tdb
[Samba/gebeck_regimport.git] / examples / nss / wbtest.c
blobfc8f575ef061151faf56c084f53470f40eba0fe4
1 /*
2 nss sample code for extended winbindd functionality
4 Copyright (C) Andrew Tridgell (tridge@samba.org)
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 */
12 compile like this:
14 cc -o wbtest wbtest.c -ldl
16 and run like this:
18 ./wbtest /lib/libnss_winbind.so
21 #define _GNU_SOURCE
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <nss.h>
26 #include <dlfcn.h>
27 #include <pwd.h>
28 #include <grp.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <sys/types.h>
33 typedef enum nss_status NSS_STATUS;
35 struct nss_state {
36 void *dl_handle;
37 char *nss_name;
38 char pwnam_buf[512];
42 find a function in the nss library
44 static void *find_fn(struct nss_state *nss, const char *name)
46 void *res;
47 char *s = NULL;
49 asprintf(&s, "_nss_%s_%s", nss->nss_name, name);
50 if (!s) {
51 errno = ENOMEM;
52 return NULL;
54 res = dlsym(nss->dl_handle, s);
55 free(s);
56 if (!res) {
57 errno = ENOENT;
58 return NULL;
60 return res;
64 establish a link to the nss library
65 Return 0 on success and -1 on error
67 int nss_open(struct nss_state *nss, const char *nss_path)
69 char *p;
70 p = strrchr(nss_path, '_');
71 if (!p) {
72 errno = EINVAL;
73 return -1;
76 nss->nss_name = strdup(p+1);
77 p = strchr(nss->nss_name, '.');
78 if (p) *p = 0;
80 nss->dl_handle = dlopen(nss_path, RTLD_LAZY);
81 if (!nss->dl_handle) {
82 free(nss->nss_name);
83 return -1;
86 return 0;
90 close and cleanup a nss state
92 void nss_close(struct nss_state *nss)
94 free(nss->nss_name);
95 dlclose(nss->dl_handle);
99 make a getpwnam call.
100 Return 0 on success and -1 on error
102 int nss_getpwent(struct nss_state *nss, struct passwd *pwd)
104 NSS_STATUS (*_nss_getpwent_r)(struct passwd *, char *,
105 size_t , int *) = find_fn(nss, "getpwent_r");
106 NSS_STATUS status;
107 int nss_errno = 0;
109 if (!_nss_getpwent_r) {
110 return -1;
113 status = _nss_getpwent_r(pwd, nss->pwnam_buf, sizeof(nss->pwnam_buf), &nss_errno);
114 if (status == NSS_STATUS_NOTFOUND) {
115 errno = ENOENT;
116 return -1;
118 if (status != NSS_STATUS_SUCCESS) {
119 errno = nss_errno;
120 return -1;
123 return 0;
127 make a setpwent call.
128 Return 0 on success and -1 on error
130 int nss_setpwent(struct nss_state *nss)
132 NSS_STATUS (*_nss_setpwent)(void) = find_fn(nss, "setpwent");
133 NSS_STATUS status;
134 if (!_nss_setpwent) {
135 return -1;
137 status = _nss_setpwent();
138 if (status != NSS_STATUS_SUCCESS) {
139 errno = EINVAL;
140 return -1;
142 return 0;
146 make a endpwent call.
147 Return 0 on success and -1 on error
149 int nss_endpwent(struct nss_state *nss)
151 NSS_STATUS (*_nss_endpwent)(void) = find_fn(nss, "endpwent");
152 NSS_STATUS status;
153 if (!_nss_endpwent) {
154 return -1;
156 status = _nss_endpwent();
157 if (status != NSS_STATUS_SUCCESS) {
158 errno = EINVAL;
159 return -1;
161 return 0;
166 convert a name to a SID
167 caller frees
168 Return 0 on success and -1 on error
170 int nss_nametosid(struct nss_state *nss, const char *name, char **sid)
172 NSS_STATUS (*_nss_nametosid)(const char *, char **, char *, size_t, int *) =
173 find_fn(nss, "nametosid");
174 NSS_STATUS status;
175 int nss_errno = 0;
176 char buf[200];
178 if (!_nss_nametosid) {
179 return -1;
182 status = _nss_nametosid(name, sid, buf, sizeof(buf), &nss_errno);
183 if (status == NSS_STATUS_NOTFOUND) {
184 errno = ENOENT;
185 return -1;
187 if (status != NSS_STATUS_SUCCESS) {
188 errno = nss_errno;
189 return -1;
192 *sid = strdup(*sid);
194 return 0;
198 convert a SID to a name
199 caller frees
200 Return 0 on success and -1 on error
202 int nss_sidtoname(struct nss_state *nss, char *sid, char **name)
204 NSS_STATUS (*_nss_sidtoname)(const char *, char **, char *, size_t, int *) =
205 find_fn(nss, "sidtoname");
206 NSS_STATUS status;
207 int nss_errno = 0;
208 char buf[200];
210 if (!_nss_sidtoname) {
211 return -1;
214 status = _nss_sidtoname(sid, name, buf, sizeof(buf), &nss_errno);
215 if (status == NSS_STATUS_NOTFOUND) {
216 errno = ENOENT;
217 return -1;
219 if (status != NSS_STATUS_SUCCESS) {
220 errno = nss_errno;
221 return -1;
224 *name = strdup(*name);
226 return 0;
230 return a list of group SIDs for a user SID
231 the returned list is NULL terminated
232 Return 0 on success and -1 on error
234 int nss_getusersids(struct nss_state *nss, const char *user_sid, char ***sids)
236 NSS_STATUS (*_nss_getusersids)(const char *, char **, int *, char *, size_t, int *) =
237 find_fn(nss, "getusersids");
238 NSS_STATUS status;
239 int nss_errno = 0;
240 char *s;
241 int i, num_groups = 0;
242 unsigned bufsize = 10;
243 char *buf;
245 if (!_nss_getusersids) {
246 return -1;
249 again:
250 buf = malloc(bufsize);
251 if (!buf) {
252 errno = ENOMEM;
253 return -1;
256 status = _nss_getusersids(user_sid, &s, &num_groups, buf, bufsize, &nss_errno);
257 if (status == NSS_STATUS_NOTFOUND) {
258 errno = ENOENT;
259 free(buf);
260 return -1;
263 if (status == NSS_STATUS_TRYAGAIN) {
264 bufsize *= 2;
265 free(buf);
266 goto again;
269 if (status != NSS_STATUS_SUCCESS) {
270 free(buf);
271 errno = nss_errno;
272 return -1;
275 if (num_groups == 0) {
276 free(buf);
277 return 0;
280 *sids = (char **)malloc(sizeof(char *) * (num_groups+1));
281 if (! *sids) {
282 errno = ENOMEM;
283 free(buf);
284 return -1;
287 for (i=0;i<num_groups;i++) {
288 (*sids)[i] = strdup(s);
289 s += strlen(s) + 1;
291 (*sids)[i] = NULL;
293 free(buf);
295 return 0;
299 static int nss_test_users(struct nss_state *nss)
301 struct passwd pwd;
303 if (nss_setpwent(nss) != 0) {
304 perror("setpwent");
305 return -1;
308 /* loop over all users */
309 while ((nss_getpwent(nss, &pwd) == 0)) {
310 char *sid, **group_sids, *name2;
311 int i;
313 printf("User %s\n", pwd.pw_name);
314 if (nss_nametosid(nss, pwd.pw_name, &sid) != 0) {
315 perror("nametosid");
316 return -1;
318 printf("\tSID %s\n", sid);
320 if (nss_sidtoname(nss, sid, &name2) != 0) {
321 perror("sidtoname");
322 return -1;
324 printf("\tSID->name %s\n", name2);
326 if (nss_getusersids(nss, sid, &group_sids) != 0) {
327 perror("getusersids");
328 return -1;
331 printf("\tGroups:\n");
332 for (i=0; group_sids[i]; i++) {
333 printf("\t\t%s\n", group_sids[i]);
334 free(group_sids[i]);
337 free(sid);
338 free(name2);
339 free(group_sids);
343 if (nss_endpwent(nss) != 0) {
344 perror("endpwent");
345 return -1;
348 return 0;
353 main program. It lists all users, listing user SIDs for each user
355 int main(int argc, char *argv[])
357 struct nss_state nss;
358 const char *so_path = "/lib/libnss_winbind.so";
359 int ret;
361 if (argc > 1) {
362 so_path = argv[1];
365 if (nss_open(&nss, so_path) != 0) {
366 perror("nss_open");
367 exit(1);
370 ret = nss_test_users(&nss);
372 nss_close(&nss);
374 return ret;