/* This is a reversible version of become_user, and returns the saved * credentials so that creds can be switched back calling restore_creds */ errno_t switch_creds(TALLOC_CTX *mem_ctx, uid_t uid, gid_t gid, int num_gids, gid_t *gids, struct sss_creds **saved_creds) { struct sss_creds *ssc = NULL; int size; int ret; uid_t myuid; uid_t mygid; DEBUG(SSSDBG_FUNC_DATA, "Switch user to [%d][%d].\n", uid, gid); myuid = geteuid(); mygid = getegid(); if (saved_creds) { /* save current user credentials */ size = getgroups(0, NULL); if (size == -1) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, "Getgroups failed! (%d, %s)\n", ret, strerror(ret)); goto done; } ssc = talloc_size(mem_ctx, (sizeof(struct sss_creds) + size * sizeof(gid_t))); if (!ssc) { DEBUG(SSSDBG_CRIT_FAILURE, "Allocation failed!\n"); ret = ENOMEM; goto done; } ssc->num_gids = size; size = getgroups(ssc->num_gids, ssc->gids); if (size == -1) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, "Getgroups failed! (%d, %s)\n", ret, strerror(ret)); /* free ssc immediately otherwise the code will try to restore * wrong creds */ talloc_zfree(ssc); goto done; } /* we care only about effective ids */ ssc->uid = myuid; ssc->gid = mygid; } /* if we are regaining root set euid first so that we have CAP_SETUID back, * ane the other calls work too, otherwise call it last so that we can * change groups before we loose CAP_SETUID */ if (uid == 0) { ret = setresuid(0, 0, 0); if (ret == -1) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, "setresuid failed [%d][%s].\n", ret, strerror(ret)); goto done; } } /* TODO: use libcap-ng if we need to get/set capabilities too ? */ if (myuid == uid && mygid == gid) { DEBUG(SSSDBG_FUNC_DATA, "Already user [%"SPRIuid"].\n", uid); return EOK; } /* try to setgroups first should always work if CAP_SETUID is set, * otherwise it will always fail, failure is not critical though as * generally we only really care about uid and at mot primary gid */ ret = setgroups(num_gids, gids); if (ret == -1) { ret = errno; DEBUG(SSSDBG_TRACE_FUNC, "setgroups failed [%d][%s].\n", ret, strerror(ret)); } /* change gid now, (leaves saved gid to current, so we can restore) */ ret = setresgid(-1, gid, -1); if (ret == -1) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, "setresgid failed [%d][%s].\n", ret, strerror(ret)); goto done; } if (uid != 0) { /* change uid, (leaves saved uid to current, so we can restore) */ ret = setresuid(-1, uid, -1); if (ret == -1) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, "setresuid failed [%d][%s].\n", ret, strerror(ret)); goto done; } } ret = 0; done: if (ret) { /* attempt to restore creds first */ restore_creds(ssc); talloc_free(ssc); } else if (saved_creds) { *saved_creds = ssc; } return ret; }
void api_test() { /* int getgroups( int gidsetsize, gid_t grouplist[]); * int setgroups( int size_t size, const gid_t grouplist[]); */ /* The getgroups() function shall fill in the array grouplist with the current * supplementary group IDs of the calling process. It is implementation- * defined whether getgroups() also returns the effective group ID in the * grouplist array. * The gidsetsize argument specifies the number of elements in the array * grouplist. The actual number of group IDs stored in the array shall be * returned. The values of array entries with indices greater than or equal to * the value returned are undefined. * If gidsetsize is 0, getgroups shall return the number of group IDs that it * would otherwise return without modifying the array pointed to by grouplist. * * setgroups() sets the supplementary group IDs for the calling process. The * size argument specifies the number of supplementary group IDs in the buffer * pointed to by grouplist. setgroups() is a privileged operation. */ /* Minix does not return the effective group ID with the supplementary groups. * Use getegid() to get that value. In order to call setgroups, a process * must have super user privileges. */ int i; gid_t *grouplist, *grouplist2; long ngroups_max; subtest = 2; /* Ask the system how many groups we're allowed to set */ ngroups_max = sysconf(_SC_NGROUPS_MAX); grouplist = malloc(ngroups_max *sizeof(gid_t)); grouplist2 = malloc(ngroups_max *sizeof(gid_t)); /* Let's invent some imaginary groups */ #define START_GID 20001 for (i = 0; i < ngroups_max; i++) grouplist[i] = i + START_GID; /* Normal usage */ if (setgroups(ngroups_max, grouplist) != 0) e(1); /* Try one less than max supported groups */ if (setgroups(ngroups_max - 1, grouplist) != 0) e(2); /* Try just one group */ if (setgroups(1, grouplist) != 0) e(3); /* Unset all supplementary groups */ if (setgroups(0, grouplist) != 0) e(4); /* Should not be allowed to use a negative set size */ if (setgroups(-1, grouplist) == 0) e(5); else if(errno != EINVAL) e(6); /* error must be EINVAL */ /* Should not be allowed to set more groups than supported by the system */ if (setgroups(ngroups_max + 1, grouplist) == 0) e(7); else if(errno != EINVAL) e(8); /* error must be EINVAL */ /* Should not be allowed to provide an invalid grouplist address */ if (setgroups(ngroups_max, NULL) == 0) e(9); else if(errno != EFAULT) e(10); /* error must be EFAULT */ /* The last time we called setgroups with proper parameters, we effectively * cleared the list. Verify that with getgroups(). */ if (getgroups(ngroups_max, grouplist2) != 0) e(11); /* Repopulate grouplist with values and read them back */ if (setgroups(ngroups_max, grouplist) != 0) e(12); if (getgroups(0, grouplist2) != ngroups_max) e(13); if (getgroups(ngroups_max, grouplist2) != ngroups_max) e(14); for (i = 0; i < ngroups_max; i++) { if(grouplist[i] != grouplist2[i]) { e(15); break; /* One error message should be enough here */ } } /* Should not be able to read less groups than are actually stored. */ if (getgroups(ngroups_max - 1, grouplist2) != -1) e(16); /* Repopulate grouplist with only half the groups and read them back */ memset(grouplist2, 0, ngroups_max * sizeof(gid_t)); /* Clear array */ #define HALF_LIST_SIZE ngroups_max / 2 if (setgroups(HALF_LIST_SIZE, grouplist) != 0) e(17); if (getgroups(0, grouplist2) != HALF_LIST_SIZE) e(18); if (getgroups(HALF_LIST_SIZE, grouplist2) != HALF_LIST_SIZE) e(19); for (i = 0; i < HALF_LIST_SIZE; i++) { if(grouplist[i] != grouplist2[i]) { e(20); break; /* Also here one message ought to be enough */ } } /* Try to read more groups than we have set */ memset(grouplist2, 0, ngroups_max * sizeof(gid_t)); /* Clear array */ if (getgroups(ngroups_max, grouplist2) != HALF_LIST_SIZE) e(21); for (i = 0; i < HALF_LIST_SIZE; i++) { /* Anything above indices 'HALF_LIST_SIZE' is undefined */ if(grouplist[i] != grouplist2[i]) { e(22); break; } } /* Try to set too high a group ID */ grouplist2[0] = GID_MAX + 1; /* Out of range */ if (setgroups(1, grouplist2) == 0) e(23); if (errno != EINVAL) e(24); free(grouplist); free(grouplist2); }
int sandbox(const char *user, bool capsicum, const char *fmt, ...) { #ifdef HAVE_JAIL struct jail jailst; char *jailhost; va_list ap; #endif struct passwd *pw; uid_t ruid, euid; gid_t rgid, egid; #ifdef HAVE_GETRESUID uid_t suid; #endif #ifdef HAVE_GETRESGID gid_t sgid; #endif gid_t *groups, *ggroups; bool jailed; int ngroups, ret; PJDLOG_ASSERT(user != NULL); PJDLOG_ASSERT(fmt != NULL); ret = -1; groups = NULL; ggroups = NULL; /* * According to getpwnam(3) we have to clear errno before calling the * function to be able to distinguish between an error and missing * entry (with is not treated as error by getpwnam(3)). */ errno = 0; pw = getpwnam(user); if (pw == NULL) { if (errno != 0) { pjdlog_errno(LOG_ERR, "Unable to find info about '%s' user", user); goto out; } else { pjdlog_error("'%s' user doesn't exist.", user); errno = ENOENT; goto out; } } ngroups = sysconf(_SC_NGROUPS_MAX); if (ngroups == -1) { pjdlog_errno(LOG_WARNING, "Unable to obtain maximum number of groups"); ngroups = NGROUPS_MAX; } ngroups++; /* For base gid. */ groups = malloc(sizeof(groups[0]) * ngroups); if (groups == NULL) { pjdlog_error("Unable to allocate memory for %d groups.", ngroups); goto out; } if (getgrouplist(user, pw->pw_gid, groups, &ngroups) == -1) { pjdlog_error("Unable to obtain groups of user %s.", user); goto out; } #ifdef HAVE_JAIL va_start(ap, fmt); (void)vasprintf(&jailhost, fmt, ap); va_end(ap); if (jailhost == NULL) { pjdlog_error("Unable to allocate memory for jail host name."); goto out; } bzero(&jailst, sizeof(jailst)); jailst.version = JAIL_API_VERSION; jailst.path = pw->pw_dir; jailst.hostname = jailhost; if (jail(&jailst) >= 0) { jailed = true; } else { jailed = false; pjdlog_errno(LOG_WARNING, "Unable to jail to directory %s", pw->pw_dir); } free(jailhost); #else /* !HAVE_JAIL */ jailed = false; #endif /* !HAVE_JAIL */ if (!jailed) { if (chroot(pw->pw_dir) == -1) { pjdlog_errno(LOG_ERR, "Unable to change root directory to %s", pw->pw_dir); goto out; } } PJDLOG_VERIFY(chdir("/") == 0); if (setgroups(ngroups, groups) == -1) { pjdlog_errno(LOG_ERR, "Unable to set groups"); goto out; } if (setgid(pw->pw_gid) == -1) { pjdlog_errno(LOG_ERR, "Unable to set gid to %u", (unsigned int)pw->pw_gid); goto out; } if (setuid(pw->pw_uid) == -1) { pjdlog_errno(LOG_ERR, "Unable to set uid to %u", (unsigned int)pw->pw_uid); goto out; } #ifdef HAVE_CAP_ENTER if (capsicum) { capsicum = (cap_enter() == 0); if (!capsicum) { pjdlog_common(LOG_DEBUG, 1, errno, "Unable to sandbox using capsicum"); } } #else /* !HAVE_CAP_ENTER */ capsicum = false; #endif /* !HAVE_CAP_ENTER */ /* * Better be sure that everything succeeded. */ #ifdef HAVE_GETRESUID PJDLOG_VERIFY(getresuid(&ruid, &euid, &suid) == 0); PJDLOG_VERIFY(suid == pw->pw_uid); #else ruid = getuid(); euid = geteuid(); #endif PJDLOG_VERIFY(ruid == pw->pw_uid); PJDLOG_VERIFY(euid == pw->pw_uid); #ifdef HAVE_GETRESGID PJDLOG_VERIFY(getresgid(&rgid, &egid, &sgid) == 0); PJDLOG_VERIFY(sgid == pw->pw_gid); #else rgid = getgid(); egid = getegid(); #endif PJDLOG_VERIFY(rgid == pw->pw_gid); PJDLOG_VERIFY(egid == pw->pw_gid); PJDLOG_VERIFY(getgroups(0, NULL) == ngroups); ggroups = malloc(sizeof(ggroups[0]) * ngroups); if (ggroups == NULL) { pjdlog_error("Unable to allocate memory for %d groups.", ngroups); goto out; } PJDLOG_VERIFY(getgroups(ngroups, ggroups) == ngroups); qsort(groups, (size_t)ngroups, sizeof(groups[0]), groups_compare); qsort(ggroups, (size_t)ngroups, sizeof(ggroups[0]), groups_compare); PJDLOG_VERIFY(bcmp(groups, ggroups, sizeof(groups[0]) * ngroups) == 0); pjdlog_debug(1, "Privileges successfully dropped using %s%s+setgid+setuid.", capsicum ? "capsicum+" : "", jailed ? "jail" : "chroot"); ret = 0; out: if (groups != NULL) free(groups); if (ggroups != NULL) free(ggroups); return (ret); }
int main (int argc, char **argv) { unsigned int i; unsigned int use_capabilities=0; int ret; char **newargv; char *user=NULL, *tmp=NULL; struct passwd *pw=NULL; struct group *gr=NULL; unsigned long ngroups_max=NGROUPS_MAX; unsigned long ngroups=0; gid_t *gids; struct passwd *intpw=NULL; /* for internal_getpwuid() */ char *jaildir=NULL, *newhome=NULL, *shell=NULL; Tiniparser *parser=NULL; char **envs=NULL; unsigned int relax_home_group_permissions=0; unsigned int relax_home_other_permissions=0; unsigned int relax_home_group=0; char *injail_shell=NULL; unsigned int skip_injail_passwd_check=0; DEBUG_MSG(PROGRAMNAME", started\n"); /* open the log facility */ openlog(PROGRAMNAME, LOG_PID, LOG_AUTH); /* attach signal handler */ signal(SIGILL,signal_handler); signal(SIGSEGV,signal_handler); signal(SIGTERM,signal_handler); signal(SIGFPE,signal_handler); /* check if it PRORAMNAME that the user wants */ tmp = strrchr(argv[0], '/'); if (!tmp) { tmp = argv[0]; } else { tmp++; } if (strcmp(tmp, PROGRAMNAME) != 0 && strcmp(tmp, "su")!= 0 && (tmp[0] != '-' || strcmp(&tmp[1], PROGRAMNAME))) { DEBUG_MSG("wrong name, tmp=%s, &tmp[1]=%s\n", tmp, &tmp[1]); syslog(LOG_ERR, "abort, "PROGRAMNAME" is called as %s", argv[0]); exit(1); } /* now test if we are setuid root (the effective user id must be 0, and the real user id > 0 */ if (geteuid() != 0) { if (have_capabilities()) { use_capabilities=1; } else { syslog(LOG_ERR, "abort, effective user ID is not 0, possibly "PROGRAMNAME" is not setuid root"); exit(11); } } if (getuid() == 0) { syslog(LOG_ERR, "abort, "PROGRAMNAME" is run by root, which does not make sense because user root can break out of a jail anyway"); exit(12); } DEBUG_MSG("get user info\n"); /* get user info based on the users name and not on the uid. this enables support for systems with multiple users with the same user id */ tmp = getenv("USER"); if (tmp && strlen(tmp)) { user = strdup(tmp); } if (user) { pw = getpwnam(user); } else { pw = getpwuid(getuid()); } if (!pw) { syslog(LOG_ERR, "abort, failed to get user information for user ID %d: %s, check /etc/passwd", getuid(), strerror(errno)); exit(13); } if (!pw->pw_name || strlen(pw->pw_name)==0) { syslog(LOG_ERR, "abort, got an empty username for user ID %d: %s, check /etc/passwd", getuid(), strerror(errno)); exit(13); } if (user && strcmp(user,pw->pw_name)!=0) { syslog(LOG_ERR, "abort, asked for user %s, got user info for %s", user, pw->pw_name); exit(13); } if (pw->pw_uid != getuid()) { syslog(LOG_ERR, "abort, started by user ID %d, got user info %s with user ID %d,", getuid(), pw->pw_name, pw->pw_uid); exit(13); } DEBUG_MSG("got user %s\nget group info\n",pw->pw_name); gr = getgrgid(getgid()); if (!gr) { syslog(LOG_ERR, "abort, failed to get group information for group ID %d: %s, check /etc/group", getgid(), strerror(errno)); exit(13); } DEBUG_MSG("get additional groups\n"); /* ngroups_max = sysconf(_SC_NGROUPS_MAX);*/ gids = malloc(ngroups_max * sizeof(gid_t)); ngroups = getgroups(ngroups_max,gids); if (ngroups == -1) { syslog(LOG_ERR, "abort, failed to get additional group information: %s, check /etc/group", strerror(errno)); exit(13); } #ifdef DEBUG printf("got additional groups "); for (i=0;i<ngroups;i++) { printf("%d, ",gids[i]); } printf("\n"); #endif /* make sure the jailkit config directory is owned root:root and not writable for others */ if ( (testsafepath(INIPREFIX, 0, 0) &~TESTPATH_GROUPW) != 0 ) { syslog(LOG_ERR, "abort, jailkit configuration directory "INIPREFIX" is not safe; it should be owned 0:0 and not writable for others"); exit(14); } parser = new_iniparser(CONFIGFILE); if (parser) { char *groupsec, *section=NULL, buffer[1024]; /* openbsd complains if this is <1024 */ groupsec = strcat(strcpy(malloc0(strlen(gr->gr_name)+7), "group "), gr->gr_name); if (iniparser_has_section(parser, pw->pw_name)) { section = strdup(pw->pw_name); } else if (iniparser_has_section(parser, groupsec)) { section = groupsec; } else if (iniparser_has_section(parser, "DEFAULT")) { section = strdup("DEFAULT"); } if (section != groupsec) free(groupsec); if (section) { unsigned int pos = iniparser_get_position(parser) - strlen(section) - 2; if (iniparser_get_string_at_position(parser, section, "env", pos, buffer, 1024) > 0) { envs = explode_string(buffer, ','); } relax_home_group_permissions = iniparser_get_int_at_position(parser, section, "relax_home_group_permissions", pos); relax_home_other_permissions = iniparser_get_int_at_position(parser, section, "relax_home_other_permissions", pos); relax_home_group = iniparser_get_int_at_position(parser, section, "relax_home_group", pos); if (iniparser_get_string_at_position(parser, section, "injail_shell", pos, buffer, 1024) > 0) { injail_shell = strdup(buffer); } if (injail_shell) { skip_injail_passwd_check = iniparser_get_int_at_position(parser, section, "skip_injail_passwd_check", pos); } DEBUG_MSG("section %s: relax_home_group_permissions=%d, relax_home_other_permissions=%d, relax_home_group=%d, injail_shell=%s, skip_injail_passwd_check=%d\n", section, relax_home_group_permissions, relax_home_other_permissions, relax_home_group, injail_shell, skip_injail_passwd_check); free(section); } else { DEBUG_MSG("no relevant section found in configfile\n"); } iniparser_close(parser); } else { DEBUG_MSG("no configfile "CONFIGFILE" ??\n"); } DEBUG_MSG("close filedescriptors\n"); /* open file descriptors can be used to break out of a chroot, so we close all of them, except for stdin,stdout and stderr */ #ifdef OPEN_MAX i = OPEN_MAX; #elif defined(NOFILE) i = NOFILE; #else i = getdtablesize(); #endif while (--i > 2) { /*printf("closing file descriptor %d\n",i);*/ while (close(i) != 0 && errno == EINTR); } /* now make sure file descriptors 0 1 and 2 are valid before we (or a child) starts writing to it */ while (1) { int fd; fd = open("/dev/null", O_RDWR); if (fd < 0) exit(10); if (fd > 2) { close(fd); break; } else { DEBUG_MSG("re-opening file descriptor %d\n",fd); } } /* now we clear the environment, except for values allowed in /etc/jailkit/jk_chrootsh.ini */ unset_environ_except(envs); if (envs) { free_array(envs); } if (pw->pw_gid != getgid()) { syslog(LOG_ERR, "abort, the group ID from /etc/passwd (%d) does not match the group ID we run with (%d)", pw->pw_gid, getgid()); exit(15); } if (!pw->pw_dir || strlen(pw->pw_dir) ==0) { syslog(LOG_ERR, "abort, got an empty home directory for user %s (%d)", pw->pw_name, getuid()); exit(16); } if (strstr(pw->pw_dir, "/./") == NULL) { syslog(LOG_ERR, "abort, homedir '%s' for user %s (%d) does not contain the jail separator <jail>/./<home>", pw->pw_dir, pw->pw_name, getuid()); exit(17); } DEBUG_MSG("get jaildir\n"); if (!getjaildir(pw->pw_dir, &jaildir, &newhome)) { syslog(LOG_ERR, "abort, failed to read the jail and the home from %s for user %s (%d)",pw->pw_dir, pw->pw_name, getuid()); exit(17); } DEBUG_MSG("dir=%s,jaildir=%s,newhome=%s\n",pw->pw_dir, jaildir, newhome); DEBUG_MSG("get chdir()\n"); if (chdir(jaildir) != 0) { syslog(LOG_ERR, "abort, chdir(%s) failed: %s, check the permissions for %s",jaildir,strerror(errno),jaildir); exit(19); } else { char test[1024]; /* test if it really succeeded */ if (getcwd(test, 1024)==NULL || !dirs_equal(jaildir, test)) { syslog(LOG_ERR, "abort, the current dir is %s after chdir(%s), but it should be %s",test,jaildir,jaildir); exit(21); } } /* here do test the ownership of the jail and the homedir and such the function testsafepath doe exit itself on any failure */ if (!basicjailissafe(jaildir)) { syslog(LOG_ERR, "abort, %s is not a safe chroot jail.", jaildir); exit(53); } ret = testsafepath(pw->pw_dir, getuid(), getgid()); if ((ret & TESTPATH_NOREGPATH) ) { syslog(LOG_ERR, "abort, path %s is not a directory", pw->pw_dir); exit(53); } if ((ret & TESTPATH_OWNER) ) { syslog(LOG_ERR, "abort, path %s is not owned by %d", pw->pw_dir,getuid()); exit(53); } if (!relax_home_group && (ret & TESTPATH_GROUP)) { syslog(LOG_ERR, "abort, path %s does not have group owner %d, set option 'relax_home_group' to relax this check", pw->pw_dir,getgid()); exit(53); } if (!relax_home_group_permissions && (ret & TESTPATH_GROUPW)) { syslog(LOG_ERR, "abort, path %s is group writable, set option 'relax_home_group_permissions' to relax this check", pw->pw_dir); exit(53); } if (!relax_home_other_permissions && (ret & TESTPATH_OTHERW)) { syslog(LOG_ERR, "abort, path %s is writable for other, set option 'relax_home_other_permissions' to relax this check", pw->pw_dir); exit(53); } /* do a final log message */ tmp = implode_array(&argv[1], argc-1, " "); syslog(LOG_INFO, "now entering jail %s for user %s (%d) with arguments %s", jaildir, pw->pw_name, getuid(), tmp); free(tmp); DEBUG_MSG("chroot()\n"); /* do the chroot() call */ if (chroot(jaildir)) { syslog(LOG_ERR, "abort, chroot(%s) failed: %s, check the permissions for %s", jaildir, strerror(errno), jaildir); exit(33); } if (use_capabilities) { #ifdef HAVE_CAP_GET_PROC cap_t caps; cap_value_t capv[1]; /* drop chroot capability, should we drop all other capabilities that may be used to escape from the jail too ? */ if ((caps = cap_get_proc()) == NULL) { syslog(LOG_ERR, "abort, failed to retrieve current capabilities: %s", strerror(errno)); exit(101); } capv[0] = CAP_SYS_CHROOT; /* other capabilities that should/could be dropped: CAP_SETPCAP, CAP_SYS_MODULE, CAP_SYS_RAWIO, CAP_SYS_PTRACE, CAP_SYS_ADMIN */ if (cap_set_flag(caps, CAP_PERMITTED, 1, capv, CAP_CLEAR)) { syslog(LOG_ERR, "abort, failed to set PERMITTED capabilities: %s", strerror(errno)); exit(102); } if (cap_set_flag(caps, CAP_EFFECTIVE, 1, capv, CAP_CLEAR)) { syslog(LOG_ERR, "abort, failed to set effective capabilities: %s", strerror(errno)); exit(103); } if (cap_set_flag(caps, CAP_INHERITABLE, 1, capv, CAP_CLEAR)) { syslog(LOG_ERR, "abort, failed to set INHERITABLE capabilities: %s", strerror(errno)); exit(104); } if (cap_set_proc(caps)) { syslog(LOG_ERR, "abort, failed to apply new capabilities: %s", strerror(errno)); exit(105); } #else /* we should never get here */ exit(333); #endif } else { /* drop all privileges, it seems that we first have to setgid(), then we have to call initgroups(), then we call setuid() */ if (setgid(getgid())) { syslog(LOG_ERR, "abort, failed to set effective group ID %d: %s", getgid(), strerror(errno)); exit(34); } if (setgroups(ngroups, gids)==-1) { syslog(LOG_ERR, "abort, failed to set additional groups: %s", strerror(errno)); exit(35); } free(gids); /* if (initgroups(pw->pw_name, getgid())) { syslog(LOG_ERR, "abort, failed to init groups for user %s (%d), check %s/etc/group", pw->pw_name,getuid(),jaildir); exit(35); }*/ if (setuid(getuid())) { syslog(LOG_ERR, "abort, failed to set effective user ID %d: %s", getuid(), strerror(errno)); exit(36); } } /* test for user and group info, is it the same? checks username, groupname and home */ if (!skip_injail_passwd_check){ char *oldpw_name,*oldgr_name; oldpw_name = strdup(pw->pw_name); oldgr_name = strdup(gr->gr_name); if (user) { pw = getpwnam(user); } else { pw = getpwuid(getuid()); } if (!pw) { syslog(LOG_ERR, "abort, failed to get user information in the jail for user ID %d: %s, check %s/etc/passwd",getuid(),strerror(errno),jaildir); exit(35); } if (pw->pw_uid != getuid()) { syslog(LOG_ERR, "abort, got user information in the jail for user ID %d instead of user ID %d, check %s/etc/passwd",pw->pw_uid,getuid(),jaildir); exit(35); } DEBUG_MSG("got %s as pw_dir\n",pw->pw_dir); gr = getgrgid(getgid()); if (!gr) { syslog(LOG_ERR, "abort, failed to get group information in the jail for group ID %d: %s, check %s/etc/group",getgid(),strerror(errno),jaildir); exit(35); } if (strcmp(pw->pw_name, oldpw_name)!=0) { syslog(LOG_ERR, "abort, username %s differs from jail username %s for user ID %d, check /etc/passwd and %s/etc/passwd", oldpw_name, pw->pw_name, getuid(), jaildir); exit(37); } if (strcmp(gr->gr_name, oldgr_name)!=0) { syslog(LOG_ERR, "abort, groupname %s differs from jail groupname %s for group ID %d, check /etc/passwd and %s/etc/passwd", oldgr_name, gr->gr_name, getgid(), jaildir); exit(37); } if (strcmp(pw->pw_dir, newhome)!=0) { DEBUG_MSG("%s!=%s\n",pw->pw_dir, newhome); /* if these are different, it could be that getpwuid() gets the real user info (from for example ldap or nscd), and not the info inside the jail, lets test that, and if true, we should use the shell from the internal function as well*/ intpw = internal_getpwuid("/etc/passwd", getuid()); if (!intpw) { DEBUG_MSG("%s!=%s\n",intpw->pw_dir, newhome); syslog(LOG_ERR, "abort, failed to find user %d in %s/etc/passwd", getuid(), jaildir); exit(39); } if (!dirs_equal(intpw->pw_dir, newhome)) { DEBUG_MSG("%s!=%s\n",intpw->pw_dir, newhome); syslog(LOG_ERR, "abort, home directory %s differs from jail home directory %s for user %s (%d), check /etc/passwd and %s/etc/passwd", newhome, pw->pw_dir, pw->pw_name, getuid(), jaildir); exit(39); } } free(oldpw_name); free(oldgr_name); } if (injail_shell) { shell = injail_shell; } else if (intpw) { shell = intpw->pw_shell; } else { shell = pw->pw_shell; } /* test the shell in the jail, it is not allowed to be setuid() root */ testsafepath(shell,0,0); /* prepare the new environment */ setenv("HOME",newhome,1); setenv("USER",pw->pw_name,1); setenv("USERNAME",pw->pw_name,1); setenv("SHELL",shell,1); if (chdir(newhome) != 0) { syslog(LOG_ERR, "abort, chdir(%s) failed inside the jail %s: %s, check the permissions for %s/%s",newhome,jaildir,strerror(errno),jaildir,newhome); exit(41); } /* cleanup before execution */ free(newhome); /* now execute the jailed shell */ /*execl(pw->pw_shell, pw->pw_shell, NULL);*/ newargv = malloc0((argc+1)*sizeof(char *)); newargv[0] = shell; for (i=1;i<argc;i++) { newargv[i] = argv[i]; } execv(shell, newargv); DEBUG_MSG(strerror(errno)); syslog(LOG_ERR, "ERROR: failed to execute shell %s for user %s (%d), check the permissions and libraries of %s/%s",shell,pw->pw_name,getuid(),jaildir,shell); free(jaildir); exit(111); }
/* {{{ php_stat */ static void phar_fancy_stat(zend_stat_t *stat_sb, int type, zval *return_value) { zval stat_dev, stat_ino, stat_mode, stat_nlink, stat_uid, stat_gid, stat_rdev, stat_size, stat_atime, stat_mtime, stat_ctime, stat_blksize, stat_blocks; int rmask=S_IROTH, wmask=S_IWOTH, xmask=S_IXOTH; /* access rights defaults to other */ char *stat_sb_names[13] = { "dev", "ino", "mode", "nlink", "uid", "gid", "rdev", "size", "atime", "mtime", "ctime", "blksize", "blocks" }; if (type >= FS_IS_W && type <= FS_IS_X) { if(stat_sb->st_uid==getuid()) { rmask=S_IRUSR; wmask=S_IWUSR; xmask=S_IXUSR; } else if(stat_sb->st_gid==getgid()) { rmask=S_IRGRP; wmask=S_IWGRP; xmask=S_IXGRP; } else { int groups, n, i; gid_t *gids; groups = getgroups(0, NULL); if(groups > 0) { gids=(gid_t *)safe_emalloc(groups, sizeof(gid_t), 0); n=getgroups(groups, gids); for(i=0;i<n;++i){ if(stat_sb->st_gid==gids[i]) { rmask=S_IRGRP; wmask=S_IWGRP; xmask=S_IXGRP; break; } } efree(gids); } } } switch (type) { case FS_PERMS: RETURN_LONG((zend_long)stat_sb->st_mode); case FS_INODE: RETURN_LONG((zend_long)stat_sb->st_ino); case FS_SIZE: RETURN_LONG((zend_long)stat_sb->st_size); case FS_OWNER: RETURN_LONG((zend_long)stat_sb->st_uid); case FS_GROUP: RETURN_LONG((zend_long)stat_sb->st_gid); case FS_ATIME: RETURN_LONG((zend_long)stat_sb->st_atime); case FS_MTIME: RETURN_LONG((zend_long)stat_sb->st_mtime); case FS_CTIME: RETURN_LONG((zend_long)stat_sb->st_ctime); case FS_TYPE: if (S_ISLNK(stat_sb->st_mode)) { RETURN_STRING("link"); } switch(stat_sb->st_mode & S_IFMT) { case S_IFDIR: RETURN_STRING("dir"); case S_IFREG: RETURN_STRING("file"); } php_error_docref(NULL, E_NOTICE, "Unknown file type (%u)", stat_sb->st_mode & S_IFMT); RETURN_STRING("unknown"); case FS_IS_W: RETURN_BOOL((stat_sb->st_mode & wmask) != 0); case FS_IS_R: RETURN_BOOL((stat_sb->st_mode&rmask)!=0); case FS_IS_X: RETURN_BOOL((stat_sb->st_mode&xmask)!=0 && !S_ISDIR(stat_sb->st_mode)); case FS_IS_FILE: RETURN_BOOL(S_ISREG(stat_sb->st_mode)); case FS_IS_DIR: RETURN_BOOL(S_ISDIR(stat_sb->st_mode)); case FS_IS_LINK: RETURN_BOOL(S_ISLNK(stat_sb->st_mode)); case FS_EXISTS: RETURN_TRUE; /* the false case was done earlier */ case FS_LSTAT: /* FALLTHROUGH */ case FS_STAT: array_init(return_value); ZVAL_LONG(&stat_dev, stat_sb->st_dev); ZVAL_LONG(&stat_ino, stat_sb->st_ino); ZVAL_LONG(&stat_mode, stat_sb->st_mode); ZVAL_LONG(&stat_nlink, stat_sb->st_nlink); ZVAL_LONG(&stat_uid, stat_sb->st_uid); ZVAL_LONG(&stat_gid, stat_sb->st_gid); #ifdef HAVE_ST_RDEV ZVAL_LONG(&stat_rdev, stat_sb->st_rdev); #else ZVAL_LONG(&stat_rdev, -1); #endif ZVAL_LONG(&stat_size, stat_sb->st_size); ZVAL_LONG(&stat_atime, stat_sb->st_atime); ZVAL_LONG(&stat_mtime, stat_sb->st_mtime); ZVAL_LONG(&stat_ctime, stat_sb->st_ctime); #ifdef HAVE_ST_BLKSIZE ZVAL_LONG(&stat_blksize, stat_sb->st_blksize); #else ZVAL_LONG(&stat_blksize,-1); #endif #ifdef HAVE_ST_BLOCKS ZVAL_LONG(&stat_blocks, stat_sb->st_blocks); #else ZVAL_LONG(&stat_blocks,-1); #endif /* Store numeric indexes in proper order */ zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_dev); zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_ino); zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_mode); zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_nlink); zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_uid); zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_gid); zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_rdev); zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_size); zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_atime); zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_mtime); zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_ctime); zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_blksize); zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &stat_blocks); /* Store string indexes referencing the same zval*/ zend_hash_str_update(Z_ARRVAL_P(return_value), stat_sb_names[0], strlen(stat_sb_names[0]), &stat_dev); zend_hash_str_update(Z_ARRVAL_P(return_value), stat_sb_names[1], strlen(stat_sb_names[1]), &stat_ino); zend_hash_str_update(Z_ARRVAL_P(return_value), stat_sb_names[2], strlen(stat_sb_names[2]), &stat_mode); zend_hash_str_update(Z_ARRVAL_P(return_value), stat_sb_names[3], strlen(stat_sb_names[3]), &stat_nlink); zend_hash_str_update(Z_ARRVAL_P(return_value), stat_sb_names[4], strlen(stat_sb_names[4]), &stat_uid); zend_hash_str_update(Z_ARRVAL_P(return_value), stat_sb_names[5], strlen(stat_sb_names[5]), &stat_gid); zend_hash_str_update(Z_ARRVAL_P(return_value), stat_sb_names[6], strlen(stat_sb_names[6]), &stat_rdev); zend_hash_str_update(Z_ARRVAL_P(return_value), stat_sb_names[7], strlen(stat_sb_names[7]), &stat_size); zend_hash_str_update(Z_ARRVAL_P(return_value), stat_sb_names[8], strlen(stat_sb_names[8]), &stat_atime); zend_hash_str_update(Z_ARRVAL_P(return_value), stat_sb_names[9], strlen(stat_sb_names[9]), &stat_mtime); zend_hash_str_update(Z_ARRVAL_P(return_value), stat_sb_names[10], strlen(stat_sb_names[10]), &stat_ctime); zend_hash_str_update(Z_ARRVAL_P(return_value), stat_sb_names[11], strlen(stat_sb_names[11]), &stat_blksize); zend_hash_str_update(Z_ARRVAL_P(return_value), stat_sb_names[12], strlen(stat_sb_names[12]), &stat_blocks); return; } php_error_docref(NULL, E_WARNING, "Didn't understand stat call"); RETURN_FALSE; }
int main(int argc, char** argv) { uid_t uid=getuid(); int user_good=FAILED; char err_mesg[1024]={0}; int myerror=0,i=0; for (i=0;i<argc;i++) { if(!strcmp("-v",argv[i])) { printf ("ds_suusrmgt: Version 2.0.0 - %s %s\n", __DATE__,__TIME__); return 0; } } struct passwd *pwd=getpwuid(uid); if(pwd==NULL) { myerror=errno; sprintf(err_mesg,"ds_suusrmgt: ERROR: Unable to find user with uid \"%d\"! - %d:%s\n",myerror,strerror(myerror)); } else { if (strlen(pwd->pw_name)==6 && !strcmp("secadm",pwd->pw_name)) { //is the user secadm user_good=SECADM; } else if (strlen(pwd->pw_name)==6 && !strcmp("secopr",pwd->pw_name)) { user_good=SECOPR; } else { //is the user a member of security group (primary or secondary) struct group *grp=getgrnam("security"); if (grp==NULL) { myerror=errno; sprintf(err_mesg,"ds_suusrmgt: ERROR: Unable to find group \"security\"! - %d:%s\n",errno,strerror(myerror)); } else { if(grp->gr_gid == pwd->pw_gid) { //Is the primary group the security group user_good=SECURITY; } else { int gsize = getgroups(0,NULL); gid_t *glist=NULL; if(gsize>0) { glist=calloc(gsize,sizeof(gid_t)); getgroups(gsize,glist); for(i=0; i<gsize;i++) { if(grp->gr_gid == glist[i]) { user_good=SECURITY; } } free(glist); } } } } } if(user_good) { int prog_good=0; if(user_good==SECOPR && (argc==7 || argc==8) && !strcmp(argv[1],USRMGR) && !strcmp(argv[2],"-O") && !strcmp(argv[4],"-p")) { prog_good=1; } else if((user_good==SECADM || user_good==SECURITY) && argc>4 && (!strcmp(argv[1],USRMGR) || !strcmp(argv[1],GRPMGR)) && !strcmp(argv[2],"-O")) { prog_good=1; } if (prog_good) { char **newargv=calloc(argc,sizeof(char*)); //argv-1 and a null at the end for (i=1;i<argc;i++) { newargv[i-1]=argv[i]; } i=0; //Execute the command with arguments and a NULL enviroment setuid(0); setgid(0); execve(newargv[0], newargv, NULL); } else { printf("ds_suusrmgt: Permission Denied! - Invalid Program or Arguments\n"); //TODO void syslog(int priority, const char *message, .../* arguments */); } } else { if(err_mesg[0]) { printf(err_mesg); } else { printf("ds_suusrmgt: Permission Denied! - Invalid User\n"); //TODO void syslog(int priority, const char *message, .../* arguments */); } } exit(1); }
int main(int ac, char **av) { int lc; /* loop counter */ char *ptr; /* message returned from parse_opts */ gid_t group; int i; /* counter */ int entries; /* number of group entries */ initgroups("root", 0); if ((ptr = parse_opts(ac, av, NULL, NULL)) != NULL) tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", ptr); setup(); for (lc = 0; TEST_LOOPING(lc); lc++) { Tst_count = 0; TEST(getgroups(-1, gidset)); if (TEST_RETURN == 0) tst_resm(TFAIL, "getgroups succeeded unexpectedly"); else if (STD_FUNCTIONAL_TEST) { if (errno == EINVAL) tst_resm(TPASS, "getgroups failed as expected with EINVAL"); else tst_resm(TFAIL|TTERRNO, "getgroups didn't fail as expected with EINVAL"); } /* * Check that if ngrps is zero that the number of groups is * return and the the gidset array is not modified. * This is a POSIX special case. */ memset(gidset, 052, NGROUPS); memset(cmpset, 052, NGROUPS); TEST(getgroups(0, gidset)); if (TEST_RETURN == -1) tst_resm(TFAIL|TTERRNO, "getgroups failed"); else if (STD_FUNCTIONAL_TEST) { if (memcmp(cmpset, gidset, NGROUPS) != 0) tst_resm(TFAIL, "getgroups modified the gidset array"); else tst_resm(TPASS, "getgroups did not modify the gidset " "array"); } /* * Check to see that is -1 is returned and errno is set to * EINVAL when ngroups is not big enough to hold all groups. */ if (TEST_RETURN <= 1) tst_resm(TCONF, "getgroups returned %ld; unable to test that using ngrps >=1 but less than number of grps", TEST_RETURN); else { TEST(getgroups(TEST_RETURN - 1, gidset)); if (TEST_RETURN == -1) { if (STD_FUNCTIONAL_TEST) { if (errno == EINVAL) tst_resm(TPASS, "getgroups failed as " "expected with EINVAL"); else tst_resm(TFAIL|TERRNO, "getgroups didn't fail " "with EINVAL"); } } else tst_resm(TFAIL, "getgroups succeeded unexpectedly with %ld", TEST_RETURN); } TEST(getgroups(NGROUPS, gidset)); if ((entries = TEST_RETURN) == -1) tst_resm(TFAIL|TTERRNO, "getgroups failed unexpectedly"); else if (STD_FUNCTIONAL_TEST) { group = getgid(); for (i = 0; i < entries; i++) if (gidset[i] == group) { tst_resm(TPASS, "getgroups(NGROUPS,gidset) " "returned %d contains gid %d " "(from getgid)", entries, group); break; } if (i == entries) tst_resm(TFAIL, "getgroups(NGROUPS,gidset) ret %d, does " "not contain gid %d (from getgid)", entries, group); } } cleanup(); tst_exit(); }
/* * NOTE: the "groups" string will be modified in place by strtok() */ void obtain_user_info(const char *user, const char *groups) { struct passwd *pw; int i; uid_t uid = -1; /* no user specified? use the current uid. */ if (!user) { uid = getuid(); pw = getpwuid(uid); } else { /* try to resolve the pw struct from the user string */ pw = getpwnam(user); /* if it fails, try to treat it as a number */ if (!pw) { char *endptr = (char *)user; long uid_tmp; /* try by id as well */ uid_tmp = strtol(user, &endptr, 0); if (uid_tmp == LONG_MAX || *endptr != '\0') { fprintf(stderr, "[!] Invalid user id: %s!\n", user); exit(1); } uid = uid_tmp; pw = getpwuid(uid); } } if (!pw) { fprintf(stderr, "[!] Unable to find uid %lu, trying anyway...\n", (unsigned long)uid); g_uid = uid; g_ngroups = 0; } else g_uid = pw->pw_uid; /* find out what groups the current or specified user is in */ if (!user) { int num = getgroups(0, g_groups); if (num > g_ngroups) { fprintf(stderr, "[!] Too many groups!\n"); exit(1); } if ((g_ngroups = getgroups(g_ngroups, g_groups)) == -1) { perror("[!] Unable to getgroups"); exit(1); } /* make sure our gid is in the groups */ if (!in_group(pw->pw_gid)) add_group(pw->pw_gid); } else if (pw) { /* since we are passing the max, we shouldn't have an issue with failed return */ getgrouplist(pw->pw_name, pw->pw_gid, g_groups, &g_ngroups); } /* else we have no way of knowing, the user doesn't exist =) */ /* append any extra groups */ if (groups) { char *grnam = strtok((char *)groups, ","); while (grnam) { struct group *pg = getgrnam(grnam); unsigned long gid_tmp; gid_t gid; if (!pg) { char *endptr = grnam; gid_tmp = strtoul(grnam, &endptr, 0); /* a bad number indicates a probably mistake */ if (gid_tmp == ULONG_MAX || *endptr != '\0') { fprintf(stderr, "[!] Unknown/invalid group: %s\n", grnam); exit(1); } gid = gid_tmp; /* try again */ pg = getgrgid(gid); } if (!pg) { /* this is just a warning, add the number and keep processing others */ fprintf(stderr, "[!] Unable to find gid %s, trying anyway...\n", grnam); if (!in_group(gid)) add_group(gid); } else if (!in_group(pg->gr_gid)) add_group(pg->gr_gid); /* process the next group name. */ grnam = strtok(NULL, ","); } } /* print what we found :) */ if (pw) printf("[*] uid=%u(%s), groups=", pw->pw_uid, pw->pw_name); else printf("[*] uid=%u(?), groups=", g_uid); for (i = 0; i < g_ngroups; i++) { struct group *pg = getgrgid(g_groups[i]); if (pg) printf("%u(%s)", pg->gr_gid, pg->gr_name); else printf("%u(?)", g_groups[i]); if (i != g_ngroups - 1) printf(","); } printf("\n"); }
static void initialize_group_array() { ngroups = getgroups(0, NULL); group_array = xrealloc(group_array, ngroups * sizeof(gid_t)); getgroups(ngroups, group_array); }
static void addgroup(const char *grpname) { gid_t *grps; long lgid, ngrps_max; int dbmember, i, ngrps; gid_t egid; struct group *grp; char *ep, *pass, *cryptpw; char **p; egid = getegid(); /* Try it as a group name, then a group id. */ if ((grp = getgrnam(grpname)) == NULL) if ((lgid = strtol(grpname, &ep, 10)) <= 0 || *ep != '\0' || (grp = getgrgid((gid_t)lgid)) == NULL ) { warnx("%s: bad group name", grpname); return; } /* * If the user is not a member of the requested group and the group * has a password, prompt and check it. */ dbmember = 0; if (pwd->pw_gid == grp->gr_gid) dbmember = 1; for (p = grp->gr_mem; *p != NULL; p++) if (strcmp(*p, pwd->pw_name) == 0) { dbmember = 1; break; } if (!dbmember && *grp->gr_passwd != '\0' && getuid() != 0) { pass = getpass("Password:"******"Sorry\n"); return; } } ngrps_max = sysconf(_SC_NGROUPS_MAX) + 1; if ((grps = malloc(sizeof(gid_t) * ngrps_max)) == NULL) err(1, "malloc"); if ((ngrps = getgroups(ngrps_max, (gid_t *)grps)) < 0) { warn("getgroups"); goto end; } /* Remove requested gid from supp. list if it exists. */ if (grp->gr_gid != egid && inarray(grp->gr_gid, grps, ngrps)) { for (i = 0; i < ngrps; i++) if (grps[i] == grp->gr_gid) break; ngrps--; memmove(&grps[i], &grps[i + 1], (ngrps - i) * sizeof(gid_t)); PRIV_START; if (setgroups(ngrps, (const gid_t *)grps) < 0) { PRIV_END; warn("setgroups"); goto end; } PRIV_END; } PRIV_START; if (setgid(grp->gr_gid)) { PRIV_END; warn("setgid"); goto end; } PRIV_END; grps[0] = grp->gr_gid; /* Add old effective gid to supp. list if it does not exist. */ if (egid != grp->gr_gid && !inarray(egid, grps, ngrps)) { if (ngrps == ngrps_max) warnx("too many groups"); else { grps[ngrps++] = egid; PRIV_START; if (setgroups(ngrps, (const gid_t *)grps)) { PRIV_END; warn("setgroups"); goto end; } PRIV_END; } } end: free(grps); }
int csopen(register Cs_t* state, const char* apath, int op) { register char* path = (char*)apath; register char* b; register char* s; register int n; int fd; char* t; char* u; char* type; char* endtype; char* host; char* endhost; char* serv; char* endserv; char* qual; char* endqual; char* opath; char* user = 0; char* group = 0; char* trust = 0; char* arg = 0; int nfd = -1; int uid = -1; int gid = -1; int sid = -1; int auth = 1; int mode; unsigned long addr; unsigned long port = 0; struct stat st; char buf[PATH_MAX]; char tmp[PATH_MAX]; if (!path) { errno = EFAULT; return -1; } csprotect(&cs); if (op < 0) op = CS_OPEN_TEST; messagef((state->id, NiL, -8, "open(%s,%o) call", path, op)); /* * blast out the parts */ opath = path; if (pathgetlink(path, buf, sizeof(buf)) <= 0) { if (strlen(path) >= sizeof(buf)) return -1; strcpy(buf, path); } else if ((state->flags & CS_ADDR_LOCAL) && (s = strrchr(buf, '/'))) { /* * dynamic ip assignment can change the addr * underfoot in some implementations so we * double check the local ip here */ strcpy(tmp, buf); if (tokscan(tmp, NiL, "/dev/%s/%s/%s", &type, NiL, &serv) == 3) sfsprintf(buf, sizeof(buf), "/dev/%s/%s/%s", type, csntoa(state, 0), serv); } path = buf; pathcanon(path, 0, 0); errno = ENOENT; strcpy(state->path, path); b = path; if ((*b++ != '/') || !(s = strchr(b, '/'))) return -1; *s++ = 0; if (!streq(b, "dev")) return -1; if (b = strchr(s, '/')) *b++ = 0; if (streq(s, "fdp")) { #if !( CS_LIB_SOCKET_UN || CS_LIB_STREAM || CS_LIB_V10 ) if (access(CS_PROC_FD_TST, F_OK)) { errno = ENODEV; messagef((state->id, NiL, -1, "open: %s: %s: not supported", state->path, s)); return -1; } #endif } else if (!streq(s, "tcp") && !streq(s, "udp")) { messagef((state->id, NiL, -1, "open: %s: %s: invalid type", state->path, s)); return -1; } #if !( CS_LIB_SOCKET || CS_LIB_STREAM || CS_LIB_V10 ) else { errno = ENODEV; messagef((state->id, NiL, -1, "open: %s: %s: not supported", state->path, s)); return -1; } #endif type = s; qual = state->qual; if (!b) host = serv = 0; else { host = b; if (!(s = strchr(b, '/'))) serv = 0; else { *s++ = 0; serv = s; /* * grab the next fd to preserve open semantics */ for (n = 0; n < 10; n++) if ((nfd = dup(n)) >= 0) break; /* * get qual, perm and arg */ mode = S_IRWXU|S_IRWXG|S_IRWXO; if (b = strchr(s, '/')) { *b++ = 0; do { if (*b == '#') { arg = b + 1; break; } if (u = strchr(b, '/')) *u++ = 0; if (s = strchr(b, '=')) *s++ = 0; for (n = 0, t = b; *t; n = HASHKEYPART(n, *t++)); switch (n) { case HASHKEY5('g','r','o','u','p'): group = s ? s : ""; break; case HASHKEY5('l','o','c','a','l'): op |= CS_OPEN_LOCAL; break; case HASHKEY3('n','o','w'): op |= CS_OPEN_NOW; break; case HASHKEY5('o','t','h','e','r'): auth = 0; break; case HASHKEY6('r','e','m','o','t','e'): op |= CS_OPEN_REMOTE; break; case HASHKEY5('s','h','a','r','e'): op |= CS_OPEN_SHARE; break; case HASHKEY5('s','l','a','v','e'): op |= CS_OPEN_SLAVE; break; case HASHKEY4('t','e','s','t'): op |= CS_OPEN_TEST; break; case HASHKEY5('t','r','u','s','t'): op |= CS_OPEN_TRUST; trust = s; break; case HASHKEY4('u','s','e','r'): user = s ? s : ""; break; default: qual += sfsprintf(qual, sizeof(state->qual) - (qual - state->qual) - 1, "%s%s", qual == state->qual ? "" : "-", b); if (s) *(s - 1) = '='; break; } } while (b = u); } } } if (*type != 't') auth = 0; strncpy(state->type, type, sizeof(state->type) - 1); qual = (qual == state->qual) ? (char*)0 : state->qual; messagef((state->id, NiL, -8, "open: type=%s host=%s serv=%s qual=%s", type, host, serv, qual)); if (host) { /* * validate host */ if (!(state->addr = addr = csaddr(state, host))) { if (serv && !(op & CS_OPEN_CREATE) && *type == 't' && (port = csport(state, type, serv)) >= CS_PORT_MIN && port <= CS_PORT_MAX) { /* * attempt proxy connection */ if (nfd >= 0) { close(nfd); nfd = -1; } if ((fd = state->proxy.addr ? csbind(state, type, state->proxy.addr, state->proxy.port, 0L) : reopen(state, csvar(state, CS_VAR_PROXY, 0))) >= 0) { state->proxy.addr = state->addr; state->proxy.port = state->port; n = sfsprintf(tmp, sizeof(tmp), "\n%s!%s!%d\n\n%s\n%s\n0\n-1\n-1\n", type, host, port, csname(state, 0), error_info.id ? error_info.id : state->id); if (cswrite(state, fd, tmp, n) == n && (n = csread(state, fd, tmp, sizeof(tmp), CS_LINE)) >= 2) { if (tmp[0] == '0' && tmp[1] == '\n') return fd; if (error_info.trace <= -4 && n > 2) { s = tmp; s[n - 1] = 0; while (*s && *s++ != '\n'); messagef((state->id, NiL, -4, "%s error message `%s'", csvar(state, CS_VAR_PROXY, 0), s)); } } close(fd); } } #ifdef EADDRNOTAVAIL errno = EADDRNOTAVAIL; #else errno = ENOENT; #endif goto bad; } if (op & CS_OPEN_LOCAL) { state->flags |= CS_ADDR_LOCAL; state->flags &= ~CS_ADDR_REMOTE; } if (op & CS_OPEN_NOW) state->flags |= CS_ADDR_NOW; if ((op & (CS_OPEN_AGENT|CS_OPEN_REMOTE)) == CS_OPEN_REMOTE) { state->flags |= CS_ADDR_REMOTE; state->flags &= ~CS_ADDR_LOCAL; } if (op & CS_OPEN_SHARE) state->flags |= CS_ADDR_SHARE; if (op & CS_OPEN_SLAVE) state->flags |= CS_DAEMON_SLAVE; if (op & CS_OPEN_TEST) state->flags |= CS_ADDR_TEST; if (op & CS_OPEN_TRUST) state->flags |= CS_ADDR_TRUST; if ((state->flags & CS_ADDR_REMOTE) && (!serv || !strneq(serv, CS_SVC_INET, sizeof(CS_SVC_INET) - 1) && (strtol(serv, &t, 0), *t))) return agent(state, state->host, state->user, state->path); if (s = user) { n = geteuid(); if (*s) { if ((uid = struid(s)) < 0) { uid = strtol(s, &t, 0); if (*t) { errno = EACCES; goto bad; } } if (n && uid != n) { errno = EACCES; goto bad; } } else uid = n; mode &= ~(S_IRWXG|S_IRWXO); } if (s = group) { n = getegid(); if (*s) { if ((gid = strgid(s)) < 0) { gid = strtol(s, &t, 0); if (*t) { errno = EACCES; goto bad; } } if (geteuid() && gid != n) { gid_t* groups; int g; if ((g = getgroups(0, NiL)) <= 0) g = getconf("NGROUPS_MAX"); if (groups = newof(0, gid_t, g, 0)) { for (n = getgroups(g, groups); n >= 0; n--) if (gid == groups[n]) break; free(groups); } else n = -1; if (n < 0) { errno = EACCES; goto bad; } } } else gid = n; mode &= ~S_IRWXO; } if (s = trust) { if (!*s) sid = geteuid(); else if ((sid = struid(s)) < 0) { sid = strtol(s, &t, 0); if (*t) { errno = EACCES; goto bad; } } } if (state->flags & CS_ADDR_SHARE) host = CS_HOST_SHARE; else { host = state->host; if (!(state->flags & CS_ADDR_LOCAL)) { if (*type == 'f') { errno = ENODEV; goto bad; } if (op & CS_OPEN_CREATE) { errno = EROFS; goto bad; } } if (serv && !qual && *type != 'f' && (port = csport(state, type, serv)) != CS_PORT_INVALID) { if (op & CS_OPEN_CREATE) addr = 0; else if (port == CS_PORT_RESERVED || port == CS_PORT_NORMAL) goto bad; if (nfd >= 0) { close(nfd); nfd = -1; } state->control = 0; if ((fd = csbind(state, type, addr, port, 0L)) >= 0) { if (mode != (S_IRWXU|S_IRWXG|S_IRWXO) && csauth(state, fd, NiL, NiL)) { close(fd); return -1; } return fd; } } } } /* * get the mount dir prefix */ if (opath == (b = path = state->mount)) { #ifdef ELOOP errno = ELOOP; #else errno = EINVAL; #endif goto bad; } if (*type == 'f') { if (host && !(state->flags & CS_ADDR_LOCAL)) { errno = ENODEV; goto bad; } b += sfsprintf(b, sizeof(state->mount) - (b - path), "%s", csvar(state, CS_VAR_LOCAL, 0)); if ((op & CS_OPEN_CREATE) && eaccess(path, X_OK) && (mkdir(path, S_IRWXU|S_IRWXG|S_IRWXO) || chmod(path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO))) goto bad; } else { if (op & CS_OPEN_TRUST) { if (!pathaccess(csvar(state, CS_VAR_TRUST, 1), csvar(state, CS_VAR_SHARE, 1), NiL, PATH_EXECUTE, b, sizeof(state->mount) - (b - state->mount))) goto bad; } else if (!pathpath(csvar(state, CS_VAR_SHARE, 0), "", PATH_EXECUTE, b, sizeof(state->mount) - (b - state->mount))) goto bad; b += strlen(b); } /* * add the type */ b += sfsprintf(b, sizeof(state->mount) - (b - path), "/%s", type); if (!host) { *(state->control = b + 1) = 0; if (nfd >= 0) close(nfd); if ((fd = open(path, O_RDONLY)) < 0) { mkmount(state, S_IRWXU|S_IRWXG|S_IRWXO, -1, -1, NiL, NiL, NiL); fd = open(path, O_RDONLY); } if (fd < 0) messagef((state->id, NiL, -1, "open: %s: %s: open error", state->path, path)); return fd; } endtype = b; /* * add the host */ if (strlen(host) <= CS_MNT_MAX) b += sfsprintf(b, sizeof(state->mount) - (b - path), "/%s", host); else { s = csntoa(state, addr); if (strlen(s) <= CS_MNT_MAX) b += sfsprintf(b, sizeof(state->mount) - (b - path), "/%s", s); else { unsigned char* a = (unsigned char*)&addr; b += sfsprintf(b, sizeof(state->mount) - (b - path), "/0x%X.%X.%X.%X", a[0], a[1], a[2], a[3]); } } messagef((state->id, NiL, -8, "%s:%d host=`%s' path=`%s'", __FILE__, __LINE__, host, path)); if (!serv) { *(state->control = b + 1) = 0; if (nfd >= 0) close(nfd); if ((fd = open(path, O_RDONLY)) < 0) messagef((state->id, NiL, -1, "open: %s: %s: open error", state->path, path)); return fd; } endhost = b; /* * add the service */ sfsprintf(b, sizeof(state->mount) - (b - path), "%s/%s/%s/%s%s", CS_SVC_DIR, type, serv, serv, CS_SVC_SUFFIX); if (!pathpath(b, "", PATH_ABSOLUTE|PATH_EXECUTE, tmp, sizeof(tmp)) || stat(tmp, &st)) op |= CS_OPEN_TEST; else { *strrchr(tmp, '/') = 0; if (!(op & CS_OPEN_TRUST)) sid = st.st_uid; if (!st.st_size) op |= CS_OPEN_TEST; } b += sfsprintf(b, sizeof(state->mount) - (b - path), "/%s", serv); endserv = b; /* * add the qualifier and perm */ if (sid >= 0) b += sfsprintf(b, sizeof(state->mount) - (b - path), "/%d-", sid); else b += sfsprintf(b, sizeof(state->mount) - (b - path), "/-"); if (uid >= 0) b += sfsprintf(b, sizeof(state->mount) - (b - path), "%d-", uid); else if (gid >= 0) b += sfsprintf(b, sizeof(state->mount) - (b - path), "-%d", gid); else b += sfsprintf(b, sizeof(state->mount) - (b - path), "-"); #if limit_qualifier_length endqual = endserv + CS_MNT_MAX + 1; #else endqual = state->mount + sizeof(state->mount) - 1; #endif if (qual) { if (b < endqual) *b++ = '-'; while (b < endqual && *qual) *b++ = *qual++; } if (*type == 't' && !auth) { if (b >= endqual) b--; *b++ = CS_MNT_OTHER; } /* * add in the connect stream control */ *b++ = '/'; *b = CS_MNT_STREAM; strcpy(b + 1, CS_MNT_TAIL); messagef((state->id, NiL, -8, "%s:%d %s", __FILE__, __LINE__, state->mount)); state->control = b; /* * create the mount subdirs if necessary */ if ((op & CS_OPEN_CREATE) && mkmount(state, mode, uid, gid, endserv, endhost, endtype)) goto bad; mode &= S_IRWXU|S_IRWXG|S_IRWXO; if (nfd >= 0) { close(nfd); nfd = -1; } if (op & CS_OPEN_MOUNT) { messagef((state->id, NiL, -1, "open(%s,%o) = %d, mount = %s", state->path, op, state->mount)); return 0; } if (*type == 'f') { /* * {fdp} */ if ((fd = doattach(state, path, op, mode, user, opath, tmp, serv, b)) < 0) return -1; } else { /* * {tcp,udp} */ messagef((state->id, NiL, -8, "%s:%d %s", __FILE__, __LINE__, state->mount)); if ((fd = reopen(state, path)) < 0) { /* * check for old single char cs mount */ *(state->control + 1) = 0; if ((fd = reopen(state, path)) < 0) messagef((state->id, NiL, -1, "open: %s: %s: reopen error", state->path, path)); *(state->control + 1) = CS_MNT_TAIL[0]; } if (op & CS_OPEN_CREATE) { if (fd >= 0) { close(fd); errno = EEXIST; return -1; } if (errno != ENOENT && errno != ENOTDIR) return -1; sigcritical(1); *state->control = CS_MNT_LOCK; if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0)) < 0) { if (stat(path, &st)) { messagef((state->id, NiL, -1, "open: %s: %s: creat error", state->path, path)); goto unblock; } if ((CSTIME() - (unsigned long)st.st_ctime) < 2 * 60) { errno = EEXIST; messagef((state->id, NiL, -1, "open: %s: %s: another server won the race", state->path, path)); goto unblock; } if (remove(path)) { messagef((state->id, NiL, -1, "open: %s: %s: remove error", state->path, path)); goto unblock; } if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0)) < 0) { messagef((state->id, NiL, -1, "open: %s: %s: creat error", state->path, path)); goto unblock; } } close(fd); if (!port && (n = strtol(serv, &t, 0)) && t > serv && !*t) port = n; else if (geteuid()) port = CS_NORMAL; else port = CS_RESERVED; if ((fd = csbind(state, type, 0L, port, 0L)) >= 0) { *state->control = CS_MNT_STREAM; remove(path); if (pathsetlink(cspath(state, fd, 0), path)) { messagef((state->id, NiL, -1, "open: %s: %s: link error", cspath(state, fd, 0), path)); close(fd); fd = -1; } } unblock: *state->control = CS_MNT_LOCK; remove(path); sigcritical(0); *state->control = CS_MNT_STREAM; if (fd < 0) return -1; } else if (fd < 0 && ((op & CS_OPEN_TEST) || initiate(state, user, opath, tmp, serv) || (fd = reopen(state, path)) < 0)) { messagef((state->id, NiL, -1, "open: %s: %s: reopen/initiate error", state->path, path)); return -1; } else if (!(op & CS_OPEN_AGENT)) { *state->control = CS_MNT_AUTH; n = csauth(state, fd, path, arg); *state->control = CS_MNT_STREAM; if (n) { close(fd); messagef((state->id, NiL, -1, "open: %s: %s: authentication error", state->path, path)); return -1; } } } /* * fd is open at this point * make sure its not a bogus mount */ if (mode != (S_IRWXU|S_IRWXG|S_IRWXO)) { *state->control = 0; n = stat(path, &st); *state->control = CS_MNT_STREAM; if (n) { messagef((state->id, NiL, -1, "open: %s: %s: stat error", state->path, path)); close(fd); return -1; } if (uid >= 0 && st.st_uid != uid || gid >= 0 && st.st_gid != gid) { close(fd); errno = EPERM; messagef((state->id, NiL, -1, "open: %s: %s: uid/gid error", state->path, path)); return -1; } } return fd; bad: if (nfd >= 0) close(nfd); return -1; }
/* * Temporarily changes to the given uid. If the effective user * id is not root, this does nothing. This call cannot be nested. */ void temporarily_use_uid(struct passwd *pw) { /* Save the current euid, and egroups. */ #ifdef SAVED_IDS_WORK_WITH_SETEUID saved_euid = geteuid(); saved_egid = getegid(); debug("temporarily_use_uid: %u/%u (e=%u/%u)", (u_int)pw->pw_uid, (u_int)pw->pw_gid, (u_int)saved_euid, (u_int)saved_egid); #ifndef HAVE_CYGWIN if (saved_euid != 0) { privileged = 0; return; } #endif #else if (geteuid() != 0) { privileged = 0; return; } #endif /* SAVED_IDS_WORK_WITH_SETEUID */ privileged = 1; temporarily_use_uid_effective = 1; saved_egroupslen = getgroups(0, NULL); if (saved_egroupslen < 0) fatal("getgroups: %.100s", strerror(errno)); if (saved_egroupslen > 0) { saved_egroups = xreallocarray(saved_egroups, saved_egroupslen, sizeof(gid_t)); if (getgroups(saved_egroupslen, saved_egroups) < 0) fatal("getgroups: %.100s", strerror(errno)); } else { /* saved_egroupslen == 0 */ free(saved_egroups); } /* set and save the user's groups */ if (user_groupslen == -1) { if (initgroups(pw->pw_name, pw->pw_gid) < 0) fatal("initgroups: %s: %.100s", pw->pw_name, strerror(errno)); user_groupslen = getgroups(0, NULL); if (user_groupslen < 0) fatal("getgroups: %.100s", strerror(errno)); if (user_groupslen > 0) { user_groups = xreallocarray(user_groups, user_groupslen, sizeof(gid_t)); if (getgroups(user_groupslen, user_groups) < 0) fatal("getgroups: %.100s", strerror(errno)); } else { /* user_groupslen == 0 */ free(user_groups); } } /* Set the effective uid to the given (unprivileged) uid. */ if (setgroups(user_groupslen, user_groups) < 0) fatal("setgroups: %.100s", strerror(errno)); #ifndef SAVED_IDS_WORK_WITH_SETEUID /* Propagate the privileged gid to all of our gids. */ if (setgid(getegid()) < 0) debug("setgid %u: %.100s", (u_int) getegid(), strerror(errno)); /* Propagate the privileged uid to all of our uids. */ if (setuid(geteuid()) < 0) debug("setuid %u: %.100s", (u_int) geteuid(), strerror(errno)); #endif /* SAVED_IDS_WORK_WITH_SETEUID */ if (setegid(pw->pw_gid) < 0) fatal("setegid %u: %.100s", (u_int)pw->pw_gid, strerror(errno)); if (seteuid(pw->pw_uid) == -1) fatal("seteuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno)); }
static int check_account(const char *service, const char *tty , const char *user) { int from=0,to=0,fd=-1; char *buffer=NULL; int count=0; TIME here_and_now; int retval=PAM_SUCCESS; gid_t *grps; int no_grps; /* * first we get the current list of groups - the application * will have previously done an initgroups(), or equivalent. */ D(("counting supplementary groups")); no_grps = getgroups(0, NULL); /* find the current number of groups */ if (no_grps > 0) { grps = calloc( blk_size(no_grps) , sizeof(gid_t) ); D(("copying current list into grps [%d big]",blk_size(no_grps))); (void) getgroups(no_grps, grps); #ifdef DEBUG { int z; for (z=0; z<no_grps; ++z) { D(("gid[%d]=%d", z, grps[z])); } } #endif } else { D(("no supplementary groups known")); no_grps = 0; grps = NULL; } here_and_now = time_now(); /* find current time */ /* parse the rules in the configuration file */ do { int good=TRUE; /* here we get the service name field */ fd = read_field(fd,&buffer,&from,&to); if (!buffer || !buffer[0]) { /* empty line .. ? */ continue; } ++count; D(("working on rule #%d",count)); good = logic_field(service, buffer, count, is_same); D(("with service: %s", good ? "passes":"fails" )); /* here we get the terminal name field */ fd = read_field(fd,&buffer,&from,&to); if (!buffer || !buffer[0]) { _log_err(PAM_GROUP_CONF "; no tty entry #%d", count); continue; } good &= logic_field(tty, buffer, count, is_same); D(("with tty: %s", good ? "passes":"fails" )); /* here we get the username field */ fd = read_field(fd,&buffer,&from,&to); if (!buffer || !buffer[0]) { _log_err(PAM_GROUP_CONF "; no user entry #%d", count); continue; } good &= logic_field(user, buffer, count, is_same); D(("with user: %s", good ? "passes":"fails" )); /* here we get the time field */ fd = read_field(fd,&buffer,&from,&to); if (!buffer || !buffer[0]) { _log_err(PAM_GROUP_CONF "; no time entry #%d", count); continue; } good &= logic_field(&here_and_now, buffer, count, check_time); D(("with time: %s", good ? "passes":"fails" )); fd = read_field(fd,&buffer,&from,&to); if (!buffer || !buffer[0]) { _log_err(PAM_GROUP_CONF "; no listed groups for rule #%d" , count); continue; } /* * so we have a list of groups, we need to turn it into * something to send to setgroups(2) */ if (good) { D(("adding %s to gid list", buffer)); good = mkgrplist(buffer, &grps, no_grps); if (good < 0) { no_grps = 0; } else { no_grps = good; } } /* check the line is terminated correctly */ fd = read_field(fd,&buffer,&from,&to); if (buffer && buffer[0]) { _log_err(PAM_GROUP_CONF "; poorly terminated rule #%d", count); } if (good > 0) { D(("rule #%d passed, added %d groups", count, good)); } else if (good < 0) { retval = PAM_BUF_ERR; } else { D(("rule #%d failed", count)); } } while (buffer); /* now set the groups for the user */ if (no_grps > 0) { int err; D(("trying to set %d groups", no_grps)); #ifdef DEBUG for (err=0; err<no_grps; ++err) { D(("gid[%d]=%d", err, grps[err])); } #endif if ((err = setgroups(no_grps, grps))) { D(("but couldn't set groups %d", err)); _log_err("unable to set the group membership for user (err=%d)" , err); retval = PAM_CRED_ERR; } } if (grps) { /* tidy up */ memset(grps, 0, sizeof(gid_t) * blk_size(no_grps)); _pam_drop(grps); no_grps = 0; } return retval; }
static int #if defined(USE_PAM) || defined(_AIX) isNoPassAllowed( const char *un ) { struct passwd *pw = 0; # ifdef HAVE_GETSPNAM /* (sic!) - not USESHADOW */ struct spwd *spw; # endif #else isNoPassAllowed( const char *un, struct passwd *pw ) { #endif struct group *gr; char **fp; int hg; if (!*un) return 0; if (cursource != PWSRC_MANUAL) return 1; for (hg = 0, fp = td->noPassUsers; *fp; fp++) if (**fp == '@') hg = 1; else if (!strcmp( un, *fp )) return 1; else if (!strcmp( "*", *fp )) { #if defined(USE_PAM) || defined(_AIX) if (!(pw = getpwnam( un ))) return 0; if (pw->pw_passwd[0] == '!' || pw->pw_passwd[0] == '*') continue; # ifdef HAVE_GETSPNAM /* (sic!) - not USESHADOW */ if ((spw = getspnam( un )) && (spw->sp_pwdp[0] == '!' || spw->sp_pwdp[0] == '*')) continue; # endif #endif if (pw->pw_uid) return 1; } #if defined(USE_PAM) || defined(_AIX) if (hg && (pw || (pw = getpwnam( un )))) { #else if (hg) { #endif for (setgrent(); (gr = getgrent()); ) for (fp = td->noPassUsers; *fp; fp++) if (**fp == '@' && !strcmp( gr->gr_name, *fp + 1 )) { if (pw->pw_gid == gr->gr_gid) { endgrent(); return 1; } for (; *gr->gr_mem; gr->gr_mem++) if (!strcmp( un, *gr->gr_mem )) { endgrent(); return 1; } } endgrent(); } return 0; } #if !defined(USE_PAM) && !defined(_AIX) && defined(HAVE_SETUSERCONTEXT) # define LC_RET0 do { login_close(lc); return 0; } while(0) #else # define LC_RET0 return 0 #endif int verify( GConvFunc gconv, int rootok ) { #ifdef USE_PAM const char *psrv; struct pam_data pdata; int pretc, pnopass; char psrvb[64]; #elif defined(_AIX) char *msg, *curret; int i, reenter; #else struct stat st; const char *nolg; char *buf; int fd; # ifdef HAVE_GETUSERSHELL char *s; # endif # if defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || defined(USESHADOW) int tim, expir, warntime, quietlog; # endif #endif debug( "verify ...\n" ); #ifdef USE_PAM pnopass = FALSE; if (!strcmp( curtype, "classic" )) { if (!gconv( GCONV_USER, 0 )) return 0; if (isNoPassAllowed( curuser )) { gconv( GCONV_PASS_ND, 0 ); if (!*curpass) { pnopass = TRUE; sprintf( psrvb, "%.31s-np", PAMService ); psrv = psrvb; } else psrv = PAMService; } else psrv = PAMService; pdata.usecur = TRUE; } else { sprintf( psrvb, "%.31s-%.31s", PAMService, curtype ); psrv = psrvb; pdata.usecur = FALSE; } pdata.gconv = gconv; if (!doPAMAuth( psrv, &pdata )) return 0; #elif defined(_AIX) if ((td->displayType & d_location) == dForeign) { char *tmpch; strncpy( hostname, td->name, sizeof(hostname) - 1 ); hostname[sizeof(hostname)-1] = '\0'; if ((tmpch = strchr( hostname, ':' ))) *tmpch = '\0'; } else hostname[0] = '\0'; /* tty names should only be 15 characters long */ # if 0 for (i = 0; i < 15 && td->name[i]; i++) { if (td->name[i] == ':' || td->name[i] == '.') tty[i] = '_'; else tty[i] = td->name[i]; } tty[i] = '\0'; # else memcpy( tty, "/dev/xdm/", 9 ); for (i = 0; i < 6 && td->name[i]; i++) { if (td->name[i] == ':' || td->name[i] == '.') tty[9 + i] = '_'; else tty[9 + i] = td->name[i]; } tty[9 + i] = '\0'; # endif if (!strcmp( curtype, "classic" )) { if (!gconv( GCONV_USER, 0 )) return 0; if (isNoPassAllowed( curuser )) { gconv( GCONV_PASS_ND, 0 ); if (!*curpass) { debug( "accepting despite empty password\n" ); goto done; } } else if (!gconv( GCONV_PASS, 0 )) return 0; enduserdb(); msg = NULL; if ((i = authenticate( curuser, curpass, &reenter, &msg ))) { debug( "authenticate() failed: %s\n", msg ); if (msg) free( msg ); loginfailed( curuser, hostname, tty ); if (i == ENOENT || i == ESAD) V_RET_AUTH; else V_RET_FAIL( 0 ); } if (reenter) { logError( "authenticate() requests more data: %s\n", msg ); free( msg ); V_RET_FAIL( 0 ); } } else if (!strcmp( curtype, "generic" )) { if (!gconv( GCONV_USER, 0 )) return 0; for (curret = 0;;) { msg = NULL; if ((i = authenticate( curuser, curret, &reenter, &msg ))) { debug( "authenticate() failed: %s\n", msg ); if (msg) free( msg ); loginfailed( curuser, hostname, tty ); if (i == ENOENT || i == ESAD) V_RET_AUTH; else V_RET_FAIL( 0 ); } if (curret) free( curret ); if (!reenter) break; if (!(curret = gconv( GCONV_HIDDEN, msg ))) return 0; free( msg ); } } else { logError( "Unsupported authentication type %\"s requested\n", curtype ); V_RET_FAIL( 0 ); } if (msg) { displayStr( V_MSG_INFO, msg ); free( msg ); } done: #else if (strcmp( curtype, "classic" )) { logError( "Unsupported authentication type %\"s requested\n", curtype ); V_RET_FAIL( 0 ); } if (!gconv( GCONV_USER, 0 )) return 0; if (!(p = getpwnam( curuser ))) { debug( "getpwnam() failed.\n" ); gconv( GCONV_PASS, 0 ); V_RET_AUTH; } if (p->pw_passwd[0] == '!' || p->pw_passwd[0] == '*') { debug( "account is locked\n" ); gconv( GCONV_PASS, 0 ); V_RET_AUTH; } # ifdef USESHADOW if ((sp = getspnam( curuser ))) { p->pw_passwd = sp->sp_pwdp; if (p->pw_passwd[0] == '!' || p->pw_passwd[0] == '*') { debug( "account is locked\n" ); gconv( GCONV_PASS, 0 ); V_RET_AUTH; } } else debug( "getspnam() failed: %m. Are you root?\n" ); # endif if (!*p->pw_passwd) { if (!td->allowNullPasswd) { debug( "denying user with empty password\n" ); gconv( GCONV_PASS, 0 ); V_RET_AUTH; } goto nplogin; } if (isNoPassAllowed( curuser, p )) { nplogin: gconv( GCONV_PASS_ND, 0 ); if (!*curpass) { debug( "accepting password-less login\n" ); goto done; } } else if (!gconv( GCONV_PASS, 0 )) return 0; # ifdef KERBEROS if (p->pw_uid) { int ret; char realm[REALM_SZ]; if (krb_get_lrealm( realm, 1 )) { logError( "Cannot get KerberosIV realm.\n" ); V_RET_FAIL( 0 ); } sprintf( krbtkfile, "%s.%.*s", TKT_ROOT, MAXPATHLEN - strlen( TKT_ROOT ) - 2, td->name ); krb_set_tkt_string( krbtkfile ); unlink( krbtkfile ); ret = krb_verify_user( curuser, "", realm, curpass, 1, "rcmd" ); if (ret == KSUCCESS) { chown( krbtkfile, p->pw_uid, p->pw_gid ); debug( "KerberosIV verify succeeded\n" ); goto done; } else if (ret != KDC_PR_UNKNOWN && ret != SKDC_CANT) { logError( "KerberosIV verification failure %\"s for %s\n", krb_get_err_text( ret ), curuser ); krbtkfile[0] = '\0'; V_RET_FAIL( 0 ); } debug( "KerberosIV verify failed: %s\n", krb_get_err_text( ret ) ); } krbtkfile[0] = '\0'; # endif /* KERBEROS */ # if defined(ultrix) || defined(__ultrix__) if (authenticate_user( p, curpass, NULL ) < 0) # elif defined(HAVE_PW_ENCRYPT) if (strcmp( pw_encrypt( curpass, p->pw_passwd ), p->pw_passwd )) # elif defined(HAVE_CRYPT) if (strcmp( crypt( curpass, p->pw_passwd ), p->pw_passwd )) # else if (strcmp( curpass, p->pw_passwd )) # endif { debug( "password verify failed\n" ); V_RET_AUTH; } done: #endif /* !defined(USE_PAM) && !defined(_AIX) */ debug( "restrict %s ...\n", curuser ); #if defined(USE_PAM) || defined(_AIX) if (!(p = getpwnam( curuser ))) { logError( "getpwnam(%s) failed.\n", curuser ); V_RET_FAIL( 0 ); } #endif if (!p->pw_uid) { if (!rootok && !td->allowRootLogin) V_RET_FAIL( "Root logins are not allowed" ); return 1; /* don't deny root to log in */ } #ifdef USE_PAM debug( " pam_acct_mgmt() ...\n" ); pretc = pam_acct_mgmt( pamh, 0 ); reInitErrorLog(); debug( " pam_acct_mgmt() returned: %s\n", pam_strerror( pamh, pretc ) ); if (pretc == PAM_NEW_AUTHTOK_REQD) { pdata.usecur = FALSE; pdata.gconv = conv_interact; /* pam will have output a message already, so no prepareErrorGreet() */ if (gconv != conv_interact || pnopass) { pam_end( pamh, PAM_SUCCESS ); pamh = 0; gSendInt( V_CHTOK_AUTH ); /* this cannot auth the wrong user, as only classic auths get here */ while (!doPAMAuth( PAMService, &pdata )) if (pdata.abort) return 0; gSendInt( V_PRE_OK ); } else gSendInt( V_CHTOK ); for (;;) { debug( " pam_chauthtok() ...\n" ); pretc = pam_chauthtok( pamh, PAM_CHANGE_EXPIRED_AUTHTOK ); reInitErrorLog(); debug( " pam_chauthtok() returned: %s\n", pam_strerror( pamh, pretc ) ); if (pdata.abort) { pam_end( pamh, PAM_SUCCESS ); pamh = 0; return 0; } if (pretc == PAM_SUCCESS) break; /* effectively there is only PAM_AUTHTOK_ERR */ gSendInt( V_FAIL ); } if (curpass) free( curpass ); curpass = newpass; newpass = 0; } else if (pretc != PAM_SUCCESS) { pam_end( pamh, pretc ); pamh = 0; V_RET_AUTH; } #elif defined(_AIX) /* USE_PAM */ msg = NULL; if (loginrestrictions( curuser, ((td->displayType & d_location) == dForeign) ? S_RLOGIN : S_LOGIN, tty, &msg ) == -1) { debug( "loginrestrictions() - %s\n", msg ? msg : "error" ); loginfailed( curuser, hostname, tty ); prepareErrorGreet(); if (msg) { displayStr( V_MSG_ERR, msg ); free( msg ); } gSendInt( V_AUTH ); return 0; } if (msg) free( (void *)msg ); #endif /* USE_PAM || _AIX */ #ifndef _AIX # ifdef HAVE_SETUSERCONTEXT # ifdef HAVE_LOGIN_GETCLASS lc = login_getclass( p->pw_class ); # else lc = login_getpwclass( p ); # endif if (!lc) V_RET_FAIL( 0 ); p->pw_shell = login_getcapstr( lc, "shell", p->pw_shell, p->pw_shell ); # endif # ifndef USE_PAM /* restrict_expired */ # if defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || defined(USESHADOW) # if !defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || (!defined(HAVE_SETUSERCONTEXT) && defined(USESHADOW)) if (sp) # endif { # define DEFAULT_WARN (2L * 7L) /* Two weeks */ tim = time( NULL ) / 86400L; # ifdef HAVE_SETUSERCONTEXT quietlog = login_getcapbool( lc, "hushlogin", 0 ); warntime = login_getcaptime( lc, "warnexpire", DEFAULT_WARN * 86400L, DEFAULT_WARN * 86400L ) / 86400L; # else quietlog = 0; # ifdef USESHADOW warntime = sp->sp_warn != -1 ? sp->sp_warn : DEFAULT_WARN; # else warntime = DEFAULT_WARN; # endif # endif # ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE if (p->pw_expire) { expir = p->pw_expire / 86400L; # else if (sp->sp_expire != -1) { expir = sp->sp_expire; # endif if (tim > expir) { displayStr( V_MSG_ERR, "Your account has expired;" " please contact your system administrator" ); gSendInt( V_FAIL ); LC_RET0; } else if (tim > (expir - warntime) && !quietlog) { displayMsg( V_MSG_INFO, "Warning: your account will expire in %d day(s)", expir - tim ); } } # ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE if (p->pw_change) { expir = p->pw_change / 86400L; # else if (!sp->sp_lstchg) { displayStr( V_MSG_ERR, "You are required to change your password immediately" " (root enforced)" ); /* XXX todo password change */ gSendInt( V_FAIL ); LC_RET0; } else if (sp->sp_max != -1) { expir = sp->sp_lstchg + sp->sp_max; if (sp->sp_inact != -1 && tim > expir + sp->sp_inact) { displayStr( V_MSG_ERR, "Your account has expired;" " please contact your system administrator" ); gSendInt( V_FAIL ); LC_RET0; } # endif if (tim > expir) { displayStr( V_MSG_ERR, "You are required to change your password immediately" " (password aged)" ); /* XXX todo password change */ gSendInt( V_FAIL ); LC_RET0; } else if (tim > (expir - warntime) && !quietlog) { displayMsg( V_MSG_INFO, "Warning: your password will expire in %d day(s)", expir - tim ); } } } # endif /* HAVE_STRUCT_PASSWD_PW_EXPIRE || USESHADOW */ /* restrict_nologin */ # ifndef _PATH_NOLOGIN # define _PATH_NOLOGIN "/etc/nologin" # endif if (( # ifdef HAVE_SETUSERCONTEXT /* Do we ignore a nologin file? */ !login_getcapbool( lc, "ignorenologin", 0 )) && (!stat( (nolg = login_getcapstr( lc, "nologin", "", NULL )), &st ) || # endif !stat( (nolg = _PATH_NOLOGIN), &st ))) { if (st.st_size && (fd = open( nolg, O_RDONLY )) >= 0) { if ((buf = Malloc( st.st_size + 1 ))) { if (read( fd, buf, st.st_size ) == st.st_size) { close( fd ); buf[st.st_size] = 0; displayStr( V_MSG_ERR, buf ); free( buf ); gSendInt( V_FAIL ); LC_RET0; } free( buf ); } close( fd ); } displayStr( V_MSG_ERR, "Logins are not allowed at the moment.\nTry again later" ); gSendInt( V_FAIL ); LC_RET0; } /* restrict_time */ # if defined(HAVE_SETUSERCONTEXT) && defined(HAVE_AUTH_TIMEOK) if (!auth_timeok( lc, time( NULL ) )) { displayStr( V_MSG_ERR, "You are not allowed to login at the moment" ); gSendInt( V_FAIL ); LC_RET0; } # endif # ifdef HAVE_GETUSERSHELL for (;;) { if (!(s = getusershell())) { debug( "shell not in /etc/shells\n" ); endusershell(); V_RET_FAIL( "Your login shell is not listed in /etc/shells" ); } if (!strcmp( s, p->pw_shell )) { endusershell(); break; } } # endif # endif /* !USE_PAM */ /* restrict_nohome */ # ifdef HAVE_SETUSERCONTEXT if (login_getcapbool( lc, "requirehome", 0 )) { struct stat st; if (!*p->pw_dir || stat( p->pw_dir, &st ) || st.st_uid != p->pw_uid) { displayStr( V_MSG_ERR, "Home folder not available" ); gSendInt( V_FAIL ); LC_RET0; } } # endif #endif /* !_AIX */ return 1; } static const char *envvars[] = { "TZ", /* SYSV and SVR4, but never hurts */ #ifdef _AIX "AUTHSTATE", /* for kerberos */ #endif NULL }; #if defined(USE_PAM) && defined(HAVE_INITGROUPS) static int num_saved_gids; static gid_t *saved_gids; static int saveGids( void ) { num_saved_gids = getgroups( 0, 0 ); if (!(saved_gids = Malloc( sizeof(gid_t) * num_saved_gids ))) return 0; if (getgroups( num_saved_gids, saved_gids ) < 0) { logError( "saving groups failed: %m\n" ); return 0; } return 1; } static int restoreGids( void ) { if (setgroups( num_saved_gids, saved_gids ) < 0) { logError( "restoring groups failed: %m\n" ); return 0; } if (setgid( p->pw_gid ) < 0) { logError( "restoring gid failed: %m\n" ); return 0; } return 1; } #endif /* USE_PAM && HAVE_INITGROUPS */ static int resetGids( void ) { #ifdef HAVE_INITGROUPS if (setgroups( 0, &p->pw_gid /* anything */ ) < 0) { logError( "restoring groups failed: %m\n" ); return 0; } #endif if (setgid( 0 ) < 0) { logError( "restoring gid failed: %m\n" ); return 0; } return 1; } static int setGid( const char *name, int gid ) { if (setgid( gid ) < 0) { logError( "setgid(%d) (user %s) failed: %m\n", gid, name ); return 0; } #ifdef HAVE_INITGROUPS if (initgroups( name, gid ) < 0) { logError( "initgroups for %s failed: %m\n", name ); setgid( 0 ); return 0; } #endif /* QNX4 doesn't support multi-groups, no initgroups() */ return 1; } static int setUid( const char *name, int uid ) { if (setuid( uid ) < 0) { logError( "setuid(%d) (user %s) failed: %m\n", uid, name ); return 0; } return 1; } static int setUser( const char *name, int uid, int gid ) { if (setGid( name, gid )) { if (setUid( name, uid )) return 1; resetGids(); } return 0; } #if defined(SECURE_RPC) || defined(K5AUTH) static void nukeAuth( int len, const char *name ) { int i; for (i = 0; i < td->authNum; i++) if (td->authorizations[i]->name_length == len && !memcmp( td->authorizations[i]->name, name, len )) { memcpy( &td->authorizations[i], &td->authorizations[i+1], sizeof(td->authorizations[i]) * (--td->authNum - i) ); break; } } #endif static void mergeSessionArgs( int cansave ) { char *mfname; const char *fname; int i, needsave; mfname = 0; fname = ".dmrc"; if ((!curdmrc || newdmrc) && *dmrcDir) if (strApp( &mfname, dmrcDir, "/", curuser, fname, (char *)0 )) fname = mfname; needsave = 0; if (!curdmrc) { curdmrc = iniLoad( fname ); if (!curdmrc) { strDup( &curdmrc, "[Desktop]\nSession=default\n" ); needsave = 1; } } if (newdmrc) { curdmrc = iniMerge( curdmrc, newdmrc ); needsave = 1; } if (needsave && cansave) if (!iniSave( curdmrc, fname ) && errno == ENOENT && mfname) { for (i = 0; mfname[i]; i++) if (mfname[i] == '/') { mfname[i] = 0; mkdir( mfname, 0755 ); mfname[i] = '/'; } iniSave( curdmrc, mfname ); } if (mfname) free( mfname ); } static int createClientLog( const char *log ) { char randstr[32], *randstrp = 0, *lname; int lfd; for (;;) { struct expando macros[] = { { 'd', 0, td->name }, { 'u', 0, curuser }, { 'r', 0, randstrp }, { 0, 0, 0 } }; if (!(lname = expandMacros( log, macros ))) exit( 1 ); unlink( lname ); if ((lfd = open( lname, O_WRONLY|O_CREAT|O_EXCL, 0600 )) >= 0) { dup2( lfd, 1 ); dup2( lfd, 2 ); close( lfd ); free( lname ); return TRUE; } if (errno != EEXIST || !macros[2].uses) { free( lname ); return FALSE; } logInfo( "Session log file %s not usable, trying another one.\n", lname ); free( lname ); sprintf( randstr, "%d", secureRandom() ); randstrp = randstr; } }
//**************************************************************************** // Attach to an environment - switches are: // x = xecute command Opt // e = environment (UCI) Opt int INIT_Run( char *file, // database file char *env, // environment (UCI) char *cmd) // command { int i; // an int int dbfd = 0; // database file descriptor int ret = 0; // return value int env_num = 1; // startup environemnt number var_u tmp; // temp descriptor uci_tab *uci_ptr; // for uci search int pid; // job number int ssp = 0; // string stack ptr int asp = 0; // address stack ptr mvar *var; // a variable pointer cstring *cptr; // a handy pointer cstring *sptr; // cstring ptr short s; // for functions short start_type = TYPE_RUN; // how we started gid_t gidset[MAX_GROUPS]; // for getgroups() struct termios tty_settings; // man 4 termios start: #if defined(__APPLE__) || defined(__FreeBSD__) srandomdev(); // randomize #endif partab.jobtab = (jobtab *) NULL; // clear jobtab pointer dbfd = open(file, O_RDONLY); // open the database for read if (dbfd < 0) return (errno); // if that failed // i = fcntl(dbfd, F_NOCACHE, 1); if (start_type == TYPE_RUN) // if not from JOB { i = UTIL_Share(file); // attach to shared mem if (i != 0) return(i); // quit on error } if (env != NULL) // passed in uci ? { env_num = 0; // clear uci number uci_ptr = &systab->vol[0]->vollab->uci[0]; // get ptr to uci table //tmp.var_qu = 0; // zero entire name X_Clear(tmp.var_xu); // zero entire name for (i = 0; i < MAX_NAME_BYTES; i++) // copy in name { if (env[i] == '\0') break; // done at null tmp.var_cu[i] = env[i]; // copy character } for (i = 0; i < UCIS; i++) // scan all ucis //if (uci_ptr[i].name.var_qu == tmp.var_qu) // if we have a match if (X_EQ(uci_ptr[i].name.var_xu, tmp.var_xu)) // if we have a match { env_num = i + 1; // save it break; // and exit loop } if (env_num == 0) { ret = ENOENT; // complain on fail goto exit; // and exit } } pid = (int) getpid(); // get process id for (i = 0; i < systab->maxjob; i++) // scan the slots { ret = systab->jobtab[i].pid; // get pid if ((ret != pid) && (ret)) // if one there and not us { if (kill(ret, 0)) // check the job { if (errno == ESRCH) // doesn't exist { ret = CleanJob(i + 1); // zot if not there if (ret == 0) // success ? break; // have at least one } } } else // it's free or ours { break; // quit } } ret = SemOp(SEM_SYS, -systab->maxjob); // lock systab if (ret < 0) goto exit; // give up on error for (i = 0; i < systab->maxjob; i++) // look for a free slot { if (((systab->jobtab[i].pid == 0) && // this one ? (start_type == TYPE_RUN)) || ((systab->jobtab[i].pid == pid) && // or already done (JOB) (start_type == TYPE_JOB))) { bzero(&systab->jobtab[i], sizeof(jobtab)); // yes - zot the lot partab.jobtab = &systab->jobtab[i]; // and save our jobtab address partab.jobtab->pid = pid; // copy in our pid break; // end loop } } ret = SemOp(SEM_SYS, systab->maxjob); // unlock systab if (partab.jobtab == NULL) // if that failed { ret = ENOMEM; // error message goto exit; // and exit } partab.jobtab->user = (short) getuid(); // get user number if ((partab.jobtab->user == systab->start_user) || // if he started it (partab.jobtab->user == 0)) // or is root { partab.jobtab->priv = 1; // say yes } else { if (systab->maxjob == 1) // if single job { ret = ENOMEM; // error message partab.jobtab = NULL; // clear this goto exit; // and exit } i = getgroups(MAX_GROUPS, gidset); // get groups if (i < 0) // if an error { ret = errno; // get the error goto exit; // and exit } while (i > 0) // for each group { if (gidset[i - 1] == PRVGRP) // if it's "wheel" or "admin" { partab.jobtab->priv = 1; // say yes break; // and exit } i--; // decrement i } } partab.jobtab->precision = systab->precision; // decimal precision partab.jobtab->uci = env_num; // uci number partab.jobtab->vol = 1; // volset partab.jobtab->luci = env_num; // uci number partab.jobtab->lvol = 1; // volset partab.jobtab->ruci = env_num; // uci number partab.jobtab->rvol = 1; // volset partab.jobtab->start_len = Vhorolog(partab.jobtab->start_dh); // store start date/time partab.jobtab->dostk[0].type = TYPE_RUN; // ensure slot 0 has a value failed_tty = tcgetattr ( 0, &tty_settings ); i = SQ_Init(); // have seqio setup chan 0 systab->last_blk_used[partab.jobtab - systab->jobtab] = 0; // clear last global block partab.debug = 0; // clear debug flag partab.sstk_start = &sstk[0]; // address of sstk partab.sstk_last = &sstk[MAX_SSTK]; // and the last char partab.varlst = NULL; // used by compiler partab.vol_fds[0] = dbfd; // make sure fd is right ST_Init(); // initialize symbol table if ((systab->vol[0]->vollab->journal_available) && (systab->vol[0]->vollab->journal_requested)) // if journaling { partab.jnl_fds[0] = open(systab->vol[0]->vollab->journal_file, O_RDWR); if (partab.jnl_fds[0] < 0) { fprintf(stderr, "Failed to open journal file %s\nerrno = %d\n", systab->vol[0]->vollab->journal_file, errno); ret = -1; if (cmd != NULL) goto exit; } else { // i = fcntl(dbfd, F_NOCACHE, 1); } } if (cmd != NULL) // command specified ? { source_ptr = (u_char *) cmd; // where the code is cptr = (cstring *) &sstk[ssp]; // where the compiled goes comp_ptr = cptr->buf; // the data bit parse(); *comp_ptr++ = CMQUIT; // add the quit *comp_ptr++ = ENDLIN; // JIC *comp_ptr++ = ENDLIN; // JIC i = &comp_ptr[0] - &cptr->buf[0]; // get number of bytes cptr->len = i; // save for ron ssp = ssp + i + sizeof(short) + 1; // point past it mumpspc = &cptr->buf[0]; // setup the mumpspc partab.jobtab->dostk[0].routine = (u_char *) cmd; // where we started partab.jobtab->dostk[0].pc = mumpspc; // where we started partab.jobtab->dostk[0].symbol = NULL; // nowhere partab.jobtab->dostk[0].newtab = NULL; // nowhere partab.jobtab->dostk[0].endlin = mumpspc + i - 4; // ENDLIN //partab.jobtab->dostk[0].rounam.var_qu = 0;// zero the routine name X_Clear(partab.jobtab->dostk[0].rounam.var_xu); // zero the routine name partab.jobtab->dostk[0].vol = partab.jobtab->vol; // current volume partab.jobtab->dostk[0].uci = partab.jobtab->uci; // current uci partab.jobtab->dostk[0].line_num = 0; // no line number partab.jobtab->dostk[0].type = start_type; // how we started partab.jobtab->dostk[0].estack = 0; // estack offset partab.jobtab->dostk[0].level = 0; // where we started partab.jobtab->dostk[0].flags = 0; // no flags partab.jobtab->dostk[0].savasp = asp; // address stack ptr partab.jobtab->dostk[0].savssp = ssp; // string stack partab.jobtab->dostk[0].asp = asp; // address stack ptr partab.jobtab->dostk[0].ssp = ssp; // string stack partab.jobtab->attention = 0; partab.jobtab->trap = 0; partab.jobtab->async_error = 0; isp = 0; // clear indirect pointer s = run(asp, ssp); if (s == OPHALT) goto exit; // look after halt if (s == JOBIT) goto jobit; // look after JOB partab.jobtab->io = 0; // force chan 0 var = (mvar *) &sstk[0]; // space to setup a var X_set("$ECODE\0\0", &var->name.var_cu[0], 8); var->volset = 0; var->uci = UCI_IS_LOCALVAR; var->slen = 0; // setup for $EC cptr = (cstring *) &sstk[sizeof(mvar)]; // for result bcopy("$ECODE=", cptr->buf, 7); s = ST_Get(var, &cptr->buf[7]); if (s > 1) // ignore if nothing there { cptr->len = s + 7; s = SQ_WriteFormat(SQ_LF); // new line s = SQ_Write(cptr); // write the prompt s = SQ_WriteFormat(SQ_LF); // new line cptr = (cstring *) (((u_char *) cptr) + 8); if (cptr->buf[0] != 'U') { cptr->len = 4; // max error size cptr->len = Xcall_errmsg((char *) cptr->buf, cptr, cptr); // cvt to str s = SQ_Write(cptr); // write the error s = SQ_WriteFormat(SQ_LF); // new line } ret = ESRCH; // set an error for exit } goto exit; // and halt } while (TRUE) // forever { sptr = (cstring *) &sstk[0]; // front of string stack asp = 0; // zot address stack ssp = 0; // and the string stack bcopy("M> ", sptr->buf, 3); // copy in the prompt sptr->buf[3] = '\0'; // null terminate sptr->len = 3; // and the length partab.jobtab->io = 0; // force chan 0 if (partab.jobtab->seqio[0].dx) // if not at right margin { s = SQ_WriteFormat(SQ_LF); // new line if (s < 0) ser(s); // check for error } s = SQ_Write(sptr); // write the prompt if (s < 0) ser(s); // check for error s = SQ_Read(sptr->buf, -1, -1); // get a string i = attention(); // check signals if (i == OPHALT) break; // exit on halt if (i == -(ERRZ51+ERRMLAST)) // control c controlc(); // say if (s < 0) { ser(s); // complain on error s = 0; } sptr->len = s; // save the length if (s == 0) continue; // ignore null astk[asp++] = (u_char *) sptr; // save address of string ssp = ssp + s + sizeof(short) + 1; // point past it s = SQ_WriteFormat(SQ_LF); // new line if (s < 0) ser(s); // check for error source_ptr = sptr->buf; // where the code is cptr = (cstring *) &sstk[ssp]; // where the compiled goes comp_ptr = cptr->buf; // the data bit parse(); *comp_ptr++ = CMQUIT; // add the quit *comp_ptr++ = ENDLIN; // JIC *comp_ptr++ = ENDLIN; // JIC i = &comp_ptr[0] - &cptr->buf[0]; // get number of bytes cptr->len = i; // save for ron ssp = ssp + i + sizeof(short) + 1; // point past it mumpspc = &cptr->buf[0]; // setup the mumpspc partab.jobtab->dostk[0].routine = sptr->buf; // where we started partab.jobtab->dostk[0].pc = mumpspc; // where we started partab.jobtab->dostk[0].symbol = NULL; // nowhere partab.jobtab->dostk[0].newtab = NULL; // nowhere partab.jobtab->dostk[0].endlin = mumpspc + i - 4; // ENDLIN //partab.jobtab->dostk[0].rounam.var_qu = 0;// zero the routine name X_Clear(partab.jobtab->dostk[0].rounam.var_xu);// zero the routine name partab.jobtab->dostk[0].vol = partab.jobtab->vol; // current volume partab.jobtab->dostk[0].uci = partab.jobtab->uci; // current uci partab.jobtab->dostk[0].line_num = 0; // no line number partab.jobtab->dostk[0].type = TYPE_RUN; // how we started partab.jobtab->dostk[0].estack = 0; // estack offset partab.jobtab->dostk[0].level = 0; // where we started partab.jobtab->dostk[0].flags = 0; // no flags partab.jobtab->dostk[0].savasp = asp; // address stack ptr partab.jobtab->dostk[0].savssp = ssp; // string stack partab.jobtab->dostk[0].asp = asp; // address stack ptr partab.jobtab->dostk[0].ssp = ssp; // string stack partab.jobtab->attention = 0; partab.jobtab->trap = 0; partab.jobtab->async_error = 0; isp = 0; // clear indirect pointer s = run(asp, ssp); if (s == JOBIT) goto jobit; // look after JOB if (s == OPHALT) break; // exit on halt partab.jobtab->io = 0; // force chan 0 if (s == -(ERRZ51+ERRMLAST)) // control c controlc(); // say else if (s < 0) ser(s); partab.jobtab->error_frame = 0; // and that one var = (mvar *) &sstk[0]; // space to setup a var X_set("$ECODE\0\0", &var->name.var_cu[0], 8); var->volset = 0; var->uci = UCI_IS_LOCALVAR; var->slen = 0; // setup for $EC cptr = (cstring *) &sstk[sizeof(mvar)]; // for result bcopy("$ECODE=", cptr->buf, 7); s = ST_Get(var, &cptr->buf[7]); if (s < 1) continue; // ignore if nothing there cptr->len = s + 7; s = SQ_Write(cptr); // write the prompt if (s < 0) ser(s); // check for error s = SQ_WriteFormat(SQ_LF); // new line if (s < 0) ser(s); // check for error s = ST_Kill(var); // dong $EC cptr = (cstring *) (((u_char *) cptr) + 8); if (cptr->buf[0] != 'U') { cptr->len = 4; // max error size cptr->len = Xcall_errmsg((char *) cptr->buf, cptr, cptr); // cvt to str s = SQ_Write(cptr); // write the error if (s < 0) ser(s); // check for error s = SQ_WriteFormat(SQ_LF); // new line } } // end command level loop exit: // general exit code if (partab.jobtab != NULL) // if we have a jobtab CleanJob(0); // remove all locks etc i = shmdt(systab); // detach the shared mem if (dbfd) i = close(dbfd); // close the database if (!failed_tty) // reset terminal if possible { failed_tty = tcsetattr ( 0, TCSANOW, &tty_settings ); } if (start_type == TYPE_JOB) return 0; // no error from JOB return ret; // and exit jobit: // code for JOB start_type = TYPE_JOB; // what we are doing env_num = partab.jobtab->ruci; // remember (current) rou uci cmd = (char *) &sstk[0]; // where the command is ssp = strlen((const char *) sstk); // protect original command isp = 0; // clear all these asp = 0; ret = 0; env = NULL; goto start; // go do it }
main (int argc, char **argv, char **envp) { register c; if (argc > 2) { outerr("Usage: deco [dirname]\n",0); exit (1); } outerr("Demos Commander, Copyright (C) 1989-1994 Serge Vakulenko\n",0); palette = dflt_palette; EnvInit (envp); uid = getuid (); gid = getgid (); # ifdef GROUPS gidnum = getgroups (sizeof(gidlist)/sizeof(gidlist[0]), (unsigned int *)gidlist); # endif ppid = getppid (); user = username (uid); group = groupname (gid); tty = ttyname (0); machine = getmachine (); #if 0 sigign(); #else signal(SIGTERM, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGINT, SIG_IGN); # ifdef SIGTSTP signal(SIGTSTP, SIG_IGN); # endif #endif init (); // inithome (); VClear (); /* init class dir */ if (argc > 1) // chdir (argv [1]); left = new dir(argv [1]); else left = new dir; right = new dir; left->d.basecol = 0; right->d.basecol = 40; /*-----------*/ initfile.read(); if (uid == 0) palette.dimfg = 6; v.VSetPalette (palette.fg, palette.bg, palette.revfg, palette.revbg, palette.boldfg, palette.boldbg, palette.boldrevfg, palette.boldrevbg, palette.dimfg, palette.dimbg, palette.dimrevfg, palette.dimrevbg); setdir (left, "."); setdir (right, "."); left->chdir(left->d.cwd); cur = left; draw.draw(cur, left, right); for (;;) { if (! cmdreg) draw.drawcursor(cur); // cmd.drawcmd(cur, &left, &right); VSync (); c = KeyGet (); if (! cmdreg) draw.undrawcursor(cur); switch (c) { case '+': /* select */ case '-': /* unselect */ if (! cpos && ! cmdreg && ! cur->d.status) { if (c == '+') tagall (); else untagall (); draw.draw(cur, left, right); continue; } default: // if (c>=' ' && c<='~' || c>=0300 && c<=0376) { // if (cpos || c!=' ') // cmd.inscmd(c); // continue; // } VBeep (); continue; // case cntrl ('V'): /* quote next char */ // cmd.inscmd(quote ()); // continue; // case cntrl ('J'): /* insert file name */ // if (! cmdreg && ! cur->status) // cmd.namecmd(cur); // continue; // case cntrl ('G'): // cmd.delcmd(); // continue; // case meta ('b'): /* backspace */ // if (cpos) { // cmd.leftcmd(); // cmd.delcmd(); // } // continue; case cntrl ('O'): /* set/unset command mode */ case cntrl ('P'): /* set/unset command mode */ switchcmdreg (); if (! cmdreg) visualwin = 1; draw.draw(cur, left, right); continue; case cntrl ('M'): /* return */ // if (command [0]) { // cmd.exec(cur, &left, &right, 1, 1); // draw.draw(cur, &left, &right); // continue; // } if (cmdreg) { cmdreg = 0; if (! visualwin) { visualwin = 1; setdir (cur==left ? right : left, NULL); setdir (cur, NULL); } draw.draw(cur, left, right); continue; } execute (); continue; case cntrl (']'): /* redraw screen */ VRedraw (); continue; // case cntrl ('B'): /* history */ // if (! visualwin) // VClearBox (1, 0, LINES-2, 80); // cmd.histmenu(cur, &left, &right); // draw.draw(cur, &left, &right); // continue; case meta ('A'): /* f1 */ genhelp (); draw.draw(cur, left, right); continue; case meta ('B'): /* f2 */ udm.menu(); draw.draw(cur, left, right); continue; case meta ('I'): /* f9 */ mymenu.runmenu (cur==left ? 'l' : 'r'); draw.draw(cur, left, right); continue; case meta ('J'): /* f0 */ case cntrl ('C'): /* quit */ quit (); continue; case cntrl ('U'): /* swap panels */ swappanels (); draw.draw(cur, left, right); continue; case cntrl ('F'): /* full screen */ fullscreen (); draw.draw(cur, left, right); continue; case cntrl ('^'): /* cd / */ directory (0, 'r'); if (! cur->d.status) draw.drawdir(cur, 1, left, right); continue; case cntrl ('\\'): /* cd $HOME */ directory (0, 'o'); if (! cur->d.status) draw.drawdir(cur, 1, left, right); continue; // case cntrl ('Y'): /* clear line */ // command [cpos = 0] = 0; // continue; // case cntrl ('X'): /* next history */ // cmd.nextcmd(); // continue; // case cntrl ('E'): /* prev history */ // cmd.prevcmd(); // continue; // case cntrl ('S'): /* char left */ // case cntrl ('A'): /* char left */ // cmd.leftcmd(); // continue; // case cntrl ('D'): /* char right */ // cmd.rightcmd(); // continue; case cntrl ('I'): /* tab */ if (cmdreg) {} // if (command [cpos]) // cmd.endcmd(); // else // cmd.homecmd(); else { switchpanels (); if (fullwin) { draw.drawbanners(); draw.drawdir(cur, 0, left, right); break; } } continue; case cntrl ('W'): /* double width */ if (! cmdreg) { setdwid (); draw.draw(cur, left, right); } continue; // case meta ('G'): /* f7 */ // makedir (); // draw.draw(cur, &left, &right); // continue; case meta ('h'): /* home */ case meta ('e'): /* end */ case meta ('u'): /* up */ case meta ('d'): /* down */ case meta ('l'): /* left */ case meta ('r'): /* right */ case meta ('n'): /* next page */ case meta ('p'): /* prev page */ case cntrl ('K'): /* find file */ case cntrl ('R'): /* reread catalog */ case cntrl ('T'): /* tag file */ case meta ('C'): /* f3 */ case meta ('D'): /* f4 */ case meta ('E'): /* f5 */ case meta ('F'): /* f6 */ case meta ('H'): /* f8 */ case cntrl ('L'): /* status */ if (cmdreg || cur->d.status) {} // docmdreg (c); else doscrreg (c); continue; } } }
void priv_init(void) { uid = cur_uid = getuid(); if (!uid) under_root_login =1; euid = cur_euid = geteuid(); if (!euid) can_do_root_stuff = 1; if (!uid) skip_priv_setting = 1; gid = cur_gid = getgid(); egid = cur_egid = getegid(); /* must store the /proc/self/exe symlink contents before dropping privs! */ dosemu_proc_self_exe = readlink_malloc("/proc/self/exe"); /* For Fedora we must also save a file descriptor to /proc/self/maps */ dosemu_proc_self_maps_fd = open("/proc/self/maps", O_RDONLY); if (under_root_login) { /* check for sudo and set to original user */ char *s = getenv("SUDO_GID"); if (s) { gid = cur_gid = atoi(s); if (gid) { setregid(gid, egid); } } s = getenv("SUDO_UID"); if (s) { uid = cur_uid = atoi(s); if (uid) { pid_t ppid; char *path; FILE *fp; size_t n; char *line; skip_priv_setting = under_root_login = 0; using_sudo = 1; s = getenv("SUDO_USER"); if (s) { initgroups(s, gid); setenv("USER", s, 1); } setreuid(uid, euid); /* retrieve $HOME from sudo's (the parent process') environment */ ppid = getppid(); if (asprintf(&path, "/proc/%d/environ", ppid) != -1) { if ((fp = fopen(path, "r"))) { line = NULL; while(getdelim(&line, &n, '\0', fp) != -1) { if(n>5 && memcmp(line, "HOME=", 5) == 0) { setenv("HOME", line+5, 1); } } free(line); fclose(fp); } free(path); } } } } if (!can_do_root_stuff) { skip_priv_setting = 1; } num_groups = getgroups(0,0); groups = malloc(num_groups * sizeof(gid_t)); getgroups(num_groups,groups); if (!skip_priv_setting) _priv_off(); }
int main (int argc, char **argv) { long sys_ngroups; #ifdef HAVE_GETGROUPS int ngroups; GETGROUPS_T *groups; int pri_grp; int i; struct group *gr; #else char *logname; char *getlogin (); #endif sys_ngroups = sysconf (_SC_NGROUPS_MAX); #ifdef HAVE_GETGROUPS groups = malloc (sys_ngroups * sizeof (GETGROUPS_T)); #endif setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); if (argc == 1) { /* * Called with no arguments - give the group set for the * current user. */ #ifdef HAVE_GETGROUPS /* * This system supports concurrent group sets, so I can ask * the system to tell me which groups are currently set for * this process. */ ngroups = getgroups (sys_ngroups, groups); if (ngroups < 0) { perror ("getgroups"); exit (1); } /* * The groupset includes the primary group as well. */ pri_grp = getegid (); for (i = 0; i < ngroups; i++) if (pri_grp == (int) groups[i]) break; if (i != ngroups) pri_grp = -1; /* * Print out the name of every group in the current group * set. Unknown groups are printed as their decimal group ID * values. */ if (pri_grp != -1) { if ((gr = getgrgid (pri_grp))) printf ("%s", gr->gr_name); else printf ("%d", pri_grp); } for (i = 0; i < ngroups; i++) { if (i || pri_grp != -1) putchar (' '); if ((gr = getgrgid (groups[i]))) printf ("%s", gr->gr_name); else printf ("%ld", (long) groups[i]); } putchar ('\n'); #else /* * This system does not have the getgroups() system call, so * I must check the groups file directly. */ if ((logname = getlogin ())) print_groups (logname); else exit (1); #endif } else { /* * The invoker wanted to know about some other user. Use * that name to look up the groups instead. */ print_groups (argv[1]); } exit (0); }
C_Int_t Posix_ProcEnv_getgroupsN (void) { return getgroups (0, (gid_t*)NULL); }
int mgetgroups (char const *username, gid_t gid, gid_t **groups) { int max_n_groups; int ng; gid_t *g; #if HAVE_GETGROUPLIST /* We prefer to use getgrouplist if available, because it has better performance characteristics. In glibc 2.3.2, getgrouplist is buggy. If you pass a zero as the length of the output buffer, getgrouplist will still write to the buffer. Contrary to what some versions of the getgrouplist manpage say, this doesn't happen with nonzero buffer sizes. Therefore our usage here just avoids a zero sized buffer. */ if (username) { enum { N_GROUPS_INIT = 10 }; max_n_groups = N_GROUPS_INIT; g = realloc_groupbuf (NULL, max_n_groups); if (g == NULL) return -1; while (1) { gid_t *h; int last_n_groups = max_n_groups; /* getgrouplist updates max_n_groups to num required. */ ng = getgrouplist (username, gid, g, &max_n_groups); /* Some systems (like Darwin) have a bug where they never increase max_n_groups. */ if (ng < 0 && last_n_groups == max_n_groups) max_n_groups *= 2; if ((h = realloc_groupbuf (g, max_n_groups)) == NULL) { int saved_errno = errno; free (g); errno = saved_errno; return -1; } g = h; if (0 <= ng) { *groups = g; /* On success some systems just return 0 from getgrouplist, so return max_n_groups rather than ng. */ return max_n_groups; } } } /* else no username, so fall through and use getgroups. */ #endif max_n_groups = (username ? getugroups (0, NULL, username, gid) : getgroups (0, NULL)); /* If we failed to count groups because there is no supplemental group support, then return an array containing just GID. Otherwise, we fail for the same reason. */ if (max_n_groups < 0) { if (errno == ENOSYS && (g = realloc_groupbuf (NULL, 1))) { *groups = g; *g = gid; return gid != (gid_t) -1; } return -1; } if (max_n_groups == 0 || (!username && gid != (gid_t) -1)) max_n_groups++; g = realloc_groupbuf (NULL, max_n_groups); if (g == NULL) return -1; ng = (username ? getugroups (max_n_groups, g, username, gid) : getgroups (max_n_groups - (gid != (gid_t) -1), g + (gid != (gid_t) -1))); if (ng < 0) { /* Failure is unexpected, but handle it anyway. */ int saved_errno = errno; free (g); errno = saved_errno; return -1; } if (!username && gid != (gid_t) -1) { *g = gid; ng++; } *groups = g; /* Reduce the number of duplicates. On some systems, getgroups returns the effective gid twice: once as the first element, and once in its position within the supplementary groups. On other systems, getgroups does not return the effective gid at all, which is why we provide a GID argument. Meanwhile, the GID argument, if provided, is typically any member of the supplementary groups, and not necessarily the effective gid. So, the most likely duplicates are the first element with an arbitrary other element, or pair-wise duplication between the first and second elements returned by getgroups. It is possible that this O(n) pass will not remove all duplicates, but it is not worth the effort to slow down to an O(n log n) algorithm that sorts the array in place, nor the extra memory needed for duplicate removal via an O(n) hash-table. Hence, this function is only documented as guaranteeing no pair-wise duplicates, rather than returning the minimal set. */ if (1 < ng) { gid_t first = *g; gid_t *next; gid_t *groups_end = g + ng; for (next = g + 1; next < groups_end; next++) { if (*next == first || *next == *g) ng--; else *++g = *next; } } return ng; }
int drop_privs(const struct hast_resource *res) { char jailhost[sizeof(res->hr_name) * 2]; struct jail jailst; struct passwd *pw; uid_t ruid, euid, suid; gid_t rgid, egid, sgid; gid_t gidset[1]; bool capsicum, jailed; /* * According to getpwnam(3) we have to clear errno before calling the * function to be able to distinguish between an error and missing * entry (with is not treated as error by getpwnam(3)). */ errno = 0; pw = getpwnam(HAST_USER); if (pw == NULL) { if (errno != 0) { pjdlog_errno(LOG_ERR, "Unable to find info about '%s' user", HAST_USER); return (-1); } else { pjdlog_error("'%s' user doesn't exist.", HAST_USER); errno = ENOENT; return (-1); } } bzero(&jailst, sizeof(jailst)); jailst.version = JAIL_API_VERSION; jailst.path = pw->pw_dir; if (res == NULL) { (void)snprintf(jailhost, sizeof(jailhost), "hastctl"); } else { (void)snprintf(jailhost, sizeof(jailhost), "hastd: %s (%s)", res->hr_name, role2str(res->hr_role)); } jailst.hostname = jailhost; jailst.jailname = NULL; jailst.ip4s = 0; jailst.ip4 = NULL; jailst.ip6s = 0; jailst.ip6 = NULL; if (jail(&jailst) >= 0) { jailed = true; } else { jailed = false; pjdlog_errno(LOG_WARNING, "Unable to jail to directory to %s", pw->pw_dir); if (chroot(pw->pw_dir) == -1) { pjdlog_errno(LOG_ERR, "Unable to change root directory to %s", pw->pw_dir); return (-1); } } PJDLOG_VERIFY(chdir("/") == 0); gidset[0] = pw->pw_gid; if (setgroups(1, gidset) == -1) { pjdlog_errno(LOG_ERR, "Unable to set groups to gid %u", (unsigned int)pw->pw_gid); return (-1); } if (setgid(pw->pw_gid) == -1) { pjdlog_errno(LOG_ERR, "Unable to set gid to %u", (unsigned int)pw->pw_gid); return (-1); } if (setuid(pw->pw_uid) == -1) { pjdlog_errno(LOG_ERR, "Unable to set uid to %u", (unsigned int)pw->pw_uid); return (-1); } #ifdef HAVE_CAPSICUM capsicum = (cap_enter() == 0); if (!capsicum) { pjdlog_common(LOG_DEBUG, 1, errno, "Unable to sandbox using capsicum"); } else if (res != NULL) { cap_rights_t rights; static const unsigned long geomcmds[] = { DIOCGDELETE, DIOCGFLUSH }; PJDLOG_ASSERT(res->hr_role == HAST_ROLE_PRIMARY || res->hr_role == HAST_ROLE_SECONDARY); cap_rights_init(&rights, CAP_FLOCK, CAP_IOCTL, CAP_PREAD, CAP_PWRITE); if (cap_rights_limit(res->hr_localfd, &rights) == -1) { pjdlog_errno(LOG_ERR, "Unable to limit capability rights on local descriptor"); } if (cap_ioctls_limit(res->hr_localfd, geomcmds, sizeof(geomcmds) / sizeof(geomcmds[0])) == -1) { pjdlog_errno(LOG_ERR, "Unable to limit allowed GEOM ioctls"); } if (res->hr_role == HAST_ROLE_PRIMARY) { static const unsigned long ggatecmds[] = { G_GATE_CMD_MODIFY, G_GATE_CMD_START, G_GATE_CMD_DONE, G_GATE_CMD_DESTROY }; cap_rights_init(&rights, CAP_IOCTL); if (cap_rights_limit(res->hr_ggatefd, &rights) == -1) { pjdlog_errno(LOG_ERR, "Unable to limit capability rights to CAP_IOCTL on ggate descriptor"); } if (cap_ioctls_limit(res->hr_ggatefd, ggatecmds, sizeof(ggatecmds) / sizeof(ggatecmds[0])) == -1) { pjdlog_errno(LOG_ERR, "Unable to limit allowed ggate ioctls"); } } } #else capsicum = false; #endif /* * Better be sure that everything succeeded. */ PJDLOG_VERIFY(getresuid(&ruid, &euid, &suid) == 0); PJDLOG_VERIFY(ruid == pw->pw_uid); PJDLOG_VERIFY(euid == pw->pw_uid); PJDLOG_VERIFY(suid == pw->pw_uid); PJDLOG_VERIFY(getresgid(&rgid, &egid, &sgid) == 0); PJDLOG_VERIFY(rgid == pw->pw_gid); PJDLOG_VERIFY(egid == pw->pw_gid); PJDLOG_VERIFY(sgid == pw->pw_gid); PJDLOG_VERIFY(getgroups(0, NULL) == 1); PJDLOG_VERIFY(getgroups(1, gidset) == 1); PJDLOG_VERIFY(gidset[0] == pw->pw_gid); pjdlog_debug(1, "Privileges successfully dropped using %s%s+setgid+setuid.", capsicum ? "capsicum+" : "", jailed ? "jail" : "chroot"); return (0); }
static int set_ids_by_number (uid_t uid, gid_t gid, char **message_ret) { int uid_errno = 0; int gid_errno = 0; int sgs_errno = 0; struct passwd *p = getpwuid (uid); struct group *g = getgrgid (gid); if (message_ret) *message_ret = 0; /* Rumor has it that some implementations of of setuid() do nothing when called with -1; therefore, if the "nobody" user has a uid of -1, then that would be Really Bad. Rumor further has it that such systems really ought to be using -2 for "nobody", since that works. So, if we get a uid (or gid, for good measure) of -1, switch to -2 instead. Note that this must be done after we've looked up the user/group names with getpwuid(-1) and/or getgrgid(-1). */ if (gid == (gid_t) -1) gid = (gid_t) -2; if (uid == (uid_t) -1) uid = (uid_t) -2; errno = 0; if (setgroups_needed_p (gid) && setgroups (1, &gid) < 0) sgs_errno = errno ? errno : -1; errno = 0; if (setgid (gid) != 0) gid_errno = errno ? errno : -1; errno = 0; if (setuid (uid) != 0) uid_errno = errno ? errno : -1; if (uid_errno == 0 && gid_errno == 0 && sgs_errno == 0) { static char buf [1024]; sprintf (buf, "changed uid/gid to %.100s/%.100s (%ld/%ld).", (p && p->pw_name ? p->pw_name : "???"), (g && g->gr_name ? g->gr_name : "???"), (long) uid, (long) gid); if (message_ret) *message_ret = buf; return 0; } else { char buf [1024]; gid_t groups[1024]; int n, size; if (sgs_errno) { sprintf (buf, "%s: couldn't setgroups to %.100s (%ld)", blurb(), (g && g->gr_name ? g->gr_name : "???"), (long) gid); if (sgs_errno == -1) fprintf(stderr, "%s: unknown error\n", buf); else { errno = sgs_errno; perror(buf); } fprintf (stderr, "%s: effective group list: ", blurb()); size = sizeof(groups) / sizeof(gid_t); n = getgroups (size - 1, groups); if (n < 0) fprintf (stderr, "unknown!\n"); else { int i; fprintf (stderr, "["); for (i = 0; i < n; i++) { g = getgrgid (groups[i]); if (i > 0) fprintf (stderr, ", "); if (g && g->gr_name) fprintf (stderr, "%s", g->gr_name); else fprintf (stderr, "%ld", (long) groups[i]); } fprintf (stderr, "]\n"); } } if (gid_errno) { sprintf (buf, "%s: couldn't set gid to %.100s (%ld)", blurb(), (g && g->gr_name ? g->gr_name : "???"), (long) gid); if (gid_errno == -1) fprintf(stderr, "%s: unknown error\n", buf); else { errno = gid_errno; perror(buf); } } if (uid_errno) { sprintf (buf, "%s: couldn't set uid to %.100s (%ld)", blurb(), (p && p->pw_name ? p->pw_name : "???"), (long) uid); if (uid_errno == -1) fprintf(stderr, "%s: unknown error\n", buf); else { errno = uid_errno; perror(buf); } } return -1; } }
/********************************************************************************************************* ** 函数名称: __unix_smsg_proc ** 功能描述: 处理一个发送的 msg ** 输 入 : pafunixRecver unix 接收节点 ** pvMsgEx 扩展消息 ** uiLenEx 扩展消息长度 ** pidSend sender pid ** 输 出 : 是否正确 ** 全局变量: ** 调用模块: *********************************************************************************************************/ INT __unix_smsg_proc (AF_UNIX_T *pafunixRecver, PVOID pvMsgEx, socklen_t uiLenEx, pid_t pidSend) { INT i; struct cmsghdr *pcmhdr; struct msghdr msghdrBuf; socklen_t uiTotalLen = 0; if ((pvMsgEx == LW_NULL) || (uiLenEx < sizeof(struct cmsghdr))) { return (PX_ERROR); } lib_bzero(&msghdrBuf, sizeof(struct msghdr)); msghdrBuf.msg_control = pvMsgEx; msghdrBuf.msg_controllen = uiLenEx; pcmhdr = CMSG_FIRSTHDR(&msghdrBuf); /* 遍历消息确认发送消息的合法性*/ while (pcmhdr) { uiTotalLen += pcmhdr->cmsg_len; if (uiTotalLen > uiLenEx) { /* cmsghdr->cmsg_len 设置有错 */ _ErrorHandle(EMSGSIZE); /* 扩展消息内部大小错误 */ return (PX_ERROR); } if (pcmhdr->cmsg_level == SOL_SOCKET) { if ((pcmhdr->cmsg_type == SCM_CREDENTIALS) || /* Linux 进程凭证 */ (pcmhdr->cmsg_type == SCM_CRED)) { /* BSD 进程凭证 */ if (pafunixRecver->UNIX_iPassCred == 0) { /* 接收方没有开启对应的使能位 */ _ErrorHandle(EINVAL); return (PX_ERROR); } } } pcmhdr = CMSG_NXTHDR(&msghdrBuf, pcmhdr); } pcmhdr = CMSG_FIRSTHDR(&msghdrBuf); /* 遍历消息预处理发送的消息 */ while (pcmhdr) { if (pcmhdr->cmsg_level == SOL_SOCKET) { if (pcmhdr->cmsg_type == SCM_RIGHTS) { /* 传送文件描述符 */ INT *iFdArry = (INT *)CMSG_DATA(pcmhdr); INT iNum = (pcmhdr->cmsg_len - CMSG_LEN(0)) / sizeof(INT); for (i = 0; i < iNum; i++) { __unix_flight(pidSend, iFdArry[i]); } } else if (pcmhdr->cmsg_type == SCM_CREDENTIALS) { /* Linux 进程凭证 */ struct ucred *pucred = (struct ucred *)CMSG_DATA(pcmhdr); pucred->pid = __PROC_GET_PID_CUR(); if (geteuid() != 0) { /* 非特权用户 */ pucred->uid = geteuid(); if ((pucred->gid != getegid()) && (pucred->gid != getgid())) { /* 判断设置是否正确 */ pucred->gid = getegid(); } } } else if (pcmhdr->cmsg_type == SCM_CRED) { /* BSD 进程凭证 */ struct cmsgcred *pcmcred = (struct cmsgcred *)CMSG_DATA(pcmhdr); pcmcred->cmcred_pid = __PROC_GET_PID_CUR(); pcmcred->cmcred_uid = getuid(); pcmcred->cmcred_euid = geteuid(); pcmcred->cmcred_gid = getgid(); pcmcred->cmcred_ngroups = (short)getgroups(CMGROUP_MAX, pcmcred->cmcred_groups); } } pcmhdr = CMSG_NXTHDR(&msghdrBuf, pcmhdr); } return (ERROR_NONE); }
int run_pelog( int which, /* I (one of PE_*) */ char *specpelog, /* I - script path */ job *pjob, /* I - associated job */ int pe_io_type) /* I */ { struct sigaction act; struct sigaction oldact; char *arg[12]; int fds1 = 0; int fds2 = 0; int fd_input; char resc_list[2048]; char resc_used[2048]; struct stat sbuf; char sid[20]; char exit_stat[11]; int waitst; int isjoined; /* boolean */ char buf[MAXPATHLEN + 1024]; char pelog[MAXPATHLEN + 1024]; uid_t real_uid; gid_t *real_gids = NULL; gid_t real_gid; int num_gids; int jobtypespecified = 0; resource *r; char *EmptyString = ""; int LastArg; int aindex; int rc; char *ptr; int moabenvcnt = 14; /* # of entries in moabenvs */ static char *moabenvs[] = { "MOAB_NODELIST", "MOAB_JOBID", "MOAB_JOBNAME", "MOAB_USER", "MOAB_GROUP", "MOAB_CLASS", "MOAB_TASKMAP", "MOAB_QOS", "MOAB_PARTITION", "MOAB_PROCCOUNT", "MOAB_NODECOUNT", "MOAB_MACHINE", "MOAB_JOBARRAYINDEX", "MOAB_JOBARRAYRANGE" }; if ((pjob == NULL) || (specpelog == NULL) || (specpelog[0] == '\0')) { return(0); } ptr = pjob->ji_wattr[JOB_ATR_jobtype].at_val.at_str; if (ptr != NULL) { jobtypespecified = 1; snprintf(pelog,sizeof(pelog),"%s.%s", specpelog, ptr); } else { snprintf(pelog, sizeof(pelog), "%s", specpelog); } real_uid = getuid(); real_gid = getgid(); if ((num_gids = getgroups(0, real_gids)) < 0) { log_err(errno, __func__, "getgroups failed\n"); return(-1); } /* to support root squashing, become the user before performing file checks */ if ((which == PE_PROLOGUSER) || (which == PE_EPILOGUSER) || (which == PE_PROLOGUSERJOB) || (which == PE_EPILOGUSERJOB)) { real_gids = calloc(num_gids, sizeof(gid_t)); if (real_gids == NULL) { log_err(ENOMEM, __func__, "Cannot allocate memory! FAILURE\n"); return(-1); } if (getgroups(num_gids,real_gids) < 0) { log_err(errno, __func__, "getgroups failed\n"); free(real_gids); return(-1); } /* pjob->ji_grpcache will not be set if using LDAP and LDAP not set */ /* It is possible that ji_grpcache failed to allocate as well. Make sure ji_grpcache is not NULL */ if (pjob->ji_grpcache != NULL) { if (setgroups( pjob->ji_grpcache->gc_ngroup, (gid_t *)pjob->ji_grpcache->gc_groups) != 0) { snprintf(log_buffer,sizeof(log_buffer), "setgroups() for UID = %lu failed: %s\n", (unsigned long)pjob->ji_qs.ji_un.ji_momt.ji_exuid, strerror(errno)); log_err(errno, __func__, log_buffer); undo_set_euid_egid(which,real_uid,real_gid,num_gids,real_gids,__func__); free(real_gids); return(-1); } } else { sprintf(log_buffer, "pjob->ji_grpcache is null. check_pwd likely failed."); log_err(-1, __func__, log_buffer); undo_set_euid_egid(which,real_uid,real_gid,num_gids,real_gids,__func__); free(real_gids); return(-1); } if (setegid(pjob->ji_qs.ji_un.ji_momt.ji_exgid) != 0) { snprintf(log_buffer,sizeof(log_buffer), "setegid(%lu) for UID = %lu failed: %s\n", (unsigned long)pjob->ji_qs.ji_un.ji_momt.ji_exgid, (unsigned long)pjob->ji_qs.ji_un.ji_momt.ji_exuid, strerror(errno)); log_err(errno, __func__, log_buffer); undo_set_euid_egid(which,real_uid,real_gid,num_gids,real_gids,__func__); free(real_gids); return(-1); } if (seteuid(pjob->ji_qs.ji_un.ji_momt.ji_exuid) != 0) { snprintf(log_buffer,sizeof(log_buffer), "seteuid(%lu) failed: %s\n", (unsigned long)pjob->ji_qs.ji_un.ji_momt.ji_exuid, strerror(errno)); log_err(errno, __func__, log_buffer); undo_set_euid_egid(which,real_uid,real_gid,num_gids,real_gids,__func__); free(real_gids); return(-1); } } rc = stat(pelog,&sbuf); if ((rc == -1) && (jobtypespecified == 1)) { snprintf(pelog, sizeof(pelog), "%s", specpelog); rc = stat(pelog,&sbuf); } if (rc == -1) { if (errno == ENOENT || errno == EBADF) { /* epilog/prolog script does not exist */ if (LOGLEVEL >= 5) { static char tmpBuf[1024]; sprintf(log_buffer, "%s script '%s' for job %s does not exist (cwd: %s,pid: %d)", PPEType[which], (pelog != NULL) ? pelog : "NULL", (pjob != NULL) ? pjob->ji_qs.ji_jobid : "NULL", getcwd(tmpBuf, sizeof(tmpBuf)), getpid()); log_record(PBSEVENT_SYSTEM, 0, __func__, log_buffer); } #ifdef ENABLE_CSA if ((which == PE_EPILOGUSER) && (!strcmp(pelog, path_epiloguser))) { /* * Add a workload management end record */ if (LOGLEVEL >= 8) { sprintf(log_buffer, "%s calling add_wkm_end from run_pelog() - no user epilog", pjob->ji_qs.ji_jobid); log_err(-1, __func__, log_buffer); } add_wkm_end(pjob->ji_wattr[JOB_ATR_pagg_id].at_val.at_ll, pjob->ji_qs.ji_un.ji_momt.ji_exitstat, pjob->ji_qs.ji_jobid); } #endif /* ENABLE_CSA */ undo_set_euid_egid(which,real_uid,real_gid,num_gids,real_gids,__func__); free(real_gids); return(0); } undo_set_euid_egid(which,real_uid,real_gid,num_gids,real_gids,__func__); free(real_gids); return(pelog_err(pjob,pelog,errno,"cannot stat")); } if (LOGLEVEL >= 5) { sprintf(log_buffer,"running %s script '%s' for job %s", PPEType[which], (pelog[0] != '\0') ? pelog : "NULL", pjob->ji_qs.ji_jobid); log_ext(-1, __func__, log_buffer, LOG_DEBUG); /* not actually an error--but informational */ } /* script must be owned by root, be regular file, read and execute by user * * and not writeable by group or other */ if (reduceprologchecks == TRUE) { if ((!S_ISREG(sbuf.st_mode)) || (!(sbuf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))) { undo_set_euid_egid(which,real_uid,real_gid,num_gids,real_gids,__func__); free(real_gids); return(pelog_err(pjob,pelog,-1,"permission Error")); } } else { if (which == PE_PROLOGUSERJOB || which == PE_EPILOGUSERJOB) { if ((sbuf.st_uid != pjob->ji_qs.ji_un.ji_momt.ji_exuid) || (!S_ISREG(sbuf.st_mode)) || ((sbuf.st_mode & (S_IRUSR | S_IXUSR)) != (S_IRUSR | S_IXUSR)) || (sbuf.st_mode & (S_IWGRP | S_IWOTH))) { undo_set_euid_egid(which,real_uid,real_gid,num_gids,real_gids,__func__); free(real_gids); return(pelog_err(pjob,pelog,-1,"permission Error")); } } else if ((sbuf.st_uid != 0) || (!S_ISREG(sbuf.st_mode)) || ((sbuf.st_mode & (S_IRUSR | S_IXUSR)) != (S_IRUSR | S_IXUSR)) ||\ (sbuf.st_mode & (S_IWGRP | S_IWOTH))) { undo_set_euid_egid(which,real_uid,real_gid,num_gids,real_gids,__func__); free(real_gids); return(pelog_err(pjob,pelog,-1,"permission Error")); } if ((which == PE_PROLOGUSER) || (which == PE_EPILOGUSER)) { /* script must also be read and execute by other */ if ((sbuf.st_mode & (S_IROTH | S_IXOTH)) != (S_IROTH | S_IXOTH)) { undo_set_euid_egid(which,real_uid,real_gid,num_gids,real_gids,__func__); free(real_gids); return(pelog_err(pjob, pelog, -1, "permission Error")); } } } /* END !reduceprologchecks */ fd_input = pe_input(pjob->ji_qs.ji_jobid); if (fd_input < 0) { undo_set_euid_egid(which,real_uid,real_gid,num_gids,real_gids,__func__); free(real_gids); return(pelog_err(pjob, pelog, -2, "no pro/epilogue input file")); } run_exit = 0; child = fork(); if (child > 0) { int KillSent = FALSE; /* parent - watch for prolog/epilog to complete */ close(fd_input); /* switch back to root if necessary */ undo_set_euid_egid(which,real_uid,real_gid,num_gids,real_gids,__func__); free(real_gids); act.sa_handler = pelogalm; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGALRM, &act, &oldact); /* it would be nice if the harvest routine could block for 5 seconds, and if the prolog is not complete in that time, mark job as prolog pending, append prolog child, and continue */ /* main loop should attempt to harvest prolog in non-blocking mode. If unsuccessful after timeout, job should be terminated, and failure reported. If successful, mom should unset prolog pending, and continue with job start sequence. Mom should report job as running while prologpending flag is set. (NOTE: must track per job prolog start time) */ alarm(pe_alarm_time); while (waitpid(child, &waitst, 0) < 0) { if (errno != EINTR) { /* exit loop. non-alarm based failure occurred */ run_exit = -3; MOMPrologFailureCount++; break; } if (run_exit == -4) { if (KillSent == FALSE) { MOMPrologTimeoutCount++; /* timeout occurred */ KillSent = TRUE; /* NOTE: prolog/epilog may be locked in KERNEL space and unkillable */ alarm(5); } else { /* cannot kill prolog/epilog, give up */ run_exit = -5; break; } } } /* END while (wait(&waitst) < 0) */ /* epilog/prolog child completed */ #ifdef ENABLE_CSA if ((which == PE_EPILOGUSER) && (!strcmp(pelog, path_epiloguser))) { /* * Add a workload management end record */ if (LOGLEVEL >= 8) { sprintf(log_buffer, "%s calling add_wkm_end from run_pelog() - after user epilog", pjob->ji_qs.ji_jobid); log_err(-1, __func__, log_buffer); } add_wkm_end(pjob->ji_wattr[JOB_ATR_pagg_id].at_val.at_ll, pjob->ji_qs.ji_un.ji_momt.ji_exitstat, pjob->ji_qs.ji_jobid); } #endif /* ENABLE_CSA */ alarm(0); /* restore the previous handler */ sigaction(SIGALRM, &oldact, 0); if (run_exit == 0) { if (WIFEXITED(waitst)) { run_exit = WEXITSTATUS(waitst); } } } else { /* child - run script */ log_close(0); if (lockfds >= 0) { close(lockfds); lockfds = -1; } net_close(-1); if (fd_input != 0) { close(0); if (dup(fd_input) == -1) {} close(fd_input); } if (pe_io_type == PE_IO_TYPE_NULL) { /* no output, force to /dev/null */ fds1 = open("/dev/null", O_WRONLY, 0600); fds2 = open("/dev/null", O_WRONLY, 0600); } else if (pe_io_type == PE_IO_TYPE_STD) { /* open job standard out/error */ /* * We need to know if files are joined or not. * If they are then open the correct file and duplicate it to the other */ isjoined = is_joined(pjob); switch (isjoined) { case -1: fds2 = open_std_file(pjob, StdErr, O_WRONLY | O_APPEND, pjob->ji_qs.ji_un.ji_momt.ji_exgid); fds1 = dup(fds2); break; case 1: fds1 = open_std_file(pjob, StdOut, O_WRONLY | O_APPEND, pjob->ji_qs.ji_un.ji_momt.ji_exgid); fds2 = dup(fds1); break; default: fds1 = open_std_file(pjob, StdOut, O_WRONLY | O_APPEND, pjob->ji_qs.ji_un.ji_momt.ji_exgid); fds2 = open_std_file(pjob, StdErr, O_WRONLY | O_APPEND, pjob->ji_qs.ji_un.ji_momt.ji_exgid); break; } } if (pe_io_type != PE_IO_TYPE_ASIS) { /* If PE_IO_TYPE_ASIS, leave as is, already open to job */ if (fds1 != 1) { close(1); if (dup(fds1) == -1) {} close(fds1); } if (fds2 != 2) { close(2); if (dup(fds2) == -1) {} close(fds2); } } if ((which == PE_PROLOGUSER) || (which == PE_EPILOGUSER) || (which == PE_PROLOGUSERJOB) || (which == PE_EPILOGUSERJOB)) { if (chdir(pjob->ji_grpcache->gc_homedir) != 0) { /* warn only, no failure */ sprintf(log_buffer, "PBS: chdir to %s failed: %s (running user %s in current directory)", pjob->ji_grpcache->gc_homedir, strerror(errno), which == PE_PROLOGUSER ? "prologue" : "epilogue"); if (write(2, log_buffer, strlen(log_buffer)) == -1) {} fsync(2); } } /* for both prolog and epilog */ if (DEBUGMODE == 1) { fprintf(stderr, "PELOGINFO: script:'%s' jobid:'%s' euser:'******' egroup:'%s' jobname:'%s' SSID:'%ld' RESC:'%s'\n", pelog, pjob->ji_qs.ji_jobid, pjob->ji_wattr[JOB_ATR_euser].at_val.at_str, pjob->ji_wattr[JOB_ATR_egroup].at_val.at_str, pjob->ji_wattr[JOB_ATR_jobname].at_val.at_str, pjob->ji_wattr[JOB_ATR_session_id].at_val.at_long, resc_to_string(pjob, JOB_ATR_resource, resc_list, sizeof(resc_list))); } arg[0] = pelog; arg[1] = pjob->ji_qs.ji_jobid; arg[2] = pjob->ji_wattr[JOB_ATR_euser].at_val.at_str; arg[3] = pjob->ji_wattr[JOB_ATR_egroup].at_val.at_str; arg[4] = pjob->ji_wattr[JOB_ATR_jobname].at_val.at_str; /* NOTE: inside child */ if ((which == PE_EPILOG) || (which == PE_EPILOGUSER) || (which == PE_EPILOGUSERJOB)) { /* for epilog only */ sprintf(sid, "%ld", pjob->ji_wattr[JOB_ATR_session_id].at_val.at_long); sprintf(exit_stat,"%d", pjob->ji_qs.ji_un.ji_momt.ji_exitstat); arg[5] = sid; arg[6] = resc_to_string(pjob, JOB_ATR_resource, resc_list, sizeof(resc_list)); arg[7] = resc_to_string(pjob, JOB_ATR_resc_used, resc_used, sizeof(resc_used)); arg[8] = pjob->ji_wattr[JOB_ATR_in_queue].at_val.at_str; arg[9] = pjob->ji_wattr[JOB_ATR_account].at_val.at_str; arg[10] = exit_stat; arg[11] = NULL; LastArg = 11; } else { /* prolog */ arg[5] = resc_to_string(pjob, JOB_ATR_resource, resc_list, sizeof(resc_list)); arg[6] = pjob->ji_wattr[JOB_ATR_in_queue].at_val.at_str; arg[7] = pjob->ji_wattr[JOB_ATR_account].at_val.at_str; arg[8] = NULL; LastArg = 8; } for (aindex = 0;aindex < LastArg;aindex++) { if (arg[aindex] == NULL) arg[aindex] = EmptyString; } /* END for (aindex) */ /* * Pass Resource_List.nodes request in environment * to allow pro/epi-logue setup/teardown of system * settings. --pw, 2 Jan 02 * Fixed to use putenv for sysV compatibility. * --troy, 11 jun 03 * */ r = find_resc_entry( &pjob->ji_wattr[JOB_ATR_resource], find_resc_def(svr_resc_def, "nodes", svr_resc_size)); if (r != NULL) { /* setenv("PBS_RESOURCE_NODES",r->rs_value.at_val.at_str,1); */ const char *envname = "PBS_RESOURCE_NODES="; char *envstr; envstr = calloc((strlen(envname) + strlen(r->rs_value.at_val.at_str) + 1), sizeof(char)); if (envstr != NULL) { strcpy(envstr,envname); strcat(envstr,r->rs_value.at_val.at_str); /* do _not_ free the string when using putenv */ putenv(envstr); } } /* END if (r != NULL) */ r = find_resc_entry( &pjob->ji_wattr[JOB_ATR_resource], find_resc_def(svr_resc_def, "gres", svr_resc_size)); if (r != NULL) { /* setenv("PBS_RESOURCE_NODES",r->rs_value.at_val.at_str,1); */ const char *envname = "PBS_RESOURCE_GRES="; char *envstr; envstr = calloc((strlen(envname) + strlen(r->rs_value.at_val.at_str) + 1), sizeof(char)); if (envstr != NULL) { strcpy(envstr,envname); strcat(envstr,r->rs_value.at_val.at_str); /* do _not_ free the string when using putenv */ putenv(envstr); } } /* END if (r != NULL) */ if (TTmpDirName(pjob, buf, sizeof(buf))) { const char *envname = "TMPDIR="; char *envstr; envstr = calloc((strlen(envname) + strlen(buf) + 1), sizeof(char)); if (envstr != NULL) { strcpy(envstr,envname); strcat(envstr,buf); /* do _not_ free the string when using putenv */ putenv(envstr); } } /* END if (TTmpDirName(pjob,&buf)) */ /* Set PBS_SCHED_HINT */ { char *envname = "PBS_SCHED_HINT"; char *envval; char *envstr; if ((envval = get_job_envvar(pjob, envname)) != NULL) { envstr = calloc((strlen(envname) + strlen(envval) + 2), sizeof(char)); if (envstr != NULL) { sprintf(envstr,"%s=%s", envname, envval); putenv(envstr); } } } /* Set PBS_NODENUM */ { char *envname = "PBS_NODENUM"; char *envstr; sprintf(buf, "%d", pjob->ji_nodeid); envstr = calloc((strlen(envname) + strlen(buf) + 2), sizeof(char)); if (envstr != NULL) { sprintf(envstr,"%s=%d", envname, pjob->ji_nodeid); putenv(envstr); } } /* Set PBS_MSHOST */ { char *envname = "PBS_MSHOST"; char *envstr; if ((pjob->ji_vnods[0].vn_host != NULL) && (pjob->ji_vnods[0].vn_host->hn_host != NULL)) { envstr = calloc((strlen(envname) + strlen(pjob->ji_vnods[0].vn_host->hn_host) + 2), sizeof(char)); if (envstr != NULL) { sprintf(envstr,"%s=%s", envname, pjob->ji_vnods[0].vn_host->hn_host); putenv(envstr); } } } /* Set PBS_NODEFILE */ { char *envname = "PBS_NODEFILE"; char *envstr; if (pjob->ji_flags & MOM_HAS_NODEFILE) { sprintf(buf, "%s/%s", path_aux, pjob->ji_qs.ji_jobid); envstr = calloc((strlen(envname) + strlen(buf) + 2), sizeof(char)); if (envstr != NULL) { sprintf(envstr,"%s=%s", envname, buf); putenv(envstr); } } } /* Set PBS_O_Workdir */ { char *envname = "PBS_O_WORKDIR"; char *workdir_val; char *envstr; workdir_val = get_job_envvar(pjob,envname); if (workdir_val != NULL) { envstr = calloc((strlen(workdir_val) + strlen(envname) + 2), sizeof(char)); if (envstr != NULL) { sprintf(envstr,"%s=%s", envname, workdir_val); putenv(envstr); } } } /* SET BEOWULF_JOB_MAP */ { struct array_strings *vstrs; int VarIsSet = 0; int j; vstrs = pjob->ji_wattr[JOB_ATR_variables].at_val.at_arst; for (j = 0;j < vstrs->as_usedptr;++j) { if (!strncmp( vstrs->as_string[j], "BEOWULF_JOB_MAP=", strlen("BEOWULF_JOB_MAP="))) { VarIsSet = 1; break; } } if (VarIsSet == 1) { char *envstr; envstr = calloc((strlen(vstrs->as_string[j])), sizeof(char)); if (envstr != NULL) { strcpy(envstr,vstrs->as_string[j]); putenv(envstr); } } } /* Set some Moab env variables if they exist */ if ((which == PE_PROLOG) || (which == PE_EPILOG)) { char *tmp_val; char *envstr; for (aindex=0;aindex<moabenvcnt;aindex++) { tmp_val = get_job_envvar(pjob,moabenvs[aindex]); if (tmp_val != NULL) { envstr = calloc((strlen(tmp_val) + strlen(moabenvs[aindex]) + 2), sizeof(char)); if (envstr != NULL) { sprintf(envstr,"%s=%s", moabenvs[aindex], tmp_val); putenv(envstr); } } } } /* * if we want to run as user then we need to reset real user permissions * since it seems that some OSs use real not effective user id when execv'ing */ if ((which == PE_PROLOGUSER) || (which == PE_EPILOGUSER) || (which == PE_PROLOGUSERJOB) || (which == PE_EPILOGUSERJOB)) { seteuid(pbsuser); setegid(pbsgroup); if (setgid(pjob->ji_qs.ji_un.ji_momt.ji_exgid) != 0) { snprintf(log_buffer,sizeof(log_buffer), "setgid(%lu) for UID = %lu failed: %s\n", (unsigned long)pjob->ji_qs.ji_un.ji_momt.ji_exgid, (unsigned long)pjob->ji_qs.ji_un.ji_momt.ji_exuid, strerror(errno)); log_err(errno, __func__, log_buffer); return(-1); } if (setuid(pjob->ji_qs.ji_un.ji_momt.ji_exuid) != 0) { snprintf(log_buffer,sizeof(log_buffer), "setuid(%lu) failed: %s\n", (unsigned long)pjob->ji_qs.ji_un.ji_momt.ji_exuid, strerror(errno)); log_err(errno, __func__, log_buffer); return(-1); } } execv(pelog,arg); sprintf(log_buffer,"execv of %s failed: %s\n", pelog, strerror(errno)); if (write(2, log_buffer, strlen(log_buffer)) == -1) { /* cannot write message to stderr */ /* NO-OP */ } fsync(2); exit(255); } /* END else () */ switch (run_exit) { case 0: /* SUCCESS */ /* NO-OP */ break; case - 3: pelog_err(pjob, pelog, run_exit, "child wait interrupted"); break; case - 4: pelog_err(pjob, pelog, run_exit, "prolog/epilog timeout occurred, child cleaned up"); break; case - 5: pelog_err(pjob, pelog, run_exit, "prolog/epilog timeout occurred, cannot kill child"); break; default: pelog_err(pjob, pelog, run_exit, "nonzero p/e exit status"); break; } /* END switch (run_exit) */ return(run_exit); } /* END run_pelog() */
int main(int argc, const char *argv[]) { struct passwd *pw; struct group *gp; int current_user = 0; uid_t id; int i; if (argc > 2) usage(1, NULL); if (argc == 1) { id = getuid(); current_user = 1; if (!(pw = getpwuid(id))) usage(1, "Username does not exist"); } else { if (!(pw = getpwnam(argv[1]))) usage(1, "Username does not exist"); id = pw->pw_uid; } printf("uid=%d(%s)", id, pw->pw_name); if ((gp = getgrgid(pw->pw_gid))) printf(" gid=%d(%s)", pw->pw_gid, gp->gr_name); if (current_user) { gid_t *gid_list; int gid_size; if (getuid() != geteuid()) { id = geteuid(); if (!(pw = getpwuid(id))) usage(1, "Username does not exist"); printf(" euid=%d(%s)", id, pw->pw_name); } if (getgid() != getegid()) { id = getegid(); if (!(gp = getgrgid(id))) usage(1, "Group does not exist"); printf(" egid=%d(%s)", id, gp->gr_name); } /* use getgroups interface to get current groups */ gid_size = getgroups(0, NULL); if (gid_size) { gid_list = malloc(gid_size * sizeof(gid_t)); getgroups(gid_size, gid_list); for (i = 0; i < gid_size; i++) { if (!(gp = getgrgid(gid_list[i]))) die("Group does not exist"); printf("%s%d(%s)", (i == 0) ? " groups=" : ",", gp->gr_gid, gp->gr_name); } free(gid_list); } } else { /* get list of groups from group database */ i = 0; while ((gp = getgrent())) { char *c = *(gp->gr_mem); while (c && *c) { if (!strncmp(c, pw->pw_name, 16)) { printf("%s%d(%s)", (i++ == 0) ? " groups=" : ",", gp->gr_gid, gp->gr_name); c = NULL; } else { c++; } } } endgrent(); } printf("\n"); exit(0); }
/* * Collect the requested quota information. */ struct dquot *getprivs(qid_t id, struct quota_handle **handles, int quiet) { struct dquot *q, *qtail = NULL, *qhead = NULL; int i; char name[MAXNAMELEN]; #if defined(BSD_BEHAVIOUR) int j, ngroups; uid_t euid; gid_t gidset[NGROUPS], *gidsetp; #endif for (i = 0; handles[i]; i++) { #if defined(BSD_BEHAVIOUR) switch (handles[i]->qh_type) { case USRQUOTA: euid = geteuid(); if (euid != id && euid != 0) { uid2user(id, name); errstr(_("%s (uid %d): Permission denied\n"), name, id); return (struct dquot *)NULL; } break; case GRPQUOTA: if (geteuid() == 0) break; ngroups = sysconf(_SC_NGROUPS_MAX); if (ngroups > NGROUPS) { gidsetp = malloc(ngroups * sizeof(gid_t)); if (!gidsetp) { gid2group(id, name); errstr(_("%s (gid %d): gid set allocation (%d): %s\n"), name, id, ngroups, strerror(errno)); return (struct dquot *)NULL; } } else gidsetp = &gidset[0]; ngroups = getgroups(ngroups, gidsetp); if (ngroups < 0) { if (gidsetp != gidset) free(gidsetp); gid2group(id, name); errstr(_("%s (gid %d): error while trying getgroups(): %s\n"), name, id, strerror(errno)); return (struct dquot *)NULL; } for (j = 0; j < ngroups; j++) if (id == gidsetp[j]) break; if (gidsetp != gidset) free(gidsetp); if (j >= ngroups) { gid2group(id, name); errstr(_("%s (gid %d): Permission denied\n"), name, id); return (struct dquot *)NULL; } break; default: break; } #endif if (!(q = handles[i]->qh_ops->read_dquot(handles[i], id))) { /* If rpc.rquotad is not running filesystem might be just without quotas... */ if (errno != ENOENT && (errno != ECONNREFUSED || !quiet)) { int olderrno = errno; id2name(id, handles[i]->qh_type, name); errstr(_("error while getting quota from %s for %s (id %u): %s\n"), handles[i]->qh_quotadev, name, id, strerror(olderrno)); } continue; } if (qhead == NULL) qhead = q; else qtail->dq_next = q; qtail = q; q->dq_next = NULL; /* This should be already set, but just for sure... */ } return qhead; }
int main(int argc, char *argv[]) { struct group *gr; struct stat st; int ask, ch, cnt, fflag, hflag, pflag, sflag, quietlog, rootlogin, rval; uid_t uid, saved_uid; gid_t saved_gid, saved_gids[NGROUPS_MAX]; int nsaved_gids; #ifdef notdef char *domain; #endif char *p, *ttyn; const char *pwprompt; char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; char localhost[MAXHOSTNAMELEN + 1]; int need_chpass, require_chpass; int login_retries = DEFAULT_RETRIES, login_backoff = DEFAULT_BACKOFF; time_t pw_warntime = _PASSWORD_WARNDAYS * SECSPERDAY; char *loginname = NULL; #ifdef KERBEROS5 int Fflag; krb5_error_code kerror; #endif #if defined(KERBEROS5) int got_tickets = 0; #endif #ifdef LOGIN_CAP char *shell = NULL; login_cap_t *lc = NULL; #endif tbuf[0] = '\0'; rval = 0; pwprompt = NULL; nested = NULL; need_chpass = require_chpass = 0; (void)signal(SIGALRM, timedout); (void)alarm(timeout); (void)signal(SIGQUIT, SIG_IGN); (void)signal(SIGINT, SIG_IGN); (void)setpriority(PRIO_PROCESS, 0, 0); openlog("login", 0, LOG_AUTH); /* * -p is used by getty to tell login not to destroy the environment * -f is used to skip a second login authentication * -h is used by other servers to pass the name of the remote host to * login so that it may be placed in utmp/utmpx and wtmp/wtmpx * -a in addition to -h, a server may supply -a to pass the actual * server address. * -s is used to force use of S/Key or equivalent. */ if (gethostname(localhost, sizeof(localhost)) < 0) { syslog(LOG_ERR, "couldn't get local hostname: %m"); strcpy(hostname, "amnesiac"); } #ifdef notdef domain = strchr(localhost, '.'); #endif localhost[sizeof(localhost) - 1] = '\0'; fflag = hflag = pflag = sflag = 0; have_ss = 0; #ifdef KERBEROS5 Fflag = 0; have_forward = 0; #endif uid = getuid(); while ((ch = getopt(argc, argv, "a:Ffh:ps")) != -1) switch (ch) { case 'a': if (uid) errx(EXIT_FAILURE, "-a option: %s", strerror(EPERM)); decode_ss(optarg); #ifdef notdef (void)sockaddr_snprintf(optarg, sizeof(struct sockaddr_storage), "%a", (void *)&ss); #endif break; case 'F': #ifdef KERBEROS5 Fflag = 1; #endif /* FALLTHROUGH */ case 'f': fflag = 1; break; case 'h': if (uid) errx(EXIT_FAILURE, "-h option: %s", strerror(EPERM)); hflag = 1; #ifdef notdef if (domain && (p = strchr(optarg, '.')) != NULL && strcasecmp(p, domain) == 0) *p = '\0'; #endif hostname = optarg; break; case 'p': pflag = 1; break; case 's': sflag = 1; break; default: case '?': usage(); break; } setproctitle(NULL); argc -= optind; argv += optind; if (*argv) { username = loginname = *argv; ask = 0; } else ask = 1; #ifdef F_CLOSEM (void)fcntl(3, F_CLOSEM, 0); #else for (cnt = getdtablesize(); cnt > 2; cnt--) (void)close(cnt); #endif ttyn = ttyname(STDIN_FILENO); if (ttyn == NULL || *ttyn == '\0') { (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY); ttyn = tname; } if ((tty = strstr(ttyn, "/pts/")) != NULL) ++tty; else if ((tty = strrchr(ttyn, '/')) != NULL) ++tty; else tty = ttyn; if (issetugid()) { nested = strdup(user_from_uid(getuid(), 0)); if (nested == NULL) { syslog(LOG_ERR, "strdup: %m"); sleepexit(EXIT_FAILURE); } } #ifdef LOGIN_CAP /* Get "login-retries" and "login-backoff" from default class */ if ((lc = login_getclass(NULL)) != NULL) { login_retries = (int)login_getcapnum(lc, "login-retries", DEFAULT_RETRIES, DEFAULT_RETRIES); login_backoff = (int)login_getcapnum(lc, "login-backoff", DEFAULT_BACKOFF, DEFAULT_BACKOFF); login_close(lc); lc = NULL; } #endif #ifdef KERBEROS5 kerror = krb5_init_context(&kcontext); if (kerror) { /* * If Kerberos is not configured, that is, we are * not using Kerberos, do not log the error message. * However, if Kerberos is configured, and the * context init fails for some other reason, we need * to issue a no tickets warning to the user when the * login succeeds. */ if (kerror != ENXIO) { /* XXX NetBSD-local Heimdal hack */ syslog(LOG_NOTICE, "%s when initializing Kerberos context", error_message(kerror)); krb5_configured = 1; } login_krb5_get_tickets = 0; } #endif /* KERBEROS5 */ for (cnt = 0;; ask = 1) { #if defined(KERBEROS5) if (login_krb5_get_tickets) k5destroy(); #endif if (ask) { fflag = 0; loginname = getloginname(); } rootlogin = 0; #ifdef KERBEROS5 if ((instance = strchr(loginname, '/')) != NULL) *instance++ = '\0'; else instance = __UNCONST(""); #endif username = trimloginname(loginname); /* * Note if trying multiple user names; log failures for * previous user name, but don't bother logging one failure * for nonexistent name (mistyped username). */ if (failures && strcmp(tbuf, username)) { if (failures > (pwd ? 0 : 1)) badlogin(tbuf); failures = 0; } (void)strlcpy(tbuf, username, sizeof(tbuf)); pwd = getpwnam(username); #ifdef LOGIN_CAP /* * Establish the class now, before we might goto * within the next block. pwd can be NULL since it * falls back to the "default" class if it is. */ lc = login_getclass(pwd ? pwd->pw_class : NULL); #endif /* * if we have a valid account name, and it doesn't have a * password, or the -f option was specified and the caller * is root or the caller isn't changing their uid, don't * authenticate. */ if (pwd) { if (pwd->pw_uid == 0) rootlogin = 1; if (fflag && (uid == 0 || uid == pwd->pw_uid)) { /* already authenticated */ #ifdef KERBEROS5 if (login_krb5_get_tickets && Fflag) k5_read_creds(username); #endif break; } else if (pwd->pw_passwd[0] == '\0') { /* pretend password okay */ rval = 0; goto ttycheck; } } fflag = 0; (void)setpriority(PRIO_PROCESS, 0, -4); #ifdef SKEY if (skey_haskey(username) == 0) { static char skprompt[80]; const char *skinfo = skey_keyinfo(username); (void)snprintf(skprompt, sizeof(skprompt), "Password [ %s ]:", skinfo ? skinfo : "error getting challenge"); pwprompt = skprompt; } else #endif pwprompt = "Password:"******"Login incorrect or refused on this " "terminal.\n"); if (hostname) syslog(LOG_NOTICE, "LOGIN %s REFUSED FROM %s ON TTY %s", pwd->pw_name, hostname, tty); else syslog(LOG_NOTICE, "LOGIN %s REFUSED ON TTY %s", pwd->pw_name, tty); continue; } if (pwd && !rval) break; (void)printf("Login incorrect or refused on this " "terminal.\n"); failures++; cnt++; /* * We allow login_retries tries, but after login_backoff * we start backing off. These default to 10 and 3 * respectively. */ if (cnt > login_backoff) { if (cnt >= login_retries) { badlogin(username); sleepexit(EXIT_FAILURE); } sleep((u_int)((cnt - login_backoff) * 5)); } } /* committed to login -- turn off timeout */ (void)alarm((u_int)0); endpwent(); /* if user not super-user, check for disabled logins */ #ifdef LOGIN_CAP if (!login_getcapbool(lc, "ignorenologin", rootlogin)) checknologin(login_getcapstr(lc, "nologin", NULL, NULL)); #else if (!rootlogin) checknologin(NULL); #endif #ifdef LOGIN_CAP quietlog = login_getcapbool(lc, "hushlogin", 0); #else quietlog = 0; #endif /* Temporarily give up special privileges so we can change */ /* into NFS-mounted homes that are exported for non-root */ /* access and have mode 7x0 */ saved_uid = geteuid(); saved_gid = getegid(); nsaved_gids = getgroups(NGROUPS_MAX, saved_gids); (void)setegid(pwd->pw_gid); initgroups(username, pwd->pw_gid); (void)seteuid(pwd->pw_uid); if (chdir(pwd->pw_dir) < 0) { #ifdef LOGIN_CAP if (login_getcapbool(lc, "requirehome", 0)) { (void)printf("Home directory %s required\n", pwd->pw_dir); sleepexit(EXIT_FAILURE); } #endif (void)printf("No home directory %s!\n", pwd->pw_dir); if (chdir("/") == -1) exit(EXIT_FAILURE); pwd->pw_dir = __UNCONST("/"); (void)printf("Logging in with home = \"/\".\n"); } if (!quietlog) quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; /* regain special privileges */ (void)seteuid(saved_uid); setgroups(nsaved_gids, saved_gids); (void)setegid(saved_gid); #ifdef LOGIN_CAP pw_warntime = login_getcaptime(lc, "password-warn", _PASSWORD_WARNDAYS * SECSPERDAY, _PASSWORD_WARNDAYS * SECSPERDAY); #endif (void)gettimeofday(&now, NULL); if (pwd->pw_expire) { if (now.tv_sec >= pwd->pw_expire) { (void)printf("Sorry -- your account has expired.\n"); sleepexit(EXIT_FAILURE); } else if (pwd->pw_expire - now.tv_sec < pw_warntime && !quietlog) (void)printf("Warning: your account expires on %s", ctime(&pwd->pw_expire)); } if (pwd->pw_change) { if (pwd->pw_change == _PASSWORD_CHGNOW) need_chpass = 1; else if (now.tv_sec >= pwd->pw_change) { (void)printf("Sorry -- your password has expired.\n"); sleepexit(EXIT_FAILURE); } else if (pwd->pw_change - now.tv_sec < pw_warntime && !quietlog) (void)printf("Warning: your password expires on %s", ctime(&pwd->pw_change)); } /* Nothing else left to fail -- really log in. */ update_db(quietlog, rootlogin, fflag); (void)chown(ttyn, pwd->pw_uid, (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); if (ttyaction(ttyn, "login", pwd->pw_name)) (void)printf("Warning: ttyaction failed.\n"); #if defined(KERBEROS5) /* Fork so that we can call kdestroy */ if (! login_krb5_retain_ccache && has_ccache) dofork(); #endif /* Destroy environment unless user has requested its preservation. */ if (!pflag) environ = envinit; #ifdef LOGIN_CAP if (nested == NULL && setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETLOGIN) != 0) { syslog(LOG_ERR, "setusercontext failed"); exit(EXIT_FAILURE); } if (setusercontext(lc, pwd, pwd->pw_uid, (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETLOGIN))) != 0) { syslog(LOG_ERR, "setusercontext failed"); exit(EXIT_FAILURE); } #else (void)setgid(pwd->pw_gid); initgroups(username, pwd->pw_gid); if (nested == NULL && setlogin(pwd->pw_name) < 0) syslog(LOG_ERR, "setlogin() failure: %m"); /* Discard permissions last so can't get killed and drop core. */ if (rootlogin) (void)setuid(0); else (void)setuid(pwd->pw_uid); #endif if (*pwd->pw_shell == '\0') pwd->pw_shell = __UNCONST(_PATH_BSHELL); #ifdef LOGIN_CAP if ((shell = login_getcapstr(lc, "shell", NULL, NULL)) != NULL) { if ((shell = strdup(shell)) == NULL) { syslog(LOG_ERR, "Cannot alloc mem"); sleepexit(EXIT_FAILURE); } pwd->pw_shell = shell; } #endif (void)setenv("HOME", pwd->pw_dir, 1); (void)setenv("SHELL", pwd->pw_shell, 1); if (term[0] == '\0') { const char *tt = stypeof(tty); #ifdef LOGIN_CAP if (tt == NULL) tt = login_getcapstr(lc, "term", NULL, NULL); #endif /* unknown term -> "su" */ (void)strlcpy(term, tt != NULL ? tt : "su", sizeof(term)); } (void)setenv("TERM", term, 0); (void)setenv("LOGNAME", pwd->pw_name, 1); (void)setenv("USER", pwd->pw_name, 1); #ifdef LOGIN_CAP setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH); #else (void)setenv("PATH", _PATH_DEFPATH, 0); #endif #ifdef KERBEROS5 if (krb5tkfile_env) (void)setenv("KRB5CCNAME", krb5tkfile_env, 1); #endif /* If fflag is on, assume caller/authenticator has logged root login. */ if (rootlogin && fflag == 0) { if (hostname) syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s", username, tty, hostname); else syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty); } #if defined(KERBEROS5) if (KERBEROS_CONFIGURED && !quietlog && notickets == 1) (void)printf("Warning: no Kerberos tickets issued.\n"); #endif if (!quietlog) { const char *fname; #ifdef LOGIN_CAP fname = login_getcapstr(lc, "copyright", NULL, NULL); if (fname != NULL && access(fname, F_OK) == 0) motd(fname); else #endif (void)printf("%s", copyrightstr); #ifdef LOGIN_CAP fname = login_getcapstr(lc, "welcome", NULL, NULL); if (fname == NULL || access(fname, F_OK) != 0) #endif fname = _PATH_MOTDFILE; motd(fname); (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name); if (stat(tbuf, &st) == 0 && st.st_size != 0) (void)printf("You have %smail.\n", (st.st_mtime > st.st_atime) ? "new " : ""); } #ifdef LOGIN_CAP login_close(lc); #endif (void)signal(SIGALRM, SIG_DFL); (void)signal(SIGQUIT, SIG_DFL); (void)signal(SIGINT, SIG_DFL); (void)signal(SIGTSTP, SIG_IGN); tbuf[0] = '-'; (void)strlcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ? p + 1 : pwd->pw_shell, sizeof(tbuf) - 1); /* Wait to change password until we're unprivileged */ if (need_chpass) { if (!require_chpass) (void)printf( "Warning: your password has expired. Please change it as soon as possible.\n"); else { int status; (void)printf( "Your password has expired. Please choose a new one.\n"); switch (fork()) { case -1: warn("fork"); sleepexit(EXIT_FAILURE); case 0: execl(_PATH_BINPASSWD, "passwd", NULL); _exit(EXIT_FAILURE); default: if (wait(&status) == -1 || WEXITSTATUS(status)) sleepexit(EXIT_FAILURE); } } } #ifdef KERBEROS5 if (login_krb5_get_tickets) k5_write_creds(); #endif execlp(pwd->pw_shell, tbuf, NULL); err(EXIT_FAILURE, "%s", pwd->pw_shell); }
/* * stat() or lstat() a path as a particular user/group. */ static int _path_stat(const char *path, int link, uid_t uid, gid_t gid) { struct stat sb; gid_t orig_gidset[NGROUPS_MAX]; int ngroups, status, stat_status; struct passwd *p; uint32_t orig_cache_enabled; /* disable L1 cache to avoid notification deadlock */ orig_cache_enabled = gL1CacheEnabled; gL1CacheEnabled = 0; /* get my group list */ memset(orig_gidset, 0, sizeof(orig_gidset)); ngroups = getgroups(NGROUPS_MAX, orig_gidset); if (ngroups < 0) { return PATH_STAT_FAILED; } /* look up user name */ p = getpwuid(uid); if (p == NULL) { gL1CacheEnabled = orig_cache_enabled; return PATH_STAT_FAILED; } /* switch to user's grouplist */ status = initgroups(p->pw_name, gid); if (status < 0) { gL1CacheEnabled = orig_cache_enabled; return PATH_STAT_FAILED; } /* reset gL1CacheEnabled */ gL1CacheEnabled = orig_cache_enabled; /* set thread credentials */ pthread_setugid_np(uid, gid); /* stat the file */ stat_status = -1; if (link != 0) { stat_status = lstat(path, &sb); } else { stat_status = stat(path, &sb); } /* unset thread credentials */ pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE); /* restore original grouplist for UID 0 */ status = syscall(SYS_initgroups, ngroups, orig_gidset, 0); if (status < 0) { return PATH_STAT_FAILED; } /* return status */ if (stat_status == 0) { return PATH_STAT_OK; } if (errno == EACCES) { return PATH_STAT_ACCESS; } return PATH_STAT_FAILED; }
int main(int argc, char *argv[]) { int ngroups; gid_t mygid, gidset[NGROUPS]; int i, gflag = 0, uflag = 0; char ch; while ((ch = getopt(argc, argv, "glquv")) != -1) { switch(ch) { case 'g': gflag++; break; case 'l': lflag++; break; case 'q': qflag++; break; case 'u': uflag++; break; case 'v': vflag++; break; default: usage(); } } argc -= optind; argv += optind; if (!uflag && !gflag) uflag++; if (argc == 0) { if (uflag) showuid(getuid()); if (gflag) { mygid = getgid(); ngroups = getgroups(NGROUPS, gidset); if (ngroups < 0) err(1, "getgroups"); showgid(mygid); for (i = 0; i < ngroups; i++) if (gidset[i] != mygid) showgid(gidset[i]); } return(0); } if (uflag && gflag) usage(); if (uflag) { for (; argc > 0; argc--, argv++) { if (alldigits(*argv)) showuid(atoi(*argv)); else showusrname(*argv); } return(0); } if (gflag) { for (; argc > 0; argc--, argv++) { if (alldigits(*argv)) showgid(atoi(*argv)); else showgrpname(*argv); } } return(0); }
/*********************************************************************** * MAIN ***********************************************************************/ int main(int ac, char **av) { int lc; /* loop counter */ const char *ptr; /* message returned from parse_opts */ int i, /* counter */ group, /* return value from Getgid() call */ entries; /* number of group entries */ gid_t gidset[NGROUPS]; /* storage for all group ids */ gid_t cmpset[NGROUPS]; int ret; int ret2; int errors = 0; char msg[500]; /*************************************************************** * parse standard options, and exit if there is an error ***************************************************************/ if ( (ptr=parse_opts(ac, av, (option_t *) NULL, NULL)) != (char *) NULL ) { tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", ptr); tst_exit(); } /*************************************************************** * perform global setup for test ***************************************************************/ setup(); /*************************************************************** * check looping state if -c option given ***************************************************************/ for (lc=0; TEST_LOOPING(lc); lc++) { /* reset Tst_count in case we are looping. */ Tst_count=0; /* * Check to see if getgroups() fails on erraneous condition. */ TEST( getgroups(-1,gidset) ); if((ret=TEST_RETURN) != -1) { sprintf(msg, "getgroups(-1,gidset) returned %d, expected -1 and errno = EINVAL", ret); tst_resm(TFAIL,msg); errors++; } else if ( STD_FUNCTIONAL_TEST ) { if(errno != EINVAL) { sprintf(msg, "getgroups(-1,gidset) returned %d, errno = %d, expected errno %d (EINVAL)", ret, errno, EINVAL); tst_resm(TFAIL,msg); errors++; } else { sprintf(msg, "getgroups(-1,gidset) returned %d and error = %d (EINVAL) as expected", ret, errno); tst_resm(TPASS, msg); } } /* * Check that if ngrps is zero that the number of groups is return and * the the gidset array is not modified. * This is a POSIX special case. */ memset(gidset, 052, NGROUPS); memset(cmpset, 052, NGROUPS); TEST( getgroups(0,gidset) ); if((ret=TEST_RETURN) < 0) { sprintf(msg, "getgroups(0,gidset) returned %d with errno = %d, expected num gids with no change to gidset", ret, errno); tst_resm(TFAIL,msg); errors++; } else if ( STD_FUNCTIONAL_TEST ) { /* * check that gidset was unchanged */ if ( memcmp(cmpset, gidset, NGROUPS) != 0 ) { sprintf(msg, "getgroups(0,gidset) returned %d, the gidset array was modified", ret); tst_resm(TFAIL,msg); errors++; } else { sprintf(msg, "getgroups(0,gidset) returned %d, the gidset array not was modified", ret); tst_resm(TPASS, msg); } } /* * Check to see that is -1 is returned and errno is set to EINVAL when * ngroups is not big enough to hold all groups. */ if ( ret <= 1 ) { sprintf(msg, "getgroups(0,gidset) returned %d, Unable to test that\nusing ngrps >=1 but less than number of grps", ret); tst_resm(TCONF, msg); errors++; } else { TEST( getgroups(ret-1, gidset) ); if ((ret2 = TEST_RETURN) == -1 ) { if ( STD_FUNCTIONAL_TEST ) { if ( errno != EINVAL ) { sprintf(msg, "getgroups(%d, gidset) returned -1, but not errno %d (EINVAL) but %d", ret-1, EINVAL, errno); tst_resm(TFAIL, msg); errors++; } else { sprintf(msg, "getgroups(%d, gidset) returned -1, and errno %d (EINVAL) when %d grps", ret-1, errno, ret); tst_resm(TPASS, msg); } } } else { sprintf(msg, "getgroups(%d, gidset) returned %d, expected -1 and errno EINVAL.", ret-1, ret2); tst_resm(TFAIL, msg); errors++; } } /* * Check to see if getgroups() succeeds and contains getgid's gid. */ TEST( getgroups(NGROUPS,gidset) ); if((entries = TEST_RETURN) == -1) { sprintf(msg, "getgroups(NGROUPS,gidset) returned -1 and errno = %d", errno); tst_resm(TFAIL, msg); errors++; } else if ( STD_FUNCTIONAL_TEST ) { /* * Check to see if getgroups() contains getgid(). */ group = getgid(); for(i = 0; i < entries; i++) { if(gidset[i] == group) { sprintf(msg, "getgroups(NGROUPS,gidset) ret %d contains gid %d (from getgid)", entries, group); tst_resm(TPASS, msg); break; } } if( i == entries ) { sprintf(msg, "getgroups(NGROUPS,gidset) ret %d, does not contain gid %d (from getgid)", entries, group); tst_resm(TFAIL,msg); errors++; } } } cleanup(); return 0; } /* end main() */