Beispiel #1
0
/* 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;
}
Beispiel #2
0
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);
}
Beispiel #3
0
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);
}
Beispiel #4
0
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);
}
Beispiel #5
0
/* {{{ 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;
}
Beispiel #6
0
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);
}
Beispiel #7
0
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();
}
Beispiel #8
0
/*
 * 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");
}
Beispiel #9
0
static void initialize_group_array()
{
	ngroups = getgroups(0, NULL);
	group_array = xrealloc(group_array, ngroups * sizeof(gid_t));
	getgroups(ngroups, group_array);
}
Beispiel #10
0
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:");
		if (pass == NULL)
			return;
		cryptpw = crypt(pass, grp->gr_passwd);
		if (cryptpw == NULL || strcmp(grp->gr_passwd, cryptpw) != 0) {
			fprintf(stderr, "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);
}
Beispiel #11
0
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;
}
Beispiel #12
0
/*
 * 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));
}
Beispiel #13
0
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;
}
Beispiel #14
0
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;
	}
}
Beispiel #15
0
//****************************************************************************
// 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
}
Beispiel #16
0
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;
		}
	}
}
Beispiel #17
0
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();
}
Beispiel #18
0
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);
}
Beispiel #19
0
C_Int_t Posix_ProcEnv_getgroupsN (void) {
  return getgroups (0, (gid_t*)NULL);
}
Beispiel #20
0
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;
}
Beispiel #21
0
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);
}
Beispiel #22
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;
    }
}
Beispiel #23
0
/*********************************************************************************************************
** 函数名称: __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);
}
Beispiel #24
0
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:'%s'  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() */
Beispiel #25
0
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);
}
Beispiel #26
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;
}
Beispiel #27
0
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:";

		p = getpass(pwprompt);

		if (pwd == NULL) {
			rval = 1;
			goto skip;
		}
#ifdef KERBEROS5
		if (login_krb5_get_tickets &&
		    k5login(pwd, instance, localhost, p) == 0) {
			rval = 0;
			got_tickets = 1;
		}
#endif
#if defined(KERBEROS5)
		if (got_tickets)
			goto skip;
#endif
#ifdef SKEY
		if (skey_haskey(username) == 0 &&
		    skey_passcheck(username, p) != -1) {
			rval = 0;
			goto skip;
		}
#endif
		if (!sflag && *pwd->pw_passwd != '\0' &&
		    !strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd)) {
			rval = 0;
			require_chpass = 1;
			goto skip;
		}
		rval = 1;

	skip:
		memset(p, 0, strlen(p));

		(void)setpriority(PRIO_PROCESS, 0, 0);

	ttycheck:
		/*
		 * If trying to log in as root without Kerberos,
		 * but with insecure terminal, refuse the login attempt.
		 */
		if (pwd && !rval && rootlogin && !rootterm(tty)) {
			(void)printf("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);
}
Beispiel #28
0
/*
 * 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;
}
Beispiel #29
0
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);
}
Beispiel #30
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() */