1/* 2 Unix SMB/CIFS implementation. 3 a WINS nsswitch module 4 Copyright (C) Andrew Tridgell 1999 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 20*/ 21 22#define NO_SYSLOG 23 24#include "includes.h" 25#ifdef HAVE_NS_API_H 26#undef VOLATILE 27 28#include <ns_daemon.h> 29#endif 30 31#ifndef INADDRSZ 32#define INADDRSZ 4 33#endif 34 35static int initialised; 36 37extern BOOL AllowDebugChange; 38 39/* Use our own create socket code so we don't recurse.... */ 40 41static int wins_lookup_open_socket_in(void) 42{ 43 struct sockaddr_in sock; 44 int val=1; 45 int res; 46 47 memset((char *)&sock,'\0',sizeof(sock)); 48 49#ifdef HAVE_SOCK_SIN_LEN 50 sock.sin_len = sizeof(sock); 51#endif 52 sock.sin_port = 0; 53 sock.sin_family = AF_INET; 54 sock.sin_addr.s_addr = interpret_addr("0.0.0.0"); 55 res = socket(AF_INET, SOCK_DGRAM, 0); 56 if (res == -1) 57 return -1; 58 59 setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val)); 60#ifdef SO_REUSEPORT 61 setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val)); 62#endif /* SO_REUSEPORT */ 63 64 /* now we've got a socket - we need to bind it */ 65 66 if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0) { 67 close(res); 68 return(-1); 69 } 70 71 set_socket_options(res,"SO_BROADCAST"); 72 73 return res; 74} 75 76 77static void nss_wins_init(void) 78{ 79 initialised = 1; 80 DEBUGLEVEL = 0; 81 AllowDebugChange = False; 82 83 TimeInit(); 84 setup_logging("nss_wins",False); 85 lp_load(dyn_CONFIGFILE,True,False,False); 86 load_interfaces(); 87} 88 89static struct in_addr *lookup_byname_backend(const char *name, int *count) 90{ 91 int fd = -1; 92 struct ip_service *address = NULL; 93 struct in_addr *ret = NULL; 94 int j, flags = 0; 95 96 if (!initialised) { 97 nss_wins_init(); 98 } 99 100 *count = 0; 101 102 /* always try with wins first */ 103 if (resolve_wins(name,0x00,&address,count)) { 104 if ( (ret = SMB_MALLOC_P(struct in_addr)) == NULL ) { 105 free( address ); 106 return NULL; 107 } 108 *ret = address[0].ip; 109 free( address ); 110 return ret; 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;j >= 0;j--) { 120 struct in_addr *bcast = iface_n_bcast(j); 121 ret = name_query(fd,name,0x00,True,True,*bcast,count, &flags, NULL); 122 if (ret) break; 123 } 124 125 close(fd); 126 return ret; 127} 128 129#ifdef HAVE_NS_API_H 130 131static struct node_status *lookup_byaddr_backend(char *addr, int *count) 132{ 133 int fd; 134 struct in_addr ip; 135 struct nmb_name nname; 136 struct node_status *status; 137 138 if (!initialised) { 139 nss_wins_init(); 140 } 141 142 fd = wins_lookup_open_socket_in(); 143 if (fd == -1) 144 return NULL; 145 146 make_nmb_name(&nname, "*", 0); 147 ip = *interpret_addr2(addr); 148 status = node_status_query(fd,&nname,ip, count, NULL); 149 150 close(fd); 151 return status; 152} 153 154/* IRIX version */ 155 156int init(void) 157{ 158 nsd_logprintf(NSD_LOG_MIN, "entering init (wins)\n"); 159 nss_wins_init(); 160 return NSD_OK; 161} 162 163int lookup(nsd_file_t *rq) 164{ 165 char *map; 166 char *key; 167 char *addr; 168 struct in_addr *ip_list; 169 struct node_status *status; 170 int i, count, len, size; 171 char response[1024]; 172 BOOL found = False; 173 174 nsd_logprintf(NSD_LOG_MIN, "entering lookup (wins)\n"); 175 if (! rq) 176 return NSD_ERROR; 177 178 map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0); 179 if (! map) { 180 rq->f_status = NS_FATAL; 181 return NSD_ERROR; 182 } 183 184 key = nsd_attr_fetch_string(rq->f_attrs, "key", (char*)0); 185 if (! key || ! *key) { 186 rq->f_status = NS_FATAL; 187 return NSD_ERROR; 188 } 189 190 response[0] = '\0'; 191 len = sizeof(response) - 2; 192 193 /* 194 * response needs to be a string of the following format 195 * ip_address[ ip_address]*\tname[ alias]* 196 */ 197 if (StrCaseCmp(map,"hosts.byaddr") == 0) { 198 if ( status = lookup_byaddr_backend(key, &count)) { 199 size = strlen(key) + 1; 200 if (size > len) { 201 free(status); 202 return NSD_ERROR; 203 } 204 len -= size; 205 strncat(response,key,size); 206 strncat(response,"\t",1); 207 for (i = 0; i < count; i++) { 208 /* ignore group names */ 209 if (status[i].flags & 0x80) continue; 210 if (status[i].type == 0x20) { 211 size = sizeof(status[i].name) + 1; 212 if (size > len) { 213 free(status); 214 return NSD_ERROR; 215 } 216 len -= size; 217 strncat(response, status[i].name, size); 218 strncat(response, " ", 1); 219 found = True; 220 } 221 } 222 response[strlen(response)-1] = '\n'; 223 free(status); 224 } 225 } else if (StrCaseCmp(map,"hosts.byname") == 0) { 226 if (ip_list = lookup_byname_backend(key, &count)) { 227 for (i = count; i ; i--) { 228 addr = inet_ntoa(ip_list[i-1]); 229 size = strlen(addr) + 1; 230 if (size > len) { 231 free(ip_list); 232 return NSD_ERROR; 233 } 234 len -= size; 235 if (i != 0) 236 response[strlen(response)-1] = ' '; 237 strncat(response,addr,size); 238 strncat(response,"\t",1); 239 } 240 size = strlen(key) + 1; 241 if (size > len) { 242 free(ip_list); 243 return NSD_ERROR; 244 } 245 strncat(response,key,size); 246 strncat(response,"\n",1); 247 found = True; 248 free(ip_list); 249 } 250 } 251 252 if (found) { 253 nsd_logprintf(NSD_LOG_LOW, "lookup (wins %s) %s\n",map,response); 254 nsd_set_result(rq,NS_SUCCESS,response,strlen(response),VOLATILE); 255 return NSD_OK; 256 } 257 nsd_logprintf(NSD_LOG_LOW, "lookup (wins) not found\n"); 258 rq->f_status = NS_NOTFOUND; 259 return NSD_NEXT; 260} 261 262#else 263 264/* Allocate some space from the nss static buffer. The buffer and buflen 265 are the pointers passed in by the C library to the _nss_*_* 266 functions. */ 267 268static char *get_static(char **buffer, size_t *buflen, int len) 269{ 270 char *result; 271 272 /* Error check. We return false if things aren't set up right, or 273 there isn't enough buffer space left. */ 274 275 if ((buffer == NULL) || (buflen == NULL) || (*buflen < len)) { 276 return NULL; 277 } 278 279 /* Return an index into the static buffer */ 280 281 result = *buffer; 282 *buffer += len; 283 *buflen -= len; 284 285 return result; 286} 287 288/**************************************************************************** 289gethostbyname() - we ignore any domain portion of the name and only 290handle names that are at most 15 characters long 291 **************************************************************************/ 292NSS_STATUS 293_nss_wins_gethostbyname_r(const char *hostname, struct hostent *he, 294 char *buffer, size_t buflen, int *h_errnop) 295{ 296 struct in_addr *ip_list; 297 int i, count; 298 fstring name; 299 size_t namelen; 300 301 memset(he, '\0', sizeof(*he)); 302 fstrcpy(name, hostname); 303 304 /* Do lookup */ 305 306 ip_list = lookup_byname_backend(name, &count); 307 308 if (!ip_list) 309 return NSS_STATUS_NOTFOUND; 310 311 /* Copy h_name */ 312 313 namelen = strlen(name) + 1; 314 315 if ((he->h_name = get_static(&buffer, &buflen, namelen)) == NULL) 316 return NSS_STATUS_TRYAGAIN; 317 318 memcpy(he->h_name, name, namelen); 319 320 /* Copy h_addr_list, align to pointer boundary first */ 321 322 if ((i = (unsigned long)(buffer) % sizeof(char*)) != 0) 323 i = sizeof(char*) - i; 324 325 if (get_static(&buffer, &buflen, i) == NULL) 326 return NSS_STATUS_TRYAGAIN; 327 328 if ((he->h_addr_list = (char **)get_static( 329 &buffer, &buflen, (count + 1) * sizeof(char *))) == NULL) 330 return NSS_STATUS_TRYAGAIN; 331 332 for (i = 0; i < count; i++) { 333 if ((he->h_addr_list[i] = get_static(&buffer, &buflen, 334 INADDRSZ)) == NULL) 335 return NSS_STATUS_TRYAGAIN; 336 memcpy(he->h_addr_list[i], &ip_list[i], INADDRSZ); 337 } 338 339 he->h_addr_list[count] = NULL; 340 341 if (ip_list) 342 free(ip_list); 343 344 /* Set h_addr_type and h_length */ 345 346 he->h_addrtype = AF_INET; 347 he->h_length = INADDRSZ; 348 349 /* Set h_aliases */ 350 351 if ((i = (unsigned long)(buffer) % sizeof(char*)) != 0) 352 i = sizeof(char*) - i; 353 354 if (get_static(&buffer, &buflen, i) == NULL) 355 return NSS_STATUS_TRYAGAIN; 356 357 if ((he->h_aliases = (char **)get_static( 358 &buffer, &buflen, sizeof(char *))) == NULL) 359 return NSS_STATUS_TRYAGAIN; 360 361 he->h_aliases[0] = NULL; 362 363 return NSS_STATUS_SUCCESS; 364} 365 366 367NSS_STATUS 368_nss_wins_gethostbyname2_r(const char *name, int af, struct hostent *he, 369 char *buffer, size_t buflen, int *h_errnop) 370{ 371 if(af!=AF_INET) { 372 *h_errnop = NO_DATA; 373 return NSS_STATUS_UNAVAIL; 374 } 375 376 return _nss_wins_gethostbyname_r( 377 name, he, buffer, buflen, h_errnop); 378} 379#endif 380