Line data Source code
1 : /*
2 : Copyright (C) 2015 Red Hat
3 :
4 : SSSD tests: PAM tests
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include <stdint.h>
21 : #include <errno.h>
22 : #include <sys/types.h>
23 : #include "sss_cli.h"
24 :
25 : #include "responder/pam/pamsrv.h"
26 : #include "responder/common/responder_packet.h"
27 : #include "providers/data_provider.h"
28 :
29 : /* FIXME - move the definition to a private header */
30 : struct sss_packet {
31 : size_t memsize;
32 :
33 : /* Structure of the buffer:
34 : * Bytes Content
35 : * ---------------------------------
36 : * 0-15 packet header
37 : * 0-3 packet length (uint32_t)
38 : * 4-7 command type (uint32_t)
39 : * 8-11 status (uint32_t)
40 : * 12-15 reserved
41 : * 16+ packet body */
42 : uint8_t *buffer;
43 :
44 : /* io pointer */
45 : size_t iop;
46 : };
47 :
48 : /* Make linker happy */
49 16 : int __wrap_sss_parse_name_for_domains(TALLOC_CTX *memctx,
50 : struct sss_domain_info *domains,
51 : const char *default_domain,
52 : const char *orig,
53 : char **domain, char **name)
54 : {
55 : char *atsign;
56 :
57 16 : atsign = strrchr(orig, '@');
58 16 : if (atsign == NULL) {
59 16 : *domain = NULL;
60 16 : *name = talloc_strdup(memctx, orig);
61 16 : if (*name == NULL) {
62 0 : return ENOMEM;
63 : }
64 16 : return EOK;
65 : }
66 :
67 0 : *name = talloc_strndup(memctx, orig, atsign - orig);
68 0 : *domain = talloc_strdup(memctx, atsign+1);
69 0 : if (*name == NULL || *domain == NULL) {
70 0 : return ENOMEM;
71 : }
72 :
73 0 : return EOK;
74 : }
75 :
76 32 : void __wrap_sss_packet_get_body(struct sss_packet *packet, uint8_t **body, size_t *blen)
77 : {
78 32 : *body = packet->buffer;
79 32 : *blen = packet->memsize;
80 32 : }
81 :
82 : static struct cli_ctx *
83 16 : mock_pam_cctx(TALLOC_CTX *mem_ctx,
84 : enum sss_cli_command cmd,
85 : int cli_protocol_version,
86 : struct sss_cli_req_data *rd)
87 : {
88 16 : struct cli_ctx *cctx = NULL;
89 : int ret;
90 :
91 16 : cctx = talloc_zero(mem_ctx, struct cli_ctx);
92 16 : if (!cctx) goto fail;
93 :
94 16 : cctx->creq = talloc_zero(cctx, struct cli_request);
95 16 : if (cctx->creq == NULL) goto fail;
96 :
97 16 : cctx->cli_protocol_version = talloc_zero(cctx,
98 : struct cli_protocol_version);
99 16 : if (cctx->cli_protocol_version == NULL) goto fail;
100 :
101 16 : cctx->cli_protocol_version->version = cli_protocol_version;
102 :
103 16 : cctx->creq = talloc_zero(cctx, struct cli_request);
104 16 : if (cctx->creq == NULL) goto fail;
105 :
106 16 : ret = sss_packet_new(cctx->creq, 0, cmd, &cctx->creq->in);
107 16 : if (ret != EOK) goto fail;
108 :
109 16 : cctx->rctx = talloc_zero(cctx, struct resp_ctx);
110 16 : if (cctx->rctx == NULL) goto fail;
111 :
112 16 : cctx->creq->in->buffer = discard_const(rd->data);
113 16 : cctx->creq->in->memsize = rd->len;
114 :
115 16 : return cctx;
116 :
117 : fail:
118 0 : talloc_free(cctx);
119 0 : return NULL;
120 : }
121 :
122 : static struct pam_data *
123 16 : mock_pam_data(TALLOC_CTX *mem_ctx, enum sss_cli_command cmd)
124 : {
125 16 : struct pam_data *pd = NULL;
126 :
127 16 : pd = talloc_zero(mem_ctx, struct pam_data);
128 16 : if (pd == NULL) goto fail;
129 :
130 16 : pd->cmd = cmd;
131 16 : pd->authtok = sss_authtok_new(pd);
132 16 : pd->newauthtok = sss_authtok_new(pd);
133 16 : if (pd->authtok == NULL || pd->newauthtok == NULL) goto fail;
134 :
135 16 : return pd;
136 :
137 : fail:
138 0 : talloc_free(pd);
139 0 : return NULL;
140 : }
141 :
142 10 : static bool authtok_matches(struct sss_auth_token *authtok,
143 : const char *exp_pass)
144 : {
145 : int ret;
146 : const char *password;
147 : size_t pwlen;
148 :
149 10 : ret = sss_authtok_get_password(authtok, &password, &pwlen);
150 10 : if (ret != EOK) {
151 0 : return EINVAL;
152 : }
153 :
154 10 : if (strncmp(password, exp_pass, pwlen) == 0) {
155 5 : return true;
156 : }
157 :
158 5 : return false;
159 : }
160 :
161 10 : static int test_auth(struct pam_data *pd, const char *exp_pass)
162 : {
163 10 : pd->pam_status = PAM_AUTH_ERR;
164 :
165 10 : if (authtok_matches(pd->authtok, exp_pass) == true) {
166 5 : pd->pam_status = PAM_SUCCESS;
167 : }
168 :
169 10 : return EOK;
170 : }
171 :
172 0 : static int test_chauthtok(struct pam_data *pd, const char *exp_pass)
173 : {
174 0 : pd->pam_status = PAM_AUTH_ERR;
175 :
176 0 : if (authtok_matches(pd->authtok, exp_pass) == true
177 0 : && authtok_matches(pd->newauthtok, exp_pass) == true) {
178 0 : pd->pam_status = PAM_SUCCESS;
179 : }
180 :
181 0 : return EOK;
182 : }
183 :
184 10 : static int mock_pam_auth(struct pam_data *pd)
185 : {
186 10 : errno_t ret = PAM_SYSTEM_ERR;
187 :
188 10 : if (strcmp(pd->user, "testuser") == 0) {
189 5 : ret = test_auth(pd, "secret");
190 5 : } else if (strcmp(pd->user, "domtest") == 0) {
191 1 : pd->pam_status = PAM_AUTH_ERR;
192 1 : if (pd->requested_domains[0] != NULL
193 1 : && strcmp(pd->requested_domains[0], "mydomain") == 0
194 1 : && pd->requested_domains[1] == NULL) {
195 1 : pd->pam_status = PAM_SUCCESS;
196 : }
197 :
198 1 : ret = EOK;
199 4 : } else if (strcmp(pd->user, "retrytest") == 0) {
200 4 : ret = test_auth(pd, "retried_secret");
201 : }
202 :
203 10 : return ret;
204 : }
205 :
206 1 : static int mock_pam_chauthtok(struct pam_data *pd)
207 : {
208 1 : errno_t ret = PAM_SYSTEM_ERR;
209 :
210 1 : if (strcmp(pd->user, "testuser") == 0) {
211 1 : ret = test_auth(pd, "secret");
212 0 : } else if (strcmp(pd->user, "domtest") == 0) {
213 0 : pd->pam_status = PAM_AUTH_ERR;
214 0 : if (pd->requested_domains[0] != NULL
215 0 : && strcmp(pd->requested_domains[0], "mydomain") == 0
216 0 : && pd->requested_domains[1] == NULL) {
217 0 : pd->pam_status = PAM_SUCCESS;
218 : }
219 :
220 0 : ret = EOK;
221 0 : } else if (strcmp(pd->user, "retrytest") == 0) {
222 0 : ret = test_auth(pd, "retried_secret");
223 : }
224 :
225 1 : return ret;
226 : }
227 :
228 2 : static int mock_pam_acct(struct pam_data *pd)
229 : {
230 2 : if (strcmp(pd->user, "allowed_user") == 0) {
231 1 : pd->pam_status = PAM_SUCCESS;
232 1 : } else if (strcmp(pd->user, "denied_user") == 0) {
233 1 : pd->pam_status = PAM_PERM_DENIED;
234 : }
235 :
236 2 : return EOK;
237 : }
238 :
239 1 : static int mock_pam_set_cred(struct pam_data *pd)
240 : {
241 1 : const char *cred_msg = "CREDS=set";
242 :
243 1 : pd->pam_status = PAM_SUCCESS;
244 1 : return pam_add_response(pd, SSS_ALL_ENV_ITEM,
245 1 : strlen(cred_msg)+1,
246 : (const uint8_t *) cred_msg);
247 : }
248 :
249 1 : static int mock_pam_open_session(struct pam_data *pd)
250 : {
251 1 : const char *session_msg = "SESSION=open";
252 :
253 1 : pd->pam_status = PAM_SUCCESS;
254 1 : return pam_add_response(pd, SSS_ALL_ENV_ITEM,
255 1 : strlen(session_msg)+1,
256 : (const uint8_t *) session_msg);
257 : }
258 :
259 1 : static int mock_pam_close_session(struct pam_data *pd)
260 : {
261 1 : pd->pam_status = PAM_SUCCESS;
262 1 : return EOK;
263 : }
264 :
265 : /* Receives a packed response and returns a mock reply */
266 16 : int __wrap_sss_pam_make_request(enum sss_cli_command cmd,
267 : struct sss_cli_req_data *rd,
268 : uint8_t **repbuf, size_t *replen,
269 : int *errnop)
270 : {
271 : errno_t ret;
272 : TALLOC_CTX *test_ctx;
273 : struct cli_ctx *cctx;
274 : struct pam_data *pd;
275 :
276 16 : test_ctx = talloc_new(NULL);
277 16 : if (test_ctx == NULL) {
278 0 : return ENOMEM;
279 : }
280 :
281 : /* The PAM responder functions expect both cctx and pd to be talloc
282 : * contexts
283 : */
284 16 : cctx = mock_pam_cctx(test_ctx, cmd, 3, rd);
285 16 : pd = mock_pam_data(test_ctx, cmd);
286 16 : if (cctx == NULL || pd == NULL) {
287 0 : ret = ENOMEM;
288 0 : goto done;
289 : }
290 :
291 16 : ret = pam_forwarder_parse_data(cctx, pd);
292 16 : if (ret != EOK) {
293 0 : goto done;
294 : }
295 :
296 16 : pd->pam_status = PAM_SYSTEM_ERR;
297 :
298 16 : if (cmd == SSS_PAM_AUTHENTICATE) {
299 7 : ret = mock_pam_auth(pd);
300 9 : } else if (cmd == SSS_PAM_ACCT_MGMT) {
301 2 : ret = mock_pam_acct(pd);
302 7 : } else if (cmd == SSS_PAM_CHAUTHTOK_PRELIM) {
303 3 : ret = mock_pam_auth(pd);
304 4 : } else if (cmd == SSS_PAM_CHAUTHTOK) {
305 1 : ret = mock_pam_chauthtok(pd);
306 3 : } else if (cmd == SSS_PAM_SETCRED) {
307 1 : ret = mock_pam_set_cred(pd);
308 2 : } else if (cmd == SSS_PAM_OPEN_SESSION) {
309 1 : ret = mock_pam_open_session(pd);
310 1 : } else if (cmd == SSS_PAM_CLOSE_SESSION) {
311 1 : ret = mock_pam_close_session(pd);
312 : }
313 :
314 16 : if (ret != EOK) {
315 0 : goto done;
316 : }
317 :
318 16 : ret = pamsrv_reply_packet(cctx->creq, pd, cmd, &cctx->creq->out);
319 16 : if (ret != EOK) {
320 0 : goto done;
321 : }
322 :
323 16 : *repbuf = malloc(cctx->creq->out->memsize);
324 16 : memcpy(*repbuf, cctx->creq->out->buffer, cctx->creq->out->memsize);
325 16 : *replen = cctx->creq->out->memsize;
326 :
327 16 : ret = EOK;
328 : done:
329 16 : return ret;
330 : }
|