CVE-2018-10919 security: Add more comments to the object-specific access checks
[vlendec/samba-autobuild/.git] / nsswitch / wins.c
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 3 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, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 #include "includes.h"
22 #include "nsswitch/winbind_client.h"
23 #include "nsswitch/libwbclient/wbclient.h"
24
25 #ifdef HAVE_NS_API_H
26
27 #include <ns_daemon.h>
28 #endif
29
30 #if HAVE_PTHREAD_H
31 #include <pthread.h>
32 #endif
33
34 #if HAVE_PTHREAD
35 static pthread_mutex_t wins_nss_mutex = PTHREAD_MUTEX_INITIALIZER;
36 #endif
37
38 #ifndef INADDRSZ
39 #define INADDRSZ 4
40 #endif
41
42 NSS_STATUS _nss_wins_gethostbyname_r(const char *hostname,
43                                      struct hostent *he,
44                                      char *buffer,
45                                      size_t buflen,
46                                      int *errnop,
47                                      int *h_errnop);
48 NSS_STATUS _nss_wins_gethostbyname2_r(const char *name,
49                                       int af,
50                                       struct hostent *he,
51                                       char *buffer,
52                                       size_t buflen,
53                                       int *errnop,
54                                       int *h_errnop);
55
56 static char *lookup_byname_backend(const char *name)
57 {
58         const char *p;
59         char *ip, *ipp;
60         size_t nbt_len;
61         wbcErr result;
62
63         nbt_len = strlen(name);
64         if (nbt_len > MAX_NETBIOSNAME_LEN - 1) {
65                 return NULL;
66         }
67         p = strchr(name, '.');
68         if (p != NULL) {
69                 return NULL;
70         }
71
72         result = wbcResolveWinsByName(name, &ip);
73         if (result != WBC_ERR_SUCCESS) {
74                 return NULL;
75         }
76
77         ipp = strchr(ip, '\t');
78         if (ipp != NULL) {
79                 *ipp = '\0';
80         }
81
82         return ip;
83 }
84
85 #ifdef HAVE_NS_API_H
86
87 static char *lookup_byaddr_backend(const char *ip)
88 {
89         wbcErr result;
90         char *name = NULL;
91
92         result = wbcResolveWinsByIP(ip, &name);
93         if (result != WBC_ERR_SUCCESS) {
94                 return NULL;
95         }
96
97         return name;
98 }
99
100 /* IRIX version */
101
102 int init(void)
103 {
104         bool ok;
105
106         nsd_logprintf(NSD_LOG_MIN, "entering init (wins)\n");
107
108         ok = nss_wins_init();
109         if (!ok) {
110                 return NSD_ERROR;
111         }
112
113         return NSD_OK;
114 }
115
116 int lookup(nsd_file_t *rq)
117 {
118         char *map;
119         char *key;
120         char *addr;
121         int i, count, len, size;
122         char response[1024];
123         bool found = False;
124
125         nsd_logprintf(NSD_LOG_MIN, "entering lookup (wins)\n");
126         if (! rq)
127                 return NSD_ERROR;
128
129         map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0);
130         if (! map) {
131                 rq->f_status = NS_FATAL;
132                 return NSD_ERROR;
133         }
134
135         key = nsd_attr_fetch_string(rq->f_attrs, "key", (char*)0);
136         if (! key || ! *key) {
137                 rq->f_status = NS_FATAL;
138                 return NSD_ERROR;
139         }
140
141         response[0] = '\0';
142         len = sizeof(response) - 2;
143
144         /*
145          * response needs to be a string of the following format
146          * ip_address[ ip_address]*\tname[ alias]*
147          */
148         if (strcasecmp_m(map,"hosts.byaddr") == 0) {
149                 char *name;
150
151                 name = lookup_byaddr_backend(key);
152                 if (name != NULL) {
153                         size = strlen(key) + 1;
154                         if (size > len) {
155                                 return NSD_ERROR;
156                         }
157                         len -= size;
158                         strncat(response,key,size);
159                         strncat(response,"\t",1);
160
161                         size = strlen(name) + 1;
162                         if (size > len) {
163                                 return NSD_ERROR;
164                         }
165                         len -= size;
166                         strncat(response, name, size);
167                         strncat(response, " ", 1);
168                         found = True;
169                 }
170                 response[strlen(response)-1] = '\n';
171         } else if (strcasecmp_m(map,"hosts.byname") == 0) {
172                 char *ip;
173
174                 ip = lookup_byname_backend(key);
175                 if (ip != NULL) {
176                         size = strlen(ip) + 1;
177                         if (size > len) {
178                                 wbcFreeMemory(ip);
179                                 return NSD_ERROR;
180                         }
181                         len -= size;
182                         strncat(response,ip,size);
183                         strncat(response,"\t",1);
184                         size = strlen(key) + 1;
185                         wbcFreeMemory(ip);
186                         if (size > len) {
187                                 return NSD_ERROR;
188                         }
189                         strncat(response,key,size);
190                         strncat(response,"\n",1);
191
192                         found = True;
193                 }
194         }
195
196         if (found) {
197             nsd_logprintf(NSD_LOG_LOW, "lookup (wins %s) %s\n",map,response);
198             nsd_set_result(rq,NS_SUCCESS,response,strlen(response),VOLATILE);
199             return NSD_OK;
200         }
201         nsd_logprintf(NSD_LOG_LOW, "lookup (wins) not found\n");
202         rq->f_status = NS_NOTFOUND;
203         return NSD_NEXT;
204 }
205
206 #else
207
208 /* Allocate some space from the nss static buffer.  The buffer and buflen
209    are the pointers passed in by the C library to the _nss_*_*
210    functions. */
211
212 static char *get_static(char **buffer, size_t *buflen, size_t len)
213 {
214         char *result;
215
216         /* Error check.  We return false if things aren't set up right, or
217            there isn't enough buffer space left. */
218
219         if ((buffer == NULL) || (buflen == NULL) || (*buflen < len)) {
220                 return NULL;
221         }
222
223         /* Return an index into the static buffer */
224
225         result = *buffer;
226         *buffer += len;
227         *buflen -= len;
228
229         return result;
230 }
231
232 /****************************************************************************
233 gethostbyname() - we ignore any domain portion of the name and only
234 handle names that are at most 15 characters long
235   **************************************************************************/
236 NSS_STATUS
237 _nss_wins_gethostbyname_r(const char *hostname,
238                           struct hostent *he,
239                           char *buffer,
240                           size_t buflen,
241                           int *errnop,
242                           int *h_errnop)
243 {
244         NSS_STATUS nss_status = NSS_STATUS_SUCCESS;
245         char *ip;
246         struct in_addr in;
247         int i;
248         fstring name;
249         size_t namelen;
250         int rc;
251
252 #if HAVE_PTHREAD
253         pthread_mutex_lock(&wins_nss_mutex);
254 #endif
255
256         memset(he, '\0', sizeof(*he));
257         fstrcpy(name, hostname);
258
259         /* Do lookup */
260
261         ip = lookup_byname_backend(name);
262         if (ip == NULL) {
263                 *h_errnop = HOST_NOT_FOUND;
264                 nss_status = NSS_STATUS_NOTFOUND;
265                 goto out;
266         }
267
268         rc = inet_pton(AF_INET, ip, &in);
269         wbcFreeMemory(ip);
270         if (rc == 0) {
271                 *errnop = errno;
272                 *h_errnop = NETDB_INTERNAL;
273                 nss_status = NSS_STATUS_TRYAGAIN;
274                 goto out;
275         }
276
277         /* Copy h_name */
278
279         namelen = strlen(name) + 1;
280
281         if ((he->h_name = get_static(&buffer, &buflen, namelen)) == NULL) {
282                 *errnop = EAGAIN;
283                 *h_errnop = NETDB_INTERNAL;
284                 nss_status = NSS_STATUS_TRYAGAIN;
285                 goto out;
286         }
287
288         memcpy(he->h_name, name, namelen);
289
290         /* Copy h_addr_list, align to pointer boundary first */
291
292         if ((i = (unsigned long)(buffer) % sizeof(char*)) != 0)
293                 i = sizeof(char*) - i;
294
295         if (get_static(&buffer, &buflen, i) == NULL) {
296                 *errnop = EAGAIN;
297                 *h_errnop = NETDB_INTERNAL;
298                 nss_status = NSS_STATUS_TRYAGAIN;
299                 goto out;
300         }
301
302         if ((he->h_addr_list = (char **)get_static(
303                      &buffer, &buflen, 2 * sizeof(char *))) == NULL) {
304                 *errnop = EAGAIN;
305                 *h_errnop = NETDB_INTERNAL;
306                 nss_status = NSS_STATUS_TRYAGAIN;
307                 goto out;
308         }
309
310         if ((he->h_addr_list[0] = get_static(&buffer, &buflen,
311                                              INADDRSZ)) == NULL) {
312                 *errnop = EAGAIN;
313                 *h_errnop = NETDB_INTERNAL;
314                 nss_status = NSS_STATUS_TRYAGAIN;
315                 goto out;
316         }
317
318         memcpy(he->h_addr_list[0], &in, INADDRSZ);
319
320         he->h_addr_list[1] = NULL;
321
322         /* Set h_addr_type and h_length */
323
324         he->h_addrtype = AF_INET;
325         he->h_length = INADDRSZ;
326
327         /* Set h_aliases */
328
329         if ((i = (unsigned long)(buffer) % sizeof(char*)) != 0)
330                 i = sizeof(char*) - i;
331
332         if (get_static(&buffer, &buflen, i) == NULL) {
333                 *errnop = EAGAIN;
334                 *h_errnop = NETDB_INTERNAL;
335                 nss_status = NSS_STATUS_TRYAGAIN;
336                 goto out;
337         }
338
339         if ((he->h_aliases = (char **)get_static(
340                      &buffer, &buflen, sizeof(char *))) == NULL) {
341                 *errnop = EAGAIN;
342                 *h_errnop = NETDB_INTERNAL;
343                 nss_status = NSS_STATUS_TRYAGAIN;
344                 goto out;
345         }
346
347         he->h_aliases[0] = NULL;
348
349         *h_errnop = NETDB_SUCCESS;
350         nss_status = NSS_STATUS_SUCCESS;
351
352   out:
353
354 #if HAVE_PTHREAD
355         pthread_mutex_unlock(&wins_nss_mutex);
356 #endif
357         return nss_status;
358 }
359
360
361 NSS_STATUS
362 _nss_wins_gethostbyname2_r(const char *name,
363                            int af,
364                            struct hostent *he,
365                            char *buffer,
366                            size_t buflen,
367                            int *errnop,
368                            int *h_errnop)
369 {
370         NSS_STATUS nss_status;
371
372         if(af!=AF_INET) {
373                 *errnop = EAFNOSUPPORT;
374                 *h_errnop = NO_DATA;
375                 nss_status = NSS_STATUS_UNAVAIL;
376         } else {
377                 nss_status = _nss_wins_gethostbyname_r(name,
378                                                        he,
379                                                        buffer,
380                                                        buflen,
381                                                        errnop,
382                                                        h_errnop);
383         }
384         return nss_status;
385 }
386 #endif