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; }
cstp_printf(worker_st *ws, const char *fmt, ...) { char *buf; va_list args; int ret, s; va_start(args, fmt); s = vasprintf(&buf, fmt, args); va_end(args); if (s == -1) return -1; ret = cstp_send(ws, buf, s); free(buf); return ret; }
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; }
ssize_t cstp_send_file(worker_st *ws, const char *file) { FILE* fp; char buf[512]; ssize_t len, total = 0; int ret; fp = fopen(file, "r"); if (fp == NULL) return GNUTLS_E_FILE_ERROR; while ( (len = fread( buf, 1, sizeof(buf), fp)) > 0) { ret = cstp_send(ws, buf, len); FATAL_ERR(ws, ret); total += ret; } fclose(fp); return total; }
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 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; }