diff options
Diffstat (limited to 'source3/nsswitch')
-rw-r--r-- | source3/nsswitch/wb_common.c | 108 | ||||
-rw-r--r-- | source3/nsswitch/winbind_nss.c | 504 | ||||
-rw-r--r-- | source3/nsswitch/wins.c | 151 |
3 files changed, 666 insertions, 97 deletions
diff --git a/source3/nsswitch/wb_common.c b/source3/nsswitch/wb_common.c index 0cfefa6f86..d3feaeb450 100644 --- a/source3/nsswitch/wb_common.c +++ b/source3/nsswitch/wb_common.c @@ -28,9 +28,19 @@ /* Global variables. These are effectively the client state information */ -static int established_socket = -1; /* fd for winbindd socket */ +int winbindd_fd = -1; /* fd for winbindd socket */ static char *excluded_domain; +/* Free a response structure */ + +void free_response(struct winbindd_response *response) +{ + /* Free any allocated extra_data */ + + if (response) + SAFE_FREE(response->extra_data); +} + /* smbd needs to be able to exclude lookups for its own domain */ @@ -77,15 +87,15 @@ void init_response(struct winbindd_response *response) void close_sock(void) { - if (established_socket != -1) { - close(established_socket); - established_socket = -1; + if (winbindd_fd != -1) { + close(winbindd_fd); + winbindd_fd = -1; } } /* Connect to winbindd socket */ -static int open_pipe_sock(void) +int winbind_open_pipe_sock(void) { struct sockaddr_un sunaddr; static pid_t our_pid; @@ -93,15 +103,12 @@ static int open_pipe_sock(void) pstring path; if (our_pid != getpid()) { - if (established_socket != -1) { - close(established_socket); - } - established_socket = -1; + close_sock(); our_pid = getpid(); } - if (established_socket != -1) { - return established_socket; + if (winbindd_fd != -1) { + return winbindd_fd; } /* Check permissions on unix socket directory */ @@ -147,18 +154,17 @@ static int open_pipe_sock(void) /* Connect to socket */ - if ((established_socket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + if ((winbindd_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { return -1; } - if (connect(established_socket, (struct sockaddr *)&sunaddr, + if (connect(winbindd_fd, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) { close_sock(); - established_socket = -1; return -1; } - return established_socket; + return winbindd_fd; } /* Write data to winbindd socket with timeout */ @@ -171,7 +177,7 @@ int write_sock(void *buffer, int count) restart: - if (open_pipe_sock() == -1) { + if (winbind_open_pipe_sock() == -1) { return -1; } @@ -182,28 +188,26 @@ int write_sock(void *buffer, int count) while(nwritten < count) { struct timeval tv; fd_set r_fds; - int selret; /* Catch pipe close on other end by checking if a read() call would not block by calling select(). */ FD_ZERO(&r_fds); - FD_SET(established_socket, &r_fds); + FD_SET(winbindd_fd, &r_fds); ZERO_STRUCT(tv); - if ((selret = select(established_socket + 1, &r_fds, - NULL, NULL, &tv)) == -1) { + if (select(winbindd_fd + 1, &r_fds, NULL, NULL, &tv) == -1) { close_sock(); return -1; /* Select error */ } /* Write should be OK if fd not available for reading */ - if (!FD_ISSET(established_socket, &r_fds)) { + if (!FD_ISSET(winbindd_fd, &r_fds)) { /* Do the write */ - result = write(established_socket, + result = write(winbindd_fd, (char *)buffer + nwritten, count - nwritten); @@ -239,7 +243,7 @@ static int read_sock(void *buffer, int count) while(nread < count) { - result = read(established_socket, (char *)buffer + nread, + result = read(winbindd_fd, (char *)buffer + nread, count - nread); if ((result == -1) || (result == 0)) { @@ -296,6 +300,7 @@ int read_reply(struct winbindd_response *response) if ((result2 = read_sock(response->extra_data, extra_data_len)) == -1) { + free_response(response); return -1; } } @@ -305,24 +310,13 @@ int read_reply(struct winbindd_response *response) return result1 + result2; } -/* Free a response structure */ - -void free_response(struct winbindd_response *response) -{ - /* Free any allocated extra_data */ - - if (response) - SAFE_FREE(response->extra_data); -} - -/* Handle simple types of requests */ +/* + * send simple types of requests + */ -NSS_STATUS winbindd_request(int req_type, - struct winbindd_request *request, - struct winbindd_response *response) +NSS_STATUS winbindd_send_request(int req_type, struct winbindd_request *request) { struct winbindd_request lrequest; - struct winbindd_response lresponse; /* Check for our tricky environment variable */ @@ -336,11 +330,6 @@ NSS_STATUS winbindd_request(int req_type, return NSS_STATUS_NOTFOUND; } - if (!response) { - ZERO_STRUCT(lresponse); - response = &lresponse; - } - if (!request) { ZERO_STRUCT(lrequest); request = &lrequest; @@ -349,12 +338,29 @@ NSS_STATUS winbindd_request(int req_type, /* Fill in request and send down pipe */ init_request(request, req_type); - init_response(response); if (write_sock(request, sizeof(*request)) == -1) { return NSS_STATUS_UNAVAIL; } + return NSS_STATUS_SUCCESS; +} + +/* + * Get results from winbindd request + */ + +NSS_STATUS winbindd_get_response(struct winbindd_response *response) +{ + struct winbindd_response lresponse; + + if (!response) { + ZERO_STRUCT(lresponse); + response = &lresponse; + } + + init_response(response); + /* Wait for reply */ if (read_reply(response) == -1) { return NSS_STATUS_UNAVAIL; @@ -372,3 +378,17 @@ NSS_STATUS winbindd_request(int req_type, return NSS_STATUS_SUCCESS; } + +/* Handle simple types of requests */ + +NSS_STATUS winbindd_request(int req_type, + struct winbindd_request *request, + struct winbindd_response *response) +{ + NSS_STATUS status; + + status = winbindd_send_request(req_type, request); + if (status != NSS_STATUS_SUCCESS) + return(status); + return winbindd_get_response(response); +} diff --git a/source3/nsswitch/winbind_nss.c b/source3/nsswitch/winbind_nss.c index 462c791277..0c4a61d2cb 100644 --- a/source3/nsswitch/winbind_nss.c +++ b/source3/nsswitch/winbind_nss.c @@ -25,16 +25,489 @@ #include "winbind_nss_config.h" #include "winbindd_nss.h" -/* Prototypes from common.c */ +#ifdef HAVE_NS_API_H +#undef VOLATILE + +#include <ns_daemon.h> +#endif + +#define MAX_GETPWENT_USERS 250 +#define MAX_GETGRENT_USERS 250 + +/* Prototypes from wb_common.c */ + +extern int winbindd_fd; void init_request(struct winbindd_request *req,int rq_type); +NSS_STATUS winbindd_send_request(int req_type, + struct winbindd_request *request); +NSS_STATUS winbindd_get_response(struct winbindd_response *response); NSS_STATUS winbindd_request(int req_type, struct winbindd_request *request, struct winbindd_response *response); +int winbind_open_pipe_sock(void); int write_sock(void *buffer, int count); int read_reply(struct winbindd_response *response); void free_response(struct winbindd_response *response); +#ifdef HAVE_NS_API_H +/* IRIX version */ + +static int send_next_request(nsd_file_t *, struct winbindd_request *); +static int do_list(int state, nsd_file_t *rq); + +static nsd_file_t *current_rq = NULL; +static int current_winbind_xid = 0; +static int next_winbind_xid = 0; + +typedef struct winbind_xid { + int xid; + nsd_file_t *rq; + struct winbindd_request *request; + struct winbind_xid *next; +} winbind_xid_t; + +static winbind_xid_t *winbind_xids = (winbind_xid_t *)0; + +static int +winbind_xid_new(int xid, nsd_file_t *rq, struct winbindd_request *request) +{ + winbind_xid_t *new; + + nsd_logprintf(NSD_LOG_LOW, + "entering winbind_xid_new xid = %d rq = 0x%x, request = 0x%x\n", + xid, rq, request); + new = (winbind_xid_t *)nsd_calloc(1,sizeof(winbind_xid_t)); + if (!new) { + nsd_logprintf(NSD_LOG_RESOURCE,"winbind_xid_new: failed malloc\n"); + return NSD_ERROR; + } + + new->xid = xid; + new->rq = rq; + new->request = request; + new->next = winbind_xids; + winbind_xids = new; + + return NSD_CONTINUE; +} + +/* +** This routine will look down the xid list and return the request +** associated with an xid. We remove the record if it is found. +*/ +nsd_file_t * +winbind_xid_lookup(int xid, struct winbindd_request **requestp) +{ + winbind_xid_t **last, *dx; + nsd_file_t *result=0; + + for (last = &winbind_xids, dx = winbind_xids; dx && (dx->xid != xid); + last = &dx->next, dx = dx->next); + if (dx) { + *last = dx->next; + result = dx->rq; + *requestp = dx->request; + free(dx); + } + nsd_logprintf(NSD_LOG_LOW, + "entering winbind_xid_lookup xid = %d rq = 0x%x, request = 0x%x\n", + xid, result, dx->request); + + return result; +} + +static int +winbind_startnext_timeout(nsd_file_t **rqp, nsd_times_t *to) +{ + nsd_file_t *rq; + struct winbindd_request *request; + + nsd_logprintf(NSD_LOG_MIN, "timeout (winbind startnext)\n"); + rq = to->t_file; + *rqp = rq; + nsd_timeout_remove(rq); + request = to->t_clientdata; + return(send_next_request(rq, request)); +} + +static void +dequeue_request() +{ + nsd_file_t *rq; + struct winbindd_request *request; + + /* + * Check for queued requests + */ + if (winbind_xids) { + nsd_logprintf(NSD_LOG_MIN, "timeout (winbind) unqueue xid %d\n", + current_winbind_xid); + rq = winbind_xid_lookup(current_winbind_xid++, &request); + /* cause a timeout on the queued request so we can send it */ + nsd_timeout_new(rq,1,winbind_startnext_timeout,request); + } +} + +static int +do_request(nsd_file_t *rq, struct winbindd_request *request) +{ + if (winbind_xids == NULL) { + /* + * No outstanding requests. + * Send off the request to winbindd + */ + nsd_logprintf(NSD_LOG_MIN, "lookup (winbind) sending request\n"); + return(send_next_request(rq, request)); + } else { + /* + * Just queue it up for now - previous callout or timout + * will start it up + */ + nsd_logprintf(NSD_LOG_MIN, + "lookup (winbind): queue request xid = %d\n", + next_winbind_xid); + return(winbind_xid_new(next_winbind_xid++, rq, request)); + } +} + +static int +winbind_callback(nsd_file_t **rqp, int fd) +{ + struct winbindd_response response; + struct winbindd_pw *pw = &response.data.pw; + struct winbindd_gr *gr = &response.data.gr; + nsd_file_t *rq; + NSS_STATUS status; + char result[1024]; + char *members; + int i; + + dequeue_request(); + + nsd_logprintf(NSD_LOG_MIN, "entering callback (winbind)\n"); + + rq = current_rq; + *rqp = rq; + + nsd_timeout_remove(rq); + nsd_callback_remove(fd); + + ZERO_STRUCT(response); + status = winbindd_get_response(&response); + + if (status != NSS_STATUS_SUCCESS) { + /* free any extra data area in response structure */ + free_response(&response); + nsd_logprintf(NSD_LOG_MIN, + "callback (winbind) returning not found, status = %d\n", + status); + rq->f_status = NS_NOTFOUND; + return NSD_NEXT; + } + switch ((int)rq->f_cmd_data) { + case WINBINDD_GETPWNAM_FROM_UID: + case WINBINDD_GETPWNAM_FROM_USER: + snprintf(result,1023,"%s:%s:%d:%d:%s:%s:%s\n", + pw->pw_name, + pw->pw_passwd, + pw->pw_uid, + pw->pw_gid, + pw->pw_gecos, + pw->pw_dir, + pw->pw_shell); + break; + case WINBINDD_GETGRNAM_FROM_GROUP: + case WINBINDD_GETGRNAM_FROM_GID: + if (gr->num_gr_mem && response.extra_data) + members = response.extra_data; + else + members = ""; + snprintf(result,1023,"%s:%s:%d:%s\n", + gr->gr_name, gr->gr_passwd, gr->gr_gid, members); + break; + case WINBINDD_SETGRENT: + case WINBINDD_SETPWENT: + nsd_logprintf(NSD_LOG_MIN, "callback (winbind) - SETPWENT/SETGRENT\n"); + free_response(&response); + return(do_list(1,rq)); + case WINBINDD_GETGRENT: + nsd_logprintf(NSD_LOG_MIN, + "callback (winbind) - %d GETGRENT responses\n", + response.data.num_entries); + if (response.data.num_entries) { + gr = (struct winbindd_gr *)response.extra_data; + if (! gr ) { + nsd_logprintf(NSD_LOG_MIN, " no extra_data\n"); + free_response(&response); + return NSD_ERROR; + } + members = (char *)response.extra_data + + (response.data.num_entries * sizeof(struct winbindd_gr)); + for (i = 0; i < response.data.num_entries; i++) { + snprintf(result,1023,"%s:%s:%d:%s\n", + gr->gr_name, gr->gr_passwd, gr->gr_gid, + &members[gr->gr_mem_ofs]); + nsd_logprintf(NSD_LOG_MIN, " GETGRENT %s\n",result); + nsd_append_element(rq,NS_SUCCESS,result,strlen(result)); + gr++; + } + } + i = response.data.num_entries; + free_response(&response); + if (i < MAX_GETPWENT_USERS) + return(do_list(2,rq)); + else + return(do_list(1,rq)); + case WINBINDD_GETPWENT: + nsd_logprintf(NSD_LOG_MIN, + "callback (winbind) - %d GETPWENT responses\n", + response.data.num_entries); + if (response.data.num_entries) { + pw = (struct winbindd_pw *)response.extra_data; + if (! pw ) { + nsd_logprintf(NSD_LOG_MIN, " no extra_data\n"); + free_response(&response); + return NSD_ERROR; + } + for (i = 0; i < response.data.num_entries; i++) { + snprintf(result,1023,"%s:%s:%d:%d:%s:%s:%s", + pw->pw_name, + pw->pw_passwd, + pw->pw_uid, + pw->pw_gid, + pw->pw_gecos, + pw->pw_dir, + pw->pw_shell); + nsd_logprintf(NSD_LOG_MIN, " GETPWENT %s\n",result); + nsd_append_element(rq,NS_SUCCESS,result,strlen(result)); + pw++; + } + } + i = response.data.num_entries; + free_response(&response); + if (i < MAX_GETPWENT_USERS) + return(do_list(2,rq)); + else + return(do_list(1,rq)); + case WINBINDD_ENDGRENT: + case WINBINDD_ENDPWENT: + nsd_logprintf(NSD_LOG_MIN, "callback (winbind) - ENDPWENT/ENDGRENT\n"); + nsd_append_element(rq,NS_SUCCESS,"\n",1); + free_response(&response); + return NSD_NEXT; + default: + free_response(&response); + nsd_logprintf(NSD_LOG_MIN, "callback (winbind) - no valid command\n"); + return NSD_NEXT; + } + nsd_logprintf(NSD_LOG_MIN, "callback (winbind) %s\n", result); + /* free any extra data area in response structure */ + free_response(&response); + nsd_set_result(rq,NS_SUCCESS,result,strlen(result),VOLATILE); + return NSD_OK; +} + +static int +winbind_timeout(nsd_file_t **rqp, nsd_times_t *to) +{ + nsd_file_t *rq; + + dequeue_request(); + + nsd_logprintf(NSD_LOG_MIN, "timeout (winbind)\n"); + + rq = to->t_file; + *rqp = rq; + + /* Remove the callback and timeout */ + nsd_callback_remove(winbindd_fd); + nsd_timeout_remove(rq); + + rq->f_status = NS_NOTFOUND; + return NSD_NEXT; +} + +static int +send_next_request(nsd_file_t *rq, struct winbindd_request *request) +{ + NSS_STATUS status; + long timeout; + + timeout = 1000; + + nsd_logprintf(NSD_LOG_MIN, "send_next_request (winbind) %d to = %d\n", + rq->f_cmd_data, timeout); + status = winbindd_send_request((int)rq->f_cmd_data,request); + free(request); + + if (status != NSS_STATUS_SUCCESS) { + nsd_logprintf(NSD_LOG_MIN, + "send_next_request (winbind) error status = %d\n",status); + rq->f_status = status; + return NSD_NEXT; + } + + current_rq = rq; + + /* + * Set up callback and timeouts + */ + nsd_logprintf(NSD_LOG_MIN, "send_next_request (winbind) fd = %d\n",winbindd_fd); + nsd_callback_new(winbindd_fd,winbind_callback,NSD_READ); + nsd_timeout_new(rq,timeout,winbind_timeout,(void *)0); + return NSD_CONTINUE; +} + +int init(void) +{ + nsd_logprintf(NSD_LOG_MIN, "entering init (winbind)\n"); + return(NSD_OK); +} + +int lookup(nsd_file_t *rq) +{ + char *map; + char *key; + struct winbindd_request *request; + + nsd_logprintf(NSD_LOG_MIN, "entering lookup (winbind)\n"); + if (! rq) + return NSD_ERROR; + + map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0); + key = nsd_attr_fetch_string(rq->f_attrs, "key", (char*)0); + if (! map || ! key) { + nsd_logprintf(NSD_LOG_MIN, "lookup (winbind) table or key not defined\n"); + rq->f_status = NS_BADREQ; + return NSD_ERROR; + } + + nsd_logprintf(NSD_LOG_MIN, "lookup (winbind %s)\n",map); + + request = (struct winbindd_request *)nsd_calloc(1,sizeof(struct winbindd_request)); + if (! request) { + nsd_logprintf(NSD_LOG_RESOURCE, + "lookup (winbind): failed malloc\n"); + return NSD_ERROR; + } + + if (strcasecmp(map,"passwd.byuid") == 0) { + request->data.uid = atoi(key); + rq->f_cmd_data = (void *)WINBINDD_GETPWNAM_FROM_UID; + } else if (strcasecmp(map,"passwd.byname") == 0) { + strncpy(request->data.username, key, + sizeof(request->data.username) - 1); + request->data.username[sizeof(request->data.username) - 1] = '\0'; + rq->f_cmd_data = (void *)WINBINDD_GETPWNAM_FROM_USER; + } else if (strcasecmp(map,"group.byname") == 0) { + strncpy(request->data.groupname, key, + sizeof(request->data.groupname) - 1); + request->data.groupname[sizeof(request->data.groupname) - 1] = '\0'; + rq->f_cmd_data = (void *)WINBINDD_GETGRNAM_FROM_GROUP; + } else if (strcasecmp(map,"group.bygid") == 0) { + request->data.gid = atoi(key); + rq->f_cmd_data = (void *)WINBINDD_GETGRNAM_FROM_GID; + } else { + /* + * Don't understand this map - just return not found + */ + nsd_logprintf(NSD_LOG_MIN, "lookup (winbind) unknown table\n"); + free(request); + rq->f_status = NS_NOTFOUND; + return NSD_NEXT; + } + + return(do_request(rq, request)); +} + +int list(nsd_file_t *rq) +{ + char *map; + + nsd_logprintf(NSD_LOG_MIN, "entering list (winbind)\n"); + if (! rq) + return NSD_ERROR; + + map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0); + if (! map ) { + nsd_logprintf(NSD_LOG_MIN, "list (winbind) table not defined\n"); + rq->f_status = NS_BADREQ; + return NSD_ERROR; + } + + nsd_logprintf(NSD_LOG_MIN, "list (winbind %s)\n",map); + + return (do_list(0,rq)); +} + +static int +do_list(int state, nsd_file_t *rq) +{ + char *map; + struct winbindd_request *request; + + nsd_logprintf(NSD_LOG_MIN, "entering do_list (winbind) state = %d\n",state); + + map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0); + request = (struct winbindd_request *)nsd_calloc(1,sizeof(struct winbindd_request)); + if (! request) { + nsd_logprintf(NSD_LOG_RESOURCE, + "do_list (winbind): failed malloc\n"); + return NSD_ERROR; + } + + if (strcasecmp(map,"passwd.byname") == 0) { + switch (state) { + case 0: + rq->f_cmd_data = (void *)WINBINDD_SETPWENT; + break; + case 1: + request->data.num_entries = MAX_GETPWENT_USERS; + rq->f_cmd_data = (void *)WINBINDD_GETPWENT; + break; + case 2: + rq->f_cmd_data = (void *)WINBINDD_ENDPWENT; + break; + default: + nsd_logprintf(NSD_LOG_MIN, "do_list (winbind) unknown state\n"); + free(request); + rq->f_status = NS_NOTFOUND; + return NSD_NEXT; + } + } else if (strcasecmp(map,"group.byname") == 0) { + switch (state) { + case 0: + rq->f_cmd_data = (void *)WINBINDD_SETGRENT; + break; + case 1: + request->data.num_entries = MAX_GETGRENT_USERS; + rq->f_cmd_data = (void *)WINBINDD_GETGRENT; + break; + case 2: + rq->f_cmd_data = (void *)WINBINDD_ENDGRENT; + break; + default: + nsd_logprintf(NSD_LOG_MIN, "do_list (winbind) unknown state\n"); + free(request); + rq->f_status = NS_NOTFOUND; + return NSD_NEXT; + } + } else { + /* + * Don't understand this map - just return not found + */ + nsd_logprintf(NSD_LOG_MIN, "do_list (winbind) unknown table\n"); + free(request); + rq->f_status = NS_NOTFOUND; + return NSD_NEXT; + } + + return(do_request(rq, request)); +} + +#else + /* Allocate some space from the nss static buffer. The buffer and buflen are the pointers passed in by the C library to the _nss_ntdom_* functions. */ @@ -50,16 +523,6 @@ static char *get_static(char **buffer, int *buflen, int len) return NULL; } - /* Some architectures, like Sparc, need pointers aligned on - boundaries */ -#if _ALIGNMENT_REQUIRED - { - int mod = len % _MAX_ALIGNMENT; - if(mod != 0) - len += _MAX_ALIGNMENT - mod; - } -#endif - /* Return an index into the static buffer */ result = *buffer; @@ -194,6 +657,7 @@ static int fill_grent(struct group *result, struct winbindd_gr *gr, { fstring name; int i; + char *tst; /* Group name */ @@ -229,14 +693,20 @@ static int fill_grent(struct group *result, struct winbindd_gr *gr, gr->num_gr_mem = 0; } - if ((result->gr_mem = - (char **)get_static(buffer, buflen, (gr->num_gr_mem + 1) * - sizeof(char *))) == NULL) { + /* this next value is a pointer to a pointer so let's align it */ + + /* Calculate number of extra bytes needed to align on pointer size boundry */ + if (i = (int)*buffer % sizeof(char*)) + i = sizeof(char*) - i; + + if ((tst = get_static(buffer, buflen, ((gr->num_gr_mem + 1) * + sizeof(char *)+i))) == NULL) { /* Out of memory */ return NSS_STATUS_TRYAGAIN; } + result->gr_mem = (char **)(tst + i); if (gr->num_gr_mem == 0) { @@ -318,8 +788,6 @@ _nss_winbind_endpwent(void) /* Fetch the next password entry from ntdom password database */ -#define MAX_GETPWENT_USERS 250 - NSS_STATUS _nss_winbind_getpwent_r(struct passwd *result, char *buffer, size_t buflen, int *errnop) @@ -562,8 +1030,6 @@ _nss_winbind_endgrent(void) /* Get next entry from ntdom group database */ -#define MAX_GETGRENT_USERS 250 - NSS_STATUS _nss_winbind_getgrent_r(struct group *result, char *buffer, size_t buflen, int *errnop) @@ -844,3 +1310,5 @@ _nss_winbind_initgroups_dyn(char *user, gid_t group, long int *start, done: return ret; } + +#endif diff --git a/source3/nsswitch/wins.c b/source3/nsswitch/wins.c index 0ab0954812..8f34222bbf 100644 --- a/source3/nsswitch/wins.c +++ b/source3/nsswitch/wins.c @@ -27,7 +27,6 @@ #undef VOLATILE #include <ns_daemon.h> -#define NSD_LOGLEVEL NSD_LOG_MIN #endif #ifndef INADDRSZ @@ -36,6 +35,7 @@ static int initialised; +extern BOOL AllowDebugChange; /* Use our own create socket code so we don't recurse.... */ @@ -64,8 +64,12 @@ static int wins_lookup_open_socket_in(void) /* now we've got a socket - we need to bind it */ - if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0) + if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0) { + close(res); return(-1); + } + + set_socket_options(res,"SO_BROADCAST"); return res; } @@ -75,13 +79,42 @@ static void nss_wins_init(void) { initialised = 1; DEBUGLEVEL = 0; + AllowDebugChange = False; + + /* needed for lp_xx() functions */ + charset_initialise(); + TimeInit(); setup_logging("nss_wins",False); lp_load(dyn_CONFIGFILE,True,False,False); load_interfaces(); + codepage_initialise(lp_client_code_page()); +} + +static struct node_status *lookup_byaddr_backend(char *addr, int *count) +{ + int fd; + struct in_addr ip; + struct nmb_name nname; + struct node_status *status; + + if (!initialised) { + nss_wins_init(); + } + + fd = wins_lookup_open_socket_in(); + if (fd == -1) + return NULL; + + make_nmb_name(&nname, "*", 0); + ip = *interpret_addr2(addr); + status = node_status_query(fd,&nname,ip, count); + + close(fd); + return status; } -static struct in_addr *lookup_backend(const char *name, int *count) +static struct in_addr *lookup_byname_backend(const char *name, int *count) { int fd; struct in_addr *ret = NULL; @@ -98,15 +131,6 @@ static struct in_addr *lookup_backend(const char *name, int *count) if (fd == -1) return NULL; - set_socket_options(fd,"SO_BROADCAST"); - -/* The next four lines commented out by JHT - and replaced with the four lines following */ -/* if( !is_zero_ip( wins_ip ) ) { - * ret = name_query( fd, name, 0x20, False, True, wins_src_ip(), count ); - * goto out; - * } - */ p = wins_srv_ip(); if( !is_zero_ip(p) ) { ret = name_query(fd,name,0x20,False,True, p, count); @@ -135,16 +159,12 @@ static struct in_addr *lookup_backend(const char *name, int *count) } -/**************************************************************************** -gethostbyname() - we ignore any domain portion of the name and only -handle names that are at most 15 characters long - **************************************************************************/ #ifdef HAVE_NS_API_H /* IRIX version */ int init(void) { - nsd_logprintf(NSD_LOGLEVEL, "init (wins)\n"); + nsd_logprintf(NSD_LOG_MIN, "entering init (wins)\n"); nss_wins_init(); return NSD_OK; } @@ -153,11 +173,14 @@ int lookup(nsd_file_t *rq) { char *map; char *key; + char *addr; struct in_addr *ip_list; - int count; - char response[80]; + struct node_status *status; + int i, count, len, size; + char response[1024]; + BOOL found = False; - nsd_logprintf(NSD_LOGLEVEL, "lookup (wins)\n"); + nsd_logprintf(NSD_LOG_MIN, "entering lookup (wins)\n"); if (! rq) return NSD_ERROR; @@ -167,31 +190,89 @@ int lookup(nsd_file_t *rq) return NSD_ERROR; } - if (strcasecmp(map,"hosts.byname") != 0) { - rq->f_status = NS_NOTFOUND; - return NSD_NEXT; - } - key = nsd_attr_fetch_string(rq->f_attrs, "key", (char*)0); if (! key || ! *key) { rq->f_status = NS_FATAL; return NSD_ERROR; } - ip_list = lookup_backend(key, &count); - - if (!ip_list) { - rq->f_status = NSS_STATUS_NOTFOUND; - return NSD_NEXT; + response[0] = '\0'; + len = sizeof(response) - 2; + + /* + * response needs to be a string of the following format + * ip_address[ ip_address]*\tname[ alias]* + */ + if (strcasecmp(map,"hosts.byaddr") == 0) { + if ( status = lookup_byaddr_backend(key, &count)) { + size = strlen(key) + 1; + if (size > len) { + free(status); + return NSD_ERROR; + } + len -= size; + strncat(response,key,size); + strncat(response,"\t",1); + for (i = 0; i < count; i++) { + /* ignore group names */ + if (status[i].flags & 0x80) continue; + if (status[i].type == 0x20) { + size = sizeof(status[i].name) + 1; + if (size > len) { + free(status); + return NSD_ERROR; + } + len -= size; + strncat(response, status[i].name, size); + strncat(response, " ", 1); + found = True; + } + } + response[strlen(response)-1] = '\n'; + free(status); + } + } else if (strcasecmp(map,"hosts.byname") == 0) { + if (ip_list = lookup_byname_backend(key, &count)) { + for (i = count; i ; i--) { + addr = inet_ntoa(ip_list[i-1]); + size = strlen(addr) + 1; + if (size > len) { + free(ip_list); + return NSD_ERROR; + } + len -= size; + if (i != 0) + response[strlen(response)-1] = ' '; + strncat(response,addr,size); + strncat(response,"\t",1); + } + size = strlen(key) + 1; + if (size > len) { + free(ip_list); + return NSD_ERROR; + } + strncat(response,key,size); + strncat(response,"\n",1); + found = True; + free(ip_list); + } } - snprintf(response,79,"%s %s\n",inet_ntoa(*ip_list),key); - free(ip_list); - nsd_set_result(rq,NS_SUCCESS,response,strlen(response),VOLATILE); - return NSD_OK; + if (found) { + nsd_logprintf(NSD_LOG_LOW, "lookup (wins %s) %s\n",map,response); + nsd_set_result(rq,NS_SUCCESS,response,strlen(response),VOLATILE); + return NSD_OK; + } + nsd_logprintf(NSD_LOG_LOW, "lookup (wins) not found\n"); + rq->f_status = NS_NOTFOUND; + return NSD_NEXT; } #else +/**************************************************************************** +gethostbyname() - we ignore any domain portion of the name and only +handle names that are at most 15 characters long + **************************************************************************/ NSS_STATUS _nss_wins_gethostbyname_r(const char *name, struct hostent *he, char *buffer, size_t buflen, int *errnop, @@ -204,7 +285,7 @@ _nss_wins_gethostbyname_r(const char *name, struct hostent *he, memset(he, '\0', sizeof(*he)); - ip_list = lookup_backend(name, &count); + ip_list = lookup_byname_backend(name, &count); if (!ip_list) { return NSS_STATUS_NOTFOUND; } |