docs: include the type attribute for getwd cache
[Samba.git] / nsswitch / winbind_nss_solaris.c
blob6d3c8a964fdc98271562fb3cac8e6e5366b6d44a
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 return ret;
265 static NSS_STATUS
266 _nss_winbind_getgrgid_solwrap(nss_backend_t* be, void* args)
268 NSS_STATUS ret;
269 struct group* result = (struct group*) NSS_ARGS(args)->buf.result;
271 NSS_DEBUG("_nss_winbind_getgrgid_solwrap");
272 ret = _nss_winbind_getgrgid_r (NSS_ARGS(args)->key.gid,
273 result,
274 NSS_ARGS(args)->buf.buffer,
275 NSS_ARGS(args)->buf.buflen,
276 &NSS_ARGS(args)->erange);
278 if(ret == NSS_STATUS_SUCCESS)
279 NSS_ARGS(args)->returnval = (void*) result;
281 return ret;
284 static NSS_STATUS
285 _nss_winbind_getgroupsbymember_solwrap(nss_backend_t* be, void* args)
287 int errnop;
288 struct nss_groupsbymem *gmem = (struct nss_groupsbymem *)args;
289 long int numgids = gmem->numgids;
290 long int maxgids = gmem->maxgids;
292 NSS_DEBUG("_nss_winbind_getgroupsbymember");
294 _nss_winbind_initgroups_dyn(gmem->username,
295 gmem->gid_array[0], /* Primary Group */
296 &numgids,
297 &maxgids,
298 &gmem->gid_array,
299 gmem->maxgids,
300 &errnop);
302 gmem->numgids = numgids;
303 gmem->maxgids = maxgids;
306 * If the maximum number of gids have been found, return
307 * SUCCESS so the switch engine will stop searching. Otherwise
308 * return NOTFOUND so nsswitch will continue to get groups
309 * from the remaining database backends specified in the
310 * nsswitch.conf file.
312 return (gmem->numgids == gmem->maxgids ? NSS_STATUS_SUCCESS : NSS_STATUS_NOTFOUND);
315 static NSS_STATUS
316 _nss_winbind_group_destr (nss_backend_t* be, void* args)
318 SAFE_FREE(be);
319 NSS_DEBUG("_nss_winbind_group_destr");
320 return NSS_STATUS_SUCCESS;
323 static nss_backend_op_t group_ops[] =
325 _nss_winbind_group_destr,
326 _nss_winbind_endgrent_solwrap,
327 _nss_winbind_setgrent_solwrap,
328 _nss_winbind_getgrent_solwrap,
329 _nss_winbind_getgrnam_solwrap,
330 _nss_winbind_getgrgid_solwrap,
331 _nss_winbind_getgroupsbymember_solwrap
334 nss_backend_t*
335 _nss_winbind_group_constr (const char* db_name,
336 const char* src_name,
337 const char* cfg_args)
339 nss_backend_t* be;
341 if(!(be = SMB_MALLOC_P(nss_backend_t)) )
342 return NULL;
344 be->ops = group_ops;
345 be->n_ops = sizeof(group_ops) / sizeof(nss_backend_op_t);
347 NSS_DEBUG("Initialized nss_winbind group backend");
348 return be;
351 /*****************************************************************
352 hosts and ipnodes backend
353 *****************************************************************/
354 #if defined(SUNOS5) /* not compatible with HP-UX */
356 /* this parser is shared between get*byname and get*byaddr, as key type
357 in request is stored in different locations, I had to provide the
358 address family as an argument, caller must free the winbind response. */
360 static NSS_STATUS
361 parse_response(int af, nss_XbyY_args_t* argp, struct winbindd_response *response)
363 struct hostent *he = (struct hostent *)argp->buf.result;
364 char *buffer = argp->buf.buffer;
365 int buflen = argp->buf.buflen;
366 NSS_STATUS ret;
368 char *p, *data;
369 int addrcount = 0;
370 int len = 0;
371 struct in_addr *addrp;
372 #if defined(AF_INET6)
373 struct in6_addr *addrp6;
374 #endif
375 int i;
377 /* response is tab separated list of ip addresses with hostname
378 and newline at the end. so at first we will strip newline
379 then construct list of addresses for hostent.
381 p = strchr(response->data.winsresp, '\n');
382 if(p) *p = '\0';
383 else {/* it must be broken */
384 argp->h_errno = NO_DATA;
385 return NSS_STATUS_UNAVAIL;
388 for(; p != response->data.winsresp; p--) {
389 if(*p == '\t') addrcount++;
392 if(addrcount == 0) {/* it must be broken */
393 argp->h_errno = NO_DATA;
394 return NSS_STATUS_UNAVAIL;
397 /* allocate space for addresses and h_addr_list */
398 he->h_addrtype = af;
399 if( he->h_addrtype == AF_INET) {
400 he->h_length = sizeof(struct in_addr);
401 addrp = (struct in_addr *)ROUND_DOWN(buffer + buflen,
402 sizeof(struct in_addr));
403 addrp -= addrcount;
404 he->h_addr_list = (char **)ROUND_DOWN(addrp, sizeof (char*));
405 he->h_addr_list -= addrcount+1;
407 #if defined(AF_INET6)
408 else {
409 he->h_length = sizeof(struct in6_addr);
410 addrp6 = (struct in6_addr *)ROUND_DOWN(buffer + buflen,
411 sizeof(struct in6_addr));
412 addrp6 -= addrcount;
413 he->h_addr_list = (char **)ROUND_DOWN(addrp6, sizeof (char*));
414 he->h_addr_list -= addrcount+1;
416 #endif
418 /* buffer too small?! */
419 if((char *)he->h_addr_list < buffer ) {
420 argp->erange = 1;
421 return NSS_STR_PARSE_ERANGE;
424 data = response->data.winsresp;
425 for( i = 0; i < addrcount; i++) {
426 p = strchr(data, '\t');
427 if(p == NULL) break; /* just in case... */
429 *p = '\0'; /* terminate the string */
430 if(he->h_addrtype == AF_INET) {
431 he->h_addr_list[i] = (char *)&addrp[i];
432 if ((addrp[i].s_addr = inet_addr(data)) == -1) {
433 argp->erange = 1;
434 return NSS_STR_PARSE_ERANGE;
437 #if defined(AF_INET6)
438 else {
439 he->h_addr_list[i] = (char *)&addrp6[i];
440 if (strchr(data, ':') != 0) {
441 if (inet_pton(AF_INET6, data, &addrp6[i]) != 1) {
442 argp->erange = 1;
443 return NSS_STR_PARSE_ERANGE;
445 } else {
446 struct in_addr in4;
447 if ((in4.s_addr = inet_addr(data)) == -1) {
448 argp->erange = 1;
449 return NSS_STR_PARSE_ERANGE;
451 IN6_INADDR_TO_V4MAPPED(&in4, &addrp6[i]);
454 #endif
455 data = p+1;
458 he->h_addr_list[i] = (char *)NULL;
460 len = strlen(data);
461 if(len > he->h_addr_list - (char**)argp->buf.buffer) {
462 argp->erange = 1;
463 return NSS_STR_PARSE_ERANGE;
466 /* this is a bit overkill to use _nss_netdb_aliases here since
467 there seems to be no aliases but it will create all data for us */
468 he->h_aliases = _nss_netdb_aliases(data, len, buffer,
469 ((char*) he->h_addr_list) - buffer);
470 if(he->h_aliases == NULL) {
471 argp->erange = 1;
472 ret = NSS_STR_PARSE_ERANGE;
473 } else {
474 he->h_name = he->h_aliases[0];
475 he->h_aliases++;
476 ret = NSS_STR_PARSE_SUCCESS;
479 argp->returnval = (void*)he;
480 return ret;
483 static NSS_STATUS
484 _nss_winbind_ipnodes_getbyname(nss_backend_t* be, void *args)
486 nss_XbyY_args_t *argp = (nss_XbyY_args_t*) args;
487 struct winbindd_response response;
488 struct winbindd_request request;
489 NSS_STATUS ret;
490 int af;
492 ZERO_STRUCT(response);
493 ZERO_STRUCT(request);
495 /* I assume there that AI_ADDRCONFIG cases are handled in nss
496 frontend code, at least it seems done so in solaris...
498 we will give NO_DATA for pure IPv6; IPv4 will be returned for
499 AF_INET or for AF_INET6 and AI_ALL|AI_V4MAPPED we have to map
500 IPv4 to IPv6.
502 #if defined(AF_INET6)
503 #ifdef HAVE_NSS_XBYY_KEY_IPNODE
504 af = argp->key.ipnode.af_family;
505 if(af == AF_INET6 && argp->key.ipnode.flags == 0) {
506 argp->h_errno = NO_DATA;
507 return NSS_STATUS_UNAVAIL;
509 #else
510 /* I'm not that sure if this is correct, but... */
511 af = AF_INET6;
512 #endif
513 #endif
515 strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1);
516 request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0';
518 if( (ret = winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response))
519 == NSS_STATUS_SUCCESS ) {
520 ret = parse_response(af, argp, &response);
523 winbindd_free_response(&response);
524 return ret;
527 static NSS_STATUS
528 _nss_winbind_hosts_getbyname(nss_backend_t* be, void *args)
530 nss_XbyY_args_t *argp = (nss_XbyY_args_t*) args;
531 struct winbindd_response response;
532 struct winbindd_request request;
533 NSS_STATUS ret;
535 ZERO_STRUCT(response);
536 ZERO_STRUCT(request);
538 strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1);
539 request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0';
541 if( (ret = winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response))
542 == NSS_STATUS_SUCCESS ) {
543 ret = parse_response(AF_INET, argp, &response);
546 winbindd_free_response(&response);
547 return ret;
550 static NSS_STATUS
551 _nss_winbind_hosts_getbyaddr(nss_backend_t* be, void *args)
553 NSS_STATUS ret;
554 struct winbindd_response response;
555 struct winbindd_request request;
556 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)args;
557 const char *p;
559 ZERO_STRUCT(response);
560 ZERO_STRUCT(request);
562 #if defined(AF_INET6)
563 /* winbindd currently does not resolve IPv6 */
564 if(argp->key.hostaddr.type == AF_INET6) {
565 argp->h_errno = NO_DATA;
566 return NSS_STATUS_UNAVAIL;
569 p = inet_ntop(argp->key.hostaddr.type, argp->key.hostaddr.addr,
570 request.data.winsreq, sizeof request.data.winsreq);
571 #else
572 snprintf(request.data.winsreq, sizeof request.data.winsreq,
573 "%u.%u.%u.%u",
574 ((unsigned char *)argp->key.hostaddr.addr)[0],
575 ((unsigned char *)argp->key.hostaddr.addr)[1],
576 ((unsigned char *)argp->key.hostaddr.addr)[2],
577 ((unsigned char *)argp->key.hostaddr.addr)[3]);
578 #endif
580 ret = winbindd_request_response(WINBINDD_WINS_BYIP, &request, &response);
582 if( ret == NSS_STATUS_SUCCESS) {
583 parse_response(argp->key.hostaddr.type, argp, &response);
585 winbindd_free_response(&response);
586 return ret;
589 /* winbind does not provide setent, getent, endent for wins */
590 static NSS_STATUS
591 _nss_winbind_common_endent(nss_backend_t* be, void *args)
593 return (NSS_STATUS_UNAVAIL);
596 static NSS_STATUS
597 _nss_winbind_common_setent(nss_backend_t* be, void *args)
599 return (NSS_STATUS_UNAVAIL);
602 static NSS_STATUS
603 _nss_winbind_common_getent(nss_backend_t* be, void *args)
605 return (NSS_STATUS_UNAVAIL);
608 static nss_backend_t*
609 _nss_winbind_common_constr (nss_backend_op_t ops[], int n_ops)
611 nss_backend_t* be;
613 if(!(be = SMB_MALLOC_P(nss_backend_t)) )
614 return NULL;
616 be->ops = ops;
617 be->n_ops = n_ops;
619 return be;
622 static NSS_STATUS
623 _nss_winbind_common_destr (nss_backend_t* be, void* args)
625 SAFE_FREE(be);
626 return NSS_STATUS_SUCCESS;
629 static nss_backend_op_t ipnodes_ops[] = {
630 _nss_winbind_common_destr,
631 _nss_winbind_common_endent,
632 _nss_winbind_common_setent,
633 _nss_winbind_common_getent,
634 _nss_winbind_ipnodes_getbyname,
635 _nss_winbind_hosts_getbyaddr,
638 nss_backend_t *
639 _nss_winbind_ipnodes_constr(dummy1, dummy2, dummy3)
640 const char *dummy1, *dummy2, *dummy3;
642 return (_nss_winbind_common_constr(ipnodes_ops,
643 sizeof (ipnodes_ops) / sizeof (ipnodes_ops[0])));
646 static nss_backend_op_t host_ops[] = {
647 _nss_winbind_common_destr,
648 _nss_winbind_common_endent,
649 _nss_winbind_common_setent,
650 _nss_winbind_common_getent,
651 _nss_winbind_hosts_getbyname,
652 _nss_winbind_hosts_getbyaddr,
655 nss_backend_t *
656 _nss_winbind_hosts_constr(dummy1, dummy2, dummy3)
657 const char *dummy1, *dummy2, *dummy3;
659 return (_nss_winbind_common_constr(host_ops,
660 sizeof (host_ops) / sizeof (host_ops[0])));
663 #endif /* defined(SUNOS5) */
664 #endif /* defined(HAVE_NSS_COMMON_H) || defined(HPUX) */