1 /* This file is part of pam-modules.
2 Copyright (C) 2005-2008, 2010-2012, 2014-2015, 2018 Sergey Poznyakoff
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 3 of the License, or (at your
7 option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program. If not, see <http://www.gnu.org/licenses/>. */
16
17 #include "pam_sql.h"
18
19 /* indicate the following groups are defined */
20 #define PAM_SM_AUTH
21 #define PAM_SM_SESSION
22
23 #define CNTL_AUTHTOK 0x0010
24
25 static int cntl_flags;
26 long gpam_sql_debug_level;
27 char *gpam_sql_config_file = SYSCONFDIR "/pam_sql.conf";
28
29 struct pam_opt pam_opt[] = {
30 { PAM_OPTSTR(debug), pam_opt_long, &debug_level },
31 { PAM_OPTSTR(debug), pam_opt_const, &debug_level, { 1 } },
32 { PAM_OPTSTR(audit), pam_opt_const, &debug_level, { 100 } },
33 { PAM_OPTSTR(waitdebug), pam_opt_null, NULL, { 0 },
34 gray_wait_debug_fun },
35 { PAM_OPTSTR(use_authtok), pam_opt_bitmask, &cntl_flags,
36 { CNTL_AUTHTOK } },
37 { PAM_OPTSTR(config), pam_opt_string, &gpam_sql_config_file },
38 { NULL }
39 };
40
41 static void
_pam_parse(int argc,const char ** argv)42 _pam_parse(int argc, const char **argv)
43 {
44 cntl_flags = 0;
45 debug_level = 0;
46 gpam_sql_config_file = SYSCONFDIR "/pam_sql.conf";
47 gray_log_init(0, gpam_sql_module_name, LOG_AUTHPRIV);
48 gray_parseopt(pam_opt, argc, argv);
49 }
50
51
52 static int
_pam_get_password(pam_handle_t * pamh,char ** password,const char * prompt)53 _pam_get_password(pam_handle_t *pamh, char **password, const char *prompt)
54 {
55 char *item, *token;
56 int retval;
57 struct pam_message msg[3], *pmsg[3];
58 struct pam_response *resp;
59 int i, replies;
60
61 DEBUG(90,("enter _pam_get_password"));
62
63 if (cntl_flags & CNTL_AUTHTOK) {
64 /*
65 * get the password from the PAM item
66 */
67 retval = pam_get_item(pamh, PAM_AUTHTOK,
68 (const void **) &item);
69 if (retval != PAM_SUCCESS) {
70 /* very strange. */
71 _pam_log(LOG_ALERT,
72 "can't retrieve password item: %s",
73 pam_strerror(pamh, retval));
74 return retval;
75 } else if (item != NULL) {
76 *password = item;
77 item = NULL;
78 return PAM_SUCCESS;
79 } else
80 return PAM_AUTHTOK_RECOVER_ERR;
81 }
82
83 /*
84 * ask user for the password
85 */
86 /* prepare to converse */
87
88 i = 0;
89 pmsg[i] = &msg[i];
90 msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
91 msg[i++].msg = (const void*)prompt;
92 replies = 1;
93
94 /* run conversation */
95 resp = NULL;
96 token = NULL;
97 retval = gray_converse(pamh, i, pmsg, &resp);
98
99 if (resp != NULL && resp[i - replies].resp) {
100 if (retval == PAM_SUCCESS) { /* a good conversation */
101 token = XSTRDUP(resp[i - replies].resp);
102 DEBUG(100,("app returned [%s]", token));
103 pam_set_item(pamh, PAM_AUTHTOK, token);
104 PAM_DROP_REPLY(resp, 1);
105 } else {
106 _pam_log(LOG_ERR, "conversation error: %s",
107 pam_strerror(pamh, retval));
108 }
109
110 } else {
111 retval = (retval == PAM_SUCCESS)
112 ? PAM_AUTHTOK_RECOVER_ERR : retval;
113 }
114
115 if (retval == PAM_SUCCESS) {
116 /*
117 * keep password as data specific to this module. pam_end()
118 * will arrange to clean it up.
119 */
120 retval = pam_set_data(pamh, "password",
121 (void *)token,
122 gray_cleanup_string);
123 if (retval != PAM_SUCCESS) {
124 _pam_log(LOG_CRIT,
125 "can't keep password: %s",
126 pam_strerror(pamh, retval));
127 gray_pam_delete(token);
128 } else {
129 *password = token;
130 token = NULL; /* break link to password */
131 }
132 } else {
133 _pam_log(LOG_ERR,
134 "unable to obtain a password: %s",
135 pam_strerror(pamh, retval));
136 }
137
138 DEBUG(90,("exit _pam_get_password: %d", retval));
139 return retval;
140 }
141
142
143 /* Configuration */
144 static struct gray_env *config_env;
145
146 char *
gpam_sql_find_config(const char * name)147 gpam_sql_find_config(const char *name)
148 {
149 return gray_env_get(config_env, name);
150 }
151
152 int
gpam_sql_check_boolean_config(const char * name,int defval)153 gpam_sql_check_boolean_config(const char *name, int defval)
154 {
155 const char *value = gpam_sql_find_config(name);
156 if (value)
157 defval = gray_boolean_true_p(value);
158 return defval;
159 }
160
161
162 const char *
gpam_sql_get_query(pam_handle_t * pamh,const char * name,gray_slist_t * pslist,int required)163 gpam_sql_get_query(pam_handle_t *pamh, const char *name, gray_slist_t *pslist,
164 int required)
165 {
166 gray_slist_t slist;
167 const char *query = gpam_sql_find_config(name);
168
169 if (!query) {
170 if (required)
171 gray_raise("%s: %s not defined", gpam_sql_config_file, name);
172 return NULL;
173 }
174
175 slist = gray_slist_create();
176 gray_expand_string(pamh, query, slist);
177 gray_slist_append_char(slist, 0);
178 *pslist = slist;
179 return gray_slist_finish(slist);
180 }
181
182 static const char *
get_query2(pam_handle_t * pamh,const char * name1,const char * name2,gray_slist_t * pslist,int required)183 get_query2(pam_handle_t *pamh, const char *name1, const char *name2,
184 gray_slist_t *pslist, int required)
185 {
186 gray_slist_t slist;
187 const char *query = gpam_sql_find_config(name1);
188
189 if (!query)
190 query = gpam_sql_find_config(name2);
191
192 if (!query) {
193 if (required)
194 gray_raise("%s: %s not defined",
195 gpam_sql_config_file, name1);
196 return NULL;
197 }
198
199 slist = gray_slist_create();
200 gray_expand_string(pamh, query, slist);
201 gray_slist_append_char(slist, 0);
202 *pslist = slist;
203 return gray_slist_finish(slist);
204 }
205
206
207 /* --- authentication management functions (only) --- */
208
209 PAM_EXTERN int
pam_sm_authenticate(pam_handle_t * pamh,int flags,int argc,const char ** argv)210 pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
211 {
212 const char *username;
213 char *password;
214 int retval = PAM_AUTH_ERR;
215 gray_pam_init(PAM_SERVICE_ERR);
216
217 /* parse arguments */
218 _pam_parse(argc, argv);
219
220 /* Get the username */
221 retval = pam_get_user(pamh, &username, NULL);
222 if (retval != PAM_SUCCESS || !username) {
223 DEBUG(1, ("can not get the username"));
224 return PAM_SERVICE_ERR;
225 }
226
227 /* Get the password */
228 if (_pam_get_password(pamh, &password, "Password:"))
229 return PAM_SERVICE_ERR;
230
231 if (retval != PAM_SUCCESS) {
232 _pam_log(LOG_ERR, "Could not retrive user's password");
233 return PAM_SERVICE_ERR;
234 }
235
236 if (gray_env_read(gpam_sql_config_file, &config_env))
237 retval = PAM_SERVICE_ERR;
238 else {
239 gray_slist_t slist;
240 /* FIXME: This comment is needed to pacify
241 `make check-sql-config' in doc:
242 gpam_sql_find_config("passwd-query") */
243 retval = gpam_sql_verify_user_pass(pamh, password,
244 get_query2(pamh, "passwd-query",
245 "query", &slist, 1));
246 gray_slist_free(&slist);
247 }
248
249 gray_env_free(config_env);
250 config_env = NULL;
251
252 switch (retval) {
253 case PAM_ACCT_EXPIRED:
254 _pam_log(LOG_NOTICE, "user '%s': account expired", username);
255 break;
256 case PAM_SUCCESS:
257 _pam_log(LOG_NOTICE, "user '%s' granted access", username);
258 break;
259 default:
260 _pam_log(LOG_NOTICE, "user '%s' failed to authenticate",
261 username);
262 }
263
264 return retval;
265 }
266
267 PAM_EXTERN int
pam_sm_setcred(pam_handle_t * pamh,int flags,int argc,const char ** argv)268 pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
269 {
270 return PAM_SUCCESS;
271 }
272
273 static int
sql_session_mgmt(pam_handle_t * pamh,int flags,int argc,const char ** argv,const char * query_name)274 sql_session_mgmt(pam_handle_t *pamh, int flags,
275 int argc, const char **argv, const char *query_name)
276 {
277 int retval;
278
279 gray_pam_init(PAM_SERVICE_ERR);
280
281 /* parse arguments */
282 _pam_parse(argc, argv);
283
284 if (gray_env_read(gpam_sql_config_file, &config_env))
285 retval = PAM_SERVICE_ERR;
286 else {
287 gray_slist_t slist;
288 retval = gpam_sql_acct(pamh,
289 gpam_sql_get_query(pamh, query_name,
290 &slist, 0));
291 gray_slist_free(&slist);
292 }
293
294 gray_env_free(config_env);
295 config_env = NULL;
296
297 return retval;
298 }
299
300 PAM_EXTERN int
pam_sm_open_session(pam_handle_t * pamh,int flags,int argc,const char ** argv)301 pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
302 {
303 /* FIXME: This comment is needed to pacify `make check-sql-config'
304 in doc:
305 gpam_sql_find_config("session-start-query") */
306 return sql_session_mgmt(pamh, flags, argc, argv,
307 "session-start-query");
308 }
309
310 PAM_EXTERN int
pam_sm_close_session(pam_handle_t * pamh,int flags,int argc,const char ** argv)311 pam_sm_close_session(pam_handle_t *pamh, int flags,
312 int argc, const char **argv)
313 {
314 /* FIXME: This comment is needed to pacify `make check-sql-config'
315 in doc:
316 gpam_sql_find_config("session-stop-query") */
317 return sql_session_mgmt(pamh, flags, argc, argv,
318 "session-stop-query");
319 }
320