2 * Copyright (c) 1995 - 2005 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 __RCSID("$Heimdal: krb4.c 15574 2005-07-07 20:06:19Z assar $"
41 struct krb4_kx_context
{
43 des_key_schedule schedule
;
47 typedef struct krb4_kx_context krb4_kx_context
;
50 * Destroy the krb4 context in `c'.
54 krb4_destroy (kx_context
*c
)
56 memset (c
->data
, 0, sizeof(krb4_kx_context
));
61 * Read the authentication information from `s' and return 0 if
66 krb4_authenticate (kx_context
*kc
, int s
)
72 krb4_kx_context
*c
= (krb4_kx_context
*)kc
->data
;
73 const char *host
= kc
->host
;
75 if (kc
->thisaddr
->sa_family
!= AF_INET
) {
76 warnx ("%s: used Kerberos v4 authentiocation on non-IP4 address", host
);
80 #ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM
81 if (krb_get_config_bool("nat_in_use")) {
82 struct in_addr natAddr
;
84 if (krb_get_our_ip_for_realm(krb_realmofhost(kc
->host
),
86 || krb_get_our_ip_for_realm (NULL
, &natAddr
) == KSUCCESS
)
87 ((struct sockaddr_in
*)kc
->thisaddr
)->sin_addr
= natAddr
;
91 status
= krb_sendauth (KOPT_DO_MUTUAL
, s
, &text
, "rcmd",
92 (char *)host
, krb_realmofhost (host
),
93 getpid(), &msg
, &cred
, c
->schedule
,
94 (struct sockaddr_in
*)kc
->thisaddr
,
95 (struct sockaddr_in
*)kc
->thataddr
, KX_VERSION
);
96 if (status
!= KSUCCESS
) {
97 warnx ("%s: %s", host
, krb_get_err_text(status
));
100 memcpy (c
->key
, cred
.session
, sizeof(des_cblock
));
105 * Read a krb4 priv packet from `fd' into `buf' (of size `len').
106 * Return the number of bytes read or 0 on EOF or -1 on error.
110 krb4_read (kx_context
*kc
,
111 int fd
, void *buf
, size_t len
)
113 unsigned char tmp
[4];
117 krb4_kx_context
*c
= (krb4_kx_context
*)kc
->data
;
120 ret
= krb_net_read (fd
, tmp
, 4);
125 l
= (tmp
[0] << 24) | (tmp
[1] << 16) | (tmp
[2] << 8) | tmp
[3];
128 if (krb_net_read (fd
, buf
, l
) != l
)
130 status
= krb_rd_priv (buf
, l
, c
->schedule
, &c
->key
,
131 (struct sockaddr_in
*)kc
->thataddr
,
132 (struct sockaddr_in
*)kc
->thisaddr
, &msg
);
133 if (status
!= RD_AP_OK
) {
134 warnx ("krb4_read: %s", krb_get_err_text(status
));
137 memmove (buf
, msg
.app_data
, msg
.app_length
);
138 return msg
.app_length
;
142 * Write a krb4 priv packet on `fd' with the data in `buf, len'.
143 * Return len or -1 on error
147 krb4_write(kx_context
*kc
,
148 int fd
, const void *buf
, size_t len
)
151 krb4_kx_context
*c
= (krb4_kx_context
*)kc
->data
;
153 unsigned char tmp
[4];
155 outbuf
= malloc (len
+ 30);
158 outlen
= krb_mk_priv ((void *)buf
, outbuf
, len
, c
->schedule
, &c
->key
,
159 (struct sockaddr_in
*)kc
->thisaddr
,
160 (struct sockaddr_in
*)kc
->thataddr
);
165 tmp
[0] = (outlen
>> 24) & 0xFF;
166 tmp
[1] = (outlen
>> 16) & 0xFF;
167 tmp
[2] = (outlen
>> 8) & 0xFF;
168 tmp
[3] = (outlen
>> 0) & 0xFF;
170 if (krb_net_write (fd
, tmp
, 4) != 4 ||
171 krb_net_write (fd
, outbuf
, outlen
) != outlen
) {
180 * Copy data from `fd1' to `fd2', {en,de}crypting with cfb64
181 * with `mode' and state stored in `iv', `schedule', and `num'.
182 * Return -1 if error, 0 if eof, else 1
186 do_enccopy (int fd1
, int fd2
, int mode
, des_cblock
*iv
,
187 des_key_schedule schedule
, int *num
)
192 ret
= read (fd1
, buf
, sizeof(buf
));
200 des_cfb64_encrypt (buf
, buf
, ret
, schedule
, iv
,
203 ret
= krb_net_write (fd2
, buf
, ret
);
212 * Copy data between fd1 and fd2, encrypting one way and decrypting
217 krb4_copy_encrypted (kx_context
*kc
,
220 krb4_kx_context
*c
= (krb4_kx_context
*)kc
->data
;
222 int num1
= 0, num2
= 0;
224 memcpy (iv1
, c
->key
, sizeof(iv1
));
225 memcpy (iv2
, c
->key
, sizeof(iv2
));
230 if (fd1
>= FD_SETSIZE
|| fd2
>= FD_SETSIZE
) {
231 warnx ("fd too large");
239 ret
= select (max(fd1
, fd2
)+1, &fdset
, NULL
, NULL
, NULL
);
240 if (ret
< 0 && errno
!= EINTR
) {
244 if (FD_ISSET(fd1
, &fdset
)) {
245 ret
= do_enccopy (fd1
, fd2
, DES_ENCRYPT
, &iv1
, c
->schedule
, &num1
);
249 if (FD_ISSET(fd2
, &fdset
)) {
250 ret
= do_enccopy (fd2
, fd1
, DES_DECRYPT
, &iv2
, c
->schedule
, &num2
);
258 * Return 0 if the user authenticated on `kc' is allowed to login as
263 krb4_userok (kx_context
*kc
, char *user
)
265 krb4_kx_context
*c
= (krb4_kx_context
*)kc
->data
;
268 tmp
= krb_unparse_name_long (c
->auth
.pname
,
271 kc
->user
= strdup (tmp
);
272 if (kc
->user
== NULL
)
276 return kuserok (&c
->auth
, user
);
280 * Create an instance of an krb4 context.
284 krb4_make_context (kx_context
*kc
)
286 kc
->authenticate
= krb4_authenticate
;
287 kc
->userok
= krb4_userok
;
288 kc
->read
= krb4_read
;
289 kc
->write
= krb4_write
;
290 kc
->copy_encrypted
= krb4_copy_encrypted
;
291 kc
->destroy
= krb4_destroy
;
293 kc
->data
= malloc(sizeof(krb4_kx_context
));
295 if (kc
->data
== NULL
)
300 * Receive authentication information on `sock' (first four bytes
305 recv_v4_auth (kx_context
*kc
, int sock
, u_char
*buf
)
309 char instance
[INST_SZ
+ 1];
310 char version
[KRB_SENDAUTH_VLEN
+ 1];
313 des_key_schedule schedule
;
315 if (kc
->thisaddr
->sa_family
!= AF_INET
)
318 if (memcmp (buf
, KRB_SENDAUTH_VERS
, 4) != 0)
320 if (net_read (sock
, buf
+ 4, KRB_SENDAUTH_VLEN
- 4) !=
321 KRB_SENDAUTH_VLEN
- 4) {
322 syslog (LOG_ERR
, "read: %m");
325 if (memcmp (buf
, KRB_SENDAUTH_VERS
, KRB_SENDAUTH_VLEN
) != 0) {
326 syslog (LOG_ERR
, "unrecognized auth protocol: %.8s", buf
);
330 k_getsockinst (sock
, instance
, sizeof(instance
));
331 status
= krb_recvauth (KOPT_IGNORE_PROTOCOL
| KOPT_DO_MUTUAL
,
336 (struct sockaddr_in
*)kc
->thataddr
,
337 (struct sockaddr_in
*)kc
->thisaddr
,
342 if (status
!= KSUCCESS
) {
343 syslog (LOG_ERR
, "krb_recvauth: %s", krb_get_err_text(status
));
346 if (strncmp (version
, KX_VERSION
, KRB_SENDAUTH_VLEN
) != 0) {
347 /* Try to be nice to old kx's */
348 if (strncmp (version
, KX_OLD_VERSION
, KRB_SENDAUTH_VLEN
) == 0) {
349 char *old_errmsg
= "\001Old version of kx. Please upgrade.";
352 syslog (LOG_ERR
, "Old version client (%s)", version
);
354 krb_net_read (sock
, user
, sizeof(user
));
355 krb_net_write (sock
, old_errmsg
, strlen(old_errmsg
) + 1);
358 syslog (LOG_ERR
, "bad version: %s", version
);
363 krb4_make_context (kc
);
364 c
= (krb4_kx_context
*)kc
->data
;
367 memcpy (c
->key
, &auth
.session
, sizeof(des_cblock
));
368 memcpy (&c
->schedule
, &schedule
, sizeof(schedule
));