/**
 * QUERY.
 *
 */
static query_state
query_process_query(query_type* q, ldns_rr_type qtype, engine_type* engine)
{
    dnsout_type* dnsout = NULL;
    if (!q || !q->zone) {
        return QUERY_DISCARDED;
    }
    ods_log_assert(q->zone->name);
    ods_log_debug("[%s] incoming query qtype=%s for zone %s", query_str,
        rrset_type2str(qtype), q->zone->name);
    /* sanity checks */
    if (buffer_pkt_qdcount(q->buffer) != 1 || buffer_pkt_tc(q->buffer)) {
        buffer_pkt_set_flags(q->buffer, 0);
        return query_formerr(q);
    }
    if (buffer_pkt_ancount(q->buffer) != 0 ||
        (qtype != LDNS_RR_TYPE_IXFR && buffer_pkt_nscount(q->buffer) != 0)) {
        buffer_pkt_set_flags(q->buffer, 0);
        return query_formerr(q);
    }
    /* acl */
    if (!q->zone->adoutbound || q->zone->adoutbound->type != ADAPTER_DNS) {
        ods_log_error("[%s] zone %s is not configured to have output dns "
            "adapter", query_str, q->zone->name);
        return query_refused(q);
    }
    ods_log_assert(q->zone->adoutbound->config);
    dnsout = (dnsout_type*) q->zone->adoutbound->config;
    /* acl also in use for soa and other queries */
    if (!acl_find(dnsout->provide_xfr, &q->addr, q->tsig_rr)) {
        return query_refused(q);
    }
    /* ixfr? */
    if (qtype == LDNS_RR_TYPE_IXFR) {
        if (query_process_ixfr(q) != QUERY_PROCESSED) {
            buffer_pkt_set_flags(q->buffer, 0);
            return query_formerr(q);
        }
        query_prepare(q);
        ods_log_assert(q->zone->name);
        ods_log_debug("[%s] incoming ixfr request serial=%u for zone %s",
            query_str, q->serial, q->zone->name);
        return ixfr(q, engine);
    }

    query_prepare(q);
    /* axfr? */
    if (qtype == LDNS_RR_TYPE_AXFR) {
        ods_log_assert(q->zone->name);
        ods_log_debug("[%s] incoming axfr request for zone %s",
            query_str, q->zone->name);
        return axfr(q, engine);
    }
    /* (soa) query */
    return query_response(q, qtype);
}
static security_context_t
config_context (pam_handle_t *pamh, security_context_t defaultcon, int use_current_range, int debug)
{
  security_context_t newcon=NULL;
  context_t new_context;
  int mls_enabled = is_selinux_mls_enabled();
  char *response=NULL;
  char *type=NULL;
  char resp_val = 0;

  pam_prompt (pamh, PAM_TEXT_INFO, NULL, _("Default Security Context %s\n"), defaultcon);

  while (1) {
    if (query_response(pamh,
		   _("Would you like to enter a different role or level?"), "n", 
		   &response, debug) == PAM_SUCCESS) {
	resp_val = response[0];
	_pam_drop(response);
    } else {
	resp_val = 'N';
    }
    if ((resp_val == 'y') || (resp_val == 'Y'))
      {
        if ((new_context = context_new(defaultcon)) == NULL)
    	    goto fail_set;

	/* Allow the user to enter role and level individually */
	if (query_response(pamh, _("role:"), context_role_get(new_context), 
		       &response, debug) == PAM_SUCCESS && response[0]) {
	  if (get_default_type(response, &type)) {
	    pam_prompt (pamh, PAM_ERROR_MSG, NULL, _("No default type for role %s\n"), response);
	    _pam_drop(response);
	    continue;
	  } else {
	    if (context_role_set(new_context, response)) 
	      goto fail_set;
	    if (context_type_set (new_context, type))
	      goto fail_set;
	  } 
	}
	_pam_drop(response);

	if (mls_enabled)
	  {
	    if (use_current_range) {
	        security_context_t mycon = NULL;
	        context_t my_context;

		if (getcon(&mycon) != 0)
		    goto fail_set;
    		my_context = context_new(mycon);
	        if (my_context == NULL) {
    		    freecon(mycon);
		    goto fail_set;
		}
		freecon(mycon);
		if (context_range_set(new_context, context_range_get(my_context))) {
		    context_free(my_context);
		    goto fail_set;
		}
		context_free(my_context);
	    } else if (query_response(pamh, _("level:"), context_range_get(new_context), 
			   &response, debug) == PAM_SUCCESS && response[0]) {
		if (context_range_set(new_context, response))
		    goto fail_set;
	    } 
	    _pam_drop(response);
	  }

	if (debug)
	  pam_syslog(pamh, LOG_NOTICE, "Selected Security Context %s", context_str(new_context));

        /* Get the string value of the context and see if it is valid. */
        if (!security_check_context(context_str(new_context))) {
	  newcon = strdup(context_str(new_context));
	  if (newcon == NULL)
	    goto fail_set;
	  context_free(new_context);

          /* we have to check that this user is allowed to go into the
             range they have specified ... role is tied to an seuser, so that'll
             be checked at setexeccon time */
          if (mls_enabled && !mls_range_allowed(pamh, defaultcon, newcon, debug)) {
	    pam_syslog(pamh, LOG_NOTICE, "Security context %s is not allowed for %s", defaultcon, newcon);

    	    send_audit_message(pamh, 0, defaultcon, newcon);

	    free(newcon);
            goto fail_range;
	  }
	  return newcon;
	}
	else {
	  send_audit_message(pamh, 0, defaultcon, context_str(new_context));
	  send_text(pamh,_("Not a valid security context"),debug);
	}
        context_free(new_context); /* next time around allocates another */
      }
    else
      return strdup(defaultcon);
  } /* end while */

  return NULL;

 fail_set:
  free(type);
  _pam_drop(response);
  context_free (new_context);
  send_audit_message(pamh, 0, defaultcon, NULL);
 fail_range:
  return NULL;  
}
static security_context_t
manual_context (pam_handle_t *pamh, const char *user, int debug)
{
  security_context_t newcon=NULL;
  context_t new_context;
  int mls_enabled = is_selinux_mls_enabled();
  char *type=NULL;
  char *response=NULL;

  while (1) {
    if (query_response(pamh,
		   _("Would you like to enter a security context? [N] "), NULL,
		   &response, debug) != PAM_SUCCESS)
	return NULL;

    if ((response[0] == 'y') || (response[0] == 'Y'))
      {
	if (mls_enabled)
	  new_context = context_new ("user:role:type:level");
	else
	  new_context = context_new ("user:role:type");

	if (!new_context)
              goto fail_set;

	if (context_user_set (new_context, user))
              goto fail_set;

	_pam_drop(response);
	/* Allow the user to enter each field of the context individually */
	if (query_response(pamh, _("role:"), NULL, &response, debug) == PAM_SUCCESS &&
	    response[0] != '\0') {
	   if (context_role_set (new_context, response)) 
              goto fail_set;
	   if (get_default_type(response, &type)) 
              goto fail_set;
	   if (context_type_set (new_context, type)) 
              goto fail_set;
	}
	_pam_drop(response);

	if (mls_enabled)
	  {
	    if (query_response(pamh, _("level:"), NULL, &response, debug) == PAM_SUCCESS &&
		response[0] != '\0') {
	      if (context_range_set (new_context, response))
		goto fail_set;
	    }
	    _pam_drop(response);
	  }

	/* Get the string value of the context and see if it is valid. */
	if (!security_check_context(context_str(new_context))) {
	  newcon = strdup(context_str(new_context));
	  context_free (new_context);
	  return newcon;
	}
	else
	  send_text(pamh,_("Not a valid security context"),debug);

        context_free (new_context);
      }
    else {
      _pam_drop(response);
      return NULL;
    }
  } /* end while */
 fail_set:
  free(type);
  _pam_drop(response);
  context_free (new_context);
  return NULL;
}