source: branches/samba-3.0/source/nsswitch/winbind_nss_solaris.c

Last change on this file was 165, checked in by Paul Smedley, 16 years ago

Add 'missing' 3.0.34 diffs

File size: 17.0 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 Library General Public License as
14 published by the Free Software Foundation; either version 2 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 Library General Public
23 License along with the nss_ldap library; see the file COPYING.LIB. If not,
24 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 Boston, MA 02111-1307, USA.
26*/
27
28#undef DEVELOPER
29
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*/
40#include "winbind_nss_config.h"
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#define NSS_ARGS(args) ((nss_XbyY_args_t *)args)
53
54#ifdef HPUX
55
56/*
57 * HP-UX 11 has no definiton of the nss_groupsbymem structure. This
58 * definition is taken from the nss_ldap project at:
59 * http://www.padl.com/OSS/nss_ldap.html
60 */
61
62struct nss_groupsbymem {
63 const char *username;
64 gid_t *gid_array;
65 int maxgids;
66 int force_slow_way;
67 int (*str2ent)(const char *instr, int instr_len, void *ent,
68 char *buffer, int buflen);
69 nss_status_t (*process_cstr)(const char *instr, int instr_len,
70 struct nss_groupsbymem *);
71 int numgids;
72};
73
74#endif /* HPUX */
75
76#define make_pwent_str(dest, src) \
77{ \
78 if((dest = get_static(buffer, buflen, strlen(src)+1)) == NULL) \
79 { \
80 *errnop = ERANGE; \
81 NSS_DEBUG("ERANGE error"); \
82 return NSS_STATUS_TRYAGAIN; \
83 } \
84 strcpy(dest, src); \
85}
86
87static NSS_STATUS _nss_winbind_setpwent_solwrap (nss_backend_t* be, void* args)
88{
89 NSS_DEBUG("_nss_winbind_setpwent_solwrap");
90 return _nss_winbind_setpwent();
91}
92
93static NSS_STATUS
94_nss_winbind_endpwent_solwrap (nss_backend_t * be, void *args)
95{
96 NSS_DEBUG("_nss_winbind_endpwent_solwrap");
97 return _nss_winbind_endpwent();
98}
99
100static NSS_STATUS
101_nss_winbind_getpwent_solwrap (nss_backend_t* be, void *args)
102{
103 NSS_STATUS ret;
104 char* buffer = NSS_ARGS(args)->buf.buffer;
105 int buflen = NSS_ARGS(args)->buf.buflen;
106 struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result;
107 int* errnop = &NSS_ARGS(args)->erange;
108 char logmsg[80];
109
110 ret = _nss_winbind_getpwent_r(result, buffer,
111 buflen, errnop);
112
113 if(ret == NSS_STATUS_SUCCESS)
114 {
115 snprintf(logmsg, 79, "_nss_winbind_getpwent_solwrap: Returning user: %s\n",
116 result->pw_name);
117 NSS_DEBUG(logmsg);
118 NSS_ARGS(args)->returnval = (void*) result;
119 } else {
120 snprintf(logmsg, 79, "_nss_winbind_getpwent_solwrap: Returning error: %d.\n",ret);
121 NSS_DEBUG(logmsg);
122 }
123
124 return ret;
125}
126
127static NSS_STATUS
128_nss_winbind_getpwnam_solwrap (nss_backend_t* be, void* args)
129{
130 NSS_STATUS ret;
131 struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result;
132
133 NSS_DEBUG("_nss_winbind_getpwnam_solwrap");
134
135 ret = _nss_winbind_getpwnam_r (NSS_ARGS(args)->key.name,
136 result,
137 NSS_ARGS(args)->buf.buffer,
138 NSS_ARGS(args)->buf.buflen,
139 &NSS_ARGS(args)->erange);
140 if(ret == NSS_STATUS_SUCCESS)
141 NSS_ARGS(args)->returnval = (void*) result;
142
143 return ret;
144}
145
146static NSS_STATUS
147_nss_winbind_getpwuid_solwrap(nss_backend_t* be, void* args)
148{
149 NSS_STATUS ret;
150 struct passwd* result = (struct passwd*) NSS_ARGS(args)->buf.result;
151
152 NSS_DEBUG("_nss_winbind_getpwuid_solwrap");
153 ret = _nss_winbind_getpwuid_r (NSS_ARGS(args)->key.uid,
154 result,
155 NSS_ARGS(args)->buf.buffer,
156 NSS_ARGS(args)->buf.buflen,
157 &NSS_ARGS(args)->erange);
158 if(ret == NSS_STATUS_SUCCESS)
159 NSS_ARGS(args)->returnval = (void*) result;
160
161 return ret;
162}
163
164static NSS_STATUS _nss_winbind_passwd_destr (nss_backend_t * be, void *args)
165{
166 SAFE_FREE(be);
167 NSS_DEBUG("_nss_winbind_passwd_destr");
168 return NSS_STATUS_SUCCESS;
169}
170
171static nss_backend_op_t passwd_ops[] =
172{
173 _nss_winbind_passwd_destr,
174 _nss_winbind_endpwent_solwrap, /* NSS_DBOP_ENDENT */
175 _nss_winbind_setpwent_solwrap, /* NSS_DBOP_SETENT */
176 _nss_winbind_getpwent_solwrap, /* NSS_DBOP_GETENT */
177 _nss_winbind_getpwnam_solwrap, /* NSS_DBOP_PASSWD_BYNAME */
178 _nss_winbind_getpwuid_solwrap /* NSS_DBOP_PASSWD_BYUID */
179};
180
181nss_backend_t*
182_nss_winbind_passwd_constr (const char* db_name,
183 const char* src_name,
184 const char* cfg_args)
185{
186 nss_backend_t *be;
187
188 if(!(be = SMB_MALLOC_P(nss_backend_t)) )
189 return NULL;
190
191 be->ops = passwd_ops;
192 be->n_ops = sizeof(passwd_ops) / sizeof(nss_backend_op_t);
193
194 NSS_DEBUG("Initialized nss_winbind passwd backend");
195 return be;
196}
197
198/*****************************************************************
199 GROUP database backend
200 *****************************************************************/
201
202static NSS_STATUS _nss_winbind_setgrent_solwrap (nss_backend_t* be, void* args)
203{
204 NSS_DEBUG("_nss_winbind_setgrent_solwrap");
205 return _nss_winbind_setgrent();
206}
207
208static NSS_STATUS
209_nss_winbind_endgrent_solwrap (nss_backend_t * be, void *args)
210{
211 NSS_DEBUG("_nss_winbind_endgrent_solwrap");
212 return _nss_winbind_endgrent();
213}
214
215static NSS_STATUS
216_nss_winbind_getgrent_solwrap(nss_backend_t* be, void* args)
217{
218 NSS_STATUS ret;
219 char* buffer = NSS_ARGS(args)->buf.buffer;
220 int buflen = NSS_ARGS(args)->buf.buflen;
221 struct group* result = (struct group*) NSS_ARGS(args)->buf.result;
222 int* errnop = &NSS_ARGS(args)->erange;
223 char logmsg[80];
224
225 ret = _nss_winbind_getgrent_r(result, buffer,
226 buflen, errnop);
227
228 if(ret == NSS_STATUS_SUCCESS)
229 {
230 snprintf(logmsg, 79, "_nss_winbind_getgrent_solwrap: Returning group: %s\n", result->gr_name);
231 NSS_DEBUG(logmsg);
232 NSS_ARGS(args)->returnval = (void*) result;
233 } else {
234 snprintf(logmsg, 79, "_nss_winbind_getgrent_solwrap: Returning error: %d.\n", ret);
235 NSS_DEBUG(logmsg);
236 }
237
238 return ret;
239
240}
241
242static NSS_STATUS
243_nss_winbind_getgrnam_solwrap(nss_backend_t* be, void* args)
244{
245 NSS_STATUS ret;
246 struct group* result = (struct group*) NSS_ARGS(args)->buf.result;
247
248 NSS_DEBUG("_nss_winbind_getgrnam_solwrap");
249 ret = _nss_winbind_getgrnam_r(NSS_ARGS(args)->key.name,
250 result,
251 NSS_ARGS(args)->buf.buffer,
252 NSS_ARGS(args)->buf.buflen,
253 &NSS_ARGS(args)->erange);
254
255 if(ret == NSS_STATUS_SUCCESS)
256 NSS_ARGS(args)->returnval = (void*) result;
257
258 return ret;
259}
260
261static NSS_STATUS
262_nss_winbind_getgrgid_solwrap(nss_backend_t* be, void* args)
263{
264 NSS_STATUS ret;
265 struct group* result = (struct group*) NSS_ARGS(args)->buf.result;
266
267 NSS_DEBUG("_nss_winbind_getgrgid_solwrap");
268 ret = _nss_winbind_getgrgid_r (NSS_ARGS(args)->key.gid,
269 result,
270 NSS_ARGS(args)->buf.buffer,
271 NSS_ARGS(args)->buf.buflen,
272 &NSS_ARGS(args)->erange);
273
274 if(ret == NSS_STATUS_SUCCESS)
275 NSS_ARGS(args)->returnval = (void*) result;
276
277 return ret;
278}
279
280static NSS_STATUS
281_nss_winbind_getgroupsbymember_solwrap(nss_backend_t* be, void* args)
282{
283 int errnop;
284 struct nss_groupsbymem *gmem = (struct nss_groupsbymem *)args;
285
286 NSS_DEBUG("_nss_winbind_getgroupsbymember");
287
288 _nss_winbind_initgroups_dyn(gmem->username,
289 gmem->gid_array[0], /* Primary Group */
290 &gmem->numgids,
291 &gmem->maxgids,
292 &gmem->gid_array,
293 gmem->maxgids,
294 &errnop);
295
296 /*
297 * If the maximum number of gids have been found, return
298 * SUCCESS so the switch engine will stop searching. Otherwise
299 * return NOTFOUND so nsswitch will continue to get groups
300 * from the remaining database backends specified in the
301 * nsswitch.conf file.
302 */
303 return (gmem->numgids == gmem->maxgids ? NSS_STATUS_SUCCESS : NSS_STATUS_NOTFOUND);
304}
305
306static NSS_STATUS
307_nss_winbind_group_destr (nss_backend_t* be, void* args)
308{
309 SAFE_FREE(be);
310 NSS_DEBUG("_nss_winbind_group_destr");
311 return NSS_STATUS_SUCCESS;
312}
313
314static nss_backend_op_t group_ops[] =
315{
316 _nss_winbind_group_destr,
317 _nss_winbind_endgrent_solwrap,
318 _nss_winbind_setgrent_solwrap,
319 _nss_winbind_getgrent_solwrap,
320 _nss_winbind_getgrnam_solwrap,
321 _nss_winbind_getgrgid_solwrap,
322 _nss_winbind_getgroupsbymember_solwrap
323};
324
325nss_backend_t*
326_nss_winbind_group_constr (const char* db_name,
327 const char* src_name,
328 const char* cfg_args)
329{
330 nss_backend_t* be;
331
332 if(!(be = SMB_MALLOC_P(nss_backend_t)) )
333 return NULL;
334
335 be->ops = group_ops;
336 be->n_ops = sizeof(group_ops) / sizeof(nss_backend_op_t);
337
338 NSS_DEBUG("Initialized nss_winbind group backend");
339 return be;
340}
341
342/*****************************************************************
343 hosts and ipnodes backend
344 *****************************************************************/
345#if defined(SUNOS5) /* not compatible with HP-UX */
346
347/* this parser is shared between get*byname and get*byaddr, as key type
348 in request is stored in different locations, I had to provide the
349 address family as an argument, caller must free the winbind response. */
350
351static NSS_STATUS
352parse_response(int af, nss_XbyY_args_t* argp, struct winbindd_response *response)
353{
354 struct hostent *he = (struct hostent *)argp->buf.result;
355 char *buffer = argp->buf.buffer;
356 int buflen = argp->buf.buflen;
357 NSS_STATUS ret;
358
359 char *p, *data;
360 int addrcount = 0;
361 int len = 0;
362 struct in_addr *addrp;
363#if defined(AF_INET6)
364 struct in6_addr *addrp6;
365#endif
366 int i;
367
368 /* response is tab separated list of ip addresses with hostname
369 and newline at the end. so at first we will strip newline
370 then construct list of addresses for hostent.
371 */
372 p = strchr(response->data.winsresp, '\n');
373 if(p) *p = '\0';
374 else {/* it must be broken */
375 argp->h_errno = NO_DATA;
376 return NSS_STATUS_UNAVAIL;
377 }
378
379 for(; p != response->data.winsresp; p--) {
380 if(*p == '\t') addrcount++;
381 }
382
383 if(addrcount == 0) {/* it must be broken */
384 argp->h_errno = NO_DATA;
385 return NSS_STATUS_UNAVAIL;
386 }
387
388 /* allocate space for addresses and h_addr_list */
389 he->h_addrtype = af;
390 if( he->h_addrtype == AF_INET) {
391 he->h_length = sizeof(struct in_addr);
392 addrp = (struct in_addr *)ROUND_DOWN(buffer + buflen,
393 sizeof(struct in_addr));
394 addrp -= addrcount;
395 he->h_addr_list = (char **)ROUND_DOWN(addrp, sizeof (char*));
396 he->h_addr_list -= addrcount+1;
397 }
398#if defined(AF_INET6)
399 else {
400 he->h_length = sizeof(struct in6_addr);
401 addrp6 = (struct in6_addr *)ROUND_DOWN(buffer + buflen,
402 sizeof(struct in6_addr));
403 addrp6 -= addrcount;
404 he->h_addr_list = (char **)ROUND_DOWN(addrp6, sizeof (char*));
405 he->h_addr_list -= addrcount+1;
406 }
407#endif
408
409 /* buffer too small?! */
410 if((char *)he->h_addr_list < buffer ) {
411 argp->erange = 1;
412 return NSS_STR_PARSE_ERANGE;
413 }
414
415 data = response->data.winsresp;
416 for( i = 0; i < addrcount; i++) {
417 p = strchr(data, '\t');
418 if(p == NULL) break; /* just in case... */
419
420 *p = '\0'; /* terminate the string */
421 if(he->h_addrtype == AF_INET) {
422 he->h_addr_list[i] = (char *)&addrp[i];
423 if ((addrp[i].s_addr = inet_addr(data)) == -1) {
424 argp->erange = 1;
425 return NSS_STR_PARSE_ERANGE;
426 }
427 }
428#if defined(AF_INET6)
429 else {
430 he->h_addr_list[i] = (char *)&addrp6[i];
431 if (strchr(data, ':') != 0) {
432 if (inet_pton(AF_INET6, data, &addrp6[i]) != 1) {
433 argp->erange = 1;
434 return NSS_STR_PARSE_ERANGE;
435 }
436 } else {
437 struct in_addr in4;
438 if ((in4.s_addr = inet_addr(data)) == -1) {
439 argp->erange = 1;
440 return NSS_STR_PARSE_ERANGE;
441 }
442 IN6_INADDR_TO_V4MAPPED(&in4, &addrp6[i]);
443 }
444 }
445#endif
446 data = p+1;
447 }
448
449 he->h_addr_list[i] = (char *)NULL;
450
451 len = strlen(data);
452 if(len > he->h_addr_list - (char**)argp->buf.buffer) {
453 argp->erange = 1;
454 return NSS_STR_PARSE_ERANGE;
455 }
456
457 /* this is a bit overkill to use _nss_netdb_aliases here since
458 there seems to be no aliases but it will create all data for us */
459 he->h_aliases = _nss_netdb_aliases(data, len, buffer,
460 ((char*) he->h_addr_list) - buffer);
461 if(he->h_aliases == NULL) {
462 argp->erange = 1;
463 ret = NSS_STR_PARSE_ERANGE;
464 } else {
465 he->h_name = he->h_aliases[0];
466 he->h_aliases++;
467 ret = NSS_STR_PARSE_SUCCESS;
468 }
469
470 argp->returnval = (void*)he;
471 return ret;
472}
473
474static NSS_STATUS
475_nss_winbind_ipnodes_getbyname(nss_backend_t* be, void *args)
476{
477 nss_XbyY_args_t *argp = (nss_XbyY_args_t*) args;
478 struct winbindd_response response;
479 struct winbindd_request request;
480 NSS_STATUS ret;
481 int af;
482
483 ZERO_STRUCT(response);
484 ZERO_STRUCT(request);
485
486 /* I assume there that AI_ADDRCONFIG cases are handled in nss
487 frontend code, at least it seems done so in solaris...
488
489 we will give NO_DATA for pure IPv6; IPv4 will be returned for
490 AF_INET or for AF_INET6 and AI_ALL|AI_V4MAPPED we have to map
491 IPv4 to IPv6.
492 */
493#if defined(AF_INET6)
494#ifdef HAVE_NSS_XBYY_KEY_IPNODE
495 af = argp->key.ipnode.af_family;
496 if(af == AF_INET6 && argp->key.ipnode.flags == 0) {
497 argp->h_errno = NO_DATA;
498 return NSS_STATUS_UNAVAIL;
499 }
500#else
501 /* I'm not that sure if this is correct, but... */
502 af = AF_INET6;
503#endif
504#endif
505
506 strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1);
507 request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0';
508
509 if( (ret = winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response))
510 == NSS_STATUS_SUCCESS ) {
511 ret = parse_response(af, argp, &response);
512 }
513
514 free_response(&response);
515 return ret;
516}
517
518static NSS_STATUS
519_nss_winbind_hosts_getbyname(nss_backend_t* be, void *args)
520{
521 nss_XbyY_args_t *argp = (nss_XbyY_args_t*) args;
522 struct winbindd_response response;
523 struct winbindd_request request;
524 NSS_STATUS ret;
525
526 ZERO_STRUCT(response);
527 ZERO_STRUCT(request);
528
529 strncpy(request.data.winsreq, argp->key.name, sizeof(request.data.winsreq) - 1);
530 request.data.winsreq[sizeof(request.data.winsreq) - 1] = '\0';
531
532 if( (ret = winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response))
533 == NSS_STATUS_SUCCESS ) {
534 ret = parse_response(AF_INET, argp, &response);
535 }
536
537 free_response(&response);
538 return ret;
539}
540
541static NSS_STATUS
542_nss_winbind_hosts_getbyaddr(nss_backend_t* be, void *args)
543{
544 NSS_STATUS ret;
545 struct winbindd_response response;
546 struct winbindd_request request;
547 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)args;
548 const char *p;
549
550 ZERO_STRUCT(response);
551 ZERO_STRUCT(request);
552
553#if defined(AF_INET6)
554 /* winbindd currently does not resolve IPv6 */
555 if(argp->key.hostaddr.type == AF_INET6) {
556 argp->h_errno = NO_DATA;
557 return NSS_STATUS_UNAVAIL;
558 }
559
560 p = inet_ntop(argp->key.hostaddr.type, argp->key.hostaddr.addr,
561 request.data.winsreq, sizeof request.data.winsreq);
562#else
563 snprintf(request.data.winsreq, sizeof request.data.winsreq,
564 "%u.%u.%u.%u",
565 ((unsigned char *)argp->key.hostaddr.addr)[0],
566 ((unsigned char *)argp->key.hostaddr.addr)[1],
567 ((unsigned char *)argp->key.hostaddr.addr)[2],
568 ((unsigned char *)argp->key.hostaddr.addr)[3]);
569#endif
570
571 ret = winbindd_request_response(WINBINDD_WINS_BYIP, &request, &response);
572
573 if( ret == NSS_STATUS_SUCCESS) {
574 parse_response(argp->key.hostaddr.type, argp, &response);
575 }
576 free_response(&response);
577 return ret;
578}
579
580/* winbind does not provide setent, getent, endent for wins */
581static NSS_STATUS
582_nss_winbind_common_endent(nss_backend_t* be, void *args)
583{
584 return (NSS_STATUS_UNAVAIL);
585}
586
587static NSS_STATUS
588_nss_winbind_common_setent(nss_backend_t* be, void *args)
589{
590 return (NSS_STATUS_UNAVAIL);
591}
592
593static NSS_STATUS
594_nss_winbind_common_getent(nss_backend_t* be, void *args)
595{
596 return (NSS_STATUS_UNAVAIL);
597}
598
599static nss_backend_t*
600_nss_winbind_common_constr (nss_backend_op_t ops[], int n_ops)
601{
602 nss_backend_t* be;
603
604 if(!(be = SMB_MALLOC_P(nss_backend_t)) )
605 return NULL;
606
607 be->ops = ops;
608 be->n_ops = n_ops;
609
610 return be;
611}
612
613static NSS_STATUS
614_nss_winbind_common_destr (nss_backend_t* be, void* args)
615{
616 SAFE_FREE(be);
617 return NSS_STATUS_SUCCESS;
618}
619
620static nss_backend_op_t ipnodes_ops[] = {
621 _nss_winbind_common_destr,
622 _nss_winbind_common_endent,
623 _nss_winbind_common_setent,
624 _nss_winbind_common_getent,
625 _nss_winbind_ipnodes_getbyname,
626 _nss_winbind_hosts_getbyaddr,
627};
628
629nss_backend_t *
630_nss_winbind_ipnodes_constr(dummy1, dummy2, dummy3)
631 const char *dummy1, *dummy2, *dummy3;
632{
633 return (_nss_winbind_common_constr(ipnodes_ops,
634 sizeof (ipnodes_ops) / sizeof (ipnodes_ops[0])));
635}
636
637static nss_backend_op_t host_ops[] = {
638 _nss_winbind_common_destr,
639 _nss_winbind_common_endent,
640 _nss_winbind_common_setent,
641 _nss_winbind_common_getent,
642 _nss_winbind_hosts_getbyname,
643 _nss_winbind_hosts_getbyaddr,
644};
645
646nss_backend_t *
647_nss_winbind_hosts_constr(dummy1, dummy2, dummy3)
648 const char *dummy1, *dummy2, *dummy3;
649{
650 return (_nss_winbind_common_constr(host_ops,
651 sizeof (host_ops) / sizeof (host_ops[0])));
652}
653
654#endif /* defined(SUNOS5) */
655#endif /* defined(HAVE_NSS_COMMON_H) || defined(HPUX) */
Note: See TracBrowser for help on using the repository browser.