diff --git a/appl/popper/pop_init.c b/appl/popper/pop_init.c index 3a6ac4693..3fee9c55d 100644 --- a/appl/popper/pop_init.c +++ b/appl/popper/pop_init.c @@ -7,22 +7,37 @@ #include RCSID("$Id$"); -static -int -krb_authenticate(POP *p, struct sockaddr_in *addr) +#ifdef KRB4 +static int +krb4_authenticate (POP *p, int s, u_char *buf, struct sockaddr_in *addr) { - -#ifdef KERBEROS 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(0L, 0, &ticket, "pop", instance, - addr, (struct sockaddr_in *) NULL, - &p->kdata, "", schedule, version); + 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", @@ -37,14 +52,86 @@ krb_authenticate(POP *p, struct sockaddr_in *addr) 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_sname_to_principal (p->context, + p->myhost, + "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 +static int plain_authenticate (POP *p, struct sockaddr_in *addr) { return(POP_SUCCESS); @@ -75,7 +162,7 @@ pop_init(POP *p,int argcount,char **argmessage) p->myname = argmessage[0]; /* Get the name of our host */ - k_gethostname(p->myhost,MaxHostNameLen); + gethostname(p->myhost,MaxHostNameLen); /* Open the log file */ openlog(p->myname,POP_LOGOPTS,POP_FACILITY); @@ -153,8 +240,8 @@ pop_init(POP *p,int argcount,char **argmessage) if (inetd) { if (portnum == 0) portnum = p->kerberosp ? - k_getportbyname("kpop", "tcp", htons(1109)) : - k_getportbyname("pop", "tcp", htons(110)); + krb5_getportbyname("kpop", "tcp", htons(1109)) : + krb5_getportbyname("pop", "tcp", htons(110)); mini_inetd (portnum); } @@ -245,5 +332,9 @@ pop_init(POP *p,int argcount,char **argmessage) 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)); } diff --git a/appl/popper/pop_pass.c b/appl/popper/pop_pass.c index 71e8c44e3..d81c5d92e 100644 --- a/appl/popper/pop_pass.c +++ b/appl/popper/pop_pass.c @@ -7,6 +7,95 @@ #include RCSID("$Id$"); +#ifdef KRB4 +static int +krb4_verify_password (POP *p) +{ + int status; + char lrealm[REALM_SZ + 1]; + char tkt[MaxPathLen]; + + status = krb_get_lrealm(lrealm,1); + if (status == KFAILURE) { + 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(status)); + return 1; + } + snprintf (tkt, sizeof(tkt), + TKT_ROOT "_popper.%u", (unsigned)getpid()); + krb_set_tkt_string (tkt); + + return krb_verify_user(p->user, "", lrealm, p->pop_parm[1], + 1, "pop"); +} +#endif /* KRB4 */ + +static int +krb5_verify_password (POP *p) +{ + krb5_preauthtype pre_auth_types[] = {KRB5_PADATA_ENC_TIMESTAMP}; + krb5_get_init_creds_opt get_options; + krb5_verify_init_creds_opt verify_options; + krb5_error_code ret; + krb5_principal client, server; + krb5_creds creds; + + krb5_get_init_creds_opt_init (&get_options); + + krb5_get_init_creds_opt_set_preauth_list (&get_options, + pre_auth_types, + 1); + + krb5_verify_init_creds_opt_init (&verify_options); + + ret = krb5_parse_name (p->context, p->user, &client); + if (ret) { + pop_log(p, POP_FAILURE, "krb5_parse_name: %s", + krb5_get_err_text (p->context, ret)); + return 1; + } + + ret = krb5_get_init_creds_password (p->context, + &creds, + client, + p->pop_parm[1], + NULL, + NULL, + 0, + NULL, + &get_options); + if (ret) { + pop_log(p, POP_FAILURE, + "krb5_get_init_creds_password: %s", + krb5_get_err_text (p->context, ret)); + return 1; + } + + ret = krb5_sname_to_principal (p->context, + p->myhost, + "pop", + KRB5_NT_SRV_HST, + &server); + if (ret) { + pop_log(p, POP_FAILURE, + "krb5_get_init_creds_password: %s", + krb5_get_err_text (p->context, ret)); + return 1; + } + + ret = krb5_verify_init_creds (p->context, + &creds, + server, + NULL, + NULL, + &verify_options); + krb5_free_principal (p->context, client); + krb5_free_principal (p->context, server); + krb5_free_creds_contents (p->context, &creds); + return ret; +} + /* * pass: Obtain the user password from a POP client */ @@ -15,8 +104,6 @@ int pop_pass (POP *p) { struct passwd *pw; - char lrealm[REALM_SZ + 1]; - int status; int i; /* Make one string of all these parameters */ @@ -30,18 +117,32 @@ pop_pass (POP *p) "Password supplied for \"%s\" is incorrect.", p->user)); - if ((status = krb_get_lrealm(lrealm,1)) == KFAILURE) { - 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(status)); - return(pop_msg(p,POP_FAILURE, - "Kerberos error: \"%s\".", - krb_get_err_text(status))); - } - - if (!p->kerberosp) { - char tkt[MaxPathLen]; - + if (p->kerberosp) { +#ifdef KRB4 + if (p->version == 4) { + if(kuserok (&p->kdata, p->user)) { + pop_log(p, POP_FAILURE, + "%s: (%s.%s@%s) tried to retrieve mail for %s.", + p->client, p->kdata.pname, p->kdata.pinst, + p->kdata.prealm, p->user); + return(pop_msg(p,POP_FAILURE, + "Popping not authorized")); + } + } else +#endif /* KRB4 */ + if (p->version == 5) { + if (!krb5_kuserok (p->context, p->principal, p->user)) { + pop_log (p, POP_FAILURE, + "krb5 permission denied"); + return pop_msg(p, POP_FAILURE, + "Popping not authorized"); + } + } else { + pop_log (p, POP_FAILURE, "kerberos authentication failed"); + return pop_msg (p, POP_FAILURE, + "kerberos authentication failed"); + } + } else { /* We don't accept connections from users with null passwords */ if (pw->pw_passwd == NULL) return (pop_msg(p, @@ -49,32 +150,23 @@ pop_pass (POP *p) "Password supplied for \"%s\" is incorrect.", p->user)); - snprintf (tkt, sizeof(tkt), - TKT_ROOT "_popper.%u", (unsigned)getpid()); - krb_set_tkt_string (tkt); if (otp_verify_user (&p->otp_ctx, p->pop_parm[1]) == 0) ; else if(p->auth_level != AUTH_NONE) return pop_msg(p, POP_FAILURE, "Password supplied for \"%s\" is incorrect.", p->user); - else if (krb_verify_user(p->user, "", lrealm, p->pop_parm[1], - 1, "pop") && - unix_verify_user(p->user, p->pop_parm[1])) { - dest_tkt (); - return (pop_msg(p,POP_FAILURE, - "Password supplied for \"%s\" is incorrect.", - p->user)); - } - dest_tkt (); - } else { - if (kuserok (&p->kdata, p->user)) { - pop_log(p, POP_FAILURE, - "%s: (%s.%s@%s) tried to retrieve mail for %s.", - p->client, p->kdata.pname, p->kdata.pinst, - p->kdata.prealm, p->user); - return(pop_msg(p,POP_FAILURE, - "Popping not authorized")); + else { +#ifdef KRB4 + if (krb4_verify_password (p) == 0) + ; + else +#endif /* KRB4 */ + if (krb5_verify_password (p) == 0) + ; + else + return pop_msg(p, POP_FAILURE, + "Password incorrect"); } }