about summary refs log tree commit diff stats
path: root/wiki/lib/plugins/authpgsql/auth.php
blob: 7b677d3d7394dd6bbb84ece3cdc8ca02ec5416f9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
# gridwm - grid window manager
#   (C)opyright MMVI Anselm R. Garbe

include config.mk

WMSRC = bar.c client.c draw.c event.c kb.c mouse.c util.c wm.c
WMOBJ = ${WMSRC:.c=.o}
MENSRC = menu.c draw.c util.c
MENOBJ = ${MENSRC:.c=.o}
MAN1 = gridwm.1 gridmenu.1
BIN = gridwm gridmenu

all: config gridwm gridmenu
	@echo finished

config:
	@echo gridwm build options:
	@echo "LIBS     = ${LIBS}"
	@echo "CFLAGS   = ${CFLAGS}"
	@echo "LDFLAGS  = ${LDFLAGS}"
	@echo "CC       = ${CC}"

.c.o:
	@echo CC $<
	@${CC} -c ${CFLAGS} $<

${WMOBJ}: wm.h draw.h config.h util.h

gridmenu: ${MENOBJ}
	@echo LD $@
	@${CC} -o $@ ${MENOBJ} ${LDFLAGS}

gridwm: ${WMOBJ}
	@echo LD $@
	@${CC} -o $@ ${WMOBJ} ${LDFLAGS}

clean:
	rm -f gridwm gridmenu *.o core

dist: clean
	mkdir -p gridwm-${VERSION}
	cp -R Makefile README LICENSE config.mk *.h *.c ${MAN} gridwm-${VERSION}
	tar -cf gridwm-${VERSION}.tar gridwm-${VERSION}
	gzip gridwm-${VERSION}.tar
	rm -rf gridwm-${VERSION}

install: all
	@mkdir -p ${DESTDIR}${PREFIX}/bin
	@cp -f ${BIN} ${DESTDIR}${PREFIX}/bin
	@echo installed executable files to ${DESTDIR}${PREFIX}/bin
	@mkdir -p ${DESTDIR}${MANPREFIX}/man1
	@cp -f ${M
<?php
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();

/**
 * PostgreSQL authentication backend
 *
 * This class inherits much functionality from the MySQL class
 * and just reimplements the Postgres specific parts.
 *
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @author     Andreas Gohr <andi@splitbrain.org>
 * @author     Chris Smith <chris@jalakai.co.uk>
 * @author     Matthias Grimm <matthias.grimmm@sourceforge.net>
 * @author     Jan Schumann <js@schumann-it.com>
 */
class auth_plugin_authpgsql extends auth_plugin_authmysql {

    /**
     * Constructor
     *
     * checks if the pgsql interface is available, otherwise it will
     * set the variable $success of the basis class to false
     *
     * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
     * @author Andreas Gohr <andi@splitbrain.org>
     */
    public function __construct() {
        // we don't want the stuff the MySQL constructor does, but the grandparent might do something
        DokuWiki_Auth_Plugin::__construct();

        if(!function_exists('pg_connect')) {
            $this->_debug("PgSQL err: PHP Postgres extension not found.", -1, __LINE__, __FILE__);
            $this->success = false;
            return;
        }

        $this->loadConfig();

        // set capabilities based upon config strings set
        if(empty($this->conf['user']) ||
            empty($this->conf['password']) || empty($this->conf['database'])
        ) {
            $this->_debug("PgSQL err: insufficient configuration.", -1, __LINE__, __FILE__);
            $this->success = false;
            return;
        }

        $this->cando['addUser']   = $this->_chkcnf(
            array(
                 'getUserInfo',
                 'getGroups',
                 'addUser',
                 'getUserID',
                 'getGroupID',
                 'addGroup',
                 'addUserGroup'
            )
        );
        $this->cando['delUser']   = $this->_chkcnf(
            array(
                 'getUserID',
                 'delUser',
                 'delUserRefs'
            )
        );
        $this->cando['modLogin']  = $this->_chkcnf(
            array(
                 'getUserID',
                 'updateUser',
                 'UpdateTarget'
            )
        );
        $this->cando['modPass']   = $this->cando['modLogin'];
        $this->cando['modName']   = $this->cando['modLogin'];
        $this->cando['modMail']   = $this->cando['modLogin'];
        $this->cando['modGroups'] = $this->_chkcnf(
            array(
                 'getUserID',
                 'getGroups',
                 'getGroupID',
                 'addGroup',
                 'addUserGroup',
                 'delGroup',
                 'getGroupID',
                 'delUserGroup'
            )
        );
        /* getGroups is not yet supported
           $this->cando['getGroups']    = $this->_chkcnf(array('getGroups',
           'getGroupID')); */
        $this->cando['getUsers']     = $this->_chkcnf(
            array(
                 'getUsers',
                 'getUserInfo',
                 'getGroups'
            )
        );
        $this->cando['getUserCount'] = $this->_chkcnf(array('getUsers'));
    }

    /**
     * Check if the given config strings are set
     *
     * @author  Matthias Grimm <matthiasgrimm@users.sourceforge.net>
     *
     * @param   string[] $keys
     * @param   bool  $wop
     * @return  bool
     */
    protected function _chkcnf($keys, $wop = false) {
        foreach($keys as $key) {
            if(empty($this->conf[$key])) return false;
        }
        return true;
    }

    /**
     * Counts users which meet certain $filter criteria.
     *
     * @author  Matthias Grimm <matthiasgrimm@users.sourceforge.net>
     *
     * @param  array  $filter  filter criteria in item/pattern pairs
     * @return int count of found users.
     */
    public function getUserCount($filter = array()) {
        $rc = 0;

        if($this->_openDB()) {
            $sql = $this->_createSQLFilter($this->conf['getUsers'], $filter);

            // no equivalent of SQL_CALC_FOUND_ROWS in pgsql?
            if(($result = $this->_queryDB($sql))) {
                $rc = count($result);
            }
            $this->_closeDB();
        }
        return $rc;
    }

    /**
     * Bulk retrieval of user data
     *
     * @author  Matthias Grimm <matthiasgrimm@users.sourceforge.net>
     *
     * @param   int   $first     index of first user to be returned
     * @param   int   $limit     max number of users to be returned
     * @param   array $filter    array of field/pattern pairs
     * @return  array userinfo (refer getUserData for internal userinfo details)
     */
    public function retrieveUsers($first = 0, $limit = 0, $filter = array()) {
        $out = array();

        if($this->_openDB()) {
            $this->_lockTables("READ");
            $sql = $this->_createSQLFilter($this->conf['getUsers'], $filter);
            $sql .= " ".$this->conf['SortOrder'];
            if($limit) $sql .= " LIMIT $limit";
            if($first) $sql .= " OFFSET $first";
            $result = $this->_queryDB($sql);

            foreach($result as $user) {
                if(($info = $this->_getUserInfo($user['user']))) {
                    $out[$user['user']] = $info;
                }
            }

            $this->_unlockTables();
            $this->_closeDB();
        }
        return $out;
    }

    // @inherit function joinGroup($user, $group)
    // @inherit function leaveGroup($user, $group) {

    /**
     * Adds a user to a group.
     *
     * If $force is set to true non existing groups would be created.
     *
     * The database connection must already be established. Otherwise
     * this function does nothing and returns 'false'.
     *
     * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
     * @author Andreas Gohr   <andi@splitbrain.org>
     *
     * @param   string $user    user to add to a group
     * @param   string $group   name of the group
     * @param   bool   $force   create missing groups
     * @return  bool   true on success, false on error
     */
    protected function _addUserToGroup($user, $group, $force = false) {
        $newgroup = 0;

        if(($this->dbcon) && ($user)) {
            $gid = $this->_getGroupID($group);
            if(!$gid) {
                if($force) { // create missing groups
                    $sql = str_replace('%{group}', addslashes($group), $this->conf['addGroup']);
                    $this->_modifyDB($sql);
                    //group should now exists try again to fetch it
                    $gid      = $this->_getGroupID($group);
                    $newgroup = 1; // group newly created
                }
            }
            if(!$gid) return false; // group didn't exist and can't be created

            $sql = $this->conf['addUserGroup'];
            if(strpos($sql, '%{uid}') !== false) {
                $uid = $this->_getUserID($user);
                $sql = str_replace('%{uid}', addslashes($uid), $sql);
            }
            $sql = str_replace('%{user}', addslashes($user), $sql);
            $sql = str_replace('%{gid}', addslashes($gid), $sql);
            $sql = str_replace('%{group}', addslashes($group), $sql);
            if($this->_modifyDB($sql) !== false) {
                $this->_flushUserInfoCache($user);
                return true;
            }

            if($newgroup) { // remove previously created group on error
                $sql = str_replace('%{gid}', addslashes($gid), $this->conf['delGroup']);
                $sql = str_replace('%{group}', addslashes($group), $sql);
                $this->_modifyDB($sql);
            }
        }
        return false;
    }

    // @inherit function _delUserFromGroup($user $group)
    // @inherit function _getGroups($user)
    // @inherit function _getUserID($user)

    /**
     * Adds a new User to the database.
     *
     * The database connection must already be established
     * for this function to work. Otherwise it will return
     * 'false'.
     *
     * @param  string $user  login of the user
     * @param  string $pwd   encrypted password
     * @param  string $name  full name of the user
     * @param  string $mail  email address
     * @param  array  $grps  array of groups the user should become member of
     * @return bool
     *
     * @author  Andreas Gohr <andi@splitbrain.org>
     * @author  Chris Smith <chris@jalakai.co.uk>
     * @author  Matthias Grimm <matthiasgrimm@users.sourceforge.net>
     */
    protected function _addUser($user, $pwd, $name, $mail, $grps) {
        if($this->dbcon && is_array($grps)) {
            $sql = str_replace('%{user}', addslashes($user), $this->conf['addUser']);
            $sql = str_replace('%{pass}', addslashes($pwd), $sql);
            $sql = str_replace('%{name}', addslashes($name), $sql);
            $sql = str_replace('%{email}', addslashes($mail), $sql);
            if($this->_modifyDB($sql)) {
                $uid = $this->_getUserID($user);
            } else {
                return false;
            }

            $group = '';
            $gid = false;

            if($uid) {
                foreach($grps as $group) {
                    $gid = $this->_addUserToGroup($user, $group, true);
                    if($gid === false) break;
                }

                if($gid !== false){
                    $this->_flushUserInfoCache($user);
                    return true;
                } else {
                    /* remove the new user and all group relations if a group can't
                     * be assigned. Newly created groups will remain in the database
                     * and won't be removed. This might create orphaned groups but
                     * is not a big issue so we ignore this problem here.
                     */
                    $this->_delUser($user);
                    $this->_debug("PgSQL err: Adding user '$user' to group '$group' failed.", -1, __LINE__, __FILE__);
                }
            }
        }
        return false;
    }

    /**
     * Opens a connection to a database and saves the handle for further
     * usage in the object. The successful call to this functions is
     * essential for most functions in this object.
     *
     * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
     *
     * @return bool
     */
    protected function _openDB() {
        if(!$this->dbcon) {
            $dsn = $this->conf['server'] ? 'host='.$this->conf['server'] : '';
            $dsn .= ' port='.$this->conf['port'];
            $dsn .= ' dbname='.$this->conf['database'];
            $dsn .= ' user='.$this->conf['user'];
            $dsn .= ' password='.conf_decodeString($this->conf['password']);

            $con = @pg_connect($dsn);
            if($con) {
                $this->dbcon = $con;
                return true; // connection and database successfully opened
            } else {
                $this->_debug(
                        "PgSQL err: Connection to {$this->conf['user']}@{$this->conf['server']} not possible.",
                        -1, __LINE__, __FILE__
                    );
            }
            return false; // connection failed
        }
        return true; // connection already open
    }

    /**
     * Closes a database connection.
     *
     * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
     */
    protected function _closeDB() {
        if($this->dbcon) {
            pg_close($this->dbcon);
            $this->dbcon = 0;
        }
    }

    /**
     * Sends a SQL query to the database and transforms the result into
     * an associative array.
     *
     * This function is only able to handle queries that returns a
     * table such as SELECT.
     *
     * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
     *
     * @param  string $query  SQL string that contains the query
     * @return array|false the result table
     */
    protected function _queryDB($query) {
        $resultarray = array();
        if($this->dbcon) {
            $result = @pg_query($this->dbcon, $query);
            if($result) {
                while(($t = pg_fetch_assoc($result)) !== false)
                    $resultarray[] = $t;
                pg_free_result($result);
                return $resultarray;
            } else{
                $this->_debug('PgSQL err: '.pg_last_error($this->dbcon), -1, __LINE__, __FILE__);
            }
        }
        return false;
    }

    /**
     * Executes an update or insert query. This differs from the
     * MySQL one because it does NOT return the last insertID
     *
     * @author Andreas Gohr <andi@splitbrain.org>
     *
     * @param string $query
     * @return bool
     */
    protected function _modifyDB($query) {
        if($this->dbcon) {
            $result = @pg_query($this->dbcon, $query);
            if($result) {
                pg_free_result($result);
                return true;
            }
            $this->_debug('PgSQL err: '.pg_last_error($this->dbcon), -1, __LINE__, __FILE__);
        }
        return false;
    }

    /**
     * Start a transaction
     *
     * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
     *
     * @param string $mode  could be 'READ' or 'WRITE'
     * @return bool
     */
    protected function _lockTables($mode) {
        if($this->dbcon) {
            $this->_modifyDB('BEGIN');
            return true;
        }
        return false;
    }

    /**
     * Commit a transaction
     *
     * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
     *
     * @return bool
     */
    protected function _unlockTables() {
        if($this->dbcon) {
            $this->_modifyDB('COMMIT');
            return true;
        }
        return false;
    }

    /**
     * Escape a string for insertion into the database
     *
     * @author Andreas Gohr <andi@splitbrain.org>
     *
     * @param  string  $string The string to escape
     * @param  bool    $like   Escape wildcard chars as well?
     * @return string
     */
    protected function _escape($string, $like = false) {
        $string = pg_escape_string($string);
        if($like) {
            $string = addcslashes($string, '%_');
        }
        return $string;
    }
}