nsswitch/wins.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    a WINS nsswitch module 
00004    Copyright (C) Andrew Tridgell 1999
00005    
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015    
00016    You should have received a copy of the GNU General Public License
00017    along with this program; if not, write to the Free Software
00018    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019    
00020 */
00021 
00022 #include "includes.h"
00023 #ifdef HAVE_NS_API_H
00024 #undef VOLATILE
00025 
00026 #include <ns_daemon.h>
00027 #endif
00028 
00029 #ifndef INADDRSZ
00030 #define INADDRSZ 4
00031 #endif
00032 
00033 static int initialised;
00034 
00035 extern BOOL AllowDebugChange;
00036 
00037 NSS_STATUS _nss_wins_gethostbyname_r(const char *hostname, struct hostent *he,
00038                           char *buffer, size_t buflen, int *h_errnop);
00039 NSS_STATUS _nss_wins_gethostbyname2_r(const char *name, int af, struct hostent *he,
00040                            char *buffer, size_t buflen, int *h_errnop);
00041 
00042 /* Use our own create socket code so we don't recurse.... */
00043 
00044 static int wins_lookup_open_socket_in(void)
00045 {
00046         struct sockaddr_in sock;
00047         int val=1;
00048         int res;
00049 
00050         memset((char *)&sock,'\0',sizeof(sock));
00051 
00052 #ifdef HAVE_SOCK_SIN_LEN
00053         sock.sin_len = sizeof(sock);
00054 #endif
00055         sock.sin_port = 0;
00056         sock.sin_family = AF_INET;
00057         sock.sin_addr.s_addr = interpret_addr("0.0.0.0");
00058         res = socket(AF_INET, SOCK_DGRAM, 0);
00059         if (res == -1)
00060                 return -1;
00061 
00062         setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val));
00063 #ifdef SO_REUSEPORT
00064         setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val));
00065 #endif /* SO_REUSEPORT */
00066 
00067         /* now we've got a socket - we need to bind it */
00068 
00069         if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0) {
00070                 close(res);
00071                 return(-1);
00072         }
00073 
00074         set_socket_options(res,"SO_BROADCAST");
00075 
00076         return res;
00077 }
00078 
00079 
00080 static void nss_wins_init(void)
00081 {
00082         initialised = 1;
00083         DEBUGLEVEL = 0;
00084         AllowDebugChange = False;
00085 
00086         TimeInit();
00087         setup_logging("nss_wins",False);
00088         load_case_tables();
00089         lp_load(dyn_CONFIGFILE,True,False,False,True);
00090         load_interfaces();
00091 }
00092 
00093 static struct in_addr *lookup_byname_backend(const char *name, int *count)
00094 {
00095         int fd = -1;
00096         struct ip_service *address = NULL;
00097         struct in_addr *ret = NULL;
00098         int j, flags = 0;
00099 
00100         if (!initialised) {
00101                 nss_wins_init();
00102         }
00103 
00104         *count = 0;
00105 
00106         /* always try with wins first */
00107         if (resolve_wins(name,0x00,&address,count)) {
00108                 if ( (ret = SMB_MALLOC_P(struct in_addr)) == NULL ) {
00109                         free( address );
00110                         return NULL;
00111                 }
00112                 *ret = address[0].ip;
00113                 free( address );
00114                 return ret;
00115         }
00116 
00117         fd = wins_lookup_open_socket_in();
00118         if (fd == -1) {
00119                 return NULL;
00120         }
00121 
00122         /* uggh, we have to broadcast to each interface in turn */
00123         for (j=iface_count() - 1;j >= 0;j--) {
00124                 struct in_addr *bcast = iface_n_bcast(j);
00125                 ret = name_query(fd,name,0x00,True,True,*bcast,count, &flags, NULL);
00126                 if (ret) break;
00127         }
00128 
00129         close(fd);
00130         return ret;
00131 }
00132 
00133 #ifdef HAVE_NS_API_H
00134 
00135 static NODE_STATUS_STRUCT *lookup_byaddr_backend(char *addr, int *count)
00136 {
00137         int fd;
00138         struct in_addr  ip;
00139         struct nmb_name nname;
00140         NODE_STATUS_STRUCT *status;
00141 
00142         if (!initialised) {
00143                 nss_wins_init();
00144         }
00145 
00146         fd = wins_lookup_open_socket_in();
00147         if (fd == -1)
00148                 return NULL;
00149 
00150         make_nmb_name(&nname, "*", 0);
00151         ip = *interpret_addr2(addr);
00152         status = node_status_query(fd,&nname,ip, count, NULL);
00153 
00154         close(fd);
00155         return status;
00156 }
00157 
00158 /* IRIX version */
00159 
00160 int init(void)
00161 {
00162         nsd_logprintf(NSD_LOG_MIN, "entering init (wins)\n");
00163         nss_wins_init();
00164         return NSD_OK;
00165 }
00166 
00167 int lookup(nsd_file_t *rq)
00168 {
00169         char *map;
00170         char *key;
00171         char *addr;
00172         struct in_addr *ip_list;
00173         NODE_STATUS_STRUCT *status;
00174         int i, count, len, size;
00175         char response[1024];
00176         BOOL found = False;
00177 
00178         nsd_logprintf(NSD_LOG_MIN, "entering lookup (wins)\n");
00179         if (! rq) 
00180                 return NSD_ERROR;
00181 
00182         map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0);
00183         if (! map) {
00184                 rq->f_status = NS_FATAL;
00185                 return NSD_ERROR;
00186         }
00187 
00188         key = nsd_attr_fetch_string(rq->f_attrs, "key", (char*)0);
00189         if (! key || ! *key) {
00190                 rq->f_status = NS_FATAL;
00191                 return NSD_ERROR;
00192         }
00193 
00194         response[0] = '\0';
00195         len = sizeof(response) - 2;
00196 
00197         /* 
00198          * response needs to be a string of the following format
00199          * ip_address[ ip_address]*\tname[ alias]*
00200          */
00201         if (StrCaseCmp(map,"hosts.byaddr") == 0) {
00202                 if ( status = lookup_byaddr_backend(key, &count)) {
00203                     size = strlen(key) + 1;
00204                     if (size > len) {
00205                         free(status);
00206                         return NSD_ERROR;
00207                     }
00208                     len -= size;
00209                     strncat(response,key,size);
00210                     strncat(response,"\t",1);
00211                     for (i = 0; i < count; i++) {
00212                         /* ignore group names */
00213                         if (status[i].flags & 0x80) continue;
00214                         if (status[i].type == 0x20) {
00215                                 size = sizeof(status[i].name) + 1;
00216                                 if (size > len) {
00217                                     free(status);
00218                                     return NSD_ERROR;
00219                                 }
00220                                 len -= size;
00221                                 strncat(response, status[i].name, size);
00222                                 strncat(response, " ", 1);
00223                                 found = True;
00224                         }
00225                     }
00226                     response[strlen(response)-1] = '\n';
00227                     free(status);
00228                 }
00229         } else if (StrCaseCmp(map,"hosts.byname") == 0) {
00230             if (ip_list = lookup_byname_backend(key, &count)) {
00231                 for (i = count; i ; i--) {
00232                     addr = inet_ntoa(ip_list[i-1]);
00233                     size = strlen(addr) + 1;
00234                     if (size > len) {
00235                         free(ip_list);
00236                         return NSD_ERROR;
00237                     }
00238                     len -= size;
00239                     if (i != 0)
00240                         response[strlen(response)-1] = ' ';
00241                     strncat(response,addr,size);
00242                     strncat(response,"\t",1);
00243                 }
00244                 size = strlen(key) + 1;
00245                 if (size > len) {
00246                     free(ip_list);
00247                     return NSD_ERROR;
00248                 }   
00249                 strncat(response,key,size);
00250                 strncat(response,"\n",1);
00251                 found = True;
00252                 free(ip_list);
00253             }
00254         }
00255 
00256         if (found) {
00257             nsd_logprintf(NSD_LOG_LOW, "lookup (wins %s) %s\n",map,response);
00258             nsd_set_result(rq,NS_SUCCESS,response,strlen(response),VOLATILE);
00259             return NSD_OK;
00260         }
00261         nsd_logprintf(NSD_LOG_LOW, "lookup (wins) not found\n");
00262         rq->f_status = NS_NOTFOUND;
00263         return NSD_NEXT;
00264 }
00265 
00266 #else
00267 
00268 /* Allocate some space from the nss static buffer.  The buffer and buflen
00269    are the pointers passed in by the C library to the _nss_*_*
00270    functions. */
00271 
00272 static char *get_static(char **buffer, size_t *buflen, int len)
00273 {
00274         char *result;
00275 
00276         /* Error check.  We return false if things aren't set up right, or
00277            there isn't enough buffer space left. */
00278         
00279         if ((buffer == NULL) || (buflen == NULL) || (*buflen < len)) {
00280                 return NULL;
00281         }
00282 
00283         /* Return an index into the static buffer */
00284 
00285         result = *buffer;
00286         *buffer += len;
00287         *buflen -= len;
00288 
00289         return result;
00290 }
00291 
00292 /****************************************************************************
00293 gethostbyname() - we ignore any domain portion of the name and only
00294 handle names that are at most 15 characters long
00295   **************************************************************************/
00296 NSS_STATUS
00297 _nss_wins_gethostbyname_r(const char *hostname, struct hostent *he,
00298                           char *buffer, size_t buflen, int *h_errnop)
00299 {
00300         struct in_addr *ip_list;
00301         int i, count;
00302         fstring name;
00303         size_t namelen;
00304                 
00305         memset(he, '\0', sizeof(*he));
00306         fstrcpy(name, hostname);
00307 
00308         /* Do lookup */
00309 
00310         ip_list = lookup_byname_backend(name, &count);
00311 
00312         if (!ip_list)
00313                 return NSS_STATUS_NOTFOUND;
00314 
00315         /* Copy h_name */
00316 
00317         namelen = strlen(name) + 1;
00318 
00319         if ((he->h_name = get_static(&buffer, &buflen, namelen)) == NULL)
00320                 return NSS_STATUS_TRYAGAIN;
00321 
00322         memcpy(he->h_name, name, namelen);
00323 
00324         /* Copy h_addr_list, align to pointer boundary first */
00325 
00326         if ((i = (unsigned long)(buffer) % sizeof(char*)) != 0)
00327                 i = sizeof(char*) - i;
00328 
00329         if (get_static(&buffer, &buflen, i) == NULL)
00330                 return NSS_STATUS_TRYAGAIN;
00331 
00332         if ((he->h_addr_list = (char **)get_static(
00333                      &buffer, &buflen, (count + 1) * sizeof(char *))) == NULL)
00334                 return NSS_STATUS_TRYAGAIN;
00335 
00336         for (i = 0; i < count; i++) {
00337                 if ((he->h_addr_list[i] = get_static(&buffer, &buflen,
00338                                                      INADDRSZ)) == NULL)
00339                         return NSS_STATUS_TRYAGAIN;
00340                 memcpy(he->h_addr_list[i], &ip_list[i], INADDRSZ);
00341         }
00342 
00343         he->h_addr_list[count] = NULL;
00344 
00345         if (ip_list)
00346                 free(ip_list);
00347 
00348         /* Set h_addr_type and h_length */
00349 
00350         he->h_addrtype = AF_INET;
00351         he->h_length = INADDRSZ;
00352 
00353         /* Set h_aliases */
00354 
00355         if ((i = (unsigned long)(buffer) % sizeof(char*)) != 0)
00356                 i = sizeof(char*) - i;
00357 
00358         if (get_static(&buffer, &buflen, i) == NULL)
00359                 return NSS_STATUS_TRYAGAIN;
00360 
00361         if ((he->h_aliases = (char **)get_static(
00362                      &buffer, &buflen, sizeof(char *))) == NULL)
00363                 return NSS_STATUS_TRYAGAIN;
00364 
00365         he->h_aliases[0] = NULL;
00366 
00367         return NSS_STATUS_SUCCESS;
00368 }
00369 
00370 
00371 NSS_STATUS
00372 _nss_wins_gethostbyname2_r(const char *name, int af, struct hostent *he,
00373                            char *buffer, size_t buflen, int *h_errnop)
00374 {
00375         if(af!=AF_INET) {
00376                 *h_errnop = NO_DATA;
00377                 return NSS_STATUS_UNAVAIL;
00378         }
00379 
00380         return _nss_wins_gethostbyname_r(
00381                 name, he, buffer, buflen, h_errnop);
00382 }
00383 #endif

Sambaに対してSat Aug 29 21:23:11 2009に生成されました。  doxygen 1.4.7