access.c 5.0 KB

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