2 Solaris NSS wrapper for winbind
5 Based on Luke Howard's ldap_nss module for Solaris
9 Copyright (C) 1997-2003 Luke Howard.
10 This file is part of the nss_ldap library.
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.
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.
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/>.
30 #include "winbind_client.h"
32 #include <sys/types.h>
33 #include <sys/param.h>
39 #include <sys/syslog.h>
42 #if defined(HAVE_NSS_COMMON_H) || defined(HPUX)
47 #define NSS_DEBUG(str) syslog(LOG_DEBUG, "nss_winbind: %s", str);
49 #define NSS_DEBUG(str) ;
52 #if !defined(SMB_MALLOC_P)
53 #define SMB_MALLOC_P(type) (type *)malloc(sizeof(type))
56 #define NSS_ARGS(args) ((nss_XbyY_args_t *)args)
61 * HP-UX 11 has no definiton of the nss_groupsbymem structure. This
62 * definition is taken from the nss_ldap project at:
63 * http://www.padl.com/OSS/nss_ldap.html
66 struct nss_groupsbymem
{
71 int (*str2ent
)(const char *instr
, int instr_len
, void *ent
,
72 char *buffer
, int buflen
);
73 nss_status_t (*process_cstr
)(const char *instr
, int instr_len
,
74 struct nss_groupsbymem
*);
80 #define make_pwent_str(dest, src) \
82 if((dest = get_static(buffer, buflen, strlen(src)+1)) == NULL) \
85 NSS_DEBUG("ERANGE error"); \
86 return NSS_STATUS_TRYAGAIN; \
91 static NSS_STATUS
_nss_winbind_setpwent_solwrap (nss_backend_t
* be
, void* args
)
93 NSS_DEBUG("_nss_winbind_setpwent_solwrap");
94 return _nss_winbind_setpwent();
98 _nss_winbind_endpwent_solwrap (nss_backend_t
* be
, void *args
)
100 NSS_DEBUG("_nss_winbind_endpwent_solwrap");
101 return _nss_winbind_endpwent();
105 _nss_winbind_getpwent_solwrap (nss_backend_t
* be
, void *args
)
108 char* buffer
= NSS_ARGS(args
)->buf
.buffer
;
109 int buflen
= NSS_ARGS(args
)->buf
.buflen
;
110 struct passwd
* result
= (struct passwd
*) NSS_ARGS(args
)->buf
.result
;
111 int* errnop
= &NSS_ARGS(args
)->erange
;
114 ret
= _nss_winbind_getpwent_r(result
, buffer
,
117 if(ret
== NSS_STATUS_SUCCESS
)
119 snprintf(logmsg
, 79, "_nss_winbind_getpwent_solwrap: Returning user: %s\n",
122 NSS_ARGS(args
)->returnval
= (void*) result
;
124 snprintf(logmsg
, 79, "_nss_winbind_getpwent_solwrap: Returning error: %d.\n",ret
);
132 _nss_winbind_getpwnam_solwrap (nss_backend_t
* be
, void* args
)
135 struct passwd
* result
= (struct passwd
*) NSS_ARGS(args
)->buf
.result
;
137 NSS_DEBUG("_nss_winbind_getpwnam_solwrap");
139 ret
= _nss_winbind_getpwnam_r (NSS_ARGS(args
)->key
.name
,
141 NSS_ARGS(args
)->buf
.buffer
,
142 NSS_ARGS(args
)->buf
.buflen
,
143 &NSS_ARGS(args
)->erange
);
144 if(ret
== NSS_STATUS_SUCCESS
)
145 NSS_ARGS(args
)->returnval
= (void*) result
;
151 _nss_winbind_getpwuid_solwrap(nss_backend_t
* be
, void* args
)
154 struct passwd
* result
= (struct passwd
*) NSS_ARGS(args
)->buf
.result
;
156 NSS_DEBUG("_nss_winbind_getpwuid_solwrap");
157 ret
= _nss_winbind_getpwuid_r (NSS_ARGS(args
)->key
.uid
,
159 NSS_ARGS(args
)->buf
.buffer
,
160 NSS_ARGS(args
)->buf
.buflen
,
161 &NSS_ARGS(args
)->erange
);
162 if(ret
== NSS_STATUS_SUCCESS
)
163 NSS_ARGS(args
)->returnval
= (void*) result
;
168 static NSS_STATUS
_nss_winbind_passwd_destr (nss_backend_t
* be
, void *args
)
171 NSS_DEBUG("_nss_winbind_passwd_destr");
172 return NSS_STATUS_SUCCESS
;
175 static nss_backend_op_t passwd_ops
[] =
177 _nss_winbind_passwd_destr
,
178 _nss_winbind_endpwent_solwrap
, /* NSS_DBOP_ENDENT */
179 _nss_winbind_setpwent_solwrap
, /* NSS_DBOP_SETENT */
180 _nss_winbind_getpwent_solwrap
, /* NSS_DBOP_GETENT */
181 _nss_winbind_getpwnam_solwrap
, /* NSS_DBOP_PASSWD_BYNAME */
182 _nss_winbind_getpwuid_solwrap
/* NSS_DBOP_PASSWD_BYUID */
186 _nss_winbind_passwd_constr (const char* db_name
,
187 const char* src_name
,
188 const char* cfg_args
)
192 if(!(be
= SMB_MALLOC_P(nss_backend_t
)) )
195 be
->ops
= passwd_ops
;
196 be
->n_ops
= sizeof(passwd_ops
) / sizeof(nss_backend_op_t
);
198 NSS_DEBUG("Initialized nss_winbind passwd backend");
202 /*****************************************************************
203 GROUP database backend
204 *****************************************************************/
206 static NSS_STATUS
_nss_winbind_setgrent_solwrap (nss_backend_t
* be
, void* args
)
208 NSS_DEBUG("_nss_winbind_setgrent_solwrap");
209 return _nss_winbind_setgrent();
213 _nss_winbind_endgrent_solwrap (nss_backend_t
* be
, void *args
)
215 NSS_DEBUG("_nss_winbind_endgrent_solwrap");
216 return _nss_winbind_endgrent();
220 _nss_winbind_getgrent_solwrap(nss_backend_t
* be
, void* args
)
223 char* buffer
= NSS_ARGS(args
)->buf
.buffer
;
224 int buflen
= NSS_ARGS(args
)->buf
.buflen
;
225 struct group
* result
= (struct group
*) NSS_ARGS(args
)->buf
.result
;
226 int* errnop
= &NSS_ARGS(args
)->erange
;
229 ret
= _nss_winbind_getgrent_r(result
, buffer
,
232 if(ret
== NSS_STATUS_SUCCESS
)
234 snprintf(logmsg
, 79, "_nss_winbind_getgrent_solwrap: Returning group: %s\n", result
->gr_name
);
236 NSS_ARGS(args
)->returnval
= (void*) result
;
238 snprintf(logmsg
, 79, "_nss_winbind_getgrent_solwrap: Returning error: %d.\n", ret
);
247 _nss_winbind_getgrnam_solwrap(nss_backend_t
* be
, void* args
)
250 struct group
* result
= (struct group
*) NSS_ARGS(args
)->buf
.result
;
252 NSS_DEBUG("_nss_winbind_getgrnam_solwrap");
253 ret
= _nss_winbind_getgrnam_r(NSS_ARGS(args
)->key
.name
,
255 NSS_ARGS(args
)->buf
.buffer
,
256 NSS_ARGS(args
)->buf
.buflen
,
257 &NSS_ARGS(args
)->erange
);
259 if(ret
== NSS_STATUS_SUCCESS
)
260 NSS_ARGS(args
)->returnval
= (void*) result
;
262 if (NSS_ARGS(args
)->erange
== ERANGE
&& ret
== NSS_STATUS_TRYAGAIN
)
263 return NSS_STATUS_UNAVAIL
;
269 _nss_winbind_getgrgid_solwrap(nss_backend_t
* be
, void* args
)
272 struct group
* result
= (struct group
*) NSS_ARGS(args
)->buf
.result
;
274 NSS_DEBUG("_nss_winbind_getgrgid_solwrap");
275 ret
= _nss_winbind_getgrgid_r (NSS_ARGS(args
)->key
.gid
,
277 NSS_ARGS(args
)->buf
.buffer
,
278 NSS_ARGS(args
)->buf
.buflen
,
279 &NSS_ARGS(args
)->erange
);
281 if(ret
== NSS_STATUS_SUCCESS
)
282 NSS_ARGS(args
)->returnval
= (void*) result
;
284 if (NSS_ARGS(args
)->erange
== ERANGE
&& ret
== NSS_STATUS_TRYAGAIN
)
285 return NSS_STATUS_UNAVAIL
;
291 _nss_winbind_getgroupsbymember_solwrap(nss_backend_t
* be
, void* args
)
294 struct nss_groupsbymem
*gmem
= (struct nss_groupsbymem
*)args
;
295 long int numgids
= gmem
->numgids
;
296 long int maxgids
= gmem
->maxgids
;
298 NSS_DEBUG("_nss_winbind_getgroupsbymember");
300 _nss_winbind_initgroups_dyn(gmem
->username
,
301 gmem
->gid_array
[0], /* Primary Group */
308 gmem
->numgids
= numgids
;
309 gmem
->maxgids
= maxgids
;
312 * If the maximum number of gids have been found, return
313 * SUCCESS so the switch engine will stop searching. Otherwise
314 * return NOTFOUND so nsswitch will continue to get groups
315 * from the remaining database backends specified in the
316 * nsswitch.conf file.
318 return (gmem
->numgids
== gmem
->maxgids
? NSS_STATUS_SUCCESS
: NSS_STATUS_NOTFOUND
);
322 _nss_winbind_group_destr (nss_backend_t
* be
, void* args
)
325 NSS_DEBUG("_nss_winbind_group_destr");
326 return NSS_STATUS_SUCCESS
;
329 static nss_backend_op_t group_ops
[] =
331 _nss_winbind_group_destr
,
332 _nss_winbind_endgrent_solwrap
,
333 _nss_winbind_setgrent_solwrap
,
334 _nss_winbind_getgrent_solwrap
,
335 _nss_winbind_getgrnam_solwrap
,
336 _nss_winbind_getgrgid_solwrap
,
337 _nss_winbind_getgroupsbymember_solwrap
341 _nss_winbind_group_constr (const char* db_name
,
342 const char* src_name
,
343 const char* cfg_args
)
347 if(!(be
= SMB_MALLOC_P(nss_backend_t
)) )
351 be
->n_ops
= sizeof(group_ops
) / sizeof(nss_backend_op_t
);
353 NSS_DEBUG("Initialized nss_winbind group backend");
357 /*****************************************************************
358 hosts and ipnodes backend
359 *****************************************************************/
360 #if defined(SUNOS5) /* not compatible with HP-UX */
362 /* this parser is shared between get*byname and get*byaddr, as key type
363 in request is stored in different locations, I had to provide the
364 address family as an argument, caller must free the winbind response. */
367 parse_response(int af
, nss_XbyY_args_t
* argp
, struct winbindd_response
*response
)
369 struct hostent
*he
= (struct hostent
*)argp
->buf
.result
;
370 char *buffer
= argp
->buf
.buffer
;
371 int buflen
= argp
->buf
.buflen
;
377 struct in_addr
*addrp
;
378 #if defined(AF_INET6)
379 struct in6_addr
*addrp6
;
383 /* response is tab separated list of ip addresses with hostname
384 and newline at the end. so at first we will strip newline
385 then construct list of addresses for hostent.
387 p
= strchr(response
->data
.winsresp
, '\n');
389 else {/* it must be broken */
390 argp
->h_errno
= NO_DATA
;
391 return NSS_STATUS_UNAVAIL
;
394 for(; p
!= response
->data
.winsresp
; p
--) {
395 if(*p
== '\t') addrcount
++;
398 if(addrcount
== 0) {/* it must be broken */
399 argp
->h_errno
= NO_DATA
;
400 return NSS_STATUS_UNAVAIL
;
403 /* allocate space for addresses and h_addr_list */
405 if( he
->h_addrtype
== AF_INET
) {
406 he
->h_length
= sizeof(struct in_addr
);
407 addrp
= (struct in_addr
*)ROUND_DOWN(buffer
+ buflen
,
408 sizeof(struct in_addr
));
410 he
->h_addr_list
= (char **)ROUND_DOWN(addrp
, sizeof (char*));
411 he
->h_addr_list
-= addrcount
+1;
413 #if defined(AF_INET6)
415 he
->h_length
= sizeof(struct in6_addr
);
416 addrp6
= (struct in6_addr
*)ROUND_DOWN(buffer
+ buflen
,
417 sizeof(struct in6_addr
));
419 he
->h_addr_list
= (char **)ROUND_DOWN(addrp6
, sizeof (char*));
420 he
->h_addr_list
-= addrcount
+1;
424 /* buffer too small?! */
425 if((char *)he
->h_addr_list
< buffer
) {
427 return NSS_STR_PARSE_ERANGE
;
430 data
= response
->data
.winsresp
;
431 for( i
= 0; i
< addrcount
; i
++) {
432 p
= strchr(data
, '\t');
433 if(p
== NULL
) break; /* just in case... */
435 *p
= '\0'; /* terminate the string */
436 if(he
->h_addrtype
== AF_INET
) {
437 he
->h_addr_list
[i
] = (char *)&addrp
[i
];
438 if ((addrp
[i
].s_addr
= inet_addr(data
)) == -1) {
440 return NSS_STR_PARSE_ERANGE
;
443 #if defined(AF_INET6)
445 he
->h_addr_list
[i
] = (char *)&addrp6
[i
];
446 if (strchr(data
, ':') != 0) {
447 if (inet_pton(AF_INET6
, data
, &addrp6
[i
]) != 1) {
449 return NSS_STR_PARSE_ERANGE
;
453 if ((in4
.s_addr
= inet_addr(data
)) == -1) {
455 return NSS_STR_PARSE_ERANGE
;
457 IN6_INADDR_TO_V4MAPPED(&in4
, &addrp6
[i
]);
464 he
->h_addr_list
[i
] = (char *)NULL
;
467 if(len
> he
->h_addr_list
- (char**)argp
->buf
.buffer
) {
469 return NSS_STR_PARSE_ERANGE
;
472 /* this is a bit overkill to use _nss_netdb_aliases here since
473 there seems to be no aliases but it will create all data for us */
474 he
->h_aliases
= _nss_netdb_aliases(data
, len
, buffer
,
475 ((char*) he
->h_addr_list
) - buffer
);
476 if(he
->h_aliases
== NULL
) {
478 ret
= NSS_STR_PARSE_ERANGE
;
480 he
->h_name
= he
->h_aliases
[0];
482 ret
= NSS_STR_PARSE_SUCCESS
;
485 argp
->returnval
= (void*)he
;
490 _nss_winbind_ipnodes_getbyname(nss_backend_t
* be
, void *args
)
492 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*) args
;
493 struct winbindd_response response
;
494 struct winbindd_request request
;
498 ZERO_STRUCT(response
);
499 ZERO_STRUCT(request
);
501 /* I assume there that AI_ADDRCONFIG cases are handled in nss
502 frontend code, at least it seems done so in solaris...
504 we will give NO_DATA for pure IPv6; IPv4 will be returned for
505 AF_INET or for AF_INET6 and AI_ALL|AI_V4MAPPED we have to map
508 #if defined(AF_INET6)
509 #ifdef HAVE_NSS_XBYY_KEY_IPNODE
510 af
= argp
->key
.ipnode
.af_family
;
511 if(af
== AF_INET6
&& argp
->key
.ipnode
.flags
== 0) {
512 argp
->h_errno
= NO_DATA
;
513 return NSS_STATUS_UNAVAIL
;
516 /* I'm not that sure if this is correct, but... */
521 strncpy(request
.data
.winsreq
, argp
->key
.name
, sizeof(request
.data
.winsreq
) - 1);
522 request
.data
.winsreq
[sizeof(request
.data
.winsreq
) - 1] = '\0';
524 if( (ret
= winbindd_request_response(NULL
, WINBINDD_WINS_BYNAME
,
525 &request
, &response
))
526 == NSS_STATUS_SUCCESS
) {
527 ret
= parse_response(af
, argp
, &response
);
530 winbindd_free_response(&response
);
535 _nss_winbind_hosts_getbyname(nss_backend_t
* be
, void *args
)
537 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*) args
;
538 struct winbindd_response response
;
539 struct winbindd_request request
;
542 ZERO_STRUCT(response
);
543 ZERO_STRUCT(request
);
545 strncpy(request
.data
.winsreq
, argp
->key
.name
, sizeof(request
.data
.winsreq
) - 1);
546 request
.data
.winsreq
[sizeof(request
.data
.winsreq
) - 1] = '\0';
548 if( (ret
= winbindd_request_response(NULL
, WINBINDD_WINS_BYNAME
,
549 &request
, &response
))
550 == NSS_STATUS_SUCCESS
) {
551 ret
= parse_response(AF_INET
, argp
, &response
);
554 winbindd_free_response(&response
);
559 _nss_winbind_hosts_getbyaddr(nss_backend_t
* be
, void *args
)
562 struct winbindd_response response
;
563 struct winbindd_request request
;
564 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*)args
;
567 ZERO_STRUCT(response
);
568 ZERO_STRUCT(request
);
570 #if defined(AF_INET6)
571 /* winbindd currently does not resolve IPv6 */
572 if(argp
->key
.hostaddr
.type
== AF_INET6
) {
573 argp
->h_errno
= NO_DATA
;
574 return NSS_STATUS_UNAVAIL
;
577 p
= inet_ntop(argp
->key
.hostaddr
.type
, argp
->key
.hostaddr
.addr
,
578 request
.data
.winsreq
, sizeof request
.data
.winsreq
);
580 snprintf(request
.data
.winsreq
, sizeof request
.data
.winsreq
,
582 ((unsigned char *)argp
->key
.hostaddr
.addr
)[0],
583 ((unsigned char *)argp
->key
.hostaddr
.addr
)[1],
584 ((unsigned char *)argp
->key
.hostaddr
.addr
)[2],
585 ((unsigned char *)argp
->key
.hostaddr
.addr
)[3]);
588 ret
= winbindd_request_response(NULL
, WINBINDD_WINS_BYIP
,
589 &request
, &response
);
591 if( ret
== NSS_STATUS_SUCCESS
) {
592 parse_response(argp
->key
.hostaddr
.type
, argp
, &response
);
594 winbindd_free_response(&response
);
598 /* winbind does not provide setent, getent, endent for wins */
600 _nss_winbind_common_endent(nss_backend_t
* be
, void *args
)
602 return (NSS_STATUS_UNAVAIL
);
606 _nss_winbind_common_setent(nss_backend_t
* be
, void *args
)
608 return (NSS_STATUS_UNAVAIL
);
612 _nss_winbind_common_getent(nss_backend_t
* be
, void *args
)
614 return (NSS_STATUS_UNAVAIL
);
617 static nss_backend_t
*
618 _nss_winbind_common_constr (nss_backend_op_t ops
[], int n_ops
)
622 if(!(be
= SMB_MALLOC_P(nss_backend_t
)) )
632 _nss_winbind_common_destr (nss_backend_t
* be
, void* args
)
635 return NSS_STATUS_SUCCESS
;
638 static nss_backend_op_t ipnodes_ops
[] = {
639 _nss_winbind_common_destr
,
640 _nss_winbind_common_endent
,
641 _nss_winbind_common_setent
,
642 _nss_winbind_common_getent
,
643 _nss_winbind_ipnodes_getbyname
,
644 _nss_winbind_hosts_getbyaddr
,
648 _nss_winbind_ipnodes_constr(dummy1
, dummy2
, dummy3
)
649 const char *dummy1
, *dummy2
, *dummy3
;
651 return (_nss_winbind_common_constr(ipnodes_ops
,
652 sizeof (ipnodes_ops
) / sizeof (ipnodes_ops
[0])));
655 static nss_backend_op_t host_ops
[] = {
656 _nss_winbind_common_destr
,
657 _nss_winbind_common_endent
,
658 _nss_winbind_common_setent
,
659 _nss_winbind_common_getent
,
660 _nss_winbind_hosts_getbyname
,
661 _nss_winbind_hosts_getbyaddr
,
665 _nss_winbind_hosts_constr(dummy1
, dummy2
, dummy3
)
666 const char *dummy1
, *dummy2
, *dummy3
;
668 return (_nss_winbind_common_constr(host_ops
,
669 sizeof (host_ops
) / sizeof (host_ops
[0])));
672 #endif /* defined(SUNOS5) */
673 #endif /* defined(HAVE_NSS_COMMON_H) || defined(HPUX) */