1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
|
/*
* lib/krb425/sendauth.c
*
* Copyright 1987,1988,1990 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
* require a specific license from the United States Government.
* It is the responsibility of any person or organization contemplating
* export to obtain such a license before exporting.
*
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
* distribute this software and its documentation for any purpose and
* without fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright notice and
* this permission notice appear in supporting documentation, and that
* the name of M.I.T. not be used in advertising or publicity pertaining
* to distribution of the software without specific, written prior
* permission. M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
*
*
*/
#include "krb425.h"
#include <sys/types.h>
#include <syslog.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#define KRB_SENDAUTH_VERS "AUTHV0.1" /* MUST be KRB_SENDAUTH_VLEN chars */
/*
* If the protocol changes, you will need to change the version string
* and make appropriate changes in krb_recvauth.c
*/
extern int errno;
extern char *krb_get_phost();
/*
* This file contains two routines: krb_sendauth() and krb_sendsrv().
*
* krb_sendauth() transmits a ticket over a file descriptor for a
* desired service, instance, and realm, doing mutual authentication
* with the server if desired.
*
* krb_sendsvc() sends a service name to a remote knetd server.
*/
/*
* The first argument to krb_sendauth() contains a bitfield of
* options (the options are defined in "krb.h"):
*
* KOPT_DONT_CANON Don't canonicalize instance as a hostname.
* (If this option is not chosen, krb_get_phost()
* is called to canonicalize it.)
*
* KOPT_DONT_MK_REQ Don't request server ticket from Kerberos.
* A ticket must be supplied in the "ticket"
* argument.
* (If this option is not chosen, and there
* is no ticket for the given server in the
* ticket cache, one will be fetched using
* krb_mk_req() and returned in "ticket".)
*
* KOPT_DO_MUTUAL Do mutual authentication, requiring that the
* receiving server return the checksum+1 encrypted
* in the session key. The mutual authentication
* is done using krb_mk_priv() on the other side
* (see "recvauth.c") and krb_rd_priv() on this
* side.
*
* The "fd" argument is a file descriptor to write to the remote
* server on. The "ticket" argument is used to store the new ticket
* from the krb_mk_req() call. If the KOPT_DONT_MK_REQ options is
* chosen, the ticket must be supplied in the "ticket" argument.
* The "service", "inst", and "realm" arguments identify the ticket.
* If "realm" is null, the local realm is used.
*
* The following arguments are only needed if the KOPT_DO_MUTUAL option
* is chosen:
*
* The "checksum" argument is a number that the server will add 1 to
* to authenticate itself back to the client; the "msg_data" argument
* holds the returned mutual-authentication message from the server
* (i.e., the checksum+1); the "cred" structure is used to hold the
* session key of the server, extracted from the ticket file, for use
* in decrypting the mutual authentication message from the server;
* and "schedule" holds the key schedule for that decryption. The
* the local and server addresses are given in "laddr" and "faddr".
*
* The application protocol version number (of up to KRB_SENDAUTH_VLEN
* characters) is passed in "version".
*
* If all goes well, KSUCCESS is returned, otherwise some error code.
*
* The format of the message sent to the server is:
*
* Size Variable Field
* ---- -------- -----
*
* KRB_SENDAUTH_VLEN KRB_SENDAUTH_VER sendauth protocol
* bytes version number
*
* KRB_SENDAUTH_VLEN version application protocol
* bytes version number
*
* 4 bytes ticket->length length of ticket
*
* ticket->length ticket->dat ticket itself
*/
/*
* XXX: Note that krb_rd_priv() is coded in such a way that
* "msg_data->app_data" will be pointing into "priv_buf", which
* will disappear when krb_sendauth() returns.
*/
int
krb_sendauth(options, fd, ticket, service, inst, realm, checksum,
msg_data, cred, schedule, laddr, faddr, version)
long options; /* bit-pattern of options */
int fd; /* file descriptor to write onto */
KTEXT ticket; /* where to put ticket (return); or
* supplied in case of KOPT_DONT_MK_REQ */
char *service, *inst, *realm; /* service name, instance, realm */
u_long checksum; /* checksum to include in request */
MSG_DAT *msg_data; /* mutual auth MSG_DAT (return) */
CREDENTIALS *cred; /* credentials (return) */
Key_schedule schedule; /* key schedule (return) */
struct sockaddr_in *laddr; /* local address */
struct sockaddr_in *faddr; /* address of foreign host on fd */
char *version; /* version string */
{
int rem, i, cc;
char srv_inst[INST_SZ];
char krb_realm[REALM_SZ];
char buf[BUFSIZ];
long tkt_len;
u_char priv_buf[1024];
u_long cksum;
rem=KSUCCESS;
/* get current realm if not passed in */
if (!realm) {
rem = krb_get_lrealm(krb_realm,1);
if (rem != KSUCCESS)
return(rem);
realm = krb_realm;
}
/* copy instance into local storage, canonicalizing if desired */
if (options & KOPT_DONT_CANON)
(void) strncpy(srv_inst, inst, INST_SZ);
else
(void) strncpy(srv_inst, krb_get_phost(inst), INST_SZ);
/* get the ticket if desired */
if (!(options & KOPT_DONT_MK_REQ)) {
rem = krb_mk_req(ticket, service, srv_inst, realm, checksum);
if (rem != KSUCCESS)
return(rem);
}
/* if mutual auth, get credentials so we have service session
keys for decryption below */
if (options & KOPT_DO_MUTUAL)
if (cc = krb_get_cred(service, srv_inst, realm, cred))
return(cc);
/* zero the buffer */
(void) memset(buf, 0, BUFSIZ);
/* insert version strings */
(void) strncpy(buf, KRB_SENDAUTH_VERS, KRB_SENDAUTH_VLEN);
(void) strncpy(buf+KRB_SENDAUTH_VLEN, version, KRB_SENDAUTH_VLEN);
/* increment past vers strings */
i = 2*KRB_SENDAUTH_VLEN;
/* put ticket length into buffer */
tkt_len = htonl((unsigned long) ticket->length);
(void) memcpy(buf+i, (char *) &tkt_len, sizeof(tkt_len));
i += sizeof(tkt_len);
/* put ticket into buffer */
(void) memcpy(buf+i, (char *) ticket->dat, ticket->length);
i += ticket->length;
/* write the request to the server */
if ((cc = krb_net_write(fd, buf, i)) != i)
return(cc);
/* mutual authentication, if desired */
if (options & KOPT_DO_MUTUAL) {
int r;
/* get the length of the reply */
if ((r = krb_net_read(fd, (char *) &tkt_len, sizeof(tkt_len))) !=
sizeof(tkt_len)) {
#ifdef EBUG
EPRINT "krb_net_read(%d, tkt_len, %d) returns %d\n",
fd, sizeof(tkt_len), r);
ERROR(errno);
#endif
return(errno);
}
tkt_len = ntohl((unsigned long)tkt_len);
/* if the length is negative, the server failed to recognize us. */
if ((tkt_len < 0) || (tkt_len > sizeof(priv_buf)))
return(KFAILURE); /* XXX */
/* read the reply... */
if (krb_net_read(fd, (char *)priv_buf, (int) tkt_len) != (int) tkt_len)
return(errno);
/* ...and decrypt it */
#ifndef NOENCRYPTION
key_sched(cred->session, schedule);
#endif /* !NOENCRYPTION */
if (cc = krb_rd_priv(priv_buf,(unsigned long) tkt_len, schedule,
cred->session, faddr, laddr, msg_data))
return(cc);
/* fetch the (modified) checksum */
(void) memcpy((char *)&cksum, (char *)msg_data->app_data,
sizeof(cksum));
cksum = ntohl(cksum);
/* if it doesn't match, fail */
if (cksum != checksum + 1)
return(KFAILURE); /* XXX */
}
return(KSUCCESS);
}
#ifdef ATHENA_COMPAT
/*
* krb_sendsvc
*/
int
krb_sendsvc(fd, service)
int fd;
char *service;
{
/* write the service name length and then the service name to
the fd */
long serv_length;
int cc;
serv_length = htonl((unsigned long)strlen(service));
if ((cc = krb_net_write(fd, (char *) &serv_length,
sizeof(serv_length)))
!= sizeof(serv_length))
return(cc);
if ((cc = krb_net_write(fd, service, strlen(service)))
!= strlen(service))
return(cc);
return(KSUCCESS);
}
#endif /* ATHENA_COMPAT */
|