| 
					
				 | 
			
			
				@@ -0,0 +1,56 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <assert.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <security/pam_appl.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <stdio.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <stdlib.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <string.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <unistd.h> // getpass 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// apt install libpam0g-dev 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// compile with flag -lpam 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+char *pam_get_str(const pam_handle_t *pamh, int item_type) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  char *str; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  assert(pam_get_item(pamh, item_type, (const void **)&str) == PAM_SUCCESS); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return str; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+int conv(int num_msg, const struct pam_message **msg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         struct pam_response **resp, void *appdata_ptr) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // [...] *resp is a struct pam_response array [...] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  *resp = calloc(num_msg, sizeof(struct pam_response)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  assert(*resp != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (int i = 0; i < num_msg; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // getpass returns a statically allocated string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    (*resp)[i].resp = strdup(getpass(msg[i]->msg)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return PAM_SUCCESS; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+int main(int argc, char **argv) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const char *user = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const char *service_name; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (argc > 1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    service_name = argv[1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    service_name = "test"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const struct pam_conv pam_conversation = {conv, NULL}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pam_handle_t *pamh; // blind structure, see security/_pam_types.h 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  int status = pam_start(service_name, NULL, &pam_conversation, &pamh); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (status != PAM_SUCCESS) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fprintf(stderr, "pam_start: %s\n", pam_strerror(pamh, PAM_SYSTEM_ERR)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    printf("PAM service name \"%s\"\n", pam_get_str(pamh, PAM_SERVICE)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    int status = pam_authenticate(pamh, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (status != PAM_SUCCESS) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      fprintf(stderr, "pam_authenticate: %s\n", pam_strerror(pamh, status)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      char *user = pam_get_str(pamh, PAM_USER); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      fprintf(stderr, "Successfully authenticated user \"%s\".\n", user); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      fprintf(stdout, "%s\n", user); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    assert(pam_end(pamh, status) == PAM_SUCCESS); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return status == PAM_SUCCESS ? 0 : 2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |