]> git.defcon.no Git - hermes/blob - api/user.php
0dcd23cf1a53505ce9bb49484cd68927e71f8932
[hermes] / api / user.php
1 <?php
2 require_once('config.php');
3 require_once('lib/auth_base.php');
4 require_once('lib/user_functions.php');
5 require_once('lib/common_functions.php');
6 require_once('lib/db_functions.php');
7 require_once('lib/phone_functions.php');
8 require_once('lib/alias_functions.php');
9
10 $config = get_config();
11
12 $config['sql_link'] = @mysql_connect(
13 $config['sql_server'],
14 $config['sql_username'],
15 $config['sql_password']
16 );
17 if ( !$config['sql_link'] )
18 {
19 print json_encode( array( 'response' => 'failed', 'cause' => 'error', 'detail' => 'Database connection failed.'));
20 exit;
21 }
22 token_auth();
23
24 //*************************************************************************************
25 switch ( $_SERVER['PATH_INFO'] )
26 {
27 case "/get":
28 // Required GET parameters:
29 // user: authentication username, SIP-username without domain component
30 // domain: Domain/realm of the user. username + '@' + domain == SIP address.
31
32 if ( array_key_exists('user', $_POST) ||
33 ( array_key_exists('username', $_POST) && array_key_exists('domain', $_POST )))
34 {
35 $username = "";
36 $domain = "";
37 if ( array_key_exists('username', $_POST) )
38 {
39 $username = $_POST['username'];
40 $domain = $_POST['domain'];
41 }
42 else
43 {
44 $user = split_sipaddress($_POST['user']);
45 if ( !$user )
46 {
47 print json_encode ( array( 'response' => 'failed', 'cause' => 'invalid', 'detail' => 'Invalid SIP address') );
48 break;
49 }
50 list ( $username, $domain ) = $user;
51 }
52
53 // Now, do funky stuff.
54 /*
55 Test if user exists in both 'kamailio.subscribers' and 'hermes.users'
56 * Return 'response' => 'ok', 'type' => 'local', 'user' => complete user object.
57 Test if user exists in 'hermes.user' only
58 * Return 'response' => 'ok', 'type' => 'remote', 'user' => complete user object.
59 If user does is neither local nor remote
60 * Return 'response' => 'failed' with 'cause' => 'nonexistant'
61 On failure, return 'response' => 'failed' with 'cause' => 'error' (may set 'detail' => 'message')
62
63 */
64 // Dummy-response:
65 $userdata = get_userdata( $username, $domain );
66 if ( $userdata )
67 {
68 print json_encode( array( 'response' => 'ok', 'user' => $userdata ));
69 }
70 else
71 {
72 print json_encode( array ( 'response' => 'failed', 'cause' => 'nonexistant', 'detail' => 'Request for user ' . $username . '@' . $domain . ' failed.'));
73 }
74 }
75 else
76 print json_encode ( array( 'response' => 'invalid') );
77 break;
78 case "/list":
79 /*
80 Simply list all users in user@domain format
81 Perform a search operation if 'search' exists as a GET-parameter
82 * The search should try to do a "smart search" on SIP-usernames:
83 * Try to search with names in in username@domain format
84 * Do the search with wildcards before and after input text.
85 * The search must be done in the provisioning tables, to be able
86 to match non-local users.
87 * SQL SELECT CONCAT() WHERE CONCAT() must be used *shrug*
88 */
89 $search = null;
90 if ( array_key_exists ( 'search', $_POST ) )
91 $search = $_POST['search']; // TODO: Add some sanitation and input validation!
92 $list = list_users( $search );
93 print json_encode( array( 'response' => 'ok', 'list' => $list ));
94 break;
95 case "/add_local":
96 /*
97 What to do??
98 Required parameters should be...
99 ( username & domain ) | user
100 displayname
101 email
102
103 Verify that domain is local (lookup in the 'kamailio.domain' table.
104 Verify that the username is available (nonexistant for domain in kamilio.subscribers (and hermes.users?))
105 * Autocreate password
106 * Add username, domain, email and created password to the 'kamailio.subscriber' table
107 * Get the registrar+port, proxy+port from the 'hermes.servers' table.
108 * standard dialplan from configuration.
109 * Add to the 'hermes.users' table:
110 username -> username
111 password -> generated password
112 displayname -> displayname
113 domain -> domain
114 registrar -> hermes.servers.registrar
115 r_port -> hermes.servers.r_port
116 proxy -> hermes.servers.proxy
117 p_port -> hermes.servers.p_port
118 authid -> username
119 dialplan -> standard dialplan
120 linetext -> username
121 * Return 'response' => 'ok' with a full user object in JSON format.
122 If any of the tests fail, return 'response' => 'failed' with 'cause' => "description" on JSON format.
123
124 */
125 // Test required parameters:
126 if (
127 ( ( array_key_exists( 'username', $_POST) && array_key_exists( 'domain', $_POST ) ) || array_key_exists('user', $_POST) )
128 && array_key_exists( 'displayname', $_POST )
129 && array_key_exists( 'email', $_POST ) )
130 {
131 $username = "";
132 $domain = "";
133 if ( array_key_exists('username', $_POST) )
134 {
135 $username = $_POST['username'];
136 $domain = $_POST['domain'];
137 }
138 else
139 {
140 $user = split_sipaddress($_POST['user']);
141 if ( !$user )
142 {
143 print json_encode ( array( 'response' => 'failed', 'cause' => 'invalid', 'detail' => 'Invalid SIP address') );
144 break;
145 }
146 list ( $username, $domain ) = $user;
147 }
148
149 $password = generate_password();
150 $displayname = $_POST['displayname'];
151 $email = $_POST['email'];
152
153 if ( !is_kamailio_domain( $domain ) )
154 {
155 print json_encode ( array( 'response' => 'failed', 'cause' => 'nxdomain', 'detail' => 'The selected domain is not local' ));
156 break;
157 }
158
159 $servers = get_servers( $domain );
160 if ( !$servers )
161 {
162 print json_encode( array( 'response' => 'failed', 'cause' => 'servfail', 'detail' => 'Servers lookup failed for domain '. $domain ) );
163 break;
164 }
165 $registrar = $servers['registrar'];
166 $r_port = $servers['r_port'];
167 $proxy = $servers['proxy'];
168 $p_port = $servers['p_port'];
169 $authid = $username;
170 $linetext = $username;
171 $dialplan = $config['standard_dialplan'];
172
173 if ( is_provision_user ( $username, $domain ) )
174 {
175 print json_encode ( array( 'response' => 'failed', 'cause' => 'exists', 'detail' => 'User already exists in provisioning configuration' ));
176 break;
177 }
178 if ( is_kamailio_subscriber ( $username, $domain ) )
179 {
180 print json_encode ( array( 'response' => 'failed', 'cause' => 'exists', 'detail' => 'User already exists as a Kamailio subscriber' ));
181 break;
182 }
183 if ( alias_exists ( $username, $domain ) )
184 {
185 print json_encode ( array( 'response' => 'failed', 'cause' => 'exists', 'detail' => 'Username exists as an alias' ));
186 break;
187 }
188
189 $kam_res = add_kamailio_subscriber( $username, $domain, $password, $email );
190 if ( !$kam_res )
191 {
192 print json_encode( array( 'response' => 'failed', 'cause' => 'dbfail', 'detail' => 'Failed to add kamailio subscriber.' ) );
193 break;
194 }
195 $pro_res = add_provision_user( $username, $password, $domain, $authid, $registrar, $r_port, $proxy, $p_port, $displayname, $dialplan, $linetext );
196 if ( !$pro_res )
197 {
198 // Rollback data added to Kamailio! Try to simulate atomicity, or atleast maintain integrity...
199 delete_kamailio_subscriber( $username, $domain );
200 // Give errormessage, and quit.
201 print json_encode( array( 'response' => 'failed', 'cause' => 'dbfail', 'detail' => 'Failed to add user for provisioning. Rolled back kamailio subscriber' ) );
202 break;
203 }
204 $userdata = get_userdata( $username, $domain );
205 if ( !$userdata )
206 {
207 // Rollback data added to Kamailio! Try to simulate atomicity, or atleast maintain integrity...
208 delete_kamailio_subscriber( $username, $domain );
209 delete_provision_user( $username, $domain );
210 // Give errormessage, and quit.
211 print json_encode( array( 'response' => 'failed', 'cause' => 'dbfail', 'detail' => 'Failed to read recently added data. Operations rolled back' ) );
212
213 }
214 print json_encode( array( 'response' => 'ok', 'user' => $userdata ));
215 }
216 else
217 print json_encode( array( 'response' => 'invalid', 'cause' => 'parameters' ) );
218 break;
219 case "/add_remote":
220 /*
221 Required parameters should be...
222 ( username & domain ) | user
223 displayname
224 password
225 registrar
226 Optional parameters
227 r_port
228 proxy
229 p_port
230 authid
231 dialplan
232 linetext
233
234 Verify that the domain is not a local kamailio domain (REMOTE user..)
235 Verify that the username+domain is not already registered in 'hermes.users'.
236 * If r_port is empty, set to 5060
237 * If proxy/port is empty, set to registrar/port
238 * If authid is empty, set to username
239 * If dialplan is empty, set to standard dialplan
240 * If linetext is empty, set to username@domain
241 * Add to the 'hermes.users' table:
242 username -> username
243 password -> supplied password
244 displayname -> displayname
245 domain -> domain
246 registrar -> registrar
247 r_port -> r_port
248 proxy -> proxy
249 p_port -> p_port
250 authid -> authid
251 dialplan -> dialplan
252 linetext -> linetext
253 * Return 'response' => 'ok' with a full user object in JSON format.
254 If any of the tests fail, return 'response' => 'failed' with 'cause' => "description" in JSON format.
255 */
256
257
258 // Test required parameters:
259 if (
260 ( ( array_key_exists( 'username', $_POST) && array_key_exists( 'domain', $_POST ) ) || array_key_exists('user', $_POST) )
261 && array_key_exists( 'displayname', $_POST )
262 && array_key_exists( 'password', $_POST )
263 && array_key_exists( 'registrar', $_POST ) )
264 {
265 $username = "";
266 $domain = "";
267 if ( array_key_exists('username', $_POST) )
268 {
269 $username = $_POST['username'];
270 $domain = $_POST['domain'];
271 }
272 else
273 {
274 $user = split_sipaddress($_POST['user']);
275 if ( !$user )
276 {
277 print json_encode ( array( 'response' => 'failed', 'cause' => 'invalid', 'detail' => 'Invalid SIP address') );
278 break;
279 }
280 list ( $username, $domain ) = $user;
281 }
282
283 $password = $_POST['password'];
284 $displayname = $_POST['displayname'];
285 $registrar = $_POST['registrar'];
286 $r_port = ( array_key_exists('r_port', $_POST) ) ? $_POST['r_port'] : 5060;
287
288 $proxy = ( array_key_exists('proxy', $_POST) ) ? $_POST['proxy'] : $registrar;
289 $p_port = ( array_key_exists('p_port', $_POST) ) ? $_POST['p_port'] : $r_port;
290 $authid = ( array_key_exists('authid', $_POST) ) ? $_POST['authid'] : $username;
291 $dialplan = ( array_key_exists('dialplan', $_POST) ) ? $_POST['dialplan'] : $config['standard_dialplan'];
292 $linetext = ( array_key_exists('linetext', $_POST) ) ? $_POST['linetext'] : $username . '@' . $domain;
293
294 if ( is_kamailio_domain( $domain ) )
295 {
296 print json_encode ( array( 'response' => 'failed', 'cause' => 'domain', 'detail' => 'The selected domain is local, cannot add remote user' ));
297 break;
298 }
299
300 if ( is_provision_user ( $username, $domain ) )
301 {
302 print json_encode ( array( 'response' => 'failed', 'cause' => 'exists', 'detail' => 'User already exists in provisioning configuration' ));
303 break;
304 }
305 if ( is_kamailio_subscriber ( $username, $domain ) )
306 {
307 print json_encode ( array( 'response' => 'failed', 'cause' => 'exists', 'detail' => 'User already exists as a Kamailio subscriber' ));
308 break;
309 }
310
311 // Should be impossible to hit this test, all aliases are required to be local.
312 if ( alias_exists ( $username, $domain ) )
313 {
314 print json_encode ( array( 'response' => 'failed', 'cause' => 'exists', 'detail' => 'Username exists as an alias' ));
315 break;
316 }
317
318
319 $pro_res = add_provision_user( $username, $password, $domain, $authid, $registrar, $r_port, $proxy, $p_port, $displayname, $dialplan, $linetext );
320 if ( !$pro_res )
321 {
322 // Give errormessage, and quit.
323 print json_encode( array( 'response' => 'failed', 'cause' => 'dbfail', 'detail' => 'Failed to add user for provisioning.' ) );
324 break;
325 }
326 $userdata = get_userdata( $username, $domain );
327 if ( !$userdata )
328 {
329 // Rollback data added!
330 delete_provision_user( $username, $domain );
331 // Give errormessage, and quit.
332 print json_encode( array( 'response' => 'failed', 'cause' => 'dbfail', 'detail' => 'Failed to read recently added data. Operations rolled back' ) );
333
334 }
335 print json_encode( array( 'response' => 'ok', 'user' => $userdata ));
336 }
337 else
338 print json_encode( array( 'response' => 'invalid', 'cause' => 'parameters' ) );
339 break;
340 case "/remove":
341 /*
342 Required parameters should be...
343 ( username & domain ) | user
344
345 * Verify that no associations/relations exist in 'hermes.phones'
346 * Verify that the user exists in 'hermes.users'
347 * Remove from 'hermes.users'
348 * Test to see of user exists in 'kamailio.subscriber'.
349 * Remove from 'kamailio.subscribers'
350 * Return response' => 'ok', 'type' => 'local'
351 * If not in 'kamailio.subscribers'
352 * Return response' => 'ok', 'type' => 'remote'
353 * If associations exist, return 'response' => 'failed', 'cause' => 'inuse'
354 * If no such user exists, return 'response' => 'failed' with 'cause' => 'nonexistant'
355 * On other failures, return 'response' => 'failed' with 'cause' => 'error' (may set 'detail' => 'message')
356 */
357 if ( ( array_key_exists( 'username', $_POST) && array_key_exists( 'domain', $_POST ) )
358 || array_key_exists('user', $_POST) )
359
360 {
361 $username = "";
362 $domain = "";
363 if ( array_key_exists('username', $_POST) )
364 {
365 $username = $_POST['username'];
366 $domain = $_POST['domain'];
367 }
368 else
369 {
370 $user = split_sipaddress($_POST['user']);
371 if ( !$user )
372 {
373 print json_encode ( array( 'response' => 'failed', 'cause' => 'invalid', 'detail' => 'Invalid SIP address') );
374 break;
375 }
376 list ( $username, $domain ) = $user;
377 }
378
379 if ( get_user_phones ( $username, $domain ) )
380 {
381 print json_encode( array( 'response' => 'failed', 'cause' => 'inuse', 'detail' => 'User has associated provisioning. Remove and retry.' ) );
382 break;
383 }
384 if ( is_provision_user( $username, $domain ) || is_kamailio_subscriber( $username, $domain ) )
385 {
386 delete_provision_user( $username, $domain );
387 delete_kamailio_subscriber( $username, $domain );
388 print json_encode( array ( 'response' => 'ok', 'detail' => 'User ' . $username . '@' . $domain . ' deleted.'));
389 break;
390 }
391 else
392 {
393 print json_encode( array ( 'response' => 'failed', 'cause' => 'nonexistant', 'detail' => 'Unable to remove nonexistant user.'));
394 break;
395 }
396
397 break;
398
399 }
400 print json_encode ( array( 'response' => 'invalid') );
401 break;
402 case "/change_pw":
403 /*
404 Required parameters should be...
405 ( username & domain ) | user
406 password
407
408 * Verify that no associations/relations exist in 'hermes.phones'
409 * Verify that the user exists ...
410 * Test to see of user exists in 'hermes.users'
411 * Test to see of user exists in 'kamailio.subscriber'.
412 * If no such user exists, return 'response' => 'failed' with 'cause' => 'nonexistant'
413 * Update user passwords in 'hermes' and 'kamailio' as appropriate
414 * On other failures, return 'response' => 'failed' with 'cause' => 'error' (may set 'detail' => 'message')
415 */
416 if ( array_key_exists('password', $_POST) &&
417 ( ( array_key_exists( 'username', $_POST) && array_key_exists( 'domain', $_POST ) )
418 || array_key_exists('user', $_POST) ))
419
420 {
421 $username = "";
422 $domain = "";
423 if ( array_key_exists('username', $_POST) )
424 {
425 $username = $_POST['username'];
426 $domain = $_POST['domain'];
427 }
428 else
429 {
430 $user = split_sipaddress($_POST['user']);
431 if ( !$user )
432 {
433 print json_encode ( array( 'response' => 'failed', 'cause' => 'invalid', 'detail' => 'Invalid SIP address') );
434 break;
435 }
436 list ( $username, $domain ) = $user;
437 }
438 $password = $_POST['password'];
439
440 // Check compatibility of password? TODO...
441 // Fetch old password for rollback? TODO...
442 // Verify that user exists for provisioning
443 if ( ! is_provision_user( $username, $domain ) )
444 {
445 print json_encode( array ( 'response' => 'failed', 'cause' => 'nonexistant', 'detail' => '' . $username . '@' . $domain . ' does not exist.'));
446 break;
447 }
448 if ( is_provision_user( $username, $domain ) )
449 {
450 // Update provisioning password
451 if ( update_provision_pw( $username, $domain, $password ) < 0 )
452 {
453 print json_encode( array( 'response' => 'failed', 'cause' => 'dbfail', 'detail' => 'Failed to update provisioning password' ) );
454 break;
455 }
456 }
457 // Check for user in kamailio
458 if ( is_kamailio_subscriber( $username, $domain ) )
459 {
460 // Update kamailio password
461 if ( update_kamailio_pw( $username, $domain, $password ) < 0 )
462 {
463 print json_encode( array( 'response' => 'failed', 'cause' => 'dbfail', 'detail' => 'Failed to update kamailio password' ) );
464 break;
465 }
466 }
467 print json_encode( array ( 'response' => 'ok', 'detail' => 'Password changed for user '.$username.'@'.$domain.'.'));
468 break;
469 }
470 else
471 print json_encode( array( 'response' => 'invalid', 'cause' => 'parameters' ) );
472 break;
473
474
475 case "/change_email":
476 /*
477 Required parameters should be...
478 ( username & domain ) | user
479 email
480 */
481 if ( array_key_exists('email', $_POST) &&
482 ( ( array_key_exists( 'username', $_POST) && array_key_exists( 'domain', $_POST ) )
483 || array_key_exists('user', $_POST) ))
484
485 {
486 $username = "";
487 $domain = "";
488 if ( array_key_exists('username', $_POST) )
489 {
490 $username = $_POST['username'];
491 $domain = $_POST['domain'];
492 }
493 else
494 {
495 $user = split_sipaddress($_POST['user']);
496 if ( !$user )
497 {
498 print json_encode ( array( 'response' => 'failed', 'cause' => 'invalid', 'detail' => 'Invalid SIP address') );
499 break;
500 }
501 list ( $username, $domain ) = $user;
502 }
503 $email = $_POST['email'];
504
505 // Check for user in kamailio
506 if ( is_kamailio_subscriber( $username, $domain ) )
507 {
508 // Update kamailio email
509 if ( update_kamailio_email( $username, $domain, $email ) < 0 )
510 {
511 print json_encode( array( 'response' => 'failed', 'cause' => 'dbfail', 'detail' => 'Failed to update kamailio email' ) );
512 break;
513 }
514 }
515 print json_encode( array ( 'response' => 'ok', 'user' => $username.'@'.$domain, 'email' => $email));
516 break;
517 }
518 else
519 print json_encode( array( 'response' => 'invalid', 'cause' => 'parameters' ) );
520 break;
521
522
523
524
525
526
527
528 case "/update":
529 /*
530 Required parameters should be...
531 ( username & domain ) | user
532
533 * Verify that no associations/relations exist in 'hermes.phones'
534 * Verify that the user exists ...
535 * Test to see of user exists in 'hermes.users'
536 * Test to see of user exists in 'kamailio.subscriber'.
537 * If no such user exists, return 'response' => 'failed' with 'cause' => 'nonexistant'
538 * Get update parameters, and change as appropriate ;)
539 * On other failures, return 'response' => 'failed' with 'cause' => 'error' (may set 'detail' => 'message')
540 */
541 if ( ( array_key_exists( 'username', $_POST) && array_key_exists( 'domain', $_POST ) )
542 || array_key_exists('user', $_POST) )
543
544 {
545 $username = "";
546 $domain = "";
547 if ( array_key_exists('username', $_POST) )
548 {
549 $username = $_POST['username'];
550 $domain = $_POST['domain'];
551 }
552 else
553 {
554 $user = split_sipaddress($_POST['user']);
555 if ( !$user )
556 {
557 print json_encode ( array( 'response' => 'failed', 'cause' => 'invalid', 'detail' => 'Invalid SIP address') );
558 break;
559 }
560 list ( $username, $domain ) = $user;
561 }
562 if ( ! is_provision_user ( $username, $domain ) )
563 {
564 print json_encode( array ( 'response' => 'failed', 'cause' => 'nonexistant', 'detail' => '' . $username . '@' . $domain . ' does not exist.'));
565 break;
566 }
567 $updated = array();
568 $failed = array();
569 $error = 1;
570 $result_text = "";
571 $params = array('displayname', 'dialplan', 'linetext', 'registrar', 'r_port', 'proxy', 'p_port');
572 foreach ( $params as $p )
573 {
574 if ( array_key_exists($p, $_POST ) )
575 {
576 $data = $_POST[$p];
577 $t = update_provision_data($p, $username, $domain, $data);
578 if ( $t != true )
579 {
580 $error = $t;
581 array_push($failed, $p);
582 }
583 else
584 {
585 array_push( $updated, $p);
586 }
587 }
588 }
589 $res = array();
590 if ( ( $error == 1 ) || ( $error == 0 ) )
591 {
592 $res['response'] = 'ok';
593 $res['skipped'] = $failed;
594 }
595 else if ( $error == -1 )
596 {
597 $res['response'] = 'failed';
598 $res['cause'] = 'param';
599 $res['detail'] = 'Invalid parameters';
600 $res['failed'] = $failed;
601 }
602 else if ( $error == -2 )
603 {
604 $res['response'] = 'failed';
605 $res['cause'] = 'dbfail';
606 $res['detail'] = 'Database failure';
607 $res['failed'] = $failed;
608 }
609 else
610 $res['response'] = 'error'; // Wait, what?
611
612 $res['updated'] = $updated;
613
614 print json_encode ( $res );
615 }
616 else
617 print json_encode( array( 'response' => 'invalid', 'cause' => 'parameters' ) );
618 break;
619 case "/available":
620 if ( ( array_key_exists( 'username', $_POST) && array_key_exists( 'domain', $_POST ) )
621 || array_key_exists('user', $_POST) )
622
623 {
624 $username = "";
625 $domain = "";
626 if ( array_key_exists('username', $_POST) )
627 {
628 $username = $_POST['username'];
629 $domain = $_POST['domain'];
630 }
631 else
632 {
633 $user = split_sipaddress($_POST['user']);
634 if ( !$user )
635 {
636 print json_encode ( array( 'response' => 'failed', 'cause' => 'invalid', 'detail' => 'Invalid SIP address') );
637 break;
638 }
639 list ( $username, $domain ) = $user;
640 }
641 if ( is_provision_user ( $username, $domain ) )
642 {
643 print json_encode ( array( 'response' => 'failed', 'cause' => 'exists', 'detail' => 'User already exists in provisioning configuration' ));
644 break;
645 }
646 if ( is_kamailio_subscriber ( $username, $domain ) )
647 {
648 print json_encode ( array( 'response' => 'failed', 'cause' => 'exists', 'detail' => 'User already exists as a Kamailio subscriber' ));
649 break;
650 }
651 if ( alias_exists ( $username, $domain ) )
652 {
653 print json_encode ( array( 'response' => 'failed', 'cause' => 'exists', 'detail' => 'Username exists as an alias' ));
654 break;
655 }
656 print json_encode( array ( 'response' => 'ok', 'cause' => 'nonexistant', 'detail' => '' . $username . '@' . $domain . ' does not exist.'));
657
658 }
659 else
660 print json_encode( array( 'response' => 'invalid', 'cause' => 'parameters' ) );
661 break;
662 case "/gen_pw":
663 print generate_password();
664 break;
665 default:
666 print json_encode ( array( 'response' => 'invalid') );
667 }
668 mysql_close( $config['sql_link'] );
669 ?>