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>
40 #include <sys/syslog.h>
43 #if defined(HAVE_NSS_COMMON_H) || defined(HPUX)
48 #define NSS_DEBUG(str) syslog(LOG_DEBUG, "nss_winbind: %s", str);
50 #define NSS_DEBUG(str) ;
53 #if !defined(SMB_MALLOC_P)
54 #define SMB_MALLOC_P(type) (type *)malloc(sizeof(type))
57 #define NSS_ARGS(args) ((nss_XbyY_args_t *)args)
62 * HP-UX 11 has no definiton of the nss_groupsbymem structure. This
63 * definition is taken from the nss_ldap project at:
64 * http://www.padl.com/OSS/nss_ldap.html
67 struct nss_groupsbymem
{
72 int (*str2ent
)(const char *instr
, int instr_len
, void *ent
,
73 char *buffer
, int buflen
);
74 nss_status_t (*process_cstr
)(const char *instr
, int instr_len
,
75 struct nss_groupsbymem
*);
81 #define make_pwent_str(dest, src) \
83 if((dest = get_static(buffer, buflen, strlen(src)+1)) == NULL) \
86 NSS_DEBUG("ERANGE error"); \
87 return NSS_STATUS_TRYAGAIN; \
92 static NSS_STATUS
_nss_winbind_setpwent_solwrap (nss_backend_t
* be
, void* args
)
94 NSS_DEBUG("_nss_winbind_setpwent_solwrap");
95 return _nss_winbind_setpwent();
99 _nss_winbind_endpwent_solwrap (nss_backend_t
* be
, void *args
)
101 NSS_DEBUG("_nss_winbind_endpwent_solwrap");
102 return _nss_winbind_endpwent();
106 _nss_winbind_getpwent_solwrap (nss_backend_t
* be
, void *args
)
109 char* buffer
= NSS_ARGS(args
)->buf
.buffer
;
110 int buflen
= NSS_ARGS(args
)->buf
.buflen
;
111 struct passwd
* result
= (struct passwd
*) NSS_ARGS(args
)->buf
.result
;
112 int* errnop
= &NSS_ARGS(args
)->erange
;
115 ret
= _nss_winbind_getpwent_r(result
, buffer
,
118 if(ret
== NSS_STATUS_SUCCESS
)
120 snprintf(logmsg
, 79, "_nss_winbind_getpwent_solwrap: Returning user: %s\n",
123 NSS_ARGS(args
)->returnval
= (void*) result
;
125 snprintf(logmsg
, 79, "_nss_winbind_getpwent_solwrap: Returning error: %d.\n",ret
);
133 _nss_winbind_getpwnam_solwrap (nss_backend_t
* be
, void* args
)
136 struct passwd
* result
= (struct passwd
*) NSS_ARGS(args
)->buf
.result
;
138 NSS_DEBUG("_nss_winbind_getpwnam_solwrap");
140 ret
= _nss_winbind_getpwnam_r (NSS_ARGS(args
)->key
.name
,
142 NSS_ARGS(args
)->buf
.buffer
,
143 NSS_ARGS(args
)->buf
.buflen
,
144 &NSS_ARGS(args
)->erange
);
145 if(ret
== NSS_STATUS_SUCCESS
)
146 NSS_ARGS(args
)->returnval
= (void*) result
;
152 _nss_winbind_getpwuid_solwrap(nss_backend_t
* be
, void* args
)
155 struct passwd
* result
= (struct passwd
*) NSS_ARGS(args
)->buf
.result
;
157 NSS_DEBUG("_nss_winbind_getpwuid_solwrap");
158 ret
= _nss_winbind_getpwuid_r (NSS_ARGS(args
)->key
.uid
,
160 NSS_ARGS(args
)->buf
.buffer
,
161 NSS_ARGS(args
)->buf
.buflen
,
162 &NSS_ARGS(args
)->erange
);
163 if(ret
== NSS_STATUS_SUCCESS
)
164 NSS_ARGS(args
)->returnval
= (void*) result
;
169 static NSS_STATUS
_nss_winbind_passwd_destr (nss_backend_t
* be
, void *args
)
172 NSS_DEBUG("_nss_winbind_passwd_destr");
173 return NSS_STATUS_SUCCESS
;
176 static nss_backend_op_t passwd_ops
[] =
178 _nss_winbind_passwd_destr
,
179 _nss_winbind_endpwent_solwrap
, /* NSS_DBOP_ENDENT */
180 _nss_winbind_setpwent_solwrap
, /* NSS_DBOP_SETENT */
181 _nss_winbind_getpwent_solwrap
, /* NSS_DBOP_GETENT */
182 _nss_winbind_getpwnam_solwrap
, /* NSS_DBOP_PASSWD_BYNAME */
183 _nss_winbind_getpwuid_solwrap
/* NSS_DBOP_PASSWD_BYUID */
187 _nss_winbind_passwd_constr (const char* db_name
,
188 const char* src_name
,
189 const char* cfg_args
)
193 if(!(be
= SMB_MALLOC_P(nss_backend_t
)) )
196 be
->ops
= passwd_ops
;
197 be
->n_ops
= sizeof(passwd_ops
) / sizeof(nss_backend_op_t
);
199 NSS_DEBUG("Initialized nss_winbind passwd backend");
203 /*****************************************************************
204 GROUP database backend
205 *****************************************************************/
207 static NSS_STATUS
_nss_winbind_setgrent_solwrap (nss_backend_t
* be
, void* args
)
209 NSS_DEBUG("_nss_winbind_setgrent_solwrap");
210 return _nss_winbind_setgrent();
214 _nss_winbind_endgrent_solwrap (nss_backend_t
* be
, void *args
)
216 NSS_DEBUG("_nss_winbind_endgrent_solwrap");
217 return _nss_winbind_endgrent();
221 _nss_winbind_getgrent_solwrap(nss_backend_t
* be
, void* args
)
224 char* buffer
= NSS_ARGS(args
)->buf
.buffer
;
225 int buflen
= NSS_ARGS(args
)->buf
.buflen
;
226 struct group
* result
= (struct group
*) NSS_ARGS(args
)->buf
.result
;
227 int* errnop
= &NSS_ARGS(args
)->erange
;
230 ret
= _nss_winbind_getgrent_r(result
, buffer
,
233 if(ret
== NSS_STATUS_SUCCESS
)
235 snprintf(logmsg
, 79, "_nss_winbind_getgrent_solwrap: Returning group: %s\n", result
->gr_name
);
237 NSS_ARGS(args
)->returnval
= (void*) result
;
239 snprintf(logmsg
, 79, "_nss_winbind_getgrent_solwrap: Returning error: %d.\n", ret
);
248 _nss_winbind_getgrnam_solwrap(nss_backend_t
* be
, void* args
)
251 struct group
* result
= (struct group
*) NSS_ARGS(args
)->buf
.result
;
253 NSS_DEBUG("_nss_winbind_getgrnam_solwrap");
254 ret
= _nss_winbind_getgrnam_r(NSS_ARGS(args
)->key
.name
,
256 NSS_ARGS(args
)->buf
.buffer
,
257 NSS_ARGS(args
)->buf
.buflen
,
258 &NSS_ARGS(args
)->erange
);
260 if(ret
== NSS_STATUS_SUCCESS
)
261 NSS_ARGS(args
)->returnval
= (void*) result
;
267 _nss_winbind_getgrgid_solwrap(nss_backend_t
* be
, void* args
)
270 struct group
* result
= (struct group
*) NSS_ARGS(args
)->buf
.result
;
272 NSS_DEBUG("_nss_winbind_getgrgid_solwrap");
273 ret
= _nss_winbind_getgrgid_r (NSS_ARGS(args
)->key
.gid
,
275 NSS_ARGS(args
)->buf
.buffer
,
276 NSS_ARGS(args
)->buf
.buflen
,
277 &NSS_ARGS(args
)->erange
);
279 if(ret
== NSS_STATUS_SUCCESS
)
280 NSS_ARGS(args
)->returnval
= (void*) result
;
286 _nss_winbind_getgroupsbymember_solwrap(nss_backend_t
* be
, void* args
)
289 struct nss_groupsbymem
*gmem
= (struct nss_groupsbymem
*)args
;
290 long int numgids
= gmem
->numgids
;
291 long int maxgids
= gmem
->maxgids
;
293 NSS_DEBUG("_nss_winbind_getgroupsbymember");
295 _nss_winbind_initgroups_dyn(gmem
->username
,
296 gmem
->gid_array
[0], /* Primary Group */
303 gmem
->numgids
= numgids
;
304 gmem
->maxgids
= maxgids
;
307 * If the maximum number of gids have been found, return
308 * SUCCESS so the switch engine will stop searching. Otherwise
309 * return NOTFOUND so nsswitch will continue to get groups
310 * from the remaining database backends specified in the
311 * nsswitch.conf file.
313 return (gmem
->numgids
== gmem
->maxgids
? NSS_STATUS_SUCCESS
: NSS_STATUS_NOTFOUND
);
317 _nss_winbind_group_destr (nss_backend_t
* be
, void* args
)
320 NSS_DEBUG("_nss_winbind_group_destr");
321 return NSS_STATUS_SUCCESS
;
324 static nss_backend_op_t group_ops
[] =
326 _nss_winbind_group_destr
,
327 _nss_winbind_endgrent_solwrap
,
328 _nss_winbind_setgrent_solwrap
,
329 _nss_winbind_getgrent_solwrap
,
330 _nss_winbind_getgrnam_solwrap
,
331 _nss_winbind_getgrgid_solwrap
,
332 _nss_winbind_getgroupsbymember_solwrap
336 _nss_winbind_group_constr (const char* db_name
,
337 const char* src_name
,
338 const char* cfg_args
)
342 if(!(be
= SMB_MALLOC_P(nss_backend_t
)) )
346 be
->n_ops
= sizeof(group_ops
) / sizeof(nss_backend_op_t
);
348 NSS_DEBUG("Initialized nss_winbind group backend");
352 /*****************************************************************
353 hosts and ipnodes backend
354 *****************************************************************/
355 #if defined(SUNOS5) /* not compatible with HP-UX */
357 /* this parser is shared between get*byname and get*byaddr, as key type
358 in request is stored in different locations, I had to provide the
359 address family as an argument, caller must free the winbind response. */
362 parse_response(int af
, nss_XbyY_args_t
* argp
, struct winbindd_response
*response
)
364 struct hostent
*he
= (struct hostent
*)argp
->buf
.result
;
365 char *buffer
= argp
->buf
.buffer
;
366 int buflen
= argp
->buf
.buflen
;
372 struct in_addr
*addrp
;
373 #if defined(AF_INET6)
374 struct in6_addr
*addrp6
;
378 /* response is tab separated list of ip addresses with hostname
379 and newline at the end. so at first we will strip newline
380 then construct list of addresses for hostent.
382 p
= strchr(response
->data
.winsresp
, '\n');
384 else {/* it must be broken */
385 argp
->h_errno
= NO_DATA
;
386 return NSS_STATUS_UNAVAIL
;
389 for(; p
!= response
->data
.winsresp
; p
--) {
390 if(*p
== '\t') addrcount
++;
393 if(addrcount
== 0) {/* it must be broken */
394 argp
->h_errno
= NO_DATA
;
395 return NSS_STATUS_UNAVAIL
;
398 /* allocate space for addresses and h_addr_list */
400 if( he
->h_addrtype
== AF_INET
) {
401 he
->h_length
= sizeof(struct in_addr
);
402 addrp
= (struct in_addr
*)ROUND_DOWN(buffer
+ buflen
,
403 sizeof(struct in_addr
));
405 he
->h_addr_list
= (char **)ROUND_DOWN(addrp
, sizeof (char*));
406 he
->h_addr_list
-= addrcount
+1;
408 #if defined(AF_INET6)
410 he
->h_length
= sizeof(struct in6_addr
);
411 addrp6
= (struct in6_addr
*)ROUND_DOWN(buffer
+ buflen
,
412 sizeof(struct in6_addr
));
414 he
->h_addr_list
= (char **)ROUND_DOWN(addrp6
, sizeof (char*));
415 he
->h_addr_list
-= addrcount
+1;
419 /* buffer too small?! */
420 if((char *)he
->h_addr_list
< buffer
) {
422 return NSS_STR_PARSE_ERANGE
;
425 data
= response
->data
.winsresp
;
426 for( i
= 0; i
< addrcount
; i
++) {
427 p
= strchr(data
, '\t');
428 if(p
== NULL
) break; /* just in case... */
430 *p
= '\0'; /* terminate the string */
431 if(he
->h_addrtype
== AF_INET
) {
432 he
->h_addr_list
[i
] = (char *)&addrp
[i
];
433 if ((addrp
[i
].s_addr
= inet_addr(data
)) == -1) {
435 return NSS_STR_PARSE_ERANGE
;
438 #if defined(AF_INET6)
440 he
->h_addr_list
[i
] = (char *)&addrp6
[i
];
441 if (strchr(data
, ':') != 0) {
442 if (inet_pton(AF_INET6
, data
, &addrp6
[i
]) != 1) {
444 return NSS_STR_PARSE_ERANGE
;
448 if ((in4
.s_addr
= inet_addr(data
)) == -1) {
450 return NSS_STR_PARSE_ERANGE
;
452 IN6_INADDR_TO_V4MAPPED(&in4
, &addrp6
[i
]);
459 he
->h_addr_list
[i
] = (char *)NULL
;
462 if(len
> he
->h_addr_list
- (char**)argp
->buf
.buffer
) {
464 return NSS_STR_PARSE_ERANGE
;
467 /* this is a bit overkill to use _nss_netdb_aliases here since
468 there seems to be no aliases but it will create all data for us */
469 he
->h_aliases
= _nss_netdb_aliases(data
, len
, buffer
,
470 ((char*) he
->h_addr_list
) - buffer
);
471 if(he
->h_aliases
== NULL
) {
473 ret
= NSS_STR_PARSE_ERANGE
;
475 he
->h_name
= he
->h_aliases
[0];
477 ret
= NSS_STR_PARSE_SUCCESS
;
480 argp
->returnval
= (void*)he
;
485 _nss_winbind_ipnodes_getbyname(nss_backend_t
* be
, void *args
)
487 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*) args
;
488 struct winbindd_response response
;
489 struct winbindd_request request
;
493 ZERO_STRUCT(response
);
494 ZERO_STRUCT(request
);
496 /* I assume there that AI_ADDRCONFIG cases are handled in nss
497 frontend code, at least it seems done so in solaris...
499 we will give NO_DATA for pure IPv6; IPv4 will be returned for
500 AF_INET or for AF_INET6 and AI_ALL|AI_V4MAPPED we have to map
503 #if defined(AF_INET6)
504 #ifdef HAVE_NSS_XBYY_KEY_IPNODE
505 af
= argp
->key
.ipnode
.af_family
;
506 if(af
== AF_INET6
&& argp
->key
.ipnode
.flags
== 0) {
507 argp
->h_errno
= NO_DATA
;
508 return NSS_STATUS_UNAVAIL
;
511 /* I'm not that sure if this is correct, but... */
516 strncpy(request
.data
.winsreq
, argp
->key
.name
, sizeof(request
.data
.winsreq
) - 1);
517 request
.data
.winsreq
[sizeof(request
.data
.winsreq
) - 1] = '\0';
519 if( (ret
= winbindd_request_response(WINBINDD_WINS_BYNAME
, &request
, &response
))
520 == NSS_STATUS_SUCCESS
) {
521 ret
= parse_response(af
, argp
, &response
);
524 winbindd_free_response(&response
);
529 _nss_winbind_hosts_getbyname(nss_backend_t
* be
, void *args
)
531 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*) args
;
532 struct winbindd_response response
;
533 struct winbindd_request request
;
536 ZERO_STRUCT(response
);
537 ZERO_STRUCT(request
);
539 strncpy(request
.data
.winsreq
, argp
->key
.name
, sizeof(request
.data
.winsreq
) - 1);
540 request
.data
.winsreq
[sizeof(request
.data
.winsreq
) - 1] = '\0';
542 if( (ret
= winbindd_request_response(WINBINDD_WINS_BYNAME
, &request
, &response
))
543 == NSS_STATUS_SUCCESS
) {
544 ret
= parse_response(AF_INET
, argp
, &response
);
547 winbindd_free_response(&response
);
552 _nss_winbind_hosts_getbyaddr(nss_backend_t
* be
, void *args
)
555 struct winbindd_response response
;
556 struct winbindd_request request
;
557 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*)args
;
560 ZERO_STRUCT(response
);
561 ZERO_STRUCT(request
);
563 #if defined(AF_INET6)
564 /* winbindd currently does not resolve IPv6 */
565 if(argp
->key
.hostaddr
.type
== AF_INET6
) {
566 argp
->h_errno
= NO_DATA
;
567 return NSS_STATUS_UNAVAIL
;
570 p
= inet_ntop(argp
->key
.hostaddr
.type
, argp
->key
.hostaddr
.addr
,
571 request
.data
.winsreq
, sizeof request
.data
.winsreq
);
573 snprintf(request
.data
.winsreq
, sizeof request
.data
.winsreq
,
575 ((unsigned char *)argp
->key
.hostaddr
.addr
)[0],
576 ((unsigned char *)argp
->key
.hostaddr
.addr
)[1],
577 ((unsigned char *)argp
->key
.hostaddr
.addr
)[2],
578 ((unsigned char *)argp
->key
.hostaddr
.addr
)[3]);
581 ret
= winbindd_request_response(WINBINDD_WINS_BYIP
, &request
, &response
);
583 if( ret
== NSS_STATUS_SUCCESS
) {
584 parse_response(argp
->key
.hostaddr
.type
, argp
, &response
);
586 winbindd_free_response(&response
);
590 /* winbind does not provide setent, getent, endent for wins */
592 _nss_winbind_common_endent(nss_backend_t
* be
, void *args
)
594 return (NSS_STATUS_UNAVAIL
);
598 _nss_winbind_common_setent(nss_backend_t
* be
, void *args
)
600 return (NSS_STATUS_UNAVAIL
);
604 _nss_winbind_common_getent(nss_backend_t
* be
, void *args
)
606 return (NSS_STATUS_UNAVAIL
);
609 static nss_backend_t
*
610 _nss_winbind_common_constr (nss_backend_op_t ops
[], int n_ops
)
614 if(!(be
= SMB_MALLOC_P(nss_backend_t
)) )
624 _nss_winbind_common_destr (nss_backend_t
* be
, void* args
)
627 return NSS_STATUS_SUCCESS
;
630 static nss_backend_op_t ipnodes_ops
[] = {
631 _nss_winbind_common_destr
,
632 _nss_winbind_common_endent
,
633 _nss_winbind_common_setent
,
634 _nss_winbind_common_getent
,
635 _nss_winbind_ipnodes_getbyname
,
636 _nss_winbind_hosts_getbyaddr
,
640 _nss_winbind_ipnodes_constr(dummy1
, dummy2
, dummy3
)
641 const char *dummy1
, *dummy2
, *dummy3
;
643 return (_nss_winbind_common_constr(ipnodes_ops
,
644 sizeof (ipnodes_ops
) / sizeof (ipnodes_ops
[0])));
647 static nss_backend_op_t host_ops
[] = {
648 _nss_winbind_common_destr
,
649 _nss_winbind_common_endent
,
650 _nss_winbind_common_setent
,
651 _nss_winbind_common_getent
,
652 _nss_winbind_hosts_getbyname
,
653 _nss_winbind_hosts_getbyaddr
,
657 _nss_winbind_hosts_constr(dummy1
, dummy2
, dummy3
)
658 const char *dummy1
, *dummy2
, *dummy3
;
660 return (_nss_winbind_common_constr(host_ops
,
661 sizeof (host_ops
) / sizeof (host_ops
[0])));
664 #endif /* defined(SUNOS5) */
665 #endif /* defined(HAVE_NSS_COMMON_H) || defined(HPUX) */