Print this page
remove lint supression made unnecessary by the openssl upgrade
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/cmd-inet/usr.lib/wanboot/wanboot-cgi/wanboot-cgi.c
+++ new/usr/src/cmd/cmd-inet/usr.lib/wanboot/wanboot-cgi/wanboot-cgi.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 * Copyright 2012 Milan Jurik. All rights reserved.
24 24 */
25 25
26 26 #include <stdio.h>
27 27 #include <stdlib.h>
28 28 #include <strings.h>
29 29 #include <string.h>
30 30 #include <libgen.h>
31 31 #include <unistd.h>
32 32 #include <fcntl.h>
33 33 #include <errno.h>
34 34 #include <netdb.h>
35 35 #include <libnvpair.h>
36 36 #include <sys/types.h>
37 37 #include <sys/wait.h>
38 38 #include <sys/stat.h>
39 39 #include <sys/param.h>
40 40 #include <sys/sysmacros.h>
41 41 #include <sys/mman.h>
42 42 #include <sys/socket.h>
43 43 #include <sys/utsname.h>
44 44 #include <sys/wanboot_impl.h>
45 45 #include <netinet/in.h>
46 46 #include <arpa/inet.h>
47 47
48 48 #include <openssl/crypto.h>
49 49 #include <openssl/x509.h>
50 50 #include <openssl/x509v3.h>
51 51 #include <openssl/pem.h>
52 52 #include <openssl/pkcs12.h>
53 53 #include <openssl/evp.h>
54 54 #include <openssl/err.h>
55 55
56 56 #include <p12aux.h>
57 57
58 58 #include <parseURL.h>
59 59 /*
60 60 * These can be replaced with wanbootutil.h once the openssl interfaces
61 61 * are moved to libwanboot.
62 62 */
63 63 #include <wanboot/key_util.h>
64 64 #include <wanboot/key_xdr.h>
65 65 #include <hmac_sha1.h>
66 66
67 67 #include <netboot_paths.h>
68 68 #include <wanboot_conf.h>
69 69
70 70 /*
71 71 * Exit status:
72 72 */
73 73 #define WBCGI_STATUS_OK 0
74 74 #define WBCGI_STATUS_ERR 1
75 75
76 76 #define WBCGI_FILE_EXISTS(file, statbuf) \
77 77 (stat(file, &statbuf) == 0 && S_ISREG(statbuf.st_mode))
78 78
79 79 #define WBCGI_DIR_EXISTS(dir, statbuf) \
80 80 (stat(dir, &statbuf) == 0 && S_ISDIR(statbuf.st_mode))
81 81
82 82 #define WBCGI_HMAC_PATH "/usr/lib/inet/wanboot/hmac"
83 83 #define WBCGI_ENCR_PATH "/usr/lib/inet/wanboot/encr"
84 84 #define WBCGI_KEYMGMT_PATH "/usr/lib/inet/wanboot/keymgmt"
85 85 #define WBCGI_MKISOFS_PATH "/bin/mkisofs"
86 86
87 87 #define WBCGI_DEV_URANDOM "/dev/urandom"
88 88
89 89 #define WBCGI_CONTENT_TYPE "Content-Type: "
90 90 #define WBCGI_CONTENT_LENGTH "Content-Length: "
91 91 #define WBCGI_WANBOOT_BNDTXT "WANBoot_Part_Boundary"
92 92 #define WBCGI_CRNL "\r\n"
93 93
94 94 #define WBCGI_CNSTR "CN="
95 95 #define WBCGI_CNSTR_LEN (sizeof (WBCGI_CNSTR) - 1)
96 96 #define WBCGI_NAMESEP ",/\n\r"
97 97
98 98 #define WBCGI_MAXBUF 256
99 99
100 100 /*
101 101 * Possible return values from netboot_ftw():
102 102 */
103 103 #define WBCGI_FTW_CBOK 2 /* CB terminated walk OK */
104 104 #define WBCGI_FTW_CBCONT 1 /* CB wants walk should continue */
105 105 #define WBCGI_FTW_DONE 0 /* Walk terminated without CBERR/CBOK */
106 106 #define WBCGI_FTW_CBERR -1 /* CB terminated walk with err */
107 107
108 108 /*
109 109 * getsubopt() is used to map one of the contents[] keywords
110 110 * to one of these types
111 111 */
112 112 #define WBCGI_CONTENT_ERROR -1
113 113 #define WBCGI_CONTENT_BOOTFILE 0
114 114 #define WBCGI_CONTENT_BOOTFS 1
115 115 #define WBCGI_CONTENT_ROOTFS 2
116 116
117 117 static char *contents[] =
118 118 { "bootfile", "bootfs", "rootfs", NULL };
119 119
120 120 /*
121 121 * getsubopt() is used to parse the query string for
122 122 * the keywords defined by queryopts[]
123 123 */
124 124 #define WBCGI_QUERYOPT_CONTENT 0
125 125 #define WBCGI_QUERYOPT_NET 1
126 126 #define WBCGI_QUERYOPT_CID 2
127 127 #define WBCGI_QUERYOPT_NONCE 3
128 128
129 129 static char *queryopts[] =
130 130 { "CONTENT", "IP", "CID", "NONCE", NULL };
131 131
132 132 static bc_handle_t bc_handle;
133 133
134 134
135 135 static char *
136 136 status_msg(int status)
137 137 {
138 138 char *msg;
139 139
140 140 switch (status) {
141 141 case 400:
142 142 msg = "Bad Request";
143 143 break;
144 144 case 403:
145 145 msg = "Forbidden";
146 146 break;
147 147 case 500:
148 148 msg = "Internal Server Error";
149 149 break;
150 150 default:
151 151 msg = "Unknown status";
152 152 break;
153 153 }
154 154
155 155 return (msg);
156 156 }
157 157
158 158 static void
159 159 print_status(int status, const char *spec_msg)
160 160 {
161 161 if (spec_msg == NULL) {
162 162 spec_msg = "";
163 163 }
164 164
165 165 (void) fprintf(stdout, "Status: %d %s %s%s", status,
166 166 status_msg(status), spec_msg, WBCGI_CRNL);
167 167 }
168 168
169 169 static char *
170 170 make_path(const char *root, const char *suffix)
171 171 {
172 172 char path[MAXPATHLEN];
173 173 char *ptr = NULL;
174 174 int chars;
175 175
176 176 if ((chars = snprintf(path, sizeof (path),
177 177 "%s/%s", root, suffix)) < 0 || chars > sizeof (path) ||
178 178 (ptr = strdup(path)) == NULL) {
179 179 print_status(500, "(error making path)");
180 180 }
181 181
182 182 return (ptr);
183 183 }
184 184
185 185 static void
186 186 free_path(char **pathp)
187 187 {
188 188 if (*pathp != NULL) {
189 189 free(*pathp);
190 190 *pathp = NULL;
191 191 }
192 192 }
193 193
194 194 static char *
195 195 gen_tmppath(const char *prefix, const char *net, const char *cid)
196 196 {
197 197 pid_t pid;
198 198 time_t secs;
199 199 int chars;
200 200 char path[MAXPATHLEN];
201 201 char *ptr = NULL;
202 202
203 203 if ((pid = getpid()) < 0 || (secs = time(NULL)) < 0 ||
204 204 (chars = snprintf(path, sizeof (path), "/tmp/%s_%s_%s_%ld_%ld",
205 205 prefix, net, cid, pid, secs)) < 0 || chars > sizeof (path) ||
206 206 (ptr = strdup(path)) == NULL) {
207 207 print_status(500, "(error creating temporary filename)");
208 208 }
209 209
210 210 return (ptr);
211 211 }
212 212
213 213 /*
214 214 * File I/O stuff:
215 215 */
216 216 static boolean_t
217 217 write_buffer(int fd, const void *buffer, size_t buflen)
218 218 {
219 219 size_t nwritten;
220 220 ssize_t nbytes;
221 221 const char *buf = buffer;
222 222
223 223 for (nwritten = 0; nwritten < buflen; nwritten += nbytes) {
224 224 nbytes = write(fd, &buf[nwritten], buflen - nwritten);
225 225 if (nbytes <= 0) {
226 226 return (B_FALSE);
227 227 }
228 228 }
229 229
230 230 return (B_TRUE);
231 231 }
232 232
233 233 static boolean_t
234 234 write_file(int ofd, const char *filename, size_t size)
235 235 {
236 236 boolean_t ret = B_TRUE;
237 237 int ifd;
238 238 char buf[1024];
239 239 size_t rlen;
240 240 ssize_t wlen;
241 241
242 242 if ((ifd = open(filename, O_RDONLY)) < 0) {
243 243 return (B_FALSE);
244 244 }
245 245
246 246 for (; size != 0; size -= wlen) {
247 247 rlen = (size < sizeof (buf)) ? size : sizeof (buf);
248 248
249 249 if ((wlen = read(ifd, buf, rlen)) < 0 ||
250 250 !write_buffer(ofd, buf, wlen)) {
251 251 ret = B_FALSE;
252 252 break;
253 253 }
254 254 }
255 255 (void) close(ifd);
256 256
257 257 return (ret);
258 258 }
259 259
260 260 static boolean_t
261 261 copy_file(const char *src, const char *dest)
262 262 {
263 263 boolean_t ret = B_FALSE;
264 264 char message[WBCGI_MAXBUF];
265 265 const size_t chunksize = 16 * PAGESIZE;
266 266 size_t validsize;
267 267 size_t nwritten = 0;
268 268 size_t nbytes = 0;
269 269 off_t roff;
270 270 int mflags = MAP_PRIVATE;
271 271 char *buf = NULL;
272 272 struct stat st;
273 273 int rfd = -1;
274 274 int wfd = -1;
275 275 int chars;
276 276
277 277 if ((rfd = open(src, O_RDONLY)) < 0 ||
278 278 (wfd = open(dest, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR)) < 0 ||
279 279 fstat(rfd, &st) == -1) {
280 280 goto cleanup;
281 281 }
282 282
283 283 for (nbytes = st.st_size, roff = 0; nwritten < nbytes;
284 284 nwritten += validsize, roff += validsize) {
285 285 buf = mmap(buf, chunksize, PROT_READ, mflags, rfd, roff);
286 286 if (buf == MAP_FAILED) {
287 287 goto cleanup;
288 288 }
289 289 mflags |= MAP_FIXED;
290 290
291 291 validsize = MIN(chunksize, nbytes - nwritten);
292 292 if (!write_buffer(wfd, buf, validsize)) {
293 293 (void) munmap(buf, chunksize);
294 294 goto cleanup;
295 295 }
296 296
297 297 }
298 298 if (buf != NULL) {
299 299 (void) munmap(buf, chunksize);
300 300 }
301 301
302 302 ret = B_TRUE;
303 303 cleanup:
304 304 if (ret == B_FALSE) {
305 305 if ((chars = snprintf(message, sizeof (message),
306 306 "error copying %s to %s", src, dest)) > 0 &&
307 307 chars <= sizeof (message)) {
308 308 print_status(500, message);
309 309 } else {
310 310 print_status(500, NULL);
311 311 }
312 312 }
313 313 if (rfd != -1) {
314 314 (void) close(rfd);
315 315 }
316 316 if (wfd != -1) {
317 317 (void) close(wfd);
318 318 }
319 319
320 320 return (ret);
321 321 }
322 322
323 323 static boolean_t
324 324 create_nonce(const char *noncepath, const char *nonce)
325 325 {
326 326 boolean_t ret = B_TRUE;
327 327 int fd;
328 328
329 329 if ((fd = open(noncepath,
330 330 O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 ||
331 331 !write_buffer(fd, nonce, strlen(nonce))) {
332 332 print_status(500, "(error creating nonce file)");
333 333 ret = B_FALSE;
334 334 }
335 335 if (fd != -1) {
336 336 (void) close(fd);
337 337 }
338 338
339 339 return (ret);
340 340 }
341 341
342 342 static boolean_t
343 343 create_timestamp(const char *timestamppath, const char *timestamp)
344 344 {
345 345 boolean_t ret = B_TRUE;
346 346 int fd;
347 347
348 348 if ((fd = open(timestamppath,
349 349 O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 ||
350 350 !write_buffer(fd, timestamp, strlen(timestamp))) {
351 351 print_status(500, "(error creating timestamp file)");
352 352 ret = B_FALSE;
353 353 }
354 354 if (fd != -1) {
355 355 (void) close(fd);
356 356 }
357 357
358 358 return (ret);
359 359 }
360 360
361 361 static boolean_t
362 362 create_urandom(const char *urandompath)
363 363 {
364 364 boolean_t ret = B_TRUE;
365 365 int fd;
366 366
367 367 if ((fd = open(urandompath,
368 368 O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 ||
369 369 !write_file(fd, WBCGI_DEV_URANDOM, 32 * 1024)) {
370 370 print_status(500, "(error creating urandom file)");
371 371 ret = B_FALSE;
372 372 }
373 373 if (fd != -1) {
374 374 (void) close(fd);
375 375 }
376 376
377 377 return (ret);
378 378 }
379 379
380 380 static boolean_t
381 381 create_null_hash(const char *hashpath)
382 382 {
383 383 boolean_t ret = B_TRUE;
384 384 int fd;
385 385 static char null_hash[HMAC_DIGEST_LEN];
386 386
387 387 if ((fd = open(hashpath,
388 388 O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 ||
389 389 !write_buffer(fd, null_hash, sizeof (null_hash))) {
390 390 print_status(500, "(error creating null hash)");
391 391 ret = B_FALSE;
392 392 }
393 393 if (fd != -1) {
394 394 (void) close(fd);
395 395 }
396 396
397 397 return (ret);
398 398 }
399 399
400 400
401 401 static char *
402 402 determine_doc_root(void)
403 403 {
404 404 char *doc_root;
405 405
406 406 /*
407 407 * If DOCUMENT_ROOT is valid, use that.
408 408 */
409 409 if ((doc_root = getenv("DOCUMENT_ROOT")) == NULL ||
410 410 strlen(doc_root) == 0) {
411 411 /*
412 412 * No DOCUMENT_ROOT - try PATH_TRANSLATED.
413 413 */
414 414 if ((doc_root = getenv("PATH_TRANSLATED")) == NULL ||
415 415 strlen(doc_root) == 0) {
416 416 /*
417 417 * Can't determine the document root.
418 418 */
419 419 return (NULL);
420 420 }
421 421 }
422 422
423 423 return (doc_root);
424 424 }
425 425
426 426 static boolean_t
427 427 get_request_info(int *contentp, char **netp, char **cidp, char **noncep,
428 428 char **docrootp)
429 429 {
430 430 char *method;
431 431 char *query_string;
432 432 char *value;
433 433 char *junk;
434 434 int i;
435 435
436 436 if ((method = getenv("REQUEST_METHOD")) == NULL ||
437 437 strncasecmp(method, "GET", strlen("GET") != 0)) {
438 438 print_status(403, "(GET method expected)");
439 439 return (B_FALSE);
440 440 }
441 441
442 442 if ((query_string = getenv("QUERY_STRING")) == NULL) {
443 443 print_status(400, "(empty query string)");
444 444 return (B_FALSE);
445 445 }
446 446
447 447 for (i = 0; i < strlen(query_string); i++) {
448 448 if (query_string[i] == '&') {
449 449 query_string[i] = ',';
450 450 }
451 451 }
452 452
453 453 *contentp = WBCGI_CONTENT_ERROR;
454 454 *netp = *cidp = *noncep = NULL;
455 455
456 456 if ((*docrootp = determine_doc_root()) == NULL) {
457 457 print_status(400, "(unable to determine document root)");
458 458 return (B_FALSE);
459 459 }
460 460
461 461 while (*query_string != '\0') {
462 462 switch (getsubopt(&query_string, queryopts, &value)) {
463 463 case WBCGI_QUERYOPT_CONTENT:
464 464 *contentp = getsubopt(&value, contents, &junk);
465 465 break;
466 466 case WBCGI_QUERYOPT_NET:
467 467 *netp = value;
468 468 break;
469 469 case WBCGI_QUERYOPT_CID:
470 470 *cidp = value;
471 471 break;
472 472 case WBCGI_QUERYOPT_NONCE:
473 473 *noncep = value;
474 474 break;
475 475 default:
476 476 print_status(400, "(illegal query string)");
477 477 return (B_FALSE);
478 478 }
479 479 }
480 480
481 481 switch (*contentp) {
482 482 default:
483 483 print_status(400, "(missing or illegal CONTENT)");
484 484 return (B_FALSE);
485 485
486 486 case WBCGI_CONTENT_BOOTFS:
487 487 if (*netp == NULL || *cidp == NULL || *noncep == NULL) {
488 488 print_status(400,
489 489 "(CONTENT, IP, CID and NONCE required)");
490 490 return (B_FALSE);
491 491 }
492 492 break;
493 493
494 494 case WBCGI_CONTENT_BOOTFILE:
495 495 case WBCGI_CONTENT_ROOTFS:
496 496 if (*netp == NULL || *cidp == NULL || *docrootp == NULL) {
497 497 print_status(400,
498 498 "(CONTENT, IP, CID and DOCUMENT_ROOT required)");
499 499 return (B_FALSE);
500 500 }
501 501 break;
502 502 }
503 503
504 504 return (B_TRUE);
505 505 }
506 506
507 507 static boolean_t
508 508 encrypt_payload(const char *payload, const char *encr_payload,
509 509 const char *keyfile, const char *encryption_type)
510 510 {
511 511 struct stat sbuf;
512 512 int chars;
513 513 char cmd[MAXPATHLEN];
514 514 FILE *fp;
515 515 int status;
516 516 char msg[WBCGI_MAXBUF];
517 517
518 518 if (!WBCGI_FILE_EXISTS(payload, sbuf)) {
519 519 print_status(500, "(encrypt_payload: missing payload)");
520 520 return (B_FALSE);
521 521 }
522 522
523 523 if ((chars = snprintf(cmd, sizeof (cmd),
524 524 "%s -o type=%s -k %s < %s > %s", WBCGI_ENCR_PATH,
525 525 encryption_type, keyfile, payload, encr_payload)) < 0 ||
526 526 chars > sizeof (cmd)) {
527 527 print_status(500, "(encrypt_payload: buffer overflow)");
528 528 return (B_FALSE);
529 529 }
530 530
531 531 if ((fp = popen(cmd, "w")) == NULL) {
532 532 print_status(500, "(encrypt_payload: missing/file error)");
533 533 return (B_FALSE);
534 534 }
535 535 if ((status = WEXITSTATUS(pclose(fp))) != 0) {
536 536 (void) snprintf(msg, sizeof (msg),
537 537 "(encrypt_payload: failed, status=%d)", status);
538 538 print_status(500, msg);
539 539 return (B_FALSE);
540 540 }
541 541
542 542 if (!WBCGI_FILE_EXISTS(encr_payload, sbuf)) {
543 543 print_status(500, "(encrypt_payload: bad encrypted file)");
544 544 return (B_FALSE);
545 545 }
546 546
547 547 return (B_TRUE);
548 548 }
549 549
550 550 static boolean_t
551 551 hash_payload(const char *payload, const char *payload_hash,
552 552 const char *keyfile)
553 553 {
554 554 struct stat sbuf;
555 555 int chars;
556 556 char cmd[MAXPATHLEN];
557 557 FILE *fp;
558 558 int status;
559 559 char msg[WBCGI_MAXBUF];
560 560
561 561 if (!WBCGI_FILE_EXISTS(payload, sbuf)) {
562 562 print_status(500, "(hash_payload: missing payload)");
563 563 return (B_FALSE);
564 564 }
565 565
566 566 if ((chars = snprintf(cmd, sizeof (cmd), "%s -i %s -k %s > %s",
567 567 WBCGI_HMAC_PATH, payload, keyfile, payload_hash)) < 0 ||
568 568 chars > sizeof (cmd)) {
569 569 print_status(500, "(hash_payload: buffer overflow)");
570 570 return (B_FALSE);
571 571 }
572 572
573 573 if ((fp = popen(cmd, "w")) == NULL) {
574 574 print_status(500, "(hash_payload: missing/file error)");
575 575 return (B_FALSE);
576 576 }
577 577 if ((status = WEXITSTATUS(pclose(fp))) != 0) {
578 578 (void) snprintf(msg, sizeof (msg),
579 579 "(hash_payload: failed, status=%d)", status);
580 580 print_status(500, msg);
581 581 return (B_FALSE);
582 582 }
583 583
584 584 if (!WBCGI_FILE_EXISTS(payload_hash, sbuf) ||
585 585 sbuf.st_size < HMAC_DIGEST_LEN) {
586 586 print_status(500, "(hash_payload: bad signature file)");
587 587 return (B_FALSE);
588 588 }
589 589
590 590 return (B_TRUE);
591 591 }
592 592
593 593 static boolean_t
594 594 extract_keystore(const char *path, const char *keystorepath)
595 595 {
596 596 struct stat sbuf;
597 597 int chars;
598 598 char cmd[MAXPATHLEN];
599 599 FILE *fp;
600 600 int status;
601 601 char msg[WBCGI_MAXBUF];
602 602
603 603 if (!WBCGI_FILE_EXISTS(path, sbuf)) {
604 604 print_status(500, "(extract_keystore: missing keystore)");
605 605 return (B_FALSE);
606 606 }
607 607
608 608 if ((chars = snprintf(cmd, sizeof (cmd),
609 609 "%s -x -f %s -s %s -o type=rsa",
610 610 WBCGI_KEYMGMT_PATH, keystorepath, path)) < 0 ||
611 611 chars > sizeof (cmd)) {
612 612 print_status(500, "(extract_keystore: buffer overflow)");
613 613 return (B_FALSE);
614 614 }
615 615
616 616 if ((fp = popen(cmd, "w")) == NULL) {
617 617 print_status(500, "(extract_keystore: missing/file error)");
618 618 return (B_FALSE);
619 619 }
620 620 if ((status = WEXITSTATUS(pclose(fp))) != 0) {
621 621 (void) snprintf(msg, sizeof (msg),
622 622 "(extract_keystore: failed, status=%d)", status);
623 623 print_status(500, msg);
624 624 return (B_FALSE);
625 625 }
626 626
627 627 if (!WBCGI_FILE_EXISTS(keystorepath, sbuf)) {
628 628 print_status(500, "(extract_keystore: failed to create)");
629 629 return (B_FALSE);
630 630 }
631 631
632 632 return (B_TRUE);
633 633 }
634 634
635 635 static boolean_t
636 636 mkisofs(const char *image_dir, const char *image)
637 637 {
638 638 struct stat sbuf;
639 639 int chars;
640 640 char cmd[MAXPATHLEN];
641 641 FILE *fp;
642 642 int status;
643 643 char msg[WBCGI_MAXBUF];
644 644
645 645 if (!WBCGI_DIR_EXISTS(image_dir, sbuf)) {
646 646 print_status(500, "(mksiofs: missing image_dir)");
647 647 return (B_FALSE);
648 648 }
649 649
650 650 if ((chars = snprintf(cmd, sizeof (cmd), "%s -quiet -o %s -r %s",
651 651 WBCGI_MKISOFS_PATH, image, image_dir)) < 0 ||
652 652 chars > sizeof (cmd)) {
653 653 print_status(500, "(mkisofs: buffer overflow)");
654 654 return (B_FALSE);
655 655 }
656 656
657 657 if ((fp = popen(cmd, "w")) == NULL) {
658 658 print_status(500, "(mkisofs: missing/file error)");
659 659 return (B_FALSE);
660 660 }
661 661 if ((status = WEXITSTATUS(pclose(fp))) != 0) {
662 662 (void) snprintf(msg, sizeof (msg),
663 663 "(mkisofs: failed, status=%d)", status);
664 664 print_status(500, msg);
665 665 return (B_FALSE);
666 666 }
667 667
668 668 if (!WBCGI_FILE_EXISTS(image, sbuf)) {
669 669 print_status(500, "(mksiofs: failed to create image)");
670 670 return (B_FALSE);
671 671 }
672 672
673 673 return (B_TRUE);
674 674 }
675 675
676 676 /*
677 677 * This function, when invoked with a file name, optional network and
678 678 * client ID strings, and callback function will search for the file
679 679 * in the following locations:
680 680 *
681 681 * NB_NETBOOT_ROOT/<network>/<client id>/<file>
682 682 * NB_NETBOOT_ROOT/<client id>/<file>
683 683 * NB_NETBOOT_ROOT/<network>/<file>
684 684 * NB_NETBOOT_ROOT/<file>
685 685 *
686 686 * The callback function is invoked each time the file is found until
687 687 * we have searched all of the above locations or the callback function
688 688 * returns a value other than WBCGI_FTW_CBCONT.
689 689 *
690 690 * Arguments:
691 691 * filename - Name of file to search for.
692 692 * net - Optional network number to include in search hierarchy.
693 693 * cid - Optional client ID to include in search hierarchy.
694 694 * cb - Callback function to be called when file is found.
695 695 * arg - Argument to be supplied to the callback funtion.
696 696 *
697 697 * Returns:
698 698 * WBCGI_FTW_DONE, WBCGI_FTW_CBOK or WBCGI_FTW_CBERR.
699 699 */
700 700 static int
701 701 netboot_ftw(const char *filename, const char *net, const char *cid,
702 702 int (*cb)(const char *, void *arg), void *arg)
703 703 {
704 704 char ckpath[4][MAXPATHLEN];
705 705 int ret;
706 706 struct stat buf;
707 707 int i = 0;
708 708
709 709 if (snprintf(ckpath[i++], MAXPATHLEN, "%s%s", NB_NETBOOT_ROOT, filename)
710 710 >= MAXPATHLEN)
711 711 return (WBCGI_FTW_CBERR);
712 712
713 713 if (net != NULL && snprintf(ckpath[i++], MAXPATHLEN, "%s%s/%s",
714 714 NB_NETBOOT_ROOT, net, filename) >= MAXPATHLEN)
715 715 return (WBCGI_FTW_CBERR);
716 716
717 717 if (cid != NULL) {
718 718 if (snprintf(ckpath[i++], MAXPATHLEN, "%s%s/%s",
719 719 NB_NETBOOT_ROOT, cid, filename) >= MAXPATHLEN)
720 720 return (WBCGI_FTW_CBERR);
721 721
722 722 if (net != NULL && snprintf(ckpath[i++], MAXPATHLEN,
723 723 "%s%s/%s/%s", NB_NETBOOT_ROOT, net, cid, filename) >=
724 724 MAXPATHLEN)
725 725 return (WBCGI_FTW_CBERR);
726 726 }
727 727
728 728 /*
729 729 * Loop through hierarchy and check for file existence.
730 730 */
731 731 while (i > 0) {
732 732 --i;
733 733 if (WBCGI_FILE_EXISTS(ckpath[i], buf)) {
734 734 if ((ret = cb(ckpath[i], arg)) != WBCGI_FTW_CBCONT)
735 735 return (ret);
736 736 }
737 737 }
738 738 return (WBCGI_FTW_DONE);
739 739 }
740 740
741 741 /*ARGSUSED*/
742 742 static int
743 743 noact_cb(const char *path, void *arg)
744 744 {
745 745 return (WBCGI_FTW_CBOK);
746 746 }
747 747
748 748 static int
749 749 set_pathname(const char *path, void *pathname)
750 750 {
751 751 *(char **)pathname = strdup((char *)path);
752 752 return (WBCGI_FTW_CBOK);
753 753 }
754 754
755 755 static int
756 756 create_keystore(const char *path, void *keystorepath)
757 757 {
758 758 if (!extract_keystore(path, (char *)keystorepath)) {
759 759 return (WBCGI_FTW_CBERR);
760 760 }
761 761 return (WBCGI_FTW_CBOK);
762 762 }
763 763
764 764 static int
765 765 copy_certstore(const char *path, void *certstorepath)
766 766 {
767 767 if (!copy_file(path, (char *)certstorepath)) {
768 768 return (WBCGI_FTW_CBERR);
769 769 }
770 770 return (WBCGI_FTW_CBOK);
771 771 }
772 772
773 773 /*
774 774 * Add the certs found in the trustfile found in path (a trust store) to
775 775 * the file found at bootfs_dir/truststore. If necessary, create the
776 776 * output file.
777 777 */
778 778 static int
779 779 build_trustfile(const char *path, void *truststorepath)
780 780 {
781 781 int ret = WBCGI_FTW_CBERR;
782 782 STACK_OF(X509) *i_anchors = NULL;
783 783 STACK_OF(X509) *o_anchors = NULL;
784 784 char message[WBCGI_MAXBUF];
785 785 PKCS12 *p12 = NULL;
786 786 FILE *rfp = NULL;
787 787 FILE *wfp = NULL;
788 788 struct stat i_st;
789 789 struct stat o_st;
790 790 X509 *x = NULL;
791 791 int errtype = 0;
792 792 int wfd = -1;
793 793 int chars;
794 794 int i;
795 795
796 796 if (!WBCGI_FILE_EXISTS(path, i_st)) {
797 797 goto cleanup;
798 798 }
799 799
800 800 if (WBCGI_FILE_EXISTS((char *)truststorepath, o_st)) {
801 801 /*
802 802 * If we are inadvertantly writing to the input file.
803 803 * return success.
804 804 * XXX Pete: how can this happen, and why success?
805 805 */
806 806 if (i_st.st_ino == o_st.st_ino) {
807 807 ret = WBCGI_FTW_CBCONT;
808 808 goto cleanup;
809 809 }
810 810 if ((wfp = fopen((char *)truststorepath, "r+")) == NULL) {
811 811 goto cleanup;
812 812 }
813 813 /*
814 814 * Read what's already there, so that new information
815 815 * can be added.
816 816 */
817 817 if ((p12 = d2i_PKCS12_fp(wfp, NULL)) == NULL) {
818 818 errtype = 1;
819 819 goto cleanup;
820 820 }
821 821 i = sunw_PKCS12_parse(p12, WANBOOT_PASSPHRASE, DO_NONE, NULL,
822 822 0, NULL, NULL, NULL, &o_anchors);
823 823 if (i <= 0) {
824 824 errtype = 1;
825 825 goto cleanup;
826 826 }
827 827
828 828 PKCS12_free(p12);
829 829 p12 = NULL;
830 830 } else {
831 831 if (errno != ENOENT) {
832 832 chars = snprintf(message, sizeof (message),
833 833 "(error accessing file %s, error %s)",
834 834 path, strerror(errno));
835 835 if (chars > 0 && chars < sizeof (message))
836 836 print_status(500, message);
837 837 else
838 838 print_status(500, NULL);
839 839 return (WBCGI_FTW_CBERR);
840 840 }
841 841
842 842 /*
843 843 * Note: We could copy the file to the new trustfile, but
844 844 * we can't verify the password that way. Therefore, copy
845 845 * it by reading it.
846 846 */
847 847 if ((wfd = open((char *)truststorepath,
848 848 O_CREAT|O_EXCL|O_RDWR, 0700)) < 0) {
849 849 goto cleanup;
850 850 }
851 851 if ((wfp = fdopen(wfd, "w+")) == NULL) {
852 852 goto cleanup;
853 853 }
854 854 o_anchors = sk_X509_new_null();
855 855 if (o_anchors == NULL) {
856 856 goto cleanup;
857 857 }
858 858 }
859 859
860 860 if ((rfp = fopen(path, "r")) == NULL) {
861 861 goto cleanup;
862 862 }
863 863 if ((p12 = d2i_PKCS12_fp(rfp, NULL)) == NULL) {
864 864 errtype = 1;
865 865 goto cleanup;
866 866 }
867 867 i = sunw_PKCS12_parse(p12, WANBOOT_PASSPHRASE, DO_NONE, NULL, 0, NULL,
868 868 NULL, NULL, &i_anchors);
869 869 if (i <= 0) {
↓ open down ↓ |
869 lines elided |
↑ open up ↑ |
870 870 errtype = 1;
871 871 goto cleanup;
872 872 }
873 873 PKCS12_free(p12);
874 874 p12 = NULL;
875 875
876 876 /*
877 877 * Merge the two stacks of pkcs12 certs.
878 878 */
879 879 for (i = 0; i < sk_X509_num(i_anchors); i++) {
880 - /* LINTED */
881 880 x = sk_X509_delete(i_anchors, i);
882 881 (void) sk_X509_push(o_anchors, x);
883 882 }
884 883
885 884 /*
886 885 * Create the pkcs12 structure from the modified input stack and
887 886 * then write out that structure.
888 887 */
889 888 p12 = sunw_PKCS12_create((const char *)WANBOOT_PASSPHRASE, NULL, NULL,
890 889 o_anchors);
891 890 if (p12 == NULL) {
892 891 goto cleanup;
893 892 }
894 893 rewind(wfp);
895 894 if (i2d_PKCS12_fp(wfp, p12) == 0) {
896 895 goto cleanup;
897 896 }
898 897
899 898 ret = WBCGI_FTW_CBCONT;
900 899 cleanup:
901 900 if (ret == WBCGI_FTW_CBERR) {
902 901 if (errtype == 1) {
903 902 chars = snprintf(message, sizeof (message),
904 903 "(internal PKCS12 error while copying %s to %s)",
905 904 path, (char *)truststorepath);
906 905 } else {
907 906 chars = snprintf(message, sizeof (message),
908 907 "(error copying %s to %s)",
909 908 path, (char *)truststorepath);
910 909 }
911 910 if (chars > 0 && chars <= sizeof (message)) {
912 911 print_status(500, message);
913 912 } else {
914 913 print_status(500, NULL);
915 914 }
916 915 }
917 916 if (rfp != NULL) {
918 917 (void) fclose(rfp);
919 918 }
920 919 if (wfp != NULL) {
921 920 /* Will also close wfd */
922 921 (void) fclose(wfp);
923 922 }
924 923 if (p12 != NULL) {
925 924 PKCS12_free(p12);
926 925 }
927 926 if (i_anchors != NULL) {
928 927 sk_X509_pop_free(i_anchors, X509_free);
929 928 }
930 929 if (o_anchors != NULL) {
931 930 sk_X509_pop_free(o_anchors, X509_free);
932 931 }
933 932
934 933 return (ret);
935 934 }
936 935
937 936 static boolean_t
938 937 check_key_type(const char *keyfile, const char *keytype, int flag)
939 938 {
940 939 boolean_t ret = B_FALSE;
941 940 FILE *key_fp = NULL;
942 941 wbku_key_attr_t ka;
943 942
944 943 /*
945 944 * Map keytype into the ka structure
946 945 */
947 946 if (wbku_str_to_keyattr(keytype, &ka, flag) != WBKU_SUCCESS) {
948 947 goto cleanup;
949 948 }
950 949
951 950 /*
952 951 * Open the key file for reading.
953 952 */
954 953 if ((key_fp = fopen(keyfile, "r")) == NULL) {
955 954 goto cleanup;
956 955 }
957 956
958 957 /*
959 958 * Find the valid client key, if it exists.
960 959 */
961 960 if (wbku_find_key(key_fp, NULL, &ka, NULL, B_FALSE) != WBKU_SUCCESS) {
962 961 goto cleanup;
963 962 }
964 963
965 964 ret = B_TRUE;
966 965 cleanup:
967 966 if (key_fp != NULL) {
968 967 (void) fclose(key_fp);
969 968 }
970 969
971 970 return (ret);
972 971 }
973 972
974 973 static boolean_t
975 974 resolve_hostname(const char *hostname, nvlist_t *nvl, boolean_t may_be_crap)
976 975 {
977 976 struct sockaddr_in sin;
978 977 struct hostent *hp;
979 978 struct utsname un;
980 979 static char myname[SYS_NMLN] = { '\0' };
981 980 char *cp = NULL;
982 981 char msg[WBCGI_MAXBUF];
983 982
984 983 /*
985 984 * Initialize cached nodename
986 985 */
987 986 if (strlen(myname) == 0) {
988 987 if (uname(&un) == -1) {
989 988 (void) snprintf(msg, sizeof (msg),
990 989 "(unable to retrieve uname, errno %d)", errno);
991 990 print_status(500, msg);
992 991 return (B_FALSE);
993 992 }
994 993 (void) strcpy(myname, un.nodename);
995 994 }
996 995
997 996 /*
998 997 * If hostname is local node name, return the address this
999 998 * request came in on, which is supplied as SERVER_ADDR in the
1000 999 * cgi environment. This ensures we don't send back a possible
1001 1000 * alternate address that may be unreachable from the client's
1002 1001 * network. Otherwise, just resolve with nameservice.
1003 1002 */
1004 1003 if ((strcmp(hostname, myname) != 0) ||
1005 1004 ((cp = getenv("SERVER_ADDR")) == NULL)) {
1006 1005 if (((hp = gethostbyname(hostname)) == NULL) ||
1007 1006 (hp->h_addrtype != AF_INET) ||
1008 1007 (hp->h_length != sizeof (struct in_addr))) {
1009 1008 if (!may_be_crap) {
1010 1009 print_status(500, "(error resolving hostname)");
1011 1010 }
1012 1011 return (may_be_crap);
1013 1012 }
1014 1013 (void) memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
1015 1014 cp = inet_ntoa(sin.sin_addr);
1016 1015 }
1017 1016
1018 1017 if (nvlist_add_string(nvl, (char *)hostname, cp) != 0) {
1019 1018 print_status(500, "(error adding hostname to nvlist)");
1020 1019 return (B_FALSE);
1021 1020 }
1022 1021
1023 1022 return (B_TRUE);
1024 1023 }
1025 1024
1026 1025 /*
1027 1026 * one_name() is called for each certificate found and is passed the string
1028 1027 * that X509_NAME_oneline() returns. Its job is to find the common name and
1029 1028 * determine whether it is a host name; if it is then a line suitable for
1030 1029 * inclusion in /etc/inet/hosts is written to that file.
1031 1030 */
1032 1031 static boolean_t
1033 1032 one_name(const char *namestr, nvlist_t *nvl)
1034 1033 {
1035 1034 boolean_t ret = B_TRUE;
1036 1035 char *p;
1037 1036 char *q;
1038 1037 char c;
1039 1038
1040 1039 if (namestr != NULL &&
1041 1040 (p = strstr(namestr, WBCGI_CNSTR)) != NULL) {
1042 1041 p += WBCGI_CNSTR_LEN;
1043 1042
1044 1043 if ((q = strpbrk(p, WBCGI_NAMESEP)) != NULL) {
1045 1044 c = *q;
1046 1045 *q = '\0';
1047 1046 ret = resolve_hostname(p, nvl, B_TRUE);
1048 1047 *q = c;
1049 1048 } else {
1050 1049 ret = resolve_hostname(p, nvl, B_TRUE);
1051 1050 }
1052 1051 }
1053 1052
1054 1053 return (ret);
1055 1054 }
1056 1055
1057 1056 /*
1058 1057 * Loop through the certificates in a file
1059 1058 */
1060 1059 static int
1061 1060 get_hostnames(const char *path, void *nvl)
1062 1061 {
1063 1062 int ret = WBCGI_FTW_CBERR;
1064 1063 STACK_OF(X509) *certs = NULL;
1065 1064 PKCS12 *p12 = NULL;
1066 1065 char message[WBCGI_MAXBUF];
1067 1066 char buf[WBCGI_MAXBUF + 1];
1068 1067 FILE *rfp = NULL;
1069 1068 X509 *x = NULL;
1070 1069 int errtype = 0;
1071 1070 int chars;
1072 1071 int i;
1073 1072
1074 1073 if ((rfp = fopen(path, "r")) == NULL) {
1075 1074 goto cleanup;
1076 1075 }
1077 1076
1078 1077 if ((p12 = d2i_PKCS12_fp(rfp, NULL)) == NULL) {
1079 1078 errtype = 1;
1080 1079 goto cleanup;
1081 1080 }
1082 1081 i = sunw_PKCS12_parse(p12, WANBOOT_PASSPHRASE, DO_NONE, NULL, 0, NULL,
↓ open down ↓ |
192 lines elided |
↑ open up ↑ |
1083 1082 NULL, NULL, &certs);
1084 1083 if (i <= 0) {
1085 1084 errtype = 1;
1086 1085 goto cleanup;
1087 1086 }
1088 1087
1089 1088 PKCS12_free(p12);
1090 1089 p12 = NULL;
1091 1090
1092 1091 for (i = 0; i < sk_X509_num(certs); i++) {
1093 - /* LINTED */
1094 1092 x = sk_X509_value(certs, i);
1095 1093 if (!one_name(sunw_issuer_attrs(x, buf, sizeof (buf) - 1),
1096 1094 nvl)) {
1097 1095 goto cleanup;
1098 1096 }
1099 1097 }
1100 1098
1101 1099 ret = WBCGI_FTW_CBCONT;
1102 1100 cleanup:
1103 1101 if (ret == WBCGI_FTW_CBERR) {
1104 1102 if (errtype == 1) {
1105 1103 chars = snprintf(message, sizeof (message),
1106 1104 "(internal PKCS12 error reading %s)", path);
1107 1105 } else {
1108 1106 chars = snprintf(message, sizeof (message),
1109 1107 "error reading %s", path);
1110 1108 }
1111 1109 if (chars > 0 && chars <= sizeof (message)) {
1112 1110 print_status(500, message);
1113 1111 } else {
1114 1112 print_status(500, NULL);
1115 1113 }
1116 1114 }
1117 1115 if (rfp != NULL) {
1118 1116 (void) fclose(rfp);
1119 1117 }
1120 1118 if (p12 != NULL) {
1121 1119 PKCS12_free(p12);
1122 1120 }
1123 1121 if (certs != NULL) {
1124 1122 sk_X509_pop_free(certs, X509_free);
1125 1123 }
1126 1124
1127 1125 return (ret);
1128 1126 }
1129 1127
1130 1128 /*
1131 1129 * Create a hosts file by extracting hosts from client and truststore
1132 1130 * files. Use the CN. Then we should copy that file to the inet dir.
1133 1131 */
1134 1132 static boolean_t
1135 1133 create_hostsfile(const char *hostsfile, const char *net, const char *cid)
1136 1134 {
1137 1135 boolean_t ret = B_FALSE;
1138 1136 nvlist_t *nvl;
1139 1137 nvpair_t *nvp;
1140 1138 FILE *hostfp = NULL;
1141 1139 int hostfd = -1;
1142 1140 int i;
1143 1141 char *hostslist;
1144 1142 const char *bc_urls[] = { BC_ROOT_SERVER, BC_BOOT_LOGGER, NULL };
1145 1143
1146 1144 /*
1147 1145 * Allocate nvlist handle to store our hostname/IP pairs.
1148 1146 */
1149 1147 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
1150 1148 print_status(500, "(error allocating hostname nvlist)");
1151 1149 goto cleanup;
1152 1150 }
1153 1151
1154 1152 /*
1155 1153 * Extract and resolve hostnames from CNs.
1156 1154 */
1157 1155 if (netboot_ftw(NB_CLIENT_CERT, net, cid,
1158 1156 get_hostnames, nvl) == WBCGI_FTW_CBERR ||
1159 1157 netboot_ftw(NB_CA_CERT, net, cid,
1160 1158 get_hostnames, nvl) == WBCGI_FTW_CBERR) {
1161 1159 goto cleanup;
1162 1160 }
1163 1161
1164 1162 /*
1165 1163 * Extract and resolve hostnames from any URLs in bootconf.
1166 1164 */
1167 1165 for (i = 0; bc_urls[i] != NULL; ++i) {
1168 1166 char *urlstr;
1169 1167 url_t url;
1170 1168
1171 1169 if ((urlstr = bootconf_get(&bc_handle, bc_urls[i])) != NULL &&
1172 1170 url_parse(urlstr, &url) == URL_PARSE_SUCCESS) {
1173 1171 if (!resolve_hostname(url.hport.hostname,
1174 1172 nvl, B_FALSE)) {
1175 1173 goto cleanup;
1176 1174 }
1177 1175 }
1178 1176 }
1179 1177
1180 1178 /*
1181 1179 * If there is a resolve-hosts list in bootconf, resolve those
1182 1180 * hostnames too.
1183 1181 */
1184 1182 if ((hostslist = bootconf_get(&bc_handle, BC_RESOLVE_HOSTS)) != NULL) {
1185 1183 char *hostname;
1186 1184
1187 1185 for (hostname = strtok(hostslist, ","); hostname != NULL;
1188 1186 hostname = strtok(NULL, ",")) {
1189 1187 if (!resolve_hostname(hostname, nvl, B_FALSE)) {
1190 1188 goto cleanup;
1191 1189 }
1192 1190 }
1193 1191 }
1194 1192
1195 1193 /*
1196 1194 * Now write the hostname/IP pairs gathered to the hosts file.
1197 1195 */
1198 1196 if ((hostfd = open(hostsfile,
1199 1197 O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 ||
1200 1198 (hostfp = fdopen(hostfd, "w+")) == NULL) {
1201 1199 print_status(500, "(error creating hosts file)");
1202 1200 goto cleanup;
1203 1201 }
1204 1202 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
1205 1203 nvp = nvlist_next_nvpair(nvl, nvp)) {
1206 1204 char *hostname;
1207 1205 char *ipstr;
1208 1206
1209 1207 hostname = nvpair_name(nvp);
1210 1208 if (nvpair_value_string(nvp, &ipstr) != 0) {
1211 1209 print_status(500, "(nvl error writing hosts file)");
1212 1210 goto cleanup;
1213 1211 }
1214 1212
1215 1213 if (fprintf(hostfp, "%s\t%s\n", ipstr, hostname) < 0) {
1216 1214 print_status(500, "(error writing hosts file)");
1217 1215 goto cleanup;
1218 1216 }
1219 1217 }
1220 1218
1221 1219 ret = B_TRUE;
1222 1220 cleanup:
1223 1221 if (nvl != NULL) {
1224 1222 nvlist_free(nvl);
1225 1223 }
1226 1224 if (hostfp != NULL) {
1227 1225 /*
1228 1226 * hostfd is automatically closed as well.
1229 1227 */
1230 1228 (void) fclose(hostfp);
1231 1229 }
1232 1230
1233 1231 return (ret);
1234 1232 }
1235 1233
1236 1234 static boolean_t
1237 1235 bootfile_payload(const char *docroot, char **bootpathp)
1238 1236 {
1239 1237 boolean_t ret = B_FALSE;
1240 1238 char *boot_file;
1241 1239 struct stat sbuf;
1242 1240
1243 1241 if ((boot_file = bootconf_get(&bc_handle, BC_BOOT_FILE)) == NULL) {
1244 1242 print_status(500, "(boot_file must be specified)");
1245 1243 goto cleanup;
1246 1244 }
1247 1245 if ((*bootpathp = make_path(docroot, boot_file)) == NULL) {
1248 1246 goto cleanup;
1249 1247 }
1250 1248 if (!WBCGI_FILE_EXISTS(*bootpathp, sbuf)) {
1251 1249 print_status(500, "(boot_file missing)");
1252 1250 goto cleanup;
1253 1251 }
1254 1252
1255 1253 ret = B_TRUE;
1256 1254 cleanup:
1257 1255 return (ret);
1258 1256 }
1259 1257
1260 1258 /*
1261 1259 * Create the wanboot file system whose contents are determined by the
1262 1260 * security configuration specified in bootconf.
1263 1261 */
1264 1262 static boolean_t
1265 1263 wanbootfs_payload(const char *net, const char *cid, const char *nonce,
1266 1264 const char *bootconf, char **wanbootfs_imagep)
1267 1265 {
1268 1266 int ret = B_FALSE;
1269 1267
1270 1268 char *server_authentication;
1271 1269 char *client_authentication;
1272 1270 char *scf;
1273 1271
1274 1272 char *bootfs_dir = NULL;
1275 1273 char *bootfs_etc_dir = NULL;
1276 1274 char *bootfs_etc_inet_dir = NULL;
1277 1275 char *bootfs_dev_dir = NULL;
1278 1276
1279 1277 char *systemconf = NULL;
1280 1278 char *keystorepath = NULL;
1281 1279 char *certstorepath = NULL;
1282 1280 char *truststorepath = NULL;
1283 1281 char *bootconfpath = NULL;
1284 1282 char *systemconfpath = NULL;
1285 1283 char *urandompath = NULL;
1286 1284 char *noncepath = NULL;
1287 1285 char *hostspath = NULL;
1288 1286 char *etc_hostspath = NULL;
1289 1287 char *timestamppath = NULL;
1290 1288
1291 1289 boolean_t authenticate_client;
1292 1290 boolean_t authenticate_server;
1293 1291
1294 1292 struct stat sbuf;
1295 1293
1296 1294 /*
1297 1295 * Initialize SSL stuff.
1298 1296 */
1299 1297 sunw_crypto_init();
1300 1298
1301 1299 /*
1302 1300 * Get the security strategy values.
1303 1301 */
1304 1302 client_authentication = bootconf_get(&bc_handle,
1305 1303 BC_CLIENT_AUTHENTICATION);
1306 1304 authenticate_client = (client_authentication != NULL &&
1307 1305 strcmp(client_authentication, "yes") == 0);
1308 1306 server_authentication = bootconf_get(&bc_handle,
1309 1307 BC_SERVER_AUTHENTICATION);
1310 1308 authenticate_server = (server_authentication != NULL &&
1311 1309 strcmp(server_authentication, "yes") == 0);
1312 1310
1313 1311 /*
1314 1312 * Make a temporary directory structure for the wanboot file system.
1315 1313 */
1316 1314 if ((bootfs_dir = gen_tmppath("bootfs_dir", net, cid)) == NULL ||
1317 1315 (bootfs_etc_dir = make_path(bootfs_dir, "etc")) == NULL ||
1318 1316 (bootfs_etc_inet_dir = make_path(bootfs_etc_dir, "inet")) == NULL ||
1319 1317 (bootfs_dev_dir = make_path(bootfs_dir, "dev")) == NULL) {
1320 1318 goto cleanup;
1321 1319 }
1322 1320 if (mkdirp(bootfs_dir, 0700) ||
1323 1321 mkdirp(bootfs_etc_dir, 0700) ||
1324 1322 mkdirp(bootfs_etc_inet_dir, 0700) ||
1325 1323 mkdirp(bootfs_dev_dir, 0700)) {
1326 1324 print_status(500, "(error creating wanbootfs dir structure)");
1327 1325 goto cleanup;
1328 1326 }
1329 1327
1330 1328 if (authenticate_client) {
1331 1329 /*
1332 1330 * Add the client private key.
1333 1331 */
1334 1332 if ((keystorepath = make_path(bootfs_dir,
1335 1333 NB_CLIENT_KEY)) == NULL ||
1336 1334 netboot_ftw(NB_CLIENT_KEY, net, cid,
1337 1335 create_keystore, keystorepath) != WBCGI_FTW_CBOK) {
1338 1336 goto cleanup;
1339 1337 }
1340 1338
1341 1339 /*
1342 1340 * Add the client certificate.
1343 1341 */
1344 1342 if ((certstorepath = make_path(bootfs_dir,
1345 1343 NB_CLIENT_CERT)) == NULL ||
1346 1344 netboot_ftw(NB_CLIENT_CERT, net, cid,
1347 1345 copy_certstore, certstorepath) != WBCGI_FTW_CBOK) {
1348 1346 goto cleanup;
1349 1347 }
1350 1348 }
1351 1349
1352 1350 if (authenticate_client || authenticate_server) {
1353 1351 /*
1354 1352 * Add the trustfile; at least one truststore must exist.
1355 1353 */
1356 1354 if ((truststorepath = make_path(bootfs_dir,
1357 1355 NB_CA_CERT)) == NULL) {
1358 1356 goto cleanup;
1359 1357 }
1360 1358 if (netboot_ftw(NB_CA_CERT, net, cid,
1361 1359 noact_cb, NULL) != WBCGI_FTW_CBOK) {
1362 1360 print_status(500, "(truststore not found)");
1363 1361 }
1364 1362 if (netboot_ftw(NB_CA_CERT, net, cid,
1365 1363 build_trustfile, truststorepath) == WBCGI_FTW_CBERR) {
1366 1364 goto cleanup;
1367 1365 }
1368 1366
1369 1367 /*
1370 1368 * Create the /dev/urandom file.
1371 1369 */
1372 1370 if ((urandompath = make_path(bootfs_dev_dir,
1373 1371 "urandom")) == NULL ||
1374 1372 !create_urandom(urandompath)) {
1375 1373 goto cleanup;
1376 1374 }
1377 1375 }
1378 1376
1379 1377 /*
1380 1378 * Add the wanboot.conf(4) file.
1381 1379 */
1382 1380 if ((bootconfpath = make_path(bootfs_dir, NB_WANBOOT_CONF)) == NULL ||
1383 1381 !copy_file(bootconf, bootconfpath)) {
1384 1382 goto cleanup;
1385 1383 }
1386 1384
1387 1385 /*
1388 1386 * Add the system_conf file if present.
1389 1387 */
1390 1388 if ((scf = bootconf_get(&bc_handle, BC_SYSTEM_CONF)) != NULL) {
1391 1389 if (netboot_ftw(scf, net, cid,
1392 1390 set_pathname, &systemconf) != WBCGI_FTW_CBOK) {
1393 1391 print_status(500, "(system_conf file not found)");
1394 1392 goto cleanup;
1395 1393 }
1396 1394 if ((systemconfpath = make_path(bootfs_dir,
1397 1395 NB_SYSTEM_CONF)) == NULL ||
1398 1396 !copy_file(systemconf, systemconfpath)) {
1399 1397 goto cleanup;
1400 1398 }
1401 1399 }
1402 1400
1403 1401 /*
1404 1402 * Create the /nonce file.
1405 1403 */
1406 1404 if ((noncepath = make_path(bootfs_dir, "nonce")) == NULL ||
1407 1405 !create_nonce(noncepath, nonce)) {
1408 1406 goto cleanup;
1409 1407 }
1410 1408
1411 1409 /*
1412 1410 * Create an /etc/inet/hosts file by extracting hostnames from CN,
1413 1411 * URLs in bootconf and resolve-hosts in bootconf.
1414 1412 */
1415 1413 if ((hostspath = make_path(bootfs_etc_inet_dir, "hosts")) == NULL ||
1416 1414 !create_hostsfile(hostspath, net, cid)) {
1417 1415 goto cleanup;
1418 1416 }
1419 1417
1420 1418 /*
1421 1419 * We would like to create a symbolic link etc/hosts -> etc/inet/hosts,
1422 1420 * but unfortunately the HSFS support in the standalone doesn't handle
1423 1421 * symlinks.
1424 1422 */
1425 1423 if ((etc_hostspath = make_path(bootfs_etc_dir, "hosts")) == NULL ||
1426 1424 !copy_file(hostspath, etc_hostspath)) {
1427 1425 goto cleanup;
1428 1426 }
1429 1427
1430 1428 /*
1431 1429 * Create the /timestamp file.
1432 1430 */
1433 1431 if ((timestamppath = make_path(bootfs_dir, "timestamp")) == NULL ||
1434 1432 !create_timestamp(timestamppath, "timestamp")) {
1435 1433 goto cleanup;
1436 1434 }
1437 1435
1438 1436 /*
1439 1437 * Create an HSFS file system for the directory.
1440 1438 */
1441 1439 if ((*wanbootfs_imagep = gen_tmppath("wanbootfs", net, cid)) == NULL ||
1442 1440 !mkisofs(bootfs_dir, *wanbootfs_imagep)) {
1443 1441 goto cleanup;
1444 1442 }
1445 1443
1446 1444 ret = B_TRUE;
1447 1445 cleanup:
1448 1446 /*
1449 1447 * Clean up temporary files and directories.
1450 1448 */
1451 1449 if (keystorepath != NULL &&
1452 1450 WBCGI_FILE_EXISTS(keystorepath, sbuf)) {
1453 1451 (void) unlink(keystorepath);
1454 1452 }
1455 1453 if (certstorepath != NULL &&
1456 1454 WBCGI_FILE_EXISTS(certstorepath, sbuf)) {
1457 1455 (void) unlink(certstorepath);
1458 1456 }
1459 1457 if (truststorepath != NULL &&
1460 1458 WBCGI_FILE_EXISTS(truststorepath, sbuf)) {
1461 1459 (void) unlink(truststorepath);
1462 1460 }
1463 1461 if (bootconfpath != NULL &&
1464 1462 WBCGI_FILE_EXISTS(bootconfpath, sbuf)) {
1465 1463 (void) unlink(bootconfpath);
1466 1464 }
1467 1465 if (systemconfpath != NULL &&
1468 1466 WBCGI_FILE_EXISTS(systemconfpath, sbuf)) {
1469 1467 (void) unlink(systemconfpath);
1470 1468 }
1471 1469 if (urandompath != NULL &&
1472 1470 WBCGI_FILE_EXISTS(urandompath, sbuf)) {
1473 1471 (void) unlink(urandompath);
1474 1472 }
1475 1473 if (noncepath != NULL &&
1476 1474 WBCGI_FILE_EXISTS(noncepath, sbuf)) {
1477 1475 (void) unlink(noncepath);
1478 1476 }
1479 1477 if (hostspath != NULL &&
1480 1478 WBCGI_FILE_EXISTS(hostspath, sbuf)) {
1481 1479 (void) unlink(hostspath);
1482 1480 }
1483 1481 if (etc_hostspath != NULL &&
1484 1482 WBCGI_FILE_EXISTS(etc_hostspath, sbuf)) {
1485 1483 (void) unlink(etc_hostspath);
1486 1484 }
1487 1485 if (timestamppath != NULL &&
1488 1486 WBCGI_FILE_EXISTS(timestamppath, sbuf)) {
1489 1487 (void) unlink(timestamppath);
1490 1488 }
1491 1489
1492 1490 if (bootfs_etc_inet_dir != NULL &&
1493 1491 WBCGI_DIR_EXISTS(bootfs_etc_inet_dir, sbuf)) {
1494 1492 (void) rmdir(bootfs_etc_inet_dir);
1495 1493 }
1496 1494 if (bootfs_etc_dir != NULL &&
1497 1495 WBCGI_DIR_EXISTS(bootfs_etc_dir, sbuf)) {
1498 1496 (void) rmdir(bootfs_etc_dir);
1499 1497 }
1500 1498 if (bootfs_dev_dir != NULL &&
1501 1499 WBCGI_DIR_EXISTS(bootfs_dev_dir, sbuf)) {
1502 1500 (void) rmdir(bootfs_dev_dir);
1503 1501 }
1504 1502 if (bootfs_dir != NULL &&
1505 1503 WBCGI_DIR_EXISTS(bootfs_dir, sbuf)) {
1506 1504 (void) rmdir(bootfs_dir);
1507 1505 }
1508 1506
1509 1507 /*
1510 1508 * Free allocated memory.
1511 1509 */
1512 1510 free_path(&bootfs_dir);
1513 1511 free_path(&bootfs_etc_dir);
1514 1512 free_path(&bootfs_etc_inet_dir);
1515 1513 free_path(&bootfs_dev_dir);
1516 1514
1517 1515 free_path(&systemconf);
1518 1516 free_path(&keystorepath);
1519 1517 free_path(&certstorepath);
1520 1518 free_path(&truststorepath);
1521 1519 free_path(&bootconfpath);
1522 1520 free_path(&systemconfpath);
1523 1521 free_path(&urandompath);
1524 1522 free_path(&noncepath);
1525 1523 free_path(&hostspath);
1526 1524 free_path(&etc_hostspath);
1527 1525 free_path(×tamppath);
1528 1526
1529 1527 return (ret);
1530 1528 }
1531 1529
1532 1530 static boolean_t
1533 1531 miniroot_payload(const char *net, const char *cid, const char *docroot,
1534 1532 char **rootpathp, char **rootinfop, boolean_t *https_rootserverp)
1535 1533 {
1536 1534 boolean_t ret = B_FALSE;
1537 1535 char *root_server;
1538 1536 char *root_file;
1539 1537 url_t url;
1540 1538 struct stat sbuf;
1541 1539 char sizebuf[WBCGI_MAXBUF];
1542 1540 int chars;
1543 1541 int fd = -1;
1544 1542
1545 1543 if ((root_server = bootconf_get(&bc_handle, BC_ROOT_SERVER)) == NULL) {
1546 1544 print_status(500, "(root_server must be specified)");
1547 1545 goto cleanup;
1548 1546 }
1549 1547 if (url_parse(root_server, &url) != URL_PARSE_SUCCESS) {
1550 1548 print_status(500, "(root_server URL is invalid)");
1551 1549 }
1552 1550 *https_rootserverp = url.https;
1553 1551
1554 1552 if ((root_file = bootconf_get(&bc_handle, BC_ROOT_FILE)) == NULL) {
1555 1553 print_status(500, "(rootfile must be specified)");
1556 1554 goto cleanup;
1557 1555 }
1558 1556 if ((*rootpathp = make_path(docroot, root_file)) == NULL) {
1559 1557 goto cleanup;
1560 1558 }
1561 1559 if (!WBCGI_FILE_EXISTS(*rootpathp, sbuf)) {
1562 1560 print_status(500, "(root filesystem image missing)");
1563 1561 goto cleanup;
1564 1562 }
1565 1563
1566 1564 if ((*rootinfop = gen_tmppath("mrinfo", net, cid)) == NULL) {
1567 1565 goto cleanup;
1568 1566 }
1569 1567 if ((chars = snprintf(sizebuf, sizeof (sizebuf), "%ld",
1570 1568 sbuf.st_size)) < 0 || chars > sizeof (sizebuf) ||
1571 1569 (fd = open(*rootinfop,
1572 1570 O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1 ||
1573 1571 !write_buffer(fd, sizebuf, strlen(sizebuf))) {
1574 1572 print_status(500, "(error creating miniroot info file)");
1575 1573 goto cleanup;
1576 1574 }
1577 1575
1578 1576 ret = B_TRUE;
1579 1577 cleanup:
1580 1578 if (fd != -1) {
1581 1579 (void) close(fd);
1582 1580 }
1583 1581
1584 1582 return (ret);
1585 1583 }
1586 1584
1587 1585 static boolean_t
1588 1586 deliver_payload(const char *payload, const char *payload_hash)
1589 1587 {
1590 1588 int fd = fileno(stdout);
1591 1589 struct stat payload_buf, hash_buf;
1592 1590 int chars;
1593 1591 char main_header[WBCGI_MAXBUF];
1594 1592 char multi_header[WBCGI_MAXBUF];
1595 1593 char multi_header1[WBCGI_MAXBUF];
1596 1594 char multi_header2[WBCGI_MAXBUF];
1597 1595 char multi_end[WBCGI_MAXBUF];
1598 1596 size_t msglen;
1599 1597
1600 1598 if (!WBCGI_FILE_EXISTS(payload, payload_buf) ||
1601 1599 !WBCGI_FILE_EXISTS(payload_hash, hash_buf)) {
1602 1600 print_status(500, "(payload/hash file(s) missing)");
1603 1601 return (B_FALSE);
1604 1602 }
1605 1603
1606 1604 /*
1607 1605 * Multi-part header.
1608 1606 */
1609 1607 if ((chars = snprintf(multi_header, sizeof (multi_header),
1610 1608 "%s--%s%s%sapplication/octet-stream%s%s", WBCGI_CRNL,
1611 1609 WBCGI_WANBOOT_BNDTXT, WBCGI_CRNL, WBCGI_CONTENT_TYPE, WBCGI_CRNL,
1612 1610 WBCGI_CONTENT_LENGTH)) < 0 || chars > sizeof (multi_header)) {
1613 1611 print_status(500, "(error creating multi_header)");
1614 1612 return (B_FALSE);
1615 1613 }
1616 1614
1617 1615 /*
1618 1616 * Multi-part header for part one.
1619 1617 */
1620 1618 if ((chars = snprintf(multi_header1, sizeof (multi_header1),
1621 1619 "%s%ld%s%s", multi_header, payload_buf.st_size, WBCGI_CRNL,
1622 1620 WBCGI_CRNL)) < 0 || chars > sizeof (multi_header1)) {
1623 1621 print_status(500, "(error creating multi_header1)");
1624 1622 return (B_FALSE);
1625 1623 }
1626 1624
1627 1625 /*
1628 1626 * Multi-part header for part two.
1629 1627 */
1630 1628 if ((chars = snprintf(multi_header2, sizeof (multi_header2),
1631 1629 "%s%ld%s%s", multi_header, hash_buf.st_size, WBCGI_CRNL,
1632 1630 WBCGI_CRNL)) < 0 || chars > sizeof (multi_header2)) {
1633 1631 print_status(500, "(error creating multi_header2)");
1634 1632 return (B_FALSE);
1635 1633 }
1636 1634
1637 1635 /*
1638 1636 * End-of-parts Trailer.
1639 1637 */
1640 1638 if ((chars = snprintf(multi_end, sizeof (multi_end),
1641 1639 "%s--%s--%s", WBCGI_CRNL, WBCGI_WANBOOT_BNDTXT,
1642 1640 WBCGI_CRNL)) < 0 || chars > sizeof (multi_end)) {
1643 1641 print_status(500, "(error creating multi_end)");
1644 1642 return (B_FALSE);
1645 1643 }
1646 1644
1647 1645 /*
1648 1646 * Message header.
1649 1647 */
1650 1648 msglen = payload_buf.st_size + hash_buf.st_size +
1651 1649 strlen(multi_header1) + strlen(multi_header2) + strlen(multi_end);
1652 1650
1653 1651 if ((chars = snprintf(main_header, sizeof (main_header),
1654 1652 "%s%u%s%smultipart/mixed; boundary=%s%s%s", WBCGI_CONTENT_LENGTH,
1655 1653 msglen, WBCGI_CRNL, WBCGI_CONTENT_TYPE, WBCGI_WANBOOT_BNDTXT,
1656 1654 WBCGI_CRNL, WBCGI_CRNL)) < 0 || chars > sizeof (main_header)) {
1657 1655 print_status(500, "(error creating main_header)");
1658 1656 return (B_FALSE);
1659 1657 }
1660 1658
1661 1659 /*
1662 1660 * Write the message out. If things fall apart during this then
1663 1661 * there's no way to report the error back to the client.
1664 1662 */
1665 1663 if (!write_buffer(fd, main_header, strlen(main_header)) ||
1666 1664 !write_buffer(fd, multi_header1, strlen(multi_header1)) ||
1667 1665 !write_file(fd, payload, payload_buf.st_size) ||
1668 1666 !write_buffer(fd, multi_header2, strlen(multi_header2)) ||
1669 1667 !write_file(fd, payload_hash, hash_buf.st_size) ||
1670 1668 !write_buffer(fileno(stdout), multi_end, strlen(multi_end))) {
1671 1669 return (B_FALSE);
1672 1670 }
1673 1671
1674 1672 return (B_TRUE);
1675 1673 }
1676 1674
1677 1675
1678 1676 /*ARGSUSED*/
1679 1677 int
1680 1678 main(int argc, char **argv)
1681 1679 {
1682 1680 int ret = WBCGI_STATUS_ERR;
1683 1681 struct stat sbuf;
1684 1682 int content;
1685 1683 char *net;
1686 1684 char *cid;
1687 1685 char *nonce;
1688 1686 char *docroot;
1689 1687 char *payload;
1690 1688 char *signature_type;
1691 1689 char *encryption_type;
1692 1690 char *bootconf = NULL;
1693 1691 char *keyfile = NULL;
1694 1692 char *bootpath = NULL;
1695 1693 char *wanbootfs_image = NULL;
1696 1694 char *rootpath = NULL;
1697 1695 char *miniroot_info = NULL;
1698 1696 char *encr_payload = NULL;
1699 1697 char *payload_hash = NULL;
1700 1698 boolean_t https_rootserver;
1701 1699
1702 1700 /*
1703 1701 * Process the query string.
1704 1702 */
1705 1703 if (!get_request_info(&content, &net, &cid, &nonce, &docroot)) {
1706 1704 goto cleanup;
1707 1705 }
1708 1706
1709 1707 /*
1710 1708 * Sanity check that the netboot directory exists.
1711 1709 */
1712 1710 if (!WBCGI_DIR_EXISTS(NB_NETBOOT_ROOT, sbuf)) {
1713 1711 print_status(500, "(" NB_NETBOOT_ROOT " does not exist)");
1714 1712 goto cleanup;
1715 1713 }
1716 1714
1717 1715 /*
1718 1716 * Get absolute bootconf pathname.
1719 1717 */
1720 1718 if (netboot_ftw(NB_WANBOOT_CONF, net, cid,
1721 1719 set_pathname, &bootconf) != WBCGI_FTW_CBOK) {
1722 1720 print_status(500, "(wanboot.conf not found)");
1723 1721 goto cleanup;
1724 1722 }
1725 1723
1726 1724 /*
1727 1725 * Initialize bc_handle from the given wanboot.conf file.
1728 1726 */
1729 1727 if (bootconf_init(&bc_handle, bootconf) != BC_SUCCESS) {
1730 1728 char message[WBCGI_MAXBUF];
1731 1729 int chars;
1732 1730
1733 1731 chars = snprintf(message, sizeof (message),
1734 1732 "(wanboot.conf error: %s)", bootconf_errmsg(&bc_handle));
1735 1733 if (chars > 0 && chars < sizeof (message))
1736 1734 print_status(500, message);
1737 1735 else
1738 1736 print_status(500, "(wanboot.conf error)");
1739 1737 goto cleanup;
1740 1738 }
1741 1739
1742 1740 /*
1743 1741 * Get and check signature and encryption types,
1744 1742 * presence of helper utilities, keystore, etc.
1745 1743 */
1746 1744 if ((signature_type = bootconf_get(&bc_handle,
1747 1745 BC_SIGNATURE_TYPE)) != NULL) {
1748 1746 if (!WBCGI_FILE_EXISTS(WBCGI_HMAC_PATH, sbuf)) {
1749 1747 print_status(500, "(hmac utility not found)");
1750 1748 goto cleanup;
1751 1749 }
1752 1750 if (keyfile == NULL && netboot_ftw(NB_CLIENT_KEY, net, cid,
1753 1751 set_pathname, &keyfile) != WBCGI_FTW_CBOK) {
1754 1752 print_status(500, "(keystore not found)");
1755 1753 goto cleanup;
1756 1754 }
1757 1755 if (!check_key_type(keyfile, signature_type, WBKU_HASH_KEY)) {
1758 1756 print_status(500, "(hash key not found)");
1759 1757 goto cleanup;
1760 1758 }
1761 1759 }
1762 1760 if ((encryption_type = bootconf_get(&bc_handle,
1763 1761 BC_ENCRYPTION_TYPE)) != NULL) {
1764 1762 if (signature_type == NULL) {
1765 1763 print_status(500, "(encrypted but not signed)");
1766 1764 goto cleanup;
1767 1765 }
1768 1766 if (!WBCGI_FILE_EXISTS(WBCGI_ENCR_PATH, sbuf)) {
1769 1767 print_status(500, "(encr utility not found)");
1770 1768 goto cleanup;
1771 1769 }
1772 1770 if (keyfile == NULL && netboot_ftw(NB_CLIENT_KEY, net, cid,
1773 1771 set_pathname, &keyfile) != WBCGI_FTW_CBOK) {
1774 1772 print_status(500, "(keystore not found)");
1775 1773 goto cleanup;
1776 1774 }
1777 1775 if (!check_key_type(keyfile, encryption_type, WBKU_ENCR_KEY)) {
1778 1776 print_status(500, "(encr key not found)");
1779 1777 goto cleanup;
1780 1778 }
1781 1779 }
1782 1780
1783 1781 /*
1784 1782 * Determine/create our payload.
1785 1783 */
1786 1784 switch (content) {
1787 1785 case WBCGI_CONTENT_BOOTFILE:
1788 1786 if (!bootfile_payload(docroot, &bootpath)) {
1789 1787 goto cleanup;
1790 1788 }
1791 1789 payload = bootpath;
1792 1790
1793 1791 break;
1794 1792
1795 1793 case WBCGI_CONTENT_BOOTFS:
1796 1794 if (!wanbootfs_payload(net, cid, nonce,
1797 1795 bootconf, &wanbootfs_image)) {
1798 1796 goto cleanup;
1799 1797 }
1800 1798 payload = wanbootfs_image;
1801 1799
1802 1800 break;
1803 1801
1804 1802 case WBCGI_CONTENT_ROOTFS:
1805 1803 if (!miniroot_payload(net, cid, docroot,
1806 1804 &rootpath, &miniroot_info, &https_rootserver)) {
1807 1805 goto cleanup;
1808 1806 }
1809 1807 payload = rootpath;
1810 1808
1811 1809 break;
1812 1810 }
1813 1811
1814 1812 /*
1815 1813 * Encrypt the payload if necessary.
1816 1814 */
1817 1815 if (content != WBCGI_CONTENT_BOOTFILE &&
1818 1816 content != WBCGI_CONTENT_ROOTFS &&
1819 1817 encryption_type != NULL) {
1820 1818 if ((encr_payload = gen_tmppath("encr", net, cid)) == NULL) {
1821 1819 goto cleanup;
1822 1820 }
1823 1821
1824 1822 if (!encrypt_payload(payload, encr_payload, keyfile,
1825 1823 encryption_type)) {
1826 1824 goto cleanup;
1827 1825 }
1828 1826
1829 1827 payload = encr_payload;
1830 1828 }
1831 1829
1832 1830 /*
1833 1831 * Compute the hash (actual or null).
1834 1832 */
1835 1833 if ((payload_hash = gen_tmppath("hash", net, cid)) == NULL) {
1836 1834 goto cleanup;
1837 1835 }
1838 1836
1839 1837 if (signature_type != NULL &&
1840 1838 (content != WBCGI_CONTENT_ROOTFS || !https_rootserver)) {
1841 1839 if (!hash_payload(payload, payload_hash, keyfile)) {
1842 1840 goto cleanup;
1843 1841 }
1844 1842 } else {
1845 1843 if (!create_null_hash(payload_hash)) {
1846 1844 goto cleanup;
1847 1845 }
1848 1846 }
1849 1847
1850 1848 /*
1851 1849 * For the rootfs the actual payload transmitted is the file
1852 1850 * containing the size of the rootfs (as a string of ascii digits);
1853 1851 * point payload at this instead.
1854 1852 */
1855 1853 if (content == WBCGI_CONTENT_ROOTFS) {
1856 1854 payload = miniroot_info;
1857 1855 }
1858 1856
1859 1857 /*
1860 1858 * Finally, deliver the payload and hash as a multipart message.
1861 1859 */
1862 1860 if (!deliver_payload(payload, payload_hash)) {
1863 1861 goto cleanup;
1864 1862 }
1865 1863
1866 1864 ret = WBCGI_STATUS_OK;
1867 1865 cleanup:
1868 1866 /*
1869 1867 * Clean up temporary files.
1870 1868 */
1871 1869 if (wanbootfs_image != NULL &&
1872 1870 WBCGI_FILE_EXISTS(wanbootfs_image, sbuf)) {
1873 1871 (void) unlink(wanbootfs_image);
1874 1872 }
1875 1873 if (miniroot_info != NULL &&
1876 1874 WBCGI_FILE_EXISTS(miniroot_info, sbuf)) {
1877 1875 (void) unlink(miniroot_info);
1878 1876 }
1879 1877 if (encr_payload != NULL &&
1880 1878 WBCGI_FILE_EXISTS(encr_payload, sbuf)) {
1881 1879 (void) unlink(encr_payload);
1882 1880 }
1883 1881 if (payload_hash != NULL &&
1884 1882 WBCGI_FILE_EXISTS(payload_hash, sbuf)) {
1885 1883 (void) unlink(payload_hash);
1886 1884 }
1887 1885
1888 1886 /*
1889 1887 * Free up any allocated strings.
1890 1888 */
1891 1889 free_path(&bootconf);
1892 1890 free_path(&keyfile);
1893 1891 free_path(&bootpath);
1894 1892 free_path(&wanbootfs_image);
1895 1893 free_path(&rootpath);
1896 1894 free_path(&miniroot_info);
1897 1895 free_path(&encr_payload);
1898 1896 free_path(&payload_hash);
1899 1897
1900 1898 bootconf_end(&bc_handle);
1901 1899
1902 1900 return (ret);
1903 1901 }
↓ open down ↓ |
800 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX