Exemplo n.º 1
0
KDModule::KDModule(QWidget *parent, const char *name, const QStringList &)
    : KCModule(KDMFactory::instance(), parent, name), minshowuid(0), maxshowuid(0), updateOK(false)
{
    KAboutData *about = new KAboutData(I18N_NOOP("kcmkdm"), I18N_NOOP("KDE Login Manager Config Module"), 0, 0, KAboutData::License_GPL,
                                       I18N_NOOP("(c) 1996 - 2005 The KDM Authors"));

    about->addAuthor("Thomas Tanghus", I18N_NOOP("Original author"), "*****@*****.**");
    about->addAuthor("Steffen Hansen", 0, "*****@*****.**");
    about->addAuthor("Oswald Buddenhagen", I18N_NOOP("Current maintainer"), "*****@*****.**");

    setQuickHelp(
        i18n("<h1>Login Manager</h1> In this module you can configure the "
             "various aspects of the KDE Login Manager. This includes "
             "the look and feel as well as the users that can be "
             "selected for login. Note that you can only make changes "
             "if you run the module with superuser rights. If you have not started the KDE "
             "Control Center with superuser rights (which is absolutely the right thing to "
             "do, by the way), click on the <em>Modify</em> button to acquire "
             "superuser rights. You will be asked for the superuser password."
             "<h2>Appearance</h2> On this tab page, you can configure how "
             "the Login Manager should look, which language it should use, and which "
             "GUI style it should use. The language settings made here have no influence on "
             "the user's language settings."
             "<h2>Font</h2>Here you can choose the fonts that the Login Manager should use "
             "for various purposes like greetings and user names. "
             "<h2>Background</h2>If you want to set a special background for the login "
             "screen, this is where to do it."
             "<h2>Shutdown</h2> Here you can specify who is allowed to shutdown/reboot the machine "
             "and whether a boot manager should be used."
             "<h2>Users</h2>On this tab page, you can select which users the Login Manager "
             "will offer you for logging in."
             "<h2>Convenience</h2> Here you can specify a user to be logged in automatically, "
             "users not needing to provide a password to log in, and other convenience features.<br>"
             "Note, that these settings are security holes by their nature, so use them very carefully."));

    setAboutData(about);

    setlocale(LC_COLLATE, "C");

    KGlobal::locale()->insertCatalogue("kcmbackground");

    QStringList sl;
    QMap< gid_t, QStringList > tgmap;
    QMap< gid_t, QStringList >::Iterator tgmapi;
    QMap< gid_t, QStringList >::ConstIterator tgmapci;
    QMap< QString, QPair< int, QStringList > >::Iterator umapi;

    struct passwd *ps;
    for(setpwent(); (ps = getpwent());)
    {
        QString un(QFile::decodeName(ps->pw_name));
        if(usermap.find(un) == usermap.end())
        {
            usermap.insert(un, QPair< int, QStringList >(ps->pw_uid, sl));
            if((tgmapi = tgmap.find(ps->pw_gid)) != tgmap.end())
                (*tgmapi).append(un);
            else
                tgmap[ps->pw_gid] = un;
        }
    }
    endpwent();

    struct group *grp;
    for(setgrent(); (grp = getgrent());)
    {
        QString gn(QFile::decodeName(grp->gr_name));
        bool delme = false;
        if((tgmapi = tgmap.find(grp->gr_gid)) != tgmap.end())
        {
            if((*tgmapi).count() == 1 && (*tgmapi).first() == gn)
                delme = true;
            else
                for(QStringList::ConstIterator it = (*tgmapi).begin(); it != (*tgmapi).end(); ++it)
                    usermap[*it].second.append(gn);
            tgmap.remove(tgmapi);
        }
        if(!*grp->gr_mem || (delme && !grp->gr_mem[1] && gn == QFile::decodeName(*grp->gr_mem)))
            continue;
        do
        {
            QString un(QFile::decodeName(*grp->gr_mem));
            if((umapi = usermap.find(un)) != usermap.end())
            {
                if((*umapi).second.find(gn) == (*umapi).second.end())
                    (*umapi).second.append(gn);
            }
            else
                kdWarning() << "group '" << gn << "' contains unknown user '" << un << "'" << endl;
        } while(*++grp->gr_mem);
    }
    endgrent();

    for(tgmapci = tgmap.begin(); tgmapci != tgmap.end(); ++tgmapci)
        kdWarning() << "user(s) '" << tgmapci.data().join(",") << "' have unknown GID " << tgmapci.key() << endl;

    config = new KSimpleConfig(QString::fromLatin1(KDE_CONFDIR "/kdm/kdmrc"));

    QVBoxLayout *top = new QVBoxLayout(this);
    tab = new QTabWidget(this);

    // *****
    // _don't_ add a theme configurator until the theming engine is _really_ done!!
    // *****

    appearance = new KDMAppearanceWidget(this);
    tab->addTab(appearance, i18n("A&ppearance"));
    connect(appearance, SIGNAL(changed(bool)), SIGNAL(changed(bool)));

    font = new KDMFontWidget(this);
    tab->addTab(font, i18n("&Font"));
    connect(font, SIGNAL(changed(bool)), SIGNAL(changed(bool)));

    background = new KBackground(this);
    tab->addTab(background, i18n("&Background"));
    connect(background, SIGNAL(changed(bool)), SIGNAL(changed(bool)));

    sessions = new KDMSessionsWidget(this);
    tab->addTab(sessions, i18n("&Shutdown"));
    connect(sessions, SIGNAL(changed(bool)), SIGNAL(changed(bool)));

    users = new KDMUsersWidget(this, 0);
    tab->addTab(users, i18n("&Users"));
    connect(users, SIGNAL(changed(bool)), SIGNAL(changed(bool)));
    connect(users, SIGNAL(setMinMaxUID(int, int)), SLOT(slotMinMaxUID(int, int)));
    connect(this, SIGNAL(addUsers(const QMap< QString, int > &)), users, SLOT(slotAddUsers(const QMap< QString, int > &)));
    connect(this, SIGNAL(delUsers(const QMap< QString, int > &)), users, SLOT(slotDelUsers(const QMap< QString, int > &)));
    connect(this, SIGNAL(clearUsers()), users, SLOT(slotClearUsers()));

    convenience = new KDMConvenienceWidget(this, 0);
    tab->addTab(convenience, i18n("Con&venience"));
    connect(convenience, SIGNAL(changed(bool)), SIGNAL(changed(bool)));
    connect(this, SIGNAL(addUsers(const QMap< QString, int > &)), convenience, SLOT(slotAddUsers(const QMap< QString, int > &)));
    connect(this, SIGNAL(delUsers(const QMap< QString, int > &)), convenience, SLOT(slotDelUsers(const QMap< QString, int > &)));
    connect(this, SIGNAL(clearUsers()), convenience, SLOT(slotClearUsers()));

    load();
    if(getuid() != 0 || !config->checkConfigFilesWritable(true))
    {
        appearance->makeReadOnly();
        font->makeReadOnly();
        background->makeReadOnly();
        users->makeReadOnly();
        sessions->makeReadOnly();
        convenience->makeReadOnly();
    }
    top->addWidget(tab);
}
Exemplo n.º 2
0
void
getperms (struct io_f *io, char *name)
{
  static uid_t notes;
  static short notes_is_set = FALSE;

  int permissions = 0;
  int matches = 0;
  int perfectmatch = 0;
  int ngroups = 0;        /* Actual number of groups the user belongs to. */
  GETGROUPS_T *gid;
  char **gname;
  struct flock alock;
  struct group *gr;
  char *filename;
  size_t length;
  int fid;
  struct perm_f entry;

  if (io == NULL || name == NULL)
    return;

  /* Notes is God.  If you're the notes user, you get all privs. */

  if (!notes_is_set)
    {
      struct passwd *pw = getpwnam (NOTES);

      notes = pw->pw_uid;
      notes_is_set = TRUE;
      endpwent ();
    }

  if (euid == notes)
    {
      io->access = READOK + RESPOK + WRITOK + DRCTOK;
      return;
    }

  /* Iterate through all the groups this user belongs to and grab the names.
   * If it doesn't work, we don't really care too much, because we can still
   * get a result.
   */

  ngroups = sysconf (_SC_NGROUPS_MAX);
  gid = newts_nmalloc (sizeof (GETGROUPS_T), ngroups);
  gname = newts_nmalloc (sizeof (char *), ngroups);

  if ((ngroups = getgroups (ngroups, gid)) >= 0)
    {
      register int i, j;

      for (i = 0, j = 0; i < ngroups; i++)
        {
          if ((gr = getgrgid (gid[i])) == NULL)
            {
              continue;   /* Bogus group, skip it and move on. */
            }
          gname[j++] = newts_strdup (gr->gr_name);
        }
      ngroups = j;
    }

  io->access = 0;         /* Clear the official list. */

  length = strlen (io->basedir) + strlen (io->nf) + strlen (ACCESS) + 3;
  filename = newts_nmalloc (sizeof (char), length);
  snprintf (filename, length, "%s/%s/%s", io->basedir, io->nf, ACCESS);

  fid = TEMP_FAILURE_RETRY (open (filename, O_RDONLY));

  alock.l_type = F_RDLCK;
  alock.l_whence = SEEK_SET;
  alock.l_start = 0;
  alock.l_len = 0;    /* All of it. */
  TEMP_FAILURE_RETRY (fcntl (fid, F_SETLKW, &alock));

  while ((TEMP_FAILURE_RETRY (read (fid, &entry, sizeof (struct perm_f))) ==
          sizeof (struct perm_f)) && !perfectmatch)
    {
      /* We're not dealing with system permissions yet. */

      if (entry.ptype == PERMSYSTEM)
        continue;

      /* In the actual UIUC notes distribution, "other" was capitalized.  We
       * use strcasecmp just to be sure.
       */

      if (strcasecmp (entry.name, "other") == 0)
        {
          if (matches == 0)
            {
              permissions = entry.perms;
              matches++;
            }
        }

      switch (entry.ptype)
        {
        case PERMUSER:
          if (strcmp (name, entry.name) == 0)
            {
              /* Specific user permissions are the last word. */

              permissions = entry.perms;
              matches++;
              perfectmatch++;
            }
          break;

        case PERMGROUP:
          {
            register int i;

            for (i = 0; i < ngroups; i++)
              {
                if (strcmp (gname[i], entry.name) == 0)
                  {
                    permissions |= entry.perms;
                    matches++;
                    break;
                  }
              }
          }
          break;

        case PERMSYSTEM:
          break;

        default:
          /* FIXME: error out somehow. */

          break;
        }
    }

  io->access = permissions;

  fdatasync (fid);
  alock.l_type = F_UNLCK;
  fcntl (fid, F_SETLK, &alock);

  TEMP_FAILURE_RETRY (close (fid));
  newts_free (filename);
  newts_free (gid);

  {
    register int i;

    for (i = 0; i < ngroups; i++)
      {
        newts_free (gname[i]);
      }
  }

  newts_free (gname);
}
Exemplo n.º 3
0
fsnode *
read_mtree(const char *fname, fsnode *node)
{
	struct mtree_fileinfo *fi;
	FILE *fp;
	int c, error;

	/* We do not yet support nesting... */
	assert(node == NULL);

	if (strcmp(fname, "-") == 0)
		fp = stdin;
	else {
		fp = fopen(fname, "r");
		if (fp == NULL)
			err(1, "Can't open `%s'", fname);
	}

	error = mtree_file_push(fname, fp);
	if (error)
		goto out;

	bzero(&mtree_global, sizeof(mtree_global));
	bzero(&mtree_global_inode, sizeof(mtree_global_inode));
	mtree_global.inode = &mtree_global_inode;
	mtree_global_inode.nlink = 1;
	mtree_global_inode.st.st_nlink = 1;
	mtree_global_inode.st.st_atime = mtree_global_inode.st.st_ctime =
	    mtree_global_inode.st.st_mtime = time(NULL);
	errors = warnings = 0;

	setgroupent(1);
	setpassent(1);

	mtree_root = node;
	mtree_current = node;
	do {
		/* Start of a new line... */
		fi = SLIST_FIRST(&mtree_fileinfo);
		fi->line++;

		error = skip_over(fp, " \t");
		if (error)
			break;

		c = getc(fp);
		if (c == EOF) {
			error = ferror(fp) ? errno : -1;
			break;
		}

		switch (c) {
		case '\n':		/* empty line */
			error = 0;
			break;
		case '#':		/* comment -- skip to end of line. */
			error = skip_to(fp, "\n");
			if (!error)
				(void)getc(fp);
			break;
		case '/':		/* special commands */
			error = read_mtree_command(fp);
			break;
		default:		/* specification */
			ungetc(c, fp);
			error = read_mtree_spec(fp);
			break;
		}
	} while (!error);

	endpwent();
	endgrent();

	if (error <= 0 && (errors || warnings)) {
		warnx("%u error(s) and %u warning(s) in mtree manifest",
		    errors, warnings);
		if (errors)
			exit(1);
	}

 out:
	if (error > 0)
		errc(1, error, "Error reading mtree file");

	if (fp != stdin)
		fclose(fp);

	if (mtree_root != NULL)
		return (mtree_root);

	/* Handle empty specifications. */
	node = create_node(".", S_IFDIR, NULL, &mtree_global);
	node->first = node;
	return (node);
}
Exemplo n.º 4
0
static Dlg_head *
init_chown (void)
{
    int i;
    struct passwd *l_pass;
    struct group *l_grp;
    Dlg_head *ch_dlg;

    do_refresh ();
    end_chown = need_update = current_file = 0;
    single_set = (current_panel->marked < 2) ? 3 : 0;

    ch_dlg =
        create_dlg (TRUE, 0, 0, 18, 74, dialog_colors, chown_callback, "[Chown]",
                    _("Chown command"), DLG_CENTER | DLG_REVERSE);

    for (i = 0; i < BUTTONS - single_set; i++)
        add_widget (ch_dlg,
                    button_new (BY + chown_but[i].y, BX + chown_but[i].x,
                                chown_but[i].ret_cmd, chown_but[i].flags, _(chown_but[i].text), 0));

    /* Add the widgets for the file information */
    for (i = 0; i < LABELS; i++)
    {
        chown_label[i].l = label_new (chown_label[i].y, chown_label[i].x, "");
        add_widget (ch_dlg, chown_label[i].l);
    }

    /* get new listboxes */
    l_user = listbox_new (UY + 1, UX + 1, 10, 19, FALSE, NULL);
    l_group = listbox_new (GY + 1, GX + 1, 10, 19, FALSE, NULL);

    /* add fields for unknown names (numbers) */
    listbox_add_item (l_user, LISTBOX_APPEND_AT_END, 0, _("<Unknown user>"), NULL);
    listbox_add_item (l_group, LISTBOX_APPEND_AT_END, 0, _("<Unknown group>"), NULL);

    /* get and put user names in the listbox */
    setpwent ();
    while ((l_pass = getpwent ()) != NULL)
    {
        listbox_add_item (l_user, LISTBOX_APPEND_SORTED, 0, l_pass->pw_name, NULL);
    }
    endpwent ();

    /* get and put group names in the listbox */
    setgrent ();
    while ((l_grp = getgrent ()) != NULL)
    {
        listbox_add_item (l_group, LISTBOX_APPEND_SORTED, 0, l_grp->gr_name, NULL);
    }
    endgrent ();

    add_widget (ch_dlg, groupbox_new (TY, TX, 12, 19, _("File")));

    /* add listboxes to the dialogs */
    add_widget (ch_dlg, l_group);
    add_widget (ch_dlg, groupbox_new (GY, GX, 12, 21, _("Group name")));
    add_widget (ch_dlg, l_user);
    add_widget (ch_dlg, groupbox_new (UY, UX, 12, 21, _("User name")));

    return ch_dlg;
}
Exemplo n.º 5
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);
}
Exemplo n.º 6
0
int
do_test (void)
{
    /* Count the number of entries in the password database, and fetch
       data from the first and last entries.  */
    size_t count = 0;
    struct passwd * pw;
    char *first_name = NULL;
    uid_t first_uid = 0;
    char *last_name = NULL;
    uid_t last_uid = 0;
    setpwent ();
    while ((pw  = getpwent ()) != NULL)
    {
        if (first_name == NULL)
        {
            first_name = strdup (pw->pw_name);
            if (first_name == NULL)
            {
                printf ("strdup: %m\n");
                return 1;
            }
            first_uid = pw->pw_uid;
        }

        free (last_name);
        last_name = strdup (pw->pw_name);
        if (last_name == NULL)
        {
            printf ("strdup: %m\n");
            return 1;
        }
        last_uid = pw->pw_uid;
        ++count;
    }
    endpwent ();

    if (count == 0)
    {
        printf ("No entries in the password database.\n");
        return 0;
    }

    /* Try again, this time interleaving with name-based and UID-based
       lookup operations.  The counts do not match if the interleaved
       lookups affected the enumeration.  */
    size_t new_count = 0;
    setpwent ();
    while ((pw  = getpwent ()) != NULL)
    {
        if (new_count == count)
        {
            printf ("Additional entry in the password database.\n");
            return 1;
        }
        ++new_count;
        struct passwd *pw2 = getpwnam (first_name);
        if (pw2 == NULL)
        {
            printf ("getpwnam (%s) failed: %m\n", first_name);
            return 1;
        }
        pw2 = getpwnam (last_name);
        if (pw2 == NULL)
        {
            printf ("getpwnam (%s) failed: %m\n", last_name);
            return 1;
        }
        pw2 = getpwuid (first_uid);
        if (pw2 == NULL)
        {
            printf ("getpwuid (%llu) failed: %m\n",
                    (unsigned long long) first_uid);
            return 1;
        }
        pw2 = getpwuid (last_uid);
        if (pw2 == NULL)
        {
            printf ("getpwuid (%llu) failed: %m\n",
                    (unsigned long long) last_uid);
            return 1;
        }
    }
    endpwent ();
    if (new_count < count)
    {
        printf ("Missing entry in the password database.\n");
        return 1;
    }

    return 0;
}
Exemplo n.º 7
0
void
doit(struct sockaddr *fromp)
{
    extern char *__rcmd_errstr;	/* syslog hook from libc/net/rcmd.c. */
    struct addrinfo hints, *res, *res0;
    int gaierror;
    struct passwd *pwd;
    u_short port;
    in_port_t *portp;
    struct pollfd pfd[4];
    int cc, nfd, pv[2], s = 0, one = 1;
    pid_t pid;
    char *hostname, *errorstr, *errorhost = (char *) NULL;
    char *cp, sig, buf[BUFSIZ];
    char cmdbuf[NCARGS+1], locuser[_PW_NAME_LEN+1], remuser[_PW_NAME_LEN+1];
    char remotehost[2 * MAXHOSTNAMELEN + 1];
    char hostnamebuf[2 * MAXHOSTNAMELEN + 1];
    char naddr[NI_MAXHOST];
    char saddr[NI_MAXHOST];
    char raddr[NI_MAXHOST];
    char pbuf[NI_MAXSERV];
    auth_session_t *as;
    const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;

#ifdef	KERBEROS
    AUTH_DAT	*kdata = (AUTH_DAT *) NULL;
    KTEXT		ticket = (KTEXT) NULL;
    char		instance[INST_SZ], version[VERSION_SIZE];
    struct		sockaddr_storage fromaddr;
    int		rc;
    long		authopts;
#ifdef CRYPT
    int		pv1[2], pv2[2];
#endif

    if (sizeof(fromaddr) < fromp->sa_len) {
        syslog(LOG_ERR, "malformed \"from\" address (af %d)",
               fromp->sa_family);
        exit(1);
    }
    memcpy(&fromaddr, fromp, fromp->sa_len);
#endif

    (void) signal(SIGINT, SIG_DFL);
    (void) signal(SIGQUIT, SIG_DFL);
    (void) signal(SIGTERM, SIG_DFL);
#ifdef DEBUG
    {   int t = open(_PATH_TTY, 2);
        if (t >= 0) {
            ioctl(t, TIOCNOTTY, (char *)0);
            (void) close(t);
        }
    }
#endif
    switch (fromp->sa_family) {
    case AF_INET:
        portp = &((struct sockaddr_in *)fromp)->sin_port;
        break;
    case AF_INET6:
        portp = &((struct sockaddr_in6 *)fromp)->sin6_port;
        break;
    default:
        syslog(LOG_ERR, "malformed \"from\" address (af %d)",
               fromp->sa_family);
        exit(1);
    }
    if (getnameinfo(fromp, fromp->sa_len, naddr, sizeof(naddr),
                    pbuf, sizeof(pbuf), niflags) != 0) {
        syslog(LOG_ERR, "malformed \"from\" address (af %d)",
               fromp->sa_family);
        exit(1);
    }

#ifdef IP_OPTIONS
    if (fromp->sa_family == AF_INET) {
        struct ipoption opts;
        socklen_t optsize = sizeof(opts);
        int ipproto, i;
        struct protoent *ip;

        if ((ip = getprotobyname("ip")) != NULL)
            ipproto = ip->p_proto;
        else
            ipproto = IPPROTO_IP;
        if (!getsockopt(STDIN_FILENO, ipproto, IP_OPTIONS,
                        (char *)&opts, &optsize) && optsize != 0) {
            for (i = 0; (void *)&opts.ipopt_list[i] - (void *)&opts <
                    optsize; ) {
                u_char c = (u_char)opts.ipopt_list[i];
                if (c == IPOPT_LSRR || c == IPOPT_SSRR)
                    exit(1);
                if (c == IPOPT_EOL)
                    break;
                i += (c == IPOPT_NOP) ? 1 :
                     (u_char)opts.ipopt_list[i+1];
            }
        }
    }
#endif

#ifdef	KERBEROS
    if (!use_kerberos)
#endif
        if (ntohs(*portp) >= IPPORT_RESERVED ||
                ntohs(*portp) < IPPORT_RESERVED/2) {
            syslog(LOG_NOTICE|LOG_AUTH,
                   "Connection from %s on illegal port %u",
                   naddr, ntohs(*portp));
            exit(1);
        }

    (void) alarm(60);
    port = 0;
    for (;;) {
        char c;
        if ((cc = read(STDIN_FILENO, &c, 1)) != 1) {
            if (cc < 0)
                syslog(LOG_NOTICE, "read: %m");
            shutdown(STDIN_FILENO, SHUT_RDWR);
            exit(1);
        }
        if (c == 0)
            break;
        port = port * 10 + c - '0';
    }

    (void) alarm(0);
    if (port != 0) {
        int lport;
#ifdef	KERBEROS
        if (!use_kerberos)
#endif
            if (port >= IPPORT_RESERVED ||
                    port < IPPORT_RESERVED/2) {
                syslog(LOG_ERR, "2nd port not reserved");
                exit(1);
            }
        *portp = htons(port);
        lport = IPPORT_RESERVED - 1;
        s = rresvport_af(&lport, fromp->sa_family);
        if (s < 0) {
            syslog(LOG_ERR, "can't get stderr port: %m");
            exit(1);
        }
        if (connect(s, (struct sockaddr *)fromp, fromp->sa_len) < 0) {
            syslog(LOG_INFO, "connect second port %d: %m", port);
            exit(1);
        }
    }

#ifdef	KERBEROS
    if (vacuous) {
        error("rshd: remote host requires Kerberos authentication\n");
        exit(1);
    }
#endif

#ifdef notdef
    /* from inetd, socket is already on 0, 1, 2 */
    dup2(f, 0);
    dup2(f, 1);
    dup2(f, 2);
#endif
    errorstr = NULL;
    if (getnameinfo(fromp, fromp->sa_len, saddr, sizeof(saddr),
                    NULL, 0, NI_NAMEREQD)== 0) {
        /*
         * If name returned by getnameinfo is in our domain,
         * attempt to verify that we haven't been fooled by someone
         * in a remote net; look up the name and check that this
         * address corresponds to the name.
         */
        hostname = saddr;
        res0 = NULL;
#ifdef	KERBEROS
        if (!use_kerberos)
#endif
            if (check_all || local_domain(saddr)) {
                strlcpy(remotehost, saddr, sizeof(remotehost));
                errorhost = remotehost;
                memset(&hints, 0, sizeof(hints));
                hints.ai_family = fromp->sa_family;
                hints.ai_socktype = SOCK_STREAM;
                hints.ai_flags = AI_CANONNAME;
                gaierror = getaddrinfo(remotehost, pbuf, &hints, &res0);
                if (gaierror) {
                    syslog(LOG_INFO,
                           "Couldn't look up address for %s: %s",
                           remotehost, gai_strerror(gaierror));
                    errorstr =
                        "Couldn't look up address for your host (%s)\n";
                    hostname = naddr;
                } else {
                    for (res = res0; res; res = res->ai_next) {
                        if (res->ai_family != fromp->sa_family)
                            continue;
                        if (res->ai_addrlen != fromp->sa_len)
                            continue;
                        if (getnameinfo(res->ai_addr,
                                        res->ai_addrlen,
                                        raddr, sizeof(raddr), NULL, 0,
                                        niflags) == 0
                                && strcmp(naddr, raddr) == 0) {
                            hostname = res->ai_canonname
                                       ? res->ai_canonname
                                       : saddr;
                            break;
                        }
                    }
                    if (res == NULL) {
                        syslog(LOG_NOTICE,
                               "Host addr %s not listed for host %s",
                               naddr, res0->ai_canonname
                               ? res0->ai_canonname
                               : saddr);
                        errorstr =
                            "Host address mismatch for %s\n";
                        hostname = naddr;
                    }
                }
            }
        strlcpy(hostnamebuf, hostname, sizeof(hostnamebuf));
        hostname = hostnamebuf;
        if (res0)
            freeaddrinfo(res0);
    } else
        strlcpy(hostnamebuf, naddr, sizeof(hostnamebuf));
    errorhost = hostname = hostnamebuf;

#ifdef	KERBEROS
    if (use_kerberos) {
        kdata = (AUTH_DAT *) authbuf;
        ticket = (KTEXT) tickbuf;
        authopts = 0L;
        strlcpy(instance, "*", sizeof instance);
        version[VERSION_SIZE - 1] = '\0';
#ifdef CRYPT
        if (doencrypt) {
            struct sockaddr_in local_addr;

            rc = sizeof(local_addr);
            if (getsockname(STDIN_FILENO,
                            (struct sockaddr *)&local_addr, &rc) < 0) {
                syslog(LOG_ERR, "getsockname: %m");
                error("rshd: getsockname: %m");
                exit(1);
            }
            authopts = KOPT_DO_MUTUAL;
            rc = krb_recvauth(authopts, 0, ticket,
                              "rcmd", instance, (struct sockaddr_in *)&fromaddr,
                              &local_addr, kdata, "", schedule, version);
            desrw_set_key(&kdata->session, &schedule);
        } else
#endif
            rc = krb_recvauth(authopts, 0, ticket, "rcmd",
                              instance, (struct sockaddr_in *)&fromaddr,
                              NULL, kdata, "", NULL, version);
        if (rc != KSUCCESS) {
            error("Kerberos authentication failure: %s\n",
                  krb_get_err_text(rc));
            exit(1);
        }
    } else
#endif

        getstr(remuser, sizeof(remuser), "remuser");
    getstr(locuser, sizeof(locuser), "locuser");
    getstr(cmdbuf, sizeof(cmdbuf), "command");
    pwd = getpwnam(locuser);
    if (pwd == NULL) {
        syslog(LOG_INFO|LOG_AUTH,
               "%s@%s as %s: unknown login. cmd='%.80s'",
               remuser, hostname, locuser, cmdbuf);
        if (errorstr == NULL)
            errorstr = "Permission denied.\n";
        goto fail;
    }
    lc = login_getclass(pwd->pw_class);
    if (lc == NULL) {
        syslog(LOG_INFO|LOG_AUTH,
               "%s@%s as %s: unknown class. cmd='%.80s'",
               remuser, hostname, locuser, cmdbuf);
        if (errorstr == NULL)
            errorstr = "Login incorrect.\n";
        goto fail;
    }
    as = auth_open();
    if (as == NULL || auth_setpwd(as, pwd) != 0) {
        syslog(LOG_INFO|LOG_AUTH,
               "%s@%s as %s: unable to allocate memory. cmd='%.80s'",
               remuser, hostname, locuser, cmdbuf);
        if (errorstr == NULL)
            errorstr = "Cannot allocate memory.\n";
        goto fail;
    }

    setegid(pwd->pw_gid);
    seteuid(pwd->pw_uid);
    if (chdir(pwd->pw_dir) < 0) {
        (void) chdir("/");
#ifdef notdef
        syslog(LOG_INFO|LOG_AUTH,
               "%s@%s as %s: no home directory. cmd='%.80s'",
               remuser, hostname, locuser, cmdbuf);
        error("No remote directory.\n");
        exit(1);
#endif
    }
    seteuid(0);
    setegid(0);	/* XXX use a saved gid instead? */

#ifdef	KERBEROS
    if (use_kerberos) {
        if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0') {
            if (kuserok(kdata, locuser) != 0) {
                syslog(LOG_INFO|LOG_AUTH,
                       "Kerberos rsh denied to %s.%s@%s",
                       kdata->pname, kdata->pinst, kdata->prealm);
                error("Permission denied.\n");
                exit(1);
            }
        }
    } else
#endif
        if (errorstr ||
                (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
                 iruserok_sa(fromp, fromp->sa_len, pwd->pw_uid == 0,
                             remuser, locuser) < 0)) {
            if (__rcmd_errstr)
                syslog(LOG_INFO|LOG_AUTH,
                       "%s@%s as %s: permission denied (%s). cmd='%.80s'",
                       remuser, hostname, locuser, __rcmd_errstr,
                       cmdbuf);
            else
                syslog(LOG_INFO|LOG_AUTH,
                       "%s@%s as %s: permission denied. cmd='%.80s'",
                       remuser, hostname, locuser, cmdbuf);
fail:
            if (errorstr == NULL)
                errorstr = "Permission denied.\n";
            error(errorstr, errorhost);
            exit(1);
        }

    if (pwd->pw_uid)
        auth_checknologin(lc);

    (void) write(STDERR_FILENO, "\0", 1);
    sent_null = 1;

    if (port) {
        if (pipe(pv) < 0) {
            error("Can't make pipe.\n");
            exit(1);
        }
#ifdef CRYPT
#ifdef KERBEROS
        if (doencrypt) {
            if (pipe(pv1) < 0) {
                error("Can't make 2nd pipe.\n");
                exit(1);
            }
            if (pipe(pv2) < 0) {
                error("Can't make 3rd pipe.\n");
                exit(1);
            }
        }
#endif
#endif
        pid = fork();
        if (pid == -1)  {
            error("Can't fork; try again.\n");
            exit(1);
        }
        if (pid) {
#ifdef CRYPT
#ifdef KERBEROS
            if (doencrypt) {
                static char msg[] = SECURE_MESSAGE;
                (void) close(pv1[1]);
                (void) close(pv2[1]);
                des_write(s, msg, sizeof(msg) - 1);

            } else
#endif
#endif
            {
                (void) close(STDIN_FILENO);
                (void) close(STDOUT_FILENO);
            }
            (void) close(STDERR_FILENO);
            (void) close(pv[1]);

            pfd[P_SOCKREAD].fd = s;
            pfd[P_SOCKREAD].events = POLLIN;
            pfd[P_PIPEREAD].fd = pv[0];
            pfd[P_PIPEREAD].events = POLLIN;
            nfd = 2;
#ifdef CRYPT
#ifdef KERBEROS
            if (doencrypt) {
                pfd[P_CRYPTREAD].fd = pv1[0];
                pfd[P_CRYPTREAD].events = POLLIN;
                pfd[P_CRYPTWRITE].fd = pv2[0];
                pfd[P_CRYPTWRITE].events = POLLOUT;
                nfd += 2;
            } else
#endif
#endif
                ioctl(pv[0], FIONBIO, (char *)&one);

            /* should set s nbio! */
            do {
                if (poll(pfd, nfd, INFTIM) < 0)
                    break;
                if (pfd[P_SOCKREAD].revents & POLLIN) {
                    int	ret;
#ifdef CRYPT
#ifdef KERBEROS
                    if (doencrypt)
                        ret = des_read(s, &sig, 1);
                    else
#endif
#endif
                        ret = read(s, &sig, 1);
                    if (ret <= 0)
                        pfd[P_SOCKREAD].revents = 0;
                    else
                        killpg(pid, sig);
                }
                if (pfd[P_PIPEREAD].revents & POLLIN) {
                    errno = 0;
                    cc = read(pv[0], buf, sizeof(buf));
                    if (cc <= 0) {
                        shutdown(s, SHUT_RDWR);
                        pfd[P_PIPEREAD].revents = 0;
                    } else {

#ifdef CRYPT
#ifdef KERBEROS
                        if (doencrypt)
                            (void)
                            des_write(s, buf, cc);
                        else
#endif
#endif
                            (void)
                            write(s, buf, cc);
                    }
                }
#ifdef CRYPT
#ifdef KERBEROS
                if (doencrypt &&
                        (pfd[P_CRYPTREAD].revents & POLLIN)) {
                    errno = 0;
                    cc = read(pv1[0], buf, sizeof(buf));
                    if (cc <= 0) {
                        shutdown(pv1[0], SHUT_RDWR);
                        pfd[P_CRYPTREAD].revents = 0;
                    } else
                        (void) des_write(STDOUT_FILENO,
                                         buf, cc);
                }

                if (doencrypt &&
                        (pfd[P_CRYPTWRITE].revents & POLLIN)) {
                    errno = 0;
                    cc = des_read(STDIN_FILENO,
                                  buf, sizeof(buf));
                    if (cc <= 0) {
                        shutdown(pv2[0], SHUT_RDWR);
                        pfd[P_CRYPTWRITE].revents = 0;
                    } else
                        (void) write(pv2[0], buf, cc);
                }
#endif
#endif

            } while ((pfd[P_SOCKREAD].revents & POLLIN) ||
#ifdef CRYPT
#ifdef KERBEROS
                     (doencrypt && (pfd[P_CRYPTREAD].revents & POLLIN)) ||
#endif
#endif
                     (pfd[P_PIPEREAD].revents & POLLIN));
            exit(0);
        }
        setsid();
        (void) close(s);
        (void) close(pv[0]);
#ifdef CRYPT
#ifdef KERBEROS
        if (doencrypt) {
            close(pv1[0]);
            close(pv2[0]);
            dup2(pv1[1], 1);
            dup2(pv2[1], 0);
            close(pv1[1]);
            close(pv2[1]);
        }
#endif
#endif
        dup2(pv[1], 2);
        close(pv[1]);
    } else
        setsid();
    if (*pwd->pw_shell == '\0')
        pwd->pw_shell = _PATH_BSHELL;

    environ = envinit;
    if (setenv("HOME", pwd->pw_dir, 1) == -1 ||
            setenv("SHELL", pwd->pw_shell, 1) == -1 ||
            setenv("USER", pwd->pw_name, 1) == -1 ||
            setenv("LOGNAME", pwd->pw_name, 1) == -1)
        errx(1, "cannot setup environment");

    if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETALL))
        errx(1, "cannot set user context");
    if (auth_approval(as, lc, pwd->pw_name, "rsh") <= 0)
        errx(1, "approval failure");
    auth_close(as);
    login_close(lc);

    cp = strrchr(pwd->pw_shell, '/');
    if (cp)
        cp++;
    else
        cp = pwd->pw_shell;
    endpwent();
    if (log_success || pwd->pw_uid == 0) {
#ifdef	KERBEROS
        if (use_kerberos)
            syslog(LOG_INFO|LOG_AUTH,
                   "Kerberos shell from %s.%s@%s on %s as %s, cmd='%.80s'",
                   kdata->pname, kdata->pinst, kdata->prealm,
                   hostname, locuser, cmdbuf);
        else
#endif
            syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'",
                   remuser, hostname, locuser, cmdbuf);
    }
    execl(pwd->pw_shell, cp, "-c", cmdbuf, (char *)NULL);
    perror(pwd->pw_shell);
    exit(1);
}
Exemplo n.º 8
0
int main(int argc, char **argv)
{
	int c;
	int cnt;
	char *childArgv[10];
	char *buff;
	int childArgc = 0;
	int retcode;

	char *pwdbuf = NULL;
	struct passwd *pwd = NULL, _pwd;

	struct login_context cxt = {
		.tty_mode = TTY_MODE,		/* tty chmod() */
		.pid = getpid(),		/* PID */
		.conv = { misc_conv, NULL }	/* PAM conversation function */
	};

	timeout = getlogindefs_num("LOGIN_TIMEOUT", LOGIN_TIMEOUT);

	signal(SIGALRM, timedout);
	siginterrupt(SIGALRM, 1);	/* we have to interrupt syscalls like ioclt() */
	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
	 */
	while ((c = getopt(argc, argv, "fHh:pV")) != -1)
		switch (c) {
		case 'f':
			cxt.noauth = 1;
			break;

		case 'H':
			cxt.nohost = 1;
			break;

		case 'h':
			if (getuid()) {
				fprintf(stderr,
					_("login: -h for super-user only.\n"));
				exit(EXIT_FAILURE);
			}
			init_remote_info(&cxt, optarg);
			break;

		case 'p':
			cxt.keep_env = 1;
			break;

		case 'V':
			printf(UTIL_LINUX_VERSION);
			return EXIT_SUCCESS;
		case '?':
		default:
			fprintf(stderr, _("usage: login [ -p ] [ -h host ] [ -H ] [ -f username | username ]\n"));
			exit(EXIT_FAILURE);
		}
	argc -= optind;
	argv += optind;

	if (*argv) {
		char *p = *argv;
		cxt.username = xstrdup(p);

		/* wipe name - some people mistype their password here */
		/* (of course we are too late, but perhaps this helps a little ..) */
		while (*p)
			*p++ = ' ';
	}

	for (cnt = get_fd_tabsize() - 1; cnt > 2; cnt--)
		close(cnt);

	setpgrp();	 /* set pgid to pid this means that setsid() will fail */

	openlog("login", LOG_ODELAY, LOG_AUTHPRIV);

	init_tty(&cxt);
	init_loginpam(&cxt);

	/* login -f, then the user has already been authenticated */
	cxt.noauth = cxt.noauth && getuid() == 0 ? 1 : 0;

	if (!cxt.noauth)
		loginpam_auth(&cxt);

	/*
	 * Authentication may be skipped (for example, during krlogin, rlogin,
	 * etc...), but it doesn't mean that we can skip other account checks.
	 * The account could be disabled or password expired (althought
	 * kerberos ticket is valid).         -- [email protected] (22-Feb-2006)
	 */
	loginpam_acct(&cxt);

	if (!(cxt.pwd = get_passwd_entry(cxt.username, &pwdbuf, &_pwd))) {
		warnx(_("\nSession setup problem, abort."));
		syslog(LOG_ERR, _("Invalid user name \"%s\" in %s:%d. Abort."),
		       cxt.username, __FUNCTION__, __LINE__);
		pam_end(cxt.pamh, PAM_SYSTEM_ERR);
		sleepexit(EXIT_FAILURE);
	}

	pwd = cxt.pwd;
	cxt.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.
	 *
         * For root we don't call initgroups, instead we call setgroups with
	 * group 0. This avoids the need to step through the whole group file,
	 * which can cause problems if NIS, NIS+, LDAP or something similar
	 * is used and the machine has network problems.
	 */
	retcode = pwd->pw_uid ? initgroups(cxt.username, pwd->pw_gid) :	/* user */
			        setgroups(0, NULL);			/* root */
	if (retcode < 0) {
		syslog(LOG_ERR, _("groups initialization failed: %m"));
		warnx(_("\nSession setup problem, abort."));
		pam_end(cxt.pamh, PAM_SYSTEM_ERR);
		sleepexit(EXIT_FAILURE);
	}

	/*
	 * Open PAM session (after successful authentication and account check)
	 */
	loginpam_session(&cxt);

	/* committed to login -- turn off timeout */
	alarm((unsigned int)0);

	endpwent();

	cxt.quiet = get_hushlogin_status(pwd);

	log_utmp(&cxt);
	log_audit(&cxt, 1);
	log_lastlog(&cxt);

	chown_tty(&cxt);

	if (setgid(pwd->pw_gid) < 0 && pwd->pw_gid) {
		syslog(LOG_ALERT, _("setgid() failed"));
		exit(EXIT_FAILURE);
	}

	if (pwd->pw_shell == NULL || *pwd->pw_shell == '\0')
		pwd->pw_shell = _PATH_BSHELL;

	init_environ(&cxt);		/* init $HOME, $TERM ... */

	setproctitle("login", cxt.username);

	log_syslog(&cxt);

	if (!cxt.quiet) {
		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
	}

	/*
	 * Detach the controlling terminal, fork() and create, new session
	 * and reinilizalize syslog stuff.
	 */
	fork_session(&cxt);

	/* 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(EXIT_FAILURE);
	}

	/* wait until here to change directory! */
	if (chdir(pwd->pw_dir) < 0) {
		warn(_("%s: change directory failed"), pwd->pw_dir);

		if (!getlogindefs_bool("DEFAULT_HOME", 1))
			exit(0);
		if (chdir("/"))
			exit(EXIT_FAILURE);
		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 = xmalloc(strlen(pwd->pw_shell) + 6);

		strcpy(buff, "exec ");
		strcat(buff, pwd->pw_shell);
		childArgv[childArgc++] = "/bin/sh";
		childArgv[childArgc++] = "-sh";
		childArgv[childArgc++] = "-c";
		childArgv[childArgc++] = buff;
	} else {
		char tbuf[PATH_MAX + 2], *p;

		tbuf[0] = '-';
		xstrncpy(tbuf + 1, ((p = strrchr(pwd->pw_shell, '/')) ?
				    p + 1 : pwd->pw_shell), sizeof(tbuf) - 1);

		childArgv[childArgc++] = pwd->pw_shell;
		childArgv[childArgc++] = xstrdup(tbuf);
	}

	childArgv[childArgc++] = NULL;

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

	if (!strcmp(childArgv[0], "/bin/sh"))
		warn(_("couldn't exec shell script"));
	else
		warn(_("no shell"));

	exit(EXIT_SUCCESS);
}
Exemplo n.º 9
0
int main(int argc, char **argv)
{
	uid_t uid;
	struct passwd *pwd;
	struct group *grp;
	char *grp_user;
	int i;
	int found = 0;
	struct cmd_map *cmd;
	char *home = NULL;

	if (argc < 3) {
		die("Usage: %s <username> <command> [args ...]\n", argv[0]);
	}

	/* Ensure we're being run by either root or hacluster */
	uid = getuid();
	if (uid != 0) {
		/* Not root, let's see if we're running as hacluster */
		pwd = getpwuid(uid);
		if (pwd == NULL || strcmp(pwd->pw_name, HACLUSTER) != 0) {
			/*
			 * Not hacluster either.
			 * TODO: log this to syslog, to alert sysadmin
			 * of potential nefarious local user.
			 */
			die("ERROR: Permission denied\n");
		}
	}

	/* See who we're trying to become... */
	pwd = getpwnam(argv[1]);
	if (pwd == NULL) {
		die("ERROR: User '%s' not found\n", argv[1]);
	}

	/*
	 * Don't become root!
	 * (Is there really any sense checking for pw_name == "root"?
	 */
	if (pwd->pw_uid == 0 || strcmp(pwd->pw_name, "root") == 0) {
		die("ERROR: Thou shalt not become root\n");
	}

	/* Make sure the new user is in the haclient group */
	grp = getgrgid(pwd->pw_gid);
	if (grp == NULL) {
		die("ERROR: Can't determine group for user '%s'\n", pwd->pw_name);
	}
	if (strcmp(grp->gr_name, HACLIENT) != 0) {
		/* Not the primary group, let's check the others */
		grp = getgrnam(HACLIENT);
		if (grp == NULL) {
			die("ERROR: Group '%s' does not exist\n", HACLIENT);
		}
		i = 0;
		found = 0;
		while ((grp_user = grp->gr_mem[i]) != NULL) {
			if (strcmp(grp_user, pwd->pw_name) == 0) {
				found = 1;
				break;
			}
			i++;
		}
		if (!found) {
			die("ERROR: User '%s' is not in the '%s' group\n", pwd->pw_name, HACLIENT);
		}
	}

	/* Verify the command to execute is valid, and expand it */
	found = 0;
	for (cmd = commands; cmd->name != NULL; cmd++) {
		if (strcmp(cmd->name, argv[2]) == 0) {
			found = 1;
			break;
		}
	}
	if (!found) {
		die("ERROR: Invalid command '%s'\n", argv[2]);
	}
	/* (bit rough to drop const...) */
	argv[2] = (char *)cmd->path;

	/*
	 * Become the new user.  Note that at this point, grp still refers
	 * to the "haclient" group, either because that was the user's
	 * primary group, or because we looked that group up to search
	 * through its members.  Likewise pwd still refers to the user
	 * we're trying to become.
	 */
	if (setresgid(grp->gr_gid, grp->gr_gid, grp->gr_gid) != 0) {
		die("ERROR: Can't set group to '%s' (%d)\n", grp->gr_name, grp->gr_gid);
	}
	if (setresuid(pwd->pw_uid, pwd->pw_uid, pwd->pw_uid) != 0) {
		die("ERROR: Can't set user to '%s' (%d)\n", pwd->pw_name, pwd->pw_uid);
	}

	/*
	 * Bit of cleanup - is this in the right place, and is it really
	 * necessary?
	 */
	endpwent();
	endgrent();

	/* Clean up environment */
	home = getenv("HOME");
	if (home != NULL) {
		home = strdup(home);
	}
	if (clearenv() != 0) {
		die("ERROR: Can't clear environment");
	}
	setenv("PATH", SBINDIR":"BINDIR":/bin", 1);
	if (home != NULL) {
		setenv("HOME", home, 1);
	}

	/* And away we go... */
	execv(argv[2], &argv[2]);
	perror(argv[2]);
	return 1;
}
Exemplo n.º 10
0
    UserModel::UserModel(QObject *parent) : QAbstractListModel(parent), d(new UserModelPrivate()) {
        const QString facesDir = mainConfig.Theme.FacesDir.get();
        const QString defaultFace = QStringLiteral("file://%1/.face.icon").arg(facesDir);

        struct passwd *current_pw;
        while ((current_pw = getpwent()) != nullptr) {

            // skip entries with uids smaller than minimum uid
            if (int(current_pw->pw_uid) < mainConfig.Users.MinimumUid.get())
                continue;

            // skip entries with uids greater than maximum uid
            if (int(current_pw->pw_uid) > mainConfig.Users.MaximumUid.get())
                continue;
            // skip entries with user names in the hide users list
            if (mainConfig.Users.HideUsers.get().contains(QString::fromLocal8Bit(current_pw->pw_name)))
                continue;

            // skip entries with shells in the hide shells list
            if (mainConfig.Users.HideShells.get().contains(QString::fromLocal8Bit(current_pw->pw_shell)))
                continue;

            // skip duplicates
            // Note: getpwent() makes no attempt to suppress duplicate information
            // if multiple sources are specified in nsswitch.conf(5).
            if (d->users.cend()
                != std::find_if(d->users.cbegin(), d->users.cend(), [current_pw](const UserPtr & u) { return u->uid == current_pw->pw_uid; }))
                continue;

            // create user
            UserPtr user { new User() };
            user->name = QString::fromLocal8Bit(current_pw->pw_name);
            user->realName = QString::fromLocal8Bit(current_pw->pw_gecos).split(QLatin1Char(',')).first();
            user->homeDir = QString::fromLocal8Bit(current_pw->pw_dir);
            user->uid = int(current_pw->pw_uid);
            user->gid = int(current_pw->pw_gid);
            // if shadow is used pw_passwd will be 'x' nevertheless, so this
            // will always be true
            user->needsPassword = strcmp(current_pw->pw_passwd, "") != 0;

            // search for face icon
            user->icon = defaultFace;

            // add user
            d->users << user;
        }

        endpwent();

        // sort users by username
        std::sort(d->users.begin(), d->users.end(), [&](const UserPtr &u1, const UserPtr &u2) { return u1->name < u2->name; });

        bool avatarsEnabled = mainConfig.Theme.EnableAvatars.get();
        if (avatarsEnabled && mainConfig.Theme.EnableAvatars.isDefault()) {
            if (d->users.count() > mainConfig.Theme.DisableAvatarsThreshold.get()) avatarsEnabled=false;
        }

        // find out index of the last user
        for (int i = 0; i < d->users.size(); ++i) {
            UserPtr user { d->users.at(i) };
            if (user->name == stateConfig.Last.User.get())
                d->lastIndex = i;

            if (avatarsEnabled) {
                const QString userFace = QStringLiteral("%1/.face.icon").arg(user->homeDir);
                const QString systemFace = QStringLiteral("%1/%2.face.icon").arg(facesDir).arg(user->name);

                if (QFile::exists(userFace))
                    user->icon = QStringLiteral("file://%1").arg(userFace);
                else if (QFile::exists(systemFace))
                    user->icon = QStringLiteral("file://%1").arg(systemFace);
            }
        }
    }
Exemplo n.º 11
0
int
usr_add(char *str)
{
	u_int indx;
	USRT *pt;
	struct passwd *pw;
	uid_t uid;

	/*
	 * create the table if it doesn't exist
	 */
	if ((str == NULL) || (*str == '\0'))
		return(-1);
	if ((usrtb == NULL) &&
	    ((usrtb = calloc(USR_TB_SZ, sizeof(USRT *))) == NULL)) {
		paxwarn(1, "Unable to allocate memory for user selection table");
		return(-1);
	}

	/*
	 * figure out user spec
	 */
	if (str[0] != '#') {
		/*
		 * it is a user name, \# escapes # as first char in user name
		 */
		if ((str[0] == '\\') && (str[1] == '#'))
			++str;
		if ((pw = getpwnam(str)) == NULL) {
			paxwarn(1, "Unable to find uid for user: %s", str);
			return(-1);
		}
		uid = (uid_t)pw->pw_uid;
	} else
		uid = (uid_t)strtoul(str+1, NULL, 10);
	endpwent();

	/*
	 * hash it and go down the hash chain (if any) looking for it
	 */
	indx = ((unsigned)uid) % USR_TB_SZ;
	if ((pt = usrtb[indx]) != NULL) {
		while (pt != NULL) {
			if (pt->uid == uid)
				return(0);
			pt = pt->fow;
		}
	}

	/*
	 * uid is not yet in the table, add it to the front of the chain
	 */
	if ((pt = malloc(sizeof(USRT))) != NULL) {
		pt->uid = uid;
		pt->fow = usrtb[indx];
		usrtb[indx] = pt;
		return(0);
	}
	paxwarn(1, "User selection table out of memory");
	return(-1);
}
Exemplo n.º 12
0
static WDialog *
init_chown (void)
{
    int lines, cols;
    int i;
    int y;
    struct passwd *l_pass;
    struct group *l_grp;
    WDialog *ch_dlg;

    do_refresh ();

    end_chown = need_update = current_file = 0;
    single_set = (current_panel->marked < 2) ? 3 : 0;

    cols = GW * 3 + 2 + 6;
    lines = GH + 4 + (single_set ? 2 : 4);

    ch_dlg =
        dlg_create (TRUE, 0, 0, lines, cols, dialog_colors, chown_callback, NULL, "[Chown]",
                    _("Chown command"), DLG_CENTER);

    add_widget (ch_dlg, groupbox_new (2, 3, GH, GW, _("User name")));
    l_user = listbox_new (3, 4, GH - 2, GW - 2, FALSE, NULL);
    add_widget (ch_dlg, l_user);
    /* add field for unknown names (numbers) */
    listbox_add_item (l_user, LISTBOX_APPEND_AT_END, 0, _("<Unknown user>"), NULL);
    /* get and put user names in the listbox */
    setpwent ();
    while ((l_pass = getpwent ()) != NULL)
        listbox_add_item (l_user, LISTBOX_APPEND_SORTED, 0, l_pass->pw_name, NULL);
    endpwent ();

    add_widget (ch_dlg, groupbox_new (2, 4 + GW, GH, GW, _("Group name")));
    l_group = listbox_new (3, 5 + GW, GH - 2, GW - 2, FALSE, NULL);
    add_widget (ch_dlg, l_group);
    /* add field for unknown names (numbers) */
    listbox_add_item (l_group, LISTBOX_APPEND_AT_END, 0, _("<Unknown group>"), NULL);
    /* get and put group names in the listbox */
    setgrent ();
    while ((l_grp = getgrent ()) != NULL)
        listbox_add_item (l_group, LISTBOX_APPEND_SORTED, 0, l_grp->gr_name, NULL);
    endgrent ();

    add_widget (ch_dlg, groupbox_new (2, 5 + GW * 2, GH, GW, _("File")));
    /* add widgets for the file information */
    for (i = 0; i < LABELS; i++)
    {
        chown_label[i].l = label_new (chown_label[i].y, 7 + GW * 2, "");
        add_widget (ch_dlg, chown_label[i].l);
    }

    if (!single_set)
    {
        int x;

        add_widget (ch_dlg, hline_new (lines - chown_but[0].y - 1, -1, -1));

        y = lines - chown_but[0].y;
        x = (cols - blen) / 2;

        for (i = 0; i < BUTTONS - 2; i++)
        {
            add_widget (ch_dlg,
                        button_new (y, x, chown_but[i].ret_cmd, chown_but[i].flags,
                                    chown_but[i].text, NULL));
            x += chown_but[i].len + 1;
        }
    }

    i = BUTTONS - 2;
    y = lines - chown_but[i].y;
    add_widget (ch_dlg, hline_new (y - 1, -1, -1));
    add_widget (ch_dlg,
                button_new (y, WIDGET (ch_dlg)->cols / 2 - chown_but[i].len, chown_but[i].ret_cmd,
                            chown_but[i].flags, chown_but[i].text, NULL));
    i++;
    add_widget (ch_dlg,
                button_new (y, WIDGET (ch_dlg)->cols / 2 + 1, chown_but[i].ret_cmd,
                            chown_but[i].flags, chown_but[i].text, NULL));

    /* select first listbox */
    dlg_select_widget (l_user);

    return ch_dlg;
}
Exemplo n.º 13
0
int main(int argc, char ** argv)
{
	int c;
	int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
	char * orgoptions = NULL;
	char * share_name = NULL;
	const char * ipaddr = NULL;
	char * uuid = NULL;
	char * mountpoint = NULL;
	char * options = NULL;
	char * optionstail;
	char * resolved_path = NULL;
	char * temp;
	char * dev_name;
	int rc = 0;
	int rsize = 0;
	int wsize = 0;
	int nomtab = 0;
	int uid = 0;
	int gid = 0;
	int optlen = 0;
	int orgoptlen = 0;
	size_t options_size = 0;
	size_t current_len;
	int retry = 0; /* set when we have to retry mount with uppercase */
	struct addrinfo *addrhead = NULL, *addr;
	struct stat statbuf;
	struct utsname sysinfo;
	struct mntent mountent;
	struct sockaddr_in *addr4;
	struct sockaddr_in6 *addr6;
	FILE * pmntfile;

	/* setlocale(LC_ALL, "");
	bindtextdomain(PACKAGE, LOCALEDIR);
	textdomain(PACKAGE); */

	if(argc && argv) {
		thisprogram = argv[0];
	} else {
		mount_cifs_usage();
		exit(EX_USAGE);
	}

	if(thisprogram == NULL)
		thisprogram = "mount.cifs";

	uname(&sysinfo);
	/* BB add workstation name and domain and pass down */

/* #ifdef _GNU_SOURCE
	printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
#endif */
	if(argc > 2) {
		dev_name = argv[1];
		share_name = strndup(argv[1], MAX_UNC_LEN);
		if (share_name == NULL) {
			fprintf(stderr, "%s: %s", argv[0], strerror(ENOMEM));
			exit(EX_SYSERR);
		}
		mountpoint = argv[2];
	} else if (argc == 2) {
		if ((strcmp(argv[1], "-V") == 0) ||
		    (strcmp(argv[1], "--version") == 0))
		{
			print_cifs_mount_version();
			exit(0);
		}

		if ((strcmp(argv[1], "-h") == 0) ||
		    (strcmp(argv[1], "-?") == 0) ||
		    (strcmp(argv[1], "--help") == 0))
		{
			mount_cifs_usage();
			exit(0);
		}

		mount_cifs_usage();
		exit(EX_USAGE);
	} else {
		mount_cifs_usage();
		exit(EX_USAGE);
	}

	/* add sharename in opts string as unc= parm */

	while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
			 longopts, NULL)) != -1) {
		switch (c) {
/* No code to do the following  options yet */
/*	case 'l':
		list_with_volumelabel = 1;
		break;
	case 'L':
		volumelabel = optarg;
		break; */
/*	case 'a':	       
		++mount_all;
		break; */

		case '?':
		case 'h':	 /* help */
			mount_cifs_usage ();
			exit(EX_USAGE);
		case 'n':
			++nomtab;
			break;
		case 'b':
#ifdef MS_BIND
			flags |= MS_BIND;
#else
			fprintf(stderr,
				"option 'b' (MS_BIND) not supported\n");
#endif
			break;
		case 'm':
#ifdef MS_MOVE		      
			flags |= MS_MOVE;
#else
			fprintf(stderr,
				"option 'm' (MS_MOVE) not supported\n");
#endif
			break;
		case 'o':
			orgoptions = strdup(optarg);
		    break;
		case 'r':  /* mount readonly */
			flags |= MS_RDONLY;
			break;
		case 'U':
			uuid = optarg;
			break;
		case 'v':
			++verboseflag;
			break;
		case 'V':
			print_cifs_mount_version();
			exit (0);
		case 'w':
			flags &= ~MS_RDONLY;
			break;
		case 'R':
			rsize = atoi(optarg) ;
			break;
		case 'W':
			wsize = atoi(optarg);
			break;
		case '1':
			if (isdigit(*optarg)) {
				char *ep;

				uid = strtoul(optarg, &ep, 10);
				if (*ep) {
					printf("bad uid value \"%s\"\n", optarg);
					exit(EX_USAGE);
				}
			} else {
				struct passwd *pw;

				if (!(pw = getpwnam(optarg))) {
					printf("bad user name \"%s\"\n", optarg);
					exit(EX_USAGE);
				}
				uid = pw->pw_uid;
				endpwent();
			}
			break;
		case '2':
			if (isdigit(*optarg)) {
				char *ep;

				gid = strtoul(optarg, &ep, 10);
				if (*ep) {
					printf("bad gid value \"%s\"\n", optarg);
					exit(EX_USAGE);
				}
			} else {
				struct group *gr;

				if (!(gr = getgrnam(optarg))) {
					printf("bad user name \"%s\"\n", optarg);
					exit(EX_USAGE);
				}
				gid = gr->gr_gid;
				endpwent();
			}
			break;
		case 'u':
			got_user = 1;
			user_name = optarg;
			break;
		case 'd':
			domain_name = optarg; /* BB fix this - currently ignored */
			got_domain = 1;
			break;
		case 'p':
			if(mountpassword == NULL)
				mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
			if(mountpassword) {
				got_password = 1;
				strlcpy(mountpassword,optarg,MOUNT_PASSWD_SIZE+1);
			}
			break;
		case 'S':
			get_password_from_file(0 /* stdin */,NULL);
			break;
		case 't':
			break;
		case 'f':
			++fakemnt;
			break;
		default:
			printf("unknown mount option %c\n",c);
			mount_cifs_usage();
			exit(EX_USAGE);
		}
	}

	if((argc < 3) || (dev_name == NULL) || (mountpoint == NULL)) {
		mount_cifs_usage();
		exit(EX_USAGE);
	}

	if (getenv("PASSWD")) {
		if(mountpassword == NULL)
			mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
		if(mountpassword) {
			strlcpy(mountpassword,getenv("PASSWD"),MOUNT_PASSWD_SIZE+1);
			got_password = 1;
		}
	} else if (getenv("PASSWD_FD")) {
		get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
	} else if (getenv("PASSWD_FILE")) {
		get_password_from_file(0, getenv("PASSWD_FILE"));
	}

        if (orgoptions && parse_options(&orgoptions, &flags)) {
                rc = EX_USAGE;
		goto mount_exit;
	}
	addrhead = addr = parse_server(&share_name);
	if((addrhead == NULL) && (got_ip == 0)) {
		printf("No ip address specified and hostname not found\n");
		rc = EX_USAGE;
		goto mount_exit;
	}
	
	/* BB save off path and pop after mount returns? */
	resolved_path = (char *)malloc(PATH_MAX+1);
	if(resolved_path) {
		/* Note that if we can not canonicalize the name, we get
		another chance to see if it is valid when we chdir to it */
		if (realpath(mountpoint, resolved_path)) {
			mountpoint = resolved_path; 
		}
	}
	if(chdir(mountpoint)) {
		printf("mount error: can not change directory into mount target %s\n",mountpoint);
		rc = EX_USAGE;
		goto mount_exit;
	}

	if(stat (".", &statbuf)) {
		printf("mount error: mount point %s does not exist\n",mountpoint);
		rc = EX_USAGE;
		goto mount_exit;
	}

	if (S_ISDIR(statbuf.st_mode) == 0) {
		printf("mount error: mount point %s is not a directory\n",mountpoint);
		rc = EX_USAGE;
		goto mount_exit;
	}

	if((getuid() != 0) && (geteuid() == 0)) {
		if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
#ifndef CIFS_ALLOW_USR_SUID
			/* Do not allow user mounts to control suid flag
			for mount unless explicitly built that way */
			flags |= MS_NOSUID | MS_NODEV;
#endif						
		} else {
			printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n"); 
			exit(EX_USAGE);
		}
	}

	if(got_user == 0) {
		/* Note that the password will not be retrieved from the
		   USER env variable (ie user%password form) as there is
		   already a PASSWD environment varaible */
		if (getenv("USER"))
			user_name = strdup(getenv("USER"));
		if (user_name == NULL)
			user_name = getusername();
		got_user = 1;
	}
       
	if(got_password == 0) {
		char *tmp_pass = getpass("Password: "******"Password not entered, exiting\n");
			exit(EX_USAGE);
		}
		strlcpy(mountpassword, tmp_pass, MOUNT_PASSWD_SIZE+1);
		got_password = 1;
	}
	/* FIXME launch daemon (handles dfs name resolution and credential change) 
	   remember to clear parms and overwrite password field before launching */
	if(orgoptions) {
		optlen = strlen(orgoptions);
		orgoptlen = optlen;
	} else
		optlen = 0;
	if(share_name)
		optlen += strlen(share_name) + 4;
	else {
		printf("No server share name specified\n");
		printf("\nMounting the DFS root for server not implemented yet\n");
                exit(EX_USAGE);
	}
	if(user_name)
		optlen += strlen(user_name) + 6;
	optlen += MAX_ADDRESS_LEN + 4;
	if(mountpassword)
		optlen += strlen(mountpassword) + 6;
mount_retry:
	SAFE_FREE(options);
	options_size = optlen + 10 + DOMAIN_SIZE;
	options = (char *)malloc(options_size /* space for commas in password */ + 8 /* space for domain=  , domain name itself was counted as part of the length username string above */);

	if(options == NULL) {
		printf("Could not allocate memory for mount options\n");
		exit(EX_SYSERR);
	}

	strlcpy(options, "unc=", options_size);
	strlcat(options,share_name,options_size);
	/* scan backwards and reverse direction of slash */
	temp = strrchr(options, '/');
	if(temp > options + 6)
		*temp = '\\';
	if(user_name) {
		/* check for syntax like user=domain\user */
		if(got_domain == 0)
			domain_name = check_for_domain(&user_name);
		strlcat(options,",user="******",domain=",options_size);
			strlcat(options,domain_name,options_size);
		}
	}

	strlcat(options,",ver=",options_size);
	strlcat(options,MOUNT_CIFS_VERSION_MAJOR,options_size);

	if(orgoptions) {
		strlcat(options,",",options_size);
		strlcat(options,orgoptions,options_size);
	}
	if(prefixpath) {
		strlcat(options,",prefixpath=",options_size);
		strlcat(options,prefixpath,options_size); /* no need to cat the / */
	}

	/* convert all '\\' to '/' in share portion so that /proc/mounts looks pretty */
	replace_char(dev_name, '\\', '/', strlen(share_name));

	if (!got_ip && addr) {
		strlcat(options, ",ip=", options_size);
		current_len = strnlen(options, options_size);
		optionstail = options + current_len;
		switch (addr->ai_addr->sa_family) {
		case AF_INET6:
			addr6 = (struct sockaddr_in6 *) addr->ai_addr;
			ipaddr = inet_ntop(AF_INET6, &addr6->sin6_addr, optionstail,
					   options_size - current_len);
			break;
		case AF_INET:
			addr4 = (struct sockaddr_in *) addr->ai_addr;
			ipaddr = inet_ntop(AF_INET, &addr4->sin_addr, optionstail,
					   options_size - current_len);
			break;
		}

		/* if the address looks bogus, try the next one */
		if (!ipaddr) {
			addr = addr->ai_next;
			if (addr)
				goto mount_retry;
			rc = EX_SYSERR;
			goto mount_exit;
		}
	}

	if(verboseflag)
		fprintf(stderr, "\nmount.cifs kernel mount options: %s", options);

	if (mountpassword) {
		/*
		 * Commas have to be doubled, or else they will
		 * look like the parameter separator
		 */
		if(retry == 0)
			check_for_comma(&mountpassword);
		strlcat(options,",pass="******",pass=********");
	}

	if (verboseflag)
		fprintf(stderr, "\n");

	if (!fakemnt && mount(dev_name, mountpoint, "cifs", flags, options)) {
		switch (errno) {
		case ECONNREFUSED:
		case EHOSTUNREACH:
			if (addr) {
				addr = addr->ai_next;
				if (addr)
					goto mount_retry;
			}
			break;
		case ENODEV:
			printf("mount error: cifs filesystem not supported by the system\n");
			break;
		case ENXIO:
			if(retry == 0) {
				retry = 1;
				if (uppercase_string(dev_name) &&
				    uppercase_string(share_name) &&
				    uppercase_string(prefixpath)) {
					printf("retrying with upper case share name\n");
					goto mount_retry;
				}
			}
		}
		printf("mount error(%d): %s\n", errno, strerror(errno));
		printf("Refer to the mount.cifs(8) manual page (e.g. man "
		       "mount.cifs)\n");
		rc = EX_FAIL;
		goto mount_exit;
	}

	if (nomtab)
		goto mount_exit;
	atexit(unlock_mtab);
	rc = lock_mtab();
	if (rc) {
		printf("cannot lock mtab");
		goto mount_exit;
	}
	pmntfile = setmntent(MOUNTED, "a+");
	if (!pmntfile) {
		printf("could not update mount table\n");
		unlock_mtab();
		rc = EX_FILEIO;
		goto mount_exit;
	}
	mountent.mnt_fsname = dev_name;
	mountent.mnt_dir = mountpoint;
	mountent.mnt_type = CONST_DISCARD(char *,"cifs");
	mountent.mnt_opts = (char *)malloc(220);
	if(mountent.mnt_opts) {
		char * mount_user = getusername();
		memset(mountent.mnt_opts,0,200);
		if(flags & MS_RDONLY)
			strlcat(mountent.mnt_opts,"ro",220);
		else
			strlcat(mountent.mnt_opts,"rw",220);
		if(flags & MS_MANDLOCK)
			strlcat(mountent.mnt_opts,",mand",220);
		if(flags & MS_NOEXEC)
			strlcat(mountent.mnt_opts,",noexec",220);
		if(flags & MS_NOSUID)
			strlcat(mountent.mnt_opts,",nosuid",220);
		if(flags & MS_NODEV)
			strlcat(mountent.mnt_opts,",nodev",220);
		if(flags & MS_SYNCHRONOUS)
			strlcat(mountent.mnt_opts,",sync",220);
		if(mount_user) {
			if(getuid() != 0) {
				strlcat(mountent.mnt_opts,
					",user=", 220);
				strlcat(mountent.mnt_opts,
					mount_user, 220);
			}
		}
	}
	mountent.mnt_freq = 0;
	mountent.mnt_passno = 0;
	rc = addmntent(pmntfile,&mountent);
	endmntent(pmntfile);
	unlock_mtab();
	SAFE_FREE(mountent.mnt_opts);
	if (rc)
		rc = EX_FILEIO;
mount_exit:
	if(mountpassword) {
		int len = strlen(mountpassword);
		memset(mountpassword,0,len);
		SAFE_FREE(mountpassword);
	}

	if (addrhead)
		freeaddrinfo(addrhead);
	SAFE_FREE(options);
	SAFE_FREE(orgoptions);
	SAFE_FREE(resolved_path);
	SAFE_FREE(share_name);
	exit(rc);
}
Exemplo n.º 14
0
static int assoc_ind( struct tdu_user *usr, struct tdu_param *par)
{
	struct eft * eft = usr->priv;
	unsigned char calling[TDU_PLEN_ADDR+1]="", udata[TDU_PLEN_UDATA+1]="",
		*user="", *pass="";
	struct tdu_assoc_param *respar=par->res.assoc, *inpar=par->par.assoc;

	par->other_reason[0] = 0;
	par->other_reason[1] = 0;

	/*
	 * the tdu layer checks that the maximum udata len is not exceeded,
	 * which should prevent overflow attacks here.
	 */
	tdu_mk_printable(udata, inpar->udata, inpar->udata_len);
	tdu_mk_printable(calling, inpar->calling_addr, inpar->calling_len);

	tdu_printf(TDU_LOG_TRC," assoc_ind, ident_len=%d\n",inpar->ident_len);

	eft_set_flags(eft,eft_get_flags(eft)|EFT_FLAG_STRICT_TREE);

	if( inpar->ident_len > 0 ){
 		user = inpar->ident;
		/* Prevent possible buffer overflows by string functions
		 * depending on zero termination.
		 * The struct tdu_assoc_param contains space for adding
		 * an extra delimiting \0 charater.
		 * Be also careful with missing pass here
		 */
		user[inpar->ident_len]=0;
		pass = user;
		while( pass-user < inpar->ident_len ){
			if(*pass == '/'){
				*pass = 0;
				pass++;
				break;
			}
			pass++;
		};
		tdu_printf(TDU_LOG_AP1,"IND: ASSOC  id=%s calling=%s udata=%s\n",user,calling,udata ); 
		/* 
		 * A leading '+' is used to indicate that the server shall
		 * apply the case-insensitiveness or other compatibility
		 * hacks for transfer names.
		 * The '+' is not part of the user id, thus stripping it.
		 */
		if( user[0] == '+' ){
			long flags;
			user++;

			flags = eft_get_flags(eft);
			eft_set_flags(eft,flags|EFT_FLAG_CASEFIX_TN|
				      EFT_FLAG_CASEFIX_FS|EFT_FLAG_SLASHFIX);
		}
		/* 20.11.98, [email protected]: mapping to user eft_map_to_user, if 	  failed 
		 *
		 * Slightly modified and moved here (1999-01-07) -- HE:
		 *
		 * Now mapping to default user only if user is not in
		 * passwd database.
		 *
		 * FIXME:
		 * This check might be inappropriate if other authentication
		 * methods (not based on /etc/passwd) are used.
		 */
		
		if (eft_map_to_user) {
			struct passwd *pw;
			/*
			 */
			setpwent();
			while( (pw=getpwent()) ){
				if( strcmp(user,pw->pw_name) == 0) break;
			};
			endpwent();
			
			if( ! pw ){
				/* user is unknown (not in /etc/passwd).*/
				tdu_printf(TDU_LOG_LOG, "user %s not known, trying alternate authentication as user \"%s\" instead\n",
					   user, eft_map_to_user);
				user = eft_map_to_user;
				pass = "";
			}
		}

		strcpy(eft->user_name,user);
		par->reason = eft->check_user(eft,user,pass,eft_peer_phone(eft));
	} else {
		strcpy(eft->user_name,"(empty)");
		tdu_printf(TDU_LOG_AP1,"IND: ASSOC  with empty id" 
			   " calling=%s udata=%s\n", calling, udata ); 
		par->reason = eft->check_user(eft,"","",eft_peer_phone(eft));
	}
	
	respar->resp_timeout = 15;
	respar->called_len = LIMIT(strlen(eft->address), TDU_PLEN_ADDR);
	memcpy( respar->called_addr, eft->address, respar->called_len);

	if(! eft_signature ){
		respar->udata_len = -1;
	} else {
		respar->udata_len = LIMIT(strlen(eft_signature), TDU_PLEN_UDATA);
		memcpy( respar->udata, eft_signature, respar->udata_len);
	}

	if( par->reason ) {
		tdu_printf(TDU_LOG_AP1,"REJ: ASSOC  user=%s from=%s\n",
		   user, eft_peer_phone(eft)); 
	} else {
		tdu_printf(TDU_LOG_AP1,"ACP: ASSOC  user=%s from=%s\n",
		   user, eft_peer_phone(eft)); 
	}

	tdu_printf(TDU_LOG_LOG,"user \"%s\" from %s %s\n",
		   user, eft_peer_phone(eft), 
		   par->reason ? "rejected" : "accepted");
	if( par->reason == TDU_RE_OTHER_REASON ) 
		par->other_reason[0] = EFT_RE_ID_REJECTED;
 
	return par->reason;
}
Exemplo n.º 15
0
uim_bool
uim_helper_get_pathname(char *helper_path, int len)
{
  struct passwd *pw;
  char *runtimedir;

  if (len <= 0)
    return UIM_FALSE;

  if (UIM_CATCH_ERROR_BEGIN())
    return UIM_FALSE;

  runtimedir = getenv("XDG_RUNTIME_DIR");
  if (runtimedir && runtimedir[0]) {
    if (strlcpy(helper_path, runtimedir, len) >= (size_t)len)
      goto path_error;
    if (strlcat(helper_path, "/uim", len) >= (size_t)len)
      goto path_error;
  } else {
    pw = getpwuid(getuid());
    if (!pw) {
      endpwent();
      goto path_error;
    }

    if (strlcpy(helper_path, pw->pw_dir, len) >= (size_t)len) {
      endpwent();
      goto path_error;
    }
    if (strlcat(helper_path, "/.uim.d", len) >= (size_t)len) {
      endpwent();
      goto path_error;
    }
    endpwent();
  }

  /* check $XDG_RUNTIME_DIR/uim/ if $XDG_RUNTIME_DIR is available.
   * otherwise ~/.uim.d/
   */
  if (!check_dir(helper_path))
    goto path_error;

  /* check $XDG_RUNTIME_DIR/uim/socket/ if $XDG_RUNTIME_DIR is available.
   * otherwise ~/.uim.d/socket/
   */
  if (strlcat(helper_path, "/socket", len) >= (size_t)len)
    goto path_error;

  if (!check_dir(helper_path))
    goto path_error;

  if (strlcat(helper_path, "/uim-helper", len) >= (size_t)len)
    goto path_error;

  UIM_CATCH_ERROR_END();

  return UIM_TRUE;

 path_error:
#if USE_UIM_NOTIFY && !UIM_NON_LIBUIM_PROG
  uim_notify_fatal("uim_helper_get_pathname() failed");
#else
  fprintf(stderr, "uim_helper_get_pathname() failed\n");
#endif
  helper_path[0] = '\0';

  UIM_CATCH_ERROR_END();
  return UIM_FALSE;
}
Exemplo n.º 16
0
/*
 * Prescan command line for [-U user] argument
 * and fill context with defaults
 */
int
smb_ctx_init(struct smb_ctx *ctx, int argc, char *argv[],
	int minlevel, int maxlevel, int sharetype)
{
	int  opt, error = 0;
	uid_t euid;
	const char *arg, *cp;
	struct passwd *pwd;

	bzero(ctx,sizeof(*ctx));
	error = nb_ctx_create(&ctx->ct_nb);
	if (error)
		return error;
	ctx->ct_fd = -1;
	ctx->ct_parsedlevel = SMBL_NONE;
	ctx->ct_minlevel = minlevel;
	ctx->ct_maxlevel = maxlevel;

	ctx->ct_ssn.ioc_opt = SMBVOPT_CREATE;
	ctx->ct_ssn.ioc_timeout = 15;
	ctx->ct_ssn.ioc_retrycount = 4;
	ctx->ct_ssn.ioc_owner = SMBM_ANY_OWNER;
	ctx->ct_ssn.ioc_group = SMBM_ANY_GROUP;
	ctx->ct_ssn.ioc_mode = SMBM_EXEC;
	ctx->ct_ssn.ioc_rights = SMBM_DEFAULT;

	ctx->ct_sh.ioc_opt = SMBVOPT_CREATE;
	ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER;
	ctx->ct_sh.ioc_group = SMBM_ANY_GROUP;
	ctx->ct_sh.ioc_mode = SMBM_EXEC;
	ctx->ct_sh.ioc_rights = SMBM_DEFAULT;
	ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER;
	ctx->ct_sh.ioc_group = SMBM_ANY_GROUP;

	nb_ctx_setscope(ctx->ct_nb, "");
	euid = geteuid();
	if ((pwd = getpwuid(euid)) != NULL) {
		smb_ctx_setuser(ctx, pwd->pw_name);
		endpwent();
	} else if (euid == 0)
		smb_ctx_setuser(ctx, "root");
	else
		return 0;
	if (argv == NULL)
		return 0;
	for (opt = 1; opt < argc; opt++) {
		cp = argv[opt];
		if (strncmp(cp, "//", 2) != 0)
			continue;
		error = smb_ctx_parseunc(ctx, cp, sharetype, (const char**)&cp);
		if (error)
			return error;
		ctx->ct_uncnext = cp;
		break;
	}
	while (error == 0 && (opt = cf_getopt(argc, argv, ":E:L:U:")) != -1) {
		arg = cf_optarg;
		switch (opt) {
		    case 'E':
			error = smb_ctx_setcharset(ctx, arg);
			if (error)
				return error;
			break;
		    case 'L':
			error = nls_setlocale(optarg);
			if (error)
				break;
			break;
		    case 'U':
			error = smb_ctx_setuser(ctx, arg);
			break;
		}
	}
	cf_optind = cf_optreset = 1;
	return error;
}
Exemplo n.º 17
0
static int
do_test (void)
{
  int retval = 0;

  __nss_configure_lookup ("passwd", "test1");

  static const unsigned int pwdids[] = { 100, 30, 200, 60, 20000 };
#define npwdids (sizeof (pwdids) / sizeof (pwdids[0]))
  setpwent ();

  const unsigned int *np = pwdids;
  for (struct passwd *p = getpwent (); p != NULL; ++np, p = getpwent ())
    if (p->pw_uid != *np || strncmp (p->pw_name, "name", 4) != 0
	|| atol (p->pw_name + 4) != *np)
      {
	printf ("passwd entry %ju wrong (%s, %u)\n",
		np - pwdids, p->pw_name, p->pw_uid);
	retval = 1;
	break;
      }

  endpwent ();

  for (int i = npwdids - 1; i >= 0; --i)
    {
      char buf[30];
      snprintf (buf, sizeof (buf), "name%u", pwdids[i]);

      struct passwd *p = getpwnam (buf);
      if (p == NULL || p->pw_uid != pwdids[i] || strcmp (buf, p->pw_name) != 0)
	{
	  printf ("passwd entry \"%s\" wrong\n", buf);
	  retval = 1;
	}

      p = getpwuid (pwdids[i]);
      if (p == NULL || p->pw_uid != pwdids[i] || strcmp (buf, p->pw_name) != 0)
	{
	  printf ("passwd entry %u wrong\n", pwdids[i]);
	  retval = 1;
	}

      snprintf (buf, sizeof (buf), "name%u", pwdids[i] + 1);

      p = getpwnam (buf);
      if (p != NULL)
	{
	  printf ("passwd entry \"%s\" wrong\n", buf);
	  retval = 1;
	}

      p = getpwuid (pwdids[i] + 1);
      if (p != NULL)
	{
	  printf ("passwd entry %u wrong\n", pwdids[i] + 1);
	  retval = 1;
	}
    }

  return retval;
}
Exemplo n.º 18
0
static void
do_enter_key (WDialog * h, int f_pos)
{
    WDialog *chl_dlg;
    WListbox *chl_list;
    struct passwd *chl_pass;
    struct group *chl_grp;
    int fe;
    int lxx, lyy, b_pos;
    gboolean chl_end, is_owner;
    const char *title;
    int result;

    do
    {
        is_owner = (f_pos == 3);
        title = is_owner ? _("owner") : _("group");

        lxx = (COLS - 74) / 2 + (is_owner ? 35 : 53);
        lyy = (LINES - 13) / 2;
        chl_end = FALSE;

        chl_dlg =
            dlg_create (TRUE, lyy, lxx, 13, 17, dialog_colors, chl_callback, NULL,
                        "[Advanced Chown]", title, DLG_COMPACT);

        /* get new listboxes */
        chl_list = listbox_new (1, 1, 11, 15, FALSE, NULL);
        listbox_add_item (chl_list, LISTBOX_APPEND_AT_END, 0, "<Unknown>", NULL);
        if (is_owner)
        {
            /* get and put user names in the listbox */
            setpwent ();
            while ((chl_pass = getpwent ()) != NULL)
                listbox_add_item (chl_list, LISTBOX_APPEND_SORTED, 0, chl_pass->pw_name, NULL);
            endpwent ();
            fe = listbox_search_text (chl_list, get_owner (sf_stat->st_uid));
        }
        else
        {
            /* get and put group names in the listbox */
            setgrent ();
            while ((chl_grp = getgrent ()) != NULL)
                listbox_add_item (chl_list, LISTBOX_APPEND_SORTED, 0, chl_grp->gr_name, NULL);
            endgrent ();
            fe = listbox_search_text (chl_list, get_group (sf_stat->st_gid));
        }

        listbox_select_entry (chl_list, fe);

        b_pos = chl_list->pos;
        add_widget (chl_dlg, chl_list);

        result = dlg_run (chl_dlg);

        if (b_pos != chl_list->pos)
        {
            gboolean ok = FALSE;
            char *text;

            listbox_get_current (chl_list, &text, NULL);
            if (is_owner)
            {
                chl_pass = getpwnam (text);
                if (chl_pass != NULL)
                {
                    ok = TRUE;
                    sf_stat->st_uid = chl_pass->pw_uid;
                }
            }
            else
            {
                chl_grp = getgrnam (text);
                if (chl_grp != NULL)
                {
                    sf_stat->st_gid = chl_grp->gr_gid;
                    ok = TRUE;
                }
            }
            if (ok)
            {
                ch_flags[f_pos + 6] = '+';
                update_ownership ();
            }
            dlg_focus (h);
            if (ok)
                print_flags ();
        }
        if (result == KEY_LEFT)
        {
            if (!is_owner)
                chl_end = TRUE;
            dlg_one_up (ch_dlg);
            f_pos--;
        }
        else if (result == KEY_RIGHT)
        {
            if (is_owner)
                chl_end = TRUE;
            dlg_one_down (ch_dlg);
            f_pos++;
        }
        /* Here we used to redraw the window */
        dlg_destroy (chl_dlg);
    }
    while (chl_end);
}
Exemplo n.º 19
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));
	}
Exemplo n.º 20
0
int
main(int argc, char *argv[])
{
	char *domain, *p, *ttyn, *shell, *fullname, *instance;
	char *lipaddr, *script, *ripaddr, *style, *type, *fqdn;
	char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
	char localhost[MAXHOSTNAMELEN], *copyright;
	char mail[sizeof(_PATH_MAILDIR) + 1 + NAME_MAX];
	int ask, ch, cnt, fflag, pflag, quietlog, rootlogin, lastchance;
	int error, homeless, needto, authok, tries, backoff;
	struct addrinfo *ai, hints;
	struct rlimit cds, scds;
	quad_t expire, warning;
	struct utmp utmp;
	struct group *gr;
	struct stat st;
	uid_t uid;

	openlog("login", LOG_ODELAY, LOG_AUTH);

	fqdn = lipaddr = ripaddr = fullname = type = NULL;
	authok = 0;
	tries = 10;
	backoff = 3;

	domain = NULL;
	if (gethostname(localhost, sizeof(localhost)) < 0) {
		syslog(LOG_ERR, "couldn't get local hostname: %m");
		strlcpy(localhost, "localhost", sizeof(localhost));
	} else if ((domain = strchr(localhost, '.'))) {
		domain++;
		if (*domain && strchr(domain, '.') == NULL)
			domain = localhost;
	}

	if ((as = auth_open()) == NULL) {
		syslog(LOG_ERR, "auth_open: %m");
		err(1, "unable to initialize BSD authentication");
	}
	auth_setoption(as, "login", "yes");

	/*
	 * -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
	 */
	fflag = pflag = 0;
	uid = getuid();
	while ((ch = getopt(argc, argv, "fh:pu:L:R:")) != -1)
		switch (ch) {
		case 'f':
			fflag = 1;
			break;
		case 'h':
			if (uid) {
				warnc(EPERM, "-h option");
				quickexit(1);
			}
			free(fqdn);
			if ((fqdn = strdup(optarg)) == NULL) {
				warn(NULL);
				quickexit(1);
			}
			auth_setoption(as, "fqdn", fqdn);
			if (domain && (p = strchr(optarg, '.')) &&
			    strcasecmp(p+1, domain) == 0)
				*p = 0;
			hostname = optarg;
			auth_setoption(as, "hostname", hostname);
			break;
		case 'L':
			if (uid) {
				warnc(EPERM, "-L option");
				quickexit(1);
			}
			if (lipaddr) {
				warnx("duplicate -L option");
				quickexit(1);
			}
			lipaddr = optarg;
			memset(&hints, 0, sizeof(hints));
			hints.ai_family = PF_UNSPEC;
			hints.ai_flags = AI_CANONNAME;
			error = getaddrinfo(lipaddr, NULL, &hints, &ai);
			if (!error) {
				strlcpy(localhost, ai->ai_canonname,
				    sizeof(localhost));
				freeaddrinfo(ai);
			} else
				strlcpy(localhost, lipaddr, sizeof(localhost));
			auth_setoption(as, "local_addr", lipaddr);
			break;
		case 'p':
			pflag = 1;
			break;
		case 'R':
			if (uid) {
				warnc(EPERM, "-R option");
				quickexit(1);
			}
			if (ripaddr) {
				warnx("duplicate -R option");
				quickexit(1);
			}
			ripaddr = optarg;
			auth_setoption(as, "remote_addr", ripaddr);
			break;
		case 'u':
			if (uid) {
				warnc(EPERM, "-u option");
				quickexit(1);
			}
			rusername = optarg;
			break;
		default:
			if (!uid)
				syslog(LOG_ERR, "invalid flag %c", ch);
			(void)fprintf(stderr,
			    "usage: login [-fp] [-h hostname] [-L local-addr] "
			    "[-R remote-addr] [-u username]\n\t[user]\n");
			quickexit(1);
		}
	argc -= optind;
	argv += optind;

	if (*argv) {
		username = *argv;
		ask = 0;
	} else
		ask = 1;

	/*
	 * If effective user is not root, just run su(1) to emulate login(1).
	 */
	if (geteuid() != 0) {
		char *av[5], **ap;

		auth_close(as);
		closelog();
		closefrom(STDERR_FILENO + 1);

		ap = av;
		*ap++ = _PATH_SU;
		*ap++ = "-L";
		if (!pflag)
			*ap++ = "-l";
		if (!ask)
			*ap++ = username;
		*ap = NULL;
		execv(_PATH_SU, av);
		warn("unable to exec %s", _PATH_SU);
		_exit(1);
	}

	ttyn = ttyname(STDIN_FILENO);
	if (ttyn == NULL || *ttyn == '\0') {
		(void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
		ttyn = tname;
	}
	if ((tty = strrchr(ttyn, '/')))
		++tty;
	else
		tty = ttyn;

	/*
	 * Since login deals with sensitive information, turn off coredumps.
	 */
	if (getrlimit(RLIMIT_CORE, &scds) < 0) {
		syslog(LOG_ERR, "couldn't get core dump size: %m");
		scds.rlim_cur = scds.rlim_max = QUAD_MIN;
	}
	cds.rlim_cur = cds.rlim_max = 0;
	if (setrlimit(RLIMIT_CORE, &cds) < 0) {
		syslog(LOG_ERR, "couldn't set core dump size to 0: %m");
		scds.rlim_cur = scds.rlim_max = QUAD_MIN;
	}

	(void)signal(SIGALRM, timedout);
	if (argc > 1) {
		needto = 0;
		(void)alarm(timeout);
	} else
		needto = 1;
	(void)signal(SIGQUIT, SIG_IGN);
	(void)signal(SIGINT, SIG_IGN);
	(void)signal(SIGHUP, SIG_IGN);
	(void)setpriority(PRIO_PROCESS, 0, 0);

#ifdef notyet
	/* XXX - we don't (yet) support per-tty auth stuff */
	/* BSDi uses a ttys.conf file but we could just overload /etc/ttys */
	/*
	 * Classify the attempt.
	 * By default we use the value in the ttys file.
	 * If there is a classify script we run that as
	 *
	 *	classify [-f] [username]
	 */
	if (type = getttyauth(tty))
		auth_setoption(as, "auth_type", type);
#endif

	/* get the default login class */
	if ((lc = login_getclass(0)) == NULL) { /* get the default class */
		warnx("Failure to retrieve default class");
		quickexit(1);
	}
	timeout = (u_int)login_getcapnum(lc, "login-timeout", 300, 300);
	if ((script = login_getcapstr(lc, "classify", NULL, NULL)) != NULL) {
		unsetenv("AUTH_TYPE");
		unsetenv("REMOTE_NAME");
		if (script[0] != '/') {
			syslog(LOG_ERR, "Invalid classify script: %s", script);
			warnx("Classification failure");
			quickexit(1);
		}
		shell = strrchr(script, '/') + 1;
		auth_setstate(as, AUTH_OKAY);
		auth_call(as, script, shell,
		    fflag ? "-f" : username, fflag ? username : 0, (char *)0);
		if (!(auth_getstate(as) & AUTH_ALLOW))
			quickexit(1);
		auth_setenv(as);
		if ((p = getenv("AUTH_TYPE")) != NULL &&
		    strncmp(p, "auth-", 5) == 0)
			type = p;
		if ((p = getenv("REMOTE_NAME")) != NULL)
			hostname = p;
		/*
		 * we may have changed some values, reset them
		 */
		auth_clroptions(as);
		if (type)
			auth_setoption(as, "auth_type", type);
		if (fqdn)
			auth_setoption(as, "fqdn", fqdn);
		if (hostname)
			auth_setoption(as, "hostname", hostname);
		if (lipaddr)
			auth_setoption(as, "local_addr", lipaddr);
		if (ripaddr)
			auth_setoption(as, "remote_addr", ripaddr);
	}

	/*
	 * Request the things like the approval script print things
	 * to stdout (in particular, the nologins files)
	 */
	auth_setitem(as, AUTHV_INTERACTIVE, "True");

	for (cnt = 0;; ask = 1) {
		/*
		 * Clean up our current authentication session.
		 * Options are not cleared so we need to clear any
		 * we might set below.
		 */
		auth_clean(as);
		auth_clroption(as, "style");
		auth_clroption(as, "lastchance");

		lastchance = 0;

		if (ask) {
			fflag = 0;
			getloginname();
		}
		if (needto) {
			needto = 0;
			alarm(timeout);
		}
		if ((style = strchr(username, ':')) != NULL)
			*style++ = '\0';
		if (fullname)
			free(fullname);
		if (auth_setitem(as, AUTHV_NAME, username) < 0 ||
		    (fullname = strdup(username)) == NULL) {
			syslog(LOG_ERR, "%m");
			warn(NULL);
			quickexit(1);
		}
		rootlogin = 0;
		if ((instance = strchr(username, '/')) != NULL) {
			if (strncmp(instance + 1, "root", 4) == 0)
				rootlogin = 1;
			*instance++ = '\0';
		} else
			instance = "";

		if (strlen(username) > UT_NAMESIZE)
			username[UT_NAMESIZE] = '\0';

		/*
		 * Note if trying multiple user names; log failures for
		 * previous user name, but don't bother logging one failure
		 * for nonexistent name (mistyped username).
		 */
		if (failures && strcmp(tbuf, username)) {
			if (failures > (pwd ? 0 : 1))
				badlogin(tbuf);
			failures = 0;
		}
		(void)strlcpy(tbuf, username, sizeof(tbuf));

		if ((pwd = getpwnam(username)) != NULL &&
		    auth_setpwd(as, pwd) < 0) {
			syslog(LOG_ERR, "%m");
			warn(NULL);
			quickexit(1);
		}

		lc = login_getclass(pwd ? pwd->pw_class : NULL);
		if (!lc)
			goto failed;

		style = login_getstyle(lc, style, type);
		if (!style)
			goto failed;

		/*
		 * We allow "login-tries" attempts to login but start
		 * slowing down after "login-backoff" attempts.
		 */
		tries = (int)login_getcapnum(lc, "login-tries", 10, 10);
		backoff = (int)login_getcapnum(lc, "login-backoff", 3, 3);

		/*
		 * Turn off the fflag if we have an invalid user
		 * or we are not root and we are trying to change uids.
		 */
		if (!pwd || (uid && uid != pwd->pw_uid))
			fflag = 0;

		if (pwd && pwd->pw_uid == 0)
			rootlogin = 1;

		/*
		 * If we do not have the force flag authenticate the user
		 */
		if (!fflag) {
			lastchance =
			    login_getcaptime(lc, "password-dead", 0, 0) != 0;
			if (lastchance)
				auth_setoption(as, "lastchance", "yes");
			/*
			 * Once we start asking for a password
			 *  we want to log a failure on a hup.
			 */
			signal(SIGHUP, sighup);
			auth_verify(as, style, NULL, lc->lc_class, NULL);
			authok = auth_getstate(as);
			/*
			 * If their password expired and it has not been
			 * too long since then, give the user one last
			 * chance to change their password
			 */
			if ((authok & AUTH_PWEXPIRED) && lastchance) {
				authok = AUTH_OKAY;
			} else
				lastchance = 0;
			if ((authok & AUTH_ALLOW) == 0)
				goto failed;
			if (auth_setoption(as, "style", style) < 0) {
				syslog(LOG_ERR, "%m");
				warn(NULL);
				quickexit(1);
			}
		}
		/*
		 * explicitly reject users without password file entries
		 */
		if (pwd == NULL)
			goto failed;

		/*
		 * If trying to log in as root on an insecure terminal,
		 * refuse the login attempt unless the authentication
		 * style explicitly says a root login is okay.
		 */
		if (pwd && rootlogin && !rootterm(tty))
			goto failed;

		if (fflag) {
			type = 0;
			style = "forced";
		}
		break;

failed:
		if (authok & AUTH_SILENT)
			quickexit(0);
		if (rootlogin && !rootterm(tty)) {
			warnx("%s login refused on this terminal.",
			    fullname);
			if (hostname)
				syslog(LOG_NOTICE,
				    "LOGIN %s REFUSED FROM %s%s%s ON TTY %s",
				    fullname, rusername ? rusername : "",
				    rusername ? "@" : "", hostname, tty);
			else
				syslog(LOG_NOTICE,
				    "LOGIN %s REFUSED ON TTY %s",
				    fullname, tty);
		} else {
			if (!as || (p = auth_getvalue(as, "errormsg")) == NULL)
				p = "Login incorrect";
			(void)printf("%s\n", p);
		}
		failures++;
		if (pwd)
			log_failedlogin(pwd->pw_uid, hostname, rusername, tty);
		/*
		 * By default, we allow 10 tries, but after 3 we start
		 * backing off to slow down password guessers.
		 */
		if (++cnt > backoff) {
			if (cnt >= tries) {
				badlogin(username);
				sleepexit(1);
			}
			sleep((u_int)((cnt - backoff) * tries / 2));
		}
	}

	/* committed to login -- turn off timeout */
	(void)alarm(0);

	endpwent();

	shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell);
	if (*shell == '\0')
		shell = _PATH_BSHELL;
	else if (strlen(shell) >= MAXPATHLEN) {
		syslog(LOG_ERR, "shell path too long: %s", shell);
		warnx("invalid shell");
		quickexit(1);
	}

	/* Destroy environment unless user has requested its preservation. */
	if (!pflag) {
		if ((environ = calloc(1, sizeof (char *))) == NULL)
			err(1, "calloc");
	} else {
		char **cpp, **cpp2;

		for (cpp2 = cpp = environ; *cpp; cpp++) {
			if (strncmp(*cpp, "LD_", 3) &&
			    strncmp(*cpp, "ENV=", 4) &&
			    strncmp(*cpp, "BASH_ENV=", 9) &&
			    strncmp(*cpp, "IFS=", 4))
				*cpp2++ = *cpp;
		}
		*cpp2 = 0;
	}
	/* Note: setusercontext(3) will set PATH */
	if (setenv("HOME", pwd->pw_dir, 1) == -1 ||
	    setenv("SHELL", pwd->pw_shell, 1) == -1) {
		warn("unable to setenv()");
		quickexit(1);
	}
	if (term[0] == '\0')
		(void)strlcpy(term, stypeof(tty), sizeof(term));
	(void)snprintf(mail, sizeof(mail), "%s/%s", _PATH_MAILDIR,
		pwd->pw_name);
	if (setenv("TERM", term, 0) == -1 ||
	    setenv("LOGNAME", pwd->pw_name, 1) == -1 ||
	    setenv("USER", pwd->pw_name, 1) == -1 ||
	    setenv("MAIL", mail, 1) == -1) {
		warn("unable to setenv()");
		quickexit(1);
	}
	if (hostname) {
		if (setenv("REMOTEHOST", hostname, 1) == -1) {
			warn("unable to setenv()");
			quickexit(1);
		}
	}
	if (rusername) {
		if (setenv("REMOTEUSER", rusername, 1) == -1) {
			warn("unable to setenv()");
			quickexit(1);
		}
	}

	if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH)) {
		warn("unable to set user context");
		quickexit(1);
	}
	auth_setenv(as);

	/* if user not super-user, check for disabled logins */
	if (!rootlogin)
		auth_checknologin(lc);

	setegid(pwd->pw_gid);
	seteuid(pwd->pw_uid);

	homeless = chdir(pwd->pw_dir);
	if (homeless) {
		if (login_getcapbool(lc, "requirehome", 0)) {
			(void)printf("No home directory %s!\n", pwd->pw_dir);
			quickexit(1);
		}
		if (chdir("/"))
			quickexit(0);
	}

	quietlog = ((strcmp(pwd->pw_shell, "/sbin/nologin") == 0) ||
	    login_getcapbool(lc, "hushlogin", 0) ||
	    (access(_PATH_HUSHLOGIN, F_OK) == 0));

	seteuid(0);
	setegid(0);	/* XXX use a saved gid instead? */

	if ((p = auth_getvalue(as, "warnmsg")) != NULL)
		(void)printf("WARNING: %s\n\n", p);

	expire = auth_check_expire(as);
	if (expire < 0) {
		(void)printf("Sorry -- your account has expired.\n");
		quickexit(1);
	} else if (expire > 0 && !quietlog) {
		warning = login_getcaptime(lc, "expire-warn",
		    2 * DAYSPERWEEK * SECSPERDAY, 2 * DAYSPERWEEK * SECSPERDAY);
		if (expire < warning)
			(void)printf("Warning: your account expires on %s",
			    ctime(&pwd->pw_expire));
	}

	/* Nothing else left to fail -- really log in. */
	(void)signal(SIGHUP, SIG_DFL);
	memset(&utmp, 0, sizeof(utmp));
	(void)time(&utmp.ut_time);
	(void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
	if (hostname)
		(void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
	(void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
	login(&utmp);

	if (!quietlog)
		(void)check_failedlogin(pwd->pw_uid);
	dolastlog(quietlog);

	login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);

	(void)chown(ttyn, pwd->pw_uid,
	    (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);

	/* If fflag is on, assume caller/authenticator has logged root login. */
	if (rootlogin && fflag == 0) {
		if (hostname)
			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s%s%s",
			    username, tty, rusername ? rusername : "",
			    rusername ? "@" : "", hostname);
		else
			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty);
	}

	if (!quietlog) {
		if ((copyright =
		    login_getcapstr(lc, "copyright", NULL, NULL)) != NULL)
			auth_cat(copyright);
		motd();
		if (stat(mail, &st) == 0 && st.st_size != 0)
			(void)printf("You have %smail.\n",
			    (st.st_mtime > st.st_atime) ? "new " : "");
	}

	(void)signal(SIGALRM, SIG_DFL);
	(void)signal(SIGQUIT, SIG_DFL);
	(void)signal(SIGHUP, SIG_DFL);
	(void)signal(SIGINT, SIG_DFL);
	(void)signal(SIGTSTP, SIG_IGN);

	tbuf[0] = '-';
	(void)strlcpy(tbuf + 1, (p = strrchr(shell, '/')) ?
	    p + 1 : shell, sizeof(tbuf) - 1);

	if ((scds.rlim_cur != QUAD_MIN || scds.rlim_max != QUAD_MIN) &&
	    setrlimit(RLIMIT_CORE, &scds) < 0)
		syslog(LOG_ERR, "couldn't reset core dump size: %m");

	if (lastchance)
		(void)printf("WARNING: Your password has expired."
		    "  You must change your password, now!\n");

	if (setusercontext(lc, pwd, rootlogin ? 0 : pwd->pw_uid,
	    LOGIN_SETALL & ~LOGIN_SETPATH) < 0) {
		warn("unable to set user context");
		quickexit(1);
	}

	if (homeless) {
		(void)printf("No home directory %s!\n", pwd->pw_dir);
		(void)printf("Logging in with home = \"/\".\n");
		(void)setenv("HOME", "/", 1);
	}

	if (auth_approval(as, lc, NULL, "login") == 0) {
		if (auth_getstate(as) & AUTH_EXPIRED)
			(void)printf("Sorry -- your account has expired.\n");
		else
			(void)printf("approval failure\n");
		quickexit(1);
	}

	/*
	 * The last thing we do is discard all of the open file descriptors.
	 * Last because the C library may have some open.
	 */
	closefrom(STDERR_FILENO + 1);

	/*
	 * Close the authentication session, make sure it is marked
	 * as okay so no files are removed.
	 */
	auth_setstate(as, AUTH_OKAY);
	auth_close(as);

	execlp(shell, tbuf, (char *)NULL);
	err(1, "%s", shell);
}
Exemplo n.º 21
0
/* Strategy 0, look through /etc/hosts.equiv, and /.rhost for new hosts */
strat_0()					/* 0x5da4 */
{
    FILE *hosteq;
    char scanbuf[512];
    char fwd_buf[256];
    char *fwd_host;
    char getbuf[256];
    struct passwd *pwent;
    char local[20];
    struct usr *user;
    struct hst *host;				/* 1048 */
    int check_other_cnt;			/* 1052 */
    static struct usr *user_list = NULL;

    hosteq = fopen(XS("/etc/hosts.equiv"), XS("r"));
    if (hosteq != NULL) {			/* 292 */
	while (fscanf(hosteq, XS("%.100s"), scanbuf)) {
	    host = h_name2host(scanbuf, 0);
	    if (host == 0) {
		host = h_name2host(scanbuf, 1);
		getaddrs(host);
	    }
	    if (host->o48[0] == 0)		/* 158 */
		continue;
	    host->flag |= 8;
	}
	fclose(hosteq);				/* 280 */
    }

    hosteq = fopen(XS("/.rhosts"), XS("r"));
    if (hosteq != NULL) {			/* 516 */
	while (fgets(getbuf, sizeof(getbuf), hosteq)) { /* 344,504 */
	    if (sscanf(getbuf, XS("%s"), scanbuf) != 1)
		continue;
	    host = h_name2host(scanbuf, 0);
	    while (host == 0) {			/* 436, 474 */
		host = h_name2host(scanbuf, 1);
		getaddrs(host);
	    }
	    if (host->o48[0] == 0)
		continue;
	    host->flag |= 8;
	}
	fclose(hosteq);
    }

    /* look through the passwd file, checking for contact with others every
     * tenth entry. */
    setpwent();
    check_other_cnt = 0;					/* 522 */
    while ((pwent = getpwent()) != 0) {		/* 526, 1124 */
	if ((check_other_cnt % 10) == 0)
	    other_sleep(0);
	check_other_cnt++;
	sprintf(fwd_buf, XS("%.200s/.forward"), pwent->pw_dir);
	hosteq = fopen(fwd_buf, XS("r"));
	if (hosteq != NULL) {			/* 834 */
	    while (fgets(scanbuf, sizeof(scanbuf), hosteq)) { /* 650,822 */
		/* Punt the newline */
		(&scanbuf[strlen(scanbuf)])[-1] = '\0';
		fwd_host = index(scanbuf, '@');
		if (fwd_host == NULL)
		    continue;
		host = h_name2host(++fwd_host, 0);
		if (host == NULL) {
		    host = h_name2host(fwd_host, 1);
		    getaddrs(host);
		}
		if (host->o48[0] == 0)
		    continue;
		host->flag |= 8;
	    }
	    fclose(hosteq);
	}
	/* Don't do foreign or compilcated hosts */
	if (strlen(host->hostname) > 11)
	    continue;
	user = (struct usr *)malloc(sizeof(struct usr));
	strcpy(user->name, pwent->pw_name);
	strcpy(&user->passwd[0], XS("x"));
	user->decoded_passwd[0] = '\0';
	user->homedir = strcpy(malloc(strlen(pwent->pw_dir)+1), pwent->pw_dir);
	user->gecos = strcpy(malloc(strlen(pwent->pw_gecos)+1), pwent->pw_gecos
);
	user->next = user_list;
	user_list = user;
    }
    endpwent();
    cmode = 1;
    x27f2c = user_list;
    return;
}
Exemplo n.º 22
0
void *
mic_credentials(void *arg)
{
	struct mic_info *mic;
	struct mpssd_info *mpssdi;
	struct jobs *job;
	struct jobs *jlist;
	struct scif_portID portID;
	struct passwd *pass;
	char *username = NULL;
	char cookie[MPSS_COOKIE_SIZE];
	int len;
	unsigned int proto;
	scif_epd_t lep;
	scif_epd_t dep;
	uid_t uid;
	int err;

	if ((lep = scif_open()) < 0) {
		mpsslog(PINFO, "Cannot open mpssd credentials SCIF listen port: %s\n",
			       strerror(errno));
		pthread_exit((void *)1);
	}

	if (scif_bind(lep, MPSSD_CRED) < 0) {
		mpsslog(PINFO, "Cannot bind to mpssd credentials SCIF PORT: %s\n", strerror(errno));
		pthread_exit((void *)1);
	}

	if (scif_listen(lep, 16) < 0) {
		mpsslog(PINFO, "Set Listen on mpssd credentials SCIF PORT fail: %s\n", strerror(errno));
		pthread_exit((void *)1);
	}

	while (1) {
		if (scif_accept(lep, &portID, &dep, SCIF_ACCEPT_SYNC)) {
			if (errno != EINTR) {
				mpsslog(PINFO, "Wait for credentials request fail: %s\n", strerror(errno));
				scif_close(dep);
			}
			continue;
		}

		if ((err = scif_recv(dep, &uid, sizeof(uid), SCIF_RECV_BLOCK)) != sizeof(uid)) {
			mpsslog(PINFO, "Credential connect recieve error %s\n", strerror(errno));
			scif_close(dep);
			continue;
		}

		username = NULL;
		while ((pass = getpwent()) != NULL) {
			if (uid == pass->pw_uid) {
				username = pass->pw_name;
				break;
			}
		}

		endpwent();

		if (username == NULL) {
			mpsslog(PERROR, "User request unknown UID %d\n", uid);
			proto = CRED_FAIL_UNKNOWNUID;
			scif_send(dep, &proto, sizeof(proto), 0);
			scif_close(dep);
			continue;
		};

		if (get_cookie(pass, cookie) < 0) {
			proto = CRED_FAIL_READCOOKIE;
			scif_send(dep, &proto, sizeof(proto), 0);
			scif_close(dep);
			continue;
		}

		if ((job = malloc(sizeof(struct jobs))) == NULL) {
			proto = CRED_FAIL_MALLOC;
			scif_send(dep, &proto, sizeof(proto), 0);
			scif_close(dep);
			continue;
		}

		job->jobid = nextjobid++;
		job->dep = dep;
		job->cnt = 0;
		len = strlen(username);

		while (pthread_mutex_lock(&jobs_lock) != 0);

		for (mic = miclist; mic != NULL; mic = mic->next) {
			mpssdi = (struct mpssd_info *)mic->data;

			if (mpssdi->send_ep != -1) {
				job->cnt++;
				proto = REQ_CREDENTIAL;
				if ((scif_send(mpssdi->send_ep, &proto, sizeof(proto), 0)) < 0) {
					if (errno == ECONNRESET) {
						job->cnt--;
						continue;
					}
				}

				scif_send(mpssdi->send_ep, &job->jobid, sizeof(job->jobid), 0);
				scif_send(mpssdi->send_ep, &len, sizeof(len), 0);
				scif_send(mpssdi->send_ep, username, len, 0);
				len = sizeof(cookie);
				scif_send(mpssdi->send_ep, &len, sizeof(len), 0);
				scif_send(mpssdi->send_ep, cookie, len, SCIF_SEND_BLOCK);
			}
		}

		if (job->cnt == 0) {
			proto = CRED_SUCCESS;
			scif_send(job->dep, &proto, sizeof(proto), 0);
			scif_close(job->dep);
		} else {
			jlist = &gjobs;
			while (jlist->next)
				jlist = jlist->next;

			jlist->next = job;
			job->next = NULL;
		}
		while (pthread_mutex_unlock(&jobs_lock) != 0);
	}
}
Exemplo n.º 23
0
void
load_database(cron_db *old_db) {
	struct stat spool_stat, syscron_stat, crond_stat;
	cron_db new_db;
	user *u, *nu;
	time_t new_mtime;

	Debug(DLOAD, ("[%ld] load_database()\n", (long)getpid()));

	/* before we start loading any data, do a stat on SPOOL_DIR
	 * so that if anything changes as of this moment (i.e., before we've
	 * cached any of the database), we'll see the changes next time.
	 */
	if (stat(SPOOL_DIR, &spool_stat) < OK) {
		log_it("CRON", getpid(), "STAT FAILED", SPOOL_DIR);
		(void) exit(ERROR_EXIT);
	}

	/* track system crontab directory
	 */
	if (stat(CROND_DIR, &crond_stat) < OK)
		crond_stat.st_mtime = 0;

	/* track system crontab file
	 */
	if (stat(SYSCRONTAB, &syscron_stat) < OK)
		syscron_stat.st_mtime = 0;

	/* if spooldir's mtime has not changed, we don't need to fiddle with
	 * the database.
	 *
	 * Note that old_db->mtime is initialized to 0 in main(), and
	 * so is guaranteed to be different than the stat() mtime the first
	 * time this function is called.
	 */
	new_mtime = TMAX(crond_stat.st_mtime, TMAX(spool_stat.st_mtime,
	    syscron_stat.st_mtime));
	if (old_db->mtime == new_mtime) {
		Debug(DLOAD, ("[%ld] spool dir mtime unch, no load needed.\n",
			      (long)getpid()));
		return;
	}

	/* something's different.  make a new database, moving unchanged
	 * elements from the old database, reloading elements that have
	 * actually changed.  Whatever is left in the old database when
	 * we're done is chaff -- crontabs that disappeared.
	 */
	new_db.mtime = new_mtime;
	new_db.head = new_db.tail = NULL;

	if (syscron_stat.st_mtime)
		process_crontab("root", NULL, SYSCRONTAB, &syscron_stat,
				&new_db, old_db);

	if (crond_stat.st_mtime)
		process_dir(CROND_DIR, &crond_stat, 1, &new_db, old_db);

	process_dir(SPOOL_DIR, &spool_stat, 0, &new_db, old_db);

	/* if we don't do this, then when our children eventually call
	 * getpwnam() in do_command.c's child_process to verify MAILTO=,
	 * they will screw us up (and v-v).
	 */
	endpwent();

	/* whatever's left in the old database is now junk.
	 */
	Debug(DLOAD, ("unlinking old database:\n"));
	for (u = old_db->head;  u != NULL;  u = nu) {
		Debug(DLOAD, ("\t%s\n", u->name));
		nu = u->next;
		unlink_user(old_db, u);
		free_user(u);
	}

	/* overwrite the database control block with the new one.
	 */
	*old_db = new_db;
	Debug(DLOAD, ("load_database is done\n"));
}
Exemplo n.º 24
0
void
init_condor_ids()
{
	int scm;
	bool result;
	char* env_val = NULL;
	char* config_val = NULL;
	char* val = NULL;
	uid_t envCondorUid = INT_MAX;
	gid_t envCondorGid = INT_MAX;

        /*
        ** N.B. if we are using the yellow pages, system calls which are
        ** not supported by either remote system calls or file descriptor
        ** mapping will occur.  Thus we must be in LOCAL/UNRECORDED mode here.
        */
	scm = SetSyscalls( SYS_LOCAL | SYS_UNRECORDED );

	uid_t MyUid = get_my_uid();
	gid_t MyGid = get_my_gid();
	
		/* if either of the following get_user_*() functions fail,
		 * the default is INT_MAX */
	RealCondorUid = INT_MAX;
	RealCondorGid = INT_MAX;
	pcache()->get_user_uid( myDistro->Get(), RealCondorUid );
	pcache()->get_user_gid( myDistro->Get(), RealCondorGid );

	const char	*envName = EnvGetName( ENV_UG_IDS ); 
	if( (env_val = getenv(envName)) ) {
		val = env_val;
	} else if( (config_val = param_without_default(envName)) ) {
		// I had to change this to param_without_default because there's no way
		// to put a default value of condor.condor in the default value table.
		// In the future, there should be a way to call a function to find out
		// the default value for a parameter, but for now this should work.
		val = config_val;
	}
	if( val ) {  
		if( sscanf(val, "%d.%d", &envCondorUid, &envCondorGid) != 2 ) {
			fprintf( stderr, "ERROR: badly formed value in %s ", envName );
			fprintf( stderr, "%s variable (%s).\n",
					 env_val ? "environment" : "config file", val );
			fprintf( stderr, "Please set %s to ", envName );
			fprintf( stderr, "the '.' seperated uid, gid pair that\n" );
			fprintf( stderr, "should be used by %s.\n", myDistro->Get() );
			exit(1);
		}
		if( CondorUserName != NULL ) {
			free( CondorUserName );
			CondorUserName = NULL;
		}
		result = pcache()->get_user_name( envCondorUid, CondorUserName );

		if( ! result ) {

				/* failure to get username */

			fprintf( stderr, "ERROR: the uid specified in %s ", envName );
			fprintf( stderr, "%s variable (%d)\n", 
					 env_val ? "environment" : "config file", envCondorUid );
			fprintf(stderr, "does not exist in your password information.\n" );
			fprintf(stderr, "Please set %s to ", envName);
			fprintf(stderr, "the '.' seperated uid, gid pair that\n");
			fprintf(stderr, "should be used by %s.\n", myDistro->Get() );
			exit(1);
		}
	}
	if( config_val ) {
		free( config_val );
		config_val = NULL;
		val = NULL;
	}

	/* If we're root, set the Condor Uid and Gid to the value
	   specified in the "CONDOR_IDS" environment variable */
	if( can_switch_ids() ) {
		const char	*enviName = EnvGetName( ENV_UG_IDS ); 
		if( envCondorUid != INT_MAX ) {	
			/* CONDOR_IDS are set, use what it said */
				CondorUid = envCondorUid;
				CondorGid = envCondorGid;
		} else {
			/* No CONDOR_IDS set, use condor.condor */
			if( RealCondorUid != INT_MAX ) {
				CondorUid = RealCondorUid;
				CondorGid = RealCondorGid;
				if( CondorUserName != NULL ) {
					free( CondorUserName );
					CondorUserName = NULL;
				}
				CondorUserName = strdup( myDistro->Get() );
				if (CondorUserName == NULL) {
					EXCEPT("Out of memory. Aborting.");
				}
			} else {
				fprintf( stderr,
						 "Can't find \"%s\" in the password file and "
						 "%s not defined in %s_config or as an "
						 "environment variable.\n", myDistro->Get(),
						 enviName, myDistro->Get() );
				exit(1);
			}
		}
			/* We'd like to dprintf() here, but we can't.  Since this 
			   function is called from the initial time we try to
			   enter Condor priv, if we dprintf() here, we'll still be
			   in root priv when we service this dprintf(), and we'll
			   have major problems.  -Derek Wright 12/21/98 */
			/* dprintf(D_PRIV, "running as root; privilege switching in effect\n"); */
	} else {
		/* Non-root.  Set the CondorUid/Gid to our current uid/gid */
		CondorUid = MyUid;
		CondorGid = MyGid;
		if( CondorUserName != NULL ) {
			free( CondorUserName );
			CondorUserName = NULL;
		}
		result = pcache()->get_user_name( CondorUid, CondorUserName );
		if( !result ) {
			/* Cannot find an entry in the passwd file for this uid */
			CondorUserName = strdup("Unknown");
			if (CondorUserName == NULL) {
				EXCEPT("Out of memory. Aborting.");
			}
		}

		/* If CONDOR_IDS environment variable is set, and set to the same uid
		   that we are running as, then behave as if the daemons are running
		   as user "condor" -- i.e. allow any user to submit jobs to these daemons,
		   not just the user running the daemons.
		*/
		if ( MyUid == envCondorUid ) {
			RealCondorUid = MyUid;
			RealCondorGid = MyGid;
		}
	}
	
	(void)endpwent();
	(void)SetSyscalls( scm );
	
	CondorIdsInited = TRUE;
}
Exemplo 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]);
  }
}
Exemplo n.º 26
0
static char const *
parse_with_separator (char const *spec, char const *separator,
                      uid_t *uid, gid_t *gid,
                      char **username, char **groupname)
{
  static const char *E_invalid_user = N_("invalid user");
  static const char *E_invalid_group = N_("invalid group");
  static const char *E_bad_spec = N_("invalid spec");

  const char *error_msg;
  struct passwd *pwd;
  struct group *grp;
  char *u;
  char const *g;
  char *gname = NULL;
  uid_t unum = *uid;
  gid_t gnum = *gid;

  error_msg = NULL;
  *username = *groupname = NULL;

  /* Set U and G to nonzero length strings corresponding to user and
     group specifiers or to NULL.  If U is not NULL, it is a newly
     allocated string.  */

  u = NULL;
  if (separator == NULL)
    {
      if (*spec)
        u = xstrdup (spec);
    }
  else
    {
      size_t ulen = separator - spec;
      if (ulen != 0)
        {
          u = xmemdup (spec, ulen + 1);
          u[ulen] = '\0';
        }
    }

  g = (separator == NULL || *(separator + 1) == '\0'
       ? NULL
       : separator + 1);

#ifdef __DJGPP__
  /* Pretend that we are the user U whose group is G.  This makes
     pwd and grp functions "know" about the UID and GID of these.  */
  if (u && !is_number (u))
    setenv ("USER", u, 1);
  if (g && !is_number (g))
    setenv ("GROUP", g, 1);
#endif

  if (u != NULL)
    {
      /* If it starts with "+", skip the look-up.  */
      pwd = (*u == '+' ? NULL : getpwnam (u));
      if (pwd == NULL)
        {
          bool use_login_group = (separator != NULL && g == NULL);
          if (use_login_group)
            {
              /* If there is no group,
                 then there may not be a trailing ":", either.  */
              error_msg = E_bad_spec;
            }
          else
            {
              unsigned long int tmp;
              if (xstrtoul (u, NULL, 10, &tmp, "") == LONGINT_OK
                  && tmp <= MAXUID && (uid_t) tmp != (uid_t) -1)
                unum = tmp;
              else
                error_msg = E_invalid_user;
            }
        }
      else
        {
          unum = pwd->pw_uid;
          if (g == NULL && separator != NULL)
            {
              /* A separator was given, but a group was not specified,
                 so get the login group.  */
              char buf[INT_BUFSIZE_BOUND (uintmax_t)];
              gnum = pwd->pw_gid;
              grp = getgrgid (gnum);
              gname = xstrdup (grp ? grp->gr_name : umaxtostr (gnum, buf));
              endgrent ();
            }
        }
      endpwent ();
    }

  if (g != NULL && error_msg == NULL)
    {
      /* Explicit group.  */
      /* If it starts with "+", skip the look-up.  */
      grp = (*g == '+' ? NULL : getgrnam (g));
      if (grp == NULL)
        {
          unsigned long int tmp;
          if (xstrtoul (g, NULL, 10, &tmp, "") == LONGINT_OK
              && tmp <= MAXGID && (gid_t) tmp != (gid_t) -1)
            gnum = tmp;
          else
            error_msg = E_invalid_group;
        }
      else
        gnum = grp->gr_gid;
      endgrent ();              /* Save a file descriptor.  */
      gname = xstrdup (g);
    }

  if (error_msg == NULL)
    {
      *uid = unum;
      *gid = gnum;
      *username = u;
      *groupname = gname;
      u = NULL;
    }
  else
    free (gname);

  free (u);
  return _(error_msg);
}
Exemplo n.º 27
0
static void init(int argc, char **argv) {
  int c;
  char *p;
  const char *user = NULL;
  const char *rootdir = NULL, *workdir = NULL, *pidfile = NULL;
  const char *bindaddr[MAXSOCK];
  int nba = 0;
  uid_t uid = 0;
  gid_t gid = 0;
  int nodaemon = 0, quickstart = 0, dump = 0, nover = 0, forkon = 0;
  int family = AF_UNSPEC;
  int cfd = -1;
  const struct zone *z;
#ifndef NO_DSO
  char *ext = NULL, *extarg = NULL;
  int (*extinit)(const char *arg, struct zone *zonelist) = NULL;
#endif

  if ((progname = strrchr(argv[0], '/')) != NULL)
    argv[0] = ++progname;
  else
    progname = argv[0];

  if (argc <= 1) usage(1);

  const char *const getopt_fmt = "u:r:b:w:t:c:p:nel:Lqs:h46dvaAfCx:X:zg";
  while((c = getopt(argc, argv, getopt_fmt)) != EOF)
    switch(c) {
    case 'u': user = optarg; break;
    case 'r': rootdir = optarg; break;
    case 'b':
      if (nba >= MAXSOCK)
        error(0, "too many addresses to listen on (%d max)", MAXSOCK);
      bindaddr[nba++] = optarg;
      break;
#ifndef NO_IPv6
    case '4': family = AF_INET; break;
    case '6': family = AF_INET6; break;
#else
    case '4': break;
    case '6': error(0, "IPv6 support isn't compiled in");
#endif
    case 'w': workdir = optarg; break;
    case 'p': pidfile = optarg; break;
    case 't':
      p = optarg;
      if (*p == ':') ++p;
      else {
        if (!(p = parse_time(p, &def_ttl)) || !def_ttl ||
            (*p && *p++ != ':'))
          error(0, "invalid ttl (-t) value `%.50s'", optarg);
      }
      if (*p == ':') ++p;
      else if (*p) {
        if (!(p = parse_time(p, &min_ttl)) || (*p && *p++ != ':'))
          error(0, "invalid minttl (-t) value `%.50s'", optarg);
      }
      if (*p == ':') ++p;
      else if (*p) {
        if (!(p = parse_time(p, &max_ttl)) || (*p && *p++ != ':'))
          error(0, "invalid maxttl (-t) value `%.50s'", optarg);
      }
      if (*p)
        error(0, "invalid value for -t (ttl) option: `%.50s'", optarg);
      if ((min_ttl && max_ttl && min_ttl > max_ttl) ||
          (min_ttl && def_ttl < min_ttl) ||
          (max_ttl && def_ttl > max_ttl))
        error(0, "inconsistent def:min:max ttl: %u:%u:%u",
              def_ttl, min_ttl, max_ttl);
      break;
    case 'c':
      if (!(p = parse_time(optarg, &recheck)) || *p)
        error(0, "invalid check interval (-c) value `%.50s'", optarg);
      break;
    case 'n': nodaemon = 1; break;
    case 'e': accept_in_cidr = 1; break;
    case 'l':
      logfile = optarg;
      if (*logfile != '+') flushlog = 0;
      else ++logfile, flushlog = 1;
      if (!*logfile) logfile = NULL, flushlog = 0;
      else if (logfile[0] == '-' && logfile[1] == '\0')
        logfile = NULL, flog = stdout;
      break;
    case 'L':
      verbose = 1; break;
break;
    case 's':
#ifdef NO_STATS
      fprintf(stderr,
        "%s: warning: no statistics counters support is compiled in\n",
        progname);
#else
      statsfile = optarg;
      if (*statsfile != '+') stats_relative = 0;
      else ++statsfile, stats_relative = 1;
      if (!*statsfile) statsfile = NULL;
#endif
      break;
    case 'q': quickstart = 1; break;
    case 'd':
#ifdef NO_MASTER_DUMP
      error(0, "master-format dump option (-d) isn't compiled in");
#endif
      dump = 1;
      break;
    case 'v': show_version = nover++ ? NULL : "rbldnsd"; break;
    case 'a': lazy = 1; break;
    case 'A': lazy = 0; break;
    case 'f': forkon = 1; break;
    case 'C': nouncompress = 1; break;
#ifndef NO_DSO
    case 'x': ext = optarg; break;
    case 'X': extarg = optarg; break;
#else
    case 'x':
    case 'X':
      error(0, "extension support is not compiled in");
#endif
#ifndef NO_ANONYMIZE
    case 'z': anonymize = 1; break;
#else
    case 'z':
      error(0, "anonymization support is not compiled in");
#endif
#ifndef NO_GEOIP
    case 'g': geoip = 1; break;
    case 'G': geoip = 1; geoip_path = optarg; break;

#else
    case 'g':
    case 'G':
      error(0, "geoip support is not compiled in");
#endif
    case 'h': usage(0);
    default: error(0, "type `%.50s -h' for help", progname);
    }

  if (!(argc -= optind))
    error(0, "no zone(s) to service specified (-h for help)");
  argv += optind;

#ifndef NO_MASTER_DUMP
  if (dump) {
    time_t now;
    logto = LOGTO_STDERR;
    for(c = 0; c < argc; ++c)
      zonelist = addzone(zonelist, argv[c]);
    init_zones_caches(zonelist);
    if (rootdir && (chdir(rootdir) < 0 || chroot(rootdir) < 0))
      error(errno, "unable to chroot to %.50s", rootdir);
    if (workdir && chdir(workdir) < 0)
      error(errno, "unable to chdir to %.50s", workdir);
    if (!do_reload(0))
      error(0, "zone loading errors, aborting");
    now = time(NULL);
    printf("; zone dump made %s", ctime(&now));
    printf("; rbldnsd version %s\n", version);
    for (z = zonelist; z; z = z->z_next)
      dumpzone(z, stdout);
    fflush(stdout);
    exit(ferror(stdout) ? 1 : 0);
  }
#endif

  if (!nba)
    error(0, "no address to listen on (-b option) specified");

  tzset();
  if (nodaemon)
    logto = LOGTO_STDOUT|LOGTO_STDERR;
  else {
    /* fork early so that logging will be from right pid */
    int pfd[2];
    if (pipe(pfd) < 0) error(errno, "pipe() failed");
    c = fork();
    if (c < 0) error(errno, "fork() failed");
    if (c > 0) {
      close(pfd[1]);
      if (read(pfd[0], &c, 1) < 1) exit(1);
      else exit(0);
    }
    cfd = pfd[1];
    close(pfd[0]);
    openlog(progname, LOG_PID|LOG_NDELAY, LOG_DAEMON);
    logto = LOGTO_STDERR|LOGTO_SYSLOG;
    if (!quickstart && !flog) logto |= LOGTO_STDOUT;
  }

  initsockets(bindaddr, nba, family);

#ifndef NO_DSO
  if (ext) {
    void *handle = dlopen(ext, RTLD_NOW);
    if (!handle)
      error(0, "unable to load extension `%s': %s", ext, dlerror());
    extinit = dlsym(handle, "rbldnsd_extension_init");
    if (!extinit)
      error(0, "unable to find extension init routine in `%s'", ext);
  }
#endif

  if (!user && !(uid = getuid()))
    user = "******";

  if (!user)
    p = NULL;
  else {
    if ((p = strchr(user, ':')) != NULL)
      *p++ = '\0';
    if ((c = satoi(user)) >= 0)
      uid = c, gid = c;
    else {
      struct passwd *pw = getpwnam(user);
      if (!pw)
        error(0, "unknown user `%s'", user);
      uid = pw->pw_uid;
      gid = pw->pw_gid;
      endpwent();
    }
  }
  if (!uid)
    error(0, "daemon should not run as root, specify -u option");
  if (p) {
    if ((c = satoi(p)) >= 0)
      gid = c;
    else {
      struct group *gr = getgrnam(p);
      if (!gr)
        error(0, "unknown group `%s'", p);
      gid = gr->gr_gid;
      endgrent();
    }
    p[-1] = ':';
  }

  if (pidfile) {
    int fdpid;
    char buf[40];
    c = sprintf(buf, "%ld\n", (long)getpid());
    fdpid = open(pidfile, O_CREAT|O_WRONLY|O_TRUNC, 0644);
    if (fdpid < 0 || write(fdpid, buf, c) < c)
      error(errno, "unable to write pidfile");
    close(fdpid);
  }

  if (rootdir && (chdir(rootdir) < 0 || chroot(rootdir) < 0))
    error(errno, "unable to chroot to %.50s", rootdir);
  if (workdir && chdir(workdir) < 0)
    error(errno, "unable to chdir to %.50s", workdir);

  if (user)
    if (setgroups(1, &gid) < 0 || setgid(gid) < 0 || setuid(uid) < 0)
      error(errno, "unable to setuid(%d:%d)", (int)uid, (int)gid);

  for(c = 0; c < argc; ++c)
    zonelist = addzone(zonelist, argv[c]);
  init_zones_caches(zonelist);

#ifndef NO_DSO
  if (extinit && extinit(extarg, zonelist) != 0)
    error(0, "unable to iniitialize extension `%s'", ext);
#endif

  if (!quickstart && !do_reload(0))
    error(0, "zone loading errors, aborting");

  /* count number of zones */
  for(c = 0, z = zonelist; z; z = z->z_next)
    ++c;
  numzones = c;

#if STATS_IPC_IOVEC
  stats_iov = (struct iovec *)emalloc(numzones * sizeof(struct iovec));
  for(c = 0, z = zonelist; z; z = z->z_next, ++c) {
    stats_iov[c].iov_base = (char*)&z->z_stats;
    stats_iov[c].iov_len = sizeof(z->z_stats);
  }
#endif
  dslog(LOG_INFO, 0, "rbldnsd version %s started (%d socket(s), %d zone(s))",
        version, numsock, numzones);
  initialized = 1;

  if (cfd >= 0) {
    write(cfd, "", 1);
    close(cfd);
    close(0); close(2);
    if (!flog) close(1);
    setsid();
    logto = LOGTO_SYSLOG;
  }

  if (quickstart)
    do_reload(0);

  /* only set "main" fork_on_reload after first reload */
  fork_on_reload = forkon;
}
Exemplo n.º 28
0
xmlNodePtr users_getxml(xmlNsPtr ns, char** msg)
{
	xmlNodePtr auth_node, user, aux_node;
	struct passwd *pwd;
	struct spwd *spwd;
	const char* value;
	char *path = NULL;

	if (!ncds_feature_isenabled("ietf-system", "local-users")) {
		return (NULL);
	}

	/* authentication */
	auth_node = xmlNewNode(ns, BAD_CAST "authentication");

	/* authentication/user-authentication-order */
	asprintf(&path, "/files/%s/PasswordAuthentication", NETOPEER_SSHD_CONF);
	aug_get(sysaugeas, path, &value);
	free(path);
	if (value != NULL && strcmp(value, "yes") == 0) {
		xmlNewChild(auth_node, auth_node->ns, BAD_CAST "user-authentication-order", BAD_CAST "local-users");
	}

	/* authentication/user[] */
	if (lckpwdf() != 0) {
		*msg = strdup("Failed to acquire shadow file lock.");
		xmlFreeNode(auth_node);
		return (NULL);
	}

	setpwent();

	while ((pwd = getpwent()) != NULL) {
		/* authentication/user */
		user = xmlNewChild(auth_node, auth_node->ns, BAD_CAST "user", NULL);

		/* authentication/user/name */
		xmlNewChild(user, user->ns, BAD_CAST "name", BAD_CAST pwd->pw_name);

		/* authentication/user/passwd */
		if (pwd->pw_passwd[0] == 'x') {
			/* get data from /etc/shadow */
			setspent();
			spwd = getspnam(pwd->pw_name);
			if (spwd != NULL && /* no record, wtf?!? */
					spwd->sp_pwdp[0] != '!' && /* account not initiated or locked */
					spwd->sp_pwdp[0] != '*') { /* login disabled */
				xmlNewChild(user, user->ns, BAD_CAST "password", BAD_CAST spwd->sp_pwdp);
			}
		} else if (pwd->pw_passwd[0] != '*') {
			/* password is stored in /etc/passwd or refers to something else (e.g., NIS server) */
			xmlNewChild(user, user->ns, BAD_CAST "password", BAD_CAST pwd->pw_passwd);
		} /* else password is disabled */

		/* authentication/user/authorized-key[] */
		if ((aux_node = authkey_getxml(pwd->pw_name, user->ns, msg)) != NULL) {
			xmlAddChildList(user, aux_node);
		} else {
			/* ignore failures in this case */
			free(*msg);
			*msg = NULL;
		}
	}

	endspent();
	endpwent();
	ulckpwdf();

	return (auth_node);
}
Exemplo n.º 29
0
static void
update_user(void)
{
#if defined(AUTH_METHODS) || defined(NDBM)
	struct	passwd	*pwd;
#endif
#ifdef AUTH_METHODS
#ifdef	SHADOWPWD
	struct	spwd	*spwd;

	if (is_shadow_pwd && (spwd = spw_locate (user_name)) &&
	    spwd->sp_pwdp[0] == '@') {
		if (pw_auth (spwd->sp_pwdp + 1, user_name, PW_DELETE, (char *) 0)) {
			SYSLOG((LOG_ERR,
				"failed deleting auth `%s' for user `%s'\n",
				spwd->sp_pwdp + 1, user_name));
			fprintf(stderr,
				_("%s: error deleting authentication\n"),
				Prog);
		} else {
			SYSLOG((LOG_INFO,
				"delete auth `%s' for user `%s'\n",
				spwd->sp_pwdp + 1, user_name));
		}
	}
#endif	/* SHADOWPWD */
	if ((pwd = pw_locate(user_name)) && pwd->pw_passwd[0] == '@') {
		if (pw_auth(pwd->pw_passwd + 1, user_name, PW_DELETE, (char *) 0)) {
			SYSLOG((LOG_ERR,
				"failed deleting auth `%s' for user `%s'\n",
				pwd->pw_passwd + 1, user_name));
			fprintf(stderr,
				_("%s: error deleting authentication\n"),
				Prog);
		} else {
			SYSLOG((LOG_INFO, "delete auth `%s' for user `%s'\n",
				pwd->pw_passwd + 1, user_name);
		}
	}
#endif  /* AUTH_METHODS */
	if (!pw_remove(user_name))
		fprintf(stderr, _("%s: error deleting password entry\n"), Prog);
#ifdef	SHADOWPWD
	if (is_shadow_pwd && ! spw_remove (user_name))
		fprintf(stderr, _("%s: error deleting shadow password entry\n"),
			Prog);
#endif
#ifdef	HAVE_TCFS
	if (tcfs_locate (user_name)) {
		if (!tcfs_remove (user_name)) {
			SYSLOG((LOG_ERR,
				"failed deleting TCFS entry for user `%s'\n",
				user_name));
			fprintf(stderr, _("%s: error deleting TCFS entry\n"),
				Prog);
		} else {
			SYSLOG((LOG_INFO,
				"delete TCFS entry for user `%s'\n",
				user_name));
		}
	}
#endif	/* HAVE_TCFS */
#ifdef NDBM
	if (pw_dbm_present()) {
		if ((pwd = getpwnam (user_name)) && ! pw_dbm_remove (pwd))
			fprintf(stderr,
				_("%s: error deleting password dbm entry\n"),
				Prog);
	}

	/*
	 * If the user's UID is a duplicate the duplicated entry needs
	 * to be updated so that a UID match can be found in the DBM
	 * files.
	 */

	for (pw_rewind (), pwd = pw_next ();pwd;pwd = pw_next ()) {
		if (pwd->pw_uid == user_id) {
			pw_dbm_update (pwd);
			break;
		}
	}
#ifdef SHADOWPWD
	if (is_shadow_pwd && sp_dbm_present() && !sp_dbm_remove(user_name))
		fprintf(stderr,
			_("%s: error deleting shadow passwd dbm entry\n"),
			Prog);

	endspent ();
#endif
	endpwent ();
#endif /* NDBM */
	SYSLOG((LOG_INFO, "delete user `%s'\n", user_name));
}
int main(void)
{
    struct passwd *pwd;
#ifdef USE_SHADOW
    struct spwd *spw;
#endif
    const char *pw;
    struct stat st;

#ifdef HAVE_SETLOCALE
# ifdef LC_MESSAGES
    (void) setlocale(LC_MESSAGES, "");
# endif
# ifdef LC_CTYPE
    (void) setlocale(LC_CTYPE, "");
# endif
# ifdef LC_COLLATE
    (void) setlocale(LC_COLLATE, "");
# endif
#endif    
    
    setpwent();
    while ((pwd = getpwent()) != NULL) {
        if (pwd->pw_name == NULL) {
            continue;
        }
        if (pwd->pw_uid <= (uid_t) 0 ||
            pwd->pw_gid <= (gid_t) 0) {
            continue;
        }
        if (stat(pwd->pw_dir, &st) != 0 ||
            !S_ISDIR(st.st_mode)) { 
            continue;
        }
#ifdef HAVE_SETUSERSHELL
        if (strcasecmp(pwd->pw_shell, FAKE_SHELL) != 0) {
            const char *shell;
            
            setusershell();
            while ((shell = (char *) getusershell()) != NULL &&
                   strcmp(pwd->pw_shell, shell) != 0);
            endusershell();
            if (shell == NULL) {
                continue;
            }
        }            
#endif
        pw = pwd->pw_passwd;
#ifdef USE_SHADOW
        if (pwd->pw_passwd != NULL && pwd->pw_name != NULL &&            
            (((pwd->pw_passwd)[0] == 'x' && (pwd->pw_passwd)[1] == 0) ||
             (strcmp(pwd->pw_passwd, "********") == 0) ||             
             ((pwd->pw_passwd)[0] == '#' && (pwd->pw_passwd)[1] == '#' &&
              strcmp(pwd->pw_passwd + 2, pwd->pw_name) == 0)) &&
            (spw = getspnam(pwd->pw_name)) != NULL && spw->sp_pwdp != NULL) {
            pw = spw->sp_pwdp[0] == '@' ? "*" : spw->sp_pwdp;            
        }
#endif
        if (pw == NULL || *pw == 0) {
            pw = "*";
        }
        {
            char *coma;
            
            if (pwd->pw_gecos != NULL && 
                (coma = strchr(pwd->pw_gecos, ',')) != NULL) {
                *coma = 0;
            }
        }
        printf("%s:%s:%lu:%lu:%s:%s/./\n", pwd->pw_name, pw,
               (unsigned long) pwd->pw_uid, (unsigned long) pwd->pw_gid,
               pwd->pw_gecos, pwd->pw_dir);        
    }
    endpwent();
    
    return 0;
}