Move copychunk locking to be local to the read/write calls.
[Samba/gebeck_regimport.git] / nsswitch / winbind_nss_solaris.c
blob92da8591b7d9cccc30ed6cbec77113afc4f6aa35
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 "includes.h"
37 #include <syslog.h>
39 #if !defined(HPUX)
40 #include <sys/syslog.h>
41 #endif /*hpux*/
43 #if defined(HAVE_NSS_COMMON_H) || defined(HPUX)
45 #undef NSS_DEBUG
47 #ifdef NSS_DEBUG
48 #define NSS_DEBUG(str) syslog(LOG_DEBUG, "nss_winbind: %s", str);
49 #else
50 #define NSS_DEBUG(str) ;
51 #endif
53 #if !defined(SMB_MALLOC_P)
54 #define SMB_MALLOC_P(type) (type *)malloc(sizeof(type))
55 #endif
57 #define NSS_ARGS(args) ((nss_XbyY_args_t *)args)
59 #ifdef HPUX
62 * HP-UX 11 has no definiton of the nss_groupsbymem structure. This
63 * definition is taken from the nss_ldap project at:
64 * http://www.padl.com/OSS/nss_ldap.html
67 struct nss_groupsbymem {
68 const char *username;
69 gid_t *gid_array;
70 int maxgids;
71 int force_slow_way;
72 int (*str2ent)(const char *instr, int instr_len, void *ent,
73 char *buffer, int buflen);
74 nss_status_t (*process_cstr)(const char *instr, int instr_len,
75 struct nss_groupsbymem *);
76 int numgids;
79 #endif /* HPUX */
81 #define make_pwent_str(dest, src) \
82 { \
83 if((dest = get_static(buffer, buflen, strlen(src)+1)) == NULL) \
84 { \
85 *errnop = ERANGE; \
86 NSS_DEBUG("ERANGE error"); \
87 return NSS_STATUS_TRYAGAIN; \
88 } \
89 strcpy(dest, src); \
92 static NSS_STATUS _nss_winbind_setpwent_solwrap (nss_backend_t* be, void* args)
94 NSS_DEBUG("_nss_winbind_setpwent_solwrap");
95 return _nss_winbind_setpwent();
98 static NSS_STATUS
99 _nss_winbind_endpwent_solwrap (nss_backend_t * be, void *args)
101 NSS_DEBUG("_nss_winbind_endpwent_solwrap");
102 return _nss_winbind_endpwent();
105 static NSS_STATUS
106 _nss_winbind_getpwent_solwrap (nss_backend_t* be, void *args)
108 NSS_STATUS ret;
109 char* buffer = NSS_ARGS(args)->buf.buffer;
110 int buflen = NSS_ARGS(args)->buf.buflen;
111 struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result;
112 int* errnop = &NSS_ARGS(args)->erange;
113 char logmsg[80];
115 ret = _nss_winbind_getpwent_r(result, buffer,
116 buflen, errnop);
118 if(ret == NSS_STATUS_SUCCESS)
120 snprintf(logmsg, 79, "_nss_winbind_getpwent_solwrap: Returning user: %s\n",
121 result->pw_name);
122 NSS_DEBUG(logmsg);
123 NSS_ARGS(args)->returnval = (void*) result;
124 } else {
125 snprintf(logmsg, 79, "_nss_winbind_getpwent_solwrap: Returning error: %d.\n",ret);
126 NSS_DEBUG(logmsg);
129 return ret;
132 static NSS_STATUS
133 _nss_winbind_getpwnam_solwrap (nss_backend_t* be, void* args)
135 NSS_STATUS ret;
136 struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result;
138 NSS_DEBUG("_nss_winbind_getpwnam_solwrap");
140 ret = _nss_winbind_getpwnam_r (NSS_ARGS(args)->key.name,
141 result,
142 NSS_ARGS(args)->buf.buffer,
143 NSS_ARGS(args)->buf.buflen,
144 &NSS_ARGS(args)->erange);
145 if(ret == NSS_STATUS_SUCCESS)
146 NSS_ARGS(args)->returnval = (void*) result;
148 return ret;
151 static NSS_STATUS
152 _nss_winbind_getpwuid_solwrap(nss_backend_t* be, void* args)
154 NSS_STATUS ret;
155 struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result;
157 NSS_DEBUG("_nss_winbind_getpwuid_solwrap");
158 ret = _nss_winbind_getpwuid_r (NSS_ARGS(args)->key.uid,
159 result,
160 NSS_ARGS(args)->buf.buffer,
161 NSS_ARGS(args)->buf.buflen,
162 &NSS_ARGS(args)->erange);
163 if(ret == NSS_STATUS_SUCCESS)
164 NSS_ARGS(args)->returnval = (void*) result;
166 return ret;
169 static NSS_STATUS _nss_winbind_passwd_destr (nss_backend_t * be, void *args)
171 SAFE_FREE(be);
172 NSS_DEBUG("_nss_winbind_passwd_destr");
173 return NSS_STATUS_SUCCESS;
176 static nss_backend_op_t passwd_ops[] =
178 _nss_winbind_passwd_destr,
179 _nss_winbind_endpwent_solwrap, /* NSS_DBOP_ENDENT */
180 _nss_winbind_setpwent_solwrap, /* NSS_DBOP_SETENT */
181 _nss_winbind_getpwent_solwrap, /* NSS_DBOP_GETENT */
182 _nss_winbind_getpwnam_solwrap, /* NSS_DBOP_PASSWD_BYNAME */
183 _nss_winbind_getpwuid_solwrap /* NSS_DBOP_PASSWD_BYUID */
186 nss_backend_t*
187 _nss_winbind_passwd_constr (const char* db_name,
188 const char* src_name,
189 const char* cfg_args)
191 nss_backend_t *be;
193 if(!(be = SMB_MALLOC_P(nss_backend_t)) )
194 return NULL;
196 be->ops = passwd_ops;
197 be->n_ops = sizeof(passwd_ops) / sizeof(nss_backend_op_t);
199 NSS_DEBUG("Initialized nss_winbind passwd backend");
200 return be;
203 /*****************************************************************
204 GROUP database backend
205 *****************************************************************/
207 static NSS_STATUS _nss_winbind_setgrent_solwrap (nss_backend_t* be, void* args)
209 NSS_DEBUG("_nss_winbind_setgrent_solwrap");
210 return _nss_winbind_setgrent();
213 static NSS_STATUS
214 _nss_winbind_endgrent_solwrap (nss_backend_t * be, void *args)
216 NSS_DEBUG("_nss_winbind_endgrent_solwrap");
217 return _nss_winbind_endgrent();
220 static NSS_STATUS
221 _nss_winbind_getgrent_solwrap(nss_backend_t* be, void* args)
223 NSS_STATUS ret;
224 char* buffer = NSS_ARGS(args)->buf.buffer;
225 int buflen = NSS_ARGS(args)->buf.buflen;
226 struct group* result = (struct group*) NSS_ARGS(args)->buf.result;
227 int* errnop = &NSS_ARGS(args)->erange;
228 char logmsg[80];
230 ret = _nss_winbind_getgrent_r(result, buffer,
231 buflen, errnop);
233 if(ret == NSS_STATUS_SUCCESS)
235 snprintf(logmsg, 79, "_nss_winbind_getgrent_solwrap: Returning group: %s\n", result->gr_name);
236 NSS_DEBUG(logmsg);
237 NSS_ARGS(args)->returnval = (void*) result;
238 } else {
239 snprintf(logmsg, 79, "_nss_winbind_getgrent_solwrap: Returning error: %d.\n", ret);
240 NSS_DEBUG(logmsg);
243 return ret;
247 static NSS_STATUS
248 _nss_winbind_getgrnam_solwrap(nss_backend_t* be, void* args)
250 NSS_STATUS ret;
251 struct group* result = (struct group*) NSS_ARGS(args)->buf.result;
253 NSS_DEBUG("_nss_winbind_getgrnam_solwrap");
254 ret = _nss_winbind_getgrnam_r(NSS_ARGS(args)->key.name,
255 result,
256 NSS_ARGS(args)->buf.buffer,
257 NSS_ARGS(args)->buf.buflen,
258 &NSS_ARGS(args)->erange);
260 if(ret == NSS_STATUS_SUCCESS)
261 NSS_ARGS(args)->returnval = (void*) result;
263 return ret;
266 static NSS_STATUS
267 _nss_winbind_getgrgid_solwrap(nss_backend_t* be, void* args)
269 NSS_STATUS ret;
270 struct group* result = (struct group*) NSS_ARGS(args)->buf.result;
272 NSS_DEBUG("_nss_winbind_getgrgid_solwrap");
273 ret = _nss_winbind_getgrgid_r (NSS_ARGS(args)->key.gid,
274 result,
275 NSS_ARGS(args)->buf.buffer,
276 NSS_ARGS(args)->buf.buflen,
277 &NSS_ARGS(args)->erange);
279 if(ret == NSS_STATUS_SUCCESS)
280 NSS_ARGS(args)->returnval = (void*) result;
282 return ret;
285 static NSS_STATUS
286 _nss_winbind_getgroupsbymember_solwrap(nss_backend_t* be, void* args)
288 int errnop;
289 struct nss_groupsbymem *gmem = (struct nss_groupsbymem *)args;
290 long int numgids = gmem->numgids;
291 long int maxgids = gmem->maxgids;
293 NSS_DEBUG("_nss_winbind_getgroupsbymember");
295 _nss_winbind_initgroups_dyn(gmem->username,
296 gmem->gid_array[0], /* Primary Group */
297 &numgids,
298 &maxgids,
299 &gmem->gid_array,
300 gmem->maxgids,
301 &errnop);
303 gmem->numgids = numgids;
304 gmem->maxgids = maxgids;
307 * If the maximum number of gids have been found, return
308 * SUCCESS so the switch engine will stop searching. Otherwise
309 * return NOTFOUND so nsswitch will continue to get groups
310 * from the remaining database backends specified in the
311 * nsswitch.conf file.
313 return (gmem->numgids == gmem->maxgids ? NSS_STATUS_SUCCESS : NSS_STATUS_NOTFOUND);
316 static NSS_STATUS
317 _nss_winbind_group_destr (nss_backend_t* be, void* args)
319 SAFE_FREE(be);
320 NSS_DEBUG("_nss_winbind_group_destr");
321 return NSS_STATUS_SUCCESS;
324 static nss_backend_op_t group_ops[] =
326 _nss_winbind_group_destr,
327 _nss_winbind_endgrent_solwrap,
328 _nss_winbind_setgrent_solwrap,
329 _nss_winbind_getgrent_solwrap,
330 _nss_winbind_getgrnam_solwrap,
331 _nss_winbind_getgrgid_solwrap,
332 _nss_winbind_getgroupsbymember_solwrap
335 nss_backend_t*
336 _nss_winbind_group_constr (const char* db_name,
337 const char* src_name,
338 const char* cfg_args)
340 nss_backend_t* be;
342 if(!(be = SMB_MALLOC_P(nss_backend_t)) )
343 return NULL;
345 be->ops = group_ops;
346 be->n_ops = sizeof(group_ops) / sizeof(nss_backend_op_t);
348 NSS_DEBUG("Initialized nss_winbind group backend");
349 return be;
352 /*****************************************************************
353 hosts and ipnodes backend
354 *****************************************************************/
355 #if defined(SUNOS5) /* not compatible with HP-UX */
357 /* this parser is shared between get*byname and get*byaddr, as key type
358 in request is stored in different locations, I had to provide the
359 address family as an argument, caller must free the winbind response. */
361 static NSS_STATUS
362 parse_response(int af, nss_XbyY_args_t* argp, struct winbindd_response *response)
364 struct hostent *he = (struct hostent *)argp->buf.result;
365 char *buffer = argp->buf.buffer;
366 int buflen = argp->buf.buflen;
367 NSS_STATUS ret;
369 char *p, *data;
370 int addrcount = 0;
371 int len = 0;
372 struct in_addr *addrp;
373 #if defined(AF_INET6)
374 struct in6_addr *addrp6;
375 #endif
376 int i;
378 /* response is tab separated list of ip addresses with hostname
379 and newline at the end. so at first we will strip newline
380 then construct list of addresses for hostent.
382 p = strchr(response->data.winsresp, '\n');
383 if(p) *p = '\0';
384 else {/* it must be broken */
385 argp->h_errno = NO_DATA;
386 return NSS_STATUS_UNAVAIL;
389 for(; p != response->data.winsresp; p--) {
390 if(*p == '\t') addrcount++;
393 if(addrcount == 0) {/* it must be broken */
394 argp->h_errno = NO_DATA;
395 return NSS_STATUS_UNAVAIL;
398 /* allocate space for addresses and h_addr_list */
399 he->h_addrtype = af;
400 if( he->h_addrtype == AF_INET) {
401 he->h_length = sizeof(struct in_addr);
402 addrp = (struct in_addr *)ROUND_DOWN(buffer + buflen,
403 sizeof(struct in_addr));
404 addrp -= addrcount;
405 he->h_addr_list = (char **)ROUND_DOWN(addrp, sizeof (char*));
406 he->h_addr_list -= addrcount+1;
408 #if defined(AF_INET6)
409 else {
410 he->h_length = sizeof(struct in6_addr);
411 addrp6 = (struct in6_addr *)ROUND_DOWN(buffer + buflen,
412 sizeof(struct in6_addr));
413 addrp6 -= addrcount;
414 he->h_addr_list = (char **)ROUND_DOWN(addrp6, sizeof (char*));
415 he->h_addr_list -= addrcount+1;
417 #endif
419 /* buffer too small?! */
420 if((char *)he->h_addr_list < buffer ) {
421 argp->erange = 1;
422 return NSS_STR_PARSE_ERANGE;
425 data = response->data.winsresp;
426 for( i = 0; i < addrcount; i++) {
427 p = strchr(data, '\t');
428 if(p == NULL) break; /* just in case... */
430 *p = '\0'; /* terminate the string */
431 if(he->h_addrtype == AF_INET) {
432 he->h_addr_list[i] = (char *)&addrp[i];
433 if ((addrp[i].s_addr = inet_addr(data)) == -1) {
434 argp->erange = 1;
435 return NSS_STR_PARSE_ERANGE;
438 #if defined(AF_INET6)
439 else {
440 he->h_addr_list[i] = (char *)&addrp6[i];
441 if (strchr(data, ':') != 0) {
442 if (inet_pton(AF_INET6, data, &addrp6[i]) != 1) {
443 argp->erange = 1;
444 return NSS_STR_PARSE_ERANGE;
446 } else {
447 struct in_addr in4;
448 if ((in4.s_addr = inet_addr(data)) == -1) {
449 argp->erange = 1;
450 return NSS_STR_PARSE_ERANGE;
452 IN6_INADDR_TO_V4MAPPED(&in4, &addrp6[i]);
455 #endif
456 data = p+1;
459 he->h_addr_list[i] = (char *)NULL;
461 len = strlen(data);
462 if(len > he->h_addr_list - (char**)argp->buf.buffer) {
463 argp->erange = 1;
464 return NSS_STR_PARSE_ERANGE;
467 /* this is a bit overkill to use _nss_netdb_aliases here since
468 there seems to be no aliases but it will create all data for us */
469 he->h_aliases = _nss_netdb_aliases(data, len, buffer,
470 ((char*) he->h_addr_list) - buffer);
471 if(he->h_aliases == NULL) {
472 argp->erange = 1;
473 ret = NSS_STR_PARSE_ERANGE;
474 } else {
475 he->h_name = he->h_aliases[0];
476 he->h_aliases++;
477 ret = NSS_STR_PARSE_SUCCESS;
480 argp->returnval = (void*)he;
481 return ret;
484 static NSS_STATUS
485 _nss_winbind_ipnodes_getbyname(nss_backend_t* be, void *args)
487 nss_XbyY_args_t *argp = (nss_XbyY_args_t*) args;
488 struct winbindd_response response;
489 struct winbindd_request request;
490 NSS_STATUS ret;
491 int af;
493 ZERO_STRUCT(response);
494 ZERO_STRUCT(request);
496 /* I assume there that AI_ADDRCONFIG cases are handled in nss
497 frontend code, at least it seems done so in solaris...
499 we will give NO_DATA for pure IPv6; IPv4 will be returned for
500 AF_INET or for AF_INET6 and AI_ALL|AI_V4MAPPED we have to map
501 IPv4 to IPv6.
503 #if defined(AF_INET6)
504 #ifdef HAVE_NSS_XBYY_KEY_IPNODE
505 af = argp->key.ipnode.af_family;
506 if(af == AF_INET6 && argp->key.ipnode.flags == 0) {
507 argp->h_errno = NO_DATA;
508 return NSS_STATUS_UNAVAIL;
510 #else
511 /* I'm not that sure if this is correct, but... */
512 af = AF_INET6;
513 #endif
514 #endif
516 strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1);
517 request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0';
519 if( (ret = winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response))
520 == NSS_STATUS_SUCCESS ) {
521 ret = parse_response(af, argp, &response);
524 winbindd_free_response(&response);
525 return ret;
528 static NSS_STATUS
529 _nss_winbind_hosts_getbyname(nss_backend_t* be, void *args)
531 nss_XbyY_args_t *argp = (nss_XbyY_args_t*) args;
532 struct winbindd_response response;
533 struct winbindd_request request;
534 NSS_STATUS ret;
536 ZERO_STRUCT(response);
537 ZERO_STRUCT(request);
539 strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1);
540 request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0';
542 if( (ret = winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response))
543 == NSS_STATUS_SUCCESS ) {
544 ret = parse_response(AF_INET, argp, &response);
547 winbindd_free_response(&response);
548 return ret;
551 static NSS_STATUS
552 _nss_winbind_hosts_getbyaddr(nss_backend_t* be, void *args)
554 NSS_STATUS ret;
555 struct winbindd_response response;
556 struct winbindd_request request;
557 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)args;
558 const char *p;
560 ZERO_STRUCT(response);
561 ZERO_STRUCT(request);
563 #if defined(AF_INET6)
564 /* winbindd currently does not resolve IPv6 */
565 if(argp->key.hostaddr.type == AF_INET6) {
566 argp->h_errno = NO_DATA;
567 return NSS_STATUS_UNAVAIL;
570 p = inet_ntop(argp->key.hostaddr.type, argp->key.hostaddr.addr,
571 request.data.winsreq, sizeof request.data.winsreq);
572 #else
573 snprintf(request.data.winsreq, sizeof request.data.winsreq,
574 "%u.%u.%u.%u",
575 ((unsigned char *)argp->key.hostaddr.addr)[0],
576 ((unsigned char *)argp->key.hostaddr.addr)[1],
577 ((unsigned char *)argp->key.hostaddr.addr)[2],
578 ((unsigned char *)argp->key.hostaddr.addr)[3]);
579 #endif
581 ret = winbindd_request_response(WINBINDD_WINS_BYIP, &request, &response);
583 if( ret == NSS_STATUS_SUCCESS) {
584 parse_response(argp->key.hostaddr.type, argp, &response);
586 winbindd_free_response(&response);
587 return ret;
590 /* winbind does not provide setent, getent, endent for wins */
591 static NSS_STATUS
592 _nss_winbind_common_endent(nss_backend_t* be, void *args)
594 return (NSS_STATUS_UNAVAIL);
597 static NSS_STATUS
598 _nss_winbind_common_setent(nss_backend_t* be, void *args)
600 return (NSS_STATUS_UNAVAIL);
603 static NSS_STATUS
604 _nss_winbind_common_getent(nss_backend_t* be, void *args)
606 return (NSS_STATUS_UNAVAIL);
609 static nss_backend_t*
610 _nss_winbind_common_constr (nss_backend_op_t ops[], int n_ops)
612 nss_backend_t* be;
614 if(!(be = SMB_MALLOC_P(nss_backend_t)) )
615 return NULL;
617 be->ops = ops;
618 be->n_ops = n_ops;
620 return be;
623 static NSS_STATUS
624 _nss_winbind_common_destr (nss_backend_t* be, void* args)
626 SAFE_FREE(be);
627 return NSS_STATUS_SUCCESS;
630 static nss_backend_op_t ipnodes_ops[] = {
631 _nss_winbind_common_destr,
632 _nss_winbind_common_endent,
633 _nss_winbind_common_setent,
634 _nss_winbind_common_getent,
635 _nss_winbind_ipnodes_getbyname,
636 _nss_winbind_hosts_getbyaddr,
639 nss_backend_t *
640 _nss_winbind_ipnodes_constr(dummy1, dummy2, dummy3)
641 const char *dummy1, *dummy2, *dummy3;
643 return (_nss_winbind_common_constr(ipnodes_ops,
644 sizeof (ipnodes_ops) / sizeof (ipnodes_ops[0])));
647 static nss_backend_op_t host_ops[] = {
648 _nss_winbind_common_destr,
649 _nss_winbind_common_endent,
650 _nss_winbind_common_setent,
651 _nss_winbind_common_getent,
652 _nss_winbind_hosts_getbyname,
653 _nss_winbind_hosts_getbyaddr,
656 nss_backend_t *
657 _nss_winbind_hosts_constr(dummy1, dummy2, dummy3)
658 const char *dummy1, *dummy2, *dummy3;
660 return (_nss_winbind_common_constr(host_ops,
661 sizeof (host_ops) / sizeof (host_ops[0])));
664 #endif /* defined(SUNOS5) */
665 #endif /* defined(HAVE_NSS_COMMON_H) || defined(HPUX) */