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