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 3 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, see <http://www.gnu.org/licenses/>. 21*/ 22 23#include "includes.h" 24#include "winbindd.h" 25 26#undef DBGC_CLASS 27#define DBGC_CLASS DBGC_WINBIND 28 29/* Use our own create socket code so we don't recurse.... */ 30 31static int wins_lookup_open_socket_in(void) 32{ 33 struct sockaddr_in sock; 34 int val=1; 35 int res; 36 37 memset((char *)&sock,'\0',sizeof(sock)); 38 39#ifdef HAVE_SOCK_SIN_LEN 40 sock.sin_len = sizeof(sock); 41#endif 42 sock.sin_port = 0; 43 sock.sin_family = AF_INET; 44 sock.sin_addr.s_addr = interpret_addr("0.0.0.0"); 45 res = socket(AF_INET, SOCK_DGRAM, 0); 46 if (res == -1) 47 return -1; 48 49 if (setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val))) { 50 close(res); 51 return -1; 52 } 53#ifdef SO_REUSEPORT 54 if (setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val))) { 55 close(res); 56 return -1; 57 } 58#endif /* SO_REUSEPORT */ 59 60 /* now we've got a socket - we need to bind it */ 61 62 if (bind(res, (struct sockaddr *)(void *)&sock, sizeof(sock)) < 0) { 63 close(res); 64 return(-1); 65 } 66 67 set_socket_options(res,"SO_BROADCAST"); 68 69 return res; 70} 71 72 73static NODE_STATUS_STRUCT *lookup_byaddr_backend(const char *addr, int *count) 74{ 75 int fd; 76 struct sockaddr_storage ss; 77 struct nmb_name nname; 78 NODE_STATUS_STRUCT *status; 79 80 fd = wins_lookup_open_socket_in(); 81 if (fd == -1) 82 return NULL; 83 84 make_nmb_name(&nname, "*", 0); 85 if (!interpret_string_addr(&ss, addr, AI_NUMERICHOST)) { 86 return NULL; 87 } 88 status = node_status_query(fd, &nname, &ss, count, NULL, 2000); 89 90 close(fd); 91 return status; 92} 93 94static struct sockaddr_storage *lookup_byname_backend(const char *name, 95 int *count) 96{ 97 int fd; 98 struct ip_service *ret = NULL; 99 struct sockaddr_storage *return_ss = NULL; 100 int j, i, flags = 0; 101 102 *count = 0; 103 104 /* always try with wins first */ 105 if (NT_STATUS_IS_OK(resolve_wins(name,0x20,&ret,count))) { 106 if ( *count == 0 ) 107 return NULL; 108 if ( (return_ss = SMB_MALLOC_ARRAY(struct sockaddr_storage, *count)) == NULL ) { 109 free( ret ); 110 return NULL; 111 } 112 113 /* copy the IP addresses */ 114 for ( i=0; i<(*count); i++ ) 115 return_ss[i] = ret[i].ss; 116 117 free( ret ); 118 return return_ss; 119 } 120 121 fd = wins_lookup_open_socket_in(); 122 if (fd == -1) { 123 return NULL; 124 } 125 126 /* uggh, we have to broadcast to each interface in turn */ 127 for (j=iface_count() - 1; 128 j >= 0; 129 j--) { 130 const struct sockaddr_storage *bcast_ss = iface_n_bcast(j); 131 if (!bcast_ss) { 132 continue; 133 } 134 return_ss = name_query(fd,name,0x20,True,True,bcast_ss,count, &flags, NULL); 135 if (return_ss) { 136 break; 137 } 138 } 139 140 close(fd); 141 return return_ss; 142} 143 144/* Get hostname from IP */ 145 146void winbindd_wins_byip(struct winbindd_cli_state *state) 147{ 148 fstring response; 149 int i, count, maxlen, size; 150 NODE_STATUS_STRUCT *status; 151 152 /* Ensure null termination */ 153 state->request->data.winsreq[sizeof(state->request->data.winsreq)-1]='\0'; 154 155 DEBUG(3, ("[%5lu]: wins_byip %s\n", (unsigned long)state->pid, 156 state->request->data.winsreq)); 157 158 *response = '\0'; 159 maxlen = sizeof(response) - 1; 160 161 if ((status = lookup_byaddr_backend(state->request->data.winsreq, &count))){ 162 size = strlen(state->request->data.winsreq); 163 if (size > maxlen) { 164 SAFE_FREE(status); 165 request_error(state); 166 return; 167 } 168 fstrcat(response,state->request->data.winsreq); 169 fstrcat(response,"\t"); 170 for (i = 0; i < count; i++) { 171 /* ignore group names */ 172 if (status[i].flags & 0x80) continue; 173 if (status[i].type == 0x20) { 174 size = sizeof(status[i].name) + strlen(response); 175 if (size > maxlen) { 176 SAFE_FREE(status); 177 request_error(state); 178 return; 179 } 180 fstrcat(response, status[i].name); 181 fstrcat(response, " "); 182 } 183 } 184 /* make last character a newline */ 185 response[strlen(response)-1] = '\n'; 186 SAFE_FREE(status); 187 } 188 fstrcpy(state->response->data.winsresp,response); 189 request_ok(state); 190} 191 192/* Get IP from hostname */ 193 194void winbindd_wins_byname(struct winbindd_cli_state *state) 195{ 196 struct sockaddr_storage *ip_list = NULL; 197 int i, count, maxlen, size; 198 fstring response; 199 char addr[INET6_ADDRSTRLEN]; 200 201 /* Ensure null termination */ 202 state->request->data.winsreq[sizeof(state->request->data.winsreq)-1]='\0'; 203 204 DEBUG(3, ("[%5lu]: wins_byname %s\n", (unsigned long)state->pid, 205 state->request->data.winsreq)); 206 207 *response = '\0'; 208 maxlen = sizeof(response) - 1; 209 210 if ((ip_list = lookup_byname_backend(state->request->data.winsreq,&count))){ 211 for (i = count; i ; i--) { 212 print_sockaddr(addr, sizeof(addr), &ip_list[i-1]); 213 size = strlen(addr); 214 if (size > maxlen) { 215 SAFE_FREE(ip_list); 216 request_error(state); 217 return; 218 } 219 if (i != 0) { 220 /* Clear out the newline character */ 221 /* But only if there is something in there, 222 otherwise we clobber something in the stack */ 223 if (strlen(response)) { 224 response[strlen(response)-1] = ' '; 225 } 226 } 227 fstrcat(response,addr); 228 fstrcat(response,"\t"); 229 } 230 size = strlen(state->request->data.winsreq) + strlen(response); 231 if (size > maxlen) { 232 SAFE_FREE(ip_list); 233 request_error(state); 234 return; 235 } 236 fstrcat(response,state->request->data.winsreq); 237 fstrcat(response,"\n"); 238 SAFE_FREE(ip_list); 239 } else { 240 request_error(state); 241 return; 242 } 243 244 fstrcpy(state->response->data.winsresp,response); 245 246 request_ok(state); 247} 248