/* * Emergency Access Daemon * Copyright (C) 2008 Felix Fietkau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "list.h" #include "ead.h" #include "ead-pcap.h" #include "ead-crypt.h" #include "filter.c" #ifdef linux #include "libbridge_init.c" #endif #ifdef linux #include #endif #define PASSWD_FILE "/etc/passwd" #ifndef DEFAULT_IFNAME #define DEFAULT_IFNAME "eth0" #endif #ifndef DEFAULT_DEVNAME #define DEFAULT_DEVNAME "Unknown" #endif #define PCAP_MRU 1600 #define PCAP_TIMEOUT 200 #if EAD_DEBUGLEVEL >= 1 #define DEBUG(n, format, ...) do { \ if (EAD_DEBUGLEVEL >= n) \ fprintf(stderr, format, ##__VA_ARGS__); \ } while (0); #else #define DEBUG(n, format, ...) do {} while(0) #endif struct ead_instance { struct list_head list; char ifname[16]; int pid; char id; #ifdef linux char bridge[16]; bool br_check; #endif }; static char ethmac[6] = "\x00\x13\x37\x00\x00\x00"; /* last 3 bytes will be randomized */ static pcap_t *pcap_fp = NULL; static pcap_t *pcap_fp_rx = NULL; static char pktbuf_b[PCAP_MRU]; static struct ead_packet *pktbuf = (struct ead_packet *)pktbuf_b; static u16_t nid = 0xffff; /* node id */ static char username[32] = ""; static int state = EAD_TYPE_SET_USERNAME; static const char *passwd_file = PASSWD_FILE; static const char password[MAXPARAMLEN]; static bool child_pending = false; static unsigned char abuf[MAXPARAMLEN + 1]; static unsigned char pwbuf[MAXPARAMLEN]; static unsigned char saltbuf[MAXSALTLEN]; static unsigned char pw_saltbuf[MAXSALTLEN]; static struct list_head instances; static const char *dev_name = DEFAULT_DEVNAME; static bool nonfork = false; static struct ead_instance *instance = NULL; static struct t_pwent tpe = { .name = username, .index = 1, .password.data = pwbuf, .password.len = 0, .salt.data = saltbuf, .salt.len = 0, }; struct t_confent *tce = NULL; static struct t_server *ts = NULL; static struct t_num A, *B = NULL; unsigned char *skey; static void set_recv_type(pcap_t *p, bool rx) { #ifdef PACKET_RECV_TYPE struct sockaddr_ll sll; struct ifreq ifr; int ifindex, mask; int fd, ret; fd = pcap_get_selectable_fd(p); if (fd < 0) return; if (rx) mask = 1 << PACKET_BROADCAST; else mask = 0; ret = setsockopt(fd, SOL_PACKET, PACKET_RECV_TYPE, &mask, sizeof(mask)); #endif } static pcap_t * ead_open_pcap(const char *ifname, char *errbuf, bool rx) { pcap_t *p; p = pcap_create(ifname, errbuf); if (p == NULL) goto out; pcap_set_snaplen(p, PCAP_MRU); pcap_set_promisc(p, rx); pcap_set_timeout(p, PCAP_TIMEOUT); #ifdef HAS_PROTO_EXTENSION pcap_set_protocol(p, (rx ? htons(ETH_P_IP) : 0)); #endif pcap_set_buffer_size(p, (rx ? 10 : 1) * PCAP_MRU); pcap_activate(p); set_recv_type(p, rx); out: return p; } static void get_random_bytes(void *ptr, int len) { int fd; fd = open("/dev/urandom", O_RDONLY); if (fd < 0) { perror("open"); exit(1); } read(fd, ptr, len); close(fd); } static bool prepare_password(void) { static char lbuf[1024]; unsigned char dig[SHA_DIGESTSIZE]; BigInteger x, v, n, g; SHA1_CTX ctxt; int ulen = strlen(username); FILE *f; lbuf[sizeof(lbuf) - 1] = 0; f = fopen(passwd_file, "r"); if (!f) return false; while (fgets(lbuf, sizeof(lbuf) - 1, f) != NULL) { char *str, *s2; if (strncmp(lbuf, username, ulen) != 0) continue; if (lbuf[ulen] != ':') continue; str = &lbuf[ulen + 1]; if (strncmp(str, "$1$", 3) != 0) continue; s2 = strchr(str + 3, '$'); if (!s2) continue; if (s2 - str >= MAXSALTLEN) continue; strncpy((char *) pw_saltbuf, str, s2 - str); pw_saltbuf[s2 - str] = 0; s2 = strchr(s2, ':'); if (!s2) continue; *s2 = 0; if (s2 - str >= MAXPARAMLEN) continue; strncpy((char *)password, str, MAXPARAMLEN); fclose(f); goto hash_password; } /* not found */ fclose(f); return false; hash_password: tce = gettcid(tpe.index); do { t_random(tpe.password.data, SALTLEN); } while (memcmp(saltbuf, (char *)dig, sizeof(saltbuf)) == 0); if (saltbuf[0] == 0) saltbuf[0] = 0xff; n = BigIntegerFromBytes(tce->modulus.data, tce->modulus.len); g = BigIntegerFromBytes(tce->generator.data, tce->generator.len); v = BigIntegerFromInt(0); SHA1Init(&ctxt); SHA1Update(&ctxt, (unsigned char *) username, strlen(username)); SHA1Update(&ctxt, (unsigned char *) ":", 1); SHA1Update(&ctxt, (unsigned char *) password, strlen(password)); SHA1Final(dig, &ctxt); SHA1Init(&ctxt); SHA1Update(&ctxt, saltbuf, tpe.salt.len); SHA1Update(&ctxt, dig, sizeof(dig)); SHA1Final(dig, &ctxt); /* x = H(s, H(u, ':', p)) */ x = BigIntegerFromBytes(dig, sizeof(dig)); BigIntegerModExp(v, g, x, n); tpe.password.len = BigIntegerToBytes(v, (unsigned char *)pwbuf); BigIntegerFree(v); BigIntegerFree(x); BigIntegerFree(g); BigIntegerFree(n); return true; } static u16_t chksum(u16_t sum, const u8_t *data, u16_t len) { u16_t t; const u8_t *dataptr; const u8_t *last_byte; dataptr = data; last_byte = data + len - 1; while(dataptr < last_byte) { /* At least two more bytes */ t = (dataptr[0] << 8) + dataptr[1]; sum += t; if(sum < t) { sum++; /* carry */ } dataptr += 2; } if(dataptr == last_byte) { t = (dataptr[0] << 8) + 0; sum += t; if(sum < t) { sum++; /* carry */ } } /* Return sum in host byte order. */ return sum; } static void ead_send_packet_clone(struct ead_packet *pkt) { u16_t len, sum; memcpy(pktbuf, pkt, offsetof(struct ead_packet, msg)); memcpy(pktbuf->eh.ether_shost, ethmac, 6); memcpy(pktbuf->eh.ether_dhost, pkt->eh.ether_shost, 6); /* ip header */ len = sizeof(struct ead_packet) - sizeof(struct ether_header) + ntohl(pktbuf->msg.len); pktbuf->len[0] = len >> 8; pktbuf->len[1] = len & 0xff; memcpy(pktbuf->srcipaddr, &pkt->msg.ip, 4); memcpy(pktbuf->destipaddr, pkt->srcipaddr, 4); /* ip checksum */ pktbuf->ipchksum = 0; sum = chksum(0, (void *) &pktbuf->vhl, UIP_IPH_LEN); if (sum == 0) sum = 0xffff; pktbuf->ipchksum = htons(~sum); /* udp header */ pktbuf->srcport = pkt->destport; pktbuf->destport = pkt->srcport; /* udp checksum */ len -= UIP_IPH_LEN; pktbuf->udplen = htons(len); pktbuf->udpchksum = 0; sum = len + UIP_PROTO_UDP; sum = chksum(sum, (void *) &pktbuf->srcipaddr[0], 8); /* src, dest ip */ sum = chksum(sum, (void *) &pktbuf->srcport, len); if (sum == 0) sum = 0xffff; pktbuf->udpchksum = htons(~sum); pcap_sendpacket(pcap_fp, (void *) pktbuf, sizeof(struct ead_packet) + ntohl(pktbuf->msg.len)); } static void set_state(int nstate) { if (state == nstate) return; if (nstate < state) { if ((nstate < EAD_TYPE_GET_PRIME) && (state >= EAD_TYPE_GET_PRIME)) { t_serverclose(ts); ts = NULL; } goto done; } switch(state) { case EAD_TYPE_SET_USERNAME: if (!prepare_password()) goto error; ts = t_serveropenraw(&tpe, tce); if (!ts) goto error; break; case EAD_TYPE_GET_PRIME: B = t_servergenexp(ts); break; case EAD_TYPE_SEND_A: skey = t_servergetkey(ts, &A); if (!skey) goto error; ead_set_key(skey); break; } done: state = nstate; error: return; } static bool handle_ping(struct ead_packet *pkt, int len, int *nstate) { struct ead_msg *msg = &pktbuf->msg; struct ead_msg_pong *pong = EAD_DATA(msg, pong); int slen; slen = strlen(dev_name); if (
/dts-v1/;

/include/ "rt3883.dtsi"

/ {
	compatible = "DIR-645", "ralink,rt3883-soc";
	model = "D-Link DIR-645";

	palmbus@10000000 {
		gpio1: gpio@638 {
			status = "okay";
		};

		spi@b00 {
			status = "okay";

			m25p80@0 {
				#address-cells = <1>;
				#size-cells = <1>;
				compatible = "mx25l6405d";
				reg = <0 0>;
				linux,modalias = "m25p80";
				spi-max-frequency = <25000000>;
				partition@0 {
					label = "uboot";
					reg = <0x0 0x30000>;
					read-only;
				};
				partition@30000 {
					label = "uboot-env";
					reg = <0x30000 0x4000>;
					read-only;
				};
				factory: partition@34000 {
					label = "factory";
					reg = <0x34000 0x4000>;
					read-only;
				};
				partition@38000 {
					label = "nvram";
					reg = <0x38000 0x8000>;
					read-only;
				};
				partition@40000 {
					label = "devdata";
					reg = <0x40000 0x10000>;
				};
				partition@50000 {
					label = "firmware";
					reg = <0x50000 0x7b0000>;
				};
			};
		};
	};

	pinctrl {
		state_default: pinctrl0 {
			gpio {
				ralink,group = "i2c", "jtag", "uartf";
				ralink,function = "gpio";
			};
		};
	};

	ethernet@10100000 {
		mtd-mac-address = <&factory 0x28>;
		port@0 {
			ralink,fixed-link = <1000 1 1 0>;
		};
	};

	wmac@10180000 {
		ralink,5ghz = <0>;
	};

	ehci@101c0000 {
		status = "okay";
	};

	ohci@101c1000 {
		status = "okay";
	};

	rtl8367b {
		compatible = "realtek,rtl8367b";
		gpio-sda = <&gpio0 1 0>;
		gpio-sck = <&gpio0 2 0>;
		realtek,extif1 = <1 0 1 1 1 1 1 1 2>;
	};

	gpio-keys-polled {
		compatible = "gpio-keys-polled";
		#address-cells = <1>;
		#size-cells = <0>;
		poll-interval = <100>;
		reset {
			label = "reset";
			gpios = <&gpio0 9 0>;
			linux,code = <0x198>;
		};
		wps {
			label = "wps";
			gpios = <&gpio0 14 0>;
			linux,code = <0x211>;
		};
	};

	gpio-leds {
		compatible = "gpio-leds";

		inet {
			label = "d-link:green:inet";
			gpios = <&gpio0 0 1>;
		};
		wps {
			label = "d-link:green:wps";
			gpios = <&gpio1 2 0>;
		};
	};

	gpio_export {
		compatible = "gpio-export";
		#size-cells = <0>;
		usb {
			gpio-export,name = "usb";
			gpio-export,output = <1>;
			gpios = <&gpio1 6 0>;
		};
	};
};