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.
31 #include <sys/types.h>
32 #include <sys/param.h>
38 #include <sys/syslog.h>
40 #include "winbind_nss_config.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 #define NSS_ARGS(args) ((nss_XbyY_args_t *)args)
57 * HP-UX 11 has no definiton of the nss_groupsbymem structure. This
58 * definition is taken from the nss_ldap project at:
59 * http://www.padl.com/OSS/nss_ldap.html
62 struct nss_groupsbymem
{
67 int (*str2ent
)(const char *instr
, int instr_len
, void *ent
,
68 char *buffer
, int buflen
);
69 nss_status_t (*process_cstr
)(const char *instr
, int instr_len
,
70 struct nss_groupsbymem
*);
76 #define make_pwent_str(dest, src) \
78 if((dest = get_static(buffer, buflen, strlen(src)+1)) == NULL) \
81 NSS_DEBUG("ERANGE error"); \
82 return NSS_STATUS_TRYAGAIN; \
87 static NSS_STATUS
_nss_winbind_setpwent_solwrap (nss_backend_t
* be
, void* args
)
89 NSS_DEBUG("_nss_winbind_setpwent_solwrap");
90 return _nss_winbind_setpwent();
94 _nss_winbind_endpwent_solwrap (nss_backend_t
* be
, void *args
)
96 NSS_DEBUG("_nss_winbind_endpwent_solwrap");
97 return _nss_winbind_endpwent();
101 _nss_winbind_getpwent_solwrap (nss_backend_t
* be
, void *args
)
104 char* buffer
= NSS_ARGS(args
)->buf
.buffer
;
105 int buflen
= NSS_ARGS(args
)->buf
.buflen
;
106 struct passwd
* result
= (struct passwd
*) NSS_ARGS(args
)->buf
.result
;
107 int* errnop
= &NSS_ARGS(args
)->erange
;
110 ret
= _nss_winbind_getpwent_r(result
, buffer
,
113 if(ret
== NSS_STATUS_SUCCESS
)
115 snprintf(logmsg
, 79, "_nss_winbind_getpwent_solwrap: Returning user: %s\n",
118 NSS_ARGS(args
)->returnval
= (void*) result
;
120 snprintf(logmsg
, 79, "_nss_winbind_getpwent_solwrap: Returning error: %d.\n",ret
);
128 _nss_winbind_getpwnam_solwrap (nss_backend_t
* be
, void* args
)
131 struct passwd
* result
= (struct passwd
*) NSS_ARGS(args
)->buf
.result
;
133 NSS_DEBUG("_nss_winbind_getpwnam_solwrap");
135 ret
= _nss_winbind_getpwnam_r (NSS_ARGS(args
)->key
.name
,
137 NSS_ARGS(args
)->buf
.buffer
,
138 NSS_ARGS(args
)->buf
.buflen
,
139 &NSS_ARGS(args
)->erange
);
140 if(ret
== NSS_STATUS_SUCCESS
)
141 NSS_ARGS(args
)->returnval
= (void*) result
;
147 _nss_winbind_getpwuid_solwrap(nss_backend_t
* be
, void* args
)
150 struct passwd
* result
= (struct passwd
*) NSS_ARGS(args
)->buf
.result
;
152 NSS_DEBUG("_nss_winbind_getpwuid_solwrap");
153 ret
= _nss_winbind_getpwuid_r (NSS_ARGS(args
)->key
.uid
,
155 NSS_ARGS(args
)->buf
.buffer
,
156 NSS_ARGS(args
)->buf
.buflen
,
157 &NSS_ARGS(args
)->erange
);
158 if(ret
== NSS_STATUS_SUCCESS
)
159 NSS_ARGS(args
)->returnval
= (void*) result
;
164 static NSS_STATUS
_nss_winbind_passwd_destr (nss_backend_t
* be
, void *args
)
167 NSS_DEBUG("_nss_winbind_passwd_destr");
168 return NSS_STATUS_SUCCESS
;
171 static nss_backend_op_t passwd_ops
[] =
173 _nss_winbind_passwd_destr
,
174 _nss_winbind_endpwent_solwrap
, /* NSS_DBOP_ENDENT */
175 _nss_winbind_setpwent_solwrap
, /* NSS_DBOP_SETENT */
176 _nss_winbind_getpwent_solwrap
, /* NSS_DBOP_GETENT */
177 _nss_winbind_getpwnam_solwrap
, /* NSS_DBOP_PASSWD_BYNAME */
178 _nss_winbind_getpwuid_solwrap
/* NSS_DBOP_PASSWD_BYUID */
182 _nss_winbind_passwd_constr (const char* db_name
,
183 const char* src_name
,
184 const char* cfg_args
)
188 if(!(be
= SMB_MALLOC_P(nss_backend_t
)) )
191 be
->ops
= passwd_ops
;
192 be
->n_ops
= sizeof(passwd_ops
) / sizeof(nss_backend_op_t
);
194 NSS_DEBUG("Initialized nss_winbind passwd backend");
198 /*****************************************************************
199 GROUP database backend
200 *****************************************************************/
202 static NSS_STATUS
_nss_winbind_setgrent_solwrap (nss_backend_t
* be
, void* args
)
204 NSS_DEBUG("_nss_winbind_setgrent_solwrap");
205 return _nss_winbind_setgrent();
209 _nss_winbind_endgrent_solwrap (nss_backend_t
* be
, void *args
)
211 NSS_DEBUG("_nss_winbind_endgrent_solwrap");
212 return _nss_winbind_endgrent();
216 _nss_winbind_getgrent_solwrap(nss_backend_t
* be
, void* args
)
219 char* buffer
= NSS_ARGS(args
)->buf
.buffer
;
220 int buflen
= NSS_ARGS(args
)->buf
.buflen
;
221 struct group
* result
= (struct group
*) NSS_ARGS(args
)->buf
.result
;
222 int* errnop
= &NSS_ARGS(args
)->erange
;
225 ret
= _nss_winbind_getgrent_r(result
, buffer
,
228 if(ret
== NSS_STATUS_SUCCESS
)
230 snprintf(logmsg
, 79, "_nss_winbind_getgrent_solwrap: Returning group: %s\n", result
->gr_name
);
232 NSS_ARGS(args
)->returnval
= (void*) result
;
234 snprintf(logmsg
, 79, "_nss_winbind_getgrent_solwrap: Returning error: %d.\n", ret
);
243 _nss_winbind_getgrnam_solwrap(nss_backend_t
* be
, void* args
)
246 struct group
* result
= (struct group
*) NSS_ARGS(args
)->buf
.result
;
248 NSS_DEBUG("_nss_winbind_getgrnam_solwrap");
249 ret
= _nss_winbind_getgrnam_r(NSS_ARGS(args
)->key
.name
,
251 NSS_ARGS(args
)->buf
.buffer
,
252 NSS_ARGS(args
)->buf
.buflen
,
253 &NSS_ARGS(args
)->erange
);
255 if(ret
== NSS_STATUS_SUCCESS
)
256 NSS_ARGS(args
)->returnval
= (void*) result
;
262 _nss_winbind_getgrgid_solwrap(nss_backend_t
* be
, void* args
)
265 struct group
* result
= (struct group
*) NSS_ARGS(args
)->buf
.result
;
267 NSS_DEBUG("_nss_winbind_getgrgid_solwrap");
268 ret
= _nss_winbind_getgrgid_r (NSS_ARGS(args
)->key
.gid
,
270 NSS_ARGS(args
)->buf
.buffer
,
271 NSS_ARGS(args
)->buf
.buflen
,
272 &NSS_ARGS(args
)->erange
);
274 if(ret
== NSS_STATUS_SUCCESS
)
275 NSS_ARGS(args
)->returnval
= (void*) result
;
281 _nss_winbind_getgroupsbymember_solwrap(nss_backend_t
* be
, void* args
)
284 struct nss_groupsbymem
*gmem
= (struct nss_groupsbymem
*)args
;
286 NSS_DEBUG("_nss_winbind_getgroupsbymember");
288 _nss_winbind_initgroups_dyn(gmem
->username
,
289 gmem
->gid_array
[0], /* Primary Group */
297 * If the maximum number of gids have been found, return
298 * SUCCESS so the switch engine will stop searching. Otherwise
299 * return NOTFOUND so nsswitch will continue to get groups
300 * from the remaining database backends specified in the
301 * nsswitch.conf file.
303 return (gmem
->numgids
== gmem
->maxgids
? NSS_STATUS_SUCCESS
: NSS_STATUS_NOTFOUND
);
307 _nss_winbind_group_destr (nss_backend_t
* be
, void* args
)
310 NSS_DEBUG("_nss_winbind_group_destr");
311 return NSS_STATUS_SUCCESS
;
314 static nss_backend_op_t group_ops
[] =
316 _nss_winbind_group_destr
,
317 _nss_winbind_endgrent_solwrap
,
318 _nss_winbind_setgrent_solwrap
,
319 _nss_winbind_getgrent_solwrap
,
320 _nss_winbind_getgrnam_solwrap
,
321 _nss_winbind_getgrgid_solwrap
,
322 _nss_winbind_getgroupsbymember_solwrap
326 _nss_winbind_group_constr (const char* db_name
,
327 const char* src_name
,
328 const char* cfg_args
)
332 if(!(be
= SMB_MALLOC_P(nss_backend_t
)) )
336 be
->n_ops
= sizeof(group_ops
) / sizeof(nss_backend_op_t
);
338 NSS_DEBUG("Initialized nss_winbind group backend");
342 /*****************************************************************
343 hosts and ipnodes backend
344 *****************************************************************/
345 #if defined(SUNOS5) /* not compatible with HP-UX */
347 /* this parser is shared between get*byname and get*byaddr, as key type
348 in request is stored in different locations, I had to provide the
349 address family as an argument, caller must free the winbind response. */
352 parse_response(int af
, nss_XbyY_args_t
* argp
, struct winbindd_response
*response
)
354 struct hostent
*he
= (struct hostent
*)argp
->buf
.result
;
355 char *buffer
= argp
->buf
.buffer
;
356 int buflen
= argp
->buf
.buflen
;
362 struct in_addr
*addrp
;
363 struct in6_addr
*addrp6
;
366 /* response is tab separated list of ip addresses with hostname
367 and newline at the end. so at first we will strip newline
368 then construct list of addresses for hostent.
370 p
= strchr(response
->data
.winsresp
, '\n');
372 else {/* it must be broken */
373 argp
->h_errno
= NO_DATA
;
374 return NSS_STATUS_UNAVAIL
;
377 for(; p
!= response
->data
.winsresp
; p
--) {
378 if(*p
== '\t') addrcount
++;
381 if(addrcount
== 0) {/* it must be broken */
382 argp
->h_errno
= NO_DATA
;
383 return NSS_STATUS_UNAVAIL
;
386 /* allocate space for addresses and h_addr_list */
388 if( he
->h_addrtype
== AF_INET
) {
389 he
->h_length
= sizeof(struct in_addr
);
390 addrp
= (struct in_addr
*)ROUND_DOWN(buffer
+ buflen
,
391 sizeof(struct in_addr
));
393 he
->h_addr_list
= (char **)ROUND_DOWN(addrp
, sizeof (char*));
394 he
->h_addr_list
-= addrcount
+1;
396 he
->h_length
= sizeof(struct in6_addr
);
397 addrp6
= (struct in6_addr
*)ROUND_DOWN(buffer
+ buflen
,
398 sizeof(struct in6_addr
));
400 he
->h_addr_list
= (char **)ROUND_DOWN(addrp6
, sizeof (char*));
401 he
->h_addr_list
-= addrcount
+1;
404 /* buffer too small?! */
405 if((char *)he
->h_addr_list
< buffer
) {
407 return NSS_STR_PARSE_ERANGE
;
410 data
= response
->data
.winsresp
;
411 for( i
= 0; i
< addrcount
; i
++) {
412 p
= strchr(data
, '\t');
413 if(p
== NULL
) break; /* just in case... */
415 *p
= '\0'; /* terminate the string */
416 if(he
->h_addrtype
== AF_INET
) {
417 he
->h_addr_list
[i
] = (char *)&addrp
[i
];
418 if ((addrp
[i
].s_addr
= inet_addr(data
)) == -1) {
420 return NSS_STR_PARSE_ERANGE
;
423 he
->h_addr_list
[i
] = (char *)&addrp6
[i
];
424 if (strchr(data
, ':') != 0) {
425 if (inet_pton(AF_INET6
, data
, &addrp6
[i
]) != 1) {
427 return NSS_STR_PARSE_ERANGE
;
431 if ((in4
.s_addr
= inet_addr(data
)) == -1) {
433 return NSS_STR_PARSE_ERANGE
;
435 IN6_INADDR_TO_V4MAPPED(&in4
, &addrp6
[i
]);
441 he
->h_addr_list
[i
] = (char *)NULL
;
444 if(len
> he
->h_addr_list
- (char**)argp
->buf
.buffer
) {
446 return NSS_STR_PARSE_ERANGE
;
449 /* this is a bit overkill to use _nss_netdb_aliases here since
450 there seems to be no aliases but it will create all data for us */
451 he
->h_aliases
= _nss_netdb_aliases(data
, len
, buffer
,
452 ((char*) he
->h_addr_list
) - buffer
);
453 if(he
->h_aliases
== NULL
) {
455 ret
= NSS_STR_PARSE_ERANGE
;
457 he
->h_name
= he
->h_aliases
[0];
459 ret
= NSS_STR_PARSE_SUCCESS
;
462 argp
->returnval
= (void*)he
;
467 _nss_winbind_ipnodes_getbyname(nss_backend_t
* be
, void *args
)
469 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*) args
;
470 struct winbindd_response response
;
471 struct winbindd_request request
;
475 ZERO_STRUCT(response
);
476 ZERO_STRUCT(request
);
478 /* I assume there that AI_ADDRCONFIG cases are handled in nss
479 frontend code, at least it seems done so in solaris...
481 we will give NO_DATA for pure IPv6; IPv4 will be returned for
482 AF_INET or for AF_INET6 and AI_ALL|AI_V4MAPPED we have to map
485 #ifdef HAVE_NSS_XBYY_KEY_IPNODE
486 af
= argp
->key
.ipnode
.af_family
;
487 if(af
== AF_INET6
&& argp
->key
.ipnode
.flags
== 0) {
488 argp
->h_errno
= NO_DATA
;
489 return NSS_STATUS_UNAVAIL
;
492 /* I'm not that sure if this is correct, but... */
496 strncpy(request
.data
.winsreq
, argp
->key
.name
, sizeof(request
.data
.winsreq
) - 1);
497 request
.data
.winsreq
[sizeof(request
.data
.winsreq
) - 1] = '\0';
499 if( (ret
= winbindd_request_response(WINBINDD_WINS_BYNAME
, &request
, &response
))
500 == NSS_STATUS_SUCCESS
) {
501 ret
= parse_response(af
, argp
, &response
);
504 free_response(&response
);
509 _nss_winbind_hosts_getbyname(nss_backend_t
* be
, void *args
)
511 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*) args
;
512 struct winbindd_response response
;
513 struct winbindd_request request
;
516 ZERO_STRUCT(response
);
517 ZERO_STRUCT(request
);
519 strncpy(request
.data
.winsreq
, argp
->key
.name
, sizeof(request
.data
.winsreq
) - 1);
520 request
.data
.winsreq
[sizeof(request
.data
.winsreq
) - 1] = '\0';
522 if( (ret
= winbindd_request_response(WINBINDD_WINS_BYNAME
, &request
, &response
))
523 == NSS_STATUS_SUCCESS
) {
524 ret
= parse_response(AF_INET
, argp
, &response
);
527 free_response(&response
);
532 _nss_winbind_hosts_getbyaddr(nss_backend_t
* be
, void *args
)
535 struct winbindd_response response
;
536 struct winbindd_request request
;
537 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*)args
;
540 ZERO_STRUCT(response
);
541 ZERO_STRUCT(request
);
543 /* winbindd currently does not resolve IPv6 */
544 if(argp
->key
.hostaddr
.type
== AF_INET6
) {
545 argp
->h_errno
= NO_DATA
;
546 return NSS_STATUS_UNAVAIL
;
549 p
= inet_ntop(argp
->key
.hostaddr
.type
, argp
->key
.hostaddr
.addr
,
550 request
.data
.winsreq
, INET6_ADDRSTRLEN
);
552 ret
= winbindd_request_response(WINBINDD_WINS_BYIP
, &request
, &response
);
554 if( ret
== NSS_STATUS_SUCCESS
) {
555 parse_response(argp
->key
.hostaddr
.type
, argp
, &response
);
557 free_response(&response
);
561 /* winbind does not provide setent, getent, endent for wins */
563 _nss_winbind_common_endent(nss_backend_t
* be
, void *args
)
565 return (NSS_STATUS_UNAVAIL
);
569 _nss_winbind_common_setent(nss_backend_t
* be
, void *args
)
571 return (NSS_STATUS_UNAVAIL
);
575 _nss_winbind_common_getent(nss_backend_t
* be
, void *args
)
577 return (NSS_STATUS_UNAVAIL
);
580 static nss_backend_t
*
581 _nss_winbind_common_constr (nss_backend_op_t ops
[], int n_ops
)
585 if(!(be
= SMB_MALLOC_P(nss_backend_t
)) )
595 _nss_winbind_common_destr (nss_backend_t
* be
, void* args
)
598 return NSS_STATUS_SUCCESS
;
601 static nss_backend_op_t ipnodes_ops
[] = {
602 _nss_winbind_common_destr
,
603 _nss_winbind_common_endent
,
604 _nss_winbind_common_setent
,
605 _nss_winbind_common_getent
,
606 _nss_winbind_ipnodes_getbyname
,
607 _nss_winbind_hosts_getbyaddr
,
611 _nss_winbind_ipnodes_constr(dummy1
, dummy2
, dummy3
)
612 const char *dummy1
, *dummy2
, *dummy3
;
614 return (_nss_winbind_common_constr(ipnodes_ops
,
615 sizeof (ipnodes_ops
) / sizeof (ipnodes_ops
[0])));
618 static nss_backend_op_t host_ops
[] = {
619 _nss_winbind_common_destr
,
620 _nss_winbind_common_endent
,
621 _nss_winbind_common_setent
,
622 _nss_winbind_common_getent
,
623 _nss_winbind_hosts_getbyname
,
624 _nss_winbind_hosts_getbyaddr
,
628 _nss_winbind_hosts_constr(dummy1
, dummy2
, dummy3
)
629 const char *dummy1
, *dummy2
, *dummy3
;
631 return (_nss_winbind_common_constr(host_ops
,
632 sizeof (host_ops
) / sizeof (host_ops
[0])));
635 #endif /* defined(SUNOS5) */
636 #endif /* defined(HAVE_NSS_COMMON_H) || defined(HPUX) */