📄 auth-pam.c
字号:
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 (); /* Daemonize if --daemon option is set. */ daemonize (envp); /* 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;}OPENVPN_EXPORT intopenvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]){ struct auth_pam_context *context = (struct auth_pam_context *) handle; if (type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY && context->foreground_fd >= 0) { /* get username/password from envp string array */ const char *username = get_env ("username", envp); const char *password = get_env ("password", envp); if (username && strlen (username) > 0 && password) { if (send_control (context->foreground_fd, COMMAND_VERIFY) == -1 || send_string (context->foreground_fd, username) == -1 || send_string (context->foreground_fd, password) == -1) { fprintf (stderr, "AUTH-PAM: Error sending auth info to background process\n"); } else { const int status = recv_control (context->foreground_fd); if (status == RESPONSE_VERIFY_SUCCEEDED) return OPENVPN_PLUGIN_FUNC_SUCCESS; if (status == -1) fprintf (stderr, "AUTH-PAM: Error receiving auth confirmation from background process\n"); } } } return OPENVPN_PLUGIN_FUNC_ERROR;}OPENVPN_EXPORT voidopenvpn_plugin_close_v1 (openvpn_plugin_handle_t handle){ struct auth_pam_context *context = (struct auth_pam_context *) handle; if (DEBUG (context->verb)) fprintf (stderr, "AUTH-PAM: close\n"); if (context->foreground_fd >= 0) { /* tell background process to exit */ if (send_control (context->foreground_fd, COMMAND_EXIT) == -1) fprintf (stderr, "AUTH-PAM: Error signaling background process to exit\n"); /* wait for background process to exit */ if (context->background_pid > 0) waitpid (context->background_pid, NULL, 0); close (context->foreground_fd); context->foreground_fd = -1; } free (context);}OPENVPN_EXPORT voidopenvpn_plugin_abort_v1 (openvpn_plugin_handle_t handle){ struct auth_pam_context *context = (struct auth_pam_context *) handle; /* tell background process to exit */ if (context->foreground_fd >= 0) { send_control (context->foreground_fd, COMMAND_EXIT); close (context->foreground_fd); context->foreground_fd = -1; }}/* * PAM conversation function */static intmy_conv (int n, const struct pam_message **msg_array, struct pam_response **response_array, void *appdata_ptr){ const struct user_pass *up = ( const struct user_pass *) appdata_ptr; struct pam_response *aresp; int i; int ret = PAM_SUCCESS; *response_array = NULL; if (n <= 0 || n > PAM_MAX_NUM_MSG) return (PAM_CONV_ERR); if ((aresp = calloc (n, sizeof *aresp)) == NULL) return (PAM_BUF_ERR); /* loop through each PAM-module query */ for (i = 0; i < n; ++i) { const struct pam_message *msg = msg_array[i]; aresp[i].resp_retcode = 0; aresp[i].resp = NULL; if (DEBUG (up->verb)) { fprintf (stderr, "AUTH-PAM: BACKGROUND: my_conv[%d] query='%s' style=%d\n", i, msg->msg ? msg->msg : "NULL", msg->msg_style); } if (up->name_value_list && up->name_value_list->len > 0) { /* use name/value list match method */ const struct name_value_list *list = up->name_value_list; int j; /* loop through name/value pairs */ for (j = 0; j < list->len; ++j) { const char *match_name = list->data[j].name; const char *match_value = list->data[j].value; if (name_value_match (msg->msg, match_name)) { /* found name/value match */ const char *return_value = NULL; if (DEBUG (up->verb)) fprintf (stderr, "AUTH-PAM: BACKGROUND: name match found, query/match-string ['%s', '%s'] = '%s'\n", msg->msg, match_name, match_value); if (!strcmp (match_value, "USERNAME")) return_value = up->username; else if (!strcmp (match_value, "PASSWORD")) return_value = up->password; else return_value = match_value; aresp[i].resp = strdup (return_value); if (aresp[i].resp == NULL) ret = PAM_CONV_ERR; break; } } if (j == list->len) ret = PAM_CONV_ERR; } else { /* use PAM_PROMPT_ECHO_x hints */ switch (msg->msg_style) { case PAM_PROMPT_ECHO_OFF: aresp[i].resp = strdup (up->password); if (aresp[i].resp == NULL) ret = PAM_CONV_ERR; break; case PAM_PROMPT_ECHO_ON: aresp[i].resp = strdup (up->username); if (aresp[i].resp == NULL) ret = PAM_CONV_ERR; break; case PAM_ERROR_MSG: case PAM_TEXT_INFO: break; default: ret = PAM_CONV_ERR; break; } } } if (ret == PAM_SUCCESS) *response_array = aresp; return ret;}/* * Return 1 if authenticated and 0 if failed. * Called once for every username/password * to be authenticated. */static intpam_auth (const char *service, const struct user_pass *up){ struct pam_conv conv; pam_handle_t *pamh = NULL; int status = PAM_SUCCESS; int ret = 0; const int name_value_list_provided = (up->name_value_list && up->name_value_list->len > 0); /* Initialize PAM */ conv.conv = my_conv; conv.appdata_ptr = (void *)up; status = pam_start (service, name_value_list_provided ? NULL : up->username, &conv, &pamh); if (status == PAM_SUCCESS) { /* Call PAM to verify username/password */ status = pam_authenticate(pamh, 0); if (status == PAM_SUCCESS) status = pam_acct_mgmt (pamh, 0); if (status == PAM_SUCCESS) ret = 1; /* Output error message if failed */ if (!ret) { fprintf (stderr, "AUTH-PAM: BACKGROUND: user '%s' failed to authenticate: %s\n", up->username, pam_strerror (pamh, status)); } /* Close PAM */ pam_end (pamh, status); } return ret;}/* * Background process -- runs with privilege. */static voidpam_server (int fd, const char *service, int verb, const struct name_value_list *name_value_list){ struct user_pass up; int command;#if DLOPEN_PAM static const char pam_so[] = "libpam.so";#endif /* * Do initialization */ if (DEBUG (verb)) fprintf (stderr, "AUTH-PAM: BACKGROUND: INIT service='%s'\n", service);#if DLOPEN_PAM /* * Load PAM shared object */ if (!dlopen_pam (pam_so)) { fprintf (stderr, "AUTH-PAM: BACKGROUND: could not load PAM lib %s: %s\n", pam_so, dlerror()); send_control (fd, RESPONSE_INIT_FAILED); goto done; }#endif /* * Tell foreground that we initialized successfully */ if (send_control (fd, RESPONSE_INIT_SUCCEEDED) == -1) { fprintf (stderr, "AUTH-PAM: BACKGROUND: write error on response socket [1]\n"); goto done; } /* * Event loop */ while (1) { memset (&up, 0, sizeof (up)); up.verb = verb; up.name_value_list = name_value_list; /* get a command from foreground process */ command = recv_control (fd); if (DEBUG (verb)) fprintf (stderr, "AUTH-PAM: BACKGROUND: received command code: %d\n", command); switch (command) { case COMMAND_VERIFY: if (recv_string (fd, up.username, sizeof (up.username)) == -1 || recv_string (fd, up.password, sizeof (up.password)) == -1) { fprintf (stderr, "AUTH-PAM: BACKGROUND: read error on command channel: code=%d, exiting\n", command); goto done; } if (DEBUG (verb)) fprintf (stderr, "AUTH-PAM: BACKGROUND: USER/PASS: %s/%s\n", up.username, up.password); if (pam_auth (service, &up)) /* Succeeded */ { if (send_control (fd, RESPONSE_VERIFY_SUCCEEDED) == -1) { fprintf (stderr, "AUTH-PAM: BACKGROUND: write error on response socket [2]\n"); goto done; } } else /* Failed */ { if (send_control (fd, RESPONSE_VERIFY_FAILED) == -1) { fprintf (stderr, "AUTH-PAM: BACKGROUND: write error on response socket [3]\n"); goto done; } } break; case COMMAND_EXIT: goto done; case -1: fprintf (stderr, "AUTH-PAM: BACKGROUND: read error on command channel\n"); goto done; default: fprintf (stderr, "AUTH-PAM: BACKGROUND: unknown command code: code=%d, exiting\n", command); goto done; } } done:#if DLOPEN_PAM dlclose_pam ();#endif if (DEBUG (verb)) fprintf (stderr, "AUTH-PAM: BACKGROUND: EXIT\n"); return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -