/* prepares a base64-encode challenge packet to be sent to the client * note: domain should be upper_case * note: the storage type for the returned value depends on * base64_encode_bin. Currently this means static storage. */ const char * ntlm_make_challenge(char *domain, char *domain_controller, char *challenge_nonce, int challenge_nonce_len) { ntlm_challenge ch; int pl = 0; const char *encoded; memset(&ch, 0, sizeof(ntlm_challenge)); /* reset */ memcpy(ch.signature, "NTLMSSP", 8); /* set the signature */ ch.type = WSWAP(NTLM_CHALLENGE); /* this is a challenge */ ntlm_add_to_payload(ch.payload, &pl, &ch.target, domain, strlen(domain), NTLM_CHALLENGE_HEADER_OFFSET); ch.flags = WSWAP( REQUEST_NON_NT_SESSION_KEY | CHALLENGE_TARGET_IS_DOMAIN | NEGOTIATE_ALWAYS_SIGN | NEGOTIATE_USE_NTLM | NEGOTIATE_USE_LM | NEGOTIATE_ASCII | 0 ); ch.context_low = 0; /* check this out */ ch.context_high = 0; memcpy(ch.challenge, challenge_nonce, challenge_nonce_len); encoded = base64_encode_bin((char *) &ch, NTLM_CHALLENGE_HEADER_OFFSET + pl); return encoded; }
void pciconf_1_writew(U32 pci_id, I32 reg_num, U16 val) { *GT_PCI_1_CONFIG_ADDR_REG = DWSWAP(pci_id | (reg_num & PCI_ADDR_REG_SZ)); if ( pci_id & PCI_ADDR_BUSDEV_M) *((U16 *)((GT_PCI_1_CONFIG_DATA + 2) - (reg_num & 0x2))) = val; else /* Galileo */ *((U16 *)(GT_PCI_1_CONFIG_DATA +(reg_num & 0x2))) = WSWAP(val); }
U16 pciconf_readw(U32 pci_id, I32 reg_num) { U16 val; *GT_PCI_CONFIG_ADDR_REG = DWSWAP(pci_id | (reg_num & PCI_ADDR_REG_SZ)); if ( pci_id & PCI_ADDR_BUSDEV_M) val = *((U16 *)((GT_PCI_CONFIG_DATA + 2) - (reg_num & 0x2))); else /* Galileo */ val = WSWAP(*((U16 *)(GT_PCI_CONFIG_DATA +(reg_num & 0x2)))); return(val); }
/* Adds something to the payload. The caller must guarrantee that * there is enough space in the payload string to accommodate the * added value. * payload_length and hdr will be modified as a side-effect. * base_offset is the payload offset from the packet's beginning, and is */ void ntlm_add_to_payload(char *payload, int *payload_length, strhdr * hdr, char *toadd, int toadd_length, int base_offset) { int l = (*payload_length); memcpy(payload + l, toadd, toadd_length); hdr->len = SSWAP(toadd_length); hdr->maxlen = SSWAP(toadd_length); hdr->offset = WSWAP(l + base_offset); /* 48 is the base offset of the payload */ (*payload_length) += toadd_length; }
/* fetches a string from the authentication packet. * The lstring data-part points to inside the packet itself. * It's up to the user to memcpy() that if the value needs to * be used in any way that requires a tailing \0. (he can check whether the * value is there though, in that case lstring.length==-1). */ lstring ntlm_fetch_string(char *packet, int32_t length, strhdr * str) { int16_t l; /* length */ int32_t o; /* offset */ lstring rv; lstring_zero(rv); l = SSWAP(str->len); o = WSWAP(str->offset); /* debug("fetch_string(plength=%d,l=%d,o=%d)\n",length,l,o); */ if (l < 0 || o <= 0 || l > MAX_FIELD_LENGTH || o + l > length) { /* debug("ntlmssp: insane data (l: %d, o: %d)\n", l,o); */ return rv; } rv.str = packet + o; rv.l = l; return rv; }
// ntlm auth header username extraction - also lets connection persist long enough to complete NTLM negotiation int ntlminstance::identify(Socket& peercon, Socket& proxycon, HTTPHeader &h, std::string &string) { FDTunnel fdt; Socket* upstreamcon; Socket ntlmcon; String url; if (transparent) { // we are actually sending to a second Squid, which just does NTLM ntlmcon.connect(transparent_ip, transparent_port); upstreamcon = &ntlmcon; url = h.getUrl(); h.makeTransparent(false); } else { upstreamcon = &proxycon; } String at(h.getAuthType()); if (transparent && (at != "NTLM")) { // obey forwarded-for options in what we send out std::string clientip; if (o.forwarded_for == 1) { if (o.use_xforwardedfor == 1) { // grab the X-Forwarded-For IP if available clientip = h.getXForwardedForIP(); // otherwise, grab the IP directly from the client connection if (clientip.length() == 0) clientip = peercon.getPeerIP(); } else { clientip = peercon.getPeerIP(); } h.addXForwardedFor(clientip); // add squid-like entry } // in transparent mode, we need to make the initial auth required response // appear to come from the smoothie itself as an origin server, not as a proxy. // // accomplish this by redirecting to a URL that results in accessing DG as if it was // a webserver, fudging origin-server-style NTLM auth to the client whilst actually // performing proper proxy-style auth to the parent proxy, then redirecting the client // back to the actual URL. if (!url.contains("sgtransntlmdest=")) { // user has not yet been redirected // get the browser to make a request to the proxy port on the relevant interface, // embedding the original URL they were trying to access. // unless they're accessing a domain for which authentication is not required, // in which case return a no match response straight away. if (no_auth_list >= 0) { #ifdef DGDEBUG std::cout << "NTLM: Checking noauthdomains list" << std::endl; #endif std::string::size_type start = url.find("://"); if (start != std::string::npos) { start += 3; std::string domain; domain = url.getHostname(); #ifdef DGDEBUG std::cout << "NTLM: URL " << url << ", domain " << domain << std::endl; #endif char *i; while ((start = domain.find('.')) != std::string::npos) { i = o.lm.l[no_auth_list]->findInList(domain.c_str()); if (i != NULL) { #ifdef DGDEBUG std::cout << "NTLM: Found domain in noauthdomains list" << std::endl; #endif return DGAUTH_NOMATCH; } domain.assign(domain.substr(start + 1)); } if (!domain.empty()) { domain = "." + domain; i = o.lm.l[no_auth_list]->findInList(domain.c_str()); if (i != NULL) { #ifdef DGDEBUG std::cout << "NTLM: Found domain in noauthdomains list" << std::endl; #endif return DGAUTH_NOMATCH; } } } } string = "http://"; string += hostname; string += ":"; string += String(peercon.getPort()).toCharArray(); string += "/?sgtransntlmdest="; string += url.toCharArray(); #ifdef DGDEBUG std::cout << "NTLM - redirecting client to " << string << std::endl; #endif return DGAUTH_REDIRECT; } #ifdef DGDEBUG std::cout << "NTLM - forging initial auth required from origin server" << std::endl; #endif // obey forwarded-for options in what we send out if (o.forwarded_for == 1) { std::string clientip; if (o.use_xforwardedfor == 1) { // grab the X-Forwarded-For IP if available clientip = h.getXForwardedForIP(); // otherwise, grab the IP directly from the client connection if (clientip.length() == 0) clientip = peercon.getPeerIP(); } else { clientip = peercon.getPeerIP(); } h.addXForwardedFor(clientip); // add squid-like entry } // send a variant on the original request (has to be something Squid will route to the outside // world, and that it will require NTLM authentication for) String domain(url.after("?sgtransntlmdest=").after("://")); if (domain.contains("/")) domain = domain.before("/"); domain = "http://" + domain + "/"; h.setURL(domain); h.makePersistent(); h.out(&peercon, upstreamcon, __DGHEADER_SENDALL); // grab the auth required response and make it look like it's from the origin server h.in(upstreamcon, true); h.makeTransparent(true); h.makePersistent(); // send it to the client h.out(NULL, &peercon, __DGHEADER_SENDALL); if (h.contentLength() != -1) fdt.tunnel(*upstreamcon, peercon, false, h.contentLength(), true); if (h.isPersistent()) { // now grab the client's response to the auth request, and carry on as usual. h.in(&peercon, true); h.makeTransparent(false); at = h.getAuthType(); } else return DGAUTH_NOMATCH; } else if (transparent && url.contains("?sgtransntlmdest=")) { // send a variant on the original request (has to be something Squid will route to the outside // world, and that it will require NTLM authentication for) String domain(url.after("?sgtransntlmdest=").after("://")); if (domain.contains("/")) domain = domain.before("/"); domain = "http://" + domain + "/"; h.setURL(domain); } if (at != "NTLM") { // if no auth currently underway, then... if (at.length() == 0) { // allow the initial request through so the client will get the proxy's initial auth required response. // advertise persistent connections so that parent proxy will agree to advertise NTLM support. #ifdef DGDEBUG std::cout << "No auth negotiation currently in progress - making initial request persistent so that proxy will advertise NTLM" << std::endl; #endif h.makePersistent(); } return DGAUTH_NOMATCH; } #ifdef DGDEBUG std::cout << "NTLM - sending step 1" << std::endl; #endif if (o.forwarded_for) { std::string clientip; if (o.use_xforwardedfor) { // grab the X-Forwarded-For IP if available clientip = h.getXForwardedForIP(); // otherwise, grab the IP directly from the client connection if (clientip.length() == 0) clientip = peercon.getPeerIP(); } else { clientip = peercon.getPeerIP(); } h.addXForwardedFor(clientip); // add squid-like entry } h.makePersistent(); h.out(&peercon, upstreamcon, __DGHEADER_SENDALL); #ifdef DGDEBUG std::cout << "NTLM - receiving step 2" << std::endl; #endif h.in(upstreamcon, true); if (h.authRequired()) { #ifdef DGDEBUG std::cout << "NTLM - sending step 2" << std::endl; #endif if (transparent) h.makeTransparent(true); h.out(NULL, &peercon, __DGHEADER_SENDALL); if (h.contentLength() != -1) fdt.tunnel(*upstreamcon, peercon, false, h.contentLength(), true); #ifdef DGDEBUG std::cout << "NTLM - receiving step 3" << std::endl; #endif h.in(&peercon, true); if (transparent) { h.makeTransparent(false); String domain(url.after("?sgtransntlmdest=").after("://")); if (domain.contains("/")) domain = domain.before("/"); domain = "http://" + domain + "/"; h.setURL(domain); } #ifdef DGDEBUG std::cout << "NTLM - decoding type 3 message" << std::endl; #endif std::string message(h.getAuthData()); ntlm_authenticate auth; ntlm_auth *a = &(auth.a); static char username[256]; // fixed size static char username2[256]; char* inptr = username; char* outptr = username2; size_t l,o; // copy the NTLM message into the union's buffer, simultaneously filling in the struct if ((message.length() > sizeof(ntlm_auth)) || (message.length() < offsetof(ntlm_auth, payload))) { syslog(LOG_ERR, "NTLM - Invalid message of length %zd, message was: %s", message.length(), message.c_str()); #ifdef DGDEBUG std::cerr << "NTLM - Invalid message of length " << message.length() << ", message was: " << message << std::endl; #endif return -3; } memcpy((void *)auth.buf, (const void *)message.c_str(), message.length()); // verify that the message is indeed a type 3 if (strcmp("NTLMSSP",a->h.signature) == 0 && WSWAP(a->h.type) == 3) { // grab the length & offset of the username within the message // cope with the possibility we are a different byte order to Windows l = SSWAP(a->user.len); o = WSWAP(a->user.offset); if ((l > 0) && (o >= 0) && (o + l) <= sizeof(a->payload) && (l <= 254)) { // everything is in range // note offsets are from start of packet - not the start of the payload area memcpy((void *)username, (const void *)&(auth.buf[o]),l); username[l] = '\0'; // check flags - we may need to convert from UTF-16 to something more sensible int f = WSWAP(a->flags); if (f & WSWAP(0x0001)) { iconv_t ic = iconv_open("UTF-8", "UTF-16LE"); if (ic == (iconv_t)-1) { syslog(LOG_ERR, "NTLM - Cannot initialise conversion from UTF-16LE to UTF-8: %s", strerror(errno)); #ifdef DGDEBUG std::cerr << "NTLM - Cannot initialise conversion from UTF-16LE to UTF-8: " << strerror(errno) << std::endl; #endif iconv_close(ic); return -2; } size_t l2 = 256; local_iconv_adaptor(iconv, ic, &inptr, &l, &outptr, &l2); iconv_close(ic); username2[256 - l2] = '\0'; #ifdef DGDEBUG std::cout << "NTLM - got username (converted from UTF-16LE) " << username2 << std::endl; #endif string = username2; } else { #ifdef DGDEBUG std::cout << "NTLM - got username " << username << std::endl; #endif string = username; } if (!transparent) return DGAUTH_OK; // if in transparent mode, send a redirect to the client's original requested URL, // having sent the final headers to the NTLM-only Squid to do with what it will std::string tmp = peercon.getPeerIP(); h.addXForwardedFor(tmp); h.out(&peercon, upstreamcon, __DGHEADER_SENDALL); // also, the return code matters in ways it hasn't mattered before: // mustn't send a redirect if it is still 407, or we get a redirection loop h.in(upstreamcon, true); if (h.returnCode() == 407) { h.makeTransparent(false); h.out(NULL, &peercon, __DGHEADER_SENDALL); return -10; } url = url.after("="); string = url.toCharArray(); return DGAUTH_REDIRECT; } } return DGAUTH_NOMATCH; } else { #ifdef DGDEBUG std::cout << "NTLM - step 2 was not part of an auth handshake!" << std::endl; for (unsigned int i = 0; i < h.header.size(); i++) std::cout << h.header[i] << std::endl; #endif syslog(LOG_ERR, "NTLM - step 2 was not part of an auth handshake! (%s)", h.header[0].toCharArray()); return -1; } }