/* * netsniff-ng - the packet sniffing beast * Copyright 2011 Daniel Borkmann. * Subject to the GPL, version 2. */ #include #include #include #include #include #include #include #include #include #include "die.h" #include "locking.h" #include "xmalloc.h" #include "ioexact.h" #include "ioops.h" #include "str.h" #include "curvetun.h" #include "curve.h" #include "crypto.h" #include "curvetun_mgmt_users.h" #include "hash.h" struct user_store { char username[256]; unsigned char publickey[crypto_box_pub_key_size]; struct curve25519_proto proto_inf; struct user_store *next; }; struct sock_map_entry { int fd; struct curve25519_proto *proto; struct sock_map_entry *next; }; struct sockaddr_map_entry { struct sockaddr_storage *sa; size_t sa_len; struct curve25519_proto *proto; struct sockaddr_map_entry *next; }; static struct user_store *store = NULL; static struct rwlock store_lock; static struct hash_table sock_mapper; static struct rwlock sock_map_lock; static struct hash_table sockaddr_mapper; static struct rwlock sockaddr_map_lock; static unsigned char token[crypto_auth_hmacsha512256_KEYBYTES]; static void init_sock_mapper(void) { rwlock_init(&sock_map_lock); rwlock_wr_lock(&sock_map_lock); memset(&sock_mapper, 0, sizeof(sock_mapper)); init_hash(&sock_mapper); rwlock_unlock(&sock_map_lock); } static void init_sockaddr_mapper(void) { rwlock_init(&sockaddr_map_lock); rwlock_wr_lock(&sockaddr_map_lock); memset(&sockaddr_mapper, 0, sizeof(sockaddr_mapper)); init_hash(&sockaddr_mapper); rwlock_unlock(&sockaddr_map_lock); } static int cleanup_batch_sock_mapper(void *ptr) { struct sock_map_entry *next; struct sock_map_entry *e = ptr; if (!e) return 0; while ((next = e->next)) { e->next = NULL; xfree(e); e = next; } xfree(e); return 0; } static void destroy_sock_mapper(void) { rwlock_wr_lock(&sock_map_lock); for_each_hash(&sock_mapper, cleanup_batch_sock_mapper); free_hash(&sock_mapper); rwlock_unlock(&sock_map_lock); rwlock_destroy(&sock_map_lock); } static int cleanup_batch_sockaddr_mapper(void *ptr) { struct sockaddr_map_entry *next; struct sockaddr_map_entry *e = ptr; if (!e) return 0; while ((next = e->next)) { e->next = NULL; xfree(e); e = next; } xfree(e); return 0; } static void destroy_sockaddr_mapper(void) { rwlock_wr_lock(&sockaddr_map_lock); for_each_hash(&sockaddr_mapper, cleanup_batch_sockaddr_mapper); free_hash(&sockaddr_mapper); rwlock_unlock(&sockaddr_map_lock); rwlock_destroy(&sockaddr_map_lock); } static struct user_store *user_store_alloc(void) { return xzmalloc(sizeof(struct user_store)); } static void user_store_free(struct user_store *us) { if (!us) return; memset(us, 0, sizeof(struct user_store)); xfree(us); } /* already in lock */ static int __check_duplicate_username(char *username, size_t len) { int duplicate = 0; struct user_store *elem = store; while (elem) { if (!memcmp(elem->username, username, strlen(elem->username) + 1)) { duplicate = 1; break; } elem = elem->next; } return duplicate; } /* already in lock */ static int __check_duplicate_pubkey(unsigned char *pubkey, size_t len) { int duplicate = 0; struct user_store *elem = store; while (elem) { if (!memcmp(elem->publickey, pubkey, sizeof(elem->publickey))) { duplicate = 1; break; } elem = elem->next; } return duplicate; } enum parse_states { PARSE_USERNAME, PARSE_PUBKEY, PARSE_DONE, }; static int parse_line(char *line, char *homedir) { char *str; enum parse_states s = PARSE_USERNAME; struct user_store *elem; unsigned char pkey[crypto_box_pub_key_size]; elem = user_store_alloc(); elem->next = store; str = strtok(line, ";"); for (; str != NULL;) { switch (s) { case PARSE_USERNAME: if (__check_duplicate_username(str, strlen(str) + 1)) { user_store_free(elem); return -EINVAL; } strlcpy(elem->username, str, sizeof(elem->username)); s = PARSE_PUBKEY; break; case PARSE_PUBKEY: if (!curve25519_pubkey_hexparse_32(pkey, sizeof(pkey), str, strlen(str))) { user_store_free(elem); return -EINVAL; } if (__check_duplicate_pubkey(pkey, sizeof(pkey))) { user_store_free(elem); return -EINVAL; } memcpy(elem->publickey, pkey, sizeof(elem->publickey)); curve25519_proto_init(&elem->proto_inf, elem->publickey, sizeof(elem->publickey)); s = PARSE_DONE; break; case PARSE_DONE: break; default: user_store_free(elem); return -EIO; } str = strtok(NULL, ";"); } store = elem; return s == PARSE_DONE ? 0 : -EIO; } void parse_userfile_and_generate_user_store_or_die(char *homedir) { FILE *fp; char path[PATH_MAX], buff[512]; int line = 1, ret, fd; memset(path, 0, sizeof(path)); slprintf(path, sizeof(path), "%s/%s", homedir, FILE_CLIENTS); rwlock_init(&store_lock); rwlock_wr_lock(&store_lock); fp = fopen(path, "r"); if (!fp) panic("Cannot open client file!\n"); memset(buff, 0, sizeof(buff)); while (fgets(buff, sizeof(buff), fp) != NULL) { buff[sizeof(buff) - 1] = 0; /* A comment. Skip this line */ if (buff[0] == '#' || buff[0] == '\n') { memset(buff, 0, sizeof(buff)); line++; continue; } ret = parse_line(buff, homedir); if (ret < 0) panic("Cannot parse line %d from clients!\n", line); line++; memset(buff, 0, sizeof(buff)); } fclose(fp); if (store == NULL) panic("No registered clients found!\n"); rwlock_unlock(&store_lock); init_sock_mapper(); init_sockaddr_mapper(); /* * Pubkey is also used as a hmac of the initial packet to check * the integrity of the packet, so that we know if it's just random * garbage or a 'valid' packet. Again, just for the integrity! */ memset(path, 0, sizeof(path)); slprintf(path, sizeof(path), "%s/%s", homedir, FILE_PUBKEY); fd = open_or_die(path, O_RDONLY); ret = read(fd, token, sizeof(token)); if (ret != crypto_auth_hmacsha512256_KEYBYTES) panic("Cannot read public key!\n"); close(fd); } void dump_user_store(void) { int i; struct user_store *elem; rwlock_rd_lock(&store_lock); elem = store; while (elem) { printf("%s -> ", elem->username); for (i = 0; i < sizeof(elem->publickey); ++i) if (i == (sizeof(elem->publickey) - 1)) printf("%02x\n", (unsigned char) elem->publickey[i]); else printf("%02x:", (unsigned char) elem->publickey[i]); elem = elem->next; } rwlock_unlock(&store_lock); } void destroy_user_store(void) { struct user_store *elem, *nelem = NULL; rwlock_wr_lock(&store_lock); elem = store; while (elem) { nelem = elem->next; elem->next = NULL; user_store_free(elem); elem = nelem; } rwlock_unlock(&store_lock); rwlock_destroy(&store_lock); destroy_sock_mapper(); destroy_sockaddr_mapper(); } int username_msg(char *username, size_t len, char *dst, size_t dlen) { int fd; ssize_t ret; uint32_t salt; unsigned char h[crypto_hash_sha512_BYTES]; struct username_struct *us = (struct username_struct *) dst; char *uname; size_t uname_len; if (dlen < sizeof(struct username_struct)) return -ENOMEM; uname_len = 512; uname = xzmalloc(uname_len); fd = open_or_die("/dev/random", O_RDONLY); ret = read_exact(fd, &salt, sizeof(salt), 0); if (ret != sizeof(salt)) panic("Cannot read from /dev/random!\n"); close(fd); slprintf(uname, uname_len, "%s%u", username, salt); crypto_hash_sha512(h, (unsigned char *) uname, strlen(uname)); us->salt = htonl(salt); memcpy(us->hash, h, sizeof(us->hash)); xfree(uname); return 0; } enum is_user_enum username_msg_is_user(char *src, size_t slen, char *username, size_t len) { char *uname; size_t uname_len; uint32_t salt; struct username_struct *us = (struct username_struct *) src; unsigned char h[crypto_hash_sha512_BYTES]; if (slen < sizeof(struct username_struct)) { errno = ENOMEM; return USERNAMES_ERR; } uname_len = 512; uname = xzmalloc(uname_len); salt = ntohl(us->salt); slprintf(uname, uname_len, "%s%u", username, salt); crypto_hash_sha512(h, (unsigned char *) uname, strlen(uname)); xfree(uname); if (!crypto_verify_32(&h[0], &us->hash[0]) && !crypto_verify_32(&h[32], &us->hash[32])) return USERNAMES_OK; else return USERNAMES_NE; } static int register_user_by_socket(int fd, struct curve25519_proto *proto) { void **pos; struct sock_map_entry *entry; rwlock_wr_lock(&sock_map_lock); entry = xzmalloc(sizeof(*entry)); entry->fd = fd; entry->proto = proto; pos = insert_hash(entry->fd, entry, &sock_mapper); if (pos) { entry->next = (*pos); (*pos) = entry; } rwlock_unlock(&sock_map_lock); return 0; } static int register_user_by_sockaddr(struct sockaddr_storage *sa, size_t sa_len, struct curve25519_proto *proto) { void **pos; struct sockaddr_map_entry *entry; unsigned int hash = hash_name((char *) sa, sa_len); rwlock_wr_lock(&sockaddr_map_lock); entry = xzmalloc(sizeof(*entry)); entry->sa = xmemdupz(sa, sa_len); entry->sa_len = sa_len; entry->proto = proto; pos = insert_hash(hash, entry, &sockaddr_mapper); if (pos) { entry->next = (*pos); (*pos) = entry; } rwlock_unlock(&sockaddr_map_lock); return 0; } int try_register_user_by_socket(struct curve25519_struct *c, char *src, size_t slen, int sock, int log) { int ret = -1; char *cbuff = NULL; size_t real_len = 132; ssize_t clen; struct user_store *elem; enum is_user_enum err; unsigned char auth[crypto_auth_hmacsha512256_BYTES]; struct taia arrival_taia; /* assert(132 == clen + sizeof(auth)); */ /* * Check hmac first, if malicious, drop immediately before we * investigate more efforts. */ if (slen < real_len) return -1; taia_now(&arrival_taia); memcpy(auth, src, sizeof(auth)); src += sizeof(auth); real_len -= sizeof(auth); if (crypto_auth_hmacsha512256_verify(auth, (unsigned char *) src, real_len, token)) { syslog(LOG_ERR, "Bad packet hmac for id %d! Dropping!\n", sock); return -1; } else { if (log) syslog(LOG_INFO, "Good packet hmac for id %d!\n", sock); } rwlock_rd_lock(&store_lock); elem = store; while (elem) { clen = curve25519_decode(c, &elem->proto_inf, (unsigned char *) src, real_len, (unsigned char **) &cbuff, &arrival_taia); if (clen <= 0) { elem = elem->next; continue; } cbuff += crypto_box_zerobytes; clen -= crypto_box_zerobytes; if (log) syslog(LOG_INFO, "Packet decoded successfully for id %d!\n", sock); err = username_msg_is_user(cbuff, clen, elem->username, strlen(elem->username) + 1); if (err == USERNAMES_OK) { if (log) syslog(LOG_INFO, "Found user %s for id %d! Registering ...\n", elem->username, sock); ret = register_user_by_socket(sock, &elem->proto_inf); break; } elem = elem->next; } rwlock_unlock(&store_lock); if (ret == -1) syslog(LOG_ERR, "User not found! Dropping connection!\n"); return ret; } int try_register_user_by_sockaddr(struct curve25519_struct *c, char *src, size_t slen, struct sockaddr_storage *sa, size_t sa_len, int log) { int ret = -1; char *cbuff = NULL; struct user_store *elem; ssize_t clen; size_t real_len = 132; enum is_user_enum err; unsigned char auth[crypto_auth_hmacsha512256_BYTES]; struct taia arrival_taia; /* assert(132 == clen + sizeof(auth)); */ /* * Check hmac first, if malicious, drop immediately before we * investigate more efforts. */ if (slen < real_len) return -1; taia_now(&arrival_taia); memcpy(auth, src, sizeof(auth)); src += sizeof(auth); real_len -= sizeof(auth); if (crypto_auth_hmacsha512256_verify(auth, (unsigned char *) src, real_len, token)) { syslog(LOG_ERR, "Got bad packet hmac! Dropping!\n"); return -1; } else { if (log) syslog(LOG_INFO, "Got good packet hmac!\n"); } rwlock_rd_lock(&store_lock); elem = store; while (elem) { clen = curve25519_decode(c, &elem->proto_inf, (unsigned char *) src, real_len, (unsigned char **) &cbuff, &arrival_taia); if (clen <= 0) { elem = elem->next; continue; } cbuff += crypto_box_zerobytes; clen -= crypto_box_zerobytes; if (log) syslog(LOG_INFO, "Packet decoded successfully!\n"); err = username_msg_is_user(cbuff, clen, elem->username, strlen(elem->username) + 1); if (err == USERNAMES_OK) { if (log) syslog(LOG_INFO, "Found user %s! Registering ...\n", elem->username); ret = register_user_by_sockaddr(sa, sa_len, &elem->proto_inf); break; } elem = elem->next; } rwlock_unlock(&store_lock); if (ret == -1) syslog(LOG_ERR, "User not found! Dropping connection!\n"); return ret; } int get_user_by_socket(int fd, struct curve25519_proto **proto) { int ret = -1; struct sock_map_entry *entry; errno = 0; rwlock_rd_lock(&sock_map_lock); entry = lookup_hash(fd, &sock_mapper); while (entry && fd != entry->fd) entry = entry->next; if (entry && fd == entry->fd) { (*proto) = entry->proto; ret = 0; } else { (*proto) = NULL; errno = ENOENT; } rwlock_unlock(&sock_map_lock); return ret; } int get_user_by_sockaddr(struct sockaddr_storage *sa, size_t sa_len, struct curve25519_proto **proto) { int ret = -1; struct sockaddr_map_entry *entry; unsigned int hash = hash_name((char *) sa, sa_len); errno = 0; rwlock_rd_lock(&sockaddr_map_lock); entry = lookup_hash(hash, &sockaddr_mapper); while (entry && entry->sa_len == sa_len && memcmp(sa, entry->sa, entry->sa_len)) entry = entry->next; if (entry && entry->sa_len == sa_len && !memcmp(sa, entry->sa, entry->sa_len)) { (*proto) = entry->proto; ret = 0; } else { (*proto) = NULL; errno = ENOENT; } rwlock_unlock(&sockaddr_map_lock); return ret; } static struct sock_map_entry *socket_to_sock_map_entry(int fd) { struct sock_map_entry *entry, *ret = NULL; errno = 0; rwlock_rd_lock(&sock_map_lock); entry = lookup_hash(fd, &sock_mapper); while (entry && fd != entry->fd) entry = entry->next; if (entry && fd == entry->fd) ret = entry; else errno = ENOENT; rwlock_unlock(&sock_map_lock); return ret; } void remove_user_by_socket(int fd) { struct sock_map_entry *pos; struct sock_map_entry *entry = socket_to_sock_map_entry(fd); if (!entry) return; rwlock_wr_lock(&sock_map_lock); pos = remove_hash(entry->fd, entry, entry->next, &sock_mapper); while (pos && pos->next && pos->next != entry) pos = pos->next; if (pos && pos->next && pos->next == entry) pos->next = entry->next; memset(entry->proto->enonce, 0, sizeof(entry->proto->enonce)); memset(entry->proto->dnonce, 0, sizeof(entry->proto->dnonce)); entry->proto = NULL; entry->next = NULL; xfree(entry); rwlock_unlock(&sock_map_lock); } static struct sockaddr_map_entry * sockaddr_to_sockaddr_map_entry(struct sockaddr_storage *sa, size_t sa_len) { struct sockaddr_map_entry *entry, *ret = NULL; unsigned int hash = hash_name((char *) sa, sa_len); errno = 0; rwlock_rd_lock(&sockaddr_map_lock); entry = lookup_hash(hash, &sockaddr_mapper); while (entry && entry->sa_len == sa_len && memcmp(sa, entry->sa, entry->sa_len)) entry = entry->next; if (entry && entry->sa_len == sa_len && !memcmp(sa, entry->sa, entry->sa_len)) ret = entry; else errno = ENOENT; rwlock_unlock(&sockaddr_map_lock); return ret; } void remove_user_by_sockaddr(struct sockaddr_storage *sa, size_t sa_len) { struct sockaddr_map_entry *pos; struct sockaddr_map_entry *entry; unsigned int hash = hash_name((char *) sa, sa_len); entry = sockaddr_to_sockaddr_map_entry(sa, sa_len); if (!entry) return; rwlock_wr_lock(&sockaddr_map_lock); pos = remove_hash(hash, entry, entry->next, &sockaddr_mapper); while (pos && pos->next && pos->next != entry) pos = pos->next; if (pos && pos->next && pos->next == entry) pos->next = entry->next; memset(entry->proto->enonce, 0, sizeof(entry->proto->enonce)); memset(entry->proto->dnonce, 0, sizeof(entry->proto->dnonce)); entry->proto = NULL; entry->next = NULL; xfree(entry->sa); xfree(entry); rwlock_unlock(&sockaddr_map_lock); } exynos5260-clk.h14876logplain -rw-r--r--exynos5410.h1689logplain -rw-r--r--exynos5420.h6857logplain -rw-r--r--exynos5433.h45372logplain -rw-r--r--exynos5440.h1141logplain -rw-r--r--exynos7-clk.h5281logplain -rw-r--r--gxbb-aoclkc.h2866logplain -rw-r--r--gxbb-clkc.h592logplain -rw-r--r--hi3516cv300-clock.h1668logplain -rw-r--r--hi3519-clock.h1328logplain -rw-r--r--hi3620-clock.h4496logplain -rw-r--r--hi6220-clock.h4508logplain -rw-r--r--hip04-clock.h1137logplain -rw-r--r--histb-clock.h2012logplain -rw-r--r--hix5hd2-clock.h2415logplain -rw-r--r--imx1-clock.h1055logplain -rw-r--r--imx21-clock.h2461logplain -rw-r--r--imx27-clock.h3494logplain -rw-r--r--imx5-clock.h7212logplain -rw-r--r--imx6qdl-clock.h9593logplain -rw-r--r--imx6sl-clock.h5849logplain -rw-r--r--imx6sx-clock.h9099logplain -rw-r--r--imx6ul-clock.h8203logplain -rw-r--r--imx7d-clock.h15974logplain -rw-r--r--jz4740-cgu.h1028logplain -rw-r--r--jz4780-cgu.h2470logplain -rw-r--r--lpc18xx-ccu.h2134logplain -rw-r--r--lpc18xx-cgu.h1142logplain -rw-r--r--lpc32xx-clock.h1633logplain -rw-r--r--lsi,axm5516-clks.h974logplain -rw-r--r--marvell,mmp2.h2022logplain -rw-r--r--marvell,pxa168.h1654logplain -rw-r--r--marvell,pxa1928.h1535logplain -rw-r--r--marvell,pxa910.h1598logplain -rw-r--r--maxim,max77620.h632logplain -rw-r--r--maxim,max77686.h648logplain -rw-r--r--maxim,max77802.h630logplain -rw-r--r--meson8b-clkc.h523logplain -rw-r--r--microchip,pic32-clock.h1150logplain -rw-r--r--mpc512x-clock.h2236logplain -rw-r--r--mt2701-clk.h13832logplain -rw-r--r--mt8135-clk.h5641logplain -rw-r--r--mt8173-clk.h9293logplain -rw-r--r--oxsemi,ox810se.h1002logplain -rw-r--r--oxsemi,ox820.h1203logplain -rw-r--r--pistachio-clk.h4863logplain -rw-r--r--pxa-clock.h1715logplain -rw-r--r--qcom,gcc-apq8084.h12872logplain -rw-r--r--qcom,gcc-ipq4019.h5423logplain -rw-r--r--qcom,gcc-ipq806x.h8574logplain -rw-r--r--qcom,gcc-mdm9615.h9497logplain -rw-r--r--qcom,gcc-msm8660.h7932logplain -rw-r--r--qcom,gcc-msm8916.h6190logplain -rw-r--r--qcom,gcc-msm8960.h9342logplain -rw-r--r--qcom,gcc-msm8974.h12340logplain -rw-r--r--qcom,gcc-msm8994.h4858logplain -rw-r--r--qcom,gcc-msm8996.h12575logplain -rw-r--r--qcom,lcc-ipq806x.h899logplain -rw-r--r--qcom,lcc-mdm9615.h1701logplain -rw-r--r--qcom,lcc-msm8960.h1616logplain -rw-r--r--qcom,mmcc-apq8084.h5722logplain -rw-r--r--qcom,mmcc-msm8960.h4109logplain -rw-r--r--qcom,mmcc-msm8974.h5223logplain -rw-r--r--qcom,mmcc-msm8996.h9403logplain -rw-r--r--qcom,rpmcc.h2101logplain -rw-r--r--r7s72100-clock.h1218logplain -rw-r--r--r8a73a4-clock.h1596logplain -rw-r--r--r8a7740-clock.h1992logplain -rw-r--r--r8a7743-cpg-mssr.h1269logplain -rw-r--r--r8a7745-cpg-mssr.h1298logplain -rw-r--r--r8a7778-clock.h1855logplain -rw-r--r--r8a7779-clock.h1647logplain -rw-r--r--r8a7790-clock.h4367logplain -rw-r--r--r8a7791-clock.h4388logplain -rw-r--r--r8a7792-clock.h2562logplain -rw-r--r--r8a7793-clock.h4561logplain -rw-r--r--r8a7794-clock.h3679logplain -rw-r--r--r8a7795-cpg-mssr.h1890logplain -rw-r--r--r8a7796-cpg-mssr.h2066logplain -rw-r--r--renesas-cpg-mssr.h542logplain -rw-r--r--rk1108-cru.h6605logplain -rw-r--r--rk3036-cru.h4584logplain -rw-r--r--rk3066a-cru.h1068logplain -rw-r--r--rk3188-cru-common.h6105logplain -rw-r--r--rk3188-cru.h1435logplain