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