Exemplo n.º 1
0
Arquivo: 524.c Projeto: gojdic/samba
krb5_error_code
_kdc_do_524(krb5_context context,
	    krb5_kdc_configuration *config,
	    const Ticket *t, krb5_data *reply,
	    const char *from, struct sockaddr *addr)
{
    krb5_error_code ret = 0;
    krb5_crypto crypto;
    hdb_entry_ex *server = NULL;
    Key *skey;
    krb5_data et_data;
    EncTicketPart et;
    EncryptedData ticket;
    krb5_storage *sp;
    char *spn = NULL;
    unsigned char buf[MAX_KTXT_LEN + 4 * 4];
    size_t len;
    int kvno = 0;

    if(!config->enable_524) {
	ret = KRB5KDC_ERR_POLICY;
	kdc_log(context, config, 0,
		"Rejected ticket conversion request from %s", from);
	goto out;
    }

    ret = fetch_server (context, config, t, &spn, &server, from);
    if (ret) {
	goto out;
    }

    ret = hdb_enctype2key(context, &server->entry, t->enc_part.etype, &skey);
    if(ret){
	kdc_log(context, config, 0,
		"No suitable key found for server (%s) from %s", spn, from);
	goto out;
    }
    ret = krb5_crypto_init(context, &skey->key, 0, &crypto);
    if (ret) {
	kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
		krb5_get_err_text(context, ret));
	goto out;
    }
    ret = krb5_decrypt_EncryptedData (context,
				      crypto,
				      KRB5_KU_TICKET,
				      &t->enc_part,
				      &et_data);
    krb5_crypto_destroy(context, crypto);
    if(ret){
	kdc_log(context, config, 0,
		"Failed to decrypt ticket from %s for %s", from, spn);
	goto out;
    }
    ret = krb5_decode_EncTicketPart(context, et_data.data, et_data.length,
				    &et, &len);
    krb5_data_free(&et_data);
    if(ret){
	kdc_log(context, config, 0,
		"Failed to decode ticket from %s for %s", from, spn);
	goto out;
    }

    ret = log_524 (context, config, &et, from, spn);
    if (ret) {
	free_EncTicketPart(&et);
	goto out;
    }

    ret = verify_flags (context, config, &et, spn);
    if (ret) {
	free_EncTicketPart(&et);
	goto out;
    }

    ret = set_address (context, config, &et, addr, from);
    if (ret) {
	free_EncTicketPart(&et);
	goto out;
    }

    ret = encode_524_response(context, config, spn, et, t,
			      server, &ticket, &kvno);
    free_EncTicketPart(&et);

 out:
    /* make reply */
    memset(buf, 0, sizeof(buf));
    sp = krb5_storage_from_mem(buf, sizeof(buf));
    if (sp) {
	krb5_store_int32(sp, ret);
	if(ret == 0){
	    krb5_store_int32(sp, kvno);
	    krb5_store_data(sp, ticket.cipher);
	    /* Aargh! This is coded as a KTEXT_ST. */
	    krb5_storage_seek(sp, MAX_KTXT_LEN - ticket.cipher.length, SEEK_CUR);
	    krb5_store_int32(sp, 0); /* mbz */
	    free_EncryptedData(&ticket);
	}
	ret = krb5_storage_to_data(sp, reply);
	reply->length = krb5_storage_seek(sp, 0, SEEK_CUR);
	krb5_storage_free(sp);
    } else
	krb5_data_zero(reply);
    if(spn)
	free(spn);
    if(server)
	_kdc_free_ent (context, server);
    return ret;
}
Exemplo n.º 2
0
static krb5_error_code
tgs_build_reply(krb5_context context, 
		krb5_kdc_configuration *config,
		KDC_REQ *req, 
		KDC_REQ_BODY *b,
		hdb_entry_ex *krbtgt,
		krb5_enctype krbtgt_etype,
		krb5_ticket *ticket,
		krb5_data *reply,
		const char *from,
		const char **e_text,
		AuthorizationData *auth_data,
		const struct sockaddr *from_addr,
		int datagram_reply)
{
    krb5_error_code ret;
    krb5_principal cp = NULL, sp = NULL;
    krb5_principal client_principal = NULL;
    char *spn = NULL, *cpn = NULL;
    hdb_entry_ex *server = NULL, *client = NULL;
    EncTicketPart *tgt = &ticket->ticket;
    KRB5SignedPathPrincipals *spp = NULL;
    const EncryptionKey *ekey;
    krb5_keyblock sessionkey;
    krb5_kvno kvno;
    krb5_data rspac;
    int cross_realm = 0;

    PrincipalName *s;
    Realm r;
    int nloop = 0;
    EncTicketPart adtkt;
    char opt_str[128];
    int require_signedpath = 0;

    memset(&sessionkey, 0, sizeof(sessionkey));
    memset(&adtkt, 0, sizeof(adtkt));
    krb5_data_zero(&rspac);

    s = b->sname;
    r = b->realm;

    if(b->kdc_options.enc_tkt_in_skey){
	Ticket *t;
	hdb_entry_ex *uu;
	krb5_principal p;
	Key *uukey;
	    
	if(b->additional_tickets == NULL || 
	   b->additional_tickets->len == 0){
	    ret = KRB5KDC_ERR_BADOPTION; /* ? */
	    kdc_log(context, config, 0,
		    "No second ticket present in request");
	    goto out;
	}
	t = &b->additional_tickets->val[0];
	if(!get_krbtgt_realm(&t->sname)){
	    kdc_log(context, config, 0,
		    "Additional ticket is not a ticket-granting ticket");
	    ret = KRB5KDC_ERR_POLICY;
	    goto out;
	}
	_krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
	ret = _kdc_db_fetch(context, config, p, 
			    HDB_F_GET_CLIENT|HDB_F_GET_SERVER, 
			    NULL, &uu);
	krb5_free_principal(context, p);
	if(ret){
	    if (ret == HDB_ERR_NOENTRY)
		ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
	    goto out;
	}
	ret = hdb_enctype2key(context, &uu->entry, 
			      t->enc_part.etype, &uukey);
	if(ret){
	    _kdc_free_ent(context, uu);
	    ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
	    goto out;
	}
	ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
	_kdc_free_ent(context, uu);
	if(ret)
	    goto out;

	ret = verify_flags(context, config, &adtkt, spn);
	if (ret)
	    goto out;

	s = &adtkt.cname;
	r = adtkt.crealm;
    }

    _krb5_principalname2krb5_principal(context, &sp, *s, r);
    ret = krb5_unparse_name(context, sp, &spn);	
    if (ret)
	goto out;
    _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
    ret = krb5_unparse_name(context, cp, &cpn);
    if (ret)
	goto out;
    unparse_flags (KDCOptions2int(b->kdc_options),
		   asn1_KDCOptions_units(),
		   opt_str, sizeof(opt_str));
    if(*opt_str)
	kdc_log(context, config, 0,
		"TGS-REQ %s from %s for %s [%s]", 
		cpn, from, spn, opt_str);
    else
	kdc_log(context, config, 0,
		"TGS-REQ %s from %s for %s", cpn, from, spn);

    /*
     * Fetch server
     */

server_lookup:
    ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER, NULL, &server);

    if(ret){
	const char *new_rlm;
	Realm req_rlm;
	krb5_realm *realms;

	if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
	    if(nloop++ < 2) {
		new_rlm = find_rpath(context, tgt->crealm, req_rlm);
		if(new_rlm) {
		    kdc_log(context, config, 5, "krbtgt for realm %s "
			    "not found, trying %s", 
			    req_rlm, new_rlm);
		    krb5_free_principal(context, sp);
		    free(spn);
		    krb5_make_principal(context, &sp, r, 
					KRB5_TGS_NAME, new_rlm, NULL);
		    ret = krb5_unparse_name(context, sp, &spn);	
		    if (ret)
			goto out;
		    goto server_lookup;
		}
	    }
	} else if(need_referral(context, sp, &realms)) {
	    if (strcmp(realms[0], sp->realm) != 0) {
		kdc_log(context, config, 5,
			"Returning a referral to realm %s for "
			"server %s that was not found",
			realms[0], spn);
		krb5_free_principal(context, sp);
		free(spn);
		krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
				    realms[0], NULL);
		ret = krb5_unparse_name(context, sp, &spn);
		if (ret)
		    goto out;
		krb5_free_host_realm(context, realms);
		goto server_lookup;
	    }
	    krb5_free_host_realm(context, realms);
	}
	kdc_log(context, config, 0,
		"Server not found in database: %s: %s", spn,
		krb5_get_err_text(context, ret));
	if (ret == HDB_ERR_NOENTRY)
	    ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
	goto out;
    }

    ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT, NULL, &client);
    if(ret) {
	const char *krbtgt_realm; 

	/*
	 * If the client belongs to the same realm as our krbtgt, it
	 * should exist in the local database.
	 *
	 */

	krbtgt_realm = 
	    krb5_principal_get_comp_string(context, 
					   krbtgt->entry.principal, 1);

	if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
	    if (ret == HDB_ERR_NOENTRY)
		ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
	    kdc_log(context, config, 1, "Client no longer in database: %s",
		    cpn);
	    goto out;
	}
	
	kdc_log(context, config, 1, "Client not found in database: %s: %s",
		cpn, krb5_get_err_text(context, ret));

	cross_realm = 1;
    }
    
    /*
     * Check that service is in the same realm as the krbtgt. If its
     * not the same, its someone that is using a uni-directional trust
     * backward.
     */
    
    if (strcmp(krb5_principal_get_realm(context, sp),
	       krb5_principal_get_comp_string(context, 
					      krbtgt->entry.principal, 
					      1)) != 0) {
	char *tpn;
	ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn);
	kdc_log(context, config, 0,
		"Request with wrong krbtgt: %s",
		(ret == 0) ? tpn : "<unknown>");
	if(ret == 0)
	    free(tpn);
	ret = KRB5KRB_AP_ERR_NOT_US;
	goto out;
    }

    /*
     *
     */

    client_principal = cp;

    if (client) {
	const PA_DATA *sdata;
	int i = 0;

	sdata = _kdc_find_padata(req, &i, KRB5_PADATA_S4U2SELF);
	if (sdata) {
	    krb5_crypto crypto;
	    krb5_data datack;
	    PA_S4U2Self self;
	    char *selfcpn = NULL;
	    const char *str;

	    ret = decode_PA_S4U2Self(sdata->padata_value.data, 
				     sdata->padata_value.length,
				     &self, NULL);
	    if (ret) {
		kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
		goto out;
	    }

	    ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
	    if (ret)
		goto out;

	    ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
	    if (ret) {
		free_PA_S4U2Self(&self);
		krb5_data_free(&datack);
		kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
			krb5_get_err_text(context, ret));
		goto out;
	    }

	    ret = krb5_verify_checksum(context,
				       crypto,
				       KRB5_KU_OTHER_CKSUM,
				       datack.data, 
				       datack.length, 
				       &self.cksum);
	    krb5_data_free(&datack);
	    krb5_crypto_destroy(context, crypto);
	    if (ret) {
		free_PA_S4U2Self(&self);
		kdc_log(context, config, 0, 
			"krb5_verify_checksum failed for S4U2Self: %s",
			krb5_get_err_text(context, ret));
		goto out;
	    }

	    ret = _krb5_principalname2krb5_principal(context,
						     &client_principal,
						     self.name,
						     self.realm);
	    free_PA_S4U2Self(&self);
	    if (ret)
		goto out;

	    ret = krb5_unparse_name(context, client_principal, &selfcpn);	
	    if (ret)
		goto out;

	    /*
	     * Check that service doing the impersonating is
	     * requesting a ticket to it-self.
	     */
	    if (krb5_principal_compare(context, cp, sp) != TRUE) {
		kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
			"to impersonate some other user "
			"(tried for user %s to service %s)",
			cpn, selfcpn, spn);
		free(selfcpn);
		ret = KRB5KDC_ERR_BADOPTION; /* ? */
		goto out;
	    }

	    /*
	     * If the service isn't trusted for authentication to
	     * delegation, remove the forward flag.
	     */

	    if (client->entry.flags.trusted_for_delegation) {
		str = "[forwardable]";
	    } else {
		b->kdc_options.forwardable = 0;
		str = "";
	    }
	    kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
		    "service %s %s", cpn, selfcpn, spn, str);
	    free(selfcpn);
	}
    }

    /*
     * Constrained delegation
     */

    if (client != NULL
	&& b->additional_tickets != NULL
	&& b->additional_tickets->len != 0
	&& b->kdc_options.enc_tkt_in_skey == 0)
    {
	Key *clientkey;
	Ticket *t;
	char *str;

	t = &b->additional_tickets->val[0];

	ret = hdb_enctype2key(context, &client->entry, 
			      t->enc_part.etype, &clientkey);
	if(ret){
	    ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
	    goto out;
	}

	ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
	if (ret) {
	    kdc_log(context, config, 0,
		    "failed to decrypt ticket for "
		    "constrained delegation from %s to %s ", spn, cpn);
	    goto out;
	}

	/* check that ticket is valid */

	if (adtkt.flags.forwardable == 0) {
	    kdc_log(context, config, 0,
		    "Missing forwardable flag on ticket for "
		    "constrained delegation from %s to %s ", spn, cpn);
	    ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
	    goto out;
	}

	ret = check_constrained_delegation(context, config, client, sp);
	if (ret) {
	    kdc_log(context, config, 0,
		    "constrained delegation from %s to %s not allowed", 
		    spn, cpn);
	    goto out;
	}

	ret = _krb5_principalname2krb5_principal(context,
						 &client_principal,
						 adtkt.cname,
						 adtkt.crealm);
	if (ret)
	    goto out;

	ret = krb5_unparse_name(context, client_principal, &str);
	if (ret)
	    goto out;

	ret = verify_flags(context, config, &adtkt, str);
	if (ret) {
	    free(str);
	    goto out;
	}

	/*
	 * Check KRB5SignedPath in authorization data and add new entry to
	 * make sure servers can't fake a ticket to us.
	 */

	ret = check_KRB5SignedPath(context,
				   config,
				   krbtgt,
				   &adtkt,
				   &spp,
				   1);
	if (ret) {
	    kdc_log(context, config, 0,
		    "KRB5SignedPath check from service %s failed "
		    "for delegation to %s for client %s "
		    "from %s failed with %s",
		    spn, str, cpn, from, krb5_get_err_text(context, ret));
	    free(str);
	    goto out;
	}

	kdc_log(context, config, 0, "constrained delegation for %s "
		"from %s to %s", str, cpn, spn);
	free(str);

	/* 
	 * Also require that the KDC have issue the service's krbtgt
	 * used to do the request. 
	 */
	require_signedpath = 1;
    }

    /*
     * Check flags
     */

    ret = _kdc_check_flags(context, config, 
			   client, cpn,
			   server, spn,
			   FALSE);
    if(ret)
	goto out;

    if((b->kdc_options.validate || b->kdc_options.renew) && 
       !krb5_principal_compare(context, 
			       krbtgt->entry.principal,
			       server->entry.principal)){
	kdc_log(context, config, 0, "Inconsistent request.");
	ret = KRB5KDC_ERR_SERVER_NOMATCH;
	goto out;
    }

    /* check for valid set of addresses */
    if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
	ret = KRB5KRB_AP_ERR_BADADDR;
	kdc_log(context, config, 0, "Request from wrong address");
	goto out;
    }
	
    /*
     * Select enctype, return key and kvno.
     */

    {
	krb5_enctype etype;

	if(b->kdc_options.enc_tkt_in_skey) {
	    int i;
	    ekey = &adtkt.key;
	    for(i = 0; i < b->etype.len; i++)
		if (b->etype.val[i] == adtkt.key.keytype)
		    break;
	    if(i == b->etype.len) {
		krb5_clear_error_string(context);
		return KRB5KDC_ERR_ETYPE_NOSUPP;
	    }
	    etype = b->etype.val[i];
	    kvno = 0;
	} else {
	    Key *skey;
	    
	    ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len,
				  &skey, &etype);
	    if(ret) {
		kdc_log(context, config, 0, 
			"Server (%s) has no support for etypes", spp);
		return ret;
	    }
	    ekey = &skey->key;
	    kvno = server->entry.kvno;
	}
	
	ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
	if (ret)
	    goto out;
    }

    /* check PAC if not cross realm and if there is one */
    if (!cross_realm) {
	Key *tkey;

	ret = hdb_enctype2key(context, &krbtgt->entry, 
			      krbtgt_etype, &tkey);
	if(ret) {
	    kdc_log(context, config, 0,
		    "Failed to find key for krbtgt PAC check");
	    goto out;
	}

	ret = check_PAC(context, config, client_principal, 
			client, server, ekey, &tkey->key,
			tgt, &rspac, &require_signedpath);
	if (ret) {
	    kdc_log(context, config, 0,
		    "Verify PAC failed for %s (%s) from %s with %s",
		    spn, cpn, from, krb5_get_err_text(context, ret));
	    goto out;
	}
    }

    /* also check the krbtgt for signature */
    ret = check_KRB5SignedPath(context,
			       config,
			       krbtgt,
			       tgt,
			       &spp,
			       require_signedpath);
    if (ret) {
	kdc_log(context, config, 0,
		"KRB5SignedPath check failed for %s (%s) from %s with %s",
		spn, cpn, from, krb5_get_err_text(context, ret));
	goto out;
    }

    /*
     *
     */

    ret = tgs_make_reply(context,
			 config, 
			 b, 
			 client_principal,
			 tgt, 
			 ekey,
			 &sessionkey,
			 kvno,
			 auth_data,
			 server, 
			 spn,
			 client, 
			 cp, 
			 krbtgt, 
			 krbtgt_etype,
			 spp,
			 &rspac,
			 e_text,
			 reply);
	
out:
    free(spn);
    free(cpn);
	    
    krb5_data_free(&rspac);
    krb5_free_keyblock_contents(context, &sessionkey);
    if(server)
	_kdc_free_ent(context, server);
    if(client)
	_kdc_free_ent(context, client);

    if (client_principal && client_principal != cp)
	krb5_free_principal(context, client_principal);
    if (cp)
	krb5_free_principal(context, cp);
    if (sp)
	krb5_free_principal(context, sp);

    free_EncTicketPart(&adtkt);

    return ret;
}
Exemplo n.º 3
0
int main(int argc, char **argv)
   {
   console_init(Version) ;

   //***********************************************************
   //  Check for NDIR environment variable
   //***********************************************************

   //  get program filename
   int startIdx = 1 ;
   char exename[PATH_MAX] ;

   // for (int j = 1; j < argc; j++) {
   //    printf("0: %s\n", argv[j]) ;
   // }

   //  interesting lessons from WinNT 4.0:
   //  If the OS is WinNT 4.0, and;
   //  If the executable file is located in the current directory,
   //  THEN:
   //    argv[0] does NOT contain the fully-qualified
   //    path of the EXE, it *only* contains the EXE name.
   //    In all other situations, argv[0] is fully qualified!!
   //  
   //  P.S.  While we're here, derive default INI filename also
   // printf("argv0=%s\n", argv[0]) ;
   char* strptr = strrchr(argv[0], '\\') ;
   //  no path present
   if (strptr == 0) {
      SearchPath(NULL, argv[0], ".exe", PATH_MAX, ininame, NULL) ;
      strptr = strrchr(ininame, '\\') ;
      if (strptr != 0) 
         strcpy(strptr, "\\ndir.ini") ;

      strcpy(exename, argv[0]) ;
      // ininame[0] = 0 ;  //  ONLY support current location
   }
   else {
      //  pick up INI filename
      strcpy(ininame, argv[0]) ;
      strptr = strrchr(ininame, '\\') ;
      if (strptr == 0)
         return 1;
      strcpy(strptr, "\\ndir.ini") ;
      
      //  now process exe name for getenv()
      strptr++ ;  //lint !e613:  skip backslash
      strcpy(exename, strptr) ;  //lint !e613
      strptr = strchr(exename, '.') ;
      if (strptr != 0) 
         *strptr = 0 ;  //  strip the extension
   }

   char* options = getenv(exename) ; 
   if (options != 0) {
      argv[0] = options ;
      startIdx = 0 ;
   }
// printf("ininame=%s\n", ininame) ;
// getchar() ;

   // for (int j = startIdx; j < argc; j++) {
   //    printf("1: %s\n", argv[j]) ;
   // }
   //***********************************************************
   //  first read default settings
   //***********************************************************
   read_config_file() ;

   //***********************************************************
   //  override defaults with command line and environment vars
   //***********************************************************
   parse_command_args(startIdx, argc, argv) ;
   verify_flags() ;  //  this may add extensions if -x is given

   //***********************************************************
   //  Execute the requested command
   //***********************************************************
   // output_html_header("ndir32");
   display_logo() ;

   if (n.help)
      info(helptxt) ;
   else if (n.info)
      info(idtxt) ;
   else if (n.drive_summary)
      display_drive_summary() ;
   else {
      //  If no filespec was given, insert current path with *.*
      if (tcount==0)
         insert_target_filespec(".") ;

      sort_target_paths() ;      //  LFN: okay
      process_filespecs() ;
   }

   // output_html_footer();
   error_exit(DATA_OKAY, NULL) ;
   return 0 ;
   }