main.c

Go to the documentation of this file.
00001 /*
00002  ** Copyright (C) 2002-2007 INL
00003  ** Written by Eric Leblond <regit@inl.fr>
00004  **            Vincent Deffontaines <vincent@gryzor.com>
00005  ** INL http://www.inl.fr/
00006  **
00007  ** $Id: main.c 5275 2008-11-21 14:48:01Z pollux $
00008  **
00009  ** This program is free software; you can redistribute it and/or modify
00010  ** it under the terms of the GNU General Public License as published by
00011  ** the Free Software Foundation, version 3 of the License.
00012  **
00013  ** This program is distributed in the hope that it will be useful,
00014  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  ** GNU General Public License for more details.
00017  **
00018  ** You should have received a copy of the GNU General Public License
00019  ** along with this program; if not, write to the Free Software
00020  ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00021  */
00022 
00031 #include "nufw.h"
00032 
00033 #include <linux/netfilter.h>
00034 #include <unistd.h>
00035 #include <pthread.h>
00036 #include <netdb.h>
00037 #include <signal.h>
00038 #include <syslog.h>
00039 #include <errno.h>
00040 #include <sys/types.h>
00041 
00042 #include <nubase.h>
00043 
00044 GCRY_THREAD_OPTION_PTHREAD_IMPL;
00045 
00046 char *key_file = NULL;
00047 char *cert_file = NULL;
00048 
00049 /* packet server thread */
00050 struct nufw_threadtype thread;
00051 
00052 /* packet server thread */
00053 struct nufw_signals signals;
00054 
00057 #define NUFW_PID_FILE  LOCAL_STATE_DIR "/run/nufw.pid"
00058 
00062 void nufw_stop_thread()
00063 {
00064         /* ask threads to stop */
00065         pthread_mutex_lock(&tls.auth_server_mutex);
00066         pthread_mutex_lock(&thread.mutex);
00067 
00068         /* wait for thread end */
00069         log_area_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_MESSAGE,
00070                         "Wait threads end");
00071         if (tls.auth_server_running) {
00072                 pthread_join(tls.auth_server, NULL);
00073         }
00074         pthread_mutex_unlock(&tls.auth_server_mutex);
00075         pthread_join(thread.thread, NULL);
00076         pthread_mutex_unlock(&thread.mutex);
00077 }
00078 
00082 void nufw_prepare_quit()
00083 {
00084         /* clear packet list: use trylock() instead of lock() because the
00085          * mutex may already be locked */
00086         clear_packet_list();
00087         pthread_mutex_destroy(&packets_list.mutex);
00088 
00089         /* close tls session */
00090         close_tls_session();
00091         pthread_mutex_destroy(&tls.mutex);
00092 
00093         /* destroy conntrack handle */
00094 #ifdef HAVE_LIBCONNTRACK
00095         nfct_close(cth);
00096 #endif
00097 
00098         /* free memory */
00099         free(key_file);
00100         free(cert_file);
00101         free(ca_file);
00102         free(crl_file);
00103         freeaddrinfo(adr_srv);
00104 
00105         /* destroy pid file */
00106         unlink(NUFW_PID_FILE);
00107 }
00108 
00113 void nufw_hard_cleanup(int signal)
00114 {
00115         /* reinstall old handlers */
00116         (void) sigaction(SIGTERM, &signals.old_sigterm_hdl, NULL);
00117         (void) sigaction(SIGINT, &signals.old_sigint_hdl, NULL);
00118 
00119         log_area_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_FATAL,
00120                         "[+] NuFW \"hard\" cleanup (catch double signal)");
00121         nufw_prepare_quit();
00122         log_area_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_FATAL,
00123                         "[+] Exit NuFW");
00124         exit(EXIT_SUCCESS);
00125 }
00126 
00134 void nufw_cleanup(int signal)
00135 {
00136         struct sigaction action;
00137 
00138         /* install "hard cleanup" for SIGTERM */
00139         memset(&action, 0, sizeof(action));
00140         action.sa_handler = nufw_hard_cleanup;
00141         sigemptyset(&(action.sa_mask));
00142         action.sa_flags = 0;
00143         sigaction(SIGTERM, &action, NULL);
00144 
00145         /* install "hard cleanup" for SIGINT */
00146         memset(&action, 0, sizeof(action));
00147         action.sa_handler = nufw_hard_cleanup;
00148         sigemptyset(&(action.sa_mask));
00149         action.sa_flags = 0;
00150         sigaction(SIGINT, &action, NULL);
00151 
00152         log_area_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_FATAL,
00153                         "[+] Stop NuFW (catch signal)");
00154         nufw_stop_thread();
00155         nufw_prepare_quit();
00156         log_area_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_FATAL,
00157                         "[+] Exit NuFW");
00158         exit(EXIT_SUCCESS);
00159 }
00160 
00166 void create_thread()
00167 {
00168         /* should be static because thread may read data after this function exits */
00169         static struct nufw_threadargument arg;
00170         arg.thread = &thread;
00171         arg.parent_pid = getpid();
00172 
00173         /* set attribute to "joinable thread" */
00174         pthread_attr_t attr;
00175         pthread_attr_init(&attr);
00176         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
00177 
00178         /* create mutex */
00179         pthread_mutex_init(&thread.mutex, NULL);
00180 
00181         /* try to create the thread */
00182         if (pthread_create(&thread.thread, &attr, packetsrv, &arg) != 0) {
00183                 pthread_mutex_destroy(&thread.mutex);
00184                 log_area_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_FATAL,
00185                                 "Fail to create thread!");
00186                 exit(EXIT_FAILURE);
00187         }
00188 #ifdef HAVE_LIBCONNTRACK
00189         if (handle_conntrack_event) {
00190                 if (pthread_create
00191                     (&(tls.conntrack_event_handler), NULL,
00192                      conntrack_event_handler, NULL) == EAGAIN) {
00193                         exit(EXIT_FAILURE);
00194                 }
00195         }
00196 #endif
00197 
00198 }
00199 
00209 void install_signals()
00210 {
00211         struct sigaction action;
00212 
00213         /* intercept SIGTERM */
00214         memset(&action, 0, sizeof(action));
00215         action.sa_handler = nufw_cleanup;
00216         sigemptyset(&(action.sa_mask));
00217         action.sa_flags = 0;
00218         if (sigaction(SIGTERM, &action, &signals.old_sigterm_hdl) != 0) {
00219                 log_area_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_FATAL,
00220                                 "Fail to install SIGTERM handler: %d \n",
00221                                 errno);
00222                 exit(EXIT_FAILURE);
00223         }
00224 
00225         /* intercept SIGINT */
00226         memset(&action, 0, sizeof(action));
00227         action.sa_handler = nufw_cleanup;
00228         sigemptyset(&(action.sa_mask));
00229         action.sa_flags = 0;
00230         if (sigaction(SIGINT, &action, &signals.old_sigint_hdl) != 0) {
00231                 log_area_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_FATAL,
00232                                 "Fail to install SIGINT handler: %d \n",
00233                                 errno);
00234                 exit(EXIT_FAILURE);
00235         }
00236 
00237         /* ignore "broken pipe" signal */
00238         signal(SIGPIPE, SIG_IGN);
00239 
00240         /* intercept SIGUSR1 */
00241         memset(&action, 0, sizeof(action));
00242         action.sa_handler = &process_usr1;
00243         action.sa_flags = SIGUSR1;
00244         if (sigaction(SIGUSR1, &action, NULL) == -1) {
00245                 log_area_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_WARNING,
00246                                 "Warning: Could not set signal USR1");
00247         }
00248 
00249         /* intercept SIGUSR2 */
00250         memset(&action, 0, sizeof(action));
00251         action.sa_handler = &process_usr2;
00252         action.sa_flags = SIGUSR2;
00253         if (sigaction(SIGUSR2, &action, NULL) == -1) {
00254                 log_area_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_WARNING,
00255                                 "Warning: Could not set signal USR2");
00256         }
00257 
00258         /* intercept SIGPOLL */
00259         memset(&action, 0, sizeof(action));
00260         action.sa_handler = &process_poll;
00261         action.sa_flags = SIGPOLL;
00262         if (sigaction(SIGPOLL, &action, NULL) == -1) {
00263                 log_area_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_WARNING,
00264                                 "Warning: Could not set signal POLL");
00265         }
00266 
00267         /* intercept SIGHUP */
00268         memset(&action, 0, sizeof(action));
00269         action.sa_handler = &process_hup;
00270         action.sa_flags = SIGHUP;
00271         if (sigaction(SIGHUP, &action, NULL) == -1) {
00272                 log_area_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_WARNING,
00273                                 "Warning: Could not set signal HUP");
00274         }
00275 }
00276 
00280 void nufw_daemonize()
00281 {
00282         FILE *pf;
00283         pid_t pidf;
00284 
00285         if (access(NUFW_PID_FILE, R_OK) == 0) {
00286                 /* Check if the existing process is still alive. */
00287                 pid_t pidv;
00288 
00289                 pf = fopen(NUFW_PID_FILE, "r");
00290                 if (pf != NULL &&
00291                     fscanf(pf, "%d", &pidv) == 1 && kill(pidv, 0) == 0) {
00292                         fclose(pf);
00293                         printf
00294                             ("pid file exists. Is nufw already running? Aborting!\n");
00295                         exit(EXIT_FAILURE);
00296                 }
00297 
00298                 if (pf != NULL)
00299                         fclose(pf);
00300         }
00301 
00302         pidf = fork();
00303         if (pidf < 0) {
00304                 log_printf(DEBUG_LEVEL_FATAL, "Unable to fork. Aborting!");
00305                 exit(-1);
00306         } else {
00307                 /* parent */
00308                 if (pidf > 0) {
00309                         if ((pf = fopen(NUFW_PID_FILE, "w")) != NULL) {
00310                                 fprintf(pf, "%d\n", (int) pidf);
00311                                 fclose(pf);
00312                         } else {
00313                                 printf("Dying, can not create PID file : "
00314                                        NUFW_PID_FILE "\n");
00315                                 exit(EXIT_FAILURE);
00316                         }
00317                         exit(EXIT_SUCCESS);
00318                 }
00319         }
00320 
00321         chdir("/");
00322 
00323         setsid();
00324 
00325         /* set log engine */
00326         log_engine = LOG_TO_SYSLOG;
00327 
00328         /* Close stdin, stdout, stderr. */
00329         (void) close(0);
00330         (void) close(1);
00331         (void) close(2);
00332 }
00333 
00334 
00339 int init_checks()
00340 {
00341 #if USE_X509
00342         if (!init_x509_filenames()) {
00343                 printf("ERROR: Unable to allocate memory for "
00344                                 "key or cert filename!\n");
00345                 return 0;
00346         }
00347         if (access(key_file, R_OK)) {
00348                 printf("ERROR: Unable to read key file: %s\n", key_file);
00349                 return 0;
00350         }
00351         if (access(cert_file, R_OK)) {
00352                 printf("ERROR: Unable to read key file: %s\n", cert_file);
00353                 return 0;
00354         }
00355 #endif
00356         return 1;
00357 }
00358 
00359 
00385 int main(int argc, char *argv[])
00386 {
00387         /* option */
00388 #if USE_NFQUEUE
00389         char *options_list = "4sSDhVvmq:"
00390 #ifdef HAVE_NFQ_SET_QUEUE_MAXLEN
00391             "L:"
00392 #endif
00393             "c:k:a:n:r:d:p:t:T:A:"
00394 #ifdef HAVE_LIBCONNTRACK
00395             "CM"
00396 #endif
00397             ;
00398 #else
00399         char *options_list = "4sSDhVvmc:k:a:n:r:d:p:t:T:A:";
00400 #endif
00401         int option, daemonize = 0;
00402         char *version = PACKAGE_VERSION;
00403         nufw_no_ipv6 = 0;
00404 
00405         /* initialize variables */
00406 
00407         log_engine = LOG_TO_STD;        /* default is to send debug messages to stdout + stderr */
00408         authreq_port = AUTHREQ_PORT;
00409         packet_timeout = PACKET_TIMEOUT;
00410         track_size = TRACK_SIZE;
00411         cert_file = NULL;
00412         key_file = NULL;
00413         ca_file = NULL;
00414         crl_file = NULL;
00415         nuauth_cert_dn = NULL;
00416         SECURE_STRNCPY(authreq_addr, AUTHREQ_ADDR, sizeof authreq_addr);
00417         debug_level = DEFAULT_DEBUG_LEVEL;
00418         debug_areas = DEFAULT_DEBUG_AREAS;
00419 #if USE_NFQUEUE
00420         nfqueue_num = DEFAULT_NFQUEUE;
00421 #ifdef HAVE_LIBCONNTRACK
00422         handle_conntrack_event = CONNTRACK_HANDLE_DEFAULT;
00423         nufw_conntrack_uses_mark = 0;
00424 #endif
00425 #ifdef HAVE_NFQ_SET_QUEUE_MAXLEN
00426 
00427         queue_maxlen = QUEUE_MAXLEN;
00428 #endif
00429 #endif
00430         nufw_set_mark = 0;
00431         nufw_strict_tls = 1;
00432 
00433 
00434         log_area_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_VERBOSE_DEBUG,
00435                         "[+] Start NuFW");
00436 
00437         /*parse options */
00438         while ((option = getopt(argc, argv, options_list)) != -1) {
00439                 switch (option) {
00440                 case 'k':
00441                         key_file = strdup(optarg);
00442                         if (key_file == NULL) {
00443                                 fprintf(stderr,
00444                                         "Couldn't malloc! Exiting");
00445                                 exit(EXIT_FAILURE);
00446                         }
00447                         break;
00448                 case 'c':
00449                         cert_file = strdup(optarg);
00450                         if (cert_file == NULL) {
00451                                 fprintf(stderr,
00452                                         "Couldn't malloc! Exiting");
00453                                 exit(EXIT_FAILURE);
00454                         }
00455                         break;
00456                 case 'a':
00457                         ca_file = strdup(optarg);
00458                         if (ca_file == NULL) {
00459                                 fprintf(stderr,
00460                                         "Couldn't malloc! Exiting");
00461                                 exit(EXIT_FAILURE);
00462                         }
00463                         break;
00464                 case 'r':
00465                         crl_file = strdup(optarg);
00466                         if (crl_file == NULL) {
00467                                 fprintf(stderr,
00468                                         "Couldn't malloc! Exiting");
00469                                 exit(EXIT_FAILURE);
00470                         }
00471                         break;
00472                 case 'n':
00473                         nuauth_cert_dn = strdup(optarg);
00474                         if (nuauth_cert_dn == NULL) {
00475                                 fprintf(stderr,
00476                                         "Couldn't malloc! Exiting");
00477                                 exit(EXIT_FAILURE);
00478                         }
00479                         break;
00480                 case 'V':
00481                         fprintf(stdout, "%s (version %s)\n", PACKAGE_NAME,
00482                                 version);
00483                         return 1;
00484                 case 'D':
00485                         daemonize = 1;
00486                         break;
00487                 case 'v':
00488                         /*fprintf (stdout, "Debug should be On\n"); */
00489                         debug_level += 1;
00490                         break;
00491                 case 'p':
00492                         authreq_port = atoi(optarg);
00493                         break;
00494                         /* destination IP */
00495                 case 'd':
00496                         SECURE_STRNCPY(authreq_addr, optarg,
00497                                        sizeof authreq_addr);
00498                         printf("Sending Auth request to %s\n",
00499                                authreq_addr);
00500                         break;
00501                         /* packet timeout */
00502                 case 't':
00503                         sscanf(optarg, "%d", &packet_timeout);
00504                         break;
00505                         /* max size of packet list */
00506                 case 'T':
00507                         sscanf(optarg, "%d", &track_size);
00508                         break;
00509                 case 'A':
00510                         sscanf(optarg, "%d", &debug_areas);
00511                         break;
00512                 case 'm':
00513                         nufw_set_mark = 1;
00514                         break;
00515                 case 's':
00516                         nufw_strict_tls = 0;
00517                         break;
00518                 case 'S':
00519                         break;
00520                 case '4':
00521                         nufw_no_ipv6 = 1;
00522                         break;
00523 #if USE_NFQUEUE
00524                 case 'q':
00525                         sscanf(optarg, "%hu", &nfqueue_num);
00526                         break;
00527                 case 'C':
00528 #if HAVE_LIBCONNTRACK
00529                         handle_conntrack_event = 1;
00530                         break;
00531                 case 'M':
00532                         nufw_conntrack_uses_mark = 1;
00533                         /* this implies -C */
00534                         handle_conntrack_event = 1;
00535                         /* and -m */
00536                         nufw_set_mark = 1;
00537                         break;
00538 #endif                          /* HAVE_LIBCONNTRACK */
00539 #ifdef HAVE_NFQ_SET_QUEUE_MAXLEN
00540                 case 'L':
00541                         sscanf(optarg, "%u", &queue_maxlen);
00542                         break;
00543 #endif
00544 #endif                          /* USE_NFQUEUE */
00545 
00546                 case 'h':
00547                         fprintf(stdout, "%s [-hVc"
00548 #ifdef HAVE_LIBCONNTRACK
00549                                 "CM"
00550 #endif
00551                                 "v[v[v[v[v[v[v[v[v[v]]]]]]]]]] [-d remote_addr] [-p remote_port]  [-t packet_timeout] [-T track_size]"
00552 #ifdef USE_NFQUEUE
00553                                 " [-q queue_num]"
00554 #ifdef HAVE_NFQ_SET_QUEUE_MAXLEN
00555                                 " [-L queue_maxlen]"
00556 #endif
00557 #endif
00558                                 "\n\
00559 \t-h: display this help and exit\n\
00560 \t-V: display version and exit\n\
00561 \t-D: daemonize\n\
00562 \t-s: do not enforce strict checking of TLS certificates\n\
00563 \t-S: this option does nothing, it is here for backward compatibility\n\
00564 \t-k: use specified file as key file\n\
00565 \t-c: use specified file as cert file\n\
00566 \t-a: use specified file as ca file (strict checking is done if selected) (default: none)\n\
00567 \t-r: use specified file as crl file (default: none)\n\
00568 \t-n: use specified string as the needed DN of nuauth (enforce certificate checking) (default is to)\n\
00569 \t\tcheck the DN against nuauth FQDN specified using the -d option)\n\
00570 \t-v: increase debug level (+1 for each 'v') (max useful number: 10)\n\
00571 \t-A: debug areas (see man page for details)\n\
00572 \t-4: use this flag if your system does not have IPv6 support for nfnetlink\n\
00573 \t-m: mark packet with nuauth provided mark\n"
00574 #ifdef HAVE_LIBCONNTRACK
00575                                 "\t-C: listen to conntrack events (needed for connection expiration)\n\
00576 \t-M: only report event on marked connections to nuauth (implies -C and -m)\n"
00577 #endif
00578                                 "\t-d: remote address we send auth requests to (address of the nuauth server) (default: 127.0.0.1)\n\
00579 \t-p: remote port we send auth requests to (TCP port nuauth server listens on) (default: 4128)\n"
00580 #if USE_NFQUEUE
00581                                 "\t-q: use nfqueue number (default: 0)\n"
00582 #ifdef HAVE_NFQ_SET_QUEUE_MAXLEN
00583                                 "\t-L : set queue max len (default: 1024)\n"
00584 #endif
00585 #endif
00586                                 "\t-t : timeout to forget about packets when they don't match (default: 15 s)\n\
00587 \t-T : track size (default : 1000)\n",
00588                                 PACKAGE_TARNAME);
00589 
00590                         exit(EXIT_SUCCESS);
00591                 }
00592         }
00593 
00594         if (getuid()) {
00595                 printf("nufw must be run as root! Sorry\n");
00596                 exit(EXIT_FAILURE);
00597         }
00598 
00599         if (!init_checks()) {
00600                 exit(EXIT_FAILURE);
00601         }
00602 
00603         /* Nice nufw to increase performance of nfnetlink layer */
00604         nice(-1);
00605 
00606         /* Daemon code */
00607         if (daemonize == 1) {
00608                 nufw_daemonize();
00609         }
00610 
00611         install_signals();
00612 
00613         init_log_engine("nufw");
00614 
00615         /* open ICMP (IPv4) socket */
00616         raw_sock4 = socket(PF_INET, SOCK_RAW, 1);       /* 1: ICMP protocol */
00617         if (raw_sock4 == -1) {
00618                 log_area_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_CRITICAL,
00619                                 "Fail to create socket for ICMP!");
00620                 exit(EXIT_FAILURE);
00621         }
00622 
00623         if (!nufw_no_ipv6) {
00624                 /* open ICMPv6 socket */
00625                 raw_sock6 = socket(PF_INET6, SOCK_RAW, 58);     /* 58: ICMPv6 protocol */
00626                 if (raw_sock6 == -1) {
00627                         log_area_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_CRITICAL,
00628                                         "Fail to create socket for ICMPv6!");
00629                 }
00630         }
00631 
00632         /* create packet list */
00633         packets_list.start = NULL;
00634         packets_list.end = NULL;
00635         packets_list.length = 0;
00636         pthread_mutex_init(&packets_list.mutex, NULL);
00637 
00638         /* init. tls */
00639         tls.session = NULL;
00640         tls.auth_server_running = 0;
00641         pthread_mutex_init(&tls.mutex, NULL);
00642 
00643         /* start GNU TLS library */
00644         gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
00645         if (nussl_init() != NUSSL_OK) {
00646                 log_area_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_FATAL,
00647                                 "Unable to initialize NuSSL library.");
00648 
00649         }
00650 
00651 #ifdef HAVE_LIBCONNTRACK
00652         cth = nfct_open(CONNTRACK, 0);
00653 #endif
00654 
00655 
00656         /* create packet server thread */
00657         create_thread();
00658 
00659         /* do initial connect */
00660         tls_connect();
00661         if (tls.session) {
00662                 log_area_printf(DEBUG_AREA_GW,
00663                                 DEBUG_LEVEL_WARNING,
00664                                 "[+] TLS connection to nuauth established");
00665         } else {
00666                 log_area_printf(DEBUG_AREA_GW,
00667                                 DEBUG_LEVEL_CRITICAL,
00668                                 "[!] TLS connection to nuauth can NOT be established");
00669         }
00670 
00671         log_area_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_FATAL,
00672                         "[+] NuFW " VERSION " started");
00673 
00674         if (daemonize == 0) {
00675                 log_area_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_CRITICAL,
00676                                 "NuFW launched in foreground (without -D option), "
00677                                 "logging to stdout and stderr only (no syslog).");
00678         }
00679 
00680         /* control stuff */
00681         pckt_tx = pckt_rx = 0;
00682         while (1 == 1) {
00683                 int stat = pckt_tx;
00684                 const int seconds = 5;
00685 
00686                 sleep(seconds);
00687 
00688                 stat = pckt_tx - stat;
00689 
00690                 /* clean old packets */
00691                 pthread_mutex_lock(&packets_list.mutex);
00692                 clean_old_packets();
00693                 pthread_mutex_unlock(&packets_list.mutex);
00694 #ifdef DEBUG_ENABLE
00695                 /* display stats */
00696                 process_poll(0);
00697                 printf("Average: %u\n", stat / seconds);
00698 #endif
00699         }
00700 
00701         nufw_stop_thread();
00702         nufw_prepare_quit();
00703         return EXIT_SUCCESS;
00704 }

Generated on Sat Nov 22 04:00:38 2008 for NuFW by  doxygen 1.4.7