1/* 2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 This program implements a PPP central server, listening for incoming calls 26 and forking/execing pppd processes to handle the incoming sessions. 27 This is primarily designed to imnplement the VPN server, hence is name 'vpnd'. 28 29 The architecture of this program, and in particular the plugin management, is 30 largely inspired by pppd. 31 32*/ 33 34#include <stdio.h> 35#include <ctype.h> 36#include <stdlib.h> 37#include <string.h> 38#include <unistd.h> 39#include <signal.h> 40#include <errno.h> 41#include <fcntl.h> 42#include <syslog.h> 43#include <netdb.h> 44#include <paths.h> 45#include <sys/queue.h> 46 47#include <sys/param.h> 48#include <sys/types.h> 49#include <sys/wait.h> 50#include <sys/time.h> 51#include <sys/resource.h> 52#include <sys/stat.h> 53#include <sys/socket.h> 54#include <sys/sysctl.h> 55#include <net/if.h> 56#include <netinet/in.h> 57#include <arpa/inet.h> 58#include <libgen.h> 59 60#include <CoreFoundation/CoreFoundation.h> 61#include <SystemConfiguration/SystemConfiguration.h> 62#include "../../Family/if_ppplink.h" 63 64#include "vpnd.h" 65#include "vpnoptions.h" 66#include "vpnplugins.h" 67#include "cf_utils.h" 68#include "ipsec_utils.h" 69 70 71// ---------------------------------------------------------------------------- 72// Globals 73// ---------------------------------------------------------------------------- 74char *no_ppp_msg = "This system lacks PPP kernel support\n"; 75static char pid_path[MAXPATHLEN] = _PATH_VARRUN DAEMON_NAME "-"; // pid file path - the rest will be filled in later 76// ---------------------------------------------------------------------------- 77// Private Globals 78// ---------------------------------------------------------------------------- 79 80static volatile int rcvd_sig_child = 0; 81static volatile int rcvd_sig_hup = 0; 82static volatile int rcvd_sig_usr1 = 0; 83static volatile int terminate = 0; 84static int forwarding = -1; 85static FILE *logfile = 0; 86static int stdio_is_valid = 1; 87static struct vpn_params *params; 88 89static int spawn(struct vpn_params *params); 90static void close_file_descriptors(void); 91static void redirect_std_file(void); 92static void detach(void); 93static void write_pid_file(struct vpn_params *params); 94static void delete_pid_file(void); 95static void sig_chld(int inSignal); 96static void sig_term(int inSignal); 97static void sig_hup(int inSignal); 98static void setup_signal_handlers(void); 99static int set_forwarding(int *oldval, int newval); 100static void create_log_file(char *inLogPath); 101static void close_log_file(void); 102void vpnlog(int nSyslogPriority, char *format_str, ...); 103static void dump_params(struct vpn_params *params); 104 105// ---------------------------------------------------------------------------- 106// main 107// ---------------------------------------------------------------------------- 108int main (int argc, char *argv[]) 109{ 110 111 int i; 112 113 /* 114 * Check that we are running as root. 115 */ 116 if (geteuid() != 0) { 117 fprintf(stderr, "must be root to run %s, since it is not setuid-root\n", argv[0]); 118 exit(EXIT_NOT_ROOT); 119 } 120 121 122 params = (struct vpn_params*)malloc(sizeof (struct vpn_params)); 123 if (params == 0) 124 exit(EXIT_FATAL_ERROR); 125 bzero(params, sizeof(*params)); 126 127 // Close all non-standard file descriptors. 128 close_file_descriptors(); 129 130 /* 131 * Ensure that fds 0, 1, 2 are open, to /dev/null if nowhere else. 132 * This way we can close 0, 1, 2 in detach() without clobbering 133 * a fd that we are using. 134 */ 135 if ((i = open("/dev/null", O_RDWR)) >= 0) { 136 while (0 <= i && i <= 2) 137 i = dup(i); 138 if (i >= 0) 139 close(i); 140 } 141 142 /* 143 * open syslog facility. 144 */ 145 openlog("vpnd", LOG_PID | LOG_NDELAY, LOG_RAS); 146 147 /* 148 * read and process options. 149 */ 150 if (process_options(params, argc, argv)) 151 exit(EXIT_OPTION_ERROR); 152 153 /* Check if ppp is available in the kernel */ 154 if (!ppp_available()) { 155 vpnlog(LOG_ERR, "The PPP kernel extension could not be loaded\n"); 156 exit(EXIT_NO_KERNEL_SUPPORT); 157 } 158 159 // if no server id option - read active server list and 160 // launch a vpnd process for each 161 if (params->server_id == 0) { 162 close_file_descriptors(); // close all but std fd 163 redirect_std_file(); // redirect std 164 spawn(params); 165 exit(EXIT_OK); 166 } 167 168 vpnlog(LOG_NOTICE, "Server '%s' starting...\n", params->server_id); 169 170 open_dynamic_store(params); // open a connection to the dynamic store 171 init_address_lists(); // init the address lists 172 173 if (process_prefs(params)) { // prepare launch args 174 vpnlog(LOG_ERR, "Error processing prefs file\n"); 175 // <rdar://problem/7052049> return ok, otherwise launchd will most likely restart vpnd with the same erroneous prefs 176 exit(EXIT_OK); 177 } 178 if (check_conflicts(params)) // check if another server of this type already running 179 exit(EXIT_OPTION_ERROR); 180 181 if (kill_orphans(params)) // check for and kill orphan pppd processes running with the same 182 exit(EXIT_FATAL_ERROR); // server id left over from a crashed vpnd process. 183 184 if (params->log_path) 185 create_log_file(params->log_path); 186 187 if (init_plugin(params)) { 188 vpnlog(LOG_ERR, "Initialization of vpnd plugin failed\n"); 189 exit(EXIT_FATAL_ERROR); 190 } 191 if (get_plugin_args(params, 0)) { 192 vpnlog(LOG_ERR, "Error getting arguments from plugin\n"); 193 exit(EXIT_OPTION_ERROR); 194 } 195 196 if (params->debug) 197 dump_params(params); 198 199 setuid(geteuid()); 200 201 // OK, everything looks good. Daemonize now and redirect std fd's. 202 if (params->daemonize) { 203 stdio_is_valid = 0; 204 close_dynamic_store(params); // close it now, re-open after detach 205 detach(); 206 setsid(); 207 redirect_std_file(); 208 open_dynamic_store(params); // re-open after detach 209 vpnlog(LOG_NOTICE, "Server '%s' moved to background\n", params->server_id); 210 } 211 212 setup_signal_handlers(); 213 write_pid_file(params); /* Write out our pid like a good little daemon */ 214 publish_state(params); 215 216 /* activate IP forwarding */ 217 if (set_forwarding(&forwarding, 1)) 218 vpnlog(LOG_ERR, "Cannot activate IP forwarding (error %d)\n", errno); 219 220 /* now listen for connections*/ 221 vpnlog(LOG_NOTICE, "Listening for connections...\n"); 222 accept_connections(params); 223 224 /* restore IP forwarding to former state */ 225 if (set_forwarding(0, forwarding)) 226 vpnlog(LOG_ERR, "Cannot reset IP forwarding (error %d)\n", errno); 227 228 close_log_file(); 229 delete_pid_file(); 230 vpnlog(LOG_NOTICE, "Server '%s' stopped\n", params->server_id); 231 232 exit(EXIT_OK) ; 233} 234 235//----------------------------------------------------------------------------- 236// spawn - launch a copy of vpnd for each active server id 237//----------------------------------------------------------------------------- 238static int spawn(struct vpn_params *params) 239{ 240 int i, j, count; 241 char server[OPT_STR_LEN]; 242 pid_t pidChild = 0; 243 char *args[6]; 244 char *vpnd_prog = VPND_PRGM; 245 char *debug_opt = "-d"; 246 char *no_detach_opt = "-x"; 247 char *server_id_opt = "-i"; 248 CFArrayRef active_servers; 249 CFStringRef string; 250 251 // setup the common args 252 server[0] = 0; 253 args[0] = vpnd_prog; 254 i = 1; 255 if (params->debug) 256 args[i++] = debug_opt; 257 if (params->daemonize == 0) 258 args[i++] = no_detach_opt; 259 args[i++] = server_id_opt; 260 args[i++] = server; 261 args[i] = 0; // teminating zero 262 263 if ((active_servers = get_active_servers(params)) == 0) 264 return 0; // no active servers 265 count = CFArrayGetCount(active_servers); 266 267 // find and launch active server ids 268 for (j = 0; j < count; j++) { 269 string = CFArrayGetValueAtIndex(active_servers, j); 270 if (isString(string)) 271 CFStringGetCString(string, server, OPT_STR_LEN, kCFStringEncodingMacRoman); 272 else 273 continue; // skip it 274 275 switch (pidChild = fork ()) { 276 case 0: // in child 277 execve(PATH_VPND, args, NULL); // launch it 278 break; 279 case -1: // error 280 vpnlog(LOG_ERR, "Attempt to fork new vpnd failed\n") ; 281 return -1; 282 default: 283 vpnlog(LOG_INFO, "Launched vpnd process id '%d' for server id '%s'\n", pidChild, server); 284 break; 285 } 286 } 287 CFRelease(active_servers); 288 return 0; 289} 290 291//----------------------------------------------------------------------------- 292// change the ip forwarding setting. 293//----------------------------------------------------------------------------- 294static int set_forwarding(int *oldval, int newval) 295{ 296 size_t len = sizeof(int); 297 298 if (newval != 0 && newval != 1) 299 return 0; // ignore the command 300 301 return sysctlbyname("net.inet.ip.forwarding", oldval, &len, &newval, sizeof(int)); 302} 303 304//----------------------------------------------------------------------------- 305// close_file_descriptors - closes all file descriptors except std. 306//----------------------------------------------------------------------------- 307static void close_file_descriptors(void) 308{ 309 // Find the true upper limit on file descriptors. 310 register int i = OPEN_MAX; 311 register int nMin = STDERR_FILENO; 312 struct rlimit lim; 313 314 if (!getrlimit (RLIMIT_NOFILE, &lim)) 315 i = lim.rlim_cur; 316 else 317 vpnlog(LOG_ERR, "close_file_descriptors() - getrlimit() failed\n"); 318 319 // Close all file descriptors except std*. 320 while (--i > nMin) 321 close (i) ; 322} 323 324//----------------------------------------------------------------------------- 325// redirect_std_file - redirect standard file descriptors to /dev/null. 326//----------------------------------------------------------------------------- 327static void redirect_std_file(void) 328{ 329 int i; 330 331 // Handle stdin 332 i = open(_PATH_DEVNULL, O_RDONLY); 333 if ((i != -1) && (i != STDIN_FILENO)) { 334 dup2(i, STDIN_FILENO); 335 close (i); 336 } 337 338 // Handle stdout and stderr 339 i = open (_PATH_DEVNULL, O_WRONLY); 340 341 if (i != STDOUT_FILENO) 342 dup2(i, STDOUT_FILENO); 343 if (i != STDERR_FILENO) 344 dup2(i, STDERR_FILENO); 345 346 if ((i != -1) && (i != STDOUT_FILENO) && (i != STDERR_FILENO)) 347 close(i); 348 349} 350 351 352//----------------------------------------------------------------------------- 353// detach - closes all file descriptors for this process. 354//----------------------------------------------------------------------------- 355static void detach(void) 356{ 357 errno = 0; 358 switch (fork()) { 359 case 0: // in child 360 break; 361 case -1: // error 362 vpnlog(LOG_ERR, "Detach failed: errno= %d\n", errno); 363 /* FALLTHRU */ 364 default: // parent 365 exit(errno) ; 366 } 367} 368 369 370//----------------------------------------------------------------------------- 371// write_pid_file - writes out standard pid file at given path. 372//----------------------------------------------------------------------------- 373static void write_pid_file(struct vpn_params *params) 374{ 375 FILE *pidfile; 376 char subtype[OPT_STR_LEN]; 377 378 subtype[0] = 0; 379 if (params->serverSubTypeRef) 380 CFStringGetCString(params->serverSubTypeRef, subtype, OPT_STR_LEN, kCFStringEncodingUTF8); 381 if (subtype[0]) 382 strlcat(pid_path, subtype, sizeof(pid_path)); 383 strlcat(pid_path, ".pid", sizeof(pid_path)); 384 385 if ((pidfile = fopen(pid_path, "w")) != NULL) { 386 fprintf(pidfile, "%d\n", getpid()); 387 fclose(pidfile); 388 } else 389 vpnlog(LOG_WARNING, "Failed to create pid file %s: %m", pid_path); 390} 391 392//----------------------------------------------------------------------------- 393// delete_pid_file 394//----------------------------------------------------------------------------- 395static void delete_pid_file(void) 396{ 397 remove(pid_path); 398} 399 400// ---------------------------------------------------------------------------- 401// Log File Functions 402// ---------------------------------------------------------------------------- 403static char *log_time_string(time_t inNow, char *inTimeString, int maxLen) 404{ 405 struct tm *tmTime; 406 407 if (!inTimeString) 408 return 0; 409 410 tmTime = localtime(&inNow); 411 412 snprintf(inTimeString, maxLen, "%04d-%02d-%02d %02d:%02d:%02d %s", 413 tmTime->tm_year + 1900, tmTime->tm_mon + 1, tmTime->tm_mday, 414 tmTime->tm_hour, tmTime->tm_min, tmTime->tm_sec, 415 tmTime->tm_zone); 416 return inTimeString; 417} 418 419// ---------------------------------------------------------------------------- 420// create_log_file 421// ---------------------------------------------------------------------------- 422static void create_log_file(char *inLogPath) 423{ 424 char theTime[40]; 425 mode_t mask; 426 427 // Setup the log file. 428 429 mask = umask(S_IWGRP|S_IXGRP|S_IWOTH|S_IXOTH); 430 logfile = fopen(inLogPath, "a"); 431 mask = umask(mask); 432 433 /* if the first fopen fails, then it's likely to be due to an inexistant directory path. 434 * Create the directory subtree and try fopen again 435 */ 436 if (logfile == 0) 437 { 438 char *dirPath = dirname(inLogPath); 439 vpnlog(LOG_WARNING, "Warning: Creating directory for log file = %s\n", inLogPath); 440 makepath(dirPath); 441 logfile = fopen(inLogPath, "a"); 442 } 443 444 if(logfile == 0) 445 { 446 vpnlog(LOG_ERR, "Could not open log file = %s\n", inLogPath); 447 } 448 else { 449 fcntl(fileno(logfile), F_SETFD, 1); 450 451 // Add the file header only when first created. 452 //if (!ftell(logfile)) 453 // fprintf(logfile, "#Version: 1.0\n#Software: %s, build %s\n", 454 // inSoftware, inVersion); 455 456 // Always add time stamp and field ID 457 fprintf(logfile, "#Start-Date: %s\n" 458 "#Fields: date time s-comment\n", 459 log_time_string(time(NULL), theTime, sizeof(theTime))); 460 fflush(logfile); 461 } 462} 463 464// ---------------------------------------------------------------------------- 465// close_log_file 466// ---------------------------------------------------------------------------- 467static void close_log_file(void) 468{ 469 char the_time[40]; 470 471 if (!logfile) 472 return; 473 474 fprintf (logfile, "#End-Date: %s\n", log_time_string(time(NULL), the_time, sizeof(the_time))) ; 475 fclose(logfile) ; 476} 477 478// ---------------------------------------------------------------------------- 479// debug_log 480// ---------------------------------------------------------------------------- 481void vpnlog(int nSyslogPriority, char *format_str, ...) 482{ 483 va_list args; 484 time_t tNow; 485 struct tm *tmTime; 486 char theTime[40]; 487 488 if (!params->debug && LOG_PRI(nSyslogPriority) == LOG_DEBUG) 489 return; 490 491 tNow = time(NULL); 492 tmTime = localtime(&tNow); 493 494 // If the facility hasn't been defined, make it LOG_DAEMON. 495 //if (!(nSyslogPriority & LOG_FACMASK)) 496 // nSyslogPriority |= LOG_DAEMON; 497 498 snprintf(theTime, sizeof(theTime), "%04d-%02d-%02d %02d:%02d:%02d %s\t", 499 tmTime->tm_year + 1900, tmTime->tm_mon + 1, tmTime->tm_mday, 500 tmTime->tm_hour, tmTime->tm_min, tmTime->tm_sec, 501 tmTime->tm_zone); 502 503 if (logfile) { 504 va_start(args, format_str); 505 fputs(theTime, logfile); 506 vfprintf(logfile, format_str, args); 507 fflush(logfile); 508 va_end(args); 509 } 510 511 va_start(args, format_str); 512 vsyslog(nSyslogPriority, format_str, args); 513 va_end(args); 514 515 // Log to stderr if the socket is valid 516 // AND ( we're debugging OR this is a high priority message) 517 if (stdio_is_valid && (params->debug || (LOG_PRI(nSyslogPriority) >= LOG_WARNING))) { 518 va_start(args, format_str); 519 fputs(theTime, stderr); 520 vfprintf(stderr, format_str, args); 521 fflush(stderr); 522 va_end(args); 523 } 524 525} 526 527//----------------------------------------------------------------------------- 528// dump_params 529//----------------------------------------------------------------------------- 530static void dump_params(struct vpn_params *params) 531{ 532 int i; 533 char *subtype = 0, *servertype = "Unknown"; 534 535 switch (params->server_type) { 536 case SERVER_TYPE_IPSEC: 537 servertype = "IPSec"; 538 break; 539 case SERVER_TYPE_PPP: 540 servertype = "PPP"; 541 switch (params->server_subtype) { 542 case PPP_TYPE_SERIAL: 543 subtype = "Serial"; 544 break; 545 case PPP_TYPE_PPPoE: 546 subtype = "PPPoE"; 547 break; 548 case PPP_TYPE_PPTP: 549 subtype = "PPTP"; 550 break; 551 case PPP_TYPE_L2TP: 552 subtype = "L2TP"; 553 break; 554 default: 555 subtype = "Unknown"; 556 break; 557 } 558 break; 559 } 560 561 vpnlog(LOG_DEBUG, "params->daemonize = %d\n", params->daemonize); 562 vpnlog(LOG_DEBUG, "params->max_sessions = %d\n", params->max_sessions); 563 vpnlog(LOG_DEBUG, "params->server_id = %s\n", params->server_id); 564 vpnlog(LOG_DEBUG, "params->server_type = %s\n", servertype); 565 if (subtype) 566 vpnlog(LOG_DEBUG, "params->server_subtype = %s\n", subtype); 567 568 vpnlog(LOG_DEBUG, "params->lb_enable = %d\n", params->lb_enable); 569 if (params->lb_enable) { 570 char str[32]; 571 //vpnlog(LOG_DEBUG, "params->lb_priority = %d\n", params->lb_priority); 572 vpnlog(LOG_DEBUG, "params->lb_interface = %s\n", params->lb_interface); 573 inet_ntop(AF_INET, ¶ms->lb_cluster_address, str, sizeof(str)); 574 vpnlog(LOG_DEBUG, "params->lb_cluster_address = %s\n", str); 575 inet_ntop(AF_INET, ¶ms->lb_redirect_address, str, sizeof(str)); 576 vpnlog(LOG_DEBUG, "params->lb_redirect_address = %s\n", str); 577 vpnlog(LOG_DEBUG, "params->lb_port = %d\n", ntohs(params->lb_port)); 578 } 579 580 if (params->plugin_path) 581 vpnlog(LOG_DEBUG, "params->plugin_path = %s\n", params->plugin_path); 582 vpnlog(LOG_DEBUG, "params->log_path = %s\n", params->log_path); 583 if (params->next_arg_index) 584 vpnlog(LOG_DEBUG, "params->next_arg_index = %d\n", params->next_arg_index); 585 586 for (i = 0; i < params->next_arg_index; i++) 587 vpnlog(LOG_DEBUG, "params->exec_args[%d] = %s\n", i, params->exec_args[i]); 588 589} 590 591//----------------------------------------------------------------------------- 592// set_terminate 593//----------------------------------------------------------------------------- 594void set_terminate(void) 595{ 596 terminate = 1; 597} 598 599//----------------------------------------------------------------------------- 600// got_terminate 601//----------------------------------------------------------------------------- 602int got_terminate(void) 603{ 604 return terminate; 605} 606 607//----------------------------------------------------------------------------- 608// got_sig_chld 609//----------------------------------------------------------------------------- 610int got_sig_chld(void) 611{ 612 if (rcvd_sig_child) { 613 rcvd_sig_child = 0; 614 return 1; 615 } 616 return 0; 617} 618 619//----------------------------------------------------------------------------- 620// got_sig_hup 621//----------------------------------------------------------------------------- 622int got_sig_hup(void) 623{ 624 if (rcvd_sig_hup) { 625 rcvd_sig_hup = 0; 626 return 1; 627 } 628 return 0; 629} 630 631//----------------------------------------------------------------------------- 632// got_sig_usr1 633//----------------------------------------------------------------------------- 634int got_sig_usr1(void) 635{ 636 if (rcvd_sig_usr1) { 637 rcvd_sig_usr1 = 0; 638 return 1; 639 } 640 return 0; 641} 642 643 644 645//----------------------------------------------------------------------------- 646// setup_signal_handlers 647//----------------------------------------------------------------------------- 648static void sig_chld(int inSignal) 649{ 650 rcvd_sig_child = 1; 651} 652 653static void sig_term(int inSignal) 654{ 655 vpnlog(LOG_INFO, "terminating on signal %d\n", inSignal); 656 terminate = 1; 657} 658 659static void sig_hup(int inSignal) 660{ 661 rcvd_sig_hup = 1; 662} 663 664static void sig_usr1(int inSignal) 665{ 666 rcvd_sig_usr1 = 1; 667} 668 669 670static void setup_signal_handlers(void) 671{ 672 // Setup the signal handlers. 673 struct sigaction sSigAction, sSigOldAction; 674 675 sigemptyset (&sSigAction.sa_mask); 676 // Not sure if we always want to restart system calls... 677 sSigAction.sa_flags = 0; //SA_RESTART; 678 679 sSigAction.sa_handler = sig_term; 680 sigaction(SIGTERM, &sSigAction, &sSigOldAction); 681 682 sSigAction.sa_handler = sig_term; 683 sigaction(SIGINT, &sSigAction, &sSigOldAction); 684 685 sSigAction.sa_handler = sig_hup; 686 sigaction(SIGHUP, &sSigAction, &sSigOldAction); 687 688 sSigAction.sa_handler = sig_usr1; 689 sigaction(SIGUSR1, &sSigAction, &sSigOldAction); 690 691 sSigAction.sa_flags |= SA_NOCLDSTOP; //%%%% do we want this ?? 692 sSigAction.sa_handler = sig_chld; 693 sigaction(SIGCHLD, &sSigAction, &sSigOldAction); 694} 695 696//----------------------------------------------------------------------------- 697// toggle_debug 698//----------------------------------------------------------------------------- 699void toggle_debug(void) 700{ 701 if (params->debug) { 702 vpnlog(LOG_DEBUG, "debugging disabled\n"); 703 params->debug = 0; 704 } else { 705 params->debug = 1; 706 vpnlog(LOG_DEBUG, "debugging enabled - dumping current parameters\n"); 707 dump_params(params); 708 } 709} 710 711//----------------------------------------------------------------------------- 712// update_prefs 713//----------------------------------------------------------------------------- 714int update_prefs(void) 715{ 716 int i; 717 struct vpn_params *old_params; 718 int debug = params->debug; 719 720 721 // need to update existing params structure because ptr 722 // to this struct is passed to accept_connections function 723 724 old_params = (struct vpn_params*)malloc(sizeof(struct vpn_params)); 725 if (old_params == 0) { 726 vpnlog(LOG_ERR, "Could not allocate memory for old preferences"); 727 return -1; 728 } 729 730 // save current parameters and clear params struct 731 *old_params = *params; 732 bzero(params, sizeof(*params)); 733 params->debug = old_params->debug; 734 params->server_id = old_params->server_id; 735 params->daemonize = old_params->daemonize; 736 737 begin_address_update(); 738 739 if (process_prefs(params)) { 740 vpnlog(LOG_ERR, "Update preferences - Error processing prefs file\n"); 741 goto fail; 742 } 743 744 // check for consistency 745 if (params->server_subtype != old_params->server_subtype) { 746 vpnlog(LOG_ERR, "Update preferences - server subtype does not match\n"); 747 goto fail; 748 } 749 750 // get and check plugin args 751 if (get_plugin_args(params, 1)) { 752 vpnlog(LOG_ERR, "Update preferences - plugin arguments invalid or inconsistent\n"); 753 goto fail; 754 } 755 756 // 757 // success 758 // 759 CFRelease(old_params->serverSubTypeRef); 760 CFRelease(old_params->serverRef); 761 CFRelease(old_params->serverIDRef); 762 if (old_params->plugin_path) 763 free(old_params->plugin_path); 764 for (i = 0; i < old_params->next_arg_index; i++) 765 free(old_params->exec_args[i]); 766 free(old_params); 767 apply_address_update(); 768 vpnlog(LOG_INFO, "Update of preferences succeeded - settings have been changed\n"); 769 if (debug) 770 dump_params(params); 771 return 0; 772 773fail: 774 cancel_address_update(); 775 if (debug) 776 dump_params(params); 777 if (params->serverSubTypeRef) 778 CFRelease(params->serverSubTypeRef); 779 if (params->serverRef) 780 CFRelease(params->serverRef); 781 if (params->serverIDRef) 782 CFRelease(params->serverIDRef); 783 if (params->plugin_path) 784 free(params->plugin_path); 785 if (params->plugin_path) 786 free(params->plugin_path); 787 for (i = 0; i < params->next_arg_index; i++) 788 free(params->exec_args[i]); 789 *params = *old_params; 790 free(old_params); 791 792 vpnlog(LOG_ERR, "Update of preferences failed - settings left unchanged\n"); 793 return 0; 794 795} 796 797