Пример #1
0
static krb5_error_code
fast_armor_ap_request(krb5_context context,
                      struct krb5int_fast_request_state *state,
                      krb5_ccache ccache, krb5_principal target_principal)
{
    krb5_error_code retval = 0;
    krb5_creds creds, *out_creds = NULL;
    krb5_auth_context authcontext = NULL;
    krb5_data encoded_authenticator;
    krb5_fast_armor *armor = NULL;
    krb5_keyblock *subkey = NULL, *armor_key = NULL;

    encoded_authenticator.data = NULL;
    memset(&creds, 0, sizeof(creds));
    creds.server = target_principal;
    retval = krb5_cc_get_principal(context, ccache, &creds.client);
    if (retval == 0)
        retval = krb5_get_credentials(context, 0, ccache,  &creds, &out_creds);
    if (retval == 0) {
        TRACE_FAST_ARMOR_CCACHE_KEY(context, &out_creds->keyblock);
        retval = krb5_mk_req_extended(context, &authcontext,
                                      AP_OPTS_USE_SUBKEY, NULL /*data*/,
                                      out_creds, &encoded_authenticator);
    }
    if (retval == 0)
        retval = krb5_auth_con_getsendsubkey(context, authcontext, &subkey);
    if (retval == 0)
        retval = krb5_c_fx_cf2_simple(context, subkey, "subkeyarmor",
                                      &out_creds->keyblock, "ticketarmor",
                                      &armor_key);
    if (retval == 0) {
        TRACE_FAST_ARMOR_KEY(context, armor_key);
        armor = calloc(1, sizeof(krb5_fast_armor));
        if (armor == NULL)
            retval = ENOMEM;
    }
    if (retval == 0) {
        armor->armor_type = KRB5_FAST_ARMOR_AP_REQUEST;
        armor->armor_value = encoded_authenticator;
        encoded_authenticator.data = NULL;
        encoded_authenticator.length = 0;
        state->armor = armor;
        armor = NULL;
        state->armor_key = armor_key;
        armor_key = NULL;
    }
    krb5_free_keyblock(context, armor_key);
    krb5_free_keyblock(context, subkey);
    if (out_creds)
        krb5_free_creds(context, out_creds);
    /* target_principal is owned by caller. */
    creds.server = NULL;
    krb5_free_cred_contents(context, &creds);
    if (encoded_authenticator.data)
        krb5_free_data_contents(context, &encoded_authenticator);
    krb5_auth_con_free(context, authcontext);
    return retval;
}
Пример #2
0
/*
 * @Description: Make a TGS_REQ
 * @Param: input context, principal, time expire, kdc_option
 * @return: 0 if success, otherwise -1
 * */
int ads_krb5_mk_req(/*krb5_context context,
	       krb5_auth_context *auth_context,
	       const krb5_flags ap_req_options,
	       const char *principal,
	       krb5_ccache ccache,
	       krb5_data *outbuf,
	       time_t *expire_time,
	       const char *impersonate_princ_s*/)
{
	/*get credentials */
	smb_krb5_get_credentials();

	/* make request*/
	krb5_mk_req_extended();
}
Пример #3
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_mk_req_exact(krb5_context context,
		  krb5_auth_context *auth_context,
		  const krb5_flags ap_req_options,
		  const krb5_principal server,
		  krb5_data *in_data,
		  krb5_ccache ccache,
		  krb5_data *outbuf)
{
    krb5_error_code ret;
    krb5_creds this_cred, *cred;

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

    ret = krb5_cc_get_principal(context, ccache, &this_cred.client);

    if(ret)
	return ret;

    ret = krb5_copy_principal (context, server, &this_cred.server);
    if (ret) {
	krb5_free_cred_contents (context, &this_cred);
	return ret;
    }

    this_cred.times.endtime = 0;
    if (auth_context && *auth_context && (*auth_context)->keytype)
	this_cred.session.keytype = (*auth_context)->keytype;

    ret = krb5_get_credentials (context, 0, ccache, &this_cred, &cred);
    krb5_free_cred_contents(context, &this_cred);
    if (ret)
	return ret;

    ret = krb5_mk_req_extended (context,
				auth_context,
				ap_req_options,
				in_data,
				cred,
				outbuf);
    krb5_free_creds(context, cred);
    return ret;
}
Пример #4
0
krb5_error_code KRB5_CALLCONV
krb5_mk_req(krb5_context context, krb5_auth_context *auth_context,
	    krb5_flags ap_req_options, char *service, char *hostname,
	    krb5_data *in_data, krb5_ccache ccache, krb5_data *outbuf)
{
    krb5_error_code 	  retval;
    krb5_principal	  server;
    krb5_creds 		* credsp;
    krb5_creds 		  creds;

    retval = krb5_sname_to_principal(context, hostname, service,
				     KRB5_NT_SRV_HST, &server);
    if (retval)
      return retval;

    /* obtain ticket & session key */
    memset((char *)&creds, 0, sizeof(creds));
    if ((retval = krb5_copy_principal(context, server, &creds.server)))
	goto cleanup_princ;

    if ((retval = krb5_cc_get_principal(context, ccache, &creds.client)) != 0)
	goto cleanup_creds;

    if ((retval = krb5_get_credentials(context, 0,
				       ccache, &creds, &credsp)) != 0)
	goto cleanup_creds;

    retval = krb5_mk_req_extended(context, auth_context, ap_req_options,
				  in_data, credsp, outbuf);

    krb5_free_creds(context, credsp);

cleanup_creds:
    krb5_free_cred_contents(context, &creds);

cleanup_princ:
    krb5_free_principal(context, server);

    return retval;
}
Пример #5
0
static krb5_error_code
chgpw_prexmit(krb5_context context, int proto,
              void *ctx, rk_socket_t fd, krb5_data *data)
{
    struct request *request = ctx;
    krb5_data ap_req_data, krb_priv_data, passwd_data;
    krb5_storage *sp = NULL;
    krb5_error_code ret;
    krb5_ssize_t slen;
    size_t len;

    krb5_data_zero(&ap_req_data);
    krb5_data_zero(&krb_priv_data);

    ret = krb5_auth_con_genaddrs(context, request->ac, fd,
                                 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR);
    if (ret)
        goto out;

    ret = krb5_mk_req_extended(context,
                               &request->ac,
                               AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
                               NULL,
                               request->creds,
                               &ap_req_data);
    if (ret)
        goto out;

    passwd_data.data   = rk_UNCONST(request->password);
    passwd_data.length = strlen(request->password);

    ret = krb5_mk_priv(context,
                       request->ac,
                       &passwd_data,
                       &krb_priv_data,
                       NULL);
    if (ret)
        goto out;

    sp = krb5_storage_emem();
    if (sp == NULL) {
        ret = ENOMEM;
        goto out;
    }

    len = 6 + ap_req_data.length + krb_priv_data.length;

    ret = krb5_store_uint16(sp, len);
    if (ret) goto out;
    ret = krb5_store_uint16(sp, 1);
    if (ret) goto out;
    ret = krb5_store_uint16(sp, ap_req_data.length);
    if (ret) goto out;
    slen = krb5_storage_write(sp, ap_req_data.data, ap_req_data.length);
    if (slen != ap_req_data.length) {
        ret = EINVAL;
        goto out;
    }
    slen = krb5_storage_write(sp, krb_priv_data.data, krb_priv_data.length);
    if (slen != krb_priv_data.length) {
        ret = EINVAL;
        goto out;
    }

    ret = krb5_storage_to_data(sp, data);

out:
    if (ret)
        _krb5_debugx(context, 10, "chgpw_prexmit failed with: %d", ret);
    if (sp)
        krb5_storage_free(sp);
    krb5_data_free(&krb_priv_data);
    krb5_data_free(&ap_req_data);
    return ret;
}
Пример #6
0
krb5_error_code KRB5_CALLCONV
krb5_sendauth(krb5_context context, krb5_auth_context *auth_context, krb5_pointer fd, char *appl_version, krb5_principal client, krb5_principal server, krb5_flags ap_req_options, krb5_data *in_data, krb5_creds *in_creds, krb5_ccache ccache, krb5_error **error, krb5_ap_rep_enc_part **rep_result, krb5_creds **out_creds)
{
	krb5_octet		result;
	krb5_creds 		creds;
	krb5_creds		 * credsp = NULL;
	krb5_creds		 * credspout = NULL;
	krb5_error_code		retval = 0;
	krb5_data		inbuf, outbuf;
	int			len;
	krb5_ccache		use_ccache = 0;

	if (error)
	    *error = 0;

	/*
	 * First, send over the length of the sendauth version string;
	 * then, we send over the sendauth version.  Next, we send
	 * over the length of the application version strings followed
	 * by the string itself.
	 */
	outbuf.length = strlen(sendauth_version) + 1;
	outbuf.data = (char *) sendauth_version;
	if ((retval = krb5_write_message(context, fd, &outbuf)))
		return(retval);
	outbuf.length = strlen(appl_version) + 1;
	outbuf.data = appl_version;
	if ((retval = krb5_write_message(context, fd, &outbuf)))
		return(retval);
	/*
	 * Now, read back a byte: 0 means no error, 1 means bad sendauth
	 * version, 2 means bad application version
	 */
	len = krb5_net_read(context, *((int *) fd), (char *)&result, 1);
	if (len != 1)
		return((len < 0) ? errno : ECONNABORTED);
	if (result == 1)
		return(KRB5_SENDAUTH_BADAUTHVERS);
	else if (result == 2)
		return(KRB5_SENDAUTH_BADAPPLVERS);
	else if (result != 0)
		return(KRB5_SENDAUTH_BADRESPONSE);
	/*
	 * We're finished with the initial negotiations; let's get and
	 * send over the authentication header.  (The AP_REQ message)
	 */

	/*
	 * If no credentials were provided, try getting it from the
	 * credentials cache.
	 */
	memset((char *)&creds, 0, sizeof(creds));

	/*
	 * See if we need to access the credentials cache
	 */
	if (!in_creds || !in_creds->ticket.length) {
		if (ccache)
			use_ccache = ccache;
		/* Solaris Kerberos */
		else if ((retval = krb5int_cc_default(context, &use_ccache)) != 0)
			goto error_return;
	}
	if (!in_creds) {
		if ((retval = krb5_copy_principal(context, server,
						  &creds.server)))
			goto error_return;
		if (client)
			retval = krb5_copy_principal(context, client,
						     &creds.client);
		else
			retval = krb5_cc_get_principal(context, use_ccache,
						       &creds.client);
		if (retval) {
			krb5_free_principal(context, creds.server);
			goto error_return;
		}
		/* creds.times.endtime = 0; -- memset 0 takes care of this
					zero means "as long as possible" */
		/* creds.keyblock.enctype = 0; -- as well as this.
					zero means no session enctype
					preference */
		in_creds = &creds;
	}
	if (!in_creds->ticket.length) {
		/* Solaris Kerberos */
	    if ((retval = krb5_get_credentials(context, 0,
					       use_ccache, in_creds, &credsp)) != 0)
		    goto error_return;
	    credspout = credsp;
	} else {
	    credsp = in_creds;
	}

	if (ap_req_options & AP_OPTS_USE_SUBKEY) {
	    /* Provide some more fodder for random number code.
	       This isn't strong cryptographically; the point here is
	       not to guarantee randomness, but to make it less likely
	       that multiple sessions could pick the same subkey.  */
	    char rnd_data[1024];
	    GETPEERNAME_ARG3_TYPE len2;
	    krb5_data d;
	    d.length = sizeof (rnd_data);
	    d.data = rnd_data;
	    len2 = sizeof (rnd_data);
	    if (getpeername (*(int*)fd, (GETPEERNAME_ARG2_TYPE *) rnd_data,
			     &len2) == 0) {
		d.length = len2;
		/* Solaris Kerberos */
		(void) krb5_c_random_seed (context, &d);
	    }
	    len2 = sizeof (rnd_data);
	    if (getsockname (*(int*)fd, (GETSOCKNAME_ARG2_TYPE *) rnd_data,
			     &len2) == 0) {
		d.length = len2;
		/* Solaris Kerberos */
		(void) krb5_c_random_seed (context, &d);
	    }
	}

	/* Solaris Kerberos */
	if ((retval = krb5_mk_req_extended(context, auth_context,
					   ap_req_options, in_data, credsp,
					   &outbuf)) != 0)
	    goto error_return;

	/*
	 * First write the length of the AP_REQ message, then write
	 * the message itself.
	 */
	retval = krb5_write_message(context, fd, &outbuf);
	free(outbuf.data);
	if (retval)
	    goto error_return;

	/*
	 * Now, read back a message.  If it was a null message (the
	 * length was zero) then there was no error.  If not, we the
	 * authentication was rejected, and we need to return the
	 * error structure.
	 */
	/* Solaris Kerberos */
	if ((retval = krb5_read_message(context, fd, &inbuf)) != 0)
	    goto error_return;

	if (inbuf.length) {
		if (error) {
		    /* Solaris Kerberos */
		    if ((retval = krb5_rd_error(context, &inbuf, error)) != 0) {
			krb5_xfree(inbuf.data);
			goto error_return;
		    }
		}
		retval = KRB5_SENDAUTH_REJECTED;
		krb5_xfree(inbuf.data);
		goto error_return;
	}

	/*
	 * If we asked for mutual authentication, we should now get a
	 * length field, followed by a AP_REP message
	 */
	if ((ap_req_options & AP_OPTS_MUTUAL_REQUIRED)) {
	    krb5_ap_rep_enc_part	*repl = 0;
	    /* Solaris Kerberos */
	    if ((retval = krb5_read_message(context, fd, &inbuf)) != 0)
		goto error_return;

	    /* Solaris Kerberos */
	    if ((retval = krb5_rd_rep(context, *auth_context, &inbuf,
				      &repl)) != 0) {
		if (repl)
		    krb5_free_ap_rep_enc_part(context, repl);
	        krb5_xfree(inbuf.data);
		goto error_return;
	    }

	    krb5_xfree(inbuf.data);
	    /*
	     * If the user wants to look at the AP_REP message,
	     * copy it for them.
	     */
	    if (rep_result)
		*rep_result = repl;
	    else
		krb5_free_ap_rep_enc_part(context, repl);
	}
	retval = 0;		/* Normal return */
	if (out_creds) {
	    *out_creds = credsp;
	    credspout = NULL;
	}

error_return:
    krb5_free_cred_contents(context, &creds);
    if (credspout != NULL)
	krb5_free_creds(context, credspout);
    /* Solaris Kerberos */
    if (!ccache && use_ccache)
	(void) krb5_cc_close(context, use_ccache);
    return(retval);
}
Пример #7
0
static krb5_error_code
setpw_send_request (krb5_context context,
		    krb5_auth_context *auth_context,
		    krb5_creds *creds,
		    krb5_principal targprinc,
		    int is_stream,
		    int sock,
		    char *passwd,
		    const char *host)
{
    krb5_error_code ret;
    krb5_data ap_req_data;
    krb5_data krb_priv_data;
    krb5_data pwd_data;
    ChangePasswdDataMS chpw;
    size_t len;
    u_char header[4 + 6];
    u_char *p;
    struct iovec iov[3];
    struct msghdr msghdr;

    krb5_data_zero (&ap_req_data);

    ret = krb5_mk_req_extended (context,
				auth_context,
				AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
				NULL, /* in_data */
				creds,
				&ap_req_data);
    if (ret)
	return ret;

    chpw.newpasswd.length = strlen(passwd);
    chpw.newpasswd.data = passwd;
    if (targprinc) {
	chpw.targname = &targprinc->name;
	chpw.targrealm = &targprinc->realm;
    } else {
	chpw.targname = NULL;
	chpw.targrealm = NULL;
    }
	
    ASN1_MALLOC_ENCODE(ChangePasswdDataMS, pwd_data.data, pwd_data.length,
		       &chpw, &len, ret);
    if (ret) {
	krb5_data_free (&ap_req_data);
	return ret;
    }

    if(pwd_data.length != len)
	krb5_abortx(context, "internal error in ASN.1 encoder");

    ret = krb5_mk_priv (context,
			*auth_context,
			&pwd_data,
			&krb_priv_data,
			NULL);
    if (ret)
	goto out2;

    len = 6 + ap_req_data.length + krb_priv_data.length;
    p = header;
    if (is_stream) {
	_krb5_put_int(p, len, 4);
	p += 4;
    }
    *p++ = (len >> 8) & 0xFF;
    *p++ = (len >> 0) & 0xFF;
    *p++ = 0xff;
    *p++ = 0x80;
    *p++ = (ap_req_data.length >> 8) & 0xFF;
    *p++ = (ap_req_data.length >> 0) & 0xFF;

    memset(&msghdr, 0, sizeof(msghdr));
    msghdr.msg_name       = NULL;
    msghdr.msg_namelen    = 0;
    msghdr.msg_iov        = iov;
    msghdr.msg_iovlen     = sizeof(iov)/sizeof(*iov);
#if 0
    msghdr.msg_control    = NULL;
    msghdr.msg_controllen = 0;
#endif

    iov[0].iov_base    = (void*)header;
    if (is_stream)
	iov[0].iov_len     = 10;
    else
	iov[0].iov_len     = 6;
    iov[1].iov_base    = ap_req_data.data;
    iov[1].iov_len     = ap_req_data.length;
    iov[2].iov_base    = krb_priv_data.data;
    iov[2].iov_len     = krb_priv_data.length;

    if (sendmsg (sock, &msghdr, 0) < 0) {
	ret = errno;
	krb5_set_error_string(context, "sendmsg %s: %s", host, strerror(ret));
    }

    krb5_data_free (&krb_priv_data);
out2:
    krb5_data_free (&ap_req_data);
    krb5_data_free (&pwd_data);
    return ret;
}
Пример #8
0
static ADS_STATUS do_krb5_kpasswd_request(krb5_context context,
					  const char *kdc_host,
					  uint16 pversion,
					  krb5_creds *credsp,
					  const char *princ,
					  const char *newpw)
{
	krb5_auth_context auth_context = NULL;
	krb5_data ap_req, chpw_req, chpw_rep;
	int ret, sock;
	socklen_t addr_len;
	struct sockaddr_storage remote_addr, local_addr;
	struct sockaddr_storage addr;
	krb5_address local_kaddr, remote_kaddr;
	bool use_tcp = False;


	if (!interpret_string_addr(&addr, kdc_host, 0)) {
	}

	ret = krb5_mk_req_extended(context, &auth_context, AP_OPTS_USE_SUBKEY,
				   NULL, credsp, &ap_req);
	if (ret) {
		DEBUG(1,("krb5_mk_req_extended failed (%s)\n", error_message(ret)));
		return ADS_ERROR_KRB5(ret);
	}

	do {

		if (!use_tcp) {

			sock = open_udp_socket(kdc_host, DEFAULT_KPASSWD_PORT);
			if (sock == -1) {
				int rc = errno;
				SAFE_FREE(ap_req.data);
				krb5_auth_con_free(context, auth_context);
				DEBUG(1,("failed to open kpasswd socket to %s "
					 "(%s)\n", kdc_host, strerror(errno)));
				return ADS_ERROR_SYSTEM(rc);
			}
		} else {
			NTSTATUS status;
			status = open_socket_out(&addr, DEFAULT_KPASSWD_PORT,
						 LONG_CONNECT_TIMEOUT, &sock);
			if (!NT_STATUS_IS_OK(status)) {
				SAFE_FREE(ap_req.data);
				krb5_auth_con_free(context, auth_context);
				DEBUG(1,("failed to open kpasswd socket to %s "
					 "(%s)\n", kdc_host,
					 nt_errstr(status)));
				return ADS_ERROR_NT(status);
			}
		}

		addr_len = sizeof(remote_addr);
		if (getpeername(sock, (struct sockaddr *)&remote_addr, &addr_len) != 0) {
			close(sock);
			SAFE_FREE(ap_req.data);
			krb5_auth_con_free(context, auth_context);
			DEBUG(1,("getpeername() failed (%s)\n", error_message(errno)));
			return ADS_ERROR_SYSTEM(errno);
		}
		addr_len = sizeof(local_addr);
		if (getsockname(sock, (struct sockaddr *)&local_addr, &addr_len) != 0) {
			close(sock);
			SAFE_FREE(ap_req.data);
			krb5_auth_con_free(context, auth_context);
			DEBUG(1,("getsockname() failed (%s)\n", error_message(errno)));
			return ADS_ERROR_SYSTEM(errno);
		}
		if (!setup_kaddr(&remote_kaddr, &remote_addr) ||
				!setup_kaddr(&local_kaddr, &local_addr)) {
			DEBUG(1,("do_krb5_kpasswd_request: "
				"Failed to setup addresses.\n"));
			close(sock);
			SAFE_FREE(ap_req.data);
			krb5_auth_con_free(context, auth_context);
			errno = EINVAL;
			return ADS_ERROR_SYSTEM(EINVAL);
		}

		ret = krb5_auth_con_setaddrs(context, auth_context, &local_kaddr, NULL);
		if (ret) {
			close(sock);
			SAFE_FREE(ap_req.data);
			krb5_auth_con_free(context, auth_context);
			DEBUG(1,("krb5_auth_con_setaddrs failed (%s)\n", error_message(ret)));
			return ADS_ERROR_KRB5(ret);
		}

		ret = build_kpasswd_request(pversion, context, auth_context, &ap_req,
					  princ, newpw, use_tcp, &chpw_req);
		if (ret) {
			close(sock);
			SAFE_FREE(ap_req.data);
			krb5_auth_con_free(context, auth_context);
			DEBUG(1,("build_setpw_request failed (%s)\n", error_message(ret)));
			return ADS_ERROR_KRB5(ret);
		}

		ret = write(sock, chpw_req.data, chpw_req.length); 

		if (ret != chpw_req.length) {
			close(sock);
			SAFE_FREE(chpw_req.data);
			SAFE_FREE(ap_req.data);
			krb5_auth_con_free(context, auth_context);
			DEBUG(1,("send of chpw failed (%s)\n", strerror(errno)));
			return ADS_ERROR_SYSTEM(errno);
		}
	
		SAFE_FREE(chpw_req.data);
	
		chpw_rep.length = 1500;
		chpw_rep.data = (char *) SMB_MALLOC(chpw_rep.length);
		if (!chpw_rep.data) {
			close(sock);
			SAFE_FREE(ap_req.data);
			krb5_auth_con_free(context, auth_context);
			DEBUG(1,("send of chpw failed (%s)\n", strerror(errno)));
			errno = ENOMEM;
			return ADS_ERROR_SYSTEM(errno);
		}
	
		ret = read(sock, chpw_rep.data, chpw_rep.length);
		if (ret < 0) {
			close(sock);
			SAFE_FREE(chpw_rep.data);
			SAFE_FREE(ap_req.data);
			krb5_auth_con_free(context, auth_context);
			DEBUG(1,("recv of chpw reply failed (%s)\n", strerror(errno)));
			return ADS_ERROR_SYSTEM(errno);
		}
	
		close(sock);
		chpw_rep.length = ret;
	
		ret = krb5_auth_con_setaddrs(context, auth_context, NULL,&remote_kaddr);
		if (ret) {
			SAFE_FREE(chpw_rep.data);
			SAFE_FREE(ap_req.data);
			krb5_auth_con_free(context, auth_context);
			DEBUG(1,("krb5_auth_con_setaddrs on reply failed (%s)\n", 
				 error_message(ret)));
			return ADS_ERROR_KRB5(ret);
		}
	
		ret = parse_setpw_reply(context, use_tcp, auth_context, &chpw_rep);
		SAFE_FREE(chpw_rep.data);
	
		if (ret) {
			
			if (ret == KRB5KRB_ERR_RESPONSE_TOO_BIG && !use_tcp) {
				DEBUG(5, ("Trying setpw with TCP!!!\n"));
				use_tcp = True;
				continue;
			}

			SAFE_FREE(ap_req.data);
			krb5_auth_con_free(context, auth_context);
			DEBUG(1,("parse_setpw_reply failed (%s)\n", 
				 error_message(ret)));
			return ADS_ERROR_KRB5(ret);
		}
	
		SAFE_FREE(ap_req.data);
		krb5_auth_con_free(context, auth_context);
	} while ( ret );

	return ADS_SUCCESS;
}
Пример #9
0
/*
** The logic for setting and changing a password is mostly the same
** change_set_password handles both cases
**      if set_password_for is NULL, then a password change is performed,
**  otherwise, the password is set for the principal indicated in set_password_for
*/
static krb5_error_code
change_set_password(krb5_context context,
                    krb5_creds *creds,
                    char *newpw,
                    krb5_principal set_password_for,
                    int *result_code,
                    krb5_data *result_code_string,
                    krb5_data *result_string)
{
    krb5_data                   chpw_rep;
    krb5_address                remote_kaddr;
    krb5_boolean                use_tcp = 0;
    GETSOCKNAME_ARG3_TYPE       addrlen;
    krb5_error_code             code = 0;
    char                        *code_string;
    int                         local_result_code;

    struct sendto_callback_context  callback_ctx;
    struct sendto_callback_info callback_info;
    struct sockaddr_storage     remote_addr;
    struct serverlist           sl = SERVERLIST_INIT;

    memset(&chpw_rep, 0, sizeof(krb5_data));
    memset( &callback_ctx, 0, sizeof(struct sendto_callback_context));
    callback_ctx.context = context;
    callback_ctx.newpw = newpw;
    callback_ctx.set_password_for = set_password_for;

    if ((code = krb5_auth_con_init(callback_ctx.context,
                                   &callback_ctx.auth_context)))
        goto cleanup;

    if ((code = krb5_mk_req_extended(callback_ctx.context,
                                     &callback_ctx.auth_context,
                                     AP_OPTS_USE_SUBKEY,
                                     NULL,
                                     creds,
                                     &callback_ctx.ap_req)))
        goto cleanup;

    callback_ctx.remote_seq_num = callback_ctx.auth_context->remote_seq_number;
    callback_ctx.local_seq_num = callback_ctx.auth_context->local_seq_number;

    do {
        int socktype = (use_tcp ? SOCK_STREAM : SOCK_DGRAM);
        code = locate_kpasswd(callback_ctx.context, &creds->server->realm, &sl,
                              socktype);
        if (code)
            break;

        addrlen = sizeof(remote_addr);

        callback_info.data = &callback_ctx;
        callback_info.pfn_callback = kpasswd_sendto_msg_callback;
        callback_info.pfn_cleanup = kpasswd_sendto_msg_cleanup;
        krb5_free_data_contents(callback_ctx.context, &chpw_rep);

        code = k5_sendto(callback_ctx.context, NULL, &sl, socktype, 0,
                         &callback_info, &chpw_rep, ss2sa(&remote_addr),
                         &addrlen, NULL, NULL, NULL);
        if (code) {
            /*
             * Here we may want to switch to TCP on some errors.
             * right?
             */
            break;
        }

        if (remote_addr.ss_family == AF_INET) {
            remote_kaddr.addrtype = ADDRTYPE_INET;
            remote_kaddr.length = sizeof(ss2sin(&remote_addr)->sin_addr);
            remote_kaddr.contents =
                (krb5_octet *) &ss2sin(&remote_addr)->sin_addr;
        } else if (remote_addr.ss_family == AF_INET6) {
            remote_kaddr.addrtype = ADDRTYPE_INET6;
            remote_kaddr.length = sizeof(ss2sin6(&remote_addr)->sin6_addr);
            remote_kaddr.contents =
                (krb5_octet *) &ss2sin6(&remote_addr)->sin6_addr;
        } else {
            break;
        }

        if ((code = krb5_auth_con_setaddrs(callback_ctx.context,
                                           callback_ctx.auth_context,
                                           NULL,
                                           &remote_kaddr)))
            break;

        code = krb5int_rd_chpw_rep(callback_ctx.context,
                                   callback_ctx.auth_context,
                                   &chpw_rep, &local_result_code,
                                   result_string);

        if (code) {
            if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !use_tcp) {
                k5_free_serverlist(&sl);
                use_tcp = 1;
                continue;
            }

            break;
        }

        if (result_code)
            *result_code = local_result_code;

        if (result_code_string) {
            code = krb5_chpw_result_code_string(callback_ctx.context,
                                                local_result_code,
                                                &code_string);
            if (code)
                goto cleanup;

            result_code_string->length = strlen(code_string);
            result_code_string->data = malloc(result_code_string->length);
            if (result_code_string->data == NULL) {
                code = ENOMEM;
                goto cleanup;
            }
            strncpy(result_code_string->data, code_string, result_code_string->length);
        }

        if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !use_tcp) {
            k5_free_serverlist(&sl);
            use_tcp = 1;
        } else {
            break;
        }
    } while (TRUE);

cleanup:
    if (callback_ctx.auth_context != NULL)
        krb5_auth_con_free(callback_ctx.context, callback_ctx.auth_context);

    k5_free_serverlist(&sl);
    krb5_free_data_contents(callback_ctx.context, &callback_ctx.ap_req);
    krb5_free_data_contents(callback_ctx.context, &chpw_rep);

    return(code);
}
Пример #10
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);
}
Пример #11
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;
}
Пример #12
0
krb5_error_code KRB5_CALLCONV
krb5_verify_init_creds(krb5_context context,
		       krb5_creds *creds,
		       krb5_principal server_arg,
		       krb5_keytab keytab_arg,
		       krb5_ccache *ccache_arg,
		       krb5_verify_init_creds_opt *options)
{
   krb5_error_code ret;
   krb5_principal server;
   krb5_keytab keytab;
   krb5_ccache ccache;
   krb5_keytab_entry kte;
   krb5_creds in_creds, *out_creds;
   krb5_auth_context authcon;
   krb5_data ap_req;
   
   /* KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN */

   server = NULL;
   keytab = NULL;
   ccache = NULL;
   out_creds = NULL;
   authcon = NULL;
   ap_req.data = NULL;

   if (server_arg)
      server = server_arg;
   else if (ret = krb5_sname_to_principal(context, NULL, NULL, 
					KRB5_NT_SRV_HST, &server))
      goto cleanup;
      
   /* first, check if the server is in the keytab.  If not, there's
      no reason to continue.  rd_req does all this, but there's
      no way to know that a given error is caused by a missing
      keytab or key, and not by some other problem. */

   if (keytab_arg) {
      keytab = keytab_arg;
   } else {
       /* Solaris Kerberos: ignore errors here, deal with below */
      ret = krb5_kt_default(context, &keytab);
   }

   /* Warning: be very, very careful when modifying the logic here */
   if (keytab == NULL ||
       (ret = krb5_kt_get_entry(context, keytab, server, 0, 0, &kte))) {
       /* this means there is no keying material.  This is ok, as long as
	  it is not prohibited by the configuration */

       int nofail = 1;  /* Solaris Kerberos: default return error if keytab problems */

       if (options &&
	   (options->flags & KRB5_VERIFY_INIT_CREDS_OPT_AP_REQ_NOFAIL)) {
	   /* first, if options are set then use the option value to set nofail */
	    nofail = options->ap_req_nofail;
       } else {
	   /* 
	    * Check verify_ap_req_nofail if set in config file.  Note this logic
	    * assumes that krb5_libdefault_boolean will not set nofail to a
	    * default value if verify_ap_req_nofail is not explictly set in
	    * config file.  Don't care about the return code.
	    */
	   (void) krb5_libdefault_boolean(context, &creds->client->realm,
					  "verify_ap_req_nofail",
					  &nofail);
       }
       /* Solaris Kerberos: exit without an error ONLY if nofail is false */
       if (!nofail)
	   ret = 0; 

       goto cleanup;
   }

   krb5_kt_free_entry(context, &kte);

   /* If the creds are for the server principal, we're set, just do
      a mk_req.	 Otherwise, do a get_credentials first. */

   if (krb5_principal_compare(context, server, creds->server)) {
      /* make an ap_req */
      if ((ret = krb5_mk_req_extended(context, &authcon, 0, NULL, creds,
				     &ap_req)))
	 goto cleanup;
   } else {
      /* this is unclean, but it's the easiest way without ripping the
	 library into very small pieces.  store the client's initial cred
	 in a memory ccache, then call the library.  Later, we'll copy
	 everything except the initial cred into the ccache we return to
	 the user.  A clean implementation would involve library
	 internals with a coherent idea of "in" and "out". */

      /* insert the initial cred into the ccache */

      if ((ret = krb5_cc_resolve(context, "MEMORY:rd_req", &ccache)))
	 goto cleanup;

      if ((ret = krb5_cc_initialize(context, ccache, creds->client)) != NULL)
	 goto cleanup;

      if ((ret = krb5_cc_store_cred(context, ccache, creds)) != NULL)
	 goto cleanup;

      /* set up for get_creds */
      memset(&in_creds, 0, sizeof(in_creds));
      in_creds.client = creds->client;
      in_creds.server = server;
      if ((ret = krb5_timeofday(context, &in_creds.times.endtime)))
	 goto cleanup;
      in_creds.times.endtime += 5*60;

      if ((ret = krb5_get_credentials(context, 0, ccache, &in_creds,
				     &out_creds)))
	 goto cleanup;

      /* make an ap_req */
      if ((ret = krb5_mk_req_extended(context, &authcon, 0, NULL, out_creds,
				     &ap_req)))
	 goto cleanup;
   }

   /* wipe the auth context for mk_req */
   if (authcon) {
      krb5_auth_con_free(context, authcon);
      authcon = NULL;
   }

   /* verify the ap_req */

   if ((ret = krb5_rd_req(context, &authcon, &ap_req, server, keytab,
			 NULL, NULL)))
      goto cleanup;

   /* if we get this far, then the verification succeeded.  We can
      still fail if the library stuff here fails, but that's it */

   if (ccache_arg && ccache) {
       if (*ccache_arg == NULL) {
	   krb5_ccache retcc;

	   retcc = NULL;

	   if (((ret = krb5_cc_resolve(context, "MEMORY:rd_req2", &retcc)) != NULL) ||
	       ((ret = krb5_cc_initialize(context, retcc, creds->client)) != NULL) ||
	       ((ret = krb5_cc_copy_creds_except(context, ccache, retcc,
						creds->server)) != NULL)) {
	       if (retcc)
		   (void) krb5_cc_destroy(context, retcc);
	   } else {
	       *ccache_arg = retcc;
	   }
       } else {
	   ret = krb5_cc_copy_creds_except(context, ccache, *ccache_arg,
					   server);
       }
   }

   /* if any of the above paths returned an errors, then ret is set
      accordingly.  either that, or it's zero, which is fine, too */

cleanup:
   if (!server_arg && server)
      krb5_free_principal(context, server);
   if (!keytab_arg && keytab)
      (void) krb5_kt_close(context, keytab);
   if (ccache)
      (void) krb5_cc_destroy(context, ccache);
   if (out_creds)
      krb5_free_creds(context, out_creds);
   if (authcon)
      krb5_auth_con_free(context, authcon);
   if (ap_req.data)
      krb5_xfree(ap_req.data);

   return(ret);
}
Пример #13
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;
}
Пример #14
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;
}
Пример #15
0
/*	Given krb5 service (typically "kssl") and hostname in kssl_ctx,
**	Return encrypted Kerberos ticket for service @ hostname.
**	If authenp is non-NULL, also return encrypted authenticator,
**	whose data should be freed by caller.
**	(Originally was: Create Kerberos AP_REQ message for SSL Client.)
**
**	19990628	VRS 	Started; Returns Kerberos AP_REQ message.
**	20010409	VRS 	Modified for RFC2712; Returns enc tkt.
**	20010606	VRS 	May also return optional authenticator.
*/
krb5_error_code
kssl_cget_tkt(
	/* UPDATE */	KSSL_CTX *kssl_ctx,
	/* OUT    */	krb5_data **enc_ticketp,
	/* UPDATE */	krb5_data *authenp,
	/* OUT    */	KSSL_ERR *kssl_err)
{
	krb5_error_code		krb5rc = KRB5KRB_ERR_GENERIC;
	krb5_context		krb5context = NULL;
	krb5_auth_context	krb5auth_context = NULL;
	krb5_ccache 		krb5ccdef = NULL;
	krb5_creds		krb5creds, *krb5credsp = NULL;
	krb5_data		krb5_app_req;

	kssl_err_set(kssl_err, 0, "");
	memset((char *)&krb5creds, 0, sizeof(krb5creds));

	if (!kssl_ctx) {
		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
		    "No kssl_ctx defined.\n");
		goto err;
	} else if (!kssl_ctx->service_host) {
		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
		    "kssl_ctx service_host undefined.\n");
		goto err;
	}

	if ((krb5rc = krb5_init_context(&krb5context)) != 0) {
		(void) snprintf(kssl_err->text,KSSL_ERR_MAX,
		    "krb5_init_context() fails: %d\n", krb5rc);
		kssl_err->reason = SSL_R_KRB5_C_INIT;
		goto err;
	}

	if ((krb5rc = krb5_sname_to_principal(krb5context,
	    kssl_ctx->service_host,
	    (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC,
            KRB5_NT_SRV_HST, &krb5creds.server)) != 0) {
		(void) snprintf(kssl_err->text,KSSL_ERR_MAX,
		    "krb5_sname_to_principal() fails for %s/%s\n",
		    kssl_ctx->service_host,
		    (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC);
		kssl_err->reason = SSL_R_KRB5_C_INIT;
		goto err;
	}

	if ((krb5rc = krb5_cc_default(krb5context, &krb5ccdef)) != 0) {
		kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC,
		    "krb5_cc_default fails.\n");
		goto err;
	}

	if ((krb5rc = krb5_cc_get_principal(krb5context, krb5ccdef,
                &krb5creds.client)) != 0)
                {
		kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC,
                        "krb5_cc_get_principal() fails.\n");
		goto err;
		}

	if ((krb5rc = krb5_get_credentials(krb5context, 0, krb5ccdef,
	    &krb5creds, &krb5credsp)) != 0) {
		kssl_err_set(kssl_err, SSL_R_KRB5_C_GET_CRED,
		    "krb5_get_credentials() fails.\n");
		goto err;
	}

	*enc_ticketp = &krb5credsp->ticket;
#ifdef KRB5_HEIMDAL
	kssl_ctx->enctype = krb5credsp->session.keytype;
#else
	kssl_ctx->enctype = krb5credsp->keyblock.enctype;
#endif

	krb5rc = KRB5KRB_ERR_GENERIC;
	/*	caller should free data of krb5_app_req  */
	/*  20010406 VRS deleted for real KerberosWrapper
	**  20010605 VRS reinstated to offer Authenticator to KerberosWrapper
	*/
	krb5_app_req.length = 0;
	if (authenp) {
		krb5_data	krb5in_data;
		const unsigned char	*p;
		long		arlen;
		KRB5_APREQBODY	*ap_req;

		authenp->length = 0;
		krb5in_data.data = NULL;
		krb5in_data.length = 0;
		if ((krb5rc = krb5_mk_req_extended(krb5context,
		    &krb5auth_context, 0, &krb5in_data, krb5credsp,
		    &krb5_app_req)) != 0) {
			kssl_err_set(kssl_err, SSL_R_KRB5_C_MK_REQ,
			    "krb5_mk_req_extended() fails.\n");
			goto err;
		}

		arlen = krb5_app_req.length;
		p = (unsigned char *)krb5_app_req.data;
		ap_req = (KRB5_APREQBODY *) d2i_KRB5_APREQ(NULL, &p, arlen);
		if (ap_req) {
			authenp->length = i2d_KRB5_ENCDATA(
			ap_req->authenticator, NULL);
			if (authenp->length &&
			    (authenp->data = malloc(authenp->length))) {
				unsigned char	*adp = (unsigned char *)authenp->data;
				authenp->length = i2d_KRB5_ENCDATA(
				ap_req->authenticator, &adp);
			}
		}

		if (ap_req)
			KRB5_APREQ_free((KRB5_APREQ *) ap_req);
		if (krb5_app_req.length)
			kssl_krb5_free_data_contents(krb5context, &krb5_app_req);
	}
#ifdef KRB5_HEIMDAL
	if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->session)) {
		kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
		    "kssl_ctx_setkey() fails.\n");
	}
#else
	if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->keyblock)) {
		kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
		    "kssl_ctx_setkey() fails.\n");
	}
#endif
	else
		krb5rc = 0;

	err:
#ifdef KSSL_DEBUG
	kssl_ctx_show(kssl_ctx);
#endif	/* KSSL_DEBUG */

	if (krb5creds.client)
		krb5_free_principal(krb5context, krb5creds.client);
	if (krb5creds.server)
		krb5_free_principal(krb5context, krb5creds.server);
	if (krb5auth_context)
		krb5_auth_con_free(krb5context, krb5auth_context);
	if (krb5context)
		krb5_free_context(krb5context);
	return (krb5rc);
}
Пример #16
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);
}
Пример #17
0
static krb5_error_code
get_vfy_cred(krb5_context context, krb5_creds *creds, krb5_principal server,
             krb5_keytab keytab, krb5_ccache *ccache_arg)
{
    krb5_error_code ret;
    krb5_ccache ccache = NULL, retcc = NULL;
    krb5_creds in_creds, *out_creds = NULL;
    krb5_auth_context authcon = NULL;
    krb5_data ap_req = empty_data();

    /* If the creds are for the server principal, we're set, just do a mk_req.
     * Otherwise, do a get_credentials first. */
    if (krb5_principal_compare(context, server, creds->server)) {
        /* Make an ap-req. */
        ret = krb5_mk_req_extended(context, &authcon, 0, NULL, creds, &ap_req);
        if (ret)
            goto cleanup;
    } else {
        /*
         * This is unclean, but it's the easiest way without ripping the
         * library into very small pieces.  store the client's initial cred
         * in a memory ccache, then call the library.  Later, we'll copy
         * everything except the initial cred into the ccache we return to
         * the user.  A clean implementation would involve library
         * internals with a coherent idea of "in" and "out".
         */

        /* Insert the initial cred into the ccache. */
        ret = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache);
        if (ret)
            goto cleanup;
        ret = krb5_cc_initialize(context, ccache, creds->client);
        if (ret)
            goto cleanup;
        ret = krb5_cc_store_cred(context, ccache, creds);
        if (ret)
            goto cleanup;

        /* Get credentials with get_creds. */
        memset(&in_creds, 0, sizeof(in_creds));
        in_creds.client = creds->client;
        in_creds.server = server;
        ret = krb5_timeofday(context, &in_creds.times.endtime);
        if (ret)
            goto cleanup;
        in_creds.times.endtime += 5*60;
        ret = krb5_get_credentials(context, 0, ccache, &in_creds, &out_creds);
        if (ret)
            goto cleanup;

        /* Make an ap-req. */
        ret = krb5_mk_req_extended(context, &authcon, 0, NULL, out_creds,
                                   &ap_req);
        if (ret)
            goto cleanup;
    }

    /* Wipe the auth context created by mk_req. */
    if (authcon) {
        krb5_auth_con_free(context, authcon);
        authcon = NULL;
    }

    /* Verify the ap_req. */
    ret = krb5_rd_req(context, &authcon, &ap_req, server, keytab, NULL, NULL);
    if (ret)
        goto cleanup;

    /* If we get this far, then the verification succeeded.  We can
     * still fail if the library stuff here fails, but that's it. */
    if (ccache_arg != NULL && ccache != NULL) {
        if (*ccache_arg == NULL) {
            ret = krb5_cc_resolve(context, "MEMORY:rd_req2", &retcc);
            if (ret)
                goto cleanup;
            ret = krb5_cc_initialize(context, retcc, creds->client);
            if (ret)
                goto cleanup;
            ret = copy_creds_except(context, ccache, retcc, creds->server);
            if (ret)
                goto cleanup;
            *ccache_arg = retcc;
            retcc = NULL;
        } else {
            ret = copy_creds_except(context, ccache, *ccache_arg, server);
        }
    }

cleanup:
    if (retcc != NULL)
        krb5_cc_destroy(context, retcc);
    if (ccache != NULL)
        krb5_cc_destroy(context, ccache);
    krb5_free_creds(context, out_creds);
    krb5_auth_con_free(context, authcon);
    krb5_free_data_contents(context, &ap_req);
    return ret;
}
Пример #18
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_sendauth(krb5_context context,
	      krb5_auth_context *auth_context,
	      krb5_pointer p_fd,
	      const char *appl_version,
	      krb5_principal client,
	      krb5_principal server,
	      krb5_flags ap_req_options,
	      krb5_data *in_data,
	      krb5_creds *in_creds,
	      krb5_ccache ccache,
	      krb5_error **ret_error,
	      krb5_ap_rep_enc_part **rep_result,
	      krb5_creds **out_creds)
{
    krb5_error_code ret;
    uint32_t len, net_len;
    const char *version = KRB5_SENDAUTH_VERSION;
    u_char repl;
    krb5_data ap_req, error_data;
    krb5_creds this_cred;
    krb5_principal this_client = NULL;
    krb5_creds *creds;
    ssize_t sret;
    krb5_boolean my_ccache = FALSE;

    len = strlen(version) + 1;
    net_len = htonl(len);
    if (krb5_net_write (context, p_fd, &net_len, 4) != 4
	|| krb5_net_write (context, p_fd, version, len) != len) {
	ret = errno;
	krb5_set_error_string (context, "write: %s", strerror(ret));
	return ret;
    }

    len = strlen(appl_version) + 1;
    net_len = htonl(len);
    if (krb5_net_write (context, p_fd, &net_len, 4) != 4
	|| krb5_net_write (context, p_fd, appl_version, len) != len) {
	ret = errno;
	krb5_set_error_string (context, "write: %s", strerror(ret));
	return ret;
    }

    sret = krb5_net_read (context, p_fd, &repl, sizeof(repl));
    if (sret < 0) {
	ret = errno;
	krb5_set_error_string (context, "read: %s", strerror(ret));
	return ret;
    } else if (sret != sizeof(repl)) {
	krb5_clear_error_string (context);
	return KRB5_SENDAUTH_BADRESPONSE;
    }

    if (repl != 0) {
	krb5_clear_error_string (context);
	return KRB5_SENDAUTH_REJECTED;
    }

    if (in_creds == NULL) {
	if (ccache == NULL) {
	    ret = krb5_cc_default (context, &ccache);
	    if (ret)
		return ret;
	    my_ccache = TRUE;
	}

	if (client == NULL) {
	    ret = krb5_cc_get_principal (context, ccache, &this_client);
	    if (ret) {
		if(my_ccache)
		    krb5_cc_close(context, ccache);
		return ret;
	    }
	    client = this_client;
	}
	memset(&this_cred, 0, sizeof(this_cred));
	this_cred.client = client;
	this_cred.server = server;
	this_cred.times.endtime = 0;
	this_cred.ticket.length = 0;
	in_creds = &this_cred;
    }
    if (in_creds->ticket.length == 0) {
	ret = krb5_get_credentials (context, 0, ccache, in_creds, &creds);
	if (ret) {
	    if(my_ccache)
		krb5_cc_close(context, ccache);
	    return ret;
	}
    } else {
	creds = in_creds;
    }
    if(my_ccache)
	krb5_cc_close(context, ccache);
    ret = krb5_mk_req_extended (context,
				auth_context,
				ap_req_options,
				in_data,
				creds,
				&ap_req);

    if (out_creds)
	*out_creds = creds;
    else
	krb5_free_creds(context, creds);
    if(this_client)
	krb5_free_principal(context, this_client);

    if (ret)
	return ret;

    ret = krb5_write_message (context,
			      p_fd,
			      &ap_req);
    if (ret)
	return ret;

    krb5_data_free (&ap_req);

    ret = krb5_read_message (context, p_fd, &error_data);
    if (ret)
	return ret;

    if (error_data.length != 0) {
	KRB_ERROR error;

	ret = krb5_rd_error (context, &error_data, &error);
	krb5_data_free (&error_data);
	if (ret == 0) {
	    ret = krb5_error_from_rd_error(context, &error, NULL);
	    if (ret_error != NULL) {
		*ret_error = malloc (sizeof(krb5_error));
		if (*ret_error == NULL) {
		    krb5_free_error_contents (context, &error);
		} else {
		    **ret_error = error;
		}
	    } else {
		krb5_free_error_contents (context, &error);
	    }
	    return ret;
	} else {
	    krb5_clear_error_string(context);
	    return ret;
	}
    }

    if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED) {
	krb5_data ap_rep;
	krb5_ap_rep_enc_part *ignore;

	krb5_data_zero (&ap_rep);
	ret = krb5_read_message (context,
				 p_fd,
				 &ap_rep);
	if (ret)
	    return ret;

	ret = krb5_rd_rep (context, *auth_context, &ap_rep,
			   rep_result ? rep_result : &ignore);
	krb5_data_free (&ap_rep);
	if (ret)
	    return ret;
	if (rep_result == NULL)
	    krb5_free_ap_rep_enc_part (context, ignore);
    }
    return 0;
}
Пример #19
0
int Condor_Auth_Kerberos :: authenticate_client_kerberos()
{
    krb5_error_code        code;
    krb5_flags             flags;
    krb5_data              request;
    int                    reply, rc = FALSE;
    
    request.data = 0;
    request.length = 0;
    //------------------------------------------
    // Set up the flags
    //------------------------------------------
    flags = AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY;
    
    //------------------------------------------
    // Load local addresses
    //------------------------------------------
	assert(creds_);
    if (creds_->addresses == NULL) {
		dprintf ( D_SECURITY, "KERBEROS: creds_->addresses == NULL\n");
        if ((code = krb5_os_localaddr(krb_context_, &(creds_->addresses)))) {
            goto error;
        }
    }
    
	dprintf_krb5_principal ( D_FULLDEBUG, "KERBEROS: creds_->client is '%s'\n", creds_->client);
	dprintf_krb5_principal ( D_FULLDEBUG, "KERBEROS: creds_->server is '%s'\n", creds_->server);
   
    //------------------------------------------
    // Let's create the KRB_AP_REQ message
    //------------------------------------------    
    if ((code = krb5_mk_req_extended(krb_context_, 
                                    &auth_context_, 
                                    flags,
                                    0, 
                                    creds_, 
                                    &request))) {
        goto error;
    }
    
    // Send out the request
    if ((reply = send_request(&request)) != KERBEROS_MUTUAL) {
        dprintf( D_ALWAYS, "KERBEROS: Could not authenticate!\n" );
        return FALSE;
    }
    
    //------------------------------------------
    // Now, mutual authenticate
    //------------------------------------------
    reply = client_mutual_authenticate();

    switch (reply) 
        {
        case KERBEROS_DENY:
            dprintf( D_ALWAYS, "KERBEROS: Authentication failed\n" );
            return FALSE;
            break; // unreachable
        case KERBEROS_FORWARD:
            // We need to forward the credentials
            // We could do a fast forwarding (i.e stashing, if client/server
            // are located on the same machine. However, I want to keep the
            // forwarding mechanism clean, so, we use krb5_fwd_tgt_creds
            // regardless of where client/server are located
            
            // This is an implict GRANT
            //if (forward_tgt_creds(creds_, 0)) {
            //    dprintf(D_ALWAYS,"KERBEROS: Unable to forward credentials\n");
            //return FALSE;  
            //            }
        case KERBEROS_GRANT:
            break; 
        default:
            dprintf( D_ALWAYS, "KERBEROS: Response is invalid\n" );
            break;
        }
    
    //------------------------------------------
    // Success, do some cleanup
    //------------------------------------------
    setRemoteAddress();
    
    //------------------------------------------
    // Store the session key for encryption
    //------------------------------------------
    if ((code = krb5_copy_keyblock(krb_context_, &(creds_->keyblock), &sessionKey_))) {
        goto error;			  
    } 

    rc = TRUE;
    goto cleanup;
    
 error:
    dprintf( D_ALWAYS, "KERBEROS: %s\n", error_message(code) );
    // Abort
    mySock_->encode();
    reply = KERBEROS_ABORT;
    if (!mySock_->code(reply) || !mySock_->end_of_message()) {
        dprintf( D_ALWAYS, "KERBEROS: Failed to send ABORT message.\n");
    }

    rc = FALSE;
    
 cleanup:
    
    if (creds_) {
        krb5_free_creds(krb_context_, creds_);
    }
    
    if (request.data) {
        free(request.data);
    }
    
    return rc;
}
Пример #20
0
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_verify_init_creds(krb5_context context,
		       krb5_creds *creds,
		       krb5_principal ap_req_server,
		       krb5_keytab ap_req_keytab,
		       krb5_ccache *ccache,
		       krb5_verify_init_creds_opt *options)
{
    krb5_error_code ret;
    krb5_data req;
    krb5_ccache local_ccache = NULL;
    krb5_creds *new_creds = NULL;
    krb5_auth_context auth_context = NULL;
    krb5_principal server = NULL;
    krb5_keytab keytab = NULL;

    krb5_data_zero (&req);

    if (ap_req_server == NULL) {
	char local_hostname[MAXHOSTNAMELEN];

	if (gethostname (local_hostname, sizeof(local_hostname)) < 0) {
	    ret = errno;
	    krb5_set_error_message (context, ret, "gethostname: %s",
				    strerror(ret));
	    return ret;
	}

	ret = krb5_sname_to_principal (context,
				       local_hostname,
				       "host",
				       KRB5_NT_SRV_HST,
				       &server);
	if (ret)
	    goto cleanup;
    } else
	server = ap_req_server;

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

    if (ccache && *ccache)
	local_ccache = *ccache;
    else {
	ret = krb5_cc_new_unique(context, krb5_cc_type_memory,
				 NULL, &local_ccache);
	if (ret)
	    goto cleanup;
	ret = krb5_cc_initialize (context,
				  local_ccache,
				  creds->client);
	if (ret)
	    goto cleanup;
	ret = krb5_cc_store_cred (context,
				  local_ccache,
				  creds);
	if (ret)
	    goto cleanup;
    }

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

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

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

	ret = krb5_get_credentials (context,
				    0,
				    local_ccache,
				    &match_cred,
				    &new_creds);
	if (ret) {
	    if (fail_verify_is_ok (context, options))
		ret = 0;
	    goto cleanup;
	}
	creds = new_creds;
    }

    ret = krb5_mk_req_extended (context,
				&auth_context,
				0,
				NULL,
				creds,
				&req);

    krb5_auth_con_free (context, auth_context);
    auth_context = NULL;

    if (ret)
	goto cleanup;

    ret = krb5_rd_req (context,
		       &auth_context,
		       &req,
		       server,
		       keytab,
		       0,
		       NULL);

    if (ret == KRB5_KT_NOTFOUND && fail_verify_is_ok (context, options))
	ret = 0;
cleanup:
    if (auth_context)
	krb5_auth_con_free (context, auth_context);
    krb5_data_free (&req);
    if (new_creds != NULL)
	krb5_free_creds (context, new_creds);
    if (ap_req_server == NULL && server)
	krb5_free_principal (context, server);
    if (ap_req_keytab == NULL && keytab)
	krb5_kt_close (context, keytab);
    if (local_ccache != NULL
	&&
	(ccache == NULL
	 || (ret != 0 && *ccache == NULL)))
	krb5_cc_destroy (context, local_ccache);

    if (ret == 0 && ccache != NULL && *ccache == NULL)
	*ccache = local_ccache;

    return ret;
}
Пример #21
0
static int
cifs_krb5_get_req(const char *host, const char *ccname,
		  DATA_BLOB * mechtoken, DATA_BLOB * sess_key)
{
	krb5_error_code ret;
	krb5_keyblock *tokb;
	krb5_context context;
	krb5_ccache ccache;
	krb5_creds in_creds, *out_creds;
	krb5_data apreq_pkt, in_data;
	krb5_auth_context auth_context = NULL;
#if defined(HAVE_KRB5_AUTH_CON_SETADDRS) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE)
	static const uint8_t gss_cksum[24] = { 0x10, 0x00, /* ... */};
#endif

	ret = krb5_init_context(&context);
	if (ret) {
		syslog(LOG_DEBUG, "%s: unable to init krb5 context", __func__);
		return ret;
	}

	ret = krb5_cc_resolve(context, ccname, &ccache);
	if (ret) {
		syslog(LOG_DEBUG, "%s: unable to resolve %s to ccache\n",
		       __func__, ccname);
		goto out_free_context;
	}

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

	ret = krb5_cc_get_principal(context, ccache, &in_creds.client);
	if (ret) {
		syslog(LOG_DEBUG, "%s: unable to get client principal name",
		       __func__);
		goto out_free_ccache;
	}

	ret = krb5_sname_to_principal(context, host, "cifs", KRB5_NT_UNKNOWN,
					&in_creds.server);
	if (ret) {
		syslog(LOG_DEBUG, "%s: unable to convert sname to princ (%s).",
		       __func__, host);
		goto out_free_principal;
	}

	ret = krb5_get_credentials(context, 0, ccache, &in_creds, &out_creds);
	krb5_free_principal(context, in_creds.server);
	if (ret) {
		syslog(LOG_DEBUG, "%s: unable to get credentials for %s",
		       __func__, host);
		goto out_free_principal;
	}

	in_data.length = 0;
	in_data.data = NULL;

	ret = krb5_auth_con_init(context, &auth_context);
	if (ret) {
		syslog(LOG_DEBUG, "%s: unable to create auth_context: %d",
		       __func__, ret);
		goto out_free_creds;
	}

#if defined(HAVE_KRB5_AUTH_CON_SETADDRS) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE)
	/* Ensure we will get an addressless ticket. */
	ret = krb5_auth_con_setaddrs(context, auth_context, NULL, NULL);
	if (ret) {
		syslog(LOG_DEBUG, "%s: unable to set NULL addrs: %d",
		       __func__, ret);
		goto out_free_auth;
	}

	/*
	 * Create a GSSAPI checksum (0x8003), see RFC 4121.
	 *
	 * The current layout is
	 *
	 * 0x10, 0x00, 0x00, 0x00 - length = 16
	 * 0x00, 0x00, 0x00, 0x00 - channel binding info - 16 zero bytes
	 * 0x00, 0x00, 0x00, 0x00
	 * 0x00, 0x00, 0x00, 0x00
	 * 0x00, 0x00, 0x00, 0x00
	 * 0x00, 0x00, 0x00, 0x00 - flags
	 *
	 * GSS_C_NO_CHANNEL_BINDINGS means 16 zero bytes,
	 * this is needed to work against some closed source
	 * SMB servers.
	 *
	 * See https://bugzilla.samba.org/show_bug.cgi?id=7890
	 */
	in_data.data = discard_const_p(char, gss_cksum);
	in_data.length = 24;

	/* MIT krb5 < 1.7 is missing the prototype, but still has the symbol */
#if !HAVE_DECL_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE
	krb5_error_code krb5_auth_con_set_req_cksumtype(
		krb5_context      context,
		krb5_auth_context auth_context,
		krb5_cksumtype    cksumtype);
#endif
	ret = krb5_auth_con_set_req_cksumtype(context, auth_context, 0x8003);
	if (ret) {
		syslog(LOG_DEBUG, "%s: unable to set 0x8003 checksum",
		       __func__);
		goto out_free_auth;
	}
#endif

	apreq_pkt.length = 0;
	apreq_pkt.data = NULL;
	ret = krb5_mk_req_extended(context, &auth_context, AP_OPTS_USE_SUBKEY,
				   &in_data, out_creds, &apreq_pkt);
	if (ret) {
		syslog(LOG_DEBUG, "%s: unable to make AP-REQ for %s",
		       __func__, host);
		goto out_free_auth;
	}

	ret = krb5_auth_con_getsendsubkey(context, auth_context, &tokb);
	if (ret) {
		syslog(LOG_DEBUG, "%s: unable to get session key for %s",
		       __func__, host);
		goto out_free_auth;
	}

	*mechtoken = data_blob(apreq_pkt.data, apreq_pkt.length);
	*sess_key = data_blob(KRB5_KEY_DATA(tokb), KRB5_KEY_LENGTH(tokb));

	krb5_free_keyblock(context, tokb);
out_free_auth:
	krb5_auth_con_free(context, auth_context);
out_free_creds:
	krb5_free_creds(context, out_creds);
out_free_principal:
	krb5_free_principal(context, in_creds.client);
out_free_ccache:
#if defined(KRB5_TC_OPENCLOSE)
	krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
#endif
	krb5_cc_close(context, ccache);
out_free_context:
	krb5_free_context(context);
	return ret;
}
Пример #22
0
krb5_error_code KRB5_CALLCONV
krb5_verify_init_creds(krb5_context context,
                       krb5_creds *creds,
                       krb5_principal server_arg,
                       krb5_keytab keytab_arg,
                       krb5_ccache *ccache_arg,
                       krb5_verify_init_creds_opt *options)
{
    krb5_error_code ret;
    krb5_principal server;
    krb5_keytab keytab;
    krb5_ccache ccache;
    krb5_keytab_entry kte;
    krb5_creds in_creds, *out_creds;
    krb5_auth_context authcon;
    krb5_data ap_req;

    /* KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN */

    server = NULL;
    keytab = NULL;
    ccache = NULL;
    out_creds = NULL;
    authcon = NULL;
    ap_req.data = NULL;

    if (keytab_arg) {
        keytab = keytab_arg;
    } else {
        if ((ret = krb5_kt_default(context, &keytab)))
            goto cleanup;
    }

    if (server_arg) {
        ret = krb5_copy_principal(context, server_arg, &server);
        if (ret)
            goto cleanup;
    } else {
        /* Use a principal name from the keytab. */
        ret = k5_kt_get_principal(context, keytab, &server);
        if (ret) {
            /* There's no keytab, or it's empty, or we can't read it.
             * Allow this unless configuration demands verification. */
            if (!nofail(context, options, creds))
                ret = 0;
            goto cleanup;
        }
    }

    /* first, check if the server is in the keytab.  If not, there's
       no reason to continue.  rd_req does all this, but there's
       no way to know that a given error is caused by a missing
       keytab or key, and not by some other problem. */

    if (krb5_is_referral_realm(&server->realm)) {
        krb5_free_data_contents(context, &server->realm);
        ret = krb5_get_default_realm(context, &server->realm.data);
        if (ret) goto cleanup;
        server->realm.length = strlen(server->realm.data);
    }

    if ((ret = krb5_kt_get_entry(context, keytab, server, 0, 0, &kte))) {
        /* this means there is no keying material.  This is ok, as long as
           it is not prohibited by the configuration */
        if (!nofail(context, options, creds))
            ret = 0;
        goto cleanup;
    }

    krb5_kt_free_entry(context, &kte);

    /* If the creds are for the server principal, we're set, just do a mk_req.
     * Otherwise, do a get_credentials first.
     */

    if (krb5_principal_compare(context, server, creds->server)) {
        /* make an ap_req */
        if ((ret = krb5_mk_req_extended(context, &authcon, 0, NULL, creds,
                                        &ap_req)))
            goto cleanup;
    } else {
        /* this is unclean, but it's the easiest way without ripping the
           library into very small pieces.  store the client's initial cred
           in a memory ccache, then call the library.  Later, we'll copy
           everything except the initial cred into the ccache we return to
           the user.  A clean implementation would involve library
           internals with a coherent idea of "in" and "out". */

        /* insert the initial cred into the ccache */

        if ((ret = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache))) {
            ccache = NULL;
            goto cleanup;
        }

        if ((ret = krb5_cc_initialize(context, ccache, creds->client)))
            goto cleanup;

        if ((ret = krb5_cc_store_cred(context, ccache, creds)))
            goto cleanup;

        /* set up for get_creds */
        memset(&in_creds, 0, sizeof(in_creds));
        in_creds.client = creds->client;
        in_creds.server = server;
        if ((ret = krb5_timeofday(context, &in_creds.times.endtime)))
            goto cleanup;
        in_creds.times.endtime += 5*60;

        if ((ret = krb5_get_credentials(context, 0, ccache, &in_creds,
                                        &out_creds)))
            goto cleanup;

        /* make an ap_req */
        if ((ret = krb5_mk_req_extended(context, &authcon, 0, NULL, out_creds,
                                        &ap_req)))
            goto cleanup;
    }

    /* wipe the auth context for mk_req */
    if (authcon) {
        krb5_auth_con_free(context, authcon);
        authcon = NULL;
    }

    /* verify the ap_req */

    if ((ret = krb5_rd_req(context, &authcon, &ap_req, server, keytab,
                           NULL, NULL)))
        goto cleanup;

    /* if we get this far, then the verification succeeded.  We can
       still fail if the library stuff here fails, but that's it */

    if (ccache_arg && ccache) {
        if (*ccache_arg == NULL) {
            krb5_ccache retcc;

            retcc = NULL;

            if ((ret = krb5_cc_resolve(context, "MEMORY:rd_req2", &retcc)) ||
                (ret = krb5_cc_initialize(context, retcc, creds->client)) ||
                (ret = copy_creds_except(context, ccache, retcc,
                                         creds->server))) {
                if (retcc)
                    krb5_cc_destroy(context, retcc);
            } else {
                *ccache_arg = retcc;
            }
        } else {
            ret = copy_creds_except(context, ccache, *ccache_arg,
                                    server);
        }
    }

    /* if any of the above paths returned an errors, then ret is set accordingly.
     * Either that, or it's zero, which is fine, too
     */

cleanup:
    if ( server)
        krb5_free_principal(context, server);
    if (!keytab_arg && keytab)
        krb5_kt_close(context, keytab);
    if (ccache)
        krb5_cc_destroy(context, ccache);
    if (out_creds)
        krb5_free_creds(context, out_creds);
    if (authcon)
        krb5_auth_con_free(context, authcon);
    if (ap_req.data)
        free(ap_req.data);

    return(ret);
}
Пример #23
0
/*
  we can't use krb5_mk_req because w2k wants the service to be in a particular format
*/
static krb5_error_code ads_krb5_mk_req(krb5_context context, 
				       krb5_auth_context *auth_context, 
				       const krb5_flags ap_req_options,
				       const char *principal,
				       krb5_ccache ccache, 
				       krb5_data *outbuf, 
				       time_t *expire_time)
{
	krb5_error_code 	  retval;
	krb5_principal	  server;
	krb5_creds 		* credsp;
	krb5_creds 		  creds;
	krb5_data in_data;
	BOOL creds_ready = False;
	int i = 0, maxtries = 3;
	
	retval = smb_krb5_parse_name(context, principal, &server);
	if (retval) {
		DEBUG(1,("ads_krb5_mk_req: Failed to parse principal %s\n", principal));
		return retval;
	}
	
	/* obtain ticket & session key */
	ZERO_STRUCT(creds);
	if ((retval = krb5_copy_principal(context, server, &creds.server))) {
		DEBUG(1,("ads_krb5_mk_req: krb5_copy_principal failed (%s)\n", 
			 error_message(retval)));
		goto cleanup_princ;
	}
	
	if ((retval = krb5_cc_get_principal(context, ccache, &creds.client))) {
		/* This can commonly fail on smbd startup with no ticket in the cache.
		 * Report at higher level than 1. */
		DEBUG(3,("ads_krb5_mk_req: krb5_cc_get_principal failed (%s)\n", 
			 error_message(retval)));
		goto cleanup_creds;
	}

	while (!creds_ready && (i < maxtries)) {

		if ((retval = krb5_get_credentials(context, 0, ccache, 
						   &creds, &credsp))) {
			DEBUG(1,("ads_krb5_mk_req: krb5_get_credentials failed for %s (%s)\n",
				 principal, error_message(retval)));
			goto cleanup_creds;
		}

		/* cope with ticket being in the future due to clock skew */
		if ((unsigned)credsp->times.starttime > time(NULL)) {
			time_t t = time(NULL);
			int time_offset =(int)((unsigned)credsp->times.starttime-t);
			DEBUG(4,("ads_krb5_mk_req: Advancing clock by %d seconds to cope with clock skew\n", time_offset));
			krb5_set_real_time(context, t + time_offset + 1, 0);
		}

		if (!ads_cleanup_expired_creds(context, ccache, credsp)) {
			creds_ready = True;
		}

		i++;
	}

	DEBUG(10,("ads_krb5_mk_req: Ticket (%s) in ccache (%s:%s) is valid until: (%s - %u)\n",
		  principal, krb5_cc_get_type(context, ccache), krb5_cc_get_name(context, ccache),
		  http_timestring((unsigned)credsp->times.endtime), 
		  (unsigned)credsp->times.endtime));

	if (expire_time) {
		*expire_time = (time_t)credsp->times.endtime;
	}

	in_data.length = 0;
	retval = krb5_mk_req_extended(context, auth_context, ap_req_options, 
				      &in_data, credsp, outbuf);
	if (retval) {
		DEBUG(1,("ads_krb5_mk_req: krb5_mk_req_extended failed (%s)\n", 
			 error_message(retval)));
	}
	
	krb5_free_creds(context, credsp);

cleanup_creds:
	krb5_free_cred_contents(context, &creds);

cleanup_princ:
	krb5_free_principal(context, server);

	return retval;
}
Пример #24
0
static krb5_error_code
chgpw_send_request (krb5_context context,
		    krb5_auth_context *auth_context,
		    krb5_creds *creds,
		    krb5_principal targprinc,
		    int is_stream,
		    int sock,
		    char *passwd,
		    const char *host)
{
    krb5_error_code ret;
    krb5_data ap_req_data;
    krb5_data krb_priv_data;
    krb5_data passwd_data;
    size_t len;
    u_char header[6];
    u_char *p;
    struct iovec iov[3];
    struct msghdr msghdr;

    if (is_stream)
	return KRB5_KPASSWD_MALFORMED;

    if (targprinc &&
	krb5_principal_compare(context, creds->client, targprinc) != TRUE)
	return KRB5_KPASSWD_MALFORMED;

    krb5_data_zero (&ap_req_data);

    ret = krb5_mk_req_extended (context,
				auth_context,
				AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
				NULL, /* in_data */
				creds,
				&ap_req_data);
    if (ret)
	return ret;

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

    krb5_data_zero (&krb_priv_data);

    ret = krb5_mk_priv (context,
			*auth_context,
			&passwd_data,
			&krb_priv_data,
			NULL);
    if (ret)
	goto out2;

    len = 6 + ap_req_data.length + krb_priv_data.length;
    p = header;
    *p++ = (len >> 8) & 0xFF;
    *p++ = (len >> 0) & 0xFF;
    *p++ = 0;
    *p++ = 1;
    *p++ = (ap_req_data.length >> 8) & 0xFF;
    *p++ = (ap_req_data.length >> 0) & 0xFF;

    memset(&msghdr, 0, sizeof(msghdr));
    msghdr.msg_name       = NULL;
    msghdr.msg_namelen    = 0;
    msghdr.msg_iov        = iov;
    msghdr.msg_iovlen     = sizeof(iov)/sizeof(*iov);
#if 0
    msghdr.msg_control    = NULL;
    msghdr.msg_controllen = 0;
#endif

    iov[0].iov_base    = (void*)header;
    iov[0].iov_len     = 6;
    iov[1].iov_base    = ap_req_data.data;
    iov[1].iov_len     = ap_req_data.length;
    iov[2].iov_base    = krb_priv_data.data;
    iov[2].iov_len     = krb_priv_data.length;

    if (sendmsg (sock, &msghdr, 0) < 0) {
	ret = errno;
	krb5_set_error_string(context, "sendmsg %s: %s", host, strerror(ret));
    }

    krb5_data_free (&krb_priv_data);
out2:
    krb5_data_free (&ap_req_data);
    return ret;
}
Пример #25
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;
}
Пример #26
0
static krb5_error_code
setpw_prexmit(krb5_context context, int proto,
              void *ctx, int fd, krb5_data *data)
{
    struct request *request = ctx;
    krb5_data ap_req_data, krb_priv_data, pwd_data;
    krb5_error_code ret;
    ChangePasswdDataMS chpw;
    krb5_storage *sp = NULL;
    ssize_t slen;
    size_t len;

    krb5_data_zero(&ap_req_data);
    krb5_data_zero(&krb_priv_data);
    krb5_data_zero(&pwd_data);

    ret = krb5_auth_con_genaddrs(context, request->ac, fd,
                                 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR);
    if (ret)
        goto out;

    ret = krb5_mk_req_extended(context,
                               &request->ac,
                               AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
                               NULL,
                               request->creds,
                               &ap_req_data);
    if (ret)
        goto out;

    chpw.newpasswd.length = strlen(request->password);
    chpw.newpasswd.data = rk_UNCONST(request->password);
    if (request->target) {
        chpw.targname = &request->target->name;
        chpw.targrealm = &request->target->realm;
    } else {
        chpw.targname = NULL;
        chpw.targrealm = NULL;
    }

    ASN1_MALLOC_ENCODE(ChangePasswdDataMS, pwd_data.data, pwd_data.length,
                       &chpw, &len, ret);
    if (ret)
        goto out;
    if(pwd_data.length != len)
        krb5_abortx(context, "internal error in ASN.1 encoder");

    ret = krb5_mk_priv (context,
                        request->ac,
                        &pwd_data,
                        &krb_priv_data,
                        NULL);
    if (ret)
        goto out;

    sp = krb5_storage_emem();
    if (sp == NULL) {
        ret = ENOMEM;
        goto out;
    }

    len = 6 + ap_req_data.length + krb_priv_data.length;

    ret = krb5_store_uint16(sp, len);
    if (ret) goto out;
    ret = krb5_store_uint16(sp, 0xff80);
    if (ret) goto out;
    ret = krb5_store_uint16(sp, ap_req_data.length);
    if (ret) goto out;
    slen = krb5_storage_write(sp, ap_req_data.data, ap_req_data.length);
    if (slen != ap_req_data.length) {
        ret = EINVAL;
        goto out;
    }
    slen = krb5_storage_write(sp, krb_priv_data.data, krb_priv_data.length);
    if (slen != krb_priv_data.length) {
        ret = EINVAL;
        goto out;
    }

    ret = krb5_storage_to_data(sp, data);

out:
    if (ret)
        _krb5_debugx(context, 10, "setpw_prexmit failed with %d", ret);
    if (sp)
        krb5_storage_free(sp);
    krb5_data_free(&krb_priv_data);
    krb5_data_free(&ap_req_data);
    krb5_data_free(&pwd_data);

    return ret;
}
Пример #27
0
Code_t
Z_MakeZcodeAuthentication(register ZNotice_t *notice,
			  char *buffer,
			  int buffer_len,
			  int *phdr_len,
			  krb5_creds *creds)
{
    krb5_error_code result = 0;
    krb5_keyblock *keyblock;
    krb5_auth_context authctx;
    krb5_data *authent;
    char *cksum_start, *cstart, *cend;
    int cksum_len, zcode_len = 0, phdr_adj = 0;

    notice->z_ascii_authent = NULL;

    keyblock = Z_credskey(creds);

    authent = (krb5_data *)malloc(sizeof(krb5_data));
    if (authent == NULL)
	result = ENOMEM;
    authent->data = NULL; /* so that we can blithely krb5_fre_data_contents on
			     the way out */

    if (!result)
	result = krb5_auth_con_init(Z_krb5_ctx, &authctx);

    if (!result) {
	result = krb5_mk_req_extended(Z_krb5_ctx, &authctx, 0 /* options */,
				      0 /* in_data */, creds, authent);
	krb5_auth_con_free(Z_krb5_ctx, authctx);
    }
    if (!result || result == KRB5KRB_AP_ERR_TKT_EXPIRED) {
	notice->z_auth = 1;
	if (result == 0) {
	    notice->z_authent_len = authent->length;
	} else {
	    notice->z_authent_len = 0;
	    result = 0;
	}
	zcode_len = notice->z_authent_len * 2 + 2; /* 2x growth plus Z and null */
	notice->z_ascii_authent = (char *)malloc(zcode_len);
	if (notice->z_ascii_authent == NULL)
	    result = ENOMEM;
    }
    if (!result)
	result = ZMakeZcode(notice->z_ascii_authent, zcode_len,
			    (unsigned char *)authent->data, notice->z_authent_len);

    /* format the notice header, with a zero checksum */
    if (!result)
	result = Z_NewFormatRawHeader(notice, buffer, buffer_len, phdr_len,
				      &cksum_start, &cksum_len, &cstart, &cend);
    notice->z_authent_len = 0;
    if (!result)
	result = Z_InsertZcodeChecksum(keyblock, notice, buffer, cksum_start,
				       cksum_len, cstart, cend, buffer_len,
				       &phdr_adj, 0);
    if (!result) 
	*phdr_len += phdr_adj;

    if (notice->z_ascii_authent != NULL)
	free(notice->z_ascii_authent);
    krb5_free_data_contents(Z_krb5_ctx, authent);
    if (authent != NULL)
	free(authent);
    return result;
}