PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

lib/libminlib/servxcheck.c

http://www.minix3.org/
C | 283 lines | 218 code | 32 blank | 33 comment | 125 complexity | 507062d282cb4e743ce95d6def257f96 MD5 | raw file
Possible License(s): MIT, WTFPL, AGPL-1.0, BSD-3-Clause, GPL-3.0, LGPL-2.0, JSON, 0BSD
  1. /* servxcheck() - Service access check. Author: Kees J. Bot
  2. * 8 Jan 1997
  3. */
  4. #define nil 0
  5. #define ioctl _ioctl
  6. #define open _open
  7. #define write _write
  8. #define close _close
  9. #include <sys/types.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <syslog.h>
  13. #include <errno.h>
  14. #include <string.h>
  15. #include <fcntl.h>
  16. #include <unistd.h>
  17. #include <time.h>
  18. #include <sys/ioctl.h>
  19. #include <net/hton.h>
  20. #include <net/gen/in.h>
  21. #include <net/gen/tcp.h>
  22. #include <net/gen/tcp_io.h>
  23. #include <net/gen/inet.h>
  24. #include <net/gen/socket.h>
  25. #include <net/gen/netdb.h>
  26. /* Default service access file. */
  27. static const char *path_servacces = _PATH_SERVACCES;
  28. #define WLEN 256
  29. static int getword(FILE *fp, char *word)
  30. /* Read a word from the file open by 'fp', skip whitespace and comments.
  31. * Colon and semicolon are returned as a one character "word". Returns
  32. * word[0] or EOF.
  33. */
  34. {
  35. int c;
  36. char *pw;
  37. int wc;
  38. wc= 0;
  39. for (;;) {
  40. if ((c= getc(fp)) == EOF) return EOF;
  41. if (c == '#') { wc= 1; continue; }
  42. if (c == '\n') { wc= 0; continue; }
  43. if (wc) continue;
  44. if (c <= ' ') continue;
  45. break;
  46. }
  47. pw= word;
  48. if (c == ':' || c == ';') {
  49. *pw++ = c;
  50. } else {
  51. do {
  52. if (pw < word + WLEN-1) *pw++ = c;
  53. c= getc(fp);
  54. } while (c != EOF && c > ' ' && c != ':' && c != ';');
  55. if (c != EOF) ungetc(c, fp);
  56. }
  57. *pw= 0;
  58. return word[0];
  59. }
  60. static int netspec(char *word, ipaddr_t *addr, ipaddr_t *mask)
  61. /* Try to interpret 'word' as an network spec, e.g. 172.16.102.64/27. */
  62. {
  63. char *slash;
  64. int r;
  65. static char S32[]= "/32";
  66. if (*word == 0) return 0;
  67. if ((slash= strchr(word, '/')) == NULL) slash= S32;
  68. *slash= 0;
  69. r= inet_aton(word, addr);
  70. *slash++= '/';
  71. if (!r) return 0;
  72. r= 0;
  73. while ((*slash - '0') < 10u) {
  74. r= 10*r + (*slash++ - '0');
  75. if (r > 32) return 0;
  76. }
  77. if (*slash != 0 || slash[-1] == '/') return 0;
  78. *mask= htonl(r == 0 ? 0L : (0xFFFFFFFFUL >> (32 - r)) << (32 - r));
  79. return 1;
  80. }
  81. static int match(const char *word, const char *pattern)
  82. /* Match word onto a pattern. Pattern may contain the * wildcard. */
  83. {
  84. unsigned cw, cp;
  85. #define lc(c, d) ((((c)= (d)) - 'A') <= ('Z' - 'A') ? (c)+= ('a' - 'A') : 0)
  86. for (;;) {
  87. (void) lc(cw, *word);
  88. (void) lc(cp, *pattern);
  89. if (cp == '*') {
  90. do pattern++; while (*pattern == '*');
  91. (void) lc(cp, *pattern);
  92. if (cp == 0) return 1;
  93. while (cw != 0) {
  94. if (cw == cp && match(word+1, pattern+1)) return 1;
  95. word++;
  96. (void) lc(cw, *word);
  97. }
  98. return 0;
  99. } else
  100. if (cw == 0 || cp == 0) {
  101. return cw == cp;
  102. } else
  103. if (cw == cp) {
  104. word++;
  105. pattern++;
  106. } else {
  107. return 0;
  108. }
  109. }
  110. #undef lc
  111. }
  112. static int get_name(ipaddr_t addr, char *name)
  113. /* Do a reverse lookup on the remote IP address followed by a forward lookup
  114. * to check if the host has that address. Return true if this is so, return
  115. * either the true name or the ascii IP address in name[].
  116. */
  117. {
  118. struct hostent *he;
  119. int i;
  120. he= gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);
  121. if (he != NULL) {
  122. strcpy(name, he->h_name);
  123. he= gethostbyname(name);
  124. if (he != NULL && he->h_addrtype == AF_INET) {
  125. for (i= 0; he->h_addr_list[i] != NULL; i++) {
  126. if (memcmp(he->h_addr_list[i], &addr, sizeof(addr)) == 0) {
  127. strcpy(name, he->h_name);
  128. return 1;
  129. }
  130. }
  131. }
  132. }
  133. strcpy(name, inet_ntoa(addr));
  134. return 0;
  135. }
  136. /* "state" and "log" flags, made to be bitwise comparable. */
  137. #define DEFFAIL 0x01
  138. #define FAIL (0x02 | DEFFAIL)
  139. #define PASS 0x04
  140. int servxcheck(unsigned long peer, const char *service,
  141. void (*logf)(int pass, const char *name))
  142. {
  143. FILE *fp;
  144. char word[WLEN];
  145. char name[WLEN];
  146. int c;
  147. int got_name, slist, seen, explicit, state, log;
  148. ipaddr_t addr, mask;
  149. /* Localhost? */
  150. if ((peer & htonl(0xFF000000)) == htonl(0x7F000000)) return 1;
  151. if ((fp= fopen(path_servacces, "r")) == nil) {
  152. /* Succeed on error, fail if simply nonexistent. */
  153. return (errno != ENOENT);
  154. }
  155. slist= 1; /* Services list (before the colon.) */
  156. seen= 0; /* Given service not yet seen. */
  157. explicit= 0; /* Service mentioned explicitly. */
  158. got_name= -1; /* No reverse lookup done yet. */
  159. log= FAIL; /* By default log failures only. */
  160. state= DEFFAIL; /* Access denied until we know better. */
  161. while ((c= getword(fp, word)) != EOF) {
  162. if (c == ':') {
  163. slist= 0; /* Switch to access list. */
  164. } else
  165. if (c == ';') {
  166. slist= 1; /* Back to list of services. */
  167. seen= 0;
  168. } else
  169. if (slist) {
  170. /* Traverse services list. */
  171. if (match(service, word)) {
  172. /* Service has been spotted! */
  173. if (match(word, service)) {
  174. /* Service mentioned without wildcards. */
  175. seen= explicit= 1;
  176. } else {
  177. /* Matched by a wildcard. */
  178. if (!explicit) seen= 1;
  179. }
  180. }
  181. } else {
  182. /* Traverse access list. */
  183. if (c == 'l' && strcmp(word, "log") == 0) {
  184. if (seen) {
  185. /* Log failures and successes. */
  186. log= FAIL|PASS;
  187. }
  188. continue;
  189. }
  190. if (c != '-' && c != '+') {
  191. if (logf == nil) {
  192. syslog(LOG_ERR, "%s: strange check word '%s'\n",
  193. path_servacces, word);
  194. }
  195. continue;
  196. }
  197. if (seen) {
  198. if (state == DEFFAIL) {
  199. /* First check determines the default. */
  200. state= c == '+' ? FAIL : PASS;
  201. }
  202. if ((state == PASS) == (c == '+')) {
  203. /* This check won't change state. */
  204. } else
  205. if (word[1] == 0) {
  206. /* Lone + or - allows all or none. */
  207. state= c == '-' ? FAIL : PASS;
  208. } else
  209. if (netspec(word+1, &addr, &mask)) {
  210. /* Remote host is on the specified network? */
  211. if (((peer ^ addr) & mask) == 0) {
  212. state= c == '-' ? FAIL : PASS;
  213. }
  214. } else {
  215. /* Name check. */
  216. if (got_name == -1) {
  217. got_name= get_name(peer, name);
  218. }
  219. /* Remote host name matches the word? */
  220. if (!got_name) {
  221. state= FAIL;
  222. } else
  223. if (match(name, word+1)) {
  224. state= c == '-' ? FAIL : PASS;
  225. }
  226. }
  227. }
  228. }
  229. }
  230. fclose(fp);
  231. if ((log & state) != 0) {
  232. /* Log the result of the check. */
  233. if (got_name == -1) (void) get_name(peer, name);
  234. if (logf != nil) {
  235. (*logf)(state == PASS, name);
  236. } else {
  237. syslog(LOG_NOTICE, "service '%s' %s to %s\n",
  238. service, state == PASS ? "granted" : "denied", name);
  239. }
  240. }
  241. return state == PASS;
  242. }
  243. char *servxfile(const char *file)
  244. /* Specify a file to use for the access checks other than the default. Return
  245. * the old path.
  246. */
  247. {
  248. const char *oldpath= path_servacces;
  249. path_servacces= file;
  250. return (char *) oldpath; /* (avoid const poisoning) */
  251. }