]> andersk Git - moira.git/blob - update/get_file.c
KEYFILE is no longer a compile-time constant in krb5's krb4 compat
[moira.git] / update / get_file.c
1 /* $Id$
2  *
3  * Copyright (C) 1988-1998 by the Massachusetts Institute of Technology.
4  * For copying and distribution information, please see the file
5  * <mit-copyright.h>.
6  */
7
8 #include <mit-copyright.h>
9 #include <moira.h>
10 #include "update_server.h"
11 #include "update.h"
12
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18
19 #include <des.h>
20
21 RCSID("$Header$");
22
23 #ifndef MIN
24 #define MIN(a, b)    (((a) < (b)) ? (a) : (b))
25 #endif /* MIN */
26
27 static des_key_schedule sched;
28 static des_cblock ivec;
29 extern des_cblock session;
30
31 static int get_block(int conn, int fd, int max_size, int encrypt);
32
33 /*
34  * get_file()
35  *
36  * arguments:
37  *      char *pathname
38  *              file to receive
39  *      int file_size
40  *              number of bytes
41  *      int checksum
42  *              linear checksum of bytes
43  *
44  * syntax:
45  * (initial protocol already done)
46  * <<< (int)code        (can we accept the file?)
47  * >>> (STRING)data
48  * <<< (int)code
49  * >>> (STRING)data
50  * <<< (int)code
51  * ...
52  * >>> (STRING)data     (last data block)
53  * <<< (int)code        (from read, write, checksum verify)
54  *
55  * returns:
56  *      int
57  *              0 for success, 1 for failure
58  *
59  * function:
60  *      perform initial preparations and receive file as
61  * a single string, storing it into <pathname>
62  *
63  */
64
65 int get_file(int conn, char *pathname, int file_size, int checksum,
66              int mode, int encrypt)
67 {
68   int fd, n_written, code;
69   int found_checksum;
70   char buf[BUFSIZ];
71
72   if (!have_authorization)
73     {
74       send_int(conn, MR_PERM);
75       return 1;
76     }
77   if (setuid(uid) < 0)
78     {
79       com_err(whoami, errno, "Unable to setuid to %d\n", uid);
80       exit(1);
81     }
82
83   /* unlink old file */
84   if (!config_lookup("noclobber"))
85     unlink(pathname);
86   /* open file descriptor */
87   fd = open(pathname, O_CREAT|O_EXCL|O_WRONLY, mode);
88   if (fd == -1)
89     {
90       code = errno;
91       com_err(whoami, errno, "creating file %s (get_file)", pathname);
92       send_int(conn, code);
93       if (setuid(0) < 0)
94         {
95           com_err(whoami, errno, "Unable to setuid back to %d\n", 0);
96           exit(1);
97         }
98       return 1;
99     }
100
101   /* check to see if we've got the disk space */
102   n_written = 0;
103   while (n_written < file_size)
104     {
105       int n_wrote;
106       n_wrote = write(fd, buf, sizeof(buf));
107       if (n_wrote == -1)
108         {
109           code = errno;
110           com_err(whoami, code, "verifying free disk space for %s (get_file)",
111                   pathname);
112           send_int(conn, code);
113
114           /* do all we can to free the space */
115           unlink(pathname);
116           ftruncate(fd, 0);
117           close(fd);
118
119           if (setuid(0) < 0)
120             {
121               com_err(whoami, errno, "Unable to setuid back to %d\n", 0);
122               exit(1);
123             }
124           return 1;
125         }
126       n_written += n_wrote;
127     }
128
129   lseek(fd, 0, SEEK_SET);
130   send_ok(conn);
131
132   if (encrypt)
133     {
134       des_key_sched(session, sched);
135       memcpy(ivec, session, sizeof(ivec));
136     }
137
138   n_written = 0;
139   while (n_written < file_size)
140     {
141       int n_got = get_block(conn, fd, file_size - n_written, encrypt);
142
143       if (n_got == -1)
144         {
145           /* get_block has already printed a message */
146           unlink(pathname);
147           if (setuid(0) < 0)
148             {
149               com_err(whoami, errno, "Unable to setuid back to %d\n", 0);
150               exit(1);
151             }
152           return 1;
153         }
154       n_written += n_got;
155       if (n_written != file_size)
156         send_ok(conn);
157     }
158
159   fsync(fd);
160   ftruncate(fd, file_size);
161   fsync(fd);
162   close(fd);
163
164   if (setuid(0) < 0)
165     {
166       com_err(whoami, errno, "Unable to setuid back to %d\n", 0);
167       exit(1);
168     }
169
170   /* validate checksum */
171   found_checksum = checksum_file(pathname);
172   if (checksum != found_checksum)
173     {
174       code = MR_MISSINGFILE;
175       com_err(whoami, code, ": expected = %d, found = %d",
176               checksum, found_checksum);
177       send_int(conn, code);
178       return 1;
179     }
180
181   send_ok(conn);
182   return 0;
183 }
184
185 static int get_block(int conn, int fd, int max_size, int encrypt)
186 {
187   char *data;
188   size_t len;
189   int n_read, n, i, code;
190
191   recv_string(conn, &data, &len);
192
193   if (encrypt)
194     {
195       char *unenc = malloc(len);
196
197       if (!unenc)
198         {
199           send_int(conn, ENOMEM);
200           return -1;
201         }
202
203       des_pcbc_encrypt(data, unenc, len, sched, ivec, 1);
204       for (i = 0; i < 8; i++)
205         ivec[i] = data[len - 8 + i] ^ unenc[len - 8 + i];
206       free(data);
207       data = unenc;
208     }
209
210   n_read = MIN(len, max_size);
211   n = 0;
212   while (n < n_read)
213     {
214       int n_wrote;
215       n_wrote = write(fd, data + n, n_read - n);
216       if (n_wrote == -1)
217         {
218           code = errno;
219           com_err(whoami, errno, "writing file (get_file)");
220           send_int(conn, code);
221           free(data);
222           close(fd);
223           return -1;
224         }
225       n += n_wrote;
226     }
227   free(data);
228   return n;
229 }
This page took 0.055681 seconds and 5 git commands to generate.