// Cribbed from directConnectToSockAddr(). Could probably just call it // between SetSyscalls(), but I don't know that SO_KEEPALIVE doesn't matter. int open_tcp_stream( const condor_sockaddr & sa ) { int scm = SetSyscalls( SYS_LOCAL | SYS_UNMAPPED ); int fd = socket( sa.get_aftype(), SOCK_STREAM, 0 ); assert( fd != -1 ); int rv = _condor_local_bind( TRUE, fd ); if( rv != TRUE ) { close( fd ); SetSyscalls( scm ); return -1; } // condor_connect ends up pulling in param() via ip6_get_scope_id(), // which we can't allow, since this function is linked into standard // universe jobs. // rv = condor_connect( fd, sa ); rv = connect( fd, sa.to_sockaddr(), sa.get_socklen() ); if( rv != 0 ) { dprintf( D_ALWAYS, "condor_connect() failed - errno = %d (rv %d)\n", errno, rv ); close( fd ); SetSyscalls( scm ); return -1; } SetSyscalls( scm ); return fd; }
MyString get_hostname(const condor_sockaddr& addr) { MyString ret; if (nodns_enabled()) return convert_ipaddr_to_hostname(addr); condor_sockaddr targ_addr; // just like sin_to_string(), if given address is 0.0.0.0 or equivalent, // it changes to local IP address. if (addr.is_addr_any()) targ_addr = get_local_ipaddr(addr.get_protocol()); else targ_addr = addr; int e; char hostname[NI_MAXHOST]; // if given address is link-local IPv6 address, it will have %NICname // at the end of string // we would like to avoid it if (targ_addr.is_ipv6()) targ_addr.set_scope_id(0); e = condor_getnameinfo(targ_addr, hostname, sizeof(hostname), NULL, 0, 0); if (e) return ret; ret = hostname; return ret; }
condor_sockaddr get_local_ipaddr(condor_protocol proto) { init_local_hostname(); if ((proto == CP_IPV4) && local_ipv4addr.is_ipv4()) { return local_ipv4addr; } if ((proto == CP_IPV6) && local_ipv6addr.is_ipv6()) { return local_ipv6addr; } return local_ipaddr; }
bool condor_sockaddr::compare_address(const condor_sockaddr& addr) const { if (is_ipv4()) { if (!addr.is_ipv4()) return false; return v4.sin_addr.s_addr == addr.v4.sin_addr.s_addr; } else if (is_ipv6()) { if (!addr.is_ipv6()) return false; return memcmp((const void*)&v6.sin6_addr, (const void*)&addr.v6.sin6_addr, sizeof(in6_addr)) == 0; } return false; }
MyString convert_ipaddr_to_hostname(const condor_sockaddr& addr) { MyString ret; MyString default_domain; if (!param(default_domain, "DEFAULT_DOMAIN_NAME")) { dprintf(D_HOSTNAME, "NO_DNS: DEFAULT_DOMAIN_NAME must be defined in your " "top-level config file\n"); return ret; } ret = addr.to_ip_string(); for (int i = 0; i < ret.Length(); ++i) { if (ret[i] == '.' || ret[i] == ':') ret.setChar(i, '-'); } ret += "."; ret += default_domain; // Hostnames can't begin with -, as per RFC 1123 // ipv6 zero-compression could cause this, esp. for the loopback addr if (ret[0] == '-') { ret = "0" + ret; } return ret; }
std::vector<MyString> get_hostname_with_alias(const condor_sockaddr& addr) { std::vector<MyString> prelim_ret; std::vector<MyString> actual_ret; MyString hostname = get_hostname(addr); if (hostname.IsEmpty()) return prelim_ret; // we now start to construct a list (prelim_ret) of the hostname and all // the aliases. first the name itself. prelim_ret.push_back(hostname); if (nodns_enabled()) // don't need to verify this... the string is actually an IP here return prelim_ret; // no need to call further DNS functions. // now, add the aliases hostent* ent; //int aftype = addr.get_aftype(); //ent = gethostbyname2(hostname.Value(), addr.get_aftype()); // really should call gethostbyname2() however most platforms do not // support. (Solaris, HP-UX, IRIX) // complete DNS aliases can be only obtained by gethostbyname. // however, what happens if we call it in IPv6-only system? // can we get DNS aliases for the hostname that only contains // IPv6 addresses? ent = gethostbyname(hostname.Value()); if (ent) { char** alias = ent->h_aliases; for (; *alias; ++alias) { prelim_ret.push_back(MyString(*alias)); } } // WARNING! there is a reason this is implimented as two separate loops, // so please don't try to combine them. // // calling verify_name_has_ip() will potentially overwrite static data that // is referred to by ent->h_aliases (man 3 gethostbyname, see notes). so // first, we push the name and then all aliases into the MyString vector // prelim_ret, and then verify them in the following loop. for (unsigned int i = 0; i < prelim_ret.size(); i++) { if(verify_name_has_ip(prelim_ret[i], addr)) { actual_ret.push_back(prelim_ret[i]); } else { dprintf(D_ALWAYS, "WARNING: forward resolution of %s doesn't match %s!\n", prelim_ret[i].Value(), addr.to_ip_string().Value()); } } return actual_ret; }
bool verify_name_has_ip(MyString name, condor_sockaddr addr){ std::vector<condor_sockaddr> addrs; bool found = false; addrs = resolve_hostname(name); dprintf(D_FULLDEBUG, "IPVERIFY: checking %s against %s\n", name.Value(), addr.to_ip_string().Value()); for(unsigned int i = 0; i < addrs.size(); i++) { // compare MyStrings // addr.to_ip_string if(addrs[i].to_ip_string() == addr.to_ip_string()) { dprintf(D_FULLDEBUG, "IPVERIFY: matched %s to %s\n", addrs[i].to_ip_string().Value(), addr.to_ip_string().Value()); found = true; } else { dprintf(D_FULLDEBUG, "IPVERIFY: comparing %s to %s\n", addrs[i].to_ip_string().Value(), addr.to_ip_string().Value()); } } dprintf(D_FULLDEBUG, "IPVERIFY: ip found is %i\n", found); return found; }
static void replace_higher_scoring_addr(const char * reason, condor_sockaddr & current, int & current_score, const condor_sockaddr & potential, int potential_score) { const char * result = "skipped for low score"; if(current_score < potential_score) { current = potential; current_score = potential_score; result = "new winner"; } dprintf(D_HOSTNAME, "%s: %s (score %d) %s\n", reason, potential.to_ip_string().Value(), potential_score, result); }
bool init_local_hostname_impl() { bool local_hostname_initialized = false; if (param(local_hostname, "NETWORK_HOSTNAME")) { local_hostname_initialized = true; dprintf(D_HOSTNAME, "NETWORK_HOSTNAME says we are %s\n", local_hostname.Value()); } if( ! local_hostname_initialized ) { // [TODO:IPV6] condor_gethostname is not IPv6 safe. Reimplement it. char hostname[MAXHOSTNAMELEN]; int ret = condor_gethostname(hostname, sizeof(hostname)); if (ret) { dprintf(D_ALWAYS, "condor_gethostname() failed. Cannot initialize " "local hostname, ip address, FQDN.\n"); return false; } local_hostname = hostname; } MyString test_hostname = local_hostname; bool local_ipaddr_initialized = false; bool local_ipv4addr_initialized = false; bool local_ipv6addr_initialized = false; MyString network_interface; if (param(network_interface, "NETWORK_INTERFACE")) { if(local_ipaddr_initialized == false && local_ipaddr.from_ip_string(network_interface)) { local_ipaddr_initialized = true; if(local_ipaddr.is_ipv4()) { local_ipv4addr = local_ipaddr; local_ipv4addr_initialized = true; } if(local_ipaddr.is_ipv6()) { local_ipv6addr = local_ipaddr; local_ipv6addr_initialized = true; } } } if( ! local_ipaddr_initialized ) { std::string ipv4, ipv6, ipbest; if( network_interface_to_ip("NETWORK_INTERFACE", network_interface.Value(), ipv4, ipv6, ipbest, NULL)) { ASSERT(local_ipaddr.from_ip_string(ipbest)); // If this fails, network_interface_to_ip returns something invalid. local_ipaddr_initialized = true; } else { dprintf(D_ALWAYS, "Unable to identify IP address from interfaces. None match NETWORK_INTERFACE=%s. Problems are likely.\n", network_interface.Value()); } if((!ipv4.empty()) && local_ipv4addr.from_ip_string(ipv4)) { local_ipv4addr_initialized = true; ASSERT(local_ipv4addr.is_ipv4()); } if((!ipv6.empty()) && local_ipv6addr.from_ip_string(ipv6)) { local_ipv6addr_initialized = true; ASSERT(local_ipv6addr.is_ipv6()); } } bool local_fqdn_initialized = false; if (nodns_enabled()) { // condor_gethostname() returns a hostname with // DEFAULT_DOMAIN_NAME. Thus, it is always fqdn local_fqdn = local_hostname; local_fqdn_initialized = true; if (!local_ipaddr_initialized) { local_ipaddr = convert_hostname_to_ipaddr(local_hostname); local_ipaddr_initialized = true; } } addrinfo_iterator ai; if( ! nodns_enabled() ) { const int MAX_TRIES = 20; const int SLEEP_DUR = 3; bool gai_success = false; for(int try_count = 1; true; try_count++) { addrinfo hint = get_default_hint(); hint.ai_family = AF_UNSPEC; int ret = ipv6_getaddrinfo(test_hostname.Value(), NULL, ai, hint); if(ret == 0) { gai_success = true; break; } if(ret != EAI_AGAIN ) { dprintf(D_ALWAYS, "init_local_hostname_impl: ipv6_getaddrinfo() could not look up '%s': %s (%d). Error is not recoverable; giving up. Problems are likely.\n", test_hostname.Value(), gai_strerror(ret), ret ); gai_success = false; break; } dprintf(D_ALWAYS, "init_local_hostname_impl: ipv6_getaddrinfo() returned EAI_AGAIN for '%s'. Will try again after sleeping %d seconds (try %d of %d).\n", test_hostname.Value(), SLEEP_DUR, try_count + 1, MAX_TRIES ); if(try_count == MAX_TRIES) { dprintf(D_ALWAYS, "init_local_hostname_impl: ipv6_getaddrinfo() never succeeded. Giving up. Problems are likely\n"); break; } sleep(SLEEP_DUR); } if(gai_success) { int local_hostname_desireability = 0; #ifdef TEST_DNS_TODO int local_ipaddr_desireability = 0; int local_ipv4addr_desireability = 0; int local_ipv6addr_desireability = 0; #endif while (addrinfo* info = ai.next()) { // TODO: the only time ai_canonname should be set is the first // record. Why are we testing its desirability? const char* name = info->ai_canonname; if (!name) continue; condor_sockaddr addr(info->ai_addr); int desireability = addr.desirability(); const char * result = "skipped for low score"; if(desireability > local_hostname_desireability) { result = "new winner"; dprintf(D_HOSTNAME, " I like it.\n"); local_hostname_desireability = desireability; const char* dotpos = strchr(name, '.'); if (dotpos) { // consider it as a FQDN local_fqdn = name; local_hostname = local_fqdn.Substr(0, dotpos-name-1); } else { local_hostname = name; local_fqdn = local_hostname; MyString default_domain; if (param(default_domain, "DEFAULT_DOMAIN_NAME")) { if (default_domain[0] != '.') local_fqdn += "."; local_fqdn += default_domain; } } } dprintf(D_HOSTNAME, "hostname: %s (score %d) %s\n", name, desireability, result); #ifdef TEST_DNS_TODO // Resist urge to set local_ip*addr_initialized=true, // We want to repeatedly retest this looking for // better results. if (!local_ipaddr_initialized) { replace_higher_scoring_addr("IP", local_ipaddr, local_ipaddr_desireability, addr, desireability); } if (addr.is_ipv4() && !local_ipv4addr_initialized) { replace_higher_scoring_addr("IPv4", local_ipv4addr, local_ipv4addr_desireability, addr, desireability); } if (addr.is_ipv6() && !local_ipv6addr_initialized) { replace_higher_scoring_addr("IPv6", local_ipv6addr, local_ipv6addr_desireability, addr, desireability); } #else // Make Fedora quit complaining. if( local_ipv4addr_initialized && local_ipv6addr_initialized && local_fqdn_initialized ) { local_ipv4addr_initialized = false; local_ipv6addr_initialized = false; local_fqdn_initialized = false; } #endif } } } return true; }
void reset_local_hostname() { if( ! init_local_hostname_impl() ) { dprintf( D_ALWAYS, "Something went wrong identifying my hostname and IP address.\n" ); hostname_initialized = false; } else { dprintf( D_HOSTNAME, "I am: hostname: %s, fully qualified doman name: %s, IP: %s, IPv4: %s, IPv6: %s\n", local_hostname.Value(), local_fqdn.Value(), local_ipaddr.to_ip_string().Value(), local_ipv4addr.to_ip_string().Value(), local_ipv6addr.to_ip_string().Value() ); hostname_initialized = true; } }
/* * @returns: the number of bytes sent, if succeeds * -1, if fails */ int _condorOutMsg::sendMsg(const int sock, const condor_sockaddr& who, _condorMsgID msgID, unsigned char * mac) { _condorPacket* tempPkt; int seqNo = 0, msgLen = 0, sent; int total = 0; unsigned char * md = mac; //char str[10000]; if(headPacket->empty()) // empty message return 0; while(headPacket != lastPacket) { tempPkt = headPacket; headPacket = headPacket->next; tempPkt->makeHeader(false, seqNo++, msgID, md); msgLen += tempPkt->length; sent = condor_sendto(sock, tempPkt->dataGram, tempPkt->length + SAFE_MSG_HEADER_SIZE, 0, who); if(sent != tempPkt->length + SAFE_MSG_HEADER_SIZE) { dprintf(D_ALWAYS, "sendMsg:sendto failed - errno: %d\n", errno); headPacket = tempPkt; clearMsg(); return -1; } //int i; //str[0] = 0; //for (i=0; i<tempPkt->length + SAFE_MSG_HEADER_SIZE; i++) { // sprintf(&str[strlen(str)], "%02x,", tempPkt->dataGram[i]); //} //dprintf(D_NETWORK, "--->packet [%d bytes]: %s\n", sent, str); dprintf( D_NETWORK, "SEND [%d] %s ", sent, sock_to_string(sock) ); dprintf( D_NETWORK|D_NOHEADER, "%s\n", who.to_sinful().Value()); total += sent; delete tempPkt; md = 0; } // headPacket = lastPacket if(seqNo == 0) { // a short message msgLen = lastPacket->length; lastPacket->makeHeader(true, 0, msgID, md); // Short messages are sent without initial "magic" header, // because we don't need to specify sequence number, // and presumably for backwards compatibility with ancient // versions of Condor. The crypto header may still // be there, since that is in the buffer starting at // the position pointed to by "data". sent = condor_sendto(sock, lastPacket->data, lastPacket->length, 0, who); if(sent != lastPacket->length) { dprintf( D_ALWAYS, "SafeMsg: sending small msg failed. errno: %d\n", errno ); headPacket->reset(); return -1; } //str[0] = 0; //for (i=0; i<lastPacket->length + SAFE_MSG_HEADER_SIZE; i++) { // sprintf(&str[strlen(str)], "%02x,", lastPacket->dataGram[i]); //} //dprintf(D_NETWORK, "--->packet [%d bytes]: %s\n", sent, str); dprintf( D_NETWORK, "SEND [%d] %s ", sent, sock_to_string(sock) ); dprintf( D_NETWORK|D_NOHEADER, "%s\n", who.to_sinful().Value()); total = sent; } else { lastPacket->makeHeader(true, seqNo, msgID, md); msgLen += lastPacket->length; sent = condor_sendto(sock, lastPacket->dataGram, lastPacket->length + SAFE_MSG_HEADER_SIZE, 0, who); if(sent != lastPacket->length + SAFE_MSG_HEADER_SIZE) { dprintf( D_ALWAYS, "SafeMsg: sending last packet failed. errno: %d\n", errno ); headPacket->reset(); return -1; } //str[0] = 0; //for (i=0; i<lastPacket->length + SAFE_MSG_HEADER_SIZE; i++) { // sprintf(&str[strlen(str)], "%02x,", lastPacket->dataGram[i]); //} //dprintf(D_NETWORK, "--->packet [%d bytes]: %s\n", sent, str); dprintf( D_NETWORK, "SEND [%d] %s ", sent, sock_to_string(sock) ); dprintf( D_NETWORK|D_NOHEADER, "%s\n", who.to_sinful().Value()); total += sent; } headPacket->reset(); noMsgSent++; if(noMsgSent == 1) avgMsgSize = msgLen; else avgMsgSize = ((noMsgSent - 1) * avgMsgSize + msgLen) / noMsgSent; return total; }
void init_local_hostname() { // [m.] // initializing local hostname, ip address, fqdn was // super complex. // // implementation was scattered over condor_netdb and // my_hostname, get_full_hostname. // // above them has duplicated code in many ways. // so I aggregated all of them into here. bool ipaddr_inited = false; char hostname[MAXHOSTNAMELEN]; int ret; // [TODO:IPV6] condor_gethostname is not IPv6 safe. // reimplement it. ret = condor_gethostname(hostname, sizeof(hostname)); if (ret) { dprintf(D_ALWAYS, "condor_gethostname() failed. Cannot initialize " "local hostname, ip address, FQDN.\n"); return; } dprintf(D_HOSTNAME, "condor_gethostname() claims we are %s\n", hostname); // Fallback case. local_hostname = hostname; // if NETWORK_INTERFACE is defined, we use that as a local ip addr. MyString network_interface; if (param(network_interface, "NETWORK_INTERFACE", "*")) { if (local_ipaddr.from_ip_string(network_interface)) ipaddr_inited = true; } // Dig around for an IP address in the interfaces // TODO WARNING: Will only return IPv4 addresses! if( ! ipaddr_inited ) { std::string ip; if( ! network_interface_to_ip("NETWORK_INTERFACE", network_interface.Value(), ip, NULL)) { dprintf(D_ALWAYS, "Unable to identify IP address from interfaces. None matches NETWORK_INTERFACE=%s. Problems are likely.\n", network_interface.Value()); return; } if ( ! local_ipaddr.from_ip_string(ip)) { // Should not happen; means network_interface_to_ip returned // invalid IP address. ASSERT(FALSE); } ipaddr_inited = true; } // now initialize hostname and fqdn if (nodns_enabled()) { // if nodns is enabled, we can cut some slack. // condor_gethostname() returns a hostname with // DEFAULT_DOMAIN_NAME. Thus, it is always fqdn local_fqdn = hostname; if (!ipaddr_inited) { local_ipaddr = convert_hostname_to_ipaddr(local_hostname); } return; } addrinfo_iterator ai; ret = ipv6_getaddrinfo(hostname, NULL, ai); if (ret) { // write some error message dprintf(D_HOSTNAME, "hostname %s cannot be resolved by getaddrinfo\n", hostname); return; } int local_hostname_desireability = 0; while (addrinfo* info = ai.next()) { const char* name = info->ai_canonname; if (!name) continue; condor_sockaddr addr(info->ai_addr); int desireability = 0; if (addr.is_loopback()) { desireability = 1; } else if(addr.is_private_network()) { desireability = 2; } else { desireability = 3; } dprintf(D_HOSTNAME, "Considering %s (Ranked at %d) as possible local hostname versus %s/%s (%d)\n", name, desireability, local_hostname.Value(), local_fqdn.Value(), local_hostname_desireability); if(desireability < local_hostname_desireability) { continue; } local_hostname_desireability = desireability; if (!ipaddr_inited) local_ipaddr = addr; const char* dotpos = strchr(name, '.'); if (dotpos) { // consider it as a FQDN local_fqdn = name; local_hostname = local_fqdn.Substr(0, dotpos-name-1); } else { local_hostname = name; local_fqdn = local_hostname; MyString default_domain; if (param(default_domain, "DEFAULT_DOMAIN_NAME")) { if (default_domain[0] != '.') local_fqdn += "."; local_fqdn += default_domain; } } } dprintf(D_HOSTNAME, "Identifying myself as: Short:: %s, Long: %s, IP: %s\n", local_hostname.Value(), local_fqdn.Value(), local_ipaddr.to_ip_string().Value()); hostname_initialized = true; }
int IpVerify::Verify( DCpermission perm, const condor_sockaddr& addr, const char * user, MyString *allow_reason, MyString *deny_reason ) { perm_mask_t mask; in6_addr sin6_addr; const char *thehost; const char * who = user; MyString peer_description; // we build this up as we go along (DNS etc.) if( !did_init ) { Init(); } /* * Be Warned: careful about parameter "sin" being NULL. It could be, in * which case we should return FALSE (unless perm is ALLOW) * */ switch ( perm ) { case ALLOW: return USER_AUTH_SUCCESS; break; default: break; } sin6_addr = addr.to_ipv6_address(); mask = 0; // must initialize to zero because we logical-or bits into this if (who == NULL || *who == '\0') { who = TotallyWild; } if ( perm >= LAST_PERM || !PermTypeArray[perm] ) { EXCEPT("IpVerify::Verify: called with unknown permission %d\n",perm); } // see if a authorization hole has been dyamically punched (via // PunchHole) for this perm / user / IP // Note that the permission hierarchy is dealt with in // PunchHole(), by punching a hole for all implied levels. // Therefore, if there is a hole or an implied hole, we will // always find it here before we get into the subsequent code // which recursively calls Verify() to traverse the hierarchy. // This is important, because we do not want holes to find // there way into the authorization cache. // if ( PunchedHoleArray[perm] != NULL ) { HolePunchTable_t* hpt = PunchedHoleArray[perm]; MyString ip_str_buf = addr.to_ip_string(); const char* ip_str = ip_str_buf.Value(); MyString id_with_ip; MyString id; int count; if ( who != TotallyWild ) { id_with_ip.sprintf("%s/%s", who, ip_str); id = who; if ( hpt->lookup(id, count) != -1 ) { if( allow_reason ) { allow_reason->sprintf( "%s authorization has been made automatic for %s", PermString(perm), id.Value() ); } return USER_AUTH_SUCCESS; } if ( hpt->lookup(id_with_ip, count) != -1 ) { if( allow_reason ) { allow_reason->sprintf( "%s authorization has been made automatic for %s", PermString(perm), id_with_ip.Value() ); } return USER_AUTH_SUCCESS; } } id = ip_str; if ( hpt->lookup(id, count) != -1 ) { if( allow_reason ) { allow_reason->sprintf( "%s authorization has been made automatic for %s", PermString(perm), id.Value() ); } return USER_AUTH_SUCCESS; } } if ( PermTypeArray[perm]->behavior == USERVERIFY_ALLOW ) { // allow if no HOSTALLOW_* or HOSTDENY_* restrictions // specified. if( allow_reason ) { allow_reason->sprintf( "%s authorization policy allows access by anyone", PermString(perm)); } return USER_AUTH_SUCCESS; } if ( PermTypeArray[perm]->behavior == USERVERIFY_DENY ) { // deny if( deny_reason ) { deny_reason->sprintf( "%s authorization policy denies all access", PermString(perm)); } return USER_AUTH_FAILURE; } if( LookupCachedVerifyResult(perm,sin6_addr,who,mask) ) { if( deny_reason && (mask&deny_mask(perm)) ) { deny_reason->sprintf( "cached result for %s; see first case for the full reason", PermString(perm)); } else if( allow_reason && (mask&allow_mask(perm)) ) { allow_reason->sprintf( "cached result for %s; see first case for the full reason", PermString(perm)); } } else { mask = 0; // if the deny bit is already set, skip further DENY analysis perm_mask_t const deny_resolved = deny_mask(perm); // if the allow or deny bit is already set, // skip further ALLOW analysis perm_mask_t const allow_resolved = allow_mask(perm)|deny_mask(perm); // check for matching subnets in ip/mask style char ipstr[INET6_ADDRSTRLEN] = { 0, }; addr.to_ip_string(ipstr, INET6_ADDRSTRLEN); peer_description = addr.to_ip_string(); if ( !(mask&deny_resolved) && lookup_user_ip_deny(perm,who,ipstr)) { mask |= deny_mask(perm); if( deny_reason ) { deny_reason->sprintf( "%s authorization policy denies IP address %s", PermString(perm), addr.to_ip_string().Value() ); } } if ( !(mask&allow_resolved) && lookup_user_ip_allow(perm,who,ipstr)) { mask |= allow_mask(perm); if( allow_reason ) { allow_reason->sprintf( "%s authorization policy allows IP address %s", PermString(perm), addr.to_ip_string().Value() ); } } std::vector<MyString> hostnames; // now scan through hostname strings if( !(mask&allow_resolved) || !(mask&deny_resolved) ) { hostnames = get_hostname_with_alias(addr); } for (unsigned int i = 0; i < hostnames.size(); ++i) { thehost = hostnames[i].Value(); peer_description.append_to_list(thehost); if ( !(mask&deny_resolved) && lookup_user_host_deny(perm,who,thehost) ) { mask |= deny_mask(perm); if( deny_reason ) { deny_reason->sprintf( "%s authorization policy denies hostname %s", PermString(perm), thehost ); } } if ( !(mask&allow_resolved) && lookup_user_host_allow(perm,who,thehost) ) { mask |= allow_mask(perm); if( allow_reason ) { allow_reason->sprintf( "%s authorization policy allows hostname %s", PermString(perm), thehost ); } } } // if we found something via our hostname or subnet mactching, we now have // a mask, and we should add it into our table so we need not // do a gethostbyaddr() next time. if we still do not have a mask // (perhaps because this host doesn't appear in any list), create one // and then add to the table. // But first, check our parent permission levels in the // authorization heirarchy. // DAEMON and ADMINISTRATOR imply WRITE. // WRITE, NEGOTIATOR, and CONFIG_PERM imply READ. bool determined_by_parent = false; if ( mask == 0 ) { if ( PermTypeArray[perm]->behavior == USERVERIFY_ONLY_DENIES ) { dprintf(D_SECURITY,"IPVERIFY: %s at %s not matched to deny list, so allowing.\n",who, addr.to_sinful().Value()); if( allow_reason ) { allow_reason->sprintf( "%s authorization policy does not deny, so allowing", PermString(perm)); } mask |= allow_mask(perm); } else { DCpermissionHierarchy hierarchy( perm ); DCpermission const *parent_perms = hierarchy.getPermsIAmDirectlyImpliedBy(); bool parent_allowed = false; for( ; *parent_perms != LAST_PERM; parent_perms++ ) { if( Verify( *parent_perms, addr, user, allow_reason, NULL ) == USER_AUTH_SUCCESS ) { determined_by_parent = true; parent_allowed = true; dprintf(D_SECURITY,"IPVERIFY: allowing %s at %s for %s because %s is allowed\n",who, addr.to_sinful().Value(),PermString(perm),PermString(*parent_perms)); if( allow_reason ) { MyString tmp = *allow_reason; allow_reason->sprintf( "%s is implied by %s; %s", PermString(perm), PermString(*parent_perms), tmp.Value()); } break; } } if( parent_allowed ) { mask |= allow_mask(perm); } else { mask |= deny_mask(perm); if( !determined_by_parent && deny_reason ) { // We don't just allow anyone, and this request // did not match any of the entries we do allow. // In case the reason we didn't match is // because of a typo or a DNS problem, record // all the hostnames we searched for. deny_reason->sprintf( "%s authorization policy contains no matching " "ALLOW entry for this request" "; identifiers used for this host: %s, hostname size = %lu, " "original ip address = %s", PermString(perm), peer_description.Value(), (unsigned long)hostnames.size(), ipstr); } } } } if( !determined_by_parent && (mask&allow_mask(perm)) ) { // In case we are allowing because of not matching a DENY // entry that the user expected us to match (e.g. because // of typo or DNS problem), record all the hostnames we // searched for. if( allow_reason && !peer_description.IsEmpty() ) { allow_reason->sprintf_cat( "; identifiers used for this remote host: %s", peer_description.Value()); } } // finally, add the mask we computed into the table with this IP addr add_hash_entry(sin6_addr, who, mask); } // end of if find_match is FALSE // decode the mask and return True or False to the user. if ( mask & deny_mask(perm) ) { return USER_AUTH_FAILURE; } if ( mask & allow_mask(perm) ) { return USER_AUTH_SUCCESS; } return USER_AUTH_FAILURE; }