1/* 2 Solaris NSS wrapper for winbind 3 - Shirish Kalele 2000 4 5 Based on Luke Howard's ldap_nss module for Solaris 6 */ 7 8/* 9 Copyright (C) 1997-2003 Luke Howard. 10 This file is part of the nss_ldap library. 11 12 The nss_ldap library is free software; you can redistribute it and/or 13 modify it under the terms of the GNU Library General Public License as 14 published by the Free Software Foundation; either version 2 of the 15 License, or (at your option) any later version. 16 17 The nss_ldap library is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 Library General Public License for more details. 21 22 You should have received a copy of the GNU Library General Public 23 License along with the nss_ldap library; see the file COPYING.LIB. If not, 24 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 25 Boston, MA 02111-1307, USA. 26*/ 27 28#undef DEVELOPER 29 30#include <stdlib.h> 31#include <sys/types.h> 32#include <sys/param.h> 33#include <string.h> 34#include <pwd.h> 35#include "includes.h" 36#include <syslog.h> 37#if !defined(HPUX) 38#include <sys/syslog.h> 39#endif /*hpux*/ 40#include "winbind_nss_config.h" 41 42#if defined(HAVE_NSS_COMMON_H) || defined(HPUX) 43 44#undef NSS_DEBUG 45 46#ifdef NSS_DEBUG 47#define NSS_DEBUG(str) syslog(LOG_DEBUG, "nss_winbind: %s", str); 48#else 49#define NSS_DEBUG(str) ; 50#endif 51 52#define NSS_ARGS(args) ((nss_XbyY_args_t *)args) 53 54#ifdef HPUX 55 56/* 57 * HP-UX 11 has no definiton of the nss_groupsbymem structure. This 58 * definition is taken from the nss_ldap project at: 59 * http://www.padl.com/OSS/nss_ldap.html 60 */ 61 62struct nss_groupsbymem { 63 const char *username; 64 gid_t *gid_array; 65 int maxgids; 66 int force_slow_way; 67 int (*str2ent)(const char *instr, int instr_len, void *ent, 68 char *buffer, int buflen); 69 nss_status_t (*process_cstr)(const char *instr, int instr_len, 70 struct nss_groupsbymem *); 71 int numgids; 72}; 73 74#endif /* HPUX */ 75 76#define make_pwent_str(dest, src) \ 77{ \ 78 if((dest = get_static(buffer, buflen, strlen(src)+1)) == NULL) \ 79 { \ 80 *errnop = ERANGE; \ 81 NSS_DEBUG("ERANGE error"); \ 82 return NSS_STATUS_TRYAGAIN; \ 83 } \ 84 strcpy(dest, src); \ 85} 86 87static NSS_STATUS _nss_winbind_setpwent_solwrap (nss_backend_t* be, void* args) 88{ 89 NSS_DEBUG("_nss_winbind_setpwent_solwrap"); 90 return _nss_winbind_setpwent(); 91} 92 93static NSS_STATUS 94_nss_winbind_endpwent_solwrap (nss_backend_t * be, void *args) 95{ 96 NSS_DEBUG("_nss_winbind_endpwent_solwrap"); 97 return _nss_winbind_endpwent(); 98} 99 100static NSS_STATUS 101_nss_winbind_getpwent_solwrap (nss_backend_t* be, void *args) 102{ 103 NSS_STATUS ret; 104 char* buffer = NSS_ARGS(args)->buf.buffer; 105 int buflen = NSS_ARGS(args)->buf.buflen; 106 struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result; 107 int* errnop = &NSS_ARGS(args)->erange; 108 char logmsg[80]; 109 110 ret = _nss_winbind_getpwent_r(result, buffer, 111 buflen, errnop); 112 113 if(ret == NSS_STATUS_SUCCESS) 114 { 115 snprintf(logmsg, 79, "_nss_winbind_getpwent_solwrap: Returning user: %s\n", 116 result->pw_name); 117 NSS_DEBUG(logmsg); 118 NSS_ARGS(args)->returnval = (void*) result; 119 } else { 120 snprintf(logmsg, 79, "_nss_winbind_getpwent_solwrap: Returning error: %d.\n",ret); 121 NSS_DEBUG(logmsg); 122 } 123 124 return ret; 125} 126 127static NSS_STATUS 128_nss_winbind_getpwnam_solwrap (nss_backend_t* be, void* args) 129{ 130 NSS_STATUS ret; 131 struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result; 132 133 NSS_DEBUG("_nss_winbind_getpwnam_solwrap"); 134 135 ret = _nss_winbind_getpwnam_r (NSS_ARGS(args)->key.name, 136 result, 137 NSS_ARGS(args)->buf.buffer, 138 NSS_ARGS(args)->buf.buflen, 139 &NSS_ARGS(args)->erange); 140 if(ret == NSS_STATUS_SUCCESS) 141 NSS_ARGS(args)->returnval = (void*) result; 142 143 return ret; 144} 145 146static NSS_STATUS 147_nss_winbind_getpwuid_solwrap(nss_backend_t* be, void* args) 148{ 149 NSS_STATUS ret; 150 struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result; 151 152 NSS_DEBUG("_nss_winbind_getpwuid_solwrap"); 153 ret = _nss_winbind_getpwuid_r (NSS_ARGS(args)->key.uid, 154 result, 155 NSS_ARGS(args)->buf.buffer, 156 NSS_ARGS(args)->buf.buflen, 157 &NSS_ARGS(args)->erange); 158 if(ret == NSS_STATUS_SUCCESS) 159 NSS_ARGS(args)->returnval = (void*) result; 160 161 return ret; 162} 163 164static NSS_STATUS _nss_winbind_passwd_destr (nss_backend_t * be, void *args) 165{ 166 SAFE_FREE(be); 167 NSS_DEBUG("_nss_winbind_passwd_destr"); 168 return NSS_STATUS_SUCCESS; 169} 170 171static nss_backend_op_t passwd_ops[] = 172{ 173 _nss_winbind_passwd_destr, 174 _nss_winbind_endpwent_solwrap, /* NSS_DBOP_ENDENT */ 175 _nss_winbind_setpwent_solwrap, /* NSS_DBOP_SETENT */ 176 _nss_winbind_getpwent_solwrap, /* NSS_DBOP_GETENT */ 177 _nss_winbind_getpwnam_solwrap, /* NSS_DBOP_PASSWD_BYNAME */ 178 _nss_winbind_getpwuid_solwrap /* NSS_DBOP_PASSWD_BYUID */ 179}; 180 181nss_backend_t* 182_nss_winbind_passwd_constr (const char* db_name, 183 const char* src_name, 184 const char* cfg_args) 185{ 186 nss_backend_t *be; 187 188 if(!(be = SMB_MALLOC_P(nss_backend_t)) ) 189 return NULL; 190 191 be->ops = passwd_ops; 192 be->n_ops = sizeof(passwd_ops) / sizeof(nss_backend_op_t); 193 194 NSS_DEBUG("Initialized nss_winbind passwd backend"); 195 return be; 196} 197 198/***************************************************************** 199 GROUP database backend 200 *****************************************************************/ 201 202static NSS_STATUS _nss_winbind_setgrent_solwrap (nss_backend_t* be, void* args) 203{ 204 NSS_DEBUG("_nss_winbind_setgrent_solwrap"); 205 return _nss_winbind_setgrent(); 206} 207 208static NSS_STATUS 209_nss_winbind_endgrent_solwrap (nss_backend_t * be, void *args) 210{ 211 NSS_DEBUG("_nss_winbind_endgrent_solwrap"); 212 return _nss_winbind_endgrent(); 213} 214 215static NSS_STATUS 216_nss_winbind_getgrent_solwrap(nss_backend_t* be, void* args) 217{ 218 NSS_STATUS ret; 219 char* buffer = NSS_ARGS(args)->buf.buffer; 220 int buflen = NSS_ARGS(args)->buf.buflen; 221 struct group* result = (struct group*) NSS_ARGS(args)->buf.result; 222 int* errnop = &NSS_ARGS(args)->erange; 223 char logmsg[80]; 224 225 ret = _nss_winbind_getgrent_r(result, buffer, 226 buflen, errnop); 227 228 if(ret == NSS_STATUS_SUCCESS) 229 { 230 snprintf(logmsg, 79, "_nss_winbind_getgrent_solwrap: Returning group: %s\n", result->gr_name); 231 NSS_DEBUG(logmsg); 232 NSS_ARGS(args)->returnval = (void*) result; 233 } else { 234 snprintf(logmsg, 79, "_nss_winbind_getgrent_solwrap: Returning error: %d.\n", ret); 235 NSS_DEBUG(logmsg); 236 } 237 238 return ret; 239 240} 241 242static NSS_STATUS 243_nss_winbind_getgrnam_solwrap(nss_backend_t* be, void* args) 244{ 245 NSS_STATUS ret; 246 struct group* result = (struct group*) NSS_ARGS(args)->buf.result; 247 248 NSS_DEBUG("_nss_winbind_getgrnam_solwrap"); 249 ret = _nss_winbind_getgrnam_r(NSS_ARGS(args)->key.name, 250 result, 251 NSS_ARGS(args)->buf.buffer, 252 NSS_ARGS(args)->buf.buflen, 253 &NSS_ARGS(args)->erange); 254 255 if(ret == NSS_STATUS_SUCCESS) 256 NSS_ARGS(args)->returnval = (void*) result; 257 258 return ret; 259} 260 261static NSS_STATUS 262_nss_winbind_getgrgid_solwrap(nss_backend_t* be, void* args) 263{ 264 NSS_STATUS ret; 265 struct group* result = (struct group*) NSS_ARGS(args)->buf.result; 266 267 NSS_DEBUG("_nss_winbind_getgrgid_solwrap"); 268 ret = _nss_winbind_getgrgid_r (NSS_ARGS(args)->key.gid, 269 result, 270 NSS_ARGS(args)->buf.buffer, 271 NSS_ARGS(args)->buf.buflen, 272 &NSS_ARGS(args)->erange); 273 274 if(ret == NSS_STATUS_SUCCESS) 275 NSS_ARGS(args)->returnval = (void*) result; 276 277 return ret; 278} 279 280static NSS_STATUS 281_nss_winbind_getgroupsbymember_solwrap(nss_backend_t* be, void* args) 282{ 283 int errnop; 284 struct nss_groupsbymem *gmem = (struct nss_groupsbymem *)args; 285 286 NSS_DEBUG("_nss_winbind_getgroupsbymember"); 287 288 _nss_winbind_initgroups_dyn(gmem->username, 289 gmem->gid_array[0], /* Primary Group */ 290 &gmem->numgids, 291 &gmem->maxgids, 292 &gmem->gid_array, 293 gmem->maxgids, 294 &errnop); 295 296 /* 297 * If the maximum number of gids have been found, return 298 * SUCCESS so the switch engine will stop searching. Otherwise 299 * return NOTFOUND so nsswitch will continue to get groups 300 * from the remaining database backends specified in the 301 * nsswitch.conf file. 302 */ 303 return (gmem->numgids == gmem->maxgids ? NSS_STATUS_SUCCESS : NSS_STATUS_NOTFOUND); 304} 305 306static NSS_STATUS 307_nss_winbind_group_destr (nss_backend_t* be, void* args) 308{ 309 SAFE_FREE(be); 310 NSS_DEBUG("_nss_winbind_group_destr"); 311 return NSS_STATUS_SUCCESS; 312} 313 314static nss_backend_op_t group_ops[] = 315{ 316 _nss_winbind_group_destr, 317 _nss_winbind_endgrent_solwrap, 318 _nss_winbind_setgrent_solwrap, 319 _nss_winbind_getgrent_solwrap, 320 _nss_winbind_getgrnam_solwrap, 321 _nss_winbind_getgrgid_solwrap, 322 _nss_winbind_getgroupsbymember_solwrap 323}; 324 325nss_backend_t* 326_nss_winbind_group_constr (const char* db_name, 327 const char* src_name, 328 const char* cfg_args) 329{ 330 nss_backend_t* be; 331 332 if(!(be = SMB_MALLOC_P(nss_backend_t)) ) 333 return NULL; 334 335 be->ops = group_ops; 336 be->n_ops = sizeof(group_ops) / sizeof(nss_backend_op_t); 337 338 NSS_DEBUG("Initialized nss_winbind group backend"); 339 return be; 340} 341 342/***************************************************************** 343 hosts and ipnodes backend 344 *****************************************************************/ 345#if defined(SUNOS5) /* not compatible with HP-UX */ 346 347/* this parser is shared between get*byname and get*byaddr, as key type 348 in request is stored in different locations, I had to provide the 349 address family as an argument, caller must free the winbind response. */ 350 351static NSS_STATUS 352parse_response(int af, nss_XbyY_args_t* argp, struct winbindd_response *response) 353{ 354 struct hostent *he = (struct hostent *)argp->buf.result; 355 char *buffer = argp->buf.buffer; 356 int buflen = argp->buf.buflen; 357 NSS_STATUS ret; 358 359 char *p, *data; 360 int addrcount = 0; 361 int len = 0; 362 struct in_addr *addrp; 363 struct in6_addr *addrp6; 364 int i; 365 366 /* response is tab separated list of ip addresses with hostname 367 and newline at the end. so at first we will strip newline 368 then construct list of addresses for hostent. 369 */ 370 p = strchr(response->data.winsresp, '\n'); 371 if(p) *p = '\0'; 372 else {/* it must be broken */ 373 argp->h_errno = NO_DATA; 374 return NSS_STATUS_UNAVAIL; 375 } 376 377 for(; p != response->data.winsresp; p--) { 378 if(*p == '\t') addrcount++; 379 } 380 381 if(addrcount == 0) {/* it must be broken */ 382 argp->h_errno = NO_DATA; 383 return NSS_STATUS_UNAVAIL; 384 } 385 386 /* allocate space for addresses and h_addr_list */ 387 he->h_addrtype = af; 388 if( he->h_addrtype == AF_INET) { 389 he->h_length = sizeof(struct in_addr); 390 addrp = (struct in_addr *)ROUND_DOWN(buffer + buflen, 391 sizeof(struct in_addr)); 392 addrp -= addrcount; 393 he->h_addr_list = (char **)ROUND_DOWN(addrp, sizeof (char*)); 394 he->h_addr_list -= addrcount+1; 395 } else { 396 he->h_length = sizeof(struct in6_addr); 397 addrp6 = (struct in6_addr *)ROUND_DOWN(buffer + buflen, 398 sizeof(struct in6_addr)); 399 addrp6 -= addrcount; 400 he->h_addr_list = (char **)ROUND_DOWN(addrp6, sizeof (char*)); 401 he->h_addr_list -= addrcount+1; 402 } 403 404 /* buffer too small?! */ 405 if((char *)he->h_addr_list < buffer ) { 406 argp->erange = 1; 407 return NSS_STR_PARSE_ERANGE; 408 } 409 410 data = response->data.winsresp; 411 for( i = 0; i < addrcount; i++) { 412 p = strchr(data, '\t'); 413 if(p == NULL) break; /* just in case... */ 414 415 *p = '\0'; /* terminate the string */ 416 if(he->h_addrtype == AF_INET) { 417 he->h_addr_list[i] = (char *)&addrp[i]; 418 if ((addrp[i].s_addr = inet_addr(data)) == -1) { 419 argp->erange = 1; 420 return NSS_STR_PARSE_ERANGE; 421 } 422 } else { 423 he->h_addr_list[i] = (char *)&addrp6[i]; 424 if (strchr(data, ':') != 0) { 425 if (inet_pton(AF_INET6, data, &addrp6[i]) != 1) { 426 argp->erange = 1; 427 return NSS_STR_PARSE_ERANGE; 428 } 429 } else { 430 struct in_addr in4; 431 if ((in4.s_addr = inet_addr(data)) == -1) { 432 argp->erange = 1; 433 return NSS_STR_PARSE_ERANGE; 434 } 435 IN6_INADDR_TO_V4MAPPED(&in4, &addrp6[i]); 436 } 437 } 438 data = p+1; 439 } 440 441 he->h_addr_list[i] = (char *)NULL; 442 443 len = strlen(data); 444 if(len > he->h_addr_list - (char**)argp->buf.buffer) { 445 argp->erange = 1; 446 return NSS_STR_PARSE_ERANGE; 447 } 448 449 /* this is a bit overkill to use _nss_netdb_aliases here since 450 there seems to be no aliases but it will create all data for us */ 451 he->h_aliases = _nss_netdb_aliases(data, len, buffer, 452 ((char*) he->h_addr_list) - buffer); 453 if(he->h_aliases == NULL) { 454 argp->erange = 1; 455 ret = NSS_STR_PARSE_ERANGE; 456 } else { 457 he->h_name = he->h_aliases[0]; 458 he->h_aliases++; 459 ret = NSS_STR_PARSE_SUCCESS; 460 } 461 462 argp->returnval = (void*)he; 463 return ret; 464} 465 466static NSS_STATUS 467_nss_winbind_ipnodes_getbyname(nss_backend_t* be, void *args) 468{ 469 nss_XbyY_args_t *argp = (nss_XbyY_args_t*) args; 470 struct winbindd_response response; 471 struct winbindd_request request; 472 NSS_STATUS ret; 473 int af; 474 475 ZERO_STRUCT(response); 476 ZERO_STRUCT(request); 477 478 /* I assume there that AI_ADDRCONFIG cases are handled in nss 479 frontend code, at least it seems done so in solaris... 480 481 we will give NO_DATA for pure IPv6; IPv4 will be returned for 482 AF_INET or for AF_INET6 and AI_ALL|AI_V4MAPPED we have to map 483 IPv4 to IPv6. 484 */ 485#ifdef HAVE_NSS_XBYY_KEY_IPNODE 486 af = argp->key.ipnode.af_family; 487 if(af == AF_INET6 && argp->key.ipnode.flags == 0) { 488 argp->h_errno = NO_DATA; 489 return NSS_STATUS_UNAVAIL; 490 } 491#else 492 /* I'm not that sure if this is correct, but... */ 493 af = AF_INET6; 494#endif 495 496 strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1); 497 request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0'; 498 499 if( (ret = winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response)) 500 == NSS_STATUS_SUCCESS ) { 501 ret = parse_response(af, argp, &response); 502 } 503 504 free_response(&response); 505 return ret; 506} 507 508static NSS_STATUS 509_nss_winbind_hosts_getbyname(nss_backend_t* be, void *args) 510{ 511 nss_XbyY_args_t *argp = (nss_XbyY_args_t*) args; 512 struct winbindd_response response; 513 struct winbindd_request request; 514 NSS_STATUS ret; 515 516 ZERO_STRUCT(response); 517 ZERO_STRUCT(request); 518 519 strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1); 520 request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0'; 521 522 if( (ret = winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response)) 523 == NSS_STATUS_SUCCESS ) { 524 ret = parse_response(AF_INET, argp, &response); 525 } 526 527 free_response(&response); 528 return ret; 529} 530 531static NSS_STATUS 532_nss_winbind_hosts_getbyaddr(nss_backend_t* be, void *args) 533{ 534 NSS_STATUS ret; 535 struct winbindd_response response; 536 struct winbindd_request request; 537 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)args; 538 const char *p; 539 540 ZERO_STRUCT(response); 541 ZERO_STRUCT(request); 542 543 /* winbindd currently does not resolve IPv6 */ 544 if(argp->key.hostaddr.type == AF_INET6) { 545 argp->h_errno = NO_DATA; 546 return NSS_STATUS_UNAVAIL; 547 } 548 549 p = inet_ntop(argp->key.hostaddr.type, argp->key.hostaddr.addr, 550 request.data.winsreq, INET6_ADDRSTRLEN); 551 552 ret = winbindd_request_response(WINBINDD_WINS_BYIP, &request, &response); 553 554 if( ret == NSS_STATUS_SUCCESS) { 555 parse_response(argp->key.hostaddr.type, argp, &response); 556 } 557 free_response(&response); 558 return ret; 559} 560 561/* winbind does not provide setent, getent, endent for wins */ 562static NSS_STATUS 563_nss_winbind_common_endent(nss_backend_t* be, void *args) 564{ 565 return (NSS_STATUS_UNAVAIL); 566} 567 568static NSS_STATUS 569_nss_winbind_common_setent(nss_backend_t* be, void *args) 570{ 571 return (NSS_STATUS_UNAVAIL); 572} 573 574static NSS_STATUS 575_nss_winbind_common_getent(nss_backend_t* be, void *args) 576{ 577 return (NSS_STATUS_UNAVAIL); 578} 579 580static nss_backend_t* 581_nss_winbind_common_constr (nss_backend_op_t ops[], int n_ops) 582{ 583 nss_backend_t* be; 584 585 if(!(be = SMB_MALLOC_P(nss_backend_t)) ) 586 return NULL; 587 588 be->ops = ops; 589 be->n_ops = n_ops; 590 591 return be; 592} 593 594static NSS_STATUS 595_nss_winbind_common_destr (nss_backend_t* be, void* args) 596{ 597 SAFE_FREE(be); 598 return NSS_STATUS_SUCCESS; 599} 600 601static nss_backend_op_t ipnodes_ops[] = { 602 _nss_winbind_common_destr, 603 _nss_winbind_common_endent, 604 _nss_winbind_common_setent, 605 _nss_winbind_common_getent, 606 _nss_winbind_ipnodes_getbyname, 607 _nss_winbind_hosts_getbyaddr, 608}; 609 610nss_backend_t * 611_nss_winbind_ipnodes_constr(dummy1, dummy2, dummy3) 612 const char *dummy1, *dummy2, *dummy3; 613{ 614 return (_nss_winbind_common_constr(ipnodes_ops, 615 sizeof (ipnodes_ops) / sizeof (ipnodes_ops[0]))); 616} 617 618static nss_backend_op_t host_ops[] = { 619 _nss_winbind_common_destr, 620 _nss_winbind_common_endent, 621 _nss_winbind_common_setent, 622 _nss_winbind_common_getent, 623 _nss_winbind_hosts_getbyname, 624 _nss_winbind_hosts_getbyaddr, 625}; 626 627nss_backend_t * 628_nss_winbind_hosts_constr(dummy1, dummy2, dummy3) 629 const char *dummy1, *dummy2, *dummy3; 630{ 631 return (_nss_winbind_common_constr(host_ops, 632 sizeof (host_ops) / sizeof (host_ops[0]))); 633} 634 635#endif /* defined(SUNOS5) */ 636#endif /* defined(HAVE_NSS_COMMON_H) || defined(HPUX) */ 637