passdb-pam.c revision 72fe7206d6a695fee2dc43c390b38e1d39b9b543
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen Based on auth_pam.c from popa3d by Solar Designer <solar@openwall.com>.
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen You're allowed to do whatever you like with this software (including
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen re-distribution in source and/or binary form, with or without
1171f0abf442638bac1827bb24a0b6b8eb682a82Timo Sirainen modification), provided that credit is given where it is due and any
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen modified versions are marked as such. There's absolutely no warranty.
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen#if !defined(_SECURITY_PAM_APPL_H) && !defined(LINUX_PAM) && !defined(_OPENPAM)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Sun's PAM doesn't use const. we use a bit dirty hack to check it.
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen Originally it was just __sun__ check, but HP/UX also uses Sun's PAM
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen so I thought this might work better. */
fcfb528483369975066c6adf1c55c16e6fb6e91fTimo Sirainen/* Linux-PAM prior to 0.74 */
72368bc3058d36912317ffe55e6017205f4fa036Timo Sirainenstatic int pam_userpass_conv(int num_msg, linux_const struct pam_message **msg,
72368bc3058d36912317ffe55e6017205f4fa036Timo Sirainen struct pam_response **resp, void *appdata_ptr)
72368bc3058d36912317ffe55e6017205f4fa036Timo Sirainen /* @UNSAFE */
72368bc3058d36912317ffe55e6017205f4fa036Timo Sirainen struct pam_userpass *userpass = (struct pam_userpass *) appdata_ptr;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if (num_msg != 1 || msg[0]->msg_style != PAM_BINARY_PROMPT)
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen if (PAM_BP_RCONTROL(prompt) != PAM_BPC_SELECT ||
785b1ca149341b70bf2cb8cc3049f1c4c1070b52Timo Sirainen strncmp(input, USERPASS_AGENT_ID "/", USERPASS_AGENT_ID_LENGTH + 1))
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen if ((flags & USERPASS_USER_MASK) == USERPASS_USER_FIXED &&
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (!(*resp = malloc(sizeof(struct pam_response))))
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen PAM_BP_RENEW(&prompt, PAM_BPC_DONE, userlen + 1 + passlen);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen memcpy(output + userlen + 1, userpass->pass, passlen);
73a44af966c790560a72a0447f37bb35b1031a83Timo Sirainen if (!(*resp = malloc(num_msg * sizeof(struct pam_response))))
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen for (i = 0; i < num_msg; i++) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen i_fatal_status(FATAL_OUTOFMEM, "Out of memory");
73a44af966c790560a72a0447f37bb35b1031a83Timo Sirainen i_fatal_status(FATAL_OUTOFMEM, "Out of memory");
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen while (--i >= 0) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenstatic int pam_auth(struct auth_request *request,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if ((status = pam_authenticate(pamh, 0)) != PAM_SUCCESS) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen *error = t_strdup_printf("pam_authenticate() failed: %s",
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if ((status = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen *error = t_strdup_printf("pam_setcred() failed: %s",
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if ((status = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen *error = t_strdup_printf("pam_acct_mgmt() failed: %s",
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if ((status = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen "pam_open_session() failed: %s",
5e4f94015f5bbc9eefb1f2cb7af81ed50dcd2b39Timo Sirainen if ((status = pam_close_session(pamh, 0)) != PAM_SUCCESS) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen "pam_close_session() failed: %s",
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen status = pam_get_item(pamh, PAM_USER, (linux_const void **)&item);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen *error = t_strdup_printf("pam_get_item() failed: %s",
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen auth_request_set_field(request, "user", item, NULL);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenpam_verify_plain_child(struct auth_request *request, const char *service,
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen const char *str;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen status = pam_start(service, request->user, &conv, &pamh);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen str = t_strdup_printf("pam_start() failed: %s",
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen const char *host = net_ip2addr(&request->remote_ip);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if ((status2 = pam_end(pamh, status)) == PAM_SUCCESS) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* FIXME: check for PASSDB_RESULT_UNKNOWN_USER
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen result = status == PAM_SUCCESS ? PASSDB_RESULT_OK :
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen buf = buffer_create_data(pool_datastack_create(),
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen /* may truncate the error. tough luck. */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen write(fd, buf_data, buffer_get_used_size(buf));
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen struct auth_request *auth_request = request->request;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen /* POSIX guarantees that writing 512 bytes or less to pipes is atomic.
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen We rely on that. */
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen "read() from child process failed: %m");
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen } else if (ret == 0) {
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen /* it died */
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen "Child process died");
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen /* error message included */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (result == PASSDB_RESULT_INTERNAL_FAILURE) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen "close(child input) failed: %m");
dd4b5f14b71b01a84af942e720a2d6e5f15ee1a7Timo Sirainenstatic void wait_timeout(void *context __attr_unused__)
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen /* FIXME: if we ever do some other kind of forking, this needs fixing */
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen while ((pid = waitpid(-1, &status, WNOHANG)) != 0) {
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainenpam_verify_plain(struct auth_request *request, const char *password,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service = service_name != NULL ? service_name : request->service;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen auth_request_log_error(request, "pam", "pipe() failed: %m");
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen callback(PASSDB_RESULT_INTERNAL_FAILURE, request);
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen auth_request_log_error(request, "pam", "fork() failed: %m");
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen callback(PASSDB_RESULT_INTERNAL_FAILURE, request);
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen pam_verify_plain_child(request, service, password, fd[1]);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen "close(fd[1]) failed: %m");
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainen pam_auth_request = i_new(struct pam_auth_request, 1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen io_add(fd[0], IO_READ, pam_child_input, pam_auth_request);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen to_wait = timeout_add(1000, wait_timeout, NULL);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen const char *const *t_args;
1b97a59edb073e9a89ac43a21a9abe5d590d4a56Timo Sirainenstatic void pam_deinit(void)