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 static NSS_STATUS
_nss_winbind_setpwent_solwrap (nss_backend_t
* be
, void* args
)
82 NSS_DEBUG("_nss_winbind_setpwent_solwrap");
83 return _nss_winbind_setpwent();
87 _nss_winbind_endpwent_solwrap (nss_backend_t
* be
, void *args
)
89 NSS_DEBUG("_nss_winbind_endpwent_solwrap");
90 return _nss_winbind_endpwent();
94 _nss_winbind_getpwent_solwrap (nss_backend_t
* be
, void *args
)
97 char* buffer
= NSS_ARGS(args
)->buf
.buffer
;
98 int buflen
= NSS_ARGS(args
)->buf
.buflen
;
99 struct passwd
* result
= (struct passwd
*) NSS_ARGS(args
)->buf
.result
;
100 int* errnop
= &NSS_ARGS(args
)->erange
;
103 ret
= _nss_winbind_getpwent_r(result
, buffer
,
106 if(ret
== NSS_STATUS_SUCCESS
)
108 snprintf(logmsg
, 79, "_nss_winbind_getpwent_solwrap: Returning user: %s\n",
111 NSS_ARGS(args
)->returnval
= (void*) result
;
113 snprintf(logmsg
, 79, "_nss_winbind_getpwent_solwrap: Returning error: %d.\n",ret
);
121 _nss_winbind_getpwnam_solwrap (nss_backend_t
* be
, void* args
)
124 struct passwd
* result
= (struct passwd
*) NSS_ARGS(args
)->buf
.result
;
126 NSS_DEBUG("_nss_winbind_getpwnam_solwrap");
128 ret
= _nss_winbind_getpwnam_r (NSS_ARGS(args
)->key
.name
,
130 NSS_ARGS(args
)->buf
.buffer
,
131 NSS_ARGS(args
)->buf
.buflen
,
132 &NSS_ARGS(args
)->erange
);
133 if(ret
== NSS_STATUS_SUCCESS
)
134 NSS_ARGS(args
)->returnval
= (void*) result
;
140 _nss_winbind_getpwuid_solwrap(nss_backend_t
* be
, void* args
)
143 struct passwd
* result
= (struct passwd
*) NSS_ARGS(args
)->buf
.result
;
145 NSS_DEBUG("_nss_winbind_getpwuid_solwrap");
146 ret
= _nss_winbind_getpwuid_r (NSS_ARGS(args
)->key
.uid
,
148 NSS_ARGS(args
)->buf
.buffer
,
149 NSS_ARGS(args
)->buf
.buflen
,
150 &NSS_ARGS(args
)->erange
);
151 if(ret
== NSS_STATUS_SUCCESS
)
152 NSS_ARGS(args
)->returnval
= (void*) result
;
157 static NSS_STATUS
_nss_winbind_passwd_destr (nss_backend_t
* be
, void *args
)
160 NSS_DEBUG("_nss_winbind_passwd_destr");
161 return NSS_STATUS_SUCCESS
;
164 static nss_backend_op_t passwd_ops
[] =
166 _nss_winbind_passwd_destr
,
167 _nss_winbind_endpwent_solwrap
, /* NSS_DBOP_ENDENT */
168 _nss_winbind_setpwent_solwrap
, /* NSS_DBOP_SETENT */
169 _nss_winbind_getpwent_solwrap
, /* NSS_DBOP_GETENT */
170 _nss_winbind_getpwnam_solwrap
, /* NSS_DBOP_PASSWD_BYNAME */
171 _nss_winbind_getpwuid_solwrap
/* NSS_DBOP_PASSWD_BYUID */
175 _nss_winbind_passwd_constr (const char* db_name
,
176 const char* src_name
,
177 const char* cfg_args
)
181 if(!(be
= SMB_MALLOC_P(nss_backend_t
)) )
184 be
->ops
= passwd_ops
;
185 be
->n_ops
= sizeof(passwd_ops
) / sizeof(nss_backend_op_t
);
187 NSS_DEBUG("Initialized nss_winbind passwd backend");
191 /*****************************************************************
192 GROUP database backend
193 *****************************************************************/
195 static NSS_STATUS
_nss_winbind_setgrent_solwrap (nss_backend_t
* be
, void* args
)
197 NSS_DEBUG("_nss_winbind_setgrent_solwrap");
198 return _nss_winbind_setgrent();
202 _nss_winbind_endgrent_solwrap (nss_backend_t
* be
, void *args
)
204 NSS_DEBUG("_nss_winbind_endgrent_solwrap");
205 return _nss_winbind_endgrent();
209 _nss_winbind_getgrent_solwrap(nss_backend_t
* be
, void* args
)
212 char* buffer
= NSS_ARGS(args
)->buf
.buffer
;
213 int buflen
= NSS_ARGS(args
)->buf
.buflen
;
214 struct group
* result
= (struct group
*) NSS_ARGS(args
)->buf
.result
;
215 int* errnop
= &NSS_ARGS(args
)->erange
;
218 ret
= _nss_winbind_getgrent_r(result
, buffer
,
221 if(ret
== NSS_STATUS_SUCCESS
)
223 snprintf(logmsg
, 79, "_nss_winbind_getgrent_solwrap: Returning group: %s\n", result
->gr_name
);
225 NSS_ARGS(args
)->returnval
= (void*) result
;
227 snprintf(logmsg
, 79, "_nss_winbind_getgrent_solwrap: Returning error: %d.\n", ret
);
236 _nss_winbind_getgrnam_solwrap(nss_backend_t
* be
, void* args
)
239 struct group
* result
= (struct group
*) NSS_ARGS(args
)->buf
.result
;
241 NSS_DEBUG("_nss_winbind_getgrnam_solwrap");
242 ret
= _nss_winbind_getgrnam_r(NSS_ARGS(args
)->key
.name
,
244 NSS_ARGS(args
)->buf
.buffer
,
245 NSS_ARGS(args
)->buf
.buflen
,
246 &NSS_ARGS(args
)->erange
);
248 if(ret
== NSS_STATUS_SUCCESS
)
249 NSS_ARGS(args
)->returnval
= (void*) result
;
251 if (NSS_ARGS(args
)->erange
== ERANGE
&& ret
== NSS_STATUS_TRYAGAIN
)
252 return NSS_STATUS_UNAVAIL
;
258 _nss_winbind_getgrgid_solwrap(nss_backend_t
* be
, void* args
)
261 struct group
* result
= (struct group
*) NSS_ARGS(args
)->buf
.result
;
263 NSS_DEBUG("_nss_winbind_getgrgid_solwrap");
264 ret
= _nss_winbind_getgrgid_r (NSS_ARGS(args
)->key
.gid
,
266 NSS_ARGS(args
)->buf
.buffer
,
267 NSS_ARGS(args
)->buf
.buflen
,
268 &NSS_ARGS(args
)->erange
);
270 if(ret
== NSS_STATUS_SUCCESS
)
271 NSS_ARGS(args
)->returnval
= (void*) result
;
273 if (NSS_ARGS(args
)->erange
== ERANGE
&& ret
== NSS_STATUS_TRYAGAIN
)
274 return NSS_STATUS_UNAVAIL
;
280 _nss_winbind_getgroupsbymember_solwrap(nss_backend_t
* be
, void* args
)
283 struct nss_groupsbymem
*gmem
= (struct nss_groupsbymem
*)args
;
284 long int numgids
= gmem
->numgids
;
285 long int maxgids
= gmem
->maxgids
;
287 NSS_DEBUG("_nss_winbind_getgroupsbymember");
289 _nss_winbind_initgroups_dyn(gmem
->username
,
290 gmem
->gid_array
[0], /* Primary Group */
297 gmem
->numgids
= numgids
;
298 gmem
->maxgids
= maxgids
;
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.
307 return (gmem
->numgids
== gmem
->maxgids
? NSS_STATUS_SUCCESS
: NSS_STATUS_NOTFOUND
);
311 _nss_winbind_group_destr (nss_backend_t
* be
, void* args
)
314 NSS_DEBUG("_nss_winbind_group_destr");
315 return NSS_STATUS_SUCCESS
;
318 static nss_backend_op_t group_ops
[] =
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
330 _nss_winbind_group_constr (const char* db_name
,
331 const char* src_name
,
332 const char* cfg_args
)
336 if(!(be
= SMB_MALLOC_P(nss_backend_t
)) )
340 be
->n_ops
= sizeof(group_ops
) / sizeof(nss_backend_op_t
);
342 NSS_DEBUG("Initialized nss_winbind group backend");
346 /*****************************************************************
347 hosts and ipnodes backend
348 *****************************************************************/
349 #if defined(SUNOS5) /* not compatible with HP-UX */
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. */
356 parse_response(int af
, nss_XbyY_args_t
* argp
, struct winbindd_response
*response
)
358 struct hostent
*he
= (struct hostent
*)argp
->buf
.result
;
359 char *buffer
= argp
->buf
.buffer
;
360 int buflen
= argp
->buf
.buflen
;
366 struct in_addr
*addrp
;
367 #if defined(AF_INET6)
368 struct in6_addr
*addrp6
;
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.
376 p
= strchr(response
->data
.winsresp
, '\n');
378 else {/* it must be broken */
379 argp
->h_errno
= NO_DATA
;
380 return NSS_STATUS_UNAVAIL
;
383 for(; p
!= response
->data
.winsresp
; p
--) {
384 if(*p
== '\t') addrcount
++;
387 if(addrcount
== 0) {/* it must be broken */
388 argp
->h_errno
= NO_DATA
;
389 return NSS_STATUS_UNAVAIL
;
392 /* allocate space for addresses and h_addr_list */
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
));
399 he
->h_addr_list
= (char **)ROUND_DOWN(addrp
, sizeof (char*));
400 he
->h_addr_list
-= addrcount
+1;
402 #if defined(AF_INET6)
404 he
->h_length
= sizeof(struct in6_addr
);
405 addrp6
= (struct in6_addr
*)ROUND_DOWN(buffer
+ buflen
,
406 sizeof(struct in6_addr
));
408 he
->h_addr_list
= (char **)ROUND_DOWN(addrp6
, sizeof (char*));
409 he
->h_addr_list
-= addrcount
+1;
413 /* buffer too small?! */
414 if((char *)he
->h_addr_list
< buffer
) {
416 return NSS_STR_PARSE_ERANGE
;
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... */
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) {
429 return NSS_STR_PARSE_ERANGE
;
432 #if defined(AF_INET6)
434 he
->h_addr_list
[i
] = (char *)&addrp6
[i
];
435 if (strchr(data
, ':') != 0) {
436 if (inet_pton(AF_INET6
, data
, &addrp6
[i
]) != 1) {
438 return NSS_STR_PARSE_ERANGE
;
442 if ((in4
.s_addr
= inet_addr(data
)) == -1) {
444 return NSS_STR_PARSE_ERANGE
;
446 IN6_INADDR_TO_V4MAPPED(&in4
, &addrp6
[i
]);
453 he
->h_addr_list
[i
] = (char *)NULL
;
456 if(len
> he
->h_addr_list
- (char**)argp
->buf
.buffer
) {
458 return NSS_STR_PARSE_ERANGE
;
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
) {
467 ret
= NSS_STR_PARSE_ERANGE
;
469 he
->h_name
= he
->h_aliases
[0];
471 ret
= NSS_STR_PARSE_SUCCESS
;
474 argp
->returnval
= (void*)he
;
479 _nss_winbind_ipnodes_getbyname(nss_backend_t
* be
, void *args
)
481 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*) args
;
482 struct winbindd_response response
;
483 struct winbindd_request request
;
487 ZERO_STRUCT(response
);
488 ZERO_STRUCT(request
);
490 /* I assume there that AI_ADDRCONFIG cases are handled in nss
491 frontend code, at least it seems done so in solaris...
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
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
;
505 /* I'm not that sure if this is correct, but... */
510 strncpy(request
.data
.winsreq
, argp
->key
.name
, sizeof(request
.data
.winsreq
) - 1);
511 request
.data
.winsreq
[sizeof(request
.data
.winsreq
) - 1] = '\0';
513 if( (ret
= winbindd_request_response(NULL
, WINBINDD_WINS_BYNAME
,
514 &request
, &response
))
515 == NSS_STATUS_SUCCESS
) {
516 ret
= parse_response(af
, argp
, &response
);
519 winbindd_free_response(&response
);
524 _nss_winbind_hosts_getbyname(nss_backend_t
* be
, void *args
)
526 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*) args
;
527 struct winbindd_response response
;
528 struct winbindd_request request
;
531 ZERO_STRUCT(response
);
532 ZERO_STRUCT(request
);
534 strncpy(request
.data
.winsreq
, argp
->key
.name
, sizeof(request
.data
.winsreq
) - 1);
535 request
.data
.winsreq
[sizeof(request
.data
.winsreq
) - 1] = '\0';
537 if( (ret
= winbindd_request_response(NULL
, WINBINDD_WINS_BYNAME
,
538 &request
, &response
))
539 == NSS_STATUS_SUCCESS
) {
540 ret
= parse_response(AF_INET
, argp
, &response
);
543 winbindd_free_response(&response
);
548 _nss_winbind_hosts_getbyaddr(nss_backend_t
* be
, void *args
)
551 struct winbindd_response response
;
552 struct winbindd_request request
;
553 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*)args
;
556 ZERO_STRUCT(response
);
557 ZERO_STRUCT(request
);
559 #if defined(AF_INET6)
560 /* winbindd currently does not resolve IPv6 */
561 if(argp
->key
.hostaddr
.type
== AF_INET6
) {
562 argp
->h_errno
= NO_DATA
;
563 return NSS_STATUS_UNAVAIL
;
566 p
= inet_ntop(argp
->key
.hostaddr
.type
, argp
->key
.hostaddr
.addr
,
567 request
.data
.winsreq
, sizeof request
.data
.winsreq
);
569 snprintf(request
.data
.winsreq
, sizeof request
.data
.winsreq
,
571 ((unsigned char *)argp
->key
.hostaddr
.addr
)[0],
572 ((unsigned char *)argp
->key
.hostaddr
.addr
)[1],
573 ((unsigned char *)argp
->key
.hostaddr
.addr
)[2],
574 ((unsigned char *)argp
->key
.hostaddr
.addr
)[3]);
577 ret
= winbindd_request_response(NULL
, WINBINDD_WINS_BYIP
,
578 &request
, &response
);
580 if( ret
== NSS_STATUS_SUCCESS
) {
581 parse_response(argp
->key
.hostaddr
.type
, argp
, &response
);
583 winbindd_free_response(&response
);
587 /* winbind does not provide setent, getent, endent for wins */
589 _nss_winbind_common_endent(nss_backend_t
* be
, void *args
)
591 return (NSS_STATUS_UNAVAIL
);
595 _nss_winbind_common_setent(nss_backend_t
* be
, void *args
)
597 return (NSS_STATUS_UNAVAIL
);
601 _nss_winbind_common_getent(nss_backend_t
* be
, void *args
)
603 return (NSS_STATUS_UNAVAIL
);
606 static nss_backend_t
*
607 _nss_winbind_common_constr (nss_backend_op_t ops
[], int n_ops
)
611 if(!(be
= SMB_MALLOC_P(nss_backend_t
)) )
621 _nss_winbind_common_destr (nss_backend_t
* be
, void* args
)
624 return NSS_STATUS_SUCCESS
;
627 static nss_backend_op_t ipnodes_ops
[] = {
628 _nss_winbind_common_destr
,
629 _nss_winbind_common_endent
,
630 _nss_winbind_common_setent
,
631 _nss_winbind_common_getent
,
632 _nss_winbind_ipnodes_getbyname
,
633 _nss_winbind_hosts_getbyaddr
,
637 _nss_winbind_ipnodes_constr(dummy1
, dummy2
, dummy3
)
638 const char *dummy1
, *dummy2
, *dummy3
;
640 return (_nss_winbind_common_constr(ipnodes_ops
,
641 sizeof (ipnodes_ops
) / sizeof (ipnodes_ops
[0])));
644 static nss_backend_op_t host_ops
[] = {
645 _nss_winbind_common_destr
,
646 _nss_winbind_common_endent
,
647 _nss_winbind_common_setent
,
648 _nss_winbind_common_getent
,
649 _nss_winbind_hosts_getbyname
,
650 _nss_winbind_hosts_getbyaddr
,
654 _nss_winbind_hosts_constr(dummy1
, dummy2
, dummy3
)
655 const char *dummy1
, *dummy2
, *dummy3
;
657 return (_nss_winbind_common_constr(host_ops
,
658 sizeof (host_ops
) / sizeof (host_ops
[0])));
661 #endif /* defined(SUNOS5) */
662 #endif /* defined(HAVE_NSS_COMMON_H) || defined(HPUX) */