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