Add heimdal-0.6.3
[dragonfly.git] / crypto / heimdal-0.6.3 / appl / popper / pop_auth.c
1 /*
2  * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  * 
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by the Kungliga Tekniska
20  *      Högskolan and its contributors.
21  * 
22  * 4. Neither the name of the Institute nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  * 
26  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38
39 #include <popper.h>
40 #include <base64.h>
41 RCSID("$Id: pop_auth.c,v 1.2 2000/04/12 15:37:45 assar Exp $");
42
43 #ifdef KRB4
44
45 enum {
46     NO_PROT   = 1,
47     INT_PROT  = 2,
48     PRIV_PROT = 4
49 };
50
51 static int
52 auth_krb4(POP *p)
53 {
54     int ret;
55     des_cblock key;
56     u_int32_t nonce, nonce_reply;
57     u_int32_t max_client_packet;
58     int protocols = NO_PROT | INT_PROT | PRIV_PROT;
59     char data[8];
60     int len;
61     char *s;
62     char instance[INST_SZ];  
63     KTEXT_ST authent;
64     des_key_schedule schedule;
65     struct passwd *pw;
66
67     /* S -> C: 32 bit nonce in MSB base64 */
68
69     des_new_random_key(&key);
70     nonce = (key[0] | (key[1] << 8) | (key[2] << 16) | (key[3] << 24)
71              | key[4] | (key[5] << 8) | (key[6] << 16) | (key[7] << 24));
72     krb_put_int(nonce, data, 4, 8);
73     len = base64_encode(data, 4, &s);
74
75     pop_msg(p, POP_CONTINUE, "%s", s);
76     free(s);
77
78     /* C -> S: ticket and authenticator */
79
80     ret = sch_readline(p->input, &s);
81     if (ret <= 0 || strcmp (s, "*") == 0)
82         return pop_msg(p, POP_FAILURE,
83                        "authentication aborted by client");
84     len = strlen(s);
85     if (len > sizeof(authent.dat)) {
86         return pop_msg(p, POP_FAILURE, "data packet too long");
87     }
88
89     authent.length = base64_decode(s, authent.dat);
90
91     k_getsockinst (0, instance, sizeof(instance));
92     ret = krb_rd_req(&authent, "pop", instance,
93                      p->in_addr.sin_addr.s_addr,
94                      &p->kdata, NULL);
95     if (ret != 0) {
96         return pop_msg(p, POP_FAILURE, "rd_req: %s",
97                        krb_get_err_text(ret));
98     }
99     if (p->kdata.checksum != nonce) {
100         return pop_msg(p, POP_FAILURE, "data stream modified");
101     }
102
103     /* S -> C: nonce + 1 | bit | max segment */
104
105     krb_put_int(nonce + 1, data, 4, 7);
106     data[4] = protocols;
107     krb_put_int(1024, data + 5, 3, 3); /* XXX */
108     des_key_sched(&p->kdata.session, schedule);
109     des_pcbc_encrypt((des_cblock*)data,
110                      (des_cblock*)data, 8,
111                      schedule,
112                      &p->kdata.session,
113                      DES_ENCRYPT);
114     len = base64_encode(data, 8, &s);
115     pop_msg(p, POP_CONTINUE, "%s", s);
116
117     free(s);
118
119     /* C -> S: nonce | bit | max segment | username */
120
121     ret = sch_readline(p->input, &s);
122     if (ret <= 0 || strcmp (s, "*") == 0)
123         return pop_msg(p, POP_FAILURE,
124                        "authentication aborted");
125     len = strlen(s);
126     if (len > sizeof(authent.dat)) {
127         return pop_msg(p, POP_FAILURE, "data packet too long");
128     }
129
130     authent.length = base64_decode(s, authent.dat);
131     
132     if (authent.length % 8 != 0) {
133         return pop_msg(p, POP_FAILURE, "reply is not a multiple of 8 bytes");
134     }
135
136     des_key_sched(&p->kdata.session, schedule);
137     des_pcbc_encrypt((des_cblock*)authent.dat,
138                      (des_cblock*)authent.dat,
139                      authent.length,
140                      schedule,
141                      &p->kdata.session,
142                      DES_DECRYPT);
143
144     krb_get_int(authent.dat, &nonce_reply, 4, 0);
145     if (nonce_reply != nonce) {
146         return pop_msg(p, POP_FAILURE, "data stream modified");
147     }
148     protocols &= authent.dat[4];
149     krb_get_int(authent.dat + 5, &max_client_packet, 3, 0);
150     if(authent.dat[authent.length - 1] != '\0') {
151         return pop_msg(p, POP_FAILURE, "bad format of username");
152     }
153     strncpy (p->user, authent.dat + 8, sizeof(p->user));
154     pw = k_getpwnam(p->user);
155     if (pw == NULL) {
156         return (pop_msg(p,POP_FAILURE,
157                         "Password supplied for \"%s\" is incorrect.",
158                         p->user));
159     }
160
161     if (kuserok(&p->kdata, p->user)) {
162         pop_log(p, POP_PRIORITY,
163                 "%s: (%s.%s@%s) tried to retrieve mail for %s.",
164                 p->client, p->kdata.pname, p->kdata.pinst,
165                 p->kdata.prealm, p->user);
166         return(pop_msg(p,POP_FAILURE,
167                        "Popping not authorized"));
168     }
169     pop_log(p, POP_INFO, "%s: %s.%s@%s -> %s",
170             p->ipaddr,
171             p->kdata.pname, p->kdata.pinst, p->kdata.prealm,
172             p->user);
173     ret = pop_login(p, pw);
174     if (protocols & PRIV_PROT)
175         ;
176     else if (protocols & INT_PROT)
177         ;
178     else
179         ;
180     
181     return ret;
182 }
183 #endif /* KRB4 */
184
185 #ifdef KRB5
186 static int
187 auth_gssapi(POP *p)
188 {
189     
190 }
191 #endif /* KRB5 */
192
193 /* 
194  *  auth: RFC1734
195  */
196
197 static struct {
198     const char *name;
199     int (*func)(POP *);
200 } methods[] = {
201 #ifdef KRB4
202     {"KERBEROS_V4",     auth_krb4},
203 #endif
204 #ifdef KRB5
205     {"GSSAPI",          auth_gssapi},
206 #endif
207     {NULL,              NULL}
208 };
209
210 int
211 pop_auth (POP *p)
212 {
213     int i;
214
215     for (i = 0; methods[i].name != NULL; ++i)
216         if (strcasecmp(p->pop_parm[1], methods[i].name) == 0)
217             return (*methods[i].func)(p);
218     return pop_msg(p, POP_FAILURE,
219                    "Authentication method %s unknown", p->pop_parm[1]);
220 }