/* Build: cc -std=c99 -pedantic -Wall -Werror -lpam -o pwc pwc.c */ #include #include #include #include #include #include static const char * const me = "myservice"; static pam_handle_t *pamh = NULL; static int auth_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata); static int auth_pam(const char*, const char*, const char*); struct cred_t { const char *uname; /* user name */ const char *pass; /* password */ }; typedef struct cred_t cred_t; #define COPY_STRING(s) (s ? strdup(s) : NULL) static int auth_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata) { int i; cred_t *cred = (cred_t *) appdata; struct pam_response *reply; reply = calloc(num_msg, sizeof *reply); if (reply == NULL) return PAM_BUF_ERR; for (i = 0; i < num_msg; i++) { switch (msg[i]->msg_style) { case PAM_PROMPT_ECHO_ON: /* assume want user name */ reply[i].resp_retcode = PAM_SUCCESS; reply[i].resp = COPY_STRING(cred->uname); /* PAM frees resp. */ break; case PAM_PROMPT_ECHO_OFF: /* assume want password */ reply[i].resp_retcode = PAM_SUCCESS; reply[i].resp = COPY_STRING(cred->pass); /* PAM frees resp. */ break; case PAM_TEXT_INFO: case PAM_ERROR_MSG: reply[i].resp_retcode = PAM_SUCCESS; reply[i].resp = NULL; break; default: /* unknown message style */ free(reply); return PAM_CONV_ERR; } } *resp = reply; return PAM_SUCCESS; } static int auth_pam(const char *name, const char *pass, const char *remotehost) { const void *item; int e; cred_t auth_cred = { name, pass }; struct pam_conv conv = { &auth_conv, &auth_cred }; e = pam_start(me, name, &conv, &pamh); if (e != PAM_SUCCESS) errx(2, "cannot start PAM: %s", pam_strerror(pamh, e)); e = pam_acct_mgmt(pamh, PAM_SILENT); /* Expired password shouldn't prevent the job from running. */ if (e != PAM_SUCCESS && e != PAM_NEW_AUTHTOK_REQD) errx(3, "Account %s unavailable: %s", name, pam_strerror(pamh, e)); e = pam_set_item(pamh, PAM_RHOST, remotehost); if (e != PAM_SUCCESS) errx(3, "pam_set_item(PAM_RHOST): %s", pam_strerror(pamh, e)); e = pam_authenticate(pamh, 0); switch (e) { case PAM_SUCCESS: if ((e = pam_get_item(pamh, PAM_USER, &item)) == PAM_SUCCESS) printf ("PAM OK: %s\n", (const char *) item); else errx(4, "Couldn't get PAM_USER: %s", pam_strerror(pamh, e)); break; /* case PAM_AUTH_ERR: case PAM_USER_UNKNOWN: case PAM_MAXTRIES: */ default: errx(5, "pam_authenticate: %s", pam_strerror(pamh, e)); break; } pam_end(pamh, e); return (0); } int main(int argc, char* argv[]) { if (argc < 4) errx(1, "Usage: %s username password remotehost\n", argv[0]); auth_pam(argv[1], argv[2], argv[3]); return (0); }