1 /* Written by Ricky Zhou <ricky@fedoraproject.org>
2  * Fredrik Thulin <fredrik@yubico.com> implemented pam_modutil_drop_priv
3  *
4  * Copyright (c) 2011-2014 Yubico AB
5  * Copyright (c) 2011 Ricky Zhou <ricky@fedoraproject.org>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are
10  * met:
11  *
12  *     * Redistributions of source code must retain the above copyright
13  *       notice, this list of conditions and the following disclaimer.
14  *
15  *     * Redistributions in binary form must reproduce the above
16  *       copyright notice, this list of conditions and the following
17  *       disclaimer in the documentation and/or other materials provided
18  *       with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #ifndef HAVE_PAM_MODUTIL_DROP_PRIV
34 
35 #include <unistd.h>
36 #include <pwd.h>
37 #include <grp.h>
38 #include <errno.h>
39 #include <string.h>
40 #include <stdlib.h>
41 
42 #include "drop_privs.h"
43 #include "util.h"
44 
45 #ifdef HAVE_SECURITY_PAM_APPL_H
46 #include <security/pam_appl.h>
47 #endif
48 #ifdef HAVE_SECURITY_PAM_MODULES_H
49 #include <security/pam_modules.h>
50 #endif
51 
52 
pam_modutil_drop_priv(pam_handle_t * pamh,struct _ykpam_privs * privs,struct passwd * pw)53 int pam_modutil_drop_priv(pam_handle_t *pamh, struct _ykpam_privs *privs, struct passwd *pw) {
54     privs->saved_euid = geteuid();
55     privs->saved_egid = getegid();
56 
57     if ((privs->saved_euid == pw->pw_uid) && (privs->saved_egid == pw->pw_gid)) {
58         D (privs->debug_file, "Privilges already dropped, pretend it is all right");
59         return 0;
60     }
61 
62     privs->saved_groups_length = getgroups(0, NULL);
63     if (privs->saved_groups_length < 0) {
64         D (privs->debug_file, "getgroups: %s", strerror(errno));
65         return -1;
66     }
67 
68     if (privs->saved_groups_length > SAVED_GROUPS_MAX_LEN) {
69         D (privs->debug_file, "to many groups, limiting.");
70         privs->saved_groups_length = SAVED_GROUPS_MAX_LEN;
71     }
72 
73     if (privs->saved_groups_length > 0) {
74         if (getgroups(privs->saved_groups_length, privs->saved_groups) < 0) {
75             D (privs->debug_file, "getgroups: %s", strerror(errno));
76             goto free_out;
77         }
78     }
79 
80     if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
81         D (privs->debug_file, "initgroups: %s", strerror(errno));
82         goto free_out;
83     }
84 
85     if (setegid(pw->pw_gid) < 0) {
86         D (privs->debug_file, "setegid: %s", strerror(errno));
87         goto free_out;
88     }
89 
90     if (seteuid(pw->pw_uid) < 0) {
91         D (privs->debug_file, "seteuid: %s", strerror(errno));
92         goto free_out;
93     }
94 
95     return 0;
96 free_out:
97     return -1;
98 }
99 
pam_modutil_regain_priv(pam_handle_t * pamh,struct _ykpam_privs * privs)100 int pam_modutil_regain_priv(pam_handle_t *pamh, struct _ykpam_privs *privs) {
101     if ((privs->saved_euid == geteuid()) && (privs->saved_egid == getegid())) {
102         D (privs->debug_file, "Privilges already as requested, pretend it is all right");
103         return 0;
104     }
105 
106     if (seteuid(privs->saved_euid) < 0) {
107         D (privs->debug_file, "seteuid: %s", strerror(errno));
108         return -1;
109     }
110 
111     if (setegid(privs->saved_egid) < 0) {
112         D (privs->debug_file, "setegid: %s", strerror(errno));
113         return -1;
114     }
115 
116     if (setgroups(privs->saved_groups_length, privs->saved_groups) < 0) {
117         D (privs->debug_file, "setgroups: %s", strerror(errno));
118         return -1;
119     }
120 
121     return 0;
122 }
123 
124 #endif // HAVE_PAM_MODUTIL_DROP_PRIV
125