Example #1
0
void
IpVerify::PrintAuthTable(int dprintf_level) {
	struct in6_addr host;
	UserPerm_t * ptable;
	PermHashTable->startIterations();

	while (PermHashTable->iterate(host, ptable)) {
		MyString userid;
		perm_mask_t mask;

		ptable->startIterations();
		while( ptable->iterate(userid,mask) ) {
				// Call has_user() to get the full mask
			has_user(ptable, userid.Value(), mask);

			MyString auth_entry_str;
			AuthEntryToString(host,userid.Value(),mask, auth_entry_str);
			dprintf(dprintf_level,"%s\n", auth_entry_str.Value());
		}
	}

	dprintf(dprintf_level,"Authorizations yet to be resolved:\n");
	DCpermission perm;
	for ( perm=FIRST_PERM; perm < LAST_PERM; perm=NEXT_PERM(perm) ) {

		PermTypeEntry* pentry = PermTypeArray[perm];
		ASSERT( pentry );

		MyString allow_users,deny_users;

		if( pentry->allow_users ) {
			UserHashToString(pentry->allow_users,allow_users);
		}

		if( pentry->deny_users ) {
			UserHashToString(pentry->deny_users,deny_users);
		}

		if( allow_users.Length() ) {
			dprintf(dprintf_level,"allow %s: %s\n",
					PermString(perm),
					allow_users.Value());
		}

		if( deny_users.Length() ) {
			dprintf(dprintf_level,"deny %s: %s\n",
					PermString(perm),
					deny_users.Value());
		}
	}
}
Example #2
0
// FillHole - plug up a dynamically punched authorization hole
//
bool
IpVerify::FillHole(DCpermission perm, MyString& id)
{
	HolePunchTable_t* table = PunchedHoleArray[perm];
	if (table == NULL) {
		return false;
	}

	int count;
	if (table->lookup(id, count) == -1) {
		return false;
	}
	if (table->remove(id) == -1) {
		EXCEPT("IpVerify::FillHole: table entry removal error");
	}

	count--;

	if (count != 0) {
		if (table->insert(id, count) == -1) {
			EXCEPT("IpVerify::FillHole: "
			           "table entry insertion error");
		}
	}

	if (count == 0) {
		dprintf(D_SECURITY,
		        "IpVerify::FillHole: "
		            "removed %s-level opening for %s\n",
		        PermString(perm),
		        id.Value());
	}
	else {
		dprintf(D_SECURITY,
		        "IpVerify::FillHole: "
		            "open count at level %s for %s now %d\n",
		        PermString(perm),
		        id.Value(),
		        count);
	}

	DCpermissionHierarchy hierarchy( perm );
	DCpermission const *implied_perms=hierarchy.getImpliedPerms();
	for(; implied_perms[0] != LAST_PERM; implied_perms++ ) {
		if( perm != implied_perms[0] ) {
			FillHole(implied_perms[0],id);
		}
	}

	return true;
}
Example #3
0
void
IpVerify::PermMaskToString(perm_mask_t mask, MyString &mask_str)
{
	DCpermission perm;
	for(perm=FIRST_PERM; perm<LAST_PERM; perm=NEXT_PERM(perm)) {
		if( mask & allow_mask(perm) ) {
			mask_str.append_to_list(PermString(perm));
		}
		if( mask & deny_mask(perm) ) {
			mask_str.append_to_list("DENY_");
			mask_str += PermString(perm);
		}
	}
}
Example #4
0
// PunchHole - dynamically opens up a perm level to the
// given user / IP. The hole can be removed with FillHole.
// Additions persist across a reconfig.  This is intended
// for transient permissions (like to automatic permission
// granted to a remote startd host when a shadow starts up.)
//
bool
IpVerify::PunchHole(DCpermission perm, MyString& id)
{
	int count = 0;
	if (PunchedHoleArray[perm] == NULL) {
		PunchedHoleArray[perm] =
			new HolePunchTable_t(compute_host_hash);
		ASSERT(PunchedHoleArray[perm] != NULL);
	}
	else {
		int c;
		if (PunchedHoleArray[perm]->lookup(id, c) != -1) {
			count = c;
			if (PunchedHoleArray[perm]->remove(id) == -1) {
				EXCEPT("IpVerify::PunchHole: "
				           "table entry removal error");
			}
		}
	}

	count++;
	if (PunchedHoleArray[perm]->insert(id, count) == -1) {
		EXCEPT("IpVerify::PunchHole: table entry insertion error");
	}

	if (count == 1) {
		dprintf(D_SECURITY,
		        "IpVerify::PunchHole: opened %s level to %s\n",
		        PermString(perm),
		        id.Value());
	}
	else {
		dprintf(D_SECURITY,
		        "IpVerify::PunchHole: "
			    "open count at level %s for %s now %d\n",
		        PermString(perm),
		        id.Value(),
		        count);
	}

	DCpermissionHierarchy hierarchy( perm );
	DCpermission const *implied_perms=hierarchy.getImpliedPerms();
	for(; implied_perms[0] != LAST_PERM; implied_perms++ ) {
		if( perm != implied_perms[0] ) {
			PunchHole(implied_perms[0],id);
		}
	}

	return true;
}
Example #5
0
DCpermission
StringToDCpermission(char const *str) {
	DCpermission perm;

	for(perm = FIRST_PERM;perm!=LAST_PERM;perm=NEXT_PERM(perm)) {
		if(str && !strcasecmp(str,PermString(perm)) ) {
			return perm;
		}
	}
	return LAST_PERM;
}
Example #6
0
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;
}
Example #7
0
int
IpVerify::Init()
{
	char *pAllow = NULL, *pDeny = NULL, *pOldAllow = NULL, *pOldDeny = NULL,
		*pNewAllow = NULL, *pNewDeny = NULL;
	DCpermission perm;
	const char* const ssysname = get_mySubSystem()->getName();	

	did_init = TRUE;

	// Make sure that perm_mask_t is big enough to hold all possible
	// results of allow_mask() and deny_mask().
	ASSERT( sizeof(perm_mask_t)*8 - 2 > LAST_PERM );

	// Clear the Permission Hash Table in case re-initializing
	if (PermHashTable) {
		// iterate through the table and delete the entries
		struct in6_addr key;
		UserPerm_t * value;
		PermHashTable->startIterations();

		while (PermHashTable->iterate(key, value)) {
			delete value;
		}

		PermHashTable->clear();
	}

	// and Clear the Permission Type Array
	for (perm=FIRST_PERM; perm<LAST_PERM; perm=NEXT_PERM(perm)) {
		if ( PermTypeArray[perm] ) {
			delete PermTypeArray[perm];
			PermTypeArray[perm] = NULL;
		}
	}

	// This is the new stuff
	for ( perm=FIRST_PERM; perm < LAST_PERM; perm=NEXT_PERM(perm) ) {
		PermTypeEntry* pentry = new PermTypeEntry();
		ASSERT( pentry );
		PermTypeArray[perm] = pentry;
		MyString allow_param, deny_param;

		dprintf(D_SECURITY,"IPVERIFY: Subsystem %s\n",ssysname);
		dprintf(D_SECURITY,"IPVERIFY: Permission %s\n",PermString(perm));
		if(strcmp(ssysname,"TOOL")==0 || strcmp(ssysname,"SUBMIT")==0){
			// to avoid unneccesary DNS activity, the TOOL and SUBMIT
			// subsystems only load the CLIENT lists, since they have no
			// command port and don't need the other authorization lists.
			if(strcmp(PermString(perm),"CLIENT")==0){ 
				pNewAllow = SecMan::getSecSetting("ALLOW_%s",perm,&allow_param, ssysname );
				pOldAllow = SecMan::getSecSetting("HOSTALLOW_%s",perm,&allow_param, ssysname );
				pNewDeny = SecMan::getSecSetting("DENY_%s",perm,&deny_param, ssysname );
				pOldDeny = SecMan::getSecSetting("HOSTDENY_%s",perm,&deny_param, ssysname );
			}
		} else {
			pNewAllow = SecMan::getSecSetting("ALLOW_%s",perm,&allow_param, ssysname );
			pOldAllow = SecMan::getSecSetting("HOSTALLOW_%s",perm,&allow_param, ssysname );
			pNewDeny = SecMan::getSecSetting("DENY_%s",perm,&deny_param, ssysname );
			pOldDeny = SecMan::getSecSetting("HOSTDENY_%s",perm,&deny_param, ssysname );
		}
		// concat the two
		pAllow = merge(pNewAllow, pOldAllow);
		// concat the two
		pDeny = merge(pNewDeny, pOldDeny);
		if( pAllow ) {
			dprintf ( D_SECURITY, "IPVERIFY: allow %s: %s (from config value %s)\n", PermString(perm),pAllow,allow_param.Value());
		}
		if( pDeny ) {
			dprintf ( D_SECURITY, "IPVERIFY: deny %s: %s (from config value %s)\n", PermString(perm),pDeny,deny_param.Value());
		}
		// Treat a "*", "*/*" for ALLOW_XXX as if it's just undefined,
		// because that's the optimized default, except for
		// CONFIG_PERM which has a different default (see below).
		if( perm != CONFIG_PERM ) {
			if(pAllow && (!strcmp(pAllow, "*") || !strcmp(pAllow, "*/*"))) {
				free( pAllow );
				pAllow = NULL;
			}
		}
		if ( !pAllow && !pDeny ) {
			if (perm == CONFIG_PERM) { 	  // deny all CONFIG requests 
				pentry->behavior = USERVERIFY_DENY; // by default
				dprintf( D_SECURITY, "ipverify: %s optimized to deny everyone\n", PermString(perm) );
			} else {
				pentry->behavior = USERVERIFY_ALLOW;
				if( perm != ALLOW ) {
					dprintf( D_SECURITY, "ipverify: %s optimized to allow anyone\n", PermString(perm) );
				}
			}
		} else {
			if ( pDeny && !pAllow && perm != CONFIG_PERM ) {
				pentry->behavior = USERVERIFY_ONLY_DENIES;
			} else {
				pentry->behavior = USERVERIFY_USE_TABLE;
			}
			if ( pAllow ) {
				fill_table( pentry, pAllow, true );
				free(pAllow);
				pAllow = NULL;
			}
			if ( pDeny ) {
				fill_table( pentry,	pDeny, false );
				free(pDeny);
				pDeny = NULL;
			}
		}
		if (pAllow) {
			free(pAllow);
			pAllow = NULL;
		}
		if (pDeny) {
			free(pDeny);
			pDeny = NULL;
		}
		if (pOldAllow) {
			free(pOldAllow);
			pOldAllow = NULL;
		}
		if (pOldDeny) {
			free(pOldDeny);
			pOldDeny = NULL;
		}
		if (pNewAllow) {
			free(pNewAllow);
			pNewAllow = NULL;
		}
		if (pNewDeny) {
			free(pNewDeny);
			pNewDeny = NULL;
		}
	}
	dprintf(D_FULLDEBUG|D_SECURITY,"Initialized the following authorization table:\n");
	if(PermHashTable)	
		PrintAuthTable(D_FULLDEBUG|D_SECURITY);
	return TRUE;
}