]>
Commit | Line | Data |
---|---|---|
de56407f | 1 | /* |
2 | * $Source$ | |
3 | * $Header$ | |
4 | */ | |
5 | ||
6 | #ifndef lint | |
7 | static char *rcsid_client2_c = "$Header$"; | |
8 | #endif lint | |
9 | ||
10 | /* | |
11 | * MODULE IDENTIFICATION: | |
12 | * $Header$ | |
13 | * Copyright 1987 MIT Project Athena. | |
14 | * DESCRIPTION: | |
15 | * This code handles the actual distribution of data files | |
16 | * to servers in the SMS server-update program. | |
17 | * AUTHOR: | |
18 | * Ken Raeburn (spook@athena.MIT.EDU), | |
19 | * MIT Project Athena/MIT Information Systems. | |
20 | * DEFINED VALUES: | |
21 | * conn | |
22 | * update_info | |
23 | * sms_update_server | |
24 | * VERSION HISTORY: | |
25 | * $Log$ | |
26 | * Revision 1.1 1987-08-22 17:53:46 wesommer | |
27 | * Initial revision | |
28 | * | |
29 | */ | |
30 | ||
31 | #include <stdio.h> | |
32 | #include <strings.h> | |
33 | #include "gdb.h" | |
34 | #include <sys/stat.h> | |
35 | #include <sys/file.h> | |
36 | #include <sys/param.h> | |
37 | #include "update.h" | |
38 | #include <errno.h> | |
39 | #include "sms_update_int.h" | |
40 | #include "smsu_int.h" | |
41 | #include <krb.h> | |
42 | ||
43 | extern char *malloc(), *error_message(); | |
44 | extern int errno; | |
45 | ||
46 | /* XXX */ | |
47 | #include "kludge.h" | |
48 | /* XXX */ | |
49 | ||
50 | static char buf[BUFSIZ]; | |
51 | ||
52 | CONNECTION conn; | |
53 | struct update_desc *info; | |
54 | ||
55 | static int code; | |
56 | ||
57 | /* | |
58 | * FUNCTION: | |
59 | * initialize() | |
60 | * DESCRIPTION: | |
61 | * Insures that various libraries have a chance to get | |
62 | * initialized. | |
63 | * INPUT: | |
64 | * OUTPUT: | |
65 | * RETURN VALUE: | |
66 | * void | |
67 | * SIDE EFFECTS: | |
68 | * Initializes GDB library and SMSU error table. | |
69 | * PROBLEMS: | |
70 | * | |
71 | */ | |
72 | static | |
73 | void | |
74 | initialize() | |
75 | { | |
76 | static int initialized = 0; | |
77 | if (!initialized) { | |
78 | gdb_init(); | |
79 | init_smsU_err_tbl(); | |
80 | initialized++; | |
81 | } | |
82 | } | |
83 | ||
84 | /* | |
85 | * FUNCTION: | |
86 | * sms_update_server(info) | |
87 | * DESCRIPTION: | |
88 | * Attempts to perform an update based on the information | |
89 | * contained in the data structure pointed to by "info". | |
90 | * Errors in performing the update are logged with the | |
91 | * sms_log* routines; the 'override' field may be updated | |
92 | * to cause updates to occur other than on the regular | |
93 | * schedule (generally to force an earlier retry). | |
94 | * INPUT: | |
95 | * info->service_name | |
96 | * Name of service to be updated; used to find | |
97 | * the source data file in the SMS data directory. | |
98 | * info->host_name | |
99 | * info->target_path | |
100 | * Location to install the file. | |
101 | * info->enable | |
102 | * Must be non-zero. | |
103 | * info->instructions | |
104 | * Sequence of commands to execute on remote | |
105 | * machine to effect the installation. | |
106 | * OUTPUT: | |
107 | * info->last_time | |
108 | * Set to the current time if the update was | |
109 | * attempted. | |
110 | * info->success | |
111 | * Set to non-zero if the update succeeded, set | |
112 | * to zero otherwise. | |
113 | * info->override | |
114 | * Set to -1 if the update succeeds, to (possibly) | |
115 | * some other value otherwise. | |
116 | * RETURN VALUE: | |
117 | * int: | |
118 | * Error code, or zero if no error was detected | |
119 | * in the data supplied to this routine. | |
120 | * SIDE EFFECTS: | |
121 | * May write information to logs. | |
122 | * PROBLEMS: | |
123 | * | |
124 | */ | |
125 | ||
126 | int | |
127 | sms_update_server(update_info, pathname) | |
128 | struct update_desc *update_info; | |
129 | char *pathname; | |
130 | { | |
131 | #define ASSERT(condition,amsg) \ | |
132 | if (!(condition)) { msg = amsg; code = 0; goto local_error; } | |
133 | #define NONNULL(str) \ | |
134 | (((str) != (char *)NULL) && ((size = strlen(str)) != 0)) | |
135 | #define IO_ERROR(msg) \ | |
136 | {log_priority=log_ERROR;com_err(whoami,connection_errno(conn),msg);goto io_error;} | |
137 | ||
138 | char *service_address; | |
139 | char *service_updated; | |
140 | char *msg; | |
141 | register char *cp; | |
142 | STRING string_data, string2; | |
143 | int size, num; | |
144 | int fd = -1; | |
145 | struct stat statb; | |
146 | ||
147 | /* variable initializations */ | |
148 | code = 0; | |
149 | info = update_info; | |
150 | service_updated = (char *)NULL; | |
151 | STRING_DATA(string_data) = (char *)NULL; | |
152 | ||
153 | /* pessimism */ | |
154 | info->success = 0; | |
155 | ||
156 | /* some sanity checking of arguments while we build data */ | |
157 | strcpy(buf, "???:???"); | |
158 | ASSERT(NONNULL(info->host_name), "null host name"); | |
159 | /* XXX -- check length here */ | |
160 | strcpy(buf, info->host_name); | |
161 | for (cp = buf; *cp; cp++) | |
162 | ; | |
163 | strcpy(cp, ":???"); | |
164 | ASSERT(NONNULL(info->service_name), "null service name"); | |
165 | /* XXX -- check length here */ | |
166 | strcpy(++cp, info->service_name); | |
167 | service_updated = malloc(strlen(buf)+1); | |
168 | /* XXX -- check allocation succeeded */ | |
169 | strcpy(service_updated, buf); | |
170 | service_address = malloc(strlen(SERVICE_NAME)+strlen(info->host_name)+1); | |
171 | if (!service_address) { | |
172 | code = errno; | |
173 | info->override = -1; | |
174 | return(code); | |
175 | } | |
176 | strcpy(service_address, info->host_name); | |
177 | strcat(service_address, ":"); | |
178 | strcat(service_address, SERVICE_NAME); | |
179 | ASSERT(info->enable, "server is disabled"); | |
180 | ASSERT(NONNULL(info->target_path), "null target pathname"); | |
181 | ASSERT(size < MAXPATHLEN, "target pathname too long"); | |
182 | ASSERT(info->target_path[0] == '/', "non-absolute pathname supplied"); | |
183 | ||
184 | initialize(); | |
185 | ||
186 | string_alloc(&string2, BUFSIZ); | |
187 | ||
188 | sprintf(buf, "starting update for %s", service_updated); | |
189 | sms_log_info(buf); | |
190 | ||
191 | fd = open(pathname, O_RDONLY, 0); | |
192 | if (fd < 0) { | |
193 | code = errno; | |
194 | msg = pathname; | |
195 | goto local_error; | |
196 | } | |
197 | if (fstat(fd, &statb)) { | |
198 | code = errno; | |
199 | close(fd); fd = -1; | |
200 | strcat(buf, ": can't fstat:"); | |
201 | strcat(buf, error_message(code)); | |
202 | sms_log_error(buf); | |
203 | goto error_exit; | |
204 | } | |
205 | size = statb.st_size; | |
206 | ||
207 | /* open connection */ | |
208 | conn = start_server_connection(service_address, 0); | |
209 | if (!conn) { | |
210 | com_err(whoami, 0, "can't connect to update %s", service_address); | |
211 | connect_failed: | |
212 | if (info->override<0 || info->override>INTERVAL_connection_failed) | |
213 | info->override = INTERVAL_connection_failed; | |
214 | return(0); | |
215 | } | |
216 | else if (connection_status(conn) == CON_STOPPED) { | |
217 | com_err(whoami, connection_errno(conn), ": can't connect to update %s", | |
218 | service_address); | |
219 | goto connect_failed; | |
220 | } | |
221 | ||
222 | ||
223 | /* send authenticators */ | |
224 | code = send_auth(); | |
225 | if (code) { | |
226 | sprintf(buf, "authorization attempt to %s failed: %s\n", | |
227 | service_updated, error_message(code)); | |
228 | goto update_failed; | |
229 | } | |
230 | ||
231 | /* send file over */ | |
232 | fd = open(pathname, O_RDONLY, 0); | |
233 | if (fd < 0) { | |
234 | code = errno; | |
235 | msg = pathname; | |
236 | goto local_error; | |
237 | } | |
238 | sprintf(STRING_DATA(string2), "XFER_002 %d %d %s", | |
239 | size, checksum_fd(fd), info->target_path); | |
240 | code = send_object(conn, (char *)&string2, STRING_T); | |
241 | if (code) | |
242 | IO_ERROR("%s: sending XFER_002 request"); | |
243 | code = receive_object(conn, (char *)&num, INTEGER_T); | |
244 | if (code) | |
245 | IO_ERROR("%s: getting reply from XFER_002 request"); | |
246 | if (num) { | |
247 | sprintf(buf, "transfer request to %s (XFER_002) rejected: %s", | |
248 | service_updated, error_message(num)); | |
249 | update_failed: | |
250 | sms_log_error(buf); | |
251 | /* | |
252 | * * if the update fails, something is probably wrong on | |
253 | * * the remote side; we'll have to let a maintainer | |
254 | * * take care of it. don't bother trying again any sooner | |
255 | * * than INTERVAL_update_failed minutes | |
256 | * */ | |
257 | update_failed_1: | |
258 | if (info->override < INTERVAL_update_failed && info->override != -1) | |
259 | info->override = INTERVAL_update_failed; | |
260 | goto do_quit; | |
261 | } | |
262 | /* send actual data */ | |
263 | code = send_file(pathname, size); | |
264 | if (code) | |
265 | goto update_failed_1; | |
266 | string_free(&string_data); | |
267 | close(fd); | |
268 | ||
269 | /* send instructions for installation */ | |
270 | strcpy(buf, "/tmp/sms-update.XXXXXX"); | |
271 | mktemp(buf); | |
272 | fd = open(info->instructions, O_RDONLY, 0); | |
273 | if (fd < 0) { | |
274 | code = errno; | |
275 | log_priority = log_ERROR; | |
276 | com_err(whoami, code, ": can't open %s", info->instructions); | |
277 | send_quit(); | |
278 | info->override = INTERVAL_local_error; | |
279 | goto error_exit; | |
280 | } | |
281 | if (fstat(fd, &statb)) { | |
282 | code = errno; | |
283 | close(fd); | |
284 | fd = -1; | |
285 | log_priority = log_ERROR; | |
286 | com_err(whoami, code, ": can't fstat %s", info->instructions); | |
287 | goto error_exit; | |
288 | } | |
289 | sprintf(STRING_DATA(string2), "XFER_002 %d %d %s", | |
290 | statb.st_size, checksum_fd(fd), buf); | |
291 | code = send_object(conn, (char *)&string2, STRING_T); | |
292 | if (code) | |
293 | IO_ERROR("%s: sending request for transfer of instructions"); | |
294 | code = receive_object(conn, (char *)&num, INTEGER_T); | |
295 | if (code) | |
296 | IO_ERROR("%s: lost reply from installation script request"); | |
297 | if (num) { | |
298 | com_err(whoami, num, ": transfer request rejected for %s", buf); | |
299 | goto update_failed_1; | |
300 | } | |
301 | code = send_file(info->instructions, statb.st_size); | |
302 | if (code) | |
303 | goto update_failed_1; | |
304 | ||
305 | /* perform installation */ | |
306 | code = execute(buf); | |
307 | if (code) { | |
308 | sprintf(buf, "installation of %s failed: %s", service_updated, | |
309 | error_message(code)); | |
310 | sms_log_error(buf); | |
311 | } | |
312 | ||
313 | /* clear override timer and indicate success */ | |
314 | info->override = -1; | |
315 | info->success = 1; | |
316 | ||
317 | /* finished updates */ | |
318 | do_quit: | |
319 | send_quit(); | |
320 | ||
321 | /* fall through */ | |
322 | EGRESS: | |
323 | code = 0; | |
324 | error_exit: | |
325 | info->last_time = time((long *)0); | |
326 | if (STRING_DATA(string2)) | |
327 | string_free(&string2); | |
328 | if (STRING_DATA(string_data)) | |
329 | string_free(&string_data); | |
330 | conn = sever_connection(conn); | |
331 | return(code); | |
332 | ||
333 | local_error: | |
334 | log_priority = log_ERROR; | |
335 | com_err(whoami, code, code ? ": %s" : "%s", msg); | |
336 | return(SMSU_INTERNAL_ERROR); | |
337 | ||
338 | io_error: | |
339 | sms_log_error(buf); | |
340 | if (info->override== -1 || info->override > INTERVAL_connection_lost) | |
341 | info->override = INTERVAL_connection_lost; | |
342 | goto EGRESS; | |
343 | ||
344 | #undef IO_ERROR | |
345 | #undef NONNULL | |
346 | #undef ASSERT | |
347 | } | |
348 | ||
349 | static | |
350 | send_auth() | |
351 | { | |
352 | KTEXT_ST ticket_st; | |
353 | KTEXT ticket = &ticket_st; | |
354 | STRING data; | |
355 | register int code; | |
356 | int response; | |
357 | ||
358 | code = get_sms_update_ticket(info->host_name, ticket); | |
359 | if (code) { | |
360 | return(code); | |
361 | } | |
362 | STRING_DATA(data) = "AUTH_001"; | |
363 | MAX_STRING_SIZE(data) = 9; | |
364 | code = send_object(conn, (char *)&data, STRING_T); | |
365 | if (code) { | |
366 | return(connection_errno(conn)); | |
367 | } | |
368 | code = receive_object(conn, (char *)&response, INTEGER_T); | |
369 | if (code) { | |
370 | return(connection_errno(conn)); | |
371 | } | |
372 | if (response) { | |
373 | return(response); | |
374 | } | |
375 | STRING_DATA(data) = (char *)ticket->dat; | |
376 | MAX_STRING_SIZE(data) = ticket->length; | |
377 | code = send_object(conn, (char *)&data, STRING_T); | |
378 | if (code) { | |
379 | return(connection_errno(conn)); | |
380 | } | |
381 | code = receive_object(conn, (char *)&response, INTEGER_T); | |
382 | if (code) { | |
383 | return(connection_errno(conn)); | |
384 | } | |
385 | if (response) { | |
386 | return(response); | |
387 | } | |
388 | return(0); | |
389 | } | |
390 | ||
391 | static | |
392 | execute(path) | |
393 | char *path; | |
394 | { | |
395 | int response; | |
396 | STRING data; | |
397 | register int code; | |
398 | ||
399 | string_alloc(&data, BUFSIZ); | |
400 | sprintf(STRING_DATA(data), "EXEC_002 %s", path); | |
401 | code = send_object(conn, (char *)&data, STRING_T); | |
402 | if (code) | |
403 | return(connection_errno(conn)); | |
404 | code = receive_object(conn, (char *)&response, INTEGER_T); | |
405 | if (code) | |
406 | return(connection_errno(conn)); | |
407 | if (response) | |
408 | return(response); | |
409 | return(0); | |
410 | } | |
411 | ||
412 | send_quit() | |
413 | { | |
414 | STRING str; | |
415 | if (!conn) | |
416 | return; | |
417 | string_alloc(&str, 5); | |
418 | (void) strcpy(STRING_DATA(str), "quit"); | |
419 | (void) send_object(conn, (char *)&str, STRING_T); | |
420 | string_free(&str); | |
421 | } |