s3/selftest: adopt config.h check from source4
[Samba.git] / nsswitch / winbind_nss_solaris.c
blobdfb87e3fdcb42c014b7e15cd3ef77b6dcdd1267a
1 /*
2 Solaris NSS wrapper for winbind
3 - Shirish Kalele 2000
5 Based on Luke Howard's ldap_nss module for Solaris
6 */
8 /*
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/>.
27 #undef DEVELOPER
30 #include "winbind_client.h"
31 #include <stdlib.h>
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <string.h>
35 #include <pwd.h>
36 #include <syslog.h>
38 #if !defined(HPUX)
39 #include <sys/syslog.h>
40 #endif /*hpux*/
42 #if defined(HAVE_NSS_COMMON_H) || defined(HPUX)
44 #undef NSS_DEBUG
46 #ifdef NSS_DEBUG
47 #define NSS_DEBUG(str) syslog(LOG_DEBUG, "nss_winbind: %s", str);
48 #else
49 #define NSS_DEBUG(str) ;
50 #endif
52 #if !defined(SMB_MALLOC_P)
53 #define SMB_MALLOC_P(type) (type *)malloc(sizeof(type))
54 #endif
56 #define NSS_ARGS(args) ((nss_XbyY_args_t *)args)
58 #ifdef HPUX
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 {
67 const char *username;
68 gid_t *gid_array;
69 int maxgids;
70 int force_slow_way;
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 *);
75 int numgids;
78 #endif /* HPUX */
80 #define make_pwent_str(dest, src) \
81 { \
82 if((dest = get_static(buffer, buflen, strlen(src)+1)) == NULL) \
83 { \
84 *errnop = ERANGE; \
85 NSS_DEBUG("ERANGE error"); \
86 return NSS_STATUS_TRYAGAIN; \
87 } \
88 strcpy(dest, src); \
91 static NSS_STATUS _nss_winbind_setpwent_solwrap (nss_backend_t* be, void* args)
93 NSS_DEBUG("_nss_winbind_setpwent_solwrap");
94 return _nss_winbind_setpwent();
97 static NSS_STATUS
98 _nss_winbind_endpwent_solwrap (nss_backend_t * be, void *args)
100 NSS_DEBUG("_nss_winbind_endpwent_solwrap");
101 return _nss_winbind_endpwent();
104 static NSS_STATUS
105 _nss_winbind_getpwent_solwrap (nss_backend_t* be, void *args)
107 NSS_STATUS ret;
108 char* buffer = NSS_ARGS(args)->buf.buffer;
109 int buflen = NSS_ARGS(args)->buf.buflen;
110 struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result;
111 int* errnop = &NSS_ARGS(args)->erange;
112 char logmsg[80];
114 ret = _nss_winbind_getpwent_r(result, buffer,
115 buflen, errnop);
117 if(ret == NSS_STATUS_SUCCESS)
119 snprintf(logmsg, 79, "_nss_winbind_getpwent_solwrap: Returning user: %s\n",
120 result->pw_name);
121 NSS_DEBUG(logmsg);
122 NSS_ARGS(args)->returnval = (void*) result;
123 } else {
124 snprintf(logmsg, 79, "_nss_winbind_getpwent_solwrap: Returning error: %d.\n",ret);
125 NSS_DEBUG(logmsg);
128 return ret;
131 static NSS_STATUS
132 _nss_winbind_getpwnam_solwrap (nss_backend_t* be, void* args)
134 NSS_STATUS ret;
135 struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result;
137 NSS_DEBUG("_nss_winbind_getpwnam_solwrap");
139 ret = _nss_winbind_getpwnam_r (NSS_ARGS(args)->key.name,
140 result,
141 NSS_ARGS(args)->buf.buffer,
142 NSS_ARGS(args)->buf.buflen,
143 &NSS_ARGS(args)->erange);
144 if(ret == NSS_STATUS_SUCCESS)
145 NSS_ARGS(args)->returnval = (void*) result;
147 return ret;
150 static NSS_STATUS
151 _nss_winbind_getpwuid_solwrap(nss_backend_t* be, void* args)
153 NSS_STATUS ret;
154 struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result;
156 NSS_DEBUG("_nss_winbind_getpwuid_solwrap");
157 ret = _nss_winbind_getpwuid_r (NSS_ARGS(args)->key.uid,
158 result,
159 NSS_ARGS(args)->buf.buffer,
160 NSS_ARGS(args)->buf.buflen,
161 &NSS_ARGS(args)->erange);
162 if(ret == NSS_STATUS_SUCCESS)
163 NSS_ARGS(args)->returnval = (void*) result;
165 return ret;
168 static NSS_STATUS _nss_winbind_passwd_destr (nss_backend_t * be, void *args)
170 SAFE_FREE(be);
171 NSS_DEBUG("_nss_winbind_passwd_destr");
172 return NSS_STATUS_SUCCESS;
175 static nss_backend_op_t passwd_ops[] =
177 _nss_winbind_passwd_destr,
178 _nss_winbind_endpwent_solwrap, /* NSS_DBOP_ENDENT */
179 _nss_winbind_setpwent_solwrap, /* NSS_DBOP_SETENT */
180 _nss_winbind_getpwent_solwrap, /* NSS_DBOP_GETENT */
181 _nss_winbind_getpwnam_solwrap, /* NSS_DBOP_PASSWD_BYNAME */
182 _nss_winbind_getpwuid_solwrap /* NSS_DBOP_PASSWD_BYUID */
185 nss_backend_t*
186 _nss_winbind_passwd_constr (const char* db_name,
187 const char* src_name,
188 const char* cfg_args)
190 nss_backend_t *be;
192 if(!(be = SMB_MALLOC_P(nss_backend_t)) )
193 return NULL;
195 be->ops = passwd_ops;
196 be->n_ops = sizeof(passwd_ops) / sizeof(nss_backend_op_t);
198 NSS_DEBUG("Initialized nss_winbind passwd backend");
199 return be;
202 /*****************************************************************
203 GROUP database backend
204 *****************************************************************/
206 static NSS_STATUS _nss_winbind_setgrent_solwrap (nss_backend_t* be, void* args)
208 NSS_DEBUG("_nss_winbind_setgrent_solwrap");
209 return _nss_winbind_setgrent();
212 static NSS_STATUS
213 _nss_winbind_endgrent_solwrap (nss_backend_t * be, void *args)
215 NSS_DEBUG("_nss_winbind_endgrent_solwrap");
216 return _nss_winbind_endgrent();
219 static NSS_STATUS
220 _nss_winbind_getgrent_solwrap(nss_backend_t* be, void* args)
222 NSS_STATUS ret;
223 char* buffer = NSS_ARGS(args)->buf.buffer;
224 int buflen = NSS_ARGS(args)->buf.buflen;
225 struct group* result = (struct group*) NSS_ARGS(args)->buf.result;
226 int* errnop = &NSS_ARGS(args)->erange;
227 char logmsg[80];
229 ret = _nss_winbind_getgrent_r(result, buffer,
230 buflen, errnop);
232 if(ret == NSS_STATUS_SUCCESS)
234 snprintf(logmsg, 79, "_nss_winbind_getgrent_solwrap: Returning group: %s\n", result->gr_name);
235 NSS_DEBUG(logmsg);
236 NSS_ARGS(args)->returnval = (void*) result;
237 } else {
238 snprintf(logmsg, 79, "_nss_winbind_getgrent_solwrap: Returning error: %d.\n", ret);
239 NSS_DEBUG(logmsg);
242 return ret;
246 static NSS_STATUS
247 _nss_winbind_getgrnam_solwrap(nss_backend_t* be, void* args)
249 NSS_STATUS ret;
250 struct group* result = (struct group*) NSS_ARGS(args)->buf.result;
252 NSS_DEBUG("_nss_winbind_getgrnam_solwrap");
253 ret = _nss_winbind_getgrnam_r(NSS_ARGS(args)->key.name,
254 result,
255 NSS_ARGS(args)->buf.buffer,
256 NSS_ARGS(args)->buf.buflen,
257 &NSS_ARGS(args)->erange);
259 if(ret == NSS_STATUS_SUCCESS)
260 NSS_ARGS(args)->returnval = (void*) result;
262 if (NSS_ARGS(args)->erange == ERANGE && ret == NSS_STATUS_TRYAGAIN)
263 return NSS_STATUS_UNAVAIL;
265 return ret;
268 static NSS_STATUS
269 _nss_winbind_getgrgid_solwrap(nss_backend_t* be, void* args)
271 NSS_STATUS ret;
272 struct group* result = (struct group*) NSS_ARGS(args)->buf.result;
274 NSS_DEBUG("_nss_winbind_getgrgid_solwrap");
275 ret = _nss_winbind_getgrgid_r (NSS_ARGS(args)->key.gid,
276 result,
277 NSS_ARGS(args)->buf.buffer,
278 NSS_ARGS(args)->buf.buflen,
279 &NSS_ARGS(args)->erange);
281 if(ret == NSS_STATUS_SUCCESS)
282 NSS_ARGS(args)->returnval = (void*) result;
284 if (NSS_ARGS(args)->erange == ERANGE && ret == NSS_STATUS_TRYAGAIN)
285 return NSS_STATUS_UNAVAIL;
287 return ret;
290 static NSS_STATUS
291 _nss_winbind_getgroupsbymember_solwrap(nss_backend_t* be, void* args)
293 int errnop;
294 struct nss_groupsbymem *gmem = (struct nss_groupsbymem *)args;
295 long int numgids = gmem->numgids;
296 long int maxgids = gmem->maxgids;
298 NSS_DEBUG("_nss_winbind_getgroupsbymember");
300 _nss_winbind_initgroups_dyn(gmem->username,
301 gmem->gid_array[0], /* Primary Group */
302 &numgids,
303 &maxgids,
304 &gmem->gid_array,
305 gmem->maxgids,
306 &errnop);
308 gmem->numgids = numgids;
309 gmem->maxgids = maxgids;
312 * If the maximum number of gids have been found, return
313 * SUCCESS so the switch engine will stop searching. Otherwise
314 * return NOTFOUND so nsswitch will continue to get groups
315 * from the remaining database backends specified in the
316 * nsswitch.conf file.
318 return (gmem->numgids == gmem->maxgids ? NSS_STATUS_SUCCESS : NSS_STATUS_NOTFOUND);
321 static NSS_STATUS
322 _nss_winbind_group_destr (nss_backend_t* be, void* args)
324 SAFE_FREE(be);
325 NSS_DEBUG("_nss_winbind_group_destr");
326 return NSS_STATUS_SUCCESS;
329 static nss_backend_op_t group_ops[] =
331 _nss_winbind_group_destr,
332 _nss_winbind_endgrent_solwrap,
333 _nss_winbind_setgrent_solwrap,
334 _nss_winbind_getgrent_solwrap,
335 _nss_winbind_getgrnam_solwrap,
336 _nss_winbind_getgrgid_solwrap,
337 _nss_winbind_getgroupsbymember_solwrap
340 nss_backend_t*
341 _nss_winbind_group_constr (const char* db_name,
342 const char* src_name,
343 const char* cfg_args)
345 nss_backend_t* be;
347 if(!(be = SMB_MALLOC_P(nss_backend_t)) )
348 return NULL;
350 be->ops = group_ops;
351 be->n_ops = sizeof(group_ops) / sizeof(nss_backend_op_t);
353 NSS_DEBUG("Initialized nss_winbind group backend");
354 return be;
357 /*****************************************************************
358 hosts and ipnodes backend
359 *****************************************************************/
360 #if defined(SUNOS5) /* not compatible with HP-UX */
362 /* this parser is shared between get*byname and get*byaddr, as key type
363 in request is stored in different locations, I had to provide the
364 address family as an argument, caller must free the winbind response. */
366 static NSS_STATUS
367 parse_response(int af, nss_XbyY_args_t* argp, struct winbindd_response *response)
369 struct hostent *he = (struct hostent *)argp->buf.result;
370 char *buffer = argp->buf.buffer;
371 int buflen = argp->buf.buflen;
372 NSS_STATUS ret;
374 char *p, *data;
375 int addrcount = 0;
376 int len = 0;
377 struct in_addr *addrp;
378 #if defined(AF_INET6)
379 struct in6_addr *addrp6;
380 #endif
381 int i;
383 /* response is tab separated list of ip addresses with hostname
384 and newline at the end. so at first we will strip newline
385 then construct list of addresses for hostent.
387 p = strchr(response->data.winsresp, '\n');
388 if(p) *p = '\0';
389 else {/* it must be broken */
390 argp->h_errno = NO_DATA;
391 return NSS_STATUS_UNAVAIL;
394 for(; p != response->data.winsresp; p--) {
395 if(*p == '\t') addrcount++;
398 if(addrcount == 0) {/* it must be broken */
399 argp->h_errno = NO_DATA;
400 return NSS_STATUS_UNAVAIL;
403 /* allocate space for addresses and h_addr_list */
404 he->h_addrtype = af;
405 if( he->h_addrtype == AF_INET) {
406 he->h_length = sizeof(struct in_addr);
407 addrp = (struct in_addr *)ROUND_DOWN(buffer + buflen,
408 sizeof(struct in_addr));
409 addrp -= addrcount;
410 he->h_addr_list = (char **)ROUND_DOWN(addrp, sizeof (char*));
411 he->h_addr_list -= addrcount+1;
413 #if defined(AF_INET6)
414 else {
415 he->h_length = sizeof(struct in6_addr);
416 addrp6 = (struct in6_addr *)ROUND_DOWN(buffer + buflen,
417 sizeof(struct in6_addr));
418 addrp6 -= addrcount;
419 he->h_addr_list = (char **)ROUND_DOWN(addrp6, sizeof (char*));
420 he->h_addr_list -= addrcount+1;
422 #endif
424 /* buffer too small?! */
425 if((char *)he->h_addr_list < buffer ) {
426 argp->erange = 1;
427 return NSS_STR_PARSE_ERANGE;
430 data = response->data.winsresp;
431 for( i = 0; i < addrcount; i++) {
432 p = strchr(data, '\t');
433 if(p == NULL) break; /* just in case... */
435 *p = '\0'; /* terminate the string */
436 if(he->h_addrtype == AF_INET) {
437 he->h_addr_list[i] = (char *)&addrp[i];
438 if ((addrp[i].s_addr = inet_addr(data)) == -1) {
439 argp->erange = 1;
440 return NSS_STR_PARSE_ERANGE;
443 #if defined(AF_INET6)
444 else {
445 he->h_addr_list[i] = (char *)&addrp6[i];
446 if (strchr(data, ':') != 0) {
447 if (inet_pton(AF_INET6, data, &addrp6[i]) != 1) {
448 argp->erange = 1;
449 return NSS_STR_PARSE_ERANGE;
451 } else {
452 struct in_addr in4;
453 if ((in4.s_addr = inet_addr(data)) == -1) {
454 argp->erange = 1;
455 return NSS_STR_PARSE_ERANGE;
457 IN6_INADDR_TO_V4MAPPED(&in4, &addrp6[i]);
460 #endif
461 data = p+1;
464 he->h_addr_list[i] = (char *)NULL;
466 len = strlen(data);
467 if(len > he->h_addr_list - (char**)argp->buf.buffer) {
468 argp->erange = 1;
469 return NSS_STR_PARSE_ERANGE;
472 /* this is a bit overkill to use _nss_netdb_aliases here since
473 there seems to be no aliases but it will create all data for us */
474 he->h_aliases = _nss_netdb_aliases(data, len, buffer,
475 ((char*) he->h_addr_list) - buffer);
476 if(he->h_aliases == NULL) {
477 argp->erange = 1;
478 ret = NSS_STR_PARSE_ERANGE;
479 } else {
480 he->h_name = he->h_aliases[0];
481 he->h_aliases++;
482 ret = NSS_STR_PARSE_SUCCESS;
485 argp->returnval = (void*)he;
486 return ret;
489 static NSS_STATUS
490 _nss_winbind_ipnodes_getbyname(nss_backend_t* be, void *args)
492 nss_XbyY_args_t *argp = (nss_XbyY_args_t*) args;
493 struct winbindd_response response;
494 struct winbindd_request request;
495 NSS_STATUS ret;
496 int af;
498 ZERO_STRUCT(response);
499 ZERO_STRUCT(request);
501 /* I assume there that AI_ADDRCONFIG cases are handled in nss
502 frontend code, at least it seems done so in solaris...
504 we will give NO_DATA for pure IPv6; IPv4 will be returned for
505 AF_INET or for AF_INET6 and AI_ALL|AI_V4MAPPED we have to map
506 IPv4 to IPv6.
508 #if defined(AF_INET6)
509 #ifdef HAVE_NSS_XBYY_KEY_IPNODE
510 af = argp->key.ipnode.af_family;
511 if(af == AF_INET6 && argp->key.ipnode.flags == 0) {
512 argp->h_errno = NO_DATA;
513 return NSS_STATUS_UNAVAIL;
515 #else
516 /* I'm not that sure if this is correct, but... */
517 af = AF_INET6;
518 #endif
519 #endif
521 strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1);
522 request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0';
524 if( (ret = winbindd_request_response(NULL, WINBINDD_WINS_BYNAME,
525 &request, &response))
526 == NSS_STATUS_SUCCESS ) {
527 ret = parse_response(af, argp, &response);
530 winbindd_free_response(&response);
531 return ret;
534 static NSS_STATUS
535 _nss_winbind_hosts_getbyname(nss_backend_t* be, void *args)
537 nss_XbyY_args_t *argp = (nss_XbyY_args_t*) args;
538 struct winbindd_response response;
539 struct winbindd_request request;
540 NSS_STATUS ret;
542 ZERO_STRUCT(response);
543 ZERO_STRUCT(request);
545 strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1);
546 request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0';
548 if( (ret = winbindd_request_response(NULL, WINBINDD_WINS_BYNAME,
549 &request, &response))
550 == NSS_STATUS_SUCCESS ) {
551 ret = parse_response(AF_INET, argp, &response);
554 winbindd_free_response(&response);
555 return ret;
558 static NSS_STATUS
559 _nss_winbind_hosts_getbyaddr(nss_backend_t* be, void *args)
561 NSS_STATUS ret;
562 struct winbindd_response response;
563 struct winbindd_request request;
564 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)args;
565 const char *p;
567 ZERO_STRUCT(response);
568 ZERO_STRUCT(request);
570 #if defined(AF_INET6)
571 /* winbindd currently does not resolve IPv6 */
572 if(argp->key.hostaddr.type == AF_INET6) {
573 argp->h_errno = NO_DATA;
574 return NSS_STATUS_UNAVAIL;
577 p = inet_ntop(argp->key.hostaddr.type, argp->key.hostaddr.addr,
578 request.data.winsreq, sizeof request.data.winsreq);
579 #else
580 snprintf(request.data.winsreq, sizeof request.data.winsreq,
581 "%u.%u.%u.%u",
582 ((unsigned char *)argp->key.hostaddr.addr)[0],
583 ((unsigned char *)argp->key.hostaddr.addr)[1],
584 ((unsigned char *)argp->key.hostaddr.addr)[2],
585 ((unsigned char *)argp->key.hostaddr.addr)[3]);
586 #endif
588 ret = winbindd_request_response(NULL, WINBINDD_WINS_BYIP,
589 &request, &response);
591 if( ret == NSS_STATUS_SUCCESS) {
592 parse_response(argp->key.hostaddr.type, argp, &response);
594 winbindd_free_response(&response);
595 return ret;
598 /* winbind does not provide setent, getent, endent for wins */
599 static NSS_STATUS
600 _nss_winbind_common_endent(nss_backend_t* be, void *args)
602 return (NSS_STATUS_UNAVAIL);
605 static NSS_STATUS
606 _nss_winbind_common_setent(nss_backend_t* be, void *args)
608 return (NSS_STATUS_UNAVAIL);
611 static NSS_STATUS
612 _nss_winbind_common_getent(nss_backend_t* be, void *args)
614 return (NSS_STATUS_UNAVAIL);
617 static nss_backend_t*
618 _nss_winbind_common_constr (nss_backend_op_t ops[], int n_ops)
620 nss_backend_t* be;
622 if(!(be = SMB_MALLOC_P(nss_backend_t)) )
623 return NULL;
625 be->ops = ops;
626 be->n_ops = n_ops;
628 return be;
631 static NSS_STATUS
632 _nss_winbind_common_destr (nss_backend_t* be, void* args)
634 SAFE_FREE(be);
635 return NSS_STATUS_SUCCESS;
638 static nss_backend_op_t ipnodes_ops[] = {
639 _nss_winbind_common_destr,
640 _nss_winbind_common_endent,
641 _nss_winbind_common_setent,
642 _nss_winbind_common_getent,
643 _nss_winbind_ipnodes_getbyname,
644 _nss_winbind_hosts_getbyaddr,
647 nss_backend_t *
648 _nss_winbind_ipnodes_constr(dummy1, dummy2, dummy3)
649 const char *dummy1, *dummy2, *dummy3;
651 return (_nss_winbind_common_constr(ipnodes_ops,
652 sizeof (ipnodes_ops) / sizeof (ipnodes_ops[0])));
655 static nss_backend_op_t host_ops[] = {
656 _nss_winbind_common_destr,
657 _nss_winbind_common_endent,
658 _nss_winbind_common_setent,
659 _nss_winbind_common_getent,
660 _nss_winbind_hosts_getbyname,
661 _nss_winbind_hosts_getbyaddr,
664 nss_backend_t *
665 _nss_winbind_hosts_constr(dummy1, dummy2, dummy3)
666 const char *dummy1, *dummy2, *dummy3;
668 return (_nss_winbind_common_constr(host_ops,
669 sizeof (host_ops) / sizeof (host_ops[0])));
672 #endif /* defined(SUNOS5) */
673 #endif /* defined(HAVE_NSS_COMMON_H) || defined(HPUX) */