2
Unix SMB/CIFS implementation.
3
run a command as a specified user
4
Copyright (C) Andrew Tridgell 1992-1998
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.
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.
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.
23
/* need to move this from here!! need some sleep ... */
24
struct current_user current_user;
26
/****************************************************************************
27
This is a utility function of smbrun().
28
****************************************************************************/
30
static int setup_out_fd(void)
35
slprintf(path, sizeof(path)-1, "%s/smb.XXXXXX", tmpdir());
37
/* now create the file */
38
fd = smb_mkstemp(path);
41
DEBUG(0,("setup_out_fd: Failed to create file %s. (%s)\n",
42
path, strerror(errno) ));
46
DEBUG(10,("setup_out_fd: Created tmp file %s\n", path ));
48
/* Ensure file only kept around by open fd. */
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
****************************************************************************/
58
int smbrun(const char *cmd, int *outfd)
61
uid_t uid = current_user.ut.uid;
62
gid_t gid = current_user.ut.gid;
65
* Lose any elevated privileges.
67
drop_effective_capability(KERNEL_OPLOCK_CAPABILITY);
68
drop_effective_capability(DMAPI_ACCESS_CAPABILITY);
70
/* point our stdout at the file we want output to go into */
72
if (outfd && ((*outfd = setup_out_fd()) == -1)) {
76
/* in this method we will exec /bin/sh with the correct
77
arguments, after first setting stdout to point at the file */
80
* We need to temporarily stop CatchChild from eating
81
* SIGCLD signals as it also eats the exit status code. JRA.
84
CatchChildLeaveStatus();
86
if ((pid=sys_fork()) < 0) {
87
DEBUG(0,("smbrun: fork failed with error %s\n", strerror(errno) ));
104
/* the parent just waits for the child to exit */
105
while((wpid = sys_waitpid(pid,&status,0)) < 0) {
116
DEBUG(2,("waitpid(%d) : %s\n",(int)pid,strerror(errno)));
124
/* Reset the seek pointer. */
126
sys_lseek(*outfd, 0, SEEK_SET);
129
#if defined(WIFEXITED) && defined(WEXITSTATUS)
130
if (WIFEXITED(status)) {
131
return WEXITSTATUS(status);
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 */
144
/* point our stdout at the file we want output to go into */
147
if (sys_dup2(*outfd,1) != 1) {
148
DEBUG(2,("Failed to create stdout file descriptor\n"));
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 */
157
become_user_permanently(uid, gid);
159
if (getuid() != uid || geteuid() != uid ||
160
getgid() != gid || getegid() != gid) {
161
/* we failed to lose our privileges - do not execute
163
exit(81); /* we can't print stuff at this stage,
164
instead use exit codes for debugging */
168
/* close all other file descriptors, leaving only 0, 1 and 2. 0 and
169
2 point to /dev/null from the startup code */
172
for (fd=3;fd<256;fd++) close(fd);
176
execl("/bin/sh","sh","-c",cmd,NULL);
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
****************************************************************************/
190
int smbrunsecret(const char *cmd, const char *secret)
193
uid_t uid = current_user.ut.uid;
194
gid_t gid = current_user.ut.gid;
198
* Lose any elevated privileges.
200
drop_effective_capability(KERNEL_OPLOCK_CAPABILITY);
201
drop_effective_capability(DMAPI_ACCESS_CAPABILITY);
203
/* build up an input pipe */
208
/* in this method we will exec /bin/sh with the correct
209
arguments, after first setting stdout to point at the file */
212
* We need to temporarily stop CatchChild from eating
213
* SIGCLD signals as it also eats the exit status code. JRA.
216
CatchChildLeaveStatus();
218
if ((pid=sys_fork()) < 0) {
219
DEBUG(0, ("smbrunsecret: fork failed with error %s\n", strerror(errno)));
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));
243
/* the parent just waits for the child to exit */
244
while((wpid = sys_waitpid(pid, &status, 0)) < 0) {
255
DEBUG(2, ("waitpid(%d) : %s\n", (int)pid, strerror(errno)));
259
#if defined(WIFEXITED) && defined(WEXITSTATUS)
260
if (WIFEXITED(status)) {
261
return WEXITSTATUS(status);
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 */
276
if (sys_dup2(ifd[0], 0) != 0) {
277
DEBUG(2,("Failed to create stdin file descriptor\n"));
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 */
285
become_user_permanently(uid, gid);
287
if (getuid() != uid || geteuid() != uid ||
288
getgid() != gid || getegid() != gid) {
289
/* we failed to lose our privileges - do not execute
291
exit(81); /* we can't print stuff at this stage,
292
instead use exit codes for debugging */
296
/* close all other file descriptors, leaving only 0, 1 and 2. 0 and
297
2 point to /dev/null from the startup code */
300
for (fd = 3; fd < 256; fd++) close(fd);
304
execl("/bin/sh", "sh", "-c", cmd, NULL);