Line data Source code
1 : /*
2 : SSSD
3 :
4 : PAM Responder
5 :
6 : Copyright (C) Simo Sorce <ssorce@redhat.com> 2009
7 : Copyright (C) Sumit Bose <sbose@redhat.com> 2009
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "util/util.h"
24 : #include "providers/data_provider.h"
25 : #include "responder/pam/pamsrv.h"
26 : #include "responder/common/responder_packet.h"
27 :
28 : static int pam_parse_in_data(struct pam_data *pd,
29 : uint8_t *body, size_t blen);
30 : static int pam_parse_in_data_v2(struct pam_data *pd,
31 : uint8_t *body, size_t blen);
32 : static int pam_parse_in_data_v3(struct pam_data *pd,
33 : uint8_t *body, size_t blen);
34 :
35 47 : errno_t pam_forwarder_parse_data(struct cli_ctx *cctx, struct pam_data *pd)
36 : {
37 : uint8_t *body;
38 : size_t blen;
39 : errno_t ret;
40 : uint32_t terminator;
41 :
42 47 : sss_packet_get_body(cctx->creq->in, &body, &blen);
43 47 : if (blen >= sizeof(uint32_t)) {
44 47 : SAFEALIGN_COPY_UINT32(&terminator,
45 : body + blen - sizeof(uint32_t),
46 : NULL);
47 47 : if (terminator != SSS_END_OF_PAM_REQUEST) {
48 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Received data not terminated.\n");
49 0 : ret = EINVAL;
50 0 : goto done;
51 : }
52 : }
53 :
54 47 : switch (cctx->cli_protocol_version->version) {
55 : case 1:
56 0 : ret = pam_parse_in_data(pd, body, blen);
57 0 : break;
58 : case 2:
59 0 : ret = pam_parse_in_data_v2(pd, body, blen);
60 0 : break;
61 : case 3:
62 47 : ret = pam_parse_in_data_v3(pd, body, blen);
63 47 : break;
64 : default:
65 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Illegal protocol version [%d].\n",
66 : cctx->cli_protocol_version->version);
67 0 : ret = EINVAL;
68 : }
69 47 : if (ret != EOK) {
70 0 : goto done;
71 : }
72 :
73 47 : if (pd->logon_name != NULL) {
74 86 : ret = sss_parse_name_for_domains(pd, cctx->rctx->domains,
75 43 : cctx->rctx->default_domain,
76 43 : pd->logon_name,
77 : &pd->domain, &pd->user);
78 : } else {
79 : /* Only SSS_PAM_PREAUTH request may have a missing name, e.g. if the
80 : * name is determined with the help of a certificate */
81 4 : if (pd->cmd == SSS_PAM_PREAUTH
82 4 : && may_do_cert_auth(talloc_get_type(cctx->rctx->pvt_ctx,
83 : struct pam_ctx), pd)) {
84 3 : ret = EOK;
85 : } else {
86 1 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing logon name in PAM request.\n");
87 1 : ret = ERR_NO_CREDS;
88 1 : goto done;
89 : }
90 : }
91 :
92 46 : DEBUG_PAM_DATA(SSSDBG_CONF_SETTINGS, pd);
93 :
94 : done:
95 47 : return ret;
96 : }
97 :
98 : static int extract_authtok_v1(struct sss_auth_token *tok,
99 : uint8_t *body, size_t blen, size_t *c);
100 : static int extract_authtok_v2(struct sss_auth_token *tok,
101 : size_t data_size, uint8_t *body, size_t blen,
102 : size_t *c);
103 : static int extract_string(char **var, size_t size, uint8_t *body, size_t blen,
104 : size_t *c);
105 : static int extract_uint32_t(uint32_t *var, size_t size, uint8_t *body,
106 : size_t blen, size_t *c);
107 :
108 0 : static int pam_parse_in_data(struct pam_data *pd,
109 : uint8_t *body, size_t blen)
110 : {
111 : size_t start;
112 : size_t end;
113 : size_t last;
114 : int ret;
115 :
116 0 : last = blen - 1;
117 0 : end = 0;
118 :
119 : /* user name */
120 0 : for (start = end; end < last; end++) if (body[end] == '\0') break;
121 0 : if (body[end++] != '\0') return EINVAL;
122 0 : pd->logon_name = (char *) &body[start];
123 :
124 0 : for (start = end; end < last; end++) if (body[end] == '\0') break;
125 0 : if (body[end++] != '\0') return EINVAL;
126 0 : pd->service = (char *) &body[start];
127 :
128 0 : for (start = end; end < last; end++) if (body[end] == '\0') break;
129 0 : if (body[end++] != '\0') return EINVAL;
130 0 : pd->tty = (char *) &body[start];
131 :
132 0 : for (start = end; end < last; end++) if (body[end] == '\0') break;
133 0 : if (body[end++] != '\0') return EINVAL;
134 0 : pd->ruser = (char *) &body[start];
135 :
136 0 : for (start = end; end < last; end++) if (body[end] == '\0') break;
137 0 : if (body[end++] != '\0') return EINVAL;
138 0 : pd->rhost = (char *) &body[start];
139 :
140 0 : ret = extract_authtok_v1(pd->authtok, body, blen, &end);
141 0 : if (ret) {
142 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid auth token\n");
143 0 : return ret;
144 : }
145 0 : ret = extract_authtok_v1(pd->newauthtok, body, blen, &end);
146 0 : if (ret) {
147 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid new auth token\n");
148 0 : return ret;
149 : }
150 :
151 0 : DEBUG_PAM_DATA(SSSDBG_CONF_SETTINGS, pd);
152 :
153 0 : return EOK;
154 : }
155 :
156 47 : static int pam_parse_in_data_v2(struct pam_data *pd,
157 : uint8_t *body, size_t blen)
158 : {
159 : size_t c;
160 : uint32_t type;
161 : uint32_t size;
162 : int ret;
163 : uint32_t start;
164 : uint32_t terminator;
165 : char *requested_domains;
166 :
167 47 : if (blen < 4*sizeof(uint32_t)+2) {
168 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Received data is invalid.\n");
169 0 : return EINVAL;
170 : }
171 :
172 47 : SAFEALIGN_COPY_UINT32(&start, body, NULL);
173 47 : SAFEALIGN_COPY_UINT32(&terminator, body + blen - sizeof(uint32_t), NULL);
174 :
175 47 : if (start != SSS_START_OF_PAM_REQUEST
176 47 : || terminator != SSS_END_OF_PAM_REQUEST) {
177 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Received data is invalid.\n");
178 0 : return EINVAL;
179 : }
180 :
181 47 : c = sizeof(uint32_t);
182 : do {
183 303 : SAFEALIGN_COPY_UINT32_CHECK(&type, &body[c], blen, &c);
184 :
185 303 : if (type == SSS_END_OF_PAM_REQUEST) {
186 47 : if (c != blen) return EINVAL;
187 : } else {
188 256 : SAFEALIGN_COPY_UINT32_CHECK(&size, &body[c], blen, &c);
189 : /* the uint32_t end maker SSS_END_OF_PAM_REQUEST does not count to
190 : * the remaining buffer */
191 256 : if (size > (blen - c - sizeof(uint32_t))) {
192 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid data size.\n");
193 0 : return EINVAL;
194 : }
195 :
196 256 : switch(type) {
197 : case SSS_PAM_ITEM_USER:
198 43 : ret = extract_string(&pd->logon_name, size, body, blen, &c);
199 43 : if (ret != EOK) return ret;
200 43 : break;
201 : case SSS_PAM_ITEM_SERVICE:
202 47 : ret = extract_string(&pd->service, size, body, blen, &c);
203 47 : if (ret != EOK) return ret;
204 47 : break;
205 : case SSS_PAM_ITEM_TTY:
206 31 : ret = extract_string(&pd->tty, size, body, blen, &c);
207 31 : if (ret != EOK) return ret;
208 31 : break;
209 : case SSS_PAM_ITEM_RUSER:
210 31 : ret = extract_string(&pd->ruser, size, body, blen, &c);
211 31 : if (ret != EOK) return ret;
212 31 : break;
213 : case SSS_PAM_ITEM_RHOST:
214 31 : ret = extract_string(&pd->rhost, size, body, blen, &c);
215 31 : if (ret != EOK) return ret;
216 31 : break;
217 : case SSS_PAM_ITEM_REQUESTED_DOMAINS:
218 1 : ret = extract_string(&requested_domains, size, body, blen,
219 : &c);
220 1 : if (ret != EOK) return ret;
221 :
222 1 : ret = split_on_separator(pd, requested_domains, ',', true,
223 : true, &pd->requested_domains,
224 : NULL);
225 1 : if (ret != EOK) {
226 0 : DEBUG(SSSDBG_CRIT_FAILURE,
227 : "Failed to parse requested_domains list!\n");
228 0 : return ret;
229 : }
230 1 : break;
231 : case SSS_PAM_ITEM_CLI_PID:
232 47 : ret = extract_uint32_t(&pd->cli_pid, size,
233 : body, blen, &c);
234 47 : if (ret != EOK) return ret;
235 47 : break;
236 : case SSS_PAM_ITEM_AUTHTOK:
237 24 : ret = extract_authtok_v2(pd->authtok,
238 : size, body, blen, &c);
239 24 : if (ret != EOK) return ret;
240 24 : break;
241 : case SSS_PAM_ITEM_NEWAUTHTOK:
242 1 : ret = extract_authtok_v2(pd->newauthtok,
243 : size, body, blen, &c);
244 1 : if (ret != EOK) return ret;
245 1 : break;
246 : default:
247 0 : DEBUG(SSSDBG_CRIT_FAILURE,
248 : "Ignoring unknown data type [%d].\n", type);
249 0 : c += size;
250 : }
251 : }
252 :
253 303 : } while(c < blen);
254 :
255 47 : return EOK;
256 :
257 : }
258 :
259 47 : static int pam_parse_in_data_v3(struct pam_data *pd,
260 : uint8_t *body, size_t blen)
261 : {
262 : int ret;
263 :
264 47 : ret = pam_parse_in_data_v2(pd, body, blen);
265 47 : if (ret != EOK) {
266 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_parse_in_data_v2 failed.\n");
267 0 : return ret;
268 : }
269 :
270 47 : if (pd->cli_pid == 0) {
271 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing client PID.\n");
272 0 : return EINVAL;
273 : }
274 :
275 47 : return EOK;
276 : }
277 :
278 184 : static int extract_string(char **var, size_t size, uint8_t *body, size_t blen,
279 : size_t *c)
280 : {
281 : uint8_t *str;
282 :
283 184 : if (*c+size > blen || SIZE_T_OVERFLOW(*c, size)) return EINVAL;
284 :
285 184 : str = body+(*c);
286 :
287 184 : if (str[size-1]!='\0') return EINVAL;
288 :
289 : /* If the string isn't valid UTF-8, fail */
290 184 : if (!sss_utf8_check(str, size-1)) {
291 0 : return EINVAL;
292 : }
293 :
294 184 : *c += size;
295 :
296 184 : *var = (char *) str;
297 :
298 184 : return EOK;
299 : }
300 :
301 47 : static int extract_uint32_t(uint32_t *var, size_t size, uint8_t *body,
302 : size_t blen, size_t *c)
303 : {
304 :
305 47 : if (size != sizeof(uint32_t)
306 47 : || *c+size > blen
307 47 : || SIZE_T_OVERFLOW(*c, size)) {
308 0 : return EINVAL;
309 : }
310 :
311 47 : SAFEALIGN_COPY_UINT32_CHECK(var, &body[*c], blen, c);
312 :
313 47 : return EOK;
314 : }
315 :
316 0 : static int extract_authtok_v1(struct sss_auth_token *tok,
317 : uint8_t *body, size_t blen, size_t *c)
318 : {
319 : uint32_t auth_token_type;
320 : uint32_t auth_token_length;
321 : uint8_t *auth_token_data;
322 0 : int ret = EOK;
323 :
324 0 : SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c);
325 0 : SAFEALIGN_COPY_UINT32_CHECK(&auth_token_length, &body[*c], blen, c);
326 0 : auth_token_data = body+(*c);
327 :
328 0 : switch (auth_token_type) {
329 : case SSS_AUTHTOK_TYPE_EMPTY:
330 0 : sss_authtok_set_empty(tok);
331 0 : break;
332 : case SSS_AUTHTOK_TYPE_PASSWORD:
333 0 : ret = sss_authtok_set_password(tok, (const char *)auth_token_data,
334 : auth_token_length);
335 0 : break;
336 : default:
337 0 : return EINVAL;
338 : }
339 :
340 0 : *c += auth_token_length;
341 :
342 0 : return ret;
343 : }
344 :
345 25 : static int extract_authtok_v2(struct sss_auth_token *tok,
346 : size_t data_size, uint8_t *body, size_t blen,
347 : size_t *c)
348 : {
349 : uint32_t auth_token_type;
350 : uint32_t auth_token_length;
351 : uint8_t *auth_token_data;
352 25 : int ret = EOK;
353 :
354 50 : if (data_size < sizeof(uint32_t) || *c+data_size > blen ||
355 25 : SIZE_T_OVERFLOW(*c, data_size)) return EINVAL;
356 :
357 25 : SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c);
358 25 : auth_token_length = data_size - sizeof(uint32_t);
359 25 : auth_token_data = body+(*c);
360 :
361 25 : switch (auth_token_type) {
362 : case SSS_AUTHTOK_TYPE_EMPTY:
363 0 : sss_authtok_set_empty(tok);
364 0 : break;
365 : case SSS_AUTHTOK_TYPE_PASSWORD:
366 20 : if (auth_token_length == 0) {
367 0 : sss_authtok_set_empty(tok);
368 : } else {
369 20 : ret = sss_authtok_set_password(tok, (const char *)auth_token_data,
370 : auth_token_length);
371 : }
372 20 : break;
373 : case SSS_AUTHTOK_TYPE_2FA:
374 4 : ret = sss_authtok_set(tok, SSS_AUTHTOK_TYPE_2FA,
375 : auth_token_data, auth_token_length);
376 4 : break;
377 : case SSS_AUTHTOK_TYPE_SC_PIN:
378 1 : ret = sss_authtok_set_sc_pin(tok, (const char *) auth_token_data,
379 : auth_token_length);
380 1 : break;
381 : case SSS_AUTHTOK_TYPE_SC_KEYPAD:
382 0 : sss_authtok_set_sc_keypad(tok);
383 0 : break;
384 : default:
385 0 : return EINVAL;
386 : }
387 :
388 25 : *c += auth_token_length;
389 :
390 25 : return ret;
391 : }
392 :
|