/
ECKrbAuth.cpp
147 lines (131 loc) · 3.6 KB
/
ECKrbAuth.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
* SPDX-License-Identifier: AGPL-3.0-only
* Copyright 2005 - 2016 Zarafa and its licensors
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <string>
#include "ECKrbAuth.h"
#ifndef HAVE_KRB5
namespace KC {
ECRESULT ECKrb5AuthenticateUser(const std::string &user,
const std::string &pass, std::string *lpstrError)
{
*lpstrError = "Server is not compiled with kerberos support.";
return KCERR_NO_SUPPORT;
}
}
#else
// error_message() is wrongly typed in c++ context
extern "C" {
#include <krb5.h>
#include <et/com_err.h>
}
using namespace std::string_literals;
namespace KC {
ECRESULT ECKrb5AuthenticateUser(const std::string &strUsername, const std::string &strPassword, std::string *lpstrError)
{
ECRESULT er = erSuccess;
krb5_get_init_creds_opt options;
krb5_creds my_creds;
krb5_context ctx;
krb5_principal me;
char *name = NULL;
memset(&ctx, 0, sizeof(ctx));
memset(&me, 0, sizeof(me));
auto code = krb5_init_context(&ctx);
if (code) {
*lpstrError = "Unable to initialize kerberos 5 library: code "s + error_message(code);
er = KCERR_INVALID_PARAMETER;
goto exit;
}
code = krb5_parse_name(ctx, strUsername.c_str(), &me);
if (code) {
*lpstrError = "Error parsing kerberos 5 username: code "s + error_message(code);
er = KCERR_INVALID_PARAMETER;
goto exit;
}
code = krb5_unparse_name(ctx, me, &name);
if (code) {
*lpstrError = "Error unparsing kerberos 5 username: code "s + error_message(code);
er = KCERR_INVALID_PARAMETER;
goto exit;
}
krb5_get_init_creds_opt_init(&options);
memset(&my_creds, 0, sizeof(my_creds));
code = krb5_get_init_creds_password(ctx, &my_creds, me, strPassword.c_str(), 0, 0, 0, nullptr, &options);
if (code) {
*lpstrError = error_message(code);
er = KCERR_LOGON_FAILED;
goto exit;
}
exit:
if (name)
krb5_free_unparsed_name(ctx, name);
if (me)
krb5_free_principal(ctx, me);
if (ctx)
krb5_free_context(ctx);
memset(&ctx, 0, sizeof(ctx));
memset(&me, 0, sizeof(me));
return er;
}
} /* namespace */
#endif /* HAVE_KRB5 */
#ifndef HAVE_PAM
namespace KC {
ECRESULT ECPAMAuthenticateUser(const char *szPamService,
const std::string &strUsername, const std::string &strPassword,
std::string *lpstrError)
{
*lpstrError = "Server is not compiled with pam support.";
return KCERR_NO_SUPPORT;
}
}
#else
#include <security/pam_appl.h>
namespace KC {
static int converse(int num_msg, const struct pam_message **msg,
struct pam_response **resp, void *appdata_ptr)
{
auto password = static_cast<const char *>(appdata_ptr);
if (!resp || !msg || !password)
return PAM_CONV_ERR;
auto response = static_cast<struct pam_response *>(malloc(num_msg * sizeof(**resp)));
if (!response)
return PAM_BUF_ERR;
for (int i = 0; i < num_msg; ++i) {
response[i].resp_retcode = 0;
response[i].resp = 0;
if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF) {
response[i].resp = strdup(password);
} else {
free(response);
return PAM_CONV_ERR;
}
}
*resp = response;
return PAM_SUCCESS;
}
ECRESULT ECPAMAuthenticateUser(const char *szPamService,
const std::string &strUsername, const std::string &strPassword,
std::string *lpstrError)
{
pam_handle_t *pamh = nullptr;
struct pam_conv conv_info = {&converse, const_cast<char *>(strPassword.c_str())};
auto res = pam_start(szPamService, strUsername.c_str(), &conv_info, &pamh);
if (res != PAM_SUCCESS) {
*lpstrError = pam_strerror(nullptr, res);
return KCERR_LOGON_FAILED;
}
res = pam_authenticate(pamh, PAM_SILENT);
pam_end(pamh, res);
if (res != PAM_SUCCESS) {
*lpstrError = pam_strerror(nullptr, res);
return KCERR_LOGON_FAILED;
}
return erSuccess;
}
} /* namespace */
#endif /* HAVE_PAM */