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 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.
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 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.
29 #include <sys/types.h>
30 #include <sys/param.h>
36 #include <sys/syslog.h>
38 #include "winbind_nss_config.h"
40 #if defined(HAVE_NSS_COMMON_H) || defined(HPUX)
45 #define NSS_DEBUG(str) syslog(LOG_DEBUG, "nss_winbind: %s", str);
47 #define NSS_DEBUG(str) ;
50 #define NSS_ARGS(args) ((nss_XbyY_args_t *)args)
55 * HP-UX 11 has no definiton of the nss_groupsbymem structure. This
56 * definition is taken from the nss_ldap project at:
57 * http://www.padl.com/OSS/nss_ldap.html
60 struct nss_groupsbymem
{
65 int (*str2ent
)(const char *instr
, int instr_len
, void *ent
,
66 char *buffer
, int buflen
);
67 nss_status_t (*process_cstr
)(const char *instr
, int instr_len
,
68 struct nss_groupsbymem
*);
74 #define make_pwent_str(dest, src) \
76 if((dest = get_static(buffer, buflen, strlen(src)+1)) == NULL) \
79 NSS_DEBUG("ERANGE error"); \
80 return NSS_STATUS_TRYAGAIN; \
85 static NSS_STATUS
_nss_winbind_setpwent_solwrap (nss_backend_t
* be
, void* args
)
87 NSS_DEBUG("_nss_winbind_setpwent_solwrap");
88 return _nss_winbind_setpwent();
92 _nss_winbind_endpwent_solwrap (nss_backend_t
* be
, void *args
)
94 NSS_DEBUG("_nss_winbind_endpwent_solwrap");
95 return _nss_winbind_endpwent();
99 _nss_winbind_getpwent_solwrap (nss_backend_t
* be
, void *args
)
102 char* buffer
= NSS_ARGS(args
)->buf
.buffer
;
103 int buflen
= NSS_ARGS(args
)->buf
.buflen
;
104 struct passwd
* result
= (struct passwd
*) NSS_ARGS(args
)->buf
.result
;
105 int* errnop
= &NSS_ARGS(args
)->erange
;
108 ret
= _nss_winbind_getpwent_r(result
, buffer
,
111 if(ret
== NSS_STATUS_SUCCESS
)
113 snprintf(logmsg
, 79, "_nss_winbind_getpwent_solwrap: Returning user: %s\n",
116 NSS_ARGS(args
)->returnval
= (void*) result
;
118 snprintf(logmsg
, 79, "_nss_winbind_getpwent_solwrap: Returning error: %d.\n",ret
);
126 _nss_winbind_getpwnam_solwrap (nss_backend_t
* be
, void* args
)
129 struct passwd
* result
= (struct passwd
*) NSS_ARGS(args
)->buf
.result
;
131 NSS_DEBUG("_nss_winbind_getpwnam_solwrap");
133 ret
= _nss_winbind_getpwnam_r (NSS_ARGS(args
)->key
.name
,
135 NSS_ARGS(args
)->buf
.buffer
,
136 NSS_ARGS(args
)->buf
.buflen
,
137 &NSS_ARGS(args
)->erange
);
138 if(ret
== NSS_STATUS_SUCCESS
)
139 NSS_ARGS(args
)->returnval
= (void*) result
;
145 _nss_winbind_getpwuid_solwrap(nss_backend_t
* be
, void* args
)
148 struct passwd
* result
= (struct passwd
*) NSS_ARGS(args
)->buf
.result
;
150 NSS_DEBUG("_nss_winbind_getpwuid_solwrap");
151 ret
= _nss_winbind_getpwuid_r (NSS_ARGS(args
)->key
.uid
,
153 NSS_ARGS(args
)->buf
.buffer
,
154 NSS_ARGS(args
)->buf
.buflen
,
155 &NSS_ARGS(args
)->erange
);
156 if(ret
== NSS_STATUS_SUCCESS
)
157 NSS_ARGS(args
)->returnval
= (void*) result
;
162 static NSS_STATUS
_nss_winbind_passwd_destr (nss_backend_t
* be
, void *args
)
165 NSS_DEBUG("_nss_winbind_passwd_destr");
166 return NSS_STATUS_SUCCESS
;
169 static nss_backend_op_t passwd_ops
[] =
171 _nss_winbind_passwd_destr
,
172 _nss_winbind_endpwent_solwrap
, /* NSS_DBOP_ENDENT */
173 _nss_winbind_setpwent_solwrap
, /* NSS_DBOP_SETENT */
174 _nss_winbind_getpwent_solwrap
, /* NSS_DBOP_GETENT */
175 _nss_winbind_getpwnam_solwrap
, /* NSS_DBOP_PASSWD_BYNAME */
176 _nss_winbind_getpwuid_solwrap
/* NSS_DBOP_PASSWD_BYUID */
180 _nss_winbind_passwd_constr (const char* db_name
,
181 const char* src_name
,
182 const char* cfg_args
)
186 if(!(be
= (nss_backend_t
*) malloc(sizeof(nss_backend_t
))) )
189 be
->ops
= passwd_ops
;
190 be
->n_ops
= sizeof(passwd_ops
) / sizeof(nss_backend_op_t
);
192 NSS_DEBUG("Initialized nss_winbind passwd backend");
196 /*****************************************************************
197 GROUP database backend
198 *****************************************************************/
200 static NSS_STATUS
_nss_winbind_setgrent_solwrap (nss_backend_t
* be
, void* args
)
202 NSS_DEBUG("_nss_winbind_setgrent_solwrap");
203 return _nss_winbind_setgrent();
207 _nss_winbind_endgrent_solwrap (nss_backend_t
* be
, void *args
)
209 NSS_DEBUG("_nss_winbind_endgrent_solwrap");
210 return _nss_winbind_endgrent();
214 _nss_winbind_getgrent_solwrap(nss_backend_t
* be
, void* args
)
217 char* buffer
= NSS_ARGS(args
)->buf
.buffer
;
218 int buflen
= NSS_ARGS(args
)->buf
.buflen
;
219 struct group
* result
= (struct group
*) NSS_ARGS(args
)->buf
.result
;
220 int* errnop
= &NSS_ARGS(args
)->erange
;
223 ret
= _nss_winbind_getgrent_r(result
, buffer
,
226 if(ret
== NSS_STATUS_SUCCESS
)
228 snprintf(logmsg
, 79, "_nss_winbind_getgrent_solwrap: Returning group: %s\n", result
->gr_name
);
230 NSS_ARGS(args
)->returnval
= (void*) result
;
232 snprintf(logmsg
, 79, "_nss_winbind_getgrent_solwrap: Returning error: %d.\n", ret
);
241 _nss_winbind_getgrnam_solwrap(nss_backend_t
* be
, void* args
)
244 struct group
* result
= (struct group
*) NSS_ARGS(args
)->buf
.result
;
246 NSS_DEBUG("_nss_winbind_getgrnam_solwrap");
247 ret
= _nss_winbind_getgrnam_r(NSS_ARGS(args
)->key
.name
,
249 NSS_ARGS(args
)->buf
.buffer
,
250 NSS_ARGS(args
)->buf
.buflen
,
251 &NSS_ARGS(args
)->erange
);
253 if(ret
== NSS_STATUS_SUCCESS
)
254 NSS_ARGS(args
)->returnval
= (void*) result
;
260 _nss_winbind_getgrgid_solwrap(nss_backend_t
* be
, void* args
)
263 struct group
* result
= (struct group
*) NSS_ARGS(args
)->buf
.result
;
265 NSS_DEBUG("_nss_winbind_getgrgid_solwrap");
266 ret
= _nss_winbind_getgrgid_r (NSS_ARGS(args
)->key
.gid
,
268 NSS_ARGS(args
)->buf
.buffer
,
269 NSS_ARGS(args
)->buf
.buflen
,
270 &NSS_ARGS(args
)->erange
);
272 if(ret
== NSS_STATUS_SUCCESS
)
273 NSS_ARGS(args
)->returnval
= (void*) result
;
279 _nss_winbind_getgroupsbymember_solwrap(nss_backend_t
* be
, void* args
)
282 struct nss_groupsbymem
*gmem
= (struct nss_groupsbymem
*)args
;
284 NSS_DEBUG("_nss_winbind_getgroupsbymember");
286 _nss_winbind_initgroups_dyn(gmem
->username
,
287 gmem
->gid_array
[0], /* Primary Group */
295 * If the maximum number of gids have been found, return
296 * SUCCESS so the switch engine will stop searching. Otherwise
297 * return NOTFOUND so nsswitch will continue to get groups
298 * from the remaining database backends specified in the
299 * nsswitch.conf file.
301 return (gmem
->numgids
== gmem
->maxgids
? NSS_STATUS_SUCCESS
: NSS_STATUS_NOTFOUND
);
305 _nss_winbind_group_destr (nss_backend_t
* be
, void* args
)
308 NSS_DEBUG("_nss_winbind_group_destr");
309 return NSS_STATUS_SUCCESS
;
312 static nss_backend_op_t group_ops
[] =
314 _nss_winbind_group_destr
,
315 _nss_winbind_endgrent_solwrap
,
316 _nss_winbind_setgrent_solwrap
,
317 _nss_winbind_getgrent_solwrap
,
318 _nss_winbind_getgrnam_solwrap
,
319 _nss_winbind_getgrgid_solwrap
,
320 _nss_winbind_getgroupsbymember_solwrap
324 _nss_winbind_group_constr (const char* db_name
,
325 const char* src_name
,
326 const char* cfg_args
)
330 if(!(be
= (nss_backend_t
*) malloc(sizeof(nss_backend_t
))) )
334 be
->n_ops
= sizeof(group_ops
) / sizeof(nss_backend_op_t
);
336 NSS_DEBUG("Initialized nss_winbind group backend");
340 /*****************************************************************
341 hosts and ipnodes backend
342 *****************************************************************/
343 #if defined(SUNOS5) /* not compatible with HP-UX */
345 /* this parser is shared between get*byname and get*byaddr, as key type
346 in request is stored in different locations, I had to provide the
347 address family as an argument, caller must free the winbind response. */
350 parse_response(int af
, nss_XbyY_args_t
* argp
, struct winbindd_response
*response
)
352 struct hostent
*he
= (struct hostent
*)argp
->buf
.result
;
353 char *buffer
= argp
->buf
.buffer
;
354 int buflen
= argp
->buf
.buflen
;
360 struct in_addr
*addrp
;
361 struct in6_addr
*addrp6
;
364 /* response is tab separated list of ip addresses with hostname
365 and newline at the end. so at first we will strip newline
366 then construct list of addresses for hostent.
368 p
= strchr(response
->data
.winsresp
, '\n');
370 else {/* it must be broken */
371 argp
->h_errno
= NO_DATA
;
372 return NSS_STATUS_UNAVAIL
;
375 for(; p
!= response
->data
.winsresp
; p
--) {
376 if(*p
== '\t') addrcount
++;
379 if(addrcount
== 0) {/* it must be broken */
380 argp
->h_errno
= NO_DATA
;
381 return NSS_STATUS_UNAVAIL
;
384 /* allocate space for addresses and h_addr_list */
386 if( he
->h_addrtype
== AF_INET
) {
387 he
->h_length
= sizeof(struct in_addr
);
388 addrp
= (struct in_addr
*)ROUND_DOWN(buffer
+ buflen
,
389 sizeof(struct in_addr
));
391 he
->h_addr_list
= (char **)ROUND_DOWN(addrp
, sizeof (char*));
392 he
->h_addr_list
-= addrcount
+1;
394 he
->h_length
= sizeof(struct in6_addr
);
395 addrp6
= (struct in6_addr
*)ROUND_DOWN(buffer
+ buflen
,
396 sizeof(struct in6_addr
));
398 he
->h_addr_list
= (char **)ROUND_DOWN(addrp6
, sizeof (char*));
399 he
->h_addr_list
-= addrcount
+1;
402 /* buffer too small?! */
403 if((char *)he
->h_addr_list
< buffer
) {
405 return NSS_STR_PARSE_ERANGE
;
408 data
= response
->data
.winsresp
;
409 for( i
= 0; i
< addrcount
; i
++) {
410 p
= strchr(data
, '\t');
411 if(p
== NULL
) break; /* just in case... */
413 *p
= '\0'; /* terminate the string */
414 if(he
->h_addrtype
== AF_INET
) {
415 he
->h_addr_list
[i
] = (char *)&addrp
[i
];
416 if ((addrp
[i
].s_addr
= inet_addr(data
)) == -1) {
418 return NSS_STR_PARSE_ERANGE
;
421 he
->h_addr_list
[i
] = (char *)&addrp6
[i
];
422 if (strchr(data
, ':') != 0) {
423 if (inet_pton(AF_INET6
, data
, &addrp6
[i
]) != 1) {
425 return NSS_STR_PARSE_ERANGE
;
429 if ((in4
.s_addr
= inet_addr(data
)) == -1) {
431 return NSS_STR_PARSE_ERANGE
;
433 IN6_INADDR_TO_V4MAPPED(&in4
, &addrp6
[i
]);
439 he
->h_addr_list
[i
] = (char *)NULL
;
442 if(len
> he
->h_addr_list
- (char**)argp
->buf
.buffer
) {
444 return NSS_STR_PARSE_ERANGE
;
447 /* this is a bit overkill to use _nss_netdb_aliases here since
448 there seems to be no aliases but it will create all data for us */
449 he
->h_aliases
= _nss_netdb_aliases(data
, len
, buffer
,
450 ((char*) he
->h_addr_list
) - buffer
);
451 if(he
->h_aliases
== NULL
) {
453 ret
= NSS_STR_PARSE_ERANGE
;
455 he
->h_name
= he
->h_aliases
[0];
457 ret
= NSS_STR_PARSE_SUCCESS
;
460 argp
->returnval
= (void*)he
;
465 _nss_winbind_ipnodes_getbyname(nss_backend_t
* be
, void *args
)
467 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*) args
;
468 struct winbindd_response response
;
469 struct winbindd_request request
;
473 ZERO_STRUCT(response
);
474 ZERO_STRUCT(request
);
476 /* I assume there that AI_ADDRCONFIG cases are handled in nss
477 frontend code, at least it seems done so in solaris...
479 we will give NO_DATA for pure IPv6; IPv4 will be returned for
480 AF_INET or for AF_INET6 and AI_ALL|AI_V4MAPPED we have to map
483 #ifdef HAVE_NSS_XBYY_KEY_IPNODE
484 af
= argp
->key
.ipnode
.af_family
;
485 if(af
== AF_INET6
&& argp
->key
.ipnode
.flags
== 0) {
486 argp
->h_errno
= NO_DATA
;
487 return NSS_STATUS_UNAVAIL
;
490 /* I'm not that sure if this is correct, but... */
494 strncpy(request
.data
.winsreq
, argp
->key
.name
, strlen(argp
->key
.name
)) ;
496 if( (ret
= winbindd_request_response(WINBINDD_WINS_BYNAME
, &request
, &response
))
497 == NSS_STATUS_SUCCESS
) {
498 ret
= parse_response(af
, argp
, &response
);
501 free_response(&response
);
506 _nss_winbind_hosts_getbyname(nss_backend_t
* be
, void *args
)
508 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*) args
;
509 struct winbindd_response response
;
510 struct winbindd_request request
;
513 ZERO_STRUCT(response
);
514 ZERO_STRUCT(request
);
516 strncpy(request
.data
.winsreq
, argp
->key
.name
, strlen(argp
->key
.name
));
518 if( (ret
= winbindd_request_response(WINBINDD_WINS_BYNAME
, &request
, &response
))
519 == NSS_STATUS_SUCCESS
) {
520 ret
= parse_response(AF_INET
, argp
, &response
);
523 free_response(&response
);
528 _nss_winbind_hosts_getbyaddr(nss_backend_t
* be
, void *args
)
531 struct winbindd_response response
;
532 struct winbindd_request request
;
533 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*)args
;
536 ZERO_STRUCT(response
);
537 ZERO_STRUCT(request
);
539 /* winbindd currently does not resolve IPv6 */
540 if(argp
->key
.hostaddr
.type
== AF_INET6
) {
541 argp
->h_errno
= NO_DATA
;
542 return NSS_STATUS_UNAVAIL
;
545 p
= inet_ntop(argp
->key
.hostaddr
.type
, argp
->key
.hostaddr
.addr
,
546 request
.data
.winsreq
, INET6_ADDRSTRLEN
);
548 ret
= winbindd_request_response(WINBINDD_WINS_BYIP
, &request
, &response
);
550 if( ret
== NSS_STATUS_SUCCESS
) {
551 parse_response(argp
->key
.hostaddr
.type
, argp
, &response
);
553 free_response(&response
);
557 /* winbind does not provide setent, getent, endent for wins */
559 _nss_winbind_common_endent(nss_backend_t
* be
, void *args
)
561 return (NSS_STATUS_UNAVAIL
);
565 _nss_winbind_common_setent(nss_backend_t
* be
, void *args
)
567 return (NSS_STATUS_UNAVAIL
);
571 _nss_winbind_common_getent(nss_backend_t
* be
, void *args
)
573 return (NSS_STATUS_UNAVAIL
);
576 static nss_backend_t
*
577 _nss_winbind_common_constr (nss_backend_op_t ops
[], int n_ops
)
581 if(!(be
= (nss_backend_t
*) malloc(sizeof(nss_backend_t
))) )
591 _nss_winbind_common_destr (nss_backend_t
* be
, void* args
)
594 return NSS_STATUS_SUCCESS
;
597 static nss_backend_op_t ipnodes_ops
[] = {
598 _nss_winbind_common_destr
,
599 _nss_winbind_common_endent
,
600 _nss_winbind_common_setent
,
601 _nss_winbind_common_getent
,
602 _nss_winbind_ipnodes_getbyname
,
603 _nss_winbind_hosts_getbyaddr
,
607 _nss_winbind_ipnodes_constr(dummy1
, dummy2
, dummy3
)
608 const char *dummy1
, *dummy2
, *dummy3
;
610 return (_nss_winbind_common_constr(ipnodes_ops
,
611 sizeof (ipnodes_ops
) / sizeof (ipnodes_ops
[0])));
614 static nss_backend_op_t host_ops
[] = {
615 _nss_winbind_common_destr
,
616 _nss_winbind_common_endent
,
617 _nss_winbind_common_setent
,
618 _nss_winbind_common_getent
,
619 _nss_winbind_hosts_getbyname
,
620 _nss_winbind_hosts_getbyaddr
,
624 _nss_winbind_hosts_constr(dummy1
, dummy2
, dummy3
)
625 const char *dummy1
, *dummy2
, *dummy3
;
627 return (_nss_winbind_common_constr(host_ops
,
628 sizeof (host_ops
) / sizeof (host_ops
[0])));
631 #endif /* defined(SUNOS5) */
632 #endif /* defined(HAVE_NSS_COMMON_H) || defined(HPUX) */