source: vendor/current/nsswitch/winbind_nss_solaris.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 17.3 KB
Line 
1/*
2 Solaris NSS wrapper for winbind
3 - Shirish Kalele 2000
4
5 Based on Luke Howard's ldap_nss module for Solaris
6 */
7
8/*
9 Copyright (C) 1997-2003 Luke Howard.
10 This file is part of the nss_ldap library.
11
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.
16
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.
21
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/>.
25*/
26
27#undef DEVELOPER
28
29
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>
37
38#if !defined(HPUX)
39#include <sys/syslog.h>
40#endif /*hpux*/
41
42#if defined(HAVE_NSS_COMMON_H) || defined(HPUX)
43
44#undef NSS_DEBUG
45
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
51
52#if !defined(SMB_MALLOC_P)
53#define SMB_MALLOC_P(type) (type *)malloc(sizeof(type))
54#endif
55
56#define NSS_ARGS(args) ((nss_XbyY_args_t *)args)
57
58#ifdef HPUX
59
60/*
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
64 */
65
66struct 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;
76};
77
78#endif /* HPUX */
79
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); \
89}
90
91static NSS_STATUS _nss_winbind_setpwent_solwrap (nss_backend_t* be, void* args)
92{
93 NSS_DEBUG("_nss_winbind_setpwent_solwrap");
94 return _nss_winbind_setpwent();
95}
96
97static NSS_STATUS
98_nss_winbind_endpwent_solwrap (nss_backend_t * be, void *args)
99{
100 NSS_DEBUG("_nss_winbind_endpwent_solwrap");
101 return _nss_winbind_endpwent();
102}
103
104static NSS_STATUS
105_nss_winbind_getpwent_solwrap (nss_backend_t* be, void *args)
106{
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];
113
114 ret = _nss_winbind_getpwent_r(result, buffer,
115 buflen, errnop);
116
117 if(ret == NSS_STATUS_SUCCESS)
118 {
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);
126 }
127
128 return ret;
129}
130
131static NSS_STATUS
132_nss_winbind_getpwnam_solwrap (nss_backend_t* be, void* args)
133{
134 NSS_STATUS ret;
135 struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result;
136
137 NSS_DEBUG("_nss_winbind_getpwnam_solwrap");
138
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;
146
147 return ret;
148}
149
150static NSS_STATUS
151_nss_winbind_getpwuid_solwrap(nss_backend_t* be, void* args)
152{
153 NSS_STATUS ret;
154 struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result;
155
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;
164
165 return ret;
166}
167
168static NSS_STATUS _nss_winbind_passwd_destr (nss_backend_t * be, void *args)
169{
170 SAFE_FREE(be);
171 NSS_DEBUG("_nss_winbind_passwd_destr");
172 return NSS_STATUS_SUCCESS;
173}
174
175static nss_backend_op_t passwd_ops[] =
176{
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 */
183};
184
185nss_backend_t*
186_nss_winbind_passwd_constr (const char* db_name,
187 const char* src_name,
188 const char* cfg_args)
189{
190 nss_backend_t *be;
191
192 if(!(be = SMB_MALLOC_P(nss_backend_t)) )
193 return NULL;
194
195 be->ops = passwd_ops;
196 be->n_ops = sizeof(passwd_ops) / sizeof(nss_backend_op_t);
197
198 NSS_DEBUG("Initialized nss_winbind passwd backend");
199 return be;
200}
201
202/*****************************************************************
203 GROUP database backend
204 *****************************************************************/
205
206static NSS_STATUS _nss_winbind_setgrent_solwrap (nss_backend_t* be, void* args)
207{
208 NSS_DEBUG("_nss_winbind_setgrent_solwrap");
209 return _nss_winbind_setgrent();
210}
211
212static NSS_STATUS
213_nss_winbind_endgrent_solwrap (nss_backend_t * be, void *args)
214{
215 NSS_DEBUG("_nss_winbind_endgrent_solwrap");
216 return _nss_winbind_endgrent();
217}
218
219static NSS_STATUS
220_nss_winbind_getgrent_solwrap(nss_backend_t* be, void* args)
221{
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];
228
229 ret = _nss_winbind_getgrent_r(result, buffer,
230 buflen, errnop);
231
232 if(ret == NSS_STATUS_SUCCESS)
233 {
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);
240 }
241
242 return ret;
243
244}
245
246static NSS_STATUS
247_nss_winbind_getgrnam_solwrap(nss_backend_t* be, void* args)
248{
249 NSS_STATUS ret;
250 struct group* result = (struct group*) NSS_ARGS(args)->buf.result;
251
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);
258
259 if(ret == NSS_STATUS_SUCCESS)
260 NSS_ARGS(args)->returnval = (void*) result;
261
262 if (NSS_ARGS(args)->erange == ERANGE && ret == NSS_STATUS_TRYAGAIN)
263 return NSS_STATUS_UNAVAIL;
264
265 return ret;
266}
267
268static NSS_STATUS
269_nss_winbind_getgrgid_solwrap(nss_backend_t* be, void* args)
270{
271 NSS_STATUS ret;
272 struct group* result = (struct group*) NSS_ARGS(args)->buf.result;
273
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);
280
281 if(ret == NSS_STATUS_SUCCESS)
282 NSS_ARGS(args)->returnval = (void*) result;
283
284 if (NSS_ARGS(args)->erange == ERANGE && ret == NSS_STATUS_TRYAGAIN)
285 return NSS_STATUS_UNAVAIL;
286
287 return ret;
288}
289
290static NSS_STATUS
291_nss_winbind_getgroupsbymember_solwrap(nss_backend_t* be, void* args)
292{
293 int errnop;
294 struct nss_groupsbymem *gmem = (struct nss_groupsbymem *)args;
295 long int numgids = gmem->numgids;
296 long int maxgids = gmem->maxgids;
297
298 NSS_DEBUG("_nss_winbind_getgroupsbymember");
299
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);
307
308 gmem->numgids = numgids;
309 gmem->maxgids = maxgids;
310
311 /*
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.
317 */
318 return (gmem->numgids == gmem->maxgids ? NSS_STATUS_SUCCESS : NSS_STATUS_NOTFOUND);
319}
320
321static NSS_STATUS
322_nss_winbind_group_destr (nss_backend_t* be, void* args)
323{
324 SAFE_FREE(be);
325 NSS_DEBUG("_nss_winbind_group_destr");
326 return NSS_STATUS_SUCCESS;
327}
328
329static nss_backend_op_t group_ops[] =
330{
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
338};
339
340nss_backend_t*
341_nss_winbind_group_constr (const char* db_name,
342 const char* src_name,
343 const char* cfg_args)
344{
345 nss_backend_t* be;
346
347 if(!(be = SMB_MALLOC_P(nss_backend_t)) )
348 return NULL;
349
350 be->ops = group_ops;
351 be->n_ops = sizeof(group_ops) / sizeof(nss_backend_op_t);
352
353 NSS_DEBUG("Initialized nss_winbind group backend");
354 return be;
355}
356
357/*****************************************************************
358 hosts and ipnodes backend
359 *****************************************************************/
360#if defined(SUNOS5) /* not compatible with HP-UX */
361
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. */
365
366static NSS_STATUS
367parse_response(int af, nss_XbyY_args_t* argp, struct winbindd_response *response)
368{
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;
373
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;
382
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.
386 */
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;
392 }
393
394 for(; p != response->data.winsresp; p--) {
395 if(*p == '\t') addrcount++;
396 }
397
398 if(addrcount == 0) {/* it must be broken */
399 argp->h_errno = NO_DATA;
400 return NSS_STATUS_UNAVAIL;
401 }
402
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;
412 }
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;
421 }
422#endif
423
424 /* buffer too small?! */
425 if((char *)he->h_addr_list < buffer ) {
426 argp->erange = 1;
427 return NSS_STR_PARSE_ERANGE;
428 }
429
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... */
434
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;
441 }
442 }
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;
450 }
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;
456 }
457 IN6_INADDR_TO_V4MAPPED(&in4, &addrp6[i]);
458 }
459 }
460#endif
461 data = p+1;
462 }
463
464 he->h_addr_list[i] = (char *)NULL;
465
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;
470 }
471
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;
483 }
484
485 argp->returnval = (void*)he;
486 return ret;
487}
488
489static NSS_STATUS
490_nss_winbind_ipnodes_getbyname(nss_backend_t* be, void *args)
491{
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;
497
498 ZERO_STRUCT(response);
499 ZERO_STRUCT(request);
500
501 /* I assume there that AI_ADDRCONFIG cases are handled in nss
502 frontend code, at least it seems done so in solaris...
503
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.
507 */
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;
514 }
515#else
516 /* I'm not that sure if this is correct, but... */
517 af = AF_INET6;
518#endif
519#endif
520
521 strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1);
522 request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0';
523
524 if( (ret = winbindd_request_response(NULL, WINBINDD_WINS_BYNAME,
525 &request, &response))
526 == NSS_STATUS_SUCCESS ) {
527 ret = parse_response(af, argp, &response);
528 }
529
530 winbindd_free_response(&response);
531 return ret;
532}
533
534static NSS_STATUS
535_nss_winbind_hosts_getbyname(nss_backend_t* be, void *args)
536{
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;
541
542 ZERO_STRUCT(response);
543 ZERO_STRUCT(request);
544
545 strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1);
546 request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0';
547
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);
552 }
553
554 winbindd_free_response(&response);
555 return ret;
556}
557
558static NSS_STATUS
559_nss_winbind_hosts_getbyaddr(nss_backend_t* be, void *args)
560{
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;
566
567 ZERO_STRUCT(response);
568 ZERO_STRUCT(request);
569
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;
575 }
576
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
587
588 ret = winbindd_request_response(NULL, WINBINDD_WINS_BYIP,
589 &request, &response);
590
591 if( ret == NSS_STATUS_SUCCESS) {
592 parse_response(argp->key.hostaddr.type, argp, &response);
593 }
594 winbindd_free_response(&response);
595 return ret;
596}
597
598/* winbind does not provide setent, getent, endent for wins */
599static NSS_STATUS
600_nss_winbind_common_endent(nss_backend_t* be, void *args)
601{
602 return (NSS_STATUS_UNAVAIL);
603}
604
605static NSS_STATUS
606_nss_winbind_common_setent(nss_backend_t* be, void *args)
607{
608 return (NSS_STATUS_UNAVAIL);
609}
610
611static NSS_STATUS
612_nss_winbind_common_getent(nss_backend_t* be, void *args)
613{
614 return (NSS_STATUS_UNAVAIL);
615}
616
617static nss_backend_t*
618_nss_winbind_common_constr (nss_backend_op_t ops[], int n_ops)
619{
620 nss_backend_t* be;
621
622 if(!(be = SMB_MALLOC_P(nss_backend_t)) )
623 return NULL;
624
625 be->ops = ops;
626 be->n_ops = n_ops;
627
628 return be;
629}
630
631static NSS_STATUS
632_nss_winbind_common_destr (nss_backend_t* be, void* args)
633{
634 SAFE_FREE(be);
635 return NSS_STATUS_SUCCESS;
636}
637
638static 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,
645};
646
647nss_backend_t *
648_nss_winbind_ipnodes_constr(dummy1, dummy2, dummy3)
649 const char *dummy1, *dummy2, *dummy3;
650{
651 return (_nss_winbind_common_constr(ipnodes_ops,
652 sizeof (ipnodes_ops) / sizeof (ipnodes_ops[0])));
653}
654
655static 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,
662};
663
664nss_backend_t *
665_nss_winbind_hosts_constr(dummy1, dummy2, dummy3)
666 const char *dummy1, *dummy2, *dummy3;
667{
668 return (_nss_winbind_common_constr(host_ops,
669 sizeof (host_ops) / sizeof (host_ops[0])));
670}
671
672#endif /* defined(SUNOS5) */
673#endif /* defined(HAVE_NSS_COMMON_H) || defined(HPUX) */
Note: See TracBrowser for help on using the repository browser.