main.c 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. #include <assert.h>
  2. #include <security/pam_appl.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <unistd.h> // getpass
  7. // apt install libpam0g-dev
  8. // compile with flag -lpam
  9. char *pam_get_str(const pam_handle_t *pamh, int item_type) {
  10. char *str;
  11. assert(pam_get_item(pamh, item_type, (const void **)&str) == PAM_SUCCESS);
  12. return str;
  13. }
  14. int conv(int num_msg, const struct pam_message **msg,
  15. struct pam_response **resp, void *appdata_ptr) {
  16. // [...] *resp is a struct pam_response array [...]
  17. *resp = calloc(num_msg, sizeof(struct pam_response));
  18. assert(*resp != NULL);
  19. for (int i = 0; i < num_msg; i++) {
  20. // getpass returns a statically allocated string
  21. (*resp)[i].resp = strdup(getpass(msg[i]->msg));
  22. }
  23. return PAM_SUCCESS;
  24. }
  25. int main(int argc, char **argv) {
  26. char *service_name;
  27. if (argc > 1) {
  28. service_name = argv[1];
  29. } else {
  30. service_name = "test";
  31. }
  32. char *user;
  33. if (argc > 2) {
  34. user = argv[2];
  35. } else {
  36. user = NULL; // ask later
  37. }
  38. const struct pam_conv pam_conversation = {conv, NULL};
  39. pam_handle_t *pamh; // blind structure, see security/_pam_types.h
  40. int status = pam_start(service_name, user, &pam_conversation, &pamh);
  41. if (status != PAM_SUCCESS) {
  42. fprintf(stderr, "pam_start: %s\n", pam_strerror(pamh, PAM_SYSTEM_ERR));
  43. return 1;
  44. } else {
  45. printf("PAM service name \"%s\"\n", pam_get_str(pamh, PAM_SERVICE));
  46. int status = pam_authenticate(pamh, 0);
  47. if (status != PAM_SUCCESS) {
  48. fprintf(stderr, "pam_authenticate: %s\n", pam_strerror(pamh, status));
  49. } else {
  50. user = pam_get_str(pamh, PAM_USER);
  51. fprintf(stderr, "Successfully authenticated user \"%s\".\n", user);
  52. fprintf(stdout, "%s\n", user);
  53. }
  54. assert(pam_end(pamh, status) == PAM_SUCCESS);
  55. return status == PAM_SUCCESS ? 0 : 2;
  56. }
  57. }