Esempio n. 1
0
static krb5_error_code armor_ap_request
(struct kdc_request_state *state, krb5_fast_armor *armor)
{
    krb5_error_code retval = 0;
    krb5_auth_context authcontext = NULL;
    krb5_ticket *ticket = NULL;
    krb5_keyblock *subkey = NULL;
    kdc_realm_t *kdc_active_realm = state->realm_data;

    assert(armor->armor_type == KRB5_FAST_ARMOR_AP_REQUEST);
    krb5_clear_error_message(kdc_context);
    retval = krb5_auth_con_init(kdc_context, &authcontext);
    if (retval == 0)
        retval = krb5_auth_con_setflags(kdc_context,
                                        authcontext, 0); /*disable replay cache*/
    retval = krb5_rd_req(kdc_context, &authcontext,
                         &armor->armor_value, NULL /*server*/,
                         kdc_active_realm->realm_keytab,  NULL, &ticket);
    if (retval != 0) {
        const char * errmsg = krb5_get_error_message(kdc_context, retval);
        krb5_set_error_message(kdc_context, retval,
                               _("%s while handling ap-request armor"),
                               errmsg);
        krb5_free_error_message(kdc_context, errmsg);
    }
    if (retval == 0) {
        if (!krb5_principal_compare_any_realm(kdc_context,
                                              tgs_server,
                                              ticket->server)) {
            krb5_set_error_message(kdc_context, KRB5KDC_ERR_SERVER_NOMATCH,
                                   _("ap-request armor for something other "
                                     "than the local TGS"));
            retval = KRB5KDC_ERR_SERVER_NOMATCH;
        }
    }
    if (retval == 0) {
        retval = krb5_auth_con_getrecvsubkey(kdc_context, authcontext, &subkey);
        if (retval != 0 || subkey == NULL) {
            krb5_set_error_message(kdc_context, KRB5KDC_ERR_POLICY,
                                   _("ap-request armor without subkey"));
            retval = KRB5KDC_ERR_POLICY;
        }
    }
    if (retval == 0)
        retval = krb5_c_fx_cf2_simple(kdc_context,
                                      subkey, "subkeyarmor",
                                      ticket->enc_part2->session, "ticketarmor",
                                      &state->armor_key);
    if (ticket)
        krb5_free_ticket(kdc_context, ticket);
    if (subkey)
        krb5_free_keyblock(kdc_context, subkey);
    if (authcontext)
        krb5_auth_con_free(kdc_context, authcontext);
    return retval;
}
Esempio n. 2
0
//----------------------------------------------------------------------
// Initialze some general structures for kerberos
//----------------------------------------------------------------------
int Condor_Auth_Kerberos :: init_kerberos_context()
{
    krb5_error_code code = 0;
    krb5_address  ** localAddr  = NULL;
    krb5_address  ** remoteAddr = NULL;

    // kerberos context_
    if (krb_context_ == NULL) {
        if ((code = krb5_init_context(&krb_context_))) {
            goto error;
        }
    }

    if ((code = krb5_auth_con_init(krb_context_, &auth_context_))) {
        goto error;
    }

    if ((code = krb5_auth_con_setflags(krb_context_, 
                                      auth_context_, 
                                      KRB5_AUTH_CONTEXT_DO_SEQUENCE))) {
        goto error;
    }
        
    if ((code = krb5_auth_con_genaddrs(krb_context_, 
                                      auth_context_, 
                                      mySock_->get_file_desc(),
                                      KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|
                                      KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR
                                      ))) {
        goto error;
    }

    if ((code = krb5_auth_con_getaddrs(krb_context_, 
                                      auth_context_,
                                      localAddr, 
                                      remoteAddr))) {
        goto error;
    }

    // stash location
    defaultStash_ = param(STR_CONDOR_CACHE_DIR);

    if (defaultStash_ == NULL) {
        defaultStash_ = strdup(STR_DEFAULT_CONDOR_SPOOL);
    }
    
    return TRUE;
 error:
    dprintf( D_ALWAYS, "Unable to initialize kerberos: %s\n",
			 error_message(code) );
    return FALSE;
}
Esempio n. 3
0
static void
kerberos_authenticate(krb5_context context, krb5_auth_context *auth_context,
                      int fd, krb5_principal me, krb5_creds **new_creds)
{
    krb5_error_code retval;
    krb5_error *error = NULL;
    krb5_ap_rep_enc_part *rep_result;

    retval = krb5_auth_con_init(context, auth_context);
    if (retval)
        exit(1);

    krb5_auth_con_setflags(context, *auth_context,
                           KRB5_AUTH_CONTEXT_DO_SEQUENCE);

    retval = krb5_auth_con_setaddrs(context, *auth_context, sender_addr,
                                    receiver_addr);
    if (retval) {
        com_err(progname, retval, _("in krb5_auth_con_setaddrs"));
        exit(1);
    }

    retval = krb5_sendauth(context, auth_context, &fd, kprop_version,
                           me, creds.server, AP_OPTS_MUTUAL_REQUIRED, NULL,
                           &creds, NULL, &error, &rep_result, new_creds);
    if (retval) {
        com_err(progname, retval, _("while authenticating to server"));
        if (error != NULL) {
            if (error->error == KRB_ERR_GENERIC) {
                if (error->text.data) {
                    fprintf(stderr, _("Generic remote error: %s\n"),
                            error->text.data);
                }
            } else if (error->error) {
                com_err(progname,
                        (krb5_error_code)error->error + ERROR_TABLE_BASE_krb5,
                        _("signalled from server"));
                if (error->text.data) {
                    fprintf(stderr, _("Error text from server: %s\n"),
                            error->text.data);
                }
            }
            krb5_free_error(context, error);
        }
        exit(1);
    }
    krb5_free_ap_rep_enc_part(context, rep_result);
}
Esempio n. 4
0
static int krb5_build_auth_context(rlm_krb5_t *inst,
				   krb5_context context,
				   krb5_auth_context *auth_context)
{
	int ret;
	krb5_int32 flags;
	
	ret = krb5_auth_con_init(context, auth_context);
	if (ret)
		return ret;
	
	ret = krb5_auth_con_getflags(context, *auth_context, &flags);
	if (ret)
		return ret;
		
	if (!inst->cache && (flags & KRB5_AUTH_CONTEXT_DO_TIME)) {
		ret = krb5_auth_con_setflags(context, *auth_context, flags & ~KRB5_AUTH_CONTEXT_DO_TIME);

		if (ret)
			return ret;
	}
	
	return 0;
}
Esempio n. 5
0
static int 
k5_auth_send(kstream ks, int how)
{
  krb5_error_code r;
  krb5_ccache ccache;
  krb5_creds creds;
  krb5_creds * new_creds;
  extern krb5_flags krb5_kdc_default_options;
  krb5_flags ap_opts;
  char type_check[2];
  krb5_data check_data;
  int len;
#ifdef ENCRYPTION
  krb5_keyblock *newkey = 0;
#endif

  if (r = krb5_cc_default(k5_context, &ccache)) {
    com_err(NULL, r, "while authorizing.");
    return(0);
  }

  memset((char *)&creds, 0, sizeof(creds));
  if (r = krb5_sname_to_principal(k5_context, szHostName, KRB_SERVICE_NAME,
				  KRB5_NT_SRV_HST, &creds.server)) {
    com_err(NULL, r, "while authorizing.");
    return(0);
  }

  if (r = krb5_cc_get_principal(k5_context, ccache, &creds.client)) {
    com_err(NULL, r, "while authorizing.");
    krb5_free_cred_contents(k5_context, &creds);
    return(0);
  }
  if (szUserName[0] == '\0') {                /* Get user name now */
    len  = krb5_princ_component(k5_context, creds.client, 0)->length;
    memcpy(szUserName,
	   krb5_princ_component(k5_context, creds.client, 0)->data,
	   len);
    szUserName[len] = '\0';
  }

  if (r = krb5_get_credentials(k5_context, 0,
			       ccache, &creds, &new_creds)) {
    com_err(NULL, r, "while authorizing.");
    krb5_free_cred_contents(k5_context, &creds);
    return(0);
  }

  ap_opts = 0;
  if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
    ap_opts = AP_OPTS_MUTUAL_REQUIRED;

#ifdef ENCRYPTION
  ap_opts |= AP_OPTS_USE_SUBKEY;
#endif

  if (auth_context) {
    krb5_auth_con_free(k5_context, auth_context);
    auth_context = 0;
  }
  if ((r = krb5_auth_con_init(k5_context, &auth_context))) {
    com_err(NULL, r, "while initializing auth context");
    return(0);
  }

  krb5_auth_con_setflags(k5_context, auth_context,
			 KRB5_AUTH_CONTEXT_RET_TIME);

  type_check[0] = AUTHTYPE_KERBEROS_V5;
  type_check[1] = AUTH_WHO_CLIENT| (how & AUTH_HOW_MASK);
#ifdef ENCRYPTION
  type_check[1] |= AUTH_ENCRYPT_ON;
#endif
  check_data.magic = KV5M_DATA;
  check_data.length = 2;
  check_data.data = (char *)&type_check;

  r = krb5_mk_req_extended(k5_context, &auth_context, ap_opts,
			   NULL, new_creds, &auth);
  
#ifdef ENCRYPTION
  krb5_auth_con_getlocalsubkey(k5_context, auth_context, &newkey);
  if (session_key) {
    krb5_free_keyblock(k5_context, session_key);
    session_key = 0;
  }
  
  if (newkey) {
    /*
     * keep the key in our private storage, but don't use it
     * yet---see kerberos5_reply() below
     */
    if ((newkey->enctype != ENCTYPE_DES_CBC_CRC) &&
	(newkey-> enctype != ENCTYPE_DES_CBC_MD5)) {
      if ((new_creds->keyblock.enctype == ENCTYPE_DES_CBC_CRC) ||
	  (new_creds->keyblock.enctype == ENCTYPE_DES_CBC_MD5))
	/* use the session key in credentials instead */
	krb5_copy_keyblock(k5_context, &new_creds->keyblock, &session_key);
      else
	; 	/* What goes here? XXX */
    } else {
      krb5_copy_keyblock(k5_context, newkey, &session_key);
    }
    krb5_free_keyblock(k5_context, newkey);
  }
#endif  /* ENCRYPTION */

  krb5_free_cred_contents(k5_context, &creds);
  krb5_free_creds(k5_context, new_creds);
  
  if (r) {
    com_err(NULL, r, "while authorizing.");
    return(0);
  }

  return(1);
}
Esempio n. 6
0
static krb5_error_code
change_password_loop(krb5_context	context,
                     struct request *request,
                     int		*result_code,
                     krb5_data		*result_code_string,
                     krb5_data		*result_string,
                     struct kpwd_proc	*proc)
{
    krb5_error_code ret;
    krb5_data zero, zero2;
    krb5_sendto_ctx ctx = NULL;
    krb5_realm realm;

    krb5_data_zero(&zero);
    krb5_data_zero(&zero2);

    if (request->target)
        realm = request->target->realm;
    else
        realm = request->creds->client->realm;

    _krb5_debugx(context, 1, "trying to set password using: %s in realm %s",
                 proc->name, realm);

    ret = krb5_auth_con_init(context, &request->ac);
    if (ret)
        goto out;

    krb5_auth_con_setflags(context, request->ac, KRB5_AUTH_CONTEXT_DO_SEQUENCE);

    ret = krb5_sendto_ctx_alloc(context, &ctx);
    if (ret)
        goto out;

    krb5_sendto_ctx_set_type(ctx, KRB5_KRBHST_CHANGEPW);

    /* XXX this is a evil hack */
    if (request->creds->ticket.length > 700) {
        _krb5_debugx(context, 1, "using TCP since the ticket is large: %lu",
                     (unsigned long)request->creds->ticket.length);
        krb5_sendto_ctx_add_flags(ctx, KRB5_KRBHST_FLAGS_LARGE_MSG);
    }

    _krb5_sendto_ctx_set_prexmit(ctx, proc->prexmit, request);

    ret = krb5_sendto_context(context, ctx, &zero, realm, &zero2);

    if (ret == 0)
        ret = proc->process_rep(context, request->ac, &zero2,
                                result_code, result_code_string, result_string);

out:
    _krb5_debugx(context, 1, "set password using %s returned: %d result_code %d",
                 proc->name, ret, *result_code);

    krb5_auth_con_free(context, request->ac);
    if (ctx)
        krb5_sendto_ctx_free(context, ctx);

    krb5_data_free(&zero2);

    if (ret == KRB5_KDC_UNREACH) {
        krb5_set_error_message(context,
                               ret,
                               N_("Unable to reach any changepw server "
                                  " in realm %s", "realm"), realm);
        *result_code = KRB5_KPASSWD_HARDERROR;
    }
    return ret;
}
Esempio n. 7
0
int
kerberos5_send (TN_Authenticator * ap)
{
  krb5_error_code r;
  krb5_ccache ccache;
  krb5_creds creds;
  krb5_creds *new_creds = 0;
  int ap_opts;
  char type_check[2];
  krb5_data check_data;

  if (!UserNameRequested)
    {
      DEBUG (("telnet: Kerberos V5: no user name supplied\r\n"));
      return 0;
    }

  if ((r = krb5_cc_default (telnet_context, &ccache)))
    {
      DEBUG (("telnet: Kerberos V5: could not get default ccache\r\n"));
      return 0;
    }

  memset (&creds, 0, sizeof (creds));
  if ((r = krb5_sname_to_principal (telnet_context, RemoteHostName,
				    "host", KRB5_NT_SRV_HST, &creds.server)))
    {
      DEBUG (("telnet: Kerberos V5: error while constructing service name: %s\r\n", error_message (r)));
      return 0;
    }

  if (telnet_krb5_realm)
    {
      krb5_data rdata;

      rdata.length = strlen (telnet_krb5_realm);
      rdata.data = malloc (rdata.length + 1);
      assert (rdata.data);
      strcpy (rdata.data, telnet_krb5_realm);
      krb5_princ_set_realm (telnet_context, creds.server, &rdata);
    }

  if ((r = krb5_cc_get_principal (telnet_context, ccache, &creds.client)))
    {
      DEBUG (("telnet: Kerberos V5: failure on principal (%s)\r\n",
	      error_message (r)));
      krb5_free_cred_contents (telnet_context, &creds);
      return 0;
    }

  creds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
  if ((r = krb5_get_credentials (telnet_context, 0,
				 ccache, &creds, &new_creds)))
    {
      DEBUG (("telnet: Kerberos V5: failure on credentials(%s)\r\n",
	      error_message (r)));
      krb5_free_cred_contents (telnet_context, &creds);
      return 0;
    }

  if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
    ap_opts = AP_OPTS_MUTUAL_REQUIRED;
  else
    ap_opts = 0;

# ifdef ENCRYPTION
  ap_opts |= AP_OPTS_USE_SUBKEY;
# endif

  if (auth_context)
    {
      krb5_auth_con_free (telnet_context, auth_context);
      auth_context = 0;
    }

  if ((r = krb5_auth_con_init (telnet_context, &auth_context)))
    {
      DEBUG (("Kerberos V5: failed to init auth_context (%s)\r\n",
	      error_message (r)));
      return 0;
    }

  krb5_auth_con_setflags (telnet_context, auth_context,
			  KRB5_AUTH_CONTEXT_RET_TIME);

  type_check[0] = ap->type;
  type_check[1] = ap->way;
  check_data.magic = KV5M_DATA;
  check_data.length = 2;
  check_data.data = (char *) &type_check;

  r = krb5_mk_req_extended (telnet_context, &auth_context, ap_opts,
			    &check_data, new_creds, &auth);

  encryption_init (new_creds);

  krb5_free_cred_contents (telnet_context, &creds);
  krb5_free_creds (telnet_context, new_creds);
  if (r)
    {
      DEBUG (("telnet: Kerberos V5: mk_req failed (%s)\r\n",
	      error_message (r)));
      return 0;
    }

  if (!auth_sendname (UserNameRequested, strlen (UserNameRequested)))
    {
      DEBUG (("telnet: Not enough room for user name\r\n"));
      return 0;
    }

  if (!Data (ap, KRB_AUTH, auth.data, auth.length))
    {
      DEBUG (("telnet: Not enough room for authentication data\r\n"));
      return 0;
    }

  DEBUG (("telnet: Sent Kerberos V5 credentials to server\r\n"));

  return 1;
}
Esempio n. 8
0
static OM_uint32
acceptor_wait_for_dcestyle(OM_uint32 * minor_status,
			   gsskrb5_ctx ctx,
			   krb5_context context,
			   const gss_cred_id_t acceptor_cred_handle,
			   const gss_buffer_t input_token_buffer,
			   const gss_channel_bindings_t input_chan_bindings,
			   gss_name_t * src_name,
			   gss_OID * mech_type,
			   gss_buffer_t output_token,
			   OM_uint32 * ret_flags,
			   OM_uint32 * time_rec,
			   gss_cred_id_t * delegated_cred_handle)
{
    OM_uint32 ret;
    krb5_error_code kret;
    krb5_data inbuf;
    int32_t r_seq_number, l_seq_number;

    /*
     * We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP
     */

    inbuf.length = input_token_buffer->length;
    inbuf.data = input_token_buffer->value;

    /*
     * We need to remeber the old remote seq_number, then check if the
     * client has replied with our local seq_number, and then reset
     * the remote seq_number to the old value
     */
    {
	kret = krb5_auth_con_getlocalseqnumber(context,
					       ctx->auth_context,
					       &l_seq_number);
	if (kret) {
	    *minor_status = kret;
	    return GSS_S_FAILURE;
	}

	kret = krb5_auth_con_getremoteseqnumber(context,
						ctx->auth_context,
						&r_seq_number);
	if (kret) {
	    *minor_status = kret;
	    return GSS_S_FAILURE;
	}

	kret = krb5_auth_con_setremoteseqnumber(context,
						ctx->auth_context,
						l_seq_number);
	if (kret) {
	    *minor_status = kret;
	    return GSS_S_FAILURE;
	}
    }

    /*
     * We need to verify the AP_REP, but we need to flag that this is
     * DCE_STYLE, so don't check the timestamps this time, but put the
     * flag DO_TIME back afterward.
    */
    {
	krb5_ap_rep_enc_part *repl;
	int32_t auth_flags;

	krb5_auth_con_removeflags(context,
				  ctx->auth_context,
				  KRB5_AUTH_CONTEXT_DO_TIME,
				  &auth_flags);

	kret = krb5_rd_rep(context, ctx->auth_context, &inbuf, &repl);
	if (kret) {
	    *minor_status = kret;
	    return GSS_S_FAILURE;
	}
	krb5_free_ap_rep_enc_part(context, repl);
	krb5_auth_con_setflags(context, ctx->auth_context, auth_flags);
    }

    /* We need to check the liftime */
    {
	OM_uint32 lifetime_rec;

	ret = _gsskrb5_lifetime_left(minor_status,
				     context,
				     ctx->lifetime,
				     &lifetime_rec);
	if (ret) {
	    return ret;
	}
	if (lifetime_rec == 0) {
	    return GSS_S_CONTEXT_EXPIRED;
	}

	if (time_rec) *time_rec = lifetime_rec;
    }

    /* We need to give the caller the flags which are in use */
    if (ret_flags) *ret_flags = ctx->flags;

    if (src_name) {
	kret = krb5_copy_principal(context,
				   ctx->source,
				   (gsskrb5_name*)src_name);
	if (kret) {
	    *minor_status = kret;
	    return GSS_S_FAILURE;
	}
    }

    /*
     * After the krb5_rd_rep() the remote and local seq_number should
     * be the same, because the client just replies the seq_number
     * from our AP-REP in its AP-REP, but then the client uses the
     * seq_number from its AP-REQ for GSS_wrap()
     */
    {
	int32_t tmp_r_seq_number, tmp_l_seq_number;

	kret = krb5_auth_con_getremoteseqnumber(context,
						ctx->auth_context,
						&tmp_r_seq_number);
	if (kret) {
	    *minor_status = kret;
	    return GSS_S_FAILURE;
	}

	kret = krb5_auth_con_getlocalseqnumber(context,
					       ctx->auth_context,
					       &tmp_l_seq_number);
	if (kret) {

	    *minor_status = kret;
	    return GSS_S_FAILURE;
	}

	/*
	 * Here we check if the client has responsed with our local seq_number,
	 */
	if (tmp_r_seq_number != tmp_l_seq_number) {
	    return GSS_S_UNSEQ_TOKEN;
	}
    }

    /*
     * We need to reset the remote seq_number, because the client will use,
     * the old one for the GSS_wrap() calls
     */
    {
	kret = krb5_auth_con_setremoteseqnumber(context,
						ctx->auth_context,
						r_seq_number);
	if (kret) {
	    *minor_status = kret;
	    return GSS_S_FAILURE;
	}
    }

    return gsskrb5_acceptor_ready(minor_status, ctx, context,
				  delegated_cred_handle);
}
Esempio n. 9
0
static krb5_error_code
change_password_loop (krb5_context	context,
		      krb5_creds	*creds,
		      krb5_principal	targprinc,
		      char		*newpw,
		      int		*result_code,
		      krb5_data		*result_code_string,
		      krb5_data		*result_string,
		      struct kpwd_proc	*proc)
{
    krb5_error_code ret;
    krb5_auth_context auth_context = NULL;
    krb5_krbhst_handle handle = NULL;
    krb5_krbhst_info *hi;
    int sock;
    int i;
    int done = 0;
    krb5_realm realm = creds->client->realm;

    ret = krb5_auth_con_init (context, &auth_context);
    if (ret)
	return ret;

    krb5_auth_con_setflags (context, auth_context,
			    KRB5_AUTH_CONTEXT_DO_SEQUENCE);

    ret = krb5_krbhst_init (context, realm, KRB5_KRBHST_CHANGEPW, &handle);
    if (ret)
	goto out;

    while (!done && (ret = krb5_krbhst_next(context, handle, &hi)) == 0) {
	struct addrinfo *ai, *a;
	int is_stream;

	switch (hi->proto) {
	case KRB5_KRBHST_UDP:
	    if ((proc->flags & SUPPORT_UDP) == 0)
		continue;
	    is_stream = 0;
	    break;
	case KRB5_KRBHST_TCP:
	    if ((proc->flags & SUPPORT_TCP) == 0)
		continue;
	    is_stream = 1;
	    break;
	default:
	    continue;
	}

	ret = krb5_krbhst_get_addrinfo(context, hi, &ai);
	if (ret)
	    continue;

	for (a = ai; !done && a != NULL; a = a->ai_next) {
	    int replied = 0;

	    sock = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
	    if (sock < 0)
		continue;

	    ret = connect(sock, a->ai_addr, a->ai_addrlen);
	    if (ret < 0) {
		close (sock);
		goto out;
	    }

	    ret = krb5_auth_con_genaddrs (context, auth_context, sock,
					  KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR);
	    if (ret) {
		close (sock);
		goto out;
	    }

	    for (i = 0; !done && i < 5; ++i) {
		fd_set fdset;
		struct timeval tv;

		if (!replied) {
		    replied = 0;
		    
		    ret = (*proc->send_req) (context,
					     &auth_context,
					     creds,
					     targprinc,
					     is_stream,
					     sock,
					     newpw,
					     hi->hostname);
		    if (ret) {
			close(sock);
			goto out;
		    }
		}
	    
		if (sock >= FD_SETSIZE) {
		    krb5_set_error_string(context, "fd %d too large", sock);
		    ret = ERANGE;
		    close (sock);
		    goto out;
		}

		FD_ZERO(&fdset);
		FD_SET(sock, &fdset);
		tv.tv_usec = 0;
		tv.tv_sec  = 1 + (1 << i);

		ret = select (sock + 1, &fdset, NULL, NULL, &tv);
		if (ret < 0 && errno != EINTR) {
		    close(sock);
		    goto out;
		}
		if (ret == 1) {
		    ret = (*proc->process_rep) (context,
						auth_context,
						is_stream,
						sock,
						result_code,
						result_code_string,
						result_string,
						hi->hostname);
		    if (ret == 0)
			done = 1;
		    else if (i > 0 && ret == KRB5KRB_AP_ERR_MUT_FAIL)
			replied = 1;
		} else {
		    ret = KRB5_KDC_UNREACH;
		}
	    }
	    close (sock);
	}
    }

 out:
    krb5_krbhst_free (context, handle);
    krb5_auth_con_free (context, auth_context);
    if (done)
	return 0;
    else {
	if (ret == KRB5_KDC_UNREACH) {
	    krb5_set_error_string(context,
				  "unable to reach any changepw server "
				  " in realm %s", realm);
	    *result_code = KRB5_KPASSWD_HARDERROR;
	}
	return ret;
    }
}
Esempio n. 10
0
DWORD
LwKrb5InitializeUserLoginCredentials(
    IN PCSTR pszUserPrincipalName,
    IN PCSTR pszPassword,
    IN uid_t uid,
    IN gid_t gid,
    IN LW_KRB5_LOGIN_FLAGS Flags,
    IN PCSTR pszServicePrincipal,
    IN PCSTR pszServiceRealm,
    IN PCSTR pszServicePassword,
    OUT PVOID* ppNdrPacInfo,
    OUT size_t* pNdrPacInfoSize,
    OUT PDWORD pdwGoodUntilTime
    )
{
    DWORD dwError = 0;
    krb5_error_code ret = 0;
    krb5_context ctx = NULL;
    krb5_ccache cc = NULL;
    // Free with krb5_free_cred_contents
    krb5_creds credsRequest = {0};
    krb5_creds *pTgsCreds = NULL;
    krb5_ticket *pTgsTicket = NULL;
    krb5_ticket *pDecryptedTgs = NULL;
    krb5_auth_context authContext = NULL;
    krb5_data apReqPacket = {0};
    krb5_keyblock serviceKey = {0};
    krb5_data salt = {0};
    // Do not free
    krb5_data machinePassword = {0};
    krb5_flags flags = 0;
    krb5_int32 authcon_flags = 0;
    BOOLEAN bInLock = FALSE;
    PCSTR pszTempCacheName = NULL;
    PSTR pszTempCachePath = NULL;
    PVOID pNdrPacInfo = NULL;
    size_t ndrPacInfoSize = 0;
    DWORD dwGoodUntilTime = 0;

    ret = krb5_init_context(&ctx);
    BAIL_ON_KRB_ERROR(ctx, ret);

    /* Generates a new filed based credentials cache in /tmp. The file will
     * be owned by root and only accessible by root.
     */
    ret = krb5_cc_new_unique(
            ctx, 
            "FILE",
            "hint",
            &cc);
    BAIL_ON_KRB_ERROR(ctx, ret);


    if (Flags & LW_KRB5_LOGIN_FLAG_SMART_CARD)
    {
        dwError = LwKrb5GetTgtWithSmartCard(
                pszUserPrincipalName,
                pszPassword,
                krb5_cc_get_name(ctx, cc),
                &dwGoodUntilTime);
    }
    else
    {
        dwError = LwKrb5GetTgt(
                pszUserPrincipalName,
                pszPassword,
                krb5_cc_get_name(ctx, cc),
                &dwGoodUntilTime);
    }

    BAIL_ON_LW_ERROR(dwError);

    ret = krb5_parse_name(ctx, pszServicePrincipal, &credsRequest.server);
    BAIL_ON_KRB_ERROR(ctx, ret);

    ret = krb5_cc_get_principal(ctx, cc, &credsRequest.client);
    BAIL_ON_KRB_ERROR(ctx, ret);
 
    /* Get a TGS for our service using the tgt in the cache */
    ret = krb5_get_credentials(
            ctx,
            0, /*no options (not user to user encryption,
                 and not only cached) */
            cc,
            &credsRequest,
            &pTgsCreds);

    // Don't trust pTgsCreds on an unsuccessful return
    // This may be non-zero due to the krb5 libs following referrals
    // but has been freed in the krb5 libs themselves and any useful
    // tickets have already been cached.
    if (ret != 0) {
        pTgsCreds = NULL;
    }
    
    BAIL_ON_KRB_ERROR(ctx, ret);

    //No need to store the tgs in the cc. Kerberos does that automatically

    /* Generate an ap_req message, but don't send it anywhere. Just decode it
     * immediately. This is the only way to get kerberos to decrypt the tgs
     * using public APIs */
    ret = krb5_mk_req_extended(
            ctx,
            &authContext,
            0, /* no options necessary */
            NULL, /* since this isn't a real ap_req, we don't have any
                     supplemental data to send with it. */
            pTgsCreds,
            &apReqPacket);
    BAIL_ON_KRB_ERROR(ctx, ret);

    /* Decode (but not decrypt) the tgs ticket so that we can figure out
     * which encryption type was used in it. */
    ret = krb5_decode_ticket(&pTgsCreds->ticket, &pTgsTicket);

    /* The TGS ticket is encrypted with the machine password and salted with
     * the service principal. pszServicePrincipal could probably be used
     * directly, but it's safer to unparse pTgsCreds->server, because the KDC
     * sent that to us.
     */
    salt.magic = KV5M_DATA;
    ret = krb5_unparse_name(
            ctx,
            pTgsCreds->server,
            &salt.data);
    BAIL_ON_KRB_ERROR(ctx, ret);
    salt.length = strlen(salt.data);

    machinePassword.magic = KV5M_DATA;
    machinePassword.data = (PSTR)pszServicePassword,
    machinePassword.length = strlen(pszServicePassword),

    /* Generate a key to decrypt the TGS */
    ret = krb5_c_string_to_key(
            ctx,
            pTgsTicket->enc_part.enctype,
            &machinePassword,
            &salt,
            &serviceKey);
    BAIL_ON_KRB_ERROR(ctx, ret);

    /* Typically krb5_rd_req would decode the AP_REQ using the keytab, but
     * we don't want to depend on the keytab. As a side effect of kerberos'
     * user to user authentication support, if a key is explictly set on the
     * auth context, that key will be used to decrypt the TGS instead of the
     * keytab.
     *
     * By manually generating the key and setting it, we don't require
     * a keytab.
     */
    if (authContext != NULL)
    {
        ret = krb5_auth_con_free(ctx, authContext);
        BAIL_ON_KRB_ERROR(ctx, ret);
    }
    
    ret = krb5_auth_con_init(ctx, &authContext);
    BAIL_ON_KRB_ERROR(ctx, ret);

    ret = krb5_auth_con_setuseruserkey(
            ctx,
            authContext,
            &serviceKey);
    BAIL_ON_KRB_ERROR(ctx, ret);

    /* Disable replay detection which is unnecessary and
     * can fail when authenticating large numbers of users.
     */
    krb5_auth_con_getflags(ctx,
                           authContext,
                           &authcon_flags);
    krb5_auth_con_setflags(ctx,
                           authContext,
                           authcon_flags & ~KRB5_AUTH_CONTEXT_DO_TIME);


    if (pszServiceRealm)
    {
        ret = krb5_set_default_realm(ctx, pszServiceRealm);
        BAIL_ON_KRB_ERROR(ctx, ret);
    }

    /* This decrypts the TGS. As a side effect it ensures that the KDC that
     * the user's TGT came from is in the same realm that the machine was
     * joined to (this prevents users from spoofing the KDC).
     */
    ret = krb5_rd_req(
            ctx,
            &authContext,
            &apReqPacket,
            pTgsCreds->server,
            NULL, /* we're not using the keytab */
            &flags,
            &pDecryptedTgs);
    BAIL_ON_KRB_ERROR(ctx, ret);

    dwError = LwKrb5FindPac(
        ctx,
        pDecryptedTgs,
        &serviceKey,
        &pNdrPacInfo,
        &ndrPacInfoSize);
    BAIL_ON_LW_ERROR(dwError);

    if (Flags & LW_KRB5_LOGIN_FLAG_UPDATE_CACHE)
    {
        /* 1. Copy old credentials from the existing user creds cache to
         *      the temporary cache.
         * 2. Delete the existing creds cache.
         * 3. Move the temporary cache file into the final path.
         */
        dwError = pthread_mutex_lock(&gLwKrb5State.UserCacheMutex);
        BAIL_ON_LW_ERROR(dwError);
        bInLock = TRUE;

        dwError = LwKrb5CopyFromUserCache(
                    ctx,
                    cc,
                    uid
                    );
        BAIL_ON_LW_ERROR(dwError);

        pszTempCacheName = krb5_cc_get_name(ctx, cc);
        if (!strncasecmp(pszTempCacheName, "FILE:", sizeof("FILE:")-1)) {
            pszTempCacheName += sizeof("FILE:") - 1;
        }

        dwError = LwAllocateString(pszTempCacheName, &pszTempCachePath);
        BAIL_ON_LW_ERROR(dwError);

        krb5_cc_close(ctx, cc);
        // Just to make sure no one accesses this now invalid pointer
        cc = NULL;

        dwError = LwKrb5MoveCCacheToUserPath(
                    ctx,
                    pszTempCachePath,
                    uid,
                    gid);
        if (dwError != LW_ERROR_SUCCESS)
        {
            /* Let the user login, even if we couldn't create the ccache for
             * them. Possible causes are:
             * 1. /tmp is readonly
             * 2. Another user maliciously setup a weird file (such as a
             *    directory) where the ccache would go.
             * 3. Someone created a ccache in the small window after we delete
             *    the old one and before we move in the new one.
             */
            LW_LOG_WARNING("Unable to set up credentials cache with tgt for uid %ld", (long)uid);
            dwError = LwRemoveFile(pszTempCachePath);
            BAIL_ON_LW_ERROR(dwError);
        }
    }

error:
    if (dwError)
    {
        LW_SAFE_FREE_MEMORY(pNdrPacInfo);
        ndrPacInfoSize = 0;
        dwGoodUntilTime = 0;
    }

    if (ctx)
    {
        // This function skips fields which are NULL
        krb5_free_cred_contents(ctx, &credsRequest);
    
        if (pTgsCreds != NULL)
        {
            krb5_free_creds(ctx, pTgsCreds);
        }
        
        if (pTgsTicket != NULL)
        {
            krb5_free_ticket(ctx, pTgsTicket);
        }
        
        if (pDecryptedTgs != NULL)
        {
            krb5_free_ticket(ctx, pDecryptedTgs);
        }
        
        if (authContext != NULL)
        {
            krb5_auth_con_free(ctx, authContext);
        }
        
        krb5_free_data_contents(ctx, &apReqPacket);
        krb5_free_data_contents(ctx, &salt);
        krb5_free_keyblock_contents(ctx, &serviceKey);

        if (cc != NULL)
        {
            krb5_cc_destroy(ctx, cc);
        }
        krb5_free_context(ctx);
    }
    if (bInLock)
    {
        pthread_mutex_unlock(&gLwKrb5State.UserCacheMutex);
    }
    LW_SAFE_FREE_STRING(pszTempCachePath);

    *ppNdrPacInfo = pNdrPacInfo;
    *pNdrPacInfoSize = ndrPacInfoSize;
    *pdwGoodUntilTime = dwGoodUntilTime;

    return dwError;
}
Esempio n. 11
0
int main(int argc, char **argv)
{
	int log_level = 0;
	char *ap_req_str = NULL;

	/* krb5 */
	krb5_error_code ret;
	krb5_context context;
	krb5_auth_context auth_context;
	char *princ_str_tn = "kink/tn.example.com";
	krb5_principal princ_tn;
	char *princ_str_nut = "kink/nut.example.com";
	krb5_principal princ_nut;
	char *princ_str_krbtgt = "krbtgt/EXAMPLE.COM";
	krb5_principal princ_krbtgt;
	krb5_ccache ccache;
	krb5_keytab keytab;
	krb5_creds creds_tgt;
	krb5_data ap_req;

	prog = (const char *) basename(argv[0]);
	if (prog == NULL) {
		fprintf(stderr,
			"basename: %s -- %s\n", strerror(errno), argv[0]);

		return(0);
		/* NOTREACHED */
	}

	{
		int ch = 0;

		while ((ch = getopt(argc, argv, "dq:")) != -1) {
			switch (ch) {
			case 'd':
				log_level++;
				break;
			case 'q':
				ap_req_str = optarg;
				break;
			default:
				usage();
				/* NOTREACHED */

				break;
			}
		}

		argc -= optind;
		argv += optind;
	}

	if (argc) {
		usage();
		/* NOTREACHED */
	}

	{
		printf("dbg: %s starts\n", prog);
	}

	if (ap_req_str != NULL) {
		hex2krb5data(ap_req_str, &ap_req);
		if (log_level) {
			dump_krb5_data(&ap_req);
		}
		{ /* stdout */
			int i = 0;
			unsigned char *p;
			p = (unsigned char *)ap_req.data;
			printf("std:ap_req:");
			for (i = 0; i < ap_req.length; i++) {
				printf("%02x", *p++);
			}
			printf("\n");
		}
	}

	/* prepare krb5 context */
	{
		/** init context */
		ret = krb5_init_context(&context);
		if (ret != 0) {
			printf("ERR:krb5_init_context:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		/** setup principals */
		ret = krb5_parse_name(context, princ_str_tn, &princ_tn);
		if (ret != 0) {
			printf("ERR:krb5_parse_name:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}
		ret = krb5_parse_name(context, princ_str_nut, &princ_nut);
		if (ret != 0) {
			printf("ERR:krb5_parse_name:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}
		ret = krb5_parse_name(context, princ_str_krbtgt, &princ_krbtgt);
		if (ret != 0) {
			printf("ERR:krb5_parse_name:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		/** prepare credential cache */
		ret = krb5_cc_default(context, &ccache);
		if (ret != 0) {
			printf("ERR:krb5_cc_default:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		/** prepare keytab */
		/*ret = krb5_kt_resolve(context, "/usr/local/var/krb5kdc/kadm5.keytab", &keytab);*/
		ret = krb5_kt_default(context, &keytab);
		if (ret != 0) {
			/* printf("ERR:krb5_kt_default:%s", krb5_get_err_text(context, ret)); */
			printf("ERR:krb5_kt_resolve:%s", krb5_get_err_text(context, ret));
			return(ret);
		}

	}

	/* get TGT */
	{
		krb5_creds mcreds;
		memset(&mcreds, 0, sizeof(mcreds));
		mcreds.client = princ_tn;
		mcreds.server = princ_krbtgt;

		ret = krb5_cc_retrieve_cred(context, ccache, 0, &mcreds, &creds_tgt);
		if (ret != 0) {
			printf("ERR:krb5_cc_retrieve_cred:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}
	}

	/* prepare authentiation context */
	{
		ret = krb5_auth_con_init(context, &auth_context);
		if (ret != 0) {
			printf("ERR:krb5_auth_con_init:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		ret = krb5_auth_con_setflags(context, auth_context,
					     KRB5_AUTH_CONTEXT_DO_SEQUENCE);
		if (ret != 0) {
			printf("ERR:krb5_auth_con_setflags:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		/* if USE_SKEY */
		/*
		ret = krb5_auth_con_setuserkey(context, auth_context, &creds_tgt.session);
		if (ret != 0) {
			printf("ERR:krb5_auth_con_setuseruserkey:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}
		*/
	}

	/* set keyblock in auth_context */
	{
		krb5_ticket *ticket;
		krb5_flags ap_req_options;
		
		ap_req_options = AP_OPTS_MUTUAL_REQUIRED;
		ticket = NULL;
		ret = krb5_rd_req(context,
				  &auth_context,
				  &ap_req,
				  NULL,
				  keytab,
				  &ap_req_options,
				  &ticket);
		if (log_level) {
			printf("info: ticket.ticket.key is SKEYID_d\n");
			/*dump_krb5_ticket(context, *ticket);*/
		}
		if (log_level) {
			printf("ap_req_opt (%d)\n", ap_req_options);
		}
		if (ret != 0) {
			printf("ERR:krb5_rd_req:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}
		if (log_level) {
			dump_krb5_keyblock(auth_context->keyblock);
		}

		krb5_free_ticket(context, ticket);
	}

	/* make AP_REP */
	{
		krb5_data ap_rep;
		ret = krb5_mk_rep(context, auth_context, &ap_rep);
		if (ret != 0) {
			printf("ERR:krb5_mk_rep:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}
		{ /* stdout */
			int i = 0;
			unsigned char *p;
			p = (unsigned char *)ap_rep.data;
			printf("std:ap_rep:");
			for (i = 0; i < ap_rep.length; i++) {
				printf("%02x", *p++);
			}
			printf("\n");
		}
	}

	/* clenaup */
	{
		/*free(data);*/
		/*krb5_data_free(&ap_req);*/
		krb5_free_cred_contents(context, &creds_tgt);

		ret = krb5_kt_close(context, keytab);
		if (ret != 0) {
			printf("ERR:krb5_kt_close:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		ret = krb5_cc_close(context, ccache);
		if (ret != 0) {
			printf("ERR:krb5_cc_close:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		krb5_free_principal(context, princ_krbtgt);
		krb5_free_principal(context, princ_nut);
		krb5_free_principal(context, princ_tn);
		krb5_free_context(context);
	}

	return(0);
}
Esempio n. 12
0
File: chpw.c Progetto: jmoldow/krb5
krb5_error_code
krb5int_mk_chpw_req(krb5_context context,
                    krb5_auth_context auth_context,
                    krb5_data *ap_req,
                    char *passwd,
                    krb5_data *packet)
{
    krb5_error_code ret = 0;
    krb5_data clearpw;
    krb5_data cipherpw;
    krb5_replay_data replay;
    char *ptr;

    cipherpw.data = NULL;

    if ((ret = krb5_auth_con_setflags(context, auth_context,
                                      KRB5_AUTH_CONTEXT_DO_SEQUENCE)))
        goto cleanup;

    clearpw.length = strlen(passwd);
    clearpw.data = passwd;

    if ((ret = krb5_mk_priv(context, auth_context,
                            &clearpw, &cipherpw, &replay)))
        goto cleanup;

    packet->length = 6 + ap_req->length + cipherpw.length;
    packet->data = (char *) malloc(packet->length);
    if (packet->data == NULL) {
        ret = ENOMEM;
        goto cleanup;
    }
    ptr = packet->data;

    /* length */

    store_16_be(packet->length, ptr);
    ptr += 2;

    /* version == 0x0001 big-endian */

    *ptr++ = 0;
    *ptr++ = 1;

    /* ap_req length, big-endian */

    store_16_be(ap_req->length, ptr);
    ptr += 2;

    /* ap-req data */

    memcpy(ptr, ap_req->data, ap_req->length);
    ptr += ap_req->length;

    /* krb-priv of password */

    memcpy(ptr, cipherpw.data, cipherpw.length);

cleanup:
    if (cipherpw.data != NULL)  /* allocated by krb5_mk_priv */
        free(cipherpw.data);

    return(ret);
}
Esempio n. 13
0
File: chpw.c Progetto: jmoldow/krb5
krb5_error_code
krb5int_mk_setpw_req(krb5_context context,
                     krb5_auth_context auth_context,
                     krb5_data *ap_req,
                     krb5_principal targprinc,
                     char *passwd,
                     krb5_data *packet)
{
    krb5_error_code ret;
    krb5_data   cipherpw;
    krb5_data   *encoded_setpw;
    struct krb5_setpw_req req;

    char *ptr;

    cipherpw.data = NULL;
    cipherpw.length = 0;

    if ((ret = krb5_auth_con_setflags(context, auth_context,
                                      KRB5_AUTH_CONTEXT_DO_SEQUENCE)))
        return(ret);

    req.target = targprinc;
    req.password.data = passwd;
    req.password.length = strlen(passwd);
    ret = encode_krb5_setpw_req(&req, &encoded_setpw);
    if (ret) {
        return ret;
    }

    if ((ret = krb5_mk_priv(context, auth_context, encoded_setpw, &cipherpw, NULL)) != 0) {
        krb5_free_data(context, encoded_setpw);
        return(ret);
    }
    krb5_free_data(context, encoded_setpw);


    packet->length = 6 + ap_req->length + cipherpw.length;
    packet->data = (char *) malloc(packet->length);
    if (packet->data  == NULL) {
        ret = ENOMEM;
        goto cleanup;
    }
    ptr = packet->data;
    /*
    ** build the packet -
    */
    /* put in the length */
    store_16_be(packet->length, ptr);
    ptr += 2;
    /* put in the version */
    *ptr++ = (char)0xff;
    *ptr++ = (char)0x80;
    /* the ap_req length is big endian */
    store_16_be(ap_req->length, ptr);
    ptr += 2;
    /* put in the request data */
    memcpy(ptr, ap_req->data, ap_req->length);
    ptr += ap_req->length;
    /*
    ** put in the "private" password data -
    */
    memcpy(ptr, cipherpw.data, cipherpw.length);
    ret = 0;
cleanup:
    if (cipherpw.data)
        krb5_free_data_contents(context, &cipherpw);
    if ((ret != 0) && packet->data) {
        free(packet->data);
        packet->data = NULL;
    }
    return ret;
}
Esempio n. 14
0
static krb5_error_code
process_chpw_request(krb5_context context, void *server_handle, char *realm,
                     krb5_keytab keytab, const krb5_fulladdr *local_faddr,
                     const krb5_fulladdr *remote_faddr, krb5_data *req,
                     krb5_data *rep)
{
    krb5_error_code ret;
    char *ptr;
    unsigned int plen, vno;
    krb5_data ap_req, ap_rep = empty_data();
    krb5_data cipher = empty_data(), clear = empty_data();
    krb5_auth_context auth_context = NULL;
    krb5_principal changepw = NULL;
    krb5_principal client, target = NULL;
    krb5_ticket *ticket = NULL;
    krb5_replay_data replay;
    krb5_error krberror;
    int numresult;
    char strresult[1024];
    char *clientstr = NULL, *targetstr = NULL;
    const char *errmsg = NULL;
    size_t clen;
    char *cdots;
    struct sockaddr_storage ss;
    socklen_t salen;
    char addrbuf[100];
    krb5_address *addr = remote_faddr->address;

    *rep = empty_data();

    if (req->length < 4) {
        /* either this, or the server is printing bad messages,
           or the caller passed in garbage */
        ret = KRB5KRB_AP_ERR_MODIFIED;
        numresult = KRB5_KPASSWD_MALFORMED;
        strlcpy(strresult, "Request was truncated", sizeof(strresult));
        goto bailout;
    }

    ptr = req->data;

    /* verify length */

    plen = (*ptr++ & 0xff);
    plen = (plen<<8) | (*ptr++ & 0xff);

    if (plen != req->length) {
        ret = KRB5KRB_AP_ERR_MODIFIED;
        numresult = KRB5_KPASSWD_MALFORMED;
        strlcpy(strresult, "Request length was inconsistent",
                sizeof(strresult));
        goto bailout;
    }

    /* verify version number */

    vno = (*ptr++ & 0xff) ;
    vno = (vno<<8) | (*ptr++ & 0xff);

    if (vno != 1 && vno != RFC3244_VERSION) {
        ret = KRB5KDC_ERR_BAD_PVNO;
        numresult = KRB5_KPASSWD_BAD_VERSION;
        snprintf(strresult, sizeof(strresult),
                 "Request contained unknown protocol version number %d", vno);
        goto bailout;
    }

    /* read, check ap-req length */

    ap_req.length = (*ptr++ & 0xff);
    ap_req.length = (ap_req.length<<8) | (*ptr++ & 0xff);

    if (ptr + ap_req.length >= req->data + req->length) {
        ret = KRB5KRB_AP_ERR_MODIFIED;
        numresult = KRB5_KPASSWD_MALFORMED;
        strlcpy(strresult, "Request was truncated in AP-REQ",
                sizeof(strresult));
        goto bailout;
    }

    /* verify ap_req */

    ap_req.data = ptr;
    ptr += ap_req.length;

    ret = krb5_auth_con_init(context, &auth_context);
    if (ret) {
        numresult = KRB5_KPASSWD_HARDERROR;
        strlcpy(strresult, "Failed initializing auth context",
                sizeof(strresult));
        goto chpwfail;
    }

    ret = krb5_auth_con_setflags(context, auth_context,
                                 KRB5_AUTH_CONTEXT_DO_SEQUENCE);
    if (ret) {
        numresult = KRB5_KPASSWD_HARDERROR;
        strlcpy(strresult, "Failed initializing auth context",
                sizeof(strresult));
        goto chpwfail;
    }

    ret = krb5_build_principal(context, &changepw, strlen(realm), realm,
                               "kadmin", "changepw", NULL);
    if (ret) {
        numresult = KRB5_KPASSWD_HARDERROR;
        strlcpy(strresult, "Failed building kadmin/changepw principal",
                sizeof(strresult));
        goto chpwfail;
    }

    ret = krb5_rd_req(context, &auth_context, &ap_req, changepw, keytab,
                      NULL, &ticket);

    if (ret) {
        numresult = KRB5_KPASSWD_AUTHERROR;
        strlcpy(strresult, "Failed reading application request",
                sizeof(strresult));
        goto chpwfail;
    }

    /* construct the ap-rep */

    ret = krb5_mk_rep(context, auth_context, &ap_rep);
    if (ret) {
        numresult = KRB5_KPASSWD_AUTHERROR;
        strlcpy(strresult, "Failed replying to application request",
                sizeof(strresult));
        goto chpwfail;
    }

    /* decrypt the ChangePasswdData */

    cipher.length = (req->data + req->length) - ptr;
    cipher.data = ptr;

    /*
     * Don't set a remote address in auth_context before calling krb5_rd_priv,
     * so that we can work against clients behind a NAT.  Reflection attacks
     * aren't a concern since we use sequence numbers and since our requests
     * don't look anything like our responses.  Also don't set a local address,
     * since we don't know what interface the request was received on.
     */

    ret = krb5_rd_priv(context, auth_context, &cipher, &clear, &replay);
    if (ret) {
        numresult = KRB5_KPASSWD_HARDERROR;
        strlcpy(strresult, "Failed decrypting request", sizeof(strresult));
        goto chpwfail;
    }

    client = ticket->enc_part2->client;

    /* decode ChangePasswdData for setpw requests */
    if (vno == RFC3244_VERSION) {
        krb5_data *clear_data;

        ret = decode_krb5_setpw_req(&clear, &clear_data, &target);
        if (ret != 0) {
            numresult = KRB5_KPASSWD_MALFORMED;
            strlcpy(strresult, "Failed decoding ChangePasswdData",
                    sizeof(strresult));
            goto chpwfail;
        }

        zapfree(clear.data, clear.length);

        clear = *clear_data;
        free(clear_data);

        if (target != NULL) {
            ret = krb5_unparse_name(context, target, &targetstr);
            if (ret != 0) {
                numresult = KRB5_KPASSWD_HARDERROR;
                strlcpy(strresult, "Failed unparsing target name for log",
                        sizeof(strresult));
                goto chpwfail;
            }
        }
    }

    ret = krb5_unparse_name(context, client, &clientstr);
    if (ret) {
        numresult = KRB5_KPASSWD_HARDERROR;
        strlcpy(strresult, "Failed unparsing client name for log",
                sizeof(strresult));
        goto chpwfail;
    }

    /* for cpw, verify that this is an AS_REQ ticket */
    if (vno == 1 &&
        (ticket->enc_part2->flags & TKT_FLG_INITIAL) == 0) {
        numresult = KRB5_KPASSWD_INITIAL_FLAG_NEEDED;
        strlcpy(strresult, "Ticket must be derived from a password",
                sizeof(strresult));
        goto chpwfail;
    }

    /* change the password */

    ptr = k5memdup0(clear.data, clear.length, &ret);
    ret = schpw_util_wrapper(server_handle, client, target,
                             (ticket->enc_part2->flags & TKT_FLG_INITIAL) != 0,
                             ptr, NULL, strresult, sizeof(strresult));
    if (ret)
        errmsg = krb5_get_error_message(context, ret);

    /* zap the password */
    zapfree(clear.data, clear.length);
    zapfree(ptr, clear.length);
    clear = empty_data();

    clen = strlen(clientstr);
    trunc_name(&clen, &cdots);

    switch (addr->addrtype) {
    case ADDRTYPE_INET: {
        struct sockaddr_in *sin = ss2sin(&ss);

        sin->sin_family = AF_INET;
        memcpy(&sin->sin_addr, addr->contents, addr->length);
        sin->sin_port = htons(remote_faddr->port);
        salen = sizeof(*sin);
        break;
    }
    case ADDRTYPE_INET6: {
        struct sockaddr_in6 *sin6 = ss2sin6(&ss);

        sin6->sin6_family = AF_INET6;
        memcpy(&sin6->sin6_addr, addr->contents, addr->length);
        sin6->sin6_port = htons(remote_faddr->port);
        salen = sizeof(*sin6);
        break;
    }
    default: {
        struct sockaddr *sa = ss2sa(&ss);

        sa->sa_family = AF_UNSPEC;
        salen = sizeof(*sa);
        break;
    }
    }

    if (getnameinfo(ss2sa(&ss), salen,
                    addrbuf, sizeof(addrbuf), NULL, 0,
                    NI_NUMERICHOST | NI_NUMERICSERV) != 0)
        strlcpy(addrbuf, "<unprintable>", sizeof(addrbuf));

    if (vno == RFC3244_VERSION) {
        size_t tlen;
        char *tdots;
        const char *targetp;

        if (target == NULL) {
            tlen = clen;
            tdots = cdots;
            targetp = targetstr;
        } else {
            tlen = strlen(targetstr);
            trunc_name(&tlen, &tdots);
            targetp = clientstr;
        }

        krb5_klog_syslog(LOG_NOTICE, _("setpw request from %s by %.*s%s for "
                                       "%.*s%s: %s"), addrbuf, (int) clen,
                         clientstr, cdots, (int) tlen, targetp, tdots,
                         errmsg ? errmsg : "success");
    } else {
        krb5_klog_syslog(LOG_NOTICE, _("chpw request from %s for %.*s%s: %s"),
                         addrbuf, (int) clen, clientstr, cdots,
                         errmsg ? errmsg : "success");
    }
    switch (ret) {
    case KADM5_AUTH_CHANGEPW:
        numresult = KRB5_KPASSWD_ACCESSDENIED;
        break;
    case KADM5_PASS_Q_TOOSHORT:
    case KADM5_PASS_REUSE:
    case KADM5_PASS_Q_CLASS:
    case KADM5_PASS_Q_DICT:
    case KADM5_PASS_Q_GENERIC:
    case KADM5_PASS_TOOSOON:
        numresult = KRB5_KPASSWD_SOFTERROR;
        break;
    case 0:
        numresult = KRB5_KPASSWD_SUCCESS;
        strlcpy(strresult, "", sizeof(strresult));
        break;
    default:
        numresult = KRB5_KPASSWD_HARDERROR;
        break;
    }

chpwfail:

    ret = alloc_data(&clear, 2 + strlen(strresult));
    if (ret)
        goto bailout;

    ptr = clear.data;

    *ptr++ = (numresult>>8) & 0xff;
    *ptr++ = numresult & 0xff;

    memcpy(ptr, strresult, strlen(strresult));

    cipher = empty_data();

    if (ap_rep.length) {
        ret = krb5_auth_con_setaddrs(context, auth_context,
                                     local_faddr->address, NULL);
        if (ret) {
            numresult = KRB5_KPASSWD_HARDERROR;
            strlcpy(strresult,
                    "Failed storing client and server internet addresses",
                    sizeof(strresult));
        } else {
            ret = krb5_mk_priv(context, auth_context, &clear, &cipher,
                               &replay);
            if (ret) {
                numresult = KRB5_KPASSWD_HARDERROR;
                strlcpy(strresult, "Failed encrypting reply",
                        sizeof(strresult));
            }
        }
    }

    /* if no KRB-PRIV was constructed, then we need a KRB-ERROR.
       if this fails, just bail.  there's nothing else we can do. */

    if (cipher.length == 0) {
        /* clear out ap_rep now, so that it won't be inserted in the
           reply */

        if (ap_rep.length) {
            free(ap_rep.data);
            ap_rep = empty_data();
        }

        krberror.ctime = 0;
        krberror.cusec = 0;
        krberror.susec = 0;
        ret = krb5_timeofday(context, &krberror.stime);
        if (ret)
            goto bailout;

        /* this is really icky.  but it's what all the other callers
           to mk_error do. */
        krberror.error = ret;
        krberror.error -= ERROR_TABLE_BASE_krb5;
        if (krberror.error < 0 || krberror.error > KRB_ERR_MAX)
            krberror.error = KRB_ERR_GENERIC;

        krberror.client = NULL;

        ret = krb5_build_principal(context, &krberror.server,
                                   strlen(realm), realm,
                                   "kadmin", "changepw", NULL);
        if (ret)
            goto bailout;
        krberror.text.length = 0;
        krberror.e_data = clear;

        ret = krb5_mk_error(context, &krberror, &cipher);

        krb5_free_principal(context, krberror.server);

        if (ret)
            goto bailout;
    }

    /* construct the reply */

    ret = alloc_data(rep, 6 + ap_rep.length + cipher.length);
    if (ret)
        goto bailout;
    ptr = rep->data;

    /* length */

    *ptr++ = (rep->length>>8) & 0xff;
    *ptr++ = rep->length & 0xff;

    /* version == 0x0001 big-endian */

    *ptr++ = 0;
    *ptr++ = 1;

    /* ap_rep length, big-endian */

    *ptr++ = (ap_rep.length>>8) & 0xff;
    *ptr++ = ap_rep.length & 0xff;

    /* ap-rep data */

    if (ap_rep.length) {
        memcpy(ptr, ap_rep.data, ap_rep.length);
        ptr += ap_rep.length;
    }

    /* krb-priv or krb-error */

    memcpy(ptr, cipher.data, cipher.length);

bailout:
    krb5_auth_con_free(context, auth_context);
    krb5_free_principal(context, changepw);
    krb5_free_ticket(context, ticket);
    free(ap_rep.data);
    free(clear.data);
    free(cipher.data);
    krb5_free_principal(context, target);
    krb5_free_unparsed_name(context, targetstr);
    krb5_free_unparsed_name(context, clientstr);
    krb5_free_error_message(context, errmsg);
    return ret;
}
Esempio n. 15
0
static krb5_error_code mod_authn_gssapi_verify_krb5_init_creds(server *srv, krb5_context context, krb5_creds *creds, krb5_principal ap_req_server, krb5_keytab ap_req_keytab)
{
    krb5_error_code ret;
    krb5_data req;
    krb5_ccache local_ccache       = NULL;
    krb5_creds *new_creds          = NULL;
    krb5_auth_context auth_context = NULL;
    krb5_keytab keytab             = NULL;
    char *server_name;

    memset(&req, 0, sizeof(req));

    if (ap_req_keytab == NULL) {
        ret = krb5_kt_default(context, &keytab);
        if (ret)
            return ret;
    } else
        keytab = ap_req_keytab;

    ret = krb5_cc_resolve(context, "MEMORY:", &local_ccache);
    if (ret) {
        log_error_write(srv, __FILE__, __LINE__, "s", "krb5_cc_resolve() failed when verifying KDC");
        /* return ret; */
        goto end;
    }

    ret = krb5_cc_initialize(context, local_ccache, creds->client);
    if (ret) {
        log_error_write(srv, __FILE__, __LINE__, "s", "krb5_cc_initialize() failed when verifying KDC");
        goto end;
    }

    ret = krb5_cc_store_cred(context, local_ccache, creds);
    if (ret) {
        log_error_write(srv, __FILE__, __LINE__, "s", "krb5_cc_store_cred() failed when verifying KDC");
        goto end;
    }

    ret = krb5_unparse_name(context, ap_req_server, &server_name);
    if (ret) {
        log_error_write(srv, __FILE__, __LINE__, "s", "krb5_unparse_name() failed when verifying KDC");
        goto end;
    }
    krb5_free_unparsed_name(context, server_name);

    if (!krb5_principal_compare(context, ap_req_server, creds->server)) {
        krb5_creds match_cred;

        memset(&match_cred, 0, sizeof(match_cred));

        match_cred.client = creds->client;
        match_cred.server = ap_req_server;

        ret = krb5_get_credentials(context, 0, local_ccache, &match_cred, &new_creds);
        if (ret) {
            log_error_write(srv, __FILE__, __LINE__, "s", "krb5_get_credentials() failed when verifying KDC");
            goto end;
        }
        creds = new_creds;
    }

    ret = krb5_mk_req_extended(context, &auth_context, 0, NULL, creds, &req);
    if (ret) {
        log_error_write(srv, __FILE__, __LINE__, "s", "krb5_mk_req_extended() failed when verifying KDC");
        goto end;
    }

    krb5_auth_con_free(context, auth_context);
    auth_context = NULL;
    ret = krb5_auth_con_init(context, &auth_context);
    if (ret) {
        log_error_write(srv, __FILE__, __LINE__, "s", "krb5_auth_con_init() failed when verifying KDC");
        goto end;
    }

    /* use KRB5_AUTH_CONTEXT_DO_SEQUENCE to skip replay cache checks */
    krb5_auth_con_setflags(context, auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
    ret = krb5_rd_req(context, &auth_context, &req, ap_req_server, keytab, 0, NULL);
    if (ret) {
        log_error_write(srv, __FILE__, __LINE__, "s", "krb5_rd_req() failed when verifying KDC");
        goto end;
    }

    end:
        krb5_free_data_contents(context, &req);
        if (auth_context)
            krb5_auth_con_free(context, auth_context);
        if (new_creds)
            krb5_free_creds(context, new_creds);
        if (ap_req_keytab == NULL && keytab)
            krb5_kt_close(context, keytab);
        if (local_ccache)
            krb5_cc_destroy(context, local_ccache);

    return ret;
}
Esempio n. 16
0
Code_t
ZCheckSrvAuthentication(ZNotice_t *notice,
			struct sockaddr_in *from,
			char *realm)
{
#ifdef HAVE_KRB5
    unsigned char *authbuf;
    krb5_principal princ;
    krb5_data packet;
    krb5_ticket *tkt;
    char *name;
    krb5_error_code result;
    krb5_principal server;
    krb5_keytab keytabid = 0;
    krb5_auth_context authctx;
    krb5_keyblock *keyblock;
    krb5_enctype enctype;
    krb5_cksumtype cksumtype;
    krb5_data cksumbuf;
    int valid;
    char *cksum0_base, *cksum1_base = NULL, *cksum2_base;
    char *x;
    unsigned char *asn1_data, *key_data, *cksum_data;
    int asn1_len, key_len, cksum0_len = 0, cksum1_len = 0, cksum2_len = 0;
    KRB5_AUTH_CON_FLAGS_TYPE acflags;
#ifdef KRB5_AUTH_CON_GETAUTHENTICATOR_TAKES_DOUBLE_POINTER
    krb5_authenticator *authenticator;
#define KRB5AUTHENT authenticator
#else
    krb5_authenticator authenticator;
#define KRB5AUTHENT &authenticator
#endif
    int len;
    char *sender;
    char rlmprincipal[MAX_PRINCIPAL_SIZE];

    if (!notice->z_auth)
        return ZAUTH_NO;

    /* Check for bogus authentication data length. */
    if (notice->z_authent_len <= 0) {
        syslog(LOG_DEBUG, "ZCheckSrvAuthentication: bogus authenticator length");
        return ZAUTH_FAILED;
    }

#ifdef HAVE_KRB4
    if (notice->z_ascii_authent[0] != 'Z' && realm == NULL)
      return ZCheckAuthentication4(notice, from);
#endif

    len = strlen(notice->z_ascii_authent)+1;
    authbuf = malloc(len);

    /* Read in the authentication data. */
    if (ZReadZcode((unsigned char *)notice->z_ascii_authent,
                   authbuf,
                   len, &len) == ZERR_BADFIELD) {
        syslog(LOG_DEBUG, "ZCheckSrvAuthentication: ZReadZcode: Improperly formatted field");
        return ZAUTH_FAILED;
    }

    if (realm == NULL) {
	sender = notice->z_sender;
    } else {
	(void) snprintf(rlmprincipal, MAX_PRINCIPAL_SIZE, "%s/%s@%s", SERVER_SERVICE,
			SERVER_INSTANCE, realm);
	sender = rlmprincipal;
    }

    packet.length = len;
    packet.data = (char *)authbuf;

    result = krb5_kt_resolve(Z_krb5_ctx,
                        keytab_file, &keytabid);
    if (result) {
        free(authbuf);
        syslog(LOG_DEBUG, "ZCheckSrvAuthentication: krb5_kt_resolve: %s", error_message(result));
        return ZAUTH_FAILED;
    }

    /* HOLDING: authbuf, keytabid */
    /* Create the auth context */
    result = krb5_auth_con_init(Z_krb5_ctx, &authctx);
    if (result) {
        krb5_kt_close(Z_krb5_ctx, keytabid);
        free(authbuf);
        syslog(LOG_DEBUG, "ZCheckSrvAuthentication: krb5_auth_con_init: %s", error_message(result));
        return ZAUTH_FAILED;
    }

    /* HOLDING: authbuf, keytabid, authctx */
    result = krb5_auth_con_getflags(Z_krb5_ctx, authctx, &acflags);
    if (result) {
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        krb5_kt_close(Z_krb5_ctx, keytabid);
        free(authbuf);
        syslog(LOG_DEBUG, "ZCheckSrvAuthentication: krb5_auth_con_getflags: %s", error_message(result));
        return ZAUTH_FAILED;
    }

    acflags &= ~KRB5_AUTH_CONTEXT_DO_TIME;

    result = krb5_auth_con_setflags(Z_krb5_ctx, authctx, acflags);
    if (result) {
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        krb5_kt_close(Z_krb5_ctx, keytabid);
        free(authbuf);
        syslog(LOG_DEBUG, "ZCheckSrvAuthentication: krb5_auth_con_setflags: %s", error_message(result));
        return ZAUTH_FAILED;
    }

    result = krb5_build_principal(Z_krb5_ctx, &server, strlen(__Zephyr_realm),
				  __Zephyr_realm, SERVER_SERVICE,
				  SERVER_INSTANCE, NULL);
    if (!result) {
        result = krb5_rd_req(Z_krb5_ctx, &authctx, &packet, server,
                             keytabid, NULL, &tkt);
	krb5_free_principal(Z_krb5_ctx, server);
    }
    krb5_kt_close(Z_krb5_ctx, keytabid);

    /* HOLDING: authbuf, authctx */
    if (result) {
        if (result == KRB5KRB_AP_ERR_REPEAT)
            syslog(LOG_DEBUG, "ZCheckSrvAuthentication: k5 auth failed: %s",
                   error_message(result));
        else
            syslog(LOG_WARNING,"ZCheckSrvAuthentication: k5 auth failed: %s",
                   error_message(result));
        free(authbuf);
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        return ZAUTH_FAILED;
    }

    /* HOLDING: authbuf, authctx, tkt */

    if (tkt == 0 || !Z_tktprincp(tkt)) {
        if (tkt)
            krb5_free_ticket(Z_krb5_ctx, tkt);
        free(authbuf);
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        syslog(LOG_WARNING, "ZCheckSrvAuthentication: No Ticket");
        return ZAUTH_FAILED;
    }

    princ = Z_tktprinc(tkt);

    if (princ == 0) {
        krb5_free_ticket(Z_krb5_ctx, tkt);
        free(authbuf);
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        syslog(LOG_WARNING, "ZCheckSrvAuthentication: No... Ticket?");
        return ZAUTH_FAILED;
    }

    /* HOLDING: authbuf, authctx, tkt */
    result = krb5_unparse_name(Z_krb5_ctx, princ, &name);
    if (result) {
        syslog(LOG_WARNING, "ZCheckSrvAuthentication: krb5_unparse_name failed: %s",
               error_message(result));
        free(authbuf);
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        krb5_free_ticket(Z_krb5_ctx, tkt);
        return ZAUTH_FAILED;
    }

    krb5_free_ticket(Z_krb5_ctx, tkt);

    /* HOLDING: authbuf, authctx, name */
    if (strcmp(name, sender)) {
        syslog(LOG_WARNING, "ZCheckSrvAuthentication: name mismatch: '%s' vs '%s'",
               name, sender);
        krb5_auth_con_free(Z_krb5_ctx, authctx);
#ifdef HAVE_KRB5_FREE_UNPARSED_NAME
        krb5_free_unparsed_name(Z_krb5_ctx, name);
#else
        free(name);
#endif
        free(authbuf);
        return ZAUTH_FAILED;
    }
#ifdef HAVE_KRB5_FREE_UNPARSED_NAME
    krb5_free_unparsed_name(Z_krb5_ctx, name);
#else
    free(name);
#endif
    free(authbuf);

    /* HOLDING: authctx */
    /* Get an authenticator so we can get the keyblock */
    result = krb5_auth_con_getauthenticator (Z_krb5_ctx, authctx,
    					     &authenticator);
    if (result) {
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        syslog(LOG_WARNING, "ZCheckSrvAuthentication: krb5_auth_con_getauthenticator failed: %s",
               error_message(result));
        return ZAUTH_FAILED;
    }

    /* HOLDING: authctx, authenticator */
    result = krb5_auth_con_getkey(Z_krb5_ctx, authctx, &keyblock);
    if (result) {
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
        syslog(LOG_WARNING, "ZCheckSrvAuthentication: krb5_auth_con_getkey failed: %s",
               error_message(result));
        return (ZAUTH_FAILED);
    }

    /* HOLDING: authctx, authenticator, keyblock */
    /* Figure out what checksum type to use */
    key_data = Z_keydata(keyblock);
    key_len = Z_keylen(keyblock);
    result = Z_ExtractEncCksum(keyblock, &enctype, &cksumtype);
    if (result) {
        krb5_free_keyblock(Z_krb5_ctx, keyblock);
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
        syslog(LOG_WARNING, "ZCheckSrvAuthentication: Z_ExtractEncCksum failed: %s",
               error_message(result));
        return (ZAUTH_FAILED);
    }
    /* HOLDING: authctx, authenticator, keyblock */

    if (realm == NULL)
	ZSetSession(keyblock);

    /* Assemble the things to be checksummed */
    /* first part is from start of packet through z_default_format:
     * - z_version
     * - z_num_other_fields
     * - z_kind
     * - z_uid
     * - z_port
     * - z_auth
     * - z_authent_len
     * - z_ascii_authent
     * - z_class
     * - z_class_inst
     * - z_opcode
     * - z_sender
     * - z_recipient
     * - z_default_format
     */
    cksum0_base = notice->z_packet;
    x           = notice->z_default_format;
    cksum0_len  = x + strlen(x) + 1 - cksum0_base;
    /* second part is from z_multinotice through other fields:
     * - z_multinotice
     * - z_multiuid
     * - z_sender_(sock)addr
     * - z_charset
     * - z_other_fields[]
     */
    if (notice->z_num_hdr_fields > 15 ) {
	cksum1_base = notice->z_multinotice;
	if (notice->z_num_other_fields)
	    x = notice->z_other_fields[notice->z_num_other_fields - 1];
	else {
	    /* see also ZCheckRealmAuthentication
	       and lib/ZCkZaut.c:ZCheckZcodeAuthentication  */
	    /* XXXXXXXXXXXXXXXXXXXXXXX */
	    if (notice->z_num_hdr_fields > 16)
		x = cksum1_base + strlen(cksum1_base) + 1; /* multinotice */
	    if (notice->z_num_hdr_fields > 17)
		x = x + strlen(x) + 1; /* multiuid */
	    if (notice->z_num_hdr_fields > 18)
		x = x + strlen(x) + 1; /* sender */
	}
	cksum1_len  = x + strlen(x) + 1 - cksum1_base; /* charset / extra field */
    }

    /* last part is the message body */
    cksum2_base = notice->z_message;
    cksum2_len  = notice->z_message_len;

    /*XXX we may wish to ditch this code someday?*/
    if ((!notice->z_ascii_checksum || *notice->z_ascii_checksum != 'Z') &&
        key_len == 8 &&
        (enctype == (krb5_enctype)ENCTYPE_DES_CBC_CRC ||
         enctype == (krb5_enctype)ENCTYPE_DES_CBC_MD4 ||
         enctype == (krb5_enctype)ENCTYPE_DES_CBC_MD5)) {
      /* try old-format checksum (covers cksum0 only) */

      ZChecksum_t our_checksum;

      if (realm == NULL)
	  our_checksum = compute_checksum(notice, key_data);
      else
	  our_checksum = compute_rlm_checksum(notice, key_data);

      krb5_free_keyblock(Z_krb5_ctx, keyblock);
      krb5_auth_con_free(Z_krb5_ctx, authctx);
      krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);

      if (our_checksum == notice->z_checksum) {
          return ZAUTH_YES;
      } else {
          syslog(LOG_DEBUG, "ZCheckSrvAuthentication: des quad checksum mismatch");
          return ZAUTH_FAILED;
      }
    }

    /* HOLDING: authctx, authenticator */

    cksumbuf.length = cksum0_len + cksum1_len + cksum2_len;
    cksumbuf.data = malloc(cksumbuf.length);
    if (!cksumbuf.data) {
        krb5_free_keyblock(Z_krb5_ctx, keyblock);
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
        syslog(LOG_ERR, "ZCheckSrvAuthentication: malloc(cksumbuf.data): %m");
        return ZAUTH_FAILED;
    }
    /* HOLDING: authctx, authenticator, cksumbuf.data */

    cksum_data = (unsigned char *)cksumbuf.data;
    memcpy(cksum_data, cksum0_base, cksum0_len);
    if (cksum1_len)
	memcpy(cksum_data + cksum0_len, cksum1_base, cksum1_len);
    memcpy(cksum_data + cksum0_len + cksum1_len,
           cksum2_base, cksum2_len);

    /* decode zcoded checksum */
    /* The encoded form is always longer than the original */
    asn1_len = strlen(notice->z_ascii_checksum) + 1;
    asn1_data = malloc(asn1_len);
    if (!asn1_data) {
        krb5_free_keyblock(Z_krb5_ctx, keyblock);
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
        free(cksumbuf.data);
        syslog(LOG_ERR, "ZCheckSrvAuthentication: malloc(asn1_data): %m");
        return ZAUTH_FAILED;
    }
    /* HOLDING: authctx, authenticator, cksumbuf.data, asn1_data */
    result = ZReadZcode((unsigned char *)notice->z_ascii_checksum,
                        asn1_data, asn1_len, &asn1_len);
    if (result != ZERR_NONE) {
        krb5_free_keyblock(Z_krb5_ctx, keyblock);
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
        free(asn1_data);
        free(cksumbuf.data);
        syslog(LOG_WARNING, "ZCheckSrvAuthentication: ZReadZcode: %s",
               error_message(result));
        return ZAUTH_FAILED;
    }
    /* HOLDING: asn1_data, cksumbuf.data, authctx, authenticator */

    valid = Z_krb5_verify_cksum(keyblock, &cksumbuf, cksumtype,
				Z_KEYUSAGE_CLT_CKSUM,
				asn1_data, asn1_len);

    /* XXX compatibility with unreleased interrealm krb5; drop in 3.1 */
    if (!valid && realm)
	valid = Z_krb5_verify_cksum(keyblock, &cksumbuf, cksumtype,
				    Z_KEYUSAGE_SRV_CKSUM,
				    asn1_data, asn1_len);

    free(asn1_data);
    krb5_auth_con_free(Z_krb5_ctx, authctx);
    krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
    krb5_free_keyblock(Z_krb5_ctx, keyblock);
    free(cksumbuf.data);

    if (valid) {
        return ZAUTH_YES;
    } else {
        syslog(LOG_DEBUG, "ZCheckSrvAuthentication: Z_krb5_verify_cksum: failed");
        return ZAUTH_FAILED;
    }
#else
    return (notice->z_auth) ? ZAUTH_YES : ZAUTH_NO;
#endif
}
Esempio n. 17
0
static void
process (krb5_realm *realms,
         krb5_keytab keytab,
         int s,
         krb5_address *this_addr,
         struct sockaddr *sa,
         int sa_size,
         u_char *msg,
         int len)
{
    krb5_error_code ret;
    krb5_auth_context auth_context = NULL;
    krb5_data out_data;
    krb5_ticket *ticket;
    krb5_address other_addr;
    uint16_t version;

    memset(&other_addr, 0, sizeof(other_addr));
    krb5_data_zero (&out_data);

    ret = krb5_auth_con_init (context, &auth_context);
    if (ret) {
        krb5_warn (context, ret, "krb5_auth_con_init");
        return;
    }

    krb5_auth_con_setflags (context, auth_context,
                            KRB5_AUTH_CONTEXT_DO_SEQUENCE);

    ret = krb5_sockaddr2address (context, sa, &other_addr);
    if (ret) {
        krb5_warn (context, ret, "krb5_sockaddr2address");
        goto out;
    }

    ret = krb5_auth_con_setaddrs (context, auth_context, this_addr, NULL);
    if (ret) {
        krb5_warn (context, ret, "krb5_auth_con_setaddr(this)");
        goto out;
    }

    if (verify (&auth_context, realms, keytab, &ticket, &out_data,
                &version, s, sa, sa_size, msg, len, &other_addr) == 0)
    {
        /*
         * We always set the client_addr, to assume that the client
         * can ignore it if it choose to do so (just the server does
         * so for addressless tickets).
         */
        ret = krb5_auth_con_setaddrs (context, auth_context,
                                      this_addr, &other_addr);
        if (ret) {
            krb5_warn (context, ret, "krb5_auth_con_setaddr(other)");
            goto out;
        }

        change (auth_context,
                ticket->client,
                version,
                s,
                sa, sa_size,
                &out_data);
        memset (out_data.data, 0, out_data.length);
        krb5_free_ticket (context, ticket);
    }

out:
    krb5_free_address(context, &other_addr);
    krb5_data_free(&out_data);
    krb5_auth_con_free(context, auth_context);
}
Esempio n. 18
0
NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
			   const char *realm,
			   time_t time_offset,
			   const DATA_BLOB *ticket,
			   char **principal,
			   struct PAC_DATA **pac_data,
			   DATA_BLOB *ap_rep,
			   DATA_BLOB *session_key,
			   bool use_replay_cache)
{
	NTSTATUS sret = NT_STATUS_LOGON_FAILURE;
	NTSTATUS pac_ret;
	DATA_BLOB auth_data;
	krb5_context context = NULL;
	krb5_auth_context auth_context = NULL;
	krb5_data packet;
	krb5_ticket *tkt = NULL;
	krb5_rcache rcache = NULL;
	krb5_keyblock *keyblock = NULL;
	time_t authtime;
	krb5_error_code ret = 0;
	int flags = 0;	
	krb5_principal host_princ = NULL;
	krb5_const_principal client_principal = NULL;
	char *host_princ_s = NULL;
	bool auth_ok = False;
	bool got_auth_data = False;
	struct named_mutex *mutex = NULL;

	ZERO_STRUCT(packet);
	ZERO_STRUCT(auth_data);

	*principal = NULL;
	*pac_data = NULL;
	*ap_rep = data_blob_null;
	*session_key = data_blob_null;

	initialize_krb5_error_table();
	ret = krb5_init_context(&context);
	if (ret) {
		DEBUG(1,("ads_verify_ticket: krb5_init_context failed (%s)\n", error_message(ret)));
		return NT_STATUS_LOGON_FAILURE;
	}

	if (time_offset != 0) {
		krb5_set_real_time(context, time(NULL) + time_offset, 0);
	}

	ret = krb5_set_default_realm(context, realm);
	if (ret) {
		DEBUG(1,("ads_verify_ticket: krb5_set_default_realm failed (%s)\n", error_message(ret)));
		goto out;
	}

	/* This whole process is far more complex than I would
           like. We have to go through all this to allow us to store
           the secret internally, instead of using /etc/krb5.keytab */

	ret = krb5_auth_con_init(context, &auth_context);
	if (ret) {
		DEBUG(1,("ads_verify_ticket: krb5_auth_con_init failed (%s)\n", error_message(ret)));
		goto out;
	}

	krb5_auth_con_getflags( context, auth_context, &flags );
	if ( !use_replay_cache ) {
		/* Disable default use of a replay cache */
		flags &= ~KRB5_AUTH_CONTEXT_DO_TIME;
		krb5_auth_con_setflags( context, auth_context, flags );
	}

	if (asprintf(&host_princ_s, "%s$", global_myname()) == -1) {
		goto out;
	}

	strlower_m(host_princ_s);
	ret = smb_krb5_parse_name(context, host_princ_s, &host_princ);
	if (ret) {
		DEBUG(1,("ads_verify_ticket: smb_krb5_parse_name(%s) failed (%s)\n",
					host_princ_s, error_message(ret)));
		goto out;
	}


	if ( use_replay_cache ) {
		
		/* Lock a mutex surrounding the replay as there is no 
		   locking in the MIT krb5 code surrounding the replay 
		   cache... */

		mutex = grab_named_mutex(talloc_tos(), "replay cache mutex",
					 10);
		if (mutex == NULL) {
			DEBUG(1,("ads_verify_ticket: unable to protect "
				 "replay cache with mutex.\n"));
			ret = KRB5_CC_IO;
			goto out;
		}

		/* JRA. We must set the rcache here. This will prevent 
		   replay attacks. */
		
		ret = krb5_get_server_rcache(context, 
					     krb5_princ_component(context, host_princ, 0), 
					     &rcache);
		if (ret) {
			DEBUG(1,("ads_verify_ticket: krb5_get_server_rcache "
				 "failed (%s)\n", error_message(ret)));
			goto out;
		}

		ret = krb5_auth_con_setrcache(context, auth_context, rcache);
		if (ret) {
			DEBUG(1,("ads_verify_ticket: krb5_auth_con_setrcache "
				 "failed (%s)\n", error_message(ret)));
			goto out;
		}
	}

	/* Try secrets.tdb first and fallback to the krb5.keytab if
	   necessary */

	auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ,
					    ticket, &tkt, &keyblock, &ret);

	if (!auth_ok &&
	    (ret == KRB5KRB_AP_ERR_TKT_NYV ||
	     ret == KRB5KRB_AP_ERR_TKT_EXPIRED ||
	     ret == KRB5KRB_AP_ERR_SKEW)) {
		goto auth_failed;
	}

	if (!auth_ok && lp_use_kerberos_keytab()) {
		auth_ok = ads_keytab_verify_ticket(context, auth_context, 
						   ticket, &tkt, &keyblock, &ret);
	}

	if ( use_replay_cache ) {		
		TALLOC_FREE(mutex);
#if 0
		/* Heimdal leaks here, if we fix the leak, MIT crashes */
		if (rcache) {
			krb5_rc_close(context, rcache);
		}
#endif
	}	

 auth_failed:
	if (!auth_ok) {
		DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n", 
			 error_message(ret)));
		/* Try map the error return in case it's something like
		 * a clock skew error.
		 */
		sret = krb5_to_nt_status(ret);
		if (NT_STATUS_IS_OK(sret) || NT_STATUS_EQUAL(sret,NT_STATUS_UNSUCCESSFUL)) {
			sret = NT_STATUS_LOGON_FAILURE;
		}
		DEBUG(10,("ads_verify_ticket: returning error %s\n",
			nt_errstr(sret) ));
		goto out;
	} 
	
	authtime = get_authtime_from_tkt(tkt);
	client_principal = get_principal_from_tkt(tkt);

	ret = krb5_mk_rep(context, auth_context, &packet);
	if (ret) {
		DEBUG(3,("ads_verify_ticket: Failed to generate mutual authentication reply (%s)\n",
			error_message(ret)));
		goto out;
	}

	*ap_rep = data_blob(packet.data, packet.length);
	if (packet.data) {
		kerberos_free_data_contents(context, &packet);
		ZERO_STRUCT(packet);
	}

	get_krb5_smb_session_key(context, auth_context, session_key, True);
	dump_data_pw("SMB session key (from ticket)\n", session_key->data, session_key->length);

#if 0
	file_save("/tmp/ticket.dat", ticket->data, ticket->length);
#endif

	/* continue when no PAC is retrieved or we couldn't decode the PAC 
	   (like accounts that have the UF_NO_AUTH_DATA_REQUIRED flag set, or
	   Kerberos tickets encrypted using a DES key) - Guenther */

	got_auth_data = get_auth_data_from_tkt(mem_ctx, &auth_data, tkt);
	if (!got_auth_data) {
		DEBUG(3,("ads_verify_ticket: did not retrieve auth data. continuing without PAC\n"));
	}

	if (got_auth_data) {
		pac_ret = decode_pac_data(mem_ctx, &auth_data, context, keyblock, client_principal, authtime, pac_data);
		if (!NT_STATUS_IS_OK(pac_ret)) {
			DEBUG(3,("ads_verify_ticket: failed to decode PAC_DATA: %s\n", nt_errstr(pac_ret)));
			*pac_data = NULL;
		}
		data_blob_free(&auth_data);
	}

#if 0
#if defined(HAVE_KRB5_TKT_ENC_PART2)
	/* MIT */
	if (tkt->enc_part2) {
		file_save("/tmp/authdata.dat",
			  tkt->enc_part2->authorization_data[0]->contents,
			  tkt->enc_part2->authorization_data[0]->length);
	}
#else
	/* Heimdal */
	if (tkt->ticket.authorization_data) {
		file_save("/tmp/authdata.dat",
			  tkt->ticket.authorization_data->val->ad_data.data,
			  tkt->ticket.authorization_data->val->ad_data.length);
	}
#endif
#endif

	if ((ret = smb_krb5_unparse_name(context, client_principal, principal))) {
		DEBUG(3,("ads_verify_ticket: smb_krb5_unparse_name failed (%s)\n", 
			 error_message(ret)));
		sret = NT_STATUS_LOGON_FAILURE;
		goto out;
	}

	sret = NT_STATUS_OK;

 out:

	TALLOC_FREE(mutex);

	if (!NT_STATUS_IS_OK(sret)) {
		data_blob_free(&auth_data);
	}

	if (!NT_STATUS_IS_OK(sret)) {
		data_blob_free(ap_rep);
	}

	if (host_princ) {
		krb5_free_principal(context, host_princ);
	}

	if (keyblock) {
		krb5_free_keyblock(context, keyblock);
	}

	if (tkt != NULL) {
		krb5_free_ticket(context, tkt);
	}

	SAFE_FREE(host_princ_s);

	if (auth_context) {
		krb5_auth_con_free(context, auth_context);
	}

	if (context) {
		krb5_free_context(context);
	}

	return sret;
}
Esempio n. 19
0
static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security, bool gssapi)
{
	krb5_error_code ret;
	struct gensec_krb5_state *gensec_krb5_state;
	struct cli_credentials *creds;
	const struct tsocket_address *tlocal_addr, *tremote_addr;
	krb5_address my_krb5_addr, peer_krb5_addr;
	
	creds = gensec_get_credentials(gensec_security);
	if (!creds) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	gensec_krb5_state = talloc(gensec_security, struct gensec_krb5_state);
	if (!gensec_krb5_state) {
		return NT_STATUS_NO_MEMORY;
	}

	gensec_security->private_data = gensec_krb5_state;
	gensec_krb5_state->smb_krb5_context = NULL;
	gensec_krb5_state->auth_context = NULL;
	gensec_krb5_state->ticket = NULL;
	ZERO_STRUCT(gensec_krb5_state->enc_ticket);
	gensec_krb5_state->keyblock = NULL;
	gensec_krb5_state->gssapi = gssapi;

	talloc_set_destructor(gensec_krb5_state, gensec_krb5_destroy); 

	if (cli_credentials_get_krb5_context(creds, 
					     gensec_security->settings->lp_ctx, &gensec_krb5_state->smb_krb5_context)) {
		talloc_free(gensec_krb5_state);
		return NT_STATUS_INTERNAL_ERROR;
	}

	ret = krb5_auth_con_init(gensec_krb5_state->smb_krb5_context->krb5_context, &gensec_krb5_state->auth_context);
	if (ret) {
		DEBUG(1,("gensec_krb5_start: krb5_auth_con_init failed (%s)\n", 
			 smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
						    ret, gensec_krb5_state)));
		talloc_free(gensec_krb5_state);
		return NT_STATUS_INTERNAL_ERROR;
	}

	ret = krb5_auth_con_setflags(gensec_krb5_state->smb_krb5_context->krb5_context, 
				     gensec_krb5_state->auth_context,
				     KRB5_AUTH_CONTEXT_DO_SEQUENCE);
	if (ret) {
		DEBUG(1,("gensec_krb5_start: krb5_auth_con_setflags failed (%s)\n", 
			 smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
						    ret, gensec_krb5_state)));
		talloc_free(gensec_krb5_state);
		return NT_STATUS_INTERNAL_ERROR;
	}

	tlocal_addr = gensec_get_local_address(gensec_security);
	if (tlocal_addr) {
		ssize_t socklen;
		struct sockaddr_storage ss;

		socklen = tsocket_address_bsd_sockaddr(tlocal_addr,
				(struct sockaddr *) &ss,
				sizeof(struct sockaddr_storage));
		if (socklen < 0) {
			talloc_free(gensec_krb5_state);
			return NT_STATUS_INTERNAL_ERROR;
		}
		ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context,
				(const struct sockaddr *) &ss, &my_krb5_addr);
		if (ret) {
			DEBUG(1,("gensec_krb5_start: krb5_sockaddr2address (local) failed (%s)\n", 
				 smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
							    ret, gensec_krb5_state)));
			talloc_free(gensec_krb5_state);
			return NT_STATUS_INTERNAL_ERROR;
		}
	}

	tremote_addr = gensec_get_remote_address(gensec_security);
	if (tremote_addr) {
		ssize_t socklen;
		struct sockaddr_storage ss;

		socklen = tsocket_address_bsd_sockaddr(tremote_addr,
				(struct sockaddr *) &ss,
				sizeof(struct sockaddr_storage));
		if (socklen < 0) {
			talloc_free(gensec_krb5_state);
			return NT_STATUS_INTERNAL_ERROR;
		}
		ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context,
				(const struct sockaddr *) &ss, &peer_krb5_addr);
		if (ret) {
			DEBUG(1,("gensec_krb5_start: krb5_sockaddr2address (local) failed (%s)\n", 
				 smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
							    ret, gensec_krb5_state)));
			talloc_free(gensec_krb5_state);
			return NT_STATUS_INTERNAL_ERROR;
		}
	}

	ret = krb5_auth_con_setaddrs(gensec_krb5_state->smb_krb5_context->krb5_context, 
				     gensec_krb5_state->auth_context,
				     tlocal_addr ? &my_krb5_addr : NULL,
				     tremote_addr ? &peer_krb5_addr : NULL);
	if (ret) {
		DEBUG(1,("gensec_krb5_start: krb5_auth_con_setaddrs failed (%s)\n", 
			 smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
						    ret, gensec_krb5_state)));
		talloc_free(gensec_krb5_state);
		return NT_STATUS_INTERNAL_ERROR;
	}

	return NT_STATUS_OK;
}
Esempio n. 20
0
int auks_cred_init(auks_cred_t * credential, char *data, size_t length)
{
	int fstatus = AUKS_ERROR ;

	char *tmp_string = NULL;
	size_t tmp_size = 0;

	/* kerberos related variables */
	krb5_error_code err_code;
	krb5_context context;
	krb5_auth_context auth_context;
	krb5_data kdata;
	krb5_creds **creds;
	krb5_replay_data krdata;

	char username[AUKS_PRINCIPAL_MAX_LENGTH + 1];
	struct passwd user_pwent;
	struct passwd *p_pwent;
	size_t pwnam_buffer_length = sysconf(_SC_GETPW_R_SIZE_MAX);
	char pwnam_buffer[pwnam_buffer_length];

	credential->info.principal[0] = '\0';
	credential->info.uid = AUKS_CRED_INVALID_UID;

	credential->info.starttime = AUKS_CRED_INVALID_TIME;
	credential->info.endtime = AUKS_CRED_INVALID_TIME;
	credential->info.renew_till = AUKS_CRED_INVALID_TIME;

	credential->info.addressless = 1;

	credential->data[1] = '\0';
	credential->length = 0;
	credential->max_length = AUKS_CRED_DATA_MAX_LENGTH;
	credential->status = AUKS_SUCCESS;

	/* check input buffer length versus auks credential internal buffer */
	/* max length */
	if ((unsigned int) length > (unsigned int) credential->max_length) {
		auks_error("input buffer is bigger than auks credential internal "
			   "buffer (%u versus %u)",length, credential->max_length);
		fstatus = AUKS_ERROR_CRED_INIT_BUFFER_TOO_LARGE ;
		goto exit;
	}

	/* extract informations from buffer */
	if (data == NULL) {
		auks_error("input buffer is NULL");
		fstatus = AUKS_ERROR_CRED_INIT_BUFFER_IS_NULL ;
		goto exit;
	}
	fstatus = AUKS_ERROR ;

	/* initialize kerberos context */
	err_code = krb5_init_context(&context);
	if (err_code) {
		auks_error("unable to initialize kerberos context : %s",
			   error_message(err_code));
		fstatus = AUKS_ERROR_CRED_INIT_KRB_CTX_INIT ;
		goto exit;
	}
	auks_log("kerberos context successfully initialized");

	/* initialize a nullified kerberos authentication context 
	   in order to decode credential from buffer */
	err_code =
		krb5_auth_con_init(context,&auth_context);
	if (err_code) {
		auks_error("unable to initialize connection "
			   "authentication context : %s",
			   error_message(err_code));
		fstatus = AUKS_ERROR_CRED_INIT_KRB_AUTH_CTX_INIT ;
		goto ctx_exit;
	}
	
	/* clear kerberos authentication context flags */
	krb5_auth_con_setflags(context,auth_context,0);
	/* set a kerberos data structure with input buffer */
	kdata.data = data ;
	kdata.length = (unsigned int) length ;

	/* build kerberos credential structure using this data structure */
	err_code = krb5_rd_cred(context,auth_context,&kdata, &creds,&krdata);
	if (err_code) {
		auks_error("unable to deserialize input buffer credential : %s",
			   error_message(err_code));
		fstatus = AUKS_ERROR_CRED_INIT_KRB_RD_BUFFER ;
		goto auth_ctx_exit;
	}

	auks_log("input buffer credential successfully unserialized");
	err_code = krb5_unparse_name_ext(context,(*creds)->client,&tmp_string,
					 (unsigned int *) &tmp_size);
	if (err_code) {
		auks_error("unable to unparse principal : %s",
			   error_message(err_code));
		fstatus = AUKS_ERROR_CRED_INIT_KRB_RD_PRINC ;
		goto creds_exit;
	} else if (tmp_size > AUKS_PRINCIPAL_MAX_LENGTH) {
		auks_error("unable to unparse principal : %s",
			   "principal is too long (more than %d characters)",
			   AUKS_PRINCIPAL_MAX_LENGTH);
		free(tmp_string);
		fstatus = AUKS_ERROR_CRED_INIT_KRB_PRINC_TOO_LONG ;
		goto creds_exit;
	}
	auks_log("principal successfully unparse");
	memcpy(credential->info.principal,tmp_string,tmp_size);
	credential->info.principal[tmp_size] = '\0';
	/* associated username from principal */
	err_code = krb5_aname_to_localname(context,(*creds)->client,
					   AUKS_PRINCIPAL_MAX_LENGTH,username);
	if (err_code) {
		auks_error("unable to get username from principal %s : %s",
			   credential->info.principal,error_message(err_code));
		fstatus = AUKS_ERROR_CRED_INIT_KRB_PRINC_TO_UNAME ;
		goto string_exit;
	}

	/* associated uid from username */
	fstatus = getpwnam_r(username,&user_pwent,pwnam_buffer,
			     pwnam_buffer_length,&p_pwent) ;
	if (fstatus) {
		auks_log("unable to get %s pwnam entry : %s",username,
			 strerror(fstatus)) ;
		fstatus = AUKS_ERROR_CRED_INIT_GETPWNAM ;
		goto string_exit;
	}

	/* uid information */
	credential->info.uid = user_pwent.pw_uid;

	credential->info.starttime = (time_t) (*creds)->times.starttime ;
	credential->info.endtime = (time_t) (*creds)->times.endtime ;
	credential->info.renew_till = (time_t) (*creds)->times.renew_till ;

	/* addresslessness */
	if (((*creds)->addresses) != NULL)
		credential->info.addressless = 0;

	/* duplicate input buffer */
	credential->length = (unsigned int) length;
	memcpy(credential->data,data,(unsigned int) length);

	fstatus = AUKS_SUCCESS;

string_exit:
	free(tmp_string);

creds_exit:
	krb5_free_creds(context,*creds);
	free(creds);

auth_ctx_exit:
	krb5_auth_con_free(context,auth_context);

ctx_exit:
	krb5_free_context(context);

exit:
	/* if valid buffer, store it */
	if (fstatus != 0) {
		/* bad credential buffer in input, clean this auks credential */
		auks_cred_free_contents(credential);
	}
	
	return fstatus;
}
Esempio n. 21
0
static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security, bool gssapi)
{
	krb5_error_code ret;
	struct gensec_krb5_state *gensec_krb5_state;
	struct cli_credentials *creds;
	const struct socket_address *my_addr, *peer_addr;
	krb5_address my_krb5_addr, peer_krb5_addr;
	
	creds = gensec_get_credentials(gensec_security);
	if (!creds) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	gensec_krb5_state = talloc(gensec_security, struct gensec_krb5_state);
	if (!gensec_krb5_state) {
		return NT_STATUS_NO_MEMORY;
	}

	gensec_security->private_data = gensec_krb5_state;
	gensec_krb5_state->smb_krb5_context = NULL;
	gensec_krb5_state->auth_context = NULL;
	gensec_krb5_state->ticket = NULL;
	ZERO_STRUCT(gensec_krb5_state->enc_ticket);
	gensec_krb5_state->keyblock = NULL;
	gensec_krb5_state->session_key = data_blob(NULL, 0);
	gensec_krb5_state->pac = data_blob(NULL, 0);
	gensec_krb5_state->gssapi = gssapi;

	talloc_set_destructor(gensec_krb5_state, gensec_krb5_destroy); 

	if (cli_credentials_get_krb5_context(creds, 
					     gensec_security->event_ctx, 
					     gensec_security->settings->lp_ctx, &gensec_krb5_state->smb_krb5_context)) {
		talloc_free(gensec_krb5_state);
		return NT_STATUS_INTERNAL_ERROR;
	}

	ret = krb5_auth_con_init(gensec_krb5_state->smb_krb5_context->krb5_context, &gensec_krb5_state->auth_context);
	if (ret) {
		DEBUG(1,("gensec_krb5_start: krb5_auth_con_init failed (%s)\n", 
			 smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
						    ret, gensec_krb5_state)));
		talloc_free(gensec_krb5_state);
		return NT_STATUS_INTERNAL_ERROR;
	}

	ret = krb5_auth_con_setflags(gensec_krb5_state->smb_krb5_context->krb5_context, 
				     gensec_krb5_state->auth_context,
				     KRB5_AUTH_CONTEXT_DO_SEQUENCE);
	if (ret) {
		DEBUG(1,("gensec_krb5_start: krb5_auth_con_setflags failed (%s)\n", 
			 smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
						    ret, gensec_krb5_state)));
		talloc_free(gensec_krb5_state);
		return NT_STATUS_INTERNAL_ERROR;
	}

	my_addr = gensec_get_my_addr(gensec_security);
	if (my_addr && my_addr->sockaddr) {
		ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context, 
					    my_addr->sockaddr, &my_krb5_addr);
		if (ret) {
			DEBUG(1,("gensec_krb5_start: krb5_sockaddr2address (local) failed (%s)\n", 
				 smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
							    ret, gensec_krb5_state)));
			talloc_free(gensec_krb5_state);
			return NT_STATUS_INTERNAL_ERROR;
		}
	}

	peer_addr = gensec_get_peer_addr(gensec_security);
	if (peer_addr && peer_addr->sockaddr) {
		ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context, 
					    peer_addr->sockaddr, &peer_krb5_addr);
		if (ret) {
			DEBUG(1,("gensec_krb5_start: krb5_sockaddr2address (local) failed (%s)\n", 
				 smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
							    ret, gensec_krb5_state)));
			talloc_free(gensec_krb5_state);
			return NT_STATUS_INTERNAL_ERROR;
		}
	}

	ret = krb5_auth_con_setaddrs(gensec_krb5_state->smb_krb5_context->krb5_context, 
				     gensec_krb5_state->auth_context,
				     my_addr ? &my_krb5_addr : NULL, 
				     peer_addr ? &peer_krb5_addr : NULL);
	if (ret) {
		DEBUG(1,("gensec_krb5_start: krb5_auth_con_setaddrs failed (%s)\n", 
			 smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
						    ret, gensec_krb5_state)));
		talloc_free(gensec_krb5_state);
		return NT_STATUS_INTERNAL_ERROR;
	}

	return NT_STATUS_OK;
}
Esempio n. 22
0
int main(int argc, char **argv)
{
	int log_level = 0;
	char *data_str;
	char *ap_req_str = NULL;
	unsigned char *data;
	size_t data_len;

	/* krb5 */
	krb5_error_code ret;
	krb5_context context;
	krb5_auth_context auth_context;
	char *princ_str_tn = "kink/tn.example.com";
	krb5_principal princ_tn;
	char *princ_str_nut = "kink/nut.example.com";
	krb5_principal princ_nut;
	char *princ_str_krbtgt = "krbtgt/EXAMPLE.COM";
	krb5_principal princ_krbtgt;
	krb5_ccache ccache;
	krb5_keytab keytab;
	krb5_creds creds_tgt;
	krb5_data ap_req;

	prog = (const char *) basename(argv[0]);
	if (prog == NULL) {
		fprintf(stderr,
			"basename: %s -- %s\n", strerror(errno), argv[0]);

		return(0);
		/* NOTREACHED */
	}

	{
		int ch = 0;

		while ((ch = getopt(argc, argv, "dq:")) != -1) {
			switch (ch) {
			case 'd':
				log_level++;
				break;
			case 'q':
				ap_req_str = optarg;
				break;
			default:
				usage();
				/* NOTREACHED */

				break;
			}
		}

		argc -= optind;
		argv += optind;
	}

	if (!argc) {
		usage();
		/* NOTREACHED */
	}
	data_str = argv[0];

	{
		printf("dbg: %s starts arg(%s)\n", prog, data_str);
	}

	{
		{ /* stdout */
			printf("std:data:%s\n", data_str);
		}
		data_len = strlen(data_str);
		data_len = data_len/2 + data_len%2;
		data = (unsigned char *)malloc(data_len);
		memset(data, 0, data_len);
		data = hex2data(data_str, data);
	}

	if (ap_req_str != NULL) {
		hex2krb5data(ap_req_str, &ap_req);
		if (log_level) {
			dump_krb5_data(&ap_req);
		}
		{ /* stdout */
			int i = 0;
			unsigned char *p;
			p = (unsigned char *)ap_req.data;
			printf("std:ap_req:");
			for (i = 0; i < ap_req.length; i++) {
				printf("%02x", *p++);
			}
			printf("\n");
		}
	}

	/* prepare krb5 context */
	{
		/** init context */
		ret = krb5_init_context(&context);
		if (ret != 0) {
			printf("ERR:krb5_init_context:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		/** setup principals */
		ret = krb5_parse_name(context, princ_str_tn, &princ_tn);
		if (ret != 0) {
			printf("ERR:krb5_parse_name:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}
		ret = krb5_parse_name(context, princ_str_nut, &princ_nut);
		if (ret != 0) {
			printf("ERR:krb5_parse_name:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}
		ret = krb5_parse_name(context, princ_str_krbtgt, &princ_krbtgt);
		if (ret != 0) {
			printf("ERR:krb5_parse_name:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		/** prepare credential cache */
		ret = krb5_cc_default(context, &ccache);
		if (ret != 0) {
			printf("ERR:krb5_cc_default:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		/** prepare keytab */
		/*ret = krb5_kt_resolve(context, "/usr/local/var/krb5kdc/kadm5.keytab", &keytab);*/
		ret = krb5_kt_default(context, &keytab);
		if (ret != 0) {
			/* printf("ERR:krb5_kt_default:%s", krb5_get_err_text(context, ret)); */
			printf("ERR:krb5_kt_resolve:%s", krb5_get_err_text(context, ret));
			return(ret);
		}

	}

	/* get TGT */
	{
		krb5_creds mcreds;
		memset(&mcreds, 0, sizeof(mcreds));
		mcreds.client = princ_tn;
		mcreds.server = princ_krbtgt;

		ret = krb5_cc_retrieve_cred(context, ccache, 0, &mcreds, &creds_tgt);
		if (ret != 0) {
			printf("ERR:krb5_cc_retrieve_cred:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}
	}

	/* prepare authentiation context */
	{
		ret = krb5_auth_con_init(context, &auth_context);
		if (ret != 0) {
			printf("ERR:krb5_auth_con_init:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		ret = krb5_auth_con_setflags(context, auth_context,
					     KRB5_AUTH_CONTEXT_DO_SEQUENCE);
		if (ret != 0) {
			printf("ERR:krb5_auth_con_setflags:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		/* if USE_SKEY */
		/*
		ret = krb5_auth_con_setuserkey(context, auth_context, &creds_tgt.session);
		if (ret != 0) {
			printf("ERR:krb5_auth_con_setuseruserkey:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}
		*/
	}

	/* set keyblock in auth_context */
	if (ap_req_str != NULL) {
		krb5_ticket *ticket;
		krb5_flags ap_req_options;
		
		ap_req_options = AP_OPTS_MUTUAL_REQUIRED;
		ticket = NULL;
		ret = krb5_rd_req(context,
				  &auth_context,
				  &ap_req,
				  NULL,
				  keytab,
				  &ap_req_options,
				  &ticket);
		if (log_level) {
			printf("info: ticket.ticket.key is SKEYID_d\n");
			/*dump_krb5_ticket(context, *ticket);*/
		}
		if (log_level) {
			printf("ap_req_opt (%d)\n", ap_req_options);
		}
		if (ret != 0) {
			printf("ERR:krb5_rd_req:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}
		if (log_level) {
			dump_krb5_keyblock(auth_context->keyblock);
		}

		krb5_free_ticket(context, ticket);
	}
	else {
		krb5_creds mcreds;
		krb5_creds *cred;
		krb5_creds cred_copy;

		memset(&mcreds, 0, sizeof(mcreds));
		mcreds.client = princ_tn;
		mcreds.server = princ_nut;

		ret = krb5_get_credentials(context, KRB5_GC_CACHED, ccache, &mcreds, &cred);
		if (ret != 0) {
			printf("ERR:krb5_get_credentials:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		/* mk_req_extends reallocate cred, so use a copy */
		ret = krb5_copy_creds_contents(context,
					       (const krb5_creds *)cred,
					       &cred_copy);
		if (ret != 0) {
			printf("ERR:krb5_copy_creds_contents:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		/*
		 * If auth_con == NULL, one is allocated.
		 * This is used later. (keyblock is used to decrypt AP_REP)
		 */
		ret = krb5_mk_req_extended(context, &auth_context,
					   AP_OPTS_MUTUAL_REQUIRED,
					   NULL /* in_data */,
					   &cred_copy,
					   &ap_req);
		if (ret != 0) {
			printf("ERR:krb5_mk_req_extended:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}
	}

	/* create checksum */
	{
		krb5_crypto crypto;
		krb5_checksum cksum;

		ret = krb5_crypto_init(context,
				       auth_context->keyblock,
				       auth_context->keyblock->keytype,
				       &crypto);
		if (ret != 0) {
			printf("ERR:krb5_crypto_init:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		if (0) {
			dump_krb5_keyblock(auth_context->keyblock);
		}
		ret = krb5_create_checksum(context,
					   crypto,
					   40,
					   0 /* krb5_cksumtype type */,
					   data,
					   data_len,
					   &cksum);
		if (ret != 0) {
			printf("ERR:krb5_create_checksum:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}
		if (log_level) {
			dump_krb5_checksum(cksum);
		}
		{ /* stdout */
			int i = 0;
			unsigned char *p;
			p = (unsigned char *)cksum.checksum.data;
			printf("std:cksum:");
			for (i = 0; i < cksum.checksum.length; i++) {
				printf("%02x", *p++);
			}
			printf("\n");
		}

		krb5_crypto_destroy(context, crypto);
	}

	/* clenaup */
	{
		/*free(data);*/
		/*krb5_data_free(&ap_req);*/
		krb5_free_cred_contents(context, &creds_tgt);

		ret = krb5_kt_close(context, keytab);
		if (ret != 0) {
			printf("ERR:krb5_kt_close:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		ret = krb5_cc_close(context, ccache);
		if (ret != 0) {
			printf("ERR:krb5_cc_close:%s\n", krb5_get_err_text(context, ret));
			return(ret);
		}

		krb5_free_principal(context, princ_krbtgt);
		krb5_free_principal(context, princ_nut);
		krb5_free_principal(context, princ_tn);
		krb5_free_context(context);
	}

	return(0);
}
Esempio n. 23
0
static krb5_error_code build_kpasswd_request(uint16 pversion,
					   krb5_context context,
					   krb5_auth_context auth_context,
					   krb5_data *ap_req,
					   const char *princ,
					   const char *passwd,
					   bool use_tcp,
					   krb5_data *packet)
{
	krb5_error_code ret;
	krb5_data cipherpw;
	krb5_data encoded_setpw;
	krb5_replay_data replay;
	char *p, *msg_start;
	DATA_BLOB setpw;
	unsigned int msg_length;

	ret = krb5_auth_con_setflags(context,
				     auth_context,KRB5_AUTH_CONTEXT_DO_SEQUENCE);
	if (ret) {
		DEBUG(1,("krb5_auth_con_setflags failed (%s)\n",
			 error_message(ret)));
		return ret;
	}

	/* handle protocol differences in chpw and setpw */
	if (pversion  == KRB5_KPASSWD_VERS_CHANGEPW)
		setpw = data_blob(passwd, strlen(passwd));
	else if (pversion == KRB5_KPASSWD_VERS_SETPW ||
		 pversion == KRB5_KPASSWD_VERS_SETPW_ALT)
		setpw = encode_krb5_setpw(princ, passwd);
	else
		return EINVAL;

	if (setpw.data == NULL || setpw.length == 0) {
		return EINVAL;
	}

	encoded_setpw.data = (char *)setpw.data;
	encoded_setpw.length = setpw.length;

	ret = krb5_mk_priv(context, auth_context,
			   &encoded_setpw, &cipherpw, &replay);
	
	data_blob_free(&setpw); 	/*from 'encode_krb5_setpw(...)' */
	
	if (ret) {
		DEBUG(1,("krb5_mk_priv failed (%s)\n", error_message(ret)));
		return ret;
	}

	packet->data = (char *)SMB_MALLOC(ap_req->length + cipherpw.length + (use_tcp ? 10 : 6 ));
	if (!packet->data)
		return -1;



	/* see the RFC for details */

	msg_start = p = ((char *)packet->data) + (use_tcp ? 4 : 0);
	p += 2;
	RSSVAL(p, 0, pversion);
	p += 2;
	RSSVAL(p, 0, ap_req->length);
	p += 2;
	memcpy(p, ap_req->data, ap_req->length);
	p += ap_req->length;
	memcpy(p, cipherpw.data, cipherpw.length);
	p += cipherpw.length;
	packet->length = PTR_DIFF(p,packet->data);
	msg_length = PTR_DIFF(p,msg_start);

	if (use_tcp) {
		RSIVAL(packet->data, 0, msg_length);
	}
	RSSVAL(msg_start, 0, msg_length);
	
	free(cipherpw.data);    /* from 'krb5_mk_priv(...)' */

	return 0;
}
Esempio n. 24
0
int
auks_krb5_cred_get(char *ccachefilename,char **pbuffer,
		   size_t * plength)
{
	int fstatus = AUKS_ERROR ;

	/* kerberos related variables */
	krb5_error_code err_code;
	krb5_context context;
	krb5_auth_context auth_context;
	krb5_ccache ccache;
	krb5_creds read_cred;
	krb5_cc_cursor cc_cursor;
	krb5_data *p_outbuf;
	krb5_replay_data krdata;

	int read_cred_was_used = 0;
	int read_cred_is_tgt = 0;

	char *buffer;
	size_t length;

	/* initialize kerberos context */
	err_code = krb5_init_context(&context);
	if (err_code) {
		auks_error("unable to initialize kerberos context : %s",
			   error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_INIT_CTX ;
		goto exit;
	}
	auks_log("kerberos context successfully initialized");

	/* initialize kerberos credential cache structure */
	if (ccachefilename == NULL)
		err_code = krb5_cc_default(context, &ccache);
	else
		err_code = krb5_cc_resolve(context, ccachefilename,&ccache);
	if (err_code) {
		auks_error("unable to resolve credential cache : %s",
			   error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_OPEN_CC ;
		goto ctx_exit ;
	}
	auks_log("credential cache successfully resolved");

	/* start credential cache sequential reading */
	err_code = krb5_cc_start_seq_get(context, ccache,&cc_cursor);
	if (err_code) {
		auks_error("unable to start credential cache sequential "
			   "read : %s",error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_READ_CC ;
		goto cc_exit;
	}
	auks_log("credential cache sequential read successfully started");

	/* look for the first TGT of the cache */
	do {
		err_code = krb5_cc_next_cred(context,ccache,
					     &cc_cursor,&read_cred);
		if (!err_code) {
			/* mark read_cred variable as used */
			read_cred_was_used = 1;
			/* just check initial or forwarded tickets (TGTs) */
			if ((read_cred.ticket_flags & TKT_FLG_INITIAL)
			    || (read_cred.ticket_flags & TKT_FLG_FORWARDED)) {
				read_cred_is_tgt = 1 ;
				break;
			}
		}
	}
	while (!err_code);

	/* stop credential cache sequential reading */
	err_code = krb5_cc_end_seq_get(context,ccache,&cc_cursor);
	if (err_code) {
		auks_error("unable to stop credential cache sequential "
			   "read : %s",error_message(err_code));
	} else
		auks_log("credential cache sequential read "
			 "successfully stopped");

	/* extract credential if a TGT was found */
	if (!read_cred_is_tgt) {
		auks_error("no TGT found in credential cache");
		fstatus = AUKS_ERROR_KRB5_CRED_NO_TGT_FOUND ;
		goto seq_exit;
	}
	auks_log("TGT found in credential cache");

	/* initialize a nullified kerberos authentication context in order */
	/* to serialize credential into buffer */
	err_code = krb5_auth_con_init(context,&auth_context);
	if (err_code) {
		auks_error("unable to initialize kerberos authentication "
			   "context : %s",error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_INIT_AUTH_CTX ;
		goto seq_exit;
	}
	auks_log("kerberos authentication context successfully initialized");

	/* clear kerberos authentication context flags */
	krb5_auth_con_setflags(context,auth_context,0);

	/* extract credential data */
	err_code = krb5_mk_1cred(context,auth_context,&read_cred,
				 &p_outbuf,&krdata);
	if (err_code) {
		auks_error("unable to dump credential into working buffer : %s",
			   error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_MK_CRED ;
		goto auth_ctx_exit;
	}
	auks_log("credential successfully dumped into buffer");

	/* allocate output buffer */
	length = p_outbuf->length;
	buffer = (char *) malloc(length * sizeof(char));
	if (buffer == NULL) {
		auks_error("unable to allocate memory for credential data "
			   "storage");
		fstatus = AUKS_ERROR_KRB5_CRED_MALLOC ;
		goto cred_exit;
	}

	/* copy credential data into output buffer */
	memcpy(buffer,p_outbuf->data,length);
	*pbuffer = buffer;
	*plength = length;
	auks_log("credential successfully stored in output buffer");
	fstatus = AUKS_SUCCESS ;

cred_exit:
	krb5_free_data(context,p_outbuf);

auth_ctx_exit:
	/* free kerberos authentication context */
	krb5_auth_con_free(context,auth_context);

seq_exit:
	/* free credential contents */
	if (read_cred_was_used)
		krb5_free_cred_contents(context,&read_cred);

cc_exit:
	krb5_cc_close(context, ccache);

ctx_exit:
	krb5_free_context(context);

exit:
	return fstatus;
}
Esempio n. 25
0
/**
 * @brief
 *		Get a kerberos credential set up to send to a remote host.
 *
 * @param[in]	remote	- server name
 * @param[in]	pjob	- pointer to job structure
 * @param[out]	data	- kerberos credential
 * @param[out]	dsize	- kerberos credential data length
 *
 * @return	int
 * @retval	0	- success
 * @retval	-1	- error
 */
static int
get_kerb_cred(char *remote, job *pjob, char **data, size_t *dsize)
{
	int			ret = -1;
#ifdef	PBS_CRED_DCE_KRB5
	krb5_error_code		err;
	int			got_auth = 0;
	char			server_name[512];
	char			namebuf[MAXPATHLEN+1];
	krb5_context		ktext = 0;
	krb5_auth_context	kauth = 0;
	krb5_ccache		kache = 0;
	krb5_principal		client = 0;
	krb5_principal		server = 0;
	krb5_data		forw_creds;
	krb5_data		packet;
	extern char		*path_jobs;

	DBPRT(("%s: entered %s\n", id, remote))
	memset(&forw_creds, 0, sizeof(forw_creds));
	memset(&packet, 0, sizeof(packet));

	if ((err = krb5_init_context(&ktext)) != 0) {
		sprintf(log_buffer,
			"krb5_init_context(%s)", error_message(err));
		log_err(-1, __func__, log_buffer);
		return ret;
	}

	if ((err = krb5_auth_con_init(ktext, &kauth)) != 0) {
		sprintf(log_buffer,
			"krb5_auth_con_init(%s)", error_message(err));
		log_err(-1, __func__, log_buffer);
		return ret;
	}
	got_auth = 1;

	krb5_auth_con_setflags(ktext, kauth, KRB5_AUTH_CONTEXT_RET_TIME);

	(void)strcpy(namebuf, path_jobs);
	if (*pjob->ji_qs.ji_fileprefix != '\0')
		(void)strcat(namebuf, pjob->ji_qs.ji_fileprefix);
	else
		(void)strcat(namebuf, pjob->ji_qs.ji_jobid);
	(void)strcat(namebuf, JOB_CRED_SUFFIX);
	if ((err = krb5_cc_resolve(ktext, namebuf, &kache)) != 0) {
		sprintf(log_buffer,
			"krb5_cc_resolve(%s)", error_message(err));
		log_err(-1, __func__, log_buffer);
		goto done;
	}

	if ((err = krb5_cc_get_principal(ktext, kache, &client)) != 0) {
		sprintf(log_buffer,
			"krb5_cc_get_principal(%s)", error_message(err));
		log_err(-1, __func__, log_buffer);
		goto done;
	}

	snprintf(server_name, sizeof(server_name), "host/%s@", remote);
	strncat(server_name, client->realm.data, client->realm.length);
	krb5_parse_name(ktext, server_name, &server);
	server->type = KRB5_NT_SRV_HST;

	if ((err = fwd_tgt_creds(ktext, kauth,
		client, server, kache, &forw_creds)) != 0) {
		sprintf(log_buffer, "no usable cred(%s)", error_message(err));
		log_err(-1, __func__, log_buffer);
		goto done;
	}

	*dsize = forw_creds.length;
	*data = forw_creds.data;
	ret = 0;

done:
	if (forw_creds.data && *data != forw_creds.data)
		free(forw_creds.data);
	if (client)
		krb5_free_principal(ktext, client);
	if (server)
		krb5_free_principal(ktext, server);
	if (got_auth)
		krb5_auth_con_free(ktext, kauth);
	krb5_free_context(ktext);
#endif	/* PBS_CRED_DCE_KRB5 */
	return ret;
}
Esempio n. 26
0
int
auks_krb5_cred_store(char *cachefilename, char *buffer,
		     size_t buffer_length)
{
	int fstatus = AUKS_ERROR ;

	/* kerberos related variables */
	krb5_error_code err_code;
	krb5_context context;
	krb5_auth_context auth_context;
	krb5_ccache ccache;
	krb5_creds **creds;
	krb5_data data;
	krb5_replay_data krdata;

	/* initialize kerberos context */
	err_code = krb5_init_context(&context);
	if (err_code) {
		auks_error("unable to initialize kerberos context : %s",
			   error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_INIT_CTX ;
		goto exit;
	}
	auks_log("kerberos context successfully initialized");

	/* initialize a nullified kerberos authentication context in order */
	/* to decode credential from buffer */
	err_code = krb5_auth_con_init(context, &auth_context);
	if (err_code) {
		auks_error("unable to initialize kerberos authentication"
			   " context : %s",error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_INIT_AUTH_CTX ;
		goto ctx_exit;
	}
	auks_log("kerberos authentication context successfully initialized");

	/* clear kerberos authentication context flags */
	krb5_auth_con_setflags(context, auth_context, 0);

	/* build a kerberos data structure with input buffer */
	data.data = buffer;
	data.length = buffer_length;

	/* build kerberos credential structure using this data structure */
	err_code = krb5_rd_cred(context, auth_context, &data,&creds,&krdata);
	if (err_code) {
		auks_error("unable to deserialize credential data : %s",
			   error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_RD_CRED ;
		goto auth_ctx_exit;

	}
	auks_log("credential data successfully deserialized");

	/* resolve kerberos credential cache */
	if (cachefilename == NULL)
		err_code = krb5_cc_default(context,&ccache);
	else
		err_code = krb5_cc_resolve(context,cachefilename,&ccache);
	if (err_code) {
		auks_error("unable to resolve credential cache : %s",
			   error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_OPEN_CC ;
		goto cred_exit;
	}
	auks_log("credential cache successfully resolved");

	/* initialize kerberos credential structure */
	err_code = krb5_cc_initialize(context,ccache,(*creds)->client);
	if (err_code) {
		auks_error("unable to initialize credential cache : %s",
			   error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_INIT_CC ;
		goto cc_exit;

	}
	auks_log("credential cache successfully initialized",cachefilename);

	/* store credential in credential cache */
	err_code = krb5_cc_store_cred(context,ccache,*creds);
	if (err_code) {
		auks_error("unable to store credential in credential "
			   "cache : %s",error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_STORE_CRED ;
	} else {
		auks_log("credential successfully stored in credential cache");
		fstatus = AUKS_SUCCESS ;
	}

cc_exit:
	krb5_cc_close(context, ccache);

cred_exit:
	krb5_free_creds(context, *creds);
	free(creds);

auth_ctx_exit:
	krb5_auth_con_free(context, auth_context);

ctx_exit:
	krb5_free_context(context);

exit:
	return fstatus;
}
Esempio n. 27
0
static OM_uint32
gsskrb5_accept_delegated_token
(OM_uint32 * minor_status,
 gsskrb5_ctx ctx,
 krb5_context context,
 gss_cred_id_t * delegated_cred_handle
    )
{
    krb5_ccache ccache = NULL;
    krb5_error_code kret;
    int32_t ac_flags, ret = GSS_S_COMPLETE;

    *minor_status = 0;

    /* XXX Create a new delegated_cred_handle? */
    if (delegated_cred_handle == NULL) {
	kret = krb5_cc_default (context, &ccache);
    } else {
	*delegated_cred_handle = NULL;
	kret = krb5_cc_new_unique (context, krb5_cc_type_memory,
				   NULL, &ccache);
    }
    if (kret) {
	ctx->flags &= ~GSS_C_DELEG_FLAG;
	goto out;
    }

    kret = krb5_cc_initialize(context, ccache, ctx->source);
    if (kret) {
	ctx->flags &= ~GSS_C_DELEG_FLAG;
	goto out;
    }

    krb5_auth_con_removeflags(context,
			      ctx->auth_context,
			      KRB5_AUTH_CONTEXT_DO_TIME,
			      &ac_flags);
    kret = krb5_rd_cred2(context,
			 ctx->auth_context,
			 ccache,
			 &ctx->fwd_data);
    krb5_auth_con_setflags(context,
			   ctx->auth_context,
			   ac_flags);
    if (kret) {
	ctx->flags &= ~GSS_C_DELEG_FLAG;
	ret = GSS_S_FAILURE;
	*minor_status = kret;
	goto out;
    }

    if (delegated_cred_handle) {
	gsskrb5_cred handle;

	ret = _gsskrb5_krb5_import_cred(minor_status,
					ccache,
					NULL,
					NULL,
					delegated_cred_handle);
	if (ret != GSS_S_COMPLETE)
	    goto out;

	handle = (gsskrb5_cred) *delegated_cred_handle;

	handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
	krb5_cc_close(context, ccache);
	ccache = NULL;
    }

out:
    if (ccache) {
	/* Don't destroy the default cred cache */
	if (delegated_cred_handle == NULL)
	    krb5_cc_close(context, ccache);
	else
	    krb5_cc_destroy(context, ccache);
    }
    return ret;
}
Esempio n. 28
0
int
auks_krb5_cred_get_fwd(char *ccachefilename, char *serverName,
		       char **p_buffer,
		       size_t * p_buffer_length)
{

	int fstatus = AUKS_ERROR ;

	/* kerberos related variables */
	krb5_error_code err_code;
	krb5_context context;
	krb5_ccache ccache;
	krb5_principal principal;
	krb5_creds **out_creds_array = NULL;
	krb5_auth_context auth_context;
	krb5_flags authopts;
	krb5_data outbuf;
	krb5_data *p_outbuf;
	krb5_replay_data krdata;

	authopts = AP_OPTS_MUTUAL_REQUIRED;
	authopts &= (~OPTS_FORWARD_CREDS);
	authopts &= (~OPTS_FORWARDABLE_CREDS);

	if ( serverName == NULL ) {
		auks_error("no host specified");
		fstatus = AUKS_ERROR_KRB5_CRED_NO_HOST_SPECIFIED ;
		goto exit;
	}

	/* initialize kerberos context */
	err_code = krb5_init_context(&context);
	if (err_code) {
		auks_error("unable to initialize kerberos context : %s",
			   error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_INIT_CTX ;
		goto exit;
	}
	auks_log("kerberos context successfully initialized");

	/* initialize kerberos credential cache structure */
	if (ccachefilename == NULL)
		err_code = krb5_cc_default(context, &ccache);
	else
		err_code = krb5_cc_resolve(context,ccachefilename,&ccache);
	if (err_code) {
		auks_error("unable to resolve credential cache : %s",
			   error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_OPEN_CC ;
		goto ctx_exit ;
	}
	auks_log("credential cache successfully resolved");

	/* get principal using credential cache */
	err_code = krb5_cc_get_principal(context,ccache,&principal);
	if (err_code) {
		auks_error("unable to get principal from credential cache : %s",
			   error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_GET_PRINC ;
		goto cc_exit ;
	}
	auks_log("principal successfully extracted from credential cache");

	/* initialize kerberos authentication context */
	err_code = krb5_auth_con_init(context,&auth_context);
	if (err_code) {
		auks_error("unable to initialize kerberos authentication "
			   "context : %s",error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_INIT_AUTH_CTX ;
		goto princ_exit;
	}
	auks_log("kerberos authentication context successfully initialized");

	/* do replay detection using timestamps */
	krb5_auth_con_setflags(context,auth_context,KRB5_AUTH_CONTEXT_RET_TIME);

	/* get forwarded credential for server */
	err_code = krb5_fwd_tgt_creds(context,auth_context,serverName,
				      principal,NULL,NULL,authopts,&outbuf);
	if (err_code) {
		auks_error("unable to get serialized and crypted forwarded "
			   "credential for %s from KDC : %s",
			   serverName,error_message(err_code));
		fstatus =  AUKS_ERROR_KRB5_CRED_GET_FWD_CRED ;
		goto auth_ctx_exit;
	}
	auks_log("serialized and crypted forwarded credential for %s "
		 "successfully got from KDC",serverName);

	/* desactive replay detection */
	krb5_auth_con_setflags(context,auth_context,0);

	/* decrypt (using session key stored in auth context) and */
	/* unserialized forwarded credential in a kerberos credential */
	/* structure */
	err_code = krb5_rd_cred(context,auth_context,&outbuf,&out_creds_array,
				&krdata);
	if (err_code) {
		auks_error("unable to unserialize and decrypt forwarded "
			   "credential for %s : %s",serverName,
			   error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_RD_CRED ;
		goto fwd_exit;
	}
	auks_log("unserialization and decryption of forwarded "
		 "credential for %s succesfully done",serverName);

	/* Reinitialize kerberos authentication context in order to */
	/* write credential to output buffer */
	krb5_auth_con_free(context,auth_context);
	err_code = krb5_auth_con_init(context,&auth_context);
	if (err_code) {
		auks_error("unable to reinitialize kerberos connection "
			   "authentication context : %s",error_message
			   (err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_INIT_AUTH_CTX ;
		goto rd_cred_exit;
	}
	auks_log("kerberos connection authentication context "
		 "reinitialization successfully done");

	/* no flags */
	krb5_auth_con_setflags(context,auth_context,0);

	/* serialize forwarded credential (no encryption because auth */
	/* context session key is nullified) */
	err_code = krb5_mk_1cred(context,auth_context,*out_creds_array,
				 &p_outbuf,&krdata);
	if (err_code) {
		auks_error("unable to serialize forwarded credential for "
			   "%s : %s",serverName,error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_MK_CRED ;
		goto rd_cred_exit;
	}
	auks_log("forwarded credential for %s successfully serialized",
		 serverName);

	/* allocate output buffer and store serialized credential */
	(*p_buffer) = (char *) malloc(p_outbuf->length * sizeof(char));
	if ((*p_buffer) == NULL) {
		auks_error("unable to allocate serialized credential output "
			   "buffer for %s",serverName);
		*p_buffer_length = 0 ;
		fstatus = AUKS_ERROR_KRB5_CRED_MALLOC ;
	} else {
		/* copy data */
		memcpy(*p_buffer,p_outbuf->data,p_outbuf->length);
		*p_buffer_length = p_outbuf->length;
		auks_log("forwarded credential successfully stored "
			 "in output buffer");
		fstatus	= AUKS_SUCCESS ;
	}

	krb5_free_data(context,p_outbuf);

rd_cred_exit:
	krb5_free_creds(context,*out_creds_array);
	free(out_creds_array);

fwd_exit:
	krb5_free_data_contents(context, &outbuf);

auth_ctx_exit:
	krb5_auth_con_free(context,auth_context);

princ_exit:
	krb5_free_principal(context, principal);

cc_exit:
	krb5_cc_close(context, ccache);

ctx_exit:
	krb5_free_context(context);

exit:
	return fstatus;
}
Esempio n. 29
0
int
auks_krb5_cred_deladdr_buffer(char *in_buf,size_t in_buf_len,
			      char** pout_buf,size_t *pout_buf_len)
{
	int fstatus = AUKS_ERROR ;

	/* kerberos related variables */
	krb5_error_code err_code;
	krb5_context context;
	krb5_auth_context auth_context;

	krb5_creds **creds;
	krb5_data data;
	krb5_replay_data krdata;

	krb5_data *p_outbuf;

	krb5_creds fwd_cred;
	krb5_creds *p_cred_out = NULL;

	krb5_address **addresses;

	char* buffer;
	size_t length;

	/* initialize kerberos context */
	err_code = krb5_init_context(&context);
	if (err_code) {
		auks_error("unable to initialize kerberos context : %s",
			   error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_INIT_CTX ; 
		goto exit;
	}
	auks_log("kerberos context successfully initialized");

	/* initialize a nullified kerberos authentication context in order */
	/* to decode credential from buffer */
	err_code = krb5_auth_con_init(context, &auth_context);
	if (err_code) {
		auks_error("unable to initialize kerberos authentication"
			   " context : %s",error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_INIT_AUTH_CTX ;
		goto ctx_exit;
	}
	auks_log("kerberos authentication context successfully initialized");

	/* clear kerberos authentication context flags */
	krb5_auth_con_setflags(context, auth_context, 0);

	/* build a kerberos data structure with input buffer */
	data.data = in_buf;
	data.length = in_buf_len;

	/* build kerberos credential structure using this data structure */
	err_code = krb5_rd_cred(context, auth_context, &data,&creds,&krdata);
	if (err_code) {
		auks_error("unable to deserialize credential data : %s",
			   error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_RD_CRED ;
		goto auth_ctx_exit;
	}
	auks_log("credential data successfully deserialized");

	memset(&fwd_cred, 0,sizeof(fwd_cred));

	/* copy client principal in futur credential */
	err_code = krb5_copy_principal(context,(*creds)->client,
				       &fwd_cred.client);
	if (err_code) {
		auks_error("unable to put client principal into "
			   "request cred : %s",error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_CP_PRINC ;
		goto cred_exit;
	}
	auks_log("client principal successfully put into request cred");

	/* copy krbtgt/... principal in futur credential as required */
	/* server principal for TGS */
	err_code = krb5_copy_principal(context,(*creds)->server,
				       &fwd_cred.server);
	if (err_code) {
		auks_error("unable to put server principal into "
			   "request cred : %s",error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_CP_PRINC ;
		goto cred_exit;
	}
	auks_log("server principal successfully put into request cred");

	/* get addressless forwarded ticket */
	err_code = krb5_get_cred_via_tkt(context,(*creds),
					 ( KDC_OPT_CANONICALIZE |
					   KDC_OPT_FORWARDED |
					   ( (*creds)->ticket_flags &
					     KDC_TKT_COMMON_MASK )  ),
					 addresses=NULL,
					 &fwd_cred,&p_cred_out);
	if (err_code) {
		auks_error("unable to get addressless forwarded cred from auks"
			   " cred buffer : %s",error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_GET_FWD_CRED ;
		goto cred_exit;
	}
	auks_log("addressless forwarded cred successfully"
		 " got using auks cred buffer");

	/* extract credential data */
	err_code = krb5_mk_1cred(context,auth_context,p_cred_out,
				 &p_outbuf,&krdata);
	if (err_code) {
		auks_error("unable to dump credential into working buffer : %s",
			   error_message(err_code));
		fstatus = AUKS_ERROR_KRB5_CRED_MK_CRED ;
		goto fwd_exit;
	}
	auks_log("credential successfully dumped into buffer");

	/* allocate output buffer */
	length = p_outbuf->length;
	buffer = (char *) malloc(length * sizeof(char));
	if (buffer == NULL) {
		auks_error("unable to allocate memory for credential data "
			   "storage");
		fstatus = AUKS_ERROR_KRB5_CRED_MALLOC ;
		goto mk_exit;
	}

	/* copy credential data into output buffer */
	memcpy(buffer,p_outbuf->data,length);
	*pout_buf = buffer;
	*pout_buf_len = length;
	auks_log("credential successfully stored in output buffer");
	fstatus = AUKS_SUCCESS ;

	auks_log("in length : %u | out length : %u",
		 in_buf_len,
		 p_outbuf->length);
mk_exit:
	krb5_free_data(context,p_outbuf);

fwd_exit:
	krb5_free_creds(context,p_cred_out);

cred_exit:
	krb5_free_cred_contents(context,&fwd_cred);
	krb5_free_creds(context, *creds);
	free(creds);

auth_ctx_exit:
	krb5_auth_con_free(context, auth_context);

ctx_exit:
	krb5_free_context(context);

exit:
	return fstatus;
}
Esempio n. 30
0
/*
 * The username/password have been verified, now we must verify the
 * response came from a valid KDC by getting a ticket for our own
 * service that we can verify using our keytab.
 *
 * Based on mod_auth_kerb
 */
static gss_client_response *verify_krb5_kdc(krb5_context context,
					       krb5_creds *creds,
					       const char *service)
{
    krb5_error_code problem;
    krb5_keytab keytab = NULL;
    krb5_ccache tmp_ccache = NULL;
    krb5_principal server_princ = NULL;
    krb5_creds *new_creds = NULL;
    krb5_auth_context auth_context = NULL;
    krb5_data req;
    gss_client_response *response = NULL;

    memset(&req, 0, sizeof(req));

    problem = krb5_kt_default (context, &keytab);

    if (problem) {
	response = krb5_ctx_error(context, problem);
        goto out;
    }

    problem = krb5_cc_new_unique(context, "MEMORY", NULL, &tmp_ccache);
    if (problem) {
	response = krb5_ctx_error(context, problem);
        goto out;
    }

    problem = krb5_cc_initialize(context, tmp_ccache, creds->client);
    if (problem) {
	response = krb5_ctx_error(context, problem);
        goto out;
    }

    problem = krb5_cc_store_cred(context, tmp_ccache, creds);
    if (problem) {
	response = krb5_ctx_error(context, problem);
        goto out;
    }

    problem = krb5_parse_name(context, service, &server_princ);
    if (problem) {
	response = krb5_ctx_error(context, problem);
        goto out;
    }

    /*
     * creds->server is (almost always?) krbtgt service, and server_princ is not.
     * In which case retrieve a service ticket for server_princ service from KDC
     */
    if (!krb5_principal_compare(context, server_princ, creds->server)) {
	krb5_creds match_cred;

	memset (&match_cred, 0, sizeof(match_cred));

	match_cred.client = creds->client;
	match_cred.server = server_princ;

	problem = krb5_get_credentials(context, 0, tmp_ccache, &match_cred, &new_creds);
	if (problem) {
	    response = krb5_ctx_error(context, problem);
	    goto out;
	}

	creds = new_creds;
    }

    problem = krb5_mk_req_extended(context, &auth_context, 0, NULL, creds, &req);
    if (problem) {
	response = krb5_ctx_error(context, problem);
        goto out;
    }

    krb5_auth_con_free(context, auth_context);
    auth_context = NULL;

    problem = krb5_auth_con_init(context, &auth_context);
    if (problem) {
	response = krb5_ctx_error(context, problem);
        goto out;
    }

    /* disable replay cache checks */
    krb5_auth_con_setflags(context, auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE);

    problem = krb5_rd_req(context, &auth_context, &req,
			  server_princ, keytab, 0, NULL);
    if (problem) {
	response = krb5_ctx_error(context, problem);
        goto out;
    }

  out:

    krb5_free_data_contents(context, &req);

    if (auth_context) {
        krb5_auth_con_free(context, auth_context);
    }

    if (new_creds) {
	krb5_free_creds(context, new_creds);
    }

    if (server_princ) {
	krb5_free_principal(context, server_princ);
    }

    if (tmp_ccache) {
	krb5_cc_destroy (context, tmp_ccache);
    }

    if (keytab) {
	krb5_kt_close (context, keytab);
    }

    return response;
}