Beispiel #1
0
krb5_error_code
krb5int_tgtname(krb5_context context, const krb5_data *server, const krb5_data *client, krb5_principal *tgtprinc)
{
    return krb5_build_principal_ext(context, tgtprinc, client->length, client->data,
                                    KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
                                    server->length, server->data,
                                    0);
}
Beispiel #2
0
struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
{
  char svrnam[MAILTMPLEN],cltnam[MAILTMPLEN];
  krb5_context ctx;
  krb5_timestamp now;
  krb5_principal service;
  krb5_ccache ccache;
  krb5_error_code code;
  krb5_creds *crd = (krb5_creds *) memset (fs_get (sizeof (krb5_creds)),0,
						   sizeof (krb5_creds));
  struct passwd *ret = NIL;
  if (*pass) {			/* only if password non-empty */
				/* make service name */
    sprintf (svrnam,"%.80s@%.512s",
	     (char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
	     tcp_serverhost ());
				/* make client name with principal */
    sprintf (cltnam,"%.80s/%.80s",pw->pw_name,
	     (char *) mail_parameters (NIL,GET_SERVICENAME,NIL));
				/* get a context */
    if (!krb5_init_context (&ctx)) {
				/* get time, client and server principals */
      if (!krb5_timeofday (ctx,&now) &&
	/* Normally, kerb_cp_svr_name (defined/set in env_unix.c) is NIL, so
	 * only the user name is used as a client principal.  A few sites want
	 * to have separate client principals for different services, but many
	 * other sites vehemently object...
	 */
	  !krb5_parse_name (ctx,kerb_cp_svr_name ? cltnam : pw->pw_name,
			    &crd->client) &&
	  !krb5_parse_name (ctx,svrnam,&service) &&
	  !krb5_build_principal_ext(ctx,&crd->server,
				    krb5_princ_realm (ctx,crd->client)->length,
				    krb5_princ_realm (ctx,crd->client)->data,
				    KRB5_TGS_NAME_SIZE,KRB5_TGS_NAME,
				    krb5_princ_realm (ctx,crd->client)->length,
				    krb5_princ_realm (ctx,crd->client)->data,
				    0)) {
				/* expire in 3 minutes */
	crd->times.endtime = now + (3 * 60);
	if (krb5_cc_resolve (ctx,"MEMORY:pwk",&ccache) ||
	    krb5_cc_initialize (ctx,ccache,crd->client)) ccache = 0;
	if (!krb5_get_in_tkt_with_password (ctx,NIL,NIL,NIL,NIL,pass,ccache,
					    crd,0) &&
	    !krb5_verify_init_creds (ctx,crd,service,0,ccache ? &ccache : 0,0))
	  ret = pw;
	krb5_free_creds (ctx,crd);/* flush creds and service principal */
	krb5_free_principal (ctx,service);
      }
      krb5_free_context (ctx);	/* don't need context any more */
    }
  }
  return ret;
}
Beispiel #3
0
bool
v5::getTgtFromCcache (krb5_context context, krb5_creds *creds)
{
	krb5_ccache ccache;
	krb5_creds mcreds;
	krb5_principal principal, tgt_principal;
	bool ret;

	memset(&ccache, 0, sizeof(ccache));
	ret = FALSE;
	if (krb5_cc_default(context, &ccache) == 0)
	{
		memset(&principal, 0, sizeof(principal));
		if (krb5_cc_get_principal(context, ccache, &principal) == 0)
		{
			memset(&tgt_principal, 0, sizeof(tgt_principal));
			if (krb5_build_principal_ext(context, &tgt_principal,
			                             getPrincipalRealmLength(principal),
			                             getPrincipalRealmData(principal),
			                             KRB5_TGS_NAME_SIZE,
			                             KRB5_TGS_NAME,
			                             getPrincipalRealmLength(principal),
			                             getPrincipalRealmData(principal),
			                             0) == 0)
			{
				memset(creds, 0, sizeof(*creds));
				memset(&mcreds, 0, sizeof(mcreds));
				mcreds.client = principal;
				mcreds.server = tgt_principal;
				if (krb5_cc_retrieve_cred(context, ccache,
				                          0,
				                          &mcreds,
				                          creds) == 0)
				{
					ret = TRUE;
				}
				else
				{
					memset(creds, 0, sizeof(*creds));
				}
				krb5_free_principal(context, tgt_principal);
			}
			krb5_free_principal(context, principal);
		}
		krb5_cc_close(context, ccache);
	}
	return ret;
}
Beispiel #4
0
/*
 * Test whether anonymous authentication works.  If this doesn't, we need to
 * skip the tests of anonymous FAST.
 */
static bool
anon_fast_works(void)
{
    krb5_context ctx;
    krb5_error_code retval;
    krb5_principal princ = NULL;
    char *realm;
    krb5_creds creds;
    krb5_get_init_creds_opt *opts = NULL;

    /* Construct the anonymous principal name. */
    retval = krb5_init_context(&ctx);
    if (retval != 0)
        bail("cannot initialize Kerberos");
    retval = krb5_get_default_realm(ctx, &realm);
    if (retval != 0)
        bail("cannot get default realm");
    retval = krb5_build_principal_ext(ctx, &princ, strlen(realm), realm,
                 strlen(KRB5_WELLKNOWN_NAME), KRB5_WELLKNOWN_NAME,
                 strlen(KRB5_ANON_NAME), KRB5_ANON_NAME, NULL);
    if (retval != 0)
        bail("cannot construct anonymous principal");
    krb5_free_default_realm(ctx, realm);

    /* Obtain the credentials. */
    memset(&creds, 0, sizeof(creds));
    retval = krb5_get_init_creds_opt_alloc(ctx, &opts);
    if (retval != 0)
        bail("cannot create credential options");
    krb5_get_init_creds_opt_set_anonymous(opts, 1);
    krb5_get_init_creds_opt_set_tkt_life(opts, 60);
    retval = krb5_get_init_creds_password(ctx, &creds, princ, NULL, NULL,
                                          NULL, 0, NULL, opts);

    /* Clean up. */
    if (princ != NULL)
        krb5_free_principal(ctx, princ);
    if (opts != NULL)
        krb5_get_init_creds_opt_free(ctx, opts);
    krb5_free_cred_contents(ctx, &creds);
    return (retval == 0);
}
Beispiel #5
0
/* Get a TGT for use at the remote host */
krb5_error_code KRB5_CALLCONV
krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, char *rhost, krb5_principal client, krb5_principal server, krb5_ccache cc, int forwardable, krb5_data *outbuf)
                         
                                   
                
                          
                          
                   
                          /* Should forwarded TGT also be forwardable? */
                      
{
    krb5_replay_data replaydata;
    krb5_data * scratch = 0;
    krb5_address **addrs = NULL;
    krb5_error_code retval;
    krb5_creds creds, tgt;
    krb5_creds *pcreds;
    krb5_flags kdcoptions;
    int close_cc = 0;
    int free_rhost = 0;
    krb5_enctype enctype = 0;
    krb5_keyblock *session_key;
    krb5_boolean old_use_conf_ktypes = context->use_conf_ktypes;

    memset((char *)&creds, 0, sizeof(creds));
    memset((char *)&tgt, 0, sizeof(creds));

    if (cc == 0) {
      if ((retval = krb5int_cc_default(context, &cc)))
	goto errout;
      close_cc = 1;
    }
    retval = krb5_auth_con_getkey (context, auth_context, &session_key);
    if (retval)
      goto errout;
    if (session_key) {
	enctype = session_key->enctype;
	krb5_free_keyblock (context, session_key);
	session_key = NULL;
    } else if (server) { /* must server be non-NULL when rhost is given? */
	/* Try getting credentials to see what the remote side supports.
	   Not bulletproof, just a heuristic.  */
	krb5_creds in, *out = 0;
	memset (&in, 0, sizeof(in));

	retval = krb5_copy_principal (context, server, &in.server);
	if (retval)
	    goto punt;
	retval = krb5_copy_principal (context, client, &in.client);
	if (retval)
	    goto punt;
	retval = krb5_get_credentials (context, 0, cc, &in, &out);
	if (retval)
	    goto punt;
	/* Got the credentials.  Okay, now record the enctype and
	   throw them away.  */
	enctype = out->keyblock.enctype;
	krb5_free_creds (context, out);
    punt:
	krb5_free_cred_contents (context, &in);
    }

    if ((retval = krb5_copy_principal(context, client, &creds.client)))
	goto errout;
    
    if ((retval = krb5_build_principal_ext(context, &creds.server,
					   client->realm.length,
					   client->realm.data,
					   KRB5_TGS_NAME_SIZE,
					   KRB5_TGS_NAME,
					   client->realm.length,
					   client->realm.data,
					   0)))
	goto errout;
	
    /* fetch tgt directly from cache */
    context->use_conf_ktypes = 1;
    retval = krb5_cc_retrieve_cred (context, cc, KRB5_TC_SUPPORTED_KTYPES,
				    &creds, &tgt);
    context->use_conf_ktypes = old_use_conf_ktypes;
    if (retval)
	goto errout;

    /* tgt->client must be equal to creds.client */
    if (!krb5_principal_compare(context, tgt.client, creds.client)) {	
        /* Solaris Kerberos */
        char *r_name = NULL;
	char *t_name = NULL;
	krb5_error_code r_err, t_err;
	t_err = krb5_unparse_name(context, tgt.client, &t_name);
	r_err = krb5_unparse_name(context, creds.client, &r_name);
	krb5_set_error_message(context, KRB5_PRINC_NOMATCH,
			    dgettext(TEXT_DOMAIN,
				    "Requested principal and ticket don't match:  Requested principal is '%s' and TGT principal is '%s'"),
			    r_err ? "unknown" : r_name,
			    t_err ? "unknown" : t_name);
	if (r_name)
	    krb5_free_unparsed_name(context, r_name);
	if (t_name)
	    krb5_free_unparsed_name(context, t_name);
	retval = KRB5_PRINC_NOMATCH;
	goto errout;
    }

    if (!tgt.ticket.length) {
	retval = KRB5_NO_TKT_SUPPLIED;
	goto errout;
    }
    
    if (tgt.addresses && *tgt.addresses) {
      if (rhost == NULL) {
	if (krb5_princ_type(context, server) != KRB5_NT_SRV_HST) {
retval = KRB5_FWD_BAD_PRINCIPAL;
 goto errout;
	}

	if (krb5_princ_size(context, server) < 2){
	  retval = KRB5_CC_BADNAME;
	  goto errout;
	}
	
	rhost = malloc(server->data[1].length+1);
	if (!rhost) {
	  retval = ENOMEM;
	  goto errout;
	}
	free_rhost = 1;
	/* Solaris Kerberos */
	(void) memcpy(rhost, server->data[1].data, server->data[1].length);
	rhost[server->data[1].length] = '\0';
      }

	retval = krb5_os_hostaddr(context, rhost, &addrs);
	if (retval)
	    goto errout;
    }
    
    creds.keyblock.enctype = enctype;
    creds.times = tgt.times;
    creds.times.starttime = 0;
    kdcoptions = flags2options(tgt.ticket_flags)|KDC_OPT_FORWARDED;

    if (!forwardable) /* Reset KDC_OPT_FORWARDABLE */
      kdcoptions &= ~(KDC_OPT_FORWARDABLE);

    if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions,
					addrs, &creds, &pcreds))) {
	if (enctype) {
	    creds.keyblock.enctype = 0;
	    if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions,
						addrs, &creds, &pcreds))) 
		goto errout;
	}
	else goto errout;
    }
    retval = krb5_mk_1cred(context, auth_context, pcreds,
                           &scratch, &replaydata);
    krb5_free_creds(context, pcreds);

    /*
     * Solaris Kerberos: changed this logic from the MIT 1.2.1 version to be
     * more robust.
     */
    if (scratch) {
	if (retval)
	    krb5_free_data(context, scratch);
	else {                                 
	    *outbuf = *scratch;
	    krb5_xfree(scratch);
	}                      
    }
        
errout:
    if (addrs)
	krb5_free_addresses(context, addrs);
    /* Solaris Kerberos */
    if (close_cc)
	(void) krb5_cc_close(context, cc);
    if (free_rhost)
	free(rhost);
    krb5_free_cred_contents(context, &creds);
    krb5_free_cred_contents(context, &tgt);
    return retval;
}
Beispiel #6
0
/*
 * Get a ticket granting ticket and stuff it in the cache
 */
static const char *
get_tgt(
    char *	keytab_name,
    char *	principal_name)
{
    krb5_context context;
    krb5_error_code ret;
    krb5_principal client = NULL, server = NULL;
    krb5_creds creds;
    krb5_keytab keytab;
    krb5_ccache ccache;
    krb5_timestamp now;
#ifdef KRB5_HEIMDAL_INCLUDES
    krb5_data tgtname = { KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME };
#else
    krb5_data tgtname = { 0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME };
#endif
    static char *error = NULL;

    if (error != NULL) {
	amfree(error);
	error = NULL;
    }
    if ((ret = krb5_init_context(&context)) != 0) {
	error = vstrallocf(_("error initializing krb5 context: %s"),
	    error_message(ret));
	return (error);
    }

    /*krb5_init_ets(context);*/

    if(!keytab_name) {
        error = vstrallocf(_("error  -- no krb5 keytab defined"));
        return(error);
    }

    if(!principal_name) {
        error = vstrallocf(_("error  -- no krb5 principal defined"));
        return(error);
    }

    /*
     * Resolve keytab file into a keytab object
     */
    if ((ret = krb5_kt_resolve(context, keytab_name, &keytab)) != 0) {
	error = vstrallocf(_("error resolving keytab %s: %s"), keytab_name, 
	    error_message(ret));
	return (error);
    }

    /*
     * Resolve the amanda service held in the keytab into a principal
     * object
     */
    ret = krb5_parse_name(context, principal_name, &client);
    if (ret != 0) {
	error = vstrallocf(_("error parsing %s: %s"), principal_name,
	    error_message(ret));
	return (error);
    }

#ifdef KRB5_HEIMDAL_INCLUDES
    ret = krb5_build_principal_ext(context, &server,
        krb5_realm_length(*krb5_princ_realm(context, client)),
        krb5_realm_data(*krb5_princ_realm(context, client)),
        tgtname.length, tgtname.data,
        krb5_realm_length(*krb5_princ_realm(context, client)),
        krb5_realm_data(*krb5_princ_realm(context, client)),
        0);
#else
    ret = krb5_build_principal_ext(context, &server,
	krb5_princ_realm(context, client)->length,
	krb5_princ_realm(context, client)->data,
	tgtname.length, tgtname.data,
	krb5_princ_realm(context, client)->length,
	krb5_princ_realm(context, client)->data,
	0);
#endif
    if (ret != 0) {
	error = vstrallocf(_("error while building server name: %s"),
	    error_message(ret));
	return (error);
    }

    ret = krb5_timeofday(context, &now);
    if (ret != 0) {
	error = vstrallocf(_("error getting time of day: %s"), error_message(ret));
	return (error);
    }

    memset(&creds, 0, SIZEOF(creds));
    creds.times.starttime = 0;
    creds.times.endtime = now + AMANDA_TKT_LIFETIME;

    creds.client = client;
    creds.server = server;

    /*
     * Get a ticket for the service, using the keytab
     */
    ret = krb5_get_in_tkt_with_keytab(context, 0, NULL, NULL, NULL,
	keytab, 0, &creds, 0);

    if (ret != 0) {
	error = vstrallocf(_("error getting ticket for %s: %s"),
	    principal_name, error_message(ret));
	goto cleanup2;
    }

    if ((ret = krb5_cc_default(context, &ccache)) != 0) {
	error = vstrallocf(_("error initializing ccache: %s"), error_message(ret));
	goto cleanup;
    }
    if ((ret = krb5_cc_initialize(context, ccache, client)) != 0) {
	error = vstrallocf(_("error initializing ccache: %s"), error_message(ret));
	goto cleanup;
    }
    if ((ret = krb5_cc_store_cred(context, ccache, &creds)) != 0) {
	error = vstrallocf(_("error storing creds in ccache: %s"), 
	    error_message(ret));
	/* FALLTHROUGH */
    }
    krb5_cc_close(context, ccache);
cleanup:
    krb5_free_cred_contents(context, &creds);
cleanup2:
#if 0
    krb5_free_principal(context, client);
    krb5_free_principal(context, server);
#endif
    krb5_free_context(context);
    return (error);
}
Beispiel #7
0
/*******************************************************************
check on Kerberos authentication
********************************************************************/
static BOOL krb5_auth(char *this_user,char *password)
{
	krb5_data tgtname = {
		0,
		KRB5_TGS_NAME_SIZE,
	 	KRB5_TGS_NAME
 	};
	krb5_context kcontext;
	krb5_principal kprinc;
	krb5_principal server;
	krb5_creds kcreds;
	int options = 0;
	krb5_address **addrs = (krb5_address **)0;
	krb5_preauthtype *preauth = NULL;
	krb5_keytab keytab = NULL;
	krb5_timestamp now;
	krb5_ccache ccache = NULL;
	int retval;
	char *name;

	if ( retval=krb5_init_context(&kcontext))
	{
		return(False);
	}

	if ( retval = krb5_timeofday(kcontext, &now) )
	{
		return(False);
	}

	if ( retval = krb5_cc_default(kcontext, &ccache) )
	{
		return(False);
	}
	
	if ( retval = krb5_parse_name(kcontext, this_user, &kprinc) )
	{
		return(False);
	}

	memset((char *)&kcreds, 0, sizeof(kcreds));

	kcreds.client = kprinc;
	
	if ((retval = krb5_build_principal_ext(kcontext, &server,
		krb5_princ_realm(kcontext, kprinc)->length,
		krb5_princ_realm(kcontext, kprinc)->data,
		tgtname.length,
		tgtname.data,
		krb5_princ_realm(kcontext, kprinc)->length,
		krb5_princ_realm(kcontext, kprinc)->data,
		0)))
	{
 		return(False);
	}

	kcreds.server = server;

	retval = krb5_get_in_tkt_with_password(kcontext,
		options,
		addrs,
		NULL,
		preauth,
		password,
		0,
		&kcreds,
		0);

	if ( retval )
	{
		return(False);
	}

	return(True);
}
Beispiel #8
0
int
main(int argc, const char **argv)
{
    krb5_context ctx;
    krb5_ccache ccache;
    krb5_creds mcreds, creds;
    krb5_keytab keytab;
    krb5_principal server;
    krb5_verify_init_creds_opt opts;
    int ret;

    ctx = NULL;
    ret = krb5_init_context(&ctx);
    if (ret != 0) {
        crit("error initializing Kerberos: %s", error_message(ret));
        return ret;
    }

    ccache = NULL;
    ret = krb5_cc_default(ctx, &ccache);
    if (ret != 0) {
        crit("error resolving ccache: %s", error_message(ret));
        return ret;
    }

    keytab = NULL;
    ret = krb5_kt_default(ctx, &keytab);
    if (ret != 0) {
        crit("error resolving keytab: %s", error_message(ret));
        return ret;
    }

    server = NULL;
    memset(&mcreds, 0, sizeof(mcreds));
    ret = krb5_cc_get_principal(ctx, ccache, &mcreds.client);
    if (ret != 0) {
        crit("error reading client name from ccache: %s",
             error_message(ret));
        return ret;
    }
    ret = krb5_build_principal_ext(ctx, &mcreds.server,
                                   v5_princ_realm_length(mcreds.client),
                                   v5_princ_realm_contents(mcreds.client),
                                   KRB5_TGS_NAME_SIZE,
                                   KRB5_TGS_NAME,
                                   v5_princ_realm_length(mcreds.client),
                                   v5_princ_realm_contents(mcreds.client),
                                   0);
    if (ret != 0) {
        crit("error building ticket granting server name: %s",
             error_message(ret));
        return ret;
    }

    ret = krb5_cc_retrieve_cred(ctx, ccache, 0, &mcreds, &creds);
    if (ret != 0) {
        crit("error reading ccache: %s", error_message(ret));
        return ret;
    }
    krb5_cc_close(ctx, ccache);

    krb5_verify_init_creds_opt_init(&opts);
    ret = krb5_verify_init_creds(ctx, &creds,
                                 server, keytab, NULL,
                                 &opts);
    if (ret != 0) {
        crit("error verifying creds: %s", error_message(ret));
    } else {
        printf("OK\n");
    }

    krb5_free_context(ctx);

    return ret;
}
Beispiel #9
0
/**
 * @brief
 * 		Get a TGT for use at the remote host.
 *
 * @param[in]	context	-	The Kerberos context.
 * @param[in]	auth_context	- Authentication context
 * @param[in]	client	-	Principal to be copied
 * @param[in]	server	-	Server of type krb5_principal
 * @param[in]	cc	-	Credential cache handle
 * @param[out]	outbuf	-	Replay cache data (NULL if not needed)
 *
 * @return	krb5_error_code
 * @retval	0	- success
 * @retval	!=0	- failure
 */
static
krb5_error_code
fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, krb5_principal client, krb5_principal server, krb5_ccache cc, krb5_data outbuf)
{
	krb5_replay_data	replaydata;
	krb5_data		*scratch = 0;
	krb5_address		**addrs = 0;
	krb5_flags		kdcoptions;
	krb5_error_code		retval;
	krb5_creds		creds, tgt;
	krb5_creds		*pcreds;
	int			free_rhost = 0;
	char			*rhost;

	memset((char *)&creds, 0, sizeof(creds));
	memset((char *)&tgt, 0, sizeof(creds));

	if (krb5_princ_type(context, server) != KRB5_NT_SRV_HST)
		return KRB5_FWD_BAD_PRINCIPAL;

	if (krb5_princ_size(context, server) < 2)
		return KRB5_CC_BADNAME;

	rhost = malloc(server->data[1].length+1);
	if (!rhost)
		return ENOMEM;
	free_rhost = 1;
	memcpy(rhost, server->data[1].data, server->data[1].length);
	rhost[server->data[1].length] = '\0';

	retval = krb5_os_hostaddr(context, rhost, &addrs);
	if (retval)
		goto errout;

	if ((retval = krb5_copy_principal(context, client, &creds.client)))
		goto errout;

	if ((retval = krb5_build_principal_ext(context, &creds.server,
		client->realm.length,
		client->realm.data,
		KRB5_TGS_NAME_SIZE,
		KRB5_TGS_NAME,
		client->realm.length,
		client->realm.data,
		0)))
		goto errout;

	/* fetch tgt directly from cache */
	retval = 	krb5_cc_retrieve_cred(context, cc, KRB5_TC_SUPPORTED_KTYPES,
		&creds, &tgt);
	if (retval)
		goto errout;

	/* tgt->client must be equal to creds.client */
	if (!krb5_principal_compare(context, tgt.client, creds.client)) {
		retval = KRB5_PRINC_NOMATCH;
		goto errout;
	}
	if (!tgt.ticket.length) {
		retval = KRB5_NO_TKT_SUPPLIED;
		goto errout;
	}

	kdcoptions = flags2options(tgt.ticket_flags)|
		KDC_OPT_FORWARDED;

	if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions,
		addrs, &creds, &pcreds)))
		goto errout;

	retval = krb5_mk_1cred(context, auth_context, pcreds,
		&scratch, &replaydata);
	krb5_free_creds(context, pcreds);

	if (retval) {
		if (scratch)
			krb5_free_data(context, scratch);
	}
	else {
		*outbuf = *scratch;
		free(scratch);
	}

errout:
	if (addrs)
		krb5_free_addresses(context, addrs);
	if (free_rhost)
		free(rhost);
	krb5_free_cred_contents(context, &creds);
	krb5_free_cred_contents(context, &tgt);

	return retval;
}
Beispiel #10
0
/*
 * Find a keytab entry to use for a given target hostname.
 * Tries to find the most appropriate keytab to use given the
 * name of the host we are trying to connect with.
 */
static int find_keytab_entry(krb5_context context, krb5_keytab kt,
			     const char *hostname, krb5_keytab_entry *kte,
			     const char **svcnames)
{
	krb5_error_code code;
	char **realmnames = NULL;
	char myhostname[NI_MAXHOST], targethostname[NI_MAXHOST];
	char myhostad[NI_MAXHOST + 1];
	int i, j, retval;
	char *default_realm = NULL;
	char *realm;
	char *k5err = NULL;
	int tried_all = 0, tried_default = 0;
	krb5_principal princ;

	/* Get full target hostname */
	retval =
	    get_full_hostname(hostname, targethostname, sizeof(targethostname));
	if (retval)
		goto out;

	/* Get full local hostname */
	retval = gethostname(myhostname, sizeof(myhostname));
	if (retval) {
		k5err = gssd_k5_err_msg(context, retval);
		printerr(1, "%s while getting local hostname\n", k5err);
		gsh_free(k5err);
		goto out;
	}

	/* Compute the active directory machine name HOST$ */
	strcpy(myhostad, myhostname);
	for (i = 0; myhostad[i] != 0; ++i)
		myhostad[i] = toupper(myhostad[i]);
	myhostad[i] = '$';
	myhostad[i + 1] = 0;

	retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname));
	if (retval)
		goto out;

	code = krb5_get_default_realm(context, &default_realm);
	if (code) {
		retval = code;
		k5err = gssd_k5_err_msg(context, code);
		printerr(1, "%s while getting default realm name\n", k5err);
		gsh_free(k5err);
		goto out;
	}

	/*
	 * Get the realm name(s) for the target hostname.
	 * In reality, this function currently only returns a
	 * single realm, but we code with the assumption that
	 * someday it may actually return a list.
	 */
	code = krb5_get_host_realm(context, targethostname, &realmnames);
	if (code) {
		k5err = gssd_k5_err_msg(context, code);
		printerr(0, "ERROR: %s while getting realm(s) for host '%s'\n",
			 k5err, targethostname);
		gsh_free(k5err);
		retval = code;
		goto out;
	}

	/*
	 * Try the "appropriate" realm first, and if nothing found for that
	 * realm, try the default realm (if it hasn't already been tried).
	 */
	i = 0;
	realm = realmnames[i];
	while (1) {
		if (realm == NULL) {
			tried_all = 1;
			if (!tried_default)
				realm = default_realm;
		}
		if (tried_all && tried_default)
			break;
		if (strcmp(realm, default_realm) == 0)
			tried_default = 1;
		for (j = 0; svcnames[j] != NULL; j++) {
			char spn[300];

			/*
			 * The special svcname "$" means 'try the active
			 * directory machine account'
			 */
			if (strcmp(svcnames[j], "$") == 0) {
				snprintf(spn, sizeof(spn), "%s@%s", myhostad,
					 realm);
				code =
				    krb5_build_principal_ext(context, &princ,
							     strlen(realm),
							     realm,
							     strlen(myhostad),
							     myhostad, NULL);
			} else {
				snprintf(spn, sizeof(spn), "%s/%s@%s",
					 svcnames[j], myhostname, realm);
				code =
				    krb5_build_principal_ext(context, &princ,
							     strlen(realm),
							     realm,
							     strlen(svcnames
								    [j]),
							     svcnames[j],
							     strlen(myhostname),
							     myhostname, NULL);
			}

			if (code) {
				k5err = gssd_k5_err_msg(context, code);
				printerr(1,
					 "%s while building principal for '%s'\n",
					 k5err, spn);
				gsh_free(k5err);
				continue;
			}
			code = krb5_kt_get_entry(context, kt, princ, 0, 0, kte);
			krb5_free_principal(context, princ);
			if (code) {
				k5err = gssd_k5_err_msg(context, code);
				printerr(3,
					 "%s while getting keytab entry for '%s'\n",
					 k5err, spn);
				gsh_free(k5err);
			} else {
				printerr(3,
					 "Success getting keytab entry for '%s'\n",
					 spn);
				retval = 0;
				goto out;
			}
			retval = code;
		}
		/*
		 * Nothing found with our hostname instance, now look for
		 * names with any instance (they must have an instance)
		 */
		for (j = 0; svcnames[j] != NULL; j++) {
			int found = 0;
			if (strcmp(svcnames[j], "$") == 0)
				continue;
			code =
			    gssd_search_krb5_keytab(context, kt, realm,
						    svcnames[j], &found, kte);
			if (!code && found) {
				printerr(3,
					 "Success getting keytab entry for "
					 "%s/*@%s\n", svcnames[j], realm);
				retval = 0;
				goto out;
			}
		}
		if (!tried_all) {
			i++;
			realm = realmnames[i];
		}
	}
 out:
	if (default_realm)
		k5_free_default_realm(context, default_realm);
	if (realmnames)
		krb5_free_host_realm(context, realmnames);

	return retval;
}
Beispiel #11
0
/*
 * PAM test callback to check whether we created a ticket cache and the ticket
 * cache is for the correct user.
 */
static void
check_cache(pam_handle_t *pamh, const struct script_config *config, void *data)
{
    struct extra *extra = data;
    const char *cache, *file;
    struct stat st;
    char *prefix;
    krb5_error_code code;
    krb5_context ctx = NULL;
    krb5_ccache ccache = NULL;
    krb5_principal princ = NULL;
    krb5_principal tgtprinc = NULL;
    krb5_creds in, out;
    char *principal = NULL;

    /* Check cache naming, ownership, and permissions. */
    cache = pam_getenv(pamh, "KRB5CCNAME");
    ok(cache != NULL, "KRB5CCNAME is set in PAM environment");
    if (cache == NULL)
        return;
    basprintf(&prefix, "FILE:/tmp/krb5cc_%lu_", (unsigned long) getuid());
    diag("KRB5CCNAME = %s", cache);
    ok(strncmp(prefix, cache, strlen(prefix)) == 0,
       "cache file name prefix is correct");
    free(prefix);
    file = cache + strlen("FILE:");
    is_int(0, stat(file, &st), "cache exists");
    is_int(getuid(), st.st_uid, "...with correct UID");
    is_int(getgid(), st.st_gid, "...with correct GID");
    is_int(0600, (st.st_mode & 0777), "...with correct permissions");

    /* Check the existence of the ticket cache and its principal. */
    code = krb5_init_context(&ctx);
    if (code != 0)
        bail("cannot create Kerberos context");
    code = krb5_cc_resolve(ctx, cache, &ccache);
    is_int(0, code, "able to resolve Kerberos ticket cache");
    code = krb5_cc_get_principal(ctx, ccache, &princ);
    is_int(0, code, "able to get principal");
    code = krb5_unparse_name(ctx, princ, &principal);
    is_int(0, code, "...and principal is valid");
    is_string(config->extra[0], principal, "...and matches our principal");

    /* Retrieve the krbtgt for the realm and check properties. */
    code = krb5_build_principal_ext(ctx, &tgtprinc,
                                    strlen(extra->realm), extra->realm,
                                    KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
                                    strlen(extra->realm), extra->realm,
                                    NULL);
    if (code != 0)
        bail("cannot create krbtgt principal name");
    memset(&in, 0, sizeof(in));
    memset(&out, 0, sizeof(out));
    in.server = tgtprinc;
    in.client = princ;
    code = krb5_cc_retrieve_cred(ctx, ccache, KRB5_TC_MATCH_SRV_NAMEONLY,
                                 &in, &out);
    is_int(0, code, "able to get krbtgt credentials");
    ok(out.times.endtime > time(NULL) + 30 * 60, "...good for 30 minutes");
    krb5_free_cred_contents(ctx, &out);

    /* Close things and release memory. */
    krb5_free_principal(ctx, tgtprinc);
    krb5_free_unparsed_name(ctx, principal);
    krb5_free_principal(ctx, princ);
    krb5_cc_close(ctx, ccache);
    krb5_free_context(ctx);
}
Beispiel #12
0
static int krb5_auth(void *instance, REQUEST *request)
{
	rlm_krb5_t *inst = instance;
	int ret;
	
	static char tgs_name[] = KRB5_TGS_NAME;
	krb5_data tgtname = {
		0,
		KRB5_TGS_NAME_SIZE,
		tgs_name
	};
	
	krb5_creds kcreds;
	krb5_ccache ccache;
	
	/* MEMORY: + unsigned int (20) + NULL */
	char cache_name[28];

	krb5_context context = *(inst->context); /* copy data */
	const char *user, *pass;

	/*
	 *  We can only authenticate user requests which HAVE
	 *  a User-Name attribute.
	 */
	if (!request->username) {
		radlog(L_AUTH, "rlm_krb5: Attribute \"User-Name\" is required for authentication.");
		
		return RLM_MODULE_INVALID;
	}

	/*
	 *  We can only authenticate user requests which HAVE
	 *  a User-Password attribute.
	 */
	if (!request->password) {
		radlog(L_AUTH, "rlm_krb5: Attribute \"User-Password\" is required for authentication.");
		
		return RLM_MODULE_INVALID;
	}

	/*
	 *  Ensure that we're being passed a plain-text password,
	 *  and not anything else.
	 */
	if (request->password->attribute != PW_USER_PASSWORD) {
		radlog(L_AUTH, "rlm_krb5: Attribute \"User-Password\" is required for authentication.  Cannot use \"%s\".", request->password->name);
		
		return RLM_MODULE_INVALID;
	}

	user = request->username->vp_strvalue;
	pass = request->password->vp_strvalue;

	/*
	 *  Generate a unique cache_name.
	 */
	snprintf(cache_name, sizeof(cache_name), "MEMORY:%u", request->number);

	ret = krb5_cc_resolve(context, cache_name, &ccache);
	if (ret) {
		radlog(L_AUTH, "rlm_krb5: [%s] krb5_cc_resolve(): %s",
		       user, error_message(ret));
		       
		return RLM_MODULE_REJECT;
	}

	/*
	 *  Actually perform the authentication.
	 */
	memset((char *)&kcreds, 0, sizeof(kcreds));

	ret = krb5_parse_name(context, user, &kcreds.client);
	if (ret) {
		radlog(L_AUTH, "rlm_krb5: [%s] krb5_parse_name failed: %s",
		       user, error_message(ret));
		       
		return RLM_MODULE_REJECT;
	}

	ret = krb5_cc_initialize(context, ccache, kcreds.client);
	if (ret) {
		radlog(L_AUTH, "rlm_krb5: [%s] krb5_cc_initialize(): %s",
		       user, error_message(ret));
		       
		return RLM_MODULE_REJECT;
	}

	/*
	 *  MIT krb5 verification.
	 */
	ret = krb5_build_principal_ext(context, &kcreds.server,
			krb5_princ_realm(context, kcreds.client)->length,
			krb5_princ_realm(context, kcreds.client)->data,
			tgtname.length,
			tgtname.data,
			krb5_princ_realm(context, kcreds.client)->length,
			krb5_princ_realm(context, kcreds.client)->data,
			0);
	if (ret) {
		radlog(L_AUTH, "rlm_krb5: [%s] krb5_build_principal_ext failed: %s",
			user, error_message(ret));
		krb5_cc_destroy(context, ccache);
		
		return RLM_MODULE_REJECT;
	}

	ret = krb5_get_in_tkt_with_password(context, 0, NULL, NULL, NULL, pass,
					    ccache, &kcreds, 0);
	if (ret) {
		radlog(L_AUTH, "rlm_krb5: [%s] krb5_g_i_t_w_p failed: %s",
		       user, error_message(ret));
		krb5_free_cred_contents(context, &kcreds);
		krb5_cc_destroy(context, ccache);
		
		return RLM_MODULE_REJECT;
	}

	/*
	 *  Now verify the KDC's identity.
	 */
	ret = verify_krb5_tgt(context, inst, user, ccache);
	krb5_free_cred_contents(context, &kcreds);
	krb5_cc_destroy(context, ccache);
	
	return ret;
}
Beispiel #13
0
static krb5_error_code
krb5_validate_or_renew_creds(krb5_context context, krb5_creds *creds,
			     krb5_principal client, krb5_ccache ccache,
			     char *in_tkt_service, int validate)
{
    krb5_error_code ret;
    krb5_creds in_creds; /* only client and server need to be filled in */
    krb5_creds *out_creds = 0; /* for check before dereferencing below */
    krb5_creds **tgts;

    memset((char *)&in_creds, 0, sizeof(krb5_creds));

    in_creds.server = NULL;
    tgts = NULL;

    in_creds.client = client;

    if (in_tkt_service) {
	/* this is ugly, because so are the data structures involved.  I'm
	   in the library, so I'm going to manipulate the data structures
	   directly, otherwise, it will be worse. */

        if ((ret = krb5_parse_name(context, in_tkt_service, &in_creds.server)))
	    goto cleanup;

	/* stuff the client realm into the server principal.
	   realloc if necessary */
	if (in_creds.server->realm.length < in_creds.client->realm.length)
	    if ((in_creds.server->realm.data =
		 (char *) realloc(in_creds.server->realm.data,
				  in_creds.client->realm.length)) == NULL) {
		ret = ENOMEM;
		goto cleanup;
	    }

	in_creds.server->realm.length = in_creds.client->realm.length;
	memcpy(in_creds.server->realm.data, in_creds.client->realm.data,
	       in_creds.client->realm.length);
    } else {
	if ((ret = krb5_build_principal_ext(context, &in_creds.server,
					   in_creds.client->realm.length,
					   in_creds.client->realm.data,
					   KRB5_TGS_NAME_SIZE,
					   KRB5_TGS_NAME,
					   in_creds.client->realm.length,
					   in_creds.client->realm.data,
					    0)))
	    goto cleanup;
    }

    if (validate)
	ret = krb5_get_cred_from_kdc_validate(context, ccache, 
					      &in_creds, &out_creds, &tgts);
    else
	ret = krb5_get_cred_from_kdc_renew(context, ccache, 
					   &in_creds, &out_creds, &tgts);
   
    /* ick.  copy the struct contents, free the container */
    if (out_creds) {
	*creds = *out_creds;
	krb5_xfree(out_creds);
    }

cleanup:

    if (in_creds.server)
	krb5_free_principal(context, in_creds.server);
    if (tgts)
	krb5_free_tgt_creds(context, tgts);

    return(ret);
}
Beispiel #14
0
int
main(int argc, char **argv)
{
    krb5_context context;
    krb5_keytab kt;
    krb5_keytab_entry ktent;
    krb5_encrypt_block eblock;
    krb5_creds my_creds;
    krb5_get_init_creds_opt *opt;
    kadm5_principal_ent_rec princ_ent;
    krb5_principal princ, server;
    char pw[16];
    char *whoami, *principal, *authprinc, *authpwd;
    krb5_data pwdata;
    void *handle;
    int ret, test, encnum;
    unsigned int i;

    whoami = argv[0];

    if (argc < 2 || argc > 4) {
        fprintf(stderr, "Usage: %s principal [authuser] [authpwd]\n", whoami);
        exit(1);
    }
    principal = argv[1];
    authprinc = (argc > 2) ? argv[2] : argv[0];
    authpwd = (argc > 3) ? argv[3] : NULL;

    /*
     * Setup.  Initialize data structures, open keytab, open connection
     * to kadm5 server.
     */

    memset(&context, 0, sizeof(context));
    kadm5_init_krb5_context(&context);

    ret = krb5_parse_name(context, principal, &princ);
    if (ret) {
        com_err(whoami, ret, "while parsing principal name %s", principal);
        exit(1);
    }

    if((ret = krb5_build_principal_ext(context, &server,
                                       krb5_princ_realm(kcontext, princ)->length,
                                       krb5_princ_realm(kcontext, princ)->data,
                                       tgtname.length, tgtname.data,
                                       krb5_princ_realm(kcontext, princ)->length,
                                       krb5_princ_realm(kcontext, princ)->data,
                                       0))) {
        com_err(whoami, ret, "while building server name");
        exit(1);
    }

    ret = krb5_kt_default(context, &kt);
    if (ret) {
        com_err(whoami, ret, "while opening keytab");
        exit(1);
    }

    ret = kadm5_init(context, authprinc, authpwd, KADM5_ADMIN_SERVICE, NULL,
                     KADM5_STRUCT_VERSION, KADM5_API_VERSION_4, NULL,
                     &handle);
    if (ret) {
        com_err(whoami, ret, "while initializing connection");
        exit(1);
    }

    /* these pw's don't need to be secure, just different every time */
    SRAND((RAND_TYPE)time((void *) NULL));
    pwdata.data = pw;
    pwdata.length = sizeof(pw);

    /*
     * For each test:
     *
     * For each enctype in the test, construct a random password/key.
     * Assign all keys to principal with kadm5_setkey_principal.  Add
     * each key to the keytab, and acquire an initial ticket with the
     * keytab (XXX can I specify the kvno explicitly?).  If
     * krb5_get_init_creds_keytab succeeds, then the keys were set
     * successfully.
     */
    for (test = 0; tests[test] != NULL; test++) {
        krb5_keyblock *testp = tests[test];
        kadm5_key_data *extracted;
        int n_extracted, match;
        printf("+ Test %d:\n", test);

        for (encnum = 0; testp[encnum].magic != -1; encnum++) {
            for (i = 0; i < sizeof(pw); i++)
                pw[i] = (RAND() % 26) + '0'; /* XXX */

            krb5_use_enctype(context, &eblock, testp[encnum].enctype);
            ret = krb5_string_to_key(context, &eblock, &testp[encnum],
                                     &pwdata, NULL);
            if (ret) {
                com_err(whoami, ret, "while converting string to key");
                exit(1);
            }
        }

        /* now, encnum == # of keyblocks in testp */
        ret = kadm5_setkey_principal(handle, princ, testp, encnum);
        if (ret) {
            com_err(whoami, ret, "while setting keys");
            exit(1);
        }

        ret = kadm5_get_principal(handle, princ, &princ_ent, KADM5_KVNO);
        if (ret) {
            com_err(whoami, ret, "while retrieving principal");
            exit(1);
        }

        ret = kadm5_get_principal_keys(handle, princ, 0, &extracted,
                                       &n_extracted);
        if (ret) {
            com_err(whoami, ret, "while extracting keys");
            exit(1);
        }

        for (encnum = 0; testp[encnum].magic != -1; encnum++) {
            printf("+   enctype %d\n", testp[encnum].enctype);

            for (match = 0; match < n_extracted; match++) {
                if (extracted[match].key.enctype == testp[encnum].enctype)
                    break;
            }
            if (match >= n_extracted) {
                com_err(whoami, KRB5_WRONG_ETYPE, "while matching enctypes");
                exit(1);
            }
            if (extracted[match].key.length != testp[encnum].length ||
                memcmp(extracted[match].key.contents, testp[encnum].contents,
                       testp[encnum].length) != 0) {
                com_err(whoami, KRB5_KDB_NO_MATCHING_KEY, "verifying keys");
                exit(1);
            }

            memset(&ktent, 0, sizeof(ktent));
            ktent.principal = princ;
            ktent.key = testp[encnum];
            ktent.vno = princ_ent.kvno;

            ret = krb5_kt_add_entry(context, kt, &ktent);
            if (ret) {
                com_err(whoami, ret, "while adding keytab entry");
                exit(1);
            }

            memset(&my_creds, 0, sizeof(my_creds));
            my_creds.client = princ;
            my_creds.server = server;

            ktypes[0] = testp[encnum].enctype;
            ret = krb5_get_init_creds_opt_alloc(context, &opt);
            if (ret) {
                com_err(whoami, ret, "while allocating gic opts");
                exit(1);
            }
            krb5_get_init_creds_opt_set_etype_list(opt, ktypes, 1);
            ret = krb5_get_init_creds_keytab(context, &my_creds, princ,
                                             kt, 0, NULL /* in_tkt_service */,
                                             opt);
            krb5_get_init_creds_opt_free(context, opt);
            if (ret) {
                com_err(whoami, ret, "while acquiring initial ticket");
                exit(1);
            }
            krb5_free_cred_contents(context, &my_creds);

            /* since I can't specify enctype explicitly ... */
            ret = krb5_kt_remove_entry(context, kt, &ktent);
            if (ret) {
                com_err(whoami, ret, "while removing keytab entry");
                exit(1);
            }
        }

        (void)kadm5_free_kadm5_key_data(context, n_extracted, extracted);
    }

    ret = krb5_kt_close(context, kt);
    if (ret) {
        com_err(whoami, ret, "while closing keytab");
        exit(1);
    }

    ret = kadm5_destroy(handle);
    if (ret) {
        com_err(whoami, ret, "while closing kadmin connection");
        exit(1);
    }

    krb5_free_principal(context, princ);
    krb5_free_principal(context, server);
    krb5_free_context(context);
    return 0;
}
Beispiel #15
0
int do_command(krb5_context context, krb5_keytab keytab, krb5_principal me, char *princ, char *cmd, char *cmddir) {
	char *p;
	char *answer;
	static char answer_exec[] = "Cannot execute command.";
	static char answer_priv[] = "You are not privileged to execute this command.";
	static char answer_regexp[] = "Command doesn't match any allowed regexp.";
	int result;

	if (debug)
		syslog(LOG_DEBUG, "Principal %s is trying to execute command %s", princ, cmd);

	/* Replace \n with \0 */
	p = cmd;
	while (*p != '\0' && *p != '\n')
		p++;
	*p = '\0';

	if (gethelp(cmd) == 0)
		return 0;

	if ((result = chk_user_cmd(princ, cmd)) != 0) {
		switch(result) {
			case CHK_GRP:
				answer = answer_priv;
				break;
			case CHK_REGEXP:
				answer = answer_regexp;
				break;
			default:
				answer = answer_exec;
		}
		if (debug)
			syslog(LOG_DEBUG, "%s", answer);
		if (write(1, answer, strlen(answer)) == -1)
			printf("Failed write to stdout.\n");
		return 0;
	} else {
		char *localcmd, *pathenv;
		char ccname[255];
		krb5_ccache ccache;
		krb5_creds creds;
		krb5_principal tgtserver;
		krb5_error_code retval;
		krb5_get_init_creds_opt opts;

		pathenv = malloc((strlen(cmddir) + 6) * sizeof(char));
		if (pathenv == NULL) {
			syslog(LOG_ERR, "Not enough memory (env)");
			exit(1);
		}
		sprintf(pathenv, "PATH=%s", cmddir);

		preauth = preauth_list;
#ifdef __osf__
		sprintf(ccname, "FILE:/tmp/afsadm_%d", getpid());
#else
		snprintf(ccname, 255, "FILE:/tmp/afsadm_%d", getpid());
#endif
		if (retval = krb5_cc_resolve(context, ccname, &ccache)) {
			syslog(LOG_ERR, "%s while resolving ccache", error_message(retval));
			exit(1);
		}
#ifdef __osf__
		sprintf(ccname, "KRB5CCNAME=FILE:/tmp/afsadm_%d", getpid());
#else
		snprintf(ccname, 255, "KRB5CCNAME=FILE:/tmp/afsadm_%d", getpid());
#endif

		putenv(ccname);
		if (retval = krb5_cc_initialize(context, ccache, me)) {
			syslog(LOG_ERR, "%s while initialize ccache", error_message(retval));
			exit(1);
		}

		memset((char *)&creds, 0, sizeof(creds));
		creds.client = me;

		krb5_data *realm = krb5_princ_realm(context, me);

		if ((retval = krb5_build_principal_ext(context, &tgtserver, realm->length, realm->data, tgtname.length, tgtname.data, realm->length, realm->data, 0))) {
			syslog(LOG_ERR, "%s while building server name", error_message(retval));
			krb5_cc_destroy(context, ccache);
			exit(1);
		}

		creds.server = tgtserver;

		krb5_get_init_creds_opt_init(&opts);
		opts.preauth_list = preauth;

		if (retval = krb5_get_init_creds_keytab(context, &creds, me, keytab, 0, NULL, &opts)) {
			syslog(LOG_ERR, "%s while getting tgt", error_message(retval));
			krb5_cc_destroy(context, ccache);
			exit(1);
		}

		if (retval = krb5_cc_store_cred(context, ccache, &creds)) {
			syslog(LOG_ERR, "%s while saving credentials to ccache", error_message(retval));
			krb5_cc_destroy(context, ccache);
			exit(1);
		}

		if (k_hasafs())
			k_setpag();

		localcmd = malloc(sizeof(char) * (strlen(cmd) + strlen(cmddir) + 2));
		if (localcmd == NULL) {
			syslog(LOG_ERR, "Not enough memory (cmdpath malloc)");
			exit(1);
		}
		sprintf(localcmd, "%s/%s", cmddir, cmd);

		syslog(LOG_INFO, "Principal %s : system(%s)", princ, localcmd);

		/* Set PATH to dircmd !!!! */
		putenv(pathenv);
		//system("/usr/bin/id -a; aklog");

		if (system("aklog") == -1)
			printf("Cannot execute aklog.\n");
		result = system(localcmd);

		syslog(LOG_INFO, "Principal %s : system(%s) returns with %d", princ, localcmd, result);

		free(pathenv);
		free(localcmd);

		if (k_hasafs())
			k_unlog();

		krb5_cc_destroy(context, ccache);
		return 0;
	}
}