Пример #1
0
/* Set the key for krb_rd_req so we can check tgt */
static int
set_tgtkey(char *r, krb5_kvno kvno, krb5_boolean use_3des)
{
    int     n;
    static char lastrealm[REALM_SZ] = "";
    static int last_kvno = 0;
    static krb5_boolean last_use_3des = 0;
    static int more;
    Principal p_st;
    Principal *p = &p_st;
    C_Block key;
    krb5_keyblock k5key;

    k5key.contents = NULL;
    if (!strcmp(lastrealm, r) && last_kvno == kvno && last_use_3des == use_3des)
	return (KSUCCESS);

/*  log("Getting key for %s", r); */

    n = kerb_get_principal("krbtgt", r, p, &more, &k5key, kvno, 1, NULL);
    if (n == 0)
	return (KFAILURE);

    if (isflagset(p->attributes, V4_KDB_DISALLOW_ALL_TIX)) {
	lt = klog(L_ERR_SEXP,
		  "V5 DISALLOW_ALL_TIX set: \"krbtgt\" \"%s\"", r);
	krb5_free_keyblock_contents(kdc_context, &k5key);
	return KFAILURE;
    }

    if (isflagset(p->attributes, V4_KDB_DISALLOW_SVR)) {
	lt = klog(L_ERR_SEXP, "V5 DISALLOW_SVR set: \"krbtgt\" \"%s\"", r);
	krb5_free_keyblock_contents(kdc_context, &k5key);
	return KFAILURE;
    }

    if (use_3des&&!K4KDC_ENCTYPE_OK(k5key.enctype)) {
	krb_set_key_krb5(kdc_context, &k5key);
	strncpy(lastrealm, r, sizeof(lastrealm) - 1);
	lastrealm[sizeof(lastrealm) - 1] = '\0';
	last_kvno = kvno;
	last_use_3des = use_3des;
    } else {
	/* unseal tgt key from master key */
	memcpy(key,                &p->key_low,  4);
	memcpy(((krb5_ui_4 *) key) + 1, &p->key_high, 4);
	kdb_encrypt_key(key, key, master_key,
			master_key_schedule, DECRYPT);
	krb_set_key((char *) key, 0);
	strncpy(lastrealm, r, sizeof(lastrealm) - 1);
	lastrealm[sizeof(lastrealm) - 1] = '\0';
	last_kvno = kvno;
    }
    krb5_free_keyblock_contents(kdc_context, &k5key);
    return (KSUCCESS);
}
Пример #2
0
main()
{
	struct	sockaddr_in	foreign;
	int			foreign_len = sizeof(foreign);
	int			rval, more;
	static  char	name[] = "kpasswdd";

	static	struct rlimit	rl = { 0, 0 };

	progname = name;
	openlog("kpasswdd", LOG_CONS | LOG_PID, LOG_AUTH);

	signal(SIGHUP, SIG_IGN);
	signal(SIGINT, SIG_IGN);
	signal(SIGTSTP, SIG_IGN);
	if(setrlimit(RLIMIT_CORE, &rl) < 0) {
		syslog(LOG_ERR, "setrlimit: %m");
		exit(1);
	}

	if(getpeername(0, &foreign, &foreign_len) < 0) {
		syslog(LOG_ERR,"getpeername: %m");
		exit(1);
	}

	strcpy(inst, "*");
	rval = krb_recvauth(
		0L,				/* !MUTUAL */
		0,				/* file desc */
		&ticket,			/* client's ticket */
		SERVICE,			/* expected service */
		inst,				/* expected instance */
		&foreign,			/* foreign addr */
		(struct sockaddr_in *) 0,	
		&kdata,
		"",
		(bit_64 *) NULL,		/* key schedule */
		version
	);


	if(rval != KSUCCESS) {
		syslog(LOG_ERR, "krb_recvauth: %s", krb_err_txt[rval]);
		cleanup();
		exit(1);
	}


	/* get master key */
	if(kdb_get_master_key(0, master_key, master_key_schedule) != 0) {
		syslog(LOG_ERR, "couldn't get master key");
		cleanup();
		exit(1);
	}

	mkeyversion = 
	   kdb_get_master_key(master_key, master_key_schedule, NULL);


	if(mkeyversion < 0) {
		syslog(LOG_NOTICE, "couldn't verify master key");
		cleanup();
		exit(1);
	}

	/* get principal info */
	rval = kerb_get_principal(
		kdata.pname,
		kdata.pinst,
		&principal_data,
		1,
		&more
	);

	if(rval != 1 || (more != 0)) {
		syslog(LOG_NOTICE, "more than 1 entry for %s.%s",
			kdata.pname, kdata.pinst);
		cleanup();
		exit(1);
	}

	/* get the user's key */

	bcopy(&principal_data.key_low, key, 4);
	bcopy(&principal_data.key_high, ((long *) key) + 1, 4);
	kdb_encrypt_key(key, key, master_key, master_key_schedule,
		DECRYPT);
	key_sched(key, key_schedule);
	des_set_key(key, key_schedule);


	/* get random key and send it over {random} Kperson */

	random_key(kpwd_data.random_key);
	strcpy(kpwd_data.secure_msg, SECURE_STRING);
	if(des_write(0, &kpwd_data, sizeof(kpwd_data)) != sizeof(kpwd_data)) {
		syslog(LOG_ERR, "error writing initial data");
		cleanup();
		exit(1);
	}

	bzero(key, sizeof(key));
	bzero(key_schedule, sizeof(key_schedule));

	/* now read update info: { info }Krandom */

	key_sched(kpwd_data.random_key, random_sched);
	des_set_key(kpwd_data.random_key, random_sched);
	if(des_read(0, &ud_data, sizeof(ud_data)) != sizeof(ud_data)) {
		syslog(LOG_ERR, "update aborted");
		cleanup();
		exit(1);
	}

	/* validate info string by looking at the embedded string */

	if(strcmp(ud_data.secure_msg, SECURE_STRING)) {
		syslog(LOG_NOTICE, "invalid update from %s",
			inet_ntoa(foreign.sin_addr));
		cleanup();
		exit(1);
	}

	/* produce the new key entry in the database { key }Kmaster */
	string_to_key(ud_data.pw, key);
	kdb_encrypt_key(key, key,
		master_key, master_key_schedule,
		ENCRYPT);
	bcopy(key, &principal_data.key_low, 4);
	bcopy(((long *) key) + 1,
		&principal_data.key_high, 4);
	bzero(key, sizeof(key));
	principal_data.key_version++;
	if(kerb_put_principal(&principal_data, 1)) {
		syslog(LOG_ERR, "couldn't write new record for %s.%s",
			principal_data.name, principal_data.instance);
		cleanup();
		exit(1);
	}

	syslog(LOG_NOTICE,"wrote new password field for %s.%s from %s",
		principal_data.name,
		principal_data.instance,
		inet_ntoa(foreign.sin_addr)
	);

	send_ack(0, "Update complete.\n");
	cleanup();
	exit(0);
}
Пример #3
0
void
kerberos_v4(struct sockaddr_in *client, KTEXT pkt)
{
    static KTEXT_ST rpkt_st;
    KTEXT   rpkt = &rpkt_st;
    static KTEXT_ST ciph_st;
    KTEXT   ciph = &ciph_st;
    static KTEXT_ST tk_st;
    KTEXT   tk = &tk_st;
    static KTEXT_ST auth_st;
    KTEXT   auth = &auth_st;
    AUTH_DAT ad_st;
    AUTH_DAT *ad = &ad_st;


    static struct in_addr client_host;
    static int msg_byte_order;
    static int swap_bytes;
    static u_char k_flags;
 /* char   *p_name, *instance; */
    int     lifetime = 0;
    int     i;
    C_Block key;
    Key_schedule key_s;
    char   *ptr;

    krb5_keyblock k5key;
    krb5_kvno kvno;
    krb5_deltat sk5life, ck5life;
    KRB4_32 v4endtime, v4req_end;

    k5key.contents = NULL;	/* in case we have to free it */

    ciph->length = 0;

    client_host = client->sin_addr;

    /* eval macros and correct the byte order and alignment as needed */
    req_version = pkt_version(pkt);	/* 1 byte, version */
    req_msg_type = pkt_msg_type(pkt);	/* 1 byte, Kerberos msg type */

    /* set these to point to something safe */
    req_name_ptr = req_inst_ptr = req_realm_ptr = "";

    /* check if disabled, but we tell client */
    if (kdc_v4 == KDC_V4_DISABLE) {
	lt = klog(L_KRB_PERR,
	"KRB will not handle v4 request from %s",
		  inet_ntoa(client_host));
	/* send an error reply */
	req_name_ptr = req_inst_ptr = req_realm_ptr = "";
	kerb_err_reply(client, pkt, KERB_ERR_PKT_VER, lt);
	return;
    }

    /* check packet version */
    if (req_version != KRB_PROT_VERSION) {
	lt = klog(L_KRB_PERR,
	"KRB prot version mismatch: KRB =%d request = %d",
		  KRB_PROT_VERSION, req_version, 0);
	/* send an error reply */
	req_name_ptr = req_inst_ptr = req_realm_ptr = "";
	kerb_err_reply(client, pkt, KERB_ERR_PKT_VER, lt);
	return;
    }
    msg_byte_order = req_msg_type & 1;

    swap_bytes = 0;
    if (msg_byte_order != HOST_BYTE_ORDER) {
	swap_bytes++;
    }
    klog(L_KRB_PINFO,
	"Prot version: %d, Byte order: %d, Message type: %d",
	 (int) req_version, msg_byte_order, req_msg_type);

    switch (req_msg_type & ~1) {

    case AUTH_MSG_KDC_REQUEST:
	{
	    int    req_life;	/* Requested liftime */
	    unsigned int request_backdate =  0; /*How far to backdate
						  in seconds.*/
	    char   *service;	/* Service name */
	    char   *instance;	/* Service instance */
#ifdef notdef
	    int     kerno;	/* Kerberos error number */
#endif
	    n_auth_req++;
	    tk->length = 0;
	    k_flags = 0;	/* various kerberos flags */


	    /* set up and correct for byte order and alignment */
	    req_name_ptr = (char *) pkt_a_name(pkt);
	    str_length_check(req_name_ptr, ANAME_SZ);
	    req_inst_ptr = (char *) pkt_a_inst(pkt);
	    str_length_check(req_inst_ptr, INST_SZ);
	    req_realm_ptr = (char *) pkt_a_realm(pkt);
	    str_length_check(req_realm_ptr, REALM_SZ);
	    memcpy(&req_time_ws, pkt_time_ws(pkt), sizeof(req_time_ws));
	    /* time has to be diddled */
	    if (swap_bytes) {
		swap_u_long(req_time_ws);
	    }
	    ptr = (char *) pkt_time_ws(pkt) + 4;

	    req_life = (*ptr++) & 0xff;

	    service = ptr;
	    str_length_check(service, SNAME_SZ);
	    instance = ptr + strlen(service) + 1;
	    str_length_check(instance, INST_SZ);

	    rpkt = &rpkt_st;

	    klog(L_INI_REQ,
	    "Initial ticket request Host: %s User: \"%s\" \"%s\"",
	       inet_ntoa(client_host), req_name_ptr, req_inst_ptr, 0);

	    if ((i = check_princ(req_name_ptr, req_inst_ptr, 0,
				 &a_name_data, &k5key, 0, &ck5life))) {
		kerb_err_reply(client, pkt, i, "check_princ failed");
		a_name_data.key_low = a_name_data.key_high = 0;
		krb5_free_keyblock_contents(kdc_context, &k5key);
		return;
	    }
	    /* don't use k5key for client */
	    krb5_free_keyblock_contents(kdc_context, &k5key);
	    tk->length = 0;	/* init */
	    if (strcmp(service, "krbtgt"))
		klog(L_NTGT_INTK,
		    "INITIAL request from %s.%s for %s.%s", req_name_ptr,
		    req_inst_ptr, service, instance, 0);
	    /* this does all the checking */
	    if ((i = check_princ(service, instance, lifetime,
				 &s_name_data, &k5key, 1, &sk5life))) {
		kerb_err_reply(client, pkt, i, "check_princ failed");
		a_name_data.key_high = a_name_data.key_low = 0;
		s_name_data.key_high = s_name_data.key_low = 0;
		krb5_free_keyblock_contents(kdc_context, &k5key);
		return;
	    }
	    /* Bound requested lifetime with service and user */
	    v4req_end = krb_life_to_time(kerb_time.tv_sec, req_life);
	    v4req_end = min(v4req_end, kerb_time.tv_sec + ck5life);
	    v4req_end = min(v4req_end, kerb_time.tv_sec + sk5life);
	    lifetime = krb_time_to_life(kerb_time.tv_sec, v4req_end);
	    v4endtime = krb_life_to_time(kerb_time.tv_sec, lifetime);
	    /*
	     * Adjust issue time backwards if necessary, due to
	     * roundup in krb_time_to_life().
	     */
	    if (v4endtime > v4req_end)
		request_backdate = v4endtime - v4req_end;

#ifdef NOENCRYPTION
	    memset(session_key, 0, sizeof(C_Block));
#else
	    /* random session key */
	    des_new_random_key(session_key);
#endif

	    /* unseal server's key from master key */
	    memcpy( key,                &s_name_data.key_low,  4);
	    memcpy( ((krb5_ui_4 *) key) + 1, &s_name_data.key_high, 4);

	    s_name_data.key_low = s_name_data.key_high = 0;
	    kdb_encrypt_key(key, key, master_key,
			    master_key_schedule, DECRYPT);
	    /* construct and seal the ticket */
	    /* We always issue des tickets; the 3des tickets are a broken hack*/
	    krb_create_ticket(tk, k_flags, a_name_data.name,
			      a_name_data.instance, local_realm,
			      client_host.s_addr, (char *) session_key,
			      lifetime, kerb_time.tv_sec - request_backdate,
			      s_name_data.name, s_name_data.instance,
			      key);

	    krb5_free_keyblock_contents(kdc_context, &k5key);
	    memset(key, 0, sizeof(key));
	    memset(key_s, 0, sizeof(key_s));

	    /*
	     * get the user's key, unseal it from the server's key, and
	     * use it to seal the cipher 
	     */

	    /* a_name_data.key_low a_name_data.key_high */
	    memcpy( key,                &a_name_data.key_low,  4);
	    memcpy( ((krb5_ui_4 *) key) + 1, &a_name_data.key_high, 4);
	    a_name_data.key_low= a_name_data.key_high = 0;

	    /* unseal the a_name key from the master key */
	    kdb_encrypt_key(key, key, master_key, 
			    master_key_schedule, DECRYPT);

	    create_ciph(ciph, session_key, s_name_data.name,
			s_name_data.instance, local_realm, lifetime,
		  s_name_data.key_version, tk, kerb_time.tv_sec, key);

	    /* clear session key */
	    memset(session_key, 0, sizeof(session_key));

	    memset(key, 0, sizeof(key));



	    /* always send a reply packet */
	    rpkt = create_auth_reply(req_name_ptr, req_inst_ptr,
		req_realm_ptr, req_time_ws, 0, a_name_data.exp_date,
		a_name_data.key_version, ciph);
	    krb4_sendto(f, (char *) rpkt->dat, rpkt->length, 0,
		   (struct sockaddr *) client, sizeof (struct sockaddr_in));
	    memset(&a_name_data, 0, sizeof(a_name_data));
	    memset(&s_name_data, 0, sizeof(s_name_data));
	    break;
	}
    case AUTH_MSG_APPL_REQUEST:
	{
	    krb5_ui_4  time_ws;	/* Workstation time */
	    int    req_life;	/* Requested liftime */
	    char   *service;	/* Service name */
	    char   *instance;	/* Service instance */
	    int     kerno = 0;	/* Kerberos error number */
	    unsigned int request_backdate =  0; /*How far to backdate
						  in seconds.*/
	    char    tktrlm[REALM_SZ];

	    n_appl_req++;
	    tk->length = 0;
	    k_flags = 0;	/* various kerberos flags */

	    auth->mbz = 0;	/* pkt->mbz already zeroed */
	    auth->length = 4 + strlen((char *)pkt->dat + 3);
	    if (auth->length + 1 > MAX_KTXT_LEN) {
		lt = klog(L_KRB_PERR,
			  "APPL request with realm length too long from %s",
			  inet_ntoa(client_host));
		kerb_err_reply(client, pkt, RD_AP_INCON,
			       "realm length too long");
		return;
	    }

	    auth->length += (int) *(pkt->dat + auth->length) +
		(int) *(pkt->dat + auth->length + 1) + 2;
	    if (auth->length > MAX_KTXT_LEN) {
		lt = klog(L_KRB_PERR,
			  "APPL request with funky tkt or req_id length from %s",
			  inet_ntoa(client_host));
		kerb_err_reply(client, pkt, RD_AP_INCON,
			       "funky tkt or req_id length");
		return;
	    }

	    memcpy(auth->dat, pkt->dat, auth->length);

	    strncpy(tktrlm, (char *)auth->dat + 3, REALM_SZ);
	    tktrlm[REALM_SZ-1] = '\0';
	    kvno = (krb5_kvno)auth->dat[2];
	    if ((!allow_v4_crossrealm)&&strcmp(tktrlm, local_realm) != 0) {
	      lt = klog(L_ERR_UNK,
			"Cross realm ticket from %s denied by policy,", tktrlm);
	      kerb_err_reply(client, pkt,
			       KERB_ERR_PRINCIPAL_UNKNOWN, lt);
		return;
	    }
	    if (set_tgtkey(tktrlm, kvno, 0)) {
	      lt = klog(L_ERR_UNK,
			  "FAILED set_tgtkey realm %s, kvno %d. Host: %s ",
			  tktrlm, kvno, inet_ntoa(client_host));
		/* no better error code */
		kerb_err_reply(client, pkt,
			       KERB_ERR_PRINCIPAL_UNKNOWN, lt);
		return;
	    }
	    kerno = krb_rd_req(auth, "krbtgt", tktrlm, client_host.s_addr,
		ad, 0);
	    if (kerno) {
		if (set_tgtkey(tktrlm, kvno, 1)) {
		    lt = klog(L_ERR_UNK,
			      "FAILED 3des set_tgtkey realm %s, kvno %d. Host: %s ",
			      tktrlm, kvno, inet_ntoa(client_host));
		    /* no better error code */
		    kerb_err_reply(client, pkt,
				   KERB_ERR_PRINCIPAL_UNKNOWN, lt);
		    return;
		}
		kerno = krb_rd_req(auth, "krbtgt", tktrlm, client_host.s_addr,
				   ad, 0);
	    }

	    if (kerno) {
		klog(L_ERR_UNK, "FAILED krb_rd_req from %s: %s",
		     inet_ntoa(client_host), krb_get_err_text(kerno));
		req_name_ptr = req_inst_ptr = req_realm_ptr = "";
		kerb_err_reply(client, pkt, kerno, "krb_rd_req failed");
		return;
	    }
	    ptr = (char *) pkt->dat + auth->length;

	    memcpy(&time_ws, ptr, 4);
	    ptr += 4;

	    req_life = (*ptr++) & 0xff;

	    service = ptr;
	    str_length_check(service, SNAME_SZ);
	    instance = ptr + strlen(service) + 1;
	    str_length_check(instance, INST_SZ);

	    klog(L_APPL_REQ, "APPL Request %s.%s@%s on %s for %s.%s",
	     ad->pname, ad->pinst, ad->prealm,
	     inet_ntoa(client_host), service, instance, 0);
	    req_name_ptr = ad->pname;
	    req_inst_ptr = ad->pinst;
	    req_realm_ptr = ad->prealm;

	    if (strcmp(ad->prealm, tktrlm)) {
		kerb_err_reply(client, pkt, KERB_ERR_PRINCIPAL_UNKNOWN,
		     "Can't hop realms");
		return;
	    }
	    if (!strcmp(service, "changepw")) {
		kerb_err_reply(client, pkt, KERB_ERR_PRINCIPAL_UNKNOWN,
		     "Can't authorize password changed based on TGT");
		return;
	    }
	    kerno = check_princ(service, instance, req_life,
				&s_name_data, &k5key, 1, &sk5life);
	    if (kerno) {
		kerb_err_reply(client, pkt, kerno, "check_princ failed");
		s_name_data.key_high = s_name_data.key_low = 0;
		krb5_free_keyblock_contents(kdc_context, &k5key);
		return;
	    }
	    /* Bound requested lifetime with service and user */
	    v4endtime = krb_life_to_time((KRB4_32)ad->time_sec, ad->life);
	    v4req_end = krb_life_to_time(kerb_time.tv_sec, req_life);
	    v4req_end = min(v4endtime, v4req_end);
	    v4req_end = min(v4req_end, kerb_time.tv_sec + sk5life);

	    lifetime = krb_time_to_life(kerb_time.tv_sec, v4req_end);
	    v4endtime = krb_life_to_time(kerb_time.tv_sec, lifetime);
	    /*
	     * Adjust issue time backwards if necessary, due to
	     * roundup in krb_time_to_life().
	     */
	    if (v4endtime > v4req_end)
		request_backdate = v4endtime - v4req_end;

	    /* unseal server's key from master key */
	    memcpy(key,                &s_name_data.key_low,  4);
	    memcpy(((krb5_ui_4 *) key) + 1, &s_name_data.key_high, 4);
	    s_name_data.key_low = s_name_data.key_high = 0;
	    kdb_encrypt_key(key, key, master_key,
			    master_key_schedule, DECRYPT);
	    /* construct and seal the ticket */

#ifdef NOENCRYPTION
	    memset(session_key, 0, sizeof(C_Block));
#else
	    /* random session key */
	    des_new_random_key(session_key);
#endif

	    /* ALways issue des tickets*/
	    krb_create_ticket(tk, k_flags, ad->pname, ad->pinst,
			      ad->prealm, client_host.s_addr,
			      (char *) session_key, lifetime,
			      kerb_time.tv_sec - request_backdate,
			      s_name_data.name, s_name_data.instance,
			      key);
	    krb5_free_keyblock_contents(kdc_context, &k5key);
	    memset(key, 0, sizeof(key));
	    memset(key_s, 0, sizeof(key_s));

	    create_ciph(ciph, session_key, service, instance,
			local_realm,
			lifetime, s_name_data.key_version, tk,
			kerb_time.tv_sec, ad->session);

	    /* clear session key */
	    memset(session_key, 0, sizeof(session_key));

	    memset(ad->session, 0, sizeof(ad->session));

	    rpkt = create_auth_reply(ad->pname, ad->pinst,
				     ad->prealm, time_ws,
				     0, 0, 0, ciph);
	    krb4_sendto(f, (char *) rpkt->dat, rpkt->length, 0,
		   (struct sockaddr *) client, sizeof (struct sockaddr_in));
	    memset(&s_name_data, 0, sizeof(s_name_data));
	    break;
	}


#ifdef notdef_DIE
    case AUTH_MSG_DIE:
	{
	    lt = klog(L_DEATH_REQ,
	        "Host: %s User: \"%s\" \"%s\" Kerberos killed",
	        inet_ntoa(client_host), req_name_ptr, req_inst_ptr, 0);
	    exit(0);
	}
#endif /* notdef_DIE */

    default:
	{
	    lt = klog(L_KRB_PERR,
		"Unknown message type: %d from %s port %u",
		req_msg_type, inet_ntoa(client_host),
		ntohs(client->sin_port));
	    break;
	}
    }
}