Annotation of embedaddon/rsync/access.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Routines to authenticate access to a daemon (hosts allow/deny).
3: *
4: * Copyright (C) 1998 Andrew Tridgell
5: * Copyright (C) 2004-2009 Wayne Davison
6: *
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.
11: *
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.
16: *
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.
19: */
20:
21: #include "rsync.h"
22:
23: static int match_hostname(char *host, char *tok)
24: {
25: if (!host || !*host)
26: return 0;
27: return wildmatch(tok, host);
28: }
29:
30: static int match_binary(char *b1, char *b2, char *mask, int addrlen)
31: {
32: int i;
33:
34: for (i = 0; i < addrlen; i++) {
35: if ((b1[i] ^ b2[i]) & mask[i])
36: return 0;
37: }
38:
39: return 1;
40: }
41:
42: static void make_mask(char *mask, int plen, int addrlen)
43: {
44: int w, b;
45:
46: w = plen >> 3;
47: b = plen & 0x7;
48:
49: if (w)
50: memset(mask, 0xff, w);
51: if (w < addrlen)
52: mask[w] = 0xff & (0xff<<(8-b));
53: if (w+1 < addrlen)
54: memset(mask+w+1, 0, addrlen-w-1);
55:
56: return;
57: }
58:
59: static int match_address(char *addr, char *tok)
60: {
61: char *p;
62: struct addrinfo hints, *resa, *rest;
63: int gai;
64: int ret = 0;
65: int addrlen = 0;
66: #ifdef HAVE_STRTOL
67: long int bits;
68: #else
69: int bits;
70: #endif
71: char mask[16];
72: char *a = NULL, *t = NULL;
73: unsigned int len;
74:
75: if (!addr || !*addr)
76: return 0;
77:
78: p = strchr(tok,'/');
79: if (p) {
80: *p = '\0';
81: len = p - tok;
82: } else
83: len = strlen(tok);
84:
85: /* Fail quietly if tok is a hostname (not an address) */
86: if (strspn(tok, ".0123456789") != len
87: #ifdef INET6
88: && strchr(tok, ':') == NULL
89: #endif
90: ) {
91: if (p)
92: *p = '/';
93: return 0;
94: }
95:
96: memset(&hints, 0, sizeof(hints));
97: hints.ai_family = PF_UNSPEC;
98: hints.ai_socktype = SOCK_STREAM;
99: #ifdef AI_NUMERICHOST
100: hints.ai_flags = AI_NUMERICHOST;
101: #endif
102:
103: if (getaddrinfo(addr, NULL, &hints, &resa) != 0) {
104: if (p)
105: *p = '/';
106: return 0;
107: }
108:
109: gai = getaddrinfo(tok, NULL, &hints, &rest);
110: if (p)
111: *p++ = '/';
112: if (gai != 0) {
113: rprintf(FLOG, "error matching address %s: %s\n",
114: tok, gai_strerror(gai));
115: freeaddrinfo(resa);
116: return 0;
117: }
118:
119: if (rest->ai_family != resa->ai_family) {
120: ret = 0;
121: goto out;
122: }
123:
124: switch(resa->ai_family) {
125: case PF_INET:
126: a = (char *)&((struct sockaddr_in *)resa->ai_addr)->sin_addr;
127: t = (char *)&((struct sockaddr_in *)rest->ai_addr)->sin_addr;
128: addrlen = 4;
129:
130: break;
131:
132: #ifdef INET6
133: case PF_INET6:
134: {
135: struct sockaddr_in6 *sin6a, *sin6t;
136:
137: sin6a = (struct sockaddr_in6 *)resa->ai_addr;
138: sin6t = (struct sockaddr_in6 *)rest->ai_addr;
139:
140: a = (char *)&sin6a->sin6_addr;
141: t = (char *)&sin6t->sin6_addr;
142:
143: addrlen = 16;
144:
145: #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
146: if (sin6t->sin6_scope_id &&
147: sin6a->sin6_scope_id != sin6t->sin6_scope_id) {
148: ret = 0;
149: goto out;
150: }
151: #endif
152:
153: break;
154: }
155: #endif
156: default:
157: rprintf(FLOG, "unknown family %u\n", rest->ai_family);
158: ret = 0;
159: goto out;
160: }
161:
162: bits = -1;
163: if (p) {
164: if (inet_pton(resa->ai_addr->sa_family, p, mask) <= 0) {
165: #ifdef HAVE_STRTOL
166: char *ep = NULL;
167: #else
168: unsigned char *pp;
169: #endif
170:
171: #ifdef HAVE_STRTOL
172: bits = strtol(p, &ep, 10);
173: if (!*p || *ep) {
174: rprintf(FLOG, "malformed mask in %s\n", tok);
175: ret = 0;
176: goto out;
177: }
178: #else
179: for (pp = (unsigned char *)p; *pp; pp++) {
180: if (!isascii(*pp) || !isdigit(*pp)) {
181: rprintf(FLOG, "malformed mask in %s\n", tok);
182: ret = 0;
183: goto out;
184: }
185: }
186: bits = atoi(p);
187: #endif
188: if (bits == 0) {
189: ret = 1;
190: goto out;
191: }
192: if (bits < 0 || bits > (addrlen << 3)) {
193: rprintf(FLOG, "malformed mask in %s\n", tok);
194: ret = 0;
195: goto out;
196: }
197: }
198: } else {
199: bits = 128;
200: }
201:
202: if (bits >= 0)
203: make_mask(mask, bits, addrlen);
204:
205: ret = match_binary(a, t, mask, addrlen);
206:
207: out:
208: freeaddrinfo(resa);
209: freeaddrinfo(rest);
210: return ret;
211: }
212:
213: static int access_match(char *list, char *addr, char *host)
214: {
215: char *tok;
216: char *list2 = strdup(list);
217:
218: if (!list2)
219: out_of_memory("access_match");
220:
221: strlower(list2);
222: if (host)
223: strlower(host);
224:
225: for (tok = strtok(list2, " ,\t"); tok; tok = strtok(NULL, " ,\t")) {
226: if (match_hostname(host, tok) || match_address(addr, tok)) {
227: free(list2);
228: return 1;
229: }
230: }
231:
232: free(list2);
233: return 0;
234: }
235:
236: int allow_access(char *addr, char *host, char *allow_list, char *deny_list)
237: {
238: if (allow_list && !*allow_list)
239: allow_list = NULL;
240: if (deny_list && !*deny_list)
241: deny_list = NULL;
242:
243: /* If we match an allow-list item, we always allow access. */
244: if (allow_list) {
245: if (access_match(allow_list, addr, host))
246: return 1;
247: /* For an allow-list w/o a deny-list, disallow non-matches. */
248: if (!deny_list)
249: return 0;
250: }
251:
252: /* If we match a deny-list item (and got past any allow-list
253: * items), we always disallow access. */
254: if (deny_list && access_match(deny_list, addr, host))
255: return 0;
256:
257: /* Allow all other access. */
258: return 1;
259: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>