int srv_check_authtoken(const SRV_LISTENER_CFG_T *pListenCfg, const HTTP_REQ_T *pReq, int allowcomma) { int rc = 0; const char *parg = NULL; char buf[KEYVAL_MAXLEN]; const char *p; if(pListenCfg->pAuthTokenId && pListenCfg->pAuthTokenId[0] != '\0') { if(!((parg = conf_find_keyval(pReq->uriPairs, VSX_URI_TOKEN_QUERY_PARAM)))) { rc = -1; } else if(allowcomma && (p = strchr(parg, ','))) { memset(buf, 0, sizeof(buf)); strncpy(buf, parg, MIN(sizeof(buf), p - parg)); parg = buf; } if(rc >= 0 && strcmp(pListenCfg->pAuthTokenId, parg)) { rc = -1; } } if(rc < 0) { LOG(X_WARNING("Missing or invalid HTTP security token for '%s'"), pReq->url); } return rc; }
static int get_ts(HTTPLIVE_CLIENT_T *pClient, const char *puri) { int rc = 0; HTTP_PARSE_CTXT_T hdrCtxt; HTTP_RESP_T httpResp; const char *p = NULL; unsigned char *pdata; unsigned int contentLen = 0; char fulluri[256]; unsigned char buf[RTP_JTBUF_PKT_BUFSZ_LOCAL + SOCKET_LIST_PREBUF_SZ]; //LOG(X_DEBUG("Retrieving TS chunk '%s'"), puri); if(pClient->uriprefix[0] != '\0') { snprintf(fulluri, sizeof(fulluri), "%s%s", pClient->uriprefix, puri); puri = fulluri; } memset(&hdrCtxt, 0, sizeof(hdrCtxt)); memset(&httpResp, 0, sizeof(httpResp)); hdrCtxt.pnetsock = &pClient->netsock; hdrCtxt.pbuf = (char *) buf; hdrCtxt.szbuf = sizeof(buf); hdrCtxt.tmtms = 0; if((httpcli_gethdrs(&hdrCtxt, &httpResp, &pClient->sa, puri, http_getConnTypeStr(HTTP_CONN_TYPE_KEEPALIVE), 0, 0, pClient->hostbuf, NULL)) < 0) { return -1; } if(!(p = conf_find_keyval(httpResp.hdrPairs, HTTP_HDR_CONTENT_TYPE))) { LOG(X_ERROR("No "HTTP_HDR_CONTENT_TYPE" found in response")); return -1; } else if(!(strncasecmp(p, CONTENT_TYPE_MP2TS, strlen(CONTENT_TYPE_MP2TS)) && strncasecmp(p, CONTENT_TYPE_OCTET_STREAM, strlen(CONTENT_TYPE_OCTET_STREAM)))) { LOG(X_ERROR("Unsupported %s: %s received in response for %s"), HTTP_HDR_CONTENT_TYPE, (p ? p : "<Not Found>"), puri); rc = -1; } if(!(pdata = http_get_contentlen_start(&httpResp, &hdrCtxt, buf, sizeof(buf), 0, &contentLen))) { rc = -1; } //fprintf(stderr, "TS contentlen:%d pdata:0x%x idxb:%d hdrslen:%d\n", contentLen, pdata, hdrCtxt.idxbuf, hdrCtxt.hdrslen); if(rc >= 0 && pClient->pCfg->running == 0) { rc = http_recvloop(pClient->pCfg, &pClient->netsock, &pClient->sa, pClient->pStreamsOut, pClient->pStream, hdrCtxt.hdrslen, hdrCtxt.idxbuf - hdrCtxt.hdrslen, contentLen, buf, sizeof(buf)); } //fprintf(stderr, "TS DONE w rc:%d\n", rc); return rc; }
unsigned char *http_get_contentlen_start(HTTP_RESP_T *pHttpResp, HTTP_PARSE_CTXT_T *pHdrCtxt, unsigned char *pbuf, unsigned int szbuf, int verifybufsz, unsigned int *pcontentLen) { const char *p; int contentLen = 0; unsigned int consumed = 0; unsigned char *pdata = NULL; if((p = conf_find_keyval(pHttpResp->hdrPairs, HTTP_HDR_CONTENT_LEN))) { contentLen = atoi(p); } if(contentLen <= 0) { LOG(X_ERROR("%s not found in response"), HTTP_HDR_CONTENT_LEN); } else if(verifybufsz && (unsigned int) contentLen >= szbuf) { LOG(X_ERROR("Input buffer size too small %d / %d"), szbuf, contentLen); } else if(pHdrCtxt->idxbuf > pHdrCtxt->hdrslen) { if((consumed = pHdrCtxt->idxbuf - pHdrCtxt->hdrslen) < szbuf) { if((char *) pbuf != pHdrCtxt->pbuf) { memcpy(pbuf, &pHdrCtxt->pbuf[pHdrCtxt->hdrslen], consumed); pdata = pbuf; } else { pdata = &pbuf[pHdrCtxt->hdrslen]; } } else { LOG(X_ERROR("Input buffer size too small %d / %d"), szbuf, contentLen); } } else if(pHdrCtxt->idxbuf == pHdrCtxt->hdrslen) { pdata = pbuf; } if(pdata && pcontentLen) { *pcontentLen = contentLen; } return pdata; }
int rtmp_auth_parse_req(const char *url, RTMP_AUTH_PARSE_CTXT_T *pParseCtxt) { int rc = 0; const char *p = NULL; if(!url|| !pParseCtxt) { return -1; } if(!(p = strchr(url, '?'))) { return rc; } p++; rc = strutil_parse_delimeted_str(cbparse_authmod_descr_params, &pParseCtxt->authList, p, '&'); if((p = conf_find_keyval(&pParseCtxt->authList.list[0], "authmod"))) { strncpy(pParseCtxt->authmodStr, p, sizeof(pParseCtxt->authmodStr) - 1); } return rc; }
int srv_ctrl_pip(CLIENT_CONN_T *pConn) { int rc = 0; int rcTmp; enum HTTP_STATUS statusCode = HTTP_STATUS_OK; const char *parg; PIP_CFG_T pipCfg; IXCODE_VIDEO_CROP_T crop; IXCODE_PIP_MOTION_T *pipMotion = NULL; int idx = 0; int pip_id = 0; int do_stop = 0; int do_start = 0; int do_update = 0; int do_status = 0; int do_crop = 0; STUN_POLICY_T stunPolicy; int activePipIds[MAX_PIPS]; const char *do_pipconf = NULL; unsigned int idxResp; char tmp[128]; char buf[1024]; char respExtra[512]; STREAMER_CFG_T *pCfg = NULL; char *strxcodebuf = NULL; LOG(X_DEBUG("Received PIP command %s%s from %s:%d"), pConn->httpReq.puri, http_req_dump_uri(&pConn->httpReq, buf, sizeof(buf)), FORMAT_NETADDR(pConn->sd.sa, tmp, sizeof(tmp)), htons(INET_PORT(pConn->sd.sa))); buf[0] = '\0'; respExtra[0] = '\0'; if(pConn->pStreamerCfg0 && pConn->pStreamerCfg0->running >= 0) { pCfg = (STREAMER_CFG_T *) pConn->pStreamerCfg0; } else if(pConn->pStreamerCfg1 && pConn->pStreamerCfg1->running >= 0) { pCfg = (STREAMER_CFG_T *) pConn->pStreamerCfg1; } if(pCfg) { memset(&crop, 0, sizeof(crop)); if((parg = conf_find_keyval(pConn->httpReq.uriPairs, PIP_KEY_PAD_TOP))) { crop.padTop = atoi(parg); do_crop = 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, PIP_KEY_PAD_BOTTOM))) { crop.padBottom = atoi(parg); do_crop = 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, PIP_KEY_PAD_LEFT))) { crop.padLeft = atoi(parg); do_crop = 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, PIP_KEY_PAD_RGB))) { strutil_read_rgb(parg, crop.padRGB); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, PIP_KEY_PAD_RIGHT))) { crop.padRight = atoi(parg); do_crop = 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, PIP_KEY_CROP_TOP))) { crop.cropTop = atoi(parg); do_crop = 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, PIP_KEY_CROP_BOTTOM))) { crop.cropBottom = atoi(parg); do_crop = 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, PIP_KEY_CROP_LEFT))) { crop.cropLeft = atoi(parg); do_crop = 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, PIP_KEY_CROP_RIGHT))) { crop.cropRight = atoi(parg); do_crop = 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, PIP_KEY_PAD_ASPECT_RATIO))) { crop.padAspectR = atoi(parg); do_crop = 1; } if(do_crop) { if((rc = xcode_set_crop_pad(&crop, &pCfg->xcode.vid.out[0], crop.padAspectR, pCfg->xcode.vid.out[0].resOutH, pCfg->xcode.vid.out[0].resOutV, 0, 0)) < 0) { LOG(X_ERROR("Invalid picture pad / crop dimensions")); } else { //TODO: updating these params does not work via xcode ipc //TODO: this should be atomic w/ respect to xcoder memcpy(&pCfg->xcode.vid.out[0].crop, &crop, sizeof(pCfg->xcode.vid.out[0].crop)); } } memset(&pipCfg, 0, sizeof(pipCfg)); pipCfg.rtpPktzMode = -1; pipCfg.dtls_handshake_server = -1; if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipstatus"))) { do_status = 1; pip_id = atoi(parg); } else if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipstop"))) { do_stop = 1; pip_id = atoi(parg); } else if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipstart"))) { if(atoi(parg) > 0) { do_start = 1; } } else if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipupdate"))) { // start a PIP which was previously started with 'delaystart' parameter if((pip_id = atoi(parg)) > 0) { do_update = 1; } } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipconf"))) { do_pipconf = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipxcode")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "xcode"))) { pipCfg.strxcode = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pip")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "in")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "input"))) { pipCfg.input = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "out")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "output"))) { pipCfg.output = parg; //pipCfg.output="dtlssrtp://127.0.0.1:5000,5008"; //pipCfg.output="srtp://127.0.0.1:5000,5000"; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "tslive"))) { pipCfg.tsliveaddr = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "rtppayloadtype"))) { pipCfg.output_rtpptstr = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "rtpssrc"))) { pipCfg.output_rtpssrcsstr = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "mtu"))) { pipCfg.mtu = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "rtppktzmode"))) { pipCfg.rtpPktzMode = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "rtcpports"))) { pipCfg.rtcpPorts = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "srtpkey"))) { pipCfg.srtpKeysBase64 = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "dtls"))) { pipCfg.use_dtls = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "dtlssrtp"))) { pipCfg.use_dtls = pipCfg.use_srtp = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "dtlsserver"))) { pipCfg.dtls_handshake_server = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "dtlsclient"))) { pipCfg.dtls_handshake_server = !atoi(parg); } //if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "dtlsoutserverkey"))) { // pipCfg.dtls_xmit_serverkey = atoi(parg); // } //if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "dtlsinserverkey")) || // (parg = conf_find_keyval(pConn->httpReq.uriPairs, "dtlsserverkey"))) { // pipCfg.dtls_capture_serverkey = atoi(parg); //} if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "stunrespond"))) { if((stunPolicy = atoi(parg)) != STUN_POLICY_ENABLED) { stunPolicy = STUN_POLICY_NONE; } if((pipCfg.stunBindingResponse = stunPolicy) != STUN_POLICY_NONE) { pipCfg.stunRespUseSDPIceufrag = 1; } } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "stunrequestuser"))) { pipCfg.stunReqUsername = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "stunrequestpass"))) { pipCfg.stunReqPass = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "stunrequestrealm"))) { pipCfg.stunReqRealm = parg; } if(pipCfg.stunBindingRequest == STUN_POLICY_NONE && (pipCfg.stunReqUsername || pipCfg.stunReqPass || pipCfg.stunReqRealm)) { pipCfg.stunBindingRequest = STUN_POLICY_XMIT_IF_RCVD; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "stunrequest"))) { stunPolicy = atoi(parg); pipCfg.stunBindingRequest = stunPolicy; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "turnuser"))) { pipCfg.turnCfg.turnUsername = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "turnpass"))) { pipCfg.turnCfg.turnPass = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "turnrealm"))) { pipCfg.turnCfg.turnRealm = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "turnserver"))) { pipCfg.turnCfg.turnServer = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "turnpeer"))) { pipCfg.turnCfg.turnPeerRelay = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "turnsdp"))) { pipCfg.turnCfg.turnSdpOutPath = parg; } //if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "turnout"))) { // pipCfg.turnCfg.turnOutput = parg; //} else if(pipCfg.turnCfg.turnServer) { // pipCfg.turnCfg.turnOutput = pipCfg.turnCfg.turnServer; //} if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "delaystart"))) { pipCfg.delayed_output = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "abrself"))) { pipCfg.abrSelf = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "abrauto")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "abr"))) { pipCfg.abrAuto = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "piplayout")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "layout"))) { pipCfg.layoutType = pip_str2layout(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipx")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipxleft")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipxright"))) { pipCfg.posx = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipy")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipytop")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipybottom"))) { pipCfg.posy = atoi(parg); } // PIP_KEY_ZORDER "zorder" if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipzorder")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "zorder"))) { pipCfg.zorder = atoi(parg); } // PIP_KEY_NOAUDIO if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipnoaudio")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "noaud")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "noaudio"))) { pipCfg.noaud = 1; } // PIP_KEY_NOVIDEO if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipnovideo")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "novid")) || (parg = conf_find_keyval(pConn->httpReq.uriPairs, "novideo"))) { pipCfg.novid = 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "duplicate"))) { pipCfg.allowDuplicate = 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "startchime"))) { pipCfg.startChimeFile = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "stopchime"))) { pipCfg.stopChimeFile = parg; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "rtpretransmit"))) { pipCfg.nackRtpRetransmitVideo = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "rembxmitmaxrate"))) { pipCfg.apprembRtcpSendVideoMaxRateBps = (unsigned int) strutil_read_numeric(optarg, 0, 1000, 0); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "rembxmitminrate"))) { pipCfg.apprembRtcpSendVideoMinRateBps = (unsigned int) strutil_read_numeric(optarg, 0, 1000, 0); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "rembxmitforce"))) { pipCfg.apprembRtcpSendVideoForceAdjustment = atoi(parg); } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipalphamax"))) { pipCfg.alphamax_min1 = atoi(parg) + 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipalphamin"))) { pipCfg.alphamin_min1 = atoi(parg) + 1; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipbefore"))) { if(atoi(parg) > 0) { pipCfg.flags |= PIP_FLAGS_INSERT_BEFORE_SCALE; } } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipxright"))) { pipCfg.flags |= PIP_FLAGS_POSITION_RIGHT; } if((parg = conf_find_keyval(pConn->httpReq.uriPairs, "pipybottom"))) { pipCfg.flags |= PIP_FLAGS_POSITION_BOTTOM; } // // Read the PIP configuration from a fiel // if(do_pipconf) { pipCfg.cfgfile = do_pipconf; //if((idx = pip_getIndexById(pCfg, pip_id, 1)) >= 0 && idx < MAX_PIPS && pCfg->pStorageBuf) { // strxcodebuf = ((STREAM_STORAGE_T *) pCfg->pStorageBuf)->pipxcodeStrbuf[idx]; if(pCfg->pStorageBuf) { //TODO: if we're all going to use the same buffer (temporarily) we need some locking here... strxcodebuf = ((STREAM_STORAGE_T *) pCfg->pStorageBuf)->pipxcodeStrbuf[0]; } if((pipMotion = pip_read_conf(&pipCfg, pCfg->status.pathFile, strxcodebuf))) { do_start = 1; do_stop = 0; } else { } } if(do_status) { if(pip_id == -1) { if((rc = pip_getActiveIds(pCfg, activePipIds, 1)) > 0) { idxResp = 0; if((rcTmp = snprintf(respExtra, sizeof(respExtra), "&ids=")) > 0) { idxResp += rcTmp; } for(idx = 0; idx < rc; idx++) { if((rcTmp = snprintf(&respExtra[idxResp], sizeof(respExtra) - idxResp, "%s%d", idx > 0 ? "," : "", activePipIds[idx])) > 0) { idxResp += rcTmp; } } } } else if((idx = pip_getIndexById(pCfg, pip_id, 1)) >= 0) { rc = pip_id; } else { rc = -1; } } else if(do_update) { if((idx = pip_getIndexById(pCfg, pip_id, 1)) >= 0) { rc = pip_update(&pipCfg, pCfg, pip_id); } else { do_update = 0; } } else if(do_stop) { if((rc = pip_stop(pCfg, pip_id)) < 0) { LOG(X_ERROR("Failed to stop PIP[%d]"), pip_id); } } else if(do_start && rc >= 0) { rc = pip_start(&pipCfg, pCfg, pipMotion); } // // The html body response // snprintf(buf, sizeof(buf), "code=%d%s", rc, respExtra[0] != '\0' ? respExtra : ""); } else { rc = -1; } if(rc < 0) { statusCode = HTTP_STATUS_SERVERERROR; } rc = http_resp_send(&pConn->sd, &pConn->httpReq, statusCode, (unsigned char *) buf, strlen(buf)); LOG(X_DEBUG("Sent PIP response '%s' to %s:%d"), buf, FORMAT_NETADDR(pConn->sd.sa, tmp, sizeof(tmp)), htons(INET_PORT(pConn->sd.sa))); return rc; }
//TODO: move this to http files int http_getpage(const char *addr, uint16_t port, const char *uri, char *buf, unsigned int szbuf, unsigned int tmtms) { int rc = 0; NETIO_SOCK_T netsock; struct sockaddr_in sa; HTTP_PARSE_CTXT_T hdrCtxt; HTTP_RESP_T httpResp; unsigned int contentLen = 0; const char *p; unsigned int consumed = 0; struct timeval tv0, tv1; char hdr[1024]; if(!addr || !buf || szbuf <= 0) { return -1; } if(!uri) { uri = "/"; } memset(&netsock, 0, sizeof(netsock)); if((NETIOSOCK_FD(netsock) = net_opensocket(SOCK_STREAM, 0, 0, NULL)) == INVALID_SOCKET) { return -1; } memset(&sa, 0, sizeof(sa)); sa.sin_addr.s_addr = inet_addr(addr); sa.sin_port = htons(port); if((rc = net_connect(NETIOSOCK_FD(netsock), &sa)) != 0) { return rc; } gettimeofday(&tv0, NULL); memset(&hdrCtxt, 0, sizeof(hdrCtxt)); memset(&httpResp, 0, sizeof(httpResp)); hdrCtxt.pnetsock = &netsock; hdrCtxt.pbuf = hdr; hdrCtxt.szbuf = sizeof(hdr); hdrCtxt.tmtms = tmtms; VSX_DEBUG_MGR(LOG(X_DEBUG("MGR - Sending local status command: '%s' to: %d"), uri, htons(sa.sin_port))); if((httpcli_gethdrs(&hdrCtxt, &httpResp, &sa, uri, NULL, 0, 0, NULL, NULL)) < 0) { return -1; } if(rc >= 0 && (p = conf_find_keyval(httpResp.hdrPairs, HTTP_HDR_CONTENT_LEN))) { contentLen = atoi(p); } if(rc >= 0) { if(contentLen <= 0) { LOG(X_ERROR("Content-Length not found in response")); rc = -1; } else if(contentLen > szbuf) { LOG(X_ERROR("Input buffer size too small %d / %d"), szbuf, contentLen); rc = -1; } else if(hdrCtxt.idxbuf > hdrCtxt.hdrslen) { if((consumed = hdrCtxt.idxbuf - hdrCtxt.hdrslen) < szbuf) { memcpy(buf, &hdr[hdrCtxt.hdrslen], consumed); } else { LOG(X_ERROR("Input buffer size too small %d / %d"), szbuf, contentLen); rc = -1; } } } if(rc >= 0 && net_setsocknonblock(NETIOSOCK_FD(netsock), 1) < 0) { rc = -1; } //fprintf(stderr, "GET PAGE OK idx:%d hdrs:%d conentlen:%d\n", hdrCtxt.idxbuf, hdrCtxt.hdrslen, contentLen); while(rc >= 0 && consumed < contentLen) { if((rc = netio_recvnb(&netsock, (unsigned char *) &buf[consumed], contentLen - consumed, 500)) > 0) { consumed += rc; } gettimeofday(&tv1, NULL); if(tmtms > 0 && consumed < contentLen && TIME_TV_DIFF_MS(tv1, tv0) > tmtms) { LOG(X_WARNING("HTTP %s:%d%s timeout %d ms exceeded"), net_inet_ntoa(sa.sin_addr, hdr), ntohs(sa.sin_port), uri, tmtms); break; rc = -1; } } if(contentLen > 0 && consumed >= contentLen) { rc = consumed; } else { rc = -1; } netio_closesocket(&netsock); return rc; }
int srvauth_authenticate(const AUTH_CREDENTIALS_STORE_T *pAuthStore, const HTTP_REQ_T *pReq, const char *nonce_srv, const char *opaque_srv, const char *realm_srv, char *bufAuthHdr, unsigned int bufOutSz) { int rc = 0; int ok_auth = 0; int do_basic = 0; char bufAuth[1024]; char tmpH1[KEYVAL_MAXLEN]; char tmpH2[KEYVAL_MAXLEN]; char tmpDigest[KEYVAL_MAXLEN]; char tmps[6][KEYVAL_MAXLEN]; char bufnonce[AUTH_NONCE_MAXLEN]; const char *pAuthHdr = NULL; const char *enc = NULL; const char *realm = NULL; const char *uri_cli = NULL; const char *qop_cli = NULL; const char *nc_cli = NULL; const char *cnonce_cli = NULL; const char *nonce_cli = NULL; const char *resp_cli = NULL; AUTH_LIST_T authList; AUTH_CREDENTIALS_STORE_T authStore; if(!pAuthStore || !pReq) { return -1; } if(!IS_AUTH_CREDENTIALS_SET(pAuthStore)) { // // No username and password has been set // return 0; } if(!(realm = realm_srv)) { realm = pAuthStore->realm; } if(!realm || realm[0] == '\0') { realm = VSX_BINARY; } if(pAuthStore->authtype == HTTP_AUTH_TYPE_FORCE_BASIC) { do_basic = 1; } if(ok_auth >= 0 && !(pAuthHdr = conf_find_keyval((const KEYVAL_PAIR_T *) &pReq->reqPairs, HTTP_HDR_AUTHORIZATION))) { LOG(X_WARNING("Client request doest not include "HTTP_HDR_AUTHORIZATION" header for %s %s"), pReq->method, pReq->url); ok_auth = -1; } if(ok_auth >= 0) { enc = pAuthHdr; MOVE_WHILE_SPACE(enc); if(!strncasecmp(AUTH_STR_BASIC, enc, strlen(AUTH_STR_BASIC))) { enc += strlen(AUTH_STR_BASIC); MOVE_WHILE_SPACE(enc); if(pAuthStore->authtype == HTTP_AUTH_TYPE_ALLOW_BASIC || pAuthStore->authtype == HTTP_AUTH_TYPE_FORCE_BASIC) { do_basic = 1; } else { LOG(X_WARNING("Client wants disabled Basic authentication for %s %s"), pReq->method, pReq->url); ok_auth = -1; } } else if(!strncasecmp(AUTH_STR_DIGEST, enc, strlen(AUTH_STR_DIGEST))) { enc += strlen(AUTH_STR_DIGEST); MOVE_WHILE_SPACE(enc); } else { LOG(X_WARNING("Client request contains unsupported "HTTP_HDR_AUTHORIZATION " header type '%s' for %s %s"), pAuthHdr, pReq->method, pReq->url); ok_auth = -1; } } if(ok_auth >= 0 && do_basic) { // // Basic Auth // memset(&authStore, 0, sizeof(authStore)); // // Parse the header Authorization: Basic <Base64(username:password)> // if(ok_auth >= 0 && auth_basic_decode(enc, authStore.username, sizeof(authStore.username), authStore.pass, sizeof(authStore.pass)) < 0) { LOG(X_WARNING("Client "HTTP_HDR_AUTHORIZATION" Basic Auth decode failed for '%s' for %s %s"), enc, pReq->method, pReq->url); ok_auth = -1; } // // Verify the username and password // if(ok_auth >= 0) { if(((pAuthStore->username[0] != '\0' && !strcmp(pAuthStore->username, authStore.username)) && (pAuthStore->pass[0] != '\0' && !strcmp(pAuthStore->pass, authStore.pass)))) { ok_auth = 1; } else { LOG(X_WARNING("Client "HTTP_HDR_AUTHORIZATION" incorrect Basic auth credentials for " "'%s' for %s %s username: %s"), pAuthHdr, pReq->method, pReq->url, pAuthStore->username); ok_auth = -1; } } } else if(ok_auth >= 0) { // // Parse the Digest Authorization header // if(ok_auth >= 0 && auth_digest_parse(enc, &authList) < 0) { LOG(X_WARNING("Failed to parse client "HTTP_HDR_AUTHORIZATION" '%s' for %s %s"), pAuthHdr, pReq->method, pReq->url); ok_auth = -1; } else if(ok_auth >= 0) { uri_cli = avc_dequote(conf_find_keyval(&authList.list[0], "uri"), tmps[0], sizeof(tmps[0])); qop_cli = avc_dequote(conf_find_keyval(&authList.list[0], "qop"), tmps[1], sizeof(tmps[1])); nc_cli = avc_dequote(conf_find_keyval(&authList.list[0], "nc"), tmps[2], sizeof(tmps[2])); cnonce_cli = avc_dequote(conf_find_keyval(&authList.list[0], "cnonce"), tmps[3], sizeof(tmps[3])); nonce_cli = avc_dequote(conf_find_keyval(&authList.list[0], "nonce"), tmps[4], sizeof(tmps[4])); resp_cli = avc_dequote(conf_find_keyval(&authList.list[0], "response"), tmps[5], sizeof(tmps[5])); // // If nonce_srv is supplied, we try to do nonce validation // (prior generated nonce should not be stored per-connection but globally with matching // client IP and creation time // if(ok_auth >= 0 && (!nonce_cli || (nonce_srv && strcmp(nonce_cli, nonce_srv)))) { LOG(X_WARNING("Invalid nonce from client: '%s', expected: '%s' for %s %s"), nonce_cli, nonce_srv, pReq->method, pReq->url); ok_auth = -1; } if(ok_auth >= 0 && (rc = auth_digest_getH1(pAuthStore->username, realm, pAuthStore->pass, tmpH1, sizeof(tmpH1))) < 0) { ok_auth = -1; } if(ok_auth >= 0 && (rc = auth_digest_getH2(pReq->method, uri_cli, tmpH2, sizeof(tmpH2))) < 0) { ok_auth = -1; } if(ok_auth >= 0 && (rc = auth_digest_getDigest(tmpH1, nonce_srv ? nonce_srv : nonce_cli, tmpH2, nc_cli, cnonce_cli, qop_cli, tmpDigest, sizeof(tmpDigest))) < 0) { ok_auth = -1; } if(ok_auth >= 0 && resp_cli && !strcmp(tmpDigest, resp_cli)) { ok_auth = 1; } else { LOG(X_WARNING("Client "HTTP_HDR_AUTHORIZATION" incorrect Digest auth credentials for '%s' " "for %s %s username: %s"), pAuthHdr, pReq->method, pReq->url, pAuthStore->username); ok_auth = -1; } } } if(ok_auth > 0) { LOG(X_DEBUG("Succesful %s authentication for %s %s username: %s"), do_basic ? "Basic" : "Digest", pReq->method, pReq->url, pAuthStore->username); } else if(ok_auth <= 0 && bufAuthHdr && bufOutSz > 0) { if(do_basic == 1) { // // Basic Auth unauthorized resposne // if((rc = snprintf(bufAuthHdr, bufOutSz, "%s: %s realm=\"%s\"\r\n", HTTP_HDR_WWW_AUTHENTICATE, AUTH_STR_BASIC, realm)) < 0) { return -1; } } else { // // Digest Auth RFC 2069 / RFC 2617 unauthorized response // memset(&authList, 0, sizeof(authList)); if(nonce_srv && nonce_srv[0] == '\0') { auth_digest_gethexrandom(16, (char *) nonce_srv, AUTH_NONCE_MAXLEN); } else { auth_digest_gethexrandom(16, (char *) bufnonce, AUTH_NONCE_MAXLEN); } if(opaque_srv && opaque_srv[0] == '\0') { auth_digest_gethexrandom(16, (char *) opaque_srv, AUTH_OPAQUE_MAXLEN); } //auth_digest_additem(&authList, "qop", "auth", 1); auth_digest_additem(&authList, "realm", realm, 1); auth_digest_additem(&authList, "nonce", nonce_srv ? nonce_srv : bufnonce, 1); if(opaque_srv) { auth_digest_additem(&authList, "opaque", opaque_srv, 1); } if((rc = auth_digest_write(&authList, bufAuth, sizeof(bufAuth))) < 0) { return -1; } if((rc = snprintf(bufAuthHdr, bufOutSz, "%s: %s\r\n", HTTP_HDR_WWW_AUTHENTICATE, bufAuth)) < 0) { return -1; } } //if(rtsp_resp_sendhdr(pRtsp->pSd, statusCode, pReq->cseq, // pRtsp->pSession, 0, NULL, bufAuthHdr) < 0) { // rc = -1; //} } return ok_auth > 0 ? 0 : -1; }