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