cpd_http.c

Go to the documentation of this file.
00001 /*
00002  * $Id: cpd_http.c 346460 2009-11-14 05:06:47Z ssiano $
00003  *
00004  * This code is provided as is by Juniper Networks SDK Developer Support.
00005  * It is provided with no warranties or guarantees, and Juniper Networks
00006  * will not provide support or maintenance of this code in any fashion.
00007  * The code is provided only to help a developer better understand how
00008  * the SDK can be used.
00009  *
00010  * Copyright (c) 2007-2008, Juniper Networks, Inc.
00011  * All rights reserved.
00012  */
00013 
00024 #include <sys/types.h>
00025 #include <errno.h>
00026 #include <stdio.h>
00027 #include <string.h>
00028 #include <dirent.h>
00029 #include <signal.h>
00030 #include <pthread.h>
00031 #include <mihl.h>
00032 #include <jnx/aux_types.h>
00033 #include "cpd_http.h"
00034 #include "cpd_config.h"
00035 #include "cpd_conn.h"
00036 #include "cpd_logging.h"
00037 
00038 /*** Constants ***/
00039 
00043 #define CPD_HTTP_PORT 80
00044 
00048 #define CPD_HTTP_MAX_CONNECTIONS 100
00049 
00053 #define HTTP_SERVER_LOG_LEVEL \
00054     (MIHL_LOG_ERROR | MIHL_LOG_WARNING | MIHL_LOG_INFO | MIHL_LOG_INFO_VERBOSE)
00055 
00059 #define HTML_CONTENT "Content-type: text/html\r\n"
00060 
00064 #define CPD_CONTENT_DIRECTORY "/var/cpd_content"
00065 
00069 #define MEDIA_TYPES 9
00070 
00074 #define DEFAULT_MEDIA_TYPE "text/plain"
00075 
00080 const char * type_mappings[MEDIA_TYPES][2] = {
00081     {".html", "text/html"},
00082     {".htm",  "text/html"},
00083     {".css",  "text/css"},
00084     {".xml",  "text/xml"},
00085     {".jpg",  "image/jpeg"},
00086     {".gif",  "image/gif"},
00087     {".png",  "image/png"},
00088     {".js",   "application/javascript"},
00089     {".swf",  "application/x-shockwave-flash"}
00090 };
00091 
00092 
00093 /*** Data structures: ***/
00094 
00098 static boolean shutdown_server = TRUE;
00099 
00103 static pthread_t http_thread;
00104 
00108 static char * pfd_address = NULL;
00109 
00110 
00114 static char * cpd_address = NULL;
00115 
00116 
00117 /*** STATIC/INTERNAL Functions ***/
00118 
00119 
00130 static void
00131 write_page(mihl_cnx_t * cnx, char const * message)
00132 {
00133     mihl_add(cnx,
00134         "<html>"
00135         "<head>"
00136         "<META HTTP-EQUIV=\"pragma\" CONTENT=\"no-cache\">"
00137         "<title>SYNC Captive Portal</title>"
00138         "<style> "
00139         "body { "
00140             "background-color: #666666;"
00141             "font-family: Arial, sans-serif;"
00142             "font-size: 10pt;"
00143         "} "
00144         "#content { "
00145             "background-color: #FFFFFF;"
00146             "border: 1px outset #000000;"
00147             "height: 400px;"
00148             "min-width: 700px;"
00149             "width: 700px;"
00150             "padding: 10px;"
00151         "} "
00152         "#message { "
00153             "color: #CC0000;"
00154             "font-weight: bold;"
00155         "} "
00156         "</style>"
00157         "</head>"
00158         "<body><div align=\"center\"><div id=\"content\" align=\"left\">"
00159         "<p align=\"center\"><strong><u>Welcome to the SDK Your Net Corporation "
00160         "(SYNC) Policy Manager Captive Portal Example</u></strong></p>"
00161         "<p>&nbsp;</p>"
00162         "<p id=\"message\" align=\"center\">%s</p>"
00163         "<p>&nbsp;</p>"
00164         "<p align=\"center\"><a href=\"/index.html\">Return Home</a></p>"
00165         "</div></div></body></html>",
00166 
00167             message);
00168 }
00169 
00190 static int
00191 page_not_found(mihl_cnx_t * cnx,
00192                char const * tag,
00193                char const * host,
00194                void * param __unused) {
00195     
00196     mihl_add(cnx, "<html><body>"
00197                     "<script>"
00198                         "window.location = 'http://%s/index.html';"
00199                     "</script>"
00200                   "</body></html>", cpd_address);
00201     
00202     LOG(LOG_INFO, "%s: sending a redirect script pointing to the CPD for "
00203         "connection from %s requesting page: %s", __func__, host, tag);
00204     
00205     return mihl_send(cnx, NULL, HTML_CONTENT);
00206 }
00207 
00208 
00229 static int
00230 repudiate_access(mihl_cnx_t * cnx,
00231                char const * tag,
00232                char const * host,
00233                void * param) {
00234     
00235     struct in_addr client_address;
00236     int rc;
00237     
00238     if(strcmp(host, pfd_address) == 0) {
00239         return page_not_found(cnx, tag, host, param);
00240     }
00241     
00242     rc = inet_aton(host, &client_address); // client_address is nw-byte order
00243     
00244     if(rc != 1) {
00245         LOG(LOG_INFO, "%s: Couldn't parse host IP: %s", __func__, host);
00246         return 0;
00247     }
00248     
00249     LOG(LOG_INFO, "%s: Repudiating access for host: %s", __func__, host);
00250     
00251     if(is_auth_user(client_address.s_addr)) {
00252         delete_auth_user_addr(client_address.s_addr);
00253         send_repudiated_user(client_address.s_addr);
00254         write_page(cnx, "Your access has been repudiated");
00255     } else {
00256         write_page(cnx, "Your access is already currently unauthorized");
00257     }
00258     
00259     return mihl_send(cnx, NULL, HTML_CONTENT);
00260 }
00261 
00262 
00283 static int
00284 authorize_access(mihl_cnx_t * cnx,
00285                char const * tag,
00286                char const * host,
00287                void * param) {
00288 
00289     struct in_addr client_address;
00290     int rc;
00291     
00292     if(strcmp(host, pfd_address) == 0) {
00293         return page_not_found(cnx, tag, host, param);
00294     }
00295     
00296     rc = inet_aton(host, &client_address); // client_address is nw-byte order
00297     
00298     if(rc != 1) {
00299         LOG(LOG_INFO, "%s: Couldn't parse host IP: %s", __func__, host);
00300         return 0;
00301     }
00302     
00303     LOG(LOG_INFO, "%s: Authorizing access for host %s", __func__, host);
00304     
00305     if(!is_auth_user(client_address.s_addr)) {
00306         add_auth_user_addr(client_address.s_addr);
00307         send_authorized_user(client_address.s_addr);
00308         write_page(cnx, "Your access has been authorized");
00309     } else {
00310         write_page(cnx, "Your access is already currently authorized");
00311     }
00312     
00313     return mihl_send(cnx, NULL, HTML_CONTENT);
00314 }
00315 
00316 
00337 static int
00338 check_access(mihl_cnx_t * cnx,
00339              char const * tag,
00340              char const * host,
00341              void * param) {
00342     
00343     struct in_addr client_address;
00344     int rc;
00345     
00346     if(strcmp(host, pfd_address) == 0) {
00347         return page_not_found(cnx, tag, host, param);
00348     }
00349     
00350     rc = inet_aton(host, &client_address); // client_address is nw-byte order
00351     
00352     if(rc != 1) {
00353         LOG(LOG_INFO, "%s: Couldn't parse host IP: %s", __func__, host);
00354         return 0;
00355     }
00356     
00357     LOG(LOG_INFO, "%s: Checking access for host %s", __func__, host);
00358     
00359     if(is_auth_user(client_address.s_addr)) {
00360         write_page(cnx, "Your access is currently authorized");
00361     } else {
00362         write_page(cnx, "Your access is currently unauthorized");
00363     }
00364     
00365     return mihl_send(cnx, NULL, HTML_CONTENT);
00366 }
00367 
00368 
00375 static void
00376 register_content(mihl_ctx_t * ctx)
00377 {
00378     struct dirent * direntry;
00379     DIR * dfd;
00380     char filename[256], path[256];
00381     int i;
00382     boolean found;
00383     
00384     errno = 0;
00385     dfd = opendir(CPD_CONTENT_DIRECTORY);
00386     
00387     if(dfd == NULL) {
00388         LOG(LOG_ERR, "%s: Failed to open directory of content (%s) for the HTTP"
00389             " server due to error: %m", __func__, CPD_CONTENT_DIRECTORY);
00390         return;
00391     }
00392         
00393     while((direntry = readdir(dfd))) {
00394 
00395         if(direntry->d_name[0] == '.' || direntry->d_type == DT_DIR) {
00396             continue; // ignore files with names starting with . and directories
00397         }
00398         
00399         // build filename
00400         snprintf(filename, 256, "%s/%s", CPD_CONTENT_DIRECTORY, 
00401             direntry->d_name);
00402 
00403         // Check that we have permission to read this file
00404         if (access(filename, R_OK ) == 0) {
00405             
00406             // build path to file on the server
00407             snprintf(path, 256, "/%s", direntry->d_name);
00408             
00409             // check if it is a known media type
00410             found = FALSE;
00411             for(i = 0; i < MEDIA_TYPES; ++i) {
00412                 if(strstr(path, type_mappings[i][0])) {
00413                     
00414                     // register handler of path with this file and type
00415                     mihl_handle_file(ctx, path, filename, 
00416                         type_mappings[i][1], 0);
00417                     
00418                     LOG(LOG_INFO, "%s:  path: %s , file: %s , type: %s",
00419                         __func__, path, filename, type_mappings[i][1]);
00420                     
00421                     found = TRUE;
00422                     break;
00423                 }
00424             }
00425             if(!found) {
00426                 // register handler of path with this file and default type
00427                 mihl_handle_file(ctx, path, filename, DEFAULT_MEDIA_TYPE, 0);
00428                 
00429                 LOG(LOG_INFO, "%s:  path: %s , file: %s , type: %s",
00430                     __func__, path, filename, DEFAULT_MEDIA_TYPE);
00431                 
00432             }
00433         }
00434         else {
00435             LOG(LOG_ERR, "%s: Failed to access file %s in the directory of "
00436                 " content for the HTTP server: %m", __func__, filename);
00437             errno = 0;
00438         }
00439     }
00440     
00441     if(errno) {
00442         LOG(LOG_ERR, "%s: Failed to read from the directory of content (%s)"
00443             "for the HTTP server: %m", __func__, CPD_CONTENT_DIRECTORY);
00444     }
00445     // else normal end of directory
00446     
00447     closedir(dfd);
00448 }
00449 
00450 
00459 static void *
00460 run_http_server(void * params __unused)
00461 {
00462     mihl_ctx_t * ctx;
00463     struct in_addr tmp;
00464     sigset_t sig_mask;
00465     
00466     LOG(LOG_INFO, "%s: HTTP server thread alive", __func__);
00467     
00468     // Block SIGTERM to this thread/main thread will handle otherwise we inherit
00469     // this behaviour in our threads sigmask and the signal might come here
00470     sigemptyset(&sig_mask);
00471     sigaddset(&sig_mask, SIGTERM);
00472     pthread_sigmask(SIG_BLOCK, &sig_mask, NULL);
00473     
00474     tmp.s_addr = get_cpd_address();
00475     cpd_address = strdup(inet_ntoa(tmp));
00476     tmp.s_addr = get_pfd_address();
00477     pfd_address = strdup(inet_ntoa(tmp));
00478     
00479     // initial a server and get the server context
00480     ctx = mihl_init(cpd_address, CPD_HTTP_PORT,
00481             CPD_HTTP_MAX_CONNECTIONS, HTTP_SERVER_LOG_LEVEL);
00482     
00483     if (!ctx) {
00484         LOG(LOG_ERR, "%s: Failed to start HTTP server on %s:%d using library",
00485             __func__, cpd_address, CPD_HTTP_PORT);
00486         pthread_exit((void *) 0);
00487         return NULL;
00488     }
00489 
00490     LOG(LOG_INFO, "%s: Started HTTP server on %s:%d using library",
00491         __func__, cpd_address, CPD_HTTP_PORT);
00492     
00493     // register default handler
00494     mihl_handle_get(ctx, NULL, page_not_found, NULL);
00495 
00496     // register handler for all pages
00497     register_content(ctx);
00498     
00499     LOG(LOG_INFO, "%s: Registered CPD server URLs with content", __func__);
00500     
00501     // register other handlers to control access
00502     mihl_handle_get(ctx, "/repudiate.html", repudiate_access, NULL);
00503     mihl_handle_get(ctx, "/authorize.html", authorize_access, NULL);
00504     mihl_handle_get(ctx, "/check.html",     check_access,     NULL);
00505     
00506     LOG(LOG_INFO, "%s: Registered other CPD server URLs", __func__);
00507 
00508     while(!shutdown_server) {
00509         mihl_server(ctx); // serve pages and accept/terminate connections
00510     }
00511     
00512     LOG(LOG_INFO, "%s: Shutting down the server", __func__);
00513     
00514     mihl_end(ctx);
00515     
00516     free(pfd_address);
00517     pfd_address = NULL;
00518     free(cpd_address);
00519     cpd_address = NULL;
00520     
00521     LOG(LOG_INFO, "%s: HTTP server thread exiting", __func__);
00522 
00523     pthread_exit((void *) 0); // explicitly return to join
00524     return NULL;
00525 }
00526 
00527 
00528 /*** GLOBAL/EXTERNAL Functions ***/
00529 
00530 
00534 void
00535 init_http_server(void)
00536 {
00537     pthread_attr_t attr;
00538     int rc;
00539     
00540     if(!shutdown_server) { // if server is running
00541         shutdown_http_server();
00542     }
00543 
00544     /* Initialize and set thread detached attribute */
00545     pthread_attr_init(&attr);
00546     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
00547 
00548     shutdown_server = FALSE; // server started
00549     
00550     LOG(LOG_INFO, "%s: Staring CPD's HTTP server", __func__);
00551     
00552     rc = pthread_create(&http_thread, NULL, run_http_server, NULL);
00553     if(rc) {
00554         LOG(LOG_ERR, "%s: Failed to start http server thread (%d)",
00555             __func__, rc);
00556         shutdown_server = TRUE; // still shutdown
00557     }
00558     
00559     pthread_attr_destroy(&attr);
00560 }
00561 
00562 
00566 void
00567 shutdown_http_server(void)
00568 {
00569     int rc, status;
00570     
00571     if(shutdown_server) { // if server isn't running
00572         return;
00573     }
00574     
00575     shutdown_server = TRUE;
00576     
00577     LOG(LOG_INFO, "%s: Shutting down CPD's HTTP server", __func__);
00578     
00579     rc = pthread_join(http_thread, (void **)&status); // wait for server thread
00580     if(rc) {
00581         LOG(LOG_ERR, "%s: Failed to synchronize on http server thread exit "
00582             "(%d)", __func__, rc);
00583     }
00584 }
00585 
00586 
00587 
00588 

2007-2009 Juniper Networks, Inc. All rights reserved. The information contained herein is confidential information of Juniper Networks, Inc., and may not be used, disclosed, distributed, modified, or copied without the prior written consent of Juniper Networks, Inc. in an express license. This information is subject to change by Juniper Networks, Inc. Juniper Networks, the Juniper Networks logo, and JUNOS are registered trademarks of Juniper Networks, Inc. in the United States and other countries. All other trademarks, service marks, registered trademarks, or registered service marks are the property of their respective owners.
Generated on Sun May 30 20:26:53 2010 for SDK Your Net Corporation Policy Manager Example: Captive Portal Daemon (cpd) 1.0 by Doxygen 1.5.1