Esempio n. 1
1
/*
 * Convert a quota file from one format to another.
 */
int
quota_convert(struct quotafile *qf, int wordsize)
{
	struct quotafile *newqf;
	struct dqhdr64 dqh;
	struct dqblk dqblk;
	struct group *grp;
	int serrno, maxid, id, fd;

	/*
	 * Quotas must not be active and quotafile must be open
	 * for reading and writing.
	 */
	if ((qf->accmode & O_RDWR) != O_RDWR || qf->fd == -1) {
		errno = EBADF;
		return (-1);
	}
	if ((wordsize != 32 && wordsize != 64) ||
	     wordsize == qf->wordsize) {
		errno = EINVAL;
		return (-1);
	}
	maxid = quota_maxid(qf);
	if ((newqf = calloc(1, sizeof(*qf))) == NULL) {
		errno = ENOMEM;
		return (-1);
	}
	*newqf = *qf;
	snprintf(newqf->qfname, MAXPATHLEN + 1, "%s_%d.orig", qf->qfname,
	    qf->wordsize);
	if (rename(qf->qfname, newqf->qfname) < 0) {
		free(newqf);
		return (-1);
	}
	if ((newqf->fd = open(qf->qfname, O_RDWR|O_CREAT|O_TRUNC, 0)) < 0) {
		serrno = errno;
		goto error;
	}
	newqf->wordsize = wordsize;
	if (wordsize == 64) {
		memset(&dqh, 0, sizeof(dqh));
		memcpy(dqh.dqh_magic, Q_DQHDR64_MAGIC, sizeof(dqh.dqh_magic));
		dqh.dqh_version = htobe32(Q_DQHDR64_VERSION);
		dqh.dqh_hdrlen = htobe32(sizeof(struct dqhdr64));
		dqh.dqh_reclen = htobe32(sizeof(struct dqblk64));
		if (write(newqf->fd, &dqh, sizeof(dqh)) != sizeof(dqh)) {
			serrno = errno;
			goto error;
		}
	}
	grp = getgrnam(QUOTAGROUP);
	fchown(newqf->fd, 0, grp ? grp->gr_gid : 0);
	fchmod(newqf->fd, 0640);
	for (id = 0; id <= maxid; id++) {
		if ((quota_read(qf, &dqblk, id)) < 0)
			break;
		switch (newqf->wordsize) {
		case 32:
			if ((quota_write32(newqf, &dqblk, id)) < 0)
				break;
			continue;
		case 64:
			if ((quota_write64(newqf, &dqblk, id)) < 0)
				break;
			continue;
		default:
			errno = EINVAL;
			break;
		}
	}
	if (id < maxid) {
		serrno = errno;
		goto error;
	}
	/*
	 * Update the passed in quotafile to reference the new file
	 * of the converted format size.
	 */
	fd = qf->fd;
	qf->fd = newqf->fd;
	newqf->fd = fd;
	qf->wordsize = newqf->wordsize;
	quota_close(newqf);
	return (0);
error:
	/* put back the original file */
	(void) rename(newqf->qfname, qf->qfname);
	quota_close(newqf);
	errno = serrno;
	return (-1);
}
Esempio n. 2
0
void
create_config ()
{
  FILE *config_file = NULL;
  int tmp;

  if (!globalconfig.allow_registration) globalconfig.allow_registration = 1;
  globalconfig.menulist = NULL;
  globalconfig.banner_var_list = NULL;
  globalconfig.locale = NULL;
  globalconfig.defterm = NULL;

  globalconfig.shed_uid = (uid_t)-1;
  globalconfig.shed_gid = (gid_t)-1;

  globalconfig.sortmode = SORTMODE_USERNAME;
  globalconfig.utf8esc = 0;
  globalconfig.flowctrl = -1; /* undefined, don't touch it */

  if (config)
  {
    if ((config_file = fopen(config, "r")) != NULL)
    {
      yyin = config_file;
      yyparse();
      fclose(config_file);
      free (config);
    }
    else
    {
      fprintf(stderr, "ERROR: can't find or open %s for reading\n", config);
      debug_write("cannot read config file");
      graceful_exit(104);
      return;
    }
  }
  else
  {
#ifdef DEFCONFIG
    config = DEFCONFIG;
    if ((config_file = fopen(DEFCONFIG, "r")) != NULL)
    {
      yyin = config_file;
      yyparse();
      fclose(config_file);
    } else {
	fprintf(stderr, "ERROR: can't find or open %s for reading\n", config);
	debug_write("cannot read default config file");
	graceful_exit(105);
	return;
    }
#else
    num_games = 0;
    myconfig = calloc(1, sizeof(myconfig[0]));
    myconfig[0] = &defconfig;
    return;
#endif
  }

  if (!myconfig) /* a parse error occurred */
  {
      fprintf(stderr, "ERROR: configuration parsing failed\n");
      debug_write("config file parsing failed");
      graceful_exit(113);
  }

  if (!globalconfig.chroot) globalconfig.chroot = "/var/lib/dgamelaunch/";

  if (globalconfig.max == 0) globalconfig.max = 64000;
  if (globalconfig.max_newnick_len == 0) globalconfig.max_newnick_len = DGL_PLAYERNAMELEN;
  if (!globalconfig.dglroot) globalconfig.dglroot = "/dgldir/";
  if (!globalconfig.banner)  globalconfig.banner = "/dgl-banner";

  if (!globalconfig.passwd) globalconfig.passwd = "/etc/dgamelaunch.conf";

  if (!globalconfig.lockfile) globalconfig.lockfile = "/dgl-lock";
  if (!globalconfig.shed_user && globalconfig.shed_uid == (uid_t)-1)
	  {
	      struct passwd *pw;
	      if ((pw = getpwnam("games")))
		  globalconfig.shed_uid = pw->pw_uid;
	      else
		  globalconfig.shed_uid = 5; /* games uid in debian */
	  }

  if (!globalconfig.shed_group && globalconfig.shed_gid == (gid_t)-1)
	  {
	      struct group *gr;
	      if ((gr = getgrnam("games")))
		  globalconfig.shed_gid = gr->gr_gid;
	      else
		  globalconfig.shed_gid = 60; /* games gid in debian */
	  }

}
Esempio n. 3
0
static void TransformGidsToGroups(StringSet **list)
{
    StringSet *new_list = StringSetNew();
    StringSetIterator i = StringSetIteratorInit(*list);
    const char *data;
    for (data = StringSetIteratorNext(&i); data; data = StringSetIteratorNext(&i))
    {
        if (strlen(data) != strspn(data, "0123456789"))
        {
            // Cannot possibly be a gid.
            StringSetAdd(new_list, xstrdup(data));
            continue;
        }
        // In groups vs gids, groups take precedence. So check if it exists.
        errno = 0;
        struct group *group_info = getgrnam(data);
        if (!group_info)
        {
            switch (errno)
            {
            case 0:
            case ENOENT:
            case EBADF:
            case ESRCH:
            case EWOULDBLOCK:
            case EPERM:
                // POSIX is apparently ambiguous here. All values mean "not found".
                errno = 0;
                group_info = getgrgid(atoi(data));
                if (!group_info)
                {
                    switch (errno)
                    {
                    case 0:
                    case ENOENT:
                    case EBADF:
                    case ESRCH:
                    case EWOULDBLOCK:
                    case EPERM:
                        // POSIX is apparently ambiguous here. All values mean "not found".
                        //
                        // Neither group nor gid is found. This will lead to an error later, but we don't
                        // handle that here.
                        break;
                    default:
                        Log(LOG_LEVEL_ERR, "Error while checking group name '%s'. (getgrgid: '%s')", data, GetErrorStr());
                        StringSetDestroy(new_list);
                        return;
                    }
                }
                else
                {
                    // Replace gid with group name.
                    StringSetAdd(new_list, xstrdup(group_info->gr_name));
                }
                break;
            default:
                Log(LOG_LEVEL_ERR, "Error while checking group name '%s'. (getgrnam: '%s')", data, GetErrorStr());
                StringSetDestroy(new_list);
                return;
            }
        }
        else
        {
            StringSetAdd(new_list, xstrdup(data));
        }
    }
    StringSet *old_list = *list;
    *list = new_list;
    StringSetDestroy(old_list);
}
Esempio n. 4
0
// mknod in /dev based on a path like "/sys/block/hda/hda1"
static void make_device(char *path)
{
  char *device_name, *s, *temp;
  int major, minor, type, len, fd;
  int mode = 0660;
  uid_t uid = 0;
  gid_t gid = 0;

  // Try to read major/minor string

  temp = strrchr(path, '/');
  fd = open(path, O_RDONLY);
  *temp=0;
  temp = toybuf;
  len = read(fd, temp, 64);
  close(fd);
  if (len<1) return;
  temp[len] = 0;

  // Determine device name, type, major and minor

  device_name = strrchr(path, '/') + 1;
  type = path[5]=='c' ? S_IFCHR : S_IFBLK;
  major = minor = 0;
  sscanf(temp, "%u:%u", &major, &minor);

  // If we have a config file, look up permissions for this device

  if (CFG_MDEV_CONF) {
    char *conf, *pos, *end;

    // mmap the config file
    if (-1!=(fd = open("/etc/mdev.conf", O_RDONLY))) {
      len = fdlength(fd);
      conf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
      if (conf) {
        int line = 0;

        // Loop through lines in mmaped file
        for (pos = conf; pos-conf<len;) {
          int field;
          char *end2;

          line++;
          // find end of this line
          for(end = pos; end-conf<len && *end!='\n'; end++);

          // Three fields: regex, uid:gid, mode
          for (field = 3; field; field--) {
            // Skip whitespace
            while (pos<end && isspace(*pos)) pos++;
            if (pos==end || *pos=='#') break;
            for (end2 = pos;
              end2<end && !isspace(*end2) && *end2!='#'; end2++);
            switch(field) {
              // Regex to match this device
              case 3:
              {
                char *regex = strndup(pos, end2-pos);
                regex_t match;
                regmatch_t off;
                int result;

                // Is this it?
                xregcomp(&match, regex, REG_EXTENDED);
                result=regexec(&match, device_name, 1, &off, 0);
                regfree(&match);
                free(regex);

                // If not this device, skip rest of line
                if (result || off.rm_so
                  || off.rm_eo!=strlen(device_name))
                    goto end_line;

                break;
              }
              // uid:gid
              case 2:
              {
                char *s2;

                // Find :
                for(s = pos; s<end2 && *s!=':'; s++);
                if (s==end2) goto end_line;

                // Parse UID
                uid = strtoul(pos,&s2,10);
                if (s!=s2) {
                  struct passwd *pass;
                  char *str = strndup(pos, s-pos);
                  pass = getpwnam(str);
                  free(str);
                  if (!pass) goto end_line;
                  uid = pass->pw_uid;
                }
                s++;
                // parse GID
                gid = strtoul(s,&s2,10);
                if (end2!=s2) {
                  struct group *grp;
                  char *str = strndup(s, end2-s);
                  grp = getgrnam(str);
                  free(str);
                  if (!grp) goto end_line;
                  gid = grp->gr_gid;
                }
                break;
              }
              // mode
              case 1:
              {
                mode = strtoul(pos, &pos, 8);
                if (pos!=end2) goto end_line;
                goto found_device;
              }
            }
            pos=end2;
          }
end_line:
          // Did everything parse happily?
          if (field && field!=3) error_exit("Bad line %d", line);

          // Next line
          pos = ++end;
        }
found_device:
        munmap(conf, len);
      }
      close(fd);
    }
  }

  sprintf(temp, "/dev/%s", device_name);
  if (mknod(temp, mode | type, makedev(major, minor)) && errno != EEXIST)
    perror_exit("mknod %s failed", temp);

  if (CFG_MDEV_CONF) mode=chown(temp, uid, gid);
}
Esempio n. 5
0
// Init unix related stuff.
// Daemon, chroot, setgid and setuid code (-d, -t, -g, -u)
// was copied from bind (DNS server) sources.
static void SV_System_Init(void)
{
	int j;
	qbool ind;
	uid_t user_id = 0;
	gid_t group_id = 0;
	struct passwd *pw = NULL;
	struct group *gr;
	char *user_name = NULL, *group_name = NULL, *chroot_dir;

	// daemon
	if (COM_CheckParm ("-d"))
	{
		switch (fork())
		{
		case -1:
			exit(-1); // Error, do normal exit().
		case 0:
			break; // Child, continue process.
		default:
			_exit(0); // Parent, for some reason we prefer here "limited" clean up with _exit().
		}

		if (setsid() == -1)
			Sys_Printf("setsid: %s\n", strerror(qerrno));

		if ((j = open(_PATH_DEVNULL, O_RDWR)) != -1)
		{
			(void)dup2(j, STDIN_FILENO);
			(void)dup2(j, STDOUT_FILENO);
			(void)dup2(j, STDERR_FILENO);
			if (j > 2)
				(void)close(j);
			//isdaemon = true;
			do_stdin = false;
		}
	}

	// setgid
	j = COM_CheckParm ("-g");
	if (j && j + 1 < com_argc)
	{
		ind = true;
		group_name = com_argv[j + 1];
		if (only_digits(group_name))
			group_id = Q_atoi(group_name);
		else
		{
			if (!(gr = getgrnam(group_name)))
			{
				Sys_Printf("WARNING: group \"%s\" unknown\n", group_name);
				ind = false;
			}
			else
				group_id = gr->gr_gid;
		}
		if (ind)
			if (setgid(group_id) < 0)
				Sys_Printf("WARNING: Can't setgid to group \"%s\": %s\n",
							group_name, strerror(qerrno));
	}

	// setuid - only resolve name
	ind = false;
	j = COM_CheckParm ("-u");
	if (j && j + 1 < com_argc)
	{
		ind = true;
		user_name = com_argv[j + 1];
		j = only_digits(user_name);
		if (j)
		{
			user_id = Q_atoi(user_name);
			pw = getpwuid(user_id);
		}
		if (!j || !pw)
		{
			if (!(pw = getpwnam(user_name)))
			{
				if (j)
					Sys_Printf("WARNING: user with uid %u unknown, but we will try to setuid\n",
								(unsigned)user_id);
				else
				{
					Sys_Printf("WARNING: user \"%s\" unknown\n", user_name);
					ind = false;
				}
			}
			else
				user_id = pw->pw_uid;
		}

		if (ind)
		{
			if (pw)
			{
				if (!group_name)
				{
					group_id = pw->pw_gid;
					if (setgid(group_id) < 0)
						Sys_Printf("WARNING: Can't setgid to group \"%s\": %s\n",
									group_name, strerror(qerrno));
				}
				if (!getuid() && initgroups(pw->pw_name, group_id) < 0)
					Sys_Printf("WARNING: Can't initgroups(%s, %d): %s",
								user_name, (unsigned)group_id, strerror(qerrno));
			}
		}
	}

	// chroot
	j = COM_CheckParm ("-t");
	if (j && j + 1 < com_argc)
	{
		chroot_dir = com_argv[j + 1];
		if (chroot(chroot_dir) < 0)
			Sys_Printf("chroot %s failed: %s\n", chroot_dir, strerror(qerrno));
		else
			if (chdir("/") < 0)
				Sys_Printf("chdir(\"/\") to %s failed: %s\n", chroot_dir, strerror(qerrno));
	}

	// setuid - we can't setuid before chroot and
	// can't resolve uid/gid from user/group names after chroot
	if (ind)
	{
		if (setuid(user_id) < 0)
			Sys_Printf("WARNING: Can't setuid to user \"%s\": %s\n",
						user_name, strerror(qerrno));
	}
}
Esempio n. 6
0
static bool
parseconfig (const char *dir, const char *file)
{
  str cf;
  if (!file)
    return false;
  if (file[0] == '/')
    cf = file;
  else if (!dir)
    return false;
  else
    cf = strbuf ("%s/%s", dir, file);

  if (access (cf, F_OK) < 0) {
    if (errno != ENOENT)
      warn << cf << ": " << strerror (errno) << "\n";
    return false;
  }

  conftab ct;

  bool dirset = false;
  ct.add ("RSASize", &sfs_rsasize, sfs_minrsasize, sfs_maxrsasize)
    .add ("DLogSize", &sfs_dlogsize, sfs_mindlogsize, sfs_maxdlogsize)
    .add ("PwdCost", &sfs_pwdcost, 0, 32)
    .add ("LogPriority", &syslog_priority)
    .add ("sfsdir", wrap (&got_sfsdir, &dirset));

  str uid, gid, nuid, ngid, resvgidlow, resvgidhigh;

  bool errors = false;
  parseargs pa (cf);
  int line;
  vec<str> av;
  while (pa.getline (&av, &line)) {
    if (!strcasecmp (av[0], "sfsuser")) {
      if (uid) {
	errors = true;
	warn << cf << ":" << line << ": Duplicate sfsuser directive\n";
      }
      else if (av.size () == 2)
	uid = gid = av[1];
      else if (av.size () == 3) {
	uid = av[1];
	gid = av[2];
      }
      else {
	errors = true;
	warn << cf << ":" << line << ": usage: sfsuser user [group]\n";
      }
    }
    else if (!strcasecmp (av[0], "anonuser")) {
      if (nuid) {
	errors = true;
	warn << cf << ":" << line << ": Duplicate anonuser directive\n";
      }
      else if (av.size () == 2)
	nuid = av[1];
      else if (av.size () == 3) {
	nuid = av[1];
	ngid = av[2];
      }
      else {
	errors = true;
	warn << cf << ":" << line << ": usage: anonuser user [group]\n";
	continue;
      }

      gid_t g;
      if (ngid) {
	if (!convertint (ngid, &g)) {
	  if (struct group *gr = getgrnam (ngid))
	    g = gr->gr_gid;
	  else {
	    errors = true;
	    warn << cf << ":" << line << ": no group " << ngid << "\n";
	    ngid = NULL;
	  }
	}
      }

      uid_t u;
      if (!convertint (nuid, &u)) {
	struct passwd *pw = getpwnam (nuid);
	if (!pw) {
	  errors = true;
	  warn << cf << ":" << line << ": no user " << nuid << "\n";
	  continue;
	}
	nobody_uid = pw->pw_uid;
	if (ngid)
	  nobody_gid = g;
	else
	  nobody_gid = pw->pw_gid;
      }
      else if (ngid) {
	nobody_uid = u;
	nobody_gid = g;
      }
      else {
	errors = true;
	warn << cf << ":" << line << ": Must specify gid with numeric uid";
	continue;
      }
    }
    else if (!strcasecmp (av[0], "resvgids")) {
      if (resvgidhigh) {
	errors = true;
	warn << cf << ":" << line << ": Duplicate resvgids directive\n";
      }
      else if (av.size () != 3) {
	errors = true;
	warn << cf << ":" << line << ": usage: resvgids lower upper\n";
      }
      else {
	resvgidlow = av[1];
	resvgidhigh = av[2];
      }
    }
    else if (!ct.match (av, cf, line, &errors)) {
      warn << cf << ":" << line << ": Unknown directive '"
	   << av[0] << "'\n";
    }
  }    

  if (errors)
    warn << "errors in " << cf << "\n";

  if (uid)
    idlookup (uid, gid);
  resvgidset (resvgidlow, resvgidhigh);
  return true;
}
Esempio n. 7
0
void
chown_cmd (void)
{
    char *fname;
    struct stat sf_stat;
    Dlg_head *ch_dlg;
    uid_t new_user;
    gid_t new_group;
    char buffer[BUF_TINY];

    do
    {                           /* do while any files remaining */
        ch_dlg = init_chown ();
        new_user = new_group = -1;

        if (current_panel->marked)
            fname = next_file ();       /* next marked file */
        else
            fname = selection (current_panel)->fname;   /* single file */

        if (mc_stat (fname, &sf_stat) != 0)
        {                       /* get status of file */
            destroy_dlg (ch_dlg);
            break;
        }

        /* select in listboxes */
        listbox_select_entry (l_user, listbox_search_text (l_user, get_owner (sf_stat.st_uid)));
        listbox_select_entry (l_group, listbox_search_text (l_group, get_group (sf_stat.st_gid)));

        chown_label (0, str_trunc (fname, 15));
        chown_label (1, str_trunc (get_owner (sf_stat.st_uid), 15));
        chown_label (2, str_trunc (get_group (sf_stat.st_gid), 15));
        size_trunc_len (buffer, 15, sf_stat.st_size, 0, panels_options.kilobyte_si);
        chown_label (3, buffer);
        chown_label (4, string_perm (sf_stat.st_mode));

        switch (run_dlg (ch_dlg))
        {
        case B_CANCEL:
            end_chown = 1;
            break;

        case B_SETUSR:
            {
                struct passwd *user;
                char *text;

                listbox_get_current (l_user, &text, NULL);
                user = getpwnam (text);
                if (user)
                {
                    new_user = user->pw_uid;
                    apply_chowns (new_user, new_group);
                }
                break;
            }

        case B_SETGRP:
            {
                struct group *grp;
                char *text;

                listbox_get_current (l_group, &text, NULL);
                grp = getgrnam (text);
                if (grp)
                {
                    new_group = grp->gr_gid;
                    apply_chowns (new_user, new_group);
                }
                break;
            }

        case B_SETALL:
        case B_ENTER:
            {
                struct group *grp;
                struct passwd *user;
                char *text;

                listbox_get_current (l_group, &text, NULL);
                grp = getgrnam (text);
                if (grp)
                    new_group = grp->gr_gid;
                listbox_get_current (l_user, &text, NULL);
                user = getpwnam (text);
                if (user)
                    new_user = user->pw_uid;
                if (ch_dlg->ret_value == B_ENTER)
                {
                    need_update = 1;
                    if (mc_chown (fname, new_user, new_group) == -1)
                        message (D_ERROR, MSG_ERROR, _("Cannot chown \"%s\"\n%s"),
                                 fname, unix_error_string (errno));
                }
                else
                    apply_chowns (new_user, new_group);
                break;
            }
        }                       /* switch */

        if (current_panel->marked && ch_dlg->ret_value != B_CANCEL)
        {
            do_file_mark (current_panel, current_file, 0);
            need_update = 1;
        }

        destroy_dlg (ch_dlg);
    }
    while (current_panel->marked && !end_chown);

    chown_done ();
}
Esempio n. 8
0
/*
 * Parse the argument to the -R or --owner flag.
 *
 * The format is one of the following:
 *   <username|uid>    - Override user but not group
 *   <username>:   - Override both, group is user's default group
 *   <uid>:    - Override user but not group
 *   <username|uid>:<groupname|gid> - Override both
 *   :<groupname|gid>  - Override group but not user
 *
 * Where uid/gid are decimal representations and groupname/username
 * are names to be looked up in system database.  Note that we try
 * to look up an argument as a name first, then try numeric parsing.
 *
 * A period can be used instead of the colon.
 *
 * Sets uid/gid return as appropriate, -1 indicates uid/gid not specified.
 * TODO: If the spec uses uname/gname, then return those to the caller
 * as well.  If the spec provides uid/gid, just return names as NULL.
 *
 * Returns NULL if no error, otherwise returns error string for display.
 *
 */
const char *
owner_parse(const char *spec, int *uid, int *gid)
{
	static char errbuff[128];
	const char *u, *ue, *g;

	*uid = -1;
	*gid = -1;

	if (spec[0] == '\0')
		return ("Invalid empty user/group spec");

	/*
	 * Split spec into [user][:.][group]
	 *  u -> first char of username, NULL if no username
	 *  ue -> first char after username (colon, period, or \0)
	 *  g -> first char of group name
	 */
	if (*spec == ':' || *spec == '.') {
		/* If spec starts with ':' or '.', then just group. */
		ue = u = NULL;
		g = spec + 1;
	} else {
		/* Otherwise, [user] or [user][:] or [user][:][group] */
		ue = u = spec;
		while (*ue != ':' && *ue != '.' && *ue != '\0')
			++ue;
		g = ue;
		if (*g != '\0') /* Skip : or . to find first char of group. */
			++g;
	}

	if (u != NULL) {
		/* Look up user: ue is first char after end of user. */
		char *user;
		struct passwd *pwent;

		user = (char *)malloc(ue - u + 1);
		if (user == NULL)
			return ("Couldn't allocate memory");
		memcpy(user, u, ue - u);
		user[ue - u] = '\0';
		if ((pwent = getpwnam(user)) != NULL) {
			*uid = pwent->pw_uid;
			if (*ue != '\0')
				*gid = pwent->pw_gid;
		} else {
			char *end;
			errno = 0;
			*uid = (int)strtoul(user, &end, 10);
			if (errno || *end != '\0') {
				snprintf(errbuff, sizeof(errbuff),
				    "Couldn't lookup user ``%s''", user);
				errbuff[sizeof(errbuff) - 1] = '\0';
				free(user);
				return (errbuff);
			}
		}
		free(user);
	}

	if (*g != '\0') {
		struct group *grp;
		if ((grp = getgrnam(g)) != NULL) {
			*gid = grp->gr_gid;
		} else {
			char *end;
			errno = 0;
			*gid = (int)strtoul(g, &end, 10);
			if (errno || *end != '\0') {
				snprintf(errbuff, sizeof(errbuff),
				    "Couldn't lookup group ``%s''", g);
				errbuff[sizeof(errbuff) - 1] = '\0';
				return (errbuff);
			}
		}
	}
	return (NULL);
}
Esempio n. 9
0
int main(int argc, char **argv)
{
        static struct cl_engine *engine = NULL;
	const struct optstruct *opt;
#ifndef	_WIN32
        struct passwd *user = NULL;
	struct sigaction sa;
	struct rlimit rlim;
#endif
	time_t currtime;
	const char *dbdir, *cfgfile;
	char *pua_cats = NULL, *pt;
	int ret, tcpsock = 0, localsock = 0, i, min_port, max_port;
	unsigned int sigs = 0;
	int lsockets[2], nlsockets = 0;
	unsigned int dboptions = 0;
#ifdef C_LINUX
	struct stat sb;
#endif

    if(check_flevel())
	exit(1);

#ifndef _WIN32
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = SIG_IGN;
    sigaction(SIGHUP, &sa, NULL);
    sigaction(SIGUSR2, &sa, NULL);
#endif

    if((opts = optparse(NULL, argc, argv, 1, OPT_CLAMD, 0, NULL)) == NULL) {
	mprintf("!Can't parse command line options\n");
	return 1;
    }

    if(optget(opts, "help")->enabled) {
    	help();
	optfree(opts);
	return 0;
    }

    if(optget(opts, "debug")->enabled) {
#if defined(C_LINUX)
	/* [email protected]: create a dump if needed */
	rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
	if(setrlimit(RLIMIT_CORE, &rlim) < 0)
	    perror("setrlimit");
#endif
	debug_mode = 1;
    }

    /* parse the config file */
    cfgfile = optget(opts, "config-file")->strarg;
    pt = strdup(cfgfile);
    if((opts = optparse(cfgfile, 0, NULL, 1, OPT_CLAMD, 0, opts)) == NULL) {
	fprintf(stderr, "ERROR: Can't open/parse the config file %s\n", pt);
	free(pt);
	return 1;
    }
    free(pt);

    if(optget(opts, "version")->enabled) {
	print_version(optget(opts, "DatabaseDirectory")->strarg);
	optfree(opts);
	return 0;
    }

    /* drop privileges */
#ifndef _WIN32
    if(geteuid() == 0 && (opt = optget(opts, "User"))->enabled) {
	if((user = getpwnam(opt->strarg)) == NULL) {
	    fprintf(stderr, "ERROR: Can't get information about user %s.\n", opt->strarg);
	    optfree(opts);
	    return 1;
	}

	if(optget(opts, "AllowSupplementaryGroups")->enabled) {
#ifdef HAVE_INITGROUPS
	    if(initgroups(opt->strarg, user->pw_gid)) {
		fprintf(stderr, "ERROR: initgroups() failed.\n");
		optfree(opts);
		return 1;
	    }
#else
	    mprintf("!AllowSupplementaryGroups: initgroups() is not available, please disable AllowSupplementaryGroups in %s\n", cfgfile);
	    optfree(opts);
	    return 1;
#endif
	} else {
#ifdef HAVE_SETGROUPS
	    if(setgroups(1, &user->pw_gid)) {
		fprintf(stderr, "ERROR: setgroups() failed.\n");
		optfree(opts);
		return 1;
	    }
#endif
	}

	if(setgid(user->pw_gid)) {
	    fprintf(stderr, "ERROR: setgid(%d) failed.\n", (int) user->pw_gid);
	    optfree(opts);
	    return 1;
	}

	if(setuid(user->pw_uid)) {
	    fprintf(stderr, "ERROR: setuid(%d) failed.\n", (int) user->pw_uid);
	    optfree(opts);
	    return 1;
	}
    }
#endif

    /* initialize logger */
    logg_lock = !optget(opts, "LogFileUnlock")->enabled;
    logg_time = optget(opts, "LogTime")->enabled;
    logok = optget(opts, "LogClean")->enabled;
    logg_size = optget(opts, "LogFileMaxSize")->numarg;
    logg_verbose = mprintf_verbose = optget(opts, "LogVerbose")->enabled;
    mprintf_send_timeout = optget(opts, "SendBufTimeout")->numarg;

    do { /* logger initialized */

    if((opt = optget(opts, "LogFile"))->enabled) {
	char timestr[32];
	logg_file = opt->strarg;
	if(!cli_is_abspath(logg_file)) {
	    fprintf(stderr, "ERROR: LogFile requires full path.\n");
	    ret = 1;
	    break;
	}
	time(&currtime);
	if(logg("#+++ Started at %s", cli_ctime(&currtime, timestr, sizeof(timestr)))) {
	    fprintf(stderr, "ERROR: Can't initialize the internal logger\n");
	    ret = 1;
	    break;
	}
    } else
	logg_file = NULL;

    if (optget(opts,"DevLiblog")->enabled)
	cl_set_clcb_msg(msg_callback);
    if((ret = cl_init(CL_INIT_DEFAULT))) {
	logg("!Can't initialize libclamav: %s\n", cl_strerror(ret));
	ret = 1;
	break;
    }

    if(optget(opts, "Debug")->enabled) /* enable debug messages in libclamav */ {
	cl_debug();
	logg_verbose = 2;
    }

#if defined(USE_SYSLOG) && !defined(C_AIX)
    if(optget(opts, "LogSyslog")->enabled) {
	    int fac = LOG_LOCAL6;

	opt = optget(opts, "LogFacility");
	if((fac = logg_facility(opt->strarg)) == -1) {
	    logg("!LogFacility: %s: No such facility.\n", opt->strarg);
	    ret = 1;
	    break;
	}

	openlog("clamd", LOG_PID, fac);
	logg_syslog = 1;
    }
#endif

#ifdef C_LINUX
    procdev = 0;
    if(stat("/proc", &sb) != -1 && !sb.st_size)
	procdev = sb.st_dev;
#endif

    /* check socket type */

    if(optget(opts, "TCPSocket")->enabled)
	tcpsock = 1;

    if(optget(opts, "LocalSocket")->enabled)
	localsock = 1;

    if(!tcpsock && !localsock) {
	logg("!Please define server type (local and/or TCP).\n");
	ret = 1;
	break;
    }

    logg("#clamd daemon %s (OS: "TARGET_OS_TYPE", ARCH: "TARGET_ARCH_TYPE", CPU: "TARGET_CPU_TYPE")\n", get_version());

#ifndef _WIN32
    if(user)
	logg("#Running as user %s (UID %u, GID %u)\n", user->pw_name, user->pw_uid, user->pw_gid);
#endif

#if defined(RLIMIT_DATA) && defined(C_BSD)
    if (getrlimit(RLIMIT_DATA, &rlim) == 0) {
       /* bb #1941.
        * On 32-bit FreeBSD if you set ulimit -d to >2GB then mmap() will fail
        * too soon (after ~120 MB).
        * Set limit lower than 2G if on 32-bit */
       uint64_t lim = rlim.rlim_cur;
       if (sizeof(void*) == 4 &&
           lim > (1ULL << 31)) {
           rlim.rlim_cur = 1ULL << 31;
           if (setrlimit(RLIMIT_DATA, &rlim) < 0)
               logg("!setrlimit(RLIMIT_DATA) failed: %s\n", strerror(errno));
           else
               logg("Running on 32-bit system, and RLIMIT_DATA > 2GB, lowering to 2GB!\n");
       }
    }
#endif


    if(logg_size)
	logg("#Log file size limited to %d bytes.\n", logg_size);
    else
	logg("#Log file size limit disabled.\n");

    min_port = optget(opts, "StreamMinPort")->numarg;
    max_port = optget(opts, "StreamMaxPort")->numarg;
    if (min_port < 1024 || min_port > max_port || max_port > 65535) {
	logg("!Invalid StreamMinPort/StreamMaxPort: %d, %d\n", min_port, max_port);
	ret = 1;
	break;
    }

    if(!(engine = cl_engine_new())) {
	logg("!Can't initialize antivirus engine\n");
	ret = 1;
	break;
    }

    /* load the database(s) */
    dbdir = optget(opts, "DatabaseDirectory")->strarg;
    logg("#Reading databases from %s\n", dbdir);

    if(optget(opts, "DetectPUA")->enabled) {
	dboptions |= CL_DB_PUA;

	if((opt = optget(opts, "ExcludePUA"))->enabled) {
	    dboptions |= CL_DB_PUA_EXCLUDE;
	    i = 0;
	    logg("#Excluded PUA categories:");
	    while(opt) {
		if(!(pua_cats = realloc(pua_cats, i + strlen(opt->strarg) + 3))) {
		    logg("!Can't allocate memory for pua_cats\n");
		    cl_engine_free(engine);
		    ret = 1;
		    break;
		}
		logg("# %s", opt->strarg);
		sprintf(pua_cats + i, ".%s", opt->strarg);
		i += strlen(opt->strarg) + 1;
		pua_cats[i] = 0;
		opt = opt->nextarg;
	    }
	    if (ret)
		break;
	    logg("#\n");
	    pua_cats[i] = '.';
	    pua_cats[i + 1] = 0;
	}

	if((opt = optget(opts, "IncludePUA"))->enabled) {
	    if(pua_cats) {
		logg("!ExcludePUA and IncludePUA cannot be used at the same time\n");
		free(pua_cats);
		ret = 1;
		break;
	    }
	    dboptions |= CL_DB_PUA_INCLUDE;
	    i = 0;
	    logg("#Included PUA categories:");
	    while(opt) {
		if(!(pua_cats = realloc(pua_cats, i + strlen(opt->strarg) + 3))) {
		    logg("!Can't allocate memory for pua_cats\n");
		    ret = 1;
		    break;
		}
		logg("# %s", opt->strarg);
		sprintf(pua_cats + i, ".%s", opt->strarg);
		i += strlen(opt->strarg) + 1;
		pua_cats[i] = 0;
		opt = opt->nextarg;
	    }
	    if (ret)
		break;
	    logg("#\n");
	    pua_cats[i] = '.';
	    pua_cats[i + 1] = 0;
	}

	if(pua_cats) {
	    if((ret = cl_engine_set_str(engine, CL_ENGINE_PUA_CATEGORIES, pua_cats))) {
		logg("!cli_engine_set_str(CL_ENGINE_PUA_CATEGORIES) failed: %s\n", cl_strerror(ret));
		free(pua_cats);
		ret = 1;
		break;
	    }
	    free(pua_cats);
	}
    } else {
	logg("#Not loading PUA signatures.\n");
    }

    if(optget(opts, "OfficialDatabaseOnly")->enabled) {
	dboptions |= CL_DB_OFFICIAL_ONLY;
	logg("#Only loading official signatures.\n");
    }

    /* set the temporary dir */
    if((opt = optget(opts, "TemporaryDirectory"))->enabled) {
	if((ret = cl_engine_set_str(engine, CL_ENGINE_TMPDIR, opt->strarg))) {
	    logg("!cli_engine_set_str(CL_ENGINE_TMPDIR) failed: %s\n", cl_strerror(ret));
	    ret = 1;
	    break;
	}
    }

    cl_engine_set_clcb_hash(engine, hash_callback);
    detstats_clear();

    if(optget(opts, "LeaveTemporaryFiles")->enabled)
	cl_engine_set_num(engine, CL_ENGINE_KEEPTMP, 1);

    if(optget(opts, "PhishingSignatures")->enabled)
	dboptions |= CL_DB_PHISHING;
    else
	logg("#Not loading phishing signatures.\n");

    if(optget(opts,"Bytecode")->enabled) {
	dboptions |= CL_DB_BYTECODE;
	if((opt = optget(opts,"BytecodeSecurity"))->enabled) {
	    enum bytecode_security s;
	    if (!strcmp(opt->strarg, "TrustSigned")) {
		s = CL_BYTECODE_TRUST_SIGNED;
		logg("#Bytecode: Security mode set to \"TrustSigned\".\n");
	    } else if (!strcmp(opt->strarg, "Paranoid")) {
		s = CL_BYTECODE_TRUST_NOTHING;
		logg("#Bytecode: Security mode set to \"Paranoid\".\n");
	    } else {
		logg("!Unable to parse bytecode security setting:%s\n",
		    opt->strarg);
		ret = 1;
		break;
	    }
	    if ((ret = cl_engine_set_num(engine, CL_ENGINE_BYTECODE_SECURITY, s))) {
		logg("^Invalid bytecode security setting %s: %s\n", opt->strarg, cl_strerror(ret));
		ret = 1;
		break;
	    }
	}
	if((opt = optget(opts,"BytecodeUnsigned"))->enabled) {
	    dboptions |= CL_DB_BYTECODE_UNSIGNED;
	    logg("#Bytecode: Enabled support for unsigned bytecode.\n");
	}
	if((opt = optget(opts,"BytecodeMode"))->enabled) {
	    enum bytecode_mode mode;
	    if (!strcmp(opt->strarg, "ForceJIT"))
		mode = CL_BYTECODE_MODE_JIT;
	    else if(!strcmp(opt->strarg, "ForceInterpreter"))
		mode = CL_BYTECODE_MODE_INTERPRETER;
	    else if(!strcmp(opt->strarg, "Test"))
		mode = CL_BYTECODE_MODE_TEST;
	    else
		mode = CL_BYTECODE_MODE_AUTO;
	    cl_engine_set_num(engine, CL_ENGINE_BYTECODE_MODE, mode);
	}
	if((opt = optget(opts,"BytecodeTimeout"))->enabled) {
	    cl_engine_set_num(engine, CL_ENGINE_BYTECODE_TIMEOUT, opt->numarg);
	}
    } else
	logg("#Bytecode support disabled.\n");

    if(optget(opts,"PhishingScanURLs")->enabled)
	dboptions |= CL_DB_PHISHING_URLS;
    else
	logg("#Disabling URL based phishing detection.\n");

    if(optget(opts,"DevACOnly")->enabled) {
	logg("#Only using the A-C matcher.\n");
	cl_engine_set_num(engine, CL_ENGINE_AC_ONLY, 1);
    }

    if((opt = optget(opts, "DevACDepth"))->enabled) {
        cl_engine_set_num(engine, CL_ENGINE_AC_MAXDEPTH, opt->numarg);
	logg("#Max A-C depth set to %u\n", (unsigned int) opt->numarg);
    }

    if((ret = cl_load(dbdir, engine, &sigs, dboptions))) {
	logg("!%s\n", cl_strerror(ret));
	ret = 1;
	break;
    }

    logg("#Loaded %u signatures.\n", sigs);
    if((ret = cl_engine_compile(engine)) != 0) {
	logg("!Database initialization error: %s\n", cl_strerror(ret));
	ret = 1;
	break;
    }

    if(tcpsock) {
	if ((lsockets[nlsockets] = tcpserver(opts)) == -1) {
	    ret = 1;
	    break;
	}
	nlsockets++;
    }
#ifndef _WIN32
    if(localsock) {
	mode_t sock_mode, umsk = umask(0777); /* socket is created with 000 to avoid races */
	if ((lsockets[nlsockets] = localserver(opts)) == -1) {
	    ret = 1;
	    umask(umsk);
	    break;
	}
	umask(umsk); /* restore umask */
	if(optget(opts, "LocalSocketGroup")->enabled) {
	    char *gname = optget(opts, "LocalSocketGroup")->strarg, *end;
	    gid_t sock_gid = strtol(gname, &end, 10);
	    if(*end) {
		struct group *pgrp = getgrnam(gname);
		if(!pgrp) {
		    logg("!Unknown group %s\n", gname);
		    ret = 1;
		    break;
		}
		sock_gid = pgrp->gr_gid;
	    }
	    if(chown(optget(opts, "LocalSocket")->strarg, -1, sock_gid)) {
		logg("!Failed to change socket ownership to group %s\n", gname);
		ret = 1;
		break;
	    }
	}
	if(optget(opts, "LocalSocketMode")->enabled) {
	    char *end;
	    sock_mode = strtol(optget(opts, "LocalSocketMode")->strarg, &end, 8);
	    if(*end) {
		logg("!Invalid LocalSocketMode %s\n", optget(opts, "LocalSocketMode")->strarg);
		ret = 1;
		break;
	    }
	} else
	    sock_mode = 0777 /* & ~umsk*/; /* conservative default: umask was 0 in clamd < 0.96 */

	if(chmod(optget(opts, "LocalSocket")->strarg, sock_mode & 0666)) {
	    logg("!Cannot set socket permission to %s\n", optget(opts, "LocalSocketMode")->strarg);
	    ret = 1;
	    break;
	}

	nlsockets++;
    }

    /* fork into background */
    if(!optget(opts, "Foreground")->enabled) {
#ifdef C_BSD	    
	/* workaround for OpenBSD bug, see https://wwws.clamav.net/bugzilla/show_bug.cgi?id=885 */
	for(ret=0;ret<nlsockets;ret++) {
		fcntl(lsockets[ret], F_SETFL, fcntl(lsockets[ret], F_GETFL) | O_NONBLOCK);
	}
#endif
	gengine = engine;
	atexit(free_engine);
	if(daemonize() == -1) {
	    logg("!daemonize() failed: %s\n", strerror(errno));
	    ret = 1;
	    break;
	}
	gengine = NULL;
#ifdef C_BSD
	for(ret=0;ret<nlsockets;ret++) {
		fcntl(lsockets[ret], F_SETFL, fcntl(lsockets[ret], F_GETFL) & ~O_NONBLOCK);
	}
#endif
	if(!debug_mode)
	    if(chdir("/") == -1)
		logg("^Can't change current working directory to root\n");

    } else
        foreground = 1;
#endif

    ret = recvloop_th(lsockets, nlsockets, engine, dboptions, opts);

    } while (0);

    logg("*Closing the main socket%s.\n", (nlsockets > 1) ? "s" : "");

    for (i = 0; i < nlsockets; i++) {
	closesocket(lsockets[i]);
    }

#ifndef _WIN32
    if(nlsockets && localsock) {
	opt = optget(opts, "LocalSocket");
	if(unlink(opt->strarg) == -1)
	    logg("!Can't unlink the socket file %s\n", opt->strarg);
	else
	    logg("Socket file removed.\n");
    }
#endif

    logg_close();
    optfree(opts);

    return ret;
}
Esempio n. 10
0
static int fpm_unix_conf_wp(struct fpm_worker_pool_s *wp) /* {{{ */
{
	int is_root = !geteuid();

	if (is_root) {
		if (wp->config->user && *wp->config->user) {
			if (strlen(wp->config->user) == strspn(wp->config->user, "0123456789")) {
				wp->set_uid = strtoul(wp->config->user, 0, 10);
			} else {
				struct passwd *pwd;

				pwd = getpwnam(wp->config->user);
				if (!pwd) {
					zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] cannot get uid for user '%s'", wp->config->name, wp->config->user);
					return -1;
				}

				wp->set_uid = pwd->pw_uid;
				wp->set_gid = pwd->pw_gid;

				wp->user = strdup(pwd->pw_name);
				wp->home = strdup(pwd->pw_dir);
			}
		}

		if (wp->config->group && *wp->config->group) {
			if (strlen(wp->config->group) == strspn(wp->config->group, "0123456789")) {
				wp->set_gid = strtoul(wp->config->group, 0, 10);
			} else {
				struct group *grp;

				grp = getgrnam(wp->config->group);
				if (!grp) {
					zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] cannot get gid for group '%s'", wp->config->name, wp->config->group);
					return -1;
				}
				wp->set_gid = grp->gr_gid;
			}
		}

#ifndef I_REALLY_WANT_ROOT_PHP
		if (wp->set_uid == 0 || wp->set_gid == 0) {
			zlog(ZLOG_STUFF, ZLOG_ERROR, "[pool %s] please specify user and group other than root", wp->config->name);
			return -1;
		}
#endif
	} else { /* not root */
		if (wp->config->user && *wp->config->user) {
			zlog(ZLOG_STUFF, ZLOG_WARNING, "[pool %s] 'user' directive is ignored", wp->config->name);
		}
		if (wp->config->group && *wp->config->group) {
			zlog(ZLOG_STUFF, ZLOG_WARNING, "[pool %s] 'group' directive is ignored", wp->config->name);
		}
		if (wp->config->chroot && *wp->config->chroot) {
			zlog(ZLOG_STUFF, ZLOG_WARNING, "[pool %s] 'chroot' directive is ignored", wp->config->name);
		}

		{ /* set up HOME and USER anyway */
			struct passwd *pwd;

			pwd = getpwuid(getuid());
			if (pwd) {
				wp->user = strdup(pwd->pw_name);
				wp->home = strdup(pwd->pw_dir);
			}
		}
	}
	return 0;
}
Esempio n. 11
0
M3_DLL_EXPORT m3_group_t* __cdecl
Ugrp__getgrnam(m3_group_t* m3group, const char* name)
{
    Scheduler__DisableSwitching();
    return native_to_m3(getgrnam(name), m3group);
}
Esempio n. 12
0
// Main Function of threads
void *access_change(void *par)
{
	int t;
	mode_t droits_acces;
	struct param *p ;
	p=(struct param*) par;
	char *panzer;
	vector<char*> mateurs(1000);
	FILE *cmd; FILE *script_pipe;
	int fd, wd;
	struct passwd *pwd;
	struct group *grp;
	char buf[BUF_LEN],ligne[CHAR_SIZE];
	int len,event_int,i=0;
	__u32 events_to_monitor;
	char **scripts=NULL;
	
	struct script_execute sc_execute[EVENT_QTY];
	
	uid_t userid=-1;
	gid_t grpid=-1;
	char tmp[BUF_LEN/2];
	
	
	struct stat statfile;
	
	
	scripts=scripts_for_event(p->scripts, sc_execute);	
	events_to_monitor=get_events_to_watch(p->scripts);
	
	//init inotify
	fd = inotify_init();
	
	if (fd < 0)
		perror("inotify_init");
		
	
	//syslog(LOG_INFO,"thread %s: nombre de scripts: %d",p->dossier,p->scripts.size());
	/*for(unsigned char a=0;a<p->scripts.size();a++)
	{
		syslog(LOG_INFO,"thread %s: masque:%u",p->dossier,p->scripts[a].mask);
	}*/
	if(p->recursive ==1)
	{
		//we call the following script through a pipe open and
		//get the result: the list of all subdirectories of the
		//one we have to watch
		sprintf(tmp,"bash /etc/dir1984/getdirs.sh %s",p->dossier);
		cmd=popen(tmp,"r");
	
		//Add a watch to each subdirectory
		while(fgets(ligne,sizeof(ligne),cmd)!=NULL)
		{
	
			ligne[strlen(ligne)-1]=0;
			wd = inotify_add_watch(fd,ligne,events_to_monitor);//IN_CREATE|IN_MOVED_TO);
			if (wd < 0)
			{
				perror("inotify_add_watch");
				syslog(LOG_INFO,"%s Error: inotify_add_watch %s",DAEMON_NAME,ligne);
			}
			else
			{
				panzer=(char*)malloc(strlen(ligne)+1);
				strncpy(panzer,ligne,strlen(ligne)+1);
				mateurs[wd]=panzer;		
				syslog(LOG_INFO,"inotify_add_watch %s OK",panzer);
	
			}
			
		}
		pclose(cmd);
	}
	else 
	{
		//add watch to the directory
		wd= inotify_add_watch(fd,p->dossier,events_to_monitor);//IN_CREATE|IN_MOVED_TO);
		if (wd < 0)
		{
			perror("inotify_add_watch");printf("%d %s\n",wd,ligne);
			syslog(LOG_INFO,"%s Error: inotify_add_watch %s",DAEMON_NAME,ligne);
		}
		else
		{
			panzer=(char*)malloc(strlen(p->dossier)+1);
			strncpy(panzer,p->dossier,strlen(p->dossier)+1);
			mateurs[wd]=panzer;
		}
	}
	// if userowner is not set, we won't change it
	if(strcmp(p->userowner,".")!=0)
	{
		//get pwd struct related to the chosen user
		if((pwd=getpwnam(p->userowner))==NULL)
		{
			syslog(LOG_INFO,"%d User %s unknown",t,p->userowner);
		}
		else
		{
		//if user exists, we get his id
			syslog(LOG_INFO,"%s files will be given to user %s id:%d",p->dossier,p->userowner,pwd->pw_uid);	
			userid=(pwd->pw_uid);
		}
	}
			
	// we do the same for group as we did for user.
	if(strcmp(p->grpowner,".")!=0)
	{
		if((grp=getgrnam(p->grpowner))==NULL)
		{
			syslog(LOG_INFO,"Group %s unknown",p->grpowner);
		}
		else
		{
			syslog(LOG_INFO,"%s files will be given to group %s grid:%d",p->dossier,p->grpowner,grp->gr_gid);
			grpid= (grp->gr_gid);
		}
	}
	
	while(0==0)
	{
		len = read(fd,buf,BUF_LEN);
		if(len<=0) printf("len = %d\n",len);
		i=0;
		//get inotify events
		while(i<len)
		{
			struct inotify_event *event;
			event = (struct inotify_event*) &buf[i];
			
			if(event->len)
		//	syslog(LOG_INFO,"evenement: %d",event->mask);
				printf("name=%s\n", event->name);
			
		
			
			sprintf(tmp,"%s/%s",mateurs[event->wd],event->name);
			
			
			
			//get stat struct for the file that provoked the event
			if(stat(tmp,&statfile)==0)
			{
				// If the new file is actually a directory
				// we add a watcher for this directory
				if(S_ISDIR(statfile.st_mode) && p->recursive==1)
				{
					wd = inotify_add_watch(fd,tmp,events_to_monitor);//IN_CREATE|IN_MOVED_TO);
					if (wd < 0)
					{
						perror("inotify_add_watch");
						syslog(LOG_INFO,"Error: inotify_add_watch for newly created: %s",tmp);	
					}
					else
					{
						panzer=(char*)malloc(strlen(tmp)+1);
						strncpy(panzer,tmp,strlen(tmp)+1);
						mateurs[wd]=panzer;
					}
				}
				//apply permission rules for new file
				// !!!! ONLY FOR CREATE AND MOVED_TO EVENTS
				if(mask_to_int(event->mask)==7 || mask_to_int(event->mask)==8)
				{
					apply_access(statfile.st_mode,p->masks,&droits_acces);
					//syslog(LOG_INFO,"NOUVEAU DROIT ACCESS %s %d",tmp,droits_acces);
					chmod(tmp,droits_acces);
				}
	
			}
			//change owner and grp owner of the new file
			chown(tmp,userid,grpid);
				
			
			if((event_int=mask_to_int(event->mask))>=0)
			{
				//run each script for the event type that occured
				for(int a=0; a<sc_execute[event_int].nbr_scripts;a++)
				{
					//run script
					script_pipe=popen(scripts[sc_execute[event_int].scripts_id[a]],"r");
					//close pipe
					pclose(script_pipe);
				}
			}
			
			
			i+= EVENT_SIZE + event->len;
			
		}
		
	}

	pthread_exit(NULL);

}
static int
owner_mt6_parse_v0(int c, char **argv, int invert, unsigned int *flags,
                   const void *entry, struct xt_entry_match **match)
{
	struct ip6t_owner_info *info = (void *)(*match)->data;
	struct passwd *pwd;
	struct group *grp;
	unsigned int id;

	switch (c) {
	case 'u':
		xtables_param_act(XTF_ONLY_ONCE, "owner", "--uid-owner",
		          *flags & FLAG_UID_OWNER);
		if ((pwd = getpwnam(optarg)) != NULL)
			id = pwd->pw_uid;
		else if (!xtables_strtoui(optarg, NULL, &id, 0, UINT32_MAX - 1))
			xtables_param_act(XTF_BAD_VALUE, "owner", "--uid-owner", optarg);
		if (invert)
			info->invert |= IP6T_OWNER_UID;
		info->match |= IP6T_OWNER_UID;
		info->uid    = id;
		*flags      |= FLAG_UID_OWNER;
		return true;

	case 'g':
		xtables_param_act(XTF_ONLY_ONCE, "owner", "--gid-owner",
		          *flags & FLAG_GID_OWNER);
		if ((grp = getgrnam(optarg)) != NULL)
			id = grp->gr_gid;
		else if (!xtables_strtoui(optarg, NULL, &id, 0, UINT32_MAX - 1))
			xtables_param_act(XTF_BAD_VALUE, "owner", "--gid-owner", optarg);
		if (invert)
			info->invert |= IP6T_OWNER_GID;
		info->match |= IP6T_OWNER_GID;
		info->gid    = id;
		*flags      |= FLAG_GID_OWNER;
		return true;

	case 'p':
		xtables_param_act(XTF_ONLY_ONCE, "owner", "--pid-owner",
		          *flags & FLAG_PID_OWNER);
		if (!xtables_strtoui(optarg, NULL, &id, 0, INT_MAX))
			xtables_param_act(XTF_BAD_VALUE, "owner", "--pid-owner", optarg);
		if (invert)
			info->invert |= IP6T_OWNER_PID;
		info->match |= IP6T_OWNER_PID;
		info->pid    = id;
		*flags      |= FLAG_PID_OWNER;
		return true;

	case 's':
		xtables_param_act(XTF_ONLY_ONCE, "owner", "--sid-owner",
		          *flags & FLAG_SID_OWNER);
		if (!xtables_strtoui(optarg, NULL, &id, 0, INT_MAX))
			xtables_param_act(XTF_BAD_VALUE, "owner", "--sid-owner", optarg);
		if (invert)
			info->invert |= IP6T_OWNER_SID;
		info->match |= IP6T_OWNER_SID;
		info->sid    = id;
		*flags      |= FLAG_SID_OWNER;
		return true;
	}
	return false;
}
static int
owner_mt_parse_v0(int c, char **argv, int invert, unsigned int *flags,
                  const void *entry, struct xt_entry_match **match)
{
	struct ipt_owner_info *info = (void *)(*match)->data;
	struct passwd *pwd;
	struct group *grp;
	unsigned int id;

	switch (c) {
	case 'u':
		xtables_param_act(XTF_ONLY_ONCE, "owner", "--uid-owner", *flags & FLAG_UID_OWNER);
		if ((pwd = getpwnam(optarg)) != NULL)
			id = pwd->pw_uid;
		else if (!xtables_strtoui(optarg, NULL, &id, 0, UINT32_MAX - 1))
			xtables_param_act(XTF_BAD_VALUE, "owner", "--uid-owner", optarg);
		if (invert)
			info->invert |= IPT_OWNER_UID;
		info->match |= IPT_OWNER_UID;
		info->uid    = id;
		*flags      |= FLAG_UID_OWNER;
		return true;

	case 'g':
		xtables_param_act(XTF_ONLY_ONCE, "owner", "--gid-owner", *flags & FLAG_GID_OWNER);
		if ((grp = getgrnam(optarg)) != NULL)
			id = grp->gr_gid;
		else if (!xtables_strtoui(optarg, NULL, &id, 0, UINT32_MAX - 1))
			xtables_param_act(XTF_BAD_VALUE, "owner", "--gid-owner", optarg);
		if (invert)
			info->invert |= IPT_OWNER_GID;
		info->match |= IPT_OWNER_GID;
		info->gid    = id;
		*flags      |= FLAG_GID_OWNER;
		return true;

	case 'p':
		xtables_param_act(XTF_ONLY_ONCE, "owner", "--pid-owner", *flags & FLAG_PID_OWNER);
		if (!xtables_strtoui(optarg, NULL, &id, 0, INT_MAX))
			xtables_param_act(XTF_BAD_VALUE, "owner", "--pid-owner", optarg);
		if (invert)
			info->invert |= IPT_OWNER_PID;
		info->match |= IPT_OWNER_PID;
		info->pid    = id;
		*flags      |= FLAG_PID_OWNER;
		return true;

	case 's':
		xtables_param_act(XTF_ONLY_ONCE, "owner", "--sid-owner", *flags & FLAG_SID_OWNER);
		if (!xtables_strtoui(optarg, NULL, &id, 0, INT_MAX))
			xtables_param_act(XTF_BAD_VALUE, "owner", "--sid-value", optarg);
		if (invert)
			info->invert |= IPT_OWNER_SID;
		info->match |= IPT_OWNER_SID;
		info->sid    = id;
		*flags      |= FLAG_SID_OWNER;
		return true;

#ifdef IPT_OWNER_COMM
	case 'c':
		xtables_param_act(XTF_ONLY_ONCE, "owner", "--cmd-owner", *flags & FLAG_COMM);
		if (strlen(optarg) > sizeof(info->comm))
			xtables_error(PARAMETER_PROBLEM, "owner match: command "
			           "\"%s\" too long, max. %zu characters",
			           optarg, sizeof(info->comm));

		info->comm[sizeof(info->comm)-1] = '\0';
		strncpy(info->comm, optarg, sizeof(info->comm));

		if (invert)
			info->invert |= IPT_OWNER_COMM;
		info->match |= IPT_OWNER_COMM;
		*flags      |= FLAG_COMM;
		return true;
#endif
	}
	return false;
}
Esempio n. 15
0
InspIRCd::InspIRCd(int argc, char** argv) :
	 ConfigFileName(INSPIRCD_CONFIG_PATH "/inspircd.conf"),
	 PI(&DefaultProtocolInterface),

	 /* Functor pointer initialisation.
	  *
	  * THIS MUST MATCH THE ORDER OF DECLARATION OF THE FUNCTORS, e.g. the methods
	  * themselves within the class.
	  */
	 OperQuit("operquit", ExtensionItem::EXT_USER, NULL),
	 GenRandom(&HandleGenRandom),
	 IsChannel(&HandleIsChannel),
	 IsNick(&HandleIsNick),
	 IsIdent(&HandleIsIdent),
	 OnCheckExemption(&HandleOnCheckExemption)
{
	ServerInstance = this;

	Extensions.Register(&OperQuit);

	FailedPortList pl;
	// Flag variables passed to getopt_long() later
	int do_version = 0, do_nofork = 0, do_debug = 0,
	    do_nolog = 0, do_root = 0;

	// Initialize so that if we exit before proper initialization they're not deleted
	this->Config = 0;
	this->XLines = 0;
	this->ConfigThread = NULL;
	this->FakeClient = NULL;

	UpdateTime();
	this->startup_time = TIME.tv_sec;

	SocketEngine::Init();

	this->Config = new ServerConfig;
	dynamic_reference_base::reset_all();
	this->XLines = new XLineManager;

	this->Config->cmdline.argv = argv;
	this->Config->cmdline.argc = argc;

#ifdef _WIN32
	srand(TIME.tv_nsec ^ TIME.tv_sec);

	// Initialize the console values
	g_hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_SCREEN_BUFFER_INFO bufinf;
	if(GetConsoleScreenBufferInfo(g_hStdout, &bufinf))
	{
		g_wOriginalColors = bufinf.wAttributes & 0x00FF;
		g_wBackgroundColor = bufinf.wAttributes & 0x00F0;
	}
	else
	{
		g_wOriginalColors = FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN;
		g_wBackgroundColor = 0;
	}
#else
	srandom(TIME.tv_nsec ^ TIME.tv_sec);
#endif

	struct option longopts[] =
	{
		{ "nofork",	no_argument,		&do_nofork,	1	},
		{ "config",	required_argument,	NULL,		'c'	},
		{ "debug",	no_argument,		&do_debug,	1	},
		{ "nolog",	no_argument,		&do_nolog,	1	},
		{ "runasroot",	no_argument,		&do_root,	1	},
		{ "version",	no_argument,		&do_version,	1	},
#ifdef INSPIRCD_ENABLE_TESTSUITE
		{ "testsuite",	no_argument,		&do_testsuite,	1	},
#endif
		{ 0, 0, 0, 0 }
	};

	int c;
	int index;
	while ((c = getopt_long(argc, argv, ":c:", longopts, &index)) != -1)
	{
		switch (c)
		{
			case 'c':
				/* Config filename was set */
				ConfigFileName = ServerInstance->Config->Paths.PrependConfig(optarg);
			break;
			case 0:
				/* getopt_long_only() set an int variable, just keep going */
			break;
			case '?':
				/* Unknown parameter */
			default:
				/* Fall through to handle other weird values too */
				std::cout << "Unknown parameter '" << argv[optind-1] << "'" << std::endl;
				std::cout << "Usage: " << argv[0] << " [--nofork] [--nolog] [--debug] [--config <config>]" << std::endl <<
					std::string(static_cast<int>(8+strlen(argv[0])), ' ') << "[--runasroot] [--version]" << std::endl;
				Exit(EXIT_STATUS_ARGV);
			break;
		}
	}

#ifdef INSPIRCD_ENABLE_TESTSUITE
	if (do_testsuite)
		do_nofork = do_debug = true;
#endif

	if (do_version)
	{
		std::cout << std::endl << INSPIRCD_VERSION << " " << INSPIRCD_REVISION << std::endl;
		Exit(EXIT_STATUS_NOERROR);
	}

#ifdef _WIN32
	// Set up winsock
	WSADATA wsadata;
	WSAStartup(MAKEWORD(2,2), &wsadata);
#endif

	/* Set the finished argument values */
	Config->cmdline.nofork = (do_nofork != 0);
	Config->cmdline.forcedebug = (do_debug != 0);
	Config->cmdline.writelog = !do_nolog;

	if (do_debug)
	{
		FileWriter* fw = new FileWriter(stdout);
		FileLogStream* fls = new FileLogStream(LOG_RAWIO, fw);
		Logs->AddLogTypes("*", fls, true);
	}

	if (!FileSystem::FileExists(ConfigFileName))
	{
#ifdef _WIN32
		/* Windows can (and defaults to) hide file extensions, so let's play a bit nice for windows users. */
		std::string txtconf = this->ConfigFileName;
		txtconf.append(".txt");

		if (FileSystem::FileExists(txtconf))
		{
			ConfigFileName = txtconf;
		}
		else
#endif
		{
			std::cout << "ERROR: Cannot open config file: " << ConfigFileName << std::endl << "Exiting..." << std::endl;
			this->Logs->Log("STARTUP", LOG_DEFAULT, "Unable to open config file %s", ConfigFileName.c_str());
			Exit(EXIT_STATUS_CONFIG);
		}
	}

	std::cout << con_green << "InspIRCd - Internet Relay Chat Daemon" << con_reset << ", compiled on " __DATE__ " at " __TIME__ << std::endl;
	std::cout << con_green << "(C) InspIRCd Development Team." << con_reset << std::endl << std::endl;
	std::cout << "Developers:" << std::endl;
	std::cout << con_green << "\tBrain, FrostyCoolSlug, w00t, Om, Special, peavey" << std::endl;
	std::cout << "\taquanight, psychon, dz, danieldg, jackmcbarn" << std::endl;
	std::cout << "\tAttila" << con_reset << std::endl << std::endl;
	std::cout << "Others:\t\t\t" << con_green << "See /INFO Output" << con_reset << std::endl;

#ifndef _WIN32
	if (!do_root)
		this->CheckRoot();
	else
	{
		std::cout << "* WARNING * WARNING * WARNING * WARNING * WARNING *" << std::endl
		<< "YOU ARE RUNNING INSPIRCD AS ROOT. THIS IS UNSUPPORTED" << std::endl
		<< "AND IF YOU ARE HACKED, CRACKED, SPINDLED OR MUTILATED" << std::endl
		<< "OR ANYTHING ELSE UNEXPECTED HAPPENS TO YOU OR YOUR" << std::endl
		<< "SERVER, THEN IT IS YOUR OWN FAULT. IF YOU DID NOT MEAN" << std::endl
		<< "TO START INSPIRCD AS ROOT, HIT CTRL+C NOW AND RESTART" << std::endl
		<< "THE PROGRAM AS A NORMAL USER. YOU HAVE BEEN WARNED!" << std::endl << std::endl
		<< "InspIRCd starting in 20 seconds, ctrl+c to abort..." << std::endl;
		sleep(20);
	}
#endif

	this->SetSignals();

	if (!Config->cmdline.nofork)
	{
		if (!this->DaemonSeed())
		{
			std::cout << "ERROR: could not go into daemon mode. Shutting down." << std::endl;
			Logs->Log("STARTUP", LOG_DEFAULT, "ERROR: could not go into daemon mode. Shutting down.");
			Exit(EXIT_STATUS_FORK);
		}
	}

	SocketEngine::RecoverFromFork();

	/* During startup we read the configuration now, not in
	 * a seperate thread
	 */
	this->Config->Read();
	this->Config->Apply(NULL, "");
	Logs->OpenFileLogs();
	ModeParser::InitBuiltinModes();

	// If we don't have a SID, generate one based on the server name and the server description
	if (Config->sid.empty())
		Config->sid = UIDGenerator::GenerateSID(Config->ServerName, Config->ServerDesc);

	// Initialize the UID generator with our sid
	this->UIDGen.init(Config->sid);

	// Create the server user for this server
	this->FakeClient = new FakeUser(Config->sid, Config->ServerName, Config->ServerDesc);

	// This is needed as all new XLines are marked pending until ApplyLines() is called
	this->XLines->ApplyLines();

	int bounditems = BindPorts(pl);

	std::cout << std::endl;

	this->Modules->LoadAll();

	// Build ISupport as ModuleManager::LoadAll() does not do it
	this->ISupport.Build();
	Config->ApplyDisabledCommands(Config->DisabledCommands);

	if (!pl.empty())
	{
		std::cout << std::endl << "WARNING: Not all your client ports could be bound -- " << std::endl << "starting anyway with " << bounditems
			<< " of " << bounditems + (int)pl.size() << " client ports bound." << std::endl << std::endl;
		std::cout << "The following port(s) failed to bind:" << std::endl << std::endl;
		int j = 1;
		for (FailedPortList::iterator i = pl.begin(); i != pl.end(); i++, j++)
		{
			std::cout << j << ".\tAddress: " << (i->first.empty() ? "<all>" : i->first) << " \tReason: " << i->second << std::endl;
		}

		std::cout << std::endl << "Hint: Try using a public IP instead of blank or *" << std::endl;
	}

	std::cout << "InspIRCd is now running as '" << Config->ServerName << "'[" << Config->GetSID() << "] with " << SocketEngine::GetMaxFds() << " max open sockets" << std::endl;

#ifndef _WIN32
	if (!Config->cmdline.nofork)
	{
		if (kill(getppid(), SIGTERM) == -1)
		{
			std::cout << "Error killing parent process: " << strerror(errno) << std::endl;
			Logs->Log("STARTUP", LOG_DEFAULT, "Error killing parent process: %s",strerror(errno));
		}
	}

	/* Explicitly shut down stdio's stdin/stdout/stderr.
	 *
	 * The previous logic here was to only do this if stdio was connected to a controlling
	 * terminal.  However, we must do this always to avoid information leaks and other
	 * problems related to stdio.
	 *
	 * The only exception is if we are in debug mode.
	 *
	 *    -- nenolod
	 */
	if ((!do_nofork) && (!Config->cmdline.forcedebug))
	{
		int fd = open("/dev/null", O_RDWR);

		fclose(stdin);
		fclose(stderr);
		fclose(stdout);

		if (dup2(fd, STDIN_FILENO) < 0)
			Logs->Log("STARTUP", LOG_DEFAULT, "Failed to dup /dev/null to stdin.");
		if (dup2(fd, STDOUT_FILENO) < 0)
			Logs->Log("STARTUP", LOG_DEFAULT, "Failed to dup /dev/null to stdout.");
		if (dup2(fd, STDERR_FILENO) < 0)
			Logs->Log("STARTUP", LOG_DEFAULT, "Failed to dup /dev/null to stderr.");
		close(fd);
	}
	else
	{
		Logs->Log("STARTUP", LOG_DEFAULT, "Keeping pseudo-tty open as we are running in the foreground.");
	}
#else
	/* Set win32 service as running, if we are running as a service */
	SetServiceRunning();

	// Handle forking
	if(!do_nofork)
	{
		FreeConsole();
	}

	QueryPerformanceFrequency(&stats.QPFrequency);
#endif

	Logs->Log("STARTUP", LOG_DEFAULT, "Startup complete as '%s'[%s], %d max open sockets", Config->ServerName.c_str(),Config->GetSID().c_str(), SocketEngine::GetMaxFds());

#ifndef _WIN32
	std::string SetUser = Config->ConfValue("security")->getString("runasuser");
	std::string SetGroup = Config->ConfValue("security")->getString("runasgroup");
	if (!SetGroup.empty())
	{
		int ret;

		// setgroups
		ret = setgroups(0, NULL);

		if (ret == -1)
		{
			this->Logs->Log("STARTUP", LOG_DEFAULT, "setgroups() failed (wtf?): %s", strerror(errno));
			this->QuickExit(0);
		}

		// setgid
		struct group *g;

		errno = 0;
		g = getgrnam(SetGroup.c_str());

		if (!g)
		{
			this->Logs->Log("STARTUP", LOG_DEFAULT, "getgrnam(%s) failed (wrong group?): %s", SetGroup.c_str(), strerror(errno));
			this->QuickExit(0);
		}

		ret = setgid(g->gr_gid);

		if (ret == -1)
		{
			this->Logs->Log("STARTUP", LOG_DEFAULT, "setgid() failed (wrong group?): %s", strerror(errno));
			this->QuickExit(0);
		}
	}

	if (!SetUser.empty())
	{
		// setuid
		struct passwd *u;

		errno = 0;
		u = getpwnam(SetUser.c_str());

		if (!u)
		{
			this->Logs->Log("STARTUP", LOG_DEFAULT, "getpwnam(%s) failed (wrong user?): %s", SetUser.c_str(), strerror(errno));
			this->QuickExit(0);
		}

		int ret = setuid(u->pw_uid);

		if (ret == -1)
		{
			this->Logs->Log("STARTUP", LOG_DEFAULT, "setuid() failed (wrong user?): %s", strerror(errno));
			this->QuickExit(0);
		}
	}

	this->WritePID(Config->PID);
#endif
}
Esempio n. 16
0
C_Errno_t(C_Int_t) Posix_SysDB_getgrnam(NullString8_t s) {
  return NULL != (Posix_SysDB_Group_group = getgrnam ((const char*)s));
}
Esempio n. 17
0
main(int argc, char *argv[])
#endif
{
    char            options[128] = "aAc:CdD::fhHI:l:L:m:M:n:p:P:qrsS:UvV-:Y:";
    int             arg, i, ret;
    int             dont_fork = 0, do_help = 0;
    int             log_set = 0;
    int             uid = 0, gid = 0;
    int             agent_mode = -1;
    char           *cptr, **argvptr;
    char           *pid_file = NULL;
    char            option_compatability[] = "-Le";
#if HAVE_GETPID
    int fd;
    FILE           *PID;
#endif
#if HAVE_GETPWNAM && HAVE_PWD_H
    struct passwd  *info;
#endif
#if HAVE_UNISTD_H
    const char     *persistent_dir;
#endif

#ifndef WIN32
    /*
     * close all non-standard file descriptors we may have
     * inherited from the shell.
     */
    for (i = getdtablesize() - 1; i > 2; --i) {
        (void) close(i);
    }
#endif /* #WIN32 */
    
    /*
     * register signals ASAP to prevent default action (usually core)
     * for signals during startup...
     */
#ifdef SIGTERM
    DEBUGMSGTL(("signal", "registering SIGTERM signal handler\n"));
    signal(SIGTERM, SnmpdShutDown);
#endif
#ifdef SIGINT
    DEBUGMSGTL(("signal", "registering SIGINT signal handler\n"));
    signal(SIGINT, SnmpdShutDown);
#endif
#ifdef SIGHUP
    signal(SIGHUP, SIG_IGN);   /* do not terminate on early SIGHUP */
#endif
#ifdef SIGUSR1
    DEBUGMSGTL(("signal", "registering SIGUSR1 signal handler\n"));
    signal(SIGUSR1, SnmpdDump);
#endif
#ifdef SIGPIPE
    DEBUGMSGTL(("signal", "registering SIGPIPE signal handler\n"));
    signal(SIGPIPE, SIG_IGN);   /* 'Inline' failure of wayward readers */
#endif
#ifdef SIGXFSZ
    signal(SIGXFSZ, SnmpdCatchRandomSignal);
#endif

#ifdef NETSNMP_NO_ROOT_ACCESS
    /*
     * Default to no.  
     */
    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
			   NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1);
#endif
    /*
     * Default to NOT running an AgentX master.  
     */
    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
			   NETSNMP_DS_AGENT_AGENTX_MASTER, 0);
    netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID,
                       NETSNMP_DS_AGENT_AGENTX_TIMEOUT, -1);
    netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID,
                       NETSNMP_DS_AGENT_AGENTX_RETRIES, -1);

    netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID,
                       NETSNMP_DS_AGENT_CACHE_TIMEOUT, 5);
    /*
     * Add some options if they are available.  
     */
#if HAVE_UNISTD_H
    strcat(options, "g:u:");
#endif
#if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE)
    strcat(options, "x:");
#endif
#ifdef USING_AGENTX_SUBAGENT_MODULE
    strcat(options, "X");
#endif

    /*
     * This is incredibly ugly, but it's probably the simplest way
     *  to handle the old '-L' option as well as the new '-Lx' style
     */
    for (i=0; i<argc; i++) {
        if (!strcmp(argv[i], "-L"))
            argv[i] = option_compatability;            
    }

#ifdef WIN32
    snmp_log_syslogname(app_name_long);
#else
    snmp_log_syslogname(app_name);
#endif
    netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
                          NETSNMP_DS_LIB_APPTYPE, app_name);

    /*
     * Now process options normally.  
     */
    while ((arg = getopt(argc, argv, options)) != EOF) {
        switch (arg) {
        case '-':
            if (strcasecmp(optarg, "help") == 0) {
                usage(argv[0]);
            }
            if (strcasecmp(optarg, "version") == 0) {
                version();
            }

            handle_long_opt(optarg);
            break;

        case 'a':
            log_addresses++;
            break;

        case 'A':
            netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
                                   NETSNMP_DS_LIB_APPEND_LOGFILES, 1);
            break;

        case 'c':
            if (optarg != NULL) {
                netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, 
				      NETSNMP_DS_LIB_OPTIONALCONFIG, optarg);
            } else {
                usage(argv[0]);
            }
            break;

        case 'C':
            netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
				   NETSNMP_DS_LIB_DONT_READ_CONFIGS, 1);
            break;

        case 'd':
            snmp_set_dump_packet(++snmp_dump_packet);
            netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
				   NETSNMP_DS_AGENT_VERBOSE, 1);
            break;

        case 'D':
            debug_register_tokens(optarg);
            snmp_set_do_debugging(1);
            break;

        case 'f':
            dont_fork = 1;
            break;

#if HAVE_UNISTD_H
        case 'g':
            if (optarg != NULL) {
                char           *ecp;
                int             gid;

                gid = strtoul(optarg, &ecp, 10);
                if (*ecp) {
#if HAVE_GETPWNAM && HAVE_PWD_H
                    struct group  *info;
                    info = getgrnam(optarg);
                    if (info) {
                        gid = info->gr_gid;
                    } else {
#endif
                        fprintf(stderr, "Bad group id: %s\n", optarg);
                        exit(1);
#if HAVE_GETPWNAM && HAVE_PWD_H
                    }
#endif
                }
                netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, 
				   NETSNMP_DS_AGENT_GROUPID, gid);
            } else {
                usage(argv[0]);
            }
            break;
#endif

        case 'h':
            usage(argv[0]);
            break;

        case 'H':
            do_help = 1;
            break;

        case 'I':
            if (optarg != NULL) {
                add_to_init_list(optarg);
            } else {
                usage(argv[0]);
            }
            break;

        case 'l':
            printf("Warning: -l option is deprecated, use -Lf <file> instead\n");
            if (optarg != NULL) {
                if (strlen(optarg) > PATH_MAX) {
                    fprintf(stderr,
                            "%s: logfile path too long (limit %d chars)\n",
                            argv[0], PATH_MAX);
                    exit(1);
                }
                snmp_enable_filelog(optarg,
                                    netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
                                                           NETSNMP_DS_LIB_APPEND_LOGFILES));
                log_set = 1;
            } else {
                usage(argv[0]);
            }
            break;

        case 'L':
	    if  (snmp_log_options( optarg, argc, argv ) < 0 ) {
                usage(argv[0]);
            }
            log_set = 1;
            break;

        case 'm':
            if (optarg != NULL) {
                setenv("MIBS", optarg, 1);
            } else {
                usage(argv[0]);
            }
            break;

        case 'M':
            if (optarg != NULL) {
                setenv("MIBDIRS", optarg, 1);
            } else {
                usage(argv[0]);
            }
            break;

        case 'n':
            if (optarg != NULL) {
                app_name = optarg;
                netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
                                      NETSNMP_DS_LIB_APPTYPE, app_name);
            } else {
                usage(argv[0]);
            }
            break;

        case 'P':
            printf("Warning: -P option is deprecated, use -p instead\n");
        case 'p':
            if (optarg != NULL) {
                pid_file = optarg;
            } else {
                usage(argv[0]);
            }
            break;

        case 'q':
            snmp_set_quick_print(1);
            break;

        case 'r':
            netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, 
				      NETSNMP_DS_AGENT_NO_ROOT_ACCESS);
            break;

        case 's':
            printf("Warning: -s option is deprecated, use -Lsd instead\n");
            snmp_enable_syslog();
            log_set = 1;
            break;

        case 'S':
            printf("Warning: -S option is deprecated, use -Ls <facility> instead\n");
            if (optarg != NULL) {
                switch (*optarg) {
                case 'd':
                case 'D':
                    Facility = LOG_DAEMON;
                    break;
                case 'i':
                case 'I':
                    Facility = LOG_INFO;
                    break;
                case '0':
                    Facility = LOG_LOCAL0;
                    break;
                case '1':
                    Facility = LOG_LOCAL1;
                    break;
                case '2':
                    Facility = LOG_LOCAL2;
                    break;
                case '3':
                    Facility = LOG_LOCAL3;
                    break;
                case '4':
                    Facility = LOG_LOCAL4;
                    break;
                case '5':
                    Facility = LOG_LOCAL5;
                    break;
                case '6':
                    Facility = LOG_LOCAL6;
                    break;
                case '7':
                    Facility = LOG_LOCAL7;
                    break;
                default:
                    fprintf(stderr, "invalid syslog facility: -S%c\n",*optarg);
                    usage(argv[0]);
                }
                snmp_enable_syslog_ident(snmp_log_syslogname(NULL), Facility);
                log_set = 1;
            } else {
                fprintf(stderr, "no syslog facility specified\n");
                usage(argv[0]);
            }
            break;

        case 'U':
            netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, 
				      NETSNMP_DS_AGENT_LEAVE_PIDFILE);
            break;

#if HAVE_UNISTD_H
        case 'u':
            if (optarg != NULL) {
                char           *ecp;
                int             uid;

                uid = strtoul(optarg, &ecp, 10);
                if (*ecp) {
#if HAVE_GETPWNAM && HAVE_PWD_H
                    info = getpwnam(optarg);
                    if (info) {
                        uid = info->pw_uid;
                    } else {
#endif
                        fprintf(stderr, "Bad user id: %s\n", optarg);
                        exit(1);
#if HAVE_GETPWNAM && HAVE_PWD_H
                    }
#endif
                }
                netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, 
				   NETSNMP_DS_AGENT_USERID, uid);
            } else {
                usage(argv[0]);
            }
            break;
#endif

        case 'v':
            version();

        case 'V':
            netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
				   NETSNMP_DS_AGENT_VERBOSE, 1);
            break;

#if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE)
        case 'x':
            if (optarg != NULL) {
                netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, 
				      NETSNMP_DS_AGENT_X_SOCKET, optarg);
            } else {
                usage(argv[0]);
            }
            netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
				   NETSNMP_DS_AGENT_AGENTX_MASTER, 1);
            break;
#endif

        case 'X':
#if defined(USING_AGENTX_SUBAGENT_MODULE)
            agent_mode = SUB_AGENT;
#else
            fprintf(stderr, "%s: Illegal argument -X:"
		            "AgentX support not compiled in.\n", argv[0]);
            usage(argv[0]);
            exit(1);
#endif
            break;

        case 'Y':
            netsnmp_config_remember(optarg);
            break;

        default:
            usage(argv[0]);
            break;
        }
    }

    if (do_help) {
        netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
                               NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1);
        init_agent(app_name);        /* register our .conf handlers */
        init_mib_modules();
        init_snmp(app_name);
        fprintf(stderr, "Configuration directives understood:\n");
        read_config_print_usage("  ");
        exit(0);
    }

    if (optind < argc) {
        /*
         * There are optional transport addresses on the command line.  
         */
        DEBUGMSGTL(("snmpd/main", "optind %d, argc %d\n", optind, argc));
        for (i = optind; i < argc; i++) {
            char *c, *astring;
            if ((c = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, 
					   NETSNMP_DS_AGENT_PORTS))) {
                astring = (char*)malloc(strlen(c) + 2 + strlen(argv[i]));
                if (astring == NULL) {
                    fprintf(stderr, "malloc failure processing argv[%d]\n", i);
                    exit(1);
                }
                sprintf(astring, "%s,%s", c, argv[i]);
                netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, 
				      NETSNMP_DS_AGENT_PORTS, astring);
                SNMP_FREE(astring);
            } else {
                netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, 
				      NETSNMP_DS_AGENT_PORTS, argv[i]);
            }
        }
        DEBUGMSGTL(("snmpd/main", "port spec: %s\n",
                    netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, 
					  NETSNMP_DS_AGENT_PORTS)));
    }

#ifdef NETSNMP_LOGFILE
    if (0 == log_set)
        snmp_enable_filelog(NETSNMP_LOGFILE,
                            netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
                                                   NETSNMP_DS_LIB_APPEND_LOGFILES));
#endif

    /*
     * Initialize a argv set to the current for restarting the agent.   
     */
    argvrestartp = (char **)malloc((argc + 2) * sizeof(char *));
    argvptr = argvrestartp;
    for (i = 0, ret = 1; i < argc; i++) {
        ret += strlen(argv[i]) + 1;
    }
    argvrestart = (char *) malloc(ret);
    argvrestartname = (char *) malloc(strlen(argv[0]) + 1);
    if (!argvrestartp || !argvrestart || !argvrestartname) {
        fprintf(stderr, "malloc failure processing argvrestart\n");
        exit(1);
    }
    strcpy(argvrestartname, argv[0]);
    if (agent_mode == -1) {
        if (strstr(argvrestartname, "agentxd") != NULL) {
            netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
				   NETSNMP_DS_AGENT_ROLE, SUB_AGENT);
        } else {
            netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
				   NETSNMP_DS_AGENT_ROLE, MASTER_AGENT);
        }
    } else {
        netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
			       NETSNMP_DS_AGENT_ROLE, agent_mode);
    }

    for (cptr = argvrestart, i = 0; i < argc; i++) {
        strcpy(cptr, argv[i]);
        *(argvptr++) = cptr;
        cptr += strlen(argv[i]) + 1;
    }
    *cptr = 0;
    *argvptr = NULL;

    SOCK_STARTUP;
    init_agent(app_name);        /* do what we need to do first. */
    init_mib_modules();

    /*
     * start library 
     */
    init_snmp(app_name);

    if ((ret = init_master_agent()) != 0) {
        /*
         * Some error opening one of the specified agent transports.  
         */
        Exit(1);                /*  Exit logs exit val for us  */
    }

    /*
     * Initialize the world.  Detach from the shell.  Create initial user.  
     */
    if(!dont_fork) {
        int quit = ! netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
                                            NETSNMP_DS_AGENT_QUIT_IMMEDIATELY);
        ret = netsnmp_daemonize(quit, snmp_stderrlog_status());
        /*
         * xxx-rks: do we care if fork fails? I think we should...
         */
        if(ret != 0)
            Exit(1);                /*  Exit logs exit val for us  */
    }

#if HAVE_GETPID
    if (pid_file != NULL) {
        /*
         * unlink the pid_file, if it exists, prior to open.  Without
         * doing this the open will fail if the user specified pid_file
         * already exists.
         */
        unlink(pid_file);
        fd = open(pid_file, O_CREAT | O_EXCL | O_WRONLY, 0600);
        if (fd == -1) {
            snmp_log_perror(pid_file);
            if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
                                        NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
                exit(1);
            }
        } else {
            if ((PID = fdopen(fd, "w")) == NULL) {
                snmp_log_perror(pid_file);
                exit(1);
            } else {
                fprintf(PID, "%d\n", (int) getpid());
                fclose(PID);
            }
            close(fd);
        }
    }
#endif

#if HAVE_UNISTD_H
    persistent_dir = get_persistent_directory();
    mkdirhier( persistent_dir, NETSNMP_AGENT_DIRECTORY_MODE, 0 );
   
    uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 
			     NETSNMP_DS_AGENT_USERID);
    gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 
			     NETSNMP_DS_AGENT_GROUPID);
    
#ifdef HAVE_CHOWN
    if ( uid != 0 || gid != 0 )
        chown( persistent_dir, uid, gid );
#endif

#ifdef HAVE_SETGID
    if ((gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 
				  NETSNMP_DS_AGENT_GROUPID)) != 0) {
        DEBUGMSGTL(("snmpd/main", "Changing gid to %d.\n", gid));
        if (setgid(gid) == -1
#ifdef HAVE_SETGROUPS
            || setgroups(1, (gid_t *)&gid) == -1
#endif
            ) {
            snmp_log_perror("setgid failed");
            if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
					NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
                exit(1);
            }
        }
    }
#endif
#ifdef HAVE_SETUID
    if ((uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 
				  NETSNMP_DS_AGENT_USERID)) != 0) {
#if HAVE_GETPWNAM && HAVE_PWD_H && HAVE_INITGROUPS
        /*
         * Set supplementary groups before changing UID
         *   (which probably involves giving up privileges)
         */
        info = getpwuid(uid);
        if (info) {
            DEBUGMSGTL(("snmpd/main", "Supplementary groups for %s.\n", info->pw_name));
            if (initgroups(info->pw_name, (gid != 0 ? (gid_t)gid : info->pw_gid)) == -1) {
                snmp_log_perror("initgroups failed");
                if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
                                            NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
                    exit(1);
                }
            }
        }
#endif
        DEBUGMSGTL(("snmpd/main", "Changing uid to %d.\n", uid));
        if (setuid(uid) == -1) {
            snmp_log_perror("setuid failed");
            if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
					NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
                exit(1);
            }
        }
    }
#endif
#endif

    /*
     * Store persistent data immediately in case we crash later.  
     */
    snmp_store(app_name);

#ifdef SIGHUP
    DEBUGMSGTL(("signal", "registering SIGHUP signal handler\n"));
    signal(SIGHUP, SnmpdReconfig);
#endif

    /*
     * Send coldstart trap if possible.  
     */
    send_easy_trap(0, 0);

    /*
     * We're up, log our version number.  
     */
    snmp_log(LOG_INFO, "NET-SNMP version %s\n", netsnmp_get_version());
#ifdef WIN32SERVICE
    agent_status = AGENT_RUNNING;
#endif
    netsnmp_addrcache_initialise();

    /*
     * Forever monitor the dest_port for incoming PDUs.  
     */
    DEBUGMSGTL(("snmpd/main", "We're up.  Starting to process data.\n"));
    if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
				NETSNMP_DS_AGENT_QUIT_IMMEDIATELY))
        receive();
    DEBUGMSGTL(("snmpd/main", "sending shutdown trap\n"));
    SnmpTrapNodeDown();
    DEBUGMSGTL(("snmpd/main", "Bye...\n"));
    snmp_shutdown(app_name);
    shutdown_master_agent();
    shutdown_agent();

    if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
				NETSNMP_DS_AGENT_LEAVE_PIDFILE) &&
	(pid_file != NULL)) {
        unlink(pid_file);
    }
#ifdef WIN32SERVICE
    agent_status = AGENT_STOPPED;
#endif

    SNMP_FREE(argvrestartname);
    SNMP_FREE(argvrestart);
    SNMP_FREE(argvrestartp);
    SOCK_CLEANUP;
    return 0;
}                               /* End main() -- snmpd */
Esempio n. 18
0
static void compute_file_name(char **strp,
    const char *user,
    const char *suffix,
    const char *what)
{
  char *str = NULL;

  str = *strp;

  if (!str) {
    /* We'll put our various artifacts in a user specific dir
     * within the state dir location */
    char *state_dir = NULL;
    const char *state_parent = test_state_dir ? test_state_dir :
#ifdef WATCHMAN_STATE_DIR
          WATCHMAN_STATE_DIR
#else
          watchman_tmp_dir
#endif
          ;

    ignore_result(asprintf(&state_dir, "%s%c%s-state",
          state_parent,
          WATCHMAN_DIR_SEP,
          user));

    if (!state_dir) {
      w_log(W_LOG_ERR, "out of memory computing %s\n", what);
      exit(1);
    }

    if (mkdir(state_dir, 0700) == 0 || errno == EEXIST) {
#ifndef _WIN32
      // verify ownership
      struct stat st;
      DIR *dirp;
      int dir_fd;
      int ret = 0;
      uid_t euid = geteuid();
      // TODO: also allow a gid to be specified here
      const char *sock_group_name = cfg_get_string(NULL, "sock_group", NULL);
      // S_ISGID is set so that files inside this directory inherit the group
      // name
      mode_t dir_perms = cfg_get_perms(NULL, "sock_access",
                                       false /* write bits */,
                                       true /* execute bits */) | S_ISGID;

      dirp = opendir(state_dir);
      if (!dirp) {
        w_log(W_LOG_ERR, "opendir(%s): %s\n", state_dir, strerror(errno));
        exit(1);
      }

      dir_fd = dirfd(dirp);
      if (dir_fd == -1) {
        w_log(W_LOG_ERR, "dirfd(%s): %s\n", state_dir, strerror(errno));
        goto bail;
      }

      if (fstat(dir_fd, &st) != 0) {
        w_log(W_LOG_ERR, "fstat(%s): %s\n", state_dir, strerror(errno));
        ret = 1;
        goto bail;
      }
      if (euid != st.st_uid) {
        w_log(W_LOG_ERR,
            "the owner of %s is uid %d and doesn't match your euid %d\n",
            state_dir, st.st_uid, euid);
        ret = 1;
        goto bail;
      }
      if (st.st_mode & 0022) {
        w_log(W_LOG_ERR,
            "the permissions on %s allow others to write to it. "
            "Verify that you own the contents and then fix its "
            "permissions by running `chmod 0700 %s`\n",
            state_dir,
            state_dir);
        ret = 1;
        goto bail;
      }

      if (sock_group_name) {
        struct group *sock_group;
        // This explicit errno statement is necessary to distinguish between the
        // group not existing and an error.
        errno = 0;
        sock_group = getgrnam(sock_group_name);
        if (!sock_group) {
          if (errno == 0) {
            w_log(W_LOG_ERR, "group '%s' does not exist", sock_group_name);
          } else {
            w_log(W_LOG_ERR, "getting gid for '%s' failed: %s", sock_group_name,
                  strerror(errno));
          }
          ret = 1;
          goto bail;
        }

        if (fchown(dir_fd, -1, sock_group->gr_gid) == -1) {
          w_log(W_LOG_ERR, "setting up group '%s' failed: %s", sock_group_name,
                strerror(errno));
          ret = 1;
          goto bail;
        }
      }

      // Depending on group and world accessibility, change permissions on the
      // directory. We can't leave the directory open and set permissions on the
      // socket because not all POSIX systems respect permissions on UNIX domain
      // sockets, but all POSIX systems respect permissions on the containing
      // directory.
      w_log(W_LOG_DBG, "Setting permissions on state dir to 0%o", dir_perms);
      if (fchmod(dir_fd, dir_perms) == -1) {
        w_log(W_LOG_ERR, "fchmod(%s, %#o): %s\n", state_dir, dir_perms,
              strerror(errno));
        ret = 1;
        goto bail;
      }

    bail:
      closedir(dirp);
      if (ret) {
        exit(ret);
      }
#endif
    } else {
      w_log(W_LOG_ERR, "while computing %s: failed to create %s: %s\n", what,
            state_dir, strerror(errno));
      exit(1);
    }

    ignore_result(asprintf(&str, "%s%c%s",
          state_dir, WATCHMAN_DIR_SEP, suffix));

    if (!str) {
      w_log(W_LOG_ERR, "out of memory computing %s", what);
      abort();
    }

    free(state_dir);
  }

#ifndef _WIN32
  if (str[0] != '/') {
    w_log(W_LOG_ERR, "invalid %s: %s", what, str);
    abort();
  }
#endif

  *strp = str;
}
Esempio n. 19
0
extern void
daemon_init(msg_dest_t log_dest, const char *program, int facility, const char *pidfile, const char *username, const char *groupname)
{
	pid_t pid;
	int i;
	FILE *pid_fp;
	int sigs[] = { SIGHUP, SIGINT, SIGQUIT, SIGTSTP, SIGTTIN, SIGTTOU };
	struct passwd *pw;
	struct group *grp;

	/* make sure all those nice signals are going to be ignored */
	for (i = 0; i < sizeof(sigs) / sizeof(int); i++)
	{
		if (!_daemon_handle_signal(sigs[i], SIG_IGN))
		{
			msg_log(LOG_ERR, "Fatal error in daemon_init(): %s\n", strerror(errno));
			exit(EXIT_FAILURE);
		}
	}

	/* stalking off to background... */
	switch (pid = fork())
	{
		case -1:
			msg_log(LOG_ERR, "Fatal error in fork(): %s\n", strerror(errno));
			exit(EXIT_FAILURE);
			break;
		case 0:
			msg_close();
			msg_open(log_dest, program, LOG_PID, facility);
			break;
		default:
			exit(EXIT_SUCCESS);
			break;
	}

	/* get rid of the associated terminal */
	if (setsid() < 0)
	{
		msg_log(LOG_ERR, "Fatal error in setsid(): %s\n", strerror(errno));
		exit(EXIT_FAILURE);
	}

	/* make sure we cannot be prosecuted by a not yet controlling terminal */
	switch (pid = fork())
	{
		case -1:
			msg_log(LOG_ERR, "Fatal error in fork(): %s\n", strerror(errno));
			exit(EXIT_FAILURE);
			break;
		case 0:
			break;
		default:
			exit(EXIT_SUCCESS);
			break;
	}

	/* close unnecessary file descriptors */
	close(STDIN_FILENO);
	close(STDOUT_FILENO);
	close(STDERR_FILENO);

	/* change working directory */
	chdir("/");

	/* set default file mode creation mask */
	umask(0);

	/* write PID to pidfile */
	if (NULL != pidfile)
	{
		pid_fp = fopen(pidfile, "w");
		if (NULL == pid_fp)
		{
			msg_log(LOG_ERR, "Fatal error in fopen(): %s\n", strerror(errno));
			exit(EXIT_FAILURE);
		}
		fprintf(pid_fp, "%d", (int)getpid());
		fclose(pid_fp);
	}

	/* change user and group id */
	if (NULL != groupname)
	{   
		grp = getgrnam(groupname);      /* using a non-threadsafe function is ok here */
		if (0 != setgid(grp->gr_gid))
			msg_log(LOG_WARNING, "Unable to change GID to %d (%s): %s\n", (int)grp->gr_gid, groupname, strerror(errno));
		else
			msg_log(LOG_INFO, "Changed GID to %d (%s)\n", (int)grp->gr_gid, groupname);
	}

	if (NULL != username)
	{
		pw = getpwnam(username);		/* using a non-threadsafe function is ok here */
		if  (0 != setuid(pw->pw_uid))
			msg_log(LOG_WARNING, "Unable to change UID to %d (%s): %s\n", (int)pw->pw_uid, username, strerror(errno));
		else
			msg_log(LOG_INFO, "Changed UID to %d (%s)\n", (int)pw->pw_uid, username);
	}
}
Esempio n. 20
0
struct quotafile *
quota_open(struct fstab *fs, int quotatype, int openflags)
{
	struct quotafile *qf;
	struct dqhdr64 dqh;
	struct group *grp;
	struct stat st;
	int qcmd, serrno;

	if (strcmp(fs->fs_vfstype, "ufs"))
		return (NULL);
	if ((qf = calloc(1, sizeof(*qf))) == NULL)
		return (NULL);
	qf->fd = -1;
	qf->quotatype = quotatype;
	strncpy(qf->fsname, fs->fs_file, sizeof(qf->fsname));
	if (stat(qf->fsname, &st) != 0)
		goto error;
	qf->dev = st.st_dev;
	serrno = hasquota(fs, quotatype, qf->qfname, sizeof(qf->qfname));
	qcmd = QCMD(Q_GETQUOTASIZE, quotatype);
	if (quotactl(qf->fsname, qcmd, 0, &qf->wordsize) == 0)
		return (qf);
	if (serrno == 0) {
		errno = EOPNOTSUPP;
		goto error;
	}
	qf->accmode = openflags & O_ACCMODE;
	if ((qf->fd = open(qf->qfname, qf->accmode)) < 0 &&
	    (openflags & O_CREAT) != O_CREAT)
		goto error;
	/* File open worked, so process it */
	if (qf->fd != -1) {
		qf->wordsize = 32;
		switch (read(qf->fd, &dqh, sizeof(dqh))) {
		case -1:
			goto error;
		case sizeof(dqh):
			if (strcmp(dqh.dqh_magic, Q_DQHDR64_MAGIC) != 0) {
				/* no magic, assume 32 bits */
				qf->wordsize = 32;
				return (qf);
			}
			if (be32toh(dqh.dqh_version) != Q_DQHDR64_VERSION ||
			    be32toh(dqh.dqh_hdrlen) != sizeof(struct dqhdr64) ||
			    be32toh(dqh.dqh_reclen) != sizeof(struct dqblk64)) {
				/* correct magic, wrong version / lengths */
				errno = EINVAL;
				goto error;
			}
			qf->wordsize = 64;
			return (qf);
		default:
			qf->wordsize = 32;
			return (qf);
		}
		/* not reached */
	}
	/* open failed, but O_CREAT was specified, so create a new file */
	if ((qf->fd = open(qf->qfname, O_RDWR|O_CREAT|O_TRUNC, 0)) < 0)
		goto error;
	qf->wordsize = 64;
	memset(&dqh, 0, sizeof(dqh));
	memcpy(dqh.dqh_magic, Q_DQHDR64_MAGIC, sizeof(dqh.dqh_magic));
	dqh.dqh_version = htobe32(Q_DQHDR64_VERSION);
	dqh.dqh_hdrlen = htobe32(sizeof(struct dqhdr64));
	dqh.dqh_reclen = htobe32(sizeof(struct dqblk64));
	if (write(qf->fd, &dqh, sizeof(dqh)) != sizeof(dqh)) {
		/* it was one we created ourselves */
		unlink(qf->qfname);
		goto error;
	}
	grp = getgrnam(QUOTAGROUP);
	fchown(qf->fd, 0, grp ? grp->gr_gid : 0);
	fchmod(qf->fd, 0640);
	return (qf);
error:
	serrno = errno;
	/* did we have an open file? */
	if (qf->fd != -1)
		close(qf->fd);
	free(qf);
	errno = serrno;
	return (NULL);
}
Esempio n. 21
0
static bool
drop_root(char const *user, char const *group)
{
	gid_t	gid;
	uid_t	uid;
	char	*ep;

	if ((uid = getuid()) != 0) {
		log_notice("Cannot set uid/gid. Not a superuser");
		return true; /* dont do anything unless root */
	}

	gid = getgid();

	if (user != NULL) {
		uid = strtol(user, &ep, 10);
		if (*ep != '\0') {
			struct passwd	*pwd = getpwnam(user);

			if (pwd == NULL) {
				log_err("No passwd entry for user %s", user);
				return false;
			}

			uid = pwd->pw_uid;
		}
	}

	if (group != NULL) {
		gid = strtol(group, &ep, 10);
		if (*ep != '\0') {
			struct group	*grp = getgrnam(group);

			if (grp == NULL) {
				log_err("No group entry for group %s", group);
				return false;
			}

			gid = grp->gr_gid;
		}
	}

	if (setgid(gid) < 0) {
		log_err("Could not setgid(%s). %s (%d)", group,
		    strerror(errno), errno);

		return false;
	}

	if (setgroups(0, NULL) < 0) {
		log_err("Could not setgroups(0). %s (%d)",
		    strerror(errno), errno);

		return false;
	}

	if (setuid(uid) < 0) {
		log_err("Could not setuid(%s). %s (%d)", user,
		    strerror(errno), errno);

		return false;
	}

	return true;
}
Esempio n. 22
0
File: daemon.c Progetto: astubbs/git
int main(int argc, char **argv)
{
	int listen_port = 0;
	char *listen_addr = NULL;
	int inetd_mode = 0;
	const char *pid_file = NULL, *user_name = NULL, *group_name = NULL;
	int detach = 0;
	struct passwd *pass = NULL;
	struct group *group;
	gid_t gid = 0;
	int i;

	git_extract_argv0_path(argv[0]);

	for (i = 1; i < argc; i++) {
		char *arg = argv[i];

		if (!prefixcmp(arg, "--listen=")) {
			listen_addr = xstrdup_tolower(arg + 9);
			continue;
		}
		if (!prefixcmp(arg, "--port=")) {
			char *end;
			unsigned long n;
			n = strtoul(arg+7, &end, 0);
			if (arg[7] && !*end) {
				listen_port = n;
				continue;
			}
		}
		if (!strcmp(arg, "--inetd")) {
			inetd_mode = 1;
			log_syslog = 1;
			continue;
		}
		if (!strcmp(arg, "--verbose")) {
			verbose = 1;
			continue;
		}
		if (!strcmp(arg, "--syslog")) {
			log_syslog = 1;
			continue;
		}
		if (!strcmp(arg, "--export-all")) {
			export_all_trees = 1;
			continue;
		}
		if (!prefixcmp(arg, "--timeout=")) {
			timeout = atoi(arg+10);
			continue;
		}
		if (!prefixcmp(arg, "--init-timeout=")) {
			init_timeout = atoi(arg+15);
			continue;
		}
		if (!prefixcmp(arg, "--max-connections=")) {
			max_connections = atoi(arg+18);
			if (max_connections < 0)
				max_connections = 0;	        /* unlimited */
			continue;
		}
		if (!strcmp(arg, "--strict-paths")) {
			strict_paths = 1;
			continue;
		}
		if (!prefixcmp(arg, "--base-path=")) {
			base_path = arg+12;
			continue;
		}
		if (!strcmp(arg, "--base-path-relaxed")) {
			base_path_relaxed = 1;
			continue;
		}
		if (!prefixcmp(arg, "--interpolated-path=")) {
			interpolated_path = arg+20;
			continue;
		}
		if (!strcmp(arg, "--reuseaddr")) {
			reuseaddr = 1;
			continue;
		}
		if (!strcmp(arg, "--user-path")) {
			user_path = "";
			continue;
		}
		if (!prefixcmp(arg, "--user-path=")) {
			user_path = arg + 12;
			continue;
		}
		if (!prefixcmp(arg, "--pid-file=")) {
			pid_file = arg + 11;
			continue;
		}
		if (!strcmp(arg, "--detach")) {
			detach = 1;
			log_syslog = 1;
			continue;
		}
		if (!prefixcmp(arg, "--user="******"--group=")) {
			group_name = arg + 8;
			continue;
		}
		if (!prefixcmp(arg, "--enable=")) {
			enable_service(arg + 9, 1);
			continue;
		}
		if (!prefixcmp(arg, "--disable=")) {
			enable_service(arg + 10, 0);
			continue;
		}
		if (!prefixcmp(arg, "--allow-override=")) {
			make_service_overridable(arg + 17, 1);
			continue;
		}
		if (!prefixcmp(arg, "--forbid-override=")) {
			make_service_overridable(arg + 18, 0);
			continue;
		}
		if (!strcmp(arg, "--")) {
			ok_paths = &argv[i+1];
			break;
		} else if (arg[0] != '-') {
			ok_paths = &argv[i];
			break;
		}

		usage(daemon_usage);
	}

	if (log_syslog) {
		openlog("git-daemon", LOG_PID, LOG_DAEMON);
		set_die_routine(daemon_die);
	} else
		/* avoid splitting a message in the middle */
		setvbuf(stderr, NULL, _IOLBF, 0);

	if (inetd_mode && (group_name || user_name))
		die("--user and --group are incompatible with --inetd");

	if (inetd_mode && (listen_port || listen_addr))
		die("--listen= and --port= are incompatible with --inetd");
	else if (listen_port == 0)
		listen_port = DEFAULT_GIT_PORT;

	if (group_name && !user_name)
		die("--group supplied without --user");

	if (user_name) {
		pass = getpwnam(user_name);
		if (!pass)
			die("user not found - %s", user_name);

		if (!group_name)
			gid = pass->pw_gid;
		else {
			group = getgrnam(group_name);
			if (!group)
				die("group not found - %s", group_name);

			gid = group->gr_gid;
		}
	}

	if (strict_paths && (!ok_paths || !*ok_paths))
		die("option --strict-paths requires a whitelist");

	if (base_path && !is_directory(base_path))
		die("base-path '%s' does not exist or is not a directory",
		    base_path);

	if (inetd_mode) {
		struct sockaddr_storage ss;
		struct sockaddr *peer = (struct sockaddr *)&ss;
		socklen_t slen = sizeof(ss);

		if (!freopen("/dev/null", "w", stderr))
			die_errno("failed to redirect stderr to /dev/null");

		if (getpeername(0, peer, &slen))
			peer = NULL;

		return execute(peer);
	}

	if (detach) {
		daemonize();
		loginfo("Ready to rumble");
	}
	else
		sanitize_stdfds();

	if (pid_file)
		store_pid(pid_file);

	return serve(listen_addr, listen_port, pass, gid);
}
Esempio n. 23
0
int
main(int argc, char **argv)
{
    extern int optind;
    extern char *optarg, **environ;
    struct group *gr;
    register int ch;
    register char *p;
    int ask, fflag, hflag, pflag, cnt, errsv;
    int quietlog, passwd_req;
    char *domain, *ttyn;
    char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
    char *termenv;
    char *childArgv[10];
    char *buff;
    int childArgc = 0;
#ifdef HAVE_SECURITY_PAM_MISC_H
    int retcode;
    pam_handle_t *pamh = NULL;
    struct pam_conv conv = { misc_conv, NULL };
    pid_t childPid;
#else
    char *salt, *pp;
#endif
#ifdef LOGIN_CHOWN_VCS
    char vcsn[20], vcsan[20];
#endif

    pid = getpid();

    signal(SIGALRM, timedout);
    alarm((unsigned int)timeout);
    signal(SIGQUIT, SIG_IGN);
    signal(SIGINT, SIG_IGN);

    setlocale(LC_ALL, "");
    bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);
    
    setpriority(PRIO_PROCESS, 0, 0);
    initproctitle(argc, argv);
    
    /*
     * -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 and wtmp
     */
    gethostname(tbuf, sizeof(tbuf));
    xstrncpy(thishost, tbuf, sizeof(thishost));
    domain = index(tbuf, '.');
    
    username = tty_name = hostname = NULL;
    fflag = hflag = pflag = 0;
    passwd_req = 1;

    while ((ch = getopt(argc, argv, "fh:p")) != -1)
      switch (ch) {
	case 'f':
	  fflag = 1;
	  break;
	  
	case 'h':
	  if (getuid()) {
	      fprintf(stderr,
		      _("login: -h for super-user only.\n"));
	      exit(1);
	  }
	  hflag = 1;
	  if (domain && (p = index(optarg, '.')) &&
	      strcasecmp(p, domain) == 0)
	    *p = 0;

	  hostname = strdup(optarg); 	/* strdup: Ambrose C. Li */
	  {
		  struct hostent *he = gethostbyname(hostname);

		  /* he points to static storage; copy the part we use */
		  hostaddress[0] = 0;
		  if (he && he->h_addr_list && he->h_addr_list[0])
			  memcpy(hostaddress, he->h_addr_list[0],
				 sizeof(hostaddress));
	  }
	  break;
	  
	case 'p':
	  pflag = 1;
	  break;

	case '?':
	default:
	  fprintf(stderr,
		  _("usage: login [-fp] [username]\n"));
	  exit(1);
      }
    argc -= optind;
    argv += optind;
    if (*argv) {
	char *p = *argv;
	username = strdup(p);
	ask = 0;
	/* wipe name - some people mistype their password here */
	/* (of course we are too late, but perhaps this helps a little ..) */
	while(*p)
	    *p++ = ' ';
    } else
        ask = 1;

    for (cnt = getdtablesize(); cnt > 2; cnt--)
      close(cnt);
    
    ttyn = ttyname(0);

    if (ttyn == NULL || *ttyn == '\0') {
	/* no snprintf required - see definition of tname */
	sprintf(tname, "%s??", _PATH_TTY);
	ttyn = tname;
    }

    check_ttyname(ttyn);

    if (strncmp(ttyn, "/dev/", 5) == 0)
	tty_name = ttyn+5;
    else
	tty_name = ttyn;

    if (strncmp(ttyn, "/dev/tty", 8) == 0)
	tty_number = ttyn+8;
    else {
	char *p = ttyn;
	while (*p && !isdigit(*p)) p++;
	tty_number = p;
    }

#ifdef LOGIN_CHOWN_VCS
    /* find names of Virtual Console devices, for later mode change */
    snprintf(vcsn, sizeof(vcsn), "/dev/vcs%s", tty_number);
    snprintf(vcsan, sizeof(vcsan), "/dev/vcsa%s", tty_number);
#endif

    /* set pgid to pid */
    setpgrp();
    /* this means that setsid() will fail */
    
    {
	struct termios tt, ttt;
	
	tcgetattr(0, &tt);
	ttt = tt;
	ttt.c_cflag &= ~HUPCL;

	/* These can fail, e.g. with ttyn on a read-only filesystem */
	chown(ttyn, 0, 0);
	chmod(ttyn, TTY_MODE);

	/* Kill processes left on this tty */
	tcsetattr(0,TCSAFLUSH,&ttt);
	signal(SIGHUP, SIG_IGN); /* so vhangup() wont kill us */
	vhangup();
	signal(SIGHUP, SIG_DFL);

	/* open stdin,stdout,stderr to the tty */
	opentty(ttyn);
	
	/* restore tty modes */
	tcsetattr(0,TCSAFLUSH,&tt);
    }

    openlog("login", LOG_ODELAY, LOG_AUTHPRIV);

#if 0
    /* other than iso-8859-1 */
    printf("\033(K");
    fprintf(stderr,"\033(K");
#endif

#ifdef HAVE_SECURITY_PAM_MISC_H
    /*
     * username is initialized to NULL
     * and if specified on the command line it is set.
     * Therefore, we are safe not setting it to anything
     */

    retcode = pam_start("login",username, &conv, &pamh);
    if(retcode != PAM_SUCCESS) {
	fprintf(stderr, _("login: PAM Failure, aborting: %s\n"),
		pam_strerror(pamh, retcode));
	syslog(LOG_ERR, _("Couldn't initialize PAM: %s"),
	       pam_strerror(pamh, retcode));
	exit(99);
    }
    /* hostname & tty are either set to NULL or their correct values,
       depending on how much we know */
    retcode = pam_set_item(pamh, PAM_RHOST, hostname);
    PAM_FAIL_CHECK;
    retcode = pam_set_item(pamh, PAM_TTY, tty_name);
    PAM_FAIL_CHECK;

    /*
     * [email protected]: Provide a user prompt to PAM
     * so that the "login: "******"Password: "******"login: "******"\033(K");
    fprintf(stderr,"\033(K");
#endif
	    
    /* if fflag == 1, then the user has already been authenticated */
    if (fflag && (getuid() == 0))
	passwd_req = 0;
    else
	passwd_req = 1;

    if(passwd_req == 1) {
	int failcount=0;

	/* if we didn't get a user on the command line, set it to NULL */
	pam_get_item(pamh,  PAM_USER, (const void **) &username);
	if (!username)
		pam_set_item(pamh, PAM_USER, NULL);

	/* there may be better ways to deal with some of these
	   conditions, but at least this way I don't think we'll
	   be giving away information... */
	/* Perhaps someday we can trust that all PAM modules will
	   pay attention to failure count and get rid of MAX_LOGIN_TRIES? */

	retcode = pam_authenticate(pamh, 0);
	while((failcount++ < PAM_MAX_LOGIN_TRIES) &&
	      ((retcode == PAM_AUTH_ERR) ||
	       (retcode == PAM_USER_UNKNOWN) ||
	       (retcode == PAM_CRED_INSUFFICIENT) ||
	       (retcode == PAM_AUTHINFO_UNAVAIL))) {
	    pam_get_item(pamh, PAM_USER, (const void **) &username);

	    syslog(LOG_NOTICE,_("FAILED LOGIN %d FROM %s FOR %s, %s"),
		   failcount, hostname, username, pam_strerror(pamh, retcode));
	    logbtmp(tty_name, username, hostname);

	    fprintf(stderr,_("Login incorrect\n\n"));
	    pam_set_item(pamh,PAM_USER,NULL);
	    retcode = pam_authenticate(pamh, 0);
	}

	if (retcode != PAM_SUCCESS) {
	    pam_get_item(pamh, PAM_USER, (const void **) &username);

	    if (retcode == PAM_MAXTRIES)
		syslog(LOG_NOTICE,_("TOO MANY LOGIN TRIES (%d) FROM %s FOR "
			"%s, %s"), failcount, hostname, username,
			 pam_strerror(pamh, retcode));
	    else
		syslog(LOG_NOTICE,_("FAILED LOGIN SESSION FROM %s FOR %s, %s"),
			hostname, username, pam_strerror(pamh, retcode));
	    logbtmp(tty_name, username, hostname);

	    fprintf(stderr,_("\nLogin incorrect\n"));
	    pam_end(pamh, retcode);
	    exit(0);
	}

	retcode = pam_acct_mgmt(pamh, 0);

	if(retcode == PAM_NEW_AUTHTOK_REQD) {
	    retcode = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
	}

	PAM_FAIL_CHECK;
    }

    /*
     * Grab the user information out of the password file for future usage
     * First get the username that we are actually using, though.
     */
    retcode = pam_get_item(pamh, PAM_USER, (const void **) &username);
    PAM_FAIL_CHECK;

    if (!username || !*username) {
	    fprintf(stderr, _("\nSession setup problem, abort.\n"));
	    syslog(LOG_ERR, _("NULL user name in %s:%d. Abort."),
		   __FUNCTION__, __LINE__);
	    pam_end(pamh, PAM_SYSTEM_ERR);
	    exit(1);
    }
    if (!(pwd = getpwnam(username))) {
	    fprintf(stderr, _("\nSession setup problem, abort.\n"));
	    syslog(LOG_ERR, _("Invalid user name \"%s\" in %s:%d. Abort."),
		   username, __FUNCTION__, __LINE__);
	    pam_end(pamh, PAM_SYSTEM_ERR);
	    exit(1);
    }

    /*
     * Create a copy of the pwd struct - otherwise it may get
     * clobbered by PAM
     */
    memcpy(&pwdcopy, pwd, sizeof(*pwd));
    pwd = &pwdcopy;
    pwd->pw_name   = strdup(pwd->pw_name);
    pwd->pw_passwd = strdup(pwd->pw_passwd);
    pwd->pw_gecos  = strdup(pwd->pw_gecos);
    pwd->pw_dir    = strdup(pwd->pw_dir);
    pwd->pw_shell  = strdup(pwd->pw_shell);
    if (!pwd->pw_name || !pwd->pw_passwd || !pwd->pw_gecos ||
	!pwd->pw_dir || !pwd->pw_shell) {
	    fprintf(stderr, _("login: Out of memory\n"));
	    syslog(LOG_ERR, "Out of memory");
	    pam_end(pamh, PAM_SYSTEM_ERR);
	    exit(1);
    }
    username = pwd->pw_name;

    /*
     * Initialize the supplementary group list.
     * This should be done before pam_setcred because
     * the PAM modules might add groups during pam_setcred.
     */
    if (initgroups(username, pwd->pw_gid) < 0) {
	    syslog(LOG_ERR, "initgroups: %m");
	    fprintf(stderr, _("\nSession setup problem, abort.\n"));
	    pam_end(pamh, PAM_SYSTEM_ERR);
	    exit(1);
    }

    retcode = pam_open_session(pamh, 0);
    PAM_FAIL_CHECK;

    retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED);
    PAM_FAIL_CHECK;

#else /* ! HAVE_SECURITY_PAM_MISC_H */

    for (cnt = 0;; ask = 1) {

	if (ask) {
	    fflag = 0;
	    getloginname();
	}

	/* Dirty patch to fix a gigantic security hole when using 
	   yellow pages. This problem should be solved by the
	   libraries, and not by programs, but this must be fixed
	   urgently! If the first char of the username is '+', we 
	   avoid login success.
	   Feb 95 <*****@*****.**> */
	
	if (username[0] == '+') {
	    puts(_("Illegal username"));
	    badlogin(username);
	    sleepexit(1);
	}
	
	/* (void)strcpy(tbuf, username); why was this here? */
	if ((pwd = getpwnam(username))) {
#  ifdef SHADOW_PWD
	    struct spwd *sp;
	    
	    if ((sp = getspnam(username)))
	      pwd->pw_passwd = sp->sp_pwdp;
#  endif
	    salt = pwd->pw_passwd;
	} else
	  salt = "xx";
	
	if (pwd) {
	    initgroups(username, pwd->pw_gid);
	    checktty(username, tty_name, pwd); /* in checktty.c */
	}
	
	/* if user not super-user, check for disabled logins */
	if (pwd == NULL || pwd->pw_uid)
	  checknologin();
	
	/*
	 * Disallow automatic login to root; if not invoked by
	 * root, disallow if the uid's differ.
	 */
	if (fflag && pwd) {
	    int uid = getuid();
	    
	    passwd_req = pwd->pw_uid == 0 ||
	      (uid && uid != pwd->pw_uid);
	}
	
	/*
	 * If trying to log in as root, but with insecure terminal,
	 * refuse the login attempt.
	 */
	if (pwd && pwd->pw_uid == 0 && !rootterm(tty_name)) {
	    fprintf(stderr,
		    _("%s login refused on this terminal.\n"),
		    pwd->pw_name);
	    
	    if (hostname)
	      syslog(LOG_NOTICE,
		     _("LOGIN %s REFUSED FROM %s ON TTY %s"),
		     pwd->pw_name, hostname, tty_name);
	    else
	      syslog(LOG_NOTICE,
		     _("LOGIN %s REFUSED ON TTY %s"),
		     pwd->pw_name, tty_name);
	    continue;
	}

	/*
	 * If no pre-authentication and a password exists
	 * for this user, prompt for one and verify it.
	 */
	if (!passwd_req || (pwd && !*pwd->pw_passwd))
	  break;
	
	setpriority(PRIO_PROCESS, 0, -4);
	pp = getpass(_("Password: "******"CRYPTO", 6) == 0) {
	    if (pwd && cryptocard()) break;
	}
#  endif /* CRYPTOCARD */
	
	p = crypt(pp, salt);
	setpriority(PRIO_PROCESS, 0, 0);

#  ifdef KERBEROS
	/*
	 * If not present in pw file, act as we normally would.
	 * If we aren't Kerberos-authenticated, try the normal
	 * pw file for a password.  If that's ok, log the user
	 * in without issueing any tickets.
	 */
	
	if (pwd && !krb_get_lrealm(realm,1)) {
	    /*
	     * get TGT for local realm; be careful about uid's
	     * here for ticket file ownership
	     */
	    setreuid(geteuid(),pwd->pw_uid);
	    kerror = krb_get_pw_in_tkt(pwd->pw_name, "", realm,
				       "krbtgt", realm, DEFAULT_TKT_LIFE, pp);
	    setuid(0);
	    if (kerror == INTK_OK) {
		memset(pp, 0, strlen(pp));
		notickets = 0;	/* user got ticket */
		break;
	    }
	}
#  endif /* KERBEROS */
	memset(pp, 0, strlen(pp));

	if (pwd && !strcmp(p, pwd->pw_passwd))
	  break;
	
	printf(_("Login incorrect\n"));
	badlogin(username); /* log ALL bad logins */
	failures++;
	
	/* we allow 10 tries, but after 3 we start backing off */
	if (++cnt > 3) {
	    if (cnt >= 10) {
		sleepexit(1);
	    }
	    sleep((unsigned int)((cnt - 3) * 5));
	}
    }
#endif /* !HAVE_SECURITY_PAM_MISC_H */
    
    /* committed to login -- turn off timeout */
    alarm((unsigned int)0);
    
    endpwent();
    
    /* This requires some explanation: As root we may not be able to
       read the directory of the user if it is on an NFS mounted
       filesystem. We temporarily set our effective uid to the user-uid
       making sure that we keep root privs. in the real uid. 
       
       A portable solution would require a fork(), but we rely on Linux
       having the BSD setreuid() */
    
    {
	char tmpstr[MAXPATHLEN];
	uid_t ruid = getuid();
	gid_t egid = getegid();

	/* avoid snprintf - old systems do not have it, or worse,
	   have a libc in which snprintf is the same as sprintf */
	if (strlen(pwd->pw_dir) + sizeof(_PATH_HUSHLOGIN) + 2 > MAXPATHLEN)
		quietlog = 0;
	else {
		sprintf(tmpstr, "%s/%s", pwd->pw_dir, _PATH_HUSHLOGIN);
		setregid(-1, pwd->pw_gid);
		setreuid(0, pwd->pw_uid);
		quietlog = (access(tmpstr, R_OK) == 0);
		setuid(0); /* setreuid doesn't do it alone! */
		setreuid(ruid, 0);
		setregid(-1, egid);
	}
    }
    
    /* for linux, write entries in utmp and wtmp */
    {
	struct utmp ut;
	struct utmp *utp;
	
	utmpname(_PATH_UTMP);
	setutent();

	/* Find pid in utmp.
login sometimes overwrites the runlevel entry in /var/run/utmp,
confusing sysvinit. I added a test for the entry type, and the problem
was gone. (In a runlevel entry, st_pid is not really a pid but some number
calculated from the previous and current runlevel).
Michael Riepe <*****@*****.**>
	*/
	while ((utp = getutent()))
		if (utp->ut_pid == pid
		    && utp->ut_type >= INIT_PROCESS
		    && utp->ut_type <= DEAD_PROCESS)
			break;

	/* If we can't find a pre-existing entry by pid, try by line.
	   BSD network daemons may rely on this. (anonymous) */
	if (utp == NULL) {
	     setutent();
	     ut.ut_type = LOGIN_PROCESS;
	     strncpy(ut.ut_line, tty_name, sizeof(ut.ut_line));
	     utp = getutline(&ut);
	}
	
	if (utp) {
	    memcpy(&ut, utp, sizeof(ut));
	} else {
	    /* some gettys/telnetds don't initialize utmp... */
	    memset(&ut, 0, sizeof(ut));
	}
	
	if (ut.ut_id[0] == 0)
	  strncpy(ut.ut_id, tty_number, sizeof(ut.ut_id));
	
	strncpy(ut.ut_user, username, sizeof(ut.ut_user));
	xstrncpy(ut.ut_line, tty_name, sizeof(ut.ut_line));
#ifdef _HAVE_UT_TV		/* in <utmpbits.h> included by <utmp.h> */
	gettimeofday(&ut.ut_tv, NULL);
#else
	{
	    time_t t;
	    time(&t);
	    ut.ut_time = t;	/* ut_time is not always a time_t */
				/* glibc2 #defines it as ut_tv.tv_sec */
	}
#endif
	ut.ut_type = USER_PROCESS;
	ut.ut_pid = pid;
	if (hostname) {
		xstrncpy(ut.ut_host, hostname, sizeof(ut.ut_host));
		if (hostaddress[0])
			memcpy(&ut.ut_addr, hostaddress, sizeof(ut.ut_addr));
	}
	
	pututline(&ut);
	endutent();

#if HAVE_UPDWTMP
	updwtmp(_PATH_WTMP, &ut);
#else
#if 0
	/* The O_APPEND open() flag should be enough to guarantee
	   atomic writes at end of file. */
	{
	    int wtmp;

	    if((wtmp = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) {
		write(wtmp, (char *)&ut, sizeof(ut));
		close(wtmp);
	    }
	}
#else
	/* Probably all this locking below is just nonsense,
	   and the short version is OK as well. */
	{ 
	    int lf, wtmp;
	    if ((lf = open(_PATH_WTMPLOCK, O_CREAT|O_WRONLY, 0660)) >= 0) {
		flock(lf, LOCK_EX);
		if ((wtmp = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) {
		    write(wtmp, (char *)&ut, sizeof(ut));
		    close(wtmp);
		}
		flock(lf, LOCK_UN);
		close(lf);
	    }
	}
#endif
#endif
    }
    
    dolastlog(quietlog);
    
    chown(ttyn, pwd->pw_uid,
	  (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
    chmod(ttyn, TTY_MODE);

#ifdef LOGIN_CHOWN_VCS
    /* if tty is one of the VC's then change owner and mode of the 
       special /dev/vcs devices as well */
    if (consoletty(0)) {
	chown(vcsn, pwd->pw_uid, (gr ? gr->gr_gid : pwd->pw_gid));
	chown(vcsan, pwd->pw_uid, (gr ? gr->gr_gid : pwd->pw_gid));
	chmod(vcsn, TTY_MODE);
	chmod(vcsan, TTY_MODE);
    }
#endif

    setgid(pwd->pw_gid);
    
    if (*pwd->pw_shell == '\0')
      pwd->pw_shell = _PATH_BSHELL;
    
    /* preserve TERM even without -p flag */
    {
	char *ep;
	
	if(!((ep = getenv("TERM")) && (termenv = strdup(ep))))
	  termenv = "dumb";
    }
    
    /* destroy environment unless user has requested preservation */
    if (!pflag)
      {
          environ = (char**)malloc(sizeof(char*));
	  memset(environ, 0, sizeof(char*));
      }
    
    setenv("HOME", pwd->pw_dir, 0);      /* legal to override */
    if(pwd->pw_uid)
      setenv("PATH", _PATH_DEFPATH, 1);
    else
      setenv("PATH", _PATH_DEFPATH_ROOT, 1);
    
    setenv("SHELL", pwd->pw_shell, 1);
    setenv("TERM", termenv, 1);
    
    /* mailx will give a funny error msg if you forget this one */
    {
      char tmp[MAXPATHLEN];
      /* avoid snprintf */
      if (sizeof(_PATH_MAILDIR) + strlen(pwd->pw_name) + 1 < MAXPATHLEN) {
	      sprintf(tmp, "%s/%s", _PATH_MAILDIR, pwd->pw_name);
	      setenv("MAIL",tmp,0);
      }
    }
    
    /* LOGNAME is not documented in login(1) but
       HP-UX 6.5 does it. We'll not allow modifying it.
       */
    setenv("LOGNAME", pwd->pw_name, 1);

#ifdef HAVE_SECURITY_PAM_MISC_H
    {
	int i;
	char ** env = pam_getenvlist(pamh);

	if (env != NULL) {
	    for (i=0; env[i]; i++) {
		putenv(env[i]);
		/* D(("env[%d] = %s", i,env[i])); */
	    }
	}
    }
#endif

    setproctitle("login", username);
    
    if (!strncmp(tty_name, "ttyS", 4))
      syslog(LOG_INFO, _("DIALUP AT %s BY %s"), tty_name, pwd->pw_name);
    
    /* allow tracking of good logins.
       -steve philp ([email protected]) */
    
    if (pwd->pw_uid == 0) {
	if (hostname)
	  syslog(LOG_NOTICE, _("ROOT LOGIN ON %s FROM %s"),
		 tty_name, hostname);
	else
	  syslog(LOG_NOTICE, _("ROOT LOGIN ON %s"), tty_name);
    } else {
	if (hostname) 
	  syslog(LOG_INFO, _("LOGIN ON %s BY %s FROM %s"), tty_name, 
		 pwd->pw_name, hostname);
	else 
	  syslog(LOG_INFO, _("LOGIN ON %s BY %s"), tty_name, 
		 pwd->pw_name);
    }
    
    if (!quietlog) {
	motd();

#ifdef LOGIN_STAT_MAIL
	/*
	 * This turns out to be a bad idea: when the mail spool
	 * is NFS mounted, and the NFS connection hangs, the
	 * login hangs, even root cannot login.
	 * Checking for mail should be done from the shell.
	 */
	{
	    struct stat st;
	    char *mail;
	
	    mail = getenv("MAIL");
	    if (mail && stat(mail, &st) == 0 && st.st_size != 0) {
		if (st.st_mtime > st.st_atime)
			printf(_("You have new mail.\n"));
		else
			printf(_("You have mail.\n"));
	    }
	}
#endif
    }
    
    signal(SIGALRM, SIG_DFL);
    signal(SIGQUIT, SIG_DFL);
    signal(SIGTSTP, SIG_IGN);

#ifdef HAVE_SECURITY_PAM_MISC_H
    /*
     * We must fork before setuid() because we need to call
     * pam_close_session() as root.
     */
    
    childPid = fork();
    if (childPid < 0) {
       int errsv = errno;
       /* error in fork() */
       fprintf(stderr, _("login: failure forking: %s"), strerror(errsv));
       PAM_END;
       exit(0);
    }

    if (childPid) {
       /* parent - wait for child to finish, then cleanup session */
       signal(SIGHUP, SIG_IGN);
       signal(SIGINT, SIG_IGN);
       signal(SIGQUIT, SIG_IGN);
       signal(SIGTSTP, SIG_IGN);
       signal(SIGTTIN, SIG_IGN);
       signal(SIGTTOU, SIG_IGN);

       wait(NULL);
       PAM_END;
       exit(0);
    }

    /* child */
    /*
     * Problem: if the user's shell is a shell like ash that doesnt do
     * setsid() or setpgrp(), then a ctrl-\, sending SIGQUIT to every
     * process in the pgrp, will kill us.
     */

    /* start new session */
    setsid();

    /* make sure we have a controlling tty */
    opentty(ttyn);
    openlog("login", LOG_ODELAY, LOG_AUTHPRIV);	/* reopen */

    /*
     * TIOCSCTTY: steal tty from other process group.
     */
    if (ioctl(0, TIOCSCTTY, 1))
	    syslog(LOG_ERR, _("TIOCSCTTY failed: %m"));
#endif
    signal(SIGINT, SIG_DFL);
    
    /* discard permissions last so can't get killed and drop core */
    if(setuid(pwd->pw_uid) < 0 && pwd->pw_uid) {
	syslog(LOG_ALERT, _("setuid() failed"));
	exit(1);
    }
    
    /* wait until here to change directory! */
    if (chdir(pwd->pw_dir) < 0) {
	printf(_("No directory %s!\n"), pwd->pw_dir);
	if (chdir("/"))
	  exit(0);
	pwd->pw_dir = "/";
	printf(_("Logging in with home = \"/\".\n"));
    }
    
    /* if the shell field has a space: treat it like a shell script */
    if (strchr(pwd->pw_shell, ' ')) {
	buff = malloc(strlen(pwd->pw_shell) + 6);

	if (!buff) {
	    fprintf(stderr, _("login: no memory for shell script.\n"));
	    exit(0);
	}

	strcpy(buff, "exec ");
	strcat(buff, pwd->pw_shell);
	childArgv[childArgc++] = "/bin/sh";
	childArgv[childArgc++] = "-sh";
	childArgv[childArgc++] = "-c";
	childArgv[childArgc++] = buff;
    } else {
	tbuf[0] = '-';
	xstrncpy(tbuf + 1, ((p = rindex(pwd->pw_shell, '/')) ?
			   p + 1 : pwd->pw_shell),
		sizeof(tbuf)-1);
	
	childArgv[childArgc++] = pwd->pw_shell;
	childArgv[childArgc++] = tbuf;
    }

    childArgv[childArgc++] = NULL;

    execvp(childArgv[0], childArgv + 1);

    errsv = errno;

    if (!strcmp(childArgv[0], "/bin/sh"))
	fprintf(stderr, _("login: couldn't exec shell script: %s.\n"),
		strerror(errsv));
    else
	fprintf(stderr, _("login: no shell: %s.\n"), strerror(errsv));

    exit(0);
}
Esempio n. 24
0
void config_param_validate (char *k, char *v, stud_config *cfg, char *file, int line) {
    int r = 1;
    struct stat st;

    if (strcmp(k, "tls") == 0) {
        cfg->ETYPE = ENC_TLS;
    }
    else if (strcmp(k, "ssl") == 0) {
        cfg->ETYPE = ENC_SSL;
    }
    else if (strcmp(k, CFG_CIPHERS) == 0) {
        if (v != NULL && strlen(v) > 0) {
            config_assign_str(&cfg->CIPHER_SUITE, v);
        }
    }
    else if (strcmp(k, CFG_SSL_ENGINE) == 0) {
        if (v != NULL && strlen(v) > 0) {
            config_assign_str(&cfg->ENGINE, v);
        }
    }
    else if (strcmp(k, CFG_PREFER_SERVER_CIPHERS) == 0) {
        r = config_param_val_bool(v, &cfg->PREFER_SERVER_CIPHERS);
    }
    else if (strcmp(k, CFG_FRONTEND) == 0) {
        r = config_param_host_port_wildcard(v, &cfg->FRONT_IP, &cfg->FRONT_PORT, 1);
    }
    else if (strcmp(k, CFG_BACKEND) == 0) {
        r = config_param_host_port(v, &cfg->BACK_IP, &cfg->BACK_PORT);
    }
    else if (strcmp(k, CFG_WORKERS) == 0) {
        r = config_param_val_intl_pos(v, &cfg->NCORES);
    }
    else if (strcmp(k, CFG_BACKLOG) == 0) {
        r = config_param_val_int(v, &cfg->BACKLOG);
        if (r && cfg->BACKLOG < -1) cfg->BACKLOG = -1;
    }
    else if (strcmp(k, CFG_KEEPALIVE) == 0) {
        r = config_param_val_int_pos(v, &cfg->TCP_KEEPALIVE_TIME);
    }
#ifdef USE_SHARED_CACHE
    else if (strcmp(k, CFG_SHARED_CACHE) == 0) {
        r = config_param_val_int(v, &cfg->SHARED_CACHE);
    }
    else if (strcmp(k, CFG_SHARED_CACHE_LISTEN) == 0) {
        if (v != NULL && strlen(v) > 0)
            r = config_param_host_port_wildcard(v, &cfg->SHCUPD_IP, &cfg->SHCUPD_PORT, 1);
    }
    else if (strcmp(k, CFG_SHARED_CACHE_PEER) == 0) {
        r = config_param_shcupd_peer(v, cfg);
    }
    else if (strcmp(k, CFG_SHARED_CACHE_MCASTIF) == 0) {
        r = config_param_shcupd_mcastif(v, &cfg->SHCUPD_MCASTIF, &cfg->SHCUPD_MCASTTTL);
    }
#endif
    else if (strcmp(k, CFG_CHROOT) == 0) {
        if (v != NULL && strlen(v) > 0) {
            // check directory
            if (stat(v, &st) != 0) {
                config_error_set("Unable to stat directory '%s': %s'.", v, strerror(errno));
                r = 0;
            } else {
                if (! S_ISDIR(st.st_mode)) {
                    config_error_set("Bad chroot directory '%s': Not a directory.", v, strerror(errno));
                    r = 0;
                } else {
                    config_assign_str(&cfg->CHROOT, v);
                }
            }
        }
    }
    else if (strcmp(k, CFG_USER) == 0) {
        if (v != NULL && strlen(v) > 0) {
            struct passwd *passwd;
            passwd = getpwnam(v);
            if (!passwd) {
                config_error_set("Invalid user '%s'.", v);
                r = 0;
            } else {
                cfg->UID = passwd->pw_uid;
                cfg->GID = passwd->pw_gid;
            }
        }
    }
    else if (strcmp(k, CFG_GROUP) == 0) {
        if (v != NULL && strlen(v) > 0) {
            struct group *grp;
            grp = getgrnam(v);
            if (!grp) {
                config_error_set("Invalid group '%s'.", v);
                r = 0;
            } else {
                cfg->GID = grp->gr_gid;
            }
        }
    }
    else if (strcmp(k, CFG_QUIET) == 0) {
        r = config_param_val_bool(v, &cfg->QUIET);
    }
    else if (strcmp(k, CFG_SYSLOG) == 0) {
        r = config_param_val_bool(v, &cfg->SYSLOG);
    }
    else if (strcmp(k, CFG_SYSLOG_FACILITY) == 0) {
        r = 1;
        if (!strcmp(v, "auth") || !strcmp(v, "authpriv"))
            cfg->SYSLOG_FACILITY = LOG_AUTHPRIV;
        else if (!strcmp(v, "cron"))
            cfg->SYSLOG_FACILITY = LOG_CRON;
        else if (!strcmp(v, "daemon"))
            cfg->SYSLOG_FACILITY = LOG_DAEMON;
        else if (!strcmp(v, "ftp"))
            cfg->SYSLOG_FACILITY = LOG_FTP;
        else if (!strcmp(v, "local0"))
            cfg->SYSLOG_FACILITY = LOG_LOCAL0;
        else if (!strcmp(v, "local1"))
            cfg->SYSLOG_FACILITY = LOG_LOCAL1;
        else if (!strcmp(v, "local2"))
            cfg->SYSLOG_FACILITY = LOG_LOCAL2;
        else if (!strcmp(v, "local3"))
            cfg->SYSLOG_FACILITY = LOG_LOCAL3;
        else if (!strcmp(v, "local4"))
            cfg->SYSLOG_FACILITY = LOG_LOCAL4;
        else if (!strcmp(v, "local5"))
            cfg->SYSLOG_FACILITY = LOG_LOCAL5;
        else if (!strcmp(v, "local6"))
            cfg->SYSLOG_FACILITY = LOG_LOCAL6;
        else if (!strcmp(v, "local7"))
            cfg->SYSLOG_FACILITY = LOG_LOCAL7;
        else if (!strcmp(v, "lpr"))
            cfg->SYSLOG_FACILITY = LOG_LPR;
        else if (!strcmp(v, "mail"))
            cfg->SYSLOG_FACILITY = LOG_MAIL;
        else if (!strcmp(v, "news"))
            cfg->SYSLOG_FACILITY = LOG_NEWS;
        else if (!strcmp(v, "user"))
            cfg->SYSLOG_FACILITY = LOG_USER;
        else if (!strcmp(v, "uucp"))
            cfg->SYSLOG_FACILITY = LOG_UUCP;
        else {
            config_error_set("Invalid facility '%s'.", v);
            r = 0;
        }
    }
    else if (strcmp(k, CFG_DAEMON) == 0) {
        r = config_param_val_bool(v, &cfg->DAEMONIZE);
    }
    else if (strcmp(k, CFG_WRITE_IP) == 0) {
        r = config_param_val_bool(v, &cfg->WRITE_IP_OCTET);
    }
    else if (strcmp(k, CFG_WRITE_PROXY) == 0) {
        r = config_param_val_bool(v, &cfg->WRITE_PROXY_LINE);
    }
    else if (strcmp(k, CFG_PROXY_PROXY) == 0) {
        r = config_param_val_bool(v, &cfg->PROXY_PROXY_LINE);
    }
    else if (strcmp(k, CFG_PEM_FILE) == 0) {
        if (v != NULL && strlen(v) > 0) {
            if (stat(v, &st) != 0) {
                config_error_set("Unable to stat x509 certificate PEM file '%s': ", v, strerror(errno));
                r = 0;
            }
            else if (! S_ISREG(st.st_mode)) {
                config_error_set("Invalid x509 certificate PEM file '%s': Not a file.", v);
                r = 0;
            } else {
                struct cert_files *cert = calloc(1, sizeof(*cert));
                config_assign_str(&cert->CERT_FILE, v);
                cert->NEXT = cfg->CERT_FILES;
                cfg->CERT_FILES = cert;
            }
        }
    }
    else {
        fprintf(
            stderr,
            "Ignoring unknown configuration key '%s' in configuration file '%s', line %d\n",
            k, file, line
        );
    }

    if (! r) {
        if (file != NULL)
            config_die("Error in configuration file '%s', line %d: %s\n", file, line, config_error_get());
        else
            config_die("Invalid parameter '%s': %s", k, config_error_get());
    }
}
Esempio n. 25
0
int
su_main (int argc, char **argv, int mode)
{
  int optc;
  const char *new_user = DEFAULT_USER, *runuser_user = NULL;
  char *command = NULL;
  int request_same_session = 0;
  char *shell = NULL;
  struct passwd *pw;
  struct passwd pw_copy;
  struct group *gr;
  gid_t groups[NGROUPS_MAX];
  int num_supp_groups = 0;
  int use_gid = 0;

  static const struct option longopts[] = {
    {"command", required_argument, NULL, 'c'},
    {"session-command", required_argument, NULL, 'C'},
    {"fast", no_argument, NULL, 'f'},
    {"login", no_argument, NULL, 'l'},
    {"preserve-environment", no_argument, NULL, 'p'},
    {"shell", required_argument, NULL, 's'},
    {"group", required_argument, NULL, 'g'},
    {"supp-group", required_argument, NULL, 'G'},
    {"user", required_argument, NULL, 'u'},		/* runuser only */
    {"help", no_argument, 0, 'h'},
    {"version", no_argument, 0, 'V'},
    {NULL, 0, NULL, 0}
  };

  setlocale (LC_ALL, "");
  bindtextdomain (PACKAGE, LOCALEDIR);
  textdomain (PACKAGE);
  atexit(close_stdout);

  su_mode = mode;
  fast_startup = false;
  simulate_login = false;
  change_environment = true;

  while ((optc = getopt_long (argc, argv, "c:fg:G:lmps:u:hV", longopts, NULL)) != -1)
    {
      switch (optc)
	{
	case 'c':
	  command = optarg;
	  break;

        case 'C':
          command = optarg;
          request_same_session = 1;
          break;

	case 'f':
	  fast_startup = true;
	  break;

	case 'g':
	  gr = getgrnam(optarg);
	  if (!gr)
	    errx(EXIT_FAILURE, _("group %s does not exist"), optarg);
	  use_gid = 1;
	  groups[0] = gr->gr_gid;
	  break;

	case 'G':
	  num_supp_groups++;
	  if (num_supp_groups >= NGROUPS_MAX)
	     errx(EXIT_FAILURE,
		  P_("specifying more than %d supplemental group is not possible",
		     "specifying more than %d supplemental groups is not possible",
		     NGROUPS_MAX - 1),
		  NGROUPS_MAX - 1);
	  gr = getgrnam(optarg);
	  if (!gr)
	    errx(EXIT_FAILURE, _("group %s does not exist"), optarg);
	  groups[num_supp_groups] = gr->gr_gid;
	  break;

	case 'l':
	  simulate_login = true;
	  break;

	case 'm':
	case 'p':
	  change_environment = false;
	  break;

	case 's':
	  shell = optarg;
	  break;

	case 'u':
	  if (su_mode != RUNUSER_MODE)
	    usage (EXIT_FAILURE);
	  runuser_user = optarg;
	  break;

	case 'h':
	  usage(0);

	case 'V':
	  printf(UTIL_LINUX_VERSION);
	  exit(EXIT_SUCCESS);

	default:
	  usage (EXIT_FAILURE);
	}
    }

  restricted = evaluate_uid ();

  if (optind < argc && !strcmp (argv[optind], "-"))
    {
      simulate_login = true;
      ++optind;
    }

  if (simulate_login && !change_environment) {
    warnx(_("ignore --preserve-environment, it's mutually exclusive to --login."));
    change_environment = true;
  }

  switch (su_mode) {
  case RUNUSER_MODE:
    if (runuser_user) {
      /* runuser -u <user> <command> */
      new_user = runuser_user;
      if (shell || fast_startup || command || simulate_login) {
        errx(EXIT_FAILURE,
	   _("options --{shell,fast,command,session-command,login} and "
	     "--user are mutually exclusive."));
      }
      if (optind == argc)
        errx(EXIT_FAILURE, _("COMMAND not specified."));

      break;
    }
    /* fallthrough if -u <user> is not specified, then follow
     * traditional su(1) behavior
     */
  case SU_MODE:
    if (optind < argc)
      new_user = argv[optind++];
    break;
  }

  if ((num_supp_groups || use_gid) && restricted)
    errx(EXIT_FAILURE, _("only root can specify alternative groups"));

  logindefs_load_defaults = load_config;

  pw = getpwnam (new_user);
  if (! (pw && pw->pw_name && pw->pw_name[0] && pw->pw_dir && pw->pw_dir[0]
	 && pw->pw_passwd))
    errx (EXIT_FAILURE, _("user %s does not exist"), new_user);

  /* Make a copy of the password information and point pw at the local
     copy instead.  Otherwise, some systems (e.g. Linux) would clobber
     the static data through the getlogin call from log_su.
     Also, make sure pw->pw_shell is a nonempty string.
     It may be NULL when NEW_USER is a username that is retrieved via NIS (YP),
     but that doesn't have a default shell listed.  */
  pw_copy = *pw;
  pw = &pw_copy;
  pw->pw_name = xstrdup (pw->pw_name);
  pw->pw_passwd = xstrdup (pw->pw_passwd);
  pw->pw_dir = xstrdup (pw->pw_dir);
  pw->pw_shell = xstrdup (pw->pw_shell && pw->pw_shell[0]
			  ? pw->pw_shell
			  : DEFAULT_SHELL);
  endpwent ();

  if (num_supp_groups && !use_gid)
  {
    pw->pw_gid = groups[1];
    memmove (groups, groups + 1, sizeof(gid_t) * num_supp_groups);
  }
  else if (use_gid)
  {
    pw->pw_gid = groups[0];
    num_supp_groups++;
  }

  authenticate (pw);

  if (request_same_session || !command || !pw->pw_uid)
    same_session = 1;

  /* initialize shell variable only if "-u <user>" not specified */
  if (runuser_user) {
    shell = NULL;
  } else {
    if (!shell && !change_environment)
      shell = getenv ("SHELL");
    if (shell && getuid () != 0 && restricted_shell (pw->pw_shell))
      {
	/* The user being su'd to has a nonstandard shell, and so is
	   probably a uucp account or has restricted access.  Don't
	   compromise the account by allowing access with a standard
	   shell.  */
	warnx (_("using restricted shell %s"), pw->pw_shell);
	shell = NULL;
      }
    shell = xstrdup (shell ? shell : pw->pw_shell);
  }

  init_groups (pw, groups, num_supp_groups);

  if (!simulate_login || command)
    suppress_pam_info = 1;		/* don't print PAM info messages */

  create_watching_parent ();
  /* Now we're in the child.  */

  change_identity (pw);
  if (!same_session)
    setsid ();

  /* Set environment after pam_open_session, which may put KRB5CCNAME
     into the pam_env, etc.  */

  modify_environment (pw, shell);

  if (simulate_login && chdir (pw->pw_dir) != 0)
    warn (_("warning: cannot change directory to %s"), pw->pw_dir);

  if (shell)
    run_shell (shell, command, argv + optind, max (0, argc - optind));
  else {
    execvp(argv[optind], &argv[optind]);
    err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]);
  }
}
Esempio n. 26
0
int main(int argc, char **argv)
{
	int devnull_fd = -1;
#ifdef TIOCNOTTY
	int tty_fd = -1;
#endif

#ifdef HAVE_PAM
	pam_handle_t *pamh = NULL;
	int pamr;
	const char *const *pamenv = NULL;
#endif

	int opt;
	size_t size = 0;
	bool start = false;
	bool stop = false;
	bool oknodo = false;
	bool test = false;
	char *exec = NULL;
	char *startas = NULL;
	char *name = NULL;
	char *pidfile = NULL;
	char *retry = NULL;
	int sig = -1;
	int nicelevel = 0, ionicec = -1, ioniced = 0;
	bool background = false;
	bool makepidfile = false;
	bool interpreted = false;
	bool progress = false;
	uid_t uid = 0;
	gid_t gid = 0;
	char *home = NULL;
	int tid = 0;
	char *redirect_stderr = NULL;
	char *redirect_stdout = NULL;
	char *stderr_process = NULL;
	char *stdout_process = NULL;
	int stdin_fd;
	int stdout_fd;
	int stderr_fd;
	pid_t pid, spid;
	RC_PIDLIST *pids;
	int i;
	char *svcname = getenv("RC_SVCNAME");
	RC_STRINGLIST *env_list;
	RC_STRING *env;
	char *tmp, *newpath, *np;
	char *p;
	char *token;
	char *exec_file = NULL;
	struct passwd *pw;
	struct group *gr;
	char *line = NULL;
	FILE *fp;
	size_t len;
	mode_t numask = 022;
	char **margv;
	unsigned int start_wait = 0;

	applet = basename_c(argv[0]);
	atexit(cleanup);

	signal_setup(SIGINT, handle_signal);
	signal_setup(SIGQUIT, handle_signal);
	signal_setup(SIGTERM, handle_signal);

	if ((tmp = getenv("SSD_NICELEVEL")))
		if (sscanf(tmp, "%d", &nicelevel) != 1)
			eerror("%s: invalid nice level `%s' (SSD_NICELEVEL)",
			    applet, tmp);
	if ((tmp = getenv("SSD_IONICELEVEL"))) {
		int n = sscanf(tmp, "%d:%d", &ionicec, &ioniced);
		if (n != 1 && n != 2)
			eerror("%s: invalid ionice level `%s' (SSD_IONICELEVEL)",
			    applet, tmp);
		if (ionicec == 0)
			ioniced = 0;
		else if (ionicec == 3)
			ioniced = 7;
		ionicec <<= 13; /* class shift */
	}

	/* Get our user name and initial dir */
	p = getenv("USER");
	home = getenv("HOME");
	if (home == NULL || p == NULL) {
		pw = getpwuid(getuid());
		if (pw != NULL) {
			if (p == NULL)
				setenv("USER", pw->pw_name, 1);
			if (home == NULL) {
				setenv("HOME", pw->pw_dir, 1);
				home = pw->pw_dir;
			}
		}
	}

	while ((opt = getopt_long(argc, argv, getoptstring, longopts,
		    (int *) 0)) != -1)
		switch (opt) {
		case 'I': /* --ionice */
			if (sscanf(optarg, "%d:%d", &ionicec, &ioniced) == 0)
				eerrorx("%s: invalid ionice `%s'",
				    applet, optarg);
			if (ionicec == 0)
				ioniced = 0;
			else if (ionicec == 3)
				ioniced = 7;
			ionicec <<= 13; /* class shift */
			break;

		case 'K':  /* --stop */
			stop = true;
			break;

		case 'N':  /* --nice */
			if (sscanf(optarg, "%d", &nicelevel) != 1)
				eerrorx("%s: invalid nice level `%s'",
				    applet, optarg);
			break;

		case 'P':  /* --progress */
			progress = true;
			break;

		case 'R':  /* --retry <schedule>|<timeout> */
			retry = optarg;
			break;

		case 'S':  /* --start */
			start = true;
			break;

		case 'b':  /* --background */
			background = true;
			break;

		case 'c':  /* --chuid <username>|<uid> */
			/* DEPRECATED */
			ewarn("WARNING: -c/--chuid is deprecated and will be removed in the future, please use -u/--user instead");
			/* falls through */
		case 'u':  /* --user <username>|<uid> */
		{
			p = optarg;
			tmp = strsep(&p, ":");
			changeuser = xstrdup(tmp);
			if (sscanf(tmp, "%d", &tid) != 1)
				pw = getpwnam(tmp);
			else
				pw = getpwuid((uid_t)tid);

			if (pw == NULL)
				eerrorx("%s: user `%s' not found",
				    applet, tmp);
			uid = pw->pw_uid;
			home = pw->pw_dir;
			unsetenv("HOME");
			if (pw->pw_dir)
				setenv("HOME", pw->pw_dir, 1);
			unsetenv("USER");
			if (pw->pw_name)
				setenv("USER", pw->pw_name, 1);
			if (gid == 0)
				gid = pw->pw_gid;

			if (p) {
				tmp = strsep (&p, ":");
				if (sscanf(tmp, "%d", &tid) != 1)
					gr = getgrnam(tmp);
				else
					gr = getgrgid((gid_t) tid);

				if (gr == NULL)
					eerrorx("%s: group `%s'"
					    " not found",
					    applet, tmp);
				gid = gr->gr_gid;
			}
		}
		break;

		case 'd':  /* --chdir /new/dir */
			ch_dir = optarg;
			break;

		case 'e': /* --env */
			putenv(optarg);
			break;

		case 'g':  /* --group <group>|<gid> */
			if (sscanf(optarg, "%d", &tid) != 1)
				gr = getgrnam(optarg);
			else
				gr = getgrgid((gid_t)tid);
			if (gr == NULL)
				eerrorx("%s: group `%s' not found",
				    applet, optarg);
			gid = gr->gr_gid;
			break;

		case 'i': /* --interpreted */
			interpreted = true;
			break;

		case 'k':
			if (parse_mode(&numask, optarg))
				eerrorx("%s: invalid mode `%s'",
				    applet, optarg);
			break;

		case 'm':  /* --make-pidfile */
			makepidfile = true;
			break;

		case 'n':  /* --name <process-name> */
			name = optarg;
			break;

		case 'o':  /* --oknodo */
			/* DEPRECATED */
			ewarn("WARNING: -o/--oknodo is deprecated and will be removed in the future");
			oknodo = true;
			break;

		case 'p':  /* --pidfile <pid-file> */
			pidfile = optarg;
			break;

		case 's':  /* --signal <signal> */
			sig = parse_signal(applet, optarg);
			break;

		case 't':  /* --test */
			test = true;
			break;

		case 'r':  /* --chroot /new/root */
			ch_root = optarg;
			break;

		case 'a': /* --startas <name> */
			/* DEPRECATED */
			ewarn("WARNING: -a/--startas is deprecated and will be removed in the future, please use -x/--exec or -n/--name instead");
			startas = optarg;
			break;
		case 'w':
			if (sscanf(optarg, "%d", &start_wait) != 1)
				eerrorx("%s: `%s' not a number",
				    applet, optarg);
			break;
		case 'x':  /* --exec <executable> */
			exec = optarg;
			break;

		case '1':   /* --stdout /path/to/stdout.lgfile */
			redirect_stdout = optarg;
			break;

		case '2':  /* --stderr /path/to/stderr.logfile */
			redirect_stderr = optarg;
			break;

		case '3':   /* --stdout-logger "command to run for stdout logging" */
			stdout_process = optarg;
			break;

		case '4':  /* --stderr-logger "command to run for stderr logging" */
			stderr_process = optarg;
			break;

		case_RC_COMMON_GETOPT
		}

	endpwent();
	argc -= optind;
	argv += optind;

	/* Allow start-stop-daemon --signal HUP --exec /usr/sbin/dnsmasq
	 * instead of forcing --stop --oknodo as well */
	if (!start &&
	    !stop &&
	    sig != SIGINT &&
	    sig != SIGTERM &&
	    sig != SIGQUIT &&
	    sig != SIGKILL)
		oknodo = true;

	if (!exec)
		exec = startas;
	else if (!name)
		name = startas;

	if (!exec) {
		exec = *argv;
		if (!exec)
			exec = name;
		if (name && start)
			*argv = name;
	} else if (name) {
		*--argv = name;
		++argc;
    } else if (exec) {
		*--argv = exec;
		++argc;
	};

	if (stop || sig != -1) {
		if (sig == -1)
			sig = SIGTERM;
		if (!*argv && !pidfile && !name && !uid)
			eerrorx("%s: --stop needs --exec, --pidfile,"
			    " --name or --user", applet);
		if (background)
			eerrorx("%s: --background is only relevant with"
			    " --start", applet);
		if (makepidfile)
			eerrorx("%s: --make-pidfile is only relevant with"
			    " --start", applet);
		if (redirect_stdout || redirect_stderr)
			eerrorx("%s: --stdout and --stderr are only relevant"
			    " with --start", applet);
		if (stdout_process || stderr_process)
			eerrorx("%s: --stdout-logger and --stderr-logger are only relevant"
			    " with --start", applet);
		if (start_wait)
			ewarn("using --wait with --stop has no effect,"
			    " use --retry instead");
	} else {
		if (!exec)
			eerrorx("%s: nothing to start", applet);
		if (makepidfile && !pidfile)
			eerrorx("%s: --make-pidfile is only relevant with"
			    " --pidfile", applet);
		if ((redirect_stdout || redirect_stderr) && !background)
			eerrorx("%s: --stdout and --stderr are only relevant"
			    " with --background", applet);
		if ((stdout_process || stderr_process) && !background)
			eerrorx("%s: --stdout-logger and --stderr-logger are only relevant"
			    " with --background", applet);
		if (redirect_stdout && stdout_process)
			eerrorx("%s: do not use --stdout and --stdout-logger together",
					applet);
		if (redirect_stderr && stderr_process)
			eerrorx("%s: do not use --stderr and --stderr-logger together",
					applet);
	}

	/* Expand ~ */
	if (ch_dir && *ch_dir == '~')
		ch_dir = expand_home(home, ch_dir);
	if (ch_root && *ch_root == '~')
		ch_root = expand_home(home, ch_root);
	if (exec) {
		if (*exec == '~')
			exec = expand_home(home, exec);

		/* Validate that the binary exists if we are starting */
		if (*exec == '/' || *exec == '.') {
			/* Full or relative path */
			if (ch_root)
				xasprintf(&exec_file, "%s/%s", ch_root, exec);
			else
				xasprintf(&exec_file, "%s", exec);
		} else {
			/* Something in $PATH */
			p = tmp = xstrdup(getenv("PATH"));
			exec_file = NULL;
			while ((token = strsep(&p, ":"))) {
				if (ch_root)
					xasprintf(&exec_file, "%s/%s/%s", ch_root, token, exec);
				else
					xasprintf(&exec_file, "%s/%s", token, exec);
				if (exec_file && exists(exec_file))
					break;
				free(exec_file);
				exec_file = NULL;
			}
			free(tmp);
		}
	}
	if (start && !exists(exec_file)) {
		eerror("%s: %s does not exist", applet,
		    *exec_file ? exec_file : exec);
		free(exec_file);
		exit(EXIT_FAILURE);
	}
	if (start && retry)
		ewarn("using --retry with --start has no effect,"
		    " use --wait instead");

	/* If we don't have a pidfile we should check if it's interpreted
	 * or not. If it we, we need to pass the interpreter through
	 * to our daemon calls to find it correctly. */
	if (interpreted && !pidfile) {
		fp = fopen(exec_file, "r");
		if (fp) {
			line = NULL;
			if (getline(&line, &size, fp) == -1)
				eerrorx("%s: %s", applet, strerror(errno));
			p = line;
			fclose(fp);
			if (p != NULL && line[0] == '#' && line[1] == '!') {
				p = line + 2;
				/* Strip leading spaces */
				while (*p == ' ' || *p == '\t')
					p++;
				/* Remove the trailing newline */
				len = strlen(p) - 1;
				if (p[len] == '\n')
					p[len] = '\0';
				token = strsep(&p, " ");
				free(exec_file);
				xasprintf(&exec_file, "%s", token);
				opt = 0;
				for (nav = argv; *nav; nav++)
					opt++;
				nav = xmalloc(sizeof(char *) * (opt + 3));
				nav[0] = exec_file;
				len = 1;
				if (p)
					nav[len++] = p;
				for (i = 0; i < opt; i++)
					nav[i + len] = argv[i];
				nav[i + len] = '\0';
			}
		}
	}
	margv = nav ? nav : argv;

	if (stop || sig != -1) {
		if (sig == -1)
			sig = SIGTERM;
		if (!stop)
			oknodo = true;
		if (retry)
			parse_schedule(applet, retry, sig);
		else if (test || oknodo)
			parse_schedule(applet, "0", sig);
		else
			parse_schedule(applet, NULL, sig);
		if (pidfile) {
			pid = get_pid(applet, pidfile);
			if (pid == -1 && errno != ENOENT)
				exit(EXIT_FAILURE);
		} else {
			pid = 0;
		}
		i = run_stop_schedule(applet, exec, (const char *const *)margv,
		    pid, uid, test, progress, false);

		if (i < 0)
			/* We failed to stop something */
			exit(EXIT_FAILURE);
		if (test || oknodo)
			return i > 0 ? EXIT_SUCCESS : EXIT_FAILURE;

		/* Even if we have not actually killed anything, we should
		 * remove information about it as it may have unexpectedly
		 * crashed out. We should also return success as the end
		 * result would be the same. */
		if (pidfile && exists(pidfile))
			unlink(pidfile);
		if (svcname)
			rc_service_daemon_set(svcname, exec,
			    (const char *const *)argv,
			    pidfile, false);
		exit(EXIT_SUCCESS);
	}

	if (pidfile)
		pid = get_pid(applet, pidfile);
	else
		pid = 0;

	if (pid)
		pids = rc_find_pids(NULL, NULL, 0, pid);
	else
		pids = rc_find_pids(exec, (const char * const *) argv, uid, 0);
	if (pids)
		eerrorx("%s: %s is already running", applet, exec);

	free(pids);
	if (test) {
		if (rc_yesno(getenv("EINFO_QUIET")))
			exit (EXIT_SUCCESS);

		einfon("Would start");
		while (argc-- > 0)
			printf(" %s", *argv++);
		printf("\n");
		eindent();
		if (uid != 0)
			einfo("as user id %d", uid);
		if (gid != 0)
			einfo("as group id %d", gid);
		if (ch_root)
			einfo("in root `%s'", ch_root);
		if (ch_dir)
			einfo("in dir `%s'", ch_dir);
		if (nicelevel != 0)
			einfo("with a priority of %d", nicelevel);
		if (name)
			einfo ("with a process name of %s", name);
		eoutdent();
		exit(EXIT_SUCCESS);
	}

	ebeginv("Detaching to start `%s'", exec);
	eindentv();

	/* Remove existing pidfile */
	if (pidfile)
		unlink(pidfile);

	if (background)
		signal_setup(SIGCHLD, handle_signal);

	if ((pid = fork()) == -1)
		eerrorx("%s: fork: %s", applet, strerror(errno));

	/* Child process - lets go! */
	if (pid == 0) {
		pid_t mypid = getpid();
		umask(numask);

#ifdef TIOCNOTTY
		tty_fd = open("/dev/tty", O_RDWR);
#endif

		devnull_fd = open("/dev/null", O_RDWR);

		if (nicelevel) {
			if (setpriority(PRIO_PROCESS, mypid, nicelevel) == -1)
				eerrorx("%s: setpritory %d: %s",
				    applet, nicelevel,
				    strerror(errno));
		}

		if (ionicec != -1 &&
		    ioprio_set(1, mypid, ionicec | ioniced) == -1)
			eerrorx("%s: ioprio_set %d %d: %s", applet,
			    ionicec, ioniced, strerror(errno));

		if (ch_root && chroot(ch_root) < 0)
			eerrorx("%s: chroot `%s': %s",
			    applet, ch_root, strerror(errno));

		if (ch_dir && chdir(ch_dir) < 0)
			eerrorx("%s: chdir `%s': %s",
			    applet, ch_dir, strerror(errno));

		if (makepidfile && pidfile) {
			fp = fopen(pidfile, "w");
			if (! fp)
				eerrorx("%s: fopen `%s': %s", applet, pidfile,
				    strerror(errno));
			fprintf(fp, "%d\n", mypid);
			fclose(fp);
		}

#ifdef HAVE_PAM
		if (changeuser != NULL) {
			pamr = pam_start("start-stop-daemon",
			    changeuser, &conv, &pamh);

			if (pamr == PAM_SUCCESS)
				pamr = pam_acct_mgmt(pamh, PAM_SILENT);
			if (pamr == PAM_SUCCESS)
				pamr = pam_open_session(pamh, PAM_SILENT);
			if (pamr != PAM_SUCCESS)
				eerrorx("%s: pam error: %s",
					applet, pam_strerror(pamh, pamr));
		}
#endif

		if (gid && setgid(gid))
			eerrorx("%s: unable to set groupid to %d",
			    applet, gid);
		if (changeuser && initgroups(changeuser, gid))
			eerrorx("%s: initgroups (%s, %d)",
			    applet, changeuser, gid);
		if (uid && setuid(uid))
			eerrorx ("%s: unable to set userid to %d",
			    applet, uid);

		/* Close any fd's to the passwd database */
		endpwent();

#ifdef TIOCNOTTY
		ioctl(tty_fd, TIOCNOTTY, 0);
		close(tty_fd);
#endif

		/* Clean the environment of any RC_ variables */
		env_list = rc_stringlist_new();
		i = 0;
		while (environ[i])
			rc_stringlist_add(env_list, environ[i++]);

#ifdef HAVE_PAM
		if (changeuser != NULL) {
			pamenv = (const char *const *)pam_getenvlist(pamh);
			if (pamenv) {
				while (*pamenv) {
					/* Don't add strings unless they set a var */
					if (strchr(*pamenv, '='))
						putenv(xstrdup(*pamenv));
					else
						unsetenv(*pamenv);
					pamenv++;
				}
			}
		}
#endif

		TAILQ_FOREACH(env, env_list, entries) {
			if ((strncmp(env->value, "RC_", 3) == 0 &&
				strncmp(env->value, "RC_SERVICE=", 10) != 0 &&
				strncmp(env->value, "RC_SVCNAME=", 10) != 0) ||
				strncmp(env->value, "SSD_NICELEVEL=", 14) == 0 ||
				strncmp(env->value, "SSD_IONICELEVEL=", 16) == 0)
			{
				p = strchr(env->value, '=');
				*p = '\0';
				unsetenv(env->value);
				continue;
			}
		}
		rc_stringlist_free(env_list);

		/* For the path, remove the rcscript bin dir from it */
		if ((token = getenv("PATH"))) {
			len = strlen(token);
			newpath = np = xmalloc(len + 1);
			while (token && *token) {
				p = strchr(token, ':');
				if (p) {
					*p++ = '\0';
					while (*p == ':')
						p++;
				}
				if (strcmp(token, RC_LIBEXECDIR "/bin") != 0 &&
				    strcmp(token, RC_LIBEXECDIR "/sbin") != 0)
				{
					len = strlen(token);
					if (np != newpath)
						*np++ = ':';
					memcpy(np, token, len);
					np += len;
				}
				token = p;
			}
			*np = '\0';
			unsetenv("PATH");
			setenv("PATH", newpath, 1);
		}

		stdin_fd = devnull_fd;
		stdout_fd = devnull_fd;
		stderr_fd = devnull_fd;
		if (redirect_stdout) {
			if ((stdout_fd = open(redirect_stdout,
				    O_WRONLY | O_CREAT | O_APPEND,
				    S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1)
				eerrorx("%s: unable to open the logfile"
				    " for stdout `%s': %s",
				    applet, redirect_stdout, strerror(errno));
		}else if (stdout_process) {
			stdout_fd = rc_pipe_command(stdout_process);
			if (stdout_fd == -1)
				eerrorx("%s: unable to open the logging process"
				    " for stdout `%s': %s",
				    applet, stdout_process, strerror(errno));
		}
		if (redirect_stderr) {
			if ((stderr_fd = open(redirect_stderr,
				    O_WRONLY | O_CREAT | O_APPEND,
				    S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1)
				eerrorx("%s: unable to open the logfile"
				    " for stderr `%s': %s",
				    applet, redirect_stderr, strerror(errno));
		}else if (stderr_process) {
			stderr_fd = rc_pipe_command(stderr_process);
			if (stderr_fd == -1)
				eerrorx("%s: unable to open the logging process"
				    " for stderr `%s': %s",
				    applet, stderr_process, strerror(errno));
		}

		if (background)
			dup2(stdin_fd, STDIN_FILENO);
		if (background || redirect_stdout || stdout_process
				|| rc_yesno(getenv("EINFO_QUIET")))
			dup2(stdout_fd, STDOUT_FILENO);
		if (background || redirect_stderr || stderr_process
				|| rc_yesno(getenv("EINFO_QUIET")))
			dup2(stderr_fd, STDERR_FILENO);

		for (i = getdtablesize() - 1; i >= 3; --i)
			close(i);

		setsid();
		execvp(exec, argv);
#ifdef HAVE_PAM
		if (changeuser != NULL && pamr == PAM_SUCCESS)
			pam_close_session(pamh, PAM_SILENT);
#endif
		eerrorx("%s: failed to exec `%s': %s",
		    applet, exec,strerror(errno));
	}
Esempio n. 27
0
static void pty_open_master(Pty pty)
{
#ifdef BSD_PTYS
    const char chars1[] = "pqrstuvwxyz";
    const char chars2[] = "0123456789abcdef";
    const char *p1, *p2;
    char master_name[20];
    struct group *gp;

    for (p1 = chars1; *p1; p1++)
	for (p2 = chars2; *p2; p2++) {
	    sprintf(master_name, "/dev/pty%c%c", *p1, *p2);
	    pty->master_fd = open(master_name, O_RDWR);
	    if (pty->master_fd >= 0) {
		if (geteuid() == 0 ||
		    access(master_name, R_OK | W_OK) == 0) {
		    /*
		     * We must also check at this point that we are
		     * able to open the slave side of the pty. We
		     * wouldn't want to allocate the wrong master,
		     * get all the way down to forking, and _then_
		     * find we're unable to open the slave.
		     */
		    strcpy(pty->name, master_name);
		    pty->name[5] = 't'; /* /dev/ptyXX -> /dev/ttyXX */

                    cloexec(pty->master_fd);

		    if (pty_open_slave(pty) >= 0 &&
			access(pty->name, R_OK | W_OK) == 0)
			goto got_one;
		    if (pty->slave_fd > 0)
			close(pty->slave_fd);
		    pty->slave_fd = -1;
		}
		close(pty->master_fd);
	    }
	}

    /* If we get here, we couldn't get a tty at all. */
    fprintf(stderr, "pterm: unable to open a pseudo-terminal device\n");
    exit(1);

    got_one:

    /* We need to chown/chmod the /dev/ttyXX device. */
    gp = getgrnam("tty");
    chown(pty->name, getuid(), gp ? gp->gr_gid : -1);
    chmod(pty->name, 0600);
#else

    const int flags = O_RDWR
#ifdef O_NOCTTY
        | O_NOCTTY
#endif
        ;

#ifdef HAVE_POSIX_OPENPT
#ifdef SET_NONBLOCK_VIA_OPENPT
    /*
     * OS X, as of 10.10 at least, doesn't permit me to set O_NONBLOCK
     * on pty master fds via the usual fcntl mechanism. Fortunately,
     * it does let me work around this by adding O_NONBLOCK to the
     * posix_openpt flags parameter, which isn't a documented use of
     * the API but seems to work. So we'll do that for now.
     */
    pty->master_fd = posix_openpt(flags | O_NONBLOCK);
#else
    pty->master_fd = posix_openpt(flags);
#endif

    if (pty->master_fd < 0) {
	perror("posix_openpt");
	exit(1);
    }
#else
    pty->master_fd = open("/dev/ptmx", flags);

    if (pty->master_fd < 0) {
	perror("/dev/ptmx: open");
	exit(1);
    }
#endif

    if (grantpt(pty->master_fd) < 0) {
	perror("grantpt");
	exit(1);
    }
    
    if (unlockpt(pty->master_fd) < 0) {
	perror("unlockpt");
	exit(1);
    }

    cloexec(pty->master_fd);

    pty->name[FILENAME_MAX-1] = '\0';
    strncpy(pty->name, ptsname(pty->master_fd), FILENAME_MAX-1);
#endif

#ifndef SET_NONBLOCK_VIA_OPENPT
    nonblock(pty->master_fd);
#endif

    if (!ptys_by_fd)
	ptys_by_fd = newtree234(pty_compare_by_fd);
    add234(ptys_by_fd, pty);
}
Esempio n. 28
0
static int ParseEntityPosixLinux(char **str, acl_entry_t ace, int *is_mask)
{
    struct passwd *pwd;
    struct group *grp;
    acl_tag_t etype;
    size_t idsz;
    id_t id;
    char *ids;
    char *id_end;
    int result = true;
    int i;

    ids = NULL;

// TODO: Support numeric id in addition to (user/group) name ?

// Posix language: tag type, qualifier, permissions

    if (strncmp(*str, "user:"******"*", 2) == 0)
        {
            etype = ACL_USER_OBJ;
            id = 0;
        }
        else
        {
            etype = ACL_USER;
            pwd = getpwnam(ids);

            if (pwd == NULL)
            {
                CfOut(OUTPUT_LEVEL_ERROR, "getpwnnam", "Couldn't find user id for %s", ids);
                free(ids);
                return false;
            }

            id = pwd->pw_uid;
        }
    }
    else if (strncmp(*str, "group:", 6) == 0)
    {
        *str += 6;

        // create null-terminated string for entity id
        id_end = index(*str, ':');

        if (id_end == NULL)     // entity id already null-terminated
        {
            idsz = strlen(*str);
        }
        else                    // copy entity-id to new null-terminated string
        {
            idsz = id_end - *str;
        }

        ids = xmalloc(idsz + 1);
        for (i = 0; i < idsz; i++)
            ids[i] = (*str)[i];
        ids[idsz] = '\0';

        *str += idsz;

        // file group
        if (strncmp(ids, "*", 2) == 0)
        {
            etype = ACL_GROUP_OBJ;
            id = 0;             // TODO: Correct file group id ??
        }
        else
        {
            etype = ACL_GROUP;
            grp = getgrnam(ids);

            if (grp == NULL)
            {
                CfOut(OUTPUT_LEVEL_ERROR, "", "Error looking up group id for %s", ids);
                free(ids);
                return false;
            }

            id = grp->gr_gid;
        }

    }
    else if (strncmp(*str, "all:", 4) == 0)
    {
        *str += 3;
        etype = ACL_OTHER;
    }
    else if (strncmp(*str, "mask:", 5) == 0)
    {
        *str += 4;
        etype = ACL_MASK;
        *is_mask = true;
    }
    else
    {
        CfOut(OUTPUT_LEVEL_ERROR, "", "ace does not start with user:/group:/all:/mask:");
        return false;
    }

    if (acl_set_tag_type(ace, etype) != 0)
    {
        CfOut(OUTPUT_LEVEL_ERROR, "acl_set_tag_type", "Could not set ACE tag type.");
        result = false;
    }
    else if (etype == ACL_USER || etype == ACL_GROUP)
    {
        if ((acl_set_qualifier(ace, &id)) != 0)
        {
            CfOut(OUTPUT_LEVEL_ERROR, "acl_set_qualifier", "Could not set ACE qualifier.");
            result = false;
        }
    }

    if (ids != NULL)
    {
        free(ids);
    }

    return result;
}
Esempio n. 29
0
static bool VerifyIfUserNeedsModifs (const char *puser, User u, const struct passwd *passwd_info,
                             uint32_t *changemap)
{
    if (u.description != NULL && strcmp (u.description, passwd_info->pw_gecos))
    {
        CFUSR_SETBIT (*changemap, i_comment);
    }
    if (u.uid != NULL && (atoi (u.uid) != passwd_info->pw_uid))
    {
        CFUSR_SETBIT (*changemap, i_uid);
    }
    if (u.home_dir != NULL && strcmp (u.home_dir, passwd_info->pw_dir))
    {
        CFUSR_SETBIT (*changemap, i_home);
    }
    if (u.shell != NULL && strcmp (u.shell, passwd_info->pw_shell))
    {
        CFUSR_SETBIT (*changemap, i_shell);
    }
    bool account_is_locked = IsAccountLocked(puser, passwd_info);
    if ((!account_is_locked && u.policy == USER_STATE_LOCKED)
        || (account_is_locked && u.policy != USER_STATE_LOCKED))
    {
        CFUSR_SETBIT(*changemap, i_locked);
    }
    // Don't bother with passwords if the account is going to be locked anyway.
    if (u.password != NULL && strcmp (u.password, "")
        && u.policy != USER_STATE_LOCKED)
    {
        if (!IsPasswordCorrect(puser, u.password, u.password_format, passwd_info))
        {
            CFUSR_SETBIT (*changemap, i_password);
        }
    }

    if (SafeStringLength(u.group_primary))
    {
        bool group_could_be_gid = (strlen(u.group_primary) == strspn(u.group_primary, "0123456789"));
        int gid;

        // We try name first, even if it looks like a gid. Only fall back to gid.
        struct group *group_info;
        errno = 0;
        group_info = getgrnam(u.group_primary);
        // Apparently POSIX is ambiguous here. All the values below mean "not found".
        if (!group_info && errno != 0 && errno != ENOENT && errno != EBADF && errno != ESRCH
            && errno != EWOULDBLOCK && errno != EPERM)
        {
            Log(LOG_LEVEL_ERR, "Could not obtain information about group '%s'. (getgrnam: '%s')", u.group_primary, GetErrorStr());
            gid = -1;
        }
        else if (!group_info)
        {
            if (group_could_be_gid)
            {
                gid = atoi(u.group_primary);
            }
            else
            {
                Log(LOG_LEVEL_ERR, "No such group '%s'.", u.group_primary);
                gid = -1;
            }
        }
        else
        {
            gid = group_info->gr_gid;
        }

        if (gid != passwd_info->pw_gid)
        {
            CFUSR_SETBIT (*changemap, i_group);
        }
    }
    if (u.groups_secondary != NULL)
    {
        StringSet *wanted_groups = StringSetNew();
        for (Rlist *ptr = u.groups_secondary; ptr; ptr = ptr->next)
        {
            if (strcmp(RvalScalarValue(ptr->val), CF_NULL_VALUE) != 0)
            {
                StringSetAdd(wanted_groups, xstrdup(RvalScalarValue(ptr->val)));
            }
        }
        TransformGidsToGroups(&wanted_groups);
        StringSet *current_groups = StringSetNew();
        if (!GroupGetUserMembership (puser, current_groups))
        {
            CFUSR_SETBIT (*changemap, i_groups);
        }
        else if (!StringSetIsEqual (current_groups, wanted_groups))
        {
            CFUSR_SETBIT (*changemap, i_groups);
        }
        StringSetDestroy(current_groups);
        StringSetDestroy(wanted_groups);
    }

    ////////////////////////////////////////////
    if (*changemap == 0)
    {
        return false;
    }
    else
    {
        return true;
    }
}
Esempio n. 30
0
int
main(int argc, char **argv)
{
	int event_fd;
	int sock_fd = -1; /* init to avoid a compiler warning */

	/* learn who we really are */
	progname = (const char *)strrchr(argv[0], '/');
	progname = progname ? (progname + 1) : argv[0];

	/* handle the commandline  */
	handle_cmdline(&argc, &argv);

	/* close any extra file descriptors */
	close_fds();

	/* actually open the event file */
	event_fd = open(eventfile, O_RDONLY);
	if (event_fd < 0) {
		fprintf(stderr, "%s: can't open %s: %s\n", progname, 
			eventfile, strerror(errno));
		exit(EXIT_FAILURE);
	}
	fcntl(event_fd, F_SETFD, FD_CLOEXEC);

/*
 * if there is data, and the kernel is NOT broken, this eats 1 byte.  We
 * can't have that.  This is ifdef'ed out on the assumption that old kernels
 * are out of popular use, by now.
 */
#ifdef TEST_FOR_BAD_KERNELS
	/*
	 * Older kernels did not support read() properly or poll() at all
	 * Check that the kernel supports the proper semantics, or die.
	 *
	 * Good kernels will respect O_NONBLOCK and return -1.  Bad kernels
	 * will ignore O_NONBLOCK and return 0.  Really bad kernels will block
	 * and overflow the buffer.  Can't deal with the really bad ones.
	 */
	{
		int fl;
		char buf;

		fl = fcntl(event_fd, F_GETFL);
		fcntl(event_fd, F_SETFL, fl | O_NONBLOCK);
		if (read(event_fd, &buf, 1) == 0) {
			fprintf(stderr, 
				"%s: this kernel does not support proper "
				"event file handling.\n"
				"Please get the patch from "
				"http://acpid.sourceforge.net\n", 
				progname);
			exit(EXIT_FAILURE);
		}
		fcntl(event_fd, F_SETFL, fl);
	}
#endif

	/* open our socket */
	if (!nosocket) {
		sock_fd = ud_create_socket(socketfile);
		if (sock_fd < 0) {
			fprintf(stderr, "%s: can't open socket %s: %s\n",
				progname, socketfile, strerror(errno));
			exit(EXIT_FAILURE);
		}
		fcntl(sock_fd, F_SETFD, FD_CLOEXEC);
		chmod(socketfile, socketmode);
		if (socketgroup) {
			struct group *gr;
			struct stat buf;
			gr = getgrnam(socketgroup);
			if (!gr) {
				fprintf(stderr, "%s: group %s does not exist\n",
					progname, socketgroup);
				exit(EXIT_FAILURE);
			}
			if (stat(socketfile, &buf) < 0) {
				fprintf(stderr, "%s: can't stat %s\n",
					progname, socketfile);
				exit(EXIT_FAILURE);
			}
			if (chown(socketfile, buf.st_uid, gr->gr_gid) < 0) {
				fprintf(stderr, "%s: chown(): %s\n",
					progname, strerror(errno));
				exit(EXIT_FAILURE);
			}
		}
	}

	/* if we're running in foreground, we don't daemonize */
	if (!foreground) {
		if (daemonize() < 0)
			exit(EXIT_FAILURE);
	}

	/* open the log */
	if (open_log() < 0) {
		exit(EXIT_FAILURE);
	}
	acpid_log(LOG_INFO, "starting up\n");

	/* trap key signals */
	signal(SIGHUP, reload_conf);
	signal(SIGINT, clean_exit);
	signal(SIGQUIT, clean_exit);
	signal(SIGTERM, clean_exit);
	signal(SIGPIPE, SIG_IGN);

	/* read in our configuration */
	if (acpid_read_conf(confdir)) {
		exit(EXIT_FAILURE);
	}

	/* create our pidfile */
	if (create_pidfile() < 0) {
		exit(EXIT_FAILURE);
	}

	/* main loop */
	acpid_log(LOG_INFO, "waiting for events: event logging is %s\n",
	    logevents ? "on" : "off");
	while (1) {
		struct pollfd ar[2];
		int r;
		int fds = 0;

		/* poll for the socket and the event file */
		ar[0].fd = event_fd; ar[0].events = POLLIN; fds++;
		if (!nosocket) {
			ar[1].fd = sock_fd; ar[1].events = POLLIN; fds++;
		}
		r = poll(ar, fds, -1);

		if (r < 0 && errno == EINTR) {
			continue;
		} else if (r < 0) {
			acpid_log(LOG_ERR, "poll(): %s\n", strerror(errno));
			continue;
		}

		/* house keeping */
		acpid_close_dead_clients();

		/* was it an event? */
		if (ar[0].revents) {
			char *event;
			struct stat trash;
			int fexists;

			/* check for existence of a lockfile */
			fexists = (stat(lockfile, &trash) == 0);

			/* this shouldn't happen */
			if (!ar[0].revents & POLLIN) {
				acpid_log(LOG_DEBUG,
				    "odd, poll set flags 0x%x\n",
				    ar[0].revents);
				continue;
			}

			/* read an event */
			event = read_line(event_fd);

			/* if we're locked, don't process the event */
			if (fexists) {
				if (logevents) {
					acpid_log(LOG_INFO,
					    "lockfile present, not processing "
					    "event \"%s\"\n", event);
				}
				continue;
			}

			/* handle the event */
			if (event) {
				if (logevents) {
					acpid_log(LOG_INFO,
					    "received event \"%s\"\n", event);
				}
				acpid_handle_event(event);
				if (logevents) {
					acpid_log(LOG_INFO,
					    "completed event \"%s\"\n", event);
				}
			} else if (errno == EPIPE) {
				acpid_log(LOG_WARNING,
				    "events file connection closed\n");
				break;
			} else {
				static int nerrs;
				if (++nerrs >= ACPID_MAX_ERRS) {
					acpid_log(LOG_ERR,
					    "too many errors reading "
					    "events file - aborting\n");
					break;
				}
			}
		}

		/* was it a new connection? */
		if (!nosocket && ar[1].revents) {
			int cli_fd;
			struct ucred creds;
			char buf[32];
			static int accept_errors;

			/* this shouldn't happen */
			if (!ar[1].revents & POLLIN) {
				acpid_log(LOG_DEBUG,
				    "odd, poll set flags 0x%x\n",
				    ar[1].revents);
				continue;
			}

			/* accept and add to our lists */
			cli_fd = ud_accept(sock_fd, &creds);
			if (cli_fd < 0) {
				acpid_log(LOG_ERR, "can't accept client: %s\n",
				    strerror(errno));
				accept_errors++;
				if (accept_errors >= 5) {
					acpid_log(LOG_ERR, "giving up\n");
					clean_exit_with_status(EXIT_FAILURE);
				}
				continue;
			}
			accept_errors = 0;
			if (creds.uid != 0 && non_root_clients >= clientmax) {
				close(cli_fd);
				acpid_log(LOG_ERR,
				    "too many non-root clients\n");
				continue;
			}
			if (creds.uid != 0) {
				non_root_clients++;
			}
			fcntl(cli_fd, F_SETFD, FD_CLOEXEC);
			snprintf(buf, sizeof(buf)-1, "%d[%d:%d]",
				creds.pid, creds.uid, creds.gid);
			acpid_add_client(cli_fd, buf);
		}
	}

	clean_exit_with_status(EXIT_SUCCESS);

	return 0;
}