source: trunk/third/moira/update/get_file.c @ 24319

Revision 24319, 4.5 KB checked in by broder, 14 years ago (diff)
New Moira snapshot from SVN.
Line 
1/* $Id: get_file.c 3956 2010-01-05 20:56:56Z zacheiss $
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
24RCSID("$HeadURL: svn+ssh://svn.mit.edu/moira/trunk/moira/update/get_file.c $ $Id: get_file.c 3956 2010-01-05 20:56:56Z zacheiss $");
25
26#ifndef MIN
27#define MIN(a, b)    (((a) < (b)) ? (a) : (b))
28#endif /* MIN */
29
30#ifdef HAVE_KRB4
31static des_key_schedule sched;
32static des_cblock ivec;
33extern des_cblock session;
34#endif
35
36static 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
70int 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
177static int get_block(int conn, int fd, int max_size, int encrypt)
178{
179  char *data;
180  long 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((des_cblock *)data, (des_cblock *)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}
Note: See TracBrowser for help on using the repository browser.