passdb-pam.c revision dd93aba1901a457346990f49c54a738947dc7128
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
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen re-distribution in source and/or binary form, with or without
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen modification), provided that credit is given where it is due and any
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen modified versions are marked as such. There's absolutely no warranty.
ad850190d946d34966a56838cfdb216e021b5b5fTimo Sirainen#if !defined(_SECURITY_PAM_APPL_H) && !defined(LINUX_PAM) && !defined(_OPENPAM)
ad850190d946d34966a56838cfdb216e021b5b5fTimo Sirainen/* Sun's PAM doesn't use const. we use a bit dirty hack to check it.
d35fee8d1e5e31614dba5e64d45ed23c7d6bfa53Timo Sirainen Originally it was just __sun__ check, but HP/UX also uses Sun's PAM
d35fee8d1e5e31614dba5e64d45ed23c7d6bfa53Timo Sirainen so I thought this might work better. */
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainenpam_userpass_conv(int num_msg, linux_const struct pam_message **msg,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct pam_response **resp_r, void *appdata_ptr)
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen /* @UNSAFE */
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen struct passdb_module *_passdb = ctx->request->passdb->passdb;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen struct pam_passdb_module *passdb = (struct pam_passdb_module *)_passdb;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen resp = calloc(num_msg, sizeof(struct pam_response));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_fatal_status(FATAL_OUTOFMEM, "Out of memory");
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen for (i = 0; i < num_msg; i++) {
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen /* Assume we're asking for user. We might not ever
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen get here because PAM already knows the user. */
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen i_fatal_status(FATAL_OUTOFMEM, "Out of memory");
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen /* Assume we're asking for password */
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen i_fatal_status(FATAL_OUTOFMEM, "Out of memory");
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen while (--i >= 0) {
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainenstatic const char *
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainenpam_get_missing_service_file_path(const char *service ATTR_UNUSED)
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen /* Uses /etc/pam.conf - we're not going to parse that */
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen /* check and complain only once */
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen path = t_strdup_printf("/etc/pam.d/%s", service);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen /* looks like it's missing. but before assuming that the system
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen even uses /etc/pam.d, make sure that it exists. */
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen /* exists or is unknown */
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainenstatic int try_pam_auth(struct auth_request *request, pam_handle_t *pamh,
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen struct passdb_module *_module = request->passdb->passdb;
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen struct pam_passdb_module *module = (struct pam_passdb_module *)_module;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if ((status = pam_authenticate(pamh, 0)) != PAM_SUCCESS) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen path = pam_get_missing_service_file_path(service);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen str = t_strconcat("pam_authenticate() failed: ",
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* log this as error, since it probably is */
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen str = t_strdup_printf("%s (%s missing?)", str, path);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen auth_request_log_error(request, "pam", "%s", str);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen str = t_strconcat(str, " (password mismatch?)",
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen auth_request_log_info(request, "pam", "%s", str);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if ((status = pam_setcred(pamh, PAM_ESTABLISH_CRED)) !=
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen "pam_setcred() failed: %s",
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen if ((status = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) {
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen "pam_acct_mgmt() failed: %s",
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen if ((status = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen "pam_open_session() failed: %s",
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen if ((status = pam_close_session(pamh, 0)) != PAM_SUCCESS) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "pam_close_session() failed: %s",
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen "pam_get_item(PAM_USER) failed: %s",
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen auth_request_set_field(request, "user", item, NULL);
e192a3b1ca8ae857e7d87298ea507d32977ba570Timo Sirainenstatic void set_pam_items(struct auth_request *request, pam_handle_t *pamh)
c4877db8b6559846f4b58be8e42422dc734c193fTimo Sirainen /* These shouldn't fail, and we don't really care if they do. */
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen (void)pam_set_item(pamh, PAM_RUSER, request->user);
8b9342aa96b2f297e23afb261f9f7dd859800952Timo Sirainen /* TTY is needed by eg. pam_access module */
37e6cf44d61a81c6839e3ab76234b54309d8d292Timo Sirainenpam_verify_plain_call(struct auth_request *request, const char *service,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen status = pam_start(service, request->user, &conv, &pamh);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen auth_request_log_error(request, "pam", "pam_start() failed: %s",
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen status = try_pam_auth(request, pamh, service);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if ((status2 = pam_end(pamh, status)) != PAM_SUCCESS) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen auth_request_log_error(request, "pam", "pam_end() failed: %s",
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (result != PASSDB_RESULT_OK && ctx.failure_msg != NULL) {
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainenpam_verify_plain(struct auth_request *request, const char *password,
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen struct passdb_module *_module = request->passdb->passdb;
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen struct pam_passdb_module *module = (struct pam_passdb_module *)_module;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen var_expand(expanded_service, module->service_name,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen auth_request_get_var_expand_table(request, NULL));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen auth_request_log_debug(request, "pam", "lookup service=%s", service);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen result = pam_verify_plain_call(request, service, password);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainenpam_preinit(struct auth_passdb *auth_passdb, const char *args)
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen const char *const *t_args;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen module = p_new(auth_passdb->auth->pool, struct pam_passdb_module, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we're caching the password by using directly the plaintext password
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen given by the auth mechanism */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* -session for backwards compatibility */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (strcmp(t_args[i], "setcred=yes") == 0)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen else if (strncmp(t_args[i], "cache_key=", 10) == 0) {
f519e4c2ad4ef826f1b08f3e0138b9b287a52c80Timo Sirainen } else if (strcmp(t_args[i], "blocking=yes") == 0) {
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen /* ignore, for backwards compatibility */
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen } else if (strcmp(t_args[i], "failure_show_msg=yes") == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* for backwards compatibility */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_fatal("passdb pam: Unknown setting: %s", t_args[i]);