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*/ 26static 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*/ 49int 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*/ 74void 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*/ 84int 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*/ 115int 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*/ 134int 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*/ 155int 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*/ 189int 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*/ 223int 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 240again: 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*/ 295int 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*/ 327int 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*/ 360int 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*/ 394int 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 423