main.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /**
  2. * nmrpflash - Netgear Unbrick Utility
  3. * Copyright (C) 2016 Joseph Lehner <joseph.c.lehner@gmail.com>
  4. *
  5. * nmrpflash is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * nmrpflash is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with nmrpflash. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. */
  19. #include <unistd.h>
  20. #include <getopt.h>
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include "nmrpd.h"
  24. #define NMRPFLASH_SET_REGION
  25. int verbosity = 0;
  26. void usage(FILE *fp)
  27. {
  28. fprintf(fp,
  29. "Usage: nmrpflash [OPTIONS...]\n"
  30. "\n"
  31. "Options (-i, -f and/or -c are mandatory):\n"
  32. " -a <ipaddr> IP address to assign to target device\n"
  33. " -A <ipaddr> IP address to assign to seleted interface\n"
  34. " -c <command> Command to run before (or instead of) TFTP upload\n"
  35. " -f <firmware> Firmware file\n"
  36. " -F <filename> Remote filename to use during TFTP upload\n"
  37. " -i <interface> Network interface directly connected to device\n"
  38. " -m <mac> MAC address of target device (xx:xx:xx:xx:xx:xx)\n"
  39. " -M <netmask> Subnet mask to assign to target device\n"
  40. " -t <timeout> Timeout (in milliseconds) for regular messages\n"
  41. " -T <timeout> Time (seconds) to wait after successfull TFTP upload\n"
  42. " -p <port> Port to use for TFTP upload\n"
  43. #ifdef NMRPFLASH_SET_REGION
  44. " -R <region> Set device region (NA, WW, GR, PR, RU, BZ, IN, KO, JP)\n"
  45. #endif
  46. #ifdef NMRPFLASH_TFTP_TEST
  47. " -U Test TFTP upload\n"
  48. #endif
  49. " -v Be verbose\n"
  50. " -V Print version and exit\n"
  51. " -L List network interfaces\n"
  52. " -h Show this screen\n"
  53. "\n"
  54. "Example: (run as "
  55. #ifndef NMRPFLASH_WINDOWS
  56. "root"
  57. #else
  58. "administrator"
  59. #endif
  60. ")\n\n"
  61. #ifndef NMRPFLASH_WINDOWS
  62. "# nmrpflash -i eth0 -f firmware.bin\n"
  63. #else
  64. "C:\\> nmrpflash.exe -i net0 -f firmware.bin\n"
  65. #endif
  66. "\n"
  67. "When using -c, the environment variables IP, PORT, NETMASK\n"
  68. "and MAC are set to the device IP address, TFTP port, subnet\n"
  69. "mask and MAC address, respectively.\n"
  70. "\n"
  71. "nmrpflash %s, Copyright (C) 2016 Joseph C. Lehner\n"
  72. "nmrpflash is free software, licensed under the GNU GPLv3.\n"
  73. "Source code at https://github.com/jclehner/nmrpflash\n"
  74. "\n",
  75. NMRPFLASH_VERSION
  76. );
  77. }
  78. #ifdef NMRPFLASH_WINDOWS
  79. void require_admin()
  80. {
  81. SID_IDENTIFIER_AUTHORITY auth = SECURITY_NT_AUTHORITY;
  82. PSID adminGroup = NULL;
  83. BOOL success = AllocateAndInitializeSid(
  84. &auth, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
  85. 0, 0, 0, 0, 0, 0, &adminGroup
  86. );
  87. if (success) {
  88. if (CheckTokenMembership(NULL, adminGroup, &success)) {
  89. if (!success) {
  90. fprintf(stderr, "Error: must be run as administrator\n");
  91. exit(1);
  92. } else {
  93. return;
  94. }
  95. }
  96. FreeSid(adminGroup);
  97. }
  98. fprintf(stderr, "Warning: failed to check administrator privileges\n");
  99. }
  100. #else
  101. void require_admin()
  102. {
  103. if (getuid() != 0) {
  104. fprintf(stderr, "Error: must be run as root\n");
  105. exit(1);
  106. }
  107. }
  108. #endif
  109. int main(int argc, char **argv)
  110. {
  111. int c, val, max;
  112. int list = 0;
  113. struct nmrpd_args args = {
  114. .rx_timeout = 200,
  115. .ul_timeout = 5 * 60 * 1000,
  116. .tftpcmd = NULL,
  117. .file_local = NULL,
  118. .file_remote = NULL,
  119. .ipaddr_intf = NULL,
  120. .ipaddr = NULL,
  121. .ipmask = "255.255.255.0",
  122. .intf = NULL,
  123. .mac = "ff:ff:ff:ff:ff:ff",
  124. .op = NMRP_UPLOAD_FW,
  125. .port = 69,
  126. .region = NULL,
  127. };
  128. #ifdef NMRPFLASH_WINDOWS
  129. char *newpath = NULL;
  130. char *oldpath = NULL;
  131. char *windir = NULL;
  132. WSADATA wsa;
  133. val = WSAStartup(MAKEWORD(2, 2), &wsa);
  134. if (val != 0) {
  135. win_perror2("WSAStartup", val);
  136. return 1;
  137. }
  138. #ifndef _WIN64
  139. // This dirty hack works around the WOW64 file system redirector[1], which would prevent
  140. // us from calling programs residing in %windir%\System32 when running on a 64bit system
  141. // (since nmrpflash is currently shipped as 32bit only).
  142. //
  143. // [1] https://msdn.microsoft.com/en-us/library/windows/desktop/aa384187(v=vs.85).aspx
  144. oldpath = getenv("PATH");
  145. windir = getenv("WINDIR");
  146. if (oldpath && windir) {
  147. newpath = malloc(strlen(oldpath) + strlen(windir) + 32);
  148. sprintf(newpath, "%s;%s\\Sysnative", oldpath, windir);
  149. SetEnvironmentVariable("PATH", newpath);
  150. free(newpath);
  151. }
  152. #endif
  153. #endif
  154. opterr = 0;
  155. while ((c = getopt(argc, argv, "a:A:c:f:F:i:m:M:p:R:t:T:hLVvU")) != -1) {
  156. max = 0x7fffffff;
  157. switch (c) {
  158. case 'a':
  159. args.ipaddr = optarg;
  160. break;
  161. case 'A':
  162. args.ipaddr_intf = optarg;
  163. break;
  164. case 'c':
  165. args.tftpcmd = optarg;
  166. break;
  167. case 'f':
  168. args.file_local = optarg;
  169. break;
  170. case 'F':
  171. args.file_remote = optarg;
  172. break;
  173. case 'i':
  174. args.intf = optarg;
  175. break;
  176. case 'm':
  177. args.mac = optarg;
  178. break;
  179. case 'M':
  180. args.ipmask = optarg;
  181. break;
  182. #ifdef NMRPFLASH_SET_REGION
  183. case 'R':
  184. args.region = optarg;
  185. break;
  186. #endif
  187. case 'p':
  188. case 'T':
  189. case 't':
  190. if (c == 'p') {
  191. max = 0xffff;
  192. }
  193. val = atoi(optarg);
  194. if (val <= 0 || val > max) {
  195. fprintf(stderr, "Invalid numeric value for -%c.\n", c);
  196. return 1;
  197. }
  198. if (c == 'p') {
  199. args.port = val;
  200. } else if (c == 't') {
  201. args.rx_timeout = val;
  202. } else if (c == 'T') {
  203. args.ul_timeout = val * 1000;
  204. }
  205. break;
  206. case 'V':
  207. printf("nmrpflash %s\n", NMRPFLASH_VERSION);
  208. val = 0;
  209. goto out;
  210. case 'v':
  211. ++verbosity;
  212. break;
  213. case 'L':
  214. list = 1;
  215. break;
  216. goto out;
  217. case 'h':
  218. usage(stdout);
  219. val = 0;
  220. goto out;
  221. #ifdef NMRPFLASH_TFTP_TEST
  222. case 'U':
  223. if (args.ipaddr && args.file_local) {
  224. val = tftp_put(&args);
  225. goto out;
  226. }
  227. /* fall through */
  228. #endif
  229. default:
  230. usage(stderr);
  231. val = 1;
  232. goto out;
  233. }
  234. }
  235. if (args.ipaddr_intf && !args.ipaddr) {
  236. fprintf(stderr, "Error: cannot use -A <ipaddr> without using -a <ipaddr>.\n");
  237. return 1;
  238. }
  239. #ifndef NMRPFLASH_FUZZ
  240. if (!list && ((!args.file_local && !args.tftpcmd) || !args.intf /*|| !args.ipaddr*/)) {
  241. usage(stderr);
  242. return 1;
  243. }
  244. require_admin();
  245. #endif
  246. val = !list ? nmrp_do(&args) : ethsock_list_all();
  247. out:
  248. #ifdef NMRPFLASH_WINDOWS
  249. WSACleanup();
  250. #endif
  251. return val;
  252. }