WHATSNEW: Update changes since 3.3.0pre2.
[Samba.git] / source / nsswitch / winbind_nss_solaris.c
blob865b6ebbb068d6d3597a442a99dc7f6441ceaf55
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
29 #include "winbind_client.h"
30 #include <stdlib.h>
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <string.h>
34 #include <pwd.h>
35 #include "includes.h"
36 #include <syslog.h>
37 #if !defined(HPUX)
38 #include <sys/syslog.h>
39 #endif /*hpux*/
41 #if defined(HAVE_NSS_COMMON_H) || defined(HPUX)
43 #undef NSS_DEBUG
45 #ifdef NSS_DEBUG
46 #define NSS_DEBUG(str) syslog(LOG_DEBUG, "nss_winbind: %s", str);
47 #else
48 #define NSS_DEBUG(str) ;
49 #endif
51 #define NSS_ARGS(args) ((nss_XbyY_args_t *)args)
53 #ifdef HPUX
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 {
62 const char *username;
63 gid_t *gid_array;
64 int maxgids;
65 int force_slow_way;
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 *);
70 int numgids;
73 #endif /* HPUX */
75 #define make_pwent_str(dest, src) \
76 { \
77 if((dest = get_static(buffer, buflen, strlen(src)+1)) == NULL) \
78 { \
79 *errnop = ERANGE; \
80 NSS_DEBUG("ERANGE error"); \
81 return NSS_STATUS_TRYAGAIN; \
82 } \
83 strcpy(dest, src); \
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();
92 static NSS_STATUS
93 _nss_winbind_endpwent_solwrap (nss_backend_t * be, void *args)
95 NSS_DEBUG("_nss_winbind_endpwent_solwrap");
96 return _nss_winbind_endpwent();
99 static NSS_STATUS
100 _nss_winbind_getpwent_solwrap (nss_backend_t* be, void *args)
102 NSS_STATUS ret;
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;
107 char logmsg[80];
109 ret = _nss_winbind_getpwent_r(result, buffer,
110 buflen, errnop);
112 if(ret == NSS_STATUS_SUCCESS)
114 snprintf(logmsg, 79, "_nss_winbind_getpwent_solwrap: Returning user: %s\n",
115 result->pw_name);
116 NSS_DEBUG(logmsg);
117 NSS_ARGS(args)->returnval = (void*) result;
118 } else {
119 snprintf(logmsg, 79, "_nss_winbind_getpwent_solwrap: Returning error: %d.\n",ret);
120 NSS_DEBUG(logmsg);
123 return ret;
126 static NSS_STATUS
127 _nss_winbind_getpwnam_solwrap (nss_backend_t* be, void* args)
129 NSS_STATUS ret;
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,
135 result,
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;
142 return ret;
145 static NSS_STATUS
146 _nss_winbind_getpwuid_solwrap(nss_backend_t* be, void* args)
148 NSS_STATUS ret;
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,
153 result,
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;
160 return ret;
163 static NSS_STATUS _nss_winbind_passwd_destr (nss_backend_t * be, void *args)
165 SAFE_FREE(be);
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 */
180 nss_backend_t*
181 _nss_winbind_passwd_constr (const char* db_name,
182 const char* src_name,
183 const char* cfg_args)
185 nss_backend_t *be;
187 if(!(be = SMB_MALLOC_P(nss_backend_t)) )
188 return NULL;
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");
194 return be;
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();
207 static NSS_STATUS
208 _nss_winbind_endgrent_solwrap (nss_backend_t * be, void *args)
210 NSS_DEBUG("_nss_winbind_endgrent_solwrap");
211 return _nss_winbind_endgrent();
214 static NSS_STATUS
215 _nss_winbind_getgrent_solwrap(nss_backend_t* be, void* args)
217 NSS_STATUS ret;
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;
222 char logmsg[80];
224 ret = _nss_winbind_getgrent_r(result, buffer,
225 buflen, errnop);
227 if(ret == NSS_STATUS_SUCCESS)
229 snprintf(logmsg, 79, "_nss_winbind_getgrent_solwrap: Returning group: %s\n", result->gr_name);
230 NSS_DEBUG(logmsg);
231 NSS_ARGS(args)->returnval = (void*) result;
232 } else {
233 snprintf(logmsg, 79, "_nss_winbind_getgrent_solwrap: Returning error: %d.\n", ret);
234 NSS_DEBUG(logmsg);
237 return ret;
241 static NSS_STATUS
242 _nss_winbind_getgrnam_solwrap(nss_backend_t* be, void* args)
244 NSS_STATUS ret;
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,
249 result,
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;
257 return ret;
260 static NSS_STATUS
261 _nss_winbind_getgrgid_solwrap(nss_backend_t* be, void* args)
263 NSS_STATUS ret;
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,
268 result,
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;
276 return ret;
279 static NSS_STATUS
280 _nss_winbind_getgroupsbymember_solwrap(nss_backend_t* be, void* args)
282 int errnop;
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 */
289 &gmem->numgids,
290 &gmem->maxgids,
291 &gmem->gid_array,
292 gmem->maxgids,
293 &errnop);
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);
305 static NSS_STATUS
306 _nss_winbind_group_destr (nss_backend_t* be, void* args)
308 SAFE_FREE(be);
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
324 nss_backend_t*
325 _nss_winbind_group_constr (const char* db_name,
326 const char* src_name,
327 const char* cfg_args)
329 nss_backend_t* be;
331 if(!(be = SMB_MALLOC_P(nss_backend_t)) )
332 return NULL;
334 be->ops = group_ops;
335 be->n_ops = sizeof(group_ops) / sizeof(nss_backend_op_t);
337 NSS_DEBUG("Initialized nss_winbind group backend");
338 return be;
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. */
350 static NSS_STATUS
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;
356 NSS_STATUS ret;
358 char *p, *data;
359 int addrcount = 0;
360 int len = 0;
361 struct in_addr *addrp;
362 #if defined(AF_INET6)
363 struct in6_addr *addrp6;
364 #endif
365 int i;
367 /* response is tab separated list of ip addresses with hostname
368 and newline at the end. so at first we will strip newline
369 then construct list of addresses for hostent.
371 p = strchr(response->data.winsresp, '\n');
372 if(p) *p = '\0';
373 else {/* it must be broken */
374 argp->h_errno = NO_DATA;
375 return NSS_STATUS_UNAVAIL;
378 for(; p != response->data.winsresp; p--) {
379 if(*p == '\t') addrcount++;
382 if(addrcount == 0) {/* it must be broken */
383 argp->h_errno = NO_DATA;
384 return NSS_STATUS_UNAVAIL;
387 /* allocate space for addresses and h_addr_list */
388 he->h_addrtype = af;
389 if( he->h_addrtype == AF_INET) {
390 he->h_length = sizeof(struct in_addr);
391 addrp = (struct in_addr *)ROUND_DOWN(buffer + buflen,
392 sizeof(struct in_addr));
393 addrp -= addrcount;
394 he->h_addr_list = (char **)ROUND_DOWN(addrp, sizeof (char*));
395 he->h_addr_list -= addrcount+1;
397 #if defined(AF_INET6)
398 else {
399 he->h_length = sizeof(struct in6_addr);
400 addrp6 = (struct in6_addr *)ROUND_DOWN(buffer + buflen,
401 sizeof(struct in6_addr));
402 addrp6 -= addrcount;
403 he->h_addr_list = (char **)ROUND_DOWN(addrp6, sizeof (char*));
404 he->h_addr_list -= addrcount+1;
406 #endif
408 /* buffer too small?! */
409 if((char *)he->h_addr_list < buffer ) {
410 argp->erange = 1;
411 return NSS_STR_PARSE_ERANGE;
414 data = response->data.winsresp;
415 for( i = 0; i < addrcount; i++) {
416 p = strchr(data, '\t');
417 if(p == NULL) break; /* just in case... */
419 *p = '\0'; /* terminate the string */
420 if(he->h_addrtype == AF_INET) {
421 he->h_addr_list[i] = (char *)&addrp[i];
422 if ((addrp[i].s_addr = inet_addr(data)) == -1) {
423 argp->erange = 1;
424 return NSS_STR_PARSE_ERANGE;
427 #if defined(AF_INET6)
428 else {
429 he->h_addr_list[i] = (char *)&addrp6[i];
430 if (strchr(data, ':') != 0) {
431 if (inet_pton(AF_INET6, data, &addrp6[i]) != 1) {
432 argp->erange = 1;
433 return NSS_STR_PARSE_ERANGE;
435 } else {
436 struct in_addr in4;
437 if ((in4.s_addr = inet_addr(data)) == -1) {
438 argp->erange = 1;
439 return NSS_STR_PARSE_ERANGE;
441 IN6_INADDR_TO_V4MAPPED(&in4, &addrp6[i]);
444 #endif
445 data = p+1;
448 he->h_addr_list[i] = (char *)NULL;
450 len = strlen(data);
451 if(len > he->h_addr_list - (char**)argp->buf.buffer) {
452 argp->erange = 1;
453 return NSS_STR_PARSE_ERANGE;
456 /* this is a bit overkill to use _nss_netdb_aliases here since
457 there seems to be no aliases but it will create all data for us */
458 he->h_aliases = _nss_netdb_aliases(data, len, buffer,
459 ((char*) he->h_addr_list) - buffer);
460 if(he->h_aliases == NULL) {
461 argp->erange = 1;
462 ret = NSS_STR_PARSE_ERANGE;
463 } else {
464 he->h_name = he->h_aliases[0];
465 he->h_aliases++;
466 ret = NSS_STR_PARSE_SUCCESS;
469 argp->returnval = (void*)he;
470 return ret;
473 static NSS_STATUS
474 _nss_winbind_ipnodes_getbyname(nss_backend_t* be, void *args)
476 nss_XbyY_args_t *argp = (nss_XbyY_args_t*) args;
477 struct winbindd_response response;
478 struct winbindd_request request;
479 NSS_STATUS ret;
480 int af;
482 ZERO_STRUCT(response);
483 ZERO_STRUCT(request);
485 /* I assume there that AI_ADDRCONFIG cases are handled in nss
486 frontend code, at least it seems done so in solaris...
488 we will give NO_DATA for pure IPv6; IPv4 will be returned for
489 AF_INET or for AF_INET6 and AI_ALL|AI_V4MAPPED we have to map
490 IPv4 to IPv6.
492 #if defined(AF_INET6)
493 #ifdef HAVE_NSS_XBYY_KEY_IPNODE
494 af = argp->key.ipnode.af_family;
495 if(af == AF_INET6 && argp->key.ipnode.flags == 0) {
496 argp->h_errno = NO_DATA;
497 return NSS_STATUS_UNAVAIL;
499 #else
500 /* I'm not that sure if this is correct, but... */
501 af = AF_INET6;
502 #endif
503 #endif
505 strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1);
506 request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0';
508 if( (ret = winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response))
509 == NSS_STATUS_SUCCESS ) {
510 ret = parse_response(af, argp, &response);
513 winbindd_free_response(&response);
514 return ret;
517 static NSS_STATUS
518 _nss_winbind_hosts_getbyname(nss_backend_t* be, void *args)
520 nss_XbyY_args_t *argp = (nss_XbyY_args_t*) args;
521 struct winbindd_response response;
522 struct winbindd_request request;
523 NSS_STATUS ret;
525 ZERO_STRUCT(response);
526 ZERO_STRUCT(request);
528 strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1);
529 request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0';
531 if( (ret = winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response))
532 == NSS_STATUS_SUCCESS ) {
533 ret = parse_response(AF_INET, argp, &response);
536 winbindd_free_response(&response);
537 return ret;
540 static NSS_STATUS
541 _nss_winbind_hosts_getbyaddr(nss_backend_t* be, void *args)
543 NSS_STATUS ret;
544 struct winbindd_response response;
545 struct winbindd_request request;
546 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)args;
547 const char *p;
549 ZERO_STRUCT(response);
550 ZERO_STRUCT(request);
552 #if defined(AF_INET6)
553 /* winbindd currently does not resolve IPv6 */
554 if(argp->key.hostaddr.type == AF_INET6) {
555 argp->h_errno = NO_DATA;
556 return NSS_STATUS_UNAVAIL;
559 p = inet_ntop(argp->key.hostaddr.type, argp->key.hostaddr.addr,
560 request.data.winsreq, sizeof request.data.winsreq);
561 #else
562 snprintf(request.data.winsreq, sizeof request.data.winsreq,
563 "%u.%u.%u.%u",
564 ((unsigned char *)argp->key.hostaddr.addr)[0],
565 ((unsigned char *)argp->key.hostaddr.addr)[1],
566 ((unsigned char *)argp->key.hostaddr.addr)[2],
567 ((unsigned char *)argp->key.hostaddr.addr)[3]);
568 #endif
570 ret = winbindd_request_response(WINBINDD_WINS_BYIP, &request, &response);
572 if( ret == NSS_STATUS_SUCCESS) {
573 parse_response(argp->key.hostaddr.type, argp, &response);
575 winbindd_free_response(&response);
576 return ret;
579 /* winbind does not provide setent, getent, endent for wins */
580 static NSS_STATUS
581 _nss_winbind_common_endent(nss_backend_t* be, void *args)
583 return (NSS_STATUS_UNAVAIL);
586 static NSS_STATUS
587 _nss_winbind_common_setent(nss_backend_t* be, void *args)
589 return (NSS_STATUS_UNAVAIL);
592 static NSS_STATUS
593 _nss_winbind_common_getent(nss_backend_t* be, void *args)
595 return (NSS_STATUS_UNAVAIL);
598 static nss_backend_t*
599 _nss_winbind_common_constr (nss_backend_op_t ops[], int n_ops)
601 nss_backend_t* be;
603 if(!(be = SMB_MALLOC_P(nss_backend_t)) )
604 return NULL;
606 be->ops = ops;
607 be->n_ops = n_ops;
609 return be;
612 static NSS_STATUS
613 _nss_winbind_common_destr (nss_backend_t* be, void* args)
615 SAFE_FREE(be);
616 return NSS_STATUS_SUCCESS;
619 static nss_backend_op_t ipnodes_ops[] = {
620 _nss_winbind_common_destr,
621 _nss_winbind_common_endent,
622 _nss_winbind_common_setent,
623 _nss_winbind_common_getent,
624 _nss_winbind_ipnodes_getbyname,
625 _nss_winbind_hosts_getbyaddr,
628 nss_backend_t *
629 _nss_winbind_ipnodes_constr(dummy1, dummy2, dummy3)
630 const char *dummy1, *dummy2, *dummy3;
632 return (_nss_winbind_common_constr(ipnodes_ops,
633 sizeof (ipnodes_ops) / sizeof (ipnodes_ops[0])));
636 static nss_backend_op_t host_ops[] = {
637 _nss_winbind_common_destr,
638 _nss_winbind_common_endent,
639 _nss_winbind_common_setent,
640 _nss_winbind_common_getent,
641 _nss_winbind_hosts_getbyname,
642 _nss_winbind_hosts_getbyaddr,
645 nss_backend_t *
646 _nss_winbind_hosts_constr(dummy1, dummy2, dummy3)
647 const char *dummy1, *dummy2, *dummy3;
649 return (_nss_winbind_common_constr(host_ops,
650 sizeof (host_ops) / sizeof (host_ops[0])));
653 #endif /* defined(SUNOS5) */
654 #endif /* defined(HAVE_NSS_COMMON_H) || defined(HPUX) */