• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/samba-3.0.25b/source/nsswitch/
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