Kerberos‚Ö£ part of the TCP_NODELAY patch
[alioth/cvs.git] / src / kerberos4-client.c
1 /* CVS Kerberos4 client stuff.
2
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.  */
12
13 #include <config.h>
14
15 #include "cvs.h"
16
17 #include "buffer.h"
18 #include "socket-client.h"
19
20 #include <netinet/tcp.h>
21
22 #   include <krb.h>
23
24 extern char *krb_realmofhost ();
25 #   ifndef HAVE_KRB_GET_ERR_TEXT
26 #     define krb_get_err_text(status) krb_err_txt[status]
27 #   endif /* HAVE_KRB_GET_ERR_TEXT */
28
29 /* Information we need if we are going to use Kerberos encryption.  */
30 static C_Block kblock;
31 static Key_schedule sched;
32
33
34 /* This function has not been changed to deal with NO_SOCKET_TO_FD
35    (i.e., systems on which sockets cannot be converted to file
36    descriptors).  The first person to try building a kerberos client
37    on such a system (OS/2, Windows 95, and maybe others) will have to
38    take care of this.  */
39 void
40 start_kerberos4_server (cvsroot_t *root, struct buffer **to_server_p,
41                         struct buffer **from_server_p)
42 {
43     int s;
44     int port;
45     struct hostent *hp;
46     struct sockaddr_in sin;
47     char *hname;
48
49     s = socket (AF_INET, SOCK_STREAM, 0);
50     if (s < 0)
51         error (1, 0, "cannot create socket: %s", SOCK_STRERROR (SOCK_ERRNO));
52
53 #ifdef TCP_NODELAY
54     /* Avoid latency due to Nagle algorithm.  */
55     {
56         int on = 1;
57
58         if (setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof on) < 0)
59             error (0, errno, "warning: cannot set TCP_NODELAY on socket");
60     }
61 #endif
62
63     port = get_cvs_port_number (root);
64
65     hp = init_sockaddr (&sin, root->hostname, port);
66
67     hname = xstrdup (hp->h_name);
68   
69     TRACE (TRACE_FUNCTION, "Connecting to %s(%s):%d",
70            root->hostname,
71            inet_ntoa (sin.sin_addr),
72            port);
73
74     if (connect (s, (struct sockaddr *) &sin, sizeof sin) < 0)
75         error (1, 0, "connect to %s(%s):%d failed: %s",
76                root->hostname,
77                inet_ntoa (sin.sin_addr),
78                port, SOCK_STRERROR (SOCK_ERRNO));
79
80     {
81         const char *realm;
82         struct sockaddr_in laddr;
83         int laddrlen;
84         KTEXT_ST ticket;
85         MSG_DAT msg_data;
86         CREDENTIALS cred;
87         int status;
88
89         realm = krb_realmofhost (hname);
90
91         laddrlen = sizeof (laddr);
92         if (getsockname (s, (struct sockaddr *) &laddr, &laddrlen) < 0)
93             error (1, 0, "getsockname failed: %s", SOCK_STRERROR (SOCK_ERRNO));
94
95         /* We don't care about the checksum, and pass it as zero.  */
96         status = krb_sendauth (KOPT_DO_MUTUAL, s, &ticket, "rcmd",
97                                hname, realm, (unsigned long) 0, &msg_data,
98                                &cred, sched, &laddr, &sin, "KCVSV1.0");
99         if (status != KSUCCESS)
100             error (1, 0, "kerberos authentication failed: %s",
101                    krb_get_err_text (status));
102         memcpy (kblock, cred.session, sizeof (C_Block));
103     }
104
105     close_on_exec (s);
106
107     free (hname);
108
109     /* Give caller the values it wants. */
110     make_bufs_from_fds (s, s, 0, root, to_server_p, from_server_p, 1);
111 }
112
113 void
114 initialize_kerberos4_encryption_buffers( struct buffer **to_server_p,
115                                          struct buffer **from_server_p )
116 {
117   *to_server_p = krb_encrypt_buffer_initialize (*to_server_p, 0, sched,
118                                                 kblock, NULL);
119   *from_server_p = krb_encrypt_buffer_initialize (*from_server_p, 1,
120                                                   sched, kblock, NULL);
121 }
122