Initial import from FreeBSD RELENG_4:
[dragonfly.git] / crypto / kerberosIV / lib / kclient / KClient.c
1 /*
2  * Copyright (c) 1995, 1996, 1997, 1998 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. 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.
20  * 
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
31  * SUCH DAMAGE.
32  */
33
34 /* KClient.c - KClient glue to krb4.dll
35  * Author: Jörgen Karlsson - d93-jka@nada.kth.se
36  * Date: June 1996
37  */
38
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 RCSID("$Id: KClient.c,v 1.14 1999/12/02 16:58:40 joda Exp $");
42 #endif
43
44 #ifdef WIN32    /* Visual C++ 4.0 (Windows95/NT) */
45 #include <Windows.h>
46 #endif /* WIN32 */
47
48 //#include <string.h>
49 #include <winsock.h>
50 #include "passwd_dlg.h"
51 #include "KClient.h"
52 #include "krb.h"
53
54 char guser[64];
55
56 void
57 msg(char *text)
58 {
59     HWND wnd = GetActiveWindow();
60     MessageBox(wnd, text, "KClient message", MB_OK|MB_APPLMODAL);
61 }
62  
63 BOOL
64 SendTicketForService(LPSTR service, LPSTR version, int fd)
65 {
66     KTEXT_ST ticket;
67     MSG_DAT mdat;
68     CREDENTIALS cred;
69     des_key_schedule schedule;
70     char name[SNAME_SZ], inst[INST_SZ], realm[REALM_SZ];
71     int ret;
72     static KClientSessionInfo foo;
73     KClientKey key;
74
75     kname_parse(name, inst, realm, service);
76     strlcpy(foo.realm, realm, sizeof(foo.realm));
77
78     if(KClientStatus(&foo) == KClientNotLoggedIn)
79         KClientLogin(&foo, &key);
80
81     ret = krb_sendauth (0, fd, &ticket,
82                         name, inst, realm, 17, &mdat,
83                         &cred, &schedule, NULL, NULL, version);
84     if(ret)
85         return FALSE;
86     return TRUE;
87 }
88
89 BOOL WINAPI
90 DllMain(HANDLE hInst, ULONG reason, LPVOID lpReserved)
91 {
92     WORD wVersionRequested;
93     WSADATA wsaData;
94     int err;
95
96     switch(reason){
97     case DLL_PROCESS_ATTACH:
98         wVersionRequested = MAKEWORD(1, 1);
99
100         err = WSAStartup(wVersionRequested, &wsaData);
101
102         if (err != 0)
103         {
104             /* Tell the user that we couldn't find a useable */
105             /* winsock.dll.     */
106             msg("Cannot find winsock.dll");
107             return FALSE;
108         }
109         break;
110     case DLL_PROCESS_DETACH:
111         WSACleanup();
112     }
113
114     return TRUE;
115 }
116
117 Kerr
118 KClientMessage(char *text, Kerr error)
119 {
120     msg(text);
121     return error;
122 }
123
124 /* KClientInitSession
125  * You need to call this routine before calling most other routines.
126  * It initializes a KClientSessionInfo structure.
127  * The local and remote addresses are for use in KClientEncrypt,
128  * KClientDecrypt, KClientMakeSendAuth and KClientVerifySendAuth.
129  * If you don't use any of these routines it's perfectly OK to do the following...
130  * err = KClientInitSession(session,0,0,0,0);
131  */
132 Kerr
133 KClientInitSession(KClientSessionInfo *session,
134                    unsigned long lAddr,
135                    unsigned short lPort,
136                    unsigned long fAddr,
137                    unsigned short fPort)
138 {
139     session->lAddr = lAddr;
140     session->lPort = lPort;
141     session->fAddr = fAddr;
142     session->fPort = fPort;
143     if(tf_get_pname(session->user) != KSUCCESS)
144         *(session->user) = '\0';
145     if(tf_get_pinst(session->inst) != KSUCCESS)
146         *(session->inst) = '\0';
147     krb_get_lrealm (session->realm, 1);
148     if(*(session->user))
149         strlcpy(guser, session->user, sizeof(guser));
150     else
151         *guser ='\0';
152     
153     return 0;
154 }
155
156
157 /* KClientGetTicketForService
158  * This routine gets an authenticator to be passed to a service.
159  * If the user isn't already logged in the user is prompted for a password.
160  */
161 Kerr
162 KClientGetTicketForService(KClientSessionInfo *session,
163                            char *service,
164                            void *buf,
165                            unsigned long *buflen)
166 {
167     CREDENTIALS c;
168     KClientKey k;
169     KTEXT_ST ticket;
170     char serv[255], inst[255], realm[255];
171     Kerr err;
172
173     //  KClientSetUserName(session->user);
174     err = kname_parse(serv,inst,realm,service);
175     if(*realm)
176         strlcpy(session->realm, realm, sizeof(session->realm));
177     else
178         strlcpy(realm, session->realm, sizeof(realm));
179     if(KClientStatus(session) == KClientNotLoggedIn)
180         if((err = KClientLogin(session, &k)) != KSUCCESS)
181             return err;
182
183     if((err = krb_mk_req(&ticket, serv, inst, realm, 0)) != KSUCCESS)
184         return KClientMessage(KClientErrorText(err,0),err);
185     if((err = krb_get_cred(serv, inst, realm, &c)) != KSUCCESS)
186         return KClientMessage(KClientErrorText(err,0),err);
187
188     if(*buflen >= ticket.length)
189     {
190         *buflen = ticket.length + sizeof(unsigned long);
191         CopyMemory(buf, &ticket, *buflen);
192         CopyMemory(session->key, c.session, sizeof(session->key));
193     }
194     else
195         err = -1;
196     return err;
197 }
198
199
200 /* KClientLogin
201  * This routine "logs in" by getting a ticket granting ticket from kerberos.
202  * It returns the user's private key which can be used to automate login at
203  * a later time with KClientKeyLogin.
204  */
205
206 Kerr
207 KClientLogin(KClientSessionInfo *session,
208              KClientKey *privateKey)
209 {
210     CREDENTIALS c;
211     Kerr err;
212     char passwd[100];
213         
214     if((err = pwd_dialog(guser, passwd)))
215         return err;
216     if(KClientStatus(session) == KClientNotLoggedIn)
217     {
218
219         if((err = krb_get_pw_in_tkt(guser, session->inst, session->realm,
220                                     "krbtgt", session->realm,
221                                     DEFAULT_TKT_LIFE, passwd)) != KSUCCESS)
222             return KClientMessage(KClientErrorText(err,0),err);
223     }
224     if((err = krb_get_cred("krbtgt", session->realm,
225                            session->realm, &c)) == KSUCCESS)
226         CopyMemory(privateKey, c.session, sizeof(*privateKey));
227     return err;
228 }
229
230
231 /* KClientPasswordLogin
232  * This routine is similiar to KClientLogin but instead of prompting the user
233  * for a password it uses the password supplied to establish login.
234  */
235 Kerr
236 KClientPasswordLogin(KClientSessionInfo *session,
237                      char *password,
238                      KClientKey *privateKey)
239 {
240     return krb_get_pw_in_tkt(guser, session->inst, session->realm,
241                              "krbtgt",
242                              session->realm,
243                              DEFAULT_TKT_LIFE,
244                              password);
245 }
246
247
248 static key_proc_t
249 key_proc(void *arg)
250 {
251         return arg;
252 }
253
254 /* KClientKeyLogin
255  * This routine is similiar to KClientLogin but instead of prompting the user
256  * for a password it uses the private key supplied to establish login.
257  */
258 Kerr
259 KClientKeyLogin(KClientSessionInfo *session,
260                 KClientKey *privateKey)
261 {
262     return krb_get_in_tkt(guser, session->inst, session->realm,
263                           "krbtgt",
264                           session->realm,
265                           DEFAULT_TKT_LIFE,
266                           key_proc,
267                           0,
268                           privateKey);
269 }
270
271 /* KClientLogout
272  * This routine destroys all credentials stored in the credential cache
273  * effectively logging the user out.
274  */
275 Kerr
276 KClientLogout(void)
277 {
278     return 0;
279 }
280
281
282 /* KClientStatus
283  * This routine returns the user's login status which can be
284  * KClientLoggedIn or KClientNotLoggedIn.
285  */
286 short
287 KClientStatus(KClientSessionInfo *session)
288 {
289     CREDENTIALS c;
290     if(krb_get_cred("krbtgt",
291                     session->realm,
292                     session->realm, &c) == KSUCCESS)
293         return KClientLoggedIn;
294     else
295         return KClientNotLoggedIn;
296 }
297
298
299 /* KClientGetUserName
300  * This routine returns the name the user supplied in the login dialog.
301  * No name is returned if the user is not logged in.
302  */
303 Kerr
304 KClientGetUserName(char *user)
305 {
306     strcpy(user, guser);
307     return 0;
308 }
309
310
311 /* KClientSetUserName
312  * This routine sets the name that will come up in the login dialog
313  * the next time the user is prompted for a password.
314  */
315 Kerr
316 KClientSetUserName(char *user)
317 {
318     strlcpy(guser, user, sizeof(guser));
319     return 0;
320 }
321
322
323 /* KClientCacheInitialTicket
324  * This routine is used to obtain a ticket for the password changing service.
325  */
326 Kerr
327 KClientCacheInitialTicket(KClientSessionInfo *session,
328                           char *service)
329 {
330     return 0;
331 }
332
333
334 /* KClientGetSessionKey
335  * This routine can be used to obtain the session key which is stored
336  * in the KClientSessionInfo record. The session key has no usefullness
337  * with any KClient calls but it can be used to with the MIT kerberos API.
338  */
339 Kerr
340 KClientGetSessionKey(KClientSessionInfo *session,
341                      KClientKey *sessionKey)
342 {
343     CopyMemory(sessionKey, session->key, sizeof(*sessionKey));
344     return 0;
345 }
346
347
348 /* KClientMakeSendAuth
349  * This routine is used to create an authenticator that is the same as those
350  * created by the kerberos routine SendAuth.
351  */
352 Kerr
353 KClientMakeSendAuth(KClientSessionInfo *session,
354                     char *service,
355                     void *buf,
356                     unsigned long *buflen,
357                     long checksum,
358                     char *applicationVersion)
359 {
360     return 0;
361 }
362
363
364 /* KClientVerifySendAuth
365  * This routine is used to verify a response made by a server doing RecvAuth.
366  * The two routines KClientMakeSendAuth and KClientVerifySendAuth together
367  * provide the functionality of SendAuth minus the transmission of authenticators
368  * between client->server->client.
369  */
370 Kerr
371 KClientVerifySendAuth(KClientSessionInfo *session,
372                       void *buf,
373                       unsigned long *buflen)
374 {
375     return 0;
376 }
377
378
379 /* KClientEncrypt
380  * This routine encrypts a series a bytes for transmission to the remote host.
381  * For this to work properly you must be logged in and you must have specified
382  * the remote and local addresses in KClientInitSession. The unencrypted
383  * message pointed to by buf and of length buflen is returned encrypted
384  * in encryptBuf of length encryptLength.
385  * The encrypted buffer must be at least 26 bytes longer the buf.
386  */
387 Kerr
388 KClientEncrypt(KClientSessionInfo *session,
389                void *buf,
390                unsigned long buflen,
391                void *encryptBuf,
392                unsigned long *encryptLength)
393 {
394     int num = 64;
395     des_cfb64_encrypt(buf, encryptBuf, buflen,
396                       (struct des_ks_struct*) session->key,
397                       0, &num, 1);
398     return 0;
399 }
400
401
402 /* KClientDecrypt
403  * This routine decrypts a series of bytes received from the remote host.
404
405  * NOTE: this routine will not reverse a KClientEncrypt call.
406  * It can only decrypt messages sent from the remote host.
407
408  * Instead of copying the decrypted message to an out buffer,
409  * the message is decrypted in place and you are returned
410  * an offset into the buffer where the decrypted message begins.
411  */
412 Kerr
413 KClientDecrypt(KClientSessionInfo *session,
414                void *buf,
415                unsigned long buflen,
416                unsigned long *decryptOffset,
417                unsigned long *decryptLength)
418 {
419     int num;
420     des_cfb64_encrypt(buf, buf, buflen,
421                       (struct des_ks_struct*)session->key, 0, &num, 0);
422     *decryptOffset = 0;
423     *decryptLength = buflen;
424     return 0;
425 }
426
427
428 /* KClientErrorText
429  * This routine returns a text description of errors returned by any of
430  * the calls in this library.
431  */
432 char *
433 KClientErrorText(Kerr err,
434                  char *text)
435 {
436     char *t = krb_get_err_text(err);
437     if(text)
438         strcpy(text, t);
439     return t;
440 }