• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/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 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