~vcs-imports/samba/main

« back to all changes in this revision

Viewing changes to source/lib/smbrun.c

  • Committer: jerry
  • Date: 2006-07-14 21:48:39 UTC
  • Revision ID: vcs-imports@canonical.com-20060714214839-586d8c489a8fcead
gutting trunk to move to svn:externals

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* 
2
 
   Unix SMB/CIFS implementation.
3
 
   run a command as a specified user
4
 
   Copyright (C) Andrew Tridgell 1992-1998
5
 
   
6
 
   This program is free software; you can redistribute it and/or modify
7
 
   it under the terms of the GNU General Public License as published by
8
 
   the Free Software Foundation; either version 2 of the License, or
9
 
   (at your option) any later version.
10
 
   
11
 
   This program is distributed in the hope that it will be useful,
12
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
   GNU General Public License for more details.
15
 
   
16
 
   You should have received a copy of the GNU General Public License
17
 
   along with this program; if not, write to the Free Software
18
 
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
 
*/
20
 
 
21
 
#include "includes.h"
22
 
 
23
 
/* need to move this from here!! need some sleep ... */
24
 
struct current_user current_user;
25
 
 
26
 
/****************************************************************************
27
 
This is a utility function of smbrun().
28
 
****************************************************************************/
29
 
 
30
 
static int setup_out_fd(void)
31
 
{  
32
 
        int fd;
33
 
        pstring path;
34
 
 
35
 
        slprintf(path, sizeof(path)-1, "%s/smb.XXXXXX", tmpdir());
36
 
 
37
 
        /* now create the file */
38
 
        fd = smb_mkstemp(path);
39
 
 
40
 
        if (fd == -1) {
41
 
                DEBUG(0,("setup_out_fd: Failed to create file %s. (%s)\n",
42
 
                        path, strerror(errno) ));
43
 
                return -1;
44
 
        }
45
 
 
46
 
        DEBUG(10,("setup_out_fd: Created tmp file %s\n", path ));
47
 
 
48
 
        /* Ensure file only kept around by open fd. */
49
 
        unlink(path);
50
 
        return fd;
51
 
}
52
 
 
53
 
/****************************************************************************
54
 
run a command being careful about uid/gid handling and putting the output in
55
 
outfd (or discard it if outfd is NULL).
56
 
****************************************************************************/
57
 
 
58
 
int smbrun(const char *cmd, int *outfd)
59
 
{
60
 
        pid_t pid;
61
 
        uid_t uid = current_user.ut.uid;
62
 
        gid_t gid = current_user.ut.gid;
63
 
        
64
 
        /*
65
 
         * Lose any elevated privileges.
66
 
         */
67
 
        drop_effective_capability(KERNEL_OPLOCK_CAPABILITY);
68
 
        drop_effective_capability(DMAPI_ACCESS_CAPABILITY);
69
 
 
70
 
        /* point our stdout at the file we want output to go into */
71
 
 
72
 
        if (outfd && ((*outfd = setup_out_fd()) == -1)) {
73
 
                return -1;
74
 
        }
75
 
 
76
 
        /* in this method we will exec /bin/sh with the correct
77
 
           arguments, after first setting stdout to point at the file */
78
 
 
79
 
        /*
80
 
         * We need to temporarily stop CatchChild from eating
81
 
         * SIGCLD signals as it also eats the exit status code. JRA.
82
 
         */
83
 
 
84
 
        CatchChildLeaveStatus();
85
 
                                        
86
 
        if ((pid=sys_fork()) < 0) {
87
 
                DEBUG(0,("smbrun: fork failed with error %s\n", strerror(errno) ));
88
 
                CatchChild(); 
89
 
                if (outfd) {
90
 
                        close(*outfd);
91
 
                        *outfd = -1;
92
 
                }
93
 
                return errno;
94
 
        }
95
 
 
96
 
        if (pid) {
97
 
                /*
98
 
                 * Parent.
99
 
                 */
100
 
                int status=0;
101
 
                pid_t wpid;
102
 
 
103
 
                
104
 
                /* the parent just waits for the child to exit */
105
 
                while((wpid = sys_waitpid(pid,&status,0)) < 0) {
106
 
                        if(errno == EINTR) {
107
 
                                errno = 0;
108
 
                                continue;
109
 
                        }
110
 
                        break;
111
 
                }
112
 
 
113
 
                CatchChild(); 
114
 
 
115
 
                if (wpid != pid) {
116
 
                        DEBUG(2,("waitpid(%d) : %s\n",(int)pid,strerror(errno)));
117
 
                        if (outfd) {
118
 
                                close(*outfd);
119
 
                                *outfd = -1;
120
 
                        }
121
 
                        return -1;
122
 
                }
123
 
 
124
 
                /* Reset the seek pointer. */
125
 
                if (outfd) {
126
 
                        sys_lseek(*outfd, 0, SEEK_SET);
127
 
                }
128
 
 
129
 
#if defined(WIFEXITED) && defined(WEXITSTATUS)
130
 
                if (WIFEXITED(status)) {
131
 
                        return WEXITSTATUS(status);
132
 
                }
133
 
#endif
134
 
 
135
 
                return status;
136
 
        }
137
 
        
138
 
        CatchChild(); 
139
 
        
140
 
        /* we are in the child. we exec /bin/sh to do the work for us. we
141
 
           don't directly exec the command we want because it may be a
142
 
           pipeline or anything else the config file specifies */
143
 
        
144
 
        /* point our stdout at the file we want output to go into */
145
 
        if (outfd) {
146
 
                close(1);
147
 
                if (sys_dup2(*outfd,1) != 1) {
148
 
                        DEBUG(2,("Failed to create stdout file descriptor\n"));
149
 
                        close(*outfd);
150
 
                        exit(80);
151
 
                }
152
 
        }
153
 
 
154
 
        /* now completely lose our privileges. This is a fairly paranoid
155
 
           way of doing it, but it does work on all systems that I know of */
156
 
 
157
 
        become_user_permanently(uid, gid);
158
 
 
159
 
        if (getuid() != uid || geteuid() != uid ||
160
 
            getgid() != gid || getegid() != gid) {
161
 
                /* we failed to lose our privileges - do not execute
162
 
                   the command */
163
 
                exit(81); /* we can't print stuff at this stage,
164
 
                             instead use exit codes for debugging */
165
 
        }
166
 
        
167
 
#ifndef __INSURE__
168
 
        /* close all other file descriptors, leaving only 0, 1 and 2. 0 and
169
 
           2 point to /dev/null from the startup code */
170
 
        {
171
 
        int fd;
172
 
        for (fd=3;fd<256;fd++) close(fd);
173
 
        }
174
 
#endif
175
 
 
176
 
        execl("/bin/sh","sh","-c",cmd,NULL);  
177
 
        
178
 
        /* not reached */
179
 
        exit(82);
180
 
        return 1;
181
 
}
182
 
 
183
 
 
184
 
/****************************************************************************
185
 
run a command being careful about uid/gid handling and putting the output in
186
 
outfd (or discard it if outfd is NULL).
187
 
sends the provided secret to the child stdin.
188
 
****************************************************************************/
189
 
 
190
 
int smbrunsecret(const char *cmd, const char *secret)
191
 
{
192
 
        pid_t pid;
193
 
        uid_t uid = current_user.ut.uid;
194
 
        gid_t gid = current_user.ut.gid;
195
 
        int ifd[2];
196
 
        
197
 
        /*
198
 
         * Lose any elevated privileges.
199
 
         */
200
 
        drop_effective_capability(KERNEL_OPLOCK_CAPABILITY);
201
 
        drop_effective_capability(DMAPI_ACCESS_CAPABILITY);
202
 
 
203
 
        /* build up an input pipe */
204
 
        if(pipe(ifd)) {
205
 
                return -1;
206
 
        }
207
 
 
208
 
        /* in this method we will exec /bin/sh with the correct
209
 
           arguments, after first setting stdout to point at the file */
210
 
 
211
 
        /*
212
 
         * We need to temporarily stop CatchChild from eating
213
 
         * SIGCLD signals as it also eats the exit status code. JRA.
214
 
         */
215
 
 
216
 
        CatchChildLeaveStatus();
217
 
                                        
218
 
        if ((pid=sys_fork()) < 0) {
219
 
                DEBUG(0, ("smbrunsecret: fork failed with error %s\n", strerror(errno)));
220
 
                CatchChild(); 
221
 
                return errno;
222
 
        }
223
 
 
224
 
        if (pid) {
225
 
                /*
226
 
                 * Parent.
227
 
                 */
228
 
                int status = 0;
229
 
                pid_t wpid;
230
 
                size_t towrite;
231
 
                ssize_t wrote;
232
 
                
233
 
                close(ifd[0]);
234
 
                /* send the secret */
235
 
                towrite = strlen(secret);
236
 
                wrote = write(ifd[1], secret, towrite);
237
 
                if ( wrote != towrite ) {
238
 
                    DEBUG(0,("smbrunsecret: wrote %ld of %lu bytes\n",(long)wrote,(unsigned long)towrite));
239
 
                }
240
 
                fsync(ifd[1]);
241
 
                close(ifd[1]);
242
 
 
243
 
                /* the parent just waits for the child to exit */
244
 
                while((wpid = sys_waitpid(pid, &status, 0)) < 0) {
245
 
                        if(errno == EINTR) {
246
 
                                errno = 0;
247
 
                                continue;
248
 
                        }
249
 
                        break;
250
 
                }
251
 
 
252
 
                CatchChild(); 
253
 
 
254
 
                if (wpid != pid) {
255
 
                        DEBUG(2, ("waitpid(%d) : %s\n", (int)pid, strerror(errno)));
256
 
                        return -1;
257
 
                }
258
 
 
259
 
#if defined(WIFEXITED) && defined(WEXITSTATUS)
260
 
                if (WIFEXITED(status)) {
261
 
                        return WEXITSTATUS(status);
262
 
                }
263
 
#endif
264
 
 
265
 
                return status;
266
 
        }
267
 
        
268
 
        CatchChild(); 
269
 
        
270
 
        /* we are in the child. we exec /bin/sh to do the work for us. we
271
 
           don't directly exec the command we want because it may be a
272
 
           pipeline or anything else the config file specifies */
273
 
        
274
 
        close(ifd[1]);
275
 
        close(0);
276
 
        if (sys_dup2(ifd[0], 0) != 0) {
277
 
                DEBUG(2,("Failed to create stdin file descriptor\n"));
278
 
                close(ifd[0]);
279
 
                exit(80);
280
 
        }
281
 
 
282
 
        /* now completely lose our privileges. This is a fairly paranoid
283
 
           way of doing it, but it does work on all systems that I know of */
284
 
 
285
 
        become_user_permanently(uid, gid);
286
 
 
287
 
        if (getuid() != uid || geteuid() != uid ||
288
 
            getgid() != gid || getegid() != gid) {
289
 
                /* we failed to lose our privileges - do not execute
290
 
                   the command */
291
 
                exit(81); /* we can't print stuff at this stage,
292
 
                             instead use exit codes for debugging */
293
 
        }
294
 
        
295
 
#ifndef __INSURE__
296
 
        /* close all other file descriptors, leaving only 0, 1 and 2. 0 and
297
 
           2 point to /dev/null from the startup code */
298
 
        {
299
 
                int fd;
300
 
                for (fd = 3; fd < 256; fd++) close(fd);
301
 
        }
302
 
#endif
303
 
 
304
 
        execl("/bin/sh", "sh", "-c", cmd, NULL);  
305
 
        
306
 
        /* not reached */
307
 
        exit(82);
308
 
        return 1;
309
 
}