2 * Copyright (c) 1995 - 2000 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("$Id: krb4.c,v 1.11.2.1 2004/02/18 19:22:30 lha Exp $");
40 struct krb4_kx_context
{
42 des_key_schedule schedule
;
46 typedef struct krb4_kx_context krb4_kx_context
;
49 * Destroy the krb4 context in `c'.
53 krb4_destroy (kx_context
*c
)
55 memset (c
->data
, 0, sizeof(krb4_kx_context
));
60 * Read the authentication information from `s' and return 0 if
65 krb4_authenticate (kx_context
*kc
, int s
)
71 krb4_kx_context
*c
= (krb4_kx_context
*)kc
->data
;
72 const char *host
= kc
->host
;
74 if (kc
->thisaddr
->sa_family
!= AF_INET
) {
75 warnx ("%s: used Kerberos v4 authentiocation on non-IP4 address", host
);
79 #ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM
80 if (krb_get_config_bool("nat_in_use")) {
81 struct in_addr natAddr
;
83 if (krb_get_our_ip_for_realm(krb_realmofhost(kc
->host
),
85 || krb_get_our_ip_for_realm (NULL
, &natAddr
) == KSUCCESS
)
86 ((struct sockaddr_in
*)kc
->thisaddr
)->sin_addr
= natAddr
;
90 status
= krb_sendauth (KOPT_DO_MUTUAL
, s
, &text
, "rcmd",
91 (char *)host
, krb_realmofhost (host
),
92 getpid(), &msg
, &cred
, c
->schedule
,
93 (struct sockaddr_in
*)kc
->thisaddr
,
94 (struct sockaddr_in
*)kc
->thataddr
, KX_VERSION
);
95 if (status
!= KSUCCESS
) {
96 warnx ("%s: %s", host
, krb_get_err_text(status
));
99 memcpy (c
->key
, cred
.session
, sizeof(des_cblock
));
104 * Read a krb4 priv packet from `fd' into `buf' (of size `len').
105 * Return the number of bytes read or 0 on EOF or -1 on error.
109 krb4_read (kx_context
*kc
,
110 int fd
, void *buf
, size_t len
)
112 unsigned char tmp
[4];
116 krb4_kx_context
*c
= (krb4_kx_context
*)kc
->data
;
119 ret
= krb_net_read (fd
, tmp
, 4);
124 l
= (tmp
[0] << 24) | (tmp
[1] << 16) | (tmp
[2] << 8) | tmp
[3];
127 if (krb_net_read (fd
, buf
, l
) != l
)
129 status
= krb_rd_priv (buf
, l
, c
->schedule
, &c
->key
,
130 (struct sockaddr_in
*)kc
->thataddr
,
131 (struct sockaddr_in
*)kc
->thisaddr
, &msg
);
132 if (status
!= RD_AP_OK
) {
133 warnx ("krb4_read: %s", krb_get_err_text(status
));
136 memmove (buf
, msg
.app_data
, msg
.app_length
);
137 return msg
.app_length
;
141 * Write a krb4 priv packet on `fd' with the data in `buf, len'.
142 * Return len or -1 on error
146 krb4_write(kx_context
*kc
,
147 int fd
, const void *buf
, size_t len
)
150 krb4_kx_context
*c
= (krb4_kx_context
*)kc
->data
;
152 unsigned char tmp
[4];
154 outbuf
= malloc (len
+ 30);
157 outlen
= krb_mk_priv ((void *)buf
, outbuf
, len
, c
->schedule
, &c
->key
,
158 (struct sockaddr_in
*)kc
->thisaddr
,
159 (struct sockaddr_in
*)kc
->thataddr
);
164 tmp
[0] = (outlen
>> 24) & 0xFF;
165 tmp
[1] = (outlen
>> 16) & 0xFF;
166 tmp
[2] = (outlen
>> 8) & 0xFF;
167 tmp
[3] = (outlen
>> 0) & 0xFF;
169 if (krb_net_write (fd
, tmp
, 4) != 4 ||
170 krb_net_write (fd
, outbuf
, outlen
) != outlen
) {
179 * Copy data from `fd1' to `fd2', {en,de}crypting with cfb64
180 * with `mode' and state stored in `iv', `schedule', and `num'.
181 * Return -1 if error, 0 if eof, else 1
185 do_enccopy (int fd1
, int fd2
, int mode
, des_cblock
*iv
,
186 des_key_schedule schedule
, int *num
)
191 ret
= read (fd1
, buf
, sizeof(buf
));
199 des_cfb64_encrypt (buf
, buf
, ret
, schedule
, iv
,
202 ret
= krb_net_write (fd2
, buf
, ret
);
211 * Copy data between fd1 and fd2, encrypting one way and decrypting
216 krb4_copy_encrypted (kx_context
*kc
,
219 krb4_kx_context
*c
= (krb4_kx_context
*)kc
->data
;
221 int num1
= 0, num2
= 0;
223 memcpy (iv1
, c
->key
, sizeof(iv1
));
224 memcpy (iv2
, c
->key
, sizeof(iv2
));
229 if (fd1
>= FD_SETSIZE
|| fd2
>= FD_SETSIZE
) {
230 warnx ("fd too large");
238 ret
= select (max(fd1
, fd2
)+1, &fdset
, NULL
, NULL
, NULL
);
239 if (ret
< 0 && errno
!= EINTR
) {
243 if (FD_ISSET(fd1
, &fdset
)) {
244 ret
= do_enccopy (fd1
, fd2
, DES_ENCRYPT
, &iv1
, c
->schedule
, &num1
);
248 if (FD_ISSET(fd2
, &fdset
)) {
249 ret
= do_enccopy (fd2
, fd1
, DES_DECRYPT
, &iv2
, c
->schedule
, &num2
);
257 * Return 0 if the user authenticated on `kc' is allowed to login as
262 krb4_userok (kx_context
*kc
, char *user
)
264 krb4_kx_context
*c
= (krb4_kx_context
*)kc
->data
;
267 tmp
= krb_unparse_name_long (c
->auth
.pname
,
270 kc
->user
= strdup (tmp
);
271 if (kc
->user
== NULL
)
275 return kuserok (&c
->auth
, user
);
279 * Create an instance of an krb4 context.
283 krb4_make_context (kx_context
*kc
)
285 kc
->authenticate
= krb4_authenticate
;
286 kc
->userok
= krb4_userok
;
287 kc
->read
= krb4_read
;
288 kc
->write
= krb4_write
;
289 kc
->copy_encrypted
= krb4_copy_encrypted
;
290 kc
->destroy
= krb4_destroy
;
292 kc
->data
= malloc(sizeof(krb4_kx_context
));
294 if (kc
->data
== NULL
)
299 * Receive authentication information on `sock' (first four bytes
304 recv_v4_auth (kx_context
*kc
, int sock
, u_char
*buf
)
308 char instance
[INST_SZ
+ 1];
309 char version
[KRB_SENDAUTH_VLEN
+ 1];
312 des_key_schedule schedule
;
314 if (kc
->thisaddr
->sa_family
!= AF_INET
)
317 if (memcmp (buf
, KRB_SENDAUTH_VERS
, 4) != 0)
319 if (net_read (sock
, buf
+ 4, KRB_SENDAUTH_VLEN
- 4) !=
320 KRB_SENDAUTH_VLEN
- 4) {
321 syslog (LOG_ERR
, "read: %m");
324 if (memcmp (buf
, KRB_SENDAUTH_VERS
, KRB_SENDAUTH_VLEN
) != 0) {
325 syslog (LOG_ERR
, "unrecognized auth protocol: %.8s", buf
);
329 k_getsockinst (sock
, instance
, sizeof(instance
));
330 status
= krb_recvauth (KOPT_IGNORE_PROTOCOL
| KOPT_DO_MUTUAL
,
335 (struct sockaddr_in
*)kc
->thataddr
,
336 (struct sockaddr_in
*)kc
->thisaddr
,
341 if (status
!= KSUCCESS
) {
342 syslog (LOG_ERR
, "krb_recvauth: %s", krb_get_err_text(status
));
345 if (strncmp (version
, KX_VERSION
, KRB_SENDAUTH_VLEN
) != 0) {
346 /* Try to be nice to old kx's */
347 if (strncmp (version
, KX_OLD_VERSION
, KRB_SENDAUTH_VLEN
) == 0) {
348 char *old_errmsg
= "\001Old version of kx. Please upgrade.";
351 syslog (LOG_ERR
, "Old version client (%s)", version
);
353 krb_net_read (sock
, user
, sizeof(user
));
354 krb_net_write (sock
, old_errmsg
, strlen(old_errmsg
) + 1);
357 syslog (LOG_ERR
, "bad version: %s", version
);
362 krb4_make_context (kc
);
363 c
= (krb4_kx_context
*)kc
->data
;
366 memcpy (c
->key
, &auth
.session
, sizeof(des_cblock
));
367 memcpy (c
->schedule
, schedule
, sizeof(schedule
));