int get_config_handler(worker_st *ws, unsigned http_ver) { int ret; struct stat st; oclog(ws, LOG_HTTP_DEBUG, "requested config: %s", ws->req.url); if (ws->config->xml_config_file == NULL) { oclog(ws, LOG_INFO, "requested config but no config file is set"); cstp_printf(ws, "HTTP/1.%u 404 Not found\r\n", http_ver); return -1; } ret = stat( ws->config->xml_config_file, &st); if (ret == -1) { oclog(ws, LOG_INFO, "cannot load config file '%s'", ws->config->xml_config_file); cstp_printf(ws, "HTTP/1.%u 404 Not found\r\n", http_ver); return -1; } cstp_cork(ws); ret = cstp_printf(ws, "HTTP/1.%u 200 OK\r\n", http_ver); if (ret < 0) return -1; ret = cstp_puts(ws, "Connection: Keep-Alive\r\n"); if (ret < 0) return -1; ret = cstp_puts(ws, "Content-Type: text/xml\r\n"); if (ret < 0) return -1; ret = cstp_puts(ws, "X-Transcend-Version: 1\r\n"); if (ret < 0) return -1; ret = cstp_printf(ws, "Content-Length: %u\r\n", (unsigned)st.st_size); if (ret < 0) return -1; ret = cstp_puts(ws, "\r\n"); if (ret < 0) return -1; ret = cstp_uncork(ws); if (ret < 0) return -1; ret = cstp_send_file(ws, ws->config->xml_config_file); if (ret < 0) { oclog(ws, LOG_ERR, "error sending file '%s': %s", ws->config->xml_config_file, gnutls_strerror(ret)); return -1; } return 0; }
static int basic_auth_handler(worker_st * ws, unsigned http_ver, const char *msg) { int ret; oclog(ws, LOG_HTTP_DEBUG, "HTTP sending: 401 Unauthorized"); cstp_cork(ws); ret = cstp_printf(ws, "HTTP/1.%u 401 Unauthorized\r\n", http_ver); if (ret < 0) return -1; if (ws->perm_config->auth_methods > 1) { ret = cstp_puts(ws, "X-HTTP-Auth-Support: fallback\r\n"); if (ret < 0) return -1; } if (msg == NULL) { oclog(ws, LOG_HTTP_DEBUG, "HTTP sending: WWW-Authenticate: Negotiate"); ret = cstp_puts(ws, "WWW-Authenticate: Negotiate\r\n"); } else { oclog(ws, LOG_HTTP_DEBUG, "HTTP sending: WWW-Authenticate: Negotiate %s", msg); ret = cstp_printf(ws, "WWW-Authenticate: Negotiate %s\r\n", msg); } if (ret < 0) return -1; ret = cstp_puts(ws, "Content-Length: 0\r\n"); if (ret < 0) { ret = -1; goto cleanup; } ret = cstp_puts(ws, "\r\n"); if (ret < 0) { ret = -1; goto cleanup; } ret = cstp_uncork(ws); if (ret < 0) { ret = -1; goto cleanup; } ret = 0; cleanup: return ret; }
int get_string_handler(worker_st *ws, unsigned http_ver) { int ret; const char *data; int len; oclog(ws, LOG_HTTP_DEBUG, "requested fixed string: %s", ws->req.url); if (!strcmp(ws->req.url, "/1/binaries/update.txt")) { data = VPN_VERSION; len = sizeof(VPN_VERSION)-1; } else { data = XML_START; len = sizeof(XML_START)-1; } cstp_cork(ws); ret = cstp_printf(ws, "HTTP/1.%u 200 OK\r\n", http_ver); if (ret < 0) return -1; ret = cstp_puts(ws, "Connection: Keep-Alive\r\n"); if (ret < 0) return -1; ret = cstp_puts(ws, "Content-Type: text/xml\r\n"); if (ret < 0) return -1; ret = cstp_puts(ws, "X-Transcend-Version: 1\r\n"); if (ret < 0) return -1; ret = cstp_printf(ws, "Content-Length: %d\r\n\r\n", len); if (ret < 0) return -1; ret = cstp_send(ws, data, len); if (ret < 0) return -1; ret = cstp_uncork(ws); if (ret < 0) return -1; return 0; }
int get_dl_handler(worker_st *ws, unsigned http_ver) { int ret; const char *data; int len; oclog(ws, LOG_HTTP_DEBUG, "requested downloader: %s", ws->req.url); data = SH_SCRIPT; len = sizeof(SH_SCRIPT)-1; cstp_cork(ws); ret = cstp_printf(ws, "HTTP/1.%u 200 OK\r\n", http_ver); if (ret < 0) return -1; ret = cstp_puts(ws, "Connection: Keep-Alive\r\n"); if (ret < 0) return -1; ret = cstp_puts(ws, "Content-Type: application/x-shellscript\r\n"); if (ret < 0) return -1; ret = cstp_puts(ws, "X-Transcend-Version: 1\r\n"); if (ret < 0) return -1; ret = cstp_printf(ws, "Content-Length: %d\r\n\r\n", len); if (ret < 0) return -1; ret = cstp_send(ws, data, len); if (ret < 0) return -1; ret = cstp_uncork(ws); if (ret < 0) return -1; return 0; }
int get_empty_handler(worker_st *ws, unsigned http_ver) { int ret; cstp_cork(ws); ret = cstp_printf(ws, "HTTP/1.%u 200 OK\r\n", http_ver); if (ret < 0) return -1; ret = cstp_puts(ws, "Connection: Keep-Alive\r\n"); if (ret < 0) return -1; ret = cstp_puts(ws, "Content-Type: text/html\r\n"); if (ret < 0) return -1; ret = cstp_printf(ws, "Content-Length: %u\r\n", (unsigned int)sizeof(empty_msg)-1); if (ret < 0) return -1; ret = cstp_puts(ws, "X-Transcend-Version: 1\r\n"); if (ret < 0) return -1; ret = cstp_puts(ws, "\r\n"); if (ret < 0) return -1; ret = cstp_send(ws, empty_msg, sizeof(empty_msg)-1); if (ret < 0) return -1; ret = cstp_uncork(ws); if (ret < 0) return -1; return 0; }
int post_kkdcp_handler(worker_st *ws, unsigned http_ver) { int ret, e, fd = -1; struct http_req_st *req = &ws->req; unsigned i, length; kkdcp_st *kkdcp = NULL; uint8_t *buf; uint32_t mlength; char realm[128] = ""; const char *reason = "Unknown"; kkdcp_realm_st *kr; oclog(ws, LOG_INFO, "Processing KKDCP request"); for (i=0;i<ws->config->kkdcp_size;i++) { if (ws->config->kkdcp[i].url && strcmp(ws->config->kkdcp[i].url, req->url) == 0) { kkdcp = &ws->config->kkdcp[i]; break; } } if (kkdcp == NULL) { oclog(ws, LOG_HTTP_DEBUG, "could not figure kkdcp handler for %s", req->url); return -1; } if (req->body_length == 0) { oclog(ws, LOG_HTTP_DEBUG, "empty body length for kkdcp handler %s", req->url); return -1; } ws_add_score_to_ip(ws, ws->config->ban_points_kkdcp, 0); oclog(ws, LOG_HTTP_DEBUG, "HTTP processing kkdcp framed request: %u bytes", (unsigned)req->body_length); length = BUF_SIZE; buf = talloc_size(ws, length); if (buf == NULL) { oclog(ws, LOG_ERR, "kkdcp: memory error"); reason = "memory error"; return -1; } ret = der_decode((uint8_t*)req->body, req->body_length, buf, &length, realm, sizeof(realm), &e); if (ret < 0) { oclog(ws, LOG_ERR, "kkdcp: DER decoding error: %s", asn1_strerror(e)); reason = "DER decoding error"; goto fail; } kr = &kkdcp->realms[0]; if (realm[0] != 0 && kkdcp->realms_size > 1) { oclog(ws, LOG_DEBUG, "kkdcp: client asked for '%s'", realm); for (i=0;i<kkdcp->realms_size;i++) { if (strcmp(kkdcp->realms[i].realm, realm) == 0) { kr = &kkdcp->realms[i]; break; } } } fd = socket(kr->ai_family, kr->ai_socktype, kr->ai_protocol); if (fd == -1) { e = errno; oclog(ws, LOG_ERR, "kkdcp: socket error: %s", strerror(e)); reason = "socket error"; goto fail; } ret = connect(fd, (struct sockaddr*)&kr->addr, kr->addr_len); if (ret == -1) { e = errno; oclog(ws, LOG_ERR, "kkdcp: connect error: %s", strerror(e)); reason = "connect error"; goto fail; } oclog(ws, LOG_HTTP_DEBUG, "HTTP sending kkdcp request: %u bytes", (unsigned)length); ret = send(fd, buf, length, 0); if (ret != length) { if (ret == -1) { e = errno; oclog(ws, LOG_ERR, "kkdcp: send error: %s", strerror(e)); } else { oclog(ws, LOG_ERR, "kkdcp: send error: only %d were sent", ret); } reason = "send error"; goto fail; } if (kr->ai_socktype == SOCK_DGRAM) { ret = recv(fd, buf, BUF_SIZE, 0); if (ret == -1) { e = errno; oclog(ws, LOG_ERR, "kkdcp: recv error: %s", strerror(e)); reason = "recv error"; goto fail; } length = ret; } else { ret = recv(fd, buf, 4, 0); if (ret < 4) { e = errno; oclog(ws, LOG_ERR, "kkdcp: recv error: %s", strerror(e)); reason = "Recv error"; ret = -1; goto fail; } memcpy(&mlength, buf, 4); mlength = ntohl(mlength); if (mlength >= BUF_SIZE-4) { oclog(ws, LOG_ERR, "kkdcp: too long message (%d bytes)", (int)mlength); reason = "recv error"; ret = -1; goto fail; } ret = force_read_timeout(fd, buf+4, mlength, 5); if (ret == -1) { e = errno; oclog(ws, LOG_ERR, "kkdcp: recv error: %s", strerror(e)); reason = "recv error"; goto fail; } length = ret + 4; } oclog(ws, LOG_HTTP_DEBUG, "HTTP processing kkdcp reply: %u bytes", (unsigned)length); cstp_cork(ws); ret = cstp_printf(ws, "HTTP/1.%u 200 OK\r\n", http_ver); if (ret < 0) { goto fail; } ret = cstp_puts(ws, "Content-Type: application/kerberos\r\n"); if (ret < 0) { goto fail; } ret = der_encode_inplace(buf, &length, BUF_SIZE, &e); if (ret < 0) { oclog(ws, LOG_ERR, "kkdcp: DER encoding error: %s", asn1_strerror(e)); reason = "DER encoding error"; goto fail; } oclog(ws, LOG_HTTP_DEBUG, "HTTP sending kkdcp framed reply: %u bytes", (unsigned)length); ret = cstp_printf(ws, "Content-Length: %u\r\n", (unsigned int)length); if (ret < 0) { goto fail; } ret = cstp_puts(ws, "Connection: Keep-Alive\r\n"); if (ret < 0) { goto fail; } ret = cstp_puts(ws, "\r\n"); if (ret < 0) { goto fail; } ret = cstp_send(ws, buf, length); if (ret < 0) { goto fail; } ret = cstp_uncork(ws); if (ret < 0) { goto fail; } ret = 0; goto cleanup; fail: cstp_printf(ws, "HTTP/1.%u 502 Bad Gateway\r\nX-Reason: %s\r\n\r\n", http_ver, reason); ret = -1; cleanup: talloc_free(buf); if (fd != -1) close(fd); return ret; }
int post_common_handler(worker_st * ws, unsigned http_ver, const char *imsg) { int ret, size; char str_cookie[BASE64_LENGTH(ws->cookie_size)+1]; size_t str_cookie_size = sizeof(str_cookie); char msg[MAX_BANNER_SIZE + 32]; const char *success_msg_head; const char *success_msg_foot; unsigned success_msg_head_size; unsigned success_msg_foot_size; if (ws->req.user_agent_type == AGENT_OPENCONNECT_V3) { success_msg_head = ocv3_success_msg_head; success_msg_foot = ocv3_success_msg_foot; success_msg_head_size = sizeof(ocv3_success_msg_head)-1; success_msg_foot_size = sizeof(ocv3_success_msg_foot)-1; } else { success_msg_head = oc_success_msg_head; success_msg_foot = oc_success_msg_foot; success_msg_head_size = sizeof(oc_success_msg_head)-1; success_msg_foot_size = sizeof(oc_success_msg_foot)-1; } base64_encode((char *)ws->cookie, ws->cookie_size, (char *)str_cookie, str_cookie_size); /* reply */ oclog(ws, LOG_HTTP_DEBUG, "HTTP sending: 200 OK"); cstp_cork(ws); ret = cstp_printf(ws, "HTTP/1.%u 200 OK\r\n", http_ver); if (ret < 0) return -1; ret = cstp_puts(ws, "Connection: Keep-Alive\r\n"); if (ret < 0) return -1; if (ws->selected_auth->type & AUTH_TYPE_GSSAPI && imsg != NULL && imsg[0] != 0) { ret = cstp_printf(ws, "WWW-Authenticate: Negotiate %s\r\n", imsg); if (ret < 0) return -1; } ret = cstp_puts(ws, "Content-Type: text/xml\r\n"); if (ret < 0) return -1; if (ws->config->banner) { size = snprintf(msg, sizeof(msg), "<banner>%s</banner>", ws->config->banner); if (size <= 0) return -1; /* snprintf() returns not a very useful value, so we need to recalculate */ size = strlen(msg); } else { msg[0] = 0; size = 0; } size += success_msg_head_size + success_msg_foot_size; ret = cstp_printf(ws, "Content-Length: %u\r\n", (unsigned)size); if (ret < 0) return -1; ret = cstp_puts(ws, "X-Transcend-Version: 1\r\n"); if (ret < 0) return -1; ret = cstp_printf(ws, "Set-Cookie: webvpn=%s; Secure\r\n", str_cookie); if (ret < 0) return -1; #ifdef ANYCONNECT_CLIENT_COMPAT ret = cstp_puts(ws, "Set-Cookie: webvpnc=; expires=Thu, 01 Jan 1970 22:00:00 GMT; path=/; Secure\r\n"); if (ret < 0) return -1; if (ws->config->xml_config_file) { ret = cstp_printf(ws, "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\r\n", ws->config->cert_hash, ws->config->xml_config_file, ws->config->xml_config_hash); } else { ret = cstp_printf(ws, "Set-Cookie: webvpnc=bu:/&p:t&iu:1/&sh:%s; path=/; Secure\r\n", ws->config->cert_hash); } if (ret < 0) return -1; #endif ret = cstp_printf(ws, "\r\n%s%s%s", success_msg_head, msg, success_msg_foot); if (ret < 0) return -1; ret = cstp_uncork(ws); if (ret < 0) return -1; return 0; }
int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg) { int ret; char context[BASE64_LENGTH(SID_SIZE) + 1]; unsigned int i, j; str_st str; const char *login_msg_start; const char *login_msg_end; if (ws->req.user_agent_type == AGENT_OPENCONNECT_V3) { login_msg_start = OCV3_LOGIN_MSG_START; login_msg_end = ocv3_login_msg_end; } else { login_msg_start = OC_LOGIN_MSG_START; login_msg_end = oc_login_msg_end; } if (ws->selected_auth->type & AUTH_TYPE_GSSAPI && ws->auth_state < S_AUTH_COOKIE) { if (ws->req.authorization == NULL || ws->req.authorization_size == 0) return basic_auth_handler(ws, http_ver, NULL); else return post_auth_handler(ws, http_ver); } str_init(&str, ws); oclog(ws, LOG_HTTP_DEBUG, "HTTP sending: 200 OK"); cstp_cork(ws); ret = cstp_printf(ws, "HTTP/1.%u 200 OK\r\n", http_ver); if (ret < 0) return -1; if (ws->sid_set != 0) { base64_encode((char *)ws->sid, sizeof(ws->sid), (char *)context, sizeof(context)); ret = cstp_printf(ws, "Set-Cookie: webvpncontext=%s; Max-Age=%u; Secure\r\n", context, (unsigned)ws->config->cookie_timeout); if (ret < 0) return -1; oclog(ws, LOG_DEBUG, "sent sid: %s", context); } else { ret = cstp_puts(ws, "Set-Cookie: webvpncontext=; expires=Thu, 01 Jan 1970 22:00:00 GMT; path=/; Secure\r\n"); if (ret < 0) return -1; } ret = cstp_puts(ws, "Content-Type: text/xml\r\n"); if (ret < 0) { ret = -1; goto cleanup; } if (ws->auth_state == S_AUTH_REQ) { /* only ask password */ if (pmsg == NULL) pmsg = "Please enter your password"; ret = str_append_printf(&str, login_msg_start, pmsg); if (ret < 0) { ret = -1; goto cleanup; } ret = str_append_str(&str, login_msg_password); if (ret < 0) { ret = -1; goto cleanup; } ret = str_append_str(&str, login_msg_end); if (ret < 0) { ret = -1; goto cleanup; } } else { if (pmsg == NULL) pmsg = "Please enter your username"; /* ask for username and groups */ ret = str_append_printf(&str, login_msg_start, pmsg); if (ret < 0) { ret = -1; goto cleanup; } if (ws->selected_auth->type & AUTH_TYPE_USERNAME_PASS) { ret = str_append_str(&str, login_msg_user); if (ret < 0) { ret = -1; goto cleanup; } } if (ws->selected_auth->type & AUTH_TYPE_CERTIFICATE && ws->cert_auth_ok != 0) { ret = get_cert_info(ws); if (ret < 0) { ret = -1; oclog(ws, LOG_WARNING, "cannot obtain certificate information"); goto cleanup; } } /* send groups */ if (ws->config->group_list_size > 0 || ws->cert_groups_size > 0) { ret = str_append_str(&str, "<select name=\"group_list\" label=\"GROUP:\">\n"); if (ret < 0) { ret = -1; goto cleanup; } /* Several anyconnect clients (and openconnect) submit the group name * separately in that form. In that case they expect that we re-order * the list and we place the group they selected first. WTF! No respect * to server time. */ if (ws->groupname[0] != 0) { ret = append_group_str(ws, &str, ws->groupname); if (ret < 0) { ret = -1; goto cleanup; } } if (ws->config->default_select_group) { ret = str_append_printf(&str, "<option>%s</option>\n", ws->config->default_select_group); if (ret < 0) { ret = -1; goto cleanup; } } /* append any groups available in the certificate */ if (ws->selected_auth->type & AUTH_TYPE_CERTIFICATE && ws->cert_auth_ok != 0) { unsigned dup; for (i=0;i<ws->cert_groups_size;i++) { dup = 0; for (j=0;j<ws->config->group_list_size;j++) { if (strcmp(ws->cert_groups[i], ws->config->group_list[j]) == 0) { dup = 1; break; } } if (dup == 0 && ws->groupname[0] != 0 && strcmp(ws->groupname, ws->cert_groups[i]) == 0) dup = 1; if (dup != 0) continue; ret = str_append_printf(&str, "<option>%s</option>\n", ws->cert_groups[i]); if (ret < 0) { ret = -1; goto cleanup; } } } for (i=0;i<ws->config->group_list_size;i++) { if (ws->groupname[0] != 0 && strcmp(ws->groupname, ws->config->group_list[i]) == 0) continue; ret = append_group_idx(ws, &str, i); if (ret < 0) { ret = -1; goto cleanup; } } ret = str_append_str(&str, "</select>\n"); if (ret < 0) { ret = -1; goto cleanup; } } ret = str_append_str(&str, login_msg_end); if (ret < 0) { ret = -1; goto cleanup; } } ret = cstp_printf(ws, "Content-Length: %u\r\n", (unsigned int)str.length); if (ret < 0) { ret = -1; goto cleanup; } ret = cstp_puts(ws, "X-Transcend-Version: 1\r\n"); if (ret < 0) { ret = -1; goto cleanup; } ret = cstp_puts(ws, "\r\n"); if (ret < 0) { ret = -1; goto cleanup; } ret = cstp_send(ws, str.data, str.length); if (ret < 0) { ret = -1; goto cleanup; } ret = cstp_uncork(ws); if (ret < 0) { ret = -1; goto cleanup; } ret = 0; cleanup: str_clear(&str); return ret; }
int post_auth_handler(worker_st * ws, unsigned http_ver) { int ret = -1, sd = -1; struct http_req_st *req = &ws->req; const char *reason = "Authentication failed"; char *username = NULL; char *password = NULL; char *groupname = NULL; char *msg = NULL; unsigned def_group = 0; if (req->body_length > 0) { oclog(ws, LOG_HTTP_DEBUG, "POST body: '%.*s'", (int)req->body_length, req->body); } if (ws->sid_set && ws->auth_state == S_AUTH_INACTIVE) ws->auth_state = S_AUTH_INIT; if (ws->auth_state == S_AUTH_INACTIVE) { SecAuthInitMsg ireq = SEC_AUTH_INIT_MSG__INIT; ret = parse_reply(ws, req->body, req->body_length, GROUPNAME_FIELD, sizeof(GROUPNAME_FIELD)-1, GROUPNAME_FIELD_XML, sizeof(GROUPNAME_FIELD_XML)-1, &groupname); if (ret < 0) { ret = parse_reply(ws, req->body, req->body_length, GROUPNAME_FIELD2, sizeof(GROUPNAME_FIELD2)-1, GROUPNAME_FIELD_XML, sizeof(GROUPNAME_FIELD_XML)-1, &groupname); } if (ret < 0) { oclog(ws, LOG_HTTP_DEBUG, "failed reading groupname"); } else { if (ws->config->default_select_group != NULL && strcmp(groupname, ws->config->default_select_group) == 0) { def_group = 1; } else { strlcpy(ws->groupname, groupname, sizeof(ws->groupname)); ireq.group_name = ws->groupname; } } talloc_free(groupname); if (ws->selected_auth->type & AUTH_TYPE_GSSAPI) { if (req->authorization == NULL || req->authorization_size == 0) return basic_auth_handler(ws, http_ver, NULL); if (req->authorization_size > 10) { ireq.user_name = req->authorization + 10; ireq.auth_type |= AUTH_TYPE_GSSAPI; } else { oclog(ws, LOG_HTTP_DEBUG, "Invalid authorization data: %.*s", req->authorization_size, req->authorization); goto auth_fail; } } if (ws->selected_auth->type & AUTH_TYPE_USERNAME_PASS) { ret = parse_reply(ws, req->body, req->body_length, USERNAME_FIELD, sizeof(USERNAME_FIELD)-1, NULL, 0, &username); if (ret < 0) { oclog(ws, LOG_HTTP_DEBUG, "failed reading username"); goto ask_auth; } strlcpy(ws->username, username, sizeof(ws->username)); talloc_free(username); ireq.user_name = ws->username; ireq.auth_type |= AUTH_TYPE_USERNAME_PASS; } if (ws->selected_auth->type & AUTH_TYPE_CERTIFICATE) { if (ws->cert_auth_ok == 0) { reason = MSG_NO_CERT_ERROR; oclog(ws, LOG_INFO, "no certificate provided for authentication"); goto auth_fail; } else { ret = get_cert_info(ws); if (ret < 0) { reason = MSG_CERT_READ_ERROR; oclog(ws, LOG_ERR, "failed reading certificate info"); goto auth_fail; } } if (def_group == 0 && ws->cert_groups_size > 0 && ws->groupname[0] == 0) { oclog(ws, LOG_HTTP_DEBUG, "user has not selected a group"); return get_auth_handler2(ws, http_ver, "Please select your group"); } ireq.tls_auth_ok = ws->cert_auth_ok; ireq.cert_user_name = ws->cert_username; ireq.cert_group_names = ws->cert_groups; ireq.n_cert_group_names = ws->cert_groups_size; ireq.auth_type |= AUTH_TYPE_CERTIFICATE; } ireq.hostname = req->hostname; ireq.ip = ws->remote_ip_str; sd = connect_to_secmod(ws); if (sd == -1) { reason = MSG_INTERNAL_ERROR; oclog(ws, LOG_ERR, "failed connecting to sec mod"); goto auth_fail; } ret = send_msg_to_secmod(ws, sd, SM_CMD_AUTH_INIT, &ireq, (pack_size_func) sec_auth_init_msg__get_packed_size, (pack_func) sec_auth_init_msg__pack); if (ret < 0) { reason = MSG_INTERNAL_ERROR; oclog(ws, LOG_ERR, "failed sending auth init message to sec mod"); goto auth_fail; } ws->auth_state = S_AUTH_INIT; } else if (ws->auth_state == S_AUTH_INIT || ws->auth_state == S_AUTH_REQ) { SecAuthContMsg areq = SEC_AUTH_CONT_MSG__INIT; areq.ip = ws->remote_ip_str; if (ws->selected_auth->type & AUTH_TYPE_GSSAPI) { if (req->authorization == NULL || req->authorization_size <= 10) { if (req->authorization != NULL) oclog(ws, LOG_HTTP_DEBUG, "Invalid authorization data: %.*s", req->authorization_size, req->authorization); goto auth_fail; } areq.password = req->authorization + 10; } if (areq.password == NULL && ws->selected_auth->type & AUTH_TYPE_USERNAME_PASS) { ret = parse_reply(ws, req->body, req->body_length, PASSWORD_FIELD, sizeof(PASSWORD_FIELD)-1, NULL, 0, &password); if (ret < 0) { reason = MSG_NO_PASSWORD_ERROR; oclog(ws, LOG_ERR, "failed reading password"); goto auth_fail; } areq.password = password; } if (areq.password != NULL) { if (ws->sid_set != 0) { areq.sid.data = ws->sid; areq.sid.len = sizeof(ws->sid); } sd = connect_to_secmod(ws); if (sd == -1) { reason = MSG_INTERNAL_ERROR; oclog(ws, LOG_ERR, "failed connecting to sec mod"); goto auth_fail; } ret = send_msg_to_secmod(ws, sd, SM_CMD_AUTH_CONT, &areq, (pack_size_func) sec_auth_cont_msg__get_packed_size, (pack_func) sec_auth_cont_msg__pack); talloc_free(password); if (ret < 0) { reason = MSG_INTERNAL_ERROR; oclog(ws, LOG_ERR, "failed sending auth req message to main"); goto auth_fail; } ws->auth_state = S_AUTH_REQ; } else goto auth_fail; } else { oclog(ws, LOG_ERR, "unexpected POST request in auth state %u", (unsigned)ws->auth_state); goto auth_fail; } ret = recv_auth_reply(ws, sd, &msg); if (sd != -1) { close(sd); sd = -1; } if (ret == ERR_AUTH_CONTINUE) { oclog(ws, LOG_DEBUG, "continuing authentication for '%s'", ws->username); ws->auth_state = S_AUTH_REQ; if (ws->selected_auth->type & AUTH_TYPE_GSSAPI) { ret = basic_auth_handler(ws, http_ver, msg); } else { ret = get_auth_handler2(ws, http_ver, msg); } goto cleanup; } else if (ret < 0) { if (ws->selected_auth->type & AUTH_TYPE_GSSAPI) { /* Fallback from GSSAPI to USERNAME-PASSWORD */ ws_disable_auth(ws, AUTH_TYPE_GSSAPI); oclog(ws, LOG_ERR, "failed gssapi authentication"); if (ws_switch_auth_to(ws, AUTH_TYPE_USERNAME_PASS) == 0) goto auth_fail; ws->auth_state = S_AUTH_INACTIVE; ws->sid_set = 0; goto ask_auth; } else { oclog(ws, LOG_ERR, "failed authentication for '%s'", ws->username); goto auth_fail; } } oclog(ws, LOG_HTTP_DEBUG, "user '%s' obtained cookie", ws->username); ws->auth_state = S_AUTH_COOKIE; ret = post_common_handler(ws, http_ver, msg); goto cleanup; ask_auth: return get_auth_handler(ws, http_ver); auth_fail: if (sd != -1) close(sd); oclog(ws, LOG_HTTP_DEBUG, "HTTP sending: 401 Unauthorized"); cstp_printf(ws, "HTTP/1.%d 401 Unauthorized\r\nContent-Length: 0\r\nX-Reason: %s\r\n\r\n", http_ver, reason); cstp_fatal_close(ws, GNUTLS_A_ACCESS_DENIED); talloc_free(msg); exit_worker(ws); cleanup: talloc_free(msg); return ret; }