1#include <ctype.h>
2#include <stdio.h>
3#include <string.h>
4#include <strings.h>
5
6#define IF_LOOKUP 1
7#include <sys/ioctl.h>
8#include <net/if.h>
9#include <sys/types.h>
10#include <sys/socket.h>
11#include <netinet/in.h>
12#include <stdlib.h>
13
14#include "md5.h"
15#include "asus_ddns.h"
16#if 0
17#include <nvram_linux.h>
18#else //2007.03.14 Yau add for WL500gp2
19#include <bcmnvram.h>
20#endif
21#include <syslog.h>
22#include <shared.h>
23
24#define MAX_DOMAIN_LEN	50	// hostname len (32) + "asuscomm.com" ~~ 45, reserve 5 char
25
26//#define DUMP_KEY
27#ifdef DUMP_KEY
28#define DUMP(k)	dump (k, sizeof (k))
29#else
30#define DUMP(k)
31#endif	// DUMP_KEY
32
33enum {
34  REGISTERES_OK = 0,
35  REGISTERES_ERROR,
36  REGISTERES_SHUTDOWN,
37};
38
39/**************************************** Copy from ez-ipupdate.c * start ********************************/
40#ifdef DEBUG
41#  define BUFFER_SIZE (16*1024)
42#else
43#  define BUFFER_SIZE (4*1024-1)
44#endif
45
46#define OPT_DEBUG       0x0001
47#define OPT_DAEMON      0x0004
48#define OPT_QUIET       0x0008
49#define OPT_FOREGROUND  0x0010
50#define OPT_OFFLINE     0x0020
51
52enum {
53  UPDATERES_OK = 0,
54  UPDATERES_ERROR,
55  UPDATERES_SHUTDOWN,
56};
57/**************************************** Copy from ez-ipupdate.c * end **********************************/
58
59
60#ifdef DEBUG
61#	define PRINT(fmt,args...)	fprintf (stderr, fmt, ## args);
62#	define DBG(fmt,args...) 	fprintf (stderr, fmt, ## args);
63#else
64#	define PRINT(fmt,args...)	show_message(fmt,args...);
65//#	define PRINT(fmt,args...) 	syslog (LOG_NOTICE, fmt, ## args);
66#	define DBG(fmt,args...)
67#endif
68
69int g_asus_ddns_mode = 0; /* 0: disable;  1: register domain;  2: update ip */
70
71
72static void hm(text, text_len, key, key_len, digest)
73unsigned char *text;			/* pointer to data stream */
74int text_len;					/* length of data stream */
75unsigned char *key;				/* pointer to authentication key */
76int key_len;					/* length of authentication key */
77unsigned char *digest;			/* caller digest to be filled in */
78
79{
80	struct md5_ctx context;
81	unsigned char k_ipad[65];	/* inner padding -
82								 * key XORd with ipad
83								 */
84	unsigned char k_opad[65];	/* outer padding -
85								 * key XORd with opad
86								 */
87	unsigned char tk[16];
88	int i;
89	/* if key is longer than 64 bytes reset it to key=MD5(key) */
90	if (key_len > 64) {
91		struct md5_ctx tctx;
92		md5_init_ctx(&tctx);
93		md5_process_bytes(key, key_len, &tctx);
94		md5_finish_ctx(&tctx, tk);
95
96		key = tk;
97		key_len = 16;
98	}
99
100	/*
101	 * the HMAC_MD5 transform looks like:
102	 *
103	 * MD5(K XOR opad, MD5(K XOR ipad, text))
104	 *
105	 * where K is an n byte key
106	 * ipad is the byte 0x36 repeated 64 times
107	 * opad is the byte 0x5c repeated 64 times
108	 * and text is the data being protected
109	 */
110
111	/* start out by storing key in pads */
112	bzero(k_ipad, sizeof k_ipad);
113	bzero(k_opad, sizeof k_opad);
114	bcopy(key, k_ipad, key_len);
115	bcopy(key, k_opad, key_len);
116
117	/* XOR key with ipad and opad values */
118	for (i = 0; i < 64; i++) {
119		k_ipad[i] ^= 0x36;
120		k_opad[i] ^= 0x5c;
121	}
122	/*
123	 * perform inner MD5
124	 */
125	md5_init_ctx(&context);						/* init context for 1st * pass */
126	md5_process_bytes(k_ipad, 64, &context);	/* start with inner pad */
127	md5_process_bytes(text, text_len, &context);/* then text of datagram */
128	md5_finish_ctx(&context, digest);			/* finish up 1st pass */
129	/*
130	 * perform outer MD5
131	 */
132	md5_init_ctx(&context);						/* init context for 2nd * pass */
133	md5_process_bytes(k_opad, 64, &context);	/* start with outer pad */
134	md5_process_bytes(digest, 16, &context);	/* then results of 1st * hash */
135	md5_finish_ctx(&context, digest);			/* finish up 2nd pass */
136}
137
138
139#ifdef TEST_HMAC_MD5
140/*
141HMAC-MD5 Test Vectors (Trailing '\0' of a character string not included in test):
142
143  key =         0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
144  key_len =     16 bytes
145  data =        "Hi There"
146  data_len =    8  bytes
147  digest =      0x9294727a3638bb1c13f48ef8158bfc9d
148
149  key =         "Jefe"
150  data =        "what do ya want for nothing?"
151  data_len =    28 bytes
152  digest =      0x750c783e6ab0b503eaa86e310a5db738
153
154  key =         0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
155  key_len       16 bytes
156  data =        0xDDDDDDDDDDDDDDDDDDDD...
157                ..DDDDDDDDDDDDDDDDDDDD...
158                ..DDDDDDDDDDDDDDDDDDDD...
159                ..DDDDDDDDDDDDDDDDDDDD...
160                ..DDDDDDDDDDDDDDDDDDDD
161  data_len =    50 bytes
162  digest =      0x56be34521d144c88dbb8c733f0e8b3f6
163
164  ------------------------------------------------
165  HOW TO COMPILE TEST VECTORS?
166  gcc -Wall -c -o test_hmac_md5.o -DTEST_HMAC_MD5 -DDEBUG -DUSE_MD5 asus_ddns.c
167  gcc -Wall -c -o md5_x86.o -DTEST_HMAC_MD5 -DDEBUG -DUSE_MD5 md5.c
168  gcc -Wall -o test_hmac_md5 test_hmac_md5.o md5_x86.o
169
170  ------------------------------------------------
171  NOTES: If your device is big-endian platform, you have to define WORDS_BIGENDIAN as 1.
172
173  The test_hmac_md5 is test program. It will print three hash values and match with above.
174*/
175static void dump (unsigned char *p, unsigned int l)
176{
177	unsigned int i;
178	if (p == NULL || l == 0)
179		return;
180
181	printf ("0x");
182	for (i = 0; i < l; ++i)
183		printf ("%02x", p[i]);
184	printf ("\n\n");
185}
186
187int main(void)
188{
189	unsigned char key[16], data[256], digest[16];
190
191	// case 1
192	memset (key, 0, sizeof (key));
193	memset (key, 0x0b, 16);
194	memset (data, 0, sizeof (data));
195	strcpy ((char*)data, "Hi There");
196	hm(data, 8, key, 16, digest);
197	printf ("case 1:"); dump (digest, 16);
198
199	// case 2
200	memset (key, 0, sizeof (key));
201	strcpy ((char*)key, "Jefe");
202	memset (data, 0, sizeof (data));
203	strcpy ((char*)data, "what do ya want for nothing?");
204	hm(data, 28, key, 4, digest);
205	printf ("case 2:"); dump (digest, 16);
206
207	// case 3
208	memset (key, 0, sizeof (key));
209	memset (key, 0xAA, 16);
210	memset (data, 0, sizeof (data));
211	memset (data, 0xDD, 50);
212	hm(data, 50, key, 16, digest);
213	printf ("case 3:"); dump (digest, 16);
214
215
216	return 0;
217}
218#else	// !TEST_HMAC_MD5
219
220#define MULTICAST_BIT  0x0001
221#define UNIQUE_OUI_BIT 0x0002
222int TransferMacAddr(const char* mac, char* transfer_mac)
223{
224        int sec_byte;
225        int i = 0, s = 0;
226	char *p_mac;
227	p_mac = transfer_mac;
228
229        if( strlen(mac)!=17 || !strcmp("00:00:00:00:00:00", mac) )
230                return 0;
231
232        while( *mac && i<12 ) {
233                if( isxdigit(*mac) ) {
234                        if(i==1) {
235                                sec_byte= strtol(mac, NULL, 16);
236                                if((sec_byte & MULTICAST_BIT)||(sec_byte & UNIQUE_OUI_BIT))
237                                        break;
238                        }
239                        i++;
240		        memcpy(p_mac, mac, 1);
241                	p_mac++;
242                }
243                else if( *mac==':') {
244                        if( i==0 || i/2-1!=s )
245                                break;
246                        ++s;
247                }
248                ++mac;
249        }
250        return( i==12 && s==5 );
251}
252
253int asus_reg_domain (void)
254{
255	char buf[BUFFER_SIZE + 1];
256	char *p, *bp = buf;
257	char ret_buf[64];
258	char sug_name[MAX_DOMAIN_LEN], old_name[MAX_DOMAIN_LEN];
259	int bytes;
260	int btot;
261	int ret;
262	int retval = REGISTERES_OK;
263
264	buf[BUFFER_SIZE] = '\0';
265
266	if (do_connect((int *) &client_sockfd, server, port) != 0) {
267		PRINT ("error connecting to %s:%s\n", server, port);
268		show_message("error connecting to %s:%s\n", server, port);
269		nvram_set ("ddns_return_code", "connect_fail");
270		nvram_set ("ddns_return_code_chk", "connect_fail");
271		return (REGISTERES_ERROR);
272	}
273
274	char *ddns_transfer;
275	char old_mac[13];
276	memset(old_mac, 0, 13);
277	if(TransferMacAddr(nvram_safe_get("ddns_transfer"), old_mac)) {
278		snprintf(buf, BUFFER_SIZE, "GET /ddns/register.jsp?hostname=%s&myip=%s&oldmac=%s HTTP/1.0\015\012",
279			 host, address, old_mac);
280	}
281	else {
282		snprintf(buf, BUFFER_SIZE, "GET /ddns/register.jsp?hostname=%s&myip=%s HTTP/1.0\015\012", host, address);
283	}
284	output(buf);
285	snprintf(buf, BUFFER_SIZE, "Authorization: Basic %s\015\012", auth);
286	output(buf);
287	snprintf(buf, BUFFER_SIZE, "User-Agent: %s-%s %s [%s] (%s)\015\012", "ez-update", VERSION, OS, (options & OPT_DAEMON) ? "daemon" : "", "by Angus Mackay");
288	output(buf);
289	snprintf(buf, BUFFER_SIZE, "Host: %s\015\012", server);
290	output(buf);
291	snprintf(buf, BUFFER_SIZE, "\015\012");
292	output(buf);
293
294	memset (buf, 0, sizeof (buf));
295	bp = buf;
296	bytes = 0;
297	btot = 0;
298	ret = 0;
299	while ((bytes = read_input(bp, BUFFER_SIZE - btot)) > 0) {
300		bp += bytes;
301		btot += bytes;
302	}
303	close(client_sockfd);
304	buf[btot] = '\0';
305	//show_message("Asus Reg domain:: return: %s\n", buf);
306	if(btot) { // TODO: according to server response, parsing code have to rewrite
307		if (sscanf(buf, " HTTP/1.%*c %3d", &ret) != 1) {
308			ret = -1;
309		}
310
311		// looking for 2-th '|'
312		p = strchr (buf, '|');
313		if (p != NULL)
314			p = strchr (p+1, '|');
315		if (p == NULL)	{
316			p = "";
317		}
318		snprintf (ret_buf, sizeof (ret_buf), "%s,%d", "register", ret);
319	}
320
321	nvram_set ("ddns_return_code", ret_buf);
322	nvram_set ("ddns_return_code_chk", ret_buf);
323	switch (ret) {
324	case -1:
325		PRINT ("strange server response, are you connecting to the right server?\n");
326		retval = REGISTERES_ERROR;
327		break;
328
329	case 200:
330		PRINT ("Registration success.\n");
331		break;
332
333	case 203:
334		PRINT ("Registration failed. (203)\n");
335		memset (sug_name, 0, sizeof (sug_name));
336		sscanf (p, "|%[^|\r\n]c", sug_name);
337		nvram_set ("ddns_suggest_name", sug_name);
338
339		retval = REGISTERES_ERROR;
340		break;
341
342	case 220:
343		PRINT ("Registration same domain success.\n");
344		break;
345
346	case 230:
347		PRINT ("Registration new domain success.\n");
348		memset (old_name, 0, sizeof (old_name));
349		sscanf (p, "|%[^|\r\n]c", old_name);
350		nvram_set ("ddns_old_name", old_name);
351		break;
352
353	case 233:
354		PRINT ("Registration failed. (233)\n");
355		memset (old_name, 0, sizeof (old_name));
356		sscanf (p, "|%[^|\r\n]c", old_name);
357		nvram_set ("ddns_old_name", old_name);
358		retval = REGISTERES_ERROR;
359		break;
360
361	case 297:
362		PRINT ("Invalid hostname.\n");
363		retval = REGISTERES_ERROR;
364		break;
365
366	case 298:
367		PRINT ("Invalid domain name.\n");
368		retval = REGISTERES_ERROR;
369		break;
370
371	case 299:
372		PRINT ("Invalid IP format.\n");
373		retval = REGISTERES_ERROR;
374		break;
375
376	case 401:
377		PRINT ("authentication failure\n");
378		retval = REGISTERES_SHUTDOWN;
379		break;
380
381	case 407:
382		PRINT ("Proxy authentication Required.\n");
383		retval = REGISTERES_SHUTDOWN;
384		break;
385
386	default:
387		// reuse the auth buffer
388		*auth = '\0';
389		sscanf(buf, " HTTP/1.%*c %*3d %255[^\r\n]", auth);
390		if (ret >= 500)	{
391			retval = REGISTERES_SHUTDOWN;
392			nvram_set ("ddns_return_code","unknown_error");
393			nvram_set ("ddns_return_code_chk","unknown_error");
394		} else {
395			retval = REGISTERES_ERROR;
396			nvram_set ("ddns_return_code","Time-out");
397			nvram_set ("ddns_return_code_chk","Time-out");
398		}
399		retval = UPDATERES_SHUTDOWN;
400		break;
401	}
402
403	show_message("retval= %d, ddns_return_code (%s) ddns_suggest_name (%s) ddns_old_name (%s)", retval, nvram_safe_get ("ddns_return_code"), nvram_safe_get ("ddns_suggest_name"), nvram_safe_get ("ddns_old_name"));
404	return (retval);
405}
406
407
408int asus_update_entry(void)
409{
410	char buf[BUFFER_SIZE + 1];
411	char *p, *bp = buf;
412	char ret_buf[64];
413	char sug_name[MAX_DOMAIN_LEN], old_name[MAX_DOMAIN_LEN];
414	int bytes;
415	int btot;
416	int ret;
417	int retval = UPDATERES_OK;
418
419	buf[BUFFER_SIZE] = '\0';
420
421	if (do_connect((int *) &client_sockfd, server, port) != 0) {
422		show_message("error connecting to %s:%s\n", server, port);
423		nvram_set ("ddns_return_code", "connect_fail");
424		nvram_set ("ddns_return_code_chk", "connect_fail");
425		return (UPDATERES_ERROR);
426	}
427
428        char *ddns_transfer;
429        char old_mac[13];
430        memset(old_mac, 0, 13);
431        if(TransferMacAddr(nvram_safe_get("ddns_transfer"), old_mac)) {
432                snprintf(buf, BUFFER_SIZE, "GET /ddns/update.jsp?hostname=%s&myip=%s&oldmac=%s HTTP/1.0\015\012",
433                         host, address, old_mac);
434        }
435        else {
436                snprintf(buf, BUFFER_SIZE, "GET /ddns/update.jsp?hostname=%s&myip=%s HTTP/1.0\015\012", host, address);
437        }
438	output(buf);
439	snprintf(buf, BUFFER_SIZE, "Authorization: Basic %s\015\012", auth);
440	output(buf);
441	snprintf(buf, BUFFER_SIZE, "User-Agent: %s-%s %s [%s] (%s)\015\012", "ez-update", VERSION, OS, (options & OPT_DAEMON) ? "daemon" : "", "by Angus Mackay");
442	output(buf);
443	snprintf(buf, BUFFER_SIZE, "Host: %s\015\012", server);
444	output(buf);
445	snprintf(buf, BUFFER_SIZE, "\015\012");
446	output(buf);
447
448	bp = buf;
449	bytes = 0;
450	btot = 0;
451
452        while ((bytes = read_input(bp, BUFFER_SIZE - btot)) > 0) {
453                bp += bytes;
454                btot += bytes;
455        }
456        close(client_sockfd);
457        buf[btot] = '\0';
458        show_message("Asus update entry:: return: %s\n", buf);
459        if(btot) { // TODO: according to server response, parsing code have to rewrite
460                if (sscanf(buf, " HTTP/1.%*c %3d", &ret) != 1) {
461                        ret = -1;
462                }
463
464                // looking for 2-th '|'
465                p = strchr (buf, '|');
466                if (p != NULL)
467                        p = strchr (p+1, '|');
468                if (p == NULL)  {
469                        p = "";
470                }
471                snprintf (ret_buf, sizeof (ret_buf), "%s,%d", "", ret);
472        }
473
474	nvram_set ("ddns_return_code", ret_buf);
475	nvram_set ("ddns_return_code_chk", ret_buf);
476	switch (ret) {
477	case -1:
478		PRINT("strange server response, are you connecting to the right server?\n");
479		retval = UPDATERES_ERROR;
480		break;
481
482	case 200:
483		PRINT("Update IP successful\n");
484		break;
485
486        case 203:
487                PRINT ("Update failed. (203)\n");
488                memset (sug_name, 0, sizeof (sug_name));
489                sscanf (p, "|%[^|\r\n]c", sug_name);
490                nvram_set ("ddns_suggest_name", sug_name);
491
492                retval = REGISTERES_ERROR;
493                break;
494
495        case 230:
496                PRINT ("Update new domain success.\n");
497                memset (old_name, 0, sizeof (old_name));
498                sscanf (p, "|%[^|\r\n]c", old_name);
499                nvram_set ("ddns_old_name", old_name);
500                break;
501
502        case 233:
503                PRINT ("Update failed. (233)\n");
504                memset (old_name, 0, sizeof (old_name));
505                sscanf (p, "|%[^|\r\n]c", old_name);
506                nvram_set ("ddns_old_name", old_name);
507                retval = REGISTERES_ERROR;
508                break;
509
510	case 220:
511		PRINT("Update same domain success.\n");
512		break;
513
514	case 297:
515		PRINT("Invalid hostname\n");
516		retval = UPDATERES_ERROR;
517		break;
518
519	case 298:
520		PRINT("Invalid domain name\n");
521		retval = UPDATERES_ERROR;
522		break;
523
524	case 299:
525		PRINT("Invalid IP format\n");
526		retval = UPDATERES_ERROR;
527		break;
528
529	case 401:
530		PRINT("Authentication failure\n");
531		retval = UPDATERES_SHUTDOWN;
532		break;
533
534	case 407:
535		PRINT ("Proxy authentication Required.\n");
536		retval = UPDATERES_SHUTDOWN;
537		break;
538
539	default:
540		// reuse the auth buffer
541		*auth = '\0';
542		sscanf(buf, " HTTP/1.%*c %*3d %255[^\r\n]", auth);
543		if (ret >= 500)	{
544			retval = UPDATERES_SHUTDOWN;
545		} else {
546			retval = UPDATERES_ERROR;
547		}
548		retval = UPDATERES_SHUTDOWN;
549		break;
550	}
551
552	show_message("retval= %d, ddns_return_code (%s)", retval, nvram_safe_get ("ddns_return_code"));
553	return (retval);
554}
555
556
557static int
558alnum_cpy (unsigned char *d, unsigned char *s, unsigned int max_dlen)
559{
560	unsigned char *old_d, *max_d;
561
562	if (d == NULL || s == NULL || max_dlen == 0)
563		return 0;
564
565	old_d = d;
566	max_d = d + max_dlen;
567	while (*s != '\0' && d < max_d)	{
568		if (isalnum (*s))
569			*d++ = *s;
570		s++;
571	}
572
573	// out of range
574	if (d == max_d)	{
575		*(d-1) = '\0';
576	}
577
578	return (int) (d - old_d);
579}
580
581
582#ifdef DUMP_KEY
583static void dump (unsigned char *p, unsigned int l)
584{
585	unsigned int i;
586	if (p == NULL || l == 0)
587		return;
588
589	printf ("0x");
590	for (i = 0; i < l; ++i)
591		printf ("%02x", p[i]);
592	printf ("\n\n");
593}
594#endif	// DUMP_KEY
595
596
597static int
598wl_wscPincheck(char *pin_string)
599{
600    unsigned long PIN = strtoul(pin_string, NULL, 10 );;
601    unsigned long int accum = 0;
602
603    accum += 3 * ((PIN / 10000000) % 10);
604    accum += 1 * ((PIN / 1000000) % 10);
605    accum += 3 * ((PIN / 100000) % 10);
606    accum += 1 * ((PIN / 10000) % 10);
607    accum += 3 * ((PIN / 1000) % 10);
608    accum += 1 * ((PIN / 100) % 10);
609    accum += 3 * ((PIN / 10) % 10);
610    accum += 1 * ((PIN / 1) % 10);
611
612    if (0 == (accum % 10))
613	return 0;   // The PIN code is Vaild.
614    else
615	return 1;    // Invalid
616}
617
618
619// Generate password according to MAC address
620int asus_private(void)
621{
622#define MAX_SECRET_CODE_LEN	8
623	int i, l, c;
624	unsigned long secret;
625	unsigned char *p, user[256], hwaddr[6], hwaddr_str[18], key[64], msg[256], ipbuf[20], bin_pwd[16];
626
627	memset (hwaddr, 0, sizeof (hwaddr));
628	memset (key, 0, sizeof (key));
629	memset (msg, 0, sizeof (msg));
630	memset (user, 0, sizeof (user));
631	memset (bin_pwd, 0, sizeof (bin_pwd));
632#ifdef RTCONFIG_RGMII_BRCM5301X
633	p = nvram_get ("et1macaddr");
634#else
635	if (get_model() == MODEL_RTN56U)
636		p = nvram_get ("et1macaddr");
637	else
638	p = nvram_get ("et0macaddr");
639#endif
640#ifdef RTCONFIG_GMAC3
641	if(nvram_match("gmac3_enable", "1"))
642		p = nvram_safe_get ("et2macaddr");
643#endif
644	if (p == NULL)	{
645		PRINT ("ERROR: %s() can not take MAC address from et0macaddr\n");
646		return -1;
647	}
648	strncpy (hwaddr_str, p, sizeof (hwaddr_str));
649	p = hwaddr_str;
650	strtok (hwaddr_str, ":");
651	for (i = 0; i < 6; ++i)	{
652		if (p == NULL)	{
653			PRINT ("ERROR: %s() can not convert MAC address\n", __FUNCTION__);
654			return -1;
655		}
656		hwaddr[i] = strtoul (p, NULL, 16);
657		p = strtok (NULL, ":");
658	}
659	//DBG ("MAC %02X:%02X:%02X:%02X:%02X:%02X\n", hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
660
661	p = nvram_get ("secret_code");
662	if (p == NULL)	{
663		PRINT ("ERROR: secret_code not found.\n");
664		return -1;
665	}
666	strncpy (key, p, sizeof (key));
667	c = wl_wscPincheck (key);
668	//DBG ("secret code (%s) is %s\n", key, (c == 0)?"valid":"INVALID");
669	if (c)
670		PRINT ("WARNING: invalid secret code (%s)?\n", key);
671
672	DUMP (key);
673
674	// If address is invalid or ez-ipupdate is running as daemon, take IP address from interface.
675	if (address == NULL || *address == '\0' || options & OPT_DAEMON) {
676#ifdef IF_LOOKUP
677		struct sockaddr_in sin;
678		int sock;
679
680		if (interface == NULL)	{
681			PRINT ("ERROR: %s() invalid address and interface\n", __FUNCTION__);
682			return -1;
683		}
684
685		sock = socket(AF_INET, SOCK_STREAM, 0);
686		if (get_if_addr(sock, interface, &sin) != 0) {
687			PRINT ("ERROR: %s() get IP address of interface fail\n", __FUNCTION__);
688			return -1;
689		}
690		close(sock);
691		snprintf(ipbuf, sizeof(ipbuf), "%s", inet_ntoa(sin.sin_addr));
692		if (address)	{free(address);}
693		address = strdup (ipbuf);
694#else
695#error interface lookup not enabled at compile time.
696#endif
697	} else {
698		snprintf(ipbuf, sizeof(ipbuf), "%s", address);
699	}
700
701	// generate m
702	i = alnum_cpy (msg, host, sizeof (msg));
703	alnum_cpy (msg + i, ipbuf, sizeof (msg) - strlen (msg));
704	//DBG ("%s(): m is (%s) len %d\n", __FUNCTION__, msg, strlen (msg));
705
706	// generate password
707	hm(msg, strlen (msg), key, 64, bin_pwd);
708
709	//2007.03.19 Yau change snprintf -> sprintf
710	// This function is used to override "auth"
711	for (i = 0; i < 6; ++i)
712		//snprintf (user, sizeof (user), "%s%02X", user, hwaddr[i]);
713		sprintf (user, "%s%02X", user, hwaddr[i]);
714	//snprintf (user, sizeof (user), "%s:", user);
715	sprintf (user, "%s:", user);
716
717	for (i = 0; i < 16; ++i)
718		//snprintf (user, sizeof (user), "%s%02X", user, bin_pwd[i]);
719		sprintf (user, "%s%02X", user, bin_pwd[i]);
720
721	//DBG ("%s(): user and password (%s)\n", __FUNCTION__, user);
722	base64Encode(user, auth);
723	//PRINT("auth[] is overrode.\n");
724	//DBG("new auth[] is (%s)\n", auth);
725
726	return 0;
727}
728#endif	// TEST_HMAC_MD5
729