Passed
Push — master ( 5397c5...a7725b )
by Felipe
05:40
created

RoleTrait::_dealWithOldParentRoles()   C

Complexity

Conditions 7
Paths 13

Size

Total Lines 25
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 25
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 12
nc 13
nop 3
1
<?php
2
3
/**
4
 * PHPPgAdmin v6.0.0-beta.43
5
 */
6
7
namespace PHPPgAdmin\Traits;
8
9
/**
10
 * Common trait for roles and users manipulation.
11
 */
12
trait RoleTrait
13
{
14
    /**
15
     * Returns all roles in the database cluster.
16
     *
17
     * @param string $rolename (optional) The role name to exclude from the select
18
     *
19
     * @return \PHPPgAdmin\ADORecordSet Either one or All roles
20
     */
21
    public function getRoles($rolename = '')
22
    {
23
        $sql = '
24
			SELECT rolname, rolsuper, rolcreatedb, rolcreaterole, rolinherit,
25
				rolcanlogin, rolconnlimit, rolvaliduntil, rolconfig
26
			FROM pg_catalog.pg_roles';
27
        if ($rolename) {
28
            $sql .= " WHERE rolname!='{$rolename}'";
29
        }
30
31
        $sql .= ' ORDER BY rolname';
32
33
        return $this->selectSet($sql);
34
    }
35
36
    /**
37
     * Returns information about a single role.
38
     *
39
     * @param string $rolename The name of the role to retrieve
40
     *
41
     * @return \PHPPgAdmin\ADORecordSet The role's data
42
     */
43
    public function getRole($rolename)
44
    {
45
        $this->clean($rolename);
46
47
        $sql = "
48
			SELECT rolname, rolsuper, rolcreatedb, rolcreaterole, rolinherit,
49
				rolcanlogin, rolconnlimit, rolvaliduntil, rolconfig
50
			FROM pg_catalog.pg_roles WHERE rolname='{$rolename}'";
51
52
        return $this->selectSet($sql);
53
    }
54
55
    /**
56
     * Returns all users in the database cluster.
57
     *
58
     * @return \PHPPgAdmin\ADORecordSet All users
59
     */
60
    public function getUsers()
61
    {
62
        $sql = 'SELECT usename, usesuper, usecreatedb, valuntil AS useexpires, useconfig
63
			FROM pg_user
64
			ORDER BY usename';
65
66
        return $this->selectSet($sql);
67
    }
68
69
    /**
70
     * Returns information about a single user.
71
     *
72
     * @param string $username The username of the user to retrieve
73
     *
74
     * @return \PHPPgAdmin\ADORecordSet The user's data
75
     */
76
    public function getUser($username)
77
    {
78
        $this->clean($username);
79
80
        $sql = "SELECT usename, usesuper, usecreatedb, valuntil AS useexpires, useconfig
81
			FROM pg_user
82
			WHERE usename='{$username}'";
83
84
        return $this->selectSet($sql);
85
    }
86
87
    /**
88
     * Creates a new role.
89
     *
90
     * @param string $rolename     The name of the role to create
91
     * @param string $password     A password for the role
92
     * @param bool   $superuser    Boolean whether or not the role is a superuser
93
     * @param bool   $createdb     Boolean whether or not the role can create databases
94
     * @param bool   $createrole   Boolean whether or not the role can create other roles
95
     * @param bool   $inherits     Boolean whether or not the role inherits the privileges from parent roles
96
     * @param bool   $login        Boolean whether or not the role will be allowed to login
97
     * @param number $connlimit    Number of concurrent connections the role can make
98
     * @param string $expiry       String Format 'YYYY-MM-DD HH:MM:SS'.  '' means never expire
99
     * @param array  $new_roles_to_add     (array) Roles to which the new role will be immediately added as a new member
100
     * @param array  $new_members_of_role      (array) Roles which are automatically added as members of the new role
101
     * @param array  $new_admins_of_role (array) Roles which are automatically added as admin members of the new role
102
     *
103
     * @return int 0 if operation was successful
104
     */
105
    public function createRole(
106
        $rolename,
107
        $password,
108
        $superuser,
109
        $createdb,
110
        $createrole,
111
        $inherits,
112
        $login,
113
        $connlimit,
114
        $expiry,
115
        $new_roles_to_add,
116
        $new_members_of_role,
117
        $new_admins_of_role
118
    ) {
119
        $enc = $this->_encryptPassword($rolename, $password);
120
        $this->fieldClean($rolename);
121
        $this->clean($enc);
122
        $this->clean($connlimit);
123
        $this->clean($expiry);
124
        $this->fieldArrayClean($new_roles_to_add);
125
        $this->fieldArrayClean($new_members_of_role);
126
        $this->fieldArrayClean($new_admins_of_role);
127
128
        $sql = "CREATE ROLE \"{$rolename}\"";
129
        if ($password != '') {
130
            $sql .= " WITH ENCRYPTED PASSWORD '{$enc}'";
131
        }
132
133
        $sql .= $superuser ? ' SUPERUSER' : ' NOSUPERUSER';
134
        $sql .= $createdb ? ' CREATEDB' : ' NOCREATEDB';
135
        $sql .= $createrole ? ' CREATEROLE' : ' NOCREATEROLE';
136
        $sql .= $inherits ? ' INHERIT' : ' NOINHERIT';
137
        $sql .= $login ? ' LOGIN' : ' NOLOGIN';
138
        if ($connlimit != '') {
139
            $sql .= " CONNECTION LIMIT {$connlimit}";
140
        } else {
141
            $sql .= ' CONNECTION LIMIT -1';
142
        }
143
144
        if ($expiry != '') {
145
            $sql .= " VALID UNTIL '{$expiry}'";
146
        } else {
147
            $sql .= " VALID UNTIL 'infinity'";
148
        }
149
150
        if (is_array($new_roles_to_add) && sizeof($new_roles_to_add) > 0) {
151
            $sql .= ' IN ROLE "' . join('", "', $new_roles_to_add) . '"';
152
        }
153
154
        if (is_array($new_members_of_role) && sizeof($new_members_of_role) > 0) {
155
            $sql .= ' ROLE "' . join('", "', $new_members_of_role) . '"';
156
        }
157
158
        if (is_array($new_admins_of_role) && sizeof($new_admins_of_role) > 0) {
159
            $sql .= ' ADMIN "' . join('", "', $new_admins_of_role) . '"';
160
        }
161
162
        return $this->execute($sql);
163
    }
164
165
    /**
166
     * Helper function that computes encypted PostgreSQL passwords.
167
     *
168
     * @param string $username The username
169
     * @param string $password The password
170
     *
171
     * @return string
172
     */
173
    public function _encryptPassword($username, $password)
174
    {
175
        return 'md5' . md5($password . $username);
176
    }
177
178
    /**
179
     * Adjusts a role's info and renames it.
180
     *
181
     * @param string $rolename        The name of the role to adjust
182
     * @param string $password        A password for the role
183
     * @param bool   $superuser       Boolean whether or not the role is a superuser
184
     * @param bool   $createdb        Boolean whether or not the role can create databases
185
     * @param bool   $createrole      Boolean whether or not the role can create other roles
186
     * @param bool   $inherits        Boolean whether or not the role inherits the privileges from parent roles
187
     * @param bool   $login           Boolean whether or not the role will be allowed to login
188
     * @param number $connlimit       Number of concurrent connections the role can make
189
     * @param string $expiry          string Format 'YYYY-MM-DD HH:MM:SS'.  '' means never expire
190
     *
191
     * @param array  $new_roles_to_add        (array) Roles to which the role will be immediately added as a new member
0 ignored issues
show
Coding Style introduced by
Parameter tags must be grouped together in a doc comment
Loading history...
192
     * @param array  $new_members_of_role         (array) Roles which are automatically added as members of the role
0 ignored issues
show
Coding Style introduced by
Parameter tags must be grouped together in a doc comment
Loading history...
193
     * @param array  $new_admins_of_role    (array) Roles which are automatically added as admin members of the role
0 ignored issues
show
Coding Style introduced by
Parameter tags must be grouped together in a doc comment
Loading history...
194
     *
195
     * @param string  $original_parent_roles     Original roles whose the role belongs to, comma separated
0 ignored issues
show
Coding Style introduced by
Parameter tags must be grouped together in a doc comment
Loading history...
196
     * @param string  $original_members      Original roles that are members of the role, comma separated
0 ignored issues
show
Coding Style introduced by
Parameter tags must be grouped together in a doc comment
Loading history...
197
     * @param string  $original_admins Original roles that are admin members of the role, comma separated
0 ignored issues
show
Coding Style introduced by
Parameter tags must be grouped together in a doc comment
Loading history...
198
     * @param string $newrolename     The new name of the role
0 ignored issues
show
Coding Style introduced by
Parameter tags must be grouped together in a doc comment
Loading history...
199
     *
200
     * @return bool|int 0 success
201
     */
202
    public function setRenameRole(
203
        $rolename,
204
        $password,
205
        $superuser,
206
        $createdb,
207
        $createrole,
208
        $inherits,
209
        $login,
210
        $connlimit,
211
        $expiry,
212
        $new_roles_to_add,
213
        $new_members_of_role,
214
        $new_admins_of_role,
215
        $original_parent_roles,
216
        $original_members,
217
        $original_admins,
218
        $newrolename
219
    ) {
220
        $status = $this->beginTransaction();
221
        if ($status != 0) {
222
            return -1;
223
        }
224
225
        if ($rolename != $newrolename) {
226
            $status = $this->renameRole($rolename, $newrolename);
227
            if ($status != 0) {
228
                $this->rollbackTransaction();
229
230
                return -3;
231
            }
232
            $rolename = $newrolename;
233
        }
234
235
        $status =
0 ignored issues
show
Coding Style introduced by
Multi-line assignments must have the equal sign on the second line
Loading history...
236
        $this->setRole(
237
            $rolename,
238
            $password,
239
            $superuser,
240
            $createdb,
241
            $createrole,
242
            $inherits,
243
            $login,
244
            $connlimit,
245
            $expiry,
246
            $new_roles_to_add,
247
            $new_members_of_role,
248
            $new_admins_of_role,
249
            $original_parent_roles,
250
            $original_members,
251
            $original_admins
252
        );
253
        if ($status != 0) {
254
            $this->rollbackTransaction();
255
256
            return -2;
257
        }
258
259
        return $this->endTransaction();
260
    }
261
262
    /**
263
     * Renames a role.
264
     *
265
     * @param string $rolename    The name of the role to rename
266
     * @param string $newrolename The new name of the role
267
     *
268
     * @return int 0 if operation was successful
269
     */
270
    public function renameRole($rolename, $newrolename)
271
    {
272
        $this->fieldClean($rolename);
273
        $this->fieldClean($newrolename);
274
275
        $sql = "ALTER ROLE \"{$rolename}\" RENAME TO \"{$newrolename}\"";
276
277
        return $this->execute($sql);
278
    }
279
280
    private function _dealWithOldParentRoles($original_parent_roles, $new_roles_to_add, $rolename)
281
    {
282
        $old = explode(',', $original_parent_roles);
283
284
        // Grant the roles of the old role owners to the new owner
285
        foreach ($new_roles_to_add as $m) {
286
            if (!in_array($m, $old, true)) {
287
                $status = $this->grantRole($m, $rolename);
288
                if ($status != 0) {
289
                    return -1;
290
                }
291
            }
292
        }
293
294
        // Revoke the new role to the old members if they don't have the requested role name
295
296
        foreach ($old as $o) {
297
            if (!in_array($o, $new_roles_to_add, true)) {
298
                $status = $this->revokeRole($o, $rolename, 0, 'CASCADE');
299
                if ($status != 0) {
300
                    return -1;
301
                }
302
            }
303
        }
304
        return 0;
305
    }
306
307
    private function _dealWithOriginalMembers($original_members, $new_members_of_role, $rolename)
308
    {
309
        //members
310
        $old = explode(',', $original_members);
311
        foreach ($new_members_of_role as $m) {
312
            if (!in_array($m, $old, true)) {
313
                $status = $this->grantRole($rolename, $m);
314
                if ($status != 0) {
315
                    return -1;
316
                }
317
            }
318
        }
319
        if ($original_members) {
320
            foreach ($old as $o) {
321
                if (!in_array($o, $new_members_of_role, true)) {
322
                    $status = $this->revokeRole($rolename, $o, 0, 'CASCADE');
323
                    if ($status != 0) {
324
                        return -1;
325
                    }
326
                }
327
            }
328
        }
329
        return 0;
330
    }
331
332
    private function _dealWithOriginalAdmins($original_admins, $new_admins_of_role, $rolename)
333
    {
334
        $old = explode(',', $original_admins);
335
        foreach ($new_admins_of_role as $m) {
336
            if (!in_array($m, $old, true)) {
337
                $status = $this->grantRole($rolename, $m, 1);
338
                if ($status != 0) {
339
                    return -1;
340
                }
341
            }
342
        }
343
344
        foreach ($old as $o) {
345
            if (!in_array($o, $new_admins_of_role, true)) {
346
                $status = $this->revokeRole($rolename, $o, 1, 'CASCADE');
347
                if ($status != 0) {
348
                    return -1;
349
                }
350
            }
351
        }
352
        return 0;
353
    }
354
355
    private function _alterRole($rolename, $password, $connlimit, $expiry, $superuser, $createdb, $createrole, $inherits, $login)
356
    {
357
        $enc = $this->_encryptPassword($rolename, $password);
358
        $this->clean($enc);
359
        $this->clean($connlimit);
360
        $this->clean($expiry);
361
362
        $sql = "ALTER ROLE \"{$rolename}\"";
363
        if ($password != '') {
364
            $sql .= " WITH ENCRYPTED PASSWORD '{$enc}'";
365
        }
366
367
        $sql .= $superuser ? ' SUPERUSER' : ' NOSUPERUSER';
368
        $sql .= $createdb ? ' CREATEDB' : ' NOCREATEDB';
369
        $sql .= $createrole ? ' CREATEROLE' : ' NOCREATEROLE';
370
        $sql .= $inherits ? ' INHERIT' : ' NOINHERIT';
371
        $sql .= $login ? ' LOGIN' : ' NOLOGIN';
372
        if ($connlimit != '') {
373
            $sql .= " CONNECTION LIMIT {$connlimit}";
374
        } else {
375
            $sql .= ' CONNECTION LIMIT -1';
376
        }
377
378
        if ($expiry != '') {
379
            $sql .= " VALID UNTIL '{$expiry}'";
380
        } else {
381
            $sql .= " VALID UNTIL 'infinity'";
382
        }
383
384
        return $this->execute($sql);
385
    }
386
387
    /**
388
     * Adjusts a role's info.
389
     *
390
     * @param string $rolename        The name of the role to adjust
391
     * @param string $password        A password for the role
392
     * @param bool   $superuser       Boolean whether or not the role is a superuser
393
     * @param bool   $createdb        Boolean whether or not the role can create databases
394
     * @param bool   $createrole      Boolean whether or not the role can create other roles
395
     * @param bool   $inherits        Boolean whether or not the role inherits the privileges from parent roles
396
     * @param bool   $login           Boolean whether or not the role will be allowed to login
397
     * @param number $connlimit       Number of concurrent connections the role can make
398
     * @param string $expiry          string Format 'YYYY-MM-DD HH:MM:SS'.  '' means never expire
399
     * @param array  $new_roles_to_add        (array) Roles to which the role will be immediately added as a new member
400
     * @param array  $new_members_of_role         (array) Roles which are automatically added as members of the role
401
     * @param array  $new_admins_of_role    (array) Roles which are automatically added as admin members of the role
402
     * @param string $original_parent_roles     Original roles whose the role belongs to, comma separated
403
     * @param string $original_members      Original roles that are members of the role, comma separated
404
     * @param string $original_admins Original roles that are admin members of the role, comma separated
405
     *
406
     * @return int 0 if operation was successful
407
     */
408
    public function setRole(
409
        $rolename,
410
        $password,
411
        $superuser,
412
        $createdb,
413
        $createrole,
414
        $inherits,
415
        $login,
416
        $connlimit,
417
        $expiry,
418
        $new_roles_to_add,
419
        $new_members_of_role,
420
        $new_admins_of_role,
421
        $original_parent_roles,
422
        $original_members,
423
        $original_admins
424
    ) {
425
        $this->fieldClean($rolename);
426
427
        $this->fieldArrayClean($new_roles_to_add);
428
        $this->fieldArrayClean($new_members_of_role);
429
        $this->fieldArrayClean($new_admins_of_role);
430
431
        $status = $this->_alterRole($rolename, $password, $connlimit, $expiry, $superuser, $createdb, $createrole, $inherits, $login);
432
        if ($status !== 0) {
433
            return -1;
434
        }
435
436
        // If there were existing users with the requested role,
437
        // assign their roles to the new user, and remove said
438
        // role from them if they are not among the new authorized members
439
        if ($original_parent_roles) {
440
            $status = $this->_dealWithOldParentRoles($original_parent_roles, $new_roles_to_add, $rolename);
441
            if ($status !== 0) {
442
                return -1;
443
            }
444
        }
445
446
        if ($original_members) {
447
            $status = $this->_dealWithOriginalMembers($original_members, $new_members_of_role, $rolename);
448
            if ($status !== 0) {
449
                return -1;
450
            }
451
        }
452
453
        if ($original_admins) {
454
            $status = $this->_dealWithOriginalAdmins($original_admins, $new_admins_of_role, $rolename);
455
            if ($status !== 0) {
456
                return -1;
457
            }
458
        }
459
460
        return $status;
461
    }
462
463
    /**
464
     * Grants membership in a role.
465
     *
466
     * @param string $role     The name of the target role
467
     * @param string $rolename The name of the role that will belong to the target role
468
     * @param int    $admin    (optional) Flag to grant the admin option
469
     *
470
     * @return int 0 if operation was successful
471
     */
472
    public function grantRole($role, $rolename, $admin = 0)
473
    {
474
        $this->fieldClean($role);
475
        $this->fieldClean($rolename);
476
477
        $sql = "GRANT \"{$role}\" TO \"{$rolename}\"";
478
        if ($admin == 1) {
479
            $sql .= ' WITH ADMIN OPTION';
480
        }
481
482
        return $this->execute($sql);
483
    }
484
485
    /**
486
     * Revokes membership in a role.
487
     *
488
     * @param string $role     The name of the target role
489
     * @param string $rolename The name of the role that will not belong to the target role
490
     * @param int    $admin    (optional) Flag to revoke only the admin option
491
     * @param string $type     (optional) Type of revoke: RESTRICT | CASCADE
492
     *
493
     * @return int 0 if operation was successful
494
     */
495
    public function revokeRole($role, $rolename, $admin = 0, $type = 'RESTRICT')
496
    {
497
        $this->fieldClean($role);
498
        $this->fieldClean($rolename);
499
500
        $sql = 'REVOKE ';
501
        if ($admin == 1) {
502
            $sql .= 'ADMIN OPTION FOR ';
503
        }
504
505
        $sql .= "\"{$role}\" FROM \"{$rolename}\" {$type}";
506
507
        return $this->execute($sql);
508
    }
509
510
    /**
511
     * Removes a role.
512
     *
513
     * @param string $rolename The name of the role to drop
514
     *
515
     * @return int 0 if operation was successful
516
     */
517
    public function dropRole($rolename)
518
    {
519
        $this->fieldClean($rolename);
520
521
        $sql = "DROP ROLE \"{$rolename}\"";
522
523
        return $this->execute($sql);
524
    }
525
526
    /**
527
     * Creates a new user.
528
     *
529
     * @param string $username   The username of the user to create
530
     * @param string $password   A password for the user
531
     * @param bool   $createdb   boolean Whether or not the user can create databases
532
     * @param bool   $createuser boolean Whether or not the user can create other users
533
     * @param string $expiry     string Format 'YYYY-MM-DD HH:MM:SS'.  '' means never expire
534
     * @param array  $groups     The groups to create the user in
535
     *
536
     * @return int 0 if operation was successful
537
     *
538
     * @internal param $group (array) The groups to create the user in
539
     */
540
    public function createUser($username, $password, $createdb, $createuser, $expiry, $groups)
541
    {
542
        $enc = $this->_encryptPassword($username, $password);
543
        $this->fieldClean($username);
544
        $this->clean($enc);
545
        $this->clean($expiry);
546
        $this->fieldArrayClean($groups);
547
548
        $sql = "CREATE USER \"{$username}\"";
549
        if ($password != '') {
550
            $sql .= " WITH ENCRYPTED PASSWORD '{$enc}'";
551
        }
552
553
        $sql .= $createdb ? ' CREATEDB' : ' NOCREATEDB';
554
        $sql .= $createuser ? ' CREATEUSER' : ' NOCREATEUSER';
555
        if (is_array($groups) && sizeof($groups) > 0) {
556
            $sql .= ' IN GROUP "' . join('", "', $groups) . '"';
557
        }
558
559
        if ($expiry != '') {
560
            $sql .= " VALID UNTIL '{$expiry}'";
561
        } else {
562
            $sql .= " VALID UNTIL 'infinity'";
563
        }
564
565
        return $this->execute($sql);
566
    }
567
568
    /**
569
     * Adjusts a user's info and renames the user.
570
     *
571
     * @param string $username   The username of the user to modify
572
     * @param string $password   A new password for the user
573
     * @param bool   $createdb   boolean Whether or not the user can create databases
574
     * @param bool   $createuser boolean Whether or not the user can create other users
575
     * @param string $expiry     string Format 'YYYY-MM-DD HH:MM:SS'.  '' means never expire.
576
     * @param string $newname    The new name of the user
577
     *
578
     * @return bool|int 0 success
579
     */
580
    public function setRenameUser($username, $password, $createdb, $createuser, $expiry, $newname)
581
    {
582
        $status = $this->beginTransaction();
583
        if ($status != 0) {
584
            return -1;
585
        }
586
587
        if ($username != $newname) {
588
            $status = $this->renameUser($username, $newname);
589
            if ($status != 0) {
590
                $this->rollbackTransaction();
591
592
                return -3;
593
            }
594
            $username = $newname;
595
        }
596
597
        $status = $this->setUser($username, $password, $createdb, $createuser, $expiry);
598
        if ($status != 0) {
599
            $this->rollbackTransaction();
600
601
            return -2;
602
        }
603
604
        return $this->endTransaction();
605
    }
606
607
    /**
608
     * Renames a user.
609
     *
610
     * @param string $username The username of the user to rename
611
     * @param string $newname  The new name of the user
612
     *
613
     * @return int 0 if operation was successful
614
     */
615
    public function renameUser($username, $newname)
616
    {
617
        $this->fieldClean($username);
618
        $this->fieldClean($newname);
619
620
        $sql = "ALTER USER \"{$username}\" RENAME TO \"{$newname}\"";
621
622
        return $this->execute($sql);
623
    }
624
625
    // Tablespace functions
626
627
    /**
628
     * Adjusts a user's info.
629
     *
630
     * @param string $username   The username of the user to modify
631
     * @param string $password   A new password for the user
632
     * @param bool   $createdb   boolean Whether or not the user can create databases
633
     * @param bool   $createuser boolean Whether or not the user can create other users
634
     * @param string $expiry     string Format 'YYYY-MM-DD HH:MM:SS'.  '' means never expire.
635
     *
636
     * @return int 0 if operation was successful
637
     */
638
    public function setUser($username, $password, $createdb, $createuser, $expiry)
639
    {
640
        $enc = $this->_encryptPassword($username, $password);
641
        $this->fieldClean($username);
642
        $this->clean($enc);
643
        $this->clean($expiry);
644
645
        $sql = "ALTER USER \"{$username}\"";
646
        if ($password != '') {
647
            $sql .= " WITH ENCRYPTED PASSWORD '{$enc}'";
648
        }
649
650
        $sql .= $createdb ? ' CREATEDB' : ' NOCREATEDB';
651
        $sql .= $createuser ? ' CREATEUSER' : ' NOCREATEUSER';
652
        if ($expiry != '') {
653
            $sql .= " VALID UNTIL '{$expiry}'";
654
        } else {
655
            $sql .= " VALID UNTIL 'infinity'";
656
        }
657
658
        return $this->execute($sql);
659
    }
660
661
    /**
662
     * Removes a user.
663
     *
664
     * @param string $username The username of the user to drop
665
     *
666
     * @return int 0 if operation was successful
667
     */
668
    public function dropUser($username)
669
    {
670
        $this->fieldClean($username);
671
672
        $sql = "DROP USER \"{$username}\"";
673
674
        return $this->execute($sql);
675
    }
676
677
    /**
678
     * Changes a role's password.
679
     *
680
     * @param string $rolename The role name
681
     * @param string $password The new password
682
     *
683
     * @return int 0 if operation was successful
684
     */
685
    public function changePassword($rolename, $password)
686
    {
687
        $enc = $this->_encryptPassword($rolename, $password);
688
        $this->fieldClean($rolename);
689
        $this->clean($enc);
690
691
        $sql = "ALTER ROLE \"{$rolename}\" WITH ENCRYPTED PASSWORD '{$enc}'";
692
693
        return $this->execute($sql);
694
    }
695
696
    /**
697
     * Adds a group member.
698
     *
699
     * @param string $groname The name of the group
700
     * @param string $user    The name of the user to add to the group
701
     *
702
     * @return int 0 if operation was successful
703
     */
704
    public function addGroupMember($groname, $user)
705
    {
706
        $this->fieldClean($groname);
707
        $this->fieldClean($user);
708
709
        $sql = "ALTER GROUP \"{$groname}\" ADD USER \"{$user}\"";
710
711
        return $this->execute($sql);
712
    }
713
714
    /**
715
     * Returns all role names which the role belongs to.
716
     *
717
     * @param string $rolename The role name
718
     *
719
     * @return \PHPPgAdmin\ADORecordSet All role names
720
     */
721
    public function getMemberOf($rolename)
722
    {
723
        $this->clean($rolename);
724
725
        $sql = "
726
			SELECT rolname FROM pg_catalog.pg_roles R, pg_auth_members M
727
			WHERE R.oid=M.roleid
728
				AND member IN (
729
					SELECT oid FROM pg_catalog.pg_roles
730
					WHERE rolname='{$rolename}')
731
			ORDER BY rolname";
732
733
        return $this->selectSet($sql);
734
    }
735
736
    // Administration functions
737
738
    /**
739
     * Returns all role names that are members of a role.
740
     *
741
     * @param string $rolename The role name
742
     * @param string $admin    (optional) Find only admin members
743
     *
744
     * @return \PHPPgAdmin\ADORecordSet All role names
745
     */
746
    public function getMembers($rolename, $admin = 'f')
747
    {
748
        $this->clean($rolename);
749
750
        $sql = "
751
			SELECT rolname FROM pg_catalog.pg_roles R, pg_auth_members M
752
			WHERE R.oid=M.member AND admin_option='{$admin}'
753
				AND roleid IN (SELECT oid FROM pg_catalog.pg_roles
754
					WHERE rolname='{$rolename}')
755
			ORDER BY rolname";
756
757
        return $this->selectSet($sql);
758
    }
759
760
    /**
761
     * Removes a group member.
762
     *
763
     * @param string $groname The name of the group
764
     * @param string $user    The name of the user to remove from the group
765
     *
766
     * @return int 0 if operation was successful
767
     */
768
    public function dropGroupMember($groname, $user)
769
    {
770
        $this->fieldClean($groname);
771
        $this->fieldClean($user);
772
773
        $sql = "ALTER GROUP \"{$groname}\" DROP USER \"{$user}\"";
774
775
        return $this->execute($sql);
776
    }
777
778
    /**
779
     * Return users in a specific group.
780
     *
781
     * @param string $groname The name of the group
782
     *
783
     * @return \PHPPgAdmin\ADORecordSet All users in the group
784
     */
785
    public function getGroup($groname)
786
    {
787
        $this->clean($groname);
788
789
        $sql = "
790
			SELECT s.usename FROM pg_catalog.pg_user s, pg_catalog.pg_group g
791
			WHERE g.groname='{$groname}' AND s.usesysid = ANY (g.grolist)
792
			ORDER BY s.usename";
793
794
        return $this->selectSet($sql);
795
    }
796
797
    /**
798
     * Returns all groups in the database cluser.
799
     *
800
     * @return \PHPPgAdmin\ADORecordSet All groups
801
     */
802
    public function getGroups()
803
    {
804
        $sql = 'SELECT groname FROM pg_group ORDER BY groname';
805
806
        return $this->selectSet($sql);
807
    }
808
809
    /**
810
     * Creates a new group.
811
     *
812
     * @param string $groname The name of the group
813
     * @param array  $users   An array of users to add to the group
814
     *
815
     * @return int 0 if operation was successful
816
     */
817
    public function createGroup($groname, $users)
818
    {
819
        $this->fieldClean($groname);
820
821
        $sql = "CREATE GROUP \"{$groname}\"";
822
823
        if (is_array($users) && sizeof($users) > 0) {
824
            $this->fieldArrayClean($users);
825
            $sql .= ' WITH USER "' . join('", "', $users) . '"';
826
        }
827
828
        return $this->execute($sql);
829
    }
830
831
    /**
832
     * Removes a group.
833
     *
834
     * @param string $groname The name of the group to drop
835
     *
836
     * @return int 0 if operation was successful
837
     */
838
    public function dropGroup($groname)
839
    {
840
        $this->fieldClean($groname);
841
842
        $sql = "DROP GROUP \"{$groname}\"";
843
844
        return $this->execute($sql);
845
    }
846
847
    /**
848
     * Grants a privilege to a user, group or public.
849
     *
850
     * @param string $mode        'GRANT' or 'REVOKE';
851
     * @param mixed  $type        The type of object
852
     * @param string $object      The name of the object
853
     * @param bool   $public      True to grant to public, false otherwise
854
     * @param mixed  $usernames   the array of usernames to grant privs to
855
     * @param mixed  $groupnames  the array of group names to grant privs to
856
     * @param mixed  $privileges  The array of privileges to grant (eg. ('SELECT', 'ALL PRIVILEGES', etc.) )
857
     * @param bool   $grantoption True if has grant option, false otherwise
858
     * @param bool   $cascade     True for cascade revoke, false otherwise
859
     * @param string $table       the column's table if type=column
860
     *
861
     * @return int 0 if operation was successful
862
     */
863
    public function setPrivileges(
864
        $mode,
865
        $type,
866
        $object,
867
        $public,
868
        $usernames,
869
        $groupnames,
870
        $privileges,
871
        $grantoption,
872
        $cascade,
873
        $table
874
    ) {
875
        $f_schema = $this->_schema;
876
        $this->fieldClean($f_schema);
877
        $this->fieldArrayClean($usernames);
878
        $this->fieldArrayClean($groupnames);
879
880
        // Input checking
881
        if (!is_array($privileges) || sizeof($privileges) == 0) {
882
            return -3;
883
        }
884
885
        if (!is_array($usernames) || !is_array($groupnames) ||
886
            (!$public && sizeof($usernames) == 0 && sizeof($groupnames) == 0)) {
887
            return -4;
888
        }
889
890
        if ($mode != 'GRANT' && $mode != 'REVOKE') {
891
            return -5;
892
        }
893
894
        $sql = $mode;
895
896
        // Grant option
897
        if ($this->hasGrantOption() && $mode == 'REVOKE' && $grantoption) {
898
            $sql .= ' GRANT OPTION FOR';
899
        }
900
901
        if (in_array('ALL PRIVILEGES', $privileges, true)) {
902
            $sql .= ' ALL PRIVILEGES';
903
        } else {
904
            if ($type == 'column') {
905
                $this->fieldClean($object);
906
                $sql .= ' ' . join(" (\"{$object}\"), ", $privileges);
907
            } else {
908
                $sql .= ' ' . join(', ', $privileges);
909
            }
910
        }
911
912
        switch ($type) {
913
            case 'column':
914
                $sql .= " (\"{$object}\")";
915
                $object = $table;
916
            // no break
917
            case 'table':
918
            case 'view':
919
            case 'sequence':
920
                $this->fieldClean($object);
921
                $sql .= " ON \"{$f_schema}\".\"{$object}\"";
922
923
                break;
924
            case 'database':
925
                $this->fieldClean($object);
926
                $sql .= " ON DATABASE \"{$object}\"";
927
928
                break;
929
            case 'function':
930
                // Function comes in with $object as function OID
931
                $fn = $this->getFunction($object);
932
                $this->fieldClean($fn->fields['proname']);
933
                $sql .= " ON FUNCTION \"{$f_schema}\".\"{$fn->fields['proname']}\"({$fn->fields['proarguments']})";
934
935
                break;
936
            case 'language':
937
                $this->fieldClean($object);
938
                $sql .= " ON LANGUAGE \"{$object}\"";
939
940
                break;
941
            case 'schema':
942
                $this->fieldClean($object);
943
                $sql .= " ON SCHEMA \"{$object}\"";
944
945
                break;
946
            case 'tablespace':
947
                $this->fieldClean($object);
948
                $sql .= " ON TABLESPACE \"{$object}\"";
949
950
                break;
951
            default:
952
                return -1;
953
        }
954
955
        // Dump PUBLIC
956
        $first = true;
957
        $sql .= ($mode == 'GRANT') ? ' TO ' : ' FROM ';
958
        if ($public) {
959
            $sql .= 'PUBLIC';
960
            $first = false;
961
        }
962
        // Dump users
963
        foreach ($usernames as $v) {
964
            if ($first) {
965
                $sql .= "\"{$v}\"";
966
                $first = false;
967
            } else {
968
                $sql .= ", \"{$v}\"";
969
            }
970
        }
971
        // Dump groups
972
        foreach ($groupnames as $v) {
973
            if ($first) {
974
                $sql .= "GROUP \"{$v}\"";
975
                $first = false;
976
            } else {
977
                $sql .= ", GROUP \"{$v}\"";
978
            }
979
        }
980
981
        // Grant option
982
        if ($this->hasGrantOption() && $mode == 'GRANT' && $grantoption) {
983
            $sql .= ' WITH GRANT OPTION';
984
        }
985
986
        // Cascade revoke
987
        if ($this->hasGrantOption() && $mode == 'REVOKE' && $cascade) {
988
            $sql .= ' CASCADE';
989
        }
990
991
        return $this->execute($sql);
992
    }
993
994
    abstract public function fieldClean(&$str);
995
996
    abstract public function beginTransaction();
997
998
    abstract public function rollbackTransaction();
999
1000
    abstract public function endTransaction();
1001
1002
    abstract public function execute($sql);
1003
1004
    abstract public function setComment($obj_type, $obj_name, $table, $comment, $basetype = null);
1005
1006
    abstract public function selectSet($sql);
1007
1008
    abstract public function clean(&$str);
1009
1010
    abstract public function hasGrantOption();
1011
1012
    abstract public function getFunction($function_oid);
1013
1014
    abstract public function fieldArrayClean(&$arr);
1015
}
1016