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