/* Retrieve did directly from database, without using memory cache. Use 0 as * the value of first parameter if you only want to know whether the entry is * in the database. The function returns 1 if there is such entry, 0 if not, * and -1 on error. The result is allocated using pkg_malloc and must be * freed. */ int db_get_did(str* did, str* domain) { db_res_t* res = NULL; db_rec_t* rec; if (!domain) { ERR("BUG:Invalid parameter value\n"); goto err; } get_did_cmd->match[0].v.lstr = *domain; if (db_exec(&res, get_did_cmd) < 0) { ERR("Error in database query\n"); goto err; } rec = db_first(res); if (rec) { /* Test flags first, we are only interested in rows * that are not disabled */ if (rec->fld[1].flags & DB_NULL || (rec->fld[1].v.bitmap & SRDB_DISABLED)) { db_res_free(res); return 0; } if (did) { if (rec->fld[0].flags & DB_NULL) { did->len = 0; did->s = 0; WARN("Domain '%.*s' has NULL did\n", domain->len, ZSW(domain->s)); } else { did->s = pkg_malloc(rec->fld[0].v.lstr.len); if (!did->s) { ERR("No memory left\n"); goto err; } memcpy(did->s, rec->fld[0].v.lstr.s, rec->fld[0].v.lstr.len); did->len = rec->fld[0].v.lstr.len; } } db_res_free(res); return 1; } else { db_res_free(res); return 0; } err: if (res) db_res_free(res); return -1; }
static int sel_do_select(str* result, str *query_name, int row_no, int field_no, struct sip_msg* msg) { struct dbops_action *a; int cur_row_no, res; a = find_action_by_name(query_name->s, query_name->len); if (!a) { ERR(MODULE_NAME": select: query: %.*s not declared using declare_query param\n", query_name->len, query_name->s); return -1; } if (a->operation != OPEN_QUERY_OPS) { ERR(MODULE_NAME": select: query: %.*s is not select\n", query_name->len, query_name->s); return -1; } if (row_no < 0) { ERR(MODULE_NAME": select: Row number must not be negative: %d\n", row_no); return -1; } res = dbops_func(msg, a); if (res < 0) return res; cur_row_no = -1; if (field_no >= 0) { if (do_seek(a->result, &cur_row_no, row_no) < 0) return -1; } res = sel_get_field(result, &cur_row_no, field_no, a->result); db_res_free(a->result); return res; }
/* * Load attributes from domain_attrs table */ int db_load_domain_attrs(domain_t* d) { int_str name, v; str avp_val; db_res_t* res; db_rec_t* rec; unsigned short flags; load_attrs_cmd->match[0].v.lstr = d->did; if (db_exec(&res, load_attrs_cmd) < 0) { ERR("Error while querying database\n"); return -1; } rec = db_first(res); while(rec) { if (rec->fld[0].flags & DB_NULL || rec->fld[1].flags & DB_NULL || rec->fld[3].flags & DB_NULL) { ERR("Skipping row containing NULL entries\n"); goto skip; } if ((rec->fld[3].v.int4 & SRDB_LOAD_SER) == 0) goto skip; /* Get AVP name */ name.s = rec->fld[0].v.lstr; /* Test for NULL value */ if (rec->fld[2].flags & DB_NULL) { avp_val.s = 0; avp_val.len = 0; } else { avp_val = rec->fld[2].v.lstr; } flags = AVP_CLASS_DOMAIN | AVP_NAME_STR; if (rec->fld[1].v.int4 == AVP_VAL_STR) { /* String AVP */ v.s = avp_val; flags |= AVP_VAL_STR; } else { /* Integer AVP */ str2int(&avp_val, (unsigned*)&v.n); } if (add_avp_list(&d->attrs, flags, name, v) < 0) { ERR("Error while adding domain attribute %.*s to domain %.*s, " "skipping\n", name.s.len, ZSW(name.s.s), d->did.len, ZSW(d->did.s)); } skip: rec = db_next(res); } db_res_free(res); return 0; }
static int dbops_close_query_func(struct sip_msg* m, char* handle, char* dummy) { struct dbops_handle *a = (void *)handle; if (a->result) { db_res_free(a->result); a->result = 0; } return 1; }
/* callback function called once per cfg_group identified by group_name */ static void on_declare(str *group_name, cfg_def_t *definition) { static db_cmd_t* cmd; db_res_t *res; cfg_def_t *def; int ret; str asterisk_s = STR_STATIC_INIT("*"); DBG(MODULE_NAME": on_declare('%.*s')\n", group_name->len, group_name->s); if (connect_db() < 0) return; for (def=definition; def->name; def++) { /* for each definition lookup config tables */ if (exec_transl(group_name, &cmd, &res) < 0) return; ret = find_cfg_var(group_name, def->name, res); db_res_free(res); db_cmd_free(cmd); if (ret > 0) continue; /* not found then try default '*' translations */ if (exec_transl(&asterisk_s, &cmd, &res) < 0) return; find_cfg_var(group_name, def->name, res); db_res_free(res); db_cmd_free(cmd); } }
int sd_lookup(struct sip_msg* _msg, char* _index, char* _str2) { int i; str user_s, uid, did; db_res_t* res = NULL; db_rec_t* rec; /* init */ i = (int)(long)_index; /* Retrieve the owner of the record */ if (get_from_uid(&uid, _msg) < 0) { LOG(L_ERR, "sd_lookup: Unable to get user identity\n"); return -1; } /* Retrieve the called domain id */ if (get_to_did(&did, _msg) < 0) { LOG(L_ERR, "sd_lookup: Destination domain ID not known\n"); return -1; } tables[i].lookup_num->match[0].v.lstr = uid; tables[i].lookup_num->match[1].v.lstr = did; /* Get the called username */ if (parse_sip_msg_uri(_msg) < 0) { LOG(L_ERR, "sd_lookup: Error while parsing Request-URI\n"); goto err_badreq; } tables[i].lookup_num->match[2].v.lstr = _msg->parsed_uri.user; DBG("speeddial: Looking up (uid:%.*s,username:%.*s,did:%.*s)\n", uid.len, uid.s, _msg->parsed_uri.user.len, _msg->parsed_uri.user.s, did.len, did.s); if (db_exec(&res, tables[i].lookup_num) < 0) { ERR("speeddial: Error while executing database command\n"); goto err_server; } if (res == NULL) { DBG("speeddial: No SIP URI found for speeddial (num:%.*s, uid:%.*s," " did:%.*s)\n", _msg->parsed_uri.user.len, _msg->parsed_uri.user.s, uid.len, uid.s, did.len, did.s); return -1; } user_s.s = useruri_buf + 4; rec = db_first(res); while(rec) { if (rec->fld[0].flags & DB_NULL) goto skip; strncpy(user_s.s, rec->fld[0].v.lstr.s, rec->fld[0].v.lstr.len); user_s.len = rec->fld[0].v.lstr.len; user_s.s[user_s.len] = '\0'; goto out; skip: rec = db_next(res); } if (rec == NULL) { DBG("speeddial: No usable SIP URI found for (num:%.*s, uid:%.*s," " did:%.*s)\n", _msg->parsed_uri.user.len, _msg->parsed_uri.user.s, uid.len, uid.s, did.len, did.s); db_res_free(res); return -1; } out: /* check 'sip:' */ if(user_s.len<4 || strncmp(user_s.s, "sip:", 4)) { memcpy(useruri_buf, "sip:", 4); user_s.s -= 4; user_s.len += 4; } db_res_free(res); /* set the URI */ DBG("sd_lookup: URI of sd from R-URI [%s]\n", user_s.s); if(rewrite_uri(_msg, &user_s)<0) { LOG(L_ERR, "sd_lookup: Cannot replace the R-URI\n"); goto err_server; } return 1; err_server: if (slb.zreply(_msg, 500, "Server Internal Error") == -1) { LOG(L_ERR, "sd_lookup: Error while sending reply\n"); } return 0; err_badreq: if (slb.zreply(_msg, 400, "Bad Request") == -1) { LOG(L_ERR, "sd_lookup: Error while sending reply\n"); } return 0; }
/* module initialization function */ static int mod_init(void) { static str default_s = STR_STATIC_INIT("<default>"); db_cmd_t *cmd; db_res_t *res; db_rec_t *rec; db_fld_t cols[7]; DBG(MODULE_NAME": mod_init: initializing\n"); /* get default values from translation table */ if (connect_db() < 0) return E_CFG; DBG(MODULE_NAME": mod_init: getting default values from translation table\n"); if (exec_transl(&default_s, &cmd, &res) < 0) return E_CFG; rec = db_first(res); if (rec) { CSTRDUP(def_cfg_table, rec->fld[0]); CSTRDUP(def_cfg_table_group_name_field, rec->fld[1]); CSTRDUP(def_cfg_table_name_field, rec->fld[2]); CSTRDUP(def_cfg_table_value_field, rec->fld[3]); } // db_rec_free(rec); // ---> causes next db_cmd is aborted !!! db_res_free(res); db_cmd_free(cmd); DBG(MODULE_NAME": mod_init: default values: table='%s', group_name_field='%s', name_field='%s', value_field='%s'\n", def_cfg_table, def_cfg_table_group_name_field, def_cfg_table_name_field, def_cfg_table_value_field); /* get custom parameters from database */ DBG(MODULE_NAME": mod_init: getting custom parameters from '%s'\n", custom_tbl); memset(cols, 0, sizeof(cols)); cols[0].name = custom_tbl_group_name_fld; cols[0].type = DB_CSTR; cols[1].name = custom_tbl_name_fld; cols[1].type = DB_CSTR; cols[2].name = custom_tbl_value_type_fld; cols[2].type = DB_CSTR; cols[3].name = custom_tbl_min_value_fld; cols[3].type = DB_INT; cols[4].name = custom_tbl_max_value_fld; cols[4].type = DB_INT; cols[5].name = custom_tbl_decription_fld; cols[5].type = DB_CSTR; cmd = db_cmd(DB_GET, db_cntx, custom_tbl, cols, NULL, NULL); if (!cmd) { ERR(MODULE_NAME": Error preparing query '%s'\n", custom_tbl); return E_CFG; } if (db_exec(&res, cmd) < 0) { ERR(MODULE_NAME": Error executing query '%s'\n", custom_tbl); db_cmd_free(cmd); return E_CFG; } rec = db_first(res); while (rec) { DBG(MODULE_NAME": custom parameter '%s.%s' type:%s\n", rec->fld[0].v.cstr, rec->fld[1].v.cstr, rec->fld[2].v.cstr); if (((rec->fld[0].flags & DB_NULL) || strlen(rec->fld[0].v.cstr) == 0) || ((rec->fld[1].flags & DB_NULL) || strlen(rec->fld[1].v.cstr) == 0) || ((rec->fld[2].flags & DB_NULL) || strlen(rec->fld[2].v.cstr) == 0)) { ERR(MODULE_NAME": empty group_name,name or type value in table '%s'\n", custom_tbl); return E_CFG; } switch (rec->fld[2].v.cstr[0]) { case 'i': case 'I': if (cfg_declare_int(rec->fld[0].v.cstr, rec->fld[1].v.cstr, 0, rec->fld[3].v.int4, rec->fld[4].v.int4, rec->fld[5].v.cstr) < 0) { ERR(MODULE_NAME": Error declaring cfg int '%s.%s'\n", rec->fld[0].v.cstr, rec->fld[1].v.cstr); return E_CFG; } break; case 's': case 'S': if (cfg_declare_str(rec->fld[0].v.cstr, rec->fld[1].v.cstr, "", rec->fld[5].v.cstr) < 0) { ERR(MODULE_NAME": Error declaring cfg str '%s.%s'\n", rec->fld[0].v.cstr, rec->fld[1].v.cstr); return E_CFG; } break; default: ERR(MODULE_NAME": bad custom value type '%s'\n", rec->fld[2].v.cstr); return E_CFG; } rec = db_next(res); } db_res_free(res); db_cmd_free(cmd); /* register into config framework */ DBG(MODULE_NAME": mod_init: registering cfg callback\n"); if (cfg_register_ctx(&cfg_ctx, on_declare) < 0) { ERR(MODULE_NAME": failed to register cfg context\n"); return -1; } return 0; }
/* translate name using translation table, returns 0..not found, 1..success, -1..error */ static int find_cfg_var(str *group_name, char *def_name, db_res_t *transl_res) { db_rec_t *transl_rec; int ret = -1; DBG(MODULE_NAME": find_cfg_var('%.*s', '%s', ...)\n", group_name->len, group_name->s, def_name); transl_rec = db_first(transl_res); /* iterate through each candidate where cfg def may be found */ while (transl_rec) { static db_cmd_t* cmd; db_rec_t *rec; db_res_t *res; db_fld_t params[3], cols[2]; memset(cols, 0, sizeof(cols)); cols[0].name = GETCSTR(transl_rec->fld[3], def_cfg_table_value_field); cols[0].type = DB_NONE; memset(params, 0, sizeof(params)); params[0].name = GETCSTR(transl_rec->fld[1], def_cfg_table_group_name_field); params[0].type = DB_STR; params[0].op = DB_EQ; params[1].name = GETCSTR(transl_rec->fld[2], def_cfg_table_name_field); params[1].type = DB_CSTR; params[1].op = DB_EQ; DBG(MODULE_NAME": exec_transl: looking in '%s'\n", GETCSTR(transl_rec->fld[0], def_cfg_table)); cmd = db_cmd(DB_GET, db_cntx, GETCSTR(transl_rec->fld[0], def_cfg_table), cols, params, NULL); if (!cmd) { ERR(MODULE_NAME": Error preparing query '%s'\n", transl_tbl); return -1; } cmd->match[0].flags &= ~DB_NULL; cmd->match[0].v.lstr = *group_name; cmd->match[1].flags &= ~DB_NULL; cmd->match[1].v.cstr = def_name; // FIXME: proprietary code! db_setopt(cmd, "key", "bySerGroup"); db_setopt(cmd, "key_omit", 0); if (db_exec(&res, cmd) < 0) { ERR(MODULE_NAME": Error executing query '%s'\n", transl_tbl); db_cmd_free(cmd); return -1; } rec = db_first(res); if (rec) { /* var found in config table */ str def_name_s; def_name_s.s = def_name; def_name_s.len = strlen(def_name); DBG(MODULE_NAME": exec_transl: found record, type:%d\n", rec->fld[0].type); /* read and set cfg var */ switch (rec->fld[0].type) { case DB_STR: if (cfg_set_now(cfg_ctx, group_name, NULL /* group id */, &def_name_s, &rec->fld[0].v.lstr, CFG_VAR_STR) < 0) goto err; break; case DB_CSTR: if (cfg_set_now_string(cfg_ctx, group_name, NULL /* group id */, &def_name_s, rec->fld[0].v.cstr) < 0) goto err; break; case DB_INT: if (cfg_set_now_int(cfg_ctx, group_name, NULL /* group id */, &def_name_s, rec->fld[0].v.int4) < 0) goto err; break; default: ERR(MODULE_NAME": unexpected field type (%d), table:'%s', field:'%s'\n", rec->fld[0].type, GETCSTR(transl_rec->fld[0], def_cfg_table), GETCSTR(transl_rec->fld[3], def_cfg_table_value_field) ); goto err; } ret = 1; err: db_res_free(res); db_cmd_free(cmd); return ret; } db_res_free(res); db_cmd_free(cmd); transl_rec = db_next(transl_res); } return 0; }
/* * Create domain list from domain table */ int load_domains(domain_t** dest) { db_res_t* res = NULL; db_rec_t* rec; unsigned int flags; domain_t* d, *list; list = 0; if (db_exec(&res, load_domains_cmd) < 0) { ERR("Error while querying database\n"); return -1; } rec = db_first(res); while(rec) { /* Do not assume that the database server performs any constrain * checking (dbtext does not) and perform sanity checks here to * make sure that we only load good entried */ if (rec->fld[0].flags & DB_NULL || rec->fld[1].flags & DB_NULL || rec->fld[2].flags & DB_NULL) { ERR("Row with NULL column(s), skipping\n"); goto skip; } flags = rec->fld[2].v.int4; /* Skip entries that are disabled/scheduled for removal */ if (flags & SRDB_DISABLED) goto skip; /* Skip entries that are for serweb/ser-ctl only */ if (!(flags & SRDB_LOAD_SER)) goto skip; DBG("Processing entry (%.*s, %.*s, %u)\n", rec->fld[0].v.lstr.len, ZSW(rec->fld[0].v.lstr.s), rec->fld[1].v.lstr.len, ZSW(rec->fld[1].v.lstr.s), flags); d = domain_search(list, &rec->fld[0].v.lstr); if (d) { /* DID exists in the list, update it */ if (domain_add(d, &rec->fld[1].v.lstr, flags) < 0) goto error; } else { /* DID does not exist yet, create a new entry */ d = new_domain(&rec->fld[0].v.lstr, &rec->fld[1].v.lstr, flags); if (!d) goto error; d->next = list; list = d; } skip: rec = db_next(res); } db_res_free(res); if (load_domain_attrs) { d = list; while(d) { if (db_load_domain_attrs(d) < 0) goto error; d = d->next; } } *dest = list; return 0; error: if (res) db_res_free(res); free_domain_list(list); return 1; }
/* * Authenticate digest credentials * Returns: * -3 -- Bad Request * -2 -- Error while checking credentials (such as malformed message or database problem) * -1 -- Authentication failed * 1 -- Authentication successful */ static inline int authenticate(struct sip_msg* msg, str* realm, authdb_table_info_t *table, hdr_types_t hftype) { char ha1[256]; int res, ret; db_rec_t *row; struct hdr_field* h; auth_body_t* cred; db_res_t* result; str did; cred = 0; result = 0; ret = -1; switch(auth_api.pre_auth(msg, realm, hftype, &h, NULL)) { case ERROR: case BAD_CREDENTIALS: ret = -3; goto end; case CREATE_CHALLENGE: ERR("auth_db:authenticate: CREATE_CHALLENGE is not a valid state\n"); ret = -2; goto end; case DO_RESYNCHRONIZATION: ERR("auth_db:authenticate: DO_RESYNCHRONIZATION is not a valid state\n"); ret = -2; goto end; case NOT_AUTHENTICATED: ret = -1; goto end; case DO_AUTHENTICATION: break; case AUTHENTICATED: ret = 1; goto end; } cred = (auth_body_t*)h->parsed; if (use_did) { if (msg->REQ_METHOD == METHOD_REGISTER) { ret = get_to_did(&did, msg); } else { ret = get_from_did(&did, msg); } if (ret == 0) { did.s = DEFAULT_DID; did.len = sizeof(DEFAULT_DID) - 1; } } else { did.len = 0; did.s = 0; } if (check_all) { res = check_all_ha1(msg, h, &(cred->digest), &msg->first_line.u.request.method, &did, realm, table, &result); if (res < 0) { ret = -2; goto end; } else if (res > 0) { ret = -1; goto end; } else { ret = 1; goto end; } } else { res = get_ha1(&cred->digest.username, &did, realm, table, ha1, &result, &row); if (res < 0) { ret = -2; goto end; } if (res > 0) { /* Username not found in the database */ ret = -1; goto end; } } /* Recalculate response, it must be same to authorize successfully */ if (!check_response(&(cred->digest), &msg->first_line.u.request.method, ha1)) { switch(auth_api.post_auth(msg, h)) { case ERROR: case BAD_CREDENTIALS: ret = -2; break; case NOT_AUTHENTICATED: ret = -1; break; case AUTHENTICATED: generate_avps(result, row); ret = 1; break; default: ret = -1; break; } } else { ret = -1; } end: if (result) db_res_free(result); if (ret < 0) { if (auth_api.build_challenge(msg, (cred ? cred->stale : 0), realm, NULL, NULL, hftype) < 0) { ERR("Error while creating challenge\n"); ret = -2; } } return ret; }