1/* 2 Unix SMB/CIFS implementation. 3 4 Winbind daemon - WINS related functions 5 6 Copyright (C) Andrew Tridgell 1999 7 Copyright (C) Herb Lewis 2002 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22*/ 23 24#include "includes.h" 25#include "winbindd.h" 26 27#undef DBGC_CLASS 28#define DBGC_CLASS DBGC_WINBIND 29 30/* Use our own create socket code so we don't recurse.... */ 31 32static int wins_lookup_open_socket_in(void) 33{ 34 struct sockaddr_in sock; 35 int val=1; 36 int res; 37 38 memset((char *)&sock,'\0',sizeof(sock)); 39 40#ifdef HAVE_SOCK_SIN_LEN 41 sock.sin_len = sizeof(sock); 42#endif 43 sock.sin_port = 0; 44 sock.sin_family = AF_INET; 45 sock.sin_addr.s_addr = interpret_addr("0.0.0.0"); 46 res = socket(AF_INET, SOCK_DGRAM, 0); 47 if (res == -1) 48 return -1; 49 50 setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val)); 51#ifdef SO_REUSEPORT 52 setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val)); 53#endif /* SO_REUSEPORT */ 54 55 /* now we've got a socket - we need to bind it */ 56 57 if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0) { 58 close(res); 59 return(-1); 60 } 61 62 set_socket_options(res,"SO_BROADCAST"); 63 64 return res; 65} 66 67 68static struct node_status *lookup_byaddr_backend(char *addr, int *count) 69{ 70 int fd; 71 struct in_addr ip; 72 struct nmb_name nname; 73 struct node_status *status; 74 75 fd = wins_lookup_open_socket_in(); 76 if (fd == -1) 77 return NULL; 78 79 make_nmb_name(&nname, "*", 0); 80 ip = *interpret_addr2(addr); 81 status = node_status_query(fd,&nname,ip, count, NULL); 82 83 close(fd); 84 return status; 85} 86 87static struct in_addr *lookup_byname_backend(const char *name, int *count) 88{ 89 int fd; 90 struct ip_service *ret = NULL; 91 struct in_addr *return_ip = NULL; 92 int j, i, flags = 0; 93 94 *count = 0; 95 96 /* always try with wins first */ 97 if (resolve_wins(name,0x20,&ret,count)) { 98 if ( count == 0 ) 99 return NULL; 100 if ( (return_ip = SMB_MALLOC_ARRAY(struct in_addr, *count)) == NULL ) { 101 free( ret ); 102 return NULL; 103 } 104 105 /* copy the IP addresses */ 106 for ( i=0; i<(*count); i++ ) 107 return_ip[i] = ret[i].ip; 108 109 free( ret ); 110 return return_ip; 111 } 112 113 fd = wins_lookup_open_socket_in(); 114 if (fd == -1) { 115 return NULL; 116 } 117 118 /* uggh, we have to broadcast to each interface in turn */ 119 for (j=iface_count() - 1; 120 j >= 0; 121 j--) { 122 struct in_addr *bcast = iface_n_bcast(j); 123 return_ip = name_query(fd,name,0x20,True,True,*bcast,count, &flags, NULL); 124 if (return_ip) { 125 break; 126 } 127 } 128 129 close(fd); 130 return return_ip; 131} 132 133/* Get hostname from IP */ 134 135enum winbindd_result winbindd_wins_byip(struct winbindd_cli_state *state) 136{ 137 fstring response; 138 int i, count, maxlen, size; 139 struct node_status *status; 140 141 /* Ensure null termination */ 142 state->request.data.winsreq[sizeof(state->request.data.winsreq)-1]='\0'; 143 144 DEBUG(3, ("[%5lu]: wins_byip %s\n", (unsigned long)state->pid, 145 state->request.data.winsreq)); 146 147 *response = '\0'; 148 maxlen = sizeof(response) - 1; 149 150 if ((status = lookup_byaddr_backend(state->request.data.winsreq, &count))){ 151 size = strlen(state->request.data.winsreq); 152 if (size > maxlen) { 153 SAFE_FREE(status); 154 return WINBINDD_ERROR; 155 } 156 fstrcat(response,state->request.data.winsreq); 157 fstrcat(response,"\t"); 158 for (i = 0; i < count; i++) { 159 /* ignore group names */ 160 if (status[i].flags & 0x80) continue; 161 if (status[i].type == 0x20) { 162 size = sizeof(status[i].name) + strlen(response); 163 if (size > maxlen) { 164 SAFE_FREE(status); 165 return WINBINDD_ERROR; 166 } 167 fstrcat(response, status[i].name); 168 fstrcat(response, " "); 169 } 170 } 171 /* make last character a newline */ 172 response[strlen(response)-1] = '\n'; 173 SAFE_FREE(status); 174 } 175 fstrcpy(state->response.data.winsresp,response); 176 return WINBINDD_OK; 177} 178 179/* Get IP from hostname */ 180 181enum winbindd_result winbindd_wins_byname(struct winbindd_cli_state *state) 182{ 183 struct in_addr *ip_list; 184 int i, count, maxlen, size; 185 fstring response; 186 char * addr; 187 188 /* Ensure null termination */ 189 state->request.data.winsreq[sizeof(state->request.data.winsreq)-1]='\0'; 190 191 DEBUG(3, ("[%5lu]: wins_byname %s\n", (unsigned long)state->pid, 192 state->request.data.winsreq)); 193 194 *response = '\0'; 195 maxlen = sizeof(response) - 1; 196 197 if ((ip_list = lookup_byname_backend(state->request.data.winsreq,&count))){ 198 for (i = count; i ; i--) { 199 addr = inet_ntoa(ip_list[i-1]); 200 size = strlen(addr); 201 if (size > maxlen) { 202 SAFE_FREE(ip_list); 203 return WINBINDD_ERROR; 204 } 205 if (i != 0) { 206 /* Clear out the newline character */ 207 /* But only if there is something in there, 208 otherwise we clobber something in the stack */ 209 if (strlen(response)) 210 response[strlen(response)-1] = ' '; 211 } 212 fstrcat(response,addr); 213 fstrcat(response,"\t"); 214 } 215 size = strlen(state->request.data.winsreq) + strlen(response); 216 if (size > maxlen) { 217 SAFE_FREE(ip_list); 218 return WINBINDD_ERROR; 219 } 220 fstrcat(response,state->request.data.winsreq); 221 fstrcat(response,"\n"); 222 SAFE_FREE(ip_list); 223 } else 224 return WINBINDD_ERROR; 225 226 fstrcpy(state->response.data.winsresp,response); 227 228 return WINBINDD_OK; 229} 230