2 * Routines to authenticate access to a daemon (hosts allow/deny).
4 * Copyright (C) 1998 Andrew Tridgell
5 * Copyright (C) 2004-2022 Wayne Davison
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, visit the http://fsf.org website.
23 #ifdef HAVE_NETGROUP_H
27 static int allow_forward_dns
;
29 extern const char undetermined_hostname
[];
31 static int match_hostname(const char **host_ptr
, const char *addr
, const char *tok
)
35 const char *host
= *host_ptr
;
41 if (*tok
== '@' && tok
[1])
42 return innetgr(tok
+ 1, host
, NULL
, NULL
);
45 /* First check if the reverse-DNS-determined hostname matches. */
46 if (iwildmatch(tok
, host
))
49 if (!allow_forward_dns
)
52 /* Fail quietly if tok is an address or wildcarded entry, not a simple hostname. */
53 if (!tok
[strspn(tok
, ".0123456789")] || tok
[strcspn(tok
, ":/*?[")])
56 /* Now try forward-DNS on the token (config-specified hostname) and see if the IP matches. */
57 if (!(hp
= gethostbyname(tok
)))
60 for (i
= 0; hp
->h_addr_list
[i
] != NULL
; i
++) {
61 if (strcmp(addr
, inet_ntoa(*(struct in_addr
*)(hp
->h_addr_list
[i
]))) == 0) {
62 /* If reverse lookups are off, we'll use the conf-specified
63 * hostname in preference to UNDETERMINED. */
64 if (host
== undetermined_hostname
)
65 *host_ptr
= strdup(tok
);
73 static int match_binary(const char *b1
, const char *b2
, const char *mask
, int addrlen
)
77 for (i
= 0; i
< addrlen
; i
++) {
78 if ((b1
[i
] ^ b2
[i
]) & mask
[i
])
85 static void make_mask(char *mask
, int plen
, int addrlen
)
93 memset(mask
, 0xff, w
);
95 mask
[w
] = 0xff & (0xff<<(8-b
));
97 memset(mask
+w
+1, 0, addrlen
-w
-1);
102 static int match_address(const char *addr
, const char *tok
)
105 struct addrinfo hints
, *resa
, *rest
;
115 char *a
= NULL
, *t
= NULL
;
124 /* Fail quietly if tok is a hostname, not an address. */
125 if (tok
[strspn(tok
, ".0123456789")] && strchr(tok
, ':') == NULL
) {
131 memset(&hints
, 0, sizeof(hints
));
132 hints
.ai_family
= PF_UNSPEC
;
133 hints
.ai_socktype
= SOCK_STREAM
;
134 #ifdef AI_NUMERICHOST
135 hints
.ai_flags
= AI_NUMERICHOST
;
138 if (getaddrinfo(addr
, NULL
, &hints
, &resa
) != 0) {
144 gai
= getaddrinfo(tok
, NULL
, &hints
, &rest
);
148 rprintf(FLOG
, "error matching address %s: %s\n",
149 tok
, gai_strerror(gai
));
154 if (rest
->ai_family
!= resa
->ai_family
) {
159 switch(resa
->ai_family
) {
161 a
= (char *)&((struct sockaddr_in
*)resa
->ai_addr
)->sin_addr
;
162 t
= (char *)&((struct sockaddr_in
*)rest
->ai_addr
)->sin_addr
;
169 struct sockaddr_in6
*sin6a
, *sin6t
;
171 sin6a
= (struct sockaddr_in6
*)resa
->ai_addr
;
172 sin6t
= (struct sockaddr_in6
*)rest
->ai_addr
;
174 a
= (char *)&sin6a
->sin6_addr
;
175 t
= (char *)&sin6t
->sin6_addr
;
179 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
180 if (sin6t
->sin6_scope_id
&& sin6a
->sin6_scope_id
!= sin6t
->sin6_scope_id
) {
190 rprintf(FLOG
, "unknown family %u\n", rest
->ai_family
);
197 if (inet_pton(resa
->ai_addr
->sa_family
, p
, mask
) <= 0) {
205 bits
= strtol(p
, &ep
, 10);
207 rprintf(FLOG
, "malformed mask in %s\n", tok
);
212 for (pp
= (unsigned char *)p
; *pp
; pp
++) {
213 if (!isascii(*pp
) || !isdigit(*pp
)) {
214 rprintf(FLOG
, "malformed mask in %s\n", tok
);
225 if (bits
< 0 || bits
> (addrlen
<< 3)) {
226 rprintf(FLOG
, "malformed mask in %s\n", tok
);
236 make_mask(mask
, bits
, addrlen
);
238 ret
= match_binary(a
, t
, mask
, addrlen
);
246 static int access_match(const char *list
, const char *addr
, const char **host_ptr
)
249 char *list2
= strdup(list
);
253 for (tok
= strtok(list2
, " ,\t"); tok
; tok
= strtok(NULL
, " ,\t")) {
254 if (match_hostname(host_ptr
, addr
, tok
) || match_address(addr
, tok
)) {
264 int allow_access(const char *addr
, const char **host_ptr
, int i
)
266 const char *allow_list
= lp_hosts_allow(i
);
267 const char *deny_list
= lp_hosts_deny(i
);
269 if (allow_list
&& !*allow_list
)
271 if (deny_list
&& !*deny_list
)
274 allow_forward_dns
= lp_forward_lookup(i
);
276 /* If we match an allow-list item, we always allow access. */
278 if (access_match(allow_list
, addr
, host_ptr
))
280 /* For an allow-list w/o a deny-list, disallow non-matches. */
285 /* If we match a deny-list item (and got past any allow-list
286 * items), we always disallow access. */
287 if (deny_list
&& access_match(deny_list
, addr
, host_ptr
))
290 /* Allow all other access. */