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