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
;
266 _nss_winbind_getgrgid_solwrap(nss_backend_t
* be
, void* args
)
269 struct group
* result
= (struct group
*) NSS_ARGS(args
)->buf
.result
;
271 NSS_DEBUG("_nss_winbind_getgrgid_solwrap");
272 ret
= _nss_winbind_getgrgid_r (NSS_ARGS(args
)->key
.gid
,
274 NSS_ARGS(args
)->buf
.buffer
,
275 NSS_ARGS(args
)->buf
.buflen
,
276 &NSS_ARGS(args
)->erange
);
278 if(ret
== NSS_STATUS_SUCCESS
)
279 NSS_ARGS(args
)->returnval
= (void*) result
;
285 _nss_winbind_getgroupsbymember_solwrap(nss_backend_t
* be
, void* args
)
288 struct nss_groupsbymem
*gmem
= (struct nss_groupsbymem
*)args
;
289 long int numgids
= gmem
->numgids
;
290 long int maxgids
= gmem
->maxgids
;
292 NSS_DEBUG("_nss_winbind_getgroupsbymember");
294 _nss_winbind_initgroups_dyn(gmem
->username
,
295 gmem
->gid_array
[0], /* Primary Group */
302 gmem
->numgids
= numgids
;
303 gmem
->maxgids
= maxgids
;
306 * If the maximum number of gids have been found, return
307 * SUCCESS so the switch engine will stop searching. Otherwise
308 * return NOTFOUND so nsswitch will continue to get groups
309 * from the remaining database backends specified in the
310 * nsswitch.conf file.
312 return (gmem
->numgids
== gmem
->maxgids
? NSS_STATUS_SUCCESS
: NSS_STATUS_NOTFOUND
);
316 _nss_winbind_group_destr (nss_backend_t
* be
, void* args
)
319 NSS_DEBUG("_nss_winbind_group_destr");
320 return NSS_STATUS_SUCCESS
;
323 static nss_backend_op_t group_ops
[] =
325 _nss_winbind_group_destr
,
326 _nss_winbind_endgrent_solwrap
,
327 _nss_winbind_setgrent_solwrap
,
328 _nss_winbind_getgrent_solwrap
,
329 _nss_winbind_getgrnam_solwrap
,
330 _nss_winbind_getgrgid_solwrap
,
331 _nss_winbind_getgroupsbymember_solwrap
335 _nss_winbind_group_constr (const char* db_name
,
336 const char* src_name
,
337 const char* cfg_args
)
341 if(!(be
= SMB_MALLOC_P(nss_backend_t
)) )
345 be
->n_ops
= sizeof(group_ops
) / sizeof(nss_backend_op_t
);
347 NSS_DEBUG("Initialized nss_winbind group backend");
351 /*****************************************************************
352 hosts and ipnodes backend
353 *****************************************************************/
354 #if defined(SUNOS5) /* not compatible with HP-UX */
356 /* this parser is shared between get*byname and get*byaddr, as key type
357 in request is stored in different locations, I had to provide the
358 address family as an argument, caller must free the winbind response. */
361 parse_response(int af
, nss_XbyY_args_t
* argp
, struct winbindd_response
*response
)
363 struct hostent
*he
= (struct hostent
*)argp
->buf
.result
;
364 char *buffer
= argp
->buf
.buffer
;
365 int buflen
= argp
->buf
.buflen
;
371 struct in_addr
*addrp
;
372 #if defined(AF_INET6)
373 struct in6_addr
*addrp6
;
377 /* response is tab separated list of ip addresses with hostname
378 and newline at the end. so at first we will strip newline
379 then construct list of addresses for hostent.
381 p
= strchr(response
->data
.winsresp
, '\n');
383 else {/* it must be broken */
384 argp
->h_errno
= NO_DATA
;
385 return NSS_STATUS_UNAVAIL
;
388 for(; p
!= response
->data
.winsresp
; p
--) {
389 if(*p
== '\t') addrcount
++;
392 if(addrcount
== 0) {/* it must be broken */
393 argp
->h_errno
= NO_DATA
;
394 return NSS_STATUS_UNAVAIL
;
397 /* allocate space for addresses and h_addr_list */
399 if( he
->h_addrtype
== AF_INET
) {
400 he
->h_length
= sizeof(struct in_addr
);
401 addrp
= (struct in_addr
*)ROUND_DOWN(buffer
+ buflen
,
402 sizeof(struct in_addr
));
404 he
->h_addr_list
= (char **)ROUND_DOWN(addrp
, sizeof (char*));
405 he
->h_addr_list
-= addrcount
+1;
407 #if defined(AF_INET6)
409 he
->h_length
= sizeof(struct in6_addr
);
410 addrp6
= (struct in6_addr
*)ROUND_DOWN(buffer
+ buflen
,
411 sizeof(struct in6_addr
));
413 he
->h_addr_list
= (char **)ROUND_DOWN(addrp6
, sizeof (char*));
414 he
->h_addr_list
-= addrcount
+1;
418 /* buffer too small?! */
419 if((char *)he
->h_addr_list
< buffer
) {
421 return NSS_STR_PARSE_ERANGE
;
424 data
= response
->data
.winsresp
;
425 for( i
= 0; i
< addrcount
; i
++) {
426 p
= strchr(data
, '\t');
427 if(p
== NULL
) break; /* just in case... */
429 *p
= '\0'; /* terminate the string */
430 if(he
->h_addrtype
== AF_INET
) {
431 he
->h_addr_list
[i
] = (char *)&addrp
[i
];
432 if ((addrp
[i
].s_addr
= inet_addr(data
)) == -1) {
434 return NSS_STR_PARSE_ERANGE
;
437 #if defined(AF_INET6)
439 he
->h_addr_list
[i
] = (char *)&addrp6
[i
];
440 if (strchr(data
, ':') != 0) {
441 if (inet_pton(AF_INET6
, data
, &addrp6
[i
]) != 1) {
443 return NSS_STR_PARSE_ERANGE
;
447 if ((in4
.s_addr
= inet_addr(data
)) == -1) {
449 return NSS_STR_PARSE_ERANGE
;
451 IN6_INADDR_TO_V4MAPPED(&in4
, &addrp6
[i
]);
458 he
->h_addr_list
[i
] = (char *)NULL
;
461 if(len
> he
->h_addr_list
- (char**)argp
->buf
.buffer
) {
463 return NSS_STR_PARSE_ERANGE
;
466 /* this is a bit overkill to use _nss_netdb_aliases here since
467 there seems to be no aliases but it will create all data for us */
468 he
->h_aliases
= _nss_netdb_aliases(data
, len
, buffer
,
469 ((char*) he
->h_addr_list
) - buffer
);
470 if(he
->h_aliases
== NULL
) {
472 ret
= NSS_STR_PARSE_ERANGE
;
474 he
->h_name
= he
->h_aliases
[0];
476 ret
= NSS_STR_PARSE_SUCCESS
;
479 argp
->returnval
= (void*)he
;
484 _nss_winbind_ipnodes_getbyname(nss_backend_t
* be
, void *args
)
486 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*) args
;
487 struct winbindd_response response
;
488 struct winbindd_request request
;
492 ZERO_STRUCT(response
);
493 ZERO_STRUCT(request
);
495 /* I assume there that AI_ADDRCONFIG cases are handled in nss
496 frontend code, at least it seems done so in solaris...
498 we will give NO_DATA for pure IPv6; IPv4 will be returned for
499 AF_INET or for AF_INET6 and AI_ALL|AI_V4MAPPED we have to map
502 #if defined(AF_INET6)
503 #ifdef HAVE_NSS_XBYY_KEY_IPNODE
504 af
= argp
->key
.ipnode
.af_family
;
505 if(af
== AF_INET6
&& argp
->key
.ipnode
.flags
== 0) {
506 argp
->h_errno
= NO_DATA
;
507 return NSS_STATUS_UNAVAIL
;
510 /* I'm not that sure if this is correct, but... */
515 strncpy(request
.data
.winsreq
, argp
->key
.name
, sizeof(request
.data
.winsreq
) - 1);
516 request
.data
.winsreq
[sizeof(request
.data
.winsreq
) - 1] = '\0';
518 if( (ret
= winbindd_request_response(WINBINDD_WINS_BYNAME
, &request
, &response
))
519 == NSS_STATUS_SUCCESS
) {
520 ret
= parse_response(af
, argp
, &response
);
523 winbindd_free_response(&response
);
528 _nss_winbind_hosts_getbyname(nss_backend_t
* be
, void *args
)
530 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*) args
;
531 struct winbindd_response response
;
532 struct winbindd_request request
;
535 ZERO_STRUCT(response
);
536 ZERO_STRUCT(request
);
538 strncpy(request
.data
.winsreq
, argp
->key
.name
, sizeof(request
.data
.winsreq
) - 1);
539 request
.data
.winsreq
[sizeof(request
.data
.winsreq
) - 1] = '\0';
541 if( (ret
= winbindd_request_response(WINBINDD_WINS_BYNAME
, &request
, &response
))
542 == NSS_STATUS_SUCCESS
) {
543 ret
= parse_response(AF_INET
, argp
, &response
);
546 winbindd_free_response(&response
);
551 _nss_winbind_hosts_getbyaddr(nss_backend_t
* be
, void *args
)
554 struct winbindd_response response
;
555 struct winbindd_request request
;
556 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*)args
;
559 ZERO_STRUCT(response
);
560 ZERO_STRUCT(request
);
562 #if defined(AF_INET6)
563 /* winbindd currently does not resolve IPv6 */
564 if(argp
->key
.hostaddr
.type
== AF_INET6
) {
565 argp
->h_errno
= NO_DATA
;
566 return NSS_STATUS_UNAVAIL
;
569 p
= inet_ntop(argp
->key
.hostaddr
.type
, argp
->key
.hostaddr
.addr
,
570 request
.data
.winsreq
, sizeof request
.data
.winsreq
);
572 snprintf(request
.data
.winsreq
, sizeof request
.data
.winsreq
,
574 ((unsigned char *)argp
->key
.hostaddr
.addr
)[0],
575 ((unsigned char *)argp
->key
.hostaddr
.addr
)[1],
576 ((unsigned char *)argp
->key
.hostaddr
.addr
)[2],
577 ((unsigned char *)argp
->key
.hostaddr
.addr
)[3]);
580 ret
= winbindd_request_response(WINBINDD_WINS_BYIP
, &request
, &response
);
582 if( ret
== NSS_STATUS_SUCCESS
) {
583 parse_response(argp
->key
.hostaddr
.type
, argp
, &response
);
585 winbindd_free_response(&response
);
589 /* winbind does not provide setent, getent, endent for wins */
591 _nss_winbind_common_endent(nss_backend_t
* be
, void *args
)
593 return (NSS_STATUS_UNAVAIL
);
597 _nss_winbind_common_setent(nss_backend_t
* be
, void *args
)
599 return (NSS_STATUS_UNAVAIL
);
603 _nss_winbind_common_getent(nss_backend_t
* be
, void *args
)
605 return (NSS_STATUS_UNAVAIL
);
608 static nss_backend_t
*
609 _nss_winbind_common_constr (nss_backend_op_t ops
[], int n_ops
)
613 if(!(be
= SMB_MALLOC_P(nss_backend_t
)) )
623 _nss_winbind_common_destr (nss_backend_t
* be
, void* args
)
626 return NSS_STATUS_SUCCESS
;
629 static nss_backend_op_t ipnodes_ops
[] = {
630 _nss_winbind_common_destr
,
631 _nss_winbind_common_endent
,
632 _nss_winbind_common_setent
,
633 _nss_winbind_common_getent
,
634 _nss_winbind_ipnodes_getbyname
,
635 _nss_winbind_hosts_getbyaddr
,
639 _nss_winbind_ipnodes_constr(dummy1
, dummy2
, dummy3
)
640 const char *dummy1
, *dummy2
, *dummy3
;
642 return (_nss_winbind_common_constr(ipnodes_ops
,
643 sizeof (ipnodes_ops
) / sizeof (ipnodes_ops
[0])));
646 static nss_backend_op_t host_ops
[] = {
647 _nss_winbind_common_destr
,
648 _nss_winbind_common_endent
,
649 _nss_winbind_common_setent
,
650 _nss_winbind_common_getent
,
651 _nss_winbind_hosts_getbyname
,
652 _nss_winbind_hosts_getbyaddr
,
656 _nss_winbind_hosts_constr(dummy1
, dummy2
, dummy3
)
657 const char *dummy1
, *dummy2
, *dummy3
;
659 return (_nss_winbind_common_constr(host_ops
,
660 sizeof (host_ops
) / sizeof (host_ops
[0])));
663 #endif /* defined(SUNOS5) */
664 #endif /* defined(HAVE_NSS_COMMON_H) || defined(HPUX) */