static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, struct elfhdr * exec, abi_ulong load_addr, abi_ulong load_bias, abi_ulong interp_load_addr, int ibcs, struct image_info *info) { abi_ulong sp; int size; abi_ulong u_platform; const char *k_platform; const int n = sizeof(elf_addr_t); sp = p; u_platform = 0; k_platform = ELF_PLATFORM; if (k_platform) { size_t len = strlen(k_platform) + 1; sp -= (len + n - 1) & ~(n - 1); u_platform = sp; /* FIXME - check return value of memcpy_to_target() for failure */ memcpy_to_target(sp, k_platform, len); } /* * Force 16 byte _final_ alignment here for generality. */ sp = sp &~ (abi_ulong)15; size = (DLINFO_ITEMS + 1) * 2; if (k_platform) size += 2; #ifdef DLINFO_ARCH_ITEMS size += DLINFO_ARCH_ITEMS * 2; #endif size += envc + argc + 2; size += (!ibcs ? 3 : 1); /* argc itself */ size *= n; if (size & 15) sp -= 16 - (size & 15); /* This is correct because Linux defines * elf_addr_t as Elf32_Off / Elf64_Off */ #define NEW_AUX_ENT(id, val) do { \ sp -= n; put_user_ual(val, sp); \ sp -= n; put_user_ual(id, sp); \ } while(0) NEW_AUX_ENT (AT_NULL, 0); /* There must be exactly DLINFO_ITEMS entries here. */ NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff)); NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr))); NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum)); NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE)); NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr)); NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0); NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry); NEW_AUX_ENT(AT_UID, (abi_ulong) getuid()); NEW_AUX_ENT(AT_EUID, (abi_ulong) geteuid()); NEW_AUX_ENT(AT_GID, (abi_ulong) getgid()); NEW_AUX_ENT(AT_EGID, (abi_ulong) getegid()); NEW_AUX_ENT(AT_HWCAP, (abi_ulong) ELF_HWCAP); NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK)); if (k_platform) NEW_AUX_ENT(AT_PLATFORM, u_platform); #ifdef ARCH_DLINFO /* * ARCH_DLINFO must come last so platform specific code can enforce * special alignment requirements on the AUXV if necessary (eg. PPC). */ ARCH_DLINFO; #endif #undef NEW_AUX_ENT sp = loader_build_argptr(envc, argc, sp, p, !ibcs); return sp; }
static KMETHOD System_getegid(KonohaContext *kctx, KonohaStack *sfp) { KReturnUnboxValue(getegid()); }
static int program_client_local_connect (struct program_client *pclient) { struct program_client_local *slclient = (struct program_client_local *) pclient; int fd[2] = { -1, -1 }; struct program_client_extra_fd *efds = NULL; int *parent_extra_fds = NULL, *child_extra_fds = NULL; unsigned int xfd_count = 0, i; /* create normal I/O fd */ if ( pclient->input != NULL || pclient->output != NULL || pclient->output_seekable ) { if ( socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0 ) { i_error("socketpair() failed: %m"); return -1; } } /* create pipes for additional output through side-channel fds */ if ( array_is_created(&pclient->extra_fds) ) { int extra_fd[2]; efds = array_get_modifiable(&pclient->extra_fds, &xfd_count); if ( xfd_count > 0 ) { parent_extra_fds = t_malloc(sizeof(int) * xfd_count); child_extra_fds = t_malloc(sizeof(int) * xfd_count * 2 + 1); for ( i = 0; i < xfd_count; i++ ) { if ( pipe(extra_fd) < 0 ) { i_error("pipe() failed: %m"); return -1; } parent_extra_fds[i] = extra_fd[0]; child_extra_fds[i*2+0] = extra_fd[1]; child_extra_fds[i*2+1] = efds[i].child_fd; } child_extra_fds[xfd_count*2] = -1; } } /* fork child */ if ( (slclient->pid = fork()) == (pid_t)-1 ) { i_error("fork() failed: %m"); /* clean up */ if ( fd[0] >= 0 && close(fd[0]) < 0 ) { i_error("close(pipe_fd[0]) failed: %m"); } if ( fd[1] >= 0 && close(fd[1]) < 0 ) { i_error("close(pipe_fd[1]) failed: %m"); } for ( i = 0; i < xfd_count; i++ ) { if ( close(child_extra_fds[i*2]) < 0 ) { i_error("close(extra_fd[1]) failed: %m"); } if ( close(parent_extra_fds[i]) < 0 ) { i_error("close(extra_fd[0]) failed: %m"); } } return -1; } if ( slclient->pid == 0 ) { unsigned int count; const char *const *envs = NULL; /* child */ if ( fd[1] >= 0 && close(fd[1]) < 0 ) { i_error("close(pipe_fd[1]) failed: %m"); } for ( i = 0; i < xfd_count; i++ ) { if ( close(parent_extra_fds[i]) < 0 ) i_error("close(extra_fd[0]) failed: %m"); } /* drop privileges if we have any */ if ( getuid() == 0 ) { uid_t uid; gid_t gid; /* switch back to root */ if (seteuid(0) < 0) i_fatal("seteuid(0) failed: %m"); /* drop gids first */ gid = getgid(); if ( gid == 0 || gid != pclient->set.gid ) { if ( pclient->set.gid != 0 ) gid = pclient->set.gid; else gid = getegid(); } if ( setgroups(1, &gid) < 0 ) i_fatal("setgroups(%d) failed: %m", gid); if ( gid != 0 && setgid(gid) < 0 ) i_fatal("setgid(%d) failed: %m", gid); /* drop uid */ if ( pclient->set.uid != 0 ) uid = pclient->set.uid; else uid = geteuid(); if ( uid != 0 && setuid(uid) < 0 ) i_fatal("setuid(%d) failed: %m", uid); } i_assert(pclient->set.uid == 0 || getuid() != 0); i_assert(pclient->set.gid == 0 || getgid() != 0); if ( array_is_created(&pclient->envs) ) envs = array_get(&pclient->envs, &count); exec_child(pclient->path, pclient->args, envs, ( pclient->input != NULL ? fd[0] : -1 ), ( pclient->output != NULL || pclient->output_seekable ? fd[0] : -1 ), child_extra_fds, pclient->set.drop_stderr); i_unreached(); } /* parent */ if ( fd[0] >= 0 && close(fd[0]) < 0 ) i_error("close(pipe_fd[0]) failed: %m"); if ( fd[1] >= 0 ) { net_set_nonblock(fd[1], TRUE); pclient->fd_in = ( pclient->output != NULL || pclient->output_seekable ? fd[1] : -1 ); pclient->fd_out = ( pclient->input != NULL ? fd[1] : -1 ); } for ( i = 0; i < xfd_count; i++ ) { if ( close(child_extra_fds[i*2]) < 0 ) i_error("close(extra_fd[1]) failed: %m"); net_set_nonblock(parent_extra_fds[i], TRUE); efds[i].parent_fd = parent_extra_fds[i]; } program_client_init_streams(pclient); return program_client_connected(pclient); }
static int process_mount(struct fuse_client * c) { struct afp_server_mount_request * req; struct afp_server * s=NULL; struct afp_volume * volume; struct afp_connection_request conn_req; int ret; struct stat lstat; if ((c->incoming_size-1) < sizeof(struct afp_server_mount_request)) goto error; req=(void *) c->incoming_string+1; /* Todo should check the existance and perms of the mount point */ if ((ret=access(req->mountpoint,X_OK))!=0) { log_for_client((void *)c,AFPFSD,LOG_DEBUG, "Incorrect permissions on mountpoint %s: %s\n", req->mountpoint, strerror(errno)); goto error; } if (stat(FUSE_DEVICE,&lstat)) { printf("Could not find %s\n",FUSE_DEVICE); goto error; } if (access(FUSE_DEVICE,R_OK | W_OK )!=0) { log_for_client((void *)c, AFPFSD,LOG_NOTICE, "Incorrect permissions on %s, mode of device" " is %o, uid/gid is %d/%d. But your effective " "uid/gid is %d/%d\n", FUSE_DEVICE,lstat.st_mode, lstat.st_uid, lstat.st_gid, geteuid(),getegid()); goto error; } log_for_client((void *)c,AFPFSD,LOG_NOTICE, "Mounting %s from %s on %s\n", (char *) req->url.servername, (char *) req->url.volumename,req->mountpoint); if ((afp_default_connection_request(&conn_req,&req->url))==-1) { log_for_client((void *)c,AFPFSD,LOG_ERR, "Unknown UAM"); return -1; } conn_req.uam_mask=req->uam_mask; if ((s=afp_server_full_connect(c,&conn_req))==NULL) { signal_main_thread(); goto error; } if ((volume=mount_volume(c,s,req->url.volumename, req->url.volpassword))==NULL) { goto error; } volume->extra_flags|=req->volume_options; volume->mapping=req->map; afp_detect_mapping(volume); snprintf(volume->mountpoint,255,req->mountpoint); /* Create the new thread and block until we get an answer back */ { pthread_mutex_t mutex; struct timespec ts; struct timeval tv; int ret; struct start_fuse_thread_arg arg; memset(&arg,0,sizeof(arg)); arg.client = c; arg.volume = volume; arg.wait = 1; arg.changeuid=req->changeuid; gettimeofday(&tv,NULL); ts.tv_sec=tv.tv_sec; ts.tv_sec+=5; ts.tv_nsec=tv.tv_usec*1000; pthread_mutex_init(&mutex,NULL); pthread_cond_init(&volume->startup_condition_cond,NULL); /* Kickoff a thread to see how quickly it exits. If * it exits quickly, we have an error and it failed. */ pthread_create(&volume->thread,NULL,start_fuse_thread,&arg); if (arg.wait) ret = pthread_cond_timedwait( &volume->startup_condition_cond,&mutex,&ts); report_fuse_errors(c); switch (arg.fuse_result) { case 0: if (volume->mounted==AFP_VOLUME_UNMOUNTED) { /* Try and discover why */ switch(arg.fuse_errno) { case ENOENT: log_for_client((void *)c,AFPFSD,LOG_ERR, "Permission denied, maybe a problem with the fuse device or mountpoint?\n"); break; default: log_for_client((void *)c,AFPFSD,LOG_ERR, "Mounting of volume %s of server %s failed.\n", volume->volume_name_printable, volume->server->server_name_printable); } goto error; } else { log_for_client((void *)c,AFPFSD,LOG_NOTICE, "Mounting of volume %s of server %s succeeded.\n", volume->volume_name_printable, volume->server->server_name_printable); return 0; } break; case ETIMEDOUT: log_for_client((void *)c,AFPFSD,LOG_NOTICE, "Still trying.\n"); return 0; break; default: volume->mounted=AFP_VOLUME_UNMOUNTED; log_for_client((void *)c,AFPFSD,LOG_NOTICE, "Unknown error %d, %d.\n", arg.fuse_result,arg.fuse_errno); goto error; } } return AFP_SERVER_RESULT_OKAY; error: if ((s) && (!something_is_mounted(s))) { afp_server_remove(s); } signal_main_thread(); return AFP_SERVER_RESULT_ERROR; }
/* Modify the auxv the kernel gave us to make it look like we were execed as the shared object. This also inserts a new entry into the auxv table so we can communicate some extra information to stage2 (namely, the fd of the padding file, so it can identiry and remove the padding later). */ static void *fix_auxv(void *v_init_esp, const struct exeinfo *info, int padfile) { struct ume_auxv *auxv; int *newesp; int seen; int delta; int i; #if defined(VGO_netbsdelf2) static const int new_entries = 14; #else static const int new_entries = 2; #endif /* make sure we're running on the private stack */ assert(&delta >= stack && &delta < &stack[sizeof(stack)/sizeof(*stack)]); /* find the beginning of the AUXV table */ auxv = find_auxv(v_init_esp); printf("auxv[0].u.a_val : %d, auxv[0].a_type : %d\n",auxv[0].u.a_val, auxv[0].a_type); /* Work out how we should move things to make space for the new auxv entry. It seems that ld.so wants a 16-byte aligned stack on entry, so make sure that's the case. */ #if defined(VGO_netbsdelf2) newesp = (int *)(((unsigned long)v_init_esp - new_entries * sizeof(*auxv))); #else newesp = (int *)(((unsigned long)v_init_esp - new_entries * sizeof(*auxv)) & ~0xf); #endif delta = (char *)v_init_esp - (char *)newesp; memmove(newesp, v_init_esp, (char *)auxv - (char *)v_init_esp); v_init_esp = (void *)newesp; /* we need to see whats the size of delta, we are freeing up space to throw our own auxv headers in 3, */ printf("Space for auxv %d\n",delta/sizeof(*auxv)); printf("sizeof delta :%d , sizeof auxv : %d\n",delta, sizeof(*auxv)); /* if auxv is not aligned, we move it backward till its aligned. We find out how much space is required, walk tmp_auxv to the last auxv entry. then move the junk forward. Remeber that the AT_NULL entry also needs to be moved forward. */ /* if( ( delta%sizeof(*auxv) ) != 0 ) */ /* { int j = 0; */ /* printf("adjusting auxv\n"); */ /* struct ume_auxv* tmp = auxv; /\* to top *\/ */ /* void * new_auxv = (void *) auxv - delta%(sizeof(*auxv)); */ /* for (j=0; tmp->a_type != AT_NULL;j++,tmp++ ); */ /* memmove( new_auxv,auxv,(j+1)* sizeof(*auxv) ); */ /* auxv = (struct ume_auxv *)new_auxv; */ /* } */ auxv -= delta/sizeof(*auxv) ; /* move it back even further for 2 * new */ /* stage2 needs this so it can clean up the padding we leave in place when we start it */ auxv[0].a_type = AT_UME_PADFD; auxv[0].u.a_val = padfile; /* This will be needed by valgrind itself so that it can subsequently execve() children. This needs to be done here because /proc/self/exe will go away once we unmap stage1. */ auxv[1].a_type = AT_UME_EXECFD; #if defined(VGO_netbsdelf2) auxv[1].u.a_val = open("/proc/curproc/file", O_RDONLY); /* fill in the rest */ auxv[2].a_type= AT_PHDR; auxv[2].u.a_val = info->phdr; auxv[3].a_type = AT_PHNUM; auxv[3].u.a_val = info->phnum; auxv[4].a_type = AT_BASE; auxv[4].u.a_val = info->interp_base; auxv[5].a_type = AT_ENTRY; auxv[5].u.a_val = info->entry; auxv[6].a_type = AT_PAGESZ; auxv[6].u.a_val = 4096; auxv[7].a_type = AT_PHENT; auxv[7].u.a_val = 32; /*sizeof(info->phdr);*/ auxv[8].a_type = AT_FLAGS; auxv[8].u.a_val = 0; /* ? */ auxv[9].a_type = AT_EUID; auxv[9].u.a_val = geteuid(); auxv[10].a_type = AT_RUID; auxv[10].u.a_val = getuid(); auxv[11].a_type = AT_EGID; auxv[11].u.a_val = getegid(); auxv[12].a_type = AT_RGID; auxv[12].u.a_val = getgid(); auxv[13].a_type = AT_NULL; #else auxv[1].u.a_val = open("/proc/self/exe", O_RDONLY); #endif /* make sure the rest are sane */ for(i = new_entries; i < delta/sizeof(*auxv); i++) { auxv[i].a_type = AT_IGNORE; auxv[i].u.a_val = 0; } /* OK, go through and patch up the auxv entries to match the new executable */ seen = 0; for(; auxv->a_type != AT_NULL; auxv++) { if (1) printf("doing auxv %p %5lld: %p \n", auxv, (Long)auxv->a_type, (Long)auxv->u.a_val); /* if(seen == 0xf) */ /* break; */ switch(auxv->a_type) { case AT_PHDR: printf("seen 1\n"); seen |= 1; auxv->u.a_val = info->phdr; break; case AT_PHNUM: printf("seen 2\n"); seen |= 2; auxv->u.a_val = info->phnum; break; case AT_BASE: printf("seen 4\n"); seen |= 4; auxv->u.a_val = info->interp_base; break; case AT_ENTRY: printf("seen 8\n"); seen |= 8; auxv->u.a_val = info->entry; break; default: break; } if (1) printf("new auxv %p %5lld: %p \n", auxv, (Long)auxv->a_type, (Long)auxv->u.a_val); } /* If we didn't see all the entries we need to fix up, then we can't make the new executable viable. */ if (seen != 0xf) { fprintf(stderr, "valgrind: we didn't see enough auxv entries (seen=%x)\n", seen); exit(1); } return v_init_esp; }
int fork_execvp0(const char *file, char *const argv[], u_int flags) { if (strchr (file, '/') == NULL) { char *path, *p; struct stat st; size_t len; uid_t uid; gid_t gid; int ngroups; gid_t groups[NGROUPS_MAX]; char *name; path = getenv ("PATH"); if (path == NULL) { /* There is no `PATH' in the environment. The default search path is the current directory followed by the path `confstr' returns for `_CS_PATH'. We will just search current directory */ path = "."; } len = strlen (file) + 1; name = alloca (strlen (path) + len); uid = geteuid (); gid = getegid (); ngroups = getgroups (sizeof (groups) / sizeof (groups[0]), groups); p = path; do { path = p; p = strchr (path, ':'); if (p == NULL) p = strchr (path, '\0'); if (p == path) /* Two adjacent colons, or a colon at the beginning or the end of `PATH' means to search the current directory. */ (void) memcpy (name, file, len); else { /* Construct the pathname to try. */ (void) memcpy (name, path, p - path); name[p - path] = '/'; (void) memcpy (&name[(p - path) + 1], file, len); } if (stat (name, &st) == 0 && S_ISREG (st.st_mode)) { int bit = S_IXOTH; if (st.st_uid == uid) bit = S_IXUSR; else if (st.st_gid == gid) bit = S_IXGRP; else { register int i; for (i = 0; i < ngroups; ++i) if (st.st_gid == groups[i]) { bit = S_IXGRP; break; } } if (st.st_mode & bit) { file = name; break; } } } while (*p++ != '\0'); } return fork_execve0(file, argv, environ, -1, flags); }
int main (int argc, char **argv) { char *diskType = "auto"; char *imagefilename = NULL; char *mountpoint = NULL; int debug = 0; int foreground = 0; char c; int i; char *differencing[DIFFERENCING_MAX]; int differencingLen = 0; extern char *optarg; extern int optind; // // *** Parse the command line options *** // processName = argv[0]; while ((c = getopt (argc, argv, GETOPT_ARGS)) != -1) { switch (c) { case 'r': readonly = 1; break; case 'g': foreground = 1; break; case 'v': verbose = 1; break; case 'a': allowall = 1; break; case 'w': allowall = 1; allowallw = 1; break; case 't': diskType = (char *) optarg; break; // ignored if OLDAPI case 's': if (differencingLen == DIFFERENCING_MAX) usageAndExit ("Too many differencing disks"); differencing[differencingLen++] = (char *) optarg; break; case 'f': imagefilename = (char *) optarg; break; case 'd': foreground = 1; debug = 1; break; case 'h': usageAndExit (NULL); case '?': usageAndExit ("Unknown option"); } } // // *** Validate the command line *** // if (argc != optind + 1) usageAndExit ("a single mountpoint must be specified"); mountpoint = argv[optind]; if (!mountpoint) usageAndExit ("no mountpoint specified"); if (!imagefilename) usageAndExit ("no image chosen"); if (stat (imagefilename, &VDfile_stat) < 0) usageAndExit ("cannot access imagefile"); if (access (imagefilename, F_OK | R_OK | ((!readonly) ? W_OK : 0)) < 0) usageAndExit ("cannot access imagefile"); for (i = 0; i < differencingLen; i++) if (access (differencing[i], F_OK | R_OK | ((readonly) ? 0 : W_OK)) < 0) usageAndExit ("cannot access differencing imagefile %s", differencing[i]); #define IS_TYPE(s) (strcmp (s, diskType) == 0) if (! (IS_TYPE ("auto") || IS_TYPE ("VDI") || IS_TYPE ("VMDK") || IS_TYPE ("VHD") || IS_TYPE ("auto"))) usageAndExit ("invalid disk type specified"); if (strcmp ("auto", diskType) == 0 && detectDiskType (&diskType, imagefilename) < 0) return 1; // // *** Open the VDI, parse the MBR + EBRs and connect to the fuse service *** // if (RT_FAILURE (VDInterfaceAdd (&vdError, "VD Error", VDINTERFACETYPE_ERROR, &vdErrorCallbacks, NULL, &pVDifs))) usageAndExit ("invalid initialisation of VD interface"); if (RT_FAILURE (VDCreate (&vdError, VDTYPE_HDD, &hdDisk))) usageAndExit ("invalid initialisation of VD interface"); DISKopen (diskType, imagefilename); for (i = 0; i < differencingLen; i++) { char *diffType; char *diffFilename = differencing[i]; detectDiskType (&diffType, diffFilename); DISKopen (diffType, diffFilename); } initialisePartitionTable (); myuid = geteuid (); mygid = getegid (); fuse_opt_add_arg (&fuseArgs, "vdfuse"); { char fsname[strlen (imagefilename) + 12]; strcpy (fsname, "-ofsname=\0"); strcat (fsname, imagefilename); fuse_opt_add_arg (&fuseArgs, fsname); } fuse_opt_add_arg (&fuseArgs, "-osubtype=vdfuse"); fuse_opt_add_arg (&fuseArgs, "-o"); fuse_opt_add_arg (&fuseArgs, (allowall) ? "allow_other" : "allow_root"); if (foreground) fuse_opt_add_arg (&fuseArgs, "-f"); if (debug) fuse_opt_add_arg (&fuseArgs, "-d"); fuse_opt_add_arg (&fuseArgs, mountpoint); return fuse_main (fuseArgs.argc, fuseArgs.argv, &fuseOperations #if FUSE_USE_VERSION >= 26 , NULL #endif ); }
CAMLprim value unix_getegid(value unit) { return Val_int(getegid()); }
END_TEST #endif START_TEST(test_become_the_user) { int rc; job *pjob; int uid; int gid; // must be root to run this test if (getuid() != 0) return; pjob = (job *)calloc(1, sizeof(job)); fail_unless(pjob != NULL); pjob->ji_grpcache = (struct grpcache *)calloc(1, sizeof(struct grpcache)); fail_unless(pjob->ji_grpcache != NULL); pjob->ji_qs.ji_un.ji_momt.ji_exuid = 500; pjob->ji_qs.ji_un.ji_momt.ji_exgid = 500; pjob->ji_grpcache->gc_ngroup = 1; pjob->ji_grpcache->gc_groups[0] = 500; // fork so we can test the setxid/setexid calls in the child rc = fork(); fail_unless(rc != -1); if (rc > 0) { int status; // parent wait(&status); return; } // child rc = become_the_user(pjob, true); fail_unless(rc == PBSE_NONE); // check the group list, uid, gid uid = geteuid(); gid = getegid(); fail_unless(uid != 500); fail_unless(gid != 500); // put things back in place fail_unless(seteuid(0) == 0); fail_unless(setegid(0) == 0); rc = become_the_user(pjob, false); fail_unless(rc == PBSE_NONE); // check the uid, gid uid = getuid(); gid = getgid(); fail_unless(uid != 500); fail_unless(gid != 500); }
FILE * opencal(void) { uid_t uid; size_t i; int fd, found, pdes[2]; struct stat sbuf; /* open up calendar file as stdin */ if (!freopen(calendarFile, "r", stdin)) { if (doall) { if (chdir(calendarHomes[0]) != 0) return (NULL); if (stat(calendarNoMail, &sbuf) == 0) return (NULL); if (!freopen(calendarFile, "r", stdin)) return (NULL); } else { char *home = getenv("HOME"); if (home == NULL || *home == '\0') errx(1, "cannot get home directory"); if (chdir(home) != 0) errx(1, "cannot enter home directory"); for (found = i = 0; i < sizeof(calendarHomes) / sizeof(calendarHomes[0]); i++) if (chdir(calendarHomes[i]) == 0 && freopen(calendarFile, "r", stdin)) { found = 1; break; } if (!found) errx(1, "can't open calendar file \"%s\": %s (%d)", calendarFile, strerror(errno), errno); } } if (pipe(pdes) < 0) return (NULL); switch (fork()) { case -1: /* error */ (void)close(pdes[0]); (void)close(pdes[1]); return (NULL); case 0: /* child -- stdin already setup, set stdout to pipe input */ if (pdes[1] != STDOUT_FILENO) { (void)dup2(pdes[1], STDOUT_FILENO); (void)close(pdes[1]); } (void)close(pdes[0]); uid = geteuid(); if (setuid(getuid()) < 0) { warnx("first setuid failed"); _exit(1); }; if (setgid(getegid()) < 0) { warnx("setgid failed"); _exit(1); } if (setuid(uid) < 0) { warnx("setuid failed"); _exit(1); } execl(_PATH_CPP, "cpp", "-P", "-traditional", "-nostdinc", /* GCC specific opts */ "-I.", "-I", _PATH_INCLUDE, (char *)NULL); warn(_PATH_CPP); _exit(1); } /* parent -- set stdin to pipe output */ (void)dup2(pdes[0], STDIN_FILENO); (void)close(pdes[0]); (void)close(pdes[1]); /* not reading all calendar files, just set output to stdout */ if (!doall) return (stdout); /* set output to a temporary file, so if no output don't send mail */ (void)snprintf(path, sizeof(path), "%s/_calXXXXXX", _PATH_TMP); if ((fd = mkstemp(path)) < 0) return (NULL); return (fdopen(fd, "w+")); }
void closecal(FILE *fp) { uid_t uid; struct stat sbuf; int nread, pdes[2], status; char buf[1024]; if (!doall) return; rewind(fp); if (fstat(fileno(fp), &sbuf) || !sbuf.st_size) goto done; if (pipe(pdes) < 0) goto done; switch (fork()) { case -1: /* error */ (void)close(pdes[0]); (void)close(pdes[1]); goto done; case 0: /* child -- set stdin to pipe output */ if (pdes[0] != STDIN_FILENO) { (void)dup2(pdes[0], STDIN_FILENO); (void)close(pdes[0]); } (void)close(pdes[1]); uid = geteuid(); if (setuid(getuid()) < 0) { warnx("setuid failed"); _exit(1); }; if (setgid(getegid()) < 0) { warnx("setgid failed"); _exit(1); } if (setuid(uid) < 0) { warnx("setuid failed"); _exit(1); } execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F", "\"Reminder Service\"", (char *)NULL); warn(_PATH_SENDMAIL); _exit(1); } /* parent -- write to pipe input */ (void)close(pdes[0]); write(pdes[1], "From: \"Reminder Service\" <", 26); write(pdes[1], pw->pw_name, strlen(pw->pw_name)); write(pdes[1], ">\nTo: <", 7); write(pdes[1], pw->pw_name, strlen(pw->pw_name)); write(pdes[1], ">\nSubject: ", 11); write(pdes[1], dayname, strlen(dayname)); write(pdes[1], "'s Calendar\nPrecedence: bulk\n\n", 30); while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0) (void)write(pdes[1], buf, nread); (void)close(pdes[1]); done: (void)fclose(fp); (void)unlink(path); while (wait(&status) >= 0); }
/* drops privileges */ int drop_privileges(char *user, char *group){ uid_t uid=-1; gid_t gid=-1; struct group *grp; struct passwd *pw; /* set effective group ID */ if(group!=NULL){ /* see if this is a group name */ if(strspn(group,"0123456789")<strlen(group)){ grp=(struct group *)getgrnam(group); if(grp!=NULL) gid=(gid_t)(grp->gr_gid); else syslog(LOG_ERR,"Warning: Could not get group entry for '%s'",group); endgrent(); } /* else we were passed the GID */ else gid=(gid_t)atoi(group); /* set effective group ID if other than current EGID */ if(gid!=getegid()){ if(setgid(gid)==-1) syslog(LOG_ERR,"Warning: Could not set effective GID=%d",(int)gid); } } /* set effective user ID */ if(user!=NULL){ /* see if this is a user name */ if(strspn(user,"0123456789")<strlen(user)){ pw=(struct passwd *)getpwnam(user); if(pw!=NULL) uid=(uid_t)(pw->pw_uid); else syslog(LOG_ERR,"Warning: Could not get passwd entry for '%s'",user); endpwent(); } /* else we were passed the UID */ else uid=(uid_t)atoi(user); /* set effective user ID if other than current EUID */ if(uid!=geteuid()){ #ifdef HAVE_INITGROUPS /* initialize supplementary groups */ if(initgroups(user,gid)==-1){ if(errno==EPERM) syslog(LOG_ERR,"Warning: Unable to change supplementary groups using initgroups()"); else{ syslog(LOG_ERR,"Warning: Possibly root user failed dropping privileges with initgroups()"); return ERROR; } } #endif if(setuid(uid)==-1) syslog(LOG_ERR,"Warning: Could not set effective UID=%d",(int)uid); } } return OK; }
void _PR_InitLog(void) { char *ev; _pr_logLock = PR_NewLock(); ev = PR_GetEnv("NSPR_LOG_MODULES"); if (ev && ev[0]) { char module[64]; /* Security-Critical: If you change this * size, you must also change the sscanf * format string to be size-1. */ PRBool isSync = PR_FALSE; PRIntn evlen = strlen(ev), pos = 0; PRInt32 bufSize = DEFAULT_BUF_SIZE; while (pos < evlen) { PRIntn level = 1, count = 0, delta = 0; count = sscanf(&ev[pos], "%63[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-]%n:%d%n", module, &delta, &level, &delta); pos += delta; if (count == 0) break; /* ** If count == 2, then we got module and level. If count ** == 1, then level defaults to 1 (module enabled). */ if (strcasecmp(module, "sync") == 0) { isSync = PR_TRUE; } else if (strcasecmp(module, "bufsize") == 0) { if (level >= LINE_BUF_SIZE) { bufSize = level; } } else { PRLogModuleInfo *lm = logModules; PRBool skip_modcheck = (0 == strcasecmp (module, "all")) ? PR_TRUE : PR_FALSE; while (lm != NULL) { if (skip_modcheck) lm -> level = (PRLogModuleLevel)level; else if (strcasecmp(module, lm->name) == 0) { lm->level = (PRLogModuleLevel)level; break; } lm = lm->next; } } /*found:*/ count = sscanf(&ev[pos], " , %n", &delta); pos += delta; if (count == EOF) break; } PR_SetLogBuffering(isSync ? bufSize : 0); #ifdef XP_UNIX if ((getuid() != geteuid()) || (getgid() != getegid())) { return; } #endif /* XP_UNIX */ ev = PR_GetEnv("NSPR_LOG_FILE"); if (ev && ev[0]) { if (!PR_SetLogFile(ev)) { #ifdef XP_PC char* str = PR_smprintf("Unable to create nspr log file '%s'\n", ev); if (str) { OutputDebugString(str); PR_smprintf_free(str); } #else fprintf(stderr, "Unable to create nspr log file '%s'\n", ev); #endif } } else { #ifdef _PR_USE_STDIO_FOR_LOGGING logFile = stderr; #else logFile = _pr_stderr; #endif } } }
static int l_issetugid(void) { return (geteuid() != getuid() || getegid() != getgid()); }
/* * Check per accout or global hush-login setting. * * Hushed mode is enabled: * * a) if global (e.g. /etc/hushlogins) hush file exists: * 1) for ALL ACCOUNTS if the file is empty * 2) for the current user if the username or shell are found in the file * * b) if ~/.hushlogin file exists * * The ~/.hushlogin is ignored if the global hush file exists. * * The HUSHLOGIN_FILE login.def variable overwrites the default hush filename. * * Note that shadow-utils login(1) does not support "a1)". The "a1)" is * necessary if you want to use PAM for "Last login" message. * * -- Karel Zak <*****@*****.**> (26-Aug-2011) * * * Per-account check requires some explanation: As root we may not be able to * read the directory of the user if it is on an NFS mounted filesystem. We * temporarily set our effective uid to the user-uid making sure that we keep * root privs. in the real uid. * * A portable solution would require a fork(), but we rely on Linux having the * BSD setreuid() */ static int get_hushlogin_status(struct passwd *pwd) { const char *files[] = { _PATH_HUSHLOGINS, _PATH_HUSHLOGIN, NULL }; const char *file; char buf[BUFSIZ]; int i; file = getlogindefs_str("HUSHLOGIN_FILE", NULL); if (file) { if (!*file) return 0; /* empty HUSHLOGIN_FILE defined */ files[0] = file; files[1] = NULL; } for (i = 0; files[i]; i++) { int ok = 0; file = files[i]; /* Global hush-file*/ if (*file == '/') { struct stat st; FILE *f; if (stat(file, &st) != 0) continue; /* file does not exist */ if (st.st_size == 0) return 1; /* for all accounts */ f = fopen(file, "r"); if (!f) continue; /* ignore errors... */ while (ok == 0 && fgets(buf, sizeof(buf), f)) { buf[strlen(buf) - 1] = '\0'; ok = !strcmp(buf, *buf == '/' ? pwd->pw_shell : pwd->pw_name); } fclose(f); if (ok) return 1; /* found username/shell */ return 0; /* ignore per-account files */ } /* Per-account setting */ if (strlen(pwd->pw_dir) + sizeof(file) + 2 > sizeof(buf)) continue; else { uid_t ruid = getuid(); gid_t egid = getegid(); sprintf(buf, "%s/%s", pwd->pw_dir, file); if (setregid(-1, pwd->pw_gid) == 0 && setreuid(0, pwd->pw_uid) == 0) ok = effective_access(buf, O_RDONLY) == 0; if (setuid(0) != 0 || setreuid(ruid, 0) != 0 || setregid(-1, egid) != 0) { syslog(LOG_ALERT, _("hush login status: restore original IDs failed")); exit(EXIT_FAILURE); } if (ok) return 1; /* enabled by user */ } } return 0; }
/*static*/ status_t Inode::Create(Transaction& transaction, Inode* parent, const char* name, int32 mode, int openMode, uint8 type, bool* _created, ino_t* _id, Inode** _inode, fs_vnode_ops* vnodeOps, uint32 publishFlags) { TRACE("Inode::Create()\n"); Volume* volume = transaction.GetVolume(); DirectoryIterator* entries = NULL; ObjectDeleter<DirectoryIterator> entriesDeleter; if (parent != NULL) { parent->WriteLockInTransaction(transaction); TRACE("Inode::Create(): Looking up entry destination\n"); HTree htree(volume, parent); status_t status = htree.Lookup(name, &entries); if (status == B_ENTRY_NOT_FOUND) { panic("We need to add the first node.\n"); return B_ERROR; } if (status != B_OK) return status; entriesDeleter.SetTo(entries); TRACE("Inode::Create(): Looking up to see if file already exists\n"); ino_t entryID; status = entries->FindEntry(name, &entryID); if (status == B_OK) { // File already exists TRACE("Inode::Create(): File already exists\n"); if (S_ISDIR(mode) || S_ISLNK(mode) || (openMode & O_EXCL) != 0) return B_FILE_EXISTS; Vnode vnode(volume, entryID); Inode* inode; status = vnode.Get(&inode); if (status != B_OK) { TRACE("Inode::Create() Failed to get the inode from the " "vnode\n"); return B_ENTRY_NOT_FOUND; } if (inode->IsDirectory() && (openMode & O_RWMASK) != O_RDONLY) return B_IS_A_DIRECTORY; if ((openMode & O_DIRECTORY) != 0 && !inode->IsDirectory()) return B_NOT_A_DIRECTORY; if (inode->CheckPermissions(open_mode_to_access(openMode) | ((openMode & O_TRUNC) != 0 ? W_OK : 0)) != B_OK) return B_NOT_ALLOWED; if ((openMode & O_TRUNC) != 0) { // Truncate requested TRACE("Inode::Create(): Truncating file\n"); inode->WriteLockInTransaction(transaction); status = inode->Resize(transaction, 0); if (status != B_OK) return status; } if (_created != NULL) *_created = false; if (_id != NULL) *_id = inode->ID(); if (_inode != NULL) *_inode = inode; if (_id != NULL || _inode != NULL) vnode.Keep(); TRACE("Inode::Create(): Done opening file\n"); return B_OK; /*} else if ((mode & S_ATTR_DIR) == 0) { TRACE("Inode::Create(): (mode & S_ATTR_DIR) == 0\n"); return B_BAD_VALUE;*/ } else if ((openMode & O_DIRECTORY) != 0) { TRACE("Inode::Create(): (openMode & O_DIRECTORY) != 0\n"); return B_ENTRY_NOT_FOUND; } // Return to initial position TRACE("Inode::Create(): Restarting iterator\n"); entries->Restart(); } status_t status; if (parent != NULL) { status = parent->CheckPermissions(W_OK); if (status != B_OK) return status; } TRACE("Inode::Create(): Allocating inode\n"); ino_t id; status = volume->AllocateInode(transaction, parent, mode, id); if (status != B_OK) { ERROR("Inode::Create(): AllocateInode() failed\n"); return status; } if (entries != NULL) { size_t nameLength = strlen(name); status = entries->AddEntry(transaction, name, nameLength, id, type); if (status != B_OK) { ERROR("Inode::Create(): AddEntry() failed\n"); return status; } } TRACE("Inode::Create(): Creating inode\n"); Inode* inode = new(std::nothrow) Inode(volume); if (inode == NULL) return B_NO_MEMORY; TRACE("Inode::Create(): Getting node structure\n"); ext2_inode& node = inode->Node(); TRACE("Inode::Create(): Initializing inode data\n"); memset(&node, 0, sizeof(ext2_inode)); node.SetMode(mode); node.SetUserID(geteuid()); node.SetGroupID(parent != NULL ? parent->Node().GroupID() : getegid()); node.SetNumLinks(inode->IsDirectory() ? 2 : 1); TRACE("Inode::Create(): Updating time\n"); struct timespec timespec; _BigtimeToTimespec(real_time_clock_usecs(), ×pec); inode->SetAccessTime(×pec); inode->SetCreationTime(×pec); inode->SetModificationTime(×pec); if (parent != NULL) node.SetFlags(parent->Flags() & EXT2_INODE_INHERITED); if (volume->HasExtentsFeature() && (inode->IsDirectory() || inode->IsFile())) { node.SetFlag(EXT2_INODE_EXTENTS); ExtentStream stream(volume, &node.extent_stream, 0); stream.Init(); ASSERT(stream.Check()); } if (sizeof(ext2_inode) < volume->InodeSize()) node.SetExtraInodeSize(sizeof(ext2_inode) - EXT2_INODE_NORMAL_SIZE); TRACE("Inode::Create(): Updating ID\n"); inode->fID = id; if (inode->IsDirectory()) { TRACE("Inode::Create(): Initializing directory\n"); status = inode->InitDirectory(transaction, parent); if (status != B_OK) { ERROR("Inode::Create(): InitDirectory() failed\n"); delete inode; return status; } } // TODO: Maybe it can be better /*if (volume->HasExtendedAttributes()) { TRACE("Inode::Create(): Initializing extended attributes\n"); uint32 blockGroup = 0; uint32 pos = 0; uint32 allocated; status = volume->AllocateBlocks(transaction, 1, 1, blockGroup, pos, allocated); if (status != B_OK) return status; // Clear the new block uint32 blockNum = volume->FirstDataBlock() + pos + volume->BlocksPerGroup() * blockGroup; CachedBlock cached(volume); cached.SetToWritable(transaction, blockNum, true); node.SetExtendedAttributesBlock(blockNum); }*/ TRACE("Inode::Create(): Saving inode\n"); status = inode->WriteBack(transaction); if (status != B_OK) { delete inode; return status; } TRACE("Inode::Create(): Creating vnode\n"); Vnode vnode; status = vnode.Publish(transaction, inode, vnodeOps, publishFlags); if (status != B_OK) return status; if (!inode->IsSymLink()) { // Vnode::Publish doesn't publish symlinks if (!inode->IsDirectory()) { status = inode->CreateFileCache(); if (status != B_OK) return status; } inode->WriteLockInTransaction(transaction); } if (_created) *_created = true; if (_id != NULL) *_id = id; if (_inode != NULL) *_inode = inode; if (_id != NULL || _inode != NULL) vnode.Keep(); TRACE("Inode::Create(): Deleting entries iterator\n"); DirectoryIterator* iterator = entriesDeleter.Detach(); TRACE("Inode::Create(): Entries iterator: %p\n", entries); delete iterator; TRACE("Inode::Create(): Done\n"); return B_OK; }
/* A binary wrapper is needed around python scripts if we want * to run them in sgid/suid mode. * * This is such a wrapper. */ int main(int argc, char **argv) { /* * We disallow passing of arguments which point to writable dirs * and other files possibly not accessible to calling user. * This way, the script will always use default values for these arguments. */ char **pp = argv; char *arg; while ((arg = *++pp) != NULL) { /* Allow taking ids from stdin */ if (strcmp(arg, "--ids=-") == 0) continue; if (strncmp(arg, "--exact", 7) == 0) continue; if (strncmp(arg, "--cache", 7) == 0) error_msg_and_die("bad option %s", arg); if (strncmp(arg, "--tmpdir", 8) == 0) error_msg_and_die("bad option %s", arg); if (strncmp(arg, "--ids", 5) == 0) error_msg_and_die("bad option %s", arg); } /* Switch real user/group to effective ones. * Otherwise yum library gets confused - gets EPERM (why??). */ gid_t g = getegid(); /* do setregid only if we have to, to not upset selinux needlessly */ if (g != getgid()) IGNORE_RESULT(setregid(g, g)); uid_t u = geteuid(); if (u != getuid()) { IGNORE_RESULT(setreuid(u, u)); /* We are suid'ed! */ /* Prevent malicious user from messing up with suid'ed process: */ #if 1 // We forgot to sanitize PYTHONPATH. And who knows what else we forgot // (especially considering *future* new variables of this kind). // We switched to clearing entire environment instead: // However since we communicate through environment variables // we have to keep a whitelist of variables to keep. static const char *whitelist[] = { "REPORT_CLIENT_SLAVE" // Check if the app is being run as a slave }; const size_t wlsize = sizeof(whitelist)/sizeof(char*); char *setlist[sizeof(whitelist)/sizeof(char*)] = { 0 }; char *p = NULL; for (size_t i = 0; i < wlsize; i++) if ((p = getenv(whitelist[i])) != NULL) setlist[i] = xstrdup(p); // Now we can clear the environment clearenv(); // And once again set whitelisted variables for (size_t i = 0; i < wlsize; i++) if (setlist[i] != NULL) { xsetenv(whitelist[i], setlist[i]); free(setlist[i]); } #else /* Clear dangerous stuff from env */ static const char forbid[] = "LD_LIBRARY_PATH" "\0" "LD_PRELOAD" "\0" "LD_TRACE_LOADED_OBJECTS" "\0" "LD_BIND_NOW" "\0" "LD_AOUT_LIBRARY_PATH" "\0" "LD_AOUT_PRELOAD" "\0" "LD_NOWARN" "\0" "LD_KEEPDIR" "\0" ; const char *p = forbid; do { unsetenv(p); p += strlen(p) + 1; } while (*p); #endif /* Set safe PATH */ // Adding configure --bindir and --sbindir to the PATH so that // abrt-action-install-debuginfo doesn't fail when spawning // abrt-action-trim-files char path_env[] = "PATH=/usr/sbin:/sbin:/usr/bin:/bin:"BIN_DIR":"SBIN_DIR; if (u != 0) strcpy(path_env, "PATH=/usr/bin:/bin:"BIN_DIR); putenv(path_env); } execvp(EXECUTABLE, argv); error_msg_and_die("Can't execute %s", EXECUTABLE); }
char * makemsg(char *fname, size_t *mbufsize, int print_banner) { register int ch, cnt; struct tm *lt; struct passwd *pw; struct stat sbuf; time_t now; FILE *fp; char *p, *whom, *where, *hostname, *lbuf, *tmpname, *mbuf; long line_max; hostname = xmalloc(sysconf(_SC_HOST_NAME_MAX) + 1); line_max = sysconf(_SC_LINE_MAX); lbuf = xmalloc(line_max); if ((fp = xfmkstemp(&tmpname, NULL)) == NULL) err(EXIT_FAILURE, _("can't open temporary file")); unlink(tmpname); free(tmpname); if (print_banner == TRUE) { if (!(whom = getlogin()) || !*whom) whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???"; if (!whom) { whom = "someone"; warn(_("cannot get passwd uid")); } where = ttyname(STDOUT_FILENO); if (!where) { where = "somewhere"; warn(_("cannot get tty name")); } gethostname(hostname, sizeof(hostname)); time(&now); lt = localtime(&now); /* * all this stuff is to blank out a square for the message; * we wrap message lines at column 79, not 80, because some * terminals wrap after 79, some do not, and we can't tell. * Which means that we may leave a non-blank character * in column 80, but that can't be helped. */ /* snprintf is not always available, but the sprintf's here will not overflow as long as %d takes at most 100 chars */ fprintf(fp, "\r%79s\r\n", " "); sprintf(lbuf, _("Broadcast Message from %s@%s"), whom, hostname); fprintf(fp, "%-79.79s\007\007\r\n", lbuf); sprintf(lbuf, " (%s) at %d:%02d ...", where, lt->tm_hour, lt->tm_min); fprintf(fp, "%-79.79s\r\n", lbuf); } fprintf(fp, "%79s\r\n", " "); free(hostname); if (fname) { /* * When we are not root, but suid or sgid, refuse to read files * (e.g. device files) that the user may not have access to. * After all, our invoker can easily do "wall < file" * instead of "wall file". */ uid_t uid = getuid(); if (uid && (uid != geteuid() || getgid() != getegid())) errx(EXIT_FAILURE, _("will not read %s - use stdin."), fname); if (!freopen(fname, "r", stdin)) err(EXIT_FAILURE, _("cannot open file %s"), fname); } while (fgets(lbuf, line_max, stdin)) { for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) { if (cnt == 79 || ch == '\n') { for (; cnt < 79; ++cnt) putc(' ', fp); putc('\r', fp); putc('\n', fp); cnt = 0; } if (ch != '\n') carefulputc(ch, fp); } } fprintf(fp, "%79s\r\n", " "); free(lbuf); rewind(fp); if (fstat(fileno(fp), &sbuf)) err(EXIT_FAILURE, _("fstat failed")); *mbufsize = (size_t) sbuf.st_size; mbuf = xmalloc(*mbufsize); if (fread(mbuf, 1, *mbufsize, fp) != *mbufsize) err(EXIT_FAILURE, _("fread failed")); if (close_stream(fp) != 0) errx(EXIT_FAILURE, _("write error")); return mbuf; }
int smbrun(const char *cmd, int *outfd) { OutputDebugString("smbrun is not supported\n"); #ifndef _XBOX pid_t pid; uid_t uid = current_user.ut.uid; gid_t gid = current_user.ut.gid; /* * Lose any elevated privileges. */ drop_effective_capability(KERNEL_OPLOCK_CAPABILITY); drop_effective_capability(DMAPI_ACCESS_CAPABILITY); /* point our stdout at the file we want output to go into */ if (outfd && ((*outfd = setup_out_fd()) == -1)) { return -1; } /* in this method we will exec /bin/sh with the correct arguments, after first setting stdout to point at the file */ /* * We need to temporarily stop CatchChild from eating * SIGCLD signals as it also eats the exit status code. JRA. */ CatchChildLeaveStatus(); if ((pid=sys_fork()) < 0) { DEBUG(0,("smbrun: fork failed with error %s\n", strerror(errno) )); CatchChild(); if (outfd) { close(*outfd); *outfd = -1; } return errno; } if (pid) { /* * Parent. */ int status=0; pid_t wpid; /* the parent just waits for the child to exit */ while((wpid = sys_waitpid(pid,&status,0)) < 0) { if(errno == EINTR) { errno = 0; continue; } break; } CatchChild(); if (wpid != pid) { DEBUG(2,("waitpid(%d) : %s\n",(int)pid,strerror(errno))); if (outfd) { close(*outfd); *outfd = -1; } return -1; } /* Reset the seek pointer. */ if (outfd) { sys_lseek(*outfd, 0, SEEK_SET); } #if defined(WIFEXITED) && defined(WEXITSTATUS) if (WIFEXITED(status)) { return WEXITSTATUS(status); } #endif return status; } CatchChild(); /* we are in the child. we exec /bin/sh to do the work for us. we don't directly exec the command we want because it may be a pipeline or anything else the config file specifies */ /* point our stdout at the file we want output to go into */ if (outfd) { close(1); if (sys_dup2(*outfd,1) != 1) { DEBUG(2,("Failed to create stdout file descriptor\n")); close(*outfd); exit(80); } } /* now completely lose our privileges. This is a fairly paranoid way of doing it, but it does work on all systems that I know of */ become_user_permanently(uid, gid); if (getuid() != uid || geteuid() != uid || getgid() != gid || getegid() != gid) { /* we failed to lose our privileges - do not execute the command */ exit(81); /* we can't print stuff at this stage, instead use exit codes for debugging */ } #ifndef __INSURE__ /* close all other file descriptors, leaving only 0, 1 and 2. 0 and 2 point to /dev/null from the startup code */ { int fd; for (fd=3;fd<256;fd++) close(fd); } #endif execl("/bin/sh","sh","-c",cmd,NULL); /* not reached */ exit(82); #endif //_XBOX return 1; }
void printRealAndEffectiveId() { printf("user id = %d \n", getuid()); printf("effective user id = %d\n", geteuid()); printf("group id = %d \n", getpid()); printf("effective group id = %d\n", getegid()); }
int main(int ac, char **av) { int lc; char *msg; struct stat buf; /* * parse standard options */ if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL) { tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); } /* * perform global setup for test */ setup(); /* * check looping state if -i option given */ for (lc = 0; TEST_LOOPING(lc); lc++) { tst_count = 0; /* * TEST mkdir() base functionality */ /* Initialize the test directory name */ sprintf(tstdir1, "tstdir1.%d", getpid()); /* Call mkdir(2) using the TEST macro */ TEST(mkdir(tstdir1, PERMS)); if (TEST_RETURN == -1) { tst_resm(TFAIL, "mkdir(%s, %#o) Failed", tstdir1, PERMS); continue; } if (STD_FUNCTIONAL_TEST) { if (stat(tstdir1, &buf) == -1) { tst_brkm(TBROK, cleanup, "failed to stat the " "new directory"); } /* check the owner */ if (buf.st_uid != geteuid()) { tst_resm(TFAIL, "mkdir() FAILED to set owner ID" " as process's effective ID"); continue; } /* check the group ID */ if (buf.st_gid != getegid()) { tst_resm(TFAIL, "mkdir() failed to set group ID" " as the process's group ID"); continue; } tst_resm(TPASS, "mkdir() functionality is correct"); } else { tst_resm(TPASS, "call succeeded"); } /* clean up things in case we are looping */ if (rmdir(tstdir1) == -1) { tst_brkm(TBROK, cleanup, "could not remove directory"); } } /* * cleanup and exit */ cleanup(); tst_exit(); }
void _cupsSetDefaults(void) { cups_file_t *fp; /* File */ const char *home; /* Home directory of user */ char filename[1024]; /* Filename */ _cups_client_conf_t cc; /* client.conf values */ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ DEBUG_puts("_cupsSetDefaults()"); /* * Load initial client.conf values... */ cups_init_client_conf(&cc); /* * Read the /etc/cups/client.conf and ~/.cups/client.conf files, if * present. */ snprintf(filename, sizeof(filename), "%s/client.conf", cg->cups_serverroot); if ((fp = cupsFileOpen(filename, "r")) != NULL) { cups_read_client_conf(fp, &cc); cupsFileClose(fp); } # ifdef HAVE_GETEUID if ((geteuid() == getuid() || !getuid()) && getegid() == getgid() && (home = getenv("HOME")) != NULL) # elif !defined(WIN32) if (getuid() && (home = getenv("HOME")) != NULL) # else if ((home = getenv("HOME")) != NULL) # endif /* HAVE_GETEUID */ { /* * Look for ~/.cups/client.conf... */ snprintf(filename, sizeof(filename), "%s/.cups/client.conf", home); if ((fp = cupsFileOpen(filename, "r")) != NULL) { cups_read_client_conf(fp, &cc); cupsFileClose(fp); } } /* * Finalize things so every client.conf value is set... */ cups_finalize_client_conf(&cc); if (cg->encryption == (http_encryption_t)-1) cg->encryption = cc.encryption; if (!cg->server[0] || !cg->ipp_port) cupsSetServer(cc.server_name); if (!cg->ipp_port) cups_set_default_ipp_port(cg); if (!cg->user[0]) strlcpy(cg->user, cc.user, sizeof(cg->user)); #ifdef HAVE_GSSAPI if (!cg->gss_service_name[0]) strlcpy(cg->gss_service_name, cc.gss_service_name, sizeof(cg->gss_service_name)); #endif /* HAVE_GSSAPI */ if (cg->trust_first < 0) cg->trust_first = cc.trust_first; if (cg->any_root < 0) cg->any_root = cc.any_root; if (cg->expired_certs < 0) cg->expired_certs = cc.expired_certs; if (cg->validate_certs < 0) cg->validate_certs = cc.validate_certs; #ifdef HAVE_SSL _httpTLSSetOptions(cc.ssl_options | _HTTP_TLS_SET_DEFAULT, cc.ssl_min_version, cc.ssl_max_version); #endif /* HAVE_SSL */ }
int main(int argc, char *argv[]) { char *system = NULL; int i; char *p; char sbuf[12]; gid = getgid(); egid = getegid(); uid = getuid(); euid = geteuid(); #if INCLUDE_CU_INTERFACE if (equal(sname(argv[0]), "cu")) { cumode = 1; cumain(argc, argv); goto cucommon; } #endif /* INCLUDE_CU_INTERFACE */ if (argc > 4) usage(); if (!isatty(0)) errx(1, "must be interactive"); for (; argc > 1; argv++, argc--) { if (argv[1][0] != '-') system = argv[1]; else switch (argv[1][1]) { case 'v': vflag++; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': BR = atoi(&argv[1][1]); break; default: warnx("%s, unknown option", argv[1]); break; } } if (system == NULL) goto notnumber; if (isalpha(*system)) goto notnumber; /* * System name is really a phone number... * Copy the number then stomp on the original (in case the number * is private, we don't want 'ps' or 'w' to find it). */ if (strlen(system) > sizeof(PNbuf) - 1) errx(1, "phone number too long (max = %zd bytes)", sizeof PNbuf - 1); strncpy(PNbuf, system, sizeof(PNbuf) - 1); for (p = system; *p; p++) *p = '\0'; PN = PNbuf; (void)snprintf(sbuf, sizeof(sbuf), "tip%ld", BR); system = sbuf; notnumber: (void)signal(SIGINT, cleanup); (void)signal(SIGQUIT, cleanup); (void)signal(SIGHUP, cleanup); (void)signal(SIGTERM, cleanup); (void)signal(SIGUSR1, tipdone); if ((i = hunt(system)) == 0) { printf("all ports busy\n"); exit(3); } if (i == -1) { printf("link down\n"); (void)uu_unlock(uucplock); exit(3); } setbuf(stdout, NULL); loginit(); /* * Kludge, their's no easy way to get the initialization * in the right order, so force it here */ if ((PH = getenv("PHONES")) == NULL) PH = _PATH_PHONES; vinit(); /* init variables */ setparity("even"); /* set the parity table */ if ((i = speed(number(value(BAUDRATE)))) == 0) { printf("tip: bad baud rate %d\n", number(value(BAUDRATE))); (void)uu_unlock(uucplock); exit(3); } /* * Now that we have the logfile and the ACU open * return to the real uid and gid. These things will * be closed on exit. Swap real and effective uid's * so we can get the original permissions back * for removing the uucp lock. */ user_uid(); /* * Hardwired connections require the * line speed set before they make any transmissions * (this is particularly true of things like a DF03-AC) */ if (HW) ttysetup(i); if ((p = connect())) { printf("\07%s\n[EOT]\n", p); daemon_uid(); (void)uu_unlock(uucplock); exit(1); } if (!HW) ttysetup(i); cucommon: /* * From here down the code is shared with * the "cu" version of tip. */ #if HAVE_TERMIOS tcgetattr (0, &otermios); ctermios = otermios; #ifndef _POSIX_SOURCE ctermios.c_iflag = (IMAXBEL|IXANY|ISTRIP|IXON|BRKINT); ctermios.c_lflag = (PENDIN|IEXTEN|ISIG|ECHOCTL|ECHOE|ECHOKE); #else ctermios.c_iflag = (ISTRIP|IXON|BRKINT); ctermios.c_lflag = (PENDIN|IEXTEN|ISIG|ECHOE); #endif ctermios.c_cflag = (CLOCAL|HUPCL|CREAD|CS8); ctermios.c_cc[VINTR] = ctermios.c_cc[VQUIT] = -1; ctermios.c_cc[VSUSP] = ctermios.c_cc[VDSUSP] = ctermios.c_cc[VDISCARD] = ctermios.c_cc[VLNEXT] = -1; #else /* HAVE_TERMIOS */ ioctl(0, TIOCGETP, (char *)&defarg); ioctl(0, TIOCGETC, (char *)&defchars); ioctl(0, TIOCGLTC, (char *)&deflchars); ioctl(0, TIOCGETD, (char *)&odisc); arg = defarg; arg.sg_flags = ANYP | CBREAK; tchars = defchars; tchars.t_intrc = tchars.t_quitc = -1; ltchars = deflchars; ltchars.t_suspc = ltchars.t_dsuspc = ltchars.t_flushc = ltchars.t_lnextc = -1; #endif /* HAVE_TERMIOS */ raw(); pipe(fildes); pipe(repdes); (void)signal(SIGALRM, timeoutfunc); /* * Everything's set up now: * connection established (hardwired or dialup) * line conditioned (baud rate, mode, etc.) * internal data structures (variables) * so, fork one process for local side and one for remote. */ printf(cumode ? "Connected\r\n" : "\07connected\r\n"); if (LI != NULL && tiplink (LI, 0) != 0) { tipabort ("login failed"); } if ((pid = fork())) tipin(); else tipout(); /*NOTREACHED*/ }
int DLL_DECL Cns_lstat(const char *path, struct Cns_filestat *statbuf) { char *actual_path; int c, n; char func[16]; gid_t gid; int msglen; char *q; char *rbp; char repbuf[57]; char *sbp; char sendbuf[REQBUFSZ]; char server[CA_MAXHOSTNAMELEN+1]; struct Cns_api_thread_info *thip; uid_t uid; u_signed64 zero = 0; strcpy (func, "Cns_lstat"); if (Cns_apiinit (&thip)) return (-1); uid = geteuid(); gid = getegid(); #if defined(_WIN32) if (uid < 0 || gid < 0) { Cns_errmsg (func, NS053); serrno = SENOMAPFND; return (-1); } #endif if (! path || ! statbuf) { serrno = EFAULT; return (-1); } if (strlen (path) > CA_MAXPATHLEN) { serrno = ENAMETOOLONG; return (-1); } if (Cns_selectsrvr (path, thip->server, server, &actual_path)) return (-1); /* Build request header */ sbp = sendbuf; marshall_LONG (sbp, CNS_MAGIC2); marshall_LONG (sbp, CNS_LSTAT); q = sbp; /* save pointer. The next field will be updated */ msglen = 3 * LONGSIZE; marshall_LONG (sbp, msglen); /* Build request body */ marshall_LONG (sbp, uid); marshall_LONG (sbp, gid); marshall_HYPER (sbp, thip->cwd); marshall_HYPER (sbp, zero); marshall_STRING (sbp, actual_path); msglen = sbp - sendbuf; marshall_LONG (q, msglen); /* update length field */ c = send2nsd (NULL, server, sendbuf, msglen, repbuf, sizeof(repbuf)); if (c == 0) { rbp = repbuf; unmarshall_HYPER (rbp, statbuf->fileid); unmarshall_WORD (rbp, statbuf->filemode); unmarshall_LONG (rbp, statbuf->nlink); unmarshall_LONG (rbp, statbuf->uid); unmarshall_LONG (rbp, statbuf->gid); unmarshall_HYPER (rbp, statbuf->filesize); unmarshall_TIME_T (rbp, statbuf->atime); unmarshall_TIME_T (rbp, statbuf->mtime); unmarshall_TIME_T (rbp, statbuf->ctime); unmarshall_WORD (rbp, statbuf->fileclass); unmarshall_BYTE (rbp, statbuf->status); } if (c && serrno == SENAMETOOLONG) serrno = ENAMETOOLONG; return (c); }
EXPORT_C int OPENSSL_issetugid(void) { if (getuid() != geteuid()) return 1; if (getgid() != getegid()) return 1; return 0; }
int DLL_DECL Cns_statr(const char *sfn, struct Cns_filestatg *statbuf) { int c, n; char func[16]; gid_t gid; int msglen; char *q; char *rbp; char repbuf[132]; char *sbp; char sendbuf[REQBUFSZ]; struct Cns_api_thread_info *thip; uid_t uid; strcpy (func, "Cns_statr"); if (Cns_apiinit (&thip)) return (-1); uid = geteuid(); gid = getegid(); #if defined(_WIN32) if (uid < 0 || gid < 0) { Cns_errmsg (func, NS053); serrno = SENOMAPFND; return (-1); } #endif if (! sfn || ! statbuf) { serrno = EFAULT; return (-1); } if (strlen (sfn) > CA_MAXSFNLEN) { serrno = ENAMETOOLONG; return (-1); } /* Build request header */ sbp = sendbuf; marshall_LONG (sbp, CNS_MAGIC); marshall_LONG (sbp, CNS_STATR); q = sbp; /* save pointer. The next field will be updated */ msglen = 3 * LONGSIZE; marshall_LONG (sbp, msglen); /* Build request body */ marshall_LONG (sbp, uid); marshall_LONG (sbp, gid); marshall_STRING (sbp, sfn); msglen = sbp - sendbuf; marshall_LONG (q, msglen); /* update length field */ c = send2nsd (NULL, NULL, sendbuf, msglen, repbuf, sizeof(repbuf)); if (c == 0) { rbp = repbuf; unmarshall_HYPER (rbp, statbuf->fileid); unmarshall_STRING (rbp, statbuf->guid); unmarshall_WORD (rbp, statbuf->filemode); unmarshall_LONG (rbp, statbuf->nlink); unmarshall_LONG (rbp, statbuf->uid); unmarshall_LONG (rbp, statbuf->gid); unmarshall_HYPER (rbp, statbuf->filesize); unmarshall_TIME_T (rbp, statbuf->atime); unmarshall_TIME_T (rbp, statbuf->mtime); unmarshall_TIME_T (rbp, statbuf->ctime); unmarshall_WORD (rbp, statbuf->fileclass); unmarshall_BYTE (rbp, statbuf->status); unmarshall_STRING (rbp, statbuf->csumtype); unmarshall_STRING (rbp, statbuf->csumvalue); } if (c && serrno == SENAMETOOLONG) serrno = ENAMETOOLONG; return (c); }
int main(int argc, char **argv) { struct stat statbuf; uid_t uid = getuid(); uid_t gid = getgid(); uid_t euid = geteuid(); uid_t egid = getegid(); struct passwd *pwd = getpwuid(uid); struct group *grp = getgrgid(gid); if (argc < 3) usage(argv[0]); options_init(); openlog(PACKAGE, LOG_PID, LOG_DAEMON); memset(&statbuf, 0, sizeof(statbuf)); if (!options_binload(argv[1])) { log_err(0, "invalid binary config file %s", argv[1]); usage(argv[0]); } if (uid != 0) { if (strcmp(pwd->pw_name, CHILLI_USER)) { log_err(0, "has to run as user %s or root", CHILLI_USER); usage(argv[0]); } if (strcmp(grp->gr_name, CHILLI_GROUP)) { log_err(0, "has to run as group %s or root", CHILLI_GROUP); usage(argv[0]); } } log_dbg("USER %s(%d/%d), GROUP %s(%d/%d) CHILLI[UID %d, GID %d]", pwd->pw_name, uid, euid, grp->gr_name, gid, egid, _options.uid, _options.gid); if (stat(argv[2], &statbuf)) { log_err(errno, "%s does not exist", argv[2]); usage(argv[0]); } if (_options.uid && /* chilli is running as non-root */ _options.uid == euid && /* current euid same as chilli uid */ _options.gid == egid && /* current egid same as chilli gid */ statbuf.st_uid == 0 && /* script owned by root */ statbuf.st_gid == _options.gid && /* script group same as chilli gid */ (statbuf.st_mode & 0400) == 0400) { if (setuid(0)) log_err(errno, "setuid %s", argv[0]); } log_info("Running %s (%d/%d)", argv[2], getuid(), geteuid()); if (execv(argv[2], &argv[2])) { log_err(errno, "exec %s", argv[2]); usage(argv[0]); } return 0; }
BOOL change_to_user(connection_struct *conn, uint16 vuid) { user_struct *vuser = get_valid_user_struct(vuid); int snum; gid_t gid; uid_t uid; char group_c; BOOL must_free_token = False; NT_USER_TOKEN *token = NULL; if (!conn) { DEBUG(2,("change_to_user: Connection not open\n")); return(False); } /* * We need a separate check in security=share mode due to vuid * always being UID_FIELD_INVALID. If we don't do this then * in share mode security we are *always* changing uid's between * SMB's - this hurts performance - Badly. */ if((lp_security() == SEC_SHARE) && (current_user.conn == conn) && (current_user.ut.uid == conn->uid)) { DEBUG(4,("change_to_user: Skipping user change - already " "user\n")); return(True); } else if ((current_user.conn == conn) && (vuser != 0) && (current_user.vuid == vuid) && (current_user.ut.uid == vuser->uid)) { DEBUG(4,("change_to_user: Skipping user change - already " "user\n")); return(True); } snum = SNUM(conn); if ((vuser) && !check_user_ok(conn, vuser, snum)) { DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) " "not permitted access to share %s.\n", vuser->user.smb_name, vuser->user.unix_name, vuid, lp_servicename(snum))); return False; } if (conn->force_user) /* security = share sets this too */ { uid = conn->uid; gid = conn->gid; current_user.ut.groups = conn->groups; current_user.ut.ngroups = conn->ngroups; token = conn->nt_user_token; } else if (vuser) { uid = conn->admin_user ? 0 : vuser->uid; gid = vuser->gid; current_user.ut.ngroups = vuser->n_groups; current_user.ut.groups = vuser->groups; token = vuser->nt_user_token; } else { DEBUG(2,("change_to_user: Invalid vuid used %d in accessing " "share %s.\n",vuid, lp_servicename(snum) )); return False; } /* * See if we should force group for this service. * If so this overrides any group set in the force * user code. */ if((group_c = *lp_force_group(snum))) { token = dup_nt_token(NULL, token); if (token == NULL) { DEBUG(0, ("dup_nt_token failed\n")); return False; } must_free_token = True; if(group_c == '+') { /* * Only force group if the user is a member of * the service group. Check the group memberships for * this user (we already have this) to * see if we should force the group. */ int i; for (i = 0; i < current_user.ut.ngroups; i++) { if (current_user.ut.groups[i] == conn->gid) { gid = conn->gid; gid_to_sid(&token->user_sids[1], gid); break; } } } else { gid = conn->gid; gid_to_sid(&token->user_sids[1], gid); } } set_sec_ctx(uid, gid, current_user.ut.ngroups, current_user.ut.groups, token); /* * Free the new token (as set_sec_ctx copies it). */ if (must_free_token) TALLOC_FREE(token); current_user.conn = conn; current_user.vuid = vuid; DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n", (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid())); return(True); }
static void id_print(struct passwd *pw, int use_ggl, int p_euid, int p_egid) { struct group *gr; gid_t gid, egid, lastgid; uid_t uid, euid; int cnt, ngroups; long ngroups_max; gid_t *groups; const char *fmt; if (pw != NULL) { uid = pw->pw_uid; gid = pw->pw_gid; } else { uid = getuid(); gid = getgid(); } ngroups_max = sysconf(_SC_NGROUPS_MAX) + 1; if ((groups = malloc(sizeof(gid_t) * ngroups_max)) == NULL) err(1, "malloc"); if (use_ggl && pw != NULL) { ngroups = ngroups_max; getgrouplist(pw->pw_name, gid, groups, &ngroups); } else { ngroups = getgroups(ngroups_max, groups); } if (pw != NULL) printf("uid=%u(%s)", uid, pw->pw_name); else printf("uid=%u", getuid()); printf(" gid=%u", gid); if ((gr = getgrgid(gid))) (void)printf("(%s)", gr->gr_name); if (p_euid && (euid = geteuid()) != uid) { (void)printf(" euid=%u", euid); if ((pw = getpwuid(euid))) (void)printf("(%s)", pw->pw_name); } if (p_egid && (egid = getegid()) != gid) { (void)printf(" egid=%u", egid); if ((gr = getgrgid(egid))) (void)printf("(%s)", gr->gr_name); } fmt = " groups=%u"; for (lastgid = -1, cnt = 0; cnt < ngroups; ++cnt) { if (lastgid == (gid = groups[cnt])) continue; printf(fmt, gid); fmt = ",%u"; if ((gr = getgrgid(gid))) printf("(%s)", gr->gr_name); lastgid = gid; } printf("\n"); free(groups); }
int main(int argc, char** argv) { int i; int err; struct stat buf; int uid,gid; /* Parse the command line options */ for(i=1;i<argc;i++) { if(!strcmp(argv[i],"-h") || !strcmp(argv[i],"--help")) usage(1); if(!strcmp(argv[i],"--version")) usage(2); if(!strcmp(argv[i],"-d")) { detached=0; if(i<(argc-1) && isdigit(argv[i+1][0])) { StderrLevel=Fatal+1-atoi(argv[++i]); if(StderrLevel<0 || StderrLevel>Fatal) {fprintf(stderr,"wwwoffled: The '-d' option requires a number between 0 and %d.\n",Fatal+1); exit(1);} } continue; } if(!strcmp(argv[i],"-l")) { if(++i>=argc) {fprintf(stderr,"wwwoffled: The '-l' option requires a filename.\n"); exit(1);} if(argv[i][0]!='/') {fprintf(stderr,"wwwoffled: The '-l' option requires an absolute pathname.\n"); exit(1);} log_file=argv[i]; continue; } if(!strcmp(argv[i],"-p")) { print_pid=1; continue; } if(!strcmp(argv[i],"-f")) { nofork=1; detached=0; continue; } if(!strcmp(argv[i],"-c")) { if(++i>=argc) {fprintf(stderr,"wwwoffled: The '-c' option requires a filename.\n"); exit(1);} config_file=argv[i]; continue; } fprintf(stderr,"wwwoffled: Unknown option '%s'.\n",argv[i]); exit(1); } /* Combination options */ if(log_file) { if(nofork) log_file=NULL; /* -f overrides -l */ else detached=1; /* -l overrides -d */ if(StderrLevel==-1) StderrLevel=Inform; /* -l sets log level if no -d */ } /* Initialise things. */ for(i=0;i<MAX_FETCH_SERVERS;i++) fetch_pids[i]=0; for(i=0;i<MAX_SERVERS;i++) server_pids[i]=0; if(log_file) OpenErrorLog(log_file); InitErrorHandler("wwwoffled",0,1); /* use stderr and not syslog to start with. */ /* Read the configuration file. */ InitConfigurationFile(config_file); init_io(STDERR_FILENO); if(ReadConfigurationFile(STDERR_FILENO)) PrintMessage(Fatal,"Error in configuration file '%s'.",ConfigurationFileName()); finish_io(STDERR_FILENO); InitErrorHandler("wwwoffled",ConfigInteger(UseSyslog),1); /* enable syslog if requested. */ /* Print a startup message. */ #if USE_IPV6 #define IPV6_STRING "with ipv6" #else #define IPV6_STRING "without ipv6" #endif #define ZLIB_STRING "with zlib" #define GNUTLS_STRING "with gnutls" PrintMessage(Important,"WWWOFFLE Demon Version %s (%s,%s,%s) started.",WWWOFFLE_VERSION,IPV6_STRING,ZLIB_STRING,GNUTLS_STRING); PrintMessage(Inform,"WWWOFFLE Read Configuration File '%s'.",ConfigurationFileName()); /* Change the user and group. */ gid=ConfigInteger(WWWOFFLE_Gid); uid=ConfigInteger(WWWOFFLE_Uid); if(uid!=-1) seteuid(0); if(log_file && (uid!=-1 || gid!=-1)) chown(log_file,(uid_t)uid,(gid_t)gid); if(gid!=-1) { #if HAVE_SETGROUPS if(getuid()==0 || geteuid()==0) if(setgroups(0,NULL)<0) PrintMessage(Fatal,"Cannot clear supplementary group list [%!s]."); #endif #if HAVE_SETRESGID if(setresgid((gid_t)gid,(gid_t)gid,(gid_t)gid)<0) PrintMessage(Fatal,"Cannot set real/effective/saved group id to %d [%!s].",gid); #else if(geteuid()==0) { if(setgid((gid_t)gid)<0) PrintMessage(Fatal,"Cannot set group id to %d [%!s].",gid); } else { #if HAVE_SETREGID if(setregid(getegid(),(gid_t)gid)<0) PrintMessage(Fatal,"Cannot set effective group id to %d [%!s].",gid); if(setregid((gid_t)gid,(gid_t)~1)<0) PrintMessage(Fatal,"Cannot set real group id to %d [%!s].",gid); #else PrintMessage(Fatal,"Must be root to totally change group id."); #endif } #endif } if(uid!=-1) { #if HAVE_SETRESUID if(setresuid((uid_t)uid,(uid_t)uid,(uid_t)uid)<0) PrintMessage(Fatal,"Cannot set real/effective/saved user id to %d [%!s].",uid); #else if(geteuid()==0) { if(setuid((uid_t)uid)<0) PrintMessage(Fatal,"Cannot set user id to %d [%!s].",uid); } else { #if HAVE_SETREUID if(setreuid(geteuid(),(uid_t)uid)<0) PrintMessage(Fatal,"Cannot set effective user id to %d [%!s].",uid); if(setreuid((uid_t)uid,(uid_t)~1)<0) PrintMessage(Fatal,"Cannot set real user id to %d [%!s].",uid); #else PrintMessage(Fatal,"Must be root to totally change user id."); #endif } #endif } if(uid!=-1 || gid!=-1) PrintMessage(Inform,"Running with uid=%d, gid=%d.",geteuid(),getegid()); if(geteuid()==0 || getegid()==0) PrintMessage(Warning,"Running with root user or group privileges is not recommended."); /* Create, Change to and open the spool directory. */ umask(0); if(stat(ConfigString(SpoolDir),&buf)) { err=mkdir(ConfigString(SpoolDir),(mode_t)ConfigInteger(DirPerm)); if(err==-1 && errno!=EEXIST) PrintMessage(Fatal,"Cannot create spool directory %s [%!s].",ConfigString(SpoolDir)); stat(ConfigString(SpoolDir),&buf); } if(!S_ISDIR(buf.st_mode)) PrintMessage(Fatal,"The spool directory %s is not a directory.",SpoolDir); err=ChangeToSpoolDir(ConfigString(SpoolDir)); if(err==-1) PrintMessage(Fatal,"Cannot change to spool directory %s [%!s].",ConfigString(SpoolDir)); /* Bind the HTTP proxy socket(s). */ #if USE_IPV6 if(ConfigString(Bind_IPv6)) { http_fd[1]=OpenServerSocket(ConfigString(Bind_IPv6),ConfigInteger(HTTP_Port)); if(http_fd[1]==-1) PrintMessage(Fatal,"Cannot create HTTP IPv6 server socket."); } #endif if(ConfigString(Bind_IPv4)) { http_fd[0]=OpenServerSocket(ConfigString(Bind_IPv4),ConfigInteger(HTTP_Port)); if(http_fd[0]==-1) { #if USE_IPV6 if(http_fd[1]!=-1 && /* PS 2003-01-13 redundant? If IPv6 is listening to 0 then it doesn't matter what address IPv4 is listening to... (at least on linux?) */ /* ConfigString(Bind_IPv4) && !strcmp(ConfigString(Bind_IPv4),"0.0.0.0") && */ ConfigString(Bind_IPv6) && !strcmp(ConfigString(Bind_IPv6),"[0:0:0:0:0:0:0:0]")) PrintMessage(Warning,"Cannot create HTTP IPv4 server socket (but the IPv6 one might accept IPv4 connections)."); else PrintMessage(Fatal,"Cannot create HTTP IPv4 server socket."); #else PrintMessage(Fatal,"Cannot create HTTP server socket."); #endif } } if(http_fd[0]==-1 && http_fd[1]==-1) { #if USE_IPV6 PrintMessage(Fatal,"The IPv4 and IPv6 HTTP sockets were not bound; are they disabled in the config file?"); #else PrintMessage(Fatal,"The HTTP socket was not bound; is it disabled in the config file?"); #endif } /* Bind the HTTPS socket(s). */ if(LoadRootCredentials()) { PrintMessage(Warning,"Failed to read (or create if needed) the WWWOFFLE root certificates."); } if(LoadTrustedCertificates()) { PrintMessage(Warning,"Failed to read in any trusted certificates."); } #if USE_IPV6 if(ConfigString(Bind_IPv6)) { https_fd[1]=OpenServerSocket(ConfigString(Bind_IPv6),ConfigInteger(HTTPS_Port)); if(https_fd[1]==-1) PrintMessage(Fatal,"Cannot create HTTPS IPv6 server socket."); } #endif if(ConfigString(Bind_IPv4)) { https_fd[0]=OpenServerSocket(ConfigString(Bind_IPv4),ConfigInteger(HTTPS_Port)); if(https_fd[0]==-1) { #if USE_IPV6 if(https_fd[1]!=-1 && ConfigString(Bind_IPv4) && !strcmp(ConfigString(Bind_IPv4),"0.0.0.0") && ConfigString(Bind_IPv6) && !strcmp(ConfigString(Bind_IPv6),"[0:0:0:0:0:0:0:0]")) PrintMessage(Warning,"Cannot create HTTPS IPv4 server socket (but the IPv6 one might accept IPv4 connections)."); else PrintMessage(Fatal,"Cannot create HTTPS IPv4 server socket."); #else PrintMessage(Fatal,"Cannot create HTTPS server socket."); #endif } } if(https_fd[0]==-1 && https_fd[1]==-1) { #if USE_IPV6 PrintMessage(Fatal,"The IPv4 and IPv6 HTTPS sockets were not bound; are they disabled in the config file?"); #else PrintMessage(Fatal,"The HTTPS socket was not bound; is it disabled in the config file?"); #endif } /* Bind the WWWOFFLE control socket(s). */ #if USE_IPV6 if(ConfigString(Bind_IPv6)) { wwwoffle_fd[1]=OpenServerSocket(ConfigString(Bind_IPv6),ConfigInteger(WWWOFFLE_Port)); if(wwwoffle_fd[1]==-1) PrintMessage(Fatal,"Cannot create WWWOFFLE IPv6 server socket."); } #endif if(ConfigString(Bind_IPv4)) { wwwoffle_fd[0]=OpenServerSocket(ConfigString(Bind_IPv4),ConfigInteger(WWWOFFLE_Port)); if(wwwoffle_fd[0]==-1) { #if USE_IPV6 if(wwwoffle_fd[1]!=-1 && ConfigString(Bind_IPv4) && !strcmp(ConfigString(Bind_IPv4),"0.0.0.0") && ConfigString(Bind_IPv6) && !strcmp(ConfigString(Bind_IPv6),"[0:0:0:0:0:0:0:0]")) { PrintMessage(Warning,"Cannot create WWWOFFLE IPv4 server socket (but the IPv6 one might accept IPv4 connections)."); PrintMessage(Warning,"Consider adding \"bind-ipv4 = none\" to wwwoffle.conf if using IPv6."); } else PrintMessage(Fatal,"Cannot create WWWOFFLE IPv4 server socket."); #else PrintMessage(Fatal,"Cannot create WWWOFFLE server socket."); #endif } } if(wwwoffle_fd[0]==-1 && wwwoffle_fd[1]==-1) { #if USE_IPV6 PrintMessage(Fatal,"The IPv4 and IPv6 WWWOFFLE sockets were not bound; are they disabled in the config file?"); #else PrintMessage(Fatal,"The WWWOFFLE socket was not bound; is it disabled in the config file?"); #endif } /* Detach from terminal */ if(detached) { demoninit(); PrintMessage(Important,"Detached from terminal and changed pid to %d.",getpid()); if(log_file) InitErrorHandler("wwwoffled",-1,-1); /* pid changes after detaching, keep stderr as was. */ else InitErrorHandler("wwwoffled",-1, 0); /* pid changes after detaching, disable stderr. */ if(!log_file) close(STDERR_FILENO); } close(STDIN_FILENO); close(STDOUT_FILENO); install_sighandlers(); max_servers=ConfigInteger(MaxServers); max_fetch_servers=ConfigInteger(MaxFetchServers); /* Loop around waiting for connections. */ PrintMessage(Inform,"WWWOFFLE Ready to accept connections."); do { struct timeval tv; fd_set readfd; int nfds=0,nfd=0; FD_ZERO(&readfd); #if USE_IPV6 for(nfd=0;nfd<=1;nfd++) { #endif if(http_fd[nfd]>=nfds) nfds=http_fd[nfd]+1; if(https_fd[nfd]>=nfds) nfds=https_fd[nfd]+1; if(wwwoffle_fd[nfd]>=nfds) nfds=wwwoffle_fd[nfd]+1; if(n_servers<max_servers) { if(http_fd[nfd]!=-1) FD_SET(http_fd[nfd],&readfd); if(https_fd[nfd]!=-1) FD_SET(https_fd[nfd],&readfd); } if(wwwoffle_fd[nfd]!=-1) FD_SET(wwwoffle_fd[nfd],&readfd); #if USE_IPV6 } #endif tv.tv_sec=10; tv.tv_usec=0; if(select(nfds,&readfd,NULL,NULL,&tv)!=-1) { #if USE_IPV6 for(nfd=0;nfd<=1;nfd++) { #endif if(wwwoffle_fd[nfd]!=-1 && FD_ISSET(wwwoffle_fd[nfd],&readfd)) { char *host,*ip; int port,client; client=AcceptConnect(wwwoffle_fd[nfd]); if(client>=0) { init_io(client); configure_io_timeout(client,ConfigInteger(SocketTimeout),ConfigInteger(SocketTimeout)); if(SocketRemoteName(client,&host,&ip,&port)) { finish_io(client); CloseSocket(client); } else { char *canonical_ip=CanonicaliseHost(ip); if(IsAllowedConnectHost(host) || IsAllowedConnectHost(canonical_ip)) { PrintMessage(Important,"WWWOFFLE Connection from host %s (%s).",host,canonical_ip); /* Used in audit-usage.pl */ CommandConnect(client); if(fetch_fd!=client) { finish_io(client); CloseSocket(client); } } else { PrintMessage(Warning,"WWWOFFLE Connection rejected from host %s (%s).",host,canonical_ip); /* Used in audit-usage.pl */ finish_io(client); CloseSocket(client); } free(canonical_ip); } } } if(http_fd[nfd]!=-1 && FD_ISSET(http_fd[nfd],&readfd)) { char *host,*ip; int port,client; client=AcceptConnect(http_fd[nfd]); if(client>=0) { init_io(client); configure_io_timeout(client,ConfigInteger(SocketTimeout),ConfigInteger(SocketTimeout)); if(!SocketRemoteName(client,&host,&ip,&port)) { char *canonical_ip=CanonicaliseHost(ip); if(IsAllowedConnectHost(host) || IsAllowedConnectHost(canonical_ip)) { PrintMessage(Inform,"HTTP Proxy connection from host %s (%s).",host,canonical_ip); /* Used in audit-usage.pl */ ForkServer(client); } else PrintMessage(Warning,"HTTP Proxy connection rejected from host %s (%s).",host,canonical_ip); /* Used in audit-usage.pl */ free(canonical_ip); } if(nofork) got_sigexit=1; if(!nofork) { finish_io(client); CloseSocket(client); } } } if(https_fd[nfd]!=-1 && FD_ISSET(https_fd[nfd],&readfd)) { char *host,*ip; int port,client; client=AcceptConnect(https_fd[nfd]); if(client>=0) { init_io(client); configure_io_timeout(client,ConfigInteger(SocketTimeout),ConfigInteger(SocketTimeout)); if(!SocketRemoteName(client,&host,&ip,&port)) { char *canonical_ip=CanonicaliseHost(ip); if(IsAllowedConnectHost(host) || IsAllowedConnectHost(canonical_ip)) { PrintMessage(Inform,"HTTPS Proxy connection from host %s (%s).",host,canonical_ip); /* Used in audit-usage.pl */ ForkServer(client); } else PrintMessage(Warning,"HTTPS Proxy connection rejected from host %s (%s).",host,canonical_ip); /* Used in audit-usage.pl */ free(canonical_ip); } if(nofork) got_sigexit=1; if(!nofork) { finish_io(client); CloseSocket(client); } } } #if USE_IPV6 } #endif } if(got_sighup) { got_sighup=0; PrintMessage(Important,"SIGHUP signalled."); if(log_file) { PrintMessage(Important,"Closing and opening log file."); OpenErrorLog(log_file); } PrintMessage(Important,"WWWOFFLE Re-reading Configuration File."); if(ReadConfigurationFile(-1)) PrintMessage(Warning,"Error in configuration file; keeping old values."); PrintMessage(Important,"WWWOFFLE Finished Re-reading Configuration File."); } if(got_sigchld) { int pid, status; int isserver=0; /* To avoid race conditions, reset the flag before fetching the status */ got_sigchld=0; while((pid=waitpid(-1,&status,WNOHANG))>0) { int i; int exitval=0; if(WIFEXITED(status)) exitval=WEXITSTATUS(status); else if(WIFSIGNALED(status)) exitval=-WTERMSIG(status); if(purging) if(purge_pid==pid) { if(exitval>=0) PrintMessage(Inform,"Purge process exited with status %d (pid=%d).",exitval,pid); else PrintMessage(Important,"Purge process terminated by signal %d (pid=%d).",-exitval,pid); purging=0; } for(i=0;i<max_servers;i++) if(server_pids[i]==pid) { n_servers--; server_pids[i]=0; isserver=1; if(exitval>=0) PrintMessage(Inform,"Child wwwoffles exited with status %d (pid=%d).",exitval,pid); else PrintMessage(Important,"Child wwwoffles terminated by signal %d (pid=%d).",-exitval,pid); break; } /* Check if the child that terminated is one of the fetching wwwoffles */ for(i=0;i<max_fetch_servers;i++) if(fetch_pids[i]==pid) { n_fetch_servers--; fetch_pids[i]=0; break; } if(exitval==3) fetching=0; if(exitval==4 && online!=0) fetching=1; if(online==0) fetching=0; } if(isserver) PrintMessage(Debug,"Currently running: %d servers total, %d fetchers.",n_servers,n_fetch_servers); } /* The select timed out or we got a signal. If we are currently fetching, start fetch servers to look for jobs in the spool directory. */ while(fetching && n_fetch_servers<max_fetch_servers && n_servers<max_servers) ForkServer(fetch_fd); if(fetch_fd!=-1 && !fetching && n_fetch_servers==0) { write_string(fetch_fd,"WWWOFFLE No more to fetch.\n"); finish_io(fetch_fd); CloseSocket(fetch_fd); fetch_fd=-1; PrintMessage(Important,"WWWOFFLE Fetch finished."); ForkRunModeScript(ConfigString(RunFetch),"fetch","stop",-1); } } while(!got_sigexit); /* Close down and exit. */ /* These four sockets don't need finish_io() calling because they never had init_io() called, they are just bound to a port listening. */ if(http_fd[0]!=-1) CloseSocket(http_fd[0]); if(http_fd[1]!=-1) CloseSocket(http_fd[1]); if(wwwoffle_fd[0]!=-1) CloseSocket(wwwoffle_fd[0]); if(wwwoffle_fd[1]!=-1) CloseSocket(wwwoffle_fd[1]); if(!nofork) { if(n_servers) PrintMessage(Important,"Exit signalled - waiting for %d child wwwoffles servers.",n_servers); else PrintMessage(Important,"Exit signalled."); } while(n_servers) { int i; int pid,status,exitval=0; while((pid=waitpid(-1,&status,0))>0) { if(WIFEXITED(status)) exitval=WEXITSTATUS(status); else if(WIFSIGNALED(status)) exitval=-WTERMSIG(status); for(i=0;i<max_servers;i++) if(server_pids[i]==pid) { n_servers--; server_pids[i]=0; if(exitval>=0) PrintMessage(Inform,"Child wwwoffles exited with status %d (pid=%d).",exitval,pid); else PrintMessage(Important,"Child wwwoffles terminated by signal %d (pid=%d).",-exitval,pid); break; } if(purging) if(purge_pid==pid) { if(exitval>=0) PrintMessage(Inform,"Purge process exited with status %d (pid=%d).",exitval,pid); else PrintMessage(Important,"Purge process terminated by signal %d (pid=%d).",-exitval,pid); purging=0; } } } PrintMessage(Important,"Exiting."); FinishConfigurationFile(); FreeLoadedCredentials(); return(0); }