static int linuxset_user_group(char *user, int uid, int gid){ if (set_caps(CAPS)!=0) __abort(-1,getuid()!= uid,"set_caps(CAPS) failed"); __abort(-1,(prctl(PR_SET_KEEPCAPS,1,0,0,0) < 0),"prctl failed in linuxset_user_group"); __abort(-1,(set_user_group(user,uid,gid)!=0),"set_user_group failed in linuxset_user_group"); if (set_caps(CAPSMIN)!=0) __abort(-1,(getuid()!= uid),"set_caps(CAPSMIN) failed"); return 0; }
static bool checkuser(char *user, uid_t * uid, gid_t * gid) { struct passwd *pwds = NULL; int status = 0; pid_t pid = 0; /* Do we actually _have_ to switch user? */ if (user == NULL) return true; pwds = getpwnam(user); if (pwds == NULL) { log_error("Invalid user name '%s' specified", user); return false; } *uid = pwds->pw_uid; *gid = pwds->pw_gid; /* Validate the user name in another process */ pid = fork(); if (pid == -1) { log_error("Cannot validate user name"); return false; } /* If we're in the child process, let's validate */ if (pid == 0) { if (set_user_group(user, *uid, *gid) != 0) exit(1); /* If we got here we switched user/group */ exit(0); } while (waitpid(pid, &status, 0) != pid) { /* Just wait */ } /* The child must have exited cleanly */ if (WIFEXITED(status)) { status = WEXITSTATUS(status); /* If the child got out with 0 the user is ok */ if (status == 0) { log_debug("User '%s' validated", user); return true; } } log_error("Error validating user '%s'", user); return false; }
static int linuxset_user_group(const char *user, int uid, int gid) { int caps_set = 0; if (user == NULL) return 0; /* set capabilities enough for binding port 80 setuid/getuid */ if (getuid() == 0) { if (set_caps(CAPS) != 0) { if (getuid() != uid) { log_error("set_caps(CAPS) failed for user '%s'", user); return -1; } log_debug("set_caps(CAPS) failed for user '%s'", user); } /* make sure they are kept after setuid */ if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) { log_error("prctl failed in for user '%s'", user); return -1; } caps_set = 1; } /* set setuid/getuid */ if (set_user_group(user, uid, gid) != 0) { log_error("set_user_group failed for user '%s'", user); return -1; } if (caps_set) { /* set capability to binding port 80 read conf */ if (set_caps(CAPSMIN) != 0) { if (getuid() != uid) { log_error("set_caps(CAPSMIN) failed for user '%s'", user); return -1; } log_debug("set_caps(CAPSMIN) failed for user '%s'", user); } } return 0; }
static int checkuser( char *user, uid_t *uid, gid_t *gid ) { struct passwd *pwds = NULL; int status = 0; pid_t pid = 0; __abort(1, user == NULL,"" ); pwds = getpwnam( user ); __abort(0, (pwds == NULL ),"Invalid user name '%s' specified", user ); *uid = pwds->pw_uid; *gid = pwds->pw_gid; pid = fork( ); __abort(0,( pid == -1 ), "Cannot validate user name" ); if( pid == 0 ) { __die( set_user_group( user, *uid, *gid ) != 0,"set_user_group failed." ); exit( 0 ); } while( waitpid( pid, &status, 0 ) != pid ); if( WIFEXITED( status ) ) { status = WEXITSTATUS( status ); __abort(0, (status != 0),"User '%s' validated", user ); } return 1; }
static int child(arg_data *args, home_data *data, uid_t uid, gid_t gid) { int ret = 0; /* check the pid file */ ret = check_pid(args); if (args->vers != true && args->chck != true) { if (ret == 122) return ret; if (ret < 0) return ret; } #ifdef OS_LINUX /* setuid()/setgid() only apply the current thread so we must do it now */ if (linuxset_user_group(args->user, uid, gid) != 0) return 4; #endif /* Initialize the Java VM */ if (java_init(args, data) != true) { log_debug("java_init failed"); return 1; } else log_debug("java_init done"); /* Check wether we need to dump the VM version */ if (args->vers == true) { log_error("jsvc (Apache Commons Daemon) " JSVC_VERSION_STRING); log_error("Copyright (c) 1999-2011 Apache Software Foundation."); if (java_version() != true) { return -1; } else return 0; } /* Check wether we need to dump the VM version */ else if (args->vershow == true) { if (java_version() != true) { return 7; } } /* Do we have to do a "check-only" initialization? */ if (args->chck == true) { if (java_check(args) != true) return 2; printf("Service \"%s\" checked successfully\n", args->clas); return 0; } /* Load the service */ if (java_load(args) != true) { log_debug("java_load failed"); return 3; } else log_debug("java_load done"); /* Downgrade user */ #ifdef OS_LINUX if (args->user && set_caps(0) != 0) { log_debug("set_caps (0) failed"); return 4; } #else if (set_user_group(args->user, uid, gid) != 0) return 4; #endif /* Start the service */ umask(envmask); if (java_start() != true) { log_debug("java_start failed"); return 5; } else log_debug("java_start done"); /* Install signal handlers */ handler_hup = signal_set(SIGHUP, handler); handler_usr1 = signal_set(SIGUSR1, handler); handler_usr2 = signal_set(SIGUSR2, handler); handler_trm = signal_set(SIGTERM, handler); handler_int = signal_set(SIGINT, handler); controlled = getpid(); log_debug("Waiting for a signal to be delivered"); create_tmp_file(args); while (!stopping) { #if defined(OSD_POSIX) java_sleep(60); /* pause(); */ #else /* pause() is not threadsafe */ sleep(60); #endif if(doreopen) { doreopen = false; set_output(args->outfile, args->errfile, args->redirectstdin, args->procname); } if(dosignal) { dosignal = false; java_signal(); } } remove_tmp_file(args); log_debug("Shutdown or reload requested: exiting"); /* Stop the service */ if (java_stop() != true) return 6; if (doreload == true) ret = 123; else ret = 0; /* Destroy the service */ java_destroy(); /* Destroy the Java VM */ if (JVM_destroy(ret) != true) return 7; return ret; }