/**/ #include #include #include #include #include #include #include #include "myopt.h" void usagemessage(void) { if (fputs("usage: really [] [ ...] [--]" " [ [ ...]]\n" "user-options:\n" " if no options given, set the uid to 0;\n" " -u|--user also sets their default group list\n" " -i|--useronly } set the uid\n" " -I|--uidonly } but inherits the group list\n" "group-options:\n" " -z|--groupsclear only groups specified are to be used\n" " -g|--group } add this to\n" " -G|--gid } the group list\n", stderr) == EOF) { perror("write usage"); exit(-1); } } static const char *opt_user, *opt_useronly; static int opt_groupsclear= 0, opt_ngids= 0, opt_uidonly= -1; static int opt_gids[512]; static void af_group(const struct cmdinfo *cip, const char *value) { struct group *gr; if (opt_ngids >= sizeof(opt_gids)/sizeof(opt_gids[0])) badusage("too many groups specified"); gr= getgrnam(value); if (!gr) { fprintf(stderr,"unknown group `%s'\n",value); exit(-1); } opt_gids[opt_ngids++]= gr->gr_gid; } static void af_gid(const struct cmdinfo *cip, const char *value) { char *ep; unsigned long ul; if (opt_ngids >= sizeof(opt_gids)/sizeof(opt_gids[0])) badusage("too many gids specified"); ul= strtoul(value,&ep,0); if ((*ep) || (uid_t)ul != ul || ul>INT_MAX) badusage("bad gid `%s'",value); opt_gids[opt_ngids++]= ul; } static void af_help(const struct cmdinfo *cip, const char *value) { usagemessage(); exit(0); } static const struct cmdinfo cmdinfos[]= { { "user", 'u', 1, 0, &opt_user, 0, }, { "useronly", 'i', 1, 0, &opt_useronly, 0 }, { "uidonly", 'I', 1, &opt_uidonly, 0, 0 }, { "groupsclear", 'z', 0, &opt_groupsclear, 0, 0, 1 }, { "group", 'g', 1, 0, 0, af_group }, { "gid", 'G', 1, 0, 0, af_gid }, { "help", 'h', 0, 0, 0, af_help }, { 0, 0 } }; #ifdef REALLY_CHECK_FILE void checkroot(void) { int r; r= access(REALLY_CHECK_FILE,W_OK); if (r) { perror("sorry"); exit(-1); } } #endif #ifdef REALLY_CHECK_GID void checkroot(void) { gid_t groups[512]; int r; r= getgid(); if (r==REALLY_CHECK_GID) return; if (r<0) { perror("getgid check"); exit(-1); } r= getgroups(sizeof(groups)/sizeof(groups[0]),groups); if (r<0) { perror("getgroups check"); exit(-1); } for (i=0; ipw_uid; } orgmaingid= getgid(); orgmainuid= getuid(); if (orgmaingid<0) { perror("getgid failed"); exit(-1); } if (opt_user) { r= initgroups(opt_user,pw->pw_gid); if (r) { perror("initgroups failed"); exit(-1); } maingid= pw->pw_gid; } else { maingid= -1; } if (opt_groupsclear) { ngroups= 0; if (opt_ngids > sizeof(groups)/sizeof(groups[0])) { fputs("too many groups to set\n",stderr); exit(-1); } } else { ngroups= getgroups(0,0); if (ngroups<0) { perror("getgroups(0,0) failed"); exit(-1); } if (ngroups+opt_ngids > sizeof(groups)/sizeof(groups[0])) { fputs("too many groups already set for total to fit\n",stderr); exit(-1); } ngroups= getgroups(ngroups,groups); if (ngroups<0) { perror("getgroups failed"); exit(-1); } } if (opt_ngids) { maingid= opt_gids[0]; } if (opt_ngids || opt_groupsclear) { ngroups_in= ngroups; ngroups= 0; for (i=0; i=0) { fputs("could seteuid 0",stderr); exit(-1); } if (errno != EPERM) { perror("unexpected failure mode for seteuid 0"); exit(-1); } } r= getuid(); if (r<0) { perror("getuid failed"); exit(-1); } if (r != mainuid) { fputs("getuid mismatch",stderr); exit(-1); } r= geteuid(); if (r<0) { perror("geteuid failed"); exit(-1); } if (r != mainuid) { fputs("geteuid mismatch",stderr); exit(-1); } if (maingid != -1) { for (i=0; i=ngroups && maingid != orgmaingid) { r= setgid(orgmaingid); if (r>=0) { fputs("could setgid back",stderr); exit(-1); } if (errno != EPERM) { perror("unexpected failure mode for setgid back"); exit(-1); } } r= getgid(); if (r<0) { perror("getgid failed"); exit(-1); } if (r != maingid) { fputs("getgid mismatch",stderr); exit(-1); } r= getegid(); if (r<0) { perror("getegid failed"); exit(-1); } if (r != maingid) { fputs("getegid mismatch",stderr); exit(-1); } } if (!*argv) { cp= getenv("SHELL"); if (!cp) cp= "sh"; execlp(cp,cp,"-i",(const char*)0); } else { execvp(argv[0],(char**)argv); } perror("exec failed"); exit(-1); }