Passed
Push — develop ( 2d5edd...a33225 )
by Felipe
05:40
created

RoleTrait::setUser()   B

Complexity

Conditions 5
Paths 16

Size

Total Lines 21
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

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