char *my_acct(int fd, FILE *fp, char *param, char **pwds) { int i; char *user_name; char *ret; while (param[0] == ' ' || param[0] == '\t') param += 1; if (param[0] != '\n') return (my_rerror(ESYNTAX, 0, fd, fp)); if (!pwds || !pwds[HOME]) return (my_rerror(ENOTTAKEN, 0, fd, fp)); i = strlen(pwds[HOME]) - 2; while (pwds[HOME][i] != '/') i -= 1; if (!(user_name = strdup(pwds[HOME] + i + 1))) return (alloc_err(0, fd, 0, 0)); if (user_name[strlen(user_name) - 1] == '/') user_name[strlen(user_name) - 1] = '\0'; if (!(ret = malloc(sizeof(*ret) * (strlen(user_name) + 16)))) return (alloc_err(0, fd, 0, 0)); strcpy(ret, "257 "); strcat(ret, user_name); strcat(ret, " created.\r\n"); free(user_name); return (ret); }
char *clear_path(int fd, FILE *fp, char *param, char **pwds) { int i; char *d; if (!(d = strdup(pwds[CURRENT]))) return (alloc_err(fd, fp, 0)); while (!strncmp(param, "..", 2)) { i = strlen(d) - 2; while (i >= 0 && d[i] != '/') i -= 1; d[i] = '\0'; param += 2; if (param[0] == '/' && !strncmp(param + 1, "..", 2)) param += 1; } if (!strcmp(d + strlen(d) - 9, "Anonymous")) strcat(d, "/"); if (param[0] == '/' && param[1] && param[1] != '\n' && param[1] != ' ' && param[1] != '\t') { if (!(d = realloc(d, (strlen(d) + strlen(param) + 1)))) return (alloc_err(fd, fp, 0)); strcat(d, param); } return (d); }
/* Create and send successful response */ static void send_reply_ok(pj_turn_allocation *alloc, const pj_stun_rx_data *rdata) { pj_status_t status; unsigned interval; pj_stun_tx_data *tdata; status = pj_stun_session_create_res(alloc->sess, rdata, 0, NULL, &tdata); if (status != PJ_SUCCESS) { alloc_err(alloc, "Error creating STUN success response", status); return; } /* Calculate time to expiration */ if (alloc->relay.lifetime != 0) { pj_time_val now; pj_gettimeofday(&now); interval = alloc->relay.expiry.sec - now.sec; } else { interval = 0; } /* Add LIFETIME if this is not ChannelBind. */ if (PJ_STUN_GET_METHOD(tdata->msg->hdr.type)!=PJ_STUN_CHANNEL_BIND_METHOD){ pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_LIFETIME, interval); /* Add BANDWIDTH if lifetime is not zero */ if (interval != 0) { pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_BANDWIDTH, alloc->bandwidth); } } status = pj_stun_session_send_msg(alloc->sess, NULL, PJ_TRUE, PJ_FALSE, &alloc->hkey.clt_addr, pj_sockaddr_get_len(&alloc->hkey.clt_addr), tdata); if (status != PJ_SUCCESS) { alloc_err(alloc, "Error sending STUN success response", status); return; } }
char *process_cd(int fd, FILE *fp, char *d, char **pwds) { char *ret; if (chdir(d) == -1) { ret = strdup(ENOTTAKEN); free(d); if (!ret) return (alloc_err(fd, fp, 0)); return (ret); } free(pwds[OLD]); pwds[OLD] = pwds[CURRENT]; pwds[CURRENT] = d; if (!(ret = strdup(CMDOK))) return (alloc_err(fd, fp, 0)); return (ret); }
/******************************************************************************** my_Dyn_alloc() Allocate on the control stack. This is for objects that disappear on backtracking. ******************************************************************************/ dyn_ptr_t my_Dyn_alloc(my_alloc_size_t how_much) /* in bytes */ { dyn_ptr_t ret=NULL; ALIGN(how_much); if(!(CAN_ALLOC(how_much ,HighDyn_ptr, Dyn_ptr))) { alloc_err(DYNSPACE); } else ret = Dyn_ptr; Dyn_ptr += how_much; return(ret); }
/* Create and send error response */ static void send_reply_err(pj_turn_allocation *alloc, const pj_stun_rx_data *rdata, pj_bool_t cache, int code, const char *errmsg) { pj_status_t status; status = pj_stun_session_respond(alloc->sess, rdata, code, errmsg, NULL, cache, &alloc->hkey.clt_addr, pj_sockaddr_get_len(&alloc->hkey.clt_addr.addr)); if (status != PJ_SUCCESS) { alloc_err(alloc, "Error sending STUN error response", status); return; } }
/******************************************************************************* my_Subst_alloc() Allocate how_much bytes on the substitution stack. This is more speed-efficient than allocating struct substs on an array of structures, as there is no multiplication. ******************************************************************************/ subst_ptr_t my_Subst_alloc(my_alloc_size_t how_much) /* in bytes */ { subst_ptr_t ret=NULL; #ifndef NDEBUG if(how_much % sizeof(struct subst))INTERNAL_ERROR("alignment"); #endif if(! CAN_ALLOC(how_much ,HighSubst_ptr, Subst_ptr)) { alloc_err(SUBSTSPACE); } else ret = Subst_ptr; Subst_ptr += how_much; return(ret); }
char *cd_init(int fd, FILE *fp, char *param, char **pwds) { char *ret; if (!pwds || !strcmp(param, "-")) { if (!pwds || !pwds[OLD]) return (my_rerror(EBADSEQ, fd, fp)); ret = pwds[OLD]; pwds[OLD] = NULL; return (ret); } if (!strncmp(param, "..", 2)) return (clear_path(fd, fp, param, pwds)); ret = strdup(param); if (!ret) return (alloc_err(fd, fp, 0)); return (ret); }
char *my_pwd(int fd, FILE *fp, char *param, char **pwds) { char *ret; int size; while (param[0] == ' ' || param[0] == '\t') param += 1; if (param[0] != '\n') return (my_rerror(ESYNTAX, 0, fd, fp)); if (!pwds || !pwds[CURRENT] || !pwds[ROOT]) return (my_rerror(ENOTTAKEN, 0, fd, fp)); size = strlen(pwds[CURRENT]) - strlen(pwds[ROOT]); size += strlen(USER_DIRECTORY) + 16; ret = malloc(sizeof(*ret) * size); if (!ret) return (alloc_err(0, fd, fp, 0)); strcpy(ret, "257 "); strcat(ret, pwds[CURRENT] + strlen(pwds[ROOT]) + strlen(USER_DIRECTORY)); strcat(ret, " created.\r\n"); return (ret); }
char *my_lcd(int fd, FILE *fp, char *param, char **pwds) { char *d; if (!(param = get_path(fd, fp, param)) || !strcmp(param, ESYNTAX) || !strcmp(param, ENOTTAKEN)) return (param); d = cd_init(fd, fp, param, pwds); if (!d || !strcmp(d, EBADSEQ)) return (d); if (d[0] != '/') { param = d; d = malloc(sizeof(*d) * (strlen(param) + strlen(pwds[CURRENT]) + 2)); if (!d) return (alloc_err(fd, fp, 0)); strcpy(d, pwds[CURRENT]); if (strcmp(d + strlen(d) - 10, "Anonymous/")) strcat(d, "/"); strcat(d, param); free(param); } return (process_cd(fd, fp, d, pwds)); }
/* * Handle incoming packet from client. This would have been called by * server upon receiving packet from a listener. */ PJ_DEF(void) pj_turn_allocation_on_rx_client_pkt(pj_turn_allocation *alloc, pj_turn_pkt *pkt) { pj_bool_t is_stun; pj_status_t status; /* Lock this allocation */ pj_lock_acquire(alloc->lock); /* Quickly check if this is STUN message */ is_stun = ((*((pj_uint8_t*)pkt->pkt) & 0xC0) == 0); if (is_stun) { /* * This could be an incoming STUN requests or indications. * Pass this through to the STUN session, which will call * our stun_on_rx_request() or stun_on_rx_indication() * callbacks. * * Note: currently it is necessary to specify the * PJ_STUN_NO_FINGERPRINT_CHECK otherwise the FINGERPRINT * attribute inside STUN Send Indication message will mess up * with fingerprint checking. */ unsigned options = PJ_STUN_CHECK_PACKET | PJ_STUN_NO_FINGERPRINT_CHECK; pj_size_t parsed_len = 0; if (pkt->transport->listener->tp_type == PJ_TURN_TP_UDP) options |= PJ_STUN_IS_DATAGRAM; status = pj_stun_session_on_rx_pkt(alloc->sess, pkt->pkt, pkt->len, options, NULL, &parsed_len, &pkt->src.clt_addr, pkt->src_addr_len); if (pkt->transport->listener->tp_type == PJ_TURN_TP_UDP) { pkt->len = 0; } else if (parsed_len > 0) { if (parsed_len == pkt->len) { pkt->len = 0; } else { pj_memmove(pkt->pkt, pkt->pkt+parsed_len, pkt->len - parsed_len); pkt->len -= parsed_len; } } if (status != PJ_SUCCESS) { alloc_err(alloc, "Error handling STUN packet", status); goto on_return; } } else { /* * This is not a STUN packet, must be ChannelData packet. */ pj_turn_channel_data *cd = (pj_turn_channel_data*)pkt->pkt; pj_turn_permission *perm; pj_ssize_t len; pj_assert(sizeof(*cd)==4); /* For UDP check the packet length */ if (alloc->transport->listener->tp_type == PJ_TURN_TP_UDP) { if (pkt->len < pj_ntohs(cd->length)+sizeof(*cd)) { PJ_LOG(4,(alloc->obj_name, "ChannelData from %s discarded: UDP size error", alloc->info)); goto on_return; } } else { pj_assert(!"Unsupported transport"); goto on_return; } perm = lookup_permission_by_chnum(alloc, pj_ntohs(cd->ch_number)); if (!perm) { /* Discard */ PJ_LOG(4,(alloc->obj_name, "ChannelData from %s discarded: ch#0x%x not found", alloc->info, pj_ntohs(cd->ch_number))); goto on_return; } /* Relay the data */ len = pj_ntohs(cd->length); pj_sock_sendto(alloc->relay.tp.sock, cd+1, &len, 0, &perm->hkey.peer_addr, pj_sockaddr_get_len(&perm->hkey.peer_addr)); /* Refresh permission */ refresh_permission(perm); } on_return: /* Release lock */ pj_lock_release(alloc->lock); }
/* * Handle incoming packet from peer. This function is called by * on_rx_from_peer(). */ static void handle_peer_pkt(pj_turn_allocation *alloc, pj_turn_relay_res *rel, char *pkt, pj_size_t len, const pj_sockaddr *src_addr) { pj_turn_permission *perm; /* Lookup permission */ perm = lookup_permission_by_addr(alloc, src_addr, pj_sockaddr_get_len(src_addr)); if (perm == NULL) { /* No permission, discard data */ return; } /* Send Data Indication or ChannelData, depends on whether * this permission is attached to a channel number. */ if (perm->channel != PJ_TURN_INVALID_CHANNEL) { /* Send ChannelData */ pj_turn_channel_data *cd = (pj_turn_channel_data*)rel->tp.tx_pkt; if (len > PJ_TURN_MAX_PKT_LEN) { char peer_addr[80]; pj_sockaddr_print(src_addr, peer_addr, sizeof(peer_addr), 3); PJ_LOG(4,(alloc->obj_name, "Client %s: discarded data from %s " "because it's too long (%d bytes)", alloc->info, peer_addr, len)); return; } /* Init header */ cd->ch_number = pj_htons(perm->channel); cd->length = pj_htons((pj_uint16_t)len); /* Copy data */ pj_memcpy(rel->tp.tx_pkt+sizeof(pj_turn_channel_data), pkt, len); /* Send to client */ alloc->transport->sendto(alloc->transport, rel->tp.tx_pkt, len+sizeof(pj_turn_channel_data), 0, &alloc->hkey.clt_addr, pj_sockaddr_get_len(&alloc->hkey.clt_addr)); } else { /* Send Data Indication */ pj_stun_tx_data *tdata; pj_status_t status; status = pj_stun_session_create_ind(alloc->sess, PJ_STUN_DATA_INDICATION, &tdata); if (status != PJ_SUCCESS) { alloc_err(alloc, "Error creating Data indication", status); return; } pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_XOR_PEER_ADDR, PJ_TRUE, src_addr, pj_sockaddr_get_len(src_addr)); pj_stun_msg_add_binary_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_DATA, (const pj_uint8_t*)pkt, len); pj_stun_session_send_msg(alloc->sess, NULL, PJ_FALSE, PJ_FALSE, &alloc->hkey.clt_addr, pj_sockaddr_get_len(&alloc->hkey.clt_addr), tdata); } }