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/>.
29 #include "winbind_client.h"
31 #include <sys/types.h>
32 #include <sys/param.h>
38 #include <sys/syslog.h>
41 #if defined(HAVE_NSS_COMMON_H) || defined(HPUX)
46 #define NSS_DEBUG(str) syslog(LOG_DEBUG, "nss_winbind: %s", str);
48 #define NSS_DEBUG(str) ;
51 #define NSS_ARGS(args) ((nss_XbyY_args_t *)args)
56 * HP-UX 11 has no definiton of the nss_groupsbymem structure. This
57 * definition is taken from the nss_ldap project at:
58 * http://www.padl.com/OSS/nss_ldap.html
61 struct nss_groupsbymem
{
66 int (*str2ent
)(const char *instr
, int instr_len
, void *ent
,
67 char *buffer
, int buflen
);
68 nss_status_t (*process_cstr
)(const char *instr
, int instr_len
,
69 struct nss_groupsbymem
*);
75 #define make_pwent_str(dest, src) \
77 if((dest = get_static(buffer, buflen, strlen(src)+1)) == NULL) \
80 NSS_DEBUG("ERANGE error"); \
81 return NSS_STATUS_TRYAGAIN; \
86 static NSS_STATUS
_nss_winbind_setpwent_solwrap (nss_backend_t
* be
, void* args
)
88 NSS_DEBUG("_nss_winbind_setpwent_solwrap");
89 return _nss_winbind_setpwent();
93 _nss_winbind_endpwent_solwrap (nss_backend_t
* be
, void *args
)
95 NSS_DEBUG("_nss_winbind_endpwent_solwrap");
96 return _nss_winbind_endpwent();
100 _nss_winbind_getpwent_solwrap (nss_backend_t
* be
, void *args
)
103 char* buffer
= NSS_ARGS(args
)->buf
.buffer
;
104 int buflen
= NSS_ARGS(args
)->buf
.buflen
;
105 struct passwd
* result
= (struct passwd
*) NSS_ARGS(args
)->buf
.result
;
106 int* errnop
= &NSS_ARGS(args
)->erange
;
109 ret
= _nss_winbind_getpwent_r(result
, buffer
,
112 if(ret
== NSS_STATUS_SUCCESS
)
114 snprintf(logmsg
, 79, "_nss_winbind_getpwent_solwrap: Returning user: %s\n",
117 NSS_ARGS(args
)->returnval
= (void*) result
;
119 snprintf(logmsg
, 79, "_nss_winbind_getpwent_solwrap: Returning error: %d.\n",ret
);
127 _nss_winbind_getpwnam_solwrap (nss_backend_t
* be
, void* args
)
130 struct passwd
* result
= (struct passwd
*) NSS_ARGS(args
)->buf
.result
;
132 NSS_DEBUG("_nss_winbind_getpwnam_solwrap");
134 ret
= _nss_winbind_getpwnam_r (NSS_ARGS(args
)->key
.name
,
136 NSS_ARGS(args
)->buf
.buffer
,
137 NSS_ARGS(args
)->buf
.buflen
,
138 &NSS_ARGS(args
)->erange
);
139 if(ret
== NSS_STATUS_SUCCESS
)
140 NSS_ARGS(args
)->returnval
= (void*) result
;
146 _nss_winbind_getpwuid_solwrap(nss_backend_t
* be
, void* args
)
149 struct passwd
* result
= (struct passwd
*) NSS_ARGS(args
)->buf
.result
;
151 NSS_DEBUG("_nss_winbind_getpwuid_solwrap");
152 ret
= _nss_winbind_getpwuid_r (NSS_ARGS(args
)->key
.uid
,
154 NSS_ARGS(args
)->buf
.buffer
,
155 NSS_ARGS(args
)->buf
.buflen
,
156 &NSS_ARGS(args
)->erange
);
157 if(ret
== NSS_STATUS_SUCCESS
)
158 NSS_ARGS(args
)->returnval
= (void*) result
;
163 static NSS_STATUS
_nss_winbind_passwd_destr (nss_backend_t
* be
, void *args
)
166 NSS_DEBUG("_nss_winbind_passwd_destr");
167 return NSS_STATUS_SUCCESS
;
170 static nss_backend_op_t passwd_ops
[] =
172 _nss_winbind_passwd_destr
,
173 _nss_winbind_endpwent_solwrap
, /* NSS_DBOP_ENDENT */
174 _nss_winbind_setpwent_solwrap
, /* NSS_DBOP_SETENT */
175 _nss_winbind_getpwent_solwrap
, /* NSS_DBOP_GETENT */
176 _nss_winbind_getpwnam_solwrap
, /* NSS_DBOP_PASSWD_BYNAME */
177 _nss_winbind_getpwuid_solwrap
/* NSS_DBOP_PASSWD_BYUID */
181 _nss_winbind_passwd_constr (const char* db_name
,
182 const char* src_name
,
183 const char* cfg_args
)
187 if(!(be
= SMB_MALLOC_P(nss_backend_t
)) )
190 be
->ops
= passwd_ops
;
191 be
->n_ops
= sizeof(passwd_ops
) / sizeof(nss_backend_op_t
);
193 NSS_DEBUG("Initialized nss_winbind passwd backend");
197 /*****************************************************************
198 GROUP database backend
199 *****************************************************************/
201 static NSS_STATUS
_nss_winbind_setgrent_solwrap (nss_backend_t
* be
, void* args
)
203 NSS_DEBUG("_nss_winbind_setgrent_solwrap");
204 return _nss_winbind_setgrent();
208 _nss_winbind_endgrent_solwrap (nss_backend_t
* be
, void *args
)
210 NSS_DEBUG("_nss_winbind_endgrent_solwrap");
211 return _nss_winbind_endgrent();
215 _nss_winbind_getgrent_solwrap(nss_backend_t
* be
, void* args
)
218 char* buffer
= NSS_ARGS(args
)->buf
.buffer
;
219 int buflen
= NSS_ARGS(args
)->buf
.buflen
;
220 struct group
* result
= (struct group
*) NSS_ARGS(args
)->buf
.result
;
221 int* errnop
= &NSS_ARGS(args
)->erange
;
224 ret
= _nss_winbind_getgrent_r(result
, buffer
,
227 if(ret
== NSS_STATUS_SUCCESS
)
229 snprintf(logmsg
, 79, "_nss_winbind_getgrent_solwrap: Returning group: %s\n", result
->gr_name
);
231 NSS_ARGS(args
)->returnval
= (void*) result
;
233 snprintf(logmsg
, 79, "_nss_winbind_getgrent_solwrap: Returning error: %d.\n", ret
);
242 _nss_winbind_getgrnam_solwrap(nss_backend_t
* be
, void* args
)
245 struct group
* result
= (struct group
*) NSS_ARGS(args
)->buf
.result
;
247 NSS_DEBUG("_nss_winbind_getgrnam_solwrap");
248 ret
= _nss_winbind_getgrnam_r(NSS_ARGS(args
)->key
.name
,
250 NSS_ARGS(args
)->buf
.buffer
,
251 NSS_ARGS(args
)->buf
.buflen
,
252 &NSS_ARGS(args
)->erange
);
254 if(ret
== NSS_STATUS_SUCCESS
)
255 NSS_ARGS(args
)->returnval
= (void*) result
;
261 _nss_winbind_getgrgid_solwrap(nss_backend_t
* be
, void* args
)
264 struct group
* result
= (struct group
*) NSS_ARGS(args
)->buf
.result
;
266 NSS_DEBUG("_nss_winbind_getgrgid_solwrap");
267 ret
= _nss_winbind_getgrgid_r (NSS_ARGS(args
)->key
.gid
,
269 NSS_ARGS(args
)->buf
.buffer
,
270 NSS_ARGS(args
)->buf
.buflen
,
271 &NSS_ARGS(args
)->erange
);
273 if(ret
== NSS_STATUS_SUCCESS
)
274 NSS_ARGS(args
)->returnval
= (void*) result
;
280 _nss_winbind_getgroupsbymember_solwrap(nss_backend_t
* be
, void* args
)
283 struct nss_groupsbymem
*gmem
= (struct nss_groupsbymem
*)args
;
285 NSS_DEBUG("_nss_winbind_getgroupsbymember");
287 _nss_winbind_initgroups_dyn(gmem
->username
,
288 gmem
->gid_array
[0], /* Primary Group */
296 * If the maximum number of gids have been found, return
297 * SUCCESS so the switch engine will stop searching. Otherwise
298 * return NOTFOUND so nsswitch will continue to get groups
299 * from the remaining database backends specified in the
300 * nsswitch.conf file.
302 return (gmem
->numgids
== gmem
->maxgids
? NSS_STATUS_SUCCESS
: NSS_STATUS_NOTFOUND
);
306 _nss_winbind_group_destr (nss_backend_t
* be
, void* args
)
309 NSS_DEBUG("_nss_winbind_group_destr");
310 return NSS_STATUS_SUCCESS
;
313 static nss_backend_op_t group_ops
[] =
315 _nss_winbind_group_destr
,
316 _nss_winbind_endgrent_solwrap
,
317 _nss_winbind_setgrent_solwrap
,
318 _nss_winbind_getgrent_solwrap
,
319 _nss_winbind_getgrnam_solwrap
,
320 _nss_winbind_getgrgid_solwrap
,
321 _nss_winbind_getgroupsbymember_solwrap
325 _nss_winbind_group_constr (const char* db_name
,
326 const char* src_name
,
327 const char* cfg_args
)
331 if(!(be
= SMB_MALLOC_P(nss_backend_t
)) )
335 be
->n_ops
= sizeof(group_ops
) / sizeof(nss_backend_op_t
);
337 NSS_DEBUG("Initialized nss_winbind group backend");
341 /*****************************************************************
342 hosts and ipnodes backend
343 *****************************************************************/
344 #if defined(SUNOS5) /* not compatible with HP-UX */
346 /* this parser is shared between get*byname and get*byaddr, as key type
347 in request is stored in different locations, I had to provide the
348 address family as an argument, caller must free the winbind response. */
351 parse_response(int af
, nss_XbyY_args_t
* argp
, struct winbindd_response
*response
)
353 struct hostent
*he
= (struct hostent
*)argp
->buf
.result
;
354 char *buffer
= argp
->buf
.buffer
;
355 int buflen
= argp
->buf
.buflen
;
361 struct in_addr
*addrp
;
362 struct in6_addr
*addrp6
;
365 /* response is tab separated list of ip addresses with hostname
366 and newline at the end. so at first we will strip newline
367 then construct list of addresses for hostent.
369 p
= strchr(response
->data
.winsresp
, '\n');
371 else {/* it must be broken */
372 argp
->h_errno
= NO_DATA
;
373 return NSS_STATUS_UNAVAIL
;
376 for(; p
!= response
->data
.winsresp
; p
--) {
377 if(*p
== '\t') addrcount
++;
380 if(addrcount
== 0) {/* it must be broken */
381 argp
->h_errno
= NO_DATA
;
382 return NSS_STATUS_UNAVAIL
;
385 /* allocate space for addresses and h_addr_list */
387 if( he
->h_addrtype
== AF_INET
) {
388 he
->h_length
= sizeof(struct in_addr
);
389 addrp
= (struct in_addr
*)ROUND_DOWN(buffer
+ buflen
,
390 sizeof(struct in_addr
));
392 he
->h_addr_list
= (char **)ROUND_DOWN(addrp
, sizeof (char*));
393 he
->h_addr_list
-= addrcount
+1;
395 he
->h_length
= sizeof(struct in6_addr
);
396 addrp6
= (struct in6_addr
*)ROUND_DOWN(buffer
+ buflen
,
397 sizeof(struct in6_addr
));
399 he
->h_addr_list
= (char **)ROUND_DOWN(addrp6
, sizeof (char*));
400 he
->h_addr_list
-= addrcount
+1;
403 /* buffer too small?! */
404 if((char *)he
->h_addr_list
< buffer
) {
406 return NSS_STR_PARSE_ERANGE
;
409 data
= response
->data
.winsresp
;
410 for( i
= 0; i
< addrcount
; i
++) {
411 p
= strchr(data
, '\t');
412 if(p
== NULL
) break; /* just in case... */
414 *p
= '\0'; /* terminate the string */
415 if(he
->h_addrtype
== AF_INET
) {
416 he
->h_addr_list
[i
] = (char *)&addrp
[i
];
417 if ((addrp
[i
].s_addr
= inet_addr(data
)) == -1) {
419 return NSS_STR_PARSE_ERANGE
;
422 he
->h_addr_list
[i
] = (char *)&addrp6
[i
];
423 if (strchr(data
, ':') != 0) {
424 if (inet_pton(AF_INET6
, data
, &addrp6
[i
]) != 1) {
426 return NSS_STR_PARSE_ERANGE
;
430 if ((in4
.s_addr
= inet_addr(data
)) == -1) {
432 return NSS_STR_PARSE_ERANGE
;
434 IN6_INADDR_TO_V4MAPPED(&in4
, &addrp6
[i
]);
440 he
->h_addr_list
[i
] = (char *)NULL
;
443 if(len
> he
->h_addr_list
- (char**)argp
->buf
.buffer
) {
445 return NSS_STR_PARSE_ERANGE
;
448 /* this is a bit overkill to use _nss_netdb_aliases here since
449 there seems to be no aliases but it will create all data for us */
450 he
->h_aliases
= _nss_netdb_aliases(data
, len
, buffer
,
451 ((char*) he
->h_addr_list
) - buffer
);
452 if(he
->h_aliases
== NULL
) {
454 ret
= NSS_STR_PARSE_ERANGE
;
456 he
->h_name
= he
->h_aliases
[0];
458 ret
= NSS_STR_PARSE_SUCCESS
;
461 argp
->returnval
= (void*)he
;
466 _nss_winbind_ipnodes_getbyname(nss_backend_t
* be
, void *args
)
468 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*) args
;
469 struct winbindd_response response
;
470 struct winbindd_request request
;
474 ZERO_STRUCT(response
);
475 ZERO_STRUCT(request
);
477 /* I assume there that AI_ADDRCONFIG cases are handled in nss
478 frontend code, at least it seems done so in solaris...
480 we will give NO_DATA for pure IPv6; IPv4 will be returned for
481 AF_INET or for AF_INET6 and AI_ALL|AI_V4MAPPED we have to map
484 #ifdef HAVE_NSS_XBYY_KEY_IPNODE
485 af
= argp
->key
.ipnode
.af_family
;
486 if(af
== AF_INET6
&& argp
->key
.ipnode
.flags
== 0) {
487 argp
->h_errno
= NO_DATA
;
488 return NSS_STATUS_UNAVAIL
;
491 /* I'm not that sure if this is correct, but... */
495 strncpy(request
.data
.winsreq
, argp
->key
.name
, sizeof(request
.data
.winsreq
) - 1);
496 request
.data
.winsreq
[sizeof(request
.data
.winsreq
) - 1] = '\0';
498 if( (ret
= winbindd_request_response(WINBINDD_WINS_BYNAME
, &request
, &response
))
499 == NSS_STATUS_SUCCESS
) {
500 ret
= parse_response(af
, argp
, &response
);
503 winbindd_free_response(&response
);
508 _nss_winbind_hosts_getbyname(nss_backend_t
* be
, void *args
)
510 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*) args
;
511 struct winbindd_response response
;
512 struct winbindd_request request
;
515 ZERO_STRUCT(response
);
516 ZERO_STRUCT(request
);
518 strncpy(request
.data
.winsreq
, argp
->key
.name
, sizeof(request
.data
.winsreq
) - 1);
519 request
.data
.winsreq
[sizeof(request
.data
.winsreq
) - 1] = '\0';
521 if( (ret
= winbindd_request_response(WINBINDD_WINS_BYNAME
, &request
, &response
))
522 == NSS_STATUS_SUCCESS
) {
523 ret
= parse_response(AF_INET
, argp
, &response
);
526 winbindd_free_response(&response
);
531 _nss_winbind_hosts_getbyaddr(nss_backend_t
* be
, void *args
)
534 struct winbindd_response response
;
535 struct winbindd_request request
;
536 nss_XbyY_args_t
*argp
= (nss_XbyY_args_t
*)args
;
539 ZERO_STRUCT(response
);
540 ZERO_STRUCT(request
);
542 /* winbindd currently does not resolve IPv6 */
543 if(argp
->key
.hostaddr
.type
== AF_INET6
) {
544 argp
->h_errno
= NO_DATA
;
545 return NSS_STATUS_UNAVAIL
;
548 p
= inet_ntop(argp
->key
.hostaddr
.type
, argp
->key
.hostaddr
.addr
,
549 request
.data
.winsreq
, INET6_ADDRSTRLEN
);
551 ret
= winbindd_request_response(WINBINDD_WINS_BYIP
, &request
, &response
);
553 if( ret
== NSS_STATUS_SUCCESS
) {
554 parse_response(argp
->key
.hostaddr
.type
, argp
, &response
);
556 winbindd_free_response(&response
);
560 /* winbind does not provide setent, getent, endent for wins */
562 _nss_winbind_common_endent(nss_backend_t
* be
, void *args
)
564 return (NSS_STATUS_UNAVAIL
);
568 _nss_winbind_common_setent(nss_backend_t
* be
, void *args
)
570 return (NSS_STATUS_UNAVAIL
);
574 _nss_winbind_common_getent(nss_backend_t
* be
, void *args
)
576 return (NSS_STATUS_UNAVAIL
);
579 static nss_backend_t
*
580 _nss_winbind_common_constr (nss_backend_op_t ops
[], int n_ops
)
584 if(!(be
= SMB_MALLOC_P(nss_backend_t
)) )
594 _nss_winbind_common_destr (nss_backend_t
* be
, void* args
)
597 return NSS_STATUS_SUCCESS
;
600 static nss_backend_op_t ipnodes_ops
[] = {
601 _nss_winbind_common_destr
,
602 _nss_winbind_common_endent
,
603 _nss_winbind_common_setent
,
604 _nss_winbind_common_getent
,
605 _nss_winbind_ipnodes_getbyname
,
606 _nss_winbind_hosts_getbyaddr
,
610 _nss_winbind_ipnodes_constr(dummy1
, dummy2
, dummy3
)
611 const char *dummy1
, *dummy2
, *dummy3
;
613 return (_nss_winbind_common_constr(ipnodes_ops
,
614 sizeof (ipnodes_ops
) / sizeof (ipnodes_ops
[0])));
617 static nss_backend_op_t host_ops
[] = {
618 _nss_winbind_common_destr
,
619 _nss_winbind_common_endent
,
620 _nss_winbind_common_setent
,
621 _nss_winbind_common_getent
,
622 _nss_winbind_hosts_getbyname
,
623 _nss_winbind_hosts_getbyaddr
,
627 _nss_winbind_hosts_constr(dummy1
, dummy2
, dummy3
)
628 const char *dummy1
, *dummy2
, *dummy3
;
630 return (_nss_winbind_common_constr(host_ops
,
631 sizeof (host_ops
) / sizeof (host_ops
[0])));
634 #endif /* defined(SUNOS5) */
635 #endif /* defined(HAVE_NSS_COMMON_H) || defined(HPUX) */