~kees/eucalyptus/lp436977

« back to all changes in this revision

Viewing changes to util/euca_rootwrap.c

  • Committer: Kees Cook
  • Date: 2009-10-06 20:52:06 UTC
  • Revision ID: kees@outflux.net-20091006205206-ps7pvee616tqdj2x
* Attempt to limit the scope of euca_rootwrap, with wrapper configuration
  and helper scripts (LP: #436977):
  - tools/dd-lv, tools/kill-vblade, tools/modprobe-aoe
  - util/euca_rootwrap.c, util/wrappers.conf

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
Copyright (c) 2009  Eucalyptus Systems, Inc.    
3
 
 
4
 
This program is free software: you can redistribute it and/or modify
5
 
it under the terms of the GNU General Public License as published by 
6
 
the Free Software Foundation, only version 3 of the License.  
7
 
 
8
 
This file is distributed in the hope that it will be useful, but WITHOUT
9
 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11
 
for more details.  
12
 
 
13
 
You should have received a copy of the GNU General Public License along
14
 
with this program.  If not, see <http://www.gnu.org/licenses/>.
15
 
 
16
 
Please contact Eucalyptus Systems, Inc., 130 Castilian
17
 
Dr., Goleta, CA 93101 USA or visit <http://www.eucalyptus.com/licenses/> 
18
 
if you need additional information or have any questions.
19
 
 
20
 
This file may incorporate work covered under the following copyright and
21
 
permission notice:
22
 
 
23
 
  Software License Agreement (BSD License)
24
 
 
25
 
  Copyright (c) 2008, Regents of the University of California
26
 
  
27
 
 
28
 
  Redistribution and use of this software in source and binary forms, with
29
 
  or without modification, are permitted provided that the following
30
 
  conditions are met:
31
 
 
32
 
    Redistributions of source code must retain the above copyright notice,
33
 
    this list of conditions and the following disclaimer.
34
 
 
35
 
    Redistributions in binary form must reproduce the above copyright
36
 
    notice, this list of conditions and the following disclaimer in the
37
 
    documentation and/or other materials provided with the distribution.
38
 
 
39
 
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
40
 
  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
41
 
  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
42
 
  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
43
 
  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
44
 
  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
45
 
  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
46
 
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
47
 
  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
48
 
  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
49
 
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. USERS OF
50
 
  THIS SOFTWARE ACKNOWLEDGE THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE
51
 
  LICENSED MATERIAL, COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS
52
 
  SOFTWARE, AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING
53
 
  IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, SANTA
54
 
  BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, WHICH IN
55
 
  THE REGENTS’ DISCRETION MAY INCLUDE, WITHOUT LIMITATION, REPLACEMENT
56
 
  OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO IDENTIFIED, OR
57
 
  WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT NEEDED TO COMPLY WITH
58
 
  ANY SUCH LICENSES OR RIGHTS.
 
2
   Copyright (C) 2009 Canonical, Ltd.
 
3
   Author: Kees Cook <kees@ubuntu.com>
 
4
 
 
5
   This program is free software: you can redistribute it and/or modify
 
6
   it under the terms of the GNU General Public License as published by
 
7
   the Free Software Foundation, only version 3 of the License.
 
8
 
 
9
   This file is distributed in the hope that it will be useful, but WITHOUT
 
10
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
11
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
12
   for more details.
 
13
 
 
14
   You should have received a copy of the GNU General Public License along
 
15
   with this program.  If not, see <http://www.gnu.org/licenses/>.
 
16
 
59
17
*/
 
18
#define _GNU_SOURCE
60
19
#include <stdio.h>
61
20
#include <stdlib.h>
 
21
#include <string.h>
 
22
#include <ctype.h>
62
23
#include <unistd.h>
63
 
 
64
 
int main(int argc, char **argv) {
65
 
  char **newargv;
66
 
  int i;
67
 
 
68
 
  if (argc <= 1) {
69
 
    exit(1);
70
 
  }
71
 
  newargv = argv + 1;
72
 
  exit(execvp(newargv[0], newargv));
 
24
#include <assert.h>
 
25
#include <sys/types.h>
 
26
#include <pwd.h>
 
27
#include <grp.h>
 
28
#include <sys/capability.h>
 
29
#include <sys/prctl.h>
 
30
 
 
31
struct wrapper_command {
 
32
    char *name;
 
33
    char *cmdline;
 
34
    int   uses_uid;
 
35
    uid_t uid;
 
36
    int   uses_caps;
 
37
    cap_value_t caps;
 
38
};
 
39
 
 
40
#define LINE_MAX  1024
 
41
//#define CMDS_CONF "/etc/eucalyptus/wrappers.conf"
 
42
#define CMDS_CONF "./wrappers.conf"
 
43
#define CMDS_MAX  80
 
44
struct wrapper_command cmds[CMDS_MAX] = { };
 
45
 
 
46
void load_cmds(void)
 
47
{
 
48
    char buf[LINE_MAX];
 
49
    int count = 0;
 
50
    FILE *conf;
 
51
 
 
52
    if ( !(conf = fopen(CMDS_CONF,"r")) ) {
 
53
        perror(CMDS_CONF);
 
54
        exit(1);
 
55
    }
 
56
    while (fgets(buf, LINE_MAX, conf)) {
 
57
        char *step, *name, *cmdline, *capabilities;
 
58
        if (buf[0] == '#') continue;
 
59
 
 
60
        step = buf;
 
61
 
 
62
        name = strsep(&step, " \t\n");
 
63
        if (!name) continue;
 
64
        while (*step == ' ' || *step == '\t' || *step == '\n') step++;
 
65
 
 
66
        cmdline = strsep(&step, " \t\n");
 
67
        if (!cmdline) continue;
 
68
        while (*step == ' ' || *step == '\t' || *step == '\n') step++;
 
69
 
 
70
        capabilities = strsep(&step, " \t\n");
 
71
        if (!capabilities) continue;
 
72
 
 
73
        assert (count<CMDS_MAX);
 
74
        cmds[count].name = strdup(name);
 
75
        cmds[count].cmdline = strdup(cmdline);
 
76
        if (capabilities[0] != '\0') {
 
77
            if (strncmp(capabilities,"cap",3)==0) {
 
78
                if (cap_from_name(capabilities, &cmds[count].caps)) {
 
79
                    fprintf(stderr,"Bad capabilities\n");
 
80
                    exit(1);
 
81
                }
 
82
                cmds[count].uses_caps = 1;
 
83
            }
 
84
            else {
 
85
                if (isdigit(*capabilities)) {
 
86
                    cmds[count].uses_uid = 1;
 
87
                    cmds[count].uid = atoi(capabilities);
 
88
                }
 
89
            }
 
90
        }
 
91
        count++;
 
92
    }
 
93
    fclose(conf);
 
94
}
 
95
 
 
96
#if 0
 
97
void dump(void)
 
98
{
 
99
    struct wrapper_command *cmd;
 
100
    for (cmd=cmds; cmd && cmd->name; cmd++) {
 
101
        printf("[%s] [%s] ", cmd->name, cmd->cmdline);
 
102
        if (cmd->uses_uid)
 
103
            printf("uid:%d", cmd->uid);
 
104
        else if (cmd->uses_caps) {
 
105
            char *cap_string = cap_to_name(cmd->caps);
 
106
            printf("cap:%s(%d)", cap_string, cmd->caps);
 
107
            cap_free(cap_string);
 
108
        }
 
109
        printf("\n");
 
110
    }
 
111
}
 
112
#endif
 
113
 
 
114
void run(struct wrapper_command *cmd, int argc, char *argv[])
 
115
{
 
116
    uid_t uid = getuid();
 
117
    gid_t gid = getgid();
 
118
    struct passwd *entry;
 
119
    int i;
 
120
    char **args;
 
121
    cap_t caps;
 
122
 
 
123
    if (cmd->uses_uid) {
 
124
        uid = cmd->uid;
 
125
    }
 
126
    if (cmd->uses_caps) {
 
127
        /* Set capabilities */
 
128
 
 
129
        /* Unfortunately, capabilities are unconditionally cleared across exec().
 
130
           So this wrapper is a bit useless at the moment in its attempt to limit
 
131
           privileges.
 
132
            http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=439873
 
133
            http://lkml.indiana.edu/hypermail/linux/kernel/0704.2/0667.html
 
134
         */
 
135
 
 
136
        assert (caps = cap_init());
 
137
        assert (cap_clear(caps) == 0);
 
138
        assert (cap_set_flag(caps, CAP_EFFECTIVE,   1, &cmd->caps, CAP_SET) == 0);
 
139
        assert (cap_set_flag(caps, CAP_PERMITTED,   1, &cmd->caps, CAP_SET) == 0);
 
140
        assert (cap_set_flag(caps, CAP_INHERITABLE, 1, &cmd->caps, CAP_SET) == 0);
 
141
        assert (cap_set_proc(caps) == 0);
 
142
 
 
143
        assert (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == 0);
 
144
    }
 
145
 
 
146
    if ( !(entry = getpwuid(uid)) ) {
 
147
        perror("getpwuid");
 
148
        exit(253);
 
149
    }
 
150
 
 
151
    uid = entry->pw_uid;
 
152
    gid = entry->pw_gid;
 
153
 
 
154
    /* If we're changing user id, drop all the supplemental groups */
 
155
    if (uid != getuid()) {
 
156
        if (setgroups(0, NULL)) {
 
157
            perror("setgroups");
 
158
            exit(253);
 
159
        }
 
160
    }
 
161
 
 
162
    /* Set group */
 
163
    if (setresgid(gid, gid, gid)) {
 
164
        perror("setresgid");
 
165
        exit(253);
 
166
    }
 
167
    /* Set uid */
 
168
    if (setresuid(uid, uid, uid)) {
 
169
        perror("setresuid");
 
170
        exit(253);
 
171
    }
 
172
 
 
173
    if (cmd->uses_caps) {
 
174
        /* Re-gain capabilities */
 
175
        assert (cap_set_proc(caps) == 0);
 
176
        assert (cap_free(caps) == 0);
 
177
    }
 
178
 
 
179
    if ( !(args = calloc(argc, sizeof(char*))) ) {
 
180
        perror("calloc");
 
181
        exit(253);
 
182
    }
 
183
 
 
184
    args[0] = strdup(cmd->cmdline);
 
185
    for (i = 2; i<argc; i++) {
 
186
        args[i-1] = strdup(argv[i]);
 
187
    }
 
188
    execv(args[0], args);
 
189
}
 
190
 
 
191
int main(int argc, char *argv[])
 
192
{
 
193
    struct wrapper_command *cmd;
 
194
 
 
195
    if (argc>1) {
 
196
        load_cmds();
 
197
 
 
198
        for (cmd=cmds; cmd && cmd->name; cmd++) {
 
199
            if (strcmp(argv[1],cmd->name) == 0 ||
 
200
                strcmp(argv[1],cmd->cmdline) == 0) {
 
201
 
 
202
                run(cmd, argc, argv);
 
203
                return 255;
 
204
            }
 
205
        }
 
206
    }
 
207
 
 
208
    fprintf(stderr,"Disallowed command\n");
 
209
    return 127;
73
210
}