Files
heimdal/appl/popper/pop_init.c
Assar Westerlund bd5647c2c5 Use `krb5_sock_to_principal'
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@2947 ec53bebd-3082-4978-b11e-865c3cabbd6b
1997-08-12 15:50:15 +00:00

341 lines
9.1 KiB
C

/*
* Copyright (c) 1989 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include <popper.h>
RCSID("$Id$");
#ifdef KRB4
static int
krb4_authenticate (POP *p, int s, u_char *buf, struct sockaddr_in *addr)
{
Key_schedule schedule;
KTEXT_ST ticket;
char instance[INST_SZ];
char version[9];
int auth;
u_char buf2[BUFSIZ];
if (memcmp (buf, KRB_SENDAUTH_VERS, 4) != 0)
return -1;
if (krb5_net_read (p->context, s, buf + 4,
KRB_SENDAUTH_VLEN - 4) != KRB_SENDAUTH_VLEN - 4)
return -1;
if (memcmp (buf, KRB_SENDAUTH_VERS, KRB_SENDAUTH_VLEN) != 0)
return -1;
k_getsockinst (0, instance, sizeof(instance));
auth = krb_recvauth(KOPT_IGNORE_PROTOCOL,
s,
&ticket,
"pop",
instance,
addr,
(struct sockaddr_in *) NULL,
&p->kdata,
"",
schedule,
version);
if (auth != KSUCCESS) {
pop_msg(p, POP_FAILURE, "Kerberos authentication failure: %s",
krb_get_err_text(auth));
pop_log(p, POP_FAILURE, "%s: (%s.%s@%s) %s", p->client,
p->kdata.pname, p->kdata.pinst, p->kdata.prealm,
krb_get_err_text(auth));
exit (1);
}
#ifdef DEBUG
pop_log(p, POP_DEBUG, "%s.%s@%s (%s): ok", p->kdata.pname,
p->kdata.pinst, p->kdata.prealm, inet_ntoa(addr->sin_addr));
#endif /* DEBUG */
return 0;
}
#endif /* KRB4 */
static int
krb5_authenticate (POP *p, int s, u_char *buf, struct sockaddr_in *addr)
{
krb5_error_code ret;
krb5_auth_context auth_context = NULL;
u_int32_t len;
krb5_principal server;
krb5_ticket *ticket;
if (memcmp (buf, "\x00\x00\x00\x13", 4) != 0)
return -1;
len = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]);
if (krb5_net_read(p->context, s, buf, len) != len)
return -1;
if (len != sizeof(KRB5_SENDAUTH_VERSION)
|| memcmp (buf, KRB5_SENDAUTH_VERSION, len) != 0)
return -1;
ret = krb5_sock_to_principal (p->context,
s,
"pop",
KRB5_NT_SRV_HST,
&server);
if (ret) {
pop_log (p, POP_FAILURE,
"krb5_sname_to_principal: %s",
krb5_get_err_text(p->context, ret));
exit (1);
}
ret = krb5_recvauth (p->context,
&auth_context,
&s,
"KPOPV1.0",
server,
KRB5_RECVAUTH_IGNORE_VERSION,
NULL,
&ticket);
krb5_free_principal (p->context, server);
if (ret == 0) {
krb5_auth_con_free (p->context, auth_context);
krb5_copy_principal (p->context, ticket->client, &p->principal);
krb5_free_ticket (p->context, ticket);
}
return ret;
}
static int
krb_authenticate(POP *p, struct sockaddr_in *addr)
{
#ifdef KERBEROS
u_char buf[BUFSIZ];
if (krb5_net_read (p->context, 0, buf, 4) != 4) {
pop_msg(p, POP_FAILURE, "Reading four bytes: %s",
strerror(errno));
exit (1);
}
#ifdef KRB4
if (krb4_authenticate (p, 0, buf, addr) == 0)
p->version = 4;
else
#endif /* KRB4 */
if (krb5_authenticate (p, 0, buf, addr) == 0)
p->version = 5;
else {
exit (1);
}
#endif /* KERBEROS */
return(POP_SUCCESS);
}
static int
plain_authenticate (POP *p, struct sockaddr_in *addr)
{
return(POP_SUCCESS);
}
/*
* init: Start a Post Office Protocol session
*/
int
pop_init(POP *p,int argcount,char **argmessage)
{
struct sockaddr_in cs; /* Communication parameters */
struct hostent * ch; /* Client host information */
int errflag = 0;
int c;
int len;
int options = 0;
char * trace_file_name = "/tmp/popper-trace";
int inetd = 0;
int portnum = 0;
/* Initialize the POP parameter block */
memset (p, 0, sizeof(POP));
/* Save my name in a global variable */
p->myname = argmessage[0];
/* Get the name of our host */
gethostname(p->myhost,MaxHostNameLen);
/* Open the log file */
openlog(p->myname,POP_LOGOPTS,POP_FACILITY);
p->auth_level = AUTH_NONE;
/* Process command line arguments */
while ((c = getopt(argcount,argmessage,
#ifdef KERBEROS
"k"
#endif
"a:dip:T:t:")) != EOF)
switch (c) {
/* Auth level */
case 'a':
if (strcmp (optarg, "none") == 0)
p->auth_level = AUTH_NONE;
else if(strcmp(optarg, "otp") == 0)
p->auth_level = AUTH_OTP;
else
warnx ("bad value for -a: %s", optarg);
break;
/* Debugging requested */
case 'd':
p->debug++;
options |= SO_DEBUG;
break;
/* Port number */
case 'p':
portnum = htons(atoi(optarg));
break;
/* Debugging trace file specified */
case 't':
p->debug++;
if ((p->trace = fopen(optarg,"a+")) == NULL) {
pop_log(p,POP_PRIORITY,
"Unable to open trace file \"%s\", err = %d",
optarg,errno);
exit (1);
}
trace_file_name = optarg;
break;
#ifdef KERBEROS
/* Use kerberos version of POP3 protocol */
case 'k':
p->kerberosp = 1;
break;
#endif
/* Timeout value passed. Default changed */
case 'T':
pop_timeout = atoi(optarg);
break;
/* Fake inetd */
case 'i':
inetd = 1;
break;
/* Unknown option received */
default:
errflag++;
}
/* Exit if bad options specified */
if (errflag) {
fprintf(stderr,
"Usage: %s [-T timeout] [-a] [-d] [-k] [-i] [-t tracefile]\n",
argmessage[0]);
exit (1);
}
/* Fake inetd */
if (inetd) {
if (portnum == 0)
portnum = p->kerberosp ?
krb5_getportbyname("kpop", "tcp", htons(1109)) :
krb5_getportbyname("pop", "tcp", htons(110));
mini_inetd (portnum);
}
/* Get the address and socket of the client to whom I am speaking */
len = sizeof(cs);
if (getpeername(STDIN_FILENO, (struct sockaddr *)&cs, &len) < 0){
pop_log(p,POP_PRIORITY,
"Unable to obtain socket and address of client, err = %d",errno);
exit (1);
}
/* Save the dotted decimal form of the client's IP address
in the POP parameter block */
strncpy (p->ipaddr, inet_ntoa(cs.sin_addr), sizeof(p->ipaddr));
p->ipaddr[sizeof(p->ipaddr) - 1] = '\0';
/* Save the client's port */
p->ipport = ntohs(cs.sin_port);
/* Get the canonical name of the host to whom I am speaking */
ch = gethostbyaddr((char *)&cs.sin_addr, sizeof(cs.sin_addr), AF_INET);
if (ch == NULL){
pop_log(p,POP_PRIORITY,
"Unable to get canonical name of client, err = %d",errno);
strcpy (p->client, p->ipaddr);
}
/* Save the cannonical name of the client host in
the POP parameter block */
else {
/* Distrust distant nameservers */
struct hostent * ch_again;
char * * addrp;
/* See if the name obtained for the client's IP
address returns an address */
if ((ch_again = gethostbyname(ch->h_name)) == NULL) {
pop_log(p,POP_PRIORITY,
"Client at \"%s\" resolves to an unknown host name \"%s\"",
p->ipaddr,ch->h_name);
strcpy (p->client, p->ipaddr);
}
else {
/* Save the host name (the previous value was
destroyed by gethostbyname) */
strncpy (p->client, ch_again->h_name, sizeof(p->client));
p->client[sizeof(p->client) - 1] = '\0';
/* Look for the client's IP address in the list returned
for its name */
for (addrp=ch_again->h_addr_list; *addrp; ++addrp)
if (memcmp(*addrp, &cs.sin_addr, sizeof(cs.sin_addr))
== 0)
break;
if (!*addrp) {
pop_log (p,POP_PRIORITY,
"Client address \"%s\" not listed for its host name \"%s\"",
p->ipaddr,ch->h_name);
strcpy (p->client, p->ipaddr);
}
}
}
/* Create input file stream for TCP/IP communication */
if ((p->input = fdopen(STDIN_FILENO,"r")) == NULL){
pop_log(p,POP_PRIORITY,
"Unable to open communication stream for input, err = %d",errno);
exit (1);
}
/* Create output file stream for TCP/IP communication */
if ((p->output = fdopen(STDOUT_FILENO,"w")) == NULL){
pop_log(p,POP_PRIORITY,
"Unable to open communication stream for output, err = %d",errno);
exit (1);
}
pop_log(p,POP_PRIORITY,
"(v%s) Servicing request from \"%s\" at %s\n",
VERSION,p->client,p->ipaddr);
#ifdef DEBUG
if (p->trace)
pop_log(p,POP_PRIORITY,
"Tracing session and debugging information in file \"%s\"",
trace_file_name);
else if (p->debug)
pop_log(p,POP_PRIORITY,"Debugging turned on");
#endif /* DEBUG */
#ifdef KERBEROS
krb5_init_context (&p->context);
#endif
return((p->kerberosp ? krb_authenticate : plain_authenticate)(p, &cs));
}