Initial import from FreeBSD RELENG_4:
[games.git] / crypto / kerberosIV / slave / kpropd.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 #include "slav_locl.h"
35
36 #include "kprop.h"
37
38 RCSID("$Id: kpropd.c,v 2.32 1999/12/02 16:58:56 joda Exp $");
39
40 #ifndef SBINDIR
41 #define SBINDIR "/usr/athena/sbin"
42 #endif
43
44 struct sockaddr_in master, slave;
45
46 char *database = DBM_FILE;
47
48 char *lockfile = DB_DIR "/slave_propagation";
49
50 char *logfile = K_LOGFIL;
51
52 char *kdb_util = SBINDIR "/kdb_util";
53
54 char *kdb_util_command = "load";
55
56 char *srvtab = "";
57
58 char realm[REALM_SZ];
59
60 static
61 int
62 copy_data(int from, int to, des_cblock *session, des_key_schedule schedule)
63 {
64     unsigned char tmp[4];
65     char buf[KPROP_BUFSIZ + 26];
66     u_int32_t length;
67     int n;
68     
69     int kerr;
70     MSG_DAT m;
71
72     while(1){
73         n = krb_net_read(from, tmp, 4);
74         if(n == 0)
75             break;
76         if(n < 0){
77             klog(L_KRB_PERR, "krb_net_read: %s", strerror(errno));
78             return -1;
79         }
80         if(n != 4){
81             klog(L_KRB_PERR, "Premature end of data");
82             return -1;
83         }
84         length = (tmp[0] << 24) | (tmp[1] << 16) | (tmp[2] << 8) | tmp[3];
85         if(length > sizeof(buf)){
86             klog(L_KRB_PERR, "Giant packet received: %d", length);
87             return -1;
88         }
89         if(krb_net_read(from, buf, length) != length){
90             klog(L_KRB_PERR, "Premature end of data");
91             return -1;
92         }
93         kerr = krb_rd_priv (buf, length, schedule, session,
94                             &master, &slave, &m);
95         if(kerr != KSUCCESS){
96             klog(L_KRB_PERR, "Kerberos error: %s", krb_get_err_text(kerr));
97             return -1;
98         }
99         write(to, m.app_data, m.app_length);
100     }
101     return 0;
102 }
103
104
105 static
106 int
107 kprop(int s)
108 {
109     char buf[128];
110     int n;
111     KTEXT_ST ticket;
112     AUTH_DAT ad;
113     char sinst[INST_SZ];
114     des_key_schedule schedule;
115     int mode;
116     int kerr;
117     int lock;
118     
119     n = sizeof(master);
120     if(getpeername(s, (struct sockaddr*)&master, &n) < 0){
121         klog(L_KRB_PERR, "getpeername: %s", strerror(errno));
122         return 1;
123     }
124     
125     n = sizeof(slave);
126     if(getsockname(s, (struct sockaddr*)&slave, &n) < 0){
127         klog(L_KRB_PERR, "getsockname: %s", strerror(errno));
128         return 1;
129     }
130
131     klog(L_KRB_PERR, "Connection from %s", inet_ntoa(master.sin_addr));
132
133     n = krb_net_read(s, buf, KPROP_PROT_VERSION_LEN + 2);
134     if(n < KPROP_PROT_VERSION_LEN + 2){
135         klog(L_KRB_PERR, "Premature end of data");
136         return 1;
137     }
138     if(memcmp(buf, KPROP_PROT_VERSION, KPROP_PROT_VERSION_LEN) != 0){
139         klog(L_KRB_PERR, "Bad protocol version string received");
140         return 1;
141     }
142     mode = (buf[n-2] << 8) | buf[n-1];
143     if(mode != KPROP_TRANSFER_PRIVATE){
144         klog(L_KRB_PERR, "Bad transfer mode received: %d", mode);
145         return 1;
146     }
147     k_getsockinst(s, sinst, sizeof(sinst));
148     kerr = krb_recvauth(KOPT_DO_MUTUAL, s, &ticket,
149                         KPROP_SERVICE_NAME, sinst,
150                         &master, &slave,
151                         &ad, srvtab, schedule, 
152                         buf);
153     if(kerr != KSUCCESS){
154         klog(L_KRB_PERR, "Kerberos error: %s", krb_get_err_text(kerr));
155         return 1;
156     }
157
158     if(strcmp(ad.pname, KPROP_SERVICE_NAME) ||
159 #if 0
160        strcmp(ad.pinst, /* XXX remote host */) ||
161 #else
162        strcmp(ad.pinst, KRB_MASTER) ||
163 #endif
164        strcmp(ad.prealm, realm)){
165         klog(L_KRB_PERR, "Connection from unauthorized client: %s", 
166              krb_unparse_name_long(ad.pname, ad.pinst, ad.prealm));
167         return 1;
168     }
169
170     des_set_key(&ad.session, schedule);
171     
172     lock = open(lockfile, O_WRONLY|O_CREAT, 0600);
173     if(lock < 0){
174         klog(L_KRB_PERR, "Failed to open file: %s", strerror(errno));
175         return 1;
176     }
177     if(flock(lock, LOCK_EX | LOCK_NB)){
178         close(lock);
179         klog(L_KRB_PERR, "Failed to lock file: %s", strerror(errno));
180         return 1;
181     }
182     
183     if(ftruncate(lock, 0) < 0){
184         close(lock);
185         klog(L_KRB_PERR, "Failed to lock file: %s", strerror(errno));
186         return 1;
187     }
188
189     if(copy_data(s, lock, &ad.session, schedule)){
190         close(lock);
191         return 1;
192     }
193     close(lock);
194     
195     if(simple_execlp(kdb_util, "kdb_util", kdb_util_command, 
196                      lockfile, database, NULL) != 0) {
197         klog(L_KRB_PERR, "*** Propagation failed ***");
198         return 1;
199     }else{
200         klog(L_KRB_PERR, "Propagation finished successfully");
201         return 0;
202     }
203 }
204
205 static int
206 doit(void)
207 {
208     return kprop(0);
209 }
210
211 static int
212 doit_interactive(void)
213 {
214     struct sockaddr_in sa;
215     int salen;
216     int s, s2;
217     int ret;
218
219     s = socket(AF_INET, SOCK_STREAM, 0);
220     if(s < 0){
221       klog(L_KRB_PERR, "socket: %s", strerror(errno));
222       return 1;
223     }
224     memset(&sa, 0, sizeof(sa));
225     sa.sin_family = AF_INET;
226     sa.sin_port = k_getportbyname ("krb_prop", "tcp", htons(KPROP_PORT));
227     ret = bind(s, (struct sockaddr*)&sa, sizeof(sa));
228     if (ret < 0) {
229       klog(L_KRB_PERR, "bind: %s", strerror(errno));
230       return 1;
231     }
232     ret = listen(s, SOMAXCONN);
233     if (ret < 0) {
234       klog(L_KRB_PERR, "listen: %s", strerror(errno));
235       return 1;
236     }
237     for(;;) {
238       salen = sizeof(sa);
239       s2 = accept(s, (struct sockaddr*)&sa, &salen);
240       switch(fork()){
241       case -1:
242         klog(L_KRB_PERR, "fork: %s", strerror(errno));
243         return 1;
244       case 0:
245         close(s);
246         kprop(s2);
247         return 1;
248       default: {
249           int status;
250           close(s2);
251           wait(&status);
252         }
253       }
254     }
255 }
256
257 static void
258 usage (void)
259 {
260      fprintf (stderr, 
261               "Usage: kpropd [-i] [-d database] [-l log] [-m] [-[p|P] program]"
262               " [-r realm] [-s srvtab]\n");
263      exit (1);
264 }
265
266 int
267 main(int argc, char **argv)
268 {
269     int opt;
270     int interactive = 0;
271
272     krb_get_lrealm(realm, 1);
273     
274     while((opt = getopt(argc, argv, ":d:l:mp:P:r:s:i")) >= 0){
275         switch(opt){
276         case 'd':
277             database = optarg;
278             break;
279         case 'l':
280             logfile = optarg;
281             break;
282         case 'm':
283             kdb_util_command = "merge";
284             break;
285         case 'p':
286         case 'P':
287             kdb_util = optarg;
288             break;
289         case 'r':
290             strlcpy(realm, optarg, REALM_SZ);
291             break;
292         case 's':
293             srvtab = optarg;
294             break;
295         case 'i':
296             interactive = 1;
297             break;
298         default:
299             klog(L_KRB_PERR, "Bad option: -%c", optopt);
300             usage ();
301             exit(1);
302         }
303     }
304     if (!interactive) {
305       /* Use logfile as stderr so we don't lose error messages. */
306       int fd = open(logfile, O_CREAT | O_WRONLY | O_APPEND, 0600);
307       if (fd == -1)
308         klog(L_KRB_PERR, "Can't open logfile %s: %s", logfile,strerror(errno));
309       else
310         dup2(fd, 2);
311       close(fd);
312     }
313     kset_logfile(logfile);
314     if (interactive)
315       return doit_interactive ();
316     else
317       return doit ();
318 }