diff options
Diffstat (limited to 'nsswitch/winbind_nss_solaris.c')
-rw-r--r-- | nsswitch/winbind_nss_solaris.c | 654 |
1 files changed, 654 insertions, 0 deletions
diff --git a/nsswitch/winbind_nss_solaris.c b/nsswitch/winbind_nss_solaris.c new file mode 100644 index 0000000000..4c85bd3621 --- /dev/null +++ b/nsswitch/winbind_nss_solaris.c @@ -0,0 +1,654 @@ +/* + Solaris NSS wrapper for winbind + - Shirish Kalele 2000 + + Based on Luke Howard's ldap_nss module for Solaris + */ + +/* + Copyright (C) 1997-2003 Luke Howard. + This file is part of the nss_ldap library. + + The nss_ldap library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version. + + The nss_ldap library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the nss_ldap library; see the file COPYING.LIB. If not, + see <http://www.gnu.org/licenses/>. +*/ + +#undef DEVELOPER + +#include "winbind_client.h" +#include <stdlib.h> +#include <sys/types.h> +#include <sys/param.h> +#include <string.h> +#include <pwd.h> +#include "includes.h" +#include <syslog.h> +#if !defined(HPUX) +#include <sys/syslog.h> +#endif /*hpux*/ + +#if defined(HAVE_NSS_COMMON_H) || defined(HPUX) + +#undef NSS_DEBUG + +#ifdef NSS_DEBUG +#define NSS_DEBUG(str) syslog(LOG_DEBUG, "nss_winbind: %s", str); +#else +#define NSS_DEBUG(str) ; +#endif + +#define NSS_ARGS(args) ((nss_XbyY_args_t *)args) + +#ifdef HPUX + +/* + * HP-UX 11 has no definiton of the nss_groupsbymem structure. This + * definition is taken from the nss_ldap project at: + * http://www.padl.com/OSS/nss_ldap.html + */ + +struct nss_groupsbymem { + const char *username; + gid_t *gid_array; + int maxgids; + int force_slow_way; + int (*str2ent)(const char *instr, int instr_len, void *ent, + char *buffer, int buflen); + nss_status_t (*process_cstr)(const char *instr, int instr_len, + struct nss_groupsbymem *); + int numgids; +}; + +#endif /* HPUX */ + +#define make_pwent_str(dest, src) \ +{ \ + if((dest = get_static(buffer, buflen, strlen(src)+1)) == NULL) \ + { \ + *errnop = ERANGE; \ + NSS_DEBUG("ERANGE error"); \ + return NSS_STATUS_TRYAGAIN; \ + } \ + strcpy(dest, src); \ +} + +static NSS_STATUS _nss_winbind_setpwent_solwrap (nss_backend_t* be, void* args) +{ + NSS_DEBUG("_nss_winbind_setpwent_solwrap"); + return _nss_winbind_setpwent(); +} + +static NSS_STATUS +_nss_winbind_endpwent_solwrap (nss_backend_t * be, void *args) +{ + NSS_DEBUG("_nss_winbind_endpwent_solwrap"); + return _nss_winbind_endpwent(); +} + +static NSS_STATUS +_nss_winbind_getpwent_solwrap (nss_backend_t* be, void *args) +{ + NSS_STATUS ret; + char* buffer = NSS_ARGS(args)->buf.buffer; + int buflen = NSS_ARGS(args)->buf.buflen; + struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result; + int* errnop = &NSS_ARGS(args)->erange; + char logmsg[80]; + + ret = _nss_winbind_getpwent_r(result, buffer, + buflen, errnop); + + if(ret == NSS_STATUS_SUCCESS) + { + snprintf(logmsg, 79, "_nss_winbind_getpwent_solwrap: Returning user: %s\n", + result->pw_name); + NSS_DEBUG(logmsg); + NSS_ARGS(args)->returnval = (void*) result; + } else { + snprintf(logmsg, 79, "_nss_winbind_getpwent_solwrap: Returning error: %d.\n",ret); + NSS_DEBUG(logmsg); + } + + return ret; +} + +static NSS_STATUS +_nss_winbind_getpwnam_solwrap (nss_backend_t* be, void* args) +{ + NSS_STATUS ret; + struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result; + + NSS_DEBUG("_nss_winbind_getpwnam_solwrap"); + + ret = _nss_winbind_getpwnam_r (NSS_ARGS(args)->key.name, + result, + NSS_ARGS(args)->buf.buffer, + NSS_ARGS(args)->buf.buflen, + &NSS_ARGS(args)->erange); + if(ret == NSS_STATUS_SUCCESS) + NSS_ARGS(args)->returnval = (void*) result; + + return ret; +} + +static NSS_STATUS +_nss_winbind_getpwuid_solwrap(nss_backend_t* be, void* args) +{ + NSS_STATUS ret; + struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result; + + NSS_DEBUG("_nss_winbind_getpwuid_solwrap"); + ret = _nss_winbind_getpwuid_r (NSS_ARGS(args)->key.uid, + result, + NSS_ARGS(args)->buf.buffer, + NSS_ARGS(args)->buf.buflen, + &NSS_ARGS(args)->erange); + if(ret == NSS_STATUS_SUCCESS) + NSS_ARGS(args)->returnval = (void*) result; + + return ret; +} + +static NSS_STATUS _nss_winbind_passwd_destr (nss_backend_t * be, void *args) +{ + SAFE_FREE(be); + NSS_DEBUG("_nss_winbind_passwd_destr"); + return NSS_STATUS_SUCCESS; +} + +static nss_backend_op_t passwd_ops[] = +{ + _nss_winbind_passwd_destr, + _nss_winbind_endpwent_solwrap, /* NSS_DBOP_ENDENT */ + _nss_winbind_setpwent_solwrap, /* NSS_DBOP_SETENT */ + _nss_winbind_getpwent_solwrap, /* NSS_DBOP_GETENT */ + _nss_winbind_getpwnam_solwrap, /* NSS_DBOP_PASSWD_BYNAME */ + _nss_winbind_getpwuid_solwrap /* NSS_DBOP_PASSWD_BYUID */ +}; + +nss_backend_t* +_nss_winbind_passwd_constr (const char* db_name, + const char* src_name, + const char* cfg_args) +{ + nss_backend_t *be; + + if(!(be = SMB_MALLOC_P(nss_backend_t)) ) + return NULL; + + be->ops = passwd_ops; + be->n_ops = sizeof(passwd_ops) / sizeof(nss_backend_op_t); + + NSS_DEBUG("Initialized nss_winbind passwd backend"); + return be; +} + +/***************************************************************** + GROUP database backend + *****************************************************************/ + +static NSS_STATUS _nss_winbind_setgrent_solwrap (nss_backend_t* be, void* args) +{ + NSS_DEBUG("_nss_winbind_setgrent_solwrap"); + return _nss_winbind_setgrent(); +} + +static NSS_STATUS +_nss_winbind_endgrent_solwrap (nss_backend_t * be, void *args) +{ + NSS_DEBUG("_nss_winbind_endgrent_solwrap"); + return _nss_winbind_endgrent(); +} + +static NSS_STATUS +_nss_winbind_getgrent_solwrap(nss_backend_t* be, void* args) +{ + NSS_STATUS ret; + char* buffer = NSS_ARGS(args)->buf.buffer; + int buflen = NSS_ARGS(args)->buf.buflen; + struct group* result = (struct group*) NSS_ARGS(args)->buf.result; + int* errnop = &NSS_ARGS(args)->erange; + char logmsg[80]; + + ret = _nss_winbind_getgrent_r(result, buffer, + buflen, errnop); + + if(ret == NSS_STATUS_SUCCESS) + { + snprintf(logmsg, 79, "_nss_winbind_getgrent_solwrap: Returning group: %s\n", result->gr_name); + NSS_DEBUG(logmsg); + NSS_ARGS(args)->returnval = (void*) result; + } else { + snprintf(logmsg, 79, "_nss_winbind_getgrent_solwrap: Returning error: %d.\n", ret); + NSS_DEBUG(logmsg); + } + + return ret; + +} + +static NSS_STATUS +_nss_winbind_getgrnam_solwrap(nss_backend_t* be, void* args) +{ + NSS_STATUS ret; + struct group* result = (struct group*) NSS_ARGS(args)->buf.result; + + NSS_DEBUG("_nss_winbind_getgrnam_solwrap"); + ret = _nss_winbind_getgrnam_r(NSS_ARGS(args)->key.name, + result, + NSS_ARGS(args)->buf.buffer, + NSS_ARGS(args)->buf.buflen, + &NSS_ARGS(args)->erange); + + if(ret == NSS_STATUS_SUCCESS) + NSS_ARGS(args)->returnval = (void*) result; + + return ret; +} + +static NSS_STATUS +_nss_winbind_getgrgid_solwrap(nss_backend_t* be, void* args) +{ + NSS_STATUS ret; + struct group* result = (struct group*) NSS_ARGS(args)->buf.result; + + NSS_DEBUG("_nss_winbind_getgrgid_solwrap"); + ret = _nss_winbind_getgrgid_r (NSS_ARGS(args)->key.gid, + result, + NSS_ARGS(args)->buf.buffer, + NSS_ARGS(args)->buf.buflen, + &NSS_ARGS(args)->erange); + + if(ret == NSS_STATUS_SUCCESS) + NSS_ARGS(args)->returnval = (void*) result; + + return ret; +} + +static NSS_STATUS +_nss_winbind_getgroupsbymember_solwrap(nss_backend_t* be, void* args) +{ + int errnop; + struct nss_groupsbymem *gmem = (struct nss_groupsbymem *)args; + + NSS_DEBUG("_nss_winbind_getgroupsbymember"); + + _nss_winbind_initgroups_dyn(gmem->username, + gmem->gid_array[0], /* Primary Group */ + &gmem->numgids, + &gmem->maxgids, + &gmem->gid_array, + gmem->maxgids, + &errnop); + + /* + * If the maximum number of gids have been found, return + * SUCCESS so the switch engine will stop searching. Otherwise + * return NOTFOUND so nsswitch will continue to get groups + * from the remaining database backends specified in the + * nsswitch.conf file. + */ + return (gmem->numgids == gmem->maxgids ? NSS_STATUS_SUCCESS : NSS_STATUS_NOTFOUND); +} + +static NSS_STATUS +_nss_winbind_group_destr (nss_backend_t* be, void* args) +{ + SAFE_FREE(be); + NSS_DEBUG("_nss_winbind_group_destr"); + return NSS_STATUS_SUCCESS; +} + +static nss_backend_op_t group_ops[] = +{ + _nss_winbind_group_destr, + _nss_winbind_endgrent_solwrap, + _nss_winbind_setgrent_solwrap, + _nss_winbind_getgrent_solwrap, + _nss_winbind_getgrnam_solwrap, + _nss_winbind_getgrgid_solwrap, + _nss_winbind_getgroupsbymember_solwrap +}; + +nss_backend_t* +_nss_winbind_group_constr (const char* db_name, + const char* src_name, + const char* cfg_args) +{ + nss_backend_t* be; + + if(!(be = SMB_MALLOC_P(nss_backend_t)) ) + return NULL; + + be->ops = group_ops; + be->n_ops = sizeof(group_ops) / sizeof(nss_backend_op_t); + + NSS_DEBUG("Initialized nss_winbind group backend"); + return be; +} + +/***************************************************************** + hosts and ipnodes backend + *****************************************************************/ +#if defined(SUNOS5) /* not compatible with HP-UX */ + +/* this parser is shared between get*byname and get*byaddr, as key type + in request is stored in different locations, I had to provide the + address family as an argument, caller must free the winbind response. */ + +static NSS_STATUS +parse_response(int af, nss_XbyY_args_t* argp, struct winbindd_response *response) +{ + struct hostent *he = (struct hostent *)argp->buf.result; + char *buffer = argp->buf.buffer; + int buflen = argp->buf.buflen; + NSS_STATUS ret; + + char *p, *data; + int addrcount = 0; + int len = 0; + struct in_addr *addrp; +#if defined(AF_INET6) + struct in6_addr *addrp6; +#endif + int i; + + /* response is tab separated list of ip addresses with hostname + and newline at the end. so at first we will strip newline + then construct list of addresses for hostent. + */ + p = strchr(response->data.winsresp, '\n'); + if(p) *p = '\0'; + else {/* it must be broken */ + argp->h_errno = NO_DATA; + return NSS_STATUS_UNAVAIL; + } + + for(; p != response->data.winsresp; p--) { + if(*p == '\t') addrcount++; + } + + if(addrcount == 0) {/* it must be broken */ + argp->h_errno = NO_DATA; + return NSS_STATUS_UNAVAIL; + } + + /* allocate space for addresses and h_addr_list */ + he->h_addrtype = af; + if( he->h_addrtype == AF_INET) { + he->h_length = sizeof(struct in_addr); + addrp = (struct in_addr *)ROUND_DOWN(buffer + buflen, + sizeof(struct in_addr)); + addrp -= addrcount; + he->h_addr_list = (char **)ROUND_DOWN(addrp, sizeof (char*)); + he->h_addr_list -= addrcount+1; + } +#if defined(AF_INET6) + else { + he->h_length = sizeof(struct in6_addr); + addrp6 = (struct in6_addr *)ROUND_DOWN(buffer + buflen, + sizeof(struct in6_addr)); + addrp6 -= addrcount; + he->h_addr_list = (char **)ROUND_DOWN(addrp6, sizeof (char*)); + he->h_addr_list -= addrcount+1; + } +#endif + + /* buffer too small?! */ + if((char *)he->h_addr_list < buffer ) { + argp->erange = 1; + return NSS_STR_PARSE_ERANGE; + } + + data = response->data.winsresp; + for( i = 0; i < addrcount; i++) { + p = strchr(data, '\t'); + if(p == NULL) break; /* just in case... */ + + *p = '\0'; /* terminate the string */ + if(he->h_addrtype == AF_INET) { + he->h_addr_list[i] = (char *)&addrp[i]; + if ((addrp[i].s_addr = inet_addr(data)) == -1) { + argp->erange = 1; + return NSS_STR_PARSE_ERANGE; + } + } +#if defined(AF_INET6) + else { + he->h_addr_list[i] = (char *)&addrp6[i]; + if (strchr(data, ':') != 0) { + if (inet_pton(AF_INET6, data, &addrp6[i]) != 1) { + argp->erange = 1; + return NSS_STR_PARSE_ERANGE; + } + } else { + struct in_addr in4; + if ((in4.s_addr = inet_addr(data)) == -1) { + argp->erange = 1; + return NSS_STR_PARSE_ERANGE; + } + IN6_INADDR_TO_V4MAPPED(&in4, &addrp6[i]); + } + } +#endif + data = p+1; + } + + he->h_addr_list[i] = (char *)NULL; + + len = strlen(data); + if(len > he->h_addr_list - (char**)argp->buf.buffer) { + argp->erange = 1; + return NSS_STR_PARSE_ERANGE; + } + + /* this is a bit overkill to use _nss_netdb_aliases here since + there seems to be no aliases but it will create all data for us */ + he->h_aliases = _nss_netdb_aliases(data, len, buffer, + ((char*) he->h_addr_list) - buffer); + if(he->h_aliases == NULL) { + argp->erange = 1; + ret = NSS_STR_PARSE_ERANGE; + } else { + he->h_name = he->h_aliases[0]; + he->h_aliases++; + ret = NSS_STR_PARSE_SUCCESS; + } + + argp->returnval = (void*)he; + return ret; +} + +static NSS_STATUS +_nss_winbind_ipnodes_getbyname(nss_backend_t* be, void *args) +{ + nss_XbyY_args_t *argp = (nss_XbyY_args_t*) args; + struct winbindd_response response; + struct winbindd_request request; + NSS_STATUS ret; + int af; + + ZERO_STRUCT(response); + ZERO_STRUCT(request); + + /* I assume there that AI_ADDRCONFIG cases are handled in nss + frontend code, at least it seems done so in solaris... + + we will give NO_DATA for pure IPv6; IPv4 will be returned for + AF_INET or for AF_INET6 and AI_ALL|AI_V4MAPPED we have to map + IPv4 to IPv6. + */ +#if defined(AF_INET6) +#ifdef HAVE_NSS_XBYY_KEY_IPNODE + af = argp->key.ipnode.af_family; + if(af == AF_INET6 && argp->key.ipnode.flags == 0) { + argp->h_errno = NO_DATA; + return NSS_STATUS_UNAVAIL; + } +#else + /* I'm not that sure if this is correct, but... */ + af = AF_INET6; +#endif +#endif + + strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1); + request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0'; + + if( (ret = winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response)) + == NSS_STATUS_SUCCESS ) { + ret = parse_response(af, argp, &response); + } + + winbindd_free_response(&response); + return ret; +} + +static NSS_STATUS +_nss_winbind_hosts_getbyname(nss_backend_t* be, void *args) +{ + nss_XbyY_args_t *argp = (nss_XbyY_args_t*) args; + struct winbindd_response response; + struct winbindd_request request; + NSS_STATUS ret; + + ZERO_STRUCT(response); + ZERO_STRUCT(request); + + strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1); + request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0'; + + if( (ret = winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response)) + == NSS_STATUS_SUCCESS ) { + ret = parse_response(AF_INET, argp, &response); + } + + winbindd_free_response(&response); + return ret; +} + +static NSS_STATUS +_nss_winbind_hosts_getbyaddr(nss_backend_t* be, void *args) +{ + NSS_STATUS ret; + struct winbindd_response response; + struct winbindd_request request; + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)args; + const char *p; + + ZERO_STRUCT(response); + ZERO_STRUCT(request); + +#if defined(AF_INET6) + /* winbindd currently does not resolve IPv6 */ + if(argp->key.hostaddr.type == AF_INET6) { + argp->h_errno = NO_DATA; + return NSS_STATUS_UNAVAIL; + } + + p = inet_ntop(argp->key.hostaddr.type, argp->key.hostaddr.addr, + request.data.winsreq, sizeof request.data.winsreq); +#else + snprintf(request.data.winsreq, sizeof request.data.winsreq, + "%u.%u.%u.%u", + ((unsigned char *)argp->key.hostaddr.addr)[0], + ((unsigned char *)argp->key.hostaddr.addr)[1], + ((unsigned char *)argp->key.hostaddr.addr)[2], + ((unsigned char *)argp->key.hostaddr.addr)[3]); +#endif + + ret = winbindd_request_response(WINBINDD_WINS_BYIP, &request, &response); + + if( ret == NSS_STATUS_SUCCESS) { + parse_response(argp->key.hostaddr.type, argp, &response); + } + winbindd_free_response(&response); + return ret; +} + +/* winbind does not provide setent, getent, endent for wins */ +static NSS_STATUS +_nss_winbind_common_endent(nss_backend_t* be, void *args) +{ + return (NSS_STATUS_UNAVAIL); +} + +static NSS_STATUS +_nss_winbind_common_setent(nss_backend_t* be, void *args) +{ + return (NSS_STATUS_UNAVAIL); +} + +static NSS_STATUS +_nss_winbind_common_getent(nss_backend_t* be, void *args) +{ + return (NSS_STATUS_UNAVAIL); +} + +static nss_backend_t* +_nss_winbind_common_constr (nss_backend_op_t ops[], int n_ops) +{ + nss_backend_t* be; + + if(!(be = SMB_MALLOC_P(nss_backend_t)) ) + return NULL; + + be->ops = ops; + be->n_ops = n_ops; + + return be; +} + +static NSS_STATUS +_nss_winbind_common_destr (nss_backend_t* be, void* args) +{ + SAFE_FREE(be); + return NSS_STATUS_SUCCESS; +} + +static nss_backend_op_t ipnodes_ops[] = { + _nss_winbind_common_destr, + _nss_winbind_common_endent, + _nss_winbind_common_setent, + _nss_winbind_common_getent, + _nss_winbind_ipnodes_getbyname, + _nss_winbind_hosts_getbyaddr, +}; + +nss_backend_t * +_nss_winbind_ipnodes_constr(dummy1, dummy2, dummy3) + const char *dummy1, *dummy2, *dummy3; +{ + return (_nss_winbind_common_constr(ipnodes_ops, + sizeof (ipnodes_ops) / sizeof (ipnodes_ops[0]))); +} + +static nss_backend_op_t host_ops[] = { + _nss_winbind_common_destr, + _nss_winbind_common_endent, + _nss_winbind_common_setent, + _nss_winbind_common_getent, + _nss_winbind_hosts_getbyname, + _nss_winbind_hosts_getbyaddr, +}; + +nss_backend_t * +_nss_winbind_hosts_constr(dummy1, dummy2, dummy3) + const char *dummy1, *dummy2, *dummy3; +{ + return (_nss_winbind_common_constr(host_ops, + sizeof (host_ops) / sizeof (host_ops[0]))); +} + +#endif /* defined(SUNOS5) */ +#endif /* defined(HAVE_NSS_COMMON_H) || defined(HPUX) */ |