Пример #1
0
static int
krb4_adat(void *app_data, void *buf, size_t len)
{
    KTEXT_ST tkt;
    AUTH_DAT auth_dat;
    char *p;
    int kerror;
    uint32_t cs;
    char msg[35]; /* size of encrypted block */
    int tmp_len;
    struct krb4_data *d = app_data;
    char inst[INST_SZ];
    struct sockaddr_in *his_addr_sin = (struct sockaddr_in *)his_addr;

    memcpy(tkt.dat, buf, len);
    tkt.length = len;

    k_getsockinst(0, inst, sizeof(inst));
    kerror = krb_rd_req(&tkt, "ftp", inst, 
			his_addr_sin->sin_addr.s_addr, &auth_dat, "");
    if(kerror == RD_AP_UNDEC){
	k_getsockinst(0, inst, sizeof(inst));
	kerror = krb_rd_req(&tkt, "rcmd", inst, 
			    his_addr_sin->sin_addr.s_addr, &auth_dat, "");
    }

    if(kerror){
	reply(535, "Error reading request: %s.", krb_get_err_text(kerror));
	return -1;
    }
    
    memcpy(d->key, auth_dat.session, sizeof(d->key));
    des_set_key(&d->key, d->schedule);

    strlcpy(d->name, auth_dat.pname, sizeof(d->name));
    strlcpy(d->instance, auth_dat.pinst, sizeof(d->instance));
    strlcpy(d->realm, auth_dat.prealm, sizeof(d->instance));

    cs = auth_dat.checksum + 1;
    {
	unsigned char tmp[4];
	KRB_PUT_INT(cs, tmp, 4, sizeof(tmp));
	tmp_len = krb_mk_safe(tmp, msg, 4, &d->key,
			      (struct sockaddr_in *)LOCAL_ADDR,
			      (struct sockaddr_in *)REMOTE_ADDR);
    }
    if(tmp_len < 0){
	reply(535, "Error creating reply: %s.", strerror(errno));
	return -1;
    }
    len = tmp_len;
    if(base64_encode(msg, len, &p) < 0) {
	reply(535, "Out of memory base64-encoding.");
	return -1;
    }
    reply(235, "ADAT=%s", p);
    sec_complete = 1;
    free(p);
    return 0;
}
Пример #2
0
int Krb4Validate(RPC2_CountedBS * cIdent, RPC2_EncryptionKey hKey, RPC2_EncryptionKey sKey)
{
    struct ktext *authenticator;
    struct auth_dat ticket;
    char *host = NULL;
    int rc = -1;

    if (cIdent->SeqLen != sizeof(struct ktext)) {
	fprintf(stderr, "Krb4Validate: cIdent too small to be authenticator");
	return -1;
    }

    host = krb_canonicalize_host(NULL);
    if (!host) return -1;

    authenticator = (struct ktext *)cIdent->SeqBody;

    rc = krb_rd_req(authenticator, kerberos4service, host, 0, &ticket, "");
    free(host);
    if (rc) {
	/* some kind of error */
	fprintf(stderr, "Krb4Validate: %s (%d)\n", krb_err_txt[rc], rc);
	return -1;
    }

    /* Check whether the realm is correct */
    if (strncmp(ticket.prealm, kerberos4realm, REALM_SZ)) {
	/* names differ */
	fprintf(stderr, "Krb4Validate: incorrect realm in ticket\n");
	/* do we have to clean up the ticket?? -JH */
	return -1;
    }

    /* Copy kerberos name back into cIdent. There should be room as it first
     * got to us via cIdent anyway */

    /* but let's make sure... */
    assert(ANAME_SZ + INST_SZ + 1 <= cIdent->SeqLen);

    snprintf(cIdent->SeqBody, cIdent->SeqLen, "%s.%s", ticket.pname, ticket.pinst);
    cIdent->SeqLen = strlen(cIdent->SeqBody);
    if (cIdent->SeqLen && cIdent->SeqBody[cIdent->SeqLen-1] == '.') {
	/* user.@realm == user@realm */
	cIdent->SeqLen--;
	cIdent->SeqBody[cIdent->SeqLen] = '\0';
    }
    cIdent->SeqLen++; /* include trailing '\0' */

    /* now prepare the keys */

    /* hKey is the md5 hash of the kerberos session secret */
    HashSecret(ticket.session, RPC2_KEYSIZE, hKey);

    /* sKey is a random sequence of bytes */
    GenerateSecret(sKey);

    return 0;
}
Пример #3
0
static Code_t
ZCheckAuthentication4(ZNotice_t *notice,
		      struct sockaddr_in *from)
{
    int result;
    char srcprincipal[ANAME_SZ+INST_SZ+REALM_SZ+4];
    KTEXT_ST authent;
    AUTH_DAT dat;
    ZChecksum_t checksum;
    char instance[INST_SZ+1];

    if (!notice->z_auth)
	return ZAUTH_NO;

    /* Check for bogus authentication data length. */
    if (notice->z_authent_len <= 0)
	return ZAUTH_FAILED;

    /* Read in the authentication data. */
    if (ZReadAscii(notice->z_ascii_authent,
		   strlen(notice->z_ascii_authent)+1,
		   (unsigned char *)authent.dat,
		   notice->z_authent_len) == ZERR_BADFIELD) {
	return ZAUTH_FAILED;
    }
    authent.length = notice->z_authent_len;

    strcpy(instance, SERVER_INSTANCE);

    /* We don't have the session key cached; do it the long way. */
    result = krb_rd_req(&authent, SERVER_SERVICE, instance,
			from->sin_addr.s_addr, &dat, srvtab_file);
    if (result == RD_AP_OK) {
	ZSetSessionDES(&dat.session);
	sprintf(srcprincipal, "%s%s%s@%s", dat.pname, dat.pinst[0] ? "." : "",
		dat.pinst, dat.prealm);
	if (strcmp(srcprincipal, notice->z_sender))
	    return ZAUTH_FAILED;
    } else {
	return ZAUTH_FAILED;	/* didn't decode correctly */
    }

    /* Check the cryptographic checksum. */
    checksum = compute_checksum(notice, dat.session);

    if (checksum != notice->z_checksum)
	return ZAUTH_FAILED;

    return ZAUTH_YES;
}
Пример #4
0
/*
 * GetKerberosData
 *
 * get ticket from file descriptor and decode it.
 * Return KFAILURE if we barf on reading the ticket, else return
 * the value of rd_ap_req() applied to the ticket.
 */
int
GetKerberosData(int fd, /* file descr. to read from */
		struct in_addr haddr, /* address of foreign host on fd */
		AUTH_DAT *kdata,	/* kerberos data (returned) */
		char *service, /* service principal desired */
		char *srvtab) /* file to get keys from */
{
    char p[20];
    KTEXT_ST ticket;		/* will get Kerberos ticket from client */
    unsigned int i;
    char instance[INST_SZ];

    /*
     * Get the Kerberos ticket.  The first few characters, terminated
     * by a blank, should give us a length; then get than many chars
     * which will be the ticket proper.
     */
    for (i=0; i<20; i++) {
	if (read(fd, &p[i], 1) != 1) {
	    syslog(LOG_WARNING,"bad read tkt len");
	    return(KFAILURE);
	}
	if (p[i] == ' ') {
	    p[i] = '\0';
	    break;
	}
    }
    ticket.length = atoi(p);
    if ((i==20) || (ticket.length<=0) || (ticket.length>MAX_KTXT_LEN)) {
	syslog(LOG_WARNING,"bad tkt len %d",ticket.length);
	return(KFAILURE);
    }
    for (i=0; i<ticket.length; i++) {
	if (read(fd, &ticket.dat[i], 1) != 1) {
	    syslog(LOG_WARNING,"bad tkt read");
	    return(KFAILURE);
	}
    }
    /*
     * now have the ticket.  use it to get the authenticated
     * data from Kerberos.
     */
    (void) strcpy(instance,"*");		/* let Kerberos fill it in */

    return(krb_rd_req(&ticket, service, instance, haddr.s_addr,
		      kdata, srvtab ? srvtab : ""));
}
Пример #5
0
static int decrypt_tkt(char *user, char *instance, char *realm, char *arg,
		       int (*key_proc)(char *, char *, char *,
				       char *, C_Block),
		       KTEXT *cipp)
{
    MSG_DAT msg_data;		/* Message data containing decrypted data */
    KTEXT_ST auth;		/* Authenticator */
    AUTH_DAT auth_dat;		/* Authentication data */
    KTEXT cip = *cipp;
    MSG_DAT scip;
    int status = 0;
    des_cblock key;
    des_key_schedule sched;
    char phost[MAXHOSTNAMELEN + 1];
    struct sockaddr_in caddr;	/* client internet address */
    struct sockaddr_in saddr;	/* server internet address */

    rkinitd_intkt_info *rii = (rkinitd_intkt_info *)arg;

    u_char enc_data[MAX_KTXT_LEN];

    SBCLEAR(auth);
    SBCLEAR(auth_dat);
    SBCLEAR(scip);
    BCLEAR(enc_data);

    scip.app_data = enc_data;

    /*
     * Exchange with the client our response from the KDC (ticket encrypted
     * in user's private key) for the same ticket encrypted in our
     * (not yet known) session key.
     */

    rpc_exchange_tkt(cip, &scip);

    /*
     * Get the authenticator
     */

    SBCLEAR(auth);

    rpc_getauth(&auth, &caddr, &saddr);

    /*
     * Decode authenticator and extract session key.  The first zero
     * means we don't care what host this comes from.  This needs to
     * be done with euid of root so that /etc/srvtab can be read.
     */

    BCLEAR(phost);
    this_phost(phost, sizeof(phost));

    /*
     * This function has to use longjmp to return to the caller
     * because the kerberos library routine that calls it doesn't
     * pay attention to the return value it gives.  That means that
     * if any of these routines failed, the error returned to the client
     * would be "password incorrect".
     */

    status = krb_rd_req(&auth, KEY, phost, caddr.sin_addr.s_addr,
			    &auth_dat, "");
    if (status) {
	sprintf(errbuf, "krb_rd_req: %s", krb_err_txt[status]);
	rkinit_errmsg(errbuf);
	longjmp(rii->env, status);
    }

    memcpy(key, auth_dat.session, sizeof(key));
    if (des_key_sched(key, sched)) {
	sprintf(errbuf, "Error in des_key_sched");
	rkinit_errmsg(errbuf);
	longjmp(rii->env, RKINIT_DES);
    }

    /* Decrypt the data. */
    if ((status =
	 krb_rd_priv((u_char *)scip.app_data, scip.app_length,
		     sched, key, &caddr, &saddr, &msg_data)) == KSUCCESS) {
	cip->length = msg_data.app_length;
	memcpy(cip->dat, msg_data.app_data, msg_data.app_length);
	cip->dat[cip->length] = 0;
    }
    else {
	sprintf(errbuf, "krb_rd_priv: %s", krb_err_txt[status]);
	rkinit_errmsg(errbuf);
	longjmp(rii->env, status);
    }
    if (setuid(user_id) < 0) {
	sprintf(errbuf,	"Failure setting uid to %lu: %s\n",
		(unsigned long)user_id, strerror(errno));
	rkinit_errmsg(errbuf);
	longjmp(rii->env, RKINIT_DAEMON);
    }
    return(KSUCCESS);
}
Пример #6
0
char *					/* R: allocated response string */
auth_krb4 (
  /* PARAMETERS */
  const char *login,			/* I: plaintext authenticator */
  const char *password,			/* I: plaintext password */
  const char *service,
  const char *realm_in
  /* END PARAMETERS */
  )
{
    /* VARIABLES */
    char aname[ANAME_SZ];		/* Kerberos principal */
    const char *realm;		        /* Kerberos realm to authenticate in */
    int rc;				/* return code */
    char tf_name[TF_NAME_LEN];		/* Ticket file name */
    char *instance, *user_specified;
    KTEXT_ST ticket;
    AUTH_DAT kdata;
    /* END VARIABLES */

    /*
     * Make sure we have a password. If this is NULL the call
     * to krb_get_pw_in_tkt below would try to prompt for
     * one interactively.
     */
    if (password == NULL) {
	syslog(LOG_ERR, "auth_krb4: NULL password?");
	return strdup("NO saslauthd internal error");
    }

    if (krbtf_name(tf_name, sizeof(tf_name)) != 0) {
      syslog(LOG_ERR, "auth_krb4: could not generate ticket file name");
      return strdup("NO saslauthd internal error");
    }
    krb_set_tkt_string(tf_name);

    strncpy(aname, login, ANAME_SZ-1);
    aname[ANAME_SZ-1] = '\0';

    instance = "";

    if (config) {
      char keyname[1024];

      snprintf(keyname, sizeof(keyname), "krb4_%s_instance", service);
      instance = cfile_getstring(config, keyname, "");
    }

    user_specified = strchr(aname, '.');
    if (user_specified) {
      if (instance && instance[0]) {
	/* sysadmin specified a (mandatory) instance */
	if (strcmp(user_specified + 1, instance)) {
	  return strdup("NO saslauthd principal name error");
	}
	/* nuke instance from "aname"-- matches what's already in "instance" */
	*user_specified = '\0';
      } else {
	/* sysadmin has no preference, so we shift
	 * instance name from "aname" to "instance"
	 */
	*user_specified = '\0';
	instance = user_specified + 1;
      }
    }

    if(realm_in && *realm_in != '\0') {
	realm = realm_in;
    } else {
	realm = default_realm;
    }

    rc = krb_get_pw_in_tkt(aname, instance, realm,
			   KRB_TICKET_GRANTING_TICKET,
			   realm, 1, password);

    if (rc == INTK_BADPW || rc == KDC_PR_UNKNOWN) {
	return strdup("NO");
    } else if (rc != KSUCCESS) {
      syslog(LOG_ERR, "ERROR: auth_krb4: krb_get_pw_in_tkt: %s",
	     krb_get_err_text(rc));

      return strdup("NO saslauthd internal error");
    }

    /* if the TGT wasn't spoofed, it should entitle us to an rcmd ticket... */
    rc = krb_mk_req(&ticket, verify_principal, myhostname, default_realm, 0);

    if (rc != KSUCCESS) {
      syslog(LOG_ERR, "ERROR: auth_krb4: krb_get_pw_in_tkt: %s",
	     krb_get_err_text(rc));
      dest_tkt();
      return strdup("NO saslauthd internal error");
    }

    /* .. and that ticket should match our secret host key */
    rc = krb_rd_req(&ticket, verify_principal, myhostname, 0, &kdata, srvtabname);

    if (rc != RD_AP_OK) {
      syslog(LOG_ERR, "ERROR: auth_krb4: krb_rd_req:%s",
	     krb_get_err_text(rc));
      dest_tkt();
      return strdup("NO saslauthd internal error");
    }

    dest_tkt();

    return strdup("OK");
}
Пример #7
0
void
kerberos4_is(Authenticator *ap, unsigned char *data, int cnt)
{
    struct sockaddr_in addr;
    char realm[REALM_SZ];
    char instance[INST_SZ];
    int r;
    int addr_len;

    if (cnt-- < 1)
	return;
    switch (*data++) {
    case KRB_AUTH:
	if (krb_get_lrealm(realm, 1) != KSUCCESS) {
	    Data(ap, KRB_REJECT, (void *)"No local V4 Realm.", -1);
	    auth_finished(ap, AUTH_REJECT);
	    if (auth_debug_mode)
		printf("No local realm\r\n");
	    return;
	}
	memmove(auth.dat, data, auth.length = cnt);
	if (auth_debug_mode) {
	    printf("Got %d bytes of authentication data\r\n", cnt);
	    printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length));
	    printd(auth.dat, auth.length);
	    printf("\r\n");
	}
	k_getsockinst(0, instance, sizeof(instance));
	addr_len = sizeof(addr);
	if(getpeername(0, (struct sockaddr *)&addr, &addr_len) < 0) {
	    if(auth_debug_mode)
		printf("getpeername failed\r\n");
	    Data(ap, KRB_REJECT, "getpeername failed", -1);
	    auth_finished(ap, AUTH_REJECT);
	    return;
	}
	r = krb_rd_req(&auth, KRB_SERVICE_NAME,
		       instance, addr.sin_addr.s_addr, &adat, "");
	if (r) {
	    if (auth_debug_mode)
		printf("Kerberos failed him as %s\r\n", name);
	    Data(ap, KRB_REJECT, (void *)krb_get_err_text(r), -1);
	    auth_finished(ap, AUTH_REJECT);
	    return;
	}
	/* save the session key */
	memmove(session_key, adat.session, sizeof(adat.session));
	krb_kntoln(&adat, name);

	if (UserNameRequested && !kuserok(&adat, UserNameRequested)){
	    char ts[MAXPATHLEN];
	    struct passwd *pw = getpwnam(UserNameRequested);

	    if(pw){
		snprintf(ts, sizeof(ts),
			 "%s%u",
			 TKT_ROOT,
			 (unsigned)pw->pw_uid);
		setenv("KRBTKFILE", ts, 1);
	    }
	    Data(ap, KRB_ACCEPT, NULL, 0);
	} else {
	    char *msg;

	    asprintf (&msg, "user `%s' is not authorized to "
		      "login as `%s'", 
		      krb_unparse_name_long(adat.pname, 
					    adat.pinst, 
					    adat.prealm), 
		      UserNameRequested ? UserNameRequested : "<nobody>");
	    if (msg == NULL)
		Data(ap, KRB_REJECT, NULL, 0);
	    else {
		Data(ap, KRB_REJECT, (void *)msg, -1);
		free(msg);
	    }
	}
	auth_finished(ap, AUTH_USER);
	break;
	
    case KRB_CHALLENGE:
#ifndef ENCRYPTION
	Data(ap, KRB_RESPONSE, NULL, 0);
#else
	if(!VALIDKEY(session_key)){
	    Data(ap, KRB_RESPONSE, NULL, 0);
	    break;
	}
	des_key_sched(&session_key, sched);
	{
	    des_cblock d_block;
	    int i;
	    Session_Key skey;

	    memmove(d_block, data, sizeof(d_block));

	    /* make a session key for encryption */
	    des_ecb_encrypt(&d_block, &session_key, sched, 1);
	    skey.type=SK_DES;
	    skey.length=8;
	    skey.data=session_key;
	    encrypt_session_key(&skey, 1);

	    /* decrypt challenge, add one and encrypt it */
	    des_ecb_encrypt(&d_block, &challenge, sched, 0);
	    for (i = 7; i >= 0; i--)
		if(++challenge[i] != 0)
		    break;
	    des_ecb_encrypt(&challenge, &challenge, sched, 1);
	    Data(ap, KRB_RESPONSE, (void *)challenge, sizeof(challenge));
	}
#endif
	break;

    case KRB_FORWARD:
	{
	    des_key_schedule ks;
	    unsigned char netcred[sizeof(CREDENTIALS)];
	    CREDENTIALS cred;
	    int ret;
	    if(cnt > sizeof(cred))
		abort();

	    des_set_key(&session_key, ks);
	    des_pcbc_encrypt((void*)data, (void*)netcred, cnt, 
			     ks, &session_key, DES_DECRYPT);
	    unpack_cred(netcred, cnt, &cred);
	    {
		if(strcmp(cred.service, KRB_TICKET_GRANTING_TICKET) ||
		   strncmp(cred.instance, cred.realm, sizeof(cred.instance)) ||
		   cred.lifetime < 0 || cred.lifetime > 255 ||
		   cred.kvno < 0 || cred.kvno > 255 ||
		   cred.issue_date < 0 || 
		   cred.issue_date > time(0) + CLOCK_SKEW ||
		   strncmp(cred.pname, adat.pname, sizeof(cred.pname)) ||
		   strncmp(cred.pinst, adat.pinst, sizeof(cred.pname))){
		    Data(ap, KRB_FORWARD_REJECT, "Bad credentials", -1);
		}else{
		    if((ret = tf_setup(&cred,
				       cred.pname,
				       cred.pinst)) == KSUCCESS){
		        struct passwd *pw = getpwnam(UserNameRequested);

			if (pw)
			  chown(tkt_string(), pw->pw_uid, pw->pw_gid);
			Data(ap, KRB_FORWARD_ACCEPT, 0, 0);
		    } else{
			Data(ap, KRB_FORWARD_REJECT, 
			     krb_get_err_text(ret), -1);
		    }
		}
	    }
	    memset(data, 0, cnt);
	    memset(ks, 0, sizeof(ks));
	    memset(&cred, 0, sizeof(cred));
	}
	
	break;

    default:
	if (auth_debug_mode)
	    printf("Unknown Kerberos option %d\r\n", data[-1]);
	Data(ap, KRB_REJECT, 0, 0);
	break;
    }
}
Пример #8
0
/*
 * try krb4 authentication,
 * return 1 on success, 0 on failure, -1 if krb4 is not available
 */
int
auth_krb4_password(Authctxt *authctxt, const char *password)
{
	AUTH_DAT adata;
	KTEXT_ST tkt;
	struct hostent *hp;
	struct passwd *pw;
	char localhost[MAXHOSTNAMELEN], phost[INST_SZ], realm[REALM_SZ];
	u_int32_t faddr;
	int r;

	if ((pw = authctxt->pw) == NULL)
		return (0);

	/*
	 * Try Kerberos password authentication only for non-root
	 * users and only if Kerberos is installed.
	 */
	if (pw->pw_uid != 0 && krb_get_lrealm(realm, 1) == KSUCCESS) {
		/* Set up our ticket file. */
		if (!krb4_init(authctxt)) {
			log("Couldn't initialize Kerberos ticket file for %s!",
			    pw->pw_name);
			goto failure;
		}
		/* Try to get TGT using our password. */
		r = krb_get_pw_in_tkt((char *) pw->pw_name, "", realm,
		    "krbtgt", realm, DEFAULT_TKT_LIFE, (char *)password);
		if (r != INTK_OK) {
			debug("Kerberos v4 password authentication for %s "
			    "failed: %s", pw->pw_name, krb_err_txt[r]);
			goto failure;
		}
		/* Successful authentication. */
		chown(tkt_string(), pw->pw_uid, pw->pw_gid);

		/*
		 * Now that we have a TGT, try to get a local
		 * "rcmd" ticket to ensure that we are not talking
		 * to a bogus Kerberos server.
		 */
		gethostname(localhost, sizeof(localhost));
		strlcpy(phost, (char *)krb_get_phost(localhost),
		    sizeof(phost));
		r = krb_mk_req(&tkt, KRB4_SERVICE_NAME, phost, realm, 33);

		if (r == KSUCCESS) {
			if ((hp = gethostbyname(localhost)) == NULL) {
				log("Couldn't get local host address!");
				goto failure;
			}
			memmove((void *)&faddr, (void *)hp->h_addr,
			    sizeof(faddr));

			/* Verify our "rcmd" ticket. */
			r = krb_rd_req(&tkt, KRB4_SERVICE_NAME, phost,
			    faddr, &adata, "");
			if (r == RD_AP_UNDEC) {
				/*
				 * Probably didn't have a srvtab on
				 * localhost. Disallow login.
				 */
				log("Kerberos v4 TGT for %s unverifiable, "
				    "no srvtab installed? krb_rd_req: %s",
				    pw->pw_name, krb_err_txt[r]);
				goto failure;
			} else if (r != KSUCCESS) {
				log("Kerberos v4 %s ticket unverifiable: %s",
				    KRB4_SERVICE_NAME, krb_err_txt[r]);
				goto failure;
			}
		} else if (r == KDC_PR_UNKNOWN) {
			/*
			 * Disallow login if no rcmd service exists, and
			 * log the error.
			 */
			log("Kerberos v4 TGT for %s unverifiable: %s; %s.%s "
			    "not registered, or srvtab is wrong?", pw->pw_name,
			    krb_err_txt[r], KRB4_SERVICE_NAME, phost);
			goto failure;
		} else {
			/*
			 * TGT is bad, forget it. Possibly spoofed!
			 */
			debug("WARNING: Kerberos v4 TGT possibly spoofed "
			    "for %s: %s", pw->pw_name, krb_err_txt[r]);
			goto failure;
		}
		/* Authentication succeeded. */
		return (1);
	} else
		/* Logging in as root or no local Kerberos realm. */
		debug("Unable to authenticate to Kerberos.");

 failure:
	krb4_cleanup_proc(authctxt);

	if (!options.kerberos_or_local_passwd)
		return (0);

	/* Fall back to ordinary passwd authentication. */
	return (-1);
}
Пример #9
0
int
auth_krb4(Authctxt *authctxt, KTEXT auth, char **client, KTEXT reply)
{
	AUTH_DAT adat = {0};
	Key_schedule schedule;
	struct sockaddr_in local, foreign;
	char instance[INST_SZ];
	socklen_t slen;
	u_int cksum;
	int r, s;

	s = packet_get_connection_in();

	slen = sizeof(local);
	memset(&local, 0, sizeof(local));
	if (getsockname(s, (struct sockaddr *) & local, &slen) < 0)
		debug("getsockname failed: %.100s", strerror(errno));
	slen = sizeof(foreign);
	memset(&foreign, 0, sizeof(foreign));
	if (getpeername(s, (struct sockaddr *) & foreign, &slen) < 0) {
		debug("getpeername failed: %.100s", strerror(errno));
		fatal_cleanup();
	}
	instance[0] = '*';
	instance[1] = 0;

	/* Get the encrypted request, challenge, and session key. */
	if ((r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance,
	    0, &adat, ""))) {
		debug("Kerberos v4 krb_rd_req: %.100s", krb_err_txt[r]);
		return (0);
	}
	des_key_sched((des_cblock *) adat.session, schedule);

	*client = xmalloc(MAX_K_NAME_SZ);
	(void) snprintf(*client, MAX_K_NAME_SZ, "%s%s%s@%s", adat.pname,
	    *adat.pinst ? "." : "", adat.pinst, adat.prealm);

	/* Check ~/.klogin authorization now. */
	if (kuserok(&adat, authctxt->user) != KSUCCESS) {
		log("Kerberos v4 .klogin authorization failed for %s to "
		    "account %s", *client, authctxt->user);
		xfree(*client);
		*client = NULL;
		return (0);
	}
	/* Increment the checksum, and return it encrypted with the
	   session key. */
	cksum = adat.checksum + 1;
	cksum = htonl(cksum);

	/* If we can't successfully encrypt the checksum, we send back an
	   empty message, admitting our failure. */
	if ((r = krb_mk_priv((u_char *) & cksum, reply->dat, sizeof(cksum) + 1,
	    schedule, &adat.session, &local, &foreign)) < 0) {
		debug("Kerberos v4 mk_priv: (%d) %s", r, krb_err_txt[r]);
		reply->dat[0] = 0;
		reply->length = 0;
	} else
		reply->length = r;

	/* Clear session key. */
	memset(&adat.session, 0, sizeof(&adat.session));
	return (1);
}
Пример #10
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;
	}
    }
}