====== Introduction ====== This is a "controller" class usefull to manipulate an ispcp installation programmatically (i.e. from a php script). The controller class inherits and uses data from the ispcp installation (keys etc) so it can only be run on an operational server. **Threat this class as highly experimental and alpha quality code. There is no error checking nor any safety features. Keep backups handy as this class can destroy your server.** Installation: Copy the class as "class.controller.php" in your /var/www/ispcp/gui/include directory. ====== Usage ====== Place this class in ispcp/gui/include and instantiate it. Load it with "load" methods. Use the add_domain/add_users etc methods to write to the database. Make sure the "ispcp_daemon" is turned off when using the class. You must call /var/www/ispcp/engine/ispcp-rqst-mngr by hand after to update the server. You should read the source. It has been commented and it's good to look at the methods you call before calling them. Some methods are not implemented yet. There's plenty of debugging embedded in the class, it should be enough to get you going. Included is a sample application and supporting code that I used to import data from some old ensim servers. Even if you can't run this code, you can read the code and grasp some knowledge on how things work. ====== Source ====== true, // 'if yes inbound user passwords are threaded as already crypted' 'enforce_admin_name' => true, // if true admin name will be conformed to ispcp (domain_ext) format 'mail_quota' => 52428800, // 50Mega ) ; var $admin_data = array ( // admin_data (domain owner etc) 'admin_id' => '', 'admin_name' => '', 'admin_pass' => '', 'admin_type' => '', 'domain_created' => '', 'customer_id' => '', 'created_by' => '', 'fname' => '', 'lname' => '', 'gender' => 'U', 'firm' => '', 'zip' => '', 'city' => '', 'country' => '', 'email' => '', 'phone' => '', 'fax' => '', 'street1' => '', 'street2' => '' ); // domain parameters that go in the domain table var $domain_id = 0; var $domain_data = array( 'domain_name' => '', 'domain_gid' => '', 'domain_uid' => '', 'domain_admin_id' => '', 'domain_created_id' => '', 'domain_created' => '', 'domain_last_modified' => '', 'domain_mailacc_limit' => '', 'domain_ftpacc_limit' => '', 'domain_traffic_limit' => '', 'domain_sqld_limit' => '', 'domain_sqlu_limit' => '', 'domain_status' => '', 'domain_alias_limit' => '', 'domain_subd_limit' => '', 'domain_ip_id' => '', 'domain_disk_limit' => '', 'domain_disk_usage' => '', 'domain_php' => '', 'domain_cgi' => '' ); var $mail_users = array() ; var $ftp_users = array() ; var $mysql_data = array( 'mysql_user' => '' ); var $admin_mapping = array( 'admin-user' => 'admin_name', // administrator 'cpasswd' => 'admin_pass', //$1$crdkajdlsakd9439qwmkjeqP9jXKER/ 'reseller_id' => 'created_by', ); var $domain_mapping = array( // hash map from external attributes to internal structures 'domain' => 'domain_name', // domain.ext 'diskquota' => 'domain_disk_limit', // 60.0 'webmail' => false, // 1/0 but all our domains have webmail 'perl' => false, // 1/0 but all our domains miss perl 'reseller_id' => 'domain_created_id', // external id of reseller. needs remapping (I.e. 4=>100) 'web' => false, // 1/0 but all our domains have web (change???) 'webaddress' => false, // www.domain.ext: useless 'mysql' => 'domain_sqld_limit', // 1 'mysqluser' => 'mysql_user', // adminmysql 'bandwidth' => 'domain_traffic_limit', // 1048576000 'cgi-bin' => 'domain_cgi', // 1 'adminmail' => 'email', // admin email alert@mediaits.com 'enabled' => false, // 1/0 'admin-user' => 'admin_name', // administrator 'cpasswd' => 'admin_pass', //$1$crf8Gze7$234ojrielkmd s.9jXKER/ 'ftp' => false, // enabled for us 1 'anonftp' => false, // always off for us 0 'mail' => false, // always on for us 1 'usernum' => 'domain_mailacc_limit' // 5 ); // contructor. Just pass in the sql (adodb) object function ispcpController( &$sql ) { $this->sql = $sql ; } // generic class options. function set_option($option,$value) { if ( array_key_exists($option,$this->options) ) { $this->options[$option] = $value ; } } function get_option( $option ) { if ( array_key_exists($option,$this->options) ) { return $this->options[$option]; } die ("Unknown option $option"); } // admin data options function set_admin_option($option,$value) { if ( array_key_exists($option,$this->admin_data) ) { $this->admin_data[$option] = $value ; } } // domain data options function set_domain_option($option,$value) { if ( array_key_exists($option,$this->domain_data) ) { $this->domain_data[$option] = $value ; } } // Loads domain record from db. Users and other settings are ignored // Usefull to retrieve the gid/uid after a domain has been created function load_from_db( $domain_name ) { $query = "SELECT * from domain where domain_name='$domain_name'" ; $row = $this->sql->GetAssoc($query) ; foreach ( $row as $key => $value ) { $this->set_domain_option($key,$value); } $this->domain_id = $row['domain_id']; } function mk_insert_query($table, &$data) { // Escape data and prepare keys / data pairs for the query. $escaped_data = array() ; $keys = array(); foreach ( $data as $key => $attribute ) { $keys[] = $key ; $escaped_data[] = "'".mysql_real_escape_string($attribute)."'"; } $query = "insert into $table (".implode(',',$keys).")" . " values (" . implode(',',$escaped_data).")" ; return $query ; } function mk_data($initial_data, &$mapping_hash, $attributes, $forced_attributes) { $data = $initial_data ; foreach ( $attributes as $key => $value ) { if ( array_key_exists($key,$mapping_hash)) { $local_key = $mapping_hash[$key] ; // echo "key is $local_key\n"; if ( is_string($local_key) && array_key_exists($local_key,$data)) { // echo "$key => " . $local_key . " => $value \n"; $data[$local_key] = $value ; } } } // Massaging of values foreach ( $forced_attributes as $key => $value ) { $data[$key] = $value ; } // print_r($data); return $data ; } // makes a domain admin structure suitable for add_admin // values are mapped from the external array function mk_admin_data($attributes, $forced_attributes = null ) { $data = $this->mk_data($this->admin_data, $this->admin_mapping, $attributes, $forced_attributes); if ( $this->get_option('enforce_admin_name') ) { $data['admin_name'] = $attributes['domain']; } return $data ; } // makes a domain strucute suitable for add_domain function mk_domain_data($attributes, $forced_attributes = null) { $data = $this->mk_data($this->domain_data, $this->domain_mapping, $attributes, $forced_attributes); $this->mysql_data = $this->mk_data($this->mysql_data, $this->domain_mapping, $attributes, $forced_attributes); return $data ; } function load_pars(&$attributes) { $now = time(); $this->admin_data = $this->mk_admin_data($attributes, array( 'admin_type' => 'user', 'domain_created' => $now ) ); $this->domain_data = $this->mk_domain_data($attributes, array( 'domain_created' => $now, 'domain_status' => 'toadd', ) ); } function load_users(&$users) { foreach ( $users as $user ) { print_r($user); if ( !$user['privileged']) { $newuser = array() ; $newuser['username'] = $user['username']; $newuser['fullname'] = $user['fullname']; @$newuser['password'] = $user['password']; if ( $user['ftp']) $this->ftp_users[] = $newuser ; else // $this->mail_users[] = $newuser ; } } /* echo "MAIL USERS" ; print_r($this->mail_users); echo "FTP USERS" ; print_r($this->ftp_users); */ } function add_admin() { $query = $this->mk_insert_query("admin", $this->admin_data) ; // echo $query ; $res = $this->sql->Execute($query); print $this->sql->ErrorMsg(); return $this->sql->Insert_ID(); } function add_domain() { // generate a new admin for this domain. $admin_id = $this->add_admin(); $this->set_domain_option('domain_admin_id', $admin_id) ; // find out the new uid and gid // Disabled. The uid/gid are decided by the daemon list($newuid,$newgid) = $this->sql->GetRow("SELECT MAX(domain_uid)+1 as newuid,MAX(domain_gid)+1 as newgid from domain"); print $this->sql->ErrorMsg(); $this->set_domain_option('domain_uid', $newuid); $this->set_domain_option('domain_gid', $newgid); // Add the user $groupcmd = "/usr/sbin/groupadd -g $newgid vu$newgid"; system($groupcmd); $usercmd = "/usr/sbin/useradd -c 'virtual-user' -g $newgid -u $newuid -s /bin/false -d /var/www/virtual/" . $this->domain_data['domain_name']." vu$newuid" ; system($usercmd); // set enforced options $this->set_domain_option('domain_ip_id', 1); $query = $this->mk_insert_query("domain", $this->domain_data) ; // echo "query is $query" ; $res = $this->sql->Execute($query); print $this->sql->ErrorMsg(); $this->domain_id = $this->sql->Insert_ID(); } // this function will delete (simple) domains and mail users. domain aliases are ignored (!!!) function del_domain( $domain ) { $this->load_from_db($domain); $query = "UPDATE domain set domain_status='delete' where domain_id='$this->domain_id'" ; $this->sql->Execute($query); print $this->sql->ErrorMsg() ; $query = "UPDATE mail_users set status='delete' where domain_id='$this->domain_id'" ; $this->sql->Execute($query); print $this->sql->ErrorMsg() ; $query = "delete from ftp_group where groupname='$domain'"; $this->sql->Execute($query); print $this->sql->ErrorMsg() ; $query = "delete from ftp_users where userid like '%@$domain'"; $this->sql->Execute($query); print $this->sql->ErrorMsg() ; } // this function can be called after users are loaded with load_users function add_mail_users() { // echo "Adding mail users"; foreach ( $this->mail_users as $user ) { $user_data = array() ; $user_data['mail_acc'] = $user['username']; $user_data['mail_pass'] = strlen($user['password'] > 0) ? $user['password'] : '---unset---'; $user_data['mail_forward'] = "_no_"; $user_data['domain_id'] = $this->domain_id; $user_data['mail_type'] = 'normal_mail'; $user_data['sub_id'] = '0'; $user_data['status'] = 'change'; $user_data['mail_auto_respond'] = '0'; $user_data['quota'] = $this->get_option('mail_quota'); $user_data['mail_addr'] = $user['username'] . "@" . $this->domain_data['domain_name']; // print_r($user_data); $query = $this->mk_insert_query("mail_users", $user_data); // echo "Query is $query" ; $this->sql->Execute($query); print $this->sql->ErrorMsg() ; } } // this function can be called after users are loaded with load_users function add_ftp_users() { // echo "Adding ftp users"; $group = array() ; foreach ( $this->ftp_users as $user ) { $user_data = array() ; $user_data['userid'] = $user['username']. "@" . $this->domain_data['domain_name']; $user_data['passwd'] = strlen($user['password'] > 0) ? $user['password'] : '---unset---'; $user_data['uid'] = $this->domain_data['domain_uid']; $user_data['gid'] = $this->domain_data['domain_gid']; $user_data['shell'] = '/bin/bash'; // !!! OUCH !!! $user_data['homedir'] = '/var/www/virtual/' . $this->domain_data['domain_name']; $group[] = $user_data['userid']; print_r($user_data); $query = $this->mk_insert_query("ftp_users", $user_data); echo "Query is $query" ; $this->sql->Execute($query); print $this->sql->ErrorMsg() ; } // create the group for this domain if ( count($group)) { $group_data = array() ; $group_data['groupname'] = $this->domain_data['domain_name']; $group_data['gid'] = $this->domain_data['domain_gid']; $group_data['members'] = implode(",",$group); $query = $this->mk_insert_query('ftp_group', $group_data); echo "Query is $query" ; $this->sql->Execute($query); print $this->sql->ErrorMsg() ; } } function del_mail_user( $user ) { } function del_ftp_user( $user ) { } function add_sql() { if ( !$this->domain_data['domain_sqld_limit']) return ; $db_name = str_replace(".","_",$this->domain_data['domain_name']); // ensim dbase convention is domain_ext $query = "CREATE database `$db_name`"; // create the database echo "Query $query \n"; $this->sql->Execute($query); print $this->sql->ErrorMsg() ; // add dbase to the domain $query_data = array( "domain_id" => $this->domain_id, "sqld_name" => $db_name ); $query = $this->mk_insert_query("sql_database", $query_data ); // echo "Query $query \n"; $this->sql->Execute($query); print $this->sql->ErrorMsg() ; $dbase_id = $this->sql->Insert_ID(); // add the username from domain_data and grant all privileges to it $query = "grant all on `$db_name`.* to '".$this->mysql_data['mysql_user']."'@'localhost' identified by '---unset---'"; // echo "Query $query \n"; $this->sql->Execute($query); print $this->sql->ErrorMsg() ; $query = "grant all on `$db_name`.* to '".$this->mysql_data['mysql_user']."'@'%' identified by '---unset---'"; // echo "Query $query \n"; $this->sql->Execute($query); print $this->sql->ErrorMsg() ; // Add the user to the sql_user table ; $query_data = array( 'sqld_id' => $dbase_id, 'sqlu_name' => $this->mysql_data['mysql_user'], 'sqlu_pass' => '---unset---' ); $query = $this->mk_insert_query("sql_user", $query_data); // echo "Query $query \n"; $this->sql->Execute($query); print $this->sql->ErrorMsg() ; } function print_pars() { print_r($this->admin_data); print_r($this->domain_data); print_r($this->mysql_data); } } ?> ====== Helper: class-site ====== Here's an extra class that can be used to feed data in the controller. This particular class read data from an array generated by a simple xml2array function (not included). The array is a mapping of the ensim "site pickle" structure that defines a site in ensim. The class is short enough so you can see how data is taken from the array. What is important is the "pars" and "users" data structures that are suitable for feeding into the "controller's" "load_XXX" methods. These structures are created by the load_config and load_users methods that read data coming from outside. For example usage look at the example at the end of this doc. value format (pars is short for parameters) * Users : Array of site users with their options. * * Created : ispcomm (May 14 2008) * License : GPL */ class CSite { var $pars = array ( 'domain' => '', // domain name 'diskquota' => '', // in MB 'webmail' => '', // on-off 'perl' => '', // on-off 'reseller_id' => '', // ensim id of reseller (needs remapping) 'web' => '', // www.sitename usually 'webaddress' => '', // www.sitename usually 'mysql' => '', // on-off 'mysqluser' => '', // the username of the db user 'bandwidth' => '', // in bytes 'cgi-bin' => '', // on-off 'adminmail' => '', // the email of the administrator (to send email on creation) 'enabled' => '', // on-off for site enabled 'admin-user' => '', // admin user (use to create a www ftp user) 'cpasswd' => '', // the crypted password of the admin user (useless?) 'ftp' => '', // on-off 'anonftp' => '', // anonymous ftp enabled. 'mail' => '', // on-off 'usernum' => '', // number of max allowed users ); var $users = array (); function CSite(& $site) { $this->load_config($site); $this->load_users($site); } function get_users() { return $this->users ; } function get_pars() { return $this->pars ; } function load_config(&$site) { $config = array (); foreach ($site['backup']['site']['config'] as $param => & $flags) { foreach ($flags as $key => & $flag) { // print "$key => " ; // print_r($flag); @$config[$param][$key] = $flag['value']; } } //print_r($config); $this->pars['domain' ] = $config['siteinfo']['domain']; // domain name $this->pars['diskquota' ] = $config['diskquota']['quota'] * 1024 * 1024 ; // original is in MB $this->pars['webmail' ] = $config['sqmail']['enabled']; // on-off $this->pars['perl' ] = $config['mod_perl']['enabled']; // on-off $this->pars['reseller_id'] = $config['reseller']['reseller_id']; // ensim id of reseller (needs remapping) $this->pars['web'] = $config['apache']['enabled']; // www.sitename usually $this->pars['webaddress'] = $config['apache']['webserver']; // www.sitename usually $this->pars['mysql' ] = $config['mysql']['enabled']; // on-off $this->pars['mysqluser' ] = $config['mysql']['dbaseadmin']; // the username of the db user $this->pars['bandwidth' ] = $config['bandwidth']['threshold']; // in bytes $this->pars['cgi-bin' ] = $config['cgi']['enabled']; // on-off $this->pars['adminmail' ] = $config['siteinfo']['email']; // the email of the administrator (to send email on creation) $this->pars['enabled' ] = $config['siteinfo']['enabled']; // on-off for site enabled $this->pars['admin-user'] = $config['siteinfo']['admin_user']; // admin user (use to create a www ftp user) $this->pars['cpasswd' ] = $config['siteinfo']['cpasswd']; // the crypted password of the admin user (useless?) $this->pars['ftp' ] = $config['proftpd']['enabled']; // on-off $this->pars['anonftp' ] = $config['anonftp']['enabled']; // anonymous ftp enabled. $this->pars['mail' ] = $config['sendmail']['enabled']; // on-off $this->pars['usernum' ] = $config['users']['maxusers']; // number of max allowed users // print_r($this->pars); } function load_users (&$site) { $users = array (); foreach ($site['backup']['site']['virtusers']['user'] as $param => & $flags) { // echo "$param =>"; foreach ($flags as $key => & $flag) { // echo "$key=>"; // print_r($flag); $users[$param][$key] = $flag['value']; } } foreach ($users as $num => $user) { if ( !in_array($user['username'], array('majordomo','root'))) { $this->users[$num]['username'] = $user['username'] ; $this->users[$num]['fullname'] = $user['fullname'] ; $this->users[$num]['privileged'] = $user['privileged'] ; $this->users[$num]['ftp'] = $user['proftpd']; } } // print_r($this->users); } function get_domain() { return $this->pars['domain']; } } ?> ====== Example ====== And finally here's an example usage #!/usr/bin/php '5', '5' => '2', '6' => '7', '7' => '8', '8' => '9', '9' => '10' ); while ($str = fgets(STDIN)) { // echo "- $str -"; $str = str_replace('\n', "", $str) ; //echo $str; $parts = array (); if (preg_match('/(]*>.*<\/backup>)/', $str, $parts)) { //array_shift(&$parts); //print_r($parts); $site = Cxml2array($parts[1],1); $csite = new CSite($site) ; // print_r($csite->get_pars()); // print_r($csite->get_users()); $now = time() ; $controller = new ispcpController( $sql ) ; $pars = $csite->get_pars(); $pars['reseller_id'] = $reseller_map[$pars['reseller_id']]; $controller->load_pars( $pars ); $controller->load_users($csite->get_users()); $controller->set_domain_option('domain_php', 1); $controller->set_domain_option('domain_alias_limit', 0); $controller->set_domain_option('domain_subd_limit', 0); $controller->set_domain_option('domain_ftpacc_limit', 5); echo "-----------------------------------------------------------------------\n"; $controller->print_pars() ; $controller->add_domain() ; $controller->add_mail_users(); $controller->add_ftp_users(); $controller->add_sql(); } } ?> All this stuff was written by me (ispcomm) for internal usage and might suit or not suit you. If you find bugs or write enhancements, pls. update this wiki so others can benefit. In case the ispcp dev team decides to include this code in the current ispcp, I'll be happy to contribute and integrate it better. ispcomm