You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

329 lines
7.9 KiB

  1. /*
  2. * network.c:
  3. * Part of wiringPiD
  4. * Copyright (c) 2012-2017 Gordon Henderson
  5. ***********************************************************************
  6. * This file is part of wiringPi:
  7. * https://github.com/WiringPi/WiringPi/
  8. *
  9. * wiringPi is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU Lesser General Public License as published by
  11. * the Free Software Foundation, either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * wiringPi is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public License
  20. * along with wiringPi. If not, see <http://www.gnu.org/licenses/>.
  21. ***********************************************************************
  22. */
  23. #include <sys/socket.h>
  24. #include <netinet/in.h>
  25. #include <arpa/inet.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <unistd.h>
  29. #include <string.h>
  30. #include <stdarg.h>
  31. #include <malloc.h>
  32. #include <fcntl.h>
  33. #include <crypt.h>
  34. #include <stdbool.h>
  35. #ifndef TRUE
  36. # define TRUE true
  37. # define FALSE false
  38. #endif
  39. #include "network.h"
  40. // Local data
  41. #define SALT_LEN 16
  42. static char salt [SALT_LEN + 1] ;
  43. static char *returnedHash = NULL ;
  44. static int serverFd = -1 ;
  45. // Union for the server Socket Address
  46. static union
  47. {
  48. struct sockaddr_in sin ;
  49. struct sockaddr_in6 sin6 ;
  50. } serverSockAddr ;
  51. // and client address
  52. static union
  53. {
  54. struct sockaddr_in sin ;
  55. struct sockaddr_in6 sin6 ;
  56. } clientSockAddr ;
  57. /*
  58. * getClientIP:
  59. * Returns a pointer to a static string containing the clients IP address
  60. *********************************************************************************
  61. */
  62. char *getClientIP (void)
  63. {
  64. char buf [INET6_ADDRSTRLEN] ;
  65. static char ipAddress [1024] ;
  66. if (clientSockAddr.sin.sin_family == AF_INET) // IPv4
  67. {
  68. if (snprintf (ipAddress, 1024, "IPv4: %s",
  69. inet_ntop (clientSockAddr.sin.sin_family, (void *)&clientSockAddr.sin.sin_addr, buf, sizeof (buf))) == 1024)
  70. strcpy (ipAddress, "Too long") ;
  71. }
  72. else // IPv6
  73. {
  74. if (clientSockAddr.sin.sin_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED (&clientSockAddr.sin6.sin6_addr))
  75. {
  76. if (snprintf (ipAddress, 1024, "IPv4in6: %s",
  77. inet_ntop (clientSockAddr.sin.sin_family, (char *)&clientSockAddr.sin6.sin6_addr, buf, sizeof(buf))) == 1024)
  78. strcpy (ipAddress, "Too long") ;
  79. }
  80. else
  81. {
  82. if (snprintf (ipAddress, 1024, "IPv6: %s",
  83. inet_ntop (clientSockAddr.sin.sin_family, (char *)&clientSockAddr.sin6.sin6_addr, buf, sizeof(buf))) == 1024)
  84. strcpy (ipAddress, "Too long") ;
  85. }
  86. }
  87. return ipAddress ;
  88. }
  89. /*
  90. * clientPstr: clientPrintf:
  91. * Print over a network socket
  92. *********************************************************************************
  93. */
  94. static int clientPstr (int fd, char *s)
  95. {
  96. int len = strlen (s) ;
  97. return (write (fd, s, len) == len) ? 0 : -1 ;
  98. }
  99. static int clientPrintf (const int fd, const char *message, ...)
  100. {
  101. va_list argp ;
  102. char buffer [1024] ;
  103. va_start (argp, message) ;
  104. vsnprintf (buffer, 1023, message, argp) ;
  105. va_end (argp) ;
  106. return clientPstr (fd, buffer) ;
  107. }
  108. /*
  109. * sendGreeting:
  110. * Send some text to the client device
  111. *********************************************************************************
  112. */
  113. int sendGreeting (int clientFd)
  114. {
  115. if (clientPrintf (clientFd, "200 Welcome to wiringPiD - https://github.com/WiringPi/WiringPi/\n") < 0)
  116. return -1 ;
  117. return clientPrintf (clientFd, "200 Connecting from: %s\n", getClientIP ()) ;
  118. }
  119. /*
  120. * getSalt:
  121. * Create a random 'salt' value for the password encryption process
  122. *********************************************************************************
  123. */
  124. static int getSalt (char drySalt [])
  125. {
  126. static const char *seaDog =
  127. "abcdefghijklmnopqrstuvwxyz"
  128. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  129. "0123456789/." ;
  130. unsigned char wetSalt [SALT_LEN] ;
  131. int i, fd ;
  132. if ((fd = open ("/dev/urandom", O_RDONLY)) < 0)
  133. return fd ;
  134. if (read (fd, wetSalt, SALT_LEN) != SALT_LEN)
  135. return -1 ;
  136. close (fd) ;
  137. for (i = 0 ; i < SALT_LEN ; ++i)
  138. drySalt [i] = seaDog [wetSalt [i] & 63] ;
  139. drySalt [SALT_LEN] = 0 ;
  140. return 0 ;
  141. }
  142. /*
  143. * sendChallenge:
  144. * Create and send our salt (aka nonce) to the remote device
  145. *********************************************************************************
  146. */
  147. int sendChallenge (int clientFd)
  148. {
  149. if (getSalt (salt) < 0)
  150. return -1 ;
  151. return clientPrintf (clientFd, "Challenge %s\n", salt) ;
  152. }
  153. /*
  154. * getResponse:
  155. * Read the encrypted password from the remote device.
  156. *********************************************************************************
  157. */
  158. int getResponse (int clientFd)
  159. {
  160. char reply [1024] ;
  161. int len ;
  162. // Being sort of lazy about this. I'm expecting an SHA-512 hash back and these
  163. // are exactly 86 characters long, so no reason not to, I guess...
  164. len = 86 ;
  165. if (setsockopt (clientFd, SOL_SOCKET, SO_RCVLOWAT, (void *)&len, sizeof (len)) < 0)
  166. return -1 ;
  167. len = recv (clientFd, reply, 86, 0) ;
  168. if (len != 86)
  169. return -1 ;
  170. reply [len] = 0 ;
  171. if ((returnedHash = malloc (len + 1)) == NULL)
  172. return -1 ;
  173. strcpy (returnedHash, reply) ;
  174. return 0 ;
  175. }
  176. /*
  177. * passwordMatch:
  178. * See if there's a match. If not, we simply dump them.
  179. *********************************************************************************
  180. */
  181. int passwordMatch (const char *password)
  182. {
  183. char *encrypted ;
  184. char salted [1024] ;
  185. sprintf (salted, "$6$%s$", salt) ;
  186. encrypted = crypt (password, salted) ;
  187. // 20: $6$ then 16 characters of salt, then $
  188. // 86 is the length of an SHA-512 hash
  189. return strncmp (encrypted + 20, returnedHash, 86) == 0 ;
  190. }
  191. /*
  192. * setupServer:
  193. * Do what's needed to create a local server socket instance that can listen
  194. * on both IPv4 and IPv6 interfaces.
  195. *********************************************************************************
  196. */
  197. int setupServer (int serverPort)
  198. {
  199. socklen_t clientSockAddrSize = sizeof (clientSockAddr) ;
  200. int on = 1 ;
  201. int family ;
  202. socklen_t serverSockAddrSize ;
  203. int clientFd ;
  204. // Try to create an IPv6 socket
  205. serverFd = socket (PF_INET6, SOCK_STREAM, 0) ;
  206. // If it didn't work, then fall-back to IPv4.
  207. if (serverFd < 0)
  208. {
  209. if ((serverFd = socket (PF_INET, SOCK_STREAM, 0)) < 0)
  210. return -1 ;
  211. family = AF_INET ;
  212. serverSockAddrSize = sizeof (struct sockaddr_in) ;
  213. }
  214. else // We got an IPv6 socket
  215. {
  216. family = AF_INET6 ;
  217. serverSockAddrSize = sizeof (struct sockaddr_in6) ;
  218. }
  219. if (setsockopt (serverFd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0)
  220. return -1 ;
  221. // Setup the servers socket address - cope with IPv4 and v6.
  222. memset (&serverSockAddr, 0, sizeof (serverSockAddr)) ;
  223. switch (family)
  224. {
  225. case AF_INET:
  226. serverSockAddr.sin.sin_family = AF_INET ;
  227. serverSockAddr.sin.sin_addr.s_addr = htonl (INADDR_ANY) ;
  228. serverSockAddr.sin.sin_port = htons (serverPort) ;
  229. break;
  230. case AF_INET6:
  231. serverSockAddr.sin6.sin6_family = AF_INET6 ;
  232. serverSockAddr.sin6.sin6_addr = in6addr_any ;
  233. serverSockAddr.sin6.sin6_port = htons (serverPort) ;
  234. }
  235. // Bind, listen and accept
  236. if (bind (serverFd, (struct sockaddr *)&serverSockAddr, serverSockAddrSize) < 0)
  237. return -1 ;
  238. if (listen (serverFd, 4) < 0) // Really only going to talk to one client at a time...
  239. return -1 ;
  240. if ((clientFd = accept (serverFd, (struct sockaddr *)&clientSockAddr, &clientSockAddrSize)) < 0)
  241. return -1 ;
  242. return clientFd ;
  243. }
  244. /*
  245. * closeServer:
  246. *********************************************************************************
  247. */
  248. void closeServer (int clientFd)
  249. {
  250. if (serverFd != -1) close (serverFd) ;
  251. if (clientFd != -1) close (clientFd) ;
  252. serverFd = clientFd = -1 ;
  253. }