Add missing newline
[oweals/nmrpflash.git] / main.c
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
20 #include <unistd.h>
21 #include <getopt.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include "nmrpd.h"
25
26 #define NMRPFLASH_SET_REGION
27
28 int verbosity = 0;
29
30 void usage(FILE *fp)
31 {
32         fprintf(fp,
33                         "Usage: nmrpflash [OPTIONS...]\n"
34                         "\n"
35                         "Options (-a, -i and -f and/or -c are mandatory):\n"
36                         " -a <ipaddr>     IP address to assign to target device\n"
37                         " -c <command>    Command to run before (or instead of) TFTP upload\n"
38                         " -f <firmware>   Firmware file\n"
39                         " -F <filename>   Remote filename to use during TFTP upload\n"
40                         " -i <interface>  Network interface directly connected to device\n"
41                         " -m <mac>        MAC address of target device (xx:xx:xx:xx:xx:xx)\n"
42                         " -M <netmask>    Subnet mask to assign to target device\n"
43                         " -t <timeout>    Timeout (in milliseconds) for regular messages\n"
44                         " -T <timeout>    Time (seconds) to wait after successfull TFTP upload\n"
45                         " -p <port>       Port to use for TFTP upload\n"
46 #ifdef NMRPFLASH_SET_REGION
47                         " -R <region>     Set device region (NA, WW, GR, PR, RU, BZ, IN, KO, JP)\n"
48 #endif
49 #ifdef NMRPFLASH_TFTP_TEST
50                         " -U              Test TFTP upload\n"
51 #endif
52                         " -v              Be verbose\n"
53                         " -V              Print version and exit\n"
54                         " -L              List network interfaces\n"
55                         " -h              Show this screen\n"
56                         "\n"
57                         "Example: (run as "
58 #ifndef NMRPFLASH_WINDOWS
59                         "root"
60 #else
61                         "administrator"
62 #endif
63                         ")\n\n"
64 #ifndef NMRPFLASH_WINDOWS
65                         "# nmrpflash -i eth0 -a 192.168.1.254 -f firmware.bin\n"
66 #else
67                         "C:\\> nmrpflash.exe -i net0 -a 192.168.1.254 -f firmware.bin\n"
68 #endif
69                         "\n"
70                         "nmrpflash %s, Copyright (C) 2016 Joseph C. Lehner\n"
71                         "nmrpflash is free software, licensed under the GNU GPLv3.\n"
72                         "Source code at https://github.com/jclehner/nmrpflash\n"
73                         "\n",
74                         NMRPFLASH_VERSION
75           );
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
88         if (success) {
89                 if (CheckTokenMembership(NULL, adminGroup, &success)) {
90                         if (!success) {
91                                 fprintf(stderr, "Error: must be run as administrator\n");
92                                 exit(1);
93                         } else {
94                                 return;
95                         }
96                 }
97                 FreeSid(adminGroup);
98         }
99
100         fprintf(stderr, "Warning: failed to check administrator privileges\n");
101 }
102 #else
103 void require_admin()
104 {
105         if (getuid() != 0) {
106                 fprintf(stderr, "Error: must be run as root\n");
107                 exit(1);
108         }
109 }
110 #endif
111
112 int main(int argc, char **argv)
113 {
114         int c, val, max;
115         int list = 0;
116         struct nmrpd_args args = {
117                 .rx_timeout = 200,
118                 .ul_timeout = 5 * 60 * 1000,
119                 .tftpcmd = NULL,
120                 .file_local = NULL,
121                 .file_remote = NULL,
122                 .ipaddr = NULL,
123                 .ipmask = "255.255.255.0",
124                 .intf = NULL,
125                 .mac = "ff:ff:ff:ff:ff:ff",
126                 .op = NMRP_UPLOAD_FW,
127                 .port = 69,
128                 .region = NULL,
129         };
130 #ifdef NMRPFLASH_WINDOWS
131         WSADATA wsa;
132
133         val = WSAStartup(MAKEWORD(2, 2), &wsa);
134         if (val != 0) {
135                 win_perror2("WSAStartup", val);
136                 return 1;
137         }
138 #endif
139
140         opterr = 0;
141
142         while ((c = getopt(argc, argv, "a:c:f:F:i:m:M:p:R:t:T:hLVvU")) != -1) {
143                 max = 0x7fffffff;
144                 switch (c) {
145                         case 'a':
146                                 args.ipaddr = optarg;
147                                 break;
148                         case 'c':
149                                 args.tftpcmd = optarg;
150                                 break;
151                         case 'f':
152                                 args.file_local = optarg;
153                                 break;
154                         case 'F':
155                                 args.file_remote = optarg;
156                                 break;
157                         case 'i':
158                                 args.intf = optarg;
159                                 break;
160                         case 'm':
161                                 args.mac = optarg;
162                                 break;
163                         case 'M':
164                                 args.ipmask = optarg;
165                                 break;
166 #ifdef NMRPFLASH_SET_REGION
167                         case 'R':
168                                 args.region = optarg;
169                                 break;
170 #endif
171                         case 'p':
172                         case 'T':
173                         case 't':
174                                 if (c == 'p') {
175                                         max = 0xffff;
176                                 }
177
178                                 val = atoi(optarg);
179                                 if (val <= 0 || val > max) {
180                                         fprintf(stderr, "Invalid numeric value for -%c.\n", c);
181                                         return 1;
182                                 }
183
184                                 if (c == 'p') {
185                                         args.port = val;
186                                 } else if (c == 't') {
187                                         args.rx_timeout = val;
188                                 } else if (c == 'T') {
189                                         args.ul_timeout = val * 1000;
190                                 }
191
192                                 break;
193                         case 'V':
194                                 printf("nmrpflash %s\n", NMRPFLASH_VERSION);
195                                 val = 0;
196                                 goto out;
197                         case 'v':
198                                 ++verbosity;
199                                 break;
200                         case 'L':
201                                 list = 1;
202                                 break;
203                                 goto out;
204                         case 'h':
205                                 usage(stdout);
206                                 val = 0;
207                                 goto out;
208 #ifdef NMRPFLASH_TFTP_TEST
209                         case 'U':
210                                 if (args.ipaddr && args.file_local) {
211                                         val = tftp_put(&args);
212                                         goto out;
213                                 }
214                                 /* fall through */
215 #endif
216                         default:
217                                 usage(stderr);
218                                 val = 1;
219                                 goto out;
220                 }
221         }
222
223         if (!list && ((!args.file_local && !args.tftpcmd) || !args.intf || !args.ipaddr)) {
224                 usage(stderr);
225                 return 1;
226         }
227
228         require_admin();
229         val = !list ? nmrp_do(&args) : ethsock_list_all();
230
231 out:
232 #ifdef NMRPFLASH_WINDOWS
233         WSACleanup();
234 #endif
235         return val;
236 }