45 #define AST_API_MODULE
49 #include <sys/ioctl.h>
50 #include <sys/socket.h>
53 #include <sys/sockio.h>
72 #include "asterisk/phoneprov.h"
75 #define MAX_PROVIDER_BUCKETS 1
76 #define MAX_PROFILE_BUCKETS 1
77 #define MAX_ROUTE_BUCKETS 1
78 #define MAX_USER_BUCKETS 1
80 #define MAX_PROVIDER_BUCKETS 17
81 #define MAX_PROFILE_BUCKETS 17
82 #define MAX_ROUTE_BUCKETS 563
83 #define MAX_USER_BUCKETS 563
86 #define VAR_BUF_SIZE 4096
128 #define SIMPLE_HASH_FN(fname, stype, field) \
129 static int fname(const void *obj, const int flags) \
131 const struct stype *provider = obj; \
133 switch (flags & OBJ_SEARCH_MASK) { \
134 case OBJ_SEARCH_KEY: \
137 case OBJ_SEARCH_OBJECT: \
139 key = provider->field; \
145 return ast_str_hash(key); \
157 #define SIMPLE_CMP_FN(fname, stype, field) \
158 static int fname(void *obj, void *arg, int flags) \
160 const struct stype *object_left = obj, *object_right = arg; \
161 const char *right_key = arg; \
163 switch (flags & OBJ_SEARCH_MASK) { \
164 case OBJ_SEARCH_OBJECT: \
165 right_key = object_right->field; \
166 case OBJ_SEARCH_KEY: \
167 cmp = strcmp(object_left->field, right_key); \
169 case OBJ_SEARCH_PARTIAL_KEY: \
170 cmp = strncmp(object_left->field, right_key, strlen(right_key)); \
182 static const char *variable_lookup[] = {
183 [AST_PHONEPROV_STD_MAC] =
"MAC",
184 [AST_PHONEPROV_STD_PROFILE] =
"PROFILE",
185 [AST_PHONEPROV_STD_USERNAME] =
"USERNAME",
186 [AST_PHONEPROV_STD_DISPLAY_NAME] =
"DISPLAY_NAME",
187 [AST_PHONEPROV_STD_SECRET] =
"SECRET",
188 [AST_PHONEPROV_STD_LABEL] =
"LABEL",
189 [AST_PHONEPROV_STD_CALLERID] =
"CALLERID",
190 [AST_PHONEPROV_STD_TIMEZONE] =
"TIMEZONE",
191 [AST_PHONEPROV_STD_LINENUMBER] =
"LINE",
192 [AST_PHONEPROV_STD_LINEKEYS] =
"LINEKEYS",
193 [AST_PHONEPROV_STD_SERVER] =
"SERVER",
194 [AST_PHONEPROV_STD_SERVER_PORT] =
"SERVER_PORT",
195 [AST_PHONEPROV_STD_SERVER_IFACE] =
"SERVER_IFACE",
196 [AST_PHONEPROV_STD_VOICEMAIL_EXTEN] =
"VOICEMAIL_EXTEN",
197 [AST_PHONEPROV_STD_EXTENSION_LENGTH] =
"EXTENSION_LENGTH",
198 [AST_PHONEPROV_STD_TZOFFSET] =
"TZOFFSET",
199 [AST_PHONEPROV_STD_DST_ENABLE] =
"DST_ENABLE",
200 [AST_PHONEPROV_STD_DST_START_MONTH] =
"DST_START_MONTH",
201 [AST_PHONEPROV_STD_DST_START_MDAY] =
"DST_START_MDAY",
202 [AST_PHONEPROV_STD_DST_START_HOUR] =
"DST_START_HOUR",
203 [AST_PHONEPROV_STD_DST_END_MONTH] =
"DST_END_MONTH",
204 [AST_PHONEPROV_STD_DST_END_MDAY] =
"DST_END_MDAY",
205 [AST_PHONEPROV_STD_DST_END_HOUR] =
"DST_END_HOUR",
209 static const char *pp_user_lookup[] = {
210 [AST_PHONEPROV_STD_MAC] =
"macaddress",
211 [AST_PHONEPROV_STD_PROFILE] =
"profile",
212 [AST_PHONEPROV_STD_USERNAME] =
"username",
213 [AST_PHONEPROV_STD_DISPLAY_NAME] =
"fullname",
214 [AST_PHONEPROV_STD_SECRET] =
"secret",
215 [AST_PHONEPROV_STD_LABEL] =
"label",
216 [AST_PHONEPROV_STD_CALLERID] =
"cid_number",
217 [AST_PHONEPROV_STD_TIMEZONE] =
"timezone",
218 [AST_PHONEPROV_STD_LINENUMBER] =
"linenumber",
219 [AST_PHONEPROV_STD_LINEKEYS] =
"linekeys",
220 [AST_PHONEPROV_STD_SERVER] = NULL,
221 [AST_PHONEPROV_STD_SERVER_PORT] = NULL,
222 [AST_PHONEPROV_STD_SERVER_IFACE] = NULL,
223 [AST_PHONEPROV_STD_VOICEMAIL_EXTEN] =
"vmexten",
224 [AST_PHONEPROV_STD_EXTENSION_LENGTH] =
"localextenlength",
225 [AST_PHONEPROV_STD_TZOFFSET] = NULL,
226 [AST_PHONEPROV_STD_DST_ENABLE] = NULL,
227 [AST_PHONEPROV_STD_DST_START_MONTH] = NULL,
228 [AST_PHONEPROV_STD_DST_START_MDAY] = NULL,
229 [AST_PHONEPROV_STD_DST_START_HOUR] = NULL,
230 [AST_PHONEPROV_STD_DST_END_MONTH] = NULL,
231 [AST_PHONEPROV_STD_DST_END_MDAY] = NULL,
232 [AST_PHONEPROV_STD_DST_END_HOUR] = NULL,
236 static const char *pp_general_lookup[] = {
237 [AST_PHONEPROV_STD_MAC] = NULL,
238 [AST_PHONEPROV_STD_PROFILE] =
"default_profile",
239 [AST_PHONEPROV_STD_USERNAME] = NULL,
240 [AST_PHONEPROV_STD_DISPLAY_NAME] = NULL,
241 [AST_PHONEPROV_STD_SECRET] = NULL,
242 [AST_PHONEPROV_STD_LABEL] = NULL,
243 [AST_PHONEPROV_STD_CALLERID] = NULL,
244 [AST_PHONEPROV_STD_TIMEZONE] = NULL,
245 [AST_PHONEPROV_STD_LINENUMBER] = NULL,
246 [AST_PHONEPROV_STD_LINEKEYS] = NULL,
247 [AST_PHONEPROV_STD_SERVER] =
"serveraddr",
248 [AST_PHONEPROV_STD_SERVER_PORT] =
"serverport",
249 [AST_PHONEPROV_STD_SERVER_IFACE] =
"serveriface",
250 [AST_PHONEPROV_STD_VOICEMAIL_EXTEN] = NULL,
251 [AST_PHONEPROV_STD_EXTENSION_LENGTH] = NULL,
252 [AST_PHONEPROV_STD_TZOFFSET] = NULL,
253 [AST_PHONEPROV_STD_DST_ENABLE] = NULL,
254 [AST_PHONEPROV_STD_DST_START_MONTH] = NULL,
255 [AST_PHONEPROV_STD_DST_START_MDAY] = NULL,
256 [AST_PHONEPROV_STD_DST_START_HOUR] = NULL,
257 [AST_PHONEPROV_STD_DST_END_MONTH] = NULL,
258 [AST_PHONEPROV_STD_DST_END_MDAY] = NULL,
259 [AST_PHONEPROV_STD_DST_END_HOUR] = NULL,
263 static struct in_addr
__ourip = { .s_addr = 0x00000000, };
270 ast_phoneprov_load_users_cb load_users;
317 struct phone_profile *profile;
329 struct phoneprov_file *file;
332 struct phone_profile *profile;
338 #define SIPUSERS_PROVIDER_NAME "sipusers"
341 static int lookup_iface(
const char *iface,
struct in_addr *address)
345 struct sockaddr_in *sin;
347 memset(&ifr, 0,
sizeof(ifr));
350 mysock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
352 ast_log(LOG_ERROR,
"Failed to create socket: %s\n", strerror(errno));
356 res = ioctl(mysock, SIOCGIFADDR, &ifr);
361 ast_log(LOG_WARNING,
"Unable to get IP of %s: %s\n", iface, strerror(errno));
365 sin = (
struct sockaddr_in *)&ifr.ifr_addr;
366 memcpy(address, &sin->sin_addr,
sizeof(*address));
371 static struct phoneprov_provider *find_provider(
char *name)
386 static void provider_destructor(
void *obj)
388 struct phoneprov_provider *provider = obj;
392 static void delete_file(
struct phoneprov_file *file)
399 static int load_file(
const char *filename,
char **ret)
404 if (!(f = fopen(filename,
"r"))) {
409 fseek(f, 0, SEEK_END);
411 fseek(f, 0, SEEK_SET);
417 if (len != fread(*ret,
sizeof(
char), len, f)) {
447 ast_get_dst_info(&utc_time, &dstenable, &dststart, &dstend, &tzoffset, zone);
448 snprintf(buffer,
sizeof(buffer),
"%d", tzoffset);
449 AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign(
"TZOFFSET", buffer));
455 AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign(
"DST_ENABLE",
"1"));
457 when.tv_sec = dststart;
460 snprintf(buffer,
sizeof(buffer),
"%d", tm_info.
tm_mon+1);
461 AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign(
"DST_START_MONTH", buffer));
463 snprintf(buffer,
sizeof(buffer),
"%d", tm_info.
tm_mday);
464 AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign(
"DST_START_MDAY", buffer));
466 snprintf(buffer,
sizeof(buffer),
"%d", tm_info.
tm_hour);
467 AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign(
"DST_START_HOUR", buffer));
469 when.tv_sec = dstend;
472 snprintf(buffer,
sizeof(buffer),
"%d", tm_info.
tm_mon + 1);
473 AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign(
"DST_END_MONTH", buffer));
475 snprintf(buffer,
sizeof(buffer),
"%d", tm_info.
tm_mday);
476 AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign(
"DST_END_MDAY", buffer));
478 snprintf(buffer,
sizeof(buffer),
"%d", tm_info.
tm_hour);
479 AST_VAR_LIST_INSERT_TAIL(headp, ast_var_assign(
"DST_END_HOUR", buffer));
482 static struct http_route *unref_route(
struct http_route *route)
489 static void route_destructor(
void *obj)
491 struct http_route *route = obj;
512 static void build_route(
struct phoneprov_file *pp_file,
struct phone_profile *profile,
struct user *user,
char *
uri)
514 struct http_route *route;
516 if (!(route = ao2_alloc(
sizeof(*route), route_destructor))) {
521 ast_log(LOG_ERROR,
"Couldn't create string fields for %s\n", pp_file->
format);
522 route = unref_route(route);
528 route->
file = pp_file;
529 route->profile = profile;
533 route = unref_route(route);
536 static struct phone_profile *unref_profile(
struct phone_profile *prof)
549 static void profile_destructor(
void *obj)
551 struct phone_profile *profile = obj;
552 struct phoneprov_file *file;
567 ast_free(profile->
headp);
587 struct phone_profile *profile;
589 if (!(profile = ao2_alloc(
sizeof(*profile), profile_destructor))) {
594 profile = unref_profile(profile);
598 if (!(profile->
headp = ast_var_list_create())) {
599 profile = unref_profile(profile);
607 for (; v; v = v->
next) {
608 if (!strcasecmp(v->
name,
"mime_type")) {
610 }
else if (!strcasecmp(v->
name,
"setvar")) {
611 char value_copy[strlen(v->
value) + 1];
618 strcpy(value_copy, v->
value);
621 if (ast_strlen_zero(args.varname) || ast_strlen_zero(args.varval))
625 if (ast_strlen_zero(args.varname) || ast_strlen_zero(args.varval))
627 AST_VAR_LIST_INSERT_TAIL(profile->
headp, ast_var_assign(args.varname, args.varval));
629 }
else if (!strcasecmp(v->
name,
"staticdir")) {
632 struct phoneprov_file *pp_file;
633 char *file_extension;
634 char value_copy[strlen(v->
value) + 1];
642 profile = unref_profile(profile);
646 if ((file_extension = strrchr(pp_file->
format,
'.')))
649 strcpy(value_copy, v->
value);
661 if (!strcasecmp(v->
name,
"static_file")) {
677 profile = unref_profile(profile);
680 static struct extension *delete_extension(
struct extension *exten)
682 ast_var_list_destroy(exten->
headp);
689 static struct extension *build_extension(
const char *name,
struct varshead *vars)
691 struct extension *exten;
700 exten->
headp = ast_var_list_clone(vars);
702 ast_log(LOG_ERROR,
"Unable to clone variables for extension '%s'\n", name);
703 delete_extension(exten);
707 tmp = ast_var_find(exten->
headp, variable_lookup[AST_PHONEPROV_STD_LINENUMBER]);
709 AST_VAR_LIST_INSERT_TAIL(exten->
headp,
710 ast_var_assign(variable_lookup[AST_PHONEPROV_STD_LINENUMBER],
"1"));
713 sscanf(tmp,
"%d", &exten->index);
716 if (!ast_var_find(exten->
headp, variable_lookup[AST_PHONEPROV_STD_LINEKEYS])) {
717 AST_VAR_LIST_INSERT_TAIL(exten->
headp,
718 ast_var_assign(variable_lookup[AST_PHONEPROV_STD_LINEKEYS],
"1"));
722 ast_var_find(vars, variable_lookup[AST_PHONEPROV_STD_TIMEZONE]));
727 static struct user *unref_user(
struct user *user)
740 static int routes_delete_cb(
void *obj,
void *arg,
int flags)
742 struct http_route *route = obj;
743 struct user *user = route->
user;
755 struct user *user = obj;
756 struct extension *exten;
759 exten = delete_extension(exten);
793 user = unref_user(user);
818 if (ast_var_find(exten->
headp, pvar->name)) {
824 AST_VAR_LIST_INSERT_TAIL(exten->
headp, var2);
832 struct extension *exten_iter;
835 if (exten->index < exten_iter->index) {
837 }
else if (exten->index == exten_iter->index) {
838 ast_log(LOG_WARNING,
"Duplicate linenumber=%d for %s\n", exten->index, user->
macaddress);
853 struct phoneprov_file *pp_file;
872 struct http_route *route;
877 char *newserver = NULL;
878 struct extension *exten_iter;
883 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) {
884 ast_http_error(ser, 501,
"Not Implemented",
"Attempt to use unimplemented / unsupported method");
892 snprintf(path,
sizeof(path),
"%s/phoneprov/%s", ast_config_AST_DATA_DIR, route->
file->
template);
896 fd = open(path, O_RDONLY);
901 len = lseek(fd, 0, SEEK_END);
902 lseek(fd, 0, SEEK_SET);
904 ast_log(LOG_WARNING,
"Could not load file: %s (%d)\n", path, len);
910 ast_str_set(&http_header, 0,
"Content-type: %s\r\n",
913 ast_http_send(ser, method, 200, NULL, http_header, NULL, fd, 0);
916 route = unref_route(route);
923 ast_log(LOG_WARNING,
"Could not load file: %s (%d)\n", path, len);
947 variable_lookup[AST_PHONEPROV_STD_SERVER]);
952 struct sockaddr_in sa_in;
954 socklen_t namelen =
sizeof(name.sa);
958 ast_log(LOG_WARNING,
"Could not get server IP, breakage likely.\n");
963 AST_VAR_LIST_INSERT_TAIL(exten_iter->
headp,
964 ast_var_assign(variable_lookup[AST_PHONEPROV_STD_SERVER], newserver));
977 if (!strcmp(variable_lookup[AST_PHONEPROV_STD_SERVER], ast_var_name(varns))) {
979 ast_var_delete(varns);
989 ast_str_set(&http_header, 0,
"Content-type: %s\r\n",
993 ast_log(LOG_ERROR,
"Could not create result string!\n");
997 ast_free(http_header);
1002 ast_http_send(ser, method, 200, NULL, http_header, result, 0, 0);
1005 route = unref_route(route);
1015 route = unref_route(route);
1016 ast_http_error(ser, 500,
"Internal Error",
"An internal error has occured.");
1038 while ((tmp = strstr(args.string,
"%{")))
1042 while ((user = ao2_iterator_next(&i))) {
1043 if (!ast_strlen_zero(args.exclude_mac) && !strcasecmp(user->
macaddress, args.exclude_mac)) {
1053 user = unref_user(user);
1061 static int pp_each_user_read(
struct ast_channel *chan,
const char *cmd,
char *data,
char *buf,
size_t len)
1066 static int pp_each_user_read2(
struct ast_channel *chan,
const char *cmd,
char *data,
struct ast_str **buf, ssize_t len)
1072 .
name =
"PP_EACH_USER",
1073 .read = pp_each_user_read,
1074 .read2 = pp_each_user_read2,
1081 struct extension *exten;
1082 char path[PATH_MAX];
1093 if (ast_strlen_zero(args.mac) || ast_strlen_zero(args.template)) {
1094 ast_log(LOG_WARNING,
"PP_EACH_EXTENSION requires both a macaddress and template filename.\n");
1099 ast_log(LOG_WARNING,
"Could not find user with mac = '%s'\n", args.mac);
1103 snprintf(path,
sizeof(path),
"%s/phoneprov/%s", ast_config_AST_DATA_DIR, args.template);
1106 ast_log(LOG_WARNING,
"Could not load file: %s (%d)\n", path, filelen);
1134 user = unref_user(user);
1139 static int pp_each_extension_read(
struct ast_channel *chan,
const char *cmd,
char *data,
char *buf,
size_t len)
1144 static int pp_each_extension_read2(
struct ast_channel *chan,
const char *cmd,
char *data,
struct ast_str **buf, ssize_t len)
1150 .
name =
"PP_EACH_EXTENSION",
1151 .read = pp_each_extension_read,
1152 .read2 = pp_each_extension_read2,
1155 #define FORMATS "%-20.20s %-40.40s %-30.30s\n"
1156 #define FORMATD "%-20.20s %-20.20s %-40.40s %-30.30s\n"
1157 static int route_list_cb(
void *obj,
void *arg,
void *data,
int flags)
1159 int fd = *(
int *)arg;
1160 struct http_route *route = obj;
1162 if (data && route->
user) {
1165 if (!data && !route->
user) {
1178 e->
command =
"phoneprov show routes";
1180 "Usage: phoneprov show routes\n"
1181 " Lists all registered phoneprov http routes.\n";
1189 ast_cli(a->fd,
"Static routes\n\n");
1190 ast_cli(a->fd, FORMATS,
"Profile",
"Relative URI",
"Physical location");
1194 ast_cli(a->fd,
"\nDynamic routes\n\n");
1195 ast_cli(a->fd, FORMATD,
"Provider",
"Profile",
"Relative URI",
"Template");
1208 .description =
"Asterisk HTTP Phone Provisioning Tool",
1215 static struct varshead *get_defaults(
void)
1217 struct ast_config *phoneprov_cfg, *cfg = CONFIG_STATUS_FILEINVALID;
1222 struct varshead *defaults = ast_var_list_create();
1225 ast_log(LOG_ERROR,
"Unable to create default var list.\n");
1229 if (!(phoneprov_cfg =
ast_config_load(
"phoneprov.conf", config_flags))
1230 || phoneprov_cfg == CONFIG_STATUS_FILEINVALID) {
1231 ast_log(LOG_ERROR,
"Unable to load config phoneprov.conf\n");
1232 ast_var_list_destroy(defaults);
1236 value = ast_variable_retrieve(phoneprov_cfg,
"general", pp_general_lookup[AST_PHONEPROV_STD_SERVER]);
1238 struct in_addr addr;
1239 value = ast_variable_retrieve(phoneprov_cfg,
"general", pp_general_lookup[AST_PHONEPROV_STD_SERVER_IFACE]);
1241 lookup_iface(value, &addr);
1246 var = ast_var_assign(variable_lookup[AST_PHONEPROV_STD_SERVER], value);
1247 AST_VAR_LIST_INSERT_TAIL(defaults, var);
1249 ast_log(LOG_WARNING,
"Unable to find a valid server address or name.\n");
1252 value = ast_variable_retrieve(phoneprov_cfg,
"general", pp_general_lookup[AST_PHONEPROV_STD_SERVER_PORT]);
1253 var = ast_var_assign(variable_lookup[AST_PHONEPROV_STD_SERVER_PORT],
S_OR(value,
"5060"));
1254 if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
1257 AST_VAR_LIST_INSERT_TAIL(defaults, var);
1259 value = ast_variable_retrieve(phoneprov_cfg,
"general", pp_general_lookup[AST_PHONEPROV_STD_PROFILE]);
1261 ast_log(LOG_ERROR,
"Unable to load default profile.\n");
1263 ast_var_list_destroy(defaults);
1266 var = ast_var_assign(variable_lookup[AST_PHONEPROV_STD_PROFILE], value);
1267 AST_VAR_LIST_INSERT_TAIL(defaults, var);
1270 if (!(cfg =
ast_config_load(
"users.conf", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
1271 ast_log(LOG_ERROR,
"Unable to load users.conf\n");
1272 ast_var_list_destroy(defaults);
1277 for (v = ast_variable_browse(cfg,
"general"); v; v = v->
next) {
1278 if (!strcasecmp(v->
name, pp_user_lookup[AST_PHONEPROV_STD_VOICEMAIL_EXTEN])) {
1279 var = ast_var_assign(variable_lookup[AST_PHONEPROV_STD_VOICEMAIL_EXTEN], v->
value);
1280 AST_VAR_LIST_INSERT_TAIL(defaults, var);
1282 if (!strcasecmp(v->
name, pp_user_lookup[AST_PHONEPROV_STD_EXTENSION_LENGTH])) {
1283 var = ast_var_assign(variable_lookup[AST_PHONEPROV_STD_EXTENSION_LENGTH], v->
value);
1284 AST_VAR_LIST_INSERT_TAIL(defaults, var);
1298 struct varshead *defaults = get_defaults();
1301 ast_log(LOG_WARNING,
"Unable to load default variables.\n");
1306 || cfg == CONFIG_STATUS_FILEINVALID) {
1307 ast_log(LOG_WARNING,
"Unable to load users.conf\n");
1308 ast_var_list_destroy(defaults);
1319 if (strcasecmp(cat,
"general") && strcasecmp(cat,
"authentication")) {
1320 struct varshead *variables = ast_var_list_create();
1322 if (!((tmp = ast_variable_retrieve(cfg, cat,
"autoprov")) &&
ast_true(tmp))) {
1323 ast_var_list_destroy(variables);
1328 for (i = 0; i < AST_PHONEPROV_STD_VAR_LIST_LENGTH; i++) {
1329 if (pp_user_lookup[i]) {
1330 value = ast_variable_retrieve(cfg, cat, pp_user_lookup[i]);
1332 varx = ast_var_assign(variable_lookup[i],
1334 AST_VAR_LIST_INSERT_TAIL(variables, varx);
1339 if (!ast_var_find(variables, variable_lookup[AST_PHONEPROV_STD_MAC])) {
1340 ast_log(LOG_WARNING,
"autoprov set for %s, but no mac address - skipping.\n", cat);
1341 ast_var_list_destroy(variables);
1346 AST_VAR_LIST_TRAVERSE(defaults, vard) {
1347 if (ast_var_find(variables, vard->name)) {
1350 varx = ast_var_assign(vard->name, vard->value);
1351 AST_VAR_LIST_INSERT_TAIL(variables, varx);
1358 ast_var_list_destroy(defaults);
1362 static int load_common(
void)
1368 if (!(phoneprov_cfg =
ast_config_load(
"phoneprov.conf", config_flags))
1369 || phoneprov_cfg == CONFIG_STATUS_FILEINVALID) {
1370 ast_log(LOG_ERROR,
"Unable to load config phoneprov.conf\n");
1376 if (!strcasecmp(cat,
"general")) {
1379 build_profile(cat, ast_variable_browse(phoneprov_cfg, cat));
1384 ast_log(LOG_ERROR,
"There are no provisioning profiles in phoneprov.conf.\n");
1391 static int unload_module(
void)
1403 ao2_cleanup(profiles);
1407 ao2_cleanup(http_routes);
1412 ao2_cleanup(providers);
1431 phone_profile_hash_fn, NULL, phone_profile_cmp_fn);
1433 ast_log(LOG_ERROR,
"Unable to allocate profiles container.\n");
1438 http_route_hash_fn, NULL, http_route_cmp_fn);
1440 ast_log(LOG_ERROR,
"Unable to allocate routes container.\n");
1444 if (load_common()) {
1445 ast_log(LOG_ERROR,
"Unable to load provisioning profiles.\n");
1450 user_hash_fn, NULL, user_cmp_fn);
1452 ast_log(LOG_ERROR,
"Unable to allocate users container.\n");
1457 MAX_PROVIDER_BUCKETS, phoneprov_provider_hash_fn, NULL, phoneprov_provider_cmp_fn);
1459 ast_log(LOG_ERROR,
"Unable to allocate providers container.\n");
1465 ast_log(LOG_WARNING,
"Unable register users config provider. Others may succeed.\n");
1481 static int reload(
void)
1484 struct phoneprov_provider *provider;
1492 if (load_common()) {
1493 ast_log(LOG_ERROR,
"Unable to reload provisioning profiles.\n");
1499 ao2_lock(providers);
1501 for(; (provider = ao2_iterator_next(&i));
ao2_ref(provider, -1)) {
1502 if (provider->load_users()) {
1503 ast_log(LOG_ERROR,
"Unable to load provider '%s' users. Reload aborted.\n", provider->provider_name);
1508 ao2_unlock(providers);
1513 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER,
"HTTP Phone Provisioning",
1514 .support_level = AST_MODULE_SUPPORT_EXTENDED,
1516 .unload = unload_module,
1526 if (var >= AST_PHONEPROV_STD_VAR_LIST_LENGTH) {
1530 return variable_lookup[var];
1536 struct phoneprov_provider *provider;
1538 if (ast_strlen_zero(provider_name)) {
1539 ast_log(LOG_ERROR,
"Provider name can't be empty.\n");
1544 ast_log(LOG_WARNING,
"Provider '%s' cannot be registered: res_phoneprov not loaded.\n", provider_name);
1548 provider = find_provider(provider_name);
1550 ast_log(LOG_ERROR,
"There is already a provider registered named '%s'.\n", provider_name);
1555 provider = ao2_alloc(
sizeof(
struct phoneprov_provider), provider_destructor);
1557 ast_log(LOG_ERROR,
"Unable to allocate sufficient memory for provider '%s'.\n", provider_name);
1563 ast_log(LOG_ERROR,
"Unable to allocate sufficient memory for provider '%s' stringfields.\n", provider_name);
1573 if (provider->load_users()) {
1574 ast_log(LOG_ERROR,
"Unable to load provider '%s' users. Register aborted.\n", provider_name);
1582 static int extensions_delete_cb(
void *obj,
void *arg,
int flags)
1584 char *provider_name = arg;
1585 struct user *user = obj;
1592 static int extension_delete_cb(
void *obj,
void *arg,
void *data,
int flags)
1594 struct user *user = obj;
1595 char *provider_name = data;
1596 char *macaddress = arg;
1611 extension_delete_cb, macaddress, provider_name);
1635 RAII_VAR(
struct phoneprov_provider *, provider, NULL, ao2_cleanup);
1636 RAII_VAR(
struct user *, user, NULL, ao2_cleanup);
1637 RAII_VAR(
struct phone_profile *, profile, NULL, ao2_cleanup);
1638 struct extension *exten;
1643 if (ast_strlen_zero(provider_name)) {
1644 ast_log(LOG_ERROR,
"Provider name can't be empty.\n");
1648 ast_log(LOG_ERROR,
"Variable list can't be empty.\n");
1652 username = ast_var_find(vars, variable_lookup[AST_PHONEPROV_STD_USERNAME]);
1654 ast_log(LOG_ERROR,
"Extension name can't be empty.\n");
1658 mac = ast_var_find(vars, variable_lookup[AST_PHONEPROV_STD_MAC]);
1660 ast_log(LOG_ERROR,
"MAC Address can't be empty.\n");
1664 provider = find_provider(provider_name);
1666 ast_log(LOG_ERROR,
"Provider '%s' wasn't found in the registry.\n", provider_name);
1670 profile_name = ast_var_find(vars,
1671 variable_lookup[AST_PHONEPROV_STD_PROFILE]);
1672 if (!profile_name) {
1673 ast_log(LOG_ERROR,
"No profile could be found for user '%s' - skipping.\n", username);
1677 ast_log(LOG_ERROR,
"Could not look up profile '%s' - skipping.\n", profile_name);
1683 if (!(user =
build_user(mac, profile, provider_name))) {
1684 ast_log(LOG_ERROR,
"Could not create user for '%s' - skipping\n", mac);
1688 if (!(exten = build_extension(username, vars))) {
1689 ast_log(LOG_ERROR,
"Could not create extension for '%s' - skipping\n", user->
macaddress);
1694 ast_log(LOG_WARNING,
"Could not add extension '%s' to user '%s'\n", exten->name, user->
macaddress);
1695 exten = delete_extension(exten);
1700 ast_log(LOG_WARNING,
"Could not create http routes for '%s' - skipping\n", user->
macaddress);
1707 ast_log(LOG_ERROR,
"MAC address '%s' was already added by provider '%s' - skipping\n", user->
macaddress, user->
provider_name);
1711 if (!(exten = build_extension(username, vars))) {
1712 ast_log(LOG_ERROR,
"Could not create extension for '%s' - skipping\n", user->
macaddress);
1717 ast_log(LOG_WARNING,
"Could not add extension '%s' to user '%s'\n", exten->name, user->
macaddress);
1718 exten = delete_extension(exten);
const ast_string_field staticdir
struct ast_variable * next
static void build_route(struct phoneprov_file *pp_file, struct phone_profile *profile, struct user *user, char *uri)
Build a route structure and add it to the list of available http routes.
Main Channel structure associated with a channel.
Asterisk main include file. File version handling, generic pbx functions.
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
static void build_profile(const char *name, struct ast_variable *v)
Build a phone profile and add it to the list of phone profiles.
int ast_phoneprov_provider_register(char *provider_name, ast_phoneprov_load_users_cb load_users)
Registers a config provider to phoneprov.
void ast_http_error(struct ast_tcptls_session_instance *ser, int status, const char *title, const char *text)
Send HTTP error message and close socket.
String manipulation functions.
Asterisk version information.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
The arg parameter is a search key, but is not an object.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
const ast_string_field format
#define SIMPLE_HASH_FN(fname, stype, field)
Creates a hash function for a structure string field.
descriptor for a cli entry.
void ast_phoneprov_delete_extensions(char *provider_name)
Deletes all extensions for this provider.
int ast_http_uri_link(struct ast_http_uri *urihandler)
Register a URI handler.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
const char * ast_http_ftype2mtype(const char *ftype) attribute_pure
Return mime type based on extension.
const ast_string_field template
static int pp_each_extension_helper(struct ast_channel *chan, const char *cmd, char *data, char *buf, struct ast_str **bufstr, int len)
A dialplan function that can be used to output a template for each extension attached to a user...
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Structure for variables, used for configurations and for channel variables.
static void delete_profiles(void)
Delete all phone profiles, freeing their memory.
static void delete_routes(void)
Delete all http routes, freeing their memory.
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
void ast_http_uri_unlink(struct ast_http_uri *urihandler)
Unregister a URI handler.
#define ast_calloc_with_stringfields(n, type, size)
Allocate a structure with embedded stringfields in a single allocation.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
int ast_iostream_get_fd(struct ast_iostream *stream)
Get an iostream's file descriptor.
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
static int build_user_routes(struct user *user)
Add an http route for dynamic files attached to the profile of the user.
static void delete_providers(void)
Delete all providers.
const ast_string_field uri
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
struct phoneprov_file * file
struct phone_profile::@454 static_files
structure to hold file data
list of users found in the config file
void ast_http_send(struct ast_tcptls_session_instance *ser, enum ast_http_method method, int status_code, const char *status_title, struct ast_str *http_header, struct ast_str *out, int fd, unsigned int static_content)
Generic function for sending HTTP/1.1 response.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
static struct user * find_user(const char *macaddress)
Return a user looked up by name.
const ast_string_field default_mime_type
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
static void set_timezone_variables(struct varshead *headp, const char *zone)
Set all timezone-related variables based on a zone (i.e. America/New_York)
#define SIMPLE_CMP_FN(fname, stype, field)
Creates a compare function for a structure string field.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Configuration File Parser.
Support for Private Asterisk HTTP Servers.
structure to hold config providers
#define ast_config_load(filename, flags)
Load a config file.
int ast_build_string(char **buffer, size_t *space, const char *fmt,...)
Build a string in a buffer, designed to be called repeatedly.
static int load_module(void)
Load the module.
General Asterisk PBX channel definitions.
Asterisk file paths, configured in asterisk.conf.
static struct user * build_user(const char *mac, struct phone_profile *profile, char *provider_name)
Build and return a user structure based on gathered config data.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Data structure associated with a custom dialplan function.
Access Control of various sorts.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
#define AST_STRING_FIELD(name)
Declare a string field.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
structure to hold extensions
#define ast_malloc(len)
A wrapper for malloc()
struct phone_profile * profile
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
const ast_string_field name
static int load_file(const char *filename, char **ret)
Read a TEXT file into a string and return the length.
Core PBX routines and definitions.
describes a server instance
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
static char * handle_show_routes(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command to list static and dynamic routes.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Support for dynamic strings.
void ast_str_substitute_variables_varshead(struct ast_str **buf, ssize_t maxlen, struct varshead *headp, const char *templ)
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the 'nonstandard' argument separation process for an application.
const ast_string_field provider_name
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
const char * ast_inet_ntoa(struct in_addr ia)
thread-safe replacement for inet_ntoa().
structure to hold phone profiles read from phoneprov.conf
static void user_destructor(void *obj)
Free all memory associated with a user.
Module has failed to load, may be in an inconsistent state.
int ast_phoneprov_add_extension(char *provider_name, struct varshead *vars)
Adds an extension.
structure to hold users read from users.conf
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Structure used to handle boolean flags.
struct ast_iostream * stream
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Standard Command Line Interface.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition of a URI handler.
void ast_phoneprov_provider_unregister(char *provider_name)
Unegisters a config provider from phoneprov and frees its resources.
static int load_users(void)
Callback that loads the users from phoneprov sections.
const ast_string_field macaddress
static void delete_users(void)
Delete all users.
static int add_user_extension(struct user *user, struct extension *exten)
Add an extension to a user ordered by index/linenumber.
Options provided by main asterisk program.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
ast_http_method
HTTP Request methods known by Asterisk.
#define AST_LIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list entry before the current entry during a traversal.
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
structure to hold http routes (valid URIs, and the files they link to)
static int pp_each_user_helper(struct ast_channel *chan, char *data, char *buf, struct ast_str **bufstr, int len)
A dialplan function that can be used to print a string for each phoneprov user.
#define ASTERISK_GPL_KEY
The text the key() function should return.
const char * ast_phoneprov_std_variable_lookup(enum ast_phoneprov_std_variables var)
Returns the string respresentation of a phoneprov standard variable.
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
static struct phone_profile * find_profile(const char *name)
Return a phone profile looked up by name.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
struct phone_profile::@455 dynamic_files
#define ast_custom_function_register(acf)
Register a custom function.
void ast_phoneprov_delete_extension(char *provider_name, char *macaddress)
Deletes an extension.
static struct in_addr __ourip
for use in lookup_iface
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
const ast_string_field mime_type
#define AST_APP_ARG(name)
Define an application argument.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
static int phoneprov_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers)
Callback that is executed everytime an http request is received by this module.
#define ao2_link(container, obj)
Add an object to a container.