1 /*
2  * Copyright (C) 2013, 2014, 2015 Nikos Mavrogiannopoulos
3  * Copyright (C) 2015 Red Hat, Inc.
4  *
5  * This file is part of ocserv.
6  *
7  * ocserv is free software: you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * ocserv is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <config.h>
22 
23 #include <gnutls/gnutls.h>
24 #include <gnutls/crypto.h>
25 #include <gnutls/x509.h>
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <limits.h>
36 #include <ipc.pb-c.h>
37 #include <base64-helper.h>
38 
39 #include <vpn.h>
40 #include "html.h"
41 #include <worker.h>
42 #include <common.h>
43 #include <tlslib.h>
44 
45 #include <http_parser.h>
46 
47 #define VERSION_MSG "<version who=\"sg\">0.1(1)</version>\n"
48 
49 static const char oc_success_msg_head[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
50 			"<config-auth client=\"vpn\" type=\"complete\">\n"
51 			VERSION_MSG
52                         "<auth id=\"success\">\n"
53                         "<title>SSL VPN Service</title>";
54 
55 #define OC_SUCCESS_MSG_FOOT "</auth></config-auth>\n"
56 #define OC_SUCCESS_MSG_FOOT_PROFILE \
57 			"</auth>\n" \
58 			"<config client=\"vpn\" type=\"private\">" \
59 				"<vpn-profile-manifest>" \
60 				"<vpn rev=\"1.0\">" \
61 				"<file type=\"profile\" service-type=\"user\">" \
62 				"<uri>/profiles/%s</uri>" \
63 				"<hash type=\"sha1\">%s</hash>" \
64 				"</file>" \
65 				"</vpn>" \
66 				"</vpn-profile-manifest>\n" \
67 			"</config>" \
68 			"</config-auth>"
69 
70 static const char ocv3_success_msg_head[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
71                         "<auth id=\"success\">\n"
72                         "<title>SSL VPN Service</title>";
73 
74 static const char ocv3_success_msg_foot[] = "</auth>\n";
75 
76 #define OC_LOGIN_START \
77     "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" \
78     "<config-auth client=\"vpn\" type=\"auth-request\">\n" \
79     VERSION_MSG \
80     "<auth id=\"main\">\n"
81 
82 #define OC_LOGIN_FORM_START \
83     "<message>%s</message>\n" \
84     "<form method=\"post\" action=\"/auth\">\n"
85 
86 #define OC_LOGIN_END \
87     "</form></auth>\n" "</config-auth>"
88 
89 #define OC_LOGIN_FORM_INPUT_USER \
90     "<input type=\"text\" name=\"username\" label=\"Username:\" />\n"
91 
92 #define DEFAULT_PASSWD_LABEL "Password:"
93 #define OC_LOGIN_FORM_INPUT_PASSWORD \
94     "<input type=\"password\" name=\"password\" label=\""DEFAULT_PASSWD_LABEL"\" />\n"
95 #define OC_LOGIN_FORM_INPUT_PASSWORD_CTR \
96     "<input type=\"password\" name=\"secondary_password\" label=\"Password%d:\" />\n"
97 
98 #define _OCV3_LOGIN_MSG_START(x) \
99     "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" \
100     "<auth id=\""x"\">\n"
101 
102 #define OCV3_LOGIN_START _OCV3_LOGIN_MSG_START("main")
103 #define OCV3_PASSWD_START _OCV3_LOGIN_MSG_START("passwd")
104 
105 #define OCV3_LOGIN_END "</form></auth>\n"
106 
107 #ifdef SUPPORT_OIDC_AUTH
108 #define HTTP_AUTH_OIDC_PREFIX "Bearer"
109 #endif
110 
111 
112 static int get_cert_info(worker_st * ws);
113 static int basic_auth_handler(worker_st * ws, unsigned http_ver, const char *msg);
114 
115 #ifdef SUPPORT_OIDC_AUTH
116 static int oidc_auth_handler(worker_st * ws, unsigned http_ver);
117 #endif
118 
ws_switch_auth_to(struct worker_st * ws,unsigned auth)119 int ws_switch_auth_to(struct worker_st *ws, unsigned auth)
120 {
121 	unsigned i;
122 
123 	if (ws->selected_auth && ws->selected_auth->enabled != 0 &&
124 	    ws->selected_auth->type & auth)
125 		return 1;
126 
127 	for (i=0;i<WSPCONFIG(ws)->auth_methods;i++) {
128 		if (WSPCONFIG(ws)->auth[i].enabled && (WSPCONFIG(ws)->auth[i].type & auth) != 0) {
129 			ws->selected_auth = &WSPCONFIG(ws)->auth[i];
130 			return 1;
131 		}
132 	}
133 	return 0;
134 }
135 
136 /* disables the selected auth method and switches to the next
137  * available authentication method, and returns
138  * non-zero on success */
ws_switch_auth_to_next(struct worker_st * ws)139 int ws_switch_auth_to_next(struct worker_st *ws)
140 {
141 	unsigned i;
142 
143 	if (!ws->selected_auth) {
144 		return 0;
145 	}
146 
147 	ws->selected_auth->enabled = 0;
148 
149 	for (i=0;i<WSPCONFIG(ws)->auth_methods;i++) {
150 		if (&WSPCONFIG(ws)->auth[i] != ws->selected_auth &&
151 		    WSPCONFIG(ws)->auth[i].enabled != 0) {
152 
153 			ws->selected_auth = &WSPCONFIG(ws)->auth[i];
154 			return 1;
155 		}
156 	}
157 	return 0;
158 }
159 
append_group_idx(worker_st * ws,str_st * str,unsigned i)160 static int append_group_idx(worker_st * ws, str_st *str, unsigned i)
161 {
162 	char temp[128];
163 	const char *name;
164 	const char *value;
165 
166 	value = WSCONFIG(ws)->group_list[i];
167 	if (WSCONFIG(ws)->friendly_group_list != NULL && WSCONFIG(ws)->friendly_group_list[i] != NULL)
168 		name = WSCONFIG(ws)->friendly_group_list[i];
169 	else
170 		name = WSCONFIG(ws)->group_list[i];
171 
172 	snprintf(temp, sizeof(temp), "<option value=\"%s\">%s</option>\n", value, name);
173 	if (str_append_str(str, temp) < 0)
174 		return -1;
175 
176 	return 0;
177 }
178 
append_group_str(worker_st * ws,str_st * str,const char * group)179 static int append_group_str(worker_st * ws, str_st *str, const char *group)
180 {
181 	char temp[256];
182 	const char *name;
183 	const char *value;
184 	unsigned i;
185 
186 	value = name = group;
187 
188 	if (WSCONFIG(ws)->friendly_group_list) {
189 		for (i=0;i<WSCONFIG(ws)->group_list_size;i++) {
190 			if (strcmp(WSCONFIG(ws)->group_list[i], group) == 0) {
191 				if (WSCONFIG(ws)->friendly_group_list[i] != NULL)
192 					name = WSCONFIG(ws)->friendly_group_list[i];
193 				break;
194 			}
195 		}
196 	}
197 
198 	snprintf(temp, sizeof(temp), "<option value=\"%s\">%s</option>\n", value, name);
199 	if (str_append_str(str, temp) < 0)
200 		return -1;
201 
202 	return 0;
203 }
204 
get_auth_handler2(worker_st * ws,unsigned http_ver,const char * pmsg,unsigned pcounter)205 int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg, unsigned pcounter)
206 {
207 	int ret;
208 	char context[BASE64_ENCODE_RAW_LENGTH(SID_SIZE) + 1];
209 	unsigned int i, j;
210 	str_st str;
211 	const char *login_start;
212 	const char *login_end;
213 
214 	if (ws->req.user_agent_type == AGENT_OPENCONNECT_V3) {
215 		/* certain v2.x modified clients require a different auth_id
216 		 * when password is being requested, rather than username */
217 		if (ws->auth_state == S_AUTH_REQ)
218 			login_start = OCV3_PASSWD_START;
219 		else
220 			login_start = OCV3_LOGIN_START;
221 		login_end = OCV3_LOGIN_END;
222 	} else {
223 		login_start = OC_LOGIN_START;
224 		login_end = OC_LOGIN_END;
225 	}
226 
227 	if ((ws->selected_auth->type & AUTH_TYPE_GSSAPI) && ws->auth_state < S_AUTH_COOKIE) {
228 		if (ws->req.authorization == NULL || ws->req.authorization_size == 0)
229 			return basic_auth_handler(ws, http_ver, NULL);
230 		else
231 			return post_auth_handler(ws, http_ver);
232 	}
233 
234 	str_init(&str, ws);
235 
236 	oclog(ws, LOG_HTTP_DEBUG, "HTTP sending: 200 OK");
237 	cstp_cork(ws);
238 	ret = cstp_printf(ws, "HTTP/1.%u 200 OK\r\n", http_ver);
239 	if (ret < 0)
240 		return -1;
241 
242 
243 	if (ws->sid_set != 0) {
244 		char safe_id[SAFE_ID_SIZE];
245 
246 		oc_base64_encode((char *)ws->sid, sizeof(ws->sid), (char *)context,
247 			      sizeof(context));
248 
249 		ret =
250 		    cstp_printf(ws,
251 			       "Set-Cookie: webvpncontext=%s; Max-Age=%u; Secure; HttpOnly\r\n",
252 			       context, (unsigned)WSCONFIG(ws)->cookie_timeout);
253 		if (ret < 0)
254 			return -1;
255 
256 		oclog(ws, LOG_SENSITIVE, "sent session id: %s", calc_safe_id(ws->sid, sizeof(ws->sid), safe_id, sizeof(safe_id)));
257 	} else {
258 		ret =
259 		    cstp_puts(ws,
260 			     "Set-Cookie: webvpncontext=; expires=Thu, 01 Jan 1970 22:00:00 GMT; path=/; Secure; HttpOnly\r\n");
261 		if (ret < 0)
262 			return -1;
263 	}
264 
265 	ret = cstp_puts(ws, "Content-Type: text/xml\r\n");
266 	if (ret < 0) {
267 		ret = -1;
268 		goto cleanup;
269 	}
270 
271 	if (ws->auth_state == S_AUTH_REQ) {
272 		/* Password Form */
273 		if (pmsg == NULL || strncasecmp(pmsg, DEFAULT_PASSWD_LABEL, sizeof(DEFAULT_PASSWD_LABEL)-1) == 0)
274 			pmsg = "Please enter your password.";
275 
276 		ret = str_append_str(&str, login_start);
277 		if (ret < 0) {
278 			ret = -1;
279 			goto cleanup;
280 		}
281 
282 		ret = str_append_printf(&str, OC_LOGIN_FORM_START, pmsg);
283 		if (ret < 0) {
284 			ret = -1;
285 			goto cleanup;
286 		}
287 
288 		if (pcounter > 0)
289 			ret = str_append_printf(&str, OC_LOGIN_FORM_INPUT_PASSWORD_CTR, pcounter);
290 		else
291 			ret = str_append_str(&str, OC_LOGIN_FORM_INPUT_PASSWORD);
292 		if (ret < 0) {
293 			ret = -1;
294 			goto cleanup;
295 		}
296 
297 		ret = str_append_str(&str, login_end);
298 		if (ret < 0) {
299 			ret = -1;
300 			goto cleanup;
301 		}
302 
303 	} else {
304 		/* Username / Groups Form */
305 		if (pmsg == NULL)
306 			pmsg = "Please enter your username.";
307 
308 		ret = str_append_str(&str, login_start);
309 		if (ret < 0) {
310 			ret = -1;
311 			goto cleanup;
312 		}
313 
314 		if (WSCONFIG(ws)->pre_login_banner) {
315 			ret = str_append_printf(&str, "<banner>%s</banner>", WSCONFIG(ws)->pre_login_banner);
316 			if (ret < 0) {
317 				ret = -1;
318 				goto cleanup;
319 			}
320 		}
321 
322 		ret = str_append_printf(&str, OC_LOGIN_FORM_START, pmsg);
323 		if (ret < 0) {
324 			ret = -1;
325 			goto cleanup;
326 		}
327 
328 		if (ws->selected_auth->type & AUTH_TYPE_USERNAME_PASS) {
329 			ret = str_append_str(&str, OC_LOGIN_FORM_INPUT_USER);
330 			if (ret < 0) {
331 				ret = -1;
332 				goto cleanup;
333 			}
334 		}
335 
336 		if ((ws->selected_auth->type & AUTH_TYPE_CERTIFICATE) && ws->cert_auth_ok != 0) {
337 			ret = get_cert_info(ws);
338 			if (ret < 0) {
339 				ret = -1;
340 				oclog(ws, LOG_WARNING, "cannot obtain certificate information");
341 				goto cleanup;
342 			}
343 		}
344 
345 		/* send groups */
346 		if (WSCONFIG(ws)->group_list_size > 0 || ws->cert_groups_size > 0) {
347 			ret = str_append_str(&str, "<select name=\"group_list\" label=\"Group:\">\n");
348 			if (ret < 0) {
349 				ret = -1;
350 				goto cleanup;
351 			}
352 
353 			/* Several anyconnect clients (and openconnect) submit the group name
354 			 * separately in that form. In that case they expect that we re-order
355 			 * the list and we place the group they selected first. WTF! No respect
356 			 * to server time.
357 			 */
358 			if (ws->groupname[0] != 0) {
359 				ret = append_group_str(ws, &str, ws->groupname);
360 				if (ret < 0) {
361 					ret = -1;
362 					goto cleanup;
363 				}
364 			}
365 
366 			if (WSCONFIG(ws)->default_select_group) {
367 				ret = str_append_printf(&str, "<option>%s</option>\n", WSCONFIG(ws)->default_select_group);
368 				if (ret < 0) {
369 					ret = -1;
370 					goto cleanup;
371 				}
372 			}
373 
374 			/* append any groups available in the certificate */
375 			if ((ws->selected_auth->type & AUTH_TYPE_CERTIFICATE) && ws->cert_auth_ok != 0) {
376 				unsigned dup;
377 
378 				for (i=0;i<ws->cert_groups_size;i++) {
379 					dup = 0;
380 					for (j=0;j<WSCONFIG(ws)->group_list_size;j++) {
381 						if (strcmp(ws->cert_groups[i], WSCONFIG(ws)->group_list[j]) == 0) {
382 							dup = 1;
383 							break;
384 						}
385 					}
386 
387 					if (dup == 0 && ws->groupname[0] != 0 && strcmp(ws->groupname, ws->cert_groups[i]) == 0)
388 						dup = 1;
389 
390 					if (dup != 0)
391 						continue;
392 
393 					ret = str_append_printf(&str, "<option>%s</option>\n", ws->cert_groups[i]);
394 					if (ret < 0) {
395 						ret = -1;
396 						goto cleanup;
397 					}
398 				}
399 			}
400 
401 
402 			for (i=0;i<WSCONFIG(ws)->group_list_size;i++) {
403 				if (ws->groupname[0] != 0 && strcmp(ws->groupname, WSCONFIG(ws)->group_list[i]) == 0)
404 					continue;
405 
406 				ret = append_group_idx(ws, &str, i);
407 				if (ret < 0) {
408 					ret = -1;
409 					goto cleanup;
410 				}
411 			}
412 			ret = str_append_str(&str, "</select>\n");
413 			if (ret < 0) {
414 				ret = -1;
415 				goto cleanup;
416 			}
417 		}
418 
419 		ret = str_append_str(&str, login_end);
420 		if (ret < 0) {
421 			ret = -1;
422 			goto cleanup;
423 		}
424 
425 	}
426 
427 	ret =
428 	    cstp_printf(ws, "Content-Length: %u\r\n",
429 		       (unsigned int)str.length);
430 	if (ret < 0) {
431 		ret = -1;
432 		goto cleanup;
433 	}
434 
435 	ret = cstp_puts(ws, "X-Transcend-Version: 1\r\n");
436 	if (ret < 0) {
437 		ret = -1;
438 		goto cleanup;
439 	}
440 
441 	ret = add_owasp_headers(ws);
442 	if (ret < 0) {
443 		ret = -1;
444 		goto cleanup;
445 	}
446 
447 	ret = cstp_puts(ws, "\r\n");
448 	if (ret < 0) {
449 		ret = -1;
450 		goto cleanup;
451 	}
452 
453 	ret = cstp_send(ws, str.data, str.length);
454 	if (ret < 0) {
455 		ret = -1;
456 		goto cleanup;
457 	}
458 
459 
460 	ret = cstp_uncork(ws);
461 	if (ret < 0) {
462 		ret = -1;
463 		goto cleanup;
464 	}
465 
466 	ret = 0;
467 
468  cleanup:
469  	str_clear(&str);
470 	return ret;
471 }
472 
get_auth_handler(worker_st * ws,unsigned http_ver)473 int get_auth_handler(worker_st * ws, unsigned http_ver)
474 {
475 	return get_auth_handler2(ws, http_ver, NULL, 0);
476 }
477 
get_cert_names(worker_st * ws,const gnutls_datum_t * raw)478 int get_cert_names(worker_st * ws, const gnutls_datum_t * raw)
479 {
480 	gnutls_x509_crt_t crt;
481 	int ret;
482 	unsigned i;
483 	size_t size;
484 	char cert_username[MAX_USERNAME_SIZE];
485 
486 	if (ws->cert_username[0] != 0 || ws->cert_groups_size > 0)
487 		return 0; /* already read, nothing to do */
488 
489 	ret = gnutls_x509_crt_init(&crt);
490 	if (ret < 0) {
491 		oclog(ws, LOG_ERR, "certificate init error: %s",
492 		      gnutls_strerror(ret));
493 		goto fail;
494 	}
495 
496 	ret = gnutls_x509_crt_import(crt, raw, GNUTLS_X509_FMT_DER);
497 	if (ret < 0) {
498 		oclog(ws, LOG_ERR, "certificate import error: %s",
499 		      gnutls_strerror(ret));
500 		goto fail;
501 	}
502 
503 	if (strcmp(WSCONFIG(ws)->cert_user_oid, "SAN(rfc822name)") == 0) {	/* check for RFC822Name */
504 		for (i = 0;; i++) {
505 			size = sizeof(ws->cert_username);
506 			ret =
507 			    gnutls_x509_crt_get_subject_alt_name(crt, i,
508 								 cert_username,
509 								 &size, NULL);
510 			if (ret < 0) {
511 				if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
512 					ret = 1;
513 				break;
514 			}
515 
516 			if (ret == GNUTLS_SAN_RFC822NAME) {
517 				strlcpy(ws->cert_username, cert_username, sizeof(ws->cert_username));
518 				oclog(ws, LOG_INFO,
519 				      "RFC822NAME (%s) retrieved",
520 				      cert_username);
521 				break;
522 			}
523 		}
524 
525 	} else if (WSCONFIG(ws)->cert_user_oid) { /* otherwise we check at the DN */
526 		size = sizeof(ws->cert_username);
527 		ret =
528 		    gnutls_x509_crt_get_dn_by_oid(crt,
529 					  WSCONFIG(ws)->cert_user_oid, 0,
530 					  0, cert_username, &size);
531 		if (ret >= 0)
532 			strlcpy(ws->cert_username, cert_username, sizeof(ws->cert_username));
533 
534 	} else {
535 		size = sizeof(ws->cert_username);
536 		ret = gnutls_x509_crt_get_dn(crt, cert_username, &size);
537 		if (ret >= 0)
538 			strlcpy(ws->cert_username, cert_username, sizeof(ws->cert_username));
539 	}
540 
541 	if (ret < 0) {
542 		if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
543 			oclog(ws, LOG_ERR, "certificate's username exceed the maximum buffer size (%u)",
544 			      (unsigned)sizeof(ws->cert_username));
545 		else if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
546 			oclog(ws, LOG_ERR, "the certificate's DN does not contain OID %s; cannot determine username",
547 			      WSCONFIG(ws)->cert_user_oid);
548 		} else {
549 			oclog(ws, LOG_ERR, "cannot obtain user name from certificate DN(%s): %s",
550 			      WSCONFIG(ws)->cert_user_oid, gnutls_strerror(ret));
551 		}
552 		goto fail;
553 	}
554 
555 	if (WSCONFIG(ws)->cert_group_oid) {
556 		i = 0;
557 		do {
558 			ws->cert_groups = talloc_realloc(ws, ws->cert_groups, char*,  i+1);
559 			if (ws->cert_groups == NULL) {
560 				oclog(ws, LOG_ERR, "cannot allocate memory for cert groups");
561 				ret = -1;
562 				goto fail;
563 			}
564 
565 			size = 0;
566 			ret =
567 			    gnutls_x509_crt_get_dn_by_oid(crt,
568 						  WSCONFIG(ws)->cert_group_oid, i,
569 						  0, NULL, &size);
570 			if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
571 				break;
572 
573 			if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER) {
574 				if (ret == 0)
575 					ret = GNUTLS_E_INTERNAL_ERROR;
576 				oclog(ws, LOG_ERR,
577 				      "cannot obtain group from certificate DN(%s): %s",
578 				      WSCONFIG(ws)->cert_group_oid, gnutls_strerror(ret));
579 				goto fail;
580 			}
581 
582 			ws->cert_groups[i] = talloc_size(ws->cert_groups, size);
583 			if (ws->cert_groups[i] == NULL) {
584 				oclog(ws, LOG_ERR, "cannot allocate memory for cert group");
585 				ret = -1;
586 				goto fail;
587 			}
588 
589 			ret =
590 			    gnutls_x509_crt_get_dn_by_oid(crt,
591 						  WSCONFIG(ws)->cert_group_oid, i,
592 						  0, ws->cert_groups[i], &size);
593 			if (ret < 0) {
594 				oclog(ws, LOG_ERR,
595 				      "cannot obtain group from certificate DN: %s",
596 				      gnutls_strerror(ret));
597 				goto fail;
598 			}
599 			i++;
600 		} while (1);
601 
602 		ws->cert_groups_size = i;
603 	}
604 
605 	ret = 0;
606 
607  fail:
608 	gnutls_x509_crt_deinit(crt);
609 	return ret;
610 
611 }
612 
613 static
check_if_default_route(char ** routes,unsigned routes_size)614 unsigned check_if_default_route(char **routes, unsigned routes_size)
615 {
616 	unsigned i;
617 
618 	for (i=0;i<routes_size;i++) {
619 		if (strcmp(routes[i], "default") == 0 ||
620 		    strcmp(routes[i], "0.0.0.0/0") == 0)
621 		    return 1;
622 	}
623 
624 	return 0;
625 }
626 
627 /* auth reply from main process */
recv_cookie_auth_reply(worker_st * ws)628 static int recv_cookie_auth_reply(worker_st * ws)
629 {
630 	int ret;
631 	int socketfd = -1;
632 	AuthCookieReplyMsg *msg = NULL;
633 	PROTOBUF_ALLOCATOR(pa, ws);
634 
635 	ret = recv_socket_msg(ws, ws->cmd_fd, AUTH_COOKIE_REP, &socketfd,
636 			      (void *)&msg,
637 			      (unpack_func) auth_cookie_reply_msg__unpack,
638 			      WSCONFIG(ws)->auth_timeout);
639 	if (ret < 0) {
640 		oclog(ws, LOG_ERR, "error receiving auth reply message");
641 		return ret;
642 	}
643 
644 	oclog(ws, LOG_DEBUG, "received auth reply message (value: %u)",
645 	      (unsigned)msg->reply);
646 
647 	switch (msg->reply) {
648 	case AUTH__REP__OK:
649 		if (socketfd != -1) {
650 			ws->tun_fd = socketfd;
651 			if (tun_claim(ws->tun_fd) != 0) {
652 				ret = ERR_AUTH_FAIL;
653 				goto cleanup;
654 			}
655 			if (msg->vname == NULL || msg->config == NULL || msg->user_name == NULL || msg->sid.len != sizeof(ws->sid)) {
656 				ret = ERR_AUTH_FAIL;
657 				goto cleanup;
658 			}
659 
660 			/* update our sid */
661 			memcpy(ws->sid, msg->sid.data, sizeof(ws->sid));
662 			ws->sid_set = 1;
663 
664 			strlcpy(ws->vinfo.name, msg->vname, sizeof(ws->vinfo.name));
665 			strlcpy(ws->username, msg->user_name, sizeof(ws->username));
666 
667 			if (msg->group_name != NULL) {
668 				strlcpy(ws->groupname, msg->group_name, sizeof(ws->groupname));
669 			} else {
670 				ws->groupname[0] = 0;
671 			}
672 
673 			memcpy(ws->session_id, msg->session_id.data,
674 			       msg->session_id.len);
675 
676 			ws->user_config = msg->config;
677 
678 			if (msg->ipv4 != NULL) {
679 				talloc_free(ws->vinfo.ipv4);
680 				if (strcmp(msg->ipv4, "0.0.0.0") == 0)
681 					ws->vinfo.ipv4 = NULL;
682 				else
683 					ws->vinfo.ipv4 =
684 					    talloc_strdup(ws, msg->ipv4);
685 			}
686 
687 			if (msg->ipv6 != NULL) {
688 				talloc_free(ws->vinfo.ipv6);
689 				if (strcmp(msg->ipv6, "::") == 0)
690 					ws->vinfo.ipv6 = NULL;
691 				else
692 					ws->vinfo.ipv6 =
693 					    talloc_strdup(ws, msg->ipv6);
694 			}
695 
696 			if (msg->ipv4_local != NULL) {
697 				talloc_free(ws->vinfo.ipv4_local);
698 				if (strcmp(msg->ipv4_local, "0.0.0.0") == 0)
699 					ws->vinfo.ipv4_local = NULL;
700 				else
701 					ws->vinfo.ipv4_local =
702 					    talloc_strdup(ws, msg->ipv4_local);
703 			}
704 
705 			if (msg->ipv6_local != NULL) {
706 				talloc_free(ws->vinfo.ipv6_local);
707 				if (strcmp(msg->ipv6_local, "::") == 0)
708 					ws->vinfo.ipv6_local = NULL;
709 				else
710 					ws->vinfo.ipv6_local =
711 					    talloc_strdup(ws, msg->ipv6_local);
712 			}
713 
714 			if (msg->config->no_udp != 0)
715 				WSPCONFIG(ws)->udp_port = 0;
716 
717 			/* routes */
718 			if (check_if_default_route(msg->config->routes, msg->config->n_routes))
719 				ws->default_route = 1;
720 		} else {
721 			oclog(ws, LOG_ERR, "error in received message");
722 			ret = ERR_AUTH_FAIL;
723 			goto cleanup;
724 		}
725 		break;
726 	case AUTH__REP__FAILED:
727 	default:
728 		if (msg->reply != AUTH__REP__FAILED)
729 			oclog(ws, LOG_ERR, "unexpected auth reply %u",
730 			      (unsigned)msg->reply);
731 		ret = ERR_AUTH_FAIL;
732 		goto cleanup;
733 	}
734 
735 	ret = 0;
736  cleanup:
737 	if (ret < 0) {
738 		/* we only release on error, as the user configuration
739 		 * remains. */
740 		auth_cookie_reply_msg__free_unpacked(msg, &pa);
741 		ws->user_config = NULL;
742 	}
743 	return ret;
744 }
745 
746 /* returns the fd */
connect_to_secmod(worker_st * ws)747 int connect_to_secmod(worker_st * ws)
748 {
749 	int sd, ret, e;
750 
751 	sd = socket(AF_UNIX, SOCK_STREAM, 0);
752 	if (sd == -1) {
753 		e = errno;
754 		oclog(ws, LOG_ERR, "error opening unix socket (for sec-mod) %s",
755 		      strerror(e));
756 		return -1;
757 	}
758 
759 	ret =
760 	    connect(sd, (struct sockaddr *)&ws->secmod_addr,
761 		    ws->secmod_addr_len);
762 	if (ret < 0) {
763 		e = errno;
764 		close(sd);
765 		oclog(ws, LOG_ERR,
766 		      "error connecting to sec-mod socket '%s': %s",
767 		      ws->secmod_addr.sun_path, strerror(e));
768 		return -1;
769 	}
770 	return sd;
771 }
772 
recv_auth_reply(worker_st * ws,int sd,char ** txt,unsigned * pcounter)773 static int recv_auth_reply(worker_st * ws, int sd, char **txt, unsigned *pcounter)
774 {
775 	int ret;
776 	SecAuthReplyMsg *msg = NULL;
777 	PROTOBUF_ALLOCATOR(pa, ws);
778 
779 	/* We don't use the default socket timeout here, but rather the
780 	 * longer WSCONFIG(ws)->auth_timeout to allow for authentication
781 	 * methods which require the user input prior to returning a reply */
782 	ret = recv_msg(ws, sd, CMD_SEC_AUTH_REPLY,
783 		       (void *)&msg, (unpack_func) sec_auth_reply_msg__unpack,
784 		       WSCONFIG(ws)->auth_timeout);
785 	if (ret < 0) {
786 		oclog(ws, LOG_ERR, "error receiving auth reply message");
787 		return ret;
788 	}
789 
790 	oclog(ws, LOG_DEBUG, "received auth reply message (value: %u)",
791 	      (unsigned)msg->reply);
792 
793 	if (txt) *txt = NULL;
794 
795 	switch (msg->reply) {
796 	case AUTH__REP__MSG:
797 		if (msg->msg)
798 			*txt = talloc_strdup(ws, msg->msg);
799 		else
800 			*txt = NULL;
801 
802 		if (msg->has_passwd_counter)
803 			*pcounter = msg->passwd_counter;
804 		else
805 			*pcounter = 0;
806 
807 		if (msg->has_sid && msg->sid.len == sizeof(ws->sid)) {
808 			/* update our sid */
809 			memcpy(ws->sid, msg->sid.data, sizeof(ws->sid));
810 			ws->sid_set = 1;
811 		}
812 
813 		ret = ERR_AUTH_CONTINUE;
814 		goto cleanup;
815 	case AUTH__REP__OK:
816 		if (msg->user_name == NULL) {
817 			ret = ERR_AUTH_FAIL;
818 			goto cleanup;
819 		}
820 
821 		strlcpy(ws->username, msg->user_name, sizeof(ws->username));
822 		if (msg->has_sid && msg->sid.len == sizeof(ws->sid)) {
823 			/* update our sid */
824 			memcpy(ws->sid, msg->sid.data, sizeof(ws->sid));
825 			ws->sid_set = 1;
826 		}
827 
828 		if (msg->has_sid == 0 ||
829 		    msg->sid.len != sizeof(ws->cookie) ||
830 		    msg->dtls_session_id.len != sizeof(ws->session_id)) {
831 
832 			ret = ERR_AUTH_FAIL;
833 			goto cleanup;
834 		}
835 
836 		memcpy(ws->cookie, msg->sid.data, msg->sid.len);
837 		ws->cookie_set = 1;
838 
839 		memcpy(ws->session_id, msg->dtls_session_id.data,
840 		       msg->dtls_session_id.len);
841 
842 		if (txt)
843 			*txt = talloc_strdup(ws, msg->msg);
844 
845 		break;
846 	case AUTH__REP__FAILED:
847 	default:
848 		if (msg->reply != AUTH__REP__FAILED)
849 			oclog(ws, LOG_ERR, "unexpected auth reply %u",
850 			      (unsigned)msg->reply);
851 		ret = ERR_AUTH_FAIL;
852 		goto cleanup;
853 	}
854 
855 	ret = 0;
856  cleanup:
857 	sec_auth_reply_msg__free_unpacked(msg, &pa);
858 	return ret;
859 }
860 
861 /* grabs the username from the session certificate */
862 static
get_cert_info(worker_st * ws)863 int get_cert_info(worker_st * ws)
864 {
865 	const gnutls_datum_t *cert;
866 	unsigned int ncerts;
867 	int ret;
868 
869 	if (ws->session == NULL) {
870 		/* if info has been passed using proxy protocol */
871 		if (ws->cert_username[0] != 0)
872 			return 0;
873 		else
874 			return -1;
875 	}
876 
877 	/* this is superflous. Verification has already been performed
878 	 * during handshake. */
879 	cert = gnutls_certificate_get_peers(ws->session, &ncerts);
880 
881 	if (cert == NULL) {
882 		return -1;
883 	}
884 
885 	ret = get_cert_names(ws, cert);
886 	if (ret < 0) {
887 		if (WSCONFIG(ws)->cert_user_oid == NULL) {
888 			oclog(ws, LOG_ERR, "cannot read username from certificate; cert-user-oid is not set");
889 		} else {
890 			oclog(ws, LOG_ERR, "cannot read username from certificate");
891 		}
892 		return -1;
893 	}
894 
895 	return 0;
896 }
897 
898 /* This makes sure that the provided cookie is valid,
899  * and fills in the ws->user_config.
900  */
cookie_authenticate_or_exit(worker_st * ws)901 void cookie_authenticate_or_exit(worker_st *ws)
902 {
903 	int ret;
904 
905 	if (ws->auth_state == S_AUTH_COMPLETE)
906 		return;
907 
908 	/* we must be in S_AUTH_COOKIE state */
909 	if (ws->auth_state != S_AUTH_COOKIE || ws->cookie_set == 0) {
910 		oclog(ws, LOG_WARNING, "no cookie found");
911 		cstp_puts(ws,
912 			 "HTTP/1.1 503 Service Unavailable\r\n\r\n");
913 		cstp_fatal_close(ws, GNUTLS_A_ACCESS_DENIED);
914 		exit_worker(ws);
915 	}
916 
917 	/* we have authenticated against sec-mod, we need to complete
918 	 * our authentication by forwarding our cookie to main. */
919 	ret = auth_cookie(ws, ws->cookie, sizeof(ws->cookie));
920 	if (ret < 0) {
921 		oclog(ws, LOG_WARNING, "failed cookie authentication attempt");
922 		if (ret == ERR_AUTH_FAIL) {
923 			cstp_puts(ws,
924 				 "HTTP/1.1 401 Cookie is not acceptable\r\n\r\n");
925 		} else {
926 			cstp_puts(ws,
927 				 "HTTP/1.1 503 Service Unavailable\r\n\r\n");
928 		}
929 		cstp_fatal_close(ws, GNUTLS_A_ACCESS_DENIED);
930 		exit_worker(ws);
931 	}
932 	ws->auth_state = S_AUTH_COMPLETE;
933 }
934 
935 /* sends a cookie authentication request to main thread and waits for
936  * a reply.
937  * Returns 0 on success.
938  */
auth_cookie(worker_st * ws,void * cookie,size_t cookie_size)939 int auth_cookie(worker_st * ws, void *cookie, size_t cookie_size)
940 {
941 	int ret;
942 	AuthCookieRequestMsg msg = AUTH_COOKIE_REQUEST_MSG__INIT;
943 
944 	if ((ws->selected_auth->type & AUTH_TYPE_CERTIFICATE)
945 	    && WSCONFIG(ws)->cisco_client_compat == 0) {
946 		if (ws->cert_auth_ok == 0) {
947 			oclog(ws, LOG_INFO,
948 			      "no certificate provided for cookie authentication");
949 			return -1;
950 		} else {
951 			ret = get_cert_info(ws);
952 			if (ret < 0) {
953 				oclog(ws, LOG_INFO, "cannot obtain certificate info");
954 				return -1;
955 			}
956 		}
957 	}
958 
959 	msg.cookie.data = cookie;
960 	msg.cookie.len = cookie_size;
961 	if (ws->req.hostname[0] != 0)
962 		msg.hostname = ws->req.hostname;
963 
964 	ret = send_msg_to_main(ws, AUTH_COOKIE_REQ, &msg, (pack_size_func)
965 			       auth_cookie_request_msg__get_packed_size,
966 			       (pack_func) auth_cookie_request_msg__pack);
967 	if (ret < 0) {
968 		oclog(ws, LOG_INFO,
969 		      "error sending cookie authentication request");
970 		return ret;
971 	}
972 
973 	ret = recv_cookie_auth_reply(ws);
974 	if (ret < 0) {
975 		oclog(ws, LOG_DEBUG,
976 		      "error receiving cookie authentication reply");
977 		return ret;
978 	}
979 
980 	return 0;
981 }
982 
post_common_handler(worker_st * ws,unsigned http_ver,const char * imsg)983 int post_common_handler(worker_st * ws, unsigned http_ver, const char *imsg)
984 {
985 	int ret, size;
986 	char str_cookie[BASE64_ENCODE_RAW_LENGTH(sizeof(ws->cookie))+1];
987 	size_t str_cookie_size = sizeof(str_cookie);
988 	char msg[MAX_BANNER_SIZE + 32];
989 	const char *success_msg_head;
990 	char *success_msg_foot;
991 	unsigned success_msg_head_size;
992 	unsigned success_msg_foot_size;
993 
994 	if (ws->req.user_agent_type == AGENT_OPENCONNECT_V3) {
995 		success_msg_head = ocv3_success_msg_head;
996 		success_msg_foot = talloc_strdup(ws, ocv3_success_msg_foot);
997 		success_msg_head_size = sizeof(ocv3_success_msg_head)-1;
998 		success_msg_foot_size = strlen(success_msg_foot);
999 	} else {
1000 		success_msg_head = oc_success_msg_head;
1001 		success_msg_foot = NULL;
1002 #ifdef ANYCONNECT_CLIENT_COMPAT
1003 		if (WSCONFIG(ws)->xml_config_file) {
1004 			success_msg_foot = talloc_asprintf(ws, OC_SUCCESS_MSG_FOOT_PROFILE,
1005 				WSCONFIG(ws)->xml_config_file, WSCONFIG(ws)->xml_config_hash);
1006 		}
1007 #endif
1008 
1009 		if (success_msg_foot == NULL) {
1010 			success_msg_foot = talloc_strdup(ws, OC_SUCCESS_MSG_FOOT);
1011 		}
1012 
1013 		if (success_msg_foot == NULL)
1014 			return -1;
1015 
1016 		success_msg_head_size = sizeof(oc_success_msg_head)-1;
1017 		success_msg_foot_size = strlen(success_msg_foot);
1018 	}
1019 
1020 	oc_base64_encode((char *)ws->cookie, sizeof(ws->cookie),
1021 		      (char *)str_cookie, str_cookie_size);
1022 
1023 	/* reply */
1024 	oclog(ws, LOG_HTTP_DEBUG, "HTTP sending: 200 OK");
1025 
1026 	cstp_cork(ws);
1027 	ret = cstp_printf(ws, "HTTP/1.%u 200 OK\r\n", http_ver);
1028 	if (ret < 0)
1029 		goto fail;
1030 
1031 	ret = cstp_puts(ws, "Connection: Keep-Alive\r\n");
1032 	if (ret < 0)
1033 		goto fail;
1034 
1035 	if ((ws->selected_auth->type & AUTH_TYPE_GSSAPI) && imsg != NULL && imsg[0] != 0) {
1036 		ret = cstp_printf(ws, "WWW-Authenticate: Negotiate %s\r\n", imsg);
1037 		if (ret < 0)
1038 			goto fail;
1039 	}
1040 
1041 	ret = cstp_puts(ws, "Content-Type: text/xml\r\n");
1042 	if (ret < 0)
1043 		goto fail;
1044 
1045 	if (WSCONFIG(ws)->banner) {
1046 		size =
1047 		    snprintf(msg, sizeof(msg), "<banner>%s</banner>",
1048 			     WSCONFIG(ws)->banner);
1049 		if (size <= 0)
1050 			goto fail;
1051 		/* snprintf() returns not a very useful value, so we need to recalculate */
1052 		size = strlen(msg);
1053 	} else {
1054 		msg[0] = 0;
1055 		size = 0;
1056 	}
1057 
1058 	size += success_msg_head_size + success_msg_foot_size;
1059 
1060 	ret = cstp_printf(ws, "Content-Length: %u\r\n", (unsigned)size);
1061 	if (ret < 0)
1062 		goto fail;
1063 
1064 	ret = cstp_puts(ws, "X-Transcend-Version: 1\r\n");
1065 	if (ret < 0)
1066 		goto fail;
1067 
1068 	if (ws->sid_set != 0) {
1069 		char context[BASE64_ENCODE_RAW_LENGTH(SID_SIZE) + 1];
1070 		char safe_id[SAFE_ID_SIZE];
1071 
1072 		oc_base64_encode((char *)ws->sid, sizeof(ws->sid), (char *)context,
1073 			         sizeof(context));
1074 
1075 		ret =
1076 		    cstp_printf(ws,
1077 			       "Set-Cookie: webvpncontext=%s; Secure; HttpOnly\r\n",
1078 			       context);
1079 		if (ret < 0)
1080 			goto fail;
1081 
1082 		oclog(ws, LOG_SENSITIVE, "sent session id: %s", calc_safe_id(ws->sid, sizeof(ws->sid), safe_id, sizeof(safe_id)));
1083 	}
1084 
1085 	ret =
1086 	    cstp_printf(ws,
1087 		       "Set-Cookie: webvpn=%s; Secure; HttpOnly\r\n",
1088 		       str_cookie);
1089 	if (ret < 0)
1090 		goto fail;
1091 
1092 	ret =
1093 	    cstp_puts(ws,
1094 		     "Set-Cookie: webvpnc=; expires=Thu, 01 Jan 1970 22:00:00 GMT; path=/; Secure; HttpOnly\r\n");
1095 	if (ret < 0)
1096 		goto fail;
1097 
1098 	ret =
1099 		add_owasp_headers(ws);
1100 	if (ret < 0)
1101 		goto fail;
1102 
1103 
1104 #ifdef ANYCONNECT_CLIENT_COMPAT
1105 	if (WSCONFIG(ws)->xml_config_file) {
1106 		ret =
1107 		    cstp_printf(ws,
1108 			       "Set-Cookie: webvpnc=bu:/&p:t&iu:1/&sh:%s&lu:/+CSCOT+/translation-table?textdomain%%3DAnyConnect%%26type%%3Dmanifest&fu:profiles%%2F%s&fh:%s; path=/; Secure; HttpOnly\r\n",
1109 			       WSPCONFIG(ws)->cert_hash,
1110 			       WSCONFIG(ws)->xml_config_file,
1111 			       WSCONFIG(ws)->xml_config_hash);
1112 	} else {
1113 		ret =
1114 		    cstp_printf(ws,
1115 			       "Set-Cookie: webvpnc=bu:/&p:t&iu:1/&sh:%s; path=/; Secure; HttpOnly\r\n",
1116 			       WSPCONFIG(ws)->cert_hash);
1117 	}
1118 #endif
1119 
1120 	if (ret < 0)
1121 		goto fail;
1122 
1123 	ret =
1124 	    cstp_printf(ws,
1125 		       "\r\n%s%s%s", success_msg_head, msg, success_msg_foot);
1126 	if (ret < 0)
1127 		goto fail;
1128 
1129 	ret = cstp_uncork(ws);
1130 	if (ret < 0)
1131 		goto fail;
1132 
1133 	return 0;
1134 
1135  fail:
1136 	talloc_free(success_msg_foot);
1137 	return -1;
1138 }
1139 
1140 /* Returns the contents of the password field in a newly allocated
1141  * string, or a negative value on error.
1142  *
1143  * @body: is the string to search the xml field at, should be null-terminated.
1144  * @value: the value that was found
1145  */
1146 static
match_password_in_reply(worker_st * ws,char * body,unsigned body_length,char ** value)1147 int match_password_in_reply(worker_st * ws, char *body, unsigned body_length,
1148 			    char **value)
1149 {
1150 	char *p;
1151 	unsigned len, xml = 0;
1152 
1153 	if (body == NULL || body_length == 0)
1154 		return -1;
1155 
1156 	if (memmem(body, body_length, "<?xml", 5) != 0) {
1157 		xml = 1;
1158 
1159 		/* body should contain <password?>test</password?> or <xxx_password>test</xxx_password> */
1160 		*value =
1161 		    strcasestr(body, "<password");
1162 		if (*value == NULL)
1163 			*value =
1164 			    strcasestr(body, "_password>");
1165 
1166 		if (*value == NULL) {
1167 			oclog(ws, LOG_HTTP_DEBUG,
1168 			      "cannot find password in client XML message");
1169 			return -1;
1170 		}
1171 		/* find terminator */
1172 		p = strchr(*value, '>');
1173 		if (p == NULL) {
1174 			oclog(ws, LOG_HTTP_DEBUG,
1175 			      "unterminated password in client XML message");
1176 			return -1;
1177 		}
1178 		p++;
1179 
1180 		*value = p;
1181 		len = 0;
1182 		while (*p != 0) {
1183 			if (*p == '<' && *(p+1) == '/') {
1184 				break;
1185 			}
1186 			p++;
1187 			len++;
1188 		}
1189 	} else {		/* non-xml version */
1190 		/* body should be "username=test&password?=test" */
1191 		*value =
1192 		    strcasestr(body, "password");
1193 		if (*value == NULL) {
1194 			oclog(ws, LOG_HTTP_DEBUG,
1195 			      "cannot find password in client message");
1196 			return -1;
1197 		}
1198 
1199 		p = strchr(*value, '=');
1200 		if (p == NULL) {
1201 			oclog(ws, LOG_HTTP_DEBUG,
1202 			      "unterminated password in client message");
1203 			return -1;
1204 		}
1205 		p++;
1206 
1207 		*value = p;
1208 		len = 0;
1209 		while (*p != 0) {
1210 			if (*p == '&') {
1211 				break;
1212 			}
1213 			p++;
1214 			len++;
1215 		}
1216 	}
1217 
1218 	if (len == 0) {
1219 		*value = talloc_strdup(ws->req.body, "");
1220 		if (*value != NULL)
1221 			return 0;
1222 		return -1;
1223 	}
1224 	if (xml)
1225 		*value = unescape_html(ws->req.body, *value, len, NULL);
1226 	else
1227 		*value = unescape_url(ws->req.body, *value, len, NULL);
1228 
1229 	if (*value == NULL) {
1230 		oclog(ws, LOG_ERR,
1231 		      "password requested but no such field in client message");
1232 		return -1;
1233 	}
1234 
1235 	return 0;
1236 }
1237 
1238 /* Returns the contents of the provided fields in a newly allocated
1239  * string, or a negative value on error.
1240  *
1241  * @body: is the string to search the xml field at, should be null-terminated.
1242  * @xml_field: the XML field to check for (e.g., MYFIELD)
1243  * @value: the value that was found
1244  */
1245 static
parse_reply(worker_st * ws,char * body,unsigned body_length,const char * field,unsigned field_size,const char * xml_field,unsigned xml_field_size,char ** value)1246 int parse_reply(worker_st * ws, char *body, unsigned body_length,
1247 		const char *field, unsigned field_size,
1248 		const char *xml_field, unsigned xml_field_size,
1249 		char **value)
1250 {
1251 	char *p;
1252 	char temp1[64];
1253 	char temp2[64];
1254 	unsigned temp2_len, temp1_len;
1255 	unsigned len, xml = 0;
1256 
1257 	if (body == NULL || body_length == 0)
1258 		return -1;
1259 
1260 	if (memmem(body, body_length, "<?xml", 5) != 0) {
1261 		xml = 1;
1262 		if (xml_field) {
1263 			field = xml_field;
1264 			/*field_size = xml_field_size;*/
1265 		}
1266 
1267 		snprintf(temp1, sizeof(temp1), "<%s>", field);
1268 		snprintf(temp2, sizeof(temp2), "</%s>", field);
1269 
1270 		temp1_len = strlen(temp1);
1271 		temp2_len = strlen(temp2);
1272 
1273 		/* body should contain <field>test</field> */
1274 		*value =
1275 		    strcasestr(body, temp1);
1276 		if (*value == NULL) {
1277 			oclog(ws, LOG_HTTP_DEBUG,
1278 			      "cannot find '%s' in client XML message", field);
1279 			return -1;
1280 		}
1281 		*value += temp1_len;
1282 
1283 		p = *value;
1284 		len = 0;
1285 		while (*p != 0) {
1286 			if (*p == '<'
1287 			    && (strncasecmp(p, temp2, temp2_len) == 0)) {
1288 				break;
1289 			}
1290 			p++;
1291 			len++;
1292 		}
1293 	} else {		/* non-xml version */
1294 		snprintf(temp1, sizeof(temp1), "%s=", field);
1295 		temp1_len = strlen(temp1);
1296 
1297 		/* body should be "username=test&password=test" */
1298 		*value =
1299 		    strcasestr(body, temp1);
1300 		if (*value == NULL) {
1301 			oclog(ws, LOG_HTTP_DEBUG,
1302 			      "cannot find '%s' in client message", field);
1303 			return -1;
1304 		}
1305 
1306 		*value += temp1_len;
1307 
1308 		p = *value;
1309 		len = 0;
1310 		while (*p != 0) {
1311 			if (*p == '&') {
1312 				break;
1313 			}
1314 			p++;
1315 			len++;
1316 		}
1317 	}
1318 
1319 	if (len == 0) {
1320 		*value = talloc_strdup(ws->req.body, "");
1321 		if (*value != NULL)
1322 			return 0;
1323 		return -1;
1324 	}
1325 	if (xml)
1326 		*value = unescape_html(ws->req.body, *value, len, NULL);
1327 	else
1328 		*value = unescape_url(ws->req.body, *value, len, NULL);
1329 
1330 	if (*value == NULL) {
1331 		oclog(ws, LOG_ERR,
1332 		      "%s requested but no such field in client message", field);
1333 		return -1;
1334 	}
1335 
1336 	return 0;
1337 }
1338 
1339 #define SPNEGO_MSG "<html><body>Please authenticate using GSSAPI</body></html>"
1340 static
basic_auth_handler(worker_st * ws,unsigned http_ver,const char * msg)1341 int basic_auth_handler(worker_st * ws, unsigned http_ver, const char *msg)
1342 {
1343 	int ret;
1344 
1345 	oclog(ws, LOG_HTTP_DEBUG, "HTTP sending: 401 Unauthorized");
1346 	cstp_cork(ws);
1347 	ret = cstp_printf(ws, "HTTP/1.%u 401 Unauthorized\r\n", http_ver);
1348 	if (ret < 0)
1349 		return -1;
1350 
1351 	if (WSPCONFIG(ws)->auth_methods > 1) {
1352 		ret = cstp_puts(ws, "X-HTTP-Auth-Support: fallback\r\n");
1353 		if (ret < 0)
1354 			return -1;
1355 	}
1356 
1357 	if (msg == NULL) {
1358 		oclog(ws, LOG_HTTP_DEBUG, "HTTP sending: WWW-Authenticate: Negotiate");
1359 		ret = cstp_puts(ws, "WWW-Authenticate: Negotiate\r\n");
1360 	} else {
1361 		oclog(ws, LOG_HTTP_DEBUG, "HTTP sending: WWW-Authenticate: Negotiate %s", msg);
1362 		ret = cstp_printf(ws, "WWW-Authenticate: Negotiate %s\r\n", msg);
1363 	}
1364 	if (ret < 0)
1365 		return -1;
1366 
1367 	ret = cstp_puts(ws, "Content-Length: 0\r\n");
1368 	if (ret < 0) {
1369 		ret = -1;
1370 		goto cleanup;
1371 	}
1372 
1373 	ret = cstp_puts(ws, "\r\n");
1374 	if (ret < 0) {
1375 		ret = -1;
1376 		goto cleanup;
1377 	}
1378 
1379 	ret = cstp_uncork(ws);
1380 	if (ret < 0) {
1381 		ret = -1;
1382 		goto cleanup;
1383 	}
1384 
1385 	ret = 0;
1386 
1387  cleanup:
1388 	return ret;
1389 }
1390 
1391 #ifdef SUPPORT_OIDC_AUTH
1392 static
oidc_auth_handler(worker_st * ws,unsigned http_ver)1393 int oidc_auth_handler(worker_st * ws, unsigned http_ver)
1394 {
1395 	int ret;
1396 
1397 	oclog(ws, LOG_HTTP_DEBUG, "HTTP sending: 401 Unauthorized");
1398 	cstp_cork(ws);
1399 	ret = cstp_printf(ws, "HTTP/1.%u 401 Unauthorized\r\n", http_ver);
1400 	if (ret < 0)
1401 		return -1;
1402 
1403 	oclog(ws, LOG_HTTP_DEBUG, "HTTP sending: WWW-Authenticate: %s", HTTP_AUTH_OIDC_PREFIX);
1404 	ret = cstp_printf(ws, "WWW-Authenticate: %s\r\n", HTTP_AUTH_OIDC_PREFIX);
1405 
1406 	if (ret < 0)
1407 		return -1;
1408 
1409 	ret = cstp_puts(ws, "Content-Length: 0\r\n");
1410 	if (ret < 0) {
1411 		ret = -1;
1412 		goto cleanup;
1413 	}
1414 
1415 	ret = cstp_puts(ws, "\r\n");
1416 	if (ret < 0) {
1417 		ret = -1;
1418 		goto cleanup;
1419 	}
1420 
1421 	ret = cstp_uncork(ws);
1422 	if (ret < 0) {
1423 		ret = -1;
1424 		goto cleanup;
1425 	}
1426 
1427 	ret = 0;
1428 
1429  cleanup:
1430 	return ret;
1431 }
1432 #endif
1433 
1434 #define USERNAME_FIELD "username"
1435 #define GROUPNAME_FIELD "group%5flist"
1436 #define GROUPNAME_FIELD2 "group_list"
1437 #define GROUPNAME_FIELD_XML "group-select"
1438 
1439 #define MSG_INTERNAL_ERROR "Internal error"
1440 #define MSG_CERT_READ_ERROR "Could not read certificate"
1441 #define MSG_NO_CERT_ERROR "No certificate"
1442 #define MSG_NO_PASSWORD_ERROR "No password"
1443 
post_auth_handler(worker_st * ws,unsigned http_ver)1444 int post_auth_handler(worker_st * ws, unsigned http_ver)
1445 {
1446 	int ret = -1, sd = -1;
1447 	struct http_req_st *req = &ws->req;
1448 	const char *reason = "Authentication failed";
1449 	char *username = NULL;
1450 	char *password = NULL;
1451 	char *groupname = NULL;
1452 	char *msg = NULL;
1453 	unsigned def_group = 0;
1454 	unsigned pcounter = 0;
1455 
1456 	if (req->body_length > 0) {
1457 		oclog(ws, LOG_HTTP_DEBUG, "POST body: '%.*s'", (int)req->body_length,
1458 		      req->body);
1459 	}
1460 
1461 	if (ws->sid_set && ws->auth_state == S_AUTH_INACTIVE)
1462 		ws->auth_state = S_AUTH_INIT;
1463 
1464 	if (ws->auth_state == S_AUTH_INACTIVE) {
1465 		SecAuthInitMsg ireq = SEC_AUTH_INIT_MSG__INIT;
1466 
1467 		ret = parse_reply(ws, req->body, req->body_length,
1468 				GROUPNAME_FIELD, sizeof(GROUPNAME_FIELD)-1,
1469 				GROUPNAME_FIELD_XML, sizeof(GROUPNAME_FIELD_XML)-1,
1470 				&groupname);
1471 		if (ret < 0) {
1472 			ret = parse_reply(ws, req->body, req->body_length,
1473 					GROUPNAME_FIELD2, sizeof(GROUPNAME_FIELD2)-1,
1474 					GROUPNAME_FIELD_XML, sizeof(GROUPNAME_FIELD_XML)-1,
1475 					&groupname);
1476 		}
1477 
1478 		if (ret < 0) {
1479 			oclog(ws, LOG_HTTP_DEBUG, "failed reading groupname");
1480 		} else {
1481 			if (WSCONFIG(ws)->default_select_group != NULL &&
1482 				   strcmp(groupname, WSCONFIG(ws)->default_select_group) == 0) {
1483 				def_group = 1;
1484 			} else {
1485 				/* Some anyconnect clients send the group friendly name instead of
1486 				 * the actual value; see #267 */
1487 				ws->groupname[0] = 0;
1488 				if (WSCONFIG(ws)->friendly_group_list != NULL) {
1489 					unsigned found = 0, i;
1490 
1491 					for (i=0;i<WSCONFIG(ws)->group_list_size;i++) {
1492 						if (strcmp(WSCONFIG(ws)->group_list[i], groupname) == 0) {
1493 							found = 1;
1494 							break;
1495 						}
1496 					}
1497 
1498 					if (!found)
1499 						for (i=0;i<WSCONFIG(ws)->group_list_size;i++) {
1500 							if (WSCONFIG(ws)->friendly_group_list[i] != NULL && strcmp(WSCONFIG(ws)->friendly_group_list[i], groupname) == 0) {
1501 								strlcpy(ws->groupname, WSCONFIG(ws)->group_list[i], sizeof(ws->groupname));
1502 								break;
1503 							}
1504 						}
1505 				}
1506 
1507 				if (ws->groupname[0] == 0)
1508 					strlcpy(ws->groupname, groupname, sizeof(ws->groupname));
1509 				ireq.group_name = ws->groupname;
1510 			}
1511 		}
1512 		talloc_free(groupname);
1513 
1514 #ifdef SUPPORT_OIDC_AUTH
1515 		if (ws->selected_auth->type & AUTH_TYPE_OIDC) {
1516 			if (req->authorization == NULL || req->authorization_size == 0)
1517 				return oidc_auth_handler(ws, http_ver);
1518 
1519 			if ((req->authorization_size > (sizeof(HTTP_AUTH_OIDC_PREFIX) - 1)) && strncasecmp(req->authorization, HTTP_AUTH_OIDC_PREFIX, sizeof(HTTP_AUTH_OIDC_PREFIX) - 1) == 0) {
1520 				ireq.auth_type |= AUTH_TYPE_OIDC;
1521 				ireq.user_name = req->authorization + sizeof(HTTP_AUTH_OIDC_PREFIX);
1522 			} else {
1523 				oclog(ws, LOG_HTTP_DEBUG, "Invalid authorization data: %.*s", req->authorization_size, req->authorization);
1524 				goto auth_fail;
1525 			}
1526 		}
1527 #endif
1528 
1529 		if (ws->selected_auth->type & AUTH_TYPE_GSSAPI) {
1530 			if (req->authorization == NULL || req->authorization_size == 0)
1531 				return basic_auth_handler(ws, http_ver, NULL);
1532 
1533 			if (req->authorization_size > 10) {
1534 				ireq.user_name = req->authorization + 10;
1535 				ireq.auth_type |= AUTH_TYPE_GSSAPI;
1536 			} else {
1537 				oclog(ws, LOG_HTTP_DEBUG, "Invalid authorization data: %.*s", req->authorization_size, req->authorization);
1538 				goto auth_fail;
1539 			}
1540 		}
1541 
1542 		if (ws->selected_auth->type & AUTH_TYPE_USERNAME_PASS) {
1543 
1544 			ret = parse_reply(ws, req->body, req->body_length,
1545 					USERNAME_FIELD, sizeof(USERNAME_FIELD)-1,
1546 					NULL, 0,
1547 					&username);
1548 			if (ret < 0) {
1549 				oclog(ws, LOG_HTTP_DEBUG, "failed reading username");
1550 				goto ask_auth;
1551 			}
1552 
1553 			strlcpy(ws->username, username, sizeof(ws->username));
1554 			talloc_free(username);
1555 			ireq.user_name = ws->username;
1556 			ireq.auth_type |= AUTH_TYPE_USERNAME_PASS;
1557 		}
1558 
1559 		if (ws->selected_auth->type & AUTH_TYPE_CERTIFICATE) {
1560 			if (ws->cert_auth_ok == 0) {
1561 				reason = MSG_NO_CERT_ERROR;
1562 				oclog(ws, LOG_INFO,
1563 				      "no certificate provided for authentication");
1564 
1565 				if (ws_switch_auth_to_next(ws) == 0)
1566 					goto auth_fail;
1567 
1568 				ws->auth_state = S_AUTH_INACTIVE;
1569 				ws->sid_set = 0;
1570 				goto ask_auth;
1571 			} else {
1572 				ret = get_cert_info(ws);
1573 				if (ret < 0) {
1574 					reason = MSG_CERT_READ_ERROR;
1575 					oclog(ws, LOG_ERR,
1576 					      "failed reading certificate info");
1577 					goto auth_fail;
1578 				}
1579 			}
1580 
1581 			if (def_group == 0 && ws->cert_groups_size > 0 && ws->groupname[0] == 0) {
1582 				oclog(ws, LOG_HTTP_DEBUG, "user has not selected a group");
1583 				return get_auth_handler2(ws, http_ver, "Please select your group.", 0);
1584 			}
1585 
1586 			ireq.tls_auth_ok = ws->cert_auth_ok;
1587 			ireq.cert_user_name = ws->cert_username;
1588 			ireq.cert_group_names = ws->cert_groups;
1589 			ireq.n_cert_group_names = ws->cert_groups_size;
1590 			ireq.auth_type |= AUTH_TYPE_CERTIFICATE;
1591 		}
1592 
1593 		ireq.vhost = ws->vhost->name;
1594 		ireq.ip = ws->remote_ip_str;
1595 		ireq.our_ip = ws->our_ip_str;
1596 		ireq.session_start_time = ws->session_start_time;
1597 		ireq.hmac.data = (uint8_t*)ws->sec_auth_init_hmac;
1598 		ireq.hmac.len = sizeof(ws->sec_auth_init_hmac);
1599 		if (req->user_agent[0] != 0)
1600 			ireq.user_agent = req->user_agent;
1601 
1602 		if (req->devtype[0] != 0)
1603 			ireq.device_type = req->devtype;
1604 
1605 		if (req->devplatform[0] != 0)
1606 			ireq.device_platform = req->devplatform;
1607 
1608 		sd = connect_to_secmod(ws);
1609 		if (sd == -1) {
1610 			reason = MSG_INTERNAL_ERROR;
1611 			oclog(ws, LOG_ERR, "failed connecting to sec mod");
1612 			goto auth_fail;
1613 		}
1614 
1615 		ret = send_msg_to_secmod(ws, sd, CMD_SEC_AUTH_INIT,
1616 					 &ireq, (pack_size_func)
1617 					 sec_auth_init_msg__get_packed_size,
1618 					 (pack_func) sec_auth_init_msg__pack);
1619 		if (ret < 0) {
1620 			reason = MSG_INTERNAL_ERROR;
1621 			oclog(ws, LOG_ERR,
1622 			      "failed sending auth init message to sec mod");
1623 			goto auth_fail;
1624 		}
1625 
1626 		ws->auth_state = S_AUTH_INIT;
1627 	} else if (ws->auth_state == S_AUTH_INIT
1628 		   || ws->auth_state == S_AUTH_REQ) {
1629 		SecAuthContMsg areq = SEC_AUTH_CONT_MSG__INIT;
1630 
1631 		areq.ip = ws->remote_ip_str;
1632 		if (ws->selected_auth->type & AUTH_TYPE_GSSAPI) {
1633 			if (req->authorization == NULL || req->authorization_size <= 10) {
1634 				if (req->authorization != NULL)
1635 					oclog(ws, LOG_HTTP_DEBUG, "Invalid authorization data: %.*s", req->authorization_size, req->authorization);
1636 				else
1637 					oclog(ws, LOG_HTTP_DEBUG, "No authorization data");
1638 				goto auth_fail;
1639 			}
1640 			areq.password = req->authorization + 10;
1641 		}
1642 
1643 		if (areq.password == NULL && (ws->selected_auth->type & AUTH_TYPE_USERNAME_PASS)) {
1644 			ret = match_password_in_reply(ws, req->body, req->body_length,
1645 						      &password);
1646 			if (ret < 0) {
1647 				reason = MSG_NO_PASSWORD_ERROR;
1648 				oclog(ws, LOG_ERR, "failed reading password");
1649 				goto auth_fail;
1650 			}
1651 
1652 			areq.password = password;
1653 		}
1654 
1655 		if (areq.password != NULL) {
1656 			if (ws->sid_set != 0) {
1657 				areq.sid.data = ws->sid;
1658 				areq.sid.len = sizeof(ws->sid);
1659 			}
1660 
1661 			sd = connect_to_secmod(ws);
1662 			if (sd == -1) {
1663 				reason = MSG_INTERNAL_ERROR;
1664 				oclog(ws, LOG_ERR,
1665 				      "failed connecting to sec mod");
1666 				goto auth_fail;
1667 			}
1668 
1669 			ret =
1670 			    send_msg_to_secmod(ws, sd, CMD_SEC_AUTH_CONT, &areq,
1671 					       (pack_size_func)
1672 					       sec_auth_cont_msg__get_packed_size,
1673 					       (pack_func)
1674 					       sec_auth_cont_msg__pack);
1675 			talloc_free(password);
1676 
1677 			if (ret < 0) {
1678 				reason = MSG_INTERNAL_ERROR;
1679 				oclog(ws, LOG_ERR,
1680 				      "failed sending auth req message to main");
1681 				goto auth_fail;
1682 			}
1683 
1684 			ws->auth_state = S_AUTH_REQ;
1685 		} else {
1686 			oclog(ws, LOG_ERR, "No password provided");
1687 			goto auth_fail;
1688 		}
1689 	} else {
1690 		oclog(ws, LOG_ERR, "unexpected POST request in auth state %u",
1691 		      (unsigned)ws->auth_state);
1692 		goto auth_fail;
1693 	}
1694 
1695 	ret = recv_auth_reply(ws, sd, &msg, &pcounter);
1696 	if (sd != -1) {
1697 		close(sd);
1698 		sd = -1;
1699 	}
1700 
1701 	if (ret == ERR_AUTH_CONTINUE) {
1702 
1703 		oclog(ws, LOG_DEBUG, "continuing authentication for '%s'",
1704 		      ws->username);
1705 		ws->auth_state = S_AUTH_REQ;
1706 
1707 		if (ws->selected_auth->type & AUTH_TYPE_GSSAPI) {
1708 			ret = basic_auth_handler(ws, http_ver, msg);
1709 		} else {
1710 			ret = get_auth_handler2(ws, http_ver, msg, pcounter);
1711 		}
1712 		goto cleanup;
1713 	} else if (ret < 0) {
1714 		if (ws->selected_auth->type & AUTH_TYPE_GSSAPI) {
1715 			/* Fallback from GSSAPI to USERNAME-PASSWORD */
1716 			oclog(ws, LOG_ERR, "failed gssapi authentication");
1717 			if (ws_switch_auth_to_next(ws) == 0)
1718 				goto auth_fail;
1719 
1720 			ws->auth_state = S_AUTH_INACTIVE;
1721 			ws->sid_set = 0;
1722 			goto ask_auth;
1723 		} else {
1724 			oclog(ws, LOG_ERR, "failed authentication for '%s'",
1725 			      ws->username);
1726 			goto auth_fail;
1727 		}
1728 	}
1729 
1730 	oclog(ws, LOG_HTTP_DEBUG, "user '%s' obtained cookie", ws->username);
1731 	ws->auth_state = S_AUTH_COOKIE;
1732 
1733 	ret = post_common_handler(ws, http_ver, msg);
1734 	goto cleanup;
1735 
1736  ask_auth:
1737 
1738 	return get_auth_handler(ws, http_ver);
1739 
1740  auth_fail:
1741 
1742 	if (sd != -1)
1743 		close(sd);
1744 	oclog(ws, LOG_HTTP_DEBUG, "HTTP sending: 401 Unauthorized");
1745 	ret = cstp_printf(ws,
1746 		   "HTTP/1.%d 401 %s\r\nContent-Length: 0\r\n\r\n",
1747 		   http_ver, reason);
1748 	if (ret >= 0)
1749 		cstp_fatal_close(ws, GNUTLS_A_ACCESS_DENIED);
1750 	talloc_free(msg);
1751 	exit_worker(ws);
1752  cleanup:
1753  	talloc_free(msg);
1754  	return ret;
1755 }
1756 
1757