OPENVPN_EXPORT openvpn_plugin_handle_t openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char *envp[]) { struct down_root_context *context; /* * Allocate our context */ context = (struct down_root_context *) calloc (1, sizeof (struct down_root_context)); if (!context) goto error; context->foreground_fd = -1; /* * Intercept the --up and --down callbacks */ *type_mask = OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_UP) | OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_DOWN); /* * Make sure we have two string arguments: the first is the .so name, * the second is the script command. */ if (string_array_len (argv) < 2) { fprintf (stderr, "DOWN-ROOT: need down script command\n"); goto error; } /* * Save our argument in context */ context->command = build_command_line (&argv[1]); /* * Get verbosity level from environment */ { const char *verb_string = get_env ("verb", envp); if (verb_string) context->verb = atoi (verb_string); } return (openvpn_plugin_handle_t) context; error: free_context (context); return NULL; }
OPENVPN_PLUGIN_DEF openvpn_plugin_handle_t OPENVPN_PLUGIN_FUNC(openvpn_plugin_open_v2)( unsigned int *type_mask, const char *argv[], const char *envp[], struct openvpn_plugin_string_list **return_list) { const char *verb_str = NULL; auth_http_plugin_context_t *context = NULL; if (curl_global_init(CURL_GLOBAL_ALL)) { PLUGIN_ERROR("Can not init curl."); return NULL; } /* Init logginig */ verb_str = get_openvpn_env("verb", envp); if (verb_str) init_plugin_logging(atoi(verb_str)); else init_plugin_logging(3); if (string_array_len(argv) < 2) { PLUGIN_ERROR("Missed path to file with settings."); goto error; } context = create_auth_http_plugin_context(argv[1]); if (!context) goto error; /* Intercept the --auth-user-pass-verify, --client-connect and --client-disconnect callback. */ *type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_CONNECT) | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_DISCONNECT); return (openvpn_plugin_handle_t)context; error: if (context) free(context); clear_plugin_logging(); curl_global_cleanup(); return NULL; }
OPENVPN_EXPORT openvpn_plugin_handle_t openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char *envp[]) { pid_t pid; int fd[2]; struct auth_pam_context *context; struct name_value_list name_value_list; const int base_parms = 2; /* * Allocate our context */ context = (struct auth_pam_context *) calloc (1, sizeof (struct auth_pam_context)); if (!context) goto error; context->foreground_fd = -1; /* * Intercept the --auth-user-pass-verify callback. */ *type_mask = OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY); /* * Make sure we have two string arguments: the first is the .so name, * the second is the PAM service type. */ if (string_array_len (argv) < base_parms) { fprintf (stderr, "AUTH-PAM: need PAM service parameter\n"); goto error; } /* * See if we have optional name/value pairs to match against * PAM module queried fields in the conversation function. */ name_value_list.len = 0; if (string_array_len (argv) > base_parms) { const int nv_len = string_array_len (argv) - base_parms; int i; if ((nv_len & 1) == 1 || (nv_len / 2) > N_NAME_VALUE) { fprintf (stderr, "AUTH-PAM: bad name/value list length\n"); goto error; } name_value_list.len = nv_len / 2; for (i = 0; i < name_value_list.len; ++i) { const int base = base_parms + i * 2; name_value_list.data[i].name = argv[base]; name_value_list.data[i].value = argv[base+1]; } } /* * Get verbosity level from environment */ { const char *verb_string = get_env ("verb", envp); if (verb_string) context->verb = atoi (verb_string); } /* * Make a socket for foreground and background processes * to communicate. */ if (socketpair (PF_UNIX, SOCK_DGRAM, 0, fd) == -1) { fprintf (stderr, "AUTH-PAM: socketpair call failed\n"); goto error; } /* * Fork off the privileged process. It will remain privileged * even after the foreground process drops its privileges. */ pid = fork (); if (pid) { int status; /* * Foreground Process */ context->background_pid = pid; /* close our copy of child's socket */ close (fd[1]); /* don't let future subprocesses inherit child socket */ if (fcntl (fd[0], F_SETFD, FD_CLOEXEC) < 0) fprintf (stderr, "AUTH-PAM: Set FD_CLOEXEC flag on socket file descriptor failed\n"); /* wait for background child process to initialize */ status = recv_control (fd[0]); if (status == RESPONSE_INIT_SUCCEEDED) { context->foreground_fd = fd[0]; return (openvpn_plugin_handle_t) context; } } else { /* * Background Process */ /* close all parent fds except our socket back to parent */ close_fds_except (fd[1]); /* Ignore most signals (the parent will receive them) */ set_signals (); #ifdef DO_DAEMONIZE /* Daemonize if --daemon option is set. */ daemonize (envp); #endif /* execute the event loop */ pam_server (fd[1], argv[1], context->verb, &name_value_list); close (fd[1]); exit (0); return 0; /* NOTREACHED */ } error: if (context) free (context); return NULL; }
/* * Background process -- runs with privilege. */ static void down_root_server (const int fd, char *command, const char *argv[], const char *envp[], const int verb) { const char *p[3]; char *command_line = NULL; char *argv_cat = NULL; int i; /* * Do initialization */ if (DEBUG (verb)) fprintf (stderr, "DOWN-ROOT: BACKGROUND: INIT command='%s'\n", command); /* * Tell foreground that we initialized successfully */ if (send_control (fd, RESPONSE_INIT_SUCCEEDED) == -1) { fprintf (stderr, "DOWN-ROOT: BACKGROUND: write error on response socket [1]\n"); goto done; } /* * Build command line */ if (string_array_len (argv) >= 2) argv_cat = build_command_line (&argv[1]); else argv_cat = build_command_line (NULL); p[0] = command; p[1] = argv_cat; p[2] = NULL; command_line = build_command_line (p); /* * Save envp in environment */ for (i = 0; envp[i]; ++i) { putenv ((char *)envp[i]); } /* * Event loop */ while (1) { int command_code; int status; /* get a command from foreground process */ command_code = recv_control (fd); if (DEBUG (verb)) fprintf (stderr, "DOWN-ROOT: BACKGROUND: received command code: %d\n", command_code); switch (command_code) { case COMMAND_RUN_SCRIPT: status = system (command_line); if (system_ok (status)) /* Succeeded */ { if (send_control (fd, RESPONSE_SCRIPT_SUCCEEDED) == -1) { fprintf (stderr, "DOWN-ROOT: BACKGROUND: write error on response socket [2]\n"); goto done; } } else /* Failed */ { if (send_control (fd, RESPONSE_SCRIPT_FAILED) == -1) { fprintf (stderr, "DOWN-ROOT: BACKGROUND: write error on response socket [3]\n"); goto done; } } break; case COMMAND_EXIT: goto done; case -1: fprintf (stderr, "DOWN-ROOT: BACKGROUND: read error on command channel\n"); goto done; default: fprintf (stderr, "DOWN-ROOT: BACKGROUND: unknown command code: code=%d, exiting\n", command_code); goto done; } } done: if (argv_cat) free (argv_cat); if (command_line) free (command_line); if (DEBUG (verb)) fprintf (stderr, "DOWN-ROOT: BACKGROUND: EXIT\n"); return; }
OPENVPN_EXPORT openvpn_plugin_handle_t openvpn_plugin_open_v1(unsigned int *type_mask, const char *argv[], const char *envp[]) { struct down_root_context *context; int i = 0; /* * Allocate our context */ context = (struct down_root_context *) calloc(1, sizeof(struct down_root_context)); if (!context) { warn("DOWN-ROOT: Could not allocate memory for plug-in context"); goto error; } context->foreground_fd = -1; /* * Intercept the --up and --down callbacks */ *type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_UP) | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_DOWN); /* * Make sure we have two string arguments: the first is the .so name, * the second is the script command. */ if (string_array_len(argv) < 2) { fprintf(stderr, "DOWN-ROOT: need down script command\n"); goto error; } /* * Save the arguments in our context */ context->command = calloc(string_array_len(argv), sizeof(char *)); if (!context->command) { warn("DOWN-ROOT: Could not allocate memory for command array"); goto error; } /* Ignore argv[0], as it contains just the plug-in file name */ for (i = 1; i < string_array_len(argv); i++) { context->command[i-1] = (char *) argv[i]; } /* * Get verbosity level from environment */ { const char *verb_string = get_env("verb", envp); if (verb_string) { context->verb = atoi(verb_string); } } return (openvpn_plugin_handle_t) context; error: free_context(context); return NULL; }
OPENVPN_EXPORT openvpn_plugin_handle_t openvpn_plugin_open_v2 (unsigned int *type_mask, const char *argv[], const char *envp[], struct openvpn_plugin_string_list **return_list) { ldap_context_t *context; const char *daemon_string = NULL; const char *log_redirect = NULL; const char *configfile = NULL; int rc = 0; uint8_t allow_core_files = 0; /* Are we in daemonized mode? If so, are we redirecting the logs? */ daemon_string = get_env ("daemon", envp); use_syslog = 0; if( daemon_string && daemon_string[0] == '1'){ log_redirect = get_env ("daemon_log_redirect", envp); if( !(log_redirect && log_redirect[0] == '1')) use_syslog = 1; } /* * Allocate our context */ context = ldap_context_new( ); if( !context ){ LOGERROR( "Failed to initialize ldap_context, no memory available?" ); goto error; } /* * Intercept the --auth-user-pass-verify callback. */ *type_mask = OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY); while ( ( rc = getopt ( string_array_len (argv), (char **)argv, ":H:D:c:t:WZC" ) ) != - 1 ){ switch( rc ) { case 'H': context->config->ldap->uri = strdup(optarg); break; case 'Z': context->config->ldap->ssl = strdup("start_tls"); break; case 'D': context->config->ldap->binddn = strdup(optarg); break; case 'W': context->config->ldap->bindpw = get_passwd("BindPW Password: "******"Password is %s: length: %d\n", config->bindpw, strlen(config->bindpw) ); break; case 'c': configfile = optarg; break; case 't': context->config->ldap->timeout = atoi( optarg ); break; case 'C': LOGDEBUG("Core file generation requested"); allow_core_files = 1; break; case '?': LOGERROR("Unknown Option -%c !!", optopt ); break; case ':': LOGERROR ("Missing argument for option -%c !!", optopt ); break; default: LOGERROR ("?? getopt returned character code 0%o ??", rc); abort(); } } #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE) if (allow_core_files){ LOGDEBUG ("Setting core file"); unlimit_core_size(); } #endif /** * Parse configuration file is -c filename is provided * If not provided, use a default config file OCONFIG * This file must exists even though it might be empty */ if( configfile == NULL) { configfile = OCONFIG; } if( config_parse_file( configfile, context->config ) ){ goto error; } /** * Set default config values */ config_set_default( context->config ); /* when ldap userconf is define, we need to hook onto those callbacks */ if( config_is_pf_enabled( context->config )){ *type_mask |= OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ENABLE_PF); } #ifdef ENABLE_LDAPUSERCONF *type_mask |= OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_CONNECT_V2) | OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_DISCONNECT); #else if( config_is_redirect_gw_enabled( context->config ) ){ *type_mask |= OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_CONNECT_V2); } #endif /* * Get verbosity level from environment */ const char *verb_string = get_env ("verb", envp); if (verb_string) context->verb = atoi (verb_string); if( DODEBUG( context->verb ) ) config_dump( context->config ); /* set up mutex/cond */ pthread_mutex_init (&action_mutex, NULL); pthread_cond_init (&action_cond, NULL); /* start our authentication thread */ pthread_attr_setdetachstate(&action_thread_attr, PTHREAD_CREATE_JOINABLE); rc = pthread_create(&action_thread, &action_thread_attr, action_thread_main_loop, context); switch( rc ){ case EAGAIN: LOGERROR( "pthread_create returned EAGAIN: lacking resources" ); break; case EINVAL: LOGERROR( "pthread_create returned EINVAL: invalid attributes" ); break; case EPERM: LOGERROR( "pthread_create returned EPERM: no permission to create thread" ); break; case 0: break; default: LOGERROR( "pthread_create returned an unhandled value: %d", rc ); } if( rc == 0) return (openvpn_plugin_handle_t) context; /* Failed to initialize, free resources */ pthread_attr_destroy( &action_thread_attr ); pthread_mutex_destroy( &action_mutex ); pthread_cond_destroy( &action_cond ); error: if ( context ){ ldap_context_free (context); } return NULL; }