]> andersk Git - moira.git/blob - update/get_file.c
f92a52485692363c5c3963e68c277c7f1cd113b7
[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   memset(buf, '\0', sizeof(buf));
74
75   if (!have_authorization)
76     {
77       send_int(conn, MR_PERM);
78       return 1;
79     }
80   if (setuid(uid) < 0)
81     {
82       com_err(whoami, errno, "Unable to setuid to %d\n", uid);
83       exit(1);
84     }
85
86   /* unlink old file */
87   if (!config_lookup("noclobber"))
88     unlink(pathname);
89   /* open file descriptor */
90   fd = open(pathname, O_CREAT|O_EXCL|O_WRONLY, mode);
91   if (fd == -1)
92     {
93       code = errno;
94       com_err(whoami, errno, "creating file %s (get_file)", pathname);
95       send_int(conn, code);
96       return 1;
97     }
98
99   /* check to see if we've got the disk space */
100   n_written = 0;
101   while (n_written < file_size)
102     {
103       int n_wrote;
104       n_wrote = write(fd, buf, sizeof(buf));
105       if (n_wrote == -1)
106         {
107           code = errno;
108           com_err(whoami, code, "verifying free disk space for %s (get_file)",
109                   pathname);
110           send_int(conn, code);
111
112           /* do all we can to free the space */
113           unlink(pathname);
114           ftruncate(fd, 0);
115           close(fd);
116           return 1;
117         }
118       n_written += n_wrote;
119     }
120
121   lseek(fd, 0, SEEK_SET);
122   send_ok(conn);
123
124   if (encrypt)
125     {
126       des_key_sched(session, sched);
127       memcpy(ivec, session, sizeof(ivec));
128     }
129
130   n_written = 0;
131   while (n_written < file_size)
132     {
133       int n_got = get_block(conn, fd, file_size - n_written, encrypt);
134
135       if (n_got == -1)
136         {
137           /* get_block has already printed a message */
138           unlink(pathname);
139           return 1;
140         }
141       n_written += n_got;
142       if (n_written != file_size)
143         send_ok(conn);
144     }
145
146   fsync(fd);
147   ftruncate(fd, file_size);
148   fsync(fd);
149   close(fd);
150
151   /* validate checksum */
152   found_checksum = checksum_file(pathname);
153   if (checksum != found_checksum)
154     {
155       code = MR_MISSINGFILE;
156       com_err(whoami, code, ": expected = %d, found = %d",
157               checksum, found_checksum);
158       send_int(conn, code);
159       return 1;
160     }
161
162   send_ok(conn);
163   return 0;
164 }
165
166 static int get_block(int conn, int fd, int max_size, int encrypt)
167 {
168   char *data;
169   size_t len;
170   int n_read, n, i, code;
171
172   recv_string(conn, &data, &len);
173
174   if (encrypt)
175     {
176       char *unenc = malloc(len);
177
178       if (!unenc)
179         {
180           send_int(conn, ENOMEM);
181           return -1;
182         }
183
184       des_pcbc_encrypt(data, unenc, len, sched, ivec, 1);
185       for (i = 0; i < 8; i++)
186         ivec[i] = data[len - 8 + i] ^ unenc[len - 8 + i];
187       free(data);
188       data = unenc;
189     }
190
191   n_read = MIN(len, max_size);
192   n = 0;
193   while (n < n_read)
194     {
195       int n_wrote;
196       n_wrote = write(fd, data + n, n_read - n);
197       if (n_wrote == -1)
198         {
199           code = errno;
200           com_err(whoami, errno, "writing file (get_file)");
201           send_int(conn, code);
202           free(data);
203           close(fd);
204           return -1;
205         }
206       n += n_wrote;
207     }
208   free(data);
209   return n;
210 }
This page took 0.049058 seconds and 3 git commands to generate.