/* * Reading local directory to get specific module item's contents. * In future if needed we can change this to reading from smd metadata. */ int udf_cask_info_get(char *name, char * params, cf_dyn_buf * out) { int resp = 0; char filename[128] = {0}; int filename_len = sizeof(filename); uint8_t * content = NULL; size_t content_len = 0; unsigned char content_gen[256] = {0}; uint8_t udf_type = AS_UDF_TYPE_LUA; cf_debug(AS_INFO, "UDF CASK INFO GET"); // get (required) script filename if ( as_info_parameter_get(params, "filename", filename, &filename_len) ) { cf_info(AS_INFO, "invalid or missing filename"); cf_dyn_buf_append_string(out, "error=invalid_filename"); return 0; } mod_lua_rdlock(&mod_lua); // read the script from filesystem resp = file_read(filename, &content, &content_len, content_gen); mod_lua_unlock(&mod_lua); if ( resp ) { switch ( resp ) { case 1 : { cf_dyn_buf_append_string(out, "error=not_found"); break; } case 2 : { cf_dyn_buf_append_string(out, "error=empty"); break; } default : { cf_dyn_buf_append_string(out, "error=unknown_error"); break; // complier complains without a break; } } } else { // put back the result cf_dyn_buf_append_string(out, "gen="); cf_dyn_buf_append_string(out, (char *) content_gen); cf_dyn_buf_append_string(out, ";type="); cf_dyn_buf_append_string(out, as_udf_type_name[udf_type]); cf_dyn_buf_append_string(out, ";content="); cf_dyn_buf_append_buf(out, content, content_len); cf_dyn_buf_append_string(out, ";"); } if ( content ) { cf_free(content); content = NULL; } return 0; }
/* * UDF SMD get metadata items callback. */ static int udf_cask_get_metadata_cb(char *module, as_smd_item_list_t *items, void *udata) { udf_get_data_t *p_get_data = (udf_get_data_t *) udata; cf_dyn_buf *out = p_get_data->db; unsigned char hash[SHA_DIGEST_LENGTH]; // hex string to be returned to the client unsigned char sha1_hex_buff[CF_SHA_HEX_BUFF_LEN]; // Currently just return directly for LUA uint8_t udf_type = AS_UDF_TYPE_LUA; for (int index = 0; index < items->num_items; index++) { as_smd_item_t *item = items->item[index]; cf_debug(AS_UDF, "UDF metadata item[%d]: module \"%s\" ; key \"%s\" ; value \"%s\" ; generation %u ; timestamp %lu", index, item->module_name, item->key, item->value, item->generation, item->timestamp); cf_dyn_buf_append_string(out, "filename="); cf_dyn_buf_append_buf(out, (uint8_t *)item->key, strlen(item->key)); cf_dyn_buf_append_string(out, ","); SHA1((uint8_t *)item->value, strlen(item->value), hash); // Convert to a hexadecimal string cf_convert_sha1_to_hex(hash, sha1_hex_buff); cf_dyn_buf_append_string(out, "hash="); cf_dyn_buf_append_buf(out, sha1_hex_buff, CF_SHA_HEX_BUFF_LEN); cf_dyn_buf_append_string(out, ",type="); cf_dyn_buf_append_string(out, as_udf_type_name[udf_type]); cf_dyn_buf_append_string(out, ";"); } pthread_mutex_lock(p_get_data->mt); p_get_data->done = true; int retval = pthread_cond_signal(p_get_data->cv); if (retval) { cf_warning(AS_UDF, "pthread_cond_signal failed (rv %d)", retval); } pthread_mutex_unlock(p_get_data->mt); return retval; }
int udf_cask_info_put(char *name, char * params, cf_dyn_buf * out) { cf_debug(AS_INFO, "UDF CASK INFO PUT"); int rc = 0; char filename[128] = {0}; int filename_len = sizeof(filename); // Content_len from the client and its expected size char content_len[32] = {0}; int clen = sizeof(content_len); // Udf content from the client and its expected length char *udf_content = NULL; int udf_content_len = 0; // Udf type from the client and its expected size char type[8] = {0}; int type_len = sizeof(type); // get (required) script filename char *tmp_char; if ( as_info_parameter_get(params, "filename", filename, &filename_len) || !(tmp_char = strchr(filename, '.')) // No extension in filename || tmp_char == filename // '.' at the begining of filename || strlen (tmp_char) <= 1) { // '.' in filename, but no extnsion e.g. "abc." cf_info(AS_INFO, "invalid or missing filename"); cf_dyn_buf_append_string(out, "error=invalid_filename"); return 0; } if ( as_info_parameter_get(params, "content-len", content_len, &(clen)) ) { cf_info(AS_INFO, "invalid or missing content-len"); cf_dyn_buf_append_string(out, "error=invalid_content_len"); return 0; } if ( as_info_parameter_get(params, "udf-type", type, &type_len) ) { // Replace with DEFAULT IS LUA strcpy(type, as_udf_type_name[0]); } // check type field if (-1 == udf_type_getid(type)) { cf_info(AS_INFO, "invalid or missing udf-type : %s not valid", type); cf_dyn_buf_append_string(out, "error=invalid_udf_type"); return 0; } // get b64 encoded script udf_content_len = atoi(content_len) + 1; udf_content = (char *) cf_malloc(udf_content_len); if ( udf_content == NULL ) { cf_info(AS_UDF, "internal allocation error"); cf_dyn_buf_append_string(out, "error=internal_error"); // As memory is not allocated. // It should not continue. return 0; } // cf_info(AS_UDF, "content_len = %s", content_len); // cf_info(AS_UDF, "udf_content_len = %d", udf_content_len); // get (required) script content - base64 encoded here. if ( as_info_parameter_get(params, "content", udf_content, &(udf_content_len)) ) { cf_info(AS_UDF, "invalid content"); cf_dyn_buf_append_string(out, "error=invalid_content"); cf_free(udf_content); return 0; } // base 64 decode it uint32_t encoded_len = strlen(udf_content); uint32_t decoded_len = cf_b64_decoded_buf_size(encoded_len) + 1; // Don't allow UDF file size > 1MB if ( decoded_len > MAX_UDF_CONTENT_LENGTH) { cf_info(AS_INFO, "lua file size:%d > 1MB", decoded_len); cf_dyn_buf_append_string(out, "error=invalid_udf_content_len, lua file size > 1MB"); return 0; } char * decoded_str = cf_malloc(decoded_len); if ( ! cf_b64_validate_and_decode(udf_content, encoded_len, (uint8_t*)decoded_str, &decoded_len) ) { cf_info(AS_UDF, "invalid base64 content %s", filename); cf_dyn_buf_append_string(out, "error=invalid_base64_content"); cf_free(decoded_str); return 0; } decoded_str[decoded_len] = '\0'; as_module_error err; rc = as_module_validate(&mod_lua, NULL, filename, decoded_str, decoded_len, &err); cf_free(decoded_str); decoded_str = NULL; decoded_len = 0; if ( rc ) { cf_warning(AS_UDF, "udf-put: compile error: [%s:%d] %s", err.file, err.line, err.message); cf_dyn_buf_append_string(out, "error=compile_error"); cf_dyn_buf_append_string(out, ";file="); cf_dyn_buf_append_string(out, err.file); cf_dyn_buf_append_string(out, ";line="); cf_dyn_buf_append_uint32(out, err.line); uint32_t message_len = strlen(err.message); uint32_t enc_message_len = cf_b64_encoded_len(message_len); char enc_message[enc_message_len]; cf_b64_encode((const uint8_t*)err.message, message_len, enc_message); cf_dyn_buf_append_string(out, ";message="); cf_dyn_buf_append_buf(out, (uint8_t *)enc_message, enc_message_len); cf_free(udf_content); return 0; } // Create an empty JSON object json_t *udf_obj = 0; if (!(udf_obj = json_object())) { cf_warning(AS_UDF, "failed to create JSON array for receiving UDF"); if (udf_content) cf_free(udf_content); return -1; } int e = 0; e += json_object_set_new(udf_obj, "content64", json_string(udf_content)); e += json_object_set_new(udf_obj, "type", json_string(type)); e += json_object_set_new(udf_obj, "name", json_string(filename)); if (e) { cf_warning(AS_UDF, "could not encode UDF object, error %d", e); json_decref(udf_obj); if (udf_content) cf_free(udf_content); return(-1); } // make it into a string, yet another buffer copy char *udf_obj_str = json_dumps(udf_obj, 0/*flags*/); json_decref(udf_obj); udf_obj = 0; cf_debug(AS_UDF, "created json object %s", udf_obj_str); // how do I know whether to call create or add? e = as_smd_set_metadata(udf_smd_module_name, filename, udf_obj_str); if (e) { cf_warning(AS_UDF, "could not add UDF metadata, error %d", e); cf_free(udf_obj_str); if (udf_content) cf_free(udf_content); return(-1); } cf_info(AS_UDF, "UDF module '%s' (%s/%s) registered", filename, g_config.mod_lua.user_path, filename); // free the metadata cf_free(udf_obj_str); udf_obj_str = 0; if (udf_content) cf_free(udf_content); return 0; }
int udf_cask_info_list(char *name, cf_dyn_buf * out) { DIR * dir = NULL; bool not_empty = false; struct dirent * entry = NULL; int count = 0; uint8_t * content = NULL; size_t content_len = 0; unsigned char content_gen[256] = {0}; unsigned char hash[SHA_DIGEST_LENGTH]; // hex string to be returned to the client unsigned char sha1_hex_buff[CF_SHA_HEX_BUFF_LEN]; cf_debug(AS_INFO, "UDF CASK INFO LIST"); // Currently just return directly for LUA uint8_t udf_type = AS_UDF_TYPE_LUA; dir = opendir(g_config.mod_lua.user_path); if ( dir == 0 ) { cf_warning(AS_UDF, "could not open udf directory %s: %s", g_config.mod_lua.user_path, cf_strerror(errno)); return -1; } while ( (entry = readdir(dir)) && entry->d_name ) { char * name = entry->d_name; size_t len = strlen(name); // if ( len < 4 ) continue; if ( name[0] == '.' ) continue; if ( not_empty ) { cf_dyn_buf_append_char(out, ';'); } else { not_empty = true; } cf_dyn_buf_append_string(out, "filename="); cf_dyn_buf_append_buf(out, (uint8_t *) name, len); cf_dyn_buf_append_string(out, ","); mod_lua_rdlock(&mod_lua); if (file_read(name, &content, &content_len, content_gen) != 0) { cf_info(AS_UDF, "UDF-list : file not readable"); cf_dyn_buf_append_string(out, "error=file_not_readable"); mod_lua_unlock(&mod_lua); return 0; } mod_lua_unlock(&mod_lua); SHA1(content, content_len, hash); // Convert to a hexadecimal string cf_convert_sha1_to_hex(hash, sha1_hex_buff); cf_dyn_buf_append_string(out, "hash="); cf_dyn_buf_append_buf(out, sha1_hex_buff, CF_SHA_HEX_BUFF_LEN); cf_dyn_buf_append_string(out, ",type="); cf_dyn_buf_append_string(out, as_udf_type_name[udf_type]); count ++; } if (not_empty) { cf_dyn_buf_append_string(out, ";"); } closedir(dir); return 0; }