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