|
@@ -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;
|
|
|
+ }
|
|
|
+}
|