1/*
2 * Frontend command-line utility for Linux NVRAM layer
3 *
4 * Copyright (C) 2012, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * $Id: main.c 325698 2012-04-04 12:40:07Z $
19 */
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include <typedefs.h>
26#include <rtconfig.h>
27#include <bcmnvram.h>
28
29
30#define PROFILE_HEADER		"HDR1"
31#ifdef RTCONFIG_DSL
32#define PROFILE_HEADER_NEW	"N55U"
33#else
34#define PROFILE_HEADER_NEW	"HDR2"
35#endif
36
37/*******************************************************************
38* NAME: _secure_romfile
39* AUTHOR: Andy Chiu
40* CREATE DATE: 2015/06/08
41* DESCRIPTION: replace account /password by '1' with the same string length
42* INPUT:  path: the rom file path
43* OUTPUT:
44* RETURN:  0: success, -1:failed
45* NOTE: Andy Chiu, 2015/12/18. Add new tokens.
46*           Andy Chiu, 2015/12/24. Add new tokens.
47*	     Andy Chiu, 2016/02/18. Add new token, wtf_username.
48*******************************************************************/
49static int _secure_conf(char* buf)
50{
51	char name[128], *item;
52	int i, flag;
53	const char *keyword_token[] = {"http_username", "pppoe_username", "passwd", "password", ""};	//Andy Chiu, 2015/12/18
54
55	const char *token1[] = {"wan_pppoe_passwd", "modem_pass", "modem_pincode",
56		"http_passwd", "wan0_pppoe_passwd", "dslx_pppoe_passwd", "ddns_passwd_x",
57		"wl_wpa_psk",	"wlc_wpa_psk",  "wlc_wep_key",
58		"wl0_wpa_psk", "wl0.1_wpa_psk", "wl0.2_wpa_psk", "wl0.3_wpa_psk",
59		"wl1_wpa_psk", "wl1.1_wpa_psk", "wl1.2_wpa_psk", "wl1.3_wpa_psk",
60		"wl0.1_key1", "wl0.1_key2", "wl0.1_key3", "wl0.1_key4",
61		"wl0.2_key1", "wl0.2_key2", "wl0.2_key3", "wl0.2_key4",
62		"wl0.3_key1", "wl0.3_key2", "wl0.3_key3", "wl0.3_key4",
63		"wl0_key1", "wl0_key2", "wl0_key3", "wl0_key4",
64		"wl1.1_key1", "wl1.1_key2", "wl1.1_key3", "wl1.1_key4",
65		"wl1.2_key1", "wl1.2_key2", "wl1.2_key3", "wl1.2_key4",
66		"wl1.3_key1", "wl1.3_key2", "wl1.3_key3", "wl1.3_key4",
67		"wl_key1", "wl_key2", "wl_key3", "wl_key4",
68		"wl1_key1", "wl1_key2", "wl1_key3", "wl1_key4",
69		"wl0_phrase_x", "wl0.1_phrase_x", "wl0.2_phrase_x", "wl0.3_phrase_x",
70		"wl1_phrase_x", "wl1.1_phrase_x", "wl1.2_phrase_x", "wl1.3_phrase_x",
71		"wl_phrase_x", "vpnc_openvpn_pwd", "PM_SMTP_AUTH_USER", "PM_MY_EMAIL", "PM_SMTP_AUTH_PASS", "wtf_username", ""};
72
73	const char *token2[] = {"acc_list", "pptpd_clientlist", ""};
74	//admin>99999<Family>99999999<aaaaa>9999999<bbbbb>999999
75	//pptpd_clientlist=<aaaaaaaaa>999999999<bbbbbbbbbb>9999999999
76
77	const char vpnc_token[] = "vpnc_clientlist";
78//	qwrety>PPTP>asdf>aaaaaaaaaa>999999999999<qe3rtuio>L2TP>waesrdio>bbbbbbbbb>9999999999999<wqertuio>OpenVPN>1>ccccccccc>999999999999
79
80	const char cloud_token[] = "cloud_sync";
81//	0>aaaaaaaaaaa>9999999999>none>0>/tmp/mnt/SANDISK_32G/aaa>1
82
83	if(!buf)
84		return -1;
85
86	//fprintf(stderr, "[%s, %d]\n", __FUNCTION__, __LINE__);
87	for (item = buf; *item; item += strlen(item) + 1)
88	{
89		//get name of item
90		char *ptr = strchr(item, '=');
91		if(!ptr)	//invalid item
92			continue;
93		memset(name, 0, sizeof(name));
94		strncpy(name, item, ptr - item);
95		flag = 0;
96		//skip '='
97		++ptr;
98		//fprintf(stderr, "[%s, %d]item(%s), name(%s), val(%s)\n", __FUNCTION__, __LINE__, item, name, ptr);
99
100		//check the password keyword token
101		for(i = 0; strlen(keyword_token[i]) > 0; ++i)
102		{
103			if(strstr(name, keyword_token[i]))
104			{
105				//replace the value
106				memset(ptr, '1', strlen(ptr));
107				//fprintf(stderr, "[%s, %d]<%s>replace(%s)\n", __FUNCTION__, __LINE__, name, ptr);
108				flag = 1;
109				break;
110			}
111		}
112		if(flag)
113			continue;
114
115		//check the first token group
116		for(i = 0; strlen(token1[i]) > 0; ++i)
117		{
118			if(!strcmp(name, token1[i]))
119			{
120				//replace the value
121				memset(ptr, '1', strlen(ptr));
122				//fprintf(stderr, "[%s, %d]<%s>replace(%s)\n", __FUNCTION__, __LINE__, name, ptr);
123				flag = 1;
124				break;
125			}
126		}
127		if(flag)
128			continue;
129
130		//check the 2nd token group
131		//admin>99999<Family>99999999<aaaaa>9999999<bbbbb>999999
132		for(i = 0; strlen(token2[i]) > 0; ++i)
133		{
134			if(!strcmp(name, token2[i]))
135			{
136				//replace the value
137				char *b = ptr, *e;
138				do
139				{
140					b = strchr(b, '>');
141					if(b)
142						++b;
143					else
144						break;
145					e = strchr(b, '<');
146
147					if(e)
148					{
149						memset(b, '1', e-b);
150						b = e + 1;
151					}
152					else
153						memset(b, '1', strlen(b));
154
155				}while(b);
156				//fprintf(stderr, "[%s, %d]<%s>replace(%s)\n", __FUNCTION__, __LINE__, name, ptr);
157				flag = 1;
158				break;
159			}
160		}
161		if(flag)
162			continue;
163
164		//check vpnc token
165		//qwrety>PPTP>asdf>aaaaaaaaaa>999999999999<qe3rtuio>L2TP>waesrdio>bbbbbbbbb>9999999999999<wqertuio>OpenVPN>1>ccccccccc>999999999999
166		if(!strcmp(name, vpnc_token))
167		{
168			char *b = ptr, *e;
169			if(*b == '<')
170				++b;
171			do{
172				int j;
173				for(j = 0; j < 4; ++j)
174				{
175					b = strchr(b, '>');
176					if(b)
177						++b;
178					else
179						break;
180				}
181
182				if(b)
183				{
184					e = strchr(b, '<');
185					if(e)
186					{
187						memset(b, '1', e - b);
188						b = e + 1;
189					}
190					else
191					{
192						memset(b, '1', strlen(b));
193						b = NULL;
194					}
195				}
196			}while(b);
197			//fprintf(stderr, "[%s, %d]<%s>replace(%s)\n", __FUNCTION__, __LINE__, name, ptr);
198		}
199
200		//check cloud sync token
201		//0>aaaaaaaaaaa>9999999999>none>0>/tmp/mnt/SANDISK_32G/aaa>1
202		if(!strcmp(name, cloud_token))
203		{
204			char *b = ptr, *e;
205			if(*b == '<')
206				++b;
207			do{
208				int j;
209				for(j = 0; j < 2; ++j)
210				{
211					b = strchr(b, '>');
212					if(b)
213						++b;
214					else
215						break;
216				}
217
218				if(b)
219				{
220					e = strchr(b, '>');
221					if(e)
222					{
223						memset(b, '1', e - b);
224						b = strchr(e, '<');
225					}
226					else	//invalid
227					{
228						b = NULL;
229					}
230				}
231			}while(b);
232			//fprintf(stderr, "[%s, %d]<%s>replace(%s)\n", __FUNCTION__, __LINE__, name, ptr);
233		}
234	}
235	return 0;
236}
237
238
239unsigned char get_rand()
240{
241	unsigned char buf[1];
242	FILE *fp;
243
244	fp = fopen("/dev/urandom", "r");
245	if (fp == NULL) {
246#ifdef ASUS_DEBUG
247		fprintf(stderr, "Could not open /dev/urandom.\n");
248#endif
249		return 0;
250	}
251	fread(buf, 1, 1, fp);
252	fclose(fp);
253
254	return buf[0];
255}
256
257int nvram_save_new(char *file, char *buf)
258{
259	FILE *fp;
260	char *name;
261	unsigned long count, filelen, i;
262	unsigned char rand = 0, temp;
263
264	if ((fp = fopen(file, "w")) == NULL) return -1;
265
266	count = 0;
267	for (name = buf; *name; name += strlen(name) + 1)
268	{
269#ifdef ASUS_DEBUG
270		puts(name);
271#endif
272		count = count + strlen(name) + 1;
273	}
274
275	filelen = count + (1024 - count % 1024);
276	rand = get_rand() % 30;
277#ifdef ASUS_DEBUG
278	fprintf(stderr, "random number: %x\n", rand);
279#endif
280	fwrite(PROFILE_HEADER_NEW, 1, 4, fp);
281	fwrite(&filelen, 1, 3, fp);
282	fwrite(&rand, 1, 1, fp);
283#ifdef ASUS_DEBUG
284	for (i = 0; i < 4; i++)
285	{
286		fprintf(stderr, "%2x ", PROFILE_HEADER_NEW[i]);
287	}
288	for (i = 0; i < 3; i++)
289	{
290		fprintf(stderr, "%2x ", ((char *)&filelen)[i]);
291	}
292	fprintf(stderr, "%2x ", ((char *)&rand)[0]);
293#endif
294	for (i = 0; i < count; i++)
295	{
296		if (buf[i] == 0x0)
297			buf[i] = 0xfd + get_rand() % 3;
298		else
299			buf[i] = 0xff - buf[i] + rand;
300	}
301	fwrite(buf, 1, count, fp);
302#ifdef ASUS_DEBUG
303	for (i = 0; i < count; i++)
304	{
305		if (i % 16 == 0) fprintf(stderr, "\n");
306		fprintf(stderr, "%2x ", (unsigned char) buf[i]);
307	}
308#endif
309	for (i = count; i < filelen; i++)
310	{
311		temp = 0xfd + get_rand() % 3;
312		fwrite(&temp, 1, 1, fp);
313#ifdef ASUS_DEBUG
314		if (i % 16 == 0) fprintf(stderr, "\n");
315		fprintf(stderr, "%2x ", (unsigned char) temp);
316#endif
317	}
318	fclose(fp);
319	return 0;
320}
321
322int issyspara(char *p)
323{
324	struct nvram_tuple *t;
325	extern struct nvram_tuple router_defaults[];
326
327	// skip checking for wl[]_, wan[], lan[]_
328	if (strstr(p, "wl") || strstr(p, "wan") || strstr(p, "lan"))
329		return 1;
330
331	for (t = router_defaults; t->name; t++)
332	{
333		if (strstr(p, t->name))
334			break;
335
336	}
337
338	if (t->name) return 1;
339	else return 0;
340}
341
342int nvram_restore_new(char *file, char *buf)
343{
344	FILE *fp;
345	char header[8], *p, *v;
346	unsigned long count, filelen, *filelenptr, i;
347	unsigned char rand, *randptr;
348
349	if ((fp = fopen(file, "r+")) == NULL) return -1;
350
351	count = fread(header, 1, 8, fp);
352	if (count>=8 && strncmp(header, PROFILE_HEADER, 4) == 0)
353	{
354		filelenptr = (unsigned long *)(header + 4);
355#ifdef ASUS_DEBUG
356		fprintf(stderr, "restoring original text cfg of length %x\n", *filelenptr);
357#endif
358		fread(buf, 1, *filelenptr, fp);
359	}
360	else if (count>=8 && strncmp(header, PROFILE_HEADER_NEW, 4) == 0)
361	{
362		filelenptr = (unsigned long *)(header + 4);
363		filelen = *filelenptr & 0xffffff;
364#ifdef ASUS_DEBUG
365		fprintf(stderr, "restoring non-text cfg of length %x\n", filelen);
366#endif
367		randptr = (unsigned char *)(header + 7);
368		rand = *randptr;
369#ifdef ASUS_DEBUG
370		fprintf(stderr, "non-text cfg random number %x\n", rand);
371#endif
372		count = fread(buf, 1, filelen, fp);
373#ifdef ASUS_DEBUG
374		fprintf(stderr, "non-text cfg count %x\n", count);
375#endif
376		for (i = 0; i < count; i++)
377		{
378			if ((unsigned char) buf[i] > ( 0xfd - 0x1)){
379				/* e.g.: to skip the case: 0x61 0x62 0x63 0x00 0x00 0x61 0x62 0x63 */
380				if(i > 0 && buf[i-1] != 0x0)
381					buf[i] = 0x0;
382			}
383			else
384				buf[i] = 0xff + rand - buf[i];
385		}
386#ifdef ASUS_DEBUG
387		for (i = 0; i < count; i++)
388		{
389			if (i % 16 == 0) fprintf(stderr, "\n");
390			fprintf(stderr, "%2x ", (unsigned char) buf[i]);
391		}
392
393		for (i = 0; i < count; i++)
394		{
395			if (i % 16 == 0) fprintf(stderr, "\n");
396			fprintf(stderr, "%c", buf[i]);
397		}
398#endif
399	}
400	else
401	{
402		fclose(fp);
403		return 0;
404	}
405	fclose(fp);
406
407	p = buf;
408
409	while (*p)
410	{
411#if 1
412		/* e.g.: to skip the case: 00 2e 30 2e 32 38 00 ff 77 61 6e */
413		if(*p == NULL || *p < 32 || *p > 127 ){
414			p = p + 1;
415			continue;
416		}
417#endif
418		v = strchr(p, '=');
419
420		if (v != NULL)
421		{
422			*v++ = '\0';
423
424			if (issyspara(p))
425				nvram_set(p, v);
426
427			p = v + strlen(v) + 1;
428		}
429		else
430		{
431			nvram_unset(p);
432			p = p + 1;
433		}
434	}
435	return 0;
436}
437
438void
439usage(void)
440{
441	fprintf(stderr,
442	        "usage: nvram [get name] [set name=value] "
443	        "[unset name] [show] [commit] [save] [restore] [erase][fb_save file] ...\n");
444	exit(0);
445}
446
447/* NVRAM utility */
448int
449main(int argc, char **argv)
450{
451	char *name, *value, buf[MAX_NVRAM_SPACE];
452	char *tmpbuf;	//Andy Chiu, 2015/06/09
453	int size;
454
455	/* Skip program name */
456	--argc;
457	++argv;
458
459	if (!*argv)
460		usage();
461
462	/* Process the arguments */
463	for (; *argv; ++argv) {
464		if (!strcmp(*argv, "get")) {
465			if (*++argv) {
466				if ((value = nvram_get(*argv)))
467					puts(value);
468			}
469		} else if (!strcmp(*argv, "set")) {
470			if (*++argv) {
471				strncpy(value = buf, *argv, sizeof(buf));
472				name = strsep(&value, "=");
473				nvram_set(name, value);
474			}
475		} else if (!strcmp(*argv, "unset")) {
476			if (*++argv)
477				nvram_unset(*argv);
478		} else if (!strcmp(*argv, "commit")) {
479			nvram_commit();
480		} else if (!strcmp(*argv, "save")) {
481			if (*++argv)
482			{
483				nvram_getall(buf, NVRAM_SPACE);
484				nvram_save_new(*argv, buf);
485			}
486		//Andy Chiu, 2015/06/09
487		}else if(!strncmp(*argv, "fb_save", 7)) {
488			if (*++argv)
489			{
490				tmpbuf = malloc(MAX_NVRAM_SPACE);
491				if(!tmpbuf)
492				{
493					fprintf(stderr, "Can NOT alloc memory!!!");
494					return 0;
495				}
496				nvram_getall(buf, MAX_NVRAM_SPACE);
497				memcpy(tmpbuf, buf, MAX_NVRAM_SPACE);
498				_secure_conf(tmpbuf);
499#if 0
500				FILE *fp = fopen("/tmp/var/fb_conf.test", "w");
501				if(fp)
502				{
503					fwrite(tmpbuf, 1, MAX_NVRAM_SPACE, fp);
504					fclose(fp);
505				}
506#endif
507				nvram_save_new(*argv, tmpbuf);
508				free(tmpbuf);
509			}
510		} else if (!strcmp(*argv, "restore")) {
511			if (*++argv)
512				nvram_restore_new(*argv, buf);
513		} else if (!strcmp(*argv, "erase")) {
514			system("nvram_erase");
515		} else if (!strcmp(*argv, "show") ||
516		           !strcmp(*argv, "dump")) {
517			nvram_getall(buf, sizeof(buf));
518			for (name = buf; *name; name += strlen(name) + 1)
519				puts(name);
520			size = sizeof(struct nvram_header) + (int) name - (int) buf;
521			if (**argv != 'd')
522				fprintf(stderr, "size: %d bytes (%d left)\n",
523				        size, MAX_NVRAM_SPACE - size);
524		} else
525			usage();
526	}
527
528	return 0;
529}
530