summaryrefslogtreecommitdiff
path: root/nsswitch/winbind_nss_solaris.c
diff options
context:
space:
mode:
Diffstat (limited to 'nsswitch/winbind_nss_solaris.c')
-rw-r--r--nsswitch/winbind_nss_solaris.c659
1 files changed, 659 insertions, 0 deletions
diff --git a/nsswitch/winbind_nss_solaris.c b/nsswitch/winbind_nss_solaris.c
new file mode 100644
index 0000000000..5fb37643ce
--- /dev/null
+++ b/nsswitch/winbind_nss_solaris.c
@@ -0,0 +1,659 @@
+/*
+ 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;
+ long int numgids = gmem->numgids;
+ long int maxgids = gmem->maxgids;
+
+ NSS_DEBUG("_nss_winbind_getgroupsbymember");
+
+ _nss_winbind_initgroups_dyn(gmem->username,
+ gmem->gid_array[0], /* Primary Group */
+ &numgids,
+ &maxgids,
+ &gmem->gid_array,
+ gmem->maxgids,
+ &errnop);
+
+ gmem->numgids = numgids;
+ gmem->maxgids = maxgids;
+
+ /*
+ * 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) */